bare-rb 0.1.5 → 0.2.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1e8e36acbdcc47dc92e23a029edf5fac7001fbec9bd4948549cc0e682ea238b0
4
- data.tar.gz: 86ffe342e8f2ec768b6fb222fe3575dd35eda7500ee88cff7111056a8bd422d5
3
+ metadata.gz: bbfb767287130c73249bf016a4bc3b4d9b6bd44e82ce8e7d9e3557ee6c58e7b3
4
+ data.tar.gz: aee2d8ab8457356c7e544dbd31c6f81d05c9655ab3138ddfe7315ab221d16ea0
5
5
  SHA512:
6
- metadata.gz: 555833846daa3aa6337fb836b3a7959d656dd329c3925bceb01ab27d6f873bde95e83bf965daea90f3429c73b8659b40929f6f9e1b138a631c85966910750ee2
7
- data.tar.gz: 0f9b6ef29fd8731c688f8507d6b141e2bb0992b0074b7118cb8b13a9263b57aad9e30becbb990c94d6cc33792abad805a3cd4a44d8deab93ee3847a8de57e68a
6
+ metadata.gz: e1d6c44757bcdd9f6811bf0107e7b13d68703e6616faef2029b09f2273ae75168eff02091f13cddfd6c5e5b9499db5efe2d7cf72d88c3c0e001a0da00b4c602f
7
+ data.tar.gz: e38a97985800775f0aa995db17ad9b8ea6a1294e12f0e0fd5cc60008359d286af6ec173bad63d190436bbd0bea876ff590e0a1fcac6099bd394ce9790bac1798
data/lib/bare-rb.rb CHANGED
@@ -2,66 +2,65 @@ require 'set'
2
2
  require_relative "types"
3
3
  require_relative "lexer"
4
4
  require_relative "parser"
5
+ require_relative 'dfs'
6
+ require_relative 'generative_testing/gen'
7
+ require_relative 'generative_testing/monkey_patch'
5
8
 
6
9
  class Bare
7
- def self.encode(msg, schema, type=nil)
8
- if schema.is_a?(Bare::Schema)
9
- raise NoTypeProvided("To encode with a schema as opposed to a raw type you must specify which type in the schema you want to encode as a symbol.\nBare.encode(msg, schema, :Type)") if type.nil?
10
- schema[type].encode(msg)
10
+ def self.encode(msg, schema, type = nil)
11
+ buffer = "".b
12
+ if schema.is_a?(BareTypes::Schema)
13
+ raise NoTypeProvided.new("To encode with a schema as opposed to a raw type you must specify which type in the schema you want to encode as a symbol.\nBare.encode(msg, schema, :Type)") if type.nil?
14
+ unless schema.types.include?(type)
15
+ raise("#{type} is not a type found in this schema. Choose from #{schema.types.keys}")
16
+ end
17
+ schema[type].encode(msg, buffer)
11
18
  else
12
- schema.encode(msg)
19
+ schema.encode(msg, buffer)
13
20
  end
21
+ buffer
14
22
  end
15
23
 
16
- def self.decode(msg, schema, type=nil)
17
- if schema.is_a?(Bare::Schema)
18
- raise NoTypeProvided("To decode with a schema as opposed to a raw type you must specify which type in the same you want to encode as a symbol.\nBare.encode(msg, schema, :Type)") if type.nil?
19
- value, rest = schema[type].decode(msg)
24
+ def self.decode(msg, schema, type = nil)
25
+ if schema.is_a?(BareTypes::Schema)
26
+ raise NoTypeProvided.new("To decode with a schema as opposed to a raw type you must specify which type in the same you want to encode as a symbol.\nBare.encode(msg, schema, :Type)") if type.nil?
27
+ value, _ = schema[type].decode(msg)
20
28
  value
21
29
  else
22
- value, rest = schema.decode(msg)
23
- return value
30
+ value, _ = schema.decode(msg)
31
+ value
32
+ end
33
+ end
34
+
35
+ # Returns a schema and a binary input
36
+ # optionally write these to files
37
+ def self.generative_test(schema_path=nil, binary_path=nil)
38
+ schema = BareTypes::Schema.make
39
+ input = schema.create_input
40
+ key = schema.types.keys[0]
41
+ binary = Bare.encode(input[key], schema, key)
42
+ unless binary_path.nil?
43
+ file = File.open(binary_path, 'wb+')
44
+ file.write(binary)
45
+ file.close
24
46
  end
