/*
* Copyright 2015-present Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License. You may obtain
* a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package com.facebook.buck.jvm.java;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.file.Paths;
import java.util.Locale;
import javax.annotation.Nullable;
import javax.tools.Diagnostic;
import javax.tools.JavaFileObject;
import javax.tools.SimpleJavaFileObject;
import org.junit.Test;
public class DiagnosticPrettyPrinterTest {
@Test
public void ifThereAreNoLineNumbersOnlyTheFormattedMessageIsReturned() throws Exception {
String message = "Something has gone wrong.";
String formatted =
DiagnosticPrettyPrinter.format(
createDiagnostic(message, "Example.java", "package foo", -1, -1));
// Paths should be absolute.
assertEquals(
Paths.get("Example.java").toUri().getPath() + ":-1: error: Something has gone wrong.\n",
formatted);
}
@Test
public void ifThereAreNoLineNumbersAllLinesOfTheFormattedMessageAreReturned() throws Exception {
String summary = "Something has gone wrong";
String remainder = "Very, very wrong";
String formatted =
DiagnosticPrettyPrinter.format(
createDiagnostic(summary + "\n" + remainder, "Example.java", "package foo", -1, -1));
assertTrue(formatted, formatted.contains(summary));
assertTrue(formatted, formatted.contains(remainder));
}
@Test
public void ifThereAreLineNumbersErrorContextIsDisplayed() throws Exception {
String code = "some line of\ncode with an\nerror";
// 123
String formatted =
DiagnosticPrettyPrinter.format(createDiagnostic("EOL", "Example.java", code, 2, 3));
assertTrue(formatted, formatted.contains("code with an\n ^"));
}
@Test
public void errorContextIsDisplayedAfterTheSummaryButBeforeTheRemainderOfTheMessage()
throws Exception {
String code = "some line of\ncode with an\nerror";
// 123
String formatted =
DiagnosticPrettyPrinter.format(
createDiagnostic(
"Oh noes!\nAll your build\nAre Belong to Fail", "Example.java", code, 2, 3));
// The path is actually prefixed with the cwd. This is close enough to the full report to do.
assertTrue(
formatted,
formatted.contains(
"Example.java:2: error: Oh noes!\n"
+ "code with an\n"
+ " ^\n"
+ "All your build\n"
+ "Are Belong to Fail"));
}
/**
* Create a {@link Diagnostic} for use in tests.
*
* @param message The compilation error message.
* @param row The row within the source, 1-indexed because the compiler does that.
* @param column The column within {@code row}, also 1-indexed.
*/
private Diagnostic<? extends JavaFileObject> createDiagnostic(
final String message,
String pathToSource,
String sourceContents,
final long row,
final long column)
throws Exception {
final JavaFileObject fileObject = new StringJavaFileObject(pathToSource, sourceContents);
// Calculate the position, because we're all bad at counting things
int pos = -1;
if (row != -1) {
pos = -1;
int rowCount = 1;
while (rowCount <= row) {
pos++;
if (sourceContents.charAt(pos) == '\n') {
rowCount++;
}
}
// And now just add the row, which is 1 indexed, so we then subtract 1.
pos += row - 1;
}
final int position = pos;
return new Diagnostic<JavaFileObject>() {
@Override
public Kind getKind() {
return Kind.ERROR;
}
@Override
public JavaFileObject getSource() {
return fileObject;
}
@Override
public long getPosition() {
return position;
}
@Override
public long getStartPosition() {
return position;
}
@Override
public long getEndPosition() {
return position;
}
@Override
public long getLineNumber() {
return row;
}
@Override
public long getColumnNumber() {
return column;
}
@Override
@Nullable
public String getCode() {
return null;
}
@Override
public String getMessage(Locale locale) {
return message;
}
};
}
private class StringJavaFileObject extends SimpleJavaFileObject {
private final String content;
protected StringJavaFileObject(String pathToSource, String content) throws URISyntaxException {
super(Paths.get(pathToSource).toUri(), Kind.SOURCE);
this.content = content;
}
@Override
public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
return content;
}
}
}