view Resources/CodeGeneration/stonegentool_test.py @ 1327:4f8db2d202c8 broker

OrthancSeriesProgressiveLoader now has two modes that can be selected at object creation : - progressive (will first load jpeg50, then jpeg90 then PAM) - non-progressive (will directly load PAM (uncompressed)) Please note that the slice loading order remains dynamic and depending upon the slice that the client code wishes to extract from the volume.
author Benjamin Golinvaux <bgo@osimis.io>
date Wed, 25 Mar 2020 14:34:27 +0100
parents 342f3e04bfa9
children
line wrap: on
line source

#
#        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()