smartest 0.1.0.alpha3 → 0.2.0.alpha1
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 +46 -5
- data/README.md +132 -34
- data/SMARTEST_DESIGN.md +102 -10
- data/lib/smartest/dsl.rb +13 -6
- data/lib/smartest/errors.rb +16 -0
- data/lib/smartest/hook_contexts.rb +51 -0
- data/lib/smartest/init_generator.rb +4 -1
- data/lib/smartest/reporter.rb +18 -1
- data/lib/smartest/runner.rb +78 -14
- data/lib/smartest/suite.rb +34 -1
- data/lib/smartest/suite_run.rb +24 -0
- data/lib/smartest/test_case.rb +3 -2
- data/lib/smartest/test_run.rb +58 -0
- data/lib/smartest/version.rb +1 -1
- data/lib/smartest.rb +3 -0
- data/smartest/smartest_test.rb +309 -4
- metadata +4 -1
data/lib/smartest/runner.rb
CHANGED
|
@@ -11,10 +11,33 @@ module Smartest
|
|
|
11
11
|
def run
|
|
12
12
|
results = []
|
|
13
13
|
suite_cleanup_errors = []
|
|
14
|
+
suite_errors = []
|
|
14
15
|
@suite_fixture_set = nil
|
|
15
16
|
|
|
16
17
|
@reporter.start(@tests.count)
|
|
17
18
|
|
|
19
|
+
begin
|
|
20
|
+
run_around_suite_hooks(@suite.around_suite_hooks.dup) do
|
|
21
|
+
run_tests(results, suite_cleanup_errors)
|
|
22
|
+
end
|
|
23
|
+
rescue Exception => error
|
|
24
|
+
raise if Smartest.fatal_exception?(error)
|
|
25
|
+
|
|
26
|
+
suite_errors << error
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
@reporter.finish(
|
|
30
|
+
results,
|
|
31
|
+
suite_cleanup_errors: suite_cleanup_errors,
|
|
32
|
+
suite_errors: suite_errors
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
results.any?(&:failed?) || suite_cleanup_errors.any? || suite_errors.any? ? 1 : 0
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
private
|
|
39
|
+
|
|
40
|
+
def run_tests(results, suite_cleanup_errors)
|
|
18
41
|
begin
|
|
19
42
|
@tests.each do |test_case|
|
|
20
43
|
result = run_one(test_case)
|
|
@@ -22,34 +45,42 @@ module Smartest
|
|
|
22
45
|
@reporter.record(result)
|
|
23
46
|
end
|
|
24
47
|
ensure
|
|
25
|
-
suite_cleanup_errors
|
|
48
|
+
suite_cleanup_errors.concat(@suite_fixture_set.run_cleanups) if @suite_fixture_set
|
|
26
49
|
@suite_fixture_set = nil
|
|
27
50
|
end
|
|
51
|
+
end
|
|
28
52
|
|
|
29
|
-
|
|
53
|
+
def run_around_suite_hooks(hooks, index = 0, &block)
|
|
54
|
+
return yield if index >= hooks.length
|
|
30
55
|
|
|
31
|
-
|
|
32
|
-
|
|
56
|
+
hook = hooks[index]
|
|
57
|
+
suite_run = SuiteRun.new do
|
|
58
|
+
run_around_suite_hooks(hooks, index + 1, &block)
|
|
59
|
+
end
|
|
33
60
|
|
|
34
|
-
|
|
61
|
+
AroundSuiteContext.new(@suite).call(hook, suite_run)
|
|
62
|
+
raise AroundSuiteRunError, "around_suite hook did not call suite.run" unless suite_run.ran?
|
|
63
|
+
|
|
64
|
+
suite_run.result
|
|
65
|
+
end
|
|
35
66
|
|
|
36
67
|
def run_one(test_case)
|
|
37
68
|
started_at = now
|
|
38
|
-
context = build_context
|
|
39
|
-
fixture_set = nil
|
|
40
69
|
error = nil
|
|
41
70
|
cleanup_errors = []
|
|
71
|
+
test_run = TestRun.new(
|
|
72
|
+
fixture_classes: @suite.fixture_classes,
|
|
73
|
+
matcher_modules: @suite.matcher_modules
|
|
74
|
+
) do |fixture_classes:, matcher_modules:|
|
|
75
|
+
cleanup_errors = run_test_body(test_case, fixture_classes, matcher_modules)
|
|
76
|
+
end
|
|
42
77
|
|
|
43
78
|
begin
|
|
44
|
-
|
|
45
|
-
fixtures = fixture_set.resolve_keywords(test_case.fixture_names)
|
|
46
|
-
context.instance_exec(**fixtures, &test_case.block)
|
|
79
|
+
run_around_test_hooks(@suite.around_test_hooks + test_case.around_test_hooks, test_run)
|
|
47
80
|
rescue Exception => rescued_error
|
|
48
81
|
raise if Smartest.fatal_exception?(rescued_error)
|
|
49
82
|
|
|
50
83
|
error = rescued_error
|
|
51
|
-
ensure
|
|
52
|
-
cleanup_errors = fixture_set.run_cleanups if fixture_set
|
|
53
84
|
end
|
|
54
85
|
|
|
55
86
|
duration = now - started_at
|
|
@@ -66,6 +97,39 @@ module Smartest
|
|
|
66
97
|
end
|
|
67
98
|
end
|
|
68
99
|
|
|
100
|
+
def run_test_body(test_case, fixture_classes, matcher_modules)
|
|
101
|
+
context = build_context(matcher_modules)
|
|
102
|
+
fixture_set = nil
|
|
103
|
+
cleanup_errors = []
|
|
104
|
+
|
|
105
|
+
begin
|
|
106
|
+
fixture_set = FixtureSet.new(fixture_classes, context: context, parent: suite_fixture_set)
|
|
107
|
+
fixtures = fixture_set.resolve_keywords(test_case.fixture_names)
|
|
108
|
+
context.instance_exec(**fixtures, &test_case.block)
|
|
109
|
+
ensure
|
|
110
|
+
cleanup_errors = fixture_set.run_cleanups if fixture_set
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
cleanup_errors
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def run_around_test_hooks(hooks, test_run, index = 0)
|
|
117
|
+
return test_run.run if index >= hooks.length
|
|
118
|
+
|
|
119
|
+
hook = hooks[index]
|
|
120
|
+
next_run = TestRun.new(
|
|
121
|
+
fixture_classes: [],
|
|
122
|
+
matcher_modules: []
|
|
123
|
+
) do |**_keywords|
|
|
124
|
+
run_around_test_hooks(hooks, test_run, index + 1)
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
AroundTestContext.new(test_run).call(hook, next_run)
|
|
128
|
+
raise AroundTestRunError, "around_test hook did not call test.run" unless next_run.ran?
|
|
129
|
+
|
|
130
|
+
next_run.result
|
|
131
|
+
end
|
|
132
|
+
|
|
69
133
|
def suite_fixture_set
|
|
70
134
|
@suite_fixture_set ||= FixtureSet.new(
|
|
71
135
|
@suite.fixture_classes,
|
|
@@ -74,9 +138,9 @@ module Smartest
|
|
|
74
138
|
)
|
|
75
139
|
end
|
|
76
140
|
|
|
77
|
-
def build_context
|
|
141
|
+
def build_context(matcher_modules = @suite.matcher_modules)
|
|
78
142
|
ExecutionContext.new.tap do |context|
|
|
79
|
-
|
|
143
|
+
matcher_modules.each { |matcher_module| context.extend(matcher_module) }
|
|
80
144
|
end
|
|
81
145
|
end
|
|
82
146
|
|
data/lib/smartest/suite.rb
CHANGED
|
@@ -2,12 +2,45 @@
|
|
|
2
2
|
|
|
3
3
|
module Smartest
|
|
4
4
|
class Suite
|
|
5
|
-
attr_reader :tests, :fixture_classes, :matcher_modules
|
|
5
|
+
attr_reader :tests, :fixture_classes, :matcher_modules, :around_suite_hooks, :around_test_hooks
|
|
6
6
|
|
|
7
7
|
def initialize
|
|
8
8
|
@tests = TestRegistry.new
|
|
9
9
|
@fixture_classes = FixtureClassRegistry.new
|
|
10
10
|
@matcher_modules = MatcherRegistry.new
|
|
11
|
+
@around_suite_hooks = []
|
|
12
|
+
@around_test_hooks = []
|
|
13
|
+
@around_test_hooks_by_file = Hash.new { |hash, path| hash[path] = [] }
|
|
14
|
+
@around_suite_hook_depth = 0
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def add_around_test_hook(location, hook)
|
|
18
|
+
if running_around_suite_hook?
|
|
19
|
+
@around_test_hooks << hook
|
|
20
|
+
else
|
|
21
|
+
@around_test_hooks_by_file[path_for(location)] << hook
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def around_test_hooks_for(location)
|
|
26
|
+
@around_test_hooks_by_file[path_for(location)].dup
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def around_suite_hook
|
|
30
|
+
@around_suite_hook_depth += 1
|
|
31
|
+
yield
|
|
32
|
+
ensure
|
|
33
|
+
@around_suite_hook_depth -= 1
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
private
|
|
37
|
+
|
|
38
|
+
def running_around_suite_hook?
|
|
39
|
+
@around_suite_hook_depth.positive?
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def path_for(location)
|
|
43
|
+
File.expand_path(location.absolute_path || location.path)
|
|
11
44
|
end
|
|
12
45
|
end
|
|
13
46
|
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Smartest
|
|
4
|
+
class SuiteRun
|
|
5
|
+
attr_reader :result
|
|
6
|
+
|
|
7
|
+
def initialize(&block)
|
|
8
|
+
@block = block
|
|
9
|
+
@ran = false
|
|
10
|
+
@result = nil
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def run
|
|
14
|
+
raise AroundSuiteRunError, "around_suite hook called suite.run more than once" if ran?
|
|
15
|
+
|
|
16
|
+
@ran = true
|
|
17
|
+
@result = @block.call
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def ran?
|
|
21
|
+
@ran
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
data/lib/smartest/test_case.rb
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
module Smartest
|
|
4
4
|
class TestCase
|
|
5
|
-
attr_reader :name, :metadata, :block, :location, :fixture_names
|
|
5
|
+
attr_reader :name, :metadata, :block, :location, :fixture_names, :around_test_hooks
|
|
6
6
|
|
|
7
|
-
def initialize(name:, metadata:, block:, location:)
|
|
7
|
+
def initialize(name:, metadata:, block:, location:, around_test_hooks: [])
|
|
8
8
|
raise ArgumentError, "test name is required" if name.nil? || name.to_s.empty?
|
|
9
9
|
raise ArgumentError, "test block is required" unless block
|
|
10
10
|
|
|
@@ -12,6 +12,7 @@ module Smartest
|
|
|
12
12
|
@metadata = metadata
|
|
13
13
|
@block = block
|
|
14
14
|
@location = location
|
|
15
|
+
@around_test_hooks = around_test_hooks.dup.freeze
|
|
15
16
|
@fixture_names = ParameterExtractor.required_keyword_names(block, usage: :test)
|
|
16
17
|
end
|
|
17
18
|
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Smartest
|
|
4
|
+
class TestRun
|
|
5
|
+
attr_reader :result
|
|
6
|
+
|
|
7
|
+
def initialize(fixture_classes:, matcher_modules:, &block)
|
|
8
|
+
@fixture_classes = FixtureClassRegistry.new
|
|
9
|
+
fixture_classes.each { |fixture_class| @fixture_classes.add(fixture_class) }
|
|
10
|
+
|
|
11
|
+
@matcher_modules = MatcherRegistry.new
|
|
12
|
+
matcher_modules.each { |matcher_module| @matcher_modules.add(matcher_module) }
|
|
13
|
+
|
|
14
|
+
@block = block
|
|
15
|
+
@ran = false
|
|
16
|
+
@result = nil
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def run
|
|
20
|
+
raise AroundTestRunError, "around_test hook called test.run more than once" if ran?
|
|
21
|
+
|
|
22
|
+
@ran = true
|
|
23
|
+
@result = @block.call(
|
|
24
|
+
fixture_classes: @fixture_classes,
|
|
25
|
+
matcher_modules: @matcher_modules
|
|
26
|
+
)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def ran?
|
|
30
|
+
@ran
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def add_fixture_class(klass)
|
|
34
|
+
raise AroundTestRunError, "use_fixture must be called before test.run" if ran?
|
|
35
|
+
|
|
36
|
+
reject_suite_fixture_class!(klass)
|
|
37
|
+
@fixture_classes.add(klass)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def add_matcher_module(matcher_module)
|
|
41
|
+
raise AroundTestRunError, "use_matcher must be called before test.run" if ran?
|
|
42
|
+
|
|
43
|
+
@matcher_modules.add(matcher_module)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
private
|
|
47
|
+
|
|
48
|
+
def reject_suite_fixture_class!(klass)
|
|
49
|
+
return unless klass.is_a?(Class) && klass <= Fixture
|
|
50
|
+
|
|
51
|
+
suite_fixture_names = klass.fixture_definitions.each_value.filter_map do |definition|
|
|
52
|
+
definition.name if definition.scope == :suite
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
raise AroundTestFixtureScopeError.new(klass, suite_fixture_names) if suite_fixture_names.any?
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
data/lib/smartest/version.rb
CHANGED
data/lib/smartest.rb
CHANGED
|
@@ -11,6 +11,9 @@ require_relative "smartest/fixture_class_registry"
|
|
|
11
11
|
require_relative "smartest/matcher_registry"
|
|
12
12
|
require_relative "smartest/fixture_set"
|
|
13
13
|
require_relative "smartest/suite"
|
|
14
|
+
require_relative "smartest/suite_run"
|
|
15
|
+
require_relative "smartest/test_run"
|
|
16
|
+
require_relative "smartest/hook_contexts"
|
|
14
17
|
require_relative "smartest/expectations"
|
|
15
18
|
require_relative "smartest/expectation_target"
|
|
16
19
|
require_relative "smartest/matchers"
|
data/smartest/smartest_test.rb
CHANGED
|
@@ -48,7 +48,10 @@ class SelfTestRegisteredFixture < Smartest::Fixture
|
|
|
48
48
|
end
|
|
49
49
|
end
|
|
50
50
|
|
|
51
|
-
|
|
51
|
+
around_suite do |suite|
|
|
52
|
+
use_fixture SelfTestRegisteredFixture
|
|
53
|
+
suite.run
|
|
54
|
+
end
|
|
52
55
|
|
|
53
56
|
test("registers fixture classes with use_fixture") do |registered_user_name:|
|
|
54
57
|
expect(registered_user_name).to eq("Alice")
|
|
@@ -326,6 +329,298 @@ test("suite fixture setup failures are cached and cleaned up once") do
|
|
|
326
329
|
expect(output.scan("RuntimeError: server setup failed").length).to eq(2)
|
|
327
330
|
end
|
|
328
331
|
|
|
332
|
+
test("around_suite wraps tests and suite fixture cleanup") do
|
|
333
|
+
events = []
|
|
334
|
+
|
|
335
|
+
fixture_class = Class.new(Smartest::Fixture) do
|
|
336
|
+
suite_fixture :server do
|
|
337
|
+
events << :server_setup
|
|
338
|
+
cleanup { events << :server_cleanup }
|
|
339
|
+
:server
|
|
340
|
+
end
|
|
341
|
+
end
|
|
342
|
+
|
|
343
|
+
suite = Smartest::Suite.new
|
|
344
|
+
suite.fixture_classes.add(fixture_class)
|
|
345
|
+
suite.around_suite_hooks << proc do |suite_run|
|
|
346
|
+
events << :around_before
|
|
347
|
+
suite_run.run
|
|
348
|
+
events << :around_after
|
|
349
|
+
end
|
|
350
|
+
suite.tests.add(SmartestSelfTest.test_case("uses server", proc { |server:| events << :test; expect(server).to eq(:server) }))
|
|
351
|
+
|
|
352
|
+
status, = SmartestSelfTest.run_suite(suite)
|
|
353
|
+
|
|
354
|
+
expect(status).to eq(0)
|
|
355
|
+
expect(events).to eq(%i[around_before server_setup test server_cleanup around_after])
|
|
356
|
+
end
|
|
357
|
+
|
|
358
|
+
test("around_suite hooks run in registration order") do
|
|
359
|
+
events = []
|
|
360
|
+
suite = Smartest::Suite.new
|
|
361
|
+
|
|
362
|
+
suite.around_suite_hooks << proc do |suite_run|
|
|
363
|
+
events << :outer_before
|
|
364
|
+
suite_run.run
|
|
365
|
+
events << :outer_after
|
|
366
|
+
end
|
|
367
|
+
suite.around_suite_hooks << proc do |suite_run|
|
|
368
|
+
events << :inner_before
|
|
369
|
+
suite_run.run
|
|
370
|
+
events << :inner_after
|
|
371
|
+
end
|
|
372
|
+
suite.tests.add(SmartestSelfTest.test_case("passes", proc { events << :test }))
|
|
373
|
+
|
|
374
|
+
status, = SmartestSelfTest.run_suite(suite)
|
|
375
|
+
|
|
376
|
+
expect(status).to eq(0)
|
|
377
|
+
expect(events).to eq(%i[outer_before inner_before test inner_after outer_after])
|
|
378
|
+
end
|
|
379
|
+
|
|
380
|
+
test("around_suite can register fixtures before running tests") do
|
|
381
|
+
fixture_class = Class.new(Smartest::Fixture) do
|
|
382
|
+
fixture :user_name do
|
|
383
|
+
"Alice"
|
|
384
|
+
end
|
|
385
|
+
end
|
|
386
|
+
|
|
387
|
+
suite = Smartest::Suite.new
|
|
388
|
+
suite.around_suite_hooks << proc do |suite_run|
|
|
389
|
+
use_fixture fixture_class
|
|
390
|
+
suite_run.run
|
|
391
|
+
end
|
|
392
|
+
suite.tests.add(SmartestSelfTest.test_case("uses runtime fixture", proc { |user_name:| expect(user_name).to eq("Alice") }))
|
|
393
|
+
|
|
394
|
+
status, = SmartestSelfTest.run_suite(suite)
|
|
395
|
+
|
|
396
|
+
expect(status).to eq(0)
|
|
397
|
+
end
|
|
398
|
+
|
|
399
|
+
test("around_suite can register suite-wide around_test hooks") do
|
|
400
|
+
events = []
|
|
401
|
+
suite = Smartest::Suite.new
|
|
402
|
+
|
|
403
|
+
suite.around_suite_hooks << proc do |suite_run|
|
|
404
|
+
around_test do |test_run|
|
|
405
|
+
events << :around_test_before
|
|
406
|
+
test_run.run
|
|
407
|
+
events << :around_test_after
|
|
408
|
+
end
|
|
409
|
+
|
|
410
|
+
suite_run.run
|
|
411
|
+
end
|
|
412
|
+
suite.tests.add(SmartestSelfTest.test_case("passes", proc { events << :test }))
|
|
413
|
+
|
|
414
|
+
status, = SmartestSelfTest.run_suite(suite)
|
|
415
|
+
|
|
416
|
+
expect(status).to eq(0)
|
|
417
|
+
expect(events).to eq(%i[around_test_before test around_test_after])
|
|
418
|
+
end
|
|
419
|
+
|
|
420
|
+
test("around_test wraps fixture setup, test body, and cleanup") do
|
|
421
|
+
events = []
|
|
422
|
+
|
|
423
|
+
fixture_class = Class.new(Smartest::Fixture) do
|
|
424
|
+
fixture :resource do
|
|
425
|
+
events << :fixture_setup
|
|
426
|
+
cleanup { events << :fixture_cleanup }
|
|
427
|
+
:resource
|
|
428
|
+
end
|
|
429
|
+
end
|
|
430
|
+
|
|
431
|
+
suite = Smartest::Suite.new
|
|
432
|
+
suite.fixture_classes.add(fixture_class)
|
|
433
|
+
suite.tests.add(
|
|
434
|
+
Smartest::TestCase.new(
|
|
435
|
+
name: "uses resource",
|
|
436
|
+
metadata: {},
|
|
437
|
+
location: caller_locations(1, 1).first,
|
|
438
|
+
around_test_hooks: [
|
|
439
|
+
proc do |test_run|
|
|
440
|
+
events << :around_test_before
|
|
441
|
+
test_run.run
|
|
442
|
+
events << :around_test_after
|
|
443
|
+
end
|
|
444
|
+
],
|
|
445
|
+
block: proc { |resource:| events << :test; expect(resource).to eq(:resource) }
|
|
446
|
+
)
|
|
447
|
+
)
|
|
448
|
+
|
|
449
|
+
status, = SmartestSelfTest.run_suite(suite)
|
|
450
|
+
|
|
451
|
+
expect(status).to eq(0)
|
|
452
|
+
expect(events).to eq(%i[around_test_before fixture_setup test fixture_cleanup around_test_after])
|
|
453
|
+
end
|
|
454
|
+
|
|
455
|
+
test("around_test can register fixtures for one test run") do
|
|
456
|
+
fixture_class = Class.new(Smartest::Fixture) do
|
|
457
|
+
fixture :local_value do
|
|
458
|
+
"local"
|
|
459
|
+
end
|
|
460
|
+
end
|
|
461
|
+
|
|
462
|
+
suite = Smartest::Suite.new
|
|
463
|
+
suite.tests.add(
|
|
464
|
+
Smartest::TestCase.new(
|
|
465
|
+
name: "uses local fixture",
|
|
466
|
+
metadata: {},
|
|
467
|
+
location: caller_locations(1, 1).first,
|
|
468
|
+
around_test_hooks: [
|
|
469
|
+
proc do |test_run|
|
|
470
|
+
use_fixture fixture_class
|
|
471
|
+
test_run.run
|
|
472
|
+
end
|
|
473
|
+
],
|
|
474
|
+
block: proc { |local_value:| expect(local_value).to eq("local") }
|
|
475
|
+
)
|
|
476
|
+
)
|
|
477
|
+
|
|
478
|
+
status, = SmartestSelfTest.run_suite(suite)
|
|
479
|
+
|
|
480
|
+
expect(status).to eq(0)
|
|
481
|
+
end
|
|
482
|
+
|
|
483
|
+
test("around_test rejects fixture classes with suite fixtures") do
|
|
484
|
+
fixture_class = Class.new(Smartest::Fixture) do
|
|
485
|
+
suite_fixture :server do
|
|
486
|
+
:server
|
|
487
|
+
end
|
|
488
|
+
end
|
|
489
|
+
|
|
490
|
+
suite = Smartest::Suite.new
|
|
491
|
+
suite.tests.add(
|
|
492
|
+
Smartest::TestCase.new(
|
|
493
|
+
name: "rejects local suite fixture",
|
|
494
|
+
metadata: {},
|
|
495
|
+
location: caller_locations(1, 1).first,
|
|
496
|
+
around_test_hooks: [
|
|
497
|
+
proc do |test_run|
|
|
498
|
+
use_fixture fixture_class
|
|
499
|
+
test_run.run
|
|
500
|
+
end
|
|
501
|
+
],
|
|
502
|
+
block: proc { |server:| expect(server).to eq(:server) }
|
|
503
|
+
)
|
|
504
|
+
)
|
|
505
|
+
|
|
506
|
+
status, output = SmartestSelfTest.run_suite(suite)
|
|
507
|
+
|
|
508
|
+
expect(status).to eq(1)
|
|
509
|
+
expect(output).to include("Smartest::AroundTestFixtureScopeError")
|
|
510
|
+
expect(output).to include("cannot be registered from around_test")
|
|
511
|
+
expect(output).to include("suite-scoped fixtures: :server")
|
|
512
|
+
expect(output).to include("Register fixture classes with suite_fixture from around_suite instead.")
|
|
513
|
+
end
|
|
514
|
+
|
|
515
|
+
test("around_test can register matchers for one test run") do
|
|
516
|
+
matcher_module = Module.new do
|
|
517
|
+
define_method(:equal_local) do |expected|
|
|
518
|
+
Class.new do
|
|
519
|
+
define_method(:initialize) { |value| @expected = value }
|
|
520
|
+
define_method(:matches?) { |actual| actual == @expected }
|
|
521
|
+
define_method(:failure_message) { "expected value to match" }
|
|
522
|
+
define_method(:negated_failure_message) { "expected value not to match" }
|
|
523
|
+
end.new(expected)
|
|
524
|
+
end
|
|
525
|
+
end
|
|
526
|
+
|
|
527
|
+
suite = Smartest::Suite.new
|
|
528
|
+
suite.tests.add(
|
|
529
|
+
Smartest::TestCase.new(
|
|
530
|
+
name: "uses local matcher",
|
|
531
|
+
metadata: {},
|
|
532
|
+
location: caller_locations(1, 1).first,
|
|
533
|
+
around_test_hooks: [
|
|
534
|
+
proc do |test_run|
|
|
535
|
+
use_matcher matcher_module
|
|
536
|
+
test_run.run
|
|
537
|
+
end
|
|
538
|
+
],
|
|
539
|
+
block: proc { expect("local").to equal_local("local") }
|
|
540
|
+
)
|
|
541
|
+
)
|
|
542
|
+
|
|
543
|
+
status, = SmartestSelfTest.run_suite(suite)
|
|
544
|
+
|
|
545
|
+
expect(status).to eq(0)
|
|
546
|
+
end
|
|
547
|
+
|
|
548
|
+
test("around_test must call test.run") do
|
|
549
|
+
suite = Smartest::Suite.new
|
|
550
|
+
suite.tests.add(
|
|
551
|
+
Smartest::TestCase.new(
|
|
552
|
+
name: "not reached",
|
|
553
|
+
metadata: {},
|
|
554
|
+
location: caller_locations(1, 1).first,
|
|
555
|
+
around_test_hooks: [proc { |_test_run| nil }],
|
|
556
|
+
block: proc { expect(true).to eq(false) }
|
|
557
|
+
)
|
|
558
|
+
)
|
|
559
|
+
|
|
560
|
+
status, output = SmartestSelfTest.run_suite(suite)
|
|
561
|
+
|
|
562
|
+
expect(status).to eq(1)
|
|
563
|
+
expect(output).to include("Smartest::AroundTestRunError: around_test hook did not call test.run")
|
|
564
|
+
end
|
|
565
|
+
|
|
566
|
+
test("use_fixture and use_matcher are only available inside hooks") do
|
|
567
|
+
{
|
|
568
|
+
"use_fixture Object" => "use_fixture",
|
|
569
|
+
"use_matcher Module.new" => "use_matcher"
|
|
570
|
+
}.each do |registration, method_name|
|
|
571
|
+
Dir.mktmpdir do |dir|
|
|
572
|
+
smartest_dir = File.join(dir, "smartest")
|
|
573
|
+
FileUtils.mkdir_p(smartest_dir)
|
|
574
|
+
File.write(File.join(smartest_dir, "sample_test.rb"), <<~RUBY)
|
|
575
|
+
require "smartest/autorun"
|
|
576
|
+
|
|
577
|
+
#{registration}
|
|
578
|
+
|
|
579
|
+
test("not reached") do
|
|
580
|
+
expect(true).to eq(true)
|
|
581
|
+
end
|
|
582
|
+
RUBY
|
|
583
|
+
|
|
584
|
+
_stdout, stderr, status = Open3.capture3(
|
|
585
|
+
{ "RUBYLIB" => File.expand_path("../lib", __dir__) },
|
|
586
|
+
"ruby",
|
|
587
|
+
File.expand_path("../exe/smartest", __dir__),
|
|
588
|
+
"smartest/sample_test.rb",
|
|
589
|
+
chdir: dir
|
|
590
|
+
)
|
|
591
|
+
|
|
592
|
+
expect(status.success?).to eq(false)
|
|
593
|
+
expect(stderr).to include("Error loading tests:")
|
|
594
|
+
expect(stderr).to include("NoMethodError")
|
|
595
|
+
expect(stderr).to include(method_name)
|
|
596
|
+
end
|
|
597
|
+
end
|
|
598
|
+
end
|
|
599
|
+
|
|
600
|
+
test("around_suite failures fail the run") do
|
|
601
|
+
suite = Smartest::Suite.new
|
|
602
|
+
suite.around_suite_hooks << proc { |_suite_run| raise "suite wrapper failed" }
|
|
603
|
+
suite.tests.add(SmartestSelfTest.test_case("not reached", proc { expect(true).to eq(false) }))
|
|
604
|
+
|
|
605
|
+
status, output = SmartestSelfTest.run_suite(suite)
|
|
606
|
+
|
|
607
|
+
expect(status).to eq(1)
|
|
608
|
+
expect(output).to include("Suite failures:")
|
|
609
|
+
expect(output).to include("RuntimeError: suite wrapper failed")
|
|
610
|
+
expect(output).to include("0 tests, 0 passed, 0 failed, 1 suite failure")
|
|
611
|
+
end
|
|
612
|
+
|
|
613
|
+
test("around_suite must call suite.run") do
|
|
614
|
+
suite = Smartest::Suite.new
|
|
615
|
+
suite.around_suite_hooks << proc { |_suite_run| nil }
|
|
616
|
+
suite.tests.add(SmartestSelfTest.test_case("not reached", proc { expect(true).to eq(false) }))
|
|
617
|
+
|
|
618
|
+
status, output = SmartestSelfTest.run_suite(suite)
|
|
619
|
+
|
|
620
|
+
expect(status).to eq(1)
|
|
621
|
+
expect(output).to include("Smartest::AroundSuiteRunError: around_suite hook did not call suite.run")
|
|
622
|
+
end
|
|
623
|
+
|
|
329
624
|
test("suite cleanup failures fail the run") do
|
|
330
625
|
fixture_class = Class.new(Smartest::Fixture) do
|
|
331
626
|
suite_fixture :browser do
|
|
@@ -541,7 +836,10 @@ test("cli loads matcher files registered in test helper") do
|
|
|
541
836
|
require matcher_file
|
|
542
837
|
end
|
|
543
838
|
|
|
544
|
-
|
|
839
|
+
around_suite do |suite|
|
|
840
|
+
use_matcher HaveStatusMatcher
|
|
841
|
+
suite.run
|
|
842
|
+
end
|
|
545
843
|
RUBY
|
|
546
844
|
File.write(File.join(matchers_dir, "have_status_matcher.rb"), <<~RUBY)
|
|
547
845
|
module HaveStatusMatcher
|
|
@@ -771,6 +1069,7 @@ test("cli initializes a runnable test scaffold") do
|
|
|
771
1069
|
expect(helper_contents).to include('require "smartest/autorun"')
|
|
772
1070
|
expect(helper_contents).to include('Dir[File.join(__dir__, "fixtures", "**", "*.rb")].sort.each')
|
|
773
1071
|
expect(helper_contents).to include('Dir[File.join(__dir__, "matchers", "**", "*.rb")].sort.each')
|
|
1072
|
+
expect(helper_contents).to include("around_suite do |suite|")
|
|
774
1073
|
expect(helper_contents).to include("use_matcher PredicateMatcher")
|
|
775
1074
|
predicate_matcher_contents = File.read(File.join(dir, "smartest/matchers/predicate_matcher.rb"))
|
|
776
1075
|
expect(predicate_matcher_contents).to include("module PredicateMatcher")
|
|
@@ -789,7 +1088,10 @@ test("cli initializes a runnable test scaffold") do
|
|
|
789
1088
|
File.write(File.join(dir, "smartest/auto_loaded_fixture_test.rb"), <<~RUBY)
|
|
790
1089
|
require "test_helper"
|
|
791
1090
|
|
|
792
|
-
|
|
1091
|
+
around_test do |test|
|
|
1092
|
+
use_fixture AutoLoadedFixture
|
|
1093
|
+
test.run
|
|
1094
|
+
end
|
|
793
1095
|
|
|
794
1096
|
test("auto-loaded fixture") do |auto_loaded_message:|
|
|
795
1097
|
expect(auto_loaded_message).to eq("loaded from smartest/fixtures")
|
|
@@ -828,7 +1130,10 @@ test("cli initializes a runnable test scaffold") do
|
|
|
828
1130
|
File.write(File.join(dir, "smartest/auto_loaded_matcher_test.rb"), <<~RUBY)
|
|
829
1131
|
require "test_helper"
|
|
830
1132
|
|
|
831
|
-
|
|
1133
|
+
around_test do |test|
|
|
1134
|
+
use_matcher AutoLoadedMatcher
|
|
1135
|
+
test.run
|
|
1136
|
+
end
|
|
832
1137
|
|
|
833
1138
|
test("auto-loaded matcher") do
|
|
834
1139
|
expect("loaded from smartest/matchers").to auto_eq("loaded from smartest/matchers")
|
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.
|
|
4
|
+
version: 0.2.0.alpha1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Yusuke Iwaki
|
|
@@ -52,6 +52,7 @@ files:
|
|
|
52
52
|
- lib/smartest/fixture_class_registry.rb
|
|
53
53
|
- lib/smartest/fixture_definition.rb
|
|
54
54
|
- lib/smartest/fixture_set.rb
|
|
55
|
+
- lib/smartest/hook_contexts.rb
|
|
55
56
|
- lib/smartest/init_generator.rb
|
|
56
57
|
- lib/smartest/matcher_registry.rb
|
|
57
58
|
- lib/smartest/matchers.rb
|
|
@@ -59,9 +60,11 @@ files:
|
|
|
59
60
|
- lib/smartest/reporter.rb
|
|
60
61
|
- lib/smartest/runner.rb
|
|
61
62
|
- lib/smartest/suite.rb
|
|
63
|
+
- lib/smartest/suite_run.rb
|
|
62
64
|
- lib/smartest/test_case.rb
|
|
63
65
|
- lib/smartest/test_registry.rb
|
|
64
66
|
- lib/smartest/test_result.rb
|
|
67
|
+
- lib/smartest/test_run.rb
|
|
65
68
|
- lib/smartest/version.rb
|
|
66
69
|
- smartest.gemspec
|
|
67
70
|
- smartest/smartest_test.rb
|