golem_statemachine 0.9

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,95 @@
1
+ require 'test_helper'
2
+ require 'ruby-debug'
3
+
4
+ # Tests specifically designed to address bugs/problems discovered along the way.
5
+ class ProblematicTest < Test::Unit::TestCase
6
+
7
+ def setup
8
+ @klass = Class.new
9
+ @klass.instance_eval do
10
+ include Golem
11
+ end
12
+ end
13
+
14
+ def test_fire_event_for_multiple_statemachines
15
+
16
+ @klass.instance_eval do
17
+ define_statemachine(:engine) do
18
+ initial_state :stopped
19
+ state :stopped do
20
+ on :start, :to => :idle
21
+ end
22
+ state :idle do
23
+ on :start, :to => :running
24
+ end
25
+ end
26
+ define_statemachine(:fan) do
27
+ initial_state :stopped
28
+ state :stopped do
29
+ on :start, :to => :spinning
30
+ end
31
+ end
32
+ end
33
+
34
+ widget = @klass.new
35
+
36
+ assert_equal :stopped, widget.engine_state
37
+ assert_equal :stopped, widget.fan_state
38
+
39
+ widget.start
40
+
41
+ assert_equal :idle, widget.engine_state
42
+ assert_equal :spinning, widget.fan_state
43
+
44
+ assert_nothing_raised do
45
+ # :fan will raise Golem::ImpossibleEvent, but :engine can proceed, so nothing is raised
46
+ widget.start!
47
+ end
48
+
49
+ assert_equal :running, widget.engine_state
50
+ assert_equal :spinning, widget.fan_state
51
+
52
+ assert !widget.start
53
+
54
+ assert_raise(Golem::ImpossibleEvent) do
55
+ # neither :fan nor :engine can proceed
56
+ widget.start!
57
+ end
58
+
59
+ assert !widget.start
60
+ end
61
+
62
+ def test_fire_entry_action_on_initial_state
63
+ @klass.instance_eval do
64
+ class_eval do
65
+ attr_accessor :off
66
+ end
67
+
68
+ define_statemachine(:engine) do
69
+ initial_state :stopped
70
+ state :stopped do
71
+ enter do |engine|
72
+ engine.off = true
73
+ end
74
+ on :start, :to => :idle
75
+ end
76
+ state :idle do
77
+ enter do |engine|
78
+ engine.off = false
79
+ end
80
+ on :start, :to => :running
81
+ end
82
+ end
83
+ end
84
+
85
+ widget = @klass.new
86
+
87
+ assert_equal :stopped, widget.engine_state
88
+ assert_equal true, widget.off
89
+
90
+ widget.start!
91
+
92
+ assert_equal false, widget.off
93
+ end
94
+ end
95
+
@@ -0,0 +1,106 @@
1
+ require 'test_helper'
2
+ require File.dirname(__FILE__)+'/../examples/seminar'
3
+
4
+ # Test the seminar.rb example.
5
+ class SeminarTest < Test::Unit::TestCase
6
+
7
+ def setup
8
+ @seminar = Seminar.new
9
+ Seminar.output = File.open("#{self.class.name}_#{self.method_name}.log", 'w')
10
+ end
11
+
12
+ def test_initial_status
13
+ assert_equal :proposed, @seminar.statemachine.initial_state
14
+ end
15
+
16
+ def test_open_for_enrollment
17
+ @seminar.max_class_size = 3
18
+
19
+ @seminar.schedule
20
+ @seminar.open
21
+
22
+ assert_equal :open_for_enrollment, @seminar.status
23
+
24
+ @seminar.enroll_student("socrates")
25
+ @seminar.enroll_student("plato")
26
+
27
+ assert_equal :open_for_enrollment, @seminar.status
28
+
29
+ @seminar.drop_student("socrates")
30
+
31
+ assert_equal :open_for_enrollment, @seminar.status
32
+ assert_equal ["plato"], @seminar.students
33
+
34
+ @seminar.enroll_student("aristotle")
35
+ @seminar.enroll_student("socrates")
36
+
37
+ assert_equal :full, @seminar.status
38
+
39
+ @seminar.drop_student("plato")
40
+
41
+ assert_equal :open_for_enrollment, @seminar.status
42
+ assert_equal ["aristotle", "socrates"], @seminar.students
43
+
44
+ @seminar.enroll_student("zeno")
45
+
46
+ assert_equal :full, @seminar.status
47
+
48
+ @seminar.cancel
49
+
50
+ assert_equal :cancelled, @seminar.status
51
+ @seminar.students.each do |student|
52
+ assert @seminar.notifications_sent.include?("#{student}: the seminar has been cancelled")
53
+ end
54
+ end
55
+
56
+ def test_full
57
+ @seminar.max_class_size = 3
58
+
59
+ @seminar.schedule
60
+ @seminar.open
61
+
62
+ @seminar.enroll_student("socrates")
63
+ @seminar.enroll_student("plato")
64
+ @seminar.enroll_student("aristotle")
65
+
66
+ assert_equal :full, @seminar.status
67
+
68
+ @seminar.enroll_student("zeno")
69
+
70
+ assert_equal :full, @seminar.status
71
+ assert_equal ["socrates", "plato", "aristotle"], @seminar.students
72
+ assert_equal ["zeno"], @seminar.waiting_list
73
+
74
+ @seminar.enroll_student("sofia")
75
+
76
+ assert_equal :full, @seminar.status
77
+ assert_equal ["socrates", "plato", "aristotle"], @seminar.students
78
+ assert_equal ["zeno", "sofia"], @seminar.waiting_list
79
+
80
+ @seminar.drop_student("socrates")
81
+
82
+ assert_equal :full, @seminar.status
83
+ assert_equal ["plato", "aristotle", "zeno"], @seminar.students
84
+ assert_equal ["sofia"], @seminar.waiting_list
85
+
86
+ @seminar.drop_student("aristotle")
87
+
88
+ assert_equal :full, @seminar.status
89
+ assert_equal ["plato", "zeno", "sofia"], @seminar.students
90
+ assert_equal [], @seminar.waiting_list
91
+
92
+ @seminar.enroll_student("dennett")
93
+
94
+ assert_equal :full, @seminar.status
95
+ assert_equal ["plato", "zeno", "sofia"], @seminar.students
96
+ assert_equal ["dennett"], @seminar.waiting_list
97
+
98
+ @seminar.cancel
99
+
100
+ assert_equal :cancelled, @seminar.status
101
+ (@seminar.students + @seminar.waiting_list).each do |student|
102
+ assert @seminar.notifications_sent.include?("#{student}: the seminar has been cancelled")
103
+ end
104
+ end
105
+ end
106
+
@@ -0,0 +1,79 @@
1
+ module StatemachineAssertions
2
+ def assert_equal_arrays(arr1, arr2)
3
+ assert_equal [], arr1 - arr2, "array #{arr1} is not equal to array #{arr2}"
4
+ end
5
+
6
+ def assert_transition_on_event(statemachine, event, from_state, to_state)
7
+ from_state = statemachine.states[from_state]
8
+ to_state = statemachine.states[to_state]
9
+ event = statemachine.events[event]
10
+
11
+ assert_not_nil from_state
12
+ assert_not_nil to_state
13
+ assert_not_nil event
14
+
15
+ failure_msg = "#{statemachine} does not have a transition from #{from_state.name.inspect} to #{to_state.name.inspect} on event #{event.name.inspect}"
16
+ failure_msg << "\n\tHas: #{from_state.transitions_on_event[event].collect{|tr| tr.to_s}.join("\n")}"
17
+
18
+
19
+ assert from_state.transitions_on_event[event].any?{|tr| tr.from == from_state && tr.to == to_state}, failure_msg
20
+ end
21
+
22
+ def assert_no_transition_on_event(statemachine, event, from_state, to_state)
23
+ from_state = statemachine.states[from_state]
24
+ to_state = statemachine.states[to_state]
25
+ event = statemachine.events[event]
26
+
27
+ assert_not_nil from_state
28
+ assert_not_nil to_state
29
+ assert_not_nil event
30
+
31
+ failure_msg = "#{statemachine} should not have a transition from #{from_state.name.inspect} to #{to_state.name.inspect} on event #{event.name.inspect}"
32
+
33
+ assert !from_state.transitions_on_event[event].any?{|tr| tr.from == from_state && tr.to == to_state}, failure_msg
34
+ end
35
+
36
+ def assert_transition_on_event_has_callback(statemachine, event, from_state, to_state, callback, callback_method = nil)
37
+ from_state = statemachine.states[from_state]
38
+ to_state = statemachine.states[to_state]
39
+ event = statemachine.events[event]
40
+
41
+ assert_transition_on_event(statemachine, event, from_state, to_state)
42
+
43
+ tr = from_state.transitions_on_event[event].find{|tr| tr.to == to_state}
44
+
45
+ failure_msg = "#{tr.to_s.inspect} does not have an #{callback.inspect} callback"
46
+
47
+ assert_not_nil tr.callbacks[callback], failure_msg
48
+
49
+ assert_equal callback_method, tr.callbacks[callback].callback if callback_method
50
+ end
51
+
52
+ def assert_transition_on_event_has_guard(statemachine, event, from_state, to_state, guard)
53
+ from_state = statemachine.states[from_state]
54
+ to_state = statemachine.states[to_state]
55
+ event = statemachine.events[event]
56
+
57
+ assert_transition_on_event(statemachine, event, from_state, to_state)
58
+
59
+ tr = from_state.transitions_on_event[event].find{|tr| tr.to == to_state}
60
+
61
+ failure_msg = "#{tr.to_s.inspect} does not have #{guard.inspect} as a guard condition"
62
+
63
+ assert tr.guards.collect{|g| g.callback}.include?(guard), failure_msg
64
+ end
65
+
66
+ def assert_transition_on_event_does_not_have_guard(statemachine, event, from_state, to_state, guard)
67
+ from_state = statemachine.states[from_state]
68
+ to_state = statemachine.states[to_state]
69
+ event = statemachine.events[event]
70
+
71
+ assert_transition_on_event(statemachine, event, from_state, to_state)
72
+
73
+ tr = from_state.transitions_on_event[event].find{|tr| tr.to == to_state}
74
+
75
+ failure_msg = "#{tr.to_s.inspect} should not have #{guard.inspect} as a guard condition"
76
+
77
+ assert !tr.guards.collect{|g| g.callback}.include?(guard), failure_msg
78
+ end
79
+ end
@@ -0,0 +1,5 @@
1
+ require 'test/unit'
2
+
3
+ $: << File.dirname(__FILE__)+'/../lib'
4
+
5
+ require 'golem'
@@ -0,0 +1 @@
1
+ # Uninstall hook code here
metadata ADDED
@@ -0,0 +1,119 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: golem_statemachine
3
+ version: !ruby/object:Gem::Version
4
+ hash: 25
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 9
9
+ version: "0.9"
10
+ platform: ruby
11
+ authors:
12
+ - Matt Zukowski
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2011-04-28 00:00:00 Z
18
+ dependencies:
19
+ - !ruby/object:Gem::Dependency
20
+ name: activesupport
21
+ prerelease: false
22
+ requirement: &id001 !ruby/object:Gem::Requirement
23
+ none: false
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ hash: 3
28
+ segments:
29
+ - 0
30
+ version: "0"
31
+ type: :runtime
32
+ version_requirements: *id001
33
+ description: Adds finite state machine behaviour to Ruby classes. Meant as an alternative to acts_as_state_machine/AASM.
34
+ email:
35
+ - matt@roughest.net
36
+ executables: []
37
+
38
+ extensions: []
39
+
40
+ extra_rdoc_files:
41
+ - README.rdoc
42
+ - MIT-LICENSE
43
+ files:
44
+ - .gitignore
45
+ - MIT-LICENSE
46
+ - README.rdoc
47
+ - Rakefile
48
+ - examples/document.rb
49
+ - examples/monster.rb
50
+ - examples/seminar.rb
51
+ - examples/seminar_enrollment.rb
52
+ - init.rb
53
+ - install.rb
54
+ - lib/golem.rb
55
+ - lib/golem/dsl/decision_def.rb
56
+ - lib/golem/dsl/event_def.rb
57
+ - lib/golem/dsl/state_def.rb
58
+ - lib/golem/dsl/state_machine_def.rb
59
+ - lib/golem/dsl/transition_def.rb
60
+ - lib/golem/model/callback.rb
61
+ - lib/golem/model/condition.rb
62
+ - lib/golem/model/event.rb
63
+ - lib/golem/model/state.rb
64
+ - lib/golem/model/state_machine.rb
65
+ - lib/golem/model/transition.rb
66
+ - lib/golem/util/element_collection.rb
67
+ - tasks/golem_statemachine_tasks.rake
68
+ - test/active_record_test.rb
69
+ - test/dsl_test.rb
70
+ - test/monster_test.rb
71
+ - test/problematic_test.rb
72
+ - test/seminar_test.rb
73
+ - test/statemachine_assertions.rb
74
+ - test/test.db
75
+ - test/test_helper.rb
76
+ - uninstall.rb
77
+ homepage: http://github.com/zuk/golem_statemachine
78
+ licenses: []
79
+
80
+ post_install_message:
81
+ rdoc_options:
82
+ - --quiet
83
+ - --title
84
+ - Golem Statmeachine Docs
85
+ - --opname
86
+ - index.html
87
+ - --line-numbers
88
+ - --main
89
+ - README.rdoc
90
+ - --inline-source
91
+ require_paths:
92
+ - lib
93
+ required_ruby_version: !ruby/object:Gem::Requirement
94
+ none: false
95
+ requirements:
96
+ - - ">="
97
+ - !ruby/object:Gem::Version
98
+ hash: 3
99
+ segments:
100
+ - 0
101
+ version: "0"
102
+ required_rubygems_version: !ruby/object:Gem::Requirement
103
+ none: false
104
+ requirements:
105
+ - - ">="
106
+ - !ruby/object:Gem::Version
107
+ hash: 3
108
+ segments:
109
+ - 0
110
+ version: "0"
111
+ requirements: []
112
+
113
+ rubyforge_project:
114
+ rubygems_version: 1.7.2
115
+ signing_key:
116
+ specification_version: 3
117
+ summary: Adds finite state machine behaviour to Ruby classes.
118
+ test_files: []
119
+