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.
Files changed (33) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +14 -1
  3. data/README.md +196 -45
  4. data/images/demo.png +0 -0
  5. data/lib/petitest.rb +9 -7
  6. data/lib/petitest/assertion_skip_error.rb +4 -0
  7. data/lib/petitest/autorun.rb +4 -2
  8. data/lib/petitest/dsl.rb +27 -0
  9. data/lib/petitest/subscriber_concerns/time_concern.rb +2 -2
  10. data/lib/petitest/subscribers/base_subscriber.rb +12 -12
  11. data/lib/petitest/subscribers/document_report_subscriber.rb +7 -7
  12. data/lib/petitest/subscribers/json_report_subscriber.rb +13 -13
  13. data/lib/petitest/subscribers/progress_report_subscriber.rb +5 -5
  14. data/lib/petitest/test.rb +142 -0
  15. data/lib/petitest/test_group.rb +35 -125
  16. data/lib/petitest/test_plan.rb +102 -0
  17. data/lib/petitest/{test_case.rb → test_runner.rb} +38 -21
  18. data/lib/petitest/texts/error_message_text.rb +7 -7
  19. data/lib/petitest/texts/failures_element_text.rb +9 -14
  20. data/lib/petitest/texts/failures_text.rb +7 -7
  21. data/lib/petitest/texts/filtered_backtrace_text.rb +6 -6
  22. data/lib/petitest/texts/raised_code_text.rb +7 -7
  23. data/lib/petitest/texts/test_counts_text.rb +26 -26
  24. data/lib/petitest/texts/test_result_character_text.rb +27 -0
  25. data/lib/petitest/texts/test_result_line_text.rb +37 -0
  26. data/lib/petitest/texts/tests_result_margin_top_text.rb +24 -0
  27. data/lib/petitest/texts/{test_cases_result_text.rb → tests_result_text.rb} +14 -12
  28. data/lib/petitest/version.rb +1 -1
  29. metadata +12 -8
  30. data/lib/petitest/test_cases_runner.rb +0 -90
  31. data/lib/petitest/texts/test_case_result_character_text.rb +0 -27
  32. data/lib/petitest/texts/test_case_result_line_text.rb +0 -37
  33. 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 after_running_test_case(test_case)
12
+ def after_running_test(test)
13
13
  super
14
- string = ::Petitest::Texts::TestCaseResultLineText.new(test_case: test_case).to_s
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 after_running_test_cases(test_cases)
19
+ def after_running_test_plan(test_plan)
20
20
  super
21
- string = ::Petitest::Texts::TestCasesResultText.new(
21
+ string = ::Petitest::Texts::TestsResultText.new(
22
22
  finished_at: finished_at,
23
23
  started_at: started_at,
24
- test_cases: test_cases,
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(test_group_class)
30
+ def before_running_test_group(test_group)
31
31
  super
32
- string = "#{' ' * test_group_class.nest_level}#{test_group_class.description}"
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 after_running_test_cases(test_cases)
13
+ def after_running_test_plan(test_plan)
14
14
  super
15
15
  data = {
16
- test_cases: test_cases.map do |test_case|
16
+ tests: test_plan.tests.map do |test|
17
17
  {
18
- backtrace: test_case.backtrace,
19
- class_name: test_case.test_group_class.to_s,
20
- error_class_name: test_case.error_class_name,
21
- error_message: test_case.error_message,
22
- failed: test_case.failed?,
23
- finished_at: test_case.finished_at.iso8601(6),
24
- method_line_number: test_case.test_method.line_number,
25
- method_name: test_case.test_method.method_name,
26
- path: test_case.test_method.path,
27
- skipped: test_case.skipped?,
28
- started_at: test_case.started_at.iso8601(6),
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 after_running_test_case(test_case)
12
+ def after_running_test(test)
13
13
  super
14
- string = ::Petitest::Texts::TestCaseResultCharacterText.new(test_case: test_case).to_s
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 after_running_test_cases(test_cases)
19
+ def after_running_test_plan(test_plan)
20
20
  super
21
- string = ::Petitest::Texts::TestCasesResultText.new(
21
+ string = ::Petitest::Texts::TestsResultText.new(
22
22
  finished_at: finished_at,
23
23
  started_at: started_at,
24
- test_cases: test_cases,
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
@@ -1,140 +1,50 @@
1
1
  module Petitest
2
2
  class TestGroup
3
- TEST_METHOD_NAME_PREFIX = "test_"
3
+ # @return [Class]
4
+ attr_reader :test_class
4
5
 
5
- class << self
6
- attr_writer :description
7
-
8
- attr_writer :metadata
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
- # @return [Array<Petitest::TestMethod>]
86
- def test_methods
87
- test_method_names.map do |method_name|
88
- unbound_method = public_instance_method(method_name)
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
- def undefine_test_methods
98
- test_method_names.each do |method_name|
99
- undef_method(method_name)
100
- end
101
- end
16
+ # @return [String]
17
+ def full_description
18
+ test_class.test_ancestors.reverse.map(&:description).join(" ")
19
+ end
102
20
 
103
- private
21
+ # @return [Hash{Symbol => Object}]
22
+ def metadata
23
+ test_class.metadata
24
+ end
104
25
 
105
- # @return [Array<Class>]
106
- def concrete_test_group_ancestors
107
- ancestors.each_with_object([]) do |klass, classes|
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
- # @param actual_or_message [Object]
119
- # @param message [String, nil]
120
- def assert(actual_or_message = nil, message = nil, &block)
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
- private
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
- # @param message [String, nil]
135
- def check(message, &block)
136
- unless block.call
137
- raise ::Petitest::AssertionFailureError.new(message)
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