Anton Tarasenko
2 years ago
27 changed files with 328 additions and 3860 deletions
File diff suppressed because it is too large
Load Diff
@ -1,83 +0,0 @@ |
|||||||
/** |
|
||||||
* Iterator for iterating over `AssociativeArray`'s items. |
|
||||||
* 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 <https://www.gnu.org/licenses/>. |
|
||||||
*/ |
|
||||||
class AssociativeArrayIterator extends CollectionIterator |
|
||||||
dependson(AssociativeArray); |
|
||||||
|
|
||||||
var private bool hasNotFinished; |
|
||||||
var private AssociativeArray relevantCollection; |
|
||||||
var private AssociativeArray.Index currentIndex; |
|
||||||
|
|
||||||
protected function Finalizer() |
|
||||||
{ |
|
||||||
relevantCollection = none; |
|
||||||
} |
|
||||||
|
|
||||||
public function bool Initialize(Collection relevantArray) |
|
||||||
{ |
|
||||||
local AssociativeArray.Index emptyIndex; |
|
||||||
currentIndex = emptyIndex; |
|
||||||
relevantCollection = AssociativeArray(relevantArray); |
|
||||||
if (relevantCollection == none) { |
|
||||||
return false; |
|
||||||
} |
|
||||||
hasNotFinished = (relevantCollection.GetLength() > 0); |
|
||||||
if (GetKey() == none) { |
|
||||||
relevantCollection.IncrementIndex(currentIndex); |
|
||||||
} |
|
||||||
return true; |
|
||||||
} |
|
||||||
|
|
||||||
public function Iter Next(optional bool skipNone) |
|
||||||
{ |
|
||||||
local int collectionLength; |
|
||||||
if (!skipNone) |
|
||||||
{ |
|
||||||
hasNotFinished = relevantCollection.IncrementIndex(currentIndex); |
|
||||||
return self; |
|
||||||
} |
|
||||||
collectionLength = relevantCollection.GetLength(); |
|
||||||
while (hasNotFinished) |
|
||||||
{ |
|
||||||
hasNotFinished = relevantCollection.IncrementIndex(currentIndex); |
|
||||||
if (relevantCollection.GetEntryByIndex(currentIndex).value != none) { |
|
||||||
return self; |
|
||||||
} |
|
||||||
} |
|
||||||
return self; |
|
||||||
} |
|
||||||
|
|
||||||
public function AcediaObject Get() |
|
||||||
{ |
|
||||||
return relevantCollection.GetEntryByIndex(currentIndex).value; |
|
||||||
} |
|
||||||
|
|
||||||
public function AcediaObject GetKey() |
|
||||||
{ |
|
||||||
return relevantCollection.GetEntryByIndex(currentIndex).key; |
|
||||||
} |
|
||||||
|
|
||||||
public function bool HasFinished() |
|
||||||
{ |
|
||||||
return !hasNotFinished; |
|
||||||
} |
|
||||||
|
|
||||||
defaultproperties |
|
||||||
{ |
|
||||||
} |
|
@ -1,817 +0,0 @@ |
|||||||
/** |
|
||||||
* Dynamic array object for storing arbitrary types of data. Generic |
|
||||||
* storage is achieved by using `AcediaObject` as the stored type. Native |
|
||||||
* variable types such as `int`, `bool`, etc. can be stored by boxing them into |
|
||||||
* `AcediaObject`s. |
|
||||||
* Appropriate classes and APIs for their construction are provided for |
|
||||||
* main primitive types and can be extended to any custom `struct`. |
|
||||||
* Copyright 2020 - 2021 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 <https://www.gnu.org/licenses/>. |
|
||||||
*/ |
|
||||||
class DynamicArray extends Collection; |
|
||||||
|
|
||||||
// Actual storage of all our data. |
|
||||||
var private array<AcediaObject> storedObjects; |
|
||||||
// `managedFlags[i] > 0` iff `contents[i]` is a managed object. |
|
||||||
// Invariant `managedFlags.length == contents.length` should be enforced by |
|
||||||
// all methods. |
|
||||||
var private array<byte> managedFlags; |
|
||||||
// Recorded `lifeVersions` of all stored objects. |
|
||||||
// Invariant `lifeVersions.length == contents.length` should be enforced by |
|
||||||
// all methods. |
|
||||||
var private array<int> lifeVersions; |
|
||||||
|
|
||||||
// Free array data |
|
||||||
protected function Finalizer() |
|
||||||
{ |
|
||||||
Empty(); |
|
||||||
} |
|
||||||
|
|
||||||
// Method, used to compare array values at different indices. |
|
||||||
// Does not check boundary conditions, so make sure passed indices are valid. |
|
||||||
private function bool AreEqual(AcediaObject object1, AcediaObject object2) |
|
||||||
{ |
|
||||||
if (object1 == none && object2 == none) return true; |
|
||||||
if (object1 == none || object2 == none) return false; |
|
||||||
|
|
||||||
return object1.IsEqual(object2); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Returns current length of dynamic `DynamicArray`. |
|
||||||
* Cannot fail. |
|
||||||
* |
|
||||||
* @return Returns length of the caller `DynamicArray`. |
|
||||||
* Guaranteed to be non-negative. |
|
||||||
*/ |
|
||||||
public final function int GetLength() |
|
||||||
{ |
|
||||||
return storedObjects.length; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Changes length of the caller `DynamicArray`. |
|
||||||
* If `DynamicArray` size is increased as a result - added items will be |
|
||||||
* filled with `none`s. |
|
||||||
* If `DynamicArray` size is decreased - erased managed items will be |
|
||||||
* automatically deallocated. |
|
||||||
* |
|
||||||
* @param newLength New length of an `DynamicArray`. |
|
||||||
* If negative value is passes - method will do nothing. |
|
||||||
* @return Reference to the caller `DynamicArray` to allow for method chaining. |
|
||||||
*/ |
|
||||||
public final function DynamicArray SetLength(int newLength) |
|
||||||
{ |
|
||||||
local int i; |
|
||||||
if (newLength < 0) { |
|
||||||
return self; |
|
||||||
} |
|
||||||
for (i = newLength; i < storedObjects.length; i += 1) { |
|
||||||
FreeManagedItem(i); |
|
||||||
} |
|
||||||
storedObjects.length = newLength; |
|
||||||
managedFlags.length = newLength; |
|
||||||
lifeVersions.length = newLength; |
|
||||||
return self; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Deallocates an item at a given index `index`, if it's managed. |
|
||||||
* Does not check `DynamicArray` bounds for `index`, so you must ensure that |
|
||||||
* `index` is valid. |
|
||||||
* |
|
||||||
* @param index Index of the managed item to deallocate. |
|
||||||
* @return Reference to the caller `DynamicArray` to allow for method chaining. |
|
||||||
*/ |
|
||||||
protected final function DynamicArray FreeManagedItem(int index) |
|
||||||
{ |
|
||||||
if (storedObjects[index] == none) return self; |
|
||||||
if (!storedObjects[index].IsAllocated()) return self; |
|
||||||
if (managedFlags[index] <= 0) return self; |
|
||||||
if (lifeVersions[index] != storedObjects[index].GetLifeVersion()) { |
|
||||||
return self; |
|
||||||
} |
|
||||||
if ( storedObjects[index] != none && managedFlags[index] > 0 |
|
||||||
&& lifeVersions[index] == storedObjects[index].GetLifeVersion()) |
|
||||||
{ |
|
||||||
storedObjects[index].FreeSelf(); |
|
||||||
storedObjects[index] = none; |
|
||||||
} |
|
||||||
return self; |
|
||||||
} |
|
||||||
|
|
||||||
public function Empty(optional bool deallocateKeys) |
|
||||||
{ |
|
||||||
local int i; |
|
||||||
local Collection subCollection; |
|
||||||
if (deallocateKeys) |
|
||||||
{ |
|
||||||
for (i = 0; i < storedObjects.length; i += 1) |
|
||||||
{ |
|
||||||
subCollection = Collection(GetItem(i)); |
|
||||||
if (subCollection != none) { |
|
||||||
subCollection.Empty(true); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
SetLength(0); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Adds `amountOfNewItems` empty (`none`) items at the end of |
|
||||||
* the `DynamicArray`. |
|
||||||
* To insert items at an arbitrary array index, use `Insert()`. |
|
||||||
* |
|
||||||
* @param amountOfNewItems Amount of items to add at the end. |
|
||||||
* If non-positive value is passed, - method does nothing. |
|
||||||
* @return Reference to the caller `DynamicArray` to allow for method chaining. |
|
||||||
*/ |
|
||||||
public final function DynamicArray Add(int amountOfNewItems) |
|
||||||
{ |
|
||||||
if (amountOfNewItems > 0) { |
|
||||||
SetLength(storedObjects.length + amountOfNewItems); |
|
||||||
} |
|
||||||
return self; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Inserts `count` empty (`none`) items into the `DynamicArray` |
|
||||||
* at specified position. |
|
||||||
* The indices of the following items are increased by `count` in order |
|
||||||
* to make room for the new items. |
|
||||||
* |
|
||||||
* To add items at the end of an `DynamicArray`, consider using `Add()`, |
|
||||||
* which is equivalent to `array.Insert(array.GetLength(), ...)`. |
|
||||||
* |
|
||||||
* @param index Index, where first inserted item will be located. |
|
||||||
* Must belong to `[0; self.GetLength()]` inclusive interval, |
|
||||||
* otherwise method does nothing. |
|
||||||
* @param count Amount of new items to insert. |
|
||||||
* Must be positive, otherwise method does nothing. |
|
||||||
* @return Reference to the caller `DynamicArray` to allow for method chaining. |
|
||||||
*/ |
|
||||||
public final function DynamicArray Insert(int index, int count) |
|
||||||
{ |
|
||||||
local int i; |
|
||||||
local int swapIndex; |
|
||||||
local int amountToShift; |
|
||||||
|
|
||||||
if (count <= 0) return self; |
|
||||||
if (index < 0 || index > storedObjects.length) return self; |
|
||||||
|
|
||||||
amountToShift = storedObjects.length - index; |
|
||||||
Add(count); |
|
||||||
if (amountToShift == 0) { |
|
||||||
return self; |
|
||||||
} |
|
||||||
for (i = 0; i < amountToShift; i += 1) |
|
||||||
{ |
|
||||||
swapIndex = storedObjects.length - i - 1; |
|
||||||
Swap(swapIndex, swapIndex - count); |
|
||||||
} |
|
||||||
return self; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Swaps two `DynamicArray` items, along with information about their |
|
||||||
* managed status. |
|
||||||
* |
|
||||||
* @param index1 Index of item to swap. |
|
||||||
* @param index2 Index of item to swap. |
|
||||||
*/ |
|
||||||
protected final function Swap(int index1, int index2) |
|
||||||
{ |
|
||||||
local AcediaObject temporaryItem; |
|
||||||
local int temporaryNumber; |
|
||||||
// Swap object |
|
||||||
temporaryItem = storedObjects[index1]; |
|
||||||
storedObjects[index1] = storedObjects[index2]; |
|
||||||
storedObjects[index2] = temporaryItem; |
|
||||||
// Swap life versions |
|
||||||
temporaryNumber = lifeVersions[index1]; |
|
||||||
lifeVersions[index1] = lifeVersions[index2]; |
|
||||||
lifeVersions[index2] = temporaryNumber; |
|
||||||
// Swap managed flags |
|
||||||
temporaryNumber = managedFlags[index1]; |
|
||||||
managedFlags[index1] = managedFlags[index2]; |
|
||||||
managedFlags[index2] = temporaryNumber; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Removes number items from the `DynamicArray`, starting at `index`. |
|
||||||
* All items before position and from `index + count` on are not changed, |
|
||||||
* but the item indices change, - they shift to close the gap, |
|
||||||
* created by removed items. |
|
||||||
* |
|
||||||
* @param index Remove items starting from this index. |
|
||||||
* Must belong to `[0; self.GetLength() - 1]` inclusive interval, |
|
||||||
* otherwise method does nothing. |
|
||||||
* @param count Removes at most this much items. |
|
||||||
* Must be positive, otherwise method does nothing. |
|
||||||
* Specifying more items than can be removed simply removes |
|
||||||
* all items, starting from `index`. |
|
||||||
* @return Reference to the caller `DynamicArray` to allow for method chaining. |
|
||||||
*/ |
|
||||||
public final function DynamicArray Remove(int index, int count) |
|
||||||
{ |
|
||||||
local int i; |
|
||||||
if (count <= 0) return self; |
|
||||||
if (index < 0 || index > storedObjects.length) return self; |
|
||||||
|
|
||||||
count = Min(count, storedObjects.length - index); |
|
||||||
for (i = 0; i < count; i += 1) { |
|
||||||
FreeManagedItem(index + i); |
|
||||||
} |
|
||||||
storedObjects.Remove(index, count); |
|
||||||
managedFlags.Remove(index, count); |
|
||||||
lifeVersions.Remove(index, count); |
|
||||||
return self; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Removes item at a given index, shifting all the items that come after |
|
||||||
* one place backwards. |
|
||||||
* |
|
||||||
* @param index Remove items starting from this index. |
|
||||||
* Must belong to `[0; self.GetLength() - 1]` inclusive interval, |
|
||||||
* otherwise method does nothing. |
|
||||||
* @return Reference to the caller `DynamicArray` to allow for method chaining. |
|
||||||
*/ |
|
||||||
public final function DynamicArray RemoveIndex(int index) |
|
||||||
{ |
|
||||||
Remove(index, 1); |
|
||||||
return self; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Checks if caller `DynamicArray`'s value at index `index` is managed. |
|
||||||
* |
|
||||||
* Managed values will be automatically deallocated once they are removed |
|
||||||
* (or overwritten) from the caller `DynamicArray`. |
|
||||||
* |
|
||||||
* @return `true` if value, recorded in caller `DynamicArray` at index `index` |
|
||||||
* is managed and `false` otherwise. |
|
||||||
* If `index` is invalid (outside of `DynamicArray` bounds) |
|
||||||
* also returns `false`. |
|
||||||
*/ |
|
||||||
public final function bool IsManaged(int index) |
|
||||||
{ |
|
||||||
if (index < 0) return false; |
|
||||||
if (index >= storedObjects.length) return false; |
|
||||||
if (storedObjects[index] == none) return false; |
|
||||||
if (!storedObjects[index].IsAllocated()) return false; |
|
||||||
if (storedObjects[index].GetLifeVersion() != lifeVersions[index]) { |
|
||||||
return false; |
|
||||||
} |
|
||||||
|
|
||||||
return (managedFlags[index] > 0); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Returns item at `index` and replaces it with `none` inside `DynamicArray`. |
|
||||||
* If index is invalid, returns `none`. |
|
||||||
* |
|
||||||
* If returned value was managed, it won't be deallocated |
|
||||||
* and will stop being managed. |
|
||||||
* |
|
||||||
* @param index Index of an item that `DynamicArray` has to return. |
|
||||||
* @return Either value at `index` in the caller `DynamicArray` or `none` if |
|
||||||
* passed `index` is invalid. |
|
||||||
*/ |
|
||||||
public final function AcediaObject TakeItem(int index) |
|
||||||
{ |
|
||||||
local AcediaObject result; |
|
||||||
if (index < 0) return none; |
|
||||||
if (index >= storedObjects.length) return none; |
|
||||||
if (storedObjects[index] == none) return none; |
|
||||||
if (!storedObjects[index].IsAllocated()) return none; |
|
||||||
if (storedObjects[index].GetLifeVersion() != lifeVersions[index]) { |
|
||||||
return none; |
|
||||||
} |
|
||||||
|
|
||||||
result = storedObjects[index]; |
|
||||||
storedObjects[index] = none; |
|
||||||
managedFlags[index] = 0; |
|
||||||
lifeVersions[index] = 0; |
|
||||||
return result; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Returns item at `index`. If index is invalid, returns `none`. |
|
||||||
* |
|
||||||
* @param index Index of an item that `DynamicArray` has to return. |
|
||||||
* @return Either value at `index` in the caller `DynamicArray` or `none` if |
|
||||||
* passed `index` is invalid. |
|
||||||
*/ |
|
||||||
public final function AcediaObject GetItem(int index) |
|
||||||
{ |
|
||||||
if (index < 0) return none; |
|
||||||
if (index >= storedObjects.length) return none; |
|
||||||
if (storedObjects[index] == none) return none; |
|
||||||
if (!storedObjects[index].IsAllocated()) return none; |
|
||||||
if (storedObjects[index].GetLifeVersion() != lifeVersions[index]) { |
|
||||||
return none; |
|
||||||
} |
|
||||||
|
|
||||||
return storedObjects[index]; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Changes `DynamicArray`'s value at `index` to `item`. |
|
||||||
* |
|
||||||
* @param index Index, at which to change the value. If `DynamicArray` is |
|
||||||
* not long enough to hold it, it will be automatically expanded. |
|
||||||
* If passed index is negative - method will do nothing. |
|
||||||
* @param item Value to be set at a given index. |
|
||||||
* @param managed Whether `item` should be managed by `DynamicArray`. |
|
||||||
* By default (`false`) all items are not managed. |
|
||||||
* @return Reference to the caller `DynamicArray` to allow for method chaining. |
|
||||||
*/ |
|
||||||
public final function DynamicArray SetItem( |
|
||||||
int index, |
|
||||||
AcediaObject item, |
|
||||||
optional bool managed) |
|
||||||
{ |
|
||||||
if (index < 0) { |
|
||||||
return self; |
|
||||||
} |
|
||||||
if (index >= storedObjects.length) { |
|
||||||
SetLength(index + 1); |
|
||||||
} |
|
||||||
else if (item != storedObjects[index]) { |
|
||||||
FreeManagedItem(index); |
|
||||||
} |
|
||||||
storedObjects[index] = item; |
|
||||||
managedFlags[index] = 0; |
|
||||||
if (managed) { |
|
||||||
managedFlags[index] = 1; |
|
||||||
} |
|
||||||
if (item != none) { |
|
||||||
lifeVersions[index] = item.GetLifeVersion(); |
|
||||||
} |
|
||||||
return self; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Creates a new instance of class `valueClass` and records it's value at index |
|
||||||
* `index` in the caller `DynamicArray`. Value is recorded as managed. |
|
||||||
* |
|
||||||
* @param index Index, at which to change the value. If `DynamicArray` |
|
||||||
* is not long enough to hold it, it will be automatically expanded. |
|
||||||
* If passed index is negative - method will do nothing. |
|
||||||
* @param valueClass Class of object to create. Will only be created if |
|
||||||
* passed `index` is valid. |
|
||||||
* @return Caller `DynamicArray` to allow for method chaining. |
|
||||||
*/ |
|
||||||
public final function DynamicArray CreateItem( |
|
||||||
int index, |
|
||||||
class<AcediaObject> valueClass) |
|
||||||
{ |
|
||||||
if (index < 0) return self; |
|
||||||
if (valueClass == none) return self; |
|
||||||
|
|
||||||
return SetItem(index, AcediaObject(_.memory.Allocate(valueClass)), true); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Adds given `item` at the end of the `DynamicArray`, expanding it by |
|
||||||
* one item. |
|
||||||
* Cannot fail. |
|
||||||
* |
|
||||||
* @param item Item to be added at the end of the `DynamicArray`. |
|
||||||
* @param managed Whether `item` should be managed by `DynamicArray`. |
|
||||||
* By default (`false`) all items are not managed. |
|
||||||
* @return Reference to the caller `DynamicArray` to allow for method chaining. |
|
||||||
*/ |
|
||||||
public final function DynamicArray AddItem( |
|
||||||
AcediaObject item, |
|
||||||
optional bool managed) |
|
||||||
{ |
|
||||||
return SetItem(storedObjects.length, item, managed); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Inserts given `item` at index `index` of the `DynamicArray`, |
|
||||||
* shifting all the items starting from `index` one position to the right. |
|
||||||
* Cannot fail. |
|
||||||
* |
|
||||||
* @param index Index at which to insert new item. Must belong to |
|
||||||
* inclusive range `[0; self.GetLength()]`, otherwise method does nothing. |
|
||||||
* @param item Item to insert. |
|
||||||
* @param managed Whether `item` should be managed by `DynamicArray`. |
|
||||||
* By default (`false`) all items are not managed. |
|
||||||
* @return Reference to the caller `DynamicArray` to allow for method chaining. |
|
||||||
*/ |
|
||||||
public final function DynamicArray InsertItem( |
|
||||||
int index, |
|
||||||
AcediaObject item, |
|
||||||
optional bool managed) |
|
||||||
{ |
|
||||||
if (index < 0) return self; |
|
||||||
if (index > storedObjects.length) return self; |
|
||||||
|
|
||||||
Insert(index, 1); |
|
||||||
SetItem(index, item, managed); |
|
||||||
return self; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Returns all occurrences of `item` in the caller `DynamicArray` |
|
||||||
* (optionally only first one). |
|
||||||
* |
|
||||||
* @param item Item that needs to be removed from a `DynamicArray`. |
|
||||||
* @param onlyFirstItem Set to `true` to only remove first occurrence. |
|
||||||
* By default `false`, which means all occurrences will be removed. |
|
||||||
* @return Reference to the caller `DynamicArray` to allow for method chaining. |
|
||||||
*/ |
|
||||||
public final function DynamicArray RemoveItem( |
|
||||||
AcediaObject item, |
|
||||||
optional bool onlyFirstItem) |
|
||||||
{ |
|
||||||
local int i; |
|
||||||
while (i < storedObjects.length) |
|
||||||
{ |
|
||||||
if (AreEqual(storedObjects[i], item)) |
|
||||||
{ |
|
||||||
Remove(i, 1); |
|
||||||
if (onlyFirstItem) { |
|
||||||
return self; |
|
||||||
} |
|
||||||
} |
|
||||||
else { |
|
||||||
i += 1; |
|
||||||
} |
|
||||||
} |
|
||||||
return self; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Finds first occurrence of `item` in caller `DynamicArray` and returns |
|
||||||
* it's index. |
|
||||||
* |
|
||||||
* @param item Item to find in `DynamicArray`. |
|
||||||
* @return Index of first occurrence of `item` in caller `DynamicArray`. |
|
||||||
* `-1` if `item` is not found. |
|
||||||
*/ |
|
||||||
public final function int Find(AcediaObject item) |
|
||||||
{ |
|
||||||
local int i; |
|
||||||
for (i = 0; i < storedObjects.length; i += 1) |
|
||||||
{ |
|
||||||
if (AreEqual(storedObjects[i], item)) { |
|
||||||
return i; |
|
||||||
} |
|
||||||
} |
|
||||||
return -1; |
|
||||||
} |
|
||||||
|
|
||||||
protected function AcediaObject GetByText(BaseText key) |
|
||||||
{ |
|
||||||
local int index, consumed; |
|
||||||
local Parser parser; |
|
||||||
parser = _.text.Parse(key); |
|
||||||
parser.MUnsignedInteger(index,,, consumed); |
|
||||||
if (!parser.Ok()) |
|
||||||
{ |
|
||||||
parser.FreeSelf(); |
|
||||||
return none; |
|
||||||
} |
|
||||||
parser.FreeSelf(); |
|
||||||
return GetItem(index); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Returns `bool` item at `index`. If index is invalid or |
|
||||||
* stores a non-`bool` value, returns `defaultValue`. |
|
||||||
* |
|
||||||
* Referred value must be stored as `BoolBox` or `BoolRef` |
|
||||||
* (or one of their sub-classes) for this method to work. |
|
||||||
* |
|
||||||
* @param index Index of a `bool` item that `DynamicArray` |
|
||||||
* has to return. |
|
||||||
* @param defaultValue Value to return if there is either no item recorded |
|
||||||
* at `index` or it has a wrong type. |
|
||||||
* @return `bool` value at `index` in the caller `DynamicArray`. |
|
||||||
* `defaultValue` if passed `index` is invalid or non-`bool` value |
|
||||||
* is stored there. |
|
||||||
*/ |
|
||||||
public final function bool GetBool(int index, optional bool defaultValue) |
|
||||||
{ |
|
||||||
local AcediaObject result; |
|
||||||
local BoolBox asBox; |
|
||||||
local BoolRef asRef; |
|
||||||
result = GetItem(index); |
|
||||||
if (result == none) { |
|
||||||
return defaultValue; |
|
||||||
} |
|
||||||
asBox = BoolBox(result); |
|
||||||
if (asBox != none) { |
|
||||||
return asBox.Get(); |
|
||||||
} |
|
||||||
asRef = BoolRef(result); |
|
||||||
if (asRef != none) { |
|
||||||
return asRef.Get(); |
|
||||||
} |
|
||||||
return defaultValue; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Changes `DynamicArray`'s value at `index` to `value` that will be recorded |
|
||||||
* as either `BoolBox` or `BoolRef`, depending of `asRef` optional parameter. |
|
||||||
* |
|
||||||
* Inserted value will always be recorded as a managed value, i.e. it will be |
|
||||||
* automatically deallocated when overwritten, removed or caller `DynamicArray` |
|
||||||
* is deallocated. |
|
||||||
* |
|
||||||
* @param index Index, at which to change the value. If `DynamicArray` is |
|
||||||
* not long enough to hold it, it will be automatically expanded. |
|
||||||
* If passed index is negative - method will do nothing. |
|
||||||
* @param value Value to be set at a given index. |
|
||||||
* @param asRef Given `bool` value will be recorded as immutable `BoolBox` |
|
||||||
* by default (`asRef == false`). Setting this parameter to `true` will |
|
||||||
* make this method record it as a mutable `BoolRef`. |
|
||||||
* @return Reference to the caller `DynamicArray` to allow for method chaining. |
|
||||||
*/ |
|
||||||
public final function DynamicArray SetBool( |
|
||||||
int index, |
|
||||||
bool value, |
|
||||||
optional bool asRef) |
|
||||||
{ |
|
||||||
if (asRef) { |
|
||||||
SetItem(index, _.ref.bool(value), true); |
|
||||||
} |
|
||||||
else { |
|
||||||
SetItem(index, _.box.bool(value), true); |
|
||||||
} |
|
||||||
return self; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Returns `byte` item at `index`. If index is invalid or |
|
||||||
* stores a non-`byte` value, returns `defaultValue`. |
|
||||||
* |
|
||||||
* Referred value must be stored as `ByteBox` or `ByteRef` |
|
||||||
* (or one of their sub-classes) for this method to work. |
|
||||||
* |
|
||||||
* @param index Index of a `byte` item that `DynamicArray` |
|
||||||
* has to return. |
|
||||||
* @param defaultValue Value to return if there is either no item recorded |
|
||||||
* at `index` or it has a wrong type. |
|
||||||
* @return `byte` value at `index` in the caller `DynamicArray`. |
|
||||||
* `defaultValue` if passed `index` is invalid or non-`byte` value |
|
||||||
* is stored there. |
|
||||||
*/ |
|
||||||
public final function byte GetByte(int index, optional byte defaultValue) |
|
||||||
{ |
|
||||||
local AcediaObject result; |
|
||||||
local ByteBox asBox; |
|
||||||
local ByteRef asRef; |
|
||||||
result = GetItem(index); |
|
||||||
if (result == none) { |
|
||||||
return defaultValue; |
|
||||||
} |
|
||||||
asBox = ByteBox(result); |
|
||||||
if (asBox != none) { |
|
||||||
return asBox.Get(); |
|
||||||
} |
|
||||||
asRef = ByteRef(result); |
|
||||||
if (asRef != none) { |
|
||||||
return asRef.Get(); |
|
||||||
} |
|
||||||
return defaultValue; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Changes `DynamicArray`'s value at `index` to `value` that will be recorded |
|
||||||
* as either `ByteBox` or `ByteRef`, depending of `asRef` optional parameter. |
|
||||||
* |
|
||||||
* Inserted value will always be recorded as a managed value, i.e. it will be |
|
||||||
* automatically deallocated when overwritten, removed or caller `DynamicArray` |
|
||||||
* is deallocated. |
|
||||||
* |
|
||||||
* @param index Index, at which to change the value. If `DynamicArray` is |
|
||||||
* not long enough to hold it, it will be automatically expanded. |
|
||||||
* If passed index is negative - method will do nothing. |
|
||||||
* @param value Value to be set at a given index. |
|
||||||
* @param asRef Given `byte` value will be recorded as immutable `ByteBox` |
|
||||||
* by default (`asRef == false`). Setting this parameter to `true` will |
|
||||||
* make this method record it as a mutable `ByteRef`. |
|
||||||
* @return Reference to the caller `DynamicArray` to allow for method chaining. |
|
||||||
*/ |
|
||||||
public final function DynamicArray SetByte( |
|
||||||
int index, |
|
||||||
byte value, |
|
||||||
optional bool asRef) |
|
||||||
{ |
|
||||||
if (asRef) { |
|
||||||
SetItem(index, _.ref.byte(value), true); |
|
||||||
} |
|
||||||
else { |
|
||||||
SetItem(index, _.box.byte(value), true); |
|
||||||
} |
|
||||||
return self; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Returns `int` item at `index`. If index is invalid or |
|
||||||
* stores a non-`int` value, returns `defaultValue`. |
|
||||||
* |
|
||||||
* Referred value must be stored as `IntBox` or `IntRef` |
|
||||||
* (or one of their sub-classes) for this method to work. |
|
||||||
* |
|
||||||
* @param index Index of a `int` item that `DynamicArray` |
|
||||||
* has to return. |
|
||||||
* @param defaultValue Value to return if there is either no item recorded |
|
||||||
* at `index` or it has a wrong type. |
|
||||||
* @return `int` value at `index` in the caller `DynamicArray`. |
|
||||||
* `defaultValue` if passed `index` is invalid or non-`int` value |
|
||||||
* is stored there. |
|
||||||
*/ |
|
||||||
public final function int GetInt(int index, optional int defaultValue) |
|
||||||
{ |
|
||||||
local AcediaObject result; |
|
||||||
local IntBox asBox; |
|
||||||
local IntRef asRef; |
|
||||||
result = GetItem(index); |
|
||||||
if (result == none) { |
|
||||||
return defaultValue; |
|
||||||
} |
|
||||||
asBox = IntBox(result); |
|
||||||
if (asBox != none) { |
|
||||||
return asBox.Get(); |
|
||||||
} |
|
||||||
asRef = IntRef(result); |
|
||||||
if (asRef != none) { |
|
||||||
return asRef.Get(); |
|
||||||
} |
|
||||||
return defaultValue; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Changes `DynamicArray`'s value at `index` to `value` that will be recorded |
|
||||||
* as either `IntBox` or `IntRef`, depending of `asRef` optional parameter. |
|
||||||
* |
|
||||||
* Inserted value will always be recorded as a managed value, i.e. it will be |
|
||||||
* automatically deallocated when overwritten, removed or caller `DynamicArray` |
|
||||||
* is deallocated. |
|
||||||
* |
|
||||||
* @param index Index, at which to change the value. If `DynamicArray` is |
|
||||||
* not long enough to hold it, it will be automatically expanded. |
|
||||||
* If passed index is negative - method will do nothing. |
|
||||||
* @param value Value to be set at a given index. |
|
||||||
* @param asRef Given `int` value will be recorded as immutable `IntBox` |
|
||||||
* by default (`asRef == false`). Setting this parameter to `true` will |
|
||||||
* make this method record it as a mutable `IntRef`. |
|
||||||
* @return Reference to the caller `DynamicArray` to allow for method chaining. |
|
||||||
*/ |
|
||||||
public final function DynamicArray SetInt( |
|
||||||
int index, |
|
||||||
int value, |
|
||||||
optional bool asRef) |
|
||||||
{ |
|
||||||
if (asRef) { |
|
||||||
SetItem(index, _.ref.int(value), true); |
|
||||||
} |
|
||||||
else { |
|
||||||
SetItem(index, _.box.int(value), true); |
|
||||||
} |
|
||||||
return self; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Returns `float` item at `index`. If index is invalid or |
|
||||||
* stores a non-`int` value, returns `defaultValue`. |
|
||||||
* |
|
||||||
* Referred value must be stored as `FloatBox` or `FloatRef` |
|
||||||
* (or one of their sub-classes) for this method to work. |
|
||||||
* |
|
||||||
* @param index Index of a `float` item that `DynamicArray` |
|
||||||
* has to return. |
|
||||||
* @param defaultValue Value to return if there is either no item recorded |
|
||||||
* at `index` or it has a wrong type. |
|
||||||
* @return `float` value at `index` in the caller `DynamicArray`. |
|
||||||
* `defaultValue` if passed `index` is invalid or non-`float` value |
|
||||||
* is stored there. |
|
||||||
*/ |
|
||||||
public final function float GetFloat(int index, optional float defaultValue) |
|
||||||
{ |
|
||||||
local AcediaObject result; |
|
||||||
local FloatBox asBox; |
|
||||||
local FloatRef asRef; |
|
||||||
result = GetItem(index); |
|
||||||
if (result == none) { |
|
||||||
return defaultValue; |
|
||||||
} |
|
||||||
asBox = FloatBox(result); |
|
||||||
if (asBox != none) { |
|
||||||
return asBox.Get(); |
|
||||||
} |
|
||||||
asRef = FloatRef(result); |
|
||||||
if (asRef != none) { |
|
||||||
return asRef.Get(); |
|
||||||
} |
|
||||||
return defaultValue; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Changes `DynamicArray`'s value at `index` to `value` that will be recorded |
|
||||||
* as either `FloatBox` or `FloatRef`, depending of `asRef` optional parameter. |
|
||||||
* |
|
||||||
* Inserted value will always be recorded as a managed value, i.e. it will be |
|
||||||
* automatically deallocated when overwritten, removed or caller `DynamicArray` |
|
||||||
* is deallocated. |
|
||||||
* |
|
||||||
* @param index Index, at which to change the value. If `DynamicArray` is |
|
||||||
* not long enough to hold it, it will be automatically expanded. |
|
||||||
* If passed index is negative - method will do nothing. |
|
||||||
* @param value Value to be set at a given index. |
|
||||||
* @param asRef Given `float` value will be recorded as immutable `FloatBox` |
|
||||||
* by default (`asRef == false`). Setting this parameter to `true` will |
|
||||||
* make this method record it as a mutable `FloatRef`. |
|
||||||
* @return Reference to the caller `DynamicArray` to allow for method chaining. |
|
||||||
*/ |
|
||||||
public final function DynamicArray SetFloat( |
|
||||||
int index, |
|
||||||
float value, |
|
||||||
optional bool asRef) |
|
||||||
{ |
|
||||||
if (asRef) { |
|
||||||
SetItem(index, _.ref.float(value), true); |
|
||||||
} |
|
||||||
else { |
|
||||||
SetItem(index, _.box.float(value), true); |
|
||||||
} |
|
||||||
return self; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Returns `Text` item at `index`. If index is invalid or |
|
||||||
* stores a non-`Text` value, returns `none`. |
|
||||||
* |
|
||||||
* Referred value must be stored as `Text` (or one of it's sub-classes, |
|
||||||
* such as `MutableText`) for this method to work. |
|
||||||
* |
|
||||||
* @param index Index of a `Text` item that `DynamicArray` has to return. |
|
||||||
* @return `Text` value at `index` in the caller `DynamicArray`. |
|
||||||
* `none` if passed `index` is invalid or non-`Text` value |
|
||||||
* is stored there. |
|
||||||
*/ |
|
||||||
public final function Text GetText(int index) |
|
||||||
{ |
|
||||||
return Text(GetItem(index)); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Returns `AssociativeArray` item at `index`. If index is invalid or |
|
||||||
* stores a non-`AssociativeArray` value, returns `none`. |
|
||||||
* |
|
||||||
* Referred value must be stored as `AssociativeArray` |
|
||||||
* (or one of it's sub-classes) for this method to work. |
|
||||||
* |
|
||||||
* @param index Index of an `AssociativeArray` item that `DynamicArray` |
|
||||||
* has to return. |
|
||||||
* @return `AssociativeArray` value at `index` in the caller `DynamicArray`. |
|
||||||
* `none` if passed `index` is invalid or non-`AssociativeArray` value |
|
||||||
* is stored there. |
|
||||||
*/ |
|
||||||
public final function AssociativeArray GetAssociativeArray(int index) |
|
||||||
{ |
|
||||||
return AssociativeArray(GetItem(index)); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Returns `DynamicArray` item at `index`. If index is invalid or |
|
||||||
* stores a non-`DynamicArray` value, returns `none`. |
|
||||||
* |
|
||||||
* Referred value must be stored as `Text` (or one of it's sub-classes, |
|
||||||
* such as `MutableText`) for this method to work. |
|
||||||
* |
|
||||||
* @param index Index of a `DynamicArray` item that caller `DynamicArray` |
|
||||||
* has to return. |
|
||||||
* @return `DynamicArray` value at `index` in the caller `DynamicArray`. |
|
||||||
* `none` if passed `index` is invalid or non-`DynamicArray` value |
|
||||||
* is stored there. |
|
||||||
*/ |
|
||||||
public final function DynamicArray GetDynamicArray(int index) |
|
||||||
{ |
|
||||||
return DynamicArray(GetItem(index)); |
|
||||||
} |
|
||||||
|
|
||||||
defaultproperties |
|
||||||
{ |
|
||||||
iteratorClass = class'DynamicArrayIterator' |
|
||||||
} |
|
@ -1,80 +0,0 @@ |
|||||||
/** |
|
||||||
* Iterator for iterating over `DynamicArray`'s items. |
|
||||||
* 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 <https://www.gnu.org/licenses/>. |
|
||||||
*/ |
|
||||||
class DynamicArrayIterator extends CollectionIterator; |
|
||||||
|
|
||||||
var private DynamicArray relevantCollection; |
|
||||||
var private int currentIndex; |
|
||||||
|
|
||||||
protected function Finalizer() |
|
||||||
{ |
|
||||||
relevantCollection = none; |
|
||||||
} |
|
||||||
|
|
||||||
public function bool Initialize(Collection relevantArray) |
|
||||||
{ |
|
||||||
currentIndex = 0; |
|
||||||
relevantCollection = DynamicArray(relevantArray); |
|
||||||
if (relevantCollection == none) { |
|
||||||
return false; |
|
||||||
} |
|
||||||
return true; |
|
||||||
} |
|
||||||
|
|
||||||
public function Iter Next(optional bool skipNone) |
|
||||||
{ |
|
||||||
local int collectionLength; |
|
||||||
if (!skipNone) |
|
||||||
{ |
|
||||||
currentIndex += 1; |
|
||||||
return self; |
|
||||||
} |
|
||||||
collectionLength = relevantCollection.GetLength(); |
|
||||||
while (currentIndex < collectionLength) |
|
||||||
{ |
|
||||||
currentIndex += 1; |
|
||||||
if (relevantCollection.GetItem(currentIndex) != none) { |
|
||||||
return self; |
|
||||||
} |
|
||||||
} |
|
||||||
return self; |
|
||||||
} |
|
||||||
|
|
||||||
public function AcediaObject Get() |
|
||||||
{ |
|
||||||
return relevantCollection.GetItem(currentIndex); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Note that for `DynamicArrayIterator` this method produces a new `IntBox` |
|
||||||
* object each time and requires manual deallocation. |
|
||||||
*/ |
|
||||||
public function AcediaObject GetKey() |
|
||||||
{ |
|
||||||
return _.box.int(currentIndex); |
|
||||||
} |
|
||||||
|
|
||||||
public function bool HasFinished() |
|
||||||
{ |
|
||||||
return currentIndex >= relevantCollection.GetLength(); |
|
||||||
} |
|
||||||
|
|
||||||
defaultproperties |
|
||||||
{ |
|
||||||
} |
|
@ -1,488 +0,0 @@ |
|||||||
/** |
|
||||||
* Set of tests for `AssociativeArray` class. |
|
||||||
* 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 <https://www.gnu.org/licenses/>. |
|
||||||
*/ |
|
||||||
class TEST_AssociativeArray extends TestCase |
|
||||||
abstract; |
|
||||||
|
|
||||||
protected static function TESTS() |
|
||||||
{ |
|
||||||
Test_GetSet(); |
|
||||||
Test_HasKey(); |
|
||||||
Test_GetKeys(); |
|
||||||
Test_CopyTextKeys(); |
|
||||||
Test_Remove(); |
|
||||||
Test_CreateItem(); |
|
||||||
Test_Empty(); |
|
||||||
Test_Length(); |
|
||||||
Test_Managed(); |
|
||||||
Test_DeallocationHandling(); |
|
||||||
Test_Take(); |
|
||||||
Test_LargeArray(); |
|
||||||
} |
|
||||||
|
|
||||||
protected static function Test_GetSet() |
|
||||||
{ |
|
||||||
local Text textObject; |
|
||||||
local AssociativeArray array; |
|
||||||
array = AssociativeArray(__().memory.Allocate(class'AssociativeArray')); |
|
||||||
|
|
||||||
Context("Testing getters and setters for items of `AssociativeArray`."); |
|
||||||
Issue("`SetItem()` does not correctly set new items."); |
|
||||||
textObject = __().text.FromString("value"); |
|
||||||
array.SetItem(__().text.FromString("key"), textObject); |
|
||||||
array.SetItem(__().box.int(13), __().text.FromString("value #2")); |
|
||||||
array.SetItem(__().box.float(345.2), __().box.bool(true)); |
|
||||||
TEST_ExpectTrue( Text(array.GetItem(__().box.int(13))).ToString() |
|
||||||
== "value #2"); |
|
||||||
TEST_ExpectTrue(array.GetItem(__().text.FromString("key")) == textObject); |
|
||||||
TEST_ExpectTrue(BoolBox(array.GetItem(__().box.float(345.2))).Get()); |
|
||||||
|
|
||||||
Issue("`SetItem()` does not correctly overwrite new items."); |
|
||||||
array.SetItem(__().text.FromString("key"), __().text.FromString("value")); |
|
||||||
array.SetItem(__().box.int(13), __().box.int(11)); |
|
||||||
TEST_ExpectFalse(array.GetItem(__().text.FromString("key")) == textObject); |
|
||||||
TEST_ExpectTrue( Text(array.GetItem(__().text.FromString("key"))) |
|
||||||
.ToString() == "value"); |
|
||||||
TEST_ExpectTrue( IntBox(array.GetItem(__().box.int(13))).Get() |
|
||||||
== 11); |
|
||||||
|
|
||||||
Issue("`GetItem()` does not return `none` for non-existing keys."); |
|
||||||
TEST_ExpectNone(array.GetItem(__().box.int(12))); |
|
||||||
TEST_ExpectNone(array.GetItem(__().box.byte(67))); |
|
||||||
TEST_ExpectNone(array.GetItem(__().box.float(43.1234))); |
|
||||||
TEST_ExpectNone(array.GetItem(__().text.FromString("Some random stuff"))); |
|
||||||
} |
|
||||||
|
|
||||||
protected static function Test_HasKey() |
|
||||||
{ |
|
||||||
local AssociativeArray array; |
|
||||||
array = AssociativeArray(__().memory.Allocate(class'AssociativeArray')); |
|
||||||
Context("Testing `HasKey()` method for `AssociativeArray`."); |
|
||||||
array.SetItem(__().text.FromString("key"), __().text.FromString("value")); |
|
||||||
array.SetItem(__().box.int(13), __().text.FromString("value #2")); |
|
||||||
array.SetItem(__().box.float(345.2), __().box.bool(true)); |
|
||||||
Issue("`HasKey()` reports that added keys do not exist in" |
|
||||||
@ "`AssociativeArray`."); |
|
||||||
TEST_ExpectTrue(array.HasKey(__().text.FromString("key"))); |
|
||||||
TEST_ExpectTrue(array.HasKey(__().box.int(13))); |
|
||||||
TEST_ExpectTrue(array.HasKey(__().box.float(345.2))); |
|
||||||
|
|
||||||
Issue("`HasKey()` reports that `AssociativeArray` contains keys that" |
|
||||||
@ "were never added."); |
|
||||||
TEST_ExpectFalse(array.HasKey(none)); |
|
||||||
TEST_ExpectFalse(array.HasKey(__().box.float(13))); |
|
||||||
TEST_ExpectFalse(array.HasKey(__().box.byte(139))); |
|
||||||
} |
|
||||||
|
|
||||||
protected static function Test_GetKeys() |
|
||||||
{ |
|
||||||
local int i; |
|
||||||
local AcediaObject key1, key2, key3; |
|
||||||
local array<AcediaObject> keys; |
|
||||||
local AssociativeArray array; |
|
||||||
array = AssociativeArray(__().memory.Allocate(class'AssociativeArray')); |
|
||||||
Context("Testing `GetKeys()` method for `AssociativeArray`."); |
|
||||||
key1 = __().text.FromString("key"); |
|
||||||
key2 = __().box.int(13); |
|
||||||
key3 = __().box.float(345.2); |
|
||||||
array.SetItem(key1, __().text.FromString("value")); |
|
||||||
array.SetItem(key2, __().text.FromString("value #2")); |
|
||||||
array.SetItem(key3, __().box.bool(true)); |
|
||||||
keys = array.GetKeys(); |
|
||||||
Issue("`GetKeys()` returns array with wrong amount of elements."); |
|
||||||
TEST_ExpectTrue(keys.length == 3); |
|
||||||
|
|
||||||
Issue("`GetKeys()` returns array with duplicate keys."); |
|
||||||
TEST_ExpectTrue(keys[0] != keys[1]); |
|
||||||
TEST_ExpectTrue(keys[0] != keys[2]); |
|
||||||
TEST_ExpectTrue(keys[1] != keys[2]); |
|
||||||
|
|
||||||
Issue("`GetKeys()` returns array with incorrect keys."); |
|
||||||
for (i = 0; i < 3; i += 1) { |
|
||||||
TEST_ExpectTrue(keys[i] == key1 || keys[i] == key2 || keys[i] == key3); |
|
||||||
} |
|
||||||
|
|
||||||
keys = array.RemoveItem(key1).GetKeys(); |
|
||||||
Issue("`GetKeys()` returns array with incorrect keys after removing" |
|
||||||
@ "an element."); |
|
||||||
TEST_ExpectTrue(keys.length == 2); |
|
||||||
TEST_ExpectTrue(keys[0] != keys[1]); |
|
||||||
for (i = 0; i < 2; i += 1) { |
|
||||||
TEST_ExpectTrue(keys[i] == key2 || keys[i] == key3); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
protected static function Test_CopyTextKeys() |
|
||||||
{ |
|
||||||
local array<AcediaObject> allKeys; |
|
||||||
local array<Text> keys; |
|
||||||
local AssociativeArray array; |
|
||||||
array = AssociativeArray(__().memory.Allocate(class'AssociativeArray')); |
|
||||||
Context("Testing `CopyTextKeys()` method for `AssociativeArray`."); |
|
||||||
array.SetItem(__().text.FromString("key"), __().text.FromString("value")); |
|
||||||
array.SetItem(__().box.int(13), __().text.FromString("value #2")); |
|
||||||
array.SetItem(__().box.float(-925.274), __().text.FromString("value #2")); |
|
||||||
array.SetItem(__().text.FromString("second key"), __().box.bool(true)); |
|
||||||
|
|
||||||
Issue("`CopyTextKeys()` does not return correct set of keys."); |
|
||||||
keys = array.CopyTextKeys(); |
|
||||||
TEST_ExpectTrue(keys.length == 2); |
|
||||||
TEST_ExpectTrue( |
|
||||||
(keys[0].ToString() == "key" |
|
||||||
&& keys[1].ToString() == "second key") |
|
||||||
|| (keys[0].ToString() == "second key" |
|
||||||
&& keys[1].ToString() == "key")); |
|
||||||
|
|
||||||
Issue("Deallocating keys returned by `CopyTextKeys()` affects their" |
|
||||||
@ "source collection."); |
|
||||||
allKeys = array.GetKeys(); |
|
||||||
TEST_ExpectTrue(allKeys.length == 4); |
|
||||||
TEST_ExpectNotNone(array.GetItem(__().text.FromString("key"))); |
|
||||||
TEST_ExpectNotNone(array.GetItem(__().text.FromString("second key"))); |
|
||||||
TEST_ExpectTrue( |
|
||||||
array.GetText(__().text.FromString("key")).ToString() == "value"); |
|
||||||
} |
|
||||||
|
|
||||||
protected static function Test_Remove() |
|
||||||
{ |
|
||||||
Context("Testing removing elements from `AssociativeArray`."); |
|
||||||
SubTest_RemoveWithoutKeys(); |
|
||||||
SubTest_RemoveWithKeys(); |
|
||||||
} |
|
||||||
|
|
||||||
protected static function SubTest_RemoveWithoutKeys() |
|
||||||
{ |
|
||||||
local AcediaObject key1, key2, key3; |
|
||||||
local array<AcediaObject> keys; |
|
||||||
local AssociativeArray array; |
|
||||||
array = AssociativeArray(__().memory.Allocate(class'AssociativeArray')); |
|
||||||
key1 = __().text.FromString("some key"); |
|
||||||
key2 = __().box.int(25); |
|
||||||
key3 = __().box.float(0.07); |
|
||||||
array.SetItem(key1, __().text.FromString("value")); |
|
||||||
array.SetItem(key2, __().text.FromString("value #2")); |
|
||||||
array.SetItem(key3, __().box.bool(true)); |
|
||||||
Issue("Elements are not properly removed from `AssociativeArray`."); |
|
||||||
array.RemoveItem(key1) |
|
||||||
.RemoveItem(__().box.int(25)) |
|
||||||
.RemoveItem(__().box.float(0.06)); |
|
||||||
keys = array.GetKeys(); |
|
||||||
TEST_ExpectTrue(array.GetLength() == 1); |
|
||||||
TEST_ExpectTrue(keys.length == 1); |
|
||||||
TEST_ExpectTrue(keys[0] == key3); |
|
||||||
|
|
||||||
Issue("Keys are deallocated upon removing elements from `AssociativeArray`" |
|
||||||
@ "when they should not."); |
|
||||||
TEST_ExpectTrue(key1.IsAllocated()); |
|
||||||
TEST_ExpectTrue(key2.IsAllocated()); |
|
||||||
} |
|
||||||
|
|
||||||
protected static function SubTest_RemoveWithKeys() |
|
||||||
{ |
|
||||||
local AcediaObject key1, key2, key3; |
|
||||||
local array<AcediaObject> keys; |
|
||||||
local AssociativeArray array; |
|
||||||
array = AssociativeArray(__().memory.Allocate(class'AssociativeArray')); |
|
||||||
key1 = __().text.FromString("some key"); |
|
||||||
key2 = __().box.int(25); |
|
||||||
key3 = __().box.float(0.07); |
|
||||||
array.SetItem(key1, __().text.FromString("value")); |
|
||||||
array.SetItem(key2, __().text.FromString("value #2")); |
|
||||||
array.SetItem(key3, __().box.bool(true)); |
|
||||||
Issue("Elements are not properly removed from `AssociativeArray`."); |
|
||||||
array.RemoveItem(key1, true) |
|
||||||
.RemoveItem(__().box.int(25), true) |
|
||||||
.RemoveItem(__().box.float(0.06), true); |
|
||||||
keys = array.GetKeys(); |
|
||||||
TEST_ExpectTrue(array.GetLength() == 1); |
|
||||||
TEST_ExpectTrue(keys.length == 1); |
|
||||||
TEST_ExpectTrue(keys[0] == key3); |
|
||||||
|
|
||||||
Issue("Keys are not deallocated upon removing elements from" |
|
||||||
@ "`AssociativeArray` when they should."); |
|
||||||
TEST_ExpectFalse(key1.IsAllocated()); |
|
||||||
TEST_ExpectFalse(key2.IsAllocated()); |
|
||||||
} |
|
||||||
|
|
||||||
protected static function Test_CreateItem() |
|
||||||
{ |
|
||||||
local AssociativeArray array; |
|
||||||
array = AssociativeArray(__().memory.Allocate(class'AssociativeArray')); |
|
||||||
Context("Testing creating brand new items for `AssociativeArray`."); |
|
||||||
Issue("`CreateItem()` incorrectly adds new values to the" |
|
||||||
@ "`AssociativeArray`."); |
|
||||||
array.CreateItem(__().text.FromString("key"), class'Text'); |
|
||||||
array.CreateItem(__().box.float(17.895), class'IntRef'); |
|
||||||
array.CreateItem(__().text.FromString("key #2"), class'BoolBox'); |
|
||||||
TEST_ExpectTrue(Text(array.GetItem(__().text.FromString("key"))) |
|
||||||
.ToString() == ""); |
|
||||||
TEST_ExpectTrue( IntRef(array.GetItem(__().box.float(17.895))).Get() |
|
||||||
== 0); |
|
||||||
TEST_ExpectFalse(BoolBox(array.GetItem(__().text.FromString("key #2"))) |
|
||||||
.Get()); |
|
||||||
|
|
||||||
Issue("`CreateItem()` incorrectly overrides existing values in the" |
|
||||||
@ "`AssociativeArray`."); |
|
||||||
array.SetItem(__().box.int(13), __().ref.int(7)); |
|
||||||
array.CreateItem(__().box.int(13), class'StringRef'); |
|
||||||
TEST_ExpectTrue( StringRef(array.GetItem(__().box.int(13))).Get() |
|
||||||
== ""); |
|
||||||
|
|
||||||
class'MockItem'.default.objectCount = 0; |
|
||||||
Issue("`CreateItem()` creates new object even if it cannot be recorded with" |
|
||||||
@ "a given key."); |
|
||||||
array.CreateItem(none, class'MockItem'); |
|
||||||
TEST_ExpectTrue(class'MockItem'.default.objectCount == 0); |
|
||||||
} |
|
||||||
|
|
||||||
protected static function Test_Empty() |
|
||||||
{ |
|
||||||
local AcediaObject key1, key2, key3; |
|
||||||
local AssociativeArray array; |
|
||||||
key1 = __().text.FromString("key"); |
|
||||||
key2 = __().box.int(13); |
|
||||||
key3 = __().box.float(345.2); |
|
||||||
array = AssociativeArray(__().memory.Allocate(class'AssociativeArray')); |
|
||||||
array.SetItem(key1, __().text.FromString("value")); |
|
||||||
array.SetItem(key2, __().text.FromString("value #2"), true); |
|
||||||
array.SetItem(key3, __().box.bool(true)); |
|
||||||
|
|
||||||
Context("Testing `Empty()` method for `AssociativeArray`."); |
|
||||||
Issue("`AssociativeArray` still contains elements after being emptied."); |
|
||||||
array.Empty(); |
|
||||||
TEST_ExpectTrue(array.GetKeys().length == 0); |
|
||||||
TEST_ExpectTrue(array.GetLength() == 0); |
|
||||||
|
|
||||||
Issue("`AssociativeArray` deallocated keys when not being told to do so."); |
|
||||||
TEST_ExpectTrue(key1.IsAllocated()); |
|
||||||
TEST_ExpectTrue(key2.IsAllocated()); |
|
||||||
TEST_ExpectTrue(key3.IsAllocated()); |
|
||||||
|
|
||||||
Issue("`AssociativeArray` still contains elements after being emptied."); |
|
||||||
array.SetItem(key1, __().text.FromString("value"), true); |
|
||||||
array.SetItem(key2, __().text.FromString("value #2")); |
|
||||||
array.SetItem(key3, __().box.bool(true), true); |
|
||||||
array.Empty(true); |
|
||||||
TEST_ExpectTrue(array.GetKeys().length == 0); |
|
||||||
TEST_ExpectTrue(array.GetLength() == 0); |
|
||||||
|
|
||||||
Issue("`AssociativeArray` does not deallocate keys when told to do so."); |
|
||||||
TEST_ExpectFalse(key1.IsAllocated()); |
|
||||||
TEST_ExpectFalse(key2.IsAllocated()); |
|
||||||
TEST_ExpectFalse(key3.IsAllocated()); |
|
||||||
} |
|
||||||
|
|
||||||
protected static function Test_Length() |
|
||||||
{ |
|
||||||
local AssociativeArray array; |
|
||||||
array = AssociativeArray(__().memory.Allocate(class'AssociativeArray')); |
|
||||||
Context("Testing computing length of `AssociativeArray`."); |
|
||||||
Issue("Length is not zero for newly created `AssociativeArray`."); |
|
||||||
TEST_ExpectTrue(array.GetLength() == 0); |
|
||||||
|
|
||||||
Issue("Length is incorrectly computed after adding elements to" |
|
||||||
@ "`AssociativeArray`."); |
|
||||||
array.SetItem(__().text.FromString("key"), __().text.FromString("value")); |
|
||||||
array.SetItem(__().box.int(4563), __().text.FromString("value #2")); |
|
||||||
array.SetItem(__().box.float(3425.243), __().box.byte(23)); |
|
||||||
TEST_ExpectTrue(array.GetLength() == 3); |
|
||||||
|
|
||||||
Issue("Length is incorrectly computed after removing elements from" |
|
||||||
@ "`AssociativeArray`."); |
|
||||||
array.RemoveItem(__().box.int(4563)); |
|
||||||
TEST_ExpectTrue(array.GetLength() == 2); |
|
||||||
} |
|
||||||
|
|
||||||
protected static function MockItem NewMockItem() |
|
||||||
{ |
|
||||||
return MockItem(__().memory.Allocate(class'MockItem')); |
|
||||||
} |
|
||||||
|
|
||||||
protected static function Test_Managed() |
|
||||||
{ |
|
||||||
local AssociativeArray array; |
|
||||||
class'MockItem'.default.objectCount = 0; |
|
||||||
array = AssociativeArray(__().memory.Allocate(class'AssociativeArray')); |
|
||||||
array.SetItem(__().box.int(0), NewMockItem()); |
|
||||||
array.SetItem(__().box.int(1), NewMockItem()); |
|
||||||
array.SetItem(__().box.int(2), NewMockItem()); |
|
||||||
array.SetItem(__().box.int(3), NewMockItem(), true); |
|
||||||
array.SetItem(__().box.int(4), NewMockItem(), true); |
|
||||||
array.SetItem(__().box.int(5), NewMockItem(), true); |
|
||||||
array.CreateItem(__().box.int(6), class'MockItem'); |
|
||||||
array.CreateItem(__().box.int(7), class'MockItem'); |
|
||||||
array.CreateItem(__().box.int(8), class'MockItem'); |
|
||||||
Context("Testing how `AssociativeArray` deallocates managed objects."); |
|
||||||
Issue("`RemoveItem()` incorrectly deallocates managed items."); |
|
||||||
array.RemoveItem(__().box.int(0)); |
|
||||||
array.RemoveItem(__().box.int(3)); |
|
||||||
array.RemoveItem(__().box.int(6)); |
|
||||||
TEST_ExpectTrue(class'MockItem'.default.objectCount == 7); |
|
||||||
|
|
||||||
Issue("Rewriting values with `SetItem()` incorrectly handles" |
|
||||||
@ "managed items."); |
|
||||||
array.SetItem(__().box.int(1), __().ref.int(28347)); |
|
||||||
array.SetItem(__().box.int(4), __().ref.float(13.4)); |
|
||||||
array.SetItem(__().box.int(7), __().ref.byte(94)); |
|
||||||
TEST_ExpectTrue(class'MockItem'.default.objectCount == 5); |
|
||||||
|
|
||||||
Issue("Rewriting values with `CreateItem()` incorrectly handles" |
|
||||||
@ "managed items."); |
|
||||||
array.CreateItem(__().box.int(2), class'IntRef'); |
|
||||||
array.CreateItem(__().box.int(5), class'StringRef'); |
|
||||||
array.CreateItem(__().box.int(8), class'IntArrayBox'); |
|
||||||
TEST_ExpectTrue(class'MockItem'.default.objectCount == 3); |
|
||||||
} |
|
||||||
|
|
||||||
protected static function Test_DeallocationHandling() |
|
||||||
{ |
|
||||||
Context("Testing how `AssociativeArray` deals with external deallocation of" |
|
||||||
@ "keys and managed objects."); |
|
||||||
SubTest_DeallocationHandlingKeys(); |
|
||||||
SubTest_DeallocationHandlingManagedObjects(); |
|
||||||
} |
|
||||||
|
|
||||||
protected static function SubTest_DeallocationHandlingKeys() |
|
||||||
{ |
|
||||||
local IntBox key1; |
|
||||||
local BoolBox key2; |
|
||||||
local Text key3; |
|
||||||
local AssociativeArray array; |
|
||||||
local array<AcediaObject> keys; |
|
||||||
key1 = __().box.int(3881); |
|
||||||
key2 = __().box.bool(true); |
|
||||||
key3 = __().text.FromString("Text key, bay bee"); |
|
||||||
array = AssociativeArray(__().memory.Allocate(class'AssociativeArray')); |
|
||||||
class'MockItem'.default.objectCount = 0; |
|
||||||
array.SetItem(key1, NewMockItem()); |
|
||||||
array.SetItem(key2, __().box.float(32.31), true); |
|
||||||
array.SetItem(key3, NewMockItem(), true); |
|
||||||
|
|
||||||
Issue("Deallocating keys does not remove them from `AssociativeArray`."); |
|
||||||
key1.FreeSelf(); |
|
||||||
key3.FreeSelf(); |
|
||||||
keys = array.GetKeys(); |
|
||||||
TEST_ExpectTrue(keys.length == 1); |
|
||||||
TEST_ExpectTrue(keys[0] == key2); |
|
||||||
|
|
||||||
Issue("`AssociativeArray` does not deallocate managed objects, even though" |
|
||||||
@ "their keys were deallocated"); |
|
||||||
TEST_ExpectTrue(class'MockItem'.default.objectCount < 2); |
|
||||||
TEST_ExpectNone(array.GetItem(__().box.int(3881))); |
|
||||||
|
|
||||||
Issue("`AssociativeArray` deallocates unmanaged objects, when" |
|
||||||
@ "their keys were deallocated"); |
|
||||||
TEST_ExpectTrue(class'MockItem'.default.objectCount > 0); |
|
||||||
} |
|
||||||
|
|
||||||
protected static function SubTest_DeallocationHandlingManagedObjects() |
|
||||||
{ |
|
||||||
local MockItem exampleItem; |
|
||||||
local AssociativeArray array; |
|
||||||
class'MockItem'.default.objectCount = 0; |
|
||||||
exampleItem = NewMockItem(); |
|
||||||
array = AssociativeArray(__().memory.Allocate(class'AssociativeArray')); |
|
||||||
array.SetItem(__().box.int(-34), exampleItem, true); |
|
||||||
array.SetItem(__().box.int(-7), exampleItem, true); |
|
||||||
array.SetItem(__().box.int(23), NewMockItem()); |
|
||||||
array.SetItem(__().box.int(242), NewMockItem(), true); |
|
||||||
array.CreateItem(__().box.int(24532), class'MockItem'); |
|
||||||
Issue("`AssociativeArray` does not return `none` even though stored object" |
|
||||||
@ "was already deallocated."); |
|
||||||
array.GetItem(__().box.int(23)).FreeSelf(); |
|
||||||
TEST_ExpectTrue(class'MockItem'.default.objectCount == 3); |
|
||||||
TEST_ExpectTrue(array.GetItem(__().box.int(23)) == none); |
|
||||||
|
|
||||||
Issue("Managed items are not deallocated when they are duplicated inside" |
|
||||||
@ "`AssociativeArray`, but they should."); |
|
||||||
array.RemoveItem(__().box.int(-7)); |
|
||||||
// At this point we got rid of all the managed objects that were generated |
|
||||||
// in `array` + deallocated `exampleObject`. |
|
||||||
TEST_ExpectTrue(class'MockItem'.default.objectCount == 2); |
|
||||||
TEST_ExpectTrue(array.GetItem(__().box.int(-34)) == none); |
|
||||||
} |
|
||||||
|
|
||||||
protected static function Test_Take() |
|
||||||
{ |
|
||||||
local AssociativeArray.Entry entry; |
|
||||||
local AssociativeArray array; |
|
||||||
class'MockItem'.default.objectCount = 0; |
|
||||||
array = AssociativeArray(__().memory.Allocate(class'AssociativeArray')); |
|
||||||
array.SetItem(__().box.int(0), NewMockItem()); |
|
||||||
array.SetItem(__().box.int(1), NewMockItem()); |
|
||||||
array.SetItem(__().box.int(2), NewMockItem()); |
|
||||||
array.SetItem(__().box.int(3), NewMockItem(), true); |
|
||||||
array.SetItem(__().box.int(4), NewMockItem(), true); |
|
||||||
array.SetItem(__().box.int(5), NewMockItem(), true); |
|
||||||
array.CreateItem(__().box.int(6), class'MockItem'); |
|
||||||
array.CreateItem(__().box.int(7), class'MockItem'); |
|
||||||
array.CreateItem(__().box.int(8), class'MockItem'); |
|
||||||
Context("Testing `TakeItem()` method of `AssociativeArray`."); |
|
||||||
Issue("`TakeItem()` returns incorrect value."); |
|
||||||
TEST_ExpectTrue(array.TakeItem(__().box.int(0)).class == class'MockItem'); |
|
||||||
TEST_ExpectTrue(array.TakeItem(__().box.int(3)).class == class'MockItem'); |
|
||||||
TEST_ExpectTrue(array.TakeItem(__().box.int(6)).class == class'MockItem'); |
|
||||||
|
|
||||||
Issue("`TakeEntry()` returns incorrect value."); |
|
||||||
entry = array.TakeEntry(__().box.int(4)); |
|
||||||
TEST_ExpectTrue(entry.key.class == class'IntBox'); |
|
||||||
TEST_ExpectTrue(entry.value.class == class'MockItem'); |
|
||||||
entry = array.TakeEntry(__().box.int(7)); |
|
||||||
TEST_ExpectTrue(entry.key.class == class'IntBox'); |
|
||||||
TEST_ExpectTrue(entry.value.class == class'MockItem'); |
|
||||||
|
|
||||||
Issue("Objects returned by `Take()` and `takeEntry()` are still managed by" |
|
||||||
@ "`AssociativeArray`."); |
|
||||||
array.Empty(); |
|
||||||
TEST_ExpectTrue(class'MockItem'.default.objectCount == 7); |
|
||||||
} |
|
||||||
|
|
||||||
protected static function Test_LargeArray() |
|
||||||
{ |
|
||||||
local int i; |
|
||||||
local AcediaObject nextKey; |
|
||||||
local AssociativeArray array; |
|
||||||
Context("Testing storing large amount of elements in `AssociativeArray`."); |
|
||||||
Issue("`AssociativeArray` cannot handle large amount of elements."); |
|
||||||
array = AssociativeArray(__().memory.Allocate(class'AssociativeArray')); |
|
||||||
for (i = 0; i < 2500; i += 1) { |
|
||||||
if (i % 2 == 0) { |
|
||||||
nextKey = __().text.FromString("var" @ i); |
|
||||||
} |
|
||||||
else { |
|
||||||
nextKey = __().box.int(i * 56 - 435632); |
|
||||||
} |
|
||||||
array.SetItem(nextKey, __().ref.int(i)); |
|
||||||
} |
|
||||||
for (i = 0; i < 2500; i += 1) { |
|
||||||
if (i % 2 == 0) { |
|
||||||
nextKey = __().text.FromString("var" @ i); |
|
||||||
} |
|
||||||
else { |
|
||||||
nextKey = __().box.int(i * 56 - 435632); |
|
||||||
} |
|
||||||
TEST_ExpectTrue(IntRef(array.GetItem(nextKey)).Get() == i); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
defaultproperties |
|
||||||
{ |
|
||||||
caseGroup = "Collections" |
|
||||||
caseName = "AssociativeArray" |
|
||||||
} |
|
@ -1,322 +0,0 @@ |
|||||||
/** |
|
||||||
* Set of tests for `DynamicArray` class. |
|
||||||
* 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 <https://www.gnu.org/licenses/>. |
|
||||||
*/ |
|
||||||
class TEST_DynamicArray extends TestCase |
|
||||||
abstract; |
|
||||||
|
|
||||||
protected static function TESTS() |
|
||||||
{ |
|
||||||
Test_GetSet(); |
|
||||||
Test_CreateItem(); |
|
||||||
Test_Length(); |
|
||||||
Test_Empty(); |
|
||||||
Test_AddInsert(); |
|
||||||
Test_Remove(); |
|
||||||
Test_Find(); |
|
||||||
Test_Managed(); |
|
||||||
Test_DeallocationHandling(); |
|
||||||
Test_Take(); |
|
||||||
} |
|
||||||
|
|
||||||
protected static function Test_GetSet() |
|
||||||
{ |
|
||||||
local DynamicArray array; |
|
||||||
array = DynamicArray(__().memory.Allocate(class'DynamicArray')); |
|
||||||
Context("Testing getters and setters for items of `DynamicArray`."); |
|
||||||
Issue("Setters do not correctly expand `DynamicArray`."); |
|
||||||
array.SetItem(0, __().box.int(-9)).SetItem(2, __().text.FromString("text")); |
|
||||||
TEST_ExpectTrue(array.GetLength() == 3); |
|
||||||
TEST_ExpectTrue(IntBox(array.GetItem(0)).Get() == -9); |
|
||||||
TEST_ExpectNone(array.GetItem(1)); |
|
||||||
TEST_ExpectTrue(Text(array.GetItem(2)).ToString() == "text"); |
|
||||||
|
|
||||||
Issue("Setters do not correctly overwrite items of `DynamicArray`."); |
|
||||||
array.SetItem(1, __().box.float(34.76)); |
|
||||||
array.SetItem(2, none); |
|
||||||
TEST_ExpectTrue(array.GetLength() == 3); |
|
||||||
TEST_ExpectTrue(IntBox(array.GetItem(0)).Get() == -9); |
|
||||||
TEST_ExpectTrue(FloatBox(array.GetItem(1)).Get() == 34.76); |
|
||||||
TEST_ExpectNone(array.GetItem(2)); |
|
||||||
} |
|
||||||
|
|
||||||
protected static function Test_CreateItem() |
|
||||||
{ |
|
||||||
local DynamicArray array; |
|
||||||
array = DynamicArray(__().memory.Allocate(class'DynamicArray')); |
|
||||||
Context("Testing creating brand new items for `DynamicArray`."); |
|
||||||
Issue("`CreateItem()` incorrectly adds new values to the" |
|
||||||
@ "`DynamicArray`."); |
|
||||||
array.CreateItem(1, class'Text'); |
|
||||||
array.CreateItem(3, class'IntRef'); |
|
||||||
array.CreateItem(4, class'BoolBox'); |
|
||||||
TEST_ExpectNone(array.GetItem(0)); |
|
||||||
TEST_ExpectNone(array.GetItem(2)); |
|
||||||
TEST_ExpectTrue(Text(array.GetItem(1)).ToString() == ""); |
|
||||||
TEST_ExpectTrue(IntRef(array.GetItem(3)).Get() == 0); |
|
||||||
TEST_ExpectFalse(BoolBox(array.GetItem(4)).Get()); |
|
||||||
|
|
||||||
Issue("`CreateItem()` incorrectly overrides existing values in the" |
|
||||||
@ "`DynamicArray`."); |
|
||||||
array.SetItem(5, __().ref.int(7)); |
|
||||||
array.CreateItem(5, class'StringRef'); |
|
||||||
TEST_ExpectTrue(StringRef(array.GetItem(5)).Get() == ""); |
|
||||||
|
|
||||||
class'MockItem'.default.objectCount = 0; |
|
||||||
Issue("`CreateItem()` creates new object even if it cannot be recorded at" |
|
||||||
@ "a given index."); |
|
||||||
array.CreateItem(-1, class'MockItem'); |
|
||||||
TEST_ExpectTrue(class'MockItem'.default.objectCount == 0); |
|
||||||
} |
|
||||||
|
|
||||||
protected static function Test_Length() |
|
||||||
{ |
|
||||||
local DynamicArray array; |
|
||||||
array = DynamicArray(__().memory.Allocate(class'DynamicArray')); |
|
||||||
Context("Testing length getter and setter for `DynamicArray`."); |
|
||||||
Issue("Length of just created `DynamicArray` is not zero."); |
|
||||||
TEST_ExpectTrue(array.GetLength() == 0); |
|
||||||
|
|
||||||
Issue("`SetLength()` incorrectly changes length of the `DynamicArray`."); |
|
||||||
array.SetLength(200).SetItem(198, __().box.int(25)); |
|
||||||
TEST_ExpectTrue(array.GetLength() == 200); |
|
||||||
TEST_ExpectTrue(IntBox(array.GetItem(198)).Get() == 25); |
|
||||||
array.SetLength(0); |
|
||||||
TEST_ExpectTrue(array.GetLength() == 0); |
|
||||||
|
|
||||||
Issue("Shrinking size of `DynamicArray` does not remove recorded items."); |
|
||||||
array.SetLength(1000); |
|
||||||
TEST_ExpectNone(array.GetItem(198)); |
|
||||||
} |
|
||||||
|
|
||||||
protected static function Test_Empty() |
|
||||||
{ |
|
||||||
local DynamicArray array; |
|
||||||
array = DynamicArray(__().memory.Allocate(class'DynamicArray')); |
|
||||||
Context("Testing emptying `DynamicArray`."); |
|
||||||
array.AddItem(__().box.int(1)).AddItem(__().box.int(3)) |
|
||||||
.AddItem(__().box.int(1)).AddItem(__().box.int(3)); |
|
||||||
Issue("`Empty()` does not produce an empty array."); |
|
||||||
array.Empty(); |
|
||||||
TEST_ExpectTrue(array.GetLength() == 0); |
|
||||||
} |
|
||||||
|
|
||||||
protected static function Test_AddInsert() |
|
||||||
{ |
|
||||||
local DynamicArray array; |
|
||||||
array = DynamicArray(__().memory.Allocate(class'DynamicArray')); |
|
||||||
Context("Testing adding new items to `DynamicArray`."); |
|
||||||
Issue("`Add()`/`AddItem()` incorrectly add new items to" |
|
||||||
@ "the `DynamicArray`."); |
|
||||||
array.AddItem(__().box.int(3)).Add(3).AddItem(__().box.byte(7)).Add(1); |
|
||||||
TEST_ExpectTrue(array.GetLength() == 6); |
|
||||||
TEST_ExpectNotNone(IntBox(array.GetItem(0))); |
|
||||||
TEST_ExpectTrue(IntBox(array.GetItem(0)).Get() == 3); |
|
||||||
TEST_ExpectNone(array.GetItem(1)); |
|
||||||
TEST_ExpectNone(array.GetItem(2)); |
|
||||||
TEST_ExpectNone(array.GetItem(3)); |
|
||||||
TEST_ExpectNotNone(ByteBox(array.GetItem(4))); |
|
||||||
TEST_ExpectTrue(ByteBox(array.GetItem(4)).Get() == 7); |
|
||||||
TEST_ExpectNone(array.GetItem(5)); |
|
||||||
|
|
||||||
Issue("`Insert()`/`InsertItem()` incorrectly add new items to" |
|
||||||
@ "the `DynamicArray`."); |
|
||||||
array.Insert(2, 2).InsertItem(0, __().ref.bool(true)); |
|
||||||
TEST_ExpectTrue(array.GetLength() == 9); |
|
||||||
TEST_ExpectNotNone(BoolRef(array.GetItem(0))); |
|
||||||
TEST_ExpectTrue(BoolRef(array.GetItem(0)).Get()); |
|
||||||
TEST_ExpectNotNone(IntBox(array.GetItem(1))); |
|
||||||
TEST_ExpectTrue(IntBox(array.GetItem(1)).Get() == 3); |
|
||||||
TEST_ExpectNone(array.GetItem(2)); |
|
||||||
TEST_ExpectNone(array.GetItem(6)); |
|
||||||
TEST_ExpectNotNone(ByteBox(array.GetItem(7))); |
|
||||||
TEST_ExpectTrue(ByteBox(array.GetItem(7)).Get() == 7); |
|
||||||
TEST_ExpectNone(array.GetItem(8)); |
|
||||||
} |
|
||||||
|
|
||||||
protected static function Test_Remove() |
|
||||||
{ |
|
||||||
local DynamicArray array; |
|
||||||
array = DynamicArray(__().memory.Allocate(class'DynamicArray')); |
|
||||||
Context("Testing removing items from `DynamicArray`."); |
|
||||||
array.AddItem(__().box.int(1)).AddItem(__().box.int(3)) |
|
||||||
.AddItem(__().box.int(1)).AddItem(__().box.int(3)) |
|
||||||
.AddItem(__().box.int(5)).AddItem(__().box.int(2)) |
|
||||||
.AddItem(__().box.int(4)).AddItem(__().box.int(7)) |
|
||||||
.AddItem(__().box.int(5)).AddItem(__().box.int(1)) |
|
||||||
.AddItem(__().box.int(5)).AddItem(__().box.int(0)); |
|
||||||
Issue("`Remove()` incorrectly removes items from array."); |
|
||||||
array.Remove(3, 2).Remove(0, 2).Remove(7, 9); |
|
||||||
TEST_ExpectTrue(array.GetLength() == 7); |
|
||||||
TEST_ExpectTrue(IntBox(array.GetItem(0)).Get() == 1); |
|
||||||
TEST_ExpectTrue(IntBox(array.GetItem(1)).Get() == 2); |
|
||||||
TEST_ExpectTrue(IntBox(array.GetItem(2)).Get() == 4); |
|
||||||
TEST_ExpectTrue(IntBox(array.GetItem(3)).Get() == 7); |
|
||||||
TEST_ExpectTrue(IntBox(array.GetItem(4)).Get() == 5); |
|
||||||
TEST_ExpectTrue(IntBox(array.GetItem(5)).Get() == 1); |
|
||||||
TEST_ExpectTrue(IntBox(array.GetItem(6)).Get() == 5); |
|
||||||
|
|
||||||
Issue("`RemoveItem()` incorrectly removes items from array."); |
|
||||||
array.RemoveItem(__().box.int(1)).RemoveItem(__().box.int(5), true); |
|
||||||
TEST_ExpectTrue(array.GetLength() == 4); |
|
||||||
TEST_ExpectTrue(IntBox(array.GetItem(0)).Get() == 2); |
|
||||||
TEST_ExpectTrue(IntBox(array.GetItem(1)).Get() == 4); |
|
||||||
TEST_ExpectTrue(IntBox(array.GetItem(2)).Get() == 7); |
|
||||||
TEST_ExpectTrue(IntBox(array.GetItem(3)).Get() == 5); |
|
||||||
|
|
||||||
Issue("`RemoveIndex()` incorrectly removes items from array."); |
|
||||||
array.RemoveIndex(0).RemoveIndex(1).RemoveIndex(1); |
|
||||||
TEST_ExpectTrue(array.GetLength() == 1); |
|
||||||
TEST_ExpectTrue(IntBox(array.GetItem(0)).Get() == 4); |
|
||||||
} |
|
||||||
|
|
||||||
protected static function Test_Find() |
|
||||||
{ |
|
||||||
local DynamicArray array; |
|
||||||
array = DynamicArray(__().memory.Allocate(class'DynamicArray')); |
|
||||||
Context("Testing searching for items in `DynamicArray`."); |
|
||||||
array.AddItem(__().box.int(1)).AddItem(__().box.int(3)) |
|
||||||
.AddItem(__().box.int(1)).AddItem(__().box.int(3)) |
|
||||||
.AddItem(__().box.int(5)).AddItem(__().box.bool(true)) |
|
||||||
.AddItem(none).AddItem(__().box.float(72.54)) |
|
||||||
.AddItem(__().box.int(5)).AddItem(__().box.int(1)) |
|
||||||
.AddItem(__().box.int(5)).AddItem(__().box.int(0)); |
|
||||||
Issue("`Find()` does not properly find indices of existing items."); |
|
||||||
TEST_ExpectTrue(array.Find(__().box.int(5)) == 4); |
|
||||||
TEST_ExpectTrue(array.Find(__().box.int(1)) == 0); |
|
||||||
TEST_ExpectTrue(array.Find(__().box.int(0)) == 11); |
|
||||||
TEST_ExpectTrue(array.Find(__().box.float(72.54)) == 7); |
|
||||||
TEST_ExpectTrue(array.Find(__().box.bool(true)) == 5); |
|
||||||
TEST_ExpectTrue(array.Find(none) == 6); |
|
||||||
|
|
||||||
Issue("`Find()` does not return `-1` on missing values."); |
|
||||||
TEST_ExpectTrue(array.Find(__().box.int(42)) == -1); |
|
||||||
TEST_ExpectTrue(array.Find(__().box.float(72.543)) == -1); |
|
||||||
TEST_ExpectTrue(array.Find(__().box.bool(false)) == -1); |
|
||||||
TEST_ExpectTrue(array.Find(__().box.byte(128)) == -1); |
|
||||||
} |
|
||||||
|
|
||||||
protected static function MockItem NewMockItem() |
|
||||||
{ |
|
||||||
return MockItem(__().memory.Allocate(class'MockItem')); |
|
||||||
} |
|
||||||
|
|
||||||
// Creates array with mock objects, also zeroing their count. |
|
||||||
// Managed items' count: 6, but 12 items total. |
|
||||||
protected static function DynamicArray NewMockArray() |
|
||||||
{ |
|
||||||
local DynamicArray array; |
|
||||||
class'MockItem'.default.objectCount = 0; |
|
||||||
array = DynamicArray(__().memory.Allocate(class'DynamicArray')); |
|
||||||
array.AddItem(NewMockItem(), true).AddItem(NewMockItem(), false) |
|
||||||
.InsertItem(2, NewMockItem(), true).AddItem(NewMockItem(), true) |
|
||||||
.AddItem(NewMockItem(), false).AddItem(NewMockItem(), true) |
|
||||||
.InsertItem(6, NewMockItem(), false).AddItem(NewMockItem(), true) |
|
||||||
.InsertItem(3, NewMockItem(), false).AddItem(NewMockItem(), false) |
|
||||||
.InsertItem(10, NewMockItem(), true).AddItem(NewMockItem(), false); |
|
||||||
return array; |
|
||||||
} |
|
||||||
|
|
||||||
protected static function Test_Managed() |
|
||||||
{ |
|
||||||
local MockItem exampleItem; |
|
||||||
local DynamicArray array; |
|
||||||
exampleItem = NewMockItem(); |
|
||||||
// Managed items' count: 6, but 12 items total. |
|
||||||
array = NewMockArray(); |
|
||||||
Context("Testing how `DynamicArray` deallocates managed objects."); |
|
||||||
Issue("`Remove()` incorrectly deallocates managed items."); |
|
||||||
// -2 managed items |
|
||||||
array.Remove(3, 2).Remove(0, 2).Remove(7, 9); |
|
||||||
TEST_ExpectTrue(class'MockItem'.default.objectCount == 10); |
|
||||||
|
|
||||||
Issue("`RemoveIndex()` incorrectly deallocates managed items."); |
|
||||||
// -1 managed items |
|
||||||
array.RemoveIndex(3).RemoveIndex(0); |
|
||||||
TEST_ExpectTrue(class'MockItem'.default.objectCount == 9); |
|
||||||
// -1 managed items |
|
||||||
array.RemoveItem(exampleItem, true).RemoveItem(exampleItem, true); |
|
||||||
TEST_ExpectTrue(class'MockItem'.default.objectCount == 8); |
|
||||||
// -2 managed items |
|
||||||
array.RemoveItem(exampleItem); |
|
||||||
TEST_ExpectTrue(class'MockItem'.default.objectCount == 6); |
|
||||||
|
|
||||||
array = NewMockArray(); |
|
||||||
Issue("Shrinking array with `SetLength()` incorrectly handles" |
|
||||||
@ "managed items"); |
|
||||||
// -4 managed items |
|
||||||
array.SetLength(3); |
|
||||||
TEST_ExpectTrue(class'MockItem'.default.objectCount == 8); |
|
||||||
|
|
||||||
Issue("Rewriting values with `SetItem()` incorrectly handles" |
|
||||||
@ "managed items."); |
|
||||||
// -2 managed items |
|
||||||
array.SetItem(0, exampleItem, true); |
|
||||||
array.SetItem(2, exampleItem, true); |
|
||||||
TEST_ExpectTrue(class'MockItem'.default.objectCount == 6); |
|
||||||
} |
|
||||||
|
|
||||||
protected static function Test_DeallocationHandling() |
|
||||||
{ |
|
||||||
local MockItem exampleItem; |
|
||||||
local DynamicArray array; |
|
||||||
exampleItem = NewMockItem(); |
|
||||||
// Managed items' count: 6, but 12 items total. |
|
||||||
array = NewMockArray(); |
|
||||||
Context("Testing how `DynamicArray` deals with external deallocation of" |
|
||||||
@ "managed objects."); |
|
||||||
Issue("`DynamicArray` does not return `none` even though stored object" |
|
||||||
@ "was already deallocated."); |
|
||||||
array.GetItem(0).FreeSelf(); |
|
||||||
TEST_ExpectTrue(class'MockItem'.default.objectCount == 11); |
|
||||||
TEST_ExpectTrue(array.GetItem(0) == none); |
|
||||||
|
|
||||||
Issue("Managed items are not deallocated when they are duplicated inside" |
|
||||||
@ "`DynamicArray`, but they should."); |
|
||||||
array.SetItem(1, exampleItem, true).SetItem(2, exampleItem, true); |
|
||||||
TEST_ExpectTrue(class'MockItem'.default.objectCount == 10); |
|
||||||
array.SetLength(2); |
|
||||||
// At this point we got rid of all the managed objects that were generated |
|
||||||
// in `array` + deallocated `exampleObject`. |
|
||||||
TEST_ExpectTrue(class'MockItem'.default.objectCount == 5); |
|
||||||
TEST_ExpectTrue(array.GetItem(1) == none); |
|
||||||
} |
|
||||||
|
|
||||||
protected static function Test_Take() |
|
||||||
{ |
|
||||||
local DynamicArray array; |
|
||||||
Context("Testing `TakeItem()` method of `DynamicArray`."); |
|
||||||
// Managed items' count: 6, but 12 items total. |
|
||||||
array = NewMockArray(); |
|
||||||
Issue("`TakeItem()` returns incorrect value."); |
|
||||||
TEST_ExpectTrue(array.TakeItem(0).class == class'MockItem'); |
|
||||||
TEST_ExpectTrue(array.TakeItem(3).class == class'MockItem'); |
|
||||||
TEST_ExpectTrue(array.TakeItem(4).class == class'MockItem'); |
|
||||||
TEST_ExpectTrue(array.TakeItem(6).class == class'MockItem'); |
|
||||||
|
|
||||||
Issue("Objects returned by `TakeItem()` are still managed by" |
|
||||||
@ "`DynamicArray`."); |
|
||||||
array.Empty(); |
|
||||||
TEST_ExpectTrue(class'MockItem'.default.objectCount == 9); |
|
||||||
} |
|
||||||
|
|
||||||
defaultproperties |
|
||||||
{ |
|
||||||
caseGroup = "Collections" |
|
||||||
caseName = "DynamicArray" |
|
||||||
} |
|
@ -1,143 +0,0 @@ |
|||||||
/** |
|
||||||
* 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 <https://www.gnu.org/licenses/>. |
|
||||||
*/ |
|
||||||
class TEST_IteratorOld extends TestCase |
|
||||||
abstract; |
|
||||||
|
|
||||||
var const int TESTED_ITEMS_AMOUNT; |
|
||||||
var array<AcediaObject> items; |
|
||||||
var array<byte> 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 CollectionIterator 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 CollectionIterator 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 |
|
||||||
} |
|
Loading…
Reference in new issue