Skip to content

Commit

Permalink
breaking potentially - no more un-necessary clone of isolated-scope v…
Browse files Browse the repository at this point in the history
…ariables #1685
  • Loading branch information
ptrthomas committed Jul 17, 2021
1 parent 685ee72 commit eb5a6fc
Show file tree
Hide file tree
Showing 5 changed files with 15 additions and 23 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1350,16 +1350,6 @@ public void setVariables(Map<String, Object> map) {
map.forEach((k, v) -> setVariable(k, v));
}

private static Map<String, Variable> copy(Map<String, Variable> source, boolean deep) {
Map<String, Variable> map = new HashMap(source.size());
source.forEach((k, v) -> map.put(k, v.copy(deep)));
return map;
}

public Map<String, Variable> copyVariables(boolean deep) {
return copy(vars, deep);
}

public Map<String, Object> getAllVariablesAsMap() {
Map<String, Object> map = new HashMap(vars.size());
vars.forEach((k, v) -> map.put(k, v == null ? null : v.getValue()));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,13 +82,13 @@ public ScenarioRuntime(FeatureRuntime featureRuntime, Scenario scenario, Scenari
} else { // new, but clone and copy data
logAppender = caller.parentRuntime.logAppender;
Config config = background == null ? new Config(caller.parentRuntime.engine.getConfig()) : background.engine.getConfig();
Map<String, Variable> vars = caller.parentRuntime.engine.copyVariables(false);
engine = new ScenarioEngine(config, this, vars, logger);
// in this case, parent variables are set via magic variables
engine = new ScenarioEngine(config, this, new HashMap(), logger);
}
logger.setAppender(logAppender);
actions = new ScenarioActions(engine);
this.scenario = scenario;
this.background = background; // used only to check which steps remain
this.background = background; // used only to check which steps remain
magicVariables = initMagicVariables();
result = new ScenarioResult(scenario);
if (background != null) {
Expand Down Expand Up @@ -260,8 +260,11 @@ private Map<String, Object> initMagicVariables() {
Map<String, Object> map = new HashMap();
if (!caller.isNone()) {
// karate principle: parent variables are always "visible"
// so we inject the parent magic variables
// so we inject the parent variables
// but they will be over-written by what is local to this scenario
if (!caller.isSharedScope()) {
caller.parentRuntime.engine.vars.forEach((k, v) -> map.put(k, v == null ? null : v.getValue()));
}
map.putAll(caller.parentRuntime.magicVariables);
map.put("__arg", caller.arg == null ? null : caller.arg.getValue());
map.put("__loop", caller.getLoopIndex());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -161,23 +161,23 @@ void testCallKarateFeature() {
"def b = 'bar'",
"def res = call read('called1.feature')"
);
matchVar("res", "{ a: 1, b: 'bar', foo: { hello: 'world' }, configSource: 'normal', functionFromKarateBase: '#notnull' }");
matchVar("res", "{ a: 1, foo: { hello: 'world' } }");
run(
"def b = 'bar'",
"def res = call read('called1.feature') { foo: 'bar' }"
);
matchVar("res", "{ a: 1, b: 'bar', foo: { hello: 'world' }, configSource: 'normal', functionFromKarateBase: '#notnull' }");
matchVar("res", "{ a: 1, foo: { hello: 'world' } }");
run(
"def b = 'bar'",
"def res = call read('called1.feature') [{ foo: 'bar' }]"
);
matchVar("res", "[{ a: 1, b: 'bar', foo: { hello: 'world' }, configSource: 'normal', functionFromKarateBase: '#notnull' }]");
matchVar("res", "[{ a: 1, foo: { hello: 'world' } }]");
run(
"def b = 'bar'",
"def fun = function(i){ if (i == 1) return null; return { index: i } }",
"def res = call read('called1.feature') fun"
);
matchVar("res", "[{ a: 1, b: 'bar', foo: { hello: 'world' }, configSource: 'normal', functionFromKarateBase: '#notnull', fun: '#ignore', index: 0 }]");
matchVar("res", "[{ a: 1, foo: { hello: 'world' }, index: 0 }]");
}

@Test
Expand Down Expand Up @@ -236,7 +236,7 @@ void testCallFromJs() {
run(
"def res = karate.call('called1.feature')"
);
matchVar("res", "{ a: 1, foo: { hello: 'world' }, configSource: 'normal', functionFromKarateBase: '#notnull' }");
matchVar("res", "{ a: 1, foo: { hello: 'world' } }");
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@ Feature: called file should not clobber vars in caller

Scenario:
* match foo == { key: 'value' }
* set foo.key = 'changed'
* foo.key = 'changed'
* match foo == { key: 'changed' }
5 changes: 2 additions & 3 deletions karate-core/src/test/java/com/intuit/karate/core/copy.feature
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,9 @@ Scenario: shared scope: called feature will over-write (and contribute) variable

Scenario: called feature updates a nested element of 'foo' using the 'set' keyword
* def foo = { key: 'value' }
# improved in karate 1.0 json cannot be mutated in called features
# json can be mutated in called features
* def result = call read('copy-called.feature')
# so callers cannot mutate this context !
* match foo == { key: 'value' }
* match foo == { key: 'changed' }

Scenario: you can manually 'clone' a payload if needed
* def original = { key: 'value' }
Expand Down

0 comments on commit eb5a6fc

Please sign in to comment.