cddl 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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: bc6439f876088c1d9355f78363bfa34eaa844613
4
+ data.tar.gz: eb88cc041f3a03ef495aeecf4b663af0a2384673
5
+ SHA512:
6
+ metadata.gz: 449e97a60fb3ee5584b582dc8da13d54de607f99ce02020a5565d7495142a8547965429b9d429582a2c898f8c6680a64d089339ff6c8fe4def07887da9ddd782
7
+ data.tar.gz: af6dd64fe9c1267fe4f86fbf4825e7da9faa4be03545991369b647c5766e5735fb1c760341bdf0afb7a4f07f3f7f06279bb1e900c459795eaf150c5c76cbb9a1
@@ -0,0 +1,42 @@
1
+ #!/usr/bin/env ruby
2
+ # -*- coding: utf-8 -*-
3
+ require 'cddl'
4
+ require 'cbor-diagnostic'
5
+ require 'json'
6
+
7
+ Encoding.default_external = "UTF-8" # wake up, smell the coffee
8
+
9
+ def usage
10
+ warn "Usage:"
11
+ warn "#$0 spec.cddl generate [n]"
12
+ warn "#$0 spec.cddl json-generate [n]"
13
+ warn "#$0 spec.cddl validate instance.cbor"
14
+ warn "#$0 spec.cddl validate instance.json"
15
+ exit 1
16
+ end
17
+
18
+ case ARGV[1]
19
+ when /\Ag/
20
+ parser = CDDL::Parser.new(File.read(ARGV[0]))
21
+ n = 1
22
+ n = ARGV[2].to_i if ARGV[2]
23
+ n.times do
24
+ g = parser.generate
25
+ puts g.cbor_diagnostic
26
+ end
27
+ when /\Aj/
28
+ parser = CDDL::Parser.new(File.read(ARGV[0]))
29
+ n = 1
30
+ n = ARGV[2].to_i if ARGV[2]
31
+ n.times do
32
+ g = parser.generate
33
+ puts JSON.pretty_generate(g)
34
+ end
35
+ when /\Av/
36
+ parser = CDDL::Parser.new(File.read(ARGV[0]))
37
+ instance = File.read(ARGV[2])
38
+ instance = CBOR.decode(instance) rescue JSON.load(instance)
39
+ p parser.validate(instance)
40
+ else
41
+ usage
42
+ end
@@ -0,0 +1,19 @@
1
+ spec = Gem::Specification.new do |s|
2
+ s.name = 'cddl'
3
+ s.version = '0.1.0'
4
+ s.summary = "CDDL generator and validator."
5
+ s.description = %{A parser, generator, and validator for CDDL}
6
+ s.add_dependency('cbor-diag')
7
+ s.add_dependency('abnc')
8
+ s.add_dependency('json')
9
+ s.files = `git ls-files`.split("\n").grep(/^[a-z]/)
10
+ s.files = Dir['lib/**/*.rb'] + %w(cddl.gemspec) + Dir['data/**/*.abnf'] + Dir['data/**/*.cddl'] + Dir['test-data/**/*.cddl'] + Dir['test/**/*.rb']
11
+ s.require_path = 'lib'
12
+ s.executables = ['cddl']
13
+ s.default_executable = 'cddl'
14
+ s.required_ruby_version = '>= 1.9.2'
15
+ s.author = "Carsten Bormann"
16
+ s.email = "cabo@tzi.org"
17
+ s.homepage = "http://github.com/cabo/cddl"
18
+ s.license = 'MIT'
19
+ end
@@ -0,0 +1,62 @@
1
+ cddl = S 1*rule
2
+ rule = typename S "=" S type S
3
+ / groupname S "=" S group S
4
+
5
+ typename = id
6
+ groupname = id
7
+
8
+ type = type1 S *("/" S type1 S)
9
+
10
+ type1 = value
11
+ / "#" "6" ["." uint] "(" S type S ")" ; note no space!
12
+ / "#" DIGIT ["." uint] ; major/ai
13
+ / "#" ; any
14
+ / "{" S group S "}"
15
+ / "[" S group S "]"
16
+ / "(" type ")"
17
+ / typename
18
+
19
+ group = "(" S *grpent S ")"
20
+ / *grpent
21
+
22
+ grpent = [occur S] [memberkey S] type1 optcom
23
+ / [occur S] groupname optcom ; always preempted by previous...
24
+
25
+ memberkey = membername S ":"
26
+ membername = bareword ; note that this can be a typename
27
+ / type1 ; can be preempted by previous...
28
+
29
+ bareword = id
30
+
31
+ optcom = S ["," S]
32
+
33
+ occur = [uint] "*" [uint]
34
+ / "+"
35
+ / "?"
36
+
37
+ uint = "0"
38
+ / DIGIT1 *DIGIT
39
+
40
+ value = int
41
+ / float
42
+ / string
43
+
44
+ int = ["-"] uint
45
+
46
+ float = int ["." 1*DIGIT] ["e" int ]
47
+
48
+ string = %x22 *SCHAR %x22
49
+ SCHAR = %x20-21 / %x23-7E / SESC
50
+ SESC = "\" %x20-7E
51
+
52
+ id = ALPHA *(ALPHA / DIGIT / "_" / "-")
53
+ ALPHA = %x41-5A / %x61-7A
54
+ DIGIT = %x30-39
55
+ DIGIT1 = %x31-39
56
+ S = *WS
57
+ WS = SP / NL
58
+ SP = %x20
59
+ NL = COMMENT / CRLF
60
+ COMMENT = ";" *(SP / VCHAR) CRLF
61
+ VCHAR = %x21-7E
62
+ CRLF = %x0A / %x0D.0A
@@ -0,0 +1,43 @@
1
+ ; --- prelude ---
2
+
3
+ any = #
4
+
5
+ uint = #0
6
+ nint = #1
7
+ int = uint / nint
8
+
9
+ bstr = #2
10
+ tstr = #3
11
+
12
+ tdate = #6.0(tstr)
13
+ time = #6.1(number)
14
+ number = int / float
15
+ biguint = #6.2(bstr)
16
+ bignint = #6.3(bstr)
17
+ bigint = biguint / bignint
18
+ integer = int / bigint
19
+ decfrac = #6.4([e10: int, m: integer])
20
+ bigfloat = #6.5([e2: int, m: integer])
21
+ eb64url = #6.21(any)
22
+ eb64legacy = #6.21(any)
23
+ eb16 = #6.21(any)
24
+ encoded-cbor = #6.24(bstr)
25
+ uri = #6.32(tstr)
26
+ b64url = #6.33(tstr)
27
+ b64legacy = #6.34(tstr)
28
+ regexp = #6.35(tstr)
29
+ mime-message = #6.36(tstr)
30
+ cbor-any = #6.55799(any)
31
+
32
+ float16 = #7.25
33
+ float32 = #7.26
34
+ float64 = #7.27
35
+ float16-32 = float16 / float32
36
+ float32-64 = float32 / float64
37
+ float = float16-32 / float64
38
+
39
+ false = #7.20
40
+ true = #7.21
41
+ nil = #7.22
42
+ undefined = #7.23
43
+
@@ -0,0 +1,442 @@
1
+ require 'abnc'
2
+ require 'pp'
3
+ require 'pathname'
4
+
5
+ module CDDL
6
+
7
+ DATA_DIR = Pathname.new(__FILE__).split[0] + '../data'
8
+
9
+ PRELUDE = File.read("#{DATA_DIR}/prelude.cddl")
10
+ ABNF_SPEC = File.read("#{DATA_DIR}/cddl.abnf")
11
+
12
+ class Parser
13
+ def initialize(source_text)
14
+ @abnf = Peggy::ABNF.new
15
+ _cresult = @abnf.compile! ABNF_SPEC, ignore: :s
16
+ presult = @abnf.parse? :cddl, (source_text + PRELUDE)
17
+ expected_length = source_text.length + PRELUDE.length
18
+ if expected_length != presult
19
+ upto = @abnf.parse_results.keys.max
20
+ puts "UPTO: #{upto}"
21
+ pp @abnf.parse_results[upto]
22
+ pp @abnf.parse_results[presult]
23
+ p presult
24
+ puts @abnf.ast?
25
+ raise "parse error at #{presult} upto #{upto} of #{expected_length}"
26
+ end
27
+ puts @abnf.ast? if $debug_ast
28
+ @ast = @abnf.ast?
29
+ end
30
+
31
+ def apr # for debugging
32
+ @abnf.parse_results
33
+ end
34
+
35
+ def rules
36
+ @rules = {}
37
+ ast.each :rule do |rule|
38
+ # p rule
39
+ if rulename = rule.groupname
40
+ fail "Duplicate rule #{rulename.to_s}" if @rules[rulename.to_s]
41
+ @rules[rulename.to_s] = [:grpent, *rule.group.children(:grpent)]
42
+ elsif rulename = rule.typename
43
+ fail "Duplicate rule #{rulename.to_s}" if @rules[rulename.to_s]
44
+ @rules[rulename.to_s] = [:type1, *rule.type.children(:type1)]
45
+ else
46
+ fail "Huh?"
47
+ end
48
+ end
49
+ # pp @rules
50
+ @rootrule = @rules.keys.first
51
+ # now process the rules...
52
+ @stage1 = {}
53
+ r_process(@rootrule, @rules[@rootrule])
54
+ # @rules.each do |n, r| # debug only loop
55
+ # r_process(n, r)
56
+ # end
57
+ # @stage1
58
+ end
59
+
60
+ def generate(where=rules, inmap = false)
61
+ case where[0]
62
+ when :type1
63
+ generate(where[rand(where.size-1)+1])
64
+ when :map
65
+ Hash[where[1..-1].flat_map {|m| generate(m, true)}]
66
+ when :array
67
+ where[1..-1].flat_map {|m| generate(m).map{|e| e[1]}}
68
+ when :member
69
+ s = where[1]
70
+ e = where[2]
71
+ e = 4 if e == -1
72
+ s += rand(e + 1 - s) if e != s
73
+ kr = where[3]
74
+ vr = where[4]
75
+ fail "member key not given in map for #{where}" unless kr if inmap
76
+ Array.new(s) { [ (generate(kr) if kr), # XXX: need error in map context
77
+ generate(vr)
78
+ ]}
79
+ when :string, :int, :float
80
+ where[1]
81
+ when :prim
82
+ case where[1]
83
+ when nil
84
+ gen_word
85
+ when 0
86
+ rand(4711)
87
+ when 1
88
+ ~rand(815)
89
+ when 2
90
+ gen_word.force_encoding(Encoding::BINARY)
91
+ when 3
92
+ gen_word
93
+ when 7
94
+ case where[2]
95
+ when nil
96
+ Math::PI
97
+ when 20
98
+ false
99
+ when 21
100
+ true
101
+ when 22
102
+ nil
103
+ when 23
104
+ :undefined
105
+ when 25, 26, 27
106
+ rand()
107
+ end
108
+ else
109
+ fail "Can't generate prim #{where[1]}"
110
+ end
111
+ else
112
+ # fail where
113
+ end
114
+ end
115
+
116
+ VALUE_TYPE = {string: true, int: true, float: true}
117
+ SIMPLE_VALUE = {
118
+ [:prim, 7, 20] => [true, false],
119
+ [:prim, 7, 21] => [true, true],
120
+ [:prim, 7, 22] => [true, nil],
121
+ [:prim, 7, 23] => [true, :undefined],
122
+ }
123
+
124
+ def extract_value(t)
125
+ if VALUE_TYPE[t[0]]
126
+ [true, t[1]]
127
+ elsif v = SIMPLE_VALUE[t]
128
+ v
129
+ else
130
+ [false]
131
+ end
132
+ end
133
+
134
+ def validate_diag
135
+ [@last_data, @last_rule, @last_message]
136
+ end
137
+
138
+ def validate(d, warn=true)
139
+ result = validate1(d)
140
+ unless result
141
+ if warn
142
+ warn "CDDL validation failure:"
143
+ PP::pp(validate_diag, STDERR)
144
+ end
145
+ end
146
+ result
147
+ end
148
+
149
+ def validate_result(check)
150
+ check || (
151
+ @last_message = yield
152
+ false
153
+ )
154
+ end
155
+
156
+ def validate1(d, where=rules)
157
+ # puts "DATA: #{d.inspect}"
158
+ # puts "RULE: #{where.inspect}"
159
+ @last_data = d
160
+ @last_rule = where
161
+ case where[0]
162
+ when :type1
163
+ where[1..-1].any? {|r| validate1(d, r)}
164
+ when :map
165
+ if Hash === d
166
+ d_check = d.dup
167
+ where[1..-1].all? { |r|
168
+ # puts "SUBRULE: #{r.inspect}"
169
+ t, s, _e, k, v = r
170
+ fail unless t == :member
171
+ # this is mostly quadratic; let's do the linear thing if possible
172
+ fail "member name not known for group entry #{r} in map" unless k
173
+ simple, simpleval = extract_value(k)
174
+ if simple
175
+ # puts "SIMPLE: #{d_check.inspect} #{simpleval}"
176
+ # add occurrence check; check that val is present in the first place
177
+ actual = d.fetch(simpleval, :not_found)
178
+ if actual == :not_found
179
+ s == 0 # minimum occurrence must be 0 then
180
+ else
181
+ validate1(actual, v) && d_check.delete(simpleval)
182
+ end
183
+ else
184
+ # puts "COMPLEX: #{k.inspect} #{simple.inspect} #{simpleval.inspect}"
185
+ keys = d_check.keys
186
+ ta, keys = keys.partition{ |key| validate1(key, k)}
187
+ # XXX check ta.size against s/e
188
+ ta.all? { |val|
189
+ validate1(d[val], v) && d_check.delete(val)
190
+ }
191
+ end
192
+ } && d_check == {}
193
+ end
194
+ when :array
195
+ if Array === d
196
+ # validate1 against the record
197
+ i = 0
198
+ where[1..-1].each { |r|
199
+ t, s, e, _k, v = r # XXX
200
+ fail unless t == :member
201
+ occ = 0
202
+ while ((e == -1 || occ < e) && i != d.size && validate1(d[i], v))
203
+ i += 1
204
+ occ += 1
205
+ end
206
+ if occ < s
207
+ @last_message = "occur not reached in array #{d} for #{where}"
208
+ return false
209
+ end
210
+ }
211
+ validate_result(i == d.size) { "cannot complete array #{d} for #{where}" }
212
+ end
213
+ when :string, :int, :float
214
+ _, v = extract_value(where)
215
+ d == v
216
+ when :prim
217
+ case where[1]
218
+ when nil
219
+ true
220
+ when 0
221
+ Integer === d && d >= 0 && d <= 0xffffffffffffffff
222
+ when 1
223
+ Integer === d && d < 0 && d >= -0x10000000000000000
224
+ when 2
225
+ String === d && d.encoding == Encoding::BINARY
226
+ when 3
227
+ String === d && d.encoding != Encoding::BINARY # cheat
228
+ when 7
229
+ t, v = extract_value(where)
230
+ if t
231
+ v == d
232
+ else
233
+ case where[2]
234
+ when nil
235
+ # XXX
236
+ fail
237
+ when 25, 26, 27
238
+ Float === d
239
+ else
240
+ fail
241
+ end
242
+ end
243
+
244
+ else
245
+ fail "Can't generate prim #{where[1]}"
246
+ end
247
+ else
248
+ # fail where
249
+ end
250
+ end
251
+
252
+
253
+ attr_reader :ast
254
+
255
+ private
256
+
257
+ def gen_word
258
+ @words ||= File.read("/usr/share/dict/words").lines.shuffle
259
+ @wordptr ||= 0
260
+ @wordptr = 0 if @wordptr == @words.size
261
+ w = @words[@wordptr].chomp
262
+ @wordptr += 1
263
+ w
264
+ end
265
+
266
+ # XXX needs serious memoizing
267
+
268
+ def r_process(n, r)
269
+ t = r[0]
270
+ # puts "Processing rule #{n} = #{t}"
271
+ @stage1[n] ||= [t, *r[1..-1].map {|e| send(t, e)}]
272
+ end
273
+
274
+ def value(n)
275
+ # cheat:
276
+ val = eval(n.to_s)
277
+ [case val
278
+ when Integer; :int
279
+ when Numeric; :float
280
+ when String; :string
281
+ else fail "huh? value #{val.inspect}"
282
+ end, val]
283
+ end
284
+
285
+ def grpent(n) # returns array of entries
286
+ occ = occur(n.occur)
287
+ if mk = n.memberkey # work around unclear bug in ast generation
288
+ [[:member, *occ, label(mk.membername), type1(n.type1)]]
289
+ else
290
+ # fail n.inspect unless n.type1
291
+ t = if n.membername # work around unclear bug, part 2
292
+ type1(n.membername.type1, true)
293
+ else
294
+ type1(n.type1, true) # type1 can be a group here!
295
+ end
296
+ if t[0] == :grpent
297
+ # XXX go through the members here and multiply the occs
298
+ t1 = t[1..-1].flatten(1)
299
+ t1.flat_map {|t2|
300
+ if t2[0] == :member
301
+ [t2]
302
+ else
303
+ fail unless t2[0] == :grpent
304
+ t2[1..-1]
305
+ end
306
+ }.map {|mem|
307
+ # p mem
308
+ mem[1] *= occ[0]
309
+ mem[2] *= [occ[1], -1].max
310
+ # p mem
311
+ mem
312
+ }
313
+ else
314
+ [[:member, *occ, nil, t]]
315
+ end
316
+ end
317
+ end
318
+
319
+ def label(n)
320
+ # if this is not a rulename, it's a bareword
321
+ name = n.to_s
322
+ if r = @rules[name]
323
+ r_process(name, r)
324
+ else
325
+ [:string, name]
326
+ end
327
+ end
328
+
329
+ def type_recall(name, canbegroup)
330
+ if r = @rules[name]
331
+ t = r_process(name, r)
332
+ unless t[0] == :type1
333
+ fail "#{name} not a type" unless canbegroup && t[0] == :grpent
334
+ end
335
+ t
336
+ else
337
+ fail "Unknown type #{name}"
338
+ end
339
+ end
340
+
341
+ def group_recall(name)
342
+ if r = @rules[name]
343
+ g = r_process(name, r)
344
+ fail "#{name} not a group" unless g[0] == :grpent
345
+ g[1..-1]
346
+ else
347
+ fail "Unknown group #{name}"
348
+ end
349
+ end
350
+
351
+ BRACE = {"{" => :map, "[" => :array}
352
+
353
+ def type1(n, canbegroup = false)
354
+ # puts "NVALUE #{n.value.inspect}"
355
+ if v = n.value
356
+ value(n)
357
+ elsif v = n.typename
358
+ t = type_recall(v.to_s, canbegroup)
359
+ if t[0] == :type1
360
+ if t.size == 2
361
+ t = t[1]
362
+ else
363
+ t = [:type1, *t[1..-1].flat_map {|t1|
364
+ if t1[0] == :type1
365
+ t1[1..-1]
366
+ else
367
+ [t1]
368
+ end
369
+ }]
370
+
371
+ end
372
+ end # XXX should flatten the thing, too
373
+ t
374
+ else
375
+ case str = n.to_s
376
+ when "#"
377
+ [:prim]
378
+ when /\A#(\d+)/
379
+ maj = $1.to_i
380
+ s = [:prim, maj, *n.children(:uint).map(&:to_s).map(&:to_i)]
381
+ if tagged_type = n.type
382
+ s << type(tagged_type)
383
+ end
384
+ s
385
+ when /\A\(/
386
+ type(n.type)
387
+ when /\A[\[{]/
388
+ s = n.children(:group).flat_map {|ch| group(ch)}
389
+ type = BRACE[str[0]]
390
+ if type == :map
391
+ s.each do |member|
392
+ fail unless member[0] == :member
393
+ fail "map entry without member key given: #{member}" unless member[3]
394
+ end
395
+ end
396
+ [type, *s]
397
+ else
398
+ "unimplemented #{n}"
399
+ end
400
+ end
401
+ end
402
+
403
+ def type(n)
404
+ s = n.children(:type1).map {|ch| type1(ch)}
405
+ if s.size == 1
406
+ s.first
407
+ else
408
+ [:type1, *s]
409
+ end
410
+ end
411
+
412
+ def group(n) # returns array
413
+ n.children(:grpent).flat_map {|ch| grpent(ch)}
414
+ end
415
+
416
+ def occur(n)
417
+ case n.to_s
418
+ when ""
419
+ [1, 1]
420
+ when "+"
421
+ [1, -1]
422
+ when "?"
423
+ [0, 1]
424
+ when /\A(\d*)\*(\d*)\z/
425
+ if (s = $1) == ""
426
+ s = 0
427
+ else
428
+ s = s.to_i
429
+ end
430
+ if (e = $2) == ""
431
+ e = -1
432
+ else
433
+ e = e.to_i
434
+ end
435
+ [s, e]
436
+ else
437
+ fail "huh #{n.to_s}"
438
+ end
439
+ end
440
+
441
+ end
442
+ end
@@ -0,0 +1,17 @@
1
+ reputation-object = {
2
+ application: tstr
3
+ reputons: [* reputon]
4
+ }
5
+
6
+ reputon = {
7
+ rater: tstr
8
+ assertion: tstr
9
+ rated: tstr
10
+ rating: float16
11
+ ? confidence: float16
12
+ ? normal-rating: float16
13
+ ? sample-size: uint
14
+ ? generated: uint
15
+ ? expires: uint
16
+ * any: any
17
+ }
@@ -0,0 +1,42 @@
1
+
2
+
3
+ reputation-object = {
4
+ reputation-context,
5
+ reputon-list
6
+ }
7
+
8
+ reputation-context = (
9
+ application: tstr
10
+ )
11
+
12
+ reputon-list = (
13
+ reputons: reputon-array
14
+ )
15
+
16
+ reputon-array = [* reputon]
17
+
18
+ reputon = {
19
+ rater-value,
20
+ assertion-value,
21
+ rated-value,
22
+ rating-value,
23
+ ? conf-value,
24
+ ? normal-value,
25
+ ? sample-value,
26
+ ? gen-value,
27
+ ? expire-value,
28
+ * ext-value,
29
+ }
30
+
31
+ rater-value = ( rater: tstr )
32
+ assertion-value = ( assertion: tstr )
33
+ rated-value = ( rated: tstr )
34
+ rating-value = ( rating: float16 )
35
+ conf-value = ( confidence: float16 )
36
+ normal-value = ( normal-rating: float16 )
37
+ sample-value = ( sample-size: uint )
38
+ gen-value = ( generated: uint )
39
+ expire-value = ( expires: uint )
40
+ ext-value = ( any: any )
41
+
42
+
@@ -0,0 +1,292 @@
1
+ require 'test/unit'
2
+ require 'pathname'
3
+
4
+ require 'cbor-pretty.rb'
5
+ require 'cbor-diagnostic.rb'
6
+
7
+ require_relative '../lib/cddl'
8
+
9
+
10
+ class TestABNF < Test::Unit::TestCase
11
+
12
+ TEST_DATA_DIR = Pathname.new(__FILE__).split[0] + '../test-data'
13
+
14
+ EXPECTED_RULES = [:type1,
15
+ [:map,
16
+ [:member, 1, 1, [:string, "application"], [:prim, 3]],
17
+ [:member,
18
+ 1,
19
+ 1,
20
+ [:string, "reputons"],
21
+ [:array,
22
+ [:member,
23
+ 0,
24
+ -1,
25
+ nil,
26
+ [:map,
27
+ [:member, 1, 1, [:string, "rater"], [:prim, 3]],
28
+ [:member, 1, 1, [:string, "assertion"], [:prim, 3]],
29
+ [:member, 1, 1, [:string, "rated"], [:prim, 3]],
30
+ [:member, 1, 1, [:string, "rating"], [:prim, 7, 25]],
31
+ [:member, 0, 1, [:string, "confidence"], [:prim, 7, 25]],
32
+ [:member, 0, 1, [:string, "normal-rating"], [:prim, 7, 25]],
33
+ [:member, 0, 1, [:string, "sample-size"], [:prim, 0]],
34
+ [:member, 0, 1, [:string, "generated"], [:prim, 0]],
35
+ [:member, 0, 1, [:string, "expires"], [:prim, 0]],
36
+ [:member, 0, -1, [:type1, [:prim]], [:prim]]]]]]]]
37
+
38
+ def test_aa_rfc7071_concise
39
+ parser1 = CDDL::Parser.new(File.read("#{TEST_DATA_DIR}/7071-concise.cddl"))
40
+ assert_equal EXPECTED_RULES, parser1.rules
41
+ end
42
+
43
+ def test_aa_rfc7071_verbose
44
+ parser2 = CDDL::Parser.new(File.read("#{TEST_DATA_DIR}/7071-verbose.cddl"))
45
+ assert_equal EXPECTED_RULES, parser2.rules
46
+ 3.times do
47
+ # puts CBOR::pretty(CBOR::encode(parser2.generate(EXPECTED_RULES)))
48
+ puts parser2.generate.cbor_diagnostic
49
+ end
50
+ end
51
+
52
+ def test_validate
53
+ parser1 = CDDL::Parser.new(File.read("test-data/7071-concise.cddl"))
54
+ g = parser1.generate
55
+ pp g
56
+ assert parser1.validate(g)
57
+ old = g["application"]
58
+ g["application"] = 4711
59
+ refute parser1.validate(g, false)
60
+ g["application"] = old
61
+ g["reputons"] << 5712
62
+ refute parser1.validate(g, false)
63
+ end
64
+
65
+ def test_validate_1
66
+ parser = CDDL::Parser.new <<HERE
67
+ test = 1
68
+ HERE
69
+ assert parser.validate(1)
70
+ end
71
+
72
+ def test_validate_a
73
+ parser = CDDL::Parser.new <<HERE
74
+ test = [* one: 1]
75
+ HERE
76
+ assert parser.validate([])
77
+ assert parser.validate([1])
78
+ assert parser.validate([1, 1])
79
+ refute parser.validate([1, 2], false)
80
+ refute parser.validate([2, 1], false)
81
+ end
82
+
83
+ def test_validate_a_string
84
+ parser = CDDL::Parser.new <<HERE
85
+ test = [* one: "one"]
86
+ HERE
87
+ assert parser.validate([])
88
+ assert parser.validate(["one"])
89
+ assert parser.validate(["one", "one"])
90
+ refute parser.validate([1], false)
91
+ refute parser.validate(['two'], false)
92
+ refute parser.validate(["one", "two"], false)
93
+ end
94
+
95
+
96
+ def test_validate_a_string_string
97
+ parser = CDDL::Parser.new <<HERE
98
+ test = [* "two": "one"]
99
+ HERE
100
+ assert parser.validate([])
101
+ assert parser.validate(["one"])
102
+ assert parser.validate(["one", "one"])
103
+ refute parser.validate([1], false)
104
+ refute parser.validate(['two'], false)
105
+ refute parser.validate(["one", "two"], false)
106
+ end
107
+
108
+ def test_validate_a_once
109
+ # $debug_ast = true
110
+ parser = CDDL::Parser.new <<HERE
111
+ test = [1]
112
+ HERE
113
+ # puts "RULES:"
114
+ # pp parser.rules
115
+ # puts "APR:"
116
+ # pp parser.apr
117
+ refute parser.validate([], false)
118
+ assert parser.validate([1])
119
+ refute parser.validate([1, 1], false)
120
+ refute parser.validate([1, 2], false)
121
+ refute parser.validate([2, 1], false)
122
+ end
123
+
124
+ def test_validate_unknown_key
125
+ # $debug_ast = true
126
+ parser = CDDL::Parser.new <<HERE
127
+ test = { 1, 2 }
128
+ HERE
129
+ # puts "RULES:"
130
+ assert_raise { # TODO: This really should be checked at parse time
131
+ pp parser.rules
132
+ }
133
+ # puts "APR:"
134
+ # pp parser.apr
135
+ assert_raise { puts parser.generate() }
136
+ assert_raise { parser.validate({}) }
137
+ end
138
+
139
+ def test_validate_not_unknown_key
140
+ # $debug_ast = true
141
+ parser = CDDL::Parser.new <<HERE
142
+ test = [ 1, 2 ]
143
+ HERE
144
+ # puts "RULES:"
145
+ # pp parser.rules
146
+ # puts "APR:"
147
+ # pp parser.apr
148
+ assert_equal [1, 2], parser.generate()
149
+ refute parser.validate({}, false)
150
+ refute parser.validate([], false)
151
+ refute parser.validate([1], false)
152
+ assert parser.validate([1, 2])
153
+ end
154
+
155
+
156
+ def test_validate_not_unknown_key_paren
157
+ # $debug_ast = true
158
+ parser = CDDL::Parser.new <<HERE
159
+ test = [ (1, 2) ]
160
+ HERE
161
+ # puts "RULES:"
162
+ # pp parser.rules
163
+ # puts "APR:"
164
+ # pp parser.apr
165
+ assert_equal [1, 2], parser.generate()
166
+ refute parser.validate({}, false)
167
+ refute parser.validate([], false)
168
+ refute parser.validate([1], false)
169
+ assert parser.validate([1, 2])
170
+ end
171
+
172
+
173
+ def test_validate_alternate3 # XXX need indirection for now
174
+ # $debug_ast = true
175
+ parser = CDDL::Parser.new <<HERE
176
+ test = [* test1]
177
+ test1 = (one: 1, two: 2)
178
+ HERE
179
+ # puts "RULES:"
180
+ # pp parser.rules
181
+ # puts "APR:"
182
+ # pp parser.apr
183
+ assert parser.validate([])
184
+ assert parser.validate([1, 2])
185
+ assert parser.validate([1, 1, 2, 2]) # XXX: This is probably a BUG
186
+ refute parser.validate([1, 2, 1, 2], false) # XXX->assert: major surgery required
187
+ assert parser.validate([1]) # XXX -> refute (rules left)
188
+ refute parser.validate([1, 2, 1], false)
189
+ end
190
+
191
+ def test_validate_occur1 # XXX need indirection for now
192
+ # $debug_ast = true
193
+ parser = CDDL::Parser.new <<HERE
194
+ test = [test1]
195
+ test1 = (one: 1, two: 2)
196
+ HERE
197
+ # puts "RULES:"
198
+ # pp parser.rules
199
+ # puts "APR:"
200
+ # pp parser.apr
201
+ refute parser.validate([], false)
202
+ refute parser.validate([1], false)
203
+ assert parser.validate([1, 2])
204
+ refute parser.validate([2, 1], false)
205
+ refute parser.validate([1, 1, 2, 2], false)
206
+ refute parser.validate([1, 2, 1, 2], false)
207
+ refute parser.validate([1, 2, 1], false)
208
+ end
209
+
210
+ def test_validate_occur01 # XXX need indirection for now
211
+ # $debug_ast = true
212
+ parser = CDDL::Parser.new <<HERE
213
+ test = [? test1]
214
+ test1 = (one: 1, two: 2)
215
+ HERE
216
+ # puts "RULES:"
217
+ # pp parser.rules
218
+ # puts "APR:"
219
+ # pp parser.apr
220
+ assert parser.validate([])
221
+ assert parser.validate([1])
222
+ assert parser.validate([1, 2])
223
+ refute parser.validate([2, 1], false)
224
+ refute parser.validate([1, 1, 2, 2], false)
225
+ refute parser.validate([1, 2, 1, 2], false)
226
+ refute parser.validate([1, 2, 1], false)
227
+ end
228
+
229
+ def test_validate_occur1n # XXX need indirection for now
230
+ # $debug_ast = true
231
+ parser = CDDL::Parser.new <<HERE
232
+ test = [+ test1]
233
+ test1 = (one: 1, two: 2)
234
+ HERE
235
+ # puts "RULES:"
236
+ # pp parser.rules
237
+ # puts "APR:"
238
+ # pp parser.apr
239
+ refute parser.validate([], false)
240
+ refute parser.validate([1], false)
241
+ assert parser.validate([1, 2])
242
+ refute parser.validate([2, 1], false)
243
+ assert parser.validate([1, 1, 2, 2]) # XXX not sequence preserving
244
+ refute parser.validate([1, 2, 1, 2], false)
245
+ refute parser.validate([1, 2, 1], false)
246
+ end
247
+
248
+ def test_validate_occur0n # XXX need indirection for now
249
+ # $debug_ast = true
250
+ parser = CDDL::Parser.new <<HERE
251
+ test = [* test1]
252
+ test1 = (one: 1, two: 2)
253
+ HERE
254
+ # puts "RULES:"
255
+ # pp parser.rules
256
+ # puts "APR:"
257
+ # pp parser.apr
258
+ assert parser.validate([])
259
+ assert parser.validate([1])
260
+ assert parser.validate([1, 2])
261
+ refute parser.validate([2, 1], false)
262
+ assert parser.validate([1, 1, 2, 2]) # XXX not sequence preserving
263
+ refute parser.validate([1, 2, 1, 2], false)
264
+ refute parser.validate([1, 2, 1], false)
265
+ end
266
+
267
+
268
+ def test_validate_occur23 # XXX need indirection for now
269
+ # $debug_ast = true
270
+ parser = CDDL::Parser.new <<HERE
271
+ test = [2*3 test1]
272
+ test1 = (one: 1, two: 2)
273
+ HERE
274
+ # puts "RULES:"
275
+ # pp parser.rules
276
+ # puts "APR:"
277
+ # pp parser.apr
278
+ pp parser.generate
279
+ refute parser.validate([], false)
280
+ refute parser.validate([1], false)
281
+ refute parser.validate([1, 2], false)
282
+ refute parser.validate([2, 1], false)
283
+ assert parser.validate([1, 1, 2, 2]) # XXX not sequence preserving
284
+ assert parser.validate([1, 1, 1, 2, 2]) # XXX not sequence preserving
285
+ assert parser.validate([1, 1, 2, 2, 2]) # XXX not sequence preserving
286
+ assert parser.validate([1, 1, 1, 2, 2, 2]) # XXX not sequence preserving
287
+ refute parser.validate([1, 2, 1, 2], false)
288
+ refute parser.validate([1, 2, 1], false)
289
+ end
290
+
291
+
292
+ end
metadata ADDED
@@ -0,0 +1,95 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cddl
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Carsten Bormann
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-02-28 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: cbor-diag
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: abnc
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: json
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: A parser, generator, and validator for CDDL
56
+ email: cabo@tzi.org
57
+ executables:
58
+ - cddl
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - bin/cddl
63
+ - cddl.gemspec
64
+ - data/cddl.abnf
65
+ - data/prelude.cddl
66
+ - lib/cddl.rb
67
+ - test-data/7071-concise.cddl
68
+ - test-data/7071-verbose.cddl
69
+ - test/test-cddl.rb
70
+ homepage: http://github.com/cabo/cddl
71
+ licenses:
72
+ - MIT
73
+ metadata: {}
74
+ post_install_message:
75
+ rdoc_options: []
76
+ require_paths:
77
+ - lib
78
+ required_ruby_version: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: 1.9.2
83
+ required_rubygems_version: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - ">="
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
88
+ requirements: []
89
+ rubyforge_project:
90
+ rubygems_version: 2.4.5
91
+ signing_key:
92
+ specification_version: 4
93
+ summary: CDDL generator and validator.
94
+ test_files: []
95
+ has_rdoc: