xspec 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a5dba5d7629f6d87591f9abe883290f50372dc64
4
- data.tar.gz: ead15780cdec15272984c1580051e7d7f2eadded
3
+ metadata.gz: b3831933eef297e842aeb3d87c7fd269f15e1377
4
+ data.tar.gz: 72891d3ec2b7a439cbedc809c98393591e673d46
5
5
  SHA512:
6
- metadata.gz: b37433a77450176d0cf1ebeae40d5ad24ef28ce8095887126edfd5dfd0040fdcfbf418a1726862a60eb7f275f347d19a371720331b5376145e256bff08374ef5
7
- data.tar.gz: 963b1b472454aeaeb03aa956a1e38ff3a9b1a9bb4bf78fcd8c9eb06aae26a31d4591ed8e7b9a4fa1c11f43a7413a2d37112d2bd140c182145fcadc8745922b91
6
+ metadata.gz: 3825fe02479cf05849b66351a846adb91d0af0f895b1b5a1e12e555626fca1724066d759466f8b41e7149691b5e290288098e50dff3877beb1f220549d55f9cc
7
+ data.tar.gz: e4e573a3aca9af04bfa5f9b4db9af146c29f56d1112c3ed410b78e5d5ab785db6c53abc59a74be333dc1fc92d29b1c2bfc20d147882ec194dfb9746fc6650b50
data/README.md CHANGED
@@ -21,7 +21,7 @@ extend XSpec.dsl # Use defaults
21
21
  describe 'my application' do
22
22
  it 'does math' do
23
23
  double = instance_double('Calculator')
24
- expect(double).add(1, 1) { 2 }
24
+ stub(double).add(1, 1) { 2 }
25
25
 
26
26
  assert_equal 2, double.add(1, 1)
27
27
  end
@@ -43,9 +43,9 @@ see the colors in this README, but trust me they are quite lovely.
43
43
  > xspec example.rb
44
44
 
45
45
  my application
46
- 0.000s does math
47
- 0.011s is slow sometimes
48
- 0.000s fails - FAILED
46
+ 0.000s 3l1 does math
47
+ 0.011s f0j is slow sometimes
48
+ 0.000s juj fails - FAILED
49
49
 
50
50
  Timings:
51
51
  0.001 #################### 2
@@ -54,11 +54,25 @@ my application
54
54
  0.1 ########## 1
55
55
 
56
56
 
57
- my application fails:
57
+ juj - my application fails
58
58
  "fruit" not present in: "punch"
59
59
 
60
- example.rb:18:in `block (2 levels) in <top (required)>'
61
- bin/xspec:19:in `<main>'
60
+ test.rb:17:in `block (2 levels) in <top (required)>'
61
+ bin/xspec:44:in `<main>'
62
+ ```
63
+
64
+ The three-character tag next to each test is its short id. You can use it to
65
+ run a single test:
66
+
67
+ ```
68
+ > xspec -f 3l1
69
+
70
+ my application
71
+ 0.000s 3l1 does math
72
+
73
+ Timings:
74
+ 0.001 #################### 1
75
+
62
76
  ```
63
77
 
64
78
  ### Customization
@@ -73,11 +87,11 @@ expectations. You could do that:
73
87
  require 'xspec'
74
88
 
75
89
  extend XSpec.dsl(
76
- assertion_context: XSpec::AssertionContext.stack {
77
- include XSpec::AssertionContext::RSpecExpectations
90
+ evaluator_context: XSpec::Evaluator.stack {
91
+ include XSpec::Evaluator::RSpecExpectations
78
92
  },
79
- notifier: XSpec::Notifiers::Character.new +
80
- XSpec::Notifiers::FailuresAtEnd.new
93
+ notifier: XSpec::Notifier::Character.new +
94
+ XSpec::Notifier::FailuresAtEnd.new
81
95
  )
82
96
 
83
97
  describe '...' do
@@ -86,15 +100,15 @@ end
86
100
  ```
87
101
 
88
102
  Of course, you can make your own extension classes as well. For details, see
89
- the "Configuration" section of the documentation.
103
+ the API documentation.
90
104
 
91
105
  Documentation
92
106
  -------------
93
107
 
94
108
  There are two major sources of documentation:
95
109
 
