import * as assert from 'assert' ; import { afterEach , beforeEach } from 'mocha' ; import * as os from 'os' ; import * as process from 'process' ; import * as vscode from 'vscode' ; import { activate } from '../../extension' ; import { stubConfig , stubFile , stubRemoteName , stubWslVersion } from '../stubs' ; import sinon = require ( 'sinon' ) ; suite ( 'Extension Test Suite' , ( ) => { let context ; beforeEach ( ( ) => { context = new MockContext ( ) ; } ) ; afterEach ( ( ) => { sinon . restore ( ) ; context . subscriptions . forEach ( ( s ) => s . dispose ( ) ) ; } ) ; test ( 'No remote' , async ( ) => { stubRemoteName ( undefined ) ; await activate ( context ) ; assert . deepStrictEqual ( getVariables ( context ) , { } ) ; } ) ; test ( 'Container: attached' , async ( ) => { stubRemoteName ( 'attached-container' ) ; stubConfig ( { display : 1 , screen : 2 , } ) ; await activate ( context ) ; assert . deepStrictEqual ( getVariables ( context ) , { DISPLAY : 'host.docker.internal:1.2' , LIBGL_ALWAYS_INDIRECT : '1' , } ) ; } ) ; test ( 'Container: dev' , async ( ) => { stubRemoteName ( 'dev-container' ) ; stubConfig ( { display : 1 , screen : 2 , } ) ; await activate ( context ) ; assert . deepStrictEqual ( getVariables ( context ) , { DISPLAY : 'host.docker.internal:1.2' , LIBGL_ALWAYS_INDIRECT : '1' , } ) ; } ) ; test ( 'Container: disabled' , async ( ) => { stubRemoteName ( 'attached-container' ) ; stubConfig ( { 'container.enable' : false , } ) ; await activate ( context ) ; assert . deepStrictEqual ( getVariables ( context ) , { } ) ; } ) ; test ( 'WSL 1: enabled' , async ( ) => { stubRemoteName ( 'wsl' ) ; stubWslVersion ( 1 ) ; stubConfig ( { display : 1 , screen : 2 , } ) ; await activate ( context ) ; assert . deepStrictEqual ( getVariables ( context ) , { DISPLAY : 'localhost:1.2' , LIBGL_ALWAYS_INDIRECT : '1' , } ) ; } ) ; test ( 'WSL 2: enabled' , async ( ) => { stubRemoteName ( 'wsl' ) ; stubWslVersion ( 2 ) ; stubConfig ( { display : 1 , screen : 2 , } ) ; stubFile ( '/etc/resolv.conf' , { encoding : 'utf-8' } , '# This file was automatically generated by WSL. To stop automatic generation of this file, add the following entry to /etc/wsl.conf:\n' + '# [network]\n' + '# generateResolvConf = false\n' + 'nameserver 172.24.96.1' ) ; await activate ( context ) ; assert . deepStrictEqual ( getVariables ( context ) , { DISPLAY : '172.24.96.1:1.2' , LIBGL_ALWAYS_INDIRECT : '1' , } ) ; } ) ; test ( 'WSL: disabled' , async ( ) => { stubRemoteName ( 'wsl' ) ; stubWslVersion ( 1 ) ; stubConfig ( { 'WSL.enable' : false , } ) ; await activate ( context ) ; assert . deepStrictEqual ( getVariables ( context ) , { } ) ; } ) ; test ( 'SSH: enabled' , async ( ) => { stubRemoteName ( 'ssh-remote' ) ; stubConfig ( { display : 1 , screen : 2 , } ) ; process . env [ 'SSH_CONNECTION' ] = 'clientaddr 1234 serveraddr 5678' ; sinon . stub ( os , 'userInfo' ) . returns ( { gid : 8765 , homedir : '' , shell : 'turtle' , uid : 4321 , username : 'fakeuser' , } ) ; const stub = sinon . stub ( vscode . commands , 'executeCommand' ) . withArgs ( 'remote-x11-ssh.connect' , { host : 'serveraddr' , port : 5678 , username : 'fakeuser' , } ) . resolves ( 'localhost:1.2' ) ; await activate ( context ) ; assert ( stub . called ) ; assert . deepStrictEqual ( getVariables ( context ) , { DISPLAY : 'localhost:1.2' , LIBGL_ALWAYS_INDIRECT : '1' , } ) ; } ) ; test ( 'SSH: disabled' , async ( ) => { stubRemoteName ( 'ssh-remote' ) ; stubConfig ( { 'SSH.enable' : false , } ) ; const spy = sinon . spy ( vscode . commands , 'executeCommand' ) ; await activate ( context ) ; assert ( spy . neverCalledWithMatch ( 'remote-x11-ssh.connect' ) ) ; assert . deepStrictEqual ( getVariables ( context ) , { } ) ; } ) ; test ( 'extraVariables' , async ( ) => { stubRemoteName ( 'wsl' ) ; stubWslVersion ( 1 ) ; stubConfig ( { extraVariables : [ 'FOO=1' , 'BAR = 2' , ' BAZ  =3  ' ] , } ) ; await activate ( context ) ; assert . deepStrictEqual ( getVariables ( context ) , { DISPLAY : 'localhost:0.0' , FOO : '1' , BAR : '2' , BAZ : '3' , } ) ; } ) ; test ( 'extraVariables: default' , async ( ) => { stubRemoteName ( 'wsl' ) ; stubWslVersion ( 1 ) ; stubConfig ( { } ) ; await activate ( context ) ; assert . deepStrictEqual ( getVariables ( context ) , { DISPLAY : 'localhost:0.0' , LIBGL_ALWAYS_INDIRECT : '1' , } ) ; } ) ; test ( 'extraVariables: empty' , async ( ) => { stubRemoteName ( 'wsl' ) ; stubWslVersion ( 1 ) ; stubConfig ( { extraVariables : [ ] , } ) ; await activate ( context ) ; assert . deepStrictEqual ( getVariables ( context ) , { DISPLAY : 'localhost:0.0' , } ) ; } ) ; } ) ; function getVariables ( context ) { const variables = { } ; context . environmentVariableCollection . forEach ( ( name , mutator ) => { variables [ name ] = mutator . value ; } ) ; return variables ; } class MockContext implements vscode . ExtensionContext { public readonly subscriptions : { dispose ( ) : any ; } [ ] = [ ] ; public readonly workspaceState = new MockMemento ( ) ; public readonly globalState = new MockMemento ( ) ; public readonly extensionMode = vscode . ExtensionMode . Test ; public readonly extensionUri = vscode . Uri . file ( '/fake/path' ) ; public get extensionPath ( ) { return this . extensionUri . fsPath ; } public readonly storageUri = undefined ; public readonly globalStorageUri = vscode . Uri . file ( '/fake/path' ) ; public readonly logUri = vscode . Uri . file ( '/fake/path' ) ; public readonly environmentVariableCollection = new MockEnvironmentVariableCollection ( ) ; public asAbsolutePath ( relativePath ) { return vscode . Uri . joinPath ( this . extensionUri , relativePath ) . fsPath ; } public readonly storagePath = undefined ; public readonly globalStoragePath = '/fake/path' ; public readonly logPath = '/fake/path' ; } class MockMemento implements vscode . Memento { public get < T > ( _key , _defaultValue ? ) { return undefined ; } public update ( _key , _value ) { return Promise . resolve ( ) ; } public setKeysForSync ( keys ) { } } class MockEnvironmentVariableCollection implements vscode . EnvironmentVariableCollection { public persistent = true ; private map = new Map < string , vscode . EnvironmentVariableMutator > ( ) ; public replace ( variable , value ) { this . map . set ( variable , { type : vscode . EnvironmentVariableMutatorType . Replace , value , } ) ; } public append ( variable , value ) { this . map . set ( variable , { type : vscode . EnvironmentVariableMutatorType . Append , value , } ) ; } public prepend ( variable , value ) { this . map . set ( variable , { type : vscode . EnvironmentVariableMutatorType . Prepend , value , } ) ; } public get ( variable ) { return this . map . get ( variable ) ; } public forEach ( callback , thisArg ? ) { for ( const [ variable , mutator ] of this . map ) { callback . apply ( thisArg , [ variable , mutator , this ] ) ; } } public delete ( variable ) { this . map . delete ( variable ) ; } public clear ( ) { this . map . clear ( ) ; } }