/******************************************************************************* * Copyright (c) 2008 xored software, Inc. * * 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: * xored software, Inc. - initial API and Implementation (Alex Panchenko) *******************************************************************************/ package org.eclipse.dltk.formatter.tests; import java.io.IOException; import java.net.URL; import java.util.HashMap; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.eclipse.dltk.compiler.util.Util; import org.eclipse.dltk.ui.formatter.FormatterException; import org.eclipse.dltk.ui.formatter.IScriptFormatter; import org.eclipse.dltk.utils.TextUtils; import org.osgi.framework.Bundle; import junit.framework.AssertionFailedError; import junit.framework.TestCase; import junit.framework.TestResult; import junit.framework.TestSuite; public class ScriptedTest extends AbstractFormatterTest { public static interface IScriptedTestContext { Bundle getResourceBundle(); String getCharset(); IScriptFormatter createFormatter(Map<String, Object> preferences); String validateOptionName(String name); String validateOptionValue(String name, String value); } private boolean ignored; private String input; private String expected; @Override public void run(TestResult result) { if (!ignored) { super.run(result); } } @Override protected void runTest() throws Throwable { final String output = format(input); assertEquals(expected, output); try { assertEquals("Reformatting", expected, format(output)); //$NON-NLS-1$ } catch (FormatterException e) { AssertionFailedError fail = new AssertionFailedError(e.getMessage()); fail.initCause(e); throw fail; } } private IScriptedTestContext context = null; private Map<String, Object> preferences = null; @Override protected Map<String, Object> getDefaultPreferences() { return preferences; } public void setPreference(String optionName, Object optionValue) { if (preferences == null) { preferences = new HashMap<String, Object>(); } preferences.put(optionName, optionValue); } @Override protected IScriptFormatter createFormatter(Map<String, Object> preferences) { return context.createFormatter(preferences); } protected static char[] readResource(IScriptedTestContext context, String resourceName) throws IOException { final URL resource = context.getResourceBundle().getResource( resourceName); assertNotNull(resourceName + " is not found", resource); //$NON-NLS-1$ return Util.getInputStreamAsCharArray(resource.openStream(), -1, context.getCharset()); } private static final String TEST_MARKER = "===="; //$NON-NLS-1$ private static final String IGNORE_PREFIX = "@IGNORE:"; //$NON-NLS-1$ private static final String RESPONSE_MARKER = "=="; //$NON-NLS-1$ private static final String OPTION_MARKER = "==>"; //$NON-NLS-1$ public TestSuite createScriptedSuite(IScriptedTestContext context, String resourceName) { return createScriptedSuite(context, getClass().getName(), resourceName, 0); } /** * @param resourceName * @return */ public TestSuite createScriptedSuite(IScriptedTestContext context, String suiteName, String resourceName, int beginTestIndex) { final TestSuite suite = new TestSuite(suiteName); try { final String content = new String(readResource(context, resourceName)); final String[] lines = TextUtils.splitLines(content); String testName = "START"; int testIndex = 0; int testBegin = 0; int responseBegin = -1; int i = 0; while (i < lines.length) { final String line = lines[i++]; if (line.startsWith(TEST_MARKER) || line.startsWith(OPTION_MARKER)) { final int testEnd = i - 1; if (testEnd > testBegin) { if (responseBegin < 0) { throw new IllegalArgumentException( "No response marker - next test started on line " + testEnd); } if (testIndex >= beginTestIndex) { suite.addTest(createTest(context, preferences, testName, lines, testBegin, responseBegin, testEnd)); } ++testIndex; } testBegin = i; responseBegin = -1; if (line.startsWith(TEST_MARKER)) { testName = line.substring(TEST_MARKER.length()).trim(); } else if (line.startsWith(OPTION_MARKER)) { final Matcher matcher = OPTION_PATTERN.matcher(line .substring(OPTION_MARKER.length())); if (matcher.matches()) { final String optionName = context .validateOptionName(matcher.group(1)); if (optionName == null) throw new IllegalArgumentException( "Invalid option name: " + line); final String optionValue = context .validateOptionValue(optionName, matcher .group(2)); if (optionValue == null) throw new IllegalArgumentException( "Invalid option value: " + line); setPreference(optionName, optionValue); } else { suite.addTest(new TestCase(resourceName + ":" + testEnd) { @Override protected void runTest() throws Throwable { throw new IllegalArgumentException(line); } }); } } } else if (line.startsWith(RESPONSE_MARKER)) { if (responseBegin >= 0) { throw new IllegalArgumentException( "Multiple response markers: line " + (i - 1) + ", previous on line " + responseBegin); } responseBegin = i; } } if (lines.length > testBegin) { if (responseBegin < 0) { throw new IllegalArgumentException( "No response marker in last test"); } if (testIndex >= beginTestIndex) { suite.addTest(createTest(context, preferences, testName, lines, testBegin, responseBegin, lines.length)); } } } catch (final Throwable e) { suite.addTest(new TestCase(e.getClass().getName()) { @Override protected void runTest() throws Throwable { throw e; } }); } return suite; } private static final Pattern OPTION_PATTERN = Pattern .compile("\\s*([\\w\\.]+)\\s*=\\s*(\\S+)\\s*"); //$NON-NLS-1$ private ScriptedTest createTest(IScriptedTestContext context, Map<String, Object> preferences, String testName, String[] lines, int testBegin, int responseBegin, final int testEnd) throws Exception { final String input = joinLines(lines, testBegin, responseBegin - 1); final String expected = joinLines(lines, responseBegin, testEnd); ScriptedTest test = getClass().newInstance(); if (testName.startsWith(IGNORE_PREFIX)) { test.ignored = true; test.setName(testName.substring(IGNORE_PREFIX.length()).trim()); } else { test.setName(testName); } test.input = input; test.expected = expected; test.context = context; test.preferences = preferences != null ? new HashMap<String, Object>( preferences) : preferences; return test; } }