S1005403_RisCC/tests/gui/test_trajectory_editor_window.py

234 lines
6.4 KiB
Python

import types
from collections import namedtuple
import pytest
from target_simulator.gui import trajectory_editor_window as tew
class DummyVar:
def __init__(self, value=False):
self._value = value
def get(self):
return self._value
def set(self, v):
self._value = v
class FakeTree:
def __init__(self):
self.items = {}
self._focus = ""
def delete(self, *args, **kwargs):
self.items.clear()
def get_children(self):
return list(self.items.keys())
def insert(self, parent, pos, iid=None, values=None):
self.items[iid] = values
def see(self, item_id):
pass
def focus(self):
return self._focus
def focus_set(self, v):
self._focus = v
def selection_set(self, v):
self._focus = v
def config(self, **kwargs):
pass
class DummyLabel:
def __init__(self):
self.text = ""
def config(self, **kwargs):
self.text = kwargs.get("text", self.text)
def _make_window():
# Create instance without running __init__ (which blocks on wait_window)
inst = tew.TrajectoryEditorWindow.__new__(tew.TrajectoryEditorWindow)
inst.existing_ids = []
inst.result_target = None
inst.initial_max_range = 10
inst.time_multiplier = 1.0
inst.total_sim_time = 0.0
inst.waypoints = []
inst.use_spline_var = DummyVar(False)
inst.gui_update_queue = None
inst.preview_engine = None
inst.is_preview_running = DummyVar(False)
inst.is_paused = DummyVar(False)
inst.wp_tree = FakeTree()
inst.ppi_preview = types.SimpleNamespace(
draw_trajectory_preview=lambda **k: None, update_simulated_targets=lambda u: None
)
inst.sim_progress_var = DummyVar(0.0)
inst.sim_time_label = DummyLabel()
inst.time_multiplier_var = types.SimpleNamespace(get=lambda: "1x")
inst.multiplier_combo = types.SimpleNamespace(config=lambda **k: None)
inst.play_button = types.SimpleNamespace(config=lambda **k: None)
inst.pause_button = types.SimpleNamespace(config=lambda **k: None)
inst.stop_button = types.SimpleNamespace(config=lambda **k: None)
return inst
def test_on_spline_toggle_shows_info_when_too_few_waypoints(monkeypatch):
inst = _make_window()
inst.waypoints = [1, 2] # fewer than 4
inst.use_spline_var.set(True)
called = {}
def fake_showinfo(title, message, parent=None):
called["title"] = title
called["message"] = message
monkeypatch.setattr(tew.messagebox, "showinfo", fake_showinfo)
inst._on_spline_toggle()
assert called.get("title") == "Spline Not Available"
assert inst.use_spline_var.get() is False
def test_on_time_multiplier_changed_valid_and_invalid():
inst = _make_window()
inst.time_multiplier_var = types.SimpleNamespace(get=lambda: "2x")
inst.preview_engine = None
inst._on_time_multiplier_changed()
assert inst.time_multiplier == 2.0
inst.time_multiplier_var = types.SimpleNamespace(get=lambda: "bad")
inst._on_time_multiplier_changed()
assert inst.time_multiplier == 1.0
def test_on_ok_invalid_first_waypoint_shows_error(monkeypatch):
inst = _make_window()
inst.waypoints = []
captured = {}
def fake_showerror(title, message, parent=None):
captured["title"] = title
captured["message"] = message
monkeypatch.setattr(tew.messagebox, "showerror", fake_showerror)
inst._on_ok()
assert captured.get("title") == "Invalid Trajectory"
def test_on_remove_waypoint_no_selection_and_single_waypoint(monkeypatch):
inst = _make_window()
# No selection
inst.wp_tree._focus = ""
captured = {}
def fake_showwarning(title, message, parent=None):
captured["warn"] = (title, message)
monkeypatch.setattr(tew.messagebox, "showwarning", fake_showwarning)
inst._on_remove_waypoint()
assert captured.get("warn")[0] == "No Selection"
# Single waypoint present -> error on remove
inst.wp_tree._focus = "0"
inst.waypoints = [object()]
def fake_showerror(title, message, parent=None):
captured["err"] = (title, message)
monkeypatch.setattr(tew.messagebox, "showerror", fake_showerror)
inst._on_remove_waypoint()
assert captured.get("err")[0] == "Action Denied"
def test_populate_waypoint_list_and_get_total_time(monkeypatch):
inst = _make_window()
# Create dummy waypoint objects matching expected attributes
WP = namedtuple(
"WP",
[
"maneuver_type",
"target_range_nm",
"target_azimuth_deg",
"target_altitude_ft",
"target_velocity_fps",
"target_heading_deg",
"duration_s",
"longitudinal_acceleration_g",
"lateral_acceleration_g",
"vertical_acceleration_g",
"turn_direction",
],
)
wp1 = WP(
maneuver_type=tew.ManeuverType.FLY_TO_POINT,
target_range_nm=10.0,
target_azimuth_deg=90.0,
target_altitude_ft=1000.0,
target_velocity_fps=0.0,
target_heading_deg=0.0,
duration_s=0.0,
longitudinal_acceleration_g=0.0,
lateral_acceleration_g=0.0,
vertical_acceleration_g=0.0,
turn_direction=tew.TurnDirection.LEFT,
)
wp2 = WP(
maneuver_type=tew.ManeuverType.FLY_FOR_DURATION,
target_range_nm=0,
target_azimuth_deg=0,
target_altitude_ft=0,
target_velocity_fps=100.0,
target_heading_deg=45.0,
duration_s=12.5,
longitudinal_acceleration_g=0.0,
lateral_acceleration_g=0.0,
vertical_acceleration_g=0.0,
turn_direction=tew.TurnDirection.LEFT,
)
inst.waypoints = [wp1, wp2]
inst._populate_waypoint_list()
# Verify tree has two items inserted
assert len(inst.wp_tree.items) == 2
# Test _get_total_simulation_time by monkeypatching Target.generate_path_from_waypoints
def fake_generate(wps, use_spline):
return ([], 123.4)
monkeypatch.setattr(
tew.Target, "generate_path_from_waypoints", staticmethod(fake_generate)
)
inst.use_spline_var = DummyVar(False)
total = inst._get_total_simulation_time()
assert total == 123.4
import pytest
import tkinter as tk
from target_simulator.gui.trajectory_editor_window import TrajectoryEditorWindow
def test_trajectory_editor_window_init():
root = tk.Tk()
win = TrajectoryEditorWindow(root, existing_ids=[], max_range_nm=100)
assert win is not None
root.destroy()