More robust system for testing compilation errors
This commit is contained in:
10
src/kiss/EType.hx
Normal file
10
src/kiss/EType.hx
Normal file
@@ -0,0 +1,10 @@
|
||||
package kiss;
|
||||
|
||||
enum EType {
|
||||
EStream(message:String);
|
||||
EKiss(message:String);
|
||||
EUnmatchedBracket(type:String);
|
||||
EException(message:String);
|
||||
EExpected(e:EType);
|
||||
EUnexpected(e:Dynamic);
|
||||
}
|
145
src/kiss/Kiss.hx
145
src/kiss/Kiss.hx
@@ -17,7 +17,9 @@ import kiss.Macros;
|
||||
import kiss.KissError;
|
||||
import kiss.cloner.Cloner;
|
||||
import tink.syntaxhub.*;
|
||||
import tink.macro.Exprs;
|
||||
import haxe.ds.Either;
|
||||
import kiss.EType;
|
||||
|
||||
using kiss.Kiss;
|
||||
using kiss.Helpers;
|
||||
@@ -218,29 +220,73 @@ class Kiss {
|
||||
return k;
|
||||
}
|
||||
|
||||
public static function _try<T>(operation:() -> T):Null<T> {
|
||||
public static function _try<T>(operation:() -> T, ?expectedError:EType):Null<T> {
|
||||
#if !macrotest
|
||||
try {
|
||||
#end
|
||||
return operation();
|
||||
#if !macrotest
|
||||
} catch (err:StreamError) {
|
||||
Sys.stderr().writeString(err + "\n");
|
||||
Sys.exit(1);
|
||||
return null;
|
||||
function printErr() {
|
||||
Sys.stderr().writeString(err + "\n");
|
||||
}
|
||||
switch (expectedError) {
|
||||
case EStream(message) if (message == err.message):
|
||||
throw EExpected(expectedError);
|
||||
case null:
|
||||
printErr();
|
||||
Sys.exit(1);
|
||||
return null;
|
||||
default:
|
||||
printErr();
|
||||
throw EUnexpected(err);
|
||||
}
|
||||
} catch (err:KissError) {
|
||||
Sys.stderr().writeString(err + "\n");
|
||||
Sys.exit(1);
|
||||
return null;
|
||||
function printErr() {
|
||||
Sys.stderr().writeString(err + "\n");
|
||||
}
|
||||
switch (expectedError) {
|
||||
case EKiss(message) if (message == err.message):
|
||||
throw EExpected(expectedError);
|
||||
case null:
|
||||
printErr();
|
||||
Sys.exit(1);
|
||||
return null;
|
||||
default:
|
||||
printErr();
|
||||
throw EUnexpected(err);
|
||||
}
|
||||
} catch (err:UnmatchedBracketSignal) {
|
||||
Sys.stderr().writeString(Stream.toPrint(err.position) + ': Unmatched ${err.type}\n');
|
||||
Sys.exit(1);
|
||||
return null;
|
||||
function printErr() {
|
||||
Sys.stderr().writeString(Stream.toPrint(err.position) + ': Unmatched ${err.type}\n');
|
||||
}
|
||||
switch (expectedError) {
|
||||
case EUnmatchedBracket(type) if (type == err.type):
|
||||
throw EExpected(expectedError);
|
||||
case null:
|
||||
printErr();
|
||||
Sys.exit(1);
|
||||
return null;
|
||||
default:
|
||||
printErr();
|
||||
throw EUnexpected(err);
|
||||
}
|
||||
} catch (err:Exception) {
|
||||
Sys.stderr().writeString("Error: " + err.message + "\n");
|
||||
Sys.stderr().writeString(err.stack.toString() + "\n");
|
||||
Sys.exit(1);
|
||||
return null;
|
||||
function printErr() {
|
||||
Sys.stderr().writeString("Error: " + err.message + "\n");
|
||||
Sys.stderr().writeString(err.stack.toString() + "\n");
|
||||
}
|
||||
switch (expectedError) {
|
||||
case EException(message) if (message == err.message):
|
||||
throw EExpected(expectedError);
|
||||
case null:
|
||||
printErr();
|
||||
Sys.exit(1);
|
||||
return null;
|
||||
default:
|
||||
printErr();
|
||||
throw EUnexpected(err);
|
||||
}
|
||||
}
|
||||
#end
|
||||
}
|
||||
@@ -297,10 +343,77 @@ class Kiss {
|
||||
}
|
||||
}
|
||||
|
||||
// This is only for testing:
|
||||
public static function buildExpectingError(expectedError:ExprOf<EType>, ?kissFile:String, ?k:KissState, useClassFields = true, ?context:FrontendContext):Array<Field> {
|
||||
var buildFields = Context.getBuildFields();
|
||||
var hasTestExpectedError = false;
|
||||
for (field in buildFields) {
|
||||
switch (field) {
|
||||
case {
|
||||
name: "testExpectedError",
|
||||
kind: FFun({
|
||||
params: [],
|
||||
expr: {
|
||||
expr: EBlock([{expr: ECall({expr: EConst(CIdent("_testExpectedError"))}, [])}])
|
||||
}
|
||||
})
|
||||
}:
|
||||
hasTestExpectedError = true;
|
||||
default:
|
||||
}
|
||||
}
|
||||
if (!hasTestExpectedError) {
|
||||
throw "When building with Kiss.buildExpectingError(), you must add this Haxe function: " +
|
||||
"function testExpectedError() { _testExpectedError(); }";
|
||||
}
|
||||
|
||||
var expectedError = Exprs.eval(expectedError);
|
||||
var s = Std.string(expectedError);
|
||||
|
||||
try {
|
||||
build(kissFile, k, useClassFields, context, expectedError);
|
||||
|
||||
// Build success, which is bad:
|
||||
buildFields.push({
|
||||
pos: Context.currentPos(),
|
||||
name: "_testExpectedError",
|
||||
kind: FFun({
|
||||
args: [],
|
||||
expr: macro utest.Assert.fail('Build succeeded when an error was expected: ' + $v{s})
|
||||
})
|
||||
});
|
||||
} catch (e:EType) {
|
||||
switch (e) {
|
||||
case EExpected(e):
|
||||
buildFields.push({
|
||||
pos: Context.currentPos(),
|
||||
name: "_testExpectedError",
|
||||
kind: FFun({
|
||||
args: [],
|
||||
expr: macro utest.Assert.pass()
|
||||
})
|
||||
});
|
||||
case EUnexpected(e):
|
||||
buildFields.push({
|
||||
pos: Context.currentPos(),
|
||||
name: "_testExpectedError",
|
||||
kind: FFun({
|
||||
args: [],
|
||||
expr: macro utest.Assert.fail('Build failed in an unexpected way. Expected: ' + $v{s})
|
||||
})
|
||||
});
|
||||
default:
|
||||
throw "unexpected error is neither expected nor unexpected ¯\\_(ツ)_/¯";
|
||||
}
|
||||
}
|
||||
|
||||
return buildFields;
|
||||
}
|
||||
|
||||
/**
|
||||
Build macro: add fields to a class from a corresponding .kiss file
|
||||
**/
|
||||
public static function build(?kissFile:String, ?k:KissState, useClassFields = true, ?context:FrontendContext):Array<Field> {
|
||||
public static function build(?kissFile:String, ?k:KissState, useClassFields = true, ?context:FrontendContext, ?expectedError:EType):Array<Field> {
|
||||
|
||||
var classPath = Context.getPosInfos(Context.currentPos()).file;
|
||||
// (load... ) relative to the original file
|
||||
@@ -364,7 +477,7 @@ class Kiss {
|
||||
|
||||
#end
|
||||
k.fieldList;
|
||||
});
|
||||
}, expectedError);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@@ -15,7 +15,7 @@ enum ErrorType {
|
||||
// Internal Kiss errors
|
||||
class KissError {
|
||||
var exps:List<ReaderExp>;
|
||||
var message:String;
|
||||
public var message(default, null):String;
|
||||
|
||||
public function new(exps:Array<ReaderExp>, message:String) {
|
||||
this.exps = exps;
|
||||
|
@@ -18,7 +18,7 @@ typedef Position = {
|
||||
|
||||
class StreamError {
|
||||
var position:Position;
|
||||
var message:String;
|
||||
public var message(default,null):String;
|
||||
|
||||
public function new(position:Position, message:String) {
|
||||
this.position = position;
|
||||
@@ -54,7 +54,7 @@ class Stream {
|
||||
var file = "string";
|
||||
if (position != null) {
|
||||
file = position.file;
|
||||
}
|
||||
}
|
||||
var s = new Stream(file, content);
|
||||
if (position != null) {
|
||||
s.line = position.line;
|
||||
@@ -140,7 +140,7 @@ class Stream {
|
||||
startOfLine = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function record() {
|
||||
recording += content.substr(0, count);
|
||||
}
|
||||
@@ -154,7 +154,7 @@ class Stream {
|
||||
record();
|
||||
default:
|
||||
}
|
||||
|
||||
|
||||
content = content.substr(count);
|
||||
}
|
||||
|
||||
@@ -389,7 +389,7 @@ class Stream {
|
||||
|
||||
private var recordingType:StreamRecordType = Neither;
|
||||
private var recording = "";
|
||||
|
||||
|
||||
public function recordTransaction(type:StreamRecordType = Both, transaction:Void->Void) {
|
||||
if (type == Neither) {
|
||||
error(this, "Tried to start recording a transaction that would always return an empty string");
|
||||
|
12
src/test/cases/UnmatchedBracketTestCase.hx
Normal file
12
src/test/cases/UnmatchedBracketTestCase.hx
Normal file
@@ -0,0 +1,12 @@
|
||||
package test.cases;
|
||||
|
||||
import utest.Test;
|
||||
import utest.Assert;
|
||||
import kiss.Prelude;
|
||||
|
||||
@:build(kiss.Kiss.buildExpectingError(kiss.EType.EUnmatchedBracket("}")))
|
||||
class UnmatchedBracketTestCase extends Test {
|
||||
function testExpectedError() {
|
||||
_testExpectedError();
|
||||
}
|
||||
}
|
1
src/test/cases/UnmatchedBracketTestCase.kiss
Normal file
1
src/test/cases/UnmatchedBracketTestCase.kiss
Normal file
@@ -0,0 +1 @@
|
||||
}
|
Reference in New Issue
Block a user