This is an automated email from the ASF dual-hosted git repository.

heneveld pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/brooklyn-server.git


The following commit(s) were added to refs/heads/master by this push:
     new 5b1ea500dc expression parser - tweak to multi-word handling
5b1ea500dc is described below

commit 5b1ea500dcdbe71d2c12490906a680e251f4f722
Author: Alex Heneveld <a...@cloudsoft.io>
AuthorDate: Thu Feb 8 15:32:03 2024 +0000

    expression parser - tweak to multi-word handling
    
    simplify non-final-match-raw semantics
---
 .../brooklyn/core/workflow/ShorthandProcessor.java |   3 +-
 .../core/workflow/ShorthandProcessorEpToQst.java   |  22 ++--
 .../brooklyn/core/workflow/WorkflowBasicTest.java  |  76 +++++++++---
 .../core/workflow/WorkflowMapAndListTest.java      |  15 +--
 .../core/workflow/WorkflowOperandsTest.java        |  14 +--
 .../workflow/WorkflowParsingEdgeCasesTest.java     | 134 +++++++++++++++++++++
 6 files changed, 209 insertions(+), 55 deletions(-)

diff --git 
a/core/src/main/java/org/apache/brooklyn/core/workflow/ShorthandProcessor.java 
b/core/src/main/java/org/apache/brooklyn/core/workflow/ShorthandProcessor.java
index 0adbaffc23..356d655705 100644
--- 
a/core/src/main/java/org/apache/brooklyn/core/workflow/ShorthandProcessor.java
+++ 
b/core/src/main/java/org/apache/brooklyn/core/workflow/ShorthandProcessor.java
@@ -37,7 +37,8 @@ public class ShorthandProcessor {
         return delegate.process(input);
     }
 
