From 05002b766b193d5780275eb1c828e1ea2c276124 Mon Sep 17 00:00:00 2001 From: rob Date: Thu, 30 Oct 2025 16:20:42 -0300 Subject: [PATCH] test: Add comprehensive workflow tests and improve template tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Testing improvements completing Week 1 consolidation: 1. Add tests/test_workflow.py (6 comprehensive tests) - test_extract_vote_value: Vote value extraction - test_parse_votes_single_participant_single_vote: Basic parsing - test_parse_votes_single_participant_multiple_votes: Latest vote wins - test_parse_votes_multiple_participants: Multi-participant tracking - test_parse_votes_malformed_lines: Error handling - test_parse_votes_mixed_content: Real-world scenarios 2. Improve tests/test_template_meta.py - Replace stub tests with real implementations - test_find_template_fields: Field extraction from templates - test_render_request_from_template: Template rendering - test_render_request_from_template_with_existing_meta: Preserve existing data 3. Add __init__.py files for test imports - assets/__init__.py: Make assets importable - automation/__init__.py: Make automation importable - Enables tests to import workflow.py and create_feature.py 4. Update pyproject.toml pytest configuration - Add ".", "assets" to pythonpath - Allows tests to import from automation/ and assets/ Test Results: - All 11 tests passing - Coverage: workflow vote parsing, template rendering, utils - Foundation ready for Stage 2 development 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- assets/__init__.py | 0 automation/__init__.py | 0 pyproject.toml | 2 +- tests/test_template_meta.py | 83 ++++++++++++++++++++++++++++++++++--- tests/test_workflow.py | 82 ++++++++++++++++++++++++++++++++++++ 5 files changed, 160 insertions(+), 7 deletions(-) create mode 100644 assets/__init__.py create mode 100644 automation/__init__.py create mode 100644 tests/test_workflow.py diff --git a/assets/__init__.py b/assets/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/automation/__init__.py b/automation/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pyproject.toml b/pyproject.toml index 815999d..7b44812 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -21,4 +21,4 @@ packages = ["cascadingdev"] version = { file = "VERSION" } [tool.pytest.ini_options] -pythonpath = ["src"] +pythonpath = ["src", ".", "assets"] diff --git a/tests/test_template_meta.py b/tests/test_template_meta.py index dfb877c..c312b5d 100644 --- a/tests/test_template_meta.py +++ b/tests/test_template_meta.py @@ -1,10 +1,81 @@ # tests/test_template_meta.py import pytest +from assets.runtime.create_feature import find_template_fields, render_request_from_template -def test_load_template_with_meta(): - # Test META parsing - assert True +def test_find_template_fields(): + template_content = """ +# Feature Request + +**Title**: +**Intent**: <one paragraph describing purpose> +**Motivation / Problem**: <why this is needed now> +**Feature ID**: <will be generated> +**Meta**: <will be generated> +**Author**: <name> +""" + fields = find_template_fields(template_content) + expected_fields = [ + ("Title", "<title>"), + ("Intent", "<one paragraph describing purpose>"), + ("Motivation / Problem", "<why this is needed now>"), + ("Author", "<name>") + ] + assert fields == expected_fields + +def test_render_request_from_template(): + template_content = """ +# Feature Request: <title> + +**Intent**: <one paragraph describing purpose> +**Author**: <name> +""" + fields = { + "Title": "My Awesome Feature", + "Intent": "This feature will do amazing things.", + "Author": "Test User" + } + fid = "FR_2023-10-27_my-awesome-feature" + created = "2023-10-27" + + rendered_content = render_request_from_template(template_content, fields, fid, created) + expected_content = """ +# Feature Request: My Awesome Feature + +**Intent**: This feature will do amazing things. +**Author**: Test User + +**Feature ID**: FR_2023-10-27_my-awesome-feature +**Meta**: Created: 2023-10-27 • Author: Test User +""" + assert rendered_content.strip() == expected_content.strip() + +def test_render_request_from_template_with_existing_meta(): + template_content = """ +# Feature Request: <title> + +**Intent**: <one paragraph describing purpose> +**Author**: <name> + +**Feature ID**: EXISTING_FID +**Meta**: Existing Meta Info +""" + fields = { + "Title": "Another Feature", + "Intent": "This is another feature.", + "Author": "Another User" + } + fid = "FR_2023-10-28_another-feature" + created = "2023-10-28" + + rendered_content = render_request_from_template(template_content, fields, fid, created) + expected_content = """ +# Feature Request: Another Feature + +**Intent**: This is another feature. +**Author**: Another User + +**Feature ID**: EXISTING_FID +**Meta**: Existing Meta Info +""" + assert rendered_content.strip() == expected_content.strip() -def test_render_placeholders(): - # Test token replacement - assert True diff --git a/tests/test_workflow.py b/tests/test_workflow.py new file mode 100644 index 0000000..4a66420 --- /dev/null +++ b/tests/test_workflow.py @@ -0,0 +1,82 @@ +import pytest +from pathlib import Path +from automation.workflow import parse_votes, _extract_vote_value + +def test_extract_vote_value(): + assert _extract_vote_value("READY") == "READY" + assert _extract_vote_value("CHANGES ") == "CHANGES" + assert _extract_vote_value(" REJECT") == "REJECT" + assert _extract_vote_value("INVALID") is None + assert _extract_vote_value("Some text READY") is None + assert _extract_vote_value("READY ") == "READY" + assert _extract_vote_value("No vote here") is None + +def test_parse_votes_single_participant_single_vote(tmp_path): + discussion_content = """ +- Participant A: Initial comment. +- Participant A: VOTE: READY +""" + discussion_file = tmp_path / "discussion.md" + discussion_file.write_text(discussion_content) + + votes = parse_votes(discussion_file) + assert votes == {"Participant A": "READY"} + +def test_parse_votes_single_participant_multiple_votes(tmp_path): + discussion_content = """ +- Participant B: First comment. VOTE: CHANGES +- Participant B: Second comment. +- Participant B: VOTE: READY +""" + discussion_file = tmp_path / "discussion.md" + discussion_file.write_text(discussion_content) + + votes = parse_votes(discussion_file) + assert votes == {"Participant B": "READY"} + +def test_parse_votes_multiple_participants(tmp_path): + discussion_content = """ +- Participant C: Comment one. VOTE: READY +- Participant D: Comment two. VOTE: CHANGES +- Participant C: Another comment. +- Participant D: Final thoughts. VOTE: READY +""" + discussion_file = tmp_path / "discussion.md" + discussion_file.write_text(discussion_content) + + votes = parse_votes(discussion_file) + assert votes == {"Participant C": "READY", "Participant D": "READY"} + +def test_parse_votes_malformed_lines(tmp_path): + discussion_content = """ +- Participant E: VOTE: READY +- Participant F: VOTE: INVALID_VOTE +- Participant E: Another comment. VOTE: CHANGES +- Participant F: Just a comment. +""" + discussion_file = tmp_path / "discussion.md" + discussion_file.write_text(discussion_content) + + votes = parse_votes(discussion_file) + assert votes == {"Participant E": "CHANGES"} # Participant F's vote is invalid and ignored + +def test_parse_votes_mixed_content(tmp_path): + discussion_content = """ +# Discussion Title + +Some introductory text. + +- Participant G: First point. +- Participant G: Second point. VOTE: READY + +- Participant H: Question? +- Participant H: VOTE: CHANGES + +- Participant G: Response to H. VOTE: REJECT + +""" + discussion_file = tmp_path / "discussion.md" + discussion_file.write_text(discussion_content) + + votes = parse_votes(discussion_file) + assert votes == {"Participant G": "REJECT", "Participant H": "CHANGES"}