поправлены в какой то раз удаления для верхнего счета

This commit is contained in:
2026-08-20 15:20:19 +03:00
parent 3dc21e4619
commit 8790a1e113
9 changed files with 244 additions and 78 deletions

View File

@@ -8,7 +8,7 @@ def test_ready_penalty_opens_target_when_scoreboard_is_live():
end = APP_JS.index("function finishActionMatchesSource", start)
snippet = APP_JS[start:end]
assert "if (hockeyScoreboardIsLive())" in snippet
assert 'commands.push({ Function: `OverlayInput${overlay}In`, Input: target.input });' in snippet
assert 'inCommands.push({ Function: `OverlayInput${overlay}In`, Input: target.input });' in snippet
def test_penalty_overlay_auto_in_does_not_retrigger_visible_target():

View File

@@ -50,7 +50,7 @@ def test_mapping_input_picker_sorts_by_number_and_fields_naturally():
assert "const allFields = [...(currentInput.fields || [])].sort(mappingVmixFieldOrder);" in ADMIN
def test_coincidental_penalties_fill_both_home_and_away_labels():
def test_coincidental_penalties_do_not_fill_side_powerplay_labels():
settings = {
"strength_regulation_skaters": 5,
"strength_min_skaters": 3,
@@ -62,5 +62,5 @@ def test_coincidental_penalties_fill_both_home_and_away_labels():
value = HockeyDataService._strength_payload(settings, stage="regular", current_period="1", timer_state=timer_state, language="ru")
assert value["advantage_side"] == ""
assert value["state_key"] == "4x4"
assert value["home_label"] == "4 на 4"
assert value["away_label"] == "4 на 4"
assert value["home_label"] == ""
assert value["away_label"] == ""

View File

@@ -7,13 +7,15 @@ APP_JS = (ROOT / "ui_builder/static/app.js").read_text(encoding="utf-8")
BRIDGE = (ROOT / "hockey_data/agent_bridge.py").read_text(encoding="utf-8")
def test_penalty_display_routes_single_side_to_opposite_advantage_target():
def test_penalty_display_routes_only_one_transition_timer_to_advantage_target():
start = APP_JS.index("function penaltyDisplayEntriesByTargetSide")
end = APP_JS.index("function hockeyPenaltySideMappingDetail", start)
block = APP_JS[start:end]
assert 'if (home.length && away.length)' in block
assert 'return { home: [], away: take(home), routedToAdvantage: true, advantageSide: "away" };' in block
assert 'return { home: take(away), away: [], routedToAdvantage: true, advantageSide: "home" };' in block
assert 'function penaltyLocalAdvantageSide' in APP_JS
assert 'const all = [...home, ...away].sort' in block
assert 'if (!advantageSide)' in block
assert 'home: advantageSide === "home"' in block
assert 'away: advantageSide === "away"' in block
def test_penalty_rebalance_and_initial_timer_use_same_display_plan():

View File

@@ -44,14 +44,16 @@ def test_strength_engine_reports_advantage_for_4x3_and_3x4():
assert away_advantage["advantage_side"] == "away"
def test_penalty_plate_routing_defers_powerplay_while_both_sides_have_penalties():
def test_penalty_plate_routing_uses_single_advantage_side_and_global_shortest_timer():
start = APP_JS.index("function penaltyDisplayEntriesByTargetSide")
end = APP_JS.index("function hockeyPenaltySideMappingDetail", start)
block = APP_JS[start:end]
assert 'if (home.length && away.length)' in block
assert 'return { home: take(home), away: take(away), routedToAdvantage: false, advantageSide: "" };' in block
assert 'return { home: [], away: take(home), routedToAdvantage: true, advantageSide: "away" };' in block
assert 'return { home: take(away), away: [], routedToAdvantage: true, advantageSide: "home" };' in block
assert 'const all = [...home, ...away].sort' in block
assert 'const advantageSide = penaltyLocalAdvantageSide(home.length, away.length);' in block
assert 'if (!advantageSide)' in block
assert 'transitionEntry = all[0]' in block
assert 'home: advantageSide === "home"' in block
assert 'away: advantageSide === "away"' in block
def test_database_schema_reference_lists_real_hockey_tables(tmp_path: Path):

View File

@@ -14,11 +14,12 @@ def test_authoritative_strength_change_rebalances_penalty_targets():
assert "Penalty strength rebalance error" in block
def test_penalty_plan_rebalances_after_strength_refresh_without_forcing_complex_powerplay():
def test_penalty_plan_rebalances_after_strength_refresh_to_single_advantage_plate():
start = APP_JS.index("function penaltyDisplayEntriesByTargetSide")
end = APP_JS.index("function hockeyPenaltySideMappingDetail", start)
block = APP_JS[start:end]
assert 'if (home.length && away.length)' in block
assert 'routedToAdvantage: false' in block
assert 'if (home.length)' in block
assert 'if (away.length)' in block
assert 'penaltyLocalAdvantageSide(home.length, away.length)' in block
assert 'transitionEntry = all[0]' in block
assert 'routedToAdvantage: true' in block
assert 'if (!advantageSide)' in block

View File

@@ -17,7 +17,7 @@ def _penalty(side: str, remaining: int = 90000) -> dict:
}
def test_complex_two_vs_one_keeps_real_strength_but_hides_pp_caption_until_one_side_clears():
def test_complex_two_vs_one_keeps_real_strength_and_outputs_caption_on_advantage_side():
settings = {
"strength_regulation_skaters": 5,
"strength_min_skaters": 3,
@@ -33,7 +33,7 @@ def test_complex_two_vs_one_keeps_real_strength_but_hides_pp_caption_until_one_s
assert value["strength_label"] == "3×4"
assert value["advantage_side"] == "away"
assert value["home_label"] == ""
assert value["away_label"] == ""
assert value["away_label"] == "Играют в большинстве"
def test_single_remaining_penalty_outputs_pp_caption_on_opposite_team():
@@ -54,12 +54,11 @@ def test_single_remaining_penalty_outputs_pp_caption_on_opposite_team():
assert value["away_label"] == "Играют в большинстве"
def test_display_plan_keeps_each_side_while_both_have_penalties_and_clears_when_none():
def test_display_plan_never_outputs_two_penalty_plates():
start = APP_JS.index("function penaltyDisplayEntriesByTargetSide")
end = APP_JS.index("function hockeyPenaltySideMappingDetail", start)
block = APP_JS[start:end]
assert 'if (home.length && away.length)' in block
assert 'return { home: take(home), away: take(away), routedToAdvantage: false, advantageSide: "" };' in block
assert 'return { home: [], away: take(home), routedToAdvantage: true, advantageSide: "away" };' in block
assert 'return { home: take(away), away: [], routedToAdvantage: true, advantageSide: "home" };' in block
assert 'return { home: [], away: [], routedToAdvantage: false, advantageSide: "" };' in block
assert 'const all = [...home, ...away].sort' in block
assert 'return { home: [], away: [], routedToAdvantage: false' in block
assert 'home: advantageSide === "home" && transitionEntry ? [transitionEntry] : []' in block
assert 'away: advantageSide === "away" && transitionEntry ? [transitionEntry] : []' in block

View File

@@ -0,0 +1,91 @@
from pathlib import Path
from hockey_data.service import HockeyDataService
ROOT = Path(__file__).resolve().parents[1]
APP_JS = (ROOT / "ui_builder/static/app.js").read_text(encoding="utf-8")
def _penalty(side: str, remaining: int) -> dict:
return {
"side": side,
"infraction": {"code": "TEST"},
"preset": "2",
"durationMs": 120000,
"remainingMs": remaining,
"finished": False,
}
def test_equal_coincidental_penalties_have_no_side_caption():
settings = {
"strength_regulation_skaters": 5,
"strength_min_skaters": 3,
"strength_state_labels": {"regulation": {"4x4": {"ru": "4 на 4"}}},
}
payload = HockeyDataService._strength_payload(
settings,
stage="regular",
current_period="2",
timer_state={"penalty_board": {"penalties": [_penalty("home", 100000), _penalty("away", 100000)]}},
language="ru",
)
assert payload["strength_label"] == "4×4"
assert payload["advantage_side"] == ""
assert payload["home_label"] == ""
assert payload["away_label"] == ""
def test_two_vs_one_penalties_caption_only_advantage_team():
settings = {
"strength_regulation_skaters": 5,
"strength_min_skaters": 3,
"strength_state_labels": {"regulation": {"4x3": {"ru": "Играют в большинстве"}}},
}
payload = HockeyDataService._strength_payload(
settings,
stage="regular",
current_period="2",
timer_state={"penalty_board": {"penalties": [
_penalty("home", 103000),
_penalty("home", 120000),
_penalty("away", 103000),
]}},
language="ru",
)
assert payload["strength_label"] == "3×4"
assert payload["advantage_side"] == "away"
assert payload["home_label"] == ""
assert payload["away_label"] == "Играют в большинстве"
def test_runtime_plan_uses_one_plate_and_global_shortest_transition_timer():
start = APP_JS.index("function penaltyDisplayEntriesByTargetSide")
end = APP_JS.index("function hockeyPenaltySideMappingDetail", start)
block = APP_JS[start:end]
assert 'const all = [...home, ...away].sort' in block
assert 'const transitionEntry = all[0] || null;' in block
assert 'home: advantageSide === "home" && transitionEntry ? [transitionEntry] : []' in block
assert 'away: advantageSide === "away" && transitionEntry ? [transitionEntry] : []' in block
assert 'if (!advantageSide)' in block
assert 'return { home: [], away: [], routedToAdvantage: false' in block
def test_final_full_strength_action_only_runs_after_last_penalty_and_real_advantage():
start = APP_JS.index("function fireConfiguredTimerFinishActions")
end = APP_JS.index("async function runShortcutSequenceStep", start)
block = APP_JS[start:end]
assert 'Number(meta.remaining_total || 0) > 0' in block
assert '!Boolean(meta.had_advantage)' in block
assert 'full_strength_side' in block
assert 'side !== fullStrengthSide' in block
def test_rebalance_sends_old_plate_out_before_new_plate_in():
start = APP_JS.index("async function rebalanceVmixPenaltyTargets")
end = APP_JS.index("function finishActionMatchesSource", start)
block = APP_JS[start:end]
assert 'const outCommands = [];' in block
assert 'const setCommands = [];' in block
assert 'const inCommands = [];' in block
assert 'const commands = [...outCommands, ...setCommands, ...inCommands];' in block