/* * 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.collections4.trie; import java.util.ArrayList; import java.util.Arrays; import java.util.ConcurrentModificationException; import java.util.HashSet; import java.util.Iterator; import java.util.Map; import java.util.NoSuchElementException; import java.util.Set; import java.util.SortedMap; import junit.framework.Test; import org.apache.commons.collections4.BulkTest; import org.apache.commons.collections4.Trie; import org.apache.commons.collections4.map.AbstractSortedMapTest; import org.junit.Assert; /** * JUnit tests for the PatriciaTrie. * * @since 4.0 * @version $Id$ */ public class PatriciaTrieTest<V> extends AbstractSortedMapTest<String, V> { public PatriciaTrieTest(final String testName) { super(testName); } public static Test suite() { return BulkTest.makeSuite(PatriciaTrieTest.class); } @Override public SortedMap<String, V> makeObject() { return new PatriciaTrie<V>(); } @Override public boolean isAllowNullKey() { return false; } //----------------------------------------------------------------------- public void testPrefixMap() { final PatriciaTrie<String> trie = new PatriciaTrie<String>(); final String[] keys = new String[]{ "", "Albert", "Xavier", "XyZ", "Anna", "Alien", "Alberto", "Alberts", "Allie", "Alliese", "Alabama", "Banane", "Blabla", "Amber", "Ammun", "Akka", "Akko", "Albertoo", "Amma" }; for (final String key : keys) { trie.put(key, key); } SortedMap<String, String> map; Iterator<String> iterator; Iterator<Map.Entry<String, String>> entryIterator; Map.Entry<String, String> entry; map = trie.prefixMap("Al"); Assert.assertEquals(8, map.size()); Assert.assertEquals("Alabama", map.firstKey()); Assert.assertEquals("Alliese", map.lastKey()); Assert.assertEquals("Albertoo", map.get("Albertoo")); Assert.assertNotNull(trie.get("Xavier")); Assert.assertNull(map.get("Xavier")); Assert.assertNull(trie.get("Alice")); Assert.assertNull(map.get("Alice")); iterator = map.values().iterator(); Assert.assertEquals("Alabama", iterator.next()); Assert.assertEquals("Albert", iterator.next()); Assert.assertEquals("Alberto", iterator.next()); Assert.assertEquals("Albertoo", iterator.next()); Assert.assertEquals("Alberts", iterator.next()); Assert.assertEquals("Alien", iterator.next()); Assert.assertEquals("Allie", iterator.next()); Assert.assertEquals("Alliese", iterator.next()); Assert.assertFalse(iterator.hasNext()); map = trie.prefixMap("Albert"); iterator = map.keySet().iterator(); Assert.assertEquals("Albert", iterator.next()); Assert.assertEquals("Alberto", iterator.next()); Assert.assertEquals("Albertoo", iterator.next()); Assert.assertEquals("Alberts", iterator.next()); Assert.assertFalse(iterator.hasNext()); Assert.assertEquals(4, map.size()); Assert.assertEquals("Albert", map.firstKey()); Assert.assertEquals("Alberts", map.lastKey()); Assert.assertNull(trie.get("Albertz")); map.put("Albertz", "Albertz"); Assert.assertEquals("Albertz", trie.get("Albertz")); Assert.assertEquals(5, map.size()); Assert.assertEquals("Albertz", map.lastKey()); iterator = map.keySet().iterator(); Assert.assertEquals("Albert", iterator.next()); Assert.assertEquals("Alberto", iterator.next()); Assert.assertEquals("Albertoo", iterator.next()); Assert.assertEquals("Alberts", iterator.next()); Assert.assertEquals("Albertz", iterator.next()); Assert.assertFalse(iterator.hasNext()); Assert.assertEquals("Albertz", map.remove("Albertz")); map = trie.prefixMap("Alberto"); Assert.assertEquals(2, map.size()); Assert.assertEquals("Alberto", map.firstKey()); Assert.assertEquals("Albertoo", map.lastKey()); entryIterator = map.entrySet().iterator(); entry = entryIterator.next(); Assert.assertEquals("Alberto", entry.getKey()); Assert.assertEquals("Alberto", entry.getValue()); entry = entryIterator.next(); Assert.assertEquals("Albertoo", entry.getKey()); Assert.assertEquals("Albertoo", entry.getValue()); Assert.assertFalse(entryIterator.hasNext()); trie.put("Albertoad", "Albertoad"); Assert.assertEquals(3, map.size()); Assert.assertEquals("Alberto", map.firstKey()); Assert.assertEquals("Albertoo", map.lastKey()); entryIterator = map.entrySet().iterator(); entry = entryIterator.next(); Assert.assertEquals("Alberto", entry.getKey()); Assert.assertEquals("Alberto", entry.getValue()); entry = entryIterator.next(); Assert.assertEquals("Albertoad", entry.getKey()); Assert.assertEquals("Albertoad", entry.getValue()); entry = entryIterator.next(); Assert.assertEquals("Albertoo", entry.getKey()); Assert.assertEquals("Albertoo", entry.getValue()); Assert.assertFalse(entryIterator.hasNext()); Assert.assertEquals("Albertoo", trie.remove("Albertoo")); Assert.assertEquals("Alberto", map.firstKey()); Assert.assertEquals("Albertoad", map.lastKey()); Assert.assertEquals(2, map.size()); entryIterator = map.entrySet().iterator(); entry = entryIterator.next(); Assert.assertEquals("Alberto", entry.getKey()); Assert.assertEquals("Alberto", entry.getValue()); entry = entryIterator.next(); Assert.assertEquals("Albertoad", entry.getKey()); Assert.assertEquals("Albertoad", entry.getValue()); Assert.assertFalse(entryIterator.hasNext()); Assert.assertEquals("Albertoad", trie.remove("Albertoad")); trie.put("Albertoo", "Albertoo"); map = trie.prefixMap("X"); Assert.assertEquals(2, map.size()); Assert.assertFalse(map.containsKey("Albert")); Assert.assertTrue(map.containsKey("Xavier")); Assert.assertFalse(map.containsKey("Xalan")); iterator = map.values().iterator(); Assert.assertEquals("Xavier", iterator.next()); Assert.assertEquals("XyZ", iterator.next()); Assert.assertFalse(iterator.hasNext()); map = trie.prefixMap("An"); Assert.assertEquals(1, map.size()); Assert.assertEquals("Anna", map.firstKey()); Assert.assertEquals("Anna", map.lastKey()); iterator = map.keySet().iterator(); Assert.assertEquals("Anna", iterator.next()); Assert.assertFalse(iterator.hasNext()); map = trie.prefixMap("Ban"); Assert.assertEquals(1, map.size()); Assert.assertEquals("Banane", map.firstKey()); Assert.assertEquals("Banane", map.lastKey()); iterator = map.keySet().iterator(); Assert.assertEquals("Banane", iterator.next()); Assert.assertFalse(iterator.hasNext()); map = trie.prefixMap("Am"); Assert.assertFalse(map.isEmpty()); Assert.assertEquals(3, map.size()); Assert.assertEquals("Amber", trie.remove("Amber")); iterator = map.keySet().iterator(); Assert.assertEquals("Amma", iterator.next()); Assert.assertEquals("Ammun", iterator.next()); Assert.assertFalse(iterator.hasNext()); iterator = map.keySet().iterator(); map.put("Amber", "Amber"); Assert.assertEquals(3, map.size()); try { iterator.next(); Assert.fail("CME expected"); } catch(final ConcurrentModificationException expected) {} Assert.assertEquals("Amber", map.firstKey()); Assert.assertEquals("Ammun", map.lastKey()); map = trie.prefixMap("Ak\0"); Assert.assertTrue(map.isEmpty()); map = trie.prefixMap("Ak"); Assert.assertEquals(2, map.size()); Assert.assertEquals("Akka", map.firstKey()); Assert.assertEquals("Akko", map.lastKey()); map.put("Ak", "Ak"); Assert.assertEquals("Ak", map.firstKey()); Assert.assertEquals("Akko", map.lastKey()); Assert.assertEquals(3, map.size()); trie.put("Al", "Al"); Assert.assertEquals(3, map.size()); Assert.assertEquals("Ak", map.remove("Ak")); Assert.assertEquals("Akka", map.firstKey()); Assert.assertEquals("Akko", map.lastKey()); Assert.assertEquals(2, map.size()); iterator = map.keySet().iterator(); Assert.assertEquals("Akka", iterator.next()); Assert.assertEquals("Akko", iterator.next()); Assert.assertFalse(iterator.hasNext()); Assert.assertEquals("Al", trie.remove("Al")); map = trie.prefixMap("Akka"); Assert.assertEquals(1, map.size()); Assert.assertEquals("Akka", map.firstKey()); Assert.assertEquals("Akka", map.lastKey()); iterator = map.keySet().iterator(); Assert.assertEquals("Akka", iterator.next()); Assert.assertFalse(iterator.hasNext()); map = trie.prefixMap("Ab"); Assert.assertTrue(map.isEmpty()); Assert.assertEquals(0, map.size()); try { final Object o = map.firstKey(); Assert.fail("got a first key: " + o); } catch(final NoSuchElementException nsee) {} try { final Object o = map.lastKey(); Assert.fail("got a last key: " + o); } catch(final NoSuchElementException nsee) {} iterator = map.values().iterator(); Assert.assertFalse(iterator.hasNext()); map = trie.prefixMap("Albertooo"); Assert.assertTrue(map.isEmpty()); Assert.assertEquals(0, map.size()); try { final Object o = map.firstKey(); Assert.fail("got a first key: " + o); } catch(final NoSuchElementException nsee) {} try { final Object o = map.lastKey(); Assert.fail("got a last key: " + o); } catch(final NoSuchElementException nsee) {} iterator = map.values().iterator(); Assert.assertFalse(iterator.hasNext()); map = trie.prefixMap(""); Assert.assertSame(trie, map); // stricter than necessary, but a good check map = trie.prefixMap("\0"); Assert.assertTrue(map.isEmpty()); Assert.assertEquals(0, map.size()); try { final Object o = map.firstKey(); Assert.fail("got a first key: " + o); } catch(final NoSuchElementException nsee) {} try { final Object o = map.lastKey(); Assert.fail("got a last key: " + o); } catch(final NoSuchElementException nsee) {} iterator = map.values().iterator(); Assert.assertFalse(iterator.hasNext()); } public void testPrefixMapRemoval() { final PatriciaTrie<String> trie = new PatriciaTrie<String>(); final String[] keys = new String[]{ "Albert", "Xavier", "XyZ", "Anna", "Alien", "Alberto", "Alberts", "Allie", "Alliese", "Alabama", "Banane", "Blabla", "Amber", "Ammun", "Akka", "Akko", "Albertoo", "Amma" }; for (final String key : keys) { trie.put(key, key); } SortedMap<String, String> map = trie.prefixMap("Al"); Assert.assertEquals(8, map.size()); Iterator<String> iter = map.keySet().iterator(); Assert.assertEquals("Alabama", iter.next()); Assert.assertEquals("Albert", iter.next()); Assert.assertEquals("Alberto", iter.next()); Assert.assertEquals("Albertoo", iter.next()); Assert.assertEquals("Alberts", iter.next()); Assert.assertEquals("Alien", iter.next()); iter.remove(); Assert.assertEquals(7, map.size()); Assert.assertEquals("Allie", iter.next()); Assert.assertEquals("Alliese", iter.next()); Assert.assertFalse(iter.hasNext()); map = trie.prefixMap("Ak"); Assert.assertEquals(2, map.size()); iter = map.keySet().iterator(); Assert.assertEquals("Akka", iter.next()); iter.remove(); Assert.assertEquals(1, map.size()); Assert.assertEquals("Akko", iter.next()); if(iter.hasNext()) { Assert.fail("shouldn't have next (but was: " + iter.next() + ")"); } Assert.assertFalse(iter.hasNext()); } public void testPrefixMapSizes() { // COLLECTIONS-525 PatriciaTrie<String> aTree = new PatriciaTrie<String>(); aTree.put("点评", "测试"); aTree.put("书评", "测试"); assertTrue(aTree.prefixMap("点").containsKey("点评")); assertEquals("测试", aTree.prefixMap("点").get("点评")); assertFalse(aTree.prefixMap("点").isEmpty()); assertEquals(1, aTree.prefixMap("点").size()); assertEquals(1, aTree.prefixMap("点").keySet().size()); assertEquals(1, aTree.prefixMap("点").entrySet().size()); assertEquals(1, aTree.prefixMap("点评").values().size()); aTree.clear(); aTree.put("点评", "联盟"); aTree.put("点版", "定向"); assertEquals(2, aTree.prefixMap("点").keySet().size()); assertEquals(2, aTree.prefixMap("点").values().size()); } public void testPrefixMapSizes2() { final char u8000 = Character.toChars(32768)[0]; // U+8000 (1000000000000000) final char char_b = 'b'; // 1100010 final PatriciaTrie<String> trie = new PatriciaTrie<String>(); final String prefixString = "" + char_b; final String longerString = prefixString + u8000; assertEquals(1, prefixString.length()); assertEquals(2, longerString.length()); assertTrue(longerString.startsWith(prefixString)); trie.put(prefixString, "prefixString"); trie.put(longerString, "longerString"); assertEquals(2, trie.prefixMap(prefixString).size()); assertTrue(trie.prefixMap(prefixString).containsKey(longerString)); } public void testPrefixMapClear() { Trie<String, Integer> trie = new PatriciaTrie<Integer>(); trie.put("Anna", 1); trie.put("Anael", 2); trie.put("Analu", 3); trie.put("Andreas", 4); trie.put("Andrea", 5); trie.put("Andres", 6); trie.put("Anatole", 7); SortedMap<String, Integer> prefixMap = trie.prefixMap("And"); assertEquals(new HashSet<String>(Arrays.asList("Andrea", "Andreas", "Andres")), prefixMap.keySet()); assertEquals(Arrays.asList(5, 4, 6), new ArrayList<Integer>(prefixMap.values())); prefixMap.clear(); assertTrue(prefixMap.isEmpty()); assertTrue(prefixMap.keySet().isEmpty()); assertTrue(prefixMap.values().isEmpty()); assertEquals(new HashSet<String>(Arrays.asList("Anael", "Analu", "Anatole", "Anna")), trie.keySet()); assertEquals(Arrays.asList(2, 3, 7, 1), new ArrayList<Integer>(trie.values())); } public void testPrefixMapClearNothing() { Trie<String, Integer> trie = new PatriciaTrie<Integer>(); SortedMap<String, Integer> prefixMap = trie.prefixMap("And"); assertEquals(new HashSet<String>(), prefixMap.keySet()); assertEquals(new ArrayList<Integer>(0), new ArrayList<Integer>(prefixMap.values())); prefixMap.clear(); assertTrue(prefixMap.isEmpty()); assertTrue(prefixMap.keySet().isEmpty()); assertTrue(prefixMap.values().isEmpty()); assertEquals(new HashSet<String>(), trie.keySet()); assertEquals(new ArrayList<Integer>(0), new ArrayList<Integer>(trie.values())); } public void testPrefixMapClearUsingRemove() { Trie<String, Integer> trie = new PatriciaTrie<Integer>(); trie.put("Anna", 1); trie.put("Anael", 2); trie.put("Analu", 3); trie.put("Andreas", 4); trie.put("Andrea", 5); trie.put("Andres", 6); trie.put("Anatole", 7); SortedMap<String, Integer> prefixMap = trie.prefixMap("And"); assertEquals(new HashSet<String>(Arrays.asList("Andrea", "Andreas", "Andres")), prefixMap.keySet()); assertEquals(Arrays.asList(5, 4, 6), new ArrayList<Integer>(prefixMap.values())); Set<String> keys = new HashSet<String>(prefixMap.keySet()); for (final String key : keys) { prefixMap.remove(key); } assertTrue(prefixMap.keySet().isEmpty()); assertTrue(prefixMap.values().isEmpty()); assertEquals(new HashSet<String>(Arrays.asList("Anael", "Analu", "Anatole", "Anna")), trie.keySet()); assertEquals(Arrays.asList(2, 3, 7, 1), new ArrayList<Integer>(trie.values())); } //----------------------------------------------------------------------- @Override public String getCompatibilityVersion() { return "4"; } // public void testCreate() throws Exception { // resetEmpty(); // writeExternalFormToDisk( // (java.io.Serializable) map, // "src/test/resources/data/test/PatriciaTrie.emptyCollection.version4.obj"); // resetFull(); // writeExternalFormToDisk( // (java.io.Serializable) map, // "src/test/resources/data/test/PatriciaTrie.fullCollection.version4.obj"); // } }