probatio 0.9.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a2ad9b151150b2a112358c58b0a480d72eaba65a400ae8a6a21e54d74e61136e
4
- data.tar.gz: d2d008237d2133169b56dedd842e72c27efc760caa2ddf13d95d232e6c5b6197
3
+ metadata.gz: 341afa67e0fa27ef98742a21d8e5842b132ba812cb9fc702d37793ea702fbeb7
4
+ data.tar.gz: fdf5c8a7baface7d2fa2d95ceb2b201364ce0a2c98f5926c5659617a8402cbc2
5
5
  SHA512:
6
- metadata.gz: ceb178be47b755d00d0bedb8f16087d983b3e5ab61afa1c7b22d366ecd8f3646edb231f70f840cf2a3ce65b744991802b087b9806e9f385d009d6fbf60ca76fe
7
- data.tar.gz: b1845474c38066483e226dfbd87ef75697ab0d39a2deaf9b550229ab9000744b3906f1e133b453804e5d02148b5252a5f79e691ad09c27d44ca804d496fc72c4
6
+ metadata.gz: 0ec333e78a402d7c77e518bc212c3cb47b40b26e82c807692d924c5d0755d7b460801a527966f0621b06934e66f1961d1db84896b174633bf995135f0c9cca69
7
+ data.tar.gz: c8293d3a2d05b726618ab9965ce970841fe82c14d7d35312ce650a8676aaeba873e221bf19dd7a528c690a1575b1558218995ee7ec802359e2fee4092ce541bb
data/CHANGELOG.md CHANGED
@@ -2,7 +2,17 @@
2
2
  # CHANGELOG.md
3
3
 
4
4
 
5
- ## djan 0.9.0 released 2024-12-19
5
+ ## proba 1.1.0 released 2025-04-16
6
+
7
+ * Introduce `assert_no_error { do_this_or_that() }`
8
+
9
+
10
+ ## proba 1.0.0 released 2025-02-08
11
+
12
+ * Initial release
13
+
14
+
15
+ ## proba 0.9.0 released 2024-12-19
6
16
 
7
17
  * Initial bogus release ;-)
8
18
 
data/README.md CHANGED
@@ -7,6 +7,313 @@
7
7
  Test tools for floraison and flor. Somewhere between Minitest and Rspec, but not as excellent.
8
8
 
9
9
 
