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