예제 #1
0
def has_equal_references(state, absolute=False, incorrect_msg=None):
    child = check_range(state, field="formulas", field_msg="formula")

    if absolute:
        pattern = r"\$?[A-Z]+\$?\d+(?:\:\$?[A-Z]+\$?\d+)?"
    else:
        pattern = r"[A-Za-z]+\d+(?:\:[A-Za-z]+\d+)?"

    student_formulas = child.student_data
    solution_formulas = child.solution_data

    for i, student_row in enumerate(student_formulas):
        for j, student_cell in enumerate(student_row):
            solution_cell = str(solution_formulas[i][j])
            student_cell = str(student_cell)
            solution_references = re.findall(pattern, solution_cell)

            for reference in solution_references:
                if normalize_formula(reference) not in normalize_formula(
                        student_cell):
                    _msg = (
                        incorrect_msg
                        or ("In cell `{range}`, did you use the{absolute_str} "
                            "reference `{reference}`?")).format(
                                absolute_str=" absolute" if absolute else "",
                                reference=reference,
                                **child.to_message_exposed_dict())
                    child.report(_msg)
 def normalize_condition(condition):
     if condition and condition.get("type",
                                    None) == "CUSTOM_FORMULA":
         condition = copy.deepcopy(condition)
         condition["values"][0][
             "userEnteredValue"] = normalize_formula(
                 condition["values"][0]["userEnteredValue"])
     return condition
예제 #3
0
def check_function(state, name, index=0, missing_msg=None):
    missing_msg = (
        missing_msg
        or "In cell `{range}`, did you use the `{name}()` function?").format(
            name=name, **state.to_message_exposed_dict())

    # construct regex pattern
    pattern = "(?:{pattern}.*){{{index}}}".format(
        pattern=normalize_formula(name), index=index + 1)

    has_code(
        state,
        pattern=pattern,
        fixed=False,
        incorrect_msg=missing_msg,
        normalize=normalize_formula,
    )
    # Don't return state; chaining not implemented yet
    return None
예제 #4
0
def has_equal_pivot(state, extra_msg=None):
    child = check_range(state, field="pivotTables", field_msg="pivot table")

    student_pivot_tables = child.student_data["pivotTables"]
    solution_pivot_tables = child.solution_data["pivotTables"]

    for i, student_row in enumerate(student_pivot_tables):
        for j, student_pivot_table in enumerate(student_row):
            solution_pivot_table = solution_pivot_tables[i][j]
            issues = []
            bound_rules = {
                key: RuleClass(student_pivot_table, solution_pivot_table,
                               issues)
                for key, RuleClass in rule_types.items()
            }

            bound_rules["existence"]("rows", "There are no rows."),
            bound_rules["existence"]("columns", "There are no columns.")
            bound_rules["existence"]("values", "There are no values.")
            bound_rules["existence"]("criteria", "There are no filters.")
            bound_rules["over_existence"](
                "rows", "There are rows but there shouldn't be."),
            bound_rules["over_existence"](
                "columns", "There are columns but there shouldn't be.")
            bound_rules["over_existence"](
                "values", "There are values but there shouldn't be.")
            bound_rules["equality"]("source", "The source data is incorrect.")
            bound_rules["array_equality"](
                ("rows", ["sortOrder"]),
                ("Inside rows, expected the {ordinal} sort order to be "
                 "`{expected}`, but got `{actual}`"),
            )
            bound_rules["array_equality"](
                ("columns", ["sortOrder"]),
                ("Inside columns, expected the {ordinal} sort order to be "
                 "`{expected}`, but got `{actual}`"),
            )
            bound_rules["array_equality"](
                ("rows", ["valueBucket"]),
                ("Inside rows, expected the {ordinal} sort group to be "
                 "`{expected}`, but got `{actual}`"),
            )
            bound_rules["array_equality"](
                ("columns", ["valueBucket"]),
                ("Inside columns, expected the {ordinal} sort group to be "
                 "`{expected}`, but got `{actual}`"),
            )
            bound_rules["array_equality"](
                ("rows", ["sourceColumnOffset"]),
                ("Inside rows, the {ordinal} grouping variable is incorrect."),
            )
            bound_rules["array_equality"](
                ("columns", ["sourceColumnOffset"]),
                ("Inside columns, the {ordinal} grouping variable is incorrect."
                 ),
            )
            bound_rules["array_equality"](
                ("rows", ["showTotals"]),
                ("Inside rows, the {ordinal} totals are not showing."),
            )
            bound_rules["array_equality"](
                ("columns", ["showTotals"]),
                ("Inside columns, the {ordinal} totals are not showing."),
            )
            bound_rules["array_equality"](
                ("values", ["summarizeFunction"]),
                ("Inside values, expected the {ordinal} summarize function "
                 "to be `{expected}`, but got `{actual}`."),
            )
            bound_rules["array_equality"](
                ("values", ["calculatedDisplayType"]),
                ("Inside values, expected the {ordinal} display type "
                 "to be `{expected}`, but got `{actual}`."),
            )
            bound_rules["array_equal_length"](
                "values",
                ("The number of values is incorrect. "
                 "Expected {expected}, but got {actual}."),
            )
            bound_rules["array_equal_length"](
                "rows",
                ("The number of rows is incorrect. "
                 "Expected {expected}, but got {actual}."),
            )
            bound_rules["array_equal_length"](
                "columns",
                ("The number of columns is incorrect. "
                 "Expected {expected}, but got {actual}."),
            )

            bound_rules["dict_key_equality"](
                "criteria",
                "The rows or columns used in the filter are incorrect.")
            for key in dict_keys(
                    safe_glom(solution_pivot_table, "criteria"),
                    safe_glom(student_pivot_table, "criteria"),
            ):
                bound_rules["set_equality"](
                    f"criteria.{key}.visibleValues",
                    "The filtered out values are incorrect.",
                )

            bound_rules["array_equality"](
                ("values", ["formula"]),
                "The {ordinal} value does not contain the correct calculated field.",
                lambda x, y: normalize_formula(x) == normalize_formula(y),
            )

            nb_issues = len(issues)
            if nb_issues > 0:
                _issues_msg = "\n".join([f"- {issue}" for issue in issues])
                _msg = (
                    f"There {'are' if nb_issues > 1 else 'is'} {nb_issues} "
                    f"issue{'s' if nb_issues > 1 else ''} with the pivot table "
                    f"at `{child.sct_range}`:\n\n{_issues_msg}\n")
                child.do_test(_msg)
