petitest 0.2.1 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +14 -1
- data/README.md +196 -45
- data/images/demo.png +0 -0
- data/lib/petitest.rb +9 -7
- data/lib/petitest/assertion_skip_error.rb +4 -0
- data/lib/petitest/autorun.rb +4 -2
- data/lib/petitest/dsl.rb +27 -0
- data/lib/petitest/subscriber_concerns/time_concern.rb +2 -2
- data/lib/petitest/subscribers/base_subscriber.rb +12 -12
- data/lib/petitest/subscribers/document_report_subscriber.rb +7 -7
- data/lib/petitest/subscribers/json_report_subscriber.rb +13 -13
- data/lib/petitest/subscribers/progress_report_subscriber.rb +5 -5
- data/lib/petitest/test.rb +142 -0
- data/lib/petitest/test_group.rb +35 -125
- data/lib/petitest/test_plan.rb +102 -0
- data/lib/petitest/{test_case.rb → test_runner.rb} +38 -21
- data/lib/petitest/texts/error_message_text.rb +7 -7
- data/lib/petitest/texts/failures_element_text.rb +9 -14
- data/lib/petitest/texts/failures_text.rb +7 -7
- data/lib/petitest/texts/filtered_backtrace_text.rb +6 -6
- data/lib/petitest/texts/raised_code_text.rb +7 -7
- data/lib/petitest/texts/test_counts_text.rb +26 -26
- data/lib/petitest/texts/test_result_character_text.rb +27 -0
- data/lib/petitest/texts/test_result_line_text.rb +37 -0
- data/lib/petitest/texts/tests_result_margin_top_text.rb +24 -0
- data/lib/petitest/texts/{test_cases_result_text.rb → tests_result_text.rb} +14 -12
- data/lib/petitest/version.rb +1 -1
- metadata +12 -8
- data/lib/petitest/test_cases_runner.rb +0 -90
- data/lib/petitest/texts/test_case_result_character_text.rb +0 -27
- data/lib/petitest/texts/test_case_result_line_text.rb +0 -37
- data/lib/petitest/texts/test_cases_result_margin_top_text.rb +0 -24
@@ -9,27 +9,27 @@ module Petitest
|
|
9
9
|
include ::Petitest::SubscriberConcerns::TimeConcern
|
10
10
|
|
11
11
|
# @note Override
|
12
|
-
def
|
12
|
+
def after_running_test(test)
|
13
13
|
super
|
14
|
-
string = ::Petitest::Texts::
|
14
|
+
string = ::Petitest::Texts::TestResultLineText.new(test: test).to_s
|
15
15
|
output.puts(string)
|
16
16
|
end
|
17
17
|
|
18
18
|
# @note Override
|
19
|
-
def
|
19
|
+
def after_running_test_plan(test_plan)
|
20
20
|
super
|
21
|
-
string = ::Petitest::Texts::
|
21
|
+
string = ::Petitest::Texts::TestsResultText.new(
|
22
22
|
finished_at: finished_at,
|
23
23
|
started_at: started_at,
|
24
|
-
|
24
|
+
tests: test_plan.tests,
|
25
25
|
).to_s
|
26
26
|
output.puts(string)
|
27
27
|
end
|
28
28
|
|
29
29
|
# @note Override
|
30
|
-
def before_running_test_group(
|
30
|
+
def before_running_test_group(test_group)
|
31
31
|
super
|
32
|
-
string = "#{' ' *
|
32
|
+
string = "#{' ' * test_group.nest_level}#{test_group.description}"
|
33
33
|
output.puts(string)
|
34
34
|
end
|
35
35
|
end
|
@@ -10,22 +10,22 @@ module Petitest
|
|
10
10
|
include ::Petitest::SubscriberConcerns::TimeConcern
|
11
11
|
|
12
12
|
# @note Override
|
13
|
-
def
|
13
|
+
def after_running_test_plan(test_plan)
|
14
14
|
super
|
15
15
|
data = {
|
16
|
-
|
16
|
+
tests: test_plan.tests.map do |test|
|
17
17
|
{
|
18
|
-
backtrace:
|
19
|
-
class_name:
|
20
|
-
error_class_name:
|
21
|
-
error_message:
|
22
|
-
failed:
|
23
|
-
finished_at:
|
24
|
-
method_line_number:
|
25
|
-
method_name:
|
26
|
-
path:
|
27
|
-
skipped:
|
28
|
-
started_at:
|
18
|
+
backtrace: test.runner.backtrace,
|
19
|
+
class_name: test.class.to_s,
|
20
|
+
error_class_name: test.runner.error_class_name,
|
21
|
+
error_message: test.runner.error_message,
|
22
|
+
failed: test.runner.failed?,
|
23
|
+
finished_at: test.runner.finished_at.iso8601(6),
|
24
|
+
method_line_number: test.runner.test_method.line_number,
|
25
|
+
method_name: test.runner.test_method.method_name,
|
26
|
+
path: test.runner.test_method.path,
|
27
|
+
skipped: test.runner.skipped?,
|
28
|
+
started_at: test.runner.started_at.iso8601(6),
|
29
29
|
}
|
30
30
|
end,
|
31
31
|
times: {
|
@@ -9,19 +9,19 @@ module Petitest
|
|
9
9
|
include ::Petitest::SubscriberConcerns::TimeConcern
|
10
10
|
|
11
11
|
# @note Override
|
12
|
-
def
|
12
|
+
def after_running_test(test)
|
13
13
|
super
|
14
|
-
string = ::Petitest::Texts::
|
14
|
+
string = ::Petitest::Texts::TestResultCharacterText.new(test: test).to_s
|
15
15
|
output.print(string)
|
16
16
|
end
|
17
17
|
|
18
18
|
# @note Override
|
19
|
-
def
|
19
|
+
def after_running_test_plan(test_plan)
|
20
20
|
super
|
21
|
-
string = ::Petitest::Texts::
|
21
|
+
string = ::Petitest::Texts::TestsResultText.new(
|
22
22
|
finished_at: finished_at,
|
23
23
|
started_at: started_at,
|
24
|
-
|
24
|
+
tests: test_plan.tests,
|
25
25
|
).to_s
|
26
26
|
output.puts(string)
|
27
27
|
end
|
@@ -0,0 +1,142 @@
|
|
1
|
+
module Petitest
|
2
|
+
class Test
|
3
|
+
TEST_METHOD_NAME_PREFIX = "test_"
|
4
|
+
|
5
|
+
class << self
|
6
|
+
attr_accessor :current_description
|
7
|
+
|
8
|
+
attr_writer :description
|
9
|
+
|
10
|
+
attr_writer :metadata
|
11
|
+
|
12
|
+
# @return [Array<Class>]
|
13
|
+
def children
|
14
|
+
@children ||= []
|
15
|
+
end
|
16
|
+
|
17
|
+
# @return [String]
|
18
|
+
def description
|
19
|
+
@description ||= name
|
20
|
+
end
|
21
|
+
|
22
|
+
# @return [Hash{Symbol => String}]
|
23
|
+
def description_by_method_name
|
24
|
+
@description_by_method_name ||= {}
|
25
|
+
end
|
26
|
+
|
27
|
+
# @return [Petitest::TestGroup]
|
28
|
+
def generate_test_group
|
29
|
+
::Petitest::TestGroup.new(test_class: self)
|
30
|
+
end
|
31
|
+
|
32
|
+
# @return [String, nil]
|
33
|
+
def full_description
|
34
|
+
test_ancestors.reverse.map(&:description).join(" ")
|
35
|
+
end
|
36
|
+
|
37
|
+
# @note Override
|
38
|
+
def inherited(child)
|
39
|
+
super
|
40
|
+
children << child
|
41
|
+
end
|
42
|
+
|
43
|
+
# @return [Hash{Symbol => Object}]
|
44
|
+
def metadata
|
45
|
+
@metadata ||= {}
|
46
|
+
end
|
47
|
+
|
48
|
+
# @note Override
|
49
|
+
def method_added(method_name)
|
50
|
+
super
|
51
|
+
if current_description && check_if_test_method_name(method_name)
|
52
|
+
description_by_method_name[method_name] = current_description
|
53
|
+
clear_current_description
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# @return [Array<Class>]
|
58
|
+
def test_ancestors
|
59
|
+
@test_ancestors ||= ancestors.each_with_object([]) do |klass, classes|
|
60
|
+
if klass == ::Petitest::Test
|
61
|
+
break classes
|
62
|
+
end
|
63
|
+
if klass.is_a?(::Class)
|
64
|
+
classes << klass
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
# @return [Array<Symbol>]
|
70
|
+
def test_method_names
|
71
|
+
public_instance_methods.select do |method_name|
|
72
|
+
check_if_test_method_name(method_name)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def undefine_test_methods
|
77
|
+
test_method_names.each do |method_name|
|
78
|
+
undef_method(method_name)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
private
|
83
|
+
|
84
|
+
# @param method_name [Symbol]
|
85
|
+
# @return [Boolean]
|
86
|
+
def check_if_test_method_name(method_name)
|
87
|
+
method_name.to_s.start_with?(TEST_METHOD_NAME_PREFIX)
|
88
|
+
end
|
89
|
+
|
90
|
+
def clear_current_description
|
91
|
+
self.current_description = nil
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
# @param test_group [Petitest::TestGroup]
|
96
|
+
# @param test_method_name [Symbol]
|
97
|
+
def initialize(
|
98
|
+
test_group:,
|
99
|
+
test_method_name:
|
100
|
+
)
|
101
|
+
@test_group = test_group
|
102
|
+
@test_method_name = test_method_name
|
103
|
+
end
|
104
|
+
|
105
|
+
# @param actual_or_message [Object]
|
106
|
+
# @param message [String, nil]
|
107
|
+
def assert(actual_or_message = nil, message = nil, &block)
|
108
|
+
if block
|
109
|
+
message = actual_or_message
|
110
|
+
check(message || "Expected given block to return truthy", &block)
|
111
|
+
else
|
112
|
+
actual = actual_or_message
|
113
|
+
check(message || "Expected #{actual.inspect} to be truthy") do
|
114
|
+
actual
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
# @param message [String, nil]
|
120
|
+
def skip(message = nil)
|
121
|
+
raise ::Petitest::AssertionSkipError.new(message)
|
122
|
+
end
|
123
|
+
|
124
|
+
# @return [Petitest::TestRunner]
|
125
|
+
def runner
|
126
|
+
@runner ||= Petitest::TestRunner.new(
|
127
|
+
test: self,
|
128
|
+
test_group: @test_group,
|
129
|
+
test_method_name: @test_method_name,
|
130
|
+
)
|
131
|
+
end
|
132
|
+
|
133
|
+
private
|
134
|
+
|
135
|
+
# @param message [String, nil]
|
136
|
+
def check(message, &block)
|
137
|
+
unless block.call
|
138
|
+
raise ::Petitest::AssertionFailureError.new(message)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
data/lib/petitest/test_group.rb
CHANGED
@@ -1,140 +1,50 @@
|
|
1
1
|
module Petitest
|
2
2
|
class TestGroup
|
3
|
-
|
3
|
+
# @return [Class]
|
4
|
+
attr_reader :test_class
|
4
5
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
attr_writer :nest_level
|
11
|
-
|
12
|
-
# @return [Array<Class>]
|
13
|
-
def children
|
14
|
-
@children ||= []
|
15
|
-
end
|
16
|
-
|
17
|
-
# @return [Array<Class>]
|
18
|
-
def descendants
|
19
|
-
children.flat_map(&:children)
|
20
|
-
end
|
21
|
-
|
22
|
-
# @return [String]
|
23
|
-
def description
|
24
|
-
@description ||= name
|
25
|
-
end
|
26
|
-
|
27
|
-
# @return [String, nil]
|
28
|
-
def full_description
|
29
|
-
descriptions = concrete_test_group_ancestors.reverse.map(&:description)
|
30
|
-
unless descriptions.empty?
|
31
|
-
descriptions.join(" ")
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
# @note Override
|
36
|
-
def inherited(child)
|
37
|
-
super
|
38
|
-
children << child
|
39
|
-
end
|
40
|
-
|
41
|
-
# @return [Hash{Symbol => Object}]
|
42
|
-
def metadata
|
43
|
-
@metadata ||= {}
|
44
|
-
end
|
45
|
-
|
46
|
-
# @return [Integer]
|
47
|
-
def nest_level
|
48
|
-
@nest_level ||= 0
|
49
|
-
end
|
50
|
-
|
51
|
-
# @param description [String]
|
52
|
-
# @param metadata [Hash{Symbol => Object}]
|
53
|
-
def sub_test_group(description, metadata = {}, &block)
|
54
|
-
child = ::Class.new(self)
|
55
|
-
child.nest_level = nest_level + 1
|
56
|
-
child.description = description
|
57
|
-
child.metadata = self.metadata.merge(metadata)
|
58
|
-
child.undefine_test_methods
|
59
|
-
child.class_eval(&block)
|
60
|
-
child
|
61
|
-
end
|
62
|
-
|
63
|
-
# @return [Array<Petit::TestCase>]
|
64
|
-
def test_cases
|
65
|
-
@test_cases ||= test_methods.map do |test_method|
|
66
|
-
::Petitest::TestCase.new(
|
67
|
-
test_group_class: self,
|
68
|
-
test_method: test_method,
|
69
|
-
)
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
# @return [Array<Petit::TestCase>]
|
74
|
-
def test_cases_and_children_test_cases
|
75
|
-
test_cases + children.flat_map(&:test_cases_and_children_test_cases)
|
76
|
-
end
|
77
|
-
|
78
|
-
# @return [Array<String>]
|
79
|
-
def test_method_names
|
80
|
-
public_instance_methods.map(&:to_s).select do |method_name|
|
81
|
-
method_name.start_with?(TEST_METHOD_NAME_PREFIX)
|
82
|
-
end
|
83
|
-
end
|
6
|
+
# @param test_class [Class]
|
7
|
+
def initialize(test_class:)
|
8
|
+
@test_class ||= test_class
|
9
|
+
end
|
84
10
|
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
::Petitest::TestMethod.new(
|
90
|
-
line_number: unbound_method.source_location[1],
|
91
|
-
method_name: method_name.to_s,
|
92
|
-
path: unbound_method.source_location[0],
|
93
|
-
)
|
94
|
-
end
|
95
|
-
end
|
11
|
+
# @return [String]
|
12
|
+
def description
|
13
|
+
test_class.description
|
14
|
+
end
|
96
15
|
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
end
|
16
|
+
# @return [String]
|
17
|
+
def full_description
|
18
|
+
test_class.test_ancestors.reverse.map(&:description).join(" ")
|
19
|
+
end
|
102
20
|
|
103
|
-
|
21
|
+
# @return [Hash{Symbol => Object}]
|
22
|
+
def metadata
|
23
|
+
test_class.metadata
|
24
|
+
end
|
104
25
|
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
if klass == ::Petitest::TestGroup
|
109
|
-
break classes
|
110
|
-
end
|
111
|
-
if klass.is_a?(::Class)
|
112
|
-
classes << klass
|
113
|
-
end
|
114
|
-
end
|
115
|
-
end
|
26
|
+
# @return [Integer]
|
27
|
+
def nest_level
|
28
|
+
test_class.test_ancestors.length - 1
|
116
29
|
end
|
117
30
|
|
118
|
-
# @
|
119
|
-
|
120
|
-
|
121
|
-
if block
|
122
|
-
message = actual_or_message
|
123
|
-
check(message || "Expected given block to return truthy", &block)
|
124
|
-
else
|
125
|
-
actual = actual_or_message
|
126
|
-
check(message || "Expected #{actual.inspect} to be truthy") do
|
127
|
-
actual
|
128
|
-
end
|
129
|
-
end
|
31
|
+
# @return [Array<Petitest::Test>]
|
32
|
+
def self_and_descendant_tests
|
33
|
+
tests + sub_test_groups.flat_map(&:self_and_descendant_tests)
|
130
34
|
end
|
131
35
|
|
132
|
-
|
36
|
+
# @return [Array<Petitest::TestGroup>]
|
37
|
+
def sub_test_groups
|
38
|
+
@sub_test_groups ||= test_class.children.map(&:generate_test_group)
|
39
|
+
end
|
133
40
|
|
134
|
-
# @
|
135
|
-
def
|
136
|
-
|
137
|
-
|
41
|
+
# @return [Array<Petitest::Test>]
|
42
|
+
def tests
|
43
|
+
@tests ||= test_class.test_method_names.map do |test_method_name|
|
44
|
+
test_class.new(
|
45
|
+
test_group: self,
|
46
|
+
test_method_name: test_method_name,
|
47
|
+
)
|
138
48
|
end
|
139
49
|
end
|
140
50
|
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
module Petitest
|
2
|
+
class TestPlan
|
3
|
+
# @return [Array<Class>]
|
4
|
+
attr_reader :test_classes
|
5
|
+
|
6
|
+
# @param test_classes [Array<Class>]
|
7
|
+
def initialize(test_classes:)
|
8
|
+
@test_classes = test_classes
|
9
|
+
end
|
10
|
+
|
11
|
+
# @return [Boolean]
|
12
|
+
def passed?
|
13
|
+
tests.map(&:runner).all? do |runner|
|
14
|
+
runner.passed? || runner.skipped?
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def run
|
19
|
+
before_running_test_plan
|
20
|
+
test_groups.each do |test_group|
|
21
|
+
run_test_group(test_group)
|
22
|
+
end
|
23
|
+
after_running_test_plan
|
24
|
+
end
|
25
|
+
|
26
|
+
# @return [Array<Petitest::TestGroup>]
|
27
|
+
def test_groups
|
28
|
+
@test_groups ||= test_classes.map(&:generate_test_group)
|
29
|
+
end
|
30
|
+
|
31
|
+
# @return [Array<Petitest::Test>]
|
32
|
+
def tests
|
33
|
+
test_groups.flat_map(&:self_and_descendant_tests)
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
# @param test [Petitest::Test]
|
39
|
+
def after_running_test(test)
|
40
|
+
subscribers.each do |subscriber|
|
41
|
+
subscriber.after_running_test(test)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# @param test_group [Petitest::TestGroup]
|
46
|
+
def after_running_test_group(test_group)
|
47
|
+
subscribers.each do |subscriber|
|
48
|
+
subscriber.after_running_test_group(test_group)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def after_running_test_plan
|
53
|
+
subscribers.each do |subscriber|
|
54
|
+
subscriber.after_running_test_plan(self)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# @param test [Petitest::Test]
|
59
|
+
def before_running_test(test)
|
60
|
+
subscribers.each do |subscriber|
|
61
|
+
subscriber.before_running_test(test)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
# @param test_group [Petitest::TestGroup]
|
66
|
+
def before_running_test_group(test_group)
|
67
|
+
subscribers.each do |subscriber|
|
68
|
+
subscriber.before_running_test_group(test_group)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def before_running_test_plan
|
73
|
+
subscribers.each do |subscriber|
|
74
|
+
subscriber.before_running_test_plan(self)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
# @param test [Petitest::Test]
|
79
|
+
def run_test(test)
|
80
|
+
before_running_test(test)
|
81
|
+
test.runner.run
|
82
|
+
after_running_test(test)
|
83
|
+
end
|
84
|
+
|
85
|
+
# @param test_group [Petitest::TestGroup]
|
86
|
+
def run_test_group(test_group)
|
87
|
+
before_running_test_group(test_group)
|
88
|
+
test_group.tests.each do |test|
|
89
|
+
run_test(test)
|
90
|
+
end
|
91
|
+
test_group.sub_test_groups.each do |sub_test_group|
|
92
|
+
run_test_group(sub_test_group)
|
93
|
+
end
|
94
|
+
after_running_test_group(test_group)
|
95
|
+
end
|
96
|
+
|
97
|
+
# @return [Array<Petitest::Subscribers::BaseSubscriber>]
|
98
|
+
def subscribers
|
99
|
+
::Petitest.configuration.subscribers
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|