Skip to content

Instantly share code, notes, and snippets.

@olafurpg
Created January 10, 2019 15:54
Show Gist options
  • Save olafurpg/eabbf6c7775be0556ba5f2b2c55a295e to your computer and use it in GitHub Desktop.
Save olafurpg/eabbf6c7775be0556ba5f2b2c55a295e to your computer and use it in GitHub Desktop.
package tests
import scala.concurrent.Future
object SyntaxErrorSlowSuite extends BaseSlowSuite("syntax-error") {
type Assert = (String => String, String)
def check(
name: String,
code: String,
asserts: Assert*
): Unit = {
testAsync(name) {
def runAsserts(as: List[Assert]): Future[Unit] = as match {
case Nil => Future.successful(())
case (fn, expected) :: tail =>
server
.didChange("a/src/main/scala/A.scala")(fn)
.flatMap { _ =>
assertNoDiff(client.workspaceDiagnostics, expected)
runAsserts(tail)
}
}
for {
_ <- server.initialize(
s"""
|/metals.json
|{"a": {}}
|/a/src/main/scala/A.scala
|""".stripMargin + code
)
_ <- server.didOpen("a/src/main/scala/A.scala")
_ = assertNotEmpty(client.workspaceDiagnostics)
_ <- runAsserts(asserts.toList)
} yield ()
}
}
testAsync("basic") {
for {
_ <- server.initialize(
"""|
|/metals.json
|{"a": {}}
|/project/plugins.sbt
|lazy lazy val x = 1
|/Main.scala
|object object A
|""".stripMargin
)
_ <- server.didOpen("Main.scala")
_ <- server.didOpen("project/plugins.sbt")
_ = assertNoDiff(
client.workspaceDiagnostics,
"""
|Main.scala:1:8: error: identifier expected but object found
|object object A
| ^^^^^^
|project/plugins.sbt:1:6: error: repeated modifier
|lazy lazy val x = 1
| ^^^^
|""".stripMargin
)
_ <- server.didClose("Main.scala")
_ <- server.didClose("project/plugins.sbt")
_ = assertNoDiff(client.workspaceDiagnostics, "")
_ <- server.didOpen("Main.scala")
_ <- server.didOpen("project/plugins.sbt")
_ <- server.didSave("Main.scala")(_ => "object A\n")
_ = assertNoDiff(
client.workspaceDiagnostics,
"""
|project/plugins.sbt:1:6: error: repeated modifier
|lazy lazy val x = 1
| ^^^^
|""".stripMargin
)
_ <- server.didSave("project/plugins.sbt")(_ => "lazy val x = 1\n")
_ = assertNoDiff(client.workspaceDiagnostics, "")
} yield ()
}
testAsync("mix1") {
for {
_ <- server.initialize(
"""|
|/metals.json
|{"a": {}}
|/a/src/main/scala/Main.scala
|object object A
|object object B
|""".stripMargin
)
_ <- server.didOpen("a/src/main/scala/Main.scala")
_ = assertNoDiff(
client.workspaceDiagnostics,
"""|a/src/main/scala/Main.scala:1:8: error: identifier expected but 'object' found.
|object object A
| ^^^^^^
|a/src/main/scala/Main.scala:2:8: error: identifier expected but 'object' found.
|object object B
| ^^^^^^
|""".stripMargin
)
_ <- server.didChange("a/src/main/scala/Main.scala")(t => "\n" + t)
_ = assertNoDiff(
client.workspaceDiagnostics,
"""|a/src/main/scala/Main.scala:2:8: error: identifier expected but 'object' found.
|object object A
| ^^^^^^
|a/src/main/scala/Main.scala:3:8: error: identifier expected but 'object' found.
|object object B
| ^^^^^^
|""".stripMargin
)
} yield ()
}
testAsync("mix2") {
for {
_ <- server.initialize(
"""|
|/metals.json
|{"a": {}}
|/a/src/main/scala/Main.scala
|object Main {
| val b: Int = ""
|}
|""".stripMargin
)
_ <- server.didOpen("a/src/main/scala/Main.scala")
_ <- server.didChange("a/src/main/scala/Main.scala")(
_.replaceAllLiterally("val b", "val\n val b")
)
_ <- server.didChange("a/src/main/scala/Main.scala")(
_.replaceAllLiterally("val\n", "val \n")
)
_ <- server.didChange("a/src/main/scala/Main.scala")(
_.replaceAllLiterally("val \n", "")
)
_ = assertNoDiff(
client.workspaceDiagnostics,
"""|a/src/main/scala/Main.scala:2:18: error: type mismatch;
| found : String("")
| required: Int
| val b: Int = ""
| ^^
|""".stripMargin
)
} yield ()
}
testAsync("no-build-tool") {
for {
_ <- server.initialize(
"""
|/A.scala
|object A { val x = }
|""".stripMargin,
expectError = true
)
_ <- server.didOpen("A.scala")
_ = assertNoDiff(
client.workspaceDiagnostics,
"""|A.scala:1:20: error: illegal start of simple expression
|object A { val x = }
| ^
|""".stripMargin
)
} yield ()
}
testAsync("unclosed-literal") {
for {
_ <- server.initialize(
"""
|/metals.json
|{"a": {}}
|/a/src/main/scala/A.scala
|object A {
| val x: Int = ""
|}
|""".stripMargin
)
_ <- server.didOpen("a/src/main/scala/A.scala")
typeMismatch = {
"""|a/src/main/scala/A.scala:2:16: error: type mismatch;
| found : String("")
| required: Int
| val x: Int = ""
| ^^
|""".stripMargin
}
_ = assertNoDiff(client.workspaceDiagnostics, typeMismatch)
_ <- server.didChange("a/src/main/scala/A.scala")(
_.replaceAllLiterally("\"\"", "\"")
)
// assert that a tokenization error results in a single diagnostic, hides type errors.
_ = assertNoDiff(
client.workspaceDiagnostics,
"""|a/src/main/scala/A.scala:2:16: error: unclosed string literal
| val x: Int = "
| ^
|""".stripMargin
)
_ <- server.didChange("a/src/main/scala/A.scala")(
_.replaceAllLiterally("\"", "\"\"\n // close")
)
// assert that once the tokenization error is fixed, the type error reappears.
_ = assertNoDiff(client.workspaceDiagnostics, typeMismatch)
} yield ()
}
check(
"sticky",
"""|object A {
| "".lengthCompare("1".substring(0))
|}
|""".stripMargin,
(
_.replaceAllLiterally("\"1\".substring(0)", ""),
"""|a/src/main/scala/A.scala:2:19: error: type mismatch;
| found : String
| required: Int
| "".lengthCompare()
| ^^
|""".stripMargin
),
(
_.replaceAllLiterally(".lengthCompare()", "."),
"""|a/src/main/scala/A.scala:2:5: error: type mismatch;
| found : String
| required: Int
| "".
| ^
|a/src/main/scala/A.scala:3:1: error: identifier expected but } found
|}
|^
|""".stripMargin
)
)
check(
"stable1",
"""|object A {
| "".lengthCompare()
|}
|""".stripMargin,
(
_.replaceAllLiterally("object A", "object B"),
"""|a/src/main/scala/A.scala:2:19: error: not enough arguments for method lengthCompare: (len: Int)Int.
|Unspecified value parameter len.
| "".lengthCompare()
| ^^
|""".stripMargin
)
)
check(
"stable2",
"""|object A {
| val x: Int = ""
|}
|""".stripMargin,
(
_.replaceAllLiterally("\"\"", "\"a\" // comment"),
"""|a/src/main/scala/A.scala:2:16: error: type mismatch;
| found : String("")
| required: Int
| val x: Int = "a" // comment
| ^
|""".stripMargin
)
)
check(
"stable3",
"""|object A {
| val x: Int = "a" + "b"
|}
|""".stripMargin,
(
_.replaceAllLiterally("\"b\"", "\"c\""),
"""|a/src/main/scala/A.scala:2:20: error: type mismatch;
| found : String("ab")
| required: Int
| val x: Int = "a" + "c"
| ^^^^^
|""".stripMargin
)
)
check(
"strip",
"""|object A {
| val x: Int = "a" + "b"
|}
|""".stripMargin,
(
_.replaceAllLiterally("t = \"a\" + \"b\"", ""),
"""|a/src/main/scala/A.scala:2:11: error: type mismatch;
| found : String("ab")
| required: Int
| val x: In
| ^
|""".stripMargin
)
)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment