gisele-vm 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (185) hide show
  1. data/CHANGELOG.md +5 -0
  2. data/Gemfile +18 -0
  3. data/Gemfile.lock +46 -0
  4. data/LICENCE.md +22 -0
  5. data/Manifest.txt +15 -0
  6. data/README.md +10 -0
  7. data/Rakefile +11 -0
  8. data/bin/gvm +9 -0
  9. data/gisele-vm.gemspec +191 -0
  10. data/gisele-vm.noespec +31 -0
  11. data/lib/gisele-vm.rb +4 -0
  12. data/lib/gisele-vm/loader.rb +5 -0
  13. data/lib/gisele-vm/version.rb +16 -0
  14. data/lib/gisele/compiling.rb +3 -0
  15. data/lib/gisele/compiling/gisele2gts.rb +143 -0
  16. data/lib/gisele/compiling/gts.rb +74 -0
  17. data/lib/gisele/compiling/gts2bytecode.rb +127 -0
  18. data/lib/gisele/vm.rb +87 -0
  19. data/lib/gisele/vm/bytecode.rb +84 -0
  20. data/lib/gisele/vm/bytecode/builder.rb +77 -0
  21. data/lib/gisele/vm/bytecode/grammar.citrus +116 -0
  22. data/lib/gisele/vm/bytecode/grammar.rb +19 -0
  23. data/lib/gisele/vm/bytecode/grammar.sexp.yml +113 -0
  24. data/lib/gisele/vm/bytecode/printer.rb +35 -0
  25. data/lib/gisele/vm/command.rb +140 -0
  26. data/lib/gisele/vm/component.rb +91 -0
  27. data/lib/gisele/vm/console.rb +58 -0
  28. data/lib/gisele/vm/enacter.rb +29 -0
  29. data/lib/gisele/vm/errors.rb +26 -0
  30. data/lib/gisele/vm/event.rb +11 -0
  31. data/lib/gisele/vm/event_manager.rb +65 -0
  32. data/lib/gisele/vm/kernel.rb +58 -0
  33. data/lib/gisele/vm/kernel/macros.gvm +214 -0
  34. data/lib/gisele/vm/kernel/opcodes.rb +212 -0
  35. data/lib/gisele/vm/kernel/runner.rb +63 -0
  36. data/lib/gisele/vm/lifecycle.rb +72 -0
  37. data/lib/gisele/vm/logging.rb +18 -0
  38. data/lib/gisele/vm/null_object.rb +19 -0
  39. data/lib/gisele/vm/prog.rb +63 -0
  40. data/lib/gisele/vm/prog_list.rb +55 -0
  41. data/lib/gisele/vm/prog_list/memory.rb +74 -0
  42. data/lib/gisele/vm/prog_list/sqldb.rb +123 -0
  43. data/lib/gisele/vm/prog_list/storage.rb +31 -0
  44. data/lib/gisele/vm/proxy.rb +14 -0
  45. data/lib/gisele/vm/proxy/client.rb +64 -0
  46. data/lib/gisele/vm/proxy/server.rb +29 -0
  47. data/lib/gisele/vm/registry.rb +57 -0
  48. data/lib/gisele/vm/robustness.rb +31 -0
  49. data/lib/gisele/vm/simulator/resumer.rb +32 -0
  50. data/spec/command/gvm_compile.cmd +1 -0
  51. data/spec/command/gvm_compile.stdout +111 -0
  52. data/spec/command/gvm_gts.cmd +1 -0
  53. data/spec/command/gvm_gts.stdout +101 -0
  54. data/spec/command/gvm_help.cmd +1 -0
  55. data/spec/command/gvm_help.stdout +30 -0
  56. data/spec/command/gvm_version.cmd +1 -0
  57. data/spec/command/gvm_version.stdout +2 -0
  58. data/spec/command/test_command.rb +29 -0
  59. data/spec/fixtures/complete.gis +13 -0
  60. data/spec/fixtures/fake_component.rb +24 -0
  61. data/spec/fixtures/kernel.rb +39 -0
  62. data/spec/fixtures/ts.adl +11 -0
  63. data/spec/fixtures/ts.gts +20 -0
  64. data/spec/fixtures/ts.gvm +19 -0
  65. data/spec/spec_helper.rb +86 -0
  66. data/spec/test_examples.rb +29 -0
  67. data/spec/test_gisele-vm.rb +8 -0
  68. data/spec/unit/bytecode/builder/test_at.rb +56 -0
  69. data/spec/unit/bytecode/builder/test_helpers.rb +36 -0
  70. data/spec/unit/bytecode/builder/test_instruction.rb +35 -0
  71. data/spec/unit/bytecode/builder/test_to_a.rb +53 -0
  72. data/spec/unit/bytecode/bytecode.gvm +1 -0
  73. data/spec/unit/bytecode/grammar/fixtures/comments.gvm +16 -0
  74. data/spec/unit/bytecode/grammar/fixtures/every.gvm +46 -0
  75. data/spec/unit/bytecode/grammar/fixtures/singleblock.gvm +2 -0
  76. data/spec/unit/bytecode/grammar/fixtures/twoblocks.gvm +4 -0
  77. data/spec/unit/bytecode/grammar/fixtures/with_end.gvm +5 -0
  78. data/spec/unit/bytecode/grammar/test_array.rb +24 -0
  79. data/spec/unit/bytecode/grammar/test_block.rb +35 -0
  80. data/spec/unit/bytecode/grammar/test_boolean.rb +20 -0
  81. data/spec/unit/bytecode/grammar/test_constant.rb +20 -0
  82. data/spec/unit/bytecode/grammar/test_eol.rb +20 -0
  83. data/spec/unit/bytecode/grammar/test_eol_comment.rb +36 -0
  84. data/spec/unit/bytecode/grammar/test_file.rb +38 -0
  85. data/spec/unit/bytecode/grammar/test_hash.rb +33 -0
  86. data/spec/unit/bytecode/grammar/test_instruction.rb +32 -0
  87. data/spec/unit/bytecode/grammar/test_int.rb +24 -0
  88. data/spec/unit/bytecode/grammar/test_label.rb +24 -0
  89. data/spec/unit/bytecode/grammar/test_opcode.rb +23 -0
  90. data/spec/unit/bytecode/grammar/test_string.rb +25 -0
  91. data/spec/unit/bytecode/grammar/test_symbol.rb +30 -0
  92. data/spec/unit/bytecode/test_build.rb +36 -0
  93. data/spec/unit/bytecode/test_coerce.rb +41 -0
  94. data/spec/unit/bytecode/test_fetch.rb +20 -0
  95. data/spec/unit/bytecode/test_grammar.rb +30 -0
  96. data/spec/unit/bytecode/test_parse.rb +22 -0
  97. data/spec/unit/bytecode/test_plus.rb +27 -0
  98. data/spec/unit/bytecode/test_to_a.rb +19 -0
  99. data/spec/unit/bytecode/test_to_s.rb +32 -0
  100. data/spec/unit/command/code.gis +3 -0
  101. data/spec/unit/command/test_vm.rb +51 -0
  102. data/spec/unit/compiling/gisele2gts/test_on_par_st.rb +51 -0
  103. data/spec/unit/compiling/gisele2gts/test_on_seq_st.rb +46 -0
  104. data/spec/unit/compiling/gisele2gts/test_on_task_call_st.rb +37 -0
  105. data/spec/unit/compiling/gisele2gts/test_on_task_def.rb +49 -0
  106. data/spec/unit/compiling/gisele2gts/test_on_unit_def.rb +35 -0
  107. data/spec/unit/compiling/gts2bytecode/test_on_end.rb +31 -0
  108. data/spec/unit/compiling/gts2bytecode/test_on_event.rb +37 -0
  109. data/spec/unit/compiling/gts2bytecode/test_on_fork.rb +41 -0
  110. data/spec/unit/compiling/gts2bytecode/test_on_join.rb +42 -0
  111. data/spec/unit/compiling/gts2bytecode/test_on_listen.rb +36 -0
  112. data/spec/unit/compiling/gts2bytecode/test_on_nop.rb +30 -0
  113. data/spec/unit/component/test_component_name.rb +16 -0
  114. data/spec/unit/component/test_logging.rb +36 -0
  115. data/spec/unit/enacter/test_component.rb +11 -0
  116. data/spec/unit/event/test_to_s.rb +12 -0
  117. data/spec/unit/event_manager/test_component.rb +9 -0
  118. data/spec/unit/event_manager/test_subscribe.rb +40 -0
  119. data/spec/unit/event_manager/test_unsubscribe.rb +39 -0
  120. data/spec/unit/kernel/macros/test_fork.rb +37 -0
  121. data/spec/unit/kernel/macros/test_join.rb +43 -0
  122. data/spec/unit/kernel/macros/test_listen.rb +37 -0
  123. data/spec/unit/kernel/macros/test_notify.rb +57 -0
  124. data/spec/unit/kernel/macros/test_react.rb +47 -0
  125. data/spec/unit/kernel/macros/test_schedule_at.rb +30 -0
  126. data/spec/unit/kernel/opcodes/test_op_del.rb +42 -0
  127. data/spec/unit/kernel/opcodes/test_op_event.rb +25 -0
  128. data/spec/unit/kernel/opcodes/test_op_fetch.rb +27 -0
  129. data/spec/unit/kernel/opcodes/test_op_flip.rb +17 -0
  130. data/spec/unit/kernel/opcodes/test_op_fold.rb +29 -0
  131. data/spec/unit/kernel/opcodes/test_op_fork.rb +63 -0
  132. data/spec/unit/kernel/opcodes/test_op_forka.rb +51 -0
  133. data/spec/unit/kernel/opcodes/test_op_get.rb +62 -0
  134. data/spec/unit/kernel/opcodes/test_op_getr.rb +48 -0
  135. data/spec/unit/kernel/opcodes/test_op_ifenil.rb +41 -0
  136. data/spec/unit/kernel/opcodes/test_op_ifezero.rb +32 -0
  137. data/spec/unit/kernel/opcodes/test_op_invoke.rb +34 -0
  138. data/spec/unit/kernel/opcodes/test_op_nop.rb +18 -0
  139. data/spec/unit/kernel/opcodes/test_op_parent.rb +39 -0
  140. data/spec/unit/kernel/opcodes/test_op_pop.rb +22 -0
  141. data/spec/unit/kernel/opcodes/test_op_push.rb +17 -0
  142. data/spec/unit/kernel/opcodes/test_op_save.rb +32 -0
  143. data/spec/unit/kernel/opcodes/test_op_savea.rb +34 -0
  144. data/spec/unit/kernel/opcodes/test_op_self.rb +20 -0
  145. data/spec/unit/kernel/opcodes/test_op_send.rb +20 -0
  146. data/spec/unit/kernel/opcodes/test_op_set.rb +61 -0
  147. data/spec/unit/kernel/opcodes/test_op_then.rb +50 -0
  148. data/spec/unit/kernel/opcodes/test_op_unfold.rb +22 -0
  149. data/spec/unit/kernel/opcodes/test_op_uuid.rb +16 -0
  150. data/spec/unit/kernel/runner/test_pop.rb +26 -0
  151. data/spec/unit/kernel/runner/test_stack.rb +28 -0
  152. data/spec/unit/kernel/test_progress.rb +47 -0
  153. data/spec/unit/kernel/test_resume.rb +53 -0
  154. data/spec/unit/kernel/test_start.rb +36 -0
  155. data/spec/unit/prog/test_to_hash.rb +29 -0
  156. data/spec/unit/prog/test_waitlist_eq.rb +20 -0
  157. data/spec/unit/prog_list/memory/test_component.rb +9 -0
  158. data/spec/unit/prog_list/memory/test_fetch.rb +40 -0
  159. data/spec/unit/prog_list/memory/test_pick.rb +39 -0
  160. data/spec/unit/prog_list/memory/test_save.rb +91 -0
  161. data/spec/unit/prog_list/memory/test_to_relation.rb +17 -0
  162. data/spec/unit/prog_list/sqldb/test_component.rb +11 -0
  163. data/spec/unit/prog_list/sqldb/test_connect.rb +46 -0
  164. data/spec/unit/prog_list/test_memory.rb +9 -0
  165. data/spec/unit/prog_list/test_sqldb.rb +13 -0
  166. data/spec/unit/prog_list/test_storage.rb +51 -0
  167. data/spec/unit/registry/test_component.rb +9 -0
  168. data/spec/unit/registry/test_connect.rb +53 -0
  169. data/spec/unit/registry/test_disconnect.rb +51 -0
  170. data/spec/unit/registry/test_registration.rb +44 -0
  171. data/spec/unit/shared/a_component.rb +49 -0
  172. data/spec/unit/shared/a_storage.rb +114 -0
  173. data/spec/unit/test_logging.rb +46 -0
  174. data/spec/unit/test_prog.rb +57 -0
  175. data/spec/unit/test_prog_list.rb +22 -0
  176. data/spec/unit/vm/test_event_facace.rb +11 -0
  177. data/spec/unit/vm/test_initialize.rb +59 -0
  178. data/spec/unit/vm/test_proglist_facade.rb +21 -0
  179. data/tasks/debug_mail.rake +75 -0
  180. data/tasks/debug_mail.txt +13 -0
  181. data/tasks/gem.rake +73 -0
  182. data/tasks/spec_test.rake +71 -0
  183. data/tasks/unit_test.rake +76 -0
  184. data/tasks/yard.rake +51 -0
  185. metadata +493 -0
