Class: Ace::TestRunner::Atoms::CommandBuilder

Inherits:
Object
  • Object
show all
Defined in:
lib/ace/test_runner/atoms/command_builder.rb

Overview

Builds test execution commands

Instance Method Summary collapse

Constructor Details

#initialize(ruby_command: "ruby", bundler: true) ⇒ CommandBuilder

Returns a new instance of CommandBuilder.



10
11
12
13
# File 'lib/ace/test_runner/atoms/command_builder.rb', line 10

def initialize(ruby_command: "ruby", bundler: true)
  @ruby_command = ruby_command
  @bundler = bundler
end

Instance Method Details

#build_pattern_command(pattern) ⇒ Object



90
91
92
93
94
95
96
97
98
99
# File 'lib/ace/test_runner/atoms/command_builder.rb', line 90

def build_pattern_command(pattern)
  cmd = []
  cmd << "bundle exec" if @bundler && bundler_available?
  cmd << @ruby_command
  cmd << "-Ilib:test"
  cmd << "-e"
  cmd << %{'Dir.glob("#{pattern}").each { |f| require f }'}

  cmd.join(" ")
end

#build_single_file_command(file, options = {}) ⇒ Object



85
86
87
88
# File 'lib/ace/test_runner/atoms/command_builder.rb', line 85

def build_single_file_command(file, options = {})
  # Single file uses the same logic as multiple files
  build_test_command(file, options)
end

#build_test_command(files, options = {}) ⇒ Object



15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# File 'lib/ace/test_runner/atoms/command_builder.rb', line 15

def build_test_command(files, options = {})
  cmd_parts = []

  # Use bundler if available and requested
  cmd_parts << "bundle exec" if @bundler && bundler_available?

  # Ruby command
  cmd_parts << @ruby_command

  # Add test framework options
  cmd_parts << "-Ilib:test" unless options[:no_load_path]

  # Note: fail_fast is handled by test executor, not minitest
  # We don't use minitest/fail_fast gem to avoid extra dependencies

  # Add the test files
  if files.is_a?(Array)
    # Check if any file has a line number (file:line format)
    has_line_numbers = files.any? { |f| f.match?(/:\d+$/) }

    if has_line_numbers
      # For files with line numbers, resolve to test names and filter
      build_line_number_command(cmd_parts, files, options)
    else
      # Build a Ruby script that requires each file and fails on LoadError
      requires_script = files.map do |f|
        # Add ./ prefix if it's a relative path without one
        path = f.start_with?("/", "./") ? f : "./#{f}"
        # Escape the path for shell safety
        escaped_path = path.gsub("'", "\\\\'")
        "begin; require '#{escaped_path}'; rescue LoadError => e; STDERR.puts \\\"Failed to load #{escaped_path}: \\\" + e.message; exit(1); end"
      end.join("; ")

      # Build the script parts
      script_parts = []
      # Inject ARGV with --verbose for Minitest if profile is requested
      # (Ruby's --verbose flag only sets $VERBOSE, doesn't enable Minitest verbose mode)
      script_parts << "ARGV.replace(['--verbose'])" if options[:profile]
      script_parts << requires_script
      script_parts << "exit_code = Minitest.autorun"
      script_parts << "exit(exit_code)"

      # Execute the requires and then run Minitest
      cmd_parts << "-e"
      # Use double quotes to wrap the entire script
      cmd_parts << "\"#{script_parts.join("; ")}\""
    end
  elsif files.match?(/:\d+$/)
    # Check if single file has line number
    build_line_number_command(cmd_parts, [files], options)
  elsif options[:profile]
    # Single file without line number
    cmd_parts << "-e"
    escaped_path = files.gsub("'", "\\\\'")
    path = files.start_with?("/", "./") ? escaped_path : "./#{escaped_path}"
    cmd_parts << "\"ARGV.replace(['--verbose']); require '#{path}'; exit_code = Minitest.autorun; exit(exit_code)\""
  # Inject ARGV with --verbose for Minitest profiling
  else
    # Just pass file as argument (Minitest autoruns)
    cmd_parts << files
  end

  # Add any extra arguments
  if options[:args]
    cmd_parts.concat(Array(options[:args]))
  end

  cmd_parts.join(" ")
end