Module: DIFECTS

Extended by:
DIFECTS
Included in:
DIFECTS
Defined in:
lib/difects.rb,
lib/difects/long.rb,
lib/difects/mini.rb,
lib/difects/spec.rb,
lib/difects/unit.rb,
lib/difects/inochi.rb

Defined Under Namespace

Modules: FailureDetails Classes: BINDINGS=Hash.new{|h,k|h[k]={}}, Suite

Constant Summary collapse

Describe =

for hooks

D
PROJECT =

Official name of this project.

'DIFECTS'
TAGLINE =

Short single-line description of this project.

'Assertion testing library for Ruby'
WEBSITE =

Address of this project’s official home page.

'http://snk.tuxfamily.org/lib/difects/'
VERSION =

Number of this release of this project.

'3.0.1'
RELDATE =

Date of this release of this project.

'2010-07-25'
INSTDIR =

Location of this release of this project.

File.expand_path('../../..', __FILE__)
RUNTIME =

RubyGems required by this project during runtime.

Examples:


RUNTIME = {
  # this project needs exactly version 1.2.3 of the "an_example" gem
  "an_example" => [ "1.2.3" ],

  # this project needs at least version 1.2 (but not
  # version 1.2.4 or newer) of the "another_example" gem
  "another_example" => [ ">= 1.2" , "< 1.2.4" ],

  # this project needs any version of the "yet_another_example" gem
  "yet_another_example" => [],
}
{}
DEVTIME =

RubyGems required by this project during development.

Examples:


DEVTIME = {
  # this project needs exactly version 1.2.3 of the "an_example" gem
  "an_example" => [ "1.2.3" ],

  # this project needs at least version 1.2 (but not
  # version 1.2.4 or newer) of the "another_example" gem
  "another_example" => [ ">= 1.2" , "< 1.2.4" ],

  # this project needs any version of the "yet_another_example" gem
  "yet_another_example" => [],
}
{
  'inochi' => [ '>= 3.0.0', '< 4' ],
}
D =

allow before and after hooks to be specified via the following method syntax when this module is mixed-in:

D .<< { puts "before all nested tests" }
D .<  { puts "before each nested test" }
D .>  { puts "after  each nested test" }
D .>> { puts "after  all nested tests" }
self

Class Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Class Attribute Details

.debug=(value) ⇒ Object

Launch an interactive debugger during assertion failures so the user can investigate them?

The default value is $DEBUG.



31
32
33
# File 'lib/difects.rb', line 31

def debug=(value)
  @debug = value
end

.statsObject (readonly)

Hash of counts of major events in test execution:

:time

Number of seconds elapsed for test execution.

:pass

Number of assertions that held true.

:fail

Number of assertions that did not hold true.

:error

Number of exceptions that were not rescued.



48
49
50
# File 'lib/difects.rb', line 48

def stats
  @stats
end

.traceObject (readonly)

Hierarchical trace of all tests executed, where each test is represented by its description, is mapped to an Array of nested tests, and may contain zero or more assertion failures.

Assertion failures are represented as a Hash:

:fail

Description of the assertion failure.

:call

Stack trace leading to the point of failure.

:code

Source code surrounding the point of failure.

:bind

