Skip to content

Commit

Permalink
make Exception message more clear in Neo.Json (#3579)
Browse files Browse the repository at this point in the history
  • Loading branch information
nan01ab authored Nov 14, 2024
1 parent e6fa071 commit 8328928
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 32 deletions.
5 changes: 3 additions & 2 deletions src/Neo.Json/JNumber.cs
Original file line number Diff line number Diff line change
Expand Up @@ -96,11 +96,12 @@ public override T GetEnum<T>(bool ignoreCase = false)
}
catch (OverflowException)
{
throw new InvalidCastException();
throw new InvalidCastException($"The value is out of range for the enum {enumType.FullName}");
}

object result = Enum.ToObject(enumType, value);
if (!Enum.IsDefined(enumType, result))
throw new InvalidCastException();
throw new InvalidCastException($"The value is not defined in the enum {enumType.FullName}");
return (T)result;
}

Expand Down
68 changes: 44 additions & 24 deletions src/Neo.Json/JPathToken.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ public static IEnumerable<JPathToken> Parse(string expr)
i += token.Content.Length - 1;
break;
default:
throw new FormatException();
throw new FormatException($"Invalid character '{expr[i]}' at position {i}");
}
yield return token;
}
Expand All @@ -78,7 +78,7 @@ private static string ParseString(string expr, int start)
end++;
if (c == '\'') return expr[start..end];
}
throw new FormatException();
throw new FormatException("Unterminated string");
}

public static string ParseIdentifier(string expr, int start)
Expand Down Expand Up @@ -112,7 +112,7 @@ private static string ParseNumber(string expr, int start)
private static JPathToken DequeueToken(Queue<JPathToken> tokens)
{
if (!tokens.TryDequeue(out JPathToken? token))
throw new FormatException();
throw new FormatException("Unexpected end of expression");
return token;
}

Expand All @@ -132,7 +132,7 @@ public static void ProcessJsonPath(ref JToken?[] objects, Queue<JPathToken> toke
ProcessBracket(ref objects, ref maxDepth, maxObjects, tokens);
break;
default:
throw new FormatException();
throw new FormatException($"Unexpected token {token.Type}");
}
}
}
Expand All @@ -152,7 +152,7 @@ private static void ProcessDot(ref JToken?[] objects, ref int maxDepth, int maxO
Descent(ref objects, ref maxDepth, maxObjects, token.Content!);
break;
default:
throw new FormatException();
throw new FormatException($"Unexpected token {token.Type}");
}
}

Expand All @@ -162,8 +162,9 @@ private static void ProcessBracket(ref JToken?[] objects, ref int maxDepth, int
switch (token.Type)
{
case JPathTokenType.Asterisk:
if (DequeueToken(tokens).Type != JPathTokenType.RightBracket)
throw new FormatException();
var rightBracket = DequeueToken(tokens);
if (rightBracket.Type != JPathTokenType.RightBracket)
throw new FormatException($"Unexpected token {rightBracket.Type}");
Descent(ref objects, ref maxDepth, maxObjects);
break;
case JPathTokenType.Colon:
Expand All @@ -183,7 +184,7 @@ private static void ProcessBracket(ref JToken?[] objects, ref int maxDepth, int
Descent(ref objects, ref maxDepth, maxObjects, int.Parse(token.Content!));
break;
default:
throw new FormatException();
throw new FormatException($"Unexpected token {next.Type}");
}
break;
case JPathTokenType.String:
Expand All @@ -197,19 +198,21 @@ private static void ProcessBracket(ref JToken?[] objects, ref int maxDepth, int
Descent(ref objects, ref maxDepth, maxObjects, JToken.Parse($"\"{token.Content!.Trim('\'')}\"")!.GetString());
break;
default:
throw new FormatException();
throw new FormatException($"Unexpected token {next.Type}");
}
break;
default:
throw new FormatException();
throw new FormatException($"Unexpected token {token.Type}");
}
}

