/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at * trunk/opends/resource/legal-notices/OpenDS.LICENSE * or https://OpenDS.dev.java.net/OpenDS.LICENSE. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, * add the following below this CDDL HEADER, with the fields enclosed * by brackets "[]" replaced with your own identifying information: * Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * * Copyright 2008 Sun Microsystems, Inc. */ package org.opends.server.util; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import static org.testng.Assert.*; /** * A set of generic test cases for the Levenshtein distance class. */ public class LevenshteinDistanceTestCase extends UtilTestCase { /** * Retrieves a set of data that may be used to test the Levenshtein distance * implementation. Each element of the array returned will itself be an * array whose elements are a source string, a target string, and the * expected Levenshtein distance. * * @return A set of data that may be used to test the Levenshtein distance * implementation. */ @DataProvider(name = "teststrings") public Object[][] getTestStrings() { return new Object[][] { // When the values are the same, the distance is zero. new Object[] { "", "", 0 }, new Object[] { "1", "1", 0 }, new Object[] { "12", "12", 0 }, new Object[] { "123", "123", 0 }, new Object[] { "1234", "1234", 0 }, new Object[] { "12345", "12345", 0 }, new Object[] { "password", "password", 0 }, // When one of the values is empty, the distance is the length of the // other value. new Object[] { "", "1", 1 }, new Object[] { "", "12", 2 }, new Object[] { "", "123", 3 }, new Object[] { "", "1234", 4 }, new Object[] { "", "12345", 5 }, new Object[] { "", "password", 8 }, new Object[] { "1", "", 1 }, new Object[] { "12", "", 2 }, new Object[] { "123", "", 3 }, new Object[] { "1234", "", 4 }, new Object[] { "12345", "", 5 }, new Object[] { "password", "", 8 }, // Whenever a single character is inserted or removed, the distance is // one. new Object[] { "password", "1password", 1 }, new Object[] { "password", "p1assword", 1 }, new Object[] { "password", "pa1ssword", 1 }, new Object[] { "password", "pas1sword", 1 }, new Object[] { "password", "pass1word", 1 }, new Object[] { "password", "passw1ord", 1 }, new Object[] { "password", "passwo1rd", 1 }, new Object[] { "password", "passwor1d", 1 }, new Object[] { "password", "password1", 1 }, new Object[] { "password", "assword", 1 }, new Object[] { "password", "pssword", 1 }, new Object[] { "password", "pasword", 1 }, new Object[] { "password", "pasword", 1 }, new Object[] { "password", "passord", 1 }, new Object[] { "password", "passwrd", 1 }, new Object[] { "password", "passwod", 1 }, new Object[] { "password", "passwor", 1 }, // Whenever a single character is replaced, the distance is one. new Object[] { "password", "Xassword", 1 }, new Object[] { "password", "pXssword", 1 }, new Object[] { "password", "paXsword", 1 }, new Object[] { "password", "pasXword", 1 }, new Object[] { "password", "passXord", 1 }, new Object[] { "password", "passwXrd", 1 }, new Object[] { "password", "passwoXd", 1 }, new Object[] { "password", "passworX", 1 }, // If characters are taken off the front and added to the back and all of // the characters are unique, then the distance is two times the number of // characters shifted, until you get halfway (and then it becomes easier // to shift from the other direction). new Object[] { "12345678", "23456781", 2 }, new Object[] { "12345678", "34567812", 4 }, new Object[] { "12345678", "45678123", 6 }, new Object[] { "12345678", "56781234", 8 }, new Object[] { "12345678", "67812345", 6 }, new Object[] { "12345678", "78123456", 4 }, new Object[] { "12345678", "81234567", 2 }, // If all the characters are unique and the values are reversed, then the // distance is the number of characters for an even number of characters, // and one less for an odd number of characters (since the middle // character will stay the same). new Object[] { "12", "21", 2 }, new Object[] { "123", "321", 2 }, new Object[] { "1234", "4321", 4 }, new Object[] { "12345", "54321", 4 }, new Object[] { "123456", "654321", 6 }, new Object[] { "1234567", "7654321", 6 }, new Object[] { "12345678", "87654321", 8 }, // The rest of these are miscellaneous interesting examples. They will // be illustrated using the following key: // = (the characters are equal) // + (the character is inserted) // - (the character is removed) // # (the character is replaced) // Mississippi // ippississiM // -=##====##=+ --> 6 new Object[] { "Mississippi", "ippississiM", 6 }, // eieio // oieie // #===# --> 2 new Object[] { "eieio", "oieie", 2 }, // brad+angelina // bra ngelina // ===+++======= --> 3 new Object[] { "brad+angelina", "brangelina", 3 }, // test international chars // ?e?uli?ka // e?uli?ka // -======== --> 1 new Object[] { "?e?uli?ka", "e?uli?ka", 1 }, }; } /** * Tests the {@code calculate} method with non-{@code null} String arguments. * * @param s The source string to compare. * @param t The target string to compare. * @param d The expected Levenshtein distance for the two strings. */ @Test(dataProvider = "teststrings") public void testCalculateStrings(String s, String t, int d) { assertEquals(LevenshteinDistance.calculate(s, t), d); } /** * Tests the {@code calculate} method with non-{@code null} String arguments * in reverse order to verify that they are order-independent. * * @param s The source string to compare. * @param t The target string to compare. * @param d The expected Levenshtein distance for the two strings. */ @Test(dataProvider = "teststrings") public void testCalculateStringsReversed(String s, String t, int d) { assertEquals(LevenshteinDistance.calculate(t, s), d); } /** * Retrieves a set of data that may be used to test the Levenshtein distance * implementation. Each element of the array returned will itself be an * array whose elements are a source string, a target string, and the * expected Levenshtein distance. * * @return A set of data that may be used to test the Levenshtein distance * implementation. */ @DataProvider(name = "testnulls") public Object[][] getTestNulls() { return new Object[][] { new Object[] { "notnull", null }, new Object[] { null, "notnull" }, new Object[] { null, null } }; } /** * Tests the {@code calculate} method with at least one {@code null} string. * * @param s The source string to compare. * @param t The target string to compare. */ @Test(dataProvider = "testnulls", expectedExceptions = { AssertionError.class }) public void testNullStrings(String s, String t) { LevenshteinDistance.calculate(s, t); } }