mruby-test: regenerate the per-gem test wrapper when a mrbgem.rake it is generated from changes - #7160
Conversation
The per-gem test wrapper (build/.../mrbgems/<gem>/gem_test.c) is generated
from mrbgem.rake, not only from the test files it embeds: its body follows
the gem's test_rbfiles, test_preload and test_args, and it declares and
calls the init/final function of every gem returned by tsort_dependencies.
Its file task, however, listed only the gem's test .rb files and mrbc as
prerequisites, so editing a mrbgem.rake left a stale wrapper in place and an
incremental build kept reporting the previous test result until a test file
happened to be touched or the build directory was cleaned.
Reproduced on a fully built tree by narrowing one gem's test set:
$ rake test:build # wrapper embeds 3 ireps, Total: 2049
$ # add to mrbgems/mruby-string-ext/mrbgem.rake:
$ # spec.test_rbfiles = ["#{MRUBY_ROOT}/mrbgems/mruby-string-ext/test/string.rb"]
$ rake test:build
$ ./build/host/bin/mrbtest | grep Total
Total: 2049 # unchanged, wrapper byte-identical
Touching mrbgems/mruby-string-ext/test/string.rb and rebuilding then drops
the wrapper to 1 irep and the count to 2044, confirming the stale wrapper
rather than a stale binary.
Track the rakefile of the gem and of each gem in its dependency list. The
dependency list matters on its own: adding a dependency to mruby-string-ext
changes the wrapper of mruby-regexp, which depends on it, so tracking only
the gem's own rakefile would still leave mruby-regexp stale. Also track this
file, which holds the generator, as the mrbtest.c rule in it already does.
Depending on a gem's mrbgem.rake mirrors what MRuby::Command::Compiler
#define_rules does for a gem's C objects. The existence check keeps the rule
safe for specifications not backed by an on-disk mrbgem.rake, since a
non-existent prerequisite with no rule would abort the build.
Only the test_preload path is covered this way; the contents of that file
are still not a prerequisite. No in-tree gem sets test_preload.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughThe test irep generation rule now depends on the gem’s ChangesTest irep generation
Estimated code review effort: 2 (Simple) | ~10 minutes Merge Risk: ⚪ Minimal · up to This change makes per-gem test wrappers regenerate when their rakefile inputs change; no actionable merge-blocking risk remains beyond normal checks and review. Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Problem
The per-gem test wrapper
build/<target>/mrbgems/<gem>/gem_test.cis generated frommrbgem.rake, not only from the test files it embeds. Its body follows the gem'sspec.test_rbfiles,spec.test_preload,spec.test_argsandspec.test_objs(viacustom_test_init?), and it declares and calls the init/final function of every gem returned bytsort_dependencies.The file task that generates it, however, listed only the test
.rbfiles andmrbcas prerequisites:So editing a
mrbgem.rakedoes not invalidate the wrapper. An incrementalrake testkeeps running the previously generated test set and reporting the previous result, until a test file happens to be touched or the build directory is cleaned. This is easy to mistake for a test that legitimately still passes (or still fails), which makes it an actively misleading failure mode when adding, removing or re-scoping a gem's tests.Reproduction
On a fully built tree (
rake test:build), narrow one gem's test set without touching any test file. Append tomrbgems/mruby-string-ext/mrbgem.rake:Then rebuild:
gem_test.cis byte-identical to before the edit and still embeds all three ireps; the count is unchanged.touch mrbgems/mruby-string-ext/test/string.rb && rake test:buildthen produces the expected single-irep wrapper andTotal: 2044, confirming the stale artifact is the wrapper itself.(Note that plain
rakewill not show this: themruby-testgem is only loaded under thetest:buildtask.)Fix
Add to the wrapper's prerequisites the
mrbgem.rakeof the gem and of each gem in its dependency list, plusmruby-test/mrbgem.rakeitself, which holds the generator.Tracking the dependency list is not defensive; it is load-bearing. Adding
spec.add_dependency 'mruby-math', core: 'mruby-math'tomrbgems/mruby-string-ext/mrbgem.rakechanges the wrapper ofmruby-regexp, which depends on it, becausemruby-math's init/final calls are emitted there too. Tracking only the gem's own rakefile leaves that wrapper stale.Both dependencies follow existing convention in the tree:
MRuby::Command::Compiler#define_rulesalready recordsmrbgem.rakefor a gem's C objects, and the siblingmrbtest.crule already records__FILE__for its own generator. The per-gem test wrapper was simply missing both. The change is in mrbtest's rake rules only. No gem or core source is touched, and nothing is specific to any one gem.The
File.exist?filter keeps the rule safe for aMRuby::Gem::Specificationthat is not backed by an on-diskmrbgem.rake: a prerequisite that neither exists nor has a rule would abort the build.define_rulesguards the same way.One input remains untracked and is left for a separate change: the contents of the file named by
spec.test_preloadare embedded in the wrapper, but only its path is covered here. No in-tree gem currently setstest_preload.Verification
mrbgem.rakealone, with no test file touched andtest/string.rbolder than the existinggem_test.c, now regenerates the wrapper and moves the count fromTotal: 2049toTotal: 2044; reverting the edit restoresTotal: 2049.mruby-regexp's wrapper frombb189b91…to4c6a7f5f…, withgrep -c GENERATED_TMP_mrb_mruby_math_gem_initgoing from 0 to 2, the same content reached by force-touching that gem's own rakefile.touch mrbgems/mruby-test/mrbgem.rake && rake test:buildregenerates all 50 wrappers, where previously it regenerated none.rake clean, then full build) generates all wrappers and yields the same totals as before.rake -m teston the current master with this change:Total: 2075, OK: 2046, KO: 0, Crash: 0, Warning: 0, Skip: 29, plus bintestTotal: 105, KO: 0, Crash: 0. No behavioural change to the tests themselves is expected; this only makes an incremental build notice inputs it was already using.Summary by CodeRabbit
Bug Fixes
Chores