thumblemonks-protest 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
data/lib/protest.rb CHANGED
@@ -20,18 +20,40 @@ module Protest
20
20
  def self.run(writer=nil)
21
21
  writer ||= STDOUT
22
22
  start = Time.now
23
- failures = @contexts.map { |context| context.run(writer) }.flatten
23
+ failures = @contexts.map { |context| context.run(writer) }.flatten.compact
24
24
  running_time = Time.now - start
25
25
 
26
26
  writer.puts "\n\n"
27
- failures.each_with_index { |failure, idx|
28
- message = ["##{idx + 1} - #{failure.to_s}"]
29
- message += failure.backtrace
30
- writer.puts message.join("\n") + "\n\n"
31
- } unless failures.empty?
27
+ counter = 0
28
+ @contexts.each do |context|
29
+ context.failures.each do |failure|
30
+ counter += 1
31
+ message = ["##{counter} - #{context} asserted #{failure}"]
32
+ message += failure.backtrace
33
+ writer.puts message.join("\n") + "\n\n"
34
+ end
35
+ end
32
36
  assertions = @contexts.inject(0) { |acc, context| acc + context.assertions.length }
33
37
  writer.puts "#{@contexts.length} contexts, #{assertions} assertions: #{"%0.6f" % running_time} seconds"
34
38
  end
39
+
40
+ #
41
+ # Failures
42
+
43
+ class Failure < Exception
44
+ def asserted(assertion)
45
+ @assertion = assertion
46
+ self
47
+ end
48
+
49
+ def to_s; "#{@assertion}: #{super}"; end
50
+ end
51
+ class Error < Failure
52
+ def initialize(message, e)
53
+ super(message)
54
+ set_backtrace(e.backtrace)
55
+ end
56
+ end
35
57
  end # Protest
36
58
 
37
59
  module Kernel
@@ -1,58 +1,34 @@
1
1
  module Protest
2
- class Failure < Exception; end
3
- class Error < Exception
4
- def initialize(message, e)
5
- super(message)
6
- set_backtrace(e.backtrace)
7
- end
8
- end
9
-
10
2
  class Assertion
11
3
  def initialize(description, &block)
12
4
  @description = description
13
- @evaluated_expectation = true
14
- @expects_raise = false
15
- expectation(true, &block)
5
+ assert_block do |scope|
6
+ actual = scope.instance_eval(&block)
7
+ actual || failure("expected to be true, not #{actual.inspect}")
8
+ end
16
9
  end
17
10
 
18
- def to_s
19
- "#{@description}: expected [#{@expectation}]"
20
- end
11
+ def to_s; @description; end
21
12
 
22
- def not(&block)
23
- @evaluated_expectation = false
24
- expectation(@expectation, &block)
13
+ def assert_block(&block)
14
+ @block = block if block_given?
15
+ self
25
16
  end
26
17
 
27
- def equals(expectation, &block)
28
- expectation(expectation, &block)
18
+ def run(binding_scope)
19
+ @block.call(binding_scope)
29
20
  end
30
21
 
31
- def raises(expectation, &block)
32
- @expects_raise = true
33
- expectation(expectation, &block)
34
- end
22
+ def failure(message) raise(Protest::Failure, message); end
23
+ end # Assertion
35
24
 
25
+ class Denial < Assertion
36
26
  def run(binding_scope)
37
- begin
38
- actual = binding_scope.instance_eval(&@block)
39
- rescue Exception => e
40
- errored("#{binding_scope} asserted #{self}, but errored with: #{e.to_s}", e) unless @expects_raise
41
- actual = e.class
42
- end
43
- assert(@expectation == actual, "#{binding_scope} asserted #{self}, but received [#{actual}] instead")
44
- end
45
- private
46
- def expectation(expectation, &block)
47
- @expectation = expectation
48
- @block = block if block_given?
49
- self
27
+ super
28
+ rescue Protest::Failure => e
29
+ true
30
+ else
31
+ failure("expected to fail, but did not")
50
32
  end
51
-
52
- def errored(message, e); raise Error.new(message, e); end
53
-
54
- def assert(evaluation, message)
55
- @evaluated_expectation == evaluation || raise(Failure, message)
56
- end
57
- end # Assertion
33
+ end
58
34
  end # Protest
@@ -1,16 +1,16 @@
1
1
  module Protest
