Skip to content

Commit fd654bf

Browse files
committed
Add methods to Properties to support Oakley.
1 parent ff7af50 commit fd654bf

2 files changed

Lines changed: 141 additions & 15 deletions

File tree

src/MrKWatkins.Ast.Tests/PropertiesTests.cs

Lines changed: 91 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,20 @@ public void GetOrThrow_ExceptionCreator_ThrowsIfNoValueFoundForKey()
4242

4343
var exception = new InvalidOperationException("Test");
4444

45+
Exception Creator() => exception;
46+
47+
properties.Invoking(p => p.GetOrThrow<string>("Key", Creator))
48+
.Should().Throw<InvalidOperationException>()
49+
.Which.Should().BeSameAs(exception);
50+
}
51+
52+
[Test]
53+
public void GetOrThrow_KeyedExceptionCreator_ThrowsIfNoValueFoundForKey()
54+
{
55+
var properties = new Properties();
56+
57+
var exception = new InvalidOperationException("Test");
58+
4559
Exception Creator(string key)
4660
{
4761
key.Should().Be("Key");
@@ -297,10 +311,10 @@ public void GetMultiple()
297311
properties.GetMultiple<int>("Key").Should().BeEmpty();
298312

299313
properties.AddToMultiple("Key", 1);
300-
properties.GetMultiple<int>("Key").Should().BeEquivalentTo(new[] { 1 });
314+
properties.GetMultiple<int>("Key").Should().Equal(1);
301315

302316
properties.AddToMultiple("Key", 2);
303-
properties.GetMultiple<int>("Key").Should().BeEquivalentTo(new[] { 1, 2 }, c => c.WithStrictOrdering());
317+
properties.GetMultiple<int>("Key").Should().Equal(1, 2);
304318
}
305319

306320
[Test]
@@ -332,10 +346,10 @@ public void SetMultiple()
332346
properties.GetMultiple<int>("Key").Should().BeEmpty();
333347

334348
properties.SetMultiple("Key", new[] { 1 });
335-
properties.GetMultiple<int>("Key").Should().BeEquivalentTo(new[] { 1 });
349+
properties.GetMultiple<int>("Key").Should().Equal(1);
336350

337351
properties.SetMultiple("Key", new[] { 1, 2 });
338-
properties.GetMultiple<int>("Key").Should().BeEquivalentTo(new[] { 1, 2 }, c => c.WithStrictOrdering());
352+
properties.GetMultiple<int>("Key").Should().Equal(1, 2);
339353
}
340354

341355
[Test]
@@ -376,7 +390,7 @@ public void SetMultiple_CanAddSubTypes()
376390

377391
properties.SetMultiple<object>("Key", new [] { "Value" });
378392

379-
properties.GetMultiple<object>("Key").Should().BeEquivalentTo(new [] { "Value" });
393+
properties.GetMultiple<object>("Key").Should().Equal("Value");
380394
}
381395

382396
[Test]
@@ -386,10 +400,10 @@ public void AddToMultiple()
386400
properties.GetMultiple<int>("Key").Should().BeEmpty();
387401

388402
properties.AddToMultiple("Key", 1);
389-
properties.GetMultiple<int>("Key").Should().BeEquivalentTo(new[] { 1 });
403+
properties.GetMultiple<int>("Key").Should().Equal(1);
390404

391405
properties.AddToMultiple("Key", 2);
392-
properties.GetMultiple<int>("Key").Should().BeEquivalentTo(new[] { 1, 2 }, c => c.WithStrictOrdering());
406+
properties.GetMultiple<int>("Key").Should().Equal(1, 2);
393407
}
394408

395409
[Test]
@@ -421,7 +435,69 @@ public void AddToMultiple_CanAddSubTypes()
421435

422436
properties.AddToMultiple<object>("Key", "Value");
423437

