diff --git a/sources/Data/Collections/Tests/TEST_Iterator.uc b/sources/Data/Collections/Tests/TEST_Iterator.uc index af0760b..2495e9f 100644 --- a/sources/Data/Collections/Tests/TEST_Iterator.uc +++ b/sources/Data/Collections/Tests/TEST_Iterator.uc @@ -1,6 +1,6 @@ /** * Set of tests for `Iterator` classes. - * Copyright 2020 Anton Tarasenko + * Copyright 2022 Anton Tarasenko *------------------------------------------------------------------------------ * This file is part of Acedia. * @@ -28,6 +28,7 @@ protected static function CreateItems() { local int i; ResetFlags(); + default.items.length = 0; for (i = 0; i < default.TESTED_ITEMS_AMOUNT; i += 1) { default.items[default.items.length] = __().ref.float(i*2 + 1/i); } @@ -39,15 +40,30 @@ protected static function ResetFlags() default.seenFlags.length = default.TESTED_ITEMS_AMOUNT; } -protected static function DoTestIterator(Iter iter) +protected static function DoTestIterator( + string issueSubjectAllocation, + string issueSubjectAmount, + Iter iter) { local int i; local int seenCount; local AcediaObject nextObject; + ResetFlags(); + Issue(issueSubjectAllocation); while (!iter.HasFinished()) { nextObject = iter.Get(); + // Create + insert into collection + get reference + TEST_ExpectTrue(nextObject._getRefCount() == 3); + if (iter.class == class'ArrayListIterator') { + // `ArrayList` creates keys to return on-the-fly + TEST_ExpectTrue(iter.GetKey()._getRefCount() == 1); + } + else { + // Create + insert into collection + get reference + TEST_ExpectTrue(iter.GetKey()._getRefCount() == 3); + } for (i = 0; i < default.items.length; i += 1) { if (default.items[i] == nextObject) @@ -61,33 +77,35 @@ protected static function DoTestIterator(Iter iter) } iter.Next(); } + Issue(issueSubjectAmount); TEST_ExpectTrue(seenCount == default.TESTED_ITEMS_AMOUNT); } protected static function TESTS() { - // Prepare CreateItems(); - // Test - Test_DynamicArray(); - Test_AssociativeArray(); + Test_ArrayList(); + CreateItems(); + Test_HashTable(); + Test_IterationAndNone(); } -protected static function Test_DynamicArray() +protected static function Test_ArrayList() { - local int i; - local Iter iter; - local DynamicArray array; - array = DynamicArray(__().memory.Allocate(class'DynamicArray')); + local int i; + local Iter iter; + local ArrayList array; + + array = ArrayList(__().memory.Allocate(class'ArrayList')); iter = array.Iterate(); - Context("Testing iterator for `DynamicArray`"); - Issue("`DynamicArray` returns `none` iterator."); + Context("Testing iterator for `ArrayList`"); + Issue("`ArrayList` returns `none` iterator."); TEST_ExpectNotNone(iter); - Issue("Iterator for empty `DynamicArray` is not finished by default."); + Issue("Iterator for empty `ArrayList` is not finished by default."); TEST_ExpectTrue(iter.HasFinished()); - Issue("Iterator for empty `DynamicArray` does not return `none` as" + Issue("Iterator for empty `ArrayList` does not return `none` as" @ "a current item."); TEST_ExpectNone(iter.Get()); TEST_ExpectNone(iter.Next().Get()); @@ -96,28 +114,32 @@ protected static function Test_DynamicArray() array.AddItem(default.items[i]); } iter = array.Iterate(); - Issue("`DynamicArray` returns `none` iterator."); + Issue("`ArrayList` returns `none` iterator."); TEST_ExpectNotNone(iter); - Issue("`DynamicArray`'s iterator iterates over incorrect set of items."); - DoTestIterator(iter); + Issue("`ArrayList`'s iterator iterates over incorrect set of items."); + DoTestIterator( + "`ArrayList`'s iterator incorrectly handles reference counting.", + "`ArrayList`'s iterator iterates over incorrect set of items.", + iter); } -protected static function Test_AssociativeArray() +protected static function Test_HashTable() { - local int i; - local Iter iter; - local AssociativeArray array; - array = AssociativeArray(__().memory.Allocate(class'AssociativeArray')); + local int i; + local Iter iter; + local HashTable array; + + array = HashTable(__().memory.Allocate(class'HashTable')); iter = array.Iterate(); - Context("Testing iterator for `AssociativeArray`"); - Issue("`AssociativeArray` returns `none` iterator."); + Context("Testing iterator for `HashTable`"); + Issue("`HashTable` returns `none` iterator."); TEST_ExpectNotNone(iter); - Issue("Iterator for empty `AssociativeArray` is not finished by default."); + Issue("Iterator for empty `HashTable` is not finished by default."); TEST_ExpectTrue(iter.HasFinished()); - Issue("Iterator for empty `AssociativeArray` does not return `none` as" + Issue("Iterator for empty `HashTable` does not return `none` as" @ "a current item."); TEST_ExpectNone(iter.Get()); TEST_ExpectNone(iter.Next().Get()); @@ -126,17 +148,103 @@ protected static function Test_AssociativeArray() array.SetItem(__().box.int(i), default.items[i]); } iter = array.Iterate(); - Issue("`AssociativeArray` returns `none` iterator."); + Issue("`HashTable` returns `none` iterator."); TEST_ExpectNotNone(iter); - Issue("`AssociativeArray`'s iterator iterates over incorrect set of" - @ "items."); - DoTestIterator(iter); + DoTestIterator( + "`HashTable`'s iterator incorrectly handles reference counting.", + "`HashTable`'s iterator iterates over incorrect set of items.", + iter); +} + +protected static function Test_IterationAndNone() +{ + Context("Testing how collections iterate over `none` references."); + SubTest_ArrayListIterationAndNone(); + SubTest_HashTableIterationAndNone(); +} + +protected static function SubTest_ArrayListIterationAndNone() +{ + local bool sawNone; + local int counter; + local Iter iter; + local ArrayList list; + + list = __().collections.EmptyArrayList(); + list.AddItem(__().box.int(1)); + list.AddItem(none); + list.AddItem(__().box.int(3)); + list.AddItem(none); + list.AddItem(__().box.int(5)); + Issue("`ArrayList` doesn't properly iterate over `none` items by default."); + iter = list.Iterate(); + while (!iter.HasFinished()) + { + sawNone = sawNone || (iter.Get() == none); + counter += 1; + iter.Next(); + } + TEST_ExpectTrue(sawNone); + TEST_ExpectTrue(counter == 5); + + Issue("`ArrayList` iterates over `none` items even after" + @ "`LeaveOnlyNotNone()` call."); + sawNone = false; + counter = 0; + iter = list.Iterate().LeaveOnlyNotNone(); + while (!iter.HasFinished()) + { + sawNone = sawNone || (iter.Get() == none); + counter += 1; + iter.Next(); + } + TEST_ExpectFalse(sawNone); + TEST_ExpectTrue(counter == 3); +} + +protected static function SubTest_HashTableIterationAndNone() +{ + local bool sawNone; + local int counter; + local Iter iter; + local HashTable table; + + table = __().collections.EmptyHashTable(); + table.SetItem(__().box.float(1.0), __().box.int(1)); + table.SetItem(__().box.float(0.3453), none); + table.SetItem(__().box.float(423.3), __().box.int(3)); + table.SetItem(__().box.float(7), none); + table.SetItem(__().box.float(1.1), __().box.int(5)); + Issue("`HashTable` doesn't properly iterate over `none` items by default."); + iter = table.Iterate(); + while (!iter.HasFinished()) + { + sawNone = sawNone || (iter.Get() == none); + counter += 1; + iter.Next(); + } + TEST_ExpectTrue(sawNone); + TEST_ExpectTrue(counter == 5); + + Issue("`HashTable` iterates over `none` items even after" + @ "`LeaveOnlyNotNone()` call."); + sawNone = false; + counter = 0; + iter = table.Iterate().LeaveOnlyNotNone(); + while (!iter.HasFinished()) + { + sawNone = sawNone || (iter.Get() == none); + counter += 1; + iter.Next(); + } + TEST_ExpectFalse(sawNone); + TEST_ExpectTrue(counter == 3); } defaultproperties { - caseGroup = "Collections" - caseName = "Iterator" + caseGroup = "Collections" + caseName = "Iterator" TESTED_ITEMS_AMOUNT = 100 } \ No newline at end of file diff --git a/sources/Data/Collections/Tests/TEST_IteratorOld.uc b/sources/Data/Collections/Tests/TEST_IteratorOld.uc new file mode 100644 index 0000000..52198d2 --- /dev/null +++ b/sources/Data/Collections/Tests/TEST_IteratorOld.uc @@ -0,0 +1,142 @@ +/** + * Set of tests for `Iterator` classes. + * Copyright 2020 Anton Tarasenko + *------------------------------------------------------------------------------ + * This file is part of Acedia. + * + * Acedia is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3 of the License, or + * (at your option) any later version. + * + * Acedia is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Acedia. If not, see . + */ +class TEST_IteratorOld extends TestCase + abstract; + +var const int TESTED_ITEMS_AMOUNT; +var array items; +var array seenFlags; + +protected static function CreateItems() +{ + local int i; + ResetFlags(); + for (i = 0; i < default.TESTED_ITEMS_AMOUNT; i += 1) { + default.items[default.items.length] = __().ref.float(i*2 + 1/i); + } +} + +protected static function ResetFlags() +{ + default.seenFlags.length = 0; + default.seenFlags.length = default.TESTED_ITEMS_AMOUNT; +} + +protected static function DoTestIterator(Iter iter) +{ + local int i; + local int seenCount; + local AcediaObject nextObject; + ResetFlags(); + while (!iter.HasFinished()) + { + nextObject = iter.Get(); + for (i = 0; i < default.items.length; i += 1) + { + if (default.items[i] == nextObject) + { + if (default.seenFlags[i] == 0) { + seenCount += 1; + } + default.seenFlags[i] = 1; + continue; + } + } + iter.Next(); + } + TEST_ExpectTrue(seenCount == default.TESTED_ITEMS_AMOUNT); +} + +protected static function TESTS() +{ + // Prepare + CreateItems(); + // Test + Test_DynamicArray(); + Test_AssociativeArray(); +} + +protected static function Test_DynamicArray() +{ + local int i; + local Iter iter; + local DynamicArray array; + array = DynamicArray(__().memory.Allocate(class'DynamicArray')); + iter = array.Iterate(); + Context("Testing iterator for `DynamicArray`"); + Issue("`DynamicArray` returns `none` iterator."); + TEST_ExpectNotNone(iter); + + Issue("Iterator for empty `DynamicArray` is not finished by default."); + TEST_ExpectTrue(iter.HasFinished()); + + Issue("Iterator for empty `DynamicArray` does not return `none` as" + @ "a current item."); + TEST_ExpectNone(iter.Get()); + TEST_ExpectNone(iter.Next().Get()); + + for (i = 0; i < default.items.length; i += 1) { + array.AddItem(default.items[i]); + } + iter = array.Iterate(); + Issue("`DynamicArray` returns `none` iterator."); + TEST_ExpectNotNone(iter); + + Issue("`DynamicArray`'s iterator iterates over incorrect set of items."); + DoTestIterator(iter); +} + +protected static function Test_AssociativeArray() +{ + local int i; + local Iter iter; + local AssociativeArray array; + array = AssociativeArray(__().memory.Allocate(class'AssociativeArray')); + iter = array.Iterate(); + Context("Testing iterator for `AssociativeArray`"); + Issue("`AssociativeArray` returns `none` iterator."); + TEST_ExpectNotNone(iter); + + Issue("Iterator for empty `AssociativeArray` is not finished by default."); + TEST_ExpectTrue(iter.HasFinished()); + + Issue("Iterator for empty `AssociativeArray` does not return `none` as" + @ "a current item."); + TEST_ExpectNone(iter.Get()); + TEST_ExpectNone(iter.Next().Get()); + + for (i = 0; i < default.items.length; i += 1) { + array.SetItem(__().box.int(i), default.items[i]); + } + iter = array.Iterate(); + Issue("`AssociativeArray` returns `none` iterator."); + TEST_ExpectNotNone(iter); + + Issue("`AssociativeArray`'s iterator iterates over incorrect set of" + @ "items."); + DoTestIterator(iter); +} + +defaultproperties +{ + caseGroup = "Collections" + caseName = "IteratorOld" + TESTED_ITEMS_AMOUNT = 100 +} \ No newline at end of file