Registry / RepositoryTypeScriptRustPython
Rollpie
ReadmeFiles
Versions
Info
Download
0.1.023.4 KB2026-09-14
Version
0.1.0
Copyright
Rollpie, Irohabook
Publisher
math
Published
2026-09-14
Size
23.4 KB
Downloads
1
Checksum
298d198fbc3fc0aecbe6668651a0d3beefb7ff2d1a098483af80cc924d925bdd
Dependencies
None

parse.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
//! 壊れた JSON で、エラーの位置と文言が合っているかを確かめる。

use simple_json_formatter::{Error, Options, format};


fn parse_error(source: &str) -> Error {
	format(source, &Options::default()).unwrap_err()
}


/// 行と列だけを見る
fn position(source: &str) -> (usize, usize) {
	let error = parse_error(source);
	(error.line, error.column)
}


#[test]
fn empty_input() {
	assert_eq!(parse_error("").message, "入力が空です");
	assert_eq!(parse_error(" \n ").message, "入力が空です");
}


#[test]
fn trailing_comma() {
	let error = parse_error(r#"{"a":1,}"#);
	assert_eq!((error.line, error.column), (1, 8));
	assert_eq!(error.message, "キーが必要なところに '}' があります");

	let error = parse_error("[1,2,]");
	assert_eq!((error.line, error.column), (1, 6));
	assert_eq!(error.message, "値が必要なところに ']' があります");
}


#[test]
fn unknown_word_on_second_line() {
	let error = parse_error("{\n  \"a\": tru\n}");
	assert_eq!((error.line, error.column), (2, 8));
	assert_eq!(error.message, "tru は JSON の値ではありません");
	assert_eq!(error.to_string(), "2 行 8 列: tru は JSON の値ではありません");

	assert_eq!(parse_error("[NaN]").message, "NaN は JSON の値ではありません");
}


#[test]
fn column_counts_characters() {
	// 「名前」は 6 バイトだが 2 列として数える
	assert_eq!(position(r#"{"名前": x}"#), (1, 8));
}


#[test]
fn missing_separator() {
	assert_eq!(parse_error("[1 2]").message, "配列の要素の後ろに '2' があります。, か ] が必要です");
	assert_eq!(parse_error(r#"{"a" 1}"#).message, "キーの後ろに '1' があります。: が必要です");
	assert_eq!(
		parse_error(r#"{"a":1 "b":2}"#).message,
		"オブジェクトの値の後ろに '\"' があります。, か } が必要です"
	);
	assert_eq!(parse_error("{1:2}").message, "キーが必要なところに '1' があります");
}


#[test]
fn comment_is_rejected() {
	assert_eq!(position("[1 // x\n]"), (1, 4));
}


#[test]
fn unexpected_end() {
	assert_eq!(parse_error("[1,").message, "JSON が途中で終わっています");
	assert_eq!(parse_error(r#"{"a":"#).message, "JSON が途中で終わっています");
	assert_eq!(position("[1,"), (1, 4));
}


#[test]
fn trailing_garbage() {
	let error = parse_error("[1] 2");
	assert_eq!((error.line, error.column), (1, 5));
	assert_eq!(error.message, "値の後ろに余計な '2' があります");
}


#[test]
fn unclosed_string_points_to_the_quote() {
	let error = parse_error("[\"abc");
	assert_eq!((error.line, error.column), (1, 2));
	assert_eq!(error.message, "文字列が閉じていません");
}


#[test]
fn raw_control_char_in_string() {
	let error = parse_error("[\"a\nb\"]");
	assert_eq!((error.line, error.column), (1, 4));
	assert_eq!(error.message, "文字列の中に制御文字 U+000A がそのまま入っています");
}


#[test]
fn bad_escape() {
	let error = parse_error(r#"["a\x"]"#);
	assert_eq!((error.line, error.column), (1, 4));
	assert_eq!(error.message, "\\ の後ろに 'x' は置けません");

	assert_eq!(parse_error(r#"["\u12"]"#).message, "\\u の後ろには 16 進数 4 桁が必要です");
}


#[test]
fn lone_surrogate() {
	assert_eq!(parse_error(r#"["\ud800"]"#).message, "対になっていないサロゲート \\uD800 です");
	assert_eq!(parse_error(r#"["\udc00"]"#).message, "対になっていないサロゲート \\uDC00 です");
	assert_eq!(parse_error("[\"\\ud800\\u0041\"]").message, "対になっていないサロゲート \\uD800 です");
}


#[test]
fn bad_numbers() {
	assert_eq!(parse_error("[01]").message, "数値の先頭に余計な 0 があります");
	assert_eq!(parse_error("[-]").message, "- の後ろに数字がありません");
	assert_eq!(parse_error("[1.]").message, "小数点の後ろに数字がありません");
	assert_eq!(parse_error("[1e]").message, "指数の後ろに数字がありません");
	assert_eq!(parse_error("[.5]").message, "値が必要なところに '.' があります");
	assert_eq!(parse_error("[+1]").message, "値が必要なところに '+' があります");
}


#[test]
fn long_word_is_shortened() {
	// 未知の語は先頭の 20 文字だけを出す。入力が長くても、エラーの文言は長くならない
	let source = "[".to_string() + &"a".repeat(10_000) + "]";
	assert_eq!(parse_error(&source).message, "aaaaaaaaaaaaaaaaaaaa... は JSON の値ではありません");
	assert_eq!(parse_error("[abcdefghijklmnopqrst]").message, "abcdefghijklmnopqrst は JSON の値ではありません");
}


#[test]
fn invisible_char_is_shown_as_code_point() {
	// 表示の向きを変える文字、幅のない空白、改行ではない区切り、結合文字は U+XXXX で出す
	assert_eq!(parse_error("[1 \u{202e}]").message, "配列の要素の後ろに U+202E があります。, か ] が必要です");
	assert_eq!(parse_error("[\u{200b}]").message, "値が必要なところに U+200B があります");
	assert_eq!(parse_error("[\u{a0}1]").message, "値が必要なところに U+00A0 があります");
	assert_eq!(parse_error("[\u{3000}]").message, "値が必要なところに U+3000 があります");
	assert_eq!(parse_error("[\u{2028}]").message, "値が必要なところに U+2028 があります");
	assert_eq!(parse_error("[\u{301}]").message, "値が必要なところに U+0301 があります");
	assert_eq!(parse_error("[\"\\\u{202e}\"]").message, "\\ の後ろに U+202E は置けません");

	// 見える文字は、そのまま出す
	assert_eq!(parse_error("[あ]").message, "値が必要なところに 'あ' があります");
	assert_eq!(parse_error("[1 \"]").message, "配列の要素の後ろに '\"' があります。, か ] が必要です");
}


#[test]
fn nesting_limit() {
	let deep = "[".repeat(128) + &"]".repeat(128);
	assert!(format(&deep, &Options::default()).is_ok());

	let too_deep = "[".repeat(129) + &"]".repeat(129);
	let error = parse_error(&too_deep);
	assert_eq!((error.line, error.column), (1, 129));
	assert_eq!(error.message, "入れ子が深すぎます。128 段までです");
}