adsl 0.0.3 → 0.1.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 (91) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +2 -20
  3. data/README.md +14 -21
  4. data/bin/adsl-verify +8 -8
  5. data/lib/adsl.rb +3 -0
  6. data/lib/adsl/adsl.rb +3 -0
  7. data/lib/adsl/ds/data_store_spec.rb +339 -0
  8. data/lib/adsl/extract/instrumenter.rb +206 -0
  9. data/lib/adsl/extract/meta.rb +33 -0
  10. data/lib/adsl/extract/rails/action_block_builder.rb +233 -0
  11. data/lib/adsl/extract/rails/action_instrumenter.rb +400 -0
  12. data/lib/adsl/extract/rails/action_runner.rb +57 -0
  13. data/lib/adsl/extract/rails/active_record_metaclass_generator.rb +555 -0
  14. data/lib/adsl/extract/rails/callback_chain_simulator.rb +135 -0
  15. data/lib/adsl/extract/rails/invariant_extractor.rb +48 -0
  16. data/lib/adsl/extract/rails/invariant_instrumenter.rb +70 -0
  17. data/lib/adsl/extract/rails/other_meta.rb +57 -0
  18. data/lib/adsl/extract/rails/rails_extractor.rb +211 -0
  19. data/lib/adsl/extract/rails/rails_instrumentation_test_case.rb +34 -0
  20. data/lib/adsl/extract/rails/rails_special_gem_instrumentation.rb +120 -0
  21. data/lib/adsl/extract/rails/rails_test_helper.rb +140 -0
  22. data/lib/adsl/extract/sexp_utils.rb +54 -0
  23. data/lib/adsl/fol/first_order_logic.rb +261 -0
  24. data/lib/adsl/parser/adsl_parser.racc +159 -0
  25. data/lib/{parser → adsl/parser}/adsl_parser.rex +4 -4
  26. data/lib/{parser → adsl/parser}/adsl_parser.rex.rb +6 -6
  27. data/lib/adsl/parser/adsl_parser.tab.rb +1031 -0
  28. data/lib/adsl/parser/ast_nodes.rb +1410 -0
  29. data/lib/adsl/railtie.rb +67 -0
  30. data/lib/adsl/spass/bin.rb +230 -0
  31. data/lib/{spass → adsl/spass}/ruby_extensions.rb +0 -0
  32. data/lib/adsl/spass/spass_ds_extensions.rb +931 -0
  33. data/lib/adsl/spass/spass_translator.rb +393 -0
  34. data/lib/adsl/spass/util.rb +13 -0
  35. data/lib/adsl/util/csv_hash_formatter.rb +94 -0
  36. data/lib/adsl/util/general.rb +228 -0
  37. data/lib/adsl/util/test_helper.rb +71 -0
  38. data/lib/adsl/verification/formula_generators.rb +231 -0
  39. data/lib/adsl/verification/instrumentation_filter.rb +50 -0
  40. data/lib/adsl/verification/invariant.rb +19 -0
  41. data/lib/adsl/verification/rails_verification.rb +33 -0
  42. data/lib/adsl/verification/utils.rb +20 -0
  43. data/lib/adsl/verification/verification_case.rb +13 -0
  44. data/test/integration/rails/rails_branch_verification_test.rb +112 -0
  45. data/test/integration/rails/rails_verification_test.rb +253 -0
  46. data/test/integration/spass/basic_translation_test.rb +563 -0
  47. data/test/integration/spass/control_flow_translation_test.rb +421 -0
  48. data/test/unit/adsl/ds/data_store_spec_test.rb +54 -0
  49. data/test/unit/adsl/extract/instrumenter_test.rb +103 -0
  50. data/test/unit/adsl/extract/meta_test.rb +142 -0
  51. data/test/unit/adsl/extract/rails/action_block_builder_test.rb +178 -0
  52. data/test/unit/adsl/extract/rails/action_instrumenter_test.rb +68 -0
  53. data/test/unit/adsl/extract/rails/active_record_metaclass_generator_test.rb +336 -0
  54. data/test/unit/adsl/extract/rails/callback_chain_simulator_test.rb +76 -0
  55. data/test/unit/adsl/extract/rails/invariant_extractor_test.rb +92 -0
  56. data/test/unit/adsl/extract/rails/rails_extractor_test.rb +1380 -0
  57. data/test/unit/adsl/extract/rails/rails_test_helper_test.rb +25 -0
  58. data/test/unit/adsl/extract/sexp_utils_test.rb +100 -0
  59. data/test/unit/adsl/fol/first_order_logic_test.rb +227 -0
  60. data/test/unit/adsl/parser/action_parser_test.rb +1040 -0
  61. data/test/unit/adsl/parser/ast_nodes_test.rb +359 -0
  62. data/test/unit/adsl/parser/class_parser_test.rb +288 -0
  63. data/test/unit/adsl/parser/general_parser_test.rb +67 -0
  64. data/test/unit/adsl/parser/invariant_parser_test.rb +432 -0
  65. data/test/unit/adsl/parser/parser_util_test.rb +126 -0
  66. data/test/unit/adsl/spass/bin_test.rb +65 -0
  67. data/test/unit/adsl/spass/ruby_extensions_test.rb +39 -0
  68. data/test/unit/adsl/spass/spass_ds_extensions_test.rb +7 -0
  69. data/test/unit/adsl/spass/spass_translator_test.rb +342 -0
  70. data/test/unit/adsl/util/csv_hash_formatter_test.rb +68 -0
  71. data/test/unit/adsl/util/general_test.rb +303 -0
  72. data/test/unit/adsl/util/test_helper_test.rb +120 -0
  73. data/test/unit/adsl/verification/formula_generators_test.rb +200 -0
  74. data/test/unit/adsl/verification/instrumentation_filter_test.rb +39 -0
  75. data/test/unit/adsl/verification/utils_test.rb +39 -0
  76. data/test/unit/adsl/verification/verification_case_test.rb +8 -0
  77. metadata +229 -29
  78. data/lib/ds/data_store_spec.rb +0 -292
  79. data/lib/fol/first_order_logic.rb +0 -260
  80. data/lib/parser/adsl_ast.rb +0 -779
  81. data/lib/parser/adsl_parser.racc +0 -151
  82. data/lib/parser/adsl_parser.tab.rb +0 -976
  83. data/lib/parser/dsdl_parser.rex.rb +0 -196
  84. data/lib/parser/dsdl_parser.tab.rb +0 -976
  85. data/lib/spass/bin.rb +0 -164
  86. data/lib/spass/spass_ds_extensions.rb +0 -870
  87. data/lib/spass/spass_translator.rb +0 -388
  88. data/lib/spass/util.rb +0 -11
  89. data/lib/util/csv_hash_formatter.rb +0 -47
  90. data/lib/util/test_helper.rb +0 -33
  91. data/lib/util/util.rb +0 -114
