Skip to content

Commit f1ab609

Browse files
authored
Resolve cbuild-run dir relative to workspace (#815)
* Resolve cbuild-run dir relative to workspace * Make snapshot tests OS agnostic * comparePath function to handle differing drive letter casings * Treat empty and undefined CMSIS_PACK_ROOT the same
1 parent fad098c commit f1ab609

5 files changed

Lines changed: 94 additions & 28 deletions

File tree

src/cbuild-run/__snapshots__/cbuild-run-reader.test.ts.snap

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
exports[`CbuildRunReader Parser successfully parses a *.cbuild-run.yml file 1`] = `
44
{
5+
"cbuildRunDir": Any<String>,
56
"compiler": "AC6",
67
"debug-sequences": [
78
{

src/cbuild-run/cbuild-run-reader.test.ts

Lines changed: 77 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
import * as path from 'path';
1818
import { CbuildRunReader } from './cbuild-run-reader';
19+
import { getCmsisPackRootPath } from '../utils';
1920

2021
const TEST_CBUILD_RUN_FILE = 'test-data/multi-core.cbuild-run.yml'; // Relative to repo root
2122
const TEST_FILE_PATH = 'test-data/fileReaderTest.txt'; // Relative to repo root
@@ -24,6 +25,35 @@ const PACK_ROOT = '/my/pack/root';
2425
const EXPECTED_CUSTOM_SVD = path.resolve(path.dirname(TEST_CBUILD_RUN_FILE), '../../MyDevice/multi-core-custom.svd');
2526
const EXPECTED_CUSTOM_SCVD = path.resolve(path.dirname(TEST_CBUILD_RUN_FILE), '../../MyDevice/multi-core-custom.scvd');
2627

28+
// Compare function that compares path and allows differing drive letter casing on Windows.
29+
const comparePath = (received: string|undefined, expected: string): boolean => {
30+
if (!received) {
31+
return false;
32+
}
33+
// Exact match first, majority of cases.
34+
if (received === expected) {
35+
return true;
36+
}
37+
// Exit if not Windows, no match
38+
if (process.platform !== 'win32') {
39+
return false;
40+
}
41+
// Split drive letter from path. Assumption: no URLs, no other colons in folder names.
42+
const receivedFragments = received.split(':');
43+
const expectedFragments = expected.split(':');
44+
if (receivedFragments.length !== expectedFragments.length) {
45+
return false;
46+
}
47+
return receivedFragments.every((receivedFragment, index) => {
48+
// eslint-disable-next-line security/detect-object-injection
49+
const expectedFragment = expectedFragments[index];
50+
if (index === 0) {
51+
// Drive letter
52+
return receivedFragment.toLowerCase() === expectedFragment.toLowerCase();
53+
}
54+
return receivedFragment === expectedFragment;
55+
});
56+
};
2757

2858
describe('CbuildRunReader', () => {
2959

@@ -34,7 +64,12 @@ describe('CbuildRunReader', () => {
3464
expect(cbuildRunReader.hasContents()).toBe(true);
3565
const contents = cbuildRunReader.getContents();
3666
expect(contents).toBeDefined();
37-
expect(contents).toMatchSnapshot();
67+
// Snapshot match all but cbuildRunDir which is an absolute path and hence OS specific.
68+
// That part gets tested in separate tests.
69+
expect({
70+
...contents,
71+
cbuildRunDir: expect.any(String)
72+
}).toMatchSnapshot();
3873
});
3974

4075
it('throws if it parses something other than a *.cbuild-run.yml file and correctly responds to raw contents calls', async () => {
@@ -96,8 +131,8 @@ describe('CbuildRunReader', () => {
96131
// eslint-disable-next-line security/detect-object-injection
97132
const expectedPath = path.normalize(path.resolve(expectedSvdPaths[i]));
98133
// eslint-disable-next-line security/detect-object-injection
99-
const actualPath = path.normalize(path.resolve(svdFilePaths[i]));
100-
expect(expectedPath).toEqual(actualPath);
134+
const actualPath = svdFilePaths[i];
135+
expect(comparePath(actualPath, expectedPath)).toBe(true);
101136
}
102137
});
103138

@@ -117,21 +152,26 @@ describe('CbuildRunReader', () => {
117152
expect(pnames).toEqual(['Core0', 'Core1']);
118153
});
119154

120-
it('includes descriptors without pname when filtering by pname (SVD)', async () => {
155+
it.each([
156+
{ packRoot: '', info: 'empty string' },
157+
{ packRoot: undefined, info: 'undefined' },
158+
])('includes descriptors without pname when filtering by pname (SVD) and uses default pack root if input is $info', async ({ packRoot }) => {
121159
await cbuildRunReader.parse(TEST_CBUILD_RUN_FILE);
122160
const cbuildRun = (cbuildRunReader as unknown as { cbuildRun?: { ['system-descriptions']?: Array<{ file: string; type: string; pname?: string }> } }).cbuildRun;
123161
const systemDescriptions = cbuildRun?.['system-descriptions'];
124162
expect(systemDescriptions).toBeDefined();
125-
const svdPaths = cbuildRunReader.getSvdFilePaths('', 'Core1');
126-
expect(svdPaths.map(path.normalize)).toEqual([
163+
const svdPaths = cbuildRunReader.getSvdFilePaths(packRoot, 'Core1');
164+
const expectedSvdPaths = [
127165
path.normalize(
128-
path.resolve(path.dirname(TEST_CBUILD_RUN_FILE), '${CMSIS_PACK_ROOT}', 'MyVendor', 'MyDevice', '1.0.0', 'Debug', 'SVD', 'MyDevice_Core1.svd')
166+
path.resolve(getCmsisPackRootPath(), 'MyVendor', 'MyDevice', '1.0.0', 'Debug', 'SVD', 'MyDevice_Core1.svd')
129167
),
130168
path.normalize(
131-
path.resolve(path.dirname(TEST_CBUILD_RUN_FILE), '${CMSIS_PACK_ROOT}', 'MyVendor', 'MyDevice', '1.0.0', 'Debug', 'SVD', 'MyDevice_generic.svd')
169+
path.resolve(getCmsisPackRootPath(), 'MyVendor', 'MyDevice', '1.0.0', 'Debug', 'SVD', 'MyDevice_generic.svd')
132170
),
133171
path.normalize(EXPECTED_CUSTOM_SVD),
134-
]);
172+
];
173+
// eslint-disable-next-line security/detect-object-injection
174+
svdPaths.forEach((svdPath, index) => expect(comparePath(svdPath, expectedSvdPaths[index])).toBe(true));
135175
});
136176

137177
it('includes descriptors without pname when filtering by pname (SVD)', async () => {
@@ -140,12 +180,13 @@ describe('CbuildRunReader', () => {
140180
const systemDescriptions = cbuildRun?.['system-descriptions'];
141181
expect(systemDescriptions).toBeDefined();
142182
const svdPaths = cbuildRunReader.getSvdFilePaths(PACK_ROOT, 'Core1');
143-
144-
expect(svdPaths.map(path.normalize)).toEqual([
183+
const expectedSvdPaths = [
145184
path.normalize(path.resolve(PACK_ROOT, 'MyVendor', 'MyDevice', '1.0.0', 'Debug', 'SVD', 'MyDevice_Core1.svd')),
146185
path.normalize(path.resolve(PACK_ROOT, 'MyVendor', 'MyDevice', '1.0.0', 'Debug', 'SVD', 'MyDevice_generic.svd')),
147186
path.normalize(EXPECTED_CUSTOM_SVD),
148-
]);
187+
];
188+
// eslint-disable-next-line security/detect-object-injection
189+
svdPaths.forEach((svdPath, index) => expect(comparePath(svdPath, expectedSvdPaths[index])).toBe(true));
149190
});
150191

151192
it('includes descriptors without pname when filtering by pname (SCVD)', async () => {
@@ -154,28 +195,43 @@ describe('CbuildRunReader', () => {
154195
const systemDescriptions = cbuildRun?.['system-descriptions'] ?? [];
155196
expect(systemDescriptions).toBeDefined();
156197
const scvdPaths = cbuildRunReader.getScvdFilePaths(PACK_ROOT, 'Core1');
157-
158-
expect(scvdPaths).toEqual([
198+
const expectedScvdPaths = [
159199
path.normalize(path.resolve(PACK_ROOT, 'MyVendor', 'MyDevice', '1.0.0', 'Debug', 'SCVD', 'MySoftware_component.scvd')),
160200
path.normalize(EXPECTED_CUSTOM_SCVD),
161201
path.normalize(path.resolve(PACK_ROOT, 'MyVendor', 'MyDevice', '1.0.0', 'Debug', 'SCVD', 'Core1.scvd')),
162-
]);
202+
];
203+
// eslint-disable-next-line security/detect-object-injection
204+
scvdPaths.forEach((scvdPath, index) => expect(comparePath(scvdPath, expectedScvdPaths[index])).toBe(true));
163205
});
164206

165-
it('resolves relative SVD paths relative to the cbuild-run.yml file location', async () => {
166-
await cbuildRunReader.parse(TEST_CBUILD_RUN_FILE);
207+
it.each([
208+
{
209+
cbuildRunFile: TEST_CBUILD_RUN_FILE,
210+
},
211+
{
212+
cbuildRunFile: `.${path.sep}${TEST_CBUILD_RUN_FILE}`,
213+
},
214+
])('resolves relative SVD paths relative to the cbuild-run.yml file location ($cbuildRunFile)', async ({ cbuildRunFile }) => {
215+
await cbuildRunReader.parse(cbuildRunFile);
167216
const svdFilePaths = cbuildRunReader.getSvdFilePaths(PACK_ROOT);
168217
const expectedTail = path.normalize(path.join('MyDevice', 'multi-core-custom.svd'));
169218
const resolvedCustom = svdFilePaths.find((p: string) => p.endsWith(expectedTail));
170-
expect(resolvedCustom).toEqual(path.normalize(EXPECTED_CUSTOM_SVD));
219+
expect(comparePath(resolvedCustom, path.normalize(EXPECTED_CUSTOM_SVD))).toBe(true);
171220
});
172221

173-
it('resolves relative SCVD paths relative to the cbuild-run.yml file location', async () => {
174-
await cbuildRunReader.parse(TEST_CBUILD_RUN_FILE);
222+
it.each([
223+
{
224+
cbuildRunFile: TEST_CBUILD_RUN_FILE,
225+
},
226+
{
227+
cbuildRunFile: `.${path.sep}${TEST_CBUILD_RUN_FILE}`,
228+
},
229+
])('resolves relative SCVD paths relative to the cbuild-run.yml file location ($cbuildRunFile)', async ({ cbuildRunFile }) => {
230+
await cbuildRunReader.parse(cbuildRunFile);
175231
const scvdFilePaths = cbuildRunReader.getScvdFilePaths(PACK_ROOT);
176232
const expectedTail = path.normalize(path.join('MyDevice', 'multi-core-custom.scvd'));
177233
const resolvedCustom = scvdFilePaths.find((p: string) => p.endsWith(expectedTail));
178-
expect(resolvedCustom).toEqual(path.normalize(EXPECTED_CUSTOM_SCVD));
234+
expect(comparePath(resolvedCustom, path.normalize(EXPECTED_CUSTOM_SCVD))).toBe(true);
179235
});
180236
});
181237
});

src/cbuild-run/cbuild-run-reader.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,9 @@
1414
* limitations under the License.
1515
*/
1616

17-
import * as yaml from 'yaml';
1817
import * as path from 'path';
18+
import * as vscode from 'vscode';
19+
import * as yaml from 'yaml';
1920
import { CbuildRunRootType, CbuildRunType } from './cbuild-run-types';
2021
import { FileReader, VscodeFileReader } from '../desktop/file-reader';
2122
import { getCmsisPackRootPath } from '../utils';
@@ -45,7 +46,10 @@ export class CbuildRunReader {
4546
throw new Error(`Invalid '*.cbuild-run.yml' file: ${filePath}`);
4647
}
4748
this.cbuildRunFilePath = filePath;
48-
this.cbuildRunDir = path.dirname(this.cbuildRunFilePath);
49+
const dirName = path.dirname(this.cbuildRunFilePath);
50+
const workspace = vscode.workspace.workspaceFolders?.at(0)?.uri.fsPath;
51+
// Only considers workspace if dirName is not absolute.
52+
this.cbuildRunDir = workspace ? path.resolve(workspace, dirName) : dirName;
4953
}
5054

5155
public getSvdFilePaths(cmsisPackRoot?: string, pname?: string): string[] {
@@ -68,8 +72,8 @@ export class CbuildRunReader {
6872
if (fileDescriptors.length === 0) {
6973
return [];
7074
}
71-
// Replace potential ${CMSIS_PACK_ROOT} placeholder
72-
const effectiveCmsisPackRoot = cmsisPackRoot ?? getCmsisPackRootPath();
75+
// Replace potential ${CMSIS_PACK_ROOT} placeholder, treat empty string and undefined the same.
76+
const effectiveCmsisPackRoot = cmsisPackRoot || getCmsisPackRootPath();
7377
// Map to copies, leave originals untouched, if file descriptors do not have a pname, always include it
7478
const filteredDescriptors = pname ? fileDescriptors.filter(descriptor => {
7579
if (!descriptor.pname) {

src/debug-session/__snapshots__/gdbtarget-debug-session.test.ts.snap

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
22

33
exports[`GDBTargetDebugSession with launch configuration returns a cbuild object and cbuild run path after parsing one 1`] = `
4-
CbuildRunReader {
4+
{
55
"cbuildRun": {
66
"compiler": "AC6",
77
"debug-sequences": [
@@ -182,7 +182,7 @@ CbuildRunReader {
182182
},
183183
"target-type": "My-Test-Target-Type",
184184
},
185-
"cbuildRunDir": "test-data",
185+
"cbuildRunDir": Any<String>,
186186
"cbuildRunFilePath": "test-data/multi-core.cbuild-run.yml",
187187
"reader": VscodeFileReader {},
188188
}

src/debug-session/gdbtarget-debug-session.test.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,12 @@ describe('GDBTargetDebugSession', () => {
7272
it('returns a cbuild object and cbuild run path after parsing one', async () => {
7373
await gdbTargetSession.parseCbuildRun(TEST_CBUILD_RUN_FILE);
7474
const cbuildRun = await gdbTargetSession.getCbuildRun();
75-
expect(cbuildRun).toMatchSnapshot();
75+
// Snapshot match all but cbuildRunDir which is an absolute path and hence OS specific.
76+
// That part gets tested separately in cbuild-run-reader.test.ts.
77+
expect({
78+
...cbuildRun,
79+
cbuildRunDir: expect.any(String)
80+
}).toMatchSnapshot();
7681
});
7782

7883
it('evaluates a global expression without active stack frame and returns a value', async () => {

0 commit comments

Comments
 (0)