Skip to content

Commit

Permalink
test: add testing of rename provider
Browse files Browse the repository at this point in the history
  • Loading branch information
sockmaster27 committed Jun 7, 2024
1 parent c82f446 commit 3134ee3
Show file tree
Hide file tree
Showing 7 changed files with 302 additions and 0 deletions.
162 changes: 162 additions & 0 deletions test/src/rename.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
/*
* Copyright 2024 Holger Dal Mogensen
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

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

suite('Rename', () => {
const mainDocUri = getTestDocUri('src/Main.flix')
const areaDocUri = getTestDocUri('src/Area.flix')
const equatableDocUri = getTestDocUri('src/Equatable.flix')
const dateDocUri = getTestDocUri('src/Date.flix')
const recordsDocUri = getTestDocUri('src/Records.flix')

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

test('Renaming empty line should fail', async () => {
await open(mainDocUri)
const position = new vscode.Position(0, 0)
const newName = 'NewName'
assert.rejects(async () => {
await vscode.commands.executeCommand<vscode.WorkspaceEdit>(
'vscode.executeDocumentRenameProvider',
mainDocUri,
position,
newName,
)
})
})

async function testRename(
uri: vscode.Uri,
position: vscode.Position,
expectedRanges: [vscode.Uri, vscode.Range[]][],
) {
await open(uri)
const newName = 'NewName'
const r = await vscode.commands.executeCommand<vscode.WorkspaceEdit>(
'vscode.executeDocumentRenameProvider',
uri,
position,
newName,
)

const entries = r.entries()
for (const [_uri, edits] of entries) {
for (const edit of edits) {
assert.strictEqual(edit.newText, newName)
}
}

const actualRangesString: [string, vscode.Range[]][] = entries.map(([uri, edit]) => [
uri.toString(),
edit.map(r => r.range),
])
const expectedRangesString = expectedRanges.map(([uri, edit]) => [uri.toString(), edit])

assert.deepStrictEqual(actualRangesString.sort(), expectedRangesString.sort())
}

test('Rename Shape.Circle case', async () => {
await testRename(mainDocUri, new vscode.Position(3, 9), [
[mainDocUri, [new vscode.Range(3, 9, 3, 15), new vscode.Range(12, 52, 12, 58), new vscode.Range(17, 17, 17, 29)]],
[areaDocUri, [new vscode.Range(5, 13, 5, 25)]],
])
})
test('Rename Shape.Circle case-use', async () => {
await testRename(mainDocUri, new vscode.Position(12, 52), [
[mainDocUri, [new vscode.Range(3, 9, 3, 15), new vscode.Range(12, 52, 12, 58), new vscode.Range(17, 17, 17, 29)]],
[areaDocUri, [new vscode.Range(5, 13, 5, 25)]],
])
})
test('Rename Shape.Circle case-use from pattern match', async () => {
await testRename(mainDocUri, new vscode.Position(17, 23), [
[mainDocUri, [new vscode.Range(3, 9, 3, 15), new vscode.Range(12, 52, 12, 58), new vscode.Range(17, 17, 17, 29)]],
[areaDocUri, [new vscode.Range(5, 13, 5, 25)]],
])
})

test('Rename area function', async () => {
await testRename(areaDocUri, new vscode.Position(3, 4), [
[areaDocUri, [new vscode.Range(3, 4, 3, 8), new vscode.Range(12, 39, 12, 43)]],
[mainDocUri, [new vscode.Range(10, 12, 10, 16)]],
])
})
test('Rename area function-use', async () => {
await testRename(areaDocUri, new vscode.Position(12, 39), [
[areaDocUri, [new vscode.Range(3, 4, 3, 8), new vscode.Range(12, 39, 12, 43)]],
[mainDocUri, [new vscode.Range(10, 12, 10, 16)]],
])
})

test('Rename Day type alias', async () => {
await testRename(dateDocUri, new vscode.Position(18, 11), [
[dateDocUri, [new vscode.Range(18, 11, 18, 14), new vscode.Range(21, 23, 21, 26)]],
])
})

test('Rename function parameter', async () => {
await testRename(equatableDocUri, new vscode.Position(6, 19), [
[equatableDocUri, [new vscode.Range(6, 19, 6, 20), new vscode.Range(7, 15, 7, 16)]],
])
})
test('Rename function parameter-use', async () => {
await testRename(equatableDocUri, new vscode.Position(7, 15), [
[equatableDocUri, [new vscode.Range(6, 19, 6, 20), new vscode.Range(7, 15, 7, 16)]],
])
})

test('Rename match-extracted variable', async () => {
await testRename(equatableDocUri, new vscode.Position(9, 23), [
[equatableDocUri, [new vscode.Range(9, 23, 9, 25), new vscode.Range(9, 58, 9, 60)]],
])
})
test('Rename match-extracted variable-use', async () => {
await testRename(equatableDocUri, new vscode.Position(9, 58), [
[equatableDocUri, [new vscode.Range(9, 23, 9, 25), new vscode.Range(9, 58, 9, 60)]],
])
})

test('Rename let-bound variable', async () => {
await testRename(equatableDocUri, new vscode.Position(20, 8), [
[equatableDocUri, [new vscode.Range(20, 8, 20, 13), new vscode.Range(22, 21, 22, 26)]],
])
})
test('Rename let-bound variable-use', async () => {
await testRename(equatableDocUri, new vscode.Position(22, 21), [
[equatableDocUri, [new vscode.Range(20, 8, 20, 13), new vscode.Range(22, 21, 22, 26)]],
])
})

test('Rename record label', async () => {
await testRename(recordsDocUri, new vscode.Position(3, 6), [
[
recordsDocUri,
[
new vscode.Range(2, 13, 2, 14),
new vscode.Range(2, 48, 2, 49),
new vscode.Range(3, 6, 3, 7),
new vscode.Range(13, 14, 13, 15),
new vscode.Range(15, 7, 15, 8),
new vscode.Range(15, 14, 15, 15),
],
],
])
})
})
6 changes: 6 additions & 0 deletions test/testWorkspaces/rename/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 <john@example.com>"]
13 changes: 13 additions & 0 deletions test/testWorkspaces/rename/src/Area.flix
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Blank line
/// 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)
38 changes: 38 additions & 0 deletions test/testWorkspaces/rename/src/Date.flix
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// Blank line
/// We derive the traits Eq, Order, and ToString for the enum Month
enum Month with Eq, Order, ToString {
case January
case February
case March
case April
case May
case June
case July
case August
case September
case October
case November
case December
}

type alias Year = Int32
type alias Day = Int32

/// The Date type derives the traits Eq and Order
enum Date(Year, Month, Day) with Eq, Order

/// We implement our own instance of ToString for Date
/// since we don't want the default "Date(1948, December, 10)"
instance ToString[Date] {
pub def toString(x: Date): String =
let Date.Date(y, m, d) = x;
"${d} ${m}, ${y}"
}

/// Thanks to the Eq and Order traits, we can easily compare dates.
def earlierDate(d1: Date, d2: Date): Date = Order.min(d1, d2)

/// Thanks to the ToString trait, we can easily convert dates to strings.
def printDate(d: Date): Unit \ IO =
let message = "The date is ${d}!";
println(message)
45 changes: 45 additions & 0 deletions test/testWorkspaces/rename/src/Equatable.flix
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Blank line
trait Equatable[t] {
pub def equals(x: t, y: t): Bool
}

instance Equatable[Option[t]] with Equatable[t] {
pub def equals(x: Option[t], y: Option[t]): Bool =
match (x, y) {
case (None, None) => true
case (Some(v1), Some(v2)) => Equatable.equals(v1, v2)
case _ => false
}
}

instance Equatable[Int32] {
pub def equals(x: Int32, y: Int32): Bool = x == y
}

@Test
def testOptionEquatable01(): Bool = {
let first = Some(1);
let second = Some(1);
Equatable.equals(first, second)
}

@Test
def testOptionEquatable02(): Bool = {
let first: Option[Int32] = None;
let second: Option[Int32] = None;
Equatable.equals(first, second)
}

@Test
def testOptionEquatable03(): Bool = {
let first = Some(1);
let second: Option[Int32] = None;
not Equatable.equals(first, second)
}

@Test
def testOptionEquatable04(): Bool = {
let first = Some(1);
let second = Some(2);
not Equatable.equals(first, second)
}
22 changes: 22 additions & 0 deletions test/testWorkspaces/rename/src/Main.flix
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Blank line
/// An algebraic data type for shapes.
enum Shape {
case Circle(Int32), // circle radius
case Square(Int32), // side length
case Rectangle(Int32, Int32) // height and width
}

/// Computes the area of a 2 by 4.
def main(): Unit \ IO =
println(area(Shape.Rectangle(2, 4)))

def f(): Shape \ IO = println("Hello World"); Shape.Circle(5)

instance ToString[Shape] {
pub def toString(s: Shape): String =
match s {
case Shape.Circle(r) => "Circle(${r})"
case Shape.Square(w) => "Square(${w})"
case Shape.Rectangle(h, w) => "Rectangle(${h}, ${w})"
}
}
16 changes: 16 additions & 0 deletions test/testWorkspaces/rename/src/Records.flix
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Blank line
/// Returns the record `r` with a new value of its `x` label.
def setX(r: {x = Int32, y = Int32}, v: Int32): {x = Int32, y = Int32} =
{ x = v | r }

/// Returns the record `r` with a new value of its `y` label.
/// Preserves (retains) all other labels polymorphically.
def setY(r: {y = Int32 | a}, v: Int32): {y = Int32 | a} =
{ y = v | r }


@Test
def testRecords(): Bool =
let r1 = {x = 1, y = 2};
let r2 = setX(r1, 3);
r1.x + r2.x == 4

0 comments on commit 3134ee3

Please sign in to comment.