424-
properties.GetMultiple<object>("Key").Should().BeEquivalentTo(new [] { "Value" });
438+
properties.GetMultiple<object>("Key").Should().Equal("Value");
439+
}
440+
441+
[Test]
442+
public void TryAddToMultiple()
443+
{
444+
var properties = new Properties();
445+
properties.GetMultiple<int>("Key").Should().BeEmpty();
446+
447+
properties.TryAddToMultiple("Key", 1).Should().BeTrue();
448+
properties.GetMultiple<int>("Key").Should().Equal(1);
449+
450+
properties.TryAddToMultiple("Key", 2).Should().BeTrue();
451+
properties.GetMultiple<int>("Key").Should().Equal(1, 2);
452+
453+
properties.TryAddToMultiple("Key", 1).Should().BeFalse();
454+
properties.GetMultiple<int>("Key").Should().Equal(1, 2);
455+
}
456+
457+
[Test]
458+
public void TryAddToMultiple_ValueComparer()
459+
{
460+
var properties = new Properties();
461+
properties.TryAddToMultiple("Key", "One", StringComparer.OrdinalIgnoreCase).Should().BeTrue();
462+
properties.GetMultiple<string>("Key").Should().Equal("One");
463+
464+
properties.TryAddToMultiple("Key", "one", StringComparer.OrdinalIgnoreCase).Should().BeFalse();
465+
properties.GetMultiple<string>("Key").Should().Equal("One");
466+
467+
properties.TryAddToMultiple("Key", "one").Should().BeTrue();
468+
properties.GetMultiple<string>("Key").Should().Equal("One", "one");
469+
}
470+
471+
[Test]
472+
public void TryAddToMultiple_ThrowsIfValueIsASingle()
473+
{
474+
var properties = new Properties();
475+
properties.Set("Key", 1);
476+
477+
properties.Invoking(p => p.TryAddToMultiple("Key", 1))
478+
.Should().Throw<InvalidOperationException>()
479+
.WithMessage("Property \"Key\" is a single value.");
480+
}
481+
482+
[Test]
483+
public void TryAddToMultiple_ThrowsIfExistingValueOfADifferentType()
484+
{
485+
var properties = new Properties();
486+
properties.AddToMultiple("One", 1);
487+
488+
properties.Invoking(p => p.TryAddToMultiple("One", "2"))
489+
.Should().Throw<InvalidOperationException>()
490+
.WithMessage("Property \"One\" has values of type Int32; cannot change to String.");
491+
}
492+
493+
[Test]
494+
public void TryAddToMultiple_CanAddSubTypes()
495+
{
496+
var properties = new Properties();
497+
498+
properties.TryAddToMultiple<object>("Key", "Value").Should().BeTrue();
499+
500+
properties.GetMultiple<object>("Key").Should().Equal("Value");
425501
}
426502

427503
[Test]
@@ -431,10 +507,10 @@ public void AddRangeToMultiple()
431507
properties.GetMultiple<int>("Key").Should().BeEmpty();
432508

433509
properties.AddRangeToMultiple("Key", new [] { 1, 2 });
434-
properties.GetMultiple<int>("Key").Should().BeEquivalentTo(new[] { 1, 2 }, c => c.WithStrictOrdering());
510+
properties.GetMultiple<int>("Key").Should().Equal(1, 2);
435511

436512
properties.AddRangeToMultiple("Key", new [] { 3, 4 });
437-
properties.GetMultiple<int>("Key").Should().BeEquivalentTo(new[] { 1, 2, 3, 4 }, c => c.WithStrictOrdering());
513+
properties.GetMultiple<int>("Key").Should().Equal(1, 2, 3, 4);
438514
}
439515

440516
[Test]
@@ -466,7 +542,7 @@ public void AddRangeToMultiple_CanAddSubTypes()
466542

467543
properties.AddRangeToMultiple<object>("Key", new[] { "1", "2" });
468544

469-
properties.GetMultiple<object>("Key").Should().BeEquivalentTo(new[] { "1", "2" }, c => c.WithStrictOrdering());
545+
properties.GetMultiple<object>("Key").Should().Equal("1", "2");
470546
}
471547

472548
[Test]
@@ -486,16 +562,16 @@ public void Copy()
486562
copy.GetOrThrow<string>("SingleTwo").Should().Be("Two");
487563
copy.GetOrThrow<object>("SingleThree").Should().Be("Two");
488564

