Skip to content

Commit

Permalink
Fix new failure in run.javac comparison from verifyClassFile()
Browse files Browse the repository at this point in the history
+ systematic handling of directories in AbstractModuleCompilationTests
  - no more ad-hoc use of 'javac' path segment
  - no longer pass 'output' parameter from individual tests
  + generally let ecj compile from 'src' to 'bin'
  + generally let javac compile from 'src' to 'javac'
+ when walking output files don't delete (for later inspection)
  + map ecj-output paths to expected javac-output paths
  - soften output when javac creates fewer classfiles in negative tests
+ support verifying classfiles from both compilers
  • Loading branch information
stephan-herrmann committed Jan 26, 2025
1 parent 7412090 commit 4b78994
Show file tree
Hide file tree
Showing 4 changed files with 203 additions and 215 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2024 GK Software SE, and others.
* Copyright (c) 2025 GK Software SE, and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
Expand All @@ -21,7 +21,6 @@
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.file.DirectoryNotEmptyException;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
Expand All @@ -31,7 +30,9 @@
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import junit.framework.AssertionFailedError;
import org.eclipse.jdt.core.util.ClassFormatException;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;

public abstract class AbstractModuleCompilationTest extends AbstractBatchCompilerTest {
Expand All @@ -45,7 +46,7 @@ public AbstractModuleCompilationTest(String name) {

class Runner extends AbstractRegressionTest.Runner {
StringBuilder commandLine = new StringBuilder();
String outputDir = OUTPUT_DIR + File.separator + "javac";
String outputDir = OUTPUT_DIR;
List<String> fileNames = new ArrayList<>();
/** will replace any -8, -9 ... option for javac */
String javacVersionOptions;
Expand All @@ -72,11 +73,22 @@ Set<String> runConformModuleTest() {
String javacCommandLine = adjustForJavac(commandLineString, this.javacVersionOptions);
return AbstractModuleCompilationTest.this.runConformModuleTest(this.testFiles, commandLineString,
this.expectedOutputString, this.expectedErrorString,
this.shouldFlushOutputDirectory, this.outputDir,
this.javacTestOptions, javacCommandLine);
this.shouldFlushOutputDirectory, this.javacTestOptions,
javacCommandLine);
}
}

protected String getSourceDir() {
return OUTPUT_DIR + File.separatorChar + "src";
}

protected String getEcjOutputDir() {
return OUTPUT_DIR + File.separatorChar + "bin";
}
protected String getJavacOutputDir() {
return OUTPUT_DIR + File.separatorChar + "javac";
}

protected void writeFileCollecting(List<String> collectedFiles, String directoryName, String fileName, String source) {
writeFile(directoryName, fileName, source);
collectedFiles.add(directoryName+File.separator+fileName);
Expand Down Expand Up @@ -104,44 +116,47 @@ protected void writeFile(String directoryName, String fileName, String source) {

protected void runConformModuleTest(List<String> testFileNames, StringBuilder commandLine, String expectedFailureOutOutputString, String expectedFailureErrOutputString) {
runConformModuleTest(testFileNames, commandLine,
expectedFailureOutOutputString, expectedFailureErrOutputString, OUTPUT_DIR + File.separator + "javac");
}

protected void runConformModuleTest(List<String> testFileNames, StringBuilder commandLine,
String expectedFailureOutOutputString, String expectedFailureErrOutputString,
String output) {
runConformModuleTest(testFileNames, commandLine,
expectedFailureOutOutputString, expectedFailureErrOutputString, output,
JavacTestOptions.DEFAULT);
expectedFailureOutOutputString, expectedFailureErrOutputString, JavacTestOptions.DEFAULT);
}
protected void runConformModuleTest(List<String> testFileNames, StringBuilder commandLine,
String expectedFailureOutOutputString, String expectedFailureErrOutputString,
String output, JavacTestOptions javacTestOptions) {
JavacTestOptions javacTestOptions) {
for (String file : testFileNames)
commandLine.append(" \"").append(file).append("\"");
runConformModuleTest(new String[0], commandLine.toString(),
expectedFailureOutOutputString, expectedFailureErrOutputString, false,
output, javacTestOptions, null);
javacTestOptions, null);
}

protected Set<String> runConformModuleTest(String[] testFiles, String commandLine, String expectedFailureOutOutputString, String expectedFailureErrOutputString, boolean shouldFlushOutputDirectory) {
return runConformModuleTest(testFiles, commandLine, expectedFailureErrOutputString, expectedFailureErrOutputString,
shouldFlushOutputDirectory, OUTPUT_DIR, JavacTestOptions.DEFAULT, null);
shouldFlushOutputDirectory, JavacTestOptions.DEFAULT, null);
}

