---
phase: 02-e2e-test-infrastructure
plan: 02
type: execute
wave: 2
depends_on: ["02-01"]
files_modified:
  - tests/test_harness.py
autonomous: true

must_haves:
  truths:
    - "CommandResult.success property returns True for exit_code 0, False otherwise"
    - "run_git captures stdout from git commands"
    - "run_git captures non-zero exit codes from failing git commands"
    - "git_repo fixture creates a valid git repository with .git directory"
    - "git_repo_with_commit fixture has at least one commit"
    - "git_repo_with_changes fixture has modified and untracked files"
    - "compare_exact detects string differences"
    - "compare_semantic ignores whitespace differences"
    - "assert_commands_equal raises AssertionError on exit code mismatch"
  artifacts:
    - path: "tests/test_harness.py"
      provides: "Self-validation tests for test infrastructure"
      min_lines: 80
  key_links:
    - from: "tests/test_harness.py"
      to: "tests/conftest.py"
      via: "pytest fixture injection"
      pattern: "def test_.*\\(git_repo"
    - from: "tests/test_harness.py"
      to: "tests/helpers/comparison.py"
      via: "import comparison functions"
      pattern: "from helpers.comparison import"
---

<objective>
Create self-validation tests for the test harness to ensure fixtures and helpers work correctly before using them to test gitsl.

Purpose: The test infrastructure must be validated before it can reliably test gitsl. These tests verify CommandResult, run_git, run_gitsl, fixtures, and comparison utilities all work as expected.

Output:
- `tests/test_harness.py` - Comprehensive tests for all harness components
- All tests passing via pytest
</objective>

<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/phases/02-e2e-test-infrastructure/02-RESEARCH.md
@.planning/phases/02-e2e-test-infrastructure/02-01-SUMMARY.md
</context>

<tasks>

<task type="auto">
  <name>Task 1: Create harness self-validation tests</name>
  <files>tests/test_harness.py</files>
  <action>
Create comprehensive tests that validate the test infrastructure works correctly.

Create `tests/test_harness.py` with test classes:

1. **TestCommandResult** - Test the dataclass
   - test_success_property_true: CommandResult with exit_code=0 has success=True
   - test_success_property_false: CommandResult with exit_code=1 has success=False
   - test_stores_stdout: Verify stdout is captured
   - test_stores_stderr: Verify stderr is captured

2. **TestRunGit** - Test run_git helper (uses git_repo fixture)
   - test_captures_stdout: run_git(["status"]) returns stdout with "On branch"
   - test_captures_exit_code_success: run_git(["status"]) returns exit_code=0
   - test_captures_exit_code_failure: run_git(["status", "nonexistent"]) returns non-zero exit_code
   - test_captures_stderr_on_error: run_git with invalid args has non-empty stderr

3. **TestRunGitsl** - Test run_gitsl helper (uses git_repo fixture)
   - test_runs_gitsl_script: run_gitsl(["--version"]) returns exit_code=0
   - test_captures_gitsl_stdout: run_gitsl(["--version"]) stdout contains "gitsl"

4. **TestGitRepoFixture** - Test git_repo fixture
   - test_creates_git_directory: (git_repo / ".git").is_dir() is True
   - test_is_valid_repo: run_git(["status"]) succeeds
   - test_is_temporary: git_repo path is under system temp dir (or at least not in project)

5. **TestGitRepoWithCommit** - Test git_repo_with_commit fixture
   - test_has_initial_commit: git log --oneline contains "Initial commit"
   - test_has_readme: README.md exists
   - test_clean_working_tree: git status --porcelain is empty

6. **TestGitRepoWithChanges** - Test git_repo_with_changes fixture
   - test_has_modified_file: git status --porcelain contains " M README.md"
   - test_has_untracked_file: git status --porcelain contains "?? new_file.txt"

7. **TestGitRepoWithBranch** - Test git_repo_with_branch fixture
   - test_has_feature_branch: git branch --list contains "feature"