96
- * [Main API documentation.](https://xaviershay.github.io/xspec/api.html)
97
- * [Literate source code.](https://xaviershay.github.io/xspec/)
110
+ * [Main API documentation.](https://xaviershay.github.io/xspec/docs/api.html)
111
+ * [Literate source code.](https://xaviershay.github.io/xspec/docs/xspec.html)
98
112
 
99
113
  It is expected that regular users of XSpec will read both at least once. There
100
114
  isn't much to them, and they will give you a useful mental model of how XSpec
data/bin/xspec CHANGED
@@ -1,5 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
+ require 'optparse'
4
+
3
5
  $LOAD_PATH.unshift File.expand_path("../../lib", __FILE__)
4
6
 
5
7
  require 'xspec'
@@ -7,6 +9,27 @@ require 'xspec'
7
9
  $LOAD_PATH.unshift "spec"
8
10
  $LOAD_PATH.unshift "lib"
9
11
 
12
+ filter = nil
13
+ short_ids = []
14
+
15
+ parser = OptionParser.new
16
+ parser.banner = "Usage: xspec [options] [files]"
17
+ parser.separator ""
18
+ parser.on('-e FILTER', "Run specs with full name including FILTER.") do |f|
19
+ filter = Regexp.new(f)
20
+ end
21
+ parser.on('-f ID', "Run spec with short id ID. Use multiple times to specify more than one id.") do |f|
22
+ short_ids << f
23
+ end
24
+ parser.on("-h", "--help", "Show this message.") do
25
+ $stderr.puts parser
26
+ exit
27
+ end
28
+ parser.separator ""
29
+
30
+ parser.parse!
31
+
32
+
10
33
  files = if ARGV.any? {|x| x.length > 0 }
11
34
  ARGV
12
35
  else
@@ -18,7 +41,25 @@ files.each do |f|
18
41
  end
19
42
 
20
43
  if respond_to?(:run!)
21
- exit 1 unless run!
44
+ result = run! {|config|
45
+ config.update(scheduler: XSpec::Scheduler::Filter.new(
46
+ scheduler: config.fetch(:scheduler),
47
+ filter: -> uow {
48
+ inc = true
49
+
50
+ if short_ids.any?
51
+ inc &&= short_ids.include?(config.fetch(:short_id).(uow))
52
+ end
53
+
54
+ if filter
55
+ inc &&= uow.full_name =~ filter
56
+ end
57
+
58
+ inc
59
+ }
60
+ ))
61
+ }
62
+ exit 1 unless result
22
63
  else
23
64
  $stderr.puts "This script can only be used when XSpec.dsl is mixed in to " +
24
65
  "global scope."
@@ -12,8 +12,8 @@ module XSpec
12
12
  # This enables different options to be specified per DSL, which is at the
13
13
  # heart of XSpec's modularity. It is easy to change every component to your
14
14
  # liking.
15
- def dsl(options = {})
16
- options = XSpec.add_defaults(options)
15
+ def dsl(config = {})
16
+ config = XSpec.add_defaults(config)
17
17
 
18
18
  Module.new do
19
19
  # Each DSL provides a standard set of methods provided by the [DSL
@@ -24,22 +24,26 @@ module XSpec
24
24
  # described in detail in the
25
25
  # [`data_structures.rb`](data_structures.html).
26
26
  def __xspec_context
27
- evaluator = __xspec_opts.fetch(:evaluator)
27
+ evaluator = __xspec_config.fetch(:evaluator)
28
28
  @__xspec_context ||= XSpec::Context.root(evaluator)
29
29
  end
30
30
 
31
- # Some meta-magic is needed to enable the options from local scope above
31
+ # Some meta-magic is needed to enable the config from local scope above
32
32
  # to be available inside the module.
33
- define_method(:__xspec_opts) { options }
33
+ define_method(:__xspec_config) { config }
34
34
 
35
35
  # `run!` is where the magic happens. Typically called at the end of a
36
36
  # file (or by `autorun!`), this method takes all the data that was
37
37
  # accumulated by the DSL methods above and runs it through the scheduler.
38
- def run!
39
- notifier = __xspec_opts.fetch(:notifier)
40
- scheduler = __xspec_opts.fetch(:scheduler)
38
+ #
39
+ # It takes an optional block that can be used to override any options
40
+ # set in the initial `XSpec.dsl` call.
41
+ def run!(&overrides)
42
+ overrides ||= -> x { x }
43
+ config = overrides.(__xspec_config)
44
+ scheduler = config.fetch(:scheduler)
41
45
 
42
- scheduler.run(__xspec_context, notifier)
46
+ scheduler.run(__xspec_context, config)
43
47
  end
44
48
 
45
49
  # It is often convenient to trigger a run after all files have been
@@ -2,7 +2,7 @@
2
2
 
3
3
  # XSpec data structures are very dumb. They:
4
4
  #
5
- # * Only contain iteration and creation logic.
5
+ # * Only contain iteration, property, and creation logic.
6
6
  # * Do not store recursive references ("everything flows downhill").
7
7
  module XSpec
8
8
  # A unit of work, usually created by the `it` DSL method, is a labeled,
@@ -85,7 +85,7 @@ module XSpec
85
85
  # A shared context is a floating context that isn't part of any context
86
86
  # heirachy, so its units of work will not be visible to the root node. It
87
87
  # can be brought into any point in the heirachy using `copy_into_tree`
88
- # (aliased as `it_behaves_like_a` in the DSL), and this can be done
88
+ # (aliased as `include_context` in the DSL), and this can be done
89
89
  # multiple times, which allows definitions to be reused.
90
90
  #
91
91
  # This is leaky abstraction, since only units of work are copied from
@@ -156,6 +156,10 @@ module XSpec
156
156
  def block; unit_of_work.block; end
157
157
  def name; unit_of_work.name; end
158
158
 
159
+ def full_name
160
+ (parents + [self]).map(&:name).compact.join(' ')
161
+ end
162
+
159
163
  def immediate_parent
160
164
  parents.last
161
165
  end
@@ -170,6 +174,7 @@ module XSpec
170
174
  ExecutedUnitOfWork = Struct.new(:nested_unit_of_work, :errors, :duration) do
171
175
  def name; nested_unit_of_work.name end
172
176
  def parents; nested_unit_of_work.parents end
177
+ def full_name; nested_unit_of_work.full_name end
173
178
  end
174
179
 
175
180
  # A test failure will be reported as a `Failure`, which includes contextual
@@ -7,7 +7,21 @@ require 'xspec/schedulers'
7
7
  require 'xspec/evaluators'
8
8
  require 'xspec/notifiers'
9
9
 
10
+ require 'digest/sha1'
11
+
10
12
  module XSpec
13
+ def default_short_id(uow)
14
+ length = 3
15
+ base = 32
16
+ digest = Digest::SHA1.hexdigest(uow.full_name).hex
17
+ bottom = base ** (length-1)
18
+ top = base ** length
19
+ shifted = digest % (top - bottom) + bottom
20
+
21
+ shifted.to_s(base)
22
+ end
23
+ module_function :default_short_id
24
+
11
25
  def add_defaults(options = {})
12
26
  # A notifier makes it possible to observe the state of the system, be that
13
27
  # progress or details of failing tests.
@@ -20,6 +34,9 @@ module XSpec
20
34
  # used.
21
35
  options[:evaluator] ||= Evaluator::DEFAULT
22
36
 
37
+ options[:short_id] ||= XSpec.method(:default_short_id)
38
+
39
+
23
40
  # An scheduler is responsible for scheduling units of work and handing them
24
41
  # off to the assertion context. Any logic regarding threads, remote
25
42
  # execution or the like belongs in a scheduler.
@@ -24,7 +24,7 @@ module XSpec
24
24
  __xspec_context.create_shared_context(*args, &block)
25
25
  end
26
26
 
27
- def it_behaves_like_a(context)
27
+ def include_context(context)
28
28
  __xspec_context.copy_into_tree(context)
29
29
  end
30
30
  end
@@ -33,28 +33,24 @@ module XSpec
33
33
  module Top
34
34
  def call(unit_of_work)
35
35
  super
36
+ rescue EvaluateFailed => e
37
+ [Failure.new(unit_of_work, e.message, e.backtrace)]
36
38
  rescue => e
37
39
  [CodeException.new(unit_of_work, e.message, e.backtrace)]
38
40
  end
39
41
  end
40
42
 
43
+ # As long as the `Top` evaluator is used, evaluators can raise
44
+ # `EvaluateFailed` to indicate a failure separate from a normal code
45
+ # exception.
46
+ EvaluateFailed = Class.new(RuntimeError)
47
+
41
48
  # ### Simple Assertions
42
49
  #
43
50
  # This simple evaluator provides very straight-forward assertion methods.
44
51
  module Simple
45
- class AssertionFailed < RuntimeError
46
- attr_reader :message, :backtrace
47
-
48
- def initialize(message, backtrace)
49
- @message = message
50
- @backtrace = backtrace
51
- end
52
- end
53
-
54
52
  def call(unit_of_work)
55
53
  super
56
- rescue AssertionFailed => e
57
- [Failure.new(unit_of_work, e.message, e.backtrace)]
58
54
  end
59
55
 
60
56
  def assert(proposition, message=nil)
@@ -90,7 +86,7 @@ EOS
90
86
  private
91
87
 
92
88
  def _raise(message)
93
- raise AssertionFailed.new(message, caller)
89
+ raise EvaluateFailed, message
94
90
  end
95
91
  end
96
92
 
@@ -99,12 +95,8 @@ EOS
99
95
  # The doubles module provides test doubles that can be used in-place of
100
96
  # real objects.
101
97
  module Doubles
102
- DoubleFailure = Class.new(RuntimeError)
103
-
104
98
  def call(unit_of_work)
105
99
  super
106
- rescue DoubleFailure => e
107
- [Failure.new(unit_of_work, e.message, e.backtrace)]
108
100
  end
109
101
 
110
102
  # It can be configured with the following options:
@@ -227,7 +219,7 @@ EOS
227
219
  @received.delete_at(i)
228
220
  else
229
221
  name, rest = *args
230
- ::Kernel.raise DoubleFailure,
222
+ ::Kernel.raise EvaluateFailed,
231
223
  "Did not receive: %s(%s)\nDid receive:%s\n" % [
232
224
  name,
233
225
  [*rest].map(&:inspect).join(", "),
@@ -269,7 +261,7 @@ EOS
269
261
  name, rest = *args
270
262
 
271
263
  unless @klass.respond_to?(name)
272
- raise DoubleFailure,
264
+ raise EvaluateFailed,
273
265
  "#{@klass}.#{name} is unimplemented or not public"
274
266
  end
275
267
  end
@@ -280,7 +272,7 @@ EOS
280
272
  name, rest = *args
281
273
 
282
274
  unless @klass.public_instance_methods.include?(name)
283
- raise DoubleFailure,
275
+ raise EvaluateFailed,
284
276
  "#{@klass}##{name} is unimplemented or not public"
285
277
  end
286
278
  end
@@ -293,7 +285,7 @@ EOS
293
285
  ref = if self.class.const_defined?(klass)
294
286
  type.new(self.class.const_get(klass))
295
287
  else
296
- raise DoubleFailure, "#{klass} is not a valid class name"
288
+ raise EvaluateFailed, "#{klass} is not a valid class name"
297
289
  end
298
290
 
299
291
  super
@@ -5,6 +5,17 @@
5
5
  # summarizing the run when it finished.
6
6
  module XSpec
7
7
  module Notifier
8
+ # A formatter must implement at least four methods. `run_start` and
9
+ # `run_finish` are called at the beginning and end of the full spec run
10
+ # respectively, while `evaluate_start` and `evaluate_finish` are called for
11
+ # each test. See [API docs](api.html#notifiers) for more information.
12
+ module EmptyFormatter
13
+ def run_start(*_); end
14
+ def evaluate_start(*_); end
15
+ def evaluate_finish(*_); end
16
+ def run_finish(*_); true; end
17
+ end
18
+
8
19
  # Many notifiers play nice with others, and can be composed together in a
9
20
  # way that each notifier will have its callback run in turn.
10
21
  module Composable
@@ -20,8 +31,8 @@ module XSpec
20
31
  @notifiers = notifiers
21
32
  end
22
33
 
23
- def run_start
24
- notifiers.each(&:run_start)
34
+ def run_start(*args)
35
+ notifiers.each {|x| x.run_start(*args) }
25
36
  end
26
37
 
27
38
  def evaluate_start(*args)
@@ -44,16 +55,13 @@ module XSpec
44
55
  # Outputs a single character for each executed unit of work representing
45
56
  # the result.
46
57
  class Character
58
+ include EmptyFormatter
47
59
  include Composable
48
60
 
49
61
  def initialize(out = $stdout)
50
62
  @out = out
51
63
  end
52
64
 
53
- def run_start; end
54
-
55
- def evaluate_start(*_); end
56
-
57
65
  def evaluate_finish(result)
58
66
  @out.print label_for_failure(result.errors[0])
59
67
  @failed ||= result.errors.any?
@@ -73,11 +81,11 @@ module XSpec
73
81
  else '.'
74
82
  end
75
83
  end
76
-
77
84
  end
78
85
 
79
86
  # Renders a histogram of test durations after the entire run is complete.
80
87
  class TimingsAtEnd
88
+ include EmptyFormatter
81
89
  include Composable
82
90
 
83
91
  DEFAULT_SPLITS = [0.001, 0.005, 0.01, 0.1, 1.0, Float::INFINITY]
@@ -92,11 +100,6 @@ module XSpec
92
100
  @out = out
93
101
  end
94
102
 
95
- def run_start(*_); end
96
-
97
- def evaluate_start(_)
98
- end
99
-
100
103
  def evaluate_finish(result)
101
104
  timings[result] = result.duration
102
105
  end
@@ -148,19 +151,29 @@ module XSpec
148
151
  end
149
152
  end
150
153
 
154
+ # Provides convenience methods for working with short ids.
155
+ module ShortIdSupport
156
+ def run_start(config)
157
+ super
158
+ @short_id = config.fetch(:short_id)
159
+ end
160
+
161
+ def short_id_for(x)
162
+ @short_id.(x)
163
+ end
164
+ end
165
+
151
166
  # Outputs error messages and backtraces after the entire run is complete.
152
167
  class FailuresAtEnd
168
+ include EmptyFormatter
153
169
  include Composable
170
+ include ShortIdSupport
154
171
 
155
172
  def initialize(out = $stdout)
156
173
  @errors = []
157
174
  @out = out
158
175
  end
159
176
 
160
- def run_start; end
161
-
162
- def evaluate_start(*_); end
163
-
164
177
  def evaluate_finish(result)
165
178
  self.errors += result.errors
166
179
  end
@@ -170,7 +183,11 @@ module XSpec
170
183
 
171
184
  out.puts
172
185
  errors.each do |error|
173
- out.puts "%s:\n%s\n\n" % [full_name(error.unit_of_work), error.message.lines.map {|x| " #{x}"}.join("")]
186
+ out.puts "%s - %s\n%s\n\n" % [
187
+ short_id_for(error.unit_of_work),
188
+ error.unit_of_work.full_name,
189
+ error.message.lines.map {|x| " #{x}"}.join("")
190
+ ]
174
191
  clean_backtrace(error.caller).each do |line|
175
192
  out.puts " %s" % line
176
193
  end
@@ -182,10 +199,6 @@ module XSpec
182
199
 
183
200
  private
184
201
 
185
- def full_name(unit_of_work)
186
- (unit_of_work.parents + [unit_of_work]).map(&:name).compact.join(' ')
187
- end
188
-
189
202
  # A standard backtrace contains many entries for XSpec itself which are
190
203
  # not useful for debugging your tests, so they are stripped out.
191
204
  def clean_backtrace(backtrace)
@@ -204,9 +217,9 @@ module XSpec
204
217
  # Includes nicely formatted names and durations of each test in the output,
205
218
  # with color.
206
219
  class ColoredDocumentation
207
- require 'set'
208
-
220
+ include EmptyFormatter
209
221
  include Composable
222
+ include ShortIdSupport
210
223
 
211
224
  VT100_COLORS = {
212
225
  :black => 30,
@@ -219,24 +232,6 @@ module XSpec
219
232
  :white => 37
220
233
  }
221
234
 
222
- def color_code_for(color)
223
- VT100_COLORS.fetch(color)
224
- end
225
-
226
- def colorize(text, color)
227
- "\e[#{color_code_for(color)}m#{text}\e[0m"
228
- end
229
-
230
- def decorate(result)
231
- name = result.name
232
- out = if result.errors.any?
233
- colorize(append_failed(name), :red)
234
- else
235
- colorize(name , :green)
236
- end
237
- "%.3fs " % result.duration + out
238
- end
239
-
240
235
  def initialize(out = $stdout)
241
236
  self.indent = 2
242
237
  self.last_seen_names = []
@@ -244,10 +239,6 @@ module XSpec
244
239
  self.out = out
245
240
  end
246
241
 
247
- def run_start; end
248
-
249
- def evaluate_start(*_); end
250
-
251
242
  def evaluate_finish(result)
252
243
  output_context_header! result.parents.map(&:name).compact
253
244
 
@@ -267,6 +258,28 @@ module XSpec
267
258
 
268
259
  attr_accessor :last_seen_names, :indent, :failed, :out
269
260
 
261
+ def color_code_for(color)
262
+ VT100_COLORS.fetch(color)
263
+ end
264
+
265
+ def colorize(text, color)
266
+ "\e[#{color_code_for(color)}m#{text}\e[0m"
267
+ end
268
+
269
+ def decorate(result)
270
+ name = result.name
271
+ out = if result.errors.any?
272
+ colorize(append_failed(name), :red)
273
+ else
274
+ colorize(name , :green)
275
+ end
276
+ "%.3fs %s %s" % [
277
+ result.duration,
278
+ short_id_for(result),
279
+ out,
280
+ ]
281
+ end
282
+
270
283
  def output_context_header!(parent_names)
271
284
  if parent_names != last_seen_names
272
285
  tail = parent_names - last_seen_names
@@ -299,11 +312,7 @@ module XSpec
299
312
  # Useful as a parent class for other notifiers or for testing.
300
313
  class Null
301
314
  include Composable
302
-
303
- def run_start; end
304
- def evaluate_start(*_); end
305
- def evaluate_finish(*_); end
306
- def run_finish; true; end
315
+ include EmptyFormatter
307
316
  end
308
317
 
309
318
  DEFAULT =
@@ -12,8 +12,9 @@ module XSpec
12
12
  @clock = opts.fetch(:clock, ->{ Time.now.to_f })
13
13
  end
14
14
 
15
- def run(context, notifier)
16
- notifier.run_start
15
+ def run(context, config)
16
+ notifier = config.fetch(:notifier)
17
+ notifier.run_start(config)
17
18
 
18
19
  context.nested_units_of_work.each do |x|
19
20
  notifier.evaluate_start(x)
@@ -34,6 +35,25 @@ module XSpec
34
35
  attr_reader :clock
35
36
  end
36
37
 
38
+ class Filter
39
+ def initialize(scheduler:, filter:)
40
+ @scheduler = scheduler
41
+ @filter = filter
42
+ end
43
+
44
+ def run(context, config)
45
+ scheduler.run(FilteredContext.new(context, filter), config)
46
+ end
47
+
48
+ FilteredContext = Struct.new(:context, :filter) do
49
+ def nested_units_of_work
50
+ context.nested_units_of_work.select(&filter)
51
+ end
52
+ end
53
+
54
+ attr_reader :scheduler, :filter
55
+ end
56
+
37
57
  DEFAULT = Serial.new
38
58
  end
39
59
  end
@@ -12,7 +12,7 @@ extend XSpec.dsl(
12
12
  def assert_errors_from_run(context, expected_error_messages)
13
13
  context.run!
14
14
 
15
- notifier = context.__xspec_opts.fetch(:notifier)
15
+ notifier = context.__xspec_config.fetch(:notifier)
16
16
  assert_equal expected_error_messages, notifier.errors.flatten.map(&:message)
17
17
  end
18
18
 
@@ -14,7 +14,7 @@ describe 'simple assertion context' do
14
14
  begin
15
15
  subject.assert(false)
16
16
  fail "Assertion did not fail"
17
- rescue XSpec::Evaluator::Simple::AssertionFailed => e
17
+ rescue XSpec::Evaluator::EvaluateFailed => e
18
18
  assert_equal "assertion failed", e.message
19
19
  end
20
20
  end
@@ -23,7 +23,7 @@ describe 'simple assertion context' do
23
23
  begin
24
24
  subject.assert(false, "nope")
25
25
  fail "Assertion did not fail"
26
- rescue XSpec::Evaluator::Simple::AssertionFailed => e
26
+ rescue XSpec::Evaluator::EvaluateFailed => e
27
27
  assert_equal "nope", e.message
28
28
  end
29
29
  end
@@ -38,7 +38,7 @@ describe 'simple assertion context' do
38
38
  begin
39
39
  subject.assert_equal("a", "b")
40
40
  fail "Assertion did not fail"
41
- rescue XSpec::Evaluator::Simple::AssertionFailed => e
41
+ rescue XSpec::Evaluator::EvaluateFailed => e
42
42
  assert_include 'want: "a"', e.message
43
43
  assert_include 'got: "b"', e.message
44
44
  end
@@ -50,7 +50,7 @@ describe 'simple assertion context' do
50
50
  begin
51
51
  subject.fail
52
52
  assert false, "fail did not fail"
53
- rescue XSpec::Evaluator::Simple::AssertionFailed => e
53
+ rescue XSpec::Evaluator::EvaluateFailed => e
54
54
  assert_equal "failed", e.message
55
55
  end
56
56
  end
@@ -59,7 +59,7 @@ describe 'simple assertion context' do
59
59
  begin
60
60
  subject.fail ":("
61
61
  assert false, "fail did not fail"
62
- rescue XSpec::Evaluator::Simple::AssertionFailed => e
62
+ rescue XSpec::Evaluator::EvaluateFailed => e
63
63
  assert_equal ":(", e.message
64
64
  end
65
65
  end
@@ -0,0 +1,19 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'short ids' do
4
+ def short_id_for(name)
5
+ XSpec.default_short_id \
6
+ XSpec::NestedUnitOfWork.new([], XSpec::UnitOfWork.new(name))
7
+ end
8
+
9
+ it 'is the same for same names' do
10
+ assert_equal short_id_for("abc"), short_id_for("abc")
11
+ end
12
+
13
+ it 'is always the same length' do
14
+ 100.times do
15
+ name = rand.to_s
16
+ assert 3 == short_id_for(name).length, "#{name} had bad short id"
17
+ end
18
+ end
19
+ end
@@ -12,7 +12,7 @@ describe 'doubles assertion context' do
12
12
 
13
13
  it 'converts double exceptions to failures' do
14
14
  result = subject.call(XSpec::UnitOfWork.new(nil, ->{
15
- raise XSpec::Evaluator::Doubles::DoubleFailure, "nope"
15
+ raise XSpec::Evaluator::EvaluateFailed, "nope"
16
16
  }))
17
17
  assert_equal "nope", result[0].message
18
18
  end
@@ -81,7 +81,7 @@ describe 'doubles assertion context' do
81
81
  verify(double).foo("b")
82
82
  }
83
83
  fail "no error raised"
84
- rescue XSpec::Evaluator::Doubles::DoubleFailure => e
84
+ rescue XSpec::Evaluator::EvaluateFailed => e
85
85
  assert_include "Did not receive", e.message
86
86
  assert_include 'foo("b")', e.message
87
87
  end
@@ -96,7 +96,7 @@ describe 'doubles assertion context' do
96
96
  verify(double).foo("c")
97
97
  }
98
98
  fail "no error raised"
99
- rescue XSpec::Evaluator::Doubles::DoubleFailure => e
99
+ rescue XSpec::Evaluator::EvaluateFailed => e
100
100
  assert_include "Did not receive", e.message
101
101
  assert_include 'foo("b")', e.message
102
102
  assert_include "Did receive", e.message
@@ -122,7 +122,7 @@ describe 'doubles assertion context' do
122
122
  stub(double).bogus_method { 123 }
123
123
  }
124
124
  fail "no error raised"
125
- rescue XSpec::Evaluator::Doubles::DoubleFailure => e
125
+ rescue XSpec::Evaluator::EvaluateFailed => e
126
126
  assert_include "LoadedClass#bogus_method", e.message
127
127
  end
128
128
  end
@@ -134,7 +134,7 @@ describe 'doubles assertion context' do
134
134
  verify(double).bogus_method { 123 }
135
135
  }
136
136
  fail "no error raised"
137
- rescue XSpec::Evaluator::Doubles::DoubleFailure => e
137
+ rescue XSpec::Evaluator::EvaluateFailed => e
138
138
  assert_include "LoadedClass#bogus_method", e.message
139
139
  end
140
140
  end
@@ -157,7 +157,7 @@ describe 'doubles assertion context' do
157
157
  stub(double).bogus_method { 123 }
158
158
  }
159
159
  fail "no error raised"
160
- rescue XSpec::Evaluator::Doubles::DoubleFailure => e
160
+ rescue XSpec::Evaluator::EvaluateFailed => e
161
161
  assert_include "LoadedClass.bogus_method", e.message
162
162
  end
163
163
  end
@@ -169,7 +169,7 @@ describe 'doubles assertion context' do
169
169
  verify(double).bogus_method
170
170
  }
