UNPKG

wasm4

Version:

Build retro games using WebAssembly for a fantasy console.

223 lines (204 loc) 7.48 kB
const fs = require("fs"); const { run, runAll } = require("../png2src"); function convertHexArrayToString(hexArray, prefix, separator) { return hexArray.map(hex => `${prefix}${hex.toString(16).padStart(2, '0')}`).join(separator); } describe("PNG2SRC", () => { describe("run function", () => { const testCases = [ { title: "Two-color sprite - 8x8", filePath: __dirname + "/data/smile_8x8_1BPP.png", expectedBytes: [ 0b11000011, 0b10000001, 0b00100100, 0b00100100, 0b00000000, 0b00100100, 0b10011001, 0b11000011, ], height: 8, width: 8, flags: 0, flagsHumanReadable: "BLIT_1BPP", bpp: 1, name: "smile_8x8_1BPP", rustName: "SMILE_8X8_1_B_P_P", odinName: "smile_8x8_1_b_p_p", odinFlags: "nil" }, { title: "Four-color sprite - 8x8", filePath: __dirname + "/data/smile_8x8_2BPP.png", expectedBytes: [ 0b11110000, 0b00001111, 0b11000000, 0b00000011, 0b00000100, 0b00010000, 0b00000100, 0b00010000, 0b00000000, 0b00000000, 0b00001000, 0b00100000, 0b11000010, 0b10000011, 0b11110000, 0b00001111, ], height: 8, width: 8, flags: 1, flagsHumanReadable: "BLIT_2BPP", bpp: 2, name: "smile_8x8_2BPP", rustName: "SMILE_8X8_2_B_P_P", odinName: "smile_8x8_2_b_p_p", odinFlags: "{ .USE_2BPP }" }, { title: "bunny sprite", filePath: __dirname + "/../../../site/static/img/bunny.png", expectedBytes: [ 0xaa, 0x9e, 0xac, 0xaa, 0xaa, 0x57, 0xbf, 0x2a, 0xaa, 0x57, 0xbf, 0x2a, 0xaa, 0x17, 0xbf, 0x2a, 0xaa, 0x17, 0x03, 0x2a, 0xaa, 0x57, 0x54, 0x2a, 0xa8, 0x55, 0x55, 0x6a, 0xa9, 0x55, 0x05, 0x0a, 0xaf, 0xd5, 0x55, 0x4a, 0xa8, 0x75, 0x55, 0x4a, 0xaa, 0xd5, 0x57, 0x2a, 0xaa, 0x1d, 0x7c, 0xaa, 0xa8, 0x75, 0x15, 0x2a, 0xa8, 0x45, 0x15, 0x2a, 0xaa, 0x10, 0x54, 0xaa, 0xaa, 0x85, 0x52, 0xaa ], height: 16, width: 16, flags: 1, flagsHumanReadable: "BLIT_2BPP", bpp: 2, name: "bunny", rustName: "BUNNY", odinName: "bunny", odinFlags: "{ .USE_2BPP }" }, { title: "Two-color sprite - 7x7 - with a width not dividable by eight", filePath: __dirname + "/data/smile_7x7_1BPP.png", expectedBytes: [0xc7, 0x75, 0x53, 0xe4, 0x57, 0x71, 0x80], height: 7, width: 7, flags: 0, flagsHumanReadable: "BLIT_1BPP", bpp: 1, name: "smile_7x7_1BPP", rustName: "SMILE_7X7_1_B_P_P", odinName: "smile_7x7_1_b_p_p", odinFlags: "nil" }, { title: "Four-color sprite - 7x7 - with a width not dividable by eight", filePath: __dirname + "/data/smile_7x7_2BPP.png", expectedBytes: [0xf0, 0x3f, 0x15, 0x31, 0x99, 0x05, 0x54, 0x1a, 0x93, 0x15, 0x3f, 0x03, 0xc0], height: 7, width: 7, flags: 1, flagsHumanReadable: "BLIT_2BPP", bpp: 2, name: "smile_7x7_2BPP", rustName: "SMILE_7X7_2_B_P_P", odinName: "smile_7x7_2_b_p_p", odinFlags: "{ .USE_2BPP }" }, ]; testCases.forEach(testCase => { it(`should handle ${testCase.title} correctly`, () => { const result = run(testCase.filePath); expect(result.height).toBe(testCase.height); expect(result.width).toBe(testCase.width); expect(result.flags).toBe(testCase.flags); expect(result.flagsHumanReadable).toBe(testCase.flagsHumanReadable); expect(result.bpp).toBe(testCase.bpp); expect(result.name).toBe(testCase.name); expect(result.rustName).toBe(testCase.rustName); expect(result.odinName).toBe(testCase.odinName); expect(result.odinFlags).toBe(testCase.odinFlags); expect(result.length).toBe(testCase.expectedBytes.length); expect(result.bytes).toBe(convertHexArrayToString(testCase.expectedBytes, "0x", ',')); expect(result.charBytes).toBe(convertHexArrayToString(testCase.expectedBytes, "\\x", '')); expect(result.firstByte).toBe(convertHexArrayToString([testCase.expectedBytes[0]], "0x", ',')); expect(result.restBytes).toBe(convertHexArrayToString(testCase.expectedBytes.slice(1), "0x", ',')); expect(result.wasmBytes).toBe(convertHexArrayToString(testCase.expectedBytes, "\\", '')); expect(result.porthBytes).toBe(convertHexArrayToString(testCase.expectedBytes, "\\\\", '')); }); }); it("should throw an error for too many colors", () => { const pngPath = __dirname + "/data/smile_8x8_5colors.png"; expect(() => run(pngPath)).toThrowError(/Too many colors:/); }); }); }); describe("PNG2SRC", () => { describe("runAll function", () => { beforeEach(() => { // Replace console functions with a spy jest.spyOn(console, 'error').mockImplementation(() => { }); jest.spyOn(console, 'log').mockImplementation(() => { }); jest.spyOn(fs, 'writeFileSync').mockReset(); }); afterEach(() => { // Restore originals after tests jest.restoreAllMocks(); }); it("should throw an error for invalid template path", () => { expect(() => runAll([__dirname + "/data/smile_8x8_1BPP.png"], { template: "/invalid/path", lang: "rust", output: "-", }) ).toThrow(/ENOENT: no such file or directory/); }); it("should abort and output an error message for invalid image paths", () => { expect(() => runAll(["/invalid/path"], { lang: "rust", output: "-", })).toThrowError(/Error processing \/invalid\/path: ENOENT: no such file or directory, open '\/invalid\/path'/); }); it("should console log one sprite", () => { runAll([__dirname + "/data/smile_8x8_1BPP.png"], { lang: "c", output: "-", }); expect(console.log).toHaveBeenCalledWith( "// smile_8x8_1BPP\n" + "#define smile_8x8_1BPPWidth 8\n" + "#define smile_8x8_1BPPHeight 8\n" + "#define smile_8x8_1BPPFlags BLIT_1BPP\n" + "const uint8_t smile_8x8_1BPP[8] = { 0xc3,0x81,0x24,0x24,0x00,0x24,0x99,0xc3 };\n\n"); }); it("should write one sprite", () => { runAll([__dirname + "/data/smile_8x8_1BPP.png"], { lang: "c", output: "output.h", }); expect(fs.writeFileSync).toHaveBeenCalledWith('output.h', "// smile_8x8_1BPP\n" + "#define smile_8x8_1BPPWidth 8\n" + "#define smile_8x8_1BPPHeight 8\n" + "#define smile_8x8_1BPPFlags BLIT_1BPP\n" + "const uint8_t smile_8x8_1BPP[8] = { 0xc3,0x81,0x24,0x24,0x00,0x24,0x99,0xc3 };\n\n" ); }); it("should write multiple sprites", () => { runAll( [ __dirname + "/data/smile_8x8_1BPP.png", __dirname + "/data/smile_8x8_2BPP.png", __dirname + "/data/smile_7x7_1BPP.png", __dirname + "/data/smile_7x7_2BPP.png", ], { lang: "c", output: "output.h", } ); expect(console.log).toHaveBeenCalledTimes(3); expect(fs.writeFileSync).toHaveBeenCalledTimes(1); }); }); });