@toon-format/spec 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,220 @@
1
+ {
2
+ "version": "1.3",
3
+ "category": "encode",
4
+ "description": "Object encoding - simple objects, nested objects, key encoding",
5
+ "tests": [
6
+ {
7
+ "name": "preserves key order in objects",
8
+ "input": {
9
+ "id": 123,
10
+ "name": "Ada",
11
+ "active": true
12
+ },
13
+ "expected": "id: 123\nname: Ada\nactive: true",
14
+ "specSection": "6"
15
+ },
16
+ {
17
+ "name": "encodes null values in objects",
18
+ "input": {
19
+ "id": 123,
20
+ "value": null
21
+ },
22
+ "expected": "id: 123\nvalue: null",
23
+ "specSection": "6"
24
+ },
25
+ {
26
+ "name": "encodes empty objects as empty string",
27
+ "input": {},
28
+ "expected": "",
29
+ "specSection": "6"
30
+ },
31
+ {
32
+ "name": "quotes string value with colon",
33
+ "input": {
34
+ "note": "a:b"
35
+ },
36
+ "expected": "note: \"a:b\"",
37
+ "specSection": "6"
38
+ },
39
+ {
40
+ "name": "quotes string value with comma",
41
+ "input": {
42
+ "note": "a,b"
43
+ },
44
+ "expected": "note: \"a,b\"",
45
+ "specSection": "6"
46
+ },
47
+ {
48
+ "name": "quotes string value with newline",
49
+ "input": {
50
+ "text": "line1\nline2"
51
+ },
52
+ "expected": "text: \"line1\\nline2\"",
53
+ "specSection": "6"
54
+ },
55
+ {
56
+ "name": "quotes string value with embedded quotes",
57
+ "input": {
58
+ "text": "say \"hello\""
59
+ },
60
+ "expected": "text: \"say \\\"hello\\\"\"",
61
+ "specSection": "6"
62
+ },
63
+ {
64
+ "name": "quotes string value with leading space",
65
+ "input": {
66
+ "text": " padded "
67
+ },
68
+ "expected": "text: \" padded \"",
69
+ "specSection": "6"
70
+ },
71
+ {
72
+ "name": "quotes string value with only spaces",
73
+ "input": {
74
+ "text": " "
75
+ },
76
+ "expected": "text: \" \"",
77
+ "specSection": "6"
78
+ },
79
+ {
80
+ "name": "quotes string value that looks like true",
81
+ "input": {
82
+ "v": "true"
83
+ },
84
+ "expected": "v: \"true\"",
85
+ "specSection": "6"
86
+ },
87
+ {
88
+ "name": "quotes string value that looks like number",
89
+ "input": {
90
+ "v": "42"
91
+ },
92
+ "expected": "v: \"42\"",
93
+ "specSection": "6"
94
+ },
95
+ {
96
+ "name": "quotes string value that looks like negative decimal",
97
+ "input": {
98
+ "v": "-7.5"
99
+ },
100
+ "expected": "v: \"-7.5\"",
101
+ "specSection": "6"
102
+ },
103
+ {
104
+ "name": "quotes key with colon",
105
+ "input": {
106
+ "order:id": 7
107
+ },
108
+ "expected": "\"order:id\": 7",
109
+ "specSection": "6"
110
+ },
111
+ {
112
+ "name": "quotes key with brackets",
113
+ "input": {
114
+ "[index]": 5
115
+ },
116
+ "expected": "\"[index]\": 5",
117
+ "specSection": "6"
118
+ },
119
+ {
120
+ "name": "quotes key with braces",
121
+ "input": {
122
+ "{key}": 5
123
+ },
124
+ "expected": "\"{key}\": 5",
125
+ "specSection": "6"
126
+ },
127
+ {
128
+ "name": "quotes key with comma",
129
+ "input": {
130
+ "a,b": 1
131
+ },
132
+ "expected": "\"a,b\": 1",
133
+ "specSection": "6"
134
+ },
135
+ {
136
+ "name": "quotes key with spaces",
137
+ "input": {
138
+ "full name": "Ada"
139
+ },
140
+ "expected": "\"full name\": Ada",
141
+ "specSection": "6"
142
+ },
143
+ {
144
+ "name": "quotes key with leading hyphen",
145
+ "input": {
146
+ "-lead": 1
147
+ },
148
+ "expected": "\"-lead\": 1",
149
+ "specSection": "6"
150
+ },
151
+ {
152
+ "name": "quotes key with leading and trailing spaces",
153
+ "input": {
154
+ " a ": 1
155
+ },
156
+ "expected": "\" a \": 1",
157
+ "specSection": "6"
158
+ },
159
+ {
160
+ "name": "quotes numeric key",
161
+ "input": {
162
+ "123": "x"
163
+ },
164
+ "expected": "\"123\": x",
165
+ "specSection": "6"
166
+ },
167
+ {
168
+ "name": "quotes empty string key",
169
+ "input": {
170
+ "": 1
171
+ },
172
+ "expected": "\"\": 1",
173
+ "specSection": "6"
174
+ },
175
+ {
176
+ "name": "escapes newline in key",
177
+ "input": {
178
+ "line\nbreak": 1
179
+ },
180
+ "expected": "\"line\\nbreak\": 1",
181
+ "specSection": "6"
182
+ },
183
+ {
184
+ "name": "escapes tab in key",
185
+ "input": {
186
+ "tab\there": 2
187
+ },
188
+ "expected": "\"tab\\there\": 2",
189
+ "specSection": "6"
190
+ },
191
+ {
192
+ "name": "escapes quotes in key",
193
+ "input": {
194
+ "he said \"hi\"": 1
195
+ },
196
+ "expected": "\"he said \\\"hi\\\"\": 1",
197
+ "specSection": "6"
198
+ },
199
+ {
200
+ "name": "encodes deeply nested objects",
201
+ "input": {
202
+ "a": {
203
+ "b": {
204
+ "c": "deep"
205
+ }
206
+ }
207
+ },
208
+ "expected": "a:\n b:\n c: deep",
209
+ "specSection": "6"
210
+ },
211
+ {
212
+ "name": "encodes empty nested object",
213
+ "input": {
214
+ "user": {}
215
+ },
216
+ "expected": "user:",
217
+ "specSection": "6"
218
+ }
219
+ ]
220
+ }
@@ -0,0 +1,88 @@
1
+ {
2
+ "version": "1.3",
3
+ "category": "encode",
4
+ "description": "Encoding options - lengthMarker option and combinations with delimiters",
5
+ "tests": [
6
+ {
7
+ "name": "adds length marker to primitive arrays",
8
+ "input": {
9
+ "tags": ["reading", "gaming", "coding"]
10
+ },
11
+ "expected": "tags[#3]: reading,gaming,coding",
12
+ "options": {
13
+ "lengthMarker": "#"
14
+ },
15
+ "specSection": "3"
16
+ },
17
+ {
18
+ "name": "adds length marker to empty arrays",
19
+ "input": {
20
+ "items": []
21
+ },
22
+ "expected": "items[#0]:",
23
+ "options": {
24
+ "lengthMarker": "#"
25
+ },
26
+ "specSection": "3"
27
+ },
28
+ {
29
+ "name": "adds length marker to tabular arrays",
30
+ "input": {
31
+ "items": [
32
+ { "sku": "A1", "qty": 2, "price": 9.99 },
33
+ { "sku": "B2", "qty": 1, "price": 14.5 }
34
+ ]
35
+ },
36
+ "expected": "items[#2]{sku,qty,price}:\n A1,2,9.99\n B2,1,14.5",
37
+ "options": {
38
+ "lengthMarker": "#"
39
+ },
40
+ "specSection": "3"
41
+ },
42
+ {
43
+ "name": "adds length marker to nested arrays",
44
+ "input": {
45
+ "pairs": [["a", "b"], ["c", "d"]]
46
+ },
47
+ "expected": "pairs[#2]:\n - [#2]: a,b\n - [#2]: c,d",
48
+ "options": {
49
+ "lengthMarker": "#"
50
+ },
51
+ "specSection": "3"
52
+ },
53
+ {
54
+ "name": "combines length marker with pipe delimiter",
55
+ "input": {
56
+ "tags": ["reading", "gaming", "coding"]
57
+ },
58
+ "expected": "tags[#3|]: reading|gaming|coding",
59
+ "options": {
60
+ "lengthMarker": "#",
61
+ "delimiter": "|"
62
+ },
63
+ "specSection": "3"
64
+ },
65
+ {
66
+ "name": "combines length marker with tab delimiter",
67
+ "input": {
68
+ "tags": ["reading", "gaming", "coding"]
69
+ },
70
+ "expected": "tags[#3\t]: reading\tgaming\tcoding",
71
+ "options": {
72
+ "lengthMarker": "#",
73
+ "delimiter": "\t"
74
+ },
75
+ "specSection": "3"
76
+ },
77
+ {
78
+ "name": "default lengthMarker is empty (no marker)",
79
+ "input": {
80
+ "tags": ["reading", "gaming", "coding"]
81
+ },
82
+ "expected": "tags[3]: reading,gaming,coding",
83
+ "options": {},
84
+ "specSection": "3",
85
+ "note": "Default behavior without lengthMarker option"
86
+ }
87
+ ]
88
+ }
@@ -0,0 +1,226 @@
1
+ {
2
+ "version": "1.3",
3
+ "category": "encode",
4
+ "description": "Primitive value encoding - strings, numbers, booleans, null",
5
+ "tests": [
6
+ {
7
+ "name": "encodes safe strings without quotes",
8
+ "input": "hello",
9
+ "expected": "hello",
10
+ "specSection": "5"
11
+ },
12
+ {
13
+ "name": "encodes safe string with underscore and numbers",
14
+ "input": "Ada_99",
15
+ "expected": "Ada_99",
16
+ "specSection": "5"
17
+ },
18
+ {
19
+ "name": "quotes empty string",
20
+ "input": "",
21
+ "expected": "\"\"",
22
+ "specSection": "5"
23
+ },
24
+ {
25
+ "name": "quotes string that looks like true",
26
+ "input": "true",
27
+ "expected": "\"true\"",
28
+ "specSection": "5",
29
+ "note": "String representation of boolean must be quoted"
30
+ },
31
+ {
32
+ "name": "quotes string that looks like false",
33
+ "input": "false",
34
+ "expected": "\"false\"",
35
+ "specSection": "5"
36
+ },
37
+ {
38
+ "name": "quotes string that looks like null",
39
+ "input": "null",
40
+ "expected": "\"null\"",
41
+ "specSection": "5"
42
+ },
43
+ {
44
+ "name": "quotes string that looks like integer",
45
+ "input": "42",
46
+ "expected": "\"42\"",
47
+ "specSection": "5"
48
+ },
49
+ {
50
+ "name": "quotes string that looks like negative decimal",
51
+ "input": "-3.14",
52
+ "expected": "\"-3.14\"",
53
+ "specSection": "5"
54
+ },
55
+ {
56
+ "name": "quotes string that looks like scientific notation",
57
+ "input": "1e-6",
58
+ "expected": "\"1e-6\"",
59
+ "specSection": "5"
60
+ },
61
+ {
62
+ "name": "quotes string with leading zero",
63
+ "input": "05",
64
+ "expected": "\"05\"",
65
+ "specSection": "5",
66
+ "note": "Leading zeros make it non-numeric"
67
+ },
68
+ {
69
+ "name": "escapes newline in string",
70
+ "input": "line1\nline2",
71
+ "expected": "\"line1\\nline2\"",
72
+ "specSection": "5"
73
+ },
74
+ {
75
+ "name": "escapes tab in string",
76
+ "input": "tab\there",
77
+ "expected": "\"tab\\there\"",
78
+ "specSection": "5"
79
+ },
80
+ {
81
+ "name": "escapes carriage return in string",
82
+ "input": "return\rcarriage",
83
+ "expected": "\"return\\rcarriage\"",
84
+ "specSection": "5"
85
+ },
86
+ {
87
+ "name": "escapes backslash in string",
88
+ "input": "C:\\Users\\path",
89
+ "expected": "\"C:\\\\Users\\\\path\"",
90
+ "specSection": "5"
91
+ },
92
+ {
93
+ "name": "quotes string with array-like syntax",
94
+ "input": "[3]: x,y",
95
+ "expected": "\"[3]: x,y\"",
96
+ "specSection": "5",
97
+ "note": "Looks like array header"
98
+ },
99
+ {
100
+ "name": "quotes string starting with hyphen-space",
101
+ "input": "- item",
102
+ "expected": "\"- item\"",
103
+ "specSection": "5",
104
+ "note": "Looks like list item marker"
105
+ },
106
+ {
107
+ "name": "quotes string with bracket notation",
108
+ "input": "[test]",
109
+ "expected": "\"[test]\"",
110
+ "specSection": "5"
111
+ },
112
+ {
113
+ "name": "quotes string with brace notation",
114
+ "input": "{key}",
115
+ "expected": "\"{key}\"",
116
+ "specSection": "5"
117
+ },
118
+ {
119
+ "name": "encodes Unicode string without quotes",
120
+ "input": "café",
121
+ "expected": "café",
122
+ "specSection": "5"
123
+ },
124
+ {
125
+ "name": "encodes Chinese characters without quotes",
126
+ "input": "你好",
127
+ "expected": "你好",
128
+ "specSection": "5"
129
+ },
130
+ {
131
+ "name": "encodes emoji without quotes",
132
+ "input": "🚀",
133
+ "expected": "🚀",
134
+ "specSection": "5"
135
+ },
136
+ {
137
+ "name": "encodes string with emoji and spaces",
138
+ "input": "hello 👋 world",
139
+ "expected": "hello 👋 world",
140
+ "specSection": "5"
141
+ },
142
+ {
143
+ "name": "encodes positive integer",
144
+ "input": 42,
145
+ "expected": "42",
146
+ "specSection": "5"
147
+ },
148
+ {
149
+ "name": "encodes decimal number",
150
+ "input": 3.14,
151
+ "expected": "3.14",
152
+ "specSection": "5"
153
+ },
154
+ {
155
+ "name": "encodes negative integer",
156
+ "input": -7,
157
+ "expected": "-7",
158
+ "specSection": "5"
159
+ },
160
+ {
161
+ "name": "encodes zero",
162
+ "input": 0,
163
+ "expected": "0",
164
+ "specSection": "5"
165
+ },
166
+ {
167
+ "name": "encodes negative zero as zero",
168
+ "input": -0,
169
+ "expected": "0",
170
+ "specSection": "5",
171
+ "note": "Negative zero normalizes to zero"
172
+ },
173
+ {
174
+ "name": "encodes scientific notation as decimal",
175
+ "input": 1000000,
176
+ "expected": "1000000",
177
+ "specSection": "5",
178
+ "note": "1e6 input, but represented as decimal"
179
+ },
180
+ {
181
+ "name": "encodes small decimal from scientific notation",
182
+ "input": 0.000001,
183
+ "expected": "0.000001",
184
+ "specSection": "5",
185
+ "note": "1e-6 input"
186
+ },
187
+ {
188
+ "name": "encodes large number",
189
+ "input": 100000000000000000000,
190
+ "expected": "100000000000000000000",
191
+ "specSection": "5",
192
+ "note": "1e20"
193
+ },
194
+ {
195
+ "name": "encodes MAX_SAFE_INTEGER",
196
+ "input": 9007199254740991,
197
+ "expected": "9007199254740991",
198
+ "specSection": "5"
199
+ },
200
+ {
201
+ "name": "encodes repeating decimal with full precision",
202
+ "input": 0.3333333333333333,
203
+ "expected": "0.3333333333333333",
204
+ "specSection": "5",
205
+ "note": "Result of 1/3 in JavaScript"
206
+ },
207
+ {
208
+ "name": "encodes true",
209
+ "input": true,
210
+ "expected": "true",
211
+ "specSection": "5"
212
+ },
213
+ {
214
+ "name": "encodes false",
215
+ "input": false,
216
+ "expected": "false",
217
+ "specSection": "5"
218
+ },
219
+ {
220
+ "name": "encodes null",
221
+ "input": null,
222
+ "expected": "null",
223
+ "specSection": "5"
224
+ }
225
+ ]
226
+ }
@@ -0,0 +1,29 @@
1
+ {
2
+ "version": "1.3",
3
+ "category": "encode",
4
+ "description": "Whitespace and formatting invariants - no trailing spaces, no trailing newlines",
5
+ "tests": [
6
+ {
7
+ "name": "produces no trailing newline at end of output",
8
+ "input": {
9
+ "id": 123
10
+ },
11
+ "expected": "id: 123",
12
+ "specSection": "4",
13
+ "note": "Output should not end with newline character"
14
+ },
15
+ {
16
+ "name": "maintains proper indentation for nested structures",
17
+ "input": {
18
+ "user": {
19
+ "id": 123,
20
+ "name": "Ada"
21
+ },
22
+ "items": ["a", "b"]
23
+ },
24
+ "expected": "user:\n id: 123\n name: Ada\nitems[2]: a,b",
25
+ "specSection": "4",
26
+ "note": "2-space indentation, no trailing spaces on any line"
27
+ }
28
+ ]
29
+ }
@@ -0,0 +1,106 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "$id": "https://toon-format.org/schemas/test-fixture.json",
4
+ "title": "TOON Test Fixture",
5
+ "description": "Schema for language-agnostic TOON test fixtures",
6
+ "type": "object",
7
+ "required": ["version", "category", "description", "tests"],
8
+ "properties": {
9
+ "version": {
10
+ "type": "string",
11
+ "description": "TOON specification version these tests target",
12
+ "pattern": "^\\d+\\.\\d+$",
13
+ "examples": ["1.0", "1.3"]
14
+ },
15
+ "category": {
16
+ "type": "string",
17
+ "enum": ["encode", "decode"],
18
+ "description": "Test category: encode (JSON → TOON) or decode (TOON → JSON)"
19
+ },
20
+ "description": {
21
+ "type": "string",
22
+ "description": "Brief description of what this fixture file tests",
23
+ "minLength": 1,
24
+ "examples": ["Primitives - String Encoding", "Tabular Arrays - Decoding"]
25
+ },
26
+ "tests": {
27
+ "type": "array",
28
+ "description": "Array of test cases",
29
+ "minItems": 1,
30
+ "items": {
31
+ "type": "object",
32
+ "required": ["name", "input", "expected"],
33
+ "properties": {
34
+ "name": {
35
+ "type": "string",
36
+ "description": "Descriptive test name explaining what is being validated",
37
+ "minLength": 1,
38
+ "examples": [
39
+ "encodes safe strings without quotes",
40
+ "throws on array length mismatch"
41
+ ]
42
+ },
43
+ "input": {
44
+ "description": "Input value - JSON value for encode tests, TOON string for decode tests"
45
+ },
46
+ "expected": {
47
+ "description": "Expected output - TOON string for encode tests, JSON value for decode tests"
48
+ },
49
+ "shouldError": {
50
+ "type": "boolean",
51
+ "description": "If true, this test expects an error to be thrown",
52
+ "default": false
53
+ },
54
+ "options": {
55
+ "type": "object",
56
+ "description": "Encoding or decoding options",
57
+ "properties": {
58
+ "delimiter": {
59
+ "type": "string",
60
+ "enum": [",", "\t", "|"],
61
+ "description": "Array delimiter (encode only)",
62
+ "default": ","
63
+ },
64
+ "indent": {
65
+ "type": "integer",
66
+ "description": "Number of spaces per indentation level",
67
+ "minimum": 1,
68
+ "default": 2
69
+ },
70
+ "lengthMarker": {
71
+ "type": "string",
72
+ "enum": ["#", ""],
73
+ "description": "Optional marker to prefix array lengths (encode only)",
74
+ "default": ""
75
+ },
76
+ "strict": {
77
+ "type": "boolean",
78
+ "description": "Enable strict validation (decode only)",
79
+ "default": true
80
+ }
81
+ },
82
+ "additionalProperties": false
83
+ },
84
+ "specSection": {
85
+ "type": "string",
86
+ "description": "Reference to relevant specification section",
87
+ "pattern": "^§?\\d+(\\.\\d+)*$",
88
+ "examples": ["6", "7.2", "§7.2", "9"]
89
+ },
90
+ "note": {
91
+ "type": "string",
92
+ "description": "Optional note explaining special cases or edge case behavior"
93
+ },
94
+ "minSpecVersion": {
95
+ "type": "string",
96
+ "description": "Minimum specification version required for this test",
97
+ "pattern": "^\\d+\\.\\d+$",
98
+ "examples": ["1.0", "1.3"]
99
+ }
100
+ },
101
+ "additionalProperties": false
102
+ }
103
+ }
104
+ },
105
+ "additionalProperties": false
106
+ }