test_bench-fixture 1.0.0.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.
@@ -0,0 +1,75 @@
1
+ module TestBench
2
+ module Fixture
3
+ module ErrorPolicy
4
+ def self.configure(receiver, policy: nil, attr_name: nil)
5
+ attr_name ||= :error_policy
6
+
7
+ instance = Build.(policy)
8
+ receiver.public_send(:"#{attr_name}=", instance)
9
+ instance
10
+ end
11
+
12
+ module Build
13
+ PolicyError = Class.new(RuntimeError)
14
+
15
+ def self.call(policy=nil)
16
+ cls = policy_class(policy)
17
+
18
+ cls.new
19
+ end
20
+
21
+ def self.policy_class(policy=nil)
22
+ policy ||= Defaults.policy
23
+
24
+ policies.fetch(policy) do
25
+ *policies, final_policy = self.policies.keys
26
+
27
+ policy_list = "#{policies.map(&:inspect) * ', '} or #{final_policy.inspect}"
28
+
29
+ raise PolicyError, "Policy #{policy.inspect} is unknown. It must be one of: #{policy_list}"
30
+ end
31
+ end
32
+
33
+ def self.policies
34
+ {
35
+ :abort => Abort,
36
+ :raise => Raise,
37
+ :rescue => Rescue,
38
+ :rescue_assert => RescueAssert
39
+ }
40
+ end
41
+
42
+ module Defaults
43
+ def self.policy
44
+ :rescue_assert
45
+ end
46
+ end
47
+ end
48
+
49
+ class Abort
50
+ def call(error)
51
+ abort "TestBench is aborting (#{self.class})"
52
+ end
53
+ end
54
+
55
+ class Raise
56
+ def call(error)
57
+ raise error
58
+ end
59
+ end
60
+
61
+ class Rescue
62
+ def call(error)
63
+ end
64
+ end
65
+
66
+ class RescueAssert
67
+ def call(error)
68
+ unless error.instance_of?(AssertionFailure)
69
+ raise error
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,149 @@
1
+ module TestBench
2
+ module Fixture
3
+ Error = Class.new(RuntimeError)
4
+
5
+ def self.build(cls, *args, session: nil, output: nil, error_policy: nil, factory_method: nil, **kwargs, &block)
6
+ factory_method = factory_method(cls)
7
+
8
+ if kwargs.empty?
9
+ instance = factory_method.(*args, &block)
10
+ else
11
+ instance = factory_method.(*args, **kwargs, &block)
12
+ end
13
+
14
+ Session.configure(instance, session: session, output: output, error_policy: error_policy)
15
+
16
+ instance
17
+ end
18
+
19
+ def self.factory_method(cls)
20
+ if cls.respond_to?(:build)
21
+ cls.method(:build)
22
+ elsif cls.respond_to?(:new)
23
+ cls.method(:new)
24
+ else
25
+ raise Error, "Must be given a class (Argument: #{cls.inspect})"
26
+ end
27
+ end
28
+
29
+ def self.call(cls, *args, **kwargs, &block)
30
+ factory_method = factory_method(cls)
31
+
32
+ last_parameter_type, _ = factory_method.parameters.last
33
+
34
+ if last_parameter_type == :block
35
+ instance = build(cls, *args, **kwargs, &block)
36
+ block = nil
37
+ else
38
+ instance = build(cls, *args, **kwargs)
39
+ end
40
+
41
+ instance.test_session.fixture(instance, &block)
42
+
43
+ instance
44
+ end
45
+
46
+ def test_session
47
+ @test_session ||= Session::Substitute.build
48
+ end
49
+ attr_writer :test_session
50
+ alias_method :session, :test_session
51
+ alias_method :session=, :test_session=
52
+
53
+ def comment(text)
54
+ test_session.comment(text)
55
+ end
56
+
57
+ ArgumentOmitted = Object.new
58
+ def assert(value=ArgumentOmitted, caller_location: nil, &block)
59
+ caller_location ||= caller_locations.first
60
+
61
+ unless value == ArgumentOmitted
62
+ unless block.nil?
63
+ raise ArgumentError, "Must supply a boolean value or a block (but not both)"
64
+ end
65
+
66
+ test_session.assert(value, caller_location: caller_location)
67
+ else
68
+ test_session.assert_block(caller_location: caller_location, &block)
69
+ end
70
+ end
71
+
72
+ def refute(value, caller_location: nil)
73
+ caller_location ||= caller_locations.first
74
+
75
+ test_session.assert(!value, caller_location: caller_location)
76
+ end
77
+
78
+ def assert_raises(error_class=nil, message=nil, strict: nil, caller_location: nil, &block)
79
+ if error_class.nil?
80
+ strict ||= false
81
+ error_class = StandardError
82
+ else
83
+ strict = true if strict.nil?
84
+ end
85
+
86
+ caller_location ||= caller_locations.first
87
+
88
+ assert(caller_location: caller_location) do
89
+ comment "Expected Error: #{error_class}#{' (strict)' if strict}"
90
+ comment "Expected Message: #{message.inspect}" unless message.nil?
91
+
92
+ block.()
93
+
94
+ comment "(No error was raised)"
95
+
96
+ rescue error_class => error
97
+
98
+ comment "Raised error: #{error.inspect}#{" (subclass of #{error_class})" if error.class < error_class}"
99
+
100
+ if strict && !error.instance_of?(error_class)
101
+ raise error
102
+ end
103
+
104
+ assert(message.nil? || error.message == message)
105
+ end
106
+ end
107
+
108
+ def refute_raises(error_class=nil, strict: nil, caller_location: nil, &block)
109
+ if error_class.nil?
110
+ strict ||= false
111
+ error_class = StandardError
112
+ else
113
+ strict = true if strict.nil?
114
+ end
115
+
116
+ caller_location ||= caller_locations.first
117
+
118
+ assert(caller_location: caller_location) do
119
+ comment "Prohibited Error: #{error_class}#{' (strict)' if strict}"
120
+
121
+ block.()
122
+
123
+ comment "(No error was raised)"
124
+
125
+ assert(true)
126
+
127
+ rescue error_class => error
128
+
129
+ comment "Raised Error: #{error.inspect}"
130
+
131
+ if strict && !error.instance_of?(error_class)
132
+ raise error
133
+ end
134
+ end
135
+ end
136
+
137
+ def context(text=nil, &block)
138
+ test_session.context(text, &block)
139
+ end
140
+
141
+ def test(text=nil, &block)
142
+ test_session.test(text, &block)
143
+ end
144
+
145
+ def fixture(cls, *args, **kwargs, &block)
146
+ Fixture.(cls, *args, session: test_session, **kwargs, &block)
147
+ end
148
+ end
149
+ end
@@ -0,0 +1,56 @@
1
+ module TestBench
2
+ module Fixture
3
+ module Output
4
+ def start
5
+ end
6
+
7
+ def finish(result)
8
+ end
9
+
10
+ def enter_file(path)
11
+ end
12
+
13
+ def exit_file(path, result)
14
+ end
15
+
16
+ def start_fixture(fixture)
17
+ end
18
+
19
+ def finish_fixture(fixture, result)
20
+ end
21
+
22
+ def assert(result, caller_location)
23
+ end
24
+
25
+ def enter_assert_block(caller_location)
26
+ end
27
+
28
+ def exit_assert_block(result, caller_location)
29
+ end
30
+
31
+ def comment(text)
32
+ end
33
+
34
+ def error(error)
35
+ end
36
+
37
+ def start_test(title)
38
+ end
39
+
40
+ def finish_test(title, result)
41
+ end
42
+
43
+ def skip_test(title)
44
+ end
45
+
46
+ def enter_context(title)
47
+ end
48
+
49
+ def exit_context(title, result)
50
+ end
51
+
52
+ def skip_context(title)
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,109 @@
1
+ module TestBench
2
+ module Fixture
3
+ module Output
4
+ class Log
5
+ include Output
6
+
7
+ attr_reader :logger
8
+
9
+ def initialize(logger)
10
+ @logger = logger
11
+ end
12
+
13
+ def self.build(device=nil)
14
+ device ||= $stderr
15
+
16
+ logger = Logger.new(device)
17
+
18
+ new(logger)
19
+ end
20
+
21
+ def self.configure(receiver, device=nil, attr_name: nil)
22
+ attr_name ||= :output
23
+
24
+ instance = build(device)
25
+ receiver.public_send(:"#{attr_name}=", instance)
26
+ instance
27
+ end
28
+
29
+ def start
30
+ logger.debug { "Start" }
31
+ end
32
+
33
+ def finish(result)
34
+ logger.info { "Finish (Result: #{result})" }
35
+ end
36
+
37
+ def enter_file(path)
38
+ logger.debug { "Enter file (Path: #{path})" }
39
+ end
40
+
41
+ def exit_file(path, result)
42
+ logger.info { "Exit file (Path: #{path}, Result: #{result})" }
43
+ end
44
+
45
+ def start_fixture(fixture)
46
+ logger.debug { "Start fixture (Fixture: #{fixture.inspect})" }
47
+ end
48
+
49
+ def finish_fixture(fixture, result)
50
+ logger.info { "Finish fixture (Fixture: #{fixture.inspect}, Result: #{result})" }
51
+ end
52
+
53
+ def assert(result, caller_location)
54
+ logger.info { "Assertion (Result: #{result}, Caller Location: #{caller_location})" }
55
+ end
56
+
57
+ def enter_assert_block(caller_location)
58
+ logger.debug { "Entering assert block (Caller Location: #{caller_location})" }
59
+ end
60
+
61
+ def exit_assert_block(caller_location, result)
62
+ logger.info { "Exited assert block (Caller Location: #{caller_location}, Result: #{result})" }
63
+ end
64
+
65
+ def comment(text)
66
+ logger.info { "Comment (Text: #{text})" }
67
+ end
68
+
69
+ def error(error)
70
+ logger.error { "Error (Error: #{error})" }
71
+ end
72
+
73
+ def start_test(title)
74
+ logger.debug { "Starting test (Title: #{title || '(none)'})" }
75
+ end
76
+
77
+ def finish_test(title, result)
78
+ logger.info { "Finished test (Title: #{title || '(none)'}, Result: #{result})" }
79
+ end
80
+
81
+ def skip_test(title)
82
+ logger.info { "Skipped test (Title: #{title || '(none)'})" }
83
+ end
84
+
85
+ def enter_context(title)
86
+ logger.debug { "Entering context (Title: #{title || '(none)'})" }
87
+ end
88
+
89
+ def exit_context(title, result)
90
+ logger.info { "Exited context (Title: #{title || '(none)'}, Result: #{result})" }
91
+ end
92
+
93
+ def skip_context(title)
94
+ logger.info { "Skipped context (Title: #{title || '(none)'})" }
95
+ end
96
+
97
+ def device?(device)
98
+ self.device == device
99
+ end
100
+
101
+ def device
102
+ logger.instance_exec do
103
+ @logdev.dev
104
+ end
105
+ end
106
+ end
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,42 @@
1
+ module TestBench
2
+ module Fixture
3
+ module Output
4
+ class Multiple
5
+ include Output
6
+
7
+ def outputs
8
+ @outputs ||= []
9
+ end
10
+ attr_writer :outputs
11
+
12
+ def self.build(*outputs)
13
+ outputs = Array(outputs)
14
+
15
+ instance = new
16
+
17
+ outputs.each do |output|
18
+ instance.register(output)
19
+ end
20
+
21
+ instance
22
+ end
23
+
24
+ Output.instance_methods.each do |method_name|
25
+ define_method(method_name) do |*args|
26
+ outputs.map do |output|
27
+ output.public_send(method_name, *args)
28
+ end
29
+ end
30
+ end
31
+
32
+ def register(output)
33
+ outputs << output
34
+ end
35
+
36
+ def registered?(output)
37
+ outputs.include?(output)
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,9 @@
1
+ module TestBench
2
+ module Fixture
3
+ module Output
4
+ class Null
5
+ include Output
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,141 @@
1
+ module TestBench
2
+ module Fixture
3
+ module Output
4
+ module Substitute
5
+ def self.build
6
+ Output.new
7
+ end
8
+
9
+ MatchError = Class.new(RuntimeError)
10
+
11
+ class Output
12
+ include Fixture::Output
13
+
14
+ def records
15
+ @records ||= []
16
+ end
17
+
18
+ def start
19
+ record(:start)
20
+ end
21
+
22
+ def finish(result)
23
+ record(:finish, result)
24
+ end
25
+
26
+ def enter_file(path)
27
+ record(:enter_file, path)
28
+ end
29
+
30
+ def exit_file(path, result)
31
+ record(:exit_file, path, result)
32
+ end
33
+
34
+ def start_fixture(fixture)
35
+ record(:start_fixture, fixture)
36
+ end
37
+
38
+ def finish_fixture(fixture, result)
39
+ record(:finish_fixture, fixture, result)
40
+ end
41
+
42
+ def assert(result, caller_location)
43
+ record(:assert, result, caller_location)
44
+ end
45
+
46
+ def enter_assert_block(caller_location)
47
+ record(:enter_assert_block, caller_location)
48
+ end
49
+
50
+ def exit_assert_block(caller_location, result)
51
+ record(:exit_assert_block, caller_location, result)
52
+ end
53
+
54
+ def comment(text)
55
+ record(:comment, text)
56
+ end
57
+
58
+ def error(error)
59
+ record(:error, error)
60
+ end
61
+
62
+ def start_test(title)
63
+ record(:start_test, title)
64
+ end
65
+
66
+ def finish_test(title, result)
67
+ record(:finish_test, title, result)
68
+ end
69
+
70
+ def skip_test(title)
71
+ record(:skip_test, title)
72
+ end
73
+
74
+ def enter_context(title)
75
+ record(:enter_context, title)
76
+ end
77
+
78
+ def exit_context(title, result)
79
+ record(:exit_context, title, result)
80
+ end
81
+
82
+ def skip_context(title)
83
+ record(:skip_context, title)
84
+ end
85
+
86
+ def record(signal, *data)
87
+ record = Record.new(signal, data)
88
+ records << record
89
+ record
90
+ end
91
+
92
+ def replay_records(output)
93
+ records.each do |record|
94
+ output.public_send(record.signal, *record.data)
95
+ end
96
+ end
97
+
98
+ def recorded?(signal=nil, &block)
99
+ matching_records(signal, &block).any?
100
+ end
101
+
102
+ def recorded_once?(signal=nil, &block)
103
+ one_record(signal, &block) ? true : false
104
+ end
105
+
106
+ def one_record(signal=nil, &block)
107
+ matching_records = matching_records(signal, &block)
108
+
109
+ return if matching_records.empty?
110
+
111
+ unless matching_records.one?
112
+ raise MatchError, "More than one records match"
113
+ end
114
+
115
+ matching_records.shift
116
+ end
117
+
118
+ def matching_records(signal=nil, &block)
119
+ unless signal.nil?
120
+ inner_block = block || proc { true }
121
+
122
+ block = proc { |sig, *data|
123
+ if sig == signal
124
+ inner_block.(*data)
125
+ else
126
+ false
127
+ end
128
+ }
129
+ end
130
+
131
+ records.select do |record|
132
+ block.(record.signal, *record.data)
133
+ end
134
+ end
135
+
136
+ Record = Struct.new(:signal, :data)
137
+ end
138
+ end
139
+ end
140
+ end
141
+ end