From 5d40a2d316d7ba5c9d089a919a9c8733249aed5b Mon Sep 17 00:00:00 2001 From: Lukas Sedlacek Date: Wed, 8 Mar 2017 12:44:22 +0000 Subject: [PATCH 1/2] C# - Test GenericRecord.Equals with [map,array] field --- .../src/apache/test/Generic/GenericTests.cs | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/lang/csharp/src/apache/test/Generic/GenericTests.cs b/lang/csharp/src/apache/test/Generic/GenericTests.cs index d08e7bae7b5..4d632e84753 100644 --- a/lang/csharp/src/apache/test/Generic/GenericTests.cs +++ b/lang/csharp/src/apache/test/Generic/GenericTests.cs @@ -385,6 +385,69 @@ public void TestResolutionMismatch_fixed(string ws, byte[] value, string rs) testResolutionMismatch(ws, mkFixed(ws, value), rs); } + [Test] + public void TestRecordEquality_arrayFieldnotEqual() + { + var schema = (RecordSchema)Schema.Parse( + "{\"type\":\"record\",\"name\":\"r\",\"fields\":" + + "[{\"name\":\"a\",\"type\":{\"type\":\"array\",\"items\":\"int\"}}]}"); + + Func makeRec = arr => mkRecord(new object[] { "a", arr }, schema); + + var rec1 = makeRec(new[] { 69, 23 }); + var rec2 = makeRec(new[] { 42, 11 }); + + Assert.AreNotEqual(rec1, rec2); + } + + [Test] + public void TestRecordEquality_arrayFieldequal() + { + var schema = (RecordSchema)Schema.Parse( + "{\"type\":\"record\",\"name\":\"r\",\"fields\":" + + "[{\"name\":\"a\",\"type\":{\"type\":\"array\",\"items\":\"int\"}}]}"); + + Func makeRec = arr => mkRecord(new object[] { "a", arr }, schema); + + // Intentionally duplicated so reference equality doesn't apply + var rec1 = makeRec(new[] { 89, 12, 66 }); + var rec2 = makeRec(new[] { 89, 12, 66 }); + + Assert.AreEqual(rec1, rec2); + } + + [Test] + public void TestRecordEquality_mapFieldequal() + { + var schema = (RecordSchema)Schema.Parse( + "{\"type\":\"record\",\"name\":\"r\",\"fields\":" + + "[{\"name\":\"a\",\"type\":{\"type\":\"map\",\"values\":\"int\"}}]}"); + + Func makeRec = value => mkRecord( + new object[] { "a", new Dictionary { { "key", value } } }, schema); + + var rec1 = makeRec(52); + var rec2 = makeRec(52); + + Assert.AreEqual(rec1, rec2); + } + + [Test] + public void TestRecordEquality_mapFieldnotEqual() + { + var schema = (RecordSchema)Schema.Parse( + "{\"type\":\"record\",\"name\":\"r\",\"fields\":" + + "[{\"name\":\"a\",\"type\":{\"type\":\"map\",\"values\":\"int\"}}]}"); + + Func makeRec = value => mkRecord( + new object[] { "a", new Dictionary { { "key", value } } }, schema); + + var rec1 = makeRec(69); + var rec2 = makeRec(98); + + Assert.AreNotEqual(rec1, rec2); + } + private static GenericRecord mkRecord(object[] kv, RecordSchema s) { GenericRecord input = new GenericRecord(s); From de71935e7a24264ed53a97ddd46ea75297fd9da8 Mon Sep 17 00:00:00 2001 From: Lukas Sedlacek Date: Wed, 8 Mar 2017 16:08:56 +0000 Subject: [PATCH 2/2] C# - Fix GenericRecord.Equals for [map,array] field --- .../src/apache/main/Generic/GenericRecord.cs | 56 ++++++++++--------- 1 file changed, 29 insertions(+), 27 deletions(-) diff --git a/lang/csharp/src/apache/main/Generic/GenericRecord.cs b/lang/csharp/src/apache/main/Generic/GenericRecord.cs index 3804d1584a9..35506099440 100644 --- a/lang/csharp/src/apache/main/Generic/GenericRecord.cs +++ b/lang/csharp/src/apache/main/Generic/GenericRecord.cs @@ -16,21 +16,20 @@ * limitations under the License. */ using System; +using System.Collections; using System.Collections.Generic; -using System.Linq; using System.Text; -using Avro; namespace Avro.Generic { /// /// The default type used by GenericReader and GenericWriter for RecordSchema. /// - public class GenericRecord + public class GenericRecord : IEquatable { public RecordSchema Schema { get; private set; } - private IDictionary contents = new Dictionary(); + private readonly Dictionary contents = new Dictionary(); public GenericRecord(RecordSchema schema) { this.Schema = schema; @@ -61,52 +60,55 @@ public bool TryGetValue(string fieldName, out object result) public override bool Equals(object obj) { if (this == obj) return true; - if (obj != null && obj is GenericRecord) - { - GenericRecord other = obj as GenericRecord; - return Schema.Equals(other.Schema) && areEqual(contents, other.contents); - } - return false; + return obj is GenericRecord + && Equals((GenericRecord)obj); + } + + public bool Equals(GenericRecord other) + { + return Schema.Equals(other.Schema) + && mapsEqual(contents, other.contents); } - private static bool areEqual(IDictionary d1, IDictionary d2) + private static bool mapsEqual(IDictionary d1, IDictionary d2) { - if (d1.Count == d2.Count) + if (d1.Count != d2.Count) return false; + + foreach (DictionaryEntry kv in d1) { - foreach (KeyValuePair kv in d1) - { - object o; - if (!d2.TryGetValue(kv.Key, out o)) return false; - if (!areEqual(o, kv.Value)) return false; - } - return true; + if (!d2.Contains(kv.Key)) + return false; + if (!objectsEqual(d2[kv.Key], kv.Value)) + return false; } - return false; + return true; } - private static bool areEqual(object o1, object o2) + private static bool objectsEqual(object o1, object o2) { if (o1 == null) return o2 == null; if (o2 == null) return false; if (o1 is Array) { if (!(o2 is Array)) return false; - return areEqual(o1 as Array, o1 as Array); + return arraysEqual((Array)o1 , (Array)o2); } - else if (o1 is IDictionary) + + if (o1 is IDictionary) { - if (!(o2 is IDictionary)) return false; - return areEqual(o1 as IDictionary, o1 as IDictionary); + if (!(o2 is IDictionary)) return false; + return mapsEqual((IDictionary)o1, (IDictionary)o2); } + return o1.Equals(o2); } - private static bool areEqual(Array a1, Array a2) + private static bool arraysEqual(Array a1, Array a2) { if (a1.Length != a2.Length) return false; for (int i = 0; i < a1.Length; i++) { - if (!areEqual(a1.GetValue(i), a2.GetValue(i))) return false; + if (!objectsEqual(a1.GetValue(i), a2.GetValue(i))) return false; } return true; }