1   /*
2    * SPDX-FileCopyrightText: none
3    * SPDX-License-Identifier: CC0-1.0
4    */
5   
6   package dev.metaschema.core.metapath.function.library;
7   
8   import static dev.metaschema.core.metapath.TestUtils.sequence;
9   import static dev.metaschema.core.metapath.TestUtils.string;
10  import static org.assertj.core.api.Assertions.assertThat;
11  import static org.junit.jupiter.api.Assertions.assertEquals;
12  import static org.junit.jupiter.api.Assertions.assertThrows;
13  
14  import org.junit.jupiter.api.Test;
15  import org.junit.jupiter.params.ParameterizedTest;
16  import org.junit.jupiter.params.provider.Arguments;
17  import org.junit.jupiter.params.provider.MethodSource;
18  
19  import java.util.List;
20  import java.util.regex.PatternSyntaxException;
21  import java.util.stream.Stream;
22  
23  import dev.metaschema.core.metapath.ExpressionTestBase;
24  import dev.metaschema.core.metapath.IMetapathExpression;
25  import dev.metaschema.core.metapath.function.regex.RegularExpressionMetapathException;
26  import dev.metaschema.core.metapath.item.ISequence;
27  import dev.metaschema.core.util.ObjectUtils;
28  import edu.umd.cs.findbugs.annotations.NonNull;
29  
30  class FnTokenizeTest
31      extends ExpressionTestBase {
32  
33    private static Stream<Arguments> provideValues() { // NOPMD - false positive
34      return Stream.of(
35          Arguments.of(
36              sequence(string("red"), string("green"), string("blue")),
37              "tokenize(\" red green blue \")"),
38          Arguments.of(
39              sequence(string("The"), string("cat"), string("sat"), string("on"), string("the"), string("mat")),
40              "tokenize(\"The cat sat on the mat\", \"\\s+\")"),
41          Arguments.of(
42              sequence(string(""), string("red"), string("green"), string("blue"), string("")),
43              "tokenize(\" red green blue \", \"\\s+\")"),
44          Arguments.of(
45              sequence(string("1"), string("15"), string("24"), string("50")),
46              "tokenize(\"1, 15, 24, 50\", \",\\s*\")"),
47          Arguments.of(
48              sequence(string("1"), string("15"), string(""), string("24"), string("50"), string("")),
49              "tokenize(\"1,15,,24,50,\", \",\")"),
50          Arguments.of(
51              sequence(string("Some unparsed"), string("HTML"), string("text")),
52              "tokenize(\"Some unparsed <br> HTML <BR> text\", \"\\s*<br>\\s*\", \"i\")"));
53    }
54  
55    @ParameterizedTest
56    @MethodSource("provideValues")
57    void test(@NonNull ISequence<?> expected, @NonNull String metapath) {
58      assertEquals(expected, IMetapathExpression.compile(metapath).evaluate(null, newDynamicContext()));
59    }
60  
61    // TODO: make sure this (and others) exception chain is flattened
62    @Test
63    void testMatchZeroLengthString() {
64      RegularExpressionMetapathException thrown = assertThrows(RegularExpressionMetapathException.class,
65          () -> {
66            FunctionTestBase.executeFunction(
67                FnTokenize.SIGNATURE_TWO_ARG,
68                newDynamicContext(),
69                ISequence.empty(),
70                ObjectUtils.notNull(List.of(sequence(string("abba")), sequence(string(".?")))));
71          });
72      assertThat(thrown)
73          .isExactlyInstanceOf(RegularExpressionMetapathException.class)
74          .hasNoCause()
75          .extracting(ex -> ex.getErrorCode().getCode())
76          .isEqualTo(RegularExpressionMetapathException.MATCHES_ZERO_LENGTH_STRING);
77    }
78  
79    @Test
80    void testInvalidPattern() {
81      RegularExpressionMetapathException thrown = assertThrows(RegularExpressionMetapathException.class,
82          () -> {
83            FunctionTestBase.executeFunction(
84                FnTokenize.SIGNATURE_TWO_ARG,
85                newDynamicContext(),
86                ISequence.empty(),
87                ObjectUtils.notNull(List.of(sequence(string("input")), sequence(string("pattern[")))));
88          });
89      assertThat(thrown)
90          .isExactlyInstanceOf(RegularExpressionMetapathException.class)
91          .hasCauseExactlyInstanceOf(PatternSyntaxException.class)
92          .extracting(ex -> ex.getErrorCode().getCode())
93          .isEqualTo(RegularExpressionMetapathException.INVALID_EXPRESSION);
94    }
95  
96    @Test
97    void testInvalidFlag() {
98      RegularExpressionMetapathException thrown = assertThrows(RegularExpressionMetapathException.class,
99          () -> {
100           FunctionTestBase.executeFunction(
101               FnTokenize.SIGNATURE_THREE_ARG,
102               newDynamicContext(),
103               ISequence.empty(),
104               ObjectUtils.notNull(List.of(
105                   sequence(string("input")),
106                   sequence(string("pattern")),
107                   sequence(string("dsm")))));
108         });
109     assertThat(thrown)
110         .isExactlyInstanceOf(RegularExpressionMetapathException.class)
111         .hasNoCause()
112         .extracting(ex -> ex.getErrorCode().getCode())
113         .isEqualTo(RegularExpressionMetapathException.INVALID_FLAG);
114   }
115 }