/*******************************************************************************
* Copyright (c) 2014 Bruno Medeiros and other Contributors.
* 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:
* Bruno Medeiros - initial API and implementation
*******************************************************************************/
package dtool.dub;
import static melnorme.utilbox.core.Assert.AssertNamespace.assertFail;
import static melnorme.utilbox.core.Assert.AssertNamespace.assertTrue;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.concurrent.TimeoutException;
import dtool.dub.DubBundle.BundleFile;
import dtool.tests.CommonDToolTest;
import dtool.tests.DToolTestResources;
import melnorme.lang.tooling.BundlePath;
import melnorme.lang.tooling.bundle.DependencyRef;
import melnorme.utilbox.collections.ArrayList2;
import melnorme.utilbox.concurrency.OperationCancellation;
import melnorme.utilbox.core.CommonException;
import melnorme.utilbox.misc.ArrayUtil;
import melnorme.utilbox.misc.Location;
import melnorme.utilbox.misc.StringUtil;
import melnorme.utilbox.process.ExternalProcessHelper;
import melnorme.utilbox.process.ExternalProcessHelper.ExternalProcessResult;
public class CommonDubTest extends CommonDToolTest {
public static final Location DUB_TEST_BUNDLES = DToolTestResources.getTestResourceLoc("dub");
public static final BundlePath XPTO_BUNDLE_PATH = bundlePath(DUB_TEST_BUNDLES, "XptoBundle");
public CommonDubTest() {
super();
}
public static Path path(String str) {
return Paths.get(str);
}
public static Path[] paths(String... str) {
Path[] newArray = new Path[str.length];
for (int i = 0; i < str.length; i++) {
newArray[i] = Paths.get(str[i]);
}
return newArray;
}
public static final DubBundleChecker[] IGNORE_DEPS = new DubBundleChecker[0];
public static final String[] IGNORE_RAW_DEPS = new String[0];
public static final String ERROR_DUB_RETURNED_NON_ZERO = "DUB describe error";
public static class DubBundleChecker extends CommonChecker {
public final Location location;
public final String bundleName;
public final String errorMsgStart;
public final String version;
public final Path[] sourceFolders;
public final String[] rawDeps;
public final DubBundleChecker[] expectedDeps;
public DubBundleChecker(Location location, String bundleName) {
this(location, bundleName, null, IGNORE_STR, null, IGNORE_RAW_DEPS, IGNORE_DEPS);
}
public DubBundleChecker(Location location, String bundleName, String errorMsgStart, String version,
Path[] sourceFolders, String[] rawDeps, DubBundleChecker[] deps) {
this.location = location;
this.bundleName = bundleName;
this.errorMsgStart = errorMsgStart;
this.version = version;
this.sourceFolders = sourceFolders;
this.rawDeps = rawDeps;
this.expectedDeps = deps;
}
@Override
protected boolean isIgnoreArray(Object[] expected){
return expected == IGNORE_DEPS || expected == IGNORE_ARR || expected == IGNORE_RAW_DEPS;
}
public boolean isResolvedOnlyError() {
return errorMsgStart == ERROR_DUB_RETURNED_NON_ZERO;
}
public void check(DubBundle bundle, boolean isResolved) {
checkAllExceptDepRefs(bundle, isResolved);
checkDepRefs(bundle);
}
protected void checkAllExceptDepRefs(DubBundle bundle, boolean isResolved) {
checkAreEqual(bundle.getLocation(), location);
checkAreEqual(bundle.name, bundleName);
if(isResolvedOnlyError() && !isResolved) {
// Don't check, error occurs only in resolved bundles
} else {
assertExceptionMsgStart(bundle.error, errorMsgStart);
}
checkAreEqual(bundle.version, version);
checkAreEqualArray(bundle.getEffectiveSourceFolders(), ignoreIfNull(sourceFolders));
}
protected void checkDepRefs(DubBundle bundle) {
if(rawDeps == IGNORE_RAW_DEPS) {
return;
}
assertEquals(bundle.getDependencyRefs().length, rawDeps.length);
for (int i = 0; i < rawDeps.length; i++) {
String expRawDep = rawDeps[i];
DependencyRef depRef = bundle.getDependencyRefs()[i];
checkAreEqual(depRef.getBundleName(), expRawDep);
}
}
public void checkBundleDescription(DubBundleDescription bundleDescription, boolean expectedIsResolved) {
if(bundleDescription.isResolved() != expectedIsResolved) {
assertFail(StringUtil.asString(bundleDescription.getError()));
}
if(!expectedIsResolved) {
check(bundleDescription.getMainBundle(), expectedIsResolved);
assertTrue(bundleDescription.hasErrors() ||
bundleDescription.getBundleDependencies().length == 0);
return;
} else {
checkAllExceptDepRefs(bundleDescription.getMainBundle(), expectedIsResolved);
}
if(expectedDeps == IGNORE_DEPS)
return;
DubBundle[] deps = bundleDescription.getBundleDependencies();
assertTrue(expectedDeps.length == deps.length);
ArrayList2<DubBundle> depsToCheck = ArrayList2.create(deps);
ArrayList2<DubBundleChecker> expectedDepsToCheck = ArrayList2.create(expectedDeps);
for (DubBundle dubBundle : depsToCheck) {
boolean checked = false;
for (DubBundleChecker dubBundleChecker : expectedDepsToCheck) {
if(dubBundleChecker.bundleName.equals(dubBundle.getBundleName())) {
dubBundleChecker.check(dubBundle, true);
expectedDepsToCheck.remove(dubBundleChecker);
checked = true;
break;
}
}
assertTrue(checked);
}
}
protected void checkResolvedBundle(DubBundleDescription bundleDescription, String dubDescribeError) {
assertExceptionContains(bundleDescription.error, dubDescribeError);
boolean isResolved = dubDescribeError == null;
checkBundleDescription(bundleDescription, isResolved);
}
}
public static DubBundleChecker main(Location location, String errorMsgStart, String name,
String version, Path[] srcFolders, String[] rawDeps, DubBundleChecker... deps) {
return new DubBundleChecker(location, name, errorMsgStart, version, srcFolders, rawDeps, deps);
}
public static DubBundleChecker bundle(Location location, String errorMsgStart, String name,
String version, Path[] srcFolders) {
return main(location, errorMsgStart, name, version, srcFolders, IGNORE_RAW_DEPS, IGNORE_DEPS);
}
public static DubBundleChecker bundle(Location location, String name) {
return new DubBundleChecker(location, name, null, IGNORE_STR, null, IGNORE_RAW_DEPS, IGNORE_DEPS);
}
public static DubBundleChecker bundle(String errorMsgStart, String name) {
return new DubBundleChecker(IGNORE_PATH, name, errorMsgStart, IGNORE_STR, null, IGNORE_RAW_DEPS, IGNORE_DEPS);
}
public static BundleFile bf(String filePath) {
return new BundleFile(filePath, false);
}
public static String[] rawDeps(String... rawDeps) {
return rawDeps;
}
protected void checkResolvedBundle(DubBundleDescription bundleDescription, String dubDescribeError,
DubBundleChecker mainBundleChecker) {
mainBundleChecker.checkResolvedBundle(bundleDescription, dubDescribeError);
}
/* ------------------------------ */
protected String runDubDescribe(BundlePath workingDir) throws Exception {
ExternalProcessResult processResult = startDubProcess(workingDir, false, "describe")
.awaitTerminationAndResult(2000, true);
return processResult.getStdOutBytes().toString(StringUtil.UTF8);
}
public static ExternalProcessHelper startDubProcess(BundlePath bundlePath,
boolean redirectStdErr, String... arguments)
throws IOException {
String[] command = ArrayUtil.prepend(testsDubPath(), arguments);
ProcessBuilder pb = new ProcessBuilder(command);
if(bundlePath != null) {
pb.directory(bundlePath.getLocation().toFile());
}
pb.redirectErrorStream(redirectStdErr);
return new ExternalProcessHelper(pb);
}
public static void dubAddPath(Location packageRootDir) throws CommonException {
String packageRootDirStr = packageRootDir.toString();
System.out.println(":::: Adding DUB package root path: " + packageRootDirStr);
String[] arguments = array("add-path", packageRootDirStr);
runDubCommand(3000, arguments);
}
public static void dubRemovePath(Location packageRootDir) throws CommonException {
String packageRootDirStr = packageRootDir.toString();
System.out.println(":::: Removing DUB package root path: " + packageRootDirStr);
String[] arguments = array("remove-path", packageRootDirStr);
runDubCommand(3000, arguments);
}
public static void runDubCommand(int timeout, String... arguments) throws CommonException {
try {
ExternalProcessHelper processHelper = doRunDubCommand(timeout, arguments);
assertTrue(processHelper.getProcess().exitValue() == 0);
if(processHelper.getProcess().exitValue() != 0) {
throw new CommonException("Exit value not zero");
}
} catch (TimeoutException | InterruptedException | OperationCancellation | IOException | CommonException e) {
throw new CommonException("Failed to run DUB command: " + StringUtil.collToString(arguments, " "));
}
}
public static ExternalProcessHelper doRunDubCommand(int timeout, String... arguments)
throws IOException, InterruptedException, TimeoutException, OperationCancellation {
ExternalProcessHelper processHelper = startDubProcess(null, true, arguments);
ExternalProcessResult result = processHelper.awaitTerminationAndResult(timeout, true);
System.out.println(result.getStdOutBytes().toString(StringUtil.UTF8));
System.err.println(result.getStdErrBytes().toString(StringUtil.UTF8));
return processHelper;
}
public static void runDubList() {
System.out.println(":::: -------- `dub list`");
try {
CommonDubTest.doRunDubCommand(3000, "list");
} catch(IOException | InterruptedException | OperationCancellation e) {
throw melnorme.utilbox.core.ExceptionAdapter.unchecked(e);
} catch(TimeoutException e) {
assertFail(e.toString());
}
}
}