petitest 0.2.1 → 0.3.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.
- 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
|