View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      https://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.text.similarity;
18  
19  import static org.junit.jupiter.api.Assertions.assertEquals;
20  import static org.junit.jupiter.api.Assertions.assertNull;
21  import static org.junit.jupiter.api.Assertions.assertThrows;
22  
23  import java.util.Arrays;
24  import java.util.stream.Stream;
25  
26  import org.junit.jupiter.api.BeforeAll;
27  import org.junit.jupiter.api.Test;
28  import org.junit.jupiter.params.ParameterizedTest;
29  import org.junit.jupiter.params.provider.Arguments;
30  import org.junit.jupiter.params.provider.MethodSource;
31  
32  /**
33   * Tests {@link DamerauLevenshteinDistance}.
34   */
35  public class DamerauLevenshteinDistanceTest {
36  
37      private static DamerauLevenshteinDistance defaultInstance;
38  
39      @BeforeAll
40      static void createInstance() {
41          defaultInstance = new DamerauLevenshteinDistance();
42      }
43  
44      static Stream<Arguments> limitedDamerauLevenshteinDistanceTestCases() {
45          return Stream.of(
46                  Arguments.of("", "test", 10, 4),
47                  Arguments.of("test", "", 10, 4),
48                  Arguments.of("", "test", 2, -1),
49                  Arguments.of("test", "", 2, -1),
50                  Arguments.of("testing long string", "testing", 2, -1),
51                  Arguments.of("kitten", "sitting", 1, -1),
52                  Arguments.of("saturday", "sunday", 3, 3),
53                  Arguments.of("hello", "world", 6, 4),
54                  Arguments.of("algorithm", "logarithm", 1, -1),
55                  Arguments.of("computer", "comptuer", 1, 1),
56                  Arguments.of("receive", "recieve", 3, 1),
57                  Arguments.of("programming", "porgramming", 0, -1),
58                  Arguments.of("test", "tset", 1, 1),
59                  Arguments.of("example", "exmaple", 3, 1),
60                  Arguments.of("transform", "transfrom", 0, -1),
61                  Arguments.of("information", "infromation", 1, 1),
62                  Arguments.of("development", "developemnt", 3, 1),
63                  Arguments.of("password", "passwrod", 0, -1),
64                  Arguments.of("separate", "seperate", 1, 1),
65                  Arguments.of("definitely", "definately", 3, 1),
66                  Arguments.of("occurrence", "occurence", 0, -1),
67                  Arguments.of("necessary", "neccessary", 1, 1),
68                  Arguments.of("restaurant", "restaraunt", 4, 2),
69                  Arguments.of("beginning", "begining", 0, -1),
70                  Arguments.of("government", "goverment", 1, 1),
71                  Arguments.of("abcdefghijklmnop", "ponmlkjihgfedcba", 17, 15),
72                  Arguments.of("AAAAAAAAAA", "BBBBBBBBBB", 5, -1),
73                  Arguments.of("abababababab", "babababababa", 2, 2),
74                  Arguments.of("supercalifragilisticexpialidocious", "supercalifragilisticexpialidocous", 3, 1),
75                  Arguments.of("pneumonoultramicroscopicsilicovolcanoconiosiss", "pneumonoultramicroscopicsilicovolcanoconiosis", 0, -1),
76                  Arguments.of("abcdefg", "gfedcba", 6, 6),
77                  Arguments.of("xyxyxyxyxy", "yxyxyxyxyx", 4, 2),
78                  Arguments.of("aaaaabbbbbccccc", "cccccbbbbbaaaaa", 5, -1),
79                  Arguments.of("thequickbrownfoxjumpsoverthelazydog", "thequickbrownfoxjumpsovrethelazydog", 1, 1),
80                  Arguments.of("antidisestablishmentarianism", "antidisestablishmentarianisn", 3, 1)
81          );
82      }
83  
84      static Stream<Arguments> limitedDamerauLevenshteinDistanceTestCases_SimilarityInput() {
85          return SimilarityInputTest.similarityInputs()
86                  .flatMap(cls -> limitedDamerauLevenshteinDistanceTestCases().map(arguments -> {
87                      final Object[] values = Arrays.copyOf(arguments.get(), arguments.get().length + 1);
88                      values[values.length - 1] = cls;
89                      return Arguments.of(values);
90                  }));
91      }
92  
93      static Stream<Arguments> unlimitedDamerauLevenshteinDistanceTestCases() {
94          return Stream.of(
95                  Arguments.of("", "test", 4),
96                  Arguments.of("test", "", 4),
97                  Arguments.of("kitten", "sitting", 3),
98                  Arguments.of("saturday", "sunday", 3),
99                  Arguments.of("hello", "world", 4),
100                 Arguments.of("algorithm", "logarithm", 3),
101                 Arguments.of("computer", "comptuer", 1),
102                 Arguments.of("receive", "recieve", 1),
103                 Arguments.of("programming", "porgramming", 1),
104                 Arguments.of("test", "tset", 1),
105                 Arguments.of("example", "exmaple", 1),
106                 Arguments.of("transform", "transfrom", 1),
107                 Arguments.of("information", "infromation", 1),
108                 Arguments.of("development", "developemnt", 1),
109                 Arguments.of("password", "passwrod", 1),
110                 Arguments.of("separate", "seperate", 1),
111                 Arguments.of("definitely", "definately", 1),
112                 Arguments.of("occurrence", "occurence", 1),
113                 Arguments.of("necessary", "neccessary", 1),
114                 Arguments.of("restaurant", "restaraunt", 2),
115                 Arguments.of("beginning", "begining", 1),
116                 Arguments.of("government", "goverment", 1),
117                 Arguments.of("abcdefghijklmnop", "ponmlkjihgfedcba", 15),
118                 Arguments.of("AAAAAAAAAA", "BBBBBBBBBB", 10),
119                 Arguments.of("abababababab", "babababababa", 2),
120                 Arguments.of("supercalifragilisticexpialidocious", "supercalifragilisticexpialidocous", 1),
121                 Arguments.of("pneumonoultramicroscopicsilicovolcanoconiosiss", "pneumonoultramicroscopicsilicovolcanoconiosis", 1),
122                 Arguments.of("abcdefg", "gfedcba", 6),
123                 Arguments.of("xyxyxyxyxy", "yxyxyxyxyx", 2),
124                 Arguments.of("aaaaabbbbbccccc", "cccccbbbbbaaaaa", 10),
125                 Arguments.of("thequickbrownfoxjumpsoverthelazydog", "thequickbrownfoxjumpsovrethelazydog", 1),
126                 Arguments.of("antidisestablishmentarianism", "antidisestablishmentarianisn", 1)
127         );
128     }
129 
130     static Stream<Arguments> unlimitedDamerauLevenshteinDistanceTestCases_SimilarityInput() {
131         return SimilarityInputTest.similarityInputs()
132                 .flatMap(cls -> unlimitedDamerauLevenshteinDistanceTestCases().map(arguments -> {
133                     final Object[] values = Arrays.copyOf(arguments.get(), arguments.get().length + 1);
134                     values[values.length - 1] = cls;
135                     return Arguments.of(values);
136                 }));
137     }
138 
139     @ParameterizedTest(name = "DamerauLevenshteinDistance.unlimitedCompare(\"{0}\", \"{1}\") should return {2}")
140     @MethodSource("unlimitedDamerauLevenshteinDistanceTestCases")
141     void testCalculateDamerauLevenshteinDistance(final String left, final String right, final int expectedDistance) {
142         final int leftRightDistance = defaultInstance.apply(left, right);
143         final int rightLeftDistance = defaultInstance.apply(right, left);
144         assertEquals(expectedDistance, leftRightDistance);
145         assertEquals(expectedDistance, rightLeftDistance);
146     }
147 
148     @ParameterizedTest(name = "DamerauLevenshteinDistance.limitedCompare(\"{0}\", \"{1}\") should return {2}")
149     @MethodSource("limitedDamerauLevenshteinDistanceTestCases")
150     void testCalculateDamerauLevenshteinDistance(final String left, final String right, final int threshold, final int expectedDistance) {
151         final DamerauLevenshteinDistance instance = new DamerauLevenshteinDistance(threshold);
152         final int leftRightDistance = instance.apply(left, right);
153         final int rightLeftDistance = instance.apply(right, left);
154         assertEquals(expectedDistance, leftRightDistance);
155         assertEquals(expectedDistance, rightLeftDistance);
156     }
157 
158     @ParameterizedTest(name = "DamerauLevenshteinDistance.unlimitedCompare(\"{0}\", \"{1}\") should return {2} ({3})")
159     @MethodSource("unlimitedDamerauLevenshteinDistanceTestCases_SimilarityInput")
160     void testCalculateDamerauLevenshteinDistance_SimilarityInput(final String left, final String right, final int expectedDistance, final Class<?> cls) {
161         final SimilarityInput<Object> leftInput = SimilarityInputTest.build(cls, left);
162         final SimilarityInput<Object> rightInput = SimilarityInputTest.build(cls, right);
163         final int leftRightDistance = defaultInstance.apply(leftInput, rightInput);
164         final int rightLeftDistance = defaultInstance.apply(rightInput, leftInput);
165         assertEquals(expectedDistance, leftRightDistance);
166         assertEquals(expectedDistance, rightLeftDistance);
167     }
168 
169     @ParameterizedTest(name = "DamerauLevenshteinDistance.limitedCompare(\"{0}\", \"{1}\") should return {2}")
170     @MethodSource("limitedDamerauLevenshteinDistanceTestCases_SimilarityInput")
171     void testCalculateDamerauLevenshteinDistance_SimilarityInput(final String left, final String right, final int threshold, final int expectedDistance,
172             final Class<?> cls) {
173         final DamerauLevenshteinDistance instance = new DamerauLevenshteinDistance(threshold);
174         final SimilarityInput<Object> leftInput = SimilarityInputTest.build(cls, left);
175         final SimilarityInput<Object> rightInput = SimilarityInputTest.build(cls, right);
176         final int leftRightDistance = instance.apply(leftInput, rightInput);
177         final int rightLeftDistance = instance.apply(rightInput, leftInput);
178         assertEquals(expectedDistance, leftRightDistance);
179         assertEquals(expectedDistance, rightLeftDistance);
180     }
181 
182     @Test
183     void testGetThresholdDirectlyAfterObjectInstantiation() {
184         assertNull(defaultInstance.getThreshold());
185     }
186 
187     @Test
188     void testGetThresholdIsCorrect() {
189         final DamerauLevenshteinDistance distance = new DamerauLevenshteinDistance(10);
190         assertEquals(10, distance.getThreshold());
191     }
192 
193     @Test
194     void testInvalidThresholdThrows() {
195         assertThrows(IllegalArgumentException.class, () -> new DamerauLevenshteinDistance(-1));
196     }
197 
198     @Test
199     void testNullInputsThrowLimited() {
200         final DamerauLevenshteinDistance instance = new DamerauLevenshteinDistance(10);
201         assertThrows(IllegalArgumentException.class, () -> instance.apply(null, "test"));
202         assertThrows(IllegalArgumentException.class, () -> instance.apply("test", null));
203         assertThrows(IllegalArgumentException.class, () -> instance.apply(null, SimilarityInput.input("test")));
204         assertThrows(IllegalArgumentException.class, () -> instance.apply(SimilarityInput.input("test"), null));
205     }
206 
207     @Test
208     void testNullInputsThrowUnlimited() {
209         assertThrows(IllegalArgumentException.class, () -> defaultInstance.apply(null, "test"));
210         assertThrows(IllegalArgumentException.class, () -> defaultInstance.apply("test", null));
211         assertThrows(IllegalArgumentException.class, () -> defaultInstance.apply(null, SimilarityInput.input("test")));
212         assertThrows(IllegalArgumentException.class, () -> defaultInstance.apply(SimilarityInput.input("test"), null));
213     }
214 }