/* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, 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. * */ using System; using System.Collections; using System.Collections.Generic; using NUnit.Framework; namespace Lucene.Net.Support { [TestFixture] public class TestEquatableList { /// /// This test shows that System.Collections.Generic.List is not suitable for determining uniqueness /// when used in a HashSet. This is a difference between the Java and .NET BCL Lists. Since the equatable /// behaviour of java.util.List.hashCode() in Java is relied upon for the the Java Lucene implementation, /// a correct port must use an equatable list with the same behaviour. /// /// We include this unit test here, to prove the problem with the .NET List type. If this test fails, we /// can remove the SupportClass.EquatableList class, and replace it with System.Collection.Generic.List. /// [Test] public void System_Collections_Generic_List_Not_Suitable_For_Determining_Uniqueness_In_HashSet() { // reference equality var foo = new Object(); var bar = new Object(); var list1 = new List {foo, bar}; var list2 = new List {foo, bar}; var hashSet = new HashSet>(); Assert.IsTrue(hashSet.Add(list1)); // note: compare this assertion to the assertion in Suitable_For_Determining_Uniqueness_In_HashSet Assert.IsTrue(hashSet.Add(list2), "BCL List changed equality behaviour and is now suitable for use in HashSet! Yay!"); } /// /// This test shows that System.Collections.Generic.List is not suitable for determining uniqueness /// when used in a Hashtable. This is a difference between the Java and .NET BCL Lists. Since the equatable /// behaviour of java.util.List.hashCode() in Java is relied upon for the the Java Lucene implementation, /// a correct port must use an equatable list with the same behaviour. /// /// We include this unit test here, to prove the problem with the .NET List type. If this test fails, we /// can remove the SupportClass.EquatableList class, and replace it with System.Collection.Generic.List. /// [Test] public void System_Collections_Generic_List_Not_Suitable_For_Determining_Uniqueness_In_Hashtable() { // reference equality var foo = new Object(); var bar = new Object(); var list1 = new List {foo, bar}; var list2 = new List {foo, bar}; var hashTable = new Hashtable(); Assert.IsFalse(hashTable.ContainsKey(list1)); hashTable.Add(list1, list1); // note: compare this assertion to the assertion in Suitable_For_Determining_Uniqueness_In_Hashtable Assert.IsFalse( hashTable.ContainsKey(list2), "BCL List changed behaviour and is now suitable for use as a replacement for Java's List! Yay!"); } /// /// There is a interesting problem with .NET's String.GetHashCode() for certain strings. /// This unit test displays the problem, and in the event that this is changed in the /// .NET runtime, the test will fail. /// /// This is one of the reasons that the EquatableList implementation does not use GetHashCode() /// (which is a divergence from the List.equals implementation in Java). EquatableList should have /// the same overall results as Java's List however. /// /// For an explanation of this issue see: /// http://blogs.msdn.com/b/ericlippert/archive/2011/07/12/what-curious-property-does-this-string-have.aspx /// For a description of the GetHashCode implementation see: /// http://www.dotnetperls.com/gethashcode /// For documentation on List.getHashCode(), see: /// http://download.oracle.com/javase/6/docs/api/java/util/List.html#hashCode() /// And in the general case, see: /// http://download.oracle.com/javase/6/docs/api/java/lang/Object.html#hashCode() /// [Test] public void System_String_GetHashCode_Exhibits_Inconsistent_Inequality_For_Some_Values() { var val1 = "\uA0A2\uA0A2"; var val2 = string.Empty; Assert.IsFalse(val1.Equals(val2)); var hash1 = val1.GetHashCode(); var hash2 = val2.GetHashCode(); // note: this is counter-intuative, but technically allowed by the contract for GetHashCode() // this only works in 32 bit processes. // if 32 bit process if (IntPtr.Size == 4) { // TODO: determine if there is an similar issue when in a 64 bit process. Assert.IsTrue( hash1.Equals(hash2), "BCL string.GetHashCode() no longer exhibits inconsistent inequality for certain strings." ); } } [Test] public void Suitable_For_Determining_Uniqueness_In_HashSet() { var foo = new Object(); var bar = new Object(); var list1 = new EquatableList {foo, bar}; var list2 = new EquatableList {foo, bar}; Assert.AreEqual(list1, list2); var hashSet = new HashSet>(); Assert.IsTrue(hashSet.Add(list1)); Assert.IsFalse(hashSet.Add(list2)); } [Test] public void Suitable_For_Determining_Uniqueness_In_Hashtable() { var foo = new Object(); var bar = new Object(); var list1 = new EquatableList { foo, bar }; var list2 = new EquatableList { foo, bar }; var hashTable = new Hashtable(); Assert.IsFalse(hashTable.ContainsKey(list1)); hashTable.Add(list1, list1); Assert.IsTrue(hashTable.ContainsKey(list2)); } } }