47
+ unless schema_path.nil?
48
+ file = File.open(schema_path, 'w+')
49
+ file.write(schema.to_s)
50
+ file.close
51
+ end
52
+ return schema, binary, key
25
53
  end
26
54
 
27
55
  def self.parse_schema(path)
28
- # Hash of class names to BARE ASTs
56
+ # Hash of class names to BARE types
29
57
  # Eg. types['Customer'] == Bare.i32
30
- types = parser(lexer(path))
31
- Bare.Schema(types)
58
+ parsed = parser(lexer(path))
59
+ Bare.Schema(parsed)
32
60
  end
33
61
 
34
62
  def self.Schema(hash)
35
- Bare::Schema.new(hash)
36
- end
37
-
38
- class Schema
39
- def ==(otherSchema)
40
- return false unless otherSchema.is_a?(Bare::Schema)
41
- @types == otherSchema.types
42
- end
43
-
44
- def types
45
- @types
46
- end
47
-
48
- def [](key)
49
- return @types[key]
50
- end
51
-
52
- def initialize(types)
53
- @types = types
54
- @types.keys.each do |key|
55
- if @types[key].is_a?(Symbol)
56
- @types[key] = @types[@types[key]]
57
- else
58
- # Users may use symbols to reference not yet defined types
59
- # here we recursively call our bare classes to finalize their types
60
- # replacing Symbols like :SomeType with a reference to the other type
61
- @types[key].finalize_references(@types)
62
- end
63
- end
64
- end
63
+ BareTypes::Schema.new(hash)
65
64
  end
66
65
 
67
66
  # These classes are wrapped in methods for ergonomics.
@@ -162,7 +161,4 @@ class Bare
162
161
  def self.Enum(*opts)
163
162
  return BareTypes::Enum.new(*opts)
164
163
  end
165
-
166
-
167
164
  end
168
-
data/lib/exceptions.rb CHANGED
@@ -5,6 +5,24 @@ class BareException < StandardError
5
5
  end
6
6
  end
7
7
 
8
+ class InvalidBool < BareException
9
+ def initialize(msg = nil)
10
+ super
11
+ end
12
+ end
13
+
14
+ class CircularSchema < BareException
15
+ def initialize(msg = nil)
16
+ super
17
+ end
18
+ end
19
+
20
+ class ReferenceException < BareException
21
+ def initialize(msg=nil)
22
+ super
23
+ end
24
+ end
25
+
8
26
  class FixedDataSizeWrong < BareException
9
27
  def initialize(msg=nil)
10
28
  super
