/******************************************************************************* * Copyright (c) 2009, 2016 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 * Zend Technologies *******************************************************************************/ package org.eclipse.php.core.tests; import static org.junit.Assert.assertNotNull; import java.io.BufferedInputStream; import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.URL; import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.Platform; import org.osgi.framework.Bundle; /** * Scripts are small units that provide a specific scenario to test * * Example: * * <pre> * --TEST-- * Tests a simple class name completion * --CONFIG-- * Custom configuration * --PREFERENCES-- * Eclipse preference options to set before running this test * --FILE-- * <? some PHP code ?> * --EXPECT-- * Expected result * </pre> */ public class PdttFile { protected enum STATES { TEST("--TEST--"), CONFIG("--CONFIG--"), PREFERENCES("--PREFERENCES--"), FILE("--FILE--"), EXPECT( "--EXPECT--"), OTHER("--OTHER--"), OTHER_FILE("--FILE([0-9]+)--"); private static class Names { private static Map<String, STATES> map = new HashMap<String, STATES>(); } String name; STATES(String name) { this.name = name; Names.map.put(name.toLowerCase(), this); } public String getName() { return name; } public static STATES byName(String name) { return Names.map.get(name.toLowerCase()); } } private String fileName; private Bundle testBundle; private Map<String, String> config = new HashMap<String, String>(); private String preferences; private String description; private String file = ""; /** * @since 3.5 List of additional files */ private List<CharSequence> otherFiles = new LinkedList<CharSequence>(); private int currentFile; private String expected = ""; private String other; /** * Constructs new PdttFile using default bundle: {@link PHPCoreTests} * * @param fileName * @throws Exception */ public PdttFile(String fileName) throws Exception { this(PHPCoreTests.getDefault().getBundle(), fileName, null); } /** * Constructs new PdttFile * * @param testBundle * The testing plug-in * @param fileName * @throws Exception */ public PdttFile(Bundle testBundle, String fileName) throws Exception { this(testBundle, fileName, null); } /** * Constructs new PdttFile * * @param testBundle * The testing plug-in * @param fileName * @param charsetName * charset to use (if null, platform's default charset will be * used) * @throws Exception */ public PdttFile(Bundle testBundle, String fileName, String charsetName) throws Exception { this.testBundle = testBundle; this.fileName = fileName; InputStream reader = openResource(fileName); try { parse(reader, charsetName); } finally { if (reader != null) { reader.close(); } List<CharSequence> tmp = new ArrayList<CharSequence>(otherFiles.size()); int i = 0; for (CharSequence seq : otherFiles) { tmp.add(i, seq.toString()); } otherFiles = tmp; } } /** * Returns the test description (--TEST-- section contents) * * @return */ public String getDescription() throws Exception { assertNotNull("File: " + fileName + " doesn't contain --TEST-- section", description); return description; } /** * Returns the configuration entries (--CONFIG-- section contents in format * key:value) * * @return */ public Map<String, String> getConfig() { return config; } /** * Returns the preferences (--PREFERENCES-- section contents) * * @return */ public String getPreferences() { return preferences; } /** * Applies Eclipse preferences specified in --PREFERENCES-- option. * * @throws CoreException */ public void applyPreferences() throws CoreException { if (preferences != null) { Platform.getPreferencesService().importPreferences(new ByteArrayInputStream(preferences.getBytes())); } } /** * Returns the PHP file contents (--FILE-- section contents) * * @return */ public String getFile() { assertNotNull("File: " + fileName + " doesn't contain --FILE-- section", file); return file; } /** * Returns the PDTT file name. * * @return the PDTT file name */ public String getFileName() { return fileName; } public String getOtherFile(int index) { assertNotNull(new StringBuilder("File:").append(fileName).append('[').append(index) .append("] doesn't contain --FILE").append(index).append("-- section").toString(), otherFiles.get(index)); return otherFiles.get(index).toString(); } public String[] getOtherFiles() { return otherFiles.toArray(new String[otherFiles.size()]); } /** * Returns the expected result (--EXPECT-- section contents) * * @return */ public String getExpected() { assertNotNull("File: " + fileName + " doesn't contain --EXPECT-- section", expected); return expected; } public String getOther() { return other; } public void setOther(String other) { this.other = other; } protected InputStream openResource(String path) throws IOException { File localFile = new File(path); if (localFile.exists()) { return new FileInputStream(localFile); } URL url = testBundle.getEntry(path); return new BufferedInputStream(url.openStream()); } /** * Internal method for parsing a .pdtt test file * * @param inputStream * @param charsetName * charset to use (if null, platform's default charset will be * used) * @throws Exception */ protected void parse(InputStream inputStream, String charsetName) throws Exception { BufferedReader bReader = charsetName != null ? new BufferedReader(new InputStreamReader(inputStream, charsetName)) : new BufferedReader(new InputStreamReader(inputStream)); String line = bReader.readLine(); STATES state = null; while (line != null) { if (line.matches("--[A-Z0-9]+--")) { state = parseStateLine(line); if (state == null) { throw new Exception("Wrong state: " + line); } } else { if (state != null) { onState(state, line); } } line = bReader.readLine(); } } public void setConfig(Map<String, String> config) { this.config = config; } public void setPreferences(String preferences) { this.preferences = preferences; } public void setDescription(String description) { this.description = description; } public void setFile(String file) { this.file = file; } public void setExpected(String expected) { this.expected = expected; } /** * Dumps this file back to the disk * * @throws Exception */ public void write() throws Exception { PrintWriter w = new PrintWriter(new FileWriter(fileName)); writeStates(w); w.close(); } protected void writeStates(PrintWriter w) { w.println(STATES.TEST.getName()); w.println(description.trim()); if (config != null && config.size() > 0) { w.println(STATES.CONFIG.getName()); for (String key : config.keySet()) { w.print(key); w.print(':'); w.println(config.get(key)); } } if (preferences != null) { w.println(STATES.PREFERENCES.getName()); w.println(preferences.trim()); } w.println(STATES.FILE.getName()); w.println(file.trim()); w.println(STATES.EXPECT.getName()); w.println(expected.trim()); if (other != null) { w.println(STATES.OTHER.getName()); w.println(other.trim()); } if (otherFiles.size() > 0) { int i = 0; for (CharSequence seq : otherFiles) { w.println(STATES.OTHER_FILE.getName() + i); w.println(seq.toString().trim()); } } } /** * Detects the state from the line * * @param line * @return STATE */ protected STATES parseStateLine(String line) { STATES state = STATES.byName(line); if (state == null) { Pattern compile = Pattern.compile(STATES.OTHER_FILE.name); Matcher matcher = compile.matcher(line); if (matcher.matches()) { state = STATES.OTHER_FILE; currentFile = Integer.valueOf(matcher.group(1)); otherFiles.add(currentFile, new StringBuilder()); } } return state; } /** * This callback is called while processing state section * * @param state * @param line * @throws Exception */ protected void onState(STATES state, String line) throws Exception { switch (state) { case TEST: this.description = line; break; case FILE: this.file += (line + "\n"); break; case OTHER_FILE: ((StringBuilder) this.otherFiles.get(currentFile)).append(line).append('\n'); break; case EXPECT: this.expected += (line + "\n"); break; case OTHER: if (this.other == null) { this.other = ""; } this.other += (line + "\n"); break; case CONFIG: int i = line.indexOf(':'); if (i == -1) { throw new Exception("Wrong option in " + STATES.CONFIG.getName() + " section: " + line); } String key = line.substring(0, i); String value = line.substring(i + 1); this.config.put(key.trim(), value.trim()); break; case PREFERENCES: if (line != null && line.length() > 0) { if (preferences == null) { this.preferences = (line + "\n"); } else { this.preferences += (line + "\n"); } } break; default: break; } } }