text: /*---------------------------------------------------------------------------------------------
   *  Copyright (c) Microsoft Corporation. All rights reserved.
   *  Licensed under the MIT License. See License.txt in the project root for license information.
   *--------------------------------------------------------------------------------------------*/
  
  // mocha disables running through electron by default. Note that this must
  // come before any mocha imports.
  process.env.MOCHA_COLORS = '1';
  
  const { app, BrowserWindow, ipcMain } = require('electron');
  const { tmpdir } = require('os');
  const { join } = require('path');
  const path = require('path');
  const mocha = require('mocha');
  const events = require('events');
  const MochaJUnitReporter = require('mocha-junit-reporter');
  const url = require('url');
  const createStatsCollector = require('mocha/lib/stats-collector');
  const FullJsonStreamReporter = require('../fullJsonStreamReporter');
  
  // Disable render process reuse, we still have
  // non-context aware native modules in the renderer.
  app.allowRendererProcessReuse = false;
  
  const optimist = require('optimist')
  	.describe('grep', 'only run tests matching <pattern>').alias('grep', 'g').alias('grep', 'f').string('grep')
  	.describe('run', 'only run tests from <file>').string('run')
  	.describe('runGlob', 'only run tests matching <file_pattern>').alias('runGlob', 'glob').alias('runGlob', 'runGrep').string('runGlob')
  	.describe('build', 'run with build output (out-build)').boolean('build')
  	.describe('coverage', 'generate coverage report').boolean('coverage')
  	.describe('debug', 'open dev tools, keep window open, reuse app data').string('debug')
  	.describe('reporter', 'the mocha reporter').string('reporter').default('reporter', 'spec')
  	.describe('reporter-options', 'the mocha reporter options').string('reporter-options').default('reporter-options', '')
  	.describe('tfs').string('tfs')
  	.describe('help', 'show the help').alias('help', 'h');
  
  const argv = optimist.argv;
  
  if (argv.help) {
  	optimist.showHelp();
  	process.exit(0);
  }
  
  if (!argv.debug) {
  	app.setPath('userData', join(tmpdir(), `vscode-tests-${Date.now()}`));
  }
  
  function deserializeSuite(suite) {
  	return {
  		root: suite.root,
  		suites: suite.suites,
  		tests: suite.tests,
  		title: suite.title,
  		titlePath: () => suite.titlePath,
  		fullTitle: () => suite.fullTitle,
  		timeout: () => suite.timeout,
  		retries: () => suite.retries,
  		slow: () => suite.slow,
  		bail: () => suite.bail
  	};
  }
  
  function deserializeRunnable(runnable) {
  	return {
  		title: runnable.title,
  		titlePath: () => runnable.titlePath,
  		fullTitle: () => runnable.fullTitle,
  		async: runnable.async,
  		slow: () => runnable.slow,
  		speed: runnable.speed,
  		duration: runnable.duration,
  		currentRetry: () => runnable.currentRetry
  	};
  }
  
  function importMochaReporter(name) {
  	if (name === 'full-json-stream') {
  		return FullJsonStreamReporter;
  	}
  
  	const reporterPath = path.join(path.dirname(require.resolve('mocha')), 'lib', 'reporters', name);
  	return require(reporterPath);
  }
  
  function deserializeError(err) {
  	const inspect = err.inspect;
  	err.inspect = () => inspect;
  	if (err.actual) {
  		err.actual = JSON.parse(err.actual).value;
  	}
  	if (err.expected) {
  		err.expected = JSON.parse(err.expected).value;
  	}
  	return err;
  }
  
  class IPCRunner extends events.EventEmitter {
  
  	constructor() {
  		super();
  
  		this.didFail = false;
  		this.didEnd = false;
  
  		ipcMain.on('start', () => this.emit('start'));
  		ipcMain.on('end', () => {
  			this.didEnd = true;
  			this.emit('end');
  		});
  		ipcMain.on('suite', (e, suite) => this.emit('suite', deserializeSuite(suite)));
  		ipcMain.on('suite end', (e, suite) => this.emit('suite end', deserializeSuite(suite)));
  		ipcMain.on('test', (e, test) => this.emit('test', deserializeRunnable(test)));
  		ipcMain.on('test end', (e, test) => this.emit('test end', deserializeRunnable(test)));
  		ipcMain.on('hook', (e, hook) => this.emit('hook', deserializeRunnable(hook)));
  		ipcMain.on('hook end', (e, hook) => this.emit('hook end', deserializeRunnable(hook)));
  		ipcMain.on('pass', (e, test) => this.emit('pass', deserializeRunnable(test)));
  		ipcMain.on('fail', (e, test, err) => {
  			this.didFail = true;
  			this.emit('fail', deserializeRunnable(test), deserializeError(err));
  		});
  		ipcMain.on('pending', (e, test) => this.emit('pending', deserializeRunnable(test)));
  	}
  }
  
  function parseReporterOption(value) {
  	let r = /^([^=]+)=(.*)$/.exec(value);
  	return r ? { [r[1]]: r[2] } : {};
  }
  
  app.on('ready', () => {
  
  	ipcMain.on('error', (_, err) => {
  		if (!argv.debug) {
  			console.error(err);
  			app.exit(1);
  		}
  	});
  
  	// We need to provide a basic `ISandboxConfiguration`
  	// for our preload script to function properly because
  	// some of our types depend on it (e.g. product.ts).
  	ipcMain.handle('vscode:test-vscode-window-config', async () => {
  		return {
  			product: {
  				version: '1.x.y',
  				nameShort: 'Code - OSS Dev',
  				nameLong: 'Code - OSS Dev',
  				applicationName: 'code-oss',
  				dataFolderName: '.vscode-oss',
  				urlProtocol: 'code-oss',
  			}
  		};
  	});
  
  	// No-op since invoke the IPC as part of IIFE in the preload.
  	ipcMain.handle('vscode:fetchShellEnv', event => { });
  
  	const win = new BrowserWindow({
  		height: 600,
  		width: 800,
  		show: false,
  		webPreferences: {
  			preload: path.join(__dirname, '..', '..', '..', 'src', 'vs', 'base', 'parts', 'sandbox', 'electron-browser', 'preload.js'), // ensure similar environment as VSCode as tests may depend on this
  			additionalArguments: [`--vscode-window-config=vscode:test-vscode-window-config`],
  			nodeIntegration: true,
  			contextIsolation: false,
  			enableWebSQL: false,
  			enableRemoteModule: false,
  			spellcheck: false,
  			nativeWindowOpen: true,
  			webviewTag: true
  		}
  	});
  
  	win.webContents.on('did-finish-load', () => {
  		if (argv.debug) {
  			win.show();
  			win.webContents.openDevTools();
  		}
  		win.webContents.send('run', argv);
  	});
  
  	win.loadURL(url.format({ pathname: path.join(__dirname, 'renderer.html'), protocol: 'file:', slashes: true }));
  
  	const runner = new IPCRunner();
  	createStatsCollector(runner);
  
  	// Handle renderer crashes, #117068
  	win.webContents.on('render-process-gone', (evt, details) => {
  		if (!runner.didEnd) {
  			console.error(`Renderer process crashed with: ${JSON.stringify(details)}`);
  			app.exit(1);
  		}
  	});
  
  	if (argv.tfs) {
  		new mocha.reporters.Spec(runner);
  		new MochaJUnitReporter(runner, {
  			reporterOptions: {
  				testsuitesTitle: `${argv.tfs} ${process.platform}`,
  				mochaFile: process.env.BUILD_ARTIFACTSTAGINGDIRECTORY ? path.join(process.env.BUILD_ARTIFACTSTAGINGDIRECTORY, `test-results/${process.platform}-${process.arch}-${argv.tfs.toLowerCase().replace(/[^\w]/g, '-')}-results.xml`) : undefined
  			}
  		});
  	} else {
  		// mocha patches symbols to use windows escape codes, but it seems like
  		// Electron mangles these in its output.
  		if (process.platform === 'win32') {
  			Object.assign(importMochaReporter('base').symbols, {
  				ok: '+',
  				err: 'X',
  				dot: '.',
  			});
  		}
  
  		let Reporter;
  		try {
  			Reporter = importMochaReporter(argv.reporter);
  		} catch (err) {
  			try {
  				Reporter = require(argv.reporter);
  			} catch (err) {
  				Reporter = process.platform === 'win32' ? mocha.reporters.List : mocha.reporters.Spec;
  				console.warn(`could not load reporter: ${argv.reporter}, using ${Reporter.name}`);
  			}
  		}
  
  		let reporterOptions = argv['reporter-options'];
  		reporterOptions = typeof reporterOptions === 'string' ? [reporterOptions] : reporterOptions;
  		reporterOptions = reporterOptions.reduce((r, o) => Object.assign(r, parseReporterOption(o)), {});
  
  		new Reporter(runner, { reporterOptions });
  	}
  
  	if (!argv.debug) {
  		ipcMain.on('all done', () => app.exit(runner.didFail ? 1 : 0));
  	}
  });
  