diff --git a/compiler2/Type.cc b/compiler2/Type.cc index 5cd91e85218837ea0e8524335bd06634e964c2c8..931068249e53f3d2c28c47ca2bb0bbcea7bc15cc 100644 --- a/compiler2/Type.cc +++ b/compiler2/Type.cc @@ -607,6 +607,7 @@ namespace Common { chk_finished = false; pard_type_instance = false; needs_any_from_done = false; + gen_json_coder_functions = false; default_encoding.type = CODING_UNSET; default_decoding.type = CODING_UNSET; } @@ -1759,8 +1760,7 @@ namespace Common { t->u.array.dimension->chk_index(index_value, expected_index); } else { // perform a generic index check for other types - if (refch == 0 // variable assignment - || index_value->get_valuetype() != Value::V_NOTUSED) { + if (index_value->get_valuetype() != Value::V_NOTUSED) { Error_Context cntxt(index_value, "In index value"); index_value->chk_expr_int(expected_index); } @@ -3120,6 +3120,7 @@ namespace Common { case T_SEQ_A: case T_SET_T: case T_SET_A: + case T_ANYTYPE: jsonattrib = new JsonAST; break; default: @@ -5631,20 +5632,14 @@ namespace Common { bool Type::hasEncodeAttr(const char* encoding_name) { - if (0 == strcmp(encoding_name, "JSON") && (implicit_json_encoding - || is_asn1() || (is_ref() && get_type_refd()->is_asn1()))) { + if (0 == strcmp(encoding_name, "JSON") && + (implicit_json_encoding || is_asn1())) { // ASN.1 types automatically support JSON encoding return true; } - // Check the type itself first, then the root type - WithAttribPath *aps[2] = { 0, 0 }; - size_t num_aps = ((aps[0] = get_attrib_path()) != 0); - // assign, compare, then add 0 or 1 - if (is_ref()) { - num_aps += ((aps[num_aps] = get_type_refd()->get_attrib_path()) != 0); - } - for (size_t a = 0; a < num_aps; ++a) { - const vector<SingleWithAttrib>& real = aps[a]->get_real_attrib(); + WithAttribPath* ap = get_attrib_path(); + if (ap != NULL) { + const vector<SingleWithAttrib>& real = ap->get_real_attrib(); const size_t num_atr = real.size(); for (size_t i = 0; i < num_atr; ++i) { const SingleWithAttrib& s = *real[i]; @@ -5655,13 +5650,64 @@ namespace Common { } } // if ENCODE } // for - } // next a + } // if ap + + if ((ownertype == OT_COMP_FIELD || ownertype == OT_RECORD_OF || + ownertype == OT_ARRAY) && parent_type != NULL && + parent_type->get_attrib_path() != NULL && + parent_type->hasEncodeAttrForType(this, encoding_name)) { + // the encode attribute might be in the parent type + return true; + } + return false; + } + + bool Type::hasEncodeAttrForType(Type* target_type, const char* encoding_name) + { + // if this type has an encode attribute, that also extends to its + // fields/elements + if (hasEncodeAttr(encoding_name)) { + return true; + } + // otherwise search this type's qualified attributes + MultiWithAttrib* mwa = get_attrib_path()->get_with_attr(); + if (mwa != NULL) { + for (size_t i = 0; i < mwa->get_nof_elements(); ++i) { + const SingleWithAttrib* swa = mwa->get_element(i); + if (swa->get_attribKeyword() == SingleWithAttrib::AT_ENCODE && + swa->get_attribSpec().get_spec() == encoding_name) { + // search the attribute's qualifiers for one that refers to the + // target type + Ttcn::Qualifiers* quals = swa->get_attribQualifiers(); + for (size_t j = 0; j < quals->get_nof_qualifiers(); ++j) { + Ttcn::Qualifier* qual = const_cast<Ttcn::Qualifier*>( + quals->get_qualifier(j)); + if (get_field_type(qual, EXPECTED_CONSTANT) == target_type) { + return true; + } + } + } + } + } + if ((ownertype == OT_COMP_FIELD || ownertype == OT_RECORD_OF || + ownertype == OT_ARRAY) && parent_type != NULL && + parent_type->get_attrib_path() != NULL) { + return parent_type->hasEncodeAttrForType(target_type, encoding_name); + } return false; } namespace { // unnamed - enum state { PROCESSING = -1, ANSWER_NO, ANSWER_YES }; + enum state { + PROCESSING = -1, // the type is now being checked + ANSWER_NO, // the type (and any types referencing this type) can never have + // the desired encoding type + ANSWER_YES, // the type (and any types referencing this type) has the + // desired encoding type + MISSING_ATTRIBUTE // the type does not have the desired encoding type, but a + // type referencing this type still could, with the right 'encode' attribute + }; struct memoizer : private map<Type*, state> { memoizer() : map<Type*, state>() {} @@ -5732,6 +5778,8 @@ namespace Common { return false; case ANSWER_YES: return true; + case MISSING_ATTRIBUTE: + FATAL_ERROR("Type::has_encoding"); } } @@ -5800,6 +5848,8 @@ namespace Common { case ANSWER_YES: subresult = true; break; + case MISSING_ATTRIBUTE: + FATAL_ERROR("Type::has_encoding"); } } else { @@ -5837,6 +5887,8 @@ namespace Common { case ANSWER_YES: subresult = true; break; + case MISSING_ATTRIBUTE: + FATAL_ERROR("Type::has_encoding"); } } else { @@ -5960,7 +6012,8 @@ namespace Common { } } - case CT_JSON: + case CT_JSON: { + Type* type_w_enc_attr = NULL; while (true) { if (json_mem.has_key(t)) { switch (*json_mem.get(t)) { @@ -5968,13 +6021,23 @@ namespace Common { break; case ANSWER_NO: return false; + case MISSING_ATTRIBUTE: case ANSWER_YES: - return true; + if (type_w_enc_attr != NULL) { + return json_mem.remember(type_w_enc_attr, ANSWER_YES); + } + return *json_mem.get(t) == ANSWER_YES; } } if (t->jsonattrib) { + t->get_type_refd_last()->set_gen_json_coder_functions(); return json_mem.remember(t, ANSWER_YES); } + // an 'encode' attribute is not enough, structured types must still be + // checked; this keeps track of which type had the 'encode' attribute + if (type_w_enc_attr == NULL && t->hasEncodeAttr(get_encoding_name(CT_JSON))) { + type_w_enc_attr = t; + } if (t->is_ref()) { t = t->get_type_refd(); } @@ -6033,6 +6096,7 @@ namespace Common { // Avoids infinite recursion for self-referencing types. continue; case ANSWER_NO: + case MISSING_ATTRIBUTE: // One field is not OK => the structure is not OK return json_mem.remember(t, ANSWER_NO); } @@ -6062,6 +6126,7 @@ namespace Common { // can always be broken with an empty record-of. break; case ANSWER_NO: + case MISSING_ATTRIBUTE: return json_mem.remember(t, ANSWER_NO); break; } @@ -6083,14 +6148,27 @@ namespace Common { default: return json_mem.remember(t, ANSWER_NO); } // switch - return json_mem.remember(t, hasEncodeAttr(get_encoding_name(CT_JSON)) ? ANSWER_YES : ANSWER_NO); + if (type_w_enc_attr != NULL) { + t->set_gen_json_coder_functions(); + return json_mem.remember(type_w_enc_attr, ANSWER_YES); + } + return json_mem.remember(t, MISSING_ATTRIBUTE); } // else } // while - + } // case case CT_CUSTOM: // the encoding name parameter has to be the same as the encoding name // specified for the type - return custom_encoding ? hasEncodeAttr(custom_encoding->c_str()) : false; + if (custom_encoding == NULL) { + return false; + } + if (hasEncodeAttr(custom_encoding->c_str())) { + return true; + } + if (is_ref()) { + return get_type_refd()->has_encoding(encoding_type, custom_encoding); + } + return false; default: FATAL_ERROR("Type::has_encoding()"); @@ -6530,6 +6608,7 @@ namespace Common { * descriptor. */ if (t->is_tagged() || t->rawattrib || t->textattrib || t->jsonattrib || + (!is_asn1() && t->hasEncodeAttr(get_encoding_name(CT_JSON))) || (t->xerattrib && !t->xerattrib->empty() )) { return t->get_genname_own(p_scope); @@ -6651,7 +6730,7 @@ namespace Common { { Type *t = this; while (true) { - if (t->jsonattrib) return t->get_genname_own(my_scope); + if (t->has_encoding(CT_JSON)) return t->get_genname_own(my_scope); else if (t->is_ref()) t = t->get_type_refd(); else break; } diff --git a/compiler2/Type.hh b/compiler2/Type.hh index 746710b639eaf9ae9bfbad008f9f39b2d25e1757..ffb0e605df891076c850f4e93be316c166bea709 100644 --- a/compiler2/Type.hh +++ b/compiler2/Type.hh @@ -440,6 +440,12 @@ namespace Common { * 'any from' clause) of the 'done' function needs to be generated for * this type. */ bool needs_any_from_done; + + /** True if JSON coder functions need to be generated for this type. + * This is not the same as enabling JSON encoding, since other types that + * refer to this type may have JSON encoding, in which case this type needs + * to have JSON coder functions to code them. */ + bool gen_json_coder_functions; /** Copy constructor, for the use of Type::clone() only. */ Type(const Type& p); @@ -1065,8 +1071,16 @@ namespace Common { bool hasNeedofXerAttrs(); bool hasVariantAttrs(); /** Returns whether the type has the encoding attribute specified by - * the parameter (either in its own 'with' statement or in the module's) */ + * the parameter. The function also checks the qualified attributes of + * parent types. Always returns true for ASN.1 types, when checking for a + * JSON encoding attribute. */ bool hasEncodeAttr(const char* encoding_name); + /** Helper function for hasEncodeAttr. Checks this type's qualified encoding + * attributes that refer to the specified type (target_type) and returns + * true if any of them match the specified encoding (encoding_name). + * Recursive function (calls the parent type's hasEncodeAttrForType function + * if no matching attributes are found). */ + bool hasEncodeAttrForType(Type* target_type, const char* encoding_name); /** Returns whether \a this can be encoded according to rules * \a p_encoding. * @note Should be called only during code generation, after the entire @@ -1252,6 +1266,8 @@ namespace Common { inline void set_needs_any_from_done() { needs_any_from_done = true; } + inline void set_gen_json_coder_functions() { gen_json_coder_functions = true; } + /** Calculates the type's display name from the genname (replaces double * underscore characters with single ones) */ string get_dispname() const; diff --git a/compiler2/Type_chk.cc b/compiler2/Type_chk.cc index 8d70834b3671ad9e54cf26eadaf350251a766144..3e8d4c03400d55a68a0b5bd6b250ff85ef7058a6 100644 --- a/compiler2/Type_chk.cc +++ b/compiler2/Type_chk.cc @@ -121,7 +121,7 @@ void Type::chk() textattrib = new TextAST; if(!xerattrib && hasVariantAttrs() && hasNeedofXerAttrs()) xerattrib = new XerAttributes; - if (!jsonattrib && (hasVariantAttrs() || hasEncodeAttr(get_encoding_name(CT_JSON)) || hasNeedofJsonAttrs())) { + if (!jsonattrib && hasVariantAttrs() && hasNeedofJsonAttrs()) { jsonattrib = new JsonAST; } break; @@ -258,7 +258,7 @@ void Type::parse_attributes() } if ((hasVariantAttrs()) - && (enable_text() || enable_raw() || enable_xer())) { + && (enable_text() || enable_raw() || enable_xer() || enable_json())) { #ifndef NDEBUG if (rawAST_debug) { const char *fn = get_fullname().c_str(); diff --git a/compiler2/Type_codegen.cc b/compiler2/Type_codegen.cc index 91bba9d300b02de9fe456497b40327a7d37a8c00..295f0cf2590ec6e0f6164a43f48182fd666df032 100644 --- a/compiler2/Type_codegen.cc +++ b/compiler2/Type_codegen.cc @@ -276,8 +276,8 @@ void Type::generate_code_typedescriptor(output_struct *target) // FIXME: force_xer should be elminated. if a type needs a descriptor, // it should say so via get_genname_typedescriptor() - /* genname{type,ber,raw,text,xer}descriptor == gennameown is true if - * the type needs its own {type,ber,raw,text,xer}descriptor + /* genname{type,ber,raw,text,xer,json}descriptor == gennameown is true if + * the type needs its own {type,ber,raw,text,xer,json}descriptor * and can't use the descriptor of one of the built-in types. */ if (gennametypedescriptor == gennameown @@ -1102,7 +1102,7 @@ void Type::generate_code_Enum(output_struct *target) e_def.hasText = textattrib!=NULL; e_def.hasRaw = rawattrib!=NULL; e_def.hasXer = has_encoding(CT_XER); - e_def.hasJson = has_encoding(CT_JSON); + e_def.hasJson = gen_json_coder_functions; if (xerattrib) { e_def.xerUseNumber = xerattrib->useNumber_; } @@ -1143,7 +1143,7 @@ void Type::generate_code_Choice(output_struct *target) sdef.isASN1 = is_asn1(); sdef.hasText = textattrib!=NULL; sdef.hasXer = has_encoding(CT_XER); - sdef.hasJson = has_encoding(CT_JSON); + sdef.hasJson = gen_json_coder_functions; sdef.has_opentypes = get_has_opentypes(); sdef.opentype_outermost = get_is_opentype_outermost(); sdef.ot = generate_code_ot(pool); @@ -1544,7 +1544,7 @@ void Type::generate_code_Se(output_struct *target) sdef.opentype_outermost = get_is_opentype_outermost(); sdef.ot = NULL; sdef.hasXer = has_encoding(CT_XER); - sdef.hasJson = has_encoding(CT_JSON); + sdef.hasJson = gen_json_coder_functions; if (xerattrib){ Module *my_module = get_my_scope()->get_scope_mod(); sdef.xerHasNamespaces = my_module->get_nof_ns() != 0; @@ -2005,7 +2005,7 @@ void Type::generate_code_SeOf(output_struct *target) sofdef.isASN1 = is_asn1(); sofdef.hasText = textattrib!=NULL; sofdef.hasXer = has_encoding(CT_XER); - sofdef.hasJson = has_encoding(CT_JSON); + sofdef.hasJson = gen_json_coder_functions; if (xerattrib) { //sofdef.xerList = xerattrib->list_; sofdef.xerAttribute = xerattrib->attribute_; diff --git a/compiler2/ttcn3/Attributes.cc b/compiler2/ttcn3/Attributes.cc index 4e1932708bc2a69e2f42b8cfee5477667464fb33..d94f4eb4ea088212ee54f01db6817446ac7cafd8 100644 --- a/compiler2/ttcn3/Attributes.cc +++ b/compiler2/ttcn3/Attributes.cc @@ -1155,6 +1155,12 @@ namespace Ttcn { { case SingleWithAttrib::AT_ENCODE: { + if (temp_attrib->get_attribQualifiers() != NULL && + temp_attrib->get_attribQualifiers()->get_nof_qualifiers() != 0) { + // TODO: check the attributes grouped per qualifier (for now + // ignoring this check for attributes with qualifiers is enough) + break; + } if(has_encode) { temp_attrib->warning("Only the last encode " diff --git a/regression_test/json/Functions.ttcn b/regression_test/json/Functions.ttcn index 314b6505fcc36d6be88c744df4d195e876fc2a59..40f0690e4b5de46262373e004cb14e39098112f7 100644 --- a/regression_test/json/Functions.ttcn +++ b/regression_test/json/Functions.ttcn @@ -15,6 +15,7 @@ module Functions import from Types all; import from JsonData language "ASN.1" all; +import from OtherTypes all; //=================== Encoders ===================================== @@ -135,6 +136,66 @@ external function f_enc_meta_setof(in MetainfoSetOf x) return octetstring external function f_enc_meta_arr(in MetainfoArray x) return octetstring with { extension "prototype(convert) encode(JSON)" } + +external function f_enc_type_alias_rec(in SupportedRec x) return octetstring + with { extension "prototype(convert) encode(JSON)" } + +external function f_enc_type_alias_list(in SupportedList x) return octetstring + with { extension "prototype(convert) encode(JSON)" } + +external function f_enc_type_alias_uni(in SupportedUni x) return octetstring + with { extension "prototype(convert) encode(JSON)" } + +external function f_enc_type_alias_enum(in SupportedEnum x) return octetstring + with { extension "prototype(convert) encode(JSON)" } + +external function f_enc_type_alias_any(in SupportedAny x) return octetstring + with { extension "prototype(convert) encode(JSON)" } + +external function f_enc_field_rec(in RecWithEncAttrInFields.rec x) return octetstring + with { extension "prototype(convert) encode(JSON)" } + +external function f_enc_field_list(in RecWithEncAttrInFields.list x) return octetstring + with { extension "prototype(convert) encode(JSON)" } + +external function f_enc_field_uni(in RecWithEncAttrInFields.uni x) return octetstring + with { extension "prototype(convert) encode(JSON)" } + +external function f_enc_field_enum(in RecWithEncAttr.en x) return octetstring + with { extension "prototype(convert) encode(JSON)" } + +external function f_enc_field_any(in RecWithEncAttr.at x) return octetstring + with { extension "prototype(convert) encode(JSON)" } + +external function f_enc_elem_rec(in RecOfRec[-] x) return octetstring + with { extension "prototype(convert) encode(JSON)" } + +external function f_enc_elem_list(in RecOfList[-] x) return octetstring + with { extension "prototype(convert) encode(JSON)" } + +external function f_enc_elem_uni(in RecOfUni[-] x) return octetstring + with { extension "prototype(convert) encode(JSON)" } + +external function f_enc_elem_enum(in RecOfEnum[-] x) return octetstring + with { extension "prototype(convert) encode(JSON)" } + +external function f_enc_elem_any(in RecOfAny[-] x) return octetstring + with { extension "prototype(convert) encode(JSON)" } + +external function f_enc_embedded_rec(in UniWithEmbEncAttr.rec.rec x) return octetstring + with { extension "prototype(convert) encode(JSON)" } + +external function f_enc_embedded_list(in UniWithEmbEncAttr.rec.list x) return octetstring + with { extension "prototype(convert) encode(JSON)" } + +external function f_enc_embedded_uni(in UniWithEmbEncAttr.uni_list[-] x) return octetstring + with { extension "prototype(convert) encode(JSON)" } + +external function f_enc_embedded_enum(in UniWithEmbEncAttr.emb_list[-].en x) return octetstring + with { extension "prototype(convert) encode(JSON)" } + +external function f_enc_embedded_any(in UniWithEmbEncAttr.emb_list[-].at_list[-] x) return octetstring + with { extension "prototype(convert) encode(JSON)" } // for ASN.1 types external function f_enc_seqofint(in SeqOfInt x) return octetstring @@ -268,6 +329,66 @@ external function f_dec_meta_setof(in octetstring x) return MetainfoSetOf external function f_dec_meta_arr(in octetstring x) return MetainfoArray with { extension "prototype(convert) decode(JSON)" } + +external function f_dec_type_alias_rec(in octetstring x) return SupportedRec + with { extension "prototype(convert) decode(JSON)" } + +external function f_dec_type_alias_list(in octetstring x) return SupportedList + with { extension "prototype(convert) decode(JSON)" } + +external function f_dec_type_alias_uni(in octetstring x) return SupportedUni + with { extension "prototype(convert) decode(JSON)" } + +external function f_dec_type_alias_enum(in octetstring x) return SupportedEnum + with { extension "prototype(convert) decode(JSON)" } + +external function f_dec_type_alias_any(in octetstring x) return SupportedAny + with { extension "prototype(convert) decode(JSON)" } + +external function f_dec_field_rec(in octetstring x) return RecWithEncAttrInFields.rec + with { extension "prototype(convert) decode(JSON)" } + +external function f_dec_field_list(in octetstring x) return RecWithEncAttrInFields.list + with { extension "prototype(convert) decode(JSON)" } + +external function f_dec_field_uni(in octetstring x) return RecWithEncAttrInFields.uni + with { extension "prototype(convert) decode(JSON)" } + +external function f_dec_field_enum(in octetstring x) return RecWithEncAttr.en + with { extension "prototype(convert) decode(JSON)" } + +external function f_dec_field_any(in octetstring x) return RecWithEncAttr.at + with { extension "prototype(convert) decode(JSON)" } + +external function f_dec_elem_rec(in octetstring x) return RecOfRec[-] + with { extension "prototype(convert) decode(JSON)" } + +external function f_dec_elem_list(in octetstring x) return RecOfList[-] + with { extension "prototype(convert) decode(JSON)" } + +external function f_dec_elem_uni(in octetstring x) return RecOfUni[-] + with { extension "prototype(convert) decode(JSON)" } + +external function f_dec_elem_enum(in octetstring x) return RecOfEnum[-] + with { extension "prototype(convert) decode(JSON)" } + +external function f_dec_elem_any(in octetstring x) return RecOfAny[-] + with { extension "prototype(convert) decode(JSON)" } + +external function f_dec_embedded_rec(in octetstring x) return UniWithEmbEncAttr.rec.rec + with { extension "prototype(convert) decode(JSON)" } + +external function f_dec_embedded_list(in octetstring x) return UniWithEmbEncAttr.rec.list + with { extension "prototype(convert) decode(JSON)" } + +external function f_dec_embedded_uni(in octetstring x) return UniWithEmbEncAttr.uni_list[-] + with { extension "prototype(convert) decode(JSON)" } + +external function f_dec_embedded_enum(in octetstring x) return UniWithEmbEncAttr.emb_list[-].en + with { extension "prototype(convert) decode(JSON)" } + +external function f_dec_embedded_any(in octetstring x) return UniWithEmbEncAttr.emb_list[-].at_list[-] + with { extension "prototype(convert) decode(JSON)" } // for ASN.1 types external function f_dec_seqofint(in octetstring x) return SeqOfInt diff --git a/regression_test/json/Makefile b/regression_test/json/Makefile index 53dd0318db11e44ee031cf977dc95c6611ced41f..6362c39327d527fe77d83df9aede414d73895ccc 100644 --- a/regression_test/json/Makefile +++ b/regression_test/json/Makefile @@ -19,7 +19,7 @@ include $(TOPDIR)/Makefile.regression TTCN3_LIB = ttcn3$(RT2_SUFFIX)$(DYNAMIC_SUFFIX) -TTCN3_MODULES = Types.ttcn Functions.ttcn AttributeTestcases.ttcn Testcases.ttcn SemanticCheck.ttcn +TTCN3_MODULES = Types.ttcn Functions.ttcn AttributeTestcases.ttcn Testcases.ttcn SemanticCheck.ttcn OtherTypes.ttcn ASN1_MODULES = JsonData.asn diff --git a/regression_test/json/OtherTypes.ttcn b/regression_test/json/OtherTypes.ttcn new file mode 100644 index 0000000000000000000000000000000000000000..b55ebad06a57077ac4bf7174bc0889785da8b00f --- /dev/null +++ b/regression_test/json/OtherTypes.ttcn @@ -0,0 +1,84 @@ +/****************************************************************************** + * Copyright (c) 2000-2017 Ericsson Telecom AB + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Baranyi, Botond + * + ******************************************************************************/ + +// more type definitions, but this time there's not 'encode' attribute at module-level +module OtherTypes { + +// 'base' types that do not support JSON encoding +type record NotSuppRec { + integer x +} + +type set of charstring NotSuppList; + +type union NotSuppUni { + integer x +} + +type enumerated NotSuppEnum { val1 }; + +// type aliases that give JSON encoding support to the 'base' types +type NotSuppRec SupportedRec with { encode "JSON" }; +type NotSuppList SupportedList with { encode "JSON" }; +type NotSuppUni SupportedUni with { encode "JSON" }; +type NotSuppEnum SupportedEnum with { encode "JSON" }; +type anytype SupportedAny with { encode "JSON" }; + +// types that use the 'base' types as fields/elements, and give them JSON encoding support +type record RecWithEncAttrInFields { + NotSuppRec rec, + NotSuppList list, + NotSuppUni uni +} +with { + encode (rec) "JSON"; + encode (list) "JSON"; + encode (uni) "JSON"; +} + +type record RecWithEncAttr { + NotSuppEnum en, + anytype at +} +with { + encode "JSON"; +} + +type record of NotSuppRec RecOfRec with { encode "JSON" }; +type record of NotSuppList RecOfList with { encode "JSON" }; +type record of NotSuppUni RecOfUni with { encode ([-]) "JSON" }; +type record of NotSuppEnum RecOfEnum with { encode ([-]) "JSON" }; +type record of anytype RecOfAny with { encode ([-]) "JSON" }; + +type union UniWithEmbEncAttr { + record { + NotSuppRec rec optional, + NotSuppList list optional + } rec, + record of NotSuppUni uni_list, + record of record { + SupportedEnum en optional, + record of anytype at_list optional + } emb_list +} +with { + encode (rec.rec) "JSON"; + encode (rec.list) "JSON"; + encode (uni_list[-]) "JSON"; + encode (emb_list[-].en) "JSON"; + encode (emb_list[-].at_list[-]) "JSON"; +} + +} +with { + extension "anytype integer, charstring" +} diff --git a/regression_test/json/Testcases.ttcn b/regression_test/json/Testcases.ttcn index 185ada5edeb74b8f3754f8546f0f704c0e69b118..1c890c2626eab8ac414fa1883ac50779674437ac 100644 --- a/regression_test/json/Testcases.ttcn +++ b/regression_test/json/Testcases.ttcn @@ -15,6 +15,7 @@ module Testcases { import from Functions all; import from Types all; import from JsonData language "ASN.1" all; +import from OtherTypes all; modulepar R tsp_r := { i:= 1, @@ -632,6 +633,172 @@ testcase tc_binary_strings_with_invalid_chars() runs on MTC { } } +// Coding a type alias with JSON encoding, whose base type is a record with no JSON encoding support. +testcase tc_type_alias_record() runs on MTC { + var SupportedRec x := { x := 1 }; + var octetstring os := char2oct("{\"x\":1}"); + f_check_encoding(encoded:= f_enc_type_alias_rec(x), expected := os); + f_bool2verdict(match(f_dec_type_alias_rec(os), x)); +} + +// Coding a type alias with JSON encoding, whose base type is a 'set of' with no JSON encoding support. +testcase tc_type_alias_setof() runs on MTC { + var SupportedList x := { "abc", "xyz" }; + var octetstring os := char2oct("[\"abc\",\"xyz\"]"); + f_check_encoding(encoded:= f_enc_type_alias_list(x), expected := os); + f_bool2verdict(match(f_dec_type_alias_list(os), x)); +} + +// Coding a type alias with JSON encoding, whose base type is a union with no JSON encoding support. +testcase tc_type_alias_union() runs on MTC { + var SupportedUni x := { x := 1 }; + var octetstring os := char2oct("{\"x\":1}"); + f_check_encoding(encoded:= f_enc_type_alias_uni(x), expected := os); + f_bool2verdict(match(f_dec_type_alias_uni(os), x)); +} + +// Coding a type alias with JSON encoding, whose base type is an enumerated with no JSON encoding support. +testcase tc_type_alias_enumerated() runs on MTC { + var SupportedEnum x := val1; + var octetstring os := char2oct("\"val1\""); + f_check_encoding(encoded:= f_enc_type_alias_enum(x), expected := os); + f_bool2verdict(match(f_dec_type_alias_enum(os), x)); +} + +// Coding a type alias with JSON encoding, whose base type is an anytype with no JSON encoding support. +testcase tc_type_alias_anytype() runs on MTC { + var SupportedAny x := { integer := 1 }; + var octetstring os := char2oct("{\"integer\":1}"); + f_check_encoding(encoded:= f_enc_type_alias_any(x), expected := os); + f_bool2verdict(match(f_dec_type_alias_any(os), x)); +} + +const RecWithEncAttrInFields c_fields := { + rec := { x := 1 }, + list := { "abc", "xyz" }, + uni := { x := 1 } +} + +const RecWithEncAttr c_fields2 := { + en := val1, + at := { integer := 1 } +} + +// Coding a record field with JSON encoding, whose base type is a record with no JSON encoding support. +testcase tc_field_record() runs on MTC { + var octetstring os := char2oct("{\"x\":1}"); + f_check_encoding(encoded:= f_enc_field_rec(c_fields.rec), expected := os); + f_bool2verdict(match(f_dec_field_rec(os), c_fields.rec)); +} + +// Coding a record field with JSON encoding, whose base type is a 'set of' with no JSON encoding support. +testcase tc_field_setof() runs on MTC { + var octetstring os := char2oct("[\"abc\",\"xyz\"]"); + f_check_encoding(encoded:= f_enc_field_list(c_fields.list), expected := os); + f_bool2verdict(match(f_dec_field_list(os), c_fields.list)); +} + +// Coding a record field with JSON encoding, whose base type is a union with no JSON encoding support. +testcase tc_field_union() runs on MTC { + var octetstring os := char2oct("{\"x\":1}"); + f_check_encoding(encoded:= f_enc_field_uni(c_fields.uni), expected := os); + f_bool2verdict(match(f_dec_field_uni(os), c_fields.uni)); +} + +// Coding a record field with JSON encoding, whose base type is an enumerated with no JSON encoding support. +testcase tc_field_enumerated() runs on MTC { + var octetstring os := char2oct("\"val1\""); + f_check_encoding(encoded:= f_enc_field_enum(c_fields2.en), expected := os); + f_bool2verdict(match(f_dec_field_enum(os), c_fields2.en)); +} + +// Coding a record field with JSON encoding, whose base type is an anytype with no JSON encoding support. +testcase tc_field_anytype() runs on MTC { + var octetstring os := char2oct("{\"integer\":1}"); + f_check_encoding(encoded:= f_enc_field_any(c_fields2.at), expected := os); + f_bool2verdict(match(f_dec_field_any(os), c_fields2.at)); +} + +// Coding a 'record of' element with JSON encoding, whose base type is a record with no JSON encoding support. +testcase tc_elem_record() runs on MTC { + var RecOfRec x := { { x := 1 } }; + var octetstring os := char2oct("{\"x\":1}"); + f_check_encoding(encoded:= f_enc_elem_rec(x[0]), expected := os); + f_bool2verdict(match(f_dec_elem_rec(os), x[0])); +} + +// Coding a 'record of' element with JSON encoding, whose base type is a 'set of' with no JSON encoding support. +testcase tc_elem_setof() runs on MTC { + var RecOfList x := { { "abc", "xyz" } }; + var octetstring os := char2oct("[\"abc\",\"xyz\"]"); + f_check_encoding(encoded:= f_enc_elem_list(x[0]), expected := os); + f_bool2verdict(match(f_dec_elem_list(os), x[0])); +} + +// Coding a 'record of' element with JSON encoding, whose base type is a union with no JSON encoding support. +testcase tc_elem_union() runs on MTC { + var RecOfUni x := { { x := 1 } }; + var octetstring os := char2oct("{\"x\":1}"); + f_check_encoding(encoded:= f_enc_elem_uni(x[0]), expected := os); + f_bool2verdict(match(f_dec_elem_uni(os), x[0])); +} + +// Coding a 'record of' element with JSON encoding, whose base type is an enumerated with no JSON encoding support. +testcase tc_elem_enumerated() runs on MTC { + var RecOfEnum x := { val1 }; + var octetstring os := char2oct("\"val1\""); + f_check_encoding(encoded:= f_enc_elem_enum(x[0]), expected := os); + f_bool2verdict(match(f_dec_elem_enum(os), x[0])); +} + +// Coding a 'record of' element with JSON encoding, whose base type is an anytype with no JSON encoding support. +testcase tc_elem_anytype() runs on MTC { + var RecOfAny x := { { integer := 1 } }; + var octetstring os := char2oct("{\"integer\":1}"); + f_check_encoding(encoded:= f_enc_elem_any(x[0]), expected := os); + f_bool2verdict(match(f_dec_elem_any(os), x[0])); +} + +// Coding an embedded field type (in a multi-level structure) with JSON encoding, whose base type is a record with no JSON encoding support. +testcase tc_embedded_record() runs on MTC { + var UniWithEmbEncAttr x := { rec := { rec := { x := 1 }, list := omit } }; + var octetstring os := char2oct("{\"x\":1}"); + f_check_encoding(encoded:= f_enc_embedded_rec(x.rec.rec), expected := os); + f_bool2verdict(match(f_dec_embedded_rec(os), x.rec.rec)); +} + +// Coding an embedded field type (in a multi-level structure) with JSON encoding, whose base type is a 'set of' with no JSON encoding support. +testcase tc_embedded_setof() runs on MTC { + var UniWithEmbEncAttr x := { rec := { rec := omit, list := { "abc", "xyz" } } }; + var octetstring os := char2oct("[\"abc\",\"xyz\"]"); + f_check_encoding(encoded:= f_enc_embedded_list(x.rec.list), expected := os); + f_bool2verdict(match(f_dec_embedded_list(os), x.rec.list)); +} + +// Coding an embedded element type (in a multi-level structure) with JSON encoding, whose base type is a union with no JSON encoding support. +testcase tc_embedded_union() runs on MTC { + var UniWithEmbEncAttr x := { uni_list := { { x := 1 } } }; + var octetstring os := char2oct("{\"x\":1}"); + f_check_encoding(encoded:= f_enc_embedded_uni(x.uni_list[0]), expected := os); + f_bool2verdict(match(f_dec_embedded_uni(os), x.uni_list[0])); +} + +// Coding an embedded field type (in a multi-level structure) with JSON encoding, whose base type is an enumerated with no JSON encoding support. +testcase tc_embedded_enumerated() runs on MTC { + var UniWithEmbEncAttr x := { emb_list := { { en := val1, at_list := omit } } }; + var octetstring os := char2oct("\"val1\""); + f_check_encoding(encoded:= f_enc_embedded_enum(x.emb_list[0].en), expected := os); + f_bool2verdict(match(f_dec_embedded_enum(os), x.emb_list[0].en)); +} + +// Coding an embedded element type (in a multi-level structure) with JSON encoding, whose base type is an anytype with no JSON encoding support. +testcase tc_embedded_anytype() runs on MTC { + var UniWithEmbEncAttr x := { emb_list := { { en := omit, at_list := { { integer := 1 } } } } }; + var octetstring os := char2oct("{\"integer\":1}"); + f_check_encoding(encoded:= f_enc_embedded_any(x.emb_list[0].at_list[0]), expected := os); + f_bool2verdict(match(f_dec_embedded_any(os), x.emb_list[0].at_list[0])); +} + //========================================================================= // Control //========================================================================= @@ -698,6 +865,27 @@ control { execute(tc_binary_strings_with_white_spaces()); execute(tc_binary_strings_with_invalid_chars()); + + execute(tc_type_alias_record()); + execute(tc_type_alias_setof()); + execute(tc_type_alias_union()); + execute(tc_type_alias_enumerated()); + execute(tc_type_alias_anytype()); + execute(tc_field_record()); + execute(tc_field_setof()); + execute(tc_field_union()); + execute(tc_field_enumerated()); + execute(tc_field_anytype()); + execute(tc_elem_record()); + execute(tc_elem_setof()); + execute(tc_elem_union()); + execute(tc_elem_enumerated()); + execute(tc_elem_anytype()); + execute(tc_embedded_record()); + execute(tc_embedded_setof()); + execute(tc_embedded_union()); + execute(tc_embedded_enumerated()); + execute(tc_embedded_anytype()); }