protected Set<String> runConformModuleTest(String[] testFiles, String commandLine, String expectedFailureOutOutputString, String expectedFailureErrOutputString, boolean shouldFlushOutputDirectory, String output,
JavacTestOptions options, String javacCommandLine) {
runConformTest(testFiles, commandLine, expectedFailureOutOutputString, expectedFailureErrOutputString, shouldFlushOutputDirectory);
protected Set<String> runConformModuleTest(String[] testFiles, String commandLine, String expectedFailureOutOutputString, String expectedFailureErrOutputString, boolean shouldFlushOutputDirectory, JavacTestOptions options,
String javacCommandLine) {
String ecjOutput = getEcjOutputDir();
File ecjOutFile = new File(ecjOutput);
if (!ecjOutFile.exists()) {
ecjOutFile.mkdir();
}
String ecjCommandLine = commandLine.contains("-d ")
? commandLine
: " -d " + ecjOutput + ' ' + commandLine;
runConformTest(testFiles, ecjCommandLine, expectedFailureOutOutputString, expectedFailureErrOutputString, shouldFlushOutputDirectory);
if (shouldRunJavac()) {
File outputDir = new File(output);
final Set<String> outFiles = new HashSet<>();
walkOutFiles(output, outFiles, true);
walkOutFiles(ecjOutput, outFiles, true);

String javacOutput = getJavacOutputDir();
File javacOutputDir = new File(javacOutput);

String[] testFileNames = new String[testFiles.length/2];
for (int i = 0; i < testFileNames.length; i++) {
testFileNames[i] = testFiles[i*2];
}
if (javacCommandLine == null) {
javacCommandLine = adjustForJavac(commandLine, null);
javacCommandLine = " -d " + javacOutput + ' ' + adjustForJavac(commandLine, null);
}
for (JavacCompiler javacCompiler : javacCompilers) {
if (javacCompiler.compliance < ClassFileConstants.JDK9)
Expand All @@ -153,7 +168,7 @@ protected Set<String> runConformModuleTest(String[] testFiles, String commandLin
StringBuilder log = new StringBuilder();
try {
long compileResult = javacCompiler.compile(
outputDir, /* directory */
javacOutputDir, /* directory */
javacCommandLine /* options */,
testFileNames /* source file names */,
log,
Expand All @@ -172,8 +187,8 @@ protected Set<String> runConformModuleTest(String[] testFiles, String commandLin
e.printStackTrace();
throw new AssertionFailedError(e.getMessage());
}
final Set<String> expectedFiles = new HashSet<>(outFiles);
walkOutFiles(output, expectedFiles, false);
final Set<String> expectedFiles = outFiles.stream().map(s -> s.replace(ecjOutput, javacOutput)).collect(Collectors.toSet());
walkOutFiles(javacOutput, expectedFiles, false);
for (String missingFile : expectedFiles)
System.err.println("Missing output file from javac: "+missingFile);
}
Expand All @@ -188,78 +203,88 @@ protected StringBuilder trimJavacLog(StringBuilder log) {
}

protected void runNegativeModuleTest(List<String> testFileNames, StringBuilder commandLine, String expectedFailureOutOutputString, String expectedFailureErrOutputString, String javacErrorMatch) {
runNegativeModuleTest(testFileNames, commandLine, expectedFailureOutOutputString,
expectedFailureErrOutputString, javacErrorMatch, OUTPUT_DIR + File.separator + "javac");
}

protected void runNegativeModuleTest(List<String> testFileNames, StringBuilder commandLine, String expectedFailureOutOutputString, String expectedFailureErrOutputString, String javacErrorMatch,
String output) {
runNegativeModuleTest(testFileNames, commandLine, expectedFailureOutOutputString, expectedFailureErrOutputString,
javacErrorMatch, output, JavacTestOptions.DEFAULT);
}
runNegativeModuleTest(testFileNames, commandLine, expectedFailureOutOutputString, expectedFailureErrOutputString,
javacErrorMatch, JavacTestOptions.DEFAULT);
}

protected void runNegativeModuleTest(List<String> testFileNames, StringBuilder commandLine, String expectedFailureOutOutputString, String expectedFailureErrOutputString, String javacErrorMatch,
String output, JavacTestOptions options) {
for (String file : testFileNames)
commandLine.append(" \"").append(file).append("\"");
runNegativeModuleTest(new String[0], commandLine.toString(),
expectedFailureOutOutputString, expectedFailureErrOutputString, false, javacErrorMatch, output,
options);
}
JavacTestOptions options) {
for (String file : testFileNames)
commandLine.append(" \"").append(file).append("\"");
runNegativeModuleTest(new String[0], commandLine.toString(),
expectedFailureOutOutputString, expectedFailureErrOutputString, false, javacErrorMatch, options);
}

protected void runNegativeModuleTest(String[] testFiles, String commandLine, String expectedFailureOutOutputString, String expectedFailureErrOutputString, boolean shouldFlushOutputDirectory,
String javacErrorMatch) {
runNegativeModuleTest(testFiles, commandLine, expectedFailureOutOutputString, expectedFailureErrOutputString,
shouldFlushOutputDirectory, javacErrorMatch, OUTPUT_DIR, JavacTestOptions.DEFAULT);
}
String prefix = "src" + File.separatorChar;
for (int i = 0; i + 1 < testFiles.length; i+=2) {
testFiles[i] = prefix + testFiles[i];
}
runNegativeModuleTest(testFiles, commandLine, expectedFailureOutOutputString, expectedFailureErrOutputString,
shouldFlushOutputDirectory, javacErrorMatch, JavacTestOptions.DEFAULT);
}

void runNegativeModuleTest(String[] testFiles, String commandLine, String expectedFailureOutOutputString, String expectedFailureErrOutputString, boolean shouldFlushOutputDirectory, String javacErrorMatch,
String output, JavacTestOptions options) {
runNegativeTest(testFiles, commandLine, expectedFailureOutOutputString, expectedFailureErrOutputString, shouldFlushOutputDirectory);
if (shouldRunJavac()) {
String[] testFileNames = new String[testFiles.length/2];
for (int i = 0; i < testFileNames.length; i++) {
testFileNames[i] = testFiles[i*2];
}
File outputDir = new File(OUTPUT_DIR);
final Set<String> outFiles = new HashSet<>();
walkOutFiles(output, outFiles, true);
for (JavacCompiler javacCompiler : javacCompilers) {
if (javacCompiler.compliance < ClassFileConstants.JDK9)
continue;
JavacTestOptions.Excuse excuse = options.excuseFor(javacCompiler);
JavacTestOptions options) {
String ecjOutput = getEcjOutputDir();
File ecjOutFile = new File(ecjOutput);
if (!ecjOutFile.exists()) {
ecjOutFile.mkdir();
}
String ecjCommandLine = commandLine.contains("-d ")
? commandLine
: " -d " + ecjOutput + ' ' + commandLine;
runNegativeTest(testFiles, ecjCommandLine, expectedFailureOutOutputString, expectedFailureErrOutputString, shouldFlushOutputDirectory);
if (shouldRunJavac()) {
final Set<String> outFiles = new HashSet<>();
walkOutFiles(ecjOutput, outFiles, true);

commandLine = adjustForJavac(commandLine, null);
StringBuilder log = new StringBuilder();
int mismatch = 0;
try {
long compileResult = javacCompiler.compile(
outputDir, /* directory */
commandLine /* options */,
testFileNames /* source file names */,
log);
if (compileResult == 0) {
mismatch = JavacTestOptions.MismatchType.EclipseErrorsJavacNone;
javacErrorMatch = expectedFailureErrOutputString;
System.err.println("Previous error was from "+testName());
} else if (!log.toString().contains(javacErrorMatch)) {
mismatch = JavacTestOptions.MismatchType.CompileErrorMismatch;
System.err.println(testName()+": Error match " + javacErrorMatch + " not found in \n"+log.toString());
}
} catch (IOException | InterruptedException e) {
e.printStackTrace();
throw new AssertionFailedError(e.getMessage());
}
handleMismatch(javacCompiler, testName(), testFiles, javacErrorMatch,
"", "", log, "", "",
excuse, mismatch);
final Set<String> expectedFiles = new HashSet<>(outFiles);
walkOutFiles(output, expectedFiles, false);
for (String missingFile : expectedFiles)
System.err.println("Missing output file from javac: "+missingFile);
String javacOutput = getJavacOutputDir();
File outputDir = new File(javacOutput);

String[] testFileNames = new String[testFiles.length/2];
for (int i = 0; i < testFileNames.length; i++) {
testFileNames[i] = testFiles[i*2];
}

for (JavacCompiler javacCompiler : javacCompilers) {
if (javacCompiler.compliance < ClassFileConstants.JDK9)
continue;
JavacTestOptions.Excuse excuse = options.excuseFor(javacCompiler);

String javacCommandLine = " -d " + javacOutput + ' ' + adjustForJavac(commandLine, null);
StringBuilder log = new StringBuilder();
int mismatch = 0;
try {
long compileResult = javacCompiler.compile(
outputDir, /* directory */
javacCommandLine /* options */,
testFileNames /* source file names */,
log,
false);
if (compileResult == 0) {
mismatch = JavacTestOptions.MismatchType.EclipseErrorsJavacNone;
javacErrorMatch = expectedFailureErrOutputString;
System.err.println("Previous error was from "+testName());
} else if (!log.toString().contains(javacErrorMatch)) {
mismatch = JavacTestOptions.MismatchType.CompileErrorMismatch;
System.err.println(testName()+": Error match " + javacErrorMatch + " not found in \n"+log.toString());
}
} catch (IOException | InterruptedException e) {
e.printStackTrace();
throw new AssertionFailedError(e.getMessage());
}
handleMismatch(javacCompiler, testName(), testFiles, javacErrorMatch,
"", "", log, "", "",
excuse, mismatch);
final Set<String> expectedFiles = outFiles.stream().map(s -> s.replace(ecjOutput, javacOutput)).collect(Collectors.toSet());
walkOutFiles(javacOutput, expectedFiles, false);
for (String missingFile : expectedFiles)
System.out.println("Missing output file from javac in negative test: "+missingFile);
}
}
}

/**
* @param commandLine command line arguments as used for ecj
Expand Down Expand Up @@ -329,21 +354,9 @@ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IO
if (!fileNames.remove(file.toString()))
System.err.println("Unexpected output file from javac: "+file.toString());
}
Files.delete(file);
}
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
if (!dir.toString().equals(outputLocation)) {
try {
Files.delete(dir);
} catch (DirectoryNotEmptyException ex) {
// expected
}
}
return FileVisitResult.CONTINUE;
}
});
} catch (IOException e) {
e.printStackTrace();
Expand All @@ -358,5 +371,15 @@ protected void assertClassFile(String msg, String fileName, Set<String> classFil
assertTrue(msg, (new File(fileName).exists()));
}
}

@Override
protected void verifyClassFile(String expectedOutput, String classFileName, int mode) throws IOException, ClassFormatException {
verifyClassFile(expectedOutput, classFileName, mode, false);
}
protected void verifyClassFile(String expectedOutput, String classFileName, int mode, boolean skipJavac)
throws IOException, ClassFormatException {
verifyClassFile(expectedOutput, null, getEcjOutputDir()+File.separatorChar+classFileName, mode);
if (!skipJavac && shouldRunJavac()) {
verifyClassFile(expectedOutput, null, getJavacOutputDir()+File.separatorChar+classFileName, mode);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1510,7 +1510,9 @@ protected void checkDisassembledClassFile(String fileName, String className, Str

protected static void verifyClassFile(String expectedOutput, String unexpectedOutput, String classFileName, int mode)
throws IOException, ClassFormatException {
File f = new File(OUTPUT_DIR + File.separator + classFileName);
if (!classFileName.startsWith(OUTPUT_DIR))
classFileName = OUTPUT_DIR + File.separator + classFileName;
File f = new File(classFileName);
byte[] classFileBytes = org.eclipse.jdt.internal.compiler.util.Util.getFileByteContent(f);
ClassFileBytesDisassembler disassembler = ToolFactory.createDefaultClassFileBytesDisassembler();
String result = disassembler.disassemble(classFileBytes, "\n", mode);
Expand Down
Loading

0 comments on commit 4b78994

Please sign in to comment.