diff --git a/.gitmodules b/.gitmodules index 19d4dc1e..e6bec3c7 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,3 @@ -[submodule "contrib/library/text/parser/json"] - path = contrib/library/text/parser/json - url = https://github.com/Eiffel-World/json.git [submodule "contrib/ise_library/cURL"] path = contrib/ise_library/cURL url = https://github.com/EiffelSoftware/mirror-Eiffel-cURL.git diff --git a/contrib/library/text/parser/json b/contrib/library/text/parser/json deleted file mode 160000 index c873d62e..00000000 --- a/contrib/library/text/parser/json +++ /dev/null @@ -1 +0,0 @@ -Subproject commit c873d62efa58ab1da3223cebd8e4f4670b24cd72 diff --git a/contrib/library/text/parser/json/History.txt b/contrib/library/text/parser/json/History.txt new file mode 100644 index 00000000..10ff48c6 --- /dev/null +++ b/contrib/library/text/parser/json/History.txt @@ -0,0 +1,26 @@ +History file for EJSON +====================== + +team: "" +date: "2011-07-06" +revision: "0.3.0" + + ++++++++++++++++++++++Important Changes since 0.2.0 version++++++++++++++++++++++++++++++++++++++++++++++ + +*Updated skip_white_spaces, now check %U and %T codes + +*Undo changes to is_a_valid_number, because it's doesn't follow the +JSON spec. Tests : fail13.json, fail29.json and fail30.json are valid +with this implementation, so we go back to the previous +implementation. + +*Added autotest test suite + +*Added getest based test program + +*Updated Eiffel configuration file, updated to the new clusters + +*Added converters and factory classes + +*Added new top level directories; library, test, build and example \ No newline at end of file diff --git a/contrib/library/text/parser/json/License.txt b/contrib/library/text/parser/json/License.txt new file mode 100644 index 00000000..24c06993 --- /dev/null +++ b/contrib/library/text/parser/json/License.txt @@ -0,0 +1,20 @@ +Copyright (c) 2010 Javier Velilla and others, http://ejson.origo.ethz.ch + + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. \ No newline at end of file diff --git a/contrib/library/text/parser/json/Readme.txt b/contrib/library/text/parser/json/Readme.txt new file mode 100644 index 00000000..bd8ce28d --- /dev/null +++ b/contrib/library/text/parser/json/Readme.txt @@ -0,0 +1,97 @@ +Readme file for eJSON +===================== + +team: "Javier Velilla,Jocelyn Fiat, Paul Cohen" +date: "$Date$" +revision: "$Revision$" + +1. Introduction +--------------- + +eJSON stands for Eiffel JSON library and is a small Eiffel library for dealing +with the JSON format. The objective of the library is to provide two basic +features Eiffel2JSON and JSON2Eiffel. + +2. Legal stuff +-------------- + +eJSON is copyrighted by the author Javier Velilla and others. It is licensed +under the MIT License. See the file license.txt in the same directory as this +readme file. + +3. Versioning scheme +-------------------- + +eJSON version numbers has the form: + + «major number».«minor number».«patch level» + +eJSON will retain the major number 0 as long as it has beta status. A change in +major number indicates that a release is not backward compatible. A change in +minor number indicates that a release is backward compatible (within that major +number) but that new useful features may have been added. A change in patch +level simply indicates that the release contains bug fixes for the previous +release. Note that as long as eJSON is in beta status (0.Y.Z) backward +compatibility is not guranteed for changes in minor numbers! + +4. Documentation +--------------- + +Currently the only documentation on eJSON is available at: + + http://ejson.origo.ethz.ch/wiki/user_guide + +5. Requirements and installation +-------------------------------- + +EJSON requires that you have: + +1. Gobo 3.9 installed or later +2. One of the following compiler combinations installed: + * ISE Eiffel 6.5 or later. + * gec [try to test] + * tecomp [try to test] + +eJSON probably works fine with other versions of the above compilers. +There are no known platform dependencies (Windows, Linux). + +To install eJSON simply extract the ejson-X.Y.Z.zip file to some appropriate +place on your hard disk. There are no requirements on environment variables or +registry variables. + +To verify that everything works you should compile the example programs and/or +the test program. + +6. Contents of eJSON +-------------------- + +All directory names below are relative to the root directory of your ejson +installation. + +Directory Description +--------- ----------- +doc Contains the eJSON.pdf documentation file. +examples Contains the two example programs. +ejson Contains the actual eJSON library classes. +test Contains a test program for eJSON. + +7. Contacting the Team +---------------------- + +Contact the team: + + Javier Velilla «javier.hector@gmail.com» + Paul Cohen «paco@seibostudios.se» + Jocelyn Fiat «jfiat@eiffel.com» + +8. Releases +----------- + +For more information on what was changed in each release look in the file +history.txt. + +Version Date Description +------- ---- ----------- +0.3.0 2011-07-06 JSON Factory Converters +0.2.0 2010-02-07 Adapted to EiffelStudio 6.4 or later, supports void-safety +0.1.0 2010-02-07 First release, Adapted to SmartEiffel 1.2r7 and EiffelStudio 6.2 or previous \ No newline at end of file diff --git a/contrib/library/text/parser/json/library/extras/file/json_file_reader.e b/contrib/library/text/parser/json/library/extras/file/json_file_reader.e new file mode 100644 index 00000000..3629c475 --- /dev/null +++ b/contrib/library/text/parser/json/library/extras/file/json_file_reader.e @@ -0,0 +1,38 @@ +note + description: "Objects that ..." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + JSON_FILE_READER + +feature -- Access + + read_json_from (a_path: STRING): detachable STRING + local + l_file: PLAIN_TEXT_FILE + template_content: STRING + l_last_string: detachable STRING + do + create l_file.make (a_path) + -- We perform several checks until we make a real attempt to open the file. + if not l_file.exists then + print ("error: '" + a_path + "' does not exist%N") + else + if not l_file.is_readable then + print ("error: '" + a_path + "' is not readable.%N") + else + l_file.open_read + create template_content.make_empty + l_file.read_stream (l_file.count) + l_last_string := l_file.last_string + check l_last_string /= Void end -- implied by postcondition of `l_file.read_stream' + template_content.append (l_last_string.string) + Result := template_content + l_file.close + end + end + end + +end diff --git a/contrib/library/text/parser/json/library/extras/visitor/json_visitor.e b/contrib/library/text/parser/json/library/extras/visitor/json_visitor.e new file mode 100644 index 00000000..bf2f583e --- /dev/null +++ b/contrib/library/text/parser/json/library/extras/visitor/json_visitor.e @@ -0,0 +1,59 @@ +note + description: + + "JSON Visitor" + + pattern: "Visitor" + author: "Javier Velilla" + license:"MIT (see http://www.opensource.org/licenses/mit-license.php)" + date: "2008/08/24" + revision: "Revision 0.1" + +deferred class + JSON_VISITOR + +feature -- Visitor Pattern + + visit_json_array (a_json_array: JSON_ARRAY) + -- Visit `a_json_array'. + require + a_json_array_not_void: a_json_array /= Void + deferred + end + + visit_json_boolean (a_json_boolean: JSON_BOOLEAN) + -- Visit `a_json_boolean'. + require + a_json_boolean_not_void: a_json_boolean /= Void + deferred + end + + visit_json_null (a_json_null: JSON_NULL) + -- Visit `a_json_null'. + require + a_json_null_not_void: a_json_null /= Void + deferred + end + + visit_json_number (a_json_number: JSON_NUMBER) + -- Visit `a_json_number'. + require + a_json_number_not_void: a_json_number /= Void + deferred + end + + visit_json_object (a_json_object: JSON_OBJECT) + -- Visit `a_json_object'. + require + a_json_object_not_void: a_json_object /= Void + deferred + end + + visit_json_string (a_json_string: JSON_STRING) + -- Visit `a_json_string'. + require + a_json_string_not_void: a_json_string /= Void + deferred + end + +end diff --git a/contrib/library/text/parser/json/library/extras/visitor/print_json_visitor.e b/contrib/library/text/parser/json/library/extras/visitor/print_json_visitor.e new file mode 100644 index 00000000..6fa64558 --- /dev/null +++ b/contrib/library/text/parser/json/library/extras/visitor/print_json_visitor.e @@ -0,0 +1,102 @@ +note + description: "PRINT_JSON_VISITOR Generates the JSON-String for a JSON_VALUE" + author: "jvelilla" + date: "2008/08/24" + revision: "0.1" + +class + PRINT_JSON_VISITOR + +inherit + JSON_VISITOR + +create make + +feature -- Initialization + + make + -- Create a new instance + do + create to_json.make_empty + end + +feature -- Access + + to_json: STRING + -- JSON representation + +feature -- Visitor Pattern + + visit_json_array (a_json_array: JSON_ARRAY) + -- Visit `a_json_array'. + local + value: JSON_VALUE + l_json_array: ARRAYED_LIST [JSON_VALUE] + do + l_json_array:=a_json_array.array_representation + to_json.append ("[") + from + l_json_array.start + until + l_json_array.off + loop + value := l_json_array.item + value.accept (Current) + l_json_array.forth + if not l_json_array.after then + to_json.append(",") + end + end + to_json.append ("]") + end + + visit_json_boolean (a_json_boolean: JSON_BOOLEAN) + -- Visit `a_json_boolean'. + do + to_json.append (a_json_boolean.item.out) + end + + visit_json_null (a_json_null: JSON_NULL) + -- Visit `a_json_null'. + do + to_json.append ("null") + end + + visit_json_number (a_json_number: JSON_NUMBER) + -- Visit `a_json_number'. + do + to_json.append (a_json_number.item) + end + + visit_json_object (a_json_object: JSON_OBJECT) + -- Visit `a_json_object'. + local + l_pairs: HASH_TABLE[JSON_VALUE,JSON_STRING] + do + l_pairs := a_json_object.map_representation + to_json.append ("{") + from + l_pairs.start + until + l_pairs.off + loop + l_pairs.key_for_iteration.accept (Current) + to_json.append (":") + l_pairs.item_for_iteration.accept (Current) + l_pairs.forth + if not l_pairs.after then + to_json.append (",") + end + end + to_json.append ("}") + end + + visit_json_string (a_json_string: JSON_STRING) + -- Visit `a_json_string'. + do + to_json.append ("%"") + to_json.append (a_json_string.item) + to_json.append ("%"") + end + +end diff --git a/contrib/library/text/parser/json/library/gobo/converters/json_ds_hash_table_converter.e b/contrib/library/text/parser/json/library/gobo/converters/json_ds_hash_table_converter.e new file mode 100644 index 00000000..e2532c57 --- /dev/null +++ b/contrib/library/text/parser/json/library/gobo/converters/json_ds_hash_table_converter.e @@ -0,0 +1,81 @@ +note + description: "A JSON converter for DS_HASH_TABLE [ANY, HASHABLE]" + author: "Paul Cohen" + date: "$Date: $" + revision: "$Revision: $" + file: "$HeadURL: $" + +class JSON_DS_HASH_TABLE_CONVERTER + +inherit + JSON_CONVERTER + +create + make + +feature {NONE} -- Initialization + + make + do + create object.make (0) + end + +feature -- Access + + value: JSON_OBJECT + + object: DS_HASH_TABLE [ANY, HASHABLE] + +feature -- Conversion + + from_json (j: like value): detachable like object + local + keys: ARRAY [JSON_STRING] + i: INTEGER + h: HASHABLE + a: ANY + do + keys := j.current_keys + create Result.make (keys.count) + from + i := 1 + until + i > keys.count + loop + h ?= json.object (keys [i], void) + check h /= Void end + a := json.object (j.item (keys [i]), Void) + Result.put (a, h) + i := i + 1 + end + end + + to_json (o: like object): like value + local + c: DS_HASH_TABLE_CURSOR [ANY, HASHABLE] + js: JSON_STRING + jv: JSON_VALUE + failed: BOOLEAN + do + create Result.make + from + c := o.new_cursor + c.start + until + c.after + loop + create js.make_json (c.key.out) + jv := json.value (c.item) + if jv /= Void then + Result.put (jv, js) + else + failed := True + end + c.forth + end + if failed then + Result := Void + end + end + +end -- class JSON_DS_HASH_TABLE_CONVERTER diff --git a/contrib/library/text/parser/json/library/gobo/converters/json_ds_linked_list_converter.e b/contrib/library/text/parser/json/library/gobo/converters/json_ds_linked_list_converter.e new file mode 100644 index 00000000..bf1aa516 --- /dev/null +++ b/contrib/library/text/parser/json/library/gobo/converters/json_ds_linked_list_converter.e @@ -0,0 +1,62 @@ +note + description: "A JSON converter for DS_LINKED_LIST [ANY]" + author: "Paul Cohen" + date: "$Date: $" + revision: "$Revision: $" + file: "$HeadURL: $" + +class JSON_DS_LINKED_LIST_CONVERTER + +inherit + JSON_CONVERTER + +create + make + +feature {NONE} -- Initialization + + make + do + create object.make + end + +feature -- Access + + value: JSON_ARRAY + + object: DS_LINKED_LIST [ANY] + +feature -- Conversion + + from_json (j: like value): detachable like object + local + i: INTEGER + do + create Result.make + from + i := 1 + until + i > j.count + loop + Result.put_last (json.object (j [i], Void)) + i := i + 1 + end + end + + to_json (o: like object): like value + local + c: DS_LIST_CURSOR [ANY] + do + create Result.make_array + from + c := o.new_cursor + c.start + until + c.after + loop + Result.add (json.value (c.item)) + c.forth + end + end + +end -- class JSON_DS_LINKED_LIST_CONVERTER diff --git a/contrib/library/text/parser/json/library/gobo/shared_gobo_ejson.e b/contrib/library/text/parser/json/library/gobo/shared_gobo_ejson.e new file mode 100644 index 00000000..ccc33432 --- /dev/null +++ b/contrib/library/text/parser/json/library/gobo/shared_gobo_ejson.e @@ -0,0 +1,32 @@ +note + description: "[ + Shared factory class for creating JSON objects. Maps JSON + objects to Gobo DS_HASH_TABLEs and JSON arrays to Gobo + DS_LINKED_LISTs. Use non-conforming inheritance from this + class to ensure that your classes share the same + JSON_FACTORY instance. + ]" + author: "Paul Cohen" + date: "$Date$" + revision: "$Revision$" + file: "$HeadURL: $" + +class SHARED_GOBO_EJSON + +feature + + json: EJSON + -- A shared EJSON instance with default converters for + -- DS_LINKED_LIST [ANY] and DS_HASH_TABLE [ANY, HASHABLE] + local + jllc: JSON_DS_LINKED_LIST_CONVERTER + jhtc: JSON_DS_HASH_TABLE_CONVERTER + once + create Result + create jllc.make + Result.add_converter (jllc) + create jhtc.make + Result.add_converter (jhtc) + end + +end -- class SHARED_GOBO_EJSON \ No newline at end of file diff --git a/contrib/library/text/parser/json/library/json-safe.ecf b/contrib/library/text/parser/json/library/json-safe.ecf new file mode 100644 index 00000000..b957513f --- /dev/null +++ b/contrib/library/text/parser/json/library/json-safe.ecf @@ -0,0 +1,28 @@ + + + + + + /EIFGENs$ + /CVS$ + /.svn$ + + + + + + ^/gobo$ + ^/kernel$ + ^/extras$ + + + + + + diff --git a/contrib/library/text/parser/json/library/json.ecf b/contrib/library/text/parser/json/library/json.ecf new file mode 100644 index 00000000..ee954e09 --- /dev/null +++ b/contrib/library/text/parser/json/library/json.ecf @@ -0,0 +1,28 @@ + + + + + + /EIFGENs$ + /CVS$ + /.svn$ + + + + + + ^/gobo$ + ^/kernel$ + ^/extras$ + + + + + + diff --git a/contrib/library/text/parser/json/library/json.rc b/contrib/library/text/parser/json/library/json.rc new file mode 100644 index 00000000..d3f5a12f --- /dev/null +++ b/contrib/library/text/parser/json/library/json.rc @@ -0,0 +1 @@ + diff --git a/contrib/library/text/parser/json/library/json_gobo_extension.ecf b/contrib/library/text/parser/json/library/json_gobo_extension.ecf new file mode 100644 index 00000000..dd5f9b75 --- /dev/null +++ b/contrib/library/text/parser/json/library/json_gobo_extension.ecf @@ -0,0 +1,17 @@ + + + + + + /EIFGENs$ + /CVS$ + /.svn$ + + + + + + + + diff --git a/contrib/library/text/parser/json/library/kernel/converters/json_converter.e b/contrib/library/text/parser/json/library/kernel/converters/json_converter.e new file mode 100644 index 00000000..bae2bd9c --- /dev/null +++ b/contrib/library/text/parser/json/library/kernel/converters/json_converter.e @@ -0,0 +1,36 @@ +note + description: "A JSON converter" + author: "Paul Cohen" + date: "$Date: $" + revision: "$Revision: $" + file: "$HeadURL: $" + +deferred class JSON_CONVERTER + +inherit + SHARED_EJSON + +feature -- Access + + object: ANY + -- Eiffel object + deferred + end + +feature -- Conversion + + from_json (j: attached like to_json): detachable like object + -- Convert from JSON value. + -- Returns Void if unable to convert + deferred + end + + to_json (o: like object): detachable JSON_VALUE + -- Convert to JSON value + deferred + end + +invariant + has_eiffel_object: object /= Void -- An empty object must be created at creation time! + +end diff --git a/contrib/library/text/parser/json/library/kernel/converters/json_hash_table_converter.e b/contrib/library/text/parser/json/library/kernel/converters/json_hash_table_converter.e new file mode 100644 index 00000000..8ce5260e --- /dev/null +++ b/contrib/library/text/parser/json/library/kernel/converters/json_hash_table_converter.e @@ -0,0 +1,88 @@ +note + description: "A JSON converter for HASH_TABLE [ANY, HASHABLE]" + author: "Paul Cohen" + date: "$Date$" + revision: "$Revision$" + file: "$HeadURL: $" + +class JSON_HASH_TABLE_CONVERTER + +inherit + JSON_CONVERTER + +create + make + +feature {NONE} -- Initialization + + make + do + create object.make (0) + end + +feature -- Access + + object: HASH_TABLE [ANY, HASHABLE] + +feature -- Conversion + + from_json (j: attached like to_json): like object + local + keys: ARRAY [JSON_STRING] + i: INTEGER + h: detachable HASHABLE + jv: detachable JSON_VALUE + a: detachable ANY + do + keys := j.current_keys + create Result.make (keys.count) + from + i := 1 + until + i > keys.count + loop + h ?= json.object (keys [i], void) + check h /= Void end + jv := j.item (keys [i]) + if jv /= Void then + a := json.object (jv, Void) + if a /= Void then + Result.put (a, h) + else + check a_attached: a /= Void end + end + else + check j_has_item: False end + end + i := i + 1 + end + end + + to_json (o: like object): detachable JSON_OBJECT + local + c: HASH_TABLE_ITERATION_CURSOR [ANY, HASHABLE] + js: JSON_STRING + jv: detachable JSON_VALUE + failed: BOOLEAN + do + create Result.make + from + c := o.new_cursor + until + c.after + loop + create js.make_json (c.key.out) + jv := json.value (c.item) + if jv /= Void then + Result.put (jv, js) + else + failed := True + end + c.forth + end + if failed then + Result := Void + end + end + +end -- class JSON_HASH_TABLE_CONVERTER diff --git a/contrib/library/text/parser/json/library/kernel/converters/json_linked_list_converter.e b/contrib/library/text/parser/json/library/kernel/converters/json_linked_list_converter.e new file mode 100644 index 00000000..bcc41e49 --- /dev/null +++ b/contrib/library/text/parser/json/library/kernel/converters/json_linked_list_converter.e @@ -0,0 +1,63 @@ +note + description: "A JSON converter for LINKED_LIST [ANY]" + author: "Paul Cohen" + date: "$Date$" + revision: "$Revision$" + file: "$HeadURL: $" + +class JSON_LINKED_LIST_CONVERTER + +inherit + JSON_CONVERTER + +create + make + +feature {NONE} -- Initialization + + make + do + create object.make + end + +feature -- Access + + object: LINKED_LIST [detachable ANY] + +feature -- Conversion + + from_json (j: like to_json): detachable like object + local + i: INTEGER + do + create Result.make + from + i := 1 + until + i > j.count + loop + Result.extend (json.object (j [i], Void)) + i := i + 1 + end + end + + to_json (o: like object): JSON_ARRAY + local + c: ITERATION_CURSOR [detachable ANY] + do + create Result.make_array + from + c := o.new_cursor + until + c.after + loop + if attached json.value (c.item) as v then + Result.add (v) + else + check attached_value: False end + end + c.forth + end + end + +end -- class JSON_LINKED_LIST_CONVERTER diff --git a/contrib/library/text/parser/json/library/kernel/ejson.e b/contrib/library/text/parser/json/library/kernel/ejson.e new file mode 100644 index 00000000..de9058d5 --- /dev/null +++ b/contrib/library/text/parser/json/library/kernel/ejson.e @@ -0,0 +1,268 @@ +note + description: "Core factory class for creating JSON objects and corresponding Eiffel objects." + author: "Paul Cohen" + date: "$Date: $" + revision: "$Revision: $" + file: "$HeadURL: $" + +class EJSON + +inherit + EXCEPTIONS + +feature -- Access + + value (an_object: detachable ANY): detachable JSON_VALUE + -- JSON value from Eiffel object. Raises an "eJSON exception" if + -- unable to convert value. + local + i: INTEGER + ja: JSON_ARRAY + do + -- Try to convert from basic Eiffel types. Note that we check with + -- `conforms_to' since the client may have subclassed the base class + -- that these basic types are derived from. + if an_object = Void then + create {JSON_NULL} Result + elseif attached {BOOLEAN} an_object as b then + create {JSON_BOOLEAN} Result.make_boolean (b) + elseif attached {INTEGER_8} an_object as i8 then + create {JSON_NUMBER} Result.make_integer (i8) + elseif attached {INTEGER_16} an_object as i16 then + create {JSON_NUMBER} Result.make_integer (i16) + elseif attached {INTEGER_32} an_object as i32 then + create {JSON_NUMBER} Result.make_integer (i32) + elseif attached {INTEGER_64} an_object as i64 then + create {JSON_NUMBER} Result.make_integer (i64) + elseif attached {NATURAL_8} an_object as n8 then + create {JSON_NUMBER} Result.make_natural (n8) + elseif attached {NATURAL_16} an_object as n16 then + create {JSON_NUMBER} Result.make_natural (n16) + elseif attached {NATURAL_32} an_object as n32 then + create {JSON_NUMBER} Result.make_natural (n32) + elseif attached {NATURAL_64} an_object as n64 then + create {JSON_NUMBER} Result.make_natural (n64) + elseif attached {REAL_32} an_object as r32 then + create {JSON_NUMBER} Result.make_real (r32) + elseif attached {REAL_64} an_object as r64 then + create {JSON_NUMBER} Result.make_real (r64) + elseif attached {ARRAY [detachable ANY]} an_object as a then + create ja.make_array + from + i := a.lower + until + i > a.upper + loop + if attached value (a @ i) as v then + ja.add (v) + else + check value_attached: False end + end + i := i + 1 + end + Result := ja + elseif attached {CHARACTER_8} an_object as c8 then + create {JSON_STRING} Result.make_json (c8.out) + elseif attached {CHARACTER_32} an_object as c32 then + create {JSON_STRING} Result.make_json (c32.out) + + elseif attached {STRING_8} an_object as s8 then + create {JSON_STRING} Result.make_json (s8) + elseif attached {STRING_32} an_object as s32 then + create {JSON_STRING} Result.make_json (s32.as_string_8) -- FIXME: need correct convertion/encoding here ... + end + + if Result = Void then + -- Now check the converters + if an_object /= Void and then attached converter_for (an_object) as jc then + Result := jc.to_json (an_object) + else + raise (exception_failed_to_convert_to_json (an_object)) + end + end + end + + object (a_value: detachable JSON_VALUE; base_class: detachable STRING): detachable ANY + -- Eiffel object from JSON value. If `base_class' /= Void an eiffel + -- object based on `base_class' will be returned. Raises an "eJSON + -- exception" if unable to convert value. + local + i: INTEGER + ll: LINKED_LIST [detachable ANY] + t: HASH_TABLE [detachable ANY, STRING_GENERAL] + keys: ARRAY [JSON_STRING] + do + if a_value = Void then + Result := Void + else + if base_class = Void then + if a_value = Void then + Result := Void + elseif attached {JSON_NULL} a_value then + Result := Void + elseif attached {JSON_BOOLEAN} a_value as jb then + Result := jb.item + elseif attached {JSON_NUMBER} a_value as jn then + if jn.item.is_integer_8 then + Result := jn.item.to_integer_8 + elseif jn.item.is_integer_16 then + Result := jn.item.to_integer_16 + elseif jn.item.is_integer_32 then + Result := jn.item.to_integer_32 + elseif jn.item.is_integer_64 then + Result := jn.item.to_integer_64 + elseif jn.item.is_natural_64 then + Result := jn.item.to_natural_64 + elseif jn.item.is_double then + Result := jn.item.to_double + end + elseif attached {JSON_STRING} a_value as js then + create {STRING_32} Result.make_from_string (js.unescaped_string_32) + elseif attached {JSON_ARRAY} a_value as ja then + from + create ll.make + i := 1 + until + i > ja.count + loop + ll.extend (object (ja [i], Void)) + i := i + 1 + end + Result := ll + elseif attached {JSON_OBJECT} a_value as jo then + keys := jo.current_keys + create t.make (keys.count) + from + i := keys.lower + until + i > keys.upper + loop + if attached {STRING_GENERAL} object (keys [i], Void) as s then + t.put (object (jo.item (keys [i]), Void), s) + end + i := i + 1 + end + Result := t + end + else + if converters.has_key (base_class) and then attached converters.found_item as jc then + Result := jc.from_json (a_value) + else + raise (exception_failed_to_convert_to_eiffel (a_value, base_class)) + end + end + end + end + + object_from_json (json: STRING; base_class: detachable STRING): detachable ANY + -- Eiffel object from JSON representation. If `base_class' /= Void an + -- Eiffel object based on `base_class' will be returned. Raises an + -- "eJSON exception" if unable to convert value. + require + json_not_void: json /= Void + local + jv: detachable JSON_VALUE + do + json_parser.set_representation (json) + jv := json_parser.parse + if jv /= Void then + Result := object (jv, base_class) + end + end + + converter_for (an_object: ANY): detachable JSON_CONVERTER + -- Converter for objects. Returns Void if none found. + require + an_object_not_void: an_object /= Void + do + if converters.has_key (an_object.generator) then + Result := converters.found_item + end + end + + json_reference (s: STRING): JSON_OBJECT + -- A JSON (Dojo style) reference object using `s' as the + -- reference value. The caller is responsable for ensuring + -- the validity of `s' as a json reference. + require + s_not_void: s /= Void + local + js_key, js_value: JSON_STRING + do + create Result.make + create js_key.make_json ("$ref") + create js_value.make_json (s) + Result.put (js_value, js_key) + end + + json_references (l: LIST [STRING]): JSON_ARRAY + -- A JSON array of JSON (Dojo style) reference objects using the + -- strings in `l' as reference values. The caller is responsable + -- for ensuring the validity of all strings in `l' as json + -- references. + require + l_not_void: l /= Void + local + c: ITERATION_CURSOR [STRING] + do + create Result.make_array + from + c := l.new_cursor + until + c.after + loop + Result.add (json_reference (c.item)) + c.forth + end + end + +feature -- Change + + add_converter (jc: JSON_CONVERTER) + -- Add the converter `jc'. + require + jc_not_void: jc /= Void + do + converters.force (jc, jc.object.generator) + ensure + has_converter: converter_for (jc.object) /= Void + end + +feature {NONE} -- Implementation + + converters: HASH_TABLE [JSON_CONVERTER, STRING] + -- Converters hashed by generator (base class) + once + create Result.make (10) + end + +feature {NONE} -- Implementation (Exceptions) + + exception_prefix: STRING = "eJSON exception: " + + exception_failed_to_convert_to_eiffel (a_value: JSON_VALUE; base_class: detachable STRING): STRING + -- Exception message for failing to convert a JSON_VALUE to an instance of `a'. + do + Result := exception_prefix + "Failed to convert JSON_VALUE to an Eiffel object: " + a_value.generator + if base_class /= Void then + Result.append (" -> " + base_class) + end + end + + exception_failed_to_convert_to_json (an_object: detachable ANY): STRING + -- Exception message for failing to convert `a' to a JSON_VALUE. + do + Result := exception_prefix + "Failed to convert Eiffel object to a JSON_VALUE" + if an_object /= Void then + Result := ": " + an_object.generator + end + end + +feature {NONE} -- Implementation (JSON parser) + + json_parser: JSON_PARSER + once + create Result.make_parser ("") + end + +end -- class EJSON diff --git a/contrib/library/text/parser/json/library/kernel/json_array.e b/contrib/library/text/parser/json/library/kernel/json_array.e new file mode 100644 index 00000000..dc51e1cb --- /dev/null +++ b/contrib/library/text/parser/json/library/kernel/json_array.e @@ -0,0 +1,141 @@ +note + description: "[ + JSON_ARRAY represent an array in JSON. + An array in JSON is an ordered set of names. + Examples + array + [] + [elements] + ]" + + author: "Javier Velilla" + date: "2008/08/24" + revision: "Revision 0.1" + +class + JSON_ARRAY + +inherit + JSON_VALUE + + DEBUG_OUTPUT + +create + make_array + +feature {NONE} -- Initialization + + make_array + -- Initialize JSON Array + do + create values.make (10) + end + +feature -- Access + + i_th alias "[]" (i: INTEGER): JSON_VALUE + -- Item at `i'-th position + require + is_valid_index: valid_index (i) + do + Result := values.i_th (i) + end + + representation: STRING + local + i: INTEGER + do + Result := "[" + from + i := 1 + until + i > count + loop + Result.append (i_th (i).representation) + i := i + 1 + if i <= count then + Result.append_character (',') + end + end + Result.append_character (']') + end + +feature -- Visitor pattern + + accept (a_visitor: JSON_VISITOR) + -- Accept `a_visitor'. + -- (Call `visit_json_array' procedure on `a_visitor'.) + do + a_visitor.visit_json_array (Current) + end + +feature -- Mesurement + + count: INTEGER + -- Number of items. + do + Result := values.count + end + +feature -- Status report + + valid_index (i: INTEGER): BOOLEAN + -- Is `i' a valid index? + do + Result := (1 <= i) and (i <= count) + end + +feature -- Change Element + + add (value: JSON_VALUE) + require + value_not_null: value /= void + do + values.extend (value) + ensure + has_new_value: old values.count + 1 = values.count and + values.has (value) + end + +feature -- Report + + hash_code: INTEGER + -- Hash code value + do + from + values.start + Result := values.item.hash_code + until + values.off + loop + Result:= ((Result \\ 8388593) |<< 8) + values.item.hash_code + values.forth + end + Result := Result \\ values.count + end + +feature -- Conversion + + array_representation: ARRAYED_LIST [JSON_VALUE] + -- Representation as a sequences of values + do + Result := values + end + +feature -- Status report + + debug_output: STRING + -- String that should be displayed in debugger to represent `Current'. + do + Result := count.out + end + +feature {NONE} -- Implementation + + values: ARRAYED_LIST [JSON_VALUE] + -- Value container + +invariant + value_not_void: values /= Void + +end diff --git a/contrib/library/text/parser/json/library/kernel/json_boolean.e b/contrib/library/text/parser/json/library/kernel/json_boolean.e new file mode 100644 index 00000000..32e7634a --- /dev/null +++ b/contrib/library/text/parser/json/library/kernel/json_boolean.e @@ -0,0 +1,61 @@ +note + description: "JSON Truth values" + author: "Javier Velilla" + date: "2008/08/24" + revision: "Revision 0.1" + +class + JSON_BOOLEAN + +inherit + JSON_VALUE + +create + make_boolean + +feature {NONE} -- Initialization + + make_boolean (an_item: BOOLEAN) + --Initialize. + do + item := an_item + end + +feature -- Access + + item: BOOLEAN + -- Content + + hash_code: INTEGER + -- Hash code value + do + Result := item.hash_code + end + + representation: STRING + do + if item then + Result := "true" + else + Result := "false" + end + end + +feature -- Visitor pattern + + accept (a_visitor: JSON_VISITOR) + -- Accept `a_visitor'. + -- (Call `visit_json_boolean' procedure on `a_visitor'.) + do + a_visitor.visit_json_boolean (Current) + end + +feature -- Status report + + debug_output: STRING + -- String that should be displayed in debugger to represent `Current'. + do + Result := item.out + end + +end diff --git a/contrib/library/text/parser/json/library/kernel/json_null.e b/contrib/library/text/parser/json/library/kernel/json_null.e new file mode 100644 index 00000000..176b7d38 --- /dev/null +++ b/contrib/library/text/parser/json/library/kernel/json_null.e @@ -0,0 +1,47 @@ +note + description: "JSON Null Values" + author: "Javier Velilla" + date: "2008/08/24" + revision: "Revision 0.1" + +class + JSON_NULL + +inherit + JSON_VALUE + +feature --Access + + hash_code: INTEGER + -- Hash code value + do + Result := null_value.hash_code + end + + representation: STRING + do + Result := "null" + end + +feature -- Visitor pattern + + accept (a_visitor: JSON_VISITOR) + -- Accept `a_visitor'. + -- (Call `visit_element_a' procedure on `a_visitor'.) + do + a_visitor.visit_json_null (Current) + end + +feature -- Status report + + debug_output: STRING + -- String that should be displayed in debugger to represent `Current'. + do + Result := null_value + end + +feature {NONE}-- Implementation + + null_value: STRING = "null" + +end diff --git a/contrib/library/text/parser/json/library/kernel/json_number.e b/contrib/library/text/parser/json/library/kernel/json_number.e new file mode 100644 index 00000000..69b5011e --- /dev/null +++ b/contrib/library/text/parser/json/library/kernel/json_number.e @@ -0,0 +1,99 @@ +note + + description: "JSON Numbers, octal and hexadecimal formats are not used." + author: "Javier Velilla" + date: "2008/08/24" + revision: "Revision 0.1" + license:"MIT (see http://www.opensource.org/licenses/mit-license.php)" + +class + JSON_NUMBER + +inherit + JSON_VALUE + redefine + is_equal + end + +create + make_integer, + make_natural, + make_real + +feature {NONE} -- initialization + + make_integer (an_argument: INTEGER_64) + -- Initialize an instance of JSON_NUMBER from the integer value of `an_argument'. + do + item := an_argument.out + numeric_type := INTEGER_TYPE + end + + make_natural (an_argument: NATURAL_64) + -- Initialize an instance of JSON_NUMBER from the unsigned integer value of `an_argument'. + do + item := an_argument.out + numeric_type := NATURAL_TYPE + end + + make_real (an_argument: DOUBLE) + -- Initialize an instance of JSON_NUMBER from the floating point value of `an_argument'. + do + item := an_argument.out + numeric_type := DOUBLE_TYPE + end + +feature -- Access + + item: STRING + -- Content + + hash_code: INTEGER + --Hash code value + do + Result := item.hash_code + end + + representation: STRING + do + Result := item + end + +feature -- Visitor pattern + + accept (a_visitor: JSON_VISITOR) + -- Accept `a_visitor'. + -- (Call `visit_json_number' procedure on `a_visitor'.) + do + a_visitor.visit_json_number (Current) + end + +feature -- Status + + is_equal (other: like Current): BOOLEAN + -- Is `other' attached to an object of the same type + -- as current object and identical to it? + do + Result := item.is_equal (other.item) + end + +feature -- Status report + + debug_output: STRING + -- String that should be displayed in debugger to represent `Current'. + do + Result := item + end + +feature -- Implementation + + INTEGER_TYPE: INTEGER = 1 + DOUBLE_TYPE: INTEGER = 2 + NATURAL_TYPE: INTEGER = 3 + + numeric_type: INTEGER + +invariant + item_not_void: item /= Void + +end diff --git a/contrib/library/text/parser/json/library/kernel/json_object.e b/contrib/library/text/parser/json/library/kernel/json_object.e new file mode 100644 index 00000000..ba0ad5b5 --- /dev/null +++ b/contrib/library/text/parser/json/library/kernel/json_object.e @@ -0,0 +1,160 @@ +note + + description: "[ + An JSON_OBJECT represent an object in JSON. + An object is an unordered set of name/value pairs + + Examples: + + object + {} + {"key","value"} + + ]" + author: "Javier Velilla" + date: "2008/08/24" + revision: "Revision 0.1" + license:"MIT (see http://www.opensource.org/licenses/mit-license.php)" + +class + JSON_OBJECT + +inherit + JSON_VALUE + +create + make + +feature {NONE} -- Initialization + + make + -- Initialize + do + create object.make (10) + end + +feature -- Change Element + + put (value: detachable JSON_VALUE; key: JSON_STRING) + -- Assuming there is no item of key `key', + -- insert `value' with `key'. + require + key_not_present: not has_key (key) + local + l_value: detachable JSON_VALUE + do + l_value := value + if l_value = Void then + create {JSON_NULL} l_value + end + object.extend (l_value, key) + end + +feature -- Access + + has_key (key: JSON_STRING): BOOLEAN + -- has the JSON_OBJECT contains a specific key 'key'. + do + Result := object.has (key) + end + + has_item (value: JSON_VALUE): BOOLEAN + -- has the JSON_OBJECT contain a specfic item 'value' + do + Result := object.has_item (value) + end + + item (key: JSON_STRING): detachable JSON_VALUE + -- the json_value associated with a key. + do + Result := object.item (key) + end + + current_keys: ARRAY [JSON_STRING] + -- array containing actually used keys + do + Result := object.current_keys + end + + representation: STRING + local + t: HASH_TABLE [JSON_VALUE, JSON_STRING] + do + Result := "{" + from + t := map_representation + t.start + until + t.after + loop + Result.append (t.key_for_iteration.representation) + Result.append (":") + Result.append (t.item_for_iteration.representation) + t.forth + if not t.after then + Result.append_character (',') + end + end + Result.append_character ('}') + end + +feature -- Status report + + is_empty: BOOLEAN + -- Is empty object? + do + Result := object.is_empty + end + +feature -- Visitor pattern + + accept (a_visitor: JSON_VISITOR) + -- Accept `a_visitor'. + -- (Call `visit_json_object' procedure on `a_visitor'.) + do + a_visitor.visit_json_object (Current) + end + +feature -- Conversion + + map_representation: HASH_TABLE [JSON_VALUE, JSON_STRING] + --A representation that maps keys to values + do + Result := object + end + +feature -- Report + + hash_code: INTEGER + -- Hash code value + do + from + object.start + Result := object.item_for_iteration.hash_code + until + object.off + loop + Result := ((Result \\ 8388593) |<< 8) + object.item_for_iteration.hash_code + object.forth + end + -- Ensure it is a positive value. + Result := Result.hash_code + end + +feature -- Status report + + debug_output: STRING + -- String that should be displayed in debugger to represent `Current'. + do + Result := object.count.out + end + +feature {NONE} -- Implementation + + object: HASH_TABLE [JSON_VALUE, JSON_STRING] + -- Value container + +invariant + object_not_null: object /= Void + +end diff --git a/contrib/library/text/parser/json/library/kernel/json_string.e b/contrib/library/text/parser/json/library/kernel/json_string.e new file mode 100644 index 00000000..ccd8e60d --- /dev/null +++ b/contrib/library/text/parser/json/library/kernel/json_string.e @@ -0,0 +1,329 @@ +note + + description: "[ + A JSON_STRING represent a string in JSON. + A string is a collection of zero or more Unicodes characters, wrapped in double + quotes, using blackslash espaces. + ]" + + author: "Javier Velilla" + date: "2008/08/24" + revision: "Revision 0.1" + license:"MIT (see http://www.opensource.org/licenses/mit-license.php)" + + +class + JSON_STRING + +inherit + JSON_VALUE + redefine + is_equal + end + +create + make_json, + make_json_from_string_32, + make_with_escaped_json + +convert + make_json ({READABLE_STRING_8, STRING_8, IMMUTABLE_STRING_8}), + make_json_from_string_32 ({READABLE_STRING_32, STRING_32, IMMUTABLE_STRING_32}) + +feature {NONE} -- Initialization + + make_json (s: READABLE_STRING_8) + -- Initialize. + require + item_not_void: s /= Void + do + make_with_escaped_json (escaped_json_string (s)) + end + + make_json_from_string_32 (s: READABLE_STRING_32) + -- Initialize from STRING_32 `s'. + require + item_not_void: s /= Void + do + make_with_escaped_json (escaped_json_string_32 (s)) + end + + make_with_escaped_json (s: READABLE_STRING_8) + -- Initialize with an_item already escaped + require + item_not_void: s /= Void + do + item := s + end + +feature -- Access + + item: STRING + -- Contents with escaped entities if any + + unescaped_string_8: STRING_8 + -- Unescaped string from `item' + local + s: like item + i, n: INTEGER + c: CHARACTER + do + s := item + n := s.count + create Result.make (n) + from i := 1 until i > n loop + c := s[i] + if c = '\' then + if i < n then + inspect s[i+1] + when '\' then + Result.append_character ('\') + i := i + 2 + when '%"' then + Result.append_character ('%"') + i := i + 2 + when 'n' then + Result.append_character ('%N') + i := i + 2 + when 'r' then + Result.append_character ('%R') + i := i + 2 + when 'u' then + --| Leave unicode \uXXXX unescaped + Result.append_character ('\') + i := i + 1 + else + Result.append_character ('\') + i := i + 1 + end + else + Result.append_character ('\') + i := i + 1 + end + else + Result.append_character (c) + i := i + 1 + end + end + end + + unescaped_string_32: STRING_32 + -- Unescaped string 32 from `item' + local + s: like item + i, n: INTEGER + c: CHARACTER + hex: STRING + do + s := item + n := s.count + create Result.make (n) + from i := 1 until i > n loop + c := s[i] + if c = '\' then + if i < n then + inspect s[i+1] + when '\' then + Result.append_character ('\') + i := i + 2 + when '%"' then + Result.append_character ('%"') + i := i + 2 + when 'n' then + Result.append_character ('%N') + i := i + 2 + when 'r' then + Result.append_character ('%R') + i := i + 2 + when 'u' then + hex := s.substring (i+2, i+2+4 - 1) + if hex.count = 4 then + Result.append_code (hexadecimal_to_natural_32 (hex)) + end + i := i + 2 + 4 + else + Result.append_character ('\') + i := i + 1 + end + else + Result.append_character ('\') + i := i + 1 + end + else + Result.append_character (c.to_character_32) + i := i + 1 + end + end + end + + representation: STRING + -- String representation of `item' with escaped entities if any + do + create Result.make (item.count + 2) + Result.append_character ('%"') + Result.append (item) + Result.append_character ('%"') + end + +feature -- Visitor pattern + + accept (a_visitor: JSON_VISITOR) + -- Accept `a_visitor'. + -- (Call `visit_json_string' procedure on `a_visitor'.) + do + a_visitor.visit_json_string (Current) + end + +feature -- Comparison + + is_equal (other: like Current): BOOLEAN + -- Is JSON_STRING made of same character sequence as `other' + -- (possibly with a different capacity)? + do + Result := item.same_string (other.item) + end + +feature -- Change Element + + append (a_string: STRING) + -- Add a_string + require + a_string_not_void: a_string /= Void + do + item.append_string (a_string) + end + +feature -- Status report + + hash_code: INTEGER + -- Hash code value + do + Result := item.hash_code + end + +feature -- Status report + + debug_output: STRING + -- String that should be displayed in debugger to represent `Current'. + do + Result := item + end + +feature {NONE} -- Implementation + + is_hexadecimal (s: READABLE_STRING_8): BOOLEAN + -- Is `s' an hexadecimal value? + do + Result := across s as scur all scur.item.is_hexa_digit end + end + + hexadecimal_to_natural_32 (s: READABLE_STRING_8): NATURAL_32 + -- Hexadecimal string `s' converted to NATURAL_32 value + require + s_not_void: s /= Void + is_hexadecimal: is_hexadecimal (s) + local + i, nb: INTEGER + char: CHARACTER + do + nb := s.count + + if nb >= 2 and then s.item (2) = 'x' then + i := 3 + else + i := 1 + end + + from + until + i > nb + loop + Result := Result * 16 + char := s.item (i) + if char >= '0' and then char <= '9' then + Result := Result + (char |-| '0').to_natural_32 + else + Result := Result + (char.lower |-| 'a' + 10).to_natural_32 + end + i := i + 1 + end + end + + escaped_json_string (s: READABLE_STRING_8): STRING_8 + -- JSON string with '"' and '\' characters escaped + require + s_not_void: s /= Void + local + i, n: INTEGER + c: CHARACTER_8 + do + n := s.count + create Result.make (n + n // 10) + from i := 1 until i > n loop + c := s.item (i) + inspect c + when '%"' then Result.append_string ("\%"") + when '\' then Result.append_string ("\\") + when '%R' then Result.append_string ("\r") + when '%N' then Result.append_string ("\n") + else + Result.extend (c) + end + i := i + 1 + end + end + + escaped_json_string_32 (s: READABLE_STRING_32): STRING_8 + -- JSON string with '"' and '\' characters and unicode escaped + require + s_not_void: s /= Void + local + i, j, n: INTEGER + uc: CHARACTER_32 + c: CHARACTER_8 + h: STRING_8 + do + n := s.count + create Result.make (n + n // 10) + from i := 1 until i > n loop + uc := s.item (i) + if uc.is_character_8 then + c := uc.to_character_8 + inspect c + when '%"' then Result.append_string ("\%"") + when '\' then Result.append_string ("\\") + when '%R' then Result.append_string ("\r") + when '%N' then Result.append_string ("\n") + else + Result.extend (c) + end + else + Result.append ("\u") + h := uc.code.to_hex_string + -- Remove first 0 and keep 4 hexa digit + from + j := 1 + until + h.count = 4 or (j <= h.count and then h.item (j) /= '0') + loop + j := j + 1 + end + h := h.substring (j, h.count) + + from + until + h.count >= 4 + loop + h.prepend_integer (0) + end + check h.count = 4 end + Result.append (h) + end + i := i + 1 + end + end + +invariant + item_not_void: item /= Void + +end diff --git a/contrib/library/text/parser/json/library/kernel/json_value.e b/contrib/library/text/parser/json/library/kernel/json_value.e new file mode 100644 index 00000000..bbf47c7c --- /dev/null +++ b/contrib/library/text/parser/json/library/kernel/json_value.e @@ -0,0 +1,43 @@ +note + description:"[ + JSON_VALUE represent a value in JSON. + A value can be + * a string in double quotes + * a number + * boolean value(true, false ) + * null + * an object + * an array + ]" + author: "Javier Velilla" + date: "2008/05/19" + revision: "Revision 0.1" + license:"MIT (see http://www.opensource.org/licenses/mit-license.php)" + + +deferred class + JSON_VALUE + +inherit + HASHABLE + + DEBUG_OUTPUT + +feature -- Access + + representation: STRING + -- UTF-8 encoded Unicode string representation of Current + deferred + end + +feature -- Visitor pattern + + accept (a_visitor: JSON_VISITOR) + -- Accept `a_visitor'. + -- (Call `visit_*' procedure on `a_visitor'.) + require + a_visitor_not_void: a_visitor /= Void + deferred + end + +end diff --git a/contrib/library/text/parser/json/library/kernel/scanner/json_parser.e b/contrib/library/text/parser/json/library/kernel/scanner/json_parser.e new file mode 100644 index 00000000..3eaa7388 --- /dev/null +++ b/contrib/library/text/parser/json/library/kernel/scanner/json_parser.e @@ -0,0 +1,513 @@ +note + + description: "Parse serialized JSON data" + author: "jvelilla" + date: "2008/08/24" + revision: "Revision 0.1" + +class + JSON_PARSER + +inherit + JSON_READER + JSON_TOKENS + +create + make_parser + +feature {NONE} -- Initialize + + make_parser (a_json: STRING) + -- Initialize. + require + json_not_empty: a_json /= Void and then not a_json.is_empty + do + make (a_json) + is_parsed := True + create errors.make + end + +feature -- Status report + + is_parsed: BOOLEAN + -- Is parsed? + + errors: LINKED_LIST [STRING] + -- Current errors + + current_errors: STRING + -- Current errors as string + do + create Result.make_empty + from + errors.start + until + errors.after + loop + Result.append_string (errors.item + "%N") + errors.forth + end + end + +feature -- Element change + + report_error (e: STRING) + -- Report error `e' + require + e_not_void: e /= Void + do + errors.force (e) + end + +feature -- Commands + + parse_json: detachable JSON_VALUE + -- Parse JSON data `representation' + -- start ::= object | array + do + if is_valid_start_symbol then + Result := parse + if extra_elements then + is_parsed := False + end + else + is_parsed := False + report_error ("Syntax error unexpected token, expecting `{' or `['") + end + end + + parse: detachable JSON_VALUE + -- Parse JSON data `representation' + local + c: CHARACTER + do + if is_parsed then + skip_white_spaces + c := actual + inspect c + when j_OBJECT_OPEN then + Result := parse_object + when j_STRING then + Result := parse_string + when j_ARRAY_OPEN then + Result := parse_array + else + if c.is_digit or c = j_MINUS then + Result := parse_number + elseif is_null then + Result := create {JSON_NULL} + next + next + next + elseif is_true then + Result := create {JSON_BOOLEAN}.make_boolean (True) + next + next + next + elseif is_false then + Result := create {JSON_BOOLEAN}.make_boolean (False) + next + next + next + next + else + is_parsed := False + report_error ("JSON is not well formed in parse") + Result := Void + end + end + end + ensure + is_parsed_implies_result_not_void: is_parsed implies Result /= Void + end + + parse_object: JSON_OBJECT + -- object + -- {} + -- {"key" : "value" [,]} + local + has_more: BOOLEAN + l_json_string: detachable JSON_STRING + l_value: detachable JSON_VALUE + do + create Result.make + -- check if is an empty object {} + next + skip_white_spaces + if actual = j_OBJECT_CLOSE then + --is an empty object + else + -- a complex object {"key" : "value"} + previous + from has_more := True until not has_more loop + next + skip_white_spaces + l_json_string := parse_string + next + skip_white_spaces + if actual = ':' then + next + skip_white_spaces + else + is_parsed := False + report_error ("%N Input string is a not well formed JSON, expected: : found: " + actual.out) + has_more := False + end + + l_value := parse + if is_parsed and then (l_value /= Void and l_json_string /= Void) then + Result.put (l_value, l_json_string) + next + skip_white_spaces + if actual = j_OBJECT_CLOSE then + has_more := False + elseif actual /= ',' then + has_more := False + is_parsed := False + report_error ("JSON Object syntactically malformed expected , found: [" + actual.out + "]") + end + else + has_more := False + -- explain the error + end + end + end + end + + parse_string: detachable JSON_STRING + -- Parsed string + local + has_more: BOOLEAN + l_json_string: STRING + l_unicode: STRING + c: like actual + do + create l_json_string.make_empty + if actual = j_STRING then + from + has_more := True + until + not has_more + loop + next + c := actual + if c = j_STRING then + has_more := False + elseif c = '%H' then + next + c := actual + if c = 'u' then + create l_unicode.make_from_string ("\u") + l_unicode.append (read_unicode) + c := actual + if is_valid_unicode (l_unicode) then + l_json_string.append (l_unicode) + else + has_more := False + is_parsed := False + report_error ("Input String is not well formed JSON, expected a Unicode value, found [" + c.out + " ]") + end + elseif (not is_special_character (c) and not is_special_control (c)) or c = '%N' then + has_more := False + is_parsed := False + report_error ("Input String is not well formed JSON, found [" + c.out + " ]") + else + l_json_string.append_character ('\') + l_json_string.append_character (c) + end + else + if is_special_character (c) and c /= '/' then + has_more := False + is_parsed := False + report_error ("Input String is not well formed JSON, found [" + c.out + " ]") + else + l_json_string.append_character (c) + end + end + end + create Result.make_with_escaped_json (l_json_string) + else + Result := Void + end + end + + parse_array: JSON_ARRAY + -- array + -- [] + -- [elements [,]] + local + flag: BOOLEAN + l_value: detachable JSON_VALUE + c: like actual + do + create Result.make_array + --check if is an empty array [] + next + skip_white_spaces + if actual = j_array_close then + --is an empty array + else + previous + from + flag := True + until + not flag + loop + next + skip_white_spaces + l_value := parse + if is_parsed and then l_value /= Void then + Result.add (l_value) + next + skip_white_spaces + c := actual + if c = j_ARRAY_CLOSE then + flag := False + elseif c /= ',' then + flag := False + is_parsed := False + report_error ("Array is not well formed JSON, found [" + c.out + " ]") + end + else + flag := False + report_error ("Array is not well formed JSON, found [" + actual.out + " ]") + end + end + end + end + + parse_number: detachable JSON_NUMBER + -- Parsed number + local + sb: STRING + flag: BOOLEAN + is_integer: BOOLEAN + c: like actual + do + create sb.make_empty + sb.append_character (actual) + + from + flag := True + until + not flag + loop + next + c := actual + if not has_next or is_close_token (c) + or c = ',' or c = '%N' or c = '%R' + then + flag := False + previous + else + sb.append_character (c) + end + end + + if is_valid_number (sb) then + if sb.is_integer then + create Result.make_integer (sb.to_integer) + is_integer := True + elseif sb.is_double and not is_integer then + create Result.make_real (sb.to_double) + end + else + is_parsed := False + report_error ("Expected a number, found: [ " + sb + " ]") + end + end + + is_null: BOOLEAN + -- Word at index represents null? + local + l_null: STRING + l_string: STRING + do + l_null := null_id + l_string := json_substring (index,index + l_null.count - 1) + if l_string.is_equal (l_null) then + Result := True + end + end + + is_false: BOOLEAN + -- Word at index represents false? + local + l_false: STRING + l_string: STRING + do + l_false := false_id + l_string := json_substring (index, index + l_false.count - 1) + if l_string.is_equal (l_false) then + Result := True + end + end + + is_true: BOOLEAN + -- Word at index represents true? + local + l_true: STRING + l_string: STRING + do + l_true := true_id + l_string := json_substring (index,index + l_true.count - 1) + if l_string.is_equal (l_true) then + Result := True + end + end + + read_unicode: STRING + -- Read unicode and return value + local + i: INTEGER + do + create Result.make_empty + from + i := 1 + until + i > 4 or not has_next + loop + next + Result.append_character (actual) + i := i + 1 + end + end + +feature {NONE} -- Implementation + + is_valid_number (a_number: STRING): BOOLEAN + -- is 'a_number' a valid number based on this regular expression + -- "-?(?: 0|[1-9]\d+)(?: \.\d+)?(?: [eE][+-]?\d+)?\b"? + local + s: detachable STRING + c: CHARACTER + i,n: INTEGER + do + create s.make_empty + n := a_number.count + if n = 0 then + Result := False + else + Result := True + i := 1 + --| "-?" + c := a_number[i] + if c = '-' then + s.extend (c); i := i + 1; c := a_number[i] + end + --| "0|[1-9]\d* + if c.is_digit then + if c = '0' then + --| "0" + s.extend (c); i := i + 1; c := a_number[i] + else + --| "[1-9]" + s.extend (c); i := i + 1; c := a_number[i] + --| "\d*" + from until i > n or not c.is_digit loop + s.extend (c); i := i + 1; c := a_number[i] + end + end + end + end + if Result then + --| "(\.\d+)?" + if c = '.' then + --| "\.\d+" = "\.\d\d*" + s.extend (c); i := i + 1; c := a_number[i] + if c.is_digit then + from until i > n or not c.is_digit loop + s.extend (c); i := i + 1; c := a_number[i] + end + else + Result := False --| expecting digit + end + end + end + if Result then --| "(?:[eE][+-]?\d+)?\b" + if c = 'e' or c = 'E' then + --| "[eE][+-]?\d+" + s.extend (c); i := i + 1; c := a_number[i] + if c = '+' or c = '-' then + s.extend (c); i := i + 1; c := a_number[i] + end + if c.is_digit then + from until i > n or not c.is_digit loop + s.extend (c); i := i + 1; c := a_number[i] + end + else + Result := False --| expecting digit + end + end + end + if Result then --| "\b" + from until i > n or not c.is_space loop + s.extend (c); i := i + 1; c := a_number[i] + end + Result := i > n and then s.same_string (a_number) + end + end + + is_valid_unicode (a_unicode: STRING): BOOLEAN + -- is 'a_unicode' a valid unicode based on this regular expression + -- "\\u[0-9a-fA-F]{4}" + local + i: INTEGER + do + if + a_unicode.count = 6 and then + a_unicode[1] = '\' and then + a_unicode[2] = 'u' + then + from + Result := True + i := 3 + until + i > 6 or Result = False + loop + inspect a_unicode[i] + when '0'..'9', 'a'..'f', 'A'..'F' then + else + Result := False + end + i := i + 1 + end + end + end + + extra_elements: BOOLEAN + -- has more elements? + local + c: like actual + do + if has_next then + next + end + from + c := actual + until + c /= ' ' or c /= '%R' or c /= '%U' or c /= '%T' or c /= '%N' or not has_next + loop + next + end + Result := has_next + end + + is_valid_start_symbol : BOOLEAN + -- expecting `{' or `[' as start symbol + do + if attached representation as s and then s.count > 0 then + Result := s[1] = '{' or s[1] = '[' + end + end + +feature {NONE} -- Constants + + false_id: STRING = "false" + + true_id: STRING = "true" + + null_id: STRING = "null" + + +end diff --git a/contrib/library/text/parser/json/library/kernel/scanner/json_reader.e b/contrib/library/text/parser/json/library/kernel/scanner/json_reader.e new file mode 100644 index 00000000..112857bd --- /dev/null +++ b/contrib/library/text/parser/json/library/kernel/scanner/json_reader.e @@ -0,0 +1,118 @@ +note + description: "Objects that ..." + author: "jvelilla" + date: "2008/08/24" + revision: "0.1" + +class + JSON_READER + +create + make + +feature {NONE} -- Initialization + + make (a_json: STRING) + -- Initialize Reader + do + set_representation (a_json) + end + +feature -- Commands + + set_representation (a_json: STRING) + -- Set `representation'. + do + a_json.left_adjust + a_json.right_adjust + representation := a_json + index := 1 + end + + read: CHARACTER + -- Read character + do + if not representation.is_empty then + Result := representation.item (index) + end + end + + next + -- Move to next index + require + has_more_elements: has_next + do + index := index + 1 + ensure + incremented: old index + 1 = index + end + + previous + -- Move to previous index + require + not_is_first: has_previous + do + index := index - 1 + ensure + incremented: old index - 1 = index + end + + skip_white_spaces + -- Remove white spaces + local + c: like actual + do + from + c := actual + until + (c /= ' ' and c /= '%N' and c /= '%R' and c /= '%U' and c /= '%T' ) or not has_next + loop + next + c := actual + end + end + + json_substring (start_index, end_index: INTEGER_32): STRING + -- JSON representation between `start_index' and `end_index' + do + Result := representation.substring (start_index, end_index) + end + +feature -- Status report + + has_next: BOOLEAN + -- Has a next character? + do + Result := index <= representation.count + end + + has_previous: BOOLEAN + -- Has a previous character? + do + Result := index >= 1 + end + +feature -- Access + + representation: STRING + -- Serialized representation of the original JSON string + +feature {NONE} -- Implementation + + actual: CHARACTER + -- Current character or '%U' if none + do + if index > representation.count then + Result := '%U' + else + Result := representation.item (index) + end + end + + index: INTEGER + -- Actual index + +invariant + representation_not_void: representation /= Void + +end diff --git a/contrib/library/text/parser/json/library/kernel/scanner/json_tokens.e b/contrib/library/text/parser/json/library/kernel/scanner/json_tokens.e new file mode 100644 index 00000000..db8dd9df --- /dev/null +++ b/contrib/library/text/parser/json/library/kernel/scanner/json_tokens.e @@ -0,0 +1,77 @@ +note + description: "" + author: "jvelilla" + date: "2008/08/24" + revision: "0.1" + +class + JSON_TOKENS + +feature -- Access + + j_OBJECT_OPEN: CHARACTER = '{' + j_ARRAY_OPEN: CHARACTER = '[' + j_OBJECT_CLOSE: CHARACTER = '}' + j_ARRAY_CLOSE: CHARACTER = ']' + + j_STRING: CHARACTER = '"' + j_PLUS: CHARACTER = '+' + j_MINUS: CHARACTER = '-' + j_DOT: CHARACTER = '.' + +feature -- Status report + + is_open_token (c: CHARACTER): BOOLEAN + -- Characters which open a type + do + inspect c + when j_OBJECT_OPEN, j_ARRAY_OPEN, j_STRING, j_PLUS, j_MINUS, j_DOT then + Result := True + else + + end + end + + is_close_token (c: CHARACTER): BOOLEAN + -- Characters which close a type + do + inspect c + when j_OBJECT_CLOSE, j_ARRAY_CLOSE, j_STRING then + Result := True + else + + end + end + + is_special_character (c: CHARACTER): BOOLEAN + -- Control Characters + -- %F Form feed + -- %H backslasH + -- %N Newline + -- %R carriage Return + -- %T horizontal Tab + -- %B Backspace + -- / Solidus + -- " Quotation + do + inspect c + when '%F', '%H', '%N', '%R', '%T', '%B', '/', '"' then + Result := True + else + + end + end + + is_special_control (c: CHARACTER): BOOLEAN + --Control Characters + -- \b\f\n\r\t + do + inspect c + when 'b', 'f', 'n', 'r', 't' then + Result := True + else + + end + end + +end diff --git a/contrib/library/text/parser/json/library/kernel/shared_ejson.e b/contrib/library/text/parser/json/library/kernel/shared_ejson.e new file mode 100644 index 00000000..d08a6766 --- /dev/null +++ b/contrib/library/text/parser/json/library/kernel/shared_ejson.e @@ -0,0 +1,32 @@ +note + description: "[ + Shared factory class for creating JSON objects. Maps JSON + objects to ELKS HASH_TABLEs and JSON arrays to ELKS + LINKED_LISTs. Use non-conforming inheritance from this + class to ensure that your classes share the same + JSON_FACTORY instance. + ]" + author: "Paul Cohen" + date: "$Date: $" + revision: "$Revision: $" + file: "$HeadURL: $" + +class SHARED_EJSON + +feature + + json: EJSON + -- A shared EJSON instance with default converters for + -- DS_LINKED_LIST [ANY] and DS_HASH_TABLE [ANY, HASHABLE] + local + jllc: JSON_LINKED_LIST_CONVERTER + jhtc: JSON_HASH_TABLE_CONVERTER + once + create Result + create jllc.make + Result.add_converter (jllc) + create jhtc.make + Result.add_converter (jhtc) + end + +end -- class SHARED_EJSON \ No newline at end of file diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/application.e b/contrib/library/text/parser/json/test/autotest/test_suite/application.e new file mode 100644 index 00000000..77d42fe7 --- /dev/null +++ b/contrib/library/text/parser/json/test/autotest/test_suite/application.e @@ -0,0 +1,24 @@ +note + description : "test_suite application root class" + date : "$Date$" + revision : "$Revision$" + +class + APPLICATION + +inherit + ARGUMENTS + +create + make + +feature {NONE} -- Initialization + + make + -- Run application. + do + --| Add your code here + print ("Hello Eiffel World!%N") + end + +end diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/author.e b/contrib/library/text/parser/json/test/autotest/test_suite/author.e new file mode 100644 index 00000000..9df55bf7 --- /dev/null +++ b/contrib/library/text/parser/json/test/autotest/test_suite/author.e @@ -0,0 +1,24 @@ +class AUTHOR + +create + make + +feature {NONE} -- Initialization + + make (a_name: STRING_32) + do + set_name (a_name) + end + +feature -- Access + + name: STRING_32 + +feature -- Status setting + + set_name (a_name: STRING_32) + do + name := a_name + end + +end -- class AUTHOR diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/book.e b/contrib/library/text/parser/json/test/autotest/test_suite/book.e new file mode 100644 index 00000000..414036db --- /dev/null +++ b/contrib/library/text/parser/json/test/autotest/test_suite/book.e @@ -0,0 +1,40 @@ +class BOOK + +create + make + +feature {NONE} -- Initialization + + make (a_title: STRING_32; an_author: AUTHOR; an_isbn: STRING_32) + do + set_title (a_title) + set_author (an_author) + set_isbn (an_isbn) + end + +feature -- Access + + title: STRING_32 + + isbn: STRING_32 + + author: AUTHOR + +feature -- Status setting + + set_title (a_title: STRING_32) + do + title := a_title + end + + set_author (an_author: AUTHOR) + do + author := an_author + end + + set_isbn (an_isbn: STRING_32) + do + isbn := an_isbn + end + +end -- class BOOK diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/book_collection.e b/contrib/library/text/parser/json/test/autotest/test_suite/book_collection.e new file mode 100644 index 00000000..5ee0b0dd --- /dev/null +++ b/contrib/library/text/parser/json/test/autotest/test_suite/book_collection.e @@ -0,0 +1,80 @@ +class BOOK_COLLECTION + +create + make + +feature {NONE} -- Initialization + + make (a_name: STRING_32) + do + set_name (a_name) + create book_index.make (10) + end + +feature -- Access + + name: STRING_32 + + books: LIST [BOOK] + do + from + create {LINKED_LIST [BOOK]} Result.make + book_index.start + until + book_index.after + loop + Result.append (book_index.item_for_iteration) + book_index.forth + end + end + + books_by_author (an_author: STRING_32): detachable LIST [BOOK] + do + if book_index.has (an_author) then + Result := book_index @ an_author + else + create {LINKED_LIST [BOOK]} Result.make + end + end + +feature -- Status setting + + set_name (a_name: STRING_32) + do + name := a_name + end + + add_book (a_book: BOOK) + local + l: detachable LIST [BOOK] + do + if book_index.has (a_book.author.name) then + l := book_index.at ( a_book.author.name ) + else + create {LINKED_LIST [BOOK]} l.make + book_index.put (l, a_book.author.name) + end + if attached l as la then + la.force (a_book) + end + + end + + add_books (book_list: like books) + + do + from + book_list.start + until + book_list.after + loop + add_book (book_list.item) + book_list.forth + end + end + +feature {NONE} -- Implementation + + book_index: HASH_TABLE [LIST [BOOK], STRING_32] + +end -- class BOOK_COLLECTION diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/fail1.json b/contrib/library/text/parser/json/test/autotest/test_suite/fail1.json new file mode 100644 index 00000000..6216b865 --- /dev/null +++ b/contrib/library/text/parser/json/test/autotest/test_suite/fail1.json @@ -0,0 +1 @@ +"A JSON payload should be an object or array, not a string." \ No newline at end of file diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/fail10.json b/contrib/library/text/parser/json/test/autotest/test_suite/fail10.json new file mode 100644 index 00000000..5d8c0047 --- /dev/null +++ b/contrib/library/text/parser/json/test/autotest/test_suite/fail10.json @@ -0,0 +1 @@ +{"Extra value after close": true} "misplaced quoted value" \ No newline at end of file diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/fail11.json b/contrib/library/text/parser/json/test/autotest/test_suite/fail11.json new file mode 100644 index 00000000..76eb95b4 --- /dev/null +++ b/contrib/library/text/parser/json/test/autotest/test_suite/fail11.json @@ -0,0 +1 @@ +{"Illegal expression": 1 + 2} \ No newline at end of file diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/fail12.json b/contrib/library/text/parser/json/test/autotest/test_suite/fail12.json new file mode 100644 index 00000000..77580a45 --- /dev/null +++ b/contrib/library/text/parser/json/test/autotest/test_suite/fail12.json @@ -0,0 +1 @@ +{"Illegal invocation": alert()} \ No newline at end of file diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/fail13.json b/contrib/library/text/parser/json/test/autotest/test_suite/fail13.json new file mode 100644 index 00000000..379406b5 --- /dev/null +++ b/contrib/library/text/parser/json/test/autotest/test_suite/fail13.json @@ -0,0 +1 @@ +{"Numbers cannot have leading zeroes": 013} \ No newline at end of file diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/fail14.json b/contrib/library/text/parser/json/test/autotest/test_suite/fail14.json new file mode 100644 index 00000000..0ed366b3 --- /dev/null +++ b/contrib/library/text/parser/json/test/autotest/test_suite/fail14.json @@ -0,0 +1 @@ +{"Numbers cannot be hex": 0x14} \ No newline at end of file diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/fail15.json b/contrib/library/text/parser/json/test/autotest/test_suite/fail15.json new file mode 100644 index 00000000..fc8376b6 --- /dev/null +++ b/contrib/library/text/parser/json/test/autotest/test_suite/fail15.json @@ -0,0 +1 @@ +["Illegal backslash escape: \x15"] \ No newline at end of file diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/fail16.json b/contrib/library/text/parser/json/test/autotest/test_suite/fail16.json new file mode 100644 index 00000000..3fe21d4b --- /dev/null +++ b/contrib/library/text/parser/json/test/autotest/test_suite/fail16.json @@ -0,0 +1 @@ +[\naked] \ No newline at end of file diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/fail17.json b/contrib/library/text/parser/json/test/autotest/test_suite/fail17.json new file mode 100644 index 00000000..62b9214a --- /dev/null +++ b/contrib/library/text/parser/json/test/autotest/test_suite/fail17.json @@ -0,0 +1 @@ +["Illegal backslash escape: \017"] \ No newline at end of file diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/fail18.json b/contrib/library/text/parser/json/test/autotest/test_suite/fail18.json new file mode 100644 index 00000000..edac9271 --- /dev/null +++ b/contrib/library/text/parser/json/test/autotest/test_suite/fail18.json @@ -0,0 +1 @@ +[[[[[[[[[[[[[[[[[[[["Too deep"]]]]]]]]]]]]]]]]]]]] \ No newline at end of file diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/fail19.json b/contrib/library/text/parser/json/test/autotest/test_suite/fail19.json new file mode 100644 index 00000000..3b9c46fa --- /dev/null +++ b/contrib/library/text/parser/json/test/autotest/test_suite/fail19.json @@ -0,0 +1 @@ +{"Missing colon" null} \ No newline at end of file diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/fail2.json b/contrib/library/text/parser/json/test/autotest/test_suite/fail2.json new file mode 100644 index 00000000..6b7c11e5 --- /dev/null +++ b/contrib/library/text/parser/json/test/autotest/test_suite/fail2.json @@ -0,0 +1 @@ +["Unclosed array" \ No newline at end of file diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/fail20.json b/contrib/library/text/parser/json/test/autotest/test_suite/fail20.json new file mode 100644 index 00000000..27c1af3e --- /dev/null +++ b/contrib/library/text/parser/json/test/autotest/test_suite/fail20.json @@ -0,0 +1 @@ +{"Double colon":: null} \ No newline at end of file diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/fail21.json b/contrib/library/text/parser/json/test/autotest/test_suite/fail21.json new file mode 100644 index 00000000..62474573 --- /dev/null +++ b/contrib/library/text/parser/json/test/autotest/test_suite/fail21.json @@ -0,0 +1 @@ +{"Comma instead of colon", null} \ No newline at end of file diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/fail22.json b/contrib/library/text/parser/json/test/autotest/test_suite/fail22.json new file mode 100644 index 00000000..a7752581 --- /dev/null +++ b/contrib/library/text/parser/json/test/autotest/test_suite/fail22.json @@ -0,0 +1 @@ +["Colon instead of comma": false] \ No newline at end of file diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/fail23.json b/contrib/library/text/parser/json/test/autotest/test_suite/fail23.json new file mode 100644 index 00000000..494add1c --- /dev/null +++ b/contrib/library/text/parser/json/test/autotest/test_suite/fail23.json @@ -0,0 +1 @@ +["Bad value", truth] \ No newline at end of file diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/fail24.json b/contrib/library/text/parser/json/test/autotest/test_suite/fail24.json new file mode 100644 index 00000000..caff239b --- /dev/null +++ b/contrib/library/text/parser/json/test/autotest/test_suite/fail24.json @@ -0,0 +1 @@ +['single quote'] \ No newline at end of file diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/fail25.json b/contrib/library/text/parser/json/test/autotest/test_suite/fail25.json new file mode 100644 index 00000000..8b7ad23e --- /dev/null +++ b/contrib/library/text/parser/json/test/autotest/test_suite/fail25.json @@ -0,0 +1 @@ +[" tab character in string "] \ No newline at end of file diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/fail26.json b/contrib/library/text/parser/json/test/autotest/test_suite/fail26.json new file mode 100644 index 00000000..845d26a6 --- /dev/null +++ b/contrib/library/text/parser/json/test/autotest/test_suite/fail26.json @@ -0,0 +1 @@ +["tab\ character\ in\ string\ "] \ No newline at end of file diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/fail27.json b/contrib/library/text/parser/json/test/autotest/test_suite/fail27.json new file mode 100644 index 00000000..6b01a2ca --- /dev/null +++ b/contrib/library/text/parser/json/test/autotest/test_suite/fail27.json @@ -0,0 +1,2 @@ +["line +break"] \ No newline at end of file diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/fail28.json b/contrib/library/text/parser/json/test/autotest/test_suite/fail28.json new file mode 100644 index 00000000..621a0101 --- /dev/null +++ b/contrib/library/text/parser/json/test/autotest/test_suite/fail28.json @@ -0,0 +1,2 @@ +["line\ +break"] \ No newline at end of file diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/fail29.json b/contrib/library/text/parser/json/test/autotest/test_suite/fail29.json new file mode 100644 index 00000000..47ec421b --- /dev/null +++ b/contrib/library/text/parser/json/test/autotest/test_suite/fail29.json @@ -0,0 +1 @@ +[0e] \ No newline at end of file diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/fail3.json b/contrib/library/text/parser/json/test/autotest/test_suite/fail3.json new file mode 100644 index 00000000..168c81eb --- /dev/null +++ b/contrib/library/text/parser/json/test/autotest/test_suite/fail3.json @@ -0,0 +1 @@ +{unquoted_key: "keys must be quoted"} \ No newline at end of file diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/fail30.json b/contrib/library/text/parser/json/test/autotest/test_suite/fail30.json new file mode 100644 index 00000000..8ab0bc4b --- /dev/null +++ b/contrib/library/text/parser/json/test/autotest/test_suite/fail30.json @@ -0,0 +1 @@ +[0e+] \ No newline at end of file diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/fail31.json b/contrib/library/text/parser/json/test/autotest/test_suite/fail31.json new file mode 100644 index 00000000..1cce602b --- /dev/null +++ b/contrib/library/text/parser/json/test/autotest/test_suite/fail31.json @@ -0,0 +1 @@ +[0e+-1] \ No newline at end of file diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/fail32.json b/contrib/library/text/parser/json/test/autotest/test_suite/fail32.json new file mode 100644 index 00000000..45cba739 --- /dev/null +++ b/contrib/library/text/parser/json/test/autotest/test_suite/fail32.json @@ -0,0 +1 @@ +{"Comma instead if closing brace": true, \ No newline at end of file diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/fail33.json b/contrib/library/text/parser/json/test/autotest/test_suite/fail33.json new file mode 100644 index 00000000..ca5eb19d --- /dev/null +++ b/contrib/library/text/parser/json/test/autotest/test_suite/fail33.json @@ -0,0 +1 @@ +["mismatch"} \ No newline at end of file diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/fail4.json b/contrib/library/text/parser/json/test/autotest/test_suite/fail4.json new file mode 100644 index 00000000..9de168bf --- /dev/null +++ b/contrib/library/text/parser/json/test/autotest/test_suite/fail4.json @@ -0,0 +1 @@ +["extra comma",] \ No newline at end of file diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/fail5.json b/contrib/library/text/parser/json/test/autotest/test_suite/fail5.json new file mode 100644 index 00000000..ddf3ce3d --- /dev/null +++ b/contrib/library/text/parser/json/test/autotest/test_suite/fail5.json @@ -0,0 +1 @@ +["double extra comma",,] \ No newline at end of file diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/fail6.json b/contrib/library/text/parser/json/test/autotest/test_suite/fail6.json new file mode 100644 index 00000000..ed91580e --- /dev/null +++ b/contrib/library/text/parser/json/test/autotest/test_suite/fail6.json @@ -0,0 +1 @@ +[ , "<-- missing value"] \ No newline at end of file diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/fail7.json b/contrib/library/text/parser/json/test/autotest/test_suite/fail7.json new file mode 100644 index 00000000..8a96af3e --- /dev/null +++ b/contrib/library/text/parser/json/test/autotest/test_suite/fail7.json @@ -0,0 +1 @@ +["Comma after the close"], \ No newline at end of file diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/fail8.json b/contrib/library/text/parser/json/test/autotest/test_suite/fail8.json new file mode 100644 index 00000000..b28479c6 --- /dev/null +++ b/contrib/library/text/parser/json/test/autotest/test_suite/fail8.json @@ -0,0 +1 @@ +["Extra close"]] \ No newline at end of file diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/fail9.json b/contrib/library/text/parser/json/test/autotest/test_suite/fail9.json new file mode 100644 index 00000000..5815574f --- /dev/null +++ b/contrib/library/text/parser/json/test/autotest/test_suite/fail9.json @@ -0,0 +1 @@ +{"Extra comma": true,} \ No newline at end of file diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/json_author_converter.e b/contrib/library/text/parser/json/test/autotest/test_suite/json_author_converter.e new file mode 100644 index 00000000..ec734045 --- /dev/null +++ b/contrib/library/text/parser/json/test/autotest/test_suite/json_author_converter.e @@ -0,0 +1,54 @@ +note + description: "A JSON converter for AUTHOR" + author: "Paul Cohen" + date: "$Date: 2010-03-08 20:46:59 -0300 (Mon, 08 Mar 2010) $" + revision: "$Revision: 82 $" + file: "$HeadURL: https://svn.origo.ethz.ch/ejson/branches/POC-converters-factory/test/json_author_converter.e $" + +class JSON_AUTHOR_CONVERTER + +inherit + JSON_CONVERTER + +create + make + +feature {NONE} -- Initialization + + make + local + ucs: STRING_32 + do + create ucs.make_from_string ("") + create object.make (ucs) + end + +feature -- Access + + object: AUTHOR + +feature -- Conversion + + from_json (j: like to_json): detachable like object + local + ucs: detachable STRING_32 + do + ucs ?= json.object (j.item (name_key), Void) + check ucs /= Void end + create Result.make (ucs) + end + + to_json (o: like object): JSON_OBJECT + 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/contrib/library/text/parser/json/test/autotest/test_suite/json_book_collection_converter.e b/contrib/library/text/parser/json/test/autotest/test_suite/json_book_collection_converter.e new file mode 100644 index 00000000..06b33cd0 --- /dev/null +++ b/contrib/library/text/parser/json/test/autotest/test_suite/json_book_collection_converter.e @@ -0,0 +1,79 @@ +note + description: "A JSON converter for BOOK_COLLECTION" + author: "Paul Cohen" + date: "$Date: 2010-03-08 20:46:59 -0300 (Mon, 08 Mar 2010) $" + revision: "$Revision: 82 $" + file: "$HeadURL: https://svn.origo.ethz.ch/ejson/branches/POC-converters-factory/test/json_book_collection_converter.e $" + +class JSON_BOOK_COLLECTION_CONVERTER + +inherit + JSON_CONVERTER + +create + make + +feature {NONE} -- Initialization + + make + local + ucs: STRING_32 + do + create ucs.make_from_string ("") + create object.make (ucs) + end + +feature -- Access + + object: BOOK_COLLECTION + +feature -- Conversion + + from_json (j: like to_json): detachable like object + local + ucs: detachable STRING_32 + ll: LINKED_LIST [BOOK] + b: detachable BOOK + ja: detachable JSON_ARRAY + i: INTEGER + do + ucs ?= json.object (j.item (name_key), Void) + 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.force (b) + i := i + 1 + end + check ll /= Void end + Result.add_books (ll) + end + + to_json (o: like object): JSON_OBJECT + 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/contrib/library/text/parser/json/test/autotest/test_suite/json_book_converter.e b/contrib/library/text/parser/json/test/autotest/test_suite/json_book_converter.e new file mode 100644 index 00000000..e355149f --- /dev/null +++ b/contrib/library/text/parser/json/test/autotest/test_suite/json_book_converter.e @@ -0,0 +1,73 @@ +note + description: "A JSON converter for BOOK" + author: "Paul Cohen" + date: "$Date: 2010-03-08 20:46:59 -0300 (Mon, 08 Mar 2010) $" + revision: "$Revision: 82 $" + file: "$HeadURL: https://svn.origo.ethz.ch/ejson/branches/POC-converters-factory/test/json_book_converter.e $" + +class JSON_BOOK_CONVERTER + +inherit + JSON_CONVERTER + +create + make + +feature {NONE} -- Initialization + + make + local + ucs: STRING_32 + a: AUTHOR + do + create ucs.make_from_string ("") + create a.make (ucs) + create object.make (ucs, a, ucs) + end + +feature -- Access + + object: BOOK + +feature -- Conversion + + from_json (j: like to_json): detachable like object + local + ucs1, ucs2: detachable STRING_32 + a: detachable AUTHOR + do + ucs1 ?= json.object (j.item (title_key), Void) + check ucs1 /= Void end + ucs2 ?= json.object (j.item (isbn_key), Void) + 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): JSON_OBJECT + 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/contrib/library/text/parser/json/test/autotest/test_suite/json_menu_example.txt b/contrib/library/text/parser/json/test/autotest/test_suite/json_menu_example.txt new file mode 100644 index 00000000..bce42e86 --- /dev/null +++ b/contrib/library/text/parser/json/test/autotest/test_suite/json_menu_example.txt @@ -0,0 +1,11 @@ +{"menu": { + "id": "file", + "value": "File", + "popup": { + "menuitem": [ + {"value": "New", "onclick": "CreateNewDoc()"}, + {"value": "Open", "onclick": "OpenDoc()"}, + {"value": "Close", "onclick": "CloseDoc()"} + ] + } +}} \ No newline at end of file diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/pass1.json b/contrib/library/text/parser/json/test/autotest/test_suite/pass1.json new file mode 100644 index 00000000..70e26854 --- /dev/null +++ b/contrib/library/text/parser/json/test/autotest/test_suite/pass1.json @@ -0,0 +1,58 @@ +[ + "JSON Test Pattern pass1", + {"object with 1 member":["array with 1 element"]}, + {}, + [], + -42, + true, + false, + null, + { + "integer": 1234567890, + "real": -9876.543210, + "e": 0.123456789e-12, + "E": 1.234567890E+34, + "": 23456789012E66, + "zero": 0, + "one": 1, + "space": " ", + "quote": "\"", + "backslash": "\\", + "controls": "\b\f\n\r\t", + "slash": "/ & \/", + "alpha": "abcdefghijklmnopqrstuvwyz", + "ALPHA": "ABCDEFGHIJKLMNOPQRSTUVWYZ", + "digit": "0123456789", + "0123456789": "digit", + "special": "`1~!@#$%^&*()_+-={':[,]}|;.?", + "hex": "\u0123\u4567\u89AB\uCDEF\uabcd\uef4A", + "true": true, + "false": false, + "null": null, + "array":[ ], + "object":{ }, + "address": "50 St. James Street", + "url": "http://www.JSON.org/", + "comment": "// /* */": " ", + " s p a c e d " :[1,2 , 3 + +, + +4 , 5 , 6 ,7 ],"compact":[1,2,3,4,5,6,7], + "jsontext": "{\"object with 1 member\":[\"array with 1 element\"]}", + "quotes": "" \u0022 %22 0x22 034 "", + "\/\\\"\uCAFE\uBABE\uAB98\uFCDE\ubcda\uef4A\b\f\n\r\t`1~!@#$%^&*()_+-=[]{}|;:',./<>?" +: "A key can be any string" + }, + 0.5 ,98.6 +, +99.44 +, + +1066, +1e1, +0.1e1, +1e-1, +1e00,2e+00,2e-00 +,"rosebud"] \ No newline at end of file diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/pass2.json b/contrib/library/text/parser/json/test/autotest/test_suite/pass2.json new file mode 100644 index 00000000..d3c63c7a --- /dev/null +++ b/contrib/library/text/parser/json/test/autotest/test_suite/pass2.json @@ -0,0 +1 @@ +[[[[[[[[[[[[[[[[[[["Not too deep"]]]]]]]]]]]]]]]]]]] \ No newline at end of file diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/pass3.json b/contrib/library/text/parser/json/test/autotest/test_suite/pass3.json new file mode 100644 index 00000000..4528d51f --- /dev/null +++ b/contrib/library/text/parser/json/test/autotest/test_suite/pass3.json @@ -0,0 +1,6 @@ +{ + "JSON Test Pattern pass3": { + "The outermost value": "must be an object or array.", + "In this test": "It is an object." + } +} diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/test_ds.e b/contrib/library/text/parser/json/test/autotest/test_suite/test_ds.e new file mode 100644 index 00000000..1cccd4b1 --- /dev/null +++ b/contrib/library/text/parser/json/test/autotest/test_suite/test_ds.e @@ -0,0 +1,74 @@ +class TEST_DS + +inherit + SHARED_EJSON + rename default_create as shared_default_create end + EQA_TEST_SET + select default_create end + + +feature -- Test + + test_linked_list_converter + local + jc: JSON_LINKED_LIST_CONVERTER + l: LINKED_LIST [STRING] + l2: detachable LINKED_LIST [detachable ANY] + s: STRING + jv: detachable JSON_VALUE + do + create jc.make + json.add_converter (jc) + create l.make + s := "foo" + l.force (s) + s := "bar" + l.force (s) + jv := json.value (l) + assert ("jv /= Void", jv /= Void) + if attached jv as l_jv then + s := jv.representation + l2 ?= json.object (jv, "LINKED_LIST") + assert ("l2 /= Void", l2 /= Void) + end + end + + test_hash_table_converter + local + tc: JSON_HASH_TABLE_CONVERTER + t: HASH_TABLE [STRING, STRING] + t2: detachable HASH_TABLE [ANY, HASHABLE] + s: STRING + ucs_key, ucs_value: detachable STRING_32 + jv: detachable JSON_VALUE + do + create tc.make + json.add_converter (tc) + create t.make (2) + t.put ("foo", "1") + t.put ("bar", "2") + jv := json.value (t) + assert ("jv /= Void", jv /= Void) + if attached jv as l_jv then + s := l_jv.representation + t2 ?= json.object (l_jv, "HASH_TABLE") + assert ("t2 /= Void", t2 /= Void) + end + create ucs_key.make_from_string ("1") + if attached t2 as l_t2 then + ucs_value ?= t2 @ ucs_key + assert ("ucs_value /= Void", ucs_value /= Void) + if attached ucs_value as l_ucs_value then + assert ("ucs_value.string.is_equal (%"foo%")", l_ucs_value.string.is_equal ("foo")) + end + create ucs_key.make_from_string ("2") + ucs_value ?= t2 @ ucs_key + assert ("ucs_value /= Void", ucs_value /= Void) + if attached ucs_value as l_ucs_value then + assert ("ucs_value.string.is_equal (%"bar%")", l_ucs_value.string.is_equal ("bar")) + end + + end + end + +end -- class TEST_DS diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/test_json_core.e b/contrib/library/text/parser/json/test/autotest/test_suite/test_json_core.e new file mode 100644 index 00000000..d2faa7e1 --- /dev/null +++ b/contrib/library/text/parser/json/test/autotest/test_suite/test_json_core.e @@ -0,0 +1,822 @@ +class TEST_JSON_CORE + +inherit + SHARED_EJSON + rename default_create as shared_default_create end + EQA_TEST_SET + select default_create 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 {STRING_32} json.object (js, Void) 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 {STRING_32} json.object (js, Void) 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 STRING_32 + 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, Void) + if attached ucs as l_ucs then + assert ("ucs.string.is_equal (%"foobar%")", l_ucs.string.is_equal ("foobar")) + end + end + + test_json_string_and_special_characters + local + js: detachable JSON_STRING + s: detachable STRING_8 + ucs: detachable STRING_32 + jrep: STRING + parser: JSON_PARSER + do + create s.make_from_string ("foo\bar") + create js.make_json (s) + + assert ("js.representation.same_string (%"%"foo\\bar%"%")", js.representation.same_string ("%"foo\\bar%"")) + + -- Eiffel value -> JSON value -> JSON representation with factory + js ?= json.value (s) + assert ("js /= Void", js /= Void) + if js /= Void then + assert ("js.representation.is_equal (%"%"foobar%"%")", js.representation.same_string ("%"foo\\bar%"")) + end + + -- JSON representation -> JSON value -> Eiffel value + jrep := "%"foo\\bar%"" + create parser.make_parser (jrep) + js ?= parser.parse + assert ("js /= Void", js /= Void) + ucs ?= json.object (js, Void) + if ucs /= Void then + assert ("ucs.same_string (%"foo\bar%")", ucs.same_string ("foo\bar")) + end + + jrep := "%"foo\\bar%"" + create parser.make_parser (jrep) + if attached {JSON_STRING} parser.parse as jstring then + assert ("unescaped string %"foo\\bar%" to %"foo\bar%"", jstring.unescaped_string_8.same_string ("foo\bar")) + end + + create js.make_json_from_string_32 ({STRING_32}"%/20320/%/22909/") + assert ("escaping unicode string32 %"%%/20320/%%/22909/%" %"\u4F60\u597D%"", js.item.same_string ("\u4F60\u597D")) + + jrep := "%"\u4F60\u597D%"" --| Ni hao + create parser.make_parser (jrep) + if attached {JSON_STRING} parser.parse as jstring then + assert ("same unicode string32 %"%%/20320/%%/22909/%"", jstring.unescaped_string_32.same_string ({STRING_32}"%/20320/%/22909/")) + 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 HASH_TABLE [detachable ANY, STRING_GENERAL] + i: INTEGER + ucs_key, ucs: STRING_32 + 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 HASH_TABLE, so we do it manually. + -- t = {"name": "foobar", "size": 42, "contents", [0, 1, 1, 2, 3, 5]} + 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, Void) + 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: OPERATING_ENVIRONMENT + jv: detachable JSON_VALUE + exception: BOOLEAN + do + if not exception then + create gv + jv := json.value (gv) + else + assert ("exceptions.is_developer_exception", json.is_developer_exception) +-- assert ("exceptions.is_developer_exception_of_name", json.is_developer_exception_of_name ("eJSON exception: Failed to convert Eiffel object to a JSON_VALUE: OPERATING_ENVIRONMENT")) + 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 : detachable OPERATING_ENVIRONMENT + jo: JSON_OBJECT + exception: BOOLEAN + do + if not exception then + create jo.make + gv ?= json.object (jo, "OPERATING_ENVIRONMENT") + else + assert ("exceptions.is_developer_exception", json.is_developer_exception) +-- assert ("exceptions.is_developer_exception_of_name", json.is_developer_exception_of_name ("eJSON exception: Failed to convert JSON_VALUE to an Eiffel object: JSON_OBJECT -> OPERATING_ENVIRONMENT")) + + end + rescue + exception := True + retry + end + +end -- class TEST_JSON_CORE diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/test_json_custom_classes.e b/contrib/library/text/parser/json/test/autotest/test_suite/test_json_custom_classes.e new file mode 100644 index 00000000..fc7957bc --- /dev/null +++ b/contrib/library/text/parser/json/test/autotest/test_suite/test_json_custom_classes.e @@ -0,0 +1,42 @@ +class TEST_JSON_CUSTOM_CLASSES + +inherit + SHARED_EJSON + rename default_create as shared_default_create end + EQA_TEST_SET + select default_create end +feature -- Test + + test_custom_classes + local + bc: detachable BOOK_COLLECTION + jbc: JSON_BOOK_CONVERTER + jbcc: JSON_BOOK_COLLECTION_CONVERTER + jac: JSON_AUTHOR_CONVERTER + jo: detachable JSON_OBJECT + parser: JSON_PARSER + jrep: STRING + do + 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) + if attached jo as l_jo then + assert ("JSON representation is correct", l_jo.representation.same_string ("{%"name%":%"Test collection%",%"books%":[{%"title%":%"eJSON: The Definitive Guide%",%"isbn%":%"123123-413243%",%"author%":{%"name%":%"Foo Bar%"}}]}")) + end + + end + +end -- class TEST_JSON_CUSTOM_CLASS diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/test_json_suite.e b/contrib/library/text/parser/json/test/autotest/test_suite/test_json_suite.e new file mode 100644 index 00000000..812fb391 --- /dev/null +++ b/contrib/library/text/parser/json/test/autotest/test_suite/test_json_suite.e @@ -0,0 +1,514 @@ +note + description: "[ + Eiffel tests that can be executed by testing tool. + ]" + author: "EiffelStudio test wizard" + date: "$Date$" + revision: "$Revision$" + testing: "type/manual" + +class + TEST_JSON_SUITE + +inherit + EQA_TEST_SET + redefine + on_prepare + end + +feature {NONE} -- Events + + on_prepare + -- + do + create file_reader + end + +feature -- Tests Pass + + test_json_pass1 + -- + local + parse_json: like new_json_parser + do + if attached json_file_from ("pass1.json") as json_file then + parse_json := new_json_parser (json_file) + json_value := parse_json.parse_json + assert ("pass1.json",parse_json.is_parsed = True) + end + end + + test_json_pass2 + -- + local + parse_json: like new_json_parser + do + if attached json_file_from ("pass2.json") as json_file then + parse_json := new_json_parser (json_file) + json_value := parse_json.parse_json + assert ("pass2.json",parse_json.is_parsed = True) + end + end + + test_json_pass3 + -- + local + parse_json: like new_json_parser + do + if attached json_file_from ("pass3.json") as json_file then + parse_json := new_json_parser (json_file) + json_value := parse_json.parse_json + assert ("pass3.json",parse_json.is_parsed = True) + end + end + +feature -- Tests Failures + test_json_fail1 + -- + local + parse_json: like new_json_parser + do + if attached json_file_from ("fail1.json") as json_file then + parse_json := new_json_parser (json_file) + json_value := parse_json.parse_json + assert ("fail1.json",parse_json.is_parsed = False) + end + end + + test_json_fail2 + -- + local + parse_json: like new_json_parser + do + if attached json_file_from ("fail2.json") as json_file then + parse_json := new_json_parser (json_file) + json_value := parse_json.parse_json + assert ("fail2.json",parse_json.is_parsed = False) + end + end + + test_json_fail3 + -- + local + parse_json: like new_json_parser + do + if attached json_file_from ("fail3.json") as json_file then + parse_json := new_json_parser (json_file) + json_value := parse_json.parse_json + assert ("fail3.json",parse_json.is_parsed = False) + end + end + + test_json_fail4 + -- + local + parse_json: like new_json_parser + do + if attached json_file_from ("fail4.json") as json_file then + parse_json := new_json_parser (json_file) + json_value := parse_json.parse_json + assert ("fail4.json",parse_json.is_parsed = False) + end + end + + test_json_fail5 + -- + local + parse_json: like new_json_parser + do + if attached json_file_from ("fail5.json") as json_file then + parse_json := new_json_parser (json_file) + json_value := parse_json.parse_json + assert ("fail5.json",parse_json.is_parsed = False) + end + end + + + test_json_fail6 + -- + local + parse_json: like new_json_parser + do + if attached json_file_from ("fail6.json") as json_file then + parse_json := new_json_parser (json_file) + json_value := parse_json.parse_json + assert ("fail6.json",parse_json.is_parsed = False ) + end + end + + test_json_fail7 + -- + local + parse_json: like new_json_parser + do + if attached json_file_from ("fail7.json") as json_file then + parse_json := new_json_parser (json_file) + json_value := parse_json.parse_json + assert ("fail7.json",parse_json.is_parsed = False) + end + end + + test_json_fail8 + -- + local + parse_json: like new_json_parser + do + if attached json_file_from ("fail8.json") as json_file then + parse_json := new_json_parser (json_file) + json_value := parse_json.parse_json + assert ("fail8.json",parse_json.is_parsed = False ) + end + end + + + test_json_fail9 + -- + local + parse_json: like new_json_parser + do + if attached json_file_from ("fail9.json") as json_file then + parse_json := new_json_parser (json_file) + json_value := parse_json.parse_json + assert ("fail9.json",parse_json.is_parsed = False) + end + end + + + test_json_fail10 + -- + local + parse_json: like new_json_parser + do + if attached json_file_from ("fail10.json") as json_file then + parse_json := new_json_parser (json_file) + json_value := parse_json.parse_json + assert ("fail10.json",parse_json.is_parsed = False) + end + end + + test_json_fail11 + -- + local + parse_json: like new_json_parser + do + if attached json_file_from ("fail11.json") as json_file then + parse_json := new_json_parser (json_file) + json_value := parse_json.parse_json + assert ("fail11.json",parse_json.is_parsed = False) + end + end + + test_json_fail12 + -- + local + parse_json: like new_json_parser + do + if attached json_file_from ("fail12.json") as json_file then + parse_json := new_json_parser (json_file) + json_value := parse_json.parse_json + assert ("fail12.json",parse_json.is_parsed = False) + end + end + + test_json_fail13 + -- + local + parse_json: like new_json_parser + do + if attached json_file_from ("fail13.json") as json_file then + parse_json := new_json_parser (json_file) + json_value := parse_json.parse_json + assert ("fail13.json",parse_json.is_parsed = False) + end + end + + test_json_fail14 + -- + local + parse_json: like new_json_parser + do + if attached json_file_from ("fail14.json") as json_file then + parse_json := new_json_parser (json_file) + json_value := parse_json.parse_json + assert ("fail14.json",parse_json.is_parsed = False) + end + end + + test_json_fail15 + -- + local + parse_json: like new_json_parser + do + if attached json_file_from ("fail15.json") as json_file then + parse_json := new_json_parser (json_file) + json_value := parse_json.parse_json + assert ("fail15.json",parse_json.is_parsed = False) + end + end + + test_json_fail16 + -- + local + parse_json: like new_json_parser + do + if attached json_file_from ("fail16.json") as json_file then + parse_json := new_json_parser (json_file) + json_value := parse_json.parse_json + assert ("fail16.json",parse_json.is_parsed = False) + end + end + + test_json_fail17 + -- + local + parse_json: like new_json_parser + do + if attached json_file_from ("fail17.json") as json_file then + parse_json := new_json_parser (json_file) + json_value := parse_json.parse_json + assert ("fail17.json",parse_json.is_parsed = False) + end + end + + test_json_fail18 + -- + local + parse_json: like new_json_parser + do + if attached json_file_from ("fail18.json") as json_file then + parse_json := new_json_parser (json_file) + json_value := parse_json.parse_json + assert ("fail18.json",parse_json.is_parsed = True) + end + end + + test_json_fail19 + -- + local + parse_json: like new_json_parser + do + if attached json_file_from ("fail19.json") as json_file then + parse_json := new_json_parser (json_file) + json_value := parse_json.parse_json + assert ("fail19.json",parse_json.is_parsed = False) + end + end + + test_json_fail20 + -- + local + parse_json: like new_json_parser + do + if attached json_file_from ("fail20.json") as json_file then + parse_json := new_json_parser (json_file) + json_value := parse_json.parse_json + assert ("fail20.json",parse_json.is_parsed = False) + end + end + + test_json_fail21 + -- + local + parse_json: like new_json_parser + do + if attached json_file_from ("fail21.json") as json_file then + parse_json := new_json_parser (json_file) + json_value := parse_json.parse_json + assert ("fail21.json",parse_json.is_parsed = False) + end + end + + + test_json_fail22 + -- + local + parse_json: like new_json_parser + do + if attached json_file_from ("fail22.json") as json_file then + parse_json := new_json_parser (json_file) + json_value := parse_json.parse_json + assert ("fail22.json",parse_json.is_parsed = False) + end + end + + test_json_fail23 + -- + local + parse_json: like new_json_parser + do + if attached json_file_from ("fail23.json") as json_file then + parse_json := new_json_parser (json_file) + json_value := parse_json.parse_json + assert ("fail23.json",parse_json.is_parsed = False) + end + end + + test_json_fail24 + -- + local + parse_json: like new_json_parser + do + if attached json_file_from ("fail24.json") as json_file then + parse_json := new_json_parser (json_file) + json_value := parse_json.parse_json + assert ("fail24.json",parse_json.is_parsed = False) + end + end + + test_json_fail25 + -- + local + parse_json: like new_json_parser + do + if attached json_file_from ("fail25.json") as json_file then + parse_json := new_json_parser (json_file) + json_value := parse_json.parse_json + assert ("fail25.json",parse_json.is_parsed = False) + end + end + + + test_json_fail26 + -- + local + parse_json: like new_json_parser + do + if attached json_file_from ("fail26.json") as json_file then + parse_json := new_json_parser (json_file) + json_value := parse_json.parse_json + assert ("fail26.json",parse_json.is_parsed = False) + end + end + + + test_json_fail27 + -- + local + parse_json: like new_json_parser + do + if attached json_file_from ("fail27.json") as json_file then + parse_json := new_json_parser (json_file) + json_value := parse_json.parse_json + assert ("fail27.json",parse_json.is_parsed = False) + end + end + + + test_json_fail28 + -- + local + parse_json: like new_json_parser + do + if attached json_file_from ("fail28.json") as json_file then + parse_json := new_json_parser (json_file) + json_value := parse_json.parse_json + assert ("fail28.json",parse_json.is_parsed = False) + end + end + + + test_json_fail29 + -- + local + parse_json: like new_json_parser + do + if attached json_file_from ("fail29.json") as json_file then + parse_json := new_json_parser (json_file) + json_value := parse_json.parse_json + assert ("fail29.json",parse_json.is_parsed = False ) + end + end + + + test_json_fail30 + -- + local + parse_json: like new_json_parser + do + if attached json_file_from ("fail30.json") as json_file then + parse_json := new_json_parser (json_file) + json_value := parse_json.parse_json + assert ("fail30.json",parse_json.is_parsed = False) + end + end + + test_json_fail31 + -- + local + parse_json: like new_json_parser + do + if attached json_file_from ("fail31.json") as json_file then + parse_json := new_json_parser (json_file) + json_value := parse_json.parse_json + assert ("fail31.json",parse_json.is_parsed = False) + end + end + + test_json_fail32 + -- + local + parse_json: like new_json_parser + do + if attached json_file_from ("fail32.json") as json_file then + parse_json := new_json_parser (json_file) + json_value := parse_json.parse_json + assert ("fail32.json",parse_json.is_parsed = False) + end + end + + test_json_fail33 + -- + local + parse_json: like new_json_parser + do + if attached json_file_from ("fail33.json") as json_file then + parse_json := new_json_parser (json_file) + json_value := parse_json.parse_json + assert ("fail33.json",parse_json.is_parsed = False) + end + end + +feature -- JSON_FROM_FILE + + file_reader: JSON_FILE_READER + + json_value: detachable JSON_VALUE + + json_file_from (fn: STRING): detachable STRING + do + Result := file_reader.read_json_from (test_dir + fn) + assert ("File contains json data", Result /= Void) + end + + new_json_parser (a_string: STRING): JSON_PARSER + do + create Result.make_parser (a_string) + end + + test_dir: STRING + local + i: INTEGER + do + Result := (create {EXECUTION_ENVIRONMENT}).current_working_directory + Result.append_character ((create {OPERATING_ENVIRONMENT}).directory_separator) + -- The should looks like + -- ..json\test\autotest\test_suite\EIFGENs\test_suite\Testing\execution\TEST_JSON_SUITE.test_json_fail1\..\..\..\..\..\fail1.json + from + i := 5 + until + i = 0 + loop + Result.append_character ('.') + Result.append_character ('.') + Result.append_character ((create {OPERATING_ENVIRONMENT}).directory_separator) + i := i - 1 + end +-- Result := "/home/jvelilla/work/project/Eiffel/ejson_dev/trunk/test/autotest/test_suite/" + end + +invariant + file_reader /= Void + +end + + diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/test_suite-safe.ecf b/contrib/library/text/parser/json/test/autotest/test_suite/test_suite-safe.ecf new file mode 100644 index 00000000..00552058 --- /dev/null +++ b/contrib/library/text/parser/json/test/autotest/test_suite/test_suite-safe.ecf @@ -0,0 +1,18 @@ + + + + + + /EIFGENs$ + /CVS$ + /.svn$ + + + + + + + + diff --git a/contrib/library/text/parser/json/test/autotest/test_suite/test_suite.ecf b/contrib/library/text/parser/json/test/autotest/test_suite/test_suite.ecf new file mode 100644 index 00000000..f24d3ed4 --- /dev/null +++ b/contrib/library/text/parser/json/test/autotest/test_suite/test_suite.ecf @@ -0,0 +1,19 @@ + + + + + + /EIFGENs$ + /CVS$ + /.svn$ + + + + + + + + + diff --git a/contrib/library/text/parser/json/test/getest/author.e b/contrib/library/text/parser/json/test/getest/author.e new file mode 100644 index 00000000..81906d7d --- /dev/null +++ b/contrib/library/text/parser/json/test/getest/author.e @@ -0,0 +1,24 @@ +class AUTHOR + +create + make + +feature {NONE} -- Initialization + + make (a_name: UC_STRING) is + do + set_name (a_name) + end + +feature -- Access + + name: UC_STRING + +feature -- Status setting + + set_name (a_name: UC_STRING) is + do + name := a_name + end + +end -- class AUTHOR \ No newline at end of file diff --git a/contrib/library/text/parser/json/test/getest/book.e b/contrib/library/text/parser/json/test/getest/book.e new file mode 100644 index 00000000..e896c31a --- /dev/null +++ b/contrib/library/text/parser/json/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) is + 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) is + do + title := a_title + end + + set_author (an_author: AUTHOR) is + do + author := an_author + end + + set_isbn (an_isbn: UC_STRING) is + do + isbn := an_isbn + end + +end -- class BOOK \ No newline at end of file diff --git a/contrib/library/text/parser/json/test/getest/book_collection.e b/contrib/library/text/parser/json/test/getest/book_collection.e new file mode 100644 index 00000000..816d6894 --- /dev/null +++ b/contrib/library/text/parser/json/test/getest/book_collection.e @@ -0,0 +1,82 @@ +class BOOK_COLLECTION + +create + make + +feature {NONE} -- Initialization + + make (a_name: UC_STRING) is + do + set_name (a_name) + create book_index.make (10) + end + +feature -- Access + + name: UC_STRING + + books: DS_LIST [BOOK] is + 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] is + 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) is + do + name := a_name + end + + add_book (a_book: BOOK) is + 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) is + 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 \ No newline at end of file diff --git a/contrib/library/text/parser/json/test/getest/ec_compile.bat b/contrib/library/text/parser/json/test/getest/ec_compile.bat new file mode 100644 index 00000000..1d90e40c --- /dev/null +++ b/contrib/library/text/parser/json/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/contrib/library/text/parser/json/test/getest/ec_compile.sh b/contrib/library/text/parser/json/test/getest/ec_compile.sh new file mode 100755 index 00000000..08dcd613 --- /dev/null +++ b/contrib/library/text/parser/json/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/contrib/library/text/parser/json/test/getest/ejson_test-win.cfg b/contrib/library/text/parser/json/test/getest/ejson_test-win.cfg new file mode 100644 index 00000000..9c905c21 --- /dev/null +++ b/contrib/library/text/parser/json/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/contrib/library/text/parser/json/test/getest/ejson_test.cfg b/contrib/library/text/parser/json/test/getest/ejson_test.cfg new file mode 100644 index 00000000..078526ac --- /dev/null +++ b/contrib/library/text/parser/json/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/contrib/library/text/parser/json/test/getest/ejson_test.ecf b/contrib/library/text/parser/json/test/getest/ejson_test.ecf new file mode 100644 index 00000000..d302b746 --- /dev/null +++ b/contrib/library/text/parser/json/test/getest/ejson_test.ecf @@ -0,0 +1,21 @@ + + + + + + //.svn + /cvs$ + /EIFGENs$ + + + + + + + + + + + diff --git a/contrib/library/text/parser/json/test/getest/json_author_converter.e b/contrib/library/text/parser/json/test/getest/json_author_converter.e new file mode 100644 index 00000000..39458cd3 --- /dev/null +++ b/contrib/library/text/parser/json/test/getest/json_author_converter.e @@ -0,0 +1,56 @@ +indexing + description: "A JSON converter for AUTHOR" + author: "Paul Cohen" + date: "$Date$" + revision: "$Revision$" + file: "$HeadURL: https://svn.origo.ethz.ch/ejson/branches/POC-converters-factory/test/json_author_converter.e $" + +class JSON_AUTHOR_CONVERTER + +inherit + JSON_CONVERTER + +create + make + +feature {NONE} -- Initialization + + make is + 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 is + local + ucs: UC_STRING + do + ucs ?= json.object (j.item (name_key), Void) + check ucs /= Void end + create Result.make (ucs) + end + + to_json (o: like object): like value is + do + create Result.make + Result.put (json.value (o.name), name_key) + end + +feature {NONE} -- Implementation + + name_key: JSON_STRING is + once + create Result.make_json ("name") + end + +end -- class JSON_AUTHOR_CONVERTER \ No newline at end of file diff --git a/contrib/library/text/parser/json/test/getest/json_book_collection_converter.e b/contrib/library/text/parser/json/test/getest/json_book_collection_converter.e new file mode 100644 index 00000000..4a56163a --- /dev/null +++ b/contrib/library/text/parser/json/test/getest/json_book_collection_converter.e @@ -0,0 +1,81 @@ +indexing + description: "A JSON converter for BOOK_COLLECTION" + author: "Paul Cohen" + date: "$Date$" + revision: "$Revision$" + file: "$HeadURL: https://svn.origo.ethz.ch/ejson/branches/POC-converters-factory/test/json_book_collection_converter.e $" + +class JSON_BOOK_COLLECTION_CONVERTER + +inherit + JSON_CONVERTER + +create + make + +feature {NONE} -- Initialization + + make is + 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 is + local + ucs: UC_STRING + ll: DS_LINKED_LIST [BOOK] + b: BOOK + ja: JSON_ARRAY + i: INTEGER + do + ucs ?= json.object (j.item (name_key), Void) + 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 is + 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 is + once + create Result.make_json ("name") + end + + books_key: JSON_STRING is + once + create Result.make_json ("books") + end + +end -- class JSON_BOOK_COLLECTION_CONVERTER \ No newline at end of file diff --git a/contrib/library/text/parser/json/test/getest/json_book_converter.e b/contrib/library/text/parser/json/test/getest/json_book_converter.e new file mode 100644 index 00000000..e3e61367 --- /dev/null +++ b/contrib/library/text/parser/json/test/getest/json_book_converter.e @@ -0,0 +1,75 @@ +indexing + description: "A JSON converter for BOOK" + author: "Paul Cohen" + date: "$Date$" + revision: "$Revision$" + file: "$HeadURL: https://svn.origo.ethz.ch/ejson/branches/POC-converters-factory/test/json_book_converter.e $" + +class JSON_BOOK_CONVERTER + +inherit + JSON_CONVERTER + +create + make + +feature {NONE} -- Initialization + + make is + 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 is + local + ucs1, ucs2: UC_STRING + a: AUTHOR + do + ucs1 ?= json.object (j.item (title_key), Void) + check ucs1 /= Void end + ucs2 ?= json.object (j.item (isbn_key), Void) + 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 is + 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 is + once + create Result.make_json ("title") + end + + isbn_key: JSON_STRING is + once + create Result.make_json ("isbn") + end + + author_key: JSON_STRING is + once + create Result.make_json ("author") + end + +end -- class JSON_BOOK_CONVERTER \ No newline at end of file diff --git a/contrib/library/text/parser/json/test/getest/readme.txt b/contrib/library/text/parser/json/test/getest/readme.txt new file mode 100644 index 00000000..56294420 --- /dev/null +++ b/contrib/library/text/parser/json/test/getest/readme.txt @@ -0,0 +1,10 @@ +To compile and run the test program do as follows: + +1. Make sure you have a compiled version of getest in your PATH. + +2. In this dircetory, run the command: + + $ getest --verbose --ise ejson_test.cfg + + +Note: on Windows, you should use ejson_test-win.cfg \ No newline at end of file diff --git a/contrib/library/text/parser/json/test/getest/test_ds.e b/contrib/library/text/parser/json/test/getest/test_ds.e new file mode 100644 index 00000000..88bf0d81 --- /dev/null +++ b/contrib/library/text/parser/json/test/getest/test_ds.e @@ -0,0 +1,71 @@ +class TEST_DS + +inherit + SHARED_GOBO_EJSON + + TS_TEST_CASE + +create + make_default + +feature {NONE} -- Initialization + + make is + -- Create test object. + do + end + +feature -- Test + + test_ds_linked_list_converter is + 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 is + 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) + 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 \ No newline at end of file diff --git a/contrib/library/text/parser/json/test/getest/test_json_core.e b/contrib/library/text/parser/json/test/getest/test_json_core.e new file mode 100644 index 00000000..3396d17e --- /dev/null +++ b/contrib/library/text/parser/json/test/getest/test_json_core.e @@ -0,0 +1,703 @@ +class TEST_JSON_CORE + +inherit + TS_TEST_CASE + SHARED_EJSON + +create + make_default + +feature {NONE} -- Initialization + + make is + -- Create test object. + do + end + +feature -- Test + + test_json_number_and_integer is + local + i: INTEGER + i8: INTEGER_8 + jn: JSON_NUMBER + jrep: STRING + parser: JSON_PARSER + do + i := 42 + -- Eiffel value -> JSON value -> JSON representation + create jn.make_integer (i) + assert ("jn /= Void", jn /= Void) + assert ("jn.representation.is_equal (%"42%")", jn.representation.is_equal ("42")) + -- Eiffel value -> JSON value -> JSON representation with factory + jn := Void + jn ?= json.value (i) + assert ("jn /= Void", jn /= Void) + assert ("jn.representation.is_equal (%"42%")", jn.representation.is_equal ("42")) + -- 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) + jn := Void + jn ?= parser.parse + assert ("jn /= Void", jn /= Void) + i8 := 0 + i8 ?= json.object (jn, Void) + assert ("i8 = 42", i8 = 42) + end + + test_json_number_and_integer_8 is + 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 /= Void", jn /= Void) + assert ("jn.representation.is_equal (%"42%")", jn.representation.is_equal ("42")) + -- Eiffel value -> JSON value -> JSON representation with factory + jn := Void + jn ?= json.value (i8) + assert ("jn /= Void", jn /= Void) + assert ("jn.representation.is_equal (%"42%")", jn.representation.is_equal ("42")) + -- 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) + jn := Void + jn ?= parser.parse + assert ("jn /= Void", jn /= Void) + i8 := 0 + i8 ?= json.object (jn, Void) + assert ("i8 = 42", i8 = 42) + end + + test_json_number_and_integer_16 is + 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 /= Void", jn /= Void) + assert ("jn.representation.is_equal (%"300%")", jn.representation.is_equal ("300")) + -- Eiffel value -> JSON with factory + jn := Void + jn ?= json.value (i16) + assert ("jn /= Void", jn /= Void) + assert ("jn.representation.is_equal (%"300%")", jn.representation.is_equal ("300")) + -- 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) + jn := Void + jn ?= parser.parse + assert ("jn /= Void", jn /= Void) + i16 := 0 + i16 ?= json.object (jn, Void) + assert ("i16 = 300", i16 = 300) + end + + test_json_number_and_integer_32 is + 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 /= Void", jn /= Void) + assert ("jn.representation.is_equal (%"100000%")", jn.representation.is_equal ("100000")) + -- Eiffel value -> JSON representation -> JSON value with factory + jn := Void + jn ?= json.value (i32) + assert ("jn /= Void", jn /= Void) + assert ("jn.representation.is_equal (%"100000%")", jn.representation.is_equal ("100000")) + -- 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) + jn := Void + jn ?= parser.parse + assert ("jn /= Void", jn /= Void) + i32 := 0 + i32 ?= json.object (jn, Void) + assert ("i32 = 100000", i32 = 100000) + end + + test_json_number_and_integer_64 is + 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 /= Void", jn /= Void) + assert ("jn.representation.is_equal (%"42949672960%")", jn.representation.is_equal ("42949672960")) + -- Eiffel value -> JSON value -> JSON representation with factory + jn := Void + jn ?= json.value (i64) + assert ("jn /= Void", jn /= Void) + assert ("jn.representation.is_equal (%"42949672960%")", jn.representation.is_equal ("42949672960")) + -- 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) + jn := Void + jn ?= parser.parse + assert ("jn /= Void", jn /= Void) + i64 := 0 + i64 ?= json.object (jn, Void) + assert ("i64 = 42949672960", i64 = 42949672960) + end + + test_json_number_and_natural_8 is + local + n8: NATURAL_8 + i16: INTEGER_16 + jn: JSON_NUMBER + jrep: STRING + parser: JSON_PARSER + do + n8 := 200 + -- Eiffel value -> JSON value -> JSON representation + create jn.make_natural (n8) + assert ("jn /= Void", jn /= Void) + assert ("jn.representation.is_equal (%"200%")", jn.representation.is_equal ("200")) + -- Eiffel value -> JSON value -> JSON representation with factory + jn := Void + jn ?= json.value (n8) + assert ("jn /= Void", jn /= Void) + assert ("jn.representation.is_equal (%"200%")", jn.representation.is_equal ("200")) + -- 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) + jn := Void + jn ?= parser.parse + assert ("jn /= Void", jn /= Void) + i16 := 0 + i16 ?= json.object (jn, Void) + assert ("i16 = 200", i16 = 200) + end + + test_json_number_and_natural_16 is + local + n16: NATURAL_16 + i32: INTEGER_32 + jn: JSON_NUMBER + jrep: STRING + parser: JSON_PARSER + do + n16 := 32768 + -- Eiffel value -> JSON value -> JSON representation + create jn.make_natural (n16) + assert ("jn /= Void", jn /= Void) + assert ("jn.representation.is_equal (%"32768%")", jn.representation.is_equal ("32768")) + -- Eiffel value -> JSON value -> JSON representation with factory + jn := Void + jn ?= json.value (n16) + assert ("jn /= Void", jn /= Void) + assert ("jn.representation.is_equal (%"32768%")", jn.representation.is_equal ("32768")) + -- 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) + jn := Void + jn ?= parser.parse + assert ("jn /= Void", jn /= Void) + i32 := 0 + i32 ?= json.object (jn, Void) + assert ("i32 = 32768", i32 = 32768) + end + + test_json_number_and_natural_32 is + local + n32: NATURAL_32 + i64: INTEGER_64 + jn: JSON_NUMBER + jrep: STRING + parser: JSON_PARSER + do + n32 := 2147483648 + -- Eiffel value -> JSON value -> JSON representation + create jn.make_natural (n32) + assert ("jn /= Void", jn /= Void) + assert ("jn.representation.is_equal (%"2147483648%")", jn.representation.is_equal ("2147483648")) + -- Eiffel value -> JSON value -> JSON representation with factory + jn := Void + jn ?= json.value (n32) + assert ("jn /= Void", jn /= Void) + assert ("jn.representation.is_equal (%"2147483648%")", jn.representation.is_equal ("2147483648")) + -- 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) + jn := Void + jn ?= parser.parse + assert ("jn /= Void", jn /= Void) + i64 := 0 + i64 ?= json.object (jn, Void) + assert ("i64 = 2147483648", i64 = 2147483648) + end + + test_json_number_and_large_integers is + local + jrep: STRING + jn: JSON_NUMBER + n64: NATURAL_64 + parser: JSON_PARSER + do + n64 := 9223372036854775808 + -- Eiffel value -> JSON value -> JSON representation + create jn.make_natural (n64) + assert ("jn /= Void", jn /= Void) + assert ("jn.representation.is_equal (%"9223372036854775808%")", jn.representation.is_equal ("9223372036854775808")) + jn := Void + -- Eiffel value -> JSON value -> JSON representation with factory + jn ?= json.value (n64) + assert ("jn /= Void", jn /= Void) + assert ("jn.representation.is_equal (%"9223372036854775808%")", jn.representation.is_equal ("9223372036854775808")) + -- 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) + jn := Void + jn ?= parser.parse + assert ("jn /= Void", jn /= Void) + n64 := 0 + n64 ?= json.object (jn, Void) + end + + test_json_number_and_eiffel_real is + local + r: REAL + r64: REAL_64 + 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 /= Void", jn /= Void) + assert ("jn.representation.is_equal (%"3.1400001049041748%")", jn.representation.is_equal ("3.1400001049041748")) + -- Eiffel value -> JSON value -> JSON representation with factory + jn ?= json.value (r) + assert ("jn /= Void", jn /= Void) + assert ("jn.representation.is_equal (%"3.1400001049041748%")", jn.representation.is_equal ("3.1400001049041748")) + -- 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) + jn := Void + jn ?= parser.parse + assert ("jn /= Void", jn /= Void) + r64 := 0 + r64 ?= json.object (jn, Void) + assert ("r64 = 3.1400000000000001", r64 = 3.1400000000000001) + end + + test_json_number_and_eiffel_real_32 is + local + r32: REAL_32 + r64: REAL_64 + 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 /= Void", jn /= Void) + assert ("jn.representation.is_equal (%"3.1400001049041748%")", jn.representation.is_equal ("3.1400001049041748")) + -- Eiffel value -> JSON value -> JSON representation with factory + jn ?= json.value (r32) + assert ("jn /= Void", jn /= Void) + assert ("jn.representation.is_equal (%"3.1400001049041748%")", jn.representation.is_equal ("3.1400001049041748")) + -- JSON representation -> JSON value -> Eiffel value + jrep := "3.1400001049041748" + create parser.make_parser (jrep) + jn ?= parser.parse + assert ("jn /= Void", jn /= Void) + r64 := 0 + r64 ?= json.object (jn, Void) + assert ("r64 = 3.1400001049041748", r64 = 3.1400001049041748) + end + + test_json_number_and_eiffel_real_64 is + 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 /= Void", jn /= Void) + assert ("jn.representation.is_equal (%"3.1415926535897931%")", jn.representation.is_equal ("3.1415926535897931")) + -- Eiffel value -> JSON value -> JSON representation with factory + jn ?= json.value (r64) + assert ("jn /= Void", jn /= Void) + assert ("jn.representation.is_equal (%"3.1415926535897931%")", jn.representation.is_equal ("3.1415926535897931")) + -- JSON representation -> JSON value -> Eiffel value + jrep := "3.1415926535897931" + create parser.make_parser (jrep) + jn := Void + jn ?= parser.parse + assert ("jn /= Void", jn /= Void) + r64 := 0 + r64 ?= json.object (jn, Void) + assert ("r64 = 3.1415926535897931", r64 = 3.1415926535897931) + end + + test_json_boolean is + local + b: BOOLEAN + jb: JSON_BOOLEAN + jrep: STRING + parser: JSON_PARSER + do + b := True + -- Eiffel value -> JSON value -> JSON representation + create jb.make_boolean (b) + assert ("jb /= Void", jb /= Void) + assert ("jb.representation.is_equal (%"true%")", jb.representation.is_equal ("true")) + -- Eiffel value -> JSON value -> JSON representation with factory + jb ?= json.value (b) + assert ("jb /= Void", jb /= Void) + assert ("jb.representation.is_equal (%"true%")", jb.representation.is_equal ("true")) + -- JSON representation -> JSON value -> Eiffel value + jrep := "true" + create parser.make_parser (jrep) + jb := Void + jb ?= parser.parse + assert ("jb /= Void", jb /= Void) + b := False + b ?= json.object (jb, Void) + assert ("b = True", b = True) + + b := False + -- Eiffel value -> JSON value -> JSON representation + create jb.make_boolean (b) + assert ("jb /= Void", jb /= Void) + assert ("jb.representation.is_equal (%"false%")", jb.representation.is_equal ("false")) + -- Eiffel value -> JSON value -> JSON representation with factory + jb ?= json.value (b) + assert ("jb /= Void", jb /= Void) + assert ("jb.representation.is_equal (%"false%")", jb.representation.is_equal ("false")) + -- JSON representation -> JSON value -> Eiffel value + jrep := "false" + create parser.make_parser (jrep) + jb := Void + jb ?= parser.parse + assert ("jb /= Void", jb /= Void) + b := True + b ?= json.object (jb, Void) + assert ("b = False", b = False) + end + + test_json_null is + local + a: ANY + dummy_object: STRING + jn: 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) + assert ("jn.representation.is_equal (%"null%")", jn.representation.is_equal ("null")) + -- 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 is + local + c: CHARACTER + js: JSON_STRING + ucs: UC_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) + assert ("js.representation.is_equal (%"%"a%"%")", js.representation.is_equal ("%"a%"")) + -- JSON representation -> JSON value -> Eiffel value + jrep := "%"a%"" + create parser.make_parser (jrep) + js := Void + js ?= parser.parse + assert ("js /= Void", js /= Void) + ucs ?= json.object (js, Void) + assert ("ucs.string.is_equal (%"a%")", ucs.string.is_equal ("a")) + end + + test_json_string_and_string is + local + s: STRING + js: JSON_STRING + ucs: UC_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) + assert ("js.representation.is_equal (%"%"foobar%"%")", js.representation.is_equal ("%"foobar%"")) + -- JSON representation -> JSON value -> Eiffel value + jrep := "%"foobar%"" + create parser.make_parser (jrep) + js := Void + js ?= parser.parse + assert ("js /= Void", js /= Void) + ucs ?= json.object (js, Void) + assert ("ucs.string.is_equal (%"foobar%")", ucs.string.is_equal ("foobar")) + end + + test_json_string_and_uc_string is + local + js: JSON_STRING + ucs: 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) + assert ("js.representation.is_equal (%"%"foobar%"%")", js.representation.is_equal ("%"foobar%"")) + -- 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, Void) + assert ("ucs.string.is_equal (%"foobar%")", ucs.string.is_equal ("foobar")) + end + + test_json_array is + local + ll: LINKED_LIST [INTEGER_8] + ll2: LINKED_LIST [ANY] + ja: JSON_ARRAY + jn: JSON_NUMBER + jrep: STRING + parser: JSON_PARSER + i, n: INTEGER + 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) + assert ("ja.representation.is_equal (%"[0,1,1,2,3,5]%")", ja.representation.is_equal ("[0,1,1,2,3,5]")) + -- 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 + assert ("ll2.is_equal (ll)", ll2.is_equal (ll)) + end + + test_json_object is + local + t, t2: HASH_TABLE [ANY, UC_STRING] + i: INTEGER + ucs_key, ucs: UC_STRING + a: ARRAY [INTEGER] + jo: 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]} + 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 (%"{%"size%":42,%"contents%":[0,1,1,2,3,5],%"name%":%"foobar%"}%")", jo.representation.is_equal ("{%"size%":42,%"contents%":[0,1,1,2,3,5],%"name%":%"foobar%"}")) + -- 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) + assert ("jo.representation.is_equal (%"{%"size%":42,%"contents%":[0,1,1,2,3,5],%"name%":%"foobar%"}%")", jo.representation.is_equal ("{%"size%":42,%"contents%":[0,1,1,2,3,5],%"name%":%"foobar%"}")) + -- JSON representation -> JSON value -> Eiffel value -> JSON value -> JSON representation + jrep := "{%"size%":42,%"contents%":[0,1,1,2,3,5],%"name%":%"foobar%"}" + create parser.make_parser (jrep) + jo := Void + jo ?= parser.parse + assert ("jo /= Void", jo /= Void) + t2 ?= json.object (jo, Void) + assert ("t2 /= Void", t2 /= Void) + jo ?= json.value (t2) + assert ("jo /= Void", jo /= Void) + assert ("jrep.is_equal (jo.representation)", jrep.is_equal (jo.representation)) + end + + test_json_failed_json_conversion is + -- 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 + 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 + rescue + exception := True + retry + end + + test_json_failed_eiffel_conversion is + -- 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 + 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 + rescue + exception := True + retry + end + +end -- class TEST_JSON_CORE \ No newline at end of file diff --git a/contrib/library/text/parser/json/test/getest/test_json_custom_classes.e b/contrib/library/text/parser/json/test/getest/test_json_custom_classes.e new file mode 100644 index 00000000..e9d99d26 --- /dev/null +++ b/contrib/library/text/parser/json/test/getest/test_json_custom_classes.e @@ -0,0 +1,49 @@ +class TEST_JSON_CUSTOM_CLASSES + +inherit + SHARED_EJSON + + TS_TEST_CASE + +create + make_default + +feature {NONE} -- Initialization + + make is + -- Create test object. + do + end + +feature -- Test + + test_custom_classes is + 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 + 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 ("{%"books%":[{%"title%":%"eJSON: The Definitive Guide%",%"isbn%":%"123123-413243%",%"author%":{%"name%":%"Foo Bar%"}}],%"name%":%"Test collection%"}")) + end + +end -- class TEST_JSON_CUSTOM_CLASS diff --git a/contrib/library/text/parser/json/test/run_autotest.bat b/contrib/library/text/parser/json/test/run_autotest.bat new file mode 100644 index 00000000..c1eb1eaf --- /dev/null +++ b/contrib/library/text/parser/json/test/run_autotest.bat @@ -0,0 +1,27 @@ +@echo off +setlocal +set TMP_EC_SCRIPT_FILENAME=%~dp0.tmp_ec_scripting + +cd %~dp0autotest\test_suite +set TMP_EC_CMD=ec -config test_suite-safe.ecf -target test_suite -batch + +echo # Fresh Compilation +%TMP_EC_CMD% -batch -clean -freeze -c_compile -project_path . > %~dp0autotest.compile.log 2>&1 + +rem Build scripting for freeze + testing +rem ------------------------------------ +rem Testing +echo T > %TMP_EC_SCRIPT_FILENAME% +rem Execute +echo e >> %TMP_EC_SCRIPT_FILENAME% +rem Quit +echo Q >> %TMP_EC_SCRIPT_FILENAME% + +echo # Execute test_suite +type %TMP_EC_SCRIPT_FILENAME% | %TMP_EC_CMD% -loop 1> :NULL 2> %~dp0autotest.testing.log +type %~dp0autotest.testing.log + +cd %~dp0 + +del %TMP_EC_SCRIPT_FILENAME% +endlocal