Skip to content

Commit 88507c3

Browse files
committed
✨ feat: update test entry points to support wildcard and add configuration service tests
1 parent 5131db0 commit 88507c3

File tree

3 files changed

+288
-1
lines changed

3 files changed

+288
-1
lines changed

esbuild.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ async function main() {
6060

6161
// Build tests
6262
const testCtx = await esbuild.context({
63-
entryPoints: ['src/test/extension.test.ts'],
63+
entryPoints: ['src/test/*.test.ts'],
6464
bundle: true,
6565
format: 'cjs',
6666
minify: false,
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
/*
2+
* This file is part of the vscode-ddev-phpmd extension.
3+
*
4+
* © OpenForgeProject
5+
*
6+
* This program is free software: you can redistribute it and/or modify
7+
* it under the terms of the GNU General Public License as published by
8+
* the Free Software Foundation, either version 3 of the License, or
9+
* (at your option) any later version.
10+
*
11+
* This program is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
* GNU General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU General Public License
17+
* along with this program. If not, see <https://www.gnu.org/licenses/>.
18+
*/
19+
20+
import * as assert from 'assert';
21+
import * as vscode from 'vscode';
22+
import * as sinon from 'sinon';
23+
import { afterEach, beforeEach } from 'mocha';
24+
import { ConfigurationService } from '../services/configuration-service';
25+
import { DEFAULT_CONFIG } from '../models/configuration';
26+
27+
suite('ConfigurationService Test Suite', () => {
28+
let sandbox: sinon.SinonSandbox;
29+
let getConfigurationStub: sinon.SinonStub;
30+
let mockConfiguration: any;
31+
32+
beforeEach(() => {
33+
sandbox = sinon.createSandbox();
34+
35+
// Mock configuration object
36+
mockConfiguration = {
37+
get: sandbox.stub(),
38+
update: sandbox.stub().resolves()
39+
};
40+
41+
// Mock workspace.getConfiguration
42+
getConfigurationStub = sandbox.stub(vscode.workspace, 'getConfiguration').returns(mockConfiguration);
43+
});
44+
45+
afterEach(() => {
46+
sandbox.restore();
47+
});
48+
49+
test('getConfig returns default configuration when no settings are found', () => {
50+
// Setup mocks to return undefined (no user settings)
51+
mockConfiguration.get.withArgs('enable', DEFAULT_CONFIG.enable).returns(DEFAULT_CONFIG.enable);
52+
mockConfiguration.get.withArgs('validateOn', DEFAULT_CONFIG.validateOn).returns(DEFAULT_CONFIG.validateOn);
53+
mockConfiguration.get.withArgs('rulesets', DEFAULT_CONFIG.rulesets).returns(DEFAULT_CONFIG.rulesets);
54+
mockConfiguration.get.withArgs('minSeverity', DEFAULT_CONFIG.minSeverity).returns(DEFAULT_CONFIG.minSeverity);
55+
mockConfiguration.get.withArgs('configPath', DEFAULT_CONFIG.configPath).returns(DEFAULT_CONFIG.configPath);
56+
57+
const config = ConfigurationService.getConfig();
58+
59+
assert.deepStrictEqual(config, DEFAULT_CONFIG);
60+
assert.strictEqual(getConfigurationStub.calledWith('ddev-phpmd'), true);
61+
});
62+
63+
test('getConfig returns custom configuration when settings are overridden', () => {
64+
const customConfig = {
65+
enable: false,
66+
validateOn: 'type',
67+
rulesets: ['naming', 'codesize'],
68+
minSeverity: 'error',
69+
configPath: 'custom/phpmd.xml'
70+
};
71+
72+
// Setup mocks to return custom values
73+
mockConfiguration.get.withArgs('enable', DEFAULT_CONFIG.enable).returns(customConfig.enable);
74+
mockConfiguration.get.withArgs('validateOn', DEFAULT_CONFIG.validateOn).returns(customConfig.validateOn);
75+
mockConfiguration.get.withArgs('rulesets', DEFAULT_CONFIG.rulesets).returns(customConfig.rulesets);
76+
mockConfiguration.get.withArgs('minSeverity', DEFAULT_CONFIG.minSeverity).returns(customConfig.minSeverity);
77+
mockConfiguration.get.withArgs('configPath', DEFAULT_CONFIG.configPath).returns(customConfig.configPath);
78+
79+
const config = ConfigurationService.getConfig();
80+
81+
assert.deepStrictEqual(config, customConfig);
82+
});
83+
84+
test('updateConfig calls workspace configuration update with correct parameters', async () => {
85+
await ConfigurationService.updateConfig('enable', false);
86+
87+
assert.strictEqual(getConfigurationStub.calledWith('ddev-phpmd'), true);
88+
assert.strictEqual(mockConfiguration.update.calledWith('enable', false, vscode.ConfigurationTarget.Workspace), true);
89+
});
90+
91+
test('updateConfig accepts custom configuration target', async () => {
92+
await ConfigurationService.updateConfig('minSeverity', 'info', vscode.ConfigurationTarget.Global);
93+
94+
assert.strictEqual(mockConfiguration.update.calledWith('minSeverity', 'info', vscode.ConfigurationTarget.Global), true);
95+
});
96+
97+
test('affectsConfiguration returns true for matching section', () => {
98+
const mockEvent = {
99+
affectsConfiguration: sandbox.stub().returns(true)
100+
} as any;
101+
102+
const result = ConfigurationService.affectsConfiguration(mockEvent);
103+
104+
assert.strictEqual(result, true);
105+
assert.strictEqual(mockEvent.affectsConfiguration.calledWith('ddev-phpmd'), true);
106+
});
107+
108+
test('affectsConfiguration returns true for matching subsection', () => {
109+
const mockEvent = {
110+
affectsConfiguration: sandbox.stub().returns(true)
111+
} as any;
112+
113+
const result = ConfigurationService.affectsConfiguration(mockEvent, 'enable');
114+
115+
assert.strictEqual(result, true);
116+
assert.strictEqual(mockEvent.affectsConfiguration.calledWith('ddev-phpmd.enable'), true);
117+
});
118+
119+
test('affectsConfiguration returns false for non-matching section', () => {
120+
const mockEvent = {
121+
affectsConfiguration: sandbox.stub().returns(false)
122+
} as any;
123+
124+
const result = ConfigurationService.affectsConfiguration(mockEvent);
125+
126+
assert.strictEqual(result, false);
127+
});
128+
});

src/test/ddev-utils.test.ts

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
/*
2+
* This file is part of the vscode-ddev-phpmd extension.
3+
*
4+
* © OpenForgeProject
5+
*
6+
* This program is free software: you can redistribute it and/or modify
7+
* it under the terms of the GNU General Public License as published by
8+
* the Free Software Foundation, either version 3 of the License, or
9+
* (at your option) any later version.
10+
*
11+
* This program is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
* GNU General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU General Public License
17+
* along with this program. If not, see <https://www.gnu.org/licenses/>.
18+
*/
19+
20+
import * as assert from 'assert';
21+
import * as sinon from 'sinon';
22+
import { afterEach, beforeEach } from 'mocha';
23+
import { DdevUtils } from '../shared/utils/ddev-utils';
24+
25+
suite('DdevUtils Test Suite', () => {
26+
let sandbox: sinon.SinonSandbox;
27+
let execSyncStub: sinon.SinonStub;
28+
29+
beforeEach(() => {
30+
sandbox = sinon.createSandbox();
31+
// Mock the entire child_process module
32+
const childProcess = require('child_process');
33+
execSyncStub = sandbox.stub(childProcess, 'execSync');
34+
});
35+
36+
afterEach(() => {
37+
sandbox.restore();
38+
});
39+
40+
test('hasDdevProject returns true when .ddev/config.yaml exists', () => {
41+
execSyncStub.returns('exists\n');
42+
43+
const result = DdevUtils.hasDdevProject('/test/workspace');
44+
45+
assert.strictEqual(result, true);
46+
assert.strictEqual(execSyncStub.calledOnce, true);
47+
});
48+
49+
test('hasDdevProject returns false when .ddev/config.yaml does not exist', () => {
50+
execSyncStub.throws(new Error('File not found'));
51+
52+
const result = DdevUtils.hasDdevProject('/test/workspace');
53+
54+
assert.strictEqual(result, false);
55+
});
56+
57+
test('isDdevRunning returns true when DDEV container is running', () => {
58+
execSyncStub.returns('');
59+
60+
const result = DdevUtils.isDdevRunning('/test/workspace');
61+
62+
assert.strictEqual(result, true);
63+
assert.strictEqual(execSyncStub.calledOnce, true);
64+
});
65+
66+
test('isDdevRunning returns false when DDEV container is not running', () => {
67+
execSyncStub.throws(new Error('Container not running'));
68+
69+
const result = DdevUtils.isDdevRunning('/test/workspace');
70+
71+
assert.strictEqual(result, false);
72+
});
73+
74+
test('isToolInstalled returns true when tool is available', () => {
75+
execSyncStub.returns('PHPMD 2.13.0\n');
76+
77+
const result = DdevUtils.isToolInstalled('phpmd', '/test/workspace');
78+
79+
assert.strictEqual(result, true);
80+
assert.strictEqual(execSyncStub.calledOnce, true);
81+
});
82+
83+
test('isToolInstalled returns false when tool is not available', () => {
84+
execSyncStub.throws(new Error('Command not found'));
85+
86+
const result = DdevUtils.isToolInstalled('phpmd', '/test/workspace');
87+
88+
assert.strictEqual(result, false);
89+
});
90+
91+
test('validateDdevTool returns invalid result when no DDEV project found', () => {
92+
execSyncStub.throws(new Error('File not found'));
93+
94+
const result = DdevUtils.validateDdevTool('phpmd', '/test/workspace');
95+
96+
assert.strictEqual(result.isValid, false);
97+
assert.strictEqual(result.errorType, 'no-ddev-project');
98+
assert.strictEqual(result.userMessage, 'No DDEV project found');
99+
});
100+
101+
test('validateDdevTool returns valid result when tool is available', () => {
102+
// First call (hasDdevProject) succeeds
103+
execSyncStub.onFirstCall().returns('exists\n');
104+
// Second call (tool version check) succeeds
105+
execSyncStub.onSecondCall().returns('PHPMD 2.13.0\n');
106+
107+
const result = DdevUtils.validateDdevTool('phpmd', '/test/workspace');
108+
109+
assert.strictEqual(result.isValid, true);
110+
assert.strictEqual(result.errorType, undefined);
111+
});
112+
113+
test('validateDdevTool returns error message for DDEV issues', () => {
114+
// First call (hasDdevProject) succeeds
115+
execSyncStub.onFirstCall().returns('exists\n');
116+
// Second call (tool version check) fails
117+
execSyncStub.onSecondCall().throws(new Error('Tool not available'));
118+
// Third call (error details) returns error
119+
execSyncStub.onThirdCall().throws({
120+
message: 'DDEV project not currently running',
121+
stderr: 'not currently running'
122+
});
123+
124+
const result = DdevUtils.validateDdevTool('phpmd', '/test/workspace');
125+
126+
assert.strictEqual(result.isValid, false);
127+
assert.strictEqual(result.errorType, 'unknown');
128+
assert.ok(result.userMessage?.includes('PHPMD not available'));
129+
});
130+
131+
test('execDdev returns output when command succeeds', () => {
132+
const expectedOutput = 'Command output';
133+
execSyncStub.returns(expectedOutput);
134+
135+
const result = DdevUtils.execDdev('phpmd test.php json cleancode', '/test/workspace');
136+
137+
assert.strictEqual(result, expectedOutput);
138+
assert.strictEqual(execSyncStub.calledOnce, true);
139+
});
140+
141+
test('execDdev returns stdout when command fails but has output', () => {
142+
const error = new Error('Command failed') as any;
143+
error.stdout = 'PHPMD violations found';
144+
execSyncStub.throws(error);
145+
146+
const result = DdevUtils.execDdev('phpmd test.php json cleancode', '/test/workspace');
147+
148+
assert.strictEqual(result, 'PHPMD violations found');
149+
});
150+
151+
test('execDdev throws error when command fails without stdout', () => {
152+
const error = new Error('Command failed');
153+
execSyncStub.throws(error);
154+
155+
assert.throws(() => {
156+
DdevUtils.execDdev('phpmd test.php json cleancode', '/test/workspace');
157+
}, /Command failed/);
158+
});
159+
});

0 commit comments

Comments
 (0)