stigmergy 1.1.6 โ 1.2.0
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.
- package/package.json +14 -27
- package/scripts/preinstall-check.js +78 -16
- package/src/cli/router.js +375 -29
- package/src/core/cache_cleaner.js +744 -0
- package/src/core/cli_tools.js +1 -1
- package/src/core/enhanced_installer.js +456 -0
- package/src/core/enhanced_uninstaller.js +618 -0
- package/src/core/installer.js +1 -0
- package/src/core/upgrade_manager.js +403 -0
- package/test/cache-cleaner-implemented.test.js +328 -0
- package/test/cache-cleaner.test.js +390 -0
- package/test/comprehensive-enhanced-features.test.js +252 -0
- package/test/enhanced-uninstaller-implemented.test.js +271 -0
- package/test/enhanced-uninstaller.test.js +284 -0
- package/test/plugin-deployment-test.js +1 -1
- package/test/safe-installation-cleaner.test.js +343 -0
- package/test/stigmergy-upgrade-test.js +243 -0
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Implementation Tests for Enhanced Stigmergy Uninstaller
|
|
3
|
+
*
|
|
4
|
+
* Tests that verify the actual implementation works correctly
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const fs = require('fs');
|
|
8
|
+
const path = require('path');
|
|
9
|
+
const os = require('os');
|
|
10
|
+
const EnhancedUninstaller = require('../src/core/enhanced_uninstaller');
|
|
11
|
+
|
|
12
|
+
class EnhancedUninstallerImplementationTests {
|
|
13
|
+
constructor() {
|
|
14
|
+
this.testDir = path.join(os.tmpdir(), 'stigmergy-uninstaller-impl-test');
|
|
15
|
+
this.configDir = path.join(this.testDir, '.stigmergy');
|
|
16
|
+
this.testConfigDir = path.join(this.testDir, '.stigmergy-test');
|
|
17
|
+
this.testResults = [];
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
async runAllTests() {
|
|
21
|
+
console.log('๐งช Running Enhanced Uninstaller Implementation Tests...\n');
|
|
22
|
+
|
|
23
|
+
await this.setupTestEnvironment();
|
|
24
|
+
|
|
25
|
+
try {
|
|
26
|
+
await this.testDryRunMode();
|
|
27
|
+
await this.testCompleteUninstall();
|
|
28
|
+
await this.testErrorHandling();
|
|
29
|
+
await this.testDirectoryScanning();
|
|
30
|
+
await this.testFilePatternMatching();
|
|
31
|
+
|
|
32
|
+
this.printResults();
|
|
33
|
+
} finally {
|
|
34
|
+
await this.cleanupTestEnvironment();
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
async setupTestEnvironment() {
|
|
39
|
+
console.log('๐ Setting up implementation test environment...');
|
|
40
|
+
|
|
41
|
+
// Create test directories
|
|
42
|
+
fs.mkdirSync(this.configDir, { recursive: true });
|
|
43
|
+
fs.mkdirSync(this.testConfigDir, { recursive: true });
|
|
44
|
+
|
|
45
|
+
// Create mock configuration files
|
|
46
|
+
fs.writeFileSync(path.join(this.configDir, 'config.json'), JSON.stringify({
|
|
47
|
+
version: '1.1.8',
|
|
48
|
+
clis: ['claude', 'gemini', 'qwen']
|
|
49
|
+
}, null, 2));
|
|
50
|
+
|
|
51
|
+
fs.writeFileSync(path.join(this.configDir, 'auth.json'), JSON.stringify({
|
|
52
|
+
tokens: { mock: 'token' }
|
|
53
|
+
}, null, 2));
|
|
54
|
+
|
|
55
|
+
fs.writeFileSync(path.join(this.configDir, 'error.log'), 'Mock error log\n');
|
|
56
|
+
|
|
57
|
+
// Create mock hooks directory
|
|
58
|
+
const hooksDir = path.join(this.configDir, 'hooks');
|
|
59
|
+
fs.mkdirSync(hooksDir, { recursive: true });
|
|
60
|
+
|
|
61
|
+
['claude', 'gemini', 'qwen'].forEach(cli => {
|
|
62
|
+
const cliHookDir = path.join(hooksDir, cli);
|
|
63
|
+
fs.mkdirSync(cliHookDir, { recursive: true });
|
|
64
|
+
fs.writeFileSync(path.join(cliHookDir, `${cli}_nodejs_hook.js`), '// Mock hook');
|
|
65
|
+
fs.writeFileSync(path.join(cliHookDir, 'config.json'), '{}');
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
console.log('โ
Implementation test environment setup complete\n');
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
async testDryRunMode() {
|
|
72
|
+
console.log('๐ TEST 1: Dry Run Mode');
|
|
73
|
+
|
|
74
|
+
const uninstaller = new EnhancedUninstaller({
|
|
75
|
+
dryRun: true,
|
|
76
|
+
verbose: true
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
// Verify files exist before dry run
|
|
80
|
+
const configExists = fs.existsSync(this.configDir);
|
|
81
|
+
this.assert(configExists, 'Test configuration should exist before uninstall');
|
|
82
|
+
|
|
83
|
+
// Run dry uninstall
|
|
84
|
+
const results = await uninstaller.completeUninstall();
|
|
85
|
+
|
|
86
|
+
// Verify files still exist after dry run
|
|
87
|
+
const configStillExists = fs.existsSync(this.configDir);
|
|
88
|
+
this.assert(configStillExists, 'Configuration should still exist after dry run');
|
|
89
|
+
|
|
90
|
+
// Verify dry run detected files
|
|
91
|
+
this.assert(results.filesRemoved === 0, 'Dry run should not remove files');
|
|
92
|
+
this.assert(results.directoriesRemoved === 0, 'Dry run should not remove directories');
|
|
93
|
+
|
|
94
|
+
this.recordResult('Dry Run Mode', 'โ
');
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
async testCompleteUninstall() {
|
|
98
|
+
console.log('๐๏ธ TEST 2: Complete Uninstall');
|
|
99
|
+
|
|
100
|
+
// Recreate test environment
|
|
101
|
+
await this.setupTestEnvironment();
|
|
102
|
+
|
|
103
|
+
const uninstaller = new EnhancedUninstaller({
|
|
104
|
+
dryRun: false,
|
|
105
|
+
verbose: false
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
// Verify files exist before uninstall
|
|
109
|
+
const beforeFiles = [
|
|
110
|
+
path.join(this.configDir, 'config.json'),
|
|
111
|
+
path.join(this.configDir, 'auth.json'),
|
|
112
|
+
path.join(this.configDir, 'error.log'),
|
|
113
|
+
path.join(this.configDir, 'hooks', 'claude', 'claude_nodejs_hook.js')
|
|
114
|
+
];
|
|
115
|
+
|
|
116
|
+
const beforeUninstall = beforeFiles.every(file => fs.existsSync(file));
|
|
117
|
+
this.assert(beforeUninstall, 'Test files should exist before uninstall');
|
|
118
|
+
|
|
119
|
+
// Run complete uninstall
|
|
120
|
+
const results = await uninstaller.completeUninstall();
|
|
121
|
+
|
|
122
|
+
// Verify cleanup after uninstall
|
|
123
|
+
const afterUninstall = !beforeFiles.some(file => fs.existsSync(file));
|
|
124
|
+
this.assert(afterUninstall, 'All Stigmergy files should be removed after uninstall');
|
|
125
|
+
|
|
126
|
+
// Verify results
|
|
127
|
+
this.assert(results.filesRemoved > 0, 'Should report files removed');
|
|
128
|
+
this.assert(results.directoriesRemoved >= 0, 'Should report directories removed');
|
|
129
|
+
|
|
130
|
+
this.recordResult('Complete Uninstall', 'โ
');
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
async testErrorHandling() {
|
|
134
|
+
console.log('โ ๏ธ TEST 3: Error Handling');
|
|
135
|
+
|
|
136
|
+
const uninstaller = new EnhancedUninstaller({
|
|
137
|
+
force: true,
|
|
138
|
+
dryRun: true
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
// Test with non-existent directory
|
|
142
|
+
const nonExistentPath = path.join(this.testDir, 'does-not-exist');
|
|
143
|
+
|
|
144
|
+
// Should handle missing directory gracefully
|
|
145
|
+
const plan = await uninstaller.createUninstallPlan();
|
|
146
|
+
|
|
147
|
+
// Should not crash on missing directories
|
|
148
|
+
this.assert(plan !== undefined, 'Should handle missing directories gracefully');
|
|
149
|
+
|
|
150
|
+
// Test uninstall with non-existent paths
|
|
151
|
+
const results = await uninstaller.completeUninstall();
|
|
152
|
+
|
|
153
|
+
// Should not report errors for non-existent files in dry run
|
|
154
|
+
this.assert(Array.isArray(results.errors), 'Should return error array');
|
|
155
|
+
|
|
156
|
+
this.recordResult('Error Handling', 'โ
');
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
async testDirectoryScanning() {
|
|
160
|
+
console.log('๐ TEST 4: Directory Scanning');
|
|
161
|
+
|
|
162
|
+
// Create a more complex directory structure
|
|
163
|
+
const complexDir = path.join(this.testDir, '.stigmergy-complex');
|
|
164
|
+
fs.mkdirSync(complexDir, { recursive: true });
|
|
165
|
+
|
|
166
|
+
fs.mkdirSync(path.join(complexDir, 'subdir1'), { recursive: true });
|
|
167
|
+
fs.mkdirSync(path.join(complexDir, 'subdir2'), { recursive: true });
|
|
168
|
+
|
|
169
|
+
fs.writeFileSync(path.join(complexDir, 'file1.txt'), 'content');
|
|
170
|
+
fs.writeFileSync(path.join(complexDir, 'subdir1', 'file2.txt'), 'content');
|
|
171
|
+
fs.writeFileSync(path.join(complexDir, 'subdir2', 'file3.txt'), 'content');
|
|
172
|
+
|
|
173
|
+
const uninstaller = new EnhancedUninstaller({ dryRun: true });
|
|
174
|
+
|
|
175
|
+
// Test plan creation
|
|
176
|
+
const plan = await uninstaller.createUninstallPlan();
|
|
177
|
+
|
|
178
|
+
// Should scan directories correctly
|
|
179
|
+
this.assert(plan.files.length > 0, 'Should find files in directory scan');
|
|
180
|
+
this.assert(plan.directories.length > 0, 'Should find directories in scan');
|
|
181
|
+
|
|
182
|
+
// Clean up
|
|
183
|
+
fs.rmSync(complexDir, { recursive: true, force: true });
|
|
184
|
+
|
|
185
|
+
this.recordResult('Directory Scanning', 'โ
');
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
async testFilePatternMatching() {
|
|
189
|
+
console.log('๐ฏ TEST 5: File Pattern Matching');
|
|
190
|
+
|
|
191
|
+
const uninstaller = new EnhancedUninstaller({ dryRun: true });
|
|
192
|
+
|
|
193
|
+
// Test internal pattern matching methods
|
|
194
|
+
const testFiles = [
|
|
195
|
+
'stigmergy-config.json',
|
|
196
|
+
'cross-cli-hook.js',
|
|
197
|
+
'integration-settings.json',
|
|
198
|
+
'cache-data.tmp',
|
|
199
|
+
'normal-file.txt'
|
|
200
|
+
];
|
|
201
|
+
|
|
202
|
+
// Test if methods exist and work
|
|
203
|
+
let stigmergyFilesFound = 0;
|
|
204
|
+
|
|
205
|
+
for (const fileName of testFiles) {
|
|
206
|
+
if (uninstaller.isStigmergyFile && uninstaller.isStigmergyFile(fileName)) {
|
|
207
|
+
stigmergyFilesFound++;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
this.assert(stigmergyFilesFound >= 4, 'Should identify Stigmergy files correctly');
|
|
212
|
+
|
|
213
|
+
this.recordResult('File Pattern Matching', 'โ
');
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
assert(condition, message) {
|
|
217
|
+
if (condition) {
|
|
218
|
+
console.log(` โ
${message}`);
|
|
219
|
+
} else {
|
|
220
|
+
console.log(` โ ${message}`);
|
|
221
|
+
throw new Error(`Assertion failed: ${message}`);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
recordResult(testName, status) {
|
|
226
|
+
this.testResults.push({ name: testName, status });
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
printResults() {
|
|
230
|
+
console.log('\n๐ IMPLEMENTATION TEST RESULTS:');
|
|
231
|
+
console.log('=' .repeat(50));
|
|
232
|
+
|
|
233
|
+
this.testResults.forEach(result => {
|
|
234
|
+
console.log(`${result.status} ${result.name}`);
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
const passed = this.testResults.filter(r => r.status === 'โ
').length;
|
|
238
|
+
const total = this.testResults.length;
|
|
239
|
+
|
|
240
|
+
console.log('\n๐ Summary:');
|
|
241
|
+
console.log(`Total tests: ${total}`);
|
|
242
|
+
console.log(`Passed: ${passed}`);
|
|
243
|
+
console.log(`Failed: ${total - passed}`);
|
|
244
|
+
|
|
245
|
+
if (passed === total) {
|
|
246
|
+
console.log('\n๐ All implementation tests passed!');
|
|
247
|
+
console.log('โ
Enhanced uninstaller is working correctly!');
|
|
248
|
+
} else {
|
|
249
|
+
console.log('\nโ Some tests failed. Review the implementation.');
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
async cleanupTestEnvironment() {
|
|
254
|
+
console.log('\n๐งน Cleaning up implementation test environment...');
|
|
255
|
+
|
|
256
|
+
try {
|
|
257
|
+
fs.rmSync(this.testDir, { recursive: true, force: true });
|
|
258
|
+
console.log('โ
Implementation test environment cleaned up');
|
|
259
|
+
} catch (error) {
|
|
260
|
+
console.warn('โ ๏ธ Warning: Could not clean up test environment:', error.message);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// Run tests if this file is executed directly
|
|
266
|
+
if (require.main === module) {
|
|
267
|
+
const tests = new EnhancedUninstallerImplementationTests();
|
|
268
|
+
tests.runAllTests().catch(console.error);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
module.exports = EnhancedUninstallerImplementationTests;
|
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TDD Tests for Enhanced Stigmergy Uninstaller
|
|
3
|
+
*
|
|
4
|
+
* Test-first approach to ensure complete cleanup of Stigmergy installation
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const fs = require('fs');
|
|
8
|
+
const path = require('path');
|
|
9
|
+
const os = require('os');
|
|
10
|
+
const { spawnSync } = require('child_process');
|
|
11
|
+
|
|
12
|
+
class EnhancedUninstallerTests {
|
|
13
|
+
constructor() {
|
|
14
|
+
this.testDir = path.join(os.tmpdir(), 'stigmergy-uninstaller-test');
|
|
15
|
+
this.configDir = path.join(this.testDir, '.stigmergy');
|
|
16
|
+
this.testConfigDir = path.join(this.testDir, '.stigmergy-test');
|
|
17
|
+
this.npmCacheDir = path.join(this.testDir, 'npm-cache');
|
|
18
|
+
this.testResults = [];
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
async runAllTests() {
|
|
22
|
+
console.log('๐งช Running Enhanced Uninstaller TDD Tests...\n');
|
|
23
|
+
|
|
24
|
+
await this.setupTestEnvironment();
|
|
25
|
+
|
|
26
|
+
try {
|
|
27
|
+
await this.testCompleteUninstall();
|
|
28
|
+
await this.testCacheCleaning();
|
|
29
|
+
await this.testNPXCacheCleaning();
|
|
30
|
+
await this.testCLIConfigCleanup();
|
|
31
|
+
await this.testErrorHandling();
|
|
32
|
+
await this.testDryRunMode();
|
|
33
|
+
|
|
34
|
+
this.printResults();
|
|
35
|
+
} finally {
|
|
36
|
+
await this.cleanupTestEnvironment();
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async setupTestEnvironment() {
|
|
41
|
+
console.log('๐ Setting up test environment...');
|
|
42
|
+
|
|
43
|
+
// Create test directories
|
|
44
|
+
fs.mkdirSync(this.configDir, { recursive: true });
|
|
45
|
+
fs.mkdirSync(this.testConfigDir, { recursive: true });
|
|
46
|
+
fs.mkdirSync(this.npmCacheDir, { recursive: true });
|
|
47
|
+
|
|
48
|
+
// Create mock configuration files
|
|
49
|
+
fs.writeFileSync(path.join(this.configDir, 'config.json'), JSON.stringify({
|
|
50
|
+
version: '1.1.8',
|
|
51
|
+
clis: ['claude', 'gemini', 'qwen']
|
|
52
|
+
}, null, 2));
|
|
53
|
+
|
|
54
|
+
fs.writeFileSync(path.join(this.configDir, 'auth.json'), JSON.stringify({
|
|
55
|
+
tokens: { mock: 'token' }
|
|
56
|
+
}, null, 2));
|
|
57
|
+
|
|
58
|
+
fs.writeFileSync(path.join(this.configDir, 'error.log'), 'Mock error log\n');
|
|
59
|
+
|
|
60
|
+
// Create mock hooks directory
|
|
61
|
+
const hooksDir = path.join(this.configDir, 'hooks');
|
|
62
|
+
fs.mkdirSync(hooksDir, { recursive: true });
|
|
63
|
+
|
|
64
|
+
['claude', 'gemini', 'qwen'].forEach(cli => {
|
|
65
|
+
const cliHookDir = path.join(hooksDir, cli);
|
|
66
|
+
fs.mkdirSync(cliHookDir, { recursive: true });
|
|
67
|
+
fs.writeFileSync(path.join(cliHookDir, `${cli}_nodejs_hook.js`), '// Mock hook');
|
|
68
|
+
fs.writeFileSync(path.join(cliHookDir, 'config.json'), '{}');
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
// Create mock CLI config directories
|
|
72
|
+
['claude', 'gemini', 'qwen'].forEach(cli => {
|
|
73
|
+
const cliConfig = path.join(this.testDir, `.${cli}`);
|
|
74
|
+
fs.mkdirSync(cliConfig, { recursive: true });
|
|
75
|
+
fs.writeFileSync(path.join(cliConfig, 'stigmergy-config.json'), '{}');
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
// Create mock npm cache files
|
|
79
|
+
const npxCacheDir = path.join(this.npmCacheDir, '_npx');
|
|
80
|
+
fs.mkdirSync(npxCacheDir, { recursive: true });
|
|
81
|
+
fs.mkdirSync(path.join(npxCacheDir, 'mock-cache-id'), { recursive: true });
|
|
82
|
+
|
|
83
|
+
console.log('โ
Test environment setup complete\n');
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
async testCompleteUninstall() {
|
|
87
|
+
console.log('๐ TEST 1: Complete Uninstall Functionality');
|
|
88
|
+
|
|
89
|
+
const expectedFiles = [
|
|
90
|
+
path.join(this.configDir, 'config.json'),
|
|
91
|
+
path.join(this.configDir, 'auth.json'),
|
|
92
|
+
path.join(this.configDir, 'error.log'),
|
|
93
|
+
path.join(this.configDir, 'hooks', 'claude', 'claude_nodejs_hook.js')
|
|
94
|
+
];
|
|
95
|
+
|
|
96
|
+
// Verify test files exist before uninstall
|
|
97
|
+
const beforeUninstall = expectedFiles.every(file => fs.existsSync(file));
|
|
98
|
+
this.assert(beforeUninstall, 'Test files should exist before uninstall');
|
|
99
|
+
|
|
100
|
+
// TODO: After implementing EnhancedUninstaller, call it here
|
|
101
|
+
// const uninstaller = new EnhancedUninstaller();
|
|
102
|
+
// await uninstaller.completeUninstall({ dryRun: false, testMode: true });
|
|
103
|
+
|
|
104
|
+
// TODO: Verify cleanup after uninstall
|
|
105
|
+
// const afterUninstall = !expectedFiles.some(file => fs.existsSync(file));
|
|
106
|
+
// this.assert(afterUninstall, 'All Stigmergy files should be removed after uninstall');
|
|
107
|
+
|
|
108
|
+
this.recordResult('Complete Uninstall', 'โณ Pending implementation');
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
async testCacheCleaning() {
|
|
112
|
+
console.log('๐งน TEST 2: Cache Cleaning Functionality');
|
|
113
|
+
|
|
114
|
+
// Mock cache files
|
|
115
|
+
const cacheFiles = [
|
|
116
|
+
path.join(this.configDir, 'cache', 'test-cache.json'),
|
|
117
|
+
path.join(this.configDir, 'memory.json')
|
|
118
|
+
];
|
|
119
|
+
|
|
120
|
+
cacheFiles.forEach(file => {
|
|
121
|
+
const dir = path.dirname(file);
|
|
122
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
123
|
+
fs.writeFileSync(file, 'mock cache data');
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
// Verify cache files exist
|
|
127
|
+
const beforeCleanup = cacheFiles.every(file => fs.existsSync(file));
|
|
128
|
+
this.assert(beforeCleanup, 'Cache files should exist before cleanup');
|
|
129
|
+
|
|
130
|
+
// TODO: After implementing cache cleaner
|
|
131
|
+
// const cleaner = new CacheCleaner();
|
|
132
|
+
// await cleaner.cleanAllCaches({ includeStigmergy: true, includeNPM: false });
|
|
133
|
+
|
|
134
|
+
// TODO: Verify cache files are removed
|
|
135
|
+
// const afterCleanup = !cacheFiles.some(file => fs.existsSync(file));
|
|
136
|
+
// this.assert(afterCleanup, 'Cache files should be removed after cleanup');
|
|
137
|
+
|
|
138
|
+
this.recordResult('Cache Cleaning', 'โณ Pending implementation');
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
async testNPXCacheCleaning() {
|
|
142
|
+
console.log('๐ฆ TEST 3: NPX Cache Cleaning');
|
|
143
|
+
|
|
144
|
+
// Create mock npx cache
|
|
145
|
+
const npxCachePath = path.join(this.npmCacheDir, '_npx', 'test-cache-id', 'node_modules', 'stigmergy');
|
|
146
|
+
fs.mkdirSync(npxCachePath, { recursive: true });
|
|
147
|
+
fs.writeFileSync(path.join(npxCachePath, 'package.json'), '{}');
|
|
148
|
+
|
|
149
|
+
// Verify npx cache exists
|
|
150
|
+
const beforeCleanup = fs.existsSync(npxCachePath);
|
|
151
|
+
this.assert(beforeCleanup, 'NPX cache should exist before cleanup');
|
|
152
|
+
|
|
153
|
+
// TODO: After implementing NPX cache cleaner
|
|
154
|
+
// const cleaner = new NPXCacheCleaner();
|
|
155
|
+
// const removed = await cleaner.cleanStigmergyFromNPXCache();
|
|
156
|
+
// this.assert(removed > 0, 'Should remove Stigmergy from NPX cache');
|
|
157
|
+
|
|
158
|
+
this.recordResult('NPX Cache Cleaning', 'โณ Pending implementation');
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
async testCLIConfigCleanup() {
|
|
162
|
+
console.log('โ๏ธ TEST 4: CLI Configuration Cleanup');
|
|
163
|
+
|
|
164
|
+
const cliConfigs = ['claude', 'gemini', 'qwen'].map(cli => ({
|
|
165
|
+
cli,
|
|
166
|
+
configPath: path.join(this.testDir, `.${cli}`, 'stigmergy-config.json'),
|
|
167
|
+
hooksPath: path.join(this.testDir, `.${cli}`, 'hooks', 'stigmergy')
|
|
168
|
+
}));
|
|
169
|
+
|
|
170
|
+
// Create mock CLI hooks
|
|
171
|
+
cliConfigs.forEach(config => {
|
|
172
|
+
fs.mkdirSync(path.dirname(config.hooksPath), { recursive: true });
|
|
173
|
+
fs.writeFileSync(config.hooksPath, '// mock hook');
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
// Verify CLI configs exist
|
|
177
|
+
const beforeCleanup = cliConfigs.every(config =>
|
|
178
|
+
fs.existsSync(config.configPath) || fs.existsSync(config.hooksPath)
|
|
179
|
+
);
|
|
180
|
+
this.assert(beforeCleanup, 'CLI configurations should exist before cleanup');
|
|
181
|
+
|
|
182
|
+
// TODO: After implementing CLI config cleaner
|
|
183
|
+
// const cleaner = new CLIConfigCleaner();
|
|
184
|
+
// const results = await cleaner.cleanCLIConfigurations(['claude', 'gemini', 'qwen']);
|
|
185
|
+
// this.assert(results.cleaned > 0, 'Should clean CLI configurations');
|
|
186
|
+
|
|
187
|
+
this.recordResult('CLI Config Cleanup', 'โณ Pending implementation');
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
async testErrorHandling() {
|
|
191
|
+
console.log('โ ๏ธ TEST 5: Error Handling');
|
|
192
|
+
|
|
193
|
+
// Test with non-existent directory
|
|
194
|
+
const nonExistentPath = path.join(this.testDir, 'does-not-exist');
|
|
195
|
+
|
|
196
|
+
// TODO: Test error handling for various scenarios
|
|
197
|
+
// const uninstaller = new EnhancedUninstaller();
|
|
198
|
+
|
|
199
|
+
// Should handle missing directory gracefully
|
|
200
|
+
// const result1 = await uninstaller.removeDirectory(nonExistentPath);
|
|
201
|
+
// this.assert(!result1.error, 'Should handle missing directory gracefully');
|
|
202
|
+
|
|
203
|
+
// Should handle permission denied gracefully
|
|
204
|
+
// const result2 = await uninstaller.removeDirectory('/root/protected');
|
|
205
|
+
// this.assert(result2.error, 'Should detect permission errors');
|
|
206
|
+
|
|
207
|
+
this.recordResult('Error Handling', 'โณ Pending implementation');
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
async testDryRunMode() {
|
|
211
|
+
console.log('๐ TEST 6: Dry Run Mode');
|
|
212
|
+
|
|
213
|
+
// Create files that should be preserved in dry run
|
|
214
|
+
const testFile = path.join(this.configDir, 'should-preserve.txt');
|
|
215
|
+
fs.writeFileSync(testFile, 'preserve me');
|
|
216
|
+
|
|
217
|
+
// TODO: Test dry run functionality
|
|
218
|
+
// const uninstaller = new EnhancedUninstaller();
|
|
219
|
+
// const plan = await uninstaller.createUninstallPlan({ dryRun: true });
|
|
220
|
+
|
|
221
|
+
// Should return what would be deleted
|
|
222
|
+
// this.assert(plan.files.length > 0, 'Should identify files to delete');
|
|
223
|
+
|
|
224
|
+
// Should not actually delete files in dry run
|
|
225
|
+
// const stillExists = fs.existsSync(testFile);
|
|
226
|
+
// this.assert(stillExists, 'Files should not be deleted in dry run mode');
|
|
227
|
+
|
|
228
|
+
this.recordResult('Dry Run Mode', 'โณ Pending implementation');
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
async cleanupTestEnvironment() {
|
|
232
|
+
console.log('\n๐งน Cleaning up test environment...');
|
|
233
|
+
|
|
234
|
+
try {
|
|
235
|
+
fs.rmSync(this.testDir, { recursive: true, force: true });
|
|
236
|
+
console.log('โ
Test environment cleaned up');
|
|
237
|
+
} catch (error) {
|
|
238
|
+
console.warn('โ ๏ธ Warning: Could not clean up test environment:', error.message);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
assert(condition, message) {
|
|
243
|
+
if (condition) {
|
|
244
|
+
console.log(` โ
${message}`);
|
|
245
|
+
} else {
|
|
246
|
+
console.log(` โ ${message}`);
|
|
247
|
+
throw new Error(`Assertion failed: ${message}`);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
recordResult(testName, status) {
|
|
252
|
+
this.testResults.push({ name: testName, status });
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
printResults() {
|
|
256
|
+
console.log('\n๐ TEST RESULTS:');
|
|
257
|
+
console.log('=' .repeat(50));
|
|
258
|
+
|
|
259
|
+
this.testResults.forEach(result => {
|
|
260
|
+
console.log(`${result.status} ${result.name}`);
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
const pending = this.testResults.filter(r => r.status.includes('Pending')).length;
|
|
264
|
+
const total = this.testResults.length;
|
|
265
|
+
|
|
266
|
+
console.log('\n๐ Summary:');
|
|
267
|
+
console.log(`Total tests: ${total}`);
|
|
268
|
+
console.log(`Pending implementation: ${pending}`);
|
|
269
|
+
console.log(`Ready for implementation: ${pending}/${total}`);
|
|
270
|
+
|
|
271
|
+
if (pending === total) {
|
|
272
|
+
console.log('\n๐ All test cases defined successfully!');
|
|
273
|
+
console.log('๐ก Ready to implement the enhanced uninstaller functionality.');
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// Run tests if this file is executed directly
|
|
279
|
+
if (require.main === module) {
|
|
280
|
+
const tests = new EnhancedUninstallerTests();
|
|
281
|
+
tests.runAllTests().catch(console.error);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
module.exports = EnhancedUninstallerTests;
|
|
@@ -29,7 +29,7 @@ const CLI_TOOLS = {
|
|
|
29
29
|
qwen: {
|
|
30
30
|
name: 'Qwen CLI',
|
|
31
31
|
version: 'qwen --version',
|
|
32
|
-
install: 'npm install -g @
|
|
32
|
+
install: 'npm install -g @qwen-code/qwen-code',
|
|
33
33
|
hooksDir: path.join(os.homedir(), '.qwen', 'hooks'),
|
|
34
34
|
config: path.join(os.homedir(), '.qwen', 'config.json')
|
|
35
35
|
},
|