blob: e6fe415b98fd6cacdd62c55815a342c49b4cd418 [file]
/*
* 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
*
* https://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.codec.language;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.util.HashSet;
import java.util.Locale;
import java.util.Set;
import java.util.stream.Stream;
import org.apache.commons.codec.AbstractStringEncoderTest;
import org.apache.commons.codec.EncoderException;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.opentest4j.AssertionFailedError;
/**
* Tests the {@link ColognePhonetic} class.
*
* <p>
* Keep this file in UTF-8 encoding for proper Javadoc processing.
* </p>
*/
class ColognePhoneticTest extends AbstractStringEncoderTest<ColognePhonetic> {
private static final Set<String> TESTSET = new HashSet<>();
/** Character sequences to be tested by the code. */
// @formatter:off
private static final String[] MATCHES = {
".*[AEIOUJY].*", // A, E, I, J, O, U, Y
".*H.*", // H
".*B.*", // B
".*P[^H].*", // P not before H
".*[DT][^CSZ].*", // D,T not before C,S,Z
".*[FVW].*", // F,V,W
".*PH.*", // P before H
".*[GKQ].*", // G,K,Q
"C[AHKLOQRUX].*", // Initial C before A, H, K, L, O, Q, R, U, X
".*[^SZ]C[AHKLOQRUX].*", // C before A, H, K, L, O, Q, R, U, X but not after S, Z
".*[^CKQ]X.*", // X not after C,K,Q
".*L.*", // L
".*[MN].*", // M,N
".*R.*", // R
".*[SZ].*", // S,Z
".*[SZ]C.*", // C after S,Z
"C[^AHKLOQRUX].*", // Initial C except before A, H, K, L, O, Q, R, U, X
".+C[^AHKLOQRUX].*", // C except before A, H, K, L, O, Q, R, U, X
".*[DT][CSZ].*", // D,T before C,S,Z
".*[CKQ]X.*", // X after C,K,Q
// @formatter:on
};
@AfterAll
// Check that all possible input sequence conditions are represented
static void finishTests() {
int errors = 0;
for (final String m : MATCHES) {
if (!hasTestCase(m)) {
System.out.println(m + " has no test case");
errors++;
}
}
assertEquals(0, errors, "Not expecting any missing test cases");
}
private static boolean hasTestCase(final String re) {
for (final String s : TESTSET) {
if (s.matches(re)) {
return true;
}
}
return false;
}
// Allow command-line testing
public static void main(final String[] args) {
final ColognePhonetic coder = new ColognePhonetic();
for (final String arg : args) {
final String code = coder.encode(arg);
System.out.println("'" + arg + "' = '" + code + "'");
}
}
static Stream<Arguments> testBasicEncoding() {
// @formatter:off
return Stream.of(
Arguments.arguments("01", "Aabjoe"),
Arguments.arguments("0856", "Aaclan"),
Arguments.arguments("04567", "Aychlmajr") // CODEC-122
);
// @formatter:on
}
static Stream<Arguments> testEdgeCases() {
// @formatter:off
return Stream.of(
Arguments.arguments("a", "0"),
Arguments.arguments("e", "0"),
Arguments.arguments("i", "0"),
Arguments.arguments("o", "0"),
Arguments.arguments("u", "0"),
Arguments.arguments("\u00E4", "0"), // a-umlaut
Arguments.arguments("\u00F6", "0"), // o-umlaut
Arguments.arguments("\u00FC", "0"), // u-umlaut
Arguments.arguments("\u00DF", "8"), // small sharp s
Arguments.arguments("aa", "0"),
Arguments.arguments("ha", "0"),
Arguments.arguments("h", ""),
Arguments.arguments("aha", "0"),
Arguments.arguments("b", "1"),
Arguments.arguments("p", "1"),
Arguments.arguments("ph", "3"),
Arguments.arguments("f", "3"),
Arguments.arguments("v", "3"),
Arguments.arguments("w", "3"),
Arguments.arguments("g", "4"),
Arguments.arguments("k", "4"),
Arguments.arguments("q", "4"),
Arguments.arguments("x", "48"),
Arguments.arguments("ax", "048"),
Arguments.arguments("cx", "48"),
Arguments.arguments("l", "5"),
Arguments.arguments("cl", "45"),
Arguments.arguments("acl", "085"),
Arguments.arguments("mn", "6"),
Arguments.arguments("{mn}", "6"), // test chars above Z
Arguments.arguments("r", "7")
);
// @formatter:on
}
static Stream<Arguments> testExamples() {
// @formatter:off
return Stream.of(
Arguments.arguments("m\u00DCller", "657"), // mÜller - why upper case U-umlaut?
Arguments.arguments("m\u00FCller", "657"), // müller - add equivalent lower-case
Arguments.arguments("schmidt", "862"),
Arguments.arguments("schneider", "8627"),
Arguments.arguments("fischer", "387"),
Arguments.arguments("weber", "317"),
Arguments.arguments("wagner", "3467"),
Arguments.arguments("becker", "147"),
Arguments.arguments("hoffmann", "036"),
Arguments.arguments("sch\u00C4fer", "837"), // schÄfer - why upper case A-umlaut ?
Arguments.arguments("sch\u00e4fer", "837"), // schäfer - add equivalent lower-case
Arguments.arguments("Breschnew", "17863"),
Arguments.arguments("Wikipedia", "3412"),
Arguments.arguments("peter", "127"),
Arguments.arguments("pharma", "376"),
Arguments.arguments("m\u00f6nchengladbach", "64645214"), // mönchengladbach
Arguments.arguments("deutsch", "28"),
Arguments.arguments("deutz", "28"),
Arguments.arguments("hamburg", "06174"),
Arguments.arguments("hannover", "0637"),
Arguments.arguments("christstollen", "478256"),
Arguments.arguments("Xanthippe", "48621"),
Arguments.arguments("Zacharias", "8478"),
Arguments.arguments("Holzbau", "0581"),
Arguments.arguments("matsch", "68"),
Arguments.arguments("matz", "68"),
Arguments.arguments("Arbeitsamt", "071862"),
Arguments.arguments("Eberhard", "0172"),
Arguments.arguments("Eberhardt", "0172"),
Arguments.arguments("Celsius", "858"),
Arguments.arguments("Ace", "08"),
Arguments.arguments("shch", "84"), // CODEC-254
Arguments.arguments("xch", "484"), // CODEC-255
Arguments.arguments("heithabu", "021")
);
// @formatter:on
}
static Stream<Arguments> testIsEncodeEquals() {
// @formatter:off
return Stream.of(
Arguments.arguments("Muller", "M\u00fcller"), // Müller
Arguments.arguments("Meyer", "Mayr"),
Arguments.arguments("house", "house"),
Arguments.arguments("House", "house"),
Arguments.arguments("Haus", "house"),
Arguments.arguments("ganz", "Gans"),
Arguments.arguments("ganz", "G\u00e4nse"), // Gänse
Arguments.arguments("Miyagi", "Miyako")
);
// @formatter:on
}
@Override
// Capture test strings for later checking
public void checkEncoding(final String expected, final String source) throws EncoderException {
// Note that the German letter Eszett is converted to SS by toUpperCase, so we don't need to replace it
TESTSET.add(source.toUpperCase(Locale.GERMAN).replace('Ä', 'A').replace('Ö', 'O').replace('Ü', 'U'));
super.checkEncoding(expected, source);
}
@Override
protected ColognePhonetic createStringEncoder() {
return new ColognePhonetic();
}
@ParameterizedTest
@MethodSource
void testBasicEncoding(final String expected, final String source) throws EncoderException {
checkEncoding(expected, source);
}
@Test
// Ensure that override still allows tests to work
void testCanFail() {
assertThrows(AssertionFailedError.class, () -> checkEncoding("/", "Fehler"));
}
@ParameterizedTest
@MethodSource
void testEdgeCases(final String source, final String expected) throws EncoderException {
checkEncoding(expected, source);
}
@ParameterizedTest
@MethodSource
void testExamples(final String source, final String expected) throws EncoderException {
checkEncoding(expected, source);
}
@Test
void testHyphen() throws EncoderException {
// Müller-Lüdenscheidt
checkEncodings(new String[][] { { "bergisch-gladbach", "174845214" }, { "M\u00fcller-L\u00fcdenscheidt", "65752682" } });
}
@ParameterizedTest
@MethodSource
void testIsEncodeEquals(final String source, final String expected) {
final boolean encodeEqual = getStringEncoder().isEncodeEqual(expected, source);
assertTrue(encodeEqual, () -> expected + " != " + source);
}
@Test
void testSpecialCharsBetweenSameLetters() throws EncoderException {
checkEncodingVariations("28282", "Test test", "Testtest", "Test-test", "TesT#Test", "TesT?test");
}
@Test
void testVariationsMella() throws EncoderException {
checkEncodingVariations("65", "mella", "milah", "moulla", "mellah", "muehle", "mule");
}
@Test
void testVariationsMeyer() throws EncoderException {
checkEncodingVariations("67", "Meier", "Maier", "Mair", "Meyer", "Meyr", "Mejer", "Major");
}
}