diff --git a/.gitignore b/.gitignore
index a1ff1e8..62bee11 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,8 @@
*.swp
EIFGENs
+TESTGEN
+ejson_test.h
+ejson_test*.c
+ejson_test.sh
+ejson_test*.o
+ejson_test
diff --git a/library/gobo/converters/json_ds_hash_table_converter.e b/library/gobo/converters/json_ds_hash_table_converter.e
index 46cf0ff..7f2625d 100644
--- a/library/gobo/converters/json_ds_hash_table_converter.e
+++ b/library/gobo/converters/json_ds_hash_table_converter.e
@@ -34,9 +34,11 @@ feature -- Conversion
i: INTEGER
h: HASHABLE
a: ANY
+ ucs: UC_STRING
do
keys := j.current_keys
create Result.make (keys.count)
+ create ucs.make_empty
from
i := 1
until
@@ -44,7 +46,13 @@ feature -- Conversion
loop
h ?= json.object (keys [i], void)
check h /= Void end
+ if attached {STRING_32} h and attached Json.converter_for (ucs) then
+ h ?= json.object (keys [i], ucs.generator)
+ end
a := json.object (j.item (keys [i]), Void)
+ if attached {STRING_32} a and attached Json.converter_for (ucs) then
+ a := json.object (j.item (keys [i]), ucs.generator)
+ end
Result.put (a, h)
i := i + 1
end
diff --git a/library/gobo/converters/json_uc_string_converter.e b/library/gobo/converters/json_uc_string_converter.e
new file mode 100644
index 0000000..25de837
--- /dev/null
+++ b/library/gobo/converters/json_uc_string_converter.e
@@ -0,0 +1,39 @@
+note
+ description: "JSON UC_STRING converter."
+ author: "Olivier Ligot"
+
+class
+ JSON_UC_STRING_CONVERTER
+
+inherit
+ JSON_CONVERTER
+
+create
+ make
+
+feature {NONE} -- Initialization
+
+ make
+ do
+ create object.make (0)
+ end
+
+feature -- Access
+
+ value: JSON_STRING
+
+ object: UC_STRING
+
+feature -- Conversion
+
+ from_json (j: like value): like object
+ do
+ create Result.make_from_string_general (j.unescaped_string_32)
+ end
+
+ to_json (o: like object): like value
+ do
+ create Result.make_json_from_string_32 (o.as_string_32)
+ end
+
+end
diff --git a/library/json-safe.ecf b/library/json-safe.ecf
index b957513..5342859 100644
--- a/library/json-safe.ecf
+++ b/library/json-safe.ecf
@@ -14,15 +14,20 @@
-
+
+
+
+
+
+
+
+
+
+
- ^/gobo$
- ^/kernel$
- ^/extras$
+ .*/?gobo.*
-
-
diff --git a/library/json.ecf b/library/json.ecf
index 8d6dc61..e5f1d2a 100644
--- a/library/json.ecf
+++ b/library/json.ecf
@@ -14,15 +14,20 @@
-
+
+
+
+
+
+
+
+
+
+
- ^/gobo$
- ^/kernel$
- ^/extras$
+ .*/?gobo.*
-
-
diff --git a/library/json_gobo_extension-portable.ecf b/library/json_gobo_extension-portable.ecf
new file mode 100644
index 0000000..b038b95
--- /dev/null
+++ b/library/json_gobo_extension-portable.ecf
@@ -0,0 +1,27 @@
+
+
+
+
+
+ /EIFGENs$
+ /CVS$
+ /.svn$
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/library/json_gobo_extension.ecf b/library/json_gobo_extension.ecf
index dd5f9b7..700e8c6 100644
--- a/library/json_gobo_extension.ecf
+++ b/library/json_gobo_extension.ecf
@@ -9,8 +9,18 @@
-
+
+
+
+
+
+
+
+
+
+
+
diff --git a/library/kernel/converters/json_hash_table_converter.e b/library/kernel/converters/json_hash_table_converter.e
index cf3f9cf..7b513b3 100644
--- a/library/kernel/converters/json_hash_table_converter.e
+++ b/library/kernel/converters/json_hash_table_converter.e
@@ -46,7 +46,7 @@ feature -- Conversion
jv := j.item (keys [i])
if jv /= Void then
a := json.object (jv, Void)
- if a /= Void then
+ if a /= Void and h /= Void then
Result.put (a, h)
else
check a_attached: a /= Void end
diff --git a/test/getest/author.e b/test/getest/author.e
new file mode 100644
index 0000000..f150365
--- /dev/null
+++ b/test/getest/author.e
@@ -0,0 +1,24 @@
+class AUTHOR
+
+create
+ make
+
+feature {NONE} -- Initialization
+
+ make (a_name: UC_STRING)
+ do
+ set_name (a_name)
+ end
+
+feature -- Access
+
+ name: UC_STRING
+
+feature -- Status setting
+
+ set_name (a_name: UC_STRING)
+ do
+ name := a_name
+ end
+
+end -- class AUTHOR
diff --git a/test/getest/book.e b/test/getest/book.e
new file mode 100644
index 0000000..5681221
--- /dev/null
+++ b/test/getest/book.e
@@ -0,0 +1,40 @@
+class BOOK
+
+create
+ make
+
+feature {NONE} -- Initialization
+
+ make (a_title: UC_STRING; an_author: AUTHOR; an_isbn: UC_STRING)
+ do
+ set_title (a_title)
+ set_author (an_author)
+ set_isbn (an_isbn)
+ end
+
+feature -- Access
+
+ title: UC_STRING
+
+ isbn: UC_STRING
+
+ author: AUTHOR
+
+feature -- Status setting
+
+ set_title (a_title: UC_STRING)
+ do
+ title := a_title
+ end
+
+ set_author (an_author: AUTHOR)
+ do
+ author := an_author
+ end
+
+ set_isbn (an_isbn: UC_STRING)
+ do
+ isbn := an_isbn
+ end
+
+end -- class BOOK
diff --git a/test/getest/book_collection.e b/test/getest/book_collection.e
new file mode 100644
index 0000000..1b6db0f
--- /dev/null
+++ b/test/getest/book_collection.e
@@ -0,0 +1,82 @@
+class BOOK_COLLECTION
+
+create
+ make
+
+feature {NONE} -- Initialization
+
+ make (a_name: UC_STRING)
+ do
+ set_name (a_name)
+ create book_index.make (10)
+ end
+
+feature -- Access
+
+ name: UC_STRING
+
+ books: DS_LIST [BOOK]
+ local
+ c: DS_HASH_TABLE_CURSOR [DS_LIST [BOOK], UC_STRING]
+ do
+ from
+ create {DS_LINKED_LIST [BOOK]} Result.make
+ c := book_index.new_cursor
+ c.start
+ until
+ c.after
+ loop
+ Result.append_last (c.item)
+ c.forth
+ end
+ end
+
+ books_by_author (an_author: UC_STRING): DS_LIST [BOOK]
+ do
+ if book_index.has (an_author) then
+ Result := book_index @ an_author
+ else
+ create {DS_LINKED_LIST [BOOK]} Result.make
+ end
+ end
+
+feature -- Status setting
+
+ set_name (a_name: UC_STRING)
+ do
+ name := a_name
+ end
+
+ add_book (a_book: BOOK)
+ local
+ l: DS_LIST [BOOK]
+ do
+ if book_index.has (a_book.author.name) then
+ l := book_index @ a_book.author.name
+ else
+ create {DS_LINKED_LIST [BOOK]} l.make
+ book_index.put (l, a_book.author.name)
+ end
+ l.put_last (a_book)
+ end
+
+ add_books (book_list: like books)
+ local
+ c: DS_LIST_CURSOR [BOOK]
+ do
+ from
+ c := book_list.new_cursor
+ c.start
+ until
+ c.after
+ loop
+ add_book (c.item)
+ c.forth
+ end
+ end
+
+feature {NONE} -- Implementation
+
+ book_index: DS_HASH_TABLE [DS_LIST [BOOK], UC_STRING]
+
+end -- class BOOK_COLLECTION
diff --git a/test/getest/ec_compile.bat b/test/getest/ec_compile.bat
new file mode 100644
index 0000000..1d90e40
--- /dev/null
+++ b/test/getest/ec_compile.bat
@@ -0,0 +1,11 @@
+echo Compiling ejson_test (finalized)
+ecb -finalize -c_compile -config ejson_test.ecf -batch -clean > NUL 2>&1
+IF %ERRORLEVEL% EQU -1 goto ERROR
+copy EIFGENs\ejson_test\F_code\ejson_test.exe ejson_test.exe
+goto EOF
+
+:ERROR
+echo Error occurred during ejson_test compilation
+goto EOF
+
+:EOF
diff --git a/test/getest/ec_compile.sh b/test/getest/ec_compile.sh
new file mode 100755
index 0000000..08dcd61
--- /dev/null
+++ b/test/getest/ec_compile.sh
@@ -0,0 +1,5 @@
+#!/bin/bash
+
+echo "ec -finalize -c_compile -config ejson_test.ecf > /dev/null 2>&1"
+ec -finalize -c_compile -config ejson_test.ecf > /dev/null 2>&1
+cp EIFGENs/ejson_test/F_code/ejson_test .
diff --git a/test/getest/ejson_test-win.cfg b/test/getest/ejson_test-win.cfg
new file mode 100644
index 0000000..9c905c2
--- /dev/null
+++ b/test/getest/ejson_test-win.cfg
@@ -0,0 +1,17 @@
+-- Gobo test (getest) configuration file for eJSON
+
+test
+ ejson_test
+
+default
+ class ("TEST_[A-Z0-9_]*")
+ feature ("test_[a-z0-9_]*")
+ prefix ("X")
+ testgen ("TESTGEN")
+ compile ("ec_compile.bat")
+ execute ("ejson_test.exe")
+
+cluster
+ test_dir: "."
+
+end
diff --git a/test/getest/ejson_test-win.ge b/test/getest/ejson_test-win.ge
new file mode 100644
index 0000000..fcf91f4
--- /dev/null
+++ b/test/getest/ejson_test-win.ge
@@ -0,0 +1,16 @@
+-- Gobo test (getest) configuration file for eJSON
+
+test
+ ejson_test
+
+default
+ class ("TEST_[A-Z0-9_]*")
+ feature ("test_[a-z0-9_]*")
+ prefix ("X")
+ testgen ("TESTGEN")
+ compile ("ge_compile.bat")
+
+cluster
+ test_dir: "."
+
+end
diff --git a/test/getest/ejson_test.cfg b/test/getest/ejson_test.cfg
new file mode 100644
index 0000000..078526a
--- /dev/null
+++ b/test/getest/ejson_test.cfg
@@ -0,0 +1,17 @@
+-- Gobo test (getest) configuration file for eJSON
+
+test
+ ejson_test
+
+default
+ class ("TEST_[A-Z0-9_]*")
+ feature ("test_[a-z0-9_]*")
+ prefix ("X")
+ testgen ("TESTGEN")
+ compile ("./ec_compile.sh")
+ execute ("./ejson_test")
+
+cluster
+ test_dir: "."
+
+end
diff --git a/test/getest/ejson_test.ecf b/test/getest/ejson_test.ecf
new file mode 100644
index 0000000..e8ad9f3
--- /dev/null
+++ b/test/getest/ejson_test.ecf
@@ -0,0 +1,30 @@
+
+
+
+
+
+ //.svn
+ /cvs$
+ /EIFGENs$
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/test/getest/ejson_test.ge b/test/getest/ejson_test.ge
new file mode 100644
index 0000000..f3b4f52
--- /dev/null
+++ b/test/getest/ejson_test.ge
@@ -0,0 +1,16 @@
+-- Gobo test (getest) configuration file for eJSON
+
+test
+ ejson_test
+
+default
+ class ("TEST_[A-Z0-9_]*")
+ feature ("test_[a-z0-9_]*")
+ prefix ("X")
+ testgen ("TESTGEN")
+ compile ("./ge_compile.sh")
+
+cluster
+ test_dir: "."
+
+end
diff --git a/test/getest/ge_compile.bat b/test/getest/ge_compile.bat
new file mode 100644
index 0000000..72436f9
--- /dev/null
+++ b/test/getest/ge_compile.bat
@@ -0,0 +1,3 @@
+echo Compiling with gec
+set GOBO_EIFFEL=ge
+gec.exe --finalize --catcall=no ejson_test.ecf
diff --git a/test/getest/ge_compile.sh b/test/getest/ge_compile.sh
new file mode 100755
index 0000000..b165bfd
--- /dev/null
+++ b/test/getest/ge_compile.sh
@@ -0,0 +1,4 @@
+#!/bin/bash
+
+echo "Compiling with gec"
+GOBO_EIFFEL=ge gec --finalize --catcall=no ejson_test.ecf
diff --git a/test/getest/json_author_converter.e b/test/getest/json_author_converter.e
new file mode 100644
index 0000000..36f06cd
--- /dev/null
+++ b/test/getest/json_author_converter.e
@@ -0,0 +1,55 @@
+note
+ description: "A JSON converter for AUTHOR"
+ author: "Paul Cohen"
+ date: "$Date$"
+ revision: "$Revision$"
+
+class JSON_AUTHOR_CONVERTER
+
+inherit
+ JSON_CONVERTER
+
+create
+ make
+
+feature {NONE} -- Initialization
+
+ make
+ local
+ ucs: UC_STRING
+ do
+ create ucs.make_from_string ("")
+ create object.make (ucs)
+ end
+
+feature -- Access
+
+ value: JSON_OBJECT
+
+ object: AUTHOR
+
+feature -- Conversion
+
+ from_json (j: like value): like object
+ local
+ ucs: UC_STRING
+ do
+ ucs ?= json.object (j.item (name_key), "UC_STRING")
+ check ucs /= Void end
+ create Result.make (ucs)
+ end
+
+ to_json (o: like object): like value
+ do
+ create Result.make
+ Result.put (json.value (o.name), name_key)
+ end
+
+feature {NONE} -- Implementation
+
+ name_key: JSON_STRING
+ once
+ create Result.make_json ("name")
+ end
+
+end -- class JSON_AUTHOR_CONVERTER
diff --git a/test/getest/json_book_collection_converter.e b/test/getest/json_book_collection_converter.e
new file mode 100644
index 0000000..c16ac6a
--- /dev/null
+++ b/test/getest/json_book_collection_converter.e
@@ -0,0 +1,80 @@
+note
+ description: "A JSON converter for BOOK_COLLECTION"
+ author: "Paul Cohen"
+ date: "$Date$"
+ revision: "$Revision$"
+
+class JSON_BOOK_COLLECTION_CONVERTER
+
+inherit
+ JSON_CONVERTER
+
+create
+ make
+
+feature {NONE} -- Initialization
+
+ make
+ local
+ ucs: UC_STRING
+ do
+ create ucs.make_from_string ("")
+ create object.make (ucs)
+ end
+
+feature -- Access
+
+ value: JSON_OBJECT
+
+ object: BOOK_COLLECTION
+
+feature -- Conversion
+
+ from_json (j: like value): like object
+ local
+ ucs: UC_STRING
+ ll: DS_LINKED_LIST [BOOK]
+ b: BOOK
+ ja: JSON_ARRAY
+ i: INTEGER
+ do
+ ucs ?= json.object (j.item (name_key), "UC_STRING")
+ check ucs /= Void end
+ create Result.make (ucs)
+ ja ?= j.item (books_key)
+ check ja /= Void end
+ from
+ i := 1
+ create ll.make
+ until
+ i > ja.count
+ loop
+ b ?= json.object (ja [i], "BOOK")
+ check b /= Void end
+ ll.put_last (b)
+ i := i + 1
+ end
+ check ll /= Void end
+ Result.add_books (ll)
+ end
+
+ to_json (o: like object): like value
+ do
+ create Result.make
+ Result.put (json.value (o.name), name_key)
+ Result.put (json.value (o.books), books_key)
+ end
+
+feature {NONE} -- Implementation
+
+ name_key: JSON_STRING
+ once
+ create Result.make_json ("name")
+ end
+
+ books_key: JSON_STRING
+ once
+ create Result.make_json ("books")
+ end
+
+end -- class JSON_BOOK_COLLECTION_CONVERTER
diff --git a/test/getest/json_book_converter.e b/test/getest/json_book_converter.e
new file mode 100644
index 0000000..9b63455
--- /dev/null
+++ b/test/getest/json_book_converter.e
@@ -0,0 +1,74 @@
+note
+ description: "A JSON converter for BOOK"
+ author: "Paul Cohen"
+ date: "$Date$"
+ revision: "$Revision$"
+
+class JSON_BOOK_CONVERTER
+
+inherit
+ JSON_CONVERTER
+
+create
+ make
+
+feature {NONE} -- Initialization
+
+ make
+ local
+ ucs: UC_STRING
+ a: AUTHOR
+ do
+ create ucs.make_from_string ("")
+ create a.make (ucs)
+ create object.make (ucs, a, ucs)
+ end
+
+feature -- Access
+
+ value: JSON_OBJECT
+
+ object: BOOK
+
+feature -- Conversion
+
+ from_json (j: like value): like object
+ local
+ ucs1, ucs2: UC_STRING
+ a: AUTHOR
+ do
+ ucs1 ?= json.object (j.item (title_key), "UC_STRING")
+ check ucs1 /= Void end
+ ucs2 ?= json.object (j.item (isbn_key), "UC_STRING")
+ check ucs2 /= Void end
+ a ?= json.object (j.item (author_key), "AUTHOR")
+ check a /= Void end
+ create Result.make (ucs1, a, ucs2)
+ end
+
+ to_json (o: like object): like value
+ do
+ create Result.make
+ Result.put (json.value (o.title), title_key)
+ Result.put (json.value (o.isbn), isbn_key)
+ Result.put (json.value (o.author), author_key)
+ end
+
+feature {NONE} -- Implementation
+
+ title_key: JSON_STRING
+ once
+ create Result.make_json ("title")
+ end
+
+ isbn_key: JSON_STRING
+ once
+ create Result.make_json ("isbn")
+ end
+
+ author_key: JSON_STRING
+ once
+ create Result.make_json ("author")
+ end
+
+end -- class JSON_BOOK_CONVERTER
diff --git a/test/getest/readme.txt b/test/getest/readme.txt
new file mode 100644
index 0000000..d874160
--- /dev/null
+++ b/test/getest/readme.txt
@@ -0,0 +1,36 @@
+Gobo ecf files
+==============
+
+To get the Gobo ecf files do as follows:
+
+1. Create a directory for the custum Eiffel libraries
+
+2. Define the environment variable EIFFEL_LIBRARY to point to the newly created directory
+
+3. Clone the Git repository https://github.com/oligot/gobo-ecf in the newly created directory
+
+EiffelStudio
+============
+
+To compile and run the test program using EiffelStudio do as follows:
+
+1. Make sure you have a compiled version of getest in your PATH.
+
+2. In this directory, run the command:
+
+ $ getest --verbose ejson_test.cfg
+
+Note: on Windows, you should use ejson_test-win.cfg
+
+gec
+===
+
+To compile and run the test program using gec do as follows:
+
+1. Make sure you have a compiled version of getest in your PATH.
+
+2. In this directory, run the command:
+
+ $ getest --verbose ejson_test.ge
+
+Note: on Windows, you should use ejson_test-win.ge
diff --git a/test/getest/test_ds.e b/test/getest/test_ds.e
new file mode 100644
index 0000000..6883306
--- /dev/null
+++ b/test/getest/test_ds.e
@@ -0,0 +1,72 @@
+class TEST_DS
+
+inherit
+ SHARED_GOBO_EJSON
+
+ TS_TEST_CASE
+
+create
+ make_default
+
+feature {NONE} -- Initialization
+
+ make
+ -- Create test object.
+ do
+ end
+
+feature -- Test
+
+ test_ds_linked_list_converter
+ local
+ jc: JSON_DS_LINKED_LIST_CONVERTER
+ l: DS_LINKED_LIST [STRING]
+ l2: DS_LINKED_LIST [ANY]
+ s: STRING
+ jv: JSON_VALUE
+ do
+ create jc.make
+ json.add_converter (jc)
+ create l.make
+ s := "foo"
+ l.put_last (s)
+ s := "bar"
+ l.put_last (s)
+ jv := json.value (l)
+ assert ("jv /= Void", jv /= Void)
+ s := jv.representation
+ l2 ?= json.object (jv, "DS_LINKED_LIST")
+ assert ("l2 /= Void", l2 /= Void)
+ end
+
+ test_ds_hash_table_converter
+ local
+ tc: JSON_DS_HASH_TABLE_CONVERTER
+ t: DS_HASH_TABLE [STRING, STRING]
+ t2: DS_HASH_TABLE [ANY, HASHABLE]
+ s: STRING
+ ucs_key, ucs_value: UC_STRING
+ jv: JSON_VALUE
+ do
+ create tc.make
+ json.add_converter (tc)
+ json.add_converter (create {JSON_UC_STRING_CONVERTER}.make)
+ create t.make (2)
+ t.put ("foo", "1")
+ t.put ("bar", "2")
+ jv := json.value (t)
+ assert ("jv /= Void", jv /= Void)
+ s := jv.representation
+ t2 ?= json.object (jv, "DS_HASH_TABLE")
+ assert ("t2 /= Void", t2 /= Void)
+ create ucs_key.make_from_string ("1")
+ ucs_value ?= t2 @ ucs_key
+ assert ("ucs_value /= Void", ucs_value /= Void)
+ assert ("ucs_value.string.is_equal (%"foo%")", ucs_value.string.is_equal ("foo"))
+ create ucs_key.make_from_string ("2")
+ ucs_value ?= t2 @ ucs_key
+ assert ("ucs_value /= Void", ucs_value /= Void)
+ assert ("ucs_value.string.is_equal (%"bar%")", ucs_value.string.is_equal ("bar"))
+ end
+
+end -- class TEST_DS
diff --git a/test/getest/test_json_core.e b/test/getest/test_json_core.e
new file mode 100644
index 0000000..591ca2e
--- /dev/null
+++ b/test/getest/test_json_core.e
@@ -0,0 +1,790 @@
+class TEST_JSON_CORE
+
+inherit
+ TS_TEST_CASE
+ SHARED_EJSON
+ KL_SHARED_EIFFEL_COMPILER
+
+create
+ make_default
+
+feature {NONE} -- Initialization
+
+ make
+ -- Create test object.
+ do
+ end
+
+feature -- Test
+
+ test_json_number_and_integer
+ local
+ i: INTEGER
+ jn: JSON_NUMBER
+ jrep: STRING
+ parser: JSON_PARSER
+ do
+ i := 42
+ -- Eiffel value -> JSON value -> JSON representation
+ create jn.make_integer (i)
+ assert ("jn.representation.same_string (%"42%")", jn.representation.same_string ("42"))
+ -- Eiffel value -> JSON value -> JSON representation with factory
+ if attached {JSON_NUMBER} json.value (i) as l_jn then
+ assert ("l_jn.representation.same_string (%"42%")", jn.representation.same_string ("42"))
+ else
+ assert ("json.value (i) is a JSON_NUMBER", False)
+ end
+
+ -- JSON representation-> JSON value -> Eiffel value
+ -- Note: The JSON_FACTORY will return the smallest INTEGER_* object
+ -- that can represent the value of the JSON number, in this case
+ -- we know it is INTEGER_8 since the value is 42
+ jrep := "42"
+ create parser.make_parser (jrep)
+ if attached {JSON_NUMBER} parser.parse as l_jn then
+ if attached {INTEGER_8} json.object (jn, Void) as l_i8 then
+ assert ("l_i8 = 42", l_i8 = 42)
+ else
+ assert ("json.object (jn, Void) is a INTEGER_8", False)
+ end
+ else
+ assert ("parser.parse is a JSON_NUMBER", False)
+ end
+ end
+
+ test_json_number_and_integer_8
+ local
+ i8: INTEGER_8
+ jn: JSON_NUMBER
+ jrep: STRING
+ parser: JSON_PARSER
+ do
+ i8 := 42
+ -- Eiffel value -> JSON value -> JSON representation
+ create jn.make_integer (i8)
+ assert ("jn.representation.same_string (%"42%")", jn.representation.same_string ("42"))
+ -- Eiffel value -> JSON value -> JSON representation with factory
+ if attached {JSON_NUMBER} json.value (i8) as l_jn then
+ assert ("l_jn.representation.same_string (%"42%")", jn.representation.same_string ("42"))
+ else
+ assert ("json.value (i8) is a JSON_NUMBER", False)
+ end
+
+ -- JSON representation -> JSON value -> Eiffel value
+ -- Note: The JSON_FACTORY will return the smallest INTEGER_* object
+ -- that can represent the value of the JSON number, in this case
+ -- we know it is INTEGER_8 since the value is 42
+ jrep := "42"
+ create parser.make_parser (jrep)
+ if attached {JSON_NUMBER} parser.parse as l_jn then
+ if attached {INTEGER_8} json.object (jn, Void) as l_i8 then
+ assert ("l_i8 = 42", l_i8 = 42)
+ else
+ assert ("json.object (jn, Void) is a INTEGER_8", False)
+ end
+ else
+ assert ("parser.parse is a JSON_NUMBER", False)
+ end
+ end
+
+ test_json_number_and_integer_16
+ local
+ i16: INTEGER_16
+ jn: JSON_NUMBER
+ jrep: STRING
+ parser: JSON_PARSER
+ do
+ i16 := 300
+ -- Eiffel value -> JSON value -> JSON representation
+ create jn.make_integer (i16)
+ assert ("jn.representation.same_string (%"300%")", jn.representation.same_string ("300"))
+ -- Eiffel value -> JSON with factory
+ if attached {JSON_NUMBER} json.value (i16) as l_jn then
+ assert ("l_jn.representation.same_string (%"300%")", l_jn.representation.same_string ("300"))
+ else
+ assert ("json.value (i16) is a JSON_NUMBER", False)
+ end
+
+ -- JSON representation -> JSON value -> Eiffel value
+ -- Note: The JSON_FACTORY will return the smallest INTEGER_* object
+ -- that can represent the value of the JSON number, in this case
+ -- we know it is INTEGER_16 since the value is 300
+ jrep := "300"
+ create parser.make_parser (jrep)
+ if attached {JSON_NUMBER} parser.parse as l_jn then
+ if attached {INTEGER_16} json.object (jn, Void) as l_i16 then
+ assert ("l_i16 = 300", l_i16 = 300)
+ else
+ assert ("json.object (jn, Void) is a INTEGER_16", False)
+ end
+ else
+ assert ("parser.parse is a JSON_NUMBER", False)
+ end
+ end
+
+ test_json_number_and_integer_32
+ local
+ i32: INTEGER_32
+ jn: JSON_NUMBER
+ jrep: STRING
+ parser: JSON_PARSER
+ do
+ i32 := 100000
+ -- Eiffel value -> JSON representation -> JSON value
+ create jn.make_integer (i32)
+ assert ("jn.representation.same_string (%"100000%")", jn.representation.same_string ("100000"))
+ -- Eiffel value -> JSON representation -> JSON value with factory
+ if attached {JSON_NUMBER} json.value (i32) as l_jn then
+ assert ("l_jn.representation.same_string (%"100000%")", l_jn.representation.same_string ("100000"))
+ else
+ assert ("json.value (i32) is a JSON_NUMBER", False)
+ end
+
+ -- JSON representation -> JSON value -> Eiffel value
+ -- Note: The JSON_FACTORY will return the smallest INTEGER_* object
+ -- that can represent the value of the JSON number, in this case
+ -- we know it is INTEGER_32 since the value is 100000
+ jrep := "100000"
+ create parser.make_parser (jrep)
+ if attached {JSON_NUMBER} parser.parse as l_jn then
+ if attached {INTEGER_32} json.object (jn, Void) as l_i32 then
+ assert ("l_i32 = 100000", l_i32 = 100000)
+ else
+ assert ("json.object (jn, Void) is a INTEGER_32", False)
+ end
+ else
+ assert ("parser.parse is a JSON_NUMBER", False)
+ end
+ end
+
+ test_json_number_and_integer_64
+ local
+ i64: INTEGER_64
+ jn: JSON_NUMBER
+ jrep: STRING
+ parser: JSON_PARSER
+ do
+ i64 := 42949672960
+ -- Eiffel value -> JSON value -> JSON representation
+ create jn.make_integer (i64)
+ assert ("jn.representation.same_string (%"42949672960%")", jn.representation.same_string ("42949672960"))
+ -- Eiffel value -> JSON value -> JSON representation with factory
+ if attached {JSON_NUMBER} json.value (i64) as l_jn then
+ assert ("l_jn.representation.same_string (%"42949672960%")", l_jn.representation.same_string ("42949672960"))
+ else
+ assert ("json.value (i64) is a JSON_NUMBER", False)
+ end
+
+ -- JSON representation -> JSON value -> Eiffel value
+ -- Note: The JSON_FACTORY will return the smallest INTEGER_* object
+ -- that can represent the value of the JSON number, in this case
+ -- we know it is INTEGER_32 since the value is 42949672960
+ jrep := "42949672960"
+ create parser.make_parser (jrep)
+ if attached {JSON_NUMBER} parser.parse as l_jn then
+ if attached {INTEGER_64} json.object (jn, Void) as l_i64 then
+ assert ("l_i64 = 42949672960", l_i64 = 42949672960)
+ else
+ assert ("json.object (jn, Void) is a INTEGER_64", False)
+ end
+ else
+ assert ("parser.parse is a JSON_NUMBER", False)
+ end
+ end
+
+ test_json_number_and_natural_8
+ local
+ n8: NATURAL_8
+ jn: JSON_NUMBER
+ jrep: STRING
+ parser: JSON_PARSER
+ do
+ n8 := 200
+ -- Eiffel value -> JSON value -> JSON representation
+ create jn.make_natural (n8)
+ assert ("jn.representation.same_string (%"200%")", jn.representation.same_string ("200"))
+ -- Eiffel value -> JSON value -> JSON representation with factory
+ if attached {JSON_NUMBER} json.value (n8) as l_jn then
+ assert ("l_jn.representation.same_string (%"200%")", l_jn.representation.same_string ("200"))
+ else
+ assert ("json.value (n8) is a JSON_NUMBER}", False)
+ end
+
+ -- JSON representation -> JSON value -> Eiffel value
+ -- Note: The JSON_FACTORY will return the smallest INTEGER_* object
+ -- that can represent the value of the JSON number, in this case
+ -- we know it is INTEGER_16 since the value is 200
+ jrep := "200"
+ create parser.make_parser (jrep)
+ if attached {JSON_NUMBER} parser.parse as l_jn then
+ if attached {INTEGER_16} json.object (jn, Void) as i16 then
+ assert ("i16 = 200", i16 = 200)
+ else
+ assert ("json.object (jn, Void) is an INTEGER_16", False)
+ end
+ else
+ assert ("parser.parse is a JSON_NUMBER", False)
+ end
+ end
+
+ test_json_number_and_natural_16
+ local
+ n16: NATURAL_16
+ jn: JSON_NUMBER
+ jrep: STRING
+ parser: JSON_PARSER
+ do
+ n16 := 32768
+ -- Eiffel value -> JSON value -> JSON representation
+ create jn.make_natural (n16)
+ assert ("jn.representation.same_string (%"32768%")", jn.representation.same_string ("32768"))
+ -- Eiffel value -> JSON value -> JSON representation with factory
+ if attached {JSON_NUMBER} json.value (n16) as l_jn then
+ assert ("l_jn.representation.same_string (%"32768%")", l_jn.representation.same_string ("32768"))
+ else
+ assert ("json.value (n16) is a JSON_NUMBER", False)
+ end
+
+ -- JSON representation -> JSON value -> Eiffel value
+ -- Note: The JSON_FACTORY will return the smallest INTEGER_* object
+ -- that can represent the value of the JSON number, in this case
+ -- we know it is INTEGER_32 since the value is 32768
+ jrep := "32768"
+ create parser.make_parser (jrep)
+ if attached {JSON_NUMBER} parser.parse as l_jn then
+ if attached {INTEGER_32} json.object (jn, Void) as i32 then
+ assert ("i32 = 32768", i32 = 32768)
+ else
+ assert ("json.object (jn, Void) is a INTEGER_32", False)
+ end
+ else
+ assert ("parser.parse is a JSON_NUMBER", False)
+ end
+ end
+
+ test_json_number_and_natural_32
+ local
+ n32: NATURAL_32
+ jn: JSON_NUMBER
+ jrep: STRING
+ parser: JSON_PARSER
+ do
+ n32 := 2147483648
+ -- Eiffel value -> JSON value -> JSON representation
+ create jn.make_natural (n32)
+ assert ("jn.representation.same_string (%"2147483648%")", jn.representation.same_string ("2147483648"))
+ -- Eiffel value -> JSON value -> JSON representation with factory
+ if attached json.value (n32) as l_jn then
+ assert ("l_jn.representation.same_string (%"2147483648%")", l_jn.representation.same_string ("2147483648"))
+ else
+ assert ("json.value (n32) is a JSON_NUMBER", False)
+ end
+
+ -- JSON representation -> JSON value -> Eiffel value
+ -- Note: The JSON_FACTORY will return the smallest INTEGER_* object
+ -- that can represent the value of the JSON number, in this case
+ -- we know it is INTEGER_64 since the value is 2147483648
+ jrep := "2147483648"
+ create parser.make_parser (jrep)
+ if attached {JSON_NUMBER} parser.parse as l_jn then
+ if attached {INTEGER_64} json.object (jn, Void) as i64 then
+ assert ("i64 = 2147483648", i64 = 2147483648)
+ else
+ assert ("json.object (jn, Void) is a INTEGER_64", False)
+ end
+ else
+ assert ("parser.parse is a JSON_NUMBER", False)
+ end
+ end
+
+ test_json_number_and_large_integers
+ local
+ jrep: STRING
+ n64: NATURAL_64
+ jn: JSON_NUMBER
+ parser: JSON_PARSER
+ do
+ n64 := 9223372036854775808
+ -- Eiffel value -> JSON value -> JSON representation
+ create jn.make_natural (n64)
+ assert ("jn.representation.same_string (%"9223372036854775808%")", jn.representation.same_string ("9223372036854775808"))
+ -- Eiffel value -> JSON value -> JSON representation with factory
+ if attached {JSON_NUMBER} json.value (n64) as l_jn then
+ assert ("l_jn.representation.same_string (%"9223372036854775808%")", l_jn.representation.same_string ("9223372036854775808"))
+ else
+ assert ("json.value (n64) is a JSON_NUMBER", False)
+ end
+
+ -- JSON representation -> JSON value -> Eiffel value
+ -- Note: The JSON_FACTORY will return the smallest INTEGER_* object
+ -- that can represent the value of the JSON number, in this case
+ -- we know it is INTEGER_32 since the value is 42949672960
+ jrep := "9223372036854775808" -- 1 higher than largest positive number that can be represented by INTEGER 64
+ create parser.make_parser (jrep)
+ if attached {JSON_NUMBER} parser.parse as l_jn then
+ if attached {NATURAL_64} json.object (jn, Void) as l_n64 then
+ assert ("l_n64 = 9223372036854775808", l_n64 = 9223372036854775808)
+ else
+ assert ("json.object (jn, Void) is a NATURAL_64", False)
+ end
+ else
+ assert ("parser.parse is a JSON_NUMBER", False)
+ end
+ end
+
+ test_json_number_and_eiffel_real
+ local
+ r: REAL
+ jn: JSON_NUMBER
+ jrep: STRING
+ parser: JSON_PARSER
+ do
+ r := 3.14
+ -- Eiffel value -> JSON value -> JSON representation
+ create jn.make_real (r)
+ assert ("jn.representation.same_string (%"3.1400001049041748%")", jn.representation.same_string ("3.1400001049041748"))
+ -- Eiffel value -> JSON value -> JSON representation with factory
+ if attached {JSON_NUMBER} json.value (r) as l_jn then
+ assert ("l_jn.representation.same_string (%"3.1400001049041748%")", l_jn.representation.same_string ("3.1400001049041748"))
+ else
+ assert ("json.value (r) is a JSON_NUMBER", False)
+ end
+
+ -- JSON representation -> JSON value -> Eiffel value
+ -- Note: The JSON_FACTORY will always return a REAL_64 if the value
+ -- of the JSON number is a floating point number
+ jrep := "3.14"
+ create parser.make_parser (jrep)
+ if attached {JSON_NUMBER} parser.parse as l_jn then
+ if attached {REAL_64} json.object (jn, Void) as r64 then
+ assert ("3.14 <= r64 and r64 <= 3.141", 3.14 <= r64 and r64 <= 3.141)
+ else
+ assert ("json.object (jn, Void) is a REAL_64", False)
+ end
+ else
+ assert ("parser.parse is a JSON_NUMBER", False)
+ end
+ end
+
+ test_json_number_and_eiffel_real_32
+ local
+ r32: REAL_32
+ jn: JSON_NUMBER
+ jrep: STRING
+ parser: JSON_PARSER
+ do
+ r32 := 3.14
+ -- Eiffel value -> JSON value -> JSON representation
+ create jn.make_real (r32)
+ assert ("jn.representation.same_string (%"3.1400001049041748%")", jn.representation.same_string ("3.1400001049041748"))
+ -- Eiffel value -> JSON value -> JSON representation with factory
+ if attached {JSON_NUMBER} json.value (r32) as l_jn then
+ assert ("l_jn.representation.same_string (%"3.1400001049041748%")", l_jn.representation.same_string ("3.1400001049041748"))
+ else
+ assert ("json.value (r32) is a JSON_NUMBER", False)
+ end
+
+ -- JSON representation -> JSON value -> Eiffel value
+ jrep := "3.1400001049041748"
+ create parser.make_parser (jrep)
+ if attached {JSON_NUMBER} parser.parse as l_jn then
+ if attached {REAL_64} json.object (l_jn, Void) as r64 then
+ assert ("r64 = 3.1400001049041748", r64 = 3.1400001049041748)
+ else
+ assert ("json.object (l_jn, Void) is a REAL_64", False)
+ end
+ else
+ assert ("parser.parse is a JSON_NUMBER", False)
+ end
+ end
+
+ test_json_number_and_eiffel_real_64
+ local
+ r64: REAL_64
+ jn: JSON_NUMBER
+ jrep: STRING
+ parser: JSON_PARSER
+ do
+ r64 := 3.1415926535897931
+ -- Eiffel value -> JSON value -> JSON representation
+ create jn.make_real (r64)
+ assert ("jn.representation.same_string (%"3.1415926535897931%")", jn.representation.same_string ("3.1415926535897931"))
+
+ -- Eiffel value -> JSON value -> JSON representation with factory
+ if attached {JSON_NUMBER} json.value (r64) as l_jn then
+ assert ("l_jn.representation.same_string (%"3.1415926535897931%")", l_jn.representation.same_string ("3.1415926535897931"))
+ else
+ assert ("json.value (r64) is a JSON_NUMBER", False)
+ end
+
+ -- JSON representation -> JSON value -> Eiffel value
+ jrep := "3.1415926535897931"
+ create parser.make_parser (jrep)
+ if attached {JSON_NUMBER} parser.parse as l_jn then
+ if attached {REAL_64} json.object (jn, Void) as l_r64 then
+ assert ("l_r64 = 3.1415926535897931", l_r64 = 3.1415926535897931)
+ else
+ assert ("json.object (jn, Void) is a REAL_64", False)
+ end
+ else
+ assert ("parser.parse is a JSON_NUMBER", False)
+ end
+ end
+
+ test_json_boolean
+ local
+ parser: JSON_PARSER
+ jb: JSON_BOOLEAN
+ b: BOOLEAN
+ do
+ -- Eiffel value -> JSON value -> JSON representation
+ b := True
+ create jb.make_boolean (b)
+ assert ("jb.representation.is_equal (%"true%")", jb.representation.is_equal ("true"))
+ -- Eiffel value -> JSON value -> JSON representation with factory
+ if attached {JSON_BOOLEAN} json.value (b) as l_jb then
+ assert ("l_jb.representation.same_string (%"true%")", l_jb.representation.same_string ("true"))
+ else
+ assert ("l_jb /= Void", False)
+ end
+
+ -- JSON representation -> JSON value -> Eiffel value
+ create parser.make_parser ("true")
+ if attached {JSON_BOOLEAN} parser.parse as l_jb then
+ if attached {BOOLEAN} json.object (l_jb, Void) as l_b then
+ assert ("l_b = True", l_b = True)
+ else
+ assert ("json.object (l_jb, Void) is BOOLEAN", False)
+ end
+ else
+ assert ("parser.parse is a JSON_BOOLEAN", False)
+ end
+
+ -- Eiffel value -> JSON value -> JSON representation
+ b := False
+ create jb.make_boolean (b)
+ assert ("jb.representation.same_string (%"false%")", jb.representation.same_string ("false"))
+ -- Eiffel value -> JSON value -> JSON representation with factory
+ if attached {JSON_BOOLEAN} json.value (b) as l_jb then
+ assert ("l_jb.representation.same_string (%"false%")", l_jb.representation.same_string ("false"))
+ else
+ assert ("json.value (b) is a JSON_BOOLEAN", False)
+ end
+
+ -- JSON representation -> JSON value -> Eiffel value
+ create parser.make_parser ("false")
+ if attached {JSON_BOOLEAN} parser.parse as l_jb then
+ if attached {BOOLEAN} json.object (l_jb, Void) as l_b then
+ assert ("l_b = False", l_b = False)
+ else
+ assert ("json.object (l_jb, Void) is a BOOLEAN", False)
+ end
+ else
+ assert ("parser.parse is a JSON_BOOLEAN", False)
+ end
+ end
+
+ test_json_null
+ local
+ a: detachable ANY
+ dummy_object: STRING
+ jn: detachable JSON_NULL
+ jrep: STRING
+ parser: JSON_PARSER
+ do
+ -- Eiffel value -> JSON value -> JSON representation
+ create jn
+ assert ("jn /= Void", jn /= Void)
+ assert ("jn.representation.is_equal (%"%"null%"%")", jn.representation.is_equal ("null"))
+ -- Eiffel value -> JSON value -> JSON representation with factory
+ jn ?= json.value (Void)
+ assert ("jn /= Void", jn /= Void)
+ if attached jn as l_jn then
+ assert ("jn.representation.is_equal (%"null%")", l_jn.representation.is_equal ("null"))
+ end
+
+ -- JSON representation -> JSON value -> Eiffel value
+ jrep := "null"
+ create parser.make_parser (jrep)
+ jn := Void
+ jn ?= parser.parse
+ assert ("jn /= Void", jn /= Void)
+ create dummy_object.make_empty
+ a := dummy_object
+ a ?= json.object (jn, Void)
+ assert ("a = Void", a = Void)
+ end
+
+ test_json_string_and_character
+ local
+ c: CHARACTER
+ js: detachable JSON_STRING
+ jrep: STRING
+ parser: JSON_PARSER
+ do
+ c := 'a'
+ -- Eiffel value -> JSON value -> JSON representation
+ create js.make_json (c.out)
+ assert ("js /= Void", js /= Void)
+ assert ("js.representation.is_equal (%"%"a%"%")", js.representation.is_equal ("%"a%""))
+ -- Eiffel value -> JSON value -> JSON representation with factory
+ js ?= json.value (c)
+ assert ("js /= Void", js /= Void)
+ if attached js as l_js then
+ assert ("js.representation.is_equal (%"%"a%"%")", l_js.representation.is_equal ("%"a%""))
+ end
+
+ -- JSON representation -> JSON value -> Eiffel value
+ jrep := "%"a%""
+ create parser.make_parser (jrep)
+ js := Void
+ js ?= parser.parse
+ assert ("js /= Void", js /= Void)
+ if attached {UC_STRING} json.object (js, "UC_STRING") as ucs then
+ assert ("ucs.string.is_equal (%"a%")", ucs.string.is_equal ("a"))
+ end
+ end
+
+ test_json_string_and_string
+ local
+ s: STRING
+ js: detachable JSON_STRING
+ jrep: STRING
+ parser: JSON_PARSER
+ do
+ s := "foobar"
+ -- Eiffel value -> JSON value -> JSON representation
+ create js.make_json (s)
+ assert ("js /= Void", js /= Void)
+ assert ("js.representation.is_equal (%"%"foobar%"%")", js.representation.is_equal ("%"foobar%""))
+ -- Eiffel value -> JSON value -> JSON representation with factory
+ js ?= json.value (s)
+ assert ("js /= Void", js /= Void)
+ if attached js as l_js then
+ assert ("js.representation.is_equal (%"%"foobar%"%")", js.representation.is_equal ("%"foobar%""))
+ end
+
+ -- JSON representation -> JSON value -> Eiffel value
+ jrep := "%"foobar%""
+ create parser.make_parser (jrep)
+ js := Void
+ js ?= parser.parse
+ assert ("js /= Void", js /= Void)
+ if attached {UC_STRING} json.object (js, "UC_STRING") as l_ucs then
+ assert ("ucs.string.is_equal (%"foobar%")", l_ucs.string.is_equal ("foobar"))
+ end
+ end
+
+ test_json_string_and_uc_string
+ local
+ js: detachable JSON_STRING
+ ucs: detachable UC_STRING
+ jrep: STRING
+ parser: JSON_PARSER
+ do
+ create ucs.make_from_string ("foobar")
+ -- Eiffel value -> JSON value -> JSON representation
+ create js.make_json (ucs)
+ assert ("js /= Void", js /= Void)
+ assert ("js.representation.is_equal (%"%"foobar%"%")", js.representation.is_equal ("%"foobar%""))
+ -- Eiffel value -> JSON value -> JSON representation with factory
+ js ?= json.value (ucs)
+ assert ("js /= Void", js /= Void)
+ if attached js as l_js then
+ assert ("js.representation.is_equal (%"%"foobar%"%")", l_js.representation.is_equal ("%"foobar%""))
+ end
+
+ -- JSON representation -> JSON value -> Eiffel value
+ jrep := "%"foobar%""
+ create parser.make_parser (jrep)
+ js := Void
+ js ?= parser.parse
+ assert ("js /= Void", js /= Void)
+ ucs := Void
+ ucs ?= json.object (js, "UC_STRING")
+ if attached ucs as l_ucs then
+ assert ("ucs.string.is_equal (%"foobar%")", l_ucs.string.is_equal ("foobar"))
+ end
+ end
+
+ test_json_array
+ local
+ ll: LINKED_LIST [INTEGER_8]
+ ll2: detachable LINKED_LIST [detachable ANY]
+ ja: detachable JSON_ARRAY
+ jn: JSON_NUMBER
+ jrep: STRING
+ parser: JSON_PARSER
+ do
+ -- Eiffel value -> JSON value -> JSON representation
+ create ll.make
+ ll.extend (0)
+ ll.extend (1)
+ ll.extend (1)
+ ll.extend (2)
+ ll.extend (3)
+ ll.extend (5)
+ -- Note: Currently there is no simple way of creating a JSON_ARRAY
+ -- from an LINKED_LIST.
+ create ja.make_array
+ from
+ ll.start
+ until
+ ll.after
+ loop
+ create jn.make_integer (ll.item)
+ ja.add (jn)
+ ll.forth
+ end
+ assert ("ja /= Void", ja /= Void)
+ assert ("ja.representation.is_equal (%"[0,1,1,2,3,5]%")", ja.representation.is_equal ("[0,1,1,2,3,5]"))
+ -- Eiffel value -> JSON value -> JSON representation with factory
+ ja := Void
+ ja ?= json.value (ll)
+ assert ("ja /= Void", ja /= Void)
+ if attached ja as l_ja then
+ assert ("ja.representation.is_equal (%"[0,1,1,2,3,5]%")", l_ja.representation.is_equal ("[0,1,1,2,3,5]"))
+ end
+
+ -- JSON representation -> JSON value -> Eiffel value
+ -- Note: The JSON_FACTORY will return the smallest INTEGER_* object
+ -- that can represent the value of the JSON number, in this case
+ -- it means we will get an LINKED_LIST [ANY] containing the INTEGER_8
+ -- values 0, 1, 1, 2, 3, 5
+ jrep := "[0,1,1,2,3,5]"
+ create parser.make_parser (jrep)
+ ja := Void
+ ja ?= parser.parse
+ assert ("ja /= Void", ja /= Void)
+ ll2 ?= json.object (ja, Void)
+ assert ("ll2 /= Void", ll2 /= Void)
+ --ll.compare_objects
+ --ll2.compare_objects
+ if attached ll2 as l_ll2 then
+ assert ("ll2.is_equal (ll)", l_ll2.is_equal (ll))
+ end
+
+ end
+
+ test_json_object
+ local
+ t, t2: detachable DS_HASH_TABLE [detachable ANY, HASHABLE]
+ i: INTEGER
+ ucs_key, ucs: UC_STRING
+ a: ARRAY [INTEGER]
+ jo: detachable JSON_OBJECT
+ jn: JSON_NUMBER
+ js_key, js: JSON_STRING
+ ja: JSON_ARRAY
+ jrep: STRING
+ parser: JSON_PARSER
+ do
+ -- Eiffel value -> JSON value -> JSON representation
+ -- Note: Currently there is now way of creating a JSON_OBJECT from
+ -- a DS_HASH_TABLE, so we do it manually.
+ -- t = {"name": "foobar", "size": 42, "contents", [0, 1, 1, 2, 3, 5]}
+ json.add_converter (create {JSON_DS_HASH_TABLE_CONVERTER}.make)
+ json.add_converter (create {JSON_UC_STRING_CONVERTER}.make)
+ create jo.make
+ create js_key.make_json ("name")
+ create js.make_json ("foobar")
+ jo.put (js, js_key)
+ create js_key.make_json ("size")
+ create jn.make_integer (42)
+ jo.put (jn, js_key)
+ create js_key.make_json ("contents")
+ create ja.make_array
+ create jn.make_integer (0)
+ ja.add (jn)
+ create jn.make_integer (1)
+ ja.add (jn)
+ create jn.make_integer (1)
+ ja.add (jn)
+ create jn.make_integer (2)
+ ja.add (jn)
+ create jn.make_integer (3)
+ ja.add (jn)
+ create jn.make_integer (5)
+ ja.add (jn)
+ jo.put (ja, js_key)
+ assert ("jo /= Void", jo /= Void)
+ assert ("jo.representation.is_equal (%"{%"name%":%"foobar%",%"size%":42,%"contents%":[0,1,1,2,3,5]}%")", jo.representation.is_equal ("{%"name%":%"foobar%",%"size%":42,%"contents%":[0,1,1,2,3,5]}"))
+ -- Eiffel value -> JSON value -> JSON representation with factory
+ create t.make (3)
+ create ucs_key.make_from_string ("name")
+ create ucs.make_from_string ("foobar")
+ t.put (ucs, ucs_key)
+ create ucs_key.make_from_string ("size")
+ i := 42
+ t.put (i, ucs_key)
+ create ucs_key.make_from_string ("contents")
+ a := <<0, 1, 1, 2, 3, 5>>
+ t.put (a, ucs_key)
+ jo := Void
+ jo ?= json.value (t)
+ assert ("jo /= Void", jo /= Void)
+ if attached jo as l_jo then
+ assert ("jo.representation.is_equal (%"{%"name%":%"foobar%",%"size%":42,%"contents%":[0,1,1,2,3,5]}%")", l_jo.representation.is_equal ("{%"name%":%"foobar%",%"size%":42,%"contents%":[0,1,1,2,3,5]}"))
+ end
+ -- JSON representation -> JSON value -> Eiffel value -> JSON value -> JSON representation
+ jrep := "{%"name%":%"foobar%",%"size%":42,%"contents%":[0,1,1,2,3,5]}"
+ create parser.make_parser (jrep)
+ jo := Void
+ jo ?= parser.parse
+ assert ("jo /= Void", jo /= Void)
+ t2 ?= json.object (jo, "DS_HASH_TABLE")
+ assert ("t2 /= Void", t2 /= Void)
+ jo ?= json.value (t2)
+ assert ("jo /= Void", jo /= Void)
+ if attached jo as l_jo then
+ assert ("jrep.is_equal (jo.representation)", jrep.is_equal (jo.representation))
+ end
+ end
+
+ test_json_failed_json_conversion
+ -- Test converting an Eiffel object to JSON that is based on a class
+ -- for which no JSON converter has been registered.
+ local
+ gv: KL_GOBO_VERSION
+ jv: JSON_VALUE
+ exception: BOOLEAN
+ do
+ if not exception then
+ create gv
+ jv := json.value (gv)
+ else
+ -- exceptions.is_developer_exception is not implemented in gec
+ if Eiffel_compiler.is_ise then
+ assert ("exceptions.is_developer_exception", exceptions.is_developer_exception)
+ -- assert ("exceptions.is_developer_exception_of_name", exceptions.is_developer_exception_of_name ("eJSON exception: Failed to convert Eiffel object to a JSON_VALUE: KL_GOBO_VERSION"))
+ end
+ end
+ rescue
+ exception := True
+ retry
+ end
+
+ test_json_failed_eiffel_conversion
+ -- Test converting from a JSON value to an Eiffel object based on a
+ -- class for which no JSON converter has been registered.
+ local
+ gv: KL_GOBO_VERSION
+ jo: JSON_OBJECT
+ exception: BOOLEAN
+ do
+ if not exception then
+ create jo.make
+ gv ?= json.object (jo, "KL_GOBO_VERSION")
+ else
+ -- exceptions.is_developer_exception is not implemented in gec
+ if Eiffel_compiler.is_ise then
+ assert ("exceptions.is_developer_exception", exceptions.is_developer_exception)
+ -- assert ("exceptions.is_developer_exception_of_name", exceptions.is_developer_exception_of_name ("eJSON exception: Failed to convert JSON_VALUE to an Eiffel object: JSON_OBJECT -> KL_GOBO_VERSION"))
+ end
+ end
+ rescue
+ exception := True
+ retry
+ end
+
+end -- class TEST_JSON_CORE
diff --git a/test/getest/test_json_custom_classes.e b/test/getest/test_json_custom_classes.e
new file mode 100644
index 0000000..59d15c3
--- /dev/null
+++ b/test/getest/test_json_custom_classes.e
@@ -0,0 +1,50 @@
+class TEST_JSON_CUSTOM_CLASSES
+
+inherit
+ SHARED_EJSON
+
+ TS_TEST_CASE
+
+create
+ make_default
+
+feature {NONE} -- Initialization
+
+ make
+ -- Create test object.
+ do
+ end
+
+feature -- Test
+
+ test_custom_classes
+ local
+ bc: BOOK_COLLECTION
+ jbc: JSON_BOOK_CONVERTER
+ jbcc: JSON_BOOK_COLLECTION_CONVERTER
+ jac: JSON_AUTHOR_CONVERTER
+ jo: JSON_OBJECT
+ parser: JSON_PARSER
+ jrep: STRING
+ do
+ Json.add_converter (create {JSON_UC_STRING_CONVERTER}.make)
+ create jbc.make
+ json.add_converter (jbc)
+ create jbcc.make
+ json.add_converter (jbcc)
+ create jac.make
+ json.add_converter (jac)
+ jrep := "{%"name%":%"Test collection%",%"books%":[{%"title%":%"eJSON: The Definitive Guide%",%"isbn%":%"123123-413243%",%"author%":{%"name%":%"Foo Bar%"}}]}"
+ create parser.make_parser (jrep)
+ jo := Void
+ jo ?= parser.parse
+ assert ("jo /= Void", jo /= Void)
+ bc := Void
+ bc ?= json.object (jo, "BOOK_COLLECTION")
+ assert ("bc /= Void", bc /= Void)
+ jo ?= json.value (bc)
+ assert ("jo /= Void", jo /= Void)
+ assert ("JSON representation is correct", jo.representation.is_equal ("{%"name%":%"Test collection%",%"books%":[{%"title%":%"eJSON: The Definitive Guide%",%"isbn%":%"123123-413243%",%"author%":{%"name%":%"Foo Bar%"}}]}"))
+ end
+
+end -- class TEST_JSON_CUSTOM_CLASS