View Javadoc
1   /*
2    *    Copyright 2016-2025 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.mybatis.dynamic.sql.where.condition;
17  
18  import static org.assertj.core.api.Assertions.assertThat;
19  import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
20  
21  import java.util.NoSuchElementException;
22  
23  import org.junit.jupiter.api.Test;
24  import org.mybatis.dynamic.sql.SqlBuilder;
25  
26  /**
27   * This set of tests verifies that the library handles null values in conditions as expected.
28   *
29   * <p>In version 2.0, we adopted JSpecify which brought several issues to light.
30   * In general, the library does not support passing null values into methods unless the method
31   * is a "whenPresent" method. However, from the beginning the library has handled null values in conditions
32   * by placing a null into the generated parameter map. We consider this a misuse of the library, but we are
33   * keeping that behavior for compatibility.
34   *
35   * <p>In a future version, we will stop supporting this misuse.
36   *
37   * <p>This set of tests should be the only tests in the library that verify this behavior. All other tests
38   * should use the library properly.
39   */
40  class NullContractTest {
41      @SuppressWarnings("DataFlowIssue") // we are deliberately passing nulls into non-null methods for testing
42      @Test
43      void testIsBetween() {
44          IsBetween<Integer> nullCond = SqlBuilder.isBetween((Integer) null).and((Integer) null);
45          assertThat(nullCond.isEmpty()).isFalse();
46  
47          IsBetween<Integer> cond = SqlBuilder.isBetween(1).and(10);
48          IsBetween<Integer> filtered = cond.filter(i -> i >= 1);
49          IsBetween<Integer> mapped = filtered.map(i -> null);
50          assertThat(mapped.isEmpty()).isFalse();
51  
52          mapped = filtered.map(v1 -> null, v2 -> null);
53          assertThat(mapped.isEmpty()).isFalse();
54          assertThat(mapped.value1()).isNull();
55          assertThat(mapped.value2()).isNull();
56      }
57  
58      @Test
59      void testIsBetweenWhenPresent() {
60          IsBetweenWhenPresent<Integer> nullCond = SqlBuilder.isBetweenWhenPresent((Integer) null).and((Integer) null);
61          assertThat(nullCond.isEmpty()).isTrue();
62  
63          IsBetweenWhenPresent<Integer> cond = SqlBuilder.isBetweenWhenPresent(1).and(10);
64          IsBetweenWhenPresent<Integer> filtered = cond.filter(i -> i == 1);
65          IsBetweenWhenPresent<Integer> mapped = filtered.map(i -> null);
66          assertThat(mapped.isEmpty()).isTrue();
67  
68          mapped = filtered.map(v1 -> null, v2 -> null);
69          assertThat(mapped.isEmpty()).isTrue();
70          assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(mapped::value1);
71          assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(mapped::value2);
72      }
73  
74      @SuppressWarnings("DataFlowIssue") // we are deliberately passing nulls into non-null methods for testing
75      @Test
76      void testIsEqualTo() {
77          IsEqualTo<Integer> nullCond = SqlBuilder.isEqualTo((Integer) null); // should be an IDE warning
78          assertThat(nullCond.isEmpty()).isFalse();
79  
80          IsEqualTo<Integer> cond = SqlBuilder.isEqualTo(1);
81          IsEqualTo<Integer> filtered = cond.filter(i -> i == 1);
82          IsEqualTo<Integer> mapped = filtered.map(i -> null);  // should be an IDE warning
83          assertThat(mapped.isEmpty()).isFalse();
84          assertThat(mapped.value()).isNull();
85      }
86  
87      @Test
88      void testIsEqualToWhenPresent() {
89          IsEqualToWhenPresent<Integer> nullCond = SqlBuilder.isEqualToWhenPresent((Integer) null);
90          assertThat(nullCond.isEmpty()).isTrue();
91  
92          IsEqualToWhenPresent<Integer> cond = SqlBuilder.isEqualToWhenPresent(1);
93          IsEqualToWhenPresent<Integer> filtered = cond.filter(i -> i == 1);
94          IsEqualToWhenPresent<Integer> mapped = filtered.map(i -> null);
95          assertThat(mapped.isEmpty()).isTrue();
96          assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(mapped::value);
97      }
98  
99      @SuppressWarnings("DataFlowIssue") // we are deliberately passing nulls into non-null methods for testing
100     @Test
101     void testIsGreaterThan() {
102         IsGreaterThan<Integer> nullCond = SqlBuilder.isGreaterThan((Integer) null); // should be an IDE warning
103         assertThat(nullCond.isEmpty()).isFalse();
104 
105         IsGreaterThan<Integer> cond = SqlBuilder.isGreaterThan(1);
106         IsGreaterThan<Integer> filtered = cond.filter(i -> i == 1);
107         IsGreaterThan<Integer> mapped = filtered.map(i -> null);  // should be an IDE warning
108         assertThat(mapped.isEmpty()).isFalse();
109         assertThat(mapped.value()).isNull();
110     }
111 
112     @Test
113     void testIsGreaterThanWhenPresent() {
114         IsGreaterThanWhenPresent<Integer> nullCond = SqlBuilder.isGreaterThanWhenPresent((Integer) null);
115         assertThat(nullCond.isEmpty()).isTrue();
116 
117         IsGreaterThanWhenPresent<Integer> cond = SqlBuilder.isGreaterThanWhenPresent(1);
118         IsGreaterThanWhenPresent<Integer> filtered = cond.filter(i -> i == 1);
119         IsGreaterThanWhenPresent<Integer> mapped = filtered.map(i -> null);
120         assertThat(mapped.isEmpty()).isTrue();
121         assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(mapped::value);
122     }
123 
124     @SuppressWarnings("DataFlowIssue") // we are deliberately passing nulls into non-null methods for testing
125     @Test
126     void testIsGreaterThanOrEqualTo() {
127         IsGreaterThanOrEqualTo<Integer> nullCond = SqlBuilder.isGreaterThanOrEqualTo((Integer) null); // should be an IDE warning
128         assertThat(nullCond.isEmpty()).isFalse();
129 
130         IsGreaterThanOrEqualTo<Integer> cond = SqlBuilder.isGreaterThanOrEqualTo(1);
131         IsGreaterThanOrEqualTo<Integer> filtered = cond.filter(i -> i == 1);
132         IsGreaterThanOrEqualTo<Integer> mapped = filtered.map(i -> null);  // should be an IDE warning
133         assertThat(mapped.isEmpty()).isFalse();
134         assertThat(mapped.value()).isNull();
135     }
136 
137     @Test
138     void testIsGreaterThanOrEqualToWhenPresent() {
139         IsGreaterThanOrEqualToWhenPresent<Integer> nullCond = SqlBuilder.isGreaterThanOrEqualToWhenPresent((Integer) null);
140         assertThat(nullCond.isEmpty()).isTrue();
141 
142         IsGreaterThanOrEqualToWhenPresent<Integer> cond = SqlBuilder.isGreaterThanOrEqualToWhenPresent(1);
143         IsGreaterThanOrEqualToWhenPresent<Integer> filtered = cond.filter(i -> i == 1);
144         IsGreaterThanOrEqualToWhenPresent<Integer> mapped = filtered.map(i -> null);
145         assertThat(mapped.isEmpty()).isTrue();
146         assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(mapped::value);
147     }
148 
149     @SuppressWarnings("DataFlowIssue") // we are deliberately passing nulls into non-null methods for testing
150     @Test
151     void testIsLessThan() {
152         IsLessThan<Integer> nullCond = SqlBuilder.isLessThan((Integer) null); // should be an IDE warning
153         assertThat(nullCond.isEmpty()).isFalse();
154 
155         IsLessThan<Integer> cond = SqlBuilder.isLessThan(1);
156         IsLessThan<Integer> filtered = cond.filter(i -> i == 1);
157         IsLessThan<Integer> mapped = filtered.map(i -> null);  // should be an IDE warning
158         assertThat(mapped.isEmpty()).isFalse();
159         assertThat(mapped.value()).isNull();
160     }
161 
162     @Test
163     void testIsLessThanWhenPresent() {
164         IsLessThanWhenPresent<Integer> nullCond = SqlBuilder.isLessThanWhenPresent((Integer) null);
165         assertThat(nullCond.isEmpty()).isTrue();
166 
167         IsLessThanWhenPresent<Integer> cond = SqlBuilder.isLessThanWhenPresent(1);
168         IsLessThanWhenPresent<Integer> filtered = cond.filter(i -> i == 1);
169         IsLessThanWhenPresent<Integer> mapped = filtered.map(i -> null);
170         assertThat(mapped.isEmpty()).isTrue();
171         assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(mapped::value);
172     }
173 
174     @SuppressWarnings("DataFlowIssue") // we are deliberately passing nulls into non-null methods for testing
175     @Test
176     void testIsLessThanOrEqualTo() {
177         IsLessThanOrEqualTo<Integer> nullCond = SqlBuilder.isLessThanOrEqualTo((Integer) null); // should be an IDE warning
178         assertThat(nullCond.isEmpty()).isFalse();
179 
180         IsLessThanOrEqualTo<Integer> cond = SqlBuilder.isLessThanOrEqualTo(1);
181         IsLessThanOrEqualTo<Integer> filtered = cond.filter(i -> i == 1);
182         IsLessThanOrEqualTo<Integer> mapped = filtered.map(i -> null);  // should be an IDE warning
183         assertThat(mapped.isEmpty()).isFalse();
184         assertThat(mapped.value()).isNull();
185     }
186 
187     @Test
188     void testIsLessThanOrEqualToWhenPresent() {
189         IsLessThanOrEqualToWhenPresent<Integer> nullCond = SqlBuilder.isLessThanOrEqualToWhenPresent((Integer) null);
190         assertThat(nullCond.isEmpty()).isTrue();
191 
192         IsLessThanOrEqualToWhenPresent<Integer> cond = SqlBuilder.isLessThanOrEqualToWhenPresent(1);
193         IsLessThanOrEqualToWhenPresent<Integer> filtered = cond.filter(i -> i == 1);
194         IsLessThanOrEqualToWhenPresent<Integer> mapped = filtered.map(i -> null);
195         assertThat(mapped.isEmpty()).isTrue();
196         assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(mapped::value);
197     }
198 
199     @SuppressWarnings("DataFlowIssue") // we are deliberately passing nulls into non-null methods for testing
200     @Test
201     void testIsNotBetween() {
202         IsNotBetween<Integer> nullCond = SqlBuilder.isNotBetween((Integer) null).and((Integer) null);
203         assertThat(nullCond.isEmpty()).isFalse();
204 
205         IsNotBetween<Integer> cond = SqlBuilder.isNotBetween(1).and(10);
206         IsNotBetween<Integer> filtered = cond.filter(i -> i >= 1);
207         IsNotBetween<Integer> mapped = filtered.map(i -> null);
208         assertThat(mapped.isEmpty()).isFalse();
209 
210         mapped = filtered.map(v1 -> null, v2 -> null);
211         assertThat(mapped.isEmpty()).isFalse();
212         assertThat(mapped.value1()).isNull();
213         assertThat(mapped.value2()).isNull();
214     }
215 
216     @Test
217     void testIsNotBetweenWhenPresent() {
218         IsNotBetweenWhenPresent<Integer> nullCond = SqlBuilder.isNotBetweenWhenPresent((Integer) null).and((Integer) null);
219         assertThat(nullCond.isEmpty()).isTrue();
220 
221         IsNotBetweenWhenPresent<Integer> cond = SqlBuilder.isNotBetweenWhenPresent(1).and(10);
222         IsNotBetweenWhenPresent<Integer> filtered = cond.filter(i -> i == 1);
223         IsNotBetweenWhenPresent<Integer> mapped = filtered.map(i -> null);
224         assertThat(mapped.isEmpty()).isTrue();
225 
226         mapped = filtered.map(v1 -> null, v2 -> null);
227         assertThat(mapped.isEmpty()).isTrue();
228         assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(mapped::value1);
229         assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(mapped::value2);
230     }
231 
232     @SuppressWarnings("DataFlowIssue") // we are deliberately passing nulls into non-null methods for testing
233     @Test
234     void testIsNotEqualTo() {
235         IsNotEqualTo<Integer> nullCond = SqlBuilder.isNotEqualTo((Integer) null); // should be an IDE warning
236         assertThat(nullCond.isEmpty()).isFalse();
237 
238         IsNotEqualTo<Integer> cond = SqlBuilder.isNotEqualTo(1);
239         IsNotEqualTo<Integer> filtered = cond.filter(i -> i == 1);
240         IsNotEqualTo<Integer> mapped = filtered.map(i -> null); // should be an IDE warning
241         assertThat(mapped.isEmpty()).isFalse();
242         assertThat(mapped.value()).isNull();
243     }
244 
245     @Test
246     void testIsNotEqualToWhenPresent() {
247         IsNotEqualToWhenPresent<Integer> nullCond = SqlBuilder.isNotEqualToWhenPresent((Integer) null);
248         assertThat(nullCond.isEmpty()).isTrue();
249 
250         IsNotEqualToWhenPresent<Integer> cond = SqlBuilder.isNotEqualToWhenPresent(1);
251         IsNotEqualToWhenPresent<Integer> filtered = cond.filter(i -> i == 1);
252         IsNotEqualToWhenPresent<Integer> mapped = filtered.map(i -> null);
253         assertThat(mapped.isEmpty()).isTrue();
254         assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(mapped::value);
255     }
256 
257     @SuppressWarnings("DataFlowIssue") // we are deliberately passing nulls into non-null methods for testing
258     @Test
259     void testIsLike() {
260         IsLike<String> nullCond = SqlBuilder.isLike((String) null); // should be an IDE warning
261         assertThat(nullCond.isEmpty()).isFalse();
262 
263         IsLike<String> cond = SqlBuilder.isLike("fred");
264         IsLike<String> filtered = cond.filter(i -> i.equals("fred"));
265         IsLike<String> mapped = filtered.map(i -> null); // should be an IDE warning
266         assertThat(mapped.isEmpty()).isFalse();
267         assertThat(mapped.value()).isNull();
268     }
269 
270     @Test
271     void testIsLikeWhenPresent() {
272         IsLikeWhenPresent<String> nullCond = SqlBuilder.isLikeWhenPresent((String) null);
273         assertThat(nullCond.isEmpty()).isTrue();
274 
275         IsLikeWhenPresent<String> cond = SqlBuilder.isLikeWhenPresent("fred");
276         IsLikeWhenPresent<String> filtered = cond.filter(i -> i.equals("fred"));
277         IsLikeWhenPresent<String> mapped = filtered.map(i -> null);
278         assertThat(mapped.isEmpty()).isTrue();
279         assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(mapped::value);
280     }
281 
282     @SuppressWarnings("DataFlowIssue") // we are deliberately passing nulls into non-null methods for testing
283     @Test
284     void testIsLikeCaseInsensitive() {
285         IsLikeCaseInsensitive<String> nullCond = SqlBuilder.isLikeCaseInsensitive((String) null); // should be an IDE warning
286         assertThat(nullCond.isEmpty()).isFalse();
287 
288         IsLikeCaseInsensitive<String> cond = SqlBuilder.isLikeCaseInsensitive("fred");
289         IsLikeCaseInsensitive<String> filtered = cond.filter(i -> i.equals("FRED"));
290         IsLikeCaseInsensitive<String> mapped = filtered.map(i -> null); // should be an IDE warning
291         assertThat(mapped.isEmpty()).isFalse();
292         assertThat(mapped.value()).isNull();
293     }
294 
295     @Test
296     void testIsLikeCaseInsensitiveWhenPresent() {
297         IsLikeCaseInsensitiveWhenPresent<String> nullCond = SqlBuilder.isLikeCaseInsensitiveWhenPresent((String) null);
298         assertThat(nullCond.isEmpty()).isTrue();
299 
300         IsLikeCaseInsensitiveWhenPresent<String> cond = SqlBuilder.isLikeCaseInsensitiveWhenPresent("fred");
301         IsLikeCaseInsensitiveWhenPresent<String> filtered = cond.filter(i -> i.equals("fred"));
302         IsLikeCaseInsensitiveWhenPresent<String> mapped = filtered.map(i -> null);
303         assertThat(mapped.isEmpty()).isTrue();
304         assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(mapped::value);
305     }
306 
307     @SuppressWarnings("DataFlowIssue") // we are deliberately passing nulls into non-null methods for testing
308     @Test
309     void testIsNotLike() {
310         IsNotLike<String> nullCond = SqlBuilder.isNotLike((String) null); // should be an IDE warning
311         assertThat(nullCond.isEmpty()).isFalse();
312 
313         IsNotLike<String> cond = SqlBuilder.isNotLike("fred");
314         IsNotLike<String> filtered = cond.filter(i -> i.equals("fred"));
315         IsNotLike<String> mapped = filtered.map(i -> null); // should be an IDE warning
316         assertThat(mapped.isEmpty()).isFalse();
317         assertThat(mapped.value()).isNull();
318     }
319 
320     @Test
321     void testIsNotLikeWhenPresent() {
322         IsNotLikeWhenPresent<String> nullCond = SqlBuilder.isNotLikeWhenPresent((String) null);
323         assertThat(nullCond.isEmpty()).isTrue();
324 
325         IsNotLikeWhenPresent<String> cond = SqlBuilder.isNotLikeWhenPresent("fred");
326         IsNotLikeWhenPresent<String> filtered = cond.filter(i -> i.equals("fred"));
327         IsNotLikeWhenPresent<String> mapped = filtered.map(i -> null);
328         assertThat(mapped.isEmpty()).isTrue();
329         assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(mapped::value);
330     }
331 
332     @SuppressWarnings("DataFlowIssue") // we are deliberately passing nulls into non-null methods for testing
333     @Test
334     void testIsNotLikeCaseInsensitive() {
335         IsNotLikeCaseInsensitive<String> nullCond = SqlBuilder.isNotLikeCaseInsensitive((String) null); // should be an IDE warning
336         assertThat(nullCond.isEmpty()).isFalse();
337 
338         IsNotLikeCaseInsensitive<String> cond = SqlBuilder.isNotLikeCaseInsensitive("fred");
339         IsNotLikeCaseInsensitive<String> filtered = cond.filter(i -> i.equals("FRED"));
340         IsNotLikeCaseInsensitive<String> mapped = filtered.map(i -> null); // should be an IDE warning
341         assertThat(mapped.isEmpty()).isFalse();
342         assertThat(mapped.value()).isNull();
343     }
344 
345     @Test
346     void testIsNotLikeCaseInsensitiveWhenPresent() {
347         IsNotLikeCaseInsensitiveWhenPresent<String> nullCond = SqlBuilder.isNotLikeCaseInsensitiveWhenPresent((String) null);
348         assertThat(nullCond.isEmpty()).isTrue();
349 
350         IsNotLikeCaseInsensitiveWhenPresent<String> cond = SqlBuilder.isNotLikeCaseInsensitiveWhenPresent("fred");
351         IsNotLikeCaseInsensitiveWhenPresent<String> filtered = cond.filter(i -> i.equals("FRED"));
352         IsNotLikeCaseInsensitiveWhenPresent<String> mapped = filtered.map(i -> null);
353         assertThat(mapped.isEmpty()).isTrue();
354         assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(mapped::value);
355     }
356 
357     @SuppressWarnings("DataFlowIssue") // we are deliberately passing nulls into non-null methods for testing
358     @Test
359     void testIsIn() {
360         IsIn<Integer> nullCond = SqlBuilder.isIn((Integer) null); // should be an IDE warning
361         assertThat(nullCond.isEmpty()).isFalse();
362 
363         IsIn<Integer> cond = SqlBuilder.isIn(1);
364         IsIn<Integer> filtered = cond.filter(i -> i == 1);
365         IsIn<Integer> mapped = filtered.map(i -> null); // should be an IDE warning
366         assertThat(mapped.isEmpty()).isFalse();
367         assertThat(mapped.values().toList()).containsExactly((Integer) null);
368     }
369 
370     @Test
371     void testIsInWhenPresent() {
372         IsInWhenPresent<Integer> nullCond = SqlBuilder.isInWhenPresent((Integer) null);
373         assertThat(nullCond.isEmpty()).isTrue();
374 
375         IsInWhenPresent<Integer> cond = SqlBuilder.isInWhenPresent(1);
376         IsInWhenPresent<Integer> filtered = cond.filter(i -> i == 1);
377         IsInWhenPresent<Integer> mapped = filtered.map(i -> null);
378         assertThat(mapped.isEmpty()).isTrue();
379         assertThat(mapped.values().toList()).isEmpty();
380     }
381 
382     @SuppressWarnings("DataFlowIssue") // we are deliberately passing nulls into non-null methods for testing
383     @Test
384     void testIsInCaseInsensitive() {
385         IsInCaseInsensitive<String> nullCond = SqlBuilder.isInCaseInsensitive((String) null); // should be an IDE warning
386         assertThat(nullCond.isEmpty()).isFalse();
387 
388         IsInCaseInsensitive<String> cond = SqlBuilder.isInCaseInsensitive("fred");
389         IsInCaseInsensitive<String> filtered = cond.filter(i -> i.equals("FRED"));
390         IsInCaseInsensitive<String> mapped = filtered.map(i -> null); // should be an IDE warning
391         assertThat(mapped.isEmpty()).isFalse();
392         assertThat(mapped.values().toList()).containsExactly((String) null);
393     }
394 
395     @Test
396     void testIsInCaseInsensitiveWhenPresent() {
397         IsInCaseInsensitiveWhenPresent<String> nullCond = SqlBuilder.isInCaseInsensitiveWhenPresent((String) null);
398         assertThat(nullCond.isEmpty()).isTrue();
399 
400         IsInCaseInsensitiveWhenPresent<String> cond = SqlBuilder.isInCaseInsensitiveWhenPresent("fred");
401         IsInCaseInsensitiveWhenPresent<String> filtered = cond.filter(i -> i.equals("FRED"));
402         IsInCaseInsensitiveWhenPresent<String> mapped = filtered.map(i -> null);
403         assertThat(mapped.isEmpty()).isTrue();
404         assertThat(mapped.values().toList()).isEmpty();
405     }
406 
407     @SuppressWarnings("DataFlowIssue") // we are deliberately passing nulls into non-null methods for testing
408     @Test
409     void testIsNotIn() {
410         IsNotIn<Integer> nullCond = SqlBuilder.isNotIn((Integer) null); // should be an IDE warning
411         assertThat(nullCond.isEmpty()).isFalse();
412 
413         IsNotIn<Integer> cond = SqlBuilder.isNotIn(1);
414         IsNotIn<Integer> filtered = cond.filter(i -> i == 1);
415         IsNotIn<Integer> mapped = filtered.map(i -> null); // should be an IDE warning
416         assertThat(mapped.isEmpty()).isFalse();
417         assertThat(mapped.values().toList()).containsExactly((Integer) null);
418     }
419 
420     @Test
421     void testIsNotInWhenPresent() {
422         IsNotInWhenPresent<Integer> nullCond = SqlBuilder.isNotInWhenPresent((Integer) null);
423         assertThat(nullCond.isEmpty()).isTrue();
424 
425         IsNotInWhenPresent<Integer> cond = SqlBuilder.isNotInWhenPresent(1);
426         IsNotInWhenPresent<Integer> filtered = cond.filter(i -> i == 1);
427         IsNotInWhenPresent<Integer> mapped = filtered.map(i -> null);
428         assertThat(mapped.isEmpty()).isTrue();
429         assertThat(mapped.values().toList()).isEmpty();
430     }
431 
432     @SuppressWarnings("DataFlowIssue") // we are deliberately passing nulls into non-null methods for testing
433     @Test
434     void testIsNotInCaseInsensitive() {
435         IsNotInCaseInsensitive<String> nullCond = SqlBuilder.isNotInCaseInsensitive((String) null); // should be an IDE warning
436         assertThat(nullCond.isEmpty()).isFalse();
437 
438         IsNotInCaseInsensitive<String> cond = SqlBuilder.isNotInCaseInsensitive("fred");
439         IsNotInCaseInsensitive<String> filtered = cond.filter(i -> i.equals("FRED"));
440         IsNotInCaseInsensitive<String> mapped = filtered.map(i -> null); // should be an IDE warning
441         assertThat(mapped.isEmpty()).isFalse();
442         assertThat(mapped.values().toList()).containsExactly((String) null);
443     }
444 
445     @Test
446     void testIsNotInCaseInsensitiveWhenPresent() {
447         IsNotInCaseInsensitiveWhenPresent<String> nullCond = SqlBuilder.isNotInCaseInsensitiveWhenPresent((String) null);
448         assertThat(nullCond.isEmpty()).isTrue();
449 
450         IsNotInCaseInsensitiveWhenPresent<String> cond = SqlBuilder.isNotInCaseInsensitiveWhenPresent("fred");
451         IsNotInCaseInsensitiveWhenPresent<String> filtered = cond.filter(i -> i.equals("FRED"));
452         IsNotInCaseInsensitiveWhenPresent<String> mapped = filtered.map(i -> null);
453         assertThat(mapped.isEmpty()).isTrue();
454         assertThat(mapped.values().toList()).isEmpty();
455     }
456 
457     @SuppressWarnings("DataFlowIssue") // we are deliberately passing nulls into non-null methods for testing
458     @Test
459     void testIsBetweenNull() {
460         IsBetween<Integer> cond = SqlBuilder.isBetween(() -> (Integer) null).and(() -> null);
461         assertThat(cond.value1()).isNull();
462         assertThat(cond.value2()).isNull();
463         assertThat(cond.isEmpty()).isFalse();
464     }
465 
466     @SuppressWarnings("DataFlowIssue") // we are deliberately passing nulls into non-null methods for testing
467     @Test
468     void testIsNotBetweenNull() {
469         IsNotBetween<Integer> cond = SqlBuilder.isNotBetween(() -> (Integer) null).and(() -> null);
470         assertThat(cond.value1()).isNull();
471         assertThat(cond.value2()).isNull();
472         assertThat(cond.isEmpty()).isFalse();
473     }
474 
475     @SuppressWarnings("DataFlowIssue") // we are deliberately passing nulls into non-null methods for testing
476     @Test
477     void testIsNotEqualToNull() {
478         IsNotEqualTo<Integer> cond = SqlBuilder.isNotEqualTo(() -> (Integer) null);
479         assertThat(cond.value()).isNull();
480         assertThat(cond.isEmpty()).isFalse();
481     }
482 
483     @SuppressWarnings("DataFlowIssue") // we are deliberately passing nulls into non-null methods for testing
484     @Test
485     void testIsGreaterThanNull() {
486         IsGreaterThan<Integer> cond = SqlBuilder.isGreaterThan(() -> (Integer) null);
487         assertThat(cond.value()).isNull();
488         assertThat(cond.isEmpty()).isFalse();
489     }
490 
491     @SuppressWarnings("DataFlowIssue") // we are deliberately passing nulls into non-null methods for testing
492     @Test
493     void testIsGreaterThanOrEqualToNull() {
494         IsGreaterThanOrEqualTo<Integer> cond = SqlBuilder.isGreaterThanOrEqualTo(() -> (Integer) null);
495         assertThat(cond.value()).isNull();
496         assertThat(cond.isEmpty()).isFalse();
497     }
498 
499     @SuppressWarnings("DataFlowIssue") // we are deliberately passing nulls into non-null methods for testing
500     @Test
501     void testIsLessThanNull() {
502         IsLessThan<Integer> cond = SqlBuilder.isLessThan(() -> (Integer) null);
503         assertThat(cond.value()).isNull();
504         assertThat(cond.isEmpty()).isFalse();
505     }
506 
507     @SuppressWarnings("DataFlowIssue") // we are deliberately passing nulls into non-null methods for testing
508     @Test
509     void testIsLessThanOrEqualToNull() {
510         IsLessThanOrEqualTo<Integer> cond = SqlBuilder.isLessThanOrEqualTo(() -> (Integer) null);
511         assertThat(cond.value()).isNull();
512         assertThat(cond.isEmpty()).isFalse();
513     }
514 
515     @SuppressWarnings("DataFlowIssue") // we are deliberately passing nulls into non-null methods for testing
516     @Test
517     void testIsLikeNull() {
518         IsLike<String> cond = SqlBuilder.isLike(() -> null);
519         assertThat(cond.value()).isNull();
520         assertThat(cond.isEmpty()).isFalse();
521     }
522 
523     @SuppressWarnings("DataFlowIssue") // we are deliberately passing nulls into non-null methods for testing
524     @Test
525     void testIsLikeCaseInsensitiveNull() {
526         IsLikeCaseInsensitive<String> cond = SqlBuilder.isLikeCaseInsensitive(() -> null);
527         assertThat(cond.value()).isNull();
528         assertThat(cond.isEmpty()).isFalse();
529     }
530 
531     @SuppressWarnings("DataFlowIssue") // we are deliberately passing nulls into non-null methods for testing
532     @Test
533     void testIsNotLikeNull() {
534         IsNotLike<String> cond = SqlBuilder.isNotLike(() -> null);
535         assertThat(cond.value()).isNull();
536         assertThat(cond.isEmpty()).isFalse();
537     }
538 
539     @SuppressWarnings("DataFlowIssue") // we are deliberately passing nulls into non-null methods for testing
540     @Test
541     void testIsNotLikeCaseInsensitiveNull() {
542         IsNotLikeCaseInsensitive<String> cond = SqlBuilder.isNotLikeCaseInsensitive(() -> null);
543         assertThat(cond.value()).isNull();
544         assertThat(cond.isEmpty()).isFalse();
545     }
546 }