Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions tests/test_live_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -1398,6 +1398,51 @@ def test_a_runner_started_by_a_launcher_counts_as_a_verification(cmd):
assert g.verifications == 1 and not g.resolved_proxy()


@pytest.mark.parametrize("cmd", ["ruby test/ledger_test.rb", "ruby -w -Ilib test/slugify_test.rb",
"ruby -I lib test/x_test.rb", "ruby /w/repo/test/x_test.rb",
"ruby -Itest test/models/user_test.rb", "ruby spec/foo_spec.rb",
"ruby -W0 --disable-gems test/test_parser.rb",
"ruby -W:no-deprecated test/a_test.rb", "ruby -wv test/a_test.rb",
"ruby -C /w -Itest test/a_test.rb",
"bundle exec ruby -Itest test/a_test.rb -n test_x",
"rake test", "bundle exec rake test", "rake test:models",
"bin/rake test TEST=test/a_test.rb", "rake spec", "bin/rails test",
"rails test test/models/user_test.rb"])
def test_a_ruby_test_run_counts_as_a_verification(cmd):
"""minitest and test-unit are run as `ruby` given a test file, or through rake or rails, not
by a runner of their own as `rspec` is."""
assert turn.status_of_tests(cmd) == "own"
g = guard.TurnGuard(turn_key="t")
g.fold("Edit", {"file_path": "/r/lib/a.rb", "old_string": "x", "new_string": "y"}, "ok")
g.fold("Bash", {"command": cmd}, "8 runs, 8 assertions, 1 failures, 0 errors, 0 skips", 1)
assert g.verifications == 1 and not g.resolved_proxy()


@pytest.mark.parametrize("cmd", ["ruby -Ilib -e 'require \"a\"; p A.new'", "ruby -wc lib/retry.rb",
"ruby -c test/a_test.rb", "ruby -wc test/a_test.rb",
"ruby -Wc test/a_test.rb", "ruby -cw test/a_test.rb",
"ruby -we 'load \"test/a_test.rb\"'", "ruby repro.rb", "ruby -v",
"ruby -e 'load \"test/a_test.rb\"'", "ruby lib/contest.rb",
"ruby -Icore lib/x.rb", "rake", "rake db:migrate",
"rails server", "cat test/a_test.rb"])
def test_ruby_that_runs_no_test_file_is_not_a_verification(cmd):
"""A one-off `ruby -e`, a syntax check and a script are not the project's checks."""
assert turn.status_of_tests(cmd) is None


def test_a_piped_minitest_run_is_judged_by_its_summary():
"""`ruby test/x_test.rb | tail -5` exits with `tail`'s status, so minitest's summary line
decides whether the turn ended green."""
g = guard.TurnGuard(turn_key="t")
g.fold("Edit", {"file_path": "/r/lib/a.rb", "old_string": "x", "new_string": "y"}, "ok")
g.fold("Bash", {"command": "ruby test/a_test.rb 2>&1 | tail -5"},
"8 runs, 8 assertions, 1 failures, 0 errors, 0 skips", 0)
assert g.verifications == 1 and not g.resolved_proxy()
g.fold("Bash", {"command": "ruby test/a_test.rb 2>&1 | tail -5"},
"8 runs, 8 assertions, 0 failures, 0 errors, 0 skips", 0)
assert g.verifications == 2 and g.resolved_proxy()


@pytest.mark.parametrize("cmd,status", [("uv run ruff check", None),
("npx prettier --check .", None),
("pnpm exec jest --help", None),
Expand Down Expand Up @@ -1517,6 +1562,10 @@ def test_a_test_run_followed_by_other_commands_is_judged_by_its_runners_summary(
("ok \tacme/x\t0.012s", False), ("test result: FAILED. 1 passed; 1 failed", True),
("test result: ok. 3 passed; 0 failed", False), ("5 examples, 1 failure", True),
("Tests run: 4, Failures: 0, Errors: 1", True), ("[INFO] BUILD SUCCESS", False),
("8 runs, 8 assertions, 1 failures, 0 errors, 0 skips", True),
("8 runs, 8 assertions, 0 failures, 2 errors, 0 skips", True),
("Finished in 0.01s\n5 runs, 9 assertions, 0 failures, 0 errors, 1 skips", False),
("1 tests, 1 assertions, 0 failures, 0 errors, 0 pendings, 0 omissions", False),
("+ raise ValueError('no')", None), ("ok 1 - add", None)])
def test_a_runners_summary_gives_its_verdict(out, failed):
assert turn.runner_verdict(out) is failed
Expand Down
12 changes: 12 additions & 0 deletions tokeneconomizer/loopguard/turn.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,14 @@
r"(?:npm|pnpm|yarn|bun)\s+(?:run\s+)?test|go\s+test|cargo\s+(?:test|nextest)|"
r"(?:mvn|mvnw|\./mvnw)\s+(?:\S+\s+)*test|(?:gradle|gradlew|\./gradlew)\s+(?:\S+\s+)*test|"
r"make\s+(?:test|check)|ctest|rspec|phpunit|dotnet\s+test|swift\s+test|mix\s+test|"
# Ruby: `rake test`, `bin/rails test`, and `ruby` given a test file (`ruby -Itest
# test/models/user_test.rb`), but not `ruby -e '...'`, a syntax check (`ruby -wc x.rb`) or a
# script that is not a test (`ruby repro.rb`): the options it takes are spelled out, and
# case-sensitive, so `-W` does not also take `-wc` under the pattern's `(?i)`.
r"rake(?:\s+\w+=\S*)*\s+(?:test|spec)(?::[\w:]+)?|rails\s+test(?::[\w:]+)?|"
r"ruby(?-i:\s+(?:-[Ir](?:\S+|\s+[^\s\-]\S*)|-C\s*\S+|-W[0-2]?(?::\S+)?|"
r"--[\w\-]+(?:=\S+)?|-[abdf-zABDF-Z]+))*\s+"
r"(?:[\w.\-~]*/)*(?:test_[\w.\-]*|[\w.\-]*_(?:test|spec))\.rb|"
r"deno\s+test|node\s+--test|bazel\s+test|(?:\./)?bin/test)(?![\w.\-/])")

# A command line's exit status is its LAST command's, so it may not be the test run's: `npm test
Expand Down Expand Up @@ -178,6 +186,9 @@ def status_of_tests(cmd):
r"^(?:--- FAIL: |FAIL\t|FAIL$)", # go
r"^test result: FAILED", # cargo
r"\b\d+ examples?, [1-9]\d* failures?\b", # rspec
# minitest (`8 runs, 9 assertions, 1 failures, 0 errors, 0 skips`), test-unit (`tests`)
r"^\d+ (?:runs|tests), \d+ assertions, (?:[1-9]\d* failures, \d+ errors|\d+ failures, "
r"[1-9]\d* errors)\b",
r"Tests run: \d+, Failures: (?:[1-9]|0, Errors: [1-9])", # JUnit (Maven, Gradle)
r"BUILD FAIL(?:URE|ED)")), re.MULTILINE)
_RUN_PASSED_RE = re.compile("|".join((
Expand All @@ -192,6 +203,7 @@ def status_of_tests(cmd):
r"^ok\s+\S+\s+(?:\d+(?:\.\d+)?s|\(cached\))",
r"^test result: ok\.",
r"\b\d+ examples?, 0 failures\b",
r"^\d+ (?:runs|tests), \d+ assertions, 0 failures, 0 errors\b", # minitest, test-unit
r"BUILD SUCCESS")), re.MULTILINE)


Expand Down
Loading