import { open, writeFile } from "node:fs/promises"; import { join } from "node:path"; import { expect, it, vi } from "vitest"; import { readElfBuildIds } from "../../../src/flutter/ElfBuildId.js"; import { elfNote, elfNoteFixture, } from "../../../src/native/elf/ElfNotes.fixture.js"; import { appendElfRanges, engineFixtureImage, } from "../../../src/flutter/FlutterBuild.fixture.js"; import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js"; const note = Buffer.from( "040000000800000003000000474e55000123456789abcdef", "hex", ); it.each([32, 64] as const)( "reads aligned consecutive notes in ELF%d", async (bits) => { for (const alignment of [4, 8]) { for (const table of ["program", "section", "both"] as const) { const ids = ["11".repeat(20), "22".repeat(20)]; const image = elfNoteFixture({ bits, alignment, ownership: table === "program" ? "program" : "both", notes: Buffer.concat( ids.map((id) => elfNote("GNU", 3, Buffer.from(id, "hex"), true, alignment), ), ), }); if (table === "section") image.writeUInt32LE(1, bits === 64 ? 64 : 52); const root = await createTestTempDirectory("rea-flutter-alignment-"); const path = join(root, "engine.so"); await writeFile(path, image); const file = await open(path, "r"); try { expect( await readElfBuildIds(file, image.length, undefined), `${bits}/${table}/${alignment}`, ).toEqual({ candidates: ids, failures: [] }); } finally { await file.close(); } } } }, ); it.each( ([32, 64] as const).flatMap((bits) => [ { bits, program: 8, section: 4, reads: 5 }, { bits, program: 1, section: 4, reads: 4 }, ]), )( "keys shared $bits-bit note ranges by effective alignment (p_align $program, sh_addralign $section)", async ({ bits, program, section, reads }) => { // 24-byte IDs pad identically at four and eight bytes, so only the range // key decides whether the second declaration is read. const ids = ["11".repeat(24), "22".repeat(24)]; const image = elfNoteFixture({ bits, alignment: 4, ownership: "both", notes: Buffer.concat( ids.map((id) => elfNote("GNU", 3, Buffer.from(id, "hex"))), ), }); const header = bits === 64 ? 64 : 52; const noteSection = header + (bits === 64 ? 56 : 32) + (bits === 64 ? 64 : 40); const writeAlignment = (offset: number, value: number) => { if (bits === 64) image.writeBigUInt64LE(BigInt(value), offset); else image.writeUInt32LE(value, offset); }; writeAlignment(header + (bits === 64 ? 48 : 28), program); writeAlignment(noteSection + (bits === 64 ? 48 : 32), section); const root = await createTestTempDirectory("rea-flutter-alignment-"); const path = join(root, "engine.so"); await writeFile(path, image); const file = await open(path, "r"); const read = vi.spyOn(file, "read"); try { expect(await readElfBuildIds(file, image.length, undefined)).toEqual({ candidates: ids, failures: [], }); // Header prefix, both tables, then one read per distinct note range. expect(read.mock.calls.length).toBe(reads); } finally { await file.close(); } }, ); it.each([ { bits: 32, table: "program" }, { bits: 64, table: "section" }, ] as const)( "bounds dense $bits-bit $table note ranges while retaining examined IDs", async ({ bits, table }) => { const count = 30_000; const image = appendElfRanges( engineFixtureImage({ bits, notes: Buffer.concat([note, Buffer.alloc(count)]), ownership: "both", }), table, Array.from({ length: count }, (_, index) => ({ type: table === "program" ? 4 : 7, offset: 0x400 + note.length + index, size: 1, })), ); const root = await createTestTempDirectory("rea-flutter-notes-"); const path = join(root, "engine.so"); await writeFile(path, image); const file = await open(path, "r"); const read = vi.spyOn(file, "read"); try { const result = await readElfBuildIds(file, image.length, undefined); expect(result.candidates).toEqual(["0123456789abcdef"]); expect(result.failures).toContainEqual({ reason: expect.stringContaining("note-range"), }); expect(read.mock.calls.length).toBeLessThanOrEqual(1027); } finally { await file.close(); } }, ); it("deduplicates shared program/section notes and skips empty ranges before charging inventory", async () => { const ranges = Array.from({ length: 2000 }, (_, index) => ({ type: 7, offset: index % 2 === 0 ? 0x400 : index, size: index % 2 === 0 ? note.length : 0, })); const image = appendElfRanges( engineFixtureImage({ notes: note, ownership: "both" }), "section", ranges, ); const root = await createTestTempDirectory("rea-flutter-notes-"); const path = join(root, "engine.so"); await writeFile(path, image); const file = await open(path, "r"); const read = vi.spyOn(file, "read"); try { expect(await readElfBuildIds(file, image.length, undefined)).toEqual({ candidates: ["0123456789abcdef"], failures: [], }); expect(read.mock.calls.length).toBe(4); } finally { await file.close(); } });