|
| 1 | +# typed: false |
| 2 | +# frozen_string_literal: true |
| 3 | + |
| 4 | +# Zeitwerk Compliance Smoke Test |
| 5 | +# |
| 6 | +# This test serves as a Zeitwerk compliance smoke test that validates the gem's |
| 7 | +# file structure and naming conventions. It ensures that all files in the gem |
| 8 | +# follow Zeitwerk's strict naming conventions by forcing the autoloader to |
| 9 | +# eagerly load every constant and file in the gem. |
| 10 | +# |
| 11 | +# How it works: |
| 12 | +# 1. Eager Loading: Forces Zeitwerk to immediately load all files and constants |
| 13 | +# in the gem, rather than loading them on-demand |
| 14 | +# 2. Error Detection: If there are any naming convention violations, Zeitwerk |
| 15 | +# will raise an error during this process |
| 16 | +# 3. Validation: The test passes only if no errors are raised |
| 17 | +# |
| 18 | +# What it catches: |
| 19 | +# - Misnamed files (e.g., my_class.rb should define MyClass) |
| 20 | +# - Incorrect directory structure relative to module nesting |
| 21 | +# - Missing constants (files that exist but don't define expected constants) |
| 22 | +# - Extra or orphaned files that don't follow naming patterns |
| 23 | +# - Namespace violations (constants defined in wrong namespace for their location) |
| 24 | + |
| 25 | +RSpec.describe 'zeitwerk autoloader' do |
| 26 | + it 'werks (successfully loads the gem)' do |
| 27 | + Zeitwerk::Loader.eager_load_namespace(CodeOwnership) |
| 28 | + rescue => error |
| 29 | + # Enhance the error message with more specific information |
| 30 | + enhanced_message = build_enhanced_error_message(error) |
| 31 | + raise enhanced_message |
| 32 | + end |
| 33 | + |
| 34 | + private |
| 35 | + |
| 36 | + def build_enhanced_error_message(error) |
| 37 | + message_parts = [ |
| 38 | + 'Zeitwerk eager loading failed with the following error:', |
| 39 | + '', |
| 40 | + "Original Error: #{error.class}: #{error.message}", |
| 41 | + '', |
| 42 | + ] |
| 43 | + |
| 44 | + # Add backtrace information to help identify the problematic file |
| 45 | + if error.backtrace |
| 46 | + gem_related_trace = error.backtrace.select do |line| |
| 47 | + line.include?('lib/') || line.include?('zeitwerk') |
| 48 | + end |
| 49 | + |
| 50 | + if gem_related_trace.any? |
| 51 | + message_parts << 'Relevant backtrace:' |
| 52 | + gem_related_trace.first(5).each do |line| |
| 53 | + message_parts << " #{line}" |
| 54 | + end |
| 55 | + message_parts << '' |
| 56 | + end |
| 57 | + end |
| 58 | + |
| 59 | + # Try to identify which file might be causing the issue |
| 60 | + if /(?:wrong constant name|uninitialized constant|expected.*to define)/i.match?(error.message) |
| 61 | + message_parts << 'This error typically indicates:' |
| 62 | + message_parts << "- A file name doesn't match its constant name" |
| 63 | + message_parts << '- A constant is defined in the wrong namespace' |
| 64 | + message_parts << "- A file exists but doesn't define the expected constant" |
| 65 | + message_parts << '' |
| 66 | + end |
| 67 | + |
| 68 | + # Add helpful debugging information |
| 69 | + message_parts << 'To debug this issue:' |
| 70 | + message_parts << '1. Check that all files in lib/ follow zeitwerk naming conventions' |
| 71 | + message_parts << '2. Ensure each file defines a constant matching its file path' |
| 72 | + message_parts << '3. Verify modules/classes are in the correct namespace' |
| 73 | + |
| 74 | + message_parts.join("\n") |
| 75 | + end |
| 76 | +end |
0 commit comments