diff --git a/ocaml/sdk-gen/common/CommonFunctions.ml b/ocaml/sdk-gen/common/CommonFunctions.ml index a1b613a34b8..cffa59b4276 100644 --- a/ocaml/sdk-gen/common/CommonFunctions.ml +++ b/ocaml/sdk-gen/common/CommonFunctions.ml @@ -363,3 +363,56 @@ let objects = api in objects_of_api api + +module TypesOfMessages = struct + open Xapi_stdext_std + + let records = + List.map + (fun obj -> + let obj_name = String.lowercase_ascii obj.name in + (obj_name, Datamodel_utils.fields_of_obj obj) + ) + objects + + let rec decompose = function + | Set x as y -> + y :: decompose x + | Map (a, b) as y -> + (y :: decompose a) @ decompose b + | Option x as y -> + y :: decompose x + | Record r as y -> + let name = String.lowercase_ascii r in + let types_in_field = + List.assoc_opt name records + |> Option.value ~default:[] + |> List.concat_map (fun field -> decompose field.ty) + in + y :: types_in_field + | (SecretString | String | Int | Float | DateTime | Enum _ | Bool | Ref _) + as x -> + [x] + + let mesages objects = objects |> List.concat_map (fun x -> x.messages) + + (** All types of params in a list of objects (automatically decomposes) *) + let of_params objects = + let param_types = + mesages objects + |> List.concat_map (fun x -> x.msg_params) + |> List.map (fun p -> p.param_type) + |> Listext.List.setify + in + List.concat_map decompose param_types |> Listext.List.setify + + (** All types of results in a list of objects (automatically decomposes) *) + let of_results objects = + let return_types = + let aux accu msg = + match msg.msg_result with None -> accu | Some (ty, _) -> ty :: accu + in + mesages objects |> List.fold_left aux [] |> Listext.List.setify + in + List.concat_map decompose return_types |> Listext.List.setify +end diff --git a/ocaml/sdk-gen/common/CommonFunctions.mli b/ocaml/sdk-gen/common/CommonFunctions.mli index 197dcb8a3a4..71106ad1960 100644 --- a/ocaml/sdk-gen/common/CommonFunctions.mli +++ b/ocaml/sdk-gen/common/CommonFunctions.mli @@ -137,3 +137,11 @@ val session_id : param val objects : obj list (** Objects of api that generate SDKs. *) + +module TypesOfMessages : sig + val of_params : Datamodel_types.obj list -> Datamodel_types.ty list + (** All the types in the params of messages*) + + val of_results : Datamodel_types.obj list -> Datamodel_types.ty list + (** All the types in the results of messages*) +end diff --git a/ocaml/sdk-gen/go/gen_go_binding.ml b/ocaml/sdk-gen/go/gen_go_binding.ml index b12077a7593..0203e16966c 100644 --- a/ocaml/sdk-gen/go/gen_go_binding.ml +++ b/ocaml/sdk-gen/go/gen_go_binding.ml @@ -68,11 +68,60 @@ let render_api_messages_and_errors destdir = generate_file ~rendered:messages_rendered ~destdir ~output_file:"api_messages.go" +let render_convert_header () = + let name s = `O [("name", `String s); ("sname", `Null)] in + let obj = + `O + [ + ("name", `String "convert") + ; ( "modules" + , `O + [ + ("import", `Bool true) + ; ( "items" + , `A (List.map name ["fmt"; "math"; "reflect"; "strconv"; "time"]) + ) + ] + ) + ] + in + render_template "FileHeader.mustache" obj ~newline:true () + +let render_converts destdir = + let event = render_template "ConvertBatch.mustache" Convert.event_batch () in + let interface = + render_template "ConvertInterface.mustache" Convert.interface () + in + let param_types = TypesOfMessages.of_params objects in + let result_types = TypesOfMessages.of_results objects in + let generate types of_json = + types + |> List.map (fun ty -> + let params = Convert.of_ty ty in + let template = Convert.template_of_convert params in + let json : Mustache.Json.t = of_json params in + render_template template json () + ) + |> String.concat "" + in + let rendered = + let serializes_rendered = generate param_types Convert.of_serialize in + let deserializes_rendered = generate result_types Convert.of_deserialize in + render_convert_header () + ^ serializes_rendered + ^ deserializes_rendered + ^ event + ^ String.trim interface + ^ "\n" + in + generate_file ~rendered ~destdir ~output_file:"convert.go" + let main destdir = render_api_versions destdir ; render_api_messages_and_errors destdir ; let enums = Json.all_enums objects in render_enums enums destdir ; + render_converts destdir ; let objects = Json.xenapi objects in List.iter (fun (name, obj) -> diff --git a/ocaml/sdk-gen/go/gen_go_helper.ml b/ocaml/sdk-gen/go/gen_go_helper.ml index 4a9623550a9..0a8d3740b92 100644 --- a/ocaml/sdk-gen/go/gen_go_helper.ml +++ b/ocaml/sdk-gen/go/gen_go_helper.ml @@ -52,6 +52,14 @@ let snake_to_camel (s : string) : string = ) |> String.concat "" +let records = + List.map + (fun obj -> + let obj_name = snake_to_camel obj.name ^ "Record" in + (obj_name, Datamodel_utils.fields_of_obj obj) + ) + objects + let render_template template_file json ?(newline = false) () = let templ = string_of_file (templates_dir // template_file) |> Mustache.of_string @@ -183,7 +191,7 @@ module Json = struct let all_enums objs = let enums = - Types.of_objects objs + Datamodel_utils.Types.of_objects objs |> List.map (fun ty -> let _, e = string_of_ty_with_enums ty in e @@ -425,3 +433,270 @@ module Json = struct let api_errors = List.map of_api_message_or_error !Api_errors.errors end + +module Convert = struct + type params = {func_suffix: string; value_ty: string} + + type params_of_option = {func_suffix: string} + + type params_of_set = { + func_suffix: string + ; value_ty: string + ; item_fp_type: string + } + + type params_of_record_field = { + name: string + ; name_internal: string + ; name_exported: string + ; func_suffix: string + ; type_option: bool + } + + type params_of_record = { + func_suffix: string + ; value_ty: string + ; fields: params_of_record_field list + } + + type params_of_enum_item = {value: string; name: string} + + type params_of_enum = { + func_suffix: string + ; value_ty: string + ; items: params_of_enum_item list + } + + type params_of_map = { + func_suffix: string + ; value_ty: string + ; key_ty: string + ; val_ty: string + } + + type convert_params = + | Simple of params + | Int of params + | Float of params + | Time of params + | Ref of params + | Option of params_of_option + | Set of params_of_set + | Enum of params_of_enum + | Record of params_of_record + | Map of params_of_map + + let template_of_convert : convert_params -> string = function + | Simple _ -> + "ConvertSimpleType.mustache" + | Int _ -> + "ConvertInt.mustache" + | Float _ -> + "ConvertFloat.mustache" + | Time _ -> + "ConvertTime.mustache" + | Ref _ -> + "ConvertRef.mustache" + | Set _ -> + "ConvertSet.mustache" + | Record _ -> + "ConvertRecord.mustache" + | Map _ -> + "ConvertMap.mustache" + | Enum _ -> + "ConvertEnum.mustache" + | Option _ -> + "ConvertOption.mustache" + + let to_json : convert_params -> Mustache.Json.value = function + | Simple params | Int params | Float params | Time params | Ref params -> + `O + [ + ("func_name_suffix", `String params.func_suffix) + ; ("type", `String params.value_ty) + ] + | Option params -> + `O [("func_name_suffix", `String params.func_suffix)] + | Set params -> + `O + [ + ("func_name_suffix", `String params.func_suffix) + ; ("type", `String params.value_ty) + ; ("item_func_suffix", `String params.item_fp_type) + ] + | Record params -> + let fields = + List.rev_map + (fun (field : params_of_record_field) -> + `O + [ + ("name", `String field.name) + ; ("name_internal", `String field.name_internal) + ; ("name_exported", `String field.name_exported) + ; ("func_name_suffix", `String field.func_suffix) + ; ("type_option", `Bool field.type_option) + ] + ) + params.fields + in + `O + [ + ("func_name_suffix", `String params.func_suffix) + ; ("type", `String params.value_ty) + ; ("fields", `A fields) + ] + | Enum params -> + let of_value item = + `O [("value", `String item.value); ("name", `String item.name)] + in + `O + [ + ("type", `String params.value_ty) + ; ("func_name_suffix", `String params.func_suffix) + ; ("items", `A (List.map of_value params.items)) + ] + | Map params -> + `O + [ + ("func_name_suffix", `String params.func_suffix) + ; ("type", `String params.value_ty) + ; ("key_type", `String params.key_ty) + ; ("value_type", `String params.val_ty) + ] + + let fields record_name = + let fields = + List.assoc_opt record_name records + |> Option.value ~default:[] + |> List.rev_map (fun field -> + ( String.concat "_" field.full_name + , Json.suffix_of_type field.ty + , match field.ty with Option _ -> true | _ -> false + ) + ) + in + if record_name = "EventRecord" then + ("snapshot", "RecordInterface", false) :: fields + else + fields + + let of_ty = function + | SecretString | String -> + Simple {func_suffix= "String"; value_ty= "string"} + | Int -> + Int {func_suffix= "Int"; value_ty= "int"} + | Float -> + Float {func_suffix= "Float"; value_ty= "float64"} + | Bool -> + Simple {func_suffix= "Bool"; value_ty= "bool"} + | DateTime -> + Time {func_suffix= "Time"; value_ty= "time.Time"} + | Enum (name, kv) as ty -> + let name = snake_to_camel name in + let items = + List.map (fun (k, _) -> {value= k; name= name ^ snake_to_camel k}) kv + in + Enum {func_suffix= Json.suffix_of_type ty; value_ty= name; items} + | Set ty as set -> + let fp_ty = Json.suffix_of_type ty in + let ty, _ = Json.string_of_ty_with_enums ty in + Set + { + func_suffix= Json.suffix_of_type set + ; value_ty= ty + ; item_fp_type= fp_ty + } + | Map (ty1, ty2) as ty -> + let name, _ = Json.string_of_ty_with_enums ty in + Map + { + func_suffix= Json.suffix_of_type ty + ; value_ty= name + ; key_ty= Json.suffix_of_type ty1 + ; val_ty= Json.suffix_of_type ty2 + } + | Ref _ as ty -> + let name = Json.suffix_of_type ty in + Ref {func_suffix= name; value_ty= name} + | Record r -> + let name = snake_to_camel r ^ "Record" in + let fields = + List.map + (fun (name, func_suffix, is_option_type) -> + let camel_name = snake_to_camel name in + { + name + ; name_internal= String.uncapitalize_ascii camel_name + ; name_exported= camel_name + ; func_suffix + ; type_option= is_option_type + } + ) + (fields name) + in + Record {func_suffix= name; value_ty= name; fields} + | Option ty -> + Option {func_suffix= Json.suffix_of_type ty} + + let of_serialize params = + `O [("serialize", `A [to_json params]); ("deserialize", `Null)] + + let of_deserialize params = + `O [("serialize", `Null); ("deserialize", `A [to_json params])] + + let event_batch : Mustache.Json.t = + `O + [ + ( "deserialize" + , `A + [ + `O + [ + ("func_name_suffix", `String "EventBatch") + ; ("type", `String "EventBatch") + ; ( "elements" + , `A + [ + `O + [ + ("name", `String "token") + ; ("name_internal", `String "token") + ; ("name_exported", `String "Token") + ; ("func_name_suffix", `String "String") + ] + ; `O + [ + ("name", `String "validRefCounts") + ; ("name_internal", `String "validRefCounts") + ; ("name_exported", `String "ValidRefCounts") + ; ("func_name_suffix", `String "StringToIntMap") + ] + ; `O + [ + ("name", `String "events") + ; ("name_internal", `String "events") + ; ("name_exported", `String "Events") + ; ("func_name_suffix", `String "EventRecordSet") + ] + ] + ) + ] + ] + ) + ] + + let interface : Mustache.Json.t = + `O + [ + ( "deserialize" + , `A + [ + `O + [ + ("func_name_suffix", `String "RecordInterface") + ; ("type", `String "RecordInterface") + ] + ] + ) + ] +end diff --git a/ocaml/sdk-gen/go/gen_go_helper.mli b/ocaml/sdk-gen/go/gen_go_helper.mli index 85dff4ba4d4..ffa5ac673c9 100644 --- a/ocaml/sdk-gen/go/gen_go_helper.mli +++ b/ocaml/sdk-gen/go/gen_go_helper.mli @@ -40,3 +40,72 @@ module Json : sig val api_errors : Mustache.Json.value list end + +module Convert : sig + type params = {func_suffix: string; value_ty: string} + + type params_of_option = {func_suffix: string} + + type params_of_set = { + func_suffix: string + ; value_ty: string + ; item_fp_type: string + } + + type params_of_record_field = { + name: string + ; name_internal: string + ; name_exported: string + ; func_suffix: string + ; type_option: bool + } + + type params_of_record = { + func_suffix: string + ; value_ty: string + ; fields: params_of_record_field list + } + + type params_of_enum_item = {value: string; name: string} + + type params_of_enum = { + func_suffix: string + ; value_ty: string + ; items: params_of_enum_item list + } + + type params_of_map = { + func_suffix: string + ; value_ty: string + ; key_ty: string + ; val_ty: string + } + + type convert_params = + | Simple of params + | Int of params + | Float of params + | Time of params + | Ref of params + | Option of params_of_option + | Set of params_of_set + | Enum of params_of_enum + | Record of params_of_record + | Map of params_of_map + + val template_of_convert : convert_params -> string + + val to_json : convert_params -> Mustache.Json.value + + val fields : string -> (string * string * bool) list + + val of_ty : Datamodel_types.ty -> convert_params + + val of_serialize : convert_params -> Mustache.Json.t + + val of_deserialize : convert_params -> Mustache.Json.t + + val event_batch : Mustache.Json.t + + val interface : Mustache.Json.t +end diff --git a/ocaml/sdk-gen/go/templates/ConvertBatch.mustache b/ocaml/sdk-gen/go/templates/ConvertBatch.mustache new file mode 100644 index 00000000000..42f05791cb8 --- /dev/null +++ b/ocaml/sdk-gen/go/templates/ConvertBatch.mustache @@ -0,0 +1,20 @@ +{{#deserialize}} +func deserialize{{func_name_suffix}}(context string, input interface{}) (batch {{type}}, err error) { + rpcStruct, ok := input.(map[string]interface{}) + if !ok { + err = fmt.Errorf("failed to parse XenAPI response: expected Go type %s at %s but got Go type %s with value %v", "map[string]interface{}", context, reflect.TypeOf(input), input) + return + } +{{#elements}} + {{name_internal}}Value, ok := rpcStruct["{{name}}"] + if ok && {{name_internal}}Value != nil { + batch.{{name_exported}}, err = deserialize{{func_name_suffix}}(fmt.Sprintf("%s.%s", context, "{{name}}"), {{name_internal}}Value) + if err != nil { + return + } + } +{{/elements}} + return +} + +{{/deserialize}} \ No newline at end of file diff --git a/ocaml/sdk-gen/go/templates/ConvertEnum.mustache b/ocaml/sdk-gen/go/templates/ConvertEnum.mustache new file mode 100644 index 00000000000..85bb1660c24 --- /dev/null +++ b/ocaml/sdk-gen/go/templates/ConvertEnum.mustache @@ -0,0 +1,25 @@ +{{#serialize}} +func serialize{{func_name_suffix}}(context string, value {{type}}) (string, error) { + _ = context + return string(value), nil +} + +{{/serialize}} +{{#deserialize}} +func deserialize{{func_name_suffix}}(context string, input interface{}) (value {{type}}, err error) { + strValue, err := deserializeString(context, input) + if err != nil { + return + } + switch strValue { +{{#items}} + case "{{value}}": + value = {{name}} +{{/items}} + default: + err = fmt.Errorf("unable to parse XenAPI response: got value %q for enum %s at %s, but this is not any of the known values", strValue, "{{type}}", context) + } + return +} + +{{/deserialize}} \ No newline at end of file diff --git a/ocaml/sdk-gen/go/templates/ConvertFloat.mustache b/ocaml/sdk-gen/go/templates/ConvertFloat.mustache new file mode 100644 index 00000000000..89c5910909d --- /dev/null +++ b/ocaml/sdk-gen/go/templates/ConvertFloat.mustache @@ -0,0 +1,38 @@ +{{#serialize}} +//nolint:unparam +func serialize{{func_name_suffix}}(context string, value {{type}}) (interface{}, error) { + _ = context + if math.IsInf(value, 0) { + if math.IsInf(value, 1) { + return "+Inf", nil + } + return "-Inf", nil + } else if math.IsNaN(value) { + return "NaN", nil + } + return value, nil +} + +{{/serialize}} +{{#deserialize}} +func deserialize{{func_name_suffix}}(context string, input interface{}) (value {{type}}, err error) { + _ = context + if input == nil { + return + } + strValue := fmt.Sprintf("%v", input) + value, err = strconv.ParseFloat(strValue, 64) + if err != nil { + switch strValue { + case "+Inf": + return math.Inf(1), nil + case "-Inf": + return math.Inf(-1), nil + case "NaN": + return math.NaN(), nil + } + } + return +} + +{{/deserialize}} \ No newline at end of file diff --git a/ocaml/sdk-gen/go/templates/ConvertInt.mustache b/ocaml/sdk-gen/go/templates/ConvertInt.mustache new file mode 100644 index 00000000000..dbc7cf37c56 --- /dev/null +++ b/ocaml/sdk-gen/go/templates/ConvertInt.mustache @@ -0,0 +1,25 @@ +{{#serialize}} +func serialize{{func_name_suffix}}(context string, value {{type}}) ({{type}}, error) { + _ = context + return value, nil +} + +{{/serialize}} +{{#deserialize}} +func deserialize{{func_name_suffix}}(context string, input interface{}) (value {{type}}, err error) { + _ = context + if input == nil { + return + } + strValue := fmt.Sprintf("%v", input) + value, err = strconv.Atoi(strValue) + if err != nil { + floatValue, err1 := strconv.ParseFloat(strValue, 64) + if err1 == nil { + return int(floatValue), nil + } + } + return +} + +{{/deserialize}} \ No newline at end of file diff --git a/ocaml/sdk-gen/go/templates/ConvertInterface.mustache b/ocaml/sdk-gen/go/templates/ConvertInterface.mustache new file mode 100644 index 00000000000..9090d083058 --- /dev/null +++ b/ocaml/sdk-gen/go/templates/ConvertInterface.mustache @@ -0,0 +1,8 @@ +{{#deserialize}} +func deserialize{{func_name_suffix}}(context string, input interface{}) (inter {{type}}, err error) { + _ = context + inter = input + return +} + +{{/deserialize}} \ No newline at end of file diff --git a/ocaml/sdk-gen/go/templates/ConvertMap.mustache b/ocaml/sdk-gen/go/templates/ConvertMap.mustache new file mode 100644 index 00000000000..b4cca1d7ca8 --- /dev/null +++ b/ocaml/sdk-gen/go/templates/ConvertMap.mustache @@ -0,0 +1,43 @@ +{{#serialize}} +func serialize{{func_name_suffix}}(context string, goMap {{type}}) (xenMap map[string]interface{}, err error) { + xenMap = make(map[string]interface{}) + for goKey, goValue := range goMap { + keyContext := fmt.Sprintf("%s[%s]", context, goKey) + xenKey, err := serialize{{key_type}}(keyContext, goKey) + if err != nil { + return xenMap, err + } + xenValue, err := serialize{{value_type}}(keyContext, goValue) + if err != nil { + return xenMap, err + } + xenMap[xenKey] = xenValue + } + return +} + +{{/serialize}} +{{#deserialize}} +func deserialize{{func_name_suffix}}(context string, input interface{}) (goMap {{type}}, err error) { + xenMap, ok := input.(map[string]interface{}) + if !ok { + err = fmt.Errorf("failed to parse XenAPI response: expected Go type %s at %s but got Go type %s with value %v", "map[string]interface{}", context, reflect.TypeOf(input), input) + return + } + goMap = make({{type}}, len(xenMap)) + for xenKey, xenValue := range xenMap { + keyContext := fmt.Sprintf("%s[%s]", context, xenKey) + goKey, err := deserialize{{key_type}}(keyContext, xenKey) + if err != nil { + return goMap, err + } + goValue, err := deserialize{{value_type}}(keyContext, xenValue) + if err != nil { + return goMap, err + } + goMap[goKey] = goValue + } + return +} + +{{/deserialize}} \ No newline at end of file diff --git a/ocaml/sdk-gen/go/templates/ConvertOption.mustache b/ocaml/sdk-gen/go/templates/ConvertOption.mustache new file mode 100644 index 00000000000..ca49dea9f3b --- /dev/null +++ b/ocaml/sdk-gen/go/templates/ConvertOption.mustache @@ -0,0 +1,27 @@ +{{#serialize}} +func serializeOption{{func_name_suffix}}(context string, input Option{{func_name_suffix}}) (option interface{}, err error) { + if input == nil { + return + } + option, err = serialize{{func_name_suffix}}(context, *input) + if err != nil { + return + } + return +} + +{{/serialize}} +{{#deserialize}} +func deserializeOption{{func_name_suffix}}(context string, input interface{}) (option Option{{func_name_suffix}}, err error) { + if input == nil { + return + } + value, err := deserialize{{func_name_suffix}}(context, input) + if err != nil { + return + } + option = &value + return +} + +{{/deserialize}} \ No newline at end of file diff --git a/ocaml/sdk-gen/go/templates/ConvertRecord.mustache b/ocaml/sdk-gen/go/templates/ConvertRecord.mustache new file mode 100644 index 00000000000..6e973b87dd0 --- /dev/null +++ b/ocaml/sdk-gen/go/templates/ConvertRecord.mustache @@ -0,0 +1,52 @@ +{{#serialize}} +func serialize{{func_name_suffix}}(context string, record {{type}}) (rpcStruct map[string]interface{}, err error) { + rpcStruct = map[string]interface{}{} +{{#fields}} +{{#type_option}} + {{name_internal}}, err := serializeOption{{func_name_suffix}}(fmt.Sprintf("%s.%s", context, "{{name}}"), record.{{name_exported}}) + if err != nil { + return + } + if {{name_internal}} != nil { + rpcStruct["{{name}}"] = {{name_internal}} + } +{{/type_option}} +{{^type_option}} + rpcStruct["{{name}}"], err = serialize{{func_name_suffix}}(fmt.Sprintf("%s.%s", context, "{{name}}"), record.{{name_exported}}) + if err != nil { + return + } +{{/type_option}} +{{/fields}} + return +} + +{{/serialize}} +{{#deserialize}} +func deserialize{{func_name_suffix}}(context string, input interface{}) (record {{type}}, err error) { + rpcStruct, ok := input.(map[string]interface{}) + if !ok { + err = fmt.Errorf("failed to parse XenAPI response: expected Go type %s at %s but got Go type %s with value %v", "map[string]interface{}", context, reflect.TypeOf(input), input) + return + } +{{#fields}} +{{#type_option}} + record.{{name_exported}}, err = deserializeOption{{func_name_suffix}}(fmt.Sprintf("%s.%s", context, "{{name}}"), rpcStruct["{{name}}"]) + if err != nil { + return + } +{{/type_option}} +{{^type_option}} + {{name_internal}}Value, ok := rpcStruct["{{name}}"] + if ok && {{name_internal}}Value != nil { + record.{{name_exported}}, err = deserialize{{func_name_suffix}}(fmt.Sprintf("%s.%s", context, "{{name}}"), {{name_internal}}Value) + if err != nil { + return + } + } +{{/type_option}} +{{/fields}} + return +} + +{{/deserialize}} \ No newline at end of file diff --git a/ocaml/sdk-gen/go/templates/ConvertRef.mustache b/ocaml/sdk-gen/go/templates/ConvertRef.mustache new file mode 100644 index 00000000000..2b938dcb658 --- /dev/null +++ b/ocaml/sdk-gen/go/templates/ConvertRef.mustache @@ -0,0 +1,18 @@ +{{#serialize}} +func serialize{{func_name_suffix}}(context string, ref {{type}}) (string, error) { + _ = context + return string(ref), nil +} + +{{/serialize}} +{{#deserialize}} +func deserialize{{func_name_suffix}}(context string, input interface{}) ({{type}}, error) { + var ref {{type}} + value, ok := input.(string) + if !ok { + return ref, fmt.Errorf("failed to parse XenAPI response: expected Go type %s at %s but got Go type %s with value %v", "string", context, reflect.TypeOf(input), input) + } + return {{type}}(value), nil +} + +{{/deserialize}} \ No newline at end of file diff --git a/ocaml/sdk-gen/go/templates/ConvertSet.mustache b/ocaml/sdk-gen/go/templates/ConvertSet.mustache new file mode 100644 index 00000000000..c3f37099a78 --- /dev/null +++ b/ocaml/sdk-gen/go/templates/ConvertSet.mustache @@ -0,0 +1,35 @@ +{{#serialize}} +func serialize{{func_name_suffix}}(context string, slice []{{type}}) (set []interface{}, err error) { + set = make([]interface{}, len(slice)) + for index, item := range slice { + itemContext := fmt.Sprintf("%s[%d]", context, index) + itemValue, err := serialize{{item_func_suffix}}(itemContext, item) + if err != nil { + return set, err + } + set[index] = itemValue + } + return +} + +{{/serialize}} +{{#deserialize}} +func deserialize{{func_name_suffix}}(context string, input interface{}) (slice []{{type}}, err error) { + set, ok := input.([]interface{}) + if !ok { + err = fmt.Errorf("failed to parse XenAPI response: expected Go type %s at %s but got Go type %s with value %v", "[]interface{}", context, reflect.TypeOf(input), input) + return + } + slice = make([]{{type}}, len(set)) + for index, item := range set { + itemContext := fmt.Sprintf("%s[%d]", context, index) + itemValue, err := deserialize{{item_func_suffix}}(itemContext, item) + if err != nil { + return slice, err + } + slice[index] = itemValue + } + return +} + +{{/deserialize}} \ No newline at end of file diff --git a/ocaml/sdk-gen/go/templates/ConvertSimpleType.mustache b/ocaml/sdk-gen/go/templates/ConvertSimpleType.mustache new file mode 100644 index 00000000000..552052932a6 --- /dev/null +++ b/ocaml/sdk-gen/go/templates/ConvertSimpleType.mustache @@ -0,0 +1,20 @@ +{{#serialize}} +func serialize{{func_name_suffix}}(context string, value {{type}}) ({{type}}, error) { + _ = context + return value, nil +} + +{{/serialize}} +{{#deserialize}} +func deserialize{{func_name_suffix}}(context string, input interface{}) (value {{type}}, err error) { + if input == nil { + return + } + value, ok := input.({{type}}) + if !ok { + err = fmt.Errorf("failed to parse XenAPI response: expected Go type %s at %s but got Go type %s with value %v", "{{type}}", context, reflect.TypeOf(input), input) + } + return +} + +{{/deserialize}} \ No newline at end of file diff --git a/ocaml/sdk-gen/go/templates/ConvertTime.mustache b/ocaml/sdk-gen/go/templates/ConvertTime.mustache new file mode 100644 index 00000000000..d79f65841ad --- /dev/null +++ b/ocaml/sdk-gen/go/templates/ConvertTime.mustache @@ -0,0 +1,34 @@ +{{#serialize}} +var timeFormats = []string{time.RFC3339, "20060102T15:04:05Z", "20060102T15:04:05"} + +//nolint:unparam +func serialize{{func_name_suffix}}(context string, value {{type}}) (string, error) { + _ = context + return value.Format(time.RFC3339), nil +} + +{{/serialize}} +{{#deserialize}} +func deserialize{{func_name_suffix}}(context string, input interface{}) (value {{type}}, err error) { + _ = context + if input == nil { + return + } + strValue := fmt.Sprintf("%v", input) + floatValue, err := strconv.ParseFloat(strValue, 64) + if err != nil { + for _, timeFormat := range timeFormats { + value, err = time.Parse(timeFormat, strValue) + if err == nil { + return value, nil + } + } + return + } + unixTimestamp, err := strconv.ParseInt(strconv.Itoa(int(floatValue)), 10, 64) + value = time.Unix(unixTimestamp, 0) + + return +} + +{{/deserialize}} \ No newline at end of file diff --git a/ocaml/sdk-gen/go/test_data/batch_convert.go b/ocaml/sdk-gen/go/test_data/batch_convert.go new file mode 100644 index 00000000000..fd0e70607f6 --- /dev/null +++ b/ocaml/sdk-gen/go/test_data/batch_convert.go @@ -0,0 +1,29 @@ +func deserializeEventBatch(context string, input interface{}) (batch EventBatch, err error) { + rpcStruct, ok := input.(map[string]interface{}) + if !ok { + err = fmt.Errorf("failed to parse XenAPI response: expected Go type %s at %s but got Go type %s with value %v", "map[string]interface{}", context, reflect.TypeOf(input), input) + return + } + tokenValue, ok := rpcStruct["token"] + if ok && tokenValue != nil { + batch.Token, err = deserializeString(fmt.Sprintf("%s.%s", context, "token"), tokenValue) + if err != nil { + return + } + } + validRefCountsValue, ok := rpcStruct["validRefCounts"] + if ok && validRefCountsValue != nil { + batch.ValidRefCounts, err = deserializeStringToIntMap(fmt.Sprintf("%s.%s", context, "validRefCounts"), validRefCountsValue) + if err != nil { + return + } + } + eventsValue, ok := rpcStruct["events"] + if ok && eventsValue != nil { + batch.Events, err = deserializeEventRecordSet(fmt.Sprintf("%s.%s", context, "events"), eventsValue) + if err != nil { + return + } + } + return +} \ No newline at end of file diff --git a/ocaml/sdk-gen/go/test_data/enum_convert.go b/ocaml/sdk-gen/go/test_data/enum_convert.go new file mode 100644 index 00000000000..40129c0e5ca --- /dev/null +++ b/ocaml/sdk-gen/go/test_data/enum_convert.go @@ -0,0 +1,20 @@ +func serializeEnumTaskStatusType(context string, value TaskStatusType) (string, error) { + _ = context + return string(value), nil +} + +func deserializeEnumTaskStatusType(context string, input interface{}) (value TaskStatusType, err error) { + strValue, err := deserializeString(context, input) + if err != nil { + return + } + switch strValue { + case "pending": + value = TaskStatusTypePending + case "success": + value = TaskStatusTypeSuccess + default: + err = fmt.Errorf("unable to parse XenAPI response: got value %q for enum %s at %s, but this is not any of the known values", strValue, "TaskStatusType", context) + } + return +} \ No newline at end of file diff --git a/ocaml/sdk-gen/go/test_data/float_convert.go b/ocaml/sdk-gen/go/test_data/float_convert.go new file mode 100644 index 00000000000..736ad6f8111 --- /dev/null +++ b/ocaml/sdk-gen/go/test_data/float_convert.go @@ -0,0 +1,33 @@ +//nolint:unparam +func serializeFloat(context string, value float64) (interface{}, error) { + _ = context + if math.IsInf(value, 0) { + if math.IsInf(value, 1) { + return "+Inf", nil + } + return "-Inf", nil + } else if math.IsNaN(value) { + return "NaN", nil + } + return value, nil +} + +func deserializeFloat(context string, input interface{}) (value float64, err error) { + _ = context + if input == nil { + return + } + strValue := fmt.Sprintf("%v", input) + value, err = strconv.ParseFloat(strValue, 64) + if err != nil { + switch strValue { + case "+Inf": + return math.Inf(1), nil + case "-Inf": + return math.Inf(-1), nil + case "NaN": + return math.NaN(), nil + } + } + return +} \ No newline at end of file diff --git a/ocaml/sdk-gen/go/test_data/int_convert.go b/ocaml/sdk-gen/go/test_data/int_convert.go new file mode 100644 index 00000000000..0688dffa600 --- /dev/null +++ b/ocaml/sdk-gen/go/test_data/int_convert.go @@ -0,0 +1,20 @@ +func serializeInt(context string, value int) (int, error) { + _ = context + return value, nil +} + +func deserializeInt(context string, input interface{}) (value int, err error) { + _ = context + if input == nil { + return + } + strValue := fmt.Sprintf("%v", input) + value, err = strconv.Atoi(strValue) + if err != nil { + floatValue, err1 := strconv.ParseFloat(strValue, 64) + if err1 == nil { + return int(floatValue), nil + } + } + return +} \ No newline at end of file diff --git a/ocaml/sdk-gen/go/test_data/interface_convert.go b/ocaml/sdk-gen/go/test_data/interface_convert.go new file mode 100644 index 00000000000..fec2c91d133 --- /dev/null +++ b/ocaml/sdk-gen/go/test_data/interface_convert.go @@ -0,0 +1,5 @@ +func deserializeRecordInterface(context string, input interface{}) (inter RecordInterface, err error) { + _ = context + inter = input + return +} \ No newline at end of file diff --git a/ocaml/sdk-gen/go/test_data/map_convert.go b/ocaml/sdk-gen/go/test_data/map_convert.go new file mode 100644 index 00000000000..fff680ebc35 --- /dev/null +++ b/ocaml/sdk-gen/go/test_data/map_convert.go @@ -0,0 +1,38 @@ +func serializeVIFRefToStringMap(context string, goMap map[VIFRef]string) (xenMap map[string]interface{}, err error) { + xenMap = make(map[string]interface{}) + for goKey, goValue := range goMap { + keyContext := fmt.Sprintf("%s[%s]", context, goKey) + xenKey, err := serializeVIFRef(keyContext, goKey) + if err != nil { + return xenMap, err + } + xenValue, err := serializeString(keyContext, goValue) + if err != nil { + return xenMap, err + } + xenMap[xenKey] = xenValue + } + return +} + +func deserializePBDRefToPBDRecordMap(context string, input interface{}) (goMap map[PBDRef]PBDRecord, err error) { + xenMap, ok := input.(map[string]interface{}) + if !ok { + err = fmt.Errorf("failed to parse XenAPI response: expected Go type %s at %s but got Go type %s with value %v", "map[string]interface{}", context, reflect.TypeOf(input), input) + return + } + goMap = make(map[PBDRef]PBDRecord, len(xenMap)) + for xenKey, xenValue := range xenMap { + keyContext := fmt.Sprintf("%s[%s]", context, xenKey) + goKey, err := deserializePBDRef(keyContext, xenKey) + if err != nil { + return goMap, err + } + goValue, err := deserializePBDRecord(keyContext, xenValue) + if err != nil { + return goMap, err + } + goMap[goKey] = goValue + } + return +} \ No newline at end of file diff --git a/ocaml/sdk-gen/go/test_data/option_convert.go b/ocaml/sdk-gen/go/test_data/option_convert.go new file mode 100644 index 00000000000..4a5ce03a70b --- /dev/null +++ b/ocaml/sdk-gen/go/test_data/option_convert.go @@ -0,0 +1,22 @@ +func serializeOptionSrStatRecord(context string, input OptionSrStatRecord) (option interface{}, err error) { + if input == nil { + return + } + option, err = serializeSrStatRecord(context, *input) + if err != nil { + return + } + return +} + +func deserializeOptionSrStatRecord(context string, input interface{}) (option OptionSrStatRecord, err error) { + if input == nil { + return + } + value, err := deserializeSrStatRecord(context, input) + if err != nil { + return + } + option = &value + return +} \ No newline at end of file diff --git a/ocaml/sdk-gen/go/test_data/record_convert.go b/ocaml/sdk-gen/go/test_data/record_convert.go new file mode 100644 index 00000000000..55a8e9c3c90 --- /dev/null +++ b/ocaml/sdk-gen/go/test_data/record_convert.go @@ -0,0 +1,35 @@ +func serializeVBDRecord(context string, record VBDRecord) (rpcStruct map[string]interface{}, err error) { + rpcStruct = map[string]interface{}{} + rpcStruct["uuid"], err = serializeString(fmt.Sprintf("%s.%s", context, "uuid"), record.UUID) + if err != nil { + return + } + rpcStruct["allowed_operations"], err = serializeEnumVbdOperationsSet(fmt.Sprintf("%s.%s", context, "allowed_operations"), record.AllowedOperations) + if err != nil { + return + } + return +} + +func deserializeVBDRecord(context string, input interface{}) (record VBDRecord, err error) { + rpcStruct, ok := input.(map[string]interface{}) + if !ok { + err = fmt.Errorf("failed to parse XenAPI response: expected Go type %s at %s but got Go type %s with value %v", "map[string]interface{}", context, reflect.TypeOf(input), input) + return + } + uuidValue, ok := rpcStruct["uuid"] + if ok && uuidValue != nil { + record.UUID, err = deserializeString(fmt.Sprintf("%s.%s", context, "uuid"), uuidValue) + if err != nil { + return + } + } + allowedOperationsValue, ok := rpcStruct["allowed_operations"] + if ok && allowedOperationsValue != nil { + record.AllowedOperations, err = deserializeEnumVbdOperationsSet(fmt.Sprintf("%s.%s", context, "allowed_operations"), allowedOperationsValue) + if err != nil { + return + } + } + return +} \ No newline at end of file diff --git a/ocaml/sdk-gen/go/test_data/ref_convert.go b/ocaml/sdk-gen/go/test_data/ref_convert.go new file mode 100644 index 00000000000..dc23fc88ffa --- /dev/null +++ b/ocaml/sdk-gen/go/test_data/ref_convert.go @@ -0,0 +1,13 @@ +func serializeVMRef(context string, ref VMRef) (string, error) { + _ = context + return string(ref), nil +} + +func deserializeVMRef(context string, input interface{}) (VMRef, error) { + var ref VMRef + value, ok := input.(string) + if !ok { + return ref, fmt.Errorf("failed to parse XenAPI response: expected Go type %s at %s but got Go type %s with value %v", "string", context, reflect.TypeOf(input), input) + } + return VMRef(value), nil +} \ No newline at end of file diff --git a/ocaml/sdk-gen/go/test_data/set_convert.go b/ocaml/sdk-gen/go/test_data/set_convert.go new file mode 100644 index 00000000000..1d8adb73764 --- /dev/null +++ b/ocaml/sdk-gen/go/test_data/set_convert.go @@ -0,0 +1,30 @@ +func serializeSRRefSet(context string, slice []SRRef) (set []interface{}, err error) { + set = make([]interface{}, len(slice)) + for index, item := range slice { + itemContext := fmt.Sprintf("%s[%d]", context, index) + itemValue, err := serializeSRRef(itemContext, item) + if err != nil { + return set, err + } + set[index] = itemValue + } + return +} + +func deserializeStringSet(context string, input interface{}) (slice []string, err error) { + set, ok := input.([]interface{}) + if !ok { + err = fmt.Errorf("failed to parse XenAPI response: expected Go type %s at %s but got Go type %s with value %v", "[]interface{}", context, reflect.TypeOf(input), input) + return + } + slice = make([]string, len(set)) + for index, item := range set { + itemContext := fmt.Sprintf("%s[%d]", context, index) + itemValue, err := deserializeString(itemContext, item) + if err != nil { + return slice, err + } + slice[index] = itemValue + } + return +} \ No newline at end of file diff --git a/ocaml/sdk-gen/go/test_data/simple_type_convert.go b/ocaml/sdk-gen/go/test_data/simple_type_convert.go new file mode 100644 index 00000000000..5b482e0a5b7 --- /dev/null +++ b/ocaml/sdk-gen/go/test_data/simple_type_convert.go @@ -0,0 +1,31 @@ +func serializeString(context string, value string) (string, error) { + _ = context + return value, nil +} + +func serializeBool(context string, value bool) (bool, error) { + _ = context + return value, nil +} + +func deserializeString(context string, input interface{}) (value string, err error) { + if input == nil { + return + } + value, ok := input.(string) + if !ok { + err = fmt.Errorf("failed to parse XenAPI response: expected Go type %s at %s but got Go type %s with value %v", "string", context, reflect.TypeOf(input), input) + } + return +} + +func deserializeBool(context string, input interface{}) (value bool, err error) { + if input == nil { + return + } + value, ok := input.(bool) + if !ok { + err = fmt.Errorf("failed to parse XenAPI response: expected Go type %s at %s but got Go type %s with value %v", "bool", context, reflect.TypeOf(input), input) + } + return +} \ No newline at end of file diff --git a/ocaml/sdk-gen/go/test_data/time_convert.go b/ocaml/sdk-gen/go/test_data/time_convert.go new file mode 100644 index 00000000000..d6da10f4d42 --- /dev/null +++ b/ocaml/sdk-gen/go/test_data/time_convert.go @@ -0,0 +1,29 @@ +var timeFormats = []string{time.RFC3339, "20060102T15:04:05Z", "20060102T15:04:05"} + +//nolint:unparam +func serializeTime(context string, value time.Time) (string, error) { + _ = context + return value.Format(time.RFC3339), nil +} + +func deserializeTime(context string, input interface{}) (value time.Time, err error) { + _ = context + if input == nil { + return + } + strValue := fmt.Sprintf("%v", input) + floatValue, err := strconv.ParseFloat(strValue, 64) + if err != nil { + for _, timeFormat := range timeFormats { + value, err = time.Parse(timeFormat, strValue) + if err == nil { + return value, nil + } + } + return + } + unixTimestamp, err := strconv.ParseInt(strconv.Itoa(int(floatValue)), 10, 64) + value = time.Unix(unixTimestamp, 0) + + return +} \ No newline at end of file diff --git a/ocaml/sdk-gen/go/test_gen_go.ml b/ocaml/sdk-gen/go/test_gen_go.ml index 4767b0c05ec..e9800941ea2 100644 --- a/ocaml/sdk-gen/go/test_gen_go.ml +++ b/ocaml/sdk-gen/go/test_gen_go.ml @@ -329,6 +329,12 @@ let verify_msgs_or_errors lst = in List.for_all verify_msg_or_error lst +let verify_simple_convert_member = function + | "func_name_suffix", `String _ | "type", `String _ -> + true + | _ -> + false + let verify_release_member = function | "branding", `String _ | "code_name", `String _ -> true @@ -341,6 +347,126 @@ let verify_release_member = function | _ -> false +let verify_simple_convert_keys = ["func_name_suffix"; "type"] + +let verify_simple_convert = function + | `O items -> + schema_check verify_simple_convert_keys verify_simple_convert_member items + | _ -> + false + +let verify_option_convert_member = function + | "func_name_suffix", `String _ -> + true + | _ -> + false + +let option_convert_keys = ["func_name_suffix"] + +let verify_option_convert = function + | `O items -> + schema_check option_convert_keys verify_option_convert_member items + | _ -> + false + +let verify_set_convert_member = function + | "func_name_suffix", `String _ + | "type", `String _ + | "item_func_suffix", `String _ -> + true + | _ -> + false + +let convert_set_keys = ["func_name_suffix"; "type"; "item_func_suffix"] + +let verify_set_convert = function + | `O items -> + schema_check convert_set_keys verify_set_convert_member items + | _ -> + false + +let record_field_keys = + ["name"; "name_internal"; "name_exported"; "func_name_suffix"; "type_option"] + +let verify_record_field_member = function + | "name", `String _ + | "name_internal", `String _ + | "func_name_suffix", `String _ + | "type_option", `Bool _ + | "name_exported", `String _ -> + true + | _ -> + false + +let verify_record_field = function + | `O items -> + schema_check record_field_keys verify_record_field_member items + | _ -> + false + +let verify_record_convert_member = function + | "func_name_suffix", `String _ | "type", `String _ -> + true + | "fields", `A fields -> + List.for_all verify_record_field fields + | _ -> + false + +let convert_record_keys = ["func_name_suffix"; "type"; "fields"] + +let verify_record_convert = function + | `O items -> + schema_check convert_record_keys verify_record_convert_member items + | _ -> + false + +let enum_item_keys = ["value"; "name"] + +let verify_enum_item_member = function + | "name", `String _ | "value", `String _ -> + true + | _ -> + false + +let verify_enum_item = function + | `O members -> + schema_check enum_item_keys verify_enum_item_member members + | _ -> + false + +let enum_convert_keys = ["func_name_suffix"; "type"; "items"] + +let verify_enum_convert_member = function + | "func_name_suffix", `String _ | "type", `String _ -> + true + | "items", `A items -> + List.for_all verify_enum_item items + | _ -> + false + +let verify_enum_convert = function + | `O items -> + schema_check enum_convert_keys verify_enum_convert_member items + | _ -> + false + +let map_convert_keys = ["func_name_suffix"; "type"; "key_type"; "value_type"] + +let verify_map_convert_member = function + | "type", `String _ + | "key_type", `String _ + | "func_name_suffix", `String _ + | "value_type", `String _ -> + true + | _ -> + false + +let verify_map_convert = function + | `O items -> + schema_check map_convert_keys verify_map_convert_member items + | _ -> + false + let release_keys = [ "branding" @@ -527,6 +653,151 @@ let api_messages : Mustache.Json.t = ) ] +let simple_type_convert : Mustache.Json.t = + let array = + [ + `O [("func_name_suffix", `String "String"); ("type", `String "string")] + ; `O [("func_name_suffix", `String "Bool"); ("type", `String "bool")] + ] + in + `O [("serialize", `A array); ("deserialize", `A array)] + +let int_convert : Mustache.Json.t = + let array = + [`O [("func_name_suffix", `String "Int"); ("type", `String "int")]] + in + `O [("serialize", `A array); ("deserialize", `A array)] + +let float_convert : Mustache.Json.t = + let array = + [`O [("func_name_suffix", `String "Float"); ("type", `String "float64")]] + in + `O [("serialize", `A array); ("deserialize", `A array)] + +let time_convert : Mustache.Json.t = + let array = + [`O [("func_name_suffix", `String "Time"); ("type", `String "time.Time")]] + in + `O [("serialize", `A array); ("deserialize", `A array)] + +let ref_string_convert : Mustache.Json.t = + let array = + [`O [("func_name_suffix", `String "VMRef"); ("type", `String "VMRef")]] + in + `O [("serialize", `A array); ("deserialize", `A array)] + +let set_convert : Mustache.Json.t = + let serialize = + [ + `O + [ + ("func_name_suffix", `String "SRRefSet") + ; ("type", `String "SRRef") + ; ("item_func_suffix", `String "SRRef") + ] + ] + in + let deserialize = + [ + `O + [ + ("func_name_suffix", `String "StringSet") + ; ("type", `String "string") + ; ("item_func_suffix", `String "String") + ] + ] + in + `O [("serialize", `A serialize); ("deserialize", `A deserialize)] + +let record_convert : Mustache.Json.t = + let array = + [ + `O + [ + ("func_name_suffix", `String "VBDRecord") + ; ("type", `String "VBDRecord") + ; ( "fields" + , `A + [ + `O + [ + ("name", `String "uuid") + ; ("name_internal", `String "uuid") + ; ("name_exported", `String "UUID") + ; ("func_name_suffix", `String "String") + ; ("type_option", `Bool false) + ] + ; `O + [ + ("name", `String "allowed_operations") + ; ("name_internal", `String "allowedOperations") + ; ("name_exported", `String "AllowedOperations") + ; ("func_name_suffix", `String "EnumVbdOperationsSet") + ; ("type_option", `Bool false) + ] + ] + ) + ] + ] + in + `O [("serialize", `A array); ("deserialize", `A array)] + +let map_convert : Mustache.Json.t = + let deserialize = + [ + `O + [ + ("func_name_suffix", `String "PBDRefToPBDRecordMap") + ; ("type", `String "map[PBDRef]PBDRecord") + ; ("key_type", `String "PBDRef") + ; ("value_type", `String "PBDRecord") + ] + ] + in + let serialize = + [ + `O + [ + ("func_name_suffix", `String "VIFRefToStringMap") + ; ("type", `String "map[VIFRef]string") + ; ("key_type", `String "VIFRef") + ; ("value_type", `String "String") + ] + ] + in + `O [("serialize", `A serialize); ("deserialize", `A deserialize)] + +let enum_convert : Mustache.Json.t = + let array = + [ + `O + [ + ("func_name_suffix", `String "EnumTaskStatusType") + ; ("type", `String "TaskStatusType") + ; ( "items" + , `A + [ + `O + [ + ("name", `String "TaskStatusTypePending") + ; ("value", `String "pending") + ] + ; `O + [ + ("name", `String "TaskStatusTypeSuccess") + ; ("value", `String "success") + ] + ] + ) + ] + ] + in + `O [("serialize", `A array); ("deserialize", `A array)] + +let option_convert : Mustache.Json.t = + let array = [`O [("func_name_suffix", `String "SrStatRecord")]] in + `O [("serialize", `A array); ("deserialize", `A array)] + let api_versions : Mustache.Json.t = `O [ @@ -767,6 +1038,30 @@ module TemplatesTest = Generic.MakeStateless (struct let api_messages_rendered = string_of_file "api_messages.go" + let simple_type_rendered = string_of_file "simple_type_convert.go" + + let int_convert_rendered = string_of_file "int_convert.go" + + let float_convert_rendered = string_of_file "float_convert.go" + + let time_convert_rendered = string_of_file "time_convert.go" + + let string_ref_rendered = string_of_file "ref_convert.go" + + let set_convert_rendered = string_of_file "set_convert.go" + + let record_convert_rendered = string_of_file "record_convert.go" + + let interface_convert_rendered = string_of_file "interface_convert.go" + + let map_convert_rendered = string_of_file "map_convert.go" + + let enum_convert_rendered = string_of_file "enum_convert.go" + + let batch_convert_rendered = string_of_file "batch_convert.go" + + let option_convert_rendered = string_of_file "option_convert.go" + let api_versions_rendered = string_of_file "api_versions.go" let option_rendered = "type OptionString *string" @@ -781,6 +1076,22 @@ module TemplatesTest = Generic.MakeStateless (struct ; (("SessionMethod.mustache", session_messages), session_method_rendered) ; (("APIErrors.mustache", api_errors), api_errors_rendered) ; (("APIMessages.mustache", api_messages), api_messages_rendered) + ; ( ("ConvertSimpleType.mustache", simple_type_convert) + , simple_type_rendered + ) + ; (("ConvertInt.mustache", int_convert), int_convert_rendered) + ; (("ConvertFloat.mustache", float_convert), float_convert_rendered) + ; (("ConvertTime.mustache", time_convert), time_convert_rendered) + ; (("ConvertRef.mustache", ref_string_convert), string_ref_rendered) + ; (("ConvertSet.mustache", set_convert), set_convert_rendered) + ; (("ConvertRecord.mustache", record_convert), record_convert_rendered) + ; ( ("ConvertInterface.mustache", Convert.interface) + , interface_convert_rendered + ) + ; (("ConvertMap.mustache", map_convert), map_convert_rendered) + ; (("ConvertEnum.mustache", enum_convert), enum_convert_rendered) + ; (("ConvertBatch.mustache", Convert.event_batch), batch_convert_rendered) + ; (("ConvertOption.mustache", option_convert), option_convert_rendered) ; (("APIVersions.mustache", api_versions), api_versions_rendered) ; (("Option.mustache", option), option_rendered) ] @@ -845,6 +1156,69 @@ module SuffixOfTypeTest = Generic.MakeStateless (struct ] end) +module TestConvertGeneratedJson = struct + open Convert + + let verify description verify_func actual = + Alcotest.(check bool) description true (verify_func actual) + + let param_types = TypesOfMessages.of_params objects + + let result_types = TypesOfMessages.of_results objects + + let verify_func = function + | Simple _ | Int _ | Float _ | Time _ | Ref _ -> + verify_simple_convert + | Option _ -> + verify_option_convert + | Set _ -> + verify_set_convert + | Record _ -> + verify_record_convert + | Enum _ -> + verify_enum_convert + | Map _ -> + verify_map_convert + + let convert_param_name = function + | Simple _ -> + "simple" + | Int _ -> + "int" + | Float _ -> + "float" + | Time _ -> + "time" + | Ref _ -> + "ref" + | Option _ -> + "option" + | Set _ -> + "set" + | Record _ -> + "record" + | Enum _ -> + "enum" + | Map _ -> + "map" + + let test types () = + List.iter + (fun ty -> + let param = Convert.of_ty ty in + let obj = Convert.to_json param in + let verify_func = verify_func param in + verify (convert_param_name param) verify_func obj + ) + types + + let tests = + [ + ("serialize", `Quick, test param_types) + ; ("deserialize", `Quick, test result_types) + ] +end + module StringOfTyWithEnumsTest = struct open Datamodel_types module StringMap = Json.StringMap @@ -942,6 +1316,7 @@ let tests = ; ("string_of_ty_with_enums", StringOfTyWithEnumsTest.tests) ; ("templates", TemplatesTest.tests) ; ("generated_mustache_jsons", TestGeneratedJson.tests) + ; ("generated_convert_jsons", TestConvertGeneratedJson.tests) ] let () = Alcotest.run "Gen go binding" tests