|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using Microsoft.Build.Collections;
using Shouldly;
using Xunit;
namespace Microsoft.Build.UnitTests.OM.Collections
{
/// <summary>
/// Tests for <see cref="CopyOnWritePropertyDictionary{T}"/>.
/// </summary>
public class CopyOnWritePropertyDictionary_Tests
{
[Fact]
public void Count()
{
var dic = CreateInstance();
dic.Count.ShouldBe(0);
dic.Set(new("a"));
dic.Count.ShouldBe(1);
dic.Set(new("b"));
dic.Count.ShouldBe(2);
dic.Set(new("c"));
dic.Count.ShouldBe(3);
dic.Clear();
dic.Count.ShouldBe(0);
}
[Fact]
public void Indexer()
{
var dic = CreateInstance();
MockValue a = new("a");
MockValue b = new("b");
dic["a"].ShouldBeNull();
dic["b"].ShouldBeNull();
dic["a"] = a;
dic["a"].ShouldBeSameAs(a);
dic["b"].ShouldBeNull();
dic["b"] = b;
dic["a"].ShouldBeSameAs(a);
dic["b"].ShouldBeSameAs(b);
// Cannot set a null value
Assert.ThrowsAny<Exception>(() => dic["a"] = null!);
// Value's key must match the specified key
Assert.ThrowsAny<Exception>(() => dic["a"] = b);
}
[Fact]
public void Contains()
{
var dic = CreateInstance();
MockValue a = new("a");
MockValue b = new("b");
dic.Contains("a").ShouldBeFalse();
dic.Contains("b").ShouldBeFalse();
dic["a"] = a;
dic.Contains("a").ShouldBeTrue();
dic.Contains("b").ShouldBeFalse();
dic["b"] = b;
dic.Contains("a").ShouldBeTrue();
dic.Contains("b").ShouldBeTrue();
}
[Fact]
public void Clear()
{
var dic = CreateInstance("a", "b", "c");
dic.Count.ShouldBe(3);
dic.Clear();
dic.Count.ShouldBe(0);
}
[Fact]
public void Enumeration()
{
var dic = CreateInstance();
MockValue a = new("a");
MockValue b = new("b");
dic.Set(a);
dic.Set(b);
dic.ShouldBeSetEquivalentTo(new[] { a, b });
}
[Fact]
public void Equal()
{
var dic1 = CreateInstance("a", "b", "c");
var dic2 = CreateInstance("a", "b", "c");
var dic3 = CreateInstance("c", "b", "a"); // reversed order
var dic4 = CreateInstance("a", "b"); // missing item
var dic5 = CreateInstance("a", "b", "c", "d"); // extra item
Test(dic1, dic1, true);
Test(dic1, dic2, true);
Test(dic1, dic3, true);
Test(dic1, dic4, false);
Test(dic1, dic5, false);
static void Test(CopyOnWritePropertyDictionary<MockValue> a, CopyOnWritePropertyDictionary<MockValue> b, bool expected)
{
if (expected)
{
// Test equality in both directions
a.ShouldBe(b);
b.ShouldBe(a);
}
else
{
// Test equality in both directions
a.ShouldNotBe(b);
b.ShouldNotBe(a);
}
}
}
[Fact]
public void Remove()
{
var dic = CreateInstance("a", "b", "c");
dic.Remove("ZZZ").ShouldBeFalse();
dic.Remove("a").ShouldBeTrue();
dic.Remove("a").ShouldBeFalse();
dic.Remove("b").ShouldBeTrue();
dic.Remove("c").ShouldBeTrue();
dic.Count.ShouldBe(0);
}
[Fact]
public void ImportProperties()
{
var dic = CreateInstance();
MockValue a = new("a");
MockValue b = new("b");
dic.ImportProperties(new[] { a, b });
dic.ShouldBeSetEquivalentTo(new[] { a, b });
}
[Fact]
public void DeepClone()
{
CopyOnWritePropertyDictionary<MockValue> source = CreateInstance("a", "b", "c");
CopyOnWritePropertyDictionary<MockValue> clone = (CopyOnWritePropertyDictionary<MockValue>)source.DeepClone();
source.ShouldBe(clone);
source.ShouldNotBeSameAs(clone);
}
private static CopyOnWritePropertyDictionary<MockValue> CreateInstance(params string[] values)
{
CopyOnWritePropertyDictionary<MockValue> dic = new CopyOnWritePropertyDictionary<MockValue>();
foreach (string value in values)
{
dic.Set(new(value));
}
return dic;
}
private sealed class MockValue : IKeyed, IValued, IEquatable<MockValue>, IEquatable<object>, IImmutable
{
public MockValue(string s) => Key = s;
public string Key { get; }
public string EscapedValue => Key;
public bool Equals(MockValue? other)
{
return other != null && Key == other.Key;
}
public new bool Equals(object? other)
{
if (other is MockValue mv)
{
return Equals(mv);
}
return false;
}
}
}
}
|