Skip to content

test(fix_globals): cover multi-run scenarios A-F#128

Merged
VincentGuyader merged 2 commits into
mainfrom
test/issue-127-multi-run-scenarios
May 17, 2026
Merged

test(fix_globals): cover multi-run scenarios A-F#128
VincentGuyader merged 2 commits into
mainfrom
test/issue-127-multi-run-scenarios

Conversation

@VincentGuyader
Copy link
Copy Markdown
Member

Summary

Closes #127.

Scenarios

Cell Locks in
A 2 runs, accumulation of new vars on the 2nd run; new # <fun>: group emitted per new fun; 1st-run names survive
B Overlap between runs deduplicated via the runtime unique(c(...)) wrapper
C Consecutive no-op runs yield byte-identical globals.R (idempotence after #125 early-return)
D Manually-added name survives the next pass; comment loss explicitly asserted as the current contract
E Real round-trip with create_example_pkg(): 2nd pass is a filesystem no-op (skip_on_cran())
F Function-only notes never create globals.R over N runs; liste_funs surfaces where and summarise independently every run

Test plan

  • devtools::test() green (604 PASS / 0 FAIL with the new 19 expectations).
  • TAP per-scenario walkthrough: A=4, B=2, C=1, D=4, E=2, F=6.
  • Scenario E gated behind skip_on_cran() and uses local_tempdir_clean() + on.exit(unlink).
  • No em-dash / en-dash, every body braced, every non-idiomatic positional arg named.

Follow-ups (out of scope)

  • Helper duplication: local_pkg_with_globals() is now defined inline in both test-fix-globals-merge.R and test-fix-globals-multi-run.R. Promote to tests/testthat/helpers.R in a follow-up.
  • fake_check_result() (new, flexible multi-fun) is a strict superset of fake_globals() (in merge test). Unify under a single name in helpers.R when the duplication is addressed.

Lock in the contract of `fix_globals(write = TRUE)` under repeated
invocations with varying shapes. Six new scenarios, all green on the
post-#125 / #126 codebase:

- A. 2 runs accumulating new vars on the 2nd run without losing
  1st-run names (per-`# <fun>:` group emitted for each new fun).
- B. Overlap between runs deduplicated at runtime via the
  `unique(c(...))` wrapper.
- C. Consecutive no-op runs yield byte-identical `globals.R`
  (idempotence after the #125 early-return).
- D. User-curated name added manually between runs survives the
  next `fix_globals(write = TRUE)` pass. Comment loss is documented
  as tolerated for now via an explicit `expect_false()` so a future
  change that preserves comments has to revisit the assertion.
- E. Real round-trip with `create_example_pkg()`: the 2nd pass is
  a filesystem no-op (`skip_on_cran()` because of the real
  `rcmdcheck()` call).
- F. Function-only notes on N consecutive runs never create
  `globals.R`; `liste_funs` surfaces every detected function on
  every run (both `where` and `summarise` asserted independently).

No source change; pure regression coverage. Closes #127.
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds regression coverage for repeated fix_globals(write = TRUE) runs, focusing on accumulation, deduplication, idempotence, manual edits, real package round-trips, and function-only note handling.

Changes:

  • Adds multi-run fix_globals() test scenarios A-F.
  • Introduces local helpers for temporary packages, mocked check results, and declared global extraction.
  • Includes one real create_example_pkg() round-trip gated with skip_on_cran().
Comments suppressed due to low confidence (1)

tests/testthat/test-fix-globals-multi-run.R:126

  • This assertion cannot catch duplicate declarations because after comes from declared_names(), which delegates to extract_existing_globals() and is already deduplicated with unique(). If the goal is to lock in that shared is not emitted twice, parse/read globals.R directly without the deduping helper before counting occurrences.
  after <- declared_names(globals_path)
  expect_setequal(after, c("shared", "only_in_run1", "only_in_run2"))
  expect_equal(sum(after == "shared"), 1L,
    info = "duplicate names must be collapsed by the runtime"

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +84 to +86
expect_equal(length(after), length(unique(after)),
info = "no name should be declared twice"
)
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated 1 comment.

Comment on lines +124 to +127
expect_setequal(after, c("shared", "only_in_run1", "only_in_run2"))
expect_equal(sum(after == "shared"), 1L,
info = "duplicate names must be collapsed by the runtime"
)
Both scenarios had a duplicate-suppression assertion that routed
through `declared_names()` -> `extract_existing_globals()`, which
internally calls `unique()` (R/audit_globals.R:249). The assertions
were therefore tautological - they would have passed even if the
on-disk file carried a literal duplicate.

Investigation also revealed that the merge path of
`fix_globals(write = TRUE)` does emit a literal duplicate on disk
in scenario B's shape (1 occurrence in the fresh `# fn_b:` block,
1 in the `# previously declared:` chunk); the safety net is the
`unique(c(...))` wrapper in `utils::globalVariables(unique(c(...)))`
that collapses the duplicate at runtime, which is what R CMD check
actually consumes.

Fixes:

- Scenario A: drop the tautology. `expect_setequal()` already locks
  in the runtime set.
- Scenario B: replace the tautology with a parse-and-eval assertion
  that bypasses `declared_names()` and exercises the runtime
  `unique()` directly. Docstring updated to spell out that the
  contract is the runtime set, not the on-disk text.
@VincentGuyader VincentGuyader merged commit af1384f into main May 17, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

test(fix_globals): cover multi-run scenarios (accumulation, idempotence, round-trip)

2 participants