Skip to content
This repository was archived by the owner on Dec 24, 2022. It is now read-only.

Commit 5d7a963

Browse files
committed
fix tests and cleanup parse primitive number code
1 parent eb969cc commit 5d7a963

File tree

3 files changed

+65
-65
lines changed

3 files changed

+65
-65
lines changed

src/ServiceStack.Text/Common/DeserializeType.cs

Lines changed: 55 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -149,63 +149,61 @@ public static object ParseQuotedPrimitive(string value)
149149
return Serializer.UnescapeString(value);
150150
}
151151

152-
public static object ParsePrimitive(string value)
153-
{
154-
if (string.IsNullOrEmpty(value)) return null;
155-
156-
bool boolValue;
157-
if (bool.TryParse(value, out boolValue)) return boolValue;
158-
159-
// Parse as decimal
160-
decimal decimalValue;
161-
var acceptDecimal = JsConfig.ParsePrimitiveFloatingPointTypes.HasFlag(ParseAsType.Decimal);
162-
var hasDecimal = decimal.TryParse(value, NumberStyles.Number, CultureInfo.InvariantCulture, out decimalValue);
163-
164-
// Check if the number is an Primitive Integer type given that we have a decimal
165-
if(hasDecimal && decimalValue == decimal.Truncate(decimalValue))
166-
{
167-
// Value is a whole number
168-
if (JsConfig.ParsePrimitiveIntegerTypes.HasFlag(ParseAsType.Byte) && decimalValue <= byte.MaxValue && decimalValue >= byte.MinValue) return (byte)decimalValue;
169-
if (JsConfig.ParsePrimitiveIntegerTypes.HasFlag(ParseAsType.SByte) && decimalValue <= sbyte.MaxValue && decimalValue >= sbyte.MinValue) return (sbyte)decimalValue;
170-
if (JsConfig.ParsePrimitiveIntegerTypes.HasFlag(ParseAsType.Int16) && decimalValue <= Int16.MaxValue && decimalValue >= Int16.MinValue) return (Int16)decimalValue;
171-
if (JsConfig.ParsePrimitiveIntegerTypes.HasFlag(ParseAsType.UInt16) && decimalValue <= UInt16.MaxValue && decimalValue >= UInt16.MinValue) return (UInt16)decimalValue;
172-
if (JsConfig.ParsePrimitiveIntegerTypes.HasFlag(ParseAsType.Int32) && decimalValue <= Int32.MaxValue && decimalValue >= Int32.MinValue) return (Int32)decimalValue;
173-
if (JsConfig.ParsePrimitiveIntegerTypes.HasFlag(ParseAsType.UInt32) && decimalValue <= UInt32.MaxValue && decimalValue >= UInt32.MinValue) return (UInt32)decimalValue;
174-
if (JsConfig.ParsePrimitiveIntegerTypes.HasFlag(ParseAsType.Int64) && decimalValue <= Int64.MaxValue && decimalValue >= Int64.MinValue) return (Int64)decimalValue;
175-
if (JsConfig.ParsePrimitiveIntegerTypes.HasFlag(ParseAsType.UInt64) && decimalValue <= UInt64.MaxValue && decimalValue >= UInt64.MinValue) return (UInt64)decimalValue;
176-
return null;
177-
}
178-
179-
// Value is a floating point number
180-
181-
// Return a decimal if the user accepts a decimal
182-
if(hasDecimal && acceptDecimal)
183-
return decimalValue;
184-
185-
// Parse as double if decimal failed or user wants a double
186-
double doubleValue = 0;
187-
var acceptDouble = JsConfig.ParsePrimitiveFloatingPointTypes.HasFlag(ParseAsType.Double);
188-
var hasDouble = (!hasDecimal || acceptDouble) && double.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out doubleValue);
189-
190-
// Return a double if the user accepts a double
191-
if(acceptDouble && hasDouble)
192-
return doubleValue;
193-
194-
// Parse as float
195-
float floatValue;
196-
var acceptFloat = JsConfig.ParsePrimitiveFloatingPointTypes.HasFlag(ParseAsType.Single);
197-
var hasFloat = float.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out floatValue);
198-
199-
// Return a float if the user accepts a float
200-
if(acceptFloat && hasFloat)
201-
return floatValue;
202-
203-
// Default to decimal, then double , then float or null
204-
if(hasDecimal) return decimalValue;
205-
if(hasDouble) return doubleValue;
206-
if(hasFloat) return floatValue;
207-
return null;
208-
}
152+
public static object ParsePrimitive(string value)
153+
{
154+
if (string.IsNullOrEmpty(value)) return null;
155+
156+
bool boolValue;
157+
if (bool.TryParse(value, out boolValue)) return boolValue;
158+
159+
// Parse as decimal
160+
decimal decimalValue;
161+
var acceptDecimal = JsConfig.ParsePrimitiveFloatingPointTypes.HasFlag(ParseAsType.Decimal);
162+
var isDecimal = decimal.TryParse(value, NumberStyles.Number, CultureInfo.InvariantCulture, out decimalValue);
163+
164+
// Check if the number is an Primitive Integer type given that we have a decimal
165+
if (isDecimal && decimalValue == decimal.Truncate(decimalValue))
166+
{
167+
// Value is a whole number
168+
var parseAs = JsConfig.ParsePrimitiveIntegerTypes;
169+
if (parseAs.HasFlag(ParseAsType.Byte) && decimalValue <= byte.MaxValue && decimalValue >= byte.MinValue) return (byte)decimalValue;
170+
if (parseAs.HasFlag(ParseAsType.SByte) && decimalValue <= sbyte.MaxValue && decimalValue >= sbyte.MinValue) return (sbyte)decimalValue;
171+
if (parseAs.HasFlag(ParseAsType.Int16) && decimalValue <= Int16.MaxValue && decimalValue >= Int16.MinValue) return (Int16)decimalValue;
172+
if (parseAs.HasFlag(ParseAsType.UInt16) && decimalValue <= UInt16.MaxValue && decimalValue >= UInt16.MinValue) return (UInt16)decimalValue;
173+
if (parseAs.HasFlag(ParseAsType.Int32) && decimalValue <= Int32.MaxValue && decimalValue >= Int32.MinValue) return (Int32)decimalValue;
174+
if (parseAs.HasFlag(ParseAsType.UInt32) && decimalValue <= UInt32.MaxValue && decimalValue >= UInt32.MinValue) return (UInt32)decimalValue;
175+
if (parseAs.HasFlag(ParseAsType.Int64) && decimalValue <= Int64.MaxValue && decimalValue >= Int64.MinValue) return (Int64)decimalValue;
176+
if (parseAs.HasFlag(ParseAsType.UInt64) && decimalValue <= UInt64.MaxValue && decimalValue >= UInt64.MinValue) return (UInt64)decimalValue;
177+
return decimalValue;
178+
}
179+
180+
// Value is a floating point number
181+
182+
// Return a decimal if the user accepts a decimal
183+
if (isDecimal && acceptDecimal)
184+
return decimalValue;
185+
186+
float floatValue;
187+
var acceptFloat = JsConfig.ParsePrimitiveFloatingPointTypes.HasFlag(ParseAsType.Single);
188+
var isFloat = float.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out floatValue);
189+
if (acceptFloat && isFloat)
190+
return floatValue;
191+
192+
double doubleValue;
193+
var acceptDouble = JsConfig.ParsePrimitiveFloatingPointTypes.HasFlag(ParseAsType.Double);
194+
var isDouble = double.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out doubleValue);
195+
if (acceptDouble && isDouble)
196+
return doubleValue;
197+
198+
if (isDecimal)
199+
return decimalValue;
200+
if (isFloat)
201+
return floatValue;
202+
if (isDouble)
203+
return doubleValue;
204+
205+
return null;
206+
}
209207

