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