1 /*
2  * Copyright (c) 2015, 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 package compiler.compilercontrol.share.processors;
25 
26 import compiler.compilercontrol.share.method.MethodDescriptor;
27 import compiler.compilercontrol.share.method.MethodGenerator;
28 import compiler.compilercontrol.share.pool.PoolHelper;
29 import compiler.compilercontrol.share.scenario.State;
30 import jdk.test.lib.Asserts;
31 import jdk.test.lib.process.OutputAnalyzer;
32 
33 import java.io.File;
34 import java.io.FileNotFoundException;
35 import java.lang.reflect.Executable;
36 import java.util.List;
37 import java.util.Map;
38 import java.util.Scanner;
39 import java.util.function.Consumer;
40 import java.util.regex.Matcher;
41 import java.util.regex.Pattern;
42 import java.util.stream.Collectors;
43 
44 /**
45  * Log compilation file processor
46  */
47 public class LogProcessor implements Consumer<OutputAnalyzer> {
48     public static final String LOG_FILE = "compilation.log";
49     private static final String TASK_ELEMENT = "<task [^>]*>";
50     private static final String TASK_DONE_ELEMENT = "<task_done [^>]*>";
51     private static final String TASK_END_ELEMENT = "</task>";
52     private static final String ANY_ELEMENT = "<[^>]*>";
53     private static final Pattern METHOD_PATTERN = Pattern.compile(
54             "method='([^']+)'");
55     private final List<String> loggedMethods;
56     private final List<String> testMethods;
57 
LogProcessor(Map<Executable, State> states)58     public LogProcessor(Map<Executable, State> states) {
59         loggedMethods = states.keySet().stream()
60                 .filter(x -> states.get(x).isLog())
61                 .map(MethodGenerator::commandDescriptor)
62                 .map(MethodDescriptor::getString)
63                 .collect(Collectors.toList());
64         testMethods = new PoolHelper().getAllMethods()
65                 .stream()
66                 .map(pair -> pair.first)
67                 .map(MethodGenerator::commandDescriptor)
68                 .map(MethodDescriptor::getString)
69                 .collect(Collectors.toList());
70     }
71 
72     @Override
accept(OutputAnalyzer outputAnalyzer)73     public void accept(OutputAnalyzer outputAnalyzer) {
74         if (loggedMethods.isEmpty()) {
75             return;
76         }
77         matchTasks();
78     }
79 
80     /*
81      * Gets scanner for log file of the test case
82      */
getScanner()83     private Scanner getScanner() {
84         File logFile = new File(LOG_FILE);
85         Scanner scanner;
86         try {
87             scanner = new Scanner(logFile);
88         } catch (FileNotFoundException e) {
89             throw new Error("TESTBUG: file not found: " + logFile, e);
90         }
91         return scanner;
92     }
93 
94     /*
95      * Parses for &lt;task method='java.lang.String indexOf (I)I' &gt;
96      * and finds if there is a compilation log for this task
97      */
matchTasks()98     private void matchTasks() {
99         try (Scanner scanner = getScanner()) {
100           String task = scanner.findWithinHorizon(TASK_ELEMENT, 0);
101           while (task != null) {
102               String element = scanner.findWithinHorizon(ANY_ELEMENT, 0);
103               if (Pattern.matches(TASK_DONE_ELEMENT, element)
104                       || Pattern.matches(TASK_END_ELEMENT, element)) {
105                   /* If there is nothing between <task> and </task>
106                      except <task done /> then compilation log is empty.
107                      Check the method in this task should not be logged */
108                   Asserts.assertFalse(matchMethod(task), "Compilation log "
109                           + "expected. Met: " + element);
110               }
111               task = scanner.findWithinHorizon(TASK_ELEMENT, 0);
112           }
113         }
114     }
115 
116     // Check that input method should be logged
matchMethod(String input)117     private boolean matchMethod(String input) {
118         Matcher matcher = METHOD_PATTERN.matcher(input);
119         Asserts.assertTrue(matcher.find(), "Wrong matcher or input");
120         // Get method and normalize it
121         String method = normalize(matcher.group(1));
122         if (loggedMethods.contains(method)) {
123             return true;
124         }
125         if (!testMethods.contains(method)) {
126             return false;
127         }
128         return false;
129     }
130 
131     // Normalize given signature to conform regular expression used in tests
normalize(String method)132     private String normalize(String method) {
133         return method.replaceAll("\\.", "/") // replace dots in a class string
134                 .replaceFirst(" ", ".")      // replace space between class and method
135                 .replaceFirst(" ", "")       // remove space between method and signature
136                 .replace("&lt;", "<")
137                 .replace("&gt;", ">");
138     }
139 }
140