package fr.inria.gforge.spoon.assertgenerator;

import fr.inria.gforge.spoon.assertgenerator.workflow.Analyzer;
import fr.inria.gforge.spoon.assertgenerator.workflow.AssertionAdder;
import fr.inria.gforge.spoon.assertgenerator.workflow.Collector;
import org.junit.Test;
import spoon.Launcher;
import spoon.reflect.code.CtLocalVariable;
import spoon.reflect.declaration.CtClass;
import spoon.reflect.declaration.CtMethod;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.stream.Collectors;

/**
 * Created by Benjamin DANGLOT
 * [email protected]
 * on 20/06/17
 */
public class AssertionGenerationTest {

	@Test
	public void test() {
		Launcher launcher = new Launcher();
		launcher.getEnvironment().setAutoImports(true);
		launcher.getEnvironment().setLevel(Level.ALL.toString());
		launcher.addInputResource("src/test/resources/project/src/main/java/");
		launcher.addInputResource("src/test/resources/project/src/test/java/");
		launcher.addInputResource("src/main/java/fr/inria/gforge/spoon/assertgenerator/Logger.java");
		launcher.getEnvironment().setSourceClasspath(getPathToJunit());
		launcher.buildModel();

		final Analyzer analyzer = new Analyzer();
		final Collector collector = new Collector(launcher.getFactory());
		final AssertionAdder assertionAdder = new AssertionAdder(launcher.getFactory());

		launcher.getFactory().Class().getAll().forEach(ctClass -> {
			// Analyze
			Map<CtMethod, List<CtLocalVariable>> localVariablesPerTestMethod = analyzer.analyze(ctClass);
			localVariablesPerTestMethod.keySet().stream().forEach(key -> System.out.println("{"+ key.getParent(CtClass.class).getSimpleName() + "#" + key.getSimpleName() + "=["+ localVariablesPerTestMethod.get(key) +"]"));
			if (!localVariablesPerTestMethod.isEmpty()) {
				// Collect
				localVariablesPerTestMethod.keySet().forEach(ctMethod -> collector.collect(launcher, ctMethod, localVariablesPerTestMethod.get(ctMethod)));
				// Generate
				localVariablesPerTestMethod.keySet().forEach(ctMethod -> assertionAdder.addAssertion(ctMethod, localVariablesPerTestMethod.get(ctMethod)));
			}
		});
	}

	private static String[] getPathToJunit() {
		File file = new File(".cp");
		try {
			final String cmd;
			if (System.getProperty("os.name").startsWith("Windows")) {
				cmd = "cmd /C mvn dependency:build-classpath -Dmdep.outputFile=.cp";
			} else {
				cmd = "mvn dependency:build-classpath -Dmdep.outputFile=.cp";
			}
			Process p = Runtime.getRuntime().exec(cmd);
			new Thread() {
				@Override
				public void run() {
					while (p.isAlive()) {
						try {
							System.out.print((char) p.getInputStream().read());
						} catch (IOException e) {
							e.printStackTrace();
						}
					}
				}
			}.start();
			p.waitFor();
			final String classpath;
			try (BufferedReader buffer = new BufferedReader(new FileReader(file))) {
				classpath = buffer.lines().collect(Collectors.joining(System.getProperty("path.separator")));
			}
			file.delete();
			return classpath.split(System.getProperty("path.separator"));
		} catch (IOException | InterruptedException e) {
			throw new RuntimeException(e);
		}

	}


}