Mercurial > hg > orthanc-stone
diff Deprecated/Resources/CodeGeneration/stonegentool_test.py @ 1401:f6a2d46d2b76
moved CodeGeneration into Deprecated
author | Alain Mazy <alain@mazy.be> |
---|---|
date | Wed, 29 Apr 2020 20:48:18 +0200 |
parents | Resources/CodeGeneration/stonegentool_test.py@342f3e04bfa9 |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Deprecated/Resources/CodeGeneration/stonegentool_test.py Wed Apr 29 20:48:18 2020 +0200 @@ -0,0 +1,438 @@ +# +# 1 2 3 4 5 6 7 8 +# 345678901234567890123456789012345678901234567890123456789012345678901234567890 +# + +from stonegentool import \ +EatToken,SplitListOfTypes,ParseTemplateType,ProcessSchema, \ +CheckSchemaSchema,LoadSchema,trim,ComputeRequiredDeclarationOrder, \ +GetTemplatingDictFromSchemaFilename,MakeTemplate,MakeTemplateFromFile,LoadSchemaFromString,GetTemplatingDictFromSchema +import unittest +import os +import re +import pprint +from jinja2 import Template + +def RemoveDateTimeLine(s : str): + # regex are non-multiline by default, and $ does NOT match the end of the line + s2 = re.sub(r"^// autogenerated by stonegentool on .*\n","",s) + return s2 + +class TestStonegentool(unittest.TestCase): + def test_EatToken_empty(self): + c = r"" + a,b = EatToken(c) + self.assertEqual(a,r"") + self.assertEqual(b,r"") + + def test_EatToken_simpleNonTemplate(self): + c = r"int32" + a,b = EatToken(c) + self.assertEqual(a,r"int32") + self.assertEqual(b,r"") + + def test_EatToken_simpleTemplate(self): + c = r"vector<string>" + a,b = EatToken(c) + self.assertEqual(a,r"vector<string>") + self.assertEqual(b,r"") + + def test_EatToken_complexTemplate(self): + c = r"vector<map<int64,string>>,vector<map<int32,string>>" + a,b = EatToken(c) + self.assertEqual(a,r"vector<map<int64,string>>") + self.assertEqual(b,r"vector<map<int32,string>>") + + def test_EatToken_complexTemplates(self): + c = r"vector<map<vector<string>,map<int32,string>>>,map<int32,string>,map<map<int32,string>,string>" + a,b = EatToken(c) + self.assertEqual(a,r"vector<map<vector<string>,map<int32,string>>>") + self.assertEqual(b,r"map<int32,string>,map<map<int32,string>,string>") + a,b = EatToken(b) + self.assertEqual(a,r"map<int32,string>") + self.assertEqual(b,r"map<map<int32,string>,string>") + + def test_SplitListOfTypes(self): + c = r"vector<map<vector<string>,map<int32,string>>>,map<int32,string>,map<map<int32,string>,string>" + lot = SplitListOfTypes(c) + self.assertEqual(3,len(lot)) + self.assertEqual("vector<map<vector<string>,map<int32,string>>>",lot[0]) + self.assertEqual("map<int32,string>",lot[1]) + self.assertEqual("map<map<int32,string>,string>",lot[2]) + + def test_SplitListOfTypes_bogus(self): + c = r"vector<map<vector<string>,map<int32,string>>,map<int32,string>,map<map<int32,string>,string" + self.assertRaises(Exception,SplitListOfTypes,c) # the argument c must be passed to assertRaises, not as a normal call of SplitListOfTypes + + def test_ParseTemplateType_true(self): + c = "map<vector<map<int,vector<string>>>,map<vector<int>,vector<string>>>" + (ok,a,b) = ParseTemplateType(c) + self.assertEqual(ok,True) + self.assertEqual(a,"map") + self.assertEqual(b,["vector<map<int,vector<string>>>","map<vector<int>,vector<string>>"]) + + (ok2,a2,b2) = ParseTemplateType(b[0]) + self.assertEqual(ok2,True) + self.assertEqual(a2,"vector") + self.assertEqual(b2,["map<int,vector<string>>"]) + + (ok3,a3,b3) = ParseTemplateType(b[1]) + self.assertEqual(ok3,True) + self.assertEqual(a3,"map") + self.assertEqual(b3,["vector<int>","vector<string>"]) + + (ok4,a4,b4) = ParseTemplateType(b2[0]) + self.assertEqual(ok4,True) + self.assertEqual(a4,"map") + self.assertEqual(b4,["int","vector<string>"]) + + def test_ParseSchema(self): + fn = os.path.join(os.path.dirname(__file__), 'test_data', 'testTestStoneCodeGen.yaml') + obj = LoadSchema(fn) + # we're happy if it does not crash :) + CheckSchemaSchema(obj) + + def test_ComputeRequiredDeclarationOrder(self): + fn = os.path.join(os.path.dirname(__file__), 'test_data', 'testTestStoneCodeGen.yaml') + obj = LoadSchema(fn) + genOrder: str = ComputeRequiredDeclarationOrder(obj) + self.assertEqual(5,len(genOrder)) + self.assertEqual("A",genOrder[0]) + self.assertEqual("B",genOrder[1]) + self.assertEqual("C",genOrder[2]) + self.assertEqual("Message1",genOrder[3]) + self.assertEqual("Message2",genOrder[4]) + + # def test_GeneratePreambleEnumerationAndStructs(self): + # fn = os.path.join(os.path.dirname(__file__), 'test', 'test1.jsonc') + # obj = LoadSchema(fn) + # (_,genc,_) = ProcessSchema(obj) + + def test_genEnums(self): + self.maxDiff = None + fn = os.path.join(os.path.dirname(__file__), 'test_data', 'testTestStoneCodeGen.yaml') + obj = LoadSchema(fn) + genOrder: str = ComputeRequiredDeclarationOrder(obj) + processedSchema = ProcessSchema(obj, genOrder) + self.assertTrue('rootName' in processedSchema) + + structs = {} + for v in processedSchema['structs']: + structs[v['name']] = v + enums = {} + for v in processedSchema['enums']: + enums[v['name']] = v + + self.assertTrue('C' in structs) + self.assertTrue('someBs' in structs['C']['fields']) + self.assertTrue('CrispType' in enums) + self.assertTrue('Message1' in structs) + self.assertEqual('int32', structs['Message1']['fields']['memberInt32'].type) + self.assertEqual('string', structs['Message1']['fields']['memberString'].type) + self.assertEqual('EnumMonth0', structs['Message1']['fields']['memberEnumMonth'].type) + self.assertEqual('bool', structs['Message1']['fields']['memberBool'].type) + self.assertEqual('float32', structs['Message1']['fields']['memberFloat32'].type) + self.assertEqual('float64', structs['Message1']['fields']['memberFloat64'].type) + + def test_GenerateTypeScriptEnums(self): + fn = os.path.join(os.path.dirname(__file__), 'test_data', 'testTestStoneCodeGen.yaml') + tdico = GetTemplatingDictFromSchemaFilename(fn) + template = Template(""" // end of generic methods +{% for enum in enums%} export enum {{enum['name']}} { +{% for key in enum['fields']%} {{key}}, +{%endfor%} }; + +{%endfor%}""") + renderedCode = template.render(**tdico) + renderedCodeRef = """ // end of generic methods + export enum MovieType { + RomCom, + Horror, + ScienceFiction, + Vegetables, + }; + + export enum CrispType { + SaltAndPepper, + CreamAndChives, + Paprika, + Barbecue, + }; + + export enum EnumMonth0 { + January, + February, + March, + }; + +""" + self.assertEqual(renderedCodeRef,renderedCode) + + def test_GenerateCplusplusEnums(self): + fn = os.path.join(os.path.dirname(__file__), 'test_data', 'testTestStoneCodeGen.yaml') + tdico = GetTemplatingDictFromSchemaFilename(fn) + template = Template(""" // end of generic methods +{% for enum in enums%} enum {{enum['name']}} { +{% for key in enum['fields']%} {{key}}, +{%endfor%} }; + +{%endfor%}""") + renderedCode = template.render(**tdico) + renderedCodeRef = """ // end of generic methods + enum MovieType { + RomCom, + Horror, + ScienceFiction, + Vegetables, + }; + + enum CrispType { + SaltAndPepper, + CreamAndChives, + Paprika, + Barbecue, + }; + + enum EnumMonth0 { + January, + February, + March, + }; + +""" + self.assertEqual(renderedCodeRef,renderedCode) + + def test_generateTsStructType(self): + fn = os.path.join(os.path.dirname(__file__), 'test_data', 'testTestStoneCodeGen.yaml') + tdico = GetTemplatingDictFromSchemaFilename(fn) + +# template = MakeTemplate(""" // end of generic methods +# {% for struct in struct%} export class {{struct['name']}} { +# {% for key in struct['fields']%} {{key}}:{{struct['fields'][key]}}, +# {% endfor %} +# constructor() { +# {% for key in struct['fields']%} +# {% if NeedsConstruction(struct['fields']['key'])} +# {{key}} = new {{CanonToTs(struct['fields']['key'])}}; +# {% end if %} +# {% endfor %} +# } +# {% endfor %} +# public StoneSerialize(): string { +# let container: object = {}; +# container['type'] = '{{rootName}}.{{struct['name']}}'; +# container['value'] = this; +# return JSON.stringify(container); +# } };""") + template = MakeTemplate(""" // end of generic methods +{% for struct in structs%} export class {{struct['name']}} { +{% for key in struct['fields']%} {{key}}:{{CanonToTs(struct['fields'][key]['type'])}}; +{% endfor %} + constructor() { +{% for key in struct['fields']%} this.{{key}} = new {{CanonToTs(struct['fields'][key]['type'])}}(); +{% endfor %} } + + public StoneSerialize(): string { + let container: object = {}; + container['type'] = '{{rootName}}.{{struct['name']}}'; + container['value'] = this; + return JSON.stringify(container); + } + }; + +{% endfor %}""") + renderedCode = template.render(**tdico) + renderedCodeRef = """ // end of generic methods + export class A { + someStrings:Array<string>; + someInts2:Array<number>; + movies:Array<MovieType>; + + constructor() { + this.someStrings = new Array<string>(); + this.someInts2 = new Array<number>(); + this.movies = new Array<MovieType>(); + } + + public StoneSerialize(): string { + let container: object = {}; + container['type'] = 'TestStoneCodeGen.A'; + container['value'] = this; + return JSON.stringify(container); + } + }; + + export class B { + someAs:Array<A>; + someInts:Array<number>; + + constructor() { + this.someAs = new Array<A>(); + this.someInts = new Array<number>(); + } + + public StoneSerialize(): string { + let container: object = {}; + container['type'] = 'TestStoneCodeGen.B'; + container['value'] = this; + return JSON.stringify(container); + } + }; + + export class C { + someBs:Array<B>; + ddd:Array<string>; + + constructor() { + this.someBs = new Array<B>(); + this.ddd = new Array<string>(); + } + + public StoneSerialize(): string { + let container: object = {}; + container['type'] = 'TestStoneCodeGen.C'; + container['value'] = this; + return JSON.stringify(container); + } + }; + + export class Message1 { + memberInt32:number; + memberString:string; + memberEnumMonth:EnumMonth0; + memberBool:boolean; + memberFloat32:number; + memberFloat64:number; + + constructor() { + this.memberInt32 = new number(); + this.memberString = new string(); + this.memberEnumMonth = new EnumMonth0(); + this.memberBool = new boolean(); + this.memberFloat32 = new number(); + this.memberFloat64 = new number(); + } + + public StoneSerialize(): string { + let container: object = {}; + container['type'] = 'TestStoneCodeGen.Message1'; + container['value'] = this; + return JSON.stringify(container); + } + }; + + export class Message2 { + memberString:string; + memberStringWithDefault:string; + memberVectorOfMessage1:Array<Message1>; + memberVectorOfString:Array<string>; + memberMapStringString:Map<string, string>; + memberMapStringStruct:Map<string, Message1>; + memberMapEnumFloat:Map<CrispType, number>; + memberEnumMovieType:MovieType; + memberJson:Object; + + constructor() { + this.memberString = new string(); + this.memberStringWithDefault = new string(); + this.memberVectorOfMessage1 = new Array<Message1>(); + this.memberVectorOfString = new Array<string>(); + this.memberMapStringString = new Map<string, string>(); + this.memberMapStringStruct = new Map<string, Message1>(); + this.memberMapEnumFloat = new Map<CrispType, number>(); + this.memberEnumMovieType = new MovieType(); + this.memberJson = new Object(); + } + + public StoneSerialize(): string { + let container: object = {}; + container['type'] = 'TestStoneCodeGen.Message2'; + container['value'] = this; + return JSON.stringify(container); + } + }; + +""" + # print(renderedCode) + self.maxDiff = None + self.assertEqual(renderedCodeRef, renderedCode) + + def test_generateWholeTsFile(self): + schemaFile = \ + os.path.join(os.path.dirname(__file__), 'test_data', 'testTestStoneCodeGen.yaml') + tdico = GetTemplatingDictFromSchemaFilename(schemaFile) + tsTemplateFile = \ + os.path.join(os.path.dirname(__file__), 'template.in.ts.j2') + template = MakeTemplateFromFile(tsTemplateFile) + renderedCode = template.render(**tdico) + print(renderedCode) + + def test_GenerateTypeScriptHandlerInterface(self): + pass + + def test_GenerateCppHandlerInterface(self): + pass + + def test_GenerateTypeScriptDispatcher(self): + pass + + def test_GenerateCppDispatcher(self): + pass + + def test_StringDefaultValueInTs(self): + schema = LoadSchemaFromString(""" + rootName: MyTest + struct Toto: + withoutDefault: string + withDefault: string = \"tutu\" + """) + tdico = GetTemplatingDictFromSchema(schema) + + tsTemplateFile = os.path.join(os.path.dirname(__file__), 'template.in.ts.j2') + template = MakeTemplateFromFile(tsTemplateFile) + renderedCode = template.render(**tdico) + self.assertIn("withDefault = \"tutu\"", renderedCode) + # print(renderedCode) + + cppTemplateFile = os.path.join(os.path.dirname(__file__), 'template.in.h.j2') + template = MakeTemplateFromFile(cppTemplateFile) + renderedCode = template.render(**tdico) + print(renderedCode) + self.assertIn("withDefault = \"tutu\"", renderedCode) + + + def test_EnumDefaultValue(self): + schema = LoadSchemaFromString(""" + rootName: MyTest + enum MyEnum: + - Toto + - Tutu + struct Toto: + withoutDefault: MyEnum + withDefault: MyEnum = Toto + """) + tdico = GetTemplatingDictFromSchema(schema) + + tsTemplateFile = os.path.join(os.path.dirname(__file__), 'template.in.ts.j2') + template = MakeTemplateFromFile(tsTemplateFile) + renderedCode = template.render(**tdico) + # print(renderedCode) + self.assertIn("withDefault = MyEnum.Toto", renderedCode) + + tsTemplateFile = os.path.join(os.path.dirname(__file__), 'template.in.h.j2') + template = MakeTemplateFromFile(tsTemplateFile) + renderedCode = template.render(**tdico) + self.assertIn("withDefault = MyTest::MyEnum_Toto", renderedCode) + # print(renderedCode) + + +# def test(self): +# s = 'hello world' +# self.assertEqual(s.split(), ['hello', 'world']) +# # check that s.split fails when the separator is not a string +# with self.assertRaises(TypeError): +# s.split(2) + +if __name__ == '__main__': + unittest.main() +