@@ -0,0 +1,359 @@
1
+ require 'test/unit'
2
+ require 'adsl/parser/ast_nodes'
3
+ require 'set'
4
+
5
+ class ADSL::Parser::AstNodesTest < Test::Unit::TestCase
6
+ include ADSL::Parser
7
+
8
+ def test__statements_are_statements
9
+ all_nodes = ADSL::Parser.constants.map{ |c| ADSL::Parser.const_get c }.select{ |c| c < ADSL::Parser::ASTNode }
10
+ statements = [:dummy_stmt, :assignment, :create_tup, :delete_tup, :set_tup, :delete_obj, :block, :for_each, :either, :objset_stmt, :declare_var]
11
+ statements = statements.map{ |c| ADSL::Parser.const_get "AST#{c.to_s.camelize}" }
12
+ difference = Set[*statements] ^ Set[*all_nodes.select{ |c| c.is_statement? }]
13
+ assert difference.empty?
14
+ end
15
+
16
+ def test__create_objset_has_transitive_sideeffects
17
+ assert ASTCreateObjset.new.objset_has_side_effects?
18
+
19
+ assert_false ASTSubset.new.objset_has_side_effects?
20
+ assert ASTSubset.new(:objset => ASTCreateObjset.new).objset_has_side_effects?
21
+
22
+ assert_false ASTUnion.new.objset_has_side_effects?
23
+ assert_false ASTUnion.new(:objsets => [
24
+ ASTSubset.new, ASTSubset.new
25
+ ]).objset_has_side_effects?
26
+ assert ASTUnion.new(:objsets => [
27
+ ASTSubset.new, ASTSubset.new, ASTCreateObjset.new
28
+ ]).objset_has_side_effects?
29
+ end
30
+
31
+ def test__block_optimize__merges_nested_blocks
32
+ block = ASTBlock.new(:statements => [
33
+ ASTBlock.new(:statements => [
34
+ ASTAssignment.new(:objset => 1),
35
+ ASTAssignment.new(:objset => 2)
36
+ ]),
37
+ ASTAssignment.new(:objset => 3),
38
+ ASTBlock.new(:statements => [
39
+ ASTAssignment.new(:objset => 4),
40
+ ASTBlock.new(:statements => [
41
+ ASTAssignment.new(:objset => 5),
42
+ ASTAssignment.new(:objset => 6)
43
+ ]),
44
+ ASTAssignment.new(:objset => 7)
45
+ ])
46
+ ])
47
+
48
+ block = block.optimize
49
+
50
+ assert_equal 7, block.statements.length
51
+ 7.times do |i|
52
+ assert_equal i+1, block.statements[i].objset
53
+ end
54
+ end
55
+
56
+ def test__block_optimize__remove_noop_objset_stmts
57
+ block = ASTBlock.new(:statements => [
58
+ ASTAssignment.new(:objset => 1),
59
+ ASTObjsetStmt.new(:objset => ASTEmptyObjset.new),
60
+ ASTAssignment.new(:objset => 2),
61
+ ASTAssignment.new(:objset => 3),
62
+ ASTObjsetStmt.new(:objset => ASTEmptyObjset.new)
63
+ ])
64
+
65
+ block = block.optimize
66
+
67
+ assert_equal 3, block.statements.length
68
+ 3.times do |i|
69
+ stmt = block.statements[i]
70
+ assert_equal ASTAssignment, stmt.class
71
+ assert_equal i+1, stmt.objset
72
+ end
73
+ end
74
+
75
+ def test__block_optimize__removes_dummy_stmts
76
+ block = ASTBlock.new(:statements => [
77
+ ASTAssignment.new(:objset => 1),
78
+ ASTDummyStmt.new(),
79
+ ASTAssignment.new(:objset => 2),
80
+ ASTDummyStmt.new()
81
+ ])
82
+
83
+ block = block.optimize
84
+
85
+ assert_equal 2, block.statements.length
86
+ 2.times do |i|
87
+ stmt = block.statements[i]
88
+ assert_equal ASTAssignment, stmt.class
89
+ assert_equal i+1, stmt.objset
90
+ end
91
+ end
92
+
93
+ def test__either_optimize__merges_nested_eithers
94
+ either = ASTEither.new(:blocks => [
95
+ ASTBlock.new(:statements => [ASTEither.new(:blocks => [
96
+ ASTBlock.new(:statements => [
97
+ ASTAssignment.new(:objset => 1),
98
+ ASTAssignment.new(:objset => 2)
99
+ ]),
100
+ ASTBlock.new(:statements => [
101
+ ASTAssignment.new(:objset => 3),
102
+ ASTAssignment.new(:objset => 4)
103
+ ]),
104
+ ASTBlock.new(:statements => [
105
+ ASTEither.new(:blocks => [
106
+ ASTBlock.new(:statements => [
107
+ ASTAssignment.new(:objset => 5)
108
+ ])
109
+ ])
110
+ ])
111
+ ])]),
112
+ ASTBlock.new(:statements => [
113
+ ASTAssignment.new(:objset => 6)
114
+ ]),
115
+ ])
116
+
117
+ either = either.optimize
118
+
119
+ assert_equal 4, either.blocks.length
120
+ assert_equal [1, 2], either.blocks[0].statements.map(&:objset)
121
+ assert_equal [3, 4], either.blocks[1].statements.map(&:objset)
122
+ assert_equal [5], either.blocks[2].statements.map(&:objset)
123
+ assert_equal [6], either.blocks[3].statements.map(&:objset)
124
+ end
125
+
126
+ def test__action_optimize__removes_root_either_empty_options
127
+ action = ASTAction.new(:block => ASTBlock.new(:statements => [
128
+ ASTEither.new(:blocks => [
129
+ ASTBlock.new(:statements => []),
130
+ ASTBlock.new(:statements => [
131
+ ASTEither.new(:blocks => [
132
+ ASTBlock.new(:statements => [ASTDeleteObj.new(:objset => 1)]),
133
+ ASTBlock.new(:statements => [ASTDeleteObj.new(:objset => 2)])
134
+ ])
135
+ ]),
136
+ ASTBlock.new(:statements => [])
137
+ ])
138
+ ]))
139
+
140
+ action = action.optimize
141
+
142
+ assert_equal 1, action.block.statements.length
143
+ either = action.block.statements.first
144
+ assert_equal ASTEither, either.class
145
+
146
+ assert_equal 2, either.blocks.length
147
+ 2.times do |i|
148
+ assert_equal 1, either.blocks[i].statements.length
149
+ assert_equal i+1, either.blocks[i].statements.first.objset
150
+ end
151
+ end
152
+
153
+ def test__action_optimize__removes_root_either_if_only_one_option
154
+ action = ASTAction.new(:block => ASTBlock.new(:statements => [
155
+ ASTEither.new(:blocks => [
156
+ ASTBlock.new(:statements => []),
157
+ ASTBlock.new(:statements => [
158
+ ASTEither.new(:blocks => [
159
+ ASTBlock.new(:statements => [ASTDeleteObj.new(:objset => ASTDummyObjset.new(:type => 1))]),
160
+ ASTBlock.new(:statements => [])
161
+ ])
162
+ ]),
163
+ ASTBlock.new(:statements => [])
164
+ ])
165
+ ]))
166
+
167
+ action = action.optimize
168
+
169
+ assert_equal 1, action.block.statements.length
170
+ assert_equal ASTDeleteObj, action.block.statements.first.class
171
+ end
172
+
173
+ def test__equality
174
+ assert ASTIdent.new(:text => 'asd') == ASTIdent.new(:text => 'asd')
175
+ assert_false ASTIdent.new(:text => 'asd') == ASTIdent.new(:text => :asd)
176
+ assert(
177
+ ASTSubset.new(:objset => ASTAllOf.new(:class_name => 'asd')) ==
178
+ ASTSubset.new(:objset => ASTAllOf.new(:class_name => 'asd'))
179
+ )
180
+ assert_false(
181
+ ASTSubset.new(:objset => ASTAllOf.new(:class_name => 'asd')) ==
182
+ ASTSubset.new(:objset => ASTAllOf.new(:class_name => :asd))
183
+ )
184
+ assert_false ASTSubset.new == nil
185
+ assert ASTAnd.new(:subformulae => [1, 2, 3, nil, ASTIdent.new]) == ASTAnd.new(:subformulae => [1, 2, 3, nil, ASTIdent.new])
186
+ assert_false ASTAnd.new(:subformulae => [1, 2, 3, 4, ASTIdent.new]) == ASTAnd.new(:subformulae => [1, 2, 3, nil, ASTIdent.new])
187
+ assert_false(
188
+ ASTAnd.new(:subformulae => [1, 2, 3, nil, ASTIdent.new(:text => '')]) ==
189
+ ASTAnd.new(:subformulae => [1, 2, 3, nil, ASTIdent.new])
190
+ )
191
+ assert ASTDeleteObj.new == ASTDeleteObj.new
192
+ assert ASTDeleteObj.new.eql?(ASTDeleteObj.new)
193
+ assert ASTDeleteObj.new.hash == ASTDeleteObj.new.hash
194
+ end
195
+
196
+ def test__block_replace__replaces_the_instance
197
+ ast_node = ASTSubset.new(:objset => ASTAllOf.new(:class_name => ASTIdent.new(:text => :text)))
198
+ replaced = ast_node.block_replace do |node|
199
+ next unless node.is_a? ASTIdent
200
+ ASTIdent.new :text => 'new_text'
201
+ end
202
+ assert_equal ASTSubset, replaced.class
203
+ assert_equal ASTAllOf, replaced.objset.class
204
+ assert_equal ASTIdent, replaced.objset.class_name.class
205
+ assert_equal 'new_text', replaced.objset.class_name.text
206
+ end
207
+
208
+ def test__action_optimize__prepends_instance_and_class_variables
209
+ action = ASTAction.new(:block => ASTBlock.new(:statements => [
210
+ ASTEither.new(:blocks => [
211
+ ASTBlock.new(:statements => []),
212
+ ASTBlock.new(:statements => [
213
+ ASTBlock.new(:statements => [
214
+ ASTBlock.new(:statements => [
215
+ ASTAssignment.new(:objset => ASTVariable.new(:var_name => ASTIdent.new(:text => 'kme')))
216
+ ]),
217
+ ASTBlock.new(:statements => [
218
+ ASTAssignment.new(:objset => ASTVariable.new(:var_name => ASTIdent.new(:text => 'at__blahblah')))
219
+ ]),
220
+ ASTBlock.new(:statements => [])
221
+ ])
222
+ ]),
223
+ ASTBlock.new(:statements => [])
224
+ ]),
225
+ ASTDeleteObj.new
226
+ ]))
227
+
228
+ action = action.optimize
229
+ action.prepend_global_variables_by_signatures /^at__.*$/, /^atat__.*$/
230
+ assert_equal 3, action.block.statements.length
231
+
232
+ assert_equal ASTAssignment, action.block.statements[0].class
233
+ assert_equal 'at__blahblah', action.block.statements[0].var_name.text
234
+ assert_equal ASTEmptyObjset, action.block.statements[0].objset.class
235
+
236
+ assert_equal ASTEither, action.block.statements[1].class
237
+ blocks = action.block.statements[1].blocks
238
+
239
+ assert_equal 0, blocks.first.statements.length
240
+ assert_equal 2, blocks.second.statements.length
241
+ assert_equal ASTAssignment, blocks.second.statements[0].class
242
+ assert_equal 'kme', blocks.second.statements[0].objset.var_name.text
243
+ assert_equal ASTAssignment, blocks.second.statements[1].class
244
+ assert_equal 'at__blahblah', blocks.second.statements[1].objset.var_name.text
245
+
246
+ assert_equal ASTDeleteObj, action.block.statements[2].class
247
+ end
248
+
249
+ def test__either_optimize__unique_paths
250
+ either = ASTEither.new(:blocks => [
251
+ ASTBlock.new(:statements => []),
252
+ ASTBlock.new(:statements => []),
253
+ ASTBlock.new(:statements => [ASTDeleteObj.new(:objset => 1)]),
254
+ ASTBlock.new(:statements => [ASTDeleteObj.new(:objset => 1)]),
255
+ ASTBlock.new(:statements => [])
256
+ ])
257
+
258
+ either = either.optimize
259
+
260
+ assert_equal 2, either.blocks.length
261
+
262
+ assert_equal 0, either.blocks[0].statements.length
263
+ assert_equal 1, either.blocks[1].statements.length
264
+ assert_equal ASTDeleteObj, either.blocks[1].statements[0].class
265
+ assert_equal 1, either.blocks[1].statements[0].objset
266
+ end
267
+
268
+ def test__block_optimize__removes_last_stmts_without_sideeffects
269
+ action = ASTAction.new(:block => ASTBlock.new(:statements => [
270
+ ASTAssignment.new(:var_name => ASTIdent.new(:text => 'at_asdf'), :objset => ASTEmptyObjset.new),
271
+ ASTEither.new(:blocks => [
272
+ ASTBlock.new(:statements => []),
273
+ ASTBlock.new(:statements => [
274
+ ASTEither.new(:blocks => [
275
+ ASTBlock.new(:statements => [
276
+ ASTAssignment.new(:var_name => ASTIdent.new(:text => 'at_asdf'), :objset => ASTDummyObjset.new)
277
+ ]),
278
+ ASTBlock.new(:statements => [
279
+ ASTAssignment.new(:var_name => ASTIdent.new(:text => 'at_asdf'), :objset => ASTDummyObjset.new)
280
+ ])
281
+ ])
282
+ ]),
283
+ ASTBlock.new(:statements => [
284
+ ASTAssignment.new(:var_name => ASTIdent.new(:text => 'at_asdf'), :objset => ASTDummyObjset.new)
285
+ ]),
286
+ ASTBlock.new(:statements => [
287
+ ASTAssignment.new(:var_name => ASTIdent.new(:text => 'at_asdf'), :objset => ASTCreateObjset.new)
288
+ ])
289
+ ])
290
+ ]))
291
+
292
+ action = action.optimize
293
+
294
+ stmts = action.block.statements
295
+ assert_equal 1, stmts.length
296
+ assert_equal ASTObjsetStmt, stmts.first.class
297
+ assert_equal ASTCreateObjset, stmts.first.objset.class
298
+ end
299
+
300
+ def test__adsl_ast_size
301
+ ast = ASTBlock.new(:statements => [
302
+ ASTAssignment.new(:var_name => ASTIdent.new(:text => 'asd'), :objset => ASTEmptyObjset.new),
303
+ ASTDummyStmt.new(:type => :blah)
304
+ ])
305
+ assert_equal 5, ast.adsl_ast_size
306
+
307
+ ast = ASTBlock.new(:statements => [])
308
+ assert_equal 1, ast.adsl_ast_size
309
+ end
310
+
311
+ def test__spec_adsl_ast_size
312
+ spec = ASTSpec.new(
313
+ :classes => [ASTClass.new],
314
+ :actions => [
315
+ ASTAction.new(:name => ASTIdent.new(:text => 'action1')),
316
+ ASTAction.new(:name => ASTIdent.new(:text => 'action2')),
317
+ ASTAction.new(:name => ASTIdent.new(:text => '')),
318
+ ],
319
+ :invariants => [
320
+ ASTInvariant.new(:name => ASTIdent.new(:text => 'inv_name1')),
321
+ ASTInvariant.new(:name => ASTIdent.new(:text => 'inv_name2'))
322
+ ]
323
+ )
324
+
325
+ assert_equal 12, spec.adsl_ast_size
326
+ assert_equal 8, spec.adsl_ast_size(:action_name => 'action1')
327
+ assert_equal 8, spec.adsl_ast_size(:action_name => 'action2')
328
+
329
+ assert_equal 10, spec.adsl_ast_size(:invariant_name => 'inv_name1')
330
+
331
+ assert_equal 6, spec.adsl_ast_size(:action_name => '', :invariant_name => 'inv_name2')
332
+ end
333
+
334
+ def test__spec_pre_optimize_size
335
+ spec = ASTSpec.new(
336
+ :classes => [ASTClass.new],
337
+ :actions => [ASTAction.new(
338
+ :name => ASTIdent.new(:text => 'action'),
339
+ :block => ASTBlock.new(:statements => [
340
+ ASTDummyStmt.new(:type => :asd),
341
+ ASTEither.new(:blocks => [
342
+ ASTBlock.new(:statements => []),
343
+ ASTBlock.new(:statements => [
344
+ ASTDeleteObj.new
345
+ ]),
346
+ ])
347
+ ])
348
+ )],
349
+ :invariants => []
350
+ )
351
+ spec.actions.map!(&:optimize)
352
+
353
+ assert_equal 8, spec.actions.first.pre_optimize_adsl_ast_size
354
+ assert_equal 4, spec.actions.first.adsl_ast_size
355
+
356
+ assert_equal 6, spec.adsl_ast_size
357
+ assert_equal 10, spec.adsl_ast_size(:pre_optimize => true)
358
+ end
359
+ end
@@ -0,0 +1,288 @@
1
+ require 'adsl/parser/adsl_parser.tab'
2
+ require 'adsl/parser/ast_nodes'
3
+ require 'test/unit'
4
+ require 'pp'
5
+ require 'set'
6
+
7
+ module ADSL::Parser
8
+ class ClassParserTest < Test::Unit::TestCase
9
+ include ADSL::Parser
10
+
11
+ def test_class__empty
12
+ parser = ADSLParser.new
13
+ spec = parser.parse ""
14
+ assert_equal([], spec.classes)
15
+ assert_equal([], spec.actions)
16
+ end
17
+
18
+ def test_class__no_rels_and_order
19
+ parser = ADSLParser.new
20
+ spec = parser.parse <<-adsl
21
+ class Kme {}
22
+ class Zsd {}
23
+ class Asd {}
24
+ adsl
25
+ assert_equal 3, spec.classes.length
26
+ assert_equal ["Kme", "Zsd", "Asd"], spec.classes.map{ |a| a.name }
27
+ spec.classes.each do |klass|
28
+ assert_equal 0, klass.relations.count
29
+ assert_nil klass.parent
30
+ end
31
+ assert_equal 0, spec.actions.count
32
+ end
33
+
34
+ def test_class__superclass
35
+ parser = ADSLParser.new
36
+ assert_raise ADSLError do
37
+ parser.parse <<-adsl
38
+ class Class extends Unknown {}
39
+ adsl
40
+ end
41
+
42
+ spec = parser.parse <<-adsl
43
+ class Super {}
44
+ class Sub extends Super {}
45
+ adsl
46
+ assert_equal 2, spec.classes.length
47
+ assert_nil spec.classes[0].parent
48
+ assert_equal spec.classes[0], spec.classes[1].parent
49
+
50
+ spec = parser.parse <<-adsl
51
+ class Sub extends Super {}
52
+ class Super {}
53
+ adsl
54
+ assert_equal 2, spec.classes.length
55
+ assert_nil spec.classes[1].parent
56
+ assert_equal spec.classes[1], spec.classes[0].parent
57
+
58
+ begin
59
+ parser.parse <<-adsl
60
+ class Class extends Class {}
61
+ adsl
62
+ flunk "No error raised"
63
+ rescue ADSLError => e
64
+ assert e.message.include? 'Class -> Class'
65
+ end
66
+
67
+ begin
68
+ parser.parse <<-adsl
69
+ class First extends Class1 {}
70
+ class Class2 extends Class1 {}
71
+ class Class1 extends Class2 {}
72
+ adsl
73
+ flunk "No error raised"
74
+ rescue ADSLError => e
75
+ assert e.message.include? 'Class1 -> Class2'
76
+ end
77
+ end
78
+
79
+ def test_typecheck__rels_valid
80
+ parser = ADSLParser.new
81
+ spec = parser.parse <<-adsl
82
+ class Classname {
83
+ 1 Classname other
84
+ 1 Classname something_else
85
+ 1 Classname third
86
+ }
87
+ adsl
88
+
89
+ klass = spec.classes.select{ |a| a.name == "Classname" }.first
90
+ assert klass
91
+ assert_equal 3, klass.relations.count
92
+ assert_equal 'other', klass.relations[0].name
93
+ assert_equal 'something_else', klass.relations[1].name
94
+ assert_equal 'third', klass.relations[2].name
95
+ klass.relations.each do |rel|
96
+ assert rel.inverse_of.nil?
97
+ end
98
+ end
99
+
100
+ def test_typecheck__inverse_rels_valid
101
+ parser = ADSLParser.new
102
+ spec = parser.parse <<-adsl
103
+ class Classname {
104
+ 1 Classname other
105
+ 1 Classname something_else inverseof other
106
+ }
107
+ adsl
108
+
109
+ klass = spec.classes.select{ |a| a.name == "Classname" }.first
110
+ assert klass
111
+ assert_equal 2, klass.relations.count
112
+ assert_equal 1, klass.relations.select{ |a| a.inverse_of.nil? }.length
113
+ assert_equal 1, klass.relations.select{ |a| not a.inverse_of.nil? }.length
114
+ other = klass.relations.select{ |a| a.name == 'other'}.first
115
+ something_else = klass.relations.select{ |a| a.name == 'something_else'}.first
116
+ assert_equal other, something_else.inverse_of
117
+
118
+ assert_nothing_raised ADSLError do
119
+ parser.parse <<-adsl
120
+ class Classname {
121
+ 1 Classname something_else inverseof other
122
+ 1 Classname other
123
+ }
124
+ adsl
125
+ end
126
+
127
+ assert_nothing_raised ADSLError do
128
+ parser.parse <<-adsl
129
+ class Classname1 {
130
+ 1 Classname2 something_else inverseof other
131
+ }
132
+ class Classname2 {
133
+ 1 Classname1 other
134
+ }
135
+ adsl
136
+ end
137
+ end
138
+
139
+ def test_typecheck__relation_cardinality_valid
140
+ parser = ADSLParser.new
141
+ spec = parser.parse <<-adsl
142
+ class Classname {
143
+ 1 Classname other1
144
+ 1..1 Classname other2
145
+ 0..1 Classname other3
146
+ 0+ Classname other4
147
+ 1+ Classname other5
148
+ }
149
+ adsl
150
+
151
+ klass = spec.classes.select{ |a| a.name == "Classname" }.first
152
+ assert klass
153
+ assert_equal [1, 1], klass.relations[0].cardinality
154
+ assert_equal [1, 1], klass.relations[1].cardinality
155
+ assert_equal [0, 1], klass.relations[2].cardinality
156
+ assert_equal [0, 1.0/0.0], klass.relations[3].cardinality
157
+ assert_equal [1, 1.0/0.0], klass.relations[4].cardinality
158
+ end
159
+
160
+ def test_typecheck__relation_cardinality_invalid
161
+ parser = ADSLParser.new
162
+ assert_raise ADSLError do
163
+ parser.parse <<-adsl
164
+ class Classname {
165
+ 0 Classname other
166
+ }
167
+ adsl
168
+ end
169
+ assert_raise ADSLError do
170
+ parser.parse <<-adsl
171
+ class Classname {
172
+ 0..0 Classname other
173
+ }
174
+ adsl
175
+ end
176
+ assert_raise ADSLError do
177
+ parser.parse <<-adsl
178
+ class Classname {
179
+ 1..0 Classname other
180
+ }
181
+ adsl
182
+ end
183
+ end
184
+
185
+ def test_typecheck__repeating_classname
186
+ parser = ADSLParser.new
187
+ assert_raise ADSLError do
188
+ parser.parse <<-adsl
189
+ class Classname {}
190
+ class Classname {}
191
+ adsl
192
+ end
193
+ end
194
+
195
+ def test_typecheck__unknown_rel_type
196
+ parser = ADSLParser.new
197
+ assert_raise ADSLError do
198
+ parser.parse <<-adsl
199
+ class Classname {
200
+ 1 UnknownClass other
201
+ }
202
+ adsl
203
+ end
204
+ end
205
+
206
+ def test_typecheck__mulitple_rels_under_the_same_name
207
+ parser = ADSLParser.new
208
+ assert_raise ADSLError do
209
+ parser.parse <<-adsl
210
+ class Classname {
211
+ 1 Classname other
212
+ 1 Classname other
213
+ }
214
+ adsl
215
+ end
216
+ end
217
+
218
+ def test_typecheck__multiple_rels_same_name_different_classes
219
+ parser = ADSLParser.new
220
+ assert_nothing_raised do
221
+ parser.parse <<-adsl
222
+ class Classname {
223
+ 1 Classname other
224
+ }
225
+ class Classname2 {
226
+ 1 Classname other
227
+ }
228
+ adsl
229
+ end
230
+ end
231
+
232
+ def test_typecheck__multiple_rels_same_name_parent_classes
233
+ parser = ADSLParser.new
234
+ assert_nothing_raised ADSLError do
235
+ parser.parse <<-adsl
236
+ class Parent {
237
+ 1 Parent other
238
+ }
239
+ class Child extends Parent {
240
+ 1 Parent other2
241
+ }
242
+ adsl
243
+ end
244
+ assert_raise ADSLError do
245
+ parser.parse <<-adsl
246
+ class Parent {
247
+ 1 Parent other
248
+ }
249
+ class Child extends Parent {
250
+ 1 Parent other
251
+ }
252
+ adsl
253
+ end
254
+ end
255
+
256
+ def test_typecheck__inverse_rel_of_unexisting
257
+ parser = ADSLParser.new
258
+ assert_raise ADSLError do
259
+ parser.parse <<-adsl
260
+ class Classname {
261
+ 1 Classname other
262
+ 1 Classname other2 inverseof unexisting
263
+ }
264
+ adsl
265
+ end
266
+ end
267
+
268
+ def test_typecheck__inverse_rel_of_an_inverse
269
+ parser = ADSLParser.new
270
+ assert_raise ADSLError do
271
+ parser.parse <<-adsl
272
+ class Classname {
273
+ 1 Classname other inverseof other
274
+ }
275
+ adsl
276
+ end
277
+ assert_raise ADSLError do
278
+ parser.parse <<-adsl
279
+ class Classname {
280
+ 0+ Classname rel1 inverseof rel2
281
+ 0+ Classname rel2 inverseof rel1
282
+ }
283
+ adsl
284
+ end
285
+ end
286
+
287
+ end
288
+ end