-    /** whether the last match should preserve quotes and spaces; default 
false */
+    /** optionally skip the automatic unwrapping of a single quoted last word 
lining up with the last word of a template;
+     * by default, we unwrap in that one special case, to facilitate eg return 
"something fancy" */
     public ShorthandProcessor withFinalMatchRaw(boolean finalMatchRaw) {
         delegate.withFinalMatchRaw(finalMatchRaw);
         return this;
diff --git 
a/core/src/main/java/org/apache/brooklyn/core/workflow/ShorthandProcessorEpToQst.java
 
b/core/src/main/java/org/apache/brooklyn/core/workflow/ShorthandProcessorEpToQst.java
index cb94600636..6e48f8dc80 100644
--- 
a/core/src/main/java/org/apache/brooklyn/core/workflow/ShorthandProcessorEpToQst.java
+++ 
b/core/src/main/java/org/apache/brooklyn/core/workflow/ShorthandProcessorEpToQst.java
@@ -83,7 +83,8 @@ public class ShorthandProcessorEpToQst {
         return new ShorthandProcessorQstAttempt(this, input).call();
     }
 
-    /** whether the last match should preserve quotes and spaces; default 
false */
+    /** optionally skip the automatic unwrapping of a single quoted last word 
lining up with the last word of a template;
+     * by default, we unwrap in that one special case, to facilitate eg return 
"something fancy" */
     public ShorthandProcessorEpToQst withFinalMatchRaw(boolean finalMatchRaw) {
         this.finalMatchRaw = finalMatchRaw;
         return this;
@@ -131,7 +132,6 @@ public class ShorthandProcessorEpToQst {
             inputRemaining = Strings.trimStart(inputRemaining);
             if (Strings.isNonBlank(inputRemaining)) {
                 if (valueUpdater!=null) {
-                    //QuotedStringTokenizer qstInput = qst(inputRemaining);
                     
valueUpdater.accept(getRemainderPossiblyRaw(inputRemaining));
                 } else {
                     // shouldn't come here
@@ -340,19 +340,13 @@ public class ShorthandProcessorEpToQst {
             return mp.get();
         }
         private Maybe<String> getRemainderPossiblyRawEp(String inputRemaining) 
{
-            if (options.finalMatchRaw) {
-                return Maybe.of(inputRemaining);
-            }
-            Maybe<List<ParseNodeOrValue>> mp = 
ShorthandProcessorExprParser.tokenizer().parseEverything(inputRemaining);
-            return mp.map(pnl -> {
-                final boolean UNQUOTE_INDIVIDUAL_WORDS = false;  // legacy 
behaviour
-
-                if (pnl.size()==1 || UNQUOTE_INDIVIDUAL_WORDS) {
-                    return ExpressionParser.getAllUnquoted(pnl);
-                } else {
-                    return ExpressionParser.getUnescapedButNotUnquoted(pnl);
+            if (!options.finalMatchRaw) {
+                Maybe<List<ParseNodeOrValue>> mp = 
ShorthandProcessorExprParser.tokenizer().parseEverything(inputRemaining);
+                if (mp.isPresent() && mp.get().size()==1 && 
ExpressionParser.isQuotedExpressionNode(mp.get().get(0))) {
+                    return Maybe.of(ExpressionParser.getUnquoted( 
mp.get().get(0) ));
                 }
-            });
+            }
+            return Maybe.of(inputRemaining);
         }
 
         private String 
getNextInputTokenUpToPossibleExpectedLiteralQst(QuotedStringTokenizer qstInput, 
String nextLiteral) {
diff --git 
a/core/src/test/java/org/apache/brooklyn/core/workflow/WorkflowBasicTest.java 
b/core/src/test/java/org/apache/brooklyn/core/workflow/WorkflowBasicTest.java
index 364a7090e9..1ab20b9887 100644
--- 
a/core/src/test/java/org/apache/brooklyn/core/workflow/WorkflowBasicTest.java
+++ 
b/core/src/test/java/org/apache/brooklyn/core/workflow/WorkflowBasicTest.java
@@ -18,6 +18,12 @@
  */
 package org.apache.brooklyn.core.workflow;
 
+import java.util.List;
+import java.util.Map;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
 import com.fasterxml.jackson.core.JsonProcessingException;
 import com.google.common.reflect.TypeToken;
 import org.apache.brooklyn.api.entity.Entity;
@@ -45,13 +51,38 @@ import 
org.apache.brooklyn.core.test.BrooklynMgmtUnitTestSupport;
 import org.apache.brooklyn.core.typereg.BasicTypeImplementationPlan;
 import org.apache.brooklyn.core.typereg.JavaClassNameTypePlanTransformer;
 import org.apache.brooklyn.core.typereg.RegisteredTypes;
-import org.apache.brooklyn.core.workflow.steps.*;
-import org.apache.brooklyn.core.workflow.steps.appmodel.*;
+import org.apache.brooklyn.core.workflow.steps.CustomWorkflowStep;
+import org.apache.brooklyn.core.workflow.steps.appmodel.AddEntityWorkflowStep;
+import org.apache.brooklyn.core.workflow.steps.appmodel.AddPolicyWorkflowStep;
+import 
org.apache.brooklyn.core.workflow.steps.appmodel.ApplyInitializerWorkflowStep;
+import 
org.apache.brooklyn.core.workflow.steps.appmodel.ClearConfigWorkflowStep;
+import 
org.apache.brooklyn.core.workflow.steps.appmodel.ClearSensorWorkflowStep;
+import 
org.apache.brooklyn.core.workflow.steps.appmodel.DeleteEntityWorkflowStep;
+import 
org.apache.brooklyn.core.workflow.steps.appmodel.DeletePolicyWorkflowStep;
+import 
org.apache.brooklyn.core.workflow.steps.appmodel.DeployApplicationWorkflowStep;
+import 
org.apache.brooklyn.core.workflow.steps.appmodel.InvokeEffectorWorkflowStep;
+import 
org.apache.brooklyn.core.workflow.steps.appmodel.ReparentEntityWorkflowStep;
+import org.apache.brooklyn.core.workflow.steps.appmodel.SetConfigWorkflowStep;
+import 
org.apache.brooklyn.core.workflow.steps.appmodel.SetEntityNameWorkflowStep;
+import org.apache.brooklyn.core.workflow.steps.appmodel.SetSensorWorkflowStep;
+import 
org.apache.brooklyn.core.workflow.steps.appmodel.UpdateChildrenWorkflowStep;
 import org.apache.brooklyn.core.workflow.steps.external.HttpWorkflowStep;
 import org.apache.brooklyn.core.workflow.steps.external.ShellWorkflowStep;
 import org.apache.brooklyn.core.workflow.steps.external.SshWorkflowStep;
-import org.apache.brooklyn.core.workflow.steps.flow.*;
-import org.apache.brooklyn.core.workflow.steps.variables.*;
+import org.apache.brooklyn.core.workflow.steps.flow.FailWorkflowStep;
+import org.apache.brooklyn.core.workflow.steps.flow.ForeachWorkflowStep;
+import org.apache.brooklyn.core.workflow.steps.flow.GotoWorkflowStep;
+import org.apache.brooklyn.core.workflow.steps.flow.LogWorkflowStep;
+import org.apache.brooklyn.core.workflow.steps.flow.NoOpWorkflowStep;
+import org.apache.brooklyn.core.workflow.steps.flow.RetryWorkflowStep;
+import org.apache.brooklyn.core.workflow.steps.flow.ReturnWorkflowStep;
+import org.apache.brooklyn.core.workflow.steps.flow.SleepWorkflowStep;
+import org.apache.brooklyn.core.workflow.steps.flow.SwitchWorkflowStep;
+import 
org.apache.brooklyn.core.workflow.steps.variables.ClearVariableWorkflowStep;
+import org.apache.brooklyn.core.workflow.steps.variables.LoadWorkflowStep;
+import 
org.apache.brooklyn.core.workflow.steps.variables.SetVariableWorkflowStep;
+import 
org.apache.brooklyn.core.workflow.steps.variables.TransformVariableWorkflowStep;
+import org.apache.brooklyn.core.workflow.steps.variables.WaitWorkflowStep;
 import 
org.apache.brooklyn.core.workflow.store.WorkflowStatePersistenceViaSensors;
 import org.apache.brooklyn.entity.stock.BasicApplication;
 import org.apache.brooklyn.test.Asserts;
@@ -63,14 +94,9 @@ import 
org.apache.brooklyn.util.core.json.BrooklynObjectsJsonMapper;
 import org.apache.brooklyn.util.exceptions.Exceptions;
 import org.apache.brooklyn.util.text.Strings;
 import org.apache.brooklyn.util.time.Duration;
+import org.apache.commons.lang3.tuple.Pair;
 import org.testng.annotations.Test;
 
-import java.util.List;
-import java.util.Map;
-import java.util.function.Consumer;
-import java.util.function.Function;
-import java.util.stream.Collectors;
-
 
 public class WorkflowBasicTest extends BrooklynMgmtUnitTestSupport {
 
@@ -172,6 +198,23 @@ public class WorkflowBasicTest extends 
BrooklynMgmtUnitTestSupport {
         }
     }
 
+    static Pair<BasicApplication,Object> runStepsInNewApp(ManagementContext 
mgmt, List<?> steps) {
+        WorkflowBasicTest.addWorkflowStepTypes(mgmt);
+        BasicApplication app = 
mgmt.getEntityManager().createEntity(EntitySpec.create(BasicApplication.class));
+        Task<?> invocation = runSteps(app, steps);
+        return Pair.of(app, invocation.getUnchecked());
+    }
+
+    static Task<?> runSteps(BasicApplication app, List<?> steps) {
+        WorkflowEffector eff = new WorkflowEffector(ConfigBag.newInstance()
+                .configure(WorkflowEffector.EFFECTOR_NAME, "myWorkflow")
+                .configure(WorkflowEffector.STEPS, (List) steps)
+        );
+        eff.apply((EntityLocal) app);
+        Task<?> invocation = 
app.invoke(app.getEntityType().getEffectorByName("myWorkflow").get(), null);
+        return invocation;
+    }
+
     @Test
     public void testStepResolution() throws JsonProcessingException {
         loadTypes();
@@ -376,16 +419,9 @@ public class WorkflowBasicTest extends 
BrooklynMgmtUnitTestSupport {
         loadTypes();
         BasicApplication app = 
mgmt.getEntityManager().createEntity(EntitySpec.create(BasicApplication.class));
 
-        WorkflowEffector eff = new WorkflowEffector(ConfigBag.newInstance()
-                .configure(WorkflowEffector.EFFECTOR_NAME, "myWorkflow")
-                .configure(WorkflowEffector.STEPS, MutableList.of(
-                        WorkflowTestStep.of( setup::accept ),
-                        "set-sensor " + (type!=null ? type+" " : "") + "x = " 
+ expression
-                ))
-        );
-        eff.apply((EntityLocal)app);
-
-        Task<?> invocation = 
app.invoke(app.getEntityType().getEffectorByName("myWorkflow").get(), null);
+        Task<?> invocation = runSteps(app, MutableList.of(
+                WorkflowTestStep.of(setup::accept),
+                "set-sensor " + (type != null ? type + " " : "") + "x = " + 
expression));
         invocation.getUnchecked();
         Dumper.dumpInfo(invocation);
 
diff --git 
a/core/src/test/java/org/apache/brooklyn/core/workflow/WorkflowMapAndListTest.java
 
b/core/src/test/java/org/apache/brooklyn/core/workflow/WorkflowMapAndListTest.java
index c42bd46223..738545dfcc 100644
--- 
a/core/src/test/java/org/apache/brooklyn/core/workflow/WorkflowMapAndListTest.java
+++ 
b/core/src/test/java/org/apache/brooklyn/core/workflow/WorkflowMapAndListTest.java
@@ -25,6 +25,7 @@ import java.util.Map;
 import com.google.common.collect.ImmutableMap;
 import org.apache.brooklyn.api.entity.EntityLocal;
 import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.api.mgmt.ManagementContext;
 import org.apache.brooklyn.core.config.ConfigKeys;
 import org.apache.brooklyn.core.entity.Dumper;
 import org.apache.brooklyn.core.entity.EntityAsserts;
@@ -36,6 +37,7 @@ import org.apache.brooklyn.test.Asserts;
 import org.apache.brooklyn.util.collections.MutableList;
 import org.apache.brooklyn.util.collections.MutableMap;
 import org.apache.brooklyn.util.core.config.ConfigBag;
+import org.apache.commons.lang3.tuple.Pair;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.testng.annotations.Test;
@@ -47,16 +49,9 @@ public class WorkflowMapAndListTest extends 
BrooklynMgmtUnitTestSupport {
     private BasicApplication app;
 
     Object runSteps(List<?> steps) {
-        WorkflowBasicTest.addWorkflowStepTypes(mgmt);
-
-        BasicApplication app = 
mgmt().getEntityManager().createEntity(EntitySpec.create(BasicApplication.class));
-        this.app = app;
-        WorkflowEffector eff = new WorkflowEffector(ConfigBag.newInstance()
-                .configure(WorkflowEffector.EFFECTOR_NAME, "myWorkflow")
-                .configure(WorkflowEffector.STEPS, (List) steps)
-        );
-        eff.apply((EntityLocal)app);
-        return app.invoke(app.getEntityType().getEffectorByName 
("myWorkflow").get(), null).getUnchecked();
+        Pair<BasicApplication, Object> result = 
WorkflowBasicTest.runStepsInNewApp(mgmt(), steps);
+        this.app = result.getLeft();
+        return result.getRight();
     }
 
     @Test
diff --git 
a/core/src/test/java/org/apache/brooklyn/core/workflow/WorkflowOperandsTest.java
 
b/core/src/test/java/org/apache/brooklyn/core/workflow/WorkflowOperandsTest.java
index 4f61339c9e..435348928b 100644
--- 
a/core/src/test/java/org/apache/brooklyn/core/workflow/WorkflowOperandsTest.java
+++ 
b/core/src/test/java/org/apache/brooklyn/core/workflow/WorkflowOperandsTest.java
@@ -25,6 +25,7 @@ import org.apache.brooklyn.entity.stock.BasicApplication;
 import org.apache.brooklyn.test.Asserts;
 import org.apache.brooklyn.util.collections.MutableList;
 import org.apache.brooklyn.util.core.config.ConfigBag;
+import org.apache.commons.lang3.tuple.Pair;
 import org.testng.annotations.Test;
 
 import java.util.List;
@@ -34,16 +35,9 @@ public class WorkflowOperandsTest extends 
BrooklynMgmtUnitTestSupport {
     private BasicApplication app;
 
     Object runSteps(List<?> steps) {
-        WorkflowBasicTest.addWorkflowStepTypes(mgmt);
-
-        BasicApplication app = 
mgmt().getEntityManager().createEntity(EntitySpec.create(BasicApplication.class));
-        this.app = app;
-        WorkflowEffector eff = new WorkflowEffector(ConfigBag.newInstance()
-                .configure(WorkflowEffector.EFFECTOR_NAME, "myWorkflow")
-                .configure(WorkflowEffector.STEPS, (List) steps)
-        );
-        eff.apply((EntityLocal)app);
-        return 
app.invoke(app.getEntityType().getEffectorByName("myWorkflow").get(), 
null).getUnchecked();
+        Pair<BasicApplication, Object> result = 
WorkflowBasicTest.runStepsInNewApp(mgmt(), steps);
+        this.app = result.getLeft();
+        return result.getRight();
     }
 
     public Object evaluate(String expression, String type) {
diff --git 
a/core/src/test/java/org/apache/brooklyn/core/workflow/WorkflowParsingEdgeCasesTest.java
 
b/core/src/test/java/org/apache/brooklyn/core/workflow/WorkflowParsingEdgeCasesTest.java
new file mode 100644
index 0000000000..1b2a646eda
--- /dev/null
+++ 
b/core/src/test/java/org/apache/brooklyn/core/workflow/WorkflowParsingEdgeCasesTest.java
@@ -0,0 +1,134 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.core.workflow;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.google.common.reflect.TypeToken;
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.entity.EntityLocal;
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.api.mgmt.ManagementContext;
+import org.apache.brooklyn.api.mgmt.Task;
+import org.apache.brooklyn.api.mgmt.classloading.BrooklynClassLoadingContext;
+import org.apache.brooklyn.api.objs.BrooklynObject;
+import org.apache.brooklyn.api.policy.Policy;
+import org.apache.brooklyn.api.sensor.AttributeSensor;
+import org.apache.brooklyn.api.sensor.Sensor;
+import org.apache.brooklyn.api.typereg.RegisteredType;
+import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.entity.Dumper;
+import org.apache.brooklyn.core.entity.Entities;
+import org.apache.brooklyn.core.entity.EntityAsserts;
+import org.apache.brooklyn.core.entity.EntityInternal;
+import org.apache.brooklyn.core.resolve.jackson.BeanWithTypePlanTransformer;
+import org.apache.brooklyn.core.resolve.jackson.BeanWithTypeUtils;
+import org.apache.brooklyn.core.sensor.Sensors;
+import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
+import org.apache.brooklyn.core.test.BrooklynMgmtUnitTestSupport;
+import org.apache.brooklyn.core.typereg.BasicTypeImplementationPlan;
+import org.apache.brooklyn.core.typereg.JavaClassNameTypePlanTransformer;
+import org.apache.brooklyn.core.typereg.RegisteredTypes;
+import org.apache.brooklyn.core.workflow.steps.CustomWorkflowStep;
+import org.apache.brooklyn.core.workflow.steps.appmodel.AddEntityWorkflowStep;
+import org.apache.brooklyn.core.workflow.steps.appmodel.AddPolicyWorkflowStep;
+import 
org.apache.brooklyn.core.workflow.steps.appmodel.ApplyInitializerWorkflowStep;
+import 
org.apache.brooklyn.core.workflow.steps.appmodel.ClearConfigWorkflowStep;
+import 
org.apache.brooklyn.core.workflow.steps.appmodel.ClearSensorWorkflowStep;
+import 
org.apache.brooklyn.core.workflow.steps.appmodel.DeleteEntityWorkflowStep;
+import 
org.apache.brooklyn.core.workflow.steps.appmodel.DeletePolicyWorkflowStep;
+import 
org.apache.brooklyn.core.workflow.steps.appmodel.DeployApplicationWorkflowStep;
+import 
org.apache.brooklyn.core.workflow.steps.appmodel.InvokeEffectorWorkflowStep;
+import 
org.apache.brooklyn.core.workflow.steps.appmodel.ReparentEntityWorkflowStep;
+import org.apache.brooklyn.core.workflow.steps.appmodel.SetConfigWorkflowStep;
+import 
org.apache.brooklyn.core.workflow.steps.appmodel.SetEntityNameWorkflowStep;
+import org.apache.brooklyn.core.workflow.steps.appmodel.SetSensorWorkflowStep;
+import 
org.apache.brooklyn.core.workflow.steps.appmodel.UpdateChildrenWorkflowStep;
+import org.apache.brooklyn.core.workflow.steps.external.HttpWorkflowStep;
+import org.apache.brooklyn.core.workflow.steps.external.ShellWorkflowStep;
+import org.apache.brooklyn.core.workflow.steps.external.SshWorkflowStep;
+import org.apache.brooklyn.core.workflow.steps.flow.FailWorkflowStep;
+import org.apache.brooklyn.core.workflow.steps.flow.ForeachWorkflowStep;
+import org.apache.brooklyn.core.workflow.steps.flow.GotoWorkflowStep;
+import org.apache.brooklyn.core.workflow.steps.flow.LogWorkflowStep;
+import org.apache.brooklyn.core.workflow.steps.flow.NoOpWorkflowStep;
+import org.apache.brooklyn.core.workflow.steps.flow.RetryWorkflowStep;
+import org.apache.brooklyn.core.workflow.steps.flow.ReturnWorkflowStep;
+import org.apache.brooklyn.core.workflow.steps.flow.SleepWorkflowStep;
+import org.apache.brooklyn.core.workflow.steps.flow.SwitchWorkflowStep;
+import 
org.apache.brooklyn.core.workflow.steps.variables.ClearVariableWorkflowStep;
+import org.apache.brooklyn.core.workflow.steps.variables.LoadWorkflowStep;
+import 
org.apache.brooklyn.core.workflow.steps.variables.SetVariableWorkflowStep;
+import 
org.apache.brooklyn.core.workflow.steps.variables.TransformVariableWorkflowStep;
+import org.apache.brooklyn.core.workflow.steps.variables.WaitWorkflowStep;
+import 
org.apache.brooklyn.core.workflow.store.WorkflowStatePersistenceViaSensors;
+import org.apache.brooklyn.entity.stock.BasicApplication;
+import org.apache.brooklyn.test.Asserts;
+import org.apache.brooklyn.test.ClassLogWatcher;
+import org.apache.brooklyn.util.collections.MutableList;
+import org.apache.brooklyn.util.collections.MutableMap;
+import org.apache.brooklyn.util.core.config.ConfigBag;
+import org.apache.brooklyn.util.core.json.BrooklynObjectsJsonMapper;
+import org.apache.brooklyn.util.exceptions.Exceptions;
+import org.apache.brooklyn.util.text.Strings;
+import org.apache.brooklyn.util.time.Duration;
+import org.apache.commons.lang3.tuple.Pair;
+import org.testng.annotations.Test;
+
+
+public class WorkflowParsingEdgeCasesTest extends BrooklynMgmtUnitTestSupport {
+
+    private BasicApplication app;
+
+    Object runSteps(String ...steps) {
+        Pair<BasicApplication, Object> result = 
WorkflowBasicTest.runStepsInNewApp(mgmt(), Arrays.asList(steps));
+        this.app = result.getLeft();
+        return result.getRight();
+    }
+
+    @Test
+    public void testBackslashEscaping() {
+        final String BS = "\\";
+
+        String UNQUOTED_INPUT = "double unquoted " + BS + BS;
+        String QUOTED_INPUT_UNQUOTED = "quoted " + BS + BS;
+        String QUOTED_INPUT = "\"" + QUOTED_INPUT_UNQUOTED + "\"";
+        String QUOTED_INPUT_UNQUOTED_UNESCAPED = "quoted " + BS;
+
+        // entire phrase quoted will be unquoted and unescaped
+        Asserts.assertEquals(runSteps("return " + QUOTED_INPUT), 
QUOTED_INPUT_UNQUOTED_UNESCAPED);
+        // but unquoted won't be
+        Asserts.assertEquals(runSteps("return " + UNQUOTED_INPUT), 
UNQUOTED_INPUT);
+        // and partial words won't be even if quoted
+        Asserts.assertEquals(runSteps("return " + UNQUOTED_INPUT + " and " + 
QUOTED_INPUT),
+            UNQUOTED_INPUT + " and " + QUOTED_INPUT);
+
+        // however 'let' does do unquoting on word level (according to EP 
words)
+        Asserts.assertEquals(runSteps("let x = "+UNQUOTED_INPUT+" and 
"+QUOTED_INPUT, "return ${x}"),
+                UNQUOTED_INPUT + " and " + QUOTED_INPUT_UNQUOTED_UNESCAPED);
+    }
+    
+}

Reply via email to