@@ -0,0 +1,26 @@
1
+ require_relative '../bare-rb'
2
+ require_relative './monkey_patch'
3
+ require_relative './grammar_util'
4
+
5
+ def get_type(depth, names = [], can_be_symbol = true)
6
+ if names.size == 0
7
+ can_be_symbol = false
8
+ end
9
+ terminators = [BareTypes::Data, BareTypes::DataFixedLen,
10
+ BareTypes::U8, BareTypes::U16, BareTypes::U32, BareTypes::U64,
11
+ BareTypes::I8, BareTypes::I16, BareTypes::I32, BareTypes::I64,
12
+ BareTypes::F32, BareTypes::F64]
13
+ aggregates = [BareTypes::Array, BareTypes::ArrayFixedLen,
14
+ BareTypes::Struct]
15
+
16
+ all = terminators + aggregates
17
+
18
+ # 1/5 changes of a reference
19
+ if rand(5) == 0 && names.size != 1 && can_be_symbol
20
+ names[rand(names.size)]
21
+ elsif depth >= 10 # if depth >= 10 only use terminating types
22
+ all[rand(terminators.size)].make(depth + 1, names)
23
+ else
24
+ all[rand(all.size)].make(depth + 1, names)
25
+ end
26
+ end
@@ -0,0 +1,22 @@
1
+ def create_user_type_name
2
+ upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
3
+ lower = upper.downcase
4
+ digit = "0123456789"
5
+
6
+ name = upper[rand(upper.size)]
7
+ loop do
8
+ if rand(50) < 5
9
+ break
10
+ end
11
+ num = rand(3)
12
+ if num == 0
13
+ name << upper[rand(upper.size)]
14
+ elsif num == 1
15
+ name << lower[rand(lower.size)]
16
+ else
17
+ name << digit[rand(digit.size)]
18
+ end
19
+ end
20
+ name.to_sym
21
+ end
22
+
@@ -0,0 +1,262 @@
1
+ require_relative '../bare-rb'
2
+ require_relative './grammar_util'
3
+
4
+ # 10MB max data size
5
+ DATA_MAX_SIZE = 30000
6
+ ARRAY_MAX_SIZE = 40
7
+ STRUCT_FIELDS_MAX = 5
8
+
9
+ # Monkey patch every bare class to include make and create_input
10
+ # make - a factory to create a random variant of the bare class
11
+ # create_input - creates an input that could be used with Bare.Encode for this type
12
+
13
+ class BareTypes::Reference
14
+ def create_input
15
+ self.ref.create_input
16
+ end
17
+
18
+ def self.make(depth, names)
19
+ self.ref.make(depth, names)
20
+ end
21
+ end
22
+
23
+ # region Integers
24
+ class BareTypes::U8
25
+ def self.make(depth, names)
26
+ BareTypes::U8.new
27
+ end
28
+
29
+ def create_input
30
+ rand(256)
31
+ end
32
+ end
33
+
34
+ class BareTypes::U16
35
+ def self.make(depth, names)
36
+ BareTypes::U16.new
37
+ end
38
+
39
+ def create_input
40
+ rand(2 ** 16)
41
+ end
42
+ end
43
+
44
+ class BareTypes::U32
45
+ def self.make(depth, names)
46
+ BareTypes::U32.new
47
+ end
48
+
49
+ def create_input
50
+ rand(2 ** 32)
51
+ end
52
+ end
53
+
54
+ class BareTypes::U64
55
+ def self.make(depth, names)
56
+ BareTypes::U64.new
57
+ end
58
+
59
+ def create_input
60
+ rand(2 ** 64)
61
+ end
62
+ end
63
+
64
+ class BareTypes::I8
65
+ def self.make(depth, names)
66
+ BareTypes::I8.new
67
+ end
68
+
69
+ def create_input
70
+ rand(2 ** 8) - (2 ** 7)
71
+ end
72
+ end
73
+
74
+ class BareTypes::I16
75
+ def self.make(depth, names)
76
+ BareTypes::I16.new
77
+ end
78
+
79
+ def create_input
80
+ rand(2 ** 16) - (2 ** 15)
81
+ end
82
+ end
83
+
84
+ class BareTypes::I32
85
+ def self.make(depth, names)
86
+ BareTypes::I32.new
87
+ end
88
+
89
+ def create_input
90
+ rand(2 ** 32) - (2 ** 31)
91
+ end
92
+ end
93
+
94
+ class BareTypes::I64
95
+ def self.make(depth, names)
96
+ BareTypes::I64.new
97
+ end
98
+
99
+ def create_input
100
+ rand(2 ** 64) - (2 ** 63)
101
+ end
102
+ end
103
+
104
+ # endregion
105
+
106
+ #region Floats
107
+ class BareTypes::F32
108
+ def self.make(depth, names)
109
+ self.new
110
+ end
111
+
112
+ def create_input
113
+ float = nil
114
+ loop do
115
+ input = [rand(266), rand(266), rand(266), rand(266)]
116
+ float = input.pack("cccc").unpack('e')
117
+ if float[0] == float[0] && !float[0].nan?
118
+ break
119
+ end
120
+ end
121
+ float[0]
122
+ end
123
+ end
124
+
125
+ class BareTypes::F64
126
+ def self.make(depth, names)
127
+ self.new
128
+ end
129
+
130
+ def create_input
131
+ float = nil
132
+ loop do
133
+ input = [rand(266), rand(266), rand(266), rand(266), rand(266), rand(266), rand(266), rand(266)]
134
+ float = input.pack("cccccccc").unpack('E')
135
+ if float[0] == float[0] && !float[0].nan?
136
+ break
137
+ end
138
+ end
139
+ float[0]
140
+ end
141
+ end
142
+
143
+ #endregion
144
+
145
+ #region Data
146
+ class BareTypes::DataFixedLen
147
+ def self.make(depth, names)
148
+ length = rand(max = DATA_MAX_SIZE) + 1
149
+ self.new(length)
150
+ end
151
+
152
+ def create_input
153
+ # 100 random bytes
154
+ arr = []
155
+ 0.upto(length - 1).each do |i|
156
+ arr << i % 256
157
+ end
158
+ arr.pack('c*')
159
+ end
160
+ end
161
+
162
+ class BareTypes::Data
163
+ def self.make(depth, names)
164
+ self.new
165
+ end
166
+
167
+ def create_input
168
+ arr = []
169
+ 0.upto(rand(DATA_MAX_SIZE)).each do |i|
170
+ arr << i % 256
171
+ end
172
+ arr.pack('c*')
173
+ end
174
+ end
175
+
176
+ #endregion
177
+
178
+ #region Array
179
+ class BareTypes::Array
180
+ def self.make(depth, names)
181
+ BareTypes::Array.new(get_type(depth + 1, names))
182
+ end
183
+
184
+ def create_input
185
+ count = rand(ARRAY_MAX_SIZE) + 1
186
+ arr = []
187
+ 0.upto(count) do
188
+ arr << @type.create_input
189
+ end
190
+ arr
191
+ end
192
+ end
193
+
194
+ class BareTypes::ArrayFixedLen
195
+ def self.make(depth, names)
196
+ self.new(get_type(depth + 1, names,), rand(ARRAY_MAX_SIZE) + 1)
197
+ end
198
+
199
+ def create_input
200
+ arr = []
201
+ 0.upto(@size - 1) do
202
+ arr << @type.create_input
203
+ end
204
+ arr
205
+ end
206
+ end
207
+
208
+ #endregion
209
+
210
+ #region Agg Types
211
+
212
+ class BareTypes::Struct
213
+ def self.make(depth, names)
214
+ hash = {}
215
+ 0.upto(rand(STRUCT_FIELDS_MAX) + 1) do
216
+ hash[create_user_type_name.to_sym] = get_type(depth + 1, names)
217
+ end
218
+ self.new(hash)
219
+ end
220
+
221
+ def create_input
222
+ input = {}
223
+ @mapping.keys.each do |name|
224
+ input[name] = @mapping[name].create_input
225
+ end
226
+ input
227
+ end
228
+ end
229
+
230
+ # endregion
231
+
232
+ class BareTypes::Schema
233
+ def create_input
234
+ input = {}
235
+ @types.each do |key, type|
236
+ input[key] = type.create_input
237
+ end
238
+ input
239
+ end
240
+
241
+ def self.make
242
+ schema = nil
243
+ loop do
244
+ names = []
245
+ schema = {}
246
+ 0.upto(rand(10)+1) do
247
+ names << create_user_type_name.to_sym
248
+ end
249
+ names.each do |name|
250
+ without_this_name = names.select { |n| n != name }
251
+ schema[name] = get_type(0, without_this_name, false)
252
+ end
253
+ begin
254
+ schema = Bare.Schema(schema)
255
+ rescue CircularSchema
256
+ next
257
+ end
258
+ break
259
+ end
260
+ schema
261
+ end
262
+ end
data/lib/lexer.rb CHANGED
@@ -3,7 +3,8 @@ require_relative './exceptions'
3
3
  def lexer(path)
