Skip to content

Commit

Permalink
Additional code coverage in System.Text.Json - no public constructors (
Browse files Browse the repository at this point in the history
…dotnet#33137)

* added tests for concurrent collection private constructors

* added tests for non generic collection private constructors

* added tests for generic collection private constructors

* added additional test for read only dictionary private constructor

* fixed location of compile directive

* added assertion for exception messages

* added additional assertions for exception messages

* using [Theory] tests to reduce LoC

* using [Theory] for additional tests

* reordered files in test project

* added internal ctor tests
  • Loading branch information
alanisaac committed Mar 16, 2020
1 parent 570fa1d commit 4ceccbb
Show file tree
Hide file tree
Showing 7 changed files with 289 additions and 22 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System.Collections.Concurrent;

namespace System.Text.Json.Serialization.Tests
{
public class GenericConcurrentQueuePrivateConstructor<T> : ConcurrentQueue<T>
{
private GenericConcurrentQueuePrivateConstructor() { }
}

public class GenericConcurrentQueueInternalConstructor<T> : ConcurrentQueue<T>
{
internal GenericConcurrentQueueInternalConstructor() { }
}

public class GenericConcurrentStackPrivateConstructor<T> : ConcurrentStack<T>
{
private GenericConcurrentStackPrivateConstructor() { }
}

public class GenericConcurrentStackInternalConstructor<T> : ConcurrentStack<T>
{
internal GenericConcurrentStackInternalConstructor() { }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,16 @@ IEnumerator IEnumerable.GetEnumerator()
}
}

public class GenericIEnumerableWrapperPrivateConstructor<T> : GenericIEnumerableWrapper<T>
{
private GenericIEnumerableWrapperPrivateConstructor() { }
}

public class GenericIEnumerableWrapperInternalConstructor<T> : GenericIEnumerableWrapper<T>
{
internal GenericIEnumerableWrapperInternalConstructor() { }
}

public class StringICollectionWrapper : ICollection<string>
{
private readonly List<string> _list = new List<string>();
Expand Down Expand Up @@ -372,6 +382,16 @@ IEnumerator IEnumerable.GetEnumerator()
}
}

public class GenericIListWrapperPrivateConstructor<T> : GenericIListWrapper<T>
{
private GenericIListWrapperPrivateConstructor() { }
}

public class GenericIListWrapperInternalConstructor<T> : GenericIListWrapper<T>
{
internal GenericIListWrapperInternalConstructor() { }
}

public class GenericICollectionWrapper<T> : ICollection<T>
{
private readonly List<T> _list = new List<T>();
Expand Down Expand Up @@ -416,6 +436,16 @@ IEnumerator IEnumerable.GetEnumerator()
}
}

public class GenericICollectionWrapperPrivateConstructor<T> : GenericICollectionWrapper<T>
{
private GenericICollectionWrapperPrivateConstructor() { }
}

public class GenericICollectionWrapperInternalConstructor<T> : GenericICollectionWrapper<T>
{
internal GenericICollectionWrapperInternalConstructor() { }
}

public class StringIReadOnlyCollectionWrapper : IReadOnlyCollection<string>
{
private readonly List<string> _list = new List<string>();
Expand Down Expand Up @@ -714,6 +744,16 @@ IEnumerator IEnumerable.GetEnumerator()
}
}

public class GenericISetWrapperPrivateConstructor<T> : GenericISetWrapper<T>
{
private GenericISetWrapperPrivateConstructor() { }
}

public class GenericISetWrapperInternalConstructor<T> : GenericISetWrapper<T>
{
internal GenericISetWrapperInternalConstructor() { }
}

public class StringToStringIDictionaryWrapper : IDictionary<string, string>
{
private Dictionary<string, string> _dictionary = new Dictionary<string, string>();
Expand Down Expand Up @@ -866,6 +906,11 @@ public class GenericIDictionaryWrapperPrivateConstructor<TKey, TValue> : Generic
private GenericIDictionaryWrapperPrivateConstructor() { }
}

public class GenericIDictionaryWrapperInternalConstructor<TKey, TValue> : GenericIDictionaryWrapper<TKey, TValue>
{
internal GenericIDictionaryWrapperInternalConstructor() { }
}

public class GenericIDictonaryWrapperThreeGenericParameters<TKey, TValue, TUnused> : GenericIDictionaryWrapper<TKey, TValue> { }

public class ReadOnlyStringToStringIDictionaryWrapper : StringToStringIDictionaryWrapper
Expand Down Expand Up @@ -1060,6 +1105,16 @@ IEnumerator IEnumerable.GetEnumerator()
}
}

