docs: add implementation plans for coverage work
This commit is contained in:
263
docs/plans/2025-01-20-tools-coverage-implementation.md
Normal file
263
docs/plans/2025-01-20-tools-coverage-implementation.md
Normal file
@@ -0,0 +1,263 @@
|
||||
# Implementation Plan: 100% Tool Coverage
|
||||
|
||||
**Date:** 2025-01-20
|
||||
**Goal:** Achieve 100% test coverage on note-tools.ts and vault-tools.ts
|
||||
**Approach:** Add targeted test cases to existing test files
|
||||
|
||||
## Overview
|
||||
|
||||
This plan addresses the remaining coverage gaps in the tool modules to achieve 100% statement coverage as part of pre-release validation.
|
||||
|
||||
## Current Coverage Status
|
||||
|
||||
- **note-tools.ts:** 96.01% → Target: 100% (9 uncovered lines)
|
||||
- **vault-tools.ts:** 94.22% → Target: 100% (14 uncovered lines)
|
||||
|
||||
## Gap Analysis
|
||||
|
||||
### Note-Tools Uncovered Lines (9 lines)
|
||||
|
||||
1. **Lines 238-239:** Conflict resolution loop (when creating files with duplicate names)
|
||||
2. **Lines 377, 408, 590, 710, 836:** Folder-not-file errors (5 occurrences across different methods)
|
||||
3. **Line 647:** Include compressed data flag in Excalidraw read
|
||||
4. **Line 771:** Add frontmatter to file that has no existing frontmatter
|
||||
|
||||
### Vault-Tools Uncovered Lines (14 lines)
|
||||
|
||||
1. **Line 76:** Invalid path validation error
|
||||
2. **Line 200:** Folder assignment (possibly unreachable)
|
||||
3. **Line 267:** Skip root folder in iteration
|
||||
4. **Line 272:** Glob filtering skip
|
||||
5. **Line 325:** Alias as string (non-array) normalization
|
||||
6. **Line 374:** Folder mtime extraction error catch
|
||||
7. **Lines 452-456, 524-528:** Defensive "path doesn't exist" returns
|
||||
8. **Lines 596-597:** Glob filtering in search
|
||||
9. **Lines 608, 620:** MaxResults early termination
|
||||
10. **Line 650:** Snippet end-of-line adjustment
|
||||
11. **Line 777:** Search error catch block
|
||||
|
||||
## Implementation Tasks
|
||||
|
||||
### Task 1: Add Note-Tools Conflict Resolution Tests
|
||||
|
||||
**Objective:** Cover lines 238-239 (conflict resolution loop)
|
||||
|
||||
**Steps:**
|
||||
1. Add test: "creates file with incremented counter when conflicts exist"
|
||||
2. Mock PathUtils.fileExists to return true for "file.md" and "file 2.md"
|
||||
3. Verify creates "file 3.md"
|
||||
4. Run coverage to confirm lines 238-239 covered
|
||||
|
||||
**Files to modify:**
|
||||
- `tests/note-tools.test.ts`
|
||||
|
||||
**Expected outcome:** Lines 238-239 covered
|
||||
|
||||
---
|
||||
|
||||
### Task 2: Add Note-Tools Folder-Not-File Error Tests
|
||||
|
||||
**Objective:** Cover lines 377, 408, 590, 710, 836 (folder instead of file errors)
|
||||
|
||||
**Steps:**
|
||||
1. Add test for read_note: "returns error when path is a folder"
|
||||
- Mock PathUtils.folderExists to return true
|
||||
- Verify error message uses ErrorMessages.notAFile()
|
||||
|
||||
2. Add test for rename_file: "returns error when path is a folder"
|
||||
3. Add test for update_note: "returns error when path is a folder"
|
||||
4. Add test for delete_note: "returns error when path is a folder"
|
||||
5. Add test for update_sections: "returns error when path is a folder"
|
||||
6. Run coverage to confirm all 5 lines covered
|
||||
|
||||
**Files to modify:**
|
||||
- `tests/note-tools.test.ts`
|
||||
|
||||
**Expected outcome:** Lines 377, 408, 590, 710, 836 covered
|
||||
|
||||
---
|
||||
|
||||
### Task 3: Add Note-Tools Excalidraw and Frontmatter Tests
|
||||
|
||||
**Objective:** Cover lines 647, 771
|
||||
|
||||
**Steps:**
|
||||
1. Add test for read_excalidraw: "includes compressed data when flag is true"
|
||||
- Call with includeCompressed=true
|
||||
- Verify result.compressedData is included
|
||||
|
||||
2. Add test for update_frontmatter: "adds frontmatter to file without existing frontmatter"
|
||||
- Mock file content without frontmatter
|
||||
- Update frontmatter
|
||||
- Verify frontmatter added at beginning with newline separator
|
||||
|
||||
3. Run coverage to confirm lines 647, 771 covered
|
||||
|
||||
**Files to modify:**
|
||||
- `tests/note-tools.test.ts`
|
||||
|
||||
**Expected outcome:** Lines 647, 771 covered, note-tools.ts at 100%
|
||||
|
||||
---
|
||||
|
||||
### Task 4: Add Vault-Tools Invalid Path and Glob Tests
|
||||
|
||||
**Objective:** Cover lines 76, 272, 596-597
|
||||
|
||||
**Steps:**
|
||||
1. Add test for list(): "returns error for invalid vault path"
|
||||
- Mock PathUtils.isValidVaultPath to return false
|
||||
- Verify error message
|
||||
|
||||
2. Add test for list(): "filters items using glob excludes"
|
||||
- Mock GlobUtils.shouldInclude to return false for some items
|
||||
- Verify filtered items not in results
|
||||
|
||||
3. Add test for search(): "applies glob filtering to search results"
|
||||
- Provide includes/excludes patterns
|
||||
- Verify filtered files not searched
|
||||
|
||||
4. Run coverage to confirm lines 76, 272, 596-597 covered
|
||||
|
||||
**Files to modify:**
|
||||
- `tests/vault-tools.test.ts`
|
||||
|
||||
**Expected outcome:** Lines 76, 272, 596-597 covered
|
||||
|
||||
---
|
||||
|
||||
### Task 5: Add Vault-Tools Edge Case Tests
|
||||
|
||||
**Objective:** Cover lines 267, 325, 374, 608, 620, 650
|
||||
|
||||
**Steps:**
|
||||
1. Add test for list(): "skips root folder in iteration"
|
||||
- Mock folder structure with root folder (path='', isRoot()=true)
|
||||
- Verify root not in results
|
||||
|
||||
2. Add test for list(): "normalizes aliases from string to array"
|
||||
- Mock cache.frontmatter.aliases as string instead of array
|
||||
- Verify result has aliases as array
|
||||
|
||||
3. Add test for getFolderMetadata(): "handles folder without mtime stat"
|
||||
- Mock folder without stat or with invalid stat
|
||||
- Verify doesn't crash, uses default mtime
|
||||
|
||||
4. Add test for search(): "stops searching when maxResults=1 reached"
|
||||
- Multiple files with matches
|
||||
- Verify only 1 result returned
|
||||
|
||||
5. Add test for search(): "adjusts snippet for long lines at end"
|
||||
- Mock line longer than snippetLength ending with match
|
||||
- Verify snippet adjustment logic (line 650)
|
||||
|
||||
6. Run coverage to confirm lines 267, 325, 374, 608, 620, 650 covered
|
||||
|
||||
**Files to modify:**
|
||||
- `tests/vault-tools.test.ts`
|
||||
|
||||
**Expected outcome:** Lines 267, 325, 374, 608, 620, 650 covered
|
||||
|
||||
---
|
||||
|
||||
### Task 6: Add Vault-Tools Defensive Code Coverage
|
||||
|
||||
**Objective:** Cover lines 200, 452-456, 524-528, 777
|
||||
|
||||
**Steps:**
|
||||
1. Analyze if lines 200, 452-456, 524-528 are truly unreachable
|
||||
- If unreachable: Document why (defensive code)
|
||||
- If reachable: Add tests to trigger them
|
||||
|
||||
2. Add test for search(): "handles file read errors gracefully"
|
||||
- Mock vault.read to throw error
|
||||
- Verify error caught, logged to console, search continues
|
||||
- Covers line 777
|
||||
|
||||
3. For defensive returns (452-456, 524-528):
|
||||
- Attempt to trigger "path doesn't exist" cases
|
||||
- If impossible: Document as unreachable defensive code
|
||||
|
||||
4. Run coverage to verify maximum possible coverage
|
||||
|
||||
**Files to modify:**
|
||||
- `tests/vault-tools.test.ts`
|
||||
- Possibly: add comments in source code marking defensive code
|
||||
|
||||
**Expected outcome:** Lines covered or documented as unreachable
|
||||
|
||||
---
|
||||
|
||||
### Task 7: Verify 100% Coverage
|
||||
|
||||
**Objective:** Confirm 100% coverage achieved
|
||||
|
||||
**Steps:**
|
||||
1. Run `npm run test:coverage`
|
||||
2. Check coverage report:
|
||||
- note-tools.ts: 100% or documented gaps
|
||||
- vault-tools.ts: 100% or documented gaps
|
||||
3. If any gaps remain:
|
||||
- Identify what's uncovered
|
||||
- Add tests or document as unreachable
|
||||
4. Final coverage verification
|
||||
|
||||
**Expected outcome:** Both tools at 100% coverage
|
||||
|
||||
---
|
||||
|
||||
### Task 8: Run Full Test Suite and Build
|
||||
|
||||
**Objective:** Verify no regressions
|
||||
|
||||
**Steps:**
|
||||
1. Run `npm test` - all tests must pass
|
||||
2. Run `npm run build` - must succeed
|
||||
3. Verify total test count increased
|
||||
4. Document final metrics
|
||||
|
||||
**Expected outcome:** All tests passing, build successful
|
||||
|
||||
---
|
||||
|
||||
### Task 9: Create Summary and Merge
|
||||
|
||||
**Objective:** Document and integrate work
|
||||
|
||||
**Steps:**
|
||||
1. Update IMPLEMENTATION_SUMMARY.md with:
|
||||
- Coverage improvements (before/after)
|
||||
- Test counts
|
||||
- Any unreachable code documented
|
||||
2. Use finishing-a-development-branch skill
|
||||
3. Merge to master
|
||||
|
||||
**Expected outcome:** Work merged, documentation updated
|
||||
|
||||
## Success Criteria
|
||||
|
||||
- [x] note-tools.ts at 100% statement coverage
|
||||
- [x] vault-tools.ts at 100% statement coverage
|
||||
- [x] All tests passing
|
||||
- [x] Build succeeds
|
||||
- [x] Any unreachable code documented
|
||||
- [x] Work merged to master
|
||||
|
||||
## Risk Mitigation
|
||||
|
||||
**If some lines are truly unreachable:**
|
||||
- Document with inline comments explaining why
|
||||
- Accept 99.x% if justified
|
||||
- Focus on getting all reachable code to 100%
|
||||
|
||||
**If tests become too complex:**
|
||||
- Consider minor refactoring for testability
|
||||
- Use subagent review to validate approach
|
||||
- Ensure tests remain maintainable
|
||||
|
||||
## Estimated Effort
|
||||
|
||||
- Note-tools tests: ~1 hour (7 new test cases)
|
||||
- Vault-tools tests: ~1.5 hours (10-12 new test cases)
|
||||
- Verification and cleanup: ~0.5 hours
|
||||
- **Total: ~3 hours**
|
||||
Reference in New Issue
Block a user