2
2
  class Context
3
- attr_reader :assertions, :errors
3
+ attr_reader :assertions, :failures
4
4
  def initialize(description, parent=nil)
5
5
  @description = description
6
6
  @assertions = []
7
- @errors = []
7
+ @failures = []
8
8
  @parent = parent
9
9
  @setup = nil
10
10
  end
11
11
 
12
12
  def to_s
13
- [@parent.to_s, @description].join(' ').strip
13
+ @to_s ||= [@parent.to_s, @description].join(' ').strip
14
14
  end
15
15
 
16
16
  def context(description, &block)
@@ -22,9 +22,8 @@ module Protest
22
22
  self.bootstrap(self)
23
23
  end
24
24
 
25
- def asserts(description, &block)
26
- (assertions << Assertion.new(description, &block)).last
27
- end
25
+ def asserts(description, &block) new_assertion(Assertion, description, &block); end
26
+ def denies(description, &block) new_assertion(Denial, description, &block); end
28
27
 
29
28
  def run(writer)
30
29
  assertions.each do |assertion|
@@ -32,17 +31,20 @@ module Protest
32
31
  assertion.run(self)
33
32
  writer.print '.'
34
33
  rescue Protest::Failure => e
35
- writer.print 'F'; @errors << e
36
- rescue Protest::Error => e
37
- writer.print 'E'; @errors << e
34
+ writer.print 'F'; @failures << e.asserted(assertion)
35
+ rescue Exception => e
36
+ writer.print 'E'; @failures << Protest::Error.new("errored with #{e}", e).asserted(e)
38
37
  end
39
38
  end
40
- @errors
41
39
  end
42
40
 
43
41
  def bootstrap(binder)
44
42
  @parent.bootstrap(binder) if @parent
45
43
  binder.instance_eval(&@setup) if @setup
46
44
  end
45
+ private
46
+ def new_assertion(klass, description, &block)
47
+ (assertions << klass.new(description, &block)).last
48
+ end
47
49
  end # Context
48
50
  end # Protest
@@ -1,16 +1,36 @@
1
1
  module Protest
2
- module ContextMacros
3
- def denies(description, &block)
4
- asserts(description, &block).not
5
- end
6
- end # ContextMacros
7
-
8
2
  module AssertionMacros
3
+ def equals(expected, &block)
4
+ assert_block do |scope|
5
+ actual = scope.instance_eval(&block)
6
+ expected == actual || failure("expected #{expected.inspect}, not #{actual.inspect}")
7
+ end
8
+ end
9
+
9
10
  def nil(&block)
10
11
  equals(nil, &block)
11
12
  end