public class StringToStringIReadOnlyDictionaryWrapperPrivateConstructor : StringToStringIReadOnlyDictionaryWrapper
{
private StringToStringIReadOnlyDictionaryWrapperPrivateConstructor() { }
}

public class StringToStringIReadOnlyDictionaryWrapperInternalConstructor : StringToStringIReadOnlyDictionaryWrapper
{
internal StringToStringIReadOnlyDictionaryWrapperInternalConstructor() { }
}

public class StringListWrapper : List<string> { }

class MyMyList<T> : GenericListWrapper<T>
Expand All @@ -1072,6 +1127,16 @@ class MyListString : GenericListWrapper<string>

public class GenericListWrapper<T> : List<T> { }

public class GenericListWrapperPrivateConstructor<T> : GenericListWrapper<T>
{
private GenericListWrapperPrivateConstructor() { }
}

public class GenericListWrapperInternalConstructor<T> : GenericListWrapper<T>
{
internal GenericListWrapperInternalConstructor() { }
}

public class StringStackWrapper : Stack<string>
{
public StringStackWrapper() { }
Expand Down Expand Up @@ -1100,6 +1165,16 @@ public GenericStackWrapper(IList<T> items)
}
}

public class GenericStackWrapperPrivateConstructor<T> : GenericStackWrapper<T>
{
private GenericStackWrapperPrivateConstructor() { }
}

public class GenericStackWrapperInternalConstructor<T> : GenericStackWrapper<T>
{
internal GenericStackWrapperInternalConstructor() { }
}

public class StringQueueWrapper : Queue<string>
{
public StringQueueWrapper() { }
Expand Down Expand Up @@ -1128,6 +1203,16 @@ public GenericQueueWrapper(IList<T> items)
}
}

public class GenericQueueWrapperPrivateConstructor<T> : GenericQueueWrapper<T>
{
private GenericQueueWrapperPrivateConstructor() { }
}

public class GenericQueueWrapperInternalConstructor<T> : GenericQueueWrapper<T>
{
internal GenericQueueWrapperInternalConstructor() { }
}

public class StringHashSetWrapper : HashSet<string>
{
public StringHashSetWrapper() { }
Expand Down Expand Up @@ -1240,6 +1325,16 @@ public StringToGenericDictionaryWrapper(IList<KeyValuePair<string, T>> items)
}
}

public class StringToGenericDictionaryWrapperPrivateConstructor<T> : StringToGenericDictionaryWrapper<T>
{
private StringToGenericDictionaryWrapperPrivateConstructor() { }
}

public class StringToGenericDictionaryWrapperInternalConstructor<T> : StringToGenericDictionaryWrapper<T>
{
internal StringToGenericDictionaryWrapperInternalConstructor() { }
}

public class StringToStringSortedDictionaryWrapper : SortedDictionary<string, string>
{
public StringToStringSortedDictionaryWrapper() { }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,16 @@ public IEnumerator GetEnumerator()
}
}

public class WrapperForIEnumerablePrivateConstructor : WrapperForIEnumerable
{
private WrapperForIEnumerablePrivateConstructor() { }
}

public class WrapperForIEnumerableInternalConstructor : WrapperForIEnumerable
{
internal WrapperForIEnumerableInternalConstructor() { }
}

public class WrapperForICollection : ICollection
{
private readonly List<object> _list = new List<object>();
Expand Down Expand Up @@ -180,6 +190,16 @@ public IEnumerator GetEnumerator()
}
}

public class WrapperForICollectionPrivateConstructor : WrapperForICollection
{
private WrapperForICollectionPrivateConstructor() { }
}

public class WrapperForICollectionInternalConstructor : WrapperForICollection
{
internal WrapperForICollectionInternalConstructor() { }
}

public class ReadOnlyWrapperForIList : WrapperForIList
{
public override bool IsReadOnly => true;
Expand Down Expand Up @@ -247,6 +267,15 @@ public void RemoveAt(int index)
}
}

public class WrapperForIListPrivateConstructor : WrapperForIList
{
private WrapperForIListPrivateConstructor() { }
}
public class WrapperForIListInternalConstructor : WrapperForIList
{
internal WrapperForIListInternalConstructor() { }
}

public class WrapperForIDictionary : IDictionary
{
private readonly Dictionary<string, object> _dictionary = new Dictionary<string, object>();
Expand Down Expand Up @@ -303,6 +332,16 @@ IEnumerator IEnumerable.GetEnumerator()
}
}

public class WrapperForIDictionaryPrivateConstructor : WrapperForIDictionary
{
private WrapperForIDictionaryPrivateConstructor() { }
}

