thumblemonks-protest 0.0.7 → 0.0.8

Sign up to get free protection for your applications and to get access to all the features.
data/README.markdown CHANGED
@@ -43,7 +43,7 @@ For example:
43
43
 
44
44
  Here, you should begin to notice that tests themselves return the actual value. You do not write assertions into the test. Assertions are "aspected" onto the test. If the test above did not return 'foo@bar.com' for `@user.email`, the assertion would have failed.
45
45
 
46
- The `equals` modifier works with any type of value, including nil's. However, if you wanted to test for nil explicitly, you could simple do this:
46
+ The `equals` modifier works with any type of value, including nil's. However, if you wanted to test for nil explicitly, you could simply do this:
47
47
 
48
48
  context "a new user" do
49
49
  setup { @user = User.new }
@@ -91,7 +91,7 @@ Sometimes, your test raises an exception that you actually expected.
91
91
 
92
92
  context "a new user" do
93
93
  setup { @user = User.new }
94
- asserts("with bad data") { @user.save! }.raises(ActiveRecord::RecordInvalid)
94
+ asserts("invalid data") { @user.save! }.raises(ActiveRecord::RecordInvalid)
95
95
  end
96
96
 
97
97
  #### Example: Kind Of
@@ -100,7 +100,7 @@ When you want to test that an expression returns an object of an expected type:
100
100
 
101
101
  context "a new user" do
102
102
  setup { @user = User.new }
103
- asserts("the balance") { @user.balance }.kind_of(Currency)
103
+ asserts("its balance") { @user.balance }.kind_of(Currency)
104
104
  end
105
105
 
106
106
  #### Example: Nested contexts
@@ -224,7 +224,7 @@ Make sure to check out the Protest + Sinatra testing macros in Chicago.
224
224
 
225
225
  ### With Rails
226
226
 
227
- It's doubtful that Protest works with Rails very easily as Protest completely replaces Test::Unit. I haven't tried it yet, but intend to with my next new Rails project. Porting would probably take some time unless you only have a few test cases.
227
+ It's doubtful that Protest works with Rails very easily as Protest completely replaces Test::Unit. I haven't tried it yet, but intend to with my next new Rails project. Porting would probably take some time unless you only have a few test cases. Porting is made somewhat easier if you're already using Shoulda; you can replace the `TestCase` definition with a `context` of the same name as the class under test I suppose.
228
228
 
229
229
  ## Extending Protest with Macros
230
230
 
