1 ;;; json-tests.el --- unit tests for json.c -*- lexical-binding: t; -*-
3 ;; Copyright (C) 2017-2018 Free Software Foundation, Inc.
5 ;; This file is part of GNU Emacs.
7 ;; GNU Emacs is free software: you can redistribute it and/or modify
8 ;; it under the terms of the GNU General Public License as published by
9 ;; the Free Software Foundation, either version 3 of the License, or
10 ;; (at your option) any later version.
12 ;; GNU Emacs is distributed in the hope that it will be useful,
13 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
14 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 ;; GNU General Public License for more details.
17 ;; You should have received a copy of the GNU General Public License
18 ;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
22 ;; Unit tests for src/json.c.
29 (declare-function json-serialize
"json.c" (object))
30 (declare-function json-insert
"json.c" (object))
31 (declare-function json-parse-string
"json.c" (string &rest args
))
32 (declare-function json-parse-buffer
"json.c" (&rest args
))
34 (define-error 'json-tests--error
"JSON test error")
36 (ert-deftest json-serialize
/roundtrip
()
37 (skip-unless (fboundp 'json-serialize
))
38 ;; The noncharacter U+FFFF should be passed through,
39 ;; cf. https://www.unicode.org/faq/private_use.html#noncharacters.
40 (let ((lisp [:null
:false t
0 123 -
456 3.75 "abc\uFFFFαβγ𝔸𝐁𝖢\"\\"])
41 (json "[null,false,true,0,123,-456,3.75,\"abc\uFFFFαβγ𝔸𝐁𝖢\\\"\\\\\"]"))
42 (should (equal (json-serialize lisp
) json
))
45 (should (equal (buffer-string) json
))
47 (should (equal (json-parse-string json
) lisp
))
51 (should (equal (json-parse-buffer) lisp
))
54 (ert-deftest json-serialize
/object
()
55 (skip-unless (fboundp 'json-serialize
))
56 (let ((table (make-hash-table :test
#'equal
)))
57 (puthash "abc" [1 2 t
] table
)
58 (puthash "def" :null table
)
59 (should (equal (json-serialize table
)
60 "{\"abc\":[1,2,true],\"def\":null}")))
61 (should (equal (json-serialize '((abc .
[1 2 t
]) (def .
:null
)))
62 "{\"abc\":[1,2,true],\"def\":null}"))
63 (should (equal (json-serialize nil
) "{}"))
64 (should (equal (json-serialize '((abc))) "{\"abc\":{}}"))
65 (should (equal (json-serialize '((a .
1) (b .
2) (a .
3)))
67 (should-error (json-serialize '(abc)) :type
'wrong-type-argument
)
68 (should-error (json-serialize '((a 1))) :type
'wrong-type-argument
)
69 (should-error (json-serialize '((1 .
2))) :type
'wrong-type-argument
)
70 (should-error (json-serialize '((a .
1) . b
)) :type
'wrong-type-argument
)
71 (should-error (json-serialize '#1=((a .
1) .
#1#)) :type
'circular-list
)
72 (should-error (json-serialize '(#1=(a #1#)))))
74 (ert-deftest json-serialize
/object-with-duplicate-keys
()
75 (skip-unless (fboundp 'json-serialize
))
76 (let ((table (make-hash-table :test
#'eq
)))
77 (puthash (copy-sequence "abc") [1 2 t
] table
)
78 (puthash (copy-sequence "abc") :null table
)
79 (should (equal (hash-table-count table
) 2))
80 (should-error (json-serialize table
) :type
'wrong-type-argument
)))
82 (ert-deftest json-parse-string
/object
()
83 (skip-unless (fboundp 'json-parse-string
))
85 "{ \"abc\" : [1, 2, true], \"def\" : null, \"abc\" : [9, false] }\n"))
86 (let ((actual (json-parse-string input
)))
87 (should (hash-table-p actual
))
88 (should (equal (hash-table-count actual
) 2))
89 (should (equal (cl-sort (map-pairs actual
) #'string
< :key
#'car
)
90 '(("abc" .
[9 :false
]) ("def" .
:null
)))))
91 (should (equal (json-parse-string input
:object-type
'alist
)
92 '((abc .
[9 :false
]) (def .
:null
))))))
94 (ert-deftest json-parse-string
/string
()
95 (skip-unless (fboundp 'json-parse-string
))
96 (should-error (json-parse-string "[\"formfeed\f\"]") :type
'json-parse-error
)
97 (should (equal (json-parse-string "[\"foo \\\"bar\\\"\"]") ["foo \"bar\""]))
98 (should (equal (json-parse-string "[\"abcαβγ\"]") ["abcαβγ"]))
99 (should (equal (json-parse-string "[\"\\nasd\\u0444\\u044b\\u0432fgh\\t\"]")
101 (should (equal (json-parse-string "[\"\\uD834\\uDD1E\"]") ["\U0001D11E"]))
102 (should-error (json-parse-string "foo") :type
'json-parse-error
)
103 ;; FIXME: Is this the right behavior?
104 (should (equal (json-parse-string "[\"\u00C4\xC3\x84\"]") ["\u00C4\u00C4"])))
106 (ert-deftest json-serialize
/string
()
107 (skip-unless (fboundp 'json-serialize
))
108 (should (equal (json-serialize ["foo"]) "[\"foo\"]"))
109 (should (equal (json-serialize ["a\n\fb"]) "[\"a\\n\\fb\"]"))
110 (should (equal (json-serialize ["\nasdфыв\u001f\u007ffgh\t"])
111 "[\"\\nasdфыв\\u001F\u007ffgh\\t\"]"))
112 (should (equal (json-serialize ["a\0b"]) "[\"a\\u0000b\"]"))
113 ;; FIXME: Is this the right behavior?
114 (should (equal (json-serialize ["\u00C4\xC3\x84"]) "[\"\u00C4\u00C4\"]")))
116 (ert-deftest json-serialize
/invalid-unicode
()
117 (skip-unless (fboundp 'json-serialize
))
118 (should-error (json-serialize ["a\uDBBBb"]) :type
'wrong-type-argument
)
119 (should-error (json-serialize ["u\x110000v"]) :type
'wrong-type-argument
)
120 (should-error (json-serialize ["u\x3FFFFFv"]) :type
'wrong-type-argument
)
121 (should-error (json-serialize ["u\xCCv"]) :type
'wrong-type-argument
)
122 (should-error (json-serialize ["u\u00C4\xCCv"]) :type
'wrong-type-argument
))
124 (ert-deftest json-parse-string
/null
()
125 (skip-unless (fboundp 'json-parse-string
))
126 (should-error (json-parse-string "\x00") :type
'wrong-type-argument
)
127 ;; FIXME: Reconsider whether this is the right behavior.
128 (should-error (json-parse-string "[a\\u0000b]") :type
'json-parse-error
))
130 (ert-deftest json-parse-string
/invalid-unicode
()
132 https://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt.
133 Test with both unibyte and multibyte strings."
134 (skip-unless (fboundp 'json-parse-string
))
135 ;; Invalid UTF-8 code unit sequences.
136 (should-error (json-parse-string "[\"\x80\"]") :type
'json-parse-error
)
137 (should-error (json-parse-string "[\"\u00C4\x80\"]") :type
'json-parse-error
)
138 (should-error (json-parse-string "[\"\xBF\"]") :type
'json-parse-error
)
139 (should-error (json-parse-string "[\"\u00C4\xBF\"]") :type
'json-parse-error
)
140 (should-error (json-parse-string "[\"\xFE\"]") :type
'json-parse-error
)
141 (should-error (json-parse-string "[\"\u00C4\xFE\"]") :type
'json-parse-error
)
142 (should-error (json-parse-string "[\"\xC0\xAF\"]") :type
'json-parse-error
)
143 (should-error (json-parse-string "[\"\u00C4\xC0\xAF\"]")
144 :type
'json-parse-error
)
145 (should-error (json-parse-string "[\"\u00C4\xC0\x80\"]")
146 :type
'json-parse-error
)
148 (should-error (json-parse-string "[\"\uDB7F\"]")
149 :type
'json-parse-error
)
150 (should-error (json-parse-string "[\"\xED\xAD\xBF\"]")
151 :type
'json-parse-error
)
152 (should-error (json-parse-string "[\"\u00C4\xED\xAD\xBF\"]")
153 :type
'json-parse-error
)
154 (should-error (json-parse-string "[\"\uDB7F\uDFFF\"]")
155 :type
'json-parse-error
)
156 (should-error (json-parse-string "[\"\xED\xAD\xBF\xED\xBF\xBF\"]")
157 :type
'json-parse-error
)
158 (should-error (json-parse-string "[\"\u00C4\xED\xAD\xBF\xED\xBF\xBF\"]")
159 :type
'json-parse-error
))
161 (ert-deftest json-parse-string
/incomplete
()
162 (skip-unless (fboundp 'json-parse-string
))
163 (should-error (json-parse-string "[123") :type
'json-end-of-file
))
165 (ert-deftest json-parse-string
/trailing
()
166 (skip-unless (fboundp 'json-parse-string
))
167 (should-error (json-parse-string "[123] [456]") :type
'json-trailing-content
))
169 (ert-deftest json-parse-buffer
/incomplete
()
170 (skip-unless (fboundp 'json-parse-buffer
))
174 (should-error (json-parse-buffer) :type
'json-end-of-file
)
177 (ert-deftest json-parse-buffer
/trailing
()
178 (skip-unless (fboundp 'json-parse-buffer
))
180 (insert "[123] [456]")
182 (should (equal (json-parse-buffer) [123]))
184 (should (looking-at-p (rx " [456]" eos)))))
186 (ert-deftest json-insert/signal ()
187 (skip-unless (fboundp 'json-insert))
190 (add-hook 'after-change-functions
191 (lambda (_begin _end _length)
193 (signal 'json-tests--error
194 '("Error in `after-change-functions'")))
197 (json-insert '((a . "b") (c . 123) (d . [1 2 t :false])))
198 :type 'json-tests--error)
199 (should (equal calls 1)))))
201 (ert-deftest json-insert/throw ()
202 (skip-unless (fboundp 'json-insert))
205 (add-hook 'after-change-functions
206 (lambda (_begin _end _length)
208 (throw 'test-tag 'throw-value))
212 (json-insert '((a . "b") (c . 123) (d . [1 2 t :false]))))
214 (should (equal calls 1)))))
216 (provide 'json-tests)
217 ;;; json-tests.el ends here