diff --git a/src/test/java/org/apache/commons/text/AlphabetConverterPartitionTest.java b/src/test/java/org/apache/commons/text/AlphabetConverterPartitionTest.java new file mode 100644 index 0000000000..6ea1d3f406 --- /dev/null +++ b/src/test/java/org/apache/commons/text/AlphabetConverterPartitionTest.java @@ -0,0 +1,126 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.text; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertNull; + +import java.io.UnsupportedEncodingException; + +import org.junit.jupiter.api.Test; + +public class AlphabetConverterPartitionTest { + // 1. Valid input: Basic encoding/decoding + @Test + void testSimpleEncodeDecode() throws UnsupportedEncodingException { + Character[] original = {'a', 'b', 'c'}; + Character[] encoding = {'0', '1', '2'}; + Character[] doNotEncode = {}; + AlphabetConverter converter = AlphabetConverter.createConverterFromChars(original, encoding, doNotEncode); + + assertEquals("012", converter.encode("abc")); + assertEquals("abc", converter.decode("012")); + } + + // 2. Valid input: Encoding with doNotEncode characters + @Test + void testDoNotEncodeCharacters() throws UnsupportedEncodingException { + Character[] original = {'a', 'b', 'c'}; + Character[] encoding = {'0', '1', 'c'}; + Character[] doNotEncode = {'c'}; + AlphabetConverter converter = AlphabetConverter.createConverterFromChars(original, encoding, doNotEncode); + + assertEquals("00c", converter.encode("aac")); + assertEquals("aac", converter.decode("00c")); + } + + // 3. Invalid input: doNotEncode character not in original alphabet + @Test + void testDoNotEncodeMissingFromOriginal() { + Character[] original = {'a', 'b'}; + Character[] encoding = {'0', '1', 'c'}; + Character[] doNotEncode = {'c'}; // c not in original + + assertThrows(IllegalArgumentException.class, () -> + AlphabetConverter.createConverterFromChars(original, encoding, doNotEncode) + ); + } + + // 4. Invalid input: decode contains unknown encoded group + @Test + void testDecodeWithInvalidGroup() { + Character[] original = {'a', 'b', 'c'}; + Character[] encoding = {'0', '1', '2'}; + Character[] doNotEncode = {}; + AlphabetConverter converter = AlphabetConverter.createConverterFromChars(original, encoding, doNotEncode); + + assertThrows(UnsupportedEncodingException.class, () -> + converter.decode("xyz") + ); + } + + // 5. Valid input: Empty string encoding/decoding + @Test + void testEmptyString() throws UnsupportedEncodingException { + Character[] original = {'a', 'b', 'c'}; + Character[] encoding = {'0', '1', '2'}; + Character[] doNotEncode = {}; + AlphabetConverter converter = AlphabetConverter.createConverterFromChars(original, encoding, doNotEncode); + + assertEquals("", converter.encode("")); + assertEquals("", converter.decode("")); + } + + // 6. Valid input: null passed to encode/decode should return null + @Test + void testNullInputEncodeDecode() throws UnsupportedEncodingException { + Character[] original = {'a', 'b', 'c'}; + Character[] encoding = {'0', '1', '2'}; + Character[] doNotEncode = {}; + AlphabetConverter converter = AlphabetConverter.createConverterFromChars(original, encoding, doNotEncode); + + assertNull(converter.encode(null)); + assertNull(converter.decode(null)); + } + + // 7. Invalid input: encoding alphabet too small + @Test + void testEncodingAlphabetTooSmallThrows() { + Character[] original = {'a', 'b', 'c'}; + Character[] encoding = {'x'}; // too small + Character[] doNotEncode = {}; + + assertThrows(IllegalArgumentException.class, () -> + AlphabetConverter.createConverterFromChars(original, encoding, doNotEncode) + ); + } + + // 8. Valid input: repeated characters in original or encoding should be ignored + @Test + void testRepeatedCharactersAreIgnored() throws UnsupportedEncodingException { + Character[] original = {'a', 'b', 'a', 'c'}; + Character[] encoding = {'0', '1', '0', '2'}; + Character[] doNotEncode = {}; + AlphabetConverter converter = AlphabetConverter.createConverterFromChars(original, encoding, doNotEncode); + + String encoded = converter.encode("abc"); + String decoded = converter.decode(encoded); + assertEquals("abc", decoded); + } +} diff --git a/src/test/java/org/apache/commons/text/CaseUtilsPartitionTest.java b/src/test/java/org/apache/commons/text/CaseUtilsPartitionTest.java new file mode 100644 index 0000000000..1299c1f320 --- /dev/null +++ b/src/test/java/org/apache/commons/text/CaseUtilsPartitionTest.java @@ -0,0 +1,83 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.text; + +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; + +public class CaseUtilsPartitionTest { + // Null input string + @Test + void testNullInputReturnsNull() { + assertNull(CaseUtils.toCamelCase(null, true, null)); + } + + // Empty input string + @Test + void testEmptyInputReturnsEmpty() { + assertEquals("", CaseUtils.toCamelCase("", true, null)); + } + + // Only delimiters + @Test + void testOnlyDelimitersReturnsEmpty() { + assertEquals("", CaseUtils.toCamelCase(" @ @", false, new char[]{'@'})); + } + + // No delimiters (just case change) + @Test + void testNoDelimitersCapitalizationTrue() { + assertEquals("Hello", CaseUtils.toCamelCase("hello", true, null)); + } + + @Test + void testNoDelimitersCapitalizationFalse() { + assertEquals("hello", CaseUtils.toCamelCase("HELLO", false, null)); + } + + // Capitalize first letter flag + @Test + void testCapitalizeFirstTrue() { + assertEquals("FooBar", CaseUtils.toCamelCase("foo bar", true, null)); + } + + @Test + void testCapitalizeFirstFalse() { + assertEquals("fooBar", CaseUtils.toCamelCase("foo bar", false, null)); + } + + // Null delimiters (uses space as default) + @Test + void testNullDelimitersUsesSpace() { + assertEquals("FooBar", CaseUtils.toCamelCase("foo bar", true, null)); + } + + // Empty delimiters (also uses space) + @Test + void testEmptyDelimitersUsesSpace() { + assertEquals("FooBar", CaseUtils.toCamelCase("foo bar", true, new char[0])); + } + + // Custom delimiter characters + @Test + void testCustomDelimiters() { + assertEquals("FooBarBaz", CaseUtils.toCamelCase("foo-bar_baz", true, new char[]{'-', '_'})); + } +} diff --git a/src/test/java/org/apache/commons/text/lookup/DateStringLookupPartitionTest.java b/src/test/java/org/apache/commons/text/lookup/DateStringLookupPartitionTest.java new file mode 100644 index 0000000000..87cc7114da --- /dev/null +++ b/src/test/java/org/apache/commons/text/lookup/DateStringLookupPartitionTest.java @@ -0,0 +1,71 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ + +package org.apache.commons.text.lookup; + +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.assertFalse; + +import org.junit.jupiter.api.Test; + + +public class DateStringLookupPartitionTest { + + private final DateStringLookup lookup = DateStringLookup.INSTANCE; + + // Partition 1: Valid format strings + @Test + public void testValidFormat_yyyyMMdd() { + String result = lookup.lookup("yyyy-MM-dd"); + assertNotNull(result); + assertTrue(result.matches("\\d{4}-\\d{2}-\\d{2}")); + } + + @Test + public void testValidFormat_fullDateTime() { + String result = lookup.lookup("yyyy-MM-dd HH:mm:ss"); + assertNotNull(result); + assertTrue(result.matches("\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}")); + } + + @Test + public void testValidFormat_customText() { + String result = lookup.lookup("'Today is' EEEE"); + assertNotNull(result); + assertTrue(result.startsWith("Today is")); + } + + // Partition 2: Null format (default format) + @Test + public void testNullFormat_usesDefault() { + String result = lookup.lookup(null); + assertNotNull(result); + // Since default FastDateFormat output may vary, just check it's non-empty + assertFalse(result.isEmpty()); + } + + // Partition 3: Invalid format strings + @Test + public void testInvalidFormat_throwsException() { + Exception exception = assertThrows(IllegalArgumentException.class, () -> { + lookup.lookup("invalid_format_%%"); + }); + assertTrue(exception.getMessage().contains("Invalid date format")); + } +} diff --git a/src/test/java/org/apache/commons/text/lookup/FileStringLookupPartitionTest.java b/src/test/java/org/apache/commons/text/lookup/FileStringLookupPartitionTest.java new file mode 100644 index 0000000000..eb63f1bef5 --- /dev/null +++ b/src/test/java/org/apache/commons/text/lookup/FileStringLookupPartitionTest.java @@ -0,0 +1,82 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ + +package org.apache.commons.text.lookup; + +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; + +import org.junit.jupiter.api.Test; + +public class FileStringLookupPartitionTest { + private final FileStringLookup lookup = new FileStringLookup(); + + @Test + void testNullKeyReturnsNull() { + assertNull(lookup.lookup(null)); + } + + @Test + void testKeyMissingColonThrows() { + IllegalArgumentException ex = assertThrows(IllegalArgumentException.class, () -> + lookup.lookup("UTF-8") + ); + assertTrue(ex.getMessage().contains("Bad file key format")); + } + + @Test + void testInvalidCharsetThrows() { + IllegalArgumentException ex = assertThrows(IllegalArgumentException.class, () -> + lookup.lookup("FAKECHARSET:/some/fake/file.txt") + ); + assertTrue(ex.getMessage().contains("Error looking up file")); + } + + @Test + void testNonexistentFileThrows() { + IllegalArgumentException ex = assertThrows(IllegalArgumentException.class, () -> + lookup.lookup("UTF-8:/definitely/does/not/exist.txt") + ); + assertTrue(ex.getMessage().contains("Error looking up file")); + } + + @Test + void testValidKeyReturnsFileContents() throws Exception { + Path tempFile = Files.createTempFile("test-file", ".txt"); + Files.write(tempFile, "Hello, world!".getBytes(StandardCharsets.UTF_8)); + + String key = "UTF-8:" + tempFile.toString(); + String result = lookup.lookup(key); + assertEquals("Hello, world!", result); + } + + @Test + void testMultipleColonsStillWorksOrThrowsMeaningfully() { + // File doesn't exist, but structure is valid + String key = "UTF-8:/fake/path:ignored"; + IllegalArgumentException ex = assertThrows(IllegalArgumentException.class, () -> + lookup.lookup(key) + ); + assertTrue(ex.getMessage().contains("Error looking up file")); + } +} diff --git a/src/test/java/org/apache/commons/text/lookup/PropertiesStringLookupBoundaryTest.java b/src/test/java/org/apache/commons/text/lookup/PropertiesStringLookupBoundaryTest.java new file mode 100644 index 0000000000..3d9dc45064 --- /dev/null +++ b/src/test/java/org/apache/commons/text/lookup/PropertiesStringLookupBoundaryTest.java @@ -0,0 +1,80 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ + +package org.apache.commons.text.lookup; + +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Test; + +class PropertiesStringLookupBoundaryTest { + + private final PropertiesStringLookup lookup = new PropertiesStringLookup(); + + @Test + void testNullKeyReturnsNull() { + assertNull(lookup.lookup(null)); + } + + @Test + void testEmptyKeyThrowsException() { + IllegalArgumentException ex = assertThrows(IllegalArgumentException.class, () -> { + lookup.lookup(""); + }); + assertTrue(ex.getMessage().contains("Bad properties key format")); + } + + @Test + void testOnlyFileNameNoSeparatorThrowsException() { + String key = "document.properties"; // missing "::" + IllegalArgumentException ex = assertThrows(IllegalArgumentException.class, () -> { + lookup.lookup(key); + }); + assertTrue(ex.getMessage().contains("Bad properties key format")); + } + + @Test + void testOnlySeparatorThrowsException() { + String key = "::"; // edge case: just the separator, no actual data + IllegalArgumentException ex = assertThrows(IllegalArgumentException.class, () -> { + lookup.lookup(key); + }); + assertTrue(ex.getMessage().contains("Bad properties key format")); + } + + @Test + void testBadFormatMissingSeparatorThrowsException() { + String badKey = "justakey"; // No "::", so split will produce a length < 2 + + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { + PropertiesStringLookup.INSTANCE.lookup(badKey); + }); + + assertTrue(exception.getMessage().contains("Bad properties key format")); + } + + @Test + void testSeparatorAtStartThrowsException() { + String key = "::someKey"; // edge case: no file path before separator + Exception ex = assertThrows(IllegalArgumentException.class, () -> { + lookup.lookup(key); + }); + assertTrue(ex.getMessage().contains("Error looking up properties")); + } +} diff --git a/src/test/java/org/apache/commons/text/lookup/UrlStringLookupPartitionTest.java b/src/test/java/org/apache/commons/text/lookup/UrlStringLookupPartitionTest.java new file mode 100644 index 0000000000..93e37e6519 --- /dev/null +++ b/src/test/java/org/apache/commons/text/lookup/UrlStringLookupPartitionTest.java @@ -0,0 +1,62 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache license, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + */ + +package org.apache.commons.text.lookup; + +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.junit.jupiter.api.Test; + +public class UrlStringLookupPartitionTest { + private final UrlStringLookup lookup = UrlStringLookup.INSTANCE; + + // partition: null case + @Test + void testNullKeyReturnsNull() { + assertNull(lookup.lookup(null)); + } + + // partition: bad key format + @Test + void testMalformedKeyThrowsException() { + Exception e = assertThrows(IllegalArgumentException.class, () -> { + lookup.lookup("UTF-8Only"); // No ':' present + }); + assertTrue(e.getMessage().contains("Bad URL key format")); + } + + // partition: wrong charset + @Test + void testInvalidCharsetThrowsException() { + Exception e = assertThrows(IllegalArgumentException.class, () -> { + lookup.lookup("INVALID_CHARSET:https://example.com"); + }); + assertTrue(e.getMessage().contains("Error looking up URL")); + } + + // partition: invalid url + @Test + void testInvalidUrlThrowsException() { + Exception e = assertThrows(IllegalArgumentException.class, () -> { + lookup.lookup("UTF-8:htt://invalid-url"); + }); + assertTrue(e.getMessage().contains("Error looking up URL")); + } + +} diff --git a/src/test/java/org/apache/commons/text/similarity/FuzzyScorePartitionTest.java b/src/test/java/org/apache/commons/text/similarity/FuzzyScorePartitionTest.java new file mode 100644 index 0000000000..9af1edefb9 --- /dev/null +++ b/src/test/java/org/apache/commons/text/similarity/FuzzyScorePartitionTest.java @@ -0,0 +1,83 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.text.similarity; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.util.Locale; + +import org.junit.jupiter.api.Test; + +public class FuzzyScorePartitionTest { + @Test + void testNullTermThrowsException() { + FuzzyScore fs = new FuzzyScore(Locale.ENGLISH); + assertThrows(IllegalArgumentException.class, () -> fs.fuzzyScore(null, "hello")); + } + + @Test + void testNullQueryThrowsException() { + FuzzyScore fs = new FuzzyScore(Locale.ENGLISH); + assertThrows(IllegalArgumentException.class, () -> fs.fuzzyScore("hello", null)); + } + + @Test + void testEmptyStrings() { + FuzzyScore fs = new FuzzyScore(Locale.ENGLISH); + assertEquals(0, fs.fuzzyScore("", "")); + } + + @Test + void testEmptyQuery() { + FuzzyScore fs = new FuzzyScore(Locale.ENGLISH); + assertEquals(0, fs.fuzzyScore("nonempty", "")); + } + + @Test + void testNoMatch() { + FuzzyScore fs = new FuzzyScore(Locale.ENGLISH); + assertEquals(0, fs.fuzzyScore("abc", "xyz")); + } + + @Test + void testNonConsecutiveMatch() { + FuzzyScore fs = new FuzzyScore(Locale.ENGLISH); + assertEquals(2, fs.fuzzyScore("abc", "ac")); // +1 for 'a', +1 for 'c' + } + + @Test + void testConsecutiveMatch() { + FuzzyScore fs = new FuzzyScore(Locale.ENGLISH); + assertEquals(7, fs.fuzzyScore("abcdef", "abc")); // +1, +1+2, +1+2 = 5 + } + + @Test + void testCaseInsensitiveMatch() { + FuzzyScore fs = new FuzzyScore(Locale.ENGLISH); + assertEquals(7, fs.fuzzyScore("ABCdef", "abc")); // same as lowercase + } + + @Test + void testRepeatedLetters() { + FuzzyScore fs = new FuzzyScore(Locale.ENGLISH); + // Only one 'a' and one 'n' are matched ? no consecutive bonus here + assertEquals(7, fs.fuzzyScore("banana", "ana")); // depends on match path + } + +} diff --git a/src/test/java/org/apache/commons/text/similarity/JaccardSimilarityBoundaryTest.java b/src/test/java/org/apache/commons/text/similarity/JaccardSimilarityBoundaryTest.java new file mode 100644 index 0000000000..57ced3bc5d --- /dev/null +++ b/src/test/java/org/apache/commons/text/similarity/JaccardSimilarityBoundaryTest.java @@ -0,0 +1,88 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.text.similarity; + +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertEquals; + + +import org.junit.jupiter.api.Test; + +public class JaccardSimilarityBoundaryTest { + + private final JaccardSimilarity jaccard = new JaccardSimilarity(); + + // --- Null cases --- + @Test + public void testLeftNullThrowsException() { + assertThrows(IllegalArgumentException.class, () -> jaccard.apply(null, "abc")); + } + + @Test + public void testRightNullThrowsException() { + assertThrows(IllegalArgumentException.class, () -> jaccard.apply("abc", null)); + } + + @Test + public void testBothNullThrowsException() { + assertThrows(IllegalArgumentException.class, () -> jaccard.apply((CharSequence) null, (CharSequence) null)); + } + + // --- Empty strings --- + @Test + public void testBothEmptyStringsReturnsOne() { + assertEquals(1.0, jaccard.apply("", ""), 0.00001); + } + + @Test + public void testOneEmptyOneNonEmptyReturnsZero() { + assertEquals(0.0, jaccard.apply("", "abc"), 0.00001); + assertEquals(0.0, jaccard.apply("abc", ""), 0.00001); + } + + // --- Single character --- + @Test + public void testSingleCharacterMatchReturnsOne() { + assertEquals(1.0, jaccard.apply("a", "a"), 0.00001); + } + + @Test + public void testSingleCharacterMismatchReturnsZero() { + assertEquals(0.0, jaccard.apply("a", "b"), 0.00001); + } + + // --- Identical multi-char strings --- + @Test + public void testIdenticalStringsReturnsOne() { + assertEquals(1.0, jaccard.apply("hello", "hello"), 0.00001); + } + + // --- No shared characters --- + @Test + public void testNoOverlapReturnsZero() { + assertEquals(0.0, jaccard.apply("abc", "xyz"), 0.00001); + } + + // --- Partial overlap --- + @Test + public void testPartialOverlap() { + // "abc" vs "bcd" -> intersection = {b, c}, union = {a, b, c, d} -> 2/4 = 0.5 + assertEquals(0.5, jaccard.apply("abc", "bcd"), 0.00001); + } +} + diff --git a/src/test/java/org/apache/commons/text/translate/CodePointTranslatorPartitionTest.java b/src/test/java/org/apache/commons/text/translate/CodePointTranslatorPartitionTest.java new file mode 100644 index 0000000000..5c505e9571 --- /dev/null +++ b/src/test/java/org/apache/commons/text/translate/CodePointTranslatorPartitionTest.java @@ -0,0 +1,96 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.text.translate; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.io.IOException; +import java.io.StringWriter; +import java.io.Writer; + +import org.junit.jupiter.api.Test; + +public class CodePointTranslatorPartitionTest { + + // A simple implementation of CodePointTranslator: + // Translates lowercase ASCII letters to uppercase, ignores everything else + static class UppercaseOnlyTranslator extends CodePointTranslator { + @Override + public boolean translate(int codePoint, Writer writer) throws IOException { + if (Character.isLowerCase(codePoint)) { + writer.write(Character.toUpperCase(codePoint)); + return true; + } + return false; + } + } + + @Test + void testLowercaseAsciiTranslates() throws IOException { + CodePointTranslator translator = new UppercaseOnlyTranslator(); + StringWriter writer = new StringWriter(); + int consumed = translator.translate("a", 0, writer); + + assertEquals("A", writer.toString()); + assertEquals(1, consumed); + } + + @Test + void testUppercaseAsciiDoesNotTranslate() throws IOException { + CodePointTranslator translator = new UppercaseOnlyTranslator(); + StringWriter writer = new StringWriter(); + int consumed = translator.translate("A", 0, writer); + + assertEquals("", writer.toString()); + assertEquals(0, consumed); + } + + @Test + void testDigitDoesNotTranslate() throws IOException { + CodePointTranslator translator = new UppercaseOnlyTranslator(); + StringWriter writer = new StringWriter(); + int consumed = translator.translate("5", 0, writer); + + assertEquals("", writer.toString()); + assertEquals(0, consumed); + } + + @Test + void testUnicodeEmojiDoesNotTranslate() throws IOException { + CodePointTranslator translator = new UppercaseOnlyTranslator(); + String input = "\uD83D\uDE00"; // ? emoji + StringWriter writer = new StringWriter(); + + int consumed = translator.translate(input, 0, writer); + + assertEquals("", writer.toString()); + assertEquals(0, consumed); + } + + // Edge case: empty input + // Should throw IndexOutOfBoundsException due to no character at index 0 + @Test + void testEmptyInputThrowsException() { + CodePointTranslator translator = new UppercaseOnlyTranslator(); + String input = ""; + StringWriter writer = new StringWriter(); + + assertThrows(IndexOutOfBoundsException.class, () -> translator.translate(input, 0, writer)); + } +} diff --git a/src/test/java/org/apache/commons/text/translate/LookupTranslatorPartitionTest.java b/src/test/java/org/apache/commons/text/translate/LookupTranslatorPartitionTest.java new file mode 100644 index 0000000000..92c1e4d30f --- /dev/null +++ b/src/test/java/org/apache/commons/text/translate/LookupTranslatorPartitionTest.java @@ -0,0 +1,119 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.text.translate; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.io.StringWriter; +import java.util.HashMap; +import java.util.Map; + +import org.junit.jupiter.api.Test; + +public class LookupTranslatorPartitionTest { + private final LookupTranslator translator; + + { + Map map = new HashMap<>(); + map.put("cat", "feline"); + map.put("dog", "canine"); + map.put("do", "perform"); + translator = new LookupTranslator(map); + } + + // -------------------------- + // EQUIVALENCE PARTITION TESTS + // -------------------------- + + @Test + void testExactMatchFullKey() throws Exception { + // Input matches full key "cat" + StringWriter writer = new StringWriter(); + int consumed = translator.translate("cat", 0, writer); + assertEquals("feline", writer.toString()); + assertEquals(3, consumed); // three codepoints + } + + @Test + void testNoMatchWrongPrefix() throws Exception { + // "x" is not a prefix of any key + StringWriter writer = new StringWriter(); + int consumed = translator.translate("xylophone", 0, writer); + assertEquals("", writer.toString()); + assertEquals(0, consumed); + } + + @Test + void testPrefixMatchButNotFullKey() throws Exception { + // "d" is a prefix of "dog" and "do", but "d" alone isn't a key + StringWriter writer = new StringWriter(); + int consumed = translator.translate("d", 0, writer); + assertEquals("", writer.toString()); + assertEquals(0, consumed); + } + + @Test + void testGreedyMatchPrefersLongestKey() throws Exception { + // "dog" and "do" both match ? should pick "dog" due to greedy strategy + StringWriter writer = new StringWriter(); + int consumed = translator.translate("dogma", 0, writer); + assertEquals("canine", writer.toString()); + assertEquals(3, consumed); // "dog" is three Unicode codepoint sequence + } + + // -------------------------- + // BOUNDARY VALUE TESTS + // -------------------------- + + @Test + void testInputShorterThanShortestKey() throws Exception { + // "c" is shorter than the shortest key "do" (length 2) + StringWriter writer = new StringWriter(); + int consumed = translator.translate("c", 0, writer); + assertEquals("", writer.toString()); + assertEquals(0, consumed); + } + + @Test + void testMatchAtEndOfString() throws Exception { + // "dog" is at the very end of the input + StringWriter writer = new StringWriter(); + int consumed = translator.translate("gooddog", 4, writer); + assertEquals("canine", writer.toString()); + assertEquals(3, consumed); + } + + @Test + void testInputEqualToLongestKey() throws Exception { + // "cat" is one of the keys, matches exactly + StringWriter writer = new StringWriter(); + int consumed = translator.translate("cat", 0, writer); + assertEquals("feline", writer.toString()); + assertEquals(3, consumed); + } + + @Test + void testIndexPlusLongestEqualsInputLength() throws Exception { + // longest = 3, input length = 7, index = 4 + // substring from 4 to 7 should match "dog" + StringWriter writer = new StringWriter(); + int consumed = translator.translate("bigdogdog", 6, writer); + assertEquals("canine", writer.toString()); + assertEquals(3, consumed); + } +}