Custom dictionary type for attributes
This commit is contained in:
parent
4e08eda58d
commit
6185b16795
|
|
@ -842,6 +842,22 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
|
|||
return string.Format(CultureInfo.CurrentCulture, GetString("TempData_CannotSerializeToSession"), p0, p1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The collection already contains an entry with key '{0}'.
|
||||
/// </summary>
|
||||
internal static string Dictionary_DuplicateKey
|
||||
{
|
||||
get { return GetString("Dictionary_DuplicateKey"); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The collection already contains an entry with key '{0}'.
|
||||
/// </summary>
|
||||
internal static string FormatDictionary_DuplicateKey(object p0)
|
||||
{
|
||||
return string.Format(CultureInfo.CurrentCulture, GetString("Dictionary_DuplicateKey"), p0);
|
||||
}
|
||||
|
||||
private static string GetString(string name, params string[] formatterNames)
|
||||
{
|
||||
var value = _resourceManager.GetString(name);
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
[DebuggerDisplay("{DebuggerToString()}")]
|
||||
public class TagBuilder : IHtmlContent
|
||||
{
|
||||
private AttributeDictionary _attributes;
|
||||
|
||||
public TagBuilder(string tagName)
|
||||
{
|
||||
if (string.IsNullOrEmpty(tagName))
|
||||
|
|
@ -25,15 +27,25 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
}
|
||||
|
||||
TagName = tagName;
|
||||
Attributes = new SortedDictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
InnerHtml = new BufferedHtmlContent();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the set of attributes that will be written to the tag.
|
||||
/// </summary>
|
||||
public IDictionary<string, string> Attributes { get; }
|
||||
public AttributeDictionary Attributes
|
||||
{
|
||||
get
|
||||
{
|
||||
// Perf: Avoid allocating `_attributes` if possible
|
||||
if (_attributes == null)
|
||||
{
|
||||
_attributes = new AttributeDictionary();
|
||||
}
|
||||
|
||||
return _attributes;
|
||||
}
|
||||
}
|
||||
|
||||
public IHtmlContentBuilder InnerHtml { get; }
|
||||
|
||||
|
|
@ -151,20 +163,24 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
|
||||
private void AppendAttributes(TextWriter writer, IHtmlEncoder encoder)
|
||||
{
|
||||
foreach (var attribute in Attributes)
|
||||
// Perf: Avoid allocating enumerator for `_attributes` if possible
|
||||
if (_attributes != null && _attributes.Count > 0)
|
||||
{
|
||||
var key = attribute.Key;
|
||||
if (string.Equals(key, "id", StringComparison.OrdinalIgnoreCase) &&
|
||||
string.IsNullOrEmpty(attribute.Value))
|
||||
foreach (var attribute in Attributes)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
var key = attribute.Key;
|
||||
if (string.Equals(key, "id", StringComparison.OrdinalIgnoreCase) &&
|
||||
string.IsNullOrEmpty(attribute.Value))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
writer.Write(" ");
|
||||
writer.Write(key);
|
||||
writer.Write("=\"");
|
||||
encoder.HtmlEncode(attribute.Value, writer);
|
||||
writer.Write("\"");
|
||||
writer.Write(" ");
|
||||
writer.Write(key);
|
||||
writer.Write("=\"");
|
||||
encoder.HtmlEncode(attribute.Value, writer);
|
||||
writer.Write("\"");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -193,7 +209,8 @@ namespace Microsoft.AspNet.Mvc.Rendering
|
|||
|
||||
public void MergeAttributes<TKey, TValue>(IDictionary<TKey, TValue> attributes, bool replaceExisting)
|
||||
{
|
||||
if (attributes != null)
|
||||
// Perf: Avoid allocating enumerator for `attributes` if possible
|
||||
if (attributes != null && attributes.Count > 0)
|
||||
{
|
||||
foreach (var entry in attributes)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -274,4 +274,7 @@
|
|||
<data name="TempData_CannotSerializeToSession" xml:space="preserve">
|
||||
<value>The '{0}' cannot serialize an object of type '{1}' to session state.</value>
|
||||
</data>
|
||||
<data name="Dictionary_DuplicateKey" xml:space="preserve">
|
||||
<value>The collection already contains an entry with key '{0}'.</value>
|
||||
</data>
|
||||
</root>
|
||||
|
|
@ -0,0 +1,681 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.ViewFeatures
|
||||
{
|
||||
/// <summary>
|
||||
/// A dictionary for HTML attributes.
|
||||
/// </summary>
|
||||
public class AttributeDictionary : IDictionary<string, string>, IReadOnlyDictionary<string, string>
|
||||
{
|
||||
private List<KeyValuePair<string, string>> _items;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string this[string key]
|
||||
{
|
||||
get
|
||||
{
|
||||
if (key == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(key));
|
||||
}
|
||||
|
||||
var index = Find(key);
|
||||
if (index < 0)
|
||||
{
|
||||
throw new KeyNotFoundException();
|
||||
}
|
||||
else
|
||||
{
|
||||
return Get(index).Value;
|
||||
}
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
if (key == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(key));
|
||||
}
|
||||
|
||||
var item = new KeyValuePair<string, string>(key, value);
|
||||
var index = Find(key);
|
||||
if (index < 0)
|
||||
{
|
||||
Insert(~index, item);
|
||||
}
|
||||
else
|
||||
{
|
||||
Set(index, item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public int Count => _items == null ? 0 : _items.Count;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsReadOnly
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ICollection<string> Keys
|
||||
{
|
||||
get
|
||||
{
|
||||
return new KeyCollection(this);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ICollection<string> Values
|
||||
{
|
||||
get
|
||||
{
|
||||
return new ValueCollection(this);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
IEnumerable<string> IReadOnlyDictionary<string, string>.Keys
|
||||
{
|
||||
get
|
||||
{
|
||||
return new KeyCollection(this);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
IEnumerable<string> IReadOnlyDictionary<string, string>.Values
|
||||
{
|
||||
get
|
||||
{
|
||||
return new ValueCollection(this);
|
||||
}
|
||||
}
|
||||
|
||||
private KeyValuePair<string, string> Get(int index)
|
||||
{
|
||||
if (index >= Count)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
|
||||
return _items[index];
|
||||
}
|
||||
|
||||
private void Set(int index, KeyValuePair<string, string> value)
|
||||
{
|
||||
if (index > Count)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
|
||||
if (_items == null)
|
||||
{
|
||||
_items = new List<KeyValuePair<string, string>>();
|
||||
}
|
||||
|
||||
_items[index] = value;
|
||||
}
|
||||
|
||||
private void Insert(int index, KeyValuePair<string, string> value)
|
||||
{
|
||||
if (index > Count)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
|
||||
if (_items == null)
|
||||
{
|
||||
_items = new List<KeyValuePair<string, string>>();
|
||||
}
|
||||
|
||||
_items.Insert(index, value);
|
||||
}
|
||||
|
||||
private void Remove(int index)
|
||||
{
|
||||
if (index >= Count)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
|
||||
|
||||
_items.RemoveAt(index);
|
||||
}
|
||||
|
||||
// This API is a lot like List<T>.BinarySearch https://msdn.microsoft.com/en-us/library/3f90y839(v=vs.110).aspx
|
||||
// If an item is not found, we return the compliment of where it belongs. Then we don't need to search again
|
||||
// to do something with it.
|
||||
private int Find(string key)
|
||||
{
|
||||
if (Count == 0)
|
||||
{
|
||||
return ~0;
|
||||
}
|
||||
|
||||
var start = 0;
|
||||
var end = Count - 1;
|
||||
|
||||
while (start <= end)
|
||||
{
|
||||
var pivot = start + (end - start >> 1);
|
||||
|
||||
var compare = StringComparer.OrdinalIgnoreCase.Compare(Get(pivot).Key, key);
|
||||
if (compare == 0)
|
||||
{
|
||||
return pivot;
|
||||
}
|
||||
if (compare < 0)
|
||||
{
|
||||
start = pivot + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
end = pivot - 1;
|
||||
}
|
||||
}
|
||||
|
||||
return ~start;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Clear()
|
||||
{
|
||||
if (_items != null)
|
||||
{
|
||||
_items.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Add(KeyValuePair<string, string> item)
|
||||
{
|
||||
if (item.Key == null)
|
||||
{
|
||||
throw new ArgumentException(
|
||||
Resources.FormatPropertyOfTypeCannotBeNull(
|
||||
nameof(KeyValuePair<string, string>.Key),
|
||||
nameof(KeyValuePair<string, string>)),
|
||||
nameof(item));
|
||||
}
|
||||
|
||||
var index = Find(item.Key);
|
||||
if (index < 0)
|
||||
{
|
||||
Insert(~index, item);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException(Resources.FormatDictionary_DuplicateKey(item.Key));
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Add(string key, string value)
|
||||
{
|
||||
if (key == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(key));
|
||||
}
|
||||
|
||||
Add(new KeyValuePair<string, string>(key, value));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Contains(KeyValuePair<string, string> item)
|
||||
{
|
||||
if (item.Key == null)
|
||||
{
|
||||
throw new ArgumentException(
|
||||
Resources.FormatPropertyOfTypeCannotBeNull(
|
||||
nameof(KeyValuePair<string, string>.Key),
|
||||
nameof(KeyValuePair<string, string>)),
|
||||
nameof(item));
|
||||
}
|
||||
|
||||
var index = Find(item.Key);
|
||||
if (index < 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return string.Equals(item.Value, Get(index).Value, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool ContainsKey(string key)
|
||||
{
|
||||
if (key == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(key));
|
||||
}
|
||||
|
||||
if (Count == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return Find(key) >= 0;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void CopyTo(KeyValuePair<string, string>[] array, int arrayIndex)
|
||||
{
|
||||
if (array == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(array));
|
||||
}
|
||||
|
||||
if (arrayIndex < 0 || arrayIndex >= array.Length)
|
||||
{
|
||||
throw new IndexOutOfRangeException();
|
||||
}
|
||||
|
||||
for (var i = 0; i < Count; i++)
|
||||
{
|
||||
array[arrayIndex + i] = Get(i);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Enumerator GetEnumerator()
|
||||
{
|
||||
return new Enumerator(this);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Remove(KeyValuePair<string, string> item)
|
||||
{
|
||||
if (item.Key == null)
|
||||
{
|
||||
throw new ArgumentException(
|
||||
Resources.FormatPropertyOfTypeCannotBeNull(
|
||||
nameof(KeyValuePair<string, string>.Key),
|
||||
nameof(KeyValuePair<string, string>)),
|
||||
nameof(item));
|
||||
}
|
||||
|
||||
var index = Find(item.Key);
|
||||
if (index < 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (string.Equals(item.Value, Get(index).Value, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
Remove(index);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Remove(string key)
|
||||
{
|
||||
if (key == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(key));
|
||||
}
|
||||
|
||||
var index = Find(key);
|
||||
if (index < 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
Remove(index);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool TryGetValue(string key, out string value)
|
||||
{
|
||||
if (key == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(key));
|
||||
}
|
||||
|
||||
var index = Find(key);
|
||||
if (index < 0)
|
||||
{
|
||||
value = null;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
value = Get(index).Value;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
IEnumerator<KeyValuePair<string, string>> IEnumerable<KeyValuePair<string, string>>.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// An enumerator for <see cref="AttributeDictionary"/>.
|
||||
/// </summary>
|
||||
public struct Enumerator : IEnumerator<KeyValuePair<string, string>>
|
||||
{
|
||||
private readonly AttributeDictionary _attributes;
|
||||
|
||||
private int _index;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="Enumerator"/>.
|
||||
/// </summary>
|
||||
/// <param name="attributes">The <see cref="AttributeDictionary"/>.</param>
|
||||
public Enumerator(AttributeDictionary attributes)
|
||||
{
|
||||
_attributes = attributes;
|
||||
|
||||
_index = -1;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public KeyValuePair<string, string> Current
|
||||
{
|
||||
get
|
||||
{
|
||||
return _attributes.Get(_index);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
object IEnumerator.Current
|
||||
{
|
||||
get
|
||||
{
|
||||
return Current;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Dispose()
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool MoveNext()
|
||||
{
|
||||
_index++;
|
||||
return _index < _attributes.Count;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Reset()
|
||||
{
|
||||
_index = -1;
|
||||
}
|
||||
}
|
||||
|
||||
private class KeyCollection : ICollection<string>
|
||||
{
|
||||
private readonly AttributeDictionary _attributes;
|
||||
|
||||
public KeyCollection(AttributeDictionary attributes)
|
||||
{
|
||||
_attributes = attributes;
|
||||
}
|
||||
|
||||
public int Count => _attributes.Count;
|
||||
|
||||
public bool IsReadOnly => true;
|
||||
|
||||
public void Add(string item)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public bool Contains(string item)
|
||||
{
|
||||
if (item == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(item));
|
||||
}
|
||||
|
||||
for (var i = 0; i < _attributes.Count; i++)
|
||||
{
|
||||
if (string.Equals(item, _attributes.Get(i).Key, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void CopyTo(string[] array, int arrayIndex)
|
||||
{
|
||||
if (array == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(array));
|
||||
}
|
||||
|
||||
if (arrayIndex < 0 || arrayIndex >= array.Length)
|
||||
{
|
||||
throw new IndexOutOfRangeException();
|
||||
}
|
||||
|
||||
for (var i = 0; i < _attributes.Count; i++)
|
||||
{
|
||||
array[arrayIndex + i] = _attributes.Get(i).Key;
|
||||
}
|
||||
}
|
||||
|
||||
public Enumerator GetEnumerator()
|
||||
{
|
||||
return new Enumerator(this._attributes);
|
||||
}
|
||||
|
||||
public bool Remove(string item)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
IEnumerator<string> IEnumerable<string>.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
public struct Enumerator : IEnumerator<string>
|
||||
{
|
||||
private readonly AttributeDictionary _attributes;
|
||||
|
||||
private int _index;
|
||||
|
||||
public Enumerator(AttributeDictionary attributes)
|
||||
{
|
||||
_attributes = attributes;
|
||||
|
||||
_index = -1;
|
||||
}
|
||||
|
||||
public string Current
|
||||
{
|
||||
get
|
||||
{
|
||||
return _attributes.Get(_index).Key;
|
||||
}
|
||||
}
|
||||
|
||||
object IEnumerator.Current
|
||||
{
|
||||
get
|
||||
{
|
||||
return Current;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
}
|
||||
|
||||
public bool MoveNext()
|
||||
{
|
||||
_index++;
|
||||
return _index < _attributes.Count;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
_index = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class ValueCollection : ICollection<string>
|
||||
{
|
||||
private readonly AttributeDictionary _attributes;
|
||||
|
||||
public ValueCollection(AttributeDictionary attributes)
|
||||
{
|
||||
_attributes = attributes;
|
||||
}
|
||||
public int Count => _attributes.Count;
|
||||
|
||||
public bool IsReadOnly => true;
|
||||
|
||||
public void Add(string item)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public bool Contains(string item)
|
||||
{
|
||||
for (var i = 0; i < _attributes.Count; i++)
|
||||
{
|
||||
if (string.Equals(item, _attributes.Get(i).Value, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void CopyTo(string[] array, int arrayIndex)
|
||||
{
|
||||
if (array == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(array));
|
||||
}
|
||||
|
||||
if (arrayIndex < 0 || arrayIndex >= array.Length)
|
||||
{
|
||||
throw new IndexOutOfRangeException();
|
||||
}
|
||||
|
||||
for (var i = 0; i < _attributes.Count; i++)
|
||||
{
|
||||
array[arrayIndex + i] = _attributes.Get(i).Value;
|
||||
}
|
||||
}
|
||||
|
||||
public Enumerator GetEnumerator()
|
||||
{
|
||||
return new Enumerator(this._attributes);
|
||||
}
|
||||
|
||||
public bool Remove(string item)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
IEnumerator<string> IEnumerable<string>.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
public struct Enumerator : IEnumerator<string>
|
||||
{
|
||||
private readonly AttributeDictionary _attributes;
|
||||
|
||||
private int _index;
|
||||
|
||||
public Enumerator(AttributeDictionary attributes)
|
||||
{
|
||||
_attributes = attributes;
|
||||
|
||||
_index = -1;
|
||||
}
|
||||
|
||||
public string Current
|
||||
{
|
||||
get
|
||||
{
|
||||
return _attributes.Get(_index).Key;
|
||||
}
|
||||
}
|
||||
|
||||
object IEnumerator.Current
|
||||
{
|
||||
get
|
||||
{
|
||||
return Current;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
}
|
||||
|
||||
public bool MoveNext()
|
||||
{
|
||||
_index++;
|
||||
return _index < _attributes.Count;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
_index = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -27,7 +27,7 @@ namespace Microsoft.AspNet.Mvc.Core.Rendering
|
|||
|
||||
[Theory]
|
||||
[InlineData(false, "Hello", "World")]
|
||||
[InlineData(true, "Hello", "something else")]
|
||||
[InlineData(true, "hello", "something else")]
|
||||
public void MergeAttribute_IgnoresCase(bool replaceExisting, string expectedKey, string expectedValue)
|
||||
{
|
||||
// Arrange
|
||||
|
|
@ -54,7 +54,7 @@ namespace Microsoft.AspNet.Mvc.Core.Rendering
|
|||
|
||||
// Assert
|
||||
var attribute = Assert.Single(tagBuilder.Attributes);
|
||||
Assert.Equal(new KeyValuePair<string, string>("ClaSs", "success btn"), attribute);
|
||||
Assert.Equal(new KeyValuePair<string, string>("class", "success btn"), attribute);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
|
|||
|
|
@ -0,0 +1,464 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.ViewFeatures
|
||||
{
|
||||
public class AttributeDictionaryTest
|
||||
{
|
||||
[Fact]
|
||||
public void AttributeDictionary_AddItems()
|
||||
{
|
||||
// Arrange
|
||||
var attributes = new AttributeDictionary();
|
||||
|
||||
// Act
|
||||
attributes.Add("zero", "0");
|
||||
attributes.Add("one", "1");
|
||||
attributes.Add("two", "2");
|
||||
|
||||
// Assert
|
||||
Assert.Equal(3, attributes.Count);
|
||||
Assert.Collection(
|
||||
attributes,
|
||||
kvp => Assert.Equal(new KeyValuePair<string, string>("one", "1"), kvp),
|
||||
kvp => Assert.Equal(new KeyValuePair<string, string>("two", "2"), kvp),
|
||||
kvp => Assert.Equal(new KeyValuePair<string, string>("zero", "0"), kvp));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AttributeDictionary_AddItems_AsKeyValuePairs()
|
||||
{
|
||||
// Arrange
|
||||
var attributes = new AttributeDictionary();
|
||||
|
||||
// Act
|
||||
attributes.Add(new KeyValuePair<string, string>("zero", "0"));
|
||||
attributes.Add(new KeyValuePair<string, string>("one", "1"));
|
||||
attributes.Add(new KeyValuePair<string, string>("two", "2"));
|
||||
|
||||
// Assert
|
||||
Assert.Equal(3, attributes.Count);
|
||||
Assert.Collection(
|
||||
attributes,
|
||||
kvp => Assert.Equal(new KeyValuePair<string, string>("one", "1"), kvp),
|
||||
kvp => Assert.Equal(new KeyValuePair<string, string>("two", "2"), kvp),
|
||||
kvp => Assert.Equal(new KeyValuePair<string, string>("zero", "0"), kvp));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AttributeDictionary_Add_DuplicateKey()
|
||||
{
|
||||
// Arrange
|
||||
var attributes = new AttributeDictionary();
|
||||
|
||||
attributes.Add("zero", "0");
|
||||
attributes.Add("one", "1");
|
||||
attributes.Add("two", "2");
|
||||
|
||||
// Act & Assert
|
||||
Assert.Throws<InvalidOperationException>(() => attributes.Add("one", "15"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AttributeDictionary_Clear()
|
||||
{
|
||||
// Arrange
|
||||
var attributes = new AttributeDictionary();
|
||||
|
||||
attributes.Add(new KeyValuePair<string, string>("zero", "0"));
|
||||
attributes.Add(new KeyValuePair<string, string>("one", "1"));
|
||||
attributes.Add(new KeyValuePair<string, string>("two", "2"));
|
||||
|
||||
// Act
|
||||
attributes.Clear();
|
||||
|
||||
// Assert
|
||||
Assert.Equal(0, attributes.Count);
|
||||
Assert.Empty(attributes);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AttributeDictionary_Contains_Success()
|
||||
{
|
||||
// Arrange
|
||||
var attributes = new AttributeDictionary();
|
||||
|
||||
attributes.Add(new KeyValuePair<string, string>("zero", "0"));
|
||||
attributes.Add(new KeyValuePair<string, string>("one", "1"));
|
||||
attributes.Add(new KeyValuePair<string, string>("two", "2"));
|
||||
|
||||
// Act
|
||||
var result = attributes.Contains(new KeyValuePair<string, string>("zero", "0"));
|
||||
|
||||
// Assert
|
||||
Assert.True(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AttributeDictionary_Contains_Failure()
|
||||
{
|
||||
// Arrange
|
||||
var attributes = new AttributeDictionary();
|
||||
|
||||
attributes.Add(new KeyValuePair<string, string>("zero", "0"));
|
||||
attributes.Add(new KeyValuePair<string, string>("one", "1"));
|
||||
attributes.Add(new KeyValuePair<string, string>("two", "2"));
|
||||
|
||||
// Act
|
||||
var result = attributes.Contains(new KeyValuePair<string, string>("zero", "nada"));
|
||||
|
||||
// Assert
|
||||
Assert.False(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AttributeDictionary_ContainsKey_Success()
|
||||
{
|
||||
// Arrange
|
||||
var attributes = new AttributeDictionary();
|
||||
|
||||
attributes.Add(new KeyValuePair<string, string>("zero", "0"));
|
||||
attributes.Add(new KeyValuePair<string, string>("one", "1"));
|
||||
attributes.Add(new KeyValuePair<string, string>("two", "2"));
|
||||
|
||||
// Act
|
||||
var result = attributes.ContainsKey("one");
|
||||
|
||||
// Assert
|
||||
Assert.True(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AttributeDictionary_ContainsKey_Failure()
|
||||
{
|
||||
// Arrange
|
||||
var attributes = new AttributeDictionary();
|
||||
|
||||
attributes.Add(new KeyValuePair<string, string>("zero", "0"));
|
||||
attributes.Add(new KeyValuePair<string, string>("one", "1"));
|
||||
attributes.Add(new KeyValuePair<string, string>("two", "2"));
|
||||
|
||||
// Act
|
||||
var result = attributes.ContainsKey("one!");
|
||||
|
||||
// Assert
|
||||
Assert.False(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AttributeDictionary_CopyTo()
|
||||
{
|
||||
// Arrange
|
||||
var attributes = new AttributeDictionary();
|
||||
|
||||
attributes.Add(new KeyValuePair<string, string>("zero", "0"));
|
||||
attributes.Add(new KeyValuePair<string, string>("one", "1"));
|
||||
attributes.Add(new KeyValuePair<string, string>("two", "2"));
|
||||
|
||||
var array = new KeyValuePair<string, string>[attributes.Count + 1];
|
||||
|
||||
// Act
|
||||
attributes.CopyTo(array, 1);
|
||||
|
||||
// Assert
|
||||
Assert.Collection(
|
||||
array,
|
||||
kvp => Assert.Equal(default(KeyValuePair<string, string>), kvp),
|
||||
kvp => Assert.Equal(new KeyValuePair<string, string>("one", "1"), kvp),
|
||||
kvp => Assert.Equal(new KeyValuePair<string, string>("two", "2"), kvp),
|
||||
kvp => Assert.Equal(new KeyValuePair<string, string>("zero", "0"), kvp));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AttributeDictionary_IsReadOnly()
|
||||
{
|
||||
// Arrange
|
||||
var attributes = new AttributeDictionary();
|
||||
|
||||
// Act
|
||||
var result = attributes.IsReadOnly;
|
||||
|
||||
// Assert
|
||||
Assert.False(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AttributeDictionary_Keys()
|
||||
{
|
||||
// Arrange
|
||||
var attributes = new AttributeDictionary();
|
||||
|
||||
attributes.Add(new KeyValuePair<string, string>("zero", "0"));
|
||||
attributes.Add(new KeyValuePair<string, string>("one", "1"));
|
||||
attributes.Add(new KeyValuePair<string, string>("two", "2"));
|
||||
|
||||
// Act
|
||||
var keys = attributes.Keys;
|
||||
|
||||
// Assert
|
||||
Assert.Equal(3, keys.Count);
|
||||
Assert.Collection(
|
||||
keys,
|
||||
key => Assert.Equal("one", key),
|
||||
key => Assert.Equal("two", key),
|
||||
key => Assert.Equal("zero", key));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AttributeDictionary_Remove_Success()
|
||||
{
|
||||
// Arrange
|
||||
var attributes = new AttributeDictionary();
|
||||
|
||||
attributes.Add(new KeyValuePair<string, string>("zero", "0"));
|
||||
attributes.Add(new KeyValuePair<string, string>("one", "1"));
|
||||
attributes.Add(new KeyValuePair<string, string>("two", "2"));
|
||||
|
||||
// Act
|
||||
var result = attributes.Remove("one");
|
||||
|
||||
// Assert
|
||||
Assert.True(result);
|
||||
Assert.Equal(2, attributes.Count);
|
||||
Assert.Collection(
|
||||
attributes,
|
||||
kvp => Assert.Equal(new KeyValuePair<string, string>("two", "2"), kvp),
|
||||
kvp => Assert.Equal(new KeyValuePair<string, string>("zero", "0"), kvp));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AttributeDictionary_Remove_Failure()
|
||||
{
|
||||
// Arrange
|
||||
var attributes = new AttributeDictionary();
|
||||
|
||||
attributes.Add(new KeyValuePair<string, string>("zero", "0"));
|
||||
attributes.Add(new KeyValuePair<string, string>("one", "1"));
|
||||
attributes.Add(new KeyValuePair<string, string>("two", "2"));
|
||||
|
||||
// Act
|
||||
var result = attributes.Remove("nada");
|
||||
|
||||
// Assert
|
||||
Assert.False(result);
|
||||
Assert.Equal(3, attributes.Count);
|
||||
Assert.Collection(
|
||||
attributes,
|
||||
kvp => Assert.Equal(new KeyValuePair<string, string>("one", "1"), kvp),
|
||||
kvp => Assert.Equal(new KeyValuePair<string, string>("two", "2"), kvp),
|
||||
kvp => Assert.Equal(new KeyValuePair<string, string>("zero", "0"), kvp));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AttributeDictionary_Remove_KeyValuePair_Success()
|
||||
{
|
||||
// Arrange
|
||||
var attributes = new AttributeDictionary();
|
||||
|
||||
attributes.Add(new KeyValuePair<string, string>("zero", "0"));
|
||||
attributes.Add(new KeyValuePair<string, string>("one", "1"));
|
||||
attributes.Add(new KeyValuePair<string, string>("two", "2"));
|
||||
|
||||
// Act
|
||||
var result = attributes.Remove(new KeyValuePair<string, string>("one", "1"));
|
||||
|
||||
// Assert
|
||||
Assert.True(result);
|
||||
Assert.Equal(2, attributes.Count);
|
||||
Assert.Collection(
|
||||
attributes,
|
||||
kvp => Assert.Equal(new KeyValuePair<string, string>("two", "2"), kvp),
|
||||
kvp => Assert.Equal(new KeyValuePair<string, string>("zero", "0"), kvp));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AttributeDictionary_Remove_KeyValuePair_Failure()
|
||||
{
|
||||
// Arrange
|
||||
var attributes = new AttributeDictionary();
|
||||
|
||||
attributes.Add(new KeyValuePair<string, string>("zero", "0"));
|
||||
attributes.Add(new KeyValuePair<string, string>("one", "1"));
|
||||
attributes.Add(new KeyValuePair<string, string>("two", "2"));
|
||||
|
||||
// Act
|
||||
var result = attributes.Remove(new KeyValuePair<string, string>("one", "0"));
|
||||
|
||||
// Assert
|
||||
Assert.False(result);
|
||||
Assert.Equal(3, attributes.Count);
|
||||
Assert.Collection(
|
||||
attributes,
|
||||
kvp => Assert.Equal(new KeyValuePair<string, string>("one", "1"), kvp),
|
||||
kvp => Assert.Equal(new KeyValuePair<string, string>("two", "2"), kvp),
|
||||
kvp => Assert.Equal(new KeyValuePair<string, string>("zero", "0"), kvp));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AttributeDictionary_TryGetValue_Success()
|
||||
{
|
||||
// Arrange
|
||||
var attributes = new AttributeDictionary();
|
||||
|
||||
attributes.Add(new KeyValuePair<string, string>("zero", "0"));
|
||||
attributes.Add(new KeyValuePair<string, string>("one", "1"));
|
||||
attributes.Add(new KeyValuePair<string, string>("two", "2"));
|
||||
|
||||
string value;
|
||||
|
||||
// Act
|
||||
var result = attributes.TryGetValue("two", out value);
|
||||
|
||||
// Assert
|
||||
Assert.True(result);
|
||||
Assert.Equal("2", value);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AttributeDictionary_TryGetValue_Failure()
|
||||
{
|
||||
// Arrange
|
||||
var attributes = new AttributeDictionary();
|
||||
|
||||
attributes.Add(new KeyValuePair<string, string>("zero", "0"));
|
||||
attributes.Add(new KeyValuePair<string, string>("one", "1"));
|
||||
attributes.Add(new KeyValuePair<string, string>("two", "2"));
|
||||
|
||||
string value;
|
||||
|
||||
// Act
|
||||
var result = attributes.TryGetValue("nada", out value);
|
||||
|
||||
|
||||
// Assert
|
||||
Assert.False(result);
|
||||
Assert.Null(value);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AttributeDictionary_Values()
|
||||
{
|
||||
// Arrange
|
||||
var attributes = new AttributeDictionary();
|
||||
|
||||
attributes.Add(new KeyValuePair<string, string>("zero", "0"));
|
||||
attributes.Add(new KeyValuePair<string, string>("one", "1"));
|
||||
attributes.Add(new KeyValuePair<string, string>("two", "2"));
|
||||
|
||||
// Act
|
||||
var values = attributes.Values;
|
||||
|
||||
// Assert
|
||||
Assert.Equal(3, values.Count);
|
||||
Assert.Collection(
|
||||
values,
|
||||
key => Assert.Equal("1", key),
|
||||
key => Assert.Equal("2", key),
|
||||
key => Assert.Equal("0", key));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AttributeDictionary_Indexer_Success()
|
||||
{
|
||||
// Arrange
|
||||
var attributes = new AttributeDictionary();
|
||||
|
||||
attributes.Add(new KeyValuePair<string, string>("zero", "0"));
|
||||
attributes.Add(new KeyValuePair<string, string>("one", "1"));
|
||||
attributes.Add(new KeyValuePair<string, string>("two", "2"));
|
||||
|
||||
// Act
|
||||
var value = attributes["two"];
|
||||
|
||||
// Assert
|
||||
Assert.Equal("2", value);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AttributeDictionary_Indexer_Fails()
|
||||
{
|
||||
// Arrange
|
||||
var attributes = new AttributeDictionary();
|
||||
|
||||
attributes.Add(new KeyValuePair<string, string>("zero", "0"));
|
||||
attributes.Add(new KeyValuePair<string, string>("one", "1"));
|
||||
attributes.Add(new KeyValuePair<string, string>("two", "2"));
|
||||
|
||||
// Act & Assert
|
||||
Assert.Throws<KeyNotFoundException>(() => attributes["nada"]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AttributeDictionary_Indexer_SetValue()
|
||||
{
|
||||
// Arrange
|
||||
var attributes = new AttributeDictionary();
|
||||
|
||||
attributes.Add(new KeyValuePair<string, string>("zero", "0"));
|
||||
attributes.Add(new KeyValuePair<string, string>("one", "1"));
|
||||
attributes.Add(new KeyValuePair<string, string>("two", "2"));
|
||||
|
||||
// Act
|
||||
attributes["one"] = "1!";
|
||||
|
||||
// Assert
|
||||
Assert.Equal(3, attributes.Count);
|
||||
Assert.Collection(
|
||||
attributes,
|
||||
kvp => Assert.Equal(new KeyValuePair<string, string>("one", "1!"), kvp),
|
||||
kvp => Assert.Equal(new KeyValuePair<string, string>("two", "2"), kvp),
|
||||
kvp => Assert.Equal(new KeyValuePair<string, string>("zero", "0"), kvp));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AttributeDictionary_Indexer_Insert()
|
||||
{
|
||||
// Arrange
|
||||
var attributes = new AttributeDictionary();
|
||||
|
||||
attributes.Add(new KeyValuePair<string, string>("zero", "0"));
|
||||
attributes.Add(new KeyValuePair<string, string>("one", "1"));
|
||||
attributes.Add(new KeyValuePair<string, string>("two", "2"));
|
||||
|
||||
// Act
|
||||
attributes["exciting!"] = "1!";
|
||||
|
||||
// Assert
|
||||
Assert.Equal(4, attributes.Count);
|
||||
Assert.Collection(
|
||||
attributes,
|
||||
kvp => Assert.Equal(new KeyValuePair<string, string>("exciting!", "1!"), kvp),
|
||||
kvp => Assert.Equal(new KeyValuePair<string, string>("one", "1"), kvp),
|
||||
kvp => Assert.Equal(new KeyValuePair<string, string>("two", "2"), kvp),
|
||||
kvp => Assert.Equal(new KeyValuePair<string, string>("zero", "0"), kvp));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AttributeDictionary_CaseInsensitive()
|
||||
{
|
||||
// Arrange
|
||||
var attributes = new AttributeDictionary();
|
||||
|
||||
attributes.Add(new KeyValuePair<string, string>("zero", "0"));
|
||||
attributes.Add(new KeyValuePair<string, string>("one", "1"));
|
||||
attributes.Add(new KeyValuePair<string, string>("two", "2"));
|
||||
|
||||
// Act
|
||||
attributes["oNe"] = "1!";
|
||||
|
||||
// Assert
|
||||
Assert.Equal(3, attributes.Count);
|
||||
Assert.Collection(
|
||||
attributes,
|
||||
kvp => Assert.Equal(new KeyValuePair<string, string>("oNe", "1!"), kvp),
|
||||
kvp => Assert.Equal(new KeyValuePair<string, string>("two", "2"), kvp),
|
||||
kvp => Assert.Equal(new KeyValuePair<string, string>("zero", "0"), kvp));
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue