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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6b26fde19cd7f72d505d12b67a37e9eb7c76aba2
4
- data.tar.gz: 425182f63a8d718786e63dc9f21439c764f9332a
3
+ metadata.gz: ebe37d86fc7f4beca92d9a2774ea9261f65bd3fa
4
+ data.tar.gz: 81b1927dd5809ded4855b31283a53222160160e4
5
5
  SHA512:
6
- metadata.gz: a15fbddc4618acafd6cfe069195656f11ac0ec58ac3d22b36341fa90b0c5a690d15e3ad5c687a0a1c3af134e82093428a93a07737d19f09fcd7241dca437c1a6
7
- data.tar.gz: 6f84daa5917019dbf27dc523e693d7eee093329de27826777b85c9ce173a09268751e396cbba04d55984e3bdc48c7363b66c12492b3a74428da06ea75facc5f9
6
+ metadata.gz: a2d4e8b5fb36b758459a10309ca14fef2007894f73b26301c6eb6c50ed72f7d61a829a7a5fe1606f86e46b0a40488df6950d2a1582bbb96ebd9f5036a9dc839f
7
+ data.tar.gz: ecd21de07c4f79acd1b7dd4f16240dd02adfb8ba96b0f570e937b48cff376e7925450069898ae9389e88589f15814e8fab2109656538d347b2f83765d10374b6
data/Gemfile CHANGED
@@ -1,20 +1,2 @@
1
- source "http://rubygems.org"
2
-
3
- # base
4
- # indentation added to prevent these dependencies when building the gem
5
- gem "rake"
6
- gem "test-unit"
7
- gem "i18n"
8
-
9
- # lexer/parser
10
- gem "rexical"
11
- gem "racc"
12
-
13
- # used all over the place
14
- gem "active_support"
15
-
16
- # terminal color output
17
- gem "colorize"
18
-
19
- # extraction tools
20
- gem "ruby_parser"
1
+ source 'https://rubygems.org'
2
+ gemspec
data/README.md CHANGED
@@ -1,17 +1,15 @@
1
- ADSL - Abstract Data Store Language Parser and Translator
1
+ ADSL - Abstract Data Store Library
2
2
  =========================================================
3
3
 
4
- This tool an Abstract Data Store Language (ADSL) specification verification tool.
4
+ ADSL is a gem for formal verification of Ruby on Rails models. Simply include it in your Gemfile, write a few
5
+ invariants (rules) about ActiveRecord data that you wish to verify (for example, that at any given moment, every
6
+ Address has a User) and run `rake verify`!
5
7
 
6
- ADSL is a language for specifying Abstract Data Stores using a syntax familiar to anyone that has experience
7
- with ORM tools such as Hibernate and ActiveRecord. A specification contains the model classes, actions executed
8
- using a RESTful interface, and a set of invariants to be verified.
8
+ Besides the verification algorithm, this tool includes a DSL for specifying invariants. The syntax should feel
9
+ natural to any Rails user. Look at /examples.
9
10
 
10
- This tool verifies a specification by translating it into a first order logic theorem verifiable by [Spass] [1],
11
- a theorem prover. It provides detailed information on the actions and invariants verified in human-readable or
12
- CSV format.
13
-
14
- This tool is distributed as a Ruby gem and is uploaded to [RubyGems.org] [2]. Install it and give it a try!
11
+ This tool is distributed as a Ruby gem and is uploaded to [RubyGems.org] [2]. It requires Spass[1] to run. Install
12
+ it and give it a try!
15
13
 
16
14
 
17
15
  Installation
@@ -20,24 +18,19 @@ Installation
20
18
  This gem is tested on 32 and 64 bit Linux. OS-X compatibility not tested, give it a try
21
19
  and tell us if it works! Windows is not supported at this moment.
22
20
 
