Class BareTest::Suite
In: lib/baretest/suite.rb
Parent: Object

A Suite is a container for multiple assertions. You can give a suite a description, also a suite can contain setup and teardown blocks that are executed before (setup) and after (teardown) every assertion.

Suites can also be nested. Nested suites will inherit setup and teardown.

Methods

Constants

ValidOptions = [:skip, :requires, :use, :provides, :depends_on, :tags]   A list of valid options Suite::new accepts

Attributes

ancestors  [R]  An Array containing the suite itself (first element), then its direct parent suite, then that suite‘s parent and so on
assertions  [R]  All assertions in this suite
depends_on  [R]  All things this suite depends on, see Suite::new for more information
description  [R]  This suites description. Toplevel suites usually don‘t have a description.
parent  [R]  This suites direct parent. Nil if toplevel suite.
provides  [R]  All things this suite provides, see Suite::new for more information
skipped  [R]  Whether this suite has been manually skipped (either via Suite.new(…, :skip => reason) or via Suite#skip)
suites  [R]  Nested suites, in the order of definition
tags  [R]  All things this suite is tagged with, see Suite::new for more information

Public Class methods

Create a new suite.

Arguments:

description:A string with a human readable description of this suite, preferably less than 60 characters and without newlines
parent:The suite that nests this suite. Ancestry plays a role in execution of setup and teardown blocks (all ancestors setups and teardowns are executed too).
opts:An additional options hash.

Keys the options hash accepts:

:skip:Skips the suite if true or a String is passed. If a String is passed, it is used as the reason.
:requires:A string or array of strings with requires that have to be done in order to run this suite. If a require fails, the assertions will all be skipped with reason "Missing dependency".
:use:A symbol or array of symbols with components this suite should load prior to running.
:provides:A symbol or array of symbols with dependencies this suite resolves, see ‘depends_on’.
:depends_on:A symbol or array of symbols with dependencies of this suite, see ‘provides’.
:tags:A symbol or array of symbols, useful to run only suites having/not having specific tags
&block:The given block is instance evaled and can contain further definition of this assertion. See Suite#suite and Suite#assert.

[Source]

     # File lib/baretest/suite.rb, line 86
 86:     def initialize(description=nil, parent=nil, opts=nil, &block)
 87:       @description = description
 88:       @parent      = parent
 89:       @suites      = [] # [["description", subsuite, skipped], ["description2", ...], ...] - see Array#assoc
 90:       @assertions  = []
 91:       @skipped     = false
 92:       @setup       = {nil => []}
 93:       @components  = []
 94:       @teardown    = []
 95:       @verification_exception_handlers = {}
 96:       if @parent then
 97:         @ancestors   = [self, *@parent.ancestors]
 98:         @depends_on  = @parent.depends_on
 99:         @tags        = @parent.tags
100:       else
101:         @ancestors   = [self]
102:         @depends_on  = []
103:         @tags        = []
104:       end
105:       @provides    = []
106:       @reason      = [] # skip reason
107:       if opts then
108:         raise ArgumentError, "Invalid option(s): #{(opts.keys - ValidOptions).inspect}" unless (opts.keys - ValidOptions).empty?
109:         skip, requires, use, provides, depends_on, tags = opts.values_at(*ValidOptions)
110:         skip(skip == true ? nil : skip) if skip
111:         use(*use) if use
112:         requires(*requires) if requires
113:         @depends_on |= Array(depends_on) if depends_on
114:         @provides   |= Array(provides) if provides
115:         @tags       |= Array(tags) if tags
116:       end
117:       instance_eval(&block) if block
118:     end

Public Instance methods

All setup-components in the order of their definition and nesting (outermost first, innermost last)

[Source]

     # File lib/baretest/suite.rb, line 253
253:     def ancestry_components
254:       @parent ? @parent.ancestry_components|@components : @components
255:     end

All setups in the order of their definition and nesting (outermost first, innermost last)

[Source]

     # File lib/baretest/suite.rb, line 245
245:     def ancestry_setup
246:       @parent ? @parent.ancestry_setup.merge(@setup) { |k,v1,v2|
247:         v1+v2
248:       } : @setup
249:     end

All teardowns in the order of their nesting (innermost first, outermost last)

[Source]

     # File lib/baretest/suite.rb, line 258
258:     def ancestry_teardown
259:       ancestors.map { |suite| suite.teardown }.flatten
260:     end

Define an assertion. The block is supposed to return a trueish value (anything but nil or false).

See Assertion for more info.

[Source]

     # File lib/baretest/suite.rb, line 341
341:     def assert(description=nil, opts=nil, &block)
342:       assertion = Assertion.new(self, description, opts, &block)
343:       if match = caller.first.match(/^(.*):(\d+)(?::.+)?$/) then
344:         file, line = match.captures
345:         file = File.expand_path(file)
346:         if File.exist?(file) then
347:           assertion.file = file
348:           assertion.line = line.to_i
349:         end
350:       end
351:       @assertions << assertion
352:     end

Returns the number of possible setup variations. See each_component_variant

[Source]

     # File lib/baretest/suite.rb, line 300
300:     def component_variant_count
301:       ancestry_setup.values_at(*ancestry_components).inject(1) { |r,f| r*f.size }
302:     end

Yields all possible permutations of setup components.

[Source]

     # File lib/baretest/suite.rb, line 305
305:     def each_component_variant
306:       setups     = ancestry_setup
307:       components = ancestry_components
308:       base       = setups[nil]
309: 
310:       if components.empty?
311:         yield(base)
312:       else
313:         setup_in_order = setups.values_at(*components)
314:         maximums       = setup_in_order.map { |i| i.size }
315:         iterations     = maximums.inject { |r,f| r*f } || 0
316: 
317:         iterations.times do |i|
318:           process = maximums.map { |e| i,e=i.divmod(e); e }
319:           yield base+setup_in_order.zip(process).map { |variants, current|
320:             variants[current]
321:           }
322:         end
323:       end
324: 
325:       self
326:     end

Return only the first of all possible setup variation permutations.

[Source]

     # File lib/baretest/suite.rb, line 329
329:     def first_component_variant
330:       setups, *comps = ancestry_setup.values_at(nil, *ancestry_components)
331:       setups = setups+comps.map { |comp| comp.first }
332:       yield(setups) if block_given?
333: 
334:       setups
335:     end
guard(description=nil, opts=nil, &block)

Alias for assert

An ID, usable for persistence

[Source]

     # File lib/baretest/suite.rb, line 121
121:     def id
122:       @id ||= ancestors.map { |suite| suite.description }.join("\f")
123:     end

The failure/error/skipping/pending reason. Returns nil if there‘s no reason, a string otherwise Options:

:default:Reason to return if no reason is present
:separator:String used to separate multiple reasons
:indent:A String, the indentation to use. Prefixes every line.
:first_indent:A String, used to indent the first line only (replaces indent).

[Source]

     # File lib/baretest/suite.rb, line 185
185:     def reason(opt=nil)
186:       if opt then
187:         default, separator, indent, first_indent = 
188:           *opt.values_at(:default, :separator, :indent, :first_indent)
189:         reason = @reason
190:         reason = Array(default) if reason.empty? && default
191:         return nil if reason.empty?
192:         reason = reason.join(separator || "\n")
193:         reason = reason.gsub(/^/, indent) if indent
194:         reason = reason.gsub(/^#{Regexp.escape(indent)}/, first_indent) if first_indent
195:         reason
196:       else
197:         @reason.empty? ? nil : @reason.join("\n")
198:       end
199:     end

Instruct this suite to require the given files. The suite is skipped if a file can‘t be loaded.

[Source]

     # File lib/baretest/suite.rb, line 151
151:     def requires(*paths)
152:       paths.each do |file|
153:         begin
154:           require file
155:         rescue LoadError => e
156:           skip("Missing source file: #{file} (#{e})")
157:         end
158:       end
159:     end

Define a setup block for this suite. The block will be ran before every assertion once, even for nested suites.

[Source]

     # File lib/baretest/suite.rb, line 264
264:     def setup(component=nil, multiplexed=nil, &block)
265:       if component.nil? && block then
266:         @setup[nil] << ::BareTest::Setup.new(nil, nil, nil, block)
267:       elsif block then
268:         @components << component unless @setup.has_key?(component)
269:         @setup[component] ||= []
270: 
271:         case multiplexed
272:           when nil, String
273:             @setup[component] << ::BareTest::Setup.new(component, multiplexed, nil, block)
274:           when Array
275:             multiplexed.each do |substitute|
276:               @setup[component] << BareTest::Setup.new(component, substitute.to_s, substitute, block)
277:             end
278:           when Hash
279:             multiplexed.each do |substitute, value|
280:               @setup[component] << BareTest::Setup.new(component, substitute, value, block)
281:             end
282:           else
283:             raise TypeError, "multiplexed must be an instance of NilClass, String, Array or Hash, but #{multiplexed.class} given."
284:         end
285:       elsif component || multiplexed
286:         raise ArgumentError, "With component or multiplexed given, a block must be provided too."
287:       end
288: 
289:       @setup
290:     end

Marks this suite as manually skipped.

[Source]

     # File lib/baretest/suite.rb, line 167
167:     def skip(reason=nil)
168:       @skipped  = true
169:       @reason  |= reason ? Array(reason) : ['Manually skipped']
170:       true
171:     end

Returns whether this assertion has been marked as manually skipped.

[Source]

     # File lib/baretest/suite.rb, line 174
174:     def skipped?
175:       @skipped
176:     end

Define a nested suite.

Nested suites inherit setup & teardown methods. Also if an outer suite is skipped, all inner suites are skipped too.

See Suite::new - all arguments are passed to it verbatim, and self is added as parent.

[Source]

     # File lib/baretest/suite.rb, line 208
208:     def suite(description=nil, *args, &block)
209:       suite          = self.class.new(description, self, *args, &block)
210:       existing_suite = @suites.assoc(description)
211:       if existing_suite then
212:         existing_suite.last.update(suite)
213:       else
214:         @suites << [description, suite]
215:       end
216:       suite
217:     end

Returns whether this suite has all the passed tags

[Source]

     # File lib/baretest/suite.rb, line 162
162:     def tagged?(tags)
163:       (@tags-tags).empty?
164:     end

Define a teardown block for this suite. The block will be ran after every assertion once, even for nested suites.

[Source]

     # File lib/baretest/suite.rb, line 294
294:     def teardown(&block)
295:       block ? @teardown << block : @teardown
296:     end

Performs a recursive merge with the given suite.

Used to merge suites with the same description.

[Source]

     # File lib/baretest/suite.rb, line 222
222:     def update(with_suite)
223:       assertions, setup, teardown, provides, depends_on, skipped, reason, suites =
224:         *with_suite.merge_attributes
225:       @assertions.concat(assertions)
226:       @setup.update(setup) do |k,v1,v2| v1+v2 end
227:       @teardown.concat(teardown)
228:       @provides   |= provides
229:       @depends_on |= depends_on
230:       @skipped   ||= skipped
231:       @reason.concat(reason)
232:       suites.each { |description, suite|
233:         if append_to = @suites.assoc(description) then
234:           append_to.last.update(suite)
235:         else
236:           @suites << [description, suite]
237:         end
238:       }
239: 
240:       self
241:     end

Instruct this suite to use the given components. The suite is skipped if a component is not available.

[Source]

     # File lib/baretest/suite.rb, line 127
127:     def use(*components)
128:       components.each do |name|
129:         component = BareTest.component(name)
130:         if component then
131:           instance_eval(&component)
132:         else
133:           skip("Missing component: #{name.inspect}")
134:         end
135:       end
136:     end

Protected Instance methods

All attributes that are required when merging two suites

[Source]

     # File lib/baretest/suite.rb, line 365
365:     def merge_attributes
366:       return @assertions,
367:              @setup,
368:              @teardown,
369:              @provides,
370:              @depends_on,
371:              @skipped,
372:              @reason,
373:              @suites
374:     end

[Validate]