petitest 0.2.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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