Class: TestBench::CLI

Inherits:
Object
  • Object
show all
Defined in:
lib/test_bench/cli.rb

Defined Under Namespace

Modules: Defaults

Constant Summary collapse

ArgumentError =
Class.new(RuntimeError)

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(*arguments) ⇒ CLI

Returns a new instance of CLI.



44
45
46
# File 'lib/test_bench/cli.rb', line 44

def initialize(*arguments)
  @arguments = arguments
end

Instance Attribute Details

#argumentsObject (readonly)

Returns the value of attribute arguments.



5
6
7
# File 'lib/test_bench/cli.rb', line 5

def arguments
  @arguments
end

#envObject



9
10
11
# File 'lib/test_bench/cli.rb', line 9

def env
  @env ||= {}
end

#exit_codeObject

Returns the value of attribute exit_code.



7
8
9
# File 'lib/test_bench/cli.rb', line 7

def exit_code
  @exit_code
end

#program_nameObject



14
15
16
# File 'lib/test_bench/cli.rb', line 14

def program_name
  @program_name ||= Defaults.program_name
end

#randomObject



39
40
41
# File 'lib/test_bench/cli.rb', line 39

def random
  @random ||= Random::Substitute.build
end

#runObject



34
35
36
# File 'lib/test_bench/cli.rb', line 34

def run
  @run ||= Run::Substitute.build
end

#stdinObject



24
25
26
# File 'lib/test_bench/cli.rb', line 24

def stdin
  @stdin ||= STDIN
end

#versionObject



19
20
21
# File 'lib/test_bench/cli.rb', line 19

def version
  @version ||= Defaults.version
end

#writerObject



29
30
31
# File 'lib/test_bench/cli.rb', line 29

def writer
  @writer ||= Output::Writer::Substitute.build
end

Class Method Details

.build(arguments = nil, env: nil) ⇒ Object



48
49
50
51
52
53
54
55
56
57
58
# File 'lib/test_bench/cli.rb', line 48

def self.build(arguments=nil, env: nil)
  arguments ||= ::ARGV
  env ||= ::ENV

  instance = new(*arguments)
  instance.env = env
  Output::Writer.configure(instance)
  Run.configure(instance)
  Random.configure(instance)
  instance
end

.call(arguments = nil, env: nil) ⇒ Object



60
61
62
63
64
65
66
67
68
69
# File 'lib/test_bench/cli.rb', line 60

def self.call(arguments=nil, env: nil)
  instance = build(arguments, env:)

  session = instance.run.session
  Session::Store.reset(session)

  exit_code = instance.()

  exit(exit_code)
end

.exit_code(result) ⇒ Object



288
289
290
291
292
293
294
295
296
# File 'lib/test_bench/cli.rb', line 288

def self.exit_code(result)
  if result == true
    0
  elsif result == false
    1
  else
    2
  end
end

Instance Method Details

#callObject



71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/test_bench/cli.rb', line 71

def call
  parse_arguments

  if exit_code?
    return exit_code
  end

  writer.puts(RUBY_DESCRIPTION)
  writer.puts("Random Seed: #{random.seed.to_s(36)}")
  writer.puts

  default_path = Defaults.tests_directory

  result = run.! do |run|
    if not stdin.tty?
      until stdin.eof?
        path = stdin.gets(chomp: true)

        next if path.empty?

        run << path
      end
    end

    arguments.each do |path|
      run << path
    end

    if not run.ran?
      run << default_path
    end
  end

  self.exit_code = self.class.exit_code(result)

  exit_code
end

#exit_code?Boolean

Returns:

  • (Boolean)


256
257
258
# File 'lib/test_bench/cli.rb', line 256

def exit_code?
  !exit_code.nil?
end

#negated?(switch) ⇒ Boolean

Returns:

  • (Boolean)


248
249
250
251
252
253
254
# File 'lib/test_bench/cli.rb', line 248

def negated?(switch)
  if switch.start_with?('--')
    switch.start_with?('--no-')
  else
    /^-[A-Z]/.match?(switch)
  end
end

#next_argument(argument_index) ⇒ Object



280
281
282
# File 'lib/test_bench/cli.rb', line 280

def next_argument(argument_index)
  arguments[argument_index]
end

#next_argument!(argument_index) ⇒ Object



284
285
286
# File 'lib/test_bench/cli.rb', line 284

def next_argument!(argument_index)
  arguments.delete_at(argument_index)
end

#parse_argumentsObject



109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
# File 'lib/test_bench/cli.rb', line 109

