Skip to content

Commit

Permalink
fix(FileImageGenerator): avoid icon extraction of already extracted f…
Browse files Browse the repository at this point in the history
…ile paths
  • Loading branch information
oliverschwendener committed Aug 16, 2024
1 parent cc066c0 commit 5283abb
Show file tree
Hide file tree
Showing 2 changed files with 116 additions and 92 deletions.
193 changes: 105 additions & 88 deletions src/main/Core/ImageGenerator/FileImageGenerator.test.ts
Original file line number Diff line number Diff line change
@@ -1,106 +1,123 @@
import type { Image } from "@common/Core/Image";
import { describe, expect, it } from "vitest";
import { describe, expect, it, vi } from "vitest";
import type { FileIconExtractor } from "./FileIconExtractor";
import { FileImageGenerator } from "./FileImageGenerator";

describe(FileImageGenerator, () => {
it("should return the extracted image from the first matching file icon extractor", async () => {
const fileImageGenerator = new FileImageGenerator([
{
matchesFilePath: () => false,
extractFileIcon: async () => <Image>{ url: "test url 1" },
extractFileIcons: async () => <Record<string, Image>>{},
},
{
matchesFilePath: () => false,
extractFileIcon: async () => <Image>{ url: "test url 2" },
extractFileIcons: async () => <Record<string, Image>>{},
},
{
matchesFilePath: () => true,
extractFileIcon: async () => <Image>{ url: "test url 3" },
extractFileIcons: async () => <Record<string, Image>>{},
},
]);
describe(FileImageGenerator.prototype.getImage, () => {
it("should return the extracted image from the first matching file icon extractor", async () => {
const fileImageGenerator = new FileImageGenerator([
{
matchesFilePath: () => false,
extractFileIcon: async () => <Image>{ url: "test url 1" },
extractFileIcons: async () => <Record<string, Image>>{},
},
{
matchesFilePath: () => false,
extractFileIcon: async () => <Image>{ url: "test url 2" },
extractFileIcons: async () => <Record<string, Image>>{},
},
{
matchesFilePath: () => true,
extractFileIcon: async () => <Image>{ url: "test url 3" },
extractFileIcons: async () => <Record<string, Image>>{},
},
]);

expect(await fileImageGenerator.getImage("my file path")).toEqual(<Image>{ url: "test url 3" });
});
expect(await fileImageGenerator.getImage("my file path")).toEqual(<Image>{ url: "test url 3" });
});

it("should throw an error if all file icon extractors don't match the given file path", async () => {
const fileImageGenerator = new FileImageGenerator([
{
matchesFilePath: () => false,
extractFileIcon: async () => <Image>{ url: "test url 1" },
extractFileIcons: async () => <Record<string, Image>>{},
},
{
matchesFilePath: () => false,
extractFileIcon: async () => <Image>{ url: "test url 2" },
extractFileIcons: async () => <Record<string, Image>>{},
},
{
matchesFilePath: () => false,
extractFileIcon: async () => <Image>{ url: "test url 3" },
extractFileIcons: async () => <Record<string, Image>>{},
},
]);

await expect(fileImageGenerator.getImage("my file path")).rejects.toThrowError(
`Failed to extract file icon from path "my file path". Reason: file path did not match any file icon extractor`,
);
it("should throw an error if all file icon extractors don't match the given file path", async () => {
const fileImageGenerator = new FileImageGenerator([
{
matchesFilePath: () => false,
extractFileIcon: async () => <Image>{ url: "test url 1" },
extractFileIcons: async () => <Record<string, Image>>{},
},
{
matchesFilePath: () => false,
extractFileIcon: async () => <Image>{ url: "test url 2" },
extractFileIcons: async () => <Record<string, Image>>{},
},
{
matchesFilePath: () => false,
extractFileIcon: async () => <Image>{ url: "test url 3" },
extractFileIcons: async () => <Record<string, Image>>{},
},
]);

await expect(fileImageGenerator.getImage("my file path")).rejects.toThrowError(
`Failed to extract file icon from path "my file path". Reason: file path did not match any file icon extractor`,
);
});
});

it("should bulk extract file icons", async () => {
const fileImageGenerator = new FileImageGenerator([
{
matchesFilePath: () => false,
describe(FileImageGenerator.prototype.getImages, () => {
it("should bulk extract file icons", async () => {
const extractFileIcons1 = vi.fn().mockResolvedValue({ path1: { url: "test url 1" } });
const extractFileIcons2 = vi.fn().mockResolvedValue({ path2: { url: "test url 2" } });
const extractFileIcons3 = vi.fn().mockResolvedValue({ path3: { url: "test url 3" } });

const fileIconExtractor1 = <FileIconExtractor>{
matchesFilePath: (f) => f.endsWith("1"),
extractFileIcon: async () => <Image>{},
extractFileIcons: async () => <Record<string, Image>>{},
},
{
matchesFilePath: () => false,
extractFileIcons: (f) => extractFileIcons1(f),
};

const fileIconExtractor2 = <FileIconExtractor>{
matchesFilePath: (f) => f.endsWith("2"),
extractFileIcon: async () => <Image>{},
extractFileIcons: async () => <Record<string, Image>>{},
},
{
matchesFilePath: () => true,
extractFileIcons: (f) => extractFileIcons2(f),
};

const fileIconExtractor3 = <FileIconExtractor>{
matchesFilePath: (f) => f.endsWith("3"),
extractFileIcon: async () => <Image>{},
extractFileIcons: async () =>
<Record<string, Image>>{
path1: <Image>{ url: "test url 1" },
path2: <Image>{ url: "test url 2" },
path3: <Image>{ url: "test url 3" },
},
},
]);

expect(await fileImageGenerator.getImages(["path1", "path2", "path3"])).toEqual({
path1: <Image>{ url: "test url 1" },
path2: <Image>{ url: "test url 2" },
path3: <Image>{ url: "test url 3" },
extractFileIcons: (f) => extractFileIcons3(f),
};

const fileImageGenerator = new FileImageGenerator([
fileIconExtractor1,
fileIconExtractor2,
fileIconExtractor3,
]);

expect(await fileImageGenerator.getImages(["path1", "path2", "path3"])).toEqual({
path1: { url: "test url 1" },
path2: { url: "test url 2" },
path3: { url: "test url 3" },
});

expect(extractFileIcons1).toHaveBeenCalledWith(["path1"]);
expect(extractFileIcons2).toHaveBeenCalledWith(["path2"]);
expect(extractFileIcons3).toHaveBeenCalledWith(["path3"]);
});
});

it("should throw an error when no file image extractor matches all given file paths", async () => {
const fileImageGenerator = new FileImageGenerator([
{
matchesFilePath: () => false,
extractFileIcon: async () => <Image>{},
extractFileIcons: async () => <Record<string, Image>>{},
},
{
matchesFilePath: () => false,
it("should prioritize the first matching file icon extractor", async () => {
const extractFileIcons1 = vi.fn().mockResolvedValue({ path1: { url: "url1" } });
const extractFileIcons2 = vi.fn().mockResolvedValue({ path2: { url: "url2" } });

const fileIconExtractor1 = <FileIconExtractor>{
matchesFilePath: (f) => f.endsWith("1"),
extractFileIcon: async () => <Image>{},
extractFileIcons: async () => <Record<string, Image>>{},
},
{
matchesFilePath: () => false,
extractFileIcons: (f) => extractFileIcons1(f),
};

const fileIconExtractor2 = <FileIconExtractor>{
matchesFilePath: () => true,
extractFileIcon: async () => <Image>{},
extractFileIcons: async () => <Record<string, Image>>{},
},
]);
extractFileIcons: (f) => extractFileIcons2(f),
};

await expect(fileImageGenerator.getImages(["path1", "path2", "path3"])).rejects.toThrowError(
"Failed to extract file icons. Reason: file paths did not match any file icon extractor",
);
expect(
await new FileImageGenerator([fileIconExtractor1, fileIconExtractor2]).getImages(["path1", "path2"]),
).toEqual({
path1: <Image>{ url: "url1" },
path2: <Image>{ url: "url2" },
});

expect(extractFileIcons1).toHaveBeenCalledWith(["path1"]);
expect(extractFileIcons2).toHaveBeenCalledWith(["path2"]);
});
});
});
15 changes: 11 additions & 4 deletions src/main/Core/ImageGenerator/FileImageGenerator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,19 @@ export class FileImageGenerator implements FileImageGeneratorInterface {
}

public async getImages(filePaths: string[]): Promise<Record<string, Image>> {
let result: Record<string, Image> = {};

for (const fileIconExtractor of this.fileIconExtractors) {
if (filePaths.every((filePath) => fileIconExtractor.matchesFilePath(filePath))) {
return await fileIconExtractor.extractFileIcons(filePaths);
}
const matchingFilePaths = filePaths.filter(
(filePath) => !Object.keys(result).includes(filePath) && fileIconExtractor.matchesFilePath(filePath),
);

result = {
...result,
...(await fileIconExtractor.extractFileIcons(matchingFilePaths)),
};
}

throw new Error(`Failed to extract file icons. Reason: file paths did not match any file icon extractor`);
return result;
}
}

0 comments on commit 5283abb

Please sign in to comment.