wkdhkr/dedupper

View on GitHub
__tests__/services/fs/FileService.test.js

Summary

Maintainability
A
0 mins
Test Coverage
/** @flow */
import path from "path";

import { default as Subject } from "../../../src/services/fs/FileService";
import TestHelper from "../../../src/helpers/TestHelper";
import { STATE_ACCEPTED } from "../../../src/types/FileStates";
import { TYPE_IMAGE } from "../../../src/types/ClassifyTypes";

process.setMaxListeners(0);
jest.setTimeout(15000);
describe(Subject.name, () => {
  let config;

  beforeEach(() => {
    jest.resetModules();
    config = TestHelper.createDummyConfig();
    config.path = TestHelper.sampleFile.image.jpg.default;
    config.cache = false;
    jest.doMock("wait-on", () => (opt, cb) => cb());
    jest.doMock(
      "../../../src/services/fs/contents/PHashService",
      () => class C {}
    );
  });

  const loadSubject = async () =>
    (await import("../../../src/services/fs/FileService")).default;

  it("createSymLink", async () => {
    const symlink = jest.fn().mockImplementation(() => () => Promise.resolve());
    jest.doMock("fs-extra", () => ({
      copyFile: async () => {},
      pathExists: async () => false,
      symlink
    }));
    const FileService = await loadSubject();
    config.dryrun = false;
    const subject = new FileService(config);

    await subject.createSymLink("a", "b");

    expect(symlink).toBeCalledWith(path.resolve("a"), "b");
  });

  it("createSymLink exists", async () => {
    jest.doMock("fs-extra", () => ({
      copyFile: async () => {},
      pathExists: async () => true
    }));
    const FileService = await loadSubject();
    config.dryrun = false;
    const subject = new FileService(config);

    expect(await subject.createSymLink("a", "b")).toBeUndefined();
  });

  it("createSymLink dryrun", async () => {
    const FileService = await loadSubject();
    config.dryrun = true;
    const subject = new FileService(config);

    expect(await subject.createSymLink("a", "b")).toBeUndefined();
  });

  it("unlink dryrun", async () => {
    const FileService = await loadSubject();
    config.dryrun = true;
    const subject = new FileService(config);

    expect(await subject.unlink("a")).toBeUndefined();
  });

  it("unlink", async () => {
    jest.doMock("fs-extra", () => ({
      copyFile: async () => {},
      pathExists: jest
        .fn()
        .mockImplementationOnce(async () => true)
        .mockImplementationOnce(async () => false),
      unlink: () => Promise.resolve()
    }));
    const FileService = await loadSubject();
    config.dryrun = false;
    const subject = new FileService(config);

    expect(await subject.unlink("a")).toBeUndefined();
  });

  it("createDedupperLock", async () => {
    jest.doMock("touch", () => (_, cb) => cb());
    jest.doMock("winattr", () => ({
      set: (a, b, cb) => cb()
    }));
    const FileService = await loadSubject();
    config.dryrun = false;
    const subject = new FileService(config);

    expect(await subject.createDedupperLock("a")).toBeUndefined();
  });

  it("deleteEmptyDirectory", async () => {
    const deleteEmpty = jest
      .fn()
      .mockImplementation((a, b, cb) => cb(null, ["a", "b"]));
    jest.doMock("delete-empty", () => deleteEmpty);
    const FileService = await loadSubject();
    config.dryrun = false;
    const subject = new FileService(config);

    expect(await subject.deleteEmptyDirectory("a")).toBeUndefined();
    expect(deleteEmpty).toHaveBeenCalledTimes(1);
  });

  it("moveToLibrary", async () => {
    const mv = jest.fn().mockImplementation((f, d, cb) => cb());
    jest.doMock("mv", () => mv);
    jest.doMock("fs-extra", () => ({
      copyFile: async () => {},
      pathExists: jest
        .fn()
        .mockImplementationOnce(async () => true)
        .mockImplementationOnce(async () => false),
      lstatSync: () => ({ isDirectory: () => true }),
      stat: () => ({ mtime: new Date(), birthtime: new Date() })
    }));
    const FileService = await loadSubject();
    config.dryrun = false;
    const subject = new FileService(config);

    expect(
      await subject.moveToLibrary(TestHelper.sampleFile.image.jpg.default)
    ).toContain("_1");
    expect(mv).toHaveBeenCalledTimes(1);
  });

  it("moveToLibrary replace", async () => {
    const trash = jest.fn().mockImplementation(() => Promise.resolve());
    const mv = jest.fn().mockImplementation((f, d, cb) => cb());
    jest.doMock("mv", () => mv);
    jest.doMock("trash", () => trash);
    jest.doMock("fs-extra", () => ({
      copyFile: async () => {},
      pathExists: jest
        .fn()
        .mockImplementationOnce(async () => true)
        .mockImplementationOnce(async () => true)
        .mockImplementationOnce(async () => false),
      lstatSync: () => ({ isDirectory: () => true }),
      stat: () => ({ isSymbolicLink: () => false })
    }));
    const FileService = await loadSubject();
    config.dryrun = false;
    const subject = new FileService(config);

    expect(
      await subject.moveToLibrary(TestHelper.sampleFile.image.jpg.default, true)
    ).toBe("__tests__/sample/firefox.jpg");
    expect(trash).toBeCalledWith(
      [path.resolve(TestHelper.sampleFile.image.jpg.default)],
      { glob: false }
    );
    expect(mv).toHaveBeenCalledTimes(1);
  });

  it("moveToLibrary manual", async () => {
    const mv = jest.fn().mockImplementation((f, d, cb) => cb());
    jest.doMock("mv", () => mv);
    const FileService = await loadSubject();
    config.dryrun = false;
    config.manual = true;
    const subject = new FileService(config);

    expect(
      await subject.moveToLibrary(TestHelper.sampleFile.image.jpg.default)
    ).toBe(path.resolve(TestHelper.sampleFile.image.jpg.default));
    expect(mv).toHaveBeenCalledTimes(0);
  });

  it("prepareDir", async () => {
    jest.doMock("fs-extra", () => ({
      copyFile: async () => {},
      lstatSync: () => ({ isDirectory: () => false })
    }));
    const mkdirp = jest.fn().mockImplementation((_, cb) => cb());
    jest.doMock("mkdirp", () => mkdirp);

    const FileService = await loadSubject();
    const subject = new FileService(config);
    const dir = "./hoge/fuga";

    expect(await subject.prepareDir(dir, true)).toBeUndefined();
    expect(mkdirp).toBeCalledWith(dir, expect.any(Function));
  });

  it("prepareDir dryrun", async () => {
    const FileService = await loadSubject();
    config.dryrun = true;
    const subject = new FileService(config);
    const dir = "./hoge/fuga";

    expect(await subject.prepareDir(dir)).toBeUndefined();
  });

  it("delete", async () => {
    const trash = jest.fn().mockImplementation(() => Promise.resolve());
    jest.doMock("trash", () => trash);
    const fs = {
      stat: jest.fn().mockImplementation(() =>
        Promise.resolve({
          isSymbolicLink: () => false
        })
      ),
      copyFile: async () => {},
      pathExists: jest
        .fn()
        .mockImplementationOnce(async () => true)
        .mockImplementationOnce(async () => false)
        .mockImplementationOnce(async () => true)
        .mockImplementationOnce(async () => false)
    };
    jest.doMock("fs-extra", () => fs);

    const FileService = await loadSubject();
    const subject = new FileService(config);
    const src = "/hoge/fuga/foo.txt";

    expect(await subject.delete(src)).toBeUndefined();
    expect(trash).toBeCalledWith([path.resolve(src)], { glob: false });

    expect(await subject.delete()).toBeUndefined();
    expect(trash).toBeCalledWith([subject.getSourcePath()], { glob: false });
  });

  it("delete symbolicLink", async () => {
    const unlink = jest.fn().mockImplementation(() => Promise.resolve());
    const fs = {
      stat: () =>
        Promise.resolve({
          isSymbolicLink: () => true
        }),
      unlink,
      copyFile: async () => {},
      pathExists: jest
        .fn()
        .mockImplementation(async () => true)
        .mockImplementationOnce(async () => true)
        .mockImplementationOnce(async () => false)
    };
    jest.doMock("fs-extra", () => fs);

    config.dryrun = false;

    const FileService = await loadSubject();
    const subject = new FileService(config);
    const src = "/hoge/fuga/foo.txt";

    await subject.delete(src);
    expect(unlink).toBeCalledWith(path.resolve(src));
  });

  it("delete dryrun", async () => {
    const FileService = await loadSubject();
    config.dryrun = true;
    const subject = new FileService(config);
    const src = "/hoge/fuga/foo.txt";
    expect(await subject.delete(src)).toBeUndefined();
  });

  it("rename", async () => {
    const mv = jest.fn().mockImplementation((f, d, cb) => cb());
    jest.doMock("mv", () => mv);
    jest.doMock("fs-extra", () => ({
      copyFile: async () => {},
      access() {},
      stat() {}
    }));

    const FileService = await loadSubject();
    const subject = new FileService(config);
    const src = "/hoge/fuga/foo.txt";
    const dest = src.replace("foo", "bar");

    expect(await subject.rename(src, dest)).toBeUndefined();
    expect(mv).toBeCalledWith(src, dest, expect.any(Function));
    mv.mockClear();

    expect(await subject.rename(dest)).toBeUndefined();
    expect(mv).toBeCalledWith(
      subject.getSourcePath(),
      dest,
      expect.any(Function)
    );
  });

  it("rename dryrun", async () => {
    const FileService = await loadSubject();
    config.dryrun = true;
    const subject = new FileService(config);
    const src = "/hoge/fuga/foo.txt";
    const dest = src.replace("foo", "bar");
    expect(await subject.rename(src, dest)).toBeUndefined();
  });

  it("fillInsertFileInfo", async () => {
    jest.doMock(
      "../../../src/services/fs/contents/ContentsService",
      () =>
        class C {
          calculatePHash = async () => "1234";

          calculateDHash = async () => "345";
        }
    );
    jest.doMock(
      "../../../src/services/fs/FileCacheService",
      () =>
        class C {
          write = async () => {};
        }
    );
    const FileService = await loadSubject();
    const subject = new FileService(config);
    expect(
      await subject.fillInsertFileInfo(({ type: TYPE_IMAGE }: any))
    ).toMatchObject({ p_hash: "1234", d_hash: "345" });
  });

  it("collectFileInfo", async () => {
    const write = jest.fn().mockImplementation(() => Promise.resolve());
    jest.doMock(
      "../../../src/services/fs/FileCacheService",
      () =>
        class C {
          load = async () => null;

          write = write;
        }
    );
    jest.doMock(
      "../../../src/services/fs/contents/ContentsService",
      () =>
        class C {
          calculatePHash = async () => "1234";

          calculateDHash = async () => "4567";

          readInfo = async () => ({
            damaged: false,
            height: 479,
            width: 500,
            hash: "89ab",
            ratio: 1.0438413361169103
          });
        }
    );
    jest.doMock(
      "../../../src/services/fs/AttributeService",
      () =>
        class C {
          getName = async () => "firefox";

          getFileStat = async () => ({
            size: 36189,
            birthtime: new Date("2017-01-01")
          });

          detectClassifyType = () => TYPE_IMAGE;

          getSourcePath = () => path.resolve("__tests__/sample/firefox.jpg");

          getState = () => STATE_ACCEPTED;

          getDestPath = () =>
            "B:\\Image\\2017\\06-01\\__tests__\\sample\\firefox.jpg";
        }
    );
    const FileService = await loadSubject();
    const subject = new FileService(config);
    expect(await subject.collectFileInfo()).toEqual({
      d_hash: "4567",
      from_path: path.resolve("__tests__/sample/firefox.jpg"),
      hash: "89ab",
      height: 479,
      damaged: false,
      name: "firefox",
      p_hash: "1234",
      ratio: 1.0438413361169103,
      size: 36189,
      state: STATE_ACCEPTED,
      timestamp: new Date("2017-01-01").getTime(),
      to_path: "B:\\Image\\2017\\06-01\\__tests__\\sample\\firefox.jpg",
      type: TYPE_IMAGE,
      width: 500
    });
  });

  it("cached collectFileInfo", async () => {
    const write = jest.fn().mockImplementation(() => Promise.resolve());
    jest.doMock(
      "../../../src/services/fs/FileCacheService",
      () =>
        class C {
          load = async () => ({
            type: TYPE_IMAGE,
            d_hash: undefined,
            from_path: "aaa.jpg"
          });

          write = write;
        }
    );
    jest.doMock(
      "../../../src/services/fs/contents/ContentsService",
      () =>
        class C {
          calculateDHash = async () => 1234;
        }
    );
    config.cache = true;
    config.pHash = true;
    const FileService = await loadSubject();
    const subject: FileService = new FileService(config);
    expect(await subject.collectFileInfo()).toMatchObject({
      d_hash: 1234
    });
    expect(write).toBeCalledWith({
      d_hash: 1234,
      from_path: "aaa.jpg",
      type: TYPE_IMAGE
    });
  });

  it("cached collectFileInfo", async () => {
    const write = jest.fn().mockImplementation(() => Promise.resolve());
    jest.doMock(
      "../../../src/services/fs/FileCacheService",
      () =>
        class C {
          load = async () => ({
            type: TYPE_IMAGE,
            d_hash: undefined,
            from_path: "aaa.jpg"
          });

          write = write;
        }
    );
    jest.doMock(
      "../../../src/services/fs/contents/ContentsService",
      () =>
        class C {
          calculateDHash = async () => 1234;
        }
    );
    config.cache = true;
    config.pHash = true;
    const FileService = await loadSubject();
    const subject: FileService = new FileService(config);
    expect(await subject.collectFileInfo()).toMatchObject({
      d_hash: 1234
    });
    expect(write).toBeCalledWith({
      d_hash: 1234,
      from_path: "aaa.jpg",
      type: TYPE_IMAGE
    });
  });
});