test_helpers.py 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. import subprocess
  2. from pathlib import Path
  3. BIN_DIR = Path(__file__).parent.parent / "bin"
  4. FIXTURES_DIR = Path(__file__).parent / "fixtures"
  5. def run_helper(name: str, args: list[str], cwd: Path) -> subprocess.CompletedProcess[str]:
  6. return subprocess.run(
  7. [str(BIN_DIR / name), *args],
  8. cwd=cwd,
  9. capture_output=True,
  10. text=True,
  11. )
  12. class TestToolCalled:
  13. def test_tool_present(self, tmp_path):
  14. (tmp_path / "tool_calls.jsonl").write_text((FIXTURES_DIR / "tools_multi.jsonl").read_text())
  15. result = run_helper("tool-called", ["Read"], tmp_path)
  16. assert result.returncode == 0
  17. def test_tool_absent(self, tmp_path):
  18. (tmp_path / "tool_calls.jsonl").write_text((FIXTURES_DIR / "tools_multi.jsonl").read_text())
  19. result = run_helper("tool-called", ["Write"], tmp_path)
  20. assert result.returncode == 1
  21. assert "FAIL" in result.stdout
  22. def test_empty_jsonl(self, tmp_path):
  23. (tmp_path / "tool_calls.jsonl").write_text("")
  24. result = run_helper("tool-called", ["Read"], tmp_path)
  25. assert result.returncode == 1
  26. class TestToolNotCalled:
  27. def test_tool_absent(self, tmp_path):
  28. (tmp_path / "tool_calls.jsonl").write_text((FIXTURES_DIR / "tools_multi.jsonl").read_text())
  29. result = run_helper("tool-not-called", ["Write"], tmp_path)
  30. assert result.returncode == 0
  31. def test_tool_present(self, tmp_path):
  32. (tmp_path / "tool_calls.jsonl").write_text((FIXTURES_DIR / "tools_multi.jsonl").read_text())
  33. result = run_helper("tool-not-called", ["Read"], tmp_path)
  34. assert result.returncode == 1
  35. assert "FAIL" in result.stdout
  36. def test_empty_jsonl(self, tmp_path):
  37. (tmp_path / "tool_calls.jsonl").write_text("")
  38. result = run_helper("tool-not-called", ["Read"], tmp_path)
  39. assert result.returncode == 0
  40. class TestToolCount:
  41. def test_gte_passes(self, tmp_path):
  42. (tmp_path / "tool_calls.jsonl").write_text((FIXTURES_DIR / "tools_multi.jsonl").read_text())
  43. result = run_helper("tool-count", ["Read", "gte", "2"], tmp_path)
  44. assert result.returncode == 0
  45. def test_gte_fails(self, tmp_path):
  46. (tmp_path / "tool_calls.jsonl").write_text((FIXTURES_DIR / "tools_multi.jsonl").read_text())
  47. result = run_helper("tool-count", ["Read", "gte", "5"], tmp_path)
  48. assert result.returncode == 1
  49. assert "FAIL" in result.stdout
  50. def test_eq(self, tmp_path):
  51. (tmp_path / "tool_calls.jsonl").write_text((FIXTURES_DIR / "tools_multi.jsonl").read_text())
  52. result = run_helper("tool-count", ["Read", "eq", "2"], tmp_path)
  53. assert result.returncode == 0
  54. def test_lt(self, tmp_path):
  55. (tmp_path / "tool_calls.jsonl").write_text((FIXTURES_DIR / "tools_multi.jsonl").read_text())
  56. result = run_helper("tool-count", ["Read", "lt", "3"], tmp_path)
  57. assert result.returncode == 0
  58. class TestToolBefore:
  59. def test_correct_order(self, tmp_path):
  60. (tmp_path / "tool_calls.jsonl").write_text(
  61. (FIXTURES_DIR / "tools_ordered.jsonl").read_text()
  62. )
  63. result = run_helper("tool-before", ["Read", "Edit"], tmp_path)
  64. assert result.returncode == 0
  65. def test_wrong_order(self, tmp_path):
  66. (tmp_path / "tool_calls.jsonl").write_text(
  67. (FIXTURES_DIR / "tools_ordered.jsonl").read_text()
  68. )
  69. result = run_helper("tool-before", ["Edit", "EnterWorktree"], tmp_path)
  70. assert result.returncode == 1
  71. assert "FAIL" in result.stdout
  72. def test_first_tool_missing(self, tmp_path):
  73. (tmp_path / "tool_calls.jsonl").write_text(
  74. (FIXTURES_DIR / "tools_ordered.jsonl").read_text()
  75. )
  76. result = run_helper("tool-before", ["Write", "Read"], tmp_path)
  77. assert result.returncode == 1
  78. assert "never called" in result.stdout
  79. def test_second_tool_missing(self, tmp_path):
  80. (tmp_path / "tool_calls.jsonl").write_text(
  81. (FIXTURES_DIR / "tools_ordered.jsonl").read_text()
  82. )
  83. result = run_helper("tool-before", ["Read", "Write"], tmp_path)
  84. assert result.returncode == 1
  85. assert "never called" in result.stdout
  86. class TestToolArgMatch:
  87. def test_matching_arg(self, tmp_path):
  88. (tmp_path / "tool_calls.jsonl").write_text((FIXTURES_DIR / "tools_multi.jsonl").read_text())
  89. result = run_helper(
  90. "tool-arg-match", ["Skill", '.skill == "superpowers:worktree"'], tmp_path
  91. )
  92. assert result.returncode == 0
  93. def test_no_matching_arg(self, tmp_path):
  94. (tmp_path / "tool_calls.jsonl").write_text((FIXTURES_DIR / "tools_multi.jsonl").read_text())
  95. result = run_helper("tool-arg-match", ["Skill", '.skill == "nonexistent"'], tmp_path)
  96. assert result.returncode == 1
  97. assert "FAIL" in result.stdout
  98. def test_tool_not_present(self, tmp_path):
  99. (tmp_path / "tool_calls.jsonl").write_text((FIXTURES_DIR / "tools_multi.jsonl").read_text())
  100. result = run_helper("tool-arg-match", ["Write", '.file_path == "/tmp/foo"'], tmp_path)
  101. assert result.returncode == 1