Example #1
0
def test_hierarchy_imports(generate_import_list):
    assert generate_import_list([
        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"}),
    ]) == ql.ImportList([stub_import_prefix + cls for cls in "ABCD"])
Example #2
0
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)
Example #3
0
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"])
    }
Example #4
0
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"]),
    }
Example #5
0
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)
    }
Example #6
0
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"]),
                 ])
    }
Example #7
0
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)
Example #8
0
def test_class_dir_imports(generate_import_list):
    dir = pathlib.Path("another/rel/path")
    assert generate_import_list([
        schema.Class("A", derived={"B"}, dir=dir),
        schema.Class("B", bases={"A"}),
    ]) == ql.ImportList([
        stub_import_prefix + "B",
        stub_import_prefix + "another.rel.path.A",
    ])
Example #9
0
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),
    }
Example #10
0
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),
                 ])
    }
Example #11
0
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"]),
                 ])
    }
Example #12
0
def test_empty(generate):
    assert generate([]) == {
        import_file(): ql.ImportList(),
        children_file(): ql.GetParentImplementation(),
    }
Example #13
0
def test_empty(opts, input, renderer):
    assert generate(opts, renderer) == {import_file(): ql.ImportList()}