porolog 0.0.4 → 1.0.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 (44) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +30 -5
  3. data/Rakefile +7 -2
  4. data/bin/porolog +58 -1
  5. data/coverage/badge.svg +1 -1
  6. data/coverage/index.html +76733 -2638
  7. data/doc/Array.html +1066 -0
  8. data/doc/Object.html +674 -0
  9. data/doc/Porolog.html +4153 -74
  10. data/doc/Symbol.html +501 -0
  11. data/doc/_index.html +280 -6
  12. data/doc/class_list.html +1 -1
  13. data/doc/file.README.html +34 -39
  14. data/doc/index.html +34 -39
  15. data/doc/method_list.html +1337 -57
  16. data/doc/top-level-namespace.html +4 -2
  17. data/lib/porolog.rb +1144 -4
  18. data/lib/porolog/arguments.rb +28 -24
  19. data/lib/porolog/core_ext.rb +188 -0
  20. data/lib/porolog/error.rb +9 -0
  21. data/lib/porolog/goal.rb +357 -0
  22. data/lib/porolog/instantiation.rb +346 -0
  23. data/lib/porolog/predicate.rb +74 -31
  24. data/lib/porolog/predicate/builtin.rb +825 -0
  25. data/lib/porolog/rule.rb +162 -0
  26. data/lib/porolog/scope.rb +4 -4
  27. data/lib/porolog/tail.rb +57 -0
  28. data/lib/porolog/value.rb +105 -0
  29. data/lib/porolog/variable.rb +325 -0
  30. data/test/porolog/arguments_test.rb +244 -195
  31. data/test/porolog/core_ext_test.rb +290 -0
  32. data/test/porolog/goal_test.rb +891 -0
  33. data/test/porolog/instantiation_test.rb +910 -0
  34. data/test/porolog/porolog_test.rb +2376 -13
  35. data/test/porolog/predicate/builtin_test.rb +1340 -0
  36. data/test/porolog/predicate_test.rb +84 -30
  37. data/test/porolog/rule_test.rb +527 -0
  38. data/test/porolog/scope_test.rb +0 -2
  39. data/test/porolog/tail_test.rb +127 -0
  40. data/test/porolog/value_test.rb +315 -0
  41. data/test/porolog/variable_test.rb +1614 -0
  42. data/test/samples_test.rb +277 -0
  43. data/test/test_helper.rb +115 -0
  44. metadata +34 -7
@@ -152,27 +152,11 @@ describe 'Porolog' do
152
152
 
153
153
  end
154
154
 
155
- describe '.builtin' do
156
-
157
- it 'should incremently return Predicates' do
158
- iota1 = Predicate.builtin :iota
159
- zeta1 = Predicate.builtin :zeta
160
- iota2 = Predicate.builtin :iota
161
- zeta2 = Predicate.builtin :zeta
162
-
163
- assert_Predicate iota1, :_iota_1, []
164
- assert_Predicate zeta1, :_zeta_1, []
165
- assert_Predicate iota2, :_iota_2, []
166
- assert_Predicate zeta2, :_zeta_2, []
167
- end
168
-
169
- end
170
-
171
155
  describe '#initialize' do
172
156
 
173
157
  it 'can create predicates in different scopes' do
174
158
  left = Scope.new :left
175
- #right = Scope.new :right # Not explicitly creating scope :right
159
+ #right = Scope.new :right # Not explicitly creating scope :right
176
160
 
177
161
  assert_equal left, Predicate.scope(:left)
178
162
  assert_equal :left, Predicate.scope.name
@@ -258,8 +242,6 @@ describe 'Porolog' do
258
242
  end
259
243
 
260
244
  it 'should add new facts to a predicate' do
261
- skip 'until Rule added'
262
-
263
245
  alpha = Predicate.new 'alpha'
264
246
 
265
247
  alpha.('p','q').fact!
@@ -269,12 +251,10 @@ describe 'Porolog' do
269
251
  assert_equal ' alpha("p","q"):- true', alpha.rules.first.inspect
270
252
  assert_equal 'alpha:- alpha("p","q"):- true', alpha.inspect
271
253
 
272
- assert_predicate alpha, :alpha, [alpha.rules.first]
254
+ assert_Predicate alpha, :alpha, [alpha.rules.first]
273
255
  end
274
256
 
275
257
  it 'should add new falicies to a predicate' do
