|
| 1 | +# Tests Specification |
| 2 | + |
| 3 | +This is the tests coverage details for the spec detailed in @.agent-os/specs/2025-10-18-note-tagging-system/spec.md |
| 4 | + |
| 5 | +> Created: 2025-10-18 |
| 6 | +> Version: 1.0.0 |
| 7 | +
|
| 8 | +## Test Coverage |
| 9 | + |
| 10 | +### Unit Tests |
| 11 | + |
| 12 | +**tagHelpers.ts** |
| 13 | +- `extractTagsFromContent()` extracts tags from metadata section |
| 14 | +- `extractTagsFromContent()` ignores tags in note body beyond metadata |
| 15 | +- `extractTagsFromContent()` handles empty content |
| 16 | +- `extractTagsFromContent()` handles content without tags |
| 17 | +- `extractTagsFromContent()` converts tags to lowercase |
| 18 | +- `extractTagsFromContent()` handles duplicate tags (returns unique set) |
| 19 | +- `isValidTag()` validates tag format (alphanumeric + hyphens) |
| 20 | +- `isValidTag()` rejects tags with spaces |
| 21 | +- `isValidTag()` rejects tags with special characters |
| 22 | +- `formatTagForDisplay()` formats tag with hash prefix |
| 23 | +- `formatTagForStorage()` normalizes tag to lowercase |
| 24 | + |
| 25 | +**tagService.ts** |
| 26 | +- `buildTagIndex()` scans all notes and builds tag index |
| 27 | +- `buildTagIndex()` handles notes without tags |
| 28 | +- `buildTagIndex()` counts tag occurrences correctly |
| 29 | +- `buildTagIndex()` stores note file paths for each tag |
| 30 | +- `getTagsForNote()` returns tags for a specific note |
| 31 | +- `getNotesWithTag()` returns all notes containing a tag |
| 32 | +- `getNotesWithTags()` returns notes with all specified tags (AND logic) |
| 33 | +- `getAllTags()` returns sorted tag list |
| 34 | +- `renameTag()` updates tag in all notes |
| 35 | +- `renameTag()` handles file write errors gracefully |
| 36 | +- `mergeTags()` combines tags and removes duplicates |
| 37 | +- `deleteTag()` removes tag from all notes |
| 38 | +- `addTagToNote()` adds tag to metadata section |
| 39 | +- `addTagToNote()` creates metadata section if missing |
| 40 | +- `removeTagFromNote()` removes tag from metadata section |
| 41 | + |
| 42 | +**tagsTreeProvider.ts** |
| 43 | +- `getChildren()` returns all tags as TagItems |
| 44 | +- `getChildren()` returns empty array when no tags exist |
| 45 | +- `getTreeItem()` creates tree item with correct label and count |
| 46 | +- `refresh()` triggers tree update |
| 47 | +- `sortTags()` sorts by frequency when configured |
| 48 | +- `sortTags()` sorts alphabetically when configured |
| 49 | + |
| 50 | +### Integration Tests |
| 51 | + |
| 52 | +**Tag Filtering Workflow** |
| 53 | +- User can filter notes by single tag via tree view click |
| 54 | +- User can filter notes by multiple tags via command palette |
| 55 | +- Filtered tree view shows only notes with selected tags |
| 56 | +- Clear filters command restores full tree view |
| 57 | +- Filter state persists during session |
| 58 | +- Filter indicator shows active tags in tree view title |
| 59 | + |
| 60 | +**Tag Management Workflow** |
| 61 | +- Rename tag command updates all notes successfully |
| 62 | +- Rename tag command shows confirmation with affected note count |
| 63 | +- Merge tags command combines tags and removes duplicates |
| 64 | +- Delete tag command removes tag from all notes after confirmation |
| 65 | +- Tag operations handle file system errors gracefully |
| 66 | +- Tag operations refresh tree view automatically |
| 67 | + |
| 68 | +**Search Integration Workflow** |
| 69 | +- Search with `tag:name` returns only notes with tag |
| 70 | +- Search with `tag:bug tag:urgent` returns notes with both tags |
| 71 | +- Search with `tag:bug error` returns notes with tag containing "error" |
| 72 | +- Search results highlight matched tags |
| 73 | +- Search handles malformed tag syntax gracefully |
| 74 | + |
| 75 | +**Autocomplete Workflow** |
| 76 | +- Typing `#` in metadata section triggers autocomplete |
| 77 | +- Autocomplete shows existing tags sorted by frequency |
| 78 | +- Selecting autocomplete inserts tag correctly |
| 79 | +- Autocomplete only triggers in first 10 lines |
| 80 | +- Autocomplete handles empty tag list |
| 81 | + |
| 82 | +### Performance Tests |
| 83 | + |
| 84 | +**Tag Index Building** |
| 85 | +- Build tag index for 100 notes completes in < 200ms |
| 86 | +- Build tag index for 1000 notes completes in < 500ms |
| 87 | +- Incremental index update for single note < 50ms |
| 88 | + |
| 89 | +**Filtering Performance** |
| 90 | +- Filter 100 notes by single tag < 50ms |
| 91 | +- Filter 1000 notes by single tag < 100ms |
| 92 | +- Filter by multiple tags scales linearly |
| 93 | + |
| 94 | +**Search Performance** |
| 95 | +- Search with tag + text in 100 notes < 200ms |
| 96 | +- Search with tag + text in 1000 notes < 1s |
| 97 | + |
| 98 | +### Edge Cases and Error Handling |
| 99 | + |
| 100 | +**Malformed Metadata** |
| 101 | +- Handle notes with malformed metadata gracefully |
| 102 | +- Handle notes with tags outside metadata section |
| 103 | +- Handle notes with invalid tag characters |
| 104 | +- Handle notes with extremely long tag lists (>100 tags) |
| 105 | + |
| 106 | +**File System Errors** |
| 107 | +- Handle read errors during tag index building |
| 108 | +- Handle write errors during tag rename/merge/delete |
| 109 | +- Provide user-friendly error messages |
| 110 | +- Roll back failed operations where possible |
| 111 | + |
| 112 | +**Concurrent Operations** |
| 113 | +- Handle multiple tag operations in quick succession |
| 114 | +- Handle tag index rebuild during active filtering |
| 115 | +- Handle external file modifications during tag operations |
| 116 | + |
| 117 | +## Mocking Requirements |
| 118 | + |
| 119 | +**VS Code API Mocks** |
| 120 | +- `vscode.workspace.workspaceFolders` for workspace path |
| 121 | +- `vscode.window.showQuickPick` for tag selection UI |
| 122 | +- `vscode.window.showInputBox` for rename tag input |
| 123 | +- `vscode.window.showInformationMessage` for confirmations |
| 124 | +- `vscode.window.showErrorMessage` for error display |
| 125 | +- `vscode.TreeDataProvider` event emitters |
| 126 | + |
| 127 | +**File System Mocks** |
| 128 | +- Mock `fs.promises.readFile` for reading note files |
| 129 | +- Mock `fs.promises.writeFile` for updating notes |
| 130 | +- Mock `fs.promises.readdir` for scanning note directories |
| 131 | +- Mock file system errors for error handling tests |
| 132 | + |
| 133 | +**Configuration Mocks** |
| 134 | +- Mock `vscode.workspace.getConfiguration` for settings |
| 135 | +- Mock different tag sort order settings |
| 136 | +- Mock enable/disable tag features |
| 137 | + |
| 138 | +## Test Data |
| 139 | + |
| 140 | +**Sample Notes with Tags** |
| 141 | +``` |
| 142 | +File: 2025-10-15.txt |
| 143 | +Content: |
| 144 | +tags: #bug #urgent #project-alpha |
| 145 | +
|
| 146 | +Found critical bug in user authentication. |
| 147 | +Need to fix ASAP. |
| 148 | +``` |
| 149 | + |
| 150 | +``` |
| 151 | +File: 2025-10-16.txt |
| 152 | +Content: |
| 153 | +tags: #feature #project-alpha |
| 154 | +
|
| 155 | +Implementing new dashboard feature. |
| 156 | +``` |
| 157 | + |
| 158 | +``` |
| 159 | +File: 2025-10-17.txt |
| 160 | +Content: |
| 161 | +No tags |
| 162 | +
|
| 163 | +Just some quick notes without tags. |
| 164 | +``` |
| 165 | + |
| 166 | +**Expected Tag Index** |
| 167 | +```javascript |
| 168 | +{ |
| 169 | + "bug": { count: 1, notes: ["2025-10-15.txt"] }, |
| 170 | + "urgent": { count: 1, notes: ["2025-10-15.txt"] }, |
| 171 | + "project-alpha": { count: 2, notes: ["2025-10-15.txt", "2025-10-16.txt"] }, |
| 172 | + "feature": { count: 1, notes: ["2025-10-16.txt"] } |
| 173 | +} |
| 174 | +``` |
| 175 | + |
| 176 | +## Coverage Goals |
| 177 | + |
| 178 | +- **Unit Tests**: ≥ 90% coverage for tag utilities and services |
| 179 | +- **Integration Tests**: All major user workflows covered |
| 180 | +- **Edge Cases**: All error scenarios have dedicated tests |
| 181 | +- **Performance**: All performance benchmarks validated |
0 commit comments