@@ -0,0 +1,22 @@
1
+ require 'spec_helper'
2
+ module Gisele
3
+ class VM
4
+ describe Kernel, "op_unfold" do
5
+
6
+ it 'unfolds the op array' do
7
+ runner.stack = [ :a, [:b, :c] ]
8
+ runner.op_unfold
9
+ runner.stack.should eq([:a, :b, :c])
10
+ end
11
+
12
+ it 'is the reverse of fold' do
13
+ runner.stack = [:a, [:b, :c] ]
14
+ runner.op_unfold
15
+ runner.stack.should eq([:a, :b, :c])
16
+ runner.op_fold(2)
17
+ runner.stack.should eq([:a, [:b, :c]])
18
+ end
19
+
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,16 @@
1
+ require 'spec_helper'
2
+ module Gisele
3
+ class VM
4
+ describe Kernel, "op_puid" do
5
+
6
+ let(:runn){ runner(Prog.new :puid => 17) }
7
+
8
+ it 'pushes the puid on top of the stack' do
9
+ runn.stack = [:hello]
10
+ runn.op_puid
11
+ runn.stack.should eq([:hello, 17])
12
+ end
13
+
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,26 @@
1
+ require 'spec_helper'
2
+ module Gisele
3
+ class VM
4
+ class Kernel
5
+ describe Runner, 'pop' do
6
+
7
+ before do
8
+ runner.stack = [:a, :b, :c, :d]
9
+ end
10
+
11
+ it 'returns the poped object when n is not specified' do
12
+ runner.pop.should eq(:d)
13
+ runner.pop.should eq(:c)
14
+ runner.stack.should eq([:a, :b])
15
+ end
16
+
17
+ it 'returns the poped objects when n is specified' do
18
+ runner.pop(0).should eq([])
19
+ runner.pop(2).should eq([:d, :c])
20
+ runner.pop(1).should eq([:b])
21
+ end
22
+
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,28 @@
1
+ require 'spec_helper'
2
+ module Gisele
3
+ class VM
4
+ class Kernel
5
+ describe Runner, "stack" do
6
+
7
+ it 'pushes at the end' do
8
+ runner.stack = [:hello]
9
+ runner.push :world
10
+ runner.stack.should eq([:hello, :world])
11
+ end
12
+
13
+ it 'pops from the end' do
14
+ runner.stack = [:hello, :world]
15
+ runner.pop.should eq(:world)
16
+ runner.stack.should eq([:hello])
17
+ end
18
+
19
+ it 'peeks at the the end' do
20
+ runner.stack = [:hello, :world]
21
+ runner.peek.should eq(:world)
22
+ runner.stack.should eq([:hello, :world])
23
+ end
24
+
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,47 @@
1
+ require 'spec_helper'
2
+ module Gisele
3
+ describe VM, "progress" do
4
+
5
+ subject do
6
+ kernel.progress(arg)
7
+ end
8
+
9
+ before do
10
+ @puid = kernel.start(:ping, [ "world" ])
11
+ end
12
+
13
+ context 'with a puid' do
14
+ let(:arg){ @puid }
15
+ it 'executes the Prog with its input' do
16
+ subject
17
+ prog = list.fetch(@puid)
18
+ expected_event = VM::Event.new(prog, :pong, [ "world" ])
19
+ observed_events.should eq([ expected_event ])
20
+ list.fetch(@puid).input.should eq([])
21
+ end
22
+ end
23
+
24
+ context 'with a prog' do
25
+ let(:arg){ list.fetch(@puid) }
26
+ it 'executes the Prog with its input' do
27
+ subject
28
+ observed_events.should eq([ VM::Event.new(arg, :pong, [ "world" ]) ])
29
+ list.fetch(@puid).input.should eq([])
30
+ end
31
+ end
32
+
33
+ it 'detects invalid puids' do
34
+ lambda{
35
+ kernel.progress(17)
36
+ }.should raise_error(VM::InvalidPUIDError, "Invalid puid: `17`")
37
+ end
38
+
39
+ it 'detects progs that do not wait for the enacter' do
40
+ list.save(VM::Prog.new :puid => @puid, :waitfor => :world)
41
+ lambda{
42
+ kernel.progress(@puid)
43
+ }.should raise_error(VM::InvalidStateError, "Prog `#{@puid}` does not wait for the enacter")
44
+ end
45
+
46
+ end
47
+ end
@@ -0,0 +1,53 @@
1
+ require 'spec_helper'
2
+ module Gisele
3
+ describe VM, "resume" do
4
+
5
+ subject do
6
+ kernel.resume(arg, [ :an_event ])
7
+ end
8
+
9
+ before do
10
+ @puid = list.save VM::Prog.new(:pc => :hello, :waitfor => :world)
11
+ end
12
+
13
+ let(:expected){
14
+ Relation(:puid => @puid, :waitfor => :enacter, :input => [ :an_event ])
15
+ }
16
+
17
+ context 'with a puid' do
18
+ let(:arg){ @puid }
19
+ it 'creates a fresh new Prog instance and schedules it' do
20
+ subject
21
+ list.to_relation.project([:puid, :waitfor, :input]).should eq(expected)
22
+ end
23
+ end
24
+
25
+ context 'with a Prog' do
26
+ let(:arg){ list.fetch(@puid) }
27
+ it 'creates a fresh new Prog instance and schedules it' do
28
+ subject
29
+ list.to_relation.project([:puid, :waitfor, :input]).should eq(expected)
30
+ end
31
+ end
32
+
33
+ it 'detects invalid puids' do
34
+ lambda{
35
+ kernel.resume(17, [])
36
+ }.should raise_error(VM::InvalidPUIDError, "Invalid puid: `17`")
37
+ end
38
+
39
+ it 'detects invalid inputs' do
40
+ lambda{
41
+ kernel.resume(@puid, 12)
42
+ }.should raise_error(VM::InvalidInputError, "Invalid VM input: `12`")
43
+ end
44
+
45
+ it 'detects progs that do not wait for the world' do
46
+ list.save(VM::Prog.new :puid => @puid, :waitfor => :enacter)
47
+ lambda{
48
+ kernel.resume(@puid, [])
49
+ }.should raise_error(VM::InvalidStateError, "Prog `#{@puid}` does not wait for the world")
50
+ end
51
+
52
+ end
53
+ end
@@ -0,0 +1,36 @@
1
+ require 'spec_helper'
2
+ module Gisele
3
+ describe VM, "start" do
4
+
5
+ subject do
6
+ kernel.start(:ping, [ 12 ])
7
+ end
8
+
9
+ before do
10
+ subject
11
+ end
12
+
13
+ it 'returns a puid' do
14
+ list.fetch(subject).should be_a(VM::Prog)
15
+ list.fetch(subject).pc.should eq(:ping)
16
+ end
17
+
18
+ it 'creates a fresh new Prog instance and schedules it' do
19
+ expected = Relation(:pc => :ping, :waitfor => :enacter, :input => [ 12 ])
20
+ list.to_relation.project([:pc, :waitfor, :input]).should eq(expected)
21
+ end
22
+
23
+ it 'detects invalid labels' do
24
+ lambda{
25
+ kernel.start(:nosuchone, [])
26
+ }.should raise_error(VM::InvalidLabelError, "Unknown label: `:nosuchone`")
27
+ end
28
+
29
+ it 'detects invalid inputs' do
30
+ lambda{
31
+ kernel.start(:ping, 12)
32
+ }.should raise_error(VM::InvalidInputError, "Invalid VM input: `12`")
33
+ end
34
+
35
+ end
36
+ end
@@ -0,0 +1,29 @@
1
+ require 'spec_helper'
2
+ module Gisele
3
+ class VM
4
+ describe Prog, 'to_hash' do
5
+
6
+ let(:h){ {:puid => 17, :parent => 16, :root => 8} }
7
+ let(:prog){ Prog.new(h) }
8
+
9
+ context 'without argument' do
10
+ subject do
11
+ prog.to_hash
12
+ end
13
+ it 'returns the whole hash' do
14
+ subject.size.should eq(7)
15
+ end
16
+ end
17
+
18
+ context 'with some keys only' do
19
+ subject do
20
+ prog.to_hash([:puid, :parent, :root])
21
+ end
22
+ it 'returns a projection' do
23
+ subject.should eq(h)
24
+ end
25
+ end
26
+
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,20 @@
1
+ require 'spec_helper'
2
+ module Gisele
3
+ class VM
4
+ describe Prog, 'waitlist=' do
5
+
6
+ let(:prog){ Prog.new }
7
+
8
+ it 'sets the waitlist when a Hash' do
9
+ prog.waitlist = {:event => :label}
10
+ prog.waitlist.should eq({:event => :label})
11
+ end
12
+
13
+ it 'coerces the waitlist when an Array' do
14
+ prog.waitlist = [12, 13]
15
+ prog.waitlist.should eq({12 => true, 13 => true})
16
+ end
17
+
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,9 @@
1
+ require 'spec_helper'
2
+ module Gisele
3
+ class VM
4
+ describe ProgList::Memory do
5
+ subject{ ProgList::Memory.new }
6
+ it_should_behave_like "a component"
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,40 @@
1
+ require 'spec_helper'
2
+ class Gisele::VM
3
+ describe ProgList::Memory, 'fetch' do
4
+ let(:list){ ProgList::Memory.new }
5
+
6
+ before do
7
+ @puid = list.save(Prog.new)
8
+ end
9
+
10
+ it 'returns Progs' do
11
+ list.fetch(@puid).should be_a(Prog)
12
+ end
13
+
14
+ it 'returns the correct Prog' do
15
+ list.fetch(@puid).puid.should eq(@puid)
16
+ end
17
+
18
+ it 'distributes copies, not original Progs' do
19
+ list.fetch(@puid).pc = :newpc
20
+ list.fetch(@puid).pc.should eq(:main)
21
+ end
22
+
23
+ it 'allows passing strings' do
24
+ list.fetch(@puid.to_s).should be_a(Prog)
25
+ end
26
+
27
+ it 'raises an ArgumentError if arg is not an PUID' do
28
+ lambda{
29
+ list.fetch(:blih)
30
+ }.should raise_error(InvalidPUIDError, "Invalid puid: `:blih`")
31
+ end
32
+
33
+ it 'raises an InvalidPUIDError if arg is invalid' do
34
+ lambda{
35
+ list.fetch(12)
36
+ }.should raise_error(InvalidPUIDError, "Invalid puid: `12`")
37
+ end
38
+
39
+ end
40
+ end
@@ -0,0 +1,39 @@
1
+ require 'spec_helper'
2
+ class Gisele::VM
3
+ describe ProgList::Memory, 'pick' do
4
+ let(:list){ ProgList::Memory.new }
5
+
6
+ context 'when a matching Prog exists' do
7
+
8
+ before do
9
+ @puid0 = list.save(Prog.new(:waitfor => :world))
10
+ @puid1 = list.save(Prog.new(:waitfor => :enacter))
11
+ end
12
+
13
+ it 'returns a Prog' do
14
+ list.pick(:waitfor => :enacter).should be_a(Prog)
15
+ end
16
+
17
+ it 'returns a scheduled Prog' do
18
+ list.pick(:waitfor => :enacter).waitfor.should eq(:enacter)
19
+ end
20
+
21
+ end
22
+
23
+ context 'when no matching Prog exists' do
24
+
25
+ before do
26
+ @puid0 = list.save(Prog.new(:waitfor => :world))
27
+ @puid1 = list.save(Prog.new(:waitfor => :world))
28
+ end
29
+
30
+ it 'calls the block and returns nil' do
31
+ called = false
32
+ list.pick(:waitfor => :enacter){ called = true }.should be_nil
33
+ called.should be_true
34
+ end
35
+
36
+ end
37
+
38
+ end
39
+ end
@@ -0,0 +1,91 @@
1
+ require 'spec_helper'
2
+ class Gisele::VM
3
+ describe ProgList::Memory, 'save' do
4
+
5
+ context 'when arg is an existing Prog' do
6
+ let(:puid){ @puid }
7
+ let(:list){ ProgList::Memory.new }
8
+
9
+ before do
10
+ @puid = list.save(Prog.new :pc => :main)
11
+ end
12
+
13
+ it 'returns the puid' do
14
+ list.save(list.fetch(puid)).should eq(puid)
15
+ end
16
+
17
+ it 'saves the prog for real' do
18
+ list.fetch(puid).pc.should eq(:main)
19
+
20
+ # update it
21
+ prog = list.fetch(puid)
22
+ prog.pc = 12
23
+
24
+ # the original have not changed
25
+ list.fetch(puid).pc.should eq(:main)
26
+
27
+ # save and check
28
+ list.save(prog)
29
+ list.fetch(puid).pc.should eq(12)
30
+ end
31
+
32
+ it 'makes a dup when saving' do
33
+ prog = list.fetch(puid)
34
+ prog.pc = 12
35
+ list.save(prog)
36
+ prog.pc = 23
37
+ list.fetch(puid).pc.should eq(12)
38
+ end
39
+
40
+ end # PUID
41
+
42
+ context 'when arg is a fresh new Prog' do
43
+ let(:puid){ nil }
44
+ let(:list){ ProgList::Memory.new }
45
+
46
+ it 'sets a fresh new puid' do
47
+ puid = list.save(Prog.new)
48
+ puid.should_not be_nil
49
+ list.fetch(puid).puid.should eq(puid)
50
+ list.fetch(puid).parent.should eq(puid)
51
+ list.fetch(puid).root.should eq(puid)
52
+ end
53
+
54
+ it 'accepts a valid parent' do
55
+ parent = list.save(Prog.new)
56
+ child = list.save(Prog.new(:parent => parent))
57
+ list.fetch(child).parent.should eq(parent)
58
+ end
59
+ end
60
+
61
+ context 'when arg is an array of Progs' do
62
+ let(:list){ ProgList::Memory.new }
63
+
64
+ subject do
65
+ list.save([ Prog.new, Prog.new ])
66
+ end
67
+
68
+ it 'returns a list of puids' do
69
+ subject.should be_a(Array)
70
+ end
71
+
72
+ it 'returns valid puids' do
73
+ subject.each{|p| list.fetch(p).should be_a(Prog)}
74
+ end
75
+
76
+ end
77
+
78
+ it 'raises an ArgumentError if arg is not recognized' do
79
+ lambda{
80
+ ProgList::Memory.new.save(self)
81
+ }.should raise_error(ArgumentError)
82
+ end
83
+
84
+ it 'raises an InvalidPUIDError if arg is invalid' do
85
+ lambda{
86
+ ProgList::Memory.new.save(Prog.new(:puid => 12))
87
+ }.should raise_error(InvalidPUIDError)
88
+ end
89
+
90
+ end
91
+ end