package test; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import java.io.IOException; import java.util.Date; import org.junit.BeforeClass; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import cz.vutbr.web.css.CSSException; import cz.vutbr.web.css.CSSFactory; import cz.vutbr.web.css.CSSProperty; import cz.vutbr.web.css.Declaration; import cz.vutbr.web.css.RuleSet; import cz.vutbr.web.css.StyleSheet; import cz.vutbr.web.css.TermAngle; import cz.vutbr.web.css.TermCalc; import cz.vutbr.web.css.TermFactory; import cz.vutbr.web.css.TermFloatValue; import cz.vutbr.web.css.TermFunction; import cz.vutbr.web.css.TermLengthOrPercent; import cz.vutbr.web.css.TermNumeric.Unit; import cz.vutbr.web.css.TermRect; import cz.vutbr.web.css.TermString; import cz.vutbr.web.csskit.CalcArgs; import cz.vutbr.web.csskit.fn.AttrImpl; import cz.vutbr.web.csskit.fn.BlurImpl; import cz.vutbr.web.csskit.fn.BrightnessImpl; import cz.vutbr.web.csskit.fn.ContrastImpl; import cz.vutbr.web.csskit.fn.CounterImpl; import cz.vutbr.web.csskit.fn.CountersImpl; import cz.vutbr.web.csskit.fn.DropShadowImpl; import cz.vutbr.web.csskit.fn.GrayscaleImpl; import cz.vutbr.web.csskit.fn.HueRotateImpl; import cz.vutbr.web.csskit.fn.InvertImpl; import cz.vutbr.web.csskit.fn.LinearGradientImpl; import cz.vutbr.web.csskit.fn.Matrix3dImpl; import cz.vutbr.web.csskit.fn.MatrixImpl; import cz.vutbr.web.csskit.fn.OpacityImpl; import cz.vutbr.web.csskit.fn.PerspectiveImpl; import cz.vutbr.web.csskit.fn.RadialGradientImpl; import cz.vutbr.web.csskit.fn.RepeatingLinearGradientImpl; import cz.vutbr.web.csskit.fn.Rotate3dImpl; import cz.vutbr.web.csskit.fn.RotateImpl; import cz.vutbr.web.csskit.fn.RotateXImpl; import cz.vutbr.web.csskit.fn.RotateYImpl; import cz.vutbr.web.csskit.fn.RotateZImpl; import cz.vutbr.web.csskit.fn.SaturateImpl; import cz.vutbr.web.csskit.fn.Scale3dImpl; import cz.vutbr.web.csskit.fn.ScaleImpl; import cz.vutbr.web.csskit.fn.ScaleXImpl; import cz.vutbr.web.csskit.fn.ScaleYImpl; import cz.vutbr.web.csskit.fn.ScaleZImpl; import cz.vutbr.web.csskit.fn.SepiaImpl; import cz.vutbr.web.csskit.fn.SkewImpl; import cz.vutbr.web.csskit.fn.SkewXImpl; import cz.vutbr.web.csskit.fn.SkewYImpl; import cz.vutbr.web.csskit.fn.Translate3dImpl; import cz.vutbr.web.csskit.fn.TranslateImpl; import cz.vutbr.web.csskit.fn.TranslateXImpl; import cz.vutbr.web.csskit.fn.TranslateYImpl; import cz.vutbr.web.csskit.fn.TranslateZImpl; public class FunctionsTest { private static final Logger log = LoggerFactory.getLogger(FunctionsTest.class); public static final TermFactory tf = CSSFactory.getTermFactory(); /* parentheses in strings - pair matching test */ public static final String TEST_DECL1A = " a:after { content: \"(\" attr(href) \")\"; border: 1px solid red; }"; public static final String TEST_DECL1B = " a:after { content: \"{\" attr(href) \"}\"; border: 1px solid red; }"; /* function name may start with minus */ public static final String TEST_DECL2A = " a:after { background-image:-moz-linear-gradient(top,#fff,#ececec); border: 1px solid red; }"; /* function arguments may include minus */ public static final String TEST_DECL3A = "img { translate: translateY(-.1em) }"; /* different rect() syntaxes */ public static final String TEST_RECT1 = "p { clip: rect(1px 10em 3rem 2ch); color: red; }"; public static final String TEST_RECT2 = "p { clip: rect(1px, 10em, 3rem, 2ch); color: red; }"; public static final String TEST_RECT3 = "p { clip: rect(1px, 10em, 3rem, auto); color: red; }"; /* calc() length expressions (all should evaluate to 60.0) */ public static final String TEST_CALC_L[] = new String[] { "p { width: calc(60px); color: red; }", "p { width: calc(1em + 0.5em); color: red; }", "p { width: calc(1em + (10% * 2)); color: red; }", "p { width: calc(-3em + 4.5em); color: red; }", "p { width: calc(3em + (-1.5em)); color: red; }", "p { width: calc(3em - 1.5em); color: red; }" }; /* calc() angle expressions (all should evaluate to 33) */ public static final String TEST_CALC_A[]; static { TEST_CALC_A = new String[1]; TEST_CALC_A[0] = "p { azimuth: calc(30deg + 6rad); color: red; }"; } /* invalid calc() expressions (all width declarations should be skipped) */ public static final String TEST_CALC_I[]; static { TEST_CALC_I = new String[1]; TEST_CALC_I[0] = "p { width: calc(30deg + 3em * 2); color: red; }"; //mixed types in expression } /* valid transform functions */ public static final String TEST_TRANSFORM[] = new String[] { "p { transform: matrix(1, 2, -1, 1.2, 80, 80); }", "p { transform: matrix3d(1.1, 2.2, 0, 4.4, 5.5, -6.6, 7.7, 8.8, 9, 10, -11, 12, 13.0, 14, 15, 16); }", "p { transform: perspective(800px); }", "p { transform: perspective(0); }", "p { transform: rotate(45deg); }", "p { transform: rotate(0); }", "p { transform: rotate3d(1, 1, 1, 45deg); }", "p { transform: rotate3d(2, -1, -1, -0.2turn); }", "p { transform: rotateX(-0.2turn); }", "p { transform: rotateX(0); }", "p { transform: rotateY(-0.2turn); }", "p { transform: rotateY(0); }", "p { transform: rotateZ(-0.2turn); }", "p { transform: rotateZ(0); }", "p { transform: scale(1.5, 1.2); }", "p { transform: scale(1.3); }", "p { transform: scale3d(-0.5, 1, 1.7); }", "p { transform: scaleX(1.5); }", "p { transform: scaleY(-1.5); }", "p { transform: scaleZ(1); }", "p { transform: skew(0); }", "p { transform: skew(15deg, 15deg); }", "p { transform: skew(.312rad); }", "p { transform: skewX(-35deg); }", "p { transform: skewY(0); }", "p { transform: translate(10px); }", "p { transform: translate(10px, 25%); }", "p { transform: translate(0, 12pt); }", "p { transform: translate3d(5ch, -0.4in, 5em); }", "p { transform: translateX(10px); }", "p { transform: translateY(-1.5em); }", "p { transform: translateZ(0); }" }; /* invalid transform functions; only the float declaration should be accepted */ public static final String TEST_TRANSFORM_INVALID[] = new String[] { "p { float: left; transform: scale(1.5, 1.2, 1.1); }", "p { float: left; transform: scale(); }" }; /* valid gradient functions */ public static final String TEST_GRADIENT[] = new String[] { "p { background: linear-gradient(#e66465, #9198e5); }", "p { background: linear-gradient(0.25turn, red, #ebf8e1, #f69d3c); }", "p { background: linear-gradient(to left, #333, #333 50%, #eee 75%, #333 75%); }", "p { background: linear-gradient(to bottom right, #333, #333 50%, #eee); }", "p { background: repeating-linear-gradient(#e66465, #9198e5); }", "p { background: repeating-linear-gradient(0.25turn, red, #ebf8e1, #f69d3c); }", "p { background: repeating-linear-gradient(to left, #333, #333 50%, #eee 75%, #333 75%); }", "p { background: repeating-linear-gradient(to bottom right, #333, #333 50%, #eee); }", "p { background: radial-gradient(cyan 0%, transparent 20%, salmon 40%); }", "p { background: radial-gradient(farthest-corner at 30px 40px, #f35 0%, #43e 100%); }", "p { background: radial-gradient(#e66465, #9198e5); }", "p { background: radial-gradient(closest-side, #3f87a6, #ebf8e1, #f69d3c); }", "p { background: radial-gradient(circle at 100%, #333, #333 50%, #eee 75%, #333 75%); }", "p { background: radial-gradient(circle 10px at 100%, #333, #eee); }", "p { background: radial-gradient(ellipse 10px 55% at 10px 20px, #333, #eee); }", "p { background: radial-gradient(10px at center, #333, #eee); }", "p { background: radial-gradient(10% 12% at center, #333, #eee); }", "p { background: radial-gradient(ellipse at top, #e66465, transparent), radial-gradient(ellipse at bottom, #4d9f0c, transparent); }", }; /* invalid gradient functions; only the float declaration should be accepted */ public static final String TEST_GRADIENT_INVALID[] = new String[] { "p { float: left; background: linear-gradient(12pt, red); }", "p { float: left; background: linear-gradient(to top bottom, red, blue); }", "p { float: left; background: linear-gradient(top left, red, blue); }", "p { float: left; background: linear-gradient(to nowhere, red, blue); }", "p { float: left; background: radial-gradient(circle 10% at 100%, #333, #eee); }", "p { float: left; background: radial-gradient(circle 10px 20px at 100%, #333, #eee); }", "p { float: left; background: radial-gradient(ellipse 10px at 10px 20px, #333, #eee); }", "p { float: left; background: radial-gradient(ellipse at 10px 20px 30px, #333, #eee); }", "p { float: left; background: radial-gradient(ellipse unknown at top bottom, #333, #eee); }" }; /* valid filter functions */ public static final String TEST_FILTER[] = new String[] { "p { filter: blur(1.2em); }", "p { filter: brightness(1.75); }", "p { filter: contrast(200%); }", "p { filter: drop-shadow(30px 10px 4px #4444dd); }", "p { filter: drop-shadow(-30px -10px red); }", "p { filter: grayscale(1); }", "p { filter: hue-rotate(-3.142rad); }", "p { filter: invert(0.30); }", "p { filter: opacity(0); }", "p { filter: saturate(50%); }", "p { filter: sepia(1); }", }; /* valid content functions */ public static final String TEST_CONTENT[] = new String[] { "p:before { content: attr(title); }", "p:before { content: counter(chapter_counter); }", "p:before { content: counter(chapter_counter, lower-alpha); }", "p:before { content: counters(chapter_counter, '..'); }", "p:before { content: counters(chapter_counter, '::', lower-roman); }", "p:before { content: counter(c, none) \"z\"; }" }; /* invalid content functions */ public static final String TEST_CONTENT_INVALID[] = new String[] { "p:before { font-weight: bold; content: counter(chapter_counter, '.'); }", "p:before { font-weight: bold; content: counter(chapter_counter, weird); }", "p:before { font-weight: bold; content: counters(chapter_counter); }", "p:before { font-weight: bold; content: counters(chapter_counter, '::', unknown); }", }; @BeforeClass public static void init() { log.info("\n\n\n == Functions test at {} == \n\n\n", new Date()); } @Test public void vendorSpecificUnderscore() throws IOException, CSSException { StyleSheet ss = CSSFactory.parseString(TEST_DECL1A, null); assertEquals("Two properties are accepted", 2, ss.get(0).size()); final RuleSet rule = (RuleSet) ss.get(0); assertEquals("The first property value has three terms", 3, rule.get(0).size()); } @Test public void vendorSpecificFunctions() throws IOException, CSSException { StyleSheet ss = CSSFactory.parseString(TEST_DECL2A, null); assertEquals("Two properties are accepted", 2, ss.get(0).size()); Declaration d = (Declaration) ss.get(0).get(0); TermFunction f = (TermFunction) d.get(0); char first = f.getFunctionName().charAt(0); assertEquals("Function name starts with minus", '-', first); } @Test public void negativeArgument() throws IOException, CSSException { StyleSheet ss = CSSFactory.parseString(TEST_DECL3A, null); assertEquals("One properties is accepted", 1, ss.get(0).size()); Declaration d = (Declaration) ss.get(0).get(0); TermFunction f = (TermFunction) d.get(0); assertEquals("The argument is -0.1em", tf.createLength(-0.1f, Unit.em), f.get(0)); } @Test public void rectFunctions() throws IOException, CSSException { StyleSheet ss1 = CSSFactory.parseString(TEST_RECT1, null); assertEquals("Two properties are accepted", 2, ss1.get(0).size()); Declaration d1 = (Declaration) ss1.get(0).get(0); TermRect r1 = (TermRect) d1.get(0); assertEquals("The last one is a correct length", tf.createLength(2f, Unit.ch), r1.getValue().get(3)); StyleSheet ss2 = CSSFactory.parseString(TEST_RECT2, null); assertEquals("Two properties are accepted", 2, ss2.get(0).size()); Declaration d2 = (Declaration) ss2.get(0).get(0); TermRect r2 = (TermRect) d2.get(0); assertEquals("The last one is a correct length", tf.createLength(2f, Unit.ch), r2.getValue().get(3)); StyleSheet ss3 = CSSFactory.parseString(TEST_RECT3, null); assertEquals("Two properties are accepted", 2, ss3.get(0).size()); Declaration d3 = (Declaration) ss3.get(0).get(0); TermRect r3 = (TermRect) d3.get(0); assertEquals("The last one is a correct length", null, r3.getValue().get(3)); } @Test public void calcLengths() throws IOException, CSSException { PxEvaluator eval = new PxEvaluator(); for (int i = 0; i < TEST_CALC_L.length; i++) { StyleSheet ss = CSSFactory.parseString(TEST_CALC_L[i], null); assertEquals("Two properties are accepted [" + i + "]", 2, ss.get(0).size()); Declaration d = (Declaration) ss.get(0).get(0); TermCalc calc = (TermCalc) d.get(0); Double result = calc.getArgs().evaluate(eval); assertEquals("Experssion result is correct [" + i + "]", 60.0, result.doubleValue(), 0.000001); } } @Test public void calcAngles() throws IOException, CSSException { DegEvaluator eval = new DegEvaluator(); for (int i = 0; i < TEST_CALC_A.length; i++) { StyleSheet ss = CSSFactory.parseString(TEST_CALC_A[i], null); assertEquals("Two properties are accepted [" + i + "]", 2, ss.get(0).size()); Declaration d = (Declaration) ss.get(0).get(0); TermCalc calc = (TermCalc) d.get(0); Double result = calc.getArgs().evaluate(eval); assertEquals("Experssion result is correct [" + i + "]", 33.0, result.doubleValue(), 0.000001); } } @Test public void calcInvalid() throws IOException, CSSException { for (int i = 0; i < TEST_CALC_I.length; i++) { StyleSheet ss = CSSFactory.parseString(TEST_CALC_I[i], null); assertEquals("Only one property is accepted [" + i + "]", 1, ss.get(0).size()); } } @Test public void transformValid() throws IOException, CSSException { for (int i = 0; i < TEST_TRANSFORM.length; i++) { StyleSheet ss = CSSFactory.parseString(TEST_TRANSFORM[i], null); //System.out.println(i + " ss: " + ss); assertEquals("One rule is parset [" + i + "]", 1, ss.size()); assertEquals("One property is set [" + i + "]", 1, ss.get(0).size()); Declaration d = (Declaration) ss.get(0).get(0); TermFunction fn = (TermFunction) d.get(0); //System.out.println(i + ": " + d); switch (i) { case 0: assertEquals(MatrixImpl.class, fn.getClass()); break; case 1: assertEquals(Matrix3dImpl.class, fn.getClass()); break; case 2: assertEquals(PerspectiveImpl.class, fn.getClass()); break; case 3: assertEquals(PerspectiveImpl.class, fn.getClass()); break; case 4: assertEquals(RotateImpl.class, fn.getClass()); assertEquals("Angle is correct", tf.createAngle("45", Unit.deg, 1), ((RotateImpl) fn).getAngle()); break; case 5: assertEquals(RotateImpl.class, fn.getClass()); assertEquals("Angle is correct", tf.createAngle(0.0f), ((RotateImpl) fn).getAngle()); break; case 6: assertEquals(Rotate3dImpl.class, fn.getClass()); break; case 7: assertEquals(Rotate3dImpl.class, fn.getClass()); break; case 8: assertEquals(RotateXImpl.class, fn.getClass()); break; case 9: assertEquals(RotateXImpl.class, fn.getClass()); break; case 10: assertEquals(RotateYImpl.class, fn.getClass()); break; case 11: assertEquals(RotateYImpl.class, fn.getClass()); break; case 12: assertEquals(RotateZImpl.class, fn.getClass()); break; case 13: assertEquals(RotateZImpl.class, fn.getClass()); break; case 14: assertEquals(ScaleImpl.class, fn.getClass()); assertEquals("ScaleX is correct", 1.5f, ((ScaleImpl) fn).getScaleX(), 0.001f); assertEquals("ScaleY is correct", 1.2f, ((ScaleImpl) fn).getScaleY(), 0.001f); break; case 15: assertEquals(ScaleImpl.class, fn.getClass()); assertEquals("ScaleX is correct", 1.3f, ((ScaleImpl) fn).getScaleX(), 0.001f); assertEquals("ScaleY is correct", 1.3f, ((ScaleImpl) fn).getScaleY(), 0.001f); break; case 16: assertEquals(Scale3dImpl.class, fn.getClass()); assertEquals("ScaleX is correct", -0.5f, ((Scale3dImpl) fn).getScaleX(), 0.001f); assertEquals("ScaleY is correct", 1f, ((Scale3dImpl) fn).getScaleY(), 0.001f); assertEquals("ScaleZ is correct", 1.7f, ((Scale3dImpl) fn).getScaleZ(), 0.001f); break; case 17: assertEquals(ScaleXImpl.class, fn.getClass()); assertEquals("Scale is correct", 1.5f, ((ScaleXImpl) fn).getScale(), 0.001f); break; case 18: assertEquals(ScaleYImpl.class, fn.getClass()); assertEquals("Scale is correct", -1.5f, ((ScaleYImpl) fn).getScale(), 0.001f); break; case 19: assertEquals(ScaleZImpl.class, fn.getClass()); assertEquals("Scale is correct", 1f, ((ScaleZImpl) fn).getScale(), 0.001f); break; case 20: assertEquals(SkewImpl.class, fn.getClass()); break; case 21: assertEquals(SkewImpl.class, fn.getClass()); break; case 22: assertEquals(SkewImpl.class, fn.getClass()); break; case 23: assertEquals(SkewXImpl.class, fn.getClass()); break; case 24: assertEquals(SkewYImpl.class, fn.getClass()); break; case 25: assertEquals(TranslateImpl.class, fn.getClass()); assertEquals("Length X is correct", tf.createLength("10", Unit.px, 1), ((TranslateImpl) fn).getTranslateX()); assertEquals("Length Y is correct", tf.createLength(0.0f), ((TranslateImpl) fn).getTranslateY()); break; case 26: assertEquals(TranslateImpl.class, fn.getClass()); assertEquals("Length X is correct", tf.createLength("10", Unit.px, 1), ((TranslateImpl) fn).getTranslateX()); assertEquals("Length Y is correct", tf.createPercent(25.0f), ((TranslateImpl) fn).getTranslateY()); break; case 27: assertEquals(TranslateImpl.class, fn.getClass()); assertEquals("Length X is correct", tf.createInteger(0), ((TranslateImpl) fn).getTranslateX()); assertEquals("Length Y is correct", tf.createLength("12", Unit.pt, 1), ((TranslateImpl) fn).getTranslateY()); break; case 28: assertEquals(Translate3dImpl.class, fn.getClass()); break; case 29: assertEquals(TranslateXImpl.class, fn.getClass()); break; case 30: assertEquals(TranslateYImpl.class, fn.getClass()); break; case 31: assertEquals(TranslateZImpl.class, fn.getClass()); break; } } } @Test public void transformInvalid() throws IOException, CSSException { for (int i = 0; i < TEST_TRANSFORM_INVALID.length; i++) { StyleSheet ss = CSSFactory.parseString(TEST_TRANSFORM_INVALID[i], null); assertEquals("One rule is parset [" + i + "]", 1, ss.size()); assertEquals("One property is set [" + i + "]", 1, ss.get(0).size()); } } @Test public void gradientValid() throws IOException, CSSException { for (int i = 0; i < TEST_GRADIENT.length; i++) { StyleSheet ss = CSSFactory.parseString(TEST_GRADIENT[i], null); //System.out.println(i + " ss: " + ss); assertEquals("One rule is parsed [" + i + "]", 1, ss.size()); assertEquals("One property is set [" + i + "]", 1, ss.get(0).size()); Declaration d = (Declaration) ss.get(0).get(0); TermFunction fn = (TermFunction) d.get(0); //System.out.println(i + ": " + d); switch (i) { case 0: assertEquals(LinearGradientImpl.class, fn.getClass()); assertNull("Angle is not set", ((LinearGradientImpl) fn).getAngle()); assertEquals("Two stops are set", 2, ((LinearGradientImpl) fn).getColorStops().size()); assertEquals("First stop color", tf.createColor("#e66465"), ((LinearGradientImpl) fn).getColorStops().get(0).getColor()); assertNull("First stop length", ((LinearGradientImpl) fn).getColorStops().get(0).getLength()); assertEquals("Second stop color", tf.createColor("#9198e5"), ((LinearGradientImpl) fn).getColorStops().get(1).getColor()); assertNull("Second stop length", ((LinearGradientImpl) fn).getColorStops().get(1).getLength()); break; case 1: assertEquals(LinearGradientImpl.class, fn.getClass()); assertEquals("Angle", tf.createAngle("0.25", Unit.turn, 1), ((LinearGradientImpl) fn).getAngle()); assertEquals("Three stops are set", 3, ((LinearGradientImpl) fn).getColorStops().size()); assertEquals("First stop color", tf.createColor("#ff0000"), ((LinearGradientImpl) fn).getColorStops().get(0).getColor()); assertNull("First stop length", ((LinearGradientImpl) fn).getColorStops().get(0).getLength()); assertEquals("Last stop color", tf.createColor("#f69d3c"), ((LinearGradientImpl) fn).getColorStops().get(2).getColor()); assertNull("Last stop length", ((LinearGradientImpl) fn).getColorStops().get(2).getLength()); break; case 2: assertEquals(LinearGradientImpl.class, fn.getClass()); assertEquals("Angle", tf.createAngle("270", Unit.deg, 1), ((LinearGradientImpl) fn).getAngle()); assertEquals("Four stops are set", 4, ((LinearGradientImpl) fn).getColorStops().size()); assertEquals("First stop color", tf.createColor("#333333"), ((LinearGradientImpl) fn).getColorStops().get(0).getColor()); assertNull("First stop length", ((LinearGradientImpl) fn).getColorStops().get(0).getLength()); assertEquals("Last stop color", tf.createColor("#333333"), ((LinearGradientImpl) fn).getColorStops().get(3).getColor()); assertEquals("Last stop length", tf.createPercent(75.0f), ((LinearGradientImpl) fn).getColorStops().get(3).getLength()); break; case 3: assertEquals(LinearGradientImpl.class, fn.getClass()); assertEquals("Angle", tf.createAngle("135", Unit.deg, 1), ((LinearGradientImpl) fn).getAngle()); assertEquals("Three stops are set", 3, ((LinearGradientImpl) fn).getColorStops().size()); assertEquals("First stop color", tf.createColor("#333333"), ((LinearGradientImpl) fn).getColorStops().get(0).getColor()); assertNull("First stop length", ((LinearGradientImpl) fn).getColorStops().get(0).getLength()); assertEquals("Second stop color", tf.createColor("#333333"), ((LinearGradientImpl) fn).getColorStops().get(1).getColor()); assertEquals("Second stop length", tf.createPercent(50.0f), ((LinearGradientImpl) fn).getColorStops().get(1).getLength()); break; case 4: assertEquals(RepeatingLinearGradientImpl.class, fn.getClass()); assertNull("Angle is not set", ((RepeatingLinearGradientImpl) fn).getAngle()); assertEquals("Two stops are set", 2, ((RepeatingLinearGradientImpl) fn).getColorStops().size()); assertEquals("First stop color", tf.createColor("#e66465"), ((RepeatingLinearGradientImpl) fn).getColorStops().get(0).getColor()); assertNull("First stop length", ((RepeatingLinearGradientImpl) fn).getColorStops().get(0).getLength()); assertEquals("Second stop color", tf.createColor("#9198e5"), ((RepeatingLinearGradientImpl) fn).getColorStops().get(1).getColor()); assertNull("Second stop length", ((RepeatingLinearGradientImpl) fn).getColorStops().get(1).getLength()); break; case 5: assertEquals(RepeatingLinearGradientImpl.class, fn.getClass()); assertEquals("Angle", tf.createAngle("0.25", Unit.turn, 1), ((RepeatingLinearGradientImpl) fn).getAngle()); assertEquals("Three stops are set", 3, ((RepeatingLinearGradientImpl) fn).getColorStops().size()); assertEquals("First stop color", tf.createColor("#ff0000"), ((RepeatingLinearGradientImpl) fn).getColorStops().get(0).getColor()); assertNull("First stop length", ((RepeatingLinearGradientImpl) fn).getColorStops().get(0).getLength()); assertEquals("Last stop color", tf.createColor("#f69d3c"), ((RepeatingLinearGradientImpl) fn).getColorStops().get(2).getColor()); assertNull("Last stop length", ((RepeatingLinearGradientImpl) fn).getColorStops().get(2).getLength()); break; case 6: assertEquals(RepeatingLinearGradientImpl.class, fn.getClass()); assertEquals("Angle", tf.createAngle("270", Unit.deg, 1), ((RepeatingLinearGradientImpl) fn).getAngle()); assertEquals("Four stops are set", 4, ((RepeatingLinearGradientImpl) fn).getColorStops().size()); assertEquals("First stop color", tf.createColor("#333333"), ((RepeatingLinearGradientImpl) fn).getColorStops().get(0).getColor()); assertNull("First stop length", ((RepeatingLinearGradientImpl) fn).getColorStops().get(0).getLength()); assertEquals("Last stop color", tf.createColor("#333333"), ((RepeatingLinearGradientImpl) fn).getColorStops().get(3).getColor()); assertEquals("Last stop length", tf.createPercent(75.0f), ((RepeatingLinearGradientImpl) fn).getColorStops().get(3).getLength()); break; case 7: assertEquals(RepeatingLinearGradientImpl.class, fn.getClass()); assertEquals("Angle", tf.createAngle("135", Unit.deg, 1), ((RepeatingLinearGradientImpl) fn).getAngle()); assertEquals("Three stops are set", 3, ((RepeatingLinearGradientImpl) fn).getColorStops().size()); assertEquals("First stop color", tf.createColor("#333333"), ((RepeatingLinearGradientImpl) fn).getColorStops().get(0).getColor()); assertNull("First stop length", ((RepeatingLinearGradientImpl) fn).getColorStops().get(0).getLength()); assertEquals("Second stop color", tf.createColor("#333333"), ((RepeatingLinearGradientImpl) fn).getColorStops().get(1).getColor()); assertEquals("Second stop length", tf.createPercent(50.0f), ((RepeatingLinearGradientImpl) fn).getColorStops().get(1).getLength()); break; case 8: assertEquals(RadialGradientImpl.class, fn.getClass()); assertNull("No size", ((RadialGradientImpl) fn).getSize()); assertEquals("Size ident", tf.createIdent("farthest-corner"), ((RadialGradientImpl) fn).getSizeIdent()); assertEquals("Shape is ellipse", tf.createIdent("ellipse"), ((RadialGradientImpl) fn).getShape()); assertEquals("Default position", 2, ((RadialGradientImpl) fn).getPosition().length); assertEquals("Three stops are set", 3, ((RadialGradientImpl) fn).getColorStops().size()); assertEquals("First stop color", tf.createColor("#00ffff"), ((RadialGradientImpl) fn).getColorStops().get(0).getColor()); assertEquals("First stop length", tf.createPercent(0f), ((RadialGradientImpl) fn).getColorStops().get(0).getLength()); assertEquals("Second stop color", tf.createColor(tf.createIdent("transparent")), ((RadialGradientImpl) fn).getColorStops().get(1).getColor()); assertEquals("Second stop length", tf.createPercent(20.0f), ((RadialGradientImpl) fn).getColorStops().get(1).getLength()); break; case 9: assertEquals(RadialGradientImpl.class, fn.getClass()); assertNull("No size", ((RadialGradientImpl) fn).getSize()); assertEquals("Size ident", tf.createIdent("farthest-corner"), ((RadialGradientImpl) fn).getSizeIdent()); assertEquals("Shape is ellipse", tf.createIdent("ellipse"), ((RadialGradientImpl) fn).getShape()); assertEquals("Position is set", 2, ((RadialGradientImpl) fn).getPosition().length); assertEquals("Position 1 is correct", tf.createLength(30.0f, Unit.px), ((RadialGradientImpl) fn).getPosition()[0]); assertEquals("Position 2 is correct", tf.createLength(40.0f, Unit.px), ((RadialGradientImpl) fn).getPosition()[1]); assertEquals("Two stops are set", 2, ((RadialGradientImpl) fn).getColorStops().size()); break; case 10: assertEquals(RadialGradientImpl.class, fn.getClass()); assertNull("No size", ((RadialGradientImpl) fn).getSize()); assertEquals("Size ident", tf.createIdent("farthest-corner"), ((RadialGradientImpl) fn).getSizeIdent()); assertEquals("Shape is ellipse", tf.createIdent("ellipse"), ((RadialGradientImpl) fn).getShape()); assertEquals("Default position", 2, ((RadialGradientImpl) fn).getPosition().length); assertEquals("Two stops are set", 2, ((RadialGradientImpl) fn).getColorStops().size()); assertEquals("First stop color", tf.createColor("#e66465"), ((RadialGradientImpl) fn).getColorStops().get(0).getColor()); assertNull("First stop length", ((RadialGradientImpl) fn).getColorStops().get(0).getLength()); assertEquals("Second stop color", tf.createColor("#9198e5"), ((RadialGradientImpl) fn).getColorStops().get(1).getColor()); assertNull("Second stop length", ((RadialGradientImpl) fn).getColorStops().get(1).getLength()); break; case 11: assertEquals(RadialGradientImpl.class, fn.getClass()); assertNull("No size", ((RadialGradientImpl) fn).getSize()); assertEquals("Size ident", tf.createIdent("closest-side"), ((RadialGradientImpl) fn).getSizeIdent()); assertEquals("Shape is ellipse", tf.createIdent("ellipse"), ((RadialGradientImpl) fn).getShape()); assertEquals("Position is set", 2, ((RadialGradientImpl) fn).getPosition().length); assertEquals("Position 1 is correct", tf.createPercent(50.0f), ((RadialGradientImpl) fn).getPosition()[0]); assertEquals("Position 2 is correct", tf.createPercent(50.0f), ((RadialGradientImpl) fn).getPosition()[1]); assertEquals("Three stops are set", 3, ((RadialGradientImpl) fn).getColorStops().size()); break; case 12: assertEquals(RadialGradientImpl.class, fn.getClass()); assertNull("No size", ((RadialGradientImpl) fn).getSize()); assertEquals("Shape is circle", tf.createIdent("circle"), ((RadialGradientImpl) fn).getShape()); assertEquals("Position is set", 2, ((RadialGradientImpl) fn).getPosition().length); assertEquals("Position 1 is correct", tf.createPercent(100.0f), ((RadialGradientImpl) fn).getPosition()[0]); assertEquals("Position 2 is correct", tf.createPercent(50.0f), ((RadialGradientImpl) fn).getPosition()[1]); assertEquals("Four stops are set", 4, ((RadialGradientImpl) fn).getColorStops().size()); break; case 13: assertEquals(RadialGradientImpl.class, fn.getClass()); assertEquals("Single size", 1, ((RadialGradientImpl) fn).getSize().length); assertEquals("Correct size", tf.createLength(10.0f, Unit.px), ((RadialGradientImpl) fn).getSize()[0]); assertEquals("Shape is circle", tf.createIdent("circle"), ((RadialGradientImpl) fn).getShape()); assertEquals("Position is set", 2, ((RadialGradientImpl) fn).getPosition().length); assertEquals("Position 1 is correct", tf.createPercent(100.0f), ((RadialGradientImpl) fn).getPosition()[0]); assertEquals("Position 2 is correct", tf.createPercent(50.0f), ((RadialGradientImpl) fn).getPosition()[1]); assertEquals("Two stops are set", 2, ((RadialGradientImpl) fn).getColorStops().size()); break; case 14: assertEquals(RadialGradientImpl.class, fn.getClass()); assertEquals("Two sizes", 2, ((RadialGradientImpl) fn).getSize().length); assertEquals("Correct size 1", tf.createLength(10.0f, Unit.px), ((RadialGradientImpl) fn).getSize()[0]); assertEquals("Correct size 2", tf.createPercent(55.0f), ((RadialGradientImpl) fn).getSize()[1]); assertEquals("Shape is ellipse", tf.createIdent("ellipse"), ((RadialGradientImpl) fn).getShape()); assertEquals("Position is set", 2, ((RadialGradientImpl) fn).getPosition().length); assertEquals("Position 1 is correct", tf.createLength(10.0f, Unit.px), ((RadialGradientImpl) fn).getPosition()[0]); assertEquals("Position 2 is correct", tf.createLength(20.0f, Unit.px), ((RadialGradientImpl) fn).getPosition()[1]); assertEquals("Two stops are set", 2, ((RadialGradientImpl) fn).getColorStops().size()); break; case 15: assertEquals(RadialGradientImpl.class, fn.getClass()); assertEquals("Single size", 1, ((RadialGradientImpl) fn).getSize().length); assertEquals("Correct size", tf.createLength(10.0f, Unit.px), ((RadialGradientImpl) fn).getSize()[0]); assertEquals("Shape is circle", tf.createIdent("circle"), ((RadialGradientImpl) fn).getShape()); assertEquals("Position is set", 2, ((RadialGradientImpl) fn).getPosition().length); assertEquals("Position 1 is correct", tf.createPercent(50.0f), ((RadialGradientImpl) fn).getPosition()[0]); assertEquals("Position 2 is correct", tf.createPercent(50.0f), ((RadialGradientImpl) fn).getPosition()[1]); assertEquals("Two stops are set", 2, ((RadialGradientImpl) fn).getColorStops().size()); break; case 16: assertEquals(RadialGradientImpl.class, fn.getClass()); assertEquals("Two sizes", 2, ((RadialGradientImpl) fn).getSize().length); assertEquals("Correct size 1", tf.createPercent(10.0f), ((RadialGradientImpl) fn).getSize()[0]); assertEquals("Correct size 2", tf.createPercent(12.0f), ((RadialGradientImpl) fn).getSize()[1]); assertEquals("Shape is ellipse", tf.createIdent("ellipse"), ((RadialGradientImpl) fn).getShape()); assertEquals("Position is set", 2, ((RadialGradientImpl) fn).getPosition().length); assertEquals("Position 1 is correct", tf.createPercent(50.0f), ((RadialGradientImpl) fn).getPosition()[0]); assertEquals("Position 2 is correct", tf.createPercent(50.0f), ((RadialGradientImpl) fn).getPosition()[1]); assertEquals("Two stops are set", 2, ((RadialGradientImpl) fn).getColorStops().size()); break; case 17: assertEquals(RadialGradientImpl.class, fn.getClass()); TermFunction fn2 = (TermFunction) d.get(1); assertEquals(RadialGradientImpl.class, fn2.getClass()); break; } } } @Test public void gradientInvalid() throws IOException, CSSException { for (int i = 0; i < TEST_GRADIENT_INVALID.length; i++) { StyleSheet ss = CSSFactory.parseString(TEST_GRADIENT_INVALID[i], null); assertEquals("One rule is parset [" + i + "]", 1, ss.size()); assertEquals("One property is set [" + i + "]", 1, ss.get(0).size()); } } @Test public void filterValid() throws IOException, CSSException { for (int i = 0; i < TEST_FILTER.length; i++) { StyleSheet ss = CSSFactory.parseString(TEST_FILTER[i], null); //System.out.println(i + " ss: " + ss); assertEquals("One rule is parset [" + i + "]", 1, ss.size()); assertEquals("One property is set [" + i + "]", 1, ss.get(0).size()); Declaration d = (Declaration) ss.get(0).get(0); TermFunction fn = (TermFunction) d.get(0); //System.out.println(i + ": " + d); switch (i) { case 0: assertEquals(BlurImpl.class, fn.getClass()); assertEquals("Radius is correct", tf.createLength("1.2", Unit.em, 1), ((BlurImpl) fn).getRadius()); break; case 1: assertEquals(BrightnessImpl.class, fn.getClass()); assertEquals("Amount is correct", 1.75f, ((BrightnessImpl) fn).getAmount(), 0.001f); break; case 2: assertEquals(ContrastImpl.class, fn.getClass()); assertEquals("Amount is correct", 2.0f, ((ContrastImpl) fn).getAmount(), 0.001f); break; case 3: assertEquals(DropShadowImpl.class, fn.getClass()); assertEquals("Offset X is correct", tf.createLength("30", Unit.px, 1), ((DropShadowImpl) fn).getOffsetX()); assertEquals("Offset Y is correct", tf.createLength("10", Unit.px, 1), ((DropShadowImpl) fn).getOffsetY()); assertEquals("Blur radius is correct", tf.createLength("4", Unit.px, 1), ((DropShadowImpl) fn).getBlurRadius()); assertEquals("Color is correct", tf.createColor("#4444dd"), ((DropShadowImpl) fn).getColor()); break; case 4: assertEquals(DropShadowImpl.class, fn.getClass()); assertEquals("Offset X is correct", tf.createLength("30", Unit.px, -1), ((DropShadowImpl) fn).getOffsetX()); assertEquals("Offset Y is correct", tf.createLength("10", Unit.px, -1), ((DropShadowImpl) fn).getOffsetY()); assertNull("Blur radius is enpty", ((DropShadowImpl) fn).getBlurRadius()); assertEquals("Color is correct", tf.createColor("#ff0000"), ((DropShadowImpl) fn).getColor()); break; case 5: assertEquals(GrayscaleImpl.class, fn.getClass()); assertEquals("Amount is correct", 1.0f, ((GrayscaleImpl) fn).getAmount(), 0.001f); break; case 6: assertEquals(HueRotateImpl.class, fn.getClass()); assertEquals("Angle is correct", tf.createAngle("3.142", Unit.rad, -1), ((HueRotateImpl) fn).getAngle()); break; case 7: assertEquals(InvertImpl.class, fn.getClass()); assertEquals("Amount is correct", 0.3f, ((InvertImpl) fn).getAmount(), 0.001f); break; case 8: assertEquals(OpacityImpl.class, fn.getClass()); assertEquals("Amount is correct", 0.0f, ((OpacityImpl) fn).getAmount(), 0.001f); break; case 9: assertEquals(SaturateImpl.class, fn.getClass()); assertEquals("Amount is correct", 0.5f, ((SaturateImpl) fn).getAmount(), 0.001f); break; case 10: assertEquals(SepiaImpl.class, fn.getClass()); assertEquals("Amount is correct", 1.0f, ((SepiaImpl) fn).getAmount(), 0.001f); break; } } } @Test public void contentValid() throws IOException, CSSException { for (int i = 0; i < TEST_CONTENT.length; i++) { StyleSheet ss = CSSFactory.parseString(TEST_CONTENT[i], null); //System.out.println(i + " ss: " + ss); assertEquals("One rule is parset [" + i + "]", 1, ss.size()); assertEquals("One property is set [" + i + "]", 1, ss.get(0).size()); Declaration d = (Declaration) ss.get(0).get(0); TermFunction fn = (TermFunction) d.get(0); //System.out.println(i + ": " + d); switch (i) { case 0: assertEquals(AttrImpl.class, fn.getClass()); assertEquals("Name is correct", "title", ((AttrImpl) fn).getName()); break; case 1: assertEquals(CounterImpl.class, fn.getClass()); assertEquals("Name is correct", "chapter_counter", ((CounterImpl) fn).getName()); assertNull("Style is not set", ((CounterImpl) fn).getStyle()); break; case 2: assertEquals(CounterImpl.class, fn.getClass()); assertEquals("Name is correct", "chapter_counter", ((CounterImpl) fn).getName()); assertEquals("Style is correct", CSSProperty.ListStyleType.LOWER_ALPHA, ((CounterImpl) fn).getStyle()); break; case 3: assertEquals(CountersImpl.class, fn.getClass()); assertEquals("Name is correct", "chapter_counter", ((CountersImpl) fn).getName()); assertEquals("Separator is correct", "..", ((CountersImpl) fn).getSeparator()); assertNull("Style is not set", ((CountersImpl) fn).getStyle()); break; case 4: assertEquals(CountersImpl.class, fn.getClass()); assertEquals("Name is correct", "chapter_counter", ((CountersImpl) fn).getName()); assertEquals("Separator is correct", "::", ((CountersImpl) fn).getSeparator()); assertEquals("Style is correct", CSSProperty.ListStyleType.LOWER_ROMAN, ((CountersImpl) fn).getStyle()); break; case 5: assertEquals(CounterImpl.class, fn.getClass()); assertEquals("Name is correct", "c", ((CounterImpl) fn).getName()); assertEquals("Style is correct", CSSProperty.ListStyleType.NONE, ((CounterImpl) fn).getStyle()); TermString str = (TermString) d.get(1); assertEquals("String is parsed", "z", str.getValue()); break; } } } @Test public void contentInvalid() throws IOException, CSSException { for (int i = 0; i < TEST_CONTENT_INVALID.length; i++) { StyleSheet ss = CSSFactory.parseString(TEST_CONTENT_INVALID[i], null); assertEquals("One rule is parset [" + i + "]", 1, ss.size()); assertEquals("One property is set [" + i + "]", 1, ss.get(0).size()); } } //========================================================================================== /** * A simple testing length evaluator with fixed values for 1em and 100%. */ private class PxEvaluator extends CalcArgs.DoubleEvaluator { private static final double whole = 100f; private static final double em = 40f; @Override public double resolveValue(TermFloatValue val) { if (val instanceof TermLengthOrPercent) { if (((TermLengthOrPercent) val).isPercentage()) return val.getValue() * whole / 100.0; else switch (val.getUnit()) { case px: return val.getValue(); case em: return val.getValue() * em; default: return 0.0; } } else return 0.0; //this should not happen } } /** * A simple testing angle evaluator with fixed values for 1em and 100%. */ private class DegEvaluator extends CalcArgs.DoubleEvaluator { private static final double radx = 0.5; //just a testing value, nothing real @Override public double resolveValue(TermFloatValue val) { if (val instanceof TermAngle) { switch (val.getUnit()) { case deg: return val.getValue(); case rad: return val.getValue() * radx; default: return 0.0; } } else return 0.0; //this should not happen } } }