package sh.calaba.instrumentationbackend.actions.view;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.DrawableContainer;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import sh.calaba.instrumentationbackend.Result;
import sh.calaba.instrumentationbackend.TestHelpers;
import sh.calaba.instrumentationbackend.actions.Action;
/**
* eg: performAction( 'assert_view_property', 'my_view', 'visibility', 'visible' ) // or invisible/gone
* eg: performAction( 'assert_view_property', 'my_view', 'drawable', 'expected_id' )
* eg: performAction( 'assert_view_property', 'my_view', 'compoundDrawables', 'left', 'expected_id' )
*
* @author Nicholas Albion
*/
public class AssertViewProperty extends GetViewProperty implements Action {
private static final String TAG = "assert_view_property";
@Override
protected Result getPropertyValue( String propertyName, View view, String[] args ) throws NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException {
if( "compoundDrawables".equals(propertyName) ) {
if( view instanceof TextView ) {
// performAction( 'get_view_property', 'my_view', 'compoundDrawables', 'left', 'expected_id'
String expected_id = args[3];
int pos;
if( "top".equals(args[2]) ) {
pos = 1;
} else if( "right".equals(args[2]) ) {
pos = 2;
} else if( "bottom".equals(args[2]) ) {
pos = 3;
} else {
pos = 0;
}
Drawable[] drawables = ((TextView)view).getCompoundDrawables(); // [left, top, right, bottom]
Drawable actualDrawable = drawables[pos];
Drawable expectedDrawable = TestHelpers.getDrawableById(expected_id);
return assertSameDrawables( propertyName + ", " + args[2], expectedDrawable, actualDrawable );
} else {
throw new IllegalArgumentException("compoundDrawables is only supported for subclasses of TextView, not " + view.getClass().getName());
}
} else {
return super.getPropertyValue(propertyName, view, args);
}
}
/**
* @param propertyName
* @param propertyValue
* @param args
* @return successResult if propertyValue
is equal to args[2]
* otherwise provides a descriptive message and the expected and actual values in the bonusInformation
*/
@Override
protected Result processProperty( String propertyName, Object propertyValue, String[] args ) {
String expected = args[2];
String value;
if( propertyValue == null ) {
if( expected == null || "null".equals(expected) ) {
return Result.successResult();
}
value = "null";
} else if( "drawable".equals(propertyName) ) {
Drawable actualDrawable = (Drawable)propertyValue; // ((ImageButton)view).getDrawable();
if( actualDrawable instanceof DrawableContainer ) {
actualDrawable = ((DrawableContainer)actualDrawable).getCurrent();
}
Drawable expectedDrawable = TestHelpers.getDrawableById(expected);
return assertSameDrawables( propertyName, expectedDrawable, actualDrawable );
} else {
value = propertyValue.toString();
if( value.equals(expected) ) {
return Result.successResult();
}
}
Result result = new Result(false, "For " + propertyName + " expected " + expected + " but was actually " + value);
result.addBonusInformation( expected );
result.addBonusInformation( value );
return result;
}
private Result assertSameDrawables( String propertyName, Drawable expectedDrawable, Drawable actualDrawable ) {
if( sameDrawables( expectedDrawable, actualDrawable) ) {
return Result.successResult();
} else {
Result result = new Result(false, "For " + propertyName + " expected " + expectedDrawable + " but was actually " + actualDrawable);
result.addBonusInformation( expectedDrawable == null ? "null" : expectedDrawable.toString() );
result.addBonusInformation( actualDrawable == null ? "null" : actualDrawable.toString() );
return result;
}
}
private boolean sameDrawables( Drawable expected, Drawable actual ) {
if( expected.equals(actual) ) {
return true;
}
if( expected instanceof DrawableContainer ) {
expected = ((DrawableContainer)expected).getCurrent();
}
if( actual instanceof DrawableContainer ) {
actual = ((DrawableContainer)actual).getCurrent();
}
if( (expected instanceof BitmapDrawable) && (actual instanceof BitmapDrawable) ) {
Bitmap expectedBitmap = ((BitmapDrawable)expected).getBitmap();
Bitmap actualBitmap = ((BitmapDrawable)actual).getBitmap();
try {
// As pointed out by kbielenberg, Bitmap.sameAs() was only added in level 12/Android 3.1/Honeycomb MR1
Method sameAs = Bitmap.class.getMethod("sameAs", Bitmap.class);
return (Boolean)sameAs.invoke( expectedBitmap, actualBitmap );
} catch (Exception e) {
if( expectedBitmap.getWidth() != actualBitmap.getWidth() ) { return false; }
if( expectedBitmap.getHeight() != actualBitmap.getHeight() ) { return false; }
if( expectedBitmap.getConfig() != actualBitmap.getConfig() ) { return false; }
boolean bitmapsEqual = expectedBitmap.equals(actualBitmap);
if( !bitmapsEqual ) {
Log.i(TAG, "Bitmaps are not equal");
}
boolean drawablesEqual = expected.equals(actual);
if( !drawablesEqual ) {
Log.i(TAG, "Drawables are not equal");
}
return bitmapsEqual && drawablesEqual;
}
}
return false;
}
@Override
public String key() {
return "assert_view_property";
}
}