Skip to content

Commit 5ceec8c

Browse files
Extend support for data breakpoints in VS Code API
- Allow the user to manage data breakpoints through vscode.debug API - Add methods to gain information about a potential data breakpoint - Allow data breakpoints to have different sources -- Keep use case where data id is already known (current) -- Add infrastructure for already existing address resolution -- Extend for dynamic variables resolved for a session --- Ensure dynamic variables are resolved in the debug model Communication: - Adapt DataBreakpoint with source between extension host and main - Expose DataBreakpoint in VS Code API, previously not exposed Minor: - Make bytes optional in data bytes info, as it is the same in the DAP Fixes #195151
1 parent 7473068 commit 5ceec8c

File tree

10 files changed

+294
-27
lines changed

10 files changed

+294
-27
lines changed

extensions/vscode-api-tests/src/singlefolder-tests/debug.test.ts

Lines changed: 73 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
import * as assert from 'assert';
77
import { basename } from 'path';
8-
import { commands, debug, Disposable, FunctionBreakpoint, window, workspace } from 'vscode';
8+
import { commands, DataBreakpoint, debug, Disposable, FunctionBreakpoint, window, workspace } from 'vscode';
99
import { assertNoRpc, createRandomFile, disposeAll } from '../utils';
1010

1111
suite('vscode API - debug', function () {
@@ -58,6 +58,78 @@ suite('vscode API - debug', function () {
5858
assert.strictEqual(functionBreakpoint.logMessage, 'logMessage');
5959
assert.strictEqual(functionBreakpoint.enabled, false);
6060
assert.strictEqual(functionBreakpoint.functionName, 'func');
61+
debug.removeBreakpoints([functionBreakpoint]);
62+
});
63+
64+
65+
test('data breakpoint - dataId', async function () {
66+
assert.strictEqual(debug.breakpoints.length, 0);
67+
debug.addBreakpoints([new DataBreakpoint({ type: 'variable', dataId: 'dataId' }, 'readWrite', false, 'data', false, 'condition', 'hitCondition', 'logMessage')]);
68+
const variableDbp = debug.breakpoints[0] as DataBreakpoint;
69+
assert.strictEqual(variableDbp.condition, 'condition');
70+
assert.strictEqual(variableDbp.hitCondition, 'hitCondition');
71+
assert.strictEqual(variableDbp.logMessage, 'logMessage');
72+
assert.strictEqual(variableDbp.enabled, false);
73+
assert.strictEqual(variableDbp.label, 'data');
74+
assert.strictEqual(variableDbp.source.type, 'variable');
75+
assert.strictEqual(variableDbp.source.dataId, 'dataId');
76+
assert.strictEqual(variableDbp.canPersist, false);
77+
assert.strictEqual(variableDbp.accessType, 'readWrite');
78+
assert.strictEqual(debug.breakpoints.length, 1);
79+
debug.removeBreakpoints([variableDbp]);
80+
});
81+
82+
test('data breakpoint - variable', async function () {
83+
assert.strictEqual(debug.breakpoints.length, 0);
84+
debug.addBreakpoints([new DataBreakpoint('dataId', 'readWrite', false, 'data', false, 'condition', 'hitCondition', 'logMessage')]);
85+
const dataIdDbp = debug.breakpoints[0] as DataBreakpoint;
86+
assert.strictEqual(dataIdDbp.condition, 'condition');
87+
assert.strictEqual(dataIdDbp.hitCondition, 'hitCondition');
88+
assert.strictEqual(dataIdDbp.logMessage, 'logMessage');
89+
assert.strictEqual(dataIdDbp.enabled, false);
90+
assert.strictEqual(dataIdDbp.label, 'data');
91+
assert.strictEqual(dataIdDbp.source.type, 'variable');
92+
assert.strictEqual(dataIdDbp.source.dataId, 'dataId');
93+
assert.strictEqual(dataIdDbp.canPersist, false);
94+
assert.strictEqual(dataIdDbp.accessType, 'readWrite');
95+
assert.strictEqual(debug.breakpoints.length, 1);
96+
debug.removeBreakpoints([dataIdDbp]);
97+
});
98+
99+
test('data breakpoint - address', async function () {
100+
assert.strictEqual(debug.breakpoints.length, 0);
101+
debug.addBreakpoints([new DataBreakpoint({ type: 'address', address: '0x00000', bytes: 4 }, 'readWrite', false, 'data', false, 'condition', 'hitCondition', 'logMessage')]);
102+
const addressDbp = debug.breakpoints[0] as DataBreakpoint;
103+
assert.strictEqual(addressDbp.condition, 'condition');
104+
assert.strictEqual(addressDbp.hitCondition, 'hitCondition');
105+
assert.strictEqual(addressDbp.logMessage, 'logMessage');
106+
assert.strictEqual(addressDbp.enabled, false);
107+
assert.strictEqual(addressDbp.label, 'data');
108+
assert.strictEqual(addressDbp.source.type, 'address');
109+
assert.strictEqual(addressDbp.source.address, '0x00000');
110+
assert.strictEqual(addressDbp.source.bytes, 4);
111+
assert.strictEqual(addressDbp.canPersist, false);
112+
assert.strictEqual(addressDbp.accessType, 'readWrite');
113+
assert.strictEqual(debug.breakpoints.length, 1);
114+
debug.removeBreakpoints([addressDbp]);
115+
});
116+
117+
test('data breakpoint - dynamic variable', async function () {
118+
assert.strictEqual(debug.breakpoints.length, 0);
119+
debug.addBreakpoints([new DataBreakpoint({ type: 'dynamicVariable', name: 'i', variablesReference: 1000 }, 'readWrite', false, 'data', false, 'condition', 'hitCondition', 'logMessage')]);
120+
const dynamicVariableDbp = debug.breakpoints[0] as DataBreakpoint;
121+
assert.strictEqual(dynamicVariableDbp.condition, 'condition');
122+
assert.strictEqual(dynamicVariableDbp.hitCondition, 'hitCondition');
123+
assert.strictEqual(dynamicVariableDbp.logMessage, 'logMessage');
124+
assert.strictEqual(dynamicVariableDbp.enabled, false);
125+
assert.strictEqual(dynamicVariableDbp.label, 'data');
126+
assert.strictEqual(dynamicVariableDbp.source.type, 'dynamicVariable');
127+
assert.strictEqual(dynamicVariableDbp.source.name, 'i');
128+
assert.strictEqual(dynamicVariableDbp.source.variablesReference, 1000);
129+
assert.strictEqual(dynamicVariableDbp.canPersist, false);
130+
assert.strictEqual(dynamicVariableDbp.accessType, 'readWrite');
131+
assert.strictEqual(debug.breakpoints.length, 1);
132+
debug.removeBreakpoints([dynamicVariableDbp]);
61133
});
62134

63135
test('start debugging', async function () {

src/vs/workbench/api/browser/mainThreadDebugService.ts

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ import { URI as uri, UriComponents } from 'vs/base/common/uri';
88
import { IDebugService, IConfig, IDebugConfigurationProvider, IBreakpoint, IFunctionBreakpoint, IBreakpointData, IDebugAdapter, IDebugAdapterDescriptorFactory, IDebugSession, IDebugAdapterFactory, IDataBreakpoint, IDebugSessionOptions, IInstructionBreakpoint, DebugConfigurationProviderTriggerKind, IDebugVisualization, DataBreakpointSetType } from 'vs/workbench/contrib/debug/common/debug';
99
import {
1010
ExtHostContext, ExtHostDebugServiceShape, MainThreadDebugServiceShape, DebugSessionUUID, MainContext,
11-
IBreakpointsDeltaDto, ISourceMultiBreakpointDto, ISourceBreakpointDto, IFunctionBreakpointDto, IDebugSessionDto, IDataBreakpointDto, IStartDebuggingOptions, IDebugConfiguration, IThreadFocusDto, IStackFrameFocusDto
11+
IBreakpointsDeltaDto, ISourceMultiBreakpointDto, ISourceBreakpointDto, IFunctionBreakpointDto, IDebugSessionDto, IDataBreakpointDto, IStartDebuggingOptions, IDebugConfiguration, IThreadFocusDto, IStackFrameFocusDto,
12+
IDataBreakpointInfo
1213
} from 'vs/workbench/api/common/extHost.protocol';
1314
import { extHostNamedCustomer, IExtHostContext } from 'vs/workbench/services/extensions/common/extHostCustomers';
1415
import severity from 'vs/base/common/severity';
@@ -173,7 +174,7 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb
173174
const bps = this.debugService.getModel().getBreakpoints();
174175
const fbps = this.debugService.getModel().getFunctionBreakpoints();
175176
const dbps = this.debugService.getModel().getDataBreakpoints();
176-
if (bps.length > 0 || fbps.length > 0) {
177+
if (bps.length > 0 || fbps.length > 0 || dbps.length > 0) {
177178
this._proxy.$acceptBreakpointsDelta({
178179
added: this.convertToDto(bps).concat(this.convertToDto(fbps)).concat(this.convertToDto(dbps))
179180
});
@@ -234,10 +235,16 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb
234235
} else if (dto.type === 'data') {
235236
this.debugService.addDataBreakpoint({
236237
description: dto.label,
237-
src: { type: DataBreakpointSetType.Variable, dataId: dto.dataId },
238+
src: dto.source.type === 'variable' ? { type: DataBreakpointSetType.Variable, dataId: dto.source.dataId }
239+
: dto.source.type === 'dynamicVariable' ? { type: DataBreakpointSetType.DynamicVariable, name: dto.source.name, variablesReference: dto.source.variablesReference }
240+
: { type: DataBreakpointSetType.Address, address: dto.source.address, bytes: dto.source.bytes },
241+
condition: dto.condition,
242+
enabled: dto.enabled,
243+
hitCondition: dto.hitCondition,
238244
canPersist: dto.canPersist,
239245
accessTypes: dto.accessTypes,
240246
accessType: dto.accessType,
247+
logMessage: dto.logMessage,
241248
mode: dto.mode
242249
});
243250
}
@@ -369,6 +376,22 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb
369376
return Promise.reject(new ErrorNoTelemetry('debug session not found'));
370377
}
371378

379+
public $getDataBreakpointInfo(sessionId: DebugSessionUUID, name: string, variablesReference?: number): Promise<IDataBreakpointInfo | undefined> {
380+
const session = this.debugService.getModel().getSession(sessionId, true);
381+
if (session) {
382+
return Promise.resolve(session.dataBreakpointInfo(name, variablesReference));
383+
}
384+
return Promise.reject(new ErrorNoTelemetry('debug session not found'));
385+
}
386+
387+
public $getDataBytesBreakpointInfo(sessionId: DebugSessionUUID, address: string, bytes?: number): Promise<IDataBreakpointInfo | undefined> {
388+
const session = this.debugService.getModel().getSession(sessionId, true);
389+
if (session) {
390+
return Promise.resolve(session.dataBytesBreakpointInfo(address, bytes));
391+
}
392+
return Promise.reject(new ErrorNoTelemetry('debug session not found'));
393+
}
394+
372395
public $stopDebugging(sessionId: DebugSessionUUID | undefined): Promise<void> {
373396
if (sessionId) {
374397
const session = this.debugService.getModel().getSession(sessionId, true);
@@ -457,7 +480,9 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb
457480
return {
458481
type: 'data',
459482
id: dbp.getId(),
460-
dataId: dbp.src.type === DataBreakpointSetType.Variable ? dbp.src.dataId : dbp.src.address,
483+
source: dbp.src.type === DataBreakpointSetType.Variable ? { type: 'variable', dataId: dbp.src.dataId }
484+
: dbp.src.type === DataBreakpointSetType.DynamicVariable ? { type: 'dynamicVariable', name: dbp.src.name, variablesReference: dbp.src.variablesReference }
485+
: { type: 'address', address: dbp.src.address, bytes: dbp.src.bytes },
461486
enabled: dbp.enabled,
462487
condition: dbp.condition,
463488
hitCondition: dbp.hitCondition,

src/vs/workbench/api/common/extHost.api.impl.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1562,6 +1562,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
15621562
CompletionTriggerKind: extHostTypes.CompletionTriggerKind,
15631563
ConfigurationTarget: extHostTypes.ConfigurationTarget,
15641564
CustomExecution: extHostTypes.CustomExecution,
1565+
DataBreakpoint: extHostTypes.DataBreakpoint,
15651566
DebugAdapterExecutable: extHostTypes.DebugAdapterExecutable,
15661567
DebugAdapterInlineImplementation: extHostTypes.DebugAdapterInlineImplementation,
15671568
DebugAdapterNamedPipeServer: extHostTypes.DebugAdapterNamedPipeServer,

src/vs/workbench/api/common/extHost.protocol.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ import { IFileQueryBuilderOptions, ITextQueryBuilderOptions } from 'vs/workbench
8383
import * as search from 'vs/workbench/services/search/common/search';
8484
import { TextSearchCompleteMessage } from 'vs/workbench/services/search/common/searchExtTypes';
8585
import { ISaveProfileResult } from 'vs/workbench/services/userDataProfile/common/userDataProfile';
86-
import type { TerminalShellExecutionCommandLineConfidence } from 'vscode';
86+
import type * as vscode from 'vscode';
8787

8888
export interface IWorkspaceData extends IStaticWorkspaceData {
8989
folders: { uri: UriComponents; name: string; index: number }[];
@@ -1632,6 +1632,8 @@ export interface MainThreadDebugServiceShape extends IDisposable {
16321632
$setDebugSessionName(id: DebugSessionUUID, name: string): void;
16331633
$customDebugAdapterRequest(id: DebugSessionUUID, command: string, args: any): Promise<any>;
16341634
$getDebugProtocolBreakpoint(id: DebugSessionUUID, breakpoinId: string): Promise<DebugProtocol.Breakpoint | undefined>;
1635+
$getDataBreakpointInfo(id: DebugSessionUUID, name: string, variablesReference?: number): Promise<IDataBreakpointInfo | undefined>;
1636+
$getDataBytesBreakpointInfo(id: DebugSessionUUID, address: string, bytes?: number): Promise<IDataBreakpointInfo | undefined>;
16351637
$appendDebugConsole(value: string): void;
16361638
$registerBreakpoints(breakpoints: Array<ISourceMultiBreakpointDto | IFunctionBreakpointDto | IDataBreakpointDto>): Promise<void>;
16371639
$unregisterBreakpoints(breakpointIds: string[], functionBreakpointIds: string[], dataBreakpointIds: string[]): Promise<void>;
@@ -2338,8 +2340,8 @@ export interface ExtHostTerminalServiceShape {
23382340

23392341
export interface ExtHostTerminalShellIntegrationShape {
23402342
$shellIntegrationChange(instanceId: number): void;
2341-
$shellExecutionStart(instanceId: number, commandLineValue: string, commandLineConfidence: TerminalShellExecutionCommandLineConfidence, isTrusted: boolean, cwd: UriComponents | undefined): void;
2342-
$shellExecutionEnd(instanceId: number, commandLineValue: string, commandLineConfidence: TerminalShellExecutionCommandLineConfidence, isTrusted: boolean, exitCode: number | undefined): void;
2343+
$shellExecutionStart(instanceId: number, commandLineValue: string, commandLineConfidence: vscode.TerminalShellExecutionCommandLineConfidence, isTrusted: boolean, cwd: UriComponents | undefined): void;
2344+
$shellExecutionEnd(instanceId: number, commandLineValue: string, commandLineConfidence: vscode.TerminalShellExecutionCommandLineConfidence, isTrusted: boolean, exitCode: number | undefined): void;
23432345
$shellExecutionData(instanceId: number, data: string): void;
23442346
$cwdChange(instanceId: number, cwd: UriComponents | undefined): void;
23452347
$closeTerminal(instanceId: number): void;
@@ -2395,9 +2397,11 @@ export interface IFunctionBreakpointDto extends IBreakpointDto {
23952397
mode?: string;
23962398
}
23972399

2400+
export type IDataBreakpointInfo = DebugProtocol.DataBreakpointInfoResponse['body'];
2401+
23982402
export interface IDataBreakpointDto extends IBreakpointDto {
23992403
type: 'data';
2400-
dataId: string;
2404+
source: vscode.DataBreakpointSource;
24012405
canPersist: boolean;
24022406
label: string;
24032407
accessTypes?: DebugProtocol.DataBreakpointAccessType[];

src/vs/workbench/api/common/extHostDebugService.ts

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensio
1212
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
1313
import { ISignService } from 'vs/platform/sign/common/sign';
1414
import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
15-
import { DebugSessionUUID, ExtHostDebugServiceShape, IBreakpointsDeltaDto, IThreadFocusDto, IStackFrameFocusDto, IDebugSessionDto, IFunctionBreakpointDto, ISourceMultiBreakpointDto, MainContext, MainThreadDebugServiceShape } from 'vs/workbench/api/common/extHost.protocol';
15+
import { DebugSessionUUID, ExtHostDebugServiceShape, IBreakpointsDeltaDto, IThreadFocusDto, IStackFrameFocusDto, IDebugSessionDto, IFunctionBreakpointDto, ISourceMultiBreakpointDto, MainContext, MainThreadDebugServiceShape, IDataBreakpointDto } from 'vs/workbench/api/common/extHost.protocol';
1616
import { IExtHostEditorTabs } from 'vs/workbench/api/common/extHostEditorTabs';
1717
import { IExtHostExtensionService } from 'vs/workbench/api/common/extHostExtensionService';
1818
import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
@@ -411,7 +411,7 @@ export abstract class ExtHostDebugServiceBase extends DisposableCls implements I
411411
this.fireBreakpointChanges(breakpoints, [], []);
412412

413413
// convert added breakpoints to DTOs
414-
const dtos: Array<ISourceMultiBreakpointDto | IFunctionBreakpointDto> = [];
414+
const dtos: Array<ISourceMultiBreakpointDto | IFunctionBreakpointDto | IDataBreakpointDto> = [];
415415
const map = new Map<string, ISourceMultiBreakpointDto>();
416416
for (const bp of breakpoints) {
417417
if (bp instanceof SourceBreakpoint) {
@@ -446,6 +446,20 @@ export abstract class ExtHostDebugServiceBase extends DisposableCls implements I
446446
functionName: bp.functionName,
447447
mode: bp.mode,
448448
});
449+
} else if (bp instanceof DataBreakpoint) {
450+
dtos.push({
451+
type: 'data',
452+
id: bp.id,
453+
enabled: bp.enabled,
454+
hitCondition: bp.hitCondition,
455+
logMessage: bp.logMessage,
456+
condition: bp.condition,
457+
source: bp.source,
458+
mode: bp.mode,
459+
canPersist: bp.canPersist,
460+
accessType: bp.accessType,
461+
label: bp.label
462+
});
449463
}
450464
}
451465

@@ -728,7 +742,7 @@ export abstract class ExtHostDebugServiceBase extends DisposableCls implements I
728742
if (bpd.type === 'function') {
729743
bp = new FunctionBreakpoint(bpd.functionName, bpd.enabled, bpd.condition, bpd.hitCondition, bpd.logMessage, bpd.mode);
730744
} else if (bpd.type === 'data') {
731-
bp = new DataBreakpoint(bpd.label, bpd.dataId, bpd.canPersist, bpd.enabled, bpd.hitCondition, bpd.condition, bpd.logMessage, bpd.mode);
745+
bp = new DataBreakpoint(bpd.source, bpd.accessType, bpd.canPersist, bpd.label, bpd.enabled, bpd.hitCondition, bpd.condition, bpd.logMessage, bpd.mode);
732746
} else {
733747
const uri = URI.revive(bpd.uri);
734748
bp = new SourceBreakpoint(new Location(uri, new Position(bpd.line, bpd.character)), bpd.enabled, bpd.condition, bpd.hitCondition, bpd.logMessage, bpd.mode);
@@ -769,6 +783,16 @@ export abstract class ExtHostDebugServiceBase extends DisposableCls implements I
769783
sbp.hitCondition = bpd.hitCondition;
770784
sbp.logMessage = bpd.logMessage;
771785
sbp.location = new Location(URI.revive(bpd.uri), new Position(bpd.line, bpd.character));
786+
} else if (bp instanceof DataBreakpoint && bpd.type === 'data') {
787+
const dbp = <any>bp;
788+
dbp.enabled = bpd.enabled;
789+
dbp.condition = bpd.condition;
790+
dbp.hitCondition = bpd.hitCondition;
791+
dbp.logMessage = bpd.logMessage;
792+
dbp.label = bpd.label;
793+
dbp.source = bpd.source;
794+
dbp.canPersist = bpd.canPersist;
795+
dbp.accessType = bpd.accessType;
772796
}
773797
c.push(bp);
774798
}
@@ -1133,6 +1157,12 @@ export class ExtHostDebugSession {
11331157
},
11341158
getDebugProtocolBreakpoint(breakpoint: vscode.Breakpoint): Promise<vscode.DebugProtocolBreakpoint | undefined> {
11351159
return that._debugServiceProxy.$getDebugProtocolBreakpoint(that._id, breakpoint.id);
1160+
},
1161+
getDataBreakpointInfo(name: string, variablesReference?: number): Promise<vscode.DataBreakpointInfo | undefined> {
1162+
return that._debugServiceProxy.$getDataBreakpointInfo(that._id, name, variablesReference);
1163+
},
1164+
getDataBytesBreakpointInfo(address: string, bytes?: number): Promise<vscode.DataBreakpointInfo | undefined> {
1165+
return that._debugServiceProxy.$getDataBytesBreakpointInfo(that._id, address, bytes);
11361166
}
11371167
});
11381168
}

src/vs/workbench/api/common/extHostTypes.ts

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3076,17 +3076,19 @@ export class FunctionBreakpoint extends Breakpoint {
30763076
@es5ClassCompat
30773077
export class DataBreakpoint extends Breakpoint {
30783078
readonly label: string;
3079-
readonly dataId: string;
3079+
readonly source: vscode.DataBreakpointSource;
30803080
readonly canPersist: boolean;
3081+
readonly accessType: vscode.DataBreakpointAccessType;
30813082

3082-
constructor(label: string, dataId: string, canPersist: boolean, enabled?: boolean, condition?: string, hitCondition?: string, logMessage?: string, mode?: string) {
3083+
constructor(source: vscode.DataBreakpointSource | string, accessType: vscode.DataBreakpointAccessType, canPersist?: boolean, label?: string, enabled?: boolean, condition?: string, hitCondition?: string, logMessage?: string, mode?: string) {
30833084
super(enabled, condition, hitCondition, logMessage, mode);
3084-
if (!dataId) {
3085-
throw illegalArgument('dataId');
3086-
}
3087-
this.label = label;
3088-
this.dataId = dataId;
3089-
this.canPersist = canPersist;
3085+
this.source = typeof source === 'string' ? { type: 'variable', dataId: source } : source;
3086+
this.accessType = accessType;
3087+
this.canPersist = canPersist ?? false;
3088+
this.label = label ? label
3089+
: this.source.type === 'variable' ? `DataId '${this.source.dataId}'`
3090+
: this.source.type === 'address' ? `Address '${this.source.address}${this.source.bytes ? `,${this.source.bytes}'` : ''}`
3091+
: `Variable '${this.source.name}${this.source.variablesReference ? `,${this.source.variablesReference}` : ''}'`;
30903092
}
30913093
}
30923094

@@ -4127,7 +4129,7 @@ export function validateTestCoverageCount(cc?: vscode.TestCoverageCount) {
41274129
}
41284130

41294131
if (cc.covered > cc.total) {
4130-
throw new Error(`The total number of covered items (${cc.covered}) cannot be greater than the total (${cc.total})`);
4132+
throw new Error(`The total number of covered items (${cc.covered}) cannot be greater than the total(${cc.total})`);
41314133
}
41324134

41334135
if (cc.total < 0) {

0 commit comments

Comments
 (0)