public class WrapperForIDictionaryInternalConstructor : WrapperForIDictionary
{
internal WrapperForIDictionaryInternalConstructor() { }
}

public class StackWrapper : Stack
{
public StackWrapper() { }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,24 @@ public static void Read_ConcurrentCollection()
Assert.Equal("1", val);
}

[Fact]
public static void Read_ConcurrentCollection_Throws()
[Theory]
[InlineData(typeof(BlockingCollection<string>), @"[""1""]")] // Not supported. Not IList, and we don't detect the add method for this collection.
[InlineData(typeof(ConcurrentBag<string>), @"[""1""]")] // Not supported. Not IList, and we don't detect the add method for this collection.
public static void Read_ConcurrentCollection_Throws(Type type, string json)
{
// Not supported. Not IList, and we don't detect the add method for this collection.
Assert.Throws<NotSupportedException>(() => JsonSerializer.Deserialize<BlockingCollection<string>>(@"[""1""]"));
NotSupportedException ex = Assert.Throws<NotSupportedException>(() => JsonSerializer.Deserialize(json, type));
Assert.Contains(type.ToString(), ex.Message);
}

// Not supported. Not IList, and we don't detect the add method for this collection.
Assert.Throws<NotSupportedException>(() => JsonSerializer.Deserialize<ConcurrentBag<string>>(@"[""1""]"));
[Theory]
[InlineData(typeof(GenericConcurrentQueuePrivateConstructor<string>), @"[""1""]")]
[InlineData(typeof(GenericConcurrentQueueInternalConstructor<string>), @"[""1""]")]
[InlineData(typeof(GenericConcurrentStackPrivateConstructor<string>), @"[""1""]")]
[InlineData(typeof(GenericConcurrentStackInternalConstructor<string>), @"[""1""]")]
public static void Read_ConcurrentCollection_NoPublicConstructor_Throws(Type type, string json)
{
NotSupportedException ex = Assert.Throws<NotSupportedException>(() => JsonSerializer.Deserialize(json, type));
Assert.Contains(type.ToString(), ex.Message);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1132,22 +1132,54 @@ public static void ReadSimpleTestClass_GenericCollectionWrappers()
obj.Verify();
}

[Fact]
public static void ReadSimpleTestClass_GenericWrappers_NoAddMethod_Throws()
[Theory]
[MemberData(nameof(ReadSimpleTestClass_GenericWrappers_NoAddMethod))]
public static void ReadSimpleTestClass_GenericWrappers_NoAddMethod_Throws(Type type, string json, Type exceptionMessageType)
{
Assert.Throws<NotSupportedException>(() => JsonSerializer.Deserialize<SimpleTestClassWithStringIEnumerableWrapper>(SimpleTestClassWithStringIEnumerableWrapper.s_json));
Assert.Throws<NotSupportedException>(() => JsonSerializer.Deserialize<SimpleTestClassWithStringIReadOnlyCollectionWrapper>(SimpleTestClassWithStringIReadOnlyCollectionWrapper.s_json));
Assert.Throws<NotSupportedException>(() => JsonSerializer.Deserialize<SimpleTestClassWithStringIReadOnlyListWrapper>(SimpleTestClassWithStringIReadOnlyListWrapper.s_json));
Assert.Throws<NotSupportedException>(() => JsonSerializer.Deserialize<SimpleTestClassWithStringToStringIReadOnlyDictionaryWrapper>(SimpleTestClassWithStringToStringIReadOnlyDictionaryWrapper.s_json));
NotSupportedException ex = Assert.Throws<NotSupportedException>(() => JsonSerializer.Deserialize(json, type));
Assert.Contains(exceptionMessageType.ToString(), ex.Message);
}

