/*******************************************************************************
 * Copyright (c) 2018, 2020 Cedric Chabanois and others.
 *
 * This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License 2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 *     Cedric Chabanois (cchabanois@gmail.com) - initial implementation
 *******************************************************************************/
package org.eclipse.jdt.debug.tests.launching;

import static org.junit.Assert.assertArrayEquals;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.file.Files;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.jar.Attributes;
import java.util.jar.JarInputStream;
import java.util.jar.Manifest;
import java.util.stream.Collectors;

import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.URIUtil;
import org.eclipse.jdt.debug.tests.AbstractDebugTest;
import org.eclipse.jdt.debug.tests.connectors.MockLaunch;
import org.eclipse.jdt.internal.launching.ClasspathShortener;

public class ClasspathShortenerTests extends AbstractDebugTest {
	private static final String MAIN_CLASS = "my.package.MainClass";
	private static final String ENCODING_ARG = "-Dfile.encoding=UTF-8";
	private static final String JAVA_10_PATH = "/usr/lib/jvm/java-10-jdk-amd64/bin/java";
	private static final String JAVA_8_PATH = "/usr/lib/jvm/java-8-openjdk-amd64/bin/java";
	private ClasspathShortenerForTest classpathShortener;
	private String userHome;

	public ClasspathShortenerTests(String name) {
		super(name);
	}

	@Override
	protected void setUp() throws Exception {
		super.setUp();
		userHome = System.getProperty("user.home");
	}

	@Override
	protected void tearDown() throws Exception {
		if (classpathShortener != null) {
			classpathShortener.getProcessTempFiles().forEach(file -> file.delete());
		}
		super.tearDown();
	}

	public void testNoNeedToShortenShortClasspath() {
		// Given
		String classpath = getClasspathOrModulePath(userHomePath("/workspace/myProject/bin"), userHomePath("/workspace/myProject/lib/lib 1.jar"));
		String[] cmdLine = new String[] { JAVA_10_PATH, ENCODING_ARG, "-classpath", classpath, MAIN_CLASS, "-arg1", "arg2" };
		classpathShortener = new ClasspathShortenerForTest(Platform.OS_LINUX, "10.0.1", cmdLine, 4, null);

		// When
		boolean result = classpathShortener.shortenCommandLineIfNecessary();

		// Then
		assertFalse(result);
	}

	public void testShortenClasspathWhenCommandLineIsTooLong() {
		// Given
		String classpath = getClasspathOrModulePath(userHomePath("/workspace/myProject/bin"), userHomePath("/workspace/myProject/lib/lib 1.jar"));
		String[] cmdLine = new String[] { JAVA_10_PATH, ENCODING_ARG, "-classpath", classpath, MAIN_CLASS, "-arg1", "arg2" };
		classpathShortener = new ClasspathShortenerForTest(Platform.OS_LINUX, "10.0.1", cmdLine, 4, null);

		// When
		classpathShortener.setMaxCommandLineLength(100);
		boolean result = classpathShortener.shortenCommandLineIfNecessary();

		// Then
		assertTrue(result);
	}

	public void testShortenClasspathWhenClasspathArgumentIsTooLong() {
		// Given
		String classpath = getClasspathOrModulePath(userHomePath("/workspace/myProject/bin"), userHomePath("/workspace/myProject/lib/lib 1.jar"));
		String[] cmdLine = new String[] { JAVA_10_PATH, ENCODING_ARG, "-classpath", classpath, MAIN_CLASS, "-arg1", "arg2" };
		classpathShortener = new ClasspathShortenerForTest(Platform.OS_LINUX, "10.0.1", cmdLine, 4, null);

		// When
		classpathShortener.setMaxArgLength(40);
		boolean result = classpathShortener.shortenCommandLineIfNecessary();

		// Then
		assertTrue(result);
	}

	public void testForceClasspathOnlyJar() throws Exception {
		// Given
		String classpath = getClasspathOrModulePath(userHomePath("/workspace/myProject/bin"), userHomePath("/workspace/myProject/lib/lib 1.jar"));
		String[] cmdLine = new String[] { JAVA_10_PATH, ENCODING_ARG, "-classpath", classpath, MAIN_CLASS, "-arg1", "arg2" };
		classpathShortener = new ClasspathShortenerForTest(Platform.OS_LINUX, "10.0.1", cmdLine, 4, null);

		// When
		classpathShortener.setForceUseClasspathOnlyJar(true);
		boolean result = classpathShortener.shortenCommandLineIfNecessary();

		// Then
		assertTrue(result);
		assertEquals(1, classpathShortener.getProcessTempFiles().size());
		assertArrayEquals(new String[] { JAVA_10_PATH, ENCODING_ARG, "-classpath", classpathShortener.getProcessTempFiles().get(0).getAbsolutePath(),
				MAIN_CLASS, "-arg1", "arg2" }, classpathShortener.getCmdLine());
		List<File> classpathJars = getClasspathJarsFromJarManifest(classpathShortener.getProcessTempFiles().get(0));
		String filePathSuffix = new File(userHomePath("/workspace/myProject/bin")).getPath();
		int index = classpathJars.get(0).getCanonicalFile().getPath().lastIndexOf(filePathSuffix);
		assertTrue("First Classpath jar file location not found", index != -1);
		filePathSuffix = new File(userHomePath("/workspace/myProject/lib/lib 1.jar")).getPath();
		index = classpathJars.get(1).getCanonicalFile().getPath().lastIndexOf(filePathSuffix);
		assertTrue("Second Classpath jar file location not found", index != -1);
	}

