files --collection, get, get-thumb and helper fix-missing-thumbnails --file must refuse 0x10, 1e3, 1.5, -1, an empty string, abc and an integer past Number.MAX_SAFE_INTEGER with one line naming the argument, and exit 1 before any request. A good ID goes on to the server. The commands run on a real client over a fake Ente server holding an empty account. The two older tests of a non-numeric ID are folded into these. Model: opus-5-5
This commit is contained in:
+127
-11
@@ -511,11 +511,6 @@ describe("files", () => {
|
|||||||
expect(await filesCommand(context(), { collection: "9" })).toBe(1);
|
expect(await filesCommand(context(), { collection: "9" })).toBe(1);
|
||||||
expect(stderr.text).toBe("Collection 9 not found\n");
|
expect(stderr.text).toBe("Collection 9 not found\n");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("exits 1 for a collection ID that is not a number", async () => {
|
|
||||||
expect(await filesCommand(context(), { collection: "abc" })).toBe(1);
|
|
||||||
expect(stderr.text).toBe("Invalid collection ID\n");
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("get and get-thumb", () => {
|
describe("get and get-thumb", () => {
|
||||||
@@ -546,12 +541,6 @@ describe("get and get-thumb", () => {
|
|||||||
expect(stderr.text).toBe("File 999 not found\n");
|
expect(stderr.text).toBe("File 999 not found\n");
|
||||||
expect(existsSync(out)).toBe(false);
|
expect(existsSync(out)).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("both exit 1 for a file ID that is not a number", async () => {
|
|
||||||
expect(await getCommand(context(), "abc", {})).toBe(1);
|
|
||||||
expect(await getThumbCommand(context(), "abc", {})).toBe(1);
|
|
||||||
expect(stderr.text).toBe("Invalid file ID\nInvalid file ID\n");
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// A live photo, which Ente stores as one ZIP, is written as its image and its
|
// A live photo, which Ente stores as one ZIP, is written as its image and its
|
||||||
@@ -1035,3 +1024,130 @@ describe("backup-metadata and the thumbnail helpers refresh first", () => {
|
|||||||
expect(stdout.text).toBe("");
|
expect(stdout.text).toBe("");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// `files --collection`, `get`, `get-thumb` and `helper fix-missing-thumbnails
|
||||||
|
// --file` take an ID only when it is written in decimal digits and is a safe
|
||||||
|
// integer. `Number()` alone reads `0x10` as 16, `1e3` as 1000 and an empty
|
||||||
|
// string as 0, so the command would act on a file the user never named.
|
||||||
|
// Anything else is refused with one line naming it, and exit 1, before any
|
||||||
|
// request.
|
||||||
|
//
|
||||||
|
// These run on a real client, read back from a saved session, over a fake Ente
|
||||||
|
// server holding an empty account, which records each request it receives. With
|
||||||
|
// a good ID the command goes on to ask the server, and finds nothing there.
|
||||||
|
describe("an ID given on the command line", () => {
|
||||||
|
const NOT_IDS = [
|
||||||
|
"0x10",
|
||||||
|
"1e3",
|
||||||
|
"1.5",
|
||||||
|
"-1",
|
||||||
|
"",
|
||||||
|
"abc",
|
||||||
|
// One past Number.MAX_SAFE_INTEGER: from here on a number cannot
|
||||||
|
// hold every integer, so two IDs could read as one.
|
||||||
|
"9007199254740992",
|
||||||
|
];
|
||||||
|
|
||||||
|
const requests: Request[] = [];
|
||||||
|
|
||||||
|
const emptyAccount = (): CliContext => {
|
||||||
|
const ctx = context();
|
||||||
|
const key = toBase64(new Uint8Array(32));
|
||||||
|
saveSession(ctx.sessionDir, {
|
||||||
|
email: "cli@example.com",
|
||||||
|
userID: USER_ID,
|
||||||
|
token: "token",
|
||||||
|
masterKey: key,
|
||||||
|
secretKey: key,
|
||||||
|
publicKey: key,
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
...ctx,
|
||||||
|
loadSession: (path) =>
|
||||||
|
loadSession(path, {
|
||||||
|
fetch: async (url, init) => {
|
||||||
|
requests.push(new Request(url, init));
|
||||||
|
return new Response(
|
||||||
|
JSON.stringify({ collections: [] }),
|
||||||
|
{ headers: { "content-type": "application/json" } },
|
||||||
|
);
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
requests.length = 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
it("files looks up a decimal collection ID", async () => {
|
||||||
|
const ctx = emptyAccount();
|
||||||
|
expect(await filesCommand(ctx, { collection: "1" })).toBe(1);
|
||||||
|
expect(stderr.text).toBe("Collection 1 not found\n");
|
||||||
|
expect(requests).not.toHaveLength(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it.each(NOT_IDS)(
|
||||||
|
"files refuses --collection %j before any request",
|
||||||
|
async (arg) => {
|
||||||
|
const ctx = emptyAccount();
|
||||||
|
expect(await filesCommand(ctx, { collection: arg })).toBe(1);
|
||||||
|
expect(stderr.text).toBe(`Invalid collection ID: ${arg}\n`);
|
||||||
|
expect(stdout.text).toBe("");
|
||||||
|
expect(requests).toHaveLength(0);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
it("get looks up a decimal file ID", async () => {
|
||||||
|
expect(await getCommand(emptyAccount(), "100", {})).toBe(1);
|
||||||
|
expect(stderr.text).toBe("File 100 not found\n");
|
||||||
|
expect(requests).not.toHaveLength(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it.each(NOT_IDS)("get refuses %j before any request", async (arg) => {
|
||||||
|
expect(await getCommand(emptyAccount(), arg, {})).toBe(1);
|
||||||
|
expect(stderr.text).toBe(`Invalid file ID: ${arg}\n`);
|
||||||
|
expect(stdout.text).toBe("");
|
||||||
|
expect(requests).toHaveLength(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("get-thumb looks up a decimal file ID", async () => {
|
||||||
|
expect(await getThumbCommand(emptyAccount(), "100", {})).toBe(1);
|
||||||
|
expect(stderr.text).toBe("File 100 not found\n");
|
||||||
|
expect(requests).not.toHaveLength(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it.each(NOT_IDS)("get-thumb refuses %j before any request", async (arg) => {
|
||||||
|
expect(await getThumbCommand(emptyAccount(), arg, {})).toBe(1);
|
||||||
|
expect(stderr.text).toBe(`Invalid file ID: ${arg}\n`);
|
||||||
|
expect(stdout.text).toBe("");
|
||||||
|
expect(requests).toHaveLength(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
// The fixer reports each file it was given; on this account neither is
|
||||||
|
// found, which is a failure, so it exits 1.
|
||||||
|
it("fix-missing-thumbnails looks up each decimal --file ID", async () => {
|
||||||
|
const ctx = emptyAccount();
|
||||||
|
const opts = { file: ["100", "200"], json: true };
|
||||||
|
expect(await fixMissingThumbnailsCommand(ctx, opts)).toBe(1);
|
||||||
|
expect(JSON.parse(stdout.text)).toMatchObject([
|
||||||
|
{ fileID: 100, reason: "file not found in any collection" },
|
||||||
|
{ fileID: 200, reason: "file not found in any collection" },
|
||||||
|
]);
|
||||||
|
expect(requests).not.toHaveLength(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
// One bad ID fails the whole command, so the good one before it is not
|
||||||
|
// fixed either.
|
||||||
|
it.each(NOT_IDS)(
|
||||||
|
"fix-missing-thumbnails refuses --file 100 %j before any request",
|
||||||
|
async (arg) => {
|
||||||
|
const ctx = emptyAccount();
|
||||||
|
const opts = { file: ["100", arg] };
|
||||||
|
expect(await fixMissingThumbnailsCommand(ctx, opts)).toBe(1);
|
||||||
|
expect(stderr.text).toBe(`Invalid file ID: ${arg}\n`);
|
||||||
|
expect(stdout.text).toBe("");
|
||||||
|
expect(requests).toHaveLength(0);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user