Ejemplo n.º 1
0
def assert_rule_pass_in_sql(code, sql, configs=None, msg=None):
    """Assert that a given rule doesn't fail on the given sql."""
    # Configs allows overrides if we want to use them.
    if configs is None:
        configs = {}
    core = configs.setdefault("core", {})
    core["rules"] = code
    cfg = FluffConfig(configs=configs)
    linter = Linter(config=cfg)

    # This section is mainly for aid in debugging.
    rendered = linter.render_string(sql,
                                    fname="<STR>",
                                    config=cfg,
                                    encoding="utf-8")
    parsed = linter.parse_rendered(rendered, recurse=True)
    if parsed.violations:
        if msg:
            print(msg)  # pragma: no cover
        pytest.fail(parsed.violations[0].desc() + "\n" +
                    parsed.tree.stringify())
    print(f"Parsed:\n {parsed.tree.stringify()}")

    # Note that lint_string() runs the templater and parser again, in order to
    # test the whole linting pipeline in the same way that users do. In other
    # words, the "rendered" and "parsed" variables above are irrelevant to this
    # line of code.
    lint_result = linter.lint_string(sql, config=cfg, fname="<STR>")
    lerrs = lint_result.violations
    print(f"Errors Found: {lerrs}")
    if any(v.rule.code == code for v in lerrs):
        if msg:
            print(msg)  # pragma: no cover
        pytest.fail(f"Found {code} failures in query which should pass.",
                    pytrace=False)
Ejemplo n.º 2
0
def assert_rule_fail_in_sql(code, sql, configs=None, line_numbers=None):
    """Assert that a given rule does fail on the given sql."""
    # Set up the config to only use the rule we are testing.
    cfg = FluffConfig(configs=configs, overrides={"rules": code})
    # Lint it using the current config (while in fix mode)
    linted = Linter(config=cfg).lint_string(sql, fix=True)
    lerrs = linted.get_violations()
    print(f"Errors Found: {lerrs}")
    for e in lerrs:
        if e.desc().startswith("Unexpected exception"):
            pytest.fail(f"Linter failed with {e.desc()}")
    parse_errors = list(filter(lambda v: type(v) == SQLParseError, lerrs))
    if parse_errors:
        pytest.fail(f"Found the following parse errors in test case: {parse_errors}")
    if not any(v.rule.code == code for v in lerrs):
        pytest.fail(
            f"No {code} failures found in query which should fail.",
            pytrace=False,
        )
    if line_numbers:
        actual_line_numbers = [e.line_no for e in lerrs]
        if line_numbers != actual_line_numbers:
            pytest.fail(
                "Expected errors on lines {}, but got errors on lines {}".format(
                    line_numbers, actual_line_numbers
                )
            )
    # The query should already have been fixed if possible so just return the raw.
    return linted.tree.raw
Ejemplo n.º 3
0
def test_rule_set_return_informative_error_when_rule_not_registered():
    """Assert that a rule that throws an exception returns it as a validation."""
    cfg = FluffConfig(overrides={"dialect": "ansi"})
    with pytest.raises(ValueError) as e:
        get_rule_from_set("L000", config=cfg)

    e.match("'L000' not in")
Ejemplo n.º 4
0
def test__rules__std_file(rule, path, violations):
    """Test the linter finds the given errors in (and only in) the right places."""
    assert_rule_raises_violations_in_file(
        rule=rule,
        fpath=path,
        violations=violations,
        fluff_config=FluffConfig(overrides=dict(rules=rule)),
    )
Ejemplo n.º 5
0
def test__rules__std_file_dbt(rule, path, violations, in_dbt_project_dir):  # noqa
    """Test the linter finds the given errors in (and only in) the right places (DBT)."""
    assert_rule_raises_violations_in_file(
        rule=rule,
        fpath=path,
        violations=violations,
        fluff_config=FluffConfig(configs=DBT_FLUFF_CONFIG, overrides=dict(rules=rule)),
    )
