Bryton 0.1
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 +7 -0
- data/README.md +23 -0
- data/lib/bryton/runner.rb +459 -0
- data/lib/bryton/tools.rb +394 -0
- metadata +45 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 515b6e28901538ec80a86cae04da951149a4c5e726d57869c86386ca34e8928f
|
4
|
+
data.tar.gz: c28f2fe9fb9962eef207fecdca9853e9b3489e0144a15d938bb38fbc784b7f47
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 49faf782a0a7b691a854fea4211e1038fca60df54c7000a0cae5bbbb298ba75530ba8688f2db878e1709e9b5dc53fbf2f7d7352812ec65461d4bb9d04a3405a7
|
7
|
+
data.tar.gz: 219c8f0a8106fb9715ecd05375d78346d7a2530b721680beb70ac80eb465669defb13ad9b76e96a8b51fd135dedcdb786468cd0b3fd7b66235e36835184b5501
|
data/README.md
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# Bryton
|
2
|
+
|
3
|
+
Bryton is a file based testing protocol. Each file contains one or more tests.
|
4
|
+
The results of the tests are reported in STDOUT as a JSON Object.
|
5
|
+
|
6
|
+
Bryton is not ready for use yet. Just sharing online for a few collaborators.
|
7
|
+
|
8
|
+
## Install
|
9
|
+
|
10
|
+
```
|
11
|
+
gem install bryton
|
12
|
+
```
|
13
|
+
|
14
|
+
## Author
|
15
|
+
|
16
|
+
Mike O'Sullivan
|
17
|
+
mike@idocs.com
|
18
|
+
|
19
|
+
## History
|
20
|
+
|
21
|
+
| version | date | notes |
|
22
|
+
|----------|--------------|-----------------|
|
23
|
+
| 1.0 | May 16, 2023 | Initial upload. |
|
@@ -0,0 +1,459 @@
|
|
1
|
+
#!/usr/bin/ruby -w
|
2
|
+
require 'timeout'
|
3
|
+
require 'json'
|
4
|
+
require 'fso'
|
5
|
+
require 'hash/digger'
|
6
|
+
require 'talk-to-me'
|
7
|
+
|
8
|
+
|
9
|
+
#===============================================================================
|
10
|
+
# Bryton
|
11
|
+
#
|
12
|
+
module Bryton
|
13
|
+
end
|
14
|
+
#
|
15
|
+
# Bryton
|
16
|
+
#===============================================================================
|
17
|
+
|
18
|
+
|
19
|
+
# load bryton xeme classes
|
20
|
+
require 'bryton/xeme'
|
21
|
+
|
22
|
+
|
23
|
+
#===============================================================================
|
24
|
+
# Bryton::FSO
|
25
|
+
# Just initializing namespace.
|
26
|
+
#
|
27
|
+
module Bryton::FSO
|
28
|
+
end
|
29
|
+
#
|
30
|
+
# Bryton::FSO
|
31
|
+
#===============================================================================
|
32
|
+
|
33
|
+
|
34
|
+
#===============================================================================
|
35
|
+
# Bryton::FSO::Dir
|
36
|
+
#
|
37
|
+
class Bryton::FSO::Dir < FSO::Dir
|
38
|
+
attr_reader :xeme
|
39
|
+
attr_accessor :stop_on_fail
|
40
|
+
attr_accessor :verbose
|
41
|
+
attr_accessor :run_tests
|
42
|
+
|
43
|
+
#---------------------------------------------------------------------------
|
44
|
+
# classes
|
45
|
+
#
|
46
|
+
def self.classes
|
47
|
+
return {
|
48
|
+
'dir'=>Bryton::FSO::Dir,
|
49
|
+
'file'=>Bryton::FSO::File
|
50
|
+
};
|
51
|
+
end
|
52
|
+
#
|
53
|
+
# classes
|
54
|
+
#---------------------------------------------------------------------------
|
55
|
+
|
56
|
+
|
57
|
+
#---------------------------------------------------------------------------
|
58
|
+
# initialize
|
59
|
+
#
|
60
|
+
def initialize(p_path='./')
|
61
|
+
super(p_path)
|
62
|
+
@settings = nil
|
63
|
+
@children = nil
|
64
|
+
@stop_on_fail = false
|
65
|
+
end
|
66
|
+
#
|
67
|
+
# initialize
|
68
|
+
#---------------------------------------------------------------------------
|
69
|
+
|
70
|
+
|
71
|
+
#---------------------------------------------------------------------------
|
72
|
+
# settings
|
73
|
+
#
|
74
|
+
def settings
|
75
|
+
# cache bryton.json if necessary
|
76
|
+
if not @settings
|
77
|
+
settings_path = "#{path}/bryton.json"
|
78
|
+
@settings = {'active'=>true}
|
79
|
+
|
80
|
+
# slurp in settings file
|
81
|
+
if ::File.exist?(settings_path)
|
82
|
+
explicit = ::File.read(settings_path)
|
83
|
+
explicit = JSON.parse(explicit)
|
84
|
+
@settings = @settings.merge(explicit)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
# return
|
89
|
+
return @settings
|
90
|
+
end
|
91
|
+
#
|
92
|
+
# settings
|
93
|
+
#---------------------------------------------------------------------------
|
94
|
+
|
95
|
+
|
96
|
+
#---------------------------------------------------------------------------
|
97
|
+
# meta
|
98
|
+
#
|
99
|
+
def meta
|
100
|
+
return settings['meta'] || {}
|
101
|
+
end
|
102
|
+
#
|
103
|
+
# meta
|
104
|
+
#---------------------------------------------------------------------------
|
105
|
+
|
106
|
+
|
107
|
+
#---------------------------------------------------------------------------
|
108
|
+
# children
|
109
|
+
#
|
110
|
+
def children(opts={})
|
111
|
+
# cache @children if it's not already defined
|
112
|
+
if not @children
|
113
|
+
chdir do
|
114
|
+
@children = []
|
115
|
+
|
116
|
+
# special case: files element exists but is false
|
117
|
+
if settings.has_key?('files') and (not settings['files'])
|
118
|
+
return @children
|
119
|
+
end
|
120
|
+
|
121
|
+
# build list of child files
|
122
|
+
children_explicit opts
|
123
|
+
children_implicit super(), opts
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
# return
|
128
|
+
return @children
|
129
|
+
end
|
130
|
+
#
|
131
|
+
# children
|
132
|
+
#---------------------------------------------------------------------------
|
133
|
+
|
134
|
+
|
135
|
+
#---------------------------------------------------------------------------
|
136
|
+
# children_explicit
|
137
|
+
#
|
138
|
+
def children_explicit(opts)
|
139
|
+
explicits = settings['files'] || {}
|
140
|
+
|
141
|
+
explicits.each do |child_path, child_settings|
|
142
|
+
if child_settings
|
143
|
+
if child = self.class.existing(child_path)
|
144
|
+
if child.settings['active']
|
145
|
+
@children.push child
|
146
|
+
end
|
147
|
+
else
|
148
|
+
raise 'non-existent-file-in-list: ' + child_path
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
#
|
154
|
+
# children_explicit
|
155
|
+
#---------------------------------------------------------------------------
|
156
|
+
|
157
|
+
|
158
|
+
#---------------------------------------------------------------------------
|
159
|
+
# children_implicit
|
160
|
+
# skips dev.* files
|
161
|
+
#
|
162
|
+
def children_implicit(kids, opts)
|
163
|
+
# early exit: if filter is true, don't import implicit children
|
164
|
+
settings['listed-only'] and return
|
165
|
+
|
166
|
+
kids.each do |child|
|
167
|
+
if not child_names.include?(child.name)
|
168
|
+
unless child.name.match(/\Adev\./mu)
|
169
|
+
if child.dir?
|
170
|
+
@children.push child
|
171
|
+
elsif child.executable?
|
172
|
+
@children.push child
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
#
|
179
|
+
# children_implicit
|
180
|
+
#---------------------------------------------------------------------------
|
181
|
+
|
182
|
+
|
183
|
+
#---------------------------------------------------------------------------
|
184
|
+
# child_names
|
185
|
+
#
|
186
|
+
def child_names
|
187
|
+
return @children.map{|child| child.name}
|
188
|
+
end
|
189
|
+
#
|
190
|
+
# child_names
|
191
|
+
#---------------------------------------------------------------------------
|
192
|
+
|
193
|
+
|
194
|
+
#---------------------------------------------------------------------------
|
195
|
+
# run
|
196
|
+
#
|
197
|
+
def run(opts={})
|
198
|
+
opts = {'nested'=>0}.merge(opts)
|
199
|
+
xeme = Xeme.new()
|
200
|
+
|
201
|
+
# verbosify
|
202
|
+
unless opts['first']
|
203
|
+
TTM.puts title(opts)
|
204
|
+
end
|
205
|
+
|
206
|
+
# operate in own directory
|
207
|
+
chdir() do
|
208
|
+
TTM.indent('skip'=>opts.delete('first')) do
|
209
|
+
run_children xeme, opts
|
210
|
+
run_commands xeme, opts
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
# At this point, all tests in the have been run. Attempt to succeed.
|
215
|
+
xeme.try_succeed
|
216
|
+
|
217
|
+
# if set as not ready, fail anyway
|
218
|
+
if xeme.success?
|
219
|
+
if meta.has_key?('ready') and (not meta['ready'])
|
220
|
+
xeme['success-but-not-ready'] = true
|
221
|
+
xeme.fail
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
# return xeme
|
226
|
+
return xeme
|
227
|
+
end
|
228
|
+
#
|
229
|
+
# run
|
230
|
+
#---------------------------------------------------------------------------
|
231
|
+
|
232
|
+
|
233
|
+
#---------------------------------------------------------------------------
|
234
|
+
# run_children
|
235
|
+
#
|
236
|
+
def run_children(xeme, opts)
|
237
|
+
children.each do |child|
|
238
|
+
if child.executable? or child.dir? and child.settings['active']
|
239
|
+
send_opts = opts.clone
|
240
|
+
send_opts['nested'] += 1
|
241
|
+
|
242
|
+
# run child, add to nested if any results
|
243
|
+
if nest = child.run(send_opts)
|
244
|
+
xeme['nested'].push nest
|
245
|
+
|
246
|
+
if nest.failure? and @stop_on_fail
|
247
|
+
return
|
248
|
+
end
|
249
|
+
end
|
250
|
+
end
|
251
|
+
end
|
252
|
+
end
|
253
|
+
#
|
254
|
+
# run_children
|
255
|
+
#---------------------------------------------------------------------------
|
256
|
+
|
257
|
+
|
258
|
+
#---------------------------------------------------------------------------
|
259
|
+
# run_commands
|
260
|
+
#
|
261
|
+
def run_commands(xeme, opts)
|
262
|
+
commands = settings['commands'] || []
|
263
|
+
commands.empty? and return
|
264
|
+
|
265
|
+
# load EzCapture
|
266
|
+
require 'ezcapture'
|
267
|
+
|
268
|
+
# loop through commands
|
269
|
+
commands.each do |cmd|
|
270
|
+
nest = run_command(cmd)
|
271
|
+
xeme['nested'].push nest
|
272
|
+
|
273
|
+
# exit if error
|
274
|
+
if nest.failure? and @stop_on_fail
|
275
|
+
return
|
276
|
+
end
|
277
|
+
end
|
278
|
+
end
|
279
|
+
#
|
280
|
+
# run_commands
|
281
|
+
#---------------------------------------------------------------------------
|
282
|
+
|
283
|
+
|
284
|
+
#---------------------------------------------------------------------------
|
285
|
+
# run_command
|
286
|
+
#
|
287
|
+
def run_command(cmd)
|
288
|
+
capture = EzCapture.new(*cmd)
|
289
|
+
xeme = Xeme.last_line(capture.stdout)
|
290
|
+
|
291
|
+
# if no stdout, return failure xeme
|
292
|
+
if not xeme
|
293
|
+
xeme = Xeme.new()
|
294
|
+
xeme.error 'did-not-get-xeme-in-stdout'
|
295
|
+
return xeme
|
296
|
+
end
|
297
|
+
|
298
|
+
# return
|
299
|
+
return xeme
|
300
|
+
end
|
301
|
+
#
|
302
|
+
# run_command
|
303
|
+
#---------------------------------------------------------------------------
|
304
|
+
|
305
|
+
|
306
|
+
#---------------------------------------------------------------------------
|
307
|
+
# title
|
308
|
+
# Determines the string that should be displayed when this file is listed
|
309
|
+
# when verbose setting is true.
|
310
|
+
#
|
311
|
+
def title(opts)
|
312
|
+
# if defined name for this directory
|
313
|
+
if explicit = settings.digger('meta', 'title')
|
314
|
+
return explicit
|
315
|
+
|
316
|
+
# else return the name of the directory
|
317
|
+
else
|
318
|
+
return name
|
319
|
+
end
|
320
|
+
end
|
321
|
+
#
|
322
|
+
# title
|
323
|
+
#---------------------------------------------------------------------------
|
324
|
+
end
|
325
|
+
#
|
326
|
+
# Bryton::FSO::Dir
|
327
|
+
#===============================================================================
|
328
|
+
|
329
|
+
|
330
|
+
#===============================================================================
|
331
|
+
# Bryton::FSO::File
|
332
|
+
#
|
333
|
+
class Bryton::FSO::File < FSO::File
|
334
|
+
#---------------------------------------------------------------------------
|
335
|
+
# classes
|
336
|
+
#
|
337
|
+
def self.classes
|
338
|
+
return {
|
339
|
+
'file' => Bryton::FSO::File,
|
340
|
+
'dir' => Bryton::FSO::Dir
|
341
|
+
};
|
342
|
+
end
|
343
|
+
#
|
344
|
+
# classes
|
345
|
+
#---------------------------------------------------------------------------
|
346
|
+
|
347
|
+
|
348
|
+
#---------------------------------------------------------------------------
|
349
|
+
# initialize
|
350
|
+
#
|
351
|
+
def initialize(*opts)
|
352
|
+
super(*opts)
|
353
|
+
@children = nil
|
354
|
+
@settings = nil
|
355
|
+
end
|
356
|
+
#
|
357
|
+
# initialize
|
358
|
+
#---------------------------------------------------------------------------
|
359
|
+
|
360
|
+
|
361
|
+
#---------------------------------------------------------------------------
|
362
|
+
# settings
|
363
|
+
#
|
364
|
+
def settings()
|
365
|
+
# cache if necessary
|
366
|
+
if not @settings
|
367
|
+
default = {'active'=>true}
|
368
|
+
explicit = dir.settings.digger('files', name)
|
369
|
+
|
370
|
+
# If no explicit definition of the file, initialize to empty hash.
|
371
|
+
if explicit.nil?
|
372
|
+
explicit = {}
|
373
|
+
|
374
|
+
# If explicit is defined but is not a hash, the non-hash value is
|
375
|
+
# assumed to be the "active" value.
|
376
|
+
elsif not explicit.is_a?(Hash)
|
377
|
+
explicit = {'active'=>explicit}
|
378
|
+
end
|
379
|
+
|
380
|
+
# by this point explicit is a hash
|
381
|
+
|
382
|
+
# merge explicit and default
|
383
|
+
@settings = default.merge(explicit)
|
384
|
+
end
|
385
|
+
|
386
|
+
# return
|
387
|
+
return @settings
|
388
|
+
end
|
389
|
+
#
|
390
|
+
# settings
|
391
|
+
#---------------------------------------------------------------------------
|
392
|
+
|
393
|
+
|
394
|
+
#---------------------------------------------------------------------------
|
395
|
+
# run
|
396
|
+
#
|
397
|
+
def run(opts={})
|
398
|
+
# If the file is not active, do nothing - don't even print the name.
|
399
|
+
if not settings['active']
|
400
|
+
return nil
|
401
|
+
end
|
402
|
+
|
403
|
+
# verbosify
|
404
|
+
if opts['verbose']
|
405
|
+
TTM.puts title(opts)
|
406
|
+
|
407
|
+
# message before running
|
408
|
+
if before = @settings.digger('messages', 'before')
|
409
|
+
TTM.indent do
|
410
|
+
TTM.puts before
|
411
|
+
end
|
412
|
+
end
|
413
|
+
end
|
414
|
+
|
415
|
+
# run and return xeme if necessary
|
416
|
+
unless opts['list_only']
|
417
|
+
return run_test(opts)
|
418
|
+
end
|
419
|
+
end
|
420
|
+
#
|
421
|
+
# run
|
422
|
+
#---------------------------------------------------------------------------
|
423
|
+
|
424
|
+
|
425
|
+
#---------------------------------------------------------------------------
|
426
|
+
# run_test
|
427
|
+
#
|
428
|
+
def run_test(opts)
|
429
|
+
capture = execute()
|
430
|
+
xeme = Xeme.last_line(capture.stdout)
|
431
|
+
|
432
|
+
# if no stdout, return failure xeme
|
433
|
+
if not xeme
|
434
|
+
xeme = Xeme.new()
|
435
|
+
xeme.error 'did-not-get-xeme-in-stdout'
|
436
|
+
return xeme
|
437
|
+
end
|
438
|
+
|
439
|
+
# return
|
440
|
+
return xeme
|
441
|
+
end
|
442
|
+
#
|
443
|
+
# run_test
|
444
|
+
#---------------------------------------------------------------------------
|
445
|
+
|
446
|
+
|
447
|
+
#---------------------------------------------------------------------------
|
448
|
+
# title
|
449
|
+
#
|
450
|
+
def title(opts)
|
451
|
+
return name
|
452
|
+
end
|
453
|
+
#
|
454
|
+
# title
|
455
|
+
#---------------------------------------------------------------------------
|
456
|
+
end
|
457
|
+
#
|
458
|
+
# Bryton::FSO::File
|
459
|
+
#===============================================================================
|
data/lib/bryton/tools.rb
ADDED
@@ -0,0 +1,394 @@
|
|
1
|
+
require 'xeme'
|
2
|
+
require 'talk-to-me'
|
3
|
+
|
4
|
+
|
5
|
+
#===============================================================================
|
6
|
+
# Bryton
|
7
|
+
#
|
8
|
+
module Bryton
|
9
|
+
# instance properties
|
10
|
+
@exit_on_fail = false
|
11
|
+
@ready = true
|
12
|
+
@keep_count = true
|
13
|
+
@line_comments = false
|
14
|
+
|
15
|
+
|
16
|
+
#---------------------------------------------------------------------------
|
17
|
+
# accessors
|
18
|
+
#
|
19
|
+
class << self
|
20
|
+
attr_accessor :exit_on_fail
|
21
|
+
attr_accessor :ready
|
22
|
+
attr_accessor :keep_count
|
23
|
+
attr_accessor :xeme
|
24
|
+
attr_accessor :line_comments
|
25
|
+
end
|
26
|
+
#
|
27
|
+
# accessors
|
28
|
+
#---------------------------------------------------------------------------
|
29
|
+
|
30
|
+
|
31
|
+
#---------------------------------------------------------------------------
|
32
|
+
# accessor methods
|
33
|
+
#
|
34
|
+
def self.verbose
|
35
|
+
return TTM.io ? true : false
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.verbose=(bool)
|
39
|
+
if bool
|
40
|
+
TTM.io = STDERR
|
41
|
+
else
|
42
|
+
TTM.io = nil
|
43
|
+
end
|
44
|
+
end
|
45
|
+
#
|
46
|
+
# accessor methods
|
47
|
+
#---------------------------------------------------------------------------
|
48
|
+
|
49
|
+
|
50
|
+
#---------------------------------------------------------------------------
|
51
|
+
# reset
|
52
|
+
#
|
53
|
+
def self.reset()
|
54
|
+
self.verbose= true
|
55
|
+
@xeme = Xeme.new()
|
56
|
+
@xeme['count'] = 0
|
57
|
+
end
|
58
|
+
|
59
|
+
reset()
|
60
|
+
#
|
61
|
+
# reset
|
62
|
+
#---------------------------------------------------------------------------
|
63
|
+
|
64
|
+
|
65
|
+
#---------------------------------------------------------------------------
|
66
|
+
# pause_counting
|
67
|
+
#
|
68
|
+
def self.pause_counting
|
69
|
+
hold_keep_count = @keep_count
|
70
|
+
@keep_count = false
|
71
|
+
yield
|
72
|
+
ensure
|
73
|
+
@keep_count = hold_keep_count
|
74
|
+
end
|
75
|
+
#
|
76
|
+
# pause_counting
|
77
|
+
#---------------------------------------------------------------------------
|
78
|
+
|
79
|
+
|
80
|
+
#---------------------------------------------------------------------------
|
81
|
+
# increment_count
|
82
|
+
#
|
83
|
+
def self.increment_count
|
84
|
+
if @keep_count
|
85
|
+
@xeme['count'] += 1
|
86
|
+
end
|
87
|
+
end
|
88
|
+
#
|
89
|
+
# increment_count
|
90
|
+
#---------------------------------------------------------------------------
|
91
|
+
|
92
|
+
|
93
|
+
#---------------------------------------------------------------------------
|
94
|
+
# succeed
|
95
|
+
#
|
96
|
+
def self.succeed
|
97
|
+
if not @ready
|
98
|
+
@xeme.error 'not-ready'
|
99
|
+
end
|
100
|
+
|
101
|
+
# set success to true
|
102
|
+
@xeme.try_succeed()
|
103
|
+
|
104
|
+
# output
|
105
|
+
puts xeme.to_json()
|
106
|
+
end
|
107
|
+
#
|
108
|
+
# succeed
|
109
|
+
#---------------------------------------------------------------------------
|
110
|
+
|
111
|
+
|
112
|
+
#---------------------------------------------------------------------------
|
113
|
+
# line_error
|
114
|
+
#
|
115
|
+
def self.line_error(level=1)
|
116
|
+
loc = caller_locations[level]
|
117
|
+
error = @xeme.error('line-' + loc.lineno.to_s)
|
118
|
+
|
119
|
+
# get line comment if there is one
|
120
|
+
line_comment error, loc
|
121
|
+
|
122
|
+
# exit if exiting on first fail
|
123
|
+
maybe_exit_on_fail()
|
124
|
+
end
|
125
|
+
#
|
126
|
+
# line_error
|
127
|
+
#---------------------------------------------------------------------------
|
128
|
+
|
129
|
+
|
130
|
+
#---------------------------------------------------------------------------
|
131
|
+
# line_comment
|
132
|
+
#
|
133
|
+
def self.line_comment(error, loc)
|
134
|
+
@line_comments or return
|
135
|
+
|
136
|
+
# KLUDGE: I don't understand why loc.lineno and the line number are two
|
137
|
+
# apart.
|
138
|
+
idx = 2
|
139
|
+
|
140
|
+
# read file
|
141
|
+
File.foreach(loc.path) do |line|
|
142
|
+
if idx == loc.lineno
|
143
|
+
if line.sub!(/\A\s*\#\#\s*/mu, '')
|
144
|
+
if line.match(/\S/mu)
|
145
|
+
line = line.sub(/\s+\z/mu, '')
|
146
|
+
error['comment'] = line
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
# we're done
|
151
|
+
return
|
152
|
+
end
|
153
|
+
|
154
|
+
# increment current line number
|
155
|
+
idx += 1
|
156
|
+
end
|
157
|
+
end
|
158
|
+
#
|
159
|
+
# line_comment
|
160
|
+
#---------------------------------------------------------------------------
|
161
|
+
|
162
|
+
|
163
|
+
#---------------------------------------------------------------------------
|
164
|
+
# maybe_exit_on_fail
|
165
|
+
#
|
166
|
+
def self.maybe_exit_on_fail
|
167
|
+
if @exit_on_fail
|
168
|
+
puts xeme.to_json()
|
169
|
+
exit
|
170
|
+
end
|
171
|
+
end
|
172
|
+
#
|
173
|
+
# maybe_exit_on_fail
|
174
|
+
#---------------------------------------------------------------------------
|
175
|
+
|
176
|
+
|
177
|
+
### tests
|
178
|
+
|
179
|
+
|
180
|
+
#---------------------------------------------------------------------------
|
181
|
+
# pass, fail
|
182
|
+
#
|
183
|
+
def self.pass
|
184
|
+
Bryton.increment_count()
|
185
|
+
end
|
186
|
+
|
187
|
+
def self.fail
|
188
|
+
increment_count()
|
189
|
+
line_error()
|
190
|
+
end
|
191
|
+
#
|
192
|
+
# pass, fail
|
193
|
+
#---------------------------------------------------------------------------
|
194
|
+
|
195
|
+
|
196
|
+
#---------------------------------------------------------------------------
|
197
|
+
# structure comparisons
|
198
|
+
#
|
199
|
+
def self.compare(should, is)
|
200
|
+
TTM.hrm
|
201
|
+
return Bryton::StructureComp.compare(should, is)
|
202
|
+
end
|
203
|
+
#
|
204
|
+
# structure comparisons
|
205
|
+
#---------------------------------------------------------------------------
|
206
|
+
|
207
|
+
|
208
|
+
#-------------------------------------------------------------------------------
|
209
|
+
# isa
|
210
|
+
#
|
211
|
+
def self.isa(obj, clss)
|
212
|
+
Bryton.increment_count()
|
213
|
+
|
214
|
+
# success
|
215
|
+
if obj.is_a?(clss)
|
216
|
+
return true
|
217
|
+
|
218
|
+
# failure
|
219
|
+
else
|
220
|
+
Bryton.line_error(2)
|
221
|
+
return false
|
222
|
+
end
|
223
|
+
end
|
224
|
+
#
|
225
|
+
# isa
|
226
|
+
#-------------------------------------------------------------------------------
|
227
|
+
end
|
228
|
+
#
|
229
|
+
# Bryton
|
230
|
+
#===============================================================================
|
231
|
+
|
232
|
+
|
233
|
+
#===============================================================================
|
234
|
+
# Bryton::ExceptionTest
|
235
|
+
#
|
236
|
+
class Bryton::ExceptionTest
|
237
|
+
attr_accessor :err_class
|
238
|
+
|
239
|
+
|
240
|
+
#---------------------------------------------------------------------------
|
241
|
+
# initialize
|
242
|
+
#
|
243
|
+
def initialize
|
244
|
+
@err_class = nil
|
245
|
+
end
|
246
|
+
#
|
247
|
+
# initialize
|
248
|
+
#---------------------------------------------------------------------------
|
249
|
+
|
250
|
+
|
251
|
+
#---------------------------------------------------------------------------
|
252
|
+
# exec
|
253
|
+
#
|
254
|
+
def exec
|
255
|
+
Bryton.increment()
|
256
|
+
success = false
|
257
|
+
e = nil
|
258
|
+
|
259
|
+
# Run the block. If it runs successfully then it fails the test.
|
260
|
+
begin
|
261
|
+
yield
|
262
|
+
success = true
|
263
|
+
|
264
|
+
# verbosify
|
265
|
+
TTM.puts 'block-did-not-fail'
|
266
|
+
|
267
|
+
# We want to get to this rescue block because that means the block
|
268
|
+
# failed, which is what it's supposed to do.
|
269
|
+
rescue => e
|
270
|
+
# verbosify if necessary
|
271
|
+
|
272
|
+
TTM.puts "error class: #{e.class.to_s}"
|
273
|
+
TTM.puts "error: #{e}"
|
274
|
+
|
275
|
+
# if error id, add that
|
276
|
+
if e.respond_to?('id')
|
277
|
+
TTM.puts "error id: #{e}"
|
278
|
+
end
|
279
|
+
|
280
|
+
|
281
|
+
# check error class
|
282
|
+
if @err_class
|
283
|
+
if not e.class == @err_class
|
284
|
+
if @verbose
|
285
|
+
puts "error class was #{e.class.to_s} but should have been #{@err_class.to_s}"
|
286
|
+
end
|
287
|
+
|
288
|
+
Bryton.line_error(2)
|
289
|
+
end
|
290
|
+
end
|
291
|
+
end
|
292
|
+
|
293
|
+
# if yield succeeded, then an exception did not occur
|
294
|
+
if success
|
295
|
+
Bryton.line_error()
|
296
|
+
end
|
297
|
+
|
298
|
+
# return error
|
299
|
+
return e
|
300
|
+
end
|
301
|
+
#
|
302
|
+
# exec
|
303
|
+
#---------------------------------------------------------------------------
|
304
|
+
end
|
305
|
+
#
|
306
|
+
# Bryton::ExceptionTest
|
307
|
+
#===============================================================================
|
308
|
+
|
309
|
+
|
310
|
+
#===============================================================================
|
311
|
+
# Bryton::StructureComp
|
312
|
+
#
|
313
|
+
module Bryton::StructureComp
|
314
|
+
#-------------------------------------------------------------------------------
|
315
|
+
# array_comp
|
316
|
+
#
|
317
|
+
def self.array_comp(should, is, opts={'recurse'=>true})
|
318
|
+
should.each_with_index do |should_el, idx|
|
319
|
+
element_comp should_el, is[idx], opts
|
320
|
+
end
|
321
|
+
end
|
322
|
+
#
|
323
|
+
# array_comp
|
324
|
+
#-------------------------------------------------------------------------------
|
325
|
+
|
326
|
+
|
327
|
+
#-------------------------------------------------------------------------------
|
328
|
+
# hash_comp
|
329
|
+
#
|
330
|
+
def self.hash_comp(should, is, opts={})
|
331
|
+
Bryton.increment()
|
332
|
+
opts = {'recurse'=>true}.merge(opts)
|
333
|
+
|
334
|
+
|
335
|
+
# early exit: is is null
|
336
|
+
defined is
|
337
|
+
is or return
|
338
|
+
|
339
|
+
# is a hash
|
340
|
+
isa is, Hash
|
341
|
+
is.is_a?(Hash) or return
|
342
|
+
|
343
|
+
# if not a hash, return
|
344
|
+
if not is.is_a?(Hash)
|
345
|
+
return false
|
346
|
+
end
|
347
|
+
|
348
|
+
# should be of same length
|
349
|
+
eq should.length, is.length
|
350
|
+
|
351
|
+
# loop through keys
|
352
|
+
should.keys.each do |should_k|
|
353
|
+
element_comp should[should_k], is[should_k], opts
|
354
|
+
end
|
355
|
+
end
|
356
|
+
#
|
357
|
+
# hash_comp
|
358
|
+
#-------------------------------------------------------------------------------
|
359
|
+
|
360
|
+
|
361
|
+
#-------------------------------------------------------------------------------
|
362
|
+
# compare
|
363
|
+
#
|
364
|
+
def self.compare(should, is, opts)
|
365
|
+
Bryton.increment_count()
|
366
|
+
|
367
|
+
# should be same classes
|
368
|
+
if not Bryton.isa(is, should.class)
|
369
|
+
return
|
370
|
+
end
|
371
|
+
|
372
|
+
# pause counting and recurse
|
373
|
+
Bryton.pause_counting do
|
374
|
+
# if should element is a hash
|
375
|
+
if should.is_a?(Hash)
|
376
|
+
return hash_comp(should, is, opts)
|
377
|
+
|
378
|
+
# if should is an array
|
379
|
+
elsif should.is_a?(Array)
|
380
|
+
return array_comp(should, is, opts)
|
381
|
+
|
382
|
+
# if should is a string
|
383
|
+
elsif should.is_a?(String)
|
384
|
+
return Bryon.eq(should, is)
|
385
|
+
end
|
386
|
+
end
|
387
|
+
end
|
388
|
+
#
|
389
|
+
# compare
|
390
|
+
#-------------------------------------------------------------------------------
|
391
|
+
end
|
392
|
+
#
|
393
|
+
# Bryton::StructureComp
|
394
|
+
#===============================================================================
|
metadata
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: Bryton
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: '0.1'
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Mike O'Sullivan
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2023-05-16 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: File based testing protocol.
|
14
|
+
email: mike@idocs.com
|
15
|
+
executables: []
|
16
|
+
extensions: []
|
17
|
+
extra_rdoc_files: []
|
18
|
+
files:
|
19
|
+
- README.md
|
20
|
+
- lib/bryton/runner.rb
|
21
|
+
- lib/bryton/tools.rb
|
22
|
+
homepage: https://github.com/mikosullivan/bryton
|
23
|
+
licenses:
|
24
|
+
- MIT
|
25
|
+
metadata: {}
|
26
|
+
post_install_message:
|
27
|
+
rdoc_options: []
|
28
|
+
require_paths:
|
29
|
+
- lib
|
30
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - ">="
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: '0'
|
35
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - ">="
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '0'
|
40
|
+
requirements: []
|
41
|
+
rubygems_version: 3.1.2
|
42
|
+
signing_key:
|
43
|
+
specification_version: 4
|
44
|
+
summary: Bryton
|
45
|
+
test_files: []
|