| 1 | module yaml |
| 2 | |
| 3 | // JSON round-trip: parse_text() should accept any JSON document (YAML 1.2 is |
| 4 | // a JSON superset), and to_json() should produce a JSON document that |
| 5 | // re-parses to the same logical tree. This guards against regressions in |
| 6 | // either the parser's JSON-superset fast path or the serializer's escaping. |
| 7 | |
| 8 | const json_corpus = [ |
| 9 | // scalars |
| 10 | 'true', |
| 11 | 'false', |
| 12 | 'null', |
| 13 | '0', |
| 14 | '-1', |
| 15 | '1234567890', |
| 16 | '3.14159', |
| 17 | '1.5e-10', |
| 18 | '""', |
| 19 | '"hello"', |
| 20 | '"with\\"quote"', |
| 21 | '"with\\nnewline"', |
| 22 | '"unicode: \\u00e9 \\u4e2d"', |
| 23 | '"verbatim utf8: café 中"', |
| 24 | // arrays |
| 25 | '[]', |
| 26 | '[1]', |
| 27 | '[1,2,3]', |
| 28 | '["a","b","c"]', |
| 29 | '[null,true,false,1,1.5,"s"]', |
| 30 | '[[1,2],[3,4],[]]', |
| 31 | '[{"k":"v"},{"k":"w"}]', |
| 32 | // objects |
| 33 | '{}', |
| 34 | '{"a":1}', |
| 35 | '{"a":1,"b":2,"c":3}', |
| 36 | '{"nested":{"deep":{"deeper":42}}}', |
| 37 | '{"mixed":[1,{"k":"v"},null,true]}', |
| 38 | '{"empty_arr":[],"empty_obj":{}}', |
| 39 | '{"unicode_key_café":"value","quoted.key":"v2"}', |
| 40 | // edge sizes |
| 41 | '[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19]', |
| 42 | '{"a":1,"b":2,"c":3,"d":4,"e":5,"f":6,"g":7,"h":8,"i":9,"j":10}', |
| 43 | ]! |
| 44 | |
| 45 | fn test_json_corpus_roundtrip() ! { |
| 46 | mut failed := []string{} |
| 47 | for input in json_corpus { |
| 48 | doc := parse_text(input) or { |
| 49 | failed << 'parse error on ${input}: ${err}' |
| 50 | continue |
| 51 | } |
| 52 | out := doc.to_json() |
| 53 | eq := json_logically_eq(input, out) or { |
| 54 | failed << '${input} -> ${out}: invalid JSON produced (${err})' |
| 55 | continue |
| 56 | } |
| 57 | if !eq { |
| 58 | failed << '${input} -> ${out}: not logically equal' |
| 59 | } |
| 60 | } |
| 61 | if failed.len > 0 { |
| 62 | eprintln('JSON round-trip failures (${failed.len}/${json_corpus.len}):') |
| 63 | for f in failed { |
| 64 | eprintln(' - ${f}') |
| 65 | } |
| 66 | assert false, '${failed.len} round-trip case(s) failed' |
| 67 | } |
| 68 | } |
| 69 | |
| 70 | // Anti-regression for the "first call works, repeated call breaks" family |
| 71 | // that used to surface in the json2.Any rebuild path: parse + to_json must |
| 72 | // be byte-stable across iterations on the same input. 500 iterations are |
| 73 | // enough to flush the original failure mode without bloating CI runtime. |
| 74 | fn test_json_roundtrip_is_idempotent_under_repetition() ! { |
| 75 | src := '{"users":[{"id":1,"name":"alice","tags":["x","y"]},{"id":2,"name":"bob","tags":[]}],"meta":{"count":2,"page":null,"flags":{"a":true,"b":false}}}' |
| 76 | mut prev := parse_text(src)!.to_json() |
| 77 | for _ in 0 .. 500 { |
| 78 | curr := parse_text(prev)!.to_json() |
| 79 | assert curr == prev, 'round-trip drift detected' |
| 80 | prev = curr |
| 81 | } |
| 82 | } |
| 83 | |