Skip to content

Commit 7cd7783

Browse files
authored
Add tests mapping invalid JSON to objects with parameterized ctors (#41121)
* Move invalid JSON tests to dedicated file * Add tests mapping invalid JSON to objects with parameterized ctors
1 parent 954ca9c commit 7cd7783

File tree

4 files changed

+347
-303
lines changed

4 files changed

+347
-303
lines changed

src/libraries/System.Text.Json/tests/Serialization/CollectionTests/CollectionTests.Dictionary.cs

-302
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
using System.Collections.Generic;
77
using System.Collections.Immutable;
88
using System.Collections.Specialized;
9-
using System.Reflection;
109
using System.Text.Encodings.Web;
1110
using Xunit;
1211

@@ -313,297 +312,6 @@ public static void ImplementsIDictionaryOfString()
313312
Assert.Equal("Software Architect", obj["Job"]);
314313
}
315314

316-
[Theory]
317-
[InlineData(typeof(ImmutableDictionary<string, string>), "\"headers\"")]
318-
[InlineData(typeof(Dictionary<string, string>), "\"headers\"")]
319-
[InlineData(typeof(PocoDictionary), "\"headers\"")]
320-
public static void InvalidJsonForValueShouldFail(Type type, string json)
321-
{
322-
Assert.Throws<JsonException>(() => JsonSerializer.Deserialize(json, type));
323-
}
324-
325-
public static IEnumerable<string> InvalidJsonForIntValue()
326-
{
327-
yield return @"""1""";
328-
yield return "[";
329-
yield return "}";
330-
yield return @"[""1""]";
331-
yield return "[true]";
332-
}
333-
334-
public static IEnumerable<string> InvalidJsonForPoco()
335-
{
336-
foreach (string value in InvalidJsonForIntValue())
337-
{
338-
yield return value;
339-
yield return "[" + value + "]";
340-
yield return "{" + value + "}";
341-
yield return @"{""Id"":" + value + "}";
342-
}
343-
}
344-
345-
public class ClassWithInt
346-
{
347-
public int Obj { get; set; }
348-
}
349-
350-
public class ClassWithIntList
351-
{
352-
public List<int> Obj { get; set; }
353-
}
354-
355-
public class ClassWithIntArray
356-
{
357-
public int[] Obj { get; set; }
358-
}
359-
360-
public class ClassWithPoco
361-
{
362-
public Poco Obj { get; set; }
363-
}
364-
365-
public class ClassWithPocoArray
366-
{
367-
public Poco[] Obj { get; set; }
368-
}
369-
370-
public class ClassWithDictionaryOfIntArray
371-
{
372-
public Dictionary<string, int[]> Obj { get; set; }
373-
}
374-
375-
public class ClassWithDictionaryOfPoco
376-
{
377-
public Dictionary<string, Poco> Obj { get; set; }
378-
}
379-
380-
public class ClassWithDictionaryOfPocoList
381-
{
382-
public Dictionary<string, List<Poco>> Obj { get; set; }
383-
}
384-
385-
public static IEnumerable<Type> TypesForInvalidJsonForCollectionTests()
386-
{
387-
static Type MakeClosedCollectionType(Type openCollectionType, Type elementType)
388-
{
389-
if (openCollectionType == typeof(Dictionary<,>))
390-
{
391-
return typeof(Dictionary<,>).MakeGenericType(typeof(string), elementType);
392-
}
393-
else
394-
{
395-
return openCollectionType.MakeGenericType(elementType);
396-
}
397-
}
398-
399-
Type[] elementTypes = new Type[]
400-
{
401-
typeof(int),
402-
typeof(Poco),
403-
typeof(ClassWithInt),
404-
typeof(ClassWithIntList),
405-
typeof(ClassWithPoco),
406-
typeof(ClassWithPocoArray),
407-
typeof(ClassWithDictionaryOfIntArray),
408-
typeof(ClassWithDictionaryOfPoco),
409-
typeof(ClassWithDictionaryOfPocoList),
410-
};
411-
412-
Type[] collectionTypes = new Type[]
413-
{
414-
typeof(List<>),
415-
typeof(Dictionary<,>),
416-
};
417-
418-
foreach (Type type in elementTypes)
419-
{
420-
yield return type;
421-
}
422-
423-
List<Type> innerTypes = new List<Type>(elementTypes);
424-
425-
// Create permutations of collections with 1 and 2 levels of nesting.
426-
for (int i = 0; i < 2; i++)
427-
{
428-
foreach (Type collectionType in collectionTypes)
429-
{
430-
List<Type> newInnerTypes = new List<Type>();
431-
432-
foreach (Type elementType in innerTypes)
433-
{
434-
Type newCollectionType = MakeClosedCollectionType(collectionType, elementType);
435-
newInnerTypes.Add(newCollectionType);
436-
yield return newCollectionType;
437-
}
438-
439-
innerTypes = newInnerTypes;
440-
}
441-
}
442-
}
443-
444-
static IEnumerable<string> GetInvalidJsonStringsForType(Type type)
445-
{
446-
if (type == typeof(int))
447-
{
448-
foreach (string json in InvalidJsonForIntValue())
449-
{
450-
yield return json;
451-
}
452-
yield break;
453-
}
454-
455-
if (type == typeof(Poco))
456-
{
457-
foreach (string json in InvalidJsonForPoco())
458-
{
459-
yield return json;
460-
}
461-
yield break;
462-
}
463-
464-
Type elementType;
465-
466-
if (!typeof(IEnumerable).IsAssignableFrom(type))
467-
{
468-
// Get type of "Obj" property.
469-
elementType = type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)[0].PropertyType;
470-
}
471-
else if (type.IsArray)
472-
{
473-
elementType = type.GetElementType();
474-
}
475-
else if (!type.IsGenericType)
476-
{
477-
Assert.True(false, "Expected generic type");
478-
yield break;
479-
}
480-
else
481-
{
482-
Type genericTypeDef = type.GetGenericTypeDefinition();
483-
484-
if (genericTypeDef == typeof(List<>))
485-
{
486-
elementType = type.GetGenericArguments()[0];
487-
}
488-
else if (genericTypeDef == typeof(Dictionary<,>))
489-
{
490-
elementType = type.GetGenericArguments()[1];
491-
}
492-
else
493-
{
494-
Assert.True(false, "Expected List or Dictionary type");
495-
yield break;
496-
}
497-
}
498-
499-
foreach (string invalidJson in GetInvalidJsonStringsForType(elementType))
500-
{
501-
yield return "[" + invalidJson + "]";
502-
yield return "{" + invalidJson + "}";
503-
yield return @"{""Obj"":" + invalidJson + "}";
504-
}
505-
}
506-
507-
public static IEnumerable<object[]> DataForInvalidJsonForTypeTests()
508-
{
509-
foreach (Type type in TypesForInvalidJsonForCollectionTests())
510-
{
511-
foreach (string invalidJson in GetInvalidJsonStringsForType(type))
512-
{
513-
yield return new object[] { type, invalidJson };
514-
}
515-
}
516-
517-
yield return new object[] { typeof(int[]), @"""test""" };
518-
yield return new object[] { typeof(int[]), @"1" };
519-
yield return new object[] { typeof(int[]), @"false" };
520-
yield return new object[] { typeof(int[]), @"{}" };
521-
yield return new object[] { typeof(int[]), @"{""test"": 1}" };
522-
yield return new object[] { typeof(int[]), @"[""test""" };
523-
yield return new object[] { typeof(int[]), @"[""test""]" };
524-
yield return new object[] { typeof(int[]), @"[true]" };
525-
yield return new object[] { typeof(int[]), @"[{}]" };
526-
yield return new object[] { typeof(int[]), @"[[]]" };
527-
yield return new object[] { typeof(int[]), @"[{""test"": 1}]" };
528-
yield return new object[] { typeof(int[]), @"[[true]]" };
529-
yield return new object[] { typeof(Dictionary<string, int[]>), @"{""test"": {}}" };
530-
yield return new object[] { typeof(Dictionary<string, int[]>), @"{""test"": {""test"": 1}}" };
531-
yield return new object[] { typeof(Dictionary<string, int[]>), @"{""test"": ""test""}" };
532-
yield return new object[] { typeof(Dictionary<string, int[]>), @"{""test"": 1}" };
533-
yield return new object[] { typeof(Dictionary<string, int[]>), @"{""test"": true}" };
534-
yield return new object[] { typeof(Dictionary<string, int[]>), @"{""test"": [""test""}" };
535-
yield return new object[] { typeof(Dictionary<string, int[]>), @"{""test"": [""test""]}" };
536-
yield return new object[] { typeof(Dictionary<string, int[]>), @"{""test"": [[]]}" };
537-
yield return new object[] { typeof(Dictionary<string, int[]>), @"{""test"": [true]}" };
538-
yield return new object[] { typeof(Dictionary<string, int[]>), @"{""test"": [{}]}" };
539-
yield return new object[] { typeof(ClassWithIntArray), @"{""Obj"": ""test""}" };
540-
yield return new object[] { typeof(ClassWithIntArray), @"{""Obj"": 1}" };
541-
yield return new object[] { typeof(ClassWithIntArray), @"{""Obj"": false}" };
542-
yield return new object[] { typeof(ClassWithIntArray), @"{""Obj"": {}}" };
543-
yield return new object[] { typeof(ClassWithIntArray), @"{""Obj"": {""test"": 1}}" };
544-
yield return new object[] { typeof(ClassWithIntArray), @"{""Obj"": [""test""}" };
545-
yield return new object[] { typeof(ClassWithIntArray), @"{""Obj"": [""test""]}" };
546-
yield return new object[] { typeof(ClassWithIntArray), @"{""Obj"": [true]}" };
547-
yield return new object[] { typeof(ClassWithIntArray), @"{""Obj"": [{}]}" };
548-
yield return new object[] { typeof(ClassWithIntArray), @"{""Obj"": [[]]}" };
549-
yield return new object[] { typeof(ClassWithIntArray), @"{""Obj"": [{""test"": 1}]}" };
550-
yield return new object[] { typeof(ClassWithIntArray), @"{""Obj"": [[true]]}" };
551-
yield return new object[] { typeof(Dictionary<string, string>), @"""test""" };
552-
yield return new object[] { typeof(Dictionary<string, string>), @"1" };
553-
yield return new object[] { typeof(Dictionary<string, string>), @"false" };
554-
yield return new object[] { typeof(Dictionary<string, string>), @"{"""": 1}" };
555-
yield return new object[] { typeof(Dictionary<string, string>), @"{"""": {}}" };
556-
yield return new object[] { typeof(Dictionary<string, string>), @"{"""": {"""":""""}}" };
557-
yield return new object[] { typeof(Dictionary<string, string>), @"[""test""" };
558-
yield return new object[] { typeof(Dictionary<string, string>), @"[""test""]" };
559-
yield return new object[] { typeof(Dictionary<string, string>), @"[true]" };
560-
yield return new object[] { typeof(Dictionary<string, string>), @"[{}]" };
561-
yield return new object[] { typeof(Dictionary<string, string>), @"[[]]" };
562-
yield return new object[] { typeof(Dictionary<string, string>), @"[{""test"": 1}]" };
563-
yield return new object[] { typeof(Dictionary<string, string>), @"[[true]]" };
564-
yield return new object[] { typeof(ClassWithDictionaryOfIntArray), @"{""Obj"":""test""}" };
565-
yield return new object[] { typeof(ClassWithDictionaryOfIntArray), @"{""Obj"":1}" };
566-
yield return new object[] { typeof(ClassWithDictionaryOfIntArray), @"{""Obj"":false}" };
567-
yield return new object[] { typeof(ClassWithDictionaryOfIntArray), @"{""Obj"":{"""": 1}}" };
568-
yield return new object[] { typeof(ClassWithDictionaryOfIntArray), @"{""Obj"":{"""": {}}}" };
569-
yield return new object[] { typeof(ClassWithDictionaryOfIntArray), @"{""Obj"":{"""": {"""":""""}}}" };
570-
yield return new object[] { typeof(ClassWithDictionaryOfIntArray), @"{""Obj"":[""test""}" };
571-
yield return new object[] { typeof(ClassWithDictionaryOfIntArray), @"{""Obj"":[""test""]}" };
572-
yield return new object[] { typeof(ClassWithDictionaryOfIntArray), @"{""Obj"":[true]}" };
573-
yield return new object[] { typeof(ClassWithDictionaryOfIntArray), @"{""Obj"":[{}]}" };
574-
yield return new object[] { typeof(ClassWithDictionaryOfIntArray), @"{""Obj"":[[]]}" };
575-
yield return new object[] { typeof(ClassWithDictionaryOfIntArray), @"{""Obj"":[{""test"": 1}]}" };
576-
yield return new object[] { typeof(ClassWithDictionaryOfIntArray), @"{""Obj"":[[true]]}" };
577-
yield return new object[] { typeof(Dictionary<string, Poco>), @"{""key"":[{""Id"":3}]}" };
578-
yield return new object[] { typeof(Dictionary<string, Poco>), @"{""key"":[""test""]}" };
579-
yield return new object[] { typeof(Dictionary<string, Poco>), @"{""key"":[1]}" };
580-
yield return new object[] { typeof(Dictionary<string, Poco>), @"{""key"":[false]}" };
581-
yield return new object[] { typeof(Dictionary<string, Poco>), @"{""key"":[]}" };
582-
yield return new object[] { typeof(Dictionary<string, Poco>), @"{""key"":1}" };
583-
yield return new object[] { typeof(Dictionary<string, List<Poco>>), @"{""key"":{""Id"":3}}" };
584-
yield return new object[] { typeof(Dictionary<string, List<Poco>>), @"{""key"":{}}" };
585-
yield return new object[] { typeof(Dictionary<string, List<Poco>>), @"{""key"":[[]]}" };
586-
yield return new object[] { typeof(Dictionary<string, Dictionary<string, Poco>>), @"{""key"":[]}" };
587-
yield return new object[] { typeof(Dictionary<string, Dictionary<string, Poco>>), @"{""key"":1}" };
588-
}
589-
590-
[Fact]
591-
public static void InvalidJsonForTypeShouldFail()
592-
{
593-
foreach (object[] args in DataForInvalidJsonForTypeTests()) // ~140K tests, too many for theory to handle well with our infrastructure
594-
{
595-
var type = (Type)args[0];
596-
var invalidJson = (string)args[1];
597-
Assert.Throws<JsonException>(() => JsonSerializer.Deserialize(invalidJson, type));
598-
}
599-
}
600-
601-
[Fact]
602-
public static void InvalidEmptyDictionaryInput()
603-
{
604-
Assert.Throws<JsonException>(() => JsonSerializer.Deserialize<string>("{}"));
605-
}
606-
607315
[Fact]
608316
public static void PocoWithDictionaryObject()
609317
{
@@ -612,11 +320,6 @@ public static void PocoWithDictionaryObject()
612320
Assert.Equal("d", dict.key["c"]);
613321
}
614322

615-
public class PocoDictionary
616-
{
617-
public Dictionary<string, string> key { get; set; }
618-
}
619-
620323
[Fact]
621324
public static void DictionaryOfObject_NonPrimitiveTypes()
622325
{
@@ -635,11 +338,6 @@ public static void DictionaryOfObject_NonPrimitiveTypes()
635338
Assert.Equal(@"{""Id"":10}", element.ToString());
636339
}
637340

638-
public class Poco
639-
{
640-
public int Id { get; set; }
641-
}
642-
643341
[Fact]
644342
public static void DictionaryOfList()
645343
{

0 commit comments

Comments
 (0)