Create base test class for custom views

pull/77/merge
Alinson S. Xavier 10 years ago
parent e3d96c0431
commit 2c62e1578a

1
.gitignore vendored

@ -33,3 +33,4 @@ build/
*.iml *.iml
art/ art/
*.actual.png

@ -0,0 +1,48 @@
/*
* Copyright (C) 2016 Álinson Santos Xavier <isoron@gmail.com>
*
* This file is part of Loop Habit Tracker.
*
* Loop Habit Tracker is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* Loop Habit Tracker is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.isoron.uhabits.unit.views;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.SmallTest;
import org.isoron.uhabits.helpers.ColorHelper;
import org.isoron.uhabits.views.RingView;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.io.IOException;
@RunWith(AndroidJUnit4.class)
@SmallTest
public class RingViewTest extends ViewTest
{
@Test
public void renderTest1() throws IOException
{
RingView view = new RingView(targetContext);
view.setLabel("Hello world");
view.setPercentage(0.6f);
view.setColor(ColorHelper.palette[0]);
view.setMaxDiameter(dpToPixels(100));
measureView(dpToPixels(100), dpToPixels(100), view);
assertRenders(view, "Views/RingView/renderTest1.png");
}
}

@ -0,0 +1,160 @@
/*
* Copyright (C) 2016 Álinson Santos Xavier <isoron@gmail.com>
*
* This file is part of Loop Habit Tracker.
*
* Loop Habit Tracker is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* Loop Habit Tracker is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.isoron.uhabits.unit.views;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.support.test.InstrumentationRegistry;
import android.view.View;
import org.isoron.uhabits.helpers.DialogHelper;
import org.junit.Before;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import static junit.framework.Assert.fail;
public class ViewTest
{
protected static final int SIMILARITY_CUTOFF = 6000;
protected Context testContext;
protected Context targetContext;
@Before
public void setup()
{
targetContext = InstrumentationRegistry.getTargetContext();
testContext = InstrumentationRegistry.getContext();
}
protected void measureView(int width, int height, View view)
{
int specWidth = View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY);
int specHeight = View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY);
view.measure(specWidth, specHeight);
view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight());
}
protected void assertRenders(View view, String expectedImagePath) throws IOException
{
StringBuilder errorMessage = new StringBuilder();
view.setDrawingCacheEnabled(true);
view.buildDrawingCache();
Bitmap actualBitmap = view.getDrawingCache();
Bitmap expectedBitmap = getBitmapFromAssets(expectedImagePath);
Bitmap scaledExpectedBitmap = Bitmap.createScaledBitmap(expectedBitmap,
actualBitmap.getWidth(), actualBitmap.getHeight(), false);
boolean similarEnough = true;
long distance;
if ((distance = compareHistograms(getHistogram(actualBitmap), getHistogram(
scaledExpectedBitmap))) > SIMILARITY_CUTOFF)
{
similarEnough = false;
errorMessage.append(String.format(
"Rendered image has wrong histogram (distance=%d). ",
distance));
}
if(!similarEnough)
{
String path = saveBitmap(expectedImagePath, actualBitmap);
errorMessage.append(String.format("Actual rendered image " + "saved to %s", path));
fail(errorMessage.toString());
}
actualBitmap.recycle();
expectedBitmap.recycle();
scaledExpectedBitmap.recycle();
}
private Bitmap getBitmapFromAssets(String path) throws IOException
{
InputStream stream = testContext.getAssets().open(path);
return BitmapFactory.decodeStream(stream);
}
private String saveBitmap(String filename, Bitmap bitmap)
throws IOException
{
String absolutePath = String.format("%s/Failed/%s", targetContext.getExternalCacheDir(),
filename.replaceAll("\\.png$", ".actual.png"));
new File(absolutePath).getParentFile().mkdirs();
FileOutputStream out = new FileOutputStream(absolutePath);
bitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
return absolutePath;
}
private int[][] getHistogram(Bitmap bitmap)
{
int histogram[][] = new int[4][256];
for(int x = 0; x < bitmap.getWidth(); x++)
{
for(int y = 0; y < bitmap.getHeight(); y++)
{
int color = bitmap.getPixel(x, y);
int[] argb = new int[]{
(color >> 24) & 0xff, //alpha
(color >> 16) & 0xff, //red
(color >> 8) & 0xff, //green
(color ) & 0xff //blue
};
histogram[0][argb[0]]++;
histogram[1][argb[1]]++;
histogram[2][argb[2]]++;
histogram[3][argb[3]]++;
}
}
return histogram;
}
private long compareHistograms(int[][] actualHistogram, int[][] expectedHistogram)
{
long distance = 0;
for(int i = 0; i < 255; i ++)
{
distance += Math.abs(actualHistogram[0][i] - expectedHistogram[0][i]);
distance += Math.abs(actualHistogram[1][i] - expectedHistogram[1][i]);
distance += Math.abs(actualHistogram[2][i] - expectedHistogram[2][i]);
distance += Math.abs(actualHistogram[3][i] - expectedHistogram[3][i]);
}
return distance;
}
protected int dpToPixels(int dp)
{
return (int) DialogHelper.dpToPixels(targetContext, dp);
}
}

@ -29,11 +29,11 @@ import android.text.Layout;
import android.text.StaticLayout; import android.text.StaticLayout;
import android.text.TextPaint; import android.text.TextPaint;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.util.Log;
import android.view.View; import android.view.View;
import org.isoron.uhabits.helpers.ColorHelper;
import org.isoron.uhabits.helpers.DialogHelper;
import org.isoron.uhabits.R; import org.isoron.uhabits.R;
import org.isoron.uhabits.helpers.DialogHelper;
public class RingView extends View public class RingView extends View
{ {
@ -48,10 +48,16 @@ public class RingView extends View
private int width; private int width;
private int height; private int height;
private float diameter; private float diameter;
private float maxDiameter; private float maxDiameter;
private float textSize; private float textSize;
private int fadedTextColor; private int fadedTextColor;
public RingView(Context context)
{
super(context);
init();
}
public RingView(Context context, AttributeSet attrs) public RingView(Context context, AttributeSet attrs)
{ {
@ -59,25 +65,28 @@ public class RingView extends View
this.label = DialogHelper.getAttribute(context, attrs, "label"); this.label = DialogHelper.getAttribute(context, attrs, "label");
this.maxDiameter = DialogHelper.getFloatAttribute(context, attrs, "maxDiameter"); this.maxDiameter = DialogHelper.getFloatAttribute(context, attrs, "maxDiameter");
this.maxDiameter = DialogHelper.dpToPixels(context, maxDiameter); this.maxDiameter = DialogHelper.dpToPixels(context, maxDiameter);
this.textSize = getResources().getDimension(R.dimen.smallTextSize);
this.color = ColorHelper.palette[7];
this.percentage = 0.75f;
init(); init();
} }
public void setColor(int color) public void setColor(int color)
{ {
this.color = color; this.color = color;
pRing.setColor(color); }
postInvalidate();
public void setMaxDiameter(float maxDiameter)
{
this.maxDiameter = maxDiameter;
}
public void setLabel(String label)
{
this.label = label;
} }
public void setPercentage(float percentage) public void setPercentage(float percentage)
{ {
this.percentage = percentage; this.percentage = percentage;
postInvalidate();
} }
private void init() private void init()
@ -88,6 +97,8 @@ public class RingView extends View
pRing.setTextAlign(Paint.Align.CENTER); pRing.setTextAlign(Paint.Align.CENTER);
fadedTextColor = getResources().getColor(R.color.fadedTextColor); fadedTextColor = getResources().getColor(R.color.fadedTextColor);
textSize = getResources().getDimension(R.dimen.smallTextSize);
Log.d("RingView", String.format("textSize=%f", textSize));
rect = new RectF(); rect = new RectF();
} }

Loading…
Cancel
Save