Subject: bug#21985: closed (Re: bug#21985: 25.0.50; PATCH] Extend the test suite for json.el)

From: [email-masked] (GNU bug Tracking System)
Date: Tue, 24 Nov 2015 22:17:02 +0000

Your bug report

#21985: 25.0.50; PATCH] Extend the test suite for json.el

which was filed against the emacs package, has been closed.

The explanation is attached below, along with your original report.
If you require more details, please reply to [email-masked].

-- 
21985: http://debbugs.gnu.org/cgi/bugreport.cgi?bug=21985
GNU Bug Tracking System
Contact [email-masked] with problems

Subject: Re: bug#21985: 25.0.50; PATCH] Extend the test suite for json.el
From: Simen Heggestøyl <[email-masked]>
To: Dmitry Gutov <[email-masked]>
Cc: [email-masked]
Date: Tue, 24 Nov 2015 23:16:31 +0100
List-Id: <debbugs-submit.debbugs.gnu.org>

On Tue, Nov 24, 2015 at 9:53 PM, Dmitry Gutov <[email-masked]> wrote:
> On 11/24/2015 10:25 PM, Simen Heggestøyl wrote:
> 
>> I've attached an updated patch.
> 
> Please go ahead, you obviously know what you're doing there.

Thanks, installed.

-- Simen

Subject: 25.0.50; PATCH] Extend the test suite for json.el
From: Simen Heggestøyl <[email-masked]>
To: [email-masked]
Cc: Dmitry Gutov <[email-masked]>
Date: Sun, 22 Nov 2015 22:30:19 +0100
List-Id: <debbugs-submit.debbugs.gnu.org>

Hi,

I've tried to strengthen the test suite for json.el a bit. Most of the
public functions have now received a corresponding test.

I was unsure how to best test `json-encode' without duplicating what
the other tests (`test-json-encode-string',
`test-json-encode-keyword', and so on) already do test.

-- Simen

>From 8eef0bf1c9af5fd1b14a4a6f7f6f37a240122547 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Simen=20Heggest=C3=B8yl?= <[email-masked]>
Date: Sat, 14 Nov 2015 17:54:38 +0100
Subject: [PATCH] Extend the test suite for json.el

* lisp/json.el (json-plist-p): Clarify docstring.

* test/automated/json-tests.el (json-tests--with-temp-buffer): New
macro.
(test-json-join, test-json-alist-p)
(test-json-plist-p, test-json-advance, test-json-peek)
(test-json-pop, test-json-skip-whitespace)
(test-json-read-keyword, test-json-encode-keyword)
(test-json-read-number, test-json-encode-number)
(test-json-read-escaped-char, test-json-read-string)
(test-json-encode-string, test-json-encode-key)
(test-json-new-object, test-json-add-to-object)
(test-json-read-object, test-json-encode-list)
(test-json-read-array, test-json-encode-array)
(test-json-read, test-json-read-from-string): New tests.
(json-read-simple-alist): Merged into `test-json-read-object'.
(json-encode-string-with-special-chars): Merged into
`test-json-encode-string'.
(json-read-string-with-special-chars): Split into
`test-json-encode-string' and `test-json-read-from-string'.
---
 lisp/json.el                 |   2 +-
 test/automated/json-tests.el | 290 +++++++++++++++++++++++++++++++++++++------
 2 files changed, 252 insertions(+), 40 deletions(-)

