Swift: implement @ql.hideable

This commit is contained in:
Paolo Tranquilli
2023-05-23 09:37:55 +02:00
parent 7dd18ff801
commit a087fef335
8 changed files with 112 additions and 74 deletions

View File

@@ -102,7 +102,7 @@ def _get_doc(cls: schema.Class, prop: schema.Property, plural=None):
return f"{prop_name} of this {class_name}"
def get_ql_property(cls: schema.Class, prop: schema.Property, prev_child: str = "") -> ql.Property:
def get_ql_property(cls: schema.Class, prop: schema.Property, lookup: typing.Dict[str, schema.Class], prev_child: str = "") -> ql.Property:
args = dict(
type=prop.type if not prop.is_predicate else "predicate",
qltest_skip="qltest_skip" in prop.pragmas,
@@ -110,7 +110,8 @@ def get_ql_property(cls: schema.Class, prop: schema.Property, prev_child: str =
is_optional=prop.is_optional,
is_predicate=prop.is_predicate,
is_unordered=prop.is_unordered,
description=prop.description
description=prop.description,
type_is_hideable=lookup[prop.type].hideable if prop.type in lookup else False,
)
if prop.is_single:
args.update(
@@ -147,12 +148,12 @@ def get_ql_property(cls: schema.Class, prop: schema.Property, prev_child: str =
return ql.Property(**args)
def get_ql_class(cls: schema.Class) -> ql.Class:
def get_ql_class(cls: schema.Class, lookup: typing.Dict[str, schema.Class]) -> ql.Class:
pragmas = {k: True for k in cls.pragmas if k.startswith("ql")}
prev_child = ""
properties = []
for p in cls.properties:
prop = get_ql_property(cls, p, prev_child)
prop = get_ql_property(cls, p, lookup, prev_child)
if prop.is_child:
prev_child = prop.singular
properties.append(prop)
@@ -164,6 +165,8 @@ def get_ql_class(cls: schema.Class) -> ql.Class:
dir=pathlib.Path(cls.group or ""),
ipa=bool(cls.ipa),
doc=cls.doc,
hideable=cls.hideable,
hideable_root=cls.hideable_root,
**pragmas,
)
@@ -254,7 +257,7 @@ def _get_all_properties_to_be_tested(cls: schema.Class, lookup: typing.Dict[str,
for c, p in _get_all_properties(cls, lookup):
if not ("qltest_skip" in c.pragmas or "qltest_skip" in p.pragmas):
# TODO here operations are duplicated, but should be better if we split ql and qltest generation
p = get_ql_property(c, p)
p = get_ql_property(c, p, lookup)
yield ql.PropertyForTest(p.getter, is_total=p.is_single or p.is_predicate,
type=p.type if not p.is_predicate else None, is_indexed=p.is_indexed)
if p.is_repeated and not p.is_optional:
@@ -329,7 +332,7 @@ def generate(opts, renderer):
data = schemaloader.load_file(input)
classes = {name: get_ql_class(cls) for name, cls in data.classes.items()}
classes = {name: get_ql_class(cls, data.classes) for name, cls in data.classes.items()}
if not classes:
raise NoClasses
root = next(iter(classes.values()))

View File

@@ -42,6 +42,7 @@ class Property:
description: List[str] = field(default_factory=list)
doc: Optional[str] = None
doc_plural: Optional[str] = None
type_is_hideable: bool = False
def __post_init__(self):
if self.tableparams:
@@ -113,6 +114,8 @@ class Class:
ql_internal: bool = False
ipa: bool = False
doc: List[str] = field(default_factory=list)
hideable_root: bool = False
hideable: bool = False
def __post_init__(self):
self.bases = [Base(str(b), str(prev)) for b, prev in zip(self.bases, itertools.chain([""], self.bases))]

View File

@@ -37,7 +37,8 @@ module Generated {
* Gets a comma-separated list of the names of the primary CodeQL classes to which this element belongs.
*/
final string getPrimaryQlClasses() { result = concat(this.getAPrimaryQlClass(), ",") }
{{/root}}
{{#hideable_root}}
/**
* Gets the most immediate element that should substitute this element in the explicit AST, if any.
* Classes can override this to indicate this node should be in the "hidden" AST, mostly reserved
@@ -54,13 +55,13 @@ module Generated {
or
result = this.getResolveStep().resolve()
}
{{/root}}
{{/hideable_root}}
{{#final}}
override string getAPrimaryQlClass() { result = "{{name}}" }
{{/final}}
{{#properties}}
{{#type_is_class}}
{{#type_is_hideable}}
/**
* {{>ql_property_doc}} *
* This includes nodes from the "hidden" AST. It can be overridden in subclasses to change the
@@ -85,11 +86,11 @@ module Generated {
*/
final {{type}} {{getter}}({{#is_indexed}}int index{{/is_indexed}}) {
exists({{type}} immediate | immediate = this.get{{#is_unordered}}An{{/is_unordered}}Immediate{{singular}}({{#is_indexed}}index{{/is_indexed}}) and
if exists(this.getResolveStep()) then result = immediate else result = immediate.resolve())
{{#hideable}}if exists(this.getResolveStep()) then result = immediate else {{/hideable}}result = immediate.resolve())
}
{{/type_is_class}}
{{^type_is_class}}
{{/type_is_hideable}}
{{^type_is_hideable}}
/**
* {{>ql_property_doc}} *
{{#has_description}}
@@ -100,14 +101,14 @@ module Generated {
*/
{{type}} {{getter}}({{#is_indexed}}int index{{/is_indexed}}) {
{{^ipa}}
{{^is_predicate}}result = {{/is_predicate}}Synth::convert{{name}}ToRaw(this){{^root}}.(Raw::{{name}}){{/root}}.{{getter}}({{#is_indexed}}index{{/is_indexed}})
{{^is_predicate}}result = {{/is_predicate}}{{#type_is_class}}Synth::convert{{type}}FromRaw({{/type_is_class}}Synth::convert{{name}}ToRaw(this){{^root}}.(Raw::{{name}}){{/root}}.{{getter}}({{#is_indexed}}index{{/is_indexed}}){{#type_is_class}}){{/type_is_class}}
{{/ipa}}
{{#ipa}}
none()
{{/ipa}}
}
{{/type_is_class}}
{{/type_is_hideable}}
{{#is_optional}}
/**
* Holds if `{{getter}}({{#is_repeated}}index{{/is_repeated}})` exists.

View File

@@ -28,7 +28,7 @@ private module Impl {
{{! for single and optional properties it adds 1 (regardless of whether the optional property exists) }}
{{! for repeated it adds 1 + the maximum index (which works for repeated optional as well) }}
and
n{{singular}} = n{{prev_child}} + 1{{#is_repeated}}+ max(int i | i = -1 or exists(e.getImmediate{{singular}}(i)) | i){{/is_repeated}}
n{{singular}} = n{{prev_child}} + 1{{#is_repeated}}+ max(int i | i = -1 or exists(e.get{{#type_is_hideable}}Immediate{{/type_is_hideable}}{{singular}}(i)) | i){{/is_repeated}}
{{/is_child}}
{{/properties}} and (
none()
@@ -40,10 +40,10 @@ private module Impl {
{{#is_child}}
or
{{#is_repeated}}
result = e.getImmediate{{singular}}(index - n{{prev_child}}) and partialPredicateCall = "{{singular}}(" + (index - n{{prev_child}}).toString() + ")"
result = e.get{{#type_is_hideable}}Immediate{{/type_is_hideable}}{{singular}}(index - n{{prev_child}}) and partialPredicateCall = "{{singular}}(" + (index - n{{prev_child}}).toString() + ")"
{{/is_repeated}}
{{^is_repeated}}
index = n{{prev_child}} and result = e.getImmediate{{singular}}() and partialPredicateCall = "{{singular}}()"
index = n{{prev_child}} and result = e.get{{#type_is_hideable}}Immediate{{/type_is_hideable}}{{singular}}() and partialPredicateCall = "{{singular}}()"
{{/is_repeated}}
{{/is_child}}
{{/properties}}
@@ -64,6 +64,10 @@ none()
{{/final}}
{{/classes}}
}
Element resolve(Element e) {
{{#classes}}{{#hideable_root}}if e instanceof {{name}} then result = e.({{name}}).resolve() else {{/hideable_root}}{{/classes}}result = e
}
}
/**
@@ -87,5 +91,5 @@ exists(string partialAccessor | result = Impl::getImmediateChild(e, index, parti
* Gets the child indexed at `index`. Indexes are not guaranteed to be contiguous, but are guaranteed to be distinct. `accessor` is bound the member predicate call resulting in the given child.
*/
Element getChildAndAccessor(Element e, int index, string accessor) {
exists(string partialAccessor | result = Impl::getImmediateChild(e, index, partialAccessor).resolve() and accessor = "get" + partialAccessor)
exists(string partialAccessor | result = Impl::resolve(Impl::getImmediateChild(e, index, partialAccessor)) and accessor = "get" + partialAccessor)
}

View File

@@ -139,15 +139,16 @@ def a_ql_class(**kwargs):
return ql.Class(**kwargs, import_prefix=gen_import)
def a_ql_stub(**kwargs):
return ql.Stub(**kwargs, import_prefix=gen_import)
def a_ql_stub(*, name, import_prefix="", **kwargs):
return ql.Stub(name=name, **kwargs, import_prefix=gen_import,
base_import=f"{gen_import_prefix}{import_prefix}{name}")
def test_one_empty_class(generate_classes):
assert generate_classes([
schema.Class("A")
]) == {
"A.qll": (a_ql_stub(name="A", base_import=gen_import_prefix + "A"),
"A.qll": (a_ql_stub(name="A"),
a_ql_class(name="A", final=True)),
}
@@ -159,15 +160,11 @@ def test_hierarchy(generate_classes):
schema.Class("B", bases=["A"], derived={"D"}),
schema.Class("A", derived={"B", "C"}),
]) == {
"A.qll": (a_ql_stub(name="A", base_import=gen_import_prefix + "A"),
a_ql_class(name="A")),
"B.qll": (a_ql_stub(name="B", base_import=gen_import_prefix + "B"),
a_ql_class(name="B", bases=["A"], imports=[stub_import_prefix + "A"])),
"C.qll": (a_ql_stub(name="C", base_import=gen_import_prefix + "C"),
a_ql_class(name="C", bases=["A"], imports=[stub_import_prefix + "A"])),
"D.qll": (a_ql_stub(name="D", base_import=gen_import_prefix + "D"),
a_ql_class(name="D", final=True, bases=["B", "C"],
imports=[stub_import_prefix + cls for cls in "BC"])),
"A.qll": (a_ql_stub(name="A"), a_ql_class(name="A")),
"B.qll": (a_ql_stub(name="B"), a_ql_class(name="B", bases=["A"], imports=[stub_import_prefix + "A"])),
"C.qll": (a_ql_stub(name="C"), a_ql_class(name="C", bases=["A"], imports=[stub_import_prefix + "A"])),
"D.qll": (a_ql_stub(name="D"), a_ql_class(name="D", final=True, bases=["B", "C"],
imports=[stub_import_prefix + cls for cls in "BC"])),
}
@@ -213,7 +210,7 @@ def test_single_property(generate_classes):
schema.Class("MyObject", properties=[
schema.SingleProperty("foo", "bar")]),
]) == {
"MyObject.qll": (a_ql_stub(name="MyObject", base_import=gen_import_prefix + "MyObject"),
"MyObject.qll": (a_ql_stub(name="MyObject"),
a_ql_class(name="MyObject", final=True,
properties=[
ql.Property(singular="Foo", type="bar", tablename="my_objects",
@@ -236,9 +233,8 @@ def test_children(generate_classes):
schema.RepeatedOptionalProperty("child_4", "int", is_child=True),
]),
]) == {
"FakeRoot.qll": (a_ql_stub(name="FakeRoot", base_import=gen_import_prefix + "FakeRoot"),
a_ql_class(name="FakeRoot", final=True)),
"MyObject.qll": (a_ql_stub(name="MyObject", base_import=gen_import_prefix + "MyObject"),
"FakeRoot.qll": (a_ql_stub(name="FakeRoot"), a_ql_class(name="FakeRoot", final=True)),
"MyObject.qll": (a_ql_stub(name="MyObject"),
a_ql_class(name="MyObject", final=True,
properties=[
ql.Property(singular="A", type="int", tablename="my_objects",
@@ -286,7 +282,7 @@ def test_single_properties(generate_classes):
schema.SingleProperty("three", "z"),
]),
]) == {
"MyObject.qll": (a_ql_stub(name="MyObject", base_import=gen_import_prefix + "MyObject"),
"MyObject.qll": (a_ql_stub(name="MyObject"),
a_ql_class(name="MyObject", final=True,
properties=[
ql.Property(singular="One", type="x", tablename="my_objects",
@@ -309,9 +305,8 @@ def test_optional_property(generate_classes, is_child, prev_child):
schema.Class("MyObject", properties=[
schema.OptionalProperty("foo", "bar", is_child=is_child)]),
]) == {
"FakeRoot.qll": (a_ql_stub(name="FakeRoot", base_import=gen_import_prefix + "FakeRoot"),
a_ql_class(name="FakeRoot", final=True)),
"MyObject.qll": (a_ql_stub(name="MyObject", base_import=gen_import_prefix + "MyObject"),
"FakeRoot.qll": (a_ql_stub(name="FakeRoot"), a_ql_class(name="FakeRoot", final=True)),
"MyObject.qll": (a_ql_stub(name="MyObject"),
a_ql_class(name="MyObject", final=True, properties=[
ql.Property(singular="Foo", type="bar", tablename="my_object_foos",
tableparams=["this", "result"],
@@ -327,9 +322,8 @@ def test_repeated_property(generate_classes, is_child, prev_child):
schema.Class("MyObject", properties=[
schema.RepeatedProperty("foo", "bar", is_child=is_child)]),
]) == {
"FakeRoot.qll": (a_ql_stub(name="FakeRoot", base_import=gen_import_prefix + "FakeRoot"),
a_ql_class(name="FakeRoot", final=True)),
"MyObject.qll": (a_ql_stub(name="MyObject", base_import=gen_import_prefix + "MyObject"),
"FakeRoot.qll": (a_ql_stub(name="FakeRoot"), a_ql_class(name="FakeRoot", final=True)),
"MyObject.qll": (a_ql_stub(name="MyObject"),
a_ql_class(name="MyObject", final=True, properties=[
ql.Property(singular="Foo", plural="Foos", type="bar", tablename="my_object_foos",
tableparams=["this", "index", "result"], prev_child=prev_child,
@@ -344,9 +338,8 @@ def test_repeated_unordered_property(generate_classes):
schema.Class("MyObject", properties=[
schema.RepeatedUnorderedProperty("foo", "bar")]),
]) == {
"FakeRoot.qll": (a_ql_stub(name="FakeRoot", base_import=gen_import_prefix + "FakeRoot"),
a_ql_class(name="FakeRoot", final=True)),
"MyObject.qll": (a_ql_stub(name="MyObject", base_import=gen_import_prefix + "MyObject"),
"FakeRoot.qll": (a_ql_stub(name="FakeRoot"), a_ql_class(name="FakeRoot", final=True)),
"MyObject.qll": (a_ql_stub(name="MyObject"),
a_ql_class(name="MyObject", final=True, properties=[
ql.Property(singular="Foo", plural="Foos", type="bar", tablename="my_object_foos",
tableparams=["this", "result"], is_unordered=True,
@@ -363,9 +356,8 @@ def test_repeated_optional_property(generate_classes, is_child, prev_child):
schema.RepeatedOptionalProperty("foo", "bar", is_child=is_child)]),
]) == {
"FakeRoot.qll": (a_ql_stub(name="FakeRoot", base_import=gen_import_prefix + "FakeRoot"),
a_ql_class(name="FakeRoot", final=True)),
"MyObject.qll": (a_ql_stub(name="MyObject", base_import=gen_import_prefix + "MyObject"),
"FakeRoot.qll": (a_ql_stub(name="FakeRoot"), a_ql_class(name="FakeRoot", final=True)),
"MyObject.qll": (a_ql_stub(name="MyObject"),
a_ql_class(name="MyObject", final=True, properties=[
ql.Property(singular="Foo", plural="Foos", type="bar", tablename="my_object_foos",
tableparams=["this", "index", "result"], is_optional=True,
@@ -380,7 +372,7 @@ def test_predicate_property(generate_classes):
schema.Class("MyObject", properties=[
schema.PredicateProperty("is_foo")]),
]) == {
"MyObject.qll": (a_ql_stub(name="MyObject", base_import=gen_import_prefix + "MyObject"),
"MyObject.qll": (a_ql_stub(name="MyObject"),
a_ql_class(name="MyObject", final=True, properties=[
ql.Property(singular="isFoo", type="predicate", tablename="my_object_is_foo",
tableparams=["this"], is_predicate=True, doc="this my object is foo"),
@@ -395,7 +387,7 @@ def test_single_class_property(generate_classes, is_child, prev_child):
schema.Class("MyObject", properties=[
schema.SingleProperty("foo", "Bar", is_child=is_child)]),
]) == {
"MyObject.qll": (a_ql_stub(name="MyObject", base_import=gen_import_prefix + "MyObject"),
"MyObject.qll": (a_ql_stub(name="MyObject"),
a_ql_class(
name="MyObject", final=True, imports=[stub_import_prefix + "Bar"], properties=[
ql.Property(singular="Foo", type="Bar", tablename="my_objects",
@@ -404,8 +396,7 @@ def test_single_class_property(generate_classes, is_child, prev_child):
prev_child=prev_child, doc="foo of this my object"),
],
)),
"Bar.qll": (a_ql_stub(name="Bar", base_import=gen_import_prefix + "Bar"),
a_ql_class(name="Bar", final=True)),
"Bar.qll": (a_ql_stub(name="Bar"), a_ql_class(name="Bar", final=True)),
}
@@ -414,8 +405,7 @@ def test_class_with_doc(generate_classes):
assert generate_classes([
schema.Class("A", doc=doc),
]) == {
"A.qll": (a_ql_stub(name="A", base_import=gen_import_prefix + "A"),
a_ql_class(name="A", final=True, doc=doc)),
"A.qll": (a_ql_stub(name="A"), a_ql_class(name="A", final=True, doc=doc)),
}
@@ -425,9 +415,8 @@ def test_class_dir(generate_classes):
schema.Class("A", derived={"B"}, group=dir),
schema.Class("B", bases=["A"]),
]) == {
f"{dir}/A.qll": (a_ql_stub(name="A", base_import=gen_import_prefix + "another.rel.path.A"),
a_ql_class(name="A", dir=pathlib.Path(dir))),
"B.qll": (a_ql_stub(name="B", base_import=gen_import_prefix + "B"),
f"{dir}/A.qll": (a_ql_stub(name="A", import_prefix="another.rel.path."), a_ql_class(name="A", dir=pathlib.Path(dir))),
"B.qll": (a_ql_stub(name="B"),
a_ql_class(name="B", final=True, bases=["A"],
imports=[stub_import_prefix + "another.rel.path.A"])),
}
@@ -586,11 +575,11 @@ def test_test_partial_properties(opts, generate_tests):
type="bool")),
"B/B_getZ.ql": a_ql_property_tester(class_name="B",
property=ql.PropertyForTest(getter="getZ", is_total=False,
is_indexed=True,
type="int")),
is_indexed=True,
type="int")),
"B/B_getAW.ql": a_ql_property_tester(class_name="B",
property=ql.PropertyForTest(getter="getAW", is_total=False,
type="string")),
type="string")),
}
@@ -611,7 +600,7 @@ def test_test_properties_deduplicated(opts, generate_tests):
]),
"Final/Final_getY.ql": a_ql_property_tester(class_name="Final",
property=ql.PropertyForTest(getter="getY", is_total=False,
is_indexed=True,
is_indexed=True,
type="bool")),
}
@@ -706,7 +695,7 @@ def test_property_description(generate_classes):
schema.SingleProperty("foo", "bar", description=description),
]),
]) == {
"MyObject.qll": (a_ql_stub(name="MyObject", base_import=gen_import_prefix + "MyObject"),
"MyObject.qll": (a_ql_stub(name="MyObject"),
a_ql_class(name="MyObject", final=True,
properties=[
ql.Property(singular="Foo", type="bar", tablename="my_objects",
@@ -722,7 +711,7 @@ def test_property_doc_override(generate_classes):
schema.Class("MyObject", properties=[
schema.SingleProperty("foo", "bar", doc="baz")]),
]) == {
"MyObject.qll": (a_ql_stub(name="MyObject", base_import=gen_import_prefix + "MyObject"),
"MyObject.qll": (a_ql_stub(name="MyObject"),
a_ql_class(name="MyObject", final=True,
properties=[
ql.Property(singular="Foo", type="bar", tablename="my_objects",
@@ -737,7 +726,7 @@ def test_repeated_property_doc_override(generate_classes):
schema.RepeatedProperty("x", "int", doc="children of this"),
schema.RepeatedOptionalProperty("y", "int", doc="child of this")]),
]) == {
"MyObject.qll": (a_ql_stub(name="MyObject", base_import=gen_import_prefix + "MyObject"),
"MyObject.qll": (a_ql_stub(name="MyObject"),
a_ql_class(name="MyObject", final=True,
properties=[
ql.Property(singular="X", plural="Xes", type="int",
@@ -759,7 +748,7 @@ def test_property_doc_abbreviations(generate_classes, abbr, expected):
schema.Class("Object", properties=[
schema.SingleProperty(f"foo_{abbr}_bar", "baz")]),
]) == {
"Object.qll": (a_ql_stub(name="Object", base_import=gen_import_prefix + "Object"),
"Object.qll": (a_ql_stub(name="Object"),
a_ql_class(name="Object", final=True,
properties=[
ql.Property(singular=f"Foo{abbr.capitalize()}Bar", type="baz",
@@ -776,7 +765,7 @@ def test_property_doc_abbreviations_ignored_if_within_word(generate_classes, abb
schema.Class("Object", properties=[
schema.SingleProperty(f"foo_{abbr}acadabra_bar", "baz")]),
]) == {
"Object.qll": (a_ql_stub(name="Object", base_import=gen_import_prefix + "Object"),
"Object.qll": (a_ql_stub(name="Object"),
a_ql_class(name="Object", final=True,
properties=[
ql.Property(singular=f"Foo{abbr.capitalize()}acadabraBar", type="baz",
@@ -792,7 +781,7 @@ def test_repeated_property_doc_override_with_format(generate_classes):
schema.RepeatedProperty("x", "int", doc="special {children} of this"),
schema.RepeatedOptionalProperty("y", "int", doc="special {child} of this")]),
]) == {
"MyObject.qll": (a_ql_stub(name="MyObject", base_import=gen_import_prefix + "MyObject"),
"MyObject.qll": (a_ql_stub(name="MyObject"),
a_ql_class(name="MyObject", final=True,
properties=[
ql.Property(singular="X", plural="Xes", type="int",
@@ -815,7 +804,7 @@ def test_repeated_property_doc_override_with_multiple_formats(generate_classes):
schema.RepeatedProperty("x", "int", doc="{cat} or {dog}"),
schema.RepeatedOptionalProperty("y", "int", doc="{cats} or {dogs}")]),
]) == {
"MyObject.qll": (a_ql_stub(name="MyObject", base_import=gen_import_prefix + "MyObject"),
"MyObject.qll": (a_ql_stub(name="MyObject"),
a_ql_class(name="MyObject", final=True,
properties=[
ql.Property(singular="X", plural="Xes", type="int",
@@ -835,7 +824,7 @@ def test_property_doc_override_with_format(generate_classes):
schema.Class("MyObject", properties=[
schema.SingleProperty("foo", "bar", doc="special {baz} of this")]),
]) == {
"MyObject.qll": (a_ql_stub(name="MyObject", base_import=gen_import_prefix + "MyObject"),
"MyObject.qll": (a_ql_stub(name="MyObject"),
a_ql_class(name="MyObject", final=True,
properties=[
ql.Property(singular="Foo", type="bar", tablename="my_objects",
@@ -850,7 +839,7 @@ def test_property_on_class_with_default_doc_name(generate_classes):
schema.SingleProperty("foo", "bar")],
default_doc_name="baz"),
]) == {
"MyObject.qll": (a_ql_stub(name="MyObject", base_import=gen_import_prefix + "MyObject"),
"MyObject.qll": (a_ql_stub(name="MyObject"),
a_ql_class(name="MyObject", final=True,
properties=[
ql.Property(singular="Foo", type="bar", tablename="my_objects",
@@ -863,7 +852,7 @@ def test_stub_on_class_with_ipa_from_class(generate_classes):
assert generate_classes([
schema.Class("MyObject", ipa=schema.IpaInfo(from_class="A")),
]) == {
"MyObject.qll": (a_ql_stub(name="MyObject", base_import=gen_import_prefix + "MyObject", ipa_accessors=[
"MyObject.qll": (a_ql_stub(name="MyObject", ipa_accessors=[
ql.IpaUnderlyingAccessor(argument="Entity", type="Raw::A", constructorparams=["result"]),
]),
a_ql_class(name="MyObject", final=True, ipa=True)),
@@ -874,7 +863,7 @@ def test_stub_on_class_with_ipa_on_arguments(generate_classes):
assert generate_classes([
schema.Class("MyObject", ipa=schema.IpaInfo(on_arguments={"base": "A", "index": "int", "label": "string"})),
]) == {
"MyObject.qll": (a_ql_stub(name="MyObject", base_import=gen_import_prefix + "MyObject", ipa_accessors=[
"MyObject.qll": (a_ql_stub(name="MyObject", ipa_accessors=[
ql.IpaUnderlyingAccessor(argument="Base", type="Raw::A", constructorparams=["result", "_", "_"]),
ql.IpaUnderlyingAccessor(argument="Index", type="int", constructorparams=["_", "result", "_"]),
ql.IpaUnderlyingAccessor(argument="Label", type="string", constructorparams=["_", "_", "result"]),
@@ -883,5 +872,38 @@ def test_stub_on_class_with_ipa_on_arguments(generate_classes):
}
def test_hideable_class(generate_classes):
assert generate_classes([
schema.Class("MyObject", hideable=True),
]) == {
"MyObject.qll": (a_ql_stub(name="MyObject"), a_ql_class(name="MyObject", final=True, hideable=True)),
}
def test_hideable_root_class(generate_classes):
assert generate_classes([
schema.Class("MyObject", hideable_root=True),
]) == {
"MyObject.qll": (a_ql_stub(name="MyObject"), a_ql_class(name="MyObject", final=True, hideable_root=True)),
}
def test_hideable_property(generate_classes):
assert generate_classes([
schema.Class("MyObject", hideable=True),
schema.Class("Other", properties=[
schema.SingleProperty("x", "MyObject"),
]),
]) == {
"MyObject.qll": (a_ql_stub(name="MyObject"), a_ql_class(name="MyObject", final=True, hideable=True)),
"Other.qll": (a_ql_stub(name="Other"),
a_ql_class(name="Other", imports=[stub_import_prefix + "MyObject"],
final=True, properties=[
ql.Property(singular="X", type="MyObject", tablename="others", type_is_hideable=True,
tableparams=["this", "result"], doc="x of this other"),
])),
}
if __name__ == '__main__':
sys.exit(pytest.main([__file__] + sys.argv[1:]))