yamlgraph 0.1.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of yamlgraph might be problematic. Click here for more details.
- examples/__init__.py +1 -0
- examples/storyboard/__init__.py +1 -0
- examples/storyboard/generate_videos.py +335 -0
- examples/storyboard/nodes/__init__.py +10 -0
- examples/storyboard/nodes/animated_character_node.py +248 -0
- examples/storyboard/nodes/animated_image_node.py +138 -0
- examples/storyboard/nodes/character_node.py +162 -0
- examples/storyboard/nodes/image_node.py +118 -0
- examples/storyboard/nodes/replicate_tool.py +238 -0
- examples/storyboard/retry_images.py +118 -0
- tests/__init__.py +1 -0
- tests/conftest.py +178 -0
- tests/integration/__init__.py +1 -0
- tests/integration/test_animated_storyboard.py +63 -0
- tests/integration/test_cli_commands.py +242 -0
- tests/integration/test_map_demo.py +50 -0
- tests/integration/test_memory_demo.py +281 -0
- tests/integration/test_pipeline_flow.py +105 -0
- tests/integration/test_providers.py +163 -0
- tests/integration/test_resume.py +75 -0
- tests/unit/__init__.py +1 -0
- tests/unit/test_agent_nodes.py +200 -0
- tests/unit/test_checkpointer.py +212 -0
- tests/unit/test_cli.py +121 -0
- tests/unit/test_cli_package.py +81 -0
- tests/unit/test_compile_graph_map.py +132 -0
- tests/unit/test_conditions_routing.py +253 -0
- tests/unit/test_config.py +93 -0
- tests/unit/test_conversation_memory.py +270 -0
- tests/unit/test_database.py +145 -0
- tests/unit/test_deprecation.py +104 -0
- tests/unit/test_executor.py +60 -0
- tests/unit/test_executor_async.py +179 -0
- tests/unit/test_export.py +150 -0
- tests/unit/test_expressions.py +178 -0
- tests/unit/test_format_prompt.py +145 -0
- tests/unit/test_generic_report.py +200 -0
- tests/unit/test_graph_commands.py +327 -0
- tests/unit/test_graph_loader.py +299 -0
- tests/unit/test_graph_schema.py +193 -0
- tests/unit/test_inline_schema.py +151 -0
- tests/unit/test_issues.py +164 -0
- tests/unit/test_jinja2_prompts.py +85 -0
- tests/unit/test_langsmith.py +319 -0
- tests/unit/test_llm_factory.py +109 -0
- tests/unit/test_llm_factory_async.py +118 -0
- tests/unit/test_loops.py +403 -0
- tests/unit/test_map_node.py +144 -0
- tests/unit/test_no_backward_compat.py +56 -0
- tests/unit/test_node_factory.py +225 -0
- tests/unit/test_prompts.py +166 -0
- tests/unit/test_python_nodes.py +198 -0
- tests/unit/test_reliability.py +298 -0
- tests/unit/test_result_export.py +234 -0
- tests/unit/test_router.py +296 -0
- tests/unit/test_sanitize.py +99 -0
- tests/unit/test_schema_loader.py +295 -0
- tests/unit/test_shell_tools.py +229 -0
- tests/unit/test_state_builder.py +331 -0
- tests/unit/test_state_builder_map.py +104 -0
- tests/unit/test_state_config.py +197 -0
- tests/unit/test_template.py +190 -0
- tests/unit/test_tool_nodes.py +129 -0
- yamlgraph/__init__.py +35 -0
- yamlgraph/builder.py +110 -0
- yamlgraph/cli/__init__.py +139 -0
- yamlgraph/cli/__main__.py +6 -0
- yamlgraph/cli/commands.py +232 -0
- yamlgraph/cli/deprecation.py +92 -0
- yamlgraph/cli/graph_commands.py +382 -0
- yamlgraph/cli/validators.py +37 -0
- yamlgraph/config.py +67 -0
- yamlgraph/constants.py +66 -0
- yamlgraph/error_handlers.py +226 -0
- yamlgraph/executor.py +275 -0
- yamlgraph/executor_async.py +122 -0
- yamlgraph/graph_loader.py +337 -0
- yamlgraph/map_compiler.py +138 -0
- yamlgraph/models/__init__.py +36 -0
- yamlgraph/models/graph_schema.py +141 -0
- yamlgraph/models/schemas.py +124 -0
- yamlgraph/models/state_builder.py +236 -0
- yamlgraph/node_factory.py +240 -0
- yamlgraph/routing.py +87 -0
- yamlgraph/schema_loader.py +160 -0
- yamlgraph/storage/__init__.py +17 -0
- yamlgraph/storage/checkpointer.py +72 -0
- yamlgraph/storage/database.py +320 -0
- yamlgraph/storage/export.py +269 -0
- yamlgraph/tools/__init__.py +1 -0
- yamlgraph/tools/agent.py +235 -0
- yamlgraph/tools/nodes.py +124 -0
- yamlgraph/tools/python_tool.py +178 -0
- yamlgraph/tools/shell.py +205 -0
- yamlgraph/utils/__init__.py +47 -0
- yamlgraph/utils/conditions.py +157 -0
- yamlgraph/utils/expressions.py +111 -0
- yamlgraph/utils/langsmith.py +308 -0
- yamlgraph/utils/llm_factory.py +118 -0
- yamlgraph/utils/llm_factory_async.py +105 -0
- yamlgraph/utils/logging.py +127 -0
- yamlgraph/utils/prompts.py +116 -0
- yamlgraph/utils/sanitize.py +98 -0
- yamlgraph/utils/template.py +102 -0
- yamlgraph/utils/validators.py +181 -0
- yamlgraph-0.1.1.dist-info/METADATA +854 -0
- yamlgraph-0.1.1.dist-info/RECORD +111 -0
- yamlgraph-0.1.1.dist-info/WHEEL +5 -0
- yamlgraph-0.1.1.dist-info/entry_points.txt +2 -0
- yamlgraph-0.1.1.dist-info/licenses/LICENSE +21 -0
- yamlgraph-0.1.1.dist-info/top_level.txt +3 -0
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
"""Tests for Phase 6.5: Generic Report Schema.
|
|
2
|
+
|
|
3
|
+
Tests for flexible GenericReport model that works for most analysis/summary tasks.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import pytest
|
|
7
|
+
from pydantic import ValidationError
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class TestGenericReportSchema:
|
|
11
|
+
"""Tests for GenericReport model."""
|
|
12
|
+
|
|
13
|
+
def test_generic_report_exists(self):
|
|
14
|
+
"""GenericReport model is importable."""
|
|
15
|
+
from yamlgraph.models.schemas import GenericReport
|
|
16
|
+
|
|
17
|
+
assert GenericReport is not None
|
|
18
|
+
|
|
19
|
+
def test_minimal_report(self):
|
|
20
|
+
"""Report works with just title and summary."""
|
|
21
|
+
from yamlgraph.models.schemas import GenericReport
|
|
22
|
+
|
|
23
|
+
report = GenericReport(
|
|
24
|
+
title="Test Report",
|
|
25
|
+
summary="A brief summary of findings.",
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
assert report.title == "Test Report"
|
|
29
|
+
assert report.summary == "A brief summary of findings."
|
|
30
|
+
|
|
31
|
+
def test_report_with_sections(self):
|
|
32
|
+
"""Sections field accepts arbitrary dict content."""
|
|
33
|
+
from yamlgraph.models.schemas import GenericReport
|
|
34
|
+
|
|
35
|
+
report = GenericReport(
|
|
36
|
+
title="Report",
|
|
37
|
+
summary="Summary",
|
|
38
|
+
sections={
|
|
39
|
+
"overview": "First section content",
|
|
40
|
+
"details": {"nested": "data", "count": 42},
|
|
41
|
+
"items": ["a", "b", "c"],
|
|
42
|
+
},
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
assert report.sections["overview"] == "First section content"
|
|
46
|
+
assert report.sections["details"]["count"] == 42
|
|
47
|
+
assert len(report.sections["items"]) == 3
|
|
48
|
+
|
|
49
|
+
def test_report_with_findings(self):
|
|
50
|
+
"""Findings field is list of strings."""
|
|
51
|
+
from yamlgraph.models.schemas import GenericReport
|
|
52
|
+
|
|
53
|
+
report = GenericReport(
|
|
54
|
+
title="Report",
|
|
55
|
+
summary="Summary",
|
|
56
|
+
findings=["Finding 1", "Finding 2", "Finding 3"],
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
assert len(report.findings) == 3
|
|
60
|
+
assert "Finding 1" in report.findings
|
|
61
|
+
|
|
62
|
+
def test_report_with_recommendations(self):
|
|
63
|
+
"""Recommendations field is list of strings."""
|
|
64
|
+
from yamlgraph.models.schemas import GenericReport
|
|
65
|
+
|
|
66
|
+
report = GenericReport(
|
|
67
|
+
title="Report",
|
|
68
|
+
summary="Summary",
|
|
69
|
+
recommendations=["Action 1", "Action 2"],
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
assert len(report.recommendations) == 2
|
|
73
|
+
|
|
74
|
+
def test_report_with_metadata(self):
|
|
75
|
+
"""Metadata field accepts arbitrary key-value data."""
|
|
76
|
+
from yamlgraph.models.schemas import GenericReport
|
|
77
|
+
|
|
78
|
+
report = GenericReport(
|
|
79
|
+
title="Report",
|
|
80
|
+
summary="Summary",
|
|
81
|
+
metadata={
|
|
82
|
+
"author": "Test Author",
|
|
83
|
+
"version": 1.0,
|
|
84
|
+
"tags": ["a", "b"],
|
|
85
|
+
},
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
assert report.metadata["author"] == "Test Author"
|
|
89
|
+
assert report.metadata["version"] == 1.0
|
|
90
|
+
|
|
91
|
+
def test_defaults_are_empty(self):
|
|
92
|
+
"""Optional fields default to empty collections."""
|
|
93
|
+
from yamlgraph.models.schemas import GenericReport
|
|
94
|
+
|
|
95
|
+
report = GenericReport(title="Report", summary="Summary")
|
|
96
|
+
|
|
97
|
+
assert report.sections == {}
|
|
98
|
+
assert report.findings == []
|
|
99
|
+
assert report.recommendations == []
|
|
100
|
+
assert report.metadata == {}
|
|
101
|
+
|
|
102
|
+
def test_title_is_required(self):
|
|
103
|
+
"""Title field is required."""
|
|
104
|
+
from yamlgraph.models.schemas import GenericReport
|
|
105
|
+
|
|
106
|
+
with pytest.raises(ValidationError) as exc_info:
|
|
107
|
+
GenericReport(summary="Summary")
|
|
108
|
+
|
|
109
|
+
errors = exc_info.value.errors()
|
|
110
|
+
assert any(e["loc"] == ("title",) for e in errors)
|
|
111
|
+
|
|
112
|
+
def test_summary_is_required(self):
|
|
113
|
+
"""Summary field is required."""
|
|
114
|
+
from yamlgraph.models.schemas import GenericReport
|
|
115
|
+
|
|
116
|
+
with pytest.raises(ValidationError) as exc_info:
|
|
117
|
+
GenericReport(title="Title")
|
|
118
|
+
|
|
119
|
+
errors = exc_info.value.errors()
|
|
120
|
+
assert any(e["loc"] == ("summary",) for e in errors)
|
|
121
|
+
|
|
122
|
+
def test_model_serializes_to_dict(self):
|
|
123
|
+
"""Report serializes to dictionary."""
|
|
124
|
+
from yamlgraph.models.schemas import GenericReport
|
|
125
|
+
|
|
126
|
+
report = GenericReport(
|
|
127
|
+
title="Test",
|
|
128
|
+
summary="Summary",
|
|
129
|
+
findings=["A", "B"],
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
data = report.model_dump()
|
|
133
|
+
|
|
134
|
+
assert data["title"] == "Test"
|
|
135
|
+
assert data["summary"] == "Summary"
|
|
136
|
+
assert data["findings"] == ["A", "B"]
|
|
137
|
+
|
|
138
|
+
def test_model_serializes_to_json(self):
|
|
139
|
+
"""Report serializes to JSON string."""
|
|
140
|
+
import json
|
|
141
|
+
|
|
142
|
+
from yamlgraph.models.schemas import GenericReport
|
|
143
|
+
|
|
144
|
+
report = GenericReport(title="Test", summary="Summary")
|
|
145
|
+
|
|
146
|
+
json_str = report.model_dump_json()
|
|
147
|
+
data = json.loads(json_str)
|
|
148
|
+
|
|
149
|
+
assert data["title"] == "Test"
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
class TestGenericReportUseCases:
|
|
153
|
+
"""Verify GenericReport works for common analysis patterns."""
|
|
154
|
+
|
|
155
|
+
def test_git_analysis_report(self):
|
|
156
|
+
"""GenericReport works for git analysis output."""
|
|
157
|
+
from yamlgraph.models.schemas import GenericReport
|
|
158
|
+
|
|
159
|
+
report = GenericReport(
|
|
160
|
+
title="Git Repository Analysis",
|
|
161
|
+
summary="Analysis of recent activity in the repository.",
|
|
162
|
+
sections={
|
|
163
|
+
"commit_summary": "15 commits in last 7 days",
|
|
164
|
+
"authors": ["alice", "bob", "carol"],
|
|
165
|
+
},
|
|
166
|
+
findings=[
|
|
167
|
+
"High activity in src/core module",
|
|
168
|
+
"No tests for new features",
|
|
169
|
+
"Breaking changes in v2.0",
|
|
170
|
+
],
|
|
171
|
+
recommendations=[
|
|
172
|
+
"Add tests for recent changes",
|
|
173
|
+
"Review breaking changes before release",
|
|
174
|
+
],
|
|
175
|
+
metadata={
|
|
176
|
+
"repo": "langgraph-showcase",
|
|
177
|
+
"analyzed_at": "2024-01-01T00:00:00",
|
|
178
|
+
},
|
|
179
|
+
)
|
|
180
|
+
|
|
181
|
+
assert "Git Repository" in report.title
|
|
182
|
+
assert len(report.findings) == 3
|
|
183
|
+
assert report.metadata["repo"] == "langgraph-showcase"
|
|
184
|
+
|
|
185
|
+
def test_api_analysis_report(self):
|
|
186
|
+
"""GenericReport works for API analysis output."""
|
|
187
|
+
from yamlgraph.models.schemas import GenericReport
|
|
188
|
+
|
|
189
|
+
report = GenericReport(
|
|
190
|
+
title="API Performance Report",
|
|
191
|
+
summary="Performance analysis of API endpoints.",
|
|
192
|
+
sections={
|
|
193
|
+
"latency": {"p50": 45, "p95": 120, "p99": 250},
|
|
194
|
+
"errors": {"rate": 0.02, "top_errors": ["500", "429"]},
|
|
195
|
+
},
|
|
196
|
+
findings=["High latency on /search endpoint"],
|
|
197
|
+
recommendations=["Add caching for /search"],
|
|
198
|
+
)
|
|
199
|
+
|
|
200
|
+
assert report.sections["latency"]["p95"] == 120
|
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
"""Tests for universal graph runner (Phase 7.2).
|
|
2
|
+
|
|
3
|
+
TDD tests for `yamlgraph graph run <path>` command.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import argparse
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from unittest.mock import MagicMock, patch
|
|
9
|
+
|
|
10
|
+
import pytest
|
|
11
|
+
|
|
12
|
+
# =============================================================================
|
|
13
|
+
# graph subcommand tests
|
|
14
|
+
# =============================================================================
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class TestGraphSubcommand:
|
|
18
|
+
"""Tests for graph subcommand group."""
|
|
19
|
+
|
|
20
|
+
def test_graph_subparser_exists(self):
|
|
21
|
+
"""graph subparser should be configured."""
|
|
22
|
+
from yamlgraph.cli import create_parser
|
|
23
|
+
|
|
24
|
+
parser = create_parser()
|
|
25
|
+
# Parse with graph command
|
|
26
|
+
args = parser.parse_args(["graph", "list"])
|
|
27
|
+
assert args.command == "graph"
|
|
28
|
+
|
|
29
|
+
def test_graph_run_subcommand_exists(self):
|
|
30
|
+
"""graph run subcommand should exist."""
|
|
31
|
+
from yamlgraph.cli import create_parser
|
|
32
|
+
|
|
33
|
+
parser = create_parser()
|
|
34
|
+
args = parser.parse_args(
|
|
35
|
+
["graph", "run", "graphs/yamlgraph.yaml", "--var", "topic=AI"]
|
|
36
|
+
)
|
|
37
|
+
assert args.graph_command == "run"
|
|
38
|
+
assert args.graph_path == "graphs/yamlgraph.yaml"
|
|
39
|
+
|
|
40
|
+
def test_graph_list_subcommand_exists(self):
|
|
41
|
+
"""graph list subcommand should exist."""
|
|
42
|
+
from yamlgraph.cli import create_parser
|
|
43
|
+
|
|
44
|
+
parser = create_parser()
|
|
45
|
+
args = parser.parse_args(["graph", "list"])
|
|
46
|
+
assert args.graph_command == "list"
|
|
47
|
+
|
|
48
|
+
def test_graph_info_subcommand_exists(self):
|
|
49
|
+
"""graph info subcommand should exist."""
|
|
50
|
+
from yamlgraph.cli import create_parser
|
|
51
|
+
|
|
52
|
+
parser = create_parser()
|
|
53
|
+
args = parser.parse_args(["graph", "info", "graphs/yamlgraph.yaml"])
|
|
54
|
+
assert args.graph_command == "info"
|
|
55
|
+
assert args.graph_path == "graphs/yamlgraph.yaml"
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
# =============================================================================
|
|
59
|
+
# graph run argument parsing tests
|
|
60
|
+
# =============================================================================
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
class TestGraphRunArgs:
|
|
64
|
+
"""Tests for graph run argument parsing."""
|
|
65
|
+
|
|
66
|
+
def test_var_single_value(self):
|
|
67
|
+
"""--var key=value should parse correctly."""
|
|
68
|
+
from yamlgraph.cli import create_parser
|
|
69
|
+
|
|
70
|
+
parser = create_parser()
|
|
71
|
+
args = parser.parse_args(
|
|
72
|
+
["graph", "run", "graphs/test.yaml", "--var", "topic=AI"]
|
|
73
|
+
)
|
|
74
|
+
assert args.var == ["topic=AI"]
|
|
75
|
+
|
|
76
|
+
def test_var_multiple_values(self):
|
|
77
|
+
"""Multiple --var flags should accumulate."""
|
|
78
|
+
from yamlgraph.cli import create_parser
|
|
79
|
+
|
|
80
|
+
parser = create_parser()
|
|
81
|
+
args = parser.parse_args(
|
|
82
|
+
[
|
|
83
|
+
"graph",
|
|
84
|
+
"run",
|
|
85
|
+
"graphs/test.yaml",
|
|
86
|
+
"--var",
|
|
87
|
+
"topic=AI",
|
|
88
|
+
"--var",
|
|
89
|
+
"style=casual",
|
|
90
|
+
]
|
|
91
|
+
)
|
|
92
|
+
assert args.var == ["topic=AI", "style=casual"]
|
|
93
|
+
|
|
94
|
+
def test_thread_argument(self):
|
|
95
|
+
"""--thread should set thread ID."""
|
|
96
|
+
from yamlgraph.cli import create_parser
|
|
97
|
+
|
|
98
|
+
parser = create_parser()
|
|
99
|
+
args = parser.parse_args(
|
|
100
|
+
["graph", "run", "graphs/test.yaml", "--thread", "abc123"]
|
|
101
|
+
)
|
|
102
|
+
assert args.thread == "abc123"
|
|
103
|
+
|
|
104
|
+
def test_export_flag(self):
|
|
105
|
+
"""--export flag should enable export."""
|
|
106
|
+
from yamlgraph.cli import create_parser
|
|
107
|
+
|
|
108
|
+
parser = create_parser()
|
|
109
|
+
args = parser.parse_args(["graph", "run", "graphs/test.yaml", "--export"])
|
|
110
|
+
assert args.export is True
|
|
111
|
+
|
|
112
|
+
def test_graph_path_required(self):
|
|
113
|
+
"""graph run requires a path argument."""
|
|
114
|
+
from yamlgraph.cli import create_parser
|
|
115
|
+
|
|
116
|
+
parser = create_parser()
|
|
117
|
+
with pytest.raises(SystemExit):
|
|
118
|
+
parser.parse_args(["graph", "run"])
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
# =============================================================================
|
|
122
|
+
# parse_vars helper tests
|
|
123
|
+
# =============================================================================
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
class TestParseVars:
|
|
127
|
+
"""Tests for --var parsing helper."""
|
|
128
|
+
|
|
129
|
+
def test_parse_single_var(self):
|
|
130
|
+
"""Single var should parse to dict."""
|
|
131
|
+
from yamlgraph.cli.graph_commands import parse_vars
|
|
132
|
+
|
|
133
|
+
result = parse_vars(["topic=AI"])
|
|
134
|
+
assert result == {"topic": "AI"}
|
|
135
|
+
|
|
136
|
+
def test_parse_multiple_vars(self):
|
|
137
|
+
"""Multiple vars should parse to dict."""
|
|
138
|
+
from yamlgraph.cli.graph_commands import parse_vars
|
|
139
|
+
|
|
140
|
+
result = parse_vars(["topic=AI", "style=casual", "count=5"])
|
|
141
|
+
assert result == {"topic": "AI", "style": "casual", "count": "5"}
|
|
142
|
+
|
|
143
|
+
def test_parse_empty_list(self):
|
|
144
|
+
"""Empty list returns empty dict."""
|
|
145
|
+
from yamlgraph.cli.graph_commands import parse_vars
|
|
146
|
+
|
|
147
|
+
result = parse_vars([])
|
|
148
|
+
assert result == {}
|
|
149
|
+
|
|
150
|
+
def test_parse_none_returns_empty(self):
|
|
151
|
+
"""None returns empty dict."""
|
|
152
|
+
from yamlgraph.cli.graph_commands import parse_vars
|
|
153
|
+
|
|
154
|
+
result = parse_vars(None)
|
|
155
|
+
assert result == {}
|
|
156
|
+
|
|
157
|
+
def test_parse_value_with_equals(self):
|
|
158
|
+
"""Value containing = should preserve it."""
|
|
159
|
+
from yamlgraph.cli.graph_commands import parse_vars
|
|
160
|
+
|
|
161
|
+
result = parse_vars(["equation=a=b+c"])
|
|
162
|
+
assert result == {"equation": "a=b+c"}
|
|
163
|
+
|
|
164
|
+
def test_parse_invalid_format_raises(self):
|
|
165
|
+
"""Invalid format (no =) should raise ValueError."""
|
|
166
|
+
from yamlgraph.cli.graph_commands import parse_vars
|
|
167
|
+
|
|
168
|
+
with pytest.raises(ValueError, match="Invalid"):
|
|
169
|
+
parse_vars(["invalid"])
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
# =============================================================================
|
|
173
|
+
# cmd_graph_run tests
|
|
174
|
+
# =============================================================================
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
class TestCmdGraphRun:
|
|
178
|
+
"""Tests for cmd_graph_run function."""
|
|
179
|
+
|
|
180
|
+
def test_cmd_graph_run_exists(self):
|
|
181
|
+
"""cmd_graph_run function should exist."""
|
|
182
|
+
from yamlgraph.cli.graph_commands import cmd_graph_run
|
|
183
|
+
|
|
184
|
+
assert callable(cmd_graph_run)
|
|
185
|
+
|
|
186
|
+
def test_graph_not_found_error(self):
|
|
187
|
+
"""Should error if graph file doesn't exist."""
|
|
188
|
+
from yamlgraph.cli.graph_commands import cmd_graph_run
|
|
189
|
+
|
|
190
|
+
args = argparse.Namespace(
|
|
191
|
+
graph_path="nonexistent.yaml",
|
|
192
|
+
var=[],
|
|
193
|
+
thread=None,
|
|
194
|
+
export=False,
|
|
195
|
+
)
|
|
196
|
+
|
|
197
|
+
with pytest.raises(SystemExit):
|
|
198
|
+
cmd_graph_run(args)
|
|
199
|
+
|
|
200
|
+
@patch("yamlgraph.graph_loader.load_and_compile")
|
|
201
|
+
def test_invokes_graph_with_vars(self, mock_load):
|
|
202
|
+
"""Should invoke graph with parsed vars as initial state."""
|
|
203
|
+
from yamlgraph.cli.graph_commands import cmd_graph_run
|
|
204
|
+
|
|
205
|
+
mock_graph = MagicMock()
|
|
206
|
+
mock_app = MagicMock()
|
|
207
|
+
mock_app.invoke.return_value = {"result": "success"}
|
|
208
|
+
mock_graph.compile.return_value = mock_app
|
|
209
|
+
mock_load.return_value = mock_graph
|
|
210
|
+
|
|
211
|
+
args = argparse.Namespace(
|
|
212
|
+
graph_path="graphs/yamlgraph.yaml",
|
|
213
|
+
var=["topic=AI", "style=casual"],
|
|
214
|
+
thread=None,
|
|
215
|
+
export=False,
|
|
216
|
+
)
|
|
217
|
+
|
|
218
|
+
# Mock Path.exists
|
|
219
|
+
with patch.object(Path, "exists", return_value=True):
|
|
220
|
+
cmd_graph_run(args)
|
|
221
|
+
|
|
222
|
+
mock_app.invoke.assert_called_once()
|
|
223
|
+
call_args = mock_app.invoke.call_args[0][0]
|
|
224
|
+
assert call_args["topic"] == "AI"
|
|
225
|
+
assert call_args["style"] == "casual"
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
# =============================================================================
|
|
229
|
+
# cmd_graph_list tests
|
|
230
|
+
# =============================================================================
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
class TestCmdGraphList:
|
|
234
|
+
"""Tests for cmd_graph_list function."""
|
|
235
|
+
|
|
236
|
+
def test_cmd_graph_list_exists(self):
|
|
237
|
+
"""cmd_graph_list function should exist."""
|
|
238
|
+
from yamlgraph.cli.graph_commands import cmd_graph_list
|
|
239
|
+
|
|
240
|
+
assert callable(cmd_graph_list)
|
|
241
|
+
|
|
242
|
+
@patch("yamlgraph.cli.graph_commands.Path")
|
|
243
|
+
def test_lists_yaml_files(self, mock_path):
|
|
244
|
+
"""Should list all .yaml files in graphs/."""
|
|
245
|
+
from yamlgraph.cli.graph_commands import cmd_graph_list
|
|
246
|
+
|
|
247
|
+
mock_graphs_dir = MagicMock()
|
|
248
|
+
mock_path.return_value = mock_graphs_dir
|
|
249
|
+
mock_graphs_dir.exists.return_value = True
|
|
250
|
+
mock_graphs_dir.glob.return_value = [
|
|
251
|
+
Path("graphs/yamlgraph.yaml"),
|
|
252
|
+
Path("graphs/router-demo.yaml"),
|
|
253
|
+
]
|
|
254
|
+
|
|
255
|
+
args = argparse.Namespace()
|
|
256
|
+
|
|
257
|
+
with patch("builtins.print") as mock_print:
|
|
258
|
+
cmd_graph_list(args)
|
|
259
|
+
# Check it printed something about the graphs
|
|
260
|
+
calls = [str(c) for c in mock_print.call_args_list]
|
|
261
|
+
assert any("yamlgraph" in c for c in calls)
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
# =============================================================================
|
|
265
|
+
# cmd_graph_info tests
|
|
266
|
+
# =============================================================================
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
class TestCmdGraphInfo:
|
|
270
|
+
"""Tests for cmd_graph_info function."""
|
|
271
|
+
|
|
272
|
+
def test_cmd_graph_info_exists(self):
|
|
273
|
+
"""cmd_graph_info function should exist."""
|
|
274
|
+
from yamlgraph.cli.graph_commands import cmd_graph_info
|
|
275
|
+
|
|
276
|
+
assert callable(cmd_graph_info)
|
|
277
|
+
|
|
278
|
+
def test_info_file_not_found(self):
|
|
279
|
+
"""Should error if graph file doesn't exist."""
|
|
280
|
+
from yamlgraph.cli.graph_commands import cmd_graph_info
|
|
281
|
+
|
|
282
|
+
args = argparse.Namespace(graph_path="nonexistent.yaml")
|
|
283
|
+
|
|
284
|
+
with pytest.raises(SystemExit):
|
|
285
|
+
cmd_graph_info(args)
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
# =============================================================================
|
|
289
|
+
# cmd_graph_validate tests
|
|
290
|
+
# =============================================================================
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
class TestCmdGraphValidate:
|
|
294
|
+
"""Tests for cmd_graph_validate function."""
|
|
295
|
+
|
|
296
|
+
def test_cmd_graph_validate_exists(self):
|
|
297
|
+
"""cmd_graph_validate function should exist."""
|
|
298
|
+
from yamlgraph.cli.graph_commands import cmd_graph_validate
|
|
299
|
+
|
|
300
|
+
assert callable(cmd_graph_validate)
|
|
301
|
+
|
|
302
|
+
def test_validate_file_not_found(self):
|
|
303
|
+
"""Should error if graph file doesn't exist."""
|
|
304
|
+
from yamlgraph.cli.graph_commands import cmd_graph_validate
|
|
305
|
+
|
|
306
|
+
args = argparse.Namespace(graph_path="nonexistent.yaml")
|
|
307
|
+
|
|
308
|
+
with pytest.raises(SystemExit):
|
|
309
|
+
cmd_graph_validate(args)
|
|
310
|
+
|
|
311
|
+
def test_validate_valid_graph(self):
|
|
312
|
+
"""Should validate a correct graph without errors."""
|
|
313
|
+
from yamlgraph.cli.graph_commands import cmd_graph_validate
|
|
314
|
+
|
|
315
|
+
args = argparse.Namespace(graph_path="graphs/yamlgraph.yaml")
|
|
316
|
+
|
|
317
|
+
# Should not raise
|
|
318
|
+
cmd_graph_validate(args)
|
|
319
|
+
|
|
320
|
+
def test_validate_subparser_exists(self):
|
|
321
|
+
"""graph validate subcommand should exist."""
|
|
322
|
+
from yamlgraph.cli import create_parser
|
|
323
|
+
|
|
324
|
+
parser = create_parser()
|
|
325
|
+
args = parser.parse_args(["graph", "validate", "graphs/yamlgraph.yaml"])
|
|
326
|
+
assert args.graph_command == "validate"
|
|
327
|
+
assert args.graph_path == "graphs/yamlgraph.yaml"
|