@@ -281,13 +281,14 @@ Notice in the new macro we defined the use of the magical **actual** variable. `
281
281
 
282
282
  TONS OF STUFF
283
283
 
284
- 1. Documentation
284
+ 1. Documentation about the `topic` method
285
+ 1. Better documentation for everything
285
286
  1. Refactor reporting; some abstracting is needed for recording a result (for instance)
286
- 1. Need to know where in backtrace a test failed (line number, etc.)
287
+ 1. Need to know where in backtrace a test failed (line number, etc.); i.e. backtrace filtering for clarity
287
288
  1. More assertion macros: throws, etc.
288
289
  1. Aliases for context "with, without, when, ..."; add those words to test description
289
290
  1. Optimization and simplification (ex. flog is complaining print\_result\_stack)
290
- 1. Better error messages (maybe need to rename asserts to should for better readability)
291
+ 1. Better error messages?
291
292
  1. Perhaps: Multiple setup blocks in one context
292
293
  1. Perhaps: association macro chaining
293
- 1. Perhaps: Uhhhhh ... a teardown method (maybe :)
294
+ 1. Perhaps: Uhhhhh ... a teardown method (only maybe. not sold :)
data/Rakefile CHANGED
@@ -15,6 +15,11 @@ task :flog do
15
15
  puts %x[find ./lib -name *.rb | xargs flog]
16
16
  end
17
17
 
18
+ desc "Run Flay against library (except tests)"
19
+ task :flay do
20
+ puts %x[find ./lib -name *.rb | xargs flay]
21
+ end
22
+
18
23
  desc "Run Roodi against library (except tests)"
19
24
  task :roodi do
20
25
  puts %x[find ./lib -name *.rb | xargs roodi]
data/lib/protest.rb CHANGED
@@ -29,9 +29,11 @@ module Protest
29
29
 
30
30
  #
31
31
  # Reporter
32
-
32
+
33
33
  def self.reporter; @reporter ||= TextReport.new; end
34
34
  def self.reporter=(report); @reporter = report; end
35
+ def self.silently!; @silently = true; end
36
+ def self.silently?; @silently || false; end
35
37
 
36
38
  #
37
39
  # Exception
@@ -1,10 +1,10 @@
1
1
  module Protest
2
2
 
3
3
  class Assertion
4
- attr_reader :raised, :to_s
5
- def initialize(description, target, &block)
4
+ attr_reader :raised, :to_s, :description
5
+ def initialize(description, situation, &block)
6
6
  @description = @to_s = description
7
- actualize(target, &block)
7
+ actualize(situation, &block)
8
8
  end
9
9
 
10
10
  def actual
@@ -12,26 +12,24 @@ module Protest
12
12
  @actual
13
13
  end
14
14
 
15
- def failure(message)
16
- raise Failure.new(message, self)
17
- rescue Failure => e
18
- @failure = e # Smelly (for now)
15
+ def fail(message)
16
+ @failure = Failure.new(message, self) unless errored?
19
17
  end
20
18
 
21
- def error
22
- Error.new("errored with #{raised}", self, raised) if error?
23
- end
24
-
25
- def failure?; @failure; end
26
- def error?; !failure? && raised; end
27
- def passed?; !failure? && !error?; end
19
+ def failed?; !@failure.nil?; end
20
+ def errored?; !@raised.nil?; end
21
+ def passed?; !(failed? || errored?); end
28
22
  def result; @failure || error; end
29
23
  private
30
- def actualize(target, &block)
31
- @actual = target.instance_eval(&block)
32
- @default_failure = failure("expected true, not #{@actual.inspect}") unless @actual
24
+ def actualize(situation, &block)
25
+ @actual = situation.instance_eval(&block)
26
+ @default_failure = fail("expected true, not #{@actual.inspect}") unless @actual
33
27
  rescue Exception => e
34
28
  @raised = e
35
29
  end
30
+
31
+ def error
32
+ Error.new("errored with #{@raised}", self, @raised) if errored?
33
+ end
36
34
  end # Assertion
37
35
  end # Protest
@@ -1,45 +1,57 @@
1
1
  module Protest
2
2
  class Context
3
- attr_reader :description, :assertions
3
+ # The protein
4
+ attr_reader :description, :assertions, :situation
4
5
  def initialize(description, reporter, parent=nil)
5
- @reporter = reporter
6
- @description = description
6
+ @description, @reporter = description, reporter
7
7
  @assertions = []
8
8
  @parent = parent
9
- @setup = nil
10
- bootstrap(self)
9
+ @situation = Object.new
10
+ bootstrap(@situation)
11
11
  end
12
12
 
13
- def bootstrap(binder)
14
- @parent.bootstrap(binder) if @parent
15
- binder.instance_eval(&@setup) if @setup
13
+ def bootstrap(a_situation)
14
+ @parent.bootstrap(a_situation) if @parent # Walk it out
15
+ induce_local_setup(a_situation)
16
16
  end
17
17
 
18
+ # something smelly between setup() and bootstrap()
18
19
  def setup(&block)
19
20
  @setup = block
20
- self.instance_eval(&block)
21
+ make_situation_topical(induce_local_setup(situation))
21
22
  end
22
23
 
23
- def to_s; @to_s ||= [@parent.to_s, @description].join(' ').strip; end
24
-
24
+ # DSLee stuff
25
25
  def context(description, &block) Protest.context(description, @reporter, self, &block); end
26
26
  def asserts(description, &block) new_assertion("asserts #{description}", &block); end
27
27
  def should(description, &block) new_assertion("should #{description}", &block); end
28
28
 
29
+ # In conclusion
29
30
  def report
31
+ # we should just be passing assertions to the reporter and building better descriptions earlier
30
32
  assertions.each do |assertion|
31
33
  if assertion.passed?
32
34
  @reporter.passed
33
35
  else
34
36
  result = assertion.result.contextualize(self)
35
- @reporter.errored(result) if assertion.error?
36
- @reporter.failed(result) if assertion.failure?
37
+ @reporter.send( (assertion.errored? ? :errored : :failed), result)
37
38
  end
38
39
  end
39
40
  end
41
+
42
+ def to_s; @to_s ||= [@parent.to_s, @description].join(' ').strip; end
40
43
  private
41
44
  def new_assertion(description, &block)
42
- (assertions << Assertion.new(description, self, &block)).last
45
+ (assertions << Assertion.new(description, @situation, &block)).last
46
+ end
47
+
48
+ def induce_local_setup(a_situation)
49
+ a_situation.instance_eval(&@setup) if @setup
50
+ end
51
+
52
+ def make_situation_topical(topic)
53
+ situation.instance_variable_set(:@topic, topic)
54
+ situation.instance_eval { def topic; @topic; end }
43
55
  end
44
56
  end # Context
45
57
  end # Protest
@@ -4,22 +4,22 @@ module Protest
4
4
  # asserts("test") { "foo" }.equals("foo")
5
5
  # should("test") { "foo" }.equals("foo")
6
6
  def equals(expected)
7
- expected == actual || failure("expected #{expected.inspect}, not #{actual.inspect}")
7
+ expected == actual || fail("expected #{expected.inspect}, not #{actual.inspect}")
8
8
  end
9
9
 
10
10
  # Asserts that the result of the test is nil
11
11
  # asserts("test") { nil }.nil
12
12
  # should("test") { nil }.nil
13
13
  def nil
14
- actual.nil? || failure("expected nil, not #{actual.inspect}")
14
+ actual.nil? || fail("expected nil, not #{actual.inspect}")
15
15
  end
16
16
 
17
17
  # Asserts that the test raises the expected Exception
18
18
  # asserts("test") { raise My::Exception }.raises(My::Exception)
19
19
  # should("test") { raise My::Exception }.raises(My::Exception)
20
20
  def raises(expected)
21
- failure("should have raised #{expected}, but raised nothing") unless raised
22
- failure("should have raised #{expected}, not #{error.class}") unless expected == raised.class
21
+ fail("should have raised #{expected}, but raised nothing") unless raised
22
+ fail("should have raised #{expected}, not #{error.class}") unless expected == raised.class
23
23
  @raised = nil
24
24
  end
25
25
 
@@ -28,14 +28,14 @@ module Protest
28
28
  # should("test") { "12345" }.matches(/\d+/)
29
29
  def matches(expected)
30
30
  expected = %r[#{Regexp.escape(expected)}] if expected.kind_of?(String)
31
- actual =~ expected || failure("expected #{expected.inspect} to match #{actual.inspect}")
31
+ actual =~ expected || fail("expected #{expected.inspect} to match #{actual.inspect}")
32
32
  end
33
33
 
34
34
  # Asserts that the result of the test is an object that is a kind of the expected type
35
35
  # asserts("test") { "foo" }.kind_of(String)
36
36
  # should("test") { "foo" }.kind_of(String)
37
37
  def kind_of(expected)
38
- actual.kind_of?(expected) || failure("expected kind of #{expected}, not #{actual.inspect}")
38
+ actual.kind_of?(expected) || fail("expected kind of #{expected}, not #{actual.inspect}")
39
39
  end
40
40
  end # AssertionMacros
41
41
  end # Protest
@@ -1,3 +1,5 @@
1
+ require 'stringio'
2
+
1
3
  module Protest
2
4
  class Report
3
5
  attr_reader :bad_results, :passes, :failures, :errors, :time_taken
@@ -31,7 +33,7 @@ module Protest
31
33
  class TextReport < Report
32
34
  def initialize(writer=nil)
33
35
  super()
34
- @writer ||= STDOUT
36
+ @writer ||= (Protest.silently? ? StringIO.new : STDOUT)
35
37
  end
36
38
 
37
39
  def passed
@@ -71,9 +73,6 @@ module Protest
71
73
  end # TextReport
72
74
 
73
75
  class NilReport < Report
74
- def passed; end
75
- def failed(failure); end
76
- def errored(error); end
77
76
  def results; end
78
77
  def time(&block); yield; end
79
78
  end # NilReport
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.7"
4
- s.date = "2009-08-12"
3
+ s.version = "0.0.8"
4
+ s.date = "2009-09-12"
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"
@@ -27,6 +27,7 @@ Gem::Specification.new do |s|
27
27
  s.test_files = %w[
28
28
  Rakefile
29
29
  test/assertion_test.rb
30
+ test/benchmark/simple_context_and_assertions.rb
30
31
  test/context_test.rb
31
32
  ]
32
33
  end
@@ -12,11 +12,11 @@ context "basic assertion:" do
12
12
  end
13
13
 
14
14
  asserts "failure? is true when assertion does not pass" do
15
- Protest::Assertion.new("i will pass", fake_context) { false }.failure?
15
+ Protest::Assertion.new("i will pass", fake_context) { false }.failed?
16
16
  end
17
17
 
18
18
  asserts "error? is true when an unexpected Exception is raised" do
19
- Protest::Assertion.new("error", fake_context) { raise Exception, "blah" }.error?
19
+ Protest::Assertion.new("error", fake_context) { raise Exception, "blah" }.errored?
20
20
  end
21
21
  end
22
22
 
@@ -0,0 +1,76 @@
1
+ $:.concat ['./lib']
2
+ require 'benchmark'
3
+
4
+ #
5
+ # Model
6
+
7
+ class Room
8
+ attr_reader :name
9
+ def initialize(name)
10
+ @name = name
11
+ end
12
+ end
13
+
14
+ #
15
+ # Protest
16
+
17
+ require 'protest'
18
+ Protest.silently! # Do this before any contexts are defined
19
+
20
+ context "a room" do
21
+ setup { @room = Room.new("bed") }
22
+
23
+ asserts("name") { @room.name }.equals("bed")
24
+ end # a room
25
+
26
+ #
27
+ # Test::Unit
28
+
29
+ require 'test/unit'
30
+ Test::Unit.run = false
31
+
32
+ require 'test/unit/ui/console/testrunner'
33
+
34
+ class RoomTest < Test::Unit::TestCase
35
+ def setup
36
+ @room = Room.new("bed")
37
+ end
38
+
39
+ def test_room_should_be_named_bed
40
+ assert_equal "bed", @room.name
41
+ end
42
+ end
43
+
44
+ #
45
+ # Shoulda
46
+
47
+ require 'rubygems'
48
+ require 'shoulda'
49
+
50
+ class ShouldaRoomTest < Test::Unit::TestCase
51
+ def setup
52
+ @room = Room.new("bed")
53
+ end
54
+
55
+ should("be named 'bed'") { assert_equal "bed", @room.name }
56
+ end
57
+
58
+ #
59
+ # Benchmarking
60
+
61
+ n = 100 * 100
62
+
63
+ Benchmark.bmbm do |x|
64
+ x.report("Protest") do
65
+ n.times { Protest.report }
66
+ end
67
+
68
+ x.report("Test::Unit") do
69
+ n.times { Test::Unit::UI::Console::TestRunner.new(RoomTest, Test::Unit::UI::SILENT) }
70
+ end
71
+
72
+ x.report("Shoulda") do
73
+ n.times { Test::Unit::UI::Console::TestRunner.new(ShouldaRoomTest, Test::Unit::UI::SILENT) }
74
+ end
75
+ end
76
+
data/test/context_test.rb CHANGED
@@ -7,19 +7,26 @@ context "any context" do
7
7
  @context = Protest::Context.new("a", @reporter)
8
8
  end
9
9
 
10
- # denies("two contexts with same name are the same").equals(@context) { Protest::Context.new("a") }
11
-
12
10
  context "that doesn't have passing tests" do
13
11
  setup do
14
12
  @context.should("a") { true }
15
13
  @context.should("b") { false }
16
14
  @context.should("c") { raise Exception, "blah" }
15
+ @context.report
17
16
  end
18
17
 
19
18
  asserts("passed test count") { @reporter.passes }.equals(1)
20
19
  asserts("failure count") { @reporter.failures }.equals(1)
21
20
  asserts("unexpected errors count") { @reporter.errors }.equals(1)
22
21
  end # that doesn't have passing tests
22
+
23
+ context "when running setup:" do
24
+ setup { @context.setup { "foo" } }
25
+
26
+ asserts "topic becomes available to test as result of setup" do
27
+ @context.should("bar") { topic }.actual
28
+ end.equals("foo")
29
+ end # when running setup
23
30
  end # any context
24
31
 
25
32
  #
@@ -36,8 +43,8 @@ context "test context" do
36
43
  should("confirm context description") { test_context.to_s }.equals("foo")
37
44
  should("confirm assertion count") { test_context.assertions.length }.equals(2)
38
45
 
39
- should("call setup once") do
40
- test_context.instance_variable_get(:@test_counter)
46
+ should("call setup once per context") do
47
+ test_context.situation.instance_variable_get(:@test_counter) # yuck
41
48
  end.equals(2)
42
49
  end # test context
43
50
 
@@ -67,12 +74,12 @@ context "nested context" do
67
74
  end
68
75
 
69
76
  should("inherit parent context") do
70
- inner_nested_context.instance_variable_get(:@test_counter)
77
+ inner_nested_context.situation.instance_variable_get(:@test_counter)
71
78
  end.equals(10)
72
79
 
73
80
  should("chain context names") { inner_nested_context.to_s }.equals("foo baz")
74
81
 
75
82
  asserts "parent setup is called even if setup not defined for self" do
76
- other_nested_context.instance_variable_get(:@foo)
83
+ other_nested_context.situation.instance_variable_get(:@foo)
77
84
  end.equals("bar")
78
85
  end
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.7
4
+ version: 0.0.8
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-08-12 00:00:00 -07:00
12
+ date: 2009-09-12 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -33,7 +33,6 @@ files:
33
33
  - protest.gemspec
34
34
  has_rdoc: false
35
35
  homepage: http://github.com/thumblemonks/protest
36
- licenses:
37
36
  post_install_message:
38
37
  rdoc_options:
39
38
  - --main
@@ -55,11 +54,12 @@ required_rubygems_version: !ruby/object:Gem::Requirement
55
54
  requirements: []
56
55
 
57
56
  rubyforge_project:
58
- rubygems_version: 1.3.5
57
+ rubygems_version: 1.2.0
59
58
  signing_key:
60
59
  specification_version: 2
61
60
  summary: An extremely fast, expressive, and context-driven unit-testing framework
62
61
  test_files:
63
62
  - Rakefile
64
63
  - test/assertion_test.rb
64
+ - test/benchmark/simple_context_and_assertions.rb
65
65
  - test/context_test.rb