Imports System
Imports System.Text
Imports System.Diagnostics
Imports System.Collections.Generic
Imports Microsoft.VisualStudio.TestTools.UnitTesting
Imports Mercury.Mobile.Data

<TestClass()> Public Class VirtualizingCollection_specs

    Private testContextInstance As TestContext

    '''<summary>
    '''Gets or sets the test context which provides
    '''information about and functionality for the current test run.
    '''</summary>
    Public Property TestContext() As TestContext
        Get
            Return testContextInstance
        End Get
        Set(ByVal value As TestContext)
            testContextInstance = Value
        End Set
    End Property

#Region "Additional test attributes"
    '
    ' You can use the following additional attributes as you write your tests:
    '
    ' Use ClassInitialize to run code before running the first test in the class
    ' <ClassInitialize()> Public Shared Sub MyClassInitialize(ByVal testContext As TestContext)
    ' End Sub
    '
    ' Use ClassCleanup to run code after all tests in a class have run
    ' <ClassCleanup()> Public Shared Sub MyClassCleanup()
    ' End Sub
    '
    ' Use TestInitialize to run code before running each test
    ' <TestInitialize()> Public Sub MyTestInitialize()
    ' End Sub
    '
    ' Use TestCleanup to run code after each test has run
    ' <TestCleanup()> Public Sub MyTestCleanup()
    ' End Sub
    '
