thumblemonks-protest 0.0.6 → 0.0.7
Sign up to get free protection for your applications and to get access to all the features.
- data/MIT-LICENSE +1 -1
- data/README.markdown +14 -5
- data/Rakefile +6 -1
- data/lib/protest/assertion.rb +3 -26
- data/lib/protest/context.rb +4 -4
- data/lib/protest/macros.rb +5 -0
- data/lib/protest/report.rb +3 -2
- data/lib/protest.rb +4 -0
- data/protest.gemspec +2 -2
- data/test/assertion_test.rb +17 -30
- data/test/context_test.rb +16 -22
- metadata +4 -3
data/MIT-LICENSE
CHANGED
data/README.markdown
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
# Protest
|
2
2
|
|
3
|
-
An extremely fast, expressive, and context-driven unit-testing framework.
|
3
|
+
An extremely fast, expressive, and context-driven unit-testing framework. Protest the slow test.
|
4
4
|
|
5
5
|
#### Example: Basic booleans
|
6
6
|
|
7
7
|
**NOTE:** For no specific reason, I'm going to use an ActiveRecord model in the following examples.
|
8
8
|
|
9
|
-
At it's very basic, Protest simply tries to assert that an expression is true or false. Protest does this through its `asserts`
|
9
|
+
At it's very basic, Protest simply tries to assert that an expression is true or false. Protest does this through its `asserts` or `should` tests. An `asserts` test will pass if the result of running the test is neither `nil` or `false`. A `should` test does the exact same thing - they are in fact aliases. The only difference is in the way you write the assertion.
|
10
10
|
|
11
11
|
For instance, given a test file named `foo_test.rb`, you might have the following code in it:
|
12
12
|
|
@@ -15,10 +15,20 @@ For instance, given a test file named `foo_test.rb`, you might have the followin
|
|
15
15
|
context "a new user" do
|
16
16
|
setup { @user = User.new }
|
17
17
|
asserts("that it is not yet created") { @user.new_record? }
|
18
|
-
denies("that it is valid") { @user.valid? }
|
19
18
|
end
|
20
19
|
|
21
|
-
Notice that you do not define a class anywhere. That would be the entire contents of that test file.
|
20
|
+
Notice that you do not define a class anywhere. That would be the entire contents of that test file. If you wanted to use a `should` instead, you could say this:
|
21
|
+
|
22
|
+
require 'protest'
|
23
|
+
|
24
|
+
context "a new user" do
|
25
|
+
setup { @user = User.new }
|
26
|
+
should("not be created") { @user.new_record? }
|
27
|
+
end
|
28
|
+
|
29
|
+
Sometimes it's more clear to say "this **should** be that" and sometimes it's better to say "**asserts** this is that". I promise you that Protest will get no more redundant than this, but also that besides speed, Protest will aim at being expressive with a minimal amount of syntax.
|
30
|
+
|
31
|
+
I'm going to use `asserts` for the rest of this introduction, but you should know that you can replace any instance of `asserts` with `should` and nothing would change.
|
22
32
|
|
23
33
|
#### Example: Equality
|
24
34
|
|
@@ -275,7 +285,6 @@ TONS OF STUFF
|
|
275
285
|
1. Refactor reporting; some abstracting is needed for recording a result (for instance)
|
276
286
|
1. Need to know where in backtrace a test failed (line number, etc.)
|
277
287
|
1. More assertion macros: throws, etc.
|
278
|
-
1. Handle denies macro different, so that an entire failure message can translated to the 'negative' assertion. I don't want to add deny\_this and deny\_that macros
|
279
288
|
1. Aliases for context "with, without, when, ..."; add those words to test description
|
280
289
|
1. Optimization and simplification (ex. flog is complaining print\_result\_stack)
|
281
290
|
1. Better error messages (maybe need to rename asserts to should for better readability)
|
data/Rakefile
CHANGED
@@ -10,7 +10,12 @@ task :test do
|
|
10
10
|
Protest.report
|
11
11
|
end
|
12
12
|
|
13
|
-
desc "Run
|
13
|
+
desc "Run Flog against library (except tests)"
|
14
14
|
task :flog do
|
15
15
|
puts %x[find ./lib -name *.rb | xargs flog]
|
16
16
|
end
|
17
|
+
|
18
|
+
desc "Run Roodi against library (except tests)"
|
19
|
+
task :roodi do
|
20
|
+
puts %x[find ./lib -name *.rb | xargs roodi]
|
21
|
+
end
|
data/lib/protest/assertion.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
module Protest
|
2
2
|
|
3
3
|
class Assertion
|
4
|
-
attr_reader :raised
|
4
|
+
attr_reader :raised, :to_s
|
5
5
|
def initialize(description, target, &block)
|
6
|
-
@description = description
|
6
|
+
@description = @to_s = description
|
7
7
|
actualize(target, &block)
|
8
8
|
end
|
9
9
|
|
@@ -26,35 +26,12 @@ module Protest
|
|
26
26
|
def error?; !failure? && raised; end
|
27
27
|
def passed?; !failure? && !error?; end
|
28
28
|
def result; @failure || error; end
|
29
|
-
def to_s; @description; end
|
30
29
|
private
|
31
30
|
def actualize(target, &block)
|
32
31
|
@actual = target.instance_eval(&block)
|
33
|
-
@default_failure =
|
32
|
+
@default_failure = failure("expected true, not #{@actual.inspect}") unless @actual
|
34
33
|
rescue Exception => e
|
35
34
|
@raised = e
|
36
35
|
end
|
37
|
-
|
38
|
-
def base_assertion
|
39
|
-
failure("expected true, not #{@actual.inspect}") unless @actual
|
40
|
-
end
|
41
36
|
end # Assertion
|
42
|
-
|
43
|
-
# Denial will evaulate to true if the assertion failed in some way. Errors pass through. A Failure
|
44
|
-
# is generated if the assertion actually passed.
|
45
|
-
class Denial < Assertion
|
46
|
-
def actual
|
47
|
-
@actual # Do not forget default failure unless a failure is thrown
|
48
|
-
end
|
49
|
-
|
50
|
-
alias :actual_failure :failure
|
51
|
-
def failure(message)
|
52
|
-
@default_failure = @failure = nil # this is a good thing
|
53
|
-
end
|
54
|
-
private
|
55
|
-
def base_assertion
|
56
|
-
actual_failure("expected assertion to fail") if @actual
|
57
|
-
end
|
58
|
-
end # Denial
|
59
|
-
|
60
37
|
end # Protest
|
data/lib/protest/context.rb
CHANGED
@@ -23,8 +23,8 @@ module Protest
|
|
23
23
|
def to_s; @to_s ||= [@parent.to_s, @description].join(' ').strip; end
|
24
24
|
|
25
25
|
def context(description, &block) Protest.context(description, @reporter, self, &block); end
|
26
|
-
def asserts(description, &block) new_assertion(
|
27
|
-
def
|
26
|
+
def asserts(description, &block) new_assertion("asserts #{description}", &block); end
|
27
|
+
def should(description, &block) new_assertion("should #{description}", &block); end
|
28
28
|
|
29
29
|
def report
|
30
30
|
assertions.each do |assertion|
|
@@ -38,8 +38,8 @@ module Protest
|
|
38
38
|
end
|
39
39
|
end
|
40
40
|
private
|
41
|
-
def new_assertion(
|
42
|
-
(assertions <<
|
41
|
+
def new_assertion(description, &block)
|
42
|
+
(assertions << Assertion.new(description, self, &block)).last
|
43
43
|
end
|
44
44
|
end # Context
|
45
45
|
end # Protest
|
data/lib/protest/macros.rb
CHANGED
@@ -2,18 +2,21 @@ module Protest
|
|
2
2
|
module AssertionMacros
|
3
3
|
# Asserts that the result of the test equals the expected value
|
4
4
|
# asserts("test") { "foo" }.equals("foo")
|
5
|
+
# should("test") { "foo" }.equals("foo")
|
5
6
|
def equals(expected)
|
6
7
|
expected == actual || failure("expected #{expected.inspect}, not #{actual.inspect}")
|
7
8
|
end
|
8
9
|
|
9
10
|
# Asserts that the result of the test is nil
|
10
11
|
# asserts("test") { nil }.nil
|
12
|
+
# should("test") { nil }.nil
|
11
13
|
def nil
|
12
14
|
actual.nil? || failure("expected nil, not #{actual.inspect}")
|
13
15
|
end
|
14
16
|
|
15
17
|
# Asserts that the test raises the expected Exception
|
16
18
|
# asserts("test") { raise My::Exception }.raises(My::Exception)
|
19
|
+
# should("test") { raise My::Exception }.raises(My::Exception)
|
17
20
|
def raises(expected)
|
18
21
|
failure("should have raised #{expected}, but raised nothing") unless raised
|
19
22
|
failure("should have raised #{expected}, not #{error.class}") unless expected == raised.class
|
@@ -22,6 +25,7 @@ module Protest
|
|
22
25
|
|
23
26
|
# Asserts that the result of the test equals matches against the proved expression
|
24
27
|
# asserts("test") { "12345" }.matches(/\d+/)
|
28
|
+
# should("test") { "12345" }.matches(/\d+/)
|
25
29
|
def matches(expected)
|
26
30
|
expected = %r[#{Regexp.escape(expected)}] if expected.kind_of?(String)
|
27
31
|
actual =~ expected || failure("expected #{expected.inspect} to match #{actual.inspect}")
|
@@ -29,6 +33,7 @@ module Protest
|
|
29
33
|
|
30
34
|
# Asserts that the result of the test is an object that is a kind of the expected type
|
31
35
|
# asserts("test") { "foo" }.kind_of(String)
|
36
|
+
# should("test") { "foo" }.kind_of(String)
|
32
37
|
def kind_of(expected)
|
33
38
|
actual.kind_of?(expected) || failure("expected kind of #{expected}, not #{actual.inspect}")
|
34
39
|
end
|
data/lib/protest/report.rb
CHANGED
@@ -59,13 +59,14 @@ module Protest
|
|
59
59
|
def print_result_stack
|
60
60
|
bad_results.each_with_index do |result, idx|
|
61
61
|
@writer.puts render_result(idx + 1, result)
|
62
|
-
@writer.puts " " + result.backtrace.join("\n ")
|
62
|
+
@writer.puts " " + result.backtrace.join("\n ") if result.print_stacktrace?
|
63
|
+
@writer.puts "\n\n"
|
63
64
|
end
|
64
65
|
end
|
65
66
|
|
66
67
|
def render_result(idx, result)
|
67
68
|
format_args = [idx, result.context.to_s, result.assertion.to_s, result.to_s]
|
68
|
-
"#%d - %s
|
69
|
+
"#%d - %s %s: %s" % format_args
|
69
70
|
end
|
70
71
|
end # TextReport
|
71
72
|
|
data/lib/protest.rb
CHANGED
@@ -42,16 +42,20 @@ module Protest
|
|
42
42
|
super(message)
|
43
43
|
@assertion = assertion
|
44
44
|
end
|
45
|
+
|
45
46
|
def contextualize(ctx)
|
46
47
|
@context = ctx
|
47
48
|
self
|
48
49
|
end
|
50
|
+
|
51
|
+
def print_stacktrace?; false; end
|
49
52
|
end
|
50
53
|
class Error < Failure
|
51
54
|
def initialize(message, assertion, error)
|
52
55
|
super(message, assertion)
|
53
56
|
set_backtrace(error.backtrace)
|
54
57
|
end
|
58
|
+
def print_stacktrace?; true; end
|
55
59
|
end
|
56
60
|
end # Protest
|
57
61
|
|
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.
|
4
|
-
s.date = "2009-
|
3
|
+
s.version = "0.0.7"
|
4
|
+
s.date = "2009-08-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"
|
data/test/assertion_test.rb
CHANGED
@@ -1,79 +1,66 @@
|
|
1
1
|
require 'protest'
|
2
2
|
|
3
|
-
fake_context = Object.new
|
3
|
+
fake_context = Object.new # It works ... so, why not?
|
4
4
|
|
5
5
|
context "basic assertion:" do
|
6
|
-
|
6
|
+
should "have a description" do
|
7
7
|
Protest::Assertion.new("i will pass", fake_context).to_s
|
8
8
|
end.equals("i will pass")
|
9
9
|
|
10
|
-
asserts
|
10
|
+
asserts "pass? is true when assertion passed" do
|
11
11
|
Protest::Assertion.new("i will pass", fake_context) { true }.passed?
|
12
12
|
end
|
13
13
|
|
14
|
-
asserts
|
14
|
+
asserts "failure? is true when assertion does not pass" do
|
15
15
|
Protest::Assertion.new("i will pass", fake_context) { false }.failure?
|
16
16
|
end
|
17
17
|
|
18
|
-
asserts
|
18
|
+
asserts "error? is true when an unexpected Exception is raised" do
|
19
19
|
Protest::Assertion.new("error", fake_context) { raise Exception, "blah" }.error?
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
23
|
-
context "basic denial:" do
|
24
|
-
asserts("false assertion passes") do
|
25
|
-
Protest::Denial.new("i will pass", fake_context) { false }.passed?
|
26
|
-
end
|
27
|
-
|
28
|
-
asserts("true assertion fails") do
|
29
|
-
Protest::Denial.new("i will not pass", fake_context) { true }.failure?
|
30
|
-
end
|
31
|
-
end # basic assertion
|
32
|
-
|
33
23
|
context "equals assertion:" do
|
34
|
-
asserts
|
24
|
+
asserts "result equals expectation" do
|
35
25
|
Protest::Assertion.new("i will pass", fake_context) { "foo bar" }.equals("foo bar")
|
36
26
|
end
|
37
27
|
|
38
|
-
|
28
|
+
should "raise a Failure if results don't equal each other" do
|
39
29
|
Protest::Assertion.new("failure", fake_context) { "bar" }.equals("foo")
|
40
30
|
end.kind_of(Protest::Failure)
|
41
|
-
|
42
|
-
asserts("a non-matching string is a good thing when in denial") do
|
43
|
-
Protest::Denial.new("pass", fake_context) { "bar" }.equals("foo")
|
44
|
-
end.nil
|
45
31
|
end # equals assertion
|
46
32
|
|
47
33
|
context "nil assertion:" do
|
48
|
-
asserts("
|
49
|
-
|
34
|
+
asserts("result is nil") { Protest::Assertion.new("foo", fake_context) { nil }.nil }
|
35
|
+
should "raise a Failure if not nil" do
|
50
36
|
Protest::Assertion.new("foo", fake_context) { "a" }.nil
|
51
37
|
end.kind_of(Protest::Failure)
|
52
38
|
end # nil assertion
|
53
39
|
|
54
40
|
context "raises assertion:" do
|
55
|
-
|
56
|
-
end #
|
41
|
+
should("raise an Exception") { raise Exception }.raises(Exception)
|
42
|
+
end # raises assertion
|
57
43
|
|
58
44
|
context "matching assertion:" do
|
59
|
-
asserts
|
45
|
+
asserts "result matches expression" do
|
60
46
|
Protest::Assertion.new("foo", fake_context) { "a" }.matches(%r[.])
|
61
47
|
end.equals(0)
|
62
48
|
|
63
|
-
|
49
|
+
should "raise a Failure if result does not match" do
|
64
50
|
Protest::Assertion.new("foo", fake_context) { "" }.matches(%r[.])
|
65
51
|
end.kind_of(Protest::Failure)
|
66
52
|
|
67
|
-
|
53
|
+
should "return the result of a matching operation" do
|
68
54
|
Protest::Assertion.new("foo", fake_context) { "a" }.matches("a")
|
69
55
|
end.equals(0)
|
70
56
|
end # maching assertion
|
71
57
|
|
72
58
|
context "kind_of assertion:" do
|
73
|
-
asserts
|
59
|
+
asserts "specific result is a kind of String" do
|
74
60
|
Protest::Assertion.new("foo", fake_context) { "a" }.kind_of(String)
|
75
61
|
end
|
76
|
-
|
62
|
+
|
63
|
+
should "raise a Failure if not a kind of String" do
|
77
64
|
Protest::Assertion.new("foo", fake_context) { 0 }.kind_of(String)
|
78
65
|
end.kind_of(Protest::Failure)
|
79
66
|
end # kind_of assertion
|
data/test/context_test.rb
CHANGED
@@ -11,41 +11,35 @@ context "any context" do
|
|
11
11
|
|
12
12
|
context "that doesn't have passing tests" do
|
13
13
|
setup do
|
14
|
-
@context.
|
15
|
-
@context.
|
16
|
-
@context.
|
14
|
+
@context.should("a") { true }
|
15
|
+
@context.should("b") { false }
|
16
|
+
@context.should("c") { raise Exception, "blah" }
|
17
17
|
end
|
18
18
|
|
19
|
-
asserts("
|
20
|
-
asserts("
|
21
|
-
asserts("
|
19
|
+
asserts("passed test count") { @reporter.passes }.equals(1)
|
20
|
+
asserts("failure count") { @reporter.failures }.equals(1)
|
21
|
+
asserts("unexpected errors count") { @reporter.errors }.equals(1)
|
22
22
|
end # that doesn't have passing tests
|
23
23
|
end # any context
|
24
24
|
|
25
|
-
context "when denying things" do
|
26
|
-
denies("true is false") { false }
|
27
|
-
denies("bar equals foo") { "bar" }.equals("foo")
|
28
|
-
denies("bar matches only digits") { "bar" }.matches(/^\d+$/)
|
29
|
-
end
|
30
|
-
|
31
25
|
#
|
32
26
|
# Test Context
|
33
27
|
|
34
28
|
test_context = context("foo", Protest::NilReport.new) do
|
35
29
|
setup { @test_counter = 0 }
|
36
|
-
asserts("
|
37
|
-
asserts("
|
30
|
+
asserts("truthiness") { @test_counter += 1; true }
|
31
|
+
asserts("more truthiness") { @test_counter += 1; true }
|
38
32
|
end # A CONTEXT THAT IS DEQUEUED
|
39
33
|
|
40
34
|
context "test context" do
|
41
35
|
setup { Protest.dequeue_context(test_context) }
|
42
|
-
|
43
|
-
|
36
|
+
should("confirm context description") { test_context.to_s }.equals("foo")
|
37
|
+
should("confirm assertion count") { test_context.assertions.length }.equals(2)
|
44
38
|
|
45
|
-
|
39
|
+
should("call setup once") do
|
46
40
|
test_context.instance_variable_get(:@test_counter)
|
47
41
|
end.equals(2)
|
48
|
-
end
|
42
|
+
end # test context
|
49
43
|
|
50
44
|
#
|
51
45
|
# Nested Context
|
@@ -56,7 +50,7 @@ nested_context = context("foo", Protest::NilReport.new) do
|
|
56
50
|
@test_counter = 0
|
57
51
|
@foo = "bar"
|
58
52
|
end
|
59
|
-
asserts("
|
53
|
+
asserts("truthiness") { @test_counter += 1; true }
|
60
54
|
|
61
55
|
inner_nested_context = context("baz") do
|
62
56
|
setup { @test_counter += 10 }
|
@@ -72,13 +66,13 @@ context "nested context" do
|
|
72
66
|
end
|
73
67
|
end
|
74
68
|
|
75
|
-
|
69
|
+
should("inherit parent context") do
|
76
70
|
inner_nested_context.instance_variable_get(:@test_counter)
|
77
71
|
end.equals(10)
|
78
72
|
|
79
|
-
|
73
|
+
should("chain context names") { inner_nested_context.to_s }.equals("foo baz")
|
80
74
|
|
81
|
-
asserts
|
75
|
+
asserts "parent setup is called even if setup not defined for self" do
|
82
76
|
other_nested_context.instance_variable_get(:@foo)
|
83
77
|
end.equals("bar")
|
84
78
|
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.
|
4
|
+
version: 0.0.7
|
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-
|
12
|
+
date: 2009-08-12 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
@@ -33,6 +33,7 @@ files:
|
|
33
33
|
- protest.gemspec
|
34
34
|
has_rdoc: false
|
35
35
|
homepage: http://github.com/thumblemonks/protest
|
36
|
+
licenses:
|
36
37
|
post_install_message:
|
37
38
|
rdoc_options:
|
38
39
|
- --main
|
@@ -54,7 +55,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
54
55
|
requirements: []
|
55
56
|
|
56
57
|
rubyforge_project:
|
57
|
-
rubygems_version: 1.
|
58
|
+
rubygems_version: 1.3.5
|
58
59
|
signing_key:
|
59
60
|
specification_version: 2
|
60
61
|
summary: An extremely fast, expressive, and context-driven unit-testing framework
|