Skip to content

Commit

Permalink
Merge pull request #1941 from cognitree/fix-scenario-parsing
Browse files Browse the repository at this point in the history
Scenario parser should honor double and single quotes in values
  • Loading branch information
jshook committed May 10, 2024
2 parents 64a2886 + 0f8bc4d commit f3ab1fa
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 3 deletions.
Expand Up @@ -130,7 +130,7 @@ public void testThatUndefValuesAreUndefined() {
"driver", "stdout",
"labels", "workload:scenario_test,scenario:schema_only",
"step", "schema",
"tags", "block:\"schema.*\"",
"tags", "block:schema.*",
"workload", "scenario_test"
));
NBCLIOptions opts1 = new NBCLIOptions(new String[]{"scenario_test", "schema_only", "doundef=20"}, NBCLIOptions.Mode.ParseAllOptions);
Expand Down Expand Up @@ -185,7 +185,7 @@ public void testSubStepSelection() {
"driver", "stdout",
"labels", "workload:scenario_test,scenario:schema_only",
"step", "schema",
"tags", "block:\"schema.*\"",
"tags", "block:schema.*",
"workload", "scenario_test"
));
NBCLIOptions opts1 = new NBCLIOptions(new String[]{"example_scenarios", "namedsteps.one", "testparam1=testvalue2"}, NBCLIOptions.Mode.ParseAllOptions);
Expand All @@ -201,4 +201,37 @@ public void testThatDuplicateParamInScenarioDefThrowsError() {
.isThrownBy(() -> new NBCLIOptions(new String[]{"scenario_test", "duplicate_param"}, NBCLIOptions.Mode.ParseAllOptions))
.withMessageContaining("Duplicate occurrence of parameter \"threads\"");
}

@Test
public void testCommandSplitter() {
String normalCmd = "run driver=stdout tags==block:main-read cycles==10 threads=auto param=test1";
assertThat(NBCLIScenarioPreprocessor.splitCommand(normalCmd))
.isEqualTo(new String[]{"run", "driver=stdout", "tags==block:main-read", "cycles==10", "threads=auto", "param=test1"});

// param='test1' or pram="test1" -> param=test1
String quotedParamCmd = "run driver=stdout tags==block:\"main.*\" cycles==10 threads=auto param='test1'";
assertThat(NBCLIScenarioPreprocessor.splitCommand(quotedParamCmd))
.isEqualTo(new String[]{"run", "driver=stdout", "tags==block:main.*", "cycles==10", "threads=auto", "param=test1"});

// param="test 1" or params='test 1' -> param=test 1
String paramWithSpaceCmd = "run driver=stdout tags==block:\"main.*\" cycles==10 threads=auto param='test 1'";
assertThat(NBCLIScenarioPreprocessor.splitCommand(paramWithSpaceCmd))
.isEqualTo(new String[]{"run", "driver=stdout", "tags==block:main.*", "cycles==10", "threads=auto", "param=test 1"});

// param=\"test1\" -> param="test1", param=\'test1\' -> param='test1'
String escapingQuotesParamCmd = "run driver=stdout tags==block:'main.*' cycles==10 threads=auto param=\\\"test1\\\"";
assertThat(NBCLIScenarioPreprocessor.splitCommand(escapingQuotesParamCmd))
.isEqualTo(new String[]{"run", "driver=stdout", "tags==block:main.*", "cycles==10", "threads=auto", "param=\"test1\""});

// param=test1\\test2 -> param=test1\test2
String escapingSlashParamCmd = "run driver=stdout tags==block:'main.*' cycles==10 threads=auto param=test1\\\\test2";
assertThat(NBCLIScenarioPreprocessor.splitCommand(escapingSlashParamCmd))
.isEqualTo(new String[]{"run", "driver=stdout", "tags==block:main.*", "cycles==10", "threads=auto", "param=test1\\test2"});

// param="test1 -> unclosed quote "
String unclosedQuoteCmd = "run driver=stdout tags==block:'main.*' cycles==10 threads=auto param=\"test1";
assertThatExceptionOfType(BasicError.class)
.isThrownBy(() -> NBCLIScenarioPreprocessor.splitCommand(unclosedQuoteCmd))
.withMessageContaining("Unclosed quote found in scenario cmd");
}
}
Expand Up @@ -252,10 +252,31 @@ public static String sanitize(String word) {

private static final Pattern WordAndMaybeAssignment = Pattern.compile("(?<name>\\w[-_\\d\\w.]+)((?<oper>=+)(?<val>.+))?");

public static String[] splitCommand(String cmd) {
// split command by honoring single quotes, double quotes and escape characters
String[] namedStepPieces = cmd.split(" +(?=([^\"]*\"[^\"]*\")*[^\"]*$)(?=([^']*'[^']*')*[^']*$)");
Pattern pattern1 = Pattern.compile("(?<!\\\\)\"");
Pattern pattern2 = Pattern.compile("(?<!\\\\)'");
for (int i = 0; i < namedStepPieces.length; i++) {
// check if the quotes are balanced
String stepPiece = namedStepPieces[i];
boolean balanced = pattern1.matcher(stepPiece).results().count() % 2 == 0;
balanced = balanced && (pattern2.matcher(stepPiece).results().count() % 2 == 0);
if (!balanced) {
throw new BasicError("Unclosed quote found in scenario cmd '" + cmd + "'");
}
// remove single quotes, double quotes and escape character
stepPiece = pattern1.matcher(stepPiece).replaceAll("");
stepPiece = pattern2.matcher(stepPiece).replaceAll("");
namedStepPieces[i] = stepPiece.replaceAll(Matcher.quoteReplacement("\\(?!\\)"), "");
}
return namedStepPieces;
}

private static LinkedHashMap<String, SCNamedParam> parseStep(String cmd, String stepName, String scenarioName) {
LinkedHashMap<String, SCNamedParam> parsedStep = new LinkedHashMap<>();

String[] namedStepPieces = cmd.split(" +");
String[] namedStepPieces = splitCommand(cmd);
for (String commandFragment : namedStepPieces) {
Matcher matcher = WordAndMaybeAssignment.matcher(commandFragment);

Expand Down

0 comments on commit f3ab1fa

Please sign in to comment.