Skip to content

Commit 2c5c5ee

Browse files
committed
benchmarks
1 parent bd1e944 commit 2c5c5ee

File tree

1 file changed

+144
-0
lines changed

1 file changed

+144
-0
lines changed

benchmark_comparison.rb

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
# frozen_string_literal: true
2+
3+
# gem install benchmark-ips json-repair json_mend
4+
# ruby -Ilib benchmark_comparison.rb
5+
require 'benchmark/ips'
6+
require 'json'
7+
8+
# --- Load Libraries ---
9+
begin
10+
require 'json_mend'
11+
rescue LoadError
12+
abort "❌ Could not load 'json_mend'. Make sure you are in the gem root or have it installed."
13+
end
14+
15+
begin
16+
require 'json/repair'
17+
rescue LoadError
18+
puts "❌ Could not load 'json-repair'. Benchmarks for it will be skipped."
19+
end
20+
21+
puts '========================================================='
22+
puts ' 🚀 JSON Repair Benchmark (IPS) '
23+
puts " JsonMend (v#{JsonMend::VERSION}) vs json-repair-rb (v#{JSON::Repair::VERSION})"
24+
puts '========================================================='
25+
puts
26+
27+
# --- Test Data ---
28+
29+
json_object = '{"id": 1, "name": "Test", "active": true, "tags": ["a", "b"]}'
30+
31+
TEST_CASES = {
32+
valid_single: {
33+
label: 'Valid Single JSON',
34+
input: json_object
35+
},
36+
concatenated: {
37+
label: 'Concatenated JSON (x10)',
38+
input: json_object * 10
39+
},
40+
simple_fix: {
41+
label: 'Simple Fix (Missing Quotes)',
42+
input: '{name: "Alice", age: 30, city: "Wonderland"}'
43+
},
44+
trailing_comma: {
45+
label: 'Trailing Commas',
46+
input: '{"items": [1, 2, 3,], "active": true,}'
47+
},
48+
comments: {
49+
label: 'Comments (// and #)',
50+
input: <<~JSON
51+
{
52+
"key": "value", // This is a comment
53+
"config": {
54+
"timeout": 100 # Another comment
55+
}
56+
}
57+
JSON
58+
},
59+
complex: {
60+
label: 'Complex & Mixed Errors',
61+
input: <<~JSON
62+
{
63+
name: "Broken",
64+
"nested": [
65+
{id: 1,},
66+
{id: 2}
67+
],
68+
"dangling": [1, 2, 3
69+
JSON
70+
},
71+
garbage: {
72+
label: 'Heavy Garbage / Hallucinations',
73+
input: 'Here is the JSON: ```json {"a": 1} ``` and some other text.'
74+
},
75+
python_style: {
76+
label: 'Python Literals (True/None)',
77+
input: '{"is_valid": True, "missing": None, "wrong_bool": False}'
78+
},
79+
single_quotes: {
80+
label: 'Single Quotes (JS Style)',
81+
input: "{'id': 123, 'status': 'pending', 'meta': {'active': true}}"
82+
},
83+
deep_nesting: {
84+
label: 'Deeply Nested (Stack Test)',
85+
input: '{"a":' * 50 + '1' + '}' * 50
86+
},
87+
unbalanced: {
88+
label: 'Truncated / Unbalanced',
89+
input: '{"users": [{"id": 1, "name": "Alice"}, {"id": 2'
90+
},
91+
unescaped_control: {
92+
label: 'Unescaped Newlines/Tabs',
93+
input: "{\"bio\": \"This is a \n multi-line string \t with tabs.\"}"
94+
},
95+
large_array: {
96+
label: 'Large Single Array (Throughput)',
97+
input: '[' + (1..1000).map { |i| %({"id": #{i}, "val": "item_#{i}"}) }.join(',') + ']'
98+
},
99+
concatenated_complex: {
100+
label: 'Concatenated + Broken (LLM Stream)',
101+
input: '{"part": 1} {part: 2, "broken": true} {"part": 3}'
102+
}
103+
}.freeze
104+
105+
# Helper to check if a library supports the input before benchmarking
106+
def supported?(library_proc, input)
107+
library_proc.call(input)
108+
true
109+
rescue StandardError
110+
false
111+
end
112+
113+
# --- Run Benchmarks ---
114+
115+
TEST_CASES.each_value do |data|
116+
puts "\n\n🔸 Scenario: #{data[:label]}"
117+
puts '-' * 40
118+
119+
Benchmark.ips do |x|
120+
x.config(time: 2, warmup: 1) # Short duration for quick checks
121+
122+
# 1. JsonMend
123+
if supported?(->(i) { JsonMend.repair(i) }, data[:input])
124+
x.report('JsonMend') do
125+
JsonMend.repair(data[:input])
126+
end
127+
else
128+
puts ' JsonMend: ❌ Not Supported'
129+
end
130+
131+
# 2. json-repair
132+
if defined?(JSON::Repair)
133+
if supported?(->(i) { JSON.repair(i) }, data[:input])
134+
x.report('json-repair') do
135+
JSON.repair(data[:input])
136+
end
137+
else
138+
puts ' json-repair: ❌ Not Supported'
139+
end
140+
end
141+
142+
x.compare!
143+
end
144+
end

0 commit comments

Comments
 (0)