Skip to content

Commit

Permalink
test: give each test suite an indepedent workspace (#403)
Browse files Browse the repository at this point in the history
  • Loading branch information
sockmaster27 authored May 17, 2024
1 parent 8edf062 commit 0cea61a
Show file tree
Hide file tree
Showing 45 changed files with 273 additions and 67 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,7 @@ client/server
.vscode-test
notes
target
test/activeWorkspace
!test/activeWorkspace/.gitkeep
flix.jar
*.vsix
2 changes: 1 addition & 1 deletion .vscode-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const version = process.env.VSCODE_VERSION
module.exports = defineConfig({
version,
files: ['test/out/**/*.test.js'],
workspaceFolder: 'test/testWorkspace',
workspaceFolder: 'test/activeWorkspace/',

mocha: {
// Downloading compiler takes a long time
Expand Down
1 change: 1 addition & 0 deletions test/activeWorkspace/.gitkeep
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Ensure that this empty directory is checked in
12 changes: 3 additions & 9 deletions test/src/codeActions.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,23 +16,17 @@

import * as assert from 'assert'
import * as vscode from 'vscode'
import { getTestDocUri, activate, open, copyFile, tryDeleteFile } from './util'
import { getTestDocUri, activate, open } from './util'

suite('Code actions', () => {
const docUriLatent = getTestDocUri('latent/UnusedFunction.flix')
const docUri = getTestDocUri('src/UnusedFunction.flix')

suiteSetup(async () => {
await activate()
})
teardown(async () => {
await tryDeleteFile(docUri)
await activate('codeActions')
await open(docUri)
})

test('Should propose prefixing unused def with underscore', async () => {
await copyFile(docUriLatent, docUri)
await open(docUri)

const position = new vscode.Position(1, 8)
const range = new vscode.Range(position, position)
const r = (await vscode.commands.executeCommand(
Expand Down
2 changes: 1 addition & 1 deletion test/src/codeLenses.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ suite('Code lenses', () => {
const areaDocUri = getTestDocUri('src/Area.flix')

suiteSetup(async () => {
await activate()
await activate('codeLenses')
})

test('Should propose running main function', async () => {
Expand Down
8 changes: 2 additions & 6 deletions test/src/completions.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,24 +16,20 @@

import * as assert from 'assert'
import * as vscode from 'vscode'
import { getTestDocUri, activate, open, tryDeleteFile, addFile, typeText } from './util'
import { getTestDocUri, activate, open, typeText, addFile } from './util'

suite('Completions', () => {
const docUri = getTestDocUri('src/Temp.flix')

suiteSetup(async () => {
await activate()
})
teardown(async () => {
await tryDeleteFile(docUri)
await activate('completions')
})

test('Should propose completing mod', async () => {
await addFile(docUri, '')
await open(docUri)
await typeText('mo')

// TODO: Figure out why this returns all possible keywords, which is not what is shown in the editor
const position = new vscode.Position(0, 2)
const r = (await vscode.commands.executeCommand(
'vscode.executeCompletionItemProvider',
Expand Down
2 changes: 1 addition & 1 deletion test/src/diagnostics.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ suite('Diagnostics', () => {
let tempDocUri: vscode.Uri | null = null

suiteSetup(async () => {
await activate()
await activate('diagnostics')
})
teardown(async () => {
if (tempDocUri !== null) {
Expand Down
2 changes: 1 addition & 1 deletion test/src/disconnect.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import { activate, getTestDocUri, sleep } from './util'

suite('Server disconnect', () => {
suiteSetup(async () => {
await activate()
await activate('disconnect')
})

test('When server is disconnected a reconnection should happen automatically', async () => {
Expand Down
11 changes: 3 additions & 8 deletions test/src/files.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,22 +24,17 @@ suite('File manipulation', () => {
const doc2Uri = getTestDocUri('src/Area.flix')
let doc2Content: Uint8Array

const jarUri = getTestDocUri('lib/external/SquareArea.jar')
let jarContent: Uint8Array

const fpkgUri = getTestDocUri('lib/circleArea.fpkg')
let fpkgContent: Uint8Array

suiteSetup(async () => {
await activate()
await activate('files')
doc2Content = await vscode.workspace.fs.readFile(doc2Uri)
jarContent = await vscode.workspace.fs.readFile(jarUri)
fpkgContent = await vscode.workspace.fs.readFile(fpkgUri)
})
teardown(async () => {
// Restore the original content of the file after each test
setup(async () => {
// Restore the original content of the files before each test
await addFile(doc2Uri, doc2Content)
await addFile(jarUri, jarContent)
await addFile(fpkgUri, fpkgContent)
})

Expand Down
17 changes: 5 additions & 12 deletions test/src/findReferences.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@ suite('Find references', () => {
const areaDocUri = getTestDocUri('src/Area.flix')

suiteSetup(async () => {
await activate()
await activate('findReferences')
})

test('Should find references to enum case', async () => {
test.skip('Should find references to enum case', async () => {
const position = new vscode.Position(3, 9)
const r = (await vscode.commands.executeCommand(
'vscode.executeReferenceProvider',
Expand All @@ -39,11 +39,8 @@ suite('Find references', () => {
const mainReference = r.find(l => l.uri.path.endsWith(mainDocUri.path))
const areaReference = r.find(l => l.uri.path.endsWith(areaDocUri.path))

assert.notStrictEqual(mainReference, undefined)
assert.notStrictEqual(areaReference, undefined)

assert.deepStrictEqual(mainReference?.range, new vscode.Range(3, 9, 3, 22))
assert.deepStrictEqual(areaReference?.range, new vscode.Range(6, 13, 6, 25))
assert.deepStrictEqual(areaReference?.range, new vscode.Range(5, 13, 5, 25))
})

test('Should find references to def', async () => {
Expand All @@ -57,15 +54,11 @@ suite('Find references', () => {
assert.strictEqual(r.length, 3)

const defReference = r.find(l => l.uri.path.endsWith(areaDocUri.path) && l.range.start.line === 3)
const testReference = r.find(l => l.uri.path.endsWith(areaDocUri.path) && l.range.start.line === 13)
const testReference = r.find(l => l.uri.path.endsWith(areaDocUri.path) && l.range.start.line === 12)
const mainReference = r.find(l => l.uri.path.endsWith(mainDocUri.path))

assert.notStrictEqual(defReference, undefined)
assert.notStrictEqual(testReference, undefined)
assert.notStrictEqual(mainReference, undefined)

assert.deepStrictEqual(defReference?.range, new vscode.Range(3, 4, 3, 8))
assert.deepStrictEqual(testReference?.range, new vscode.Range(13, 39, 13, 43))
assert.deepStrictEqual(testReference?.range, new vscode.Range(12, 39, 12, 43))
assert.deepStrictEqual(mainReference?.range, new vscode.Range(10, 12, 10, 16))
})
})
2 changes: 1 addition & 1 deletion test/src/hover.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ suite('Hover info', () => {
const brokenDocUri = getTestDocUri('src/Broken.flix')

suiteSetup(async () => {
await activate()
await activate('hover')
await open(docUri)
})
teardown(async () => {
Expand Down
75 changes: 68 additions & 7 deletions test/src/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,64 @@ import * as path from 'path'
import * as vscode from 'vscode'

/**
* Activates the extension in the `testWorkspace` directory.
* Activates the extension and copies the contents of the given test workspace directory into the extive workspace.
*
* @param testWorkspaceName The name of the workspace directory to copy, e.g. `codeActions`.
*/
export async function activate() {
export async function activate(testWorkspaceName: string) {
// The extensionId is `publisher.name` from package.json
const ext = vscode.extensions.getExtension('flix.flix')
if (ext === undefined) {
throw new Error('Failed to activate extension')
}

await copyWorkspace(testWorkspaceName)

// This includes the time it takes for the compiler to download
// The time it takes for the compiler to start will be awaited in the first command sent to the extension
await ext.activate()
}

/**
* Clears the test workspace, and copies the contents of the given test workspace directory into the active workspace.
*
* @param testWorkspaceName The name of the workspace directory to copy, e.g. `codeActions`.
*/
async function copyWorkspace(testWorkspaceName: string) {
vscode.commands.executeCommand('workbench.action.closeAllEditors')

const activeWorkspaceUri = vscode.workspace.workspaceFolders![0].uri

/** Recursively clears all safe files from the given directory. */
async function clearDir(uri: vscode.Uri) {
const contents = await vscode.workspace.fs.readDirectory(uri)

// Recurse into subdirectories
const dirs = contents.filter(([_, type]) => type === vscode.FileType.Directory)
const dirUris = dirs.map(([name, _]) => vscode.Uri.joinPath(uri, name))
await Promise.allSettled(dirUris.map(clearDir))

const files = contents.filter(([_, type]) => type !== vscode.FileType.Directory)
const fileNames = files.map(([name, _]) => name)

// Delete all files except .gitkeep and flix.jar
const namesToKeep = ['.gitkeep', 'flix.jar']

// Be careful, and only delete files with known extensions
const extensionsToDelete = ['flix', 'toml', 'jar', 'fpkg', 'txt']

const namesToDelete = fileNames.filter(
name => !namesToKeep.includes(name) && extensionsToDelete.includes(name.split('.').at(-1)),
)
const urisToDelete = namesToDelete.map(name => vscode.Uri.joinPath(uri, name))
await Promise.allSettled(urisToDelete.map(deleteFile))
}
await clearDir(activeWorkspaceUri)

const testWorkspacePath = path.resolve(__dirname, '../testWorkspaces', testWorkspaceName)
await copyDirContents(vscode.Uri.file(testWorkspacePath), activeWorkspaceUri)
}

/**
* Opens the document at `docUri` in the main editor.
*/
Expand All @@ -48,7 +92,7 @@ export async function typeText(text: string) {
}

function getTestDocPath(p: string) {
return path.resolve(__dirname, '../testWorkspace', p)
return path.resolve(__dirname, '../activeWorkspace', p)
}
export function getTestDocUri(p: string) {
return vscode.Uri.file(getTestDocPath(p))
Expand All @@ -68,8 +112,12 @@ async function processFileChange() {
// Wait for the file system watcher to pick up the change
await sleep(1000)

// Wait for the compiler to process the change
await vscode.commands.executeCommand('flix.allJobsFinished')
try {
// Wait for the compiler to process the change
await vscode.commands.executeCommand('flix.allJobsFinished')
} catch {
// Compiler is not running
}

// Wait for the diagnostics to be updated
await sleep(1000)
Expand All @@ -83,11 +131,24 @@ export async function addFile(uri: vscode.Uri, content: string | Uint8Array) {
await processFileChange()
}

/**
* Copies the contents of the given folder `from` to the folder `to`, leaving non-overlapping files intact.
*/
export async function copyDirContents(from: vscode.Uri, to: vscode.Uri) {
const contents = await vscode.workspace.fs.readDirectory(from)
const names = contents.map(([name, _]) => name)

const uris = names.map(name => ({ from: vscode.Uri.joinPath(from, name), to: vscode.Uri.joinPath(to, name) }))

await Promise.allSettled(uris.map(({ from, to }) => copyFile(from, to)))
await processFileChange()
}

/**
* Copy the file from `from` to `to`, and wait for the compiler to process this.
*/
export async function copyFile(from: vscode.Uri, to: vscode.Uri) {
await vscode.workspace.fs.copy(from, to)
await vscode.workspace.fs.copy(from, to, { overwrite: true })
await processFileChange()
}

Expand All @@ -97,7 +158,7 @@ export async function copyFile(from: vscode.Uri, to: vscode.Uri) {
* Throws if the file does not exist.
*/
export async function deleteFile(uri: vscode.Uri) {
await vscode.workspace.fs.delete(uri, { useTrash: true })
await vscode.workspace.fs.delete(uri)
await processFileChange()
}

Expand Down
Binary file removed test/testWorkspace/lib/external/SquareArea.jar
Binary file not shown.
12 changes: 0 additions & 12 deletions test/testWorkspace/lib/external/SquareArea.jar.txt

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,3 @@ description = "test"
version = "0.1.0"
flix = "0.44.0"
authors = ["John Doe <[email protected]>"]

[dependencies]
"github:flix/museum" = "1.4.0"

[mvn-dependencies]
"org.apache.commons:commons-lang3" = "3.12.0"
6 changes: 6 additions & 0 deletions test/testWorkspaces/codeLenses/flix.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[package]
name = "vscode-flix-test"
description = "test"
version = "0.1.0"
flix = "0.44.0"
authors = ["John Doe <[email protected]>"]
13 changes: 13 additions & 0 deletions test/testWorkspaces/codeLenses/src/Area.flix
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@

/// Computes the area of the given shape using
/// pattern matching and basic arithmetic.
def area(s: Shape): Int32 = {
match s {
case Shape.Circle(r) => 3 * r * r
case Shape.Square(w) => w * w
case Shape.Rectangle(h, w) => h * w
}
}

@Test
def testSquareArea(): Bool = Assert.eq(area(Shape.Square(5)), 25)
File renamed without changes.
6 changes: 6 additions & 0 deletions test/testWorkspaces/completions/flix.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[package]
name = "vscode-flix-test"
description = "test"
version = "0.1.0"
flix = "0.44.0"
authors = ["John Doe <[email protected]>"]
6 changes: 6 additions & 0 deletions test/testWorkspaces/diagnostics/flix.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[package]
name = "vscode-flix-test"
description = "test"
version = "0.1.0"
flix = "0.44.0"
authors = ["John Doe <[email protected]>"]
File renamed without changes.
File renamed without changes.
File renamed without changes.
Loading

0 comments on commit 0cea61a

Please sign in to comment.