001/** 002 * Logback: the reliable, generic, fast and flexible logging framework. 003 * Copyright (C) 1999-2015, QOS.ch. All rights reserved. 004 * 005 * This program and the accompanying materials are dual-licensed under 006 * either the terms of the Eclipse Public License v1.0 as published by 007 * the Eclipse Foundation 008 * 009 * or (per the licensee's choosing) 010 * 011 * under the terms of the GNU Lesser General Public License version 2.1 012 * as published by the Free Software Foundation. 013 */ 014package ch.qos.logback.core.util; 015 016import static org.junit.Assert.assertEquals; 017import static org.junit.Assert.fail; 018 019import java.util.HashMap; 020import java.util.Map; 021 022import org.junit.Before; 023import org.junit.Rule; 024import org.junit.Test; 025import org.junit.rules.ExpectedException; 026 027import ch.qos.logback.core.Context; 028import ch.qos.logback.core.ContextBase; 029import ch.qos.logback.core.joran.spi.JoranException; 030 031public class OptionHelperTest { 032 033 @Rule 034 public ExpectedException expectedException = ExpectedException.none(); 035 036 String text = "Testing ${v1} variable substitution ${v2}"; 037 String expected = "Testing if variable substitution works"; 038 Context context = new ContextBase(); 039 Map<String, String> secondaryMap; 040 041 @Before 042 public void setUp() throws Exception { 043 secondaryMap = new HashMap<String, String>(); 044 } 045 046 @Test 047 public void testLiteral() { 048 String noSubst = "hello world"; 049 String result = OptionHelper.substVars(noSubst, context); 050 assertEquals(noSubst, result); 051 } 052 053 @Test 054 public void testUndefinedValues() { 055 String withUndefinedValues = "${axyz}"; 056 057 String result = OptionHelper.substVars(withUndefinedValues, context); 058 assertEquals("axyz" + OptionHelper._IS_UNDEFINED, result); 059 } 060 061 @Test 062 public void testSubstVarsVariableNotClosed() { 063 String noSubst = "testing if ${v1 works"; 064 065 try { 066 @SuppressWarnings("unused") 067 String result = OptionHelper.substVars(noSubst, context); 068 fail(); 069 } catch (IllegalArgumentException e) { 070 // ok 071 } 072 } 073 074 @Test 075 public void testSubstVarsContextOnly() { 076 context.putProperty("v1", "if"); 077 context.putProperty("v2", "works"); 078 079 String result = OptionHelper.substVars(text, context); 080 assertEquals(expected, result); 081 } 082 083 @Test 084 public void testSubstVarsSystemProperties() { 085 System.setProperty("v1", "if"); 086 System.setProperty("v2", "works"); 087 088 String result = OptionHelper.substVars(text, context); 089 assertEquals(expected, result); 090 091 System.clearProperty("v1"); 092 System.clearProperty("v2"); 093 } 094 095 @Test 096 public void testSubstVarsWithDefault() { 097 context.putProperty("v1", "if"); 098 String textWithDefault = "Testing ${v1} variable substitution ${v2:-toto}"; 099 String resultWithDefault = "Testing if variable substitution toto"; 100 101 String result = OptionHelper.substVars(textWithDefault, context); 102 assertEquals(resultWithDefault, result); 103 } 104 105 @Test 106 public void testSubstVarsRecursive() { 107 context.putProperty("v1", "if"); 108 context.putProperty("v2", "${v3}"); 109 context.putProperty("v3", "works"); 110 111 String result = OptionHelper.substVars(text, context); 112 assertEquals(expected, result); 113 } 114 115 @Test 116 public void testSubstVarsTwoLevelsDeep() { 117 context.putProperty("v1", "if"); 118 context.putProperty("v2", "${v3}"); 119 context.putProperty("v3", "${v4}"); 120 context.putProperty("v4", "works"); 121 122 String result = OptionHelper.substVars(text, context); 123 assertEquals(expected, result); 124 } 125 126 @Test 127 public void testSubstVarsTwoLevelsWithDefault() { 128 // Example input taken from LOGBCK-943 bug report 129 context.putProperty("APP_NAME", "LOGBACK"); 130 context.putProperty("ARCHIVE_SUFFIX", "archive.log"); 131 context.putProperty("LOG_HOME", "${logfilepath.default:-logs}"); 132 context.putProperty("ARCHIVE_PATH", "${LOG_HOME}/archive/${APP_NAME}"); 133 134 String result = OptionHelper.substVars("${ARCHIVE_PATH}_trace_${ARCHIVE_SUFFIX}", context); 135 assertEquals("logs/archive/LOGBACK_trace_archive.log", result); 136 } 137 138 @Test(timeout = 1000) 139 public void stubstVarsShouldNotGoIntoInfiniteLoop() { 140 context.putProperty("v1", "if"); 141 context.putProperty("v2", "${v3}"); 142 context.putProperty("v3", "${v4}"); 143 context.putProperty("v4", "${v2}c"); 144 145 expectedException.expect(Exception.class); 146 OptionHelper.substVars(text, context); 147 } 148 149 @Test 150 public void nonCircularGraphShouldWork() { 151 context.putProperty("A", "${B} and ${C}"); 152 context.putProperty("B", "${B1}"); 153 context.putProperty("B1", "B1-value"); 154 context.putProperty("C", "${C1} and ${B}"); 155 context.putProperty("C1", "C1-value"); 156 157 String result = OptionHelper.substVars("${A}", context); 158 assertEquals("B1-value and C1-value and B1-value", result); 159 } 160 161 @Test(timeout = 1000) 162 public void detectCircularReferences0() { 163 context.putProperty("A", "${A}"); 164 165 expectedException.expect(IllegalArgumentException.class); 166 expectedException.expectMessage("Circular variable reference detected while parsing input [${A} --> ${A}]"); 167 OptionHelper.substVars("${A}", context); 168 } 169 170 @Test(timeout = 1000) 171 public void detectCircularReferences1() { 172 context.putProperty("A", "${A}a"); 173 174 expectedException.expect(IllegalArgumentException.class); 175 expectedException.expectMessage("Circular variable reference detected while parsing input [${A} --> ${A}]"); 176 OptionHelper.substVars("${A}", context); 177 } 178 179 @Test(timeout = 1000) 180 public void detectCircularReferences2() { 181 context.putProperty("A", "${B}"); 182 context.putProperty("B", "${C}"); 183 context.putProperty("C", "${A}"); 184 185 expectedException.expect(IllegalArgumentException.class); 186 expectedException.expectMessage("Circular variable reference detected while parsing input [${A} --> ${B} --> ${C} --> ${A}]"); 187 OptionHelper.substVars("${A}", context); 188 } 189 190 @Test 191 public void detectCircularReferencesInDefault() { 192 context.putProperty("A", "${B:-${A}}"); 193 expectedException.expect(IllegalArgumentException.class); 194 expectedException.expectMessage("Circular variable reference detected while parsing input [${A} --> ${B} --> ${A}]"); 195 OptionHelper.substVars("${A}", context); 196 } 197 198 @Test(timeout = 1000) 199 public void detectCircularReferences3() { 200 context.putProperty("A", "${B}"); 201 context.putProperty("B", "${C}"); 202 context.putProperty("C", "${A}"); 203 204 expectedException.expect(IllegalArgumentException.class); 205 expectedException.expectMessage("Circular variable reference detected while parsing input [${B} --> ${C} --> ${A} --> ${B}]"); 206 OptionHelper.substVars("${B} ", context); 207 } 208 209 @Test(timeout = 1000) 210 public void detectCircularReferences4() { 211 context.putProperty("A", "${B}"); 212 context.putProperty("B", "${C}"); 213 context.putProperty("C", "${A}"); 214 215 expectedException.expect(IllegalArgumentException.class); 216 expectedException.expectMessage("Circular variable reference detected while parsing input [${C} --> ${A} --> ${B} --> ${C}]"); 217 OptionHelper.substVars("${C} and ${A}", context); 218 } 219 220 @Test 221 public void detectCircularReferences5() { 222 context.putProperty("A", "${B} and ${C}"); 223 context.putProperty("B", "${B1}"); 224 context.putProperty("B1", "B1-value"); 225 context.putProperty("C", "${C1}"); 226 context.putProperty("C1", "here's the loop: ${A}"); 227 228 expectedException.expect(IllegalArgumentException.class); 229 expectedException.expectMessage("Circular variable reference detected while parsing input [${A} --> ${C} --> ${C1} --> ${A}]"); 230 String result = OptionHelper.substVars("${A}", context); 231 System.err.println(result); 232 } 233 234 @Test 235 public void defaultValueReferencingAVariable() { 236 context.putProperty("v1", "k1"); 237 String result = OptionHelper.substVars("${undef:-${v1}}", context); 238 assertEquals("k1", result); 239 } 240 241 @Test 242 public void jackrabbit_standalone() { 243 String r = OptionHelper.substVars("${jackrabbit.log:-${repo:-jackrabbit}/log/jackrabbit.log}", context); 244 assertEquals("jackrabbit/log/jackrabbit.log", r); 245 } 246 247 @Test 248 public void doesNotThrowNullPointerExceptionForEmptyVariable() throws JoranException { 249 context.putProperty("var", ""); 250 OptionHelper.substVars("${var}", context); 251 } 252 253 @Test 254 public void trailingColon_LOGBACK_1140() { 255 String prefix = "c:"; 256 String suffix = "/tmp"; 257 context.putProperty("var", prefix); 258 String r = OptionHelper.substVars("${var}" + suffix, context); 259 assertEquals(prefix + suffix, r); 260 } 261 262 @Test 263 public void curlyBraces_LOGBACK_1101() { 264 { 265 String input = "foo{bar}"; 266 String r = OptionHelper.substVars(input, context); 267 assertEquals(input, r); 268 } 269 { 270 String input = "{foo{\"bar\"}}"; 271 String r = OptionHelper.substVars(input, context); 272 assertEquals(input, r); 273 } 274 { 275 String input = "a:{y}"; 276 String r = OptionHelper.substVars(input, context); 277 assertEquals(input, r); 278 } 279 { 280 String input = "{world:{yay}}"; 281 String r = OptionHelper.substVars(input, context); 282 assertEquals(input, r); 283 } 284 { 285 String input = "{hello:{world:yay}}"; 286 String r = OptionHelper.substVars(input, context); 287 assertEquals(input, r); 288 } 289 { 290 String input = "{\"hello\":{\"world\":\"yay\"}}"; 291 String r = OptionHelper.substVars(input, context); 292 assertEquals(input, r); 293 } 294 } 295}