171
171
  fail "no error raised"
172
- rescue XSpec::Evaluator::Doubles::DoubleFailure => e
172
+ rescue XSpec::Evaluator::EvaluateFailed => e
173
173
  assert_include "LoadedClass.bogus_method", e.message
174
174
  end
175
175
  end
@@ -190,7 +190,7 @@ describe 'strict doubles assertion context' do
190
190
  begin
191
191
  subject.instance_double("Bogus")
192
192
  fail "no error raised"
193
- rescue XSpec::Evaluator::Doubles::DoubleFailure => e
193
+ rescue XSpec::Evaluator::EvaluateFailed => e
194
194
  assert_include "Bogus", e.message
195
195
  end
196
196
  end
@@ -10,6 +10,7 @@ end
10
10
  describe 'failures at end notifier' do
11
11
  let(:out) { StringIO.new }
12
12
  let(:notifier) { XSpec::Notifier::FailuresAtEnd.new(out) }
13
+ let(:config) {{ short_id: -> _ { "XXX" }}}
13
14
 
14
15
  it 'returns true when no errors are observed' do
15
16
  assert notifier.run_finish
@@ -21,10 +22,11 @@ describe 'failures at end notifier' do
21
22
  "failed",
22
23
  []
23
24
  )
25
+ notifier.run_start(config)
24
26
  notifier.evaluate_finish(make_executed_test errors: [failure])