#End Region

    <TestMethod()> _
    Public Sub Can_create_virtualizing_collection()
        Dim coll = New VirtualizingCollection(Of String)(GetDefaultItemProvider())
        Assert.IsNotNull(coll)
        Assert.IsTrue(coll.Count = 100000)
        Assert.IsTrue(coll.IsReadOnly = True)
    End Sub

    <TestMethod()> _
    Public Sub Can_select_virtualized_items()
        Dim coll = New VirtualizingCollection(Of String)(GetDefaultItemProvider())
        coll.PageTimeout = 500

        ' Basic item lookups
        Dim item As String = coll.Item(0)
        Assert.IsNotNull(item)
        Assert.IsTrue(item = "Record:0")

        item = coll.Item(99)
        Assert.IsTrue(item = "Record:99")

        item = coll.Item(309)
        Assert.IsTrue(item = "Record:309")

        item = coll.Item(378)
        Assert.IsTrue(item = "Record:378")

        ' Get middle
        item = coll.Item(51000)
        Assert.IsTrue(item = "Record:51000")

        ' Get last
        item = coll.Item(99999)
        Assert.IsTrue(item = "Record:99999")

        System.Threading.Thread.Sleep(501)

        ' Alter item at index 1
        Dim provider = TryCast(coll.ItemProvider, MockItemProvider(Of String))
        Dim newValue As String = "Record: <no record>"
        provider.Items(1) = newValue

        ' Retrieve first page
        coll.Invalidate()
        item = coll.Item(1)
        Assert.IsTrue(item = newValue)
    End Sub

    <TestMethod()> _
    Public Sub Cannot_write_to_virtualized_items()
        Dim coll = New VirtualizingCollection(Of String)(GetDefaultItemProvider())
        Assert.IsTrue(coll.IsReadOnly = True)

        Dim caught As Exception = Nothing
        Try
            coll.Add("New record")
        Catch ex As Exception
            caught = ex
        End Try
        Assert.IsNotNull(caught)

        caught = Nothing
        Try
            coll.Clear()
        Catch ex As Exception
            caught = ex
        End Try
        Assert.IsNotNull(caught)

        caught = Nothing
        Try
            coll.Insert(1, "New record")
        Catch ex As Exception
            caught = ex
        End Try
        Assert.IsNotNull(caught)

        caught = Nothing
        Try
            coll.Item(1) = "alternate record"
        Catch ex As Exception
            caught = ex
        End Try
        Assert.IsNotNull(caught)

        caught = Nothing
        Try
            coll.Remove("Record:0")
        Catch ex As Exception
            caught = ex
        End Try
        Assert.IsNotNull(caught)

        caught = Nothing
        Try
            coll.RemoveAt(3)
        Catch ex As Exception
            caught = ex
        End Try
        Assert.IsNotNull(caught)
    End Sub

    <TestMethod()> _
    Public Sub Can_determine_cached_item_existence()
        Dim coll = New VirtualizingCollection(Of String)(GetDefaultItemProvider())

        Dim item = coll.Item(393)
        Dim index As Integer = coll.IndexOf("Record:393")
        Assert.IsTrue(index = 393)

        Dim contains As Boolean = coll.Contains("Record <null>")
        Assert.IsFalse(contains)
        item = coll.Item(2100)
        contains = coll.Contains("Record:2100")
        Assert.IsTrue(contains)
    End Sub

    <TestMethod()> _
    Public Sub Can_enumerate_and_copy_virtualized_items()
        Dim coll = New VirtualizingCollection(Of String)(GetDefaultItemProvider())

        ' Enumerate
        Dim enumerator = coll.GetEnumerator()
        enumerator.Reset()
        Dim count As Integer = 0
        Do While enumerator.MoveNext()
            count += 1
        Loop
        Assert.IsTrue(count = 100000)

        ' Copy
        Dim copiedItems() As String = New String(99999) {}
        coll.CopyTo(copiedItems, 0)
        Assert.IsTrue(copiedItems.Length = 100000)
        Assert.IsTrue(copiedItems(99) = "Record:99")
    End Sub

    <TestMethod()> _
    Public Sub Can_access_collection_asynchronously()
        Dim delay = 1000
        Dim coll = New AsyncVirtualizingCollection(Of String)(GetDelayedItemProvider(delay))

        ' Get count
        coll.Invalidate()
        Dim clock = New Stopwatch()
        clock.Start()
        Dim count = coll.Count
        clock.Stop()

        Dim elapsed = clock.ElapsedMilliseconds
        Assert.IsTrue(elapsed < delay)

        System.Threading.Thread.Sleep(delay * 2)
        Assert.IsTrue(coll.Count = 100000)

        ' Get item at index
        Dim item = coll.Item(3)
        Assert.IsNull(item)
        System.Threading.Thread.Sleep(delay * 2)
        item = coll.Item(3)
        Assert.IsNotNull(item)
        Assert.IsTrue(item = "Record:3")
    End Sub

    <TestMethod()> _
    Public Sub Asynchronous_access_is_consistent()
        Dim delay = 250
        Dim coll = New AsyncVirtualizingCollection(Of String)(GetDelayedItemProvider(delay))
        coll.PageTimeout = 420

        Dim ct = coll.Count
        System.Threading.Thread.Sleep(500)
        Assert.IsTrue(coll.Count = 100000)

        For i As Integer = 0 To 499
            ' Get middle
            Dim item = coll.Item(51000)
            If (item Is Nothing) Then
                System.Threading.Thread.Sleep(350)
                item = coll.Item(51000)
            End If
            Assert.IsTrue(item = "Record:51000")

            ' Get last
            item = coll.Item(99999)
            If item Is Nothing Then
                System.Threading.Thread.Sleep(350)
                item = coll.Item(99999)
            End If
            Assert.IsTrue(item = "Record:99999")
        Next
    End Sub

    Private Shared Function GetDefaultItemProvider() As IVirtualizingItemProvider(Of String)
        Dim currentList = New List(Of String)()
        For i As Integer = 0 To 99999
            currentList.Add(String.Format("Record:{0}", i))
        Next
        Return New MockItemProvider(Of String)(currentList)
    End Function

    Private Shared Function GetDelayedItemProvider(ByVal milliseconds As Long) As IVirtualizingItemProvider(Of String)
        Dim provider = TryCast(GetDefaultItemProvider(), MockItemProvider(Of String))
        provider.Delay = TimeSpan.FromMilliseconds(milliseconds)
        Return provider
    End Function

End Class
