1104 lines
37 KiB
C#
1104 lines
37 KiB
C#
#region License
|
|
// Copyright (c) 2007 James Newton-King
|
|
//
|
|
// Permission is hereby granted, free of charge, to any person
|
|
// obtaining a copy of this software and associated documentation
|
|
// files (the "Software"), to deal in the Software without
|
|
// restriction, including without limitation the rights to use,
|
|
// copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
// copies of the Software, and to permit persons to whom the
|
|
// Software is furnished to do so, subject to the following
|
|
// conditions:
|
|
//
|
|
// The above copyright notice and this permission notice shall be
|
|
// included in all copies or substantial portions of the Software.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
// OTHER DEALINGS IN THE SOFTWARE.
|
|
#endregion
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Runtime.Serialization;
|
|
using System.Text;
|
|
using Newtonsoft.Json.Converters;
|
|
using Newtonsoft.Json.Serialization;
|
|
#if DNXCORE50
|
|
using Xunit;
|
|
using Test = Xunit.FactAttribute;
|
|
using Assert = Newtonsoft.Json.Tests.XUnitAssert;
|
|
#else
|
|
using NUnit.Framework;
|
|
#endif
|
|
using Newtonsoft.Json.Tests.TestObjects;
|
|
|
|
namespace Newtonsoft.Json.Tests.Converters
|
|
{
|
|
[TestFixture]
|
|
public class StringEnumConverterTests : TestFixtureBase
|
|
{
|
|
public class EnumClass
|
|
{
|
|
public StoreColor StoreColor { get; set; }
|
|
public StoreColor? NullableStoreColor1 { get; set; }
|
|
public StoreColor? NullableStoreColor2 { get; set; }
|
|
}
|
|
|
|
public class EnumContainer<T>
|
|
{
|
|
public T Enum { get; set; }
|
|
}
|
|
|
|
[Flags]
|
|
public enum FlagsTestEnum
|
|
{
|
|
Default = 0,
|
|
First = 1,
|
|
Second = 2
|
|
}
|
|
|
|
public enum NegativeEnum
|
|
{
|
|
Negative = -1,
|
|
Zero = 0,
|
|
Positive = 1
|
|
}
|
|
|
|
[Flags]
|
|
public enum NegativeFlagsEnum
|
|
{
|
|
NegativeFour = -4,
|
|
NegativeTwo = -2,
|
|
NegativeOne = -1,
|
|
Zero = 0,
|
|
One = 1,
|
|
Two = 2,
|
|
Four = 4
|
|
}
|
|
|
|
#if !NET20
|
|
public enum NamedEnum
|
|
{
|
|
[EnumMember(Value = "@first")]
|
|
First,
|
|
|
|
[EnumMember(Value = "@second")]
|
|
Second,
|
|
Third
|
|
}
|
|
|
|
public enum NamedEnumDuplicate
|
|
{
|
|
[EnumMember(Value = "Third")]
|
|
First,
|
|
|
|
[EnumMember(Value = "@second")]
|
|
Second,
|
|
Third
|
|
}
|
|
|
|
public enum NamedEnumWithComma
|
|
{
|
|
[EnumMember(Value = "@first")]
|
|
First,
|
|
|
|
[EnumMember(Value = "@second")]
|
|
Second,
|
|
|
|
[EnumMember(Value = ",third")]
|
|
Third,
|
|
|
|
[EnumMember(Value = ",")]
|
|
JustComma
|
|
}
|
|
#endif
|
|
|
|
public class NegativeEnumClass
|
|
{
|
|
public NegativeEnum Value1 { get; set; }
|
|
public NegativeEnum Value2 { get; set; }
|
|
}
|
|
|
|
public class NegativeFlagsEnumClass
|
|
{
|
|
public NegativeFlagsEnum Value1 { get; set; }
|
|
public NegativeFlagsEnum Value2 { get; set; }
|
|
}
|
|
|
|
[JsonConverter(typeof(StringEnumConverter), true)]
|
|
public enum CamelCaseEnumObsolete
|
|
{
|
|
This,
|
|
Is,
|
|
CamelCase
|
|
}
|
|
|
|
[JsonConverter(typeof(StringEnumConverter), typeof(CamelCaseNamingStrategy))]
|
|
public enum CamelCaseEnumNew
|
|
{
|
|
This,
|
|
Is,
|
|
CamelCase
|
|
}
|
|
|
|
[JsonConverter(typeof(StringEnumConverter), typeof(SnakeCaseNamingStrategy))]
|
|
public enum SnakeCaseEnumNew
|
|
{
|
|
This,
|
|
Is,
|
|
SnakeCase
|
|
}
|
|
|
|
[JsonConverter(typeof(StringEnumConverter), typeof(CamelCaseNamingStrategy), new object[0], false)]
|
|
public enum NotAllowIntegerValuesEnum
|
|
{
|
|
Foo = 0,
|
|
Bar = 1
|
|
}
|
|
|
|
[JsonConverter(typeof(StringEnumConverter), typeof(CamelCaseNamingStrategy))]
|
|
public enum AllowIntegerValuesEnum
|
|
{
|
|
Foo = 0,
|
|
Bar = 1
|
|
}
|
|
|
|
[JsonConverter(typeof(StringEnumConverter), typeof(CamelCaseNamingStrategy), null)]
|
|
public enum NullArgumentInAttribute
|
|
{
|
|
Foo = 0,
|
|
Bar = 1
|
|
}
|
|
|
|
[Test]
|
|
public void Serialize_CamelCaseFromAttribute_Obsolete()
|
|
{
|
|
string json = JsonConvert.SerializeObject(CamelCaseEnumObsolete.CamelCase);
|
|
Assert.AreEqual(@"""camelCase""", json);
|
|
}
|
|
|
|
[Test]
|
|
public void NamingStrategyAndCamelCaseText()
|
|
{
|
|
StringEnumConverter converter = new StringEnumConverter();
|
|
Assert.IsNull(converter.NamingStrategy);
|
|
|
|
#pragma warning disable CS0618 // Type or member is obsolete
|
|
converter.CamelCaseText = true;
|
|
#pragma warning restore CS0618 // Type or member is obsolete
|
|
Assert.IsNotNull(converter.NamingStrategy);
|
|
Assert.AreEqual(typeof(CamelCaseNamingStrategy), converter.NamingStrategy.GetType());
|
|
|
|
var camelCaseInstance = converter.NamingStrategy;
|
|
#pragma warning disable CS0618 // Type or member is obsolete
|
|
converter.CamelCaseText = true;
|
|
#pragma warning restore CS0618 // Type or member is obsolete
|
|
Assert.AreEqual(camelCaseInstance, converter.NamingStrategy);
|
|
|
|
converter.NamingStrategy = null;
|
|
#pragma warning disable CS0618 // Type or member is obsolete
|
|
Assert.IsFalse(converter.CamelCaseText);
|
|
#pragma warning restore CS0618 // Type or member is obsolete
|
|
|
|
converter.NamingStrategy = new CamelCaseNamingStrategy();
|
|
#pragma warning disable CS0618 // Type or member is obsolete
|
|
Assert.IsTrue(converter.CamelCaseText);
|
|
#pragma warning restore CS0618 // Type or member is obsolete
|
|
|
|
converter.NamingStrategy = new SnakeCaseNamingStrategy();
|
|
#pragma warning disable CS0618 // Type or member is obsolete
|
|
Assert.IsFalse(converter.CamelCaseText);
|
|
#pragma warning restore CS0618 // Type or member is obsolete
|
|
|
|
#pragma warning disable CS0618 // Type or member is obsolete
|
|
converter.CamelCaseText = false;
|
|
#pragma warning restore CS0618 // Type or member is obsolete
|
|
Assert.IsNotNull(converter.NamingStrategy);
|
|
Assert.AreEqual(typeof(SnakeCaseNamingStrategy), converter.NamingStrategy.GetType());
|
|
}
|
|
|
|
[Test]
|
|
public void StringEnumConverter_CamelCaseTextCtor()
|
|
{
|
|
#pragma warning disable CS0618 // Type or member is obsolete
|
|
StringEnumConverter converter = new StringEnumConverter(true);
|
|
#pragma warning restore CS0618 // Type or member is obsolete
|
|
|
|
Assert.IsNotNull(converter.NamingStrategy);
|
|
Assert.AreEqual(typeof(CamelCaseNamingStrategy), converter.NamingStrategy.GetType());
|
|
Assert.AreEqual(true, converter.AllowIntegerValues);
|
|
}
|
|
|
|
[Test]
|
|
public void StringEnumConverter_NamingStrategyTypeCtor()
|
|
{
|
|
StringEnumConverter converter = new StringEnumConverter(typeof(CamelCaseNamingStrategy), new object[] { true, true, true }, false);
|
|
|
|
Assert.IsNotNull(converter.NamingStrategy);
|
|
Assert.AreEqual(typeof(CamelCaseNamingStrategy), converter.NamingStrategy.GetType());
|
|
Assert.AreEqual(false, converter.AllowIntegerValues);
|
|
Assert.AreEqual(true, converter.NamingStrategy.OverrideSpecifiedNames);
|
|
Assert.AreEqual(true, converter.NamingStrategy.ProcessDictionaryKeys);
|
|
Assert.AreEqual(true, converter.NamingStrategy.ProcessExtensionDataNames);
|
|
}
|
|
|
|
[Test]
|
|
public void StringEnumConverter_NamingStrategyTypeCtor_Null()
|
|
{
|
|
ExceptionAssert.Throws<ArgumentNullException>(
|
|
() => new StringEnumConverter(null),
|
|
@"Value cannot be null.
|
|
Parameter name: namingStrategyType", "Value cannot be null. (Parameter 'namingStrategyType')");
|
|
}
|
|
|
|
[Test]
|
|
public void StringEnumConverter_NamingStrategyTypeWithArgsCtor_Null()
|
|
{
|
|
ExceptionAssert.Throws<ArgumentNullException>(
|
|
() => new StringEnumConverter(null, new object[] { true, true, true }, false),
|
|
@"Value cannot be null.
|
|
Parameter name: namingStrategyType", "Value cannot be null. (Parameter 'namingStrategyType')");
|
|
}
|
|
|
|
[Test]
|
|
public void Deserialize_CamelCaseFromAttribute_Obsolete()
|
|
{
|
|
CamelCaseEnumObsolete e = JsonConvert.DeserializeObject<CamelCaseEnumObsolete>(@"""camelCase""");
|
|
Assert.AreEqual(CamelCaseEnumObsolete.CamelCase, e);
|
|
}
|
|
|
|
[Test]
|
|
public void Serialize_CamelCaseFromAttribute()
|
|
{
|
|
string json = JsonConvert.SerializeObject(CamelCaseEnumNew.CamelCase);
|
|
Assert.AreEqual(@"""camelCase""", json);
|
|
}
|
|
|
|
[Test]
|
|
public void Deserialize_CamelCaseFromAttribute()
|
|
{
|
|
CamelCaseEnumNew e = JsonConvert.DeserializeObject<CamelCaseEnumNew>(@"""camelCase""");
|
|
Assert.AreEqual(CamelCaseEnumNew.CamelCase, e);
|
|
}
|
|
|
|
[Test]
|
|
public void Serialize_SnakeCaseFromAttribute()
|
|
{
|
|
string json = JsonConvert.SerializeObject(SnakeCaseEnumNew.SnakeCase);
|
|
Assert.AreEqual(@"""snake_case""", json);
|
|
}
|
|
|
|
[Test]
|
|
public void Deserialize_SnakeCaseFromAttribute()
|
|
{
|
|
SnakeCaseEnumNew e = JsonConvert.DeserializeObject<SnakeCaseEnumNew>(@"""snake_case""");
|
|
Assert.AreEqual(SnakeCaseEnumNew.SnakeCase, e);
|
|
}
|
|
|
|
[Test]
|
|
public void Deserialize_NotAllowIntegerValuesFromAttribute()
|
|
{
|
|
ExceptionAssert.Throws<JsonSerializationException>(() =>
|
|
{
|
|
NotAllowIntegerValuesEnum e = JsonConvert.DeserializeObject<NotAllowIntegerValuesEnum>(@"""9""");
|
|
});
|
|
}
|
|
|
|
[Test]
|
|
public void CannotPassNullArgumentToConverter()
|
|
{
|
|
var ex = ExceptionAssert.Throws<JsonException>(() =>
|
|
{
|
|
JsonConvert.DeserializeObject<NullArgumentInAttribute>(@"""9""");
|
|
});
|
|
|
|
Assert.AreEqual("Cannot pass a null parameter to the constructor.", ex.InnerException.Message);
|
|
}
|
|
|
|
[Test]
|
|
public void Deserialize_AllowIntegerValuesAttribute()
|
|
{
|
|
AllowIntegerValuesEnum e = JsonConvert.DeserializeObject<AllowIntegerValuesEnum>(@"""9""");
|
|
Assert.AreEqual(9, (int)e);
|
|
}
|
|
|
|
#if !NET20
|
|
[Test]
|
|
public void NamedEnumDuplicateTest()
|
|
{
|
|
ExceptionAssert.Throws<Exception>(() =>
|
|
{
|
|
EnumContainer<NamedEnumDuplicate> c = new EnumContainer<NamedEnumDuplicate>
|
|
{
|
|
Enum = NamedEnumDuplicate.First
|
|
};
|
|
|
|
JsonConvert.SerializeObject(c, Formatting.Indented, new StringEnumConverter());
|
|
}, "Enum name 'Third' already exists on enum 'NamedEnumDuplicate'.");
|
|
}
|
|
|
|
[Test]
|
|
public void SerializeNameEnumTest()
|
|
{
|
|
EnumContainer<NamedEnum> c = new EnumContainer<NamedEnum>
|
|
{
|
|
Enum = NamedEnum.First
|
|
};
|
|
|
|
string json = JsonConvert.SerializeObject(c, Formatting.Indented, new StringEnumConverter());
|
|
StringAssert.AreEqual(@"{
|
|
""Enum"": ""@first""
|
|
}", json);
|
|
|
|
c = new EnumContainer<NamedEnum>
|
|
{
|
|
Enum = NamedEnum.Third
|
|
};
|
|
|
|
json = JsonConvert.SerializeObject(c, Formatting.Indented, new StringEnumConverter());
|
|
StringAssert.AreEqual(@"{
|
|
""Enum"": ""Third""
|
|
}", json);
|
|
}
|
|
|
|
[Test]
|
|
public void NamedEnumCommaTest()
|
|
{
|
|
EnumContainer<NamedEnumWithComma> c = new EnumContainer<NamedEnumWithComma>
|
|
{
|
|
Enum = NamedEnumWithComma.Third
|
|
};
|
|
|
|
string json = JsonConvert.SerializeObject(c, Formatting.Indented, new StringEnumConverter());
|
|
StringAssert.AreEqual(@"{
|
|
""Enum"": "",third""
|
|
}", json);
|
|
|
|
EnumContainer<NamedEnumWithComma> c2 = JsonConvert.DeserializeObject<EnumContainer<NamedEnumWithComma>>(json, new StringEnumConverter());
|
|
Assert.AreEqual(NamedEnumWithComma.Third, c2.Enum);
|
|
}
|
|
|
|
[Test]
|
|
public void NamedEnumCommaTest2()
|
|
{
|
|
EnumContainer<NamedEnumWithComma> c = new EnumContainer<NamedEnumWithComma>
|
|
{
|
|
Enum = NamedEnumWithComma.JustComma
|
|
};
|
|
|
|
string json = JsonConvert.SerializeObject(c, Formatting.Indented, new StringEnumConverter());
|
|
StringAssert.AreEqual(@"{
|
|
""Enum"": "",""
|
|
}", json);
|
|
|
|
EnumContainer<NamedEnumWithComma> c2 = JsonConvert.DeserializeObject<EnumContainer<NamedEnumWithComma>>(json, new StringEnumConverter());
|
|
Assert.AreEqual(NamedEnumWithComma.JustComma, c2.Enum);
|
|
}
|
|
|
|
[Test]
|
|
public void NamedEnumCommaCaseInsensitiveTest()
|
|
{
|
|
EnumContainer<NamedEnumWithComma> c2 = JsonConvert.DeserializeObject<EnumContainer<NamedEnumWithComma>>(@"{""Enum"":"",THIRD""}", new StringEnumConverter());
|
|
Assert.AreEqual(NamedEnumWithComma.Third, c2.Enum);
|
|
}
|
|
|
|
[Test]
|
|
public void DeserializeNameEnumTest()
|
|
{
|
|
string json = @"{
|
|
""Enum"": ""@first""
|
|
}";
|
|
|
|
EnumContainer<NamedEnum> c = JsonConvert.DeserializeObject<EnumContainer<NamedEnum>>(json, new StringEnumConverter());
|
|
Assert.AreEqual(NamedEnum.First, c.Enum);
|
|
|
|
json = @"{
|
|
""Enum"": ""Third""
|
|
}";
|
|
|
|
c = JsonConvert.DeserializeObject<EnumContainer<NamedEnum>>(json, new StringEnumConverter());
|
|
Assert.AreEqual(NamedEnum.Third, c.Enum);
|
|
}
|
|
#endif
|
|
|
|
[Test]
|
|
public void SerializeEnumClass()
|
|
{
|
|
EnumClass enumClass = new EnumClass()
|
|
{
|
|
StoreColor = StoreColor.Red,
|
|
NullableStoreColor1 = StoreColor.White,
|
|
NullableStoreColor2 = null
|
|
};
|
|
|
|
string json = JsonConvert.SerializeObject(enumClass, Formatting.Indented, new StringEnumConverter());
|
|
|
|
StringAssert.AreEqual(@"{
|
|
""StoreColor"": ""Red"",
|
|
""NullableStoreColor1"": ""White"",
|
|
""NullableStoreColor2"": null
|
|
}", json);
|
|
}
|
|
|
|
[Test]
|
|
public void SerializeEnumClassWithCamelCase()
|
|
{
|
|
EnumClass enumClass = new EnumClass()
|
|
{
|
|
StoreColor = StoreColor.Red,
|
|
NullableStoreColor1 = StoreColor.DarkGoldenrod,
|
|
NullableStoreColor2 = null
|
|
};
|
|
|
|
#pragma warning disable CS0618 // Type or member is obsolete
|
|
string json = JsonConvert.SerializeObject(enumClass, Formatting.Indented, new StringEnumConverter { CamelCaseText = true });
|
|
#pragma warning restore CS0618 // Type or member is obsolete
|
|
|
|
StringAssert.AreEqual(@"{
|
|
""StoreColor"": ""red"",
|
|
""NullableStoreColor1"": ""darkGoldenrod"",
|
|
""NullableStoreColor2"": null
|
|
}", json);
|
|
}
|
|
|
|
[Test]
|
|
public void SerializeEnumClassUndefined()
|
|
{
|
|
EnumClass enumClass = new EnumClass()
|
|
{
|
|
StoreColor = (StoreColor)1000,
|
|
NullableStoreColor1 = (StoreColor)1000,
|
|
NullableStoreColor2 = null
|
|
};
|
|
|
|
string json = JsonConvert.SerializeObject(enumClass, Formatting.Indented, new StringEnumConverter());
|
|
|
|
StringAssert.AreEqual(@"{
|
|
""StoreColor"": 1000,
|
|
""NullableStoreColor1"": 1000,
|
|
""NullableStoreColor2"": null
|
|
}", json);
|
|
}
|
|
|
|
[Test]
|
|
public void SerializeFlagEnum()
|
|
{
|
|
EnumClass enumClass = new EnumClass()
|
|
{
|
|
StoreColor = StoreColor.Red | StoreColor.White,
|
|
NullableStoreColor1 = StoreColor.White & StoreColor.Yellow,
|
|
NullableStoreColor2 = StoreColor.Red | StoreColor.White | StoreColor.Black
|
|
};
|
|
|
|
string json = JsonConvert.SerializeObject(enumClass, Formatting.Indented, new StringEnumConverter());
|
|
|
|
StringAssert.AreEqual(@"{
|
|
""StoreColor"": ""Red, White"",
|
|
""NullableStoreColor1"": 0,
|
|
""NullableStoreColor2"": ""Black, Red, White""
|
|
}", json);
|
|
}
|
|
|
|
[Test]
|
|
public void SerializeNegativeFlagsEnum()
|
|
{
|
|
NegativeFlagsEnumClass negativeEnumClass = new NegativeFlagsEnumClass();
|
|
negativeEnumClass.Value1 = NegativeFlagsEnum.NegativeFour | NegativeFlagsEnum.NegativeTwo;
|
|
negativeEnumClass.Value2 = NegativeFlagsEnum.Two | NegativeFlagsEnum.Four;
|
|
|
|
string json = JsonConvert.SerializeObject(negativeEnumClass, Formatting.Indented, new StringEnumConverter());
|
|
|
|
StringAssert.AreEqual(@"{
|
|
""Value1"": ""NegativeTwo"",
|
|
""Value2"": ""Two, Four""
|
|
}", json);
|
|
}
|
|
|
|
[Test]
|
|
public void DeserializeNegativeFlagsEnum()
|
|
{
|
|
string json = @"{
|
|
""Value1"": ""NegativeFour,NegativeTwo"",
|
|
""Value2"": ""NegativeFour,Four""
|
|
}";
|
|
|
|
NegativeFlagsEnumClass negativeEnumClass = JsonConvert.DeserializeObject<NegativeFlagsEnumClass>(json, new StringEnumConverter());
|
|
|
|
Assert.AreEqual(NegativeFlagsEnum.NegativeFour | NegativeFlagsEnum.NegativeTwo, negativeEnumClass.Value1);
|
|
Assert.AreEqual(NegativeFlagsEnum.NegativeFour | NegativeFlagsEnum.Four, negativeEnumClass.Value2);
|
|
}
|
|
|
|
[Test]
|
|
public void SerializeNegativeEnum()
|
|
{
|
|
NegativeEnumClass negativeEnumClass = new NegativeEnumClass()
|
|
{
|
|
Value1 = NegativeEnum.Negative,
|
|
Value2 = (NegativeEnum)int.MinValue
|
|
};
|
|
|
|
string json = JsonConvert.SerializeObject(negativeEnumClass, Formatting.Indented, new StringEnumConverter());
|
|
|
|
StringAssert.AreEqual(@"{
|
|
""Value1"": ""Negative"",
|
|
""Value2"": -2147483648
|
|
}", json);
|
|
}
|
|
|
|
[Test]
|
|
public void DeserializeNegativeEnum()
|
|
{
|
|
string json = @"{
|
|
""Value1"": ""Negative"",
|
|
""Value2"": -2147483648
|
|
}";
|
|
|
|
NegativeEnumClass negativeEnumClass = JsonConvert.DeserializeObject<NegativeEnumClass>(json, new StringEnumConverter());
|
|
|
|
Assert.AreEqual(NegativeEnum.Negative, negativeEnumClass.Value1);
|
|
Assert.AreEqual((NegativeEnum)int.MinValue, negativeEnumClass.Value2);
|
|
}
|
|
|
|
[Test]
|
|
public void DeserializeFlagEnum()
|
|
{
|
|
string json = @"{
|
|
""StoreColor"": ""Red, White"",
|
|
""NullableStoreColor1"": 0,
|
|
""NullableStoreColor2"": ""black, Red, White""
|
|
}";
|
|
|
|
EnumClass enumClass = JsonConvert.DeserializeObject<EnumClass>(json, new StringEnumConverter());
|
|
|
|
Assert.AreEqual(StoreColor.Red | StoreColor.White, enumClass.StoreColor);
|
|
Assert.AreEqual((StoreColor)0, enumClass.NullableStoreColor1);
|
|
Assert.AreEqual(StoreColor.Red | StoreColor.White | StoreColor.Black, enumClass.NullableStoreColor2);
|
|
}
|
|
|
|
[Test]
|
|
public void DeserializeEnumClass()
|
|
{
|
|
string json = @"{
|
|
""StoreColor"": ""Red"",
|
|
""NullableStoreColor1"": ""White"",
|
|
""NullableStoreColor2"": null
|
|
}";
|
|
|
|
EnumClass enumClass = JsonConvert.DeserializeObject<EnumClass>(json, new StringEnumConverter());
|
|
|
|
Assert.AreEqual(StoreColor.Red, enumClass.StoreColor);
|
|
Assert.AreEqual(StoreColor.White, enumClass.NullableStoreColor1);
|
|
Assert.AreEqual(null, enumClass.NullableStoreColor2);
|
|
}
|
|
|
|
[Test]
|
|
public void DeserializeEnumClassUndefined()
|
|
{
|
|
string json = @"{
|
|
""StoreColor"": 1000,
|
|
""NullableStoreColor1"": 1000,
|
|
""NullableStoreColor2"": null
|
|
}";
|
|
|
|
EnumClass enumClass = JsonConvert.DeserializeObject<EnumClass>(json, new StringEnumConverter());
|
|
|
|
Assert.AreEqual((StoreColor)1000, enumClass.StoreColor);
|
|
Assert.AreEqual((StoreColor)1000, enumClass.NullableStoreColor1);
|
|
Assert.AreEqual(null, enumClass.NullableStoreColor2);
|
|
}
|
|
|
|
[Test]
|
|
public void CamelCaseTextFlagEnumSerialization()
|
|
{
|
|
EnumContainer<FlagsTestEnum> c = new EnumContainer<FlagsTestEnum>
|
|
{
|
|
Enum = FlagsTestEnum.First | FlagsTestEnum.Second
|
|
};
|
|
|
|
#pragma warning disable CS0618 // Type or member is obsolete
|
|
string json = JsonConvert.SerializeObject(c, Formatting.Indented, new StringEnumConverter { CamelCaseText = true });
|
|
#pragma warning restore CS0618 // Type or member is obsolete
|
|
StringAssert.AreEqual(@"{
|
|
""Enum"": ""first, second""
|
|
}", json);
|
|
}
|
|
|
|
[Test]
|
|
public void CamelCaseTextFlagEnumDeserialization()
|
|
{
|
|
string json = @"{
|
|
""Enum"": ""first, second""
|
|
}";
|
|
|
|
#pragma warning disable CS0618 // Type or member is obsolete
|
|
EnumContainer<FlagsTestEnum> c = JsonConvert.DeserializeObject<EnumContainer<FlagsTestEnum>>(json, new StringEnumConverter { CamelCaseText = true });
|
|
#pragma warning restore CS0618 // Type or member is obsolete
|
|
Assert.AreEqual(FlagsTestEnum.First | FlagsTestEnum.Second, c.Enum);
|
|
}
|
|
|
|
[Test]
|
|
public void DeserializeEmptyStringIntoNullable()
|
|
{
|
|
string json = @"{
|
|
""StoreColor"": ""Red"",
|
|
""NullableStoreColor1"": ""White"",
|
|
""NullableStoreColor2"": """"
|
|
}";
|
|
|
|
EnumClass c = JsonConvert.DeserializeObject<EnumClass>(json, new StringEnumConverter());
|
|
Assert.IsNull(c.NullableStoreColor2);
|
|
}
|
|
|
|
[Test]
|
|
public void DeserializeInvalidString()
|
|
{
|
|
string json = "{ \"Value\" : \"Three\" }";
|
|
|
|
ExceptionAssert.Throws<JsonSerializationException>(() =>
|
|
{
|
|
var serializer = new JsonSerializer();
|
|
serializer.Converters.Add(new StringEnumConverter());
|
|
serializer.Deserialize<Bucket>(new JsonTextReader(new StringReader(json)));
|
|
}, @"Error converting value ""Three"" to type 'Newtonsoft.Json.Tests.Converters.StringEnumConverterTests+MyEnum'. Path 'Value', line 1, position 19.");
|
|
}
|
|
|
|
public class Bucket
|
|
{
|
|
public MyEnum Value;
|
|
}
|
|
|
|
public enum MyEnum
|
|
{
|
|
Alpha,
|
|
Beta,
|
|
}
|
|
|
|
[Test]
|
|
public void DeserializeIntegerButNotAllowed()
|
|
{
|
|
string json = "{ \"Value\" : 123 }";
|
|
|
|
try
|
|
{
|
|
var serializer = new JsonSerializer();
|
|
serializer.Converters.Add(new StringEnumConverter { AllowIntegerValues = false });
|
|
serializer.Deserialize<Bucket>(new JsonTextReader(new StringReader(json)));
|
|
}
|
|
catch (JsonSerializationException ex)
|
|
{
|
|
Assert.AreEqual("Error converting value 123 to type 'Newtonsoft.Json.Tests.Converters.StringEnumConverterTests+MyEnum'. Path 'Value', line 1, position 15.", ex.Message);
|
|
Assert.AreEqual(@"Integer value 123 is not allowed. Path 'Value', line 1, position 15.", ex.InnerException.Message);
|
|
|
|
return;
|
|
}
|
|
|
|
Assert.Fail();
|
|
}
|
|
|
|
#if !NET20
|
|
[Test]
|
|
public void EnumMemberPlusFlags()
|
|
{
|
|
List<Foo> lfoo =
|
|
new List<Foo>
|
|
{
|
|
Foo.Bat | Foo.SerializeAsBaz,
|
|
Foo.FooBar,
|
|
Foo.Bat,
|
|
Foo.SerializeAsBaz,
|
|
Foo.FooBar | Foo.SerializeAsBaz,
|
|
(Foo)int.MaxValue
|
|
};
|
|
|
|
#pragma warning disable CS0618 // Type or member is obsolete
|
|
string json1 = JsonConvert.SerializeObject(lfoo, Formatting.Indented, new StringEnumConverter { CamelCaseText = true });
|
|
#pragma warning restore CS0618 // Type or member is obsolete
|
|
|
|
StringAssert.AreEqual(@"[
|
|
""Bat, baz"",
|
|
""foo_bar"",
|
|
""Bat"",
|
|
""baz"",
|
|
""foo_bar, baz"",
|
|
2147483647
|
|
]", json1);
|
|
|
|
IList<Foo> foos = JsonConvert.DeserializeObject<List<Foo>>(json1);
|
|
|
|
Assert.AreEqual(6, foos.Count);
|
|
Assert.AreEqual(Foo.Bat | Foo.SerializeAsBaz, foos[0]);
|
|
Assert.AreEqual(Foo.FooBar, foos[1]);
|
|
Assert.AreEqual(Foo.Bat, foos[2]);
|
|
Assert.AreEqual(Foo.SerializeAsBaz, foos[3]);
|
|
Assert.AreEqual(Foo.FooBar | Foo.SerializeAsBaz, foos[4]);
|
|
Assert.AreEqual((Foo)int.MaxValue, foos[5]);
|
|
|
|
List<Bar> lbar = new List<Bar>() { Bar.FooBar, Bar.Bat, Bar.SerializeAsBaz };
|
|
|
|
#pragma warning disable CS0618 // Type or member is obsolete
|
|
string json2 = JsonConvert.SerializeObject(lbar, Formatting.Indented, new StringEnumConverter { CamelCaseText = true });
|
|
#pragma warning restore CS0618 // Type or member is obsolete
|
|
|
|
StringAssert.AreEqual(@"[
|
|
""foo_bar"",
|
|
""Bat"",
|
|
""baz""
|
|
]", json2);
|
|
|
|
IList<Bar> bars = JsonConvert.DeserializeObject<List<Bar>>(json2);
|
|
|
|
Assert.AreEqual(3, bars.Count);
|
|
Assert.AreEqual(Bar.FooBar, bars[0]);
|
|
Assert.AreEqual(Bar.Bat, bars[1]);
|
|
Assert.AreEqual(Bar.SerializeAsBaz, bars[2]);
|
|
}
|
|
|
|
[Test]
|
|
public void DuplicateNameEnumTest()
|
|
{
|
|
ExceptionAssert.Throws<JsonSerializationException>(
|
|
() => JsonConvert.DeserializeObject<DuplicateNameEnum>("'foo_bar'", new StringEnumConverter()),
|
|
@"Error converting value ""foo_bar"" to type 'Newtonsoft.Json.Tests.Converters.DuplicateNameEnum'. Path '', line 1, position 9.");
|
|
}
|
|
|
|
// Define other methods and classes here
|
|
[Flags]
|
|
[JsonConverter(typeof(StringEnumConverter))]
|
|
private enum Foo
|
|
{
|
|
[EnumMember(Value = "foo_bar")]
|
|
FooBar = 0x01,
|
|
Bat = 0x02,
|
|
|
|
[EnumMember(Value = "baz")]
|
|
SerializeAsBaz = 0x4,
|
|
}
|
|
|
|
[JsonConverter(typeof(StringEnumConverter))]
|
|
private enum Bar
|
|
{
|
|
[EnumMember(Value = "foo_bar")]
|
|
FooBar,
|
|
Bat,
|
|
|
|
[EnumMember(Value = "baz")]
|
|
SerializeAsBaz
|
|
}
|
|
|
|
[Test]
|
|
public void DataContractSerializerDuplicateNameEnumTest()
|
|
{
|
|
MemoryStream ms = new MemoryStream();
|
|
var s = new DataContractSerializer(typeof(DuplicateEnumNameTestClass));
|
|
|
|
ExceptionAssert.Throws<InvalidDataContractException>(() =>
|
|
{
|
|
s.WriteObject(ms, new DuplicateEnumNameTestClass
|
|
{
|
|
Value = DuplicateNameEnum.foo_bar,
|
|
Value2 = DuplicateNameEnum2.foo_bar_NOT_USED
|
|
});
|
|
|
|
string xml = @"<DuplicateEnumNameTestClass xmlns=""http://schemas.datacontract.org/2004/07/Newtonsoft.Json.Tests.Converters"" xmlns:i=""http://www.w3.org/2001/XMLSchema-instance"">
|
|
<Value>foo_bar</Value>
|
|
<Value2>foo_bar</Value2>
|
|
</DuplicateEnumNameTestClass>";
|
|
|
|
var o = (DuplicateEnumNameTestClass)s.ReadObject(new MemoryStream(Encoding.UTF8.GetBytes(xml)));
|
|
|
|
Assert.AreEqual(DuplicateNameEnum.foo_bar, o.Value);
|
|
Assert.AreEqual(DuplicateNameEnum2.FooBar, o.Value2);
|
|
}, "Type 'Newtonsoft.Json.Tests.Converters.DuplicateNameEnum' contains two members 'foo_bar' 'and 'FooBar' with the same name 'foo_bar'. Multiple members with the same name in one type are not supported. Consider changing one of the member names using EnumMemberAttribute attribute.");
|
|
}
|
|
|
|
[Test]
|
|
public void EnumMemberWithNumbers()
|
|
{
|
|
StringEnumConverter converter = new StringEnumConverter();
|
|
|
|
NumberNamesEnum e = JsonConvert.DeserializeObject<NumberNamesEnum>("\"1\"", converter);
|
|
|
|
Assert.AreEqual(NumberNamesEnum.second, e);
|
|
|
|
e = JsonConvert.DeserializeObject<NumberNamesEnum>("\"2\"", converter);
|
|
|
|
Assert.AreEqual(NumberNamesEnum.first, e);
|
|
|
|
e = JsonConvert.DeserializeObject<NumberNamesEnum>("\"3\"", converter);
|
|
|
|
Assert.AreEqual(NumberNamesEnum.third, e);
|
|
|
|
e = JsonConvert.DeserializeObject<NumberNamesEnum>("\"-4\"", converter);
|
|
|
|
Assert.AreEqual(NumberNamesEnum.fourth, e);
|
|
}
|
|
|
|
[Test]
|
|
public void EnumMemberWithNumbers_NoIntegerValues()
|
|
{
|
|
StringEnumConverter converter = new StringEnumConverter { AllowIntegerValues = false };
|
|
|
|
NumberNamesEnum e = JsonConvert.DeserializeObject<NumberNamesEnum>("\"1\"", converter);
|
|
|
|
Assert.AreEqual(NumberNamesEnum.second, e);
|
|
|
|
e = JsonConvert.DeserializeObject<NumberNamesEnum>("\"2\"", converter);
|
|
|
|
Assert.AreEqual(NumberNamesEnum.first, e);
|
|
|
|
e = JsonConvert.DeserializeObject<NumberNamesEnum>("\"3\"", converter);
|
|
|
|
Assert.AreEqual(NumberNamesEnum.third, e);
|
|
|
|
e = JsonConvert.DeserializeObject<NumberNamesEnum>("\"-4\"", converter);
|
|
|
|
Assert.AreEqual(NumberNamesEnum.fourth, e);
|
|
}
|
|
#endif
|
|
|
|
[Test]
|
|
public void AllowIntegerValueAndStringNumber()
|
|
{
|
|
JsonSerializationException ex = ExceptionAssert.Throws<JsonSerializationException>(() =>
|
|
{
|
|
JsonConvert.DeserializeObject<StoreColor>("\"1\"", new StringEnumConverter { AllowIntegerValues = false });
|
|
});
|
|
|
|
Assert.AreEqual("Integer string '1' is not allowed.", ex.InnerException.Message);
|
|
}
|
|
|
|
[Test]
|
|
public void AllowIntegerValueAndNegativeStringNumber()
|
|
{
|
|
JsonSerializationException ex = ExceptionAssert.Throws<JsonSerializationException>(() =>
|
|
{
|
|
JsonConvert.DeserializeObject<StoreColor>("\"-1\"", new StringEnumConverter { AllowIntegerValues = false });
|
|
});
|
|
|
|
Assert.AreEqual("Integer string '-1' is not allowed.", ex.InnerException.Message);
|
|
}
|
|
|
|
[Test]
|
|
public void AllowIntegerValueAndPositiveStringNumber()
|
|
{
|
|
JsonSerializationException ex = ExceptionAssert.Throws<JsonSerializationException>(() =>
|
|
{
|
|
JsonConvert.DeserializeObject<StoreColor>("\"+1\"", new StringEnumConverter { AllowIntegerValues = false });
|
|
});
|
|
|
|
Assert.AreEqual("Integer string '+1' is not allowed.", ex.InnerException.Message);
|
|
}
|
|
|
|
[Test]
|
|
public void AllowIntegerValueAndDash()
|
|
{
|
|
JsonSerializationException ex = ExceptionAssert.Throws<JsonSerializationException>(() =>
|
|
{
|
|
JsonConvert.DeserializeObject<StoreColor>("\"-\"", new StringEnumConverter { AllowIntegerValues = false });
|
|
});
|
|
|
|
Assert.AreEqual("Requested value '-' was not found.", ex.InnerException.Message);
|
|
}
|
|
|
|
[Test]
|
|
public void AllowIntegerValueAndNonNamedValue()
|
|
{
|
|
ExceptionAssert.Throws<JsonSerializationException>(() =>
|
|
{
|
|
JsonConvert.SerializeObject((StoreColor)999, new StringEnumConverter { AllowIntegerValues = false });
|
|
}, "Integer value 999 is not allowed. Path ''.");
|
|
}
|
|
|
|
public enum EnumWithDifferentCases
|
|
{
|
|
M,
|
|
m
|
|
}
|
|
|
|
[Test]
|
|
public void SerializeEnumWithDifferentCases()
|
|
{
|
|
string json = JsonConvert.SerializeObject(EnumWithDifferentCases.M, new StringEnumConverter());
|
|
|
|
Assert.AreEqual(@"""M""", json);
|
|
|
|
json = JsonConvert.SerializeObject(EnumWithDifferentCases.m, new StringEnumConverter());
|
|
|
|
Assert.AreEqual(@"""m""", json);
|
|
}
|
|
|
|
[Test]
|
|
public void DeserializeEnumWithDifferentCases()
|
|
{
|
|
EnumWithDifferentCases e = JsonConvert.DeserializeObject<EnumWithDifferentCases>(@"""M""", new StringEnumConverter());
|
|
Assert.AreEqual(EnumWithDifferentCases.M, e);
|
|
|
|
e = JsonConvert.DeserializeObject<EnumWithDifferentCases>(@"""m""", new StringEnumConverter());
|
|
Assert.AreEqual(EnumWithDifferentCases.m, e);
|
|
}
|
|
|
|
#if !NET20
|
|
[JsonConverter(typeof(StringEnumConverter))]
|
|
public enum EnumMemberDoesNotMatchName
|
|
{
|
|
[EnumMember(Value = "first_value")]
|
|
First
|
|
}
|
|
|
|
[Test]
|
|
public void DeserializeEnumCaseIncensitive_ByEnumMemberValue_UpperCase()
|
|
{
|
|
var e = JsonConvert.DeserializeObject<EnumMemberDoesNotMatchName>(@"""FIRST_VALUE""", new StringEnumConverter());
|
|
Assert.AreEqual(EnumMemberDoesNotMatchName.First, e);
|
|
}
|
|
|
|
[Test]
|
|
public void DeserializeEnumCaseIncensitive_ByEnumMemberValue_MixedCase()
|
|
{
|
|
var e = JsonConvert.DeserializeObject<EnumMemberDoesNotMatchName>(@"""First_Value""", new StringEnumConverter());
|
|
Assert.AreEqual(EnumMemberDoesNotMatchName.First, e);
|
|
}
|
|
|
|
[Test]
|
|
public void DeserializeEnumCaseIncensitive_ByName_LowerCase()
|
|
{
|
|
var e = JsonConvert.DeserializeObject<EnumMemberDoesNotMatchName>(@"""first""", new StringEnumConverter());
|
|
Assert.AreEqual(EnumMemberDoesNotMatchName.First, e);
|
|
}
|
|
|
|
[Test]
|
|
public void DeserializeEnumCaseIncensitive_ByName_UperCase()
|
|
{
|
|
var e = JsonConvert.DeserializeObject<EnumMemberDoesNotMatchName>(@"""FIRST""", new StringEnumConverter());
|
|
Assert.AreEqual(EnumMemberDoesNotMatchName.First, e);
|
|
}
|
|
|
|
[Test]
|
|
public void DeserializeEnumCaseIncensitive_FromAttribute()
|
|
{
|
|
var e = JsonConvert.DeserializeObject<EnumMemberDoesNotMatchName>(@"""FIRST_VALUE""");
|
|
Assert.AreEqual(EnumMemberDoesNotMatchName.First, e);
|
|
}
|
|
|
|
[JsonConverter(typeof(StringEnumConverter))]
|
|
public enum EnumMemberWithDiffrentCases
|
|
{
|
|
[EnumMember(Value = "first_value")]
|
|
First,
|
|
[EnumMember(Value = "second_value")]
|
|
first
|
|
}
|
|
|
|
[Test]
|
|
public void DeserializeEnumMemberWithDifferentCasing_ByEnumMemberValue_First()
|
|
{
|
|
var e = JsonConvert.DeserializeObject<EnumMemberWithDiffrentCases>(@"""first_value""", new StringEnumConverter());
|
|
Assert.AreEqual(EnumMemberWithDiffrentCases.First, e);
|
|
}
|
|
|
|
[Test]
|
|
public void DeserializeEnumMemberWithDifferentCasing_ByEnumMemberValue_Second()
|
|
{
|
|
var e = JsonConvert.DeserializeObject<EnumMemberWithDiffrentCases>(@"""second_value""", new StringEnumConverter());
|
|
Assert.AreEqual(EnumMemberWithDiffrentCases.first, e);
|
|
}
|
|
|
|
[DataContract(Name = "DateFormats")]
|
|
public enum EnumMemberWithDifferentCases
|
|
{
|
|
[EnumMember(Value = "M")]
|
|
Month,
|
|
[EnumMember(Value = "m")]
|
|
Minute
|
|
}
|
|
|
|
[Test]
|
|
public void SerializeEnumMemberWithDifferentCases()
|
|
{
|
|
string json = JsonConvert.SerializeObject(EnumMemberWithDifferentCases.Month, new StringEnumConverter());
|
|
|
|
Assert.AreEqual(@"""M""", json);
|
|
|
|
json = JsonConvert.SerializeObject(EnumMemberWithDifferentCases.Minute, new StringEnumConverter());
|
|
|
|
Assert.AreEqual(@"""m""", json);
|
|
}
|
|
|
|
[Test]
|
|
public void DeserializeEnumMemberWithDifferentCases()
|
|
{
|
|
EnumMemberWithDifferentCases e = JsonConvert.DeserializeObject<EnumMemberWithDifferentCases>(@"""M""", new StringEnumConverter());
|
|
|
|
Assert.AreEqual(EnumMemberWithDifferentCases.Month, e);
|
|
|
|
e = JsonConvert.DeserializeObject<EnumMemberWithDifferentCases>(@"""m""", new StringEnumConverter());
|
|
|
|
Assert.AreEqual(EnumMemberWithDifferentCases.Minute, e);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
#if !NET20
|
|
[DataContract]
|
|
public class DuplicateEnumNameTestClass
|
|
{
|
|
[DataMember]
|
|
public DuplicateNameEnum Value { get; set; }
|
|
|
|
[DataMember]
|
|
public DuplicateNameEnum2 Value2 { get; set; }
|
|
}
|
|
|
|
[DataContract]
|
|
public enum NumberNamesEnum
|
|
{
|
|
[EnumMember(Value = "2")]
|
|
first,
|
|
[EnumMember(Value = "1")]
|
|
second,
|
|
[EnumMember(Value = "3")]
|
|
third,
|
|
[EnumMember(Value = "-4")]
|
|
fourth
|
|
}
|
|
|
|
[DataContract]
|
|
public enum DuplicateNameEnum
|
|
{
|
|
[EnumMember]
|
|
first = 0,
|
|
|
|
[EnumMember]
|
|
foo_bar = 1,
|
|
|
|
[EnumMember(Value = "foo_bar")]
|
|
FooBar = 2,
|
|
|
|
[EnumMember]
|
|
foo_bar_NOT_USED = 3
|
|
}
|
|
|
|
[DataContract]
|
|
public enum DuplicateNameEnum2
|
|
{
|
|
[EnumMember]
|
|
first = 0,
|
|
|
|
[EnumMember(Value = "foo_bar")]
|
|
FooBar = 1,
|
|
|
|
[EnumMember]
|
|
foo_bar = 2,
|
|
|
|
[EnumMember(Value = "TEST")]
|
|
foo_bar_NOT_USED = 3
|
|
}
|
|
#endif
|
|
} |