Skip to content

Commit 9818e37

Browse files
committed
add test cases
1 parent 5605708 commit 9818e37

File tree

2 files changed

+126
-2
lines changed

2 files changed

+126
-2
lines changed

lib/json_mend/parser.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ module JsonMend
88
# The core parser that does the heavy lifting of fixing the JSON
99
class Parser
1010
COMMENT_DELIMETERS = ['#', '/'].freeze
11-
NUMBER_CHARS = Set.new('0123456789-.eE/,'.chars).freeze
11+
NUMBER_CHARS = Set.new('0123456789-.eE/,_'.chars).freeze
1212
STRING_DELIMITERS = ['"', "'", '“', '”'].freeze
1313
ESCAPE_MAPPING = {
1414
't' => "\t",

spec/json_mend_spec.rb

Lines changed: 125 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -945,7 +945,7 @@ def with_timeout(seconds = 1, &)
945945
end
946946
end
947947

948-
context 'edge cases' do
948+
context 'with edge cases' do
949949
[
950950
{
951951
input: '[ "key": "value", "key2": "value2" ]',
@@ -1049,5 +1049,129 @@ def with_timeout(seconds = 1, &)
10491049
end
10501050
end
10511051
end
1052+
1053+
context 'when provided valid complex standard json' do
1054+
[
1055+
{
1056+
input: '{"simple": "string", "number": 123, "bool": true, "nil": null}',
1057+
expected_output: JSON.dump({ simple: 'string', number: 123, bool: true, nil: nil })
1058+
},
1059+
{
1060+
input: '{"nested": {"array": [1, 2, {"deep": "obj"}]}}',
1061+
expected_output: JSON.dump({ nested: { array: [1, 2, { deep: 'obj' }] } })
1062+
},
1063+
{
1064+
input: '{"unicode": "こんにちは", "emoji": "👍"}',
1065+
expected_output: JSON.dump({ unicode: 'こんにちは', emoji: '👍' })
1066+
},
1067+
{
1068+
input: '{"escapes":"\" \\\\ / \\b \\f \\n \\r \\t"}',
1069+
expected_output: JSON.dump({ escapes: "\" \\ / \b \f \n \r \t" })
1070+
},
1071+
{
1072+
input: '{"empty_obj": {}, "empty_arr": []}',
1073+
expected_output: JSON.dump({ empty_obj: {}, empty_arr: [] })
1074+
}
1075+
].each do |test_case|
1076+
it "preserves valid json: #{test_case[:input]}" do
1077+
expect(described_class.repair(test_case[:input])).to eq(test_case[:expected_output])
1078+
end
1079+
end
1080+
end
1081+
1082+
context 'when provided ambiguous number formats' do
1083+
[
1084+
{
1085+
input: '{"thousands": 1,234}',
1086+
expected_output: JSON.dump({ thousands: 1.234 })
1087+
},
1088+
{
1089+
input: '{"multi_comma": 1,234,567}',
1090+
expected_output: JSON.dump({ multi_comma: '1,234,567' })
1091+
},
1092+
{
1093+
input: '{"trailing_minus": 123-}',
1094+
expected_output: JSON.dump({ trailing_minus: 123 })
1095+
},
1096+
{
1097+
input: '{"underscores": 1_000}',
1098+
expected_output: JSON.dump({ underscores: 1000 })
1099+
}
1100+
].each do |test_case|
1101+
it "repairs number format #{test_case[:input]} to #{test_case[:expected_output]}" do
1102+
expect(described_class.repair(test_case[:input])).to eq(test_case[:expected_output])
1103+
end
1104+
end
1105+
end
1106+
1107+
context 'when provided tricky unicode and escapes' do
1108+
[
1109+
{
1110+
input: '{"short_unicode": "\\u12"}',
1111+
expected_output: JSON.dump({ short_unicode: '\\u12' })
1112+
},
1113+
{
1114+
input: '{"broken_escape": "val\\"}',
1115+
expected_output: JSON.dump({ broken_escape: 'val"' })
1116+
},
1117+
{
1118+
input: '{"hex_escape": "\\x41"}',
1119+
expected_output: JSON.dump({ hex_escape: 'A' })
1120+
}
1121+
].each do |test_case|
1122+
it "handles escapes in #{test_case[:input]}" do
1123+
expect(described_class.repair(test_case[:input])).to eq(test_case[:expected_output])
1124+
end
1125+
end
1126+
end
1127+
1128+
context 'when merging dangling arrays with interference' do
1129+
[
1130+
{
1131+
input: '{"a": [1] /* comment */ [2]}',
1132+
expected_output: JSON.dump({ 'a' => [1, 2] }),
1133+
desc: 'dangling array merge with intervening block comment'
1134+
},
1135+
{
1136+
input: "{\"a\": [1] // comment \n [2]}",
1137+
expected_output: JSON.dump({ 'a' => [1, 2] }),
1138+
desc: 'dangling array merge with intervening line comment'
1139+
},
1140+
{
1141+
input: '{"a": [1], "b": [3] [4]}',
1142+
expected_output: JSON.dump({ 'a' => [1], 'b' => [3, 4] }),
1143+
desc: 'dangling array on second key'
1144+
}
1145+
].each do |tc|
1146+
it "repairs #{tc[:desc]}" do
1147+
expect(described_class.repair(tc[:input])).to eq(tc[:expected_output])
1148+
end
1149+
end
1150+
end
1151+
1152+
context 'when provided unbalanced or garbage inputs' do
1153+
[
1154+
{
1155+
input: ']]]]]]',
1156+
expected_output: ''
1157+
},
1158+
{
1159+
input: '{{{{{{',
1160+
expected_output: JSON.dump({ '' => { '' => {} } })
1161+
},
1162+
{
1163+
input: 'random garbage text',
1164+
expected_output: ''
1165+
},
1166+
{
1167+
input: '{"key": "value"} random garbage',
1168+
expected_output: JSON.dump({ key: 'value' })
1169+
}
1170+
].each do |test_case|
1171+
it "robustly handles garbage: #{test_case[:input]}" do
1172+
expect(described_class.repair(test_case[:input])).to eq(test_case[:expected_output])
1173+
end
1174+
end
1175+
end
10521176
end
10531177
end

0 commit comments

Comments
 (0)