12
- end # ContextMacros
13
+
14
+ def raises(expected, &block)
15
+ assert_block do |scope|
16
+ begin
17
+ scope.instance_eval(&block)
18
+ rescue Exception => e
19
+ failure("should have raised #{expected}, not #{e.class}") unless expected == e.class
20
+ else
21
+ failure("should have raised #{expected}, but raised nothing")
22
+ end
23
+ end
24
+ end
25
+
26
+ def matches(expected, &block)
27
+ expected = %r[#{Regexp.escape(expected)}] if expected.kind_of?(String)
28
+ assert_block do |scope|
29
+ actual = scope.instance_eval(&block)
30
+ actual =~ expected || failure("expected #{expected.inspect}, not #{actual.inspect}")
31
+ end
32
+ end
33
+ end # AssertionMacros
13
34
  end # Protest
14
35
 
15
- Protest::Context.instance_eval { include Protest::ContextMacros }
16
36
  Protest::Assertion.instance_eval { include Protest::AssertionMacros }
data/protest.gemspec CHANGED
@@ -1,7 +1,7 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = "protest"
3
- s.version = "0.0.3"
4
- s.date = "2009-06-28"
3
+ s.version = "0.0.4"
4
+ s.date = "2009-06-29"
5
5
  s.summary = "An extremely fast, expressive, and context-driven unit-testing framework"
6
6
  s.email = %w[gus@gusg.us]
7
7
  s.homepage = "http://github.com/thumblemonks/protest"
@@ -1,31 +1,54 @@
1
1
  require 'protest'
2
2
 
3
- context "any assertion" do
4
- asserts("its description").equals("i will pass: expected [true]") do
3
+ fake_object = Object.new
4
+
5
+ context "basic assertion:" do
6
+ asserts("its description").equals("i will pass") do
5
7
  Protest::Assertion.new("i will pass").to_s
6
8
  end
7
- end # any assertion
8
9
 
9
- context "passing assertion" do
10
- asserts("true is expected") { Protest::Assertion.new("i will pass") { true }.run(Object.new) }
11
- asserts("false on denial") { Protest::Assertion.new("i will fail").not { false }.run(Object.new) }
12
- asserts("actual result is nil") { Protest::Assertion.new("i will fail").nil { nil }.run(Object.new) }
10
+ asserts("true is expected") { Protest::Assertion.new("i will pass") { true }.run(fake_object) }
11
+
12
+ asserts("a Failure if not true").raises(Protest::Failure) do
13
+ Protest::Assertion.new("i will pass") { false }.run(fake_object)
14
+ end
15
+
16
+ asserts("an Exception error is thrown").raises(Exception) do
17
+ Protest::Assertion.new("error") { raise Exception, "blah" }.run(fake_object)
18
+ end
19
+ end # basic assertion
13
20
 
14
- asserts("provided block was executed and returned true") do
15
- Protest::Assertion.new("i will pass").equals("foo bar") { "foo bar" }.run(Object.new)
21
+ context "equals assertion:" do
22
+ asserts("results equals expectation") do
23
+ Protest::Assertion.new("i will pass").equals("foo bar") { "foo bar" }.run(fake_object)
16
24
  end
17
25
 
18
- asserts("expectation does not equal actual result") do
19
- Protest::Assertion.new("i will fail").not.equals("foo") { "bar" }.run(Object.new)
26
+ asserts("a Failure if results don't equal eachother").raises(Protest::Failure) do
27
+ Protest::Assertion.new("failure").equals("foo") { "bar" }.run(fake_object)
20
28
  end
21
- end # passing assertion
29
+ end # equals assertion
22
30
 
23
- context "failing assertions:" do
24
- asserts("a Failure error is thrown").raises(Protest::Failure) do
25
- Protest::Assertion.new("failure") { false }.run(Object.new)
31
+ context "nil assertion:" do
32
+ asserts("actual result is nil") { Protest::Assertion.new("foo").nil { nil }.run(fake_object) }
33
+ asserts("a Failure if not nil").raises(Protest::Failure) do
34
+ Protest::Assertion.new("foo").nil { "a" }.run(fake_object)
35
+ end
36
+ end # nil assertion
37
+
38
+ context "matching assertion:" do
39
+ asserts("actual result matches expression").equals(0) do
40
+ Protest::Assertion.new("foo").matches(%r[.]) { "a" }.run(fake_object)
41
+ end
42
+ asserts("a Failure if not nil").raises(Protest::Failure) do
43
+ Protest::Assertion.new("foo").matches(%r[.]) { "" }.run(fake_object)
44
+ end
45
+ asserts("string matches string").equals(0) do
46
+ Protest::Assertion.new("foo").matches("a") { "a" }.run(fake_object)
26
47
  end
48
+ end # maching assertion
27
49
 
28
- asserts("an Error error is thrown").raises(Protest::Error) do
29
- Protest::Assertion.new("error") { raise Exception, "blah" }.run(Object.new)
50
+ context "a denial" do
51
+ asserts("that a passing assertion evaluates to false") do
52
+ Protest::Denial.new("foo") { false }.run(fake_object)
30
53
  end
31
- end # failing assertions
54
+ end # a denial
data/test/context_test.rb CHANGED
@@ -16,11 +16,11 @@ context "any context" do
16
16
  end
17
17
 
18
18
  asserts("that failures are captured").equals(1) do
19
- @context.errors.select{|e| e.kind_of?(Protest::Failure)}.length
19
+ @context.failures.select{|e| e.class == Protest::Failure}.length
20
20
  end
21
21
 
22
22
  asserts("that unexpected errors are captured").equals(1) do
23
- @context.errors.select{|e| e.kind_of?(Protest::Error)}.length
23
+ @context.failures.select{|e| e.class == Protest::Error}.length
24
24
  end
25
25
  end # that doesn't have passing tests
26
26
  end # any context
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: thumblemonks-protest
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Justin Knowlden
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-06-28 00:00:00 -07:00
12
+ date: 2009-06-29 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies: []
15
15