From f36030a614ee780bb05db81b0ae2dcb77a126e01 Mon Sep 17 00:00:00 2001 From: glowstick016 Date: Wed, 11 Mar 2026 17:07:19 -0400 Subject: [PATCH 1/3] Rough testing requirements. Need to go over once finished catching up on notes --- test/tcas/test_altitude_separation_test.py | 44 ++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/test/tcas/test_altitude_separation_test.py b/test/tcas/test_altitude_separation_test.py index fe06653..9ab3d53 100644 --- a/test/tcas/test_altitude_separation_test.py +++ b/test/tcas/test_altitude_separation_test.py @@ -1,6 +1,50 @@ from tcas.main import altitude_separation_test from tcas.state import State +""" +ENABLE COVERAVGE 'uv add pytest-cov' +Test Requirements: + - For positive_ra_alt_thresh: + - Line 15: + - layer == 0 -> True + - layer == 0 -> False + - Line 17: + - layer == 1 -> True + - Layer == 1 -> False + - Line 19: + - layer == 2 -> True + - layer == 2 -> False + - Line 21: + - layer == 3 -> True + - layer == 3 -> False + - For non_crossing_biased_climb: + - Line 35: + - inhibit_biased_climb(state) > state.down_seperation -> True + - Line 36 -> 37 ????? + - inhibit_biased_climb(state) > state.down_seperation -> False + - Line 40 -> 43 + - For non_crossing_biased_descend: + - Line 48: + - inhibit_biased_climb(state) > state.down_seperation -> True + - Line 49 -> 53 ????? + - inhibit_biased_climb(state) > state.down_seperation -> False + - Line 55 -> 57 + - For altitude_seperation_test: + - Line 63: + - When: + - state.high_confidence and (state.won_tracked_alt_rate <= 600) and (state.current_vertical_sep > 600) -> True + - (state.other_capability == 1) and (state.two_of_three_reports_valid and state.other_rac == 0) -> True + - or not (state.other_capability == 1) -> False + - Or when 1: + - state.high_confidence and (state.won_tracked_alt_rate <= 600) and (state.current_vertical_sep > 600) -> False + - (state.other_capability == 1) and (state.two_of_three_reports_valid and state.other_rac == 0) -> False + - or not (state.other_capability == 1) -> True + - Sub Tests: + - Line 79: need_upward_RA and need_downward_RA -> True + - Line 81: need_upward_RA -> True + - Line 83: need_downward_RA -> True + - Line 85: need_upward_RA and need_downward_RA -> False +""" def test(): state = State( From 631e5c44a41844fda533e89b8feddf297ba75571 Mon Sep 17 00:00:00 2001 From: glowstick016 Date: Fri, 20 Mar 2026 22:40:24 -0400 Subject: [PATCH 2/3] All of the testing has been done --- pyproject.toml | 2 +- src/tcas/main.py | 6 +- test/clause/test_altitude_separation_test.py | 311 ++++++++++++++ .../test_altitude_separation_test.py | 383 ++++++++++++++++++ test/tcas/test_altitude_separation_test.py | 46 +-- 5 files changed, 697 insertions(+), 51 deletions(-) create mode 100644 test/clause/test_altitude_separation_test.py create mode 100644 test/predicate/test_altitude_separation_test.py diff --git a/pyproject.toml b/pyproject.toml index 9b2c1d0..7111604 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ version = "0.1.0" description = "Add your description here" readme = "README.md" requires-python = ">=3.14" -dependencies = ["pytest>=9.0.2", "pytest-html>=4.2.0", "pytest-sugar>=1.1.1"] +dependencies = ["pytest>=9.0.2", "pytest-cov>=7.0.0", "pytest-html>=4.2.0", "pytest-sugar>=1.1.1"] [dependency-groups] dev = ["ruff>=0.15.1"] diff --git a/src/tcas/main.py b/src/tcas/main.py index 5ab8d2f..5b5e8b9 100644 --- a/src/tcas/main.py +++ b/src/tcas/main.py @@ -65,11 +65,7 @@ def altitude_separation_test(state: State) -> int: and (state.own_tracked_alt_rate <= 600) and (state.current_vertical_sep > 600) ) and ( - ( - (state.other_capability == 1) - and (state.two_of_three_reports_valid and state.other_rac == 0) - ) - or not (state.other_capability == 1) + ((state.other_capability == 1)and (state.two_of_three_reports_valid and state.other_rac == 0)) or not (state.other_capability == 1) ): need_upward_RA = non_crossing_biased_climb(state) and own_below_threat(state) need_downward_RA = non_crossing_biased_descend(state) and own_above_threat( diff --git a/test/clause/test_altitude_separation_test.py b/test/clause/test_altitude_separation_test.py new file mode 100644 index 0000000..49f1933 --- /dev/null +++ b/test/clause/test_altitude_separation_test.py @@ -0,0 +1,311 @@ +from tcas.main import altitude_separation_test +from tcas.state import State + +def test_non_crossing_biased_climb_inner_false(): + state = State( + current_vertical_sep=0, high_confidence=0, two_of_three_reports_valid=0, + own_tracked_altitude=1000, own_tracked_alt_rate=0, other_tracked_altitude=2000, + altitude_layer_value=0, up_separation=600, down_separation=500, + other_rac=0, other_capability=0, climb_inhibit=0, + ) + print(f"\n[MCDC] P9 | not own_below=not_below={not(state.own_tracked_altitude < state.other_tracked_altitude)} | not(down>=alim)=not(down>=alim)={not(state.down_separation >= 400)}") + expected = False + actual = altitude_separation_test(state) + assert actual == expected + +def test_non_crossing_biased_climb_inner_c1_true(): + state = State( + current_vertical_sep=0, high_confidence=0, two_of_three_reports_valid=0, + own_tracked_altitude=2000, own_tracked_alt_rate=0, other_tracked_altitude=1000, + altitude_layer_value=0, up_separation=600, down_separation=500, + other_rac=0, other_capability=0, climb_inhibit=0, + ) + print(f"\n[MCDC] P9/not own_below | c1=not_below={not(state.own_tracked_altitude < state.other_tracked_altitude)} | not(down>=alim)=not(down>=alim)={not(state.down_separation >= 400)}") + expected = True + actual = altitude_separation_test(state) + assert actual == expected + +def test_non_crossing_biased_climb_inner_c3_true(): + state = State( + current_vertical_sep=0, high_confidence=0, two_of_three_reports_valid=0, + own_tracked_altitude=1000, own_tracked_alt_rate=0, other_tracked_altitude=2000, + altitude_layer_value=0, up_separation=600, down_separation=100, + other_rac=0, other_capability=0, climb_inhibit=0, + ) + print(f"\n[MCDC] P9/not(down>=alim) | not own_below=not_below={not(state.own_tracked_altitude < state.other_tracked_altitude)} | not(down>=alim)=not(down>=alim)={not(state.down_separation >= 400)}") + expected = True + actual = altitude_separation_test(state) + assert actual == expected + + +def test_non_crossing_biased_climb_else_all_true(): + state = State( + current_vertical_sep=400, high_confidence=0, two_of_three_reports_valid=0, + own_tracked_altitude=3000, own_tracked_alt_rate=0, other_tracked_altitude=1000, + altitude_layer_value=0, up_separation=400, down_separation=500, + other_rac=0, other_capability=0, climb_inhibit=0, + ) + print(f"\n[MCDC] P10 | own_above=own_above={state.other_tracked_altitude < state.own_tracked_altitude} | sep>=300={state.current_vertical_sep >= 300} | up>=alim={state.up_separation >= 400}") + expected = True + actual = altitude_separation_test(state) + assert actual == expected + + +def test_non_crossing_biased_climb_else_c1_false(): + state = State( + current_vertical_sep=400, high_confidence=0, two_of_three_reports_valid=0, + own_tracked_altitude=1000, own_tracked_alt_rate=0, other_tracked_altitude=3000, + altitude_layer_value=0, up_separation=400, down_separation=500, + other_rac=0, other_capability=0, climb_inhibit=0, + ) + print(f"\n[MCDC] P10/own_above | own_above={state.other_tracked_altitude < state.own_tracked_altitude} | =sep>=300={state.current_vertical_sep >= 300} | up>=alim={state.up_separation >= 400}") + expected = False + actual = altitude_separation_test(state) + assert actual == expected + + +def test_non_crossing_biased_climb_else_c2_false(): + state = State( + current_vertical_sep=200, high_confidence=0, two_of_three_reports_valid=0, + own_tracked_altitude=3000, own_tracked_alt_rate=0, other_tracked_altitude=1000, + altitude_layer_value=0, up_separation=400, down_separation=500, + other_rac=0, other_capability=0, climb_inhibit=0, + ) + print(f"\n[MCDC] P10/sep>=300 | own_above={state.other_tracked_altitude < state.own_tracked_altitude} | sep>=300={state.current_vertical_sep >= 300} | up>=alim={state.up_separation >= 400}") + expected = False + actual = altitude_separation_test(state) + assert actual == expected + + +def test_non_crossing_biased_climb_else_c3_false(): + state = State( + current_vertical_sep=400, high_confidence=0, two_of_three_reports_valid=0, + own_tracked_altitude=3000, own_tracked_alt_rate=0, other_tracked_altitude=1000, + altitude_layer_value=0, up_separation=300, down_separation=500, + other_rac=0, other_capability=0, climb_inhibit=0, + ) + print(f"\n[MCDC] P10/up>=alim | own_above={state.other_tracked_altitude < state.own_tracked_altitude} | sep>=300={state.current_vertical_sep >= 300} | up>=alim={state.up_separation >= 400}") + expected = False + actual = altitude_separation_test(state) + assert actual == expected + +def test_non_crossing_biased_descend_inner_all_true(): + state = State( + current_vertical_sep=400, high_confidence=0, two_of_three_reports_valid=0, + own_tracked_altitude=1000, own_tracked_alt_rate=0, other_tracked_altitude=2000, + altitude_layer_value=0, up_separation=600, down_separation=450, + other_rac=0, other_capability=0, climb_inhibit=0, + ) + print(f"\n[MCDC] P12 | own_below={state.own_tracked_altitude < state.other_tracked_altitude} | sep>=300={state.current_vertical_sep >= 300} | down>=alim={state.down_separation >= 400}") + expected = True + actual = altitude_separation_test(state) + assert actual == expected + + +def test_non_crossing_biased_descend_inner_c1_false(): + state = State( + current_vertical_sep=400, high_confidence=0, two_of_three_reports_valid=0, + own_tracked_altitude=3000, own_tracked_alt_rate=0, other_tracked_altitude=1000, + altitude_layer_value=0, up_separation=600, down_separation=450, + other_rac=0, other_capability=0, climb_inhibit=0, + ) + print(f"\n[MCDC] P12/own_below | own_below={state.own_tracked_altitude < state.other_tracked_altitude} | sep>=300={state.current_vertical_sep >= 300} | down>=alim={state.down_separation >= 400}") + expected = False + actual = altitude_separation_test(state) + assert actual == expected + + +def test_non_crossing_biased_descend_inner_c2_false(): + state = State( + current_vertical_sep=200, high_confidence=0, two_of_three_reports_valid=0, + own_tracked_altitude=1000, own_tracked_alt_rate=0, other_tracked_altitude=2000, + altitude_layer_value=0, up_separation=600, down_separation=450, + other_rac=0, other_capability=0, climb_inhibit=0, + ) + print(f"\n[MCDC] P12/sep>=300 | own_below={state.own_tracked_altitude < state.other_tracked_altitude} | =sep>=300={state.current_vertical_sep >= 300} | down>=alim={state.down_separation >= 400}") + expected = False + actual = altitude_separation_test(state) + assert actual == expected + +def test_non_crossing_biased_descend_inner_c3_false(): + state = State( + current_vertical_sep=400, high_confidence=0, two_of_three_reports_valid=0, + own_tracked_altitude=1000, own_tracked_alt_rate=0, other_tracked_altitude=2000, + altitude_layer_value=0, up_separation=600, down_separation=100, + other_rac=0, other_capability=0, climb_inhibit=0, + ) + print(f"\n[MCDC] P12/down>=alim | own_below={state.own_tracked_altitude < state.other_tracked_altitude} | sep>=300={state.current_vertical_sep >= 300} | down>=alim={state.down_separation >= 400}") + expected = False + actual = altitude_separation_test(state) + assert actual == expected + +def test_non_crossing_biased_descend_else_false(): + state = State( + current_vertical_sep=0, high_confidence=0, two_of_three_reports_valid=0, + own_tracked_altitude=3000, own_tracked_alt_rate=0, other_tracked_altitude=1000, + altitude_layer_value=0, up_separation=100, down_separation=500, + other_rac=0, other_capability=0, climb_inhibit=0, + ) + print(f"\n[MCDC] P13 | not own_above={not(state.other_tracked_altitude < state.own_tracked_altitude)} | up>=alim={state.up_separation >= 400}") + expected = False + actual = altitude_separation_test(state) + assert actual == expected + + +def test_non_crossing_biased_descend_else_c1_true(): + state = State( + current_vertical_sep=0, high_confidence=0, two_of_three_reports_valid=0, + own_tracked_altitude=1000, own_tracked_alt_rate=0, other_tracked_altitude=2000, + altitude_layer_value=0, up_separation=100, down_separation=500, + other_rac=0, other_capability=0, climb_inhibit=0, + ) + print(f"\n[MCDC] P13/not own_above | not own_above={not(state.other_tracked_altitude < state.own_tracked_altitude)} | up>=alim={state.up_separation >= 400}") + expected = True + actual = altitude_separation_test(state) + assert actual == expected + + +def test_non_crossing_biased_descend_else_c3_true(): + state = State( + current_vertical_sep=0, high_confidence=0, two_of_three_reports_valid=0, + own_tracked_altitude=3000, own_tracked_alt_rate=0, other_tracked_altitude=1000, + altitude_layer_value=0, up_separation=500, down_separation=600, + other_rac=0, other_capability=0, climb_inhibit=0, + ) + print(f"\n[MCDC] P13/up>=alim | not_above={not(state.other_tracked_altitude < state.own_tracked_altitude)} | up>=alim={state.up_separation >= 400}") + expected = True + actual = altitude_separation_test(state) + assert actual == expected + + + + +# Going over the True Falses +def test_altitude_separation_test_guard_all_true(): + state = State( + current_vertical_sep=700, high_confidence=1, two_of_three_reports_valid=1, + own_tracked_altitude=1000, own_tracked_alt_rate=0, other_tracked_altitude=3000, + altitude_layer_value=0, up_separation=600, down_separation=100, + other_rac=0, other_capability=1, climb_inhibit=0, + ) + print(f"\n[MCDC] P14 | c1={state.high_confidence} | c2={state.own_tracked_alt_rate<=600} | c3={state.current_vertical_sep>600} | c4={state.other_capability==1} | c5={state.two_of_three_reports_valid} | c6={state.other_rac==0}") + expected = 1 + actual = altitude_separation_test(state) + assert actual == expected + +# First value is false +def test_altitude_separation_test_guard_c1_false(): + state = State( + current_vertical_sep=700, high_confidence=0, two_of_three_reports_valid=1, + own_tracked_altitude=1000, own_tracked_alt_rate=0, other_tracked_altitude=3000, + altitude_layer_value=0, up_separation=600, down_separation=100, + other_rac=0, other_capability=1, climb_inhibit=0, + ) + print(f"\n[MCDC] P14/c1 | c1={state.high_confidence} | c2={state.own_tracked_alt_rate<=600} | c3={state.current_vertical_sep>600} | c4={state.other_capability==1} | c5={state.two_of_three_reports_valid} | c6={state.other_rac==0}") + expected = 0 + actual = altitude_separation_test(state) + assert actual == expected + +# Second Value is false +def test_altitude_separation_test_guard_c2_false(): + state = State( + current_vertical_sep=700, high_confidence=1, two_of_three_reports_valid=1, + own_tracked_altitude=1000, own_tracked_alt_rate=700, other_tracked_altitude=3000, + altitude_layer_value=0, up_separation=600, down_separation=100, + other_rac=0, other_capability=1, climb_inhibit=0, + ) + print(f"\n[MCDC] P14/c2 | c1={state.high_confidence} | c2={state.own_tracked_alt_rate<=600} | c3={state.current_vertical_sep>600} | c4={state.other_capability==1} | c5={state.two_of_three_reports_valid} | c6={state.other_rac==0}") + expected = 0 + actual = altitude_separation_test(state) + assert actual == expected + +# Third value is false +def test_altitude_separation_test_guard_c3_false(): + state = State( + current_vertical_sep=600, high_confidence=1, two_of_three_reports_valid=1, + own_tracked_altitude=1000, own_tracked_alt_rate=0, other_tracked_altitude=3000, + altitude_layer_value=0, up_separation=600, down_separation=100, + other_rac=0, other_capability=1, climb_inhibit=0, + ) + print(f"\n[MCDC] P14/c3 | c1={state.high_confidence} | c2={state.own_tracked_alt_rate<=600} | c3={state.current_vertical_sep>600} | c4={state.other_capability==1} | c5={state.two_of_three_reports_valid} | c6={state.other_rac==0}") + expected = 0 + actual = altitude_separation_test(state) + assert actual == expected + +# 4/5 value is false (Can be condensed into 1) +def test_altitude_separation_test_guard_c5_false(): + state = State( + current_vertical_sep=700, high_confidence=1, two_of_three_reports_valid=0, + own_tracked_altitude=1000, own_tracked_alt_rate=0, other_tracked_altitude=3000, + altitude_layer_value=0, up_separation=600, down_separation=100, + other_rac=0, other_capability=1, climb_inhibit=0, + ) + print(f"\n[MCDC] P14/c5 | c4={state.other_capability==1} | c5={state.two_of_three_reports_valid} | c6={state.other_rac==0}") + expected = 0 + actual = altitude_separation_test(state) + assert actual == expected + +# Last value is false +def test_altitude_separation_test_guard_c6_false(): + state = State( + current_vertical_sep=700, high_confidence=1, two_of_three_reports_valid=1, + own_tracked_altitude=1000, own_tracked_alt_rate=0, other_tracked_altitude=3000, + altitude_layer_value=0, up_separation=600, down_separation=100, + other_rac=1, other_capability=1, climb_inhibit=0, + ) + print(f"\n[MCDC] P14/c6 | c4={state.other_capability==1} | c5={state.two_of_three_reports_valid} | c6={state.other_rac==0}") + expected = 0 + actual = altitude_separation_test(state) + assert actual == expected + +# non_cross_bias_climb=F, c2=T own_below +def test_altitude_separation_test_need_upward_c1_false(): + state = State( + current_vertical_sep=700, high_confidence=1, two_of_three_reports_valid=1, + own_tracked_altitude=1000, own_tracked_alt_rate=0, other_tracked_altitude=3000, + altitude_layer_value=0, up_separation=100, down_separation=500, + other_rac=0, other_capability=0, climb_inhibit=0, + ) + print(f"\n[MCDC] P15/c1 | c1=non_cross_bias_climb=F | c2=own_below={state.own_tracked_altitude < state.other_tracked_altitude}") + expected = 0 + actual = altitude_separation_test(state) + assert actual == expected + +# own NOT below, c1=T non_cross_bias_climb=T +def test_altitude_separation_test_need_upward_c2_false(): + state = State( + current_vertical_sep=400, high_confidence=1, two_of_three_reports_valid=1, + own_tracked_altitude=3000, own_tracked_alt_rate=0, other_tracked_altitude=1000, + altitude_layer_value=0, up_separation=400, down_separation=500, + other_rac=0, other_capability=0, climb_inhibit=0, + ) + print(f"\n[MCDC] P15/c2 | c1=non_cross_bias_climb=T(via P10) | c2=own_below={state.own_tracked_altitude < state.other_tracked_altitude}") + expected = 0 + actual = altitude_separation_test(state) + assert actual != 1 + +#non_cross_bias_desc=F, own_above = T +def test_altitude_separation_test_need_downward_c1_false(): + state = State( + current_vertical_sep=700, high_confidence=1, two_of_three_reports_valid=1, + own_tracked_altitude=3000, own_tracked_alt_rate=0, other_tracked_altitude=1000, + altitude_layer_value=0, up_separation=100, down_separation=500, + other_rac=0, other_capability=0, climb_inhibit=0, + ) + print(f"\n[MCDC] P16/c1 | c1=non_cross_bias_desc=F | c2=own_above={state.other_tracked_altitude < state.own_tracked_altitude}") + expected = 0 + actual = altitude_separation_test(state) + assert actual == expected + +# own NOT above, non_cross_bias_desc=T +def test_altitude_separation_test_need_downward_c2_false(): + state = State( + current_vertical_sep=400, high_confidence=1, two_of_three_reports_valid=1, + own_tracked_altitude=1000, own_tracked_alt_rate=0, other_tracked_altitude=2000, + altitude_layer_value=0, up_separation=600, down_separation=450, + other_rac=0, other_capability=0, climb_inhibit=0, + ) + print(f"\n[MCDC] P16/c2 | c1=non_cross_bias_desc=T(via P12) | c2=own_above={state.other_tracked_altitude < state.own_tracked_altitude}") + expected = 0 + actual = altitude_separation_test(state) + assert actual != 2 \ No newline at end of file diff --git a/test/predicate/test_altitude_separation_test.py b/test/predicate/test_altitude_separation_test.py new file mode 100644 index 0000000..79f5789 --- /dev/null +++ b/test/predicate/test_altitude_separation_test.py @@ -0,0 +1,383 @@ +from tcas.main import altitude_separation_test +from tcas.state import State + + + +# own_tracked_altitude < other_tracked_altitude + + + +# True +def test_own_below_threat_true(): + state = State( + current_vertical_sep=0, high_confidence=0, two_of_three_reports_valid=0, + own_tracked_altitude=1000, own_tracked_alt_rate=0, other_tracked_altitude=2000, + altitude_layer_value=0, up_separation=0, down_separation=0, + other_rac=0, other_capability=0, climb_inhibit=0, + ) + expected = True + actual = state.own_tracked_altitude < state.other_tracked_altitude + assert actual == expected + +# SFalse +def test_own_below_threat_false(): + state = State( + current_vertical_sep=0, high_confidence=0, two_of_three_reports_valid=0, + own_tracked_altitude=2000, own_tracked_alt_rate=0, other_tracked_altitude=2000, + altitude_layer_value=0, up_separation=0, down_separation=0, + other_rac=0, other_capability=0, climb_inhibit=0, + ) + expected = False + actual = state.own_tracked_altitude < state.other_tracked_altitude + assert actual == expected + + + +# other_tracked_altitude < own_tracked_altitude + + +# True +def test_own_above_threat_true(): + state = State( + current_vertical_sep=0, high_confidence=0, two_of_three_reports_valid=0, + own_tracked_altitude=3000, own_tracked_alt_rate=0, other_tracked_altitude=1000, + altitude_layer_value=0, up_separation=0, down_separation=0, + other_rac=0, other_capability=0, climb_inhibit=0, + ) + expected = True + actual = state.other_tracked_altitude < state.own_tracked_altitude + assert actual == expected + +# False +def test_own_above_threat_false(): + state = State( + current_vertical_sep=0, high_confidence=0, two_of_three_reports_valid=0, + own_tracked_altitude=1000, own_tracked_alt_rate=0, other_tracked_altitude=1000, + altitude_layer_value=0, up_separation=0, down_separation=0, + other_rac=0, other_capability=0, climb_inhibit=0, + ) + expected = False + actual = state.other_tracked_altitude < state.own_tracked_altitude + assert actual == expected + + + +# positive_ra_alt_thresh Layers 0 -> 3 + + + +# Layer 0 +def test_positive_ra_alt_thresh_layer0_true(): + state = State( + current_vertical_sep=0, high_confidence=0, two_of_three_reports_valid=0, + own_tracked_altitude=0, own_tracked_alt_rate=0, other_tracked_altitude=0, + altitude_layer_value=0, up_separation=0, down_separation=0, + other_rac=0, other_capability=0, climb_inhibit=0, + ) + expected = True + actual = state.altitude_layer_value == 0 + assert actual == expected + +# Layer 1 +def test_positive_ra_alt_thresh_layer1_true(): + state = State( + current_vertical_sep=0, high_confidence=0, two_of_three_reports_valid=0, + own_tracked_altitude=0, own_tracked_alt_rate=0, other_tracked_altitude=0, + altitude_layer_value=1, up_separation=0, down_separation=0, + other_rac=0, other_capability=0, climb_inhibit=0, + ) + expected = True + actual = state.altitude_layer_value == 1 + assert actual == expected + +# Layer 2 +def test_positive_ra_alt_thresh_layer2_true(): + state = State( + current_vertical_sep=0, high_confidence=0, two_of_three_reports_valid=0, + own_tracked_altitude=0, own_tracked_alt_rate=0, other_tracked_altitude=0, + altitude_layer_value=2, up_separation=0, down_separation=0, + other_rac=0, other_capability=0, climb_inhibit=0, + ) + expected = True + actual = state.altitude_layer_value == 2 + assert actual == expected + +# Layer 3 +def test_positive_ra_alt_thresh_layer3_true(): + state = State( + current_vertical_sep=0, high_confidence=0, two_of_three_reports_valid=0, + own_tracked_altitude=0, own_tracked_alt_rate=0, other_tracked_altitude=0, + altitude_layer_value=3, up_separation=0, down_separation=0, + other_rac=0, other_capability=0, climb_inhibit=0, + ) + expected = True + actual = state.altitude_layer_value == 3 + assert actual == expected + +# Else +def test_positive_ra_alt_thresh_layer3_false(): + state = State( + current_vertical_sep=0, high_confidence=0, two_of_three_reports_valid=0, + own_tracked_altitude=0, own_tracked_alt_rate=0, other_tracked_altitude=0, + altitude_layer_value=99, up_separation=0, down_separation=0, + other_rac=0, other_capability=0, climb_inhibit=0, + ) + expected = False + actual = state.altitude_layer_value == 3 + assert actual == expected + + + + +# Testing climb_inhibit + + +# True +def test_inhibit_biased_climb_true(): + state = State( + current_vertical_sep=0, high_confidence=0, two_of_three_reports_valid=0, + own_tracked_altitude=0, own_tracked_alt_rate=0, other_tracked_altitude=0, + altitude_layer_value=0, up_separation=300, down_separation=0, + other_rac=0, other_capability=0, climb_inhibit=1, + ) + expected = 400 + actual = state.up_separation + 100 + assert actual == expected + +# False +def test_inhibit_biased_climb_false(): + state = State( + current_vertical_sep=0, high_confidence=0, two_of_three_reports_valid=0, + own_tracked_altitude=0, own_tracked_alt_rate=0, other_tracked_altitude=0, + altitude_layer_value=0, up_separation=300, down_separation=0, + other_rac=0, other_capability=0, climb_inhibit=0, + ) + expected = 300 + actual = state.up_separation + assert actual == expected + + + + +# Testing non_cross_biase_climb Testing + + +# inhibit_biased_climb(state) > down_separation -> True +def test_non_crossing_biased_climb_1(): + state = State( + current_vertical_sep=0, high_confidence=0, two_of_three_reports_valid=0, + own_tracked_altitude=2000, own_tracked_alt_rate=0, other_tracked_altitude=1000, + altitude_layer_value=0, up_separation=500, down_separation=100, + other_rac=0, other_capability=0, climb_inhibit=0, + ) + expected = True + actual = altitude_separation_test(state) + assert actual == expected + +# inhibit_biased_climb(state) > down_separation -> False +def test_non_crossing_biased_climb_2(): + state = State( + current_vertical_sep=0, high_confidence=0, two_of_three_reports_valid=0, + own_tracked_altitude=1000, own_tracked_alt_rate=0, other_tracked_altitude=2000, + altitude_layer_value=0, up_separation=600, down_separation=500, + other_rac=0, other_capability=0, climb_inhibit=0, + ) + expected = False + actual = altitude_separation_test(state) + assert actual == expected + +# (NOT own_below) OR (own_below AND NOT(down >= alim)) -> True +def test_non_crossing_biased_climb_3(): + state = State( + current_vertical_sep=400, high_confidence=0, two_of_three_reports_valid=0, + own_tracked_altitude=3000, own_tracked_alt_rate=0, other_tracked_altitude=1000, + altitude_layer_value=0, up_separation=400, down_separation=500, + other_rac=0, other_capability=0, climb_inhibit=0, + ) + expected = True + actual = altitude_separation_test(state) + assert actual == expected + +# (NOT own_below) OR (own_below AND NOT(down >= alim)) -> False +def test_non_crossing_biased_climb_4(): + state = State( + current_vertical_sep=400, high_confidence=0, two_of_three_reports_valid=0, + own_tracked_altitude=1000, own_tracked_alt_rate=0, other_tracked_altitude=3000, + altitude_layer_value=0, up_separation=400, down_separation=500, + other_rac=0, other_capability=0, climb_inhibit=0, + ) + expected = False + actual = altitude_separation_test(state) + assert actual == expected + + +# Testing non_cross_biase_desc + + +# inhibit_biased_climb(state) > down_separation -> True +def test_non_crossing_biased_descend_1(): + state = State( + current_vertical_sep=400, high_confidence=0, two_of_three_reports_valid=0, + own_tracked_altitude=3000, own_tracked_alt_rate=0, other_tracked_altitude=1000, + altitude_layer_value=0, up_separation=600, down_separation=100, + other_rac=0, other_capability=0, climb_inhibit=0, + ) + expected = False + actual = altitude_separation_test(state) + assert actual == expected + +# inhibit_biased_climb(state) > down_separation -> False +def test_non_crossing_biased_descend_2(): + state = State( + current_vertical_sep=0, high_confidence=0, two_of_three_reports_valid=0, + own_tracked_altitude=1000, own_tracked_alt_rate=0, other_tracked_altitude=2000, + altitude_layer_value=0, up_separation=100, down_separation=500, + other_rac=0, other_capability=0, climb_inhibit=0, + ) + expected = True + actual = altitude_separation_test(state) + assert actual == expected + +# Both Predicates -> False +def test_non_crossing_biased_descend_3(): + state = State( + current_vertical_sep=0, high_confidence=0, two_of_three_reports_valid=0, + own_tracked_altitude=3000, own_tracked_alt_rate=0, other_tracked_altitude=1000, + altitude_layer_value=0, up_separation=100, down_separation=500, + other_rac=0, other_capability=0, climb_inhibit=0, + ) + expected = False + actual = altitude_separation_test(state) + assert actual == expected + +# guard passes, non_cross_biase_climb -> True, own_below -> True upward RA +def test_altitude_separation_test_guard_true_upward_ra(): + state = State( + current_vertical_sep=700, high_confidence=1, two_of_three_reports_valid=1, + own_tracked_altitude=1000, own_tracked_alt_rate=0, other_tracked_altitude=3000, + altitude_layer_value=0, up_separation=600, down_separation=100, + other_rac=0, other_capability=0, climb_inhibit=0, + ) + expected = 1 + actual = altitude_separation_test(state) + assert actual == expected + +# guard passes, non_cross_biase_desc -> True , own_above -> True downward RA +def test_altitude_separation_test_downward_ra(): + state = State( + current_vertical_sep=700, high_confidence=1, two_of_three_reports_valid=1, + own_tracked_altitude=3000, own_tracked_alt_rate=0, other_tracked_altitude=1000, + altitude_layer_value=0, up_separation=500, down_separation=600, + other_rac=0, other_capability=0, climb_inhibit=0, + ) + expected = 2 + actual = altitude_separation_test(state) + assert actual == expected + +# high_confidence -> False +def test_altitude_separation_test_guard_false_high_confidence(): + state = State( + current_vertical_sep=700, high_confidence=0, two_of_three_reports_valid=1, + own_tracked_altitude=1000, own_tracked_alt_rate=0, other_tracked_altitude=3000, + altitude_layer_value=0, up_separation=600, down_separation=100, + other_rac=0, other_capability=0, climb_inhibit=0, + ) + expected = 0 + actual = altitude_separation_test(state) + assert actual == expected + +# own_tracked_alt_rate -> False +def test_altitude_separation_test_guard_false_alt_rate(): + state = State( + current_vertical_sep=700, high_confidence=1, two_of_three_reports_valid=1, + own_tracked_altitude=1000, own_tracked_alt_rate=700, other_tracked_altitude=3000, + altitude_layer_value=0, up_separation=600, down_separation=100, + other_rac=0, other_capability=0, climb_inhibit=0, + ) + expected = 0 + actual = altitude_separation_test(state) + assert actual == expected + +# current_vertical_sep -> False +def test_altitude_separation_test_guard_false_vert_sep(): + state = State( + current_vertical_sep=600, high_confidence=1, two_of_three_reports_valid=1, + own_tracked_altitude=1000, own_tracked_alt_rate=0, other_tracked_altitude=3000, + altitude_layer_value=0, up_separation=600, down_separation=100, + other_rac=0, other_capability=0, climb_inhibit=0, + ) + expected = 0 + actual = altitude_separation_test(state) + assert actual == expected + +# capability -> False +def test_altitude_separation_test_guard_false_capability(): + state = State( + current_vertical_sep=700, high_confidence=1, two_of_three_reports_valid=1, + own_tracked_altitude=1000, own_tracked_alt_rate=0, other_tracked_altitude=3000, + altitude_layer_value=0, up_separation=600, down_separation=100, + other_rac=1, other_capability=1, climb_inhibit=0, + ) + expected = 0 + actual = altitude_separation_test(state) + assert actual == expected + +# non_cross_biase_climb -> False +def test_altitude_separation_test_need_upward_ra_false_non_cross_biase_climb(): + state = State( + current_vertical_sep=700, high_confidence=1, two_of_three_reports_valid=1, + own_tracked_altitude=1000, own_tracked_alt_rate=0, other_tracked_altitude=3000, + altitude_layer_value=0, up_separation=100, down_separation=500, + other_rac=0, other_capability=0, climb_inhibit=0, + ) + expected = 0 + actual = altitude_separation_test(state) + assert actual == expected + +# own_below -> False +def test_altitude_separation_test_need_upward_ra_false_not_below(): + state = State( + current_vertical_sep=700, high_confidence=1, two_of_three_reports_valid=1, + own_tracked_altitude=3000, own_tracked_alt_rate=0, other_tracked_altitude=1000, + altitude_layer_value=0, up_separation=600, down_separation=100, + other_rac=0, other_capability=0, climb_inhibit=0, + ) + expected = 0 + actual = altitude_separation_test(state) + assert actual != 1 + +# non_cross_biase_desc -> False +def test_altitude_separation_test_need_downward_ra_false_non_cross_biase_desc(): + state = State( + current_vertical_sep=700, high_confidence=1, two_of_three_reports_valid=1, + own_tracked_altitude=3000, own_tracked_alt_rate=0, other_tracked_altitude=1000, + altitude_layer_value=0, up_separation=100, down_separation=500, + other_rac=0, other_capability=0, climb_inhibit=0, + ) + expected = 0 + actual = altitude_separation_test(state) + assert actual == expected + +# own_above -> False +def test_altitude_separation_test_need_downward_ra_false_not_above(): + state = State( + current_vertical_sep=700, high_confidence=1, two_of_three_reports_valid=1, + own_tracked_altitude=1000, own_tracked_alt_rate=0, other_tracked_altitude=3000, + altitude_layer_value=0, up_separation=500, down_separation=600, + other_rac=0, other_capability=0, climb_inhibit=0, + ) + expected = 0 + actual = altitude_separation_test(state) + assert actual != 2 + +# All Falses +def test_altitude_separation_test_no_ra(): + state = State( + current_vertical_sep=700, high_confidence=1, two_of_three_reports_valid=1, + own_tracked_altitude=2000, own_tracked_alt_rate=0, other_tracked_altitude=2000, + altitude_layer_value=0, up_separation=0, down_separation=0, + other_rac=0, other_capability=0, climb_inhibit=0, + ) + expected = 0 + actual = altitude_separation_test(state) + assert actual == expected \ No newline at end of file diff --git a/test/tcas/test_altitude_separation_test.py b/test/tcas/test_altitude_separation_test.py index 9ab3d53..26cb2b1 100644 --- a/test/tcas/test_altitude_separation_test.py +++ b/test/tcas/test_altitude_separation_test.py @@ -1,50 +1,6 @@ from tcas.main import altitude_separation_test from tcas.state import State -""" -ENABLE COVERAVGE 'uv add pytest-cov' -Test Requirements: - - For positive_ra_alt_thresh: - - Line 15: - - layer == 0 -> True - - layer == 0 -> False - - Line 17: - - layer == 1 -> True - - Layer == 1 -> False - - Line 19: - - layer == 2 -> True - - layer == 2 -> False - - Line 21: - - layer == 3 -> True - - layer == 3 -> False - - For non_crossing_biased_climb: - - Line 35: - - inhibit_biased_climb(state) > state.down_seperation -> True - - Line 36 -> 37 ????? - - inhibit_biased_climb(state) > state.down_seperation -> False - - Line 40 -> 43 - - For non_crossing_biased_descend: - - Line 48: - - inhibit_biased_climb(state) > state.down_seperation -> True - - Line 49 -> 53 ????? - - inhibit_biased_climb(state) > state.down_seperation -> False - - Line 55 -> 57 - - For altitude_seperation_test: - - Line 63: - - When: - - state.high_confidence and (state.won_tracked_alt_rate <= 600) and (state.current_vertical_sep > 600) -> True - - (state.other_capability == 1) and (state.two_of_three_reports_valid and state.other_rac == 0) -> True - - or not (state.other_capability == 1) -> False - - Or when 1: - - state.high_confidence and (state.won_tracked_alt_rate <= 600) and (state.current_vertical_sep > 600) -> False - - (state.other_capability == 1) and (state.two_of_three_reports_valid and state.other_rac == 0) -> False - - or not (state.other_capability == 1) -> True - - Sub Tests: - - Line 79: need_upward_RA and need_downward_RA -> True - - Line 81: need_upward_RA -> True - - Line 83: need_downward_RA -> True - - Line 85: need_upward_RA and need_downward_RA -> False -""" def test(): state = State( @@ -66,4 +22,4 @@ def test(): actual = altitude_separation_test(state) - assert actual == expected + assert actual == expected \ No newline at end of file From ec33d31d4e21da8f2b97d14e99e918ab52fe98d8 Mon Sep 17 00:00:00 2001 From: glowstick016 Date: Wed, 1 Apr 2026 22:11:45 -0400 Subject: [PATCH 3/3] pyproject.toml broke? --- pyproject.toml | 9 ++++- test/__init__.py | 0 test/clause/__init__.py | 0 test/predicate/__init__.py | 0 test/tcas/__init__.py | 0 uv.lock | 70 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 78 insertions(+), 1 deletion(-) create mode 100644 test/__init__.py create mode 100644 test/clause/__init__.py create mode 100644 test/predicate/__init__.py create mode 100644 test/tcas/__init__.py diff --git a/pyproject.toml b/pyproject.toml index 7111604..0273909 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,13 @@ version = "0.1.0" description = "Add your description here" readme = "README.md" requires-python = ">=3.14" -dependencies = ["pytest>=9.0.2", "pytest-cov>=7.0.0", "pytest-html>=4.2.0", "pytest-sugar>=1.1.1"] +dependencies = [ + "pytest>=9.0.2", + "pytest-cov>=7.0.0", + "pytest-gremlins>=1.8.0", + "pytest-html>=4.2.0", + "pytest-sugar>=1.1.1", +] [dependency-groups] dev = ["ruff>=0.15.1"] @@ -16,3 +22,4 @@ addopts = [ "--html=reports/pytest_html/index.html", "--self-contained-html", ] +pythonpath = ["src"] \ No newline at end of file diff --git a/test/__init__.py b/test/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test/clause/__init__.py b/test/clause/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test/predicate/__init__.py b/test/predicate/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test/tcas/__init__.py b/test/tcas/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/uv.lock b/uv.lock index 2b1d0d2..43bc5a0 100644 --- a/uv.lock +++ b/uv.lock @@ -11,6 +11,45 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, ] +[[package]] +name = "coverage" +version = "7.13.5" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/9d/e0/70553e3000e345daff267cec284ce4cbf3fc141b6da229ac52775b5428f1/coverage-7.13.5.tar.gz", hash = "sha256:c81f6515c4c40141f83f502b07bbfa5c240ba25bbe73da7b33f1e5b6120ff179", size = 915967, upload-time = "2026-03-17T10:33:18.341Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8e/77/39703f0d1d4b478bfd30191d3c14f53caf596fac00efb3f8f6ee23646439/coverage-7.13.5-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:fbabfaceaeb587e16f7008f7795cd80d20ec548dc7f94fbb0d4ec2e038ce563f", size = 219621, upload-time = "2026-03-17T10:32:08.589Z" }, + { url = "https://files.pythonhosted.org/packages/e2/3e/51dff36d99ae14639a133d9b164d63e628532e2974d8b1edb99dd1ebc733/coverage-7.13.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:9bb2a28101a443669a423b665939381084412b81c3f8c0fcfbac57f4e30b5b8e", size = 219953, upload-time = "2026-03-17T10:32:10.507Z" }, + { url = "https://files.pythonhosted.org/packages/6a/6c/1f1917b01eb647c2f2adc9962bd66c79eb978951cab61bdc1acab3290c07/coverage-7.13.5-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:bd3a2fbc1c6cccb3c5106140d87cc6a8715110373ef42b63cf5aea29df8c217a", size = 250992, upload-time = "2026-03-17T10:32:12.41Z" }, + { url = "https://files.pythonhosted.org/packages/22/e5/06b1f88f42a5a99df42ce61208bdec3bddb3d261412874280a19796fc09c/coverage-7.13.5-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:6c36ddb64ed9d7e496028d1d00dfec3e428e0aabf4006583bb1839958d280510", size = 253503, upload-time = "2026-03-17T10:32:14.449Z" }, + { url = "https://files.pythonhosted.org/packages/80/28/2a148a51e5907e504fa7b85490277734e6771d8844ebcc48764a15e28155/coverage-7.13.5-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:380e8e9084d8eb38db3a9176a1a4f3c0082c3806fa0dc882d1d87abc3c789247", size = 254852, upload-time = "2026-03-17T10:32:16.56Z" }, + { url = "https://files.pythonhosted.org/packages/61/77/50e8d3d85cc0b7ebe09f30f151d670e302c7ff4a1bf6243f71dd8b0981fa/coverage-7.13.5-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e808af52a0513762df4d945ea164a24b37f2f518cbe97e03deaa0ee66139b4d6", size = 257161, upload-time = "2026-03-17T10:32:19.004Z" }, + { url = "https://files.pythonhosted.org/packages/3b/c4/b5fd1d4b7bf8d0e75d997afd3925c59ba629fc8616f1b3aae7605132e256/coverage-7.13.5-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e301d30dd7e95ae068671d746ba8c34e945a82682e62918e41b2679acd2051a0", size = 251021, upload-time = "2026-03-17T10:32:21.344Z" }, + { url = "https://files.pythonhosted.org/packages/f8/66/6ea21f910e92d69ef0b1c3346ea5922a51bad4446c9126db2ae96ee24c4c/coverage-7.13.5-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:800bc829053c80d240a687ceeb927a94fd108bbdc68dfbe505d0d75ab578a882", size = 252858, upload-time = "2026-03-17T10:32:23.506Z" }, + { url = "https://files.pythonhosted.org/packages/9e/ea/879c83cb5d61aa2a35fb80e72715e92672daef8191b84911a643f533840c/coverage-7.13.5-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:0b67af5492adb31940ee418a5a655c28e48165da5afab8c7fa6fd72a142f8740", size = 250823, upload-time = "2026-03-17T10:32:25.516Z" }, + { url = "https://files.pythonhosted.org/packages/8a/fb/616d95d3adb88b9803b275580bdeee8bd1b69a886d057652521f83d7322f/coverage-7.13.5-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:c9136ff29c3a91e25b1d1552b5308e53a1e0653a23e53b6366d7c2dcbbaf8a16", size = 255099, upload-time = "2026-03-17T10:32:27.944Z" }, + { url = "https://files.pythonhosted.org/packages/1c/93/25e6917c90ec1c9a56b0b26f6cad6408e5f13bb6b35d484a0d75c9cf000d/coverage-7.13.5-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:cff784eef7f0b8f6cb28804fbddcfa99f89efe4cc35fb5627e3ac58f91ed3ac0", size = 250638, upload-time = "2026-03-17T10:32:29.914Z" }, + { url = "https://files.pythonhosted.org/packages/fc/7b/dc1776b0464145a929deed214aef9fb1493f159b59ff3c7eeeedf91eddd0/coverage-7.13.5-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:68a4953be99b17ac3c23b6efbc8a38330d99680c9458927491d18700ef23ded0", size = 252295, upload-time = "2026-03-17T10:32:31.981Z" }, + { url = "https://files.pythonhosted.org/packages/ea/fb/99cbbc56a26e07762a2740713f3c8f9f3f3106e3a3dd8cc4474954bccd34/coverage-7.13.5-cp314-cp314-win32.whl", hash = "sha256:35a31f2b1578185fbe6aa2e74cea1b1d0bbf4c552774247d9160d29b80ed56cc", size = 222360, upload-time = "2026-03-17T10:32:34.233Z" }, + { url = "https://files.pythonhosted.org/packages/8d/b7/4758d4f73fb536347cc5e4ad63662f9d60ba9118cb6785e9616b2ce5d7fa/coverage-7.13.5-cp314-cp314-win_amd64.whl", hash = "sha256:2aa055ae1857258f9e0045be26a6d62bdb47a72448b62d7b55f4820f361a2633", size = 223174, upload-time = "2026-03-17T10:32:36.369Z" }, + { url = "https://files.pythonhosted.org/packages/2c/f2/24d84e1dfe70f8ac9fdf30d338239860d0d1d5da0bda528959d0ebc9da28/coverage-7.13.5-cp314-cp314-win_arm64.whl", hash = "sha256:1b11eef33edeae9d142f9b4358edb76273b3bfd30bc3df9a4f95d0e49caf94e8", size = 221739, upload-time = "2026-03-17T10:32:38.736Z" }, + { url = "https://files.pythonhosted.org/packages/60/5b/4a168591057b3668c2428bff25dd3ebc21b629d666d90bcdfa0217940e84/coverage-7.13.5-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:10a0c37f0b646eaff7cce1874c31d1f1ccb297688d4c747291f4f4c70741cc8b", size = 220351, upload-time = "2026-03-17T10:32:41.196Z" }, + { url = "https://files.pythonhosted.org/packages/f5/21/1fd5c4dbfe4a58b6b99649125635df46decdfd4a784c3cd6d410d303e370/coverage-7.13.5-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:b5db73ba3c41c7008037fa731ad5459fc3944cb7452fc0aa9f822ad3533c583c", size = 220612, upload-time = "2026-03-17T10:32:43.204Z" }, + { url = "https://files.pythonhosted.org/packages/d6/fe/2a924b3055a5e7e4512655a9d4609781b0d62334fa0140c3e742926834e2/coverage-7.13.5-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:750db93a81e3e5a9831b534be7b1229df848b2e125a604fe6651e48aa070e5f9", size = 261985, upload-time = "2026-03-17T10:32:45.514Z" }, + { url = "https://files.pythonhosted.org/packages/d7/0d/c8928f2bd518c45990fe1a2ab8db42e914ef9b726c975facc4282578c3eb/coverage-7.13.5-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:9ddb4f4a5479f2539644be484da179b653273bca1a323947d48ab107b3ed1f29", size = 264107, upload-time = "2026-03-17T10:32:47.971Z" }, + { url = "https://files.pythonhosted.org/packages/ef/ae/4ae35bbd9a0af9d820362751f0766582833c211224b38665c0f8de3d487f/coverage-7.13.5-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d8a7a2049c14f413163e2bdabd37e41179b1d1ccb10ffc6ccc4b7a718429c607", size = 266513, upload-time = "2026-03-17T10:32:50.1Z" }, + { url = "https://files.pythonhosted.org/packages/9c/20/d326174c55af36f74eac6ae781612d9492f060ce8244b570bb9d50d9d609/coverage-7.13.5-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e1c85e0b6c05c592ea6d8768a66a254bfb3874b53774b12d4c89c481eb78cb90", size = 267650, upload-time = "2026-03-17T10:32:52.391Z" }, + { url = "https://files.pythonhosted.org/packages/7a/5e/31484d62cbd0eabd3412e30d74386ece4a0837d4f6c3040a653878bfc019/coverage-7.13.5-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:777c4d1eff1b67876139d24288aaf1817f6c03d6bae9c5cc8d27b83bcfe38fe3", size = 261089, upload-time = "2026-03-17T10:32:54.544Z" }, + { url = "https://files.pythonhosted.org/packages/e9/d8/49a72d6de146eebb0b7e48cc0f4bc2c0dd858e3d4790ab2b39a2872b62bd/coverage-7.13.5-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:6697e29b93707167687543480a40f0db8f356e86d9f67ddf2e37e2dfd91a9dab", size = 263982, upload-time = "2026-03-17T10:32:56.803Z" }, + { url = "https://files.pythonhosted.org/packages/06/3b/0351f1bd566e6e4dd39e978efe7958bde1d32f879e85589de147654f57bb/coverage-7.13.5-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:8fdf453a942c3e4d99bd80088141c4c6960bb232c409d9c3558e2dbaa3998562", size = 261579, upload-time = "2026-03-17T10:32:59.466Z" }, + { url = "https://files.pythonhosted.org/packages/5d/ce/796a2a2f4017f554d7810f5c573449b35b1e46788424a548d4d19201b222/coverage-7.13.5-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:32ca0c0114c9834a43f045a87dcebd69d108d8ffb666957ea65aa132f50332e2", size = 265316, upload-time = "2026-03-17T10:33:01.847Z" }, + { url = "https://files.pythonhosted.org/packages/3d/16/d5ae91455541d1a78bc90abf495be600588aff8f6db5c8b0dae739fa39c9/coverage-7.13.5-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:8769751c10f339021e2638cd354e13adeac54004d1941119b2c96fe5276d45ea", size = 260427, upload-time = "2026-03-17T10:33:03.945Z" }, + { url = "https://files.pythonhosted.org/packages/48/11/07f413dba62db21fb3fad5d0de013a50e073cc4e2dc4306e770360f6dfc8/coverage-7.13.5-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:cec2d83125531bd153175354055cdb7a09987af08a9430bd173c937c6d0fba2a", size = 262745, upload-time = "2026-03-17T10:33:06.285Z" }, + { url = "https://files.pythonhosted.org/packages/91/15/d792371332eb4663115becf4bad47e047d16234b1aff687b1b18c58d60ae/coverage-7.13.5-cp314-cp314t-win32.whl", hash = "sha256:0cd9ed7a8b181775459296e402ca4fb27db1279740a24e93b3b41942ebe4b215", size = 223146, upload-time = "2026-03-17T10:33:08.756Z" }, + { url = "https://files.pythonhosted.org/packages/db/51/37221f59a111dca5e85be7dbf09696323b5b9f13ff65e0641d535ed06ea8/coverage-7.13.5-cp314-cp314t-win_amd64.whl", hash = "sha256:301e3b7dfefecaca37c9f1aa6f0049b7d4ab8dd933742b607765d757aca77d43", size = 224254, upload-time = "2026-03-17T10:33:11.174Z" }, + { url = "https://files.pythonhosted.org/packages/54/83/6acacc889de8987441aa7d5adfbdbf33d288dad28704a67e574f1df9bcbb/coverage-7.13.5-cp314-cp314t-win_arm64.whl", hash = "sha256:9dacc2ad679b292709e0f5fc1ac74a6d4d5562e424058962c7bb0c658ad25e45", size = 222276, upload-time = "2026-03-17T10:33:13.466Z" }, + { url = "https://files.pythonhosted.org/packages/9e/ee/a4cf96b8ce1e566ed238f0659ac2d3f007ed1d14b181bcb684e19561a69a/coverage-7.13.5-py3-none-any.whl", hash = "sha256:34b02417cf070e173989b3db962f7ed56d2f644307b2cf9d5a0f258e13084a61", size = 211346, upload-time = "2026-03-17T10:33:15.691Z" }, +] + [[package]] name = "iniconfig" version = "2.3.0" @@ -105,6 +144,33 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/3b/ab/b3226f0bd7cdcf710fbede2b3548584366da3b19b5021e74f5bde2a8fa3f/pytest-9.0.2-py3-none-any.whl", hash = "sha256:711ffd45bf766d5264d487b917733b453d917afd2b0ad65223959f59089f875b", size = 374801, upload-time = "2025-12-06T21:30:49.154Z" }, ] +[[package]] +name = "pytest-cov" +version = "7.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "coverage" }, + { name = "pluggy" }, + { name = "pytest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b1/51/a849f96e117386044471c8ec2bd6cfebacda285da9525c9106aeb28da671/pytest_cov-7.1.0.tar.gz", hash = "sha256:30674f2b5f6351aa09702a9c8c364f6a01c27aae0c1366ae8016160d1efc56b2", size = 55592, upload-time = "2026-03-21T20:11:16.284Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9d/7a/d968e294073affff457b041c2be9868a40c1c71f4a35fcc1e45e5493067b/pytest_cov-7.1.0-py3-none-any.whl", hash = "sha256:a0461110b7865f9a271aa1b51e516c9a95de9d696734a2f71e3e78f46e1d4678", size = 22876, upload-time = "2026-03-21T20:11:14.438Z" }, +] + +[[package]] +name = "pytest-gremlins" +version = "1.8.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "coverage" }, + { name = "pytest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/25/1c/fff467cd22eeba2d824c14b74034de00d42b49b1ee9d384c237b16b58260/pytest_gremlins-1.8.0.tar.gz", hash = "sha256:b652000731eeec98ec8d87485441f40f7e233a39e645e99ef6d0066ebcf20382", size = 3997111, upload-time = "2026-03-30T13:38:38.457Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4e/83/dac4c80f24e3b984855110fc4448fe2fcf509f6c8212ed100e21bf58d3b8/pytest_gremlins-1.8.0-py3-none-any.whl", hash = "sha256:e5432f94fb561bb765a1694166975b771ddd78ecc4fcf7beb2e441e7a27256cd", size = 113658, upload-time = "2026-03-30T13:38:36.526Z" }, +] + [[package]] name = "pytest-html" version = "4.2.0" @@ -175,6 +241,8 @@ version = "0.1.0" source = { virtual = "." } dependencies = [ { name = "pytest" }, + { name = "pytest-cov" }, + { name = "pytest-gremlins" }, { name = "pytest-html" }, { name = "pytest-sugar" }, ] @@ -187,6 +255,8 @@ dev = [ [package.metadata] requires-dist = [ { name = "pytest", specifier = ">=9.0.2" }, + { name = "pytest-cov", specifier = ">=7.0.0" }, + { name = "pytest-gremlins", specifier = ">=1.8.0" }, { name = "pytest-html", specifier = ">=4.2.0" }, { name = "pytest-sugar", specifier = ">=1.1.1" }, ]