UNPKG

6.32 kBJavaScriptView Raw
1// Property-based testing representations of various things in AMQP
2
3var C = require('claire');
4
5var forAll = C.forAll;
6var arb = C.data;
7var transform = C.transform;
8var repeat = C.repeat;
9var label = C.label;
10var sequence = C.sequence;
11var asGenerator = C.asGenerator;
12var sized = C.sized;
13var recursive = C.recursive;
14
15// Stub these out so we can use outside tests
16// if (!suite) var suite = function() {}
17// if (!test) var test = function() {}
18
19// These aren't exported in claire/index. so I could have to reproduce
20// them I guess.
21function choose(a, b) {
22 return Math.random() * (b - a) + a;
23}
24
25function chooseInt(a, b) {
26 return Math.floor(choose(a, b));
27}
28
29function rangeInt(name, a, b) {
30 return label(name,
31 asGenerator(function(_) { return chooseInt(a, b); }));
32}
33
34function toFloat32(i) {
35 var b = new Buffer(4);
36 b.writeFloatBE(i, 0);
37 return b.readFloatBE(0);
38}
39
40function 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// FIXME null, byte array, others?
53
54var Octet = rangeInt('octet', 0, 255);
55var ShortStr = label('shortstr',
56 transform(function(s) {
57 return s.substr(0, 255);
58 }, arb.Str));
59
60var LongStr = label('longstr',
61 transform(
62 function(bytes) { return new Buffer(bytes); },
63 repeat(Octet)));
64
65var UShort = rangeInt('short-uint', 0, 0xffff);
66var ULong = rangeInt('long-uint', 0, 0xffffffff);
67var ULongLong = rangeInt('longlong-uint', 0, 0xffffffffffffffff);
68var Short = rangeInt('short-int', -0x8000, 0x7fff);
69var Long = rangeInt('long-int', -0x80000000, 0x7fffffff);
70var LongLong = rangeInt('longlong-int', -0x8000000000000000,
71 0x7fffffffffffffff);
72var Bit = label('bit', arb.Bool);
73var Double = label('double', asGenerator(floatChooser(308)));
74var Float = label('float', transform(toFloat32, floatChooser(38)));
75var Timestamp = label('timestamp', transform(
76 function(n) {
77 return {'!': 'timestamp', value: n};
78 }, ULongLong));
79var Decimal = label('decimal', transform(
80 function(args) {
81 return {'!': 'decimal', value: {places: args[1], digits: args[0]}};
82 }, sequence(arb.UInt, Octet)));
83
84var FieldArray = label('field-array', recursive(function() {
85 return arb.Array(
86 // arb.Nothing,
87 LongStr, ShortStr, Octet,
88 UShort, ULong, ULongLong,
89 Short, Long, LongLong,
90 Bit, Float, Double, FieldTable)
91}));
92
93var FieldTable = label('table', recursive(function() {
94 return sized(function() { return 5; },
95 arb.Object(
96 // arb.Nothing,
97 LongStr, ShortStr, Octet,
98 UShort, ULong, ULongLong,
99 Short, Long, LongLong,
100 Bit, Float, Double, FieldArray))
101}));
102
103// Internal tests of our properties
104domainProps = [
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
128suite("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// For methods and properties (as opposed to field table values) it's
136// easier just to accept and produce numbers for timestamps.
137var ArgTimestamp = label('timestamp', ULongLong);
138
139// These are the domains used in method arguments
140ARG_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
152function argtype(thing) {
153 return ARG_TYPES[thing.type];
154}
155
156function zipObject(vals, names) {
157 var obj = {};
158 vals.forEach(function(v, i) { obj[names[i]] = v; });
159 return obj;
160}
161
162function name(arg) { return arg.name; }
163
164var defs = require('../lib/defs');
165
166function 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
175function properties(info) {
176 var types = info.args.map(argtype);
177 types.unshift(ULongLong); // size
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
187var methods = [];
188var propertieses = [];
189
190for (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
199module.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};