Skip to content

Commit e262c00

Browse files
Fixes float and double serialization for cultures that use comma as decimal separator (#17)
pt-BR for instance uses comma instead of dot as decimal separator
1 parent 4705cc5 commit e262c00

File tree

2 files changed

+74
-1
lines changed

2 files changed

+74
-1
lines changed

Serialization.NET/Segment/Serialization/JsonElement.cs

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System.Collections;
22
using System.Collections.Concurrent;
33
using System.Collections.Generic;
4+
using System.Globalization;
45
using System.Linq;
56

67
#if NETSTANDARD2_0
@@ -61,6 +62,19 @@ public static implicit operator JsonPrimitive(string value)
6162

6263
public static JsonPrimitive Create(object value, bool isString)
6364
{
65+
if (value is string s)
66+
{
67+
if (float.TryParse(s, out var f))
68+
{
69+
return new JsonLiteral(f, isString);
70+
}
71+
72+
if (double.TryParse(s, out var d))
73+
{
74+
return new JsonLiteral(d, isString);
75+
}
76+
}
77+
6478
return new JsonLiteral(value, isString);
6579
}
6680
}
@@ -74,7 +88,19 @@ internal class JsonLiteral : JsonPrimitive
7488
internal JsonLiteral(object body, bool isString)
7589
{
7690
IsString = isString;
77-
Content = body.ToString();
91+
92+
switch (body)
93+
{
94+
case float f:
95+
Content = f.ToString(CultureInfo.InvariantCulture);
96+
break;
97+
case double d:
98+
Content = d.ToString(CultureInfo.InvariantCulture);
99+
break;
100+
default:
101+
Content = body.ToString();
102+
break;
103+
}
78104
}
79105

80106
public override string ToString()
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Globalization;
4+
using Segment.Serialization;
5+
using Xunit;
6+
7+
namespace Tests
8+
{
9+
public class DecimalNumberSerializationTest
10+
{
11+
private class CurrentCultureScope : IDisposable
12+
{
13+
private readonly CultureInfo _originalCurrentCulture;
14+
15+
public CurrentCultureScope(CultureInfo cultureInfo)
16+
{
17+
_originalCurrentCulture = CultureInfo.CurrentCulture;
18+
CultureInfo.CurrentCulture = cultureInfo;
19+
}
20+
21+
public void Dispose()
22+
{
23+
CultureInfo.CurrentCulture = _originalCurrentCulture;
24+
}
25+
}
26+
27+
[Fact]
28+
public void TestDecimalNumberSerializationForAllCultures()
29+
{
30+
var eventParameters = new Dictionary<string, object> { { "FloatNumber", 1.23f } };
31+
32+
foreach (var cultureInfo in CultureInfo.GetCultures(CultureTypes.AllCultures))
33+
{
34+
using (new CurrentCultureScope(cultureInfo))
35+
{
36+
var eventParametersJson = JsonUtility.ToJson(eventParameters); // This call exist inside Segment.Analytics.Analytics::Track<T>
37+
var jsonObject = JsonUtility.FromJson<JsonObject>(eventParametersJson); // This call exist inside Segment.Analytics.Analytics::Track<T>
38+
var payloadJson = JsonUtility.ToJson(jsonObject); // Later, when dispatching the event to the analytics server, jsonObject gets serialized as JSON. If any float was serialized under pt-BR culture (which uses comma as a decimal separator), the JSON will be malformed and rejected by server.
39+
Assert.True(payloadJson != null);
40+
var payloadHashSet = new HashSet<char>(payloadJson); // Straight character comparison without culture info
41+
Assert.Contains('.', payloadHashSet);
42+
Assert.DoesNotContain(',', payloadHashSet);
43+
}
44+
}
45+
}
46+
}
47+
}

0 commit comments

Comments
 (0)