25
27
 
26
28
  assert !notifier.run_finish
27
- assert_include "a b c:\n failed", out.string
29
+ assert_include "a b c\n failed", out.string
28
30
  end
29
31
 
30
32
  it 'cleans lib entries out of backtrace' do
@@ -33,13 +35,14 @@ describe 'failures at end notifier' do
33
35
  "failed",
34
36
  [File.expand_path('../../../lib', __FILE__) + '/bogus.rb']
35
37
  )
38
+ notifier.run_start(config)
36
39
  notifier.evaluate_finish(make_executed_test errors: [failure])
37
40
 
38
41
  assert !notifier.run_finish
39
42
  assert !out.string.include?('bogus.rb')
40
43
  end
41
44
 
42
- it_behaves_like_a ComposableNotifier
45
+ include_context ComposableNotifier
43
46
  end
44
47
 
45
48
  describe 'character notifier' do
@@ -68,25 +71,27 @@ describe 'character notifier' do
68
71
  assert out.string == "E\n"
69
72
  end
70
73
 
71
- it_behaves_like_a ComposableNotifier
74
+ include_context ComposableNotifier
72
75
  end
73
76
 
74
77
  describe 'documentation notifier' do
75
78
  let(:notifier) { XSpec::Notifier::Documentation.new(out) }
