You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@avro.apache.org by dk...@apache.org on 2018/12/05 16:19:11 UTC
[avro] branch master updated: C# - Generic Record - Fix false
positive equality (#204)
This is an automated email from the ASF dual-hosted git repository.
dkulp pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/avro.git
The following commit(s) were added to refs/heads/master by this push:
new 0530d6c C# - Generic Record - Fix false positive equality (#204)
0530d6c is described below
commit 0530d6cebf1979ca65b6abb7b2df080460910127
Author: Lukas Sedlacek <ls...@users.noreply.github.com>
AuthorDate: Wed Dec 5 16:19:07 2018 +0000
C# - Generic Record - Fix false positive equality (#204)
* C# - Test GenericRecord.Equals with [map,array] field
* C# - Fix GenericRecord.Equals for [map,array] field
---
.../src/apache/main/Generic/GenericRecord.cs | 56 +++++++++----------
.../csharp/src/apache/test/Generic/GenericTests.cs | 63 ++++++++++++++++++++++
2 files changed, 92 insertions(+), 27 deletions(-)
diff --git a/lang/csharp/src/apache/main/Generic/GenericRecord.cs b/lang/csharp/src/apache/main/Generic/GenericRecord.cs
index 3804d15..3550609 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
{
/// <summary>
/// The default type used by GenericReader and GenericWriter for RecordSchema.
/// </summary>
- public class GenericRecord
+ public class GenericRecord : IEquatable<GenericRecord>
{
public RecordSchema Schema { get; private set; }
- private IDictionary<string, object> contents = new Dictionary<string, object>();
+ private readonly Dictionary<string, object> contents = new Dictionary<string, object>();
public GenericRecord(RecordSchema schema)
{
this.Schema = schema;
@@ -61,52 +60,55 @@ namespace Avro.Generic
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<string, object> d1, IDictionary<string, object> 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<string, object> 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<string, object>)
+
+ if (o1 is IDictionary)
{
- if (!(o2 is IDictionary<string, object>)) return false;
- return areEqual(o1 as IDictionary<string, object>, o1 as IDictionary<string, object>);
+ 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;
}
diff --git a/lang/csharp/src/apache/test/Generic/GenericTests.cs b/lang/csharp/src/apache/test/Generic/GenericTests.cs
index 19951fd..b5bdc8d 100644
--- a/lang/csharp/src/apache/test/Generic/GenericTests.cs
+++ b/lang/csharp/src/apache/test/Generic/GenericTests.cs
@@ -385,6 +385,69 @@ namespace Avro.Test.Generic
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<int[], GenericRecord> 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<int[], GenericRecord> 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<int, GenericRecord> makeRec = value => mkRecord(
+ new object[] { "a", new Dictionary<string, int> { { "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<int, GenericRecord> makeRec = value => mkRecord(
+ new object[] { "a", new Dictionary<string, int> { { "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);