mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-04-23 06:32:10 +02:00
Bug 494246: prepare command line arguments properly for Windows GDB
Includes splitting out and expanding CommandLineArgsTest from LaunchConfigurationAndRestartTest. Change-Id: I19fa97a847d908c1c780ca767cf688f26a51d684 Signed-off-by: Jonah Graham <jonah@kichwacoders.com>
This commit is contained in:
parent
2ae122963c
commit
03b701c9a5
5 changed files with 421 additions and 152 deletions
|
@ -24,14 +24,18 @@ import org.eclipse.osgi.service.environment.Constants;
|
|||
*/
|
||||
public class CommandLineUtil {
|
||||
|
||||
public static String[] argumentsToArray(String line) {
|
||||
private static boolean isWindows() {
|
||||
boolean osWin;
|
||||
try {
|
||||
osWin = Platform.getOS().equals(Constants.OS_WIN32);
|
||||
} catch (Exception e) {
|
||||
osWin = false;
|
||||
}
|
||||
if (osWin) {
|
||||
return osWin;
|
||||
}
|
||||
|
||||
public static String[] argumentsToArray(String line) {
|
||||
if (isWindows()) {
|
||||
return argumentsToArrayWindowsStyle(line);
|
||||
} else {
|
||||
return argumentsToArrayUnixStyle(line);
|
||||
|
@ -260,4 +264,160 @@ public class CommandLineUtil {
|
|||
}
|
||||
return aList.toArray(new String[aList.size()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts argument array to a string suitable for passing to Bash like:
|
||||
*
|
||||
* This process reverses {@link #argumentsToArray(String)}, but does not
|
||||
* restore the exact same results.
|
||||
*
|
||||
* @param args
|
||||
* the arguments to convert and escape
|
||||
* @param encodeNewline
|
||||
* <code>true</code> if newline (<code>\r</code> or
|
||||
* <code>\n</code>) should be encoded
|
||||
*
|
||||
* @return args suitable for passing to some process that decodes the string
|
||||
* into an argument array
|
||||
* @since 6.2
|
||||
*/
|
||||
public static String argumentsToString(String[] args, boolean encodeNewline) {
|
||||
if (isWindows()) {
|
||||
return argumentsToStringWindowsCreateProcess(args, encodeNewline);
|
||||
} else {
|
||||
// XXX: Bug 507568: We are currently using incorrect assumption that
|
||||
// shell is always bash. AFAIK this is only problematic when
|
||||
// encoding newlines
|
||||
return argumentsToStringBash(args, encodeNewline);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts argument array to a string suitable for passing to Bash like:
|
||||
*
|
||||
* <pre>
|
||||
* /bin/bash -c <args>
|
||||
* </pre>
|
||||
*
|
||||
* In this case the arguments array passed to exec or equivalent will be:
|
||||
*
|
||||
* <pre>
|
||||
* argv[0] = "/bin/bash"
|
||||
* argv[1] = "-c"
|
||||
* argv[2] = argumentsToStringBashStyle(argumentsAsArray)
|
||||
* </pre>
|
||||
*
|
||||
* Replace and concatenate all occurrences of:
|
||||
* <ul>
|
||||
* <li><code>'</code> with <code>"'"</code>
|
||||
* <p>
|
||||
* (as <code>'</code> is used to surround everything else it has to be
|
||||
* quoted or escaped)</li>
|
||||
* <li>newline character, if encoded, with <code>$'\n'</code>
|
||||
* <p>
|
||||
* (<code>\n</code> is treated literally within quotes or as just 'n'
|
||||
* otherwise, whilst supplying the newline character literally ends the
|
||||
* command)</li>
|
||||
* <li>Anything in between and around these occurrences is surrounded by
|
||||
* single quotes.
|
||||
* <p>
|
||||
* (to prevent bash from carrying out substitutions or running arbitrary
|
||||
* code with backticks or <code>$()</code>)</li>
|
||||
* <ul>
|
||||
*
|
||||
* @param args
|
||||
* the arguments to convert and escape
|
||||
* @param encodeNewline
|
||||
* <code>true</code> if newline (<code>\r</code> or
|
||||
* <code>\n</code>) should be encoded
|
||||
* @return args suitable for passing as single argument to bash
|
||||
* @since 6.2
|
||||
*/
|
||||
public static String argumentsToStringBash(String[] args, boolean encodeNewline) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
for (String arg : args) {
|
||||
if (builder.length() > 0) {
|
||||
builder.append(' ');
|
||||
}
|
||||
|
||||
builder.append('\'');
|
||||
for (int j = 0; j < arg.length(); j++) {
|
||||
char c = arg.charAt(j);
|
||||
if (c == '\'') {
|
||||
builder.append("'\"'\"'"); //$NON-NLS-1$
|
||||
} else if (c == '\r' && encodeNewline) {
|
||||
builder.append("'$'\\r''"); //$NON-NLS-1$
|
||||
} else if (c == '\n' && encodeNewline) {
|
||||
builder.append("'$'\\n''"); //$NON-NLS-1$
|
||||
} else {
|
||||
builder.append(c);
|
||||
}
|
||||
}
|
||||
builder.append('\'');
|
||||
}
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts argument array to a string suitable for passing to Windows
|
||||
* CreateProcess
|
||||
*
|
||||
* @param args
|
||||
* the arguments to convert and escape
|
||||
* @param encodeNewline
|
||||
* <code>true</code> if newline (<code>\r</code> or
|
||||
* <code>\n</code>) should be encoded
|
||||
* @return args suitable for passing as single argument to CreateProcess on
|
||||
* Windows
|
||||
* @since 6.2
|
||||
*/
|
||||
public static String argumentsToStringWindowsCreateProcess(String[] args, boolean encodeNewline) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
for (String arg : args) {
|
||||
if (builder.length() > 0) {
|
||||
builder.append(' ');
|
||||
}
|
||||
|
||||
builder.append('"');
|
||||
for (int j = 0; j < arg.length(); j++) {
|
||||
/*
|
||||
* backslashes are special if and only if they are followed by a
|
||||
* double-quote (") therefore doubling them depends on what is
|
||||
* next
|
||||
*/
|
||||
int numBackslashes = 0;
|
||||
for (; j < arg.length() && arg.charAt(j) == '\\'; j++) {
|
||||
numBackslashes++;
|
||||
}
|
||||
if (j == arg.length()) {
|
||||
appendNBackslashes(builder, numBackslashes * 2);
|
||||
} else if (arg.charAt(j) == '"') {
|
||||
appendNBackslashes(builder, numBackslashes * 2);
|
||||
builder.append('"');
|
||||
} else if ((arg.charAt(j) == '\n' || arg.charAt(j) == '\r') && encodeNewline) {
|
||||
builder.append(' ');
|
||||
} else {
|
||||
/*
|
||||
* this really is numBackslashes (no missing * 2), that is
|
||||
* because next character is not a double-quote (")
|
||||
*/
|
||||
appendNBackslashes(builder, numBackslashes);
|
||||
builder.append(arg.charAt(j));
|
||||
}
|
||||
}
|
||||
builder.append('"');
|
||||
}
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
private static void appendNBackslashes(StringBuilder builder, int numBackslashes) {
|
||||
for (int i = 0; i < numBackslashes; i++) {
|
||||
builder.append('\\');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ package org.eclipse.cdt.dsf.mi.service.command.commands;
|
|||
|
||||
import java.util.ArrayList;
|
||||
import org.eclipse.cdt.dsf.mi.service.IMIContainerDMContext;
|
||||
import org.eclipse.cdt.utils.CommandLineUtil;
|
||||
|
||||
/**
|
||||
* -gdb-set args ARGS
|
||||
|
@ -34,45 +35,15 @@ public class MIGDBSetArgs extends MIGDBSet {
|
|||
super(dmc, null);
|
||||
fParameters = new ArrayList<Adjustable>();
|
||||
fParameters.add(new MIStandardParameterAdjustable("args")); //$NON-NLS-1$
|
||||
for (int i = 0; i < arguments.length; i++) {
|
||||
fParameters.add(new MIArgumentAdjustable(arguments[i]));
|
||||
}
|
||||
}
|
||||
|
||||
private static class MIArgumentAdjustable extends MICommandAdjustable {
|
||||
|
||||
public MIArgumentAdjustable(String value) {
|
||||
super(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAdjustedValue() {
|
||||
// Replace and concatenate all occurrences of:
|
||||
// ' with "'"
|
||||
// (as ' is used to surround everything else
|
||||
// it has to be quoted or escaped)
|
||||
// newline character with $'\n'
|
||||
// (\n is treated literally within quotes or
|
||||
// as just 'n' otherwise, whilst supplying
|
||||
// the newline character literally ends the command)
|
||||
// Anything in between and around these occurrences
|
||||
// is surrounded by single quotes.
|
||||
// (to prevent bash from carrying out substitutions
|
||||
// or running arbitrary code with backticks or $())
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append('\'');
|
||||
for (int j = 0; j < value.length(); j++) {
|
||||
char c = value.charAt(j);
|
||||
if (c == '\'') {
|
||||
builder.append("'\"'\"'"); //$NON-NLS-1$
|
||||
} else if (c == '\n') {
|
||||
builder.append("'$'\\n''"); //$NON-NLS-1$
|
||||
} else {
|
||||
builder.append(c);
|
||||
}
|
||||
}
|
||||
builder.append('\'');
|
||||
return builder.toString();
|
||||
}
|
||||
/*
|
||||
* GDB-MI terminates the -gdb-set on the newline, so we have to encode
|
||||
* newlines or we get an MI error. Some platforms (e.g. Bash on
|
||||
* non-windows) can encode newline into something that is received as a
|
||||
* newline to the program, other platforms (windows) cannot encode the
|
||||
* newline in anyway that is recived as a newline, so it is encoded as
|
||||
* whitepsace.
|
||||
*/
|
||||
String args = CommandLineUtil.argumentsToString(arguments, true);
|
||||
fParameters.add(new MINoChangeAdjustable(args));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,243 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2011, 2016 Ericsson and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Ericsson - Initial Implementation
|
||||
* Simon Marchi (Ericsson) - Remove a catch that just fails a test.
|
||||
* Simon Marchi (Ericsson) - Disable tests for gdb < 7.2.
|
||||
* Jonah Graham (Kichwa Coders) - Split arguments tests out of LaunchConfigurationAndRestartTest
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.tests.dsf.gdb.tests;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.endsWith;
|
||||
import static org.hamcrest.Matchers.startsWith;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants;
|
||||
import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
|
||||
import org.eclipse.cdt.dsf.concurrent.Query;
|
||||
import org.eclipse.cdt.dsf.debug.service.IExpressions;
|
||||
import org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionDMContext;
|
||||
import org.eclipse.cdt.dsf.debug.service.IFormattedValues.FormattedValueDMData;
|
||||
import org.eclipse.cdt.dsf.mi.service.MIExpressions;
|
||||
import org.eclipse.cdt.dsf.mi.service.command.events.MIStoppedEvent;
|
||||
import org.eclipse.cdt.dsf.service.DsfServicesTracker;
|
||||
import org.eclipse.cdt.dsf.service.DsfSession;
|
||||
import org.eclipse.cdt.tests.dsf.gdb.framework.BaseParametrizedTestCase;
|
||||
import org.eclipse.cdt.tests.dsf.gdb.framework.SyncUtil;
|
||||
import org.eclipse.cdt.tests.dsf.gdb.launching.TestsPlugin;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
|
||||
@RunWith(Parameterized.class)
|
||||
public class CommandLineArgsTest extends BaseParametrizedTestCase {
|
||||
protected static final String EXEC_NAME = "LaunchConfigurationAndRestartTestApp.exe";
|
||||
|
||||
private DsfSession fSession;
|
||||
private DsfServicesTracker fServicesTracker;
|
||||
private IExpressions fExpService;
|
||||
|
||||
@Override
|
||||
public void doBeforeTest() throws Exception {
|
||||
removeTeminatedLaunchesBeforeTest();
|
||||
setLaunchAttributes();
|
||||
// Can't run the launch right away because each test needs to first set
|
||||
// ICDTLaunchConfigurationConstants.ATTR_PROGRAM_ARGUMENTS
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setLaunchAttributes() {
|
||||
super.setLaunchAttributes();
|
||||
|
||||
// Set the binary
|
||||
setLaunchAttribute(ICDTLaunchConfigurationConstants.ATTR_PROGRAM_NAME, EXEC_PATH + EXEC_NAME);
|
||||
}
|
||||
|
||||
// This method cannot be tagged as @Before, because the launch is not
|
||||
// running yet. We have to call this manually after all the proper
|
||||
// parameters have been set for the launch
|
||||
@Override
|
||||
protected void doLaunch() throws Exception {
|
||||
// perform the launch
|
||||
super.doLaunch();
|
||||
|
||||
fSession = getGDBLaunch().getSession();
|
||||
Runnable runnable = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
fServicesTracker = new DsfServicesTracker(TestsPlugin.getBundleContext(), fSession.getId());
|
||||
|
||||
fExpService = fServicesTracker.getService(IExpressions.class);
|
||||
}
|
||||
};
|
||||
fSession.getExecutor().submit(runnable).get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a string of form 0x123456 "ab\"cd" to ab"cd
|
||||
*/
|
||||
protected String convertDetails(String details) {
|
||||
|
||||
// check parser assumptions on input format
|
||||
assertThat(details, startsWith("0x"));
|
||||
assertThat(details, containsString(" \""));
|
||||
assertThat(details, endsWith("\""));
|
||||
|
||||
int firstSpace = details.indexOf(' ');
|
||||
boolean lastWasEscape = false;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = firstSpace + 2; i < details.length() - 1; i++) {
|
||||
char c = details.charAt(i);
|
||||
if (lastWasEscape) {
|
||||
switch (c) {
|
||||
case 't':
|
||||
sb.append('\t');
|
||||
break;
|
||||
case 'r':
|
||||
sb.append('\r');
|
||||
break;
|
||||
case 'n':
|
||||
sb.append('\n');
|
||||
break;
|
||||
default:
|
||||
sb.append(c);
|
||||
break;
|
||||
}
|
||||
lastWasEscape = false;
|
||||
} else {
|
||||
if (c == '\\') {
|
||||
lastWasEscape = true;
|
||||
} else {
|
||||
sb.append(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assertFalse("unexpected trailing backslash (\\)", lastWasEscape);
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that the target program received the arguments as expected
|
||||
*
|
||||
* @param expected
|
||||
* arguments to check, e.g. check expected[0].equals(argv[1])
|
||||
*/
|
||||
protected void checkArguments(String... expected) throws Throwable {
|
||||
|
||||
MIStoppedEvent stoppedEvent = getInitialStoppedEvent();
|
||||
|
||||
// Check that argc is correct
|
||||
final IExpressionDMContext argcDmc = SyncUtil.createExpression(stoppedEvent.getDMContext(), "argc");
|
||||
Query<FormattedValueDMData> query = new Query<FormattedValueDMData>() {
|
||||
@Override
|
||||
protected void execute(DataRequestMonitor<FormattedValueDMData> rm) {
|
||||
fExpService.getFormattedExpressionValue(
|
||||
fExpService.getFormattedValueContext(argcDmc, MIExpressions.DETAILS_FORMAT), rm);
|
||||
}
|
||||
};
|
||||
|
||||
fExpService.getExecutor().execute(query);
|
||||
FormattedValueDMData value = query.get(TestsPlugin.massageTimeout(500), TimeUnit.MILLISECONDS);
|
||||
|
||||
assertTrue("Expected " + (1 + expected.length) + " but got " + value.getFormattedValue(),
|
||||
value.getFormattedValue().trim().equals(Integer.toString(1 + expected.length)));
|
||||
|
||||
// check all argvs are correct
|
||||
for (int i = 0; i < expected.length; i++) {
|
||||
final IExpressionDMContext argvDmc = SyncUtil.createExpression(stoppedEvent.getDMContext(),
|
||||
"argv[" + (i + 1) + "]");
|
||||
Query<FormattedValueDMData> query2 = new Query<FormattedValueDMData>() {
|
||||
@Override
|
||||
protected void execute(DataRequestMonitor<FormattedValueDMData> rm) {
|
||||
fExpService.getFormattedExpressionValue(
|
||||
fExpService.getFormattedValueContext(argvDmc, MIExpressions.DETAILS_FORMAT), rm);
|
||||
}
|
||||
};
|
||||
|
||||
fExpService.getExecutor().execute(query2);
|
||||
FormattedValueDMData value2 = query2.get(TestsPlugin.massageTimeout(500), TimeUnit.MILLISECONDS);
|
||||
String details = value2.getFormattedValue();
|
||||
String actual = convertDetails(details);
|
||||
assertEquals(expected[i], actual);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the program, setting ATTR_PROGRAM_ARGUMENTS to the attrProgramArgs
|
||||
* and ensuring debugged program receives args for argv (excluding argv[0]
|
||||
* which isn't checked)
|
||||
*/
|
||||
protected void doTest(String attrProgramArgs, String... args) throws Throwable {
|
||||
setLaunchAttribute(ICDTLaunchConfigurationConstants.ATTR_PROGRAM_ARGUMENTS, attrProgramArgs);
|
||||
doLaunch();
|
||||
checkArguments(args);
|
||||
}
|
||||
|
||||
/**
|
||||
* This test will tell the launch to set some arguments for the program. We
|
||||
* will then check that the program has the same arguments.
|
||||
*/
|
||||
@Test
|
||||
public void testSettingArguments() throws Throwable {
|
||||
doTest("1 2 3\n4 5 6", "1", "2", "3", "4", "5", "6");
|
||||
}
|
||||
|
||||
/**
|
||||
* This test will tell the launch to set some arguments for the program. We
|
||||
* will then check that the program has the same arguments. See bug 381804
|
||||
*/
|
||||
@Test
|
||||
public void testSettingArgumentsWithSymbols() throws Throwable {
|
||||
// Set a argument with double quotes and spaces, which should be
|
||||
// considered a single argument
|
||||
doTest("--c=\"c < s: 'a' t: 'b'>\"", "--c=c < s: 'a' t: 'b'>");
|
||||
}
|
||||
|
||||
/**
|
||||
* This test will tell the launch to set some more arguments for the
|
||||
* program. We will then check that the program has the same arguments. See
|
||||
* bug 474648
|
||||
*/
|
||||
@Test
|
||||
public void testSettingArgumentsWithSpecialSymbols() throws Throwable {
|
||||
// Test that arguments are parsed correctly:
|
||||
// The string provided by the user is split into arguments on spaces
|
||||
// except for those inside quotation marks, double or single.
|
||||
// Any character within quotation marks or after the backslash character
|
||||
// is treated literally, whilst these special characters have to be
|
||||
// escaped explicitly to be recorded.
|
||||
// All other characters including semicolons, backticks, pipes, dollars
|
||||
// and newlines
|
||||
// must be treated literally.
|
||||
doTest("--abc=\"x;y;z\nsecondline: \"`date`$PS1\"`date | wc`\"",
|
||||
"--abc=x;y;z\nsecondline: `date`$PS1`date | wc`");
|
||||
}
|
||||
|
||||
/**
|
||||
* Check combinations of quote characters
|
||||
*/
|
||||
@Test
|
||||
public void testSettingArgumentsWithQuotes() throws Throwable {
|
||||
doTest("\"'\" '\"'", "'", "\"");
|
||||
}
|
||||
|
||||
/**
|
||||
* Check tab characters
|
||||
*/
|
||||
@Test
|
||||
public void testSettingArgumentsWithTabs() throws Throwable {
|
||||
doTest("\"\t\"\t'\t'", "\t", "\t");
|
||||
}
|
||||
}
|
|
@ -488,6 +488,10 @@ public class LaunchConfigurationAndRestartTest extends BaseParametrizedTestCase
|
|||
/**
|
||||
* This test will tell the launch to set some arguments for the program. We will
|
||||
* then check that the program has the same arguments.
|
||||
*
|
||||
* NOTE: The main setting arguments tests are in {@link CommandLineArgsTest}, this
|
||||
* test remains here to test interaction of command line arguments are restarting.
|
||||
* See {@link #testSettingArgumentsRestart()}
|
||||
*/
|
||||
@Test
|
||||
public void testSettingArguments() throws Throwable {
|
||||
|
@ -552,116 +556,6 @@ public class LaunchConfigurationAndRestartTest extends BaseParametrizedTestCase
|
|||
testSettingArguments();
|
||||
}
|
||||
|
||||
/**
|
||||
* This test will tell the launch to set some arguments for the program. We will
|
||||
* then check that the program has the same arguments.
|
||||
* See bug 381804
|
||||
*/
|
||||
@Test
|
||||
public void testSettingArgumentsWithSymbols() throws Throwable {
|
||||
// Set a argument with double quotes and spaces, which should be considered a single argument
|
||||
String argumentToPreserveSpaces = "--c=\"c < s: 'a' t: 'b'>\"";
|
||||
String argumentUsedByGDB = "\"--c=c < s: 'a' t: 'b'>\"";
|
||||
|
||||
setLaunchAttribute(ICDTLaunchConfigurationConstants.ATTR_PROGRAM_ARGUMENTS, argumentToPreserveSpaces);
|
||||
doLaunch();
|
||||
|
||||
MIStoppedEvent stoppedEvent = getInitialStoppedEvent();
|
||||
|
||||
// Check that argc is correct
|
||||
final IExpressionDMContext argcDmc = SyncUtil.createExpression(stoppedEvent.getDMContext(), "argc");
|
||||
Query<FormattedValueDMData> query = new Query<FormattedValueDMData>() {
|
||||
@Override
|
||||
protected void execute(DataRequestMonitor<FormattedValueDMData> rm) {
|
||||
fExpService.getFormattedExpressionValue(
|
||||
fExpService.getFormattedValueContext(argcDmc, MIExpressions.DETAILS_FORMAT), rm);
|
||||
}
|
||||
};
|
||||
fExpService.getExecutor().execute(query);
|
||||
FormattedValueDMData value = query.get(TestsPlugin.massageTimeout(500), TimeUnit.MILLISECONDS);
|
||||
|
||||
// Argc should be 2: the program name and the one arguments
|
||||
assertTrue("Expected 2 but got " + value.getFormattedValue(),
|
||||
value.getFormattedValue().trim().equals("2"));
|
||||
|
||||
// Check that argv is also correct.
|
||||
final IExpressionDMContext argvDmc = SyncUtil.createExpression(stoppedEvent.getDMContext(), "argv[argc-1]");
|
||||
Query<FormattedValueDMData> query2 = new Query<FormattedValueDMData>() {
|
||||
@Override
|
||||
protected void execute(DataRequestMonitor<FormattedValueDMData> rm) {
|
||||
fExpService.getFormattedExpressionValue(
|
||||
fExpService.getFormattedValueContext(argvDmc, MIExpressions.DETAILS_FORMAT), rm);
|
||||
}
|
||||
};
|
||||
fExpService.getExecutor().execute(query2);
|
||||
value = query2.get(TestsPlugin.massageTimeout(500), TimeUnit.MILLISECONDS);
|
||||
assertTrue("Expected \"" + argumentUsedByGDB + "\" but got " + value.getFormattedValue(),
|
||||
value.getFormattedValue().trim().endsWith(argumentUsedByGDB));
|
||||
}
|
||||
|
||||
/**
|
||||
* This test will tell the launch to set some more arguments for the program. We will
|
||||
* then check that the program has the same arguments.
|
||||
* See bug 474648
|
||||
*/
|
||||
@Test
|
||||
public void testSettingArgumentsWithSpecialSymbols() throws Throwable {
|
||||
// Test that arguments are parsed correctly:
|
||||
// The string provided by the user is split into arguments on spaces
|
||||
// except for those inside quotation marks, double or single.
|
||||
// Any character within quotation marks or after the backslash character
|
||||
// is treated literally, whilst these special characters have to be
|
||||
// escaped explicitly to be recorded.
|
||||
// All other characters including semicolons, backticks, pipes, dollars and newlines
|
||||
// must be treated literally.
|
||||
String argumentToPreserveSpaces = "--abc=\"x;y;z\nsecondline: \"`date`$PS1\"`date | wc`\"";
|
||||
String argumentUsedByGDB = "\"--abc=x;y;z\\nsecondline: `date`$PS1`date | wc`\"";
|
||||
|
||||
setLaunchAttribute(ICDTLaunchConfigurationConstants.ATTR_PROGRAM_ARGUMENTS, argumentToPreserveSpaces);
|
||||
doLaunch();
|
||||
|
||||
MIStoppedEvent stoppedEvent = getInitialStoppedEvent();
|
||||
|
||||
// Check that argc is correct
|
||||
final IExpressionDMContext argcDmc = SyncUtil.createExpression(stoppedEvent.getDMContext(), "argc");
|
||||
Query<FormattedValueDMData> query = new Query<FormattedValueDMData>() {
|
||||
@Override
|
||||
protected void execute(DataRequestMonitor<FormattedValueDMData> rm) {
|
||||
fExpService.getFormattedExpressionValue(
|
||||
fExpService.getFormattedValueContext(argcDmc, MIExpressions.DETAILS_FORMAT), rm);
|
||||
}
|
||||
};
|
||||
fExpService.getExecutor().execute(query);
|
||||
FormattedValueDMData value = query.get(TestsPlugin.massageTimeout(500), TimeUnit.MILLISECONDS);
|
||||
|
||||
// Argc should be 2: the program name and the four arguments.
|
||||
assertTrue("Expected 2 but got " + value.getFormattedValue(),
|
||||
value.getFormattedValue().trim().equals("2"));
|
||||
|
||||
// Check that argv is also correct.
|
||||
final IExpressionDMContext argvDmc = SyncUtil.createExpression(stoppedEvent.getDMContext(), "argv[argc-1]");
|
||||
Query<FormattedValueDMData> query2 = new Query<FormattedValueDMData>() {
|
||||
@Override
|
||||
protected void execute(DataRequestMonitor<FormattedValueDMData> rm) {
|
||||
fExpService.getFormattedExpressionValue(
|
||||
fExpService.getFormattedValueContext(argvDmc, MIExpressions.DETAILS_FORMAT), rm);
|
||||
}
|
||||
};
|
||||
fExpService.getExecutor().execute(query2);
|
||||
value = query2.get(TestsPlugin.massageTimeout(500), TimeUnit.MILLISECONDS);
|
||||
assertTrue("Expected \"" + argumentUsedByGDB + "\" but got " + value.getFormattedValue(),
|
||||
value.getFormattedValue().endsWith(argumentUsedByGDB));
|
||||
}
|
||||
|
||||
/**
|
||||
* Repeat the test testSettingArguments, but after a restart.
|
||||
*/
|
||||
@Test
|
||||
public void testSettingArgumentsWithSymbolsRestart() throws Throwable {
|
||||
fRestart = true;
|
||||
testSettingArgumentsWithSymbols();
|
||||
}
|
||||
|
||||
/**
|
||||
* This test will tell the launch to "stop on main" at method main(), which we will verify.
|
||||
*/
|
||||
|
|
|
@ -59,6 +59,7 @@ import org.junit.runners.Suite;
|
|||
PostMortemCoreTest.class,
|
||||
CommandTimeoutTest.class,
|
||||
ThreadStackFrameSyncTest.class,
|
||||
CommandLineArgsTest.class,
|
||||
/* Add your test class here */
|
||||
})
|
||||
public class SuiteGdb {
|
||||
|
|
Loading…
Add table
Reference in a new issue