bug7165725.java revision 14851:980da45565c8
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
33import java.awt.BorderLayout;
34import java.awt.Robot;
35import java.io.File;
36import java.io.FileReader;
37import java.io.IOException;
38import java.net.URL;
39import java.util.ArrayList;
40import java.util.Arrays;
41import java.util.List;
42import javax.swing.*;
43import javax.swing.text.AbstractDocument.AbstractElement;
44import javax.swing.text.AbstractDocument;
45import javax.swing.text.Document;
46import javax.swing.text.MutableAttributeSet;
47import javax.swing.text.html.HTML;
48import javax.swing.text.html.HTMLDocument;
49import javax.swing.text.html.HTMLEditorKit;
50import javax.swing.text.html.parser.ParserDelegator;
51
52public class bug7165725 extends JFrame {
53    private static class GoldenElement {
54
55        private String goldenName;
56        private List<GoldenElement> goldenChildren;
57
58        GoldenElement(String goldenName, GoldenElement... goldenChildren){
59            this.goldenName = goldenName;
60            if (goldenChildren != null) {
61                this.goldenChildren = Arrays.asList(goldenChildren);
62            } else {
63                this.goldenChildren = new ArrayList<>();
64            }
65        }
66
67        // throws RuntimeException if not ok
68        public void checkStructureEquivalence(AbstractDocument.AbstractElement elem) {
69            String name = elem.getName();
70            if (!goldenName.equals(name)) {
71                throw new RuntimeException("Bad structure: expected element name is '" + goldenName + "' but the actual name was '" + name + "'.");
72            }
73            int goldenChildCount = goldenChildren.size();
74            int childCount = elem.getChildCount();
75            if (childCount != goldenChildCount) {
76                System.out.print("D: children: ");
77                for (int i = 0; i < childCount; i++) {
78                    System.out.print(" " + elem.getElement(i).getName());
79                }
80                System.out.println("");
81                System.out.print("D: goldenChildren: ");
82                for (GoldenElement ge : goldenChildren) {
83                    System.out.print(" " + ge.goldenName);
84                }
85                System.out.println("");
86
87                throw new RuntimeException("Bad structure: expected child count of element '" + goldenName + "' is '" + goldenChildCount + "' but the actual count was '" + childCount + "'.");
88            }
89            for (int i = 0; i < childCount; i++) {
90                AbstractDocument.AbstractElement nextElem = (AbstractDocument.AbstractElement) elem.getElement(i);
91                GoldenElement goldenElement = goldenChildren.get(i);
92                goldenElement.checkStructureEquivalence(nextElem);
93            }
94        }
95    }
96
97    private JEditorPane editorPane;
98    public void execute(final String urlStr, final GoldenElement goldenElement) throws Exception {
99        System.out.println();
100        System.out.println("***** TEST: " + urlStr + " *****");
101        System.out.println();
102
103        SwingUtilities.invokeAndWait(new Runnable() {
104            public void run() {
105                try {
106                    editorPane = new JEditorPane();
107                    editorPane.setEditorKit(new HTMLEditorKit() {
108                        public Document createDefaultDocument() {
109                            AbstractDocument doc =
110                                    (AbstractDocument) super.createDefaultDocument();
111                            doc.setAsynchronousLoadPriority(-1);
112                            return doc;
113                        }
114                    });
115                    editorPane.setPage(new URL(urlStr));
116                } catch (IOException ex) {
117                    throw new RuntimeException("Test failed", ex);
118                }
119                editorPane.setEditable(false);
120                JScrollPane scroller = new JScrollPane();
121                JViewport vp = scroller.getViewport();
122                vp.add(editorPane);
123                add(scroller, BorderLayout.CENTER);
124                setDefaultCloseOperation(EXIT_ON_CLOSE);
125                setSize(400, 400);
126                setLocationRelativeTo(null);
127                setVisible(true);
128            }
129        });
130
131        Robot robot = new Robot();
132        robot.waitForIdle();
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}
308