diff --git a/policyengine/tests/economic_impact/winners_and_losers/test_by_income_decile/by_income_decile.yaml b/policyengine/tests/economic_impact/winners_and_losers/test_by_income_decile/by_income_decile.yaml new file mode 100644 index 0000000..1fa58c4 --- /dev/null +++ b/policyengine/tests/economic_impact/winners_and_losers/test_by_income_decile/by_income_decile.yaml @@ -0,0 +1,19 @@ +# Winners and Losers by income +- income_impact_test: + reform: + gov.irs.credits.ctc.refundable.fully_refundable: + "2024-01-01.2100-12-31": True + country: us + expected: + deciles: + Lose more than 5%: [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] + Lose less than 5%: [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] + No change: [82.9, 76.6, 78.3, 85.8, 89.9, 93.4, 94.7, 96.5, 96.9, 98.5] + Gain less than 5%: [0.7, 6.1, 8.2, 6.2, 4.6, 4.8, 3.7, 2.6, 2.7, 1.5] + Gain more than 5%: [16.4, 17.3, 13.4, 8.0, 5.5, 1.8, 1.6, 0.8, 0.5, 0.0] + all: + Lose more than 5%: 0.0 + Lose less than 5%: 0.0 + No change: 89.3 + Gain less than 5%: 4.1 + Gain more than 5%: 6.5 diff --git a/policyengine/tests/economic_impact/winners_and_losers/test_by_income_decile/test_by_income_decile.py b/policyengine/tests/economic_impact/winners_and_losers/test_by_income_decile/test_by_income_decile.py new file mode 100644 index 0000000..6f05044 --- /dev/null +++ b/policyengine/tests/economic_impact/winners_and_losers/test_by_income_decile/test_by_income_decile.py @@ -0,0 +1,40 @@ +import pytest +import yaml +import os +from policyengine import EconomicImpact + +def assert_dict_approx_equal(actual, expected, tolerance=1e-4): + if isinstance(expected, dict): + for key in expected: + assert_dict_approx_equal(actual[key], expected[key], tolerance) + elif isinstance(expected, list): + assert len(actual) == len(expected), f"List length mismatch: expected {len(expected)}, got {len(actual)}" + for a, e in zip(actual, expected): + assert abs(a - e) < tolerance, f"Expected {e}, got {a}" + else: + assert abs(actual - expected) < tolerance, f"Expected {expected}, got {actual}" + +yaml_file_path = "policyengine/tests/economic_impact/winners_and_losers/test_by_income_decile/by_income_decile.yaml" + +# Check if the file exists +if not os.path.exists(yaml_file_path): + raise FileNotFoundError(f"The YAML file does not exist at: {yaml_file_path}") + +with open(yaml_file_path, 'r') as file: + test_cases = yaml.safe_load(file) + +@pytest.mark.parametrize("test_case", test_cases) +def test_economic_impact(test_case): + test_name = list(test_case.keys())[0] + test_data = test_case[test_name] + + if test_name != 'income_impact_test': + pytest.skip(f"Skipping non-income test: {test_name}") + + economic_impact = EconomicImpact(test_data['reform'], test_data['country']) + result = economic_impact.calculate("winners_and_losers/by_income_decile") + + assert_dict_approx_equal(result['result'], test_data['expected']) + +if __name__ == "__main__": + pytest.main([__file__]) \ No newline at end of file diff --git a/policyengine/tests/economic_impact/winners_and_losers/test_by_wealth_decile/by_wealth_decile.yaml b/policyengine/tests/economic_impact/winners_and_losers/test_by_wealth_decile/by_wealth_decile.yaml new file mode 100644 index 0000000..7c004e1 --- /dev/null +++ b/policyengine/tests/economic_impact/winners_and_losers/test_by_wealth_decile/by_wealth_decile.yaml @@ -0,0 +1,18 @@ +- wealth_impact_test: + reform: + gov.hmrc.income_tax.rates.uk[0].rate: + "2024-01-01.2100-12-31": 0.55 + country: uk + expected: + deciles: + Lose more than 5%: [21.1, 31.6, 59.2, 64.3, 67.1, 80.1, 81.1, 82.6, 84.5, 86.4] + Lose less than 5%: [6.5, 9.7, 2.4, 2.0, 3.8, 0.8, 0.4, 2.6, 0.2, 1.2] + No change: [72.4, 58.7, 38.4, 33.6, 29.1, 19.1, 18.4, 14.8, 15.3, 12.4] + Gain less than 5%: [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] + Gain more than 5%: [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] + all: + Lose more than 5%: 65.8 + Lose less than 5%: 3.0 + No change: 31.2 + Gain less than 5%: 0.0 + Gain more than 5%: 0.0 \ No newline at end of file diff --git a/policyengine/tests/economic_impact/winners_and_losers/test_by_wealth_decile/test_by_wealth_decile.py b/policyengine/tests/economic_impact/winners_and_losers/test_by_wealth_decile/test_by_wealth_decile.py new file mode 100644 index 0000000..4c94bc3 --- /dev/null +++ b/policyengine/tests/economic_impact/winners_and_losers/test_by_wealth_decile/test_by_wealth_decile.py @@ -0,0 +1,40 @@ +import pytest +import yaml +import os +from policyengine import EconomicImpact + +def assert_dict_approx_equal(actual, expected, tolerance=5e-2): + if isinstance(expected, dict): + for key in expected: + assert_dict_approx_equal(actual[key], expected[key], tolerance) + elif isinstance(expected, list): + assert len(actual) == len(expected), f"List length mismatch: expected {len(expected)}, got {len(actual)}" + for a, e in zip(actual, expected): + assert abs(a - e) < tolerance, f"Expected {e}, got {a}" + else: + assert abs(actual - expected) < tolerance, f"Expected {expected}, got {actual}" + +yaml_file_path = "policyengine/tests/economic_impact/winners_and_losers/test_by_wealth_decile/by_wealth_decile.yaml" + +# Check if the file exists +if not os.path.exists(yaml_file_path): + raise FileNotFoundError(f"The YAML file does not exist at: {yaml_file_path}") + +with open(yaml_file_path, 'r') as file: + test_cases = yaml.safe_load(file) + +@pytest.mark.parametrize("test_case", test_cases) +def test_economic_impact(test_case): + test_name = list(test_case.keys())[0] + test_data = test_case[test_name] + + if test_name != 'wealth_impact_test': + pytest.skip(f"Skipping non-wealth test: {test_name}") + + economic_impact = EconomicImpact(test_data['reform'], test_data['country']) + result = economic_impact.calculate("winners_and_losers/by_wealth_decile") + + assert_dict_approx_equal(result['result'], test_data['expected']) + +if __name__ == "__main__": + pytest.main([__file__]) \ No newline at end of file