#region Copyright notice and license
// Protocol Buffers - Google's data interchange format
// Copyright 2015 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#endregion
using System;
using System.Collections.Generic;
using Google.Protobuf.TestProtos;
using NUnit.Framework;
using System.Collections;
using System.Linq;
namespace Google.Protobuf.Collections
{
///
/// Tests for MapField which aren't reliant on the encoded format -
/// tests for serialization/deserialization are part of GeneratedMessageTest.
///
public class MapFieldTest
{
[Test]
public void Clone_ClonesMessages()
{
var message = new ForeignMessage { C = 20 };
var map = new MapField { { "x", message } };
var clone = map.Clone();
map["x"].C = 30;
Assert.AreEqual(20, clone["x"].C);
}
[Test]
public void NullValuesProhibited()
{
TestNullValues(0);
TestNullValues("");
TestNullValues(new TestAllTypes());
}
private void TestNullValues(T nonNullValue)
{
var map = new MapField();
var nullValue = (T) (object) null;
Assert.Throws(() => map.Add(0, nullValue));
Assert.Throws(() => map[0] = nullValue);
map.Add(1, nonNullValue);
map[1] = nonNullValue;
}
[Test]
public void Add_ForbidsNullKeys()
{
var map = new MapField();
Assert.Throws(() => map.Add(null, new ForeignMessage()));
}
[Test]
public void Indexer_ForbidsNullKeys()
{
var map = new MapField();
Assert.Throws(() => map[null] = new ForeignMessage());
}
[Test]
public void AddPreservesInsertionOrder()
{
var map = new MapField();
map.Add("a", "v1");
map.Add("b", "v2");
map.Add("c", "v3");
map.Remove("b");
map.Add("d", "v4");
CollectionAssert.AreEqual(new[] { "a", "c", "d" }, map.Keys);
CollectionAssert.AreEqual(new[] { "v1", "v3", "v4" }, map.Values);
}
[Test]
public void EqualityIsOrderInsensitive()
{
var map1 = new MapField();
map1.Add("a", "v1");
map1.Add("b", "v2");
var map2 = new MapField();
map2.Add("b", "v2");
map2.Add("a", "v1");
EqualityTester.AssertEquality(map1, map2);
}
[Test]
public void EqualityIsKeySensitive()
{
var map1 = new MapField();
map1.Add("first key", "v1");
map1.Add("second key", "v2");
var map2 = new MapField();
map2.Add("third key", "v1");
map2.Add("fourth key", "v2");
EqualityTester.AssertInequality(map1, map2);
}
[Test]
public void Equality_Simple()
{
var map = new MapField();
EqualityTester.AssertEquality(map, map);
EqualityTester.AssertInequality(map, null);
Assert.IsFalse(map.Equals(new object()));
}
[Test]
public void EqualityIsValueSensitive()
{
// Note: Without some care, it's a little easier than one might
// hope to see hash collisions, but only in some environments...
var map1 = new MapField();
map1.Add("a", "first value");
map1.Add("b", "second value");
var map2 = new MapField();
map2.Add("a", "third value");
map2.Add("b", "fourth value");
EqualityTester.AssertInequality(map1, map2);
}
[Test]
public void Add_Dictionary()
{
var map1 = new MapField
{
{ "x", "y" },
{ "a", "b" }
};
var map2 = new MapField
{
{ "before", "" },
map1,
{ "after", "" }
};
var expected = new MapField
{
{ "before", "" },
{ "x", "y" },
{ "a", "b" },
{ "after", "" }
};
Assert.AreEqual(expected, map2);
CollectionAssert.AreEqual(new[] { "before", "x", "a", "after" }, map2.Keys);
}
// General IDictionary behavior tests
[Test]
public void Add_KeyAlreadyExists()
{
var map = new MapField();
map.Add("foo", "bar");
Assert.Throws(() => map.Add("foo", "baz"));
}
[Test]
public void Add_Pair()
{
var map = new MapField();
ICollection> collection = map;
collection.Add(NewKeyValuePair("x", "y"));
Assert.AreEqual("y", map["x"]);
Assert.Throws(() => collection.Add(NewKeyValuePair("x", "z")));
}
[Test]
public void Contains_Pair()
{
var map = new MapField { { "x", "y" } };
ICollection> collection = map;
Assert.IsTrue(collection.Contains(NewKeyValuePair("x", "y")));
Assert.IsFalse(collection.Contains(NewKeyValuePair("x", "z")));
Assert.IsFalse(collection.Contains(NewKeyValuePair("z", "y")));
}
[Test]
public void Remove_Key()
{
var map = new MapField();
map.Add("foo", "bar");
Assert.AreEqual(1, map.Count);
Assert.IsFalse(map.Remove("missing"));
Assert.AreEqual(1, map.Count);
Assert.IsTrue(map.Remove("foo"));
Assert.AreEqual(0, map.Count);
Assert.Throws(() => map.Remove(null));
}
[Test]
public void Remove_Pair()
{
var map = new MapField();
map.Add("foo", "bar");
ICollection> collection = map;
Assert.AreEqual(1, map.Count);
Assert.IsFalse(collection.Remove(NewKeyValuePair("wrong key", "bar")));
Assert.AreEqual(1, map.Count);
Assert.IsFalse(collection.Remove(NewKeyValuePair("foo", "wrong value")));
Assert.AreEqual(1, map.Count);
Assert.IsTrue(collection.Remove(NewKeyValuePair("foo", "bar")));
Assert.AreEqual(0, map.Count);
Assert.Throws(() => collection.Remove(new KeyValuePair(null, "")));
}
[Test]
public void CopyTo_Pair()
{
var map = new MapField();
map.Add("foo", "bar");
ICollection> collection = map;
KeyValuePair[] array = new KeyValuePair[3];
collection.CopyTo(array, 1);
Assert.AreEqual(NewKeyValuePair("foo", "bar"), array[1]);
}
[Test]
public void Clear()
{
var map = new MapField { { "x", "y" } };
Assert.AreEqual(1, map.Count);
map.Clear();
Assert.AreEqual(0, map.Count);
map.Add("x", "y");
Assert.AreEqual(1, map.Count);
}
[Test]
public void Indexer_Get()
{
var map = new MapField { { "x", "y" } };
Assert.AreEqual("y", map["x"]);
Assert.Throws(() => { var ignored = map["z"]; });
}
[Test]
public void Indexer_Set()
{
var map = new MapField();
map["x"] = "y";
Assert.AreEqual("y", map["x"]);
map["x"] = "z"; // This won't throw, unlike Add.
Assert.AreEqual("z", map["x"]);
}
[Test]
public void GetEnumerator_NonGeneric()
{
IEnumerable map = new MapField { { "x", "y" } };
CollectionAssert.AreEqual(new[] { new KeyValuePair("x", "y") },
map.Cast