tet 1.5.0 → 1.5.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.
Files changed (4) hide show
  1. checksums.yaml +4 -4
  2. data/lib/tests.rb +1 -1
  3. data/lib/tet.rb +151 -133
  4. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 97ce2949a018ea80d5012fc9dd00268098dd0ece
4
- data.tar.gz: fefa2a09bfc0adf45730b15be19785812e75d535
3
+ metadata.gz: 71c11439cad3f5c481d5242bc65ade2c8780804f
4
+ data.tar.gz: 6a410a5f775aa07096ed3b56e06cf85baddbdb33
5
5
  SHA512:
6
- metadata.gz: c60b11a370e690471156621bce8884a3daaaa13bab34e0bb80cb0a9c8e52fb11b24d9f2231f42ff80d0aa65804e25000069095324bbfb3f0f2d125d5dfc0dc6c
7
- data.tar.gz: '0719db9dedda2b62d2a413dd3b3342a28c87cff1855fb41b300e165aef30d2998156e67c3b153f1b7ef765f1cf1831e920b570efa613fb056e41d323aba95ab5'
6
+ metadata.gz: 4bcdfe86d7625c0a0a259a75f61b76165f0bb5dcb20400edaa950207553eaa451af2a219f5b7075c56caabdd46abf0fc573d006e2a3682b70fad43d41027bc2f
7
+ data.tar.gz: b24180e3e816c9e165d857547072f73e5f4d2a0cbe6d9f5a010e4017a9bf1a95392374228110d45b05241442e3793ebe12bbb9a7a3e8625dd9020c076f17e624
data/lib/tests.rb CHANGED
@@ -37,7 +37,7 @@ group '#err' do
37
37
  err('errors pass') { raise IntendedError }
38
38
  err('non-errors fail') { true }
39
39
 
40
- err('correct errors pass', expect: IntendedError) { raise IntendedError }
40
+ err('correct errors pass', expect: IntendedError) { raise IntendedError }
41
41
  err('incorrect errors err', expect: IntendedErrorChild) { raise IntendedError }
42
42
  end
43
43
 
data/lib/tet.rb CHANGED
@@ -5,7 +5,7 @@
5
5
  # terms of the three-clause BSD license. See LICENSE.txt
6
6
  # (located in root directory of this project) for details.
7
7
 
8
- # Label a block of tests
8
+ # Label a block of tests.
9
9
  def group label, &block
10
10
  Tet.run(
11
11
  label: label,
@@ -13,7 +13,7 @@ def group label, &block
13
13
  )
14
14
  end
15
15
 
16
- # Assert that a block will return a truthy value
16
+ # Assert that a block will return a truthy value.
17
17
  def assert label = '', &block
18
18
  Tet.run(
19
19
  label: label,
@@ -24,7 +24,7 @@ def assert label = '', &block
24
24
  )
25
25
  end
26
26
 
27
- # Assert that a block will err
27
+ # Assert that a block will err.
28
28
  def err label = '', expect: StandardError, &block
29
29
  Tet.run(
30
30
  label: label,
@@ -32,9 +32,9 @@ def err label = '', expect: StandardError, &block
32
32
  no_nest: true,
33
33
  truthy: -> { Tet.failed },
34
34
  falsy: -> { Tet.failed },
35
- error: ->(caught) {
35
+ error: ->(caught) do
36
36
  (expect >= caught.class) ? Tet.passed : Tet.erred(caught, expect)
37
- }
37
+ end
38
38
  )
39
39
  end
40
40
 
@@ -42,41 +42,41 @@ end
42
42
 
43
43
  # A namespace for all of the helper methods and classes.
44
44
  module Tet
45
- # Print all the reports after all the tests have run
45
+ # Print all the reports after all the tests have run.
46
46
  at_exit do
47
- unless Stats.empty?
48
- puts
49
- puts_report 'Failures', Messages.failure_report
50
- puts_report 'Exceptions', Messages.error_report
51
- puts_report 'Statistics', Stats.report
52
- end
47
+ puts
48
+ puts_report 'Failures', failure_report
49
+ puts_report 'Exceptions', error_report
50
+ puts_report 'Statistics', statistics_report
53
51
  end
54
52
 
55
53
 
56
54
 
57
- # An exception class to distinguish errors from incorrectly written tests
55
+ # An exception class to distinguish errors from incorrectly written tests.
58
56
  class TestError < StandardError; end
59
57
 
60
- # Object oriented way to do string formatting
58
+
59
+
60
+ # Object oriented ways to do string formatting.
61
61
  module StringFormatting
62
62
  refine String do
63
63
  def indent
64
64
  gsub(/^/, ' ')
65
65
  end
66
66
 
67
- def to_label
67
+ def to_label_string
68
68
  self
69
69
  end
70
70
  end
71
71
 
72
72
  refine Module do
73
- def to_label
73
+ def to_label_string
74
74
  name
75
75
  end
76
76
  end
77
77
 
78
78
  refine Object do
79
- def to_label
79
+ def to_label_string
80
80
  inspect
81
81
  end
