intermine 0.98.01

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.
@@ -0,0 +1,1202 @@
1
+ require File.dirname(__FILE__) + "/test_helper.rb"
2
+ require "intermine/query"
3
+ require "intermine/model"
4
+ require "intermine/lists"
5
+ require "intermine/service"
6
+
7
+ require "test/unit"
8
+
9
+
10
+ class TestQuery < Test::Unit::TestCase
11
+
12
+ def initialize(name)
13
+ super
14
+ file = File.new(
15
+ File.dirname(__FILE__) + "/data/model.json", "r")
16
+ data = file.read
17
+ @model = InterMine::Metadata::Model.new(data)
18
+ end
19
+
20
+ def test_instantiation
21
+ query = InterMine::PathQuery::Query.new(@model)
22
+ assert(query.is_a?(PathQuery::Query))
23
+
24
+ query = InterMine::PathQuery::Query.new(@model, "Employee")
25
+ assert_equal(query.root, @model.get_cd("Employee"))
26
+
27
+ query = InterMine::PathQuery::Query.new(@model, "Department.name")
28
+ assert_equal(query.root, @model.get_cd("Department"))
29
+
30
+ assert_raise InterMine::Metadata::PathException do
31
+ InterMine::PathQuery::Query.new(@model, "Foo")
32
+ end
33
+ end
34
+
35
+ def test_fully_qualified_views
36
+ views = [
37
+ "Employee.name",
38
+ "Employee.age",
39
+ "Employee.department.name"
40
+ ]
41
+ expected = views.to_s
42
+
43
+
44
+ query = InterMine::PathQuery::Query.new(@model)
45
+ query.add_views("Employee.name", "Employee.age",
46
+ "Employee.department.name")
47
+ assert_equal(query.views.to_s, expected)
48
+
49
+
50
+ query = InterMine::PathQuery::Query.new(@model, "Employee")
51
+ query.add_views("Employee.name", "Employee.age",
52
+ "Employee.department.name")
53
+ assert_equal(query.views.to_s, expected)
54
+
55
+ query = InterMine::PathQuery::Query.new(@model)
56
+ query.add_views(views)
57
+ assert_equal(query.views.to_s, expected)
58
+
59
+ query = InterMine::PathQuery::Query.new(@model, "Employee")
60
+ query.add_views(views)
61
+ assert_equal(query.views.to_s, expected)
62
+ end
63
+
64
+ def test_bad_viewpath
65
+ query = InterMine::PathQuery::Query.new(@model)
66
+ assert_raise InterMine::Metadata::PathException do
67
+ query.add_views("Employee.foo.id")
68
+ end
69
+ end
70
+
71
+ def test_inconsistent_view_roots
72
+ query = InterMine::PathQuery::Query.new(@model)
73
+ assert_raise InterMine::Metadata::PathException do
74
+ query.add_views("Employee.name")
75
+ query.add_views("Department.name")
76
+ end
77
+
78
+ end
79
+
80
+ def test_unqualified_views
81
+ views = [
82
+ "Employee.name",
83
+ "Employee.age",
84
+ "Employee.department.name"
85
+ ]
86
+ expected = views.to_s
87
+
88
+ query = InterMine::PathQuery::Query.new(@model, "Employee")
89
+ query.add_views("name", "age", "department.name")
90
+ assert_equal(query.views.to_s, expected)
91
+
92
+ query = InterMine::PathQuery::Query.new(@model, "Employee")
93
+ query.add_views(["name", "age", "department.name"])
94
+ assert_equal(query.views.to_s, expected)
95
+ end
96
+
97
+ def test_bad_unqualified_path
98
+ query = InterMine::PathQuery::Query.new(@model, "Employee")
99
+ assert_raise InterMine::Metadata::PathException do
100
+ query.add_views("foo.id")
101
+ end
102
+ end
103
+
104
+ def test_inconsistent_views_with_rooted_query
105
+ query = InterMine::PathQuery::Query.new(@model, "Employee")
106
+ assert_raise InterMine::Metadata::PathException do
107
+ query.add_views("Department.id")
108
+ end
109
+ end
110
+
111
+ def test_subclasses
112
+ query = InterMine::PathQuery::Query.new(@model)
113
+ query.add_constraint({
114
+ :path => "Department.employees",
115
+ :sub_class => "Manager"
116
+ })
117
+ query.add_constraint({
118
+ :path => "Department.company.departments.employees",
119
+ :sub_class => "Manager"
120
+ })
121
+ expected = {
122
+ "Department.employees" => "Manager",
123
+ "Department.company.departments.employees" => "Manager"
124
+ }
125
+ assert_equal(expected, query.subclasses)
126
+ end
127
+
128
+ def test_problem_subclasses
129
+ query = InterMine::PathQuery::Query.new(@model)
130
+ assert_raise InterMine::Metadata::PathException do
131
+ query.add_constraint({
132
+ :path => "Department.employees",
133
+ :sub_class => "Foo"
134
+ })
135
+ end
136
+
137
+ query = InterMine::PathQuery::Query.new(@model)
138
+ assert_raise ArgumentError do
139
+ query.add_constraint({
140
+ :path => "Department.employees",
141
+ :sub_class => "Company"
142
+ })
143
+ end
144
+
145
+ query = InterMine::PathQuery::Query.new(@model)
146
+ assert_raise ArgumentError do
147
+ query.add_constraint({
148
+ :path => "Department.manager",
149
+ :sub_class => "Company.departments.employees"
150
+ })
151
+ end
152
+
153
+ query = InterMine::PathQuery::Query.new(@model)
154
+ assert_raise ArgumentError do
155
+ query.add_constraint({
156
+ :path => "Department.manager",
157
+ :sub_class => "Employee"
158
+ })
159
+ end
160
+ end
161
+
162
+ def test_subclassed_views
163
+ query = InterMine::PathQuery::Query.new(@model)
164
+ query.add_constraint({
165
+ :path => "Department.employees",
166
+ :sub_class => "Manager"
167
+ })
168
+ query.add_views("Department.employees.seniority")
169
+ expected = ["Department.employees.seniority"].to_s
170
+ assert_equal(query.views.to_s, expected)
171
+
172
+ query = InterMine::PathQuery::Query.new(@model)
173
+ assert_raise InterMine::Metadata::PathException do
174
+ query.add_views("Department.employees.seniority")
175
+ end
176
+ end
177
+
178
+ def test_joins
179
+ query = InterMine::PathQuery::Query.new(@model)
180
+ query.add_join("Department.employees", "OUTER")
181
+ join = query.joins.first
182
+ assert_equal(join.path.to_s, "Department.employees")
183
+ assert_equal(join.style, "OUTER")
184
+ assert_equal(query.root.name, "Department")
185
+
186
+ query = InterMine::PathQuery::Query.new(@model)
187
+ query.add_join("Department.employees")
188
+ join = query.joins.first
189
+ assert_equal(join.path.to_s, "Department.employees")
190
+ assert_equal(join.style, "OUTER")
191
+
192
+ query = InterMine::PathQuery::Query.new(@model, "Department")
193
+ query.add_join("employees")
194
+ join = query.joins.first
195
+ assert_equal(join.path.to_s, "Department.employees")
196
+ assert_equal(join.style, "OUTER")
197
+
198
+ query = InterMine::PathQuery::Query.new(@model)
199
+ query.add_join("Department.employees", "INNER")
200
+ join = query.joins.first
201
+ assert_equal(join.path.to_s, "Department.employees")
202
+ assert_equal(join.style, "INNER")
203
+ end
204
+
205
+ def test_subclassed_joins
206
+
207
+ query = InterMine::PathQuery::Query.new(@model, "Department")
208
+
209
+ query.add_constraint({:path => "employees", :sub_class => "CEO"})
210
+ query.add_join("employees.secretarys")
211
+
212
+ assert_equal(query.joins.first.path.to_s, "Department.employees.secretarys")
213
+ assert_equal(query.joins.first.style, "OUTER")
214
+
215
+ query = InterMine::PathQuery::Query.new(@model, "Department")
216
+ assert_raise InterMine::Metadata::PathException do
217
+ query.add_join("employees.secretarys")
218
+ end
219
+ end
220
+
221
+ def test_join_problems
222
+
223
+ query = InterMine::PathQuery::Query.new(@model)
224
+ assert_raise InterMine::Metadata::PathException do
225
+ query.add_join("Foo.employees")
226
+ end
227
+
228
+ query = InterMine::PathQuery::Query.new(@model, "Employee")
229
+ assert_raise InterMine::Metadata::PathException do
230
+ query.add_join("Department.employees")
231
+ end
232
+
233
+ query = InterMine::PathQuery::Query.new(@model)
234
+ assert_raise ArgumentError do
235
+ query.add_join("Department.employees", "QUIRKY")
236
+ end
237
+
238
+ query = InterMine::PathQuery::Query.new(@model)
239
+ assert_raise InterMine::Metadata::PathException do
240
+ query.add_join("Department.employees")
241
+ query.add_join("Company.departments")
242
+ end
243
+ end
244
+
245
+ def test_unary_constraints
246
+ query = InterMine::PathQuery::Query.new(@model)
247
+ query.add_constraint({
248
+ :path => "Employee.name",
249
+ :op => "IS NULL"
250
+ })
251
+ query.add_constraint({
252
+ :path => "Employee.department",
253
+ :op => "IS NOT NULL"
254
+ })
255
+ conA = query.constraints[0]
256
+ conB = query.constraints[1]
257
+
258
+ query = InterMine::PathQuery::Query.new(@model)
259
+ query.add_constraint(
260
+ :path => "Employee.name",
261
+ :op => "IS NULL"
262
+ )
263
+ query.add_constraint(
264
+ :path => "Employee.department",
265
+ :op => "IS NOT NULL"
266
+ )
267
+ conA = query.constraints[0]
268
+ conB = query.constraints[1]
269
+
270
+ assert_equal(conA.path.to_s, "Employee.name")
271
+ assert_equal(conB.path.to_s, "Employee.department")
272
+
273
+ assert_equal(conA.op, "IS NULL")
274
+ assert_equal(conB.op, "IS NOT NULL")
275
+ end
276
+
277
+ def test_unqualified_unary_constraint
278
+ query = InterMine::PathQuery::Query.new(@model, "Employee")
279
+ query.add_constraint(
280
+ :path => "name",
281
+ :op => "IS NULL"
282
+ )
283
+
284
+ conA = query.constraints[0]
285
+ assert_equal(conA.path.to_s, "Employee.name")
286
+ assert_equal(conA.op, "IS NULL")
287
+
288
+ end
289
+
290
+ def test_bad_unary_constraint
291
+ query = InterMine::PathQuery::Query.new(@model)
292
+ assert_raise ArgumentError do
293
+ query.add_constraint(
294
+ :path => "name",
295
+ :op => "IS MAYBE NULL"
296
+ )
297
+ end
298
+
299
+ query = InterMine::PathQuery::Query.new(@model)
300
+ assert_raise InterMine::Metadata::PathException do
301
+ query.add_constraint({
302
+ :path => "Company.foo",
303
+ :op => "IS NULL"
304
+ })
305
+ end
306
+ end
307
+
308
+ def test_binary_constraints
309
+ query = InterMine::PathQuery::Query.new(@model)
310
+ query.add_constraint({
311
+ :path => "Employee.name",
312
+ :op => "=",
313
+ :value => "foo"
314
+ })
315
+ query.add_constraint({
316
+ :path => "Employee.department.name",
317
+ :op => "!=",
318
+ :value => "foo"
319
+ })
320
+ query.add_constraint({
321
+ :path => "Employee.age",
322
+ :op => ">",
323
+ :value => 1
324
+ })
325
+ query.add_constraint({
326
+ :path => "Employee.fullTime",
327
+ :op => "<",
328
+ :value => false
329
+ })
330
+ conA = query.constraints[0]
331
+ conB = query.constraints[1]
332
+ conC = query.constraints[2]
333
+ conD = query.constraints[3]
334
+
335
+ assert_equal(conA.path.to_s, "Employee.name")
336
+ assert_equal(conB.path.to_s, "Employee.department.name")
337
+ assert_equal(conC.path.to_s, "Employee.age")
338
+ assert_equal(conD.path.to_s, "Employee.fullTime")
339
+
340
+ assert_equal(conA.op, "=")
341
+ assert_equal(conB.op, "!=")
342
+ assert_equal(conC.op, ">")
343
+ assert_equal(conD.op, "<")
344
+
345
+ assert_equal(conA.value, "foo")
346
+ assert_equal(conB.value, "foo")
347
+ assert_equal(conC.value, 1)
348
+ assert_equal(conD.value, false)
349
+ end
350
+
351
+ def test_value_coercion
352
+ query = InterMine::PathQuery::Query.new(@model)
353
+ query.add_constraint({
354
+ :path => "Employee.age",
355
+ :op => ">",
356
+ :value => "1"
357
+ })
358
+ query.add_constraint({
359
+ :path => "Employee.fullTime",
360
+ :op => "<",
361
+ :value => "false"
362
+ })
363
+ conA = query.constraints[0]
364
+ conB = query.constraints[1]
365
+
366
+ assert_equal(conA.path.to_s, "Employee.age")
367
+ assert_equal(conB.path.to_s, "Employee.fullTime")
368
+
369
+ assert_equal(conA.op, ">")
370
+ assert_equal(conB.op, "<")
371
+
372
+ assert_equal(conA.value, 1)
373
+ assert_equal(conB.value, false)
374
+ end
375
+
376
+ def test_unqualified_binary_constraint
377
+ query = InterMine::PathQuery::Query.new(@model, "Employee")
378
+ query.add_constraint({
379
+ :path => "name",
380
+ :op => ">=",
381
+ :value => "foo"
382
+ })
383
+
384
+ conA = query.constraints[0]
385
+ assert_equal(conA.path.to_s, "Employee.name")
386
+ assert_equal(conA.op, ">=")
387
+ assert_equal(conA.value, "foo")
388
+
389
+ end
390
+
391
+ def test_bad_binary_constraint
392
+ query = InterMine::PathQuery::Query.new(@model, "Employee")
393
+ assert_raise ArgumentError do
394
+ query.add_constraint({
395
+ :path => "name",
396
+ :op => "===",
397
+ :value => "foo"
398
+ })
399
+ end
400
+
401
+ query = InterMine::PathQuery::Query.new(@model, "Employee")
402
+ assert_raise ArgumentError do
403
+ query.add_constraint({
404
+ :path => "age",
405
+ :op => "<",
406
+ :value => "foo"
407
+ })
408
+ end
409
+
410
+ query = InterMine::PathQuery::Query.new(@model, "Employee")
411
+ assert_raise ArgumentError do
412
+ query.add_constraint({
413
+ :path => "fullTime",
414
+ :op => "=",
415
+ :value => "foo"
416
+ })
417
+ end
418
+
419
+ query = InterMine::PathQuery::Query.new(@model)
420
+ assert_raise InterMine::Metadata::PathException do
421
+ query.add_constraint({
422
+ :path => "Company.foo",
423
+ :op => ">=",
424
+ :value => "foo"
425
+ })
426
+ end
427
+ end
428
+
429
+ def test_list_constraints
430
+ query = InterMine::PathQuery::Query.new(@model)
431
+ query.add_constraint({
432
+ :path => "Employee",
433
+ :op => "IN",
434
+ :value => "foo"
435
+ })
436
+ query.add_constraint({
437
+ :path => "Employee.department",
438
+ :op => "NOT IN",
439
+ :value => "foo"
440
+ })
441
+ conA = query.constraints[0]
442
+ conB = query.constraints[1]
443
+
444
+ assert_equal(conA.path.to_s, "Employee")
445
+ assert_equal(conB.path.to_s, "Employee.department")
446
+
447
+ assert_equal(conA.op, "IN")
448
+ assert_equal(conB.op, "NOT IN")
449
+
450
+ assert_equal(conA.value, "foo")
451
+ assert_equal(conB.value, "foo")
452
+ end
453
+
454
+ def test_unqualified_list_constraint
455
+ query = InterMine::PathQuery::Query.new(@model, "Employee")
456
+ query.add_constraint({
457
+ :path => "department",
458
+ :op => "IN",
459
+ :value => "foo"
460
+ })
461
+
462
+ conA = query.constraints[0]
463
+ assert_equal(conA.path.to_s, "Employee.department")
464
+ assert_equal(conA.op, "IN")
465
+ assert_equal(conA.value, "foo")
466
+ end
467
+
468
+ def test_bad_list_constraint
469
+ query = InterMine::PathQuery::Query.new(@model, "Employee")
470
+ assert_raise ArgumentError do
471
+ query.add_constraint({
472
+ :path => "department.name",
473
+ :op => "IN",
474
+ :value => "foo"
475
+ })
476
+ end
477
+ end
478
+
479
+ def test_lookup_constraints
480
+ query = InterMine::PathQuery::Query.new(@model)
481
+ query.add_constraint({
482
+ :path => "Employee",
483
+ :op => "LOOKUP",
484
+ :value => "foo"
485
+ })
486
+ query.add_constraint({
487
+ :path => "Employee.department",
488
+ :op => "LOOKUP",
489
+ :value => "foo",
490
+ :extra_value => "bar"
491
+ })
492
+ conA = query.constraints[0]
493
+ conB = query.constraints[1]
494
+
495
+ assert_equal(conA.path.to_s, "Employee")
496
+ assert_equal(conB.path.to_s, "Employee.department")
497
+
498
+ assert_equal(conA.op, "LOOKUP")
499
+ assert_equal(conB.op, "LOOKUP")
500
+
501
+ assert_equal(conA.value, "foo")
502
+ assert_equal(conB.value, "foo")
503
+
504
+ assert_equal(conA.extra_value, nil)
505
+ assert_equal(conB.extra_value, "bar")
506
+ end
507
+
508
+ def test_unqualified_lookup_constraint
509
+ query = InterMine::PathQuery::Query.new(@model, "Employee")
510
+ query.add_constraint({
511
+ :path => "department",
512
+ :op => "LOOKUP",
513
+ :value => "foo"
514
+ })
515
+
516
+ conA = query.constraints[0]
517
+ assert_equal(conA.path.to_s, "Employee.department")
518
+ assert_equal(conA.op, "LOOKUP")
519
+ assert_equal(conA.value, "foo")
520
+ end
521
+
522
+ def test_bad_lookup_constraint
523
+ query = InterMine::PathQuery::Query.new(@model, "Employee")
524
+ assert_raise ArgumentError do
525
+ query.add_constraint({
526
+ :path => "department.name",
527
+ :op => "LOOKUP",
528
+ :value => "foo"
529
+ })
530
+ end
531
+ end
532
+
533
+ def test_loop_constraints
534
+ query = InterMine::PathQuery::Query.new(@model)
535
+ query.add_constraint({
536
+ :path => "Employee",
537
+ :op => "IS",
538
+ :loopPath => "Employee.department.manager"
539
+ })
540
+ query.add_constraint({
541
+ :path => "Employee.department",
542
+ :op => "IS NOT",
543
+ :loopPath => "Employee.department.company.departments"
544
+ })
545
+ conA = query.constraints[0]
546
+ conB = query.constraints[1]
547
+
548
+ assert_equal(conA.path.to_s, "Employee")
549
+ assert_equal(conB.path.to_s, "Employee.department")
550
+
551
+ assert_equal(conA.op, "IS")
552
+ assert_equal(conB.op, "IS NOT")
553
+
554
+ assert_equal(conA.loopPath.to_s, "Employee.department.manager")
555
+ assert_equal(conB.loopPath.to_s, "Employee.department.company.departments")
556
+
557
+ end
558
+
559
+ def test_unqualified_loop_constraint
560
+ query = InterMine::PathQuery::Query.new(@model, "Employee")
561
+ query.add_constraint({
562
+ :path => "department",
563
+ :op => "IS",
564
+ :loopPath => "department.company.departments"
565
+ })
566
+
567
+ conA = query.constraints[0]
568
+ assert_equal(conA.path.to_s, "Employee.department")
569
+ assert_equal(conA.op, "IS")
570
+ assert_equal(conA.loopPath.to_s, "Employee.department.company.departments")
571
+ end
572
+
573
+ def test_bad_lookup_constraint
574
+ query = InterMine::PathQuery::Query.new(@model, "Employee")
575
+ assert_raise ArgumentError do
576
+ query.add_constraint({
577
+ :path => "name",
578
+ :op => "IS",
579
+ :loopPath => "department.manager"
580
+ })
581
+ end
582
+
583
+ query = InterMine::PathQuery::Query.new(@model, "Employee")
584
+ assert_raise ArgumentError do
585
+ query.add_constraint({
586
+ :path => "Employee",
587
+ :op => "IS",
588
+ :loopPath => "department.manager.name"
589
+ })
590
+ end
591
+
592
+ query = InterMine::PathQuery::Query.new(@model, "Employee")
593
+ assert_raise ArgumentError do
594
+ query.add_constraint({
595
+ :path => "Employee",
596
+ :op => "IS",
597
+ :loopPath => "department"
598
+ })
599
+ end
600
+ end
601
+
602
+ def test_multi_constraints
603
+ query = InterMine::PathQuery::Query.new(@model)
604
+ query.add_constraint({
605
+ :path => "Employee.name",
606
+ :op => "ONE OF",
607
+ :values => %w{foo bar baz}
608
+ })
609
+
610
+ query.add_constraint({
611
+ :path => "Employee.age",
612
+ :op => "NONE OF",
613
+ :values => [1, 2, 3]
614
+ })
615
+
616
+ conA = query.constraints[0]
617
+ conB = query.constraints[1]
618
+
619
+ assert_equal(conA.path.to_s, "Employee.name")
620
+ assert_equal(conB.path.to_s, "Employee.age")
621
+
622
+ assert_equal(conA.op, "ONE OF")
623
+ assert_equal(conB.op, "NONE OF")
624
+
625
+ assert_equal(conA.values, ["foo", "bar", "baz"])
626
+ assert_equal(conB.values, [1, 2, 3])
627
+ end
628
+
629
+ def test_unqualified_multi_constraint
630
+ query = InterMine::PathQuery::Query.new(@model, "Employee")
631
+ query.add_constraint({
632
+ :path => "department.name",
633
+ :op => "ONE OF",
634
+ :values => %w{Sales Marketing Janitorial}
635
+ })
636
+
637
+ conA = query.constraints[0]
638
+ assert_equal(conA.path.to_s, "Employee.department.name")
639
+ assert_equal(conA.op, "ONE OF")
640
+ assert_equal(conA.values, %w{Sales Marketing Janitorial})
641
+ end
642
+
643
+ def test_bad_multi_constraint
644
+ query = InterMine::PathQuery::Query.new(@model, "Employee")
645
+ assert_raise ArgumentError do
646
+ query.add_constraint({
647
+ :path => "name",
648
+ :op => "ONE OF",
649
+ :value => "foo"
650
+ })
651
+ end
652
+
653
+ query = InterMine::PathQuery::Query.new(@model, "Employee")
654
+ assert_raise ArgumentError do
655
+ query.add_constraint({
656
+ :path => "Employee",
657
+ :op => "ONE OF",
658
+ :values => ["foo", "bar", "baz"]
659
+ })
660
+ end
661
+
662
+ query = InterMine::PathQuery::Query.new(@model, "Employee")
663
+ assert_raise ArgumentError do
664
+ query.add_constraint({
665
+ :path => "Employee.age",
666
+ :op => "ONE OF",
667
+ :values => [1, 2, 3, "foo", 5]
668
+ })
669
+ end
670
+ end
671
+
672
+ def test_codes
673
+ query = InterMine::PathQuery::Query.new(@model, "Employee")
674
+ # Check allocation of default codes
675
+ query.add_constraint({
676
+ :path => "name",
677
+ :op => "=",
678
+ :value => "foo"
679
+ })
680
+
681
+ # Check that subclass constraints don't get codes
682
+ query.add_constraint({
683
+ :path => "department.employees",
684
+ :sub_class => "Manager"
685
+ })
686
+
687
+ # Check default code is next available
688
+ query.add_constraint({
689
+ :path => "name",
690
+ :op => "IS NOT NULL"
691
+ })
692
+
693
+ # Check allocation of custom codes
694
+ query.add_constraint({
695
+ :path => "name",
696
+ :op => "IS NOT NULL",
697
+ :code => "Q"
698
+ })
699
+
700
+ # Check that we remember allocation of default codes
701
+ query.add_constraint({
702
+ :path => "name",
703
+ :op => "IS NOT NULL",
704
+ :code => "A"
705
+ })
706
+
707
+ # Check that we remember allocation of custom codes
708
+ query.add_constraint({
709
+ :path => "name",
710
+ :op => "IS NOT NULL",
711
+ :code => "Q"
712
+ })
713
+
714
+ codes = query.constraints.map { |x|
715
+ # Filter out subclass codes
716
+ begin
717
+ x.code
718
+ rescue
719
+ nil
720
+ end
721
+ }
722
+ assert_equal(["A", nil, "B", "Q", "C", "D"], codes)
723
+ end
724
+
725
+ def test_code_exhaustion
726
+ query = InterMine::PathQuery::Query.new(@model, "Employee")
727
+ # Check we can allocate all 26 default codes
728
+ assert_nothing_raised do
729
+ 26.times do
730
+ query.add_constraint({
731
+ :path => "name",
732
+ :op => "IS NOT NULL"
733
+ })
734
+ end
735
+ end
736
+ assert_equal(query.constraints.first.code, "A")
737
+ assert_equal(query.constraints.last.code, "Z")
738
+
739
+ # But 27 is too many
740
+ query = InterMine::PathQuery::Query.new(@model, "Employee")
741
+ assert_raise RuntimeError do
742
+ 27.times do
743
+ query.add_constraint({
744
+ :path => "name",
745
+ :op => "IS NOT NULL"
746
+ })
747
+ end
748
+ end
749
+
750
+ # One more tips the balance, even with a custom code
751
+ query = InterMine::PathQuery::Query.new(@model, "Employee")
752
+ assert_raise RuntimeError do
753
+ 26.times do
754
+ query.add_constraint({
755
+ :path => "name",
756
+ :op => "IS NOT NULL"
757
+ })
758
+ end
759
+ query.add_constraint({
760
+ :path => "name",
761
+ :op => "IS NOT NULL",
762
+ :code => "Z"
763
+ })
764
+ end
765
+ end
766
+
767
+ def test_illegal_codes
768
+ query = InterMine::PathQuery::Query.new(@model, "Employee")
769
+ assert_raise ArgumentError do
770
+ query.add_constraint({
771
+ :path => "name",
772
+ :op => "IS NOT NULL",
773
+ :code => "a"
774
+ })
775
+ end
776
+
777
+ query = InterMine::PathQuery::Query.new(@model, "Employee")
778
+ assert_raise ArgumentError do
779
+ query.add_constraint({
780
+ :path => "name",
781
+ :op => "IS NOT NULL",
782
+ :code => "AA"
783
+ })
784
+ end
785
+
786
+ query = InterMine::PathQuery::Query.new(@model, "Employee")
787
+ assert_raise ArgumentError do
788
+ query.add_constraint({
789
+ :path => "name",
790
+ :op => "IS NOT NULL",
791
+ :code => "Ä"
792
+ })
793
+ end
794
+ end
795
+
796
+ def test_subclassed_constraints
797
+
798
+ query = InterMine::PathQuery::Query.new(@model, "Department")
799
+
800
+ query.add_constraint({:path => "employees", :sub_class => "Manager"})
801
+ query.add_constraint({:path => "employees.title", :op => "=", :value => "Ms"})
802
+
803
+ assert_equal(query.constraints.last.path.to_s, "Department.employees.title")
804
+ assert_equal(query.constraints.last.op, "=")
805
+ assert_equal(query.constraints.last.value, "Ms")
806
+ assert_equal(query.constraints.last.code, "A")
807
+
808
+ query = InterMine::PathQuery::Query.new(@model, "Department")
809
+ assert_raise InterMine::Metadata::PathException do
810
+ query.add_constraint({:path => "employees.title", :op => "=", :value => "Ms"})
811
+ end
812
+ end
813
+
814
+ def test_sort_order
815
+
816
+ query = InterMine::PathQuery::Query.new(@model, "Employee")
817
+
818
+ query.add_views("name", "age", "end")
819
+
820
+ query.add_sort_order("name", "ASC")
821
+
822
+ assert_equal(query.sort_order.first.path, "Employee.name")
823
+ assert_equal(query.sort_order.first.direction, "ASC")
824
+
825
+ query.add_sort_order("age")
826
+
827
+ assert_equal(query.sort_order.last.path, "Employee.age")
828
+ assert_equal(query.sort_order.last.direction, "ASC")
829
+
830
+ query.add_sort_order("end", "DESC")
831
+
832
+ assert_equal(query.sort_order.last.path, "Employee.end")
833
+ assert_equal(query.sort_order.last.direction, "DESC")
834
+
835
+ assert_raise InterMine::Metadata::PathException do
836
+ query.add_sort_order("foo")
837
+ end
838
+
839
+ assert_raise ArgumentError do
840
+ query.add_sort_order("name", "FORWARDS")
841
+ end
842
+
843
+ assert_raise ArgumentError do
844
+ query.add_sort_order("department.name")
845
+ end
846
+
847
+ query.add_sort_order("name", "desc")
848
+
849
+ assert_equal(query.sort_order.last.path, "Employee.name")
850
+ assert_equal(query.sort_order.last.direction, "DESC")
851
+ end
852
+
853
+ def test_subclassed_sort_order
854
+
855
+ query = InterMine::PathQuery::Query.new(@model, "Employee")
856
+
857
+ query.add_constraint(:path => "Employee", :sub_class => "Manager")
858
+ query.add_views(%w{name age fullTime title})
859
+ query.add_sort_order("title")
860
+
861
+ assert_equal(query.sort_order.first.path, "Employee.title")
862
+
863
+ query = InterMine::PathQuery::Query.new(@model, "Employee")
864
+ assert_raise InterMine::Metadata::PathException do
865
+ query.add_sort_order("title")
866
+ end
867
+ end
868
+
869
+ def test_logic
870
+
871
+ query = InterMine::PathQuery::Query.new(@model, "Employee")
872
+
873
+ 5.times do
874
+ query.add_constraint(:path => "name", :op => "=", :value => "foo")
875
+ end
876
+
877
+ query.set_logic("A and B and C and D and E")
878
+ assert_equal("A and B and C and D and E", query.logic.to_s)
879
+
880
+ query.set_logic("A&B&C&D&E")
881
+ assert_equal("A and B and C and D and E", query.logic.to_s)
882
+
883
+ query.set_logic("A|B|C|D|E")
884
+ assert_equal("A or B or C or D or E", query.logic.to_s)
885
+
886
+ query.set_logic("A and B or C and D or E")
887
+ assert_equal("A and (B or C) and (D or E)", query.logic.to_s)
888
+
889
+ query.set_logic("A and (B or (C and (D or E)))")
890
+ assert_equal("A and (B or (C and (D or E)))", query.logic.to_s)
891
+
892
+ query.set_logic("(((A and B) and C) and D) and E")
893
+ assert_equal("A and B and C and D and E", query.logic.to_s)
894
+
895
+ query.set_logic("A and B | (C or D) and E")
896
+ assert_equal("A and (B or C or D) and E", query.logic.to_s)
897
+
898
+ query.set_logic("A or B or (C and D) and E")
899
+ assert_equal("(A or B or (C and D)) and E", query.logic.to_s)
900
+
901
+ query.set_logic("A or B or (C and D and E)")
902
+ assert_equal("A or B or (C and D and E)", query.logic.to_s)
903
+
904
+ assert_raise InterMine::PathQuery::LogicParseError do
905
+ query.set_logic("A B | (C or D) and E")
906
+ end
907
+
908
+ assert_raise InterMine::PathQuery::LogicParseError do
909
+ query.set_logic("A ( B and C)")
910
+ end
911
+
912
+ assert_raise InterMine::PathQuery::LogicParseError do
913
+ query.set_logic("A or B and C)")
914
+ end
915
+
916
+ assert_raise InterMine::PathQuery::LogicParseError do
917
+ query.set_logic("A or (B and C")
918
+ end
919
+ end
920
+
921
+ def test_query_element_xml
922
+
923
+ query = InterMine::PathQuery::Query.new(@model, "Employee")
924
+ query.add_views("name", "age", "fullTime", "department.name")
925
+
926
+ expected = "<query model='testmodel' view='Employee.name Employee.age Employee.fullTime Employee.department.name' sortOrder='Employee.name ASC'/>"
927
+
928
+ compare_xml(expected, query.to_xml)
929
+
930
+ query.title = "Ruby Query"
931
+ query.add_sort_order("age", "desc")
932
+
933
+ expected = "<query model='testmodel' title='Ruby Query' view='Employee.name Employee.age Employee.fullTime Employee.department.name' sortOrder='Employee.age DESC'/>"
934
+ compare_xml(expected, query.to_xml)
935
+
936
+ query.add_sort_order("name")
937
+ expected = "<query model='testmodel' title='Ruby Query' view='Employee.name Employee.age Employee.fullTime Employee.department.name' sortOrder='Employee.age DESC Employee.name ASC'/>"
938
+ compare_xml(expected, query.to_xml)
939
+
940
+ end
941
+
942
+ def test_constraint_xml
943
+ query = InterMine::PathQuery::Query.new(@model, "Employee")
944
+ query.add_views("name", "age", "fullTime", "department.name")
945
+
946
+ query.add_constraint({:path => "department", :op => "IS NOT NULL"})
947
+ query.add_constraint({
948
+ :path => "name",
949
+ :op => "<",
950
+ :value => "foo"
951
+ })
952
+ query.add_constraint({
953
+ :path => "age",
954
+ :op => "ONE OF",
955
+ :values => [17, 23, 37]
956
+ })
957
+ query.add_constraint({
958
+ :path => "Employee",
959
+ :op => "IN",
960
+ :value => "bar"
961
+ })
962
+ query.add_constraint({
963
+ :path => "Employee",
964
+ :op => "IS",
965
+ :loopPath => "department.manager"
966
+ })
967
+ query.add_constraint({
968
+ :path => "Employee",
969
+ :op => "LOOKUP",
970
+ :value => "quux"
971
+ })
972
+ query.add_constraint({
973
+ :path => "Employee",
974
+ :op => "LOOKUP",
975
+ :value => "zop",
976
+ :extra_value => "zip"
977
+ })
978
+ query.add_constraint({
979
+ :path => "Employee",
980
+ :sub_class => "Manager"
981
+ })
982
+ query.add_views("title")
983
+
984
+ expected = "<query model='testmodel' view='Employee.name Employee.age Employee.fullTime Employee.department.name Employee.title' sortOrder='Employee.name ASC'>" +
985
+ "<constraint type='Manager' path='Employee'/>" +
986
+ "<constraint op='IS NOT NULL' code='A' path='Employee.department'/>" +
987
+ "<constraint op='&lt;' code='B' value='foo' path='Employee.name'/>" +
988
+ "<constraint op='ONE OF' code='C' path='Employee.age'>" +
989
+ "<value>17</value><value>23</value><value>37</value>" +
990
+ "</constraint>" +
991
+ "<constraint op='IN' code='D' value='bar' path='Employee'/>" +
992
+ "<constraint loopPath='Employee.department.manager' op='=' code='E' path='Employee'/>" +
993
+ "<constraint op='LOOKUP' code='F' value='quux' path='Employee'/>" +
994
+ "<constraint extraValue='zip' op='LOOKUP' code='G' value='zop' path='Employee'/>" +
995
+ "</query>"
996
+
997
+ compare_xml(expected, query.to_xml.to_s)
998
+ end
999
+
1000
+ def test_join_xml
1001
+
1002
+ query = InterMine::PathQuery::Query.new(@model, "Employee")
1003
+ query.add_views("name", "age", "fullTime", "department.name")
1004
+
1005
+ query.add_join("department")
1006
+ query.add_join("department.company", "INNER")
1007
+ query.add_join("department.company.address", "OUTER")
1008
+
1009
+ expected = "<query model='testmodel' view='Employee.name Employee.age Employee.fullTime Employee.department.name' sortOrder='Employee.name ASC'>" +
1010
+ "<join path='Employee.department' style='OUTER'/>" +
1011
+ "<join path='Employee.department.company' style='INNER'/>" +
1012
+ "<join path='Employee.department.company.address' style='OUTER'/>" +
1013
+ "</query>"
1014
+
1015
+ compare_xml(expected, query.to_xml)
1016
+ end
1017
+
1018
+ def test_all_xml
1019
+ query = InterMine::PathQuery::Query.new(@model, "Employee")
1020
+ query.add_views("name", "age", "fullTime", "department.name")
1021
+ query.add_constraint({
1022
+ :path => "Employee",
1023
+ :sub_class => "Manager"
1024
+ })
1025
+ query.add_views("title")
1026
+ query.add_sort_order("title", "desc")
1027
+
1028
+ query.add_join("department")
1029
+ query.add_join("department.company", "INNER")
1030
+ query.add_join("department.company.address", "OUTER")
1031
+
1032
+ query.add_constraint({:path => "department", :op => "IS NOT NULL"})
1033
+ query.add_constraint({
1034
+ :path => "name",
1035
+ :op => "<",
1036
+ :value => "foo"
1037
+ })
1038
+ query.add_constraint({
1039
+ :path => "age",
1040
+ :op => "ONE OF",
1041
+ :values => [17, 23, 37]
1042
+ })
1043
+ query.add_constraint({
1044
+ :path => "Employee",
1045
+ :op => "IN",
1046
+ :value => "bar"
1047
+ })
1048
+ query.add_constraint({
1049
+ :path => "Employee",
1050
+ :op => "IS",
1051
+ :loopPath => "department.manager"
1052
+ })
1053
+ query.add_constraint({
1054
+ :path => "Employee",
1055
+ :op => "LOOKUP",
1056
+ :value => "quux"
1057
+ })
1058
+ query.add_constraint({
1059
+ :path => "Employee",
1060
+ :op => "LOOKUP",
1061
+ :value => "zop",
1062
+ :extra_value => "zip"
1063
+ })
1064
+
1065
+ expected = "<query model='testmodel' view='Employee.name Employee.age Employee.fullTime Employee.department.name Employee.title' sortOrder='Employee.title DESC'>" +
1066
+ "<join path='Employee.department' style='OUTER'/>" +
1067
+ "<join path='Employee.department.company' style='INNER'/>" +
1068
+ "<join path='Employee.department.company.address' style='OUTER'/>" +
1069
+ "<constraint type='Manager' path='Employee'/>" +
1070
+ "<constraint op='IS NOT NULL' code='A' path='Employee.department'/>" +
1071
+ "<constraint op='&lt;' code='B' value='foo' path='Employee.name'/>" +
1072
+ "<constraint op='ONE OF' code='C' path='Employee.age'>" +
1073
+ "<value>17</value><value>23</value><value>37</value>" +
1074
+ "</constraint>" +
1075
+ "<constraint op='IN' code='D' value='bar' path='Employee'/>" +
1076
+ "<constraint loopPath='Employee.department.manager' op='=' code='E' path='Employee'/>" +
1077
+ "<constraint op='LOOKUP' code='F' value='quux' path='Employee'/>" +
1078
+ "<constraint extraValue='zip' op='LOOKUP' code='G' value='zop' path='Employee'/>" +
1079
+ "</query>"
1080
+
1081
+ compare_xml(expected, query.to_xml)
1082
+
1083
+ end
1084
+
1085
+ def test_unmarshall
1086
+ # Tricky xml with all constraint types and subclassing, as well as integer values
1087
+ xml = "<query model='testmodel' view='Employee.name Employee.age Employee.fullTime Employee.department.name Employee.title' sortOrder='Employee.title DESC' constraintLogic='(A or B) and (C or D) and (E or F)'>" +
1088
+ "<join path='Employee.department' style='OUTER'/>" +
1089
+ "<join path='Employee.department.company' style='INNER'/>" +
1090
+ "<join path='Employee.department.company.address' style='OUTER'/>" +
1091
+ "<constraint type='Manager' path='Employee'/>" +
1092
+ "<constraint op='IS NOT NULL' code='A' path='Employee.department'/>" +
1093
+ "<constraint op='&lt;' code='B' value='foo' path='Employee.name'/>" +
1094
+ "<constraint op='ONE OF' code='C' path='Employee.age'>" +
1095
+ "<value>17</value><value>23</value><value>37</value>" +
1096
+ "</constraint>" +
1097
+ "<constraint op='IN' code='D' value='bar' path='Employee'/>" +
1098
+ "<constraint loopPath='Employee.department.manager' op='=' code='E' path='Employee'/>" +
1099
+ "<constraint op='LOOKUP' code='F' value='quux' path='Employee'/>" +
1100
+ "<constraint extraValue='zip' op='LOOKUP' code='G' value='zop' path='Employee'/>" +
1101
+ "</query>"
1102
+
1103
+ q = InterMine::PathQuery::Query.parser(@model).parse(xml)
1104
+
1105
+ compare_xml(xml, q.to_xml)
1106
+ end
1107
+
1108
+ def test_unmarshall_template
1109
+ # Tricky xml with all constraint types and subclassing, as well as integer values
1110
+ src = "<template name='unmarshal_template' longDescription='Some kind of text description' comment='some comment'>" +
1111
+ "<query model='testmodel' sortOrder='Employee.title DESC' view='Employee.name Employee.age Employee.fullTime Employee.department.name Employee.title'>" +
1112
+ "<join path='Employee.department' style='OUTER'/>" +
1113
+ "<join path='Employee.department.company' style='INNER'/>" +
1114
+ "<join path='Employee.department.company.address' style='OUTER'/>" +
1115
+ "<constraint type='Manager' path='Employee'/>" +
1116
+ "<constraint op='IS NOT NULL' code='A' path='Employee.department'/>" +
1117
+ "<constraint op='&lt;' code='B' value='foo' path='Employee.name'/>" +
1118
+ "<constraint op='ONE OF' code='C' path='Employee.age'>" +
1119
+ "<value>17</value><value>23</value><value>37</value>" +
1120
+ "</constraint>" +
1121
+ "<constraint op='IN' code='D' value='bar' path='Employee'/>" +
1122
+ "<constraint loopPath='Employee.department.manager' op='=' code='E' path='Employee'/>" +
1123
+ "<constraint op='LOOKUP' code='F' value='quux' path='Employee'/>" +
1124
+ "<constraint extraValue='zip' op='LOOKUP' code='G' value='zop' path='Employee'/>" +
1125
+ "</query>" +
1126
+ "</template>"
1127
+
1128
+ expected = "<template name='unmarshal_template' longDescription='Some kind of text description' comment='some comment'>" +
1129
+ "<query name='unmarshal_template' model='testmodel' sortOrder='Employee.title DESC' view='Employee.name Employee.age Employee.fullTime Employee.department.name Employee.title'>" +
1130
+ "<join path='Employee.department' style='OUTER'/>" +
1131
+ "<join path='Employee.department.company' style='INNER'/>" +
1132
+ "<join path='Employee.department.company.address' style='OUTER'/>" +
1133
+ "<constraint type='Manager' path='Employee'/>" +
1134
+ "<constraint op='IS NOT NULL' code='A' path='Employee.department' switchable='locked' editable='true'/>" +
1135
+ "<constraint op='&lt;' code='B' value='foo' path='Employee.name' switchable='locked' editable='true'/>" +
1136
+ "<constraint op='ONE OF' code='C' path='Employee.age' switchable='locked' editable='true'>" +
1137
+ "<value>17</value><value>23</value><value>37</value>" +
1138
+ "</constraint>" +
1139
+ "<constraint op='IN' code='D' value='bar' path='Employee' switchable='locked' editable='true'/>" +
1140
+ "<constraint loopPath='Employee.department.manager' op='=' code='E' path='Employee' switchable='locked' editable='true'/>" +
1141
+ "<constraint op='LOOKUP' code='F' value='quux' path='Employee' switchable='locked' editable='true'/>" +
1142
+ "<constraint extraValue='zip' op='LOOKUP' code='G' value='zop' path='Employee' switchable='locked' editable='true'/>" +
1143
+ "</query>" +
1144
+ "</template>"
1145
+
1146
+ q = InterMine::PathQuery::Template.parser(@model).parse(src)
1147
+
1148
+ compare_xml expected, q.to_xml
1149
+ end
1150
+
1151
+ def test_template_parameters
1152
+
1153
+ # Tricky xml with all constraint types and subclassing, as well as integer values
1154
+ src = "<template name='unmarshal_template' longDescription='Some kind of text description' comment='some comment'>" +
1155
+ "<query model='testmodel' sortOrder='Employee.title DESC' view='Employee.name Employee.age Employee.fullTime Employee.department.name Employee.title'>" +
1156
+ "<join path='Employee.department' style='OUTER'/>" +
1157
+ "<join path='Employee.department.company' style='INNER'/>" +
1158
+ "<join path='Employee.department.company.address' style='OUTER'/>" +
1159
+ "<constraint type='Manager' path='Employee'/>" +
1160
+ "<constraint op='IS NOT NULL' code='A' path='Employee.department'/>" +
1161
+ "<constraint op='&lt;' code='B' value='foo' path='Employee.name'/>" +
1162
+ "<constraint op='ONE OF' code='C' path='Employee.age'>" +
1163
+ "<value>17</value><value>23</value><value>37</value>" +
1164
+ "</constraint>" +
1165
+ "<constraint op='IN' code='D' value='bar' path='Employee'/>" +
1166
+ "<constraint loopPath='Employee.department.manager' op='=' code='E' path='Employee'/>" +
1167
+ "<constraint op='LOOKUP' code='F' value='quux' path='Employee'/>" +
1168
+ "<constraint extraValue='zip' op='LOOKUP' code='G' value='zop' path='Employee'/>" +
1169
+ "</query>" +
1170
+ "</template>"
1171
+
1172
+ q = InterMine::PathQuery::Template.parser(@model).parse(src)
1173
+
1174
+ expected = {
1175
+ "name"=>"unmarshal_template",
1176
+ "constraint1"=>"Employee.department",
1177
+ "constraint2"=>"Employee.name",
1178
+ "constraint3"=>"Employee.age",
1179
+ "constraint4"=>"Employee",
1180
+ "constraint5"=>"Employee",
1181
+ "constraint6"=>"Employee",
1182
+ "constraint7"=>"Employee",
1183
+ "op1"=>"IS NOT NULL",
1184
+ "op2"=>"lt",
1185
+ "op3"=>"ONE OF",
1186
+ "op4"=>"IN",
1187
+ "op5"=>"eq",
1188
+ "op6"=>"LOOKUP",
1189
+ "op7"=>"LOOKUP",
1190
+ "value2"=>"foo",
1191
+ "value3"=>[17, 23, 37],
1192
+ "value4"=>"bar",
1193
+ "loopPath5"=>"Employee.department.manager",
1194
+ "value6"=>"quux",
1195
+ "value7"=>"zop",
1196
+ "extra7"=>"zip"
1197
+ }
1198
+
1199
+ assert_equal(expected, q.params)
1200
+ end
1201
+
1202
+ end