예제 #5
0
def has_equal_pivot(state, extra_msg=None):
    child = check_range(state, field="pivotTables", field_msg="pivot table")

    student_pivot_tables = child.student_data
    solution_pivot_tables = child.solution_data

    for i, student_row in enumerate(student_pivot_tables):
        for j, student_pivot_table in enumerate(student_row):
            solution_pivot_table = solution_pivot_tables[i][j]

            test_runner = TestRunnerProxy(state.reporter)
            selector = dispatcher_selector(student_pivot_table,
                                           solution_pivot_table)

            tests = [
                ExistenceTest(*selector("rows"), "There are no rows."),
                ExistenceTest(*selector("columns"), "There are no columns."),
                ExistenceTest(*selector("values"), "There are no values."),
                ExistenceTest(*selector("criteria"), "There are no filters."),
                OverExistenceTest(*selector("rows"),
                                  "There are rows but there shouldn't be."),
                OverExistenceTest(*selector("columns"),
                                  "There are columns but there shouldn't be."),
                OverExistenceTest(*selector("values"),
                                  "There are values but there shouldn't be."),
                EqualityTest(*selector("source"),
                             "The source data is incorrect."),
            ]

            tests += array_element_tests(
                EqualityTest,
                *selector(("rows", ["sortOrder"])),
                ("Inside rows, expected the {ordinal} sort order to be "
                 "`{expected}`, but got `{actual}`"),
            )
            tests += array_element_tests(
                EqualityTest,
                *selector(("columns", ["sortOrder"])),
                ("Inside columns, expected the {ordinal} sort order to be "
                 "`{expected}`, but got `{actual}`"),
            )
            tests += array_element_tests(
                EqualityTest,
                *selector(("rows", ["valueBucket"])),
                ("Inside rows, expected the {ordinal} sort group to be "
                 "`{expected}`, but got `{actual}`"),
            )
            tests += array_element_tests(
                EqualityTest,
                *selector(("columns", ["valueBucket"])),
                ("Inside columns, expected the {ordinal} sort group to be "
                 "`{expected}`, but got `{actual}`"),
            )
            tests += array_element_tests(
                EqualityTest,
                *selector(("rows", ["sourceColumnOffset"])),
                ("Inside rows, the {ordinal} grouping variable is incorrect."),
            )
            tests += array_element_tests(
                EqualityTest,
                *selector(("columns", ["sourceColumnOffset"])),
                ("Inside columns, the {ordinal} grouping variable is incorrect."
                 ),
            )
            tests += array_element_tests(
                EqualityTest,
                *selector(("rows", ["showTotals"])),
                ("Inside rows, the {ordinal} totals are not showing."),
            )
            tests += array_element_tests(
                EqualityTest,
                *selector(("columns", ["showTotals"])),
                ("Inside columns, the {ordinal} totals are not showing."),
            )
            tests += array_element_tests(
                EqualityTest,
                *selector(("values", ["summarizeFunction"])),
                ("Inside values, expected the {ordinal} summarize function "
                 "to be `{expected}`, but got `{actual}`."),
            )
            tests += array_element_tests(
                EqualityTest,
                *selector(("values", ["calculatedDisplayType"])),
                ("Inside values, expected the {ordinal} display type "
                 "to be `{expected}`, but got `{actual}`."),
            )

            tests += [
                ArrayEqualLengthTest(
                    *selector("values"),
                    ("The number of values is incorrect. "
                     "Expected {expected}, but got {actual}."),
                ),
                ArrayEqualLengthTest(
                    *selector("rows"),
                    ("The number of rows is incorrect. "
                     "Expected {expected}, but got {actual}."),
                ),
                ArrayEqualLengthTest(
                    *selector("columns"),
                    ("The number of columns is incorrect. "
                     "Expected {expected}, but got {actual}."),
                ),
            ]

            tests.append(
                DictKeyEqualityTest(
                    *selector("criteria"),
                    "The rows or columns used in the filter are incorrect.",
                ))
            for key in dict_keys(*selector("criteria")):
                tests.append(
                    SetEqualityTest(
                        *selector(f"criteria.{key}.visibleValues"),
                        "The filtered out values are incorrect.",
                    ))

            tests += array_element_tests(
                EqualityTest,
                *selector(("values", ["formula"])),
                "The {ordinal} value does not contain the correct calculated field.",
                lambda x, y: normalize_formula(x) == normalize_formula(y),
            )

            test_runner.do_tests(tests)

            nb_issues = len(test_runner.failures)
            if nb_issues > 0:
                _issues_msg = "\n".join([
                    f"- {test.feedback.message}"
                    for test in test_runner.failures
                ])
                _msg = (
                    f"There {'are' if nb_issues > 1 else 'is'} {nb_issues} "
                    f"issue{'s' if nb_issues > 1 else ''} with the pivot table "
                    f"at `{child.sct_range}`:\n\n{_issues_msg}\n")
                child.report(_msg)