| // Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file |
| // for details. All rights reserved. Use of this source code is governed by a |
| // BSD-style license that can be found in the LICENSE file. |
| |
| package com.android.tools.r8; |
| |
| import static org.hamcrest.MatcherAssert.assertThat; |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.assertFalse; |
| import static org.junit.Assert.assertNotEquals; |
| import static org.junit.Assert.fail; |
| |
| import com.android.tools.r8.utils.ListUtils; |
| import com.google.common.collect.Iterables; |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Set; |
| import java.util.function.BiFunction; |
| import org.hamcrest.Matcher; |
| |
| public class TestDiagnosticMessagesImpl extends TestDiagnosticMessages |
| implements DiagnosticsHandler { |
| private final List<Diagnostic> infos = new ArrayList<>(); |
| private final List<Diagnostic> warnings = new ArrayList<>(); |
| private final List<Diagnostic> errors = new ArrayList<>(); |
| BiFunction<DiagnosticsLevel, Diagnostic, DiagnosticsLevel> modifier; |
| |
| @Override |
| public String toString() { |
| StringBuilder builder = new StringBuilder(); |
| builder.append("Infos: ").append('\n'); |
| for (Diagnostic info : infos) { |
| builder.append(" - ").append(info.getDiagnosticMessage()).append('\n'); |
| } |
| builder.append("Warnings: ").append('\n'); |
| for (Diagnostic warning : warnings) { |
| builder.append(" - ").append(warning.getDiagnosticMessage()).append('\n'); |
| } |
| builder.append("Errors: ").append('\n'); |
| for (Diagnostic error : errors) { |
| builder.append(" - ").append(error.getDiagnosticMessage()).append('\n'); |
| } |
| return builder.toString(); |
| } |
| |
| @Override |
| public void info(Diagnostic info) { |
| // We are almost always compiling with assertions enabled and R8 will print a message. We |
| // discard the message here because for almost all tests, this message is not relevant. |
| if (!info.getDiagnosticMessage() |
| .equals("Running R8 version " + Version.LABEL + " with assertions enabled.")) { |
| infos.add(info); |
| } |
| } |
| |
| @Override |
| public void warning(Diagnostic warning) { |
| warnings.add(warning); |
| } |
| |
| @Override |
| public void error(Diagnostic error) { |
| errors.add(error); |
| } |
| |
| @Override |
| public DiagnosticsLevel modifyDiagnosticsLevel(DiagnosticsLevel level, Diagnostic diagnostic) { |
| return modifier == null ? level : modifier.apply(level, diagnostic); |
| } |
| |
| @Override |
| public List<Diagnostic> getInfos() { |
| return infos; |
| } |
| |
| @Override |
| public List<Diagnostic> getWarnings() { |
| return warnings; |
| } |
| |
| @Override |
| public List<Diagnostic> getErrors() { |
| return errors; |
| } |
| |
| private void assertEmpty(String type, List<Diagnostic> messages) { |
| assertEquals( |
| "Expected no " |
| + type |
| + " messages, got:\n" |
| + String.join("\n", ListUtils.map(messages, Diagnostic::getDiagnosticMessage)), |
| 0, |
| messages.size()); |
| } |
| |
| @Override |
| public TestDiagnosticMessages assertNoMessages() { |
| assertEmpty("info", getInfos()); |
| assertEmpty("warning", getWarnings()); |
| assertEmpty("error", getErrors()); |
| return this; |
| } |
| |
| @Override |
| public TestDiagnosticMessages assertHasWarnings() { |
| assertFalse(warnings.isEmpty()); |
| return this; |
| } |
| |
| @Override |
| public TestDiagnosticMessages assertOnlyInfos() { |
| assertNotEquals(0, getInfos().size()); |
| assertEmpty("warning", getWarnings()); |
| assertEmpty("error", getErrors()); |
| return this; |
| } |
| |
| @Override |
| public TestDiagnosticMessages assertOnlyWarnings() { |
| assertEmpty("info", getInfos()); |
| assertNotEquals(0, getWarnings().size()); |
| assertEmpty("error", getErrors()); |
| return this; |
| } |
| |
| @Override |
| public TestDiagnosticMessages assertOnlyErrors() { |
| assertEmpty("info", getInfos()); |
| assertEmpty("warning", getWarnings()); |
| assertNotEquals(0, getErrors().size()); |
| return this; |
| } |
| |
| @Override |
| public TestDiagnosticMessages assertInfosCount(int count) { |
| assertEquals(count, getInfos().size()); |
| return this; |
| } |
| |
| @Override |
| public TestDiagnosticMessages assertWarningsCount(int count) { |
| assertEquals(count, getWarnings().size()); |
| return this; |
| } |
| |
| @Override |
| public TestDiagnosticMessages assertErrorsCount(int count) { |
| assertEquals(count, getErrors().size()); |
| return this; |
| } |
| |
| private TestDiagnosticMessages assertAllDiagnosticsMatches( |
| Iterable<Diagnostic> diagnostics, String tag, Matcher<Diagnostic> matcher) { |
| for (Diagnostic diagnostic : diagnostics) { |
| assertThat(diagnostic, matcher); |
| } |
| return this; |
| } |
| |
| private TestDiagnosticMessages assertDiagnosticThatMatches( |
| Iterable<Diagnostic> diagnostics, String tag, Matcher<Diagnostic> matcher) { |
| int numberOfDiagnostics = 0; |
| for (Diagnostic diagnostic : diagnostics) { |
| if (matcher.matches(diagnostic)) { |
| return this; |
| } |
| numberOfDiagnostics++; |
| } |
| StringBuilder builder = new StringBuilder("No " + tag + " matches " + matcher.toString()); |
| builder.append(System.lineSeparator()); |
| if (numberOfDiagnostics == 0) { |
| builder.append("There were no " + tag + "s."); |
| } else { |
| builder.append("There were " + numberOfDiagnostics + " " + tag + "s:"); |
| builder.append(System.lineSeparator()); |
| for (Diagnostic diagnostic : diagnostics) { |
| builder.append(diagnostic.getDiagnosticMessage()); |
| builder.append(System.lineSeparator()); |
| } |
| } |
| fail(builder.toString()); |
| return this; |
| } |
| |
| private static void assertDiagnosticsMatch( |
| Iterable<Diagnostic> diagnostics, String tag, Collection<Matcher<Diagnostic>> matchers) { |
| // Match is unordered, but we make no attempts to find the maximum match. |
| int diagnosticsCount = 0; |
| Set<Diagnostic> matchedDiagnostics = new HashSet<>(); |
| Set<Matcher<Diagnostic>> matchedMatchers = new HashSet<>(); |
| for (Diagnostic diagnostic : diagnostics) { |
| diagnosticsCount++; |
| for (Matcher<Diagnostic> matcher : matchers) { |
| if (matchedMatchers.contains(matcher)) { |
| continue; |
| } |
| if (matcher.matches(diagnostic)) { |
| matchedDiagnostics.add(diagnostic); |
| matchedMatchers.add(matcher); |
| break; |
| } |
| } |
| } |
| StringBuilder builder = new StringBuilder(); |
| boolean failedMatching = false; |
| if (matchedDiagnostics.size() < diagnosticsCount) { |
| failedMatching = true; |
| builder.append("\nUnmatched diagnostics:"); |
| for (Diagnostic diagnostic : diagnostics) { |
| if (!matchedDiagnostics.contains(diagnostic)) { |
| builder |
| .append("\n - ") |
| .append(diagnostic.getClass().getName()) |
| .append(": ") |
| .append(diagnostic.getDiagnosticMessage()); |
| } |
| } |
| } |
| if (matchedMatchers.size() < matchers.size()) { |
| failedMatching = true; |
| builder.append("\nUnmatched matchers:"); |
| for (Matcher<Diagnostic> matcher : matchers) { |
| if (!matchedMatchers.contains(matcher)) { |
| builder.append("\n - ").append(matcher); |
| } |
| } |
| } |
| if (failedMatching) { |
| builder.append("\nAll diagnostics:"); |
| for (Diagnostic diagnostic : diagnostics) { |
| builder |
| .append("\n - ") |
| .append(diagnostic.getClass().getName()) |
| .append(": ") |
| .append(diagnostic.getDiagnosticMessage()); |
| } |
| builder.append("\nAll matchers:"); |
| for (Matcher<Diagnostic> matcher : matchers) { |
| builder.append("\n - ").append(matcher); |
| } |
| fail(builder.toString()); |
| } |
| // Double check consistency. |
| assertEquals(matchers.size(), diagnosticsCount); |
| assertEquals(diagnosticsCount, matchedDiagnostics.size()); |
| assertEquals(diagnosticsCount, matchedMatchers.size()); |
| } |
| |
| @Override |
| public TestDiagnosticMessages assertDiagnosticsMatch(Collection<Matcher<Diagnostic>> matchers) { |
| assertDiagnosticsMatch(getAllDiagnostics(), "diagnostics", matchers); |
| return this; |
| } |
| |
| @Override |
| public TestDiagnosticMessages assertInfosMatch(Collection<Matcher<Diagnostic>> matchers) { |
| assertDiagnosticsMatch(getInfos(), "infos", matchers); |
| return this; |
| } |
| |
| @Override |
| public TestDiagnosticMessages assertWarningsMatch(Collection<Matcher<Diagnostic>> matchers) { |
| assertDiagnosticsMatch(getWarnings(), "warnings", matchers); |
| return this; |
| } |
| |
| @Override |
| public TestDiagnosticMessages assertErrorsMatch(Collection<Matcher<Diagnostic>> matchers) { |
| assertDiagnosticsMatch(getErrors(), "errors", matchers); |
| return this; |
| } |
| |
| @Override |
| public TestDiagnosticMessages assertDiagnosticThatMatches(Matcher<Diagnostic> matcher) { |
| return assertDiagnosticThatMatches(getAllDiagnostics(), "diagnostic message", matcher); |
| } |
| |
| private Iterable<Diagnostic> getAllDiagnostics() { |
| return Iterables.concat(getInfos(), getWarnings(), getErrors()); |
| } |
| |
| @Override |
| public TestDiagnosticMessages assertInfoThatMatches(Matcher<Diagnostic> matcher) { |
| return assertDiagnosticThatMatches(getInfos(), "info", matcher); |
| } |
| |
| @Override |
| public TestDiagnosticMessages assertWarningThatMatches(Matcher<Diagnostic> matcher) { |
| return assertDiagnosticThatMatches(getWarnings(), "warning", matcher); |
| } |
| |
| @Override |
| public TestDiagnosticMessages assertErrorThatMatches(Matcher<Diagnostic> matcher) { |
| return assertDiagnosticThatMatches(getErrors(), "error", matcher); |
| } |
| |
| @Override |
| public TestDiagnosticMessages assertAllDiagnosticsMatch(Matcher<Diagnostic> matcher) { |
| return assertAllDiagnosticsMatches(getAllDiagnostics(), "diagnostic message", matcher); |
| } |
| |
| @Override |
| public TestDiagnosticMessages assertAllInfosMatch(Matcher<Diagnostic> matcher) { |
| return assertAllDiagnosticsMatches(getInfos(), "info", matcher); |
| } |
| |
| @Override |
| public TestDiagnosticMessages assertAllWarningsMatch(Matcher<Diagnostic> matcher) { |
| return assertAllDiagnosticsMatches(getWarnings(), "warning", matcher); |
| } |
| |
| @Override |
| public TestDiagnosticMessages assertAllErrorsMatch(Matcher<Diagnostic> matcher) { |
| return assertAllDiagnosticsMatches(getErrors(), "error", matcher); |
| } |
| |
| void setDiagnosticsLevelModifier( |
| BiFunction<DiagnosticsLevel, Diagnostic, DiagnosticsLevel> modifier) { |
| this.modifier = modifier; |
| } |
| } |