diff options
-rw-r--r-- | configure.ac | 20 | ||||
-rw-r--r-- | src/Makefile.in | 11 | ||||
-rw-r--r-- | src/emacs.c | 4 | ||||
-rw-r--r-- | src/json.c | 469 | ||||
-rw-r--r-- | src/lisp.h | 5 | ||||
-rw-r--r-- | test/src/json-tests.el | 61 |
6 files changed, 4 insertions, 566 deletions
diff --git a/configure.ac b/configure.ac index c9ce5ee1205..35b7e69daf0 100644 --- a/configure.ac +++ b/configure.ac @@ -348,7 +348,6 @@ OPTION_DEFAULT_ON([libsystemd],[don't compile with libsystemd support]) OPTION_DEFAULT_OFF([cairo],[compile with Cairo drawing (experimental)]) OPTION_DEFAULT_ON([xml2],[don't compile with XML parsing support]) OPTION_DEFAULT_ON([imagemagick],[don't compile with ImageMagick image support]) -OPTION_DEFAULT_ON([json], [don't compile with native JSON support]) OPTION_DEFAULT_ON([xft],[don't use XFT for anti aliased fonts]) OPTION_DEFAULT_ON([libotf],[don't use libotf for OpenType font support]) @@ -2857,22 +2856,6 @@ fi AC_SUBST(LIBSYSTEMD_LIBS) AC_SUBST(LIBSYSTEMD_CFLAGS) -HAVE_JSON=no -JSON_OBJ= - -if test "${with_json}" = yes; then - EMACS_CHECK_MODULES([JSON], [jansson >= 2.5], - [HAVE_JSON=yes], [HAVE_JSON=no]) - if test "${HAVE_JSON}" = yes; then - AC_DEFINE(HAVE_JSON, 1, [Define if using Jansson.]) - JSON_OBJ=json.o - fi -fi - -AC_SUBST(JSON_LIBS) -AC_SUBST(JSON_CFLAGS) -AC_SUBST(JSON_OBJ) - NOTIFY_OBJ= NOTIFY_SUMMARY=no @@ -5385,7 +5368,7 @@ emacs_config_features= for opt in XAW3D XPM JPEG TIFF GIF PNG RSVG CAIRO IMAGEMAGICK SOUND GPM DBUS \ GCONF GSETTINGS NOTIFY ACL LIBSELINUX GNUTLS LIBXML2 FREETYPE M17N_FLT \ LIBOTF XFT ZLIB TOOLKIT_SCROLL_BARS X_TOOLKIT OLDXMENU X11 NS MODULES \ - XWIDGETS LIBSYSTEMD JSON CANNOT_DUMP LCMS2; do + XWIDGETS LIBSYSTEMD CANNOT_DUMP LCMS2; do case $opt in CANNOT_DUMP) eval val=\${$opt} ;; @@ -5435,7 +5418,6 @@ AS_ECHO([" Does Emacs use -lXaw3d? ${HAVE_XAW3D Does Emacs use -lotf? ${HAVE_LIBOTF} Does Emacs use -lxft? ${HAVE_XFT} Does Emacs use -lsystemd? ${HAVE_LIBSYSTEMD} - Does Emacs use -ljanssoon? ${HAVE_JSON} Does Emacs directly use zlib? ${HAVE_ZLIB} Does Emacs have dynamic modules support? ${HAVE_MODULES} Does Emacs use toolkit scroll bars? ${USE_TOOLKIT_SCROLL_BARS} diff --git a/src/Makefile.in b/src/Makefile.in index 4d33682629e..0e55ad4bb29 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -312,10 +312,6 @@ LIBGNUTLS_CFLAGS = @LIBGNUTLS_CFLAGS@ LIBSYSTEMD_LIBS = @LIBSYSTEMD_LIBS@ LIBSYSTEMD_CFLAGS = @LIBSYSTEMD_CFLAGS@ -JSON_LIBS = @JSON_LIBS@ -JSON_CFLAGS = @JSON_CFLAGS@ -JSON_OBJ = @JSON_OBJ@ - INTERVALS_H = dispextern.h intervals.h composite.h GETLOADAVG_LIBS = @GETLOADAVG_LIBS@ @@ -367,7 +363,7 @@ EMACS_CFLAGS=-Demacs $(MYCPPFLAGS) -I. -I$(srcdir) \ $(WEBKIT_CFLAGS) \ $(SETTINGS_CFLAGS) $(FREETYPE_CFLAGS) $(FONTCONFIG_CFLAGS) \ $(LIBOTF_CFLAGS) $(M17N_FLT_CFLAGS) $(DEPFLAGS) \ - $(LIBSYSTEMD_CFLAGS) $(JSON_CFLAGS) \ + $(LIBSYSTEMD_CFLAGS) \ $(LIBGNUTLS_CFLAGS) $(NOTIFY_CFLAGS) $(CAIRO_CFLAGS) \ $(WERROR_CFLAGS) ALL_CFLAGS = $(EMACS_CFLAGS) $(WARN_CFLAGS) $(CFLAGS) @@ -401,7 +397,7 @@ base_obj = dispnew.o frame.o scroll.o xdisp.o menu.o $(XMENU_OBJ) window.o \ thread.o systhread.o \ $(if $(HYBRID_MALLOC),sheap.o) \ $(MSDOS_OBJ) $(MSDOS_X_OBJ) $(NS_OBJ) $(CYGWIN_OBJ) $(FONT_OBJ) \ - $(W32_OBJ) $(WINDOW_SYSTEM_OBJ) $(XGSELOBJ) $(JSON_OBJ) + $(W32_OBJ) $(WINDOW_SYSTEM_OBJ) $(XGSELOBJ) obj = $(base_obj) $(NS_OBJC_OBJ) ## Object files used on some machine or other. @@ -497,8 +493,7 @@ LIBES = $(LIBS) $(W32_LIBS) $(LIBS_GNUSTEP) $(LIBX_BASE) $(LIBIMAGE) \ $(LIBS_TERMCAP) $(GETLOADAVG_LIBS) $(SETTINGS_LIBS) $(LIBSELINUX_LIBS) \ $(FREETYPE_LIBS) $(FONTCONFIG_LIBS) $(LIBOTF_LIBS) $(M17N_FLT_LIBS) \ $(LIBGNUTLS_LIBS) $(LIB_PTHREAD) $(GETADDRINFO_A_LIBS) $(LIBLCMS2) \ - $(NOTIFY_LIBS) $(LIB_MATH) $(LIBZ) $(LIBMODULES) $(LIBSYSTEMD_LIBS) \ - $(JSON_LIBS) + $(NOTIFY_LIBS) $(LIB_MATH) $(LIBZ) $(LIBMODULES) $(LIBSYSTEMD_LIBS) ## FORCE it so that admin/unidata can decide whether these files ## are up-to-date. Although since charprop depends on bootstrap-emacs, diff --git a/src/emacs.c b/src/emacs.c index eb5f1128f6e..1ad8af70a74 100644 --- a/src/emacs.c +++ b/src/emacs.c @@ -1610,10 +1610,6 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem syms_of_threads (); syms_of_profiler (); -#ifdef HAVE_JSON - syms_of_json (); -#endif - keys_of_casefiddle (); keys_of_cmds (); keys_of_buffer (); diff --git a/src/json.c b/src/json.c deleted file mode 100644 index 85abf87e214..00000000000 --- a/src/json.c +++ /dev/null @@ -1,469 +0,0 @@ -/* JSON parsing and serialization. - -Copyright (C) 2017 Free Software Foundation, Inc. - -This file is part of GNU Emacs. - -GNU Emacs is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or (at -your option) any later version. - -GNU Emacs is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ - -#include <config.h> - -#include <stddef.h> -#include <stdint.h> - -#include <jansson.h> - -#include "lisp.h" -#include "buffer.h" - -static _Noreturn void -json_out_of_memory (void) -{ - xsignal0 (Qjson_out_of_memory); -} - -static _Noreturn void -json_parse_error (const json_error_t *error) -{ - xsignal (Qjson_parse_error, - list5 (build_string (error->text), build_string (error->source), - make_natnum (error->line), make_natnum (error->column), - make_natnum (error->position))); -} - -static void -json_release_object (void *object) -{ - json_decref (object); -} - -static void -check_string_without_embedded_nulls (Lisp_Object object) -{ - CHECK_STRING (object); - CHECK_TYPE (memchr (SDATA (object), '\0', SBYTES (object)) == NULL, - Qstring_without_embedded_nulls_p, object); -} - -static json_t * -json_check (json_t *object) -{ - if (object == NULL) - json_out_of_memory (); - return object; -} - -/* This returns Lisp_Object so we can use unbind_to. The return value - is always nil. */ - -static Lisp_Object -lisp_to_json (Lisp_Object lisp, json_t **json) -{ - if (NILP (lisp)) - { - *json =json_check (json_null ()); - return Qnil; - } - else if (EQ (lisp, QCjson_false)) - { - *json = json_check (json_false ()); - return Qnil; - } - else if (EQ (lisp, Qt)) - { - *json = json_check (json_true ()); - return Qnil; - } - else if (INTEGERP (lisp)) - { - CHECK_TYPE_RANGED_INTEGER (json_int_t, lisp); - *json = json_check (json_integer (XINT (lisp))); - return Qnil; - } - else if (FLOATP (lisp)) - { - *json = json_check (json_real (XFLOAT_DATA (lisp))); - return Qnil; - } - else if (STRINGP (lisp)) - { - ptrdiff_t size = SBYTES (lisp); - eassert (size >= 0); - if (size > SIZE_MAX) - xsignal1 (Qoverflow_error, build_pure_c_string ("string is too long")); - *json = json_check (json_stringn (SSDATA (lisp), size)); - return Qnil; - } - else if (VECTORP (lisp)) - { - if (++lisp_eval_depth > max_lisp_eval_depth) - xsignal0 (Qjson_object_too_deep); - ptrdiff_t size = ASIZE (lisp); - eassert (size >= 0); - if (size > SIZE_MAX) - xsignal1 (Qoverflow_error, build_pure_c_string ("vector is too long")); - *json = json_check (json_array ()); - ptrdiff_t count = SPECPDL_INDEX (); - record_unwind_protect_ptr (json_release_object, json); - for (ptrdiff_t i = 0; i < size; ++i) - { - json_t *element; - lisp_to_json (AREF (lisp, i), &element); - int status = json_array_append_new (*json, element); - if (status == -1) - json_out_of_memory (); - eassert (status == 0); - } - eassert (json_array_size (*json) == size); - clear_unwind_protect (count); - --lisp_eval_depth; - return unbind_to (count, Qnil); - } - else if (HASH_TABLE_P (lisp)) - { - if (++lisp_eval_depth > max_lisp_eval_depth) - xsignal0 (Qjson_object_too_deep); - struct Lisp_Hash_Table *h = XHASH_TABLE (lisp); - *json = json_check (json_object ()); - ptrdiff_t count = SPECPDL_INDEX (); - record_unwind_protect_ptr (json_release_object, *json); - for (ptrdiff_t i = 0; i < HASH_TABLE_SIZE (h); ++i) - if (!NILP (HASH_HASH (h, i))) - { - Lisp_Object key = HASH_KEY (h, i); - /* We can’t specify the length, so the string must be - null-terminated. */ - check_string_without_embedded_nulls (key); - json_t *value; - lisp_to_json (HASH_VALUE (h, i), &value); - int status = json_object_set_new (*json, SSDATA (key), value); - if (status == -1) - json_out_of_memory (); - eassert (status == 0); - } - clear_unwind_protect (count); - --lisp_eval_depth; - return unbind_to (count, Qnil); - } - wrong_type_argument (Qjson_value_p, lisp); -} - -DEFUN ("json-serialize", Fjson_serialize, Sjson_serialize, 1, 1, NULL, - doc: /* Return the JSON representation of OBJECT as a string. -OBJECT must be a vector or hashtable, and its elements can recursively -contain nil, t, `:json-false', numbers, strings, or other vectors and -hashtables. nil, t, and `:json-false' will be converted to JSON null, -true, and false values, respectively. Vectors will be converted to -JSON arrays, and hashtables to JSON objects. Hashtable keys must be -strings without embedded null characters and must be unique within -each object. */) - (Lisp_Object object) -{ - ptrdiff_t count = SPECPDL_INDEX (); - - json_t *json; - lisp_to_json (object, &json); - record_unwind_protect_ptr (json_release_object, json); - - char *string = json_dumps (json, JSON_COMPACT); - if (string == NULL) - json_out_of_memory (); - record_unwind_protect_ptr (free, string); - - return unbind_to (count, build_string (string)); -} - -struct json_buffer_and_size -{ - const char *buffer; - size_t size; -}; - -static Lisp_Object -json_insert (Lisp_Object data) -{ - const struct json_buffer_and_size *buffer_and_size = XSAVE_POINTER (data, 0); - if (FIXNUM_OVERFLOW_P (buffer_and_size->size)) - xsignal1 (Qoverflow_error, build_pure_c_string ("buffer too large")); - Lisp_Object string - = make_string (buffer_and_size->buffer, buffer_and_size->size); - insert_from_string (string, 0, 0, SCHARS (string), SBYTES (string), false); - return Qnil; -} - -struct json_insert_data -{ - /* nil if json_insert succeeded, otherwise a cons - (ERROR-SYMBOL . ERROR-DATA). */ - Lisp_Object error; -}; - -static int -json_insert_callback (const char *buffer, size_t size, void *data) -{ - /* This function may not exit nonlocally. */ - struct json_insert_data *d = data; - struct json_buffer_and_size buffer_and_size - = {.buffer = buffer, .size = size}; - d->error - = internal_condition_case_1 (json_insert, make_save_ptr (&buffer_and_size), - Qt, Fidentity); - return 0; -} - -DEFUN ("json-insert", Fjson_insert, Sjson_insert, 1, 1, NULL, - doc: /* Insert the JSON representation of OBJECT before point. -This is the same as (insert (json-serialize OBJECT)), but potentially -faster. See the function `json-serialize' for allowed values of -OBJECT. */) - (Lisp_Object object) -{ - ptrdiff_t count = SPECPDL_INDEX (); - - json_t *json; - lisp_to_json (object, &json); - record_unwind_protect_ptr (json_release_object, json); - - struct json_insert_data data; - int status - = json_dump_callback (json, json_insert_callback, &data, JSON_COMPACT); - if (status == -1) - json_out_of_memory (); - eassert (status == 0); - - if (!NILP (data.error)) - xsignal (XCAR (data.error), XCDR (data.error)); - - return unbind_to (count, Qnil); -} - -static Lisp_Object -json_to_lisp (json_t *json) -{ - switch (json_typeof (json)) - { - case JSON_NULL: - return Qnil; - case JSON_FALSE: - return QCjson_false; - case JSON_TRUE: - return Qt; - case JSON_INTEGER: - { - json_int_t value = json_integer_value (json); - if (FIXNUM_OVERFLOW_P (value)) - xsignal1 (Qoverflow_error, - build_pure_c_string ("JSON integer is too large")); - return make_number (value); - } - case JSON_REAL: - return make_float (json_real_value (json)); - case JSON_STRING: - { - size_t size = json_string_length (json); - if (FIXNUM_OVERFLOW_P (size)) - xsignal1 (Qoverflow_error, - build_pure_c_string ("JSON string is too long")); - return make_string (json_string_value (json), size); - } - case JSON_ARRAY: - { - if (++lisp_eval_depth > max_lisp_eval_depth) - xsignal0 (Qjson_object_too_deep); - size_t size = json_array_size (json); - if (FIXNUM_OVERFLOW_P (size)) - xsignal1 (Qoverflow_error, - build_pure_c_string ("JSON array is too long")); - Lisp_Object result = Fmake_vector (make_natnum (size), Qunbound); - for (ptrdiff_t i = 0; i < size; ++i) - ASET (result, i, - json_to_lisp (json_array_get (json, i))); - --lisp_eval_depth; - return result; - } - case JSON_OBJECT: - { - if (++lisp_eval_depth > max_lisp_eval_depth) - xsignal0 (Qjson_object_too_deep); - size_t size = json_object_size (json); - if (FIXNUM_OVERFLOW_P (size)) - xsignal1 (Qoverflow_error, - build_pure_c_string ("JSON object has too many elements")); - Lisp_Object result = CALLN (Fmake_hash_table, QCtest, Qequal, - QCsize, make_natnum (size)); - struct Lisp_Hash_Table *h = XHASH_TABLE (result); - const char *key_str; - json_t *value; - json_object_foreach (json, key_str, value) - { - Lisp_Object key = build_string (key_str); - EMACS_UINT hash; - ptrdiff_t i = hash_lookup (h, key, &hash); - eassert (i < 0); - hash_put (h, key, json_to_lisp (value), hash); - } - --lisp_eval_depth; - return result; - } - } - /* Can’t get here. */ - emacs_abort (); -} - -DEFUN ("json-parse-string", Fjson_parse_string, Sjson_parse_string, 1, 1, NULL, - doc: /* Parse the JSON STRING into a Lisp object. -This is essentially the reverse operation of `json-serialize', which -see. The returned object will be a vector or hashtable. Its elements -will be nil, t, `:json-false', numbers, strings, or further vectors -and hashtables. If there are duplicate keys in an object, all but the -last one are ignored. If STRING doesn't contain a valid JSON object, -an error of type `json-parse-error' is signaled. */) - (Lisp_Object string) -{ - ptrdiff_t count = SPECPDL_INDEX (); - check_string_without_embedded_nulls (string); - - json_error_t error; - json_t *object = json_loads (SSDATA (string), 0, &error); - if (object == NULL) - json_parse_error (&error); - - /* Avoid leaking the object in case of further errors. */ - if (object != NULL) - record_unwind_protect_ptr (json_release_object, object); - - return unbind_to (count, json_to_lisp (object)); -} - -struct json_read_buffer_data -{ - ptrdiff_t point; -}; - -static size_t -json_read_buffer_callback (void *buffer, size_t buflen, void *data) -{ - struct json_read_buffer_data *d = data; - - /* First, parse from point to the gap or the end of the accessible - portion, whatever is closer. */ - ptrdiff_t point = d->point; - ptrdiff_t end; - { - bool overflow = INT_ADD_WRAPV (BUFFER_CEILING_OF (point), 1, &end); - eassert (!overflow); - } - size_t count; - { - bool overflow = INT_SUBTRACT_WRAPV (end, point, &count); - eassert (!overflow); - } - if (buflen < count) - count = buflen; - memcpy (buffer, BYTE_POS_ADDR (point), count); - { - bool overflow = INT_ADD_WRAPV (d->point, count, &d->point); - eassert (!overflow); - } - return count; -} - -DEFUN ("json-parse-buffer", Fjson_parse_buffer, Sjson_parse_buffer, - 0, 0, NULL, - doc: /* Read JSON object from current buffer starting at point. -This is similar to `json-parse-string', which see. Move point after -the end of the object if parsing was successful. On error, point is -not moved. */) - (void) -{ - ptrdiff_t count = SPECPDL_INDEX (); - - ptrdiff_t point = PT_BYTE; - struct json_read_buffer_data data = {.point = point}; - json_error_t error; - json_t *object = json_load_callback (json_read_buffer_callback, &data, - JSON_DISABLE_EOF_CHECK, &error); - - if (object == NULL) - json_parse_error (&error); - - /* Avoid leaking the object in case of further errors. */ - record_unwind_protect_ptr (json_release_object, object); - - /* Convert and then move point only if everything succeeded. */ - Lisp_Object lisp = json_to_lisp (object); - - { - /* Adjust point by how much we just read. Do this here because - tokener->char_offset becomes incorrect below. */ - bool overflow = INT_ADD_WRAPV (point, error.position, &point); - eassert (!overflow); - eassert (point <= ZV_BYTE); - SET_PT_BOTH (BYTE_TO_CHAR (point), point); - } - - return unbind_to (count, lisp); -} - -/* Simplified version of ‘define-error’ that works with pure - objects. */ - -static void -define_error (Lisp_Object name, const char *message, Lisp_Object parent) -{ - eassert (SYMBOLP (name)); - eassert (SYMBOLP (parent)); - Lisp_Object parent_conditions = Fget (parent, Qerror_conditions); - eassert (CONSP (parent_conditions)); - eassert (!NILP (Fmemq (parent, parent_conditions))); - eassert (NILP (Fmemq (name, parent_conditions))); - Fput (name, Qerror_conditions, pure_cons (name, parent_conditions)); - Fput (name, Qerror_message, build_pure_c_string (message)); -} - -void -syms_of_json (void) -{ - DEFSYM (QCjson_false, ":json-false"); - - DEFSYM (Qstring_without_embedded_nulls_p, "string-without-embedded-nulls-p"); - DEFSYM (Qjson_value_p, "json-value-p"); - - DEFSYM (Qjson_error, "json-error"); - DEFSYM (Qjson_out_of_memory, "json-out-of-memory"); - DEFSYM (Qjson_parse_error, "json-parse-error"); - DEFSYM (Qjson_object_too_deep, "json-object-too-deep"); - define_error (Qjson_error, "generic JSON error", Qerror); - define_error (Qjson_out_of_memory, "no free memory for creating JSON object", - Qjson_error); - define_error (Qjson_parse_error, "could not parse JSON stream", - Qjson_error); - define_error (Qjson_object_too_deep, "object cyclic or too deep", - Qjson_error); - - DEFSYM (Qpure, "pure"); - DEFSYM (Qside_effect_free, "side-effect-free"); - - DEFSYM (Qjson_serialize, "json-serialize"); - DEFSYM (Qjson_parse_string, "json-parse-string"); - Fput (Qjson_serialize, Qpure, Qt); - Fput (Qjson_serialize, Qside_effect_free, Qt); - Fput (Qjson_parse_string, Qpure, Qt); - Fput (Qjson_parse_string, Qside_effect_free, Qt); - - defsubr (&Sjson_serialize); - defsubr (&Sjson_insert); - defsubr (&Sjson_parse_string); - defsubr (&Sjson_parse_buffer); -} diff --git a/src/lisp.h b/src/lisp.h index 8d485098ac5..c5030824427 100644 --- a/src/lisp.h +++ b/src/lisp.h @@ -3440,11 +3440,6 @@ extern int x_bitmap_mask (struct frame *, ptrdiff_t); extern void reset_image_types (void); extern void syms_of_image (void); -#ifdef HAVE_JSON -/* Defined in json.c. */ -extern void syms_of_json (void); -#endif - /* Defined in insdel.c. */ extern void move_gap_both (ptrdiff_t, ptrdiff_t); extern _Noreturn void buffer_overflow (void); diff --git a/test/src/json-tests.el b/test/src/json-tests.el deleted file mode 100644 index 1d8f9a490ba..00000000000 --- a/test/src/json-tests.el +++ /dev/null @@ -1,61 +0,0 @@ -;;; json-tests.el --- unit tests for json.c -*- lexical-binding: t; -*- - -;; Copyright (C) 2017 Free Software Foundation, Inc. - -;; This file is part of GNU Emacs. - -;; GNU Emacs is free software: you can redistribute it and/or modify -;; it under the terms of the GNU General Public License as published by -;; the Free Software Foundation, either version 3 of the License, or -;; (at your option) any later version. - -;; GNU Emacs is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. - -;; You should have received a copy of the GNU General Public License -;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. - -;;; Commentary: - -;; Unit tests for src/json.c. - -;;; Code: - -(require 'cl-lib) -(require 'map) - -(ert-deftest json-serialize/roundtrip () - (let ((lisp [nil :json-false t 0 123 -456 3.75 "foo"]) - (json "[null,false,true,0,123,-456,3.75,\"foo\"]")) - (should (equal (json-serialize lisp) json)) - (with-temp-buffer - (json-insert lisp) - (should (equal (buffer-string) json)) - (should (eobp))) - (should (equal (json-parse-string json) lisp)) - (with-temp-buffer - (insert json) - (goto-char 1) - (should (equal (json-parse-buffer) lisp)) - (should (eobp))))) - -(ert-deftest json-serialize/object () - (let ((table (make-hash-table :test #'equal))) - (puthash "abc" [1 2 t] table) - (puthash "def" nil table) - (should (equal (json-serialize table) - "{\"abc\":[1,2,true],\"def\":null}")))) - -(ert-deftest json-parse-string/object () - (let ((actual - (json-parse-string - "{ \"abc\" : [1, 2, true], \"def\" : null, \"abc\" : [9, false] }\n"))) - (should (hash-table-p actual)) - (should (equal (hash-table-count actual) 2)) - (should (equal (cl-sort (map-pairs actual) #'string< :key #'car) - '(("abc" . [9 :json-false]) ("def")))))) - -(provide 'json-tests) -;;; json-tests.el ends here |