delorean_lang 0.0.33

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.
data/spec/func_spec.rb ADDED
@@ -0,0 +1,192 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe "Delorean" do
4
+
5
+ let(:engine) {
6
+ Delorean::Engine.new("ZZZ")
7
+ }
8
+
9
+ it "should handle MAX as a node name" do
10
+ engine.parse defn("MAX:",
11
+ " a = MAX(1, 2, 3, 0, -10)",
12
+ )
13
+
14
+ r = engine.evaluate("MAX", "a")
15
+ r.should == 3
16
+ end
17
+
18
+ it "should handle MAX" do
19
+ engine.parse defn("A:",
20
+ " a = MAX(1, 2, 3)",
21
+ )
22
+
23
+ r = engine.evaluate("A", "a")
24
+ r.should == 3
25
+ end
26
+
27
+ it "should handle insufficient args" do
28
+ lambda {
29
+ engine.parse defn("A:",
30
+ " a = MAX(1)",
31
+ )
32
+ }.should raise_error(Delorean::BadCallError)
33
+ end
34
+
35
+ it "should handle MIN" do
36
+ engine.parse defn("A:",
37
+ " a = MIN(1, 2, -3, 4)",
38
+ )
39
+
40
+ r = engine.evaluate("A", "a")
41
+ r.should == -3
42
+ end
43
+
44
+ it "should handle MAXLIST" do
45
+ engine.parse defn("A:",
46
+ " a = MAXLIST([1, 2, 3])",
47
+ )
48
+
49
+ engine.evaluate("A", "a").should == 3
50
+ end
51
+
52
+ it "should handle MINLIST" do
53
+ engine.parse defn("A:",
54
+ " a = MINLIST([1, 10, -3])",
55
+ )
56
+
57
+ engine.evaluate("A", "a").should == -3
58
+ end
59
+
60
+ it "should handle ROUND" do
61
+ engine.parse defn("A:",
62
+ " a = ROUND(12.3456, 2)",
63
+ " b = ROUND(12.3456, 1)",
64
+ " c = ROUND(12.3456)",
65
+ )
66
+
67
+ r = engine.evaluate_attrs("A", ["a", "b", "c"])
68
+ r.should == [12.35, 12.3, 12]
69
+ end
70
+
71
+ it "should handle TIMEPART" do
72
+ engine.parse defn("A:",
73
+ " p =?",
74
+ " p2 =?",
75
+ " h = TIMEPART(p, 'h')",
76
+ " m = TIMEPART(p, 'm')",
77
+ " s = TIMEPART(p, 's')",
78
+ " d = TIMEPART(p, 'd')",
79
+ " d2 = TIMEPART(p2, 'd')",
80
+ " h2 = TIMEPART(p2, 'h')",
81
+ )
82
+
83
+ p = Time.now
84
+ params = {"p" => p, "p2" => Float::INFINITY}
85
+ r = engine.evaluate_attrs("A", %w{h m s d d2}, params)
86
+ r.should == [p.hour, p.min, p.sec, p.to_date, Float::INFINITY]
87
+
88
+ expect { engine.evaluate_attrs("A", ["h2"], params) }.to raise_error
89
+
90
+ # Non time argument should raise an error
91
+ expect { engine.evaluate_attrs("A", ["m"], {"p" => 123}) }.to raise_error
92
+
93
+ end
94
+
95
+ it "should handle DATEPART" do
96
+ engine.parse defn("A:",
97
+ " p =?",
98
+ " y = DATEPART(p, 'y')",
99
+ " d = DATEPART(p, 'd')",
100
+ " m = DATEPART(p, 'm')",
101
+ )
102
+
103
+ p = Date.today
104
+ r = engine.evaluate_attrs("A", ["y", "d", "m"], {"p" => p})
105
+ r.should == [p.year, p.day, p.month]
106
+
107
+ # Non date argument should raise an error
108
+ expect { engine.evaluate_attrs("A", ["y", "d", "m"], {"p" => 123}) }.to raise_error
109
+ # Invalid part argument should raise an error
110
+ engine.reset
111
+ engine.parse defn("A:",
112
+ " p =?",
113
+ " x = DATEPART(p, 'x')",
114
+ )
115
+ expect { engine.evaluate_attrs("A", ["x"], {"p" => p}) }.to raise_error
116
+ end
117
+
118
+ it "should handle DATEADD" do
119
+ engine.parse defn("A:",
120
+ " p =?",
121
+ " y = DATEADD(p, 1, 'y')",
122
+ " d = DATEADD(p, 30, 'd')",
123
+ " m = DATEADD(p, 2, 'm')",
124
+ )
125
+
126
+ p = Date.today
127
+ r = engine.evaluate_attrs("A", ["y", "d", "m"], {"p" => p})
128
+ r.should == [p + 1.years, p + 30.days, p + 2.months]
129
+
130
+ # Non date argument should raise an error
131
+ expect { engine.evaluate_attrs("A", ["y", "d", "m"], {"p" => 123}) }.to raise_error
132
+
133
+ # Invalid interval argument should raise an error
134
+ engine.reset
135
+ engine.parse defn("A:",
136
+ " p =?",
137
+ " m = DATEADD(p, 1.3, 'm')",
138
+ )
139
+ expect { engine.evaluate_attrs("A", ["m"], {"p" => p}) }.to raise_error
140
+
141
+ # Invalid part argument should raise an error
142
+ engine.reset
143
+ engine.parse defn("A:",
144
+ " p =?",
145
+ " x = DATEADD(p, 1, 'x')",
146
+ )
147
+ expect { engine.evaluate_attrs("A", ["x"], {"p" => p}) }.to raise_error
148
+ end
149
+
150
+ it "should handle INDEX" do
151
+ engine.parse defn("A:",
152
+ " a = [INDEX([0, 11, 22, 33], i) for i in [1,2]]",
153
+ )
154
+
155
+ engine.evaluate("A", "a").should == [11,22]
156
+ end
157
+
158
+ it "should handle FLATTEN" do
159
+ x = [[1,2,[3]], 4, 5, [6]]
160
+
161
+ engine.parse defn("A:",
162
+ " a = #{x}",
163
+ " b = FLATTEN(a) + FLATTEN(a, 1)"
164
+ )
165
+
166
+ engine.evaluate("A", "b").should == x.flatten + x.flatten(1)
167
+ end
168
+
169
+ it "should handle ERR" do
170
+ engine.parse defn("A:",
171
+ " a = ERR('hello')",
172
+ " b = ERR('xx', 1, 2, 3)",
173
+ )
174
+
175
+ expect { engine.evaluate("A", "a") }.to raise_error('hello')
176
+
177
+ lambda {
178
+ r = engine.evaluate("A", "b")
179
+ }.should raise_error("xx, 1, 2, 3")
180
+
181
+ end
182
+
183
+ it "should handle SYM" do
184
+ engine.parse defn("S:",
185
+ ' a = TOSYM("hello")',
186
+ )
187
+
188
+ r = engine.evaluate("S", "a")
189
+ r.should == :hello
190
+ end
191
+
192
+ end
@@ -0,0 +1,688 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe "Delorean" do
4
+
5
+ let(:engine) {
6
+ Delorean::Engine.new "YYY"
7
+ }
8
+
9
+ let(:sset) {
10
+ TestContainer.new({
11
+ ["AAA", "0001"] =>
12
+ defn("X:",
13
+ " a = 123",
14
+ " b = a",
15
+ )
16
+ })
17
+ }
18
+
19
+ it "can parse very simple calls" do
20
+ engine.parse defn("X:",
21
+ " a = 123",
22
+ " b = a",
23
+ )
24
+ end
25
+
26
+ it "can parse simple expressions - 1" do
27
+ engine.parse defn("A:",
28
+ " a = 123",
29
+ " x = -(a*2)",
30
+ " b = -(a + 1)",
31
+ )
32
+ end
33
+
34
+ it "can parse simple expressions - 2" do
35
+ engine.parse defn("A:",
36
+ " a = 1 + 2 * -3 - -4",
37
+ )
38
+ end
39
+
40
+ it "can parse params" do
41
+ engine.parse defn("A:",
42
+ " a =?",
43
+ " b =? a*2",
44
+ )
45
+ end
46
+
47
+ it "should accept default param definitions" do
48
+ lambda {
49
+ engine.parse defn("A:",
50
+ " b =? 1",
51
+ " c =? -1.1",
52
+ " d = b + c",
53
+ )
54
+ }.should_not raise_error
55
+ end
56
+
57
+ it "gives errors with attrs not in node" do
58
+ lambda {
59
+ engine.parse defn("a = 123",
60
+ "b = a * 2",
61
+ )
62
+ }.should raise_error(Delorean::ParseError)
63
+ end
64
+
65
+ it "should disallow .<digits> literals" do
66
+ lambda {
67
+ engine.parse defn("A:",
68
+ " a = .123",
69
+ )
70
+ }.should raise_error(Delorean::ParseError)
71
+ end
72
+
73
+ it "should disallow bad attr names" do
74
+ lambda {
75
+ engine.parse defn("A:",
76
+ " B = 1",
77
+ )
78
+ }.should raise_error(Delorean::ParseError)
79
+
80
+ engine.reset
81
+
82
+ lambda {
83
+ engine.parse defn("A:",
84
+ " _b = 1",
85
+ )
86
+ }.should raise_error(Delorean::ParseError)
87
+ end
88
+
89
+ it "should disallow bad node names" do
90
+ lambda {
91
+ engine.parse defn("a:",
92
+ )
93
+ }.should raise_error(Delorean::ParseError)
94
+
95
+ engine.reset
96
+
97
+ lambda {
98
+ engine.parse defn("_A:",
99
+ )
100
+ }.should raise_error(Delorean::ParseError)
101
+ end
102
+
103
+ it "should disallow recursion" do
104
+ lambda {
105
+ engine.parse defn("A:",
106
+ " a = 1",
107
+ "B: A",
108
+ " a = a + 1",
109
+ )
110
+ }.should raise_error(Delorean::RecursionError)
111
+
112
+ engine.reset
113
+
114
+ lambda {
115
+ engine.parse defn("A:",
116
+ " a = 1",
117
+ "B: A",
118
+ " b = a",
119
+ " a = b",
120
+ )
121
+ }.should raise_error(Delorean::RecursionError)
122
+
123
+ end
124
+
125
+ it "should allow non-recursive code 1" do
126
+ # this is not a recursion error
127
+ engine.parse defn("A:",
128
+ " a = 1",
129
+ " b = 2",
130
+ "B: A",
131
+ " a = A.b",
132
+ " b = a",
133
+ )
134
+
135
+ end
136
+
137
+ it "should allow non-recursive code 2" do
138
+ engine.parse defn("A:",
139
+ " a = 1",
140
+ " b = 2",
141
+ "B: A",
142
+ " a = A.b",
143
+ " b = A.b + B.a",
144
+ )
145
+ end
146
+
147
+ it "should allow non-recursive code 3" do
148
+ engine.parse defn("A:",
149
+ " b = 2",
150
+ " a = A.b + A.b",
151
+ " c = a + b + a + b",
152
+ )
153
+ end
154
+
155
+ it "should check for recursion with default params 1" do
156
+ lambda {
157
+ engine.parse defn("A:",
158
+ " a =? a",
159
+ )
160
+ }.should raise_error(Delorean::UndefinedError)
161
+ end
162
+
163
+ it "should check for recursion with default params 2" do
164
+ lambda {
165
+ engine.parse defn("A:",
166
+ " a = 1",
167
+ "B: A",
168
+ " b =? a",
169
+ " a =? b",
170
+ )
171
+ }.should raise_error(Delorean::RecursionError)
172
+ end
173
+
174
+ it "gives errors for attrs defined more than once in a node" do
175
+ lambda {
176
+ engine.parse defn("B:",
177
+ " b = 1 + 1",
178
+ " b = 123",
179
+ )
180
+ }.should raise_error(Delorean::RedefinedError)
181
+
182
+ engine.reset
183
+
184
+ lambda {
185
+ engine.parse defn("B:",
186
+ " b =?",
187
+ " b = 123",
188
+ )
189
+ }.should raise_error(Delorean::RedefinedError)
190
+
191
+ engine.reset
192
+
193
+ lambda {
194
+ engine.parse defn("B:",
195
+ " b =? 22",
196
+ " b = 123",
197
+ )
198
+ }.should raise_error(Delorean::RedefinedError)
199
+ end
200
+
201
+ it "should raise error for nodes defined more than once" do
202
+ lambda {
203
+ engine.parse defn("B:",
204
+ " b =?",
205
+ "B:",
206
+ )
207
+ }.should raise_error(Delorean::RedefinedError)
208
+
209
+ engine.reset
210
+
211
+ lambda {
212
+ engine.parse defn("B:",
213
+ "A:",
214
+ "B:",
215
+ )
216
+ }.should raise_error(Delorean::RedefinedError)
217
+ end
218
+
219
+ it "should not be valid to derive from undefined nodes" do
220
+ lambda {
221
+ engine.parse defn("A: B",
222
+ " a = 456 * 123",
223
+ )
224
+ }.should raise_error(Delorean::UndefinedError)
225
+ end
226
+
227
+ it "should not be valid to use an undefined attr" do
228
+ lambda {
229
+ engine.parse defn("A:",
230
+ " a = 456 * 123",
231
+ "B: A",
232
+ " b = a",
233
+ " c = d",
234
+ )
235
+ }.should raise_error(Delorean::UndefinedError)
236
+ end
237
+
238
+ it "should be able to use ruby keywords as identifier" do
239
+ lambda {
240
+ engine.parse defn("A:",
241
+ " in = 123",
242
+ )
243
+ }.should_not raise_error
244
+
245
+ engine.reset
246
+
247
+ lambda {
248
+ engine.parse defn("B:",
249
+ " in1 = 123",
250
+ )
251
+ }.should_not raise_error
252
+
253
+ engine.reset
254
+
255
+ lambda {
256
+ engine.parse defn("C:",
257
+ " ifx = 123",
258
+ " elsey = ifx + 1",
259
+ )
260
+ }.should_not raise_error
261
+
262
+ engine.reset
263
+
264
+ lambda {
265
+ engine.parse defn("D:",
266
+ " true = false",
267
+ )
268
+ }.should_not raise_error
269
+
270
+ engine.reset
271
+
272
+ lambda {
273
+ engine.parse defn("E:",
274
+ " a = 1",
275
+ " return=a",
276
+ )
277
+ }.should_not raise_error
278
+ end
279
+
280
+ it "should be able to chain method calls on model functions" do
281
+ lambda {
282
+ engine.parse defn("A:",
283
+ " b = Dummy.i_just_met_you('CRJ', 123).name"
284
+ )
285
+ }.should_not raise_error
286
+ end
287
+
288
+ it "should be able to call class methods on ActiveRecord classes" do
289
+ engine.parse defn("A:",
290
+ " b = Dummy.call_me_maybe()",
291
+ )
292
+ end
293
+
294
+ it "shouldn't be able to call ActiveRecord methods without signature" do
295
+ lambda {
296
+ engine.parse defn("A:",
297
+ " b = Dummy.this_is_crazy()",
298
+ )
299
+ }.should raise_error(Delorean::UndefinedFunctionError)
300
+ end
301
+
302
+ it "should be able to call class methods on ActiveRecord classes in modules" do
303
+ engine.parse defn("A:",
304
+ " b = M::LittleDummy.heres_my_number(867, 5309)",
305
+ )
306
+ end
307
+
308
+ it "should be able to override parameters with attribute definitions" do
309
+ engine.parse defn("A:",
310
+ " b =? 22",
311
+ "B: A",
312
+ " b = 123",
313
+ "C: B",
314
+ " b =? 11",
315
+ )
316
+ end
317
+
318
+ it "should raise error on node attr access without all needed params" do
319
+ pending
320
+ end
321
+
322
+ it "should be able to access derived attrs" do
323
+ engine.parse defn("A:",
324
+ " b =? 22",
325
+ "B: A",
326
+ " c = b * 123",
327
+ "C: B",
328
+ " d =? c * b + 11",
329
+ )
330
+ end
331
+
332
+ it "should not be able to access attrs not defined in ancestors" do
333
+ lambda {
334
+ engine.parse defn("A:",
335
+ " b =? 22",
336
+ "B: A",
337
+ " c = b * 123",
338
+ "C: A",
339
+ " d =? c * b + 11",
340
+ )
341
+ }.should raise_error(Delorean::UndefinedError)
342
+ end
343
+
344
+ it "should be able to access specific node attrs " do
345
+ engine.parse defn("A:",
346
+ " b = 123",
347
+ " c = A.b",
348
+ )
349
+
350
+ engine.reset
351
+
352
+ engine.parse defn("A:",
353
+ " b = 123",
354
+ "B: A",
355
+ " b = 111",
356
+ " c = A.b * 123",
357
+ " d = B.b",
358
+ )
359
+ end
360
+
361
+ it "should be able to perform arbitrary getattr" do
362
+ engine.parse defn("A:",
363
+ " b = 22",
364
+ " c = b.x.y.z",
365
+ )
366
+
367
+ engine.reset
368
+
369
+ lambda {
370
+ engine.parse defn("B:",
371
+ " c = b.x.y.z",
372
+ )
373
+ }.should raise_error(Delorean::UndefinedError)
374
+
375
+ end
376
+
377
+ it "should handle lines with comments" do
378
+ engine.parse defn("A: # kaka",
379
+ " b = 22 # testing #",
380
+ " c = b",
381
+ )
382
+ end
383
+
384
+ it "should be able to report error line during parse" do
385
+ begin
386
+ engine.parse defn("A:",
387
+ " b = 123",
388
+ "B: .A",
389
+ )
390
+ rescue => exc
391
+ end
392
+
393
+ exc.module_name.should == "YYY"
394
+ exc.line.should == 3
395
+
396
+ engine.reset
397
+
398
+ begin
399
+ engine.parse defn("A:",
400
+ " b = 3 % b",
401
+ )
402
+ rescue => exc
403
+ end
404
+
405
+ exc.module_name.should == "YYY"
406
+ exc.line.should == 2
407
+ end
408
+
409
+ it "should raise error on malformed string" do
410
+ lambda {
411
+ engine.parse defn("A:",
412
+ ' d = "testing"" ',
413
+ )
414
+ }.should raise_error(Delorean::ParseError)
415
+ end
416
+
417
+ it "should not allow inherited ruby methods as attrs" do
418
+ lambda {
419
+ engine.parse defn("A:",
420
+ " a = name",
421
+ )
422
+ }.should raise_error(Delorean::UndefinedError)
423
+
424
+ engine.reset
425
+
426
+ lambda {
427
+ engine.parse defn("A:",
428
+ " a = new",
429
+ )
430
+ }.should raise_error(Delorean::UndefinedError)
431
+ end
432
+
433
+ it "should be able to parse lists" do
434
+ engine.parse defn("A:",
435
+ " b = []",
436
+ " c = [1,2,3]",
437
+ " d = [b, c, b, c, 1, 2, '123', 1.1]",
438
+ " e = [1, 1+1, 1+1+1]",
439
+ )
440
+
441
+ engine.reset
442
+
443
+ lambda {
444
+ engine.parse defn("A:",
445
+ " a = [",
446
+ )
447
+ }.should raise_error(Delorean::ParseError)
448
+
449
+ engine.reset
450
+
451
+ lambda {
452
+ engine.parse defn("A:",
453
+ " a = []-",
454
+ )
455
+ }.should raise_error(Delorean::ParseError)
456
+
457
+ end
458
+
459
+ it "should handle trailing ',' with lists" do
460
+ engine.parse defn("A:",
461
+ " b = [1,2,3,]",
462
+ )
463
+
464
+ engine.reset
465
+
466
+ lambda {
467
+ engine.parse defn("A:",
468
+ " a = [,]",
469
+ )
470
+ }.should raise_error(Delorean::ParseError)
471
+
472
+ engine.reset
473
+
474
+ lambda {
475
+ engine.parse defn("A:",
476
+ " a = [1,2,,]",
477
+ )
478
+ }.should raise_error(Delorean::ParseError)
479
+ end
480
+
481
+ it "should be able to parse hashes" do
482
+ engine.parse defn("A:",
483
+ " b = {}",
484
+ " c = {'a':1, 'b': 2, 'c':-3}",
485
+ " d = [{1:11}, {2: 22}]",
486
+ )
487
+
488
+ engine.reset
489
+
490
+ lambda {
491
+ engine.parse defn("A:",
492
+ " a = {",
493
+ )
494
+ }.should raise_error(Delorean::ParseError)
495
+
496
+ engine.reset
497
+
498
+ lambda {
499
+ engine.parse defn("A:",
500
+ " a = {}+",
501
+ )
502
+ }.should raise_error(Delorean::ParseError)
503
+ end
504
+
505
+ it "should handle trailing ',' with hashes" do
506
+ engine.parse defn("A:",
507
+ " b = {-1:1,}",
508
+ )
509
+
510
+ engine.reset
511
+
512
+ lambda {
513
+ engine.parse defn("A:",
514
+ " a = {,}",
515
+ )
516
+ }.should raise_error(Delorean::ParseError)
517
+
518
+ engine.reset
519
+
520
+ lambda {
521
+ engine.parse defn("A:",
522
+ " a = {-1:1,,}",
523
+ )
524
+ }.should raise_error(Delorean::ParseError)
525
+ end
526
+
527
+ it "should be able to parse list operations " do
528
+ engine.parse defn("A:",
529
+ " b = [] + []",
530
+ )
531
+ end
532
+
533
+ it "should parse list comprehension" do
534
+ engine.parse defn("A:",
535
+ " b = [123 for i in 123]",
536
+ )
537
+
538
+ end
539
+
540
+ it "should parse list comprehension (2)" do
541
+ engine.parse defn("A:",
542
+ " b = [i+1 for i in [1,2,3]]",
543
+ )
544
+
545
+ end
546
+
547
+ it "should parse nested list comprehension" do
548
+ engine.parse defn("A:",
549
+ " b = [[a+c for c in [4,5]] for a in [1,2,3]]",
550
+ )
551
+
552
+ end
553
+
554
+ it "should accept list comprehension variable override" do
555
+ engine.parse defn("A:",
556
+ " b = [b+1 for b in [1,2,3]]",
557
+ )
558
+ end
559
+
560
+ it "should accept list comprehension variable override (2)" do
561
+ engine.parse defn("A:",
562
+ " a = 1",
563
+ " b = [a+1 for a in [1,2,3]]",
564
+ )
565
+ end
566
+
567
+ it "errors out on bad list comprehension" do
568
+ lambda {
569
+ engine.parse defn("A:",
570
+ " b = [i+1 for x in [1,2,3]]",
571
+ )
572
+ }.should raise_error(Delorean::UndefinedError)
573
+ engine.reset
574
+
575
+ lambda {
576
+ engine.parse defn("A:",
577
+ " a = [123 for b in b]",
578
+ )
579
+ }.should raise_error(Delorean::UndefinedError)
580
+ engine.reset
581
+
582
+ # disallow nested comprehension var reuse
583
+ lambda {
584
+ engine.parse defn("A:",
585
+ " b = [[a+1 for a in [4,5]] for a in [1,2,3]]",
586
+ )
587
+ }.should raise_error(Delorean::RedefinedError)
588
+ engine.reset
589
+ end
590
+
591
+ it "should parse module calls" do
592
+ engine.parse defn("A:",
593
+ " a = 123",
594
+ " b = 456 + a",
595
+ " n = 'A'",
596
+ " c = @('a', 'b', x: 123, y: 456)",
597
+ " d = @n('a', 'b', x: 123, y: 456)",
598
+ )
599
+ end
600
+
601
+ it "should parse module calls by node name" do
602
+ engine.parse defn("A:",
603
+ " a = 123",
604
+ " d = @A('a')",
605
+ )
606
+ end
607
+
608
+ it "should parse multiline attr defs" do
609
+ engine.parse defn("A:",
610
+ " a = [1,",
611
+ " 2,",
612
+ " 3]",
613
+ " b = 456",
614
+ )
615
+ end
616
+
617
+ it "should give proper errors on parse multiline attr defs" do
618
+ begin
619
+ engine.parse defn("A:",
620
+ " a = [1,",
621
+ " 2,",
622
+ " 3];",
623
+ " b = 456",
624
+ )
625
+ raise "fail"
626
+ rescue Delorean::ParseError => exc
627
+ exc.line.should == 2
628
+ end
629
+ end
630
+
631
+ it "should give proper errors when multiline error falls off the end" do
632
+ begin
633
+ engine.parse defn("A:",
634
+ " x = 123",
635
+ " a = 1 +",
636
+ " 2 +",
637
+ )
638
+ raise "fail"
639
+ rescue Delorean::ParseError => exc
640
+ exc.line.should == 3
641
+ end
642
+ end
643
+
644
+ it "should parse imports" do
645
+ engine.parse defn("import AAA 0001",
646
+ "A:",
647
+ " b = 456",
648
+ "B: AAA::X",
649
+ ), sset
650
+
651
+ end
652
+
653
+ it "should disallow import loops" do
654
+ pending
655
+ sset.merge({
656
+ ["BBB", "0001"] =>
657
+ defn("import AAA 0001",
658
+ "import CCC 0001",
659
+ ),
660
+ ["CCC", "0001"] =>
661
+ defn("import BBB 0001",
662
+ ),
663
+ })
664
+ sset.get_engine("CCC", "0001")
665
+ end
666
+
667
+ it "should disallow multiple versions of same script" do
668
+ sset.merge({
669
+ ["AAA", "0002"] =>
670
+ defn("A:",
671
+ ),
672
+ ["BBB", "0001"] =>
673
+ defn("import AAA 0001",
674
+ ),
675
+ ["CCC", "0001"] =>
676
+ defn("import BBB 0001",
677
+ "import AAA 0002",
678
+ ),
679
+ })
680
+ begin
681
+ sset.get_engine("CCC", "0001")
682
+ rescue Delorean::ImportError => exc
683
+ exc.line.should == 2
684
+ end
685
+ end
686
+
687
+ end
688
+