[Fact]
public static void ReadReadOnlyCollections_Throws()
public static IEnumerable<object[]> ReadSimpleTestClass_GenericWrappers_NoAddMethod
{
Assert.Throws<NotSupportedException>(() => JsonSerializer.Deserialize<ReadOnlyWrapperForIList>(@"[""1"", ""2""]"));
Assert.Throws<NotSupportedException>(() => JsonSerializer.Deserialize<ReadOnlyStringIListWrapper>(@"[""1"", ""2""]"));
Assert.Throws<NotSupportedException>(() => JsonSerializer.Deserialize<ReadOnlyStringICollectionWrapper>(@"[""1"", ""2""]"));
Assert.Throws<NotSupportedException>(() => JsonSerializer.Deserialize<ReadOnlyStringToStringIDictionaryWrapper>(@"{""Key"":""key"",""Value"":""value""}"));
get
{
yield return new object[]
{
typeof(SimpleTestClassWithStringIEnumerableWrapper),
SimpleTestClassWithStringIEnumerableWrapper.s_json,
typeof(StringIEnumerableWrapper)
};
yield return new object[]
{
typeof(SimpleTestClassWithStringIReadOnlyCollectionWrapper),
SimpleTestClassWithStringIReadOnlyCollectionWrapper.s_json,
typeof(StringIReadOnlyCollectionWrapper)
};
yield return new object[]
{
typeof(SimpleTestClassWithStringIReadOnlyListWrapper),
SimpleTestClassWithStringIReadOnlyListWrapper.s_json,
typeof(StringIReadOnlyListWrapper)
};
yield return new object[]
{
typeof(SimpleTestClassWithStringToStringIReadOnlyDictionaryWrapper),
SimpleTestClassWithStringToStringIReadOnlyDictionaryWrapper.s_json,
typeof(StringToStringIReadOnlyDictionaryWrapper)
};
}
}

[Theory]
[InlineData(typeof(ReadOnlyWrapperForIList), @"[""1"", ""2""]")]
[InlineData(typeof(ReadOnlyStringIListWrapper), @"[""1"", ""2""]")]
[InlineData(typeof(ReadOnlyStringICollectionWrapper), @"[""1"", ""2""]")]
[InlineData(typeof(ReadOnlyStringToStringIDictionaryWrapper), @"{""Key"":""key"",""Value"":""value""}")]
public static void ReadReadOnlyCollections_Throws(Type type, string json)
{
NotSupportedException ex = Assert.Throws<NotSupportedException>(() => JsonSerializer.Deserialize(json, type));
Assert.Contains(type.ToString(), ex.Message);
}

[Fact]
Expand All @@ -1161,5 +1193,32 @@ public static void Read_HigherOrderCollectionInheritance_Works()
Assert.Equal("test", JsonSerializer.Deserialize<MyMyList<string>>(json).First());
Assert.Equal("test", JsonSerializer.Deserialize<MyListString>(json).First());
}

[Theory]
[InlineData(typeof(GenericIEnumerableWrapperPrivateConstructor<string>), @"[""1""]")]
[InlineData(typeof(GenericIEnumerableWrapperInternalConstructor<string>), @"[""1""]")]
[InlineData(typeof(GenericICollectionWrapperPrivateConstructor<string>), @"[""1""]")]
[InlineData(typeof(GenericICollectionWrapperInternalConstructor<string>), @"[""1""]")]
[InlineData(typeof(GenericIListWrapperPrivateConstructor<string>), @"[""1""]")]
[InlineData(typeof(GenericIListWrapperInternalConstructor<string>), @"[""1""]")]
[InlineData(typeof(GenericISetWrapperPrivateConstructor<string>), @"[""1""]")]
[InlineData(typeof(GenericISetWrapperInternalConstructor<string>), @"[""1""]")]
[InlineData(typeof(GenericIDictionaryWrapperPrivateConstructor<string, string>), @"{""Key"":""Value""}")]
[InlineData(typeof(GenericIDictionaryWrapperInternalConstructor<string, string>), @"{""Key"":""Value""}")]
[InlineData(typeof(StringToStringIReadOnlyDictionaryWrapperPrivateConstructor), @"{""Key"":""Value""}")]
[InlineData(typeof(StringToStringIReadOnlyDictionaryWrapperInternalConstructor), @"{""Key"":""Value""}")]
[InlineData(typeof(GenericListWrapperPrivateConstructor<string>), @"[""1""]")]
[InlineData(typeof(GenericListWrapperInternalConstructor<string>), @"[""1""]")]
[InlineData(typeof(GenericQueueWrapperPrivateConstructor<string>), @"[""1""]")]
[InlineData(typeof(GenericQueueWrapperInternalConstructor<string>), @"[""1""]")]
[InlineData(typeof(GenericStackWrapperPrivateConstructor<string>), @"[""1""]")]
[InlineData(typeof(GenericStackWrapperInternalConstructor<string>), @"[""1""]")]
[InlineData(typeof(StringToGenericDictionaryWrapperPrivateConstructor<string>), @"{""Key"":""Value""}")]
[InlineData(typeof(StringToGenericDictionaryWrapperInternalConstructor<string>), @"{""Key"":""Value""}")]
public static void Read_Generic_NoPublicConstructor_Throws(Type type, string json)
{
NotSupportedException ex = Assert.Throws<NotSupportedException>(() => JsonSerializer.Deserialize(json, type));
Assert.Contains(type.ToString(), ex.Message);
}
}
}
Loading

0 comments on commit 4ceccbb

Please sign in to comment.