smartest 0.3.3.alpha3 → 0.4.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/DEVELOPMENT.md +5 -0
- data/README.md +42 -8
- data/SMARTEST_DESIGN.md +20 -3
- data/exe/smartest +50 -11
- data/lib/smartest/cli_arguments.rb +26 -3
- data/lib/smartest/constant_stub_helpers.rb +45 -0
- data/lib/smartest/execution_context.rb +1 -0
- data/lib/smartest/fixture.rb +1 -37
- data/lib/smartest/hook_contexts.rb +4 -0
- data/lib/smartest/version.rb +1 -1
- data/lib/smartest.rb +1 -0
- data/smartest/simple_stub_test.rb +69 -32
- data/smartest/smartest_test.rb +92 -5
- metadata +5 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3d2b5aeaf51e6e6878eac74601d634daab2e423cede641216856a79188c28554
|
|
4
|
+
data.tar.gz: 4f90e558f84062585a0a8b3596c91f9507f9fec09430a86c6782ae7a3ba92bb7
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 687150dcb8a16d475d76b9840fecf63b7705fc0b5e123380d6ffe3fe415a77ed89228bdbc098e66db22d67164f4b43412229e47311be15b6ab09643bf00aa43f
|
|
7
|
+
data.tar.gz: 037f50862bd76bcb86e4511227a8a5f2ce943e37fdce3d823124ff90872efa1a808bb7eee4a2ab9c0985c685baf2db451c304074e6797f88d1c2f370390adea6
|
data/DEVELOPMENT.md
CHANGED
|
@@ -46,6 +46,7 @@ smartest/
|
|
|
46
46
|
expectation_target.rb
|
|
47
47
|
matchers.rb
|
|
48
48
|
simple_stub.rb
|
|
49
|
+
constant_stub_helpers.rb
|
|
49
50
|
|
|
50
51
|
runner.rb
|
|
51
52
|
test_result.rb
|
|
@@ -647,6 +648,10 @@ A practical approach:
|
|
|
647
648
|
- `exe/smartest`
|
|
648
649
|
- load files from ARGV
|
|
649
650
|
- default glob `smartest/**/*_test.rb`
|
|
651
|
+
- print scaffold guidance and exit 1 when the default run is requested before
|
|
652
|
+
`smartest/` exists
|
|
653
|
+
- expand directory path arguments such as `smartest/` to `**/*_test.rb` files
|
|
654
|
+
under that directory
|
|
650
655
|
- support `path:line` and `path:start-end` filters that run tests whose `test`
|
|
651
656
|
blocks contain or intersect the lines
|
|
652
657
|
- add `smartest/` to the load path before loading tests
|
data/README.md
CHANGED
|
@@ -123,12 +123,34 @@ bundle exec smartest
|
|
|
123
123
|
By default, Smartest loads `smartest/**/*_test.rb`, so a separate `test/`
|
|
124
124
|
directory can remain available for Minitest.
|
|
125
125
|
|
|
126
|
+
If `smartest/` does not exist yet and no explicit paths are passed, Smartest
|
|
127
|
+
prints scaffold commands instead of attempting a default test run:
|
|
128
|
+
|
|
129
|
+
```text
|
|
130
|
+
No smartest/ directory found.
|
|
131
|
+
|
|
132
|
+
To create a Smartest test scaffold:
|
|
133
|
+
bundle exec smartest --init
|
|
134
|
+
|
|
135
|
+
For browser tests:
|
|
136
|
+
bundle exec smartest --init-browser
|
|
137
|
+
|
|
138
|
+
See all commands:
|
|
139
|
+
bundle exec smartest --help
|
|
140
|
+
```
|
|
141
|
+
|
|
126
142
|
You can also pass explicit paths:
|
|
127
143
|
|
|
128
144
|
```bash
|
|
145
|
+
bundle exec smartest smartest/suite1/
|
|
129
146
|
bundle exec smartest smartest/**/*_test.rb
|
|
147
|
+
bundle exec smartest smartest/user_test.rb
|
|
130
148
|
```
|
|
131
149
|
|
|
150
|
+
A directory path is expanded to `**/*_test.rb` under that directory, so
|
|
151
|
+
`bundle exec smartest smartest/suite1/` is equivalent to
|
|
152
|
+
`bundle exec smartest smartest/suite1/**/*_test.rb`.
|
|
153
|
+
|
|
132
154
|
To run tests by line number, append `:line` or `:start-end` to the file path.
|
|
133
155
|
Smartest runs tests whose `test` blocks contain or intersect the selected lines:
|
|
134
156
|
|
|
@@ -152,6 +174,18 @@ bundle exec smartest --help
|
|
|
152
174
|
bundle exec smartest --version
|
|
153
175
|
```
|
|
154
176
|
|
|
177
|
+
The help output lists common commands, including default runs, directory runs,
|
|
178
|
+
single-file runs, line-filtered runs, and scaffold generation:
|
|
179
|
+
|
|
180
|
+
```bash
|
|
181
|
+
bundle exec smartest
|
|
182
|
+
bundle exec smartest smartest/suite1/
|
|
183
|
+
bundle exec smartest smartest/user_test.rb
|
|
184
|
+
bundle exec smartest smartest/user_test.rb:12
|
|
185
|
+
bundle exec smartest --init
|
|
186
|
+
bundle exec smartest --init-browser
|
|
187
|
+
```
|
|
188
|
+
|
|
155
189
|
Output resembles:
|
|
156
190
|
|
|
157
191
|
```text
|
|
@@ -637,16 +671,16 @@ end
|
|
|
637
671
|
```
|
|
638
672
|
|
|
639
673
|
Use `simple_stub(Time, :now) { fixed_time }` for singleton methods such as class
|
|
640
|
-
methods.
|
|
641
|
-
|
|
642
|
-
|
|
674
|
+
methods.
|
|
675
|
+
|
|
676
|
+
Use `with_stub_const("AppConfig::PAYMENT_PROVIDER", "fake") { ... }` for
|
|
677
|
+
constants in test bodies, `around_test`, or `around_suite`. Constant stubs are
|
|
678
|
+
process-global; avoid concurrent tests that stub the same constant.
|
|
643
679
|
|
|
644
680
|
The method stub helpers call `Smartest::SimpleStub` internally, apply the stub,
|
|
645
681
|
register `cleanup { stub.reset }`, and return the stub object.
|
|
646
|
-
`
|
|
647
|
-
restores or removes
|
|
648
|
-
`Smartest::Fixture` fixture blocks because they need cleanup to tie the stub
|
|
649
|
-
lifetime to the fixture scope.
|
|
682
|
+
`with_stub_const` records the previous constant value, replaces it, yields to
|
|
683
|
+
the block, and restores or removes the constant with `ensure`.
|
|
650
684
|
|
|
651
685
|
`Smartest::SimpleStub#apply` and `#reset` are idempotent in the current Fiber.
|
|
652
686
|
`apply!` raises
|
|
@@ -880,7 +914,7 @@ Smartest currently focuses on a small runner API:
|
|
|
880
914
|
- fixture dependencies through keyword arguments
|
|
881
915
|
- fixture cleanup
|
|
882
916
|
- suite-scoped fixtures through `suite_fixture`
|
|
883
|
-
- fixture-scoped method and constant stubs
|
|
917
|
+
- fixture-scoped method stubs and block-scoped constant stubs
|
|
884
918
|
- suite hooks with `around_suite`
|
|
885
919
|
- test hooks with `around_test`
|
|
886
920
|
- skipped and pending tests through `skip` and `pending`
|
data/SMARTEST_DESIGN.md
CHANGED
|
@@ -856,7 +856,24 @@ If no paths are given:
|
|
|
856
856
|
bundle exec smartest
|
|
857
857
|
```
|
|
858
858
|
|
|
859
|
-
should default to
|
|
859
|
+
should default to `smartest/**/*_test.rb` when `smartest/` exists. If the
|
|
860
|
+
directory does not exist, the CLI should print scaffold guidance and exit with
|
|
861
|
+
status `1`:
|
|
862
|
+
|
|
863
|
+
```text
|
|
864
|
+
No smartest/ directory found.
|
|
865
|
+
|
|
866
|
+
To create a Smartest test scaffold:
|
|
867
|
+
bundle exec smartest --init
|
|
868
|
+
|
|
869
|
+
For browser tests:
|
|
870
|
+
bundle exec smartest --init-browser
|
|
871
|
+
|
|
872
|
+
See all commands:
|
|
873
|
+
bundle exec smartest --help
|
|
874
|
+
```
|
|
875
|
+
|
|
876
|
+
Default paths:
|
|
860
877
|
|
|
861
878
|
```text
|
|
862
879
|
smartest/**/*_test.rb
|
|
@@ -877,8 +894,8 @@ arguments.files.each { |file| load File.expand_path(file) }
|
|
|
877
894
|
exit Smartest::Runner.new(tests: arguments.select_tests(Smartest.suite.tests)).run
|
|
878
895
|
```
|
|
879
896
|
|
|
880
|
-
`Smartest::CLIArguments` should support file paths,
|
|
881
|
-
and `path:start-end` filters.
|
|
897
|
+
`Smartest::CLIArguments` should support file paths, directory paths, shell
|
|
898
|
+
globs, `path:line`, and `path:start-end` filters.
|
|
882
899
|
|
|
883
900
|
`smartest/autorun` should use `at_exit`.
|
|
884
901
|
|
data/exe/smartest
CHANGED
|
@@ -7,18 +7,51 @@ require "smartest"
|
|
|
7
7
|
|
|
8
8
|
usage = <<~USAGE
|
|
9
9
|
Usage:
|
|
10
|
-
smartest [
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
smartest
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
10
|
+
bundle exec smartest [options] [paths...]
|
|
11
|
+
|
|
12
|
+
Common commands:
|
|
13
|
+
bundle exec smartest
|
|
14
|
+
Run tests under smartest/**/*_test.rb
|
|
15
|
+
|
|
16
|
+
bundle exec smartest smartest/suite1/
|
|
17
|
+
Run test files matching smartest/suite1/**/*_test.rb
|
|
18
|
+
|
|
19
|
+
bundle exec smartest smartest/user_test.rb
|
|
20
|
+
Run one test file
|
|
21
|
+
|
|
22
|
+
bundle exec smartest smartest/user_test.rb:12
|
|
23
|
+
Run tests around line 12
|
|
24
|
+
|
|
25
|
+
bundle exec smartest --init
|
|
26
|
+
Generate a basic Smartest scaffold
|
|
27
|
+
|
|
28
|
+
bundle exec smartest --init-browser
|
|
29
|
+
Generate a Playwright browser-test scaffold
|
|
30
|
+
|
|
31
|
+
Options:
|
|
32
|
+
--profile N
|
|
33
|
+
Print the N slowest tests. Defaults to 5.
|
|
34
|
+
|
|
35
|
+
--version, -v
|
|
36
|
+
Print the installed Smartest version.
|
|
37
|
+
|
|
38
|
+
--help, -h
|
|
39
|
+
Print this help.
|
|
20
40
|
USAGE
|
|
21
41
|
|
|
42
|
+
missing_smartest_directory_message = <<~MESSAGE
|
|
43
|
+
No smartest/ directory found.
|
|
44
|
+
|
|
45
|
+
To create a Smartest test scaffold:
|
|
46
|
+
bundle exec smartest --init
|
|
47
|
+
|
|
48
|
+
For browser tests:
|
|
49
|
+
bundle exec smartest --init-browser
|
|
50
|
+
|
|
51
|
+
See all commands:
|
|
52
|
+
bundle exec smartest --help
|
|
53
|
+
MESSAGE
|
|
54
|
+
|
|
22
55
|
command = :run
|
|
23
56
|
|
|
24
57
|
begin
|
|
@@ -45,10 +78,16 @@ begin
|
|
|
45
78
|
Smartest.disable_autorun!
|
|
46
79
|
Smartest.install_dsl!
|
|
47
80
|
test_load_path = File.expand_path("smartest", Dir.pwd)
|
|
48
|
-
$LOAD_PATH.unshift(test_load_path) if Dir.exist?(test_load_path) && !$LOAD_PATH.include?(test_load_path)
|
|
49
81
|
|
|
50
82
|
arguments = Smartest::CLIArguments.new(ARGV)
|
|
51
83
|
|
|
84
|
+
if arguments.default_paths? && !Dir.exist?(test_load_path)
|
|
85
|
+
puts missing_smartest_directory_message
|
|
86
|
+
exit 1
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
$LOAD_PATH.unshift(test_load_path) if Dir.exist?(test_load_path) && !$LOAD_PATH.include?(test_load_path)
|
|
90
|
+
|
|
52
91
|
arguments.files.each do |file|
|
|
53
92
|
load File.expand_path(file)
|
|
54
93
|
end
|
|
@@ -5,6 +5,7 @@ require "set"
|
|
|
5
5
|
module Smartest
|
|
6
6
|
class CLIArguments
|
|
7
7
|
DEFAULT_PROFILE_COUNT = 5
|
|
8
|
+
DEFAULT_PATHS = ["smartest/**/*_test.rb"].freeze
|
|
8
9
|
|
|
9
10
|
attr_reader :files, :line_filters, :profile_count
|
|
10
11
|
|
|
@@ -13,15 +14,25 @@ module Smartest
|
|
|
13
14
|
@whole_files = Set.new
|
|
14
15
|
@line_filters = Hash.new { |hash, key| hash[key] = Set.new }
|
|
15
16
|
@profile_count = DEFAULT_PROFILE_COUNT
|
|
17
|
+
@default_paths = false
|
|
16
18
|
|
|
17
19
|
paths = extract_options(argv)
|
|
18
|
-
|
|
20
|
+
if paths.empty?
|
|
21
|
+
@default_paths = true
|
|
22
|
+
paths = DEFAULT_PATHS
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
parse_paths(paths)
|
|
19
26
|
end
|
|
20
27
|
|
|
21
28
|
def filter_tests?
|
|
22
29
|
@line_filters.any?
|
|
23
30
|
end
|
|
24
31
|
|
|
32
|
+
def default_paths?
|
|
33
|
+
@default_paths
|
|
34
|
+
end
|
|
35
|
+
|
|
25
36
|
def select_tests(tests)
|
|
26
37
|
return tests unless filter_tests?
|
|
27
38
|
|
|
@@ -64,8 +75,7 @@ module Smartest
|
|
|
64
75
|
def parse_paths(paths)
|
|
65
76
|
paths.each do |argument|
|
|
66
77
|
pattern, line_filter = split_line_filter(argument)
|
|
67
|
-
|
|
68
|
-
files = matches.empty? ? [pattern] : matches
|
|
78
|
+
files = expand_path_pattern(pattern)
|
|
69
79
|
|
|
70
80
|
files.each do |file|
|
|
71
81
|
@files << file
|
|
@@ -82,6 +92,19 @@ module Smartest
|
|
|
82
92
|
@files.uniq!
|
|
83
93
|
end
|
|
84
94
|
|
|
95
|
+
def expand_path_pattern(pattern)
|
|
96
|
+
matches = Dir[pattern]
|
|
97
|
+
return [pattern] if matches.empty?
|
|
98
|
+
|
|
99
|
+
matches.flat_map do |match|
|
|
100
|
+
if File.directory?(match)
|
|
101
|
+
Dir[File.join(match, "**", "*_test.rb")]
|
|
102
|
+
else
|
|
103
|
+
match
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
85
108
|
def split_line_filter(argument)
|
|
86
109
|
match = argument.match(/\A(.+):(\d+)(?:-(\d+))?\z/)
|
|
87
110
|
return [argument, nil] unless match
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Smartest
|
|
4
|
+
module ConstantStubHelpers
|
|
5
|
+
private
|
|
6
|
+
|
|
7
|
+
def with_stub_const(constant_path, value)
|
|
8
|
+
raise ArgumentError, "with_stub_const block is required" unless block_given?
|
|
9
|
+
|
|
10
|
+
owner, constant_name = resolve_with_stub_constant(constant_path)
|
|
11
|
+
original_defined = owner.const_defined?(constant_name, false)
|
|
12
|
+
original_value = owner.const_get(constant_name, false) if original_defined
|
|
13
|
+
|
|
14
|
+
owner.__send__(:remove_const, constant_name) if original_defined
|
|
15
|
+
owner.const_set(constant_name, value)
|
|
16
|
+
|
|
17
|
+
yield
|
|
18
|
+
ensure
|
|
19
|
+
if owner && constant_name
|
|
20
|
+
owner.__send__(:remove_const, constant_name) if owner.const_defined?(constant_name, false)
|
|
21
|
+
owner.const_set(constant_name, original_value) if original_defined
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def resolve_with_stub_constant(constant_path)
|
|
26
|
+
unless constant_path.is_a?(String) || constant_path.is_a?(Symbol)
|
|
27
|
+
raise ArgumentError, "constant path must be a String or Symbol"
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
names = constant_path.to_s.split("::")
|
|
31
|
+
names.shift if names.first == ""
|
|
32
|
+
raise ArgumentError, "constant path must not be empty" if names.empty?
|
|
33
|
+
|
|
34
|
+
names.each do |name|
|
|
35
|
+
raise ArgumentError, "invalid constant path: #{constant_path}" unless name.match?(/\A[A-Z]\w*\z/)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
constant_name = names.pop.to_sym
|
|
39
|
+
owner = names.reduce(Object) { |namespace, name| namespace.const_get(name, false) }
|
|
40
|
+
raise ArgumentError, "constant owner must be a Module or Class" unless owner.is_a?(Module)
|
|
41
|
+
|
|
42
|
+
[owner, constant_name]
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
data/lib/smartest/fixture.rb
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
module Smartest
|
|
4
4
|
class Fixture
|
|
5
|
-
RESERVED_CONTEXT_METHODS = %i[skip pending].freeze
|
|
5
|
+
RESERVED_CONTEXT_METHODS = %i[skip pending with_stub_const].freeze
|
|
6
6
|
|
|
7
7
|
class << self
|
|
8
8
|
def fixture(name, scope: :test, &block)
|
|
@@ -73,48 +73,12 @@ module Smartest
|
|
|
73
73
|
apply_simple_stub(SimpleStub.new(object.singleton_class, method_name, &block))
|
|
74
74
|
end
|
|
75
75
|
|
|
76
|
-
def simple_stub_const(constant_path, value)
|
|
77
|
-
owner, constant_name = resolve_simple_stub_constant(constant_path)
|
|
78
|
-
original_defined = owner.const_defined?(constant_name, false)
|
|
79
|
-
original_value = owner.const_get(constant_name, false) if original_defined
|
|
80
|
-
|
|
81
|
-
owner.__send__(:remove_const, constant_name) if original_defined
|
|
82
|
-
owner.const_set(constant_name, value)
|
|
83
|
-
|
|
84
|
-
cleanup do
|
|
85
|
-
owner.__send__(:remove_const, constant_name) if owner.const_defined?(constant_name, false)
|
|
86
|
-
owner.const_set(constant_name, original_value) if original_defined
|
|
87
|
-
end
|
|
88
|
-
|
|
89
|
-
value
|
|
90
|
-
end
|
|
91
|
-
|
|
92
76
|
def apply_simple_stub(stub)
|
|
93
77
|
stub.apply!
|
|
94
78
|
cleanup { stub.reset }
|
|
95
79
|
stub
|
|
96
80
|
end
|
|
97
81
|
|
|
98
|
-
def resolve_simple_stub_constant(constant_path)
|
|
99
|
-
unless constant_path.is_a?(String) || constant_path.is_a?(Symbol)
|
|
100
|
-
raise ArgumentError, "constant path must be a String or Symbol"
|
|
101
|
-
end
|
|
102
|
-
|
|
103
|
-
names = constant_path.to_s.split("::")
|
|
104
|
-
names.shift if names.first == ""
|
|
105
|
-
raise ArgumentError, "constant path must not be empty" if names.empty?
|
|
106
|
-
|
|
107
|
-
names.each do |name|
|
|
108
|
-
raise ArgumentError, "invalid constant path: #{constant_path}" unless name.match?(/\A[A-Z]\w*\z/)
|
|
109
|
-
end
|
|
110
|
-
|
|
111
|
-
constant_name = names.pop.to_sym
|
|
112
|
-
owner = names.reduce(Object) { |namespace, name| namespace.const_get(name, false) }
|
|
113
|
-
raise ArgumentError, "constant owner must be a Module or Class" unless owner.is_a?(Module)
|
|
114
|
-
|
|
115
|
-
[owner, constant_name]
|
|
116
|
-
end
|
|
117
|
-
|
|
118
82
|
def method_missing(method_name, *args, &block)
|
|
119
83
|
return super if RESERVED_CONTEXT_METHODS.include?(method_name)
|
|
120
84
|
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
module Smartest
|
|
4
4
|
class AroundSuiteContext
|
|
5
|
+
include ConstantStubHelpers
|
|
6
|
+
|
|
5
7
|
def initialize(suite)
|
|
6
8
|
@suite = suite
|
|
7
9
|
end
|
|
@@ -30,6 +32,8 @@ module Smartest
|
|
|
30
32
|
end
|
|
31
33
|
|
|
32
34
|
class AroundTestContext
|
|
35
|
+
include ConstantStubHelpers
|
|
36
|
+
|
|
33
37
|
def initialize(test_run, run_state:)
|
|
34
38
|
@test_run = test_run
|
|
35
39
|
@run_state = run_state
|
data/lib/smartest/version.rb
CHANGED
data/lib/smartest.rb
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
require_relative "smartest/version"
|
|
4
4
|
require_relative "smartest/errors"
|
|
5
5
|
require_relative "smartest/simple_stub"
|
|
6
|
+
require_relative "smartest/constant_stub_helpers"
|
|
6
7
|
require_relative "smartest/parameter_extractor"
|
|
7
8
|
require_relative "smartest/test_case"
|
|
8
9
|
require_relative "smartest/test_registry"
|
|
@@ -158,64 +158,101 @@ test("simple_stub applies and resets singleton methods from fixture cleanup") do
|
|
|
158
158
|
expect(status).to eq(0)
|
|
159
159
|
end
|
|
160
160
|
|
|
161
|
-
test("
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
161
|
+
test("with_stub_const applies and resets existing constants in test body blocks") do
|
|
162
|
+
result = with_stub_const("SimpleStubSelfTestConfig::PROVIDER", :stubbed_provider) do
|
|
163
|
+
expect(SimpleStubSelfTestConfig::PROVIDER).to eq(:stubbed_provider)
|
|
164
|
+
:block_result
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
expect(result).to eq(:block_result)
|
|
168
|
+
expect(SimpleStubSelfTestConfig::PROVIDER).to eq(:original_provider)
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
test("with_stub_const removes newly defined constants after test body blocks") do
|
|
172
|
+
with_stub_const("SimpleStubSelfTestConfig::MISSING_PROVIDER", :stubbed_missing_provider) do
|
|
173
|
+
expect(SimpleStubSelfTestConfig::MISSING_PROVIDER).to eq(:stubbed_missing_provider)
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
expect(SimpleStubSelfTestConfig.const_defined?(:MISSING_PROVIDER, false)).to eq(false)
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
test("with_stub_const restores constants when the block raises") do
|
|
180
|
+
error = SimpleStubSelfTest.capture_error(RuntimeError) do
|
|
181
|
+
with_stub_const("SimpleStubSelfTestConfig::PROVIDER", :stubbed_provider) do
|
|
182
|
+
expect(SimpleStubSelfTestConfig::PROVIDER).to eq(:stubbed_provider)
|
|
183
|
+
raise "stubbed block failed"
|
|
165
184
|
end
|
|
166
185
|
end
|
|
167
186
|
|
|
187
|
+
expect(error.message).to eq("stubbed block failed")
|
|
188
|
+
expect(SimpleStubSelfTestConfig::PROVIDER).to eq(:original_provider)
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
test("with_stub_const requires a block") do
|
|
192
|
+
error = SimpleStubSelfTest.capture_error(ArgumentError) do
|
|
193
|
+
with_stub_const("SimpleStubSelfTestConfig::PROVIDER", :stubbed_provider)
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
expect(error.message).to eq("with_stub_const block is required")
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
test("with_stub_const wraps around_test hooks") do
|
|
168
200
|
suite = Smartest::Suite.new
|
|
169
|
-
suite.
|
|
201
|
+
suite.around_test_hooks << proc do |test_run|
|
|
202
|
+
with_stub_const("SimpleStubSelfTestConfig::PROVIDER", :around_test_provider) do
|
|
203
|
+
test_run.run
|
|
204
|
+
end
|
|
205
|
+
end
|
|
170
206
|
suite.tests.add(
|
|
171
207
|
SimpleStubSelfTest.test_case(
|
|
172
|
-
"uses constant stub
|
|
173
|
-
proc
|
|
174
|
-
expect(stubbed_provider).to eq(:stubbed_provider)
|
|
175
|
-
expect(SimpleStubSelfTestConfig::PROVIDER).to eq(:stubbed_provider)
|
|
176
|
-
end
|
|
208
|
+
"uses around_test constant stub",
|
|
209
|
+
proc { expect(SimpleStubSelfTestConfig::PROVIDER).to eq(:around_test_provider) }
|
|
177
210
|
)
|
|
178
211
|
)
|
|
212
|
+
|
|
213
|
+
status, = SimpleStubSelfTest.run_suite(suite)
|
|
214
|
+
|
|
215
|
+
expect(status).to eq(0)
|
|
216
|
+
expect(SimpleStubSelfTestConfig::PROVIDER).to eq(:original_provider)
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
test("with_stub_const wraps around_suite hooks") do
|
|
220
|
+
suite = Smartest::Suite.new
|
|
221
|
+
suite.around_suite_hooks << proc do |suite_run|
|
|
222
|
+
with_stub_const("SimpleStubSelfTestConfig::PROVIDER", :around_suite_provider) do
|
|
223
|
+
suite_run.run
|
|
224
|
+
end
|
|
225
|
+
end
|
|
179
226
|
suite.tests.add(
|
|
180
227
|
SimpleStubSelfTest.test_case(
|
|
181
|
-
"
|
|
182
|
-
proc { expect(SimpleStubSelfTestConfig::PROVIDER).to eq(:
|
|
228
|
+
"uses around_suite constant stub",
|
|
229
|
+
proc { expect(SimpleStubSelfTestConfig::PROVIDER).to eq(:around_suite_provider) }
|
|
183
230
|
)
|
|
184
231
|
)
|
|
185
232
|
|
|
186
233
|
status, = SimpleStubSelfTest.run_suite(suite)
|
|
187
234
|
|
|
188
235
|
expect(status).to eq(0)
|
|
236
|
+
expect(SimpleStubSelfTestConfig::PROVIDER).to eq(:original_provider)
|
|
189
237
|
end
|
|
190
238
|
|
|
191
|
-
test("
|
|
239
|
+
test("with_stub_const is not available inside fixture blocks") do
|
|
192
240
|
fixture_class = Class.new(Smartest::Fixture) do
|
|
193
|
-
fixture :
|
|
194
|
-
|
|
241
|
+
fixture :bad_constant_stub do
|
|
242
|
+
with_stub_const("SimpleStubSelfTestConfig::PROVIDER", :fixture_provider) { :fixture_provider }
|
|
195
243
|
end
|
|
196
244
|
end
|
|
197
245
|
|
|
198
246
|
suite = Smartest::Suite.new
|
|
199
247
|
suite.fixture_classes.add(fixture_class)
|
|
200
|
-
suite.tests.add(
|
|
201
|
-
SimpleStubSelfTest.test_case(
|
|
202
|
-
"uses new constant stub fixture",
|
|
203
|
-
proc do |stubbed_missing_provider:|
|
|
204
|
-
expect(stubbed_missing_provider).to eq(:stubbed_missing_provider)
|
|
205
|
-
expect(SimpleStubSelfTestConfig::MISSING_PROVIDER).to eq(:stubbed_missing_provider)
|
|
206
|
-
end
|
|
207
|
-
)
|
|
208
|
-
)
|
|
209
|
-
suite.tests.add(
|
|
210
|
-
SimpleStubSelfTest.test_case(
|
|
211
|
-
"sees removed constant",
|
|
212
|
-
proc { expect(SimpleStubSelfTestConfig.const_defined?(:MISSING_PROVIDER, false)).to eq(false) }
|
|
213
|
-
)
|
|
214
|
-
)
|
|
248
|
+
suite.tests.add(SimpleStubSelfTest.test_case("uses bad fixture", proc { |bad_constant_stub:| bad_constant_stub }))
|
|
215
249
|
|
|
216
|
-
status, = SimpleStubSelfTest.run_suite(suite)
|
|
250
|
+
status, output = SimpleStubSelfTest.run_suite(suite)
|
|
217
251
|
|
|
218
|
-
expect(status).to eq(
|
|
252
|
+
expect(status).to eq(1)
|
|
253
|
+
expect(output).to include("NoMethodError")
|
|
254
|
+
expect(output).to include("with_stub_const")
|
|
255
|
+
expect(SimpleStubSelfTestConfig::PROVIDER).to eq(:original_provider)
|
|
219
256
|
end
|
|
220
257
|
|
|
221
258
|
test("simple stub preserves receiver self and method blocks") do
|
data/smartest/smartest_test.rb
CHANGED
|
@@ -1435,6 +1435,44 @@ test("cli loads files and returns failure status") do
|
|
|
1435
1435
|
end
|
|
1436
1436
|
end
|
|
1437
1437
|
|
|
1438
|
+
test("cli expands directory paths to tests under that directory") do
|
|
1439
|
+
Dir.mktmpdir do |dir|
|
|
1440
|
+
smartest_dir = File.join(dir, "smartest")
|
|
1441
|
+
FileUtils.mkdir_p(File.join(smartest_dir, "nested"))
|
|
1442
|
+
File.write(File.join(smartest_dir, "test_helper.rb"), <<~RUBY)
|
|
1443
|
+
require "smartest/autorun"
|
|
1444
|
+
RUBY
|
|
1445
|
+
File.write(File.join(smartest_dir, "root_test.rb"), <<~RUBY)
|
|
1446
|
+
require "test_helper"
|
|
1447
|
+
|
|
1448
|
+
test("root directory test") do
|
|
1449
|
+
expect(1).to eq(1)
|
|
1450
|
+
end
|
|
1451
|
+
RUBY
|
|
1452
|
+
File.write(File.join(smartest_dir, "nested", "nested_test.rb"), <<~RUBY)
|
|
1453
|
+
require "test_helper"
|
|
1454
|
+
|
|
1455
|
+
test("nested directory test") do
|
|
1456
|
+
expect(2).to eq(2)
|
|
1457
|
+
end
|
|
1458
|
+
RUBY
|
|
1459
|
+
|
|
1460
|
+
stdout, stderr, status = Open3.capture3(
|
|
1461
|
+
{ "RUBYLIB" => File.expand_path("../lib", __dir__) },
|
|
1462
|
+
"ruby",
|
|
1463
|
+
File.expand_path("../exe/smartest", __dir__),
|
|
1464
|
+
"smartest/",
|
|
1465
|
+
chdir: dir
|
|
1466
|
+
)
|
|
1467
|
+
|
|
1468
|
+
expect(status.success?).to eq(true)
|
|
1469
|
+
expect(stderr).to eq("")
|
|
1470
|
+
expect(stdout).to include("root directory test")
|
|
1471
|
+
expect(stdout).to include("nested directory test")
|
|
1472
|
+
expect(stdout).to include("2 tests, 2 passed, 0 failed")
|
|
1473
|
+
end
|
|
1474
|
+
end
|
|
1475
|
+
|
|
1438
1476
|
test("cli loads matcher files registered in test helper") do
|
|
1439
1477
|
Dir.mktmpdir do |dir|
|
|
1440
1478
|
smartest_dir = File.join(dir, "smartest")
|
|
@@ -1656,14 +1694,61 @@ test("cli prints help") do
|
|
|
1656
1694
|
expect(status.success?).to eq(true)
|
|
1657
1695
|
expect(stderr).to eq("")
|
|
1658
1696
|
expect(stdout).to include("Usage:")
|
|
1659
|
-
expect(stdout).to include("smartest [
|
|
1660
|
-
expect(stdout).to include("
|
|
1661
|
-
expect(stdout).to include("smartest
|
|
1662
|
-
expect(stdout).to include("smartest
|
|
1663
|
-
expect(stdout).to include("
|
|
1697
|
+
expect(stdout).to include("bundle exec smartest [options] [paths...]")
|
|
1698
|
+
expect(stdout).to include("Common commands:")
|
|
1699
|
+
expect(stdout).to include("bundle exec smartest smartest/suite1/")
|
|
1700
|
+
expect(stdout).to include("Run test files matching smartest/suite1/**/*_test.rb")
|
|
1701
|
+
expect(stdout).to include("bundle exec smartest smartest/user_test.rb")
|
|
1702
|
+
expect(stdout).to include("bundle exec smartest smartest/user_test.rb:12")
|
|
1703
|
+
expect(stdout).not_to include("bundle exec smartest smartest/example_browser_test.rb")
|
|
1704
|
+
expect(stdout).not_to include("Run a browser test file")
|
|
1705
|
+
expect(stdout).to include("bundle exec smartest --init")
|
|
1706
|
+
expect(stdout).to include("bundle exec smartest --init-browser")
|
|
1707
|
+
expect(stdout).to include("--profile N")
|
|
1664
1708
|
expect(stdout).to include("smartest/**/*_test.rb")
|
|
1665
1709
|
end
|
|
1666
1710
|
|
|
1711
|
+
test("cli explains how to initialize when default smartest directory is missing") do
|
|
1712
|
+
Dir.mktmpdir do |dir|
|
|
1713
|
+
stdout, stderr, status = Open3.capture3(
|
|
1714
|
+
{ "RUBYLIB" => File.expand_path("../lib", __dir__) },
|
|
1715
|
+
"ruby",
|
|
1716
|
+
File.expand_path("../exe/smartest", __dir__),
|
|
1717
|
+
chdir: dir
|
|
1718
|
+
)
|
|
1719
|
+
|
|
1720
|
+
expect(status.success?).to eq(false)
|
|
1721
|
+
expect(stderr).to eq("")
|
|
1722
|
+
expect(stdout).to include("No smartest/ directory found.")
|
|
1723
|
+
expect(stdout).to include("bundle exec smartest --init")
|
|
1724
|
+
expect(stdout).to include("bundle exec smartest --init-browser")
|
|
1725
|
+
expect(stdout).to include("bundle exec smartest --help")
|
|
1726
|
+
end
|
|
1727
|
+
end
|
|
1728
|
+
|
|
1729
|
+
test("cli still runs explicit paths when default smartest directory is missing") do
|
|
1730
|
+
Dir.mktmpdir do |dir|
|
|
1731
|
+
File.write(File.join(dir, "sample_test.rb"), <<~RUBY)
|
|
1732
|
+
test("explicit path") do
|
|
1733
|
+
expect(1).to eq(1)
|
|
1734
|
+
end
|
|
1735
|
+
RUBY
|
|
1736
|
+
|
|
1737
|
+
stdout, stderr, status = Open3.capture3(
|
|
1738
|
+
{ "RUBYLIB" => File.expand_path("../lib", __dir__) },
|
|
1739
|
+
"ruby",
|
|
1740
|
+
File.expand_path("../exe/smartest", __dir__),
|
|
1741
|
+
"sample_test.rb",
|
|
1742
|
+
chdir: dir
|
|
1743
|
+
)
|
|
1744
|
+
|
|
1745
|
+
expect(status.success?).to eq(true)
|
|
1746
|
+
expect(stderr).to eq("")
|
|
1747
|
+
expect(stdout).to include("explicit path")
|
|
1748
|
+
expect(stdout).to include("1 test, 1 passed, 0 failed")
|
|
1749
|
+
end
|
|
1750
|
+
end
|
|
1751
|
+
|
|
1667
1752
|
test("--profile prints the slowest tests with default count of 5") do
|
|
1668
1753
|
output = StringIO.new
|
|
1669
1754
|
reporter = Smartest::Reporter.new(output, profile_count: 5)
|
|
@@ -1760,7 +1845,9 @@ test("CLIArguments defaults profile count and parses --profile N") do
|
|
|
1760
1845
|
|
|
1761
1846
|
expect(arguments.profile_count).to eq(5)
|
|
1762
1847
|
expect(arguments.files).to eq(Dir["smartest/**/*_test.rb"])
|
|
1848
|
+
expect(arguments.default_paths?).to eq(true)
|
|
1763
1849
|
expect(Smartest::CLIArguments.new(["--profile", "3"]).profile_count).to eq(3)
|
|
1850
|
+
expect(Smartest::CLIArguments.new(["smartest/foo_test.rb"]).default_paths?).to eq(false)
|
|
1764
1851
|
end
|
|
1765
1852
|
|
|
1766
1853
|
test("CLIArguments leaves unsupported profile forms as paths") do
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: smartest
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.4.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Yusuke Iwaki
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-05-
|
|
11
|
+
date: 2026-05-06 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rake
|
|
@@ -44,6 +44,7 @@ files:
|
|
|
44
44
|
- lib/smartest.rb
|
|
45
45
|
- lib/smartest/autorun.rb
|
|
46
46
|
- lib/smartest/cli_arguments.rb
|
|
47
|
+
- lib/smartest/constant_stub_helpers.rb
|
|
47
48
|
- lib/smartest/dsl.rb
|
|
48
49
|
- lib/smartest/errors.rb
|
|
49
50
|
- lib/smartest/execution_context.rb
|
|
@@ -96,9 +97,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
96
97
|
version: '2.7'
|
|
97
98
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
98
99
|
requirements:
|
|
99
|
-
- - "
|
|
100
|
+
- - ">="
|
|
100
101
|
- !ruby/object:Gem::Version
|
|
101
|
-
version:
|
|
102
|
+
version: '0'
|
|
102
103
|
requirements: []
|
|
103
104
|
rubygems_version: 3.4.19
|
|
104
105
|
signing_key:
|