"use strict";

/* globals describe it */
const should = require("should");
const path = require("path");
const fs = require("fs");
const spawn = require("child_process").spawn;

function loadOptsFile(optsPath) {
	// Options file parser from Mocha
	// https://github.com/mochajs/mocha/blob/2bb2b9fa35818db7a02e5068364b0c417436b1af/bin/options.js#L25-L31
	return fs.readFileSync(optsPath, 'utf8')
		.replace(/\\\s/g, '%20')
		.split(/\s/)
		.filter(Boolean)
		.map(function(value) {
			return value.replace(/%20/g, ' ');
		});
}

function getTestSpecificArguments(testDirectory) {
	try {
		return loadOptsFile(path.join(testDirectory, "test.opts"));
	} catch(e) {
		return [];
	}
}

function convertToArrayOfLines(outputArray) {
	if(outputArray.length === 0) return outputArray;
	return outputArray.join('').split('\n');
}

const casesPath = path.join(__dirname, "binCases");
const defaultArgs = loadOptsFile(path.join(casesPath, "test.opts"));

describe("BinTestCases", function() {
	const categoryDirectories = fs.readdirSync(casesPath).filter((folder) => {
		return fs.statSync(path.join(casesPath, folder)).isDirectory()
	});

	const categories = categoryDirectories.map(function(categoryDirectory) {
		return {
			name: categoryDirectory,
			tests: fs.readdirSync(path.join(casesPath, categoryDirectory))
		};
	});

	categories.forEach(function(category) {
		describe(category.name, function() {

			category.tests.forEach(function(testName) {
				const testDirectory = path.join(casesPath, category.name, testName);
				const testArgs = defaultArgs.concat(getTestSpecificArguments(testDirectory));
				const testAssertions = require(path.join(testDirectory, "test.js"));
				const outputPath = path.join(path.resolve(casesPath, "../js/bin"), category.name, testName);

				const cmd = `${path.resolve(process.cwd(), "bin/webpack.js")}`;
				const args = testArgs.concat(["--output-path", `${outputPath}`]);
				const opts = {
					cwd: path.resolve("./", testDirectory)
				};

				const async = fs.existsSync(path.join(testDirectory, "async"));

				const env = {
					stdout: [],
					stderr: [],
					error: []
				};

				if(async) {
					describe(testName, function() {
						it("should run successfully", function(done) {
							this.timeout(10000);
							const child = spawn(process.execPath, [cmd].concat(args), opts);

							child.on("close", function(code) {
								env.code = code;
							});

							child.on("error", function(error) {
								env.error.push(error);
							});

							child.stdout.on("data", (data) => {
								env.stdout.push(data);
							});

							child.stderr.on("data", (data) => {
								env.stderr.push(data);
							});

							setTimeout(() => {
								if(env.code) {
									done(`Watch didn't run ${env.error}`)
								}

								const stdout = convertToArrayOfLines(env.stdout);
								const stderr = convertToArrayOfLines(env.stderr);
								testAssertions(stdout, stderr, done);
								child.kill()
							}, 3000); // wait a little to get an output
						});
					})
				} else {
					describe(testName, function() {
						before(function(done) {
							this.timeout(20000);

							const child = spawn(process.execPath, [cmd].concat(args), opts);

							child.on("close", function(code) {
								env.code = code;
								done();
							});

							child.on("error", function(error) {
								env.error.push(error);
							});

							child.stdout.on("data", (data) => {
								env.stdout.push(data);
							});

							child.stderr.on("data", (data) => {
								env.stderr.push(data);
							});
						});

						it("should not cause any errors", function() {
							should(env.error).be.empty();
						});

						it("should run successfully", function() {
							const stdout = convertToArrayOfLines(env.stdout);
							const stderr = convertToArrayOfLines(env.stderr);
							testAssertions(env.code, stdout, stderr);
						});
					});
				}
			});
		});
	});
});

@@ -1,19 +1,4 @@
-%22use strict%22;%0A%0A
 /* g
@@ -20,10 +20,32 @@
  it 
-*/
+before */%0A%22use strict%22;%0A
 %0Acon
@@ -391,14 +391,14 @@
 th, 
-'
+%22
 utf8
-'
+%22
 )%0A%09%09
@@ -419,13 +419,13 @@
 /g, 
-'%2520'
+%22%2520%22
 )%0A%09%09
@@ -517,11 +517,11 @@
 /g, 
-' '
+%22 %22
 );%0A%09
@@ -806,18 +806,18 @@
 oin(
-''
+%22%22
 ).split(
 '%5Cn'
@@ -816,12 +816,12 @@
 lit(
-'%5Cn'
+%22%5Cn%22
 );%0A%7D
@@ -1122,16 +1122,17 @@
 ectory()
+;
 %0A%09%7D);%0A%0A%09
@@ -2766,16 +2766,17 @@
 error%7D%60)
+;
 %0A%09%09%09%09%09%09%09
@@ -2961,16 +2961,17 @@
 d.kill()
+;
 %0A%09%09%09%09%09%09%09
@@ -3031,16 +3031,17 @@
 %0A%09%09%09%09%09%7D)
+;
 %0A%09%09%09%09%7D e

fix lint issues