4
4
  tokens = []
5
5
  line_num = 0
6
- File.open(path).each do |line|
6
+ file = File.open(path)
7
+ file.each do |line|
7
8
  while line.size > 0
8
9
  if /^#/.match(line)
9
10
  break
@@ -46,7 +47,7 @@ def lexer(path)
46
47
  tokens << match[0].to_i
47
48
  line = line[(match[0].size)..line.size]
48
49
  next
49
- elsif match = /^[a-z,A-Z,_][_,a-z,A-Z,0-9]+/.match(line)
50
+ elsif match = /^[a-z,A-Z,_][_,a-z,A-Z,0-9]*/.match(line)
50
51
  tokens << match[0]
51
52
  line = line[(match[0].size)..line.size]
52
53
  elsif /:/.match(line)
data/lib/parser.rb CHANGED
@@ -132,7 +132,7 @@ class Parser
132
132
  type = @primitives[tokens[0]]
133
133
  return tokens[1..tokens.size], type
134
134
  elsif @definitions.keys.include?(tokens[0].to_sym) # User defined type
135
- return tokens[1..tokens.size], @definitions[tokens[0].to_sym]
135
+ return tokens[1..tokens.size], tokens[0].to_sym
136
136
  elsif tokens[0].is_a?(String) && tokens[0][0].upcase == tokens[0][0] # Not yet defined user type
137
137
  return tokens[1..tokens.size], tokens[0].to_sym
138
138
  else