1 /*
2  * Copyright (c) 2017, 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 import java.io.ByteArrayInputStream;
25 import java.io.ByteArrayOutputStream;
26 import java.io.File;
27 import java.io.IOException;
28 import java.lang.reflect.InvocationTargetException;
29 import java.lang.reflect.Method;
30 import java.nio.file.Files;
31 import java.nio.file.Paths;
32 import java.security.*;
33 import java.util.*;
34 import java.util.concurrent.atomic.AtomicBoolean;
35 import java.util.logging.FileHandler;
36 import java.util.logging.LogManager;
37 
38 /**
39  * @test
40  * @bug 8189953
41  * @summary tests the pattern generation algorithm
42  * @modules java.logging/java.util.logging:open
43  * @run main/othervm FileHandlerPatternGeneration
44  * @author danielfuchs
45  */
46 public class FileHandlerPatternGeneration {
47 
48     /**
49      * An array of strings where the elements at even indices are the input
50      * to give to FileHandler::generate(pattern, count, generation, unique),
51      * and the elements at the next odd index are a partially computed expected
52      * output, where %t, %h, %u, %g and file separator still need to be replaced.
53      * The final expected output is obtained by passing the partially computed
54      * output to FileHandlerPatternGeneration::generateExpected
55      * <p>
56      * The test verifies that {@code
57      *    FileHandler.generate(PATTERN[i], c, g, u).toString()
58      * }
59      * is equal to {@code
60      *    FileHandlerPatternGeneration.generateExpected(PATTERN[i],
61      *                                                  PATTERN[i+1],
62      *                                                  c, g, u)
63      * }
64      */
65     static final String[] PATTERNS = {
66             "C:/Workspace/hoge.log",         "C:/Workspace/hoge.log",
67             "C:/Workspace%g/hoge.log",       "C:/Workspace%g/hoge.log",
68             "C:/%uWorkspace/hoge.log",       "C:/%uWorkspace/hoge.log",
69             "C:/%uWorkspace%g/hoge.log",     "C:/%uWorkspace%g/hoge.log",
70             "C:/Workspace/%ghoge.log",       "C:/Workspace/%ghoge.log",
71             "C:/Workspace/%ghoge%u.log",     "C:/Workspace/%ghoge%u.log",
72             "C:/Workspace-%g/hoge.log",      "C:/Workspace-%g/hoge.log",
73             "C:/Work%hspace/hoge.log",       "%h/space/hoge.log",
74             "C:/Works%tpace%g/hoge.log",     "%t/pace%g/hoge.log",
75             "C:/%uWork%hspace/hoge.log",     "%h/space/hoge.log",
76             "C:/%uWorkspace%g/%thoge.log",   "%t/hoge.log",
77             "C:/Workspace/%g%h%%hoge.log",   "%h/%%hoge.log",
78             "C:/Work%h%%hspace/hoge.log",    "%h/%%hspace/hoge.log",
79             "C:/Works%t%%hpace%g/hoge.log",  "%t/%%hpace%g/hoge.log",
80             "C:/%uWork%h%%tspace/hoge.log",  "%h/%%tspace/hoge.log",
81             "C:/%uWorkspace%g/%t%%hoge.log", "%t/%%hoge.log",
82             "C:/Workspace/%g%h%%hoge.log",   "%h/%%hoge.log",
83             "ahaha",                         "ahaha",
84             "ahaha/ahabe",                   "ahaha/ahabe",
85             "../ahaha/ahabe",                "../ahaha/ahabe",
86             "/x%ty/w/hoge.log",              "%t/y/w/hoge.log",
87             "/x/%ty/w/hoge.log",             "%t/y/w/hoge.log",
88             "/x%t/y/w/hoge.log",             "%t/y/w/hoge.log",
89             "/x/%t/y/w/hoge.log",            "%t/y/w/hoge.log",
90             "%ty/w/hoge.log",                "%t/y/w/hoge.log",
91             "%t/y/w/hoge.log",               "%t/y/w/hoge.log",
92             "/x%hy/w/hoge.log",              "%h/y/w/hoge.log",
93             "/x/%hy/w/hoge.log",             "%h/y/w/hoge.log",
94             "/x%h/y/w/hoge.log",             "%h/y/w/hoge.log",
95             "/x/%h/y/w/hoge.log",            "%h/y/w/hoge.log",
96             "%hy/w/hoge.log",                "%h/y/w/hoge.log",
97             "%h/y/w/hoge.log",               "%h/y/w/hoge.log",
98             "ahaha-%u-%g",                   "ahaha-%u-%g",
99             "ahaha-%g/ahabe-%u",             "ahaha-%g/ahabe-%u",
100             "../ahaha-%u/ahabe",             "../ahaha-%u/ahabe",
101             "/x%ty/w/hoge-%g.log",           "%t/y/w/hoge-%g.log",
102             "/x/%ty/w/hoge-%u.log",          "%t/y/w/hoge-%u.log",
103             "%u-%g/x%t/y/w/hoge.log",        "%t/y/w/hoge.log",
104             "/x/%g%t%u/y/w/hoge.log",        "%t/%u/y/w/hoge.log",
105             "%ty/w-%g/hoge.log",             "%t/y/w-%g/hoge.log",
106             "%t/y/w-%u/hoge.log",            "%t/y/w-%u/hoge.log",
107             "/x%hy/%u-%g-w/hoge.log",        "%h/y/%u-%g-w/hoge.log",
108             "/x/%hy/w-%u-%g/hoge.log",       "%h/y/w-%u-%g/hoge.log",
109             "/x%h/y/w/%u-%ghoge.log",        "%h/y/w/%u-%ghoge.log",
110             "/x/%h/y/w/hoge-%u-%g.log",      "%h/y/w/hoge-%u-%g.log",
111             "%hy/w/%u-%g-hoge.log",          "%h/y/w/%u-%g-hoge.log",
112             "%h/y/w/hoge-%u-%g.log",         "%h/y/w/hoge-%u-%g.log",
113             "/x/y/z/hoge-%u.log",            "/x/y/z/hoge-%u.log",
114     };
115 
116     // the (count, generation, unique) parameters to pass to
117     // FileHandler.generate(pattern, count, generation, unique)
118     static final int[][] GENERATIONS = {
119         {0, 0, 0},
120         {0, 1, 0},
121         {0, 1, 1},
122         {1, 1, 0},
123         {1, 1, 1},
124         {1, 1, 2},
125         {1, 2, 3},
126         {3, 4, 0},
127         {3, 4, 1},
128         {3, 4, 2},
129         {3, 0, 5},
130         {3, 1, 5},
131         {3, 2, 5},
132     };
133 
134     static final Class<FileHandler> FILE_HANDLER_CLASS = FileHandler.class;
135     static final Method GENERATE;
136     static final String USER_HOME;
137     static final String TMP;
138     static {
139         Method generate;
140         try {
141            generate = FILE_HANDLER_CLASS.getDeclaredMethod("generate",
142                                                             String.class,
143                                                             int.class,
144                                                             int.class,
145                                                             int.class);
146            generate.setAccessible(true);
147         } catch (Exception e) {
148             throw new ExceptionInInitializerError(e);
149         }
150         GENERATE = generate;
151         USER_HOME = System.getProperty("user.home");
152         TMP = System.getProperty("java.io.tmpdir", USER_HOME);
153     }
154 
main(String... args)155     public static void main(String... args) throws Throwable {
156 
157         for (int i=0; i < PATTERNS.length; i+=2) {
158             String s = PATTERNS[i];
159             String partial = PATTERNS[i+1];
160             System.out.println("generate: " + s);
161             for (int[] gen : GENERATIONS) {
162                 String expected = generateExpected(s, partial, gen[0], gen[1], gen[2]);
163                 String output = generate(s, gen[0], gen[1], gen[2]).toString();
164                 System.out.println("\t" + Arrays.toString(gen)+ ": " + output);
165                 if (!expected.equals(output)) {
166                     throw new RuntimeException("test failed for \""
167                             + s +"\" " + Arrays.toString(gen) + ": "
168                             + "\n\tgenerated: \"" + output +"\""
169                             + "\n\t expected: \"" + expected +"\"");
170                 }
171             }
172         }
173 
174     }
175 
176     // Strip the trailing separator from the string, if present
stripTrailingSeparator(String s)177     static String stripTrailingSeparator(String s) {
178         if (s.endsWith("/")) {
179             return s.substring(0, s.length() -1);
180         } else if (s.endsWith(File.separator)) {
181             return s.substring(0, s.length() - File.separator.length());
182         } else {
183             return s;
184         }
185     }
186 
187     /**
188      * Compute the final expected output from a partially computed output found
189      * at PATTERNS[i+1]
190      * @param s           The pattern string, found at PATTERN[i]
191      *                    (with i % 2 == 0)
192      * @param partial     The partially computed output, found at PATTERN[i+1]
193      * @param count       The count parameter given to FileHandler::generate
194      * @param generation  The generation parameter given to FileHandler::generate
195      * @param unique      The unique parameter given to FileHandler::generate
196      * @return  The expected output that FileHandler.generate(s, count, gen, unique)
197      *          should produce.
198      */
generateExpected(String s, String partial, int count, int generation, int unique)199     static String generateExpected(String s, String partial,
200                                    int count, int generation, int unique)
201     {
202         boolean sawu = s.replace("%%", "$$$$").contains("%u");
203         boolean sawg = s.replace("%%", "$$$$").contains("%g");
204         String result = partial.replace("%%", "$$$$");
205         String tmp = stripTrailingSeparator(TMP);
206         String home = stripTrailingSeparator(USER_HOME);
207         result = result.replace("%h", home);
208         result = result.replace("%t", tmp);
209         result = result.replace("%g", String.valueOf(generation));
210         result = result.replace("%u", String.valueOf(unique));
211         result = result.replace("$$$$", "%");
212         result = result.replace("/", File.separator);
213         if (count > 1 && !sawg) {
214             result = result + "." + generation;
215         }
216         if (unique > 0 && !sawu) {
217             result = result + "." + unique;
218         }
219         return result;
220     }
221 
222     // Calls FileHandler.generate(s, count, generation, unique) through reflection
generate(String s, int count, int generation, int unique)223     static File generate(String s, int count, int generation, int unique)
224             throws Throwable
225     {
226         try {
227             return (File) GENERATE.invoke(null, s, count, generation, unique);
228         } catch (InvocationTargetException e) {
229             throw e.getCause();
230         }
231     }
232 }
233