1 /* 2 * Copyright (c) 2012, 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. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 /* 25 * @test 26 * @key headful 27 * @bug 7165725 28 * @summary Tests if HTML parser can handle successive script tags in a line 29 * and it does not call false text callback after script tags. 30 * @run main bug7165725 31 */ 32 33 import sun.awt.SunToolkit; 34 35 import java.awt.BorderLayout; 36 import java.io.File; 37 import java.io.FileReader; 38 import java.io.IOException; 39 import java.net.URL; 40 import java.util.ArrayList; 41 import java.util.Arrays; 42 import java.util.List; 43 import javax.swing.*; 44 import javax.swing.text.AbstractDocument.AbstractElement; 45 import javax.swing.text.AbstractDocument; 46 import javax.swing.text.Document; 47 import javax.swing.text.MutableAttributeSet; 48 import javax.swing.text.html.HTML; 49 import javax.swing.text.html.HTMLDocument; 50 import javax.swing.text.html.HTMLEditorKit; 51 import javax.swing.text.html.parser.ParserDelegator; 52 53 public class bug7165725 extends JFrame { 54 private static class GoldenElement { 55 56 private String goldenName; 57 private List<GoldenElement> goldenChildren; 58 59 GoldenElement(String goldenName, GoldenElement... goldenChildren){ 60 this.goldenName = goldenName; 61 if (goldenChildren != null) { 62 this.goldenChildren = Arrays.asList(goldenChildren); 63 } else { 64 this.goldenChildren = new ArrayList<>(); 65 } 66 } 67 68 // throws RuntimeException if not ok 69 public void checkStructureEquivalence(AbstractDocument.AbstractElement elem) { 70 String name = elem.getName(); 71 if (!goldenName.equals(name)) { 72 throw new RuntimeException("Bad structure: expected element name is '" + goldenName + "' but the actual name was '" + name + "'."); 73 } 74 int goldenChildCount = goldenChildren.size(); 75 int childCount = elem.getChildCount(); 76 if (childCount != goldenChildCount) { 77 System.out.print("D: children: "); 78 for (int i = 0; i < childCount; i++) { 79 System.out.print(" " + elem.getElement(i).getName()); 80 } 81 System.out.println(""); 82 System.out.print("D: goldenChildren: "); 83 for (GoldenElement ge : goldenChildren) { 84 System.out.print(" " + ge.goldenName); 85 } 86 System.out.println(""); 87 88 throw new RuntimeException("Bad structure: expected child count of element '" + goldenName + "' is '" + goldenChildCount + "' but the actual count was '" + childCount + "'."); 89 } 90 for (int i = 0; i < childCount; i++) { 91 AbstractDocument.AbstractElement nextElem = (AbstractDocument.AbstractElement) elem.getElement(i); 92 GoldenElement goldenElement = goldenChildren.get(i); 93 goldenElement.checkStructureEquivalence(nextElem); 94 } 95 } 96 } 97 98 private JEditorPane editorPane; 99 public void execute(final String urlStr, final GoldenElement goldenElement) throws Exception { 100 System.out.println(); 101 System.out.println("***** TEST: " + urlStr + " *****"); 102 System.out.println(); 103 104 SwingUtilities.invokeAndWait(new Runnable() { 105 public void run() { 106 try { 107 editorPane = new JEditorPane(); 108 editorPane.setEditorKit(new HTMLEditorKit() { 109 public Document createDefaultDocument() { 110 AbstractDocument doc = 111 (AbstractDocument) super.createDefaultDocument(); 112 doc.setAsynchronousLoadPriority(-1); 113 return doc; 114 } 115 }); 116 editorPane.setPage(new URL(urlStr)); 117 } catch (IOException ex) { 118 throw new RuntimeException("Test failed", ex); 119 } 120 editorPane.setEditable(false); 121 JScrollPane scroller = new JScrollPane(); 122 JViewport vp = scroller.getViewport(); 123 vp.add(editorPane); 124 add(scroller, BorderLayout.CENTER); 125 setDefaultCloseOperation(EXIT_ON_CLOSE); 126 setSize(400, 400); 127 setLocationRelativeTo(null); 128 setVisible(true); 129 } 130 }); 131 132 ((SunToolkit) SunToolkit.getDefaultToolkit()).realSync(); 133 134 SwingUtilities.invokeAndWait(new Runnable() { 135 public void run() { 136 HTMLDocument doc = (HTMLDocument) editorPane.getDocument(); 137 doc.dump(System.out); 138 goldenElement.checkStructureEquivalence((AbstractElement) doc.getDefaultRootElement()); 139 dispose(); 140 } 141 }); 142 143 System.out.println(); 144 System.out.println("*********************************"); 145 System.out.println(); 146 } 147 148 public static void main(String[] args) throws Exception { 149 150 String dirURL = getDirURL(); 151 152 System.out.println("dirURL = " + dirURL); 153 154 new bug7165725().execute(dirURL + "successive-script-tag.html", createSuccessiveScriptTags()); 155 new bug7165725().execute(dirURL + "false-text-after-script.html", createFalseTextAfterScript()); 156 157 checkByCallbackForSuccessiveScript(); 158 checkByCallbackForFalseTextAfterScript(); 159 160 System.out.println(); 161 System.out.println(); 162 System.out.println("Test passed."); 163 } 164 165 static String getDirURL() { 166 return "file:///" + 167 new File(System.getProperty("test.src", ".")).getAbsolutePath() + 168 File.separator; 169 } 170 171 static String getParsedContentOneLine(String path) throws Exception { 172 File f = new File(path); 173 FileReader fr = new FileReader(f); 174 ParserDelegator pd = new ParserDelegator(); 175 SBParserCallback sbcallback = new SBParserCallback(); 176 pd.parse(fr, sbcallback, true); 177 fr.close(); 178 return sbcallback.getStringOneLine(); 179 } 180 181 static String getParsedContentOneLine(URL url) throws Exception { 182 return getParsedContentOneLine(url.getPath()); 183 } 184 185 static void checkByCallbackForSuccessiveScript() throws Exception { 186 String content = getParsedContentOneLine(new URL(getDirURL() + "successive-script-tag.html")); 187 if (!content.matches(".*<script .*/js/js1\\.js.*<script .*/js/js2\\.js.*<script .*/js/js3\\.js.*")) 188 throw new RuntimeException("Failed to lookup script tags/attributes."); 189 if (!content.matches(".*<style .*stylesheets/base\\.css.*<style .*stylesheets/adv\\.css.*")) 190 throw new RuntimeException("Failed to lookup style tags."); 191 } 192 193 static void checkByCallbackForFalseTextAfterScript() throws Exception { 194 String content = getParsedContentOneLine(new URL(getDirURL() + "false-text-after-script.html")); 195 final int bodyIdx = content.indexOf("<body "); 196 if (bodyIdx > 0) { 197 String sbody = content.substring(bodyIdx); 198 // There should be no Text(...) in this html 199 if (sbody.indexOf("Text(") >= 0) 200 throw new RuntimeException("Unexpected text found."); 201 } else { 202 throw new RuntimeException("Failed to find body tag."); 203 } 204 } 205 206 private static GoldenElement createSuccessiveScriptTags() { 207 return new GoldenElement("html", 208 new GoldenElement("head", 209 new GoldenElement("p-implied", 210 new GoldenElement("title"), 211 new GoldenElement("title"), 212 new GoldenElement("script"), 213 new GoldenElement("comment"), 214 new GoldenElement("script"), 215 new GoldenElement("script"), 216 new GoldenElement("comment"), 217 new GoldenElement("script"), 218 new GoldenElement("script"), 219 new GoldenElement("comment"), 220 new GoldenElement("script"), 221 new GoldenElement("content"))), 222 new GoldenElement("body", 223 new GoldenElement("p-implied", 224 new GoldenElement("content")))); 225 } 226 227 private static GoldenElement createFalseTextAfterScript() { 228 return new GoldenElement("html", 229 new GoldenElement("head", 230 new GoldenElement("p-implied", 231 new GoldenElement("title"), 232 new GoldenElement("title"), 233 new GoldenElement("content"))), 234 new GoldenElement("body", 235 new GoldenElement("form", 236 new GoldenElement("p-implied", 237 new GoldenElement("input"), 238 new GoldenElement("input"), 239 new GoldenElement("content"))), 240 new GoldenElement("p-implied", 241 new GoldenElement("script"), 242 new GoldenElement("comment"), 243 new GoldenElement("script"), 244 new GoldenElement("script"), 245 new GoldenElement("comment"), 246 new GoldenElement("script"), 247 new GoldenElement("content")))); 248 } 249 250 static class SBParserCallback extends HTMLEditorKit.ParserCallback 251 { 252 private int indentSize = 0; 253 private ArrayList<String> elist = new ArrayList<>(); 254 255 public String getStringOneLine() { 256 StringBuilder sb = new StringBuilder(); 257 for (String s : elist) sb.append(s); 258 return sb.toString(); 259 } 260 261 public String toString() { 262 StringBuffer sb = new StringBuffer(); 263 for (String s : elist) sb.append(s + "\n"); 264 return sb.toString(); 265 } 266 267 protected void indent() { 268 indentSize += 3; 269 } 270 protected void unIndent() { 271 indentSize -= 3; if (indentSize < 0) indentSize = 0; 272 } 273 274 protected String pIndent() { 275 StringBuilder sb = new StringBuilder(); 276 for(int i = 0; i < indentSize; i++) sb.append(" "); 277 return sb.toString(); 278 } 279 280 public void handleText(char[] data, int pos) { 281 elist.add(pIndent() + "Text(" + data.length + " chars) \"" + new String(data) + "\""); 282 } 283 284 public void handleComment(char[] data, int pos) { 285 elist.add(pIndent() + "Comment(" + data.length + " chars)"); 286 } 287 288 public void handleStartTag(HTML.Tag t, MutableAttributeSet a, int pos) { 289 elist.add(pIndent() + "Tag start(<" + t.toString() + " " + a + ">, " + 290 a.getAttributeCount() + " attrs)"); 291 indent(); 292 } 293 294 public void handleEndTag(HTML.Tag t, int pos) { 295 unIndent(); 296 elist.add(pIndent() + "Tag end(</" + t.toString() + ">)"); 297 } 298 299 public void handleSimpleTag(HTML.Tag t, MutableAttributeSet a, int pos) { 300 elist.add(pIndent() + "Tag(<" + t.toString() + ">, " + 301 a.getAttributeCount() + " attrs)"); 302 } 303 304 public void handleError(String errorMsg, int pos){ 305 } 306 } 307 }