sus 0.17.1 → 0.18.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 +4 -4
- checksums.yaml.gz.sig +0 -0
- data/bin/sus-host +93 -0
- data/bin/sus-tree +12 -0
- data/lib/sus/assertions.rb +16 -4
- data/lib/sus/base.rb +2 -1
- data/lib/sus/clock.rb +8 -0
- data/lib/sus/config.rb +20 -21
- data/lib/sus/expect.rb +2 -1
- data/lib/sus/file.rb +9 -1
- data/lib/sus/output/buffered.rb +1 -3
- data/lib/sus/registry.rb +9 -4
- data/lib/sus/tree.rb +27 -0
- data/lib/sus/version.rb +1 -1
- data/lib/sus.rb +1 -0
- data.tar.gz.sig +0 -0
- metadata +7 -2
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 77921dd1b6bbde6e2a47db7f4a2f0c421c3f517eb04b7d4273538a5891f51ad2
|
4
|
+
data.tar.gz: 204c68cd216e6ddb74e469bbdc01ce042f4d4d0d9fab9b3b897d2ebbcce7fec6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a9e50aa174880249cd96f519242d59396315475972432b60dd41e6b2c35d5025a7dfb7824fc538a1bee5199c2d93686c0673e4d72de7126f512a1c237041c8ad
|
7
|
+
data.tar.gz: 8580ec8e113b18c6e61f14c3f31804d76663cfa6288e965fb44d4a06238283461b856d593abb83bee4d270d32da865c609fc253a840d6f58d3ac49a8a7d9cc66
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
data/bin/sus-host
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
require_relative '../lib/sus/config'
|
6
|
+
config = Sus::Config.load
|
7
|
+
|
8
|
+
require_relative '../lib/sus'
|
9
|
+
|
10
|
+
verbose = false
|
11
|
+
guard = Thread::Mutex.new
|
12
|
+
|
13
|
+
require 'etc'
|
14
|
+
count = Etc.nprocessors
|
15
|
+
|
16
|
+
$stdout.sync = true
|
17
|
+
|
18
|
+
input = $stdin.dup
|
19
|
+
$stdin.reopen(File::NULL)
|
20
|
+
output = $stdout.dup
|
21
|
+
$stdout.reopen($stderr)
|
22
|
+
|
23
|
+
while line = input.gets
|
24
|
+
message = JSON.parse(line)
|
25
|
+
|
26
|
+
if tests = message['run']
|
27
|
+
jobs = Thread::Queue.new
|
28
|
+
results = Thread::Queue.new
|
29
|
+
|
30
|
+
top = Sus::Assertions.new(measure: true)
|
31
|
+
config.before_tests(top)
|
32
|
+
|
33
|
+
aggregate = Thread.new do
|
34
|
+
while result = results.pop
|
35
|
+
top.add(result)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
loader = Thread.new do
|
40
|
+
registry = config.load_registry(tests)
|
41
|
+
|
42
|
+
registry.each do |child|
|
43
|
+
jobs << child
|
44
|
+
end
|
45
|
+
|
46
|
+
jobs.close
|
47
|
+
end
|
48
|
+
|
49
|
+
workers = count.times.map do |index|
|
50
|
+
Thread.new do
|
51
|
+
while job = jobs.pop
|
52
|
+
guard.synchronize do
|
53
|
+
output.puts JSON.generate({started: job.identity})
|
54
|
+
end
|
55
|
+
|
56
|
+
assertions = Sus::Assertions.new(measure: true)
|
57
|
+
job.call(assertions)
|
58
|
+
|
59
|
+
results.push(assertions)
|
60
|
+
|
61
|
+
guard.synchronize do
|
62
|
+
if assertions.passed?
|
63
|
+
output.puts JSON.generate({passed: job.identity, message: assertions.output.string, duration: assertions.clock.ms})
|
64
|
+
else
|
65
|
+
output.puts JSON.generate({failed: job.identity, message: assertions.output.string, duration: assertions.clock.ms})
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
loader.join
|
73
|
+
workers.each(&:join)
|
74
|
+
results.close
|
75
|
+
|
76
|
+
aggregate.join
|
77
|
+
config.after_tests(top)
|
78
|
+
|
79
|
+
workers.each(&:join)
|
80
|
+
|
81
|
+
if config.respond_to?(:covered)
|
82
|
+
if covered = config.covered and covered.record?
|
83
|
+
covered.policy.each do |coverage|
|
84
|
+
output.puts JSON.generate({coverage: coverage.path, counts: coverage.counts})
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
output.puts JSON.generate({finished: true, message: top.output.string, duration: top.clock.ms})
|
90
|
+
else
|
91
|
+
$stderr.puts "Unknown message: #{message}"
|
92
|
+
end
|
93
|
+
end
|
data/bin/sus-tree
ADDED
data/lib/sus/assertions.rb
CHANGED
@@ -138,20 +138,32 @@ module Sus
|
|
138
138
|
@errored.any?
|
139
139
|
end
|
140
140
|
|
141
|
+
class Assert
|
142
|
+
def initialize(location, message)
|
143
|
+
@location = location
|
144
|
+
@message = message
|
145
|
+
end
|
146
|
+
|
147
|
+
attr :location
|
148
|
+
attr :message
|
149
|
+
end
|
150
|
+
|
141
151
|
def assert(condition, message = nil)
|
142
152
|
@count += 1
|
153
|
+
backtrace = Output::Backtrace.first(@identity)
|
143
154
|
|
144
155
|
if condition
|
145
|
-
@passed <<
|
156
|
+
@passed << Assert.new(message, backtrace)
|
146
157
|
|
147
158
|
if !@orientation || @verbose
|
148
|
-
@output.puts(:indent, *pass_prefix, message || "assertion",
|
159
|
+
@output.puts(:indent, *pass_prefix, message || "assertion", backtrace)
|
149
160
|
end
|
150
161
|
else
|
151
|
-
|
162
|
+
|
163
|
+
@failed << Assert.new(message, backtrace)
|
152
164
|
|
153
165
|
if @orientation || @verbose
|
154
|
-
@output.puts(:indent, *fail_prefix, message || "assertion",
|
166
|
+
@output.puts(:indent, *fail_prefix, message || "assertion", backtrace)
|
155
167
|
end
|
156
168
|
end
|
157
169
|
end
|
data/lib/sus/base.rb
CHANGED
@@ -39,10 +39,11 @@ module Sus
|
|
39
39
|
end
|
40
40
|
end
|
41
41
|
|
42
|
-
def self.base(description = nil)
|
42
|
+
def self.base(description = nil, root: nil)
|
43
43
|
base = Class.new(Base)
|
44
44
|
|
45
45
|
base.extend(Context)
|
46
|
+
base.identity = Identity.new(root) if root
|
46
47
|
base.description = description
|
47
48
|
|
48
49
|
return base
|
data/lib/sus/clock.rb
CHANGED
@@ -33,6 +33,10 @@ module Sus
|
|
33
33
|
duration
|
34
34
|
end
|
35
35
|
|
36
|
+
def ms
|
37
|
+
duration * 1000.0
|
38
|
+
end
|
39
|
+
|
36
40
|
def to_s
|
37
41
|
duration = self.duration
|
38
42
|
|
@@ -45,6 +49,10 @@ module Sus
|
|
45
49
|
end
|
46
50
|
end
|
47
51
|
|
52
|
+
def reset!(duration = 0.0)
|
53
|
+
@duration = duration
|
54
|
+
end
|
55
|
+
|
48
56
|
def start!
|
49
57
|
@start_time = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
50
58
|
end
|
data/lib/sus/config.rb
CHANGED
@@ -82,12 +82,12 @@ module Sus
|
|
82
82
|
@registry ||= self.load_registry
|
83
83
|
end
|
84
84
|
|
85
|
-
def load_registry
|
86
|
-
registry = Sus::Registry.new
|
85
|
+
def load_registry(paths = @paths)
|
86
|
+
registry = Sus::Registry.new(root: @root)
|
87
87
|
|
88
|
-
if
|
88
|
+
if paths&.any?
|
89
89
|
registry = Sus::Filter.new(registry)
|
90
|
-
|
90
|
+
paths.each do |path|
|
91
91
|
registry.load(path)
|
92
92
|
end
|
93
93
|
else
|
@@ -99,42 +99,41 @@ module Sus
|
|
99
99
|
return registry
|
100
100
|
end
|
101
101
|
|
102
|
-
def before_tests(assertions)
|
102
|
+
def before_tests(assertions, output: self.output)
|
103
|
+
@clock.reset!
|
103
104
|
@clock.start!
|
104
105
|
end
|
105
106
|
|
106
|
-
def after_tests(assertions)
|
107
|
+
def after_tests(assertions, output: self.output)
|
107
108
|
@clock.stop!
|
108
109
|
|
109
|
-
self.print_summary(assertions)
|
110
|
+
self.print_summary(output, assertions)
|
110
111
|
end
|
111
112
|
|
112
113
|
protected
|
113
114
|
|
114
|
-
def print_summary(assertions)
|
115
|
-
output = self.output
|
116
|
-
|
115
|
+
def print_summary(output, assertions)
|
117
116
|
assertions.print(output)
|
118
117
|
output.puts
|
119
118
|
|
120
|
-
print_finished_statistics(assertions)
|
119
|
+
print_finished_statistics(output, assertions)
|
121
120
|
|
122
121
|
if !partial? and assertions.passed?
|
123
|
-
print_test_feedback(assertions)
|
122
|
+
print_test_feedback(output, assertions)
|
124
123
|
end
|
125
124
|
|
126
|
-
print_slow_tests(assertions)
|
127
|
-
print_failed_assertions(assertions)
|
125
|
+
print_slow_tests(output, assertions)
|
126
|
+
print_failed_assertions(output, assertions)
|
128
127
|
end
|
129
128
|
|
130
|
-
def print_finished_statistics(assertions)
|
129
|
+
def print_finished_statistics(output, assertions)
|
131
130
|
duration = @clock.duration
|
132
131
|
rate = assertions.count / duration
|
133
132
|
|
134
133
|
output.puts "🏁 Finished in ", @clock, "; #{rate.round(3)} assertions per second."
|
135
134
|
end
|
136
135
|
|
137
|
-
def print_test_feedback(assertions)
|
136
|
+
def print_test_feedback(output, assertions)
|
138
137
|
duration = @clock.duration
|
139
138
|
rate = assertions.count / duration
|
140
139
|
|
@@ -179,7 +178,7 @@ module Sus
|
|
179
178
|
end
|
180
179
|
end
|
181
180
|
|
182
|
-
def print_slow_tests(assertions, threshold = 0.1)
|
181
|
+
def print_slow_tests(output, assertions, threshold = 0.1)
|
183
182
|
slowest_tests = assertions.passed.select{|test| test.clock > threshold}.sort_by(&:clock).reverse!
|
184
183
|
|
185
184
|
if slowest_tests.empty?
|
@@ -193,7 +192,7 @@ module Sus
|
|
193
192
|
end
|
194
193
|
end
|
195
194
|
|
196
|
-
def print_assertions(title, assertions)
|
195
|
+
def print_assertions(output, title, assertions)
|
197
196
|
if assertions.any?
|
198
197
|
output.puts
|
199
198
|
output.puts title
|
@@ -206,9 +205,9 @@ module Sus
|
|
206
205
|
end
|
207
206
|
end
|
208
207
|
|
209
|
-
def print_failed_assertions(assertions)
|
210
|
-
print_assertions("🤔 Failed assertions:", assertions.failed)
|
211
|
-
print_assertions("🔥 Errored assertions:", assertions.errored)
|
208
|
+
def print_failed_assertions(output, assertions)
|
209
|
+
print_assertions(output, "🤔 Failed assertions:", assertions.failed)
|
210
|
+
print_assertions(output, "🔥 Errored assertions:", assertions.errored)
|
212
211
|
end
|
213
212
|
end
|
214
213
|
end
|
data/lib/sus/expect.rb
CHANGED
data/lib/sus/file.rb
CHANGED
@@ -44,10 +44,18 @@ module Sus
|
|
44
44
|
@error = error
|
45
45
|
end
|
46
46
|
|
47
|
+
attr :identity
|
48
|
+
|
47
49
|
def leaf?
|
48
50
|
true
|
49
51
|
end
|
50
52
|
|
53
|
+
EMPTY = Array.new.freeze
|
54
|
+
|
55
|
+
def children
|
56
|
+
EMPTY
|
57
|
+
end
|
58
|
+
|
51
59
|
def print(output)
|
52
60
|
output.write("file ", :path, @identity)
|
53
61
|
end
|
@@ -64,7 +72,7 @@ module Sus
|
|
64
72
|
module Context
|
65
73
|
def file(path)
|
66
74
|
add File.build(self, path)
|
67
|
-
rescue StandardError, SyntaxError => error
|
75
|
+
rescue StandardError, LoadError, SyntaxError => error
|
68
76
|
add FileLoadError.build(self, path, error)
|
69
77
|
end
|
70
78
|
end
|
data/lib/sus/output/buffered.rb
CHANGED
@@ -30,14 +30,12 @@ module Sus
|
|
30
30
|
self.class.new(self)
|
31
31
|
end
|
32
32
|
|
33
|
-
attr :output
|
34
|
-
|
35
33
|
def each(&block)
|
36
34
|
@chunks.each(&block)
|
37
35
|
end
|
38
36
|
|
39
37
|
def append(buffer)
|
40
|
-
@chunks.concat(buffer.
|
38
|
+
@chunks.concat(buffer.chunks)
|
41
39
|
@tee&.append(buffer)
|
42
40
|
end
|
43
41
|
|
data/lib/sus/registry.rb
CHANGED
@@ -23,16 +23,21 @@ module Sus
|
|
23
23
|
DIRECTORY_GLOB = "**/*.rb"
|
24
24
|
|
25
25
|
# Create a top level scope with self as the instance:
|
26
|
-
def initialize(
|
27
|
-
@base = base
|
26
|
+
def initialize(**options)
|
27
|
+
@base = Sus.base(self, **options)
|
28
|
+
@loaded = {}
|
28
29
|
end
|
29
|
-
|
30
|
+
|
30
31
|
attr :base
|
31
32
|
|
32
33
|
def print(output)
|
33
34
|
output.write("Test Registry")
|
34
35
|
end
|
35
36
|
|
37
|
+
def to_s
|
38
|
+
@base.identity.to_s
|
39
|
+
end
|
40
|
+
|
36
41
|
def load(path)
|
37
42
|
if ::File.directory?(path)
|
38
43
|
load_directory(path)
|
@@ -42,7 +47,7 @@ module Sus
|
|
42
47
|
end
|
43
48
|
|
44
49
|
private def load_file(path)
|
45
|
-
@base.file(path)
|
50
|
+
@loaded[path] ||= @base.file(path)
|
46
51
|
end
|
47
52
|
|
48
53
|
private def load_directory(path)
|
data/lib/sus/tree.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
module Sus
|
2
|
+
class Tree
|
3
|
+
def initialize(context)
|
4
|
+
@context = context
|
5
|
+
end
|
6
|
+
|
7
|
+
def traverse(current = @context, &block)
|
8
|
+
node = {}
|
9
|
+
|
10
|
+
node[:self] = yield(current)
|
11
|
+
|
12
|
+
if children = current.children # and children.any?
|
13
|
+
node[:children] = children.values.map do |context|
|
14
|
+
self.traverse(context, &block)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
return node
|
19
|
+
end
|
20
|
+
|
21
|
+
def to_json(options = nil)
|
22
|
+
traverse do |context|
|
23
|
+
[context.identity, context.description, context.leaf?]
|
24
|
+
end.to_json(options)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
data/lib/sus/version.rb
CHANGED
data/lib/sus.rb
CHANGED
data.tar.gz.sig
CHANGED
Binary file
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sus
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.18.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Samuel Williams
|
@@ -38,7 +38,7 @@ cert_chain:
|
|
38
38
|
Q2K9NVun/S785AP05vKkXZEFYxqG6EW012U4oLcFl5MySFajYXRYbuUpH6AY+HP8
|
39
39
|
voD0MPg1DssDLKwXyt1eKD/+Fq0bFWhwVM/1XiAXL7lyYUyOq24KHgQ2Csg=
|
40
40
|
-----END CERTIFICATE-----
|
41
|
-
date: 2023-02-
|
41
|
+
date: 2023-02-19 00:00:00.000000000 Z
|
42
42
|
dependencies:
|
43
43
|
- !ruby/object:Gem::Dependency
|
44
44
|
name: bake-test
|
@@ -87,11 +87,15 @@ email:
|
|
87
87
|
executables:
|
88
88
|
- sus
|
89
89
|
- sus-parallel
|
90
|
+
- sus-tree
|
91
|
+
- sus-host
|
90
92
|
extensions: []
|
91
93
|
extra_rdoc_files: []
|
92
94
|
files:
|
93
95
|
- bin/sus
|
96
|
+
- bin/sus-host
|
94
97
|
- bin/sus-parallel
|
98
|
+
- bin/sus-tree
|
95
99
|
- lib/sus.rb
|
96
100
|
- lib/sus/assertions.rb
|
97
101
|
- lib/sus/base.rb
|
@@ -131,6 +135,7 @@ files:
|
|
131
135
|
- lib/sus/registry.rb
|
132
136
|
- lib/sus/respond_to.rb
|
133
137
|
- lib/sus/shared.rb
|
138
|
+
- lib/sus/tree.rb
|
134
139
|
- lib/sus/version.rb
|
135
140
|
- lib/sus/with.rb
|
136
141
|
- license.md
|
metadata.gz.sig
CHANGED
Binary file
|