Module: Roby::Test::Assertions

Included in:
Self, Spec, TestCase
Defined in:
lib/roby/test/assertions.rb

Defined Under Namespace

Classes: FlexmockExceptionMatcher, FlexmockExceptionTasks

Deprecated assertions replaced by expect_execution collapse

Instance Method Summary collapse

Instance Method Details

#__capture_log(mock, level) ⇒ Object



57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/roby/test/assertions.rb', line 57

def __capture_log(mock, level)
    Roby.disable_colors

    if mock.respond_to?(:logger)
        object_logger = mock.logger
    else
        object_logger = mock
    end

    capture = Array.new
    original_level = object_logger.level
    level_value = Logger.const_get(level.upcase)
    if original_level > level_value
        object_logger.level = level_value
    end

    mock.should_receive(level).
        and_return do |msg|
            if msg.respond_to?(:to_str)
                capture << msg
            else
                mock.invoke_original(level) do
                    capture << msg.call
                    break
                end
            end
        end

    yield
    capture
ensure
    Roby.enable_colors_if_available
    object_logger.level = original_level
end

#assert_adds_error(matcher, original_exception: nil, failure_point: PlanObject) ⇒ Object

Deprecated.

use #expect_execution { … }.to { have_error_matching … } instead



395
396
397
398
399
400
401
# File 'lib/roby/test/assertions.rb', line 395

def assert_adds_error(matcher, original_exception: nil, failure_point: PlanObject)
    Roby.warn_deprecated "#{__method__} is deprecated, use #expect_execution { ... }.to { have_error_matching ... } instead"
    matcher = create_exception_matcher(
        matcher, original_exception: original_exception,
        failure_point: failure_point)
    expect_execution { yield }.to { have_error_matching matcher }
end

#assert_adds_framework_error(matcher) ⇒ Object

Deprecated.

use #expect_execution { … }.to { have_framework_error_matching … } instead



404
405
406
407
# File 'lib/roby/test/assertions.rb', line 404

def assert_adds_framework_error(matcher)
    Roby.warn_deprecated "#{__method__} is deprecated, use #expect_execution { ... }.to { have_framework_error_matching ... } instead"
    expect_execution { yield }.to { have_framework_error_matching matcher }
end

#assert_child_of(parent, child, relation, *info) ⇒ Object

Asserts that two tasks are in a parent-child relationship in a specific relation