76
79
  let(:out) { StringIO.new }
80
+ let(:config) {{ short_id: -> uow { 'XXX' }}}
77
81
 
78
82
  def evaluate_finish(args)
83
+ notifier.run_start(config)
79
84
  notifier.evaluate_finish(make_executed_test args)
80
85
  out.string
81
86
  end
82
87
 
83
88
  it 'outputs each context with a header and individual tests' do
84
- assert_equal "\na\n 0.001s b\n",
89
+ assert_equal "\na\n 0.001s XXX b\n",
85
90
  evaluate_finish(parents: ['a'], name: 'b')
86
91
  end
87
92
 
88
93
  it 'adds an indent for each nested context' do
89
- assert_equal "\na\n b\n 0.001s c\n",
94
+ assert_equal "\na\n b\n 0.001s XXX c\n",
90
95
  evaluate_finish(parents: ['a', 'b'], name: 'c')
91
96
  end
92
97
 
@@ -94,11 +99,11 @@ describe 'documentation notifier' do
94
99
  evaluate_finish(parents: ['a', 'b'], name: 'c')
95
100
  evaluate_finish(parents: ['a', 'd'], name: 'e')
96
101
 
97
- assert_equal "\na\n b\n 0.001s c\n\n d\n 0.001s e\n", out.string
102
+ assert_equal "\na\n b\n 0.001s XXX c\n\n d\n 0.001s XXX e\n", out.string
98
103
  end