276
- skip 'until Rule added'
277
-
278
258
  alpha = Predicate.new 'alpha'
279
259
 
280
260
  alpha.('p','q').falicy!
@@ -284,7 +264,7 @@ describe 'Porolog' do
284
264
  assert_equal ' alpha("p","q"):- false', alpha.rules.first.inspect
285
265
  assert_equal 'alpha:- alpha("p","q"):- false', alpha.inspect
286
266
 
287
- assert_predicate alpha, :alpha, [alpha.rules.first]
267
+ assert_Predicate alpha, :alpha, [alpha.rules.first]
288
268
  end
289
269
 
290
270
  end
@@ -298,8 +278,6 @@ describe 'Porolog' do
298
278
  end
299
279
 
300
280
  it 'should return a summary of the predicate with rules' do
301
- skip 'until Rule added'
302
-
303
281
  alpha = Predicate.new 'alpha'
304
282
 
305
283
  alpha.(:x,:y) << [
@@ -316,8 +294,6 @@ describe 'Porolog' do
316
294
  describe '#<<' do
317
295
 
318
296
  it 'should add new rules to a predicate' do
319
- skip 'until Rule added'
320
-
321
297
  alpha = Predicate.new 'alpha'
322
298
 
323
299
  alpha.(:P,:Q) << [
@@ -333,8 +309,8 @@ describe 'Porolog' do
333
309
  assert_instance_of Array, alpha.rules.first.definition
334
310
  assert_equal 2, alpha.rules.first.definition.size
335
311
 
336
- assert_arguments alpha.rules.first.definition[0], :alpha, [:P,:Q]
337
- assert_arguments alpha.rules.first.definition[1], :alpha, [:Q,:P]
312
+ assert_Arguments alpha.rules.first.definition[0], :alpha, [:P,:Q]
313
+ assert_Arguments alpha.rules.first.definition[1], :alpha, [:Q,:P]
338
314
 
339
315
  assert_equal ' alpha(:P,:Q):- [alpha(:P,:Q), alpha(:Q,:P)]', alpha.rules.first.inspect
340
316
  assert_equal [
@@ -343,7 +319,85 @@ describe 'Porolog' do
343
319
  ' alpha(:P,:Q):- [alpha(:P,:P), alpha(:Q,:Q)]',
344
320
  ].join("\n"), alpha.inspect
345
321
 
346
- assert_predicate alpha, :alpha, [alpha.rules.first,alpha.rules.second]
322
+ assert_Predicate alpha, :alpha, [alpha.rules[0],alpha.rules[1]]
323
+ end
324
+
325
+ end
326
+
327
+ describe '#builtin?' do
328
+
329
+ it 'should return false for normal predicates' do
330
+ p = predicate :normal
331
+
332
+ assert_equal false, p.builtin?
333
+ end
334
+
335
+ it 'should return true for builtin predicates' do
336
+ p = builtin :append
337
+
338
+ assert_equal true, p.builtin?
339
+ end
340
+
341
+ end
342
+
343
+ describe '#satisfy_builtin' do
344
+
345
+ module Porolog
346
+ class Predicate
347
+ module Builtin
348
+ def user_defined(goal, block, *args, &arg_block)
349
+ puts 'Called user_defined'
350
+ block.call(goal, *args) || false
351
+ end
352
+ end
353
+ end
354
+ end
355
+
356
+ let(:predicate1) { Predicate.new :user_defined, builtin: true }
357
+ let(:arguments1) { predicate1.arguments(:m,:n) }
358
+ let(:goal) { arguments1.goal }
359
+
360
+ it 'should satisfy builtin predicate' do
361
+ called = false
362
+
363
+ assert_output "Called user_defined\n" do
364
+ predicate1.satisfy_builtin(goal) {|*args|
365
+ called = args
366
+ }
367
+ end
368
+
369
+ assert_equal [goal, goal[:m], goal[:n]], called
370
+ end
371
+
372
+ end
373
+
374
+ describe '.call_builtin' do
375
+
376
+ it 'should raise an exception when no such builtin predicate exists' do
377
+ assert_raises NameError do
378
+ Predicate.call_builtin(:non_existent)
379
+ end
380
+
381
+ end
382
+
383
+ it 'should call a builtin predicate' do
384
+ module Porolog
385
+ class Predicate
386
+ module Builtin
387
+ def custom(goal, block, *args, &arg_block)
388
+ block.call(goal, *args) || false
389
+ end
390
+ end
391
+ end
392
+ end
393
+ called = false
394
+
395
+ goal = new_goal :a, :b, :c
396
+ block = ->(goal, *args){
397
+ called = [goal] + args
398
+ }
399
+ Porolog::Predicate.call_builtin(:custom, goal, block, goal[:X], [1,2,3]) { 1 }
400
+ assert_equal [goal, goal[:X], [1,2,3]], called
347
401
  end
348
402
 
349
403
  end
@@ -0,0 +1,527 @@
1
+ #
2
+ # test/porolog/rule_test.rb - Test Suite for Porolog::Rule
3
+ #
4
+ # Luis Esteban 2 May 2018
5
+ # created
6
+ #
7
+
8
+
9
+ require_relative '../test_helper'
10
+
11
+ describe 'Porolog' do
12
+
13
+ before(:all) do
14
+ reset
15
+ end
16
+
17
+ describe 'Rule' do
18
+
19
+ describe '.reset' do
20
+
21
+ it 'should delete/unregister all rules' do
22
+ pred = Predicate.new :pred
23
+ args = Arguments.new pred, [1,2,3]
24
+
25
+ rule1 = Rule.new args, [1,2]
26
+ rule2 = Rule.new args, [3,4,5]
27
+ rule3 = Rule.new args, [6]
28
+
29
+ assert_equal 'Rule1', rule1.myid
30
+ assert_equal 'Rule2', rule2.myid
31
+ assert_equal 'Rule3', rule3.myid
32
+
33
+ Rule.reset
34
+
35
+ rule4 = Rule.new args, [7,8,9,0]
36
+ rule5 = Rule.new args, [:CUT,false]
37
+
38
+ assert_equal 'Rule-999', rule1.myid
39
+ assert_equal 'Rule-999', rule2.myid
40
+ assert_equal 'Rule-999', rule3.myid
41
+ assert_equal 'Rule1', rule4.myid
42
+ assert_equal 'Rule2', rule5.myid
43
+ end
44
+
45
+ end
46
+
47
+ describe '.new' do
48
+
49
+ it 'should create a new rule' do
50
+ pred = Predicate.new :pred
51
+ args = Arguments.new pred, [1,2,3]
52
+ defn = [true]
53
+ rule = Rule.new args, defn
54
+
55
+ assert_Rule rule, :pred, [1,2,3], [true]
56
+ end
57
+
58
+ end
59
+
60
+ describe '#initialize' do
61
+
62
+ it 'should initialize arguments and definition' do
63
+ pred = Predicate.new :pred
64
+ args = Arguments.new pred, [1,2,3]
65
+ defn = [:CUT,false]
66
+ rule = Rule.new args, defn
67
+
68
+ assert_Rule rule, :pred, [1,2,3], [:CUT,false]
69
+ assert_equal args, rule.arguments
70
+ assert_equal defn, rule.definition
71
+ end
72
+
73
+ end
74
+
75
+ describe '#myid' do
76
+
77
+ it 'should show the rule index' do
78
+ pred = Predicate.new :pred
79
+ args = Arguments.new pred, [1,2,3]
80
+ defn = [:CUT,false]
81
+ rule = Rule.new args, defn
82
+
83
+ assert_equal 'Rule1', rule.myid
84
+ end
85
+
86
+ it 'should show -999 when deleted/unregistered' do
87
+ pred = Predicate.new :pred
88
+ args = Arguments.new pred, [1,2,3]
89
+ defn = [:CUT,false]
90
+ rule = Rule.new args, defn
91
+
92
+ Rule.reset
93
+
94
+ assert_equal 'Rule-999', rule.myid
95
+ end
96
+
97
+ end
98
+
99
+ describe '#inspect' do
100
+
101
+ it 'should show the predicate, arguments, and definition' do
102
+ pred = Predicate.new :pred
103
+ args = Arguments.new pred, [1,2,3]
104
+ defn = [:CUT,false]
105
+ rule = Rule.new args, defn
106
+
107
+ assert_equal ' pred(1,2,3):- [:CUT, false]', rule.inspect
108
+ end
109
+
110
+ end
111
+
112
+ describe '#satisfy' do
113
+
114
+ it 'should create a subgoal and unify with the goal' do
115
+ pred = Predicate.new :pred
116
+ args = Arguments.new pred, [:a,:b,:c]
117
+ defn = [true]
118
+ rule = Rule.new args, defn
119
+
120
+ goal = new_goal :pred, :x, :y, :z
121
+
122
+ called = false
123
+ rule.satisfy(goal) do |solution_goal|
124
+ called = true
125
+
126
+ assert_Goal solution_goal, :pred, [:a, :b, :c].map{|name| solution_goal.variable(name) }
127
+ assert_Goal_variables solution_goal, { a: nil, b: nil, c: nil }, [
128
+ 'Goal2.:a',
129
+ ' Goal1.:x',
130
+ 'Goal2.:b',
131
+ ' Goal1.:y',
132
+ 'Goal2.:c',
133
+ ' Goal1.:z',
134
+ ].join("\n")
135
+
136
+ assert_equal goal, solution_goal.calling_goal
137
+ end
138
+
139
+ assert called, 'the satisfy block should be called'
140
+ end
141
+
142
+ it 'should delete the subgoal even if it does not unify with the goal' do
143
+ pred = Predicate.new :alpha
144
+ args = Arguments.new pred, [1,2,3,4]
145
+ defn = [true]
146
+ rule = Rule.new args, defn
147
+
148
+ goal = new_goal :beta, :x, :y
149
+
150
+ subgoal = new_goal :gamma, :x, :y
151
+ subgoal.expects(:delete!).with().times(1)
152
+ subgoal_spy = Spy.on(Goal, :new).and_return(subgoal)
153
+ called = false
154
+
155
+ rule.satisfy(goal) do |solution_goal|
156
+ #:nocov:
157
+ called = true
158
+ #:nocov:
159
+ end
160
+ refute called, 'the satisfy block should not be called'
161
+ assert_equal 1, subgoal_spy.calls.size
162
+ end
163
+
164
+ end
165
+
166
+ describe '#satisfy_definition' do
167
+
168
+ it 'should call block with subgoal and return true when the definition is true' do
169
+ pred = Predicate.new :normal
170
+ args = Arguments.new pred, [12]
171
+ rule = Rule.new args, true
172
+
173
+ check = 56
174
+ result = rule.satisfy_definition(12, 34) do |subgoal|
175
+ assert_equal 34, subgoal
176
+ check = 78
177
+ end
178
+ assert_equal true, result
179
+ assert_equal 78, check
180
+ end
181
+
182
+ it 'should not call block but return false when the definition is false' do
183
+ pred = Predicate.new :negative
184
+ args = Arguments.new pred, [12]
185
+ rule = Rule.new args, false
186
+
187
+ check = 56
188
+ result = rule.satisfy_definition(12, 34) do |subgoal|
189
+ #:nocov:
190
+ check = 78
191
+ #:nocov:
192
+ end
193
+ assert_equal false, result
194
+ assert_equal 56, check
195
+ end
196
+
197
+ it 'should call block with subgoal when the definition is an Array' do
198
+ pred1 = Predicate.new :success
199
+ args1 = Arguments.new pred1, [:any]
200
+ Rule.new args1, true
201
+
202
+ pred2 = Predicate.new :conjunction
203
+ args2 = Arguments.new pred2, [12]
204
+ rule2 = Rule.new args2, [true,true,true]
205
+
206
+ check = 56
207
+ result = rule2.satisfy_definition(args1.goal, args2.goal) do |subgoal|
208
+ check = 78
209
+ end
210
+ assert_equal true, result
211
+ assert_equal 78, check
212
+ end
213
+
214
+ it 'should raise an exception when the definition is unknown' do
215
+ predicate :strange
216
+
217
+ strange(12) << 3.4
218
+
219
+ exception = assert_raises Rule::DefinitionError do
220
+ strange(:X).solve
221
+ end
222
+ assert_equal 'UNEXPECTED TYPE OF DEFINITION: 3.4 (Float)', exception.message
223
+ end
224
+
225
+ end
226
+
227
+ describe '#satisfy_conjunction' do
228
+
229
+ let(:pred1 ) { Predicate.new :parent }
230
+ let(:pred2 ) { Predicate.new :child }
231
+ let(:args1 ) { Arguments.new pred1, [1,2,3,4] }
232
+ let(:args2 ) { Arguments.new pred2, [:x,:y] }
233
+ let(:goal ) { Goal.new args1, nil }
234
+ let(:subgoal) { Goal.new args2, goal }
235
+
236
+ it 'should handle CUT expression' do
237
+ rule = Rule.new args1, [:CUT,true]
238
+
239
+ goal.expects(:terminate!).with().times(1)
240
+ rule_spy = Spy.on(rule, :satisfy_conjunction).and_call_through
241
+ called = false
242
+
243
+ result = rule.satisfy_conjunction(goal, subgoal, rule.definition) do |solution_goal|
244
+ called = true
245
+ end
246
+
247
+ assert result, 'satisfy_conjunction should succeed'
248
+ assert called, 'the satisfy block should be called'
249
+ assert_equal 2, rule_spy.calls.size
250
+ assert_equal [goal, subgoal, [true]], rule_spy.calls[0].args # innermost call; finishes first
251
+ assert_equal [goal, subgoal, [:CUT,true]], rule_spy.calls[1].args # outermost call; finishes last
252
+ end
253
+
254
+ it 'should handle CUT expression at the end of a conjunction' do
255
+ rule = Rule.new args1, [:CUT]
256
+
257
+ goal.expects(:terminate!).with().times(1)
258
+ rule_spy = Spy.on(rule, :satisfy_conjunction).and_call_through
259
+ called = false
260
+
261
+ result = rule.satisfy_conjunction(goal, subgoal, rule.definition) do |solution_goal|
262
+ called = true
263
+ end
264
+
265
+ assert result, 'satisfy_conjunction should succeed'
266
+ assert called, 'the satisfy block should be called'
267
+ assert_equal 1, rule_spy.calls.size
268
+ assert_equal [goal, subgoal, [:CUT]], rule_spy.calls[0].args
269
+ end
270
+
271
+ it 'should handle true expression' do
272
+ rule = Rule.new args1, [true]
273
+
274
+ goal.expects(:terminate!).with().times(0)
275
+ rule_spy = Spy.on(rule, :satisfy_conjunction).and_call_through
276
+ called = false
277
+
278
+ result = rule.satisfy_conjunction(goal, subgoal, rule.definition) do |solution_goal|
279
+ called = true
280
+ end
281
+
282
+ assert result, 'satisfy_conjunction should succeed'
283
+ assert called, 'the satisfy block should be called'
284
+ assert_equal 1, rule_spy.calls.size
285
+ assert_equal [goal, subgoal, [true]], rule_spy.calls[0].args
286
+ end
287
+
288
+ it 'should handle false expression' do
289
+ rule = Rule.new args1, [false]
290
+
291
+ goal.expects(:terminate!).with().times(0)
292
+ rule_spy = Spy.on(rule, :satisfy_conjunction).and_call_through
293
+ called = false
294
+
295
+ result = rule.satisfy_conjunction(goal, subgoal, rule.definition) do |solution_goal|
296
+ #:nocov:
297
+ called = true
298
+ #:nocov:
299
+ end
300
+
301
+ refute result, 'satisfy_conjunction should not succeed'
302
+ refute called, 'the satisfy block should not be called'
303
+ assert_equal 1, rule_spy.calls.size
304
+ assert_equal [goal, subgoal, [false]], rule_spy.calls[0].args
305
+ end
306
+
307
+ it 'should handle nil expression' do
308
+ rule = Rule.new args1, []
309
+
310
+ goal.expects(:terminate!).with().times(0)
311
+ rule_spy = Spy.on(rule, :satisfy_conjunction).and_call_through
312
+ called = false
313
+
314
+ result = rule.satisfy_conjunction(goal, subgoal, rule.definition) do |solution_goal|
315
+ #:nocov:
316
+ called = true
317
+ #:nocov:
318
+ end
319
+
320
+ assert result, 'satisfy_conjunction should not succeed'
321
+ assert called, 'the satisfy block should not be called'
322
+ assert_equal 1, rule_spy.calls.size
323
+ assert_equal [goal, subgoal, []], rule_spy.calls[0].args
324
+ end
325
+
326
+ it 'should evaluate conjunctions until a fail' do
327
+ conjunction = [true, true, true, false, true, :CUT, true]
328
+ rule = Rule.new args1, conjunction
329
+
330
+ goal.expects(:terminate!).with().times(0)
331
+ rule_spy = Spy.on(rule, :satisfy_conjunction).and_call_through
332
+ called = false
333
+
334
+ result = rule.satisfy_conjunction(goal, subgoal, rule.definition) do |solution_goal|
335
+ #:nocov:
336
+ called = true
337
+ #:nocov:
338
+ end
339
+
340
+ refute result, 'satisfy_conjunction should not succeed'
341
+ refute called, 'the satisfy block should not be called'
342
+ assert_equal 4, rule_spy.calls.size
343
+ assert_equal [goal, subgoal, conjunction[3..-1]], rule_spy.calls[0].args
344
+ assert_equal [goal, subgoal, conjunction[2..-1]], rule_spy.calls[1].args
345
+ assert_equal [goal, subgoal, conjunction[1..-1]], rule_spy.calls[2].args
346
+ assert_equal [goal, subgoal, conjunction[0..-1]], rule_spy.calls[3].args
347
+ end
348
+
349
+ it 'should unify and instantiate variables with a subgoal and satisfy the subgoal and uninstantiate the instantiations' do
350
+ goal = Goal.new args1, nil
351
+ subgoal = Goal.new args2, goal
352
+
353
+ predicate :gamma
354
+
355
+ gamma(8,5).fact!
356
+
357
+ rule = Rule.new args1, [gamma(:j,:k)]
358
+
359
+ subsubgoal = new_goal :gamma, :y, :z
360
+ subsubgoal_spy = Spy.on(Goal, :new).and_return do |*args|
361
+ Spy.off(Goal, :new)
362
+ subsubgoal
363
+ end
364
+
365
+ goal.expects(:terminate!).with().times(0)
366
+ subgoal.expects(:terminate!).with().times(0)
367
+ subsubgoal.expects(:terminate!).with().times(0)
368
+
369
+ goal.expects(:delete!).with().times(0)
370
+ subgoal.expects(:delete!).with().times(0)
371
+ subsubgoal.expects(:delete!).with().times(1)
372
+
373
+ rule_spy = Spy.on(rule, :satisfy_conjunction).and_call_through
374
+ called = false
375
+
376
+ result = rule.satisfy_conjunction(goal, subgoal, rule.definition) do |solution_goal|
377
+ called = true
378
+ assert_Goal goal, :parent, [1,2,3,4]
379
+ assert_Goal_variables goal, {}, ''
380
+ assert_Goal_variables subgoal, { x: nil, y: 8, z: 5 }, [
381
+ 'Goal2.:x',
382
+ ' Goal3.:x',
383
+ 'Goal2.:y',
384
+ ' Goal3.:y',
385
+ ' Goal4.8',
386
+ 'Goal2.:z',
387
+ ' Goal3.:z',
388
+ ' Goal4.5',
389
+ ].join("\n")
390
+ assert_Goal_variables subsubgoal, { x: nil, y: 8, z: 5 }, [
391
+ 'Goal3.:y',
392
+ ' Goal2.:y',
393
+ ' Goal4.8',
394
+ 'Goal3.:z',
395
+ ' Goal2.:z',
396
+ ' Goal4.5',
397
+ 'Goal3.:x',
398
+ ' Goal2.:x',
399
+ ].join("\n")
400
+ end
401
+
402
+ assert result, 'satisfy_conjunction should succeed'
403
+ assert called, 'the satisfy block should be called'
404
+ assert_equal 1, subsubgoal_spy.calls.size
405
+ assert_equal 1, rule_spy.calls.size
406
+ assert_equal [goal, subgoal, [gamma(:j,:k)]], rule_spy.calls[0].args
407
+
408
+ assert_Goal_variables subgoal, { x: nil, y: nil, z: nil }, [
409
+ 'Goal2.:x',
410
+ ' Goal3.:x',
411
+ 'Goal2.:y',
412
+ ' Goal3.:y',
413
+ 'Goal2.:z',
414
+ ' Goal3.:z',
415
+ ].join("\n")
416
+ assert_Goal_variables subsubgoal, { x: nil, y: nil, z: nil }, [
417
+ 'Goal3.:y',
418
+ ' Goal2.:y',
419
+ 'Goal3.:z',
420
+ ' Goal2.:z',
421
+ 'Goal3.:x',
422
+ ' Goal2.:x',
423
+ ].join("\n")
424
+ end
425
+
426
+ it 'should not unify and not instantiate variables with a subgoal nor satisfy the subgoal when it cannot be unified' do
427
+ # -- Create Goals --
428
+ goal = Goal.new args1, nil
429
+ subgoal = Goal.new args2, goal
430
+ subgoal.instantiate :y, 7
431
+
432
+ # -- Create goal for satisfy_conjunction() --
433
+ subsubgoal = new_goal :gamma, :y, :y, :z
434
+ subsubgoal.instantiate :y, 3
435
+
436
+ # -- Check goals are setup correctly --
437
+ assert_Goal goal, :parent, [1,2,3,4]
438
+ assert_Goal subgoal, :child, [:x,:y]
439
+ assert_equal 'Goal1 -- Solve parent(1,2,3,4)', goal.inspect
440
+ assert_equal 'Goal2 -- Solve child(:x,:y)', subgoal.inspect
441
+
442
+ assert_Goal_variables goal, {}, [].join("\n")
443
+
444
+ assert_Goal_variables subgoal, { x: nil, y: 7 }, [
445
+ 'Goal2.:x',
446
+ 'Goal2.:y',
447
+ ' Goal2.7',
448
+ ].join("\n")
449
+
450
+ assert_Goal_variables subsubgoal, { y: 3, z: nil }, [
451
+ 'Goal3.:y',
452
+ ' Goal3.3',
453
+ 'Goal3.:z',
454
+ ].join("\n")
455
+
456
+ # -- Define Predicate --
457
+ predicate :gamma
458
+
459
+ gamma(8,5).fact!
460
+
461
+ rule = Rule.new args1, [gamma(:j,:k)]
462
+
463
+ # -- Prepare Checks for satisfy_conjunction() --
464
+ subsubgoal_spy = Spy.on(Goal, :new).and_return do |*args|
465
+ Spy.off(Goal, :new)
466
+ subsubgoal
467
+ end
468
+
469
+ goal. expects(:terminate!).with().times(0)
470
+ subgoal. expects(:terminate!).with().times(0)
471
+ subsubgoal.expects(:terminate!).with().times(0)
472
+
473
+ goal. expects(:delete!).with().times(0)
474
+ subgoal. expects(:delete!).with().times(0)
475
+ subsubgoal.expects(:delete!).with().times(1)
476
+
477
+ rule_spy = Spy.on(rule, :satisfy_conjunction).and_call_through
478
+ called = false
479
+
480
+ # -- Pre-execution Checks --
481
+ assert_Goal_variables goal, {}, [].join("\n")
482
+ assert_Goal_variables subgoal, { x: nil, y: 7 }, [
483
+ 'Goal2.:x',
484
+ 'Goal2.:y',
485
+ ' Goal2.7',
486
+ ].join("\n")
487
+ assert_Goal_variables subsubgoal, { y: 3, z: nil }, [
488
+ 'Goal3.:y',
489
+ ' Goal3.3',
490
+ 'Goal3.:z',
491
+ ].join("\n")
492
+
493
+ # -- Execute Code --
494
+ result = rule.satisfy_conjunction(goal, subgoal, rule.definition) do |solution_goal|
495
+ #:nocov:
496
+ called = true
497
+ #:nocov:
498
+ end
499
+
500
+ # -- Peform Checks --
501
+ refute result, 'satisfy_conjunction should not succeed'
502
+ refute called, 'the satisfy block should not be called'
503
+ assert_equal 1, subsubgoal_spy.calls.size
504
+ assert_equal 1, rule_spy.calls.size
505
+ assert_equal [goal, subgoal, [gamma(:j,:k)]], rule_spy.calls[0].args
506
+
507
+ assert_Goal_variables goal, {}, [].join("\n")
508
+
509
+ assert_Goal_variables subgoal, { x: nil, y: 7 }, [
510
+ 'Goal2.:x',
511
+ 'Goal2.:y',
512
+ ' Goal2.7',
513
+ ].join("\n")
514
+
515
+ assert_Goal_variables subsubgoal, { x: nil, y: 3, z: nil }, [
516
+ 'Goal3.:y',
517
+ ' Goal3.3',
518
+ 'Goal3.:z',
519
+ 'Goal3.:x',
520
+ ].join("\n")
521
+ end
522
+
523
+ end
524
+
525
+ end
526
+
527
+ end