Last active
July 3, 2016 16:26
-
-
Save bvenners/ebc3d1ad1e0be5a3f36f3d1c7b302fbf to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Proposed ehancement to ScalaTest to surface more info about compiler errors | |
// Existing syntax | |
// Assertions: | |
assertDoesNotCompile("val i: String = 1") // Expects either a type or parse error | |
assertTypeError("val i: String = 1") // Expects just a type error (not a parse error) | |
assertCompiles("val i: Int = 1") // Expects no error during compilation | |
// Matchers: | |
"val i: String = 1" shouldNot compile // Expects either a type or parse error | |
"val i: String = 1" shouldNot typeCheck // Expects either a type error | |
"val i: String = 1" should compile // Expects no error during compilation | |
// For assertions, I'd like to make something symetric with assertThrows (new in 3.0, which | |
// returns Succeeded) and intercept (which returns the caught exception for further inspection) | |
// I could either do this: | |
val typeError = interceptTypeError("val i: String = 1") | |
assert(typeError.message.indexOf("type mismatch") >= 0) | |
// Which would require I add this kind of ADT to the library, which would | |
// surface all the info. Not sure it is worth it if people only need in | |
// practice to check error messages. | |
sealed abstract class CompilerError extends Product with Serializable { | |
val message: String | |
val fileName: String | |
val filePathName: String | |
val lineNumber: Int | |
val columnNumber: Int | |
val point: Int | |
} | |
case class TypeError( | |
message: String, | |
fileName: String, | |
filePathName: String, | |
lineNumber: Int, | |
columnNumber: Int, | |
point: Int | |
) extends CompilerError | |
case class ParseError( | |
message: String, | |
fileName: String, | |
filePathName: String, | |
lineNumber: Int, | |
columnNumber: Int, | |
point: Int | |
) extends CompilerError | |
// Otherwise, we could do this: | |
val errMsg: String = interceptTypeErrorMessage("val i: String = 1") | |
assert(errMsg.indexOf("type mismatch") >= 0) | |
// Maybe intercept is the wrong word, though an exception is actually | |
// being caught at compile time. So I think intercept is probably the | |
// best choice. It means "catch and return (for a touchdown, if possible)" | |
// For now I'll flesh out the syntax for surfacing all the info. | |
// Assertions | |
assertParseError("val i; Int = 1") // Could add this | |
interceptParseError("val i; Int = 1") // Returns a ParseError instance for further inspection | |
assertTypeError("val i: String = 1") // This exists | |
interceptTypeError("val i: String = 1") // Returns a TypeError instance for further inspection | |
// Could stop there, or add | |
assertCompilerError("val i: String = 1") // Could deprecate assertDoesNotCompile in favor of this name, for consistency with: | |
interceptCompilerError("val i: String = 1") // Which returns an instance of CompilerError | |
// Could also just deprecate assertDoesNotCompile and make people pick between assertTypeError | |
// and assertParseError. But I think assertCompilerError balances assertCompiles nicely. | |
// Matchers: | |
theParseError producedBy "val i; Int = 1" // Returns a ParseError instance for further inspection | |
theTypeError producedBy "val i: String = 1" // Returns a TypeError instance for further inspection | |
theCompilerError producedBy "val i: String = 1" // Returns a CompilerError instance for further inspection | |
// The above is similar to the [IllegalArgumentException] thrownBy { ... } syntax for exceptions | |
// I.e. you could do things like | |
theTypeError producedBy """NonEmptyString("")""" should have message "Cannot create a NonEmptyString with the empty string" | |
// Or: | |
theTypeError.producedBy("""NonEmptyString("")""").message should include regex ".*Cannot.*" | |
// which is similar to how you can inspect an exception for an error message | |
// Just had a thought that we could also potentially add an implicit on String that supports this | |
// syntax: | |
assert("val s: String == 33".typeErrorMessageIncludes("type mismatch")) | |
// On third thought, since I don't like implicits, maybe: | |
assert(typeErrorMessageIncludes("val s: String == 33", "type mismatch")) | |
// Or even: | |
assertTypeErrorMessageIncludes("val s: String == 33", "type mismatch") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment