/* * 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.jena.mem.test; import java.util.*; import org.apache.jena.mem.HashCommon ; import org.apache.jena.rdf.model.test.ModelTestBase ; public class TestHashCommon extends ModelTestBase { protected static final Item item2X = new Item( 2, "X" ); protected static final Item item1Y = new Item( 1, "Y" ); protected static final Item item2Z = new Item( 2, "Z" ); public TestHashCommon( String name ) { super( name ); } static class ProbeHashCommon extends HashCommon<Object> { protected ProbeHashCommon( int initialCapacity ) { super( initialCapacity ); } protected void set( int index, Item object ) { keys[index] = object; } @Override public Object removeFrom( int here ) { return super.removeFrom( here ); } public int top() { return capacity - 1; } public int capacity() { return capacity; } /* Leaving the hashcode alone makes testing simpler. */ @Override protected int improveHashCode( int hashCode ) { return hashCode; } @Override protected Object[] newKeyArray( int size ) { return new Object[size]; } } static class Item { protected final int n; protected final String s; public Item( int n, String s ) { this.n = n; this.s = s; } @Override public int hashCode() { return n; } @Override public boolean equals( Object other ) { return other instanceof Item && s.equals( ((Item) other).s ); } @Override public String toString() { return s + "#" + n; } } public void testSanityCheckTestDataConstruction() { ProbeHashCommon h = probeWith( "1:2:x 4:7:y -1:5:z" ); assertEquals( new Item( 2, "x" ), h.getItemForTestingAt( 1 ) ); assertEquals( new Item( 7, "y" ), h.getItemForTestingAt( 4 ) ); assertEquals( new Item( 5, "z" ), h.getItemForTestingAt( h.top() ) ); } public void testHashcodeUsedAsIndex() { ProbeHashCommon htb = new ProbeHashCommon( 10 ); int limit = htb.capacity(); for (int i = 0; i < limit; i += 1) { Item t = new Item( i, "s p o" ); // assertEquals( i, htb.) // assertSame( t, htb.getItemForTestingAt( i ) ); } } public void testRemoveNoMove() { ProbeHashCommon h = probeWith( "1:1:Y 2:2:Z" ); Item moved = (Item) h.removeFrom( 2 ); assertSame( null, moved ); assertAlike( probeWith( "1:1:Y" ), h ); } public void testRemoveSimpleMove() { ProbeHashCommon h = probeWith( "0:2:X 1:1:Y 2:2:Z" ); assertSame( null, h.removeFrom( 1 ) ); assertAlike( probeWith( "1:2:X 2:2:Z"), h ); } public void testRemoveCircularMove() { ProbeHashCommon h = probeWith( "0:0:X 1:2:Y -1:2:Z" ); Item moved = (Item) h.removeFrom( 1 ); assertAlike( probeWith( "0:0:X 1:2:Z" ), h ); assertEquals( new Item( 2, "Z" ), moved ); } public void testKeyIterator() { ProbeHashCommon h = probeWith( "0:0:X" ); Set<?> elements = h.keyIterator().toSet(); assertEquals( itemSet( "0:X" ), elements ); } /** Assert that the two probe HashCommon's are "alike", that is, that they have key arrays of equal size and are element-by-element equal. Otherwise, fail (preferably with an appropriate message). */ private void assertAlike( ProbeHashCommon desired, ProbeHashCommon got ) { assertEquals( "capacities must be equal", desired.capacity(), got.capacity() ); for (int i = 0; i < desired.capacity(); i += 1) assertEquals( desired.getItemForTestingAt( i ), got.getItemForTestingAt( i ) ); } /** Answer a probe with the specified items. <code>items</code> is a space-separated string of item descriptions. Each description is a colon-separated sequence <code>index:hash:label</code>: the item <code>(hash, label)</code> will be placed at <code>index</code>. Negative index values are interpreted as indexs from the <i>end</code> of the key array, by adding the probe's capacity to them. */ protected ProbeHashCommon probeWith( String items ) { ProbeHashCommon result = new ProbeHashCommon( 10 ); StringTokenizer st = new StringTokenizer( items ); while (st.hasMoreTokens()) { String item = st.nextToken(); StringTokenizer itemElements = new StringTokenizer( item, ":" ); int index = Integer.parseInt( itemElements.nextToken() ); int hash = Integer.parseInt( itemElements.nextToken() ); String w = itemElements.nextToken(); result.set( (index< 0 ? index + result.capacity() : index), new Item( hash, w ) ); } return result; } protected Set<Item> itemSet( String items ) { Set<Item> result = new HashSet<>(); StringTokenizer st = new StringTokenizer( items ); while (st.hasMoreTokens()) addItem( result, st.nextToken() ); return result; } private void addItem( Set<Item> result, String item ) { StringTokenizer itemElements = new StringTokenizer( item, ":" ); int hash = Integer.parseInt( itemElements.nextToken() ); String w = itemElements.nextToken(); result.add( new Item( hash, w ) ); } }