82
82
  end
@@ -86,26 +86,27 @@ module Tet
86
86
 
87
87
 
88
88
 
89
- # Helpers for building test methods
89
+ # Helpers for building test methods.
90
90
  class << self
91
- # Call when an assertion has passed
91
+ # Call when an assertion has passed.
92
92
  def passed
93
- Stats.passed
93
+ print_now ?.
94
+ Data.add_note(:pass)
94
95
  end
95
96
 
96
- # Call when an assertion has failed
97
+ # Call when an assertion has failed.
97
98
  def failed
98
- Stats.failed
99
- Messages.failed
99
+ print_now ?!
100
+ Data.add_note(:fail)
100
101
  end
101
102
 
102
- # Call when an assertion has erred
103
+ # Call when an assertion has erred.
103
104
  def erred caught, expected = nil
104
- Stats.erred
105
- Messages.erred(caught, expected)
105
+ print_now ??
106
+ Data.add_note(:error, caught: caught, expected: expected)
106
107
  end
107
108
 
108
- # Run a block as a test
109
+ # Run a block as a test.
109
110
  def run label:,
110
111
  truthy: -> { },
111
112
  falsy: -> { },
@@ -113,7 +114,7 @@ module Tet
113
114
  no_nest: false,
114
115
  test:
115
116
 
116
- Messages.with_label(label) do
117
+ Data.with_label(label) do
117
118
  nesting_guard(no_nest) do
118
119
  begin
119
120
  test.call ? truthy.call : falsy.call
@@ -128,9 +129,15 @@ module Tet
128
129
  nil
129
130
  end
130
131
 
131
- private
132
+ private
132
133
 
133
- # Print out a report to stdout
134
+ # Print out a string immediately. Calling #print alone may have a delay.
135
+ def print_now string
136
+ print string
137
+ $stdout.flush
138
+ end
139
+
140
+ # Print out a report to stdout.
134
141
  def puts_report header, content
135
142
  unless content.empty?
136
143
  puts
@@ -139,6 +146,60 @@ module Tet
139
146
  end
140
147
  end
141
148
 
149
+ # Render a string with details about all of the test run.
150
+ def statistics_report
151
+ pass_count = Data.count_type(:pass)
152
+ fail_count = Data.count_type(:fail)
153
+ error_count = Data.count_type(:error)
154
+
155
+ output = []
156
+ output << "Errors: #{error_count}" unless error_count.zero?
157
+ output << "Failed: #{fail_count}" unless fail_count.zero?
158
+ output << "Passed: #{pass_count}" unless pass_count.zero?
159
+
160
+ output.join(?\n)
161
+ end
162
+
163
+ # Render a string with details about all of the failures encountered.
164
+ def failure_report
165
+ errors = Data.select_type(:error)
166
+
167
+ Data.select_type(:fail, :error)
168
+ .map do |node|
169
+ node.label
170
+ .tap do |label|
171
+ if node.type == :error
172
+ error_note = "EXCEPTION_#{1 + errors.index(node)}"
173
+ expected = node.data[:expected]
174
+ error_note << " (expected: #{expected}" if expected
175
+
176
+ label << error_note
177
+ end
178
+ end
179
+ .map(&:to_label_string)
180
+ .join(' :: ')
181
+ end
182
+ .join(?\n)
183
+ end
184
+
185
+ # Render a string with details about all of the errors encountered.
186
+ def error_report
187
+ Data.select_type(:error)
188
+ .map.with_index do |node, index|
189
+ error = node.data[:caught]
190
+ message = error.to_s
191
+ message << " (#{error.class})" if message != error.class.to_s
192
+ summary = "#{index + 1}. #{message}"
193
+
194
+ error.backtrace
195
+ .reject { |line| line.start_with?(__FILE__) }
196
+ .map { |line| line.indent }
197
+ .unshift(summary)
198
+ .join(?\n)
199
+ end
200
+ .join("\n\n")
201
+ end
202
+
142
203
  # Check and set a flag to prevent test blocks from nesting
143
204
  def nesting_guard guard_state
144
205
  raise TestError, 'assertions can not be nested' if @nesting_banned
@@ -150,136 +211,93 @@ module Tet
150
211
  end
151
212
 
152
213
 
214
+ # Because tests are represented as series of nested groups containing
215
+ # assertions, the test data is stored in a tree.
216
+ module Tree
217
+ module Basics
218
+ include Enumerable
153
219
 
154
- # Tracks and reports statistics about the tests that have run
155
- module Stats
156
- Counts = { passed: 0, failed: 0, erred: 0 }
157
- Marks = { passed: ?., failed: ?!, erred: ?? }
158
-
159
- class << self
160
- # Call when an assertion has passed
161
- def passed
162
- log :passed
163
- end
164
-
165
- # Call when an assertion has failed
166
- def failed
167
- log :failed
168
- end
169
-
170
- # Call when an assertion has erred
171
- def erred
172
- log :erred
220
+ # Create and append a new node to this node, returning the new node.
221
+ def append_node type, data
222
+ Node.new(type: type, data: data, parent: self)
223
+ .tap { |node| @children << node }
173
224
  end
