1 /* 2 * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package test.javafx.css; 27 28 import javafx.css.StyleConverter.StringStore; 29 import javafx.css.converter.EnumConverter; 30 import javafx.css.converter.StringConverter; 31 32 import java.io.ByteArrayInputStream; 33 import java.io.ByteArrayOutputStream; 34 import java.io.DataInputStream; 35 import java.io.DataOutputStream; 36 import java.io.File; 37 import java.io.FileWriter; 38 import java.io.IOException; 39 import java.net.URISyntaxException; 40 import java.net.URL; 41 import java.util.Collections; 42 import java.util.List; 43 import java.util.Locale; 44 import javafx.css.CssParser; 45 import javafx.css.Declaration; 46 import javafx.css.ParsedValue; 47 import javafx.css.Rule; 48 import javafx.css.RuleShim; 49 import javafx.css.Selector; 50 import javafx.css.SimpleSelector; 51 import javafx.css.StyleConverter; 52 import javafx.css.StyleOrigin; 53 import javafx.css.StyleableProperty; 54 import javafx.css.Stylesheet; 55 import javafx.css.StylesheetShim; 56 57 import javafx.geometry.NodeOrientation; 58 import javafx.geometry.Orientation; 59 import javafx.geometry.Pos; 60 import javafx.geometry.VPos; 61 import javafx.scene.Group; 62 import javafx.scene.Scene; 63 import javafx.scene.layout.StackPane; 64 import javafx.scene.paint.Color; 65 import javafx.scene.paint.Paint; 66 import javafx.scene.paint.RadialGradient; 67 import javafx.scene.shape.Rectangle; 68 import javafx.scene.text.Font; 69 import javafx.scene.text.FontSmoothingType; 70 import javafx.scene.text.TextAlignment; 71 import javafx.stage.Stage; 72 import org.junit.*; 73 import static org.junit.Assert.*; 74 import static org.junit.Assert.assertEquals; 75 76 77 public class StylesheetTest { 78 79 String testURL = null; 80 81 public StylesheetTest() { 82 testURL = getClass().getResource("HonorDeveloperSettingsTest_UA.css").toExternalForm(); 83 } 84 85 /** 86 * Test of getUrl method, of class Stylesheet. 87 */ 88 @Test 89 public void testGetUrl() { 90 Stylesheet instance = new StylesheetShim(); 91 URL expResult = null; 92 String result = instance.getUrl(); 93 assertEquals(expResult, result); 94 95 instance = new StylesheetShim(testURL); 96 result = instance.getUrl(); 97 assertEquals(testURL, result); 98 } 99 100 /** 101 * Test of getSource method, of class Stylesheet. 102 */ 103 @Test 104 public void testGetStylesheetSourceGetterAndSetter() { 105 Stylesheet instance = new StylesheetShim(); 106 StyleOrigin expResult = StyleOrigin.AUTHOR; 107 StyleOrigin result = instance.getOrigin(); 108 assertEquals(expResult, result); 109 110 instance.setOrigin(StyleOrigin.INLINE); 111 expResult = StyleOrigin.INLINE; 112 result = instance.getOrigin(); 113 assertEquals(expResult, result); 114 115 instance.setOrigin(StyleOrigin.USER); 116 expResult = StyleOrigin.USER; 117 result = instance.getOrigin(); 118 assertEquals(expResult, result); 119 120 instance.setOrigin(StyleOrigin.USER_AGENT); 121 expResult = StyleOrigin.USER_AGENT; 122 result = instance.getOrigin(); 123 assertEquals(expResult, result); 124 } 125 126 /** 127 * Test of addRule method, of class Stylesheet. 128 */ 129 @Test 130 public void testStylesheetAddAndGetRule() { 131 Rule rule = RuleShim.getRule(Collections.EMPTY_LIST, Collections.EMPTY_LIST); 132 Stylesheet instance = new StylesheetShim(); 133 instance.getRules().add(rule); 134 instance.getRules().add(rule); 135 instance.getRules().add(rule); 136 instance.getRules().add(rule); 137 instance.getRules().add(rule); 138 List<Rule> rules = instance.getRules(); 139 assert(rules.size() == 5); 140 for(Rule r : rules) assertEquals(r, rule); 141 } 142 143 @Test 144 public void testAddingRuleSetsStylesheetOnRule() { 145 Rule rule = RuleShim.getRule(Collections.EMPTY_LIST, Collections.EMPTY_LIST); 146 Stylesheet instance = new StylesheetShim(); 147 instance.getRules().add(rule); 148 assert(rule.getStylesheet() == instance); 149 } 150 151 @Test 152 public void testRemovingRuleSetsStylesheetNullOnRule() { 153 Rule rule = RuleShim.getRule(Collections.EMPTY_LIST, Collections.EMPTY_LIST); 154 Stylesheet instance = new StylesheetShim(); 155 instance.getRules().add(rule); 156 instance.getRules().remove(rule); 157 assertNull(rule.getStylesheet()); 158 } 159 160 /** 161 * Test of equals method, of class Stylesheet. 162 */ 163 @Test 164 public void testStylesheetEquals() { 165 Object obj = new StylesheetShim(); 166 Stylesheet instance = new StylesheetShim(); 167 boolean expResult = true; 168 boolean result = instance.equals(obj); 169 assertEquals(expResult, result); 170 171 obj = new StylesheetShim(testURL); 172 instance = new StylesheetShim(testURL); 173 expResult = true; 174 result = instance.equals(obj); 175 assertEquals(expResult, result); 176 177 obj = new StylesheetShim(); 178 instance = new StylesheetShim(testURL); 179 expResult = false; 180 result = instance.equals(obj); 181 assertEquals(expResult, result); 182 183 obj = instance = new StylesheetShim(testURL); 184 expResult = true; 185 result = instance.equals(obj); 186 assertEquals(expResult, result); 187 188 } 189 190 /** 191 * Test of toString method, of class Stylesheet. 192 */ 193 @Test 194 public void testStylesheetToString() { 195 Stylesheet instance = new StylesheetShim(); 196 String expResult = "/* */"; 197 String result = instance.toString(); 198 assertEquals(expResult, result); 199 200 instance = new StylesheetShim(testURL); 201 expResult = "/* " + testURL + " */"; 202 result = instance.toString(); 203 assertEquals(expResult, result); 204 205 instance = new StylesheetShim(testURL); 206 Rule rule = RuleShim.getRule(Collections.EMPTY_LIST, Collections.EMPTY_LIST); 207 instance.getRules().add(rule); 208 expResult = "/* " + testURL + " */\n{\n}\n"; 209 result = instance.toString(); 210 assertEquals(expResult, result); 211 } 212 213 /** 214 * Test of writeBinary method, of class Stylesheet. 215 @Test 216 public void testWriteAndReadBinary() throws Exception { 217 DataOutputStream os = null; 218 StringStore stringStore = null; 219 Stylesheet instance = new StylesheetShim(testURL); 220 instance.writeBinary(os, stringStore); 221 } 222 */ 223 224 /** 225 * Test of loadBinary method, of class Stylesheet. 226 @Test 227 public void testLoadBinary() { 228 System.out.println("loadBinary"); 229 URL url = null; 230 Stylesheet expResult = null; 231 Stylesheet result = Stylesheet.loadBinary(url); 232 assertEquals(expResult, result); 233 // TODO review the generated test code and remove the default call to fail. 234 fail("The test case is a prototype."); 235 } 236 */ 237 238 @Test public void test_RT_18126() { 239 // CSS cannot write binary -fx-background-repeat: repeat, no-repeat; 240 String data = "#rt18126 {" 241 + "-fx-background-repeat: repeat, no-repeat;" 242 + "-fx-border-image-repeat: repeat, no-repeat;" 243 + "}"; 244 245 try { 246 Stylesheet stylesheet = new CssParser().parse(data); 247 248 StringStore stringStore = new StringStore(); 249 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 250 DataOutputStream dos = new DataOutputStream(baos); 251 StylesheetShim.writeBinary(stylesheet, dos, stringStore); 252 dos.flush(); 253 dos.close(); 254 255 ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); 256 DataInputStream dis = new DataInputStream(bais); 257 258 Stylesheet restored = new StylesheetShim(); 259 StylesheetShim.readBinary(restored, StylesheetShim.BINARY_CSS_VERSION, dis, stringStore.strings.toArray(new String[stringStore.strings.size()])); 260 261 List<Rule> cssRules = stylesheet.getRules(); 262 List<Rule> bssRules = restored.getRules(); 263 264 // Rule does not have an equals method 265 assert(cssRules.size() == bssRules.size()); 266 for (int n=0; n<cssRules.size(); n++) { 267 Rule expected = cssRules.get(n); 268 Rule actual = bssRules.get(n); 269 assertEquals(Integer.toString(n), 270 RuleShim.getUnobservedDeclarationList(expected), 271 RuleShim.getUnobservedDeclarationList(actual)); 272 } 273 274 } catch (IOException ioe) { 275 fail(ioe.toString()); 276 } 277 278 } 279 280 @Test 281 public void testRT_23140() { 282 283 try { 284 Group root = new Group(); 285 root.getChildren().add(new Rectangle(50,50)); 286 Scene scene = new Scene(root, 500, 500); 287 root.getStylesheets().add("bogus.css"); 288 Stage stage = new Stage(); 289 stage.setScene(scene); 290 stage.show(); 291 } catch (NullPointerException e) { 292 // RT-23140 is supposed to fix the NPE. Did it? 293 fail("Test purpose failed: " + e.toString()); 294 } catch (Exception e) { 295 // Something other than an NPE should still raise a red flag, 296 // but the exception is not what RT-23140 fixed. 297 298 fail("Exception not expected: " + e.toString()); 299 } 300 301 } 302 303 @Test public void testRT_31316() { 304 305 try { 306 307 Rectangle rect = new Rectangle(50,50); 308 rect.setStyle("-fx-base: red; -fx-fill: -fx-base;"); 309 rect.setFill(Color.GREEN); 310 311 Group root = new Group(); 312 root.getChildren().add(rect); 313 Scene scene = new Scene(root, 500, 500); 314 315 root.applyCss(); 316 317 // Shows inline style works. 318 assertEquals(Color.RED, rect.getFill()); 319 320 // reset fill 321 ((StyleableProperty<Paint>)rect.fillProperty()).applyStyle(null, null); 322 323 // loop in style! 324 rect.setStyle("-fx-base: -fx-fill; -fx-fill: -fx-base;"); 325 root.applyCss(); 326 327 // Shows value was left alone 328 assertNull(rect.getFill()); 329 330 331 } catch (Exception e) { 332 // The code generates an IllegalArgumentException that should never reach here 333 fail("Exception not expected: " + e.toString()); 334 } 335 336 } 337 338 @Test public void testRT_31316_with_complex_value() { 339 340 try { 341 342 Rectangle rect = new Rectangle(50,50); 343 rect.setStyle("-fx-base: red; -fx-color: -fx-base; -fx-fill: radial-gradient(radius 100%, red, -fx-color);"); 344 rect.setFill(Color.GREEN); 345 346 Group root = new Group(); 347 root.getChildren().add(rect); 348 Scene scene = new Scene(root, 500, 500); 349 350 root.applyCss(); 351 352 // Shows inline style works. 353 assertTrue(rect.getFill() instanceof RadialGradient); 354 355 // reset fill 356 ((StyleableProperty<Paint>)rect.fillProperty()).applyStyle(null, null); 357 358 // loop in style! 359 rect.setStyle("-fx-base: -fx-color; -fx-color: -fx-base; -fx-fill: radial-gradient(radius 100%, red, -fx-color);"); 360 361 root.applyCss(); 362 363 // Shows value was left alone 364 assertNull(rect.getFill()); 365 366 } catch (Exception e) { 367 // The code generates an IllegalArgumentException that should never reach here 368 fail("Exception not expected: " + e.toString()); 369 } 370 } 371 372 373 @Test public void testRT_31316_with_complex_scenegraph() { 374 375 try { 376 377 Rectangle rect = new Rectangle(50,50); 378 rect.setStyle("-fx-fill: radial-gradient(radius 100%, red, -fx-color);"); 379 rect.setFill(Color.GREEN); 380 381 StackPane pane = new StackPane(); 382 pane.setStyle("-fx-color: -fx-base;"); 383 pane.getChildren().add(rect); 384 385 Group root = new Group(); 386 // loop in style! 387 root.setStyle("-fx-base: red;"); 388 root.getChildren().add(pane); 389 Scene scene = new Scene(root, 500, 500); 390 391 root.applyCss(); 392 393 // Shows inline style works. 394 assertTrue(rect.getFill() instanceof RadialGradient); 395 396 // reset fill 397 ((StyleableProperty<Paint>)rect.fillProperty()).applyStyle(null, null); 398 399 // loop in style 400 root.setStyle("-fx-base: -fx-color;"); 401 402 root.applyCss(); 403 404 // Shows value was left alone 405 assertNull(rect.getFill()); 406 407 } catch (Exception e) { 408 // The code generates an IllegalArgumentException that should never reach here 409 fail("Exception not expected: " + e.toString()); 410 } 411 412 } 413 414 @Test public void testRT_32229() { 415 416 try { 417 418 Rectangle rect = new Rectangle(50,50); 419 rect.setStyle("-fx-base: red; -fx-fill: radial-gradient(radius 100%, derive(-fx-base, -25%), derive(-fx-base, 25%));"); 420 rect.setFill(Color.GREEN); 421 422 Group root = new Group(); 423 root.getChildren().add(rect); 424 Scene scene = new Scene(root, 500, 500); 425 426 root.applyCss(); 427 428 // Shows inline style works. 429 assertTrue(rect.getFill() instanceof RadialGradient); 430 431 // reset fill 432 ((StyleableProperty<Paint>)rect.fillProperty()).applyStyle(null, null); 433 434 // loop in style! 435 root.setStyle("-fx-base: -fx-fill;"); 436 rect.setStyle("-fx-fill: radial-gradient(radius 100%, derive(-fx-base, -25%), derive(-fx-base, 25%));"); 437 438 439 root.applyCss(); 440 441 // Shows value was left alone 442 assertNull(rect.getFill()); 443 444 } catch (Exception e) { 445 // The code generates an IllegalArgumentException that should never reach here 446 fail("Exception not expected: " + e.toString()); 447 } 448 } 449 450 @Test 451 public void testRT_30953_parse() { 452 453 try { 454 // Make sure RT-30953.css can be parsed, serialized and deserialized with the current code, 455 // no matter the bss version 456 URL url = StylesheetTest.class.getResource("RT-30953.css"); 457 if (url == null) { 458 fail("Can't find RT-30953.css"); 459 } 460 461 Stylesheet ss = new CssParser().parse(url); 462 int nFontFaceSrcs = checkFontFace(ss); 463 assertEquals(3, nFontFaceSrcs); 464 checkConvert(ss); 465 466 } catch (Exception e) { 467 fail(e.toString()); 468 } 469 470 } 471 472 @Test public void testRT_30953_deserialize_from_v4() { 473 // RT-30953-v4.bss was generated with version 4 474 Stylesheet ss = deserialize("RT-30953-v4.bss"); 475 checkConvert(ss); 476 } 477 478 @Test 479 public void testRT_30953_deserialize_from_2_2_45() { 480 481 // RT-30953-2.2.4bss was generated with javafx version 2.2.45 from 7u?? 482 Stylesheet ss = deserialize("RT-30953-2.2.45.bss"); 483 checkConvert(ss); 484 } 485 486 @Test 487 public void testRT_30953_deserialize_from_2_2_4() { 488 489 // RT-30953-2.2.4bss was generated with javafx version 2.2.4 from 7u10 490 Stylesheet ss = deserialize("RT-30953-2.2.4.bss"); 491 checkConvert(ss); 492 } 493 494 @Test 495 public void testRT_30953_deserialize_from_2_2_21() { 496 497 // RT-30953-2.2.21.bss was generated with javafx version 2.2.21 from 7u21 498 Stylesheet ss = deserialize("RT-30953-2.2.21.bss"); 499 checkConvert(ss); 500 501 } 502 503 private Stylesheet deserialize(String bssFile) { 504 Stylesheet ss = null; 505 try { 506 URL url = StylesheetTest.class.getResource(bssFile); 507 if (url == null) { 508 fail(bssFile); 509 } 510 ss = Stylesheet.loadBinary(url); 511 } catch (IOException ioe) { 512 fail(ioe.toString()); 513 } catch (Exception e) { 514 fail(e.toString()); 515 } 516 return ss; 517 } 518 519 private void checkConvert(Stylesheet ss) { 520 Declaration decl = null; 521 StyleConverter converter = null; 522 try { 523 for (Rule r : ss.getRules()) { 524 for (Declaration d : r.getDeclarations()) { 525 decl = d; 526 ParsedValue pv = decl.getParsedValue(); 527 converter = pv.getConverter(); 528 if (converter == null) { 529 530 if ("inherit".equals(pv.getValue())) continue; 531 532 String prop = d.getProperty().toLowerCase(Locale.ROOT); 533 if ("-fx-shape".equals(prop)) { 534 StringConverter.getInstance().convert(pv, null); 535 } else if ("-fx-font-smoothing-type".equals(prop)) { 536 (new EnumConverter<FontSmoothingType>(FontSmoothingType.class)).convert(pv, null); 537 } else if ("-fx-text-alignment".equals(prop)) { 538 (new EnumConverter<TextAlignment>(TextAlignment.class)).convert(pv, null); 539 } else if ("-fx-alignment".equals(prop)) { 540 (new EnumConverter<Pos>(Pos.class)).convert(pv, null); 541 } else if ("-fx-text-origin".equals(prop)) { 542 (new EnumConverter<VPos>(VPos.class)).convert(pv, null); 543 } else if ("-fx-text-overrun".equals(prop)) { 544 Class cl = null; 545 try { 546 cl = Class.forName("javafx.scene.control.OverrunStyle"); 547 } catch (Exception ignored) { 548 // just means we're running ant test from javafx-ui-common 549 } 550 if (cl != null) { 551 (new EnumConverter(cl)).convert(pv, null); 552 } 553 } else if ("-fx-orientation".equals(prop)) { 554 (new EnumConverter<Orientation>(Orientation.class)).convert(pv, null); 555 } else if ("-fx-content-display".equals(prop)) { 556 Class cl = null; 557 try { 558 cl = Class.forName("javafx.scene.control.CpntentDisplay"); 559 } catch (Exception ignored) { 560 // just means we're running ant test from javafx-ui-common 561 } 562 if (cl != null) { 563 (new EnumConverter(cl)).convert(pv, null); 564 } 565 } else if ("-fx-hbar-policy".equals(prop)) { 566 Class cl = null; 567 try { 568 cl = Class.forName("javafx.scene.control.ScrollPane.ScrollBarPolicy"); 569 } catch (Exception ignored) { 570 // just means we're running ant test from javafx-ui-common 571 } 572 if (cl != null) { 573 (new EnumConverter(cl)).convert(pv, null); 574 } 575 } else { 576 System.out.println("No converter for " + d.toString() + ". Skipped conversion."); 577 } 578 continue; 579 } 580 Object value = converter.convert(pv, Font.getDefault()); 581 } 582 } 583 } catch (Exception e) { 584 if (decl == null) fail(e.toString()); 585 else if (converter != null) fail(decl.getProperty() + ", " + converter + ", " + e.toString()); 586 else fail(decl.getProperty() + ", " + e.toString()); 587 } 588 589 } 590 591 private int checkFontFace(Stylesheet stylesheet) { 592 return test.javafx.css.CssParserTest.checkFontFace(stylesheet); 593 } 594 595 @Test 596 public void testRT_37122() { 597 try { 598 URL url = StylesheetTest.class.getResource("RT-37122.css"); 599 File source = new File(url.toURI()); 600 File target = File.createTempFile("RT_37122_", "bss"); 601 Stylesheet.convertToBinary(source, target); 602 Stylesheet.convertToBinary(source, target); 603 } catch (URISyntaxException | IOException e) { 604 fail(e.toString()); 605 } 606 } 607 608 @Test 609 public void testRT_37301() { 610 try { 611 File source = File.createTempFile("RT_37301_", "css"); 612 FileWriter writer = new FileWriter(source); 613 writer.write("A:dir(rtl) {} B:dir(ltr) {} C {}"); 614 writer.flush(); 615 writer.close(); 616 File target = File.createTempFile("RT_37301_", "bss"); 617 Stylesheet.convertToBinary(source, target); 618 Stylesheet stylesheet = Stylesheet.loadBinary(target.toURL()); 619 int good = 0; 620 for (Rule rule : stylesheet.getRules()) { 621 for (Selector sel : rule.getSelectors()) { 622 SimpleSelector simpleSelector = (SimpleSelector)sel; 623 if ("A".equals(simpleSelector.getName())) { 624 assertEquals(NodeOrientation.RIGHT_TO_LEFT, simpleSelector.getNodeOrientation()); 625 } else if ("B".equals(simpleSelector.getName())) { 626 assertEquals(NodeOrientation.LEFT_TO_RIGHT, simpleSelector.getNodeOrientation()); 627 } else if ("C".equals(simpleSelector.getName())) { 628 assertEquals(NodeOrientation.INHERIT, simpleSelector.getNodeOrientation()); 629 } else { 630 fail(simpleSelector.toString()); 631 } 632 } 633 } 634 } catch (IOException e) { 635 fail(e.toString()); 636 } 637 } 638 639 }