thumblemonks-protest 0.0.3 → 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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