| /* |
| * 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. |
| */ |
| |
| // (FYI: Formatted and sorted with Eclipse) |
| |
| package org.apache.commons.codec.language; |
| |
| import static org.junit.jupiter.api.Assertions.assertEquals; |
| import static org.junit.jupiter.api.Assertions.assertNull; |
| import static org.junit.jupiter.api.Assertions.assertThrows; |
| |
| import org.apache.commons.codec.AbstractStringEncoderTest; |
| import org.apache.commons.codec.EncoderException; |
| import org.junit.jupiter.api.Test; |
| |
| /** |
| * Tests {@link Soundex}. |
| * |
| * <p>Keep this file in UTF-8 encoding for proper Javadoc processing.</p> |
| */ |
| class SoundexTest extends AbstractStringEncoderTest<Soundex> { |
| |
| @Override |
| protected Soundex createStringEncoder() { |
| return new Soundex(); |
| } |
| |
| @Test |
| void testB650() throws EncoderException { |
| // @formatter:off |
| checkEncodingVariations("B650", |
| "BARHAM", |
| "BARONE", |
| "BARRON", |
| "BERNA", |
| "BIRNEY", |
| "BIRNIE", |
| "BOOROM", |
| "BOREN", |
| "BORN", |
| "BOURN", |
| "BOURNE", |
| "BOWRON", |
| "BRAIN", |
| "BRAME", |
| "BRANN", |
| "BRAUN", |
| "BREEN", |
| "BRIEN", |
| "BRIM", |
| "BRIMM", |
| "BRINN", |
| "BRION", |
| "BROOM", |
| "BROOME", |
| "BROWN", |
| "BROWNE", |
| "BRUEN", |
| "BRUHN", |
| "BRUIN", |
| "BRUMM", |
| "BRUN", |
| "BRUNO", |
| "BRYAN", |
| "BURIAN", |
| "BURN", |
| "BURNEY", |
| "BYRAM", |
| "BYRNE", |
| "BYRON", |
| "BYRUM"); |
| // @formatter:on |
| } |
| |
| @Test |
| void testBadCharacters() { |
| assertEquals("H452", getStringEncoder().encode("HOL>MES")); |
| } |
| |
| @Test |
| void testDifference() throws EncoderException { |
| // Edge cases |
| assertEquals(0, getStringEncoder().difference(null, null)); |
| assertEquals(0, getStringEncoder().difference("", "")); |
| assertEquals(0, getStringEncoder().difference(" ", " ")); |
| // Normal cases |
| assertEquals(4, getStringEncoder().difference("Smith", "Smythe")); |
| assertEquals(2, getStringEncoder().difference("Ann", "Andrew")); |
| assertEquals(1, getStringEncoder().difference("Margaret", "Andrew")); |
| assertEquals(0, getStringEncoder().difference("Janet", "Margaret")); |
| // Examples from https://msdn.microsoft.com/library/default.asp?url=/library/en-us/tsqlref/ts_de-dz_8co5.asp |
| assertEquals(4, getStringEncoder().difference("Green", "Greene")); |
| assertEquals(0, getStringEncoder().difference("Blotchet-Halls", "Greene")); |
| // Examples from https://msdn.microsoft.com/library/default.asp?url=/library/en-us/tsqlref/ts_setu-sus_3o6w.asp |
| assertEquals(4, getStringEncoder().difference("Smith", "Smythe")); |
| assertEquals(4, getStringEncoder().difference("Smithers", "Smythers")); |
| assertEquals(2, getStringEncoder().difference("Anothers", "Brothers")); |
| } |
| |
| @Test |
| void testEncodeBasic() { |
| assertEquals("T235", getStringEncoder().encode("testing")); |
| assertEquals("T000", getStringEncoder().encode("The")); |
| assertEquals("Q200", getStringEncoder().encode("quick")); |
| assertEquals("B650", getStringEncoder().encode("brown")); |
| assertEquals("F200", getStringEncoder().encode("fox")); |
| assertEquals("J513", getStringEncoder().encode("jumped")); |
| assertEquals("O160", getStringEncoder().encode("over")); |
| assertEquals("T000", getStringEncoder().encode("the")); |
| assertEquals("L200", getStringEncoder().encode("lazy")); |
| assertEquals("D200", getStringEncoder().encode("dogs")); |
| } |
| |
| /** |
| * Examples from http://www.bradandkathy.com/genealogy/overviewofsoundex.html |
| */ |
| @Test |
| void testEncodeBatch2() { |
| assertEquals("A462", getStringEncoder().encode("Allricht")); |
| assertEquals("E166", getStringEncoder().encode("Eberhard")); |
| assertEquals("E521", getStringEncoder().encode("Engebrethson")); |
| assertEquals("H512", getStringEncoder().encode("Heimbach")); |
| assertEquals("H524", getStringEncoder().encode("Hanselmann")); |
| assertEquals("H431", getStringEncoder().encode("Hildebrand")); |
| assertEquals("K152", getStringEncoder().encode("Kavanagh")); |
| assertEquals("L530", getStringEncoder().encode("Lind")); |
| assertEquals("L222", getStringEncoder().encode("Lukaschowsky")); |
| assertEquals("M235", getStringEncoder().encode("McDonnell")); |
| assertEquals("M200", getStringEncoder().encode("McGee")); |
| assertEquals("O155", getStringEncoder().encode("Opnian")); |
| assertEquals("O155", getStringEncoder().encode("Oppenheimer")); |
| assertEquals("R355", getStringEncoder().encode("Riedemanas")); |
| assertEquals("Z300", getStringEncoder().encode("Zita")); |
| assertEquals("Z325", getStringEncoder().encode("Zitzmeinn")); |
| } |
| |
| /** |
| * Examples from http://www.archives.gov/research_room/genealogy/census/soundex.html |
| */ |
| @Test |
| void testEncodeBatch3() { |
| assertEquals("W252", getStringEncoder().encode("Washington")); |
| assertEquals("L000", getStringEncoder().encode("Lee")); |
| assertEquals("G362", getStringEncoder().encode("Gutierrez")); |
| assertEquals("P236", getStringEncoder().encode("Pfister")); |
| assertEquals("J250", getStringEncoder().encode("Jackson")); |
| assertEquals("T522", getStringEncoder().encode("Tymczak")); |
| // For VanDeusen: D-250 (D, 2 for the S, 5 for the N, 0 added) is also |
| // possible. |
| assertEquals("V532", getStringEncoder().encode("VanDeusen")); |
| } |
| |
| /** |
| * Examples from: http://www.myatt.demon.co.uk/sxalg.htm |
| */ |
| @Test |
| void testEncodeBatch4() { |
| assertEquals("H452", getStringEncoder().encode("HOLMES")); |
| assertEquals("A355", getStringEncoder().encode("ADOMOMI")); |
| assertEquals("V536", getStringEncoder().encode("VONDERLEHR")); |
| assertEquals("B400", getStringEncoder().encode("BALL")); |
| assertEquals("S000", getStringEncoder().encode("SHAW")); |
| assertEquals("J250", getStringEncoder().encode("JACKSON")); |
| assertEquals("S545", getStringEncoder().encode("SCANLON")); |
| assertEquals("S532", getStringEncoder().encode("SAINTJOHN")); |
| |
| } |
| |
| @Test |
| void testEncodeIgnoreApostrophes() throws EncoderException { |
| // @formatter:off |
| checkEncodingVariations("O165", |
| "OBrien", |
| "'OBrien", |
| "O'Brien", |
| "OB'rien", |
| "OBr'ien", |
| "OBri'en", |
| "OBrie'n", |
| "OBrien'"); |
| // @formatter:on |
| } |
| |
| /** |
| * Test data from http://www.myatt.demon.co.uk/sxalg.htm |
| * |
| * @throws EncoderException for some failure scenarios */ |
| @Test |
| void testEncodeIgnoreHyphens() throws EncoderException { |
| // @formatter:off |
| checkEncodingVariations("K525", |
| "KINGSMITH", |
| "-KINGSMITH", |
| "K-INGSMITH", |
| "KI-NGSMITH", |
| "KIN-GSMITH", |
| "KING-SMITH", |
| "KINGS-MITH", |
| "KINGSM-ITH", |
| "KINGSMI-TH", |
| "KINGSMIT-H", |
| "KINGSMITH-"); |
| // @formatter:on |
| } |
| |
| @Test |
| void testEncodeIgnoreTrimmable() { |
| assertEquals("W252", getStringEncoder().encode(" \t\n\r Washington \t\n\r ")); |
| } |
| |
| @Test |
| // examples and algorithm rules from: http://www.genealogy.com/articles/research/00000060.html |
| void testGenealogy() { // treat vowels and HW as silent |
| final Soundex s = Soundex.US_ENGLISH_GENEALOGY; |
| assertEquals("H251", s.encode("Heggenburger")); |
| assertEquals("B425", s.encode("Blackman")); |
| assertEquals("S530", s.encode("Schmidt")); |
| assertEquals("L150", s.encode("Lippmann")); |
| // Additional local example |
| assertEquals("D200", s.encode("Dodds")); // 'o' is not a separator here - it is silent |
| assertEquals("D200", s.encode("Dhdds")); // 'h' is silent |
| assertEquals("D200", s.encode("Dwdds")); // 'w' is silent |
| } |
| |
| /** |
| * Consonants from the same code group separated by W or H are treated as one. |
| */ |
| @Test |
| void testHWRuleEx1() { |
| // From |
| // http://www.archives.gov/research_room/genealogy/census/soundex.html: |
| // Ashcraft is coded A-261 (A, 2 for the S, C ignored, 6 for the R, 1 |
| // for the F). It is not coded A-226. |
| assertEquals("A261", getStringEncoder().encode("Ashcraft")); |
| assertEquals("A261", getStringEncoder().encode("Ashcroft")); |
| assertEquals("Y330", getStringEncoder().encode("yehudit")); |
| assertEquals("Y330", getStringEncoder().encode("yhwdyt")); |
| } |
| |
| /** |
| * Consonants from the same code group separated by W or H are treated as one. |
| * |
| * Test data from http://www.myatt.demon.co.uk/sxalg.htm |
| */ |
| @Test |
| void testHWRuleEx2() { |
| assertEquals("B312", getStringEncoder().encode("BOOTHDAVIS")); |
| assertEquals("B312", getStringEncoder().encode("BOOTH-DAVIS")); |
| } |
| |
| /** |
| * Consonants from the same code group separated by W or H are treated as one. |
| * |
| * @throws EncoderException for some failure scenarios */ |
| @Test |
| void testHWRuleEx3() throws EncoderException { |
| assertEquals("S460", getStringEncoder().encode("Sgler")); |
| assertEquals("S460", getStringEncoder().encode("Swhgler")); |
| // Also S460: |
| // @formatter:off |
| checkEncodingVariations("S460", |
| "SAILOR", |
| "SALYER", |
| "SAYLOR", |
| "SCHALLER", |
| "SCHELLER", |
| "SCHILLER", |
| "SCHOOLER", |
| "SCHULER", |
| "SCHUYLER", |
| "SEILER", |
| "SEYLER", |
| "SHOLAR", |
| "SHULER", |
| "SILAR", |
| "SILER", |
| "SILLER"); |
| // @formatter:on |
| } |
| |
| /** |
| * Examples for MS SQLServer from |
| * https://msdn.microsoft.com/library/default.asp?url=/library/en-us/tsqlref/ts_setu-sus_3o6w.asp |
| */ |
| @Test |
| void testMsSqlServer1() { |
| assertEquals("S530", getStringEncoder().encode("Smith")); |
| assertEquals("S530", getStringEncoder().encode("Smythe")); |
| } |
| |
| /** |
| * Examples for MS SQLServer from |
| * https://support.microsoft.com/default.aspx?scid=https://support.microsoft.com:80/support |
| * /kb/articles/Q100/3/65.asp&NoWebContent=1 |
| * |
| * @throws EncoderException for some failure scenarios */ |
| @Test |
| void testMsSqlServer2() throws EncoderException { |
| checkEncodingVariations("E625", "Erickson", "Erickson", "Erikson", "Ericson", "Ericksen", "Ericsen"); |
| } |
| |
| /** |
| * Examples for MS SQLServer from https://databases.about.com/library/weekly/aa042901a.htm |
| */ |
| @Test |
| void testMsSqlServer3() { |
| assertEquals("A500", getStringEncoder().encode("Ann")); |
| assertEquals("A536", getStringEncoder().encode("Andrew")); |
| assertEquals("J530", getStringEncoder().encode("Janet")); |
| assertEquals("M626", getStringEncoder().encode("Margaret")); |
| assertEquals("S315", getStringEncoder().encode("Steven")); |
| assertEquals("M240", getStringEncoder().encode("Michael")); |
| assertEquals("R163", getStringEncoder().encode("Robert")); |
| assertEquals("L600", getStringEncoder().encode("Laura")); |
| assertEquals("A500", getStringEncoder().encode("Anne")); |
| } |
| |
| /** |
| * https://issues.apache.org/jira/browse/CODEC-54 https://issues.apache.org/jira/browse/CODEC-56 |
| */ |
| @Test |
| void testNewInstance() { |
| assertEquals("W452", new Soundex().soundex("Williams")); |
| } |
| |
| @Test |
| void testNewInstance2() { |
| assertEquals("W452", new Soundex(Soundex.US_ENGLISH_MAPPING_STRING.toCharArray()).soundex("Williams")); |
| } |
| |
| @Test |
| void testNewInstance3() { |
| assertEquals("W452", new Soundex(Soundex.US_ENGLISH_MAPPING_STRING).soundex("Williams")); |
| } |
| |
| @Test |
| // examples and algorithm rules from: http://west-penwith.org.uk/misc/soundex.htm |
| void testSimplifiedSoundex() { // treat vowels and HW as separators |
| final Soundex s = Soundex.US_ENGLISH_SIMPLIFIED; |
| assertEquals("W452", s.encode("WILLIAMS")); |
| assertEquals("B625", s.encode("BARAGWANATH")); |
| assertEquals("D540", s.encode("DONNELL")); |
| assertEquals("L300", s.encode("LLOYD")); |
| assertEquals("W422", s.encode("WOOLCOCK")); |
| // Additional local examples |
| assertEquals("D320", s.encode("Dodds")); |
| assertEquals("D320", s.encode("Dwdds")); // w is a separator |
| assertEquals("D320", s.encode("Dhdds")); // h is a separator |
| } |
| |
| @Test |
| void testSoundexUtilsConstructable() { |
| new SoundexUtils(); |
| } |
| |
| @Test |
| void testSoundexUtilsNullBehaviour() { |
| assertNull(SoundexUtils.clean(null)); |
| assertEquals("", SoundexUtils.clean("")); |
| assertEquals(0, SoundexUtils.differenceEncoded(null, "")); |
| assertEquals(0, SoundexUtils.differenceEncoded("", null)); |
| } |
| |
| /** |
| * https://issues.apache.org/jira/browse/CODEC-54 https://issues.apache.org/jira/browse/CODEC-56 |
| */ |
| @Test |
| void testUsEnglishStatic() { |
| assertEquals("W452", Soundex.US_ENGLISH.soundex("Williams")); |
| } |
| |
| /** |
| * Fancy characters are not mapped by the default US mapping. |
| * |
| * https://issues.apache.org/jira/browse/CODEC-30 |
| */ |
| @Test |
| void testUsMappingEWithAcute() { |
| assertEquals("E000", getStringEncoder().encode("e")); |
| if (Character.isLetter('\u00e9')) { // e-acute |
| // uppercase E-acute |
| assertThrows(IllegalArgumentException.class, () -> getStringEncoder().encode("\u00e9")); |
| } else { |
| assertEquals("", getStringEncoder().encode("\u00e9")); |
| } |
| } |
| |
| /** |
| * Fancy characters are not mapped by the default US mapping. |
| * |
| * https://issues.apache.org/jira/browse/CODEC-30 |
| */ |
| @Test |
| void testUsMappingOWithDiaeresis() { |
| assertEquals("O000", getStringEncoder().encode("o")); |
| if (Character.isLetter('\u00f6')) { // o-umlaut |
| // uppercase O-umlaut |
| assertThrows(IllegalArgumentException.class, () -> getStringEncoder().encode("\u00f6")); |
| } else { |
| assertEquals("", getStringEncoder().encode("\u00f6")); |
| } |
| } |
| |
| /** |
| * Tests example from https://en.wikipedia.org/wiki/Soundex#American_Soundex as of 2015-03-22. |
| */ |
| @Test |
| void testWikipediaAmericanSoundex() { |
| assertEquals("R163", getStringEncoder().encode("Robert")); |
| assertEquals("R163", getStringEncoder().encode("Rupert")); |
| assertEquals("A261", getStringEncoder().encode("Ashcraft")); |
| assertEquals("A261", getStringEncoder().encode("Ashcroft")); |
| assertEquals("T522", getStringEncoder().encode("Tymczak")); |
| assertEquals("P236", getStringEncoder().encode("Pfister")); |
| } |
| } |