	public void testArgFileUsedForLongClasspathOnJava9() throws Exception {
		// Given
		String classpath = getClasspathOrModulePath(userHomePath("/workspace/myProject/bin"), userHomePath("/workspace/myProject/lib/lib 1.jar"));
		String[] cmdLine = new String[] { JAVA_10_PATH, ENCODING_ARG, "-cp", classpath, MAIN_CLASS, "-arg1", "arg2" };
		classpathShortener = new ClasspathShortenerForTest(Platform.OS_LINUX, "10.0.1", cmdLine, 4, null);
		classpathShortener.setMaxCommandLineLength(100);

		// When
		boolean result = classpathShortener.shortenCommandLineIfNecessary();

		// Then
		assertTrue(result);
		assertEquals(1, classpathShortener.getProcessTempFiles().size());
		assertArrayEquals(new String[] { JAVA_10_PATH, ENCODING_ARG, "@" + classpathShortener.getProcessTempFiles().get(0).getAbsolutePath(),
				MAIN_CLASS, "-arg1", "arg2" }, classpathShortener.getCmdLine());
		assertEquals("-classpath "
				+ classpathShortener.quoteWindowsPath(classpath), getFileContents(classpathShortener.getProcessTempFiles().get(0)));
	}

	public void testArgFileUsedForLongModulePath() throws Exception {
		// Given
		String modulepath = getClasspathOrModulePath(userHomePath("/workspace/myProject/bin"), userHomePath("/workspace/myProject/lib/lib 1.jar"));
		String[] cmdLine = new String[] { JAVA_10_PATH, ENCODING_ARG, "-p", modulepath, MAIN_CLASS, "-arg1", "arg2" };
		classpathShortener = new ClasspathShortenerForTest(Platform.OS_WIN32, "10.0.1", cmdLine, 4, null);
		classpathShortener.setMaxCommandLineLength(100);

		// When
		boolean result = classpathShortener.shortenCommandLineIfNecessary();

		// Then
		assertTrue(result);
		assertEquals(1, classpathShortener.getProcessTempFiles().size());
		assertArrayEquals(new String[] { JAVA_10_PATH, ENCODING_ARG, "@" + classpathShortener.getProcessTempFiles().get(0).getAbsolutePath(),
				MAIN_CLASS, "-arg1", "arg2" }, classpathShortener.getCmdLine());
		assertEquals("--module-path "
				+ classpathShortener.quoteWindowsPath(modulepath), getFileContents(classpathShortener.getProcessTempFiles().get(0)));
	}

	public void testLongClasspathAndLongModulePath() throws Exception {
		// Given
		String classpath = getClasspathOrModulePath(userHomePath("/workspace/myProject/lib/lib 2.jar"), userHomePath("/workspace/myProject/lib/lib 3.jar"));
		String modulepath = getClasspathOrModulePath(userHomePath("/workspace/myProject/bin"), userHomePath("/workspace/myProject/lib/lib 1.jar"));
		String[] cmdLine = new String[] { JAVA_10_PATH, ENCODING_ARG, "-cp", classpath, "-p", modulepath, MAIN_CLASS, "-arg1", "arg2" };
		classpathShortener = new ClasspathShortenerForTest(Platform.OS_WIN32, "10.0.1", cmdLine, 6, null);
		classpathShortener.setMaxCommandLineLength(100);

		// When
		boolean result = classpathShortener.shortenCommandLineIfNecessary();

		// Then
		assertTrue(result);
		assertEquals(2, classpathShortener.getProcessTempFiles().size());
		assertArrayEquals(new String[] { JAVA_10_PATH, ENCODING_ARG, "@" + classpathShortener.getProcessTempFiles().get(0).getAbsolutePath(),
				"@" + classpathShortener.getProcessTempFiles().get(1).getAbsolutePath(), MAIN_CLASS, "-arg1",
				"arg2" }, classpathShortener.getCmdLine());
		assertEquals("-classpath "
				+ classpathShortener.quoteWindowsPath(classpath), getFileContents(classpathShortener.getProcessTempFiles().get(0)));
		assertEquals("--module-path "
				+ classpathShortener.quoteWindowsPath(modulepath), getFileContents(classpathShortener.getProcessTempFiles().get(1)));
	}

