package com.limegroup.gnutella.util; import java.util.Iterator; import java.util.Locale; import java.util.NoSuchElementException; import junit.framework.Test; /** * Tests Trie. */ public class TrieTest extends com.limegroup.gnutella.util.BaseTestCase { public TrieTest(String name) { super(name); } public static Test suite() { return buildTestSuite(TrieTest.class); } private static Locale defaultLocale; private static Locale turkishLocale; public static void globalSetUp() { defaultLocale = Locale.getDefault(); turkishLocale = new Locale("tr"); // Turkish } // ensure we begin with a correct locale public void setUp() { Locale.setDefault(defaultLocale); } // ensure with end with a correct locale public void tearDown() { Locale.setDefault(defaultLocale); } private static final Object _Val = "value for _"; private static final Object aVal = "value for a"; private static final Object addVal = "value for add"; private static final Object anVal = "value for an"; private static final Object anVal0 = "another value for an"; private static final Object antVal = "value for ant"; private static final Object antVal0 = "another value for ant"; public void testBasic() throws Throwable { Locale.setDefault(defaultLocale); tTrie_Basic(); } public void testBasicInTurkish() throws Throwable { Locale.setDefault(turkishLocale); tTrie_Basic(); } // Basic Trie operations private void tTrie_Basic() throws Throwable { Trie t = new Trie(false); Iterator iter = null; Object tmp1 = null, tmp2 = null, tmp3 = null, tmp4 = null; //Note int Trie.match(String, int, int String) is private, call it //using the helper function assertEquals(-1, match(t, "abcde", 0, 5, "abc")); assertEquals(1, match(t, "abcde", 1, 5, "bXd")); assertEquals(2, match(t, "abcde", 1, 3, "bcd")); assertNull(t.get("a")); // additive insert assertNull(t.add("ant", antVal0)); //System.out.println(t.toString()); // splice insert assertNull(t.add("an", anVal)); //System.out.println(t.toString()); // split insert assertNull(t.add("add", addVal)); //System.out.println(t.toString()); // relabel insert (old -> new) assertSame(antVal0, t.add("ant", antVal)); //System.out.println(t.toString()); // relabel insert (NULL -> new) assertNull(t.add("a", aVal)); //System.out.println(t.toString()); // relabel insert (NULL -> new) assertNull(t.add("_", _Val)); //System.out.println(t.toString()); assertSame(_Val, t.get("_")); assertSame(aVal, t.get("a")); assertSame(anVal, t.get("an")); assertSame(antVal, t.get("ant")); assertSame(addVal, t.get("add")); assertNull(t.get("aDd")); // Yield all elements (in forward sort order)... assertIterator(iter = t.getPrefixedBy("")); expectNextSame(_Val, iter); expectNextSame(aVal, iter); expectNextSame(addVal, iter); expectNextSame(anVal, iter); expectNextSame(antVal, iter); assertEmpty(iter); // Yield no elements... assertEmpty(t.getPrefixedBy("ab")); assertEmpty(t.getPrefixedBy("ants")); // Yield 1 element...starting in middle of prefix assertIterator(iter = t.getPrefixedBy("ad")); expectNextSame(addVal, iter); assertEmpty(iter); // Yield many elements... final Object aVals[] = {aVal, anVal, addVal, antVal}; assertIterator(iter = t.getPrefixedBy("a")); expectNextSame(aVal, iter); expectNextSame(addVal, iter); expectNextSame(anVal, iter); expectNextSame(antVal, iter); assertEmpty(iter); } public void testEmptyString() throws Throwable { Locale.setDefault(defaultLocale); tTrie_EmptyString(); } public void testEmptyStringInTurkish() throws Throwable { Locale.setDefault(turkishLocale); tTrie_EmptyString(); } // Empty string private void tTrie_EmptyString() { Trie t = new Trie(false); Iterator iter = null; Object tmp1 = null, tmp2 = null; assertNull(t.get("")); assertNull(t.add("", aVal)); assertNull(t.add("an", anVal)); assertEquals(aVal, t.get("")); assertIterator(iter = t.getPrefixedBy("")); expectNextSame(aVal, iter); expectNextSame(anVal, iter); assertEmpty(iter); } public void testPrefix() throws Throwable { Locale.setDefault(defaultLocale); tTrie_Prefix(); } public void testPrefixInTurkish() throws Throwable { Locale.setDefault(turkishLocale); tTrie_Prefix(); } // Prefix and substring prefix tests private void tTrie_Prefix() { Trie t = new Trie(false); Iterator iter = null; assertNull(t.add("an", anVal)); assertIterator(iter = t.getPrefixedBy("XanXX")); assertEmpty(iter); assertIterator(iter = t.getPrefixedBy("")); expectNextSame(anVal, iter); assertEmpty(iter); assertIterator(iter = t.getPrefixedBy("XanXX", 1, 4)); assertEmpty(iter); assertIterator(iter = t.getPrefixedBy("XanXX", 1, 3)); expectNextSame(anVal, iter); assertEmpty(iter); assertIterator(iter = t.getPrefixedBy("XanXX", 1, 2)); expectNextSame(anVal, iter); assertEmpty(iter); } public void testRemove() throws Throwable { Locale.setDefault(defaultLocale); tTrie_Remove(); } public void testRemoveInTurkish() throws Throwable { Locale.setDefault(turkishLocale); tTrie_Remove(); } // Remove tests private void tTrie_Remove() { Trie t = new Trie(false); assertNull(t.add("an", anVal)); assertNull(t.add("ant", antVal)); assertFalse(t.remove("x")); assertFalse(t.remove("a")); assertTrue(t.remove("an")); assertNull(t.get("an")); assertSame(antVal, t.get("ant")); } public void testIgnoreCase() throws Throwable { Locale.setDefault(defaultLocale); tTrie_IgnoreCase(); } public void testIgnoreCaseInTurkish() throws Throwable { Locale.setDefault(turkishLocale); tTrie_IgnoreCase(); } // Case-insensitive tests private void tTrie_IgnoreCase() { Trie t = new Trie(true); Iterator iter = null; assertNull(t.add("an", anVal)); assertSame(anVal, t.add("An", anVal)); assertSame(anVal, t.add("aN", anVal)); assertSame(anVal, t.add("AN", anVal)); assertSame(anVal, t.get("an")); assertSame(anVal, t.get("An")); assertSame(anVal, t.get("aN")); assertSame(anVal, t.get("AN")); assertNull(t.add("ant", antVal)); assertSame(antVal, t.get("ANT")); assertIterator(iter = t.getPrefixedBy("a")); expectNextSame(anVal, iter); expectNextSame(antVal, iter); assertEmpty(iter); } private static final Object ssVal0 = "initial value for ss"; private static final Object ssVal = "value for ss"; private static final Object strasVal = "value for stras"; private static final Object strassVal = "value for strass"; private static final Object strasseVal = "value for strasse"; private static final Object strassenVal0 = "initial value for strassen"; private static final Object strassenVal = "value for strassen"; private static final Object hVal = "value for h"; private static final Object iVal0 = "value for i (capital dotted)"; private static final Object iVal = "value for i"; private static final Object inVal = "value for in"; private static final Object jVal = "value for j"; public void testIgnoreCaseSpecial() throws Throwable { Locale.setDefault(defaultLocale); tTrie_IgnoreCaseSpecial(); } public void testIgnoreCaseSpecialInTurkish() throws Throwable { Locale.setDefault(turkishLocale); tTrie_IgnoreCaseSpecial(); } // Case-insensitive with special casing tests for Java 1.1+. private void tTrie_IgnoreCaseSpecial() { Trie t = null; Iterator iter = null; // Test stability of Trie with special casing rules for strings. // 1. German keyword: test conversion of German Ess-Tsett (sharp s) // First test that sharp s is converted to a pair of uppercase S t = new Trie(true); assertNull(t.add("\u00df", ssVal0)); //System.out.println("Should list 'ss':"); //System.out.println(t.toString()); assertSame(ssVal0, t.add("ss", ssVal)); // old value replaced assertSame(ssVal, t.get("\u00df")); // new value kept assertSame(ssVal, t.get("ss")); // new value kept assertSame(ssVal, t.get("SS")); assertSame(ssVal, t.get("Ss")); assertSame(ssVal, t.get("sS")); //System.out.println(t.toString()); assertIterator(iter = t.getPrefixedBy("")); expectNextSame(ssVal, iter); assertEmpty(iter); // Special case conversion stability tests t = new Trie(true); assertNull(t.add("Stra\u00dfe", strasseVal)); assertNull(t.add("stra\u00df", strassVal)); // split e assertSame(strasseVal, t.add("STRASSE", strasseVal)); // replace assertNull(t.add("Strassen", strassenVal0)); // splice assertSame(strassenVal0, t.add("STRA\u00dfEN", strassenVal)); //replace assertNull(t.add("stras", strasVal)); // split s //System.out.println(t.toString()); assertIterator(iter = t.getPrefixedBy("")); expectNextSame(strasVal, iter); expectNextSame(strassVal, iter); expectNextSame(strasseVal, iter); expectNextSame(strassenVal, iter); assertEmpty(iter); // 2. Turkish keyword: test of i (with or without dot above) // First test if capital dotted I is converted to small ASCII i t = new Trie(true); assertNull(t.add("\u0130", iVal0)); // capital dotted I //System.out.println("Should list 'i':"); //System.out.println(t.toString()); assertNull(t.add("h", hVal)); // add before assertNull(t.add("in", inVal)); // splice after assertNull(t.add("j", jVal)); // add after //System.out.println(t.toString()); assertSame(iVal0, t.get("i")); assertSame(iVal0, t.get("I")); assertSame(iVal0, t.get("\u0130")); // capital dotted I assertSame(iVal0, t.get("\u0131")); // small dotless i assertIterator(iter = t.getPrefixedBy("")); expectNextSame(hVal, iter); expectNextSame(iVal0, iter); expectNextSame(inVal, iter); expectNextSame(jVal, iter); assertEmpty(iter); // Replace value of node "i" assertSame(iVal0, t.add("i", iVal)); //System.out.println(t.toString()); assertSame(iVal, t.get("i")); assertSame(iVal, t.get("I")); assertSame(iVal, t.get("\u0130")); // capital dotted I assertSame(iVal, t.get("\u0131")); // small dotless i assertIterator(iter = t.getPrefixedBy("")); expectNextSame(hVal, iter); expectNextSame(iVal, iter); expectNextSame(inVal, iter); expectNextSame(jVal, iter); assertEmpty(iter); } // accessible helper for private int Trie.match(String, int, int, String) private static final int match(final Trie trie, final String a, int startOffset, int stopOffset, final String b) throws Throwable { try { return ((Integer) PrivilegedAccessor.invokeMethod(trie, "match", new Object[] {a, new Integer(startOffset), //native new Integer(stopOffset), //native b}, new Class[] {String.class, int.class, //native int.class, //native String.class}) ).intValue(); // unwrap the native int result } catch(Exception e) { if( e.getCause() != null ) throw e.getCause(); throw e; } } private void assertIterator(final Iterator iter) { assertNotNull("expected valid not null Iterator", iter); } private void assertEmpty(final Iterator iter) { assertFalse(iter.hasNext()); try { iter.next(); fail("expected NoSuchElementException"); } catch (NoSuchElementException e) { } } private Object expectNextSame(final Object expected, final Iterator iter) { assertTrue(iter.hasNext()); final Object value = iter.next(); assertSame("expected same <" + expected + "> got <" + value + ">", expected, value); return value; } }