Ejemplo n.º 6
0
def test__rule_test_case(test_case):
    """Run the tests."""
    res = rules__test_helper(test_case)
    if res is not None and res != test_case.fail_str:
        cfg = FluffConfig(configs=test_case.configs)
        rule = get_rule_from_set(test_case.rule, config=cfg)
        assert is_fix_compatible(
            rule
        ), f'Rule {test_case.rule} returned fixes but does not specify "@document_fix_compatible".'
Ejemplo n.º 7
0
def test__rule_test_case(test_case, caplog):
    """Run the tests."""
    with caplog.at_level(logging.DEBUG, logger="sqlfluff.rules"):
        res = rules__test_helper(test_case)
        if res is not None and res != test_case.fail_str:
            cfg = FluffConfig(configs=test_case.configs)
            rule = get_rule_from_set(test_case.rule, config=cfg)
            assert is_fix_compatible(
                rule
            ), f'Rule {test_case.rule} returned fixes but does not specify "@document_fix_compatible".'
Ejemplo n.º 8
0
def test_rule_exception_is_caught_to_validation():
    """Assert that a rule that throws an exception on _eval returns it as a validation."""
    @std_rule_set.register
    class Rule_LXXX(BaseCrawler):
        """Rule that throws an exception."""
        def _eval(self, segment, parent_stack, **kwargs):
            raise Exception(
                "Catch me or I'll deny any linting results from you")

    linter = Linter(config=FluffConfig(overrides=dict(rules="LXXX")))

    assert linter.lint_string("select 1").check_tuples() == [("LXXX", 1, 1)]
Ejemplo n.º 9
0
def assert_rule_pass_in_sql(code, sql, configs=None):
    """Assert that a given rule doesn't fail on the given sql."""
    # Configs allows overrides if we want to use them.
    cfg = FluffConfig(configs=configs)
    r = get_rule_from_set(code, config=cfg)
    parsed = Linter(config=cfg).parse_string(sql)
    if parsed.violations:
        pytest.fail(parsed.violations[0].desc() + "\n" + parsed.tree.stringify())
    print(f"Parsed:\n {parsed.tree.stringify()}")
    lerrs, _, _, _ = r.crawl(parsed.tree, dialect=cfg.get("dialect_obj"))
    print(f"Errors Found: {lerrs}")
    if any(v.rule.code == code for v in lerrs):
        pytest.fail(f"Found {code} failures in query which should pass.", pytrace=False)
Ejemplo n.º 10
0
def test__rules__runaway_fail_catch():
    """Test that we catch runaway rules."""
    runaway_limit = 5
    my_query = "SELECT * FROM foo"
    # Set up the config to only use the rule we are testing.
    cfg = FluffConfig(overrides={"rules": "T001", "runaway_limit": runaway_limit})
    # Lint it using the current config (while in fix mode)
    linter = Linter(config=cfg, user_rules=[Rule_T001])
    # In theory this step should result in an infinite
    # loop, but the loop limit should catch it.
    linted = linter.lint_string(my_query, fix=True)
    # We should have a lot of newlines in there.
    # The number should equal the runaway limit
    assert linted.tree.raw.count("\n") == runaway_limit
Ejemplo n.º 11
0
def test__rules__std_L003_process_raw_stack(generate_test_segments):
    """Test the _process_raw_stack function.

    Note: This test probably needs expanding. It doesn't
    really check enough of the full functionality.

    """
    cfg = FluffConfig()
    r = get_rule_from_set("L003", config=cfg)
    test_stack = generate_test_segments(["bar", "\n", "     ", "foo", "baar", " \t "])
    res = r._process_raw_stack(test_stack)
    print(res)
    assert sorted(res.keys()) == [1, 2]
    assert res[2]["indent_size"] == 5
Ejemplo n.º 12
0
def test__rules__runaway_fail_catch():
    """Test that we catch runaway rules."""
    runaway_limit = 5
    my_query = "SELECT * FROM foo"
    # Set up the config to only use the rule we are testing.
    cfg = FluffConfig(overrides={
        "rules": "T001",
        "runaway_limit": runaway_limit
    })
    # Lint it using the current config (while in fix mode)
    linter = Linter(config=cfg, user_rules=[Rule_T001])
    # In theory this step should result in an infinite
    # loop, but the loop limit should catch it.
    linted = linter.lint_string(my_query, fix=True)
    # When the linter hits the runaway limit, it returns the original SQL tree.
    assert linted.tree.raw == my_query
