/******************************************************************************* * Copyright (c) 2008, 2012 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.jdt.ui.tests.chkpii; import java.io.BufferedReader; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.Writer; import java.net.URL; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.regex.Pattern; import junit.framework.TestCase; import org.eclipse.jdt.testplugin.JavaTestPlugin; import org.eclipse.core.runtime.FileLocator; import org.eclipse.jdt.internal.ui.util.StringMatcher; /** * Runs the 'tidy' command (e.g. from Cygwin) on HTML files in the workspace * and collects HTMLTidy's errors and warnings into /chkpiiResults/tidy.txt * * Note: Currently disabled. */ public class HTMLTidyTest extends TestCase { private static final int TIDY_TIMEOUT= 10000; private static final Pattern EXCLUSION_PATTERN_TABLE_SUMMARY= Pattern.compile("line \\d+ column \\d+ - Warning: <table> lacks \"summary\" attribute"); private static final Pattern EXCLUSION_PATTERN_EMPTY_TAG= Pattern.compile("line \\d+ column \\d+ - Warning: trimming empty <\\w+>"); private static final Pattern EXCLUSION_PATTERN_MALFORMED_URI= Pattern.compile("line \\d+ column \\d+ - Warning: <a> escaping malformed URI reference"); private static final Pattern eXCLUSION_PATTERN_SCRIPT_TYPE= Pattern.compile("line \\d+ column \\d+ - Warning: <script> inserting \"type\" attribute"); private static final Pattern eXCLUSION_PATTERN_IMG_LACKS_ALT= Pattern.compile("line \\d+ column \\d+ - Warning: <img> lacks \"alt\" attribute"); private int fworkspacePathLength; private StringMatcher[] fIgnores; private Writer fTidyResults; /** * Main method for manual testing of a file or folder selected in the workspace. To run, create * a Java launch configuration with program argument<br> * <code>"${resource_loc}"</code><br> * (including double quotes!). * * @param args 1 argument: Absolute path to a file or folder * @throws Exception if checking fails */ public static void main(String[] args) throws Exception { HTMLTidyTest test= new HTMLTidyTest(); test.fIgnores= new StringMatcher[0]; test.fTidyResults= new OutputStreamWriter(System.out); File file= new File(args[0]); if (file.isDirectory()) test.checkFolder(file); else test.checkFile(file); } public void testHTML() throws Exception { URL testBundleRoot= JavaTestPlugin.getDefault().getBundle().getEntry("/"); URL testBundleFile= FileLocator.toFileURL(testBundleRoot); File hostWorkspace= new File(testBundleFile.getFile()).getParentFile().getParentFile().getParentFile(); String workspacePath= hostWorkspace.getAbsolutePath(); fworkspacePathLength= workspacePath.length(); File chkpiiResults= new File(hostWorkspace, "chkpiiResults"); File tidy= new File(chkpiiResults, "tidy.txt"); fTidyResults= new OutputStreamWriter(new FileOutputStream(tidy), "UTF-8"); String startTime= new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()); fTidyResults.write(getClass().getName() + " started at " + startTime + "\n"); fIgnores= getIgnores(); try { boolean ok= true; // ok&= checkFolder(new File(hostWorkspace, "org.eclipse.jdt.doc.user"), tidyResults); // ok&= checkFolder(new File(hostWorkspace, "org.eclipse.jdt.doc.isv"), tidyResults); // ok&= checkFolder(new File(hostWorkspace, "org.eclipse.platform.doc.user"), tidyResults); // ok&= checkFolder(new File(hostWorkspace, "org.eclipse.platform.doc.isv"), tidyResults); // ok&= checkFolder(new File(hostWorkspace + "/org.eclipse.jdt.doc.isv/guide")); ok&= checkFolder(hostWorkspace); assertTrue("See " + tidy.getAbsolutePath(), ok); } finally { fTidyResults.flush(); fTidyResults.close(); fTidyResults= null; } } private StringMatcher[] getIgnores() throws IOException { ArrayList<StringMatcher> matchers= new ArrayList<>(); InputStream is= getClass().getResourceAsStream("ignoreFiles.txt"); BufferedReader reader= new BufferedReader(new InputStreamReader(is)); while (reader.ready()) { String line= reader.readLine(); if (line.length() > 0) { char first= line.charAt(0); if (line.endsWith("/*")) line= line.substring(0, line.length() - 2); // stops at directory during tree traversal if (first != '/' && first != '*') { // relative matches // emulate CHKPII specification: // matchers.add(new StringMatcher(fWorkspacePath + "/" + line, true, false)); // emulate actual CHKPII implementation: matchers.add(new StringMatcher("*/" + line, true, false)); } matchers.add(new StringMatcher(line, true, false)); } } return matchers.toArray(new StringMatcher[matchers.size()]); } private boolean isIgnored(File file) { String relativePath= file.getAbsolutePath().substring(fworkspacePathLength); relativePath= relativePath.replace('\\', '/'); for (int i= 0; i < fIgnores.length; i++) { StringMatcher matcher= fIgnores[i]; if (matcher.match(relativePath)) return true; } return false; } private boolean checkFolder(File folder) throws Exception { File[] files= folder.listFiles(); boolean success= true; for (int i= 0; i < files.length; i++) { File file= files[i]; if (isIgnored(file)) { // System.out.println("Ignored: " + file.getAbsolutePath() + (file.isDirectory() ? "/*" : "")); continue; } if (isHTMLFile(file)) { success&= checkFile(file); } else if (file.isDirectory()) { success&= checkFolder(file); } } return success; } private boolean checkFile(File file) throws Exception { String filePath= file.getAbsolutePath(); String command= "tidy -eq \"" + filePath + "\""; final Process process= Runtime.getRuntime().exec(command); long timeout= System.currentTimeMillis() + TIDY_TIMEOUT; BufferedReader tidyReader= new BufferedReader(new InputStreamReader(process.getErrorStream())); boolean available= tidyReader.ready(); boolean first= true; while (available || System.currentTimeMillis() < timeout) { if (! available) { if (! isAlive(process)) break; Thread.sleep(100); } else { while (available) { String line= tidyReader.readLine(); if (isRelevant(line)) { if (first) { first= false; fTidyResults.write("\n--- " + filePath +'\n'); } fTidyResults.write(line); fTidyResults.write('\n'); } available= tidyReader.ready(); } } available= tidyReader.ready(); if (! available && ! isAlive(process)) break; } fTidyResults.flush(); try { return process.exitValue() == 0; } catch (IllegalThreadStateException e) { process.destroy(); fTidyResults.write("Error: '" + command + "' killed after " + TIDY_TIMEOUT +" ms\n"); return false; } } private static boolean isRelevant(String line) { return ! EXCLUSION_PATTERN_TABLE_SUMMARY.matcher(line).matches() && ! EXCLUSION_PATTERN_EMPTY_TAG.matcher(line).matches() && ! EXCLUSION_PATTERN_MALFORMED_URI.matcher(line).matches() && ! eXCLUSION_PATTERN_SCRIPT_TYPE.matcher(line).matches() && ! eXCLUSION_PATTERN_IMG_LACKS_ALT.matcher(line).matches() ; } private static boolean isAlive(Process process) { try { process.exitValue(); } catch (IllegalThreadStateException e) { return true; } return false; } private static boolean isHTMLFile(File file) { String name= file.getName(); return (name.endsWith(".html") || name.endsWith(".htm")) && file.isFile(); } }