tataru 0.1.0 → 0.2.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 (102) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +5 -0
  3. data/bin/console +15 -0
  4. data/bin/setup +8 -0
  5. data/lib/tataru.rb +70 -12
  6. data/lib/tataru/base_resource.rb +49 -0
  7. data/lib/tataru/base_resource_desc.rb +35 -0
  8. data/lib/tataru/compiler.rb +100 -0
  9. data/lib/tataru/create_subroutines.rb +31 -0
  10. data/lib/tataru/delete_subroutines.rb +42 -0
  11. data/lib/tataru/flattener.rb +81 -0
  12. data/lib/tataru/init_hash_compiler.rb +41 -0
  13. data/lib/tataru/instruction.rb +52 -7
  14. data/lib/tataru/instruction_hash.rb +54 -0
  15. data/lib/tataru/instructions/call_instruction.rb +19 -0
  16. data/lib/tataru/instructions/check_create_instruction.rb +27 -0
  17. data/lib/tataru/instructions/check_delete_instruction.rb +20 -0
  18. data/lib/tataru/instructions/check_instruction.rb +26 -0
  19. data/lib/tataru/instructions/check_update_instruction.rb +27 -0
  20. data/lib/tataru/instructions/clear_instruction.rb +12 -0
  21. data/lib/tataru/instructions/compare_instruction.rb +16 -0
  22. data/lib/tataru/instructions/create_instruction.rb +20 -0
  23. data/lib/tataru/instructions/delete_instruction.rb +14 -0
  24. data/lib/tataru/instructions/end_instruction.rb +12 -0
  25. data/lib/tataru/instructions/goto_if_instruction.rb +26 -0
  26. data/lib/tataru/instructions/immediate_mode_instruction.rb +12 -0
  27. data/lib/tataru/instructions/init_instruction.rb +27 -0
  28. data/lib/tataru/instructions/key_instruction.rb +12 -0
  29. data/lib/tataru/instructions/mark_deletable_instruction.rb +13 -0
  30. data/lib/tataru/instructions/read_instruction.rb +28 -0
  31. data/lib/tataru/instructions/rescmp_instruction.rb +34 -0
  32. data/lib/tataru/instructions/resource_instruction.rb +15 -0
  33. data/lib/tataru/instructions/return_instruction.rb +16 -0
  34. data/lib/tataru/instructions/update_instruction.rb +16 -0
  35. data/lib/tataru/instructions/value_instruction.rb +15 -0
  36. data/lib/tataru/instructions/value_rom_instruction.rb +23 -0
  37. data/lib/tataru/instructions/value_update_instruction.rb +18 -0
  38. data/lib/tataru/memory.rb +16 -0
  39. data/lib/tataru/quest.rb +43 -0
  40. data/lib/tataru/representation.rb +22 -0
  41. data/lib/tataru/representations/array_representation.rb +18 -0
  42. data/lib/tataru/representations/hash_representation.rb +20 -0
  43. data/lib/tataru/representations/literal_representation.rb +9 -0
  44. data/lib/tataru/representations/output_representation.rb +19 -0
  45. data/lib/tataru/representations/resource_representation.rb +49 -0
  46. data/lib/tataru/resolver.rb +39 -0
  47. data/lib/tataru/resource_dsl.rb +21 -71
  48. data/lib/tataru/resource_type_pool.rb +22 -0
  49. data/lib/tataru/rom_reader.rb +47 -0
  50. data/lib/tataru/runner.rb +48 -0
  51. data/lib/tataru/sub_planner.rb +41 -0
  52. data/lib/tataru/subroutine_compiler.rb +52 -0
  53. data/lib/tataru/top_dsl.rb +35 -0
  54. data/lib/tataru/update_subroutines.rb +111 -0
  55. data/lib/tataru/version.rb +1 -1
  56. data/spec/compiler_spec.rb +181 -0
  57. data/spec/flattener_spec.rb +88 -0
  58. data/spec/init_hash_compiler_spec.rb +85 -0
  59. data/spec/instruction_hash_spec.rb +63 -0
  60. data/spec/instruction_spec.rb +36 -0
  61. data/spec/instructions/call_instruction_spec.rb +28 -0
  62. data/spec/instructions/check_create_instruction_spec.rb +67 -0
  63. data/spec/instructions/check_delete_instruction_spec.rb +47 -0
  64. data/spec/instructions/check_update_instruction_spec.rb +67 -0
  65. data/spec/instructions/clear_instruction_spec.rb +16 -0
  66. data/spec/instructions/compare_instruction_spec.rb +29 -0
  67. data/spec/instructions/create_instruction_spec.rb +62 -0
  68. data/spec/instructions/delete_instruction_spec.rb +20 -0
  69. data/spec/instructions/end_instruction_spec.rb +15 -0
  70. data/spec/instructions/goto_if_instruction_spec.rb +42 -0
  71. data/spec/instructions/init_instruction_spec.rb +16 -0
  72. data/spec/instructions/key_instruction_spec.rb +15 -0
  73. data/spec/instructions/mark_deletable_instruction_spec.rb +20 -0
  74. data/spec/instructions/read_instruction_spec.rb +34 -0
  75. data/spec/instructions/rescmp_instruction_spec.rb +113 -0
  76. data/spec/instructions/return_instruction_spec.rb +28 -0
  77. data/spec/instructions/update_instruction_spec.rb +39 -0
  78. data/spec/instructions/value_instruction_spec.rb +27 -0
  79. data/spec/instructions/value_rom_instruction_spec.rb +170 -0
  80. data/spec/instructions/value_update_instruction_spec.rb +35 -0
  81. data/spec/quest_spec.rb +9 -0
  82. data/spec/representations/array_representation_spec.rb +29 -0
  83. data/spec/representations/hash_representation_spec.rb +29 -0
  84. data/spec/representations/literal_representation_spec.rb +10 -0
  85. data/spec/representations/output_representation_spec.rb +11 -0
  86. data/spec/representations/resource_representation_spec.rb +50 -0
  87. data/spec/resource_dsl_spec.rb +71 -0
  88. data/spec/runner_spec.rb +99 -0
  89. data/spec/spec_helper.rb +401 -0
  90. data/spec/subroutine_compiler_spec.rb +39 -0
  91. data/spec/taru_spec.rb +616 -0
  92. data/spec/top_dsl_spec.rb +68 -0
  93. data/tataru.gemspec +45 -0
  94. metadata +145 -27
  95. data/Rakefile +0 -8
  96. data/lib/tataru/default_resource_finder.rb +0 -10
  97. data/lib/tataru/execution_step.rb +0 -79
  98. data/lib/tataru/planner.rb +0 -93
  99. data/lib/tataru/requirements.rb +0 -67
  100. data/lib/tataru/requirements_dsl.rb +0 -33
  101. data/lib/tataru/resource.rb +0 -52
  102. data/lib/tataru/state.rb +0 -64