23
- - Ruby 1.8.7 or later required. We suggest using the [Ruby Version Manager](https://rvm.io/rvm/install/) to manage this installation.
21
+ - Ruby 1.9.3 or later required, along with Rails 3.2. We suggest using the [Ruby Version Manager](https://rvm.io/rvm/install/) to manage this installation.
24
22
  - [Download and install Spass](http://www.spass-prover.org/download/index.html) and make sure its executable (`bin/SPASS`) on your $PATH
25
23
  - Install the ADSL gem by running `gem install adsl`.
26
-
27
24
  If you receive an error while generating documentation for 'activesupport' run `gem install rdoc adsl` instead.
28
- - Test the installation by verifying [the example specification](https://raw.github.com/Bocete/adsl/master/example/running-example.adsl)
29
-
25
+
30
26
  Usage
31
27
  -----
32
28
 
33
- adsl-verify <specification-file>
34
-
35
- For options and other modes of operation, run
36
-
37
- adsl-verify --help
38
-
39
- You can download sample ADSL specifications
29
+ rake verify <options>
30
+
31
+ Or, to just observe the extracted model,
40
32
 
33
+ rake adsl_translate
41
34
 
42
35
  Development
43
36
  -----------
@@ -9,7 +9,7 @@ options.language = 'spass'
9
9
  options.halt_on_error = false
10
10
  options.check_satisfiability = true
11
11
  options.timeout = 30
12
- options.csv_output = false
12
+ options.output = 'terminal'
13
13
  options.actions = nil
14
14
  options.invariants = nil
15
15
 
@@ -36,10 +36,10 @@ OptionParser.new do |opts|
36
36
  options.check_satisfiability = check
37
37
  end
38
38
 
39
- opts.on("-s", "--stats-csv",
40
- "Output the results of the verification with stats in CSV form.",
41
- " Default: #{options.csv_output}") do
42
- options.csv_output = true
39
+ opts.on("-o", "--output-format FORMAT",
40
+ "Sets the output format. Options: terminal, csv, or silent",
41
+ " Default: #{options.output}") do |format|
42
+ options.output = format
43
43
  end
44
44
 
45
45
  opts.on("-t", "--timeout TIMEOUT", Integer,
@@ -87,14 +87,14 @@ $LOAD_PATH.unshift GEM_LIB_PATH unless $LOAD_PATH.include? GEM_LIB_PATH
87
87
 
88
88
  case options.language
89
89
  when 'spass'
90
- require 'spass/bin'
91
- include Spass::Bin
90
+ require 'adsl/spass/bin'
91
+ include ADSL::Spass::Bin
92
92
  begin
93
93
  verify(input,
94
94
  :halt_on_error => options.halt_on_error,
95
95
  :check_satisfiability => options.check_satisfiability,
96
96
  :timeout => options.timeout,
97
- :csv_output => options.csv_output,
97
+ :output => options.output,
98
98
  :actions => options.actions,
99
99
  :invariants => options.invariants)
100
100
  rescue Exception => e
@@ -0,0 +1,3 @@
1
+ module ADSL
2
+ require 'adsl/railtie' if defined?(Rails)
3
+ end
@@ -0,0 +1,3 @@
1
+ module ADSL
2
+ require 'adsl/realtie' if refined?(Rails)
3
+ end
@@ -0,0 +1,339 @@
1
+ require 'adsl/util/general'
2
+
3
+ module ADSL
4
+ module DS
5
+ class DSNode
6
+ def list_entity_classes_written_to
7
+ recursively_gather :entity_class_writes
8
+ end
9
+
10
+ def list_entity_classes_read
11
+ recursively_gather :entity_class_reads
12
+ end
13
+
14
+ def replace(what, with)
15
+ to_inspect = [self]
16
+ inspected = Set.new
17
+ replaced = false
18
+ while not to_inspect.empty?
19
+ elem = to_inspect.pop
20
+ if elem.kind_of? Array
21
+ elem.length.times do |i|
22
+ if elem[i] == what
23
+ elem[i] = with
24
+ replaced = true
25
+ else
26
+ to_inspect << elem[i] unless inspected.include? elem[i]
27
+ end
28
+ inspected << elem[i]
29
+ end
30
+ elsif elem.class.methods.include? 'container_for_fields' or elem.class.methods.include? :container_for_fields
31
+ elem.class.container_for_fields.each do |field_name|
32
+ field_val = elem.send field_name
33
+ if field_val == what
34
+ elem.send "#{field_name}=", with
35
+ replaced = true
36
+ elsif field_val.kind_of?(Array) or field_val.class.methods.include?('container_for_fields')
37
+ to_inspect << field_val unless inspected.include? field_val
38
+ end
39
+ inspected << field_val
40
+ end
41
+ end
42
+ end
43
+ replaced
44
+ end
45
+ end
46
+
47
+ class DSSpec < DSNode
48
+ container_for :classes, :actions, :invariants
49
+ end
50
+
51
+ class DSClass < DSNode
52
+ container_for :name, :parent, :relations, :inverse_relations do
53
+ @relations = [] if @relations.nil?
54
+ @inverse_relations = [] if @inverse_relations.nil?
55
+ end
56
+
57
+ def to_s
58
+ @name
59
+ end
60
+
61
+ def superclass_of?(other_class)
62
+ until other_class.nil?
63
+ return true if other_class == self
64
+ other_class = other_class.parent
65
+ end
66
+ return false
67
+ end
68
+
69
+ def self.common_supertype(classes)
70
+ types = classes.uniq
71
+ types.delete nil
72
+ while types.length > 1
73
+ type1 = types.pop
74
+ type2 = types.pop
75
+ if type1.superclass_of? type2
76
+ types << type2
77
+ elsif type2.superclass_of? type1
78
+ types << type1
79
+ else
80
+ raise ADSLError, "Object sets are not of compatible types: #{classes.map { |c| c.name }.join(", ")}"
81
+ end
82
+ end
83
+ types.first
84
+ end
85
+ end
86
+
87
+ class DSRelation < DSNode
88
+ container_for :cardinality, :from_class, :to_class, :name, :inverse_of
89
+
90
+ def to_s
91
+ "#{from_class.name}.#{name}"
92
+ end
93
+ end
94
+
95
+ class DSAction < DSNode
96
+ container_for :name, :args, :cardinalities, :block
97
+
98
+ def statements
99
+ @block.statements
100
+ end
101
+ end
102
+
103
+ class DSBlock < DSNode
104
+ container_for :statements
105
+ end
106
+
107
+ class DSAssignment < DSNode
108
+ container_for :var, :objset
109
+ end
110
+
111
+ class DSCreateObj < DSNode
112
+ container_for :klass
113
+
114
+ def entity_class_writes
115
+ Set[@klass]
116
+ end
117
+ end
118
+
119
+ class DSCreateObjset < DSNode
120
+ container_for :createobj
121
+
122
+ def type
123
+ @createobj.klass
124
+ end
125
+ end
126
+
127
+ class DSCreateTup < DSNode
128
+ container_for :objset1, :relation, :objset2
129
+ end
130
+
131
+ class DSDeleteObj < DSNode
132
+ container_for :objset
133
+
134
+ def entity_class_writes
135
+ Set[@objset.type]
136
+ end
137
+ end
138
+
139
+ class DSDeleteTup < DSNode
140
+ container_for :objset1, :relation, :objset2
141
+ end
142
+
143
+ class DSEither < DSNode
144
+ container_for :blocks, :lambdas
145
+ end
146
+
147
+ class DSEitherLambdaObjset < DSNode
148
+ container_for :either, :vars
149
+ end
150
+
151
+ class DSForEachCommon < DSNode
152
+ container_for :objset, :block
153
+ end
154
+
155
+ class DSForEach < DSForEachCommon
156
+ end
157
+
158
+ class DSFlatForEach < DSForEachCommon
159
+ end
160
+
161
+ class DSForEachIteratorObjset < DSNode
162
+ container_for :for_each
163
+
164
+ def typecheck_and_resolve(context)
165
+ self
166
+ end
167
+
168
+ def type
169
+ @for_each.objset.type
170
+ end
171
+ end
172
+
173
+ class DSForEachPreLambdaObjset < DSNode
174
+ container_for :for_each, :before_var, :inside_var
175
+ end
176
+
177
+ class DSForEachPostLambdaObjset < DSNode
178
+ container_for :for_each, :before_var, :inside_var
179
+ end
180
+
181
+ class DSVariable < DSNode
182
+ container_for :name, :type
183
+ end
184
+
185
+ class DSAllOf < DSNode
186
+ container_for :klass
187
+
188
+ def type
189
+ @klass
190
+ end
191
+
192
+ def entity_class_reads
193
+ @klass
194
+ end
195
+ end
196
+
197
+ class DSSubset < DSNode
198
+ container_for :objset
199
+
200
+ def type
201
+ @objset.type
202
+ end
203
+ end
204
+
205
+ class DSUnion < DSNode
206
+ container_for :objsets
207
+
208
+ def type
209
+ DSClass.common_supertype objsets.reject{ |o| o.type.nil? }.map{ |o| o.type }
210
+ end
211
+ end
212
+
213
+ class DSOneOfObjset < DSNode
214
+ container_for :objsets
215
+
216
+ def type
217
+ DSClass.common_supertype objsets.reject{ |o| o.type.nil? }.map{ |o| o.type }
218
+ end
219
+ end
220
+
221
+ class DSOneOf < DSNode
222
+ container_for :objset
223
+ def type
224
+ @objset.type
225
+ end
226
+ end
227
+
228
+ class DSDereference < DSNode
229
+ container_for :objset, :relation
230
+
231
+ def type
232
+ @relation.to_class
233
+ end
234
+ end
235
+
236
+ class DSEmptyObjset < DSNode
237
+ container_for
238
+
239
+ def type
240
+ nil
241
+ end
242
+ end
243
+
244
+ class DSInvariant < DSNode
245
+ container_for :name, :formula
246
+ end
247
+
248
+ class DSBoolean < DSNode
249
+ container_for :bool_value
250
+
251
+ TRUE = DSBoolean.new :bool_value => true
252
+ FALSE = DSBoolean.new :bool_value => false
253
+
254
+ def type
255
+ :formula
256
+ end
257
+ end
258
+
259
+ class DSForAll < DSNode
260
+ container_for :vars, :objsets, :subformula
261
+
262
+ def type
263
+ :formula
264
+ end
265
+ end
266
+
267
+ class DSExists < DSNode
268
+ container_for :vars, :objsets, :subformula
269
+
270
+ def type
271
+ :formula
272
+ end
273
+ end
274
+
275
+ class DSIn < DSNode
276
+ container_for :objset1, :objset2
277
+
278
+ def type
279
+ :formula
280
+ end
281
+ end
282
+
283
+ class DSEmpty < DSNode
284
+ container_for :objset
285
+
286
+ def type
287
+ :formula
288
+ end
289
+ end
290
+
291
+ class DSNot < DSNode
292
+ container_for :subformula
293
+
294
+ def type
295
+ :formula
296
+ end
297
+ end
298
+
299
+ class DSAnd < DSNode
300
+ container_for :subformulae
301
+
302
+ def type
303
+ :formula
304
+ end
305
+ end
306
+
307
+ class DSOr < DSNode
308
+ container_for :subformulae
309
+
310
+ def type
311
+ :formula
312
+ end
313
+ end
314
+
315
+ class DSImplies < DSNode
316
+ container_for :subformula1, :subformula2
317
+
318
+ def type
319
+ :formula
320
+ end
321
+ end
322
+
323
+ class DSEquiv < DSNode
324
+ container_for :subformulae
325
+
326
+ def type
327
+ :formula
328
+ end
329
+ end
330
+
331
+ class DSEqual < DSNode
332
+ container_for :objsets
333
+
334
+ def type
335
+ :formula
336
+ end
337
+ end
338
+ end
339
+ end