pushwork 1.0.4 → 1.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (195) hide show
  1. package/README.md +87 -328
  2. package/dist/.pushwork/automerge/3P/Dm3ekE2pmjGnWvDaG3vSR7ww98/snapshot/aa2349c94955ea561f698720142f9d884a6872d9f82dc332d578c216beb0df0e +0 -0
  3. package/dist/.pushwork/automerge/st/orage-adapter-id +1 -0
  4. package/dist/.pushwork/config.json +15 -0
  5. package/dist/.pushwork/snapshot.json +7 -0
  6. package/dist/cli.js +231 -170
  7. package/dist/cli.js.map +1 -1
  8. package/dist/commands.d.ts +51 -0
  9. package/dist/commands.d.ts.map +1 -0
  10. package/dist/commands.js +799 -0
  11. package/dist/commands.js.map +1 -0
  12. package/dist/core/change-detection.d.ts +6 -19
  13. package/dist/core/change-detection.d.ts.map +1 -1
  14. package/dist/core/change-detection.js +101 -80
  15. package/dist/core/change-detection.js.map +1 -1
  16. package/dist/{config/index.d.ts → core/config.d.ts} +13 -3
  17. package/dist/core/config.d.ts.map +1 -0
  18. package/dist/{config/index.js → core/config.js} +55 -73
  19. package/dist/core/config.js.map +1 -0
  20. package/dist/core/index.d.ts +1 -0
  21. package/dist/core/index.d.ts.map +1 -1
  22. package/dist/core/index.js +1 -1
  23. package/dist/core/index.js.map +1 -1
  24. package/dist/core/move-detection.d.ts +12 -50
  25. package/dist/core/move-detection.d.ts.map +1 -1
  26. package/dist/core/move-detection.js +58 -139
  27. package/dist/core/move-detection.js.map +1 -1
  28. package/dist/core/snapshot.d.ts +0 -4
  29. package/dist/core/snapshot.d.ts.map +1 -1
  30. package/dist/core/snapshot.js +2 -11
  31. package/dist/core/snapshot.js.map +1 -1
  32. package/dist/core/sync-engine.d.ts +5 -11
  33. package/dist/core/sync-engine.d.ts.map +1 -1
  34. package/dist/core/sync-engine.js +220 -362
  35. package/dist/core/sync-engine.js.map +1 -1
  36. package/dist/index.d.ts +0 -1
  37. package/dist/index.d.ts.map +1 -1
  38. package/dist/index.js +0 -6
  39. package/dist/index.js.map +1 -1
  40. package/dist/types/config.d.ts +43 -67
  41. package/dist/types/config.d.ts.map +1 -1
  42. package/dist/types/config.js +6 -0
  43. package/dist/types/config.js.map +1 -1
  44. package/dist/types/documents.d.ts +15 -3
  45. package/dist/types/documents.d.ts.map +1 -1
  46. package/dist/types/documents.js.map +1 -1
  47. package/dist/types/index.d.ts.map +1 -1
  48. package/dist/types/index.js +0 -3
  49. package/dist/types/index.js.map +1 -1
  50. package/dist/types/snapshot.d.ts +3 -21
  51. package/dist/types/snapshot.d.ts.map +1 -1
  52. package/dist/types/snapshot.js +0 -14
  53. package/dist/types/snapshot.js.map +1 -1
  54. package/dist/utils/content.d.ts.map +1 -1
  55. package/dist/utils/content.js +2 -6
  56. package/dist/utils/content.js.map +1 -1
  57. package/dist/utils/directory.d.ts +10 -0
  58. package/dist/utils/directory.d.ts.map +1 -0
  59. package/dist/utils/directory.js +37 -0
  60. package/dist/utils/directory.js.map +1 -0
  61. package/dist/utils/fs.d.ts +15 -2
  62. package/dist/utils/fs.d.ts.map +1 -1
  63. package/dist/utils/fs.js +63 -53
  64. package/dist/utils/fs.js.map +1 -1
  65. package/dist/utils/index.d.ts +1 -1
  66. package/dist/utils/index.d.ts.map +1 -1
  67. package/dist/utils/index.js +1 -4
  68. package/dist/utils/index.js.map +1 -1
  69. package/dist/utils/mime-types.d.ts.map +1 -1
  70. package/dist/utils/mime-types.js +11 -4
  71. package/dist/utils/mime-types.js.map +1 -1
  72. package/dist/utils/network-sync.d.ts +0 -6
  73. package/dist/utils/network-sync.d.ts.map +1 -1
  74. package/dist/utils/network-sync.js +55 -99
  75. package/dist/utils/network-sync.js.map +1 -1
  76. package/dist/utils/output.d.ts +129 -0
  77. package/dist/utils/output.d.ts.map +1 -0
  78. package/dist/utils/output.js +375 -0
  79. package/dist/utils/output.js.map +1 -0
  80. package/dist/utils/repo-factory.d.ts +2 -6
  81. package/dist/utils/repo-factory.d.ts.map +1 -1
  82. package/dist/utils/repo-factory.js +8 -22
  83. package/dist/utils/repo-factory.js.map +1 -1
  84. package/dist/utils/string-similarity.d.ts +14 -0
  85. package/dist/utils/string-similarity.d.ts.map +1 -0
  86. package/dist/utils/string-similarity.js +43 -0
  87. package/dist/utils/string-similarity.js.map +1 -0
  88. package/dist/utils/trace.d.ts +19 -0
  89. package/dist/utils/trace.d.ts.map +1 -0
  90. package/dist/utils/trace.js +68 -0
  91. package/dist/utils/trace.js.map +1 -0
  92. package/package.json +17 -12
  93. package/src/cli.ts +326 -252
  94. package/src/commands.ts +988 -0
  95. package/src/core/change-detection.ts +199 -162
  96. package/src/{config/index.ts → core/config.ts} +65 -82
  97. package/src/core/index.ts +1 -1
  98. package/src/core/move-detection.ts +74 -180
  99. package/src/core/snapshot.ts +2 -12
  100. package/src/core/sync-engine.ts +248 -499
  101. package/src/index.ts +0 -10
  102. package/src/types/config.ts +50 -72
  103. package/src/types/documents.ts +16 -3
  104. package/src/types/index.ts +0 -5
  105. package/src/types/snapshot.ts +1 -23
  106. package/src/utils/content.ts +2 -6
  107. package/src/utils/directory.ts +50 -0
  108. package/src/utils/fs.ts +67 -56
  109. package/src/utils/index.ts +1 -6
  110. package/src/utils/mime-types.ts +12 -4
  111. package/src/utils/network-sync.ts +79 -137
  112. package/src/utils/output.ts +450 -0
  113. package/src/utils/repo-factory.ts +13 -31
  114. package/src/utils/string-similarity.ts +54 -0
  115. package/src/utils/trace.ts +70 -0
  116. package/test/integration/exclude-patterns.test.ts +6 -15
  117. package/test/integration/fuzzer.test.ts +308 -391
  118. package/test/integration/init-sync.test.ts +89 -0
  119. package/test/integration/sync-deletion.test.ts +2 -61
  120. package/test/integration/sync-flow.test.ts +4 -24
  121. package/test/jest.setup.ts +34 -0
  122. package/test/unit/deletion-behavior.test.ts +3 -14
  123. package/test/unit/enhanced-mime-detection.test.ts +0 -22
  124. package/test/unit/snapshot.test.ts +2 -29
  125. package/test/unit/sync-convergence.test.ts +3 -198
  126. package/test/unit/sync-timing.test.ts +0 -44
  127. package/test/unit/utils.test.ts +0 -2
  128. package/tsconfig.json +3 -3
  129. package/dist/browser/browser-sync-engine.d.ts +0 -64
  130. package/dist/browser/browser-sync-engine.d.ts.map +0 -1
  131. package/dist/browser/browser-sync-engine.js +0 -303
  132. package/dist/browser/browser-sync-engine.js.map +0 -1
  133. package/dist/browser/filesystem-adapter.d.ts +0 -84
  134. package/dist/browser/filesystem-adapter.d.ts.map +0 -1
  135. package/dist/browser/filesystem-adapter.js +0 -413
  136. package/dist/browser/filesystem-adapter.js.map +0 -1
  137. package/dist/browser/index.d.ts +0 -36
  138. package/dist/browser/index.d.ts.map +0 -1
  139. package/dist/browser/index.js +0 -90
  140. package/dist/browser/index.js.map +0 -1
  141. package/dist/browser/types.d.ts +0 -70
  142. package/dist/browser/types.d.ts.map +0 -1
  143. package/dist/browser/types.js +0 -6
  144. package/dist/browser/types.js.map +0 -1
  145. package/dist/cli/commands.d.ts +0 -77
  146. package/dist/cli/commands.d.ts.map +0 -1
  147. package/dist/cli/commands.js +0 -904
  148. package/dist/cli/commands.js.map +0 -1
  149. package/dist/cli/index.d.ts +0 -2
  150. package/dist/cli/index.d.ts.map +0 -1
  151. package/dist/cli/index.js +0 -19
  152. package/dist/cli/index.js.map +0 -1
  153. package/dist/config/index.d.ts.map +0 -1
  154. package/dist/config/index.js.map +0 -1
  155. package/dist/core/isomorphic-snapshot.d.ts +0 -58
  156. package/dist/core/isomorphic-snapshot.d.ts.map +0 -1
  157. package/dist/core/isomorphic-snapshot.js +0 -204
  158. package/dist/core/isomorphic-snapshot.js.map +0 -1
  159. package/dist/platform/browser-filesystem.d.ts +0 -26
  160. package/dist/platform/browser-filesystem.d.ts.map +0 -1
  161. package/dist/platform/browser-filesystem.js +0 -91
  162. package/dist/platform/browser-filesystem.js.map +0 -1
  163. package/dist/platform/filesystem.d.ts +0 -29
  164. package/dist/platform/filesystem.d.ts.map +0 -1
  165. package/dist/platform/filesystem.js +0 -65
  166. package/dist/platform/filesystem.js.map +0 -1
  167. package/dist/platform/node-filesystem.d.ts +0 -21
  168. package/dist/platform/node-filesystem.d.ts.map +0 -1
  169. package/dist/platform/node-filesystem.js +0 -93
  170. package/dist/platform/node-filesystem.js.map +0 -1
  171. package/dist/utils/content-similarity.d.ts +0 -53
  172. package/dist/utils/content-similarity.d.ts.map +0 -1
  173. package/dist/utils/content-similarity.js +0 -155
  174. package/dist/utils/content-similarity.js.map +0 -1
  175. package/dist/utils/fs-browser.d.ts +0 -57
  176. package/dist/utils/fs-browser.d.ts.map +0 -1
  177. package/dist/utils/fs-browser.js +0 -311
  178. package/dist/utils/fs-browser.js.map +0 -1
  179. package/dist/utils/fs-node.d.ts +0 -53
  180. package/dist/utils/fs-node.d.ts.map +0 -1
  181. package/dist/utils/fs-node.js +0 -220
  182. package/dist/utils/fs-node.js.map +0 -1
  183. package/dist/utils/isomorphic.d.ts +0 -29
  184. package/dist/utils/isomorphic.d.ts.map +0 -1
  185. package/dist/utils/isomorphic.js +0 -139
  186. package/dist/utils/isomorphic.js.map +0 -1
  187. package/dist/utils/pure.d.ts +0 -25
  188. package/dist/utils/pure.d.ts.map +0 -1
  189. package/dist/utils/pure.js +0 -112
  190. package/dist/utils/pure.js.map +0 -1
  191. package/src/cli/commands.ts +0 -1207
  192. package/src/cli/index.ts +0 -2
  193. package/src/utils/content-similarity.ts +0 -194
  194. package/test/README-TESTING-GAPS.md +0 -174
  195. package/test/unit/content-similarity.test.ts +0 -236
