diff --git a/library/extras/visitor/print_json_visitor.e b/library/extras/visitor/print_json_visitor.e index 6fa64558..6072769b 100644 --- a/library/extras/visitor/print_json_visitor.e +++ b/library/extras/visitor/print_json_visitor.e @@ -1,102 +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 +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/library/gobo/converters/json_ds_hash_table_converter.e b/library/gobo/converters/json_ds_hash_table_converter.e index 9f244fe0..46cf0ff9 100644 --- a/library/gobo/converters/json_ds_hash_table_converter.e +++ b/library/gobo/converters/json_ds_hash_table_converter.e @@ -1,85 +1,85 @@ -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 - if attached {JSON_STRING} json.value (c.key) as l_key then - js := l_key - else - create js.make_json (c.key.out) - end - 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 +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 + if attached {JSON_STRING} json.value (c.key) as l_key then + js := l_key + else + create js.make_json (c.key.out) + end + 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/library/gobo/converters/json_ds_linked_list_converter.e b/library/gobo/converters/json_ds_linked_list_converter.e index bf1aa516..4696051e 100644 --- a/library/gobo/converters/json_ds_linked_list_converter.e +++ b/library/gobo/converters/json_ds_linked_list_converter.e @@ -1,62 +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 +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/library/json.ecf b/library/json.ecf index ee954e09..8d6dc612 100644 --- a/library/json.ecf +++ b/library/json.ecf @@ -1,28 +1,28 @@ - - - - - - /EIFGENs$ - /CVS$ - /.svn$ - - - - - - ^/gobo$ - ^/kernel$ - ^/extras$ - - - - - - + + + + + + /EIFGENs$ + /CVS$ + /.svn$ + + + + + + ^/gobo$ + ^/kernel$ + ^/extras$ + + + + + + diff --git a/library/json.rc b/library/json.rc index d3f5a12f..8b137891 100644 --- a/library/json.rc +++ b/library/json.rc @@ -1 +1 @@ - + diff --git a/library/kernel/ejson.e b/library/kernel/ejson.e index 802d785b..cb5ed967 100644 --- a/library/kernel/ejson.e +++ b/library/kernel/ejson.e @@ -1,268 +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_from_string_32 (s32) - 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.append (" : {" + an_object.generator + "}") - end - end - -feature {NONE} -- Implementation (JSON parser) - - json_parser: JSON_PARSER - once - create Result.make_parser ("") - end - -end -- class EJSON +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_from_string_32 (s32) + 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.append (" : {" + 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/library/kernel/json_array.e b/library/kernel/json_array.e index 60757c84..62480452 100644 --- a/library/kernel/json_array.e +++ b/library/kernel/json_array.e @@ -1,176 +1,176 @@ -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 - - ITERABLE [JSON_VALUE] - -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 -- Access - - new_cursor: ITERATION_CURSOR [JSON_VALUE] - -- Fresh cursor associated with current structure - do - Result := values.new_cursor - 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 - - put_front (v: JSON_VALUE) - require - v_not_void: v /= Void - do - values.put_front (v) - ensure - has_new_value: old values.count + 1 = values.count and - values.first = v - end - - add, extend (v: JSON_VALUE) - require - v_not_void: v /= Void - do - values.extend (v) - ensure - has_new_value: old values.count + 1 = values.count and - values.has (v) - end - - prune_all (v: JSON_VALUE) - -- Remove all occurrences of `v'. - require - v_not_void: v /= Void - do - values.prune_all (v) - ensure - not_has_new_value: not values.has (v) - end - - wipe_out - -- Remove all items. - do - values.wipe_out - 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 - -- be careful, modifying the return object may have impact on the original JSON_ARRAY object - do - Result := values - end - -feature -- Status report - - debug_output: STRING - -- String that should be displayed in debugger to represent `Current'. - do - Result := count.out + " item(s)" - end - -feature {NONE} -- Implementation - - values: ARRAYED_LIST [JSON_VALUE] - -- Value container - -invariant - value_not_void: values /= Void - -end +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 + + ITERABLE [JSON_VALUE] + +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 -- Access + + new_cursor: ITERATION_CURSOR [JSON_VALUE] + -- Fresh cursor associated with current structure + do + Result := values.new_cursor + 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 + + put_front (v: JSON_VALUE) + require + v_not_void: v /= Void + do + values.put_front (v) + ensure + has_new_value: old values.count + 1 = values.count and + values.first = v + end + + add, extend (v: JSON_VALUE) + require + v_not_void: v /= Void + do + values.extend (v) + ensure + has_new_value: old values.count + 1 = values.count and + values.has (v) + end + + prune_all (v: JSON_VALUE) + -- Remove all occurrences of `v'. + require + v_not_void: v /= Void + do + values.prune_all (v) + ensure + not_has_new_value: not values.has (v) + end + + wipe_out + -- Remove all items. + do + values.wipe_out + 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 + -- be careful, modifying the return object may have impact on the original JSON_ARRAY object + do + Result := values + end + +feature -- Status report + + debug_output: STRING + -- String that should be displayed in debugger to represent `Current'. + do + Result := count.out + " item(s)" + end + +feature {NONE} -- Implementation + + values: ARRAYED_LIST [JSON_VALUE] + -- Value container + +invariant + value_not_void: values /= Void + +end diff --git a/library/kernel/json_boolean.e b/library/kernel/json_boolean.e index 32e7634a..cc17681c 100644 --- a/library/kernel/json_boolean.e +++ b/library/kernel/json_boolean.e @@ -1,61 +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 +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/library/kernel/json_null.e b/library/kernel/json_null.e index 176b7d38..9c6f4ed7 100644 --- a/library/kernel/json_null.e +++ b/library/kernel/json_null.e @@ -1,47 +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 +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/library/kernel/json_number.e b/library/kernel/json_number.e index 69b5011e..5f8ea60f 100644 --- a/library/kernel/json_number.e +++ b/library/kernel/json_number.e @@ -1,99 +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 +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/library/kernel/json_string.e b/library/kernel/json_string.e index ccd8e60d..d5401c37 100644 --- a/library/kernel/json_string.e +++ b/library/kernel/json_string.e @@ -1,329 +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 +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/library/kernel/scanner/json_parser.e b/library/kernel/scanner/json_parser.e index 3eaa7388..d90264e5 100644 --- a/library/kernel/scanner/json_parser.e +++ b/library/kernel/scanner/json_parser.e @@ -1,513 +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 +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/library/kernel/scanner/json_reader.e b/library/kernel/scanner/json_reader.e index 112857bd..977e91ae 100644 --- a/library/kernel/scanner/json_reader.e +++ b/library/kernel/scanner/json_reader.e @@ -1,118 +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 +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/library/kernel/scanner/json_tokens.e b/library/kernel/scanner/json_tokens.e index db8dd9df..86f86ba3 100644 --- a/library/kernel/scanner/json_tokens.e +++ b/library/kernel/scanner/json_tokens.e @@ -1,77 +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 +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/test/autotest/test_suite/json_menu_example.txt b/test/autotest/test_suite/json_menu_example.txt index bce42e86..fe6c37de 100644 --- a/test/autotest/test_suite/json_menu_example.txt +++ b/test/autotest/test_suite/json_menu_example.txt @@ -1,11 +1,11 @@ -{"menu": { - "id": "file", - "value": "File", - "popup": { - "menuitem": [ - {"value": "New", "onclick": "CreateNewDoc()"}, - {"value": "Open", "onclick": "OpenDoc()"}, - {"value": "Close", "onclick": "CloseDoc()"} - ] - } +{"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/test/autotest/test_suite/test_json_core.e b/test/autotest/test_suite/test_json_core.e index ec17537a..9c2febac 100644 --- a/test/autotest/test_suite/test_json_core.e +++ b/test/autotest/test_suite/test_json_core.e @@ -1,833 +1,833 @@ -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_object_hash_code - local - ht: HASH_TABLE [ANY, JSON_VALUE] - jo: JSON_OBJECT - do - create ht.make (1) - create jo.make - ht.force ("", jo) - assert ("ht.has_key (jo)", ht.has_key (jo)) - 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 +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_object_hash_code + local + ht: HASH_TABLE [ANY, JSON_VALUE] + jo: JSON_OBJECT + do + create ht.make (1) + create jo.make + ht.force ("", jo) + assert ("ht.has_key (jo)", ht.has_key (jo)) + 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/test/autotest/test_suite/test_json_suite.e b/test/autotest/test_suite/test_json_suite.e index 812fb391..30849c92 100644 --- a/test/autotest/test_suite/test_json_suite.e +++ b/test/autotest/test_suite/test_json_suite.e @@ -1,514 +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 - - +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/test/autotest/test_suite/test_suite-safe.ecf b/test/autotest/test_suite/test_suite-safe.ecf index 00552058..541c8d9e 100644 --- a/test/autotest/test_suite/test_suite-safe.ecf +++ b/test/autotest/test_suite/test_suite-safe.ecf @@ -1,18 +1,18 @@ - - - - - - /EIFGENs$ - /CVS$ - /.svn$ - - - - - - - - + + + + + + /EIFGENs$ + /CVS$ + /.svn$ + + + + + + + +