""" Tests for PipelineIntrospectionSource. """ from engine.pipeline_sources.pipeline_introspection import PipelineIntrospectionSource class TestPipelineIntrospectionSource: """Tests for PipelineIntrospectionSource.""" def test_basic_init(self): """Source initializes with defaults.""" source = PipelineIntrospectionSource() assert source.name == "pipeline-inspect" assert source.is_dynamic is True assert source.frame == 0 def test_init_with_pipelines(self): """Source initializes with custom pipelines list.""" source = PipelineIntrospectionSource( pipelines=[], viewport_width=100, viewport_height=40 ) assert source.viewport_width == 100 assert source.viewport_height == 40 def test_inlet_outlet_types(self): """Source has correct inlet/outlet types.""" source = PipelineIntrospectionSource() # inlet should be NONE (source), outlet should be SOURCE_ITEMS from engine.pipeline.core import DataType assert DataType.NONE in source.inlet_types assert DataType.SOURCE_ITEMS in source.outlet_types def test_fetch_returns_items(self): """fetch() returns SourceItem list.""" source = PipelineIntrospectionSource() items = source.fetch() assert len(items) == 1 assert items[0].source == "pipeline-inspect" def test_fetch_increments_frame(self): """fetch() increments frame counter.""" source = PipelineIntrospectionSource() assert source.frame == 0 source.fetch() assert source.frame == 1 source.fetch() assert source.frame == 2 def test_get_items(self): """get_items() returns list of SourceItems.""" source = PipelineIntrospectionSource() items = source.get_items() assert isinstance(items, list) assert len(items) > 0 assert items[0].source == "pipeline-inspect" def test_add_pipeline(self): """add_pipeline() adds pipeline to list.""" source = PipelineIntrospectionSource() mock_pipeline = object() source.add_pipeline(mock_pipeline) assert mock_pipeline in source._pipelines def test_remove_pipeline(self): """remove_pipeline() removes pipeline from list.""" source = PipelineIntrospectionSource() mock_pipeline = object() source.add_pipeline(mock_pipeline) source.remove_pipeline(mock_pipeline) assert mock_pipeline not in source._pipelines class TestPipelineIntrospectionRender: """Tests for rendering methods.""" def test_render_header_no_pipelines(self): """_render_header returns default when no pipelines.""" source = PipelineIntrospectionSource() lines = source._render_header() assert len(lines) == 1 assert "PIPELINE INTROSPECTION" in lines[0] def test_render_bar(self): """_render_bar creates correct bar.""" source = PipelineIntrospectionSource() bar = source._render_bar(50, 10) assert len(bar) == 10 assert bar.count("█") == 5 assert bar.count("░") == 5 def test_render_bar_zero(self): """_render_bar handles zero percentage.""" source = PipelineIntrospectionSource() bar = source._render_bar(0, 10) assert bar == "░" * 10 def test_render_bar_full(self): """_render_bar handles 100%.""" source = PipelineIntrospectionSource() bar = source._render_bar(100, 10) assert bar == "█" * 10 def test_render_sparkline(self): """_render_sparkline creates sparkline.""" source = PipelineIntrospectionSource() values = [1.0, 2.0, 3.0, 4.0, 5.0] sparkline = source._render_sparkline(values, 10) assert len(sparkline) == 10 def test_render_sparkline_empty(self): """_render_sparkline handles empty values.""" source = PipelineIntrospectionSource() sparkline = source._render_sparkline([], 10) assert sparkline == " " * 10 def test_render_footer_no_pipelines(self): """_render_footer shows collecting data when no pipelines.""" source = PipelineIntrospectionSource() lines = source._render_footer() assert len(lines) >= 2 assert "collecting data" in lines[1] or "Frame Time" in lines[0] class TestPipelineIntrospectionFull: """Integration tests.""" def test_render_empty(self): """_render works with no pipelines.""" source = PipelineIntrospectionSource() lines = source._render() assert len(lines) > 0 assert "PIPELINE INTROSPECTION" in lines[0] def test_render_with_mock_pipeline(self): """_render works with mock pipeline.""" source = PipelineIntrospectionSource() class MockStage: category = "source" name = "test" class MockPipeline: stages = {"test": MockStage()} execution_order = ["test"] def get_metrics_summary(self): return {"stages": {"test": {"avg_ms": 1.5}}, "avg_ms": 2.0, "fps": 60} def get_frame_times(self): return [1.0, 2.0, 3.0] source.add_pipeline(MockPipeline()) lines = source._render() assert len(lines) > 0