174
225
 
175
- # Returns true if no statistics have been logged
176
- def empty?
177
- Counts.values.inject(&:+).zero?
226
+ # Recursively iterate over each node in the test data tree in the order
227
+ # that they were added.
228
+ def each &block
229
+ @children.each do |node|
230
+ block.call(node)
231
+ node.each(&block)
232
+ end
178
233
  end
234
+ end
179
235
 
180
- # Returns a string with statistics about the tests that have been run
181
- def report
182
- errors = Counts[:erred]
183
- fails = Counts[:failed]
184
- passes = Counts[:passed]
185
-
186
- output = []
187
- output << "Errors: #{errors}" unless errors.zero?
188
- output << "Failed: #{fails}"
189
- output << "Passed: #{passes}"
236
+ # The root of the tree with methods to terminate Node methods which search
237
+ # up the tree, as well as methods for enumerating over the test data, adding
238
+ # labels and adding nodes.
239
+ class Root
240
+ include Basics
190
241
 
191
- output.join(?\n)
242
+ def initialize
243
+ @children = []
244
+ @current_node = self
192
245
  end
193
246
 
194
- private
195
-
196
- # Log an event and print a mark to show progress is being made on tests
197
- def log type
198
- Counts[type] += 1
199
-
200
- print Marks[type]
201
- $stdout.flush
247
+ # Terminate Node#label.
248
+ def label
249
+ []
202
250
  end
203
- end
204
- end
205
-
206
-
207
- # Tracks and reports messages for each test
208
- module Messages
209
- Labels = []
210
- Results = []
211
- Errors = []
212
251
 
213
- class << self
214
- # Add a label to all subsequent messages
252
+ # Run a block where any notes added will be inside a new label node.
215
253
  def with_label label
216
- Labels.push(label)
254
+ previous = @current_node
255
+ @current_node = add_note(:label, label)
217
256
  yield
218
257
  ensure
219
- Labels.pop
220
- end
221
-
222
- # Call when an assertion has failed
223
- def failed
224
- add_result!
258
+ @current_node = previous
259
+ self
225
260
  end
226
261
 
227
- # Call when an assertion has passed
228
- def erred caught, expected = nil
229
- number = Stats::Counts[:erred]
230
- label = "EXCEPTION_#{number}"
231
- label << " (expected: #{expected})" if expected
232
-
233
- with_label(label) { add_result! }
234
-
235
- Errors.push(error_message(caught, number))
262
+ # Add a node to note some data within the node that is currently active.
263
+ def add_note type, data = nil
264
+ @current_node.append_node(type, data)
236
265
  end
237
266
 
238
- # Returns a string with details about all failed tests
239
- def failure_report
240
- Results.join(?\n)
267
+ # Get an array of all nodes of some type in the order they were added.
268
+ def select_type *types
269
+ select { |node| types.include?(node.type) }
241
270
  end
242
271
 
243
- # Returns a string with details about all errors
244
- def error_report
245
- Errors.join("\n\n")
272
+ # Count the number of nodes of a given type.
273
+ def count_type type
274
+ select_type(type).size
246
275
  end
276
+ end
247
277
 
248
- private
278
+ # A node to store data about that some point in the test tree
279
+ class Node
280
+ include Basics
281
+ attr_reader :data, :type
249
282
 
250
- # Add a message for a new result using the current labels
251
- def add_result!
252
- Results.push(
253
- Labels.map { |raw| raw.to_label }
254
- .reject(&:empty?)
255
- .join(' :: ')
256
- )
283
+ def initialize parent:, type:, data: nil
284
+ @type = type
285
+ @data = data
286
+ @parent = parent
287
+ @children = []
257
288
  end
258
289
 
259
- def format_label label
260
- case label
261
- when Module
262
- label.name
263
- when String
264
- label.to_s
290
+ # Generate the array of labels that identify this point in the tree.
291
+ def label
292
+ if @type == :label
293
+ @parent.label + [@data]
265
294
  else
266
- label.inspect
295
+ @parent.label
267
296
  end
268
297
  end
269
-
270
- # Format an error into a message string
271
- def error_message error, number
272
- error_message = error.to_s
273
- error_class = error.class.to_s
274
- error_message << " (#{error.class})" if error_message != error_class
275
-
276
- summary = "#{number}. #{error_message}"
277
- details = error.backtrace
278
- .reject { |line| line.start_with?(__FILE__) }
279
- .map { |line| line.indent }
280
-
281
- details.unshift(summary).join(?\n)
282
- end
283
298
  end
284
299
  end
300
+
301
+ # The instance of the Tree data structure that stores all of the test results.
302
+ Data = Tree::Root.new
285
303
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tet
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.5.0
4
+ version: 1.5.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Colin Fulton
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-03-08 00:00:00.000000000 Z
11
+ date: 2017-03-10 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: A very minimal test framework designed for simple projects. A couple
14
14
  of features, relatively nice looking output, and nothing else. Does the world need