private static void ProcessRecursiveDescent(ref JToken?[] objects, ref int maxDepth, int maxObjects, Queue<JPathToken> tokens)
{
List<JToken?> results = new();
JPathToken token = DequeueToken(tokens);
if (token.Type != JPathTokenType.Identifier) throw new FormatException();
if (token.Type != JPathTokenType.Identifier)
throw new FormatException($"Unexpected token {token.Type}");

while (objects.Length > 0)
{
results.AddRange(objects.OfType<JObject>().SelectMany(p => p.Properties).Where(p => p.Key == token.Content).Select(p => p.Value));
Expand All @@ -225,15 +228,16 @@ private static void ProcessSlice(ref JToken?[] objects, ref int maxDepth, int ma
switch (token.Type)
{
case JPathTokenType.Number:
if (DequeueToken(tokens).Type != JPathTokenType.RightBracket)
throw new FormatException();
var next = DequeueToken(tokens);
if (next.Type != JPathTokenType.RightBracket)
throw new FormatException($"Unexpected token {next.Type}");
DescentRange(ref objects, ref maxDepth, maxObjects, start, int.Parse(token.Content!));
break;
case JPathTokenType.RightBracket:
DescentRange(ref objects, ref maxDepth, maxObjects, start, 0);
break;
default:
throw new FormatException();
throw new FormatException($"Unexpected token {token.Type}");
}
}

Expand All @@ -243,14 +247,16 @@ private static void ProcessUnion(ref JToken?[] objects, ref int maxDepth, int ma
while (true)
{
JPathToken token = DequeueToken(tokens);
if (token.Type != first.Type) throw new FormatException();
if (token.Type != first.Type)
throw new FormatException($"Unexpected token {token.Type} != {first.Type}");
items.Add(token);
token = DequeueToken(tokens);
if (token.Type == JPathTokenType.RightBracket)
break;
if (token.Type != JPathTokenType.Comma)
throw new FormatException();
throw new FormatException($"Unexpected token {token.Type} != {JPathTokenType.Comma}");
}

switch (first.Type)
{
case JPathTokenType.Number:
Expand All @@ -260,16 +266,19 @@ private static void ProcessUnion(ref JToken?[] objects, ref int maxDepth, int ma
Descent(ref objects, ref maxDepth, maxObjects, items.Select(p => JToken.Parse($"\"{p.Content!.Trim('\'')}\"")!.GetString()).ToArray());
break;
default:
throw new FormatException();
throw new FormatException($"Unexpected token {first.Type}");
}
}

private static void Descent(ref JToken?[] objects, ref int maxDepth, int maxObjects)
{
if (maxDepth <= 0) throw new InvalidOperationException();
if (maxDepth <= 0)
throw new InvalidOperationException("Exceeded max depth");
--maxDepth;

objects = objects.OfType<JContainer>().SelectMany(p => p.Children).ToArray();
if (objects.Length > maxObjects) throw new InvalidOperationException(nameof(maxObjects));
if (objects.Length > maxObjects)
throw new InvalidOperationException(nameof(maxObjects));
}

private static void Descent(ref JToken?[] objects, ref int maxDepth, int maxObjects, params string[] names)
Expand All @@ -280,10 +289,14 @@ private static void Descent(ref JToken?[] objects, ref int maxDepth, int maxObje
if (obj.ContainsProperty(name))
yield return obj[name];
}
if (maxDepth <= 0) throw new InvalidOperationException();

if (maxDepth <= 0)
throw new InvalidOperationException("Exceeded max depth");
--maxDepth;

objects = objects.OfType<JObject>().SelectMany(p => GetProperties(p, names)).ToArray();
if (objects.Length > maxObjects) throw new InvalidOperationException(nameof(maxObjects));
if (objects.Length > maxObjects)
throw new InvalidOperationException(nameof(maxObjects));
}

private static void Descent(ref JToken?[] objects, ref int maxDepth, int maxObjects, params int[] indexes)
Expand All @@ -297,16 +310,22 @@ private static void Descent(ref JToken?[] objects, ref int maxDepth, int maxObje
yield return array[i];
}
}
if (maxDepth <= 0) throw new InvalidOperationException();

if (maxDepth <= 0)
throw new InvalidOperationException("Exceeded max depth");
--maxDepth;

objects = objects.OfType<JArray>().SelectMany(p => GetElements(p, indexes)).ToArray();
if (objects.Length > maxObjects) throw new InvalidOperationException(nameof(maxObjects));
if (objects.Length > maxObjects)
throw new InvalidOperationException(nameof(maxObjects));
}

private static void DescentRange(ref JToken?[] objects, ref int maxDepth, int maxObjects, int start, int end)
{
if (maxDepth <= 0) throw new InvalidOperationException();
if (maxDepth <= 0)
throw new InvalidOperationException("Exceeded max depth");
--maxDepth;

objects = objects.OfType<JArray>().SelectMany(p =>
{
int iStart = start >= 0 ? start : start + p.Count;
Expand All @@ -315,6 +334,7 @@ private static void DescentRange(ref JToken?[] objects, ref int maxDepth, int ma
int count = iEnd - iStart;
return p.Skip(iStart).Take(count);
}).ToArray();

if (objects.Length > maxObjects) throw new InvalidOperationException(nameof(maxObjects));
}
}
Expand Down
17 changes: 11 additions & 6 deletions src/Neo.Json/JToken.cs
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ public int GetInt32()
JsonTokenType.StartObject => ReadObject(ref reader),
JsonTokenType.String => ReadString(ref reader),
JsonTokenType.True => true,
_ => throw new FormatException(),
_ => throw new FormatException($"Unexpected token {reader.TokenType}"),
};
}

Expand All @@ -189,7 +189,7 @@ private static JArray ReadArray(ref Utf8JsonReader reader)
break;
}
}
throw new FormatException();
throw new FormatException("Unterminated array");
}

private static JObject ReadObject(ref Utf8JsonReader reader)
Expand All @@ -203,15 +203,17 @@ private static JObject ReadObject(ref Utf8JsonReader reader)
return obj;
case JsonTokenType.PropertyName:
string name = ReadString(ref reader);
if (obj.Properties.ContainsKey(name)) throw new FormatException();
if (obj.Properties.ContainsKey(name))
throw new FormatException($"Duplicate property name: {name}");

JToken? value = Read(ref reader);
obj.Properties.Add(name, value);
break;
default:
throw new FormatException();
throw new FormatException($"Unexpected token {reader.TokenType}");
}
}
throw new FormatException();
throw new FormatException("Unterminated object");
}

private static string ReadString(ref Utf8JsonReader reader)
Expand Down Expand Up @@ -271,9 +273,12 @@ public JArray JsonPath(string expr)
{
JToken?[] objects = { this };
if (expr.Length == 0) return objects;

Queue<JPathToken> tokens = new(JPathToken.Parse(expr));
JPathToken first = tokens.Dequeue();
if (first.Type != JPathTokenType.Root) throw new FormatException();
if (first.Type != JPathTokenType.Root)
throw new FormatException($"Unexpected token {first.Type}");

JPathToken.ProcessJsonPath(ref objects, tokens);
return objects;
}
Expand Down

0 comments on commit 8328928

Please sign in to comment.