10
+ ## Goals
11
+
12
+ * versatile `bundle exec proba`, run this or these tests, at the line
13
+ * `bundle exec proba first` for first failing tests
14
+ * `bundle exec proba last` for last failing tests
15
+ * `bundle exec proba .` for the test currently edited `.test-point`
16
+ * `bundle exec proba f` for the test file currently edited `.test-point`
17
+ * `bundle exec proba list.txt` to run a list of tests
18
+ * `bundle exec proba list.rb` to run a list of tests (Ruby array)
19
+
20
+
21
+ ## Usage
22
+
23
+ ```
24
+ Usage: bundle exec proba [OPTIONS] [DIRS] [FILES] [OTHERS] [ENVS]
25
+
26
+ A test runner for Ruby.
27
+
28
+ Options:
29
+ -h, --help Show this help message and quit
30
+ --version Show proba's version and exit
31
+ -c, --color Enable colour output anyway
32
+ -C, --no-color Disable colour output
33
+ -y, --dry Don't run the tests, just flag them as successes
34
+ -n, --name PATTERN include tests matching /regexp/ or string in run
35
+ -e, --exclude PATTERN Exclude /regexp/ or string from run
36
+ -p, --print Dumps the test tree
37
+ -m, --map Dumps the test file map
38
+ -s, --seed Sets random seed
39
+ -d, --debug smr 's' for start opts, 'm' for messages, 'r' for $DEBUG
40
+ -x, --example Outputs an example test file
41
+ -X, --plugin-example Outputs an example plugin file
42
+ --mangle Turns the given _spec.rb files into proba _test.rb
43
+
44
+ Dirs:
45
+ Defaults to test/ if no files nor dir are given.
46
+ Probatio will look at all the *_helper[s].rb, *_test[s].rb files
47
+ under the given dirs and also at the setup.rb, *_setup.rb files
48
+
49
+ Files:
50
+ List of test files to scan for tests.
51
+ A file may end with `:123` to indicate that the test at line 123 should
52
+ be run. Multiple "colon-lnumber" suffixes may be specified, as in
53
+ `test/fun/that_test.rb:123:456`
54
+
55
+ Others:
56
+ Short codes like
57
+ * `bundle exec proba -1`
58
+ * `bundle exec proba last` run the last failing test of the last run
59
+ * `bundle exec proba first`
60
+ * `bundle exec proba 1st`
61
+ * `bundle exec proba 0` run the first failing test of the last run
62
+ Lists:
63
+ * `bundle exec proba list.txt` will run all the tests in list.txt
64
+ * `bundle exec proba a_list.rb` will eval and lists the arrayed tests
65
+
66
+
67
+ Envs:
68
+ Short FULLCAPS environment variable setters driven by a
69
+ `.probatio-environments.rb` file in the current work directory.
70
+
71
+ ```
72
+ # .probatio-environments.rb
73
+ {
74
+ D: { 'FLOR_DEBUG' => 'dbg,stdout' },
75
+ DD: { 'FLOR_DEBUG' => 'dbg,sto,stdout' },
76
+ }
77
+ ```
78
+
79
+ Examples:
80
+ # Run all tests in a dir
81
+ bundle exec proba test/
82
+
83
+ # Run all the tests in a file
84
+ bundle exec proba test/this_test.rb
85
+ ```
86
+
87
+ ## Test files
88
+
89
+ By default probatio looks into `test/` for test files ending in `_test.rb` or `_tests.rb` but first look at helpers ending in `_helper.rb` or `_helpers.rb`.
90
+
91
+ A typical test hierarchy:
92
+ ```
93
+ test/
94
+ |-- helpers/
95
+ | |-- some_helpers.rb
96
+ | `-- some_other_helpers.rb
97
+ |-- this_test.rb
98
+ |-- that_test.rb
99
+ `-- more_tests.rb
100
+ ```
101
+
102
+ ```ruby
103
+ group 'core' do
104
+
105
+ setup do
106
+ # occurs once before tests and sub-groups in group 'core'
107
+ end
108
+ teadowm do
109
+ # occurs once after tests and sub-groups in group 'core'
110
+ end
111
+
112
+ group 'alpha' do
113
+
114
+ before do
115
+ # is run in the separate test context before _each_ test
116
+ end
117
+ after do
118
+ # is run in the separate test context after _each_ test
119
+ end
120
+
121
+ test 'one' do
122
+
123
+ MyLib.do_this_or_that()
124
+
125
+ assert_nil nil
126
+ assert_not_nil [], 1
127
+
128
+ assert_true true
129
+ assert_false 1 > 2
130
+
131
+ assert_truthy "yes", "no"
132
+ assert_trueish "yes", "no"
133
+ assert_falsy nil, false
134
+ assert_falsey nil, false
135
+ assert_falseish nil, false
136
+
137
+ assert_any %w[ an array ], 'a string'
138
+ assert_empty [], ''
139
+
140
+ assert_size [], 0
141
+ assert_size 'foo', 3
142
+ assert_size { a: 1 }, 1
143
+ assert_count %w[ a b c ], 3
144
+
145
+ assert_equal 'one', 'o' + 'ne'
146
+ # checks that all its arguments are equal
147
+
148
+ assert_match 'one', /^one$/
149
+ # checks that it receives a regex and one or more strings
150
+ # and that all those strings match the regex
151
+
152
+ assert_start_with 'one', 'one two or three'
153
+ # checks that the shortest string is the start of the remaining string
154
+ # arguments
155
+ assert_end_with 'three', 'one two or three'
156
+ # checks that the shortest string is the end of the remaining string
157
+ # arguments
158
+
159
+ assert_include 1, [ 1, 'two' ]
160
+ # checks that the first array argument includes all other arguments
161
+
162
+ assert_error(ArgumentError) { do_this_or_that() }
163
+ # checks that the given block raises an ArgumentError
164
+ assert_error(ArgumentError, /bad/) { do_this_or_that() }
165
+ # checks that the given block raises an ArgumentError and
166
+ # the error message matches the /bad/ regexp
167
+ assert_error lambda { do_this_or_that() }, ArgumentError
168
+ # checks that the given Proc raises an ArgumentError
169
+ assert_error lambda { do_this_or_that() }, ArgumentError, 'bad'
170
+ # checks that the given Proc raises an ArgumentError and
171
+ # the error message == "bad"
172
+
173
+ assert_no_error { do_this_or_that() }
174
+ assert_no_error lambda { do_this_or_that() }
175
+ assert_not_error { do_this_or_that() }
176
+ assert_not_error lambda { do_this_or_that() }
177
+ # checks that the block or Proc does not raise an error
178
+
179
+ assert_hashy(
180
+ this_thing => 1,
181
+ that_thing => 'two')
182
+ # combines two assert_equals in one
183
+
184
+ assert_instance_of 1, Integer
185
+ assert_is_a Integer, 123
186
+ # checks that value or set of values are of a given of class
187
+
188
+ assert 1, 1
189
+ # behaves like assert_equal
190
+ assert 'one', /one/i
191
+ # behaves like assert_match
192
+ assert 11 => '10'.to_i + 1
193
+ # assert equality between key and value
194
+ assert 'one' => 'on' + 'e', 'two' => :two.to_s
195
+ # assert equality between keys and values
196
+ end
197
+ end
198
+
199
+ group 'bravo' do
200
+ end
201
+ end
202
+
203
+ group 'core' do
204
+ #
205
+ # it's OK to re-open a group to add sub-groups, tests,
206
+ # and setups, teardowns, befores, or afters
207
+ #
208
+ # it's OK to re-open a group in another file, as long
209
+ # as it's the same name at the same point in the name hierarchy
210
+
211
+ _test 'not yet' do
212
+ #
213
+ # prefix a test, a group, or other element with _
214
+ # marks it as _pending
215
+ end
216
+ end
217
+
218
+ group 'core', 'sub-core', 'sub-sub-core' do
219
+ #
220
+ # it's OK to specifiy a path of group names
221
+
222
+ test 'this' do
223
+ end
224
+ end
225
+
226
+ group 'core < sub-core < sub-sub-core' do
227
+ #
228
+ # this is also ok...
229
+
230
+ test 'that' do
231
+ end
232
+ end
233
+ ```
234
+
235
+
236
+ ## .test-point
237
+
238
+ By running `bx proba .`, one tells probatio to run the test pointed at in the file `.test-point`.
239
+
240
+ Here is an example of `.test-point` content:
241
+ ```
242
+ test/wma/dwm/onboarding_benchmark_non_star_test.rb:189
243
+ ```
244
+
245
+ For Vim users, here is a snippet that saves the current path and line number to `.test-point` every 700ms:
246
+ ```vim
247
+ au BufEnter test/*_test.rb,test/**/*_test.rb :set updatetime=700
248
+
249
+ au BufEnter,CursorHold,BufWrite test/*_test.rb,test/**/*_test.rb :call writefile([ expand('%') . ':' . line('.') ], '.test-point', 'b')
250
+ ```
251
+
252
+
253
+ ## .probatio-output.rb
254
+
255
+ By default, probatio summarizes a run in a `.probatio-output.rb` file.
256
+
257
+ Here is an example of such a file:
258
+ ```ruby
259
+ # .probatio-output.rb
260
+ {
261
+ argv: [ "test/alpha_test.rb:23" ],
262
+ failures:
263
+ [
264
+ { n: "test_fail", p: "test/alpha_test.rb", l: 24, t: "0s000_077" },
265
+ { n: "test_fail", p: "test/alpha_test.rb", l: 29, t: "0s000_033" },
266
+ ],
267
+ duration: "0s001_297",
268
+ probatio: { v: "1.0.0" },
269
+ ruby:
270
+ {
271
+ p: "/usr/local/bin/ruby33",
272
+ d: "ruby 3.3.5 (2024-09-03 revision ef084cc8f4) [x86_64-openbsd]",
273
+ l: 100,
274
+ },
275
+ some_env:
276
+ {
277
+ USER: "jmettraux",
278
+ HOME: "/home/jmettraux",
279
+ PATH: "/home/jmettraux/.gem/ruby/3.3/bin:/home/jmettraux/.pkg_rubies/ruby33:/usr/local/jdk-21/bin:/home/jmettraux/bin:/bin:/usr/bin:/sbin:/usr/sbin:/usr/X11R6/bin:/usr/local/bin:/usr/local/sbin",
280
+ SHELL: "/usr/local/bin/fish",
281
+ GEM_HOME: "/home/jmettraux/.gem/ruby/3.3",
282
+ PWD: "/home/jmettraux/w/probatio/test",
283
+ },
284
+ }
285
+ ```
286
+
287
+ Probatio uses it when servicing `bundle exec proba 0` or `bundle exe proba -1`.
288
+
289
+ It can also be useful to other tools around probatio.
290
+
291
+
292
+ ## Warnings
293
+
294
+ ```
295
+ $ RUBYOPT="-w $RUBYOPT" bundle exec proba
296
+ ```
297
+
298
+
299
+ ## Plugins
300
+
301
+ ```ruby
302
+ #
303
+ # examples of probatio plugins
304
+
305
+ class MyProbatioPlugin
306
+
307
+ def on_test_succeed(ev)
308
+
309
+ puts "GREAT SUCCESS! " + ev.to_s
310
+ end
311
+ end
312
+
313
+ Probatio.plug(MyProbatioPlugin.new)
314
+ ```
315
+
316
+
10
317
  ## LICENSE
