package com.svgandroid;
import android.graphics.LinearGradient;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.RadialGradient;
import android.graphics.RectF;
import android.graphics.Shader;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.xml.sax.SAXException;
import java.util.HashMap;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.core.Is.is;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
/**
* Created by Vlad Medvedev on 22.01.2016.
* vladislav.medvedev@devfactory.com
*/
@RunWith(PowerMockRunner.class)
@PrepareForTest({RectF.class})
public class SVGHandlerTest extends SVGHandlerTestSupport {
@Test
public void testScale() throws SAXException {
//given
when(canvas.getWidth()).thenReturn(2000);
when(canvas.getHeight()).thenReturn(500);
//when
parserHandler.startElement("", "svg", "svg", new AttributesMock(attr("width", "100px"), attr("height", "50px")));
//then
verify(canvas).translate(500f, 0.0f);
verify(canvas).scale(10f, 10f);
}
@Test
public void testParseGroup() throws SAXException {
//when
startSVG(parserHandler);
startElement(parserHandler, attributes(), "g");
startElement(parserHandler, attributes(attr("width", "100"), attr("height", "200"), attr("style", "stroke:#ff0000")), "rect");
endElement(parserHandler, "rect");
endElement(parserHandler, "g");
endSVG(parserHandler);
//then
verify(canvas).drawRect(0.0f, 0.0f, 100.0f, 200.0f, paint);
}
@Test
public void testParseGroup_boundsMode() throws Exception {
//given
RectF createdBounds = mock(RectF.class);
PowerMockito.whenNew(RectF.class).withArguments(eq(0.0f), eq(0.0f), eq(100.0f), eq(100.0f)).thenReturn(createdBounds);
//when
startSVG(parserHandler);
startElement(parserHandler, attributes(attr("id", "bounds"), attr("x", "0"), attr("y", "0"), attr("width", "400"), attr("height", "400")), "g");
startElement(parserHandler, attributes(attr("width", "100"), attr("height", "200"), attr("style", "stroke:#ff0000")), "rect");
endElement(parserHandler, "rect");
endElement(parserHandler, "g");
endSVG(parserHandler);
//then
assertThat(parserHandler.bounds, is(createdBounds));
verify(canvas, never()).drawRect(0.0f, 0.0f, 100.0f, 200.0f, paint);
}
@Test
public void testParseGroup_hidden() throws SAXException {
//when
startSVG(parserHandler);
startElement(parserHandler, attributes(), "g");
startElement(parserHandler, attributes(attr("width", "50"), attr("height", "50"), attr("style", "stroke:#ff0000")), "rect");
endElement(parserHandler, "rect");
//hidden group
startElement(parserHandler, attributes(attr("display", "none")), "g");
startElement(parserHandler, attributes(attr("width", "400"), attr("height", "400"), attr("style", "stroke:#ff0000")), "rect");
endElement(parserHandler, "rect");
endElement(parserHandler, "g");
endElement(parserHandler, "g");
endSVG(parserHandler);
//then
verify(canvas, never()).drawRect(0.0f, 0.0f, 400.0f, 400.0f, paint);
verify(canvas).drawRect(0.0f, 0.0f, 50.0f, 50.0f, paint);
}
@Test
public void testParseLine() throws SAXException {
//when
startSVG(parserHandler);
startElement(parserHandler, attributes(attr("x1", "0.0"), attr("y1", "0.0"), attr("x2", "10.0"), attr("y2", "10.0"), attr("style", "stroke:#ff0000")), "line");
endElement(parserHandler, "line");
endSVG(parserHandler);
//then
verify(canvas).drawLine(0.0f, 0.0f, 10.0f, 10.0f, paint);
}
@Test
public void testParseCircle() throws SAXException {
//when
startSVG(parserHandler);
startElement(parserHandler, attributes(attr("cx", "10.0"), attr("cy", "10.0"), attr("r", "5"), attr("style", "fill:#ff0000;stroke:#ff0000")), "circle");
endElement(parserHandler, "circle");
endSVG(parserHandler);
//then
verify(canvas, times(2)).drawCircle(10.0f, 10.0f, 5.0f, paint);
}
@Test
public void testParseEllipse() throws SAXException {
//when
startSVG(parserHandler);
RectF rectF = mock(RectF.class);
parserHandler.rect = rectF;
startElement(parserHandler, attributes(attr("cx", "10.0"), attr("cy", "10.0"), attr("rx", "5.0"), attr("ry", "5.0"), attr("style", "fill:#ff0000;stroke:#ff0000")), "ellipse");
endElement(parserHandler, "ellipse");
endSVG(parserHandler);
//then
verify(rectF).set(5.0f, 5.0f, 15.0f, 15.0f);
verify(canvas, times(2)).drawOval(rectF, paint);
}
@Test
public void testParseRect() throws SAXException {
//when
SVGParser.SVGHandler parserHandler = spy(this.parserHandler);
startSVG(parserHandler);
startElement(parserHandler, attributes(attr("width", "100"), attr("height", "200"), attr("style", "fill:#ff0000;stroke:#ff0000")), "rect");
endElement(parserHandler, "rect");
endSVG(parserHandler);
//then
verify(canvas, times(2)).drawRect(0.0f, 0.0f, 100.0f, 200.0f, paint);
}
@Test
public void testPushTransofrm() throws SAXException {
//given
SVGParser.SVGHandler parserHandler = spy(this.parserHandler);
// Matrix matrix = mock(Matrix.class);
// doReturn(matrix).when(parserHandler).createMatrix();
//when
startSVG(parserHandler);
startElement(parserHandler, attributes(attr("width", "100"), attr("height", "200"), attr("transform", "skewY(50)")), "rect");
endElement(parserHandler, "rect");
endSVG(parserHandler);
//then
verify(canvas).drawRect(0.0f, 0.0f, 100.0f, 200.0f, paint);
verify(canvas).save();
verify(canvas).concat(matrix);
verify(canvas).restore();
}
@Test
public void testParsePolygon() throws SAXException {
//given
SVGParser.SVGHandler parserHandler = spy(this.parserHandler);
// Path path = mock(Path.class);
// doReturn(path).when(parserHandler).createPath();
//when
startSVG(parserHandler);
startElement(parserHandler, attributes(attr("points", "220,10 300,210 170,250 123,234"), attr("style", "fill:#ff0000;stroke:#ff0000;stroke-width:1")), "polygon");
endElement(parserHandler, "polygon");
endSVG(parserHandler);
//then
verify(path).moveTo(220.0f, 10.0f);
verify(path).lineTo(300.0f, 210.0f);
verify(path).lineTo(170.0f, 250.0f);
verify(path).lineTo(123.0f, 234.0f);
verify(path).close();
verify(canvas, times(2)).drawPath(path, paint);
}
@Test
public void testParsePath() throws SAXException {
//given
SVGParser.SVGHandler parserHandler = Mockito.spy(this.parserHandler);
// Path path = mock(Path.class);
// doReturn(path).when(parserHandler).createPath();
//when
startSVG(parserHandler);
startElement(parserHandler, attributes(attr("d", "M150 0 L75 200 L225 200 Z"), attr("style", "fill:#ff0000;stroke:#ff0000;stroke-width:1")), "path");
endElement(parserHandler, "path");
endSVG(parserHandler);
//then
verify(canvas, times(2)).drawPath(path, paint);
}
@Test
public void testParseLinearGradient() throws Exception {
//given
when(picture.beginRecording(anyInt(), anyInt())).thenReturn(canvas);
LinearGradient linearGradient = mock(LinearGradient.class);
PowerMockito.whenNew(LinearGradient.class).withArguments(
eq(10.1f), eq(4.1f), eq(11.1f), eq(12.2f), eq(new int[]{-2130771968}), eq(new float[]{10.1f}), eq(Shader.TileMode.CLAMP)).
thenReturn(linearGradient);
//when
startSVG(parserHandler);
startElement(parserHandler, attributes(attr("id", "g1"), attr("x1", "10.1"), attr("y1", "4.1"), attr("x2", "11.1"), attr("y2", "12.2")), "linearGradient");
startElement(parserHandler, attributes(attr("offset", "10.1"), attr("style", "stop-color:#ff0000;stop-opacity:0.5")), "stop");
endElement(parserHandler, "stop");
endElement(parserHandler, "linearGradient");
startElement(parserHandler, attributes(attr("width", "100"), attr("height", "100"), attr("fill", "url(#g1)")), "rect");
endElement(parserHandler, "rect");
endSVG(parserHandler);
//then
verify(paint).setShader(linearGradient);
}
@Test
public void testParseLinearGradient_xlink() throws Exception {
//given
when(picture.beginRecording(anyInt(), anyInt())).thenReturn(canvas);
SVGParser.SVGHandler parserHandler = spy(this.parserHandler);
LinearGradient gr1 = mock(LinearGradient.class);
PowerMockito.whenNew(LinearGradient.class).withArguments(eq(10.1f), eq(4.1f), eq(11.1f), eq(0.0f), eq(new int[0]), eq(new float[0]), eq(Shader.TileMode.CLAMP)).
thenReturn(gr1);
LinearGradient gr2 = mock(LinearGradient.class);
PowerMockito.whenNew(LinearGradient.class).withArguments(eq(5.1f), eq(1.1f), eq(20.1f), eq(25.0f), eq(new int[0]), eq(new float[0]), eq(Shader.TileMode.CLAMP)).
thenReturn(gr2);
//when
startSVG(parserHandler);
//parent
startElement(parserHandler, attributes(attr("id", "gr1"), attr("x1", "10.1"), attr("y1", "4.1"), attr("x2", "11.1"), attr("gradientTransform", "matrix(0.2883 0 0 0.2865 153.3307 265.0264)")), "linearGradient");
endElement(parserHandler, "linearGradient");
//child
startElement(parserHandler, attributes(attr("id", "gr2"), attr("x1", "5.1"), attr("y1", "1.1"), attr("x2", "20.1"), attr("y2", "25.0"), attr("href", "#gr1")), "linearGradient");
endElement(parserHandler, "linearGradient");
endSVG(parserHandler);
//then
verify(gr2).setLocalMatrix(matrix);
}
@Test
public void testParseRadialGradient() throws Exception {
//given
when(picture.beginRecording(anyInt(), anyInt())).thenReturn(canvas);
SVGParser.SVGHandler parserHandler = spy(this.parserHandler);
RadialGradient gradient = mock(RadialGradient.class);
PowerMockito.whenNew(RadialGradient.class).withArguments(
eq(10.1f), eq(4.1f), eq(5.0f), eq(new int[]{-65536}), eq(new float[]{10.1f}), eq(Shader.TileMode.CLAMP)
).thenReturn(gradient);
//when
startSVG(parserHandler);
startElement(parserHandler, attributes(attr("id", "g1"), attr("cx", "10.1"), attr("cy", "4.1"), attr("r", "5.0")), "radialGradient");
startElement(parserHandler, attributes(attr("offset", "10.1"), attr("style", "stop-color:ff0000")), "stop");
endElement(parserHandler, "stop");
endElement(parserHandler, "radialGradient");
startElement(parserHandler, attributes(attr("width", "100"), attr("height", "100"), attr("fill", "url(#g1)")), "rect");
endElement(parserHandler, "rect");
endSVG(parserHandler);
//then
verify(paint).setShader(gradient);
;
}
@Test
public void testParseRadialGradient_xlink() throws Exception {
//given
when(picture.beginRecording(anyInt(), anyInt())).thenReturn(canvas);
SVGParser.SVGHandler parserHandler = spy(this.parserHandler);
RadialGradient gr1 = mock(RadialGradient.class);
PowerMockito.whenNew(RadialGradient.class).withArguments(eq(10.1f), eq(4.1f), eq(5.0f), eq(new int[0]), eq(new float[0]), eq(Shader.TileMode.CLAMP)).
thenReturn(gr1);
RadialGradient gr2 = mock(RadialGradient.class);
PowerMockito.whenNew(RadialGradient.class).withArguments(eq(5.0f), eq(5.0f), eq(2.0f), eq(new int[0]), eq(new float[0]), eq(Shader.TileMode.CLAMP)).
thenReturn(gr2);
Matrix subMatrix = mock(Matrix.class);
PowerMockito.whenNew(Matrix.class).withArguments(matrix).thenReturn(subMatrix);
//when
startSVG(parserHandler);
//parent gradient
startElement(parserHandler, attributes(attr("id", "gr1"), attr("cx", "10.1"), attr("cy", "4.1"), attr("r", "5.0"), attr("gradientTransform", "matrix(0.2883 0 0 0.2865 153.3307 265.0264)")), "radialGradient");
endElement(parserHandler, "radialGradient");
//child gradient
startElement(parserHandler, attributes(attr("id", "gr2"), attr("cx", "5.0"), attr("cy", "5.0"), attr("r", "2.0"), attr("href", "#gr1")), "radialGradient");
endElement(parserHandler, "radialGradient");
endSVG(parserHandler);
//then
verify(gr1, times(1)).setLocalMatrix(matrix);
verify(gr2, times(1)).setLocalMatrix(subMatrix);
verify(matrix).setValues(new float[]{0.2883f, 0.0f, 153.3307f, 0.0f, 0.2865f, 265.0264f, 0.0f, 0.0f, 1.0f});
}
@Test
public void testDoFill_none() {
boolean res = parserHandler.doFill(
new SVGParser.Properties(attributes(attr("display", "none"))),
new HashMap<String, Shader>());
assertThat(res, is(false));
}
@Test
public void testDoFill_whiteMode() {
parserHandler.setWhiteMode(true);
boolean res = parserHandler.doFill(
new SVGParser.Properties(attributes()),
new HashMap<String, Shader>());
verify(paint).setStyle(Paint.Style.FILL);
verify(paint).setColor(0xFFFFFFFF);
assertThat(res, is(true));
}
@Test
public void testDoFill_byURL() {
//given
HashMap<String, Shader> gradients = new HashMap<>();
Shader shader = mock(Shader.class);
gradients.put("gr1", shader);
//when
boolean res = parserHandler.doFill(
new SVGParser.Properties(attributes(attr("fill", "url(#gr1)"))),
gradients);
//then
assertThat(res, is(true));
verify(paint).setShader(shader);
verify(paint).setStyle(Paint.Style.FILL);
}
@Test
public void testDoFill_byURL_shaderNotFound() {
//given
HashMap<String, Shader> gradients = new HashMap<>();
Shader shader = mock(Shader.class);
gradients.put("gr1", shader);
//when
boolean res = parserHandler.doFill(
new SVGParser.Properties(attributes(attr("fill", "#gr2)"))),
gradients);
//then
assertThat(res, is(false));
}
@Test
public void testDoFill_byHexColor() {
//given
SVGParser.Properties properties = new SVGParser.Properties(attributes(attr("fill", "#ff0000")));
//when
boolean res = parserHandler.doFill(
properties,
new HashMap<String, Shader>());
//then
verify(paint).setStyle(Paint.Style.FILL);
Integer hexColor = properties.getHex("fill");
verify(paint).setColor((0xFFFFFF & hexColor) | 0xFF000000);
assertThat(res, is(true));
}
@Test
public void testDoFill_default() {
boolean res = parserHandler.doFill(
new SVGParser.Properties(attributes()),
new HashMap<String, Shader>());
verify(paint).setStyle(Paint.Style.FILL);
verify(paint).setColor(0xFF000000);
assertThat(res, is(true));
}
@Test
public void testDoStroke_whiteModeTrue() {
parserHandler.setWhiteMode(true);
assertThat(parserHandler.doStroke(new SVGParser.Properties(attributes())), is(false));
}
@Test
public void testDoStroke_displayNone() {
assertThat(parserHandler.doStroke(new SVGParser.Properties(attributes())), is(false));
}
@Test
public void testDoStroke() {
assertThat(parserHandler.doStroke(new SVGParser.Properties(attributes(attr("stroke", "#ff0000")))), is(true));
verify(paint).setStyle(Paint.Style.STROKE);
}
private void testDoStroke_strokeLinecap(String val) {
assertThat(parserHandler.doStroke(new SVGParser.Properties(attributes(attr("stroke", "#ff0000"), attr("stroke-linecap", val)))), is(true));
verify(paint).setStyle(Paint.Style.STROKE);
}
@Test
public void testDoStroke_strokeLinecapRound() {
testDoStroke_strokeLinecap("round");
verify(paint).setStrokeCap(Paint.Cap.ROUND);
}
@Test
public void testDoStroke_strokeLinecapSquare() {
testDoStroke_strokeLinecap("square");
verify(paint).setStrokeCap(Paint.Cap.SQUARE);
}
@Test
public void testDoStroke_strokeLinecapButt() {
testDoStroke_strokeLinecap("butt");
verify(paint).setStrokeCap(Paint.Cap.BUTT);
}
private void testDoStroke_linejoin(String val) {
assertThat(parserHandler.doStroke(new SVGParser.Properties(attributes(attr("stroke", "#ff0000"), attr("stroke-linejoin", val)))), is(true));
verify(paint).setStyle(Paint.Style.STROKE);
}
@Test
public void testDoStroke_linejoinMiter() {
testDoStroke_linejoin("miter");
verify(paint).setStrokeJoin(Paint.Join.MITER);
}
@Test
public void testDoStroke_linejoinRound() {
testDoStroke_linejoin("round");
verify(paint).setStrokeJoin(Paint.Join.ROUND);
}
@Test
public void testDoStroke_linejoinBevel() {
testDoStroke_linejoin("bevel");
verify(paint).setStrokeJoin(any(Paint.Join.class));
}
}