Add custom enum converter test for having flags as array (dotnet/corefx#40678)
authorSteve Harter <steveharter@users.noreply.github.com>
Thu, 29 Aug 2019 20:02:09 +0000 (15:02 -0500)
committerGitHub <noreply@github.com>
Thu, 29 Aug 2019 20:02:09 +0000 (15:02 -0500)
Commit migrated from https://github.com/dotnet/corefx/commit/e3644c538ab5dad6c19c6a7c975df0b160823875

src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests.Enum.cs

index acd99e6..36e2149 100644 (file)
@@ -2,6 +2,8 @@
 // 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.Generic;
+using System.Reflection;
 using Xunit;
 
 namespace System.Text.Json.Serialization.Tests
@@ -112,5 +114,168 @@ namespace System.Text.Json.Serialization.Tests
                 Assert.Equal(@"""?""", JsonSerializer.Serialize(value, options));
             }
         }
+
+        // A custom enum converter that uses an array for containing bit flags.
+        private sealed class JsonStringEnumArrayConverter : JsonConverterFactory
+        {
+            public JsonStringEnumArrayConverter() { }
+
+            public override bool CanConvert(Type typeToConvert)
+            {
+                return typeToConvert.IsEnum;
+            }
+
+            public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options)
+            {
+                JsonConverter converter = (JsonConverter)Activator.CreateInstance(
+                    typeof(JsonConverterEnumArray<>).MakeGenericType(typeToConvert),
+                    BindingFlags.Instance | BindingFlags.Public,
+                    binder: null,
+                    args: null,
+                    culture: null);
+
+                return converter;
+            }
+        }
+
+        internal class JsonConverterEnumArray<T> : JsonConverter<T>
+            where T : struct, Enum
+        {
+            public override bool CanConvert(Type type)
+            {
+                return type.IsEnum;
+            }
+
+            public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+            {
+                if (reader.TokenType != JsonTokenType.StartArray)
+                {
+                    throw new JsonException();
+                }
+
+                string enumString = default;
+
+                bool first = true;
+                while (true)
+                {
+                    reader.Read();
+
+                    if (reader.TokenType == JsonTokenType.EndArray)
+                    {
+                        break;
+                    }
+
+                    if (reader.TokenType != JsonTokenType.String)
+                    {
+                        throw new JsonException();
+                    }
+
+                    string enumValue = reader.GetString();
+                    if (first)
+                    {
+                        first = false;
+                    }
+                    else
+                    {
+                        enumString += ",";
+                    }
+
+                    enumString += enumValue.ToString();
+                }
+
+                if (!Enum.TryParse(enumString, out T value))
+                {
+                    throw new JsonException();
+                }
+
+                return value;
+            }
+
+            public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options)
+            {
+                string[] enumString = value.ToString().Split(',');
+
+                writer.WriteStartArray();
+
+                foreach (string enumValue in enumString)
+                {
+                    writer.WriteStringValue(enumValue.TrimStart());
+                }
+
+                writer.WriteEndArray();
+            }
+        }
+
+        [Flags]
+        [JsonConverter(typeof(JsonStringEnumArrayConverter))]
+        public enum eDevice : uint
+        {
+            Unknown = 0x0,
+            Phone = 0x1,
+            PC = 0x2,
+            Laptop = 0x4,
+            Tablet = 0x8,
+            IoT = 0x10,
+            Watch = 0x20,
+            TV = 0x40,
+            Hub = 0x80,
+            Studio = 0x100,
+            Book = 0x200,
+            MediaCenter = 0x400,
+        }
+
+        [Theory]
+        [InlineData(@"[""PC"",""Tablet""]")]
+        [InlineData(@"[""Tablet"",""PC""]")]
+        public static void EnumValue(string json)
+        {
+            eDevice obj;
+
+            void Verify()
+            {
+                Assert.Equal(eDevice.PC | eDevice.Tablet, obj);
+            }
+
+            obj = JsonSerializer.Deserialize<eDevice>(json);
+            Verify();
+
+            // Round-trip and verify.
+            json = JsonSerializer.Serialize(obj);
+            obj = JsonSerializer.Deserialize<eDevice>(json);
+            Verify();
+        }
+
+        private class ConnectionList
+        {
+            public List<ConnectionFile> Connections { get; set; }
+        }
+
+        private class ConnectionFile
+        {
+            public eDevice Device { get; set; }
+        }
+
+        [Theory]
+        [InlineData(@"{""Connections"":[{""Device"":[""PC"",""Tablet""]},{""Device"":[""PC"",""Laptop""]}]}")]
+        [InlineData(@"{""Connections"":[{""Device"":[""Tablet"",""PC""]},{""Device"":[""Laptop"",""PC""]}]}")]
+        public static void EnumArray(string json)
+        {
+            ConnectionList obj;
+
+            void Verify()
+            {
+                Assert.Equal(2, obj.Connections.Count);
+                Assert.Equal(eDevice.PC | eDevice.Tablet, obj.Connections[0].Device);
+                Assert.Equal(eDevice.PC | eDevice.Laptop, obj.Connections[1].Device);
+            }
+
+            obj = JsonSerializer.Deserialize<ConnectionList>(json);
+            Verify();
+
+            // Round-trip and verify.
+            json = JsonSerializer.Serialize(obj);
+            obj = JsonSerializer.Deserialize<ConnectionList>(json);
+            Verify();
+        }
     }
 }