210208
internal static object ParsePrimitive(string value, char firstChar)
211209
{

src/ServiceStack.Text/JsConfig.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -689,6 +689,8 @@ public static void Reset()
689689
sExcludeTypes = new HashSet<Type> { typeof(Stream) };
690690
__uniqueTypes = new HashSet<Type>();
691691
sMaxDepth = 50;
692+
sParsePrimitiveIntegerTypes = null;
693+
sParsePrimitiveFloatingPointTypes = null;
692694
PlatformExtensions.ClearRuntimeAttributes();
693695
}
694696

tests/ServiceStack.Text.Tests/DictionaryTests.cs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,7 @@ private static Dictionary<string, object> SetupDict()
183183
{ "c", false },
184184
{ "d", new[] {1, 2, 3} },
185185
{ "e", 1m },
186+
{ "f", 1.1m },
186187
};
187188
}
188189

@@ -247,7 +248,6 @@ public void Test_ServiceStack_Text_JsonSerializer_Array_Value_Deserializes_Corre
247248
Assert.AreEqual(new List<int> { 1, 2, 3 }, deserializedDict["d"]);
248249
}
249250

250-
251251
[Test]
252252
public void deserizes_to_decimal_by_default()
253253
{
@@ -256,18 +256,15 @@ public void deserizes_to_decimal_by_default()
256256
var dict = SetupDict();
257257
var json = JsonSerializer.SerializeToString(dict);
258258
var deserializedDict = JsonSerializer.DeserializeFromString<IDictionary<string, object>>(json);
259-
Assert.That(deserializedDict["e"], Is.TypeOf<decimal>());
260-
Assert.That(deserializedDict["e"], Is.EqualTo(1m));
261-
259+
Assert.That(deserializedDict["f"], Is.TypeOf<decimal>());
260+
Assert.That(deserializedDict["f"], Is.EqualTo(1.1m));
262261
}
262+
263263
class NumericType
264264
{
265-
266265
public NumericType(decimal max, Type type)
267-
: this(0, max, type)
268-
{
266+
: this(0, max, type) {}
269267

270-
}
271268
public NumericType(decimal min, decimal max, Type type)
272269
{
273270
Min = min;
@@ -299,6 +296,7 @@ public void deserizes_floats_into_to_best_fit_floating_point()
299296
{
300297
JsConfig.TryToParsePrimitiveTypeValues = true;
301298
JsConfig.TryToParseNumericType = true;
299+
JsConfig.ParsePrimitiveFloatingPointTypes = ParseAsType.Single | ParseAsType.Double;
302300

303301
float floatValue = 1.1f;
304302
//TODO find a number that doesn't suck which throws in float.Parse() but not double.Parse()
@@ -329,6 +327,8 @@ public void deserizes_floats_into_to_best_fit_floating_point()
329327

330328
Assert.That(map["long"], Is.TypeOf<long>());
331329
Assert.That(map["long"], Is.EqualTo(longValue));
330+
331+
JsConfig.Reset();
332332
}
333333

334334
[Test]

0 commit comments

Comments
 (0)