attest 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +1 -1
- data/Gemfile.lock +6 -1
- data/README.rdoc +121 -36
- data/Rakefile +12 -1
- data/VERSION +1 -1
- data/attest.gemspec +61 -36
- data/bin/attest +18 -24
- data/doodle.txt +73 -29
- data/examples/{magic_calculator.rb → basic_functionality_example.rb} +42 -8
- data/examples/mocha_example.rb +43 -0
- data/examples/module_example.rb +49 -0
- data/examples/more/{placeholder.rb → multiple_context_example.rb} +0 -0
- data/examples/more/nesting/expectations_as_tests_example.rb +20 -0
- data/lib/attest.rb +4 -20
- data/lib/attest/config.rb +3 -6
- data/lib/attest/core_ext/kernel.rb +19 -1
- data/lib/attest/core_ext/object.rb +1 -2
- data/lib/attest/core_ext/proc.rb +35 -0
- data/lib/attest/execution_context.rb +156 -50
- data/lib/attest/expectation_result.rb +22 -1
- data/lib/attest/interface/output_writer_configurator.rb +25 -0
- data/lib/attest/interface/possible_tests_configurator.rb +35 -0
- data/lib/attest/interface/test_double_configurator.rb +40 -0
- data/lib/attest/output/basic_output_writer.rb +14 -46
- data/lib/attest/output/failures_only_output_writer.rb +47 -0
- data/lib/attest/output/output_writer.rb +124 -0
- data/lib/attest/output/output_writer_interface.rb +24 -0
- data/lib/attest/output/test_unit_output_writer.rb +32 -0
- data/lib/attest/proc/proc_source_reader.rb +49 -0
- data/lib/attest/rake/attesttask.rb +38 -0
- data/lib/attest/test_container.rb +15 -4
- data/lib/attest/test_loader.rb +28 -0
- data/lib/attest/test_object.rb +35 -29
- data/lib/attest/test_parser.rb +69 -11
- data/lib/trollop.rb +782 -0
- data/spec/interface/output_writer_configurator_test.rb +18 -0
- data/spec/interface/possible_tests_configurator_test.rb +55 -0
- data/spec/interface/test_double_configurator_test.rb +20 -0
- data/spec/output/output_writer_test.rb +20 -0
- data/spec/tmp/new_require_test.rb +10 -0
- metadata +55 -18
- data/.gitignore +0 -23
- data/examples/standard_calculator.rb +0 -28
- data/lib/attest/attest_error.rb +0 -7
- data/lib/attest/itself.rb +0 -34
@@ -1,84 +1,190 @@
|
|
1
|
+
require 'attest/expectation_result'
|
2
|
+
|
1
3
|
module Attest
|
2
4
|
class ExecutionContext
|
3
5
|
attr_reader :results
|
4
6
|
|
5
|
-
|
6
|
-
|
7
|
-
|
7
|
+
class << self
|
8
|
+
def assertions
|
9
|
+
self.instance_methods(false).select{|method_name| method_name =~ /^should.*/ }.inspect
|
10
|
+
end
|
8
11
|
end
|
9
12
|
|
10
|
-
def
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
if type && type == e.class
|
19
|
-
result.success
|
20
|
-
else
|
21
|
-
result.success
|
13
|
+
def initialize(context=nil)
|
14
|
+
@results = []
|
15
|
+
@subject = self
|
16
|
+
@persistent_context = context
|
17
|
+
own_instance_variables = self.instance_variables
|
18
|
+
context.instance_variables.each do |instance_variable|
|
19
|
+
unless own_instance_variables.include? instance_variable
|
20
|
+
self.instance_variable_set(instance_variable.to_s, context.instance_variable_get(instance_variable))
|
22
21
|
end
|
23
22
|
end
|
24
|
-
|
25
|
-
|
23
|
+
end
|
24
|
+
|
25
|
+
def should_be(expected_lambda, &block)
|
26
|
+
with_new_result do |result|
|
27
|
+
expected_lambda.call == yield ? result.success : result.failure
|
26
28
|
end
|
27
|
-
@results << result
|
28
|
-
self
|
29
29
|
end
|
30
|
+
alias :should_be_a :should_be
|
31
|
+
alias :should_be_an :should_be
|
32
|
+
alias :should_match :should_be
|
33
|
+
alias :should_match_a :should_be
|
34
|
+
alias :should_match_an :should_be
|
30
35
|
|
31
|
-
def
|
32
|
-
|
33
|
-
|
34
|
-
if !(result.attributes[:expected_error].message =~ regex)
|
35
|
-
result.failure
|
36
|
-
end
|
36
|
+
def should_not_be(expected_lambda, &block)
|
37
|
+
with_new_result do |result|
|
38
|
+
expected_lambda.call != yield ? result.success : result.failure
|
37
39
|
end
|
38
|
-
self
|
39
40
|
end
|
41
|
+
alias :should_not_be_a :should_not_be
|
42
|
+
alias :should_not_be_an :should_not_be
|
43
|
+
alias :should_not_match :should_not_be
|
44
|
+
alias :should_not_match_a :should_not_be
|
45
|
+
alias :should_not_match_an :should_not_be
|
46
|
+
|
47
|
+
def should_be_same(expected_value, actual_value=nil, &block)
|
48
|
+
derive_result_status_from_method(expected_value, actual_value, :"equal?", &block)
|
49
|
+
end
|
50
|
+
alias :should_be_same_as :should_be_same
|
51
|
+
|
52
|
+
def should_not_be_same(expected_value, actual_value=nil, &block)
|
53
|
+
derive_result_status_from_method_negated(expected_value, actual_value, :"equal?", &block)
|
54
|
+
end
|
55
|
+
alias :should_not_be_same_as :should_not_be_same
|
56
|
+
|
57
|
+
def should_equal(expected_value, actual_value=nil, &block)
|
58
|
+
derive_result_status_from_method(expected_value, actual_value, :"==", &block)
|
59
|
+
end
|
60
|
+
|
61
|
+
def should_not_equal(expected_value, actual_value=nil, &block)
|
62
|
+
derive_result_status_from_method_negated(expected_value, actual_value, :"==", &block)
|
63
|
+
end
|
64
|
+
alias :should_not_be_equal :should_not_equal
|
65
|
+
|
66
|
+
def should_be_true(actual_value=nil, &block)
|
67
|
+
derive_result_status_from_method(true, actual_value, :"==", &block)
|
68
|
+
end
|
69
|
+
|
70
|
+
def should_not_be_true(actual_value = nil, &block)
|
71
|
+
derive_result_status_from_method(false, actual_value, :"==", &block)
|
72
|
+
end
|
73
|
+
alias :should_be_false :should_not_be_true
|
40
74
|
|
41
75
|
def should_fail
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
self
|
76
|
+
with_new_result do |result|
|
77
|
+
result.failure
|
78
|
+
end
|
46
79
|
end
|
80
|
+
alias :should_not_succeed :should_fail
|
47
81
|
|
48
|
-
def
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
@results << result
|
53
|
-
self
|
82
|
+
def should_succeed
|
83
|
+
with_new_result do |result|
|
84
|
+
result.success
|
85
|
+
end
|
54
86
|
end
|
87
|
+
alias :should_not_fail :should_succeed
|
88
|
+
alias :should_pass :should_succeed
|
55
89
|
|
56
90
|
def should_not_raise(&block)
|
57
91
|
should_raise(&block)
|
58
|
-
|
59
|
-
|
60
|
-
|
92
|
+
with_last_result do |result|
|
93
|
+
result.success? ? result.failure : result.success
|
94
|
+
end
|
61
95
|
end
|
62
96
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
97
|
+
#the only opt so far is :with_message which takes a regex
|
98
|
+
def should_raise(type=nil, opts={}, &block)
|
99
|
+
with_new_result do |result|
|
100
|
+
begin
|
101
|
+
if block_given?
|
102
|
+
yield
|
103
|
+
end
|
104
|
+
rescue => e
|
105
|
+
result.update(:expected_error => e)
|
106
|
+
if expected_error?(type, opts[:with_message], e)
|
107
|
+
result.success
|
108
|
+
else
|
109
|
+
result.failure
|
110
|
+
end
|
111
|
+
end
|
112
|
+
unless result.success?
|
113
|
+
result.failure
|
114
|
+
end
|
115
|
+
end
|
68
116
|
end
|
69
117
|
|
70
118
|
#worker methods
|
71
119
|
def create_and_include(module_class)
|
72
120
|
class_name = "#{module_class}Class"
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
121
|
+
klass = nil
|
122
|
+
begin
|
123
|
+
klass = Object.const_get(class_name)
|
124
|
+
rescue NameError => e
|
125
|
+
class_instance = Class.new
|
126
|
+
Object.const_set class_name, class_instance
|
127
|
+
Object.const_get(class_name).include(Object.const_get("#{module_class}"))
|
128
|
+
klass = Object.const_get(class_name)
|
129
|
+
end
|
77
130
|
klass.new
|
78
131
|
end
|
79
132
|
|
80
|
-
|
81
|
-
|
133
|
+
private
|
134
|
+
def derive_result_status_from_method(expected_value, actual_value, method, negated=false, &block)
|
135
|
+
with_new_result do |result|
|
136
|
+
if block_given?
|
137
|
+
method_return = expected_value.send(method, yield)
|
138
|
+
method_return = !method_return if negated
|
139
|
+
method_return ? result.success : result.failure
|
140
|
+
else
|
141
|
+
method_return = expected_value.send(method, actual_value)
|
142
|
+
method_return = !method_return if negated
|
143
|
+
method_return ? result.success : result.failure
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
def derive_result_status_from_method_negated(expected_value, actual_value, method, &block)
|
149
|
+
derive_result_status_from_method(expected_value, actual_value, method, true, &block)
|
150
|
+
end
|
151
|
+
|
152
|
+
def source_location
|
153
|
+
caller.each_with_index do |stack_line|
|
154
|
+
if stack_line[Attest.config.current_file]
|
155
|
+
return stack_line[/(.*:\d+):.*/, 1]
|
156
|
+
end
|
157
|
+
end
|
158
|
+
""
|
159
|
+
end
|
160
|
+
|
161
|
+
def with_new_result
|
162
|
+
result = Attest::ExpectationResult.new
|
163
|
+
yield result
|
164
|
+
result.source_location = source_location
|
165
|
+
@results << result
|
166
|
+
end
|
167
|
+
|
168
|
+
def with_last_result
|
169
|
+
result = @results.last
|
170
|
+
yield result
|
171
|
+
result.source_location = source_location
|
172
|
+
end
|
173
|
+
|
174
|
+
def expected_error?(expected_type, expected_message_regex, actual_error)
|
175
|
+
if expected_type.nil? && expected_message_regex.nil? || expected_error_type?(expected_type, actual_error.class) && expected_message_regex.nil? || expected_error_type?(expected_type, actual_error.class) && error_message_matches?(expected_message_regex, actual_error.message)
|
176
|
+
return true
|
177
|
+
else
|
178
|
+
return false
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
def expected_error_type?(expected_type, actual_type)
|
183
|
+
expected_type == actual_type
|
184
|
+
end
|
185
|
+
|
186
|
+
def error_message_matches?(expected_message_regex, actual_error_message)
|
187
|
+
actual_error_message =~ expected_message_regex
|
82
188
|
end
|
83
189
|
end
|
84
190
|
end
|
@@ -1,12 +1,24 @@
|
|
1
1
|
module Attest
|
2
2
|
class ExpectationResult
|
3
|
+
include Comparable
|
4
|
+
class << self
|
5
|
+
def status_types
|
6
|
+
status_weights.keys
|
7
|
+
end
|
8
|
+
|
9
|
+
def status_weights
|
10
|
+
{:success => 1, :failure => 2, :error => 3, :pending => 4, :disabled => 5}
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
3
14
|
attr_reader :attributes
|
15
|
+
attr_accessor :source_location
|
4
16
|
def initialize(attributes={})
|
5
17
|
@outcome = nil
|
6
18
|
@attributes = attributes
|
7
19
|
end
|
8
20
|
|
9
|
-
|
21
|
+
Attest::ExpectationResult.status_types.each do |status|
|
10
22
|
eval <<-EOT
|
11
23
|
def #{status}
|
12
24
|
@outcome = current_method
|
@@ -24,5 +36,14 @@ module Attest
|
|
24
36
|
def update(attributes={})
|
25
37
|
@attributes.merge!(attributes)
|
26
38
|
end
|
39
|
+
|
40
|
+
def status_weight
|
41
|
+
Attest::ExpectationResult.status_weights[status.to_sym]
|
42
|
+
end
|
43
|
+
|
44
|
+
def <=>(another_result)
|
45
|
+
return 1 unless another_result
|
46
|
+
self.status_weight <=> another_result.status_weight
|
47
|
+
end
|
27
48
|
end
|
28
49
|
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'attest/output/basic_output_writer'
|
2
|
+
require 'attest/output/test_unit_output_writer'
|
3
|
+
require 'attest/output/failures_only_output_writer'
|
4
|
+
|
5
|
+
module Attest
|
6
|
+
class OutputWriterConfigurator
|
7
|
+
class << self
|
8
|
+
def configure(output_writer_identifier)
|
9
|
+
output_writer_identifier = output_writer_identifier || default_output_writer_identifier
|
10
|
+
raise "You have specified an unknown output writer" unless output_writer_identifiers.include? output_writer_identifier
|
11
|
+
output_writer_class = "#{output_writer_identifier}OutputWriter"
|
12
|
+
#Attest.config.output_writer = Attest::Output.const_get(output_writer_class).new
|
13
|
+
Attest::Output.const_get(output_writer_class).new
|
14
|
+
end
|
15
|
+
|
16
|
+
def default_output_writer_identifier
|
17
|
+
"Basic"
|
18
|
+
end
|
19
|
+
|
20
|
+
def output_writer_identifiers
|
21
|
+
[default_output_writer_identifier, "TestUnit", "FailuresOnly"]
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Attest
|
2
|
+
class PossibleTestsConfigurator
|
3
|
+
class << self
|
4
|
+
def configure(included_locations, excluded_locations = nil)
|
5
|
+
raise "Need to know location for tests" if included_locations.compact.size == 0
|
6
|
+
possible_test_files = included_test_files included_locations
|
7
|
+
files_to_ignore = excluded_test_files excluded_locations
|
8
|
+
possible_test_files - files_to_ignore
|
9
|
+
end
|
10
|
+
|
11
|
+
def included_test_files(included_locations)
|
12
|
+
file_list_from_list_of included_locations
|
13
|
+
end
|
14
|
+
|
15
|
+
def excluded_test_files(excluded_locations)
|
16
|
+
return [] if excluded_locations.nil?
|
17
|
+
file_list_from_list_of excluded_locations
|
18
|
+
end
|
19
|
+
|
20
|
+
def file_list_from_list_of(locations)
|
21
|
+
file_list = []
|
22
|
+
locations.compact.each do |location|
|
23
|
+
expanded_location = File.expand_path(location)
|
24
|
+
file_list << file_list_from_single(expanded_location)
|
25
|
+
end
|
26
|
+
file_list.flatten
|
27
|
+
end
|
28
|
+
|
29
|
+
def file_list_from_single(location)
|
30
|
+
return location if File.file? location
|
31
|
+
Dir[File.join(File.expand_path(location), "**/*.rb")].collect { |ruby_file| ruby_file }
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'attest/execution_context'
|
2
|
+
|
3
|
+
module Attest
|
4
|
+
class TestDoubleConfigurator
|
5
|
+
class << self
|
6
|
+
def configure(test_double_identifier)
|
7
|
+
test_double_identifier = test_double_identifier || default_test_double_identifier
|
8
|
+
raise "You have specified an unsupported test double framework" unless test_double_identifiers.include? test_double_identifier
|
9
|
+
self.send(:"configure_#{test_double_identifier}")
|
10
|
+
#Attest.config.testdouble = test_double_identifier
|
11
|
+
test_double_identifier
|
12
|
+
end
|
13
|
+
|
14
|
+
def configure_mocha
|
15
|
+
begin
|
16
|
+
#how would this work when bundler is in play
|
17
|
+
require "mocha_standalone"
|
18
|
+
rescue LoadError => e
|
19
|
+
puts "Trying to use mocha for test double functionality, but can't find it!"
|
20
|
+
puts "Perhaps you forgot to install the mocha gem."
|
21
|
+
exit
|
22
|
+
end
|
23
|
+
Attest::ExecutionContext.class_eval do
|
24
|
+
include Mocha::API # need this so that methods like stub() and mock() can be accessed directly from the execution context
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def configure_none
|
29
|
+
end
|
30
|
+
|
31
|
+
def default_test_double_identifier
|
32
|
+
"mocha"
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_double_identifiers
|
36
|
+
[default_test_double_identifier, "none"]
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -1,31 +1,31 @@
|
|
1
|
+
require 'attest/output/output_writer'
|
2
|
+
require 'attest/expectation_result'
|
3
|
+
|
1
4
|
module Attest
|
2
5
|
module Output
|
3
|
-
class BasicOutputWriter
|
4
|
-
def
|
5
|
-
@containers = []
|
6
|
-
end
|
7
|
-
|
8
|
-
def before_everything
|
9
|
-
end
|
10
|
-
|
11
|
-
def before_context(container)
|
6
|
+
class BasicOutputWriter < Attest::Output::OutputWriter
|
7
|
+
def before_container(container)
|
12
8
|
previous_container = @containers.last
|
13
9
|
@containers << container
|
14
10
|
puts "#{container.file}:" unless previous_container && previous_container.file == container.file
|
15
11
|
puts " #{ container.description }"
|
16
12
|
end
|
17
13
|
|
14
|
+
def after_container(container)
|
15
|
+
puts
|
16
|
+
end
|
17
|
+
|
18
18
|
def before_test(test_object)
|
19
19
|
print " - #{test_object.description}"
|
20
20
|
end
|
21
21
|
|
22
22
|
def after_test(test_object)
|
23
|
-
relevant_result =
|
24
|
-
test_object.results.each do |result|
|
25
|
-
relevant_result = result if !result.success?
|
26
|
-
end
|
23
|
+
relevant_result = determine_relevant_result test_object
|
27
24
|
print " [#{relevant_result.status.upcase}]" if relevant_result
|
28
|
-
if relevant_result && relevant_result.
|
25
|
+
if relevant_result && relevant_result.failure?
|
26
|
+
2.times { puts }
|
27
|
+
puts " #{relevant_result.source_location}"
|
28
|
+
elsif relevant_result && relevant_result.error?
|
29
29
|
e = relevant_result.attributes[:unexpected_error]
|
30
30
|
2.times { puts }
|
31
31
|
puts " #{e.class}: #{e.message}"
|
@@ -36,38 +36,6 @@ module Attest
|
|
36
36
|
end
|
37
37
|
puts
|
38
38
|
end
|
39
|
-
|
40
|
-
def after_context
|
41
|
-
puts
|
42
|
-
end
|
43
|
-
|
44
|
-
def summary
|
45
|
-
return unless @containers.size >= 1
|
46
|
-
tests, success, failure, error, pending = 0, 0, 0, 0, 0
|
47
|
-
@containers.each do |container|
|
48
|
-
container.test_objects.each do |test_object|
|
49
|
-
tests += 1
|
50
|
-
test_object.results.each do |result|
|
51
|
-
if result.success?
|
52
|
-
success += 1
|
53
|
-
elsif result.failure?
|
54
|
-
failure += 1
|
55
|
-
elsif result.error?
|
56
|
-
error += 1
|
57
|
-
elsif result.pending?
|
58
|
-
pending += 1
|
59
|
-
else
|
60
|
-
raise "Errr, WTF!!!"
|
61
|
-
end
|
62
|
-
end
|
63
|
-
end
|
64
|
-
end
|
65
|
-
puts
|
66
|
-
puts "Ran #{tests} tests: #{success} successful, #{failure} failed, #{error} errors, #{pending} pending"
|
67
|
-
end
|
68
|
-
|
69
|
-
def after_everything
|
70
|
-
end
|
71
39
|
end
|
72
40
|
end
|
73
41
|
end
|