def parse_arguments
  argument_index = 0

  until argument_index == arguments.count
    next_argument = next_argument(argument_index)

    if not next_argument.start_with?('-')
      argument_index += 1
      next
    end

    switch = next_argument!(argument_index)

    case switch
    when '--'
      break

    when '-h', '--help'
      print_help_text

      self.exit_code = 0

    when '-v', '--version'
      writer.puts "TestBench Version: #{version}"

      self.exit_code = 0

    when '-d', '--detail', '--no-detail'
      if not negated?(switch)
        detail_policy_text = 'on'
      else
        detail_policy_text = 'off'
      end

      detail_policy = detail_policy_text.to_sym
      Session::Output::Detail.assure_detail(detail_policy)

      env['TEST_BENCH_DETAIL'] = detail_policy_text

    when '-x', '--exclude', '--no-exclude'
      if not negated?(switch)
        exclude_pattern_text = switch_value!(argument_index, switch)

        if env.key?('TEST_BENCH_EXCLUDE_FILE_PATTERN')
          exclude_pattern_text = [
            env['TEST_BENCH_EXCLUDE_FILE_PATTERN'],
            exclude_pattern_text
          ].join(':')
        end
      else
        exclude_pattern_text = ''
      end

      env['TEST_BENCH_EXCLUDE_FILE_PATTERN'] = exclude_pattern_text

    when '-f', '-F', '--only-failure', '--no-only-failure'
      if not negated?(switch)
        only_failure_text = 'on'
      else
        only_failure_text = 'off'
      end

      env['TEST_BENCH_ONLY_FAILURE'] = only_failure_text

    when '-p', '-P', '--require-passing-test', '--no-require-passing-test'
      if not negated?(switch)
        require_passing_tests = 'on'
      else
        require_passing_tests = 'off'
      end

      env['TEST_BENCH_REQUIRE_PASSING_TEST'] = require_passing_tests

    when '-o', '--output-styling'
      output_styling_text = switch_value(argument_index) do
        'on'
      end

      output_styling = output_styling_text.to_sym
      Output::Writer::Styling.assure_styling(output_styling)

      env['TEST_BENCH_OUTPUT_STYLING'] = output_styling_text

    when '-s', '--seed'
      seed_text = switch_value!(argument_index, switch)

      begin
        Integer(seed_text)
      rescue
        raise ArgumentError, "Seed switch must be an integer (Seed: #{seed_text.inspect})"
      end

      env['TEST_BENCH_SEED'] = seed_text

    when '-r', '--require'
      library = switch_value!(argument_index, switch)

      require library

    else
      raise ArgumentError, "Unknown switch #{switch.inspect}"
    end
  end
end


214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
# File 'lib/test_bench/cli.rb', line 214

def print_help_text
  writer.write <<~TEXT
  Usage: #{program_name} [options] [paths]

  Informational Options:
  \t-h, --help                        Print this help message and exit successfully
  \t-v, --version                     Print version and exit successfully

  Configuration Options:
  \t-d, --[no]detail                  Always show (or hide) details (Default: #{Session::Output::Detail.default})
  \t-x, --[no-]exclude PATTERN        Do not execute test files matching PATTERN (Default: #{Run::GetFiles::Defaults.exclude_patterns.inspect})
  \t-f, --[no-]only-failure           Don't display output for test files that pass (Default: #{Run::Output::File::Defaults.only_failure ? 'on' : 'off'})
  \t-o, --output-styling [on|off|detect]
  \t                                  Render output coloring and font styling escape codes (Default: #{Output::Writer::Styling.default})
  \t-s, --seed NUMBER                 Sets pseudo-random number seed (Default: not set)

  Other Options:
  \t-r, --require LIBRARY             Require LIBRARY before running any files

  Paths to test files (and directories containing test files) can be given after any command line arguments or via STDIN (or both).

  If no paths are given, a default path (#{Defaults.tests_directory}) is scanned for test files.

  The following environment variables can also control execution:

  \tTEST_BENCH_DETAIL                 Same as -d or --detail
  \tTEST_BENCH_EXCLUDE_FILE_PATTERN   Same as -x or --exclude-file-pattern
  \tTEST_BENCH_ONLY_FAILURE           Same as -f or --only-failure
  \tTEST_BENCH_OUTPUT_STYLING         Same as -o or --output-styling
  \tTEST_BENCH_SEED                   Same as -s or --seed

  TEXT
end

#switch_value(argument_index, &no_value_action) ⇒ Object



266
267
268
269
270
271
272
273
274
275
276
277
278
# File 'lib/test_bench/cli.rb', line 266

def switch_value(argument_index, &no_value_action)
  next_value = next_argument(argument_index)

  if next_value.nil? || next_value.start_with?('-')
    switch_value = nil

    return no_value_action.()
  else
    switch_value = next_argument!(argument_index)

    return switch_value
  end
end

#switch_value!(argument_index, argument) ⇒ Object



260
261
262
263
264
# File 'lib/test_bench/cli.rb', line 260

def switch_value!(argument_index, argument)
  switch_value(argument_index) do
    raise ArgumentError, "Argument #{argument.inspect} requires an argument"
  end
end