489-
copy.GetMultiple<int>("MultipleOne").Should().BeEquivalentTo(new[] { 1, 2 }, c => c.WithStrictOrdering());
490-
copy.GetMultiple<string>("MultipleTwo").Should().BeEquivalentTo(new [] { "1", "2" }, c => c.WithStrictOrdering());
491-
copy.GetMultiple<object>("MultipleThree").Should().BeEquivalentTo(new object[] { 1, "2" }, c => c.WithStrictOrdering());
565+
copy.GetMultiple<int>("MultipleOne").Should().Equal(1, 2);
566+
copy.GetMultiple<string>("MultipleTwo").Should().Equal("1", "2");
567+
copy.GetMultiple<object>("MultipleThree").Should().Equal(1, "2");
492568

493569
// Mutating the copy should not change the original.
494570
copy.Set("SingleOne", 2);
495571
properties.GetOrThrow<int>("SingleOne").Should().Be(1);
496572

497573
copy.AddToMultiple("MultipleOne", 3);
498-
properties.GetMultiple<int>("MultipleOne").Should().BeEquivalentTo(new[] { 1, 2 }, c => c.WithStrictOrdering());
574+
properties.GetMultiple<int>("MultipleOne").Should().Equal(1, 2);
499575
}
500576

501577
[DoesNotReturn]

src/MrKWatkins.Ast/Properties.cs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,21 @@ public T GetOrThrow<T>(string key)
3737
where T : notnull =>
3838
GetOrThrow<T>(key, k => new KeyNotFoundException($"No value for property with key \"{k}\"."));
3939

40+
/// <summary>
41+
/// Gets the value of a single valued property with the specified key or throws an exception if the property does not exist.
42+
/// </summary>
43+
/// <param name="key">The key of the property.</param>
44+
/// <param name="exceptionCreator">Function to create an exception to throw if the no property with the specified <paramref name="key" /> exists.</param>
45+
/// <typeparam name="T">The type of the property.</typeparam>
46+
/// <returns>The value of the property.</returns>
47+
/// <exception cref="InvalidOperationException">
48+
/// The property is a multiple value property or the type of the property does not match <typeparamref name="T"/>.
49+
/// </exception>
50+
[Pure]
51+
public T GetOrThrow<T>(string key, [InstantHandle] Func<Exception> exceptionCreator)
52+
where T : notnull =>
53+
TryGet<T>(key, out var value) ? value : throw exceptionCreator();
54+
4055
/// <summary>
4156
/// Gets the value of a single valued property with the specified key or throws an exception if the property does not exist.
4257
/// </summary>
@@ -209,6 +224,41 @@ public void AddToMultiple<T>(string key, T value)
209224

210225
list.Add(value);
211226
}
227+
228+
/// <summary>
229+
/// Tries to add a value to a multiple valued property with the specified key. If the value already exists in the multiple
230+
/// then it is not added.
231+
/// </summary>
232+
/// <param name="key">The key of the property.</param>
233+
/// <param name="value">The value to add to the property.</param>
234+
/// <param name="valueComparer">An equality comparer to compare values or <c>null</c> for the default comparer.</param>
235+
/// <returns><c>true</c> if the value was added, <c>false</c> otherwise.</returns>
236+
/// <typeparam name="T">The type of the property.</typeparam>
237+
/// <exception cref="InvalidOperationException">
238+
/// The property already has a value and is a single value property or the type of the property does not match <typeparamref name="T"/>.
239+
/// </exception>
240+
public bool TryAddToMultiple<T>(string key, T value, IEqualityComparer<T>? valueComparer = null)
241+
where T : notnull
242+
{
243+
List<T> list;
244+
if (properties.TryGetValue(key, out var property))
245+
{
246+
list = VerifyMultiple<T>(key, property);
247+
if (!list.Contains(value, valueComparer))
248+
{
249+
list.Add(value);
250+
return true;
251+
}
252+
253+
return false;
254+
}
255+
256+
list = new List<T>();
257+
properties.Add(key, new Property(true, typeof(T), list));
258+
259+
list.Add(value);
260+
return true;
261+
}
212262

213263
/// <summary>
214264
/// Adds values to a multiple valued property with the specified key.

0 commit comments

Comments
 (0)