mirror of
https://github.com/morluto/rea.git
synced 2026-11-10 17:30:32 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e303de5e76 | ||
|
|
8c68fa7e64 |
No files matched your search
@@ -175,6 +175,27 @@ describe("ESP flash layout inventory", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("inventories a zero-byte partition without reporting missing bytes", async () => {
|
||||
const dump = espFlashDump({
|
||||
bootloader: { at: 0, bytes: BOOTLOADER },
|
||||
table: partitionTable([
|
||||
...TWO_OTA_PARTITIONS,
|
||||
{ label: "empty", type: 1, subtype: 0x82, offset: 0xa000, size: 0 },
|
||||
]),
|
||||
});
|
||||
const snapshot = await scanCanonicalArtifactInventory(await writeDump(dump));
|
||||
expect(snapshot.coverage.status).toBe("complete");
|
||||
expect(
|
||||
snapshot.occurrences.find(
|
||||
({ logical_path }) => logical_path === "partitions/empty.bin",
|
||||
),
|
||||
).toMatchObject({
|
||||
declared_size: 0,
|
||||
limitations: ["partitions/empty.bin declares zero bytes."],
|
||||
format_metadata: { flash_address: 0xa000, size: 0 },
|
||||
});
|
||||
});
|
||||
|
||||
describe("ESP flash layout coverage and selection", () => {
|
||||
it("keeps usable partitions beside a truncated and a missing one", async () => {
|
||||
const cut = DUMP.subarray(0, 0x2_8000);
|
||||
|
||||
@@ -272,15 +272,17 @@ const regionEntry = (
|
||||
declaredIntegrity: null,
|
||||
unpacked: false,
|
||||
limitations:
|
||||
region.available === 0
|
||||
? [
|
||||
`${region.path} lies outside the dump: the file holds none of its ${String(region.length)} bytes.`,
|
||||
]
|
||||
: region.available < region.length
|
||||
region.availability === "empty"
|
||||
? [`${region.path} declares zero bytes.`]
|
||||
: region.availability === "missing"
|
||||
? [
|
||||
`${region.path} is truncated: the dump holds ${String(region.available)} of its ${String(region.length)} bytes.`,
|
||||
`${region.path} lies outside the dump: the file holds none of its ${String(region.length)} bytes.`,
|
||||
]
|
||||
: [],
|
||||
: region.availability === "truncated"
|
||||
? [
|
||||
`${region.path} is truncated: the dump holds ${String(region.available)} of its ${String(region.length)} bytes.`,
|
||||
]
|
||||
: [],
|
||||
adapterKey: `esp-flash-image:${region.path}`,
|
||||
...(region.partition === undefined
|
||||
? {}
|
||||
|
||||
@@ -38,6 +38,8 @@ export interface EspFlashRegion {
|
||||
readonly fileOffset: number;
|
||||
/** Bytes of the region the file holds, from `fileOffset`. */
|
||||
readonly available: number;
|
||||
/** An empty declaration has no bytes to be missing from the dump. */
|
||||
readonly availability: "empty" | "missing" | "truncated" | "complete";
|
||||
readonly partition: EspPartition | undefined;
|
||||
}
|
||||
|
||||
@@ -117,12 +119,21 @@ const partitionPaths = (
|
||||
|
||||
const region = (
|
||||
input: EspFlashPlanInput,
|
||||
fields: Omit<EspFlashRegion, "fileOffset" | "available">,
|
||||
fields: Omit<EspFlashRegion, "fileOffset" | "available" | "availability">,
|
||||
): EspFlashRegion => {
|
||||
const fileOffset = fields.flashAddress - input.origin.value;
|
||||
const start = Math.max(0, fileOffset);
|
||||
const end = Math.min(input.fileSize, fileOffset + fields.length);
|
||||
return { ...fields, fileOffset, available: Math.max(0, end - start) };
|
||||
const available = Math.max(0, end - start);
|
||||
const availability =
|
||||
fields.length === 0
|
||||
? "empty"
|
||||
: available === 0
|
||||
? "missing"
|
||||
: available < fields.length
|
||||
? "truncated"
|
||||
: "complete";
|
||||
return { ...fields, fileOffset, available, availability };
|
||||
};
|
||||
|
||||
const rangeText = (address: number, length: number): string =>
|
||||
@@ -211,11 +222,15 @@ export const planEspFlashLayout = (input: EspFlashPlanInput): EspFlashPlan => {
|
||||
limitations.push(
|
||||
`Partition ${name} at ${offsetText(part.offset)} begins before the dump's first byte at flash ${offsetText(input.origin.value)}; it is not read.`,
|
||||
);
|
||||
else if (placed.available === 0)
|
||||
else if (placed.availability === "empty")
|
||||
limitations.push(
|
||||
`Partition ${name} at ${offsetText(part.offset)} declares zero bytes.`,
|
||||
);
|
||||
else if (placed.availability === "missing")
|
||||
limitations.push(
|
||||
`Partition ${name} at ${rangeText(part.offset, part.size)} lies outside the dump, which ends at flash ${offsetText(input.origin.value + input.fileSize)}.`,
|
||||
);
|
||||
else if (placed.available < part.size)
|
||||
else if (placed.availability === "truncated")
|
||||
limitations.push(
|
||||
`Partition ${name} at ${rangeText(part.offset, part.size)} is truncated: the dump holds ${String(placed.available)} of its ${String(part.size)} bytes.`,
|
||||
);
|
||||
@@ -268,6 +283,7 @@ const overlaps = (regions: readonly EspFlashRegion[]): string[] => {
|
||||
// The region reaching furthest so far, so a long one shows every overlap.
|
||||
let furthest: EspFlashRegion | undefined;
|
||||
for (const current of ordered) {
|
||||
if (current.availability === "empty") continue;
|
||||
if (
|
||||
furthest !== undefined &&
|
||||
current.flashAddress < regionEnd(furthest) &&
|
||||
|
||||
@@ -179,6 +179,38 @@ describe("ESP flash layout plans", () => {
|
||||
});
|
||||
|
||||
describe("ESP flash layout overlaps", () => {
|
||||
it.each([
|
||||
["inside another partition", 0xa000],
|
||||
["at the end of the dump", 0x4_0000],
|
||||
])(
|
||||
"retains a zero-byte partition %s as an empty declaration",
|
||||
(_, offset) => {
|
||||
const plan = planEspFlashLayout(
|
||||
input({
|
||||
table: table([
|
||||
{
|
||||
label: "data",
|
||||
type: 1,
|
||||
subtype: 2,
|
||||
offset: 0x9000,
|
||||
size: 0x4000,
|
||||
},
|
||||
{ label: "empty", type: 1, subtype: 0x82, offset, size: 0 },
|
||||
]),
|
||||
}),
|
||||
);
|
||||
expect(plan.regions.at(-1)).toMatchObject({
|
||||
path: "partitions/empty.bin",
|
||||
fileOffset: offset,
|
||||
length: 0,
|
||||
available: 0,
|
||||
});
|
||||
expect(plan.limitations).toEqual([
|
||||
`Partition empty at 0x${offset.toString(16)} declares zero bytes.`,
|
||||
]);
|
||||
},
|
||||
);
|
||||
|
||||
it("reports every region inside a longer one", () => {
|
||||
const plan = planEspFlashLayout(
|
||||
input({
|
||||
|
||||
Reference in new issue
Block a user