Location where local variables in ‘:vars` were extracted.

:vars

Local variables visible at the point of failure.



72
73
74
# File 'lib/difects.rb', line 72

def trace
  @trace
end

Class Method Details

.<(&block) ⇒ Object

Registers the given block to be executed before each nested test inside this test.

Examples:


D .< { puts "before each nested test" }

D .< do
  puts "before each nested test"
end


161
162
163
164
165
166
167
168
169
170
171
172
173
# File 'lib/difects.rb', line 161

def <(klass = nil, &block)
  if klass
    # this method is being used as a check for inheritance
    #
    # NOTE: we cannot call super() here because this module
    #       extends itself, thereby causing an infinite loop!
    #
    ancestors.include? klass
  else
    raise ArgumentError, 'block must be given' unless block
    @suite.before_each << block
  end
end

.<<(&block) ⇒ Object

Registers the given block to be executed before all nested tests inside this test.

Examples:


D .<< { puts "before all nested tests" }

D .<< do
  puts "before all nested tests"
end

Raises:

  • (ArgumentError)


204
205
206
207
# File 'lib/difects.rb', line 204

def << &block
  raise ArgumentError, 'block must be given' unless block
  @suite.before_all << block
end

.>(&block) ⇒ Object

Registers the given block to be executed after each nested test inside this test.

Examples:


D .> { puts "after each nested test" }

D .> do
  puts "after each nested test"
end

Raises:

  • (ArgumentError)


187
188
189
190
# File 'lib/difects.rb', line 187

def > &block
  raise ArgumentError, 'block must be given' unless block
  @suite.after_each << block
end

.>>(&block) ⇒ Object

Registers the given block to be executed after all nested tests inside this test.

Examples:


D .>> { puts "after all nested tests" }

D .>> do
  puts "after all nested tests"
end

Raises:

  • (ArgumentError)


221
222
223
224
# File 'lib/difects.rb', line 221

def >> &block
  raise ArgumentError, 'block must be given' unless block
  @suite.after_all << block
end

.C(symbol, message = nil, &block) ⇒ Object

Asserts that the given symbol is thrown when the given block is executed.

Examples:

no message given


C(:foo) { throw :foo, 123 } # passes, => 123
C(:foo) { throw :bar, 456 } # fails,  => 456
C(:foo) { }                 # fails,  => nil

message is given


C(:foo, ":foo must be thrown") { throw :bar, 789 } # fails, => nil

Parameters:

  • symbol (Symbol)

    Symbol that must be thrown by the given block.

  • message (defaults to: nil)

    Optional message to show in the test execution report if this assertion fails.

Returns:

  • If a value is thrown along with the expected symbol, then that value is returned.

    Otherwise, nil is returned.



458
459
460
# File 'lib/difects.rb', line 458

def C symbol, message = nil, &block
  assert_catch :assert, symbol, message, &block
end

.C!(symbol, message = nil, &block) ⇒ Object

Asserts that the given symbol is not thrown when the given block is executed.

Examples:

no message given


C!(:foo) { throw :foo, 123 } # fails,  => nil
C!(:foo) { throw :bar, 456 } # passes, => nil
C!(:foo) { }                 # passes, => nil

message is given


C!(:foo, ":foo must be thrown") { throw :bar, 789 } # passes, => nil

Parameters:

  • symbol (Symbol)

    Symbol that must not be thrown by the given block.

  • message (defaults to: nil)

    Optional message to show in the test execution report if this assertion fails.

Returns:

  • nil, always.



484
485
486
# File 'lib/difects.rb', line 484

def C! symbol, message = nil, &block
  assert_catch :negate, symbol, message, &block
end

.C?(symbol, message = nil, &block) ⇒ Boolean

Returns true if the given symbol is thrown when the given block is executed. Otherwise, returns false.

Examples:

no message given


C?(:foo) { throw :foo, 123 } # => true
C?(:foo) { throw :bar, 456 } # => false
C?(:foo) { }                 # => false

message is given


C?(:foo, ":foo must be thrown") { throw :bar, 789 } # => false

Parameters:

  • symbol (Symbol)

    Symbol that must be thrown by the given block.

  • message (defaults to: nil)

    This parameter is optional and completely ignored.

Returns:

  • (Boolean)


506
507
508
# File 'lib/difects.rb', line 506

def C? symbol, message = nil, &block
  assert_catch :sample, symbol, message, &block
end

.D(*description, &block) ⇒ Object

Defines a new test composed of the given description and the given block to execute.

This test may contain nested tests.

Tests at the outer-most level are automatically insulated from the top-level Ruby environment.

Examples:


D "a new array" do
  D .< { @array = [] }

  D "must be empty" do
    T { @array.empty? }
  end

  D "when populated" do
    D .< { @array.push 55 }

    D "must not be empty" do
      F { @array.empty? }
    end
  end
end

Parameters:

  • description (Object, Array<Object>)

    A brief title or a series of objects that describe the test being defined.



106
107
108
# File 'lib/difects.rb', line 106

def D *description, &block
  create_test @tests.empty?, *description, &block
end

.D!(*description, &block) ⇒ Object

Defines a new test that is explicitly insulated from the tests that contain it and also from the top-level Ruby environment.

This test may contain nested tests.

Examples:


D "a root-level test" do
  @outside = 1
  T { defined? @outside }
  T { @outside == 1 }

  D "an inner, non-insulated test" do
    T { defined? @outside }
    T { @outside == 1 }
  end

  D! "an inner, insulated test" do
    F { defined? @outside }
    F { @outside == 1 }

    @inside = 2
    T { defined? @inside }
    T { @inside == 2 }
  end

  F { defined? @inside }
  F { @inside == 2 }
end

Parameters:

  • description (Object, Array<Object>)

    A brief title or a series of objects that describe the test being defined.



143
144
145
# File 'lib/difects.rb', line 143

def D! *description, &block
  create_test true, *description, &block
end

.E(*kinds_then_message, &block) ⇒ Object

Asserts that one of the given kinds of exceptions is raised when the given block is executed.

Examples:

no exceptions given


E { }       # fails
E { raise } # passes

single exception given


E(ArgumentError) { raise ArgumentError }
E(ArgumentError, "argument must be invalid") { raise ArgumentError }

multiple exceptions given


E(SyntaxError, NameError) { eval "..." }
E(SyntaxError, NameError, "string must compile") { eval "..." }

Parameters:

  • kinds_then_message (...)

    Exception classes that must be raised by the given block, optionally followed by a message to show in the test execution report if this assertion fails.

    If no exception classes are given, then StandardError is assumed (similar to how a plain ‘rescue’ statement without any arguments catches StandardError).

Returns:

  • If the block raises an exception, then that exception is returned.

    Otherwise, nil is returned.



365
366
367
# File 'lib/difects.rb', line 365

def E *kinds_then_message, &block
  assert_raise :assert, *kinds_then_message, &block
end

.E!(*kinds_then_message, &block) ⇒ Object

Asserts that one of the given kinds of exceptions is not raised when the given block is executed.

Examples:

no exceptions given


E! { }       # passes
E! { raise } # fails

single exception given


E!(ArgumentError) { raise ArgumentError } # fails
E!(ArgumentError, "argument must be invalid") { raise ArgumentError }

multiple exceptions given


E!(SyntaxError, NameError) { eval "..." }
E!(SyntaxError, NameError, "string must compile") { eval "..." }

Parameters:

  • kinds_then_message (...)

    Exception classes that must be raised by the given block, optionally followed by a message to show in the test execution report if this assertion fails.

    If no exception classes are given, then StandardError is assumed (similar to how a plain ‘rescue’ statement without any arguments catches StandardError).

Returns:

  • If the block raises an exception, then that exception is returned.

    Otherwise, nil is returned.



392
393
394
# File 'lib/difects.rb', line 392

def E! *kinds_then_message, &block
  assert_raise :negate, *kinds_then_message, &block
end

.E?(*kinds_then_message, &block) ⇒ Boolean

Returns true if one of the given kinds of exceptions is raised when the given block is executed. Otherwise, returns false.

Examples:

no exceptions given


E? { }       # => false
E? { raise } # => true

single exception given


E?(ArgumentError) { raise ArgumentError } # => true

multiple exceptions given


E?(SyntaxError, NameError) { eval "..." } # => true
E!(SyntaxError, NameError, "string must compile") { eval "..." }

Parameters:

  • kinds_then_message (...)

    Exception classes that must be raised by the given block, optionally followed by a message that is completely ignored.

    If no exception classes are given, then StandardError is assumed (similar to how a plain ‘rescue’ statement without any arguments catches StandardError).

Returns:

  • (Boolean)


426
427
428
# File 'lib/difects.rb', line 426

def E? *kinds_then_message, &block
  assert_raise :sample, *kinds_then_message, &block
end

.F?(message = nil, &block) ⇒ Boolean

Returns true if the result of the given block is either nil or false. Otherwise, returns false.

Examples:

no message given


F? { true }  # => false
F? { false } # => true
F? { nil }   # => true

message is given


F?( "computers do not doublethink" ) { 2 + 2 == 5 } # => true

Parameters:

  • message (defaults to: nil)

    This parameter is optional and completely ignored.

Returns:

  • (Boolean)


323
324
325
# File 'lib/difects.rb', line 323

def F? message = nil, &block
  not T? message, &block
end

.I(*messages) ⇒ Object

Adds the given messages to the test execution report beneath the currently running test.

You can think of “I” as to “inform” the user.

Examples:

single message given


I "establishing connection..."

multiple messages given


I "beginning calculation...", Math::PI, [1, 2, 3, ['a', 'b', 'c']]

Parameters:

  • messages

    Objects to be added to the test execution report.



528
529
530
# File 'lib/difects.rb', line 528

def I *messages
  @trace.concat messages
end

.I!Object

Starts an interactive debugging session at the location where this method was called.

You can think of “I!” as to “investigate” the program.



538
539
540
# File 'lib/difects.rb', line 538

def I!
  debug
end

.infoObject

Returns the details of the failure that is currently being debugged by the user.



682
683
684
# File 'lib/difects.rb', line 682

def info
  @trace.last
end

.inspectObject

Description of this release of this project.



31
32
33
# File 'lib/difects/inochi.rb', line 31

def self.inspect
  "#{PROJECT} #{VERSION} (#{RELDATE})"
end

.resetObject

Clear all test results that were recorded thus far.



673
674
675
676
# File 'lib/difects.rb', line 673

def reset
  @stats.clear
  @trace.clear
end

.S(identifier, &block) ⇒ Object

Mechanism for sharing code between tests.

If a block is given, it is shared under the given identifier. Otherwise, the code block that was previously shared under the given identifier is injected into the closest insulated DIFECTS test that contains the call to this method.

Examples:


S :knowledge do
  #...
end

D "some test" do
  S :knowledge
end

D "another test" do
  S :knowledge
end

Parameters:

  • identifier (Symbol, Object)

    An object that identifies shared code. This must be common knowledge to all parties that want to partake in the sharing.



571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
# File 'lib/difects.rb', line 571

def S identifier, &block
  if block_given?
    if already_shared = @share[identifier]
      raise ArgumentError, "A code block #{already_shared.inspect} has "\
        "already been shared under the identifier #{identifier.inspect}."
    end

    @share[identifier] = block

  elsif block = @share[identifier]
    if @tests.empty?
      raise "Cannot inject code block #{block.inspect} shared under "\
        "identifier #{identifier.inspect} outside of a DIFECTS test."
    else
      # find the closest insulated parent test; this should always
      # succeed because root-level tests are insulated by default
      test = @tests.reverse.find {|t| t.sandbox } or raise IndexError
      test.sandbox.instance_eval(&block)
    end

  else
    raise ArgumentError, "No code block is shared under identifier "\
      "#{identifier.inspect}."
  end
end

.S!(identifier, &block) ⇒ Object

Shares the given code block under the given identifier and then immediately injects that code block into the closest insulated DIFECTS test that contains the call to this method.

Examples:


D "some test" do
  S! :knowledge do
    #...
  end
end

D "another test" do
  S :knowledge
end

Parameters:

  • identifier (Symbol, Object)

    An object that identifies shared code. This must be common knowledge to all parties that want to partake in the sharing.



617
618
619
620
621
# File 'lib/difects.rb', line 617

def S! identifier, &block
  raise 'block must be given' unless block_given?
  S identifier, &block
  S identifier
end

.S?(identifier) ⇒ Boolean

Checks whether any code has been shared under the given identifier.

Returns:

  • (Boolean)


626
627
628
# File 'lib/difects.rb', line 626

def S? identifier
  @share.key? identifier
end

.startObject

Executes all tests defined thus far and stores the results in trace and stats.



634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
# File 'lib/difects.rb', line 634

def start
  # execute the tests
  start_time = Time.now
  catch :DIFECTS_STOP do
    BINDINGS.track do
      execute
    end
  end
  @stats[:time] = Time.now - start_time

  # print test results
  unless @stats.key? :fail or @stats.key? :error
    #
    # show execution trace only if all tests passed.
    # otherwise, we will be repeating already printed
    # failure details and obstructing the developer!
    #
    display @trace
  end

  display @stats

ensure
  @tests.clear
  @share.clear
  @files.clear
end

.stopObject

Stops the execution of the start method or raises an exception if that method is not currently executing.



666
667
668
# File 'lib/difects.rb', line 666

def stop
  throw :DIFECTS_STOP
end

.T(condition = nil, message = nil, &block) ⇒ Object Also known as: F!

Asserts that the given condition or the result of the given block is neither nil nor false and returns that result.

Examples:

no message given


T { true }  # passes
T { false } # fails
T { nil }   # fails

message is given


T("computers do not doublethink") { 2 + 2 != 5 } # passes

Parameters:

  • condition (defaults to: nil)

    The condition to be asserted. A block may be given in place of this parameter.

  • message (defaults to: nil)

    Optional message to show in the test execution report if this assertion fails.



251
252
253
# File 'lib/difects.rb', line 251

def T condition = nil, message = nil, &block
  assert_yield :assert, condition, message, &block
end

.T!(condition = nil, message = nil, &block) ⇒ Object Also known as: F

Asserts that the given condition or the result of the given block is either nil or false and returns that result.

Examples:

no message given


T! { true }  # fails
T! { false } # passes
T! { nil }   # passes

message is given


T!("computers do not doublethink") { 2 + 2 == 5 } # passes

Parameters:

  • condition (defaults to: nil)

    The condition to be asserted. A block may be given in place of this parameter.

  • message (defaults to: nil)

    Optional message to show in the test execution report if this assertion fails.



274
275
276
# File 'lib/difects.rb', line 274

def T! condition = nil, message = nil, &block
  assert_yield :negate, condition, message, &block
end

.T?(condition = nil, message = nil, &block) ⇒ Boolean

Returns true if the given condition or the result of the given block is neither nil nor false. Otherwise, returns false.

Examples:

no message given


T? { true }  # => true
T? { false } # => false
T? { nil }   # => false

message is given


T?("computers do not doublethink") { 2 + 2 != 5 } # => true

Parameters:

  • message (defaults to: nil)

    This parameter is optional and completely ignored.

  • condition (defaults to: nil)

    The condition to be asserted. A block may be given in place of this parameter.

Returns:

  • (Boolean)


299
300
301
# File 'lib/difects.rb', line 299

def T? condition = nil, message = nil, &block
  assert_yield :sample, condition, message, &block
end

Instance Method Details

#after(what, &block) ⇒ Object



21
22
23
24
25
26
27
28
29
30
# File 'lib/difects/spec.rb', line 21

def after what, &block
  meth =
    case what
    when :each then :>
    when :all  then :>>
    else raise ArgumentError, what
    end

  send meth, &block
end

#before(what, &block) ⇒ Object



10
11
12
13
14
15
16
17
18
19
# File 'lib/difects/spec.rb', line 10

def before what, &block
  meth =
    case what
    when :each then :<
    when :all  then :<<
    else raise ArgumentError, what
    end

  send meth, &block
end