Module: Dfect

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

Defined Under Namespace

Classes: Suite

Constant Summary collapse

D =

Allows 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
Describe =

for hooks

D
PROJECT =

Official name of this project.

"Dfect"
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/dfect/"
VERSION =

Number of this release of this project.

"2.2.0"
RELDATE =

Date of this release of this project.

"2010-04-28"
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" ],
}

Class Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Class Attribute Details

.optionsObject

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.



88
89
90
# File 'lib/dfect.rb', line 88

def options
  @options
end

.reportObject (readonly)

Hash of test results, assembled by 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.



70
71
72
# File 'lib/dfect.rb', line 70

def report
  @report
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


177
178
179
180
181
182
183
184
185
# File 'lib/dfect.rb', line 177

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

.<<(&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)


216
217
218
219
# File 'lib/dfect.rb', line 216

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)


199
200
201
202
# File 'lib/dfect.rb', line 199

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)


233
234
235
236
# File 'lib/dfect.rb', line 233

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


469
470
471
# File 'lib/dfect.rb', line 469

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


495
496
497
# File 'lib/dfect.rb', line 495

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


517
518
519
# File 'lib/dfect.rb', line 517

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


122
123
124
# File 'lib/dfect.rb', line 122

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


159
160
161
# File 'lib/dfect.rb', line 159

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


376
377
378
# File 'lib/dfect.rb', line 376

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


403
404
405
# File 'lib/dfect.rb', line 403

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


437
438
439
# File 'lib/dfect.rb', line 437

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


335
336
337
# File 'lib/dfect.rb', line 335

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

.infoObject

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



675
676
677
# File 'lib/dfect.rb', line 675

def info
  @trace.last
end

.inspectObject

Description of this release of this project.



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

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

.L(*messages) ⇒ Object

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']]


539
540
541
# File 'lib/dfect.rb', line 539

def L *messages
  @trace.concat messages
end

.run(continue = true) ⇒ Object

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



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
661
# File 'lib/dfect.rb', line 636

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

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


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

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

.S!(identifier, &block) ⇒ Object

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


615
616
617
618
619
# File 'lib/dfect.rb', line 615

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.



624
625
626
# File 'lib/dfect.rb', line 624

def S? identifier
  @share.key? identifier
end

.stopObject

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



667
668
669
# File 'lib/dfect.rb', line 667

def stop
  throw :stop_dfect_execution
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


263
264
265
# File 'lib/dfect.rb', line 263

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


286
287
288
# File 'lib/dfect.rb', line 286

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


311
312
313
# File 'lib/dfect.rb', line 311

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

#before(what, &block) ⇒ Object



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