Skip to content

Commit eaa5d29

Browse files
committed
fix: better performance
1 parent 60c44b2 commit eaa5d29

8 files changed

Lines changed: 725 additions & 29 deletions

File tree

src/__tests__/FileMetadataTaskParser.test.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ describe("FileMetadataTaskParser", () => {
2525
taskContentFromMetadata: "title",
2626
defaultTaskStatus: " ",
2727
enableWorkerProcessing: true,
28+
enableMtimeOptimization: false,
29+
mtimeCacheSize: 1000,
2830
};
2931
parser = new FileMetadataTaskParser(config);
3032
});
@@ -206,6 +208,8 @@ describe("FileMetadataTaskParser", () => {
206208
taskContentFromMetadata: "title",
207209
defaultTaskStatus: " ",
208210
enableWorkerProcessing: true,
211+
enableMtimeOptimization: false,
212+
mtimeCacheSize: 1000,
209213
};
210214
const disabledParser = new FileMetadataTaskParser(disabledConfig);
211215

@@ -358,6 +362,8 @@ describe("FileMetadataTaskUpdater", () => {
358362
taskContentFromMetadata: "title",
359363
defaultTaskStatus: " ",
360364
enableWorkerProcessing: true,
365+
enableMtimeOptimization: false,
366+
mtimeCacheSize: 1000,
361367
};
362368

363369
// Mock Obsidian App
Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
/**
2+
* Tests for TaskIndexer mtime-based caching functionality
3+
*/
4+
5+
import { TaskIndexer } from "../utils/import/TaskIndexer";
6+
import { Task } from "../types/task";
7+
8+
// Mock obsidian Component class
9+
jest.mock("obsidian", () => ({
10+
...jest.requireActual("obsidian"),
11+
Component: class {
12+
registerEvent = jest.fn();
13+
unload = jest.fn();
14+
},
15+
TFile: jest.fn(),
16+
}));
17+
18+
// Mock dependencies
19+
const mockApp = {} as any;
20+
const mockVault = {
21+
on: jest.fn().mockReturnValue({}),
22+
off: jest.fn(),
23+
} as any;
24+
const mockMetadataCache = {} as any;
25+
26+
describe("TaskIndexer mtime functionality", () => {
27+
let indexer: TaskIndexer;
28+
29+
beforeEach(() => {
30+
indexer = new TaskIndexer(mockApp, mockVault, mockMetadataCache);
31+
});
32+
33+
afterEach(() => {
34+
if (indexer && typeof indexer.unload === 'function') {
35+
indexer.unload();
36+
}
37+
});
38+
39+
describe("mtime comparison", () => {
40+
test("should detect file changes when mtime is newer", () => {
41+
const filePath = "test.md";
42+
const oldMtime = 1000;
43+
const newMtime = 2000;
44+
45+
// Set initial mtime
46+
indexer.updateFileMtime(filePath, oldMtime);
47+
48+
// Check if file is changed with newer mtime
49+
expect(indexer.isFileChanged(filePath, newMtime)).toBe(true);
50+
});
51+
52+
test("should not detect changes when mtime is same", () => {
53+
const filePath = "test.md";
54+
const mtime = 1000;
55+
56+
// Set initial mtime
57+
indexer.updateFileMtime(filePath, mtime);
58+
59+
// Check if file is changed with same mtime
60+
expect(indexer.isFileChanged(filePath, mtime)).toBe(false);
61+
});
62+
63+
test("should detect changes for unknown files", () => {
64+
const filePath = "unknown.md";
65+
const mtime = 1000;
66+
67+
// Check if unknown file is considered changed
68+
expect(indexer.isFileChanged(filePath, mtime)).toBe(true);
69+
});
70+
});
71+
72+
describe("cache validation", () => {
73+
test("should have valid cache when file hasn't changed and has tasks", () => {
74+
const filePath = "test.md";
75+
const mtime = 1000;
76+
const tasks: Task[] = [
77+
{
78+
id: "task1",
79+
content: "Test task",
80+
filePath,
81+
line: 1,
82+
completed: false,
83+
status: " ",
84+
originalMarkdown: "- [ ] Test task",
85+
metadata: {
86+
tags: [],
87+
project: undefined,
88+
context: undefined,
89+
priority: undefined,
90+
dueDate: undefined,
91+
startDate: undefined,
92+
scheduledDate: undefined,
93+
completedDate: undefined,
94+
cancelledDate: undefined,
95+
createdDate: undefined,
96+
recurrence: undefined,
97+
dependsOn: [],
98+
onCompletion: undefined,
99+
taskId: undefined,
100+
children: [],
101+
},
102+
},
103+
];
104+
105+
// Add tasks and set mtime
106+
indexer.updateIndexWithTasks(filePath, tasks, mtime);
107+
108+
// Check if cache is valid
109+
expect(indexer.hasValidCache(filePath, mtime)).toBe(true);
110+
});
111+
112+
test("should not have valid cache when file has changed", () => {
113+
const filePath = "test.md";
114+
const oldMtime = 1000;
115+
const newMtime = 2000;
116+
const tasks: Task[] = [];
117+
118+
// Add tasks with old mtime
119+
indexer.updateIndexWithTasks(filePath, tasks, oldMtime);
120+
121+
// Check if cache is invalid with new mtime
122+
expect(indexer.hasValidCache(filePath, newMtime)).toBe(false);
123+
});
124+
125+
test("should not have valid cache when no tasks exist", () => {
126+
const filePath = "test.md";
127+
const mtime = 1000;
128+
129+
// Don't add any tasks, just set mtime
130+
indexer.updateFileMtime(filePath, mtime);
131+
132+
// Check if cache is invalid when no tasks exist
133+
expect(indexer.hasValidCache(filePath, mtime)).toBe(false);
134+
});
135+
});
136+
137+
describe("cache cleanup", () => {
138+
test("should clean up file cache properly", () => {
139+
const filePath = "test.md";
140+
const mtime = 1000;
141+
const tasks: Task[] = [];
142+
143+
// Add tasks and set mtime
144+
indexer.updateIndexWithTasks(filePath, tasks, mtime);
145+
146+
// Verify cache exists
147+
expect(indexer.getFileLastMtime(filePath)).toBe(mtime);
148+
149+
// Clean up cache
150+
indexer.cleanupFileCache(filePath);
151+
152+
// Verify cache is cleaned
153+
expect(indexer.getFileLastMtime(filePath)).toBeUndefined();
154+
});
155+
});
156+
157+
describe("cache consistency", () => {
158+
test("should validate and fix cache consistency", () => {
159+
const filePath = "test.md";
160+
const mtime = 1000;
161+
162+
// Manually add mtime without tasks (inconsistent state)
163+
indexer.updateFileMtime(filePath, mtime);
164+
165+
// Validate consistency (should clean up orphaned mtime)
166+
indexer.validateCacheConsistency();
167+
168+
// Verify orphaned mtime is cleaned up
169+
expect(indexer.getFileLastMtime(filePath)).toBeUndefined();
170+
});
171+
});
172+
});

0 commit comments

Comments
 (0)