node-osc 9.1.7 → 11.0.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.
- package/.github/workflows/bump-version.yml +1 -1
- package/.github/workflows/create-release.yml +4 -4
- package/.github/workflows/nodejs.yml +1 -1
- package/dist/lib/Bundle.js +1 -0
- package/dist/lib/Client.js +3 -5
- package/dist/lib/internal/decode.js +3 -3
- package/dist/lib/internal/osc.js +329 -0
- package/dist/test/test-decode.js +77 -0
- package/dist/test/test-osc-internal.js +498 -0
- package/examples/esm.mjs +2 -2
- package/examples/server.js +2 -2
- package/lib/Bundle.mjs +1 -0
- package/lib/Client.mjs +1 -3
- package/lib/internal/decode.mjs +3 -3
- package/lib/internal/osc.mjs +324 -0
- package/package.json +10 -9
- package/rollup.config.mjs +0 -2
- package/test/test-decode.mjs +77 -0
- package/test/test-osc-internal.mjs +496 -0
|
@@ -21,15 +21,15 @@ jobs:
|
|
|
21
21
|
- name: Setup node
|
|
22
22
|
uses: actions/setup-node@v4
|
|
23
23
|
with:
|
|
24
|
-
node-version:
|
|
24
|
+
node-version: 22
|
|
25
25
|
registry-url: 'https://registry.npmjs.org'
|
|
26
26
|
cache: npm
|
|
27
|
-
- name: Install
|
|
28
|
-
run:
|
|
27
|
+
- name: Install latest npm
|
|
28
|
+
run: npm i -g npm
|
|
29
29
|
- name: Install dependencies and build
|
|
30
30
|
run: npm ci
|
|
31
31
|
- name: Publish package
|
|
32
|
-
run: npm publish
|
|
32
|
+
run: npm publish
|
|
33
33
|
|
|
34
34
|
create-github-release:
|
|
35
35
|
name: Create GitHub Release
|
package/dist/lib/Bundle.js
CHANGED
package/dist/lib/Client.js
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var node_dgram = require('node:dgram');
|
|
4
|
-
var
|
|
4
|
+
var _osc = require('#osc');
|
|
5
5
|
var Message = require('./Message.js');
|
|
6
6
|
|
|
7
|
-
const { toBuffer } = oscMin;
|
|
8
|
-
|
|
9
7
|
class Client {
|
|
10
8
|
constructor(host, port) {
|
|
11
9
|
this.host = host;
|
|
@@ -40,7 +38,7 @@ class Client {
|
|
|
40
38
|
try {
|
|
41
39
|
switch (typeof message) {
|
|
42
40
|
case 'object':
|
|
43
|
-
buf = toBuffer(message);
|
|
41
|
+
buf = _osc.toBuffer(message);
|
|
44
42
|
this._sock.send(buf, 0, buf.length, this.port, this.host, callback);
|
|
45
43
|
break;
|
|
46
44
|
case 'string':
|
|
@@ -48,7 +46,7 @@ class Client {
|
|
|
48
46
|
for (let i = 1; i < args.length; i++) {
|
|
49
47
|
mes.append(args[i]);
|
|
50
48
|
}
|
|
51
|
-
buf = toBuffer(mes);
|
|
49
|
+
buf = _osc.toBuffer(mes);
|
|
52
50
|
this._sock.send(buf, 0, buf.length, this.port, this.host, callback);
|
|
53
51
|
break;
|
|
54
52
|
default:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var _osc = require('#osc');
|
|
4
4
|
|
|
5
5
|
function sanitizeMessage(decoded) {
|
|
6
6
|
const message = [];
|
|
@@ -19,8 +19,8 @@ function sanitizeBundle(decoded) {
|
|
|
19
19
|
return decoded;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
function decode(data) {
|
|
23
|
-
const decoded =
|
|
22
|
+
function decode(data, customFromBuffer = _osc.fromBuffer) {
|
|
23
|
+
const decoded = customFromBuffer(data);
|
|
24
24
|
if (decoded.oscType === 'bundle') {
|
|
25
25
|
return sanitizeBundle(decoded);
|
|
26
26
|
}
|
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// OSC 1.0 Protocol Implementation
|
|
4
|
+
// Based on http://opensoundcontrol.org/spec-1_0
|
|
5
|
+
|
|
6
|
+
// Helper functions for OSC encoding/decoding
|
|
7
|
+
|
|
8
|
+
function padString(str) {
|
|
9
|
+
const nullTerminated = str + '\0';
|
|
10
|
+
const padding = 4 - (nullTerminated.length % 4);
|
|
11
|
+
return nullTerminated + '\0'.repeat(padding === 4 ? 0 : padding);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function readString(buffer, offset) {
|
|
15
|
+
let end = offset;
|
|
16
|
+
while (end < buffer.length && buffer[end] !== 0) {
|
|
17
|
+
end++;
|
|
18
|
+
}
|
|
19
|
+
const str = buffer.subarray(offset, end).toString('utf8');
|
|
20
|
+
// Find next 4-byte boundary
|
|
21
|
+
const paddedLength = Math.ceil((end - offset + 1) / 4) * 4;
|
|
22
|
+
return { value: str, offset: offset + paddedLength };
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function writeInt32(value) {
|
|
26
|
+
const buffer = Buffer.alloc(4);
|
|
27
|
+
buffer.writeInt32BE(value, 0);
|
|
28
|
+
return buffer;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function readInt32(buffer, offset) {
|
|
32
|
+
const value = buffer.readInt32BE(offset);
|
|
33
|
+
return { value, offset: offset + 4 };
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function writeFloat32(value) {
|
|
37
|
+
const buffer = Buffer.alloc(4);
|
|
38
|
+
buffer.writeFloatBE(value, 0);
|
|
39
|
+
return buffer;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function readFloat32(buffer, offset) {
|
|
43
|
+
const value = buffer.readFloatBE(offset);
|
|
44
|
+
return { value, offset: offset + 4 };
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function writeBlob(value) {
|
|
48
|
+
const length = value.length;
|
|
49
|
+
const lengthBuffer = writeInt32(length);
|
|
50
|
+
const padding = 4 - (length % 4);
|
|
51
|
+
const paddingBuffer = Buffer.alloc(padding === 4 ? 0 : padding);
|
|
52
|
+
return Buffer.concat([lengthBuffer, value, paddingBuffer]);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function readBlob(buffer, offset) {
|
|
56
|
+
const lengthResult = readInt32(buffer, offset);
|
|
57
|
+
const length = lengthResult.value;
|
|
58
|
+
const data = buffer.subarray(lengthResult.offset, lengthResult.offset + length);
|
|
59
|
+
const padding = 4 - (length % 4);
|
|
60
|
+
const nextOffset = lengthResult.offset + length + (padding === 4 ? 0 : padding);
|
|
61
|
+
return { value: data, offset: nextOffset };
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function writeTimeTag(value) {
|
|
65
|
+
// For now, treat timetag as a double (8 bytes)
|
|
66
|
+
// OSC timetag is 64-bit: 32-bit seconds since 1900, 32-bit fractional
|
|
67
|
+
const buffer = Buffer.alloc(8);
|
|
68
|
+
if (typeof value === 'number') {
|
|
69
|
+
// Convert to OSC timetag format
|
|
70
|
+
const seconds = Math.floor(value);
|
|
71
|
+
const fraction = Math.floor((value - seconds) * 0x100000000);
|
|
72
|
+
buffer.writeUInt32BE(seconds + 2208988800, 0); // Add epoch offset (1900 vs 1970)
|
|
73
|
+
buffer.writeUInt32BE(fraction, 4);
|
|
74
|
+
} else {
|
|
75
|
+
// If not a number, write zeros (immediate execution)
|
|
76
|
+
buffer.writeUInt32BE(0, 0);
|
|
77
|
+
buffer.writeUInt32BE(1, 4);
|
|
78
|
+
}
|
|
79
|
+
return buffer;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function readTimeTag(buffer, offset) {
|
|
83
|
+
const seconds = buffer.readUInt32BE(offset);
|
|
84
|
+
const fraction = buffer.readUInt32BE(offset + 4);
|
|
85
|
+
|
|
86
|
+
let value;
|
|
87
|
+
if (seconds === 0 && fraction === 1) {
|
|
88
|
+
// Immediate execution
|
|
89
|
+
value = 0;
|
|
90
|
+
} else {
|
|
91
|
+
// Convert from OSC epoch (1900) to Unix epoch (1970)
|
|
92
|
+
const unixSeconds = seconds - 2208988800;
|
|
93
|
+
const fractionalSeconds = fraction / 0x100000000;
|
|
94
|
+
value = unixSeconds + fractionalSeconds;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return { value, offset: offset + 8 };
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function writeMidi(value) {
|
|
101
|
+
// MIDI message is 4 bytes: port id, status byte, data1, data2
|
|
102
|
+
const buffer = Buffer.alloc(4);
|
|
103
|
+
|
|
104
|
+
if (Buffer.isBuffer(value)) {
|
|
105
|
+
if (value.length !== 4) {
|
|
106
|
+
throw new Error('MIDI message must be exactly 4 bytes');
|
|
107
|
+
}
|
|
108
|
+
value.copy(buffer);
|
|
109
|
+
} else if (typeof value === 'object' && value !== null) {
|
|
110
|
+
// Allow object format: { port: 0, status: 144, data1: 60, data2: 127 }
|
|
111
|
+
buffer.writeUInt8(value.port || 0, 0);
|
|
112
|
+
buffer.writeUInt8(value.status || 0, 1);
|
|
113
|
+
buffer.writeUInt8(value.data1 || 0, 2);
|
|
114
|
+
buffer.writeUInt8(value.data2 || 0, 3);
|
|
115
|
+
} else {
|
|
116
|
+
throw new Error('MIDI value must be a 4-byte Buffer or object with port, status, data1, data2 properties');
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return buffer;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function readMidi(buffer, offset) {
|
|
123
|
+
if (offset + 4 > buffer.length) {
|
|
124
|
+
throw new Error('Not enough bytes for MIDI message');
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const value = buffer.subarray(offset, offset + 4);
|
|
128
|
+
return { value, offset: offset + 4 };
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function encodeArgument(arg) {
|
|
132
|
+
if (typeof arg === 'object' && arg.type && arg.value !== undefined) {
|
|
133
|
+
// Explicit type specification
|
|
134
|
+
switch (arg.type) {
|
|
135
|
+
case 'i':
|
|
136
|
+
case 'integer':
|
|
137
|
+
return { tag: 'i', data: writeInt32(arg.value) };
|
|
138
|
+
case 'f':
|
|
139
|
+
case 'float':
|
|
140
|
+
return { tag: 'f', data: writeFloat32(arg.value) };
|
|
141
|
+
case 's':
|
|
142
|
+
case 'string':
|
|
143
|
+
return { tag: 's', data: Buffer.from(padString(arg.value)) };
|
|
144
|
+
case 'b':
|
|
145
|
+
case 'blob':
|
|
146
|
+
return { tag: 'b', data: writeBlob(arg.value) };
|
|
147
|
+
case 'd':
|
|
148
|
+
case 'double':
|
|
149
|
+
// For doubles, use float for now (OSC 1.0 doesn't have double)
|
|
150
|
+
return { tag: 'f', data: writeFloat32(arg.value) };
|
|
151
|
+
case 'T':
|
|
152
|
+
case 'boolean':
|
|
153
|
+
return arg.value ? { tag: 'T', data: Buffer.alloc(0) } : { tag: 'F', data: Buffer.alloc(0) };
|
|
154
|
+
case 'm':
|
|
155
|
+
case 'midi':
|
|
156
|
+
return { tag: 'm', data: writeMidi(arg.value) };
|
|
157
|
+
default:
|
|
158
|
+
throw new Error(`Unknown argument type: ${arg.type}`);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// Infer type from JavaScript type
|
|
163
|
+
switch (typeof arg) {
|
|
164
|
+
case 'number':
|
|
165
|
+
if (Number.isInteger(arg)) {
|
|
166
|
+
return { tag: 'i', data: writeInt32(arg) };
|
|
167
|
+
} else {
|
|
168
|
+
return { tag: 'f', data: writeFloat32(arg) };
|
|
169
|
+
}
|
|
170
|
+
case 'string':
|
|
171
|
+
return { tag: 's', data: Buffer.from(padString(arg)) };
|
|
172
|
+
case 'boolean':
|
|
173
|
+
return arg ? { tag: 'T', data: Buffer.alloc(0) } : { tag: 'F', data: Buffer.alloc(0) };
|
|
174
|
+
default:
|
|
175
|
+
if (Buffer.isBuffer(arg)) {
|
|
176
|
+
return { tag: 'b', data: writeBlob(arg) };
|
|
177
|
+
}
|
|
178
|
+
throw new Error(`Don't know how to encode argument: ${arg}`);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function decodeArgument(tag, buffer, offset) {
|
|
183
|
+
switch (tag) {
|
|
184
|
+
case 'i':
|
|
185
|
+
return readInt32(buffer, offset);
|
|
186
|
+
case 'f':
|
|
187
|
+
return readFloat32(buffer, offset);
|
|
188
|
+
case 's':
|
|
189
|
+
return readString(buffer, offset);
|
|
190
|
+
case 'b':
|
|
191
|
+
return readBlob(buffer, offset);
|
|
192
|
+
case 'T':
|
|
193
|
+
return { value: true, offset };
|
|
194
|
+
case 'F':
|
|
195
|
+
return { value: false, offset };
|
|
196
|
+
case 'N':
|
|
197
|
+
return { value: null, offset };
|
|
198
|
+
case 'm':
|
|
199
|
+
return readMidi(buffer, offset);
|
|
200
|
+
default:
|
|
201
|
+
throw new Error(`I don't understand the argument code ${tag}`);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
function toBuffer(message) {
|
|
206
|
+
if (message.oscType === 'bundle') {
|
|
207
|
+
return encodeBundleToBuffer(message);
|
|
208
|
+
} else {
|
|
209
|
+
return encodeMessageToBuffer(message);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
function encodeMessageToBuffer(message) {
|
|
214
|
+
// OSC Message format:
|
|
215
|
+
// Address pattern (padded string)
|
|
216
|
+
// Type tag string (padded string starting with ,)
|
|
217
|
+
// Arguments (encoded according to type tags)
|
|
218
|
+
|
|
219
|
+
const address = padString(message.address);
|
|
220
|
+
const addressBuffer = Buffer.from(address);
|
|
221
|
+
|
|
222
|
+
const encodedArgs = message.args.map(encodeArgument);
|
|
223
|
+
const typeTags = ',' + encodedArgs.map(arg => arg.tag).join('');
|
|
224
|
+
const typeTagsBuffer = Buffer.from(padString(typeTags));
|
|
225
|
+
|
|
226
|
+
const argumentBuffers = encodedArgs.map(arg => arg.data);
|
|
227
|
+
|
|
228
|
+
return Buffer.concat([addressBuffer, typeTagsBuffer, ...argumentBuffers]);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
function encodeBundleToBuffer(bundle) {
|
|
232
|
+
// OSC Bundle format:
|
|
233
|
+
// "#bundle" (padded string)
|
|
234
|
+
// Timetag (8 bytes)
|
|
235
|
+
// Elements (each prefixed with size)
|
|
236
|
+
|
|
237
|
+
const bundleString = padString('#bundle');
|
|
238
|
+
const bundleStringBuffer = Buffer.from(bundleString);
|
|
239
|
+
|
|
240
|
+
const timetagBuffer = writeTimeTag(bundle.timetag);
|
|
241
|
+
|
|
242
|
+
const elementBuffers = bundle.elements.map(element => {
|
|
243
|
+
let elementBuffer;
|
|
244
|
+
if (element.oscType === 'bundle') {
|
|
245
|
+
elementBuffer = encodeBundleToBuffer(element);
|
|
246
|
+
} else {
|
|
247
|
+
elementBuffer = encodeMessageToBuffer(element);
|
|
248
|
+
}
|
|
249
|
+
const sizeBuffer = writeInt32(elementBuffer.length);
|
|
250
|
+
return Buffer.concat([sizeBuffer, elementBuffer]);
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
return Buffer.concat([bundleStringBuffer, timetagBuffer, ...elementBuffers]);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
function fromBuffer(buffer) {
|
|
257
|
+
// Check if it's a bundle or message
|
|
258
|
+
if (buffer.length >= 8 && buffer.subarray(0, 8).toString() === '#bundle\0') {
|
|
259
|
+
return decodeBundleFromBuffer(buffer);
|
|
260
|
+
} else {
|
|
261
|
+
return decodeMessageFromBuffer(buffer);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
function decodeMessageFromBuffer(buffer) {
|
|
266
|
+
let offset = 0;
|
|
267
|
+
|
|
268
|
+
// Read address pattern
|
|
269
|
+
const addressResult = readString(buffer, offset);
|
|
270
|
+
const address = addressResult.value;
|
|
271
|
+
offset = addressResult.offset;
|
|
272
|
+
|
|
273
|
+
// Read type tag string
|
|
274
|
+
const typeTagsResult = readString(buffer, offset);
|
|
275
|
+
const typeTags = typeTagsResult.value;
|
|
276
|
+
offset = typeTagsResult.offset;
|
|
277
|
+
|
|
278
|
+
if (!typeTags.startsWith(',')) {
|
|
279
|
+
throw new Error('Malformed Packet');
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
const tags = typeTags.slice(1); // Remove leading comma
|
|
283
|
+
const args = [];
|
|
284
|
+
|
|
285
|
+
for (const tag of tags) {
|
|
286
|
+
const argResult = decodeArgument(tag, buffer, offset);
|
|
287
|
+
args.push({ value: argResult.value });
|
|
288
|
+
offset = argResult.offset;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
return {
|
|
292
|
+
oscType: 'message',
|
|
293
|
+
address,
|
|
294
|
+
args
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
function decodeBundleFromBuffer(buffer) {
|
|
299
|
+
let offset = 8; // Skip "#bundle\0"
|
|
300
|
+
|
|
301
|
+
// Read timetag
|
|
302
|
+
const timetagResult = readTimeTag(buffer, offset);
|
|
303
|
+
const timetag = timetagResult.value;
|
|
304
|
+
offset = timetagResult.offset;
|
|
305
|
+
|
|
306
|
+
const elements = [];
|
|
307
|
+
|
|
308
|
+
while (offset < buffer.length) {
|
|
309
|
+
// Read element size
|
|
310
|
+
const sizeResult = readInt32(buffer, offset);
|
|
311
|
+
const size = sizeResult.value;
|
|
312
|
+
offset = sizeResult.offset;
|
|
313
|
+
|
|
314
|
+
// Read element data
|
|
315
|
+
const elementBuffer = buffer.subarray(offset, offset + size);
|
|
316
|
+
const element = fromBuffer(elementBuffer);
|
|
317
|
+
elements.push(element);
|
|
318
|
+
offset += size;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
return {
|
|
322
|
+
oscType: 'bundle',
|
|
323
|
+
timetag,
|
|
324
|
+
elements
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
exports.fromBuffer = fromBuffer;
|
|
329
|
+
exports.toBuffer = toBuffer;
|
package/dist/test/test-decode.js
CHANGED
|
@@ -30,3 +30,80 @@ tap.test('decode: invalid typetags', (t) => {
|
|
|
30
30
|
}, /I don't understand the argument code R/);
|
|
31
31
|
t.end();
|
|
32
32
|
});
|
|
33
|
+
|
|
34
|
+
tap.test('decode: malformed OSC structure', (t) => {
|
|
35
|
+
// Try to create a scenario that might trigger the "else" case in decode
|
|
36
|
+
// This tests an edge case where the buffer might be parsed but not create a valid OSC structure
|
|
37
|
+
t.throws(() => {
|
|
38
|
+
// Create a buffer that's too short to be valid
|
|
39
|
+
const buf = Buffer.from('\0\0\0\0');
|
|
40
|
+
decode(buf);
|
|
41
|
+
}, /Malformed Packet/);
|
|
42
|
+
t.end();
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
tap.test('decode: corrupted buffer', (t) => {
|
|
46
|
+
// Test with a buffer that could potentially cause fromBuffer to return unexpected results
|
|
47
|
+
t.throws(() => {
|
|
48
|
+
// Create a malformed buffer that might not parse correctly
|
|
49
|
+
const buf = Buffer.from('invalid');
|
|
50
|
+
decode(buf);
|
|
51
|
+
}, /(Malformed Packet|Cannot read|out of range)/);
|
|
52
|
+
t.end();
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
// This test attempts to exercise edge cases in the decode function
|
|
56
|
+
tap.test('decode: edge case with manually crafted invalid structure', (t) => {
|
|
57
|
+
// Since the decode function has a defensive else clause, let's try to trigger it
|
|
58
|
+
// by creating a buffer that might result in an unexpected object structure
|
|
59
|
+
|
|
60
|
+
// Try with an empty buffer
|
|
61
|
+
t.throws(() => {
|
|
62
|
+
const buf = Buffer.alloc(0);
|
|
63
|
+
decode(buf);
|
|
64
|
+
}, /(Malformed Packet|Cannot read|out of range)/);
|
|
65
|
+
|
|
66
|
+
// Try with a buffer containing only null bytes
|
|
67
|
+
t.throws(() => {
|
|
68
|
+
const buf = Buffer.alloc(16, 0);
|
|
69
|
+
decode(buf);
|
|
70
|
+
}, /(Malformed Packet|Cannot read|out of range)/);
|
|
71
|
+
|
|
72
|
+
t.end();
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
tap.test('decode: malformed structure with unexpected oscType', async (t) => {
|
|
76
|
+
// Test the defensive else clause by providing a custom fromBuffer function
|
|
77
|
+
// that returns an object with an invalid oscType
|
|
78
|
+
|
|
79
|
+
const mockFromBuffer = () => ({
|
|
80
|
+
oscType: 'invalid',
|
|
81
|
+
data: 'test'
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
t.throws(() => {
|
|
85
|
+
decode(Buffer.from('test'), mockFromBuffer);
|
|
86
|
+
}, /Malformed Packet/, 'should throw for invalid oscType');
|
|
87
|
+
|
|
88
|
+
// Test with undefined oscType
|
|
89
|
+
const mockFromBufferUndefined = () => ({
|
|
90
|
+
data: 'test'
|
|
91
|
+
// missing oscType property
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
t.throws(() => {
|
|
95
|
+
decode(Buffer.from('test'), mockFromBufferUndefined);
|
|
96
|
+
}, /Malformed Packet/, 'should throw for undefined oscType');
|
|
97
|
+
|
|
98
|
+
// Test with null oscType
|
|
99
|
+
const mockFromBufferNull = () => ({
|
|
100
|
+
oscType: null,
|
|
101
|
+
data: 'test'
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
t.throws(() => {
|
|
105
|
+
decode(Buffer.from('test'), mockFromBufferNull);
|
|
106
|
+
}, /Malformed Packet/, 'should throw for null oscType');
|
|
107
|
+
|
|
108
|
+
t.end();
|
|
109
|
+
});
|