Module: Dfect

Defined in:
lib/dfect.rb,
lib/dfect/mini.rb,
lib/dfect/spec.rb,
lib/dfect/unit.rb,
lib/dfect/inochi.rb

Constant Summary

D = Allows before and after hooks to be specified via the following method syntax when this module is mixed-in:.
self
INSTDIR =
File.expand_path('../../..', __FILE__)

Class Attribute Summary

Class Method Summary

Instance Method Summary

Class Attribute Details

+ (Object) options

Hash of choices that affect how Dfect operates.

:debug
Launch an interactive debugger during assertion failures so the user can investigate them.

The default value is $DEBUG.

:quiet
Do not print the report after executing all tests.

The default value is false.



93
94
95
# File 'lib/dfect.rb', line 93

def options
  @options
end

+ (Object) report (readonly)

Hash of test results, assembled by Dfect.run.

:trace
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.
:code
Source code surrounding the point of failure.
:vars
Local variables visible at the point of failure.
:call
Stack trace leading to the point of failure.
:stats
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.


75
76
77
# File 'lib/dfect.rb', line 75

def report
  @report
end

Class Method Details

+ (Object) <(&block)

Examples:

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

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

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



182
183
184
185
186
187
188
189
190
# File 'lib/dfect.rb', line 182

def <(*args, &block)
  if args.empty?
    raise ArgumentError, 'block must be given' unless block
    @suite.before_each << block
  else
    # the < method is being used as a check for inheritance
    super
  end
end

+ (Object) <<(&block)

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)


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

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

+ (Object) >(&block)

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)


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

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

+ (Object) >>(&block)

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)


238
239
240
241
# File 'lib/dfect.rb', line 238

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

+ (Object) C(symbol, message = nil, &block)

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 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.


474
475
476
# File 'lib/dfect.rb', line 474

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

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

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 report if this assertion fails.

Returns:

  • nil, always.


500
501
502
# File 'lib/dfect.rb', line 500

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

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

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)


522
523
524
# File 'lib/dfect.rb', line 522

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

+ (Object) D(*description, &block)

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:

  • (Object, Array<Object>) description — A brief title or a series of objects that describe the test being defined.


127
128
129
# File 'lib/dfect.rb', line 127

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

+ (Object) D!(*description, &block)

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:

  • (Object, Array<Object>) description — A brief title or a series of objects that describe the test being defined.


164
165
166
# File 'lib/dfect.rb', line 164

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

+ (Object) E(*kinds_then_message, &block)

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 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.


381
382
383
# File 'lib/dfect.rb', line 381

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

+ (Object) E!(*kinds_then_message, &block)

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 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.


408
409
410
# File 'lib/dfect.rb', line 408

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

+ (Boolean) E?(*kinds_then_message, &block)

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)


442
443
444
# File 'lib/dfect.rb', line 442

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

+ (Boolean) F?(message = nil, &block)

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)


340
341
342
# File 'lib/dfect.rb', line 340

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

+ (Object) info

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



680
681
682
# File 'lib/dfect.rb', line 680

def info
  @trace.last
end

+ (Object) inspect



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

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

+ (Object) L(*messages)

Adds the given messages to the report inside the section of the currently running test.

You can think of “L” as “to log something”.

Examples:

single message given

  L "establishing connection..."

multiple messages given

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

Parameters:

  • messages — Objects to be added to the report.


544
545
546
# File 'lib/dfect.rb', line 544

def L *messages
  @trace.concat messages
end

+ (Object) run(continue = true)

Executes all tests defined thus far and stores the results in Dfect.report.

Parameters:

  • (Boolean) continue (defaults to: true) — If true, results from previous executions will not be cleared.


641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
# File 'lib/dfect.rb', line 641

def run continue = true
  # clear previous results
  unless continue
    @stats.clear
    @trace.clear
    @tests.clear
  end

  # make new results
  start = Time.now
  catch(:stop_dfect_execution) { execute }
  finish = Time.now
  @stats[:time] = finish - start

  # print new 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
end

+ (Object) S(identifier, &block)

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 Dfect 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:

  • (Symbol, Object) identifier — An object that identifies shared code. This must be common knowledge to all parties that want to partake in the sharing.


577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
# File 'lib/dfect.rb', line 577

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 Dfect 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 }
      test.sandbox.instance_eval(&block)
    end

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

+ (Object) S!(identifier, &block)

Shares the given code block under the given identifier and then immediately injects that code block into the closest insulated Dfect 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:

  • (Symbol, Object) identifier — An object that identifies shared code. This must be common knowledge to all parties that want to partake in the sharing.


620
621
622
623
624
# File 'lib/dfect.rb', line 620

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

+ (Boolean) S?(identifier)

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

Returns:

  • (Boolean)


629
630
631
# File 'lib/dfect.rb', line 629

def S? identifier
  @share.key? identifier
end

+ (Object) stop

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



672
673
674
# File 'lib/dfect.rb', line 672

def stop
  throw :stop_dfect_execution
end

+ (Object) T(condition = nil, message = nil, &block) 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 report if this assertion fails.


268
269
270
# File 'lib/dfect.rb', line 268

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

+ (Object) T!(condition = nil, message = nil, &block) 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 report if this assertion fails.


291
292
293
# File 'lib/dfect.rb', line 291

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

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

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)


316
317
318
# File 'lib/dfect.rb', line 316

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

Instance Method Details

- (Object) after(what, &block)



21
22
23
24
25
26
27
28
29
30
# File 'lib/dfect/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

- (Object) before(what, &block)



10
11
12
13
14
15
16
17
18
19
# File 'lib/dfect/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