Skip to content

Commit 1ed4e84

Browse files
committed
Add DictionaryExtensions.SequenceEqual
1 parent 2f0b014 commit 1ed4e84

File tree

2 files changed

+147
-0
lines changed

2 files changed

+147
-0
lines changed

tracer/src/Datadog.Trace/ExtensionMethods/DictionaryExtensions.cs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using System.Collections;
88
using System.Collections.Concurrent;
99
using System.Collections.Generic;
10+
using System.Collections.ObjectModel;
1011
using Datadog.Trace.Util;
1112

1213
namespace Datadog.Trace.ExtensionMethods
@@ -128,5 +129,42 @@ public static TV Get<TK, TV>(this Dictionary<TK, TV> map, TK key, Func<TK, TV> c
128129
map[key] = newVal;
129130
return newVal;
130131
}
132+
133+
/// <summary>
134+
/// Checks if two dictionaries contain the same keys and values.
135+
/// Note that this method assumes the two dictionaries use the same
136+
/// <see cref="IEqualityComparer"/>; using different comparers in each
137+
/// dictionary is not supported.
138+
/// </summary>
139+
public static bool SequenceEqual(
140+
this ReadOnlyDictionary<string, string> dict1,
141+
ReadOnlyDictionary<string, string> dict2,
142+
StringComparison valueComparison = StringComparison.Ordinal)
143+
{
144+
if (dict1 is null & dict2 is null)
145+
{
146+
return true;
147+
}
148+
149+
if (dict1 is null || dict2 is null || dict1.Count != dict2.Count)
150+
{
151+
return false;
152+
}
153+
154+
if (dict1.Count == 0 && dict2.Count == 0)
155+
{
156+
return true;
157+
}
158+
159+
foreach (var kvp1 in dict1)
160+
{
161+
if (!dict2.TryGetValue(kvp1.Key, out var val2) || !string.Equals(kvp1.Value, val2, valueComparison))
162+
{
163+
return false;
164+
}
165+
}
166+
167+
return true;
168+
}
131169
}
132170
}
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
// <copyright file="DictionaryExtensionsTests.cs" company="Datadog">
2+
// Unless explicitly stated otherwise all files in this repository are licensed under the Apache 2 License.
3+
// This product includes software developed at Datadog (https://www.datadoghq.com/). Copyright 2017 Datadog, Inc.
4+
// </copyright>
5+
6+
using System;
7+
using System.Collections.Generic;
8+
using System.Collections.ObjectModel;
9+
using Datadog.Trace.ExtensionMethods;
10+
using Datadog.Trace.Util;
11+
using FluentAssertions;
12+
using Xunit;
13+
14+
namespace Datadog.Trace.Tests.ExtensionMethods;
15+
16+
public class DictionaryExtensionsTests
17+
{
18+
[Fact]
19+
public void SequenceEqual_HandlesBothNull()
20+
{
21+
ReadOnlyDictionary<string, string> dict1 = null;
22+
dict1!.SequenceEqual(null).Should().BeTrue();
23+
}
24+
25+
[Fact]
26+
public void SequenceEqual_HandlesOneNull()
27+
{
28+
ReadOnlyDictionary<string, string> dict1 = null;
29+
ReadOnlyDictionary<string, string> dict2 = ReadOnlyDictionary.Empty;
30+
dict1!.SequenceEqual(dict2).Should().BeFalse();
31+
dict2!.SequenceEqual(dict1).Should().BeFalse();
32+
}
33+
34+
[Fact]
35+
public void SequenceEqual_HandlesEmpty()
36+
{
37+
ReadOnlyDictionary<string, string> dict1 = ReadOnlyDictionary.Empty;
38+
ReadOnlyDictionary<string, string> dict2 = ReadOnlyDictionary.Empty;
39+
dict1.SequenceEqual(dict2).Should().BeTrue();
40+
dict2.SequenceEqual(dict1).Should().BeTrue();
41+
}
42+
43+
[Fact]
44+
public void SequenceEqual_HandlesDifferentSizes()
45+
{
46+
ReadOnlyDictionary<string, string> dict1 = new(new Dictionary<string, string> { { "key", "value" } });
47+
ReadOnlyDictionary<string, string> dict2 = ReadOnlyDictionary.Empty;
48+
dict1.SequenceEqual(dict2).Should().BeFalse();
49+
dict2.SequenceEqual(dict1).Should().BeFalse();
50+
}
51+
52+
[Fact]
53+
public void SequenceEqual_HandlesDifferentKeys()
54+
{
55+
ReadOnlyDictionary<string, string> dict1 = new(new Dictionary<string, string> { { "key1", "value" } });
56+
ReadOnlyDictionary<string, string> dict2 = new(new Dictionary<string, string> { { "key2", "value" } });
57+
dict1.SequenceEqual(dict2).Should().BeFalse();
58+
dict2.SequenceEqual(dict1).Should().BeFalse();
59+
}
60+
61+
[Theory]
62+
[InlineData("value2")]
63+
[InlineData("VALUE1")]
64+
[InlineData("value1 ")]
65+
[InlineData(" value1 ")]
66+
[InlineData("")]
67+
[InlineData(null)]
68+
public void SequenceEqual_HandlesDifferentValues(string value)
69+
{
70+
ReadOnlyDictionary<string, string> dict1 = new(new Dictionary<string, string> { { "key", "value1" } });
71+
ReadOnlyDictionary<string, string> dict2 = new(new Dictionary<string, string> { { "key", value } });
72+
dict1.SequenceEqual(dict2).Should().BeFalse();
73+
dict2.SequenceEqual(dict1).Should().BeFalse();
74+
}
75+
76+
[Fact]
77+
public void SequenceEqual_UsesDictionaryKeyComparer()
78+
{
79+
ReadOnlyDictionary<string, string> dict1 = new(new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase) { { "key", "value" } });
80+
ReadOnlyDictionary<string, string> dict2 = new(new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase) { { "KEY", "value" } });
81+
dict1.SequenceEqual(dict2).Should().BeTrue();
82+
dict2.SequenceEqual(dict1).Should().BeTrue();
83+
}
84+
85+
[Fact]
86+
public void SequenceEqual_UsesDictionaryWithDifferentComparersIsNotSupported()
87+
{
88+
ReadOnlyDictionary<string, string> dict1 = new(new Dictionary<string, string>(StringComparer.Ordinal) { { "key", "value" } });
89+
ReadOnlyDictionary<string, string> dict2 = new(new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase) { { "KEY", "value" } });
90+
91+
// reversing the order changes the result
92+
dict1.SequenceEqual(dict2).Should().BeTrue();
93+
dict2.SequenceEqual(dict1).Should().BeFalse();
94+
}
95+
96+
[Theory]
97+
[InlineData(StringComparison.Ordinal, "value", true)]
98+
[InlineData(StringComparison.Ordinal, "VALUE", false)]
99+
[InlineData(StringComparison.OrdinalIgnoreCase, "VALUE", true)]
100+
public void SequenceEqual_UsesComparer(StringComparison comparison, string value, bool expected)
101+
{
102+
ReadOnlyDictionary<string, string> dict1 = new(new Dictionary<string, string> { { "key", "value" } });
103+
ReadOnlyDictionary<string, string> dict2 = new(new Dictionary<string, string> { { "key", value } });
104+
105+
// reversing the order changes the result
106+
dict1.SequenceEqual(dict2, comparison).Should().Be(expected);
107+
dict2.SequenceEqual(dict1, comparison).Should().Be(expected);
108+
}
109+
}

0 commit comments

Comments
 (0)