From 9c78cf4329d109bf331f4479eb9f723ebf29748c Mon Sep 17 00:00:00 2001 From: Joel Wetzell Date: Thu, 3 Oct 2024 21:24:01 -0500 Subject: [PATCH 01/13] add address and type string decoding --- src/models.ts | 1 + src/osc.ts | 44 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/src/models.ts b/src/models.ts index d58c04f..42c0ffc 100644 --- a/src/models.ts +++ b/src/models.ts @@ -12,4 +12,5 @@ export type OSCMessage = { export type OSCTypeConverter = { toBuffer: (value: string | number | Buffer | boolean) => Buffer | undefined; fromString: (string: string) => string | number | Buffer | boolean; + fromBuffer?: (buffer: Buffer) => [string | number | Buffer | boolean | undefined, Buffer]; }; diff --git a/src/osc.ts b/src/osc.ts index 60f741a..52a9934 100644 --- a/src/osc.ts +++ b/src/osc.ts @@ -14,6 +14,24 @@ const oscTypeConverterMap: { [key in OSCType]: OSCTypeConverter } = { throw new Error('osc type s toBuffer called with non string value'); }, fromString: (string: string) => string, + fromBuffer: (bytes: Buffer) => { + let stringEnd = 0; + let stringPaddingEnd = 0; + for (let index = 0; index < bytes.length; index++) { + if(bytes[index] === 0){ + stringEnd = index; + stringPaddingEnd = index + 1; + const stringPadding = 4-(stringEnd+1) % 4; + + if(stringPadding < 4){ + stringPaddingEnd += stringPadding; + } + break; + } + } + + return [bytes.toString('ascii', 0, stringEnd), bytes.subarray(stringPaddingEnd)] + } }, f: { toBuffer: (number) => { @@ -101,4 +119,30 @@ export function messageToBuffer(message: OSCMessage) { } const argsBuffer = argsToBuffer(message.args); return Buffer.concat([addressBuffer, typesBuffer, argsBuffer]); +} + +export function messageFromBuffer(bytes: Buffer): OSCMessage | undefined { + if(bytes[0] !== 47){ + throw new Error('osc message must start with a /') + } + + const oscArgs: OSCArg[] = [] + + if(oscTypeConverterMap.s.fromBuffer) { + const [address, bytesAfterAddress] = oscTypeConverterMap.s.fromBuffer(bytes) + if(typeof address === 'string'){ + console.log(`address: ${address}`) + console.log(`bytesAfterAddresss: ${bytesAfterAddress}`) + let [typeString, bytesAfterType] = oscTypeConverterMap.s.fromBuffer(bytesAfterAddress) + console.log(`typeString: ${typeString}`) + console.log(`bytesAfterType: ${bytesAfterType}`) + if(typeof typeString === 'string'){ + if(!typeString.startsWith(',')){ + throw new Error('osc type string must start with a ,') + } + } + } + } + + return } \ No newline at end of file From c2da7eea718cfb4f25fb2065f033cc4a1147a7f0 Mon Sep 17 00:00:00 2001 From: Joel Wetzell Date: Thu, 3 Oct 2024 21:24:10 -0500 Subject: [PATCH 02/13] add decode to example --- examples/osc-message.cjs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/examples/osc-message.cjs b/examples/osc-message.cjs index fe73a3a..a3841ad 100644 --- a/examples/osc-message.cjs +++ b/examples/osc-message.cjs @@ -1,5 +1,8 @@ const osc = require('../dist/index.js') -const buffer = osc.messageToBuffer({address:'/hello',args:[{type: 's', value: 'arg1'}]}) +const buffer = osc.messageToBuffer({address:'/hello1',args:[{type: 's', value: 'arg1'}]}) -console.log(buffer) \ No newline at end of file +console.log(buffer) +const message = osc.messageFromBuffer(buffer) + +console.log(message) \ No newline at end of file From 5eade927fabc7c0a8df8980c96035cadf5eb3ff1 Mon Sep 17 00:00:00 2001 From: Joel Wetzell Date: Mon, 7 Oct 2024 12:42:22 -0500 Subject: [PATCH 03/13] fromBuffer is not optional --- src/models.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/models.ts b/src/models.ts index 42c0ffc..eb8909b 100644 --- a/src/models.ts +++ b/src/models.ts @@ -12,5 +12,5 @@ export type OSCMessage = { export type OSCTypeConverter = { toBuffer: (value: string | number | Buffer | boolean) => Buffer | undefined; fromString: (string: string) => string | number | Buffer | boolean; - fromBuffer?: (buffer: Buffer) => [string | number | Buffer | boolean | undefined, Buffer]; + fromBuffer: (buffer: Buffer) => [string | number | Buffer | boolean | undefined, Buffer]; }; From e79771b13765acae074ec14ad437e68f3a633a0a Mon Sep 17 00:00:00 2001 From: Joel Wetzell Date: Mon, 7 Oct 2024 12:50:44 -0500 Subject: [PATCH 04/13] add fromString for bool types --- src/osc.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/osc.ts b/src/osc.ts index 52a9934..bdf4790 100644 --- a/src/osc.ts +++ b/src/osc.ts @@ -73,14 +73,13 @@ const oscTypeConverterMap: { [key in OSCType]: OSCTypeConverter } = { toBuffer: () => { return Buffer.alloc(0) }, - fromString: (string: string) => true + fromString: (string: string) => true, }, F: { toBuffer: () => { return Buffer.alloc(0) }, - fromString: (string: string) => false - } + fromString: (string: string) => false, }; function argsToBuffer(args: OSCArg[]) { From 6907cf7595aed5aac17952e39b7b834307351c49 Mon Sep 17 00:00:00 2001 From: Joel Wetzell Date: Mon, 7 Oct 2024 12:51:59 -0500 Subject: [PATCH 05/13] add fromBuffer for osc types --- src/osc.ts | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/src/osc.ts b/src/osc.ts index bdf4790..5e79725 100644 --- a/src/osc.ts +++ b/src/osc.ts @@ -43,6 +43,14 @@ const oscTypeConverterMap: { [key in OSCType]: OSCTypeConverter } = { throw new Error('osc type f toBuffer called with non number value'); }, fromString: (string: string) => Number.parseFloat(string), + fromBuffer: (buffer) => { + if (buffer.length < 4) { + throw new Error('not enough bytes to read a osc float'); + } + + const value = buffer.readFloatBE(); + return [value, buffer.subarray(4)]; + }, }, i: { toBuffer: (number) => { @@ -54,6 +62,14 @@ const oscTypeConverterMap: { [key in OSCType]: OSCTypeConverter } = { throw new Error('osc type i toBuffer called with non number value'); }, fromString: (string: string) => Number.parseInt(string, 10), + fromBuffer: (buffer) => { + if (buffer.length < 4) { + throw new Error('not enough bytes to read a osc integer'); + } + + const value = buffer.readInt32BE(); + return [value, buffer.subarray(4)]; + }, }, b: { toBuffer: (data) => { @@ -68,18 +84,39 @@ const oscTypeConverterMap: { [key in OSCType]: OSCTypeConverter } = { throw new Error('osc type b toBuffer called with non Buffer value'); }, fromString: (string: string) => Buffer.from(string, 'hex'), + fromBuffer: (buffer) => { + const [blobLength, blobBytes] = oscTypeConverterMap.i.fromBuffer(buffer); + if (typeof blobLength === 'number'){ + if(blobBytes.length < blobLength){ + throw new Error('not enough bytes left for blob length specified') + } + const value = blobBytes.subarray(0,blobLength) + const blobPadding = 4- (blobLength %4) + const blobEnd = blobPadding < 4 ? blobLength + blobPadding : blobLength + return [value, blobBytes.subarray(blobEnd)] + } else { + throw new Error('unexpected value for blob length') + } + }, }, T: { toBuffer: () => { return Buffer.alloc(0) }, fromString: (string: string) => true, + fromBuffer: (buffer) => { + return [true, buffer]; + }, }, F: { toBuffer: () => { return Buffer.alloc(0) }, fromString: (string: string) => false, + fromBuffer: (buffer) => { + return [false, buffer]; + }, + } }; function argsToBuffer(args: OSCArg[]) { From eae4ef725678a852223cd740d66f7bd6c7d05fa4 Mon Sep 17 00:00:00 2001 From: Joel Wetzell Date: Mon, 7 Oct 2024 12:54:49 -0500 Subject: [PATCH 06/13] fix type definition of converter map --- src/osc.ts | 45 ++++++++++++++++++++++++++++++--------------- 1 file changed, 30 insertions(+), 15 deletions(-) diff --git a/src/osc.ts b/src/osc.ts index 5e79725..0ee23f5 100644 --- a/src/osc.ts +++ b/src/osc.ts @@ -1,6 +1,6 @@ import { OSCType, OSCArg, OSCMessage, OSCTypeConverter } from './models'; -const oscTypeConverterMap: { [key in OSCType]: OSCTypeConverter } = { +const oscTypeConverterMap: { [key: string]: OSCTypeConverter } = { s: { toBuffer: (string) => { if (typeof string === 'string') { @@ -164,21 +164,36 @@ export function messageFromBuffer(bytes: Buffer): OSCMessage | undefined { const oscArgs: OSCArg[] = [] - if(oscTypeConverterMap.s.fromBuffer) { - const [address, bytesAfterAddress] = oscTypeConverterMap.s.fromBuffer(bytes) - if(typeof address === 'string'){ - console.log(`address: ${address}`) - console.log(`bytesAfterAddresss: ${bytesAfterAddress}`) - let [typeString, bytesAfterType] = oscTypeConverterMap.s.fromBuffer(bytesAfterAddress) - console.log(`typeString: ${typeString}`) - console.log(`bytesAfterType: ${bytesAfterType}`) - if(typeof typeString === 'string'){ - if(!typeString.startsWith(',')){ - throw new Error('osc type string must start with a ,') + const [address, bytesAfterAddress] = oscTypeConverterMap.s.fromBuffer(bytes); + if(typeof address === 'string'){ + let [typeString, bytesAfterType] = oscTypeConverterMap.s.fromBuffer(bytesAfterAddress); + if (typeof typeString === 'string') { + if (!typeString.startsWith(',')) { + throw new Error('osc type string must start with a ,'); + } + let argsBuffer = bytesAfterType + for (let index = 1; index < typeString.length; index++) { + const argType = typeString.charAt(index) as OSCType; + + const oscTypeConverter = oscTypeConverterMap[argType] + if(oscTypeConverter === undefined){ + throw new Error('unknown OSC type') } + const [value, remainingBytes] = oscTypeConverter.fromBuffer(argsBuffer) + if(value !== undefined){ + const arg: OSCArg = { + type: argType, + value: value + } + oscArgs.push(arg) + } + argsBuffer = remainingBytes; + } + + return { + address, + args: oscArgs } } } - - return -} \ No newline at end of file +} From 753ec6d8dfa9043cc8f355919b0dff00f82da3f3 Mon Sep 17 00:00:00 2001 From: Joel Wetzell Date: Mon, 7 Oct 2024 12:55:48 -0500 Subject: [PATCH 07/13] add different error classes --- src/osc.ts | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/osc.ts b/src/osc.ts index 0ee23f5..9d3d90e 100644 --- a/src/osc.ts +++ b/src/osc.ts @@ -11,7 +11,7 @@ const oscTypeConverterMap: { [key: string]: OSCTypeConverter } = { } return Buffer.from(oscString, 'ascii'); } - throw new Error('osc type s toBuffer called with non string value'); + throw new TypeError('osc type s toBuffer called with non string value'); }, fromString: (string: string) => string, fromBuffer: (bytes: Buffer) => { @@ -40,7 +40,7 @@ const oscTypeConverterMap: { [key: string]: OSCTypeConverter } = { buffer.writeFloatBE(number); return buffer; } - throw new Error('osc type f toBuffer called with non number value'); + throw new TypeError('osc type f toBuffer called with non number value'); }, fromString: (string: string) => Number.parseFloat(string), fromBuffer: (buffer) => { @@ -59,7 +59,7 @@ const oscTypeConverterMap: { [key: string]: OSCTypeConverter } = { buffer.writeInt32BE(number); return buffer; } - throw new Error('osc type i toBuffer called with non number value'); + throw new TypeError('osc type i toBuffer called with non number value'); }, fromString: (string: string) => Number.parseInt(string, 10), fromBuffer: (buffer) => { @@ -81,7 +81,7 @@ const oscTypeConverterMap: { [key: string]: OSCTypeConverter } = { return Buffer.concat([sizeBuffer, data, padBuffer]); } } - throw new Error('osc type b toBuffer called with non Buffer value'); + throw new TypeError('osc type b toBuffer called with non Buffer value'); }, fromString: (string: string) => Buffer.from(string, 'hex'), fromBuffer: (buffer) => { @@ -126,11 +126,7 @@ function argsToBuffer(args: OSCArg[]) { const arg = args[index]; const typeConverter = oscTypeConverterMap[arg.type]; if (typeConverter === undefined) { - throw new Error('osc type error: unknown type '.concat(arg.type)); - } - - if (typeConverter.fromString === undefined) { - throw new Error('osc type error: no string converter for type '.concat(arg.type)); + throw new TypeError('unknown type '.concat(arg.type)); } const buffer = typeConverter.toBuffer(arg.value); From 24e09960d9dcb25e9b83319605d948f9d69fefbb Mon Sep 17 00:00:00 2001 From: Joel Wetzell Date: Mon, 7 Oct 2024 12:56:10 -0500 Subject: [PATCH 08/13] fix issue with buffer padding --- src/osc.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/osc.ts b/src/osc.ts index 9d3d90e..a00c28a 100644 --- a/src/osc.ts +++ b/src/osc.ts @@ -77,7 +77,7 @@ const oscTypeConverterMap: { [key: string]: OSCTypeConverter } = { const sizeBuffer = oscTypeConverterMap.i.toBuffer(data.length); if (sizeBuffer) { const padSize = 4 - (data.length % 4); - const padBuffer = Buffer.from(Array(padSize).fill(0)); + const padBuffer = padSize < 4 ? Buffer.from(Array(padSize).fill(0)) : Buffer.from([]); return Buffer.concat([sizeBuffer, data, padBuffer]); } } From d295b4522899370fb9bb12ae4083192becc4eb25 Mon Sep 17 00:00:00 2001 From: Joel Wetzell Date: Mon, 7 Oct 2024 12:58:51 -0500 Subject: [PATCH 09/13] run prettier --- src/osc.ts | 63 +++++++++++++++++++++++++++--------------------------- 1 file changed, 31 insertions(+), 32 deletions(-) diff --git a/src/osc.ts b/src/osc.ts index a00c28a..081c98e 100644 --- a/src/osc.ts +++ b/src/osc.ts @@ -18,20 +18,20 @@ const oscTypeConverterMap: { [key: string]: OSCTypeConverter } = { let stringEnd = 0; let stringPaddingEnd = 0; for (let index = 0; index < bytes.length; index++) { - if(bytes[index] === 0){ + if (bytes[index] === 0) { stringEnd = index; stringPaddingEnd = index + 1; - const stringPadding = 4-(stringEnd+1) % 4; + const stringPadding = 4 - ((stringEnd + 1) % 4); - if(stringPadding < 4){ + if (stringPadding < 4) { stringPaddingEnd += stringPadding; } break; } } - return [bytes.toString('ascii', 0, stringEnd), bytes.subarray(stringPaddingEnd)] - } + return [bytes.toString('ascii', 0, stringEnd), bytes.subarray(stringPaddingEnd)]; + }, }, f: { toBuffer: (number) => { @@ -86,22 +86,22 @@ const oscTypeConverterMap: { [key: string]: OSCTypeConverter } = { fromString: (string: string) => Buffer.from(string, 'hex'), fromBuffer: (buffer) => { const [blobLength, blobBytes] = oscTypeConverterMap.i.fromBuffer(buffer); - if (typeof blobLength === 'number'){ - if(blobBytes.length < blobLength){ - throw new Error('not enough bytes left for blob length specified') + if (typeof blobLength === 'number') { + if (blobBytes.length < blobLength) { + throw new Error('not enough bytes left for blob length specified'); } - const value = blobBytes.subarray(0,blobLength) - const blobPadding = 4- (blobLength %4) - const blobEnd = blobPadding < 4 ? blobLength + blobPadding : blobLength - return [value, blobBytes.subarray(blobEnd)] + const value = blobBytes.subarray(0, blobLength); + const blobPadding = 4 - (blobLength % 4); + const blobEnd = blobPadding < 4 ? blobLength + blobPadding : blobLength; + return [value, blobBytes.subarray(blobEnd)]; } else { - throw new Error('unexpected value for blob length') + throw new Error('unexpected value for blob length'); } }, }, T: { toBuffer: () => { - return Buffer.alloc(0) + return Buffer.alloc(0); }, fromString: (string: string) => true, fromBuffer: (buffer) => { @@ -110,13 +110,13 @@ const oscTypeConverterMap: { [key: string]: OSCTypeConverter } = { }, F: { toBuffer: () => { - return Buffer.alloc(0) + return Buffer.alloc(0); }, fromString: (string: string) => false, fromBuffer: (buffer) => { return [false, buffer]; }, - } + }, }; function argsToBuffer(args: OSCArg[]) { @@ -138,7 +138,6 @@ function argsToBuffer(args: OSCArg[]) { } export function messageToBuffer(message: OSCMessage) { - const addressBuffer = oscTypeConverterMap.s.toBuffer(message.address); if (addressBuffer === undefined) { throw new Error('problem encoding address'); @@ -154,42 +153,42 @@ export function messageToBuffer(message: OSCMessage) { } export function messageFromBuffer(bytes: Buffer): OSCMessage | undefined { - if(bytes[0] !== 47){ - throw new Error('osc message must start with a /') + if (bytes[0] !== 47) { + throw new Error('osc message must start with a /'); } - const oscArgs: OSCArg[] = [] + const oscArgs: OSCArg[] = []; const [address, bytesAfterAddress] = oscTypeConverterMap.s.fromBuffer(bytes); - if(typeof address === 'string'){ + if (typeof address === 'string') { let [typeString, bytesAfterType] = oscTypeConverterMap.s.fromBuffer(bytesAfterAddress); if (typeof typeString === 'string') { if (!typeString.startsWith(',')) { throw new Error('osc type string must start with a ,'); } - let argsBuffer = bytesAfterType + let argsBuffer = bytesAfterType; for (let index = 1; index < typeString.length; index++) { const argType = typeString.charAt(index) as OSCType; - const oscTypeConverter = oscTypeConverterMap[argType] - if(oscTypeConverter === undefined){ - throw new Error('unknown OSC type') + const oscTypeConverter = oscTypeConverterMap[argType]; + if (oscTypeConverter === undefined) { + throw new Error('unknown OSC type'); } - const [value, remainingBytes] = oscTypeConverter.fromBuffer(argsBuffer) - if(value !== undefined){ + const [value, remainingBytes] = oscTypeConverter.fromBuffer(argsBuffer); + if (value !== undefined) { const arg: OSCArg = { type: argType, - value: value - } - oscArgs.push(arg) + value: value, + }; + oscArgs.push(arg); } argsBuffer = remainingBytes; } return { address, - args: oscArgs - } + args: oscArgs, + }; } } } From eea5033147f1921d93d4428f6a1100899fd3e6d7 Mon Sep 17 00:00:00 2001 From: Joel Wetzell Date: Mon, 7 Oct 2024 12:59:20 -0500 Subject: [PATCH 10/13] remove example --- examples/osc-message.cjs | 8 -------- 1 file changed, 8 deletions(-) delete mode 100644 examples/osc-message.cjs diff --git a/examples/osc-message.cjs b/examples/osc-message.cjs deleted file mode 100644 index a3841ad..0000000 --- a/examples/osc-message.cjs +++ /dev/null @@ -1,8 +0,0 @@ -const osc = require('../dist/index.js') - -const buffer = osc.messageToBuffer({address:'/hello1',args:[{type: 's', value: 'arg1'}]}) - -console.log(buffer) -const message = osc.messageFromBuffer(buffer) - -console.log(message) \ No newline at end of file From ece1d988f52888351fe237f4a70aad0c06ab1cac Mon Sep 17 00:00:00 2001 From: Joel Wetzell Date: Mon, 7 Oct 2024 12:59:31 -0500 Subject: [PATCH 11/13] add basic tests --- tests/message-decode.test.js | 104 +++++++++++++++++++++++++++++++++++ tests/message-encode.test.js | 94 +++++++++++++++++++++++++++++++ 2 files changed, 198 insertions(+) create mode 100644 tests/message-decode.test.js create mode 100644 tests/message-encode.test.js diff --git a/tests/message-decode.test.js b/tests/message-decode.test.js new file mode 100644 index 0000000..f1910fb --- /dev/null +++ b/tests/message-decode.test.js @@ -0,0 +1,104 @@ +const { deepEqual, throws } = require('assert'); +const { describe, it } = require('node:test'); +const osc = require('../dist/index'); + +const tests = [ + { + description: 'simple address no args', + bytes: Buffer.from('2f68656c6c6f00002c000000', 'hex'), + expected: { address: '/hello', args: [] }, + }, + { + description: 'simple address string arg', + bytes: Buffer.from('2f68656c6c6f00002c7300006172673100000000', 'hex'), + expected: { address: '/hello', args: [{ type: 's', value: 'arg1' }] }, + }, + { + description: 'simple address integer arg', + bytes: Buffer.from('2f68656c6c6f00002c69000000000023', 'hex'), + expected: { address: '/hello', args: [{ type: 'i', value: 35 }] }, + }, + { + description: 'simple address float arg', + bytes: Buffer.from('2f68656c6c6f00002c660000420a0000', 'hex'), + expected: { address: '/hello', args: [{ type: 'f', value: 34.5 }] }, + }, + { + description: 'simple address blob arg', + bytes: Buffer.from('2f68656c6c6f00002c62000000000004626c6f62', 'hex'), + expected: { address: '/hello', args: [{ type: 'b', value: Buffer.from('blob') }] }, + }, + { + description: 'simple address True arg', + bytes: Buffer.from('2f68656c6c6f00002c540000', 'hex'), + expected: { address: '/hello', args: [{ type: 'T', value: true }] }, + }, + { + description: 'simple address False arg', + bytes: Buffer.from('2f68656c6c6f00002c460000', 'hex'), + expected: { address: '/hello', args: [{ type: 'F', value: false }] }, + }, +]; + +describe('OSC Message Decoding', () => { + tests.forEach((messageTest) => { + it(messageTest.description, () => { + const decoded = osc.messageFromBuffer(messageTest.bytes); + deepEqual(decoded, messageTest.expected); + }); + }); + + it('bad address', () => { + throws( + () => { + osc.messageFromBuffer(Buffer.from('68656c6c6f00002c660000420a0000', 'hex')); + }, + { name: /^Error$/, message:/must start with/ } + ); + }); + + it('bad type string', () => { + throws( + () => { + osc.messageFromBuffer(Buffer.from('2f68656c6c6f000066000000420a00', 'hex')); + }, + { name: /^Error$/, message:/type string must start with/ } + ); + }); + + it('unknown type', () => { + throws( + () => { + osc.messageFromBuffer(Buffer.from('2f68656c6c6f00002c7a0000420a0000', 'hex')); + }, + { name: /^Error$/, message:/unknown/ } + ); + }); + + it('float arg missing bytes', () => { + throws( + () => { + osc.messageFromBuffer(Buffer.from('2f68656c6c6f00002c660000420a00', 'hex')); + }, + { name: /^Error$/, message:/not enough bytes/ } + ); + }); + + it('int arg missing bytes', () => { + throws( + () => { + osc.messageFromBuffer(Buffer.from('2f68656c6c6f00002c690000000000', 'hex')); + }, + { name: /^Error$/, message:/not enough bytes/ } + ); + }); + + it('blob bytes too small', () => { + throws( + () => { + osc.messageFromBuffer(Buffer.from('2f68656c6c6f00002c62000000000004626c6f', 'hex')); + }, + { name: /^Error$/, message:/not enough bytes/ } + ); + }); +}); diff --git a/tests/message-encode.test.js b/tests/message-encode.test.js new file mode 100644 index 0000000..70efb19 --- /dev/null +++ b/tests/message-encode.test.js @@ -0,0 +1,94 @@ +const { deepEqual, throws } = require('assert'); +const { describe, it } = require('node:test'); +const osc = require('../dist/index'); + +const tests = [ + { + description: 'simple address no args', + message: { address: '/hello', args: [] }, + expected: Buffer.from('2f68656c6c6f00002c000000', 'hex'), + }, + { + description: 'simple address string arg', + message: { address: '/hello', args: [{ type: 's', value: 'arg1' }] }, + expected: Buffer.from('2f68656c6c6f00002c7300006172673100000000', 'hex'), + }, + { + description: 'simple address integer arg', + message: { address: '/hello', args: [{ type: 'i', value: 35 }] }, + expected: Buffer.from('2f68656c6c6f00002c69000000000023', 'hex'), + }, + { + description: 'simple address float arg', + message: { address: '/hello', args: [{ type: 'f', value: 34.5 }] }, + expected: Buffer.from('2f68656c6c6f00002c660000420a0000', 'hex'), + }, + { + description: 'simple address blob arg', + message: { address: '/hello', args: [{ type: 'b', value: Buffer.from('blob') }] }, + expected: Buffer.from('2f68656c6c6f00002c62000000000004626c6f62', 'hex'), + }, + { + description: 'simple address True arg', + message: { address: '/hello', args: [{ type: 'T', value: true }] }, + expected: Buffer.from('2f68656c6c6f00002c540000', 'hex'), + }, + { + description: 'simple address False arg', + message: { address: '/hello', args: [{ type: 'F', value: false }] }, + expected: Buffer.from('2f68656c6c6f00002c460000', 'hex'), + }, +]; + +describe('OSC Message Encoding', () => { + tests.forEach((messageTest) => { + it(messageTest.description, () => { + const encoded = osc.messageToBuffer(messageTest.message); + deepEqual(encoded, messageTest.expected); + }); + }); + it('bad string arg', () => { + throws( + () => { + osc.messageToBuffer({ address: '/address', args: [{ type: 's', value: 123 }] }); + }, + { name: /^TypeError$/ } + ); + }); + + it('bad integer arg', () => { + throws( + () => { + osc.messageToBuffer({ address: '/address', args: [{ type: 'i', value: 'hi' }] }); + }, + { name: /^TypeError$/ } + ); + }); + + it('bad float arg', () => { + throws( + () => { + osc.messageToBuffer({ address: '/address', args: [{ type: 'f', value: 'hi' }] }); + }, + { name: /^TypeError$/ } + ); + }); + + it('bad blob arg', () => { + throws( + () => { + osc.messageToBuffer({ address: '/address', args: [{ type: 'b', value: 123 }] }); + }, + { name: /^TypeError$/ } + ); + }); + + it('unknown arg type', () => { + throws( + () => { + osc.messageToBuffer({ address: '/address', args: [{ type: 'z', value: 123 }] }); + }, + { name: /^TypeError$/ } + ); + }); +}); From 3e96e527f3ec12c356ce22368e9ed9f3dcee33a1 Mon Sep 17 00:00:00 2001 From: Joel Wetzell Date: Mon, 7 Oct 2024 20:07:32 -0500 Subject: [PATCH 12/13] add test script to package.json --- package.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 3d2bc42..33700c4 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,9 @@ "scripts": { "prebuild": "rimraf dist", "build": "tsc", - "prepublishOnly": "npm run build" + "prepublishOnly": "npm run build", + "pretest": "npm run build", + "test": "node --test --experimental-test-coverage" }, "files": [ "dist" From 30bceff46c9b102f8068a55e7ddc921199272645 Mon Sep 17 00:00:00 2001 From: Joel Wetzell Date: Mon, 7 Oct 2024 20:07:50 -0500 Subject: [PATCH 13/13] add workflow to run tests on PR --- .github/workflows/run-tests.yml | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 .github/workflows/run-tests.yml diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml new file mode 100644 index 0000000..619bd2e --- /dev/null +++ b/.github/workflows/run-tests.yml @@ -0,0 +1,23 @@ +name: Run tests +on: + pull_request: + branches: + - main +jobs: + test: + runs-on: ubuntu-latest + steps: + - name: Check out repository + uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + + - name: Set up Node.js + uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4.0.4 + with: + node-version-file: '.nvmrc' + cache: 'npm' + cache-dependency-path: './package-lock.json' + + - name: Install Node.js dependencies + run: npm ci + + - run: npm run test \ No newline at end of file