import sys from misc.codegen.generators import cppgen from misc.codegen.lib import cpp from misc.codegen.test.utils import * output_dir = pathlib.Path("path", "to", "output") @pytest.fixture def generate_grouped(opts, renderer, input): opts.cpp_output = output_dir def ret(classes): input.classes = {cls.name: cls for cls in classes} generated = run_generation(cppgen.generate, opts, renderer) for f, g in generated.items(): assert isinstance(g, cpp.ClassList), f assert g.include_parent is (f.parent != output_dir) assert f.name == "TrapClasses", f return { str(f.parent.relative_to(output_dir)): g.classes for f, g in generated.items() } return ret @pytest.fixture def generate(generate_grouped): def ret(classes): generated = generate_grouped(classes) assert set(generated) == {"."} return generated["."] return ret def test_empty(generate): assert generate([]) == [] def test_empty_class(generate): assert generate( [ schema.Class(name="MyClass"), ] ) == [cpp.Class(name="MyClass", final=True, trap_name="MyClasses")] def test_two_class_hierarchy(generate): base = cpp.Class(name="A") assert generate( [ schema.Class(name="A", derived={"B"}), schema.Class(name="B", bases=["A"]), ] ) == [ base, cpp.Class(name="B", bases=[base], final=True, trap_name="Bs"), ] @pytest.mark.parametrize( "type,expected", [ ("a", "a"), ("string", "std::string"), ("boolean", "bool"), ("MyClass", "TrapLabel"), ], ) @pytest.mark.parametrize( "property_cls,optional,repeated,unordered,trap_name", [ (schema.SingleProperty, False, False, False, None), (schema.OptionalProperty, True, False, False, "MyClassProps"), (schema.RepeatedProperty, False, True, False, "MyClassProps"), (schema.RepeatedOptionalProperty, True, True, False, "MyClassProps"), (schema.RepeatedUnorderedProperty, False, True, True, "MyClassProps"), ], ) def test_class_with_field( generate, type, expected, property_cls, optional, repeated, unordered, trap_name ): assert generate( [ schema.Class(name="MyClass", properties=[property_cls("prop", type)]), ] ) == [ cpp.Class( name="MyClass", fields=[ cpp.Field( "prop", expected, is_optional=optional, is_repeated=repeated, is_unordered=unordered, trap_name=trap_name, ) ], trap_name="MyClasses", final=True, ) ] def test_class_field_with_null(generate, input): input.null = "Null" a = cpp.Class(name="A") assert generate( [ schema.Class(name="A", derived={"B"}), schema.Class( name="B", bases=["A"], properties=[ schema.SingleProperty("x", "A"), schema.SingleProperty("y", "B"), ], ), ] ) == [ a, cpp.Class( name="B", bases=[a], final=True, trap_name="Bs", fields=[ cpp.Field("x", "TrapLabel"), cpp.Field("y", "TrapLabel"), ], ), ] def test_class_with_predicate(generate): assert generate( [ schema.Class(name="MyClass", properties=[schema.PredicateProperty("prop")]), ] ) == [ cpp.Class( name="MyClass", fields=[ cpp.Field("prop", "bool", trap_name="MyClassProp", is_predicate=True) ], trap_name="MyClasses", final=True, ) ] @pytest.mark.parametrize( "name", [ "start_line", "start_column", "end_line", "end_column", "index", "num_whatever", "width", ], ) def test_class_with_overridden_unsigned_field(generate, name): assert generate( [ schema.Class( name="MyClass", properties=[schema.SingleProperty(name, "bar")] ), ] ) == [ cpp.Class( name="MyClass", fields=[cpp.Field(name, "unsigned")], trap_name="MyClasses", final=True, ) ] def test_class_with_overridden_underscore_field(generate): assert generate( [ schema.Class( name="MyClass", properties=[schema.SingleProperty("something_", "bar")] ), ] ) == [ cpp.Class( name="MyClass", fields=[cpp.Field("something", "bar")], trap_name="MyClasses", final=True, ) ] @pytest.mark.parametrize("name", cpp.cpp_keywords) def test_class_with_keyword_field(generate, name): assert generate( [ schema.Class( name="MyClass", properties=[schema.SingleProperty(name, "bar")] ), ] ) == [ cpp.Class( name="MyClass", fields=[cpp.Field(name + "_", "bar")], trap_name="MyClasses", final=True, ) ] def test_classes_with_dirs(generate_grouped): cbase = cpp.Class(name="CBase") assert generate_grouped( [ schema.Class(name="A"), schema.Class(name="B", pragmas={"group": "foo"}), schema.Class(name="CBase", derived={"C"}, pragmas={"group": "bar"}), schema.Class(name="C", bases=["CBase"], pragmas={"group": "bar"}), schema.Class(name="D", pragmas={"group": "foo/bar/baz"}), ] ) == { ".": [cpp.Class(name="A", trap_name="As", final=True)], "foo": [cpp.Class(name="B", trap_name="Bs", final=True)], "bar": [cbase, cpp.Class(name="C", bases=[cbase], trap_name="Cs", final=True)], "foo/bar/baz": [cpp.Class(name="D", trap_name="Ds", final=True)], } def test_cpp_skip_pragma(generate): assert generate( [ schema.Class( name="A", properties=[ schema.SingleProperty("x", "foo"), schema.SingleProperty("y", "bar", pragmas=["x", "cpp_skip", "y"]), ], ) ] ) == [ cpp.Class( name="A", final=True, trap_name="As", fields=[ cpp.Field("x", "foo"), ], ), ] def test_synth_classes_ignored(generate): assert generate( [ schema.Class( name="W", pragmas={"synth": schema.SynthInfo()}, ), schema.Class( name="X", pragmas={"synth": schema.SynthInfo(from_class="A")}, ), schema.Class( name="Y", pragmas={ "synth": schema.SynthInfo(on_arguments={"a": "A", "b": "int"}) }, ), schema.Class( name="Z", ), ] ) == [ cpp.Class(name="Z", final=True, trap_name="Zs"), ] def test_synth_properties_ignored(generate): assert generate( [ schema.Class( name="X", properties=[ schema.SingleProperty("x", "a"), schema.SingleProperty("y", "b", synth=True), schema.SingleProperty("z", "c"), schema.OptionalProperty("foo", "bar", synth=True), schema.RepeatedProperty("baz", "bazz", synth=True), schema.RepeatedOptionalProperty("bazzz", "bazzzz", synth=True), schema.RepeatedUnorderedProperty("bazzzzz", "bazzzzzz", synth=True), ], ), ] ) == [ cpp.Class( name="X", final=True, trap_name="Xes", fields=[ cpp.Field("x", "a"), cpp.Field("z", "c"), ], ), ] def test_properties_with_custom_db_table_names(generate): assert generate( [ schema.Class( "Obj", properties=[ schema.OptionalProperty( "x", "a", pragmas={"ql_db_table_name": "foo"} ), schema.RepeatedProperty( "y", "b", pragmas={"ql_db_table_name": "bar"} ), schema.RepeatedOptionalProperty( "z", "c", pragmas={"ql_db_table_name": "baz"} ), schema.PredicateProperty( "p", pragmas={"ql_db_table_name": "hello"} ), schema.RepeatedUnorderedProperty( "q", "d", pragmas={"ql_db_table_name": "world"} ), ], ), ] ) == [ cpp.Class( name="Obj", final=True, trap_name="Objs", fields=[ cpp.Field("x", "a", is_optional=True, trap_name="Foo"), cpp.Field("y", "b", is_repeated=True, trap_name="Bar"), cpp.Field( "z", "c", is_repeated=True, is_optional=True, trap_name="Baz" ), cpp.Field("p", "bool", is_predicate=True, trap_name="Hello"), cpp.Field( "q", "d", is_repeated=True, is_unordered=True, trap_name="World" ), ], ), ] if __name__ == "__main__": sys.exit(pytest.main([__file__] + sys.argv[1:]))