fix(storage): adapt timestamp guard to current Commonlib

Use the packaged Commonlib type import and add regression coverage for every Obsidian vault and storage write method. Verify that fractional timestamps are floored without mutating caller-owned options.
This commit is contained in:
vorotamoroz
2026-08-09 08:46:21 +00:00
parent 00de35e5d4
commit 21d904cfd6
3 changed files with 64 additions and 2 deletions
@@ -0,0 +1,32 @@
import { describe, expect, it, vi } from "vitest";
import type { App } from "obsidian";
import { ObsidianStorageAdapter } from "./ObsidianStorageAdapter";
describe("ObsidianStorageAdapter", () => {
it("floors write-option timestamps before calling Obsidian storage methods", async () => {
const write = vi.fn().mockResolvedValue(undefined);
const writeBinary = vi.fn().mockResolvedValue(undefined);
const append = vi.fn().mockResolvedValue(undefined);
const app = {
vault: {
adapter: {
write,
writeBinary,
append,
},
},
} as unknown as App;
const adapter = new ObsidianStorageAdapter(app);
const options = { ctime: 1778511180024.462, mtime: 1778511180999.913 };
const expectedOptions = { ctime: 1778511180024, mtime: 1778511180999 };
await adapter.write("note.md", "text", options);
await adapter.writeBinary("image.bin", new ArrayBuffer(0), options);
await adapter.append("log.md", "text", options);
expect(write).toHaveBeenCalledWith("note.md", "text", expectedOptions);
expect(writeBinary).toHaveBeenCalledWith("image.bin", expect.any(ArrayBuffer), expectedOptions);
expect(append).toHaveBeenCalledWith("log.md", "text", expectedOptions);
expect(options).toEqual({ ctime: 1778511180024.462, mtime: 1778511180999.913 });
});
});
@@ -2,7 +2,7 @@ import { describe, expect, it, vi } from "vitest";
import type { App, TFile } from "obsidian";
import { ObsidianVaultAdapter } from "./ObsidianVaultAdapter";
describe("ObsidianVaultAdapter.read", () => {
describe("ObsidianVaultAdapter", () => {
it("preserves a UTF-8 BOM so the content size matches the file stat", async () => {
const path = "Transcripts/字幕.md";
const contentWithoutBom = "字幕の検証行です。\n";
@@ -34,4 +34,34 @@ describe("ObsidianVaultAdapter.read", () => {
expect(adapterRead).toHaveBeenCalledWith(path);
expect(read).not.toHaveBeenCalled();
});
it("floors write-option timestamps before calling Obsidian vault methods", async () => {
const modify = vi.fn().mockResolvedValue(undefined);
const modifyBinary = vi.fn().mockResolvedValue(undefined);
const create = vi.fn().mockResolvedValue({});
const createBinary = vi.fn().mockResolvedValue({});
const app = {
vault: {
modify,
modifyBinary,
create,
createBinary,
},
} as unknown as App;
const file = { path: "note.md" } as TFile;
const adapter = new ObsidianVaultAdapter(app);
const options = { ctime: 1778511180024.462, mtime: 1778511180999.913 };
const expectedOptions = { ctime: 1778511180024, mtime: 1778511180999 };
await adapter.modify(file, "text", options);
await adapter.modifyBinary(file, new ArrayBuffer(0), options);
await adapter.create("created.md", "text", options);
await adapter.createBinary("created.bin", new ArrayBuffer(0), options);
expect(modify).toHaveBeenCalledWith(file, "text", expectedOptions);
expect(modifyBinary).toHaveBeenCalledWith(file, expect.any(ArrayBuffer), expectedOptions);
expect(create).toHaveBeenCalledWith("created.md", "text", expectedOptions);
expect(createBinary).toHaveBeenCalledWith("created.bin", expect.any(ArrayBuffer), expectedOptions);
expect(options).toEqual({ ctime: 1778511180024.462, mtime: 1778511180999.913 });
});
});
@@ -1,4 +1,4 @@
import type { UXDataWriteOptions } from "@lib/common/types";
import type { UXDataWriteOptions } from "@vrtmrz/livesync-commonlib/compat/common/types";
/**
* Coerce the timestamp fields of a write-options object to integer milliseconds.