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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 102f27942c58c7a3da4728700344ade9803cb4efb4e9d3b2860c7b442ea73d62
4
- data.tar.gz: bbda385d1fbbe48ff8f2f38b990659f8577e5a28726ca0296c976f4ec60289dc
3
+ metadata.gz: 77921dd1b6bbde6e2a47db7f4a2f0c421c3f517eb04b7d4273538a5891f51ad2
4
+ data.tar.gz: 204c68cd216e6ddb74e469bbdc01ce042f4d4d0d9fab9b3b897d2ebbcce7fec6
5
5
  SHA512:
6
- metadata.gz: f67674f93488d7d0f1eb2cfa98d098ac78047b4fc0d1a216c7781b65757a4a0b48c74fa5c7f2e5a18f6f58e07a0564bdeb7ba9b5ef1f4412bd3d51ed7196657e
7
- data.tar.gz: bd31d9984aed574ddb68c9a4b3e7527fc6e9c05d26a0ea8dcea892ab25313d431da0b7f3e2e281c63998ed2a170e8de852143d5dd361ac9d1be61e0e0139e911
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
@@ -0,0 +1,12 @@
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
+ registry = config.registry
12
+ puts Sus::Tree.new(registry.base).to_json
@@ -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 << self
156
+ @passed << Assert.new(message, backtrace)
146
157
 
147
158
  if !@orientation || @verbose
148
- @output.puts(:indent, *pass_prefix, message || "assertion", Output::Backtrace.first(@identity))
159
+ @output.puts(:indent, *pass_prefix, message || "assertion", backtrace)
149
160
  end
150
161
  else
151
- @failed << self
162
+
163
+ @failed << Assert.new(message, backtrace)
152
164
 
153
165
  if @orientation || @verbose
154
- @output.puts(:indent, *fail_prefix, message || "assertion", Output::Backtrace.first(@identity))
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 @paths&.any?
88
+ if paths&.any?
89
89
  registry = Sus::Filter.new(registry)
90
- @paths.each do |path|
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
@@ -10,9 +10,10 @@ module Sus
10
10
  @subject = subject
11
11
  @inverted = inverted
12
12
  end
13
-
13
+
14
14
  attr :subject
15
15
  attr :inverted
16
+ attr :assertions
16
17
 
17
18
  def not
18
19
  self.dup.tap do |expect|
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
@@ -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.output)
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(base = Sus.base(self))
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
@@ -4,5 +4,5 @@
4
4
  # Copyright, 2021-2022, by Samuel Williams.
5
5
 
6
6
  module Sus
7
- VERSION = "0.17.1"
7
+ VERSION = "0.18.0"
8
8
  end
data/lib/sus.rb CHANGED
@@ -7,6 +7,7 @@ require_relative 'sus/version'
7
7
  require_relative 'sus/config'
8
8
  require_relative 'sus/registry'
9
9
  require_relative 'sus/assertions'
10
+ require_relative 'sus/tree'
10
11
 
11
12
  require_relative 'sus/expect'
12
13
  require_relative 'sus/be'
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.17.1
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-18 00:00:00.000000000 Z
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