@@ -0,0 +1,88 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'tataru'
4
+
5
+ describe Tataru::Flattener do
6
+ it 'flattens literals' do
7
+ f = Tataru::Flattener.new(Tataru::Representations::LiteralRepresentation.new('meow'))
8
+ expect(f.flattened).to eq(
9
+ top: {
10
+ type: :literal,
11
+ value: 'meow'
12
+ }
13
+ )
14
+ end
15
+
16
+ it 'flattens arrays' do
17
+ f = Tataru::Flattener.new(Tataru::Representations::ArrayRepresentation.new(['meow']))
18
+ expect(f.flattened).to eq(
19
+ top: {
20
+ type: :array,
21
+ references: {
22
+ 0 => :top_0
23
+ }
24
+ },
25
+ top_0: {
26
+ type: :literal,
27
+ value: 'meow'
28
+ }
29
+ )
30
+ end
31
+
32
+ it 'flattens hashes' do
33
+ f = Tataru::Flattener.new(Tataru::Representations::HashRepresentation.new({somefield: 'somevalue'}))
34
+ expect(f.flattened).to eq(
35
+ top: {
36
+ type: :hash,
37
+ references: {
38
+ somefield: :top_somefield
39
+ }
40
+ },
41
+ top_somefield: {
42
+ type: :literal,
43
+ value: 'somevalue'
44
+ }
45
+ )
46
+ end
47
+
48
+ it 'flattens resources' do
49
+ f = Tataru::Flattener.new(Tataru::Representations::ResourceRepresentation.new('thing', Tataru::BaseResourceDesc.new, {}))
50
+ expect(f.flattened).to eq(
51
+ top: {
52
+ type: :hash,
53
+ references: {}
54
+ }
55
+ )
56
+ end
57
+
58
+ it 'flattens outputs' do
59
+ f = Tataru::Flattener.new(Tataru::Representations::OutputRepresentation.new('employee', 'age'))
60
+ expect(f.flattened).to eq(
61
+ top: {
62
+ type: :output,
63
+ resource: 'employee',
64
+ output: 'age'
65
+ }
66
+ )
67
+ end
68
+
69
+ it 'flattens resources that have properties' do
70
+ f = Tataru::Flattener.new(Tataru::Representations::ResourceRepresentation.new(
71
+ 'thing',
72
+ Tataru::BaseResourceDesc.new,
73
+ { somefield: Tataru::Representations::LiteralRepresentation.new('somevalue') }
74
+ ))
75
+ expect(f.flattened).to eq(
76
+ top: {
77
+ type: :hash,
78
+ references: {
79
+ somefield: :top_somefield
80
+ }
81
+ },
82
+ top_somefield: {
83
+ type: :literal,
84
+ value: 'somevalue'
85
+ }
86
+ )
87
+ end
88
+ end
@@ -0,0 +1,85 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'tataru'
4
+
5
+ describe Tataru::InitHashCompiler do
6
+ it 'resolves references' do
7
+ dsl = Tataru::TopDsl.new(Tataru::ResourceTypePool.new)
8
+ ihc = Tataru::InitHashCompiler.new(dsl)
9
+
10
+ refs = {
11
+ aaa: 'top_thing',
12
+ bbb: 'top'
13
+ }
14
+
15
+ expect(ihc.resolved_references('resname', refs)).to eq(
16
+ aaa: 'resname_thing',
17
+ bbb: 'resname'
18
+ )
19
+ end
20
+
21
+ it 'generates an init hash' do
22
+ dsl = Tataru::TopDsl.new(Tataru::ResourceTypePool.new)
23
+ ihc = Tataru::InitHashCompiler.new(dsl)
24
+
25
+ expect(ihc.generate_init_hash).to eq(rom: {}, remote_ids: {})
26
+ end
27
+
28
+ it 'generates hashes for each resource' do
29
+ dsl = Tataru::TopDsl.new(Tataru::ResourceTypePool.new)
30
+ ihc = Tataru::InitHashCompiler.new(dsl)
31
+
32
+ rr = Tataru::Representations::ResourceRepresentation.new('file', Tataru::BaseResourceDesc.new, {})
33
+ allow(dsl).to receive(:resources) { { 'file1' => rr } }
34
+
35
+ allow_any_instance_of(Tataru::Flattener).to receive(:flattened) do
36
+ {
37
+ 'abc' => {
38
+ type: :teststuff
39
+ }
40
+ }
41
+ end
42
+
43
+ expect(ihc.generate_init_hash).to eq(
44
+ rom: {
45
+ 'abc' => {
46
+ type: :teststuff
47
+ }
48
+ },
49
+ remote_ids: {}
50
+ )
51
+ end
52
+
53
+ it 'generates hashes for each resource with references' do
54
+ dsl = Tataru::TopDsl.new(Tataru::ResourceTypePool.new)
55
+ ihc = Tataru::InitHashCompiler.new(dsl)
56
+
57
+ rr = Tataru::Representations::ResourceRepresentation.new('file', Tataru::BaseResourceDesc.new, {
58
+ aaa: Tataru::Representations::LiteralRepresentation.new('meow')
59
+ })
60
+ allow(dsl).to receive(:resources) { { 'file1' => rr } }
61
+
62
+ allow_any_instance_of(Tataru::Flattener).to receive(:flattened) do
63
+ {
64
+ 'abc' => {
65
+ type: :teststuff,
66
+ references: {
67
+ thing: 'top_stuff'
68
+ }
69
+ }
70
+ }
71
+ end
72
+
73
+ expect(ihc.generate_init_hash).to eq(
74
+ rom: {
75
+ 'abc' => {
76
+ type: :teststuff,
77
+ references: {
78
+ thing: 'file1_stuff'
79
+ }
80
+ }
81
+ },
82
+ remote_ids: {}
83
+ )
84
+ end
85
+ end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'tataru'
4
+
5
+ describe Tataru::InstructionHash do
6
+ it 'can be made' do
7
+ im = Tataru::InstructionHash.new(init: {})
8
+
9
+ expect(im.instruction_list).to be_empty
10
+ end
11
+
12
+ it 'makes init properly' do
13
+ im = Tataru::InstructionHash.new(init: {
14
+ remote_ids: {
15
+ 'thing' => 'abc'
16
+ }
17
+ }, instructions: [:init])
18
+
19
+ expect(im.instruction_list[0]).to be_a(Tataru::Instructions::InitInstruction)
20
+ expect(im.instruction_list[0].remote_ids).to eq('thing' => 'abc')
21
+ end
22
+
23
+ it 'adds instructions' do
24
+ im = Tataru::InstructionHash.new(instructions:[
25
+ :create
26
+ ])
27
+
28
+ expect(Tataru::Instructions::CreateInstruction).to receive(:new).and_call_original
29
+
30
+ expect(im.instruction_list[0]).to be_a(Tataru::Instructions::CreateInstruction)
31
+ end
32
+
33
+ it 'add more instructions' do
34
+ im = Tataru::InstructionHash.new(instructions:[
35
+ :create,
36
+ :delete
37
+ ])
38
+
39
+ expect(Tataru::Instructions::CreateInstruction).to receive(:new).and_call_original
40
+ expect(Tataru::Instructions::DeleteInstruction).to receive(:new).and_call_original
41
+
42
+ expect(im.instruction_list[0]).to be_a(Tataru::Instructions::CreateInstruction)
43
+ expect(im.instruction_list[1]).to be_a(Tataru::Instructions::DeleteInstruction)
44
+ end
45
+
46
+ it 'adds immediate mode instructions' do
47
+ im = Tataru::InstructionHash.new(instructions:[
48
+ { key: 'name' }
49
+ ])
50
+
51
+ expect(Tataru::Instructions::KeyInstruction).to receive(:new).with('name').and_call_original
52
+
53
+ expect(im.instruction_list[0]).to be_a(Tataru::Instructions::KeyInstruction)
54
+ end
55
+
56
+ it 'errors on unknown instruction' do
57
+ im = Tataru::InstructionHash.new(instructions:[
58
+ :unknown
59
+ ])
60
+
61
+ expect { im.instruction_list[0] }.to raise_error "Unknown instruction 'unknown'"
62
+ end
63
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'tataru'
4
+
5
+ describe Tataru::Instruction do
6
+ it 'can be made' do
7
+ Tataru::Instruction.new
8
+ end
9
+
10
+ it 'checks parameters' do
11
+ instr = Class.new(Tataru::Instruction)
12
+ instr.class_eval do
13
+ expects :param1
14
+ end
15
+
16
+ mem = Tataru::Memory.new
17
+ mem.hash[:temp] = {}
18
+
19
+ expect { instr.new.execute(mem) }.to raise_error 'required param param1 not found'
20
+ end
21
+
22
+ it 'allows execution to occur if param exists' do
23
+ instr = Class.new(Tataru::Instruction)
24
+ instr.class_eval do
25
+ expects :param1
26
+ end
27
+
28
+ mem = Tataru::Memory.new
29
+ mem.hash[:temp] = { param1: 'hello' }
30
+
31
+ instruction = instr.new
32
+ expect(instruction).to receive(:run)
33
+
34
+ instruction.execute(mem)
35
+ end
36
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'tataru'
4
+
5
+ describe Tataru::Instructions::CallInstruction do
6
+ it 'call an existing label' do
7
+ mem = Tataru::Memory.new
8
+ instr = Tataru::Instructions::CallInstruction.new('function')
9
+
10
+ mem.hash[:labels] = { 'function' => 10 }
11
+ instr.memory = mem
12
+ instr.run
13
+
14
+ expect(mem.program_counter).to eq 9
15
+ end
16
+
17
+ it 'sets error if no such label' do
18
+ mem = Tataru::Memory.new
19
+ mem.hash[:labels] = { }
20
+ instr = Tataru::Instructions::CallInstruction.new('function')
21
+
22
+ instr.memory = mem
23
+ instr.run
24
+
25
+ expect(mem.program_counter).to eq 0
26
+ expect(mem.error).to eq 'Label not found'
27
+ end
28
+ end
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'tataru'
4
+
5
+ describe Tataru::Instructions::CheckCreateInstruction do
6
+ it 'reverses program counter if not completed' do
7
+ mem = Tataru::Memory.new
8
+ instr = Tataru::Instructions::CheckCreateInstruction.new
9
+
10
+ expect(mem.program_counter).to eq 0
11
+
12
+ mem.hash[:temp] = {
13
+ resource_name: 'thing',
14
+ resource_desc: 'Tataru::BaseResourceDesc'
15
+ }
16
+ mem.hash[:remote_ids] = { 'thing' => 'hello' }
17
+ instr.memory = mem
18
+
19
+ allow_any_instance_of(Tataru::BaseResource).to receive(:create_complete?) { false }
20
+ instr.run
21
+
22
+ expect(mem.program_counter).to eq -1
23
+ end
24
+
25
+ it 'sets outputs' do
26
+ mem = Tataru::Memory.new
27
+ instr = Tataru::Instructions::CheckCreateInstruction.new
28
+
29
+ expect(mem.program_counter).to eq 0
30
+
31
+ mem.hash[:temp] = {
32
+ resource_name: 'thing',
33
+ resource_desc: 'Tataru::BaseResourceDesc'
34
+ }
35
+ mem.hash[:remote_ids] = { 'thing' => 'hello' }
36
+ mem.hash[:outputs] = {}
37
+ instr.memory = mem
38
+
39
+ allow_any_instance_of(Tataru::BaseResource).to receive(:create_complete?) { true }
40
+ allow_any_instance_of(Tataru::BaseResource).to receive(:outputs) { { something: 'a'} }
41
+ allow_any_instance_of(Tataru::BaseResourceDesc).to receive(:output_fields) { [:something] }
42
+ instr.run
43
+
44
+ expect(mem.hash[:outputs]['thing']).to eq(something: 'a')
45
+ expect(mem.program_counter).to eq 0
46
+ end
47
+
48
+ it 'throws if output is not a hash' do
49
+ mem = Tataru::Memory.new
50
+ instr = Tataru::Instructions::CheckCreateInstruction.new
51
+
52
+ expect(mem.program_counter).to eq 0
53
+
54
+ mem.hash[:temp] = {
55
+ resource_name: 'thing',
56
+ resource_desc: 'Tataru::BaseResourceDesc'
57
+ }
58
+ mem.hash[:remote_ids] = { 'thing' => 'hello' }
59
+ mem.hash[:outputs] = {}
60
+ instr.memory = mem
61
+
62
+ allow_any_instance_of(Tataru::BaseResource).to receive(:create_complete?) { true }
63
+ allow_any_instance_of(Tataru::BaseResource).to receive(:outputs) { 'a2' }
64
+ allow_any_instance_of(Tataru::BaseResourceDesc).to receive(:output_fields) { [:something] }
65
+ expect { instr.run }.to raise_error "Output for 'thing' is not a hash"
66
+ end
67
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'tataru'
4
+
5
+ describe Tataru::Instructions::CheckDeleteInstruction do
6
+ it 'reverses program counter if not completed' do
7
+ mem = Tataru::Memory.new
8
+ instr = Tataru::Instructions::CheckDeleteInstruction.new
9
+
10
+ expect(mem.program_counter).to eq 0
11
+
12
+ mem.hash[:temp] = {
13
+ resource_name: 'thing',
14
+ resource_desc: 'Tataru::BaseResourceDesc'
15
+ }
16
+ mem.hash[:remote_ids] = { 'thing' => 'hello' }
17
+ instr.memory = mem
18
+
19
+ allow_any_instance_of(Tataru::BaseResource).to receive(:delete_complete?) { false }
20
+ instr.run
21
+
22
+ expect(mem.program_counter).to eq -1
23
+ end
24
+
25
+ it 'sets deleted' do
26
+ mem = Tataru::Memory.new
27
+ instr = Tataru::Instructions::CheckDeleteInstruction.new
28
+
29
+ expect(mem.program_counter).to eq 0
30
+
31
+ mem.hash[:temp] = {
32
+ resource_name: 'thing',
33
+ resource_desc: 'Tataru::BaseResourceDesc'
34
+ }
35
+ mem.hash[:remote_ids] = { 'thing' => 'hello' }
36
+ mem.hash[:deleted] = []
37
+ instr.memory = mem
38
+
39
+ allow_any_instance_of(Tataru::BaseResource).to receive(:delete_complete?) { true }
40
+ allow_any_instance_of(Tataru::BaseResourceDesc).to receive(:needs_remote_id?) { true }
41
+ instr.run
42
+
43
+ expect(mem.hash[:deleted]).to eq ['thing']
44
+ expect(mem.hash[:remote_ids]).to eq({})
45
+ expect(mem.program_counter).to eq 0
46
+ end
47
+ end
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'tataru'
4
+
5
+ describe Tataru::Instructions::CheckUpdateInstruction do
6
+ it 'reverses program counter if not completed' do
7
+ mem = Tataru::Memory.new
8
+ instr = Tataru::Instructions::CheckUpdateInstruction.new
9
+
10
+ expect(mem.program_counter).to eq 0
11
+
12
+ mem.hash[:temp] = {
13
+ resource_name: 'thing',
14
+ resource_desc: 'Tataru::BaseResourceDesc'
15
+ }
16
+ mem.hash[:remote_ids] = { 'thing' => 'hello' }
17
+ instr.memory = mem
18
+
19
+ allow_any_instance_of(Tataru::BaseResource).to receive(:update_complete?) { false }
20
+ instr.run
21
+
22
+ expect(mem.program_counter).to eq -1
23
+ end
24
+
25
+ it 'sets outputs' do
26
+ mem = Tataru::Memory.new
27
+ instr = Tataru::Instructions::CheckUpdateInstruction.new
28
+
29
+ expect(mem.program_counter).to eq 0
30
+
31
+ mem.hash[:temp] = {
32
+ resource_name: 'thing',
33
+ resource_desc: 'Tataru::BaseResourceDesc'
34
+ }
35
+ mem.hash[:remote_ids] = { 'thing' => 'hello' }
36
+ mem.hash[:outputs] = {}
37
+ instr.memory = mem
38
+
39
+ allow_any_instance_of(Tataru::BaseResource).to receive(:update_complete?) { true }
40
+ allow_any_instance_of(Tataru::BaseResource).to receive(:outputs) { { something: 'a2'} }
41
+ allow_any_instance_of(Tataru::BaseResourceDesc).to receive(:output_fields) { [:something] }
42
+ instr.run
43
+
44
+ expect(mem.hash[:outputs]['thing']).to eq(something: 'a2')
45
+ expect(mem.program_counter).to eq 0
46
+ end
47
+
48
+ it 'throws if output is not a hash' do
49
+ mem = Tataru::Memory.new
50
+ instr = Tataru::Instructions::CheckUpdateInstruction.new
51
+
52
+ expect(mem.program_counter).to eq 0
53
+
54
+ mem.hash[:temp] = {
55
+ resource_name: 'thing',
56
+ resource_desc: 'Tataru::BaseResourceDesc'
57
+ }
58
+ mem.hash[:remote_ids] = { 'thing' => 'hello' }
59
+ mem.hash[:outputs] = {}
60
+ instr.memory = mem
61
+
62
+ allow_any_instance_of(Tataru::BaseResource).to receive(:update_complete?) { true }
63
+ allow_any_instance_of(Tataru::BaseResource).to receive(:outputs) { 'a2' }
64
+ allow_any_instance_of(Tataru::BaseResourceDesc).to receive(:output_fields) { [:something] }
65
+ expect { instr.run }.to raise_error "Output for 'thing' is not a hash"
66
+ end
67
+ end