Skip to content

Commit 3870fa1

Browse files
added tests
1 parent dae6c5f commit 3870fa1

59 files changed

Lines changed: 6464 additions & 5 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

src/views/component-viewer/model/scvd-format-specifier.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ export class ScvdFormatSpecifier {
117117

118118
if (kind === 'uint') {
119119
if (bits && bits < 32) {
120-
const mask = bits === 32 ? 0xFFFFFFFF : (1 << bits) >>> 0;
120+
const mask = (1 << bits) >>> 0;
121121
return (((value as number) >>> 0) & mask).toString(10);
122122
}
123123
return ((value as number) >>> 0).toString(10);
@@ -685,7 +685,7 @@ export class ScvdFormatSpecifier {
685685
const epNum = addr & 0x0F;
686686
const dirIn = (addr & 0x80) !== 0;
687687
const attrs = value[3] ?? 0;
688-
const xferType = ['Control', 'Isochronous', 'Bulk', 'Interrupt'][attrs & 0x3] || 'Unknown';
688+
const xferType = ['Control', 'Isochronous', 'Bulk', 'Interrupt'][attrs & 0x3];
689689
return [
690690
`USB Endpoint (len=${len})`,
691691
` bEndpointAddress ${hex(addr)} (EP${epNum} ${dirIn ? 'IN' : 'OUT'})`,

src/views/component-viewer/model/scvd-print-expression.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,10 @@ export class ScvdPrintExpression extends ScvdExpression {
4141
}
4242

4343
public override async getGuiName(): Promise<string | undefined> {
44-
return this.getGuiName();
44+
return super.getGuiName();
4545
}
4646

4747
public override async getGuiValue(): Promise<string | undefined> {
48-
return this.getGuiValue();
48+
return super.getGuiValue();
4949
}
5050
}

src/views/component-viewer/statement-engine/statement-readList.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ export class StatementReadList extends StatementBase {
7878
console.error(`${this.scvdItem.getLineNoStr()}: Executing "readlist": ${scvdReadList.name}, symbol: ${symbol?.name}, could not find symbol address for symbol: ${symbol?.symbol}`);
7979
return;
8080
}
81-
baseAddress = symAddr >>> 0;
81+
baseAddress = typeof symAddr === 'bigint' ? symAddr : (symAddr >>> 0);
8282

8383
// fetch maximum existing array size
8484
const resolvedCount = await executionContext.debugTarget.getNumArrayElements(symbol.symbol);
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
/**
2+
* Copyright 2026 Arm Limited
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
// generated with AI
17+
18+
import fs from 'fs';
19+
import os from 'os';
20+
import path from 'path';
21+
import {
22+
decodeEntities,
23+
extractExpressionsFromScvd,
24+
writeJsonl,
25+
} from './generate-scvd-expressions';
26+
27+
describe('generate-scvd-expressions', () => {
28+
it('decodes entities and extracts expressions with flags', () => {
29+
const content = `
30+
<node offset="1 &amp; 2" property="%d[%s]" unknown="skip" value=" ">
31+
<calc>
32+
a &lt; b
33+
</calc>
34+
</node>
35+
`;
36+
37+
const expressions = extractExpressionsFromScvd(content);
38+
39+
expect(expressions).toEqual([
40+
{ expr: '1 & 2', forcePrintf: false },
41+
{ expr: '%d[%s]', forcePrintf: true },
42+
{ expr: 'a < b', forcePrintf: false },
43+
]);
44+
45+
expect(decodeEntities('A &gt; B &amp; C')).toBe('A > B & C');
46+
});
47+
48+
it('writes JSONL with printf detection', () => {
49+
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'scvd-expr-'));
50+
const outPath = path.join(tempDir, 'out.jsonl');
51+
52+
writeJsonl(outPath, [
53+
{ expr: '%%', forcePrintf: false },
54+
{ expr: 'plain', forcePrintf: true },
55+
]);
56+
57+
// eslint-disable-next-line security/detect-non-literal-fs-filename
58+
const lines = fs.readFileSync(outPath, 'utf8').trim().split('\n');
59+
const meta = JSON.parse(lines[0]!);
60+
const first = JSON.parse(lines[1]!);
61+
const second = JSON.parse(lines[2]!);
62+
63+
expect(meta._meta.total).toBe(2);
64+
expect(first.isPrintf).toBe(true);
65+
expect(second.isPrintf).toBe(true);
66+
});
67+
68+
it('main reads inputs and writes outputs', async () => {
69+
const readFileSync = jest.fn(() => 'offset="1"');
70+
const writeFileSync = jest.fn();
71+
const mkdirSync = jest.fn();
72+
73+
await jest.isolateModulesAsync(async () => {
74+
jest.doMock('fs', () => ({
75+
readFileSync,
76+
writeFileSync,
77+
mkdirSync,
78+
}));
79+
const mod = await import('./generate-scvd-expressions');
80+
81+
mod.main();
82+
});
83+
84+
expect(readFileSync).toHaveBeenCalledTimes(3);
85+
expect(writeFileSync).toHaveBeenCalledTimes(3);
86+
});
87+
});
Lines changed: 231 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,231 @@
1+
/**
2+
* Copyright 2025-2026 Arm Limited
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*
16+
* Coverage for NumberType.
17+
*/
18+
// generated with AI
19+
20+
import { NumFormat, NumberType } from '../../model/number-type';
21+
22+
describe('NumberType coverage', () => {
23+
it('constructs from numbers and respects formats', () => {
24+
const num = new NumberType(42);
25+
expect(num.format).toBe(NumFormat.decimal);
26+
expect(num.displayFormat).toBe(NumFormat.decimal);
27+
expect(num.value).toBe(42);
28+
29+
const hex = new NumberType(255, NumFormat.hexadecimal, 8);
30+
expect(hex.format).toBe(NumFormat.hexadecimal);
31+
expect(hex.displayFormat).toBe(NumFormat.hexadecimal);
32+
expect(hex.numOfDisplayBits).toBe(8);
33+
});
34+
35+
it('copies from another NumberType and clamps digit setters', () => {
36+
const base = new NumberType(7, NumFormat.decimal);
37+
base.numOfDigits = 0;
38+
base.numOfDisplayBits = 0;
39+
expect(base.numOfDigits).toBe(1);
40+
expect(base.numOfDisplayBits).toBe(1);
41+
42+
const copy = new NumberType(base);
43+
copy.numOfDigits = -2;
44+
copy.numOfDisplayBits = -3;
45+
expect(copy.numOfDigits).toBe(1);
46+
expect(copy.numOfDisplayBits).toBe(1);
47+
expect(copy.value).toBe(7);
48+
});
49+
50+
it('parses string inputs and booleans', () => {
51+
const hex = new NumberType('0x1F');
52+
expect(hex.format).toBe(NumFormat.hexadecimal);
53+
expect(hex.getText()).toBe('0x1F');
54+
55+
const bin = new NumberType('0b1010');
56+
expect(bin.format).toBe(NumFormat.binary);
57+
expect(bin.getText()).toBe('0b1010');
58+
59+
const oct = new NumberType('075');
60+
expect(oct.format).toBe(NumFormat.octal);
61+
expect(oct.getText()).toBe('075');
62+
63+
const dec = new NumberType('123');
64+
expect(dec.format).toBe(NumFormat.decimal);
65+
expect(dec.getText()).toBe('123');
66+
67+
const t = new NumberType('true');
68+
const f = new NumberType('false');
69+
expect(t.format).toBe(NumFormat.boolean);
70+
expect(t.getText()).toBe('true');
71+
expect(f.format).toBe(NumFormat.boolean);
72+
expect(f.getText()).toBe('false');
73+
});
74+
75+
it('handles invalid and empty strings', () => {
76+
const invalid = new NumberType('xyz');
77+
expect(invalid.isValid()).toBe(false);
78+
expect(invalid.getText()).toBe('0');
79+
80+
const empty = new NumberType('');
81+
expect(empty.isValid()).toBe(false);
82+
expect(empty.getText()).toBe('0');
83+
84+
const single = new NumberType('7');
85+
expect(single.format).toBe(NumFormat.decimal);
86+
87+
const neg = new NumberType('-1');
88+
expect(neg.value).toBe(-1);
89+
90+
const hexEmpty = new NumberType('0x');
91+
expect(hexEmpty.numOfDigits).toBe(1);
92+
});
93+
94+
it('formats negative values and boolean defaults', () => {
95+
const neg = new NumberType(-15, NumFormat.hexadecimal);
96+
expect(neg.getValStrByFormat(NumFormat.hexadecimal, 2)).toBe('-0x0F');
97+
98+
const bool = new NumberType(2, NumFormat.boolean);
99+
expect(bool.getValStrByFormat(NumFormat.boolean, 1)).toBe('true');
100+
});
101+
102+
it('supports display formatting rules', () => {
103+
const display = new NumberType(0xA, NumFormat.hexadecimal, 5);
104+
expect(display.getDisplayText()).toBe('0x0A');
105+
106+
display.displayFormat = NumFormat.decimal;
107+
expect(display.getDisplayText()).toBe('10');
108+
109+
display.displayFormat = NumFormat.octal;
110+
display.numOfDisplayBits = 4;
111+
expect(display.getDisplayText()).toBe('012');
112+
113+
display.displayFormat = NumFormat.undefined;
114+
expect(display.getDisplayText()).toBe('10');
115+
116+
const small = new NumberType(1, NumFormat.hexadecimal, 0);
117+
expect(small.getDisplayText()).toBe('0x1');
118+
});
119+
120+
it('supports min/max bounds and accessors', () => {
121+
const bounded = new NumberType(10);
122+
bounded.setMin(3);
123+
bounded.setMax(8);
124+
expect(bounded.value).toBe(8);
125+
126+
bounded.value = 1;
127+
expect(bounded.value).toBe(3);
128+
129+
bounded.setMinMax(2, undefined);
130+
bounded.setMinMax(undefined, 12);
131+
expect(bounded.min).toBe(2);
132+
expect(bounded.max).toBe(12);
133+
expect(bounded.getMinMax()).toEqual({ min: 2, max: 12 });
134+
});
135+
136+
it('exposes format prefix and text helpers', () => {
137+
const num = new NumberType(0);
138+
expect(num.getFormatPrefix(NumFormat.decimal)).toBe('');
139+
expect(num.getFormatPrefix(NumFormat.hexadecimal)).toBe('0x');
140+
expect(num.getFormatPrefix(NumFormat.octal)).toBe('0');
141+
expect(num.getFormatPrefix(NumFormat.binary)).toBe('0b');
142+
expect(num.getFormatPrefix(NumFormat.undefined)).toBe('');
143+
144+
expect(num.getFormatText(NumFormat.decimal)).toBe('decimal');
145+
expect(num.getFormatText(NumFormat.hexadecimal)).toBe('hexadecimal');
146+
expect(num.getFormatText(NumFormat.octal)).toBe('octal');
147+
expect(num.getFormatText(NumFormat.binary)).toBe('binary');
148+
expect(num.getFormatText(NumFormat.boolean)).toBe('boolean');
149+
expect(num.getFormatText(NumFormat.undefined)).toBe('undefined');
150+
});
151+
152+
it('updates values and formats through setters', () => {
153+
const num = new NumberType();
154+
num.value = 3;
155+
expect(num.format).toBe(NumFormat.decimal);
156+
expect(num.displayFormat).toBe(NumFormat.decimal);
157+
158+
const other = new NumberType(5, NumFormat.octal);
159+
num.value = other;
160+
expect(num.format).toBe(NumFormat.octal);
161+
162+
num.value = '0b11';
163+
expect(num.format).toBe(NumFormat.binary);
164+
165+
num.format = NumFormat.hexadecimal;
166+
expect(num.format).toBe(NumFormat.hexadecimal);
167+
});
168+
169+
it('covers string setter branch directly', () => {
170+
const num = new NumberType();
171+
const setter = Object.getOwnPropertyDescriptor(NumberType.prototype, 'value')?.set;
172+
expect(typeof setter).toBe('function');
173+
setter?.call(num, '0b1');
174+
expect(num.format).toBe(NumFormat.binary);
175+
});
176+
177+
it('covers non-string setter fallthrough', () => {
178+
const num = new NumberType(11);
179+
const setter = Object.getOwnPropertyDescriptor(NumberType.prototype, 'value')?.set;
180+
setter?.call(num, true as unknown as number);
181+
expect(num.value).toBe(11);
182+
});
183+
184+
it('forces fallback when formatted text is empty', () => {
185+
const originalToString = Number.prototype.toString;
186+
Number.prototype.toString = () => '';
187+
try {
188+
const num = new NumberType(7, NumFormat.decimal);
189+
expect(num.getValStrByFormat(NumFormat.decimal, 1)).toBe('');
190+
} finally {
191+
Number.prototype.toString = originalToString;
192+
}
193+
});
194+
195+
it('pads digits when the requested width is below one', () => {
196+
const num = new NumberType(5, NumFormat.hexadecimal);
197+
expect(num.getValStrByFormat(NumFormat.hexadecimal, 0)).toBe('0x5');
198+
});
199+
200+
it('covers setter branches and protected toNumber parsing', () => {
201+
const num = new NumberType();
202+
num.numOfDigits = 0;
203+
num.numOfDigits = 2;
204+
205+
num.value = '0';
206+
expect(num.format).toBe(NumFormat.decimal);
207+
208+
const parsed = (num as unknown as { toNumber: (v: string) => { displayFormat: NumFormat } }).toNumber('-2');
209+
expect(parsed.displayFormat).toBe(NumFormat.decimal);
210+
211+
expect(num.getFormatText(NumFormat.decimal)).toBe('decimal');
212+
});
213+
214+
it('covers displayFormat branch when enum value is NaN', () => {
215+
const enumRef = NumFormat as unknown as { undefined: number };
216+
const original = enumRef.undefined;
217+
enumRef.undefined = Number.NaN;
218+
try {
219+
const num = new NumberType();
220+
const parsed = (num as unknown as { toNumber: (v: string) => { displayFormat: number } }).toNumber('1');
221+
expect(Number.isNaN(parsed.displayFormat)).toBe(true);
222+
} finally {
223+
enumRef.undefined = original;
224+
}
225+
});
226+
227+
it('covers default branch in getFormatText', () => {
228+
const num = new NumberType();
229+
expect(num.getFormatText(99 as NumFormat)).toBe('undefined');
230+
});
231+
});

0 commit comments

Comments
 (0)