/******************************************************************************* * Copyright (c) 2016 Red Hat Inc. 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: * Red Hat, Inc. - initial API and Implementation *******************************************************************************/ package org.eclipse.dltk.ruby.testing.internal.miniunit; import java.io.File; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.Assert; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.debug.core.ILaunch; import org.eclipse.debug.core.ILaunchConfiguration; import org.eclipse.dltk.ast.ASTNode; import org.eclipse.dltk.ast.declarations.MethodDeclaration; import org.eclipse.dltk.ast.declarations.ModuleDeclaration; import org.eclipse.dltk.ast.expressions.CallExpression; import org.eclipse.dltk.compiler.util.Util; import org.eclipse.dltk.core.DLTKCore; import org.eclipse.dltk.core.IModelElement; import org.eclipse.dltk.core.IScriptProject; import org.eclipse.dltk.core.ISourceModule; import org.eclipse.dltk.core.environment.IEnvironment; import org.eclipse.dltk.launching.InterpreterConfig; import org.eclipse.dltk.ruby.ast.RubyClassDeclaration; import org.eclipse.dltk.ruby.testing.internal.AbstractRubyTestingEngine; import org.eclipse.dltk.ruby.testing.internal.AbstractTestingEngineValidateVisitor; import org.eclipse.dltk.ruby.testing.internal.Messages; import org.eclipse.dltk.ruby.testing.internal.ResolverUtils; import org.eclipse.dltk.ruby.testing.internal.RubyTestingLaunchConfigurationDelegate; import org.eclipse.dltk.testing.DLTKTestingConstants; import org.eclipse.dltk.testing.ITestRunnerUI; import org.eclipse.osgi.util.NLS; public class MiniTestingEngine extends AbstractRubyTestingEngine { static class TestUnitValidateVisitor extends AbstractTestingEngineValidateVisitor { private static final String MINITEST_AUTORUN = "minitest/autorun"; //$NON-NLS-1$ private static final String MINITEST_TEST = "Minitest::Test"; //$NON-NLS-1$ private static final String TEST = "test"; //$NON-NLS-1$ private ISourceModule module; private int testUnitWeight = 0; static final int REQUIRE_WEIGHT = 10; static final int TESTCASE_WEIGHT = 10; static final int METHOD_WEIGHT = 1; public TestUnitValidateVisitor(ISourceModule module) { this.module = module; } @Override public boolean visitGeneral(ASTNode node) throws Exception { if (node instanceof CallExpression) { final CallExpression call = (CallExpression) node; if (isRequire(call, MINITEST_AUTORUN)) { testUnitWeight += REQUIRE_WEIGHT; } } else if (node instanceof RubyClassDeclaration) { if (isSuperClassOf(module, (RubyClassDeclaration) node, MINITEST_TEST)) { testUnitWeight += TESTCASE_WEIGHT; } } else if (node instanceof MethodDeclaration) { if (isNodeOnStack(RubyClassDeclaration.class) && isMethodPrefix((MethodDeclaration) node, TEST)) { testUnitWeight += METHOD_WEIGHT; } } return super.visitGeneral(node); } public IStatus getStatus() { if (testUnitWeight >= Math.min(REQUIRE_WEIGHT, TESTCASE_WEIGHT)) { return Status.OK_STATUS; } if (testUnitWeight >= METHOD_WEIGHT) { return createStatus(IStatus.INFO, Messages.validate_probablyMinitest); } return createStatus(IStatus.WARNING, Messages.validate_notMinitest); } } @Override public IStatus validateSourceModule(ISourceModule module) { final ModuleDeclaration declaration = ResolverUtils.parse(module); if (declaration == null) { return createStatus(IStatus.WARNING, Messages.validate_sourceErrors); } final TestUnitValidateVisitor visitor = new TestUnitValidateVisitor(module); try { declaration.traverse(visitor); } catch (Exception e) { return createStatus(IStatus.WARNING, NLS.bind(Messages.validate_runtimeError, e.getMessage())); } return visitor.getStatus(); } static final String MINITEST_RUNNER = "dltk-minitest-runner.rb"; //$NON-NLS-1$ @Override public void configureLaunch(InterpreterConfig config, ILaunchConfiguration configuration, ILaunch launch) throws CoreException { // select port number final String strPort = String.valueOf(allocatePort()); launch.setAttribute(DLTKTestingConstants.ATTR_PORT, strPort); config.addEnvVar(RUBY_TESTING_PORT, strPort); // add runner if (!RubyTestingLaunchConfigurationDelegate.isContainerMode(configuration)) { if (config.getEnvironment().isLocal()) { final String runnerName = MINITEST_RUNNER; if (!isDevelopmentMode(config, runnerName)) { final File runnerFile = getRunnerFile(getBundle(), RUNNER_PATH, runnerName); config.addInterpreterArg("-r"); //$NON-NLS-1$ config.addInterpreterArg(runnerFile.getPath()); } } } else { final String containerHandle = configuration.getAttribute(DLTKTestingConstants.ATTR_TEST_CONTAINER, Util.EMPTY_STRING); Assert.isLegal(containerHandle.length() != 0); IModelElement element = DLTKCore.create(containerHandle); Assert.isNotNull(element); IResource resource = element.getUnderlyingResource(); Assert.isNotNull(resource); final IPath path = resource.getProjectRelativePath(); if (path.isEmpty()) { config.addEnvVar(RUBY_TESTING_PATH, "."); //$NON-NLS-1$ } else { config.addEnvVar(RUBY_TESTING_PATH, path.toOSString()); } } } @Override public String getMainScriptPath(ILaunchConfiguration configuration, IEnvironment scriptEnvironment) throws CoreException { if (RubyTestingLaunchConfigurationDelegate.isContainerMode(configuration)) { return getRunnerFile(getBundle(), RUNNER_PATH, MINITEST_RUNNER).getPath(); } else { return null; } } @Override public ITestRunnerUI getTestRunnerUI(IScriptProject project, ILaunchConfiguration configuration) { return new MiniTestRunnerUI(this, project); } }