	public void testClasspathOnlyJarUsedForLongClasspathOnJava8() throws Exception {
		// Given
		String classpath = getClasspathOrModulePath(userHomePath("/workspace/myProject/bin"), userHomePath("/workspace/myProject/lib/lib 1.jar"));
		String[] cmdLine = new String[] { JAVA_8_PATH, ENCODING_ARG, "-cp", classpath, MAIN_CLASS, "-arg1", "arg2" };
		classpathShortener = new ClasspathShortenerForTest(Platform.OS_LINUX, "1.8.0_171", cmdLine, 4, null);
		classpathShortener.setMaxCommandLineLength(100);

		// When
		classpathShortener.setAllowToUseClasspathOnlyJar(true);
		boolean result = classpathShortener.shortenCommandLineIfNecessary();

		// Then
		assertTrue(result);
		assertEquals(1, classpathShortener.getProcessTempFiles().size());
		assertArrayEquals(new String[] { JAVA_8_PATH, ENCODING_ARG, "-cp", classpathShortener.getProcessTempFiles().get(0).getAbsolutePath(),
				MAIN_CLASS, "-arg1", "arg2" }, classpathShortener.getCmdLine());
		List<File> classpathJars = getClasspathJarsFromJarManifest(classpathShortener.getProcessTempFiles().get(0));
		assertEquals(new File(userHomePath("/workspace/myProject/bin")), classpathJars.get(0).getCanonicalFile());
		assertEquals(new File(userHomePath("/workspace/myProject/lib/lib 1.jar")), classpathJars.get(1).getCanonicalFile());
	}

	public void testClasspathEnvVariableUsedForLongClasspathOnJava8OnWindows() {
		// Given
		String classpath = getClasspathOrModulePath(userHomePath("/workspace/myProject/bin"), userHomePath("/workspace/myProject/lib/lib 1.jar"));
		String[] cmdLine = new String[] { JAVA_8_PATH, ENCODING_ARG, "-cp", classpath, MAIN_CLASS, "-arg1", "arg2" };
		classpathShortener = new ClasspathShortenerForTest(Platform.OS_WIN32, "1.8.0_171", cmdLine, 4, null);
		classpathShortener.setMaxCommandLineLength(100);

		// When
		Map<String, String> nativeEnvironment = new LinkedHashMap<>();
		nativeEnvironment.put("PATH", "C:\\WINDOWS\\System32;C:\\WINDOWS");
		classpathShortener.setNativeEnvironment(nativeEnvironment);
		boolean result = classpathShortener.shortenCommandLineIfNecessary();

		// Then
		assertTrue(result);
		assertEquals(0, classpathShortener.getProcessTempFiles().size());
		assertArrayEquals(new String[] { "PATH=C:\\WINDOWS\\System32;C:\\WINDOWS",
				"CLASSPATH=" + classpath }, classpathShortener.getEnvp());
		assertArrayEquals(new String[] { JAVA_8_PATH, ENCODING_ARG, MAIN_CLASS, "-arg1", "arg2" }, classpathShortener.getCmdLine());
	}

	public void testClasspathUsedOnWindowsWhenEnvp() {
		// Given
		String classpath = getClasspathOrModulePath(userHomePath("/workspace/myProject/bin"), userHomePath("/workspace/myProject/lib/lib 1.jar"));
		String[] cmdLine = new String[] { JAVA_8_PATH, ENCODING_ARG, "-cp", classpath, MAIN_CLASS, "-arg1", "arg2" };
		String[] envp = new String[] { "MYVAR1=value1", "MYVAR2=value2" };
		classpathShortener = new ClasspathShortenerForTest(Platform.OS_WIN32, "1.8.0_171", cmdLine, 4, envp);
		classpathShortener.setMaxCommandLineLength(100);

		// When
		boolean result = classpathShortener.shortenCommandLineIfNecessary();

		// Then
		assertTrue(result);
		assertEquals(0, classpathShortener.getProcessTempFiles().size());
		assertArrayEquals(new String[] { "MYVAR1=value1", "MYVAR2=value2",
				"CLASSPATH=" + classpath }, classpathShortener.getEnvp());
		assertArrayEquals(new String[] { JAVA_8_PATH, ENCODING_ARG, MAIN_CLASS, "-arg1", "arg2" }, classpathShortener.getCmdLine());
	}

