import pytest import track_core as tc def running_info(color=None): info = tc.TrackInfo() info.color = color or tc.Color.green() info.id = 1 info.is_running = True info.num_segments = 1 return info def report(mileage): value = tc.TrackReport() value.id = 1 value.state = tc.TrackState.run value.mileage_m = mileage value.speed_m_s = 1.0 return value def config(draw_kind): value = tc.TrackConfig() value.draw_kind = draw_kind value.line_length_m = 10.0 value.active_line_length_m = 4.0 value.head_offset_m = 0.0 value.line_leds_num = 20 return value def test_circular_render_wraps(): plan = tc.make_render_plan( config(tc.TrackDrawKind.circular), running_info(tc.Color.green()), report(8.5), ) assert plan.span_count == 2 assert [(span.start_led, span.led_count, span.color) for span in plan.spans] == [ (17, 3, tc.Color.green()), (0, 5, tc.Color.green()), ] def test_linear_render_forward_pixels(): pixels = tc.render_pixels( config(tc.TrackDrawKind.linear), running_info(tc.Color.red()), report(5.0), ) assert len(pixels) == 20 assert pixels[6] == tc.Color.cyan() assert pixels[8] == tc.Color.red() assert pixels[10] == tc.Color.red() assert pixels[12] == tc.Color.blue() assert pixels[0] == tc.Color.black() def test_linear_render_reverse_spans(): cfg = config(tc.TrackDrawKind.linear) cfg.active_line_length_m = 5.0 plan = tc.make_render_plan(cfg, running_info(tc.Color.red()), report(15.0)) assert [(span.start_led, span.led_count, span.color) for span in plan.spans] == [ (5, 2, tc.Color.blue()), (7, 3, tc.Color.red()), (10, 3, tc.Color.red()), (13, 2, tc.Color.cyan()), ] def test_linear_render_boundary_sweep_does_not_raise(): cfg = config(tc.TrackDrawKind.linear) for mileage in ( -20.0, -10.1, -10.0, -9.9, -1.0, -0.1, 0.0, 0.1, 1.0, 9.9, 10.0, 10.1, 19.9, 20.0, 20.1, 29.9, 30.0, 30.1, 40.0, ): pixels = tc.render_pixels(cfg, running_info(tc.Color.red()), report(mileage)) assert len(pixels) == cfg.line_leds_num def test_not_running_renders_black_pixels(): info = running_info() info.is_running = False pixels = tc.render_pixels(config(tc.TrackDrawKind.circular), info, report(8.5)) assert len(pixels) == 20 assert all(pixel == tc.Color.black() for pixel in pixels) def test_invalid_config_raises_value_error(): cfg = config(tc.TrackDrawKind.circular) cfg.line_leds_num = 0 with pytest.raises(ValueError): tc.render_pixels(cfg, running_info(), report(0.0)) def st_segment(speed, time_s): segment = tc.STSegment() segment.speed_m_s = speed segment.time_since_start_s = time_s return segment def sm_segment(speed, mileage): segment = tc.SMSegment() segment.speed_m_s = speed segment.mileage_from_start_m = mileage return segment def mt_segment(mileage, time_s): segment = tc.MTSegment() segment.mileage_to_travel_this_segment_m = mileage segment.time_since_start_s = time_s return segment def test_pure_speed_time_runtime_ticks(): scheme = tc.make_speed_time_scheme( 7, tc.Color.green(), tc.AccelerationProfile.instant, [st_segment(1.0, 0), st_segment(3.0, 5), st_segment(1.0, 10)], ) runtime = tc.start_scheme_track(tc.make_scheme_track_runtime(scheme)) runtime = tc.tick_scheme_track(config(tc.TrackDrawKind.circular), runtime, 6.0) state = runtime.state report = runtime.report() assert state.primary_segment_index == 1 assert report.state == tc.TrackState.run assert report.speed_m_s == pytest.approx(3.0) assert report.mileage_m == pytest.approx(6.0) def test_training_runtime_accepts_all_scheme_kinds_and_renders(): runtime = tc.SchemeTrainingRuntime() runtime.add_scheme( tc.make_speed_mileage_scheme( 1, tc.Color.red(), tc.AccelerationProfile.instant, [sm_segment(1.0, 0), sm_segment(2.0, 5), sm_segment(1.0, 10)], ) ) runtime.add_scheme( tc.make_mileage_time_scheme( 2, tc.Color.green(), tc.AccelerationProfile.instant, [mt_segment(10, 0), mt_segment(20, 5), mt_segment(1, 15)], ) ) runtime.add_scheme( tc.make_speed_time_scheme( 3, tc.Color.blue(), tc.AccelerationProfile.instant, [st_segment(1.0, 0), st_segment(1.0, 10)], ) ) repeated = tc.RepeatedSMSegment() repeated.time_since_start_s = 0 repeated.speed_mileage_segments = [sm_segment(1.0, 0), sm_segment(2.0, 5)] repeated_end = tc.RepeatedSMSegment() repeated_end.time_since_start_s = 20 repeated_end.speed_mileage_segments = [sm_segment(1.0, 0), sm_segment(1.0, 5)] runtime.add_scheme( tc.make_repeated_speed_mileage_time_scheme( 4, tc.Color.white(), tc.AccelerationProfile.instant, [repeated, repeated_end], ) ) runtime.start() runtime.tick(config(tc.TrackDrawKind.circular), 1.0) pixels = runtime.render_pixels(config(tc.TrackDrawKind.circular)) assert runtime.has_program() assert not runtime.all_stopped() assert len(runtime.state_collection()) == 4 assert len(runtime.scheme_status()) == 4 assert len(pixels) == 20