test_bench-fixture 1.0.0.0

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