/******************************************************************************* * Copyright © 2011, 2013 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation * *******************************************************************************/ package org.eclipse.edt.tests.validation.junit; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.PrintStream; import java.io.RandomAccessFile; import java.io.Reader; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.MissingResourceException; import java.util.ResourceBundle; import java.util.TreeMap; import java.util.TreeSet; import java_cup.runtime.Scanner; import junit.framework.TestCase; import org.eclipse.edt.compiler.Processor; import org.eclipse.edt.compiler.core.ast.AccumulatingSyntaxErrorRequestor; import org.eclipse.edt.compiler.core.ast.ErrorCorrectingParser; import org.eclipse.edt.compiler.core.ast.ISyntaxErrorRequestor; import org.eclipse.edt.compiler.core.ast.Lexer; import org.eclipse.edt.compiler.core.ast.SyntaxError; import org.eclipse.edt.compiler.internal.core.builder.DefaultProblemRequestor; import org.eclipse.edt.compiler.internal.core.builder.IMarker; import org.eclipse.edt.compiler.internal.core.builder.IProblemRequestor; import org.eclipse.edt.compiler.internal.sdk.compile.ISDKProblemRequestorFactory; import org.eclipse.edt.compiler.internal.sdk.utils.SDKLineTracker; import org.eclipse.edt.compiler.tools.EGL2IR; import org.eclipse.edt.tests.validation.util.ProblemCollectingProblemRequestor; /** * @author Dave Murray */ public abstract class ValidationTestCase extends TestCase { //PROFILE public static boolean PREPARSE_FOR_SYNTAX_ERRORS = true; //PROFILE public static boolean PROFILE = false; private Map lineNumbersToMessageLists = new HashMap(); private boolean exceptionOccured = false; private boolean syntaxErrorsExistInTest = false; private String testEGLFileName = null; private File file = null; private boolean isVAGCompatible = false; public static boolean PRINT_ERRORS_TO_CONSOLE = true; private static Map initialized = new TreeMap(); static File stagingDir = new File("stagingDir"); static { stagingDir.mkdir(); stagingDir.deleteOnExit(); } private static class TestResults { Map lineNumbersToMessageLists = null; boolean exceptionOccured = false; boolean syntaxErrorsInTest = false; TestResults( Map m, boolean exceptionOccured, boolean syntaxErrorsInTest ) { lineNumbersToMessageLists = m; this.exceptionOccured = exceptionOccured; this.syntaxErrorsInTest = syntaxErrorsInTest; } } protected ValidationTestCase( String testEGLFileName ) { this( testEGLFileName, false ); } protected ValidationTestCase( String testEGLFileName, boolean isVAGCompatible ) { super( "ValidationTestCase" ); this.testEGLFileName = testEGLFileName; this.isVAGCompatible = isVAGCompatible; } /* (non-Javadoc) * @see junit.framework.TestCase#setUp() */ protected void setUp() throws Exception { TestResults results = (TestResults) initialized.get( testEGLFileName ); boolean wasInitialized = false; if( results == null ) { Map tempLineNumbersToMessageLists = new HashMap(); boolean tempExceptionOccured = false; boolean tempSyntaxErrorsExistInTest = false; file = new File( testEGLFileName ); SDKLineTracker lineTracker = new SDKLineTracker(); String contents = getContents(file); lineTracker.set(contents); File stagingDirForTest = new File(stagingDir, stagingDir.getName() + testEGLFileName.replaceAll("/", "__")); stagingDirForTest.mkdir(); File testFile = new File(stagingDirForTest.getPath(), file.getName()); testFile.createNewFile(); File tempDir = new File(stagingDirForTest.getPath(), "irs"); tempDir.mkdir(); File EGLCOut = new File(stagingDirForTest.getPath(), "eglc.out"); EGLCOut.createNewFile(); PrintStream systemOut = System.out; try { copyContents(file, testFile); final ProblemCollectingProblemRequestor pRequestor = new ProblemCollectingProblemRequestor(); //PROFILE if(PREPARSE_FOR_SYNTAX_ERRORS) { /* * Remove the following block when EGLC reports syntax errors */ AccumulatingSyntaxErrorRequestor syntaxProblemRequestor = new AccumulatingSyntaxErrorRequestor(); Scanner lexer = new Lexer(new FileInputStream(file)); ((org.eclipse.edt.compiler.core.ast.File) new ErrorCorrectingParser(lexer).parse().value).accept(syntaxProblemRequestor); for(Iterator iter = syntaxProblemRequestor.getSyntaxErrors().iterator(); iter.hasNext();) { SyntaxError synError = (SyntaxError) iter.next(); // useful for debugging @SuppressWarnings("unused") String fromErrorToEnd = contents.substring(synError.startOffset); @SuppressWarnings("unused") String justErrorNode = contents.substring(synError.startOffset, synError.endOffset); pRequestor.acceptProblem(synError.startOffset, synError.endOffset, IMarker.SEVERITY_ERROR, -42, new String[] {"syntax error"}); } tempSyntaxErrorsExistInTest = !pRequestor.getProblems().isEmpty(); //PROFILE } List arguments = new ArrayList(); if(isVAGCompatible) { arguments.add("-isVAGCompatible"); } arguments.add("-eglPath"); arguments.add(stagingDirForTest.getPath()); arguments.add("-irDestination"); arguments.add(tempDir.getPath()); arguments.add("-xmlout"); arguments.add(testFile.getPath()); arguments.add("-extensions"); arguments.add("org.eclipse.edt.mof.eglx.jtopen.ext.IBMiExtension,org.eclipse.edt.mof.eglx.persistence.sql.ext.SQLExtension," + "org.eclipse.edt.mof.eglx.services.ext.ServicesExtension,org.eclipse.edt.rui.RUIExtension"); System.setOut(new PrintStream(new FileOutputStream(EGLCOut.getPath()))); //PROFILE Controller controller = null; //PROFILE if(PROFILE) { //PROFILE ValidationTestCase.PREPARSE_FOR_SYNTAX_ERRORS = false; //PROFILE try { //PROFILE controller = new Controller(); //PROFILE controller.startCPUTimesMeasuring(); //PROFILE } //PROFILE catch (Exception e) { //PROFILE e.printStackTrace(); //PROFILE } //PROFILE } Processor.skipSerialization = true; // tons of serialization still needs to be ported. disable otherwise we always get a build error EGL2IR.main((String[]) arguments.toArray(new String[0]), getProblemRequestorFactory(pRequestor)); //PROFILE if(PROFILE) { //PROFILE try { //PROFILE controller.captureCPUSnapshot(false); //PROFILE } catch (Exception e) { //PROFILE e.printStackTrace(); //PROFILE } //PROFILE } System.out.close(); System.setOut(systemOut); List messages = pRequestor.getProblems(); for( Iterator iter = messages.iterator(); iter.hasNext(); ) { ProblemCollectingProblemRequestor.Problem problem = (ProblemCollectingProblemRequestor.Problem) iter.next(); Object key = new Integer(lineTracker.getLineNumberOfOffset(problem.startOffset)); List messageListForLine = (List) tempLineNumbersToMessageLists.get( key ); if( messageListForLine == null ) { messageListForLine = new ArrayList(); tempLineNumbersToMessageLists.put( key, messageListForLine ); } messageListForLine.add( problem ); if( problem.problemKind == IProblemRequestor.COMPILATION_EXCEPTION ) { tempExceptionOccured = true; } } results = new TestResults( tempLineNumbersToMessageLists, tempExceptionOccured, tempSyntaxErrorsExistInTest ); initialized.put( testEGLFileName, results ); } catch(Exception e) { results = new TestResults( tempLineNumbersToMessageLists, true, false); initialized.put( testEGLFileName, results ); e.printStackTrace(); } finally { delete(stagingDirForTest); } } else { wasInitialized = true; } lineNumbersToMessageLists = results.lineNumbersToMessageLists; exceptionOccured = results.exceptionOccured; syntaxErrorsExistInTest = results.syntaxErrorsInTest; if( !wasInitialized && PRINT_ERRORS_TO_CONSOLE ) { printErrors(); } } private ISDKProblemRequestorFactory getProblemRequestorFactory(final ProblemCollectingProblemRequestor pRequestor) { return new ISDKProblemRequestorFactory() { @Override public IProblemRequestor getProblemRequestor(File file, final String partName) { return new DefaultProblemRequestor() { @Override public void acceptProblem(int startOffset, int endOffset, int severity, int problemKind, String[] inserts, ResourceBundle bundle) { if (severity == IMarker.SEVERITY_ERROR) { setHasError(true); } pRequestor.acceptProblem(startOffset, endOffset, severity, problemKind, inserts, bundle); } }; } @Override public ISyntaxErrorRequestor getSyntaxErrorRequestor(File file) { return new AccumulatingSyntaxErrorRequestor(); } }; } private static boolean delete(File file) { if(file.isDirectory()) { File[] children = file.listFiles(); for(int i = 0; i < children.length; i++) { delete(children[i]); } } file.deleteOnExit(); boolean result = file.delete(); return result; } private static String getContents(File file) { if (file == null) { return new String(); } else { StringBuffer buffer = new StringBuffer(); Reader reader = null; try { reader = new BufferedReader(new FileReader(file)); int cur; while((cur = reader.read()) != -1) { buffer.append((char) cur); } } catch (Exception e) { e.printStackTrace(); } finally { if(reader != null) { try { reader.close(); } catch(IOException e) {} } } return buffer.toString(); } } private static void copyContents(File srcFile, File destFile) { BufferedReader reader = null; BufferedWriter writer = null; try { reader = new BufferedReader(new FileReader(srcFile)); writer = new BufferedWriter(new FileWriter(destFile)); int ch = reader.read(); while(ch != -1) { writer.write(ch); ch = reader.read(); } } catch(Exception e) { e.printStackTrace(); } finally { if(reader != null) { try { reader.close(); } catch(Exception e) { e.printStackTrace(); } } if(writer != null) { try { writer.close(); } catch(Exception e) { e.printStackTrace(); } } } } protected List getMessagesAtLine( int lineNum ) { List result = (List) lineNumbersToMessageLists.get( new Integer( lineNum ) ); return result != null ? result : new ArrayList(); } protected Object messageWithSubstring( List messages, String substring) { return messageWithSubstring(messages, substring, false); } protected Object messageWithSubstring( List messages, String substring, boolean ignoreCase ) { for( Iterator iter = messages.iterator(); iter.hasNext(); ) { ProblemCollectingProblemRequestor.Problem next = (ProblemCollectingProblemRequestor.Problem) iter.next(); if (ignoreCase) { if( next.getErrorMessage().toUpperCase().indexOf( substring.toUpperCase() ) != -1 ) { return next; } } else { if( next.getErrorMessage().indexOf( substring ) != -1 ) { return next; } } } return null; } public void testNoExceptionsThrownDuringValidation() { assertFalse( exceptionOccured ); } public void testNoSyntaxErrorsInTest() { assertFalse( syntaxErrorsExistInTest ); } protected boolean validationErrorsInTest() { List errorLists = new ArrayList( lineNumbersToMessageLists.values() ); for( Iterator iter = errorLists.iterator(); iter.hasNext(); ) { List errors = (List) iter.next(); for( Iterator iter2 = errors.iterator(); iter2.hasNext(); ) { ProblemCollectingProblemRequestor.Problem problem = (ProblemCollectingProblemRequestor.Problem) iter2.next(); if( problem.problemKind != IProblemRequestor.GENERATABLE_PART_NAME_MUST_MATCH_FILE_NAME && problem.problemKind != IProblemRequestor.ONLY_ONE_GENERATABLE_PART_PER_FILE ) { return true; } } } return false; } protected void printErrors() { Integer[] lineNums = (Integer[]) new TreeSet( lineNumbersToMessageLists.keySet() ).toArray( new Integer[0] ); BufferedReader reader = null; RandomAccessFile raFile = null; try { reader = new BufferedReader( new FileReader( file ) ); raFile = new RandomAccessFile( file, "r" ); } catch( FileNotFoundException e ) { System.err.println( "File not found: " + file.toString() ); return; } int numErrors = 0; try { int currentReaderLine = 0; String readerLine = new String();//reader.readLine(); for( int i = 0; i < lineNums.length; i++ ) { int currentLineNum = lineNums[i].intValue(); for( ; currentReaderLine != currentLineNum; currentReaderLine++ ) { readerLine = reader.readLine(); } System.out.println( currentLineNum + ": " + readerLine.trim() ); List errors = (List) lineNumbersToMessageLists.get( lineNums[i] ); for( Iterator iter = errors.iterator(); iter.hasNext(); ) { numErrors += 1; ProblemCollectingProblemRequestor.Problem problem = (ProblemCollectingProblemRequestor.Problem) iter.next(); int startOffset = problem.startOffset; int length = problem.endOffset-problem.startOffset; //byte[] bytes = new byte[ length ]; //raFile.read( bytes, startOffset, length ); raFile.seek( startOffset ); StringBuffer sb = new StringBuffer(); for( int j = 0; j < length; j++ ) { sb.append( (char) raFile.readByte() ); } System.out.print( "[[" + sb.toString() + "]]: " ); String str; try { str = "{" + problem.problemKind + (problem.severity == IMarker.SEVERITY_WARNING ? " (warning)" : "") + "} " + problem.getErrorMessage(); } catch(MissingResourceException e) { //TODO: hack for now if(problem.problemKind == -42) { str = "Syntax error on highlighted input."; } else { str = "!! Message #" + problem.problemKind + " not found in bundle !!"; } } System.out.println(str); } if( i != lineNums.length - 1 ) { System.out.println(); } } } catch( Exception e ) { System.err.println( "Exception in printErrors(): " ); e.printStackTrace(); } finally { try { if( reader != null ) reader.close(); if( raFile != null ) raFile.close(); } catch( Exception e ) {} } if(numErrors == 0) { System.out.println( "No errors." ); } else { System.out.println(); if(numErrors == 1) { System.out.println( "1 error total." ); } else { System.out.println( numErrors + " errors total."); } } } public static void clearResultsCache() { initialized.clear(); } }