11
318
 
12
319
  MIT, see [LICENSE.txt](LICENSE.txt)
data/exe/proba CHANGED
@@ -2,15 +2,259 @@
2
2
 
3
3
  require 'probatio'
4
4
 
5
+
5
6
  #
6
7
  # gather opts
7
8
 
8
- opts = { dir: 'test' }
9
+ args = ARGV.dup
10
+
11
+ def rework_switch(a)
12
+
13
+ case a
14
+ when '-n', '--name' then '--name'
15
+ when '-e', '--exclude' then '--exclude'
16
+ when '-s', '--seed' then '--seed'
17
+ when '-d', '--debug' then '--debug'
18
+ else nil
19
+ end
20
+ end
21
+
22
+ def is_directory_with_tests?(path)
23
+
24
+ File.directory?(path) &&
25
+ Dir[File.join(path, '**', '*_test.rb')].any?
26
+ end
27
+
28
+ switches = {}
29
+ dirs, files, lists, strings, environments, integers = [], [], [], [], [], []
30
+
31
+ while a = args.shift
32
+
33
+ if a.match?(/^(-[a-z]|--[a-z0-9][-a-z0-9]+)$/i)
34
+ if k = rework_switch(a)
35
+ (switches[k] ||= []) << args.shift
36
+ else
37
+ switches[a] = true
38
+ end
39
+ elsif File.directory?(a) && a != '.'
40
+ dirs << a
41
+ elsif File.file?(a) && (a.match?(/(\.txt|_list\.rb)$/))
42
+ lists << a
43
+ elsif File.file?(a.split(':').first)
44
+ files << a
45
+ elsif a.match?(/\A-?\d+\z/)
46
+ integers << a.to_i
47
+ elsif a.match?(/\A[A-Z][A-Z0-9]*\z/)
48
+ environments << a
49
+ else
50
+ strings << a
51
+ end
52
+ end
53
+
54
+ $_PROBATIO_COLOURS =
55
+ switches['-C'] || switches['--no-color'] ? Colorato.no_colours :
56
+ switches['-c'] || switches['--color'] ? Colorato.colours :
57
+ ( ! $stdout.tty?) ? Colorato.no_colours :
58
+ Colorato.colours
59
+
60
+ $_PROBATIO_DEBUG =
61
+ (switches['--debug'] || []).join.downcase.chars.collect(&:to_sym)
62
+ $DEBUG =
63
+ true if $_PROBATIO_DEBUG.include?(:r)
64
+
65
+ Probatio.dbg_s {
66
+ ' * switches: ' + switches.inspect + "\n" +
67
+ ' * strings: ' + strings.inspect + "\n" +
68
+ ' * integers: ' + integers.inspect + "\n" +
69
+ ' * environments: ' + environments.inspect }
70
+
71
+ if switches['-h'] || switches['--help']
72
+
73
+ puts %{
74
+ Usage: bundle exec proba [OPTIONS] [DIRS] [FILES] [OTHERS] [ENVS]
75
+
76
+ A test runner for Ruby.
77
+
78
+ Options:
79
+ -h, --help Show this help message and quit
80
+ --version Show proba's version and exit
81
+ -c, --color Enable colour output anyway
82
+ -C, --no-color Disable colour output
83
+ -y, --dry Don't run the tests, just flag them as successes
84
+ -n, --name PATTERN include tests matching /regexp/ or string in run
85
+ -e, --exclude PATTERN Exclude /regexp/ or string from run
86
+ -p, --print Dumps the test tree
87
+ -m, --map Dumps the test file map
88
+ -s, --seed Sets random seed
89
+ -d, --debug smr 's' for start opts, 'm' for messages, 'r' for $DEBUG
90
+ -x, --example Outputs an example test file
91
+ -X, --plugin-example Outputs an example plugin file
92
+ --mangle Turns the given _spec.rb files into proba _test.rb
93
+
94
+ Dirs:
95
+ Defaults to test/ if no files nor dir are given.
96
+ Probatio will look at all the *_helper[s].rb, *_test[s].rb files
97
+ under the given dirs and also at the setup.rb, *_setup.rb files
98
+
99
+ Files:
100
+ List of test files to scan for tests.
101
+ A file may end with `:123` to indicate that the test at line 123 should
102
+ be run. Multiple "colon-lnumber" suffixes may be specified, as in
103
+ `test/fun/that_test.rb:123:456`
104
+
105
+ Others:
106
+ Short codes like
107
+ * `bundle exec proba -1`
108
+ * `bundle exec proba last` run the last failing test of the last run
109
+ * `bundle exec proba first`
110
+ * `bundle exec proba 1st`
111
+ * `bundle exec proba 0` run the first failing test of the last run
112
+ Lists:
113
+ * `bundle exec proba list.txt` will run all the tests in list.txt
114
+ * `bundle exec proba a_list.rb` will eval and lists the arrayed tests
115
+
116
+
117
+ Envs:
118
+ Short FULLCAPS environment variable setters driven by a
119
+ `.probatio-environments.rb` file in the current work directory.
120
+
121
+ ```
122
+ # .probatio-environments.rb
123
+ {
124
+ D: { 'FLOR_DEBUG' => 'dbg,stdout' },
125
+ DD: { 'FLOR_DEBUG' => 'dbg,sto,stdout' },
126
+ }
127
+ ```
128
+
129
+ Examples:
130
+ # Run all tests in a dir
131
+ bundle exec proba test/
132
+
133
+ # Run all the tests in a file
134
+ bundle exec proba test/this_test.rb
135
+ }.rstrip + "\n\n"
136
+ exit 0
137
+ end
138
+
139
+ if switches['--version']
140
+
141
+ puts "proba -- probatio test tool -- #{Probatio::VERSION}"
142
+ exit 0
143
+
144
+ elsif switches['-x'] || switches['--example']
145
+
146
+ puts File.read(File.join(__dir__, '../lib/probatio/examples/a_test.rb'))
147
+ exit 0
148
+
149
+ elsif switches['-X'] || switches['--plugin-example']
150
+
151
+ puts File.read(File.join(__dir__, '../lib/probatio/examples/a_plugin.rb'))
152
+ exit 0
153
+
154
+ elsif switches['--mangle']
155
+
156
+ require 'probatio/mangle'
157
+ Probatio.mangle(dirs, files, switches)
158
+ exit 0
159
+ end
160
+
161
+ opts = {}
162
+
163
+ opts[:dry] = true if switches['-y'] || switches['--dry']
164
+
165
+ opts[:map] = true if switches['-m'] || switches['--map']
166
+ opts[:print] = true if switches['-p'] || switches['--print']
167
+
168
+ opts[:dirs] = dirs if dirs.any?
169
+ opts[:files] = files.any? ? files : []
170
+
171
+ def read_list(a, item)
172
+
173
+ case item
174
+ when Array
175
+ item.each { |e| read_list(a, e) }
176
+ when Hash
177
+ if item[:p].is_a?(String)
178
+ a << [ item[:p], item[:l] ].compact.collect(&:to_s).join(':')
179
+ elsif (fs = item[:failures] || item[:files] || item[:paths]).is_a?(Array)
180
+ read_list(a, fs)
181
+ #else
182
+ # no item to add...
183
+ end
184
+ else
185
+ s = item.to_s.strip
186
+ a << s if File.file?(s.split(':').first)
187
+ end
188
+
189
+ a
190
+ end
191
+
192
+ prev = Kernel.eval(File.read(Probatio.opath)) rescue { failures: [] }
193
+ fails = prev[:failures].collect { |f| "#{f[:p]}:#{f[:l]}" }
194
+ #print 'fails:'; pp fails
195
+ #
196
+ tpoint = File.exist?(Probatio.tpath) ? File.read(Probatio.tpath).strip : nil
197
+ #
198
+ strings.each do |s|
199
+ opts[:files] <<
200
+ case s
201
+ when '.' then tpoint
202
+ when 'f' then tpoint && tpoint.split(':').first
203
+ when '1st', 'first' then fails[0]
204
+ when 'last' then fails[-1]
205
+ when /^:\d+$/ then fails.find { |f| f.end_with?(s) }
206
+ else nil; end
207
+ end
208
+ integers.each do |i|
209
+ opts[:files] << fails[i]
210
+ end
211
+ lists.each do |li|
212
+ opts[:files].concat(
213
+ li.end_with?('_list.rb') ? read_list([], Kernel.eval(File.read(li))) :
214
+ read_list([], File.readlines(li)))
215
+ end
216
+ #
217
+ opts[:files] = opts[:files].uniq.compact
218
+ opts[:files] = nil if opts[:files].empty? && strings.empty? && integers.empty?
219
+
220
+ opts[:dirs] = [
221
+ is_directory_with_tests?('test') ? 'test' :
222
+ is_directory_with_tests?('spec') ? 'spec' :
223
+ 'test'
224
+ ] unless opts[:dirs] || opts[:files]
225
+
226
+ opts[:includes] = Probatio.to_rexes_and_strs(switches['--name'])
227
+ opts[:excludes] = Probatio.to_rexes_and_strs(switches['--exclude'])
228
+
229
+ s = switches['--seed'] || []
230
+ s = s.any? ? s.first : (Time.now.to_f * 1000) % 99_999
231
+ opts[:seed] = s.to_i
232
+
233
+ if environments.any?
234
+ envs =
235
+ (File.exist?(Probatio.epath) &&
236
+ Kernel.eval(File.read(Probatio.epath)) rescue nil) ||
237
+ {}
238
+ environments.each do |e|
239
+ (envs[e.to_sym] || {}).each { |k, v|
240
+ Probatio.dbg_s { " . setting ENV[#{k.inspect}] to #{v.inspect}" }
241
+ ENV[k] = v }
242
+ end
243
+ end
244
+
245
+ Probatio.dbg_s { ' * opts: ' + opts.inspect }
246
+
247
+ if strings & %w[ . 1st first last ]
248
+ puts $_PROBATIO_COLOURS.dark_grey
249
+ puts opts[:files]
250
+ print $_PROBATIO_COLOURS.reset
251
+ end
9
252
 
10
253
  #
11
254
  # run
12
255
 
13
256
  Probatio.run(opts)
14
257
 
258
+
15
259
  # vim: set filetype=ruby
16
260