diff --git a/global.json b/global.json index 605ebddb8af3..2d6db50e5756 100644 --- a/global.json +++ b/global.json @@ -3,7 +3,7 @@ "Microsoft.Build.Traversal": "3.2.0" }, "sdk": { - "version": "8.0.100", + "version": "8.0.405", "rollForward": "feature" } } diff --git a/sdk/core/System.ClientModel/api/System.ClientModel.net6.0.cs b/sdk/core/System.ClientModel/api/System.ClientModel.net6.0.cs index 2cce8ba3d9f0..7e4be1c63632 100644 --- a/sdk/core/System.ClientModel/api/System.ClientModel.net6.0.cs +++ b/sdk/core/System.ClientModel/api/System.ClientModel.net6.0.cs @@ -185,7 +185,7 @@ public sealed override void Process(System.ClientModel.Primitives.PipelineMessag public static partial class ModelReaderWriter { public static object? Read(System.BinaryData data, [System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.NonPublicConstructors | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicConstructors)] System.Type returnType, System.ClientModel.Primitives.ModelReaderWriterOptions? options = null) { throw null; } - public static T? Read(System.BinaryData data, System.ClientModel.Primitives.ModelReaderWriterOptions? options = null) where T : System.ClientModel.Primitives.IPersistableModel { throw null; } + public static T? Read(System.BinaryData data, System.ClientModel.Primitives.ModelReaderWriterOptions? options = null) { throw null; } public static System.BinaryData Write(object model, System.ClientModel.Primitives.ModelReaderWriterOptions? options = null) { throw null; } public static System.BinaryData Write(T model, System.ClientModel.Primitives.ModelReaderWriterOptions? options = null) where T : System.ClientModel.Primitives.IPersistableModel { throw null; } } diff --git a/sdk/core/System.ClientModel/api/System.ClientModel.net8.0.cs b/sdk/core/System.ClientModel/api/System.ClientModel.net8.0.cs index 2cce8ba3d9f0..7e4be1c63632 100644 --- a/sdk/core/System.ClientModel/api/System.ClientModel.net8.0.cs +++ b/sdk/core/System.ClientModel/api/System.ClientModel.net8.0.cs @@ -185,7 +185,7 @@ public sealed override void Process(System.ClientModel.Primitives.PipelineMessag public static partial class ModelReaderWriter { public static object? Read(System.BinaryData data, [System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.NonPublicConstructors | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicConstructors)] System.Type returnType, System.ClientModel.Primitives.ModelReaderWriterOptions? options = null) { throw null; } - public static T? Read(System.BinaryData data, System.ClientModel.Primitives.ModelReaderWriterOptions? options = null) where T : System.ClientModel.Primitives.IPersistableModel { throw null; } + public static T? Read(System.BinaryData data, System.ClientModel.Primitives.ModelReaderWriterOptions? options = null) { throw null; } public static System.BinaryData Write(object model, System.ClientModel.Primitives.ModelReaderWriterOptions? options = null) { throw null; } public static System.BinaryData Write(T model, System.ClientModel.Primitives.ModelReaderWriterOptions? options = null) where T : System.ClientModel.Primitives.IPersistableModel { throw null; } } diff --git a/sdk/core/System.ClientModel/api/System.ClientModel.netstandard2.0.cs b/sdk/core/System.ClientModel/api/System.ClientModel.netstandard2.0.cs index c26dae86758c..1155a7b66401 100644 --- a/sdk/core/System.ClientModel/api/System.ClientModel.netstandard2.0.cs +++ b/sdk/core/System.ClientModel/api/System.ClientModel.netstandard2.0.cs @@ -184,7 +184,7 @@ public sealed override void Process(System.ClientModel.Primitives.PipelineMessag public static partial class ModelReaderWriter { public static object? Read(System.BinaryData data, System.Type returnType, System.ClientModel.Primitives.ModelReaderWriterOptions? options = null) { throw null; } - public static T? Read(System.BinaryData data, System.ClientModel.Primitives.ModelReaderWriterOptions? options = null) where T : System.ClientModel.Primitives.IPersistableModel { throw null; } + public static T? Read(System.BinaryData data, System.ClientModel.Primitives.ModelReaderWriterOptions? options = null) { throw null; } public static System.BinaryData Write(object model, System.ClientModel.Primitives.ModelReaderWriterOptions? options = null) { throw null; } public static System.BinaryData Write(T model, System.ClientModel.Primitives.ModelReaderWriterOptions? options = null) where T : System.ClientModel.Primitives.IPersistableModel { throw null; } } diff --git a/sdk/core/System.ClientModel/src/ModelReaderWriter/ModelReaderWriter.cs b/sdk/core/System.ClientModel/src/ModelReaderWriter/ModelReaderWriter.cs index ece3e8c64199..59f496e527e5 100644 --- a/sdk/core/System.ClientModel/src/ModelReaderWriter/ModelReaderWriter.cs +++ b/sdk/core/System.ClientModel/src/ModelReaderWriter/ModelReaderWriter.cs @@ -2,8 +2,11 @@ // Licensed under the MIT License. using System.ClientModel.Internal; +using System.Collections; +using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; +using System.Text.Json; namespace System.ClientModel.Primitives; @@ -12,6 +15,12 @@ namespace System.ClientModel.Primitives; /// public static class ModelReaderWriter { + private static readonly HashSet s_supportedCollectionTypes = + [ + typeof(List<>), + typeof(Dictionary<,>) + ]; + /// /// Converts the value of a model into a . /// @@ -61,24 +70,86 @@ public static BinaryData Write(object model, ModelReaderWriterOptions? options = } options ??= ModelReaderWriterOptions.Json; + if (model is IPersistableModel iModel && !ShouldWriteAsJson(iModel, options, out _)) + { + return iModel.Write(options); + } + else + { + using UnsafeBufferSequence sequenceWriter = new(); + using Utf8JsonWriter writer = new(sequenceWriter); + WriteJson(model, options, writer); + writer.Flush(); + return sequenceWriter.ExtractReader().ToBinaryData(); + } + } - var iModel = model as IPersistableModel; - if (iModel is null) + private static void WriteJson(object model, ModelReaderWriterOptions options, Utf8JsonWriter writer) + { + if (model is IPersistableModel iModel && ShouldWriteAsJson(iModel, options, out IJsonModel? jsonModel)) + { + jsonModel.Write(writer, options); + } + else if (model is IEnumerable enumerable) { - throw new InvalidOperationException($"{model.GetType().Name} does not implement {nameof(IPersistableModel)}"); + WriteEnumerable(options, enumerable, writer); } + else + { + throw new InvalidOperationException($"{model.GetType().Name} does not implement {nameof(IPersistableModel)} or {nameof(IEnumerable>)}"); + } + } - if (ShouldWriteAsJson(iModel, options, out IJsonModel? jsonModel)) + private static void WriteEnumerable(ModelReaderWriterOptions options, IEnumerable enumerable, Utf8JsonWriter writer) + { + var enumerableType = enumerable.GetType(); + + if (enumerableType.IsArray && enumerableType.GetArrayRank() > 1 && enumerableType.GetElementType()?.IsArray == false) //multi-dimensional array { - using (UnsafeBufferSequence.Reader reader = new ModelWriter(jsonModel, options).ExtractReader()) + Array array = (Array)enumerable; + WriteMultiDimensionalArray(array, new int[array.Rank], 0, options, writer); + } + else + { + if (enumerable is IDictionary dictionary) { - return reader.ToBinaryData(); + writer.WriteStartObject(); + foreach (var key in dictionary.Keys) + { + writer.WritePropertyName(key.ToString()!); + WriteJson(dictionary[key]!, options, writer); + } + writer.WriteEndObject(); + } + else + { + writer.WriteStartArray(); + foreach (var item in enumerable) + { + WriteJson(item, options, writer); + } + writer.WriteEndArray(); } } - else + } + + private static void WriteMultiDimensionalArray(Array array, int[] indices, int currentDimension, ModelReaderWriterOptions options, Utf8JsonWriter writer) + { + // If we've reached the innermost dimension, print the value at the collected indices + if (currentDimension == array.Rank) { - return iModel.Write(options); + WriteJson(array.GetValue(indices)!, options, writer); + return; } + + writer.WriteStartArray(); + // Recursively iterate through each level + for (int i = 0; i < array.GetLength(currentDimension); i++) + { + indices[currentDimension] = i; + WriteMultiDimensionalArray(array, indices, currentDimension + 1, options, writer); + } + writer.WriteEndArray(); } /// @@ -91,8 +162,9 @@ public static BinaryData Write(object model, ModelReaderWriterOptions? options = /// If the model does not support the requested . /// If is null. /// If does not have a public or non public empty constructor. - public static T? Read<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] T>(BinaryData data, ModelReaderWriterOptions? options = default) - where T : IPersistableModel + public static T? Read<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] T>( + BinaryData data, + ModelReaderWriterOptions? options = default) { if (data is null) { @@ -101,14 +173,36 @@ public static BinaryData Write(object model, ModelReaderWriterOptions? options = options ??= ModelReaderWriterOptions.Json; - return GetInstance().Create(data, options); + Type typeOfT = typeof(T); + + if (typeOfT.IsArray) + { + throw new ArgumentException("Arrays are not supported. Use List<> instead.", nameof(T)); + } + + var genericType = typeOfT.IsGenericType ? typeOfT.GetGenericTypeDefinition() : null; + + if (genericType is not null) + { + if (!s_supportedCollectionTypes.Contains(genericType)) + { + throw new ArgumentException($"Collection Type {typeOfT.Name} is not supported.", nameof(T)); + } + + return (T)ReadCollection(data, typeOfT, nameof(T), options); + } + else + { + var iModel = GetInstance(typeOfT) as IPersistableModel; + return iModel!.Create(data, options); + } } /// /// Converts the into a . /// /// The to convert. - /// The type of the objec to convert and return. + /// The type of the object to convert and return. /// The to use. /// A representation of the . /// Throws if does not implement . @@ -116,7 +210,10 @@ public static BinaryData Write(object model, ModelReaderWriterOptions? options = /// If the model does not support the requested . /// If or are null. /// If does not have a public or non public empty constructor. - public static object? Read(BinaryData data, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] Type returnType, ModelReaderWriterOptions? options = default) + public static object? Read( + BinaryData data, + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] Type returnType, + ModelReaderWriterOptions? options = default) { if (data is null) { @@ -128,28 +225,174 @@ public static BinaryData Write(object model, ModelReaderWriterOptions? options = throw new ArgumentNullException(nameof(returnType)); } + if (returnType.IsArray) + { + throw new ArgumentException("Arrays are not supported. Use List<> instead.", nameof(returnType)); + } + options ??= ModelReaderWriterOptions.Json; - return GetInstance(returnType).Create(data, options); + var genericType = returnType.IsGenericType ? returnType.GetGenericTypeDefinition() : null; + + if (genericType is not null) + { + if (!s_supportedCollectionTypes.Contains(genericType)) + { + throw new ArgumentException($"Collection Type {returnType.Name} is not supported.", nameof(returnType)); + } + + return ReadCollection(data, returnType, nameof(returnType), options); + } + else + { + return GetInstance(returnType).Create(data, options); + } + } + + private static object ReadCollection( + BinaryData data, + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] Type returnType, + string paramName, + ModelReaderWriterOptions options) + { + object collection = CallActivator(returnType); + Utf8JsonReader reader = new Utf8JsonReader(data); + reader.Read(); + var genericType = returnType.GetGenericTypeDefinition(); + if (genericType.Equals(typeof(Dictionary<,>))) + { + if (reader.TokenType != JsonTokenType.StartObject) + { + throw new FormatException("Expected start of dictionary."); + } + } + else if (reader.TokenType != JsonTokenType.StartArray) + { + throw new FormatException("Expected start of array."); + } + ReadJsonCollection(ref reader, collection, paramName, options); + return collection; } - private static IPersistableModel GetInstance([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] Type returnType) + private static void ReadJsonCollection( + ref Utf8JsonReader reader, + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] object collection, + string paramName, + ModelReaderWriterOptions options) { - var model = GetObjectInstance(returnType) as IPersistableModel; - if (model is null) + int argNumber = collection is IDictionary ? 1 : 0; + Type elementType = collection.GetType().GetGenericArguments()[argNumber]; + if (elementType.IsArray) { - throw new InvalidOperationException($"{returnType.Name} does not implement {nameof(IPersistableModel)}"); + throw new ArgumentException("Arrays are not supported. Use List<> instead."); + } + Type? elementGenericType = elementType.IsGenericType ? elementType.GetGenericTypeDefinition() : null; + if (elementGenericType is not null && !s_supportedCollectionTypes.Contains(elementGenericType)) + { + throw new ArgumentException($"Collection Type {elementGenericType.Name} is not supported.", paramName); + } + + bool isElementDictionary = elementGenericType is not null && elementGenericType.Equals(typeof(Dictionary<,>)); + + var persistableModel = GetObjectInstance(elementType) as IPersistableModel; + IJsonModel? iJsonModel = null; + if (elementGenericType is null && (persistableModel is null || !ShouldWriteAsJson(persistableModel, options, out iJsonModel))) + { + throw new InvalidOperationException($"Element type {elementType.Name} must implement IJsonModel<>."); + } + bool isInnerCollection = iJsonModel is null; + string? propertyName = null; + + while (reader.Read()) + { + switch (reader.TokenType) + { + case JsonTokenType.StartObject: + if (isInnerCollection) + { + if (isElementDictionary) + { + var innerDictionary = CallActivator(elementType); + AddItemToCollection(collection, propertyName, innerDictionary); + ReadJsonCollection(ref reader, innerDictionary, paramName, options); + } + else + { + throw new FormatException("Unexpected StartObject found."); + } + } + else + { + AddItemToCollection(collection, propertyName, iJsonModel!.Create(ref reader, options)); + } + break; + case JsonTokenType.StartArray: + if (!isInnerCollection || isElementDictionary) + { + throw new FormatException("Unexpected StartArray found."); + } + + object innerList = CallActivator(elementType); + AddItemToCollection(collection, propertyName, innerList); + ReadJsonCollection(ref reader, innerList, paramName, options); + break; + case JsonTokenType.EndArray: + return; + case JsonTokenType.PropertyName: + propertyName = reader.GetString(); + break; + case JsonTokenType.EndObject: + return; + default: + throw new FormatException($"Unexpected token {reader.TokenType}."); + } } - return model; } - private static IPersistableModel GetInstance<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] T>() - where T : IPersistableModel + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static object CallActivator( + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] Type typeToActivate, + bool nonPublic = false) { - var model = GetObjectInstance(typeof(T)) as IPersistableModel; + var obj = Activator.CreateInstance(typeToActivate, nonPublic); + if (obj is null) + { + //we should never get here, but just in case + throw new InvalidOperationException($"Unable to create instance of {typeToActivate.Name}."); + } + + return obj; + } + + private static void AddItemToCollection(object collection, string? key, object item) + { + if (collection is IDictionary dictionary) + { + if (key is null) + { + //we should never get here because System.Text.Json will throw JsonReaderException if there was no property name + throw new FormatException("Null key found for dictionary entry."); + } + dictionary.Add(key, item); + } + else if (collection is IList list) + { + list.Add(item); + } + else + { + //we should never be able to get here since we check for supported collection types in ReadCollection + throw new InvalidOperationException($"Collection type {collection.GetType().Name} is not supported."); + } + } + + private static IPersistableModel GetInstance( + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] Type returnType) + { + var model = GetObjectInstance(returnType) as IPersistableModel; if (model is null) { - throw new InvalidOperationException($"{typeof(T).Name} does not implement {nameof(IPersistableModel)}"); + throw new InvalidOperationException($"{returnType.Name} does not implement {nameof(IPersistableModel)}"); } return model; } @@ -164,12 +407,7 @@ internal static object GetObjectInstance([DynamicallyAccessedMembers(Dynamically throw new InvalidOperationException($"{returnType.Name} must be decorated with {nameof(PersistableModelProxyAttribute)} to be used with {nameof(ModelReaderWriter)}"); } - var obj = Activator.CreateInstance(typeToActivate, true); - if (obj is null) - { - throw new InvalidOperationException($"Unable to create instance of {typeToActivate.Name}."); - } - return obj; + return CallActivator(typeToActivate, true); } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -196,8 +434,4 @@ internal static bool ShouldWriteAsJson(IPersistableModel model, ModelRea [MethodImpl(MethodImplOptions.AggressiveInlining)] private static bool IsJsonFormatRequested(IPersistableModel model, ModelReaderWriterOptions options) => options.Format == "J" || (options.Format == "W" && model.GetFormatFromOptions(options) == "J"); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static bool IsJsonFormatRequested(IPersistableModel model, ModelReaderWriterOptions options) - => IsJsonFormatRequested(model, options); } diff --git a/sdk/core/System.ClientModel/tests/ModelReaderWriter/ModelReaderWriterTests.cs b/sdk/core/System.ClientModel/tests/ModelReaderWriter/ModelReaderWriterTests.cs index e66412cfd987..ebd65ac41149 100644 --- a/sdk/core/System.ClientModel/tests/ModelReaderWriter/ModelReaderWriterTests.cs +++ b/sdk/core/System.ClientModel/tests/ModelReaderWriter/ModelReaderWriterTests.cs @@ -1,31 +1,48 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -using NUnit.Framework; using System.ClientModel.Primitives; using System.ClientModel.Tests.Client.ModelReaderWriterTests.Models; +using System.Collections; +using System.Collections.Generic; +using System.Collections.ObjectModel; using System.Text.Json; +using NUnit.Framework; namespace System.ClientModel.Tests.ModelReaderWriterTests { public class ModelReaderWriterTests { - private static readonly ModelReaderWriterOptions _wireOptions = new ModelReaderWriterOptions("W"); + private static readonly ModelReaderWriterOptions s_wireOptions = new("W"); + + private static readonly List s_emptyCollections = + [ + new List(), + new SubType[] { }, + new Collection { }, + new ObservableCollection { }, + new HashSet { }, + new Queue { }, + new Stack { }, + new LinkedList { }, + new SortedSet { }, + new ArrayList { }, + ]; [Test] public void ArgumentExceptions() { Assert.Throws(() => ModelReaderWriter.Read(null!)); Assert.Throws(() => ModelReaderWriter.Read(null!, typeof(BaseWithNoUnknown))); - Assert.Throws(() => ModelReaderWriter.Read(new BinaryData(new byte[] { }), null!)); + Assert.Throws(() => ModelReaderWriter.Read(BinaryData.Empty, null!)); Assert.Throws(() => ModelReaderWriter.Write(null!)); Assert.Throws(() => ModelReaderWriter.Write(null!)); - Assert.Throws(() => ModelReaderWriter.Read(null!, _wireOptions)); - Assert.Throws(() => ModelReaderWriter.Read(null!, typeof(BaseWithNoUnknown), _wireOptions)); - Assert.Throws(() => ModelReaderWriter.Read(new BinaryData(new byte[] { }), null!, _wireOptions)); - Assert.Throws(() => ModelReaderWriter.Write(null!, _wireOptions)); - Assert.Throws(() => ModelReaderWriter.Write(null!, _wireOptions)); + Assert.Throws(() => ModelReaderWriter.Read(null!, s_wireOptions)); + Assert.Throws(() => ModelReaderWriter.Read(null!, typeof(BaseWithNoUnknown), s_wireOptions)); + Assert.Throws(() => ModelReaderWriter.Read(BinaryData.Empty, null!, s_wireOptions)); + Assert.Throws(() => ModelReaderWriter.Write(null!, s_wireOptions)); + Assert.Throws(() => ModelReaderWriter.Write(null!, s_wireOptions)); } [TestCaseSource(typeof(ReaderWriterTestSource), "InvalidOperationBinaryData")] @@ -49,7 +66,7 @@ public void ValidateJsonExceptionBinaryData(BinaryData data) gotException = true; } - Assert.IsTrue(gotException, "Did not recieve exception"); + Assert.IsTrue(gotException, "Did not receive exception"); gotException = false; try @@ -62,7 +79,7 @@ public void ValidateJsonExceptionBinaryData(BinaryData data) gotException = true; } - Assert.IsTrue(gotException, "Did not recieve exception"); + Assert.IsTrue(gotException, "Did not receive exception"); } [TestCaseSource(typeof(ReaderWriterTestSource), "NullBinaryData")] @@ -83,26 +100,144 @@ public void ValidateEmptyObjectBinaryData(BinaryData data) public void ValidateErrorIfUnknownDoesntExist() { BaseWithNoUnknown baseInstance = new SubType(); - Assert.Throws(() => ModelReaderWriter.Read(new BinaryData(Array.Empty()))); - Assert.Throws(() => ModelReaderWriter.Read(new BinaryData(Array.Empty()), typeof(BaseWithNoUnknown))); + Assert.Throws(() => ModelReaderWriter.Read(BinaryData.Empty)); + Assert.Throws(() => ModelReaderWriter.Read(BinaryData.Empty, typeof(BaseWithNoUnknown))); } [Test] public void ValidateErrorIfNoDefaultCtor() { - Assert.Throws(() => ModelReaderWriter.Read(new BinaryData(Array.Empty()))); + Assert.Throws(() => ModelReaderWriter.Read(BinaryData.Empty)); } [Test] public void ValidateErrorIfNotImplementInterface() { - var ex = Assert.Throws(() => ModelReaderWriter.Read(new BinaryData(Array.Empty()), typeof(DoesntImplementInterface))); + var ex = Assert.Throws(() => ModelReaderWriter.Read(BinaryData.Empty, typeof(DoesNotImplementInterface))); Assert.IsTrue(ex?.Message.Contains("does not implement")); - ex = Assert.Throws(() => ModelReaderWriter.Write(new DoesntImplementInterface())); + ex = Assert.Throws(() => ModelReaderWriter.Write(new DoesNotImplementInterface())); Assert.IsTrue(ex?.Message.Contains("does not implement")); } - private class DoesntImplementInterface { } + [Test] + public void EmptyEnumerableOfNoInterface() + { + List list = []; + BinaryData data = ModelReaderWriter.Write(list); + Assert.AreEqual("[]", data.ToString()); + } + + [Test] + public void EmptyEnumerableOfNonJson() + { + List list = []; + BinaryData data = ModelReaderWriter.Write(list, new ModelReaderWriterOptions("X")); + Assert.AreEqual("[]", data.ToString()); + } + + [Test] + public void EnumerableOfNoInterface() + { + List list = + [ + new DoesNotImplementInterface(), + ]; + Assert.Throws(() => ModelReaderWriter.Write(list)); + } + + [Test] + public void EnumerableOfNonJson() + { + List list = + [ + new SubType(), + ]; + Assert.Throws(() => ModelReaderWriter.Write(list, new ModelReaderWriterOptions("X"))); + } + + [TestCaseSource(nameof(s_emptyCollections))] + public void WriteEmptyCollection(object collection) + { + BinaryData data = ModelReaderWriter.Write(collection); + Assert.IsNotNull(data); + Assert.AreEqual("[]", data.ToString()); + } + + [Test] + public void WriteDictionaryOfInterface() + { + Dictionary dict = new() + { + { "key", new SubType() }, + }; + BinaryData data = ModelReaderWriter.Write(dict); + Assert.IsNotNull(data); + Assert.AreEqual("{\"key\":{}}", data.ToString()); + } + + [Test] + public void NullOptionsWritesJson() + { + BinaryData data = ModelReaderWriter.Write(new SubType(), null); + Assert.IsNotNull(data); + Assert.AreEqual("{}", data.ToString()); + } + + [Test] + public void ReadListOfNonPersistableFails() + { + var json = "[{\"x\":1},{\"y\":2}]"; + var ex = Assert.Throws(() => ModelReaderWriter.Read>(BinaryData.FromString(json))); + Assert.IsNotNull(ex); + Assert.IsTrue(ex!.Message.EndsWith(" must implement IJsonModel<>.")); + } + + [Test] + public void ReadListOfDictionariesAsListOfLists() + { + var json = "[{\"x\":{}},{\"y\":{}}]"; + var ex = Assert.Throws(() => ModelReaderWriter.Read>>(BinaryData.FromString(json))); + Assert.IsNotNull(ex); + Assert.IsTrue(ex!.Message.Equals("Unexpected StartObject found.")); + } + + [Test] + public void ReadListOfListsAsListOfDictionaries() + { + var json = "[[{}],[{}]]"; + var ex = Assert.Throws(() => ModelReaderWriter.Read>>(BinaryData.FromString(json))); + Assert.IsNotNull(ex); + Assert.IsTrue(ex!.Message.Equals("Unexpected StartArray found.")); + } + + [Test] + public void ReadUnexpectedToken() + { + var json = "[null{}]"; + var ex = Assert.Throws(() => ModelReaderWriter.Read>(BinaryData.FromString(json))); + Assert.IsNotNull(ex); + Assert.IsTrue(ex!.Message.Equals("Unexpected token Null.")); + } + + [Test] + public void ReadDictionaryWithNoPropertyNames() + { + bool foundException = false; + var json = "{{},{}}"; + try + { + var result = ModelReaderWriter.Read>(BinaryData.FromString(json)); + } + catch (Exception ex) + { + foundException = true; + Assert.IsTrue(ex.GetType().Name.Equals("JsonReaderException")); + Assert.IsTrue(ex.Message.StartsWith("'{' is an invalid start of a property name.")); + } + Assert.IsTrue(foundException, "Expected an exception but none was thrown"); + } + + private class DoesNotImplementInterface { } private class SubType : BaseWithNoUnknown, IJsonModel { @@ -120,6 +255,8 @@ SubType IPersistableModel.Create(BinaryData data, ModelReaderWriterOpti void IJsonModel.Write(Utf8JsonWriter writer, ModelReaderWriterOptions options) { + writer.WriteStartObject(); + writer.WriteEndObject(); return; } @@ -145,6 +282,8 @@ BaseWithNoUnknown IPersistableModel.Create(BinaryData data, M void IJsonModel.Write(Utf8JsonWriter writer, ModelReaderWriterOptions options) { + writer.WriteStartObject(); + writer.WriteEndObject(); return; } diff --git a/sdk/core/System.ClientModel/tests/ModelReaderWriter/Models/AvailabilitySetDataDictionaryOfDictionariesTests.cs b/sdk/core/System.ClientModel/tests/ModelReaderWriter/Models/AvailabilitySetDataDictionaryOfDictionariesTests.cs new file mode 100644 index 000000000000..af4fe05af253 --- /dev/null +++ b/sdk/core/System.ClientModel/tests/ModelReaderWriter/Models/AvailabilitySetDataDictionaryOfDictionariesTests.cs @@ -0,0 +1,89 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System.ClientModel.Primitives; +using System.ClientModel.Tests.Client; +using System.ClientModel.Tests.Client.Models.ResourceManager.Compute; +using System.Collections.Generic; +using System.IO; +using System.Text; +using System.Text.Json; +using NUnit.Framework; + +namespace System.ClientModel.Tests.ModelReaderWriterTests.Models +{ + public class AvailabilitySetDataDictionaryOfDictionariesTests + { + private static readonly string s_payload = File.ReadAllText(TestData.GetLocation("AvailabilitySetData/AvailabilitySetDataDictionaryOfDictionaries.json")).TrimEnd(); + private static readonly BinaryData s_data = new BinaryData(Encoding.UTF8.GetBytes(s_payload)); + private static readonly IDictionary> s_availabilitySets = ModelReaderWriter.Read>>(s_data)!; + private static readonly string s_collapsedPayload = GetCollapsedPayload(); + + private static string GetCollapsedPayload() + { + var jsonObject = JsonSerializer.Deserialize(s_payload); + return JsonSerializer.Serialize(jsonObject); + } + + [Test] + public void ReadDictionaryGeneric() + { + var asetDictionary = ModelReaderWriter.Read>>(s_data); + Assert.IsNotNull(asetDictionary); + + Assert.AreEqual(2, asetDictionary!.Count); + Assert.IsTrue(asetDictionary.ContainsKey("dictionary1")); + var innerDictionary1 = asetDictionary["dictionary1"]; + Assert.IsNotNull(innerDictionary1); + Assert.AreEqual(2, innerDictionary1.Count); + Assert.IsTrue(innerDictionary1.ContainsKey("testAS-3375")); + Assert.IsTrue(innerDictionary1["testAS-3375"].Name!.Equals("testAS-3375")); + Assert.IsTrue(innerDictionary1.ContainsKey("testAS-3376")); + Assert.IsTrue(innerDictionary1["testAS-3376"].Name!.Equals("testAS-3376")); + Assert.IsTrue(asetDictionary.ContainsKey("dictionary2")); + var innerDictionary2 = asetDictionary["dictionary2"]; + Assert.IsNotNull(innerDictionary2); + Assert.AreEqual(2, innerDictionary2.Count); + Assert.IsTrue(innerDictionary2.ContainsKey("testAS-3377")); + Assert.IsTrue(innerDictionary2["testAS-3377"].Name!.Equals("testAS-3377")); + Assert.IsTrue(innerDictionary2.ContainsKey("testAS-3378")); + Assert.IsTrue(innerDictionary2["testAS-3378"].Name!.Equals("testAS-3378")); + } + + [Test] + public void ReadDictionary() + { + var asetDictionary = ModelReaderWriter.Read(s_data, typeof(Dictionary>)); + Assert.IsNotNull(asetDictionary); + + Dictionary>? asetDictionary2 = asetDictionary! as Dictionary>; + Assert.IsNotNull(asetDictionary2); + + Assert.AreEqual(2, asetDictionary2!.Count); + Assert.IsTrue(asetDictionary2.ContainsKey("dictionary1")); + var innerDictionary1 = asetDictionary2["dictionary1"]; + Assert.IsNotNull(innerDictionary1); + Assert.AreEqual(2, asetDictionary2.Count); + Assert.IsTrue(innerDictionary1.ContainsKey("testAS-3375")); + Assert.IsTrue(innerDictionary1["testAS-3375"].Name!.Equals("testAS-3375")); + Assert.IsTrue(innerDictionary1.ContainsKey("testAS-3376")); + Assert.IsTrue(innerDictionary1["testAS-3376"].Name!.Equals("testAS-3376")); + Assert.IsTrue(asetDictionary2.ContainsKey("dictionary2")); + var innerDictionary2 = asetDictionary2["dictionary2"]; + Assert.IsNotNull(innerDictionary2); + Assert.AreEqual(2, asetDictionary2.Count); + Assert.IsTrue(innerDictionary2.ContainsKey("testAS-3377")); + Assert.IsTrue(innerDictionary2["testAS-3377"].Name!.Equals("testAS-3377")); + Assert.IsTrue(innerDictionary2.ContainsKey("testAS-3378")); + Assert.IsTrue(innerDictionary2["testAS-3378"].Name!.Equals("testAS-3378")); + } + + [Test] + public void WriteDictionary() + { + BinaryData data = ModelReaderWriter.Write(s_availabilitySets); + Assert.IsNotNull(data); + Assert.AreEqual(s_collapsedPayload, data.ToString()); + } + } +} diff --git a/sdk/core/System.ClientModel/tests/ModelReaderWriter/Models/AvailabilitySetDataDictionaryOfListsTests.cs b/sdk/core/System.ClientModel/tests/ModelReaderWriter/Models/AvailabilitySetDataDictionaryOfListsTests.cs new file mode 100644 index 000000000000..09be1913b17b --- /dev/null +++ b/sdk/core/System.ClientModel/tests/ModelReaderWriter/Models/AvailabilitySetDataDictionaryOfListsTests.cs @@ -0,0 +1,81 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System.ClientModel.Primitives; +using System.ClientModel.Tests.Client; +using System.ClientModel.Tests.Client.Models.ResourceManager.Compute; +using System.Collections.Generic; +using System.IO; +using System.Text; +using System.Text.Json; +using NUnit.Framework; + +namespace System.ClientModel.Tests.ModelReaderWriterTests.Models +{ + public class AvailabilitySetDataDictionaryOfListsTests + { + private static readonly string s_payload = File.ReadAllText(TestData.GetLocation("AvailabilitySetData/AvailabilitySetDataDictionaryOfLists.json")).TrimEnd(); + private static readonly BinaryData s_data = new BinaryData(Encoding.UTF8.GetBytes(s_payload)); + private static readonly IDictionary> s_availabilitySets = ModelReaderWriter.Read>>(s_data)!; + private static readonly string s_collapsedPayload = GetCollapsedPayload(); + + private static string GetCollapsedPayload() + { + var jsonObject = JsonSerializer.Deserialize(s_payload); + return JsonSerializer.Serialize(jsonObject); + } + + [Test] + public void ReadDictionaryGeneric() + { + var asetDictionary = ModelReaderWriter.Read>>(s_data); + Assert.IsNotNull(asetDictionary); + + Assert.AreEqual(2, asetDictionary!.Count); + Assert.IsTrue(asetDictionary.ContainsKey("list1")); + var list1 = asetDictionary["list1"]; + Assert.IsNotNull(list1); + Assert.AreEqual(2, list1.Count); + Assert.IsTrue(list1[0].Name!.Equals("testAS-3375")); + Assert.IsTrue(list1[1].Name!.Equals("testAS-3376")); + Assert.IsTrue(asetDictionary.ContainsKey("list2")); + var list2 = asetDictionary["list2"]; + Assert.IsNotNull(list2); + Assert.AreEqual(2, list2.Count); + Assert.IsTrue(list2[0].Name!.Equals("testAS-3377")); + Assert.IsTrue(list2[1].Name!.Equals("testAS-3378")); + } + + [Test] + public void ReadDictionary() + { + var asetDictionary = ModelReaderWriter.Read(s_data, typeof(Dictionary>)); + Assert.IsNotNull(asetDictionary); + + Dictionary>? asetDictionary2 = asetDictionary! as Dictionary>; + Assert.IsNotNull(asetDictionary2); + + Assert.AreEqual(2, asetDictionary2!.Count); + Assert.IsTrue(asetDictionary2.ContainsKey("list1")); + var list1 = asetDictionary2["list1"]; + Assert.IsNotNull(list1); + Assert.AreEqual(2, list1.Count); + Assert.IsTrue(list1[0].Name!.Equals("testAS-3375")); + Assert.IsTrue(list1[1].Name!.Equals("testAS-3376")); + Assert.IsTrue(asetDictionary2.ContainsKey("list2")); + var list2 = asetDictionary2["list2"]; + Assert.IsNotNull(list2); + Assert.AreEqual(2, list2.Count); + Assert.IsTrue(list2[0].Name!.Equals("testAS-3377")); + Assert.IsTrue(list2[1].Name!.Equals("testAS-3378")); + } + + [Test] + public void WriteDictionary() + { + BinaryData data = ModelReaderWriter.Write(s_availabilitySets); + Assert.IsNotNull(data); + Assert.AreEqual(s_collapsedPayload, data.ToString()); + } + } +} diff --git a/sdk/core/System.ClientModel/tests/ModelReaderWriter/Models/AvailabilitySetDataDictionaryTests.cs b/sdk/core/System.ClientModel/tests/ModelReaderWriter/Models/AvailabilitySetDataDictionaryTests.cs new file mode 100644 index 000000000000..8e2060224611 --- /dev/null +++ b/sdk/core/System.ClientModel/tests/ModelReaderWriter/Models/AvailabilitySetDataDictionaryTests.cs @@ -0,0 +1,73 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System.ClientModel.Primitives; +using System.ClientModel.Tests.Client; +using System.ClientModel.Tests.Client.Models.ResourceManager.Compute; +using System.Collections.Generic; +using System.IO; +using System.Text; +using System.Text.Json; +using NUnit.Framework; + +namespace System.ClientModel.Tests.ModelReaderWriterTests.Models +{ + public class AvailabilitySetDataDictionaryTests + { + private static readonly string s_payload = File.ReadAllText(TestData.GetLocation("AvailabilitySetData/AvailabilitySetDataDictionary.json")).TrimEnd(); + private static readonly BinaryData s_data = new BinaryData(Encoding.UTF8.GetBytes(s_payload)); + private static readonly IDictionary s_availabilitySets = ModelReaderWriter.Read>(s_data)!; + private static readonly string s_collapsedPayload = GetCollapsedPayload(); + + private static string GetCollapsedPayload() + { + var jsonObject = JsonSerializer.Deserialize(s_payload); + return JsonSerializer.Serialize(jsonObject); + } + + [Test] + public void ReadDictionaryGeneric() + { + var asetDictionary = ModelReaderWriter.Read>(s_data); + Assert.IsNotNull(asetDictionary); + + Assert.AreEqual(2, asetDictionary!.Count); + Assert.IsTrue(asetDictionary.ContainsKey("testAS-3375")); + Assert.IsTrue(asetDictionary["testAS-3375"].Name!.Equals("testAS-3375")); + Assert.IsTrue(asetDictionary.ContainsKey("testAS-3376")); + Assert.IsTrue(asetDictionary["testAS-3376"].Name!.Equals("testAS-3376")); + } + + [Test] + public void ReadDictionary() + { + var asetDictionary = ModelReaderWriter.Read(s_data, typeof(Dictionary)); + Assert.IsNotNull(asetDictionary); + + Dictionary? asetDictionary2 = asetDictionary! as Dictionary; + Assert.IsNotNull(asetDictionary2); + + Assert.AreEqual(2, asetDictionary2!.Count); + Assert.IsTrue(asetDictionary2.ContainsKey("testAS-3375")); + Assert.IsTrue(asetDictionary2["testAS-3375"].Name!.Equals("testAS-3375")); + Assert.IsTrue(asetDictionary2.ContainsKey("testAS-3376")); + Assert.IsTrue(asetDictionary2["testAS-3376"].Name!.Equals("testAS-3376")); + } + + [Test] + public void WriteDictionary() + { + BinaryData data = ModelReaderWriter.Write(s_availabilitySets); + Assert.IsNotNull(data); + Assert.AreEqual(s_collapsedPayload, data.ToString()); + } + + [Test] + public void ReadListWhenDictionary() + { + var ex = Assert.Throws(() => ModelReaderWriter.Read>(s_data)); + Assert.IsNotNull(ex); + Assert.IsTrue(ex!.Message.Equals("Expected start of array.")); + } + } +} diff --git a/sdk/core/System.ClientModel/tests/ModelReaderWriter/Models/AvailabilitySetDataListOfDictionariesTests.cs b/sdk/core/System.ClientModel/tests/ModelReaderWriter/Models/AvailabilitySetDataListOfDictionariesTests.cs new file mode 100644 index 000000000000..928fc397bdf9 --- /dev/null +++ b/sdk/core/System.ClientModel/tests/ModelReaderWriter/Models/AvailabilitySetDataListOfDictionariesTests.cs @@ -0,0 +1,81 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System.ClientModel.Primitives; +using System.ClientModel.Tests.Client; +using System.ClientModel.Tests.Client.Models.ResourceManager.Compute; +using System.Collections.Generic; +using System.IO; +using System.Text; +using System.Text.Json; +using NUnit.Framework; + +namespace System.ClientModel.Tests.ModelReaderWriterTests.Models +{ + public class AvailabilitySetDataListOfDictionariesTests + { + private static readonly string s_payload = File.ReadAllText(TestData.GetLocation("AvailabilitySetData/AvailabilitySetDataListOfDictionaries.json")).TrimEnd(); + private static readonly BinaryData s_data = new BinaryData(Encoding.UTF8.GetBytes(s_payload)); + private static readonly IList> s_availabilitySets = ModelReaderWriter.Read>>(s_data)!; + private static readonly string s_collapsedPayload = GetCollapsedPayload(); + + private static string GetCollapsedPayload() + { + var jsonObject = JsonSerializer.Deserialize(s_payload); + return JsonSerializer.Serialize(jsonObject); + } + + [Test] + public void ReadDictionaryGeneric() + { + var asetList = ModelReaderWriter.Read>>(s_data); + Assert.IsNotNull(asetList); + + Assert.AreEqual(2, asetList!.Count); + var dictionary1 = asetList[0]; + Assert.AreEqual(2, dictionary1.Count); + Assert.IsTrue(dictionary1.ContainsKey("testAS-3375")); + Assert.IsTrue(dictionary1["testAS-3375"].Name!.Equals("testAS-3375")); + Assert.IsTrue(dictionary1.ContainsKey("testAS-3376")); + Assert.IsTrue(dictionary1["testAS-3376"].Name!.Equals("testAS-3376")); + var dictionary2 = asetList[1]; + Assert.AreEqual(2, dictionary2.Count); + Assert.IsTrue(dictionary2.ContainsKey("testAS-3377")); + Assert.IsTrue(dictionary2["testAS-3377"].Name!.Equals("testAS-3377")); + Assert.IsTrue(dictionary2.ContainsKey("testAS-3378")); + Assert.IsTrue(dictionary2["testAS-3378"].Name!.Equals("testAS-3378")); + } + + [Test] + public void ReadDictionary() + { + var asetList = ModelReaderWriter.Read(s_data, typeof(List>)); + Assert.IsNotNull(asetList); + + List>? asetList2 = asetList! as List>; + Assert.IsNotNull(asetList2); + + Assert.AreEqual(2, asetList2!.Count); + var dictionary1 = asetList2[0]; + Assert.AreEqual(2, dictionary1.Count); + Assert.IsTrue(dictionary1.ContainsKey("testAS-3375")); + Assert.IsTrue(dictionary1["testAS-3375"].Name!.Equals("testAS-3375")); + Assert.IsTrue(dictionary1.ContainsKey("testAS-3376")); + Assert.IsTrue(dictionary1["testAS-3376"].Name!.Equals("testAS-3376")); + var dictionary2 = asetList2[1]; + Assert.AreEqual(2, dictionary2.Count); + Assert.IsTrue(dictionary2.ContainsKey("testAS-3377")); + Assert.IsTrue(dictionary2["testAS-3377"].Name!.Equals("testAS-3377")); + Assert.IsTrue(dictionary2.ContainsKey("testAS-3378")); + Assert.IsTrue(dictionary2["testAS-3378"].Name!.Equals("testAS-3378")); + } + + [Test] + public void WriteDictionary() + { + BinaryData data = ModelReaderWriter.Write(s_availabilitySets); + Assert.IsNotNull(data); + Assert.AreEqual(s_collapsedPayload, data.ToString()); + } + } +} diff --git a/sdk/core/System.ClientModel/tests/ModelReaderWriter/Models/AvailabilitySetDataListOfListsTests.cs b/sdk/core/System.ClientModel/tests/ModelReaderWriter/Models/AvailabilitySetDataListOfListsTests.cs new file mode 100644 index 000000000000..19a69dbaebbf --- /dev/null +++ b/sdk/core/System.ClientModel/tests/ModelReaderWriter/Models/AvailabilitySetDataListOfListsTests.cs @@ -0,0 +1,426 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System.ClientModel.Primitives; +using System.ClientModel.Tests.Client; +using System.ClientModel.Tests.Client.Models.ResourceManager.Compute; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.IO; +using System.Text; +using System.Text.Json; +using NUnit.Framework; + +namespace System.ClientModel.Tests.ModelReaderWriterTests.Models +{ + public class AvailabilitySetDataListOfListsTests + { + private static readonly string s_payload = File.ReadAllText(TestData.GetLocation("AvailabilitySetData/AvailabilitySetDataListOfLists.json")).TrimEnd(); + private static readonly BinaryData s_data = new BinaryData(Encoding.UTF8.GetBytes(s_payload)); + private static readonly string s_collapsedPayload = GetCollapsedPayload(); + + private static readonly HashSet s_supportedCollectionTypes = + [ + typeof(List<>), + typeof(Dictionary<,>) + ]; + + private List>? _availabilitySets; + + [OneTimeSetUp] + public void OneTimeSetUp() + { + _availabilitySets = ModelReaderWriter.Read>>(s_data); + } + + private static string GetCollapsedPayload() + { + var jsonObject = JsonSerializer.Deserialize(s_payload); + return JsonSerializer.Serialize(jsonObject); + } + + private class AvailabilitySetDataComparer : IComparer + { + public int Compare(AvailabilitySetData? x, AvailabilitySetData? y) + { + if (x == null && y == null) + { + return 0; + } + else if (x == null) + { + return -1; + } + else if (y == null) + { + return 1; + } + else + { + return x.Id!.CompareTo(y.Id); + } + } + } + + [Test] + public void ReadListGeneric() + { + var asetList = ModelReaderWriter.Read>>(s_data); + Assert.IsNotNull(asetList); + + Assert.AreEqual(2, asetList!.Count); + + List asetList2 = asetList[0]; + + Assert.AreEqual(2, asetList2.Count); + Assert.IsTrue(asetList2[0].Name!.Equals("testAS-3375")); + Assert.IsTrue(asetList2[1].Name!.Equals("testAS-3376")); + + List asetList3 = asetList[1]; + + Assert.AreEqual(2, asetList3.Count); + Assert.IsTrue(asetList3[0].Name!.Equals("testAS-3377")); + Assert.IsTrue(asetList3[1].Name!.Equals("testAS-3378")); + } + + [Test] + public void ReadList() + { + var asetList = ModelReaderWriter.Read(s_data, typeof(List>)); + Assert.IsNotNull(asetList); + + List>? asetList2 = asetList! as List>; + Assert.IsNotNull(asetList2); + + Assert.AreEqual(2, asetList2!.Count); + + List asetList3 = asetList2[0]; + + Assert.AreEqual(2, asetList3.Count); + Assert.IsTrue(asetList3[0].Name!.Equals("testAS-3375")); + Assert.IsTrue(asetList3[1].Name!.Equals("testAS-3376")); + + List asetList4 = asetList2[1]; + + Assert.AreEqual(2, asetList4.Count); + Assert.IsTrue(asetList4[0].Name!.Equals("testAS-3377")); + Assert.IsTrue(asetList4[1].Name!.Equals("testAS-3378")); + } + + [Test] + public void ReadArray() + { + var ex = Assert.Throws(() => ModelReaderWriter.Read(s_data, typeof(AvailabilitySetData[][]))); + Assert.IsNotNull(ex); + Assert.IsTrue(ex!.Message.StartsWith("Arrays are not supported. Use List<> instead.")); + } + + [Test] + public void ReadArrayGeneric() + { + var ex = Assert.Throws(() => ModelReaderWriter.Read(s_data)); + Assert.IsNotNull(ex); + Assert.IsTrue(ex!.Message.StartsWith("Arrays are not supported. Use List<> instead.")); + } + + [Test] + public void ValidateTypeCheckingListOfList() + { + ValidateTypeChecking(new List>(_availabilitySets!)); + } + + [Test] + public void ValidateTypeCheckingMultiDimensionalArray() + { + ValidateTypeChecking(new AvailabilitySetData[,] { { _availabilitySets![0][0], _availabilitySets[0][1] }, { _availabilitySets[1][0], _availabilitySets[1][1] } }); + } + + [Test] + public void ValidateTypeCheckingJaggedArray() + { + ValidateTypeChecking(new AvailabilitySetData[][] { new AvailabilitySetData[] { _availabilitySets![0][0], _availabilitySets[0][1] }, new AvailabilitySetData[] { _availabilitySets[1][0], _availabilitySets[1][1] } }); + } + + [Test] + public void ValidateTypeCheckingListOfArray() + { + ValidateTypeChecking(new List() { new AvailabilitySetData[] { _availabilitySets![0][0], _availabilitySets[0][1] }, new AvailabilitySetData[] { _availabilitySets[1][0], _availabilitySets[1][1] } }); + } + + [Test] + public void ValidateTypeCheckingArrayOfList() + { + ValidateTypeChecking(new List[] { _availabilitySets![0], _availabilitySets[1] }); + } + + [Test] + public void ValidateTypeCheckingCollectionOfCollection() + { + ValidateTypeChecking(new Collection>() { new(_availabilitySets![0]), new(_availabilitySets[1]) }); + } + + [Test] + public void ValidateTypeCheckingCollectionOfList() + { + ValidateTypeChecking(new Collection>() { new(_availabilitySets![0]), new(_availabilitySets[1]) }); + } + + [Test] + public void ValidateTypeCheckingListOfCollection() + { + ValidateTypeChecking(new List>() { new(_availabilitySets![0]), new(_availabilitySets[1]) }); + } + + [Test] + public void ValidateTypeCheckingObservableOfObservable() + { + ValidateTypeChecking(new ObservableCollection>() { new(_availabilitySets![0]), new(_availabilitySets[1]) }); + } + + [Test] + public void ValidateTypeCheckingObservableOfList() + { + ValidateTypeChecking(new ObservableCollection>() { new(_availabilitySets![0]), new(_availabilitySets[1]) }); + } + + [Test] + public void ValidateTypeCheckingHashOfHash() + { + ValidateTypeChecking(new HashSet>() { new(_availabilitySets![0]), new(_availabilitySets[1]) }); + } + + [Test] + public void ValidateTypeCheckingHashOfList() + { + ValidateTypeChecking(new HashSet>() { new(_availabilitySets![0]), new(_availabilitySets[1]) }); + } + + [Test] + public void ValidateTypeCheckingQueueOfQueue() + { + ValidateTypeChecking(new Queue>([new Queue(_availabilitySets![0]), new Queue(_availabilitySets[1])])); + } + + [Test] + public void ValidateTypeCheckingQueueOfList() + { + ValidateTypeChecking(new Queue>([[.. _availabilitySets![0]], [.. _availabilitySets[1]]])); + } + + [Test] + public void ValidateTypeCheckingStackOfStack() + { + ValidateTypeChecking(new Stack>([new Stack([_availabilitySets![1][1], _availabilitySets[1][0]]), new Stack([_availabilitySets[0][1], _availabilitySets[0][0]])])); + } + + [Test] + public void ValidateTypeCheckingStackOfList() + { + ValidateTypeChecking(new Stack>([[.. _availabilitySets![1]], [.. _availabilitySets[0]]])); + } + + [Test] + public void ValidateTypeCheckingLinkedOfLinked() + { + ValidateTypeChecking(new LinkedList>([new LinkedList(_availabilitySets![0]), new LinkedList(_availabilitySets[1])])); + } + + [Test] + public void ValidateTypeCheckingLinkedOfList() + { + ValidateTypeChecking(new LinkedList>([[.. _availabilitySets![0]], [.. _availabilitySets[1]]])); + } + + //[TestCaseSource(nameof(ListOfLists))] + private void ValidateTypeChecking(object collection) + { + var type = collection.GetType(); + var genericType = type.IsGenericType ? type.GetGenericTypeDefinition() : null; + if (genericType is not null && s_supportedCollectionTypes.Contains(genericType)) + { + var elementType = type.GetGenericArguments()[0]; + Assert.IsNotNull(elementType); + if (elementType.IsArray) + { + var ex = Assert.Throws(() => ModelReaderWriter.Read(s_data, type)); + Assert.IsNotNull(ex); + Assert.IsTrue(ex!.Message.StartsWith("Arrays are not supported. Use List<> instead.")); + } + else + { + var elementGenericType = elementType.IsGenericType ? elementType.GetGenericTypeDefinition() : null; + if (elementGenericType is not null && s_supportedCollectionTypes.Contains(elementGenericType)) + { + Assert.DoesNotThrow(() => ModelReaderWriter.Read(s_data, type)); + } + else + { + var ex = Assert.Throws(() => ModelReaderWriter.Read(s_data, type)); + Assert.IsNotNull(ex); + Assert.IsTrue(ex!.Message.StartsWith("Collection Type ")); + } + } + } + else if (type.IsArray) + { + var ex = Assert.Throws(() => ModelReaderWriter.Read(s_data, type)); + Assert.IsNotNull(ex); + Assert.IsTrue(ex!.Message.StartsWith("Arrays are not supported. Use List<> instead.")); + } + else if (genericType is not null && !s_supportedCollectionTypes.Contains(genericType)) + { + var ex = Assert.Throws(() => ModelReaderWriter.Read(s_data, type)); + Assert.IsNotNull(ex); + Assert.IsTrue(ex!.Message.Contains("Collection Type ")); + } + else + { + //should never get here + Assert.Fail("Unexpected condition"); + } + } + + [Test] + public void WriteListOfList() + { + WriteCollection(new List>(_availabilitySets!)); + } + + [Test] + public void WriteMultiDimensionalArray() + { + WriteCollection(new AvailabilitySetData[,] { { _availabilitySets![0][0], _availabilitySets[0][1] }, { _availabilitySets[1][0], _availabilitySets[1][1] } }); + } + + [Test] + public void WriteJaggedArray() + { + WriteCollection(new AvailabilitySetData[][] { new AvailabilitySetData[] { _availabilitySets![0][0], _availabilitySets[0][1] }, new AvailabilitySetData[] { _availabilitySets[1][0], _availabilitySets[1][1] } }); + } + + [Test] + public void WriteListOfArray() + { + WriteCollection(new List() { new AvailabilitySetData[] { _availabilitySets![0][0], _availabilitySets[0][1] }, new AvailabilitySetData[] { _availabilitySets[1][0], _availabilitySets[1][1] } }); + } + + [Test] + public void WriteArrayOfList() + { + WriteCollection(new List[] { _availabilitySets![0], _availabilitySets[1] }); + } + + [Test] + public void WriteCollectionOfCollection() + { + WriteCollection(new Collection>() { new(_availabilitySets![0]), new(_availabilitySets[1]) }); + } + + [Test] + public void WriteCollectionOfList() + { + WriteCollection(new Collection>() { new(_availabilitySets![0]), new(_availabilitySets[1]) }); + } + + [Test] + public void WriteListOfCollection() + { + WriteCollection(new List>() { new(_availabilitySets![0]), new(_availabilitySets[1]) }); + } + + [Test] + public void WriteObservableOfObservable() + { + WriteCollection(new ObservableCollection>() { new(_availabilitySets![0]), new(_availabilitySets[1]) }); + } + + [Test] + public void WriteObservableOfList() + { + WriteCollection(new ObservableCollection>() { new(_availabilitySets![0]), new(_availabilitySets[1]) }); + } + + [Test] + public void WriteHashOfHash() + { + WriteCollection(new HashSet>() { new(_availabilitySets![0]), new(_availabilitySets[1]) }); + } + + [Test] + public void WriteHashOfList() + { + WriteCollection(new HashSet>() { new(_availabilitySets![0]), new(_availabilitySets[1]) }); + } + + [Test] + public void WriteQueueOfQueue() + { + WriteCollection(new Queue>([new Queue(_availabilitySets![0]), new Queue(_availabilitySets[1])])); + } + + [Test] + public void WriteQueueOfList() + { + WriteCollection(new Queue>([[.. _availabilitySets![0]], [.. _availabilitySets[1]]])); + } + + [Test] + public void WriteStackOfStack() + { + WriteCollection(new Stack>([new Stack([_availabilitySets![1][1], _availabilitySets[1][0]]), new Stack([_availabilitySets[0][1], _availabilitySets[0][0]])])); + } + + [Test] + public void WriteStackOfList() + { + WriteCollection(new Stack>([[.. _availabilitySets![1]], [.. _availabilitySets[0]]])); + } + + [Test] + public void WriteLinkedOfLinked() + { + WriteCollection(new LinkedList>([new LinkedList(_availabilitySets![0]), new LinkedList(_availabilitySets[1])])); + } + + [Test] + public void WriteLinkedOfList() + { + WriteCollection(new LinkedList>([[.. _availabilitySets![0]], [.. _availabilitySets[1]]])); + } + + private void WriteCollection(object collection) + { + BinaryData data = ModelReaderWriter.Write(collection); + Assert.IsNotNull(data); + Assert.AreEqual(s_collapsedPayload, data.ToString()); + } + + [Test] + public void ReadBadAbstractType() + { + var ex = Assert.Throws(() => ModelReaderWriter.Read(s_data, typeof(Stream))); + Assert.IsNotNull(ex); + Assert.IsTrue(ex!.Message.Contains("must be decorated with PersistableModelProxyAttribute")); + } + + [Test] + public void ReadBadValueType() + { + var ex = Assert.Throws(() => ModelReaderWriter.Read(s_data, typeof(int))); + Assert.IsNotNull(ex); + Assert.IsTrue(ex!.Message.Contains("does not implement IPersistableModel")); + } + + [Test] + public void ReadNoPublicCtorType() + { +#if NET5_0_OR_GREATER + var ex = Assert.Throws(() => ModelReaderWriter.Read(s_data, typeof(FileStream))); + Assert.IsNotNull(ex); +#else + var ex = Assert.Throws(() => ModelReaderWriter.Read(s_data, typeof(FileStream))); + Assert.IsNotNull(ex); +#endif + } + } +} diff --git a/sdk/core/System.ClientModel/tests/ModelReaderWriter/Models/AvailabilitySetDataListTests.cs b/sdk/core/System.ClientModel/tests/ModelReaderWriter/Models/AvailabilitySetDataListTests.cs new file mode 100644 index 000000000000..3b8333d032ba --- /dev/null +++ b/sdk/core/System.ClientModel/tests/ModelReaderWriter/Models/AvailabilitySetDataListTests.cs @@ -0,0 +1,118 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System.ClientModel.Primitives; +using System.ClientModel.Tests.Client; +using System.ClientModel.Tests.Client.Models.ResourceManager.Compute; +using System.Collections; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.IO; +using System.Linq; +using System.Text; +using System.Text.Json; +using NUnit.Framework; + +namespace System.ClientModel.Tests.ModelReaderWriterTests.Models +{ + public class AvailabilitySetDataListTests + { + private static readonly string s_payload = File.ReadAllText(TestData.GetLocation("AvailabilitySetData/AvailabilitySetDataList.json")).TrimEnd(); + private static readonly BinaryData s_data = new BinaryData(Encoding.UTF8.GetBytes(s_payload)); + private static readonly IList s_availabilitySets = ModelReaderWriter.Read>(s_data)!; + private static readonly string s_collapsedPayload = GetCollapsedPayload(); + + private static string GetCollapsedPayload() + { + var jsonObject = JsonSerializer.Deserialize(s_payload); + return JsonSerializer.Serialize(jsonObject); + } + + private class AvailabilitySetDataComparer : IComparer + { + public int Compare(AvailabilitySetData? x, AvailabilitySetData? y) + { + if (x == null && y == null) + { + return 0; + } + else if (x == null) + { + return -1; + } + else if (y == null) + { + return 1; + } + else + { + return x.Id!.CompareTo(y.Id); + } + } + } + + private static readonly List s_collections = + [ + new List(s_availabilitySets), + new AvailabilitySetData[] { s_availabilitySets[0], s_availabilitySets[1] }, + new Collection (s_availabilitySets), + new ObservableCollection (s_availabilitySets), + new HashSet (s_availabilitySets), + new Queue (s_availabilitySets), + new Stack (s_availabilitySets.Reverse()), //stack has the order flipped + new LinkedList (s_availabilitySets), + new SortedSet (s_availabilitySets, new AvailabilitySetDataComparer()), + new ArrayList (new Collection(s_availabilitySets)), + ]; + + [Test] + public void ReadListGeneric() + { + var asetList = ModelReaderWriter.Read>(s_data); + Assert.IsNotNull(asetList); + + Assert.AreEqual(2, asetList!.Count); + Assert.IsTrue(asetList[0].Name!.Equals("testAS-3375")); + Assert.IsTrue(asetList[1].Name!.Equals("testAS-3376")); + } + + [Test] + public void ReadList() + { + var asetList = ModelReaderWriter.Read(s_data, typeof(List)); + Assert.IsNotNull(asetList); + + List? asetList2 = asetList! as List; + Assert.IsNotNull(asetList2); + + Assert.AreEqual(2, asetList2!.Count); + Assert.IsTrue(asetList2[0].Name!.Equals("testAS-3375")); + Assert.IsTrue(asetList2[1].Name!.Equals("testAS-3376")); + } + + [TestCaseSource(nameof(s_collections))] + public void WriteCollection(object collection) + { + BinaryData data = ModelReaderWriter.Write(collection); + Assert.IsNotNull(data); + Assert.AreEqual(s_collapsedPayload, data.ToString()); + } + + [Test] + public void ReadUnsupportedCollectionGeneric() + { + var ex = Assert.Throws(() => ModelReaderWriter.Read>(s_data)); + Assert.IsNotNull(ex); + Assert.IsTrue(ex!.Message.Contains("Collection Type ")); + Assert.AreEqual("T", ex.ParamName); + } + + [Test] + public void ReadDictionaryWhenList() + { + var ex = Assert.Throws(() => ModelReaderWriter.Read>(s_data)); + Assert.IsNotNull(ex); + Assert.IsTrue(ex!.Message.Equals("Expected start of dictionary.")); + } + } +} diff --git a/sdk/core/System.ClientModel/tests/System.ClientModel.Tests.csproj b/sdk/core/System.ClientModel/tests/System.ClientModel.Tests.csproj index 799857a08a18..09cc72ad277b 100644 --- a/sdk/core/System.ClientModel/tests/System.ClientModel.Tests.csproj +++ b/sdk/core/System.ClientModel/tests/System.ClientModel.Tests.csproj @@ -16,6 +16,7 @@ + diff --git a/sdk/core/System.ClientModel/tests/client/System.ClientModel.Tests.Client.csproj b/sdk/core/System.ClientModel/tests/client/System.ClientModel.Tests.Client.csproj index 0a74ca135ec5..30b23ef14e79 100644 --- a/sdk/core/System.ClientModel/tests/client/System.ClientModel.Tests.Client.csproj +++ b/sdk/core/System.ClientModel/tests/client/System.ClientModel.Tests.Client.csproj @@ -20,16 +20,7 @@ - - Always - - - Always - - - Always - - + Always diff --git a/sdk/core/System.ClientModel/tests/client/TestData/AvailabilitySetData/AvailabilitySetDataDictionary.json b/sdk/core/System.ClientModel/tests/client/TestData/AvailabilitySetData/AvailabilitySetDataDictionary.json new file mode 100644 index 000000000000..3e22a709def2 --- /dev/null +++ b/sdk/core/System.ClientModel/tests/client/TestData/AvailabilitySetData/AvailabilitySetDataDictionary.json @@ -0,0 +1,34 @@ +{ + "testAS-3375": { + "name": "testAS-3375", + "id": "/subscriptions/e37510d7-33b6-4676-886f-ee75bcc01871/resourceGroups/testRG-6497/providers/Microsoft.Compute/availabilitySets/testAS-3375", + "type": "Microsoft.Compute/availabilitySets", + "sku": { + "name": "Classic" + }, + "tags": { + "key": "value" + }, + "location": "eastus", + "properties": { + "platformUpdateDomainCount": 5, + "platformFaultDomainCount": 3 + } + }, + "testAS-3376": { + "name": "testAS-3376", + "id": "/subscriptions/e37510d7-33b6-4676-886f-ee75bcc01871/resourceGroups/testRG-6497/providers/Microsoft.Compute/availabilitySets/testAS-3376", + "type": "Microsoft.Compute/availabilitySets", + "sku": { + "name": "Classic" + }, + "tags": { + "key": "value" + }, + "location": "eastus", + "properties": { + "platformUpdateDomainCount": 5, + "platformFaultDomainCount": 3 + } + } +} diff --git a/sdk/core/System.ClientModel/tests/client/TestData/AvailabilitySetData/AvailabilitySetDataDictionaryOfDictionaries.json b/sdk/core/System.ClientModel/tests/client/TestData/AvailabilitySetData/AvailabilitySetDataDictionaryOfDictionaries.json new file mode 100644 index 000000000000..0ab28d2265f8 --- /dev/null +++ b/sdk/core/System.ClientModel/tests/client/TestData/AvailabilitySetData/AvailabilitySetDataDictionaryOfDictionaries.json @@ -0,0 +1,70 @@ +{ + "dictionary1": { + "testAS-3375": { + "name": "testAS-3375", + "id": "/subscriptions/e37510d7-33b6-4676-886f-ee75bcc01871/resourceGroups/testRG-6497/providers/Microsoft.Compute/availabilitySets/testAS-3375", + "type": "Microsoft.Compute/availabilitySets", + "sku": { + "name": "Classic" + }, + "tags": { + "key": "value" + }, + "location": "eastus", + "properties": { + "platformUpdateDomainCount": 5, + "platformFaultDomainCount": 3 + } + }, + "testAS-3376": { + "name": "testAS-3376", + "id": "/subscriptions/e37510d7-33b6-4676-886f-ee75bcc01871/resourceGroups/testRG-6497/providers/Microsoft.Compute/availabilitySets/testAS-3376", + "type": "Microsoft.Compute/availabilitySets", + "sku": { + "name": "Classic" + }, + "tags": { + "key": "value" + }, + "location": "eastus", + "properties": { + "platformUpdateDomainCount": 5, + "platformFaultDomainCount": 3 + } + } + }, + "dictionary2": { + "testAS-3377": { + "name": "testAS-3377", + "id": "/subscriptions/e37510d7-33b6-4676-886f-ee75bcc01871/resourceGroups/testRG-6497/providers/Microsoft.Compute/availabilitySets/testAS-3377", + "type": "Microsoft.Compute/availabilitySets", + "sku": { + "name": "Classic" + }, + "tags": { + "key": "value" + }, + "location": "eastus", + "properties": { + "platformUpdateDomainCount": 5, + "platformFaultDomainCount": 3 + } + }, + "testAS-3378": { + "name": "testAS-3378", + "id": "/subscriptions/e37510d7-33b6-4676-886f-ee75bcc01871/resourceGroups/testRG-6497/providers/Microsoft.Compute/availabilitySets/testAS-3378", + "type": "Microsoft.Compute/availabilitySets", + "sku": { + "name": "Classic" + }, + "tags": { + "key": "value" + }, + "location": "eastus", + "properties": { + "platformUpdateDomainCount": 5, + "platformFaultDomainCount": 3 + } + } + } +} diff --git a/sdk/core/System.ClientModel/tests/client/TestData/AvailabilitySetData/AvailabilitySetDataDictionaryOfLists.json b/sdk/core/System.ClientModel/tests/client/TestData/AvailabilitySetData/AvailabilitySetDataDictionaryOfLists.json new file mode 100644 index 000000000000..68b5ad12bfd8 --- /dev/null +++ b/sdk/core/System.ClientModel/tests/client/TestData/AvailabilitySetData/AvailabilitySetDataDictionaryOfLists.json @@ -0,0 +1,70 @@ +{ + "list1": [ + { + "name": "testAS-3375", + "id": "/subscriptions/e37510d7-33b6-4676-886f-ee75bcc01871/resourceGroups/testRG-6497/providers/Microsoft.Compute/availabilitySets/testAS-3375", + "type": "Microsoft.Compute/availabilitySets", + "sku": { + "name": "Classic" + }, + "tags": { + "key": "value" + }, + "location": "eastus", + "properties": { + "platformUpdateDomainCount": 5, + "platformFaultDomainCount": 3 + } + }, + { + "name": "testAS-3376", + "id": "/subscriptions/e37510d7-33b6-4676-886f-ee75bcc01871/resourceGroups/testRG-6497/providers/Microsoft.Compute/availabilitySets/testAS-3376", + "type": "Microsoft.Compute/availabilitySets", + "sku": { + "name": "Classic" + }, + "tags": { + "key": "value" + }, + "location": "eastus", + "properties": { + "platformUpdateDomainCount": 5, + "platformFaultDomainCount": 3 + } + } + ], + "list2": [ + { + "name": "testAS-3377", + "id": "/subscriptions/e37510d7-33b6-4676-886f-ee75bcc01871/resourceGroups/testRG-6497/providers/Microsoft.Compute/availabilitySets/testAS-3377", + "type": "Microsoft.Compute/availabilitySets", + "sku": { + "name": "Classic" + }, + "tags": { + "key": "value" + }, + "location": "eastus", + "properties": { + "platformUpdateDomainCount": 5, + "platformFaultDomainCount": 3 + } + }, + { + "name": "testAS-3378", + "id": "/subscriptions/e37510d7-33b6-4676-886f-ee75bcc01871/resourceGroups/testRG-6497/providers/Microsoft.Compute/availabilitySets/testAS-3378", + "type": "Microsoft.Compute/availabilitySets", + "sku": { + "name": "Classic" + }, + "tags": { + "key": "value" + }, + "location": "eastus", + "properties": { + "platformUpdateDomainCount": 5, + "platformFaultDomainCount": 3 + } + } + ] +} diff --git a/sdk/core/System.ClientModel/tests/client/TestData/AvailabilitySetData/AvailabilitySetDataList.json b/sdk/core/System.ClientModel/tests/client/TestData/AvailabilitySetData/AvailabilitySetDataList.json new file mode 100644 index 000000000000..35bf1c5addf1 --- /dev/null +++ b/sdk/core/System.ClientModel/tests/client/TestData/AvailabilitySetData/AvailabilitySetDataList.json @@ -0,0 +1,34 @@ +[ + { + "name": "testAS-3375", + "id": "/subscriptions/e37510d7-33b6-4676-886f-ee75bcc01871/resourceGroups/testRG-6497/providers/Microsoft.Compute/availabilitySets/testAS-3375", + "type": "Microsoft.Compute/availabilitySets", + "sku": { + "name": "Classic" + }, + "tags": { + "key": "value" + }, + "location": "eastus", + "properties": { + "platformUpdateDomainCount": 5, + "platformFaultDomainCount": 3 + } + }, + { + "name": "testAS-3376", + "id": "/subscriptions/e37510d7-33b6-4676-886f-ee75bcc01871/resourceGroups/testRG-6497/providers/Microsoft.Compute/availabilitySets/testAS-3376", + "type": "Microsoft.Compute/availabilitySets", + "sku": { + "name": "Classic" + }, + "tags": { + "key": "value" + }, + "location": "eastus", + "properties": { + "platformUpdateDomainCount": 5, + "platformFaultDomainCount": 3 + } + } +] diff --git a/sdk/core/System.ClientModel/tests/client/TestData/AvailabilitySetData/AvailabilitySetDataListOfDictionaries.json b/sdk/core/System.ClientModel/tests/client/TestData/AvailabilitySetData/AvailabilitySetDataListOfDictionaries.json new file mode 100644 index 000000000000..29589d9f8c9e --- /dev/null +++ b/sdk/core/System.ClientModel/tests/client/TestData/AvailabilitySetData/AvailabilitySetDataListOfDictionaries.json @@ -0,0 +1,70 @@ +[ + { + "testAS-3375": { + "name": "testAS-3375", + "id": "/subscriptions/e37510d7-33b6-4676-886f-ee75bcc01871/resourceGroups/testRG-6497/providers/Microsoft.Compute/availabilitySets/testAS-3375", + "type": "Microsoft.Compute/availabilitySets", + "sku": { + "name": "Classic" + }, + "tags": { + "key": "value" + }, + "location": "eastus", + "properties": { + "platformUpdateDomainCount": 5, + "platformFaultDomainCount": 3 + } + }, + "testAS-3376": { + "name": "testAS-3376", + "id": "/subscriptions/e37510d7-33b6-4676-886f-ee75bcc01871/resourceGroups/testRG-6497/providers/Microsoft.Compute/availabilitySets/testAS-3376", + "type": "Microsoft.Compute/availabilitySets", + "sku": { + "name": "Classic" + }, + "tags": { + "key": "value" + }, + "location": "eastus", + "properties": { + "platformUpdateDomainCount": 5, + "platformFaultDomainCount": 3 + } + } + }, + { + "testAS-3377": { + "name": "testAS-3377", + "id": "/subscriptions/e37510d7-33b6-4676-886f-ee75bcc01871/resourceGroups/testRG-6497/providers/Microsoft.Compute/availabilitySets/testAS-3377", + "type": "Microsoft.Compute/availabilitySets", + "sku": { + "name": "Classic" + }, + "tags": { + "key": "value" + }, + "location": "eastus", + "properties": { + "platformUpdateDomainCount": 5, + "platformFaultDomainCount": 3 + } + }, + "testAS-3378": { + "name": "testAS-3378", + "id": "/subscriptions/e37510d7-33b6-4676-886f-ee75bcc01871/resourceGroups/testRG-6497/providers/Microsoft.Compute/availabilitySets/testAS-3378", + "type": "Microsoft.Compute/availabilitySets", + "sku": { + "name": "Classic" + }, + "tags": { + "key": "value" + }, + "location": "eastus", + "properties": { + "platformUpdateDomainCount": 5, + "platformFaultDomainCount": 3 + } + } + } +] diff --git a/sdk/core/System.ClientModel/tests/client/TestData/AvailabilitySetData/AvailabilitySetDataListOfLists.json b/sdk/core/System.ClientModel/tests/client/TestData/AvailabilitySetData/AvailabilitySetDataListOfLists.json new file mode 100644 index 000000000000..7b8728cdea7f --- /dev/null +++ b/sdk/core/System.ClientModel/tests/client/TestData/AvailabilitySetData/AvailabilitySetDataListOfLists.json @@ -0,0 +1,70 @@ +[ + [ + { + "name": "testAS-3375", + "id": "/subscriptions/e37510d7-33b6-4676-886f-ee75bcc01871/resourceGroups/testRG-6497/providers/Microsoft.Compute/availabilitySets/testAS-3375", + "type": "Microsoft.Compute/availabilitySets", + "sku": { + "name": "Classic" + }, + "tags": { + "key": "value" + }, + "location": "eastus", + "properties": { + "platformUpdateDomainCount": 5, + "platformFaultDomainCount": 3 + } + }, + { + "name": "testAS-3376", + "id": "/subscriptions/e37510d7-33b6-4676-886f-ee75bcc01871/resourceGroups/testRG-6497/providers/Microsoft.Compute/availabilitySets/testAS-3376", + "type": "Microsoft.Compute/availabilitySets", + "sku": { + "name": "Classic" + }, + "tags": { + "key": "value" + }, + "location": "eastus", + "properties": { + "platformUpdateDomainCount": 5, + "platformFaultDomainCount": 3 + } + } + ], + [ + { + "name": "testAS-3377", + "id": "/subscriptions/e37510d7-33b6-4676-886f-ee75bcc01871/resourceGroups/testRG-6497/providers/Microsoft.Compute/availabilitySets/testAS-3377", + "type": "Microsoft.Compute/availabilitySets", + "sku": { + "name": "Classic" + }, + "tags": { + "key": "value" + }, + "location": "eastus", + "properties": { + "platformUpdateDomainCount": 5, + "platformFaultDomainCount": 3 + } + }, + { + "name": "testAS-3378", + "id": "/subscriptions/e37510d7-33b6-4676-886f-ee75bcc01871/resourceGroups/testRG-6497/providers/Microsoft.Compute/availabilitySets/testAS-3378", + "type": "Microsoft.Compute/availabilitySets", + "sku": { + "name": "Classic" + }, + "tags": { + "key": "value" + }, + "location": "eastus", + "properties": { + "platformUpdateDomainCount": 5, + "platformFaultDomainCount": 3 + } + } + ] +]