Ejemplo n.º 13
0
def assert_rule_fail_in_sql(code, sql, configs=None):
    """Assert that a given rule does fail on the given sql."""
    # Set up the config to only use the rule we are testing.
    cfg = FluffConfig(configs=configs, overrides={"rules": code})
    # Lint it using the current config (while in fix mode)
    linted = Linter(config=cfg).lint_string(sql, fix=True)
    lerrs = linted.get_violations()
    print("Errors Found: {0}".format(lerrs))
    parse_errors = list(filter(lambda v: type(v) == SQLParseError, lerrs))
    if parse_errors:
        pytest.fail(f"Found the following parse errors in test case: {parse_errors}")
    if not any(v.rule.code == code for v in lerrs):
        pytest.fail(
            "No {0} failures found in query which should fail.".format(code),
            pytrace=False,
        )
    # The query should already have been fixed if possible so just return the raw.
    return linted.tree.raw
Ejemplo n.º 14
0
def test_rule_exception_is_caught_to_validation():
    """Assert that a rule that throws an exception returns it as a validation."""
    std_rule_set = get_ruleset()

    @std_rule_set.register
    class Rule_T000(BaseRule):
        """Rule that throws an exception."""

        groups = ("all", )
        crawl_behaviour = RootOnlyCrawler()

        def _eval(self, segment, parent_stack, **kwargs):
            raise Exception(
                "Catch me or I'll deny any linting results from you")

    linter = Linter(
        config=FluffConfig(overrides=dict(rules="T000", dialect="ansi")),
        user_rules=[Rule_T000],
    )

    assert linter.lint_string("select 1").check_tuples() == [("T000", 1, 1)]
Ejemplo n.º 15
0
def test__rules__std_L007_before():
    """Verify that L007 returns the correct error message when before is used."""
    sql = """
        SELECT
            a,
            b
        FROM foo
        WHERE
            a = 1
            AND b = 2
    """
    config = FluffConfig(
        configs={"rules": {"L007": {"operator_new_lines": "before"}}},
        overrides={"dialect": "ansi"},
    )
    # The sqlfluff.lint API doesn't allow us to pass config so need to do what it does
    linter = Linter(config=config)
    result_records = linter.lint_string_wrapped(sql).as_records()
    result = result_records[0]["violations"]
    assert "L007" in [r["code"] for r in result]
    assert before_description in [r["description"] for r in result]
Ejemplo n.º 16
0
def test__rules__std_L003_process_raw_stack(generate_test_segments, test_elems,
                                            result):
    """Test the _process_raw_stack function.

    Note: This test probably needs expanding. It doesn't
    really check enough of the full functionality.

    """
    cfg = FluffConfig()
    r = get_rule_from_set("L003", config=cfg)
    test_stack = generate_test_segments(test_elems)
    res = r._process_raw_stack(test_stack, {})
    print(res)
    # Verify structure
    assert isinstance(res, dict)
    assert all(isinstance(k, int) for k in res.keys())
    assert all(isinstance(v, dict) for v in res.values())
    # Check keys are all present
    assert all(
        v.keys() == {
            "line_no",
            "templated_line",
            "line_buffer",
            "indent_buffer",
            "indent_size",
            "indent_balance",
            "hanging_indent",
            "clean_indent",
        } for v in res.values())
    for k in res:
        # For testing purposes, we won't be checking the buffer fields. They're
        # just too hard to create in the test cases and aren't critical in
        # determining what course of action to take. Most of the logic uses the
        # values which we *are* still testing.
        del res[k]["line_buffer"]
        del res[k]["indent_buffer"]
        # We also don't check the "templated_file" flag. These tests don't
        # exercise that code.
        del res[k]["templated_line"]
    assert res == result
