1 /* 2 * Copyright (c) 2011, 2016, 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.scene.web; 27 28 import java.io.File; 29 import static java.lang.String.format; 30 import java.net.HttpURLConnection; 31 import java.util.ArrayList; 32 import java.util.HashMap; 33 import java.util.Random; 34 import java.util.concurrent.Callable; 35 import java.util.concurrent.CountDownLatch; 36 import javafx.application.Platform; 37 import javafx.beans.value.ChangeListener; 38 import javafx.beans.value.ObservableValue; 39 import javafx.concurrent.Worker.State; 40 import javafx.scene.web.WebEngine; 41 import javafx.scene.web.WebView; 42 import netscape.javascript.JSObject; 43 import static org.junit.Assert.assertEquals; 44 import static org.junit.Assert.assertNotNull; 45 import static org.junit.Assert.assertTrue; 46 import static org.junit.Assert.fail; 47 import org.junit.Test; 48 import org.w3c.dom.Document; 49 50 public class MiscellaneousTest extends TestBase { 51 52 @Test public void testNoEffectOnFollowRedirects() { 53 assertEquals("Unexpected HttpURLConnection.getFollowRedirects() result", 54 true, HttpURLConnection.getFollowRedirects()); 55 load("test/html/ipsum.html"); 56 assertEquals("Unexpected HttpURLConnection.getFollowRedirects() result", 57 true, HttpURLConnection.getFollowRedirects()); 58 } 59 60 @Test public void testRT22458() throws Exception { 61 final WebEngine webEngine = createWebEngine(); 62 Platform.runLater(() -> { 63 webEngine.load(format("file://%d.ajax.googleapis.com/ajax", 64 new Random().nextInt())); 65 }); 66 Thread.sleep(200); 67 long startTime = System.currentTimeMillis(); 68 DummyClass.dummyField++; 69 long time = System.currentTimeMillis() - startTime; 70 if (time > 2000) { 71 fail(format("DummyClass took %f seconds to load", time / 1000.)); 72 } 73 } 74 75 private static final class DummyClass { 76 private static int dummyField; 77 } 78 79 @org.junit.Ignore 80 @Test public void testRT30835() throws Exception { 81 class Record { 82 private final Document document; 83 private final String location; 84 public Record(Document document, String location) { 85 this.document = document; 86 this.location = location; 87 } 88 } 89 final ArrayList<Record> records = new ArrayList<Record>(); 90 ChangeListener<State> listener = (ov, oldValue, newValue) -> { 91 if (newValue == State.SUCCEEDED) { 92 records.add(new Record( 93 getEngine().getDocument(), 94 getEngine().getLocation())); 95 } 96 }; 97 submit(() -> { 98 getEngine().getLoadWorker().stateProperty().addListener(listener); 99 }); 100 String location = new File("src/test/resources/test/html/RT30835.html") 101 .toURI().toASCIIString().replaceAll("^file:/", "file:///"); 102 load(location); 103 assertEquals(1, records.size()); 104 assertNotNull(records.get(0).document); 105 assertEquals(location, records.get(0).location); 106 } 107 108 @Test public void testRT26306() { 109 loadContent( 110 "<script language='javascript'>\n" + 111 "var s = '0123456789abcdef';\n" + 112 "while (true) {\n" + 113 " alert(s.length);\n" + 114 " s = s + s;\n" + 115 "}\n" + 116 "</script>"); 117 } 118 119 @Test public void testWebViewWithoutSceneGraph() { 120 submit(() -> { 121 WebEngine engine = new WebView().getEngine(); 122 engine.getLoadWorker().stateProperty().addListener( 123 (observable, oldValue, newValue) -> { 124 if (State.SUCCEEDED == newValue) { 125 engine.executeScript( 126 "window.scrollTo" + 127 "(0, document.documentElement.scrollHeight)"); 128 } 129 }); 130 engine.loadContent("<body> <a href=#>hello</a></body>"); 131 }); 132 } 133 134 // JDK-8133775 135 @Test(expected = IllegalStateException.class) public void testDOMObjectThreadOwnership() { 136 class IllegalStateExceptionChecker { 137 public Object resultObject; 138 public void start() { 139 WebEngine engine = new WebEngine(); 140 // Get DOM object from JavaFX Application Thread. 141 resultObject = engine.executeScript("document.createElement('span')"); 142 } 143 } 144 IllegalStateExceptionChecker obj = new IllegalStateExceptionChecker(); 145 submit(obj::start); 146 // Try accessing the resultObject created in JavaFX Application Thread 147 // from someother thread. It should throw an exception. 148 obj.resultObject.toString(); 149 } 150 151 // JDK-8162715 152 public class TimerCallback { 153 private static final int INTERVAL_COUNT = 20; 154 private final CountDownLatch latch = new CountDownLatch(INTERVAL_COUNT); 155 private class Stat { 156 private long firedTime; 157 private long createdTime; 158 private long interval; 159 } 160 private Stat[] stats = new Stat[INTERVAL_COUNT]; 161 162 public void call(long createdTime, long interval, int index) { 163 Stat stat = new Stat(); 164 stat.firedTime = System.currentTimeMillis(); 165 stat.createdTime = createdTime; 166 stat.interval = interval; 167 stats[index] = stat; 168 latch.countDown(); 169 } 170 } 171 172 @Test(timeout = 30000) public void testDOMTimer() { 173 final TimerCallback timer = new TimerCallback(); 174 final WebEngine webEngine = createWebEngine(); 175 submit(() -> { 176 final JSObject window = (JSObject) webEngine.executeScript("window"); 177 assertNotNull(window); 178 window.setMember("timer", timer); 179 // Try various intervals 180 for (int i = 0; i < timer.INTERVAL_COUNT; i++) { 181 int timeout = i * (1000 / timer.INTERVAL_COUNT); 182 webEngine.executeScript("window.setTimeout(" 183 + "timer.call.bind(timer, Date.now()," 184 // pass 'i' to call to test time 185 + timeout +"," + i + ")," 186 // set 'i' as a timeout interval 187 + timeout + ")"); 188 } 189 190 }); 191 192 try { 193 timer.latch.await(); 194 } catch (InterruptedException e) { 195 throw new AssertionError(e); 196 } 197 for (TimerCallback.Stat stat : timer.stats) { 198 assertNotNull(stat); 199 final String msg = String.format( 200 "expected delta:%d, actual delta:%d", 201 stat.interval, 202 stat.firedTime - stat.createdTime); 203 // Timer should not fire too early. Added 20 ms offset to compensate 204 // the floating point approximation issues while dealing with timer. 205 assertTrue(msg, 206 ((stat.firedTime + 20) - stat.createdTime) >= stat.interval); 207 // Timer should not be too late. Since it is not a real time system, 208 // we can't expect the timer to be fire at exactly on the requested 209 // time, give a 1000 ms extra time. 210 assertTrue(msg, 211 (stat.firedTime - stat.createdTime) <= (stat.interval + 1000)); 212 } 213 } 214 215 /** 216 * @test 217 * @bug 8163582 218 * summary svg.path.getTotalLength 219 * Load a simple SVG, Replace its path and get its path's totalLength using pat.getTotalLength 220 */ 221 @Test(timeout = 30000) public void testSvgGetTotalLength() throws Exception { 222 final String svgStub = "<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'>" + 223 " <path id='pathId' d='M150 0 L75 200 L225 200 Z' /> <svg>"; 224 225 // <Path, [Expected, Error Tolerance]> 226 final HashMap<String, Double[]> svgPaths = new HashMap<>(); 227 svgPaths.put("'M 0 0 L 100 0 L 100 100 L 0 100 Z'", 228 new Double[] {400.0, 0.000001}); 229 svgPaths.put("'M 0 0 l 100 0 l 0 100 l -100 0 Z'", 230 new Double[] {400.0, 0.000001}); 231 svgPaths.put("'M 0 0 t 0 100'", 232 new Double[] {100.0, 0.1}); 233 svgPaths.put("'M 0 0 Q 55 50 100 100'", 234 new Double[] {141.4803314, 0.000001}); 235 svgPaths.put("'M 778.4191616766467 375.19086364081954 C 781.239563 " + 236 "375.1908569 786.8525244750526 346.60170830052556 786.8802395209582 346.87991373394766'", 237 new Double[] {29.86020, 0.0001}); 238 svgPaths.put("'M 0 0 C 0.00001 0.00001 0.00002 0.00001 0.00003 0'", 239 new Double[] {0.0000344338, 0.000000001}); 240 241 loadContent(svgStub); 242 243 svgPaths.forEach((pathData, expected) -> { 244 executeScript("document.getElementById('pathId').setAttribute('d' , " + pathData + ");"); 245 // Get svg path's total length 246 Double totalLength = ((Number) executeScript("document.getElementById('pathId').getTotalLength();")).doubleValue(); 247 final String msg = String.format( 248 "svg.path.getTotalLength() for %s, expected : %f, actual : %f", 249 pathData, expected[0], totalLength); 250 assertEquals(msg, 251 expected[0], totalLength, expected[1]); 252 }); 253 } 254 255 private WebEngine createWebEngine() { 256 return submit(() -> new WebEngine()); 257 } 258 }