99
104
 
100
105
  it 'ignores contexts with no name' do
101
- assert_equal "\na\n 0.001s b\n",
106
+ assert_equal "\na\n 0.001s XXX b\n",
102
107
  evaluate_finish(parents: [nil, 'a', nil], name: 'b')
103
108
  end
104
109
 
@@ -116,32 +121,35 @@ describe 'documentation notifier' do
116
121
  assert_include "FAILED", evaluate_finish(errors: [make_error])
117
122
  end
118
123
 
119
- it_behaves_like_a ComposableNotifier
124
+ include_context ComposableNotifier
120
125
  end
121
126
 
122
127
  describe 'colored documentation notifier' do
123
128
  let(:notifier) { XSpec::Notifier::ColoredDocumentation.new(out) }
124
129
  let(:out) { StringIO.new }
130
+ let(:config) {{ short_id: -> uow { 'XXX' }}}
125
131
 
126
132
  it 'colors successful tests green' do
133
+ notifier.run_start(config)
127
134
  notifier.evaluate_finish(make_executed_test errors: [])
128
135
 
129
136
  assert_include "\e[32m\e[0m\n", out.string
130
137
  end
131
138
 
132
139
  it 'colors failed and errored tests red' do
140
+ notifier.run_start(config)
133
141
  notifier.evaluate_finish(make_executed_test errors: [make_failure])
