Skip to content

Commit

Permalink
add tests for FSM#wait_for_state including enforcement that states mu…
Browse files Browse the repository at this point in the history
…st be symbols
  • Loading branch information
ColinDKelley committed Jan 14, 2021
1 parent 92793ff commit 5e0c64d
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 0 deletions.
3 changes: 3 additions & 0 deletions lib/listen/fsm.rb
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ def initialize_fsm
# if not already, waits for a state change (up to timeout seconds--`nil` means infinite)
# returns truthy iff the transition to one of the desired state has occurred
def wait_for_state(*wait_for_states, timeout: nil)
wait_for_states.each do |state|
state.is_a?(Symbol) or raise ArgumentError, "states must be symbols (got #{state.inspect})"
end
@mutex.synchronize do
if !wait_for_states.include?(@state)
@state_changed.wait(@mutex, timeout)
Expand Down
38 changes: 38 additions & 0 deletions spec/lib/listen/fsm_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,44 @@ def initialize
expect { subject.transition(:started) }.to raise_exception(NoMethodError, /private.*transition/)
expect { subject.transition!(:started) }.to raise_exception(NoMethodError, /private.*transition!/)
end

describe '#wait_for_state' do
it 'returns truthy immediately if already in the desired state' do
expect(subject.instance_variable_get(:@state_changed)).to_not receive(:wait)
result = subject.wait_for_state(:initial)
expect(result).to be_truthy
end

it 'waits for the next state change and returns truthy if then in the desired state' do
expect(subject.instance_variable_get(:@state_changed)).to receive(:wait).with(anything, anything) do
subject.instance_variable_set(:@state, :started)
end
result = subject.wait_for_state(:started)
expect(result).to be_truthy
end

it 'waits for the next state change and returns falsey if then not the desired state' do
expect(subject.instance_variable_get(:@state_changed)).to receive(:wait).with(anything, anything)
result = subject.wait_for_state(:started)
expect(result).to be_falsey
end

it 'passes the timeout: down to wait, if given' do
expect(subject.instance_variable_get(:@state_changed)).to receive(:wait).with(anything, 5.0)
subject.wait_for_state(:started, timeout: 5.0)
end

it 'passes nil (infinite) timeout: down to wait, if none given' do
expect(subject.instance_variable_get(:@state_changed)).to receive(:wait).with(anything, nil)
subject.wait_for_state(:started)
end

it 'enforces precondition that states must be symbols' do
expect do
subject.wait_for_state(:started, 'stopped')
end.to raise_exception(ArgumentError, /states must be symbols .*got "stopped"/)
end
end
end

context 'FSM with no start state' do
Expand Down

0 comments on commit 5e0c64d

Please sign in to comment.