smartest 0.3.3.alpha3 → 0.3.3.alpha4

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 46365bf842594d74023e6c47da5b98f28e2f8ad765a035de09a54f5d127db2ee
4
- data.tar.gz: 53134bcd0052d5cd8b495b36a9ba8bb1344c6dcb0626d0547dfa49bf6eff005e
3
+ metadata.gz: 75e3f0538afd3f490c37121ae4eee497a4691f35926ff50201e035acb64d2314
4
+ data.tar.gz: 53fea3bdbbb788167d13c6a7b6c18a9258de42b971c4f2a1f36906176f75813a
5
5
  SHA512:
6
- metadata.gz: a5ffe755697e79babe4e54e52d9a2e2a13aee1ade7306dfa7adffd7d9ea6ca75b7b96825b05c713261f420f35b28e980a85b068a94823109bffc0a54774d864a
7
- data.tar.gz: c030cd6bfcfb44f8273348f99a36a6213c237c9bd580cd49287351b4bf9b70a04af3b6b7889287f12ffbda747dfd7d6a450b9954bf51f8c2bdf5fb71768027ba
6
+ metadata.gz: ba646897bc5994e7caf30fc9b1127a1ad72f2545a4ed8734820c5eeeca3e5e1e7e0302394b38916fbc9d9c153dccfdae96496093dce1f23af172fa74a01cbd75
7
+ data.tar.gz: 5c12f0c3532da8eb44c3e832d28e479b1f8a54f5797a4c67c61c865bbbedf31e2225fe441c1f433d8de6ce3b2246c374de998d2aae9b2cfa8a7ea63f043ed949
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
data/README.md CHANGED
@@ -637,16 +637,16 @@ end
637
637
  ```
638
638
 
639
639
  Use `simple_stub(Time, :now) { fixed_time }` for singleton methods such as class
640
- methods. Use `simple_stub_const("AppConfig::PAYMENT_PROVIDER", "fake")` for
641
- constants. Constant stubs are process-global; avoid concurrent tests that stub
642
- the same constant.
640
+ methods.
641
+
642
+ Use `simple_stub_const("AppConfig::PAYMENT_PROVIDER", "fake") { ... }` for
643
+ constants in test bodies, `around_test`, or `around_suite`. Constant stubs are
644
+ process-global; avoid concurrent tests that stub the same constant.
643
645
 
644
646
  The method stub helpers call `Smartest::SimpleStub` internally, apply the stub,
645
647
  register `cleanup { stub.reset }`, and return the stub object.
646
- `simple_stub_const` records the previous constant value, replaces it, and
647
- restores or removes it during cleanup. These helpers are available inside
648
- `Smartest::Fixture` fixture blocks because they need cleanup to tie the stub
649
- lifetime to the fixture scope.
648
+ `simple_stub_const` records the previous constant value, replaces it, yields to
649
+ the block, and restores or removes the constant with `ensure`.
650
650
 
651
651
  `Smartest::SimpleStub#apply` and `#reset` are idempotent in the current Fiber.
652
652
  `apply!` raises
@@ -880,7 +880,7 @@ Smartest currently focuses on a small runner API:
880
880
  - fixture dependencies through keyword arguments
881
881
  - fixture cleanup
882
882
  - suite-scoped fixtures through `suite_fixture`
883
- - fixture-scoped method and constant stubs
883
+ - fixture-scoped method stubs and block-scoped constant stubs
884
884
  - suite hooks with `around_suite`
885
885
  - test hooks with `around_test`
886
886
  - skipped and pending tests through `skip` and `pending`
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Smartest
4
+ module ConstantStubHelpers
5
+ private
6
+
7
+ def simple_stub_const(constant_path, value)
8
+ raise ArgumentError, "simple_stub_const block is required" unless block_given?
9
+
10
+ owner, constant_name = resolve_simple_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_simple_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
@@ -4,6 +4,7 @@ module Smartest
4
4
  class ExecutionContext
5
5
  include Expectations
6
6
  include Matchers
7
+ include ConstantStubHelpers
7
8
 
8
9
  def initialize(run_state: TestRunState.new)
9
10
  @run_state = run_state
@@ -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 simple_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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Smartest
4
- VERSION = "0.3.3.alpha3"
4
+ VERSION = "0.3.3.alpha4"
5
5
  end
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("simple_stub_const applies and resets existing constants from fixture cleanup") do
162
- fixture_class = Class.new(Smartest::Fixture) do
163
- fixture :stubbed_provider do
164
- simple_stub_const("SimpleStubSelfTestConfig::PROVIDER", :stubbed_provider)
161
+ test("simple_stub_const applies and resets existing constants in test body blocks") do
162
+ result = simple_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("simple_stub_const removes newly defined constants after test body blocks") do
172
+ simple_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("simple_stub_const restores constants when the block raises") do
180
+ error = SimpleStubSelfTest.capture_error(RuntimeError) do
181
+ simple_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("simple_stub_const requires a block") do
192
+ error = SimpleStubSelfTest.capture_error(ArgumentError) do
193
+ simple_stub_const("SimpleStubSelfTestConfig::PROVIDER", :stubbed_provider)
194
+ end
195
+
196
+ expect(error.message).to eq("simple_stub_const block is required")
197
+ end
198
+
199
+ test("simple_stub_const wraps around_test hooks") do
168
200
  suite = Smartest::Suite.new
169
- suite.fixture_classes.add(fixture_class)
201
+ suite.around_test_hooks << proc do |test_run|
202
+ simple_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 fixture",
173
- proc do |stubbed_provider:|
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("simple_stub_const wraps around_suite hooks") do
220
+ suite = Smartest::Suite.new
221
+ suite.around_suite_hooks << proc do |suite_run|
222
+ simple_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
- "sees restored constant",
182
- proc { expect(SimpleStubSelfTestConfig::PROVIDER).to eq(:original_provider) }
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("simple_stub_const removes newly defined constants from fixture cleanup") do
239
+ test("simple_stub_const is not available inside fixture blocks") do
192
240
  fixture_class = Class.new(Smartest::Fixture) do
193
- fixture :stubbed_missing_provider do
194
- simple_stub_const("SimpleStubSelfTestConfig::MISSING_PROVIDER", :stubbed_missing_provider)
241
+ fixture :bad_constant_stub do
242
+ simple_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(0)
252
+ expect(status).to eq(1)
253
+ expect(output).to include("NoMethodError")
254
+ expect(output).to include("simple_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
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: smartest
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.3.alpha3
4
+ version: 0.3.3.alpha4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yusuke Iwaki
@@ -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