don't need to replace() in ConfigConcatenation

Because the cycle is detected by the nested ConfigReference.
This commit is contained in:
Havoc Pennington 2012-04-05 14:49:20 -04:00
parent 8fdc372330
commit 401f2dc176
2 changed files with 52 additions and 25 deletions

View File

@ -68,33 +68,26 @@ final class ConfigConcatenation extends AbstractConfigValue implements Unmergeab
@Override
AbstractConfigValue resolveSubstitutions(ResolveContext context) throws NotPossibleToResolve {
List<AbstractConfigValue> resolved = new ArrayList<AbstractConfigValue>(pieces.size());
// if you have "foo = ${?foo}bar" then we will
// self-referentially look up foo and we need to
// get undefined, rather than "bar"
context.source().replace(this, ResolveReplacer.cycleResolveReplacer);
try {
for (AbstractConfigValue p : pieces) {
// to concat into a string we have to do a full resolve,
// so unrestrict the context
AbstractConfigValue r = context.unrestricted().resolve(p);
if (r == null) {
// it was optional... omit
} else {
switch (r.valueType()) {
case LIST:
case OBJECT:
// cannot substitute lists and objects into strings
// we know p was a ConfigReference since it wasn't
// a ConfigString
String pathString = ((ConfigReference) p).expression().toString();
throw new ConfigException.WrongType(r.origin(), pathString, "not a list or object", r.valueType().name());
default:
resolved.add(r);
}
for (AbstractConfigValue p : pieces) {
// to concat into a string we have to do a full resolve,
// so unrestrict the context
AbstractConfigValue r = context.unrestricted().resolve(p);
if (r == null) {
// it was optional... omit
} else {
switch (r.valueType()) {
case LIST:
case OBJECT:
// cannot substitute lists and objects into strings
// we know p was a ConfigReference since it wasn't
// a ConfigString
String pathString = ((ConfigReference) p).expression().toString();
throw new ConfigException.WrongType(r.origin(), pathString,
"not a list or object", r.valueType().name());
default:
resolved.add(r);
}
}
} finally {
context.source().unreplace(this);
}
// now need to concat everything

View File

@ -1053,6 +1053,19 @@ class ConfigSubstitutionTest extends TestUtils {
assertEquals(1, resolved.getInt("a.b.c"))
}
@Test
def substSelfReferenceAlongPathMoreComplex() {
// this is an example from the spec
val obj = parseObject("""
foo : { a : { c : 1 } }
foo : ${foo.a}
foo : { a : 2 }
""")
val resolved = resolve(obj)
assertEquals(1, resolved.getInt("foo.c"))
assertEquals(2, resolved.getInt("foo.a"))
}
@Test
def substSelfReferenceIndirect() {
val obj = parseObject("""a=1, b=${a}, a=${b}""")
@ -1131,6 +1144,27 @@ class ConfigSubstitutionTest extends TestUtils {
assertEquals("foo", resolved.getString("a"))
}
@Test
def substOptionalIndirectSelfReferenceInConcat() {
val obj = parseObject("""a=${?b}foo,b=${a}""")
val resolved = resolve(obj)
assertEquals("foo", resolved.getString("a"))
}
@Test
def substTwoOptionalSelfReferencesInConcat() {
val obj = parseObject("""a=${?a}foo${?a}""")
val resolved = resolve(obj)
assertEquals("foo", resolved.getString("a"))
}
@Test
def substTwoOptionalSelfReferencesInConcatWithPriorValue() {
val obj = parseObject("""a=1,a=${?a}foo${?a}""")
val resolved = resolve(obj)
assertEquals("1foo1", resolved.getString("a"))
}
@Test
def substSelfReferenceMiddleOfStack() {
val obj = parseObject("""a=1, a=${a}, a=2""")