diff --git a/lisp/json.el b/lisp/json.el
index 0214a3e..85827b5 100644
--- a/lisp/json.el
+++ b/lisp/json.el
@@ -149,7 +149,7 @@ json-alist-p
   (null list))
 
 (defun json-plist-p (list)
-  "Non-null if and only if LIST is a plist."
+  "Non-null if and only if LIST is a plist with keyword keys."
   (while (consp list)
     (setq list (if (and (keywordp (car list))
                         (consp (cdr list)))
diff --git a/test/automated/json-tests.el b/test/automated/json-tests.el
index 8f0cd6f..6a6a18d 100644
--- a/test/automated/json-tests.el
+++ b/test/automated/json-tests.el
@@ -22,6 +22,38 @@
 (require 'ert)
 (require 'json)
 
+(defmacro json-tests--with-temp-buffer (content &rest body)
+  "Create a temporary buffer with CONTENT and evaluate BODY there.
+Point is moved to beginning of the buffer."
+  (declare (indent 1))
+  `(with-temp-buffer
+     (insert ,content)
+     (goto-char (point-min))
+     ,@body))
+
+;;; Utilities
+
+(ert-deftest test-json-join ()
+  (should (equal (json-join '() ", ")  ""))
+  (should (equal (json-join '("a" "b" "c") ", ")  "a, b, c")))
+
+(ert-deftest test-json-alist-p ()
+  (should (json-alist-p '()))
+  (should (json-alist-p '((a 1) (b 2) (c 3))))
+  (should (json-alist-p '((:a 1) (:b 2) (:c 3))))
+  (should (json-alist-p '(("a" 1) ("b" 2) ("c" 3))))
+  (should-not (json-alist-p '(:a :b :c)))
+  (should-not (json-alist-p '(:a 1 :b 2 :c 3)))
+  (should-not (json-alist-p '((:a 1) (:b 2) 3))))
+
+(ert-deftest test-json-plist-p ()
+  (should (json-plist-p '()))
+  (should (json-plist-p '(:a 1 :b 2 :c 3)))
+  (should-not (json-plist-p '(a 1 b 2 c 3)))
+  (should-not (json-plist-p '("a" 1 "b" 2 "c" 3)))
+  (should-not (json-plist-p '(:a :b :c)))
+  (should-not (json-plist-p '((:a 1) (:b 2) (:c 3)))))
+
 (ert-deftest test-json-plist-reverse ()
   (should (equal (json--plist-reverse '()) '()))
   (should (equal (json--plist-reverse '(:a 1)) '(:a 1)))
@@ -34,49 +66,32 @@
   (should (equal (json--plist-to-alist '(:a 1 :b 2 :c 3))
                  '((:a . 1) (:b . 2) (:c . 3)))))
 
-(ert-deftest test-json-encode-plist ()
-  (let ((plist '(:a 1 :b 2)))
-    (should (equal (json-encode plist) "{\"a\":1,\"b\":2}"))))
+(ert-deftest test-json-advance ()
+  (json-tests--with-temp-buffer "{ \"a\": 1 }"
+    (json-advance 0)
+    (should (= (point) (point-min)))
+    (json-advance 3)
+    (should (= (point) (+ (point-min) 3)))))
 
-(ert-deftest json-encode-simple-alist ()
-  (should (equal (json-encode '((a . 1)
-                                (b . 2)))
-                 "{\"a\":1,\"b\":2}")))
+(ert-deftest test-json-peek ()
+  (json-tests--with-temp-buffer ""
+    (should (eq (json-peek) :json-eof)))
+  (json-tests--with-temp-buffer "{ \"a\": 1 }"
+    (should (equal (json-peek) ?{))))
 
-(ert-deftest test-json-encode-hash-table ()
-  (let ((hash-table (make-hash-table))
-        (json-encoding-object-sort-predicate 'string<))
-    (puthash :a 1 hash-table)
-    (puthash :b 2 hash-table)
-    (puthash :c 3 hash-table)
-    (should (equal (json-encode hash-table)
-                   "{\"a\":1,\"b\":2,\"c\":3}"))))
+(ert-deftest test-json-pop ()
+  (json-tests--with-temp-buffer ""
+    (should-error (json-pop) :type 'json-end-of-file))
+  (json-tests--with-temp-buffer "{ \"a\": 1 }"
+    (should (equal (json-pop) ?{))
+    (should (= (point) (+ (point-min) 1)))))
 
-(ert-deftest test-json-encode-alist-with-sort-predicate ()
-  (let ((alist '((:c . 3) (:a . 1) (:b . 2)))
-        (json-encoding-object-sort-predicate 'string<))
-    (should (equal (json-encode alist) "{\"a\":1,\"b\":2,\"c\":3}"))))
+(ert-deftest test-json-skip-whitespace ()
+  (json-tests--with-temp-buffer "\t\r\n\f\b { \"a\": 1 }"
+    (json-skip-whitespace)
+    (should (equal (char-after (point)) ?{))))
 
-(ert-deftest test-json-encode-plist-with-sort-predicate ()
-  (let ((plist '(:c 3 :a 1 :b 2))
-        (json-encoding-object-sort-predicate 'string<))
-    (should (equal (json-encode plist) "{\"a\":1,\"b\":2,\"c\":3}"))))
-
-(ert-deftest json-read-simple-alist ()
-  (let ((json-object-type 'alist))
-    (should (equal (json-read-from-string "{\"a\": 1, \"b\": 2}")
-                   '((a . 1)
-                     (b . 2))))))
-
-(ert-deftest json-encode-string-with-special-chars ()
-  (should (equal (json-encode-string "a\n\fb")
-                 "\"a\\n\\fb\""))
-  (should (equal (json-encode-string "\nasdфыв\u001f\u007ffgh\t")
-                 "\"\\nasdфыв\\u001f\u007ffgh\\t\"")))
-
-(ert-deftest json-read-string-with-special-chars ()
-  (should (equal (json-read-from-string "\"\\nasd\\u0444\\u044b\\u0432fgh\\t\"")
-                 "\nasdфывfgh\t")))
+;;; Paths
 
 (ert-deftest test-json-path-to-position-with-objects ()
   (let* ((json-string "{\"foo\": {\"bar\": {\"baz\": \"value\"}}}")
@@ -97,5 +112,202 @@
          (matched-path (json-path-to-position 5 json-string)))
     (should (null matched-path))))
 
+;;; Keywords
+
+(ert-deftest test-json-read-keyword ()
+  (json-tests--with-temp-buffer "true"
+    (should (json-read-keyword "true")))
+  (json-tests--with-temp-buffer "true"
+    (should-error
+     (json-read-keyword "false") :type 'json-unknown-keyword))
+  (json-tests--with-temp-buffer "foo"
+    (should-error
+     (json-read-keyword "foo") :type 'json-unknown-keyword)))
+
+(ert-deftest test-json-encode-keyword ()
+  (should (equal (json-encode-keyword t) "true"))
+  (should (equal (json-encode-keyword json-false) "false"))
+  (should (equal (json-encode-keyword json-null) "null")))
+
+;;; Numbers
+
+(ert-deftest test-json-read-number ()
+  (json-tests--with-temp-buffer "3"
+    (should (= (json-read-number) 3)))
+  (json-tests--with-temp-buffer "-5"
+    (should (= (json-read-number) -5)))
+  (json-tests--with-temp-buffer "123.456"
+    (should (= (json-read-number) 123.456)))
+  (json-tests--with-temp-buffer "1e3"
+    (should (= (json-read-number) 1e3)))
+  (json-tests--with-temp-buffer "2e+3"
+    (should (= (json-read-number) 2e3)))
+  (json-tests--with-temp-buffer "3E3"
+    (should (= (json-read-number) 3e3)))
+  (json-tests--with-temp-buffer "1e-7"
+    (should (= (json-read-number) 1e-7)))
+  (json-tests--with-temp-buffer "abc"
+    (should-error (json-read-number) :type 'json-number-format)))
+
+(ert-deftest test-json-encode-number ()
+  (should (equal (json-encode-number 3) "3"))
+  (should (equal (json-encode-number -5) "-5"))
+  (should (equal (json-encode-number 123.456) "123.456")))
+
+;; Strings
+
+(ert-deftest test-json-read-escaped-char ()
+  (json-tests--with-temp-buffer "\\\""
+    (should (equal (json-read-escaped-char) ?\"))))
+
+(ert-deftest test-json-read-string ()
+  (json-tests--with-temp-buffer "\"foo \\\"bar\\\"\""
+    (should (equal (json-read-string) "foo \"bar\"")))
+  (json-tests--with-temp-buffer "\"abcαβγ\""
+    (should (equal (json-read-string) "abcαβγ")))
+  (json-tests--with-temp-buffer "\"\\nasd\\u0444\\u044b\\u0432fgh\\t\""
+    (should (equal (json-read-string) "\nasdфывfgh\t")))
+  (json-tests--with-temp-buffer "foo"
+    (should-error (json-read-string) :type 'json-string-format)))
+
+(ert-deftest test-json-encode-string ()
+  (should (equal (json-encode-string "foo") "\"foo\""))
+  (should (equal (json-encode-string "a\n\fb") "\"a\\n\\fb\""))
+  (should (equal (json-encode-string "\nasdфыв\u001f\u007ffgh\t")
+                 "\"\\nasdфыв\\u001f\u007ffgh\\t\"")))
+
+(ert-deftest test-json-encode-key ()
+  (should (equal (json-encode-key "foo") "\"foo\""))
+  (should (equal (json-encode-key 'foo) "\"foo\""))
+  (should (equal (json-encode-key :foo) "\"foo\""))
+  (should-error (json-encode-key 5) :type 'json-key-format)
+  (should-error (json-encode-key ["foo"]) :type 'json-key-format)
+  (should-error (json-encode-key '("foo")) :type 'json-key-format))
+
+;;; Objects
+
+(ert-deftest test-json-new-object ()
+  (let ((json-object-type 'alist))
+    (should (equal (json-new-object) '())))
+  (let ((json-object-type 'plist))
+    (should (equal (json-new-object) '())))
+  (let* ((json-object-type 'hash-table)
+         (json-object (json-new-object)))
+    (should (hash-table-p json-object))
+    (should (= (hash-table-count json-object) 0))))
+
+(ert-deftest test-json-add-to-object ()
+  (let* ((json-object-type 'alist)
+         (json-key-type nil)
+         (obj (json-new-object)))
+    (setq obj (json-add-to-object obj "a" 1))
+    (setq obj (json-add-to-object obj "b" 2))
+    (should (equal (assq 'a obj) '(a . 1)))
+    (should (equal (assq 'b obj) '(b . 2))))
+  (let* ((json-object-type 'plist)
+         (json-key-type nil)
+         (obj (json-new-object)))
+    (setq obj (json-add-to-object obj "a" 1))
+    (setq obj (json-add-to-object obj "b" 2))
+    (should (= (plist-get obj :a) 1))
+    (should (= (plist-get obj :b) 2)))
+  (let* ((json-object-type 'hash-table)
+         (json-key-type nil)
+         (obj (json-new-object)))
+    (setq obj (json-add-to-object obj "a" 1))
+    (setq obj (json-add-to-object obj "b" 2))
+    (should (= (gethash "a" obj) 1))
+    (should (= (gethash "b" obj) 2))))
+
+(ert-deftest test-json-read-object ()
+  (json-tests--with-temp-buffer "{ \"a\": 1, \"b\": 2 }"
+    (let ((json-object-type 'alist))
+      (should (equal (json-read-object) '((a . 1) (b . 2))))))
+  (json-tests--with-temp-buffer "{ \"a\": 1, \"b\": 2 }"
+    (let ((json-object-type 'plist))
+      (should (equal (json-read-object) '(:a 1 :b 2)))))
+  (json-tests--with-temp-buffer "{ \"a\": 1, \"b\": 2 }"
+    (let* ((json-object-type 'hash-table)
+           (hash-table (json-read-object)))
+      (should (= (gethash "a" hash-table) 1))
+      (should (= (gethash "b" hash-table) 2))))
+  (json-tests--with-temp-buffer "{ \"a\": 1 \"b\": 2 }"
+    (should-error (json-read-object) :type 'json-object-format)))
+
+(ert-deftest test-json-encode-hash-table ()
+  (let ((hash-table (make-hash-table))
+        (json-encoding-object-sort-predicate 'string<)
+        (json-encoding-pretty-print nil))
+    (puthash :a 1 hash-table)
+    (puthash :b 2 hash-table)
+    (puthash :c 3 hash-table)
+    (should (equal (json-encode hash-table)
+                   "{\"a\":1,\"b\":2,\"c\":3}"))))
+
+(ert-deftest json-encode-simple-alist ()
+  (let ((json-encoding-pretty-print nil))
+    (should (equal (json-encode '((a . 1) (b . 2)))
+                   "{\"a\":1,\"b\":2}"))))
+
+(ert-deftest test-json-encode-plist ()
+  (let ((plist '(:a 1 :b 2))
+        (json-encoding-pretty-print nil))
+    (should (equal (json-encode plist) "{\"a\":1,\"b\":2}"))))
+
+(ert-deftest test-json-encode-plist-with-sort-predicate ()
+  (let ((plist '(:c 3 :a 1 :b 2))
+        (json-encoding-object-sort-predicate 'string<)
+        (json-encoding-pretty-print nil))
+    (should (equal (json-encode plist) "{\"a\":1,\"b\":2,\"c\":3}"))))
+
+(ert-deftest test-json-encode-alist-with-sort-predicate ()
+  (let ((alist '((:c . 3) (:a . 1) (:b . 2)))
+        (json-encoding-object-sort-predicate 'string<)
+        (json-encoding-pretty-print nil))
+    (should (equal (json-encode alist) "{\"a\":1,\"b\":2,\"c\":3}"))))
+
+(ert-deftest test-json-encode-list ()
+  (let ((json-encoding-pretty-print nil))
+    (should (equal (json-encode-list '(:a 1 :b 2))
+                   "{\"a\":1,\"b\":2}"))
+    (should (equal (json-encode-list '((:a . 1) (:b . 2)))
+                   "{\"a\":1,\"b\":2}"))
+    (should (equal (json-encode-list '(1 2 3 4)) "[1,2,3,4]"))))
+
+;;; Arrays
+
+(ert-deftest test-json-read-array ()
+  (let ((json-array-type 'vector))
+    (json-tests--with-temp-buffer "[1, 2, \"a\", \"b\"]"
+      (should (equal (json-read-array) [1 2 "a" "b"]))))
+  (let ((json-array-type 'list))
+    (json-tests--with-temp-buffer "[1, 2, \"a\", \"b\"]"
+      (should (equal (json-read-array) '(1 2 "a" "b")))))
+  (json-tests--with-temp-buffer "[1 2]"
+    (should-error (json-read-array) :type 'json-error)))
+
+(ert-deftest test-json-encode-array ()
+  (let ((json-encoding-pretty-print nil))
+    (should (equal (json-encode-array [1 2 "a" "b"])
+                   "[1,2,\"a\",\"b\"]"))))
+
+;;; Reader
+
+(ert-deftest test-json-read ()
+  (json-tests--with-temp-buffer "{ \"a\": 1 }"
+    ;; We don't care exactly what the return value is (that is tested
+    ;; in `test-json-read-object'), but it should parse without error.
+    (should (json-read)))
+  (json-tests--with-temp-buffer ""
+    (should-error (json-read) :type 'json-end-of-file))
+  (json-tests--with-temp-buffer "xxx"
+    (should-error (json-read) :type 'json-readtable-error)))
+
+(ert-deftest test-json-read-from-string ()
+  (let ((json-string "{ \"a\": 1 }"))
+    (json-tests--with-temp-buffer json-string
+      (should (equal (json-read-from-string json-string)
+                     (json-read))))))
+
 (provide 'json-tests)
 ;;; json-tests.el ends here
-- 
2.6.2