8. **TestCompareExact** - Test compare_exact function
   - test_identical_strings_match: compare_exact("a", "a") is True
   - test_different_strings_dont_match: compare_exact("a", "b") is False
   - test_whitespace_matters: compare_exact("a ", "a") is False

9. **TestCompareSemantic** - Test compare_semantic function
   - test_identical_strings_match: compare_semantic("a", "a") is True
   - test_leading_trailing_whitespace_ignored: compare_semantic(" a ", "a") is True
   - test_multiple_spaces_collapsed: compare_semantic("a  b", "a b") is True
   - test_empty_lines_ignored: compare_semantic("a\n\nb", "a\nb") is True
   - test_different_content_fails: compare_semantic("a", "b") is False

10. **TestAssertCommandsEqual** - Test assert_commands_equal function
    - test_matching_commands_pass: Same results don't raise
    - test_exit_code_mismatch_fails: Different exit codes raise AssertionError
    - test_stdout_mismatch_fails: Different stdout raises AssertionError
    - test_semantic_mode_ignores_whitespace: Whitespace-only stdout difference passes in semantic mode

Import from:
- `from pathlib import Path`
- `import pytest`
- `from conftest import run_git, run_gitsl, CommandResult` (fixtures auto-injected)
- `from helpers.commands import CommandResult`
- `from helpers.comparison import compare_exact, compare_semantic, assert_commands_equal`

Follow the test structure from 02-RESEARCH.md Example Test File, but expand coverage.
  </action>
  <verify>
    # Count test functions
    grep -c "def test_" tests/test_harness.py
    # Should be at least 25 test functions
  </verify>
  <done>
    - test_harness.py exists with at least 25 test functions
    - All 10 test classes created covering all harness components
    - Tests cover both success and failure cases
  </done>
</task>

<task type="auto">
  <name>Task 2: Verify all tests pass</name>
  <files>None (verification only)</files>
  <action>
Run pytest and ensure all harness tests pass.

1. First, ensure pytest is installed:
   ```bash
   pip install pytest
   ```

2. Run pytest on the test_harness.py file:
   ```bash
   python -m pytest tests/test_harness.py -v
   ```

3. If any tests fail:
   - Analyze the failure
   - Fix either the test or the harness code (in tests/helpers/ or tests/conftest.py)
   - Re-run until all pass

4. Run with coverage info:
   ```bash
   python -m pytest tests/test_harness.py -v --tb=short
   ```

Expected: All tests pass, demonstrating the harness is working correctly.

Note: If gitsl.py tests fail because gitsl doesn't execute commands yet (Phase 1 only parses), that's expected. TestRunGitsl tests should only verify the script runs, not that it produces git-equivalent output.
  </action>
  <verify>
    python -m pytest tests/test_harness.py -v --tb=short
    # Exit code should be 0 (all tests pass)
  </verify>
  <done>
    - pytest runs successfully
    - All tests in test_harness.py pass
    - No errors or failures in output
  </done>
</task>

</tasks>

<verification>
After all tasks complete:

```bash
# Full test run with verbose output
python -m pytest tests/test_harness.py -v

# Verify test count
python -m pytest tests/test_harness.py --collect-only | grep "test_" | wc -l
# Should be at least 25 tests

# Quick summary
python -m pytest tests/test_harness.py --tb=no -q
# Should show "X passed" with no failures
```
</verification>

<success_criteria>
1. tests/test_harness.py exists with comprehensive test coverage
2. At least 25 test functions covering all harness components
3. All tests pass when run with pytest
4. Test output shows clear pass/fail status
5. Harness is validated and ready to test gitsl in future phases
</success_criteria>

<output>
After completion, create `.planning/phases/02-e2e-test-infrastructure/02-02-SUMMARY.md`

Include:
- Test file created
- Number of tests and test classes
- All tests passing confirmation
- Any issues discovered and fixed during validation
- Ready for Phase 3 confirmation
</output>
