attest 0.1.0 → 0.2.0
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/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
|