CSC108-Fall-2022-A3 / a3_checker.py
a3_checker.py
Raw
"""A simple checker for types of functions in mm_functions.py."""

from typing import Any, Dict, Union
import pytest
import checker_generic
import a3

FILENAME = 'a3.py'
PYTA_CONFIG = 'a3_pythonta.json'
TARGET_LEN = 79
SEP = '='

CONSTANTS = {
    'ID': 'id',
    'HT_KEY': 'hypertension',
    'TOTAL': 'total',
    'LOW_INCOME': 'low_income',
    'HT_20_44': 0,
    'NBH_20_44': 1,
    'HT_45_64': 2,
    'NBH_45_64': 3,
    'HT_65_UP': 4,
    'NBH_65_UP': 5,
    'ID_COL': 0,
    'NBH_NAME_COL': 1,
    'POP_COL': 2,
    'LI_POP_COL': 3
}

SAMPLE_DATA = {
    "West Humber-Clairville": {
        "id": 1,
        "hypertension": [703, 13291, 3741, 9663, 3959, 5176],
        "total": 33230,
        "low_income": 5950,
    },
    "Mount Olive-Silverstone-Jamestown": {
        "id": 2,
        "hypertension": [789, 12906, 3578, 8815, 2927, 3902],
        "total": 32940,
        "low_income": 9690,
    },
    "Thistletown-Beaumond Heights": {
        "id": 3,
        "hypertension": [220, 3631, 1047, 2829, 1349, 1767],
        "total": 10365,
        "low_income": 2005,
    },
    "Rexdale-Kipling": {
        "id": 4,
        "hypertension": [201, 3669, 1134, 3229, 1393, 1854],
        "total": 10540,
        "low_income": 2140,
    },
    "Elms-Old Rexdale": {
        "id": 5,
        "hypertension": [176, 3353, 1040, 2842, 948, 1322],
        "total": 9460,
        "low_income": 2315,
    },
}



class TestChecker:
    """Sanity checker for assignment functions."""

    def test_get_hypertension_data(self) -> None:
        """Function get_hypertension_data"""
        with open('hypertension_data_small.csv') as f:
            d = {}
            assert a3.get_hypertension_data(d, f) is None, \
                "get_hypertension_data should return None"
            assert d != {}, \
                "The dictionary provided to get_hypertension_data " \
                "should have new elements."

    def test_get_low_income_data(self) -> None:
        """Function get_low_income_data"""
        with open('low_income_small.csv') as f:
            d = {}
            assert a3.get_low_income_data(d, f) is None, \
                "get_low_income_data should return None"
            assert d != {}, \
                "The dictionary provided to get_low_income_data " \
                "should have new elements."

    def test_get_bigger_neighbourhood(self) -> None:
        """Function get_bigger_neighbourhood"""
        self._check(a3.get_bigger_neighbourhood,
                    [SAMPLE_DATA,
                     'Mount Olive-Silverstone-Jamestown',
                     'Rexdale-Kipling'],
                    str)

    def test_get_high_hypertension_rate(self) -> None:
        """Function get_high_hypertension_rate"""
        results = checker_generic.returns_list_of_Ts(
            a3.get_high_hypertension_rate, [SAMPLE_DATA, 0.24], tuple)
        assert results[0], results[1]

    def test_get_ht_to_low_income_ratios(self) -> None:
        """Function get_ht_to_low_income_ratios"""
        self._check(a3.get_ht_to_low_income_ratios,
                    [SAMPLE_DATA], dict)

    def test_calculate_ht_rates_by_age_group(self) -> None:
        """Function calculate_ht_rates_by_age_group"""
        results = checker_generic.returns_tuple_of(a3.calculate_ht_rates_by_age_group,
                                                   [SAMPLE_DATA,
                                                    'Elms-Old Rexdale'],
                                                   (float, float, float))
        assert results[0], results[1]

    def test_get_stats_summary(self) -> None:
        """Function get_stats_summary"""
        self._check(a3.get_stats_summary, [SAMPLE_DATA], float)

    def test_order_by_ht_rate(self) -> None:
        """Function order_by_ht_rate"""
        results = checker_generic.returns_list_of_Ts(a3.order_by_ht_rate,
                                                     [SAMPLE_DATA], str)
        assert results[0], results[1]

    def test_check_constants(self) -> None:
        """Values of constants."""

        print('\nChecking that constants refer to their original values')
        self._check_constants(CONSTANTS, a3)
        print('  check complete')

    def test_test_a3_has_test_cases(self) -> None:
        """test_a3.py has test cases beyond the provided 'test_first_bigger'
        """
        import test_a3
        test_cases = [item for item in dir(test_a3)
                      if item.startswith('test_')
                      and item != 'test_first_bigger']
        assert test_cases, \
            "No new test cases were found in test_a3.py: " \
            "make sure all of your test case names start with " \
            "'test_')"

    def _check(self, func: callable, args: list, ret_type: Union[type, tuple]) -> None:
        """Check that func called with arguments args returns a value of type
        ret_type. Display the progress and the result of the check.
        """
        print('\nChecking {}...'.format(func.__name__))
        result = checker_generic.type_check_simple(func, args, ret_type)
        assert result[0] is True, result[1]
        print('  check complete')

    def _check_constants(self, name2value: Dict[str, object], mod: Any) -> None:
        """Check that, for each (name, value) pair in name2value, the value of
        a variable named name in module mod is value.
        """

        for name, expected in name2value.items():
            actual = getattr(mod, name)
            msg = 'The value of constant {} should be {} but is {}.'.format(
                name, expected, actual)
            assert expected == actual, msg


print(''.center(TARGET_LEN, SEP))
print(' Start: checking coding style with PythonTA '.center(TARGET_LEN, SEP))
checker_generic.run_pyta(FILENAME, PYTA_CONFIG)
print(' End checking coding style with PythonTA '.center(TARGET_LEN, SEP))

print(' Start: checking type contracts '.center(TARGET_LEN, SEP))
pytest.main(['--show-capture', 'no', '--disable-warnings', '--tb=short',
             'a3_checker.py'])
print(' End checking type contracts '.center(TARGET_LEN, SEP))

print('\nScroll up to see ALL RESULTS:')
print('  - checking coding style with Python TA')
print('  - checking type contract\n')