diff --git a/src/Spring/Spring.Core/Objects/Support/PropertyComparator.cs b/src/Spring/Spring.Core/Objects/Support/PropertyComparator.cs index cc15bf93..c28618a6 100644 --- a/src/Spring/Spring.Core/Objects/Support/PropertyComparator.cs +++ b/src/Spring/Spring.Core/Objects/Support/PropertyComparator.cs @@ -191,7 +191,15 @@ namespace Spring.Objects.Support /// public static void Sort(IList source, ISortDefinition sortDefinition) { - ArrayList.Adapter(source).Sort(new PropertyComparator(sortDefinition)); +// ArrayList.Adapter(source).Sort(new PropertyComparator(sortDefinition)); + ICollection coll = CollectionUtils.StableSort(source, new PropertyComparator(sortDefinition)); + int index = 0; + IEnumerator it = coll.GetEnumerator(); + while(it.MoveNext()) + { + source[index] = it.Current; + index++; + } } } } \ No newline at end of file diff --git a/src/Spring/Spring.Core/Util/CollectionUtils.cs b/src/Spring/Spring.Core/Util/CollectionUtils.cs index 394e9b5e..106f8efc 100644 --- a/src/Spring/Spring.Core/Util/CollectionUtils.cs +++ b/src/Spring/Spring.Core/Util/CollectionUtils.cs @@ -1,5 +1,5 @@ -#region License - +#region License + /* * Copyright © 2002-2005 the original author or authors. * @@ -14,206 +14,204 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. - */ - -#endregion - -#region Imports - -using System; -using System.Collections; -using System.Reflection; - -#endregion - -namespace Spring.Util -{ - /// - /// Miscellaneous collection utility methods. - /// - /// - /// Mainly for internal use within the framework. - /// - /// Mark Pollack (.NET) - public sealed class CollectionUtils - { - #region Methods - - /// - /// Determine whether a given collection only contains - /// a single unique object - /// - /// - /// - public static bool HasUniqueObject(ICollection coll) - { - if (coll.Count == 0) - { - return false; - } - object candidate = null; - foreach (object elem in coll) - { - if (candidate == null) - { - candidate = elem; - } - else if (candidate != elem) - { - return false; - } - } - return true; - } - - /// - /// Determines whether the contains the specified . - /// - /// The collection to check. - /// The object to locate in the collection. - /// if the element is in the collection, otherwise. - public static bool Contains(ICollection collection, Object element) - { - if (collection == null) - { - throw new ArgumentNullException("Collection cannot be null."); - } - MethodInfo method; - method = collection.GetType().GetMethod("contains", BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public); - if (null == method) - { - throw new InvalidOperationException("Collection type " + collection.GetType() + " does not implement a Contains() method."); - } - return (bool) method.Invoke(collection, new Object[] {element}); - } - - /// - /// Adds the specified to the specified . - /// - /// The collection to add the element to. - /// The object to add to the collection. - public static void Add(ICollection collection, object element) - { - if (collection == null) - { - throw new ArgumentNullException("Collection cannot be null."); - } - MethodInfo method; - method = collection.GetType().GetMethod("add", BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public); - if (null == method) - { - throw new InvalidOperationException("Collection type " + collection.GetType() + " does not implement a Add() method."); - } - method.Invoke(collection, new Object[] {element}); - } - - /// - /// Determines whether the collection contains all the elements in the specified collection. - /// - /// The collection to check. - /// Collection whose elements would be checked for containment. - /// true if the target collection contains all the elements of the specified collection. - public static bool ContainsAll(ICollection targetCollection, ICollection sourceCollection) - { - if (targetCollection == null || sourceCollection == null) - { - throw new ArgumentNullException("Collection cannot be null."); - } - if ( sourceCollection.Count == 0 && targetCollection.Count > 1 ) - return true; - - IEnumerator sourceCollectionEnumerator = sourceCollection.GetEnumerator(); - - bool contains = false; - - MethodInfo method; - method = targetCollection.GetType().GetMethod("containsAll", BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public); - - if (method != null) - contains = (bool) method.Invoke(targetCollection, new Object[] {sourceCollection}); - else - { - method = targetCollection.GetType().GetMethod("Contains", BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public); - if (method == null) - { - throw new InvalidOperationException("Target collection does not implment a Contains() or ContainsAll() method."); - } - while (sourceCollectionEnumerator.MoveNext() == true) - { - if ((contains = (bool) method.Invoke(targetCollection, new Object[] {sourceCollectionEnumerator.Current})) == false) - break; - } - } - return contains; - } - - /// - /// Removes all the elements from the target collection that are contained in the source collection. - /// - /// Collection where the elements will be removed. - /// Elements to remove from the target collection. - public static void RemoveAll(ICollection targetCollection, ICollection sourceCollection) - { - if (targetCollection == null || sourceCollection == null) - { - throw new ArgumentNullException("Collection cannot be null."); - } - ArrayList al = ToArrayList(sourceCollection); - - MethodInfo method; - method = targetCollection.GetType().GetMethod("removeAll", BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public); - - if (method != null) - method.Invoke(targetCollection, new Object[] {al}); - else - { - method = targetCollection.GetType().GetMethod("Remove", BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public, null, new Type[1] {typeof(object)}, null ); - MethodInfo methodContains = targetCollection.GetType().GetMethod("Contains", BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public); - if ( method == null ) - { - throw new InvalidOperationException("Target Collection must implement either a RemoveAll() or Remove() method."); - } - if ( methodContains == null ) - { - throw new InvalidOperationException("TargetCollection must implement a Contains() method."); - } - IEnumerator e = al.GetEnumerator(); - while (e.MoveNext() == true) - { - while ((bool) methodContains.Invoke(targetCollection, new Object[] {e.Current}) == true) - method.Invoke(targetCollection, new Object[] {e.Current}); - } - } - } - - /// - /// Converts an instance to an instance. - /// - /// The instance to be converted. - /// An instance in which its elements are the elements of the instance. - /// if the is null. - public static ArrayList ToArrayList(ICollection inputCollection) - { - if ( inputCollection == null ) - { - throw new ArgumentNullException("Collection cannot be null."); - } - return new ArrayList(inputCollection); - } + */ + +#endregion + +#region Imports + +using System; +using System.Collections; +using System.Reflection; + +#endregion + +namespace Spring.Util +{ + /// + /// Miscellaneous collection utility methods. + /// + /// + /// Mainly for internal use within the framework. + /// + /// Mark Pollack (.NET) + public sealed class CollectionUtils + { + /// + /// Determine whether a given collection only contains + /// a single unique object + /// + /// + /// + public static bool HasUniqueObject(ICollection coll) + { + if (coll.Count == 0) + { + return false; + } + object candidate = null; + foreach (object elem in coll) + { + if (candidate == null) + { + candidate = elem; + } + else if (candidate != elem) + { + return false; + } + } + return true; + } + + /// + /// Determines whether the contains the specified . + /// + /// The collection to check. + /// The object to locate in the collection. + /// if the element is in the collection, otherwise. + public static bool Contains(ICollection collection, Object element) + { + if (collection == null) + { + throw new ArgumentNullException("Collection cannot be null."); + } + MethodInfo method; + method = collection.GetType().GetMethod("contains", BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public); + if (null == method) + { + throw new InvalidOperationException("Collection type " + collection.GetType() + " does not implement a Contains() method."); + } + return (bool)method.Invoke(collection, new Object[] { element }); + } + + /// + /// Adds the specified to the specified . + /// + /// The collection to add the element to. + /// The object to add to the collection. + public static void Add(ICollection collection, object element) + { + if (collection == null) + { + throw new ArgumentNullException("Collection cannot be null."); + } + MethodInfo method; + method = collection.GetType().GetMethod("add", BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public); + if (null == method) + { + throw new InvalidOperationException("Collection type " + collection.GetType() + " does not implement a Add() method."); + } + method.Invoke(collection, new Object[] { element }); + } + + /// + /// Determines whether the collection contains all the elements in the specified collection. + /// + /// The collection to check. + /// Collection whose elements would be checked for containment. + /// true if the target collection contains all the elements of the specified collection. + public static bool ContainsAll(ICollection targetCollection, ICollection sourceCollection) + { + if (targetCollection == null || sourceCollection == null) + { + throw new ArgumentNullException("Collection cannot be null."); + } + if (sourceCollection.Count == 0 && targetCollection.Count > 1) + return true; + + IEnumerator sourceCollectionEnumerator = sourceCollection.GetEnumerator(); + + bool contains = false; + + MethodInfo method; + method = targetCollection.GetType().GetMethod("containsAll", BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public); + + if (method != null) + contains = (bool)method.Invoke(targetCollection, new Object[] { sourceCollection }); + else + { + method = targetCollection.GetType().GetMethod("Contains", BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public); + if (method == null) + { + throw new InvalidOperationException("Target collection does not implment a Contains() or ContainsAll() method."); + } + while (sourceCollectionEnumerator.MoveNext() == true) + { + if ((contains = (bool)method.Invoke(targetCollection, new Object[] { sourceCollectionEnumerator.Current })) == false) + break; + } + } + return contains; + } + + /// + /// Removes all the elements from the target collection that are contained in the source collection. + /// + /// Collection where the elements will be removed. + /// Elements to remove from the target collection. + public static void RemoveAll(ICollection targetCollection, ICollection sourceCollection) + { + if (targetCollection == null || sourceCollection == null) + { + throw new ArgumentNullException("Collection cannot be null."); + } + ArrayList al = ToArrayList(sourceCollection); + + MethodInfo method; + method = targetCollection.GetType().GetMethod("removeAll", BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public); + + if (method != null) + method.Invoke(targetCollection, new Object[] { al }); + else + { + method = targetCollection.GetType().GetMethod("Remove", BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public, null, new Type[1] { typeof(object) }, null); + MethodInfo methodContains = targetCollection.GetType().GetMethod("Contains", BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public); + if (method == null) + { + throw new InvalidOperationException("Target Collection must implement either a RemoveAll() or Remove() method."); + } + if (methodContains == null) + { + throw new InvalidOperationException("TargetCollection must implement a Contains() method."); + } + IEnumerator e = al.GetEnumerator(); + while (e.MoveNext() == true) + { + while ((bool)methodContains.Invoke(targetCollection, new Object[] { e.Current }) == true) + method.Invoke(targetCollection, new Object[] { e.Current }); + } + } + } + + /// + /// Converts an instance to an instance. + /// + /// The instance to be converted. + /// An instance in which its elements are the elements of the instance. + /// if the is null. + public static ArrayList ToArrayList(ICollection inputCollection) + { + if (inputCollection == null) + { + throw new ArgumentNullException("Collection cannot be null."); + } + return new ArrayList(inputCollection); + } /// /// Copies the elements of the to a /// new array of the specified element type. /// - /// The instance to be converted. + /// The instance to be converted. /// The element of the destination array to create and copy elements to - /// An array of the specified element type containing copies of the elements of the . - public static Array ToArray(ICollection inputCollection, Type elementType) + /// An array of the specified element type containing copies of the elements of the . + public static Array ToArray(ICollection inputCollection, Type elementType) { Array array = Array.CreateInstance(elementType, inputCollection.Count); inputCollection.CopyTo(array, 0); return array; - } + } /// /// Finds a value of the given type in the given collection. @@ -222,13 +220,13 @@ namespace Spring.Util /// The type to look for. /// a value of the given type found, or null if none. /// If more than one value of the given type is found - public static object FindValueOfType(ICollection collection, Type type) + public static object FindValueOfType(ICollection collection, Type type) { if (IsEmpty(collection)) { return null; } - Type typeToUse = (type != null ? type : typeof (object)); + Type typeToUse = (type != null ? type : typeof(object)); object val = null; foreach (object obj in collection) { @@ -277,7 +275,7 @@ namespace Spring.Util /// /// true if the specified collection is empty or null; otherwise, false. /// - public static bool IsEmpty(ICollection collection) + public static bool IsEmpty(ICollection collection) { return (collection == null || collection.Count == 0); } @@ -289,11 +287,162 @@ namespace Spring.Util /// /// true if the specified dictionary is empty or null; otherwise, false. /// - public static bool IsEmpty(IDictionary dictionary) + public static bool IsEmpty(IDictionary dictionary) { return (dictionary == null || dictionary.Count == 0); - } - - #endregion - } + } + + /// + /// A callback method used for comparing to items. + /// + /// + /// + /// the first object to compare + /// the second object to compare + /// Value Condition Less than zero x is less than y. Zero x equals y. Greater than zero x is greater than y. + /// + /// + public delegate int CompareCallback(object left, object right); + + /// + /// A simple stable sorting routine - far from being efficient, only for small collections. + /// + /// + /// + /// + public static ICollection StableSort(IEnumerable input, IComparer comparer) + { + return StableSort(input, new CompareCallback(comparer.Compare)); + } + + /// + /// A simple stable sorting routine - far from being efficient, only for small collections. + /// + /// + /// Sorting is not(!) done in-place. Instead a sorted copy of the original input is returned. + /// + /// input collection of items to sort + /// the for comparing 2 items in . + /// a new collection of stable sorted items. + public static ICollection StableSort(IEnumerable input, CompareCallback comparer) + { + ArrayList ehancedInput = new ArrayList(); + IEnumerator it = input.GetEnumerator(); + int index = 0; + while (it.MoveNext()) + { + ehancedInput.Add(new Entry(index, it.Current)); + index++; + } + + ehancedInput.Sort(Entry.GetComparer(comparer)); + + for (int i = 0; i < ehancedInput.Count; i++ ) + { + ehancedInput[i] = ((Entry) ehancedInput[i]).Value; + } + + return ehancedInput; + } + + /// + /// A simple stable sorting routine - far from being efficient, only for small collections. + /// + /// + /// Sorting is not(!) done in-place. Instead a sorted copy of the original input is returned. + /// + /// input collection of items to sort + /// the for comparing 2 items in . + /// a new collection of stable sorted items. + public static void StableSortInPlace(IList input, CompareCallback comparer) + { + ArrayList ehancedInput = new ArrayList(); + IEnumerator it = input.GetEnumerator(); + int index = 0; + while (it.MoveNext()) + { + ehancedInput.Add(new Entry(index, it.Current)); + index++; + } + + ehancedInput.Sort(Entry.GetComparer(comparer)); + + for (int i = 0; i < ehancedInput.Count; i++) + { + input[i] = ((Entry)ehancedInput[i]).Value; + } + } + + /// + /// A simple stable sorting routine - far from being efficient, only for small collections. + /// + /// + /// Sorting is not(!) done in-place. Instead a sorted copy of the original input is returned. + /// + /// input collection of items to sort + /// the for comparing 2 items in . + /// a new collection of stable sorted items. + public static void StableSortInPlace(Array input, CompareCallback comparer) + { + ArrayList ehancedInput = new ArrayList(); + IEnumerator it = input.GetEnumerator(); + int index = 0; + while (it.MoveNext()) + { + ehancedInput.Add(new Entry(index, it.Current)); + index++; + } + + ehancedInput.Sort(Entry.GetComparer(comparer)); + + for (int i = 0; i < ehancedInput.Count; i++) + { + throw new NotImplementedException(); +// input[i] = ((Entry)ehancedInput[i]).Value; + } + } + + #region StableSort Utility Classes + + private class Entry + { + private class EntryComparer : IComparer + { + private readonly CompareCallback innerComparer; + + public EntryComparer(CompareCallback innerComparer) + { + this.innerComparer = innerComparer; + } + + public int Compare(object x, object y) + { + Entry ex = (Entry)x; + Entry ey = (Entry)y; + int result = innerComparer(ex.Value, ey.Value); + if (result == 0) + { + result = ex.Index.CompareTo(ey.Index); + } + return result; + } + } + + public static IComparer GetComparer(CompareCallback innerComparer) + { + return new EntryComparer(innerComparer); + } + + public readonly int Index; + public readonly object Value; + + public Entry(int index, object value) + { + Index = index; + Value = value; + } + } + + #endregion + } } \ No newline at end of file diff --git a/src/Spring/Spring.Data/Transaction/Support/TransactionSynchronizationManager.cs b/src/Spring/Spring.Data/Transaction/Support/TransactionSynchronizationManager.cs index c2c48230..437797dd 100644 --- a/src/Spring/Spring.Data/Transaction/Support/TransactionSynchronizationManager.cs +++ b/src/Spring/Spring.Data/Transaction/Support/TransactionSynchronizationManager.cs @@ -336,8 +336,13 @@ namespace Spring.Transaction.Support object root = syncs.SyncRoot; lock (root) { - syncs.Sort(syncComparer); - } +// syncs.Sort(syncComparer); + + // StableSort + ICollection sorted = CollectionUtils.StableSort(syncs, syncComparer); + syncs = new ArrayList( sorted ); + } + // Return unmodifiable snapshot, to avoid exceptions // while iterating and invoking synchronization callbacks that in turn // might register further synchronizations. diff --git a/test/Spring/Spring.Core.Tests/Objects/Support/PropertyComparatorTests.cs b/test/Spring/Spring.Core.Tests/Objects/Support/PropertyComparatorTests.cs index 0e5e4eb1..c585c814 100644 --- a/test/Spring/Spring.Core.Tests/Objects/Support/PropertyComparatorTests.cs +++ b/test/Spring/Spring.Core.Tests/Objects/Support/PropertyComparatorTests.cs @@ -140,7 +140,7 @@ namespace Spring.Objects.Support } [Test] - [Ignore("Sort ordering is not preserved (unstable) with equal elements (c.f. System.Array.Sort (Array, IComparer)))")] +// [Ignore("Sort ordering is not preserved (unstable) with equal elements (c.f. System.Array.Sort (Array, IComparer)))")] public void OrderingIsUnperturbedWithEqualProps() { ISortDefinition definition = new MutableSortDefinition("Age", false, true); diff --git a/test/Spring/Spring.Core.Tests/Util/CollectionUtilsTests.cs b/test/Spring/Spring.Core.Tests/Util/CollectionUtilsTests.cs index 33c5f4f3..28062de8 100644 --- a/test/Spring/Spring.Core.Tests/Util/CollectionUtilsTests.cs +++ b/test/Spring/Spring.Core.Tests/Util/CollectionUtilsTests.cs @@ -5,303 +5,303 @@ using Spring.Objects; namespace Spring.Util { - [TestFixture] - public class CollectionUtilsTests - { - internal class NoContainsNoAddCollection : ICollection - { - internal class Iterator : IEnumerator - { - #region IEnumerator Members + [TestFixture] + public class CollectionUtilsTests + { + internal class NoContainsNoAddCollection : ICollection + { + internal class Iterator : IEnumerator + { + #region IEnumerator Members - public void Reset() - { - // TODO: Add Iterator.Reset implementation - } + public void Reset() + { + // TODO: Add Iterator.Reset implementation + } - public object Current - { - get - { - // TODO: Add Iterator.Current getter implementation - return null; - } - } + public object Current + { + get + { + // TODO: Add Iterator.Current getter implementation + return null; + } + } - public bool MoveNext() - { - // TODO: Add Iterator.MoveNext implementation - return false; - } + public bool MoveNext() + { + // TODO: Add Iterator.MoveNext implementation + return false; + } - #endregion + #endregion - } + } - public void CopyTo(Array array, int index) - { - throw new NotImplementedException(); - } + public void CopyTo(Array array, int index) + { + throw new NotImplementedException(); + } - public int Count - { - get { return 0; } - } + public int Count + { + get { return 0; } + } - public object SyncRoot - { - get { throw new NotImplementedException(); } - } + public object SyncRoot + { + get { throw new NotImplementedException(); } + } - public bool IsSynchronized - { - get { throw new NotImplementedException(); } - } + public bool IsSynchronized + { + get { throw new NotImplementedException(); } + } - public IEnumerator GetEnumerator() - { - return new Iterator(); - } - } - [Test] - [ExpectedException(typeof(ArgumentNullException))] - public void ContainsNullCollection() - { - CollectionUtils.Contains(null, null); - } - [Test] - public void ContainsNullObject() - { - ArrayList list = new ArrayList(); - list.Add(null); - Assert.IsTrue(CollectionUtils.Contains(list, null)); - } - [Test] - [ExpectedException(typeof(InvalidOperationException))] - public void ContainsCollectionDoesNotImplementContains() - { - NoContainsNoAddCollection noAddCollection = new NoContainsNoAddCollection(); - CollectionUtils.Contains(noAddCollection, new object()); - } - [Test] - public void ContainsValidElement() - { - ArrayList list = new ArrayList(); - list.Add(1); - list.Add(2); - list.Add(3); - list.Add(4); - - Assert.IsTrue(CollectionUtils.Contains(list, 3)); - } - [Test] - public void ContainsDoesNotContainElement() - { - ArrayList list = new ArrayList(); - list.Add(1); - list.Add(2); - list.Add(3); - list.Add(4); + public IEnumerator GetEnumerator() + { + return new Iterator(); + } + } + [Test] + [ExpectedException(typeof(ArgumentNullException))] + public void ContainsNullCollection() + { + CollectionUtils.Contains(null, null); + } + [Test] + public void ContainsNullObject() + { + ArrayList list = new ArrayList(); + list.Add(null); + Assert.IsTrue(CollectionUtils.Contains(list, null)); + } + [Test] + [ExpectedException(typeof(InvalidOperationException))] + public void ContainsCollectionDoesNotImplementContains() + { + NoContainsNoAddCollection noAddCollection = new NoContainsNoAddCollection(); + CollectionUtils.Contains(noAddCollection, new object()); + } + [Test] + public void ContainsValidElement() + { + ArrayList list = new ArrayList(); + list.Add(1); + list.Add(2); + list.Add(3); + list.Add(4); - Assert.IsFalse(CollectionUtils.Contains(list, 5)); - } - [Test] - [ExpectedException(typeof(ArgumentNullException))] - public void AddNullCollection() - { - CollectionUtils.Add(null, null); - } - [Test] - public void AddNullObject() - { - ArrayList list = new ArrayList(); - CollectionUtils.Add(list, null); - Assert.IsTrue(list.Count == 1); - } - [Test] - [ExpectedException(typeof(InvalidOperationException))] - public void AddCollectionDoesNotImplementAdd() - { - NoContainsNoAddCollection noAddCollection = new NoContainsNoAddCollection(); - CollectionUtils.Add(noAddCollection, null); - } - [Test] - public void AddValidElement() - { - ArrayList list = new ArrayList(); - object obj1 = new object(); - CollectionUtils.Add(list, obj1); - Assert.IsTrue(list.Count == 1); - } - [Test] - [ExpectedException(typeof(ArgumentNullException))] - public void ContainsAllNullTargetCollection() - { - CollectionUtils.ContainsAll(null, new ArrayList()); - } + Assert.IsTrue(CollectionUtils.Contains(list, 3)); + } + [Test] + public void ContainsDoesNotContainElement() + { + ArrayList list = new ArrayList(); + list.Add(1); + list.Add(2); + list.Add(3); + list.Add(4); - [Test] - [ExpectedException(typeof(ArgumentNullException))] - public void ContainsAllSourceNullCollection() - { - CollectionUtils.ContainsAll(new ArrayList(), null); - } - [Test] - [ExpectedException(typeof(InvalidOperationException))] - public void ContainsAllDoesNotImplementContains() - { - CollectionUtils.ContainsAll(new NoContainsNoAddCollection(), new ArrayList()); - } - [Test] - public void DoesNotContainAllElements() - { - ArrayList target = new ArrayList(); - target.Add(1); - target.Add(2); - target.Add(3); + Assert.IsFalse(CollectionUtils.Contains(list, 5)); + } + [Test] + [ExpectedException(typeof(ArgumentNullException))] + public void AddNullCollection() + { + CollectionUtils.Add(null, null); + } + [Test] + public void AddNullObject() + { + ArrayList list = new ArrayList(); + CollectionUtils.Add(list, null); + Assert.IsTrue(list.Count == 1); + } + [Test] + [ExpectedException(typeof(InvalidOperationException))] + public void AddCollectionDoesNotImplementAdd() + { + NoContainsNoAddCollection noAddCollection = new NoContainsNoAddCollection(); + CollectionUtils.Add(noAddCollection, null); + } + [Test] + public void AddValidElement() + { + ArrayList list = new ArrayList(); + object obj1 = new object(); + CollectionUtils.Add(list, obj1); + Assert.IsTrue(list.Count == 1); + } + [Test] + [ExpectedException(typeof(ArgumentNullException))] + public void ContainsAllNullTargetCollection() + { + CollectionUtils.ContainsAll(null, new ArrayList()); + } - ArrayList source = new ArrayList(); - source.Add(1); + [Test] + [ExpectedException(typeof(ArgumentNullException))] + public void ContainsAllSourceNullCollection() + { + CollectionUtils.ContainsAll(new ArrayList(), null); + } + [Test] + [ExpectedException(typeof(InvalidOperationException))] + public void ContainsAllDoesNotImplementContains() + { + CollectionUtils.ContainsAll(new NoContainsNoAddCollection(), new ArrayList()); + } + [Test] + public void DoesNotContainAllElements() + { + ArrayList target = new ArrayList(); + target.Add(1); + target.Add(2); + target.Add(3); - Assert.IsTrue(CollectionUtils.ContainsAll(target, source)); - } - [Test] - public void ContainsAllElements() - { - ArrayList target = new ArrayList(); - target.Add(1); - target.Add(2); - target.Add(3); + ArrayList source = new ArrayList(); + source.Add(1); - ArrayList source = new ArrayList(); - source.Add(1); - source.Add(2); - source.Add(3); + Assert.IsTrue(CollectionUtils.ContainsAll(target, source)); + } + [Test] + public void ContainsAllElements() + { + ArrayList target = new ArrayList(); + target.Add(1); + target.Add(2); + target.Add(3); - Assert.IsTrue(CollectionUtils.ContainsAll(target, source)); - } - [Test] - public void ContainsAllElementsWithNoElementsInSourceCollection() - { - ArrayList target = new ArrayList(); - target.Add(1); - target.Add(2); - target.Add(3); + ArrayList source = new ArrayList(); + source.Add(1); + source.Add(2); + source.Add(3); - ArrayList source = new ArrayList(); - Assert.IsTrue(CollectionUtils.ContainsAll(target, source)); - } - [Test] - public void ContainsAllElementsWithNoElementsEitherCollection() - { - ArrayList target = new ArrayList(); - ArrayList source = new ArrayList(); - Assert.IsFalse(CollectionUtils.ContainsAll(target, source)); - } - [Test] - [ExpectedException(typeof(ArgumentNullException))] - public void ToArrayNullTargetCollection() - { - CollectionUtils.ToArrayList(null); - } - [Test] - public void ToArrayAllElements() - { - ArrayList target = new ArrayList(); - target.Add(1); - target.Add(2); - target.Add(3); + Assert.IsTrue(CollectionUtils.ContainsAll(target, source)); + } + [Test] + public void ContainsAllElementsWithNoElementsInSourceCollection() + { + ArrayList target = new ArrayList(); + target.Add(1); + target.Add(2); + target.Add(3); - ArrayList source = CollectionUtils.ToArrayList(target); + ArrayList source = new ArrayList(); + Assert.IsTrue(CollectionUtils.ContainsAll(target, source)); + } + [Test] + public void ContainsAllElementsWithNoElementsEitherCollection() + { + ArrayList target = new ArrayList(); + ArrayList source = new ArrayList(); + Assert.IsFalse(CollectionUtils.ContainsAll(target, source)); + } + [Test] + [ExpectedException(typeof(ArgumentNullException))] + public void ToArrayNullTargetCollection() + { + CollectionUtils.ToArrayList(null); + } + [Test] + public void ToArrayAllElements() + { + ArrayList target = new ArrayList(); + target.Add(1); + target.Add(2); + target.Add(3); - Assert.AreEqual(target.Count, source.Count); - } - [Test] - public void EmptyArrayElements() - { - ArrayList source = CollectionUtils.ToArrayList(new NoContainsNoAddCollection()); - Assert.AreEqual(0, source.Count); - } + ArrayList source = CollectionUtils.ToArrayList(target); - [Test] - [ExpectedException(typeof(ArgumentNullException))] - public void RemoveAllTargetNullCollection() - { - CollectionUtils.RemoveAll(null, new ArrayList()); - } - [Test] - [ExpectedException(typeof(ArgumentNullException))] - public void RemoveAllSourceNullCollection() - { - CollectionUtils.RemoveAll(new ArrayList(), null); - } - [Test] - [ExpectedException(typeof(InvalidOperationException))] - public void RemoveAllTargetCollectionDoesNotImplementContains() - { - CollectionUtils.RemoveAll(new NoContainsNoAddCollection(), new ArrayList()); - } - [Test] - [ExpectedException(typeof(InvalidOperationException))] - public void RemoveAllTargetCollectionDoesNotImplementRemove() - { - CollectionUtils.RemoveAll(new NoContainsNoAddCollection(), new ArrayList()); - } - [Test] - public void RemoveAllNoElements() - { - ArrayList target = new ArrayList(); - target.Add(1); - target.Add(2); - target.Add(3); + Assert.AreEqual(target.Count, source.Count); + } + [Test] + public void EmptyArrayElements() + { + ArrayList source = CollectionUtils.ToArrayList(new NoContainsNoAddCollection()); + Assert.AreEqual(0, source.Count); + } - ArrayList source = new ArrayList(); - source.Add(4); - source.Add(5); - source.Add(6); + [Test] + [ExpectedException(typeof(ArgumentNullException))] + public void RemoveAllTargetNullCollection() + { + CollectionUtils.RemoveAll(null, new ArrayList()); + } + [Test] + [ExpectedException(typeof(ArgumentNullException))] + public void RemoveAllSourceNullCollection() + { + CollectionUtils.RemoveAll(new ArrayList(), null); + } + [Test] + [ExpectedException(typeof(InvalidOperationException))] + public void RemoveAllTargetCollectionDoesNotImplementContains() + { + CollectionUtils.RemoveAll(new NoContainsNoAddCollection(), new ArrayList()); + } + [Test] + [ExpectedException(typeof(InvalidOperationException))] + public void RemoveAllTargetCollectionDoesNotImplementRemove() + { + CollectionUtils.RemoveAll(new NoContainsNoAddCollection(), new ArrayList()); + } + [Test] + public void RemoveAllNoElements() + { + ArrayList target = new ArrayList(); + target.Add(1); + target.Add(2); + target.Add(3); - CollectionUtils.RemoveAll(target, source); - Assert.IsTrue(3 == target.Count); - } - [Test] - public void RemoveAllSomeElements() - { - ArrayList target = new ArrayList(); - target.Add(1); - target.Add(2); - target.Add(3); - target.Add(4); - target.Add(5); + ArrayList source = new ArrayList(); + source.Add(4); + source.Add(5); + source.Add(6); - ArrayList source = new ArrayList(); - source.Add(4); - source.Add(5); - source.Add(6); + CollectionUtils.RemoveAll(target, source); + Assert.IsTrue(3 == target.Count); + } + [Test] + public void RemoveAllSomeElements() + { + ArrayList target = new ArrayList(); + target.Add(1); + target.Add(2); + target.Add(3); + target.Add(4); + target.Add(5); - CollectionUtils.RemoveAll(target, source); - Assert.IsTrue(3 == target.Count); - } - [Test] - public void RemoveAllAllElements() - { - ArrayList target = new ArrayList(); - target.Add(1); - target.Add(2); - target.Add(3); - target.Add(4); - target.Add(5); + ArrayList source = new ArrayList(); + source.Add(4); + source.Add(5); + source.Add(6); - ArrayList source = new ArrayList(); - source.Add(1); - source.Add(2); - source.Add(3); - source.Add(4); - source.Add(5); - source.Add(6); + CollectionUtils.RemoveAll(target, source); + Assert.IsTrue(3 == target.Count); + } + [Test] + public void RemoveAllAllElements() + { + ArrayList target = new ArrayList(); + target.Add(1); + target.Add(2); + target.Add(3); + target.Add(4); + target.Add(5); - CollectionUtils.RemoveAll(target, source); - Assert.IsTrue(0 == target.Count); - } + ArrayList source = new ArrayList(); + source.Add(1); + source.Add(2); + source.Add(3); + source.Add(4); + source.Add(5); + source.Add(6); + + CollectionUtils.RemoveAll(target, source); + Assert.IsTrue(0 == target.Count); + } [Test] public void IsCollectionEmptyOrNull() @@ -331,14 +331,14 @@ namespace Spring.Util ArrayList list = new ArrayList(); Assert.IsNull(CollectionUtils.FindValueOfType(list, typeof(String))); list.Add("foo"); - object obj = CollectionUtils.FindValueOfType(list, typeof (String)); - Assert.IsNotNull(obj); + object obj = CollectionUtils.FindValueOfType(list, typeof(String)); + Assert.IsNotNull(obj); Assert.IsNotNull(obj as string); string val = obj as string; Assert.AreEqual("foo", val); list.Add(new TestObject("Joe", 34)); - obj = CollectionUtils.FindValueOfType(list, typeof (TestObject)); + obj = CollectionUtils.FindValueOfType(list, typeof(TestObject)); Assert.IsNotNull(obj); TestObject to = obj as TestObject; Assert.IsNotNull(to); @@ -349,7 +349,8 @@ namespace Spring.Util { obj = CollectionUtils.FindValueOfType(list, typeof(TestObject)); Assert.Fail("Should have thrown exception"); - } catch (ArgumentException) + } + catch (ArgumentException) { //ok } @@ -361,7 +362,7 @@ namespace Spring.Util { ArrayList list = new ArrayList(); list.Add("mystring"); - string[] strList = (string[]) CollectionUtils.ToArray(list, typeof(string)); + string[] strList = (string[])CollectionUtils.ToArray(list, typeof(string)); Assert.AreEqual(1, strList.Length); try @@ -369,7 +370,39 @@ namespace Spring.Util CollectionUtils.ToArray(list, typeof(Type)); Assert.Fail("should fail"); } - catch(InvalidCastException) {} + catch (InvalidCastException) { } } - } + + [Test] + public void StableSorting() + { + DictionaryEntry[] entries = new DictionaryEntry[] + { + new DictionaryEntry(5, 4), + new DictionaryEntry(5, 5), + new DictionaryEntry(3, 2), + new DictionaryEntry(3, 3), + new DictionaryEntry(1, 0), + new DictionaryEntry(1, 1), + }; + + ICollection resultList = CollectionUtils.StableSort(entries, new CollectionUtils.CompareCallback(CompareEntries)); + DictionaryEntry[] resultEntries = (DictionaryEntry[]) CollectionUtils.ToArray(resultList, typeof(DictionaryEntry)); + + Assert.AreEqual(0, resultEntries[0].Value); + Assert.AreEqual(1, resultEntries[1].Value); + Assert.AreEqual(2, resultEntries[2].Value); + Assert.AreEqual(3, resultEntries[3].Value); + Assert.AreEqual(4, resultEntries[4].Value); + Assert.AreEqual(5, resultEntries[5].Value); + } + + private int CompareEntries(object x, object y) + { + DictionaryEntry dex = (DictionaryEntry)x; + DictionaryEntry dey = (DictionaryEntry)y; + + return ((int)dex.Key).CompareTo(dey.Key); + } + } } diff --git a/test/Spring/Spring.Data.Tests/Transaction/Support/TransactionSynchronizationManagerTests.cs b/test/Spring/Spring.Data.Tests/Transaction/Support/TransactionSynchronizationManagerTests.cs index da888276..cb2bc502 100644 --- a/test/Spring/Spring.Data.Tests/Transaction/Support/TransactionSynchronizationManagerTests.cs +++ b/test/Spring/Spring.Data.Tests/Transaction/Support/TransactionSynchronizationManagerTests.cs @@ -1,6 +1,8 @@ using System; using System.Collections; using NUnit.Framework; +using Spring.Core; +using Spring.Util; namespace Spring.Transaction.Support { @@ -30,6 +32,7 @@ namespace Spring.Transaction.Support IList syncs = TransactionSynchronizationManager.Synchronizations; Assert.IsNotNull(syncs); // to avoid mono mcs error 219 } + [Test] [ExpectedException(typeof(InvalidOperationException))] public void InitSynchronizationsInvalid() @@ -43,12 +46,14 @@ namespace Spring.Transaction.Support { TransactionSynchronizationManager.ClearSynchronization(); } + [Test] [ExpectedException(typeof(InvalidOperationException))] public void RegisterSyncsInvalid() { TransactionSynchronizationManager.RegisterSynchronization(new MockTxnSync()); } + [Test] public void SynchronizationsLifeCycle() { @@ -60,5 +65,57 @@ namespace Spring.Transaction.Support Assert.AreEqual( 1, syncs.Count ); TransactionSynchronizationManager.ClearSynchronization(); } + + [Test(Description = "http://jira.springframework.org/browse/SPRNET-1160")] + public void SynchronizationsExecuteInOrderOfRegistration() + { + TransactionSynchronizationManager.InitSynchronization(); + + try + { + // expect syncs to be run A, B, C, D, E since all have order '1' + TransactionSynchronizationManager.RegisterSynchronization(new Sync("A", 1)); + TransactionSynchronizationManager.RegisterSynchronization(new Sync("B", 1)); + TransactionSynchronizationManager.RegisterSynchronization(new Sync("C", 1)); + TransactionSynchronizationManager.RegisterSynchronization(new Sync("D", 1)); + TransactionSynchronizationManager.RegisterSynchronization(new Sync("E", 1)); + + // simulate what APTM does + Sync[] syncs = (Sync[]) CollectionUtils.ToArray(TransactionSynchronizationManager.Synchronizations, typeof(Sync)); + Assert.AreEqual( "A", syncs[0].Name ); + Assert.AreEqual( "B", syncs[1].Name ); + Assert.AreEqual( "C", syncs[2].Name ); + Assert.AreEqual( "D", syncs[3].Name ); + Assert.AreEqual( "E", syncs[4].Name ); + } + finally + { + TransactionSynchronizationManager.ClearSynchronization(); + } + } + + private class Sync : TransactionSynchronizationAdapter, IOrdered + { + private readonly string name; + private readonly int order; + + public Sync(string name, int order) + { + this.name = name; + this.order = order; + } + + public int Order { get { return order; } } + + public string Name + { + get { return name; } + } + + public override string ToString() + { + return name; + } + } } }