Summary
Running these two spec files together fails to load, before any example runs:
bundle exec rspec spec/lib/common/authentication/login_helpers_spec.rb \
spec/lib/common/session_launcher_spec.rb
An error occurred while loading ./spec/lib/common/session_launcher_spec.rb.
Failure/Error: extend FFI::Library
NameError:
uninitialized constant Lich::Common::GUI::WindowsCredentialManager::FFI
# ./lib/common/gui/windows_credential_manager.rb:16:in '<module:WindowsCredentialManager>'
...
# ./lib/common/gui_login.rb:5:in '<top (required)>'
# ./spec/login_spec_helper.rb:127:in '<top (required)>'
# ./spec/lib/common/session_launcher_spec.rb:1:in '<top (required)>'
0 examples, 0 failures, 1 error occurred outside of examples.
Scope
- Order-dependent:
spec/lib/common/session_launcher_spec.rb on its own passes.
- The full suite is unaffected —
bundle exec rspec is green (6292 examples, 0
failures), so CI never sees this. It only bites when running a subset by hand,
which is the normal loop while working on either file.
- Not a regression from any particular change; reproduces on current
main content.
I hit it on a branch, then confirmed it at the branch point with nothing applied.
Root cause
Two competing stubs of Lich::Util.install_gem_requirements, each guarded so
whichever loads first wins and the other backs off:
spec/lib/common/authentication/login_helpers_spec.rb:19-25 defines a no-op
version, guarded unless defined?(Lich::Util).
spec/login_spec_helper.rb:34-40 defines a version that actually does
require 'os' and require 'ffi', guarded
unless respond_to?(:install_gem_requirements).
When login_helpers_spec.rb loads first, the no-op wins, so login_spec_helper.rb
declines to replace it. login_spec_helper.rb:127 then requires gui_login.rb,
which pulls in lib/common/gui/windows_credential_manager.rb. That file's line 3
calls Lich::Util.install_gem_requirements({ 'ffi' => true }) — now a no-op — so
ffi is never required, and extend FFI::Library on line 16 raises.
Verified directly: after loading login_helpers_spec.rb alone,
Lich::Util.respond_to?(:install_gem_requirements) is true while neither
lib/util/util.rb nor ffi is in $LOADED_FEATURES.
Possible fixes
- Have
spec/login_spec_helper.rb do its require 'ffi' / require 'os'
unconditionally rather than only as a side effect of defining the stub, so it
no longer matters who defined the method first.
- Or drop the ad-hoc stub in
login_helpers_spec.rb and let the shared helper own it.
- Independently of the spec plumbing:
windows_credential_manager.rb does
extend FFI::Library at module-body level on every platform, but only calls
ffi_lib inside if OS.windows?. Guarding the extend the same way would make
the file inert off-Windows and remove the load-order dependency entirely.
Happy to put up a PR for whichever of these you'd prefer.
Summary
Running these two spec files together fails to load, before any example runs:
bundle exec rspec spec/lib/common/authentication/login_helpers_spec.rb \ spec/lib/common/session_launcher_spec.rb0 examples, 0 failures, 1 error occurred outside of examples.Scope
spec/lib/common/session_launcher_spec.rbon its own passes.bundle exec rspecis green (6292 examples, 0failures), so CI never sees this. It only bites when running a subset by hand,
which is the normal loop while working on either file.
maincontent.I hit it on a branch, then confirmed it at the branch point with nothing applied.
Root cause
Two competing stubs of
Lich::Util.install_gem_requirements, each guarded sowhichever loads first wins and the other backs off:
spec/lib/common/authentication/login_helpers_spec.rb:19-25defines a no-opversion, guarded
unless defined?(Lich::Util).spec/login_spec_helper.rb:34-40defines a version that actually doesrequire 'os'andrequire 'ffi', guardedunless respond_to?(:install_gem_requirements).When
login_helpers_spec.rbloads first, the no-op wins, sologin_spec_helper.rbdeclines to replace it.
login_spec_helper.rb:127then requiresgui_login.rb,which pulls in
lib/common/gui/windows_credential_manager.rb. That file's line 3calls
Lich::Util.install_gem_requirements({ 'ffi' => true })— now a no-op — soffiis never required, andextend FFI::Libraryon line 16 raises.Verified directly: after loading
login_helpers_spec.rbalone,Lich::Util.respond_to?(:install_gem_requirements)istruewhile neitherlib/util/util.rbnorffiis in$LOADED_FEATURES.Possible fixes
spec/login_spec_helper.rbdo itsrequire 'ffi'/require 'os'unconditionally rather than only as a side effect of defining the stub, so it
no longer matters who defined the method first.
login_helpers_spec.rband let the shared helper own it.windows_credential_manager.rbdoesextend FFI::Libraryat module-body level on every platform, but only callsffi_libinsideif OS.windows?. Guarding theextendthe same way would makethe file inert off-Windows and remove the load-order dependency entirely.
Happy to put up a PR for whichever of these you'd prefer.