diff --git a/demo/components/testFunctions/testColorRois.ts b/demo/components/testFunctions/testColorRois.ts index c5b7df8f7..1e59613e0 100644 --- a/demo/components/testFunctions/testColorRois.ts +++ b/demo/components/testFunctions/testColorRois.ts @@ -1,5 +1,5 @@ import { Image } from '../../../src/index.js'; -import { fromMask, colorRois } from '../../../src/roi/index.js'; +import { colorRois, fromMask } from '../../../src/roi/index.js'; /** * Make a mask out of the image and detect all ROIs. Returns only the white ROIs on a black background. diff --git a/demo/components/testFunctions/testCorrectColor.ts b/demo/components/testFunctions/testCorrectColor.ts index f3442c43c..b7630ed0b 100644 --- a/demo/components/testFunctions/testCorrectColor.ts +++ b/demo/components/testFunctions/testCorrectColor.ts @@ -1,10 +1,10 @@ import { polishAltered } from '../../../src/correctColor/__tests__/testUtils/imageColors.js'; -import { referenceColorCard } from '../../../src/correctColor/utils/referenceColorCard.ts'; import { correctColor } from '../../../src/correctColor/correctColor.js'; import { getMeasuredColors, getReferenceColors, } from '../../../src/correctColor/utils/formatData.js'; +import { referenceColorCard } from '../../../src/correctColor/utils/referenceColorCard.ts'; import type { Image } from '../../../src/index.js'; /** diff --git a/demo/components/testFunctions/testExtract.ts b/demo/components/testFunctions/testExtract.ts index be6c521b4..29dcb6134 100644 --- a/demo/components/testFunctions/testExtract.ts +++ b/demo/components/testFunctions/testExtract.ts @@ -1,4 +1,4 @@ -import { fromMask, Image } from '../../../src/index.js'; +import { Image, fromMask } from '../../../src/index.js'; /** * Extract the pixels of a mask from the image. diff --git a/demo/components/testFunctions/testGetBorderPoints.ts b/demo/components/testFunctions/testGetBorderPoints.ts index 2a44f23e4..7bd4e27fb 100644 --- a/demo/components/testFunctions/testGetBorderPoints.ts +++ b/demo/components/testFunctions/testGetBorderPoints.ts @@ -1,5 +1,5 @@ import type { Image } from '../../../src/index.js'; -import { fromMask, Mask } from '../../../src/index.js'; +import { Mask, fromMask } from '../../../src/index.js'; /** * Paint the border of the larger black ROI on the image. * @param image - The image to process diff --git a/package.json b/package.json index fa8a72b88..7640ef46b 100644 --- a/package.json +++ b/package.json @@ -43,46 +43,46 @@ "ml-ransac": "^1.0.0", "ml-regression-multivariate-linear": "^2.0.4", "ml-regression-polynomial-2d": "^1.0.0", - "ml-spectra-processing": "^14.12.0", + "ml-spectra-processing": "^14.14.0", "robust-point-in-polygon": "^1.0.3", "ssim.js": "^3.5.0", - "tiff": "^7.0.0", + "tiff": "^7.1.0", "ts-pattern": "^5.7.1", "uint8-base64": "^1.0.0" }, "devDependencies": { - "@microsoft/api-extractor": "^7.52.8", + "@microsoft/api-extractor": "^7.52.9", "@tailwindcss/forms": "^0.5.10", - "@tailwindcss/vite": "^4.1.10", + "@tailwindcss/vite": "^4.1.11", "@types/jest-image-snapshot": "^6.4.0", "@types/js-priority-queue": "^0.0.9", - "@types/node": "^24.0.1", + "@types/node": "^24.1.0", "@types/react": "^19.1.8", "@types/react-dom": "^19.1.6", "@types/robust-point-in-polygon": "^1.0.4", - "@vitejs/plugin-react": "^4.5.2", - "@vitest/coverage-v8": "^3.2.3", - "@vitest/expect": "^3.2.3", - "@zakodium/tsconfig": "^1.0.1", + "@vitejs/plugin-react": "^4.7.0", + "@vitest/coverage-v8": "^3.2.4", + "@vitest/expect": "^3.2.4", + "@zakodium/tsconfig": "^1.0.2", "autoprefixer": "^10.4.21", "clsx": "^2.1.1", "cross-env": "^7.0.3", - "eslint": "^9.29.0", - "eslint-config-cheminfo-react": "^16.1.0", - "eslint-config-cheminfo-typescript": "^18.0.1", + "eslint": "^9.31.0", + "eslint-config-cheminfo-react": "^17.0.1", + "eslint-config-cheminfo-typescript": "^19.0.0", "immer": "^10.1.1", "jest-image-snapshot": "^6.5.1", "jest-matcher-deep-close-to": "^3.0.2", - "postcss": "^8.5.5", - "prettier": "^3.5.3", + "postcss": "^8.5.6", + "prettier": "^3.6.2", "react": "^19.1.0", "react-dom": "^19.1.0", - "react-router-dom": "^7.6.2", + "react-router-dom": "^7.7.1", "rimraf": "^6.0.1", - "tailwindcss": "^4.1.10", + "tailwindcss": "^4.1.11", "typescript": "~5.8.3", - "vite": "^6.3.5", - "vitest": "^3.2.3" + "vite": "^7.0.6", + "vitest": "^3.2.4" }, "repository": { "type": "git", diff --git a/scripts/featureMatching/featureMatchingTest.ts b/scripts/featureMatching/featureMatchingTest.ts index 374a3d574..208965158 100644 --- a/scripts/featureMatching/featureMatchingTest.ts +++ b/scripts/featureMatching/featureMatchingTest.ts @@ -2,16 +2,16 @@ import util from 'node:util'; import type { GetBriefOptions } from '../../src/featureMatching/descriptors/getBrief.js'; import { getBrief } from '../../src/featureMatching/descriptors/getBrief.js'; +import type { + DrawKeypointsOptions, + GetColorsOptions, +} from '../../src/index.js'; import { - getCrosscheckMatches, Montage, + getCrosscheckMatches, readSync, writeSync, } from '../../src/index.js'; -import type { - DrawKeypointsOptions, - GetColorsOptions, -} from '../../src/index.js'; import { getMinMax } from '../../src/utils/getMinMax.js'; util.inspect.defaultOptions.depth = 5; diff --git a/src/Image.ts b/src/Image.ts index ca73c48a4..f959db687 100644 --- a/src/Image.ts +++ b/src/Image.ts @@ -4,15 +4,15 @@ import { match } from 'ts-pattern'; import type { Mask } from './Mask.js'; import type { DivideOptions } from './compare/divide.js'; import { divide } from './compare/divide.js'; -import { add, subtract } from './compare/index.js'; import type { SubtractImageOptions } from './compare/index.js'; +import { add, subtract } from './compare/index.js'; import type { MultiplyOptions } from './compare/multiply.js'; import { multiply } from './compare/multiply.js'; import type { - MedianOptions, + HistogramOptions, MeanOptions, + MedianOptions, VarianceOptions, - HistogramOptions, } from './compute/index.js'; import { histogram, mean, median, variance } from './compute/index.js'; import { correctColor } from './correctColor/index.js'; diff --git a/src/Mask.ts b/src/Mask.ts index c8f226400..2ea4049f4 100644 --- a/src/Mask.ts +++ b/src/Mask.ts @@ -1,13 +1,6 @@ import type { BitDepth, Image } from './Image.js'; import type { SubtractImageOptions } from './compare/index.js'; import { subtract } from './compare/index.js'; -import { - drawLineOnMask, - drawPoints, - drawPolygonOnMask, - drawPolylineOnMask, - drawRectangle, -} from './draw/index.js'; import type { DrawLineOnMaskOptions, DrawPointsOptions, @@ -15,6 +8,13 @@ import type { DrawPolylineOnMaskOptions, DrawRectangleOptions, } from './draw/index.js'; +import { + drawLineOnMask, + drawPoints, + drawPolygonOnMask, + drawPolylineOnMask, + drawRectangle, +} from './draw/index.js'; import type { AndOptions, InvertOptions, OrOptions } from './filters/index.js'; import { and, invert, or } from './filters/index.js'; import { getBorderPoints } from './maskAnalysis/getBorderPoints.js'; diff --git a/src/__tests__/Image.test.ts b/src/__tests__/Image.test.ts index 1192ad974..22c827284 100644 --- a/src/__tests__/Image.test.ts +++ b/src/__tests__/Image.test.ts @@ -1,5 +1,7 @@ import { inspect } from 'node:util'; +import { describe, expect, it, test } from 'vitest'; + import type { ImageCoordinates } from '../Image.js'; import { Image } from '../Image.js'; import type { Point } from '../geometry/index.js'; @@ -7,6 +9,7 @@ import type { Point } from '../geometry/index.js'; describe('create new images', () => { it('should create a 8-bit image', () => { const img = new Image(10, 20); + expect(img).toMatchObject({ width: 10, height: 20, @@ -23,6 +26,7 @@ describe('create new images', () => { it('should create a 16-bit image', () => { const img = new Image(10, 20, { bitDepth: 16 }); + expect(img).toMatchObject({ width: 10, height: 20, @@ -39,6 +43,7 @@ describe('create new images', () => { it('should create a grey image with alpha', () => { const img = new Image(10, 20, { colorModel: 'GREYA' }); + expect(img).toMatchObject({ bitDepth: 8, colorModel: 'GREYA', @@ -56,6 +61,7 @@ describe('create new images', () => { 3, 4, 5 ]); const img = new Image(3, 2, { data, colorModel: 'GREY' }); + expect(img.getValue(0, 1, 0)).toBe(3); expect(img.getRawImage().data).toBe(data); }); @@ -80,6 +86,7 @@ describe('create new images', () => { it('should throw on wrong data size', () => { const data = new Uint16Array(2); + expect(() => new Image(2, 2, { data, bitDepth: 16 })).toThrow( /incorrect data size: 2. Expected 12/, ); @@ -94,12 +101,15 @@ describe('create new images', () => { it('should throw with bit depth 8 but data 16', () => { const data = new Uint16Array([1, 2, 3, 4]); + expect(() => new Image(2, 2, { colorModel: 'GREY', data })).toThrow( 'bitDepth is 8 but data is Uint16Array', ); }); + it('should throw with bit depth 16 but data 8', () => { const data = new Uint8Array([1, 2, 3, 4]); + expect( () => new Image(2, 2, { @@ -114,15 +124,21 @@ describe('create new images', () => { describe('get and set pixels', () => { it('should get and set', () => { const img = new Image(10, 20); + expect(img.getPixel(5, 15)).toStrictEqual([0, 0, 0]); + img.setPixel(5, 15, [1, 3, 5]); + expect(img.getPixel(5, 15)).toStrictEqual([1, 3, 5]); }); it('should get and set by index', () => { const img = new Image(10, 20); + expect(img.getPixelByIndex(5)).toStrictEqual([0, 0, 0]); + img.setPixelByIndex(5, [1, 3, 5]); + expect(img.getPixelByIndex(5)).toStrictEqual([1, 3, 5]); }); @@ -131,44 +147,64 @@ describe('get and set pixels', () => { [1, 2, 3], [4, 5, 6], ]); + expect(img.getPixelByIndex(0)).toStrictEqual([1]); expect(img.getPixelByIndex(4)).toStrictEqual([5]); }); it('should get and set value', () => { const img = new Image(10, 20); + expect(img.getValue(5, 15, 0)).toBe(0); + img.setValue(5, 15, 0, 50); + expect(img.getValue(5, 15, 0)).toBe(50); }); it('should get and set value by index', () => { const img = new Image(10, 20); + expect(img.getValueByIndex(15, 0)).toBe(0); + img.setValueByIndex(15, 0, 50); + expect(img.getValueByIndex(15, 0)).toBe(50); }); it('should get and set value by point', () => { const point = { column: 15, row: 0 }; const img = new Image(10, 20); + expect(img.getValueByPoint(point, 0)).toBe(0); + img.setValueByPoint(point, 0, 50); + expect(img.getValueByPoint(point, 0)).toBe(50); }); + it('should set clamped value', () => { const img = new Image(10, 20); img.setClampedValue(15, 0, 0, -50); + expect(img.getValue(15, 0, 0)).toBe(0); + img.setClampedValue(15, 0, 0, 99999); + expect(img.getValue(15, 0, 0)).toBe(img.maxValue); }); + it('should set clamped value by index', () => { const img = new Image(10, 20); + expect(img.getValueByIndex(15, 0)).toBe(0); + img.setClampedValueByIndex(15, 0, -50); + expect(img.getValueByIndex(15, 0)).toBe(0); + img.setClampedValueByIndex(15, 0, 999999); + expect(img.getValueByIndex(15, 0)).toBe(img.maxValue); }); }); @@ -176,6 +212,7 @@ describe('get and set pixels', () => { test('createFrom', () => { const img = new Image(2, 20, { colorModel: 'GREY' }); const newImg = Image.createFrom(img); + expect(img.width).toBe(newImg.width); expect(img.height).toBe(newImg.height); expect(img.colorModel).toBe(newImg.colorModel); @@ -186,6 +223,7 @@ test('clone', () => { const img = new Image(2, 2, { colorModel: 'GREY' }); img.setValue(1, 0, 0, 50); const copy = img.clone(); + expect(copy).toMatchImage(img); }); @@ -193,6 +231,7 @@ test('changeEach', () => { const img = new Image(1, 2); let i = 0; img.changeEach(() => i++); + expect(img).toMatchImageData([ [0, 1, 2], [3, 4, 5], @@ -207,11 +246,13 @@ test.each<[ImageCoordinates, Point]>([ ['top-right', { column: 3, row: 0 }], ])('getCoordinates - %s', (coordinates, point) => { const img = new Image(4, 5); + expect(img.getCoordinates(coordinates)).toStrictEqual(point); }); test('getCoordinates - with rounding', () => { const img = new Image(4, 5); + expect(img.getCoordinates('center', true)).toStrictEqual({ column: 2, row: 2, @@ -220,6 +261,7 @@ test('getCoordinates - with rounding', () => { test('getCoordinates - bad parameter', () => { const img = new Image(4, 5); + // @ts-expect-error bad parameter expect(() => img.getCoordinates('bad')).toThrow('bad'); }); @@ -227,6 +269,7 @@ test('getCoordinates - bad parameter', () => { test('fill with a constant color', () => { const img = new Image(2, 2); img.fill(50); + expect(img).toMatchImageData([ [50, 50, 50, 50, 50, 50], [50, 50, 50, 50, 50, 50], @@ -236,6 +279,7 @@ test('fill with a constant color', () => { test('fill with a float value', () => { const img = new Image(2, 2); img.fill(10.7); + expect(img).toMatchImageData([ [10, 10, 10, 10, 10, 10], [10, 10, 10, 10, 10, 10], @@ -245,6 +289,7 @@ test('fill with a float value', () => { test('fill with a color as RGBA array', () => { const img = new Image(1, 2); img.fill([1, 2, 3]); + expect(img).toMatchImageData([ [1, 2, 3], [1, 2, 3], @@ -253,6 +298,7 @@ test('fill with a color as RGBA array', () => { test('fill with out of range value', () => { const img = new Image(1, 1); + expect(() => img.fill(256)).toThrow( /invalid value: 256. It must be a positive value smaller than 256/, ); @@ -260,6 +306,7 @@ test('fill with out of range value', () => { test('fill with out of range value in array', () => { const img = new Image(1, 1); + expect(() => img.fill([0, -1, 2])).toThrow( /invalid value: -1. It must be a positive value smaller than 256/, ); @@ -267,6 +314,7 @@ test('fill with out of range value in array', () => { test('fill with channel mismatch', () => { const img = new Image(1, 1); + expect(() => img.fill([0, 1, 2, 3])).toThrow( /the size of value must match the number of channels \(3\). Received 4/, ); @@ -275,6 +323,7 @@ test('fill with channel mismatch', () => { test('fill channel 0', () => { const img = new Image(1, 2); img.fillChannel(0, 50); + expect(img).toMatchImageData([ [50, 0, 0], [50, 0, 0], @@ -284,6 +333,7 @@ test('fill channel 0', () => { test('fill channel 2', () => { const img = new Image(1, 2); img.fillChannel(2, 50); + expect(img).toMatchImageData([ [0, 0, 50], [0, 0, 50], @@ -292,6 +342,7 @@ test('fill channel 2', () => { test('fill channel invalid channel', () => { const img = new Image(1, 2); + expect(() => img.fillChannel(4, 50)).toThrow( /invalid channel: 4. It must be a positive integer smaller than 3/, ); @@ -320,11 +371,14 @@ test('get channel', () => { test('fill alpha', () => { const img = new Image(1, 2, { colorModel: 'RGBA' }); img.fillAlpha(0); + expect(img).toMatchImageData([ [0, 0, 0, 0], [0, 0, 0, 0], ]); + img.fillAlpha(50); + expect(img).toMatchImageData([ [0, 0, 0, 50], [0, 0, 0, 50], @@ -333,6 +387,7 @@ test('fill alpha', () => { test('fill alpha should throw if no alpha', () => { const img = new Image(1, 1); + expect(() => img.fillAlpha(50)).toThrow( /fillAlpha can only be called if the image has an alpha channel/, ); @@ -367,6 +422,7 @@ test('check getColumn and getRow methods on an RGBA image', () => { const resultRow = image.getRow(2); const resultColumn = image.getColumn(0); + expect(resultRow).toStrictEqual([[11], [2], [2], [2]]); expect(resultColumn).toStrictEqual([ [1, 1, 11, 1, 1], @@ -375,6 +431,7 @@ test('check getColumn and getRow methods on an RGBA image', () => { [1, 1, 2, 3, 3], ]); }); + test('check getColumn and getRow methods', () => { const image = testUtils.createGreyImage([ [1, 5, 1], @@ -384,6 +441,7 @@ test('check getColumn and getRow methods', () => { const resultRow = image.getRow(2); const resultColumn = image.getColumn(0); + expect(resultRow).toStrictEqual([[11, 2, 2]]); expect(resultColumn).toStrictEqual([[1, 1, 11]]); }); diff --git a/src/__tests__/Mask.test.ts b/src/__tests__/Mask.test.ts index 02a81024f..067981c59 100644 --- a/src/__tests__/Mask.test.ts +++ b/src/__tests__/Mask.test.ts @@ -1,11 +1,14 @@ import util from 'node:util'; +import { describe, expect, it, test } from 'vitest'; + import { Mask } from '../Mask.js'; import type { Point } from '../utils/geometry/points.js'; describe('create new masks', () => { it('should create a mask', () => { const mask = new Mask(10, 20); + expect(mask).toMatchObject({ width: 10, height: 20, @@ -19,6 +22,7 @@ describe('create new masks', () => { }); expect(mask.getRawImage().data).toHaveLength(200); }); + it('should throw on wrong width', () => { expect(() => new Mask(0, 1)).toThrow( /width must be an integer and at least 1. Received 0/, @@ -27,6 +31,7 @@ describe('create new masks', () => { /width must be an integer and at least 1. Received 0.5/, ); }); + it('should throw on wrong height', () => { expect(() => new Mask(1, 0)).toThrow( /height must be an integer and at least 1. Received 0/, @@ -35,8 +40,10 @@ describe('create new masks', () => { /height must be an integer and at least 1. Received 0.5/, ); }); + it('should throw on wrong data size', () => { const data = new Uint8Array(2); + expect(() => new Mask(2, 2, { data })).toThrow( /incorrect data size: 2. Expected 4/, ); @@ -46,21 +53,32 @@ describe('create new masks', () => { describe('get and set bit', () => { it('should get and set', () => { const mask = new Mask(10, 20); + expect(mask.getBit(5, 15)).toBe(0); + mask.setBit(5, 15, 1); + expect(mask.getBit(5, 15)).toBe(1); }); + it('should get and set by index', () => { const mask = new Mask(10, 20); + expect(mask.getBitByIndex(15)).toBe(0); + mask.setBitByIndex(15, 1); + expect(mask.getBitByIndex(15)).toBe(1); }); + it('should get and set value by point', () => { const point = { column: 15, row: 0 }; const mask = new Mask(10, 20); + expect(mask.getValueByPoint(point)).toBe(0); + mask.setValueByPoint(point, 1); + expect(mask.getValueByPoint(point)).toBe(1); expect(mask.getNbNonZeroPixels()).toBe(1); }); @@ -69,18 +87,27 @@ describe('get and set bit', () => { describe('get and set value', () => { it('should get and set', () => { const mask = new Mask(10, 20); + expect(mask.getValue(5, 15, 0)).toBe(0); + mask.setValue(5, 15, 0, 1); + expect(mask.getValue(5, 15, 0)).toBe(1); }); + it('should get and set by index', () => { const mask = new Mask(10, 20); + expect(mask.getValueByIndex(15, 0)).toBe(0); + mask.setValueByIndex(15, 0, 1); + expect(mask.getValueByIndex(15, 0)).toBe(1); }); + it('wrong channel value', () => { const mask = new Mask(10, 20); + expect(() => { mask.getValue(2, 1, 2); }).toThrow(/channel value must be 0 on type Mask. Received 2/); @@ -90,15 +117,21 @@ describe('get and set value', () => { describe('get and set pixels', () => { it('should get and set', () => { const img = new Mask(10, 20); + expect(img.getPixel(5, 15)).toStrictEqual([0]); + img.setPixel(5, 15, [1]); + expect(img.getPixel(5, 15)).toStrictEqual([1]); }); it('should get and set by index', () => { const img = new Mask(10, 20); + expect(img.getPixelByIndex(5)).toStrictEqual([0]); + img.setPixelByIndex(5, [1]); + expect(img.getPixelByIndex(5)).toStrictEqual([1]); }); }); @@ -106,6 +139,7 @@ describe('get and set pixels', () => { test('fill with a value', () => { const mask = new Mask(2, 2); mask.fill(1); + expect(mask).toMatchMaskData([ [1, 1], [1, 1], @@ -117,6 +151,7 @@ test('createFrom', () => { const mask = new Mask(2, 20); const newMask = Mask.createFrom(mask); + expect(mask.width).toBe(newMask.width); expect(mask.height).toBe(newMask.height); expect(mask.origin).toStrictEqual(newMask.origin); @@ -124,6 +159,7 @@ test('createFrom', () => { test('fromPoints', () => { const points: Point[] = [{ column: 1, row: 1 }]; + expect(Mask.fromPoints(5, 3, points)).toMatchMaskData([ [0, 0, 0, 0, 0], [0, 1, 0, 0, 0], @@ -135,6 +171,7 @@ test('clone', () => { const mask = new Mask(2, 2); mask.setBit(1, 0, 1); const copy = mask.clone(); + expect(copy).toMatchMask(mask); }); @@ -146,5 +183,6 @@ test('check custom inspect', () => { test('check custom inspect with image too large', () => { const image = new Mask(25, 25); + expect(util.inspect(image)).toMatchSnapshot(); }); diff --git a/src/__tests__/Stack.test.ts b/src/__tests__/Stack.test.ts index ec703cb5a..d4817cc5c 100644 --- a/src/__tests__/Stack.test.ts +++ b/src/__tests__/Stack.test.ts @@ -1,3 +1,5 @@ +import { describe, expect, it, test } from 'vitest'; + import { Image } from '../Image.js'; import { Stack } from '../Stack.js'; @@ -7,6 +9,7 @@ describe('Stack constructor', () => { const stack = new Stack([image]); const images = stack.getImages(); + expect(stack).toBeInstanceOf(Stack); expect(images).toHaveLength(1); expect(images[0]).toBeInstanceOf(Image); @@ -22,6 +25,7 @@ describe('Stack constructor', () => { it('should throw if color model is different', () => { const image1 = testUtils.createGreyImage([[1, 2, 3, 4]]); const image2 = testUtils.createRgbaImage([[1, 2, 3, 4]]); + expect(() => { return new Stack([image1, image2]); }).toThrow('images must all have the same bit depth and color model'); @@ -30,6 +34,7 @@ describe('Stack constructor', () => { it('should throw if bit depths different', () => { const image1 = testUtils.createGreyImage([[1, 2, 3, 4]], { bitDepth: 8 }); const image2 = testUtils.createGreyImage([[1, 2, 3, 4]], { bitDepth: 16 }); + expect(() => { return new Stack([image1, image2]); }).toThrow('images must all have the same bit depth and color model'); @@ -38,6 +43,7 @@ describe('Stack constructor', () => { test('iterator', () => { expect.assertions(2); + const image = testUtils.createGreyImage([[1, 2, 3, 4]]); const stack = new Stack([image, image]); @@ -50,16 +56,18 @@ test('clone', () => { const image = testUtils.createGreyImage([[1, 2, 3, 4]]); const stack = new Stack([image]); const clone = stack.clone(); + expect(clone).toBeInstanceOf(Stack); expect(clone).not.toBe(stack); expect(clone.getImages()[0]).toBeInstanceOf(Image); expect(clone.getImages()[0]).not.toBe(image); - expect(clone.getImages()[0]).toEqual(image); + expect(clone.getImages()[0]).toStrictEqual(image); }); test('getImage', () => { const image = testUtils.createGreyImage([[1, 2, 3, 4]]); const stack = new Stack([image]); + expect(stack.getImage(0)).toBe(image); }); @@ -67,6 +75,7 @@ describe('get values from stack', () => { it('getValue on grey image', () => { const image = testUtils.createGreyImage([[1, 2, 3, 4]]); const stack = new Stack([image]); + expect(stack.getValue(0, 0, 0, 0)).toBe(1); }); @@ -74,12 +83,14 @@ describe('get values from stack', () => { const image1 = testUtils.createRgbImage([[1, 2, 3]]); const image2 = testUtils.createRgbImage([[4, 5, 6]]); const stack = new Stack([image1, image2]); + expect(stack.getValue(1, 0, 0, 1)).toBe(5); }); it('getValueByIndex', () => { const image = testUtils.createGreyImage([[1, 2, 3, 4]]); const stack = new Stack([image]); + expect(stack.getValueByIndex(0, 1, 0)).toBe(2); }); }); @@ -89,6 +100,7 @@ test('level the images with map', () => { const image2 = testUtils.createGreyImage([[4, 5, 6, 7]]); const stack = new Stack([image1, image2]); const result = stack.map((image) => image.level()); + expect(result).not.toBe(stack); expect(result.getImage(0)).toMatchImageData([[0, 85, 170, 255]]); expect(result.getImage(1)).toMatchImageData([[0, 85, 170, 255]]); @@ -99,6 +111,7 @@ test('remove images too dark using filter', () => { const image2 = testUtils.createGreyImage([[100, 100, 100, 100]]); const stack = new Stack([image1, image2]); const result = stack.filter((image) => image.mean()[0] > 10); + expect(result).not.toBe(stack); expect(result.size).toBe(1); expect(result.getImage(0)).toMatchImageData([[100, 100, 100, 100]]); diff --git a/src/align/__tests__/alignMinDifference.test.ts b/src/align/__tests__/alignMinDifference.test.ts index df65d979c..1b7d71887 100644 --- a/src/align/__tests__/alignMinDifference.test.ts +++ b/src/align/__tests__/alignMinDifference.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import { overlapImages } from '../../featureMatching/index.js'; import { alignMinDifference } from '../alignMinDifference.js'; @@ -10,6 +12,7 @@ test('1 pixel source', () => { ]); const result = alignMinDifference(source, destination); + expect(result).toStrictEqual({ row: 2, column: 1, similarity: 1 }); }); @@ -25,6 +28,7 @@ test('4 pixels source', () => { ]); const result = alignMinDifference(source, destination); + expect(result).toStrictEqual({ row: 1, column: 1, @@ -38,6 +42,7 @@ test('twice same image', () => { const destination = testUtils.load('opencv/test.png').grey(); const result = alignMinDifference(source, destination); + expect(result).toStrictEqual({ row: 0, column: 0, similarity: 1 }); }); @@ -96,6 +101,7 @@ test('other id crops', () => { const result = alignMinDifference(source, destination); const overlap = overlapImages(source, destination, { origin: result }); + expect(overlap).toMatchImageSnapshot(); }); diff --git a/src/align/affineTransfrom/__tests__/applyAffineTransform.test.ts b/src/align/affineTransfrom/__tests__/applyAffineTransform.test.ts index 55be4a110..a9ba58f3c 100644 --- a/src/align/affineTransfrom/__tests__/applyAffineTransform.test.ts +++ b/src/align/affineTransfrom/__tests__/applyAffineTransform.test.ts @@ -1,4 +1,5 @@ import { Matrix } from 'ml-matrix'; +import { expect, test } from 'vitest'; import { applyAffineTransfom } from '../applyAffineTransform.js'; import { createAffineTransformModel } from '../createAffineTransformModel.js'; @@ -44,6 +45,7 @@ test('rectangle with scale = 2', () => { const model = createAffineTransformModel([-90, 2, 12, 2]); const result = applyAffineTransfom(source, model); + expect(expected).toStrictEqual(result); }); @@ -61,6 +63,7 @@ test('only one point', () => { const model = createAffineTransformModel([angle, -1, 0, 1 / 5]); const result = applyAffineTransfom(source, model); + // @ts-expect-error: toBeDeepCloseTo types are wrong expect(result).toBeDeepCloseTo(expected); }); diff --git a/src/align/affineTransfrom/__tests__/createAffineTransformModel.test.ts b/src/align/affineTransfrom/__tests__/createAffineTransformModel.test.ts index 01ff83cf6..0b7e5073a 100644 --- a/src/align/affineTransfrom/__tests__/createAffineTransformModel.test.ts +++ b/src/align/affineTransfrom/__tests__/createAffineTransformModel.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import { createAffineTransformModel } from '../createAffineTransformModel.js'; test('wrong nb of parameters', () => { diff --git a/src/align/affineTransfrom/__tests__/getMatrixFromPoints.test.ts b/src/align/affineTransfrom/__tests__/getMatrixFromPoints.test.ts index 279a83611..44200141e 100644 --- a/src/align/affineTransfrom/__tests__/getMatrixFromPoints.test.ts +++ b/src/align/affineTransfrom/__tests__/getMatrixFromPoints.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import { getMatrixFromPoints } from '../getMatrixFromPoints.js'; test('4 points', () => { diff --git a/src/align/affineTransfrom/__tests__/ransac.test.ts b/src/align/affineTransfrom/__tests__/ransac.test.ts index dba3c4b03..c5bc41848 100644 --- a/src/align/affineTransfrom/__tests__/ransac.test.ts +++ b/src/align/affineTransfrom/__tests__/ransac.test.ts @@ -1,4 +1,5 @@ import { ransac } from 'ml-ransac'; +import { describe, expect, it } from 'vitest'; import { affineFitFunction } from '../affineFitFunction.js'; import { applyAffineTransfom } from '../applyAffineTransform.js'; diff --git a/src/align/affineTransfrom/getAffineTransform.ts b/src/align/affineTransfrom/getAffineTransform.ts index 427384b76..822cf522d 100644 --- a/src/align/affineTransfrom/getAffineTransform.ts +++ b/src/align/affineTransfrom/getAffineTransform.ts @@ -5,10 +5,10 @@ import type { Image } from '../../Image.js'; import { getBrief } from '../../featureMatching/descriptors/getBrief.js'; import type { Match } from '../../featureMatching/index.js'; import { - bruteForceOneMatch, - getCrosscheckMatches, Montage, MontageDisposition, + bruteForceOneMatch, + getCrosscheckMatches, } from '../../featureMatching/index.js'; import { filterEuclideanDistance } from '../../featureMatching/matching/filterEuclideanDistance.js'; import type { Point } from '../../geometry/index.js'; diff --git a/src/align/affineTransfrom/utils/__tests__/getSourceWithoutMargins.test.ts b/src/align/affineTransfrom/utils/__tests__/getSourceWithoutMargins.test.ts index 5eb8bfb15..e8f86c163 100644 --- a/src/align/affineTransfrom/utils/__tests__/getSourceWithoutMargins.test.ts +++ b/src/align/affineTransfrom/utils/__tests__/getSourceWithoutMargins.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import { Image } from '../../../../Image.js'; import { getSourceWithoutMargins } from '../getSourceWithoutMargins.js'; @@ -10,6 +12,7 @@ test('destination fully in source', () => { destination, destinationOrigin, ); + expect(result.width).toBe(5); expect(result.height).toBe(5); }); @@ -23,6 +26,7 @@ test('destination would exceed source', () => { destination, destinationOrigin, ); + expect(result.width).toBe(5); expect(result.height).toBe(5); }); @@ -41,6 +45,7 @@ test('origin different than 0,0', () => { destination, destinationOrigin, ); + expect(result).toMatchImageData([ [6, 7], [10, 11], @@ -61,5 +66,6 @@ test('origin different than 0,0 and on border', () => { destination, destinationOrigin, ); + expect(result).toMatchImageData([[16]]); }); diff --git a/src/compare/__tests__/add.test.ts b/src/compare/__tests__/add.test.ts index 666afe725..32b2540f6 100644 --- a/src/compare/__tests__/add.test.ts +++ b/src/compare/__tests__/add.test.ts @@ -1,8 +1,11 @@ +import { expect, test } from 'vitest'; + import { add } from '../add.js'; test('add image to itself', () => { const image = testUtils.createRgbImage([[5, 5, 5, 10, 10, 10, 15, 15, 15]]); const other = image; + expect(add(image, other)).toMatchImageData([ [10, 10, 10, 20, 20, 20, 30, 30, 30], ]); @@ -11,6 +14,7 @@ test('add image to itself', () => { test('add two different images', () => { const image = testUtils.createRgbImage([[5, 5, 5, 10, 10, 10, 15, 15, 15]]); const other = testUtils.createRgbImage([[0, 0, 0, 20, 20, 20, 15, 15, 15]]); + expect(add(image, other)).toMatchImageData([ [5, 5, 5, 30, 30, 30, 30, 30, 30], ]); @@ -23,6 +27,7 @@ test('add two different images whose sum exceeds the maxValue', () => { const other = testUtils.createRgbImage([ [240, 200, 20, 20, 250, 20, 15, 15, 15], ]); + expect(image.add(other)).toMatchImageData([ [255, 255, 25, 30, 255, 30, 30, 30, 30], ]); @@ -35,6 +40,7 @@ test('different bitDepth should throw', () => { const other = testUtils.createRgbImage([[0, 0, 0, 20, 20, 20, 15, 15, 15]], { bitDepth: 8, }); + expect(() => { return add(image, other); }).toThrow('both images must have the same alpha and bitDepth'); @@ -43,6 +49,7 @@ test('different bitDepth should throw', () => { test('different size images should throw', () => { const image = testUtils.createRgbImage([[5, 5, 5, 10, 10, 10, 15, 15, 15]]); const other = testUtils.createRgbImage([[5, 5, 5, 10, 10, 10]]); + expect(() => { add(image, other); }).toThrow(`both images must have the same size`); @@ -51,14 +58,16 @@ test('different size images should throw', () => { test('different number of channels should throw', () => { const image = testUtils.createGreyImage([[5, 10, 15]]); const other = testUtils.createRgbImage([[1, 1, 1, 5, 5, 5, 10, 10, 10]]); + expect(() => { image.subtract(other); }).toThrow(`both images must have the same number of channels`); }); -test('different number of channels should throw', () => { +test('different number of channels should throw 2', () => { const image = testUtils.createGreyImage([[5, 10, 15]]); const other = testUtils.createRgbImage([[1, 1, 1, 5, 5, 5, 10, 10, 10]]); + expect(() => { image.subtract(other); }).toThrow(`both images must have the same number of channels`); diff --git a/src/compare/__tests__/computeDssim.test.ts b/src/compare/__tests__/computeDssim.test.ts index caae37738..bb446582f 100644 --- a/src/compare/__tests__/computeDssim.test.ts +++ b/src/compare/__tests__/computeDssim.test.ts @@ -1,15 +1,19 @@ +import { expect, test } from 'vitest'; + import { Image } from '../../Image.js'; import { computeDssim } from '../computeDssim.js'; test('twice the same image', () => { const image = testUtils.createGreyImage([[5, 5, 5, 10, 10, 10, 15, 15, 15]]); const other = image; + expect(computeDssim(image, other)).toBe(0); }); test('should be symetrical', () => { const image = testUtils.createGreyImage([[1, 2, 3, 4, 5]]); const other = testUtils.createGreyImage([[0, 0, 0, 0, 0]]); + expect(computeDssim(image, other)).toBe(computeDssim(other, image)); }); @@ -17,7 +21,7 @@ test('dssim should be 0.5', () => { const image = new Image(11, 11, { colorModel: 'GREY' }); const other = Image.createFrom(image).fill(255); - expect(image === other).toBe(false); + expect(image).not.toBe(other); expect(computeDssim(image, other)).toBeCloseTo(0.5); }); @@ -30,12 +34,14 @@ test('dssim should be 1 (anti-correlated images)', () => { [255, 255, 255], [0, 0, 0], ]); - expect(image === other).toBe(false); + + expect(image).not.toBe(other); expect(computeDssim(image, other)).toBeCloseTo(1); }); test('original with itself', () => { const original = testUtils.load('ssim/ssim-original.png'); const other = original; + expect(computeDssim(original, other)).toBe(0); }); diff --git a/src/compare/__tests__/computePsnr.test.ts b/src/compare/__tests__/computePsnr.test.ts index f1764d467..f1ae6f535 100644 --- a/src/compare/__tests__/computePsnr.test.ts +++ b/src/compare/__tests__/computePsnr.test.ts @@ -1,24 +1,32 @@ +import { expect, test } from 'vitest'; + import { computePsnr } from '../computePsnr.js'; test('twice the same image', () => { const image = testUtils.createRgbImage([[5, 5, 5, 10, 10, 10, 15, 15, 15]]); const other = image; + expect(computePsnr(image, other)).toBe(Number.POSITIVE_INFINITY); }); test('images are full of zeros', () => { const image = testUtils.createRgbImage([[0, 0, 0, 0, 0, 0]]); const other = image; + expect(computePsnr(image, other)).toBe(Number.POSITIVE_INFINITY); }); + test('should be symetrical', () => { const image = testUtils.createGreyImage([[1, 2, 3, 4, 5]]); const other = testUtils.createGreyImage([[0, 0, 0, 0, 0]]); + expect(computePsnr(image, other)).toBeCloseTo(37.717); expect(computePsnr(other, image)).toBeCloseTo(37.717); }); + test('RGBA images', () => { const image = testUtils.createRgbaImage([[50, 100, 150, 200]]); const other = testUtils.createRgbaImage([[0, 50, 100, 150]]); + expect(computePsnr(image, other)).toBe(20 * Math.log10(255 / 50)); }); diff --git a/src/compare/__tests__/computeRmse.test.ts b/src/compare/__tests__/computeRmse.test.ts index f83129a4e..b21c22019 100644 --- a/src/compare/__tests__/computeRmse.test.ts +++ b/src/compare/__tests__/computeRmse.test.ts @@ -1,25 +1,33 @@ +import { expect, test } from 'vitest'; + import { computeMse, computeRmse } from '../computeRmse.js'; test('twice the same image', () => { const image = testUtils.createRgbImage([[5, 5, 5, 10, 10, 10, 15, 15, 15]]); const other = image; + expect(computeRmse(image, other)).toBe(0); }); test('images are full of zeros', () => { const image = testUtils.createRgbImage([[0, 0, 0, 0, 0, 0]]); const other = image; + expect(computeRmse(image, other)).toBe(0); }); + test('should be symetrical', () => { const image = testUtils.createGreyImage([[1, 2, 3, 4, 5]]); const other = testUtils.createGreyImage([[0, 0, 0, 0, 0]]); + expect(computeMse(image, other)).toBe(11); expect(computeMse(other, image)).toBe(11); }); + test('RGBA images', () => { const image = testUtils.createRgbaImage([[50, 100, 150, 200]]); const other = testUtils.createRgbaImage([[0, 50, 100, 150]]); + expect(computeMse(image, other)).toBe(2500); expect(computeRmse(image, other)).toBe(50); }); diff --git a/src/compare/__tests__/computeSsim.test.ts b/src/compare/__tests__/computeSsim.test.ts index 5fdbd5b03..0843612c8 100644 --- a/src/compare/__tests__/computeSsim.test.ts +++ b/src/compare/__tests__/computeSsim.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import { Image } from '../../Image.js'; import { computeMse } from '../computeRmse.js'; import { computeSsim } from '../computeSsim.js'; @@ -5,12 +7,14 @@ import { computeSsim } from '../computeSsim.js'; test('twice the same image', () => { const image = testUtils.createGreyImage([[5, 5, 5, 10, 10, 10, 15, 15, 15]]); const other = image; + expect(computeSsim(image, other).mssim).toBe(1); }); test('should be symetrical', () => { const image = testUtils.createGreyImage([[1, 2, 3, 4, 5]]); const other = testUtils.createGreyImage([[0, 0, 0, 0, 0]]); + expect(computeSsim(image, other).mssim).toBe(computeSsim(other, image).mssim); }); @@ -18,7 +22,7 @@ test('ssim should be zero', () => { const image = new Image(11, 11, { colorModel: 'GREY' }); const other = Image.createFrom(image).fill(255); - expect(image === other).toBe(false); + expect(image).not.toBe(other); expect(computeSsim(image, other).mssim).toBeCloseTo(0, 3); }); @@ -31,13 +35,15 @@ test('ssim should be -1 (anti-correlated images)', () => { [255, 255, 255], [0, 0, 0], ]); - expect(image === other).toBe(false); + + expect(image).not.toBe(other); expect(computeSsim(image, other).mssim).toBeCloseTo(-1, 2); }); test('original with itself', () => { const original = testUtils.load('ssim/ssim-original.png'); const other = original; + expect(computeSsim(original, other).mssim).toBe(1); expect(computeMse(original, other)).toBe(0); }); @@ -47,30 +53,35 @@ test('original with itself', () => { test('more contrast', () => { const original = testUtils.load('ssim/ssim-original.png'); const other = testUtils.load('ssim/ssim-contrast.png'); + expect(computeSsim(original, other).mssim).toBeCloseTo(0.8201, 1); }); test('salt and pepper noise', () => { const original = testUtils.load('ssim/ssim-original.png'); const other = testUtils.load('ssim/ssim-saltPepper.png'); + expect(computeSsim(original, other).mssim).toBeCloseTo(0.7831); }); test('blurry', () => { const original = testUtils.load('ssim/ssim-original.png'); const other = testUtils.load('ssim/ssim-blurry.png'); + expect(computeSsim(original, other).mssim).toBeCloseTo(0.7659, 1); }); test('compressed', () => { const original = testUtils.load('ssim/ssim-original.png'); const other = testUtils.load('ssim/ssim-compressed.png'); + expect(computeSsim(original, other).mssim).toBeCloseTo(0.7178, 1); }); test('compressed, algorithm = fast', () => { const original = testUtils.load('ssim/ssim-original.png'); const other = testUtils.load('ssim/ssim-compressed.png'); + expect(computeSsim(original, other, { algorithm: 'fast' }).mssim).toBeCloseTo( 0.7178, 1, @@ -80,6 +91,7 @@ test('compressed, algorithm = fast', () => { test('compressed, algorithm = bezkrovny', () => { const original = testUtils.load('ssim/ssim-original.png'); const other = testUtils.load('ssim/ssim-compressed.png'); + expect( computeSsim(original, other, { algorithm: 'bezkrovny' }).mssim, ).toBeCloseTo(0.7178, 1); @@ -88,6 +100,7 @@ test('compressed, algorithm = bezkrovny', () => { test('compressed, algorithm = weber', () => { const original = testUtils.load('ssim/ssim-original.png'); const other = testUtils.load('ssim/ssim-compressed.png'); + expect( computeSsim(original, other, { algorithm: 'weber' }).mssim, ).toBeCloseTo(0.7178, 1); @@ -96,6 +109,7 @@ test('compressed, algorithm = weber', () => { test('should handle RGB images', () => { const original = testUtils.load('opencv/test.png'); const other = testUtils.load('opencv/testGaussianBlur.png'); + expect(computeSsim(original, other).mssim).toBeCloseTo(0.594, 2); }); @@ -104,12 +118,14 @@ test('should handle RGBA images', () => { const other = testUtils .load('opencv/testGaussianBlur.png') .convertColor('RGBA'); + expect(computeSsim(original, other).mssim).toBeCloseTo(0.594, 2); }); test('windowSize too large error', () => { const image = testUtils.createGreyImage([[5, 5, 5, 10, 10, 10, 15, 15, 15]]); const other = image; + expect(() => { computeSsim(image, other, { windowSize: 5 }); }).toThrow('windowSize cannot exceed image dimensions'); diff --git a/src/compare/__tests__/divide.test.ts b/src/compare/__tests__/divide.test.ts index b1b6718d7..0e93dfa90 100644 --- a/src/compare/__tests__/divide.test.ts +++ b/src/compare/__tests__/divide.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import { Image } from '../../Image.js'; import { divide } from '../divide.js'; @@ -11,6 +13,7 @@ test('divide by 2', () => { [115, 40, 60, 127], [50, 70, 6, 0], ]); + expect(image).toStrictEqual(result); }); @@ -19,10 +22,12 @@ test('error when dividing by 0', () => { [230, 80, 120, 255], [100, 140, 13, 1], ]); + expect(() => { divide(image, 0); }).toThrow('Cannot divide by 0'); }); + test('divide by decimal', () => { let image = testUtils.createRgbaImage([ [230, 80, 120, 255], @@ -33,8 +38,10 @@ test('divide by decimal', () => { [255, 255, 255, 255], [255, 255, 52, 16], ]); + expect(image).toStrictEqual(result); }); + test('divide by prime number', () => { let image = testUtils.createRgbaImage([ [230, 80, 120, 255], @@ -45,8 +52,10 @@ test('divide by prime number', () => { [32, 11, 17, 36], [14, 20, 1, 0], ]); + expect(image).toStrictEqual(result); }); + test('testing channels option', () => { let image = testUtils.createRgbaImage([ [230, 80, 120, 255], @@ -57,8 +66,10 @@ test('testing channels option', () => { [32, 11, 120, 36], [14, 20, 13, 0], ]); + expect(image).toStrictEqual(result); }); + test('testing out option', () => { const image = testUtils.createRgbaImage([ [230, 80, 120, 255], @@ -70,5 +81,6 @@ test('testing out option', () => { [32, 11, 17, 36], [14, 20, 1, 0], ]); + expect(out).toStrictEqual(result); }); diff --git a/src/compare/__tests__/multiply.test.ts b/src/compare/__tests__/multiply.test.ts index db50ee94a..4719cbca6 100644 --- a/src/compare/__tests__/multiply.test.ts +++ b/src/compare/__tests__/multiply.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import { Image } from '../../Image.js'; test('multiply by 2', () => { @@ -10,6 +12,7 @@ test('multiply by 2', () => { [255, 160, 240, 255], [200, 255, 26, 2], ]); + expect(image).toStrictEqual(result); }); @@ -23,8 +26,10 @@ test('mulitply by 100', () => { [255, 255, 255, 255], [255, 255, 255, 100], ]); + expect(image).toStrictEqual(result); }); + test('multiply by decimal', () => { let image = testUtils.createRgbaImage([ [230, 80, 120, 255], @@ -35,8 +40,10 @@ test('multiply by decimal', () => { [115, 40, 60, 127], [50, 70, 6, 0], ]); + expect(image).toStrictEqual(result); }); + test('testing channels option', () => { let image = testUtils.createRgbaImage([ [230, 80, 120, 255], @@ -47,8 +54,10 @@ test('testing channels option', () => { [115, 40, 120, 255], [50, 70, 13, 1], ]); + expect(image).toStrictEqual(result); }); + test('testing out option', () => { let image = testUtils.createRgbaImage([ [230, 80, 120, 255], @@ -60,5 +69,6 @@ test('testing out option', () => { [115, 40, 120, 255], [50, 70, 13, 1], ]); + expect(out).toStrictEqual(result); }); diff --git a/src/compare/__tests__/subtract.test.ts b/src/compare/__tests__/subtract.test.ts index cf26be27e..dc411a217 100644 --- a/src/compare/__tests__/subtract.test.ts +++ b/src/compare/__tests__/subtract.test.ts @@ -1,12 +1,16 @@ +import { expect, test } from 'vitest'; + test('subtract image to itself', () => { const image = testUtils.createRgbImage([[5, 5, 5, 10, 10, 10, 15, 15, 15]]); const other = image; + expect(image.subtract(other)).toMatchImageData([[0, 0, 0, 0, 0, 0, 0, 0, 0]]); }); test('absolute = false', () => { const image = testUtils.createRgbImage([[5, 5, 5, 10, 10, 10, 15, 15, 15]]); const other = testUtils.createRgbImage([[0, 0, 0, 20, 20, 20, 15, 15, 15]]); + expect(image.subtract(other, { absolute: false })).toMatchImageData([ [5, 5, 5, 0, 0, 0, 0, 0, 0], ]); @@ -15,6 +19,7 @@ test('absolute = false', () => { test('absolute = true', () => { const image = testUtils.createRgbImage([[5, 5, 5, 10, 10, 10, 15, 15, 15]]); const other = testUtils.createRgbImage([[0, 0, 0, 20, 20, 20, 15, 15, 15]]); + expect(image.subtract(other, { absolute: true })).toMatchImageData([ [5, 5, 5, 10, 10, 10, 0, 0, 0], ]); @@ -23,18 +28,21 @@ test('absolute = true', () => { test('subtract mask to itself', () => { const image = testUtils.createMask([[1, 1, 0, 0]]); const other = image; + expect(image.subtract(other)).toMatchMaskData([[0, 0, 0, 0]]); }); test('absolute = false with masks', () => { const image = testUtils.createMask([[1, 1, 0, 0]]); const other = testUtils.createMask([[0, 1, 1, 1]]); + expect(image.subtract(other)).toMatchMaskData([[1, 0, 0, 0]]); }); test('absolute = true with masks', () => { const image = testUtils.createMask([[1, 1, 0, 0]]); const other = testUtils.createMask([[1, 1, 1, 1]]); + expect(image.subtract(other, { absolute: true })).toMatchMaskData([ [0, 0, 1, 1], ]); @@ -43,6 +51,7 @@ test('absolute = true with masks', () => { test('difference size images should throw', () => { const image = testUtils.createRgbImage([[5, 5, 5, 10, 10, 10, 15, 15, 15]]); const other = testUtils.createRgbImage([[5, 5, 5, 10, 10, 10]]); + expect(() => { image.subtract(other); }).toThrow(`both images must have the same size`); @@ -53,6 +62,7 @@ test('different alpha should throw', () => { [5, 5, 5, 0, 10, 10, 10, 0, 15, 15, 15, 0], ]); const other = testUtils.createRgbImage([[1, 1, 1, 5, 5, 5, 10, 10, 10]]); + expect(() => { image.subtract(other); }).toThrow(`both images must have the same alpha and bitDepth`); @@ -61,6 +71,7 @@ test('different alpha should throw', () => { test('different number of channels should throw', () => { const image = testUtils.createGreyImage([[5, 10, 15]]); const other = testUtils.createRgbImage([[1, 1, 1, 5, 5, 5, 10, 10, 10]]); + expect(() => { image.subtract(other); }).toThrow(`both images must have the same number of channels`); diff --git a/src/compute/__tests__/getExtrema.test.ts b/src/compute/__tests__/getExtrema.test.ts index 2ee049a28..22f02f74a 100644 --- a/src/compute/__tests__/getExtrema.test.ts +++ b/src/compute/__tests__/getExtrema.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import { getExtrema } from '../getExtrema.js'; test('minimum of grey image from legacy code', () => { @@ -15,6 +17,7 @@ test('minimum of grey image from legacy code', () => { ]); const result = getExtrema(image, { kind: 'minimum' }); + expect(result).toStrictEqual([ { column: 3, row: 2 }, { column: 6, row: 7 }, @@ -67,6 +70,7 @@ test('maximum with square algorithm', () => { ]); const result = getExtrema(image, { kind: 'maximum', algorithm: 'square' }); + expect(result).toStrictEqual([ { column: 1, row: 1 }, { column: 2, row: 3 }, @@ -93,6 +97,7 @@ test('maximum with square algorithm with a mask option', () => { kind: 'maximum', algorithm: 'square', }); + expect(result).toStrictEqual([ { column: 1, row: 1 }, { column: 2, row: 3 }, @@ -107,6 +112,7 @@ test('testing for error handling', () => { [2, 3, 4, 0, 0], [0, 0, 0, 0, 0], ]); + //@ts-expect-error error testing expect(() => getExtrema(image, { algorithm: 'blah' })).toThrow( /unreachable: blah/, diff --git a/src/compute/__tests__/histogram.test.ts b/src/compute/__tests__/histogram.test.ts index ca467ce8a..cf0031080 100644 --- a/src/compute/__tests__/histogram.test.ts +++ b/src/compute/__tests__/histogram.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import { createImageFromData } from '../../../test/createImageFromData.js'; test('RGBA image - channel 0', () => { @@ -9,6 +11,7 @@ test('RGBA image - channel 0', () => { const expected = new Uint32Array(256); expected[230] = 1; expected[100] = 1; + expect(histogram).toStrictEqual(expected); }); @@ -20,6 +23,7 @@ test('RGBA image - channel 2', () => { const histogram = image.histogram({ channel: 2 }); const expected = new Uint32Array(256); expected[120] = 2; + expect(histogram).toStrictEqual(expected); }); @@ -32,6 +36,7 @@ test('binary image', () => { [0, 0, 0, 0, 0], ]); const histogram = image.histogram(); + expect(histogram[0]).toBe(16); expect(histogram[255]).toBe(9); }); @@ -50,7 +55,7 @@ test('grey 16-bit image', () => { ); const histogram = image.histogram(); - expect(histogram.length).toBe(2 ** 16); + expect(histogram).toHaveLength(2 ** 16); }); test('grey 16-bit image with 2 slots', () => { @@ -80,16 +85,19 @@ test('binary image with 64 slots', () => { [0, 0, 0, 0, 0], ]); const histogram = image.histogram({ channel: 0, slots: 64 }); + expect(histogram[0]).toBe(16); expect(histogram[63]).toBe(9); }); test('throw if channel option is missing', () => { const image = testUtils.load('opencv/test.png'); + expect(() => image.histogram()).toThrow( /channel option is mandatory for multi-channel images/, ); }); + test('throw if slots is not a power of 2', () => { const image = testUtils.createGreyImage([ [0, 0, 0, 0, 0], @@ -98,6 +106,7 @@ test('throw if slots is not a power of 2', () => { [0, 255, 255, 255, 0], [0, 0, 0, 0, 0], ]); + expect(() => image.histogram({ slots: 7 })).toThrow( 'slots must be a power of 2, for example: 64, 256, 1024', ); diff --git a/src/compute/__tests__/mean.test.ts b/src/compute/__tests__/mean.test.ts index d1aa5291e..41d0a610e 100644 --- a/src/compute/__tests__/mean.test.ts +++ b/src/compute/__tests__/mean.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import type { Point } from '../../geometry/index.js'; import { mean } from '../mean.js'; @@ -39,6 +41,7 @@ test('2x4 GREY image', () => { expect(result).toStrictEqual([1.5]); }); + test('mean from points', () => { const image = testUtils.createGreyImage([ [1, 2, 3, 0], @@ -53,6 +56,7 @@ test('mean from points', () => { expect(result).toStrictEqual([2]); }); + test('mean from points in rgba image', () => { const image = testUtils.createRgbaImage([ [1, 2, 3, 0], @@ -66,6 +70,7 @@ test('mean from points in rgba image', () => { expect(result).toStrictEqual([1, 2, 3, 0]); }); + test('must throw if array is empty', () => { const image = testUtils.createRgbaImage([ [1, 2, 3, 0], @@ -78,6 +83,7 @@ test('must throw if array is empty', () => { return result; }).toThrow('Array of coordinates is empty.'); }); + test("must throw if point's row is invalid.", () => { const image = testUtils.createRgbaImage([ [1, 2, 3, 0], @@ -90,6 +96,7 @@ test("must throw if point's row is invalid.", () => { return result; }).toThrow('Invalid coordinate: {column: 0, row: 2}'); }); + test("must throw if point's column is invalid.", () => { const image = testUtils.createRgbaImage([ [1, 2, 3, 0], @@ -102,6 +109,7 @@ test("must throw if point's column is invalid.", () => { return result; }).toThrow('Invalid coordinate: {column: 4, row: 1}'); }); + test('must throw if point has negative values.', () => { const image = testUtils.createRgbaImage([ [1, 2, 3, 0], diff --git a/src/compute/__tests__/median.test.ts b/src/compute/__tests__/median.test.ts index 3f41b9ee5..403ef3aa6 100644 --- a/src/compute/__tests__/median.test.ts +++ b/src/compute/__tests__/median.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import type { Point } from '../../geometry/index.js'; import { median } from '../median.js'; @@ -77,6 +79,7 @@ test('must throw if array is empty', () => { [1, 2, 3, 2], ]); const points: Point[] = []; + expect(() => { const result = image.median({ points }); return result; @@ -89,6 +92,7 @@ test("must throw if point's row is invalid", () => { [1, 2, 3, 2], ]); const points: Point[] = [{ column: 0, row: 2 }]; + expect(() => { const result = image.median({ points }); return result; @@ -101,11 +105,13 @@ test("must throw if point's column is invalid", () => { [1, 2, 3, 2], ]); const points: Point[] = [{ column: 4, row: 1 }]; + expect(() => { const result = image.median({ points }); return result; }).toThrow('Invalid coordinate: {column: 4, row: 1}'); }); + test('must throw if point has negative values.', () => { const image = testUtils.createRgbaImage([ [1, 2, 3, 0], diff --git a/src/compute/__tests__/variance.test.ts b/src/compute/__tests__/variance.test.ts index 7fc127238..baf81401a 100644 --- a/src/compute/__tests__/variance.test.ts +++ b/src/compute/__tests__/variance.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import type { Point } from '../../geometry/index.js'; import { variance } from '../variance.js'; @@ -35,39 +37,46 @@ test('variance from points', () => { expect(result).toStrictEqual([125]); }); + test('must throw if array is empty', () => { const image = testUtils.createRgbaImage([ [1, 2, 2, 2], [1, 2, 3, 2], ]); const points: Point[] = []; + expect(() => { const result = image.median({ points }); return result; }).toThrow('Array of coordinates is empty.'); }); + test("must throw if point's coordinates are invalid", () => { const image = testUtils.createGreyImage([ [1, 2, 2, 2], [1, 2, 3, 2], ]); const points: Point[] = [{ column: 0, row: 2 }]; + expect(() => { const result = image.median({ points }); return result; }).toThrow('Invalid coordinate: {column: 0, row: 2}'); }); -test("must throw if point's coordinates are invalid", () => { + +test("must throw if point's coordinates are invalid 2", () => { const image = testUtils.createGreyImage([ [1, 2, 2, 2], [1, 2, 3, 2], ]); const points: Point[] = [{ column: 4, row: 1 }]; + expect(() => { const result = image.median({ points }); return result; }).toThrow('Invalid coordinate: {column: 4, row: 1}'); }); + test('must throw if point has negative values.', () => { const image = testUtils.createRgbaImage([ [1, 2, 3, 0], diff --git a/src/correctColor/__tests__/correctColor.test.ts b/src/correctColor/__tests__/correctColor.test.ts index 36bcdbe7f..6dd8a946b 100644 --- a/src/correctColor/__tests__/correctColor.test.ts +++ b/src/correctColor/__tests__/correctColor.test.ts @@ -1,9 +1,11 @@ +import { expect, test } from 'vitest'; + import { correctColor } from '../correctColor.js'; import { getMeasuredColors, getReferenceColors } from '../utils/formatData.js'; import { getImageColors } from '../utils/getImageColors.js'; +import { referenceColorCard } from '../utils/referenceColorCard.ts'; import { polish } from './testUtils/imageColors.js'; -import { referenceColorCard } from '../utils/referenceColorCard.ts'; test('RGB image should not change', () => { const image = testUtils.createRgbImage([[0, 0, 0, 10, 10, 10, 20, 20, 20]]); diff --git a/src/correctColor/utils/formatData.ts b/src/correctColor/utils/formatData.ts index b0c843175..4449171e0 100644 --- a/src/correctColor/utils/formatData.ts +++ b/src/correctColor/utils/formatData.ts @@ -2,9 +2,10 @@ import type { RgbColor } from 'colord'; import { colord, extend } from 'colord'; import labPlugin from 'colord/plugins/lab'; -import type { ColorCard } from './referenceColorCard.ts'; import { getRegressionVariables } from '../correctColor.js'; +import type { ColorCard } from './referenceColorCard.ts'; + // We can't use ts-expect-error because it's not an error when compiling for CJS. // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore Module exports are not correctly typed. diff --git a/src/draw/__tests__/drawCircleOnImage.test.ts b/src/draw/__tests__/drawCircleOnImage.test.ts index 810202e20..b453aa045 100644 --- a/src/draw/__tests__/drawCircleOnImage.test.ts +++ b/src/draw/__tests__/drawCircleOnImage.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import { Image } from '../../Image.js'; test('draw circle image', () => { @@ -10,6 +12,7 @@ test('draw circle image', () => { const center = { row: 1, column: 1 }; const radius = 1; const expected = image.drawCircle(center, radius, { color: [255, 0, 0] }); + expect(expected).toMatchImageData([ [100, 150, 200, 255, 0, 0, 0, 100, 150], [255, 0, 0, 3, 200, 0, 255, 0, 0], @@ -28,6 +31,7 @@ test('floating point values', () => { const center = { row: 0.99, column: 0.99 }; const radius = 1; const expected = image.drawCircle(center, radius, { color: [255, 0, 0] }); + expect(expected).toMatchImageData([ [100, 150, 200, 255, 0, 0, 0, 100, 150], [255, 0, 0, 3, 200, 0, 255, 0, 0], @@ -35,6 +39,7 @@ test('floating point values', () => { ]); expect(expected).not.toBe(image); }); + test('draw filled circle image', () => { const image = testUtils.createRgbImage([ [100, 150, 200, 100, 150, 0, 0, 100, 150], @@ -48,6 +53,7 @@ test('draw filled circle image', () => { color: [255, 0, 0], fill: [1, 2, 3], }); + expect(expected).toMatchImageData([ [100, 150, 200, 255, 0, 0, 0, 100, 150], [255, 0, 0, 1, 2, 3, 255, 0, 0], @@ -68,6 +74,7 @@ test('draw circle with out parameter set to self', () => { color: [255, 0, 0, 255], out: image, }); + expect(expected).toMatchImageData([ [100, 150, 200, 1, 255, 0, 0, 255, 0, 100, 150, 55], [255, 0, 0, 255, 3, 200, 0, 3, 255, 0, 0, 255], @@ -112,6 +119,7 @@ test('draw grey circle', () => { const expected = image.drawCircle(center, radius, { color: [1], }); + expect(expected).toMatchImageData([ [0, 0, 1, 1, 1, 0], [0, 1, 0, 0, 0, 1], @@ -135,6 +143,7 @@ test('should handle points with floating values', () => { const expected = image.drawCircle(center, radius, { color: [1], }); + expect(expected).toMatchImageData([ [0, 0, 1, 1, 1, 0], [0, 1, 0, 0, 0, 1], @@ -153,6 +162,7 @@ test('negative radius error', () => { ]); const center = { row: 1, column: 1 }; const radius = -1; + expect(() => { image.drawCircle(center, radius, { color: [1], @@ -172,6 +182,7 @@ test('draw grey filled circle, radius=0', () => { color: [1], fill: [2], }); + expect(expected).toMatchImageData([ [0, 0, 0], [0, 1, 0], @@ -192,6 +203,7 @@ test('draw grey filled circle, radius=1', () => { color: [1], fill: [2], }); + expect(expected).toMatchImageData([ [0, 1, 0], [1, 2, 1], @@ -214,6 +226,7 @@ test('draw grey filled circle', () => { color: [1], fill: [2], }); + expect(expected).toMatchImageData([ [0, 0, 1, 1, 1, 0], [0, 1, 2, 2, 2, 1], @@ -243,6 +256,7 @@ test('big image not filled', () => { const expected = image.drawCircle(center, radius, { color: [1], }); + expect(expected).toMatchImageData([ [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0], @@ -315,6 +329,7 @@ test('big image filled', () => { color: [1], fill: [2], }); + expect(expected).toMatchImageData([ [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0], @@ -343,6 +358,7 @@ test('points outside image', () => { color: [1], fill: [2], }); + expect(expected).toMatchImageData([ [0, 0, 1], [0, 1, 2], @@ -359,12 +375,14 @@ test('default options', () => { const center = { row: 1, column: 1 }; const radius = 1; const expected = image.drawCircle(center, radius, { color: [1] }); + expect(expected).toMatchImageData([ [0, 1, 0], [1, 0, 1], [0, 1, 0], ]); }); + test('draw circle image with transparent color', () => { const image = testUtils.createGreyaImage([ [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], diff --git a/src/draw/__tests__/drawLineOnImage.test.ts b/src/draw/__tests__/drawLineOnImage.test.ts index e19ee1e66..58c602f2e 100644 --- a/src/draw/__tests__/drawLineOnImage.test.ts +++ b/src/draw/__tests__/drawLineOnImage.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import { Image } from '../../Image.js'; import { drawLineOnImage } from '../drawLineOnImage.js'; @@ -30,6 +32,7 @@ test('RGBA image with different alphas', () => { const from = { row: 0, column: 0 }; const to = { row: 1, column: 1 }; const result = image.drawLine(from, to, { strokeColor: [255, 0, 0, 50] }); + expect(result).toMatchImageData([ [145, 106, 141, 170, 100, 150, 0, 150], [100, 200, 5, 150, 76, 141, 0, 170], @@ -95,6 +98,7 @@ test('draw nearly horizontal line', () => { const result = image.drawLine(from, to, { strokeColor: [1], }); + expect(result).toMatchImageData([ [0, 0, 0, 0], [1, 1, 0, 0], @@ -116,6 +120,7 @@ test('draw nearly vertical line', () => { const result = image.drawLine(from, to, { strokeColor: [1], }); + expect(result).toMatchImageData([ [0, 1, 0, 0], [0, 1, 0, 0], @@ -135,6 +140,7 @@ test('should handle points with floating values', () => { const from = { row: 1.1, column: 0.1 }; const to = { row: 2.1, column: 3.1 }; const result = image.drawLine(from, to, { strokeColor: [1] }); + expect(result).toMatchImageData([ [0, 0, 0, 0], [1, 1, 0, 0], @@ -215,6 +221,7 @@ test('complicated line', () => { const result = image.drawLine(from, to, { strokeColor: [1], }); + expect(result).toMatchImageData([ [0, 0, 0, 1, 1], [0, 1, 1, 0, 0], @@ -241,6 +248,7 @@ test('big image example', () => { const result = image.drawLine(from, to, { strokeColor: [1], }); + expect(result).toMatchImageData([ [0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], @@ -327,6 +335,7 @@ test('different origin, line out of image', () => { origin: { column: 3, row: 0 }, strokeColor: [1], }); + expect(result).toMatchImageData([ [0, 0, 0, 1], [0, 0, 0, 0], diff --git a/src/draw/__tests__/drawLineOnMask.test.ts b/src/draw/__tests__/drawLineOnMask.test.ts index ea2be6c9c..094501c39 100644 --- a/src/draw/__tests__/drawLineOnMask.test.ts +++ b/src/draw/__tests__/drawLineOnMask.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import { Mask } from '../../Mask.js'; import { drawLineOnMask } from '../drawLineOnMask.js'; @@ -96,6 +98,7 @@ test('draw nearly horizontal line', () => { const from = { row: 1, column: 0 }; const to = { row: 2, column: 3 }; const expected = mask.drawLine(from, to); + expect(expected).toMatchMaskData([ [0, 0, 0, 0], [1, 1, 0, 0], @@ -115,6 +118,7 @@ test('draw horizontal line', () => { const from = { row: 1, column: 0 }; const to = { row: 1, column: 3 }; const expected = mask.drawLine(from, to); + expect(expected).toMatchMaskData([ [0, 0, 0, 0], [1, 1, 1, 1], @@ -134,6 +138,7 @@ test('draw nearly vertical line', () => { const from = { row: 0, column: 1 }; const to = { row: 3, column: 2 }; const expected = mask.drawLine(from, to); + expect(expected).toMatchMaskData([ [0, 1, 0, 0], [0, 1, 0, 0], @@ -153,6 +158,7 @@ test('draw vertical line', () => { const from = { row: 0, column: 1 }; const to = { row: 3, column: 1 }; const expected = mask.drawLine(from, to); + expect(expected).toMatchMaskData([ [0, 1, 0, 0], [0, 1, 0, 0], @@ -172,6 +178,7 @@ test('should handle points with floating values', () => { const from = { row: 1.1, column: 0.1 }; const to = { row: 2.1, column: 3.1 }; const expected = mask.drawLine(from, to); + expect(expected).toMatchMaskData([ [0, 0, 0, 0], [1, 1, 0, 0], @@ -231,6 +238,7 @@ test('3x3 mask, non-integer coordinates', () => { const from = { row: 0.5, column: 0.5 }; const to = { row: 1.5, column: 1.5 }; const result = mask.drawLine(from, to); + expect(result).toMatchMaskData([ [0, 0, 0], [0, 1, 0], @@ -249,6 +257,7 @@ test('3x3 mask, non-integer coordinates, verify symmetry', () => { const from = { row: 1.5, column: 1.5 }; const to = { row: 0.5, column: 0.5 }; const result = mask.drawLine(from, to); + expect(result).toMatchMaskData([ [0, 0, 0], [0, 1, 0], @@ -291,6 +300,7 @@ test('different origin', () => { const result = image.drawLine(from, to, { origin: { column: 1, row: 1 }, }); + expect(result).toMatchMaskData([ [1, 0, 0, 0], [1, 0, 1, 0], @@ -314,6 +324,7 @@ test('different origin, line out of mask', () => { let result = mask.drawLine(points[0], points[1], { origin: { column: 0, row: 0 }, }); + expect(result).toMatchMaskData([ [1, 0, 0, 0], [0, 1, 0, 0], @@ -324,6 +335,7 @@ test('different origin, line out of mask', () => { result = mask.drawLine(points[0], points[1], { origin: { column: 3, row: 0 }, }); + expect(result).toMatchMaskData([ [0, 0, 0, 1], [0, 0, 0, 0], diff --git a/src/draw/__tests__/drawMarker.test.ts b/src/draw/__tests__/drawMarker.test.ts index 1e32a54c4..3a832ce82 100644 --- a/src/draw/__tests__/drawMarker.test.ts +++ b/src/draw/__tests__/drawMarker.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import { Image } from '../../Image.js'; test('cross', () => { @@ -10,6 +12,7 @@ test('cross', () => { const point = { row: 2, column: 2 }; const result = image.drawMarker(point, { color: [1] }); + expect(result).toMatchImageData([ [0, 0, 0, 0], [0, 0, 1, 0], @@ -18,6 +21,7 @@ test('cross', () => { ]); expect(result).not.toBe(image); }); + test('circle', () => { const image = testUtils.createGreyImage([ [0, 0, 0, 0], @@ -28,6 +32,7 @@ test('circle', () => { const point = { row: 2, column: 2 }; const result = image.drawMarker(point, { color: [1], shape: 'circle' }); + expect(result).toMatchImageData([ [0, 0, 0, 0], [0, 0, 1, 0], @@ -36,6 +41,7 @@ test('circle', () => { ]); expect(result).not.toBe(image); }); + test('filled circle', () => { const image = testUtils.createGreyImage([ [0, 0, 0, 0], @@ -50,6 +56,7 @@ test('filled circle', () => { shape: 'circle', filled: true, }); + expect(result).toMatchImageData([ [0, 0, 0, 0], [0, 0, 1, 0], @@ -58,6 +65,7 @@ test('filled circle', () => { ]); expect(result).not.toBe(image); }); + test('square', () => { const image = testUtils.createGreyImage([ [0, 0, 0, 0], @@ -71,6 +79,7 @@ test('square', () => { color: [1], shape: 'square', }); + expect(result).toMatchImageData([ [0, 0, 0, 0], [0, 0, 0, 0], @@ -79,6 +88,7 @@ test('square', () => { ]); expect(result).not.toBe(image); }); + test('big square', () => { const image = testUtils.createGreyImage([ [0, 0, 0, 0], @@ -93,6 +103,7 @@ test('big square', () => { size: 3, shape: 'square', }); + expect(result).toMatchImageData([ [0, 0, 0, 0], [0, 1, 1, 1], @@ -101,6 +112,7 @@ test('big square', () => { ]); expect(result).not.toBe(image); }); + test('filled big square', () => { const image = testUtils.createGreyImage([ [0, 0, 0, 0], @@ -116,6 +128,7 @@ test('filled big square', () => { filled: true, shape: 'square', }); + expect(result).toMatchImageData([ [0, 0, 0, 0], [0, 1, 1, 1], @@ -124,6 +137,7 @@ test('filled big square', () => { ]); expect(result).not.toBe(image); }); + test('big triangle', () => { const image = testUtils.createGreyImage([ [0, 0, 0, 0, 0], @@ -138,6 +152,7 @@ test('big triangle', () => { size: 2, shape: 'triangle', }); + expect(result).toMatchImageData([ [0, 0, 0, 0, 0], [0, 0, 1, 0, 0], @@ -146,6 +161,7 @@ test('big triangle', () => { ]); expect(result).not.toBe(image); }); + test('filled big triangle', () => { const image = testUtils.createGreyImage([ [0, 0, 0, 0, 0], @@ -161,6 +177,7 @@ test('filled big triangle', () => { filled: true, shape: 'triangle', }); + expect(result).toMatchImageData([ [0, 0, 0, 0, 0], [0, 0, 1, 0, 0], @@ -169,6 +186,7 @@ test('filled big triangle', () => { ]); expect(result).not.toBe(image); }); + test('out parameter set to self', () => { const image = testUtils.createGreyImage([ [0, 0, 0, 0], @@ -182,6 +200,7 @@ test('out parameter set to self', () => { shape: 'square', out: image, }); + expect(result).toMatchImageData([ [0, 0, 0, 0], [0, 0, 0, 0], @@ -190,6 +209,7 @@ test('out parameter set to self', () => { ]); expect(result).toBe(image); }); + test('out to other image', () => { const out = new Image(4, 4, { colorModel: 'GREY' }); const image = testUtils.createGreyImage([ @@ -204,6 +224,7 @@ test('out to other image', () => { shape: 'square', out, }); + expect(result).toMatchImageData([ [0, 0, 0, 0], [0, 0, 0, 0], @@ -231,6 +252,7 @@ test('should handle points with floating values', () => { filled: true, shape: 'square', }); + expect(square).toMatchImageData([ [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], diff --git a/src/draw/__tests__/drawMarkers.test.ts b/src/draw/__tests__/drawMarkers.test.ts index 5bb1f708d..7bf127392 100644 --- a/src/draw/__tests__/drawMarkers.test.ts +++ b/src/draw/__tests__/drawMarkers.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import { Image } from '../../Image.js'; test('square', () => { @@ -17,6 +19,7 @@ test('square', () => { color: [1], shape: 'square', }); + expect(result).toMatchImageData([ [0, 0, 0, 0], [0, 1, 0, 0], @@ -25,6 +28,7 @@ test('square', () => { ]); expect(result).not.toBe(image); }); + test('cross', () => { const image = testUtils.createGreyImage([ [0, 0, 0, 0], @@ -38,6 +42,7 @@ test('cross', () => { ]; const result = image.drawMarkers(points, { color: [1] }); + expect(result).toMatchImageData([ [0, 1, 0, 0], [1, 1, 1, 0], @@ -46,6 +51,7 @@ test('cross', () => { ]); expect(result).not.toBe(image); }); + test('out parameter set to self', () => { const image = testUtils.createGreyImage([ [0, 0, 0, 0], @@ -63,6 +69,7 @@ test('out parameter set to self', () => { shape: 'square', out: image, }); + expect(result).toMatchImageData([ [0, 0, 0, 0], [0, 1, 0, 0], @@ -71,6 +78,7 @@ test('out parameter set to self', () => { ]); expect(result).toBe(image); }); + test('out to other image', () => { const out = new Image(4, 4, { colorModel: 'GREY' }); const image = testUtils.createGreyImage([ @@ -89,6 +97,7 @@ test('out to other image', () => { shape: 'square', out, }); + expect(result).toMatchImageData([ [0, 0, 0, 0], [0, 1, 0, 0], diff --git a/src/draw/__tests__/drawPoints.test.ts b/src/draw/__tests__/drawPoints.test.ts index 6fca18c4a..0ebef8a81 100644 --- a/src/draw/__tests__/drawPoints.test.ts +++ b/src/draw/__tests__/drawPoints.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import { Image } from '../../Image.js'; import { drawPoints } from '../drawPoints.js'; @@ -13,6 +15,7 @@ test('RGB image', () => { ]; const result = image.drawPoints(points, { color: [255, 0, 0] }); + expect(result).toMatchImageData([ [255, 0, 0, 100, 150, 200], [100, 150, 200, 255, 0, 0], @@ -158,6 +161,7 @@ test('mask', () => { { row: 0, column: 1 }, ]; const result = mask.drawPoints(points); + expect(result).toMatchMaskData([ [1, 1, 0, 0], [1, 0, 0, 0], @@ -180,6 +184,7 @@ test('default options', () => { { row: 0, column: 2 }, ]; const result = drawPoints(mask, points); + expect(result).toMatchMaskData([ [0, 0, 1, 0], [0, 0, 0, 0], @@ -203,6 +208,7 @@ test('different origin', () => { { row: 0, column: 0 }, ]; const result = drawPoints(mask, points, { origin: { column: 2, row: 2 } }); + expect(result).toMatchMaskData([ [0, 0, 0, 0], [0, 1, 1, 0], @@ -227,6 +233,7 @@ test('points outside mask', () => { { row: 2, column: 6 }, ]; const result = drawPoints(mask, points); + expect(result).toMatchMaskData([ [1, 1, 0, 0], [0, 0, 0, 0], diff --git a/src/draw/__tests__/drawPolygonOnImage.test.ts b/src/draw/__tests__/drawPolygonOnImage.test.ts index c86b4ab01..fff0546e0 100644 --- a/src/draw/__tests__/drawPolygonOnImage.test.ts +++ b/src/draw/__tests__/drawPolygonOnImage.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import { Image } from '../../Image.js'; import { drawPolygonOnImage } from '../drawPolygonOnImage.js'; @@ -12,6 +14,7 @@ test('RGB image', () => { { row: 1, column: 1 }, ]; const result = image.drawPolygon(points, { strokeColor: [255, 0, 0] }); + expect(result).toMatchImageData([ [255, 0, 0, 100, 150, 0], [100, 200, 5, 255, 0, 0], @@ -154,6 +157,7 @@ test('grey image, no fill', () => { const result = image.drawPolygon(points, { strokeColor: [1], }); + expect(result).toMatchImageData([ [1, 0, 0, 0], [1, 1, 0, 0], @@ -197,6 +201,7 @@ test('5x5 image, tilted square, filled', () => { fillColor: [6], strokeColor: [3], }); + expect(result).toMatchImageData([ [0, 0, 3, 0, 0], [0, 3, 6, 3, 0], @@ -274,6 +279,7 @@ test('stroke color not compatible with image', () => { { row: 3, column: 0 }, { row: 0, column: 0 }, ]; + expect(() => { image.drawPolygon(points, { strokeColor: [1], @@ -323,6 +329,7 @@ test('different origin', () => { strokeColor: [1], fillColor: [5], }); + expect(result).toMatchImageData([ [0, 1, 1, 1], [0, 1, 5, 1], @@ -347,6 +354,7 @@ test('outside of image', () => { strokeColor: [1], fillColor: [2], }); + expect(result).toMatchImageData([ [1, 0, 0, 0], [1, 1, 0, 0], diff --git a/src/draw/__tests__/drawPolygonOnMask.test.ts b/src/draw/__tests__/drawPolygonOnMask.test.ts index 5c9a2da1a..9e9201377 100644 --- a/src/draw/__tests__/drawPolygonOnMask.test.ts +++ b/src/draw/__tests__/drawPolygonOnMask.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import { Mask } from '../../Mask.js'; import { drawPolygonOnMask } from '../drawPolygonOnMask.js'; @@ -94,6 +96,7 @@ test('triangle not filled', () => { { row: 3, column: 0 }, ]; const result = mask.drawPolygon(points); + expect(result).toMatchMaskData([ [1, 0, 0, 0], [1, 1, 0, 0], @@ -291,6 +294,7 @@ test('different origin', () => { origin: { column: 2, row: 0 }, filled: true, }); + expect(result).toMatchMaskData([ [0, 0, 1, 1], [0, 0, 1, 1], @@ -317,6 +321,7 @@ test('outside of mask', () => { const result = mask.drawPolygon(points, { filled: true, }); + expect(result).toMatchMaskData([ [0, 1, 1, 1, 1], [0, 1, 1, 1, 0], diff --git a/src/draw/__tests__/drawPolylineOnImage.test.ts b/src/draw/__tests__/drawPolylineOnImage.test.ts index 1ae5cd248..77c01354b 100644 --- a/src/draw/__tests__/drawPolylineOnImage.test.ts +++ b/src/draw/__tests__/drawPolylineOnImage.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import { Image } from '../../Image.js'; import { drawPolylineOnImage } from '../drawPolylineOnImage.js'; @@ -12,6 +14,7 @@ test('RGB image', () => { { row: 2, column: 1 }, ]; const result = image.drawPolyline(points, { strokeColor: [255, 0, 0] }); + expect(result).toMatchImageData([ [100, 150, 200, 100, 150, 0], [255, 0, 0, 3, 200, 0], @@ -135,16 +138,19 @@ test('different origin', () => { origin: { column: 1, row: 0 }, strokeColor: [1], }); + expect(result).toMatchImageData([ [0, 1, 0, 0], [0, 1, 1, 0], [0, 0, 0, 0], [0, 0, 0, 0], ]); + result = image.drawPolyline(points, { origin: { column: 3, row: 0 }, strokeColor: [1], }); + expect(result).toMatchImageData([ [0, 0, 0, 1], [0, 0, 0, 1], @@ -169,6 +175,7 @@ test('should handle points with floating values', () => { origin: { column: 2.1, row: 0.1 }, strokeColor: [1], }); + expect(result).toMatchImageData([ [0, 0, 1, 0], [0, 0, 1, 1], diff --git a/src/draw/__tests__/drawPolylineOnMask.test.ts b/src/draw/__tests__/drawPolylineOnMask.test.ts index 26d1a5292..53fbc223c 100644 --- a/src/draw/__tests__/drawPolylineOnMask.test.ts +++ b/src/draw/__tests__/drawPolylineOnMask.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import { Mask } from '../../Mask.js'; import { drawPolylineOnMask } from '../drawPolylineOnMask.js'; @@ -8,6 +10,7 @@ test('3x3 mask', () => { { row: 2, column: 1 }, ]; const result = image.drawPolyline(points); + expect(result).toMatchMaskData([ [0, 0, 0], [1, 0, 0], @@ -131,6 +134,7 @@ test('different origin', () => { const result = mask.drawPolyline(points, { origin: { column: 1, row: 0 }, }); + expect(result).toMatchMaskData([ [0, 1, 0, 0], [0, 1, 1, 0], @@ -153,6 +157,7 @@ test('should handle points with floating values', () => { { row: 1.1, column: 1.1 }, ]; const result = mask.drawPolyline(points, { origin: { column: 1, row: 0 } }); + expect(result).toMatchMaskData([ [0, 1, 0, 0], [0, 1, 1, 0], @@ -179,6 +184,7 @@ test('different origin, outside of mask', () => { const result = mask.drawPolyline(points, { origin: { column: 0, row: 2 }, }); + expect(result).toMatchMaskData([ [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], diff --git a/src/draw/__tests__/drawRectangle.test.ts b/src/draw/__tests__/drawRectangle.test.ts index e90f4652e..e06665c0e 100644 --- a/src/draw/__tests__/drawRectangle.test.ts +++ b/src/draw/__tests__/drawRectangle.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import { Image } from '../../Image.js'; import { drawRectangle } from '../drawRectangle.js'; @@ -36,6 +38,7 @@ test('out parameter set to self', () => { fillColor: [0, 5, 2], out: image, }); + expect(result).toMatchImageData([ [255, 0, 0, 255, 0, 0, 255, 0, 0], [255, 0, 0, 0, 5, 2, 255, 0, 0], @@ -58,6 +61,7 @@ test('out to other image', () => { fillColor: [1, 1, 1], out, }); + expect(result).toMatchImageData([ [255, 0, 0, 255, 0, 0], [255, 0, 0, 255, 0, 0], @@ -81,6 +85,7 @@ test('draw rectangle in grey image', () => { height: image.height, strokeColor: [2], }); + expect(result).toMatchImageData([ [2, 2, 2, 2, 2, 2], [2, 1, 1, 1, 1, 2], @@ -109,6 +114,7 @@ test('should handle points with floating values', () => { height: height + 0.1, strokeColor: [2], }); + expect(result).toMatchImageData([ [2, 2, 2, 2, 2, 2], [2, 1, 1, 1, 1, 2], @@ -135,6 +141,7 @@ test('draw filled rectangle in grey image', () => { strokeColor: [2], fillColor: [3], }); + expect(result).toMatchImageData([ [2, 2, 2, 2, 2, 2], [2, 3, 3, 3, 3, 2], @@ -161,6 +168,7 @@ test('draw filled rectangle with no stroke', () => { strokeColor: 'none', fillColor: [3], }); + expect(result).toMatchImageData([ [1, 1, 1, 1, 1, 1], [1, 3, 3, 3, 3, 1], @@ -185,6 +193,7 @@ test('draw rectangle with no options', () => { width: image.width, height: image.height, }); + expect(result).toMatchImageData([ [0, 0, 0, 0, 0, 0], [0, 1, 1, 1, 1, 0], @@ -210,6 +219,7 @@ test('fillColor = none', () => { height: image.height, fillColor: 'none', }); + expect(result).toMatchImageData([ [0, 0, 0, 0, 0, 0], [0, 1, 1, 1, 1, 0], @@ -237,6 +247,7 @@ test('outside of image', () => { fillColor: [3], origin: { column: 1, row: 1 }, }); + expect(result).toMatchImageData([ [1, 1, 1, 1, 1, 1], [1, 2, 2, 2, 2, 2], @@ -345,6 +356,7 @@ test('points out of mask', () => { strokeColor: [1], origin: { column: 3, row: 3 }, }); + expect(result).toMatchMaskData([ [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0], diff --git a/src/draw/utils/__tests__/deleteDuplicates.test.ts b/src/draw/utils/__tests__/deleteDuplicates.test.ts index d2efdc61d..07580dea7 100644 --- a/src/draw/utils/__tests__/deleteDuplicates.test.ts +++ b/src/draw/utils/__tests__/deleteDuplicates.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import { deleteDuplicates } from '../deleteDuplicates.js'; test('should remove duplicate points', () => { diff --git a/src/featureMatching/descriptors/__tests__/getBriefDescriptors.test.ts b/src/featureMatching/descriptors/__tests__/getBriefDescriptors.test.ts index bb417525c..bf275050d 100644 --- a/src/featureMatching/descriptors/__tests__/getBriefDescriptors.test.ts +++ b/src/featureMatching/descriptors/__tests__/getBriefDescriptors.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import { Image } from '../../../Image.js'; import { getOrientedFastKeypoints } from '../../keypoints/getOrientedFastKeypoints.js'; import { getBriefDescriptors } from '../getBriefDescriptors.js'; @@ -36,14 +38,18 @@ test('alphabet image should work', () => { const grey = source.convertColor('GREY'); const sourceKeypoints = getOrientedFastKeypoints(grey); + expect(() => getBriefDescriptors(grey, sourceKeypoints)).not.toThrow(); + const result = getBriefDescriptors(grey, sourceKeypoints); - expect(result.descriptors.length).toBe(result.keypoints.length); + + expect(result.descriptors).toHaveLength(result.keypoints.length); }); test('image too small for patchsize', () => { const image = new Image(5, 5, { colorModel: 'GREY' }); const sourceKeypoints = getOrientedFastKeypoints(image); + expect(() => getBriefDescriptors(image, sourceKeypoints)).toThrow( 'image is too small for patchSize = 31', ); diff --git a/src/featureMatching/descriptors/utils/__tests__/getKeypointPatch.test.ts b/src/featureMatching/descriptors/utils/__tests__/getKeypointPatch.test.ts index c917af808..cb8e7f6fb 100644 --- a/src/featureMatching/descriptors/utils/__tests__/getKeypointPatch.test.ts +++ b/src/featureMatching/descriptors/utils/__tests__/getKeypointPatch.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import type { TestImagePath } from '../../../../../test/TestImagePath.js'; import { getOrientedFastKeypoints } from '../../../keypoints/getOrientedFastKeypoints.js'; import { drawKeypoints } from '../../../visualize/drawKeypoints.js'; diff --git a/src/featureMatching/descriptors/utils/__tests__/sliceBrief.test.ts b/src/featureMatching/descriptors/utils/__tests__/sliceBrief.test.ts index d26a1f2d8..1d3ac2cf6 100644 --- a/src/featureMatching/descriptors/utils/__tests__/sliceBrief.test.ts +++ b/src/featureMatching/descriptors/utils/__tests__/sliceBrief.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import { getOrientedFastKeypoints } from '../../../keypoints/getOrientedFastKeypoints.js'; import { getBriefDescriptors } from '../../getBriefDescriptors.js'; import { sliceBrief } from '../sliceBrief.js'; @@ -29,7 +31,7 @@ test('slice 0 to 3', () => { const result = sliceBrief(brief, { end: 3 }); - expect(result.descriptors.length).toBe(3); + expect(result.descriptors).toHaveLength(3); }); test('range error', () => { diff --git a/src/featureMatching/keypoints/__tests__/getBestKeypointsInRadius.test.ts b/src/featureMatching/keypoints/__tests__/getBestKeypointsInRadius.test.ts index 0dcd999a0..b808fe746 100644 --- a/src/featureMatching/keypoints/__tests__/getBestKeypointsInRadius.test.ts +++ b/src/featureMatching/keypoints/__tests__/getBestKeypointsInRadius.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import { drawKeypoints } from '../../visualize/drawKeypoints.js'; import { getBestKeypointsInRadius } from '../getBestKeypointsInRadius.js'; import type { OrientedFastKeypoint } from '../getOrientedFastKeypoints.js'; @@ -10,6 +12,7 @@ test('array of 3 keypoints', () => { { origin: { row: 0, column: 2 }, angle: 0, score: 6 }, ]; const result = getBestKeypointsInRadius(keypoints); + expect(result).toStrictEqual([ { origin: { row: 0, column: 2 }, angle: 0, score: 6 }, ]); @@ -23,6 +26,7 @@ test('many clusters of keypoints', () => { { origin: { row: 10, column: 11 }, angle: 0, score: 9 }, ]; const result = getBestKeypointsInRadius(keypoints); + expect(result).toStrictEqual([ { origin: { row: 1, column: 0 }, angle: 0, score: 5 }, { origin: { row: 10, column: 11 }, angle: 0, score: 9 }, diff --git a/src/featureMatching/keypoints/__tests__/getFastKeypoints.test.ts b/src/featureMatching/keypoints/__tests__/getFastKeypoints.test.ts index f822942b6..5a77eb635 100644 --- a/src/featureMatching/keypoints/__tests__/getFastKeypoints.test.ts +++ b/src/featureMatching/keypoints/__tests__/getFastKeypoints.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import { drawKeypoints } from '../../visualize/drawKeypoints.js'; import { getFastKeypoints } from '../getFastKeypoints.js'; @@ -64,6 +66,7 @@ test('star', () => { test('wrong color model error', () => { const image = testUtils.load('various/alphabet.jpg'); + expect(() => { getFastKeypoints(image); }).toThrow('image channels must be 1 to apply this algorithm'); @@ -72,6 +75,7 @@ test('wrong color model error', () => { test('undefined score algorithm error', () => { const image = testUtils.load('various/alphabet.jpg'); const grey = image.convertColor('GREY'); + expect(() => { // @ts-expect-error: test for js users getFastKeypoints(grey, { scoreAlgorithm: 'test' }); diff --git a/src/featureMatching/keypoints/__tests__/getHarrisScore.test.ts b/src/featureMatching/keypoints/__tests__/getHarrisScore.test.ts index 50d0c4114..629355298 100644 --- a/src/featureMatching/keypoints/__tests__/getHarrisScore.test.ts +++ b/src/featureMatching/keypoints/__tests__/getHarrisScore.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import { Image } from '../../../Image.js'; import { getHarrisScore } from '../getHarrisScore.js'; diff --git a/src/featureMatching/keypoints/__tests__/getIntensityCentroid.test.ts b/src/featureMatching/keypoints/__tests__/getIntensityCentroid.test.ts index 9cbd7d597..55a0e16fd 100644 --- a/src/featureMatching/keypoints/__tests__/getIntensityCentroid.test.ts +++ b/src/featureMatching/keypoints/__tests__/getIntensityCentroid.test.ts @@ -1,9 +1,12 @@ +import { expect, test } from 'vitest'; + import { Image } from '../../../Image.js'; import { getIntensityCentroid } from '../getIntensityCentroid.js'; test('3x3 empty image', () => { const image = new Image(3, 3, { colorModel: 'GREY' }); const result = getIntensityCentroid(image); + expect(result).toStrictEqual([{ column: 0, row: 0 }]); }); @@ -14,6 +17,7 @@ test('3x3 image', () => { [3, 0, 1], ]); const result = getIntensityCentroid(image); + expect(result).toStrictEqual([{ column: 0, row: 0 }]); }); @@ -24,6 +28,7 @@ test('RGB image', () => { [3, 1, 1], ]); const result = getIntensityCentroid(image); + expect(result).toStrictEqual([ { column: 0, row: 1 / 3 }, { column: 0, row: 0 }, diff --git a/src/featureMatching/keypoints/__tests__/getIntensityMoment.test.ts b/src/featureMatching/keypoints/__tests__/getIntensityMoment.test.ts index a7f8fbb69..25561d2da 100644 --- a/src/featureMatching/keypoints/__tests__/getIntensityMoment.test.ts +++ b/src/featureMatching/keypoints/__tests__/getIntensityMoment.test.ts @@ -1,15 +1,19 @@ +import { expect, test } from 'vitest'; + import { Image } from '../../../Image.js'; import { getIntensityMoment } from '../getIntensityMoment.js'; test('3x3 empty image, 00', () => { const image = new Image(3, 3, { colorModel: 'GREY' }); const result = getIntensityMoment(image, 0, 0); + expect(result).toStrictEqual([0]); }); test('1D image, 00', () => { const image = testUtils.createGreyImage([[1, 2, 3, 4, 5]]); const result = getIntensityMoment(image, 0, 0); + // should be the sum of all elements expect(result).toStrictEqual([15]); }); @@ -17,6 +21,7 @@ test('1D image, 00', () => { test('1D image, 10', () => { const image = testUtils.createGreyImage([[1, 2, 3, 4, 5]]); const result = getIntensityMoment(image, 1, 0); + expect(result).toStrictEqual([10]); }); @@ -27,6 +32,7 @@ test('3x3 image, 01', () => { [3, 0, 1], ]); const result = getIntensityMoment(image, 0, 1); + expect(result).toStrictEqual([0]); }); @@ -37,6 +43,7 @@ test('RGB image, 01', () => { [3, 0, 1], ]); const result = getIntensityMoment(image, 0, 1); + expect(result).toStrictEqual([2, 0, -2]); }); @@ -48,6 +55,7 @@ test('4x4 image, 01', () => { [4, 0, 1, 5], ]); const result = getIntensityMoment(image, 0, 1); + expect(result).toStrictEqual([0]); }); @@ -57,5 +65,6 @@ test('2x2 image, 01', () => { [2, 0], ]); const result = getIntensityMoment(image, 0, 1); + expect(result).toStrictEqual([0.5]); }); diff --git a/src/featureMatching/keypoints/__tests__/getOrientedFastKeypoints.test.ts b/src/featureMatching/keypoints/__tests__/getOrientedFastKeypoints.test.ts index 8fce2dde2..ed4ab06de 100644 --- a/src/featureMatching/keypoints/__tests__/getOrientedFastKeypoints.test.ts +++ b/src/featureMatching/keypoints/__tests__/getOrientedFastKeypoints.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import type { TestImagePath } from '../../../../test/TestImagePath.js'; import { drawKeypoints } from '../../visualize/drawKeypoints.js'; import { getOrientedFastKeypoints } from '../getOrientedFastKeypoints.js'; @@ -14,6 +16,7 @@ test('7x7 image, angle = -90°', () => { ]); const result = getOrientedFastKeypoints(image)[0]; + expect(result).toStrictEqual({ angle: -90, origin: { row: 3, column: 3 }, @@ -33,6 +36,7 @@ test('7x7 image, angle = 135°', () => { ]); const result = getOrientedFastKeypoints(image)[0]; + expect(result).toStrictEqual({ angle: -225, origin: { row: 3, column: 3 }, @@ -52,6 +56,7 @@ test('7x7 image, angle = -135°', () => { ]); const result = getOrientedFastKeypoints(image)[0]; + expect(result).toStrictEqual({ angle: 225, origin: { row: 3, column: 3 }, @@ -71,6 +76,7 @@ test('7x7 image, angle = 180°', () => { ]); const result = getOrientedFastKeypoints(image)[0]; + expect(result).toStrictEqual({ angle: 180, origin: { row: 3, column: 3 }, @@ -90,12 +96,14 @@ test('7x7 image, angle = 0°', () => { ]); const result = getOrientedFastKeypoints(image)[0]; + expect(result).toStrictEqual({ angle: -0, origin: { row: 3, column: 3 }, score: 2680, }); }); + test('7x7 image, angle = 45°', () => { const image = testUtils.createGreyImage([ [0, 0, 0, 0, 0, 0, 100], @@ -108,6 +116,7 @@ test('7x7 image, angle = 45°', () => { ]); const result = getOrientedFastKeypoints(image)[0]; + expect(result).toBeDeepCloseTo({ angle: 45, origin: { row: 3, column: 3 }, @@ -127,6 +136,7 @@ test('7x7 image, angle = -45°', () => { ]); const result = getOrientedFastKeypoints(image)[0]; + expect(result).toBeDeepCloseTo({ angle: -45, origin: { row: 3, column: 3 }, @@ -223,7 +233,8 @@ test('verify single keypoint orientation', () => { }); const keypoints = getOrientedFastKeypoints(image, { centroidPatchDiameter }); - expect(keypoints.length).toBe(1); + + expect(keypoints).toHaveLength(1); const result = drawKeypoints(image, keypoints, { markerSize: centroidPatchDiameter, @@ -259,7 +270,8 @@ test('small patchsize and large marker', () => { }); const keypoints = getOrientedFastKeypoints(image, { centroidPatchDiameter }); - expect(keypoints.length).toBe(1); + + expect(keypoints).toHaveLength(1); const result = drawKeypoints(image, keypoints, { markerSize: 31, diff --git a/src/featureMatching/keypoints/__tests__/getPatchIntensityCentroid.test.ts b/src/featureMatching/keypoints/__tests__/getPatchIntensityCentroid.test.ts index 64b71ce37..3c3cc03ab 100644 --- a/src/featureMatching/keypoints/__tests__/getPatchIntensityCentroid.test.ts +++ b/src/featureMatching/keypoints/__tests__/getPatchIntensityCentroid.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import { Image } from '../../../Image.js'; import { round, sum } from '../../../utils/geometry/points.js'; import { getPatchIntensityCentroid } from '../getPatchIntensityCentroid.js'; @@ -5,6 +7,7 @@ import { getPatchIntensityCentroid } from '../getPatchIntensityCentroid.js'; test('3x3 empty image', () => { const image = new Image(7, 7, { colorModel: 'GREY' }); const result = getPatchIntensityCentroid(image); + expect(result).toStrictEqual([{ column: 0, row: 0 }]); }); @@ -15,6 +18,7 @@ test('3x3 image', () => { [0, 0, 0], ]); const result = getPatchIntensityCentroid(image, { radius: 1 }); + expect(result).toStrictEqual([{ column: -1, row: 0 }]); }); @@ -27,6 +31,7 @@ test('5x5 image', () => { [0, 0, 0, 0, 0], ]); const result = getPatchIntensityCentroid(image, { radius: 2 }); + expect(result).toStrictEqual([{ column: 1.9, row: 0 }]); }); @@ -39,6 +44,7 @@ test('5x5 image, diagonal line', () => { [0, 0, 0, 0, 0], ]); const result = getPatchIntensityCentroid(image, { radius: 2 }); + expect(result).toStrictEqual([{ column: -0.5, row: -0.5 }]); }); @@ -51,6 +57,7 @@ test('check window is circular', () => { [0, 0, 0, 0, 100], ]); const result = getPatchIntensityCentroid(image, { radius: 2 }); + expect(result).toStrictEqual([{ column: 1, row: 0 }]); }); @@ -63,6 +70,7 @@ test('triangle center of mass', () => { [0, 0, 0, 1, 0], ]); const result = getPatchIntensityCentroid(image, { radius: 2 }); + expect(result).toBeDeepCloseTo([{ column: 0.444, row: 0 }]); }); @@ -73,6 +81,7 @@ test('patch, default options', () => { const radius = 3; const centroid = getPatchIntensityCentroid(image)[0]; + expect(centroid).toBeDeepCloseTo({ column: -1.179, row: -0.183 }); const center = image.getCoordinates('center'); @@ -109,6 +118,7 @@ test('scalene triangle keypoint', () => { }); const centroid = getPatchIntensityCentroid(image, { radius })[0]; + expect(centroid).toBeDeepCloseTo({ column: 1.281, row: 0.204 }); const center = image.getCoordinates('center'); @@ -145,6 +155,7 @@ test('scalene triangle 90 keypoint', () => { }); const centroid = getPatchIntensityCentroid(image, { radius })[0]; + expect(centroid).toBeDeepCloseTo({ column: 0.204, row: -1.281 }); const center = image.getCoordinates('center'); diff --git a/src/featureMatching/keypoints/__tests__/getPatchIntensityMoment.test.ts b/src/featureMatching/keypoints/__tests__/getPatchIntensityMoment.test.ts index b1aef66bb..bb24ebf4c 100644 --- a/src/featureMatching/keypoints/__tests__/getPatchIntensityMoment.test.ts +++ b/src/featureMatching/keypoints/__tests__/getPatchIntensityMoment.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import { getPatchIntensityMoment } from '../getPatchIntensityMoment.js'; test('5x5 image, 01, radius = 1', () => { @@ -9,6 +11,7 @@ test('5x5 image, 01, radius = 1', () => { [0, 0, 0, 0, 0], ]); const result = getPatchIntensityMoment(image, 0, 1, { radius: 1 }); + expect(result).toStrictEqual([-1]); }); @@ -21,6 +24,7 @@ test('5x5 image, 01, radius = 2', () => { [0, 0, 0, 0, 0], ]); const result = getPatchIntensityMoment(image, 0, 1, { radius: 2 }); + expect(result).toStrictEqual([-3]); }); @@ -33,6 +37,7 @@ test('5x5 image, 10, radius = 2', () => { [0, 0, 0, 0, 0], ]); const result = getPatchIntensityMoment(image, 1, 0, { radius: 2 }); + expect(result).toStrictEqual([4]); }); @@ -44,6 +49,7 @@ test('too close to border error', () => { [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], ]); + expect(() => { getPatchIntensityMoment(image, 0, 1); }).toThrow('desired patch is too close to image border'); diff --git a/src/featureMatching/keypoints/__tests__/isFastKeypoint.test.ts b/src/featureMatching/keypoints/__tests__/isFastKeypoint.test.ts index c99fd8565..bdb08661e 100644 --- a/src/featureMatching/keypoints/__tests__/isFastKeypoint.test.ts +++ b/src/featureMatching/keypoints/__tests__/isFastKeypoint.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import { Image } from '../../../Image.js'; import { getCirclePoints, @@ -57,6 +59,7 @@ test('7x7 image with corner 90 degrees', () => { expect(result).toBe(false); }); + test('7x7 image with darker and lighter areas', () => { const image = testUtils.createGreyImage([ [0, 0, 0, 0, 0, 0, 0], @@ -74,6 +77,7 @@ test('7x7 image with darker and lighter areas', () => { expect(result).toBe(true); }); + test('7x7 image with segment', () => { const image = testUtils.createGreyImage([ [0, 0, 0, 0, 0, 0, 0], @@ -91,6 +95,7 @@ test('7x7 image with segment', () => { expect(result).toBe(true); }); + test('7x7 image, threshold = 60', () => { const image = testUtils.createGreyImage([ [0, 0, 0, 0, 0, 0, 0], @@ -109,6 +114,7 @@ test('7x7 image, threshold = 60', () => { expect(result).toBe(false); }); + test('7x7 image with corner 90 degrees, n=9', () => { const image = testUtils.createGreyImage([ [0, 0, 0, 0, 0, 0, 0], diff --git a/src/featureMatching/keypoints/getHarrisScore.ts b/src/featureMatching/keypoints/getHarrisScore.ts index 7acb9ce22..a84ee33b6 100644 --- a/src/featureMatching/keypoints/getHarrisScore.ts +++ b/src/featureMatching/keypoints/getHarrisScore.ts @@ -1,4 +1,4 @@ -import { Matrix, EigenvalueDecomposition, WrapperMatrix1D } from 'ml-matrix'; +import { EigenvalueDecomposition, Matrix, WrapperMatrix1D } from 'ml-matrix'; import type { Image } from '../../Image.js'; import type { Point } from '../../geometry/index.js'; diff --git a/src/featureMatching/keypoints/utils/__tests__/getDistanceMatrix.test.ts b/src/featureMatching/keypoints/utils/__tests__/getDistanceMatrix.test.ts index bc452e60b..caeeaeb38 100644 --- a/src/featureMatching/keypoints/utils/__tests__/getDistanceMatrix.test.ts +++ b/src/featureMatching/keypoints/utils/__tests__/getDistanceMatrix.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import type { OrientedFastKeypoint } from '../../getOrientedFastKeypoints.js'; import { getDistanceMatrix } from '../getDistanceMatrix.js'; diff --git a/src/featureMatching/keypoints/utils/__tests__/getKeypointsInRadius.test.ts b/src/featureMatching/keypoints/utils/__tests__/getKeypointsInRadius.test.ts index 3d52c41d7..96c679db9 100644 --- a/src/featureMatching/keypoints/utils/__tests__/getKeypointsInRadius.test.ts +++ b/src/featureMatching/keypoints/utils/__tests__/getKeypointsInRadius.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import type { OrientedFastKeypoint } from '../../getOrientedFastKeypoints.js'; import { getKeypointsInRadius } from '../getKeypointsInRadius.js'; diff --git a/src/featureMatching/matching/__tests__/bruteForceMatch.test.ts b/src/featureMatching/matching/__tests__/bruteForceMatch.test.ts index a8f812709..877e454a1 100644 --- a/src/featureMatching/matching/__tests__/bruteForceMatch.test.ts +++ b/src/featureMatching/matching/__tests__/bruteForceMatch.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import type { TestImagePath } from '../../../../test/TestImagePath.js'; import { getBriefDescriptors } from '../../descriptors/getBriefDescriptors.js'; import { getBestKeypointsInRadius } from '../../keypoints/getBestKeypointsInRadius.js'; @@ -71,7 +73,7 @@ test.each([ const matches = bruteForceOneMatch(sourceDescriptors, destinationDescriptors); - expect(matches.length).toBe(data.expected); + expect(matches).toHaveLength(data.expected); const montage = new Montage(source, destination, { disposition: 'vertical', diff --git a/src/featureMatching/matching/__tests__/filterEuclideanDistance.test.ts b/src/featureMatching/matching/__tests__/filterEuclideanDistance.test.ts index 158d69a7f..f06d061b8 100644 --- a/src/featureMatching/matching/__tests__/filterEuclideanDistance.test.ts +++ b/src/featureMatching/matching/__tests__/filterEuclideanDistance.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import type { Match } from '../bruteForceMatch.js'; import { filterEuclideanDistance } from '../filterEuclideanDistance.js'; diff --git a/src/featureMatching/matching/__tests__/filterSmallestDistanceMatches.test.ts b/src/featureMatching/matching/__tests__/filterSmallestDistanceMatches.test.ts index 192078755..ad0a97449 100644 --- a/src/featureMatching/matching/__tests__/filterSmallestDistanceMatches.test.ts +++ b/src/featureMatching/matching/__tests__/filterSmallestDistanceMatches.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import type { Match } from '../bruteForceMatch.js'; import { filterSmallestDistanceMatches } from '../filterSmallestDistanceMatches.js'; @@ -9,6 +11,7 @@ test('3 matches', () => { ]; const result = filterSmallestDistanceMatches(matches); + expect(result).toStrictEqual([ { sourceIndex: 0, destinationIndex: 0, distance: 1 }, { sourceIndex: 1, destinationIndex: 2, distance: 3 }, diff --git a/src/featureMatching/matching/__tests__/getCrosscheckMatches.test.ts b/src/featureMatching/matching/__tests__/getCrosscheckMatches.test.ts index dda1da4de..b4085cacd 100644 --- a/src/featureMatching/matching/__tests__/getCrosscheckMatches.test.ts +++ b/src/featureMatching/matching/__tests__/getCrosscheckMatches.test.ts @@ -1,3 +1,5 @@ +import { describe, expect, it } from 'vitest'; + import type { TestImagePath } from '../../../../test/TestImagePath.js'; import { getBriefDescriptors } from '../../descriptors/getBriefDescriptors.js'; import { getBestKeypointsInRadius } from '../../keypoints/getBestKeypointsInRadius.js'; @@ -100,7 +102,7 @@ describe('crosscheck', () => { }); describe('getCrosscheckMatches', () => { - test.each([ + it.each([ { message: 'scalene triangle', source: 'scaleneTriangle', @@ -171,7 +173,7 @@ describe('getCrosscheckMatches', () => { destinationDescriptors, ); - expect(matches.length).toBe(data.expected); + expect(matches).toHaveLength(data.expected); const montage = new Montage(source, destination); montage.drawKeypoints(sourceKeypoints); diff --git a/src/featureMatching/matching/__tests__/getHammingDistance.test.ts b/src/featureMatching/matching/__tests__/getHammingDistance.test.ts index 418e0dcb2..420e19eff 100644 --- a/src/featureMatching/matching/__tests__/getHammingDistance.test.ts +++ b/src/featureMatching/matching/__tests__/getHammingDistance.test.ts @@ -1,9 +1,12 @@ +import { expect, test } from 'vitest'; + import { getBriefDescriptors } from '../../descriptors/getBriefDescriptors.js'; import { getOrientedFastKeypoints } from '../../keypoints/getOrientedFastKeypoints.js'; import { getHammingDistance } from '../getHammingDistance.js'; test('distance should be 0', () => { const a = new Uint8Array([0, 1, 0, 0, 0, 0, 0]); + expect(getHammingDistance(a, a)).toBe(0); }); diff --git a/src/featureMatching/utils/__tests__/__image_snapshots__/get-gaussian-points-test-ts-10000-gaussian-points-sigma-1-2-snap.png b/src/featureMatching/utils/__tests__/__image_snapshots__/get-gaussian-points-test-ts-10000-gaussian-points-sigma-1-2-1-snap.png similarity index 100% rename from src/featureMatching/utils/__tests__/__image_snapshots__/get-gaussian-points-test-ts-10000-gaussian-points-sigma-1-2-snap.png rename to src/featureMatching/utils/__tests__/__image_snapshots__/get-gaussian-points-test-ts-10000-gaussian-points-sigma-1-2-1-snap.png diff --git a/src/featureMatching/utils/__tests__/checkBorderDistance.test.ts b/src/featureMatching/utils/__tests__/checkBorderDistance.test.ts index 636d9811b..658ac87cf 100644 --- a/src/featureMatching/utils/__tests__/checkBorderDistance.test.ts +++ b/src/featureMatching/utils/__tests__/checkBorderDistance.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import { Image } from '../../../Image.js'; import type { Point } from '../../../geometry/index.js'; import { checkBorderDistance } from '../checkBorderDistance.js'; @@ -8,6 +10,7 @@ test('should be true', () => { const distance = 3; const point: Point = { column: 3, row: 3 }; + expect(checkBorderDistance(image, point, distance)).toBe(true); }); diff --git a/src/featureMatching/utils/__tests__/compareIntensity.test.ts b/src/featureMatching/utils/__tests__/compareIntensity.test.ts index 8f26593f2..2ee357a76 100644 --- a/src/featureMatching/utils/__tests__/compareIntensity.test.ts +++ b/src/featureMatching/utils/__tests__/compareIntensity.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import { Image } from '../../../Image.js'; import { compareIntensity } from '../compareIntensity.js'; @@ -9,6 +11,7 @@ test('verify descriptor is correct (descriptorLength = 10)', () => { } const p1 = { column: 0, row: 0 }; const p2 = { column: -1, row: -2 }; + expect(compareIntensity(image, p1, p2)).toBe(true); expect(compareIntensity(image, p2, p1)).toBe(false); }); diff --git a/src/featureMatching/utils/__tests__/extractSquareImage.test.ts b/src/featureMatching/utils/__tests__/extractSquareImage.test.ts index 01296ef2d..de38c238d 100644 --- a/src/featureMatching/utils/__tests__/extractSquareImage.test.ts +++ b/src/featureMatching/utils/__tests__/extractSquareImage.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import { extractSquareImage } from '../extractSquareImage.js'; test('7x7 image, first origin', () => { @@ -32,6 +34,7 @@ test('7x7 image, second origin', () => { ]); const result = extractSquareImage(image, { column: 3, row: 4 }, 3); + expect(result).toMatchImageData([ [255, 255, 0], [0, 255, 0], diff --git a/src/featureMatching/utils/__tests__/getColors.test.ts b/src/featureMatching/utils/__tests__/getColors.test.ts index fd0ac6fc7..2ee75468c 100644 --- a/src/featureMatching/utils/__tests__/getColors.test.ts +++ b/src/featureMatching/utils/__tests__/getColors.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import { Image } from '../../../Image.js'; import { getColors } from '../getColors.js'; diff --git a/src/featureMatching/utils/__tests__/getGaussianPoints.test.ts b/src/featureMatching/utils/__tests__/getGaussianPoints.test.ts index 61bc09d0b..797e68d55 100644 --- a/src/featureMatching/utils/__tests__/getGaussianPoints.test.ts +++ b/src/featureMatching/utils/__tests__/getGaussianPoints.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import { Image } from '../../../Image.js'; import type { Point } from '../../../geometry/index.js'; import { getGaussianPoints, getGaussianValues } from '../getGaussianPoints.js'; @@ -24,11 +26,13 @@ function drawGaussianPoints(image: Image, points: Point[]): Image { test('gaussian values, size 7', () => { const result = new Float64Array([-1, -1, 2, -2, 2, 2, 0, 2, 1, -1]); + expect(getGaussianValues(7, 0, 10)).toStrictEqual(result); }); test('gaussian values, size 20', () => { const result = new Float64Array([-3, -2, 6, -6, 6, 6, 1, 5, 3, -2]); + expect(getGaussianValues(20, 0, 10)).toStrictEqual(result); }); @@ -50,11 +54,12 @@ test('10000 gaussian points, sigma = 1', () => { expect(drawGaussianPoints(image, points)).toMatchImageSnapshot(); }); -test('10000 gaussian points, sigma = 1', () => { +test('10000 gaussian points, sigma = 1 - 2', () => { const size = 15; const image = new Image(size, size, { colorModel: 'GREY' }); const points = getGaussianPoints(size, size, { nbPoints: 10000, sigma: 1 }); + expect(drawGaussianPoints(image, points)).toMatchImageSnapshot(); }); diff --git a/src/featureMatching/utils/__tests__/getKeypointColor.test.ts b/src/featureMatching/utils/__tests__/getKeypointColor.test.ts index fe70e20b5..777c6ec60 100644 --- a/src/featureMatching/utils/__tests__/getKeypointColor.test.ts +++ b/src/featureMatching/utils/__tests__/getKeypointColor.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import { Image } from '../../../Image.js'; import { getColors } from '../getColors.js'; import { getKeypointColor } from '../getKeypointColor.js'; @@ -19,6 +21,7 @@ test('keypoint should all have a different color', () => { for (let i = 0; i < keypoints.length; i++) { result.push(getKeypointColor(keypoints, i, colors)); } + expect(result).toStrictEqual(colors); }); @@ -38,6 +41,7 @@ test('keypoint with more random scores', () => { for (let i = 0; i < keypoints.length; i++) { result.push(getKeypointColor(keypoints, i, colors)); } + expect(result).toStrictEqual([ [255, 0, 0], [204, 0, 0], @@ -60,6 +64,7 @@ test('all keypoints have same score', () => { for (let i = 0; i < keypoints.length; i++) { result.push(getKeypointColor(keypoints, i, colors)); } + expect(result).toStrictEqual([ [255, 0, 0], [255, 0, 0], diff --git a/src/featureMatching/utils/__tests__/getMatchColor.test.ts b/src/featureMatching/utils/__tests__/getMatchColor.test.ts index 3c286a11b..da9ce56c5 100644 --- a/src/featureMatching/utils/__tests__/getMatchColor.test.ts +++ b/src/featureMatching/utils/__tests__/getMatchColor.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import { Image } from '../../../Image.js'; import type { Match } from '../../matching/bruteForceMatch.js'; import { getColors } from '../getColors.js'; @@ -19,6 +21,7 @@ test('matches should all have a different color', () => { for (let i = 0; i < matches.length; i++) { result.push(getMatchColor(matches, i, colors)); } + expect(result).toStrictEqual(colors); }); @@ -35,6 +38,7 @@ test('all matches have same distance', () => { for (let i = 0; i < matches.length; i++) { result.push(getMatchColor(matches, i, colors)); } + expect(result).toStrictEqual([ [255, 0, 0], [255, 0, 0], diff --git a/src/featureMatching/utils/__tests__/sortByDistance.test.ts b/src/featureMatching/utils/__tests__/sortByDistance.test.ts index 0111ff04a..a8b7c4eb8 100644 --- a/src/featureMatching/utils/__tests__/sortByDistance.test.ts +++ b/src/featureMatching/utils/__tests__/sortByDistance.test.ts @@ -1,7 +1,9 @@ +import { expect, test } from 'vitest'; + import type { Match } from '../../matching/bruteForceMatch.js'; import { sortByDistance } from '../sortByDistance.js'; -it('should sort by source then dest', () => { +test('should sort by source then dest', () => { const matches: Match[] = [ { sourceIndex: 9, destinationIndex: 3, distance: 1 }, { sourceIndex: 1, destinationIndex: 14, distance: 2 }, @@ -12,6 +14,7 @@ it('should sort by source then dest', () => { ]; const result = sortByDistance(matches); + expect(result).toStrictEqual([ { sourceIndex: 9, destinationIndex: 3, distance: 1 }, { sourceIndex: 1, destinationIndex: 14, distance: 2 }, diff --git a/src/featureMatching/utils/__tests__/sortBySourceDest.test.ts b/src/featureMatching/utils/__tests__/sortBySourceDest.test.ts index e82e7525a..ebaae729e 100644 --- a/src/featureMatching/utils/__tests__/sortBySourceDest.test.ts +++ b/src/featureMatching/utils/__tests__/sortBySourceDest.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import type { Match } from '../../matching/bruteForceMatch.js'; import { sortByDestSource, sortBySourceDest } from '../sortBySourceDest.js'; @@ -12,6 +14,7 @@ test('should sort by source then dest', () => { ]; const result = sortBySourceDest(matches); + expect(result).toStrictEqual([ { sourceIndex: 1, destinationIndex: 2, distance: 3 }, { sourceIndex: 1, destinationIndex: 14, distance: 3 }, @@ -33,6 +36,7 @@ test('should sort by dest then source', () => { ]; const result = sortByDestSource(matches); + expect(result).toStrictEqual([ { sourceIndex: 1, destinationIndex: 2, distance: 3 }, { sourceIndex: 7, destinationIndex: 3, distance: 5 }, diff --git a/src/featureMatching/visualize/__tests__/Montage.test.ts b/src/featureMatching/visualize/__tests__/Montage.test.ts index 69970be35..9b9312447 100644 --- a/src/featureMatching/visualize/__tests__/Montage.test.ts +++ b/src/featureMatching/visualize/__tests__/Montage.test.ts @@ -13,11 +13,13 @@ describe('constructor', () => { it('default options', () => { expect(new Montage(source, source).width).toBe(2 * source.width); }); + it('should error when scale is not an integer', () => { expect(() => { return new Montage(source, source, { scale: 1.5 }); }).toThrow('scale must be an integer'); }); + it('invalid disposition type', () => { expect(() => { // @ts-expect-error: invalid disposition type @@ -33,6 +35,7 @@ describe('drawKeypoints', () => { expect(montage.image).toMatchImageSnapshot(); }); + it('disposition vertical', () => { const montage = new Montage(source, source, { disposition: 'vertical', @@ -57,6 +60,7 @@ describe('drawMatches', () => { expect(montage.image).toMatchImageSnapshot(); expect(montage.height).toBe(2 * source.height); }); + it('disposition vertical', () => { const brief = getBriefDescriptors(grey, sourceKeypoints); const matches = bruteForceOneMatch(brief.descriptors, brief.descriptors); diff --git a/src/featureMatching/visualize/__tests__/drawKeypoints.test.ts b/src/featureMatching/visualize/__tests__/drawKeypoints.test.ts index 0266a9334..1bb9e6c63 100644 --- a/src/featureMatching/visualize/__tests__/drawKeypoints.test.ts +++ b/src/featureMatching/visualize/__tests__/drawKeypoints.test.ts @@ -1,9 +1,12 @@ +import { expect, test } from 'vitest'; + import { getOrientedFastKeypoints } from '../../keypoints/getOrientedFastKeypoints.js'; import { drawKeypoints } from '../drawKeypoints.js'; const image = testUtils.load('various/alphabet.jpg'); const grey = image.convertColor('GREY'); const keypoints = getOrientedFastKeypoints(grey, { maxNbFeatures: 20 }); + test('alphabet image with score coloring', () => { const result = drawKeypoints(image, keypoints, { showScore: true, @@ -17,6 +20,7 @@ test('alphabet image with score coloring', () => { fill: true, maxNbKeypoints: 50, }); + expect(maxNbKeypoints).toMatchImage(result); }); diff --git a/src/featureMatching/visualize/__tests__/drawMatches.test.ts b/src/featureMatching/visualize/__tests__/drawMatches.test.ts index 857361815..69fe4c30b 100644 --- a/src/featureMatching/visualize/__tests__/drawMatches.test.ts +++ b/src/featureMatching/visualize/__tests__/drawMatches.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import { getBriefDescriptors } from '../../descriptors/getBriefDescriptors.js'; import { getOrientedFastKeypoints } from '../../keypoints/getOrientedFastKeypoints.js'; import { bruteForceOneMatch } from '../../matching/bruteForceMatch.js'; @@ -50,8 +52,9 @@ test('destination rotated +2°', () => { destination, destinationKeypoints, ); - expect(sourceBrief.keypoints.length).toBe(114); - expect(destinationBrief.keypoints.length).toBe(135); + + expect(sourceBrief.keypoints).toHaveLength(114); + expect(destinationBrief.keypoints).toHaveLength(135); const matches = bruteForceOneMatch( sourceBrief.descriptors, diff --git a/src/featureMatching/visualize/__tests__/overlapImages.test.ts b/src/featureMatching/visualize/__tests__/overlapImages.test.ts index 6cc3ea6a9..0dd1457d7 100644 --- a/src/featureMatching/visualize/__tests__/overlapImages.test.ts +++ b/src/featureMatching/visualize/__tests__/overlapImages.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import { overlapImages } from '../overlapImages.js'; test('two triangles', () => { @@ -16,6 +18,7 @@ test('scale cannot be zero', () => { const destination = testUtils.load( 'featureMatching/polygons/scaleneTriangle2.png', ); + expect(() => { overlapImages(source, destination, { scale: 0 }); }).toThrow('Scale cannot be 0'); diff --git a/src/featureMatching/visualize/__tests__/scaleKeypoints.test.ts b/src/featureMatching/visualize/__tests__/scaleKeypoints.test.ts index 9a8840f62..8b98bbe2c 100644 --- a/src/featureMatching/visualize/__tests__/scaleKeypoints.test.ts +++ b/src/featureMatching/visualize/__tests__/scaleKeypoints.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import type { FastKeypoint } from '../../keypoints/getFastKeypoints.js'; import { scaleKeypoints } from '../scaleKeypoints.js'; diff --git a/src/filters/__tests__/and.test.ts b/src/filters/__tests__/and.test.ts index 019f2aa1f..2516cbc30 100644 --- a/src/filters/__tests__/and.test.ts +++ b/src/filters/__tests__/and.test.ts @@ -1,18 +1,23 @@ +import { expect, test } from 'vitest'; + test('mask AND itself', () => { const image = testUtils.createMask([[1, 1, 1, 1, 1, 1, 1, 1]]); const other = image; + expect(image.and(other)).toMatchMaskData([[1, 1, 1, 1, 1, 1, 1, 1]]); }); test('two different masks', () => { const image = testUtils.createMask([[0, 0, 0, 0, 1, 1, 1, 1]]); const other = testUtils.createMask([[1, 1, 1, 1, 0, 0, 0, 0]]); + expect(image.and(other)).toMatchMaskData([[0, 0, 0, 0, 0, 0, 0, 0]]); }); test('different size error', () => { const image = testUtils.createMask([[0, 0, 0, 0, 1, 1, 1, 1]]); const other = testUtils.createMask([[1, 1, 1, 0, 0, 0]]); + expect(() => { image.and(other); }).toThrow('both masks must have the same size'); diff --git a/src/filters/__tests__/blur.test.ts b/src/filters/__tests__/blur.test.ts index ea67df9cc..890dd3111 100644 --- a/src/filters/__tests__/blur.test.ts +++ b/src/filters/__tests__/blur.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + test('blur compared to opencv', () => { const img = testUtils.load('opencv/test.png'); @@ -8,5 +10,6 @@ test('blur compared to opencv', () => { }); const expected = testUtils.load('opencv/testBlur.png'); + expect(blurred).toMatchImage(expected); }); diff --git a/src/filters/__tests__/convolution.test.ts b/src/filters/__tests__/convolution.test.ts index 09b27bd23..5dafc6ed7 100644 --- a/src/filters/__tests__/convolution.test.ts +++ b/src/filters/__tests__/convolution.test.ts @@ -1,4 +1,5 @@ import { Matrix } from 'ml-matrix'; +import { describe, expect, it } from 'vitest'; import { getClamp } from '../../utils/clamp.js'; import { getBorderInterpolation } from '../../utils/interpolateBorder.js'; @@ -35,6 +36,7 @@ describe('convolution functions', () => { }); const expected = testUtils.load('opencv/testConvolution.png'); + expect(convoluted).toMatchImage(expected); }); @@ -74,12 +76,14 @@ describe('computeConvolutionValue', () => { ]; const clamp = getClamp(image); const interpolateBorder = getBorderInterpolation('reflect101', 0); + expect( computeConvolutionValue(1, 1, 0, image, kernel, interpolateBorder, { clamp, }), ).toBe(28); }); + it('round and clamp with negative kernel values', () => { const image = testUtils.createGreyImage([ [1, 1, 1], @@ -94,12 +98,14 @@ describe('computeConvolutionValue', () => { const clamp = getClamp(image); const interpolateBorder = getBorderInterpolation('reflect101', 0); + expect( computeConvolutionValue(1, 1, 0, image, kernel, interpolateBorder, { clamp, }), ).toBe(5); }); + it('return raw value', () => { const image = testUtils.createGreyImage([ [1, 1, 1], @@ -135,8 +141,10 @@ describe('rawDirectConvolution', () => { ]; const expected = Float64Array.from([9, 28, 28, 9, 28, 28, 9, 9, 9]); + expect(rawDirectConvolution(image, kernel)).toStrictEqual(expected); }); + it('3x3 image and kernel with floats', () => { const image = testUtils.createGreyImage([ [1, 1, 1], @@ -152,6 +160,7 @@ describe('rawDirectConvolution', () => { const expected = Float64Array.from([ 8.5, 8.5, 8.5, 8.5, 8.5, 8.5, 8.5, 8.5, 8.5, ]); + expect(rawDirectConvolution(image, kernel)).toStrictEqual(expected); }); }); diff --git a/src/filters/__tests__/derivativeFilter.test.ts b/src/filters/__tests__/derivativeFilter.test.ts index 655d4fc8c..6d6a93988 100644 --- a/src/filters/__tests__/derivativeFilter.test.ts +++ b/src/filters/__tests__/derivativeFilter.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + const image = testUtils.createGreyImage([ [1, 1, 1], [1, 1, 1], @@ -41,6 +43,3 @@ test('Prewitt', () => { [2, 3, 2], ]); }); - -// To make TypeScript know it's a module -export {}; diff --git a/src/filters/__tests__/flip.test.ts b/src/filters/__tests__/flip.test.ts index db8a23b38..c9fd47c6e 100644 --- a/src/filters/__tests__/flip.test.ts +++ b/src/filters/__tests__/flip.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import { Image } from '../../Image.js'; test('invert with out parameter', () => { @@ -8,6 +10,7 @@ test('invert with out parameter', () => { ]); const expected = image.flip({ out }); + expect(expected).toMatchImageData([ [5, 6, 7, 1, 2, 3], [13, 14, 15, 9, 10, 11], @@ -19,6 +22,7 @@ test('invert with out parameter', () => { test('flip with out parameter set to self', () => { const image = testUtils.createRgbaImage([[1, 2, 3, 4, 5, 6, 7, 8]]); image.flip({ out: image }); + expect(image).toMatchImageData([[5, 6, 7, 8, 1, 2, 3, 4]]); }); @@ -28,6 +32,7 @@ test('flip pixels horizontally', () => { [9, 10, 11, 12, 13, 14, 15, 16], ]); const expected = image.flip(); + expect(expected).not.toBe(image); expect(expected).toMatchImageData([ [5, 6, 7, 8, 1, 2, 3, 4], @@ -43,6 +48,7 @@ test('flip pixels vertically', () => { ]); const expected = image.flip({ axis: 'vertical' }); + expect(expected).not.toBe(image); expect(expected).toMatchImageData([ [17, 18, 19, 20, 21, 22, 23, 24], @@ -58,6 +64,7 @@ test('flip pixels vertically and horizontally', () => { ]); const expected = image.flip({ axis: 'both' }); + expect(expected).toMatchImageData([ [13, 14, 15, 9, 10, 11], [5, 6, 7, 1, 2, 3], diff --git a/src/filters/__tests__/flipX.test.ts b/src/filters/__tests__/flipX.test.ts index ef253654d..9798cad2b 100644 --- a/src/filters/__tests__/flipX.test.ts +++ b/src/filters/__tests__/flipX.test.ts @@ -1,8 +1,11 @@ +import { expect, test } from 'vitest'; + import flipX from '../flipX.js'; test('should flip pixels horizontally of all RGBA components for a [2,1] image', () => { const image = testUtils.createRgbaImage([[1, 2, 3, 4, 5, 6, 7, 8]]); const expected = flipX(image); + expect(expected).toMatchImageData([[5, 6, 7, 8, 1, 2, 3, 4]]); }); @@ -13,6 +16,7 @@ test('should flip pixels horizontally of all RGBA components for a [2,2] image', ]); const expected = flipX(image); + expect(expected).toMatchImageData([ [5, 6, 7, 8, 1, 2, 3, 4], [13, 14, 15, 16, 9, 10, 11, 12], @@ -26,6 +30,7 @@ test('should flip pixels horizontally of all RGBA components for a [3,2] image', ]); const expected = flipX(image); + expect(expected).toMatchImageData([ [9, 10, 11, 12, 5, 6, 7, 8, 1, 2, 3, 4], [21, 22, 23, 24, 17, 18, 19, 20, 13, 14, 15, 16], @@ -39,6 +44,7 @@ test('should flip pixels horizontally of GREY image', () => { ]); const expected = flipX(image); + expect(expected).toMatchImageData([ [2, 1], [4, 3], diff --git a/src/filters/__tests__/flipY.test.ts b/src/filters/__tests__/flipY.test.ts index 1b51819e8..68df2202b 100644 --- a/src/filters/__tests__/flipY.test.ts +++ b/src/filters/__tests__/flipY.test.ts @@ -1,9 +1,12 @@ +import { expect, test } from 'vitest'; + import flipY from '../flipY.js'; test('should flip pixels vertically of all RGBA components for a [2,1] image', () => { const image = testUtils.createRgbaImage([[1, 2, 3, 4, 5, 6, 7, 8]]); const expected = flipY(image); + expect(expected).toMatchImageData([[1, 2, 3, 4, 5, 6, 7, 8]]); }); @@ -13,6 +16,7 @@ test('should flip pixels vertically of all RGBA components for a [2,2] image', ( [9, 10, 11, 12, 13, 14, 15, 16], ]); const expected = flipY(image); + expect(expected).toMatchImageData([ [9, 10, 11, 12, 13, 14, 15, 16], [1, 2, 3, 4, 5, 6, 7, 8], @@ -26,6 +30,7 @@ test('should flip pixels vertically of all RGBA components for a [3,2] image', ( ]); const expected = flipY(image); + expect(expected).toMatchImageData([ [13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], @@ -40,6 +45,7 @@ test('should flip pixels vertically of all RGBA components for a [2,3] image', ( ]); const expected = flipY(image); + expect(expected).toMatchImageData([ [17, 18, 19, 20, 21, 22, 23, 24], [9, 10, 11, 12, 13, 14, 15, 16], @@ -54,6 +60,7 @@ test('should flip pixels vertically of GREY image', () => { ]); const expected = flipY(image); + expect(expected).toMatchImageData([ [3, 4], [1, 2], diff --git a/src/filters/__tests__/gaussianBlur.test.ts b/src/filters/__tests__/gaussianBlur.test.ts index 66d08bc4e..4ec327a9d 100644 --- a/src/filters/__tests__/gaussianBlur.test.ts +++ b/src/filters/__tests__/gaussianBlur.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import type { GaussianBlurOptions, GaussianBlurSigmaOptions, @@ -90,7 +92,7 @@ test('x and y kernels', () => { ]); }); -test('x and y kernels', () => { +test('x and y kernels 2', () => { const image = testUtils.createGreyImage([ [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], @@ -121,5 +123,6 @@ test('gaussian blur should have same result as opencv', () => { const blurred = gaussianBlur(img, options); const expected = testUtils.load('opencv/testGaussianBlur.png'); + expect(blurred).toMatchImage(expected); }); diff --git a/src/filters/__tests__/gradientFilter.test.ts b/src/filters/__tests__/gradientFilter.test.ts index 0421ae2f4..2ec8c2289 100644 --- a/src/filters/__tests__/gradientFilter.test.ts +++ b/src/filters/__tests__/gradientFilter.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + const kernelX = [ [1, 0, 0], [0, 1, 0], @@ -47,12 +49,10 @@ test('gradientX and gradientY', () => { kernelY, borderType: 'constant', }); + expect(result).toMatchImageData([ [1, 1, 1], [1, 2, 2], [1, 2, 2], ]); }); - -// To make TypeScript know it's a module -export {}; diff --git a/src/filters/__tests__/hypotenuse.test.ts b/src/filters/__tests__/hypotenuse.test.ts index da2a7485f..3e3e512de 100644 --- a/src/filters/__tests__/hypotenuse.test.ts +++ b/src/filters/__tests__/hypotenuse.test.ts @@ -1,8 +1,11 @@ +import { expect, test } from 'vitest'; + test('testing with pythagorean triples', () => { const image = testUtils.createGreyImage([[3, 5, 8, 7]]); const otherImage = testUtils.createGreyImage([[4, 12, 15, 24]]); const expected = testUtils.createGreyImage([[5, 13, 17, 25]]); + expect(image.hypotenuse(otherImage)).toMatchImage(expected); }); @@ -47,6 +50,7 @@ test('testing with a custom channel', () => { const otherImage = testUtils.createRgbImage([[4, 12, 15]]); const expected = testUtils.createRgbImage([[3, 13, 8]]); + expect(image.hypotenuse(otherImage, { channels: [1] })).toMatchImage( expected, ); @@ -57,6 +61,7 @@ test('testing with custom channels', () => { const otherImage = testUtils.createRgbaImage([[4, 12, 15, 0]]); const expected = testUtils.createRgbaImage([[5, 13, 17, 0]]); + expect(image.hypotenuse(otherImage, { channels: [0, 1, 2] })).toMatchImage( expected, ); diff --git a/src/filters/__tests__/increaseContrast.test.ts b/src/filters/__tests__/increaseContrast.test.ts index f0180e60b..05dc01664 100644 --- a/src/filters/__tests__/increaseContrast.test.ts +++ b/src/filters/__tests__/increaseContrast.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import { increaseContrast } from '../increaseContrast.js'; test('3x1 rgba image, custom output min and max', () => { @@ -36,6 +38,7 @@ test('3x1 rgb image, uniform = true', () => { ]); const result = increaseContrast(image, { uniform: true }); + expect(result).toMatchImageData([ [0, 127, 0], [191, 191, 0], @@ -45,6 +48,7 @@ test('3x1 rgb image, uniform = true', () => { test('1x3 grey image', () => { const image = testUtils.createGreyImage([[50, 100]]); + expect(increaseContrast(image)).toMatchImageData([[0, 255]]); }); @@ -53,6 +57,7 @@ test('alpha should not be modified', () => { [50, 100], [100, 50], ]); + expect(increaseContrast(image)).toMatchImageData([ [0, 100], [255, 50], @@ -66,6 +71,7 @@ test('out option', () => { [60, 70], ]); const result = increaseContrast(image, { out: image }); + expect(result).toMatchImageData([ [0, 10], [127, 40], @@ -76,5 +82,6 @@ test('out option', () => { test('bigger image', () => { const image = testUtils.load('featureMatching/id-crops/crop2.png'); + expect(increaseContrast(image)).toMatchImageSnapshot(); }); diff --git a/src/filters/__tests__/invert.test.ts b/src/filters/__tests__/invert.test.ts index 31fa3e8f3..c1260c27e 100644 --- a/src/filters/__tests__/invert.test.ts +++ b/src/filters/__tests__/invert.test.ts @@ -1,3 +1,5 @@ +import { describe, expect, it } from 'vitest'; + import { Image } from '../../Image.js'; import { Mask } from '../../Mask.js'; @@ -5,6 +7,7 @@ describe('image is an Image', () => { it('invert an RGB image', () => { const img = testUtils.createRgbImage([[0, 50, 127, 255, 250, 4]]); const inverted = img.invert(); + expect(inverted).not.toBe(img); expect(inverted).toMatchImageData([[255, 205, 128, 0, 5, 251]]); }); @@ -14,6 +17,7 @@ describe('image is an Image', () => { [0, 50, 127, 200, 255, 250, 4, 200], ]); const inverted = img.invert(); + expect(inverted).not.toBe(img); expect(inverted).toMatchImageData([[255, 205, 128, 200, 0, 5, 251, 200]]); }); @@ -24,6 +28,7 @@ describe('image is an Image', () => { [255, 0], ]); const inverted = image.invert(); + expect(inverted).toMatchImageData([ [255, 255], [0, 0], @@ -37,6 +42,7 @@ describe('image is an Image', () => { ]); const inverted = image.invert(); + expect(inverted).not.toBe(image); expect(inverted).toMatchImageData([ [65534, 65533], @@ -52,6 +58,7 @@ describe('image is an Image', () => { const out = new Image(1, 2); const inverted = image.invert({ out }); + expect(inverted).toMatchImageData([ [25, 172, 135], [155, 115, 242], @@ -65,6 +72,7 @@ describe('image is an Image', () => { [255, 0], ]); image.invert({ out: image }); + expect(image).toMatchImageData([ [255, 255], [0, 0], @@ -76,9 +84,11 @@ describe('image is a Mask', () => { it('invert a Mask', () => { const mask = testUtils.createMask([[0, 1, 1, 1, 0, 0]]); const inverted = mask.invert(); + expect(inverted).not.toBe(mask); expect(inverted).toMatchMaskData([[1, 0, 0, 0, 1, 1]]); }); + it('invert with out parameter', () => { const mask = testUtils.createMask([ [1, 1, 1], @@ -87,6 +97,7 @@ describe('image is a Mask', () => { const out = new Mask(3, 2); const inverted = mask.invert({ out }); + expect(inverted).toMatchMaskData([ [0, 0, 0], [1, 1, 1], @@ -100,6 +111,7 @@ describe('image is a Mask', () => { [1, 0], ]); mask.invert({ out: mask }); + expect(mask).toMatchMaskData([ [1, 0], [0, 1], diff --git a/src/filters/__tests__/level.test.ts b/src/filters/__tests__/level.test.ts index 74502f91c..38a38b41c 100644 --- a/src/filters/__tests__/level.test.ts +++ b/src/filters/__tests__/level.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + test('3x1 rgba image, default options', () => { // should span contrast on the whole range const image = testUtils.createRgbaImage([ @@ -5,6 +7,7 @@ test('3x1 rgba image, default options', () => { [2, 2, 0, 50], [3, 1, 0, 50], ]); + expect(image.level()).toMatchImageData([ [0, 0, 255, 50], [127, 255, 0, 50], @@ -14,11 +17,13 @@ test('3x1 rgba image, default options', () => { test('1x1 rgba image, out to itself', () => { const image = testUtils.createRgbaImage([[100, 50, 0, 50]]); + expect(image.level({ out: image })).toBe(image); }); test('1x4 greya image, default options', () => { const image = testUtils.createRgbaImage([[100, 50, 0, 50]]); + expect(image.level()).toMatchImageData([[0, 0, 0, 50]]); }); @@ -28,6 +33,7 @@ test('3x1 rgba image, custom input min and max', () => { [125, 0, 0, 50], [150, 0, 0, 50], ]); + expect(image.level({ inputMin: 100, inputMax: 150 })).toMatchImageData([ [0, 0, 0, 50], [127, 0, 0, 50], @@ -41,6 +47,7 @@ test('3x1 rgba image, custom output min and max', () => { [127, 1, 0, 50], [255, 0, 0, 50], ]); + expect(image.level({ outputMin: 100, outputMax: 150 })).toMatchImageData([ [100, 100, 100, 50], [124, 150, 100, 50], @@ -50,6 +57,7 @@ test('3x1 rgba image, custom output min and max', () => { test('1x1 grey image, custom output and input values', () => { const image = testUtils.createGreyImage([[255]]); + expect( image.level({ inputMin: 50, @@ -66,6 +74,7 @@ test('3x1 rgba image, custom output and input values', () => { [30, 40, 50, 50], [60, 70, 80, 50], ]); + expect( image.level({ inputMin: 10, @@ -94,6 +103,7 @@ test('3x1 rgba image, custom channels', () => { outputMax: 100, channels: [1], }); + expect(result).toMatchImageData([ [0, 0, 20, 50], [30, 60, 50, 50], @@ -115,6 +125,7 @@ test('3x1 rgba image, other custom channels', () => { outputMax: 100, channels: [0, 3], }); + expect(result).toMatchImageData([ [0, 10, 20, 80], [40, 40, 50, 80], @@ -128,6 +139,7 @@ test('3x1 rgba image, modify alpha', () => { [30, 40, 50, 50], [60, 70, 80, 50], ]); + expect( image.level({ inputMin: 10, diff --git a/src/filters/__tests__/medianFilter.test.ts b/src/filters/__tests__/medianFilter.test.ts index db84d6104..fe9560da3 100644 --- a/src/filters/__tests__/medianFilter.test.ts +++ b/src/filters/__tests__/medianFilter.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + test('grey image 5x5', () => { const image = testUtils.createGreyImage([ [1, 2, 3, 4, 5], @@ -21,6 +23,7 @@ test('grey image 5x5', () => { [2, 2, 3, 4, 4], ]); }); + test('grey image 5x5 with bigger values', () => { const image = testUtils.createGreyImage([ [10, 2, 20, 4, 5], @@ -43,6 +46,7 @@ test('grey image 5x5 with bigger values', () => { [10, 2, 20, 4, 5], ]); }); + test('grey image 5x5 with different borderType and borderValue', () => { const image = testUtils.createGreyImage([ [10, 2, 20, 4, 5], @@ -56,6 +60,7 @@ test('grey image 5x5 with different borderType and borderValue', () => { cellSize: 7, borderValue: 1, }); + expect(result).toMatchImageData([ [1, 1, 1, 1, 1], [1, 2, 2, 2, 1], diff --git a/src/filters/__tests__/or.test.ts b/src/filters/__tests__/or.test.ts index 0c2da1045..17c5c6bea 100644 --- a/src/filters/__tests__/or.test.ts +++ b/src/filters/__tests__/or.test.ts @@ -1,24 +1,30 @@ +import { expect, test } from 'vitest'; + test('mask OR itself', () => { const image = testUtils.createMask([[1, 1, 1, 1, 1, 1, 1, 1]]); const other = image; + expect(image.or(other)).toMatchMask(image); }); test('two different masks', () => { const image = testUtils.createMask([[0, 0, 0, 0, 1, 1, 1, 1]]); const other = testUtils.createMask([[1, 1, 1, 1, 0, 0, 0, 0]]); + expect(image.or(other)).toMatchMaskData([[1, 1, 1, 1, 1, 1, 1, 1]]); }); test('when OR returns 0', () => { const image = testUtils.createMask([[0, 0, 0, 0, 1, 1, 1, 1]]); const other = testUtils.createMask([[0, 1, 0, 1, 0, 0, 0, 0]]); + expect(image.or(other)).toMatchMaskData([[0, 1, 0, 1, 1, 1, 1, 1]]); }); test('different size error', () => { const image = testUtils.createMask([[0, 0, 0, 0, 1, 1, 1, 1]]); const other = testUtils.createMask([[1, 1, 1, 0, 0, 0]]); + expect(() => { image.or(other); }).toThrow('both masks must have the same size'); diff --git a/src/filters/__tests__/pixelate.test.ts b/src/filters/__tests__/pixelate.test.ts index a0670df6a..4a71961b6 100644 --- a/src/filters/__tests__/pixelate.test.ts +++ b/src/filters/__tests__/pixelate.test.ts @@ -1,3 +1,5 @@ +import { describe, expect, it, test } from 'vitest'; + import { pixelate } from '../pixelate.js'; describe('pixelization of images', () => { @@ -9,12 +11,14 @@ describe('pixelization of images', () => { ]); const result = img.pixelate({ cellSize: 2 }); + expect(result).toMatchImageData([ [1, 1, 2], [1, 1, 2], [6, 6, 8], ]); }); + it('pixelate a simple grey image with xMedian', () => { const img = testUtils.createGreyImage([ [1, 1, 2], @@ -30,6 +34,7 @@ describe('pixelization of images', () => { [6, 6, 8], ]); }); + it('pixelate a bigger grey image', () => { const img = testUtils.createGreyImage([ [1, 1, 2, 2, 2], @@ -49,6 +54,7 @@ describe('pixelization of images', () => { [9, 9, 9, 0, 0], ]); }); + it('pixelate an RGBA image', () => { const img = testUtils.createRgbaImage([ [1, 1, 2, 2], @@ -79,6 +85,7 @@ describe('pixelization of images', () => { ]); const result = pixelate(img, { cellSize: 3 }); + expect(result).toMatchImageData([ [5, 5, 5, 5], [5, 5, 5, 5], @@ -87,6 +94,7 @@ describe('pixelization of images', () => { [4, 9, 0, 4], ]); }); + it('pixelate an RGBA H-like image with mean algorithm', () => { const img = testUtils.createRgbaImage([ [5, 1, 2, 5], @@ -97,6 +105,7 @@ describe('pixelization of images', () => { ]); const result = pixelate(img, { cellSize: 3, algorithm: 'mean' }); + expect(result).toMatchImageData([ [5, 3, 4, 5], [5, 3, 4, 5], @@ -105,6 +114,7 @@ describe('pixelization of images', () => { [4, 9, 0, 4], ]); }); + it('throws a Range error', () => { const img = testUtils.createRgbaImage([ [1, 1, 2, 2], @@ -113,10 +123,12 @@ describe('pixelization of images', () => { [2, 9, 4, 0], [1, 9, 9, 9], ]); + expect(() => { img.pixelate({ cellSize: 1 }); }).toThrow(new RangeError('cellSize must be greater than 1')); }); + it('throws a Type error', () => { const img = testUtils.createRgbaImage([ [1, 1, 2, 2], @@ -125,12 +137,14 @@ describe('pixelization of images', () => { [2, 9, 4, 0], [1, 9, 9, 9], ]); + expect(() => { img.pixelate({ cellSize: 2.3 }); }).toThrow(new TypeError('cellSize must be an integer')); }); }); -it('throws a Type error', () => { + +test('throws a Type error', () => { const img = testUtils.createRgbaImage([ [1, 1, 2, 2], [2, 3, 4, 2], @@ -138,6 +152,7 @@ it('throws a Type error', () => { [2, 9, 4, 0], [1, 9, 9, 9], ]); + expect(() => { //@ts-expect-error error testing img.pixelate({ cellSize: 2, algorithm: 'test' }); diff --git a/src/geometry/__tests__/getPerspectiveWarp.test.ts b/src/geometry/__tests__/getPerspectiveWarp.test.ts index 1ff25daf6..c50d5562e 100644 --- a/src/geometry/__tests__/getPerspectiveWarp.test.ts +++ b/src/geometry/__tests__/getPerspectiveWarp.test.ts @@ -1,8 +1,10 @@ +import { describe, expect, it } from 'vitest'; + import { Image } from '../../Image.js'; import { getPerspectiveWarp, order4Points } from '../getPerspectiveWarp.js'; describe('4 points sorting', () => { - test('basic sorting test', () => { + it('basic sorting test', () => { const points = [ { column: 0, row: 100 }, { column: 0, row: 0 }, @@ -11,14 +13,16 @@ describe('4 points sorting', () => { ]; const result = order4Points(points); - expect(result).toEqual([ + + expect(result).toStrictEqual([ { column: 0, row: 0 }, { column: 100, row: 1 }, { column: 100, row: 100 }, { column: 0, row: 100 }, ]); }); - test('inclined square', () => { + + it('inclined square', () => { const points = [ { column: 45, row: 0 }, { column: 0, row: 45 }, @@ -27,14 +31,16 @@ describe('4 points sorting', () => { ]; const result = order4Points(points); - expect(result).toEqual([ + + expect(result).toStrictEqual([ { column: 0, row: 45 }, { column: 90, row: 45 }, { column: 45, row: 0 }, { column: 45, row: 90 }, ]); }); - test('basic sorting test', () => { + + it('basic sorting test 2', () => { const points = [ { column: 155, row: 195 }, { column: 154, row: 611 }, @@ -43,7 +49,8 @@ describe('4 points sorting', () => { ]; const result = order4Points(points); - expect(result).toEqual([ + + expect(result).toStrictEqual([ { column: 155, row: 195 }, { column: 858.5, row: 700 }, @@ -67,11 +74,13 @@ describe('warping tests', () => { ]; const matrix = getPerspectiveWarp(points); const result = image.transform(matrix.matrix, { inverse: true }); + expect(result.width).not.toBeLessThan(2); expect(result.height).not.toBeLessThan(2); expect(result.width).not.toBeGreaterThan(3); expect(result.height).not.toBeGreaterThan(3); }); + it('resize without rotation 2', () => { const image = new Image(4, 4, { data: new Uint8Array([ @@ -88,6 +97,7 @@ describe('warping tests', () => { ]; const matrix = getPerspectiveWarp(points); const result = image.transform(matrix.matrix, { inverse: true }); + expect(result.width).not.toBeLessThan(3); expect(result.height).not.toBeLessThan(1); expect(result.width).not.toBeGreaterThan(4); @@ -96,7 +106,7 @@ describe('warping tests', () => { }); describe('openCV comparison', () => { - test('nearest interpolation plants', () => { + it('nearest interpolation plants', () => { const image = testUtils.load('opencv/plants.png'); const openCvResult = testUtils.load( 'opencv/test_perspective_warp_plants_nearest.png', @@ -128,12 +138,12 @@ describe('openCV comparison', () => { height: 100, }); - expect(result.width).toEqual(openCvResult.width); - expect(result.height).toEqual(openCvResult.height); - expect(croppedPiece).toEqual(croppedPieceOpenCv); + expect(result.width).toStrictEqual(openCvResult.width); + expect(result.height).toStrictEqual(openCvResult.height); + expect(croppedPiece).toStrictEqual(croppedPieceOpenCv); }); - test('nearest interpolation card', () => { + it('nearest interpolation card', () => { const image = testUtils.load('opencv/card.png'); const openCvResult = testUtils.load( 'opencv/test_perspective_warp_card_nearest.png', @@ -166,11 +176,12 @@ describe('openCV comparison', () => { height: 5, }); - expect(result.width).toEqual(openCvResult.width); - expect(result.height).toEqual(openCvResult.height); - expect(croppedPiece).toEqual(croppedPieceOpenCv); + expect(result.width).toStrictEqual(openCvResult.width); + expect(result.height).toStrictEqual(openCvResult.height); + expect(croppedPiece).toStrictEqual(croppedPieceOpenCv); }); - test('nearest interpolation poker card', () => { + + it('nearest interpolation poker card', () => { const image = testUtils.load('opencv/poker_cards.png'); const openCvResult = testUtils.load( 'opencv/test_perspective_warp_poker_cards_nearest.png', @@ -201,21 +212,22 @@ describe('openCV comparison', () => { height: 100, }); - expect(result.width).toEqual(openCvResult.width); - expect(result.height).toEqual(openCvResult.height); - expect(cropped).toEqual(croppedCV); + expect(result.width).toStrictEqual(openCvResult.width); + expect(result.height).toStrictEqual(openCvResult.height); + expect(cropped).toStrictEqual(croppedCV); }); }); describe('error testing', () => { - test("should throw if there aren't 4 points", () => { + it("should throw if there aren't 4 points", () => { expect(() => { getPerspectiveWarp([{ column: 1, row: 1 }]); }).toThrow( 'The array pts must have four elements, which are the four corners. Currently, pts have 1 elements', ); }); - test('should throw if either only width or only height are defined', () => { + + it('should throw if either only width or only height are defined', () => { expect(() => { getPerspectiveWarp( [ diff --git a/src/geometry/__tests__/resize.test.ts b/src/geometry/__tests__/resize.test.ts index 89644db31..6dcac31b1 100644 --- a/src/geometry/__tests__/resize.test.ts +++ b/src/geometry/__tests__/resize.test.ts @@ -1,5 +1,7 @@ import path from 'node:path'; +import { expect, test } from 'vitest'; + import type { Image } from '../../Image.js'; import { write } from '../../save/index.js'; @@ -56,7 +58,7 @@ test('compare with OpenCV (nearest, smaller)', async () => { expect(resized).toMatchImage('opencv/test_resize_nearest_smaller.png'); }); -test.skip('compare with OpenCV (bilinear, larger)', async () => { +test.fails('compare with OpenCV (bilinear, larger)', async () => { const img = testUtils.load('opencv/test.png'); const resized = img.resize({ @@ -69,7 +71,7 @@ test.skip('compare with OpenCV (bilinear, larger)', async () => { expect(resized).toMatchImage('opencv/test_resize_bilinear_larger.png'); }); -test.skip('compare with OpenCV (bilinear, same)', async () => { +test.fails('compare with OpenCV (bilinear, same)', async () => { const img = testUtils.load('opencv/test.png'); const resized = img.resize({ @@ -81,7 +83,7 @@ test.skip('compare with OpenCV (bilinear, same)', async () => { expect(resized).toMatchImage('opencv/test_resize_bilinear_same.png'); }); -test.skip('compare with OpenCV (bilinear, smaller)', async () => { +test.fails('compare with OpenCV (bilinear, smaller)', async () => { const img = testUtils.load('opencv/test.png'); const resized = img.resize({ @@ -94,7 +96,7 @@ test.skip('compare with OpenCV (bilinear, smaller)', async () => { expect(resized).toMatchImage('opencv/test_resize_bilinear_smaller.png'); }); -test.skip('compare with OpenCV (bicubic, larger)', async () => { +test.fails('compare with OpenCV (bicubic, larger)', async () => { const img = testUtils.load('opencv/test.png'); const resized = img.resize({ @@ -108,7 +110,7 @@ test.skip('compare with OpenCV (bicubic, larger)', async () => { expect(resized).toMatchImage('opencv/test_resize_bicubic_larger.png'); }); -test.skip('compare with OpenCV (bicubic, same)', async () => { +test.fails('compare with OpenCV (bicubic, same)', async () => { const img = testUtils.load('opencv/test.png'); const resized = img.resize({ @@ -121,7 +123,7 @@ test.skip('compare with OpenCV (bicubic, same)', async () => { expect(resized).toMatchImage('opencv/test_resize_bicubic_same.png'); }); -test.skip('compare with OpenCV (bicubic, smaller)', async () => { +test.fails('compare with OpenCV (bicubic, smaller)', async () => { const img = testUtils.load('opencv/test.png'); const resized = img.resize({ @@ -142,6 +144,7 @@ test('result should have correct dimensions', () => { xFactor: 10, yFactor: 10, }); + expect(resized.width).toBe(10 * img.width); expect(resized.height).toBe(10 * img.height); }); diff --git a/src/geometry/__tests__/rotate.test.ts b/src/geometry/__tests__/rotate.test.ts index 6e9a6082f..98089a13a 100644 --- a/src/geometry/__tests__/rotate.test.ts +++ b/src/geometry/__tests__/rotate.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + const image = testUtils.createGreyImage(` 1 2 3 4 5 6 diff --git a/src/geometry/__tests__/transform.test.ts b/src/geometry/__tests__/transform.test.ts index ed4b30dc9..5373b0aee 100644 --- a/src/geometry/__tests__/transform.test.ts +++ b/src/geometry/__tests__/transform.test.ts @@ -1,5 +1,7 @@ //To look at the equivalent opencv code go to generate.py in test/img/opencv //folder. +import { expect, test } from 'vitest'; + test('compare result of translation with opencv with default parameters', () => { const img = testUtils.load('opencv/test.png'); const translation = [ @@ -31,6 +33,7 @@ test('compare result of clockwise rotation with opencv', () => { interpolationType: 'bilinear', }, ); + expect(transformed).toMatchImage('opencv/testClockwiseRot90.png'); }); @@ -49,6 +52,7 @@ test('compare result of clockwise rotation with opencv and fullImage:true', () = interpolationType: 'bilinear', }, ); + expect(transformed).toMatchImage('opencv/testClockwiseRot90.png'); }); @@ -69,6 +73,7 @@ test('compare result of anti-clockwise rotation with opencv', () => { interpolationType: 'bilinear', }, ); + expect(transformed).toMatchImage('opencv/testAntiClockwiseRot90.png'); }); @@ -87,8 +92,10 @@ test('get a vertical reflection of an image', () => { interpolationType: 'bilinear', }, ); + expect(transformed).toMatchImage('opencv/testReflect.png'); }); + //problematic test1 //Scaling with test image works only if the image is scaled by 2 or by 4. test('get a scale of an image to 32*40', () => { @@ -108,6 +115,7 @@ test('get a scale of an image to 32*40', () => { interpolationType: 'bilinear', }, ); + expect(transformed).toMatchImage('opencv/testScale.png'); }); @@ -125,6 +133,7 @@ test('affineTransformation', () => { borderType: 'constant', }, ); + // OpenCV bilinear interpolation is less precise for speed. expect(transformed).toMatchImage('opencv/testAffineTransform.png', { error: 3, @@ -137,6 +146,7 @@ test('should throw if matrix has wrong size', () => { [1, 0, 2, 3], [0, 1, 10, 4], ]; + expect(() => { img.transform(translation); }).toThrow('transformation matrix must be 2x3 or 3x3. Received 2x4'); diff --git a/src/geometry/__tests__/transformRotate.test.ts b/src/geometry/__tests__/transformRotate.test.ts index b6ea407a0..4fb9b94de 100644 --- a/src/geometry/__tests__/transformRotate.test.ts +++ b/src/geometry/__tests__/transformRotate.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import { encodePng } from '../../save/index.js'; import { transformRotate } from '../transformRotate.js'; @@ -22,6 +24,7 @@ test('rotate + scale compared to opencv (bilinear)', () => { interpolationType: 'bilinear', center: { column: 2, row: 4 }, }); + // OpenCV bilinear interpolation is less precise for speed. expect(rotated).toMatchImage('opencv/testRotateBilinear.png', { error: 5 }); }); diff --git a/src/geometry/transform.ts b/src/geometry/transform.ts index 3efff74cf..fecc8662c 100644 --- a/src/geometry/transform.ts +++ b/src/geometry/transform.ts @@ -1,4 +1,4 @@ -import { inverse, Matrix } from 'ml-matrix'; +import { Matrix, inverse } from 'ml-matrix'; import { Image } from '../Image.js'; import { getClamp } from '../utils/clamp.js'; diff --git a/src/load/__tests__/decode.test.ts b/src/load/__tests__/decode.test.ts index 0c0df2d54..ffccca738 100644 --- a/src/load/__tests__/decode.test.ts +++ b/src/load/__tests__/decode.test.ts @@ -1,27 +1,38 @@ +import { expect, test } from 'vitest'; + import { decode } from '../decode.js'; test('auto decode png', () => { const buffer = testUtils.loadBuffer('formats/grey8.png'); + expect(() => decode(buffer)).not.toThrow(); + const decoded = decode(buffer); - expect(decoded.bitDepth).toStrictEqual(8); - expect(decoded.colorModel).toStrictEqual('GREY'); + + expect(decoded.bitDepth).toBe(8); + expect(decoded.colorModel).toBe('GREY'); }); test('auto decode jpeg', () => { const buffer = testUtils.loadBuffer('formats/rgb12.jpg'); + expect(() => decode(buffer)).not.toThrow(); + const decoded = decode(buffer); - expect(decoded.bitDepth).toStrictEqual(8); - expect(decoded.colorModel).toStrictEqual('RGBA'); + + expect(decoded.bitDepth).toBe(8); + expect(decoded.colorModel).toBe('RGBA'); }); test('auto decode tiff', () => { const buffer = testUtils.loadBuffer('formats/tif/grey8.tif'); + expect(() => decode(buffer)).not.toThrow(); + const decoded = decode(buffer); - expect(decoded.bitDepth).toStrictEqual(8); - expect(decoded.colorModel).toStrictEqual('GREY'); + + expect(decoded.bitDepth).toBe(8); + expect(decoded.colorModel).toBe('GREY'); }); test('should throw for too small data', () => { diff --git a/src/load/__tests__/decodeJpeg.test.ts b/src/load/__tests__/decodeJpeg.test.ts index 0f4034563..bb81f0479 100644 --- a/src/load/__tests__/decodeJpeg.test.ts +++ b/src/load/__tests__/decodeJpeg.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import { decodeJpeg } from '../decodeJpeg.js'; const tests = [['grey6'], ['grey12'], ['rgb6'], ['rgb12']] as const; @@ -5,6 +7,7 @@ const tests = [['grey6'], ['grey12'], ['rgb6'], ['rgb12']] as const; test.each(tests)('should load from buffer %s', (name) => { const buffer = testUtils.loadBuffer(`formats/${name}.jpg`); const img = decodeJpeg(buffer); + expect(img.colorModel).toBe('RGBA'); expect(img.bitDepth).toBe(8); }); diff --git a/src/load/__tests__/decodePng.test.ts b/src/load/__tests__/decodePng.test.ts index 5d4c5857e..ad11d575f 100644 --- a/src/load/__tests__/decodePng.test.ts +++ b/src/load/__tests__/decodePng.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import { decodePng } from '../decodePng.js'; const tests = [ @@ -17,6 +19,7 @@ const tests = [ test.each(tests)('should load from buffer %s', (name, bitDepth, colorModel) => { const buffer = testUtils.loadBuffer(`formats/${name}.png`); const img = decodePng(buffer); + expect(img.bitDepth).toBe(bitDepth); expect(img.colorModel).toBe(colorModel); }); diff --git a/src/load/__tests__/decodeTiff.test.ts b/src/load/__tests__/decodeTiff.test.ts index 34a91e646..0271f81fe 100644 --- a/src/load/__tests__/decodeTiff.test.ts +++ b/src/load/__tests__/decodeTiff.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import { decodeTiff } from '../decodeTiff.js'; const tests = [ @@ -16,6 +18,7 @@ const tests = [ test.each(tests)('%s', (name, colorModel, bitDepth) => { const buffer = testUtils.loadBuffer(`formats/tif/${name}.tif`); const img = decodeTiff(buffer); + expect(img.colorModel).toBe(colorModel); expect(img.bitDepth).toBe(bitDepth); }); diff --git a/src/load/__tests__/fetchURL.test.ts b/src/load/__tests__/fetchURL.test.ts index 9b6152294..fd71a0027 100644 --- a/src/load/__tests__/fetchURL.test.ts +++ b/src/load/__tests__/fetchURL.test.ts @@ -1,24 +1,29 @@ +import { describe, expect, it } from 'vitest'; + import { encodeDataURL } from '../../save/encodeDataURL.js'; import { fetchURL } from '../fetchURL.js'; describe('testing fetchURL', () => { - test('decodes image from data URL', async () => { + it('decodes image from data URL', async () => { const image = await fetchURL( 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAAAAACoBHk5AAAAFklEQVR4XmNggID///+DSCCEskHM/wCAnQr2TY5mOAAAAABJRU5ErkJggg==', ); + expect(image.bitDepth).toBe(8); - expect(image.getRawImage().data).toEqual( + expect(image.getRawImage().data).toStrictEqual( new Uint8Array([ 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 0, 255, 0, 255, 0, 0, 255, 255, 255, 0, 255, 0, 255, 0, 255, ]), ); }); - test('encoded URL must be equal to decoded one', async () => { + + it('encoded URL must be equal to decoded one', async () => { const dataURL = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAAAAACoBHk5AAAAFklEQVR4XmNggID///+DSCCEskHM/wCAnQr2TY5mOAAAAABJRU5ErkJggg=='; const image = await fetchURL(dataURL); const result = encodeDataURL(image); - expect(result).toEqual(dataURL); + + expect(result).toStrictEqual(dataURL); }); }); diff --git a/src/load/__tests__/getMetadata.test.ts b/src/load/__tests__/getMetadata.test.ts index 27b0bc856..35ed0082f 100644 --- a/src/load/__tests__/getMetadata.test.ts +++ b/src/load/__tests__/getMetadata.test.ts @@ -1,20 +1,25 @@ +import { expect, test } from 'vitest'; + import { decodeJpeg } from '../decodeJpeg.js'; import { decodeTiff } from '../decodeTiff.js'; test('without metadata', () => { const buffer = testUtils.loadBuffer(`various/without-metadata.jpg`); const img = decodeJpeg(buffer); + expect(img.meta).toBeUndefined(); }); test('with metadata', () => { const buffer = testUtils.loadBuffer(`formats/grey6.jpg`); const img = decodeJpeg(buffer); + expect(img.meta).toBeDefined(); }); test('with metadata 2', () => { const buffer = testUtils.loadBuffer(`formats/tif/grey32.tif`); const img = decodeTiff(buffer); + expect(img.meta).toBeDefined(); }); diff --git a/src/load/__tests__/read.test.ts b/src/load/__tests__/read.test.ts index e50d5558e..8bd06cd36 100644 --- a/src/load/__tests__/read.test.ts +++ b/src/load/__tests__/read.test.ts @@ -1,8 +1,11 @@ +import { expect, test } from 'vitest'; + import { Image } from '../../Image.js'; import { read } from '../read.js'; test('read existing image', async () => { const img = await read(testUtils.getPath('formats/rgba32.png')); + expect(img).toBeInstanceOf(Image); expect(img).toMatchObject({ width: 30, diff --git a/src/maskAnalysis/__tests__/getBorderPoints.test.ts b/src/maskAnalysis/__tests__/getBorderPoints.test.ts index a8607851d..d0446aa2d 100644 --- a/src/maskAnalysis/__tests__/getBorderPoints.test.ts +++ b/src/maskAnalysis/__tests__/getBorderPoints.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import { Mask } from '../../Mask.js'; test('3x3 mask', () => { @@ -56,6 +58,7 @@ test('5x5 mask with hole, inner borders, allow corners', () => { }); const bordersMask = Mask.fromPoints(mask.width, mask.height, points); + expect(bordersMask).toMatchMask(mask); }); diff --git a/src/maskAnalysis/__tests__/getConvexHull.test.ts b/src/maskAnalysis/__tests__/getConvexHull.test.ts index dae1e72a9..5669e52b9 100644 --- a/src/maskAnalysis/__tests__/getConvexHull.test.ts +++ b/src/maskAnalysis/__tests__/getConvexHull.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import { getConvexHull } from '../getConvexHull.js'; test('cross', () => { @@ -8,6 +10,7 @@ test('cross', () => { ]); const convexHull = getConvexHull(mask); + expect(convexHull).toBeDeepCloseTo( { points: [ @@ -35,6 +38,7 @@ test('small triangle', () => { ]); const convexHull = getConvexHull(mask); + expect(convexHull).toBeDeepCloseTo( { points: [ @@ -50,6 +54,7 @@ test('small triangle', () => { 1, ); }); + test('1 pixel ROI', () => { const mask = testUtils.createMask([ [0, 0, 0], @@ -58,6 +63,7 @@ test('1 pixel ROI', () => { ]); const convexHull = getConvexHull(mask); + expect(convexHull).toBeDeepCloseTo( { points: [ @@ -72,6 +78,7 @@ test('1 pixel ROI', () => { 1, ); }); + test('2 pixels ROI', () => { const mask = testUtils.createMask([ [0, 0, 0], @@ -80,6 +87,7 @@ test('2 pixels ROI', () => { ]); const convexHull = getConvexHull(mask); + expect(convexHull).toBeDeepCloseTo( { points: [ @@ -94,6 +102,7 @@ test('2 pixels ROI', () => { 1, ); }); + test('5x5 cross', () => { const mask = testUtils.createMask([ [0, 0, 1, 0, 0], @@ -104,6 +113,7 @@ test('5x5 cross', () => { ]); const convexHull = getConvexHull(mask); + expect(convexHull).toBeDeepCloseTo( { points: [ @@ -122,6 +132,7 @@ test('5x5 cross', () => { 1, ); }); + test('random shape', () => { const mask = testUtils.createMask([ [0, 0, 1, 0, 0], @@ -132,6 +143,7 @@ test('random shape', () => { ]); const convexHull = getConvexHull(mask); + expect(convexHull.points).toStrictEqual([ { column: 0, row: 4 }, { column: 0, row: 5 }, @@ -142,6 +154,7 @@ test('random shape', () => { { column: 2, row: 0 }, ]); }); + test('empty mask', () => { const mask = testUtils.createMask([ [0, 0], diff --git a/src/maskAnalysis/__tests__/getFeret.test.ts b/src/maskAnalysis/__tests__/getFeret.test.ts index 75b2883aa..29349eef2 100644 --- a/src/maskAnalysis/__tests__/getFeret.test.ts +++ b/src/maskAnalysis/__tests__/getFeret.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + test('empty mask', () => { const mask = testUtils.createMask(`0 0 0`); const result = mask.getFeret(); @@ -45,9 +47,11 @@ test('empty mask', () => { 3, ); }); + test('mask with only 1 pixel', () => { const mask = testUtils.createMask(`0 1 0`); const result = mask.getFeret(); + // the minimum diameter points are not as expected, // but this is a very edge case so it does not matter too much expect(result).toBeDeepCloseTo( @@ -93,6 +97,7 @@ test('mask with only 1 pixel', () => { 3, ); }); + test('mask 3x3', () => { const mask = testUtils.createMask(` 0 1 0 @@ -100,6 +105,7 @@ test('mask 3x3', () => { 0 1 0 `); const result = mask.getFeret(); + expect(result).toBeDeepCloseTo( { minDiameter: { diff --git a/src/maskAnalysis/__tests__/getMbr.test.ts b/src/maskAnalysis/__tests__/getMbr.test.ts index 4e7e4334a..b9ddaa5e6 100644 --- a/src/maskAnalysis/__tests__/getMbr.test.ts +++ b/src/maskAnalysis/__tests__/getMbr.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import { fromMask } from '../../roi/index.js'; import { angle } from '../../utils/geometry/angles.js'; import { getMbr } from '../getMbr.js'; @@ -15,6 +17,7 @@ test('verify that angle is correct', () => { `); const result = getMbr(mask).points; + expect(result).toHaveLength(4); for (let i = 0; i < 4; i++) { @@ -23,6 +26,7 @@ test('verify that angle is correct', () => { result[i], result[(i + 2) % 4], ); + expect(Math.abs(currentAngle)).toBeCloseTo(Math.PI / 2, 1e-6); } }); @@ -36,6 +40,7 @@ test('small rectangular ROI', () => { ]); const result = getMbr(mask).points; + expect(result).toBeDeepCloseTo( [ { column: 4, row: 1 }, @@ -84,6 +89,7 @@ test('other horizontal MBR', () => { ); const result = getMbr(mask); + expect(result).toBeDeepCloseTo({ points: [ { column: 6, row: 3 }, @@ -108,6 +114,7 @@ test('small tilted rectangle', () => { `); const result = getMbr(mask); + expect(result.points).toBeDeepCloseTo( [ { column: 1.5, row: 3.5 }, @@ -130,6 +137,7 @@ test('large tilted rectangle', () => { 0 0 0 1 0 0 `); const result = getMbr(mask).points; + expect(result).toBeDeepCloseTo( [ { column: 2.5, row: -0.5 }, @@ -144,6 +152,7 @@ test('large tilted rectangle', () => { test('one point ROI', () => { const mask = testUtils.createMask([[1]]); const result = getMbr(mask).points; + expect(result).toBeDeepCloseTo([ { column: 0, row: 1 }, { column: 0, row: 0 }, @@ -234,7 +243,7 @@ test('draw mbr on large image', () => { expect(result).toMatchImageSnapshot(); }); -test('other horizontal MBR', () => { +test('other horizontal MBR - aspect ratio', () => { const mask = testUtils.createMask( ` 1 0 0 0 1 0 @@ -244,10 +253,11 @@ test('other horizontal MBR', () => { ); const result = getMbr(mask); + expect(result.aspectRatio).toBeCloseTo(0.5); }); -test('small triangular ROI', () => { +test('small triangular ROI - aspect ratio', () => { const mask = testUtils.createMask([ [0, 1, 0], [1, 1, 1], @@ -259,7 +269,7 @@ test('small triangular ROI', () => { expect(result).toBeCloseTo(1); }); -test('small triangular ROI', () => { +test('small triangular ROI 2 - aspect ratio', () => { const mask = testUtils.createMask([ [0, 1, 0], [0, 1, 0], @@ -272,7 +282,7 @@ test('small triangular ROI', () => { expect(result).toStrictEqual(0.25); }); -test('small triangular ROI', () => { +test('small triangular ROI 3 - aspect ratio', () => { const mask = testUtils.createMask([[1, 1, 1, 1]]); const result = getMbr(mask).aspectRatio; diff --git a/src/maskAnalysis/utils/__tests__/getAngle.test.ts b/src/maskAnalysis/utils/__tests__/getAngle.test.ts index 8539d2f5b..625d46995 100644 --- a/src/maskAnalysis/utils/__tests__/getAngle.test.ts +++ b/src/maskAnalysis/utils/__tests__/getAngle.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import { getAngle, getClockwiseAngle } from '../getAngle.js'; test.each([ @@ -32,6 +34,7 @@ test.each([ ['90 degrees', { column: 0, row: 0 }, { column: 0, row: -1 }, -Math.PI / 2], ])('getAngle (%s)', (_, point1, point2, expectedAngle) => { const result = getAngle(point1, point2); + expect(result).toBeCloseTo(expectedAngle); }); @@ -79,5 +82,6 @@ test.each([ ], ])('getClockwiseAngle (%s)', (_, point1, point2, expectedAngle) => { const result = getClockwiseAngle(point1, point2); + expect(result).toBeCloseTo(expectedAngle); }); diff --git a/src/maskAnalysis/utils/__tests__/getExtendedBorderPoints.test.ts b/src/maskAnalysis/utils/__tests__/getExtendedBorderPoints.test.ts index f7c972b3e..b75a88a8e 100644 --- a/src/maskAnalysis/utils/__tests__/getExtendedBorderPoints.test.ts +++ b/src/maskAnalysis/utils/__tests__/getExtendedBorderPoints.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import { Mask } from '../../../Mask.js'; import { getExtendedBorderPoints } from '../getExtendedBorderPoints.js'; diff --git a/src/maskAnalysis/utils/__tests__/getMbrAngle.test.ts b/src/maskAnalysis/utils/__tests__/getMbrAngle.test.ts index 14c299a03..265f3ff40 100644 --- a/src/maskAnalysis/utils/__tests__/getMbrAngle.test.ts +++ b/src/maskAnalysis/utils/__tests__/getMbrAngle.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import { getMbrAngle } from '../getMbrAngle.js'; test.each([ diff --git a/src/maskAnalysis/utils/__tests__/getMbrFromPoints.test.ts b/src/maskAnalysis/utils/__tests__/getMbrFromPoints.test.ts index 99edeb703..83ae27c6a 100644 --- a/src/maskAnalysis/utils/__tests__/getMbrFromPoints.test.ts +++ b/src/maskAnalysis/utils/__tests__/getMbrFromPoints.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import { getMbrFromPoints } from '../getMbrFromPoints.js'; test.each([ diff --git a/src/maskAnalysis/utils/__tests__/monotoneChainConvexHull.test.ts b/src/maskAnalysis/utils/__tests__/monotoneChainConvexHull.test.ts index 129a8725a..b6ef6d675 100644 --- a/src/maskAnalysis/utils/__tests__/monotoneChainConvexHull.test.ts +++ b/src/maskAnalysis/utils/__tests__/monotoneChainConvexHull.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import { monotoneChainConvexHull as mcch } from '../monotoneChainConvexHull.js'; test('basic square', () => { @@ -7,6 +9,7 @@ test('basic square', () => { { column: 1, row: 0 }, { column: 1, row: 1 }, ]); + expect(result).toStrictEqual([ { column: 0, row: 0 }, { column: 0, row: 1 }, @@ -34,6 +37,7 @@ test('mixed square', () => { { column: 1, row: 2 }, { column: 2, row: 2 }, ]); + expect(result).toStrictEqual([ { column: 0, row: 0 }, { column: 0, row: 2 }, @@ -52,6 +56,7 @@ test('rectangle with inside points', () => { { column: 0, row: 2 }, { column: 0, row: 0 }, ]); + expect(result).toStrictEqual([ { column: 0, row: 0 }, { column: 0, row: 2 }, @@ -72,6 +77,7 @@ test('more complex shape', () => { { column: 3, row: 6 }, { column: 2, row: 4 }, ]); + expect(result).toStrictEqual([ { column: -1, row: -1 }, { column: 0, row: 8 }, @@ -94,6 +100,7 @@ test('already sorted', () => { ], { sorted: true }, ); + expect(result).toStrictEqual([ { column: 0, row: 0 }, { column: 0, row: 2 }, diff --git a/src/morphology/__tests__/bottomHat.test.ts b/src/morphology/__tests__/bottomHat.test.ts index 2093130c2..9eba84012 100644 --- a/src/morphology/__tests__/bottomHat.test.ts +++ b/src/morphology/__tests__/bottomHat.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + test('GREY image 5x5', () => { const image = testUtils.createGreyImage([ [0, 0, 255, 0, 0], diff --git a/src/morphology/__tests__/cannyEdgeDetector.test.ts b/src/morphology/__tests__/cannyEdgeDetector.test.ts index 03b332aed..f31f7cde2 100644 --- a/src/morphology/__tests__/cannyEdgeDetector.test.ts +++ b/src/morphology/__tests__/cannyEdgeDetector.test.ts @@ -1,3 +1,5 @@ +import { describe, expect, it } from 'vitest'; + import { getDirection } from '../cannyEdgeDetector.js'; describe('cannyEdgeDetector', () => { @@ -27,6 +29,7 @@ describe('cannyEdgeDetector', () => { expect(result).toMatchMask(expected); }); + it('asymetrical image', () => { const image = testUtils.createGreyImage([ [0, 0, 0, 0, 0], @@ -49,6 +52,7 @@ describe('cannyEdgeDetector', () => { expect(result).toMatchMask(expected); }); + it('5x5 grey image with circle', () => { const image = testUtils.createGreyImage([ [0, 0, 0, 0, 0], @@ -99,8 +103,10 @@ describe('cannyEdgeDetector', () => { hysteresis: true, gaussianBlurOptions: { sigma: 1, size: 1 }, }); + expect(result).toMatchMask(expected); }); + it('compare alphabet image to expected', () => { const image = testUtils.load('various/alphabet.jpg').convertColor('GREY'); @@ -109,14 +115,17 @@ describe('cannyEdgeDetector', () => { .threshold(); const result = image.cannyEdgeDetector(); + expect(result).toMatchMask(expected); }); + it('compare grey image to expected', () => { const image = testUtils.load('various/grayscale_by_zimmyrose.png'); const expected = testUtils .load('morphology/grayscaleCannyEdge.png') .threshold(); + expect(image.cannyEdgeDetector()).toMatchMask(expected); }); }); @@ -128,30 +137,35 @@ describe('getDirection', () => { expect(getDirection(x, y)).toBe(0); }); + it('horizontal, float', () => { const x = 1.5; const y = 0.1; expect(getDirection(x, y)).toBe(0); }); + it('upward diagonal', () => { const x = 1; const y = 1; expect(getDirection(x, y)).toBe(1); }); + it('vertical, integer', () => { const x = 0; const y = 1; expect(getDirection(x, y)).toBe(2); }); + it('vertical, float', () => { const x = 0.1; const y = 1.2; expect(getDirection(x, y)).toBe(2); }); + it('downward diagonal', () => { const x = -1; const y = 1; diff --git a/src/morphology/__tests__/clearBorder.test.ts b/src/morphology/__tests__/clearBorder.test.ts index 9a3fbbf1a..3e5975d64 100644 --- a/src/morphology/__tests__/clearBorder.test.ts +++ b/src/morphology/__tests__/clearBorder.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import { Mask } from '../../Mask.js'; test('5x5 mask, without corners', () => { @@ -79,6 +81,7 @@ test('Diagonal of 1, allow corners', () => { [0, 0, 0, 0, 1], ]); const result = image.clearBorder({ allowCorners: true }); + expect(result).toMatchMaskData([ [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], @@ -99,6 +102,7 @@ test('Diagonal of 1, color=black', () => { image = image.invert(); let result = image.clearBorder({ color: 'black' }); result = result.invert(); + expect(result).toMatchMaskData([ [0, 0, 0, 0, 0], [0, 1, 0, 1, 0], @@ -117,6 +121,7 @@ test('5x5 mask, full', () => { [1, 1, 1, 1, 1], ]); const result = image.clearBorder({ allowCorners: false }); + expect(result).toMatchMaskData([ [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], @@ -138,6 +143,7 @@ test('out option', () => { const out = new Mask(5, 5); image.clearBorder({ allowCorners: true, out }); + expect(out).toMatchMaskData([ [0, 0, 0, 0, 0], [0, 0, 0, 1, 0], @@ -156,6 +162,7 @@ test('5x5 mask, no pixels touching top', () => { [0, 1, 0, 0, 1], ]); const result = image.clearBorder({ allowCorners: false }); + expect(result).toMatchMaskData([ [0, 0, 0, 0, 0], [0, 1, 1, 1, 0], @@ -174,6 +181,7 @@ test('5x5 mask, snake', () => { [0, 0, 0, 1, 1], ]); const result = image.clearBorder({ allowCorners: false }); + expect(result).toMatchMaskData([ [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], @@ -187,5 +195,6 @@ test('larger image', () => { const image = testUtils.load('various/grayscale_by_zimmyrose.png'); const mask = image.threshold(); const cleared = mask.clearBorder(); + expect(cleared).toMatchImageSnapshot(); }); diff --git a/src/morphology/__tests__/close.test.ts b/src/morphology/__tests__/close.test.ts index 94ae10349..3c8d3e582 100644 --- a/src/morphology/__tests__/close.test.ts +++ b/src/morphology/__tests__/close.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + test('check for GREY image 5x5', () => { const kernel = [ [1, 1, 1], diff --git a/src/morphology/__tests__/dilate.test.ts b/src/morphology/__tests__/dilate.test.ts index b7295e08f..3d7931487 100644 --- a/src/morphology/__tests__/dilate.test.ts +++ b/src/morphology/__tests__/dilate.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + test('another GREY image 5x5, default kernel', () => { const image = testUtils.createGreyImage([ [255, 0, 0, 0, 255], diff --git a/src/morphology/__tests__/erode.test.ts b/src/morphology/__tests__/erode.test.ts index a258b35ae..98fff45aa 100644 --- a/src/morphology/__tests__/erode.test.ts +++ b/src/morphology/__tests__/erode.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + test('GREY image 5x5', () => { const image = testUtils.createGreyImage([ [255, 0, 255, 255, 255], diff --git a/src/morphology/__tests__/floodFill.test.ts b/src/morphology/__tests__/floodFill.test.ts index 85602b1f5..60ae45032 100644 --- a/src/morphology/__tests__/floodFill.test.ts +++ b/src/morphology/__tests__/floodFill.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import { Mask } from '../../Mask.js'; test('mask 5x5, default options', () => { @@ -106,5 +108,6 @@ test('larger image', () => { const image = testUtils.load('morphology/alphabetCannyEdge.png'); const mask = image.threshold(); const flooded = mask.floodFill(); + expect(flooded).toMatchImageSnapshot(); }); diff --git a/src/morphology/__tests__/morphologicalGradient.test.ts b/src/morphology/__tests__/morphologicalGradient.test.ts index 8149c0d46..c5de1677c 100644 --- a/src/morphology/__tests__/morphologicalGradient.test.ts +++ b/src/morphology/__tests__/morphologicalGradient.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + test('GREY image 5x5', () => { const image = testUtils.createGreyImage([ [0, 255, 255, 255, 0], diff --git a/src/morphology/__tests__/open.test.ts b/src/morphology/__tests__/open.test.ts index 717686a38..03b20a8f9 100644 --- a/src/morphology/__tests__/open.test.ts +++ b/src/morphology/__tests__/open.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + test('GREY image 5x5', () => { const image = testUtils.createGreyImage([ [255, 255, 0, 255, 255], diff --git a/src/morphology/__tests__/solidFill.test.ts b/src/morphology/__tests__/solidFill.test.ts index 095f24abb..bf8e8018b 100644 --- a/src/morphology/__tests__/solidFill.test.ts +++ b/src/morphology/__tests__/solidFill.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import { Mask } from '../../Mask.js'; import { encodePng } from '../../save/index.js'; @@ -91,6 +93,7 @@ test('Out option', () => { const out = new Mask(5, 5); image.solidFill({ out }); + expect(out).toMatchMaskData([ [0, 0, 0, 0, 0], [0, 1, 1, 1, 0], @@ -110,6 +113,7 @@ test('in place modification', () => { ]); image.solidFill({ out: image }); + expect(image).toMatchMaskData([ [0, 0, 0, 0, 0], [0, 1, 1, 1, 0], diff --git a/src/morphology/__tests__/topHat.test.ts b/src/morphology/__tests__/topHat.test.ts index d20722d3f..d673f95b5 100644 --- a/src/morphology/__tests__/topHat.test.ts +++ b/src/morphology/__tests__/topHat.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + test('GREY image 5x5, default kernel', () => { const image = testUtils.createGreyImage([ [0, 0, 255, 0, 0], diff --git a/src/operations/__tests__/convertBitDepth.test.ts b/src/operations/__tests__/convertBitDepth.test.ts index 7af746dd3..465cd9203 100644 --- a/src/operations/__tests__/convertBitDepth.test.ts +++ b/src/operations/__tests__/convertBitDepth.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + test('Uint8 to Uint16', () => { const img = testUtils.createGreyImage([ [1, 2], @@ -5,10 +7,11 @@ test('Uint8 to Uint16', () => { ]); const newImg = img.convertBitDepth(16); + expect(newImg.width).toBe(2); expect(newImg.height).toBe(2); - expect(newImg.bitDepth).toStrictEqual(16); - expect(newImg.colorModel).toStrictEqual('GREY'); + expect(newImg.bitDepth).toBe(16); + expect(newImg.colorModel).toBe('GREY'); expect(newImg).toMatchImageData([ [256, 512], [768, 1024], @@ -25,10 +28,11 @@ test('Uint16 to Uint8', () => { ); const newImg = img.convertBitDepth(8); + expect(newImg.width).toBe(2); expect(newImg.height).toBe(2); - expect(newImg.bitDepth).toStrictEqual(8); - expect(newImg.colorModel).toStrictEqual('GREY'); + expect(newImg.bitDepth).toBe(8); + expect(newImg.colorModel).toBe('GREY'); expect(newImg).toMatchImageData([ [0, 1], [2, 7], @@ -45,10 +49,11 @@ test('Uint16 to Uint8 for rgba', () => { ); const newImg = img.convertBitDepth(8); + expect(newImg.width).toBe(2); expect(newImg.height).toBe(2); - expect(newImg.colorModel).toStrictEqual('RGBA'); - expect(newImg.bitDepth).toStrictEqual(8); + expect(newImg.colorModel).toBe('RGBA'); + expect(newImg.bitDepth).toBe(8); expect(newImg).toMatchImageData([ [1, 1, 1, 1, 2, 2, 2, 2], [3, 3, 3, 3, 4, 4, 4, 4], @@ -65,6 +70,7 @@ test('throw if converting to same bit depth', () => { img.convertBitDepth(8); }).toThrow('cannot convert image to same bitDepth'); }); + test('throw if converting to unsupported bit depth', () => { const img = testUtils.createRgbaImage([ [256, 256, 256, 256, 512, 512, 512, 512], diff --git a/src/operations/__tests__/convertColor.test.ts b/src/operations/__tests__/convertColor.test.ts index 365c89abd..cf46f97b9 100644 --- a/src/operations/__tests__/convertColor.test.ts +++ b/src/operations/__tests__/convertColor.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + test('GREY to GREYA', () => { const image = testUtils.createGreyImage([ [10, 30], @@ -5,6 +7,7 @@ test('GREY to GREYA', () => { ]); const converted = image.convertColor('GREYA'); + expect(converted).toMatchImageData([ [10, 255, 30, 255], [50, 255, 70, 255], @@ -18,6 +21,7 @@ test('GREYA to GREY', () => { ]); const converted = image.convertColor('GREY'); + expect(converted).toMatchImageData([ [10, 30], [50, 70], @@ -31,6 +35,7 @@ test('GREY to RGB', () => { ]); const converted = image.convertColor('RGB'); + expect(converted).toMatchImageData([ [10, 10, 10, 30, 30, 30], [50, 50, 50, 70, 70, 70], @@ -44,6 +49,7 @@ test('GREYA to RGB', () => { ]); const converted = image.convertColor('RGB'); + expect(converted).toMatchImageData([ [10, 10, 10, 30, 30, 30], [50, 50, 50, 70, 70, 70], @@ -57,6 +63,7 @@ test('GREY to RGBA', () => { ]); const converted = image.convertColor('RGBA'); + expect(converted).toMatchImageData([ [10, 10, 10, 255, 30, 30, 30, 255], [50, 50, 50, 255, 70, 70, 70, 255], @@ -70,6 +77,7 @@ test('GREYA to RGBA', () => { ]); const converted = image.convertColor('RGBA'); + expect(converted).toMatchImageData([ [10, 10, 10, 100, 30, 30, 30, 100], [50, 50, 50, 100, 70, 70, 70, 100], @@ -80,6 +88,7 @@ test('RGB to RGBA', () => { const image = testUtils.createRgbImage([[10, 20, 30, 40, 60, 70]]); const converted = image.convertColor('RGBA'); + expect(converted).toMatchImageData([[10, 20, 30, 255, 40, 60, 70, 255]]); }); @@ -87,6 +96,7 @@ test('RGBA to RGB', () => { const image = testUtils.createRgbaImage([[10, 20, 30, 100, 40, 60, 70, 100]]); const converted = image.convertColor('RGB'); + expect(converted).toMatchImageData([[10, 20, 30, 40, 60, 70]]); }); @@ -97,6 +107,7 @@ test('Mask to GREY', () => { ]); const img = mask.convertColor('GREY'); + expect(img).toMatchImageData([ [255, 255], [0, 0], @@ -111,6 +122,7 @@ test('Mask to RGBA', () => { `); const img = mask.convertColor('RGBA'); + expect(img).toMatchImageData([ [0, 0, 0, 255, 0, 0, 0, 255], [255, 255, 255, 255, 0, 0, 0, 255], @@ -126,6 +138,7 @@ test('Mask to RGB', () => { `); const img = mask.convertColor('RGB'); + expect(img).toMatchImageData([ [0, 0, 0, 0, 0, 0], [255, 255, 255, 0, 0, 0], @@ -153,6 +166,7 @@ test('GREY to RGBA 16-bit', () => { const image = testUtils.createGreyImage([[256, 512, 768, 1024]]); const converted = image.convertColor('RGBA'); + expect(converted).toMatchImageData([ [ 256, 256, 256, 65535, 512, 512, 512, 65535, 768, 768, 768, 65535, 1024, @@ -176,5 +190,6 @@ test('image to GREY', () => { [0, 0, 0, 0, 0, 0, 0, 0], [255, 255, 255, 255, 255, 255, 255, 255], ]); + expect(grey).toMatchImage(expected); }); diff --git a/src/operations/__tests__/copyAlpha.test.ts b/src/operations/__tests__/copyAlpha.test.ts index 1076a2bf3..1fd569c70 100644 --- a/src/operations/__tests__/copyAlpha.test.ts +++ b/src/operations/__tests__/copyAlpha.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import { copyAlpha } from '../convertColor.js'; test('source and dest different sizes', () => { diff --git a/src/operations/__tests__/copyTo.test.ts b/src/operations/__tests__/copyTo.test.ts index 032ffdbf6..098211fb2 100644 --- a/src/operations/__tests__/copyTo.test.ts +++ b/src/operations/__tests__/copyTo.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import { Mask } from '../../Mask.js'; import { copyTo } from '../copyTo.js'; @@ -5,6 +7,7 @@ test('default options', () => { const source = testUtils.createGreyImage([[100, 0]]); const target = testUtils.createGreyImage([[50, 255]]); const result = copyTo(source, target); + expect(result).toMatchImageData([[100, 0]]); }); @@ -12,6 +15,7 @@ test('GREYA images: transparent source, opaque target', () => { const source = testUtils.createGreyaImage([[100, 0]]); const target = testUtils.createGreyaImage([[50, 255]]); const result = source.copyTo(target); + expect(result).toMatchImageData([[50, 255]]); }); @@ -19,6 +23,7 @@ test('GREYA images: opaque source, transparent target', () => { const source = testUtils.createGreyaImage([[100, 255]]); const target = testUtils.createGreyaImage([[50, 0]]); const result = source.copyTo(target); + expect(result).toMatchImageData([[100, 255]]); }); @@ -28,6 +33,7 @@ test('GREYA image: alpha different from 255', () => { const result = source.copyTo(target); const alpha = 128 + 64 * (1 - 128 / 255); const component = (100 * 128 + 50 * 64 * (1 - 128 / 255)) / alpha; + expect(result).toMatchImageData([[component, alpha]]); }); @@ -35,6 +41,7 @@ test('Bigger GREYA image', () => { const target = testUtils.createGreyaImage([[100, 0, 200, 0, 150, 0]]); const source = testUtils.createGreyaImage([[20, 255]]); const result = source.copyTo(target); + expect(result).toMatchImageData([[20, 255, 200, 0, 150, 0]]); }); @@ -42,6 +49,7 @@ test('Bigger GREYA image with offset outside target', () => { const target = testUtils.createGreyaImage([[100, 0, 200, 0, 150, 0]]); const source = testUtils.createGreyaImage([[20, 255]]); const result = source.copyTo(target, { origin: { row: -1, column: 0 } }); + expect(result).toMatchImageData([[100, 0, 200, 0, 150, 0]]); }); @@ -50,6 +58,7 @@ test('GREY image', () => { const target = testUtils.createGreyImage([[20, 50]]); const result = source.copyTo(target); + expect(result).toMatchImageData([[100, 150]]); }); @@ -60,6 +69,7 @@ test('GREY image with offset', () => { ]); const source = testUtils.createGreyImage([[20]]); const result = source.copyTo(target, { origin: { row: 1, column: 1 } }); + expect(result).toMatchImageData([ [100, 150], [200, 20], @@ -72,6 +82,7 @@ test('Copy GREY image to itself', () => { [200, 250], ]); const result = target.copyTo(target, { origin: { row: 1, column: 1 } }); + expect(result).toMatchImageData([ [100, 150], [200, 100], @@ -85,6 +96,7 @@ test('source image larger than target (should crop)', () => { ]); const target = testUtils.createGreyImage([[20]]); const result = source.copyTo(target); + expect(result).toMatchImageData([[100]]); }); @@ -96,6 +108,7 @@ test('negative offset', () => { ]); const target = testUtils.createGreyImage([[20]]); const result = source.copyTo(target, { origin: { row: -1, column: -1 } }); + expect(result).toMatchImageData([[250]]); }); @@ -107,6 +120,7 @@ test('RGB images', () => { ]); const source = testUtils.createRgbImage([[3, 3, 3]]); const result = source.copyTo(target, { origin: { row: 1, column: 0 } }); + expect(result).toMatchImageData([ [1, 2, 3], [3, 3, 3], @@ -122,12 +136,14 @@ test('RGBA images', () => { ]); const source = testUtils.createRgbaImage([[3, 3, 3, 255]]); const result = source.copyTo(target, { origin: { row: 1, column: 0 } }); + expect(result).toMatchImageData([ [1, 2, 3, 255], [3, 3, 3, 255], [7, 8, 9, 0], ]); }); + test('origin coordinates are floating values', () => { const target = testUtils.createRgbaImage([ [1, 2, 3, 255], @@ -146,6 +162,7 @@ test('testing out option', () => { const target = testUtils.createGreyaImage([[50, 0]]); const copy = source.copyTo(target); const result = source.copyTo(target, { out: target }); + expect(target).toBe(result); expect(copy).toMatchImage(target); }); @@ -158,6 +175,7 @@ test('mask, no offsets', () => { [1, 1], ]); const result = source.copyTo(target); + expect(result).toMatchImageData([ [1, 1, 0, 0], [1, 1, 0, 0], @@ -173,6 +191,7 @@ test('mask, positive offsets', () => { [1, 1], ]); const result = source.copyTo(target, { origin: { row: 0, column: 1 } }); + expect(result).toMatchImageData([ [0, 1, 1, 0], [0, 1, 1, 0], @@ -204,6 +223,7 @@ test('mask, negative offsets', () => { [1, 1], ]); const result = source.copyTo(target, { origin: { row: -1, column: 0 } }); + expect(result).toMatchImageData([ [1, 1, 0, 0], [0, 0, 0, 0], @@ -223,6 +243,7 @@ test('mask, target with some values', () => { [1, 1], ]); const result = source.copyTo(target, { origin: { row: 0, column: 1 } }); + expect(result).toMatchImageData([ [0, 1, 1, 1], [0, 1, 1, 1], diff --git a/src/operations/__tests__/correctBackground.test.ts b/src/operations/__tests__/correctBackground.test.ts index 972e3b382..def4dabf4 100644 --- a/src/operations/__tests__/correctBackground.test.ts +++ b/src/operations/__tests__/correctBackground.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import type { Point } from '../../geometry/index.js'; import { sampleBackgroundPoints } from '../../utils/sampleBackgroundPoints.js'; import { correctBackground } from '../correctBackground.js'; @@ -29,7 +31,8 @@ test('basic test', () => { [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], ]); - expect(newImage).toEqual(result); + + expect(newImage).toStrictEqual(result); }); test('test with object 8x8 and manually picked points', () => { @@ -68,7 +71,8 @@ test('test with object 8x8 and manually picked points', () => { [0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0], ]); - expect(newImage).toEqual(result); + + expect(newImage).toStrictEqual(result); }); test('test with object 8x8 and sampled points', () => { @@ -104,7 +108,8 @@ test('test with object 8x8 and sampled points', () => { [0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0], ]); - expect(newImage).toEqual(result); + + expect(newImage).toStrictEqual(result); }); test('basic screws image test', () => { @@ -120,6 +125,7 @@ test('basic screws image test', () => { order: 2, backgroundKind: 'light', }); + expect(newImage).toMatchImageSnapshot(); }); @@ -132,8 +138,10 @@ test('basic sudoku image test', () => { gridHeight: 15, }); const newImage = correctBackground(image, { background: points }); + expect(newImage).toMatchImageSnapshot(); }); + test('throw if insufficient number of points', () => { const image = testUtils.createGreyImage([ [1, 2, 3, 4, 5], diff --git a/src/operations/__tests__/crop.test.ts b/src/operations/__tests__/crop.test.ts index 54332cfe8..486c07769 100644 --- a/src/operations/__tests__/crop.test.ts +++ b/src/operations/__tests__/crop.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import { Image } from '../../Image.js'; test('GREY image, default options', () => { @@ -8,6 +10,7 @@ test('GREY image, default options', () => { ]); const result = image.crop(); + expect(result).toMatchImage(image); }); @@ -22,6 +25,7 @@ test('GREY image, various origins and sizes', () => { let result = image.crop({ origin: { row: 2, column: 2 }, }); + expect(result).toMatchImageData([ [2, 2, 0], [4, 3, 0], @@ -33,6 +37,7 @@ test('GREY image, various origins and sizes', () => { height: 2, width: 2, }); + expect(result).toMatchImageData([ [0, 1], [1, 1], @@ -43,6 +48,7 @@ test('GREY image, various origins and sizes', () => { height: 2, width: 2, }); + expect(result).toMatchImageData([ [2, 2], [4, 3], @@ -52,6 +58,7 @@ test('GREY image, various origins and sizes', () => { origin: { row: 1, column: 3 }, height: 1, }); + expect(result).toMatchImageData([[1, 1]]); }); @@ -99,6 +106,7 @@ test('origin is not integer', () => { [1, 2, 4, 3, 0], [1, 2, 3, 3, 0], ]); + expect(() => { image.crop({ origin: { row: 1.5, column: 1.5 }, @@ -114,6 +122,7 @@ test('width is not integer', () => { [1, 2, 4, 3, 0], [1, 2, 3, 3, 0], ]); + expect(() => { image.crop({ width: 3.5 }); }).toThrow('Width and height (width:3.5; height:5) must be integers'); diff --git a/src/operations/__tests__/cropAlpha.test.ts b/src/operations/__tests__/cropAlpha.test.ts index 30d36b379..c437cbc42 100644 --- a/src/operations/__tests__/cropAlpha.test.ts +++ b/src/operations/__tests__/cropAlpha.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import { cropAlpha } from '../cropAlpha.js'; test('GREYA, no crop', () => { @@ -9,6 +11,7 @@ test('GREYA, no crop', () => { ]); const cropped = cropAlpha(image); + expect(cropped).toMatchImage(image); }); @@ -21,6 +24,7 @@ test('GREYA, some crop', () => { ]); const cropped = image.cropAlpha(); + expect(cropped).toMatchImageData([ [2, 255, 3, 255], [5, 255, 6, 255], @@ -37,6 +41,7 @@ test('GREYA, single pixel remains', () => { ]); const cropped = image.cropAlpha(); + expect(cropped).toMatchImageData([[5, 255]]); }); @@ -49,6 +54,7 @@ test('GREYA, other threshold', () => { ]); const cropped = image.cropAlpha({ threshold: 240 }); + expect(cropped).toMatchImageData([ [2, 240, 3, 0], [5, 255, 6, 250], diff --git a/src/operations/__tests__/cropRectangle.test.ts b/src/operations/__tests__/cropRectangle.test.ts index 7f43b5b8e..9f278b3ff 100644 --- a/src/operations/__tests__/cropRectangle.test.ts +++ b/src/operations/__tests__/cropRectangle.test.ts @@ -1,7 +1,8 @@ +import { assert, expect, test } from 'vitest'; + import type { Image } from '../../Image.js'; import { rotatePoint } from '../../point/operations.js'; import type { Point } from '../../utils/geometry/points.js'; -import { assert } from '../../utils/validators/assert.js'; test('straight rectangle top left', () => { const image = testUtils.createGreyImage([ @@ -12,6 +13,7 @@ test('straight rectangle top left', () => { const points = testUtils.createPoints([0, 0], [2, 0], [2, 2], [0, 2]); const result = image.cropRectangle(points, { interpolationType: 'nearest' }); + expect(result).toMatchImage( testUtils.createGreyImage([ [1, 2], @@ -29,6 +31,7 @@ test('straight rectangle bottom right', () => { const points = testUtils.createPoints([1, 3], [3, 3], [3, 1], [1, 1]); const result = image.cropRectangle(points); + expect(result).toMatchImage( testUtils.createGreyImage([ [5, 6], @@ -37,6 +40,7 @@ test('straight rectangle bottom right', () => { ); }); +// eslint-disable-next-line vitest/expect-expect test('vertical rectangle with small angle', () => { const image = testUtils.createGreyImage([ [1, 2, 3], @@ -55,6 +59,7 @@ test('vertical rectangle with small angle', () => { }); }); +// eslint-disable-next-line vitest/expect-expect test('horizontal rectangle with small angle', () => { const image = testUtils.createGreyImage([ [1, 2, 3], @@ -73,6 +78,7 @@ test('horizontal rectangle with small angle', () => { }); }); +// eslint-disable-next-line vitest/expect-expect test('diagonal rectangle oriented slightly > 45 degrees clockwise', () => { const image = testUtils.createGreyImage([ [1, 2, 3], @@ -92,6 +98,7 @@ test('diagonal rectangle oriented slightly > 45 degrees clockwise', () => { }); }); +// eslint-disable-next-line vitest/expect-expect test('diagonal rectangle oriented slightly below 45 degrees', () => { const image = testUtils.createGreyImage([ [1, 2, 3], @@ -120,7 +127,7 @@ function expectCropRectangleToMatch(options: { const { image, expected, points } = options; assert(options.points.length === 4, 'Expected to receive 4 points'); const variants: Point[][] = []; - const pointsReversed = points.slice().reverse(); + const pointsReversed = points.slice().toReversed(); for (let i = 0; i < 4; i++) { const variant: Point[] = []; variants.push(variant); @@ -140,6 +147,7 @@ function expectCropRectangleToMatch(options: { const result = image.cropRectangle(points, { interpolationType: 'nearest', }); + expect(result).toMatchImage(expected); } } diff --git a/src/operations/__tests__/extendBorders.test.ts b/src/operations/__tests__/extendBorders.test.ts index 7c6963d1e..b833e8922 100644 --- a/src/operations/__tests__/extendBorders.test.ts +++ b/src/operations/__tests__/extendBorders.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import { extendBorders } from '../extendBorders.js'; test('grey image with basic value', () => { @@ -13,6 +15,7 @@ test('grey image with basic value', () => { vertical: 1, borderType: 'constant', }); + expect(newImage).toMatchImageData(` 0 0 0 0 0 1 2 0 @@ -36,6 +39,7 @@ test('grey image with wrap', () => { vertical: 3, borderType: 'wrap', }); + expect(newImage).toMatchImageData(` 5 6 3 4 5 6 3 4 6 7 4 5 6 7 4 5 diff --git a/src/operations/__tests__/extract.test.ts b/src/operations/__tests__/extract.test.ts index 274a5d9ee..554c5ed1c 100644 --- a/src/operations/__tests__/extract.test.ts +++ b/src/operations/__tests__/extract.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + test('1x1 image and mask', () => { const image = testUtils.createGreyImage([[100]]); const mask = testUtils.createMask([[1]]); diff --git a/src/operations/__tests__/getMaskFromCannyEdge.test.ts b/src/operations/__tests__/getMaskFromCannyEdge.test.ts index 9a54204ed..c52557e78 100644 --- a/src/operations/__tests__/getMaskFromCannyEdge.test.ts +++ b/src/operations/__tests__/getMaskFromCannyEdge.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import { getMaskFromCannyEdge } from '../getMaskFromCannyEdge.js'; test('basic test', () => { @@ -16,7 +18,8 @@ test('basic test', () => { [0, 0, 0, 0, 0], ]); const fromCannyMask = getMaskFromCannyEdge(image, { iterations: 0 }); - expect(fromCannyMask).toEqual(mask); + + expect(fromCannyMask).toStrictEqual(mask); }); test('testing 10x10 with dilation', () => { @@ -45,7 +48,8 @@ test('testing 10x10 with dilation', () => { [0, 0, 0, 0, 1, 1, 1, 1, 1, 1], ]); const fromCannyMask = getMaskFromCannyEdge(image); - expect(fromCannyMask).toEqual(mask); + + expect(fromCannyMask).toStrictEqual(mask); }); test('testing 7x7 without dilation', () => { @@ -68,7 +72,8 @@ test('testing 7x7 without dilation', () => { [0, 0, 0, 0, 0, 0, 0], ]); const fromCannyMask = getMaskFromCannyEdge(image, { iterations: 0 }); - expect(fromCannyMask).toEqual(mask); + + expect(fromCannyMask).toStrictEqual(mask); }); test('testing 7x7 with dilation', () => { @@ -91,5 +96,6 @@ test('testing 7x7 with dilation', () => { [1, 1, 1, 1, 1, 1, 1], ]); const fromCannyMask = getMaskFromCannyEdge(image); - expect(fromCannyMask).toEqual(mask); + + expect(fromCannyMask).toStrictEqual(mask); }); diff --git a/src/operations/__tests__/grey.test.ts b/src/operations/__tests__/grey.test.ts index 01e26d4f5..0c4051d33 100644 --- a/src/operations/__tests__/grey.test.ts +++ b/src/operations/__tests__/grey.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + test('RGBA image', () => { const image = testUtils.createRgbaImage([ [100, 150, 200, 255, 100, 150, 200, 0], @@ -73,10 +75,13 @@ test('RGB image', () => { test('wrong image color model', () => { let image = testUtils.createGreyaImage([[100, 255, 150, 0]]); + expect(() => image.grey()).toThrow( /image colorModel must be RGB or RGBA to apply this algorithm/, ); + image = testUtils.createGreyImage([[100, 255, 150, 0]]); + expect(() => image.grey()).toThrow( /image colorModel must be RGB or RGBA to apply this algorithm/, ); @@ -89,10 +94,12 @@ test('user-provided output', () => { const out = testUtils.createGreyImage([[0, 0]]); const result = image.grey({ out }); + expect(result).toBe(out); expect(out).toMatchImageData([[142, 0]]); const wrongOut = testUtils.createGreyaImage([[0, 0, 0, 0]]); + expect(() => image.grey({ out: wrongOut })).toThrow( /cannot use out image. Its colorModel property must be GREY. Received GREYA/, ); @@ -105,10 +112,12 @@ test('wrong algorithm type', () => { const out = testUtils.createGreyImage([[0, 0]]); const result = image.grey({ out }); + expect(result).toBe(out); expect(out).toMatchImageData([[142, 0]]); const wrongOut = testUtils.createGreyaImage([[0, 0, 0, 0]]); + expect(() => image.grey({ out: wrongOut })).toThrow( /cannot use out image. Its colorModel property must be GREY. Received GREYA/, ); diff --git a/src/operations/__tests__/greyAlgorithms.test.ts b/src/operations/__tests__/greyAlgorithms.test.ts index 3576ff2e6..f89de9beb 100644 --- a/src/operations/__tests__/greyAlgorithms.test.ts +++ b/src/operations/__tests__/greyAlgorithms.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import { Image } from '../../Image.js'; import { hue } from '../greyAlgorithms.js'; diff --git a/src/operations/__tests__/merge.test.ts b/src/operations/__tests__/merge.test.ts index f02abbacf..286ec0a60 100644 --- a/src/operations/__tests__/merge.test.ts +++ b/src/operations/__tests__/merge.test.ts @@ -1,26 +1,32 @@ +import { expect, test } from 'vitest'; + import { merge } from '../merge.js'; test('merge into RGB', () => { const img = testUtils.createRgbImage([[0, 1, 2, 253, 254, 255]]); const split = img.split(); + expect(merge(split)).toMatchImage(img); }); test('merge into RGBA', () => { const img = testUtils.createRgbaImage([[0, 1, 2, 42, 253, 254, 255, 42]]); const split = img.split(); + expect(merge(split)).toMatchImage(img); }); test('merge into GREYA', () => { const img = testUtils.createGreyaImage([[0, 1, 254, 255]]); const split = img.split(); + expect(merge(split)).toMatchImage(img); }); test('throw on image with more than 1 channel', () => { const img1 = testUtils.createGreyaImage([[0, 1, 254, 255]]); const img2 = testUtils.createGreyImage([[0, 1, 254, 255]]); + expect(() => { merge([img1, img2]); }).toThrow('each image must have one channel. Received 2'); @@ -32,6 +38,7 @@ test('throw on image with more than 1 channel', () => { test('throw on image with sizes different', () => { const img1 = testUtils.createGreyImage([[0, 1]]); const img2 = testUtils.createGreyImage([[0, 1, 254, 255]]); + expect(() => { merge([img1, img2]); }).toThrow('all images must have the same width, height and bitDepth'); @@ -40,6 +47,7 @@ test('throw on image with sizes different', () => { test('throw on too many images', () => { const img1 = testUtils.createGreyImage([[0, 1]]); const img2 = testUtils.createGreyImage([[0, 1, 254, 255]]); + expect(() => { merge([img1, img2, img1, img2, img1]); }).toThrow('merge expects an array of two to four images. Received 5'); diff --git a/src/operations/__tests__/paintMaskOnImage.test.ts b/src/operations/__tests__/paintMaskOnImage.test.ts index b5cf9bdf6..95efa1376 100644 --- a/src/operations/__tests__/paintMaskOnImage.test.ts +++ b/src/operations/__tests__/paintMaskOnImage.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + test('3x3 grey image, default options', () => { const image = testUtils.createGreyImage([ [30, 23, 2], @@ -123,6 +125,7 @@ test('blend = false, all values null', () => { blend: false, color: [null, null, null, null], }); + expect(result).toStrictEqual(image); }); @@ -137,6 +140,7 @@ test('blend = false, change red and alpha', () => { blend: false, color: [255, null, null, 255], }); + expect(result).toMatchImageData([ [255, 23, 2, 255], [45, 65, 1, 5], @@ -158,6 +162,7 @@ test('blend = false, change many pixels', () => { blend: false, color: [0, 100], }); + expect(result).toMatchImageData([ [0, 100, 0, 100], [45, 65, 0, 100], @@ -176,6 +181,7 @@ test('out option', () => { color: [255], out: image, }); + expect(image).toMatchImageData([ [255, 23, 2, 2], [45, 65, 1, 5], diff --git a/src/operations/__tests__/paintMaskOnMask.test.ts b/src/operations/__tests__/paintMaskOnMask.test.ts index 9b5fc09b5..2cfbc705d 100644 --- a/src/operations/__tests__/paintMaskOnMask.test.ts +++ b/src/operations/__tests__/paintMaskOnMask.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + test('3x3 mask, default options', () => { const destMask = testUtils.createMask([ [1, 0, 0], @@ -85,6 +87,7 @@ test('out option', () => { destMask.paintMask(mask, { out: destMask, }); + expect(destMask).toMatchMaskData([ [1, 0, 0, 0], [0, 0, 0, 0], diff --git a/src/operations/__tests__/split.test.ts b/src/operations/__tests__/split.test.ts index 5cb223381..78f9ce387 100644 --- a/src/operations/__tests__/split.test.ts +++ b/src/operations/__tests__/split.test.ts @@ -1,7 +1,11 @@ +import { expect, test } from 'vitest'; + test('split RGB', () => { const img = testUtils.createRgbImage([[0, 1, 2, 253, 254, 255]]); const split = img.split(); + expect(split).toHaveLength(3); + for (const g of split) { expect(g).toMatchObject({ width: 2, @@ -9,6 +13,7 @@ test('split RGB', () => { colorModel: 'GREY', }); } + expect(split[0]).toMatchImageData([[0, 253]]); expect(split[1]).toMatchImageData([[1, 254]]); expect(split[2]).toMatchImageData([[2, 255]]); @@ -17,6 +22,7 @@ test('split RGB', () => { test('split GREYA', () => { const img = testUtils.createGreyaImage([[0, 1, 254, 255]]); const split = img.split(); + expect(split).toHaveLength(2); expect(split[0]).toMatchImageData([[0, 254]]); expect(split[1]).toMatchImageData([[1, 255]]); diff --git a/src/operations/__tests__/threshold.test.ts b/src/operations/__tests__/threshold.test.ts index 4be673c2e..3fa239189 100644 --- a/src/operations/__tests__/threshold.test.ts +++ b/src/operations/__tests__/threshold.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import { Image } from '../../Image.js'; import { ImageColorModel } from '../../utils/constants/colorModels.js'; import { computeThreshold, threshold } from '../threshold.js'; @@ -28,18 +30,21 @@ test('computeThreshold with OTSU', () => { const grey = testImage.convertColor('GREY'); const thresholdValue = computeThreshold(grey, { algorithm: 'otsu' }); + expect(thresholdValue).toBe(127); }); test('computeThreshold with OTSU (2)', () => { const img = testUtils.load('various/grayscale_by_zimmyrose.png'); const thresholdValue = computeThreshold(img, { algorithm: 'otsu' }); + expect(thresholdValue).toBe(135); }); test('computeThreshold default should be Otsu', () => { const img = testUtils.load('various/grayscale_by_zimmyrose.png'); const thresholdValue = computeThreshold(img); + expect(thresholdValue).toBe(135); }); @@ -62,9 +67,11 @@ test('automatic threshold with OTSU', () => { [0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 1, 1, 1, 1, 1, 1], ]); + expect(th).toMatchMask(expected); expect(defaultThreshold).toMatchMask(expected); }); + test('threshold in percents', () => { const grey = testUtils.createGreyImage([ [1, 2, 3], @@ -79,6 +86,7 @@ test('threshold in percents', () => { [0, 0, 1], [1, 1, 1], ]); + expect(th).toMatchMask(expected); }); @@ -89,6 +97,7 @@ test('error too many channels', () => { /threshold can only be computed on images with one channel/, ); }); + test('error threshold out of range', () => { const testImage = testUtils.load('opencv/test.png'); @@ -127,7 +136,7 @@ test('16 bits image simple with default number of slots 2**16', () => { const threshold = image.threshold({ slots: 2 ** image.bitDepth }); const defaultSlotsThreshold = image.threshold(); - expect(threshold).toEqual(defaultSlotsThreshold); + expect(threshold).toStrictEqual(defaultSlotsThreshold); }); test('16 bits image simple with custom number of slots 2**8', () => { @@ -139,5 +148,5 @@ test('16 bits image simple with custom number of slots 2**8', () => { const threshold = image.threshold({ slots: 2 ** 8 }); const defaultSlotsThreshold = image.threshold(); - expect(threshold).toEqual(defaultSlotsThreshold); + expect(threshold).toStrictEqual(defaultSlotsThreshold); }); diff --git a/src/operations/thresholds/__tests__/thresholdAlgorithms.test.ts b/src/operations/thresholds/__tests__/thresholdAlgorithms.test.ts index 9d1b9a37b..fe2430967 100644 --- a/src/operations/thresholds/__tests__/thresholdAlgorithms.test.ts +++ b/src/operations/thresholds/__tests__/thresholdAlgorithms.test.ts @@ -1,76 +1,93 @@ +import { expect, test } from 'vitest'; + import { computeThreshold } from '../../threshold.js'; test('Huang should work similarily to ImageJ', () => { const img = testUtils.load('various/grayscale_by_zimmyrose.png'); + expect(computeThreshold(img, { algorithm: 'huang' })).toBe(132); }); test('Intermodes should work like ImageJ', () => { const img = testUtils.load('various/grayscale_by_zimmyrose.png'); + expect(computeThreshold(img, { algorithm: 'intermodes' })).toBe(166); }); test('Isodata should work like ImageJ', () => { const img = testUtils.load('various/grayscale_by_zimmyrose.png'); + expect(computeThreshold(img, { algorithm: 'isodata' })).toBe(135); }); test('Percentile should work like ImageJ', () => { const img = testUtils.load('various/grayscale_by_zimmyrose.png'); + expect(computeThreshold(img, { algorithm: 'percentile' })).toBe(90); }); test('Li should work similarily to ImageJ', () => { const img = testUtils.load('various/grayscale_by_zimmyrose.png'); + expect(computeThreshold(img, { algorithm: 'li' })).toBe(117); }); test('MaxEntropy should work like ImageJ', () => { const img = testUtils.load('various/grayscale_by_zimmyrose.png'); + expect(computeThreshold(img, { algorithm: 'maxEntropy' })).toBe(126); }); test('Mean should work like ImageJ', () => { const img = testUtils.load('various/grayscale_by_zimmyrose.png'); + expect(computeThreshold(img, { algorithm: 'mean' })).toBe(106); }); test('MinError should work like ImageJ', () => { const img = testUtils.load('various/grayscale_by_zimmyrose.png'); + expect(computeThreshold(img, { algorithm: 'minError' })).toBe(101); }); test('Minimum should work like ImageJ', () => { const img = testUtils.load('various/grayscale_by_zimmyrose.png'); + expect(computeThreshold(img, { algorithm: 'minimum' })).toBe(234); }); test('Moments should work like ImageJ', () => { const img = testUtils.load('various/grayscale_by_zimmyrose.png'); + expect(computeThreshold(img, { algorithm: 'moments' })).toBe(127); }); test('Otsu should work like ImageJ', () => { const img = testUtils.load('various/grayscale_by_zimmyrose.png'); + expect(computeThreshold(img, { algorithm: 'otsu' })).toBe(135); }); test('RenyiEntropy should work similarily to ImageJ', () => { const img = testUtils.load('various/grayscale_by_zimmyrose.png'); + expect(computeThreshold(img, { algorithm: 'renyiEntropy' })).toBe(116); }); test('Shanbhag should work like ImageJ', () => { const img = testUtils.load('various/grayscale_by_zimmyrose.png'); + expect(computeThreshold(img, { algorithm: 'shanbhag' })).toBe(116); }); test('Triangle should work like ImageJ', () => { const img = testUtils.load('various/grayscale_by_zimmyrose.png'); + expect(computeThreshold(img, { algorithm: 'triangle' })).toBe(87); }); test('Yen should work like ImageJ', () => { const img = testUtils.load('various/grayscale_by_zimmyrose.png'); + expect(computeThreshold(img, { algorithm: 'yen' })).toBe(108); }); diff --git a/src/roi/__tests__/Roi.test.ts b/src/roi/__tests__/Roi.test.ts index 6cbd31d68..d212b6850 100644 --- a/src/roi/__tests__/Roi.test.ts +++ b/src/roi/__tests__/Roi.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import { fromMask } from '../fromMask.js'; test('getRatio', () => { @@ -9,6 +11,7 @@ test('getRatio', () => { const roiMapManager = fromMask(mask); const rois = roiMapManager.getRois(); + expect(rois[0].getRatio()).toBe(3 / 2); }); @@ -25,5 +28,6 @@ test('getMap', () => { const result = rois[0].map.data; const expected = new Int32Array([-1, 1, -3, 1, 1, 1, -2, -2, -2]); + expect(result).toStrictEqual(expected); }); diff --git a/src/roi/__tests__/RoiMapManager.test.ts b/src/roi/__tests__/RoiMapManager.test.ts index b2f19ea32..2fc1016de 100644 --- a/src/roi/__tests__/RoiMapManager.test.ts +++ b/src/roi/__tests__/RoiMapManager.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import { RoiMapManager } from '../RoiMapManager.js'; import { fromMask } from '../fromMask.js'; @@ -17,6 +19,7 @@ test('should work with crop', () => { [0, 0, 1, 1, 1], [0, 0, 0, 0, 0], ]); + const roiMapManager = fromMask(mask); const rois = roiMapManager.getRois(); diff --git a/src/roi/__tests__/borderLengths.test.ts b/src/roi/__tests__/borderLengths.test.ts index 08294215b..55da233cd 100644 --- a/src/roi/__tests__/borderLengths.test.ts +++ b/src/roi/__tests__/borderLengths.test.ts @@ -1,4 +1,4 @@ -import { test } from 'vitest'; +import { expect, test } from 'vitest'; import { fromMask } from '../fromMask.js'; import { RoiKind } from '../getRois.js'; @@ -20,7 +20,7 @@ test('border lengths property 5x5', () => { ]); }); -test.fails.skip('border lengths property 4x4', () => { +test('border lengths property 4x4', () => { const mask = testUtils.createMask([ [0, 1, 1, 1], [0, 1, 0, 1], @@ -35,7 +35,7 @@ test.fails.skip('border lengths property 4x4', () => { expect(rois[0].borders[0]).toStrictEqual({ connectedID: -1, length: 6 }); }); -test('border lengths property 4x4', () => { +test('border lengths property 4x4 2', () => { const mask = testUtils.createMask([ [1, 0, 1, 1], [1, 0, 0, 1], @@ -53,5 +53,5 @@ test('border lengths property 4x4', () => { { connectedID: -2, length: 2 }, { connectedID: -1, length: 2 }, ]); - expect(rois[0].borders[0].length).toStrictEqual(2); + expect(rois[0].borders[0]).toHaveLength(2); }); diff --git a/src/roi/__tests__/centroid.test.ts b/src/roi/__tests__/centroid.test.ts index 63976208a..b52edbe0b 100644 --- a/src/roi/__tests__/centroid.test.ts +++ b/src/roi/__tests__/centroid.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import { fromMask } from '../fromMask.js'; test('centroid property 4x4', () => { @@ -9,6 +11,7 @@ test('centroid property 4x4', () => { ]); const roiMapManager = fromMask(mask); const rois = roiMapManager.getRois(); + expect(rois[0].centroid).toStrictEqual({ row: 1, column: 2 }); }); @@ -22,11 +25,12 @@ test('border lengths property 5x5', () => { ]); const roiMapManager = fromMask(mask); const rois = roiMapManager.getRois(); + expect(rois[0].centroid.row).toBeCloseTo(2.14286); expect(rois[0].centroid.column).toBeCloseTo(1.28571); }); -test('border lengths property 5x5', () => { +test('border lengths property 5x5 2', () => { const mask = testUtils.createMask([ [1, 1, 1], [0, 1, 0], @@ -34,6 +38,7 @@ test('border lengths property 5x5', () => { ]); const roiMapManager = fromMask(mask); const rois = roiMapManager.getRois(); + expect(rois[0].centroid.row).toBeCloseTo(1); expect(rois[0].centroid.column).toBeCloseTo(1); }); diff --git a/src/roi/__tests__/colorRois.test.ts b/src/roi/__tests__/colorRois.test.ts index 57e864589..0bb3c9893 100644 --- a/src/roi/__tests__/colorRois.test.ts +++ b/src/roi/__tests__/colorRois.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import { colorRois } from '../colorRois.js'; import { fromMask } from '../fromMask.js'; @@ -5,5 +7,6 @@ test('1x2 mask', () => { const mask = testUtils.createMask([[0, 1]]); const roiMapManager = fromMask(mask); const result = colorRois(roiMapManager); + expect(result).toMatchImageData([[255, 0, 0, 255, 0, 255, 0, 255]]); }); diff --git a/src/roi/__tests__/computeRois.test.ts b/src/roi/__tests__/computeRois.test.ts index 66f3f3f7d..31913d506 100644 --- a/src/roi/__tests__/computeRois.test.ts +++ b/src/roi/__tests__/computeRois.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import { RoiMapManager } from '../RoiMapManager.js'; import { computeRois } from '../computeRois.js'; import { fromMask } from '../fromMask.js'; @@ -11,6 +13,7 @@ test('3x3 mask', () => { ]); const roiMapManager = fromMask(mask); computeRois(roiMapManager); + expect(roiMapManager.whiteRois).toHaveLength(2); expect(roiMapManager.blackRois).toHaveLength(1); @@ -52,7 +55,9 @@ test('test 2, waterShed for a grey image', () => { width: 10, height: 10, }); + expect(roiMapManager).toStrictEqual(result); + computeRois(roiMapManager); expect(roiMapManager.blackRois[0].origin).toStrictEqual({ diff --git a/src/roi/__tests__/ellipse.test.ts b/src/roi/__tests__/ellipse.test.ts index 0080e00d4..ef9857077 100644 --- a/src/roi/__tests__/ellipse.test.ts +++ b/src/roi/__tests__/ellipse.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import { fromMask } from '../fromMask.js'; test('ellipse on a small figure 3x3', () => { @@ -31,7 +33,8 @@ test('ellipse on a small figure 3x3', () => { surface: Number.NaN, }); }); -test('ellipse on a small figure 3x3', () => { + +test('ellipse on a small figure 3x3 2', () => { const mask = testUtils.createMask([ [1, 1, 0], [0, 1, 0], @@ -74,6 +77,7 @@ test('ellipse on 3x3 cross', () => { const rois = roiMapManager.getRois(); const result = rois[0].ellipse; + expect(result).toBeDeepCloseTo({ center: { column: 1, row: 1 }, majorAxis: { @@ -95,6 +99,7 @@ test('ellipse on 3x3 cross', () => { surface: 5, }); }); + test('ellipse on slightly changed 3x3 cross', () => { const mask = testUtils.createMask([ [1, 1, 0], @@ -105,6 +110,7 @@ test('ellipse on slightly changed 3x3 cross', () => { const rois = roiMapManager.getRois(); const result = rois[0].ellipse; + expect(result).toBeDeepCloseTo({ center: { column: 0.8333333333333334, row: 0.8333333333333334 }, majorAxis: { @@ -126,6 +132,7 @@ test('ellipse on slightly changed 3x3 cross', () => { surface: 6.000000000000002, }); }); + test('ellipse on 4x4 ROI', () => { const mask = testUtils.createMask([ [0, 0, 1, 1], @@ -137,6 +144,7 @@ test('ellipse on 4x4 ROI', () => { const rois = roiMapManager.getRois(); const result = rois[0].ellipse; + expect(result).toBeDeepCloseTo({ center: { column: 1.7777777777777777, row: 1.7777777777777777 }, majorAxis: { diff --git a/src/roi/__tests__/eqpc.test.ts b/src/roi/__tests__/eqpc.test.ts index 33a94949e..4901c7daf 100644 --- a/src/roi/__tests__/eqpc.test.ts +++ b/src/roi/__tests__/eqpc.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import { fromMask } from '../fromMask.js'; test('calculates eqpc to Roi', () => { @@ -9,6 +11,7 @@ test('calculates eqpc to Roi', () => { const roiMapManager = fromMask(mask); const rois = roiMapManager.getRois(); + expect(rois[0].eqpc).toBeCloseTo(2.52, 2); }); @@ -23,5 +26,6 @@ test('calculates surface from eqpc', () => { const rois = roiMapManager.getRois(); const eqpc = rois[0].eqpc; const surface = Math.PI * (eqpc / 2) ** 2; + expect(surface).toBeCloseTo(6); }); diff --git a/src/roi/__tests__/fillRatio.test.ts b/src/roi/__tests__/fillRatio.test.ts index 1d47f14ae..0d5fb29aa 100644 --- a/src/roi/__tests__/fillRatio.test.ts +++ b/src/roi/__tests__/fillRatio.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import { fromMask } from '../fromMask.js'; test('fillRatio 4x4', () => { @@ -9,6 +11,7 @@ test('fillRatio 4x4', () => { ]); const rois = fromMask(mask).getRois(); + expect(rois[0].fillRatio).toBeCloseTo(12 / 16, 2); }); @@ -21,10 +24,11 @@ test('fillRatio 4x4 with open borders', () => { ]); const rois = fromMask(mask).getRois(); + expect(rois[0].fillRatio).toBeCloseTo(8 / 9, 2); }); -test('fillRatio 4x4 with open borders', () => { +test('fillRatio 4x4 with open borders 2', () => { const mask = testUtils.createMask([ [1, 1, 1, 1], [1, 0, 0, 1], @@ -33,5 +37,6 @@ test('fillRatio 4x4 with open borders', () => { ]); const rois = fromMask(mask).getRois(); + expect(rois[0].fillRatio).toBeCloseTo(10 / 12, 2); }); diff --git a/src/roi/__tests__/fromMask.test.ts b/src/roi/__tests__/fromMask.test.ts index 5d3420af9..1099d5954 100644 --- a/src/roi/__tests__/fromMask.test.ts +++ b/src/roi/__tests__/fromMask.test.ts @@ -14,6 +14,7 @@ test('3x3 mask, black', () => { [-1, -1, -1], [-1, -1, -1], ]; + expect(fromMask(mask).getMapMatrix()).toStrictEqual(expected); }); @@ -28,6 +29,7 @@ test('3x3 mask, white', () => { [1, 1, 1], [1, 1, 1], ]; + expect(fromMask(mask).getMapMatrix()).toStrictEqual(expected); }); @@ -42,6 +44,7 @@ test('3x3 mask, cross', () => { [1, 1, 1], [-2, 1, -4], ]; + expect(fromMask(mask).getMapMatrix()).toStrictEqual(expected); }); @@ -138,6 +141,7 @@ test('6x6 mask, allowCorners false', () => { ]; const roiMapManager = fromMask(mask); + expect(roiMapManager.getMapMatrix()).toStrictEqual(expected); expect(roiMapManager.getMap().nbNegative).toBe(4); expect(roiMapManager.getMap().nbPositive).toBe(7); @@ -178,6 +182,7 @@ test('no way to exceed max number of ROIs error', { timeout: 20_000 }, () => { } const roiMap = fromMask(mask); + //@ts-expect-error This is a test expect(roiMap.map.nbNegative).toBe(8392704); //@ts-expect-error This is a test diff --git a/src/roi/__tests__/getBorderPoints.test.ts b/src/roi/__tests__/getBorderPoints.test.ts index 445f79041..d7f0674d7 100644 --- a/src/roi/__tests__/getBorderPoints.test.ts +++ b/src/roi/__tests__/getBorderPoints.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import { Mask } from '../../Mask.js'; test('6x5 mask with hole, no inner borders', () => { diff --git a/src/roi/__tests__/getMask.test.ts b/src/roi/__tests__/getMask.test.ts index 9c2b038ca..76540c440 100644 --- a/src/roi/__tests__/getMask.test.ts +++ b/src/roi/__tests__/getMask.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import { fromMask } from '../fromMask.js'; import { getMask } from '../getMask.js'; @@ -11,6 +13,7 @@ test('cross', () => { const rois = roiMapManager.getRois({ kind: 'white' }); const roiMask = rois[0].getMask(); + expect(roiMask).toMatchMask(mask); }); diff --git a/src/roi/__tests__/getRoiById.test.ts b/src/roi/__tests__/getRoiById.test.ts index 4422bfc49..e9ec9d472 100644 --- a/src/roi/__tests__/getRoiById.test.ts +++ b/src/roi/__tests__/getRoiById.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import { fromMask } from '../fromMask.js'; test('should throw error', () => { @@ -28,7 +30,7 @@ test('should give ROI of id = 1 ', () => { const roiMapManager = fromMask(mask); const roi = roiMapManager.getRoiById(1); - expect(roi.id).toStrictEqual(1); + expect(roi.id).toBe(1); }); test('should give ROI of id = 3 ', () => { @@ -42,5 +44,5 @@ test('should give ROI of id = 3 ', () => { const roiMapManager = fromMask(mask); const roi = roiMapManager.getRoiById(3); - expect(roi.id).toStrictEqual(3); + expect(roi.id).toBe(3); }); diff --git a/src/roi/__tests__/getRois.test.ts b/src/roi/__tests__/getRois.test.ts index 4e09d9cf5..1c4f36b62 100644 --- a/src/roi/__tests__/getRois.test.ts +++ b/src/roi/__tests__/getRois.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import { fromMask } from '../fromMask.js'; import { getRois } from '../getRois.js'; @@ -9,6 +11,7 @@ test('3x3 mask, kind BLACK', () => { ]); const roiMapManager = fromMask(mask); const rois = getRois(roiMapManager, { kind: 'black' }); + expect(rois).toHaveLength(1); expect(rois[0].surface).toBe(4); expect(rois[0].id).toBe(-1); @@ -22,6 +25,7 @@ test('3x3 mask, kind BW', () => { ]); const roiMapManager = fromMask(mask); const rois = getRois(roiMapManager, { kind: 'bw' }); + expect(rois).toHaveLength(3); expect(rois[0].surface).toBe(4); expect(rois[0].id).toBe(1); @@ -36,6 +40,7 @@ test('3x3 mask, minSurface = 2', () => { const roiMapManager = fromMask(mask); const rois = getRois(roiMapManager, { minSurface: 2 }); + expect(rois).toHaveLength(1); expect(rois[0].surface).toBe(4); expect(rois[0].id).toBe(1); diff --git a/src/roi/__tests__/holesInfo.test.ts b/src/roi/__tests__/holesInfo.test.ts index 57f8a489f..0e538b9b0 100644 --- a/src/roi/__tests__/holesInfo.test.ts +++ b/src/roi/__tests__/holesInfo.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import { fromMask } from '../fromMask.js'; test('holes surface and number of holes 4x4', () => { @@ -9,6 +11,7 @@ test('holes surface and number of holes 4x4', () => { ]); const rois = fromMask(mask).getRois(); + expect(rois[0].holesInfo.surface).toBe(2); expect(rois[0].holesInfo.number).toBe(1); }); @@ -22,6 +25,7 @@ test('holes surface and number of holes 4x5', () => { ]); const rois = fromMask(mask).getRois(); + expect(rois[0].holesInfo.number).toBe(2); expect(rois[0].holesInfo.surface).toBe(4); }); diff --git a/src/roi/__tests__/ped.test.ts b/src/roi/__tests__/ped.test.ts index 65c526f3d..d77e36029 100644 --- a/src/roi/__tests__/ped.test.ts +++ b/src/roi/__tests__/ped.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import { fromMask } from '../fromMask.js'; test('calculates ped from roi', () => { @@ -9,5 +11,6 @@ test('calculates ped from roi', () => { const roiMapManager = fromMask(mask); const rois = roiMapManager.getRois(); + expect(rois[0].ped).toBeCloseTo(3.07); }); diff --git a/src/roi/__tests__/perimeter.test.ts b/src/roi/__tests__/perimeter.test.ts index 9b192c7b5..2333e23f6 100644 --- a/src/roi/__tests__/perimeter.test.ts +++ b/src/roi/__tests__/perimeter.test.ts @@ -1,7 +1,9 @@ +import { describe, expect, it } from 'vitest'; + import { fromMask } from '../fromMask.js'; describe('ROI perimeter', () => { - test('perimeter', () => { + it('perimeter', () => { const mask = testUtils.createMask([ [1, 1], [1, 1], @@ -10,9 +12,11 @@ describe('ROI perimeter', () => { ]); const roiMapManager = fromMask(mask); const rois = roiMapManager.getRois(); + expect(rois[0].perimeter).toBeCloseTo(9.656, 2); }); - test('perimeter with external borders', () => { + + it('perimeter with external borders', () => { const mask = testUtils.createMask([ [0, 1, 1, 0], [0, 1, 1, 0], @@ -21,8 +25,10 @@ describe('ROI perimeter', () => { ]); const rois = fromMask(mask).getRois(); + expect(rois[0].perimeter).toBeCloseTo(9.656, 2); }); + it('perimeter with a hole in ROI', () => { const mask = testUtils.createMask([ [0, 1, 1, 1], @@ -35,6 +41,7 @@ describe('ROI perimeter', () => { expect(rois[0].perimeter).toBeCloseTo(9.656, 2); }); + it('perimeter of ROI surrounded by 4 external sides', () => { const mask = testUtils.createMask([ [0, 1], @@ -42,12 +49,15 @@ describe('ROI perimeter', () => { ]); const rois = fromMask(mask).getRois(); + expect(rois[0].perimeter).toBeCloseTo(3.414, 2); }); + it('line', () => { const mask = testUtils.createMask([[1], [1], [1], [1]]); const rois = fromMask(mask).getRois(); + expect(rois[0].perimeter).toBeCloseTo(6.485, 2); }); }); diff --git a/src/roi/__tests__/points.test.ts b/src/roi/__tests__/points.test.ts index fd20ef70f..2bb16dc84 100644 --- a/src/roi/__tests__/points.test.ts +++ b/src/roi/__tests__/points.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import { fromMask } from '../fromMask.js'; test('points 1st test', () => { @@ -9,6 +11,7 @@ test('points 1st test', () => { ]); const roiMapManager = fromMask(mask); const rois = roiMapManager.getRois(); + expect(rois[0].relativePoints).toStrictEqual([ { column: 0, row: 0 }, { column: 1, row: 0 }, @@ -20,6 +23,7 @@ test('points 1st test', () => { { column: 1, row: 3 }, ]); }); + test('points 2nt test for absolute coordinates', () => { const mask = testUtils.createMask([ [0, 1, 1, 0], @@ -29,6 +33,7 @@ test('points 2nt test for absolute coordinates', () => { ]); const roiMapManager = fromMask(mask); const rois = roiMapManager.getRois(); + expect(rois[0].absolutePoints).toStrictEqual([ { column: 1, row: 0 }, { column: 2, row: 0 }, @@ -52,6 +57,7 @@ test('points 3rd test for relative coordinates', () => { ]); const roiMapManager = fromMask(mask); const rois = roiMapManager.getRois(); + expect(rois[1].relativePoints).toStrictEqual([ { column: 0, row: 0 }, { column: 1, row: 0 }, @@ -77,6 +83,7 @@ test('points 4th test for absolute coordinates', () => { ]); const roiMapManager = fromMask(mask); const rois = roiMapManager.getRois(); + expect(rois[1].absolutePoints).toStrictEqual([ { column: 3, row: 0 }, { column: 4, row: 0 }, diff --git a/src/roi/__tests__/roundness.test.ts b/src/roi/__tests__/roundness.test.ts index a328b103d..cc0e91704 100644 --- a/src/roi/__tests__/roundness.test.ts +++ b/src/roi/__tests__/roundness.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import { fromMask } from '../fromMask.js'; test('roundness 1 ', () => { @@ -9,6 +11,7 @@ test('roundness 1 ', () => { ]); const roiMapManager = fromMask(mask); const rois = roiMapManager.getRois(); + expect(rois[0].roundness).toBeCloseTo(0.5092, 2); }); @@ -21,5 +24,6 @@ test('roundness 2', () => { ]); const roiMapManager = fromMask(mask); const rois = roiMapManager.getRois(); + expect(rois[0].roundness).toBeCloseTo(0.42441, 2); }); diff --git a/src/roi/__tests__/solidity.test.ts b/src/roi/__tests__/solidity.test.ts index f567aed12..1a02dab47 100644 --- a/src/roi/__tests__/solidity.test.ts +++ b/src/roi/__tests__/solidity.test.ts @@ -1,3 +1,5 @@ +import { describe, expect, it } from 'vitest'; + import { fromMask } from '../fromMask.js'; describe('ROI solidity', () => { @@ -10,6 +12,7 @@ describe('ROI solidity', () => { ]); const roiMapManager = fromMask(mask); const rois = roiMapManager.getRois(); + expect(rois[0].solidity).toBeCloseTo(0.8571, 2); }); @@ -22,6 +25,7 @@ describe('ROI solidity', () => { ]); const roiMapManager = fromMask(mask); const rois = roiMapManager.getRois(); + expect(rois[0].solidity).toBeCloseTo(0.8571, 2); }); }); diff --git a/src/roi/__tests__/sphericity.test.ts b/src/roi/__tests__/sphericity.test.ts index 1e11d355e..30da7059e 100644 --- a/src/roi/__tests__/sphericity.test.ts +++ b/src/roi/__tests__/sphericity.test.ts @@ -1,7 +1,9 @@ +import { describe, expect, it } from 'vitest'; + import { fromMask } from '../fromMask.js'; describe('ROI sphericity', () => { - test('sphericity 1', () => { + it('sphericity 1', () => { const mask = testUtils.createMask([ [1, 1, 1, 1, 1], [1, 1, 1, 1, 1], @@ -11,10 +13,11 @@ describe('ROI sphericity', () => { ]); const roiMapManager = fromMask(mask); const rois = roiMapManager.getRois(); + expect(rois[0].sphericity).toBeCloseTo(1.0038, 2); }); - test('sphericity 2', () => { + it('sphericity 2', () => { const mask = testUtils.createMask([ [0, 0, 1, 0, 0], [0, 1, 1, 1, 0], @@ -24,10 +27,11 @@ describe('ROI sphericity', () => { ]); const roiMapManager = fromMask(mask); const rois = roiMapManager.getRois(); + expect(rois[0].sphericity).toBeCloseTo(0.9854, 2); }); - test('sphericity 3', () => { + it('sphericity 3', () => { const mask = testUtils.createMask([ [0, 1, 1, 1, 0], [1, 1, 1, 1, 1], @@ -37,6 +41,7 @@ describe('ROI sphericity', () => { ]); const roiMapManager = fromMask(mask); const rois = roiMapManager.getRois(); + expect(rois[0].sphericity).toBeCloseTo(1.0608, 2); }); }); diff --git a/src/roi/__tests__/surface.test.ts b/src/roi/__tests__/surface.test.ts index 2510bd18a..35aef4f12 100644 --- a/src/roi/__tests__/surface.test.ts +++ b/src/roi/__tests__/surface.test.ts @@ -1,3 +1,5 @@ +import { describe, expect, it } from 'vitest'; + import { fromMask } from '../fromMask.js'; describe('ROI surface', () => { @@ -10,7 +12,8 @@ describe('ROI surface', () => { ]); const rois = fromMask(mask).getRois(); - expect(rois[0].surface).toStrictEqual(8); + + expect(rois[0].surface).toBe(8); }); it('surface of a slightly more complex figure', () => { @@ -23,7 +26,8 @@ describe('ROI surface', () => { ]); const rois = fromMask(mask).getRois(); - expect(rois[0].surface).toStrictEqual(13); + + expect(rois[0].surface).toBe(13); }); it('surface on multiple ROIs', () => { @@ -36,8 +40,9 @@ describe('ROI surface', () => { ]); const rois = fromMask(mask).getRois(); - expect(rois[0].surface).toStrictEqual(1); - expect(rois[1].surface).toStrictEqual(3); - expect(rois[2].surface).toStrictEqual(8); + + expect(rois[0].surface).toBe(1); + expect(rois[1].surface).toBe(3); + expect(rois[2].surface).toBe(8); }); }); diff --git a/src/roi/__tests__/waterShed.test.ts b/src/roi/__tests__/waterShed.test.ts index 2feeb0cb0..e006b267b 100644 --- a/src/roi/__tests__/waterShed.test.ts +++ b/src/roi/__tests__/waterShed.test.ts @@ -1,3 +1,5 @@ +import { describe, expect, it } from 'vitest'; + import { computeThreshold } from '../../operations/index.js'; import { waterShed } from '../waterShed.js'; @@ -17,16 +19,13 @@ describe('Test WaterShed Roi generation', () => { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,`); - expect(roiMapManager).toEqual({ - map: { - data: resultArray, - nbPositive: 0, - nbNegative: 1, - width: 5, - height: 5, - }, - whiteRois: [], - blackRois: [], + + expect(roiMapManager.getMap()).toStrictEqual({ + data: resultArray, + nbPositive: 0, + nbNegative: 1, + width: 5, + height: 5, }); }); @@ -56,16 +55,13 @@ describe('Test WaterShed Roi generation', () => { 0, 0, 0, 0, 0, 0, -2, -2, -2, -2, 0, 0, 0, 0, 0, -2, -2, -2, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2, 0`); - expect(roiMapManager).toEqual({ - map: { - data: resultArray, - nbPositive: 0, - nbNegative: 2, - width: 10, - height: 10, - }, - whiteRois: [], - blackRois: [], + + expect(roiMapManager.getMap()).toStrictEqual({ + data: resultArray, + nbPositive: 0, + nbNegative: 2, + width: 10, + height: 10, }); }); @@ -88,18 +84,16 @@ describe('Test WaterShed Roi generation', () => { 0,-1,-1,-1, 0, 0, 0, 0, 0, 0, `); - expect(roiMapManager).toEqual({ - map: { - data: resultArray, - nbPositive: 0, - nbNegative: 1, - width: 5, - height: 5, - }, - whiteRois: [], - blackRois: [], + + expect(roiMapManager.getMap()).toStrictEqual({ + data: resultArray, + nbPositive: 0, + nbNegative: 1, + width: 5, + height: 5, }); }); + it('test 4, waterShed through threshold value', () => { const image = testUtils.createGreyImage([ [3, 3, 3, 3, 3, 3, 3, 3, 4, 4], @@ -130,18 +124,16 @@ describe('Test WaterShed Roi generation', () => { 0, 0, 0, 0, 0, -2, -2, -2, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2, 0 `); - expect(roiMapManager).toEqual({ - map: { - data: resultArray, - nbPositive: 0, - nbNegative: 2, - width: 10, - height: 10, - }, - whiteRois: [], - blackRois: [], + + expect(roiMapManager.getMap()).toStrictEqual({ + data: resultArray, + nbPositive: 0, + nbNegative: 2, + width: 10, + height: 10, }); }); + it('test 5, waterShed through threshold mask and with inverted image', () => { const image = testUtils.createGreyImage([ [3, 3, 3, 3, 3, 3, 3, 3, 4, 4], @@ -170,16 +162,13 @@ describe('Test WaterShed Roi generation', () => { -1, -1, -1, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, 0, -2 `); - expect(roiMapManager).toEqual({ - map: { - data: resultArray, - nbPositive: 0, - nbNegative: 2, - width: 10, - height: 10, - }, - whiteRois: [], - blackRois: [], + + expect(roiMapManager.getMap()).toStrictEqual({ + data: resultArray, + nbPositive: 0, + nbNegative: 2, + width: 10, + height: 10, }); }); }); diff --git a/src/roi/utils/__tests__/getColorMap.test.ts b/src/roi/utils/__tests__/getColorMap.test.ts index 3c31a60ea..079e2e114 100644 --- a/src/roi/utils/__tests__/getColorMap.test.ts +++ b/src/roi/utils/__tests__/getColorMap.test.ts @@ -1,8 +1,11 @@ +import { expect, test } from 'vitest'; + import { getBinaryMap } from '../colorMaps/getBinaryMap.js'; import { getColorMap } from '../getColorMap.js'; test('default options', () => { const colorMap = getBinaryMap({ nbNegative: 1, nbPositive: 1 }); + expect(Array.from(colorMap)).toStrictEqual([4278190335, 0, 4278255360]); }); @@ -11,6 +14,7 @@ test('binary, BW', () => { nbNegative: 1, nbPositive: 1, }); + expect(Array.from(colorMap)).toStrictEqual([4278190335, 0, 4278255360]); }); @@ -20,6 +24,7 @@ test('binary, WHITE', () => { nbPositive: 1, roiKind: 'white', }); + expect(Array.from(colorMap)).toStrictEqual([0, 0, 4278255360]); }); @@ -29,6 +34,7 @@ test('binary, BLACK', () => { nbPositive: 1, roiKind: 'black', }); + expect(Array.from(colorMap)).toStrictEqual([4278190335, 0, 0]); }); @@ -38,6 +44,7 @@ test('SATURATION, 1 negative and 1 positive ROIs', () => { nbNegative: 1, nbPositive: 1, }); + expect(Array.from(colorMap)).toStrictEqual([4294901760, 0, 4278190335]); }); @@ -48,6 +55,7 @@ test('RAINBOW, 1 negative and 2 positive ROIs, WHITE', () => { nbPositive: 2, roiKind: 'white', }); + expect(Array.from(colorMap)).toStrictEqual([0, 0, 4278190335, 4294967040]); }); @@ -58,6 +66,7 @@ test('RAINBOW, 1 negative and 2 positive ROIs, BLACK', () => { nbPositive: 2, roiKind: 'black', }); + expect(Array.from(colorMap)).toStrictEqual([4278190335, 0, 0, 0]); }); @@ -68,6 +77,7 @@ test('RAINBOW, 1 negative and 1 positive ROIs, BW', () => { nbPositive: 1, roiKind: 'bw', }); + expect(Array.from(colorMap)).toStrictEqual([ 4278190335, 4278255360, 0, 4294901760, ]); diff --git a/src/roi/utils/__tests__/hsvToRgb.test.ts b/src/roi/utils/__tests__/hsvToRgb.test.ts index ffeef0ba1..c8dcbd21e 100644 --- a/src/roi/utils/__tests__/hsvToRgb.test.ts +++ b/src/roi/utils/__tests__/hsvToRgb.test.ts @@ -1,41 +1,51 @@ +import { expect, test } from 'vitest'; + import { hsvToRgb } from '../hsvToRgb.js'; test('black', () => { const rgb = new Uint8Array([0, 0, 0]); + expect(hsvToRgb([50, 100, 0])).toStrictEqual(rgb); }); test('white', () => { const rgb = new Uint8Array([255, 255, 255]); + expect(hsvToRgb([50, 0, 255])).toStrictEqual(rgb); }); test('red', () => { const rgb = new Uint8Array([255, 0, 0]); + expect(hsvToRgb([0, 255, 255])).toStrictEqual(rgb); }); test('green', () => { const rgb = new Uint8Array([0, 255, 0]); + expect(hsvToRgb([120, 255, 255])).toStrictEqual(rgb); }); test('blue', () => { const rgb = new Uint8Array([0, 0, 255]); + expect(hsvToRgb([240, 255, 255])).toStrictEqual(rgb); }); test('random color', () => { const rgb = new Uint8Array([255, 0, 42]); + expect(hsvToRgb([350, 255, 255])).toStrictEqual(rgb); }); test('other random color', () => { const rgb = new Uint8Array([0, 127, 255]); + expect(hsvToRgb([210, 255, 255])).toStrictEqual(rgb); }); test('yet another random color', () => { const rgb = new Uint8Array([127, 255, 0]); + expect(hsvToRgb([90, 255, 255])).toStrictEqual(rgb); }); diff --git a/src/roi/utils/__tests__/rgbToNumber.test.ts b/src/roi/utils/__tests__/rgbToNumber.test.ts index 5e75cd0d8..57b621401 100644 --- a/src/roi/utils/__tests__/rgbToNumber.test.ts +++ b/src/roi/utils/__tests__/rgbToNumber.test.ts @@ -1,16 +1,21 @@ +import { expect, test } from 'vitest'; + import { rgbToNumber } from '../rgbToNumber.js'; test('white', () => { const rgb = new Uint8Array([255, 255, 255]); + expect(rgbToNumber(rgb)).toBe(0xffffffff); }); test('red', () => { const rgb = new Uint8Array([255, 0, 0]); + expect(rgbToNumber(rgb)).toBe(0xff0000ff); }); test('green', () => { const rgb = new Uint8Array([0, 255, 0]); + expect(rgbToNumber(rgb)).toBe(0xff00ff00); }); diff --git a/src/save/__tests__/encodeBmp.test.ts b/src/save/__tests__/encodeBmp.test.ts index 0d272222e..8a1f20ee9 100644 --- a/src/save/__tests__/encodeBmp.test.ts +++ b/src/save/__tests__/encodeBmp.test.ts @@ -13,8 +13,12 @@ test('encode 5x5 mask', () => { const mask = image.threshold({ threshold: 0.5 }); const result = testUtils.loadBuffer('formats/bmp/5x5.bmp'); const buffer = encodeBmp(mask).buffer; + + // TODO: change to `toStrictEqual`. + // eslint-disable-next-line vitest/prefer-strict-equal expect(buffer).toEqual(result.buffer); }); + test('encode 6x4 mask', () => { const image = testUtils.createGreyImage([ [255, 255, 255, 255, 255, 255], @@ -25,8 +29,12 @@ test('encode 6x4 mask', () => { const mask = image.threshold({ threshold: 0.5 }); const result = testUtils.loadBuffer('formats/bmp/6x4.bmp'); const buffer = encodeBmp(mask).buffer; + + // TODO: change to `toStrictEqual`. + // eslint-disable-next-line vitest/prefer-strict-equal expect(buffer).toEqual(result.buffer); }); + test('encode 10x2 mask', () => { const image = testUtils.createGreyImage([ [255, 255, 255, 0, 0, 255, 0, 255, 0, 255], @@ -35,8 +43,12 @@ test('encode 10x2 mask', () => { const mask = image.threshold({ threshold: 0.5 }); const result = testUtils.loadBuffer('formats/bmp/10x2.bmp'); const buffer = encodeBmp(mask).buffer; + + // TODO: change to `toStrictEqual`. + // eslint-disable-next-line vitest/prefer-strict-equal expect(buffer).toEqual(result.buffer); }); + test('should throw error', () => { const image = testUtils.createGreyImage([ [255, 255, 255, 0, 0, 255, 0, 255, 0, 255], diff --git a/src/save/__tests__/encodeDataURL.test.ts b/src/save/__tests__/encodeDataURL.test.ts index d21ea4a93..433c42e03 100644 --- a/src/save/__tests__/encodeDataURL.test.ts +++ b/src/save/__tests__/encodeDataURL.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import { encode } from '../encode.js'; import { encodeDataURL } from '../encodeDataURL.js'; @@ -27,6 +29,7 @@ test('basic image 2 (jpeg)', () => { const format = 'jpeg'; const base64 = encodeDataURL(image, { format }); const base64Data = Buffer.from(encode(image, { format })).toString('base64'); + expect(typeof base64).toBe('string'); expect(base64Data).toMatchSnapshot(); }); @@ -42,6 +45,7 @@ test('legacy image-js test', () => { const format = 'jpeg'; const url = encodeDataURL(image, { format }); const base64Data = Buffer.from(encode(image, { format })).toString('base64'); + expect(typeof url).toBe('string'); expect(base64Data).toBe(url.slice(url.indexOf(',') + 1)); }); diff --git a/src/save/__tests__/encodeJpeg.test.ts b/src/save/__tests__/encodeJpeg.test.ts index 069013d64..75e0184bd 100644 --- a/src/save/__tests__/encodeJpeg.test.ts +++ b/src/save/__tests__/encodeJpeg.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import { decode } from '../../load/decode.js'; import { encodeJpeg } from '../encodeJpeg.js'; @@ -10,10 +12,11 @@ test('encode an 8-bit rgba image', () => { const encoded = encodeJpeg(image); const reloaded = decode(encoded); + expect(reloaded.width).toBe(2); expect(reloaded.height).toBe(2); - expect(reloaded.colorModel).toStrictEqual('RGBA'); - expect(reloaded.bitDepth).toStrictEqual(8); + expect(reloaded.colorModel).toBe('RGBA'); + expect(reloaded.bitDepth).toBe(8); }); test('decode the encoded jpeg returns image with same characteristics', () => { @@ -36,8 +39,9 @@ test('encoding a 16-bit image should convert it to a 8-bit image', () => { ); const encoded = encodeJpeg(image); const reloaded = decode(encoded); + expect(reloaded.width).toBe(2); expect(reloaded.height).toBe(2); - expect(reloaded.colorModel).toStrictEqual('RGBA'); - expect(reloaded.bitDepth).toStrictEqual(8); + expect(reloaded.colorModel).toBe('RGBA'); + expect(reloaded.bitDepth).toBe(8); }); diff --git a/src/save/__tests__/encodePng.test.ts b/src/save/__tests__/encodePng.test.ts index 78c858745..d1370d604 100644 --- a/src/save/__tests__/encodePng.test.ts +++ b/src/save/__tests__/encodePng.test.ts @@ -1,19 +1,27 @@ +import { expect, test } from 'vitest'; + import { decode } from '../../load/decode.js'; import { encodePng } from '../encodePng.js'; test('should encode what it decoded', () => { const buffer = testUtils.loadBuffer('formats/grey8.png'); const img = decode(buffer); + expect(img.size).toBe(2700); + const imgDup = decode(encodePng(img)); + expect(imgDup).toMatchImage(img); }); test('should encode a 16bits image correctly', () => { const img = testUtils.load('formats/tif/grey16.tif'); + expect(img.size).toBe(2700); expect(img.bitDepth).toBe(16); + const imgDup = decode(encodePng(img)); + expect(imgDup.bitDepth).toBe(16); expect(imgDup).toMatchImage(img); }); @@ -22,6 +30,7 @@ test('add mask test', () => { const img = testUtils.load('formats/tif/grey16.tif'); const mask = img.threshold(); const imgDup = decode(encodePng(mask)); + expect(imgDup.colorModel).toBe('GREY'); expect(imgDup.bitDepth).toBe(8); }); diff --git a/src/save/__tests__/write.test.ts b/src/save/__tests__/write.test.ts index af0e0d45b..8af4585b2 100644 --- a/src/save/__tests__/write.test.ts +++ b/src/save/__tests__/write.test.ts @@ -2,13 +2,17 @@ import { existsSync } from 'node:fs'; import path from 'node:path'; import { pathToFileURL } from 'node:url'; +import { afterEach, beforeEach, expect, test } from 'vitest'; + import { read, readSync } from '../../load/index.js'; import { write, writeSync } from '../write.js'; let tmpDir: string; + beforeEach(() => { tmpDir = testUtils.makeTmpDir(); }); + afterEach(() => { testUtils.cleanTmpDir(tmpDir); }); @@ -17,8 +21,11 @@ test('async write image to disk (png)', async () => { const img = testUtils.load('opencv/test.png'); const destination = path.join(tmpDir, 'image.png'); await write(destination, img); + expect(existsSync(destination)).toBe(true); + const imgRead = await read(destination); + expect(imgRead).toMatchImage(img); }); @@ -26,8 +33,11 @@ test('format option png', async () => { const img = testUtils.load('opencv/test.png'); const destination = path.join(tmpDir, 'image.png'); await write(destination, img, { format: 'png' }); + expect(existsSync(destination)).toBe(true); + const imgRead = await read(destination); + expect(imgRead).toMatchImage(img); }); @@ -35,8 +45,11 @@ test('async write image to disk (jpeg)', async () => { const img = testUtils.load('opencv/test.png'); const destination = path.join(tmpDir, 'image.jpeg'); await write(destination, img, { format: 'jpeg' }); + expect(existsSync(destination)).toBe(true); + const imgRead = await read(destination); + expect(imgRead.width).toBe(img.width); expect(imgRead.colorModel).toBe('RGBA'); }); @@ -45,8 +58,11 @@ test('sync write image to disk', () => { const img = testUtils.load('opencv/test.png'); const destination = path.join(tmpDir, 'image.png'); writeSync(destination, img); + expect(existsSync(destination)).toBe(true); + const imgRead = readSync(destination); + expect(imgRead).toMatchImage(img); }); @@ -54,8 +70,11 @@ test('sync write image to disk (jpeg)', () => { const img = testUtils.load('opencv/test.png'); const destination = path.join(tmpDir, 'image.jpeg'); writeSync(destination, img); + expect(existsSync(destination)).toBe(true); + const imgRead = readSync(destination); + expect(imgRead.width).toBe(img.width); expect(imgRead.colorModel).toBe('RGBA'); }); @@ -67,8 +86,11 @@ test('sync write mask image to disk', () => { const maskImage = mask.convertColor('GREY'); const destination = path.join(tmpDir, 'image.png'); writeSync(destination, mask); + expect(existsSync(destination)).toBe(true); + const imgRead = readSync(destination); + expect(imgRead).toMatchImage(maskImage); }); @@ -79,8 +101,11 @@ test('async write mask image to disk', async () => { const maskImage = mask.convertColor('GREY'); const destination = path.join(tmpDir, 'image.png'); await write(destination, mask); + expect(existsSync(destination)).toBe(true); + const imgRead = await read(destination); + expect(imgRead).toMatchImage(maskImage); }); @@ -88,8 +113,11 @@ test('async write with URL', async () => { const img = testUtils.load('opencv/test.png'); const destination = pathToFileURL(path.join(tmpDir, 'image.png')); await write(destination, img); + expect(existsSync(destination)).toBe(true); + const imgRead = await read(destination); + expect(imgRead).toMatchImage(img); }); @@ -97,8 +125,11 @@ test('sync write with URL', () => { const img = testUtils.load('opencv/test.png'); const destination = pathToFileURL(path.join(tmpDir, 'image.png')); writeSync(destination, img); + expect(existsSync(destination)).toBe(true); + const imgRead = readSync(destination); + expect(imgRead).toMatchImage(img); }); @@ -106,8 +137,11 @@ test('async write with recursive option', async () => { const img = testUtils.load('opencv/test.png'); const destination = path.join(tmpDir, 'subdir/123', 'image.png'); await write(destination, img, { recursive: true }); + expect(existsSync(destination)).toBe(true); + const imgRead = await read(destination); + expect(imgRead).toMatchImage(img); }); @@ -115,14 +149,18 @@ test('sync write with recursive option', () => { const img = testUtils.load('opencv/test.png'); const destination = path.join(tmpDir, 'subdir/123', 'image.png'); writeSync(destination, img, { recursive: true }); + expect(existsSync(destination)).toBe(true); + const imgRead = readSync(destination); + expect(imgRead).toMatchImage(img); }); test('unknown format error', () => { const img = testUtils.load('opencv/test.png'); const destination = path.join(tmpDir, 'image.png'); + expect(() => { // @ts-expect-error test invalid format writeSync(destination, img, { format: 'foo' }); @@ -132,6 +170,7 @@ test('unknown format error', () => { test('image extension error', async () => { const img = testUtils.load('opencv/test.png'); const destination = path.join(tmpDir, 'image.tiff'); + await expect(write(destination, img)).rejects.toThrow( 'image format could not be determined from file extension. Use a supported extension or specify the format option', ); diff --git a/src/save/encode.ts b/src/save/encode.ts index 3bd5e769c..dffe26e2b 100644 --- a/src/save/encode.ts +++ b/src/save/encode.ts @@ -1,4 +1,4 @@ -import { match, P } from 'ts-pattern'; +import { P, match } from 'ts-pattern'; import type { Image } from '../Image.js'; import type { Mask } from '../Mask.js'; diff --git a/src/save/encodeDataURL.ts b/src/save/encodeDataURL.ts index 013002322..b6a448c68 100644 --- a/src/save/encodeDataURL.ts +++ b/src/save/encodeDataURL.ts @@ -7,7 +7,7 @@ import type { EncodeOptionsJpeg, EncodeOptionsPng, } from './encode.js'; -import { encode, defaultPng } from './encode.js'; +import { defaultPng, encode } from './encode.js'; /** * Converts image into Data URL string. * @param image - Image to get base64 encoding from. diff --git a/src/stack/compute/__tests__/histogram.test.ts b/src/stack/compute/__tests__/histogram.test.ts index b5b7a6698..69b6ddf08 100644 --- a/src/stack/compute/__tests__/histogram.test.ts +++ b/src/stack/compute/__tests__/histogram.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import { Stack } from '../../../Stack.js'; test('two grey images, bitsDepth = 8', () => { diff --git a/src/stack/compute/__tests__/maxImage.test.ts b/src/stack/compute/__tests__/maxImage.test.ts index e91aad8b2..d61aae00b 100644 --- a/src/stack/compute/__tests__/maxImage.test.ts +++ b/src/stack/compute/__tests__/maxImage.test.ts @@ -1,5 +1,7 @@ import { join } from 'node:path'; +import { expect, test } from 'vitest'; + import { Image } from '../../../Image.js'; import { Stack } from '../../../Stack.js'; import { getStackFromFolder } from '../../utils/getStackFromFolder.js'; diff --git a/src/stack/compute/__tests__/meanImage.test.ts b/src/stack/compute/__tests__/meanImage.test.ts index 1341eec28..955f1ccbc 100644 --- a/src/stack/compute/__tests__/meanImage.test.ts +++ b/src/stack/compute/__tests__/meanImage.test.ts @@ -1,5 +1,7 @@ import { join } from 'node:path'; +import { expect, test } from 'vitest'; + import { Image } from '../../../Image.js'; import { Stack } from '../../../Stack.js'; import { getStackFromFolder } from '../../utils/getStackFromFolder.js'; @@ -33,6 +35,7 @@ test('2 RGB images', () => { test('more complex stack', () => { const folder = join(import.meta.dirname, '../../../../test/img/correctColor'); const stack = getStackFromFolder(folder); + expect(stack.meanImage()).toMatchImageSnapshot(); }); diff --git a/src/stack/compute/__tests__/medianImage.test.ts b/src/stack/compute/__tests__/medianImage.test.ts index 1ceea19a7..2ba4f624a 100644 --- a/src/stack/compute/__tests__/medianImage.test.ts +++ b/src/stack/compute/__tests__/medianImage.test.ts @@ -1,5 +1,7 @@ import { join } from 'node:path'; +import { expect, test } from 'vitest'; + import { Image } from '../../../Image.js'; import { Stack } from '../../../Stack.js'; import { getStackFromFolder } from '../../utils/getStackFromFolder.js'; @@ -35,5 +37,6 @@ test('3 RGB images', () => { test('more complex stack', () => { const folder = join(import.meta.dirname, '../../../../test/img/correctColor'); const stack = getStackFromFolder(folder); + expect(stack.medianImage()).toMatchImageSnapshot(); }); diff --git a/src/stack/compute/__tests__/minImage.test.ts b/src/stack/compute/__tests__/minImage.test.ts index bc273eb6b..f80b96d03 100644 --- a/src/stack/compute/__tests__/minImage.test.ts +++ b/src/stack/compute/__tests__/minImage.test.ts @@ -1,5 +1,7 @@ import { join } from 'node:path'; +import { expect, test } from 'vitest'; + import { Image } from '../../../Image.js'; import { Stack } from '../../../Stack.js'; import { getStackFromFolder } from '../../utils/getStackFromFolder.js'; @@ -33,5 +35,6 @@ test('2 RGB images', () => { test('more complex stack', () => { const folder = join(import.meta.dirname, '../../../../test/img/correctColor'); const stack = getStackFromFolder(folder); + expect(stack.minImage()).toMatchImageSnapshot(); }); diff --git a/src/stack/compute/__tests__/sum.test.ts b/src/stack/compute/__tests__/sum.test.ts index 72633a3ce..537942954 100644 --- a/src/stack/compute/__tests__/sum.test.ts +++ b/src/stack/compute/__tests__/sum.test.ts @@ -1,5 +1,7 @@ import { join } from 'node:path'; +import { expect, test } from 'vitest'; + import { Image } from '../../../Image.js'; import { Stack } from '../../../Stack.js'; import { getStackFromFolder } from '../../utils/getStackFromFolder.js'; @@ -27,6 +29,7 @@ test('2 RGB images', () => { test('more complex stack', () => { const folder = join(import.meta.dirname, '../../../../test/img/correctColor'); const stack = getStackFromFolder(folder); + expect(stack.sum()).toMatchImageSnapshot(); }); diff --git a/src/stack/load/__tests__/decodeStack.test.ts b/src/stack/load/__tests__/decodeStack.test.ts index b34a90e0f..f1880cf99 100644 --- a/src/stack/load/__tests__/decodeStack.test.ts +++ b/src/stack/load/__tests__/decodeStack.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import type { TestImagePath } from '../../../../test/TestImagePath.js'; import { decodeStack } from '../decodeStack.js'; @@ -29,7 +31,9 @@ test.each([ ])('stacks with 2 images ($colorModel, bitDepth = $bitDepth)', (data) => { const buffer = testUtils.loadBuffer(data.name as TestImagePath); const stack = decodeStack(buffer); + expect(stack.size).toBe(data.pages); + for (const image of stack) { expect(image.colorModel).toBe(data.colorModel); expect(image.bitDepth).toBe(data.bitDepth); @@ -38,5 +42,6 @@ test.each([ test('invalid data format', () => { const buffer = testUtils.loadBuffer('formats/grey8.png'); + expect(() => decodeStack(buffer)).toThrow('invalid data format: image/png'); }); diff --git a/src/stack/utils/__tests__/checkProcessable.test.ts b/src/stack/utils/__tests__/checkProcessable.test.ts index 0a1748497..aba0ae062 100644 --- a/src/stack/utils/__tests__/checkProcessable.test.ts +++ b/src/stack/utils/__tests__/checkProcessable.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import { Image } from '../../../Image.js'; import { Stack } from '../../../Stack.js'; import { checkProcessable } from '../checkProcessable.js'; @@ -6,6 +8,7 @@ test('should throw if images have different sizes', () => { const image1 = testUtils.createGreyImage([[1, 2, 3, 4]]); const image2 = testUtils.createGreyImage([[4, 3]]); const stack = new Stack([image1, image2]); + expect(() => { checkProcessable(stack, { sameDimensions: true }); }).toThrow('images must all have same dimensions to apply this algorithm'); @@ -15,6 +18,7 @@ test('default options', () => { const image1 = testUtils.createGreyImage([[1, 2, 3, 4]]); const image2 = testUtils.createGreyImage([[4, 3, 2, 1]]); const stack = new Stack([image1, image2]); + expect(() => { checkProcessable(stack); }).not.toThrow(); @@ -24,6 +28,7 @@ test('should have alpha channel', () => { const image1 = testUtils.createGreyImage([[1, 2, 3, 4]]); const image2 = testUtils.createGreyImage([[4, 3, 2, 1]]); const stack = new Stack([image1, image2]); + expect(() => { checkProcessable(stack, { alpha: true }); }).toThrow( @@ -35,6 +40,7 @@ test('should not have alpha channel', () => { const image1 = testUtils.createGreyaImage([[1, 2, 3, 4]]); const image2 = testUtils.createGreyaImage([[4, 3, 2, 1]]); const stack = new Stack([image1, image2]); + expect(() => { checkProcessable(stack, { alpha: false }); }).toThrow( @@ -45,6 +51,7 @@ test('should not have alpha channel', () => { test('bit depth error', () => { const image = new Image(1, 2, { bitDepth: 16 }); const stack = new Stack([image, image]); + expect(() => { checkProcessable(stack, { bitDepth: 8 }); }).toThrow('image bitDepth must be 8 to apply this algorithm'); diff --git a/src/utils/__tests__/assert.test.ts b/src/utils/__tests__/assert.test.ts index 3b04f11a4..2e637dc38 100644 --- a/src/utils/__tests__/assert.test.ts +++ b/src/utils/__tests__/assert.test.ts @@ -1,21 +1,26 @@ -import { assert } from '../validators/assert.js'; +import { expect, test } from 'vitest'; + +import { assert as assertValidator } from '../validators/assert.ts'; test('should restrict type', () => { const variable: number | undefined = 3; - assert(variable); + assertValidator(variable); + expect(typeof variable).toBe('number'); }); test('should throw error message', () => { const variable: number | undefined = 3; + expect(() => { - assert(variable === 2, 'Error message'); + assertValidator(variable === 2, 'Error message'); }).toThrow('Error message'); }); test('should throw default error message', () => { const variable: number | undefined = 3; + expect(() => { - assert(variable === 2); + assertValidator(variable === 2); }).toThrow('unreachable'); }); diff --git a/src/utils/__tests__/boolToNumber.test.ts b/src/utils/__tests__/boolToNumber.test.ts index c385213a3..7927ebbd9 100644 --- a/src/utils/__tests__/boolToNumber.test.ts +++ b/src/utils/__tests__/boolToNumber.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import { boolToNumber } from '../boolToNumber.js'; test('convert number to number', () => { diff --git a/src/utils/__tests__/borderIterator.test.ts b/src/utils/__tests__/borderIterator.test.ts index 880d97447..8d5b3b209 100644 --- a/src/utils/__tests__/borderIterator.test.ts +++ b/src/utils/__tests__/borderIterator.test.ts @@ -1,9 +1,12 @@ +import { expect, test } from 'vitest'; + import { Image } from '../../Image.js'; import type { Mask } from '../../Mask.js'; import { borderIterator } from '../borderIterator.js'; test('3x4 image', () => { const image = new Image(4, 3); + expect(getBorderPixels(image)).toStrictEqual([ 0, 1, 2, 3, 7, 11, 10, 9, 8, 4, ]); @@ -11,6 +14,7 @@ test('3x4 image', () => { test('5x4 image', () => { const image = new Image(3, 5); + expect(getBorderPixels(image)).toStrictEqual([ 0, 1, 2, 5, 8, 11, 14, 13, 12, 9, 6, 3, ]); diff --git a/src/utils/__tests__/checkKernel.test.ts b/src/utils/__tests__/checkKernel.test.ts index c47d3f6fe..e84bea5fd 100644 --- a/src/utils/__tests__/checkKernel.test.ts +++ b/src/utils/__tests__/checkKernel.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import { checkKernel } from '../validators/checkKernel.js'; test('should throw', () => { diff --git a/src/utils/__tests__/checkProcessable.test.ts b/src/utils/__tests__/checkProcessable.test.ts index 96d59bb47..7046f3456 100644 --- a/src/utils/__tests__/checkProcessable.test.ts +++ b/src/utils/__tests__/checkProcessable.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import checkProcessable from '../validators/checkProcessable.js'; test('wrong bit depth', () => { @@ -5,6 +7,7 @@ test('wrong bit depth', () => { [0, 1], [2, 3], ]); + expect(() => { checkProcessable(img, { bitDepth: [1, 16], @@ -17,6 +20,7 @@ test('wrong alpha', () => { [0, 1], [2, 3], ]); + expect(() => { checkProcessable(img, { alpha: true }); }).toThrow('image alpha must be true to apply this algorithm'); @@ -27,6 +31,7 @@ test('wrong color model', () => { [0, 1], [2, 3], ]); + expect(() => { checkProcessable(img, { colorModel: ['RGB'] }); }).toThrow('image colorModel must be RGB to apply this algorithm'); @@ -37,6 +42,7 @@ test('wrong number of components', () => { [0, 1], [2, 3], ]); + expect(() => { checkProcessable(img, { components: [2, 4], @@ -49,6 +55,7 @@ test('wrong number of channels', () => { [0, 1], [2, 3], ]); + expect(() => { checkProcessable(img, { channels: [2, 3], @@ -61,6 +68,7 @@ test('only one valid bit depth or channel', () => { [0, 1], [2, 3], ]); + expect(() => { checkProcessable(img, { bitDepth: 8, @@ -71,6 +79,7 @@ test('only one valid bit depth or channel', () => { test('only grey images accepted', () => { const img = testUtils.createRgbImage([[0, 1, 2]]); + expect(() => { checkProcessable(img, { bitDepth: 8, diff --git a/src/utils/__tests__/clamp.test.ts b/src/utils/__tests__/clamp.test.ts index 11698f14b..b8b64c437 100644 --- a/src/utils/__tests__/clamp.test.ts +++ b/src/utils/__tests__/clamp.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import { Image } from '../../Image.js'; import { getClamp } from '../clamp.js'; @@ -8,6 +10,7 @@ test("clamp 65'536", () => { }); const clamp = getClamp(image); + expect(clamp(2000000)).toBe(65535); expect(clamp(-535)).toBe(0); }); diff --git a/src/utils/__tests__/copyData.test.ts b/src/utils/__tests__/copyData.test.ts index de3722746..006f32749 100644 --- a/src/utils/__tests__/copyData.test.ts +++ b/src/utils/__tests__/copyData.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import { Image } from '../../Image.js'; import { copyData } from '../copyData.js'; @@ -8,6 +10,7 @@ test('2x3 GREY image', () => { ]); const target = new Image(3, 2, { colorModel: 'GREY' }); copyData(source, target); + expect(target).toMatchImageData([ [1, 2, 3], [4, 5, 6], @@ -20,6 +23,7 @@ test('check error', () => { [4, 5, 6], ]); const target = new Image(5, 2, { colorModel: 'GREY' }); + expect(() => { copyData(source, target); }).toThrow('images width, height or color model is different'); diff --git a/src/utils/__tests__/getDefaultColor.test.ts b/src/utils/__tests__/getDefaultColor.test.ts index a1c302d51..3436951be 100644 --- a/src/utils/__tests__/getDefaultColor.test.ts +++ b/src/utils/__tests__/getDefaultColor.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import { getDefaultColor } from '../getDefaultColor.js'; test('GREY', () => { @@ -6,6 +8,7 @@ test('GREY', () => { [1, 1], ]); const expected = getDefaultColor(image); + expect(expected).toStrictEqual([0]); }); @@ -15,6 +18,7 @@ test('GREYA', () => { [1, 255, 1, 255], ]); const expected = getDefaultColor(image); + expect(expected).toStrictEqual([0, 255]); }); @@ -24,6 +28,7 @@ test('RBG', () => { [1, 255, 10, 1, 22, 255], ]); const expected = getDefaultColor(image); + expect(expected).toStrictEqual([0, 0, 0]); }); @@ -33,5 +38,6 @@ test('RBGA', () => { [1, 10, 55, 255, 10, 1, 22, 255], ]); const expected = getDefaultColor(image); + expect(expected).toStrictEqual([0, 0, 0, 255]); }); diff --git a/src/utils/__tests__/getIndex.test.ts b/src/utils/__tests__/getIndex.test.ts index 52068181d..e153b0864 100644 --- a/src/utils/__tests__/getIndex.test.ts +++ b/src/utils/__tests__/getIndex.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import { Image } from '../../Image.js'; import { Mask } from '../../Mask.js'; import { getIndex } from '../getIndex.js'; diff --git a/src/utils/__tests__/getMinMax.test.ts b/src/utils/__tests__/getMinMax.test.ts index a89c0a3d6..cbf4256ba 100644 --- a/src/utils/__tests__/getMinMax.test.ts +++ b/src/utils/__tests__/getMinMax.test.ts @@ -1,7 +1,10 @@ +import { expect, test } from 'vitest'; + import { getMinMax } from '../getMinMax.js'; test('grey image', () => { const image = testUtils.createGreyImage([[1, 2, 3, 4, 5, 7, 4, 9, 6]]); + expect(getMinMax(image)).toStrictEqual({ min: [1], max: [9] }); }); @@ -12,6 +15,7 @@ test('greya image', () => { [5, 7], [4, 9], ]); + expect(getMinMax(image)).toStrictEqual({ min: [1, 2], max: [5, 9] }); }); @@ -21,6 +25,7 @@ test('rgb image', () => { [4, 5, 7], [4, 9, 2], ]); + expect(getMinMax(image)).toStrictEqual({ min: [1, 2, 2], max: [4, 9, 7] }); }); @@ -30,6 +35,7 @@ test('rgba image', () => { [4, 5, 7, 5], [4, 9, 2, 7], ]); + expect(getMinMax(image)).toStrictEqual({ min: [1, 2, 2, 0], max: [4, 9, 7, 7], @@ -42,6 +48,7 @@ test('image.minMax', () => { [5, 1, 0, 5], [7, 9, 2, 7], ]); + expect(image.minMax()).toStrictEqual({ min: [1, 1, 0, 5], max: [7, 9, 3, 8], diff --git a/src/utils/__tests__/getOutputImage.test.ts b/src/utils/__tests__/getOutputImage.test.ts index 27386577b..ee5a317c6 100644 --- a/src/utils/__tests__/getOutputImage.test.ts +++ b/src/utils/__tests__/getOutputImage.test.ts @@ -1,3 +1,5 @@ +import { describe, expect, it } from 'vitest'; + import { Image } from '../../Image.js'; import { Mask } from '../../Mask.js'; import { ImageColorModel } from '../constants/colorModels.js'; @@ -15,6 +17,7 @@ describe('getOutputImage', () => { [2, 3], ]); const output = getOutputImage(img); + expect(output).toMatchObject({ width: 2, height: 2, @@ -33,6 +36,7 @@ describe('getOutputImage', () => { [2, 3], ]); const output = getOutputImage(img, {}, { clone: true }); + expect(output).toMatchObject({ width: 2, height: 2, @@ -44,6 +48,7 @@ describe('getOutputImage', () => { [2, 3], ]); }); + it('should clone data to out', () => { const img = testUtils.createGreyImage([ [0, 1], @@ -55,15 +60,18 @@ describe('getOutputImage', () => { [7, 8], ]); const output = getOutputImage(img, { out }, { clone: true }); + expect(out).toBe(output); expect(out).toMatchImage(img); }); + it('should create with requirements', () => { const img = new Image(1, 2); const requirements = { colorModel: ImageColorModel.GREY, }; const output = getOutputImage(img, {}, { newParameters: requirements }); + expect(output).toMatchObject({ colorModel: ImageColorModel.GREY, }); @@ -80,6 +88,7 @@ describe('getOutputImage', () => { { out: correct }, { newParameters: requirements }, ); + expect(output).toBe(correct); }); @@ -89,6 +98,7 @@ describe('getOutputImage', () => { colorModel: ImageColorModel.GREY, }; const incorrect = new Image(1, 2); + expect(() => getOutputImage(img, { out: incorrect }, { newParameters: requirements }), ).toThrow( @@ -98,17 +108,21 @@ describe('getOutputImage', () => { it('should throw if out is not an image', () => { const img = new Image(1, 2); + // @ts-expect-error: testing JS problem expect(() => getOutputImage(img, { out: 'str' })).toThrow( 'out must be an Image', ); }); + it('should keep source origin', () => { const img = new Image(2, 2, { origin: { row: 1, column: 2 } }); let output = getOutputImage(img, {}, { clone: true }); + expect(output.origin).toStrictEqual(img.origin); output = getOutputImage(img); + expect(output.origin).toStrictEqual(img.origin); }); }); @@ -117,6 +131,7 @@ describe('maskToOutputImage', () => { it('should default to creating an empty image', () => { const mask = new Mask(2, 2); const output = maskToOutputImage(mask); + expect(output).toMatchObject({ width: 2, height: 2, @@ -128,31 +143,39 @@ describe('maskToOutputImage', () => { [0, 0], ]); }); + it('providing valid out', () => { const img = new Mask(1, 2); const out = new Image(1, 2, { colorModel: ImageColorModel.GREY }); const output = maskToOutputImage(img, { out }); + expect(output).toBe(out); }); + it('providing invalid out', () => { const img = new Mask(1, 2); const out = new Image(2, 2, { colorModel: ImageColorModel.GREY }); + expect(() => { maskToOutputImage(img, { out }); }).toThrow( /cannot use out image. Its width property must be 1. Received 2/, ); }); + it('should throw if out is not an image', () => { const img = new Image(1, 2); + // @ts-expect-error: testing JS problem expect(() => maskToOutputImage(img, { out: 'str' })).toThrow( 'out must be an Image', ); }); + it('should keep source origin', () => { const mask = new Mask(1, 2); const output = maskToOutputImage(mask); + expect(output.origin).toStrictEqual(mask.origin); }); }); @@ -161,6 +184,7 @@ describe('imageToOutputMask', () => { it('should default to creating an empty mask', () => { const image = new Image(2, 2); const output = imageToOutputMask(image); + expect(output).toMatchObject({ width: 2, height: 2, @@ -172,31 +196,39 @@ describe('imageToOutputMask', () => { [0, 0], ]); }); + it('providing valid out', () => { const img = new Image(1, 2); const out = new Mask(1, 2); const output = imageToOutputMask(img, { out }); + expect(output).toBe(out); }); + it('providing invalid out', () => { const img = new Image(1, 2); const out = new Mask(2, 2); + expect(() => { imageToOutputMask(img, { out }); }).toThrow( /cannot use out image. Its width property must be 1. Received 2/, ); }); + it('should throw if out is not a mask', () => { const img = new Image(1, 2); + // @ts-expect-error: testing JS problem expect(() => imageToOutputMask(img, { out: 'str' })).toThrow( 'out must be a Mask', ); }); + it('should keep source origin', () => { const img = new Image(1, 2); const output = imageToOutputMask(img); + expect(output.origin).toStrictEqual(img.origin); }); }); @@ -205,6 +237,7 @@ describe('maskToOutputMask', () => { it('should default to creating an empty mask', () => { const mask = new Mask(2, 2); const output = maskToOutputMask(mask); + expect(output).toMatchObject({ width: 2, height: 2, @@ -216,28 +249,35 @@ describe('maskToOutputMask', () => { [0, 0], ]); }); + it('providing valid out', () => { const mask = new Mask(1, 2); const out = new Mask(1, 2); const output = maskToOutputMask(mask, { out }); + expect(output).toBe(out); }); + it('providing invalid out', () => { const mask = new Mask(1, 2); const out = new Mask(2, 2); + expect(() => { maskToOutputMask(mask, { out }); }).toThrow( /cannot use out image. Its width property must be 1. Received 2/, ); }); + it('should throw if out is not a mask', () => { const mask = new Mask(1, 2); + // @ts-expect-error: testing JS problem expect(() => maskToOutputMask(mask, { out: 'str' })).toThrow( 'out must be a Mask', ); }); + it('should clone data to out', () => { const img = testUtils.createMask([ [0, 1], @@ -249,9 +289,11 @@ describe('maskToOutputMask', () => { [0, 0], ]); const output = maskToOutputMask(img, { out }, { clone: true }); + expect(out).toBe(output); expect(out).toMatchMask(img); }); + it('should clone img to undefined out', () => { const img = testUtils.createMask([ [0, 1], @@ -259,14 +301,18 @@ describe('maskToOutputMask', () => { ]); const output = maskToOutputMask(img, {}, { clone: true }); + expect(output).toMatchMask(img); }); + it('should keep source origin', () => { const mask = new Mask(2, 2, { origin: { row: 1, column: 2 } }); let output = maskToOutputMask(mask, {}, { clone: true }); + expect(output.origin).toStrictEqual(mask.origin); output = maskToOutputMask(mask); + expect(output.origin).toStrictEqual(mask.origin); }); }); diff --git a/src/utils/__tests__/interpolateBorder.test.ts b/src/utils/__tests__/interpolateBorder.test.ts index 3ffac2555..d278c81e7 100644 --- a/src/utils/__tests__/interpolateBorder.test.ts +++ b/src/utils/__tests__/interpolateBorder.test.ts @@ -1,11 +1,13 @@ +import { expect, test } from 'vitest'; + import { Image } from '../../Image.js'; import { getBorderInterpolation, interpolateConstantPoint, + interpolateReflect101Point, interpolateReflectPoint, interpolateReplicatePoint, interpolateWrapPoint, - interpolateReflect101Point, } from '../interpolateBorder.js'; test('in range', () => { @@ -19,6 +21,7 @@ test('too far', () => { const image = new Image(10, 10); const interpolate = getBorderInterpolation('reflect', 0); const exp = 'border must be smaller than the original image'; + expect(() => interpolate(-10, 0, 0, image)).toThrow(exp); expect(() => interpolate(19, 0, 0, image)).toThrow(exp); expect(() => interpolate(-110, 0, 0, image)).toThrow(exp); @@ -26,11 +29,11 @@ test('too far', () => { }); test('CONSTANT', () => { - expect(interpolateConstantPoint(-4, 10)).toStrictEqual(-1); + expect(interpolateConstantPoint(-4, 10)).toBe(-1); expect(interpolateConstantPoint(0, 10)).toBe(0); expect(interpolateConstantPoint(1, 10)).toBe(1); - expect(interpolateConstantPoint(-200, 10)).toStrictEqual(-1); - expect(interpolateConstantPoint(200, 10)).toStrictEqual(-1); + expect(interpolateConstantPoint(-200, 10)).toBe(-1); + expect(interpolateConstantPoint(200, 10)).toBe(-1); }); test('REPLICATE - negative', () => { diff --git a/src/utils/__tests__/sampleBackgroundPoints.test.ts b/src/utils/__tests__/sampleBackgroundPoints.test.ts index 86263c7be..48a6d687a 100644 --- a/src/utils/__tests__/sampleBackgroundPoints.test.ts +++ b/src/utils/__tests__/sampleBackgroundPoints.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import { getMaskFromCannyEdge } from '../../operations/getMaskFromCannyEdge.js'; import { sampleBackgroundPoints } from '../sampleBackgroundPoints.js'; @@ -15,7 +17,8 @@ test('basic test', () => { gridWidth: 3, gridHeight: 3, }); - expect(points).toEqual([ + + expect(points).toStrictEqual([ { column: 0, row: 0 }, { column: 1, row: 0 }, { column: 2, row: 0 }, @@ -51,7 +54,8 @@ test('basic test with basic mask', () => { gridWidth: 3, gridHeight: 3, }); - expect(points).toEqual([ + + expect(points).toStrictEqual([ { column: 3, row: 1 }, { column: 5, row: 1 }, { column: 5, row: 3 }, @@ -60,7 +64,7 @@ test('basic test with basic mask', () => { ]); }); -test('basic test with basic mask', () => { +test('basic test with basic mask 2', () => { const image = testUtils.createGreyImage([ [0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0], @@ -76,7 +80,8 @@ test('basic test with basic mask', () => { gridWidth: 3, gridHeight: 3, }); - expect(points).toEqual([ + + expect(points).toStrictEqual([ { column: 1, row: 1 }, { column: 3, row: 1 }, { column: 5, row: 1 }, @@ -91,7 +96,8 @@ test('basic test of default values', () => { ]); const points = sampleBackgroundPoints(image, { gridHeight: 3, gridWidth: 3 }); - expect(points).toEqual([ + + expect(points).toStrictEqual([ { column: 0, row: 0 }, { column: 1, row: 0 }, { column: 2, row: 0 }, @@ -111,6 +117,7 @@ test('throw an error', () => { [0, 0, 0], ]); const mask = getMaskFromCannyEdge(image, { iterations: 0 }); + expect(() => sampleBackgroundPoints(image, { mask, gridWidth: -3, gridHeight: 3 }), ).toThrow(`The grid has bigger width than the image. Grid's width: -3`); diff --git a/src/utils/__tests__/setBlendedPixel.test.ts b/src/utils/__tests__/setBlendedPixel.test.ts index 381596152..9a1d1f8bf 100644 --- a/src/utils/__tests__/setBlendedPixel.test.ts +++ b/src/utils/__tests__/setBlendedPixel.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import { setBlendedPixel } from '../setBlendedPixel.js'; test('GREYA image, default options', () => { @@ -6,6 +8,7 @@ test('GREYA image, default options', () => { [20, 30], ]); setBlendedPixel(image, 0, 1); + expect(image).toMatchImageData([ [50, 255], [0, 255], @@ -15,12 +18,14 @@ test('GREYA image, default options', () => { test('GREYA images: transparent source, opaque target', () => { const image = testUtils.createGreyaImage([[50, 255]]); setBlendedPixel(image, 0, 0, [100, 0]); + expect(image).toMatchImageData([[50, 255]]); }); test('GREYA images: opaque source, transparent target', () => { const image = testUtils.createGreyaImage([[50, 0]]); setBlendedPixel(image, 0, 0, [100, 255]); + expect(image).toMatchImageData([[100, 255]]); }); @@ -31,6 +36,7 @@ test('asymetrical test', () => { [1, 2, 3, 4, 5, 6], ]); setBlendedPixel(image, 2, 0, [0, 125]); + expect(image).toMatchImageData([ [50, 255, 1, 2, 0, 127], [20, 30, 5, 6, 7, 8], @@ -44,6 +50,7 @@ test('2x2 mask, default options', () => { [0, 0], ]); setBlendedPixel(mask, 1, 0); + expect(mask).toMatchMask(mask); }); diff --git a/src/utils/__tests__/setBlendedVisiblePixel.test.ts b/src/utils/__tests__/setBlendedVisiblePixel.test.ts index de39733bf..d8c29b263 100644 --- a/src/utils/__tests__/setBlendedVisiblePixel.test.ts +++ b/src/utils/__tests__/setBlendedVisiblePixel.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import { setBlendedVisiblePixel } from '../setBlendedVisiblePixel.js'; test('GREYA image, default options', () => { @@ -6,6 +8,7 @@ test('GREYA image, default options', () => { [20, 30], ]); setBlendedVisiblePixel(image, 0, 1); + expect(image).toMatchImageData([ [50, 255], [0, 255], @@ -20,6 +23,7 @@ test('GREYA image: set pixel out of bounds', () => { ]; const image = testUtils.createGreyaImage(data); setBlendedVisiblePixel(image, 0, 5, [40, 40]); + expect(image).toMatchImageData(data); }); @@ -31,6 +35,7 @@ test('RGBA image: set pixel out of bounds', () => { ]; const image = testUtils.createGreyaImage(data); setBlendedVisiblePixel(image, 0, 5, [40, 40, 40, 40]); + expect(image).toMatchImageData(data); }); @@ -41,6 +46,7 @@ test('asymetrical test', () => { [1, 2, 3, 4, 5, 6], ]); setBlendedVisiblePixel(image, 2, 0, [0, 125]); + expect(image).toMatchImageData([ [50, 255, 1, 2, 0, 127], [20, 30, 5, 6, 7, 8], diff --git a/src/utils/constants/__tests__/channelLabels.test.ts b/src/utils/constants/__tests__/channelLabels.test.ts index 1cfee45af..4a8616c5e 100644 --- a/src/utils/constants/__tests__/channelLabels.test.ts +++ b/src/utils/constants/__tests__/channelLabels.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import { Image } from '../../../Image.js'; import { channelLabels } from '../channelLabels.js'; import { ImageColorModel } from '../colorModels.js'; @@ -34,6 +36,7 @@ test.each([ test('channelLabels through image colorModel', () => { const image = new Image(2, 2); + expect(channelLabels[image.colorModel]).toStrictEqual([ 'Red', 'Green', diff --git a/src/utils/geometry/__tests__/angles.test.ts b/src/utils/geometry/__tests__/angles.test.ts index bcbe74692..44a9f2589 100644 --- a/src/utils/geometry/__tests__/angles.test.ts +++ b/src/utils/geometry/__tests__/angles.test.ts @@ -1,3 +1,5 @@ +import { describe, expect, it, test } from 'vitest'; + import { toDegrees } from '../angles.js'; import { rotate } from '../points.js'; @@ -19,6 +21,7 @@ describe('rotate', () => { { column: 0, row: 1 }, ]); }); + it('180 degrees', () => { const points = [ { column: 0, row: 0 }, @@ -32,6 +35,7 @@ describe('rotate', () => { { column: -1, row: 0 }, ]); }); + it('360 degrees', () => { const points = [ { column: 0, row: 0 }, @@ -45,6 +49,7 @@ describe('rotate', () => { { column: 1, row: 0 }, ]); }); + it('-90 degrees', () => { const points = [ { column: 0, row: 0 }, @@ -58,6 +63,7 @@ describe('rotate', () => { { column: 0, row: -1 }, ]); }); + it('45 degrees', () => { const points = [ { column: 0, row: 0 }, @@ -71,6 +77,7 @@ describe('rotate', () => { { column: 1 / Math.sqrt(2), row: 1 / Math.sqrt(2) }, ]); }); + it('rotate small square 45 degrees', () => { const points = [ { column: 0, row: 0 }, @@ -88,6 +95,7 @@ describe('rotate', () => { { column: -1 / Math.sqrt(2), row: 1 / Math.sqrt(2) }, ]); }); + it('rotate small square 90 degrees', () => { const points = [ { column: 0, row: 0 }, @@ -97,6 +105,7 @@ describe('rotate', () => { ]; const result = rotate(Math.PI / 2, points); + expect(result).toBeDeepCloseTo([ { column: 0, row: 0 }, { column: 0, row: 1 }, @@ -104,6 +113,7 @@ describe('rotate', () => { { column: -1, row: 0 }, ]); }); + it('rotate small square 135 degrees', () => { const points = [ { column: 0, row: 0 }, @@ -113,6 +123,7 @@ describe('rotate', () => { ]; const result = rotate((3 * Math.PI) / 4, points); + expect(result).toBeDeepCloseTo([ { column: 0, row: 0 }, { column: -1 / Math.sqrt(2), row: 1 / Math.sqrt(2) }, @@ -245,6 +256,7 @@ describe('rotate', () => { }, ])('real data ($message)', (data) => { const result = rotate(data.minSurfaceAngle, data.mbr); + expect(result).toBeDeepCloseTo(data.expected); }); }); diff --git a/src/utils/geometry/__tests__/getCirclePoints.test.ts b/src/utils/geometry/__tests__/getCirclePoints.test.ts index 609922646..98644ff7f 100644 --- a/src/utils/geometry/__tests__/getCirclePoints.test.ts +++ b/src/utils/geometry/__tests__/getCirclePoints.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import { Image } from '../../../Image.js'; import { getCirclePoints, @@ -14,6 +16,7 @@ test('circle with radius 1', () => { { row: -1, column: 0 }, ]); }); + test('circle with radius 2', () => { const expected = [ { row: 0, column: 2 }, @@ -31,6 +34,7 @@ test('circle with radius 2', () => { ]; const result = getCirclePoints(2); + expect(result).toStrictEqual(expected); }); @@ -55,6 +59,7 @@ test('circle with radius 3', () => { ]; const result = getCirclePoints(3); + expect(result).toStrictEqual(expected); }); @@ -80,7 +85,7 @@ test('horizonal line', () => { test('filled circle with radius 1', () => { const points = getFilledCirclePoints(1, { column: 0, row: 0 }); - expect(points.length).toBe(5); + expect(points).toHaveLength(5); expect(points).toStrictEqual([ { row: 0, column: -1 }, { row: -1, column: 0 }, @@ -115,7 +120,7 @@ test('check for points twice in array', () => { const emptyImage = new Image(5, 5, { colorModel: 'GREY' }); const points = getFilledCirclePoints(2, { column: 2, row: 2 }); - expect(points.length).toBe(21); + expect(points).toHaveLength(21); expect( emptyImage.drawPoints(points, { color: [255] }), ).toMatchImageSnapshot(); diff --git a/src/utils/geometry/__tests__/lines.test.ts b/src/utils/geometry/__tests__/lines.test.ts index 0348e320c..75aa81bc6 100644 --- a/src/utils/geometry/__tests__/lines.test.ts +++ b/src/utils/geometry/__tests__/lines.test.ts @@ -1,3 +1,5 @@ +import { describe, expect, it } from 'vitest'; + import { getLineLength } from '../lines.js'; describe('getLineLength', () => { @@ -9,6 +11,7 @@ describe('getLineLength', () => { expect(getLineLength(points[0], points[1])).toBe(0); }); + it('horizontal line', () => { const points = [ { column: 0, row: 0 }, @@ -17,6 +20,7 @@ describe('getLineLength', () => { expect(getLineLength(points[0], points[1])).toBe(10); }); + it('tilted line', () => { const points = [ { column: 0, row: 0 }, diff --git a/src/utils/geometry/__tests__/points.test.ts b/src/utils/geometry/__tests__/points.test.ts index 0280733d3..20ebf75f3 100644 --- a/src/utils/geometry/__tests__/points.test.ts +++ b/src/utils/geometry/__tests__/points.test.ts @@ -1,12 +1,17 @@ +import { describe, expect, it, test } from 'vitest'; + import { normalize, sortByColumnRow } from '../points.js'; describe('normalize', () => { it('simple numbers', () => { const point = { column: 3, row: 4 }; + expect(normalize(point)).toStrictEqual({ column: 3 / 5, row: 4 / 5 }); }); + it('other simple numbers', () => { const point = { column: 6, row: 8 }; + expect(normalize(point)).toStrictEqual({ column: 6 / 10, row: 8 / 10 }); }); }); @@ -21,6 +26,7 @@ test('sort points', () => { { row: -1, column: 0 }, ]; const sorted = sortByColumnRow(points); + expect(sorted).toStrictEqual([ { row: 0, column: -1 }, { row: -1, column: 0 }, diff --git a/src/utils/geometry/__tests__/polygons.test.ts b/src/utils/geometry/__tests__/polygons.test.ts index 9cdc86f64..bb0b53521 100644 --- a/src/utils/geometry/__tests__/polygons.test.ts +++ b/src/utils/geometry/__tests__/polygons.test.ts @@ -1,3 +1,5 @@ +import { describe, expect, it } from 'vitest'; + import { getPolygonArea, getPolygonPerimeter } from '../polygons.js'; describe('getPolygonPerimeter', () => { @@ -76,6 +78,7 @@ describe('getPolygonArea', () => { expect(getPolygonArea(points)).toBe(12); }); + it('other triangle', () => { const points = [ { column: 0, row: 2 }, diff --git a/src/utils/geometry/__tests__/removeClosePoints.test.ts b/src/utils/geometry/__tests__/removeClosePoints.test.ts index 6b927c4c0..2582a9300 100644 --- a/src/utils/geometry/__tests__/removeClosePoints.test.ts +++ b/src/utils/geometry/__tests__/removeClosePoints.test.ts @@ -1,3 +1,5 @@ +import { expect, test } from 'vitest'; + import { getExtrema } from '../../../compute/getExtrema.js'; import { removeClosePoints } from '../removeClosePoints.js'; @@ -22,6 +24,7 @@ test('combine minimum points on 5x5 image', () => { kind: 'minimum', channel: 0, }); + expect(result).toStrictEqual([ { column: 1, row: 4 }, { column: 1, row: 1 }, @@ -70,12 +73,14 @@ test('combine maximum points after getExtrema function', () => { kind: 'maximum', distance: 3, }); + expect(result).toStrictEqual([ { column: 3, row: 5 }, { column: 7, row: 6 }, { column: 2, row: 2 }, ]); }); + test('test error handling', () => { const image = testUtils.createRgbaImage([ [1, 1, 1, 1], @@ -87,6 +92,7 @@ test('test error handling', () => { [1, 1, 1, 1], [1, 5, 6, 1], ]); + expect(() => { const points = getExtrema(image, { kind: 'maximum', diff --git a/test/__tests__/jestMatchers.test.ts b/test/__tests__/jestMatchers.test.ts index 94508e481..6c4a57f0d 100644 --- a/test/__tests__/jestMatchers.test.ts +++ b/test/__tests__/jestMatchers.test.ts @@ -1,20 +1,25 @@ +import { describe, expect, it } from 'vitest'; + import { Mask } from '../../src/Mask.js'; import { Image } from '../../src/index.js'; describe('toMatchImage', () => { it('should load and match', () => { const image1 = testUtils.load('opencv/test.png'); + expect(image1).toMatchImage('opencv/test.png'); }); it('should match identical images', () => { const image1 = new Image(1, 1); const image2 = new Image(1, 1); + expect(image1).toMatchImage(image2); }); it('should throw if the same instance is passed', () => { const image = new Image(1, 1); + expect(() => expect(image).toMatchImage(image)).toThrow( /Expected image instances to be different/, ); @@ -23,24 +28,28 @@ describe('toMatchImage', () => { it('should throw if width is different', () => { const image1 = new Image(1, 1); const image2 = new Image(2, 1); + expect(() => expect(image1).toMatchImage(image2)).toThrow(/width/); }); it('should throw if height is different', () => { const image1 = new Image(1, 1); const image2 = new Image(1, 2); + expect(() => expect(image1).toMatchImage(image2)).toThrow(/height/); }); it('should throw if bit depth is different', () => { const image1 = new Image(1, 1, { bitDepth: 8 }); const image2 = new Image(1, 1, { bitDepth: 16 }); + expect(() => expect(image1).toMatchImage(image2)).toThrow(/bitDepth/); }); it('should throw if color model is different', () => { const image1 = new Image(1, 1, { colorModel: 'GREY' }); const image2 = new Image(1, 1, { colorModel: 'RGB' }); + expect(() => expect(image1).toMatchImage(image2)).toThrow(/color model/); }); @@ -49,15 +58,18 @@ describe('toMatchImage', () => { const image2 = new Image(2, 3); image2.setValue(0, 1, 0, 128); image2.setValue(0, 2, 0, 255); + expect(() => expect(image1).toMatchImage(image2)).toThrow( /Expected pixel at \(0, 1\) to be \[128, 0, 0\], but got \[0, 0, 0\]/, ); }); + it('error range of 1', () => { const received = testUtils.createGreyImage([[1, 2, 3, 4]]); const expected = testUtils.createGreyImage([[1, 2, 3, 50]]); expected.setValue(0, 1, 0, 128); expected.setValue(0, 1, 0, 255); + expect(() => expect(received).toMatchImage(expected, { error: 1 })).toThrow( /Expected value at \(3, 0\) to be in range \[49,51\], but got 4/, ); @@ -70,6 +82,7 @@ describe('toMatchImageData', () => { colorModel: 'GREY', data: Uint8Array.of(1, 2, 3, 4), }); + expect(image).toMatchImageData([ [1, 2], [3, 4], @@ -81,6 +94,7 @@ describe('toMatchImageData', () => { colorModel: 'GREY', data: Uint8Array.of(1, 2, 3, 4), }); + expect(image).toMatchImageData(` 1 2 3 4 @@ -92,18 +106,21 @@ describe('toMatchMask', () => { it('should match identical masks', () => { const mask1 = new Mask(1, 1); const mask2 = new Mask(1, 1); + expect(mask1).toMatchMask(mask2); }); it('should throw if width is different', () => { const mask1 = new Mask(1, 1); const mask2 = new Mask(2, 1); + expect(() => expect(mask1).toMatchMask(mask2)).toThrow(/width/); }); it('should throw if height is different', () => { const mask1 = new Mask(1, 1); const mask2 = new Mask(1, 2); + expect(() => expect(mask1).toMatchMask(mask2)).toThrow(/height/); }); @@ -112,6 +129,7 @@ describe('toMatchMask', () => { const mask2 = new Mask(2, 3); mask2.setBit(0, 1, 1); mask2.setBit(0, 2, 1); + expect(() => expect(mask1).toMatchMask(mask2)).toThrow( 'Expected bit at (0, 1) to be 1, but got 0', ); @@ -123,6 +141,7 @@ describe('toMatchMaskData', () => { const mask = new Mask(2, 2, { data: Uint8Array.of(1, 1, 0, 0), }); + expect(mask).toMatchMaskData([ [1, 1], [0, 0], @@ -133,6 +152,7 @@ describe('toMatchMaskData', () => { const mask = new Mask(2, 2, { data: Uint8Array.of(1, 1, 0, 0), }); + expect(mask).toMatchMaskData(` 1 1 0 0 diff --git a/test/__tests__/testUtils.test.ts b/test/__tests__/testUtils.test.ts index 0cbcaf81b..9343a870d 100644 --- a/test/__tests__/testUtils.test.ts +++ b/test/__tests__/testUtils.test.ts @@ -1,8 +1,11 @@ +import { describe, expect, it } from 'vitest'; + import { Image } from '../../src/index.js'; describe('load', () => { it('should load the image synchronously', () => { const image = testUtils.load('opencv/test.png'); + expect(image).toBeInstanceOf(Image); }); @@ -20,6 +23,7 @@ describe('createGreyImage', () => { [7, 8, 9], [10, 11, 12], ]); + expect(image.width).toBe(3); expect(image.height).toBe(4); expect(image.getPixel(0, 1)).toStrictEqual([4]); @@ -32,6 +36,7 @@ describe('createGreyImage', () => { 7 8 9 10 11 12 `); + expect(image.width).toBe(3); expect(image.height).toBe(4); expect(image.getPixel(0, 1)).toStrictEqual([4]); @@ -41,6 +46,7 @@ describe('createGreyImage', () => { const image = testUtils.createGreyImage([[1, 32768]], { bitDepth: 16, }); + expect(image.bitDepth).toBe(16); expect(image.getValueByIndex(0, 1)).toBe(32768); }); @@ -76,6 +82,7 @@ describe('createRgbImage', () => { [7, 8, 9], [10, 11, 12], ]); + expect(image.width).toBe(1); expect(image.height).toBe(4); expect(image.getPixel(0, 1)).toStrictEqual([4, 5, 6]); @@ -88,6 +95,7 @@ describe('createRgbImage', () => { 7 8 9 10 11 12 `); + expect(image.width).toBe(1); expect(image.height).toBe(4); expect(image.getPixel(0, 1)).toStrictEqual([4, 5, 6]); @@ -97,6 +105,7 @@ describe('createRgbImage', () => { const image = testUtils.createRgbImage([[1, 2, 32768]], { bitDepth: 16, }); + expect(image.bitDepth).toBe(16); expect(image.getPixel(0, 0)).toStrictEqual([1, 2, 32768]); }); @@ -120,6 +129,7 @@ describe('createRgbaImage', () => { [7, 8, 9, 0], [10, 11, 12, 255], ]); + expect(image.width).toBe(1); expect(image.height).toBe(4); expect(image.getPixel(0, 1)).toStrictEqual([4, 5, 6, 128]); @@ -130,6 +140,7 @@ describe('createRgbaImage', () => { 1 2 3 / 255 | 4 5 6 / 128 7 8 9 / 0 | 10 11 12 / 255 `); + expect(image.width).toBe(2); expect(image.height).toBe(2); expect(image.getPixel(1, 0)).toStrictEqual([4, 5, 6, 128]); @@ -139,6 +150,7 @@ describe('createRgbaImage', () => { const image = testUtils.createRgbaImage([[1, 2, 3, 32768]], { bitDepth: 16, }); + expect(image.bitDepth).toBe(16); expect(image.getPixel(0, 0)).toStrictEqual([1, 2, 3, 32768]); }); @@ -161,6 +173,7 @@ describe('createMask', () => { [0, 0, 0], [0, 0, 1], ]); + expect(mask.width).toBe(3); expect(mask.height).toBe(4); expect(mask.getBit(0, 1)).toBe(0); @@ -171,6 +184,7 @@ describe('createMask', () => { 0 0 0 1 0 0 `); + expect(mask.width).toBe(3); expect(mask.height).toBe(2); expect(mask.getBit(0, 1)).toBe(1); @@ -210,6 +224,7 @@ describe('createRoi', () => { ], { allowCorners: true }, ); + expect(roi.width).toBe(3); expect(roi.height).toBe(4); expect(roi.id).toBe(1); @@ -220,6 +235,7 @@ describe('createRoi', () => { 0 0 0 1 0 0 `); + expect(roi.width).toBe(1); expect(roi.height).toBe(1); expect(roi.id).toBe(1); @@ -236,6 +252,7 @@ describe('createRoi', () => { 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 `); + expect(roi.width).toBe(6); expect(roi.height).toBe(6); expect(roi.id).toBe(1); diff --git a/test/jestMatchers.ts b/test/jestMatchers.ts index 4c4560c8f..ed1265b19 100644 --- a/test/jestMatchers.ts +++ b/test/jestMatchers.ts @@ -3,7 +3,7 @@ import type { MatchImageSnapshotOptions } from 'jest-image-snapshot'; import { configureToMatchImageSnapshot } from 'jest-image-snapshot'; import type { Image } from '../src/index.js'; -import { encodePng, Mask } from '../src/index.js'; +import { Mask, encodePng } from '../src/index.js'; import type { TestImagePath } from './TestImagePath.js'; import { createImageFromData } from './createImageFromData.js'; diff --git a/test/testUtils.ts b/test/testUtils.ts index 48485afae..aaf29cb45 100644 --- a/test/testUtils.ts +++ b/test/testUtils.ts @@ -25,7 +25,8 @@ export function getPath(name: TestImagePath): string { * @returns Buffer of the image. */ export function loadBuffer(path: TestImagePath): Uint8Array { - return readFileSync(join(import.meta.dirname, 'img', path)); + const buffer = readFileSync(join(import.meta.dirname, 'img', path)); + return new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength); } /** diff --git a/vitest.config.ts b/vitest.config.ts index ef007ddcf..b62d0d8c7 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -2,7 +2,6 @@ import { defineConfig } from 'vitest/config'; export default defineConfig({ test: { - globals: true, setupFiles: ['./vitest.setup.ts'], testTimeout: 10_000, coverage: {