mirror of
https://github.com/github/codeql.git
synced 2025-12-16 16:53:25 +01:00
This switched `codegen` from the `autopep8` formatting to the `black` one, and applies it to `bulk_mad_generator.py` as well. We can enroll more python scripts to it in the future.
362 lines
9.8 KiB
Python
362 lines
9.8 KiB
Python
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<MyClassTag>"),
|
|
],
|
|
)
|
|
@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<ATag>"),
|
|
cpp.Field("y", "TrapLabel<BOrNoneTag>"),
|
|
],
|
|
),
|
|
]
|
|
|
|
|
|
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:]))
|