diff --git a/CHANGELOG.md b/CHANGELOG.md index a93a613..07b5f96 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,13 +4,38 @@ All notable changes to this package will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). +## [0.6.0] - 2023-08-05 + +- Improved the *ObservableResolverList* and *ObservableResolverDictionary* data types to properly resolve lists and dictionaries with different data types from the original collection. + +## [0.5.1] - 2023-09-04 + +- Added StructPair data type to support both object and struct type containers, improving memory usage performance. + +**Fix**: +- Fixed the dispose extension methods for GameObject and Object, removing pragma directives and adding null reference check in GetValid method to avoid unwanted exceptions + +## [0.5.0] - 2023-08-05 + +- Added **floatP**, a deterministic floating-point number type, enhancing precision and predictability in mathematical operations. Including arithmetic and comparison operators for floatP to support complex calculations and conversion methods between floatP and float types. + +## [0.4.0] - 2023-07-30 + +- Added utility methods and extensions for Unity's Object and GameObject types, enhancing the codebase's functionality. +- Introduced a SerializableType struct for viewing, modifying, and saving types from the inspector, with serialization support and compatibility with filter attributes. + +## [0.3.0] - 2023-07-28 + +- Added support for observing field updates with previous and current values in the ObservableField class. +- Introduced a UnitySerializedDictionary class that allows serialization of dictionaries in Unity. + ## [0.2.0] - 2020-09-28 -- Removed *ObservableIdList* because it's behaviour was too confusing and the same result can be obtained with *ObservableList* or *ObservableDictionary* - Added new *ObservableResolverList*, *ObservableResolverDictionary* & *ObservableResolverField* to allow to create observable types without referencing the collection directly -- Added Unit tests to all types +- Added Unit tests to all data types in the project **Changed**: +- Removed *ObservableIdList* because it's behaviour was too confusing and the same result can be obtained with *ObservableList* or *ObservableDictionary* - Removed all Pair Data and moved them to new *Pair* serialized type that can now be serializable on Unity 2020.1 - Moved all Vector2, Vector3 & Vector4 extensions to the ValueData file diff --git a/Runtime/ObservableDictionary.cs b/Runtime/ObservableDictionary.cs index 83e07f8..94ce25b 100644 --- a/Runtime/ObservableDictionary.cs +++ b/Runtime/ObservableDictionary.cs @@ -1,7 +1,9 @@ +using NUnit.Framework; using System; using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; +using UnityEngine.UIElements; // ReSharper disable once CheckNamespace @@ -19,6 +21,9 @@ public interface IObservableDictionary : IEnumerable } /// + /// + /// This dictionary only allows to read the elements in it and not to modify it + /// public interface IObservableDictionaryReader : IObservableDictionary, IEnumerable> { /// @@ -71,7 +76,7 @@ public interface IObservableDictionaryReader : IObservableDictiona void StopObservingAll(object subscriber = null); } - /// + /// public interface IObservableDictionary : IObservableDictionaryReader { /// @@ -86,12 +91,77 @@ public interface IObservableDictionary : IObservableDictionaryRead /// bool Remove(TKey key); + /// + void Clear(); + /// /// It invokes any update method that is observing to the given on this dictionary /// void InvokeUpdate(TKey key); } + /// + /// + /// This interface resolves between 2 dictionaries with different types of keys and values + /// + public interface IObservableResolverDictionaryReader : + IObservableDictionaryReader + { + /// + /// The Original Dictionary that is being resolved across the entire interface + /// + ReadOnlyDictionary OriginDictionary { get; } + + /// + /// Gets the value from the origin dictionary corresponding to the specified key. + /// + /// The key to locate in the origin dictionary. + /// The value from the origin dictionary corresponding to the specified key. + TValueOrigin GetOriginValue(TKey key); + + /// + /// Attempts to get the value from the origin dictionary corresponding to the specified key. + /// + /// The key to locate in the origin dictionary. + /// When this method returns, contains the value from the origin dictionary corresponding to the specified key, if the key is found; otherwise, the default value for the type of the value parameter. This parameter is passed uninitialized. + /// true if the origin dictionary contains an element with the specified key; otherwise, false. + bool TryGetOriginValue(TKey key, out TValueOrigin value); + } + + /// + /// + /// This interface resolves between 2 dictionaries with different types of keys and values + /// + public interface IObservableResolverDictionary : + IObservableResolverDictionaryReader, + IObservableDictionary + { + /// + /// Updates the value in the origin dictionary corresponding to the specified origin key. + /// + /// The key of the value to update in the origin dictionary. + /// The new value to set in the origin dictionary. + void UpdateOrigin(TKeyOrigin key, TValueOrigin value); + + /// + /// + /// Add's to the origin dictionary + /// + void AddOrigin(TKeyOrigin key, TValueOrigin value); + + /// + /// + /// Remove's to the origin dictionary + /// + bool RemoveOrigin(TKeyOrigin key); + + /// + /// + /// Clear's to the origin dictionary + /// + void ClearOrigin(); + } + /// public class ObservableDictionary : IObservableDictionary { @@ -153,7 +223,7 @@ public bool ContainsKey(TKey key) } /// - public void Add(TKey key, TValue value) + public virtual void Add(TKey key, TValue value) { Dictionary.Add(key, value); @@ -172,7 +242,7 @@ public void Add(TKey key, TValue value) } /// - public bool Remove(TKey key) + public virtual bool Remove(TKey key) { if (!Dictionary.TryGetValue(key, out var value)) { @@ -197,6 +267,22 @@ public bool Remove(TKey key) return true; } + /// + public virtual void Clear() + { + var dictionary = new Dictionary(Dictionary); + + Dictionary.Clear(); + + for (var i = 0; i < _updateActions.Count; i++) + { + foreach (var data in dictionary) + { + _updateActions[i](data.Key, data.Value, default, ObservableUpdateType.Removed); + } + } + } + /// public void InvokeUpdate(TKey key) { @@ -310,16 +396,100 @@ protected void InvokeUpdate(TKey key, TValue previousValue) } /// - public class ObservableResolverDictionary : ObservableDictionary - where TValue : struct + public class ObservableResolverDictionary : + ObservableDictionary, + IObservableResolverDictionary { - private readonly Func> _dictionaryResolver; + private readonly IDictionary _dictionary; + private readonly Func> _toOrignResolver; + private readonly Func, KeyValuePair> _fromOrignResolver; - protected override IDictionary Dictionary => _dictionaryResolver(); + /// + public ReadOnlyDictionary OriginDictionary => new ReadOnlyDictionary(_dictionary); - public ObservableResolverDictionary(Func> dictionaryResolver) + public ObservableResolverDictionary(IDictionary dictionary, + Func, KeyValuePair> fromOrignResolver, + Func> toOrignResolver) + : base(new Dictionary(dictionary.Count)) + { + _dictionary = dictionary; + _toOrignResolver = toOrignResolver; + _fromOrignResolver = fromOrignResolver; + + foreach (var pair in dictionary) + { + Dictionary.Add(fromOrignResolver(pair)); + } + } + + /// + public TValueOrigin GetOriginValue(TKey key) + { + return _dictionary[_toOrignResolver(key, default).Key]; + } + + /// + public bool TryGetOriginValue(TKey key, out TValueOrigin value) + { + return _dictionary.TryGetValue(_toOrignResolver(key, default).Key, out value); + } + + /// + public void UpdateOrigin(TKeyOrigin key, TValueOrigin value) + { + var convertPair = _fromOrignResolver(new KeyValuePair(key, value)); + + _dictionary[key] = value; + this[convertPair.Key] = convertPair.Value; + } + + /// + public override void Add(TKey key, TValue value) + { + _dictionary.Add(_toOrignResolver(key, value)); + base.Add(key, value); + } + + /// + public override bool Remove(TKey key) + { + var pair = _toOrignResolver(key, Dictionary[key]); + + _dictionary.Remove(pair.Key); + + return base.Remove(key); + } + + /// + public override void Clear() + { + _dictionary.Clear(); + base.Clear(); ; + } + + /// + public void AddOrigin(TKeyOrigin key, TValueOrigin value) + { + var convertPair = _fromOrignResolver(new KeyValuePair(key, value)); + + _dictionary.Add(key, value); + base.Add(convertPair.Key, convertPair.Value); + } + + /// + public bool RemoveOrigin(TKeyOrigin key) + { + var convertPair = _fromOrignResolver(new KeyValuePair(key, OriginDictionary[key])); + + _dictionary.Remove(key); + return base.Remove(convertPair.Key); + } + + /// + public void ClearOrigin() { - _dictionaryResolver = dictionaryResolver; + _dictionary.Clear(); + base.Clear(); } } } \ No newline at end of file diff --git a/Runtime/ObservableList.cs b/Runtime/ObservableList.cs index f6e39bb..354278a 100644 --- a/Runtime/ObservableList.cs +++ b/Runtime/ObservableList.cs @@ -1,6 +1,8 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Linq; +using System.Reflection; // ReSharper disable once CheckNamespace @@ -70,11 +72,11 @@ public interface IObservableList : IObservableListReader /// new T this[int index] { get; set; } - /// + /// void Add(T data); /// - void Remove(T data); + bool Remove(T data); /// void RemoveAt(int index); @@ -88,6 +90,52 @@ public interface IObservableList : IObservableListReader void InvokeUpdate(int index); } + /// + /// + /// This interface resolves between 2 lists with different types of values + /// + public interface IObservableResolverListReader : IObservableListReader + { + /// + /// The Original List that is being resolved across the entire interface + /// + IReadOnlyList OriginList { get; } + } + + /// + /// + /// This interface resolves between 2 lists with different types of values + /// + public interface IObservableResolverList : + IObservableResolverListReader, + IObservableList + { + /// + /// Updates the value in the origin list corresponding to the specified index. + /// + /// The index of the value to update in the origin list. + /// The new value to set in the origin list. + void UpdateOrigin(TOrigin value, int index); + + /// + /// + /// Add's the value to the origin list + /// + void AddOrigin(TOrigin value); + + /// + /// + /// Remove's the value to the origin list + /// + bool RemoveOrigin(TOrigin value); + + /// + /// + /// Clear's to the origin list + /// + void ClearOrigin(); + } + /// public class ObservableList : IObservableList { @@ -110,15 +158,15 @@ public T this[int index] /// public int Count => List.Count; /// - public IReadOnlyList ReadOnlyList => List; + public IReadOnlyList ReadOnlyList => new List(List); protected virtual List List { get; } protected ObservableList() { } - public ObservableList(List list) + public ObservableList(IList list) { - List = list; + List = list as List ?? list.ToList(); } /// @@ -152,7 +200,7 @@ public int IndexOf(T value) } /// - public void Add(T data) + public virtual void Add(T data) { List.Add(data); @@ -163,18 +211,22 @@ public void Add(T data) } /// - public void Remove(T data) + public bool Remove(T data) { var idx = List.IndexOf(data); if (idx >= 0) { RemoveAt(idx); + + return true; } + + return false; } /// - public void RemoveAt(int index) + public virtual void RemoveAt(int index) { var data = List[index]; @@ -187,17 +239,17 @@ public void RemoveAt(int index) } /// - public void Clear() + public virtual void Clear() { - var data = new List(List); + var list = new List(List); List.Clear(); for (var i = 0; i < _updateActions.Count; i++) { - for (var j = 0; j < data.Count; j++) + for (var j = 0; j < list.Count; j++) { - _updateActions[i](j, data[j], default, ObservableUpdateType.Removed); + _updateActions[i](j, list[j], default, ObservableUpdateType.Removed); } } } @@ -257,15 +309,78 @@ protected void InvokeUpdate(int index, T previousValue) } /// - public class ObservableResolverList : ObservableList + public class ObservableResolverList : ObservableList, IObservableResolverList { - private readonly Func> _listResolver; + private readonly IList _originList; + private readonly Func _fromOrignResolver; + private readonly Func _toOrignResolver; - protected override List List => _listResolver(); + /// + public IReadOnlyList OriginList => new List(_originList); - public ObservableResolverList(Func> listResolver) + public ObservableResolverList(IList originList, + Func fromOrignResolver, + Func toOrignResolver) : + base(new List(originList.Count)) + { + _originList = originList; + _fromOrignResolver = fromOrignResolver; + _toOrignResolver = toOrignResolver; + + for (var i = 0; i < originList.Count; i++) + { + List.Add(fromOrignResolver(originList[i])); + } + } + + /// + public override void Add(T data) + { + _originList.Add(_toOrignResolver(data)); + base.Add(data); + } + + /// + public override void RemoveAt(int index) + { + _originList.RemoveAt(index); + base.RemoveAt(index); + } + + /// + public override void Clear() + { + _originList.Clear(); + base.Clear(); + } + + /// + public void UpdateOrigin(TOrigin value, int index) + { + _originList[index] = value; + List[index] = _fromOrignResolver(value); + } + + /// + public void AddOrigin(TOrigin value) + { + _originList.Add(value); + List.Add(_fromOrignResolver(value)); + } + + /// + public bool RemoveOrigin(TOrigin value) + { + _originList.Remove(value); + + return base.Remove(_fromOrignResolver(value)); + } + + /// + public void ClearOrigin() { - _listResolver = listResolver; + _originList.Clear(); + base.Clear(); } } } \ No newline at end of file diff --git a/Tests/Editor/OberservableResolverListTest.cs b/Tests/Editor/OberservableResolverListTest.cs new file mode 100644 index 0000000..453f248 --- /dev/null +++ b/Tests/Editor/OberservableResolverListTest.cs @@ -0,0 +1,70 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using System.Reflection; +using GameLovers; +using NSubstitute; +using NUnit.Framework; + +// ReSharper disable once CheckNamespace + +namespace GameLoversEditor.DataExtensions.Tests +{ + [TestFixture] + public class ObservableResolverListTest + { + private int _index = 0; + private IObservableResolverList _list; + private IList _mockList; + + [SetUp] + public void SetUp() + { + _mockList = Substitute.For>(); + _list = new ObservableResolverList(_mockList, + origin => int.Parse(origin), + value => value.ToString()); + } + + [Test] + public void AddOrigin_AddsValueToOriginList() + { + var value = "1"; + + _list.AddOrigin(value); + + _mockList.Received().Add(value); + } + + [Test] + public void UpdateOrigin_UpdatesOriginList() + { + var value = "1"; + + _list.AddOrigin(value); + _list.UpdateOrigin(value, _index); + + _mockList.Received()[_index] = value; + } + + [Test] + public void RemoveOrigin_RemovesValueFromOriginList() + { + var value = "1"; + + _list.AddOrigin(value); + + Assert.IsTrue(_list.RemoveOrigin(value)); + _mockList.Received().Remove(value); + } + + [Test] + public void ClearOrigin_ClearsOriginList() + { + _list.ClearOrigin(); + + _mockList.Received().Clear(); + } + } +} \ No newline at end of file diff --git a/Tests/Editor/OberservableResolverListTest.cs.meta b/Tests/Editor/OberservableResolverListTest.cs.meta new file mode 100644 index 0000000..7e1207b --- /dev/null +++ b/Tests/Editor/OberservableResolverListTest.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 339332fedbfe038408ad12655029d0a1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Tests/Editor/ObservableDictionaryTest.cs b/Tests/Editor/ObservableDictionaryTest.cs index 23ece15..f62a2a0 100644 --- a/Tests/Editor/ObservableDictionaryTest.cs +++ b/Tests/Editor/ObservableDictionaryTest.cs @@ -1,7 +1,9 @@ +using System; using System.Collections.Generic; using GameLovers; using NSubstitute; using NUnit.Framework; +using UnityEngine; // ReSharper disable once CheckNamespace @@ -11,8 +13,6 @@ namespace GameLoversEditor.DataExtensions.Tests public class ObservableDictionaryTest { private const int _key = 0; - private const int _previousValue = 5; - private const int _newValue = 10; /// /// Mocking interface to check method calls received @@ -22,8 +22,7 @@ public interface IMockCaller void Call(TKey key, TValue previousValue, TValue newValue, ObservableUpdateType updateType); } - private ObservableDictionary _observableDictionary; - private ObservableResolverDictionary _observableResolverDictionary; + private ObservableDictionary _dictionary; private IDictionary _mockDictionary; private IMockCaller _caller; @@ -31,110 +30,176 @@ public interface IMockCaller public void Init() { _caller = Substitute.For>(); - _mockDictionary = Substitute.For>(); - _observableDictionary = new ObservableDictionary(_mockDictionary); - _observableResolverDictionary = new ObservableResolverDictionary(() => _mockDictionary); + _mockDictionary = new Dictionary(); + _dictionary = new ObservableDictionary(_mockDictionary); + } + + [Test] + public void TryGetValue_ReturnsFalse_WhenKeyDoesNotExist() + { + bool result = _dictionary.TryGetValue(1, out int value); - _mockDictionary.TryGetValue(_key, out _).Returns(callInfo => - { - callInfo[1] = _mockDictionary[_key]; - return true; - }); + Assert.IsFalse(result); } [Test] - public void ValueCheck() + public void TryGetValue_ReturnsTrue_WhenKeyExists() { - _mockDictionary[_key].Returns(_previousValue); + _dictionary.Add(1, 100); - Assert.AreEqual(_previousValue, _observableDictionary[_key]); - Assert.AreEqual(_previousValue, _observableResolverDictionary[_key]); + bool result = _dictionary.TryGetValue(1, out int value); + + Assert.IsTrue(result); + Assert.AreEqual(100, value); } [Test] - public void ValueSetCheck() + public void ContainsKey_ReturnsFalse_WhenKeyDoesNotExist() { - const int valueCheck1 = 5; - const int valueCheck2 = 6; - const int valueCheck3 = 7; + Assert.IsFalse(_dictionary.ContainsKey(1)); + } - _mockDictionary[_key] = valueCheck1; + [Test] + public void ContainsKey_ReturnsTrue_WhenKeyExists() + { + _dictionary.Add(1, 100); - Assert.AreEqual(valueCheck1, _observableDictionary[_key]); - Assert.AreEqual(valueCheck1, _observableResolverDictionary[_key]); + Assert.IsTrue(_dictionary.ContainsKey(1)); + } - _observableDictionary[_key] = valueCheck2; + [Test] + public void Indexer_ReturnsValue_WhenKeyExists() + { + _dictionary.Add(1, 100); - Assert.AreEqual(valueCheck2, _observableDictionary[_key]); - Assert.AreEqual(valueCheck2, _observableResolverDictionary[_key]); + Assert.AreEqual(100, _dictionary[1]); + } - _observableResolverDictionary[_key] = valueCheck3; + [Test] + public void Indexer_SetsValue_WhenKeyExists() + { + _dictionary.Add(1, 100); + _dictionary[1] = 200; - Assert.AreEqual(valueCheck3, _observableDictionary[_key]); - Assert.AreEqual(valueCheck3, _observableResolverDictionary[_key]); + Assert.AreEqual(200, _dictionary[1]); } [Test] - public void ObserveCheck() + public void Add_AddsKeyValuePair_WhenKeyDoesNotExist() { - _observableDictionary.Observe(_key, _caller.Call); - _observableDictionary.Observe(_caller.Call); - _observableResolverDictionary.Observe(_key, _caller.Call); - _observableResolverDictionary.Observe(_caller.Call); + _dictionary.Add(1, 100); - // _caller.DidNotReceive().Call(Arg.Any(), Arg.Any(), Arg.Any()); + Assert.AreEqual(100, _dictionary[1]); + } - _observableDictionary.Add(_key, _previousValue); - _observableResolverDictionary.Add(_key, _previousValue); + [Test] + public void Add_ThrowsException_WhenKeyAlreadyExists() + { + _dictionary.Add(1, 100); - _mockDictionary[_key].Returns(_previousValue); + Assert.Throws(() => _dictionary.Add(1, 200)); + } - _observableDictionary[_key] = _newValue; + [Test] + public void Remove_RemovesKeyValuePair_WhenKeyExists() + { + _dictionary.Add(1, 100); - _mockDictionary[_key].Returns(_previousValue); + Assert.IsTrue(_dictionary.Remove(1)); + Assert.AreEqual(0, _dictionary.Count); + } - _observableResolverDictionary[_key] = _newValue; + [Test] + public void Remove_ReturnsFalse_WhenKeyDoesNotExist() + { + Assert.IsFalse(_dictionary.Remove(1)); + } - _observableDictionary.Remove(_key); - _observableResolverDictionary.Remove(_key); + [Test] + public void Clear_RemovesAllKeyValuePairs() + { + _dictionary.Add(1, 100); + _dictionary.Add(2, 200); + _dictionary.Clear(); - _caller.Received(4).Call(_key, 0, _previousValue, ObservableUpdateType.Added); - _caller.Received(4).Call(_key, _previousValue, _newValue, ObservableUpdateType.Updated); - _caller.Received(4).Call(_key, _newValue, 0, ObservableUpdateType.Removed); + Assert.AreEqual(0, _dictionary.Count); + } + + [Test] + public void ValueSetCheck() + { + const int valueCheck1 = 5; + const int valueCheck2 = 6; + + _mockDictionary.Add(_key, valueCheck1); + _dictionary[_key] = valueCheck2; + + Assert.AreNotEqual(valueCheck1, _mockDictionary[_key]); + Assert.AreEqual(valueCheck2, _dictionary[_key]); + } + + [Test] + public void ObserveCheck() + { + var startValue = 0; + var newValue = 1; + + _dictionary.Observe(_key, _caller.Call); + _dictionary.Observe(_caller.Call); + + _dictionary.Add(_key, startValue); + + _dictionary[_key] = newValue; + + _dictionary.Remove(_key); + + _caller.Received().Call(_key, 0, startValue, ObservableUpdateType.Added); + _caller.Received().Call(_key, startValue, newValue, ObservableUpdateType.Updated); + _caller.Received().Call(_key, newValue, 0, ObservableUpdateType.Removed); } [Test] public void InvokeObserveCheck() { - _observableDictionary.InvokeObserve(_key, _caller.Call); - _observableResolverDictionary.InvokeObserve(_key, _caller.Call); + _dictionary.Add(_key, 0); + _dictionary.InvokeObserve(_key, _caller.Call); _caller.DidNotReceive().Call(Arg.Any(), Arg.Any(), Arg.Any(), ObservableUpdateType.Added); - _caller.Received(2).Call(_key, 0, 0, ObservableUpdateType.Updated); + _caller.Received().Call(_key, 0, 0, ObservableUpdateType.Updated); _caller.DidNotReceive().Call(Arg.Any(), Arg.Any(), Arg.Any(), ObservableUpdateType.Removed); } [Test] - public void InvokeCheck() + public void InvokeUpdate_MissingKey_ThrowsException() + { + Assert.Throws(() => _dictionary.InvokeUpdate(_key)); + } + + [Test] + public void InvokeObserve_MissingKey_ThrowsException() { - _observableDictionary.Observe(_key, _caller.Call); - _observableDictionary.Observe(_caller.Call); - _observableResolverDictionary.Observe(_key, _caller.Call); - _observableResolverDictionary.Observe(_caller.Call); + Assert.Throws(() => _dictionary.InvokeObserve(_key, _caller.Call)); + } - _observableDictionary.InvokeUpdate(_key); - _observableResolverDictionary.InvokeUpdate(_key); + [Test] + public void InvokeUpdateCheck() + { + _dictionary.Add(_key, 0); + _dictionary.Observe(_key, _caller.Call); + _dictionary.Observe(_caller.Call); + + _dictionary.InvokeUpdate(_key); _caller.DidNotReceive().Call(Arg.Any(), Arg.Any(), Arg.Any(), ObservableUpdateType.Added); - _caller.Received(4).Call(_key, 0, 0, ObservableUpdateType.Updated); + _caller.Received(2).Call(_key, 0, 0, ObservableUpdateType.Updated); _caller.DidNotReceive().Call(Arg.Any(), Arg.Any(), Arg.Any(), ObservableUpdateType.Removed); } [Test] - public void InvokeCheck_NotObserving_DoesNothing() + public void InvokeUpdate_NotObserving_DoesNothing() { - _observableDictionary.InvokeUpdate(_key); - _observableResolverDictionary.InvokeUpdate(_key); + _dictionary.Add(_key, 0); + _dictionary.InvokeUpdate(_key); _caller.DidNotReceive().Call(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any()); } @@ -142,17 +207,12 @@ public void InvokeCheck_NotObserving_DoesNothing() [Test] public void StopObserveCheck() { - _observableDictionary.Observe(_caller.Call); - _observableResolverDictionary.Observe(_caller.Call); - _observableDictionary.StopObserving(_caller.Call); - _observableResolverDictionary.StopObserving(_caller.Call); + _dictionary.Observe(_caller.Call); + _dictionary.StopObserving(_caller.Call); - _observableDictionary.Add(_key, _previousValue); - _observableResolverDictionary.Add(_key, _previousValue); - _observableDictionary[_key] = _previousValue; - _observableResolverDictionary[_key] = _previousValue; - _observableDictionary.Remove(_key); - _observableResolverDictionary.Remove(_key); + _dictionary.Add(_key, 0); + _dictionary[_key] = 0; + _dictionary.Remove(_key); _caller.DidNotReceive().Call(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any()); } @@ -160,17 +220,12 @@ public void StopObserveCheck() [Test] public void StopObserve_KeyCheck() { - _observableDictionary.Observe(_key, _caller.Call); - _observableResolverDictionary.Observe(_key, _caller.Call); - _observableDictionary.StopObserving(_key); - _observableResolverDictionary.StopObserving(_key); + _dictionary.Observe(_key, _caller.Call); + _dictionary.StopObserving(_key); - _observableDictionary.Add(_key, _previousValue); - _observableResolverDictionary.Add(_key, _previousValue); - _observableDictionary[_key] = _previousValue; - _observableResolverDictionary[_key] = _previousValue; - _observableDictionary.Remove(_key); - _observableResolverDictionary.Remove(_key); + _dictionary.Add(_key, 0); + _dictionary[_key] = 0; + _dictionary.Remove(_key); _caller.DidNotReceive().Call(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any()); } @@ -178,17 +233,12 @@ public void StopObserve_KeyCheck() [Test] public void StopObservingAllCheck() { - _observableDictionary.Observe(_caller.Call); - _observableResolverDictionary.Observe(_caller.Call); - _observableDictionary.StopObservingAll(_caller); - _observableResolverDictionary.StopObservingAll(_caller); + _dictionary.Observe(_caller.Call); + _dictionary.StopObservingAll(_caller); - _observableDictionary.Add(_key, _previousValue); - _observableResolverDictionary.Add(_key, _previousValue); - _observableDictionary[_key] = _previousValue; - _observableResolverDictionary[_key] = _previousValue; - _observableDictionary.Remove(_key); - _observableResolverDictionary.Remove(_key); + _dictionary.Add(_key, 0); + _dictionary[_key] = 0; + _dictionary.Remove(_key); _caller.DidNotReceive().Call(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any()); } @@ -196,19 +246,13 @@ public void StopObservingAllCheck() [Test] public void StopObservingAll_MultipleCalls_Check() { - _observableDictionary.Observe(_caller.Call); - _observableDictionary.Observe(_caller.Call); - _observableResolverDictionary.Observe(_caller.Call); - _observableResolverDictionary.Observe(_caller.Call); - _observableDictionary.StopObservingAll(_caller); - _observableResolverDictionary.StopObservingAll(_caller); + _dictionary.Observe(_caller.Call); + _dictionary.Observe(_caller.Call); + _dictionary.StopObservingAll(_caller); - _observableDictionary.Add(_key, _previousValue); - _observableResolverDictionary.Add(_key, _previousValue); - _observableDictionary[_key] = _previousValue; - _observableResolverDictionary[_key] = _previousValue; - _observableDictionary.Remove(_key); - _observableResolverDictionary.Remove(_key); + _dictionary.Add(_key, 0); + _dictionary[_key] = 0; + _dictionary.Remove(_key); _caller.DidNotReceive().Call(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any()); } @@ -216,17 +260,12 @@ public void StopObservingAll_MultipleCalls_Check() [Test] public void StopObservingAll_Everything_Check() { - _observableDictionary.Observe(_caller.Call); - _observableResolverDictionary.Observe(_caller.Call); - _observableDictionary.StopObservingAll(); - _observableResolverDictionary.StopObservingAll(); + _dictionary.Observe(_caller.Call); + _dictionary.StopObservingAll(); - _observableDictionary.Add(_key, _previousValue); - _observableResolverDictionary.Add(_key, _previousValue); - _observableDictionary[_key] = _previousValue; - _observableResolverDictionary[_key] = _previousValue; - _observableDictionary.Remove(_key); - _observableResolverDictionary.Remove(_key); + _dictionary.Add(_key, 0); + _dictionary[_key] = 0; + _dictionary.Remove(_key); _caller.DidNotReceive().Call(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any()); } @@ -234,15 +273,11 @@ public void StopObservingAll_Everything_Check() [Test] public void StopObservingAll_NotObserving_DoesNothing() { - _observableDictionary.StopObservingAll(_caller); - _observableResolverDictionary.StopObservingAll(_caller); + _dictionary.StopObservingAll(_caller); - _observableDictionary.Add(_key, _previousValue); - _observableResolverDictionary.Add(_key, _previousValue); - _observableDictionary[_key] = _previousValue; - _observableResolverDictionary[_key] = _previousValue; - _observableDictionary.Remove(_key); - _observableResolverDictionary.Remove(_key); + _dictionary.Add(_key, 0); + _dictionary[_key] = 0; + _dictionary.Remove(_key); _caller.DidNotReceive().Call(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any()); } diff --git a/Tests/Editor/ObservableListTest.cs b/Tests/Editor/ObservableListTest.cs index caa312d..be9b939 100644 --- a/Tests/Editor/ObservableListTest.cs +++ b/Tests/Editor/ObservableListTest.cs @@ -22,74 +22,57 @@ public interface IMockCaller private const int _previousValue = 5; private const int _newValue = 10; - private ObservableList _observableList; - private ObservableResolverList _observableResolverList; - private List _list; + private ObservableList _list; + private IList _mockList; private IMockCaller _caller; [SetUp] public void Init() { _caller = Substitute.For>(); - _list = new List(); - _observableList = new ObservableList(_list); - _observableResolverList = new ObservableResolverList(() => _list); + _mockList = Substitute.For>(); + _list = new ObservableList(_mockList); } [Test] - public void ValueCheck() + public void AddValue_AddsValueToList() { _list.Add(_previousValue); - Assert.AreEqual(_previousValue, _observableList[_index]); - Assert.AreEqual(_previousValue, _observableResolverList[_index]); + Assert.AreEqual(_previousValue, _list[_index]); } [Test] - public void ValueSetCheck() + public void SetValue_UpdatesValue() { const int valueCheck1 = 5; const int valueCheck2 = 6; - const int valueCheck3 = 7; _list.Add(valueCheck1); - Assert.AreEqual(valueCheck1, _observableList[_index]); - Assert.AreEqual(valueCheck1, _observableResolverList[_index]); + Assert.AreEqual(valueCheck1, _list[_index]); - _observableList[_index] = valueCheck2; + _list[_index] = valueCheck2; - Assert.AreEqual(valueCheck2, _observableList[_index]); - Assert.AreEqual(valueCheck2, _observableResolverList[_index]); - - _observableResolverList[_index] = valueCheck3; - - Assert.AreEqual(valueCheck3, _observableList[_index]); - Assert.AreEqual(valueCheck3, _observableResolverList[_index]); + Assert.AreEqual(valueCheck2, _list[_index]); } [Test] public void ObserveCheck() { - _observableList.Observe(_caller.Call); - _observableResolverList.Observe(_caller.Call); + _list.Observe(_caller.Call); _caller.DidNotReceive().Call(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any()); - _observableList.Add(_previousValue); - _observableResolverList.Add(_previousValue); - - _observableList[_index] = _newValue; - _list[_index] = _previousValue; - _observableResolverList[_index] = _newValue; + _list.Add(_previousValue); - _observableList.RemoveAt(_index); _list[_index] = _newValue; - _observableResolverList.RemoveAt(_index); - _caller.Received(2).Call(Arg.Any(), Arg.Is(0), Arg.Is(_previousValue), ObservableUpdateType.Added); - _caller.Received(2).Call(_index, _previousValue, _newValue, ObservableUpdateType.Updated); - _caller.Received(2).Call(_index, _newValue, 0, ObservableUpdateType.Removed); + _list.RemoveAt(_index); + + _caller.Received().Call(Arg.Any(), Arg.Is(0), Arg.Is(_previousValue), ObservableUpdateType.Added); + _caller.Received().Call(_index, _previousValue, _newValue, ObservableUpdateType.Updated); + _caller.Received().Call(_index, _newValue, 0, ObservableUpdateType.Removed); } [Test] @@ -97,11 +80,10 @@ public void InvokeObserveCheck() { _list.Add(_previousValue); - _observableList.InvokeObserve(_index, _caller.Call); - _observableResolverList.InvokeObserve(_index, _caller.Call); + _list.InvokeObserve(_index, _caller.Call); _caller.DidNotReceive().Call(_index, _previousValue, _previousValue, ObservableUpdateType.Added); - _caller.Received(2).Call(_index, _previousValue, _previousValue, ObservableUpdateType.Updated); + _caller.Received().Call(_index, _previousValue, _previousValue, ObservableUpdateType.Updated); _caller.DidNotReceive().Call(_index, _previousValue, _previousValue, ObservableUpdateType.Removed); } @@ -109,17 +91,14 @@ public void InvokeObserveCheck() public void InvokeCheck() { _list.Add(_previousValue); - - _observableList.Observe(_caller.Call); - _observableResolverList.Observe(_caller.Call); + _list.Observe(_caller.Call); _caller.DidNotReceive().Call(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any()); - _observableList.InvokeUpdate(_index); - _observableResolverList.InvokeUpdate(_index); + _list.InvokeUpdate(_index); _caller.DidNotReceive().Call(Arg.Any(), Arg.Any(), Arg.Any(), ObservableUpdateType.Added); - _caller.Received(2).Call(_index, _previousValue, _previousValue, ObservableUpdateType.Updated); + _caller.Received().Call(_index, _previousValue, _previousValue, ObservableUpdateType.Updated); _caller.DidNotReceive().Call(Arg.Any(), Arg.Any(), Arg.Any(), ObservableUpdateType.Removed); } @@ -127,9 +106,7 @@ public void InvokeCheck() public void InvokeCheck_NotObserving_DoesNothing() { _list.Add(_previousValue); - - _observableList.InvokeUpdate(_index); - _observableResolverList.InvokeUpdate(_index); + _list.InvokeUpdate(_index); _caller.DidNotReceive().Call(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any()); } @@ -137,17 +114,13 @@ public void InvokeCheck_NotObserving_DoesNothing() [Test] public void StopObserveCheck() { - _observableList.Observe(_caller.Call); - _observableResolverList.Observe(_caller.Call); - _observableList.StopObserving(_caller.Call); - _observableResolverList.StopObserving(_caller.Call); - - _observableList.Add(_previousValue); - _observableResolverList.Add(_previousValue); - _observableList[_index] = _previousValue; - _observableResolverList[_index] = _previousValue; - _observableList.RemoveAt(_index); - _observableResolverList.RemoveAt(_index); + _list.Observe(_caller.Call); + _list.StopObserving(_caller.Call); + _list.Add(_previousValue); + + _list[_index] = _previousValue; + + _list.RemoveAt(_index); _caller.DidNotReceive().Call(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any()); } @@ -155,15 +128,10 @@ public void StopObserveCheck() [Test] public void StopObservingAllCheck() { - _observableList.Observe(_caller.Call); - _observableResolverList.Observe(_caller.Call); - _observableList.StopObservingAll(_caller); - _observableResolverList.StopObservingAll(_caller); - - _observableList.Add(_previousValue); - _observableResolverList.Add(_previousValue); - _observableList.InvokeUpdate(_index); - _observableResolverList.InvokeUpdate(_index); + _list.Observe(_caller.Call); + _list.StopObservingAll(_caller); + _list.Add(_previousValue); + _list.InvokeUpdate(_index); _caller.DidNotReceive().Call(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any()); } @@ -171,17 +139,11 @@ public void StopObservingAllCheck() [Test] public void StopObservingAll_MultipleCalls_Check() { - _observableList.Observe(_caller.Call); - _observableList.Observe(_caller.Call); - _observableResolverList.Observe(_caller.Call); - _observableResolverList.Observe(_caller.Call); - _observableList.StopObservingAll(_caller); - _observableResolverList.StopObservingAll(_caller); - - _observableList.Add(_previousValue); - _observableResolverList.Add(_previousValue); - _observableList.InvokeUpdate(_index); - _observableResolverList.InvokeUpdate(_index); + _list.Observe(_caller.Call); + _list.Observe(_caller.Call); + _list.StopObservingAll(_caller); + _list.Add(_previousValue); + _list.InvokeUpdate(_index); _caller.DidNotReceive().Call(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any()); } @@ -189,15 +151,11 @@ public void StopObservingAll_MultipleCalls_Check() [Test] public void StopObservingAll_Everything_Check() { - _observableList.Observe(_caller.Call); - _observableResolverList.Observe(_caller.Call); - _observableList.StopObservingAll(); - _observableResolverList.StopObservingAll(); + _list.Observe(_caller.Call); + _list.StopObservingAll(); - _observableList.Add(_previousValue); - _observableResolverList.Add(_previousValue); - _observableList.InvokeUpdate(_index); - _observableResolverList.InvokeUpdate(_index); + _list.Add(_previousValue); + _list.InvokeUpdate(_index); _caller.DidNotReceive().Call(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any()); } @@ -205,13 +163,10 @@ public void StopObservingAll_Everything_Check() [Test] public void StopObservingAll_NotObserving_DoesNothing() { - _observableList.StopObservingAll(); - _observableResolverList.StopObservingAll(); + _list.StopObservingAll(); - _observableList.Add(_previousValue); - _observableResolverList.Add(_previousValue); - _observableList.InvokeUpdate(_index); - _observableResolverList.InvokeUpdate(_index); + _list.Add(_previousValue); + _list.InvokeUpdate(_index); _caller.DidNotReceive().Call(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any()); } diff --git a/Tests/Editor/ObservableResolverDictionaryTest.cs b/Tests/Editor/ObservableResolverDictionaryTest.cs new file mode 100644 index 0000000..d3e7be9 --- /dev/null +++ b/Tests/Editor/ObservableResolverDictionaryTest.cs @@ -0,0 +1,89 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Reflection; +using GameLovers; +using NSubstitute; +using NUnit.Framework; +using UnityEngine; + +// ReSharper disable once CheckNamespace + +namespace GameLoversEditor.DataExtensions.Tests +{ + [TestFixture] + public class ObservableResolverDictionaryTest + { + private int _key = 0; + private string _value = "1"; + private ObservableResolverDictionary _dictionary; + private IDictionary _mockDictionary; + + [SetUp] + public void Init() + { + _mockDictionary = Substitute.For>(); + _dictionary = new ObservableResolverDictionary( + _mockDictionary, + origin => new KeyValuePair(origin.Key, int.Parse(origin.Value)), + (key, value) => new KeyValuePair(key, key.ToString())); + + _mockDictionary[_key].Returns(_value); + _mockDictionary.TryGetValue(_key, out _).Returns(callInfo => + { + callInfo[1] = _mockDictionary[_key]; + return true; + }); + } + + [Test] + public void TryGetOriginValue_KeyExists_ReturnsTrueAndOutValue() + { + Assert.IsTrue(_dictionary.TryGetOriginValue(_key, out var value)); + } + + [Test] + public void TryGetOriginValue_KeyDoesNotExist_ReturnsFalseAndOutDefault() + { + var result = _dictionary.TryGetOriginValue(999, out var value); + + Assert.IsFalse(result); + Assert.IsNull(value); + } + + [Test] + public void AddOrigin_AddsValueToOriginDictionary() + { + _dictionary.AddOrigin(_key, _value); + + _mockDictionary.Received().Add(_key, _value); + } + + [Test] + public void UpdateOrigin_UpdatesValueInOriginDictionary() + { + _dictionary.AddOrigin(_key, _value); + _dictionary.UpdateOrigin(_key, _value); + + _mockDictionary.Received()[_key] = _value; + } + + [Test] + public void RemoveOrigin_RemovesValueFromOriginDictionary() + { + _dictionary.AddOrigin(_key, _value); + + Assert.IsTrue(_dictionary.RemoveOrigin(_key)); + _mockDictionary.Received().Remove(_key); + } + + [Test] + public void ClearOrigin_ClearsOriginDictionary() + { + _dictionary.ClearOrigin(); + + _mockDictionary.Received().Clear(); + } + } +} \ No newline at end of file diff --git a/Tests/Editor/ObservableResolverDictionaryTest.cs.meta b/Tests/Editor/ObservableResolverDictionaryTest.cs.meta new file mode 100644 index 0000000..a08312e --- /dev/null +++ b/Tests/Editor/ObservableResolverDictionaryTest.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4caa0f2c6d7acb043a06b1edc62fbb91 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Tests/Editor/floatPTests.cs b/Tests/Editor/floatPTests.cs index 95ed1a6..44e9a1a 100644 --- a/Tests/Editor/floatPTests.cs +++ b/Tests/Editor/floatPTests.cs @@ -11,17 +11,16 @@ public class floatPTests [Test] public void Representation() { - Assert.AreEqual(floatP.Zero, 0f); - Assert.AreNotEqual(-floatP.Zero, -0f); + Assert.AreEqual(floatP.Zero, (floatP)0f); + Assert.AreEqual(-floatP.Zero, (floatP) (-0f)); Assert.AreEqual(floatP.Zero, -floatP.Zero); - Assert.AreEqual(floatP.NaN, float.NaN); - Assert.AreEqual(floatP.One, 1f); - Assert.AreEqual(floatP.MinusOne, -1f); - Assert.AreEqual(floatP.PositiveInfinity, float.PositiveInfinity); - Assert.AreEqual(floatP.NegativeInfinity, float.NegativeInfinity); - Assert.AreEqual(floatP.Epsilon, float.Epsilon); - Assert.AreEqual(floatP.MaxValue, float.MaxValue); - Assert.AreEqual(floatP.MinValue, float.MinValue); + Assert.AreEqual(floatP.NaN, (floatP) float.NaN); + Assert.AreEqual(floatP.MinusOne, (floatP) (- 1f)); + Assert.AreEqual(floatP.PositiveInfinity, (floatP)float.PositiveInfinity); + Assert.AreEqual(floatP.NegativeInfinity, (floatP)float.NegativeInfinity); + Assert.AreEqual(floatP.Epsilon, (floatP)float.Epsilon); + Assert.AreEqual(floatP.MaxValue, (floatP)float.MaxValue); + Assert.AreEqual(floatP.MinValue, (floatP)float.MinValue); } [Test] @@ -43,24 +42,24 @@ public void Equality() [Test] public void Addition() { - Assert.AreEqual(floatP.One + floatP.One, 2f); - Assert.AreEqual(floatP.One - floatP.One, 0f); + Assert.AreEqual(floatP.One + floatP.One, (floatP)2f); + Assert.AreEqual(floatP.One - floatP.One, (floatP)0f); } [Test] public void Multiplication() { - Assert.AreEqual(floatP.PositiveInfinity * floatP.Zero, float.PositiveInfinity * 0f); - Assert.AreEqual(floatP.PositiveInfinity * (-floatP.Zero), float.PositiveInfinity * (-0f)); - Assert.AreEqual(floatP.PositiveInfinity * floatP.One, float.PositiveInfinity * 1f); - Assert.AreEqual(floatP.PositiveInfinity * floatP.MinusOne, float.PositiveInfinity * -1f); + Assert.AreEqual(floatP.PositiveInfinity * floatP.Zero, (floatP) (float.PositiveInfinity * 0f)); + Assert.AreEqual(floatP.PositiveInfinity * (-floatP.Zero), (floatP)(float.PositiveInfinity * (-0f))); + Assert.AreEqual(floatP.PositiveInfinity * floatP.One, (floatP)(float.PositiveInfinity * 1f)); + Assert.AreEqual(floatP.PositiveInfinity * floatP.MinusOne, (floatP)(float.PositiveInfinity * -1f)); - Assert.AreEqual(floatP.NegativeInfinity * floatP.Zero, float.NegativeInfinity * 0f); - Assert.AreEqual(floatP.NegativeInfinity * (-floatP.Zero), float.NegativeInfinity * (-0f)); - Assert.AreEqual(floatP.NegativeInfinity * floatP.One, float.NegativeInfinity * 1f); - Assert.AreEqual(floatP.NegativeInfinity * floatP.MinusOne, float.NegativeInfinity * -1f); + Assert.AreEqual(floatP.NegativeInfinity * floatP.Zero, (floatP)(float.NegativeInfinity * 0f)); + Assert.AreEqual(floatP.NegativeInfinity * (-floatP.Zero), (floatP)(float.NegativeInfinity * (-0f))); + Assert.AreEqual(floatP.NegativeInfinity * floatP.One, (floatP)(float.NegativeInfinity * 1f)); + Assert.AreEqual(floatP.NegativeInfinity * floatP.MinusOne, (floatP)(float.NegativeInfinity * -1f)); - Assert.AreEqual(floatP.One * floatP.One, 1f); + Assert.AreEqual(floatP.One * floatP.One, (floatP)1f); } } } diff --git a/package.json b/package.json index 10d2dfc..af7dfed 100644 --- a/package.json +++ b/package.json @@ -2,8 +2,8 @@ "name": "com.gamelovers.dataextensions", "displayName": "Unity Data Type Extensions", "author": "Miguel Tomas", - "version": "0.5.1", - "unity": "2021.4", + "version": "0.6.0", + "unity": "2022.4", "license": "MIT", "description": "This package extends various sets of data types to be used in any type of data containers or persistent serializable data", "type": "library",