View Javadoc
1   /*
2    *    Copyright 2009-2023 the original author or authors.
3    *
4    *    Licensed under the Apache License, Version 2.0 (the "License");
5    *    you may not use this file except in compliance with the License.
6    *    You may obtain a copy of the License at
7    *
8    *       https://www.apache.org/licenses/LICENSE-2.0
9    *
10   *    Unless required by applicable law or agreed to in writing, software
11   *    distributed under the License is distributed on an "AS IS" BASIS,
12   *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   *    See the License for the specific language governing permissions and
14   *    limitations under the License.
15   */
16  package org.apache.ibatis.parsing;
17  
18  import static org.junit.jupiter.api.Assertions.assertEquals;
19  import static org.junit.jupiter.params.provider.Arguments.arguments;
20  
21  import java.time.Duration;
22  import java.util.HashMap;
23  import java.util.Map;
24  import java.util.stream.Stream;
25  
26  import org.junit.jupiter.api.Assertions;
27  import org.junit.jupiter.api.Disabled;
28  import org.junit.jupiter.api.Test;
29  import org.junit.jupiter.params.ParameterizedTest;
30  import org.junit.jupiter.params.provider.Arguments;
31  import org.junit.jupiter.params.provider.MethodSource;
32  
33  class GenericTokenParserTest {
34  
35    public static class VariableTokenHandler implements TokenHandler {
36      private Map<String, String> variables = new HashMap<>();
37  
38      VariableTokenHandler(Map<String, String> variables) {
39        this.variables = variables;
40      }
41  
42      @Override
43      public String handleToken(String content) {
44        return variables.get(content);
45      }
46    }
47  
48    @ParameterizedTest
49    @MethodSource("shouldDemonstrateGenericTokenReplacementProvider")
50    void shouldDemonstrateGenericTokenReplacement(String expected, String text) {
51      GenericTokenParser parser = new GenericTokenParser("${", "}",
52          new VariableTokenHandler(new HashMap<String, String>() {
53            private static final long serialVersionUID = 1L;
54  
55            {
56              put("first_name", "James");
57              put("initial", "T");
58              put("last_name", "Kirk");
59              put("var{with}brace", "Hiya");
60              put("", "");
61            }
62          }));
63      assertEquals(expected, parser.parse(text));
64    }
65  
66    static Stream<Arguments> shouldDemonstrateGenericTokenReplacementProvider() {
67      return Stream.of(arguments("James T Kirk reporting.", "${first_name} ${initial} ${last_name} reporting."),
68          arguments("Hello captain James T Kirk", "Hello captain ${first_name} ${initial} ${last_name}"),
69          arguments("James T Kirk", "${first_name} ${initial} ${last_name}"),
70          arguments("JamesTKirk", "${first_name}${initial}${last_name}"),
71          arguments("{}JamesTKirk", "{}${first_name}${initial}${last_name}"),
72          arguments("}JamesTKirk", "}${first_name}${initial}${last_name}"),
73  
74          arguments("}James{{T}}Kirk", "}${first_name}{{${initial}}}${last_name}"),
75          arguments("}James}T{Kirk", "}${first_name}}${initial}{${last_name}"),
76          arguments("}James}T{Kirk", "}${first_name}}${initial}{${last_name}"),
77          arguments("}James}T{Kirk{{}}", "}${first_name}}${initial}{${last_name}{{}}"),
78          arguments("}James}T{Kirk{{}}", "}${first_name}}${initial}{${last_name}{{}}${}"),
79  
80          arguments("{$$something}JamesTKirk", "{$$something}${first_name}${initial}${last_name}"), arguments("${", "${"),
81          arguments("${\\}", "${\\}"), arguments("Hiya", "${var{with\\}brace}"), arguments("", "${}"),
82          arguments("}", "}"), arguments("Hello ${ this is a test.", "Hello ${ this is a test."),
83          arguments("Hello } this is a test.", "Hello } this is a test."),
84          arguments("Hello } ${ this is a test.", "Hello } ${ this is a test."));
85    }
86  
87    @ParameterizedTest
88    @MethodSource("shallNotInterpolateSkippedVariablesProvider")
89    void shallNotInterpolateSkippedVariables(String expected, String text) {
90      GenericTokenParser parser = new GenericTokenParser("${", "}", new VariableTokenHandler(new HashMap<>()));
91      assertEquals(expected, parser.parse(text));
92    }
93  
94    static Stream<Arguments> shallNotInterpolateSkippedVariablesProvider() {
95      return Stream.of(arguments("${skipped} variable", "\\${skipped} variable"),
96          arguments("This is a ${skipped} variable", "This is a \\${skipped} variable"),
97          arguments("null ${skipped} variable", "${skipped} \\${skipped} variable"),
98          arguments("The null is ${skipped} variable", "The ${skipped} is \\${skipped} variable"));
99    }
100 
101   @Disabled("Because it randomly fails on Github CI. It could be useful during development.")
102   @Test
103   void shouldParseFastOnJdk7u6() {
104     Assertions.assertTimeout(Duration.ofMillis(1000), () -> {
105       // issue #760
106       GenericTokenParser parser = new GenericTokenParser("${", "}",
107           new VariableTokenHandler(new HashMap<String, String>() {
108             private static final long serialVersionUID = 1L;
109 
110             {
111               put("first_name", "James");
112               put("initial", "T");
113               put("last_name", "Kirk");
114               put("", "");
115             }
116           }));
117 
118       StringBuilder input = new StringBuilder();
119       for (int i = 0; i < 10000; i++) {
120         input.append("${first_name} ${initial} ${last_name} reporting. ");
121       }
122       StringBuilder expected = new StringBuilder();
123       for (int i = 0; i < 10000; i++) {
124         expected.append("James T Kirk reporting. ");
125       }
126       assertEquals(expected.toString(), parser.parse(input.toString()));
127     });
128   }
129 
130 }