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.builder;
17  
18  import static com.googlecode.catchexception.apis.BDDCatchException.caughtException;
19  import static com.googlecode.catchexception.apis.BDDCatchException.when;
20  import static org.assertj.core.api.Assertions.assertThat;
21  import static org.assertj.core.api.BDDAssertions.then;
22  
23  import java.io.InputStream;
24  import java.util.regex.Pattern;
25  
26  import org.apache.ibatis.builder.xml.XMLMapperBuilder;
27  import org.apache.ibatis.io.Resources;
28  import org.apache.ibatis.mapping.MappedStatement;
29  import org.apache.ibatis.mapping.ResultSetType;
30  import org.apache.ibatis.mapping.StatementType;
31  import org.apache.ibatis.session.Configuration;
32  import org.apache.ibatis.type.TypeHandler;
33  import org.junit.jupiter.api.Assertions;
34  import org.junit.jupiter.api.Test;
35  
36  class XmlMapperBuilderTest {
37  
38    @Test
39    void shouldSuccessfullyLoadXMLMapperFile() throws Exception {
40      Configuration configuration = new Configuration();
41      String resource = "org/apache/ibatis/builder/AuthorMapper.xml";
42      try (InputStream inputStream = Resources.getResourceAsStream(resource)) {
43        XMLMapperBuilder builder = new XMLMapperBuilder(inputStream, configuration, resource,
44            configuration.getSqlFragments());
45        builder.parse();
46      }
47    }
48  
49    @Test
50    void mappedStatementWithOptions() throws Exception {
51      Configuration configuration = new Configuration();
52      String resource = "org/apache/ibatis/builder/AuthorMapper.xml";
53      try (InputStream inputStream = Resources.getResourceAsStream(resource)) {
54        XMLMapperBuilder builder = new XMLMapperBuilder(inputStream, configuration, resource,
55            configuration.getSqlFragments());
56        builder.parse();
57  
58        MappedStatement mappedStatement = configuration.getMappedStatement("selectWithOptions");
59        assertThat(mappedStatement.getFetchSize()).isEqualTo(200);
60        assertThat(mappedStatement.getTimeout()).isEqualTo(10);
61        assertThat(mappedStatement.getStatementType()).isEqualTo(StatementType.PREPARED);
62        assertThat(mappedStatement.getResultSetType()).isEqualTo(ResultSetType.SCROLL_SENSITIVE);
63        assertThat(mappedStatement.isFlushCacheRequired()).isFalse();
64        assertThat(mappedStatement.isUseCache()).isFalse();
65      }
66    }
67  
68    @Test
69    void mappedStatementWithoutOptionsWhenSpecifyDefaultValue() throws Exception {
70      Configuration configuration = new Configuration();
71      configuration.setDefaultResultSetType(ResultSetType.SCROLL_INSENSITIVE);
72      String resource = "org/apache/ibatis/builder/AuthorMapper.xml";
73      InputStream inputStream = Resources.getResourceAsStream(resource);
74      XMLMapperBuilder builder = new XMLMapperBuilder(inputStream, configuration, resource,
75          configuration.getSqlFragments());
76      builder.parse();
77      inputStream.close();
78  
79      MappedStatement mappedStatement = configuration.getMappedStatement("selectAuthor");
80      assertThat(mappedStatement.getResultSetType()).isEqualTo(ResultSetType.SCROLL_INSENSITIVE);
81    }
82  
83    @Test
84    void parseExpression() {
85      BaseBuilder builder = new BaseBuilder(new Configuration()) {
86      };
87      {
88        Pattern pattern = builder.parseExpression("[0-9]", "[a-z]");
89        assertThat(pattern.matcher("0").find()).isTrue();
90        assertThat(pattern.matcher("a").find()).isFalse();
91      }
92      {
93        Pattern pattern = builder.parseExpression(null, "[a-z]");
94        assertThat(pattern.matcher("0").find()).isFalse();
95        assertThat(pattern.matcher("a").find()).isTrue();
96      }
97    }
98  
99    @Test
100   void resolveJdbcTypeWithUndefinedValue() {
101     BaseBuilder builder = new BaseBuilder(new Configuration()) {
102     };
103     when(() -> builder.resolveJdbcType("aaa"));
104     then(caughtException()).isInstanceOf(BuilderException.class)
105         .hasMessageStartingWith("Error resolving JdbcType. Cause: java.lang.IllegalArgumentException: No enum")
106         .hasMessageEndingWith("org.apache.ibatis.type.JdbcType.aaa");
107   }
108 
109   @Test
110   void resolveResultSetTypeWithUndefinedValue() {
111     BaseBuilder builder = new BaseBuilder(new Configuration()) {
112     };
113     when(() -> builder.resolveResultSetType("bbb"));
114     then(caughtException()).isInstanceOf(BuilderException.class)
115         .hasMessageStartingWith("Error resolving ResultSetType. Cause: java.lang.IllegalArgumentException: No enum")
116         .hasMessageEndingWith("org.apache.ibatis.mapping.ResultSetType.bbb");
117   }
118 
119   @Test
120   void resolveParameterModeWithUndefinedValue() {
121     BaseBuilder builder = new BaseBuilder(new Configuration()) {
122     };
123     when(() -> builder.resolveParameterMode("ccc"));
124     then(caughtException()).isInstanceOf(BuilderException.class)
125         .hasMessageStartingWith("Error resolving ParameterMode. Cause: java.lang.IllegalArgumentException: No enum")
126         .hasMessageEndingWith("org.apache.ibatis.mapping.ParameterMode.ccc");
127   }
128 
129   @Test
130   void createInstanceWithAbstractClass() {
131     BaseBuilder builder = new BaseBuilder(new Configuration()) {
132     };
133     when(() -> builder.createInstance("org.apache.ibatis.builder.BaseBuilder"));
134     then(caughtException()).isInstanceOf(BuilderException.class).hasMessage(
135         "Error creating instance. Cause: java.lang.NoSuchMethodException: org.apache.ibatis.builder.BaseBuilder.<init>()");
136   }
137 
138   @Test
139   void resolveClassWithNotFound() {
140     BaseBuilder builder = new BaseBuilder(new Configuration()) {
141     };
142     when(() -> builder.resolveClass("ddd"));
143     then(caughtException()).isInstanceOf(BuilderException.class).hasMessage(
144         "Error resolving class. Cause: org.apache.ibatis.type.TypeException: Could not resolve type alias 'ddd'.  Cause: java.lang.ClassNotFoundException: Cannot find class: ddd");
145   }
146 
147   @Test
148   void resolveTypeHandlerTypeHandlerAliasIsNull() {
149     BaseBuilder builder = new BaseBuilder(new Configuration()) {
150     };
151     TypeHandler<?> typeHandler = builder.resolveTypeHandler(String.class, (String) null);
152     assertThat(typeHandler).isNull();
153   }
154 
155   @Test
156   void resolveTypeHandlerNoAssignable() {
157     BaseBuilder builder = new BaseBuilder(new Configuration()) {
158     };
159     when(() -> builder.resolveTypeHandler(String.class, "integer"));
160     then(caughtException()).isInstanceOf(BuilderException.class).hasMessage(
161         "Type java.lang.Integer is not a valid TypeHandler because it does not implement TypeHandler interface");
162   }
163 
164   @Test
165   void setCurrentNamespaceValueIsNull() {
166     MapperBuilderAssistant builder = new MapperBuilderAssistant(new Configuration(), "resource");
167     when(() -> builder.setCurrentNamespace(null));
168     then(caughtException()).isInstanceOf(BuilderException.class)
169         .hasMessage("The mapper element requires a namespace attribute to be specified.");
170   }
171 
172   @Test
173   void useCacheRefNamespaceIsNull() {
174     MapperBuilderAssistant builder = new MapperBuilderAssistant(new Configuration(), "resource");
175     when(() -> builder.useCacheRef(null));
176     then(caughtException()).isInstanceOf(BuilderException.class)
177         .hasMessage("cache-ref element requires a namespace attribute.");
178   }
179 
180   @Test
181   void useCacheRefNamespaceIsUndefined() {
182     MapperBuilderAssistant builder = new MapperBuilderAssistant(new Configuration(), "resource");
183     when(() -> builder.useCacheRef("eee"));
184     then(caughtException()).hasMessage("No cache for namespace 'eee' could be found.");
185   }
186 
187   @Test
188   void shouldFailedLoadXMLMapperFile() throws Exception {
189     Configuration configuration = new Configuration();
190     String resource = "org/apache/ibatis/builder/ProblemMapper.xml";
191     try (InputStream inputStream = Resources.getResourceAsStream(resource)) {
192       XMLMapperBuilder builder = new XMLMapperBuilder(inputStream, configuration, resource,
193           configuration.getSqlFragments());
194       Exception exception = Assertions.assertThrows(BuilderException.class, builder::parse);
195       Assertions.assertTrue(exception.getMessage()
196           .contains("Error parsing Mapper XML. The XML location is 'org/apache/ibatis/builder/ProblemMapper.xml'"));
197     }
198   }
199 
200   // @Test
201   // public void shouldNotLoadTheSameNamespaceFromTwoResourcesWithDifferentNames() throws Exception {
202   // Configuration configuration = new Configuration();
203   // String resource = "org/apache/ibatis/builder/AuthorMapper.xml";
204   // InputStream inputStream = Resources.getResourceAsStream(resource);
205   // XMLMapperBuilder builder = new XMLMapperBuilder(inputStream, configuration, "name1",
206   // configuration.getSqlFragments());
207   // builder.parse();
208   // InputStream inputStream2 = Resources.getResourceAsStream(resource);
209   // XMLMapperBuilder builder2 = new XMLMapperBuilder(inputStream2, configuration, "name2",
210   // configuration.getSqlFragments());
211   // builder2.parse();
212   // }
213 
214   @Test
215   void errorResultMapLocation() throws Exception {
216     Configuration configuration = new Configuration();
217     String resource = "org/apache/ibatis/builder/ProblemResultMapper.xml";
218     try (InputStream inputStream = Resources.getResourceAsStream(resource)) {
219       XMLMapperBuilder builder = new XMLMapperBuilder(inputStream, configuration, resource,
220           configuration.getSqlFragments());
221       builder.parse();
222       String resultMapName = "java.lang.String";
223       // namespace + "." + id
224       String statementId = "org.mybatis.spring.ErrorProblemMapper" + "." + "findProblemResultMapTest";
225       // same as MapperBuilderAssistant.getStatementResultMaps Exception message
226       String message = "Could not find result map '" + resultMapName + "' referenced from '" + statementId + "'";
227       IncompleteElementException exception = Assertions.assertThrows(IncompleteElementException.class,
228           () -> configuration.getMappedStatement("findProblemTypeTest"));
229       assertThat(exception.getMessage()).isEqualTo(message);
230     }
231   }
232 }