osc-mcp-server
Version:
Model Context Protocol server for OSC (Open Sound Control) endpoint management
329 lines • 15.2 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const parser_1 = require("./parser");
const index_1 = require("../types/index");
describe('OSC Message Parser', () => {
describe('parseOSCMessage', () => {
it('should parse a simple message with no arguments', () => {
const buffer = Buffer.alloc(12);
let offset = 0;
buffer.write('/test', offset);
buffer.writeUInt8(0, offset + 5);
offset += 8;
buffer.write(',', offset);
buffer.writeUInt8(0, offset + 1);
const result = (0, parser_1.parseOSCMessage)(buffer, '127.0.0.1', 8000);
expect(result.error).toBeUndefined();
expect(result.message).toBeDefined();
expect(result.message.address).toBe('/test');
expect(result.message.typeTags).toBe('');
expect(result.message.arguments).toEqual([]);
expect(result.message.sourceIp).toBe('127.0.0.1');
expect(result.message.sourcePort).toBe(8000);
});
it('should parse a message with integer argument', () => {
const buffer = Buffer.alloc(20);
let offset = 0;
buffer.write('/synth/freq', offset);
buffer.writeUInt8(0, offset + 11);
offset = 12;
buffer.write(',i', offset);
buffer.writeUInt8(0, offset + 2);
offset = 16;
buffer.writeInt32BE(440, offset);
const result = (0, parser_1.parseOSCMessage)(buffer, '192.168.1.100', 57120);
expect(result.error).toBeUndefined();
expect(result.message).toBeDefined();
expect(result.message.address).toBe('/synth/freq');
expect(result.message.typeTags).toBe('i');
expect(result.message.arguments).toEqual([440]);
});
it('should parse a message with float argument', () => {
const buffer = Buffer.alloc(16);
let offset = 0;
buffer.write('/volume', offset);
buffer.writeUInt8(0, offset + 7);
offset += 8;
buffer.write(',f', offset);
buffer.writeUInt8(0, offset + 2);
offset += 4;
buffer.writeFloatBE(0.75, offset);
const result = (0, parser_1.parseOSCMessage)(buffer, '127.0.0.1', 8000);
expect(result.error).toBeUndefined();
expect(result.message).toBeDefined();
expect(result.message.address).toBe('/volume');
expect(result.message.typeTags).toBe('f');
expect(result.message.arguments).toEqual([0.75]);
});
it('should parse a message with string argument', () => {
const buffer = Buffer.alloc(20);
let offset = 0;
buffer.write('/name', offset);
buffer.writeUInt8(0, offset + 5);
offset += 8;
buffer.write(',s', offset);
buffer.writeUInt8(0, offset + 2);
offset += 4;
buffer.write('test', offset);
buffer.writeUInt8(0, offset + 4);
const result = (0, parser_1.parseOSCMessage)(buffer, '127.0.0.1', 8000);
expect(result.error).toBeUndefined();
expect(result.message).toBeDefined();
expect(result.message.address).toBe('/name');
expect(result.message.typeTags).toBe('s');
expect(result.message.arguments).toEqual(['test']);
});
it('should parse a message with blob argument', () => {
const blobData = Buffer.from([0x01, 0x02, 0x03, 0x04]);
const buffer = Buffer.alloc(20);
let offset = 0;
buffer.write('/data', offset);
buffer.writeUInt8(0, offset + 5);
offset += 8;
buffer.write(',b', offset);
buffer.writeUInt8(0, offset + 2);
offset += 4;
buffer.writeInt32BE(4, offset);
offset += 4;
blobData.copy(buffer, offset);
const result = (0, parser_1.parseOSCMessage)(buffer, '127.0.0.1', 8000);
expect(result.error).toBeUndefined();
expect(result.message).toBeDefined();
expect(result.message.address).toBe('/data');
expect(result.message.typeTags).toBe('b');
expect(result.message.arguments).toHaveLength(1);
expect(Buffer.isBuffer(result.message.arguments[0])).toBe(true);
expect(result.message.arguments[0]).toEqual(blobData);
});
it('should parse a message with multiple arguments', () => {
const buffer = Buffer.alloc(28);
let offset = 0;
buffer.write('/multi', offset);
buffer.writeUInt8(0, offset + 6);
offset += 8;
buffer.write(',ifs', offset);
buffer.writeUInt8(0, offset + 4);
offset += 8;
buffer.writeInt32BE(123, offset);
offset += 4;
buffer.writeFloatBE(4.56, offset);
offset += 4;
buffer.write('hi', offset);
buffer.writeUInt8(0, offset + 2);
const result = (0, parser_1.parseOSCMessage)(buffer, '127.0.0.1', 8000);
expect(result.error).toBeUndefined();
expect(result.message).toBeDefined();
expect(result.message.address).toBe('/multi');
expect(result.message.typeTags).toBe('ifs');
expect(result.message.arguments).toHaveLength(3);
expect(result.message.arguments[0]).toBe(123);
expect(result.message.arguments[1]).toBeCloseTo(4.56);
expect(result.message.arguments[2]).toBe('hi');
});
it('should handle unsupported type tags gracefully', () => {
const buffer = Buffer.alloc(16);
let offset = 0;
buffer.write('/test', offset);
buffer.writeUInt8(0, offset + 5);
offset += 8;
buffer.write(',xi', offset);
buffer.writeUInt8(0, offset + 3);
offset += 4;
buffer.writeInt32BE(42, offset);
const result = (0, parser_1.parseOSCMessage)(buffer, '127.0.0.1', 8000);
expect(result.error).toBeUndefined();
expect(result.message).toBeDefined();
expect(result.message.address).toBe('/test');
expect(result.message.typeTags).toBe('xi');
expect(result.message.arguments).toEqual([42]);
});
it('should return error for message too short', () => {
const buffer = Buffer.alloc(4);
buffer.write('/hi');
const result = (0, parser_1.parseOSCMessage)(buffer, '127.0.0.1', 8000);
expect(result.message).toBeUndefined();
expect(result.error).toBeDefined();
expect(result.error.code).toBe(index_1.ErrorCode.INVALID_OSC_MESSAGE);
expect(result.error.message).toContain('too short');
});
it('should return error for invalid address pattern', () => {
const buffer = Buffer.alloc(12);
let offset = 0;
buffer.write('test', offset);
buffer.writeUInt8(0, offset + 4);
offset += 8;
buffer.write(',', offset);
buffer.writeUInt8(0, offset + 1);
const result = (0, parser_1.parseOSCMessage)(buffer, '127.0.0.1', 8000);
expect(result.message).toBeUndefined();
expect(result.error).toBeDefined();
expect(result.error.code).toBe(index_1.ErrorCode.INVALID_OSC_MESSAGE);
expect(result.error.message).toContain('must start with "/"');
});
it('should return error for missing type tags', () => {
const buffer = Buffer.alloc(8);
buffer.write('/test');
const result = (0, parser_1.parseOSCMessage)(buffer, '127.0.0.1', 8000);
expect(result.message).toBeUndefined();
expect(result.error).toBeDefined();
expect(result.error.code).toBe(index_1.ErrorCode.INVALID_OSC_MESSAGE);
});
});
describe('extractAddressPattern', () => {
it('should extract valid address pattern', () => {
const buffer = Buffer.alloc(8);
buffer.write('/test');
buffer.writeUInt8(0, 5);
const result = (0, parser_1.extractAddressPattern)(buffer, 0);
expect(result.error).toBeUndefined();
expect(result.value).toBe('/test');
expect(result.nextOffset).toBe(8);
});
it('should return error for address not starting with /', () => {
const buffer = Buffer.alloc(8);
buffer.write('test');
buffer.writeUInt8(0, 4);
const result = (0, parser_1.extractAddressPattern)(buffer, 0);
expect(result.value).toBeUndefined();
expect(result.error).toBeDefined();
expect(result.error.code).toBe(index_1.ErrorCode.INVALID_OSC_MESSAGE);
});
it('should return error for non-null-terminated address', () => {
const buffer = Buffer.alloc(8);
buffer.fill(0x2f);
const result = (0, parser_1.extractAddressPattern)(buffer, 0);
expect(result.value).toBeUndefined();
expect(result.error).toBeDefined();
expect(result.error.code).toBe(index_1.ErrorCode.INVALID_OSC_MESSAGE);
});
});
describe('extractTypeTags', () => {
it('should extract valid type tags', () => {
const buffer = Buffer.alloc(8);
buffer.write(',ifs');
buffer.writeUInt8(0, 4);
const result = (0, parser_1.extractTypeTags)(buffer, 0);
expect(result.error).toBeUndefined();
expect(result.value).toBe('ifs');
expect(result.nextOffset).toBe(8);
});
it('should return error for type tags not starting with comma', () => {
const buffer = Buffer.alloc(8);
buffer.write('ifs');
buffer.writeUInt8(0, 3);
const result = (0, parser_1.extractTypeTags)(buffer, 0);
expect(result.value).toBeUndefined();
expect(result.error).toBeDefined();
expect(result.error.code).toBe(index_1.ErrorCode.INVALID_OSC_MESSAGE);
});
it('should return error for non-null-terminated type tags', () => {
const buffer = Buffer.alloc(8);
buffer.fill(0x2c);
const result = (0, parser_1.extractTypeTags)(buffer, 0);
expect(result.value).toBeUndefined();
expect(result.error).toBeDefined();
expect(result.error.code).toBe(index_1.ErrorCode.INVALID_OSC_MESSAGE);
});
it('should handle empty type tags', () => {
const buffer = Buffer.alloc(4);
buffer.write(',');
buffer.writeUInt8(0, 1);
const result = (0, parser_1.extractTypeTags)(buffer, 0);
expect(result.error).toBeUndefined();
expect(result.value).toBe('');
expect(result.nextOffset).toBe(4);
});
});
describe('extractArguments', () => {
it('should extract integer arguments', () => {
const buffer = Buffer.alloc(8);
buffer.writeInt32BE(123, 0);
buffer.writeInt32BE(456, 4);
const result = (0, parser_1.extractArguments)(buffer, 0, 'ii');
expect(result.error).toBeUndefined();
expect(result.value).toEqual([123, 456]);
});
it('should extract float arguments', () => {
const buffer = Buffer.alloc(8);
buffer.writeFloatBE(1.23, 0);
buffer.writeFloatBE(4.56, 4);
const result = (0, parser_1.extractArguments)(buffer, 0, 'ff');
expect(result.error).toBeUndefined();
expect(result.value).toHaveLength(2);
expect(result.value[0]).toBeCloseTo(1.23);
expect(result.value[1]).toBeCloseTo(4.56);
});
it('should extract string arguments', () => {
const buffer = Buffer.alloc(12);
let offset = 0;
buffer.write('hi', offset);
buffer.writeUInt8(0, offset + 2);
offset += 4;
buffer.write('test', offset);
buffer.writeUInt8(0, offset + 4);
const result = (0, parser_1.extractArguments)(buffer, 0, 'ss');
expect(result.error).toBeUndefined();
expect(result.value).toEqual(['hi', 'test']);
});
it('should extract blob arguments', () => {
const buffer = Buffer.alloc(12);
let offset = 0;
buffer.writeInt32BE(4, offset);
offset += 4;
buffer.writeUInt8(1, offset++);
buffer.writeUInt8(2, offset++);
buffer.writeUInt8(3, offset++);
buffer.writeUInt8(4, offset++);
const result = (0, parser_1.extractArguments)(buffer, 0, 'b');
expect(result.error).toBeUndefined();
expect(result.value).toHaveLength(1);
expect(Buffer.isBuffer(result.value[0])).toBe(true);
expect(result.value[0]).toEqual(Buffer.from([1, 2, 3, 4]));
});
it('should return error for insufficient data', () => {
const buffer = Buffer.alloc(2);
const result = (0, parser_1.extractArguments)(buffer, 0, 'i');
expect(result.value).toBeUndefined();
expect(result.error).toBeDefined();
expect(result.error.code).toBe(index_1.ErrorCode.INVALID_OSC_MESSAGE);
});
it('should handle mixed argument types', () => {
const buffer = Buffer.alloc(16);
let offset = 0;
buffer.writeInt32BE(42, offset);
offset += 4;
buffer.writeFloatBE(3.14, offset);
offset += 4;
buffer.write('hi', offset);
buffer.writeUInt8(0, offset + 2);
offset += 4;
const result = (0, parser_1.extractArguments)(buffer, 0, 'ifs');
expect(result.error).toBeUndefined();
expect(result.value).toHaveLength(3);
expect(result.value[0]).toBe(42);
expect(result.value[1]).toBeCloseTo(3.14);
expect(result.value[2]).toBe('hi');
});
});
describe('isValidOSCMessage', () => {
it('should return true for potentially valid OSC message', () => {
const buffer = Buffer.alloc(12);
buffer.write('/test');
buffer.writeUInt8(0, 5);
buffer.write(',', 8);
buffer.writeUInt8(0, 9);
expect((0, parser_1.isValidOSCMessage)(buffer)).toBe(true);
});
it('should return false for message too short', () => {
const buffer = Buffer.alloc(4);
buffer.write('/hi');
expect((0, parser_1.isValidOSCMessage)(buffer)).toBe(false);
});
it('should return false for message not starting with /', () => {
const buffer = Buffer.alloc(12);
buffer.write('test');
expect((0, parser_1.isValidOSCMessage)(buffer)).toBe(false);
});
});
});
//# sourceMappingURL=parser.test.js.map