Ejemplo n.º 17
0
def assert_rule_pass_in_sql(code, sql, configs=None):
    """Assert that a given rule doesn't fail on the given sql."""
    # Configs allows overrides if we want to use them.
    cfg = FluffConfig(configs=configs)
    r = get_rule_from_set(code, config=cfg)
    linter = Linter(config=cfg)
    rendered = linter.render_string(sql,
                                    fname="<STR>",
                                    config=cfg,
                                    encoding="utf-8")
    parsed = linter.parse_rendered(rendered, recurse=True)
    if parsed.violations:
        pytest.fail(parsed.violations[0].desc() + "\n" +
                    parsed.tree.stringify())
    print(f"Parsed:\n {parsed.tree.stringify()}")
    lerrs, _, _, _ = r.crawl(parsed.tree, [],
                             dialect=cfg.get("dialect_obj"),
                             templated_file=rendered[0])
    print(f"Errors Found: {lerrs}")
    if any(v.rule.code == code for v in lerrs):
        pytest.fail(f"Found {code} failures in query which should pass.",
                    pytrace=False)
Ejemplo n.º 18
0
def test__rules__std_L007_after():
    """Verify orrect error message when after is explicitly used."""
    sql = """
        SELECT
            a,
            b
        FROM foo
        WHERE
            a = 1 AND
            b = 2
    """
    config = FluffConfig(
        configs={"rules": {
            "L007": {
                "operator_new_lines": "after"
            }
        }})
    # The sqlfluff.lint API doesn't allow us to pass config so need to do what it does
    linter = Linter(config=config)
    result_records = linter.lint_string_wrapped(sql).as_records()
    result = result_records[0]["violations"]
    assert "L007" in [r["code"] for r in result]
    assert after_description in [r["description"] for r in result]
Ejemplo n.º 19
0
def assert_rule_fail_in_sql(code, sql, configs=None, line_numbers=None):
    """Assert that a given rule does fail on the given sql."""
    print("# Asserting Rule Fail in SQL")
    # Set up the config to only use the rule we are testing.
    overrides = {"rules": code}
    if configs is None or "core" not in configs or "dialect" not in configs[
            "core"]:
        overrides["dialect"] = "ansi"
    cfg = FluffConfig(configs=configs, overrides=overrides)
    # Lint it using the current config (while in fix mode)
    linted = Linter(config=cfg).lint_string(sql, fix=True)
    lerrs = linted.get_violations()
    print("Errors Found:")
    for e in lerrs:
        print("    " + repr(e))
        if e.desc().startswith("Unexpected exception"):
            pytest.fail(f"Linter failed with {e.desc()}")  # pragma: no cover
    parse_errors = list(
        filter(lambda v: isinstance(v, (SQLParseError, SQLTemplaterError)),
               lerrs))
    if parse_errors:
        pytest.fail(
            f"Found the following parse errors in test case: {parse_errors}")
    if not any(v.rule.code == code for v in lerrs):
        print(f"Parsed File:\n{linted.tree.stringify()}")
        pytest.fail(
            f"No {code} failures found in query which should fail.",
            pytrace=False,
        )
    if line_numbers:
        actual_line_numbers = [e.line_no for e in lerrs]
        if line_numbers != actual_line_numbers:  # pragma: no cover
            pytest.fail(
                "Expected errors on lines {}, but got errors on lines {}".
                format(line_numbers, actual_line_numbers))
    fixed, _ = linted.fix_string()
    return fixed, linted.violations
Ejemplo n.º 20
0
def test__plugin_default_config_read():
    """Test that the example plugin default config is merged into FluffConfig."""
    fluff_config = FluffConfig(overrides={"dialect": "ansi"})
    # The plugin import order is non-deterministic
    assert "forbidden_columns" in fluff_config._configs["rules"]["Example_L001"]
Ejemplo n.º 21
0
def test_improper_configs_are_rejected(rule_config_dict):
    """Ensure that unsupported configs raise a ValueError."""
    config = FluffConfig(configs={"rules": rule_config_dict})
    with pytest.raises(ValueError):
        get_ruleset().get_rulelist(config)