1 |
|
2 |
|
3 | var C = require('claire');
|
4 |
|
5 | var forAll = C.forAll;
|
6 | var arb = C.data;
|
7 | var transform = C.transform;
|
8 | var repeat = C.repeat;
|
9 | var label = C.label;
|
10 | var sequence = C.sequence;
|
11 | var asGenerator = C.asGenerator;
|
12 | var sized = C.sized;
|
13 | var recursive = C.recursive;
|
14 |
|
15 |
|
16 |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 | function choose(a, b) {
|
22 | return Math.random() * (b - a) + a;
|
23 | }
|
24 |
|
25 | function chooseInt(a, b) {
|
26 | return Math.floor(choose(a, b));
|
27 | }
|
28 |
|
29 | function rangeInt(name, a, b) {
|
30 | return label(name,
|
31 | asGenerator(function(_) { return chooseInt(a, b); }));
|
32 | }
|
33 |
|
34 | function toFloat32(i) {
|
35 | var b = new Buffer(4);
|
36 | b.writeFloatBE(i, 0);
|
37 | return b.readFloatBE(0);
|
38 | }
|
39 |
|
40 | function floatChooser(maxExp) {
|
41 | return function() {
|
42 | var n = Number.NaN;
|
43 | while (isNaN(n)) {
|
44 | var mantissa = Math.random() * 2 - 1;
|
45 | var exponent = chooseInt(0, maxExp);
|
46 | n = Math.pow(mantissa, exponent);
|
47 | }
|
48 | return n;
|
49 | }
|
50 | }
|
51 |
|
52 |
|
53 |
|
54 | var Octet = rangeInt('octet', 0, 255);
|
55 | var ShortStr = label('shortstr',
|
56 | transform(function(s) {
|
57 | return s.substr(0, 255);
|
58 | }, arb.Str));
|
59 |
|
60 | var LongStr = label('longstr',
|
61 | transform(
|
62 | function(bytes) { return new Buffer(bytes); },
|
63 | repeat(Octet)));
|
64 |
|
65 | var UShort = rangeInt('short-uint', 0, 0xffff);
|
66 | var ULong = rangeInt('long-uint', 0, 0xffffffff);
|
67 | var ULongLong = rangeInt('longlong-uint', 0, 0xffffffffffffffff);
|
68 | var Short = rangeInt('short-int', -0x8000, 0x7fff);
|
69 | var Long = rangeInt('long-int', -0x80000000, 0x7fffffff);
|
70 | var LongLong = rangeInt('longlong-int', -0x8000000000000000,
|
71 | 0x7fffffffffffffff);
|
72 | var Bit = label('bit', arb.Bool);
|
73 | var Double = label('double', asGenerator(floatChooser(308)));
|
74 | var Float = label('float', transform(toFloat32, floatChooser(38)));
|
75 | var Timestamp = label('timestamp', transform(
|
76 | function(n) {
|
77 | return {'!': 'timestamp', value: n};
|
78 | }, ULongLong));
|
79 | var Decimal = label('decimal', transform(
|
80 | function(args) {
|
81 | return {'!': 'decimal', value: {places: args[1], digits: args[0]}};
|
82 | }, sequence(arb.UInt, Octet)));
|
83 |
|
84 | var FieldArray = label('field-array', recursive(function() {
|
85 | return arb.Array(
|
86 |
|
87 | LongStr, ShortStr, Octet,
|
88 | UShort, ULong, ULongLong,
|
89 | Short, Long, LongLong,
|
90 | Bit, Float, Double, FieldTable)
|
91 | }));
|
92 |
|
93 | var FieldTable = label('table', recursive(function() {
|
94 | return sized(function() { return 5; },
|
95 | arb.Object(
|
96 |
|
97 | LongStr, ShortStr, Octet,
|
98 | UShort, ULong, ULongLong,
|
99 | Short, Long, LongLong,
|
100 | Bit, Float, Double, FieldArray))
|
101 | }));
|
102 |
|
103 |
|
104 | domainProps = [
|
105 | [Octet, function(n) { return n >= 0 && n < 256; }],
|
106 | [ShortStr, function(s) { return typeof s === 'string' && s.length < 256; }],
|
107 | [LongStr, function(s) { return Buffer.isBuffer(s); }],
|
108 | [UShort, function(n) { return n >= 0 && n <= 0xffff; }],
|
109 | [ULong, function(n) { return n >= 0 && n <= 0xffffffff; }],
|
110 | [ULongLong, function(n) {
|
111 | return n >= 0 && n <= 0xffffffffffffffff; }],
|
112 | [Short, function(n) { return n >= -0x8000 && n <= 0x8000; }],
|
113 | [Long, function(n) { return n >= -0x80000000 && n < 0x80000000; }],
|
114 | [LongLong, function(n) { return n >= -0x8000000000000000 && n < 0x8000000000000000; }],
|
115 | [Bit, function(b) { return typeof b === 'boolean'; }],
|
116 | [Double, function(f) { return !isNaN(f) && isFinite(f); }],
|
117 | [Float, function(f) { return !isNaN(f) && isFinite(f) && (Math.log(Math.abs(f)) * Math.LOG10E) < 309; }],
|
118 | [Decimal, function(d) {
|
119 | return d['!'] === 'decimal' &&
|
120 | d.value['places'] <= 255 &&
|
121 | d.value['digits'] <= 0xffffffff;
|
122 | }],
|
123 | [Timestamp, function(t) { return t['!'] === 'timestamp'; }],
|
124 | [FieldTable, function(t) { return typeof t === 'object'; }],
|
125 | [FieldArray, function(a) { return Array.isArray(a); }]
|
126 | ];
|
127 |
|
128 | suite("Domains", function() {
|
129 | domainProps.forEach(function(p) {
|
130 | test(p[0] + ' domain',
|
131 | forAll(p[0]).satisfy(p[1]).asTest({times: 500}));
|
132 | });
|
133 | });
|
134 |
|
135 |
|
136 |
|
137 | var ArgTimestamp = label('timestamp', ULongLong);
|
138 |
|
139 |
|
140 | ARG_TYPES = {
|
141 | 'octet': Octet,
|
142 | 'shortstr': ShortStr,
|
143 | 'longstr': LongStr,
|
144 | 'short': UShort,
|
145 | 'long': ULong,
|
146 | 'longlong': ULongLong,
|
147 | 'bit': Bit,
|
148 | 'table': FieldTable,
|
149 | 'timestamp': ArgTimestamp
|
150 | };
|
151 |
|
152 | function argtype(thing) {
|
153 | return ARG_TYPES[thing.type];
|
154 | }
|
155 |
|
156 | function zipObject(vals, names) {
|
157 | var obj = {};
|
158 | vals.forEach(function(v, i) { obj[names[i]] = v; });
|
159 | return obj;
|
160 | }
|
161 |
|
162 | function name(arg) { return arg.name; }
|
163 |
|
164 | var defs = require('../lib/defs');
|
165 |
|
166 | function method(info) {
|
167 | var domain = sequence.apply(null, info.args.map(argtype));
|
168 | var names = info.args.map(name);
|
169 | return label(info.name, transform(function(fieldVals) {
|
170 | return {id: info.id,
|
171 | fields: zipObject(fieldVals, names)};
|
172 | }, domain));
|
173 | }
|
174 |
|
175 | function properties(info) {
|
176 | var types = info.args.map(argtype);
|
177 | types.unshift(ULongLong);
|
178 | var domain = sequence.apply(null, types);
|
179 | var names = info.args.map(name);
|
180 | return label(info.name, transform(function(fieldVals) {
|
181 | return {id: info.id,
|
182 | size: fieldVals[0],
|
183 | fields: zipObject(fieldVals.slice(1), names)};
|
184 | }, domain));
|
185 | }
|
186 |
|
187 | var methods = [];
|
188 | var propertieses = [];
|
189 |
|
190 | for (var k in defs) {
|
191 | if (k.substr(0, 10) === 'methodInfo') {
|
192 | methods.push(method(defs[k]));
|
193 | }
|
194 | else if (k.substr(0, 14) === 'propertiesInfo') {
|
195 | propertieses.push(properties(defs[k]));
|
196 | }
|
197 | };
|
198 |
|
199 | module.exports = {
|
200 | Octet: Octet,
|
201 | ShortStr: ShortStr,
|
202 | LongStr: LongStr,
|
203 | UShort: UShort,
|
204 | ULong: ULong,
|
205 | ULongLong: ULongLong,
|
206 | Short: Short,
|
207 | Long: Long,
|
208 | LongLong: LongLong,
|
209 | Bit: Bit,
|
210 | Double: Double,
|
211 | Float: Float,
|
212 | Timestamp: Timestamp,
|
213 | Decimal: Decimal,
|
214 | FieldArray: FieldArray,
|
215 | FieldTable: FieldTable,
|
216 |
|
217 | methods: methods,
|
218 | properties: propertieses
|
219 | };
|