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 
 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
 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      */
 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
 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 }