package de.axone.data.weighted; import org.assertj.core.api.AbstractIterableAssert; import org.testng.annotations.Test; import de.axone.data.weighted.WeightedCollection.Weighter; import de.axone.tools.E; @Test( groups="helper.weighted_collection" ) public class WeightedCollectionTest { private TestItem id1_10 = item( 1, 10.0 ), id1_20 = item( 1, 20.0 ), id1_30 = item( 1, 30.0 ), id2_10 = item( 2, 10.0 ), id2_20 = item( 2, 20.0 ), id2_30 = item( 2, 30.0 ), id3_30 = item( 3, 30.0 ), id4_40 = item( 4, 40.0 ) ; public void testOneItem() { WeightedTestItems list = new WeightedTestItems(); list.add( id1_10 ); assertThat( list ) .hasSize( 1 ) .contains( id1_10 ) .contains( id1_20 ) .contains( id1_30 ) .containsPrecisely( id1_10 ) .doesNotContainPrecisely( id1_20 ) // Tests just the tests .hasWeight( 10.0 ) .hasMaxWeight( 10.0 ) .hasAvgWeight( 10.0 ) ; } public void testDifferentItems() { WeightedTestItems list = new WeightedTestItems(); list.add( id1_10 ); list.add( id2_10 ); assertThat( list ) .hasSize( 2 ) .containsPrecisely( id1_10 ) .contains( id1_20 ) .contains( id1_30 ) .containsPrecisely( id2_10 ) .contains( id2_20 ) .contains( id2_30 ) .hasWeight( 20.0 ) .hasMaxWeight( 10.0 ) .hasAvgWeight( 10.0 ) ; } public void testSameItems() { WeightedTestItems list = new WeightedTestItems(); list.add( id1_10 ); list.add( id1_20 ); assertThat( list ) .hasSize( 1 ) .contains( id1_10 ) .contains( id1_20 ) .contains( id1_30 ) .containsPrecisely( id1_30 ) .doesNotContainPrecisely( id1_10 ) .doesNotContainPrecisely( id1_20 ) .hasWeight( 30.0 ) .hasMaxWeight( 30.0 ) .hasAvgWeight( 30.0 ) ; } public void testMixedItems() { WeightedTestItems list = new WeightedTestItems(); list.add( id1_10 ); list.add( id1_20 ); list.add( id2_20 ); assertThat( list ) .hasSize( 2 ) .contains( id1_10 ) .contains( id1_20 ) .doesNotContainPrecisely( id1_10 ) .doesNotContainPrecisely( id1_20 ) .containsPrecisely( id1_30 ) .contains( id2_10 ) .containsPrecisely( id2_20 ) .contains( id2_30 ) .hasWeight( 50.0 ) .hasMaxWeight( 30.0 ) .hasAvgWeight( 25.0 ) ; } public void testSublists() { WeightedTestItems list = new WeightedTestItems(); assertThat( list ) .hasSize( 0 ) ; list.add( id1_10 ); list.add( id2_20 ); list.add( id3_30 ); list.add( id4_40 ); assertThat( list ) .hasSize( 4 ) ; assertThat( list.best( 0 ) ) .hasSize( 0 ) ; assertThat( list.best( 1 ) ) .hasSize( 1 ) .containsPrecisely( id4_40 ) .hasWeight( 40.0 ) .hasMaxWeight( 40.0 ) .hasAvgWeight( 40.0 ) .isNotEqualTo( list.best( 0 ) ) ; assertThat( list.best( 2 ) ) .hasSize( 2 ) .containsPrecisely( id4_40 ) .containsPrecisely( id3_30 ) .hasWeight( 70.0 ) .hasMaxWeight( 40.0 ) .hasAvgWeight( 35.0 ) .isNotEqualTo( list.best( 1 ) ) ; assertThat( list.best( 3 ) ) .hasSize( 3 ) .containsPrecisely( id4_40 ) .containsPrecisely( id3_30 ) .containsPrecisely( id2_20 ) .hasWeight( 90.0 ) .hasMaxWeight( 40.0 ) .hasAvgWeight( 30.0 ) .isNotEqualTo( list.best( 2 ) ) ; assertThat( list.best( 4 ) ) .hasSize( 4 ) .containsPrecisely( id4_40 ) .containsPrecisely( id3_30 ) .containsPrecisely( id2_20 ) .containsPrecisely( id1_10 ) .hasWeight( 100.0 ) .hasMaxWeight( 40.0 ) .hasAvgWeight( 25.0 ) .isNotEqualTo( list.best( 3 ) ) ; assertThat( list.best( 5 ) ) .isEqualTo( list.best( 4 ) ) ; } public void testNormalize() { WeightedTestItems list = new WeightedTestItems(); list.add( id1_10 ); list.add( id2_10 ); list.add( id2_10 ); list.add( id3_30 ); list.add( id4_40 ); assertThat( list ) .hasSize( 4 ) .hasWeight( 100.0 ) .hasAvgWeight( 25.0 ) .hasMaxWeight( 40.0 ) ; assertThat( list.normalized() ) .hasSize( 4 ) .containsPrecisely( item( 1, 0.25 ) ) .containsPrecisely( item( 2, 0.5 ) ) .containsPrecisely( item( 3, 0.75 ) ) .containsPrecisely( item( 4, 1.0 ) ) ; } private static class WeightedTestItems extends AbstractWeightedCollection<WeightedTestItems, TestItem> { public WeightedTestItems(){ super( WeightedTestItems::new, item -> item.weight, (item,newWeight) -> new TestItem( item.name, newWeight ) ); } } private static final TestItem item( int name, double weight ){ return new TestItem( "id"+name, weight ); } /** * Item with hashcode and equals only on payload and not on weight * * @author flo */ private static class TestItem { private final String name; private final double weight; public TestItem( String name, double weight ) { this.name = name; this.weight = weight; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ( ( name == null ) ? 0 : name.hashCode() ); return result; } @Override public boolean equals( Object obj ) { if( this == obj ) return true; if( obj == null ) return false; if( !( obj instanceof TestItem ) ) return false; TestItem other = (TestItem) obj; if( name == null ) { if( other.name != null ) return false; } else if( !name.equals( other.name ) ) return false; return true; } @Override public String toString(){ return name + "(" + weight + ")"; } } public static class WeightedCollectionAssert<T, W extends AbstractWeightedCollection<W,T>> extends AbstractIterableAssert<WeightedCollectionAssert<T,W>, W, T> { protected WeightedCollectionAssert( W actual ) { super( actual, WeightedCollectionAssert.class ); } public WeightedCollectionAssert<T,W> hasWeight( double weight ){ org.assertj.core.api.Assertions.assertThat( actual.weight() ) .isEqualTo( weight ) ; return this; } public WeightedCollectionAssert<T,W> hasMaxWeight( double weight ){ org.assertj.core.api.Assertions.assertThat( actual.maxWeight() ) .isEqualTo( weight ) ; return this; } public WeightedCollectionAssert<T,W> hasAvgWeight( double weight ){ org.assertj.core.api.Assertions.assertThat( actual.avgWeight() ) .isEqualTo( weight ) ; return this; } @SuppressWarnings( "unchecked" ) public WeightedCollectionAssert<T,W> containsPrecisely( T ... items ){ for( T item : items ) containsPrecisely( item ); return this; } protected static <X,Y extends AbstractWeightedCollection<Y,X>> boolean _containsPrecisely( Y collection, X item ) { Weighter<X> weighter = collection.weighter(); for( X it : collection ){ if( it.equals( item ) && weighter.weight( it ) == weighter.weight( item ) ) return true; } return false; } public WeightedCollectionAssert<T,W> containsPrecisely( T item ){ if( _containsPrecisely( actual, item ) ) return this; failWithMessage( "\nExpected: <%s>\nto be contained in:\n<%s>\nbut it was not", item, actual.asList() ); return this; } public WeightedCollectionAssert<T,W> doesNotContainPrecisely( T item ){ Weighter<T> weighter = actual.weighter(); for( T it : actual ){ if( it.equals( item ) && weighter.weight( it ) == weighter.weight( item ) ) failWithMessage( "\nExpected: <%s>\nto NOT be contained in:\n<%s>\nbut it was", item, actual.asList() ); } return this; } public WeightedCollectionAssert<T,W> print() { E.rr( actual ); return this; } } public static <T, W extends AbstractWeightedCollection<W,T>> WeightedCollectionAssert<T,W> assertThat( W list ){ return new WeightedCollectionAssert<T,W>( list ); } }