package/src/cli/index.ts DELETED
@@ -1,2 +0,0 @@
1
- // CLI commands
2
- export * from "./commands";
@@ -1,194 +0,0 @@
1
- import { calculateContentHash } from "./fs";
2
-
3
- /**
4
- * Content similarity calculation for move detection
5
- */
6
- export class ContentSimilarity {
7
- private static readonly CHUNK_SIZE = 1024; // 1KB chunks for sampling
8
- private static readonly AUTO_THRESHOLD = 0.8;
9
- private static readonly PROMPT_THRESHOLD = 0.5;
10
-
11
- /**
12
- * Calculate similarity between two content pieces
13
- */
14
- static async calculateSimilarity(
15
- content1: string | Uint8Array,
16
- content2: string | Uint8Array
17
- ): Promise<number> {
18
- // Quick early exit for identical content
19
- if (await this.areIdentical(content1, content2)) {
20
- return 1.0;
21
- }
22
-
23
- // Size-based quick rejection
24
- const size1 =
25
- typeof content1 === "string" ? content1.length : content1.length;
26
- const size2 =
27
- typeof content2 === "string" ? content2.length : content2.length;
28
- const sizeDiff = Math.abs(size1 - size2) / Math.max(size1, size2);
29
-
30
- if (sizeDiff > 0.5) {
31
- return 0.0; // Too different in size
32
- }
33
-
34
- // For small files, use full content comparison
35
- if (size1 < this.CHUNK_SIZE * 4 && size2 < this.CHUNK_SIZE * 4) {
36
- return this.calculateFullSimilarity(content1, content2);
37
- }
38
-
39
- // For large files, use sampling
40
- return this.calculateSampledSimilarity(content1, content2);
41
- }
42
-
43
- /**
44
- * Check if two content pieces are identical
45
- */
46
- private static async areIdentical(
47
- content1: string | Uint8Array,
48
- content2: string | Uint8Array
49
- ): Promise<boolean> {
50
- const hash1 = await calculateContentHash(content1);
51
- const hash2 = await calculateContentHash(content2);
52
- return hash1 === hash2;
53
- }
54
-
55
- /**
56
- * Calculate similarity for small files using full content
57
- */
58
- private static calculateFullSimilarity(
59
- content1: string | Uint8Array,
60
- content2: string | Uint8Array
61
- ): number {
62
- const str1 =
63
- typeof content1 === "string" ? content1 : this.bufferToString(content1);
64
- const str2 =
65
- typeof content2 === "string" ? content2 : this.bufferToString(content2);
66
-
67
- return this.levenshteinSimilarity(str1, str2);
68
- }
69
-
70
- /**
71
- * Calculate similarity for large files using sampling
72
- */
73
- private static calculateSampledSimilarity(
74
- content1: string | Uint8Array,
75
- content2: string | Uint8Array
76
- ): number {
77
- const samples1 = this.getSamples(content1);
78
- const samples2 = this.getSamples(content2);
79
-
80
- let totalSimilarity = 0;
81
- let comparisons = 0;
82
-
83
- for (let i = 0; i < Math.min(samples1.length, samples2.length); i++) {
84
- totalSimilarity += this.levenshteinSimilarity(samples1[i], samples2[i]);
85
- comparisons++;
86
- }
87
-
88
- return comparisons > 0 ? totalSimilarity / comparisons : 0;
89
- }
90
-
91
- /**
92
- * Get representative samples from content
93
- */
94
- private static getSamples(content: string | Uint8Array): string[] {
95
- const str =
96
- typeof content === "string" ? content : this.bufferToString(content);
97
- const length = str.length;
98
- const samples: string[] = [];
99
-
100
- if (length <= this.CHUNK_SIZE) {
101
- samples.push(str);
102
- return samples;
103
- }
104
-
105
- // Beginning
106
- samples.push(str.slice(0, this.CHUNK_SIZE));
107
-
108
- // Middle
109
- const midStart = Math.floor(length / 2) - Math.floor(this.CHUNK_SIZE / 2);
110
- samples.push(str.slice(midStart, midStart + this.CHUNK_SIZE));
111
-
112
- // End
113
- samples.push(str.slice(-this.CHUNK_SIZE));
114
-
115
- return samples;
116
- }
117
-
118
- /**
119
- * Calculate Levenshtein similarity (0-1 scale)
120
- */
121
- private static levenshteinSimilarity(str1: string, str2: string): number {
122
- if (str1 === str2) return 1.0;
123
- if (str1.length === 0 || str2.length === 0) return 0.0;
124
-
125
- const distance = this.levenshteinDistance(str1, str2);
126
- const maxLength = Math.max(str1.length, str2.length);
127
-
128
- return 1 - distance / maxLength;
129
- }
130
-
131
- /**
132
- * Calculate Levenshtein distance
133
- */
134
- private static levenshteinDistance(str1: string, str2: string): number {
135
- const matrix = Array(str2.length + 1)
136
- .fill(null)
137
- .map(() => Array(str1.length + 1).fill(null));
138
-
139
- for (let i = 0; i <= str1.length; i++) matrix[0][i] = i;
140
- for (let j = 0; j <= str2.length; j++) matrix[j][0] = j;
141
-
142
- for (let j = 1; j <= str2.length; j++) {
143
- for (let i = 1; i <= str1.length; i++) {
144
- const indicator = str1[i - 1] === str2[j - 1] ? 0 : 1;
145
- matrix[j][i] = Math.min(
146
- matrix[j][i - 1] + 1, // deletion
147
- matrix[j - 1][i] + 1, // insertion
148
- matrix[j - 1][i - 1] + indicator // substitution
149
- );
150
- }
151
- }
152
-
153
- return matrix[str2.length][str1.length];
154
- }
155
-
156
- /**
157
- * Convert buffer to string for comparison
158
- */
159
- private static bufferToString(buffer: Uint8Array): string {
160
- // For binary content, use hex representation for comparison
161
- return Array.from(buffer)
162
- .map((b) => b.toString(16).padStart(2, "0"))
163
- .join("");
164
- }
165
-
166
- /**
167
- * Determine confidence level based on similarity score
168
- */
169
- static getConfidenceLevel(similarity: number): "auto" | "prompt" | "low" {
170
- if (similarity >= this.AUTO_THRESHOLD) {
171
- return "auto";
172
- } else if (similarity >= this.PROMPT_THRESHOLD) {
173
- return "prompt";
174
- } else {
175
- return "low";
176
- }
177
- }
178
-
179
- /**
180
- * Should auto-apply move based on similarity
181
- */
182
- static shouldAutoApply(similarity: number): boolean {
183
- return similarity >= this.AUTO_THRESHOLD;
184
- }
185
-
186
- /**
187
- * Should prompt user for move confirmation
188
- */
189
- static shouldPromptUser(similarity: number): boolean {
190
- return (
191
- similarity >= this.PROMPT_THRESHOLD && similarity < this.AUTO_THRESHOLD
192
- );
193
- }
194
- }
@@ -1,174 +0,0 @@
1
- # Testing Gaps Analysis
2
-
3
- ## Overview
4
-
5
- This document outlines the testing gaps identified in the autosync codebase, particularly around the major architectural changes implemented for directory document management and text CRDT support.
6
-
7
- ## Current Test Coverage
8
-
9
- ✅ **Well Tested:**
10
-
11
- - File system utilities (`test/unit/utils.test.ts`) - 89 test cases
12
- - Snapshot management (`test/unit/snapshot.test.ts`) - Comprehensive coverage
13
- - Content similarity (`test/unit/content-similarity.test.ts`) - Move detection logic
14
- - Integration scenarios (`test/integration/*.test.ts`) - File operations, exclude patterns
15
-
16
- ## Critical Testing Gaps
17
-
18
- ### 1. SyncEngine Core Logic (HIGH PRIORITY)
19
-
20
- **Status:** ❌ No direct unit tests
21
- **Impact:** Core synchronization logic untested
22
-
23
- **Missing Coverage:**
24
-
25
- - `sync()` method with various file scenarios
26
- - `applyLocalChangeToRemote()` / `applyRemoteChangeToLocal()`
27
- - Bidirectional sync flow
28
- - Error handling during sync operations
29
- - Dry run mode functionality
30
-
31
- ### 2. Directory Document Management (HIGH PRIORITY)
32
-
33
- **Status:** ❌ No tests for new feature
34
- **Impact:** New architectural feature completely untested
35
-
36
- **Missing Coverage:**
37
-
38
- - `addFileToRootDirectory()` - Adding files to directory structure
39
- - `removeFileFromRootDirectory()` - Removing files from directory structure
40
- - `setRootDirectoryUrl()` - Root directory URL persistence
41
- - Directory structure synchronization between peers
42
- - Root directory document creation during init
43
-
44
- ### 3. Text CRDT Implementation (MEDIUM PRIORITY)
45
-
46
- **Status:** ❌ No tests for new feature
47
- **Impact:** New text handling functionality untested
48
-
49
- **Missing Coverage:**
50
-
51
- - `isTextContent()` method logic (simplified version)
52
- - Text files using `updateText()` vs binary files using direct assignment
53
- - Mixed content operations in single sync
54
- - Text CRDT conflict resolution behavior
55
-
56
- ### 4. CLI Command Integration (MEDIUM PRIORITY)
57
-
58
- **Status:** ❌ No end-to-end CLI tests
59
- **Impact:** User-facing functionality untested
60
-
61
- **Missing Coverage:**
62
-
63
- - `init` command with directory document creation
64
- - `sync` command full bidirectional flow
65
- - `status`, `diff`, `log` command accuracy
66
- - Error handling in CLI commands
67
- - `--dry-run` flag functionality
68
-
69
- ### 5. Automerge Repository Integration (LOW PRIORITY)
70
-
71
- **Status:** ❌ No Automerge-specific tests
72
- **Impact:** Repository lifecycle and document management untested
73
-
74
- **Missing Coverage:**
75
-
76
- - Document creation and updates
77
- - Repository shutdown behavior
78
- - Document head tracking accuracy
79
- - Network synchronization (mocked)
80
-
81
- ## Technical Challenges
82
-
83
- ### Jest + ES Modules Issue
84
-
85
- **Problem:** `@automerge/automerge-repo` uses ES modules that Jest struggles to handle
86
- **Error:** `SyntaxError: Unexpected token 'export'`
87
-
88
- **Attempted Solutions:**
89
-
90
- - Modified Jest `transformIgnorePatterns`
91
- - Added ES module configuration
92
- - All attempts failed due to complex dependency chain
93
-
94
- ### Recommended Solutions
95
-
96
- #### Option 1: Integration Testing Approach
97
-
98
- Create integration tests that test the full flow without mocking Automerge:
99
-
100
- ```typescript
101
- // test/integration/sync-engine-integration.test.ts
102
- // Test real sync operations with actual Automerge repositories
103
- // Focus on end-to-end behavior rather than unit testing
104
- ```
105
-
106
- #### Option 2: Mock-Heavy Unit Testing
107
-
108
- Create comprehensive mocks for Automerge dependencies:
109
-
110
- ```typescript
111
- // Heavy mocking of @automerge/automerge-repo
112
- // Test SyncEngine logic in isolation
113
- // More fragile but allows unit testing
114
- ```
115
-
116
- #### Option 3: Test Configuration Update
117
-
118
- Update Jest/test environment to properly handle ES modules:
119
-
120
- - Migrate to newer Jest version with better ES module support
121
- - Or switch to alternative test runner (Vitest, etc.)
122
-
123
- ## Immediate Actions Taken
124
-
125
- ### Comprehensive `isTextContent()` Testing
126
-
127
- Since this is a pure function, it can be tested independently:
128
-
129
- ```typescript
130
- // Manual testing confirmed:
131
- // ✅ Strings identified as text
132
- // ✅ Uint8Array identified as binary
133
- // ✅ Edge cases handled correctly
134
- ```
135
-
136
- ### Manual Integration Testing
137
-
138
- Verified through manual CLI testing:
139
-
140
- - ✅ Directory document management working
141
- - ✅ Root directory URL persistence
142
- - ✅ File creation/deletion updates directory structure
143
- - ✅ Text files using updateText(), binary files using direct assignment
144
-
145
- ## Recommendations
146
-
147
- ### Short Term (Implemented)
148
-
149
- 1. ✅ Document testing gaps (this file)
150
- 2. ✅ Manual testing of critical functionality
151
- 3. ✅ Existing test suite still passing (89 tests)
152
-
153
- ### Medium Term (Future Work)
154
-
155
- 1. **Integration Test Suite:** Create `test/integration/sync-engine-e2e.test.ts`
156
- 2. **CLI Testing:** Add end-to-end CLI command testing
157
- 3. **Mock Strategy:** Develop proper Automerge mocking approach
158
-
159
- ### Long Term (Future Work)
160
-
161
- 1. **Test Environment Upgrade:** Resolve ES module handling
162
- 2. **Comprehensive Unit Tests:** Full SyncEngine unit test coverage
163
- 3. **Property-Based Testing:** Add property testing for sync operations
164
-
165
- ## Current Test Status
166
-
167
- - **Total Tests:** 89 passing
168
- - **Test Suites:** 5 passing
169
- - **Coverage:** High for utilities, medium for integration, low for core sync logic
170
- - **Critical Features:** Manually verified but not automatically tested
171
-
172
- ## Conclusion
173
-
174
- While we've identified significant testing gaps around the new features, the existing test suite provides confidence in the foundation. The new features have been manually tested and are working correctly. Future development should prioritize integration testing to cover the areas where unit testing is blocked by ES module issues.
@@ -1,236 +0,0 @@
1
- import { ContentSimilarity } from "../../src/utils/content-similarity";
2
-
3
- describe("ContentSimilarity", () => {
4
- describe("calculateSimilarity", () => {
5
- it("should return 1.0 for identical strings", async () => {
6
- const content1 = "Hello, world!";
7
- const content2 = "Hello, world!";
8
-
9
- const similarity = await ContentSimilarity.calculateSimilarity(
10
- content1,
11
- content2
12
- );
13
-
14
- expect(similarity).toBe(1.0);
15
- });
16
-
17
- it("should return 1.0 for identical binary content", async () => {
18
- const content1 = new Uint8Array([0x00, 0x01, 0x02, 0x03]);
19
- const content2 = new Uint8Array([0x00, 0x01, 0x02, 0x03]);
20
-
21
- const similarity = await ContentSimilarity.calculateSimilarity(
22
- content1,
23
- content2
24
- );
25
-
26
- expect(similarity).toBe(1.0);
27
- });
28
-
29
- it("should return 0.0 for very different content sizes", async () => {
30
- const content1 = "short";
31
- const content2 = "a".repeat(1000); // Much longer
32
-
33
- const similarity = await ContentSimilarity.calculateSimilarity(
34
- content1,
35
- content2
36
- );
37
-
38
- expect(similarity).toBe(0.0);
39
- });
40
-
41
- it("should return high similarity for slightly different content", async () => {
42
- const content1 = "Hello, world!";
43
- const content2 = "Hello, world?";
44
-
45
- const similarity = await ContentSimilarity.calculateSimilarity(
46
- content1,
47
- content2
48
- );
49
-
50
- expect(similarity).toBeGreaterThan(0.9);
51
- expect(similarity).toBeLessThan(1.0);
52
- });
53
-
54
- it("should return low similarity for very different content", async () => {
55
- const content1 = "Hello, world!";
56
- const content2 = "Goodbye, universe!";
57
-
58
- const similarity = await ContentSimilarity.calculateSimilarity(
59
- content1,
60
- content2
61
- );
62
-
63
- expect(similarity).toBeLessThan(0.5);
64
- });
65
-
66
- it("should handle mixed string and binary content", async () => {
67
- const content1 = "Hello, world!";
68
- const content2 = new Uint8Array([0x48, 0x65, 0x6c, 0x6c, 0x6f]); // "Hello" in ASCII
69
-
70
- const similarity = await ContentSimilarity.calculateSimilarity(
71
- content1,
72
- content2
73
- );
74
-
75
- // Mixed content types (string vs binary) should have low similarity
76
- // since binary is converted to hex representation for comparison
77
- expect(similarity).toBe(0.0);
78
- });
79
-
80
- it("should use sampling for large content", async () => {
81
- const content1 =
82
- "a".repeat(10000) + "different middle" + "b".repeat(10000);
83
- const content2 =
84
- "a".repeat(10000) + "same middle here" + "b".repeat(10000);
85
-
86
- const similarity = await ContentSimilarity.calculateSimilarity(
87
- content1,
88
- content2
89
- );
90
-
91
- // Should still detect high similarity due to matching beginning and end
92
- expect(similarity).toBeGreaterThan(0.6);
93
- });
94
-
95
- it("should handle empty content", async () => {
96
- const content1 = "";
97
- const content2 = "not empty";
98
-
99
- const similarity = await ContentSimilarity.calculateSimilarity(
100
- content1,
101
- content2
102
- );
103
-
104
- expect(similarity).toBe(0.0);
105
- });
106
-
107
- it("should return 1.0 for both empty content", async () => {
108
- const content1 = "";
109
- const content2 = "";
110
-
111
- const similarity = await ContentSimilarity.calculateSimilarity(
112
- content1,
113
- content2
114
- );
115
-
116
- expect(similarity).toBe(1.0);
117
- });
118
- });
119
-
120
- describe("getConfidenceLevel", () => {
121
- it("should return auto for high similarity", () => {
122
- expect(ContentSimilarity.getConfidenceLevel(0.9)).toBe("auto");
123
- expect(ContentSimilarity.getConfidenceLevel(0.8)).toBe("auto");
124
- });
125
-
126
- it("should return prompt for medium similarity", () => {
127
- expect(ContentSimilarity.getConfidenceLevel(0.7)).toBe("prompt");
128
- expect(ContentSimilarity.getConfidenceLevel(0.5)).toBe("prompt");
129
- });
130
-
131
- it("should return low for low similarity", () => {
132
- expect(ContentSimilarity.getConfidenceLevel(0.4)).toBe("low");
133
- expect(ContentSimilarity.getConfidenceLevel(0.0)).toBe("low");
134
- });
135
- });
136
-
137
- describe("shouldAutoApply", () => {
138
- it("should return true for high similarity", () => {
139
- expect(ContentSimilarity.shouldAutoApply(0.9)).toBe(true);
140
- expect(ContentSimilarity.shouldAutoApply(0.8)).toBe(true);
141
- });
142
-
143
- it("should return false for medium/low similarity", () => {
144
- expect(ContentSimilarity.shouldAutoApply(0.7)).toBe(false);
145
- expect(ContentSimilarity.shouldAutoApply(0.5)).toBe(false);
146
- expect(ContentSimilarity.shouldAutoApply(0.3)).toBe(false);
147
- });
148
- });
149
-
150
- describe("shouldPromptUser", () => {
151
- it("should return true for medium similarity", () => {
152
- expect(ContentSimilarity.shouldPromptUser(0.7)).toBe(true);
153
- expect(ContentSimilarity.shouldPromptUser(0.6)).toBe(true);
154
- expect(ContentSimilarity.shouldPromptUser(0.5)).toBe(true);
155
- });
156
-
157
- it("should return false for high similarity", () => {
158
- expect(ContentSimilarity.shouldPromptUser(0.9)).toBe(false);
159
- expect(ContentSimilarity.shouldPromptUser(0.8)).toBe(false);
160
- });
161
-
162
- it("should return false for low similarity", () => {
163
- expect(ContentSimilarity.shouldPromptUser(0.4)).toBe(false);
164
- expect(ContentSimilarity.shouldPromptUser(0.3)).toBe(false);
165
- });
166
- });
167
-
168
- describe("edge cases", () => {
169
- it("should handle Unicode content correctly", async () => {
170
- const content1 = "🚀 Hello, 世界!";
171
- const content2 = "🚀 Hello, 世界?";
172
-
173
- const similarity = await ContentSimilarity.calculateSimilarity(
174
- content1,
175
- content2
176
- );
177
-
178
- expect(similarity).toBeGreaterThan(0.9);
179
- });
180
-
181
- it("should handle line breaks and whitespace", async () => {
182
- const content1 = "Line 1\nLine 2\nLine 3";
183
- const content2 = "Line 1\r\nLine 2\r\nLine 3";
184
-
185
- const similarity = await ContentSimilarity.calculateSimilarity(
186
- content1,
187
- content2
188
- );
189
-
190
- expect(similarity).toBeGreaterThan(0.8);
191
- });
192
-
193
- it("should handle very small content differences", async () => {
194
- const content1 = "a";
195
- const content2 = "b";
196
-
197
- const similarity = await ContentSimilarity.calculateSimilarity(
198
- content1,
199
- content2
200
- );
201
-
202
- expect(similarity).toBe(0.0); // Single character, completely different
203
- });
204
-
205
- it("should handle binary data with patterns", async () => {
206
- const content1 = new Uint8Array([0x00, 0x01, 0x02, 0x03, 0x04, 0x05]);
207
- const content2 = new Uint8Array([0x00, 0x01, 0x02, 0xff, 0x04, 0x05]);
208
-
209
- const similarity = await ContentSimilarity.calculateSimilarity(
210
- content1,
211
- content2
212
- );
213
-
214
- expect(similarity).toBeGreaterThan(0.5); // Most bytes are the same
215
- expect(similarity).toBeLessThan(1.0);
216
- });
217
- });
218
-
219
- describe("performance characteristics", () => {
220
- it("should handle reasonably large files efficiently", async () => {
221
- const size = 100000; // 100KB
222
- const content1 = "a".repeat(size);
223
- const content2 = "a".repeat(size - 10) + "b".repeat(10);
224
-
225
- const startTime = Date.now();
226
- const similarity = await ContentSimilarity.calculateSimilarity(
227
- content1,
228
- content2
229
- );
230
- const duration = Date.now() - startTime;
231
-
232
- expect(similarity).toBeGreaterThan(0.8);
233
- expect(duration).toBeLessThan(1000); // Should complete within 1 second
234
- }, 10000); // 10 second timeout for this test
235
- });
236
- });