Parameters:

  • parent (Roby::Task)

    the parent task

  • child (Roby::Task)

    the child task

  • relation (Relations::Models::Graph)

    the relation

  • info (#===)

    optional object used to match the edge information. Leave empty if it should not be matched. Note that giving ‘nil’ will match against nil



122
123
124
125
126
127
128
129
130
131
# File 'lib/roby/test/assertions.rb', line 122

def assert_child_of(parent, child, relation, *info)
    assert_same parent.relation_graphs, child.relation_graphs, "#{parent} and #{child} cannot be related as they are not acting on the same relation graphs"
    graph = parent.relation_graph_for(relation)
    assert graph.has_vertex?(parent), "#{parent} and #{child} canot be related in #{relation} as the former is not in the graph"
    assert graph.has_vertex?(child),  "#{parent} and #{child} canot be related in #{relation} as the latter is not in the graph"
    assert parent.child_object?(child, relation), "#{child} is not a child of #{parent} in #{relation}"
    if !info.empty?
        assert_equal info.first, parent[child, relation], "info differs"
    end
end

#assert_droby_compatible(object, local_marshaller: self.droby_local_marshaller, remote_marshaller: self.droby_remote_marshaller, bidirectional: false) ⇒ Object

Asserts that an object can marshalled an unmarshalled by the DRoby protocol

It does not verify that the resulting objects are equal as they usually are not

Parameters:

  • object (Object)

    the object to test against

  • local_marshaller (DRoby::Marshal) (defaults to: self.droby_local_marshaller)

    the local marshaller, which will be used to marshal ‘object’

  • remote_marshaller (DRoby::Marshal) (defaults to: self.droby_remote_marshaller)

    the remote marshaller, which will be used to unmarshal the marshalled version of ‘object’

Returns:

  • (Object)

    the ‘remote’ object created from the unmarshalled droby representation



203
204
205
206
207
208
209
210
211
212
213
# File 'lib/roby/test/assertions.rb', line 203

def assert_droby_compatible(object, local_marshaller: self.droby_local_marshaller, remote_marshaller: self.droby_remote_marshaller, bidirectional: false)
    remote_object = droby_transfer(object, local_marshaller: local_marshaller,
                   remote_marshaller: remote_marshaller)
    if bidirectional
        local_object  = droby_transfer(remote_object, local_marshaller: remote_marshaller,
                                       remote_marshaller: local_marshaller)
        return remote_object, local_object
    else
        return remote_object
    end
end

#assert_event_becomes_unreachable(generator, timeout: 5, &block) ⇒ Object

Deprecated.

use #expect_execution { … }.to { become_unreachable generator }



276
277
278
279
280
# File 'lib/roby/test/assertions.rb', line 276

def assert_event_becomes_unreachable(generator, timeout: 5, &block)
    Roby.warn_deprecated "#{__method__} is deprecated, use #expect_execution { ... }.to { become_unreachable generator } instead"
    expect_execution { yield }.timeout(timeout).
        to { become_unreachable generator }
end

#assert_event_command_failed(exception = CommandFailed, original_exception: nil, failure_point: EventGenerator, execution_engine: nil, &block) ⇒ Object

Deprecated.

use expect_execution { … }.to { have_error_matching CommandFailed.match… }



307
308
309
310
311
312
313
# File 'lib/roby/test/assertions.rb', line 307

def assert_event_command_failed(exception = CommandFailed, original_exception: nil, failure_point: EventGenerator, execution_engine: nil, &block)
    Roby.warn_deprecated "#{__method__} is deprecated, use #expect_execution { ... }.to { have_error_matching CommandFailed.match... } instead"
    assert_event_exception(
        exception, original_exception: original_exception,
        failure_point: failure_point,
        execution_engine: execution_engine, &block)
end

#assert_event_emission(positive = [], negative = [], msg = nil, timeout = 5, enable_scheduler: nil, garbage_collect_pass: true) ⇒ Object

Deprecated.

use #expect_execution { … }.to { emit event } instead



255
256
257
258
259
260
261
262
263
264
265
266
# File 'lib/roby/test/assertions.rb', line 255

def assert_event_emission(positive = [], negative = [], msg = nil, timeout = 5, enable_scheduler: nil, garbage_collect_pass: true)
    Roby.warn_deprecated "#{__method__} is deprecated, use #expect_execution { ... }.to { emit event } instead"
    expect_execution do
        yield if block_given?
    end.timeout(timeout).
        scheduler(enable_scheduler).
        garbage_collect(garbage_collect_pass).
    to do
        not_emit *Array(negative)
        emit *Array(positive)
    end
end

#assert_event_emission_failed(exception = EmissionFailed, original_exception: nil, failure_point: EventGenerator, execution_engine: nil, &block) ⇒ Object

Deprecated.

use expect_execution { … }.to { have_error_matching EmissionFailed.match.… }



289
290
291
292
293
294
295
# File 'lib/roby/test/assertions.rb', line 289

def assert_event_emission_failed(exception = EmissionFailed, original_exception: nil, failure_point: EventGenerator, execution_engine: nil, &block)
    Roby.warn_deprecated "#{__method__} is deprecated, use #expect_execution { ... }.to { have_error_matching EmissionFailed.match... } instead"
    assert_event_exception(
        exception, original_exception: original_exception,
        failure_point: failure_point,
        execution_engine: execution_engine, &block)
end

#assert_event_exception(matcher, original_exception: nil, failure_point: EventGenerator, execution_engine: nil) ⇒ Object

Deprecated.

use expect_execution { … }.to { have_error_matching … }



325
326
327
328
329
330
331
# File 'lib/roby/test/assertions.rb', line 325

def assert_event_exception(matcher, original_exception: nil, failure_point: EventGenerator, execution_engine: nil)
    Roby.warn_deprecated "#{__method__} is deprecated, use #expect_execution { ... }.to { have_error_matching ... } instead"
    matcher = create_exception_matcher(
        matcher, original_exception: original_exception,
        failure_point: failure_point)
    expect_execution { yield if block_given? }.to { have_error_matching matcher }
end

#assert_event_is_unreachable(event, reason: nil) ⇒ Object

Verifies that a given event is unreachable, optionally checking its unreachability reason

Returns:

  • the unreachability reason



105
106
107
108
109
110
111
# File 'lib/roby/test/assertions.rb', line 105

def assert_event_is_unreachable(event, reason: nil)
    assert event.unreachable?, "#{event} was expected to be unreachable but is not"
    if reason
        assert(reason === event.unreachability_reason, "the unreachability of #{event} was expected to match #{reason} but it is #{event.unreachability_reason}")
    end
    event.unreachability_reason
end

#assert_exception_can_be_pretty_printed(e) ⇒ Object

Verifies that the given exception object does not raise when pretty-printed

When using minitest, this is called by MinitestHelpers#assert_raises



28
29
30
# File 'lib/roby/test/assertions.rb', line 28

def assert_exception_can_be_pretty_printed(e)
    PP.pp(e, "") # verify that the exception can be pretty-printed, all Roby exceptions should
end

#assert_fatal_exception(matcher, failure_point: Task, original_exception: nil, tasks: [], kill_tasks: tasks, garbage_collect: false) ⇒ Object

Deprecated.

use expect_execution { … }.to { have_error_matching … }



344
345
346
347
348
349
350
# File 'lib/roby/test/assertions.rb', line 344

def assert_fatal_exception(matcher, failure_point: Task, original_exception: nil, tasks: [], kill_tasks: tasks, garbage_collect: false)
    Roby.warn_deprecated "#{__method__} is deprecated, use #expect_execution { ... }.to { have_error_matching ... } instead"
    matcher = create_exception_matcher(
        matcher, original_exception: original_exception,
        failure_point: failure_point)
    expect_execution { yield if block_given? }.garbage_collect(garbage_collect).to { have_error_matching matcher }.exception
end

#assert_free_event_command_failed(exception = CommandFailed, original_exception: nil, failure_point: EventGenerator, execution_engine: nil, &block) ⇒ Object

Deprecated.

use expect_execution { … }.to { have_error_matching CommandFailed.match… }



298
299
300
301
302
303
304
# File 'lib/roby/test/assertions.rb', line 298

def assert_free_event_command_failed(exception = CommandFailed, original_exception: nil, failure_point: EventGenerator, execution_engine: nil, &block)
    Roby.warn_deprecated "#{__method__} is deprecated, use #expect_execution { ... }.to { have_error_matching CommandFailed.match... } instead"
    assert_event_exception(
        exception, original_exception: original_exception,
        failure_point: failure_point,
        execution_engine: execution_engine, &block)
end

#assert_free_event_emission_failed(exception = EmissionFailed, original_exception: nil, failure_point: EventGenerator, &block) ⇒ Object

Deprecated.

use expect_execution { … }.to { have_error_matching … }



283
284
285
286
# File 'lib/roby/test/assertions.rb', line 283

def assert_free_event_emission_failed(exception = EmissionFailed, original_exception: nil, failure_point: EventGenerator, &block)
    Roby.warn_deprecated "#{__method__} is deprecated, use #expect_execution { ... }.to { have_error_matching ... } instead"
    assert_event_emission_failed(exception, original_exception: original_exception, failure_point: failure_point, &block)
end

#assert_free_event_exception(matcher, original_exception: nil, failure_point: EventGenerator, execution_engine: nil, &block) ⇒ Object

Deprecated.

use expect_execution { … }.to { have_error_matching … }



316
317
318
319
320
321
322
# File 'lib/roby/test/assertions.rb', line 316

def assert_free_event_exception(matcher, original_exception: nil, failure_point: EventGenerator, execution_engine: nil, &block)
    Roby.warn_deprecated "#{__method__} is deprecated, use #expect_execution { ... }.to { have_error_matching ... } instead"
    assert_event_exception(
        matcher, original_exception: original_exception,
        failure_point: failure_point,
        execution_engine: execution_engine, &block)
end

#assert_free_event_exception_warningObject

Deprecated.


377
378
379
380
381
382
383
# File 'lib/roby/test/assertions.rb', line 377

def assert_free_event_exception_warning
    Roby.warn_deprecated "#{__method__} is deprecated, and has no replacements. It is not needed when using the expect_execution harness"
    messages = capture_log(execution_engine, :warn) do
        yield
    end
    assert_equal ["1 free event exceptions"], messages
end

#assert_handled_exception(matcher, failure_point: Task, original_exception: nil, tasks: []) ⇒ Object

Deprecated.

use expect_execution { … }.to { have_handled_error_matching … }



353
354
355
356
357
358
359
# File 'lib/roby/test/assertions.rb', line 353

def assert_handled_exception(matcher, failure_point: Task, original_exception: nil, tasks: [])
    Roby.warn_deprecated "#{__method__} is deprecated, use #expect_execution { ... }.to { have_handled_error_matching ... } instead"
    matcher = create_exception_matcher(
        matcher, original_exception: original_exception,
        failure_point: failure_point)
    expect_execution { yield if block_given? }.to { have_handled_error_matching matcher }
end

#assert_logs_event(event_name, *args) ⇒ Object

Expects the event logger to receive the given message

The assertion is validated on teardown



218
219
220
# File 'lib/roby/test/assertions.rb', line 218

def assert_logs_event(event_name, *args)
    @expected_events << [event_name, args]
end

#assert_logs_exception_with_backtrace(exception_m, logger, level) ⇒ Object

Deprecated.


371
372
373
374
# File 'lib/roby/test/assertions.rb', line 371

def assert_logs_exception_with_backtrace(exception_m, logger, level)
    flexmock(Roby).should_receive(:log_exception_with_backtrace).once.
        with(exception_m, logger, level)
end

#assert_nonfatal_exception(matcher, failure_point: Task, original_exception: nil, tasks: []) ⇒ Object

Deprecated.

use expect_execution { … }.to { have_error_matching … }



362
363
364
365
366
367
368
# File 'lib/roby/test/assertions.rb', line 362

def assert_nonfatal_exception(matcher, failure_point: Task, original_exception: nil, tasks: [])
    Roby.warn_deprecated "#{__method__} is deprecated, use #expect_execution { ... }.to { have_error_matching ... } instead"
    matcher = create_exception_matcher(
        matcher, original_exception: original_exception,
        failure_point: failure_point)
    expect_execution { yield }.to { have_error_matching matcher }
end

#assert_notifies_free_event_exception(matcher, failure_point: nil) ⇒ Object

Deprecated.


386
387
388
389
390
391
392
# File 'lib/roby/test/assertions.rb', line 386

def assert_notifies_free_event_exception(matcher, failure_point: nil)
    Roby.warn_deprecated "#{__method__} is deprecated, and has no replacements. It is not needed when using the expect_execution harness"
    flexmock(execution_engine).should_receive(:notify_exception).
        with(ExecutionEngine::EXCEPTION_FREE_EVENT,
             *roby_make_flexmock_exception_matcher(matcher, [failure_point])).
        once
end

#assert_relative_error(expected, found, error, msg = "") ⇒ Object

This assertion fails if the relative error between found and expectedis more than error



143
144
145
146
147
148
149
# File 'lib/roby/test/assertions.rb', line 143

def assert_relative_error(expected, found, error, msg = "")
    if expected == 0
        assert_in_delta(0, found, error, "comparing #{found} to #{expected} in #{msg}")
    else
        assert_in_delta(0, (found - expected) / expected, error, "comparing #{found} to #{expected} in #{msg}")
    end
end

#assert_same_position(expected, found, dl = 0.01, dt = 0.01, msg = "") ⇒ Object

This assertion fails if found and expected are more than dl meters apart in the x, y and z coordinates, or dt radians apart in angles



154
155
156
157
158
159
160
161
# File 'lib/roby/test/assertions.rb', line 154

def assert_same_position(expected, found, dl = 0.01, dt = 0.01, msg = "")
    assert_relative_error(expected.x, found.x, dl, msg)
    assert_relative_error(expected.y, found.y, dl, msg)
    assert_relative_error(expected.z, found.z, dl, msg)
    assert_relative_error(expected.yaw, found.yaw, dt, msg)
    assert_relative_error(expected.pitch, found.pitch, dt, msg)
    assert_relative_error(expected.roll, found.roll, dt, msg)
end

#assert_sets_equal(expected, actual) ⇒ Object

Better equality test for sets

It displays the difference between the two sets



35
36
37
38
39
40
41
# File 'lib/roby/test/assertions.rb', line 35

def assert_sets_equal(expected, actual)
    if !(diff = (expected - actual)).empty?
        flunk("expects two sets to be equal, but #{expected} is missing #{diff.size} expected elements:\n  #{diff.to_a.map(&:to_s).join(", ")}")
    elsif !(diff = (actual - expected)).empty?
        flunk("expects two sets to be equal, but #{actual} has #{diff.size} more elements than expected:\n  #{diff.to_a.map(&:to_s).join(", ")}")
    end
end

#assert_state_machine_transition(state_machine_task, to_state: Regexp.new, timeout: 5, start: true) ⇒ Object

Deprecated.


457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
# File 'lib/roby/test/assertions.rb', line 457

def assert_state_machine_transition(state_machine_task, to_state: Regexp.new, timeout: 5, start: true)
    Roby.warn_deprecated "#{__method__} is deprecated, use #validate_state_machine instead"
    state_machines = state_machine_task.each_coordination_object.
        find_all { |obj| obj.kind_of?(Coordination::ActionStateMachine) }
    if state_machines.empty?
        raise ArgumentError, "#{state_machine_task} has no state machines"
    end

    if to_state.respond_to?(:to_str) && !to_state.end_with?('_state')
        to_state = "#{to_state}_state"
    end

    done = false
    state_machines.each do |m|
        m.on_transition do |_, new_state|
            if to_state === new_state.name
                done = true
            end
        end
    end
    yield if block_given?
    process_events_until(timeout: timeout, garbage_collect_pass: false) do
        done
    end
    roby_run_planner(state_machine_task)
    if start
        assert_event_emission state_machine_task.current_task_child.start_event
    end
    state_machine_task.current_task_child
end

#assert_task_fails_to_start(task, matcher, failure_point: task.start_event, original_exception: nil, tasks: []) ⇒ Object

Deprecated.

use expect_execution { … }.to { fail_to_start … }



334
335
336
337
338
339
340
341
# File 'lib/roby/test/assertions.rb', line 334

def assert_task_fails_to_start(task, matcher, failure_point: task.start_event, original_exception: nil, tasks: [])
    Roby.warn_deprecated "#{__method__} is deprecated, use #expect_execution { ... }.to { fail_to_start ... } instead"
    matcher = create_exception_matcher(
        matcher, original_exception: original_exception,
        failure_point: failure_point)
    expect_execution { yield if block_given? }.to { fail_to_start task }
    task.failure_reason
end

#assert_task_quarantined(task, timeout: 5) ⇒ Object

Deprecated.

use #expect_execution { … }.to { quarantine task }



269
270
271
272
273
# File 'lib/roby/test/assertions.rb', line 269

def assert_task_quarantined(task, timeout: 5)
    Roby.warn_deprecated "#{__method__} is deprecated, use #expect_execution { ... }.to { quarantine task } instead"
    expect_execution { yield }.timeout(timeout).
        to { quarantine task }
end

#capture_log(object, level) ⇒ Array<String>

Capture log output from one logger and returns it

Note that it currently does not “de-shares” loggers

Parameters:

  • a (Logger, #logger)

    logger object, or an object that holds one

  • level (Symbol)

    the name of the logging method (e.g. :warn)

Returns:

  • (Array<String>)


51
52
53
54
55
# File 'lib/roby/test/assertions.rb', line 51

def capture_log(object, level)
    FlexMock.use(object) do |mock|
        __capture_log(mock, level, &proc)
    end
end

#create_exception_matcher(localized_error_type, original_exception: nil, failure_point: nil) ⇒ #===

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Helper method that creates a matching object for localized errors

Parameters:

  • localized_error_type (LocalizedError)

    the error model to match

  • original_exception (Exception, nil) (defaults to: nil)

    an original exception to match, for exceptions that transform exceptions into other (e.g. CodeError)

  • failure_point (Task, EventGenerator) (defaults to: nil)

    the exceptions’ failure point

Returns:

  • (#===)

    an object that can match an execution exception



236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
# File 'lib/roby/test/assertions.rb', line 236

def create_exception_matcher(localized_error_type, original_exception: nil, failure_point: nil)
    matcher = localized_error_type.match
    if original_exception
        matcher.with_original_exception(original_exception)
    end
    if matcher.respond_to?(:with_ruby_exception) && matcher.ruby_exception_class == Exception
        if original_exception
            matcher.with_ruby_exception(original_exception)
        else
            matcher.without_ruby_exception
        end
    end
    if failure_point
        matcher.with_origin(failure_point)
    end
    matcher
end

#droby_local_marshallerObject



163
164
165
# File 'lib/roby/test/assertions.rb', line 163

def droby_local_marshaller
    @droby_local_marshaller ||= DRoby::Marshal.new
end

#droby_remote_marshallerObject



167
168
169
# File 'lib/roby/test/assertions.rb', line 167

def droby_remote_marshaller
    @droby_remote_marshaller ||= DRoby::Marshal.new
end

#droby_to_remote(object, local_marshaller: self.droby_local_marshaller) ⇒ Object



171
172
173
174
175
176
177
178
179
180
181
# File 'lib/roby/test/assertions.rb', line 171

def droby_to_remote(object, local_marshaller: self.droby_local_marshaller)
    droby = local_marshaller.dump(object)
    dumped =
        begin Marshal.dump(droby)
        rescue Exception => e
            require 'roby/droby/logfile/writer'
            obj, exception = Roby::DRoby::Logfile::Writer.find_invalid_marshalling_object(droby)
            raise e, "#{obj} cannot be marshalled: #{exception.message}", exception.backtrace
        end
    Marshal.load(dumped)
end

#droby_transfer(object, local_marshaller: self.droby_local_marshaller, remote_marshaller: self.droby_remote_marshaller) ⇒ Object



183
184
185
186
# File 'lib/roby/test/assertions.rb', line 183

def droby_transfer(object, local_marshaller: self.droby_local_marshaller, remote_marshaller: self.droby_remote_marshaller)
    loaded = droby_to_remote(object, local_marshaller: local_marshaller)
    remote_marshaller.local_object(loaded)
end

#refute_child_of(parent, child, relation) ⇒ Object

Asserts that two tasks are not a parent-child relationship in a specific relation



135
136
137
138
139
# File 'lib/roby/test/assertions.rb', line 135

def refute_child_of(parent, child, relation)
    assert_same parent.relation_graphs, child.relation_graphs, "#{parent} and #{child} cannot be related as they are not acting on the same relation graphs"
    graph = parent.relation_graph_for(relation)
    refute(graph.has_vertex?(parent) && graph.has_vertex?(child) && parent.child_object?(child, relation))
end

#roby_make_flexmock_exception_matcher(matcher, tasks) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Helper method that creates exception matchers that provide better error messages, for the benefit of the exception assertions



449
450
451
452
# File 'lib/roby/test/assertions.rb', line 449

def roby_make_flexmock_exception_matcher(matcher, tasks)
    return FlexmockExceptionMatcher.new(matcher.to_execution_exception_matcher),
        FlexmockExceptionTasks.new(tasks.to_set)
end

#setupObject



4
5
6
7
# File 'lib/roby/test/assertions.rb', line 4

def setup
    @expected_events = Array.new
    super
end

#teardownObject



9
10
11
12
13
14
15
16
17
18
19
20
# File 'lib/roby/test/assertions.rb', line 9

def teardown
    @expected_events.each do |m, args|
        if !plan.event_logger.has_received_event?(m, *args)
            flunk("expected to receive a log event #{m}(#{args.map(&:to_s).join(", ")}) but did not. Received:\n  " +
            plan.event_logger.received_events.
                find_all { |m, _, args| m.to_s !~ /timegroup/ }.
                map { |m, time, args| "#{m}(#{args.map(&:to_s).join(", ")})" }.
                join("\n  "))
        end
    end
    super
end

#validate_state_machine(task_or_action, &block) ⇒ Object



22
23
24
# File 'lib/roby/test/assertions.rb', line 22

def validate_state_machine(task_or_action, &block)
    ValidateStateMachine.new(self, task_or_action).evaluate(&block)
end