Skip to content

Commit b7e6ab9

Browse files
committed
Add tests for "run": "preserve"
1 parent 9199960 commit b7e6ab9

3 files changed

Lines changed: 163 additions & 0 deletions

File tree

src/integration-tests/attach.spec.ts

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,56 @@ describe('attach', function () {
5656
expect(await dc.evaluate('argv[1]')).to.contain('running-from-spawn');
5757
});
5858

59+
function makeRunArgTest(runArg: string) {
60+
return async function (this: Mocha.Context) {
61+
if (isRemoteTest) {
62+
// attachRemote.spec.ts is the test for when isRemoteTest
63+
this.skip();
64+
}
65+
if (!gdbAsync && runArg === 'always') {
66+
// in sync mode when all threads are running we can't ask '-thread-info'
67+
this.skip();
68+
}
69+
70+
const attachArgs = fillDefaults(this.test, {
71+
program: program,
72+
processId: `${inferior.pid}`,
73+
run: runArg,
74+
} as AttachRequestArguments);
75+
76+
await Promise.all([
77+
dc
78+
.waitForEvent('initialized')
79+
.then(() => dc.configurationDoneRequest()),
80+
dc.initializeRequest().then(() => dc.attachRequest(attachArgs)),
81+
]);
82+
83+
const threadInfo = JSON.parse(
84+
(
85+
await dc.evaluateRequest({
86+
expression: '>-thread-info',
87+
context: 'repl',
88+
})
89+
).body.result
90+
);
91+
const threadStates = threadInfo.threads.map((t: any) => t.state);
92+
if (runArg === 'always') {
93+
expect(threadStates).to.contain('running');
94+
expect(threadStates).not.to.contain('stopped');
95+
} else if (runArg === 'preserve') {
96+
expect(threadStates).to.contain('stopped');
97+
} else {
98+
expect(runArg).to.be.oneOf(['always', 'preserve']);
99+
}
100+
};
101+
}
102+
103+
it('can attach and continue stopped threads', makeRunArgTest('always'));
104+
it(
105+
'can attach without continuing stopped threads',
106+
makeRunArgTest('preserve')
107+
);
108+
59109
it('can attach and hit a breakpoint with no program specified', async function () {
60110
if (isRemoteTest) {
61111
// attachRemote.spec.ts is the test for when isRemoteTest

src/integration-tests/attachRemote.spec.ts

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import {
2323
gdbAsync,
2424
fillDefaults,
2525
gdbNonStop,
26+
isRemoteTest,
2627
} from './utils';
2728
import { expect } from 'chai';
2829
import { DebugProtocol } from '@vscode/debugprotocol';
@@ -81,6 +82,59 @@ describe('attach remote', function () {
8182
expect(await dc.evaluate('argv[1]')).to.contain('running-from-spawn');
8283
});
8384

85+
function makeRunArgTest(runArg: string) {
86+
return async function (this: Mocha.Context) {
87+
if (!isRemoteTest) {
88+
// attach.spec.ts is the test for when !isRemoteTest
89+
this.skip();
90+
}
91+
if ((!gdbAsync || !gdbNonStop) && runArg === 'always') {
92+
// in sync mode when all threads are running we can't ask '-thread-info'
93+
this.skip();
94+
}
95+
96+
const attachArgs = fillDefaults(this.test, {
97+
program: program,
98+
target: {
99+
type: 'remote',
100+
parameters: [`localhost:${port}`],
101+
} as TargetAttachArguments,
102+
run: runArg,
103+
} as TargetAttachRequestArguments);
104+
105+
await Promise.all([
106+
dc
107+
.waitForEvent('initialized')
108+
.then(() => dc.configurationDoneRequest()),
109+
dc.initializeRequest().then(() => dc.attachRequest(attachArgs)),
110+
]);
111+
112+
const threadInfo = JSON.parse(
113+
(
114+
await dc.evaluateRequest({
115+
expression: '>-thread-info',
116+
context: 'repl',
117+
})
118+
).body.result
119+
);
120+
const threadStates = threadInfo.threads.map((t: any) => t.state);
121+
if (runArg === 'always') {
122+
expect(threadStates).to.contain('running');
123+
expect(threadStates).not.to.contain('stopped');
124+
} else if (runArg === 'preserve') {
125+
expect(threadStates).to.contain('stopped');
126+
} else {
127+
expect(runArg).to.be.oneOf(['always', 'preserve']);
128+
}
129+
};
130+
}
131+
132+
it('can attach and continue stopped threads', makeRunArgTest('always'));
133+
it(
134+
'can attach without continuing stopped threads',
135+
makeRunArgTest('preserve')
136+
);
137+
84138
it('can attach remote and hit a breakpoint without a program', async function () {
85139
if (os.platform() === 'win32') {
86140
// win32 host does support this use case

src/integration-tests/launch.spec.ts

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import {
1818
import { CdtDebugClient } from './debugClient';
1919
import {
2020
fillDefaults,
21+
gdbAsync,
2122
gdbNonStop,
2223
isRemoteTest,
2324
standardBeforeEach,
@@ -33,6 +34,7 @@ describe('launch', function () {
3334
const unicodeProgram = path.join(testProgramsDir, 'bug275-测试');
3435
// the name of this file is short enough to work around https://sourceware.org/bugzilla/show_bug.cgi?id=30618
3536
const unicodeSrc = path.join(testProgramsDir, 'bug275-测试.c');
37+
const loopForeverProgram = path.join(testProgramsDir, 'loopforever');
3638

3739
beforeEach(async function () {
3840
dc = await standardBeforeEach();
@@ -54,6 +56,63 @@ describe('launch', function () {
5456
);
5557
});
5658

59+
function makeRunArgTest(runArg: string) {
60+
return async function (this: Mocha.Context) {
61+
// This tests both local and remote cases and does not need to be
62+
// duplicated in launchRemote.spec.ts (beforeEach and afterEach are
63+
// similar enough here and there).
64+
if (
65+
(!gdbAsync || (isRemoteTest && !gdbNonStop)) &&
66+
runArg === 'always'
67+
) {
68+
// in sync mode when all threads are running we can't ask '-thread-info'
69+
// (remote needs non-stop to be really async)
70+
this.skip();
71+
}
72+
73+
const launchArgs = fillDefaults(this.test, {
74+
program: loopForeverProgram,
75+
run: runArg,
76+
} as LaunchRequestArguments);
77+
78+
await Promise.all([
79+
dc
80+
.waitForEvent('initialized')
81+
.then(() => dc.configurationDoneRequest()),
82+
dc.initializeRequest().then(() => dc.launchRequest(launchArgs)),
83+
]);
84+
85+
const threadInfo = JSON.parse(
86+
(
87+
await dc.evaluateRequest({
88+
expression: '>-thread-info',
89+
context: 'repl',
90+
})
91+
).body.result
92+
);
93+
const threadStates = threadInfo.threads.map((t: any) => t.state);
94+
if (runArg === 'always') {
95+
expect(threadStates).to.contain('running');
96+
expect(threadStates).not.to.contain('stopped');
97+
} else if (runArg === 'preserve') {
98+
if (isRemoteTest) {
99+
// GDBTargetDebugSession interprets "launch" as "launch
100+
// gdbserver", not "launch the program", so this case actually
101+
// behaves like an attach, not like a launch.
102+
expect(threadStates).to.contain('stopped');
103+
} else {
104+
// GDBDebugSessionBase implements "launch" as expected.
105+
expect(threadStates).to.be.an('array').that.is.empty;
106+
}
107+
} else {
108+
expect(runArg).to.be.oneOf(['always', 'preserve']);
109+
}
110+
};
111+
}
112+
113+
it('can launch and run', makeRunArgTest('always'));
114+
it('can launch without running', makeRunArgTest('preserve'));
115+
57116
it('receives an error when no port is provided nor a suitable regex', async function () {
58117
if (!isRemoteTest) {
59118
this.skip();

0 commit comments

Comments
 (0)