using System.Globalization; using System.Text.Json; using System.Text.Json.Serialization; using Bit.Core.Utilities; using Bit.Test.Common.Helpers; using Xunit; namespace Bit.Core.Test.Utilities { public class PermissiveStringConverterTests { private const string numberJson = "{ \"StringProp\": 1, \"EnumerableStringProp\": [ 2, 3 ]}"; private const string stringJson = "{ \"StringProp\": \"1\", \"EnumerableStringProp\": [ \"2\", \"3\" ]}"; private const string nullAndEmptyJson = "{ \"StringProp\": null, \"EnumerableStringProp\": [] }"; private const string singleValueJson = "{ \"StringProp\": 1, \"EnumerableStringProp\": \"Hello!\" }"; private const string nullJson = "{ \"StringProp\": null, \"EnumerableStringProp\": null }"; private const string boolJson = "{ \"StringProp\": true, \"EnumerableStringProp\": [ false, 1.2]}"; private const string objectJsonOne = "{ \"StringProp\": { \"Message\": \"Hi\"}, \"EnumerableStringProp\": []}"; private const string objectJsonTwo = "{ \"StringProp\": \"Hi\", \"EnumerableStringProp\": {}}"; private readonly string bigNumbersJson = "{ \"StringProp\":" + decimal.MinValue + ", \"EnumerableStringProp\": [" + ulong.MaxValue + ", " + long.MinValue + "]}"; [Theory] [InlineData(numberJson)] [InlineData(stringJson)] public void Read_Success(string json) { var obj = JsonSerializer.Deserialize(json); Assert.Equal("1", obj.StringProp); Assert.Equal(2, obj.EnumerableStringProp.Count()); Assert.Equal("2", obj.EnumerableStringProp.ElementAt(0)); Assert.Equal("3", obj.EnumerableStringProp.ElementAt(1)); } [Fact] public void Read_Boolean_Success() { var obj = JsonSerializer.Deserialize(boolJson); Assert.Equal("True", obj.StringProp); Assert.Equal(2, obj.EnumerableStringProp.Count()); Assert.Equal("False", obj.EnumerableStringProp.ElementAt(0)); Assert.Equal("1.2", obj.EnumerableStringProp.ElementAt(1)); } [Fact] public void Read_Float_Success_Culture() { var ci = new CultureInfo("sv-SE"); Thread.CurrentThread.CurrentCulture = ci; Thread.CurrentThread.CurrentUICulture = ci; var obj = JsonSerializer.Deserialize(boolJson); Assert.Equal("1.2", obj.EnumerableStringProp.ElementAt(1)); } [Fact] public void Read_BigNumbers_Success() { var obj = JsonSerializer.Deserialize(bigNumbersJson); Assert.Equal(decimal.MinValue.ToString(), obj.StringProp); Assert.Equal(2, obj.EnumerableStringProp.Count()); Assert.Equal(ulong.MaxValue.ToString(), obj.EnumerableStringProp.ElementAt(0)); Assert.Equal(long.MinValue.ToString(), obj.EnumerableStringProp.ElementAt(1)); } [Fact] public void Read_SingleValue_Success() { var obj = JsonSerializer.Deserialize(singleValueJson); Assert.Equal("1", obj.StringProp); Assert.Single(obj.EnumerableStringProp); Assert.Equal("Hello!", obj.EnumerableStringProp.ElementAt(0)); } [Fact] public void Read_NullAndEmptyJson_Success() { var obj = JsonSerializer.Deserialize(nullAndEmptyJson); Assert.Null(obj.StringProp); Assert.Empty(obj.EnumerableStringProp); } [Fact] public void Read_Null_Success() { var obj = JsonSerializer.Deserialize(nullJson); Assert.Null(obj.StringProp); Assert.Null(obj.EnumerableStringProp); } [Theory] [InlineData(objectJsonOne)] [InlineData(objectJsonTwo)] public void Read_Object_Throws(string json) { var exception = Assert.Throws(() => JsonSerializer.Deserialize(json)); } [Fact] public void Write_Success() { var json = JsonSerializer.Serialize(new TestObject { StringProp = "1", EnumerableStringProp = new List { "2", "3", }, }); var jsonElement = JsonDocument.Parse(json).RootElement; var stringProp = AssertHelper.AssertJsonProperty(jsonElement, "StringProp", JsonValueKind.String); Assert.Equal("1", stringProp.GetString()); var list = AssertHelper.AssertJsonProperty(jsonElement, "EnumerableStringProp", JsonValueKind.Array); Assert.Equal(2, list.GetArrayLength()); var firstElement = list[0]; Assert.Equal(JsonValueKind.String, firstElement.ValueKind); Assert.Equal("2", firstElement.GetString()); var secondElement = list[1]; Assert.Equal(JsonValueKind.String, secondElement.ValueKind); Assert.Equal("3", secondElement.GetString()); } [Fact] public void Write_Null() { // When the values are null the converters aren't actually ran and it automatically serializes null var json = JsonSerializer.Serialize(new TestObject { StringProp = null, EnumerableStringProp = null, }); var jsonElement = JsonDocument.Parse(json).RootElement; AssertHelper.AssertJsonProperty(jsonElement, "StringProp", JsonValueKind.Null); AssertHelper.AssertJsonProperty(jsonElement, "EnumerableStringProp", JsonValueKind.Null); } [Fact] public void Write_Empty() { // When the values are null the converters aren't actually ran and it automatically serializes null var json = JsonSerializer.Serialize(new TestObject { StringProp = "", EnumerableStringProp = Enumerable.Empty(), }); var jsonElement = JsonDocument.Parse(json).RootElement; var stringVal = AssertHelper.AssertJsonProperty(jsonElement, "StringProp", JsonValueKind.String).GetString(); Assert.Equal("", stringVal); var array = AssertHelper.AssertJsonProperty(jsonElement, "EnumerableStringProp", JsonValueKind.Array); Assert.Equal(0, array.GetArrayLength()); } } public class TestObject { [JsonConverter(typeof(PermissiveStringConverter))] public string StringProp { get; set; } [JsonConverter(typeof(PermissiveStringEnumerableConverter))] public IEnumerable EnumerableStringProp { get; set; } } }