134
142
 
135
143
  assert_include "\e[31mFAILED\e[0m", out.string
136
144
  end
137
145
 
138
- it_behaves_like_a ComposableNotifier
146
+ include_context ComposableNotifier
139
147
  end
140
148
 
141
149
  describe 'composable notifier' do
142
150
  let(:notifier) { XSpec::Notifier::Composite.new }
143
151
 
144
- it_behaves_like_a ComposableNotifier
152
+ include_context ComposableNotifier
145
153
  end
146
154
 
147
155
  describe 'null notifier' do
@@ -151,17 +159,18 @@ describe 'null notifier' do
151
159
  assert notifier.run_finish
152
160
  end
153
161
 
154
- it_behaves_like_a ComposableNotifier
162
+ include_context ComposableNotifier
155
163
  end
156
164
 
157
165
  describe 'timings at end' do
158
- let(:notifier) { XSpec::Notifier::TimingsAtEnd.new }
166
+ let(:out) { StringIO.new }
167
+ let(:notifier) { XSpec::Notifier::TimingsAtEnd.new(out: out) }
159
168
 
160
169
  it 'always returns true' do
161
170
  assert notifier.run_finish
162
171
  end
163
172
 
164
- it_behaves_like_a ComposableNotifier
173
+ include_context ComposableNotifier
165
174
  end
