def test_class_dir(opts, input, renderer): dir = pathlib.Path("another/rel/path") input.classes = [ schema.Class("A", derived={"B"}, dir=dir), schema.Class("B", bases={"A"}), ] assert generate(opts, renderer) == { import_file(): ql.ImportList([ stub_import_prefix + "another.rel.path.A", stub_import_prefix + "B", ]), stub_path() / dir / "A.qll": ql.Stub(name="A", base_import=gen_import_prefix + "another.rel.path.A"), stub_path() / "B.qll": ql.Stub(name="B", base_import=gen_import_prefix + "B"), ql_output_path() / dir / "A.qll": ql.Class(name="A", dir=dir), ql_output_path() / "B.qll": ql.Class(name="B", final=True, bases=["A"], imports=[stub_import_prefix + "another.rel.path.A"]) }
def test_single_class_property(opts, input, renderer): input.classes = [ schema.Class("MyObject", properties=[schema.SingleProperty("foo", "Bar")]), schema.Class("Bar"), ] assert generate(opts, renderer) == { import_file(): ql.ImportList( [stub_import_prefix + cls for cls in ("Bar", "MyObject")]), stub_path() / "MyObject.qll": ql.Stub(name="MyObject", base_import=gen_import_prefix + "MyObject"), stub_path() / "Bar.qll": ql.Stub(name="Bar", base_import=gen_import_prefix + "Bar"), ql_output_path() / "MyObject.qll": ql.Class( name="MyObject", final=True, imports=[stub_import_prefix + "Bar"], properties=[ ql.Property(singular="Foo", type="Bar", tablename="my_objects", tableparams=["this", "result"]), ], ), ql_output_path() / "Bar.qll": ql.Class(name="Bar", final=True) }
def test_single_class_property(generate_classes, is_child): assert generate_classes([ schema.Class("MyObject", properties=[ schema.SingleProperty("foo", "Bar", is_child=is_child) ]), schema.Class("Bar"), ]) == { "MyObject.qll": (ql.Stub(name="MyObject", base_import=gen_import_prefix + "MyObject"), ql.Class( name="MyObject", final=True, imports=[stub_import_prefix + "Bar"], properties=[ ql.Property(singular="Foo", type="Bar", tablename="my_objects", tableparams=["this", "result"], is_child=is_child), ], )), "Bar.qll": (ql.Stub(name="Bar", base_import=gen_import_prefix + "Bar"), ql.Class(name="Bar", final=True)), }
def test_hierarchy(opts, input, renderer): input.classes = [ schema.Class("D", bases={"B", "C"}), schema.Class("C", bases={"A"}, derived={"D"}), schema.Class("B", bases={"A"}, derived={"D"}), schema.Class("A", derived={"B", "C"}), ] assert generate(opts, renderer) == { import_file(): ql.ImportList([stub_import_prefix + cls for cls in "ABCD"]), stub_path() / "A.qll": ql.Stub(name="A", base_import=gen_import_prefix + "A"), stub_path() / "B.qll": ql.Stub(name="B", base_import=gen_import_prefix + "B"), stub_path() / "C.qll": ql.Stub(name="C", base_import=gen_import_prefix + "C"), stub_path() / "D.qll": ql.Stub(name="D", base_import=gen_import_prefix + "D"), ql_output_path() / "A.qll": ql.Class(name="A"), ql_output_path() / "B.qll": ql.Class(name="B", bases=["A"], imports=[stub_import_prefix + "A"]), ql_output_path() / "C.qll": ql.Class(name="C", bases=["A"], imports=[stub_import_prefix + "A"]), ql_output_path() / "D.qll": ql.Class(name="D", final=True, bases=["B", "C"], imports=[stub_import_prefix + cls for cls in "BC"]), }
def test_single_properties(opts, input, renderer): input.classes = [ schema.Class("MyObject", properties=[ schema.SingleProperty("one", "x"), schema.SingleProperty("two", "y"), schema.SingleProperty("three", "z"), ]), ] assert generate(opts, renderer) == { import_file(): ql.ImportList([stub_import_prefix + "MyObject"]), stub_path() / "MyObject.qll": ql.Stub(name="MyObject", base_import=gen_import_prefix + "MyObject"), ql_output_path() / "MyObject.qll": ql.Class(name="MyObject", final=True, properties=[ ql.Property(singular="One", type="x", tablename="my_objects", tableparams=["this", "result", "_", "_"]), ql.Property(singular="Two", type="y", tablename="my_objects", tableparams=["this", "_", "result", "_"]), ql.Property(singular="Three", type="z", tablename="my_objects", tableparams=["this", "_", "_", "result"]), ]) }
def test_single_properties(generate_classes): assert generate_classes([ schema.Class("MyObject", properties=[ schema.SingleProperty("one", "x"), schema.SingleProperty("two", "y"), schema.SingleProperty("three", "z"), ]), ]) == { "MyObject.qll": (ql.Stub(name="MyObject", base_import=gen_import_prefix + "MyObject"), ql.Class(name="MyObject", final=True, properties=[ ql.Property(singular="One", type="x", tablename="my_objects", tableparams=["this", "result", "_", "_"]), ql.Property(singular="Two", type="y", tablename="my_objects", tableparams=["this", "_", "result", "_"]), ql.Property(singular="Three", type="z", tablename="my_objects", tableparams=["this", "_", "_", "result"]), ])), }
def generate(opts, renderer): input = opts.schema out = opts.ql_output stub_out = opts.ql_stub_output existing = {q for q in out.rglob("*.qll")} existing |= {q for q in stub_out.rglob("*.qll") if is_generated(q)} data = schema.load(input) classes = [get_ql_class(cls) for cls in data.classes] imports = {} for c in classes: imports[c.name] = get_import(stub_out / c.path, opts.swift_dir) for c in classes: qll = (out / c.path).with_suffix(".qll") c.imports = [imports[t] for t in get_classes_used_by(c)] renderer.render(c, qll) stub_file = (stub_out / c.path).with_suffix(".qll") if not stub_file.is_file() or is_generated(stub_file): stub = ql.Stub(name=c.name, base_import=get_import(qll, opts.swift_dir)) renderer.render(stub, stub_file) # for example path/to/syntax/generated -> path/to/syntax.qll include_file = stub_out.with_suffix(".qll") all_imports = ql.ImportList([v for _, v in sorted(imports.items())]) renderer.render(all_imports, include_file) renderer.cleanup(existing) if opts.ql_format: format(opts.codeql_binary, renderer.written)
def generate(opts, renderer): input = opts.schema out = opts.ql_output stub_out = opts.ql_stub_output test_out = opts.ql_test_output missing_test_source_filename = "MISSING_SOURCE.txt" existing = {q for q in out.rglob("*.qll")} existing |= {q for q in stub_out.rglob("*.qll") if is_generated(q)} existing |= {q for q in test_out.rglob("*.ql")} existing |= {q for q in test_out.rglob(missing_test_source_filename)} data = schema.load(input) classes = [get_ql_class(cls) for cls in data.classes] lookup = {cls.name: cls for cls in classes} classes.sort(key=lambda cls: (cls.dir, cls.name)) imports = {} for c in classes: imports[c.name] = get_import(stub_out / c.path, opts.swift_dir) for c in classes: qll = out / c.path.with_suffix(".qll") c.imports = [imports[t] for t in get_classes_used_by(c)] renderer.render(c, qll) stub_file = stub_out / c.path.with_suffix(".qll") if not stub_file.is_file() or is_generated(stub_file): stub = ql.Stub( name=c.name, base_import=get_import(qll, opts.swift_dir)) renderer.render(stub, stub_file) # for example path/to/elements -> path/to/elements.qll include_file = stub_out.with_suffix(".qll") renderer.render(ql.ImportList(list(imports.values())), include_file) renderer.render(ql.GetParentImplementation( classes), out / 'GetImmediateParent.qll') for c in classes: if not c.final or c.skip_qltest: continue test_dir = test_out / c.path test_dir.mkdir(parents=True, exist_ok=True) if not any(test_dir.glob("*.swift")): log.warning(f"no test source in {c.path}") renderer.render(ql.MissingTestInstructions(), test_dir / missing_test_source_filename) continue total_props, partial_props = _partition(_get_all_properties_to_be_tested(c, lookup), lambda p: p.is_single or p.is_predicate) renderer.render(ql.ClassTester(class_name=c.name, properties=total_props), test_dir / f"{c.name}.ql") for p in partial_props: renderer.render(ql.PropertyTester(class_name=c.name, property=p), test_dir / f"{c.name}_{p.getter}.ql") renderer.cleanup(existing) if opts.ql_format: format(opts.codeql_binary, renderer.written)
def test_class_dir(generate_classes): dir = pathlib.Path("another/rel/path") assert generate_classes([ schema.Class("A", derived={"B"}, dir=dir), schema.Class("B", bases={"A"}), ]) == { f"{dir}/A.qll": (ql.Stub(name="A", base_import=gen_import_prefix + "another.rel.path.A"), ql.Class(name="A", dir=dir)), "B.qll": (ql.Stub(name="B", base_import=gen_import_prefix + "B"), ql.Class(name="B", final=True, bases=["A"], imports=[stub_import_prefix + "another.rel.path.A"])), }
def test_one_empty_class(opts, input, renderer): input.classes = [schema.Class("A")] assert generate(opts, renderer) == { import_file(): ql.ImportList([stub_import_prefix + "A"]), stub_path() / "A.qll": ql.Stub(name="A", base_import=gen_import_prefix + "A"), ql_output_path() / "A.qll": ql.Class(name="A", final=True), }
def test_hierarchy(generate_classes): assert generate_classes([ schema.Class("D", bases={"B", "C"}), schema.Class("C", bases={"A"}, derived={"D"}), schema.Class("B", bases={"A"}, derived={"D"}), schema.Class("A", derived={"B", "C"}), ]) == { "A.qll": (ql.Stub(name="A", base_import=gen_import_prefix + "A"), ql.Class(name="A")), "B.qll": (ql.Stub(name="B", base_import=gen_import_prefix + "B"), ql.Class(name="B", bases=["A"], imports=[stub_import_prefix + "A"])), "C.qll": (ql.Stub(name="C", base_import=gen_import_prefix + "C"), ql.Class(name="C", bases=["A"], imports=[stub_import_prefix + "A"])), "D.qll": (ql.Stub(name="D", base_import=gen_import_prefix + "D"), ql.Class(name="D", final=True, bases=["B", "C"], imports=[stub_import_prefix + cls for cls in "BC"])), }
def test_single_property(generate_classes): assert generate_classes([ schema.Class("MyObject", properties=[schema.SingleProperty("foo", "bar")]), ]) == { "MyObject.qll": (ql.Stub(name="MyObject", base_import=gen_import_prefix + "MyObject"), ql.Class(name="MyObject", final=True, properties=[ ql.Property(singular="Foo", type="bar", tablename="my_objects", tableparams=["this", "result"]), ])), }
def test_predicate_property(generate_classes): assert generate_classes([ schema.Class("MyObject", properties=[schema.PredicateProperty("is_foo")]), ]) == { "MyObject.qll": (ql.Stub(name="MyObject", base_import=gen_import_prefix + "MyObject"), ql.Class(name="MyObject", final=True, properties=[ ql.Property(singular="isFoo", type="predicate", tablename="my_object_is_foo", tableparams=["this"], is_predicate=True), ])), }
def test_repeated_property(opts, input, renderer): input.classes = [ schema.Class("MyObject", properties=[schema.RepeatedProperty("foo", "bar")]), ] assert generate(opts, renderer) == { import_file(): ql.ImportList([stub_import_prefix + "MyObject"]), stub_path() / "MyObject.qll": ql.Stub(name="MyObject", base_import=gen_import_prefix + "MyObject"), ql_output_path() / "MyObject.qll": ql.Class(name="MyObject", final=True, properties=[ ql.Property(singular="Foo", plural="Foos", type="bar", tablename="my_object_foos", tableparams=["this", "index", "result"]), ]) }
def test_predicate_property(opts, input, renderer): input.classes = [ schema.Class("MyObject", properties=[schema.PredicateProperty("is_foo")]), ] assert generate(opts, renderer) == { import_file(): ql.ImportList([stub_import_prefix + "MyObject"]), stub_path() / "MyObject.qll": ql.Stub(name="MyObject", base_import=gen_import_prefix + "MyObject"), ql_output_path() / "MyObject.qll": ql.Class(name="MyObject", final=True, properties=[ ql.Property(singular="isFoo", type="predicate", tablename="my_object_is_foo", tableparams=["this"], is_predicate=True), ]) }
def test_repeated_property(generate_classes, is_child): assert generate_classes([ schema.Class("MyObject", properties=[ schema.RepeatedProperty("foo", "bar", is_child=is_child) ]), ]) == { "MyObject.qll": (ql.Stub(name="MyObject", base_import=gen_import_prefix + "MyObject"), ql.Class(name="MyObject", final=True, properties=[ ql.Property(singular="Foo", plural="Foos", type="bar", tablename="my_object_foos", tableparams=["this", "index", "result"], is_child=is_child), ])), }
def test_one_empty_class(generate_classes): assert generate_classes([schema.Class("A")]) == { "A.qll": (ql.Stub(name="A", base_import=gen_import_prefix + "A"), ql.Class(name="A", final=True)), }