state_machines_rspec 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,133 @@
1
+ require 'spec_helper'
2
+
3
+ describe StateMachinesRspec::Matchers::HandleEventMatcher do
4
+ describe '#matches?' do
5
+ context 'when :when state is specified' do
6
+ context 'but the state doesn\'t exist' do
7
+ before do
8
+ matcher_class = Class.new do
9
+ state_machine :state, initial: :mathy
10
+ end
11
+ @matcher_subject = matcher_class.new
12
+ @matcher = described_class.new([when: :artsy])
13
+ end
14
+
15
+ it 'raises' do
16
+ expect { @matcher.matches? @matcher_subject }.
17
+ to raise_error StateMachinesIntrospectorError
18
+ end
19
+ end
20
+
21
+ context 'and that state exists' do
22
+ before do
23
+ matcher_class = Class.new do
24
+ state_machine :state, initial: :mathy do
25
+ state :artsy
26
+ end
27
+ end
28
+ @matcher_subject = matcher_class.new
29
+ @matcher = described_class.new([when: :artsy])
30
+ end
31
+
32
+ it 'sets the state' do
33
+ @matcher.matches? @matcher_subject
34
+ expect(@matcher_subject.state).to eq 'artsy'
35
+ end
36
+ end
37
+ end
38
+
39
+ context 'when subject can perform events' do
40
+ before do
41
+ matcher_class = Class.new do
42
+ state_machine :mathiness, initial: :mathy do
43
+ event(:mathematize) { transition any => same }
44
+ end
45
+ end
46
+ @matcher_subject = matcher_class.new
47
+ @matcher = described_class.new([:mathematize, on: :mathiness])
48
+ end
49
+
50
+ it 'does not set a failure message' do
51
+ @matcher.matches? @matcher_subject
52
+ expect(@matcher.failure_message).to be_nil
53
+ end
54
+ it 'returns true' do
55
+ expect(@matcher.matches?(@matcher_subject)).to be_truthy
56
+ end
57
+ end
58
+
59
+ context 'when subject cannot perform events' do
60
+ before do
61
+ matcher_class = Class.new do
62
+ state_machine :state, initial: :mathy do
63
+ state :polynomial
64
+
65
+ event(:mathematize) { transition any => same }
66
+ event(:algebraify) { transition :polynomial => same }
67
+ event(:trigonomalize) { transition :trigonomalize => same }
68
+ end
69
+ end
70
+ @matcher_subject = matcher_class.new
71
+ end
72
+
73
+ context 'because it cannot perform the transition' do
74
+ before do
75
+ @matcher = described_class.new([:mathematize, :algebraify, :trigonomalize])
76
+ end
77
+
78
+ it 'sets a failure message' do
79
+ @matcher.matches? @matcher_subject
80
+ expect(@matcher.failure_message).to eq('Expected to be able to handle events: algebraify, trigonomalize ' +
81
+ 'in state: mathy')
82
+ end
83
+ it 'returns false' do
84
+ expect(@matcher.matches?(@matcher_subject)).to be_falsey
85
+ end
86
+ end
87
+
88
+ context 'because no such events exist' do
89
+ before do
90
+ @matcher = described_class.new([:polynomialize, :eulerasterize])
91
+ end
92
+
93
+ it 'does not raise' do
94
+ expect { @matcher.matches?(@matcher_subject) }.not_to raise_error
95
+ end
96
+ it 'sets a failure message' do
97
+ @matcher.matches? @matcher_subject
98
+ expect(@matcher.failure_message).to eq('state_machine: state does not ' +
99
+ 'define events: polynomialize, eulerasterize')
100
+ end
101
+ it 'returns false' do
102
+ expect(@matcher.matches?(@matcher_subject)).to be_falsey
103
+ end
104
+ end
105
+ end
106
+ end
107
+
108
+ describe '#description' do
109
+ context 'with no options' do
110
+ let(:matcher) { described_class.new([:placate, :mollify]) }
111
+
112
+ it 'returns a string description' do
113
+ expect(matcher.description).to eq('handle :placate, :mollify')
114
+ end
115
+ end
116
+
117
+ context 'when :when state is specified' do
118
+ let(:matcher) { described_class.new([:destroy_food, when: :hangry]) }
119
+
120
+ it 'mentions the requisite state' do
121
+ expect(matcher.description).to eq('handle :destroy_food when :hangry')
122
+ end
123
+ end
124
+
125
+ context 'when :on is specified' do
126
+ let(:matcher) { described_class.new([:ensmarmify, on: :tired_investors]) }
127
+
128
+ it 'mentions the state machines variable' do
129
+ expect(matcher.description).to eq('handle :ensmarmify on :tired_investors')
130
+ end
131
+ end
132
+ end
133
+ end
@@ -0,0 +1,133 @@
1
+ require 'spec_helper'
2
+
3
+ describe StateMachinesRspec::Matchers::RejectEventMatcher do
4
+ describe '#matches?' do
5
+ context 'when :when state is specified' do
6
+ context 'but that state doesn\'t exist' do
7
+ before do
8
+ matcher_class = Class.new do
9
+ state_machine :state, initial: :sleazy
10
+ end
11
+ @matcher_subject = matcher_class.new
12
+ @matcher = described_class.new([when: :sneezy])
13
+ end
14
+
15
+ it 'raises' do
16
+ expect { @matcher.matches? @matcher_subject }.
17
+ to raise_error StateMachinesIntrospectorError
18
+ end
19
+ end
20
+
21
+ context 'and that state exists' do
22
+ before do
23
+ matcher_class = Class.new do
24
+ state_machine :state, initial: :sleazy do
25
+ state :sneezy
26
+ end
27
+ end
28
+ @matcher_subject = matcher_class.new
29
+ @matcher = described_class.new([when: :sneezy])
30
+ end
31
+
32
+ it 'sets the state' do
33
+ @matcher.matches? @matcher_subject
34
+ expect(@matcher_subject.state).to eq('sneezy')
35
+ end
36
+ end
37
+ end
38
+
39
+ context 'when an expectation is made on an event that is undefined' do
40
+ before do
41
+ matcher_class = Class.new do
42
+ state_machine :state, initial: :snarky do
43
+ event(:primmadonnalize) { transition any => same }
44
+ end
45
+ end
46
+ @matcher_subject = matcher_class.new
47
+ @matcher = described_class.new([:primmadonnalize, :martinilunchitize])
48
+ end
49
+
50
+ it 'does not raise' do
51
+ expect { @matcher.matches?(@matcher_subject) }.not_to raise_error
52
+ end
53
+ it 'sets a failure message' do
54
+ @matcher.matches? @matcher_subject
55
+ expect(@matcher.failure_message).to eq('state_machine: state does not ' +
56
+ 'define events: martinilunchitize')
57
+ end
58
+ it 'returns false' do
59
+ expect(@matcher.matches?(@matcher_subject)).to be_falsey
60
+ end
61
+ end
62
+
63
+ context 'when subject cannot perform any of the specified events' do
64
+ before do
65
+ matcher_class = Class.new do
66
+ state_machine :state, initial: :snarky do
67
+ state :haughty
68
+ event(:primmadonnalize) { transition :haughty => same }
69
+ end
70
+ end
71
+ @matcher_subject = matcher_class.new
72
+ @matcher = described_class.new([:primmadonnalize])
73
+ end
74
+
75
+ it 'does not set a failure message' do
76
+ @matcher.matches? @matcher_subject
77
+ expect(@matcher.failure_message).to be_nil
78
+ end
79
+ it 'returns true' do
80
+ expect(@matcher.matches?(@matcher_subject)).to be_truthy
81
+ end
82
+ end
83
+
84
+ context 'when subject can perform any one of the specified events' do
85
+ before do
86
+ matcher_class = Class.new do
87
+ state_machine :state, initial: :snarky do
88
+ state :haughty
89
+ event(:primmadonnalize) { transition :haughty => same }
90
+ event(:defer_to_management) { transition any => same }
91
+ end
92
+ end
93
+ @matcher_subject = matcher_class.new
94
+ @matcher = described_class.new([:primmadonnalize, :defer_to_management])
95
+ end
96
+
97
+ it 'sets a failure message' do
98
+ @matcher.matches? @matcher_subject
99
+ expect(@matcher.failure_message).to eq('Did not expect to be able to handle events: defer_to_management ' +
100
+ 'in state: snarky')
101
+ end
102
+ it 'returns false' do
103
+ expect(@matcher.matches?(@matcher_subject)).to be_falsey
104
+ end
105
+ end
106
+ end
107
+
108
+ describe '#description' do
109
+ context 'with no options' do
110
+ let(:matcher) { described_class.new([:makeadealify, :hustlinate]) }
111
+
112
+ it 'returns a string description' do
113
+ expect(matcher.description).to eq('reject :makeadealify, :hustlinate')
114
+ end
115
+ end
116
+
117
+ context 'when :when state is specified' do
118
+ let(:matcher) { described_class.new([:begargle, when: :sleep_encrusted]) }
119
+
120
+ it 'mentions the requisite state' do
121
+ expect(matcher.description).to eq('reject :begargle when :sleep_encrusted')
122
+ end
123
+ end
124
+
125
+ context 'when :on is specified' do
126
+ let(:matcher) { described_class.new([:harrangue, on: :suspicious_crowd]) }
127
+
128
+ it 'mentions the state machines variable' do
129
+ expect(matcher.description).to eq('reject :harrangue on :suspicious_crowd')
130
+ end
131
+ end
132
+ end
133
+ end
@@ -0,0 +1,136 @@
1
+ require 'spec_helper'
2
+
3
+ describe StateMachinesRspec::Matchers::HaveStateMatcher do
4
+ describe '#matches?' do
5
+ before { @matcher = described_class.new([:rad, :not_so_rad, { on: :radical_state }]) }
6
+
7
+ context 'when values are asserted on multiple states' do
8
+ before do
9
+ @matcher = described_class.new([:rad, :not_so_rad, { value: 'rad' }])
10
+ end
11
+ it 'raises an ArgumentError' do
12
+ expect { @matcher.matches? nil }.to raise_error ArgumentError,
13
+ 'cannot make value assertions on multiple states at once'
14
+ end
15
+ end
16
+
17
+ context 'when class does not have a matching state attribute' do
18
+ before do
19
+ @class = Class.new do
20
+ state_machine :bodacious_state, initial: :super_bodacious
21
+ end
22
+ end
23
+
24
+ it 'raises' do
25
+ expect { @matcher.matches? @class.new }.
26
+ to raise_error StateMachinesIntrospectorError,
27
+ /.+? does not have a state machine defined on radical_state/
28
+ end
29
+ end
30
+
31
+ context 'when class has a matching state attribute' do
32
+ context 'but is missing some of the specified states' do
33
+ before do
34
+ @class = Class.new do
35
+ state_machine :radical_state do
36
+ state :not_so_rad
37
+ end
38
+ end
39
+ end
40
+
41
+ it 'sets a failure message indicating a state is missing' do
42
+ @matcher.matches? @class.new
43
+ expect(@matcher.failure_message).to eq 'Expected radical_state to allow states: rad'
44
+ end
45
+ it 'returns false' do
46
+ expect(@matcher.matches?(@class.new)).to be_falsey
47
+ end
48
+ end
49
+
50
+ context 'and has all states specified' do
51
+ before do
52
+ @class = Class.new do
53
+ state_machine :radical_state do
54
+ state :rad, value: 'totes rad'
55
+ state :not_so_rad, value: 'meh'
56
+ end
57
+ end
58
+ end
59
+
60
+ context 'state values not specified' do
61
+ it 'does not set a failure message' do
62
+ @matcher.matches? @class.new
63
+ expect(@matcher.failure_message).to be_nil
64
+ end
65
+ it 'returns true' do
66
+ expect(@matcher.matches?(@class.new)).to be_truthy
67
+ end
68
+ end
69
+
70
+ context 'state value matches specified value' do
71
+ before do
72
+ @matcher = described_class.new([:rad, { on: :radical_state, value: 'uber-rad' }])
73
+ @class = Class.new do
74
+ state_machine :radical_state do
75
+ state :rad, value: 'uber-rad'
76
+ end
77
+ end
78
+ end
79
+
80
+ it 'does not set a failure message' do
81
+ @matcher.matches? @class.new
82
+ expect(@matcher.failure_message).to be_nil
83
+ end
84
+ it 'returns true' do
85
+ expect(@matcher.matches?(@class.new)).to be_truthy
86
+ end
87
+ end
88
+
89
+ context 'state value does not match specified value' do
90
+ before do
91
+ @matcher = described_class.new([:rad, { on: :radical_state, value: 'uber-rad' }])
92
+ @class = Class.new do
93
+ state_machine :radical_state do
94
+ state :rad, value: 'kinda rad'
95
+ end
96
+ end
97
+ end
98
+
99
+ it 'does not set a failure message' do
100
+ @matcher.matches? @class.new
101
+ expect(@matcher.failure_message).to eq 'Expected rad to have value uber-rad'
102
+ end
103
+ it 'returns true' do
104
+ expect(@matcher.matches?(@class.new)).to be_falsey
105
+ end
106
+ end
107
+ end
108
+ end
109
+ end
110
+
111
+ describe '#description' do
112
+ context 'with no options' do
113
+ let(:matcher) { described_class.new([:fancy_shirt, :cracked_toenail]) }
114
+
115
+ it 'returns a string description' do
116
+ expect(matcher.description).to eq('have :fancy_shirt, :cracked_toenail')
117
+ end
118
+ end
119
+
120
+ context 'when :value is specified' do
121
+ let(:matcher) { described_class.new([:mustache, value: :really_shady]) }
122
+
123
+ it 'mentions the requisite state' do
124
+ expect(matcher.description).to eq('have :mustache == :really_shady')
125
+ end
126
+ end
127
+
128
+ context 'when :on state machines is specified' do
129
+ let(:matcher) { described_class.new([:lunch, on: :tuesday]) }
130
+
131
+ it 'mentions the state machines variable' do
132
+ expect(matcher.description).to eq('have :lunch on :tuesday')
133
+ end
134
+ end
135
+ end
136
+ end
@@ -0,0 +1,97 @@
1
+ require 'spec_helper'
2
+
3
+ describe StateMachinesRspec::Matchers::RejectStateMatcher do
4
+ describe '#matches?' do
5
+ context 'when :on state machines attribute is specified' do
6
+ before { @matcher = described_class.new([:supportive, on: :environment]) }
7
+ context 'but that state machines doesn\'t exist' do
8
+ before { @class = Class.new }
9
+ it 'raises' do
10
+ expect { @matcher.matches? @class.new }.to raise_error
11
+ end
12
+ end
13
+
14
+ context 'and that state machines exists' do
15
+ context 'but it defines states which match one of the specified states' do
16
+ before do
17
+ @class = Class.new do
18
+ state_machine :environment, initial: :supportive
19
+ end
20
+ end
21
+
22
+ it 'sets a failure message' do
23
+ @matcher.matches? @class.new
24
+ expect(@matcher.failure_message).to eq('Did not expect environment to allow states: supportive')
25
+ end
26
+ it 'returns false' do
27
+ expect(@matcher.matches?(@class.new)).to be_falsey
28
+ end
29
+ end
30
+
31
+ context 'and it does not define any of the states specified' do
32
+ before do
33
+ @class = Class.new do
34
+ state_machine :environment, initial: :conducive
35
+ end
36
+ end
37
+
38
+ it 'does not set a failure message' do
39
+ @matcher.matches? @class.new
40
+ expect(@matcher.failure_message).to be_nil
41
+ end
42
+ it 'returns true' do
43
+ expect(@matcher.matches?(@class.new)).to be_truthy
44
+ end
45
+ end
46
+ end
47
+ end
48
+
49
+ context 'when :on state machines is not specified' do
50
+ before { @matcher = described_class.new([:ever_changing]) }
51
+ context 'but the default state machines defines states which match one of the specified states' do
52
+ before do
53
+ @class = Class.new do
54
+ state_machine initial: :ever_changing
55
+ end
56
+ end
57
+
58
+ it 'sets a failure message' do
59
+ @matcher.matches? @class.new
60
+ expect(@matcher.failure_message).to eq('Did not expect state to allow states: ever_changing')
61
+ end
62
+ it 'returns false' do
63
+ expect(@matcher.matches?(@class.new)).to be_falsey
64
+ end
65
+ end
66
+
67
+ context 'and the default state machines does not define any of the states specified' do
68
+ before { @class = Class.new }
69
+ it 'does not set a failure message' do
70
+ @matcher.matches? @class.new
71
+ expect(@matcher.failure_message).to be_nil
72
+ end
73
+ it 'returns true' do
74
+ expect(@matcher.matches?(@class.new)).to be_truthy
75
+ end
76
+ end
77
+ end
78
+ end
79
+
80
+ describe '#description' do
81
+ context 'with no options' do
82
+ let(:matcher) { described_class.new([:mustard, :tomatoes]) }
83
+
84
+ it 'returns a string description' do
85
+ expect(matcher.description).to eq('not have :mustard, :tomatoes')
86
+ end
87
+ end
88
+
89
+ context 'when :on state machines is specified' do
90
+ let(:matcher) { described_class.new([:peanut_butter, on: :toast]) }
91
+
92
+ it 'mentions the state machines variable' do
93
+ expect(matcher.description).to eq('not have :peanut_butter on :toast')
94
+ end
95
+ end
96
+ end
97
+ end