import { test } from 'node:test'; import assert from 'node:assert/strict'; import { extractFrameFromBuffer, parseFrameParam } from '../src/dimse/frameExtractor'; import { BadRequestError, HttpError, statusCodeForError, UnsupportedMediaTypeError } from '../src/dimse/errors'; import { buildMonochromeImage } from './helpers/dicomWriter'; function twoFrameImage() { return buildMonochromeImage({ rows: 2, columns: 2, bitsAllocated: 8, samplesPerPixel: 1, numberOfFrames: 2, pixelData: [1, 2, 3, 4, 5, 6, 7, 8], }); } test('/frames/1 returns only the first frame byte range', () => { const extracted = extractFrameFromBuffer(twoFrameImage(), 1); assert.deepEqual([...extracted.buffer], [1, 2, 3, 4]); assert.equal(extracted.frameSize, 4); assert.equal(extracted.numberOfFrames, 2); }); test('/frames/2 returns only the second frame byte range', () => { const extracted = extractFrameFromBuffer(twoFrameImage(), 2); assert.deepEqual([...extracted.buffer], [5, 6, 7, 8]); }); test('/frames/2 for a single-frame instance is rejected with 400', () => { const singleFrame = buildMonochromeImage({ rows: 2, columns: 2, bitsAllocated: 8, pixelData: [1, 2, 3, 4], }); assert.throws( () => extractFrameFromBuffer(singleFrame, 2), (error: unknown) => error instanceof BadRequestError && statusCodeForError(error) === 400, ); }); test('extracts 16-bit frames with the correct byte offsets', () => { const image = buildMonochromeImage({ rows: 2, columns: 2, bitsAllocated: 16, samplesPerPixel: 1, numberOfFrames: 2, pixelData: [256, 257, 258, 259, 260, 261, 262, 263], }); const second = extractFrameFromBuffer(image, 2); const values = [0, 2, 4, 6].map((offset) => second.buffer.readUInt16LE(offset)); assert.deepEqual(values, [260, 261, 262, 263]); }); test('rejects out-of-range and zero frame numbers with 400', () => { const image = twoFrameImage(); assert.throws( () => extractFrameFromBuffer(image, 0), (error: unknown) => error instanceof BadRequestError, ); assert.throws( () => extractFrameFromBuffer(image, 3), (error: unknown) => error instanceof BadRequestError, ); }); test('rejects compressed transfer syntax with an explicit unsupported response', () => { const image = buildMonochromeImage({ rows: 2, columns: 2, bitsAllocated: 8, numberOfFrames: 2, pixelData: [1, 2, 3, 4, 5, 6, 7, 8], transferSyntaxUID: '1.2.840.10008.1.2.4.80', }); assert.throws( () => extractFrameFromBuffer(image, 2), (error: unknown) => error instanceof UnsupportedMediaTypeError && statusCodeForError(error) === 415, ); }); test('treats a too-short Pixel Data element as a 500 data error', () => { const image = buildMonochromeImage({ rows: 4, columns: 4, bitsAllocated: 8, pixelData: [1, 2, 3, 4], }); assert.throws( () => extractFrameFromBuffer(image, 1), (error: unknown) => error instanceof HttpError && statusCodeForError(error) === 500, ); }); test('parseFrameParam accepts only positive base-10 integers', () => { assert.equal(parseFrameParam('1'), 1); assert.equal(parseFrameParam('42'), 42); assert.equal(parseFrameParam('0'), undefined); assert.equal(parseFrameParam('-1'), undefined); assert.equal(parseFrameParam('abc'), undefined); assert.equal(parseFrameParam('1.5'), undefined); assert.equal(parseFrameParam(' 1'), undefined); assert.equal(parseFrameParam(''), undefined); assert.equal(parseFrameParam(undefined), undefined); });