166
175
 
167
176
  def make_nested_test(parent_names = [], work_name = nil)
@@ -22,6 +22,6 @@ Gem::Specification.new do |gem|
22
22
  gem.bindir = "bin"
23
23
  gem.executables << "xspec"
24
24
  gem.license = "Apache 2.0"
25
- gem.version = "0.1.0"
25
+ gem.version = "0.2.0"
26
26
  gem.has_rdoc = false
27
27
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: xspec
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Xavier Shay
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-07-29 00:00:00.000000000 Z
11
+ date: 2014-08-10 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: yeah
14
14
  email:
@@ -32,6 +32,7 @@ files:
32
32
  - spec/integration/rspec_expectations_spec.rb
33
33
  - spec/spec_helper.rb
34
34
  - spec/unit/assertion_spec.rb
35
+ - spec/unit/data_structures_spec.rb
35
36
  - spec/unit/doubles_spec.rb
36
37
  - spec/unit/let_spec.rb
37
38
  - spec/unit/notifiers_spec.rb
@@ -66,6 +67,7 @@ test_files:
66
67
  - spec/integration/rspec_expectations_spec.rb
67
68
  - spec/spec_helper.rb
68
69
  - spec/unit/assertion_spec.rb
70
+ - spec/unit/data_structures_spec.rb
69
71
  - spec/unit/doubles_spec.rb
70
72
  - spec/unit/let_spec.rb
71
73
  - spec/unit/notifiers_spec.rb