/*
* 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 ) );
}
}