	public void testClasspathInEnvironmentReplacedOnWindows() {
		// Given
		String classpath = getClasspathOrModulePath(userHomePath("/workspace/myProject/bin"), userHomePath("/workspace/myProject/lib/lib 1.jar"));
		String[] cmdLine = new String[] { JAVA_8_PATH, ENCODING_ARG, "-cp", classpath, MAIN_CLASS, "-arg1", "arg2" };
		classpathShortener = new ClasspathShortenerForTest(Platform.OS_WIN32, "1.8.0_171", cmdLine, 4, null);
		classpathShortener.setMaxCommandLineLength(100);

		// When
		Map<String, String> nativeEnvironment = new LinkedHashMap<>();
		nativeEnvironment.put("PATH", "C:\\WINDOWS\\System32;C:\\WINDOWS");
		nativeEnvironment.put("CLASSPATH", "C:\\myJars\\jar1.jar");
		classpathShortener.setNativeEnvironment(nativeEnvironment);
		boolean result = classpathShortener.shortenCommandLineIfNecessary();

		// Then
		assertTrue(result);
		assertEquals(0, classpathShortener.getProcessTempFiles().size());
		assertArrayEquals(new String[] { "PATH=C:\\WINDOWS\\System32;C:\\WINDOWS",
				"CLASSPATH=" + classpath }, classpathShortener.getEnvp());
		assertArrayEquals(new String[] { JAVA_8_PATH, ENCODING_ARG, MAIN_CLASS, "-arg1", "arg2" }, classpathShortener.getCmdLine());
	}

	private String getFileContents(File file) throws UnsupportedEncodingException, IOException {
		return new String(Files.readAllBytes(file.toPath()), "UTF-8");
	}

	private String getClasspathAttributeFromJarManifest(File jarFile) throws FileNotFoundException, IOException {
		try (JarInputStream jarStream = new JarInputStream(new FileInputStream(jarFile))) {
			Manifest mf = jarStream.getManifest();
			return mf.getMainAttributes().getValue(Attributes.Name.CLASS_PATH);
		}
	}

	private List<File> getClasspathJarsFromJarManifest(File jarFile) throws FileNotFoundException, IOException {
		File parentDir = jarFile.getParentFile();
		String classpath = getClasspathAttributeFromJarManifest(jarFile);
		return Arrays.stream(classpath.split(" ")).map(relativePath -> {
			try {
				return new File(URIUtil.makeAbsolute(new URI(relativePath), parentDir.toURI()));
			} catch (URISyntaxException e) {
				throw new RuntimeException(e);
			}
		}).collect(Collectors.toList());
	}

	private String userHomePath(String path) {
		return userHome + path;
	}

	private String getClasspathOrModulePath(String... classpathElements) {
		return String.join(";", classpathElements);
	}

	private static class ClasspathShortenerForTest extends ClasspathShortener {
		private boolean forceUseClasspathOnlyJar = false;
		private boolean allowToUseClasspathOnlyJar = false;
		private int maxArgLength = Integer.MAX_VALUE;
		private int maxCommandLineLength = Integer.MAX_VALUE;
		private Map<String, String> nativeEnvironment = new HashMap<>();

		public ClasspathShortenerForTest(String os, String javaVersion, String[] cmdLine, int classpathArgumentIndex, String[] envp) {
			super(os, javaVersion, new MockLaunch(), cmdLine, classpathArgumentIndex, null, envp);
		}

		public void setAllowToUseClasspathOnlyJar(boolean allowToUseClasspathOnlyJar) {
			this.allowToUseClasspathOnlyJar = allowToUseClasspathOnlyJar;
		}

		public void setForceUseClasspathOnlyJar(boolean forceUseClasspathOnlyJar) {
			this.forceUseClasspathOnlyJar = forceUseClasspathOnlyJar;
		}

		@Override
		protected String getLaunchConfigurationName() {
			return "launch";
		}

		@Override
		protected String getLaunchTimeStamp() {
			return Long.toString(System.currentTimeMillis());
		}

		@Override
		protected boolean handleClasspathTooLongStatus() throws CoreException {
			return allowToUseClasspathOnlyJar;
		}

		@Override
		protected boolean getLaunchConfigurationUseClasspathOnlyJarAttribute() throws CoreException {
			return forceUseClasspathOnlyJar;
		}

		@Override
		protected int getMaxArgLength() {
			return maxArgLength;
		}

		@Override
		protected int getMaxCommandLineLength() {
			return maxCommandLineLength;
		}

		public void setMaxArgLength(int maxArgLength) {
			this.maxArgLength = maxArgLength;
		}

		public void setMaxCommandLineLength(int maxCommandLineLength) {
			this.maxCommandLineLength = maxCommandLineLength;
		}

		public void setNativeEnvironment(Map<String, String> nativeEnvironment) {
			this.nativeEnvironment = nativeEnvironment;
		}

		@Override
		protected Map<String, String> getNativeEnvironment() {
			return nativeEnvironment;
		}

		@Override
		protected char getPathSeparatorChar() {
			// always use ';' as separator (tests would fail on windows otherwise with paths c:\ ...)
			return ';';
		}

	}

}
