storing full sourcemap in token, refactored error reporting
This commit is contained in:
@@ -41,15 +41,17 @@ func testEnvironment() {
|
||||
}
|
||||
|
||||
func expectedSyntaxError(token: String, template: Template, description: String) -> TemplateSyntaxError {
|
||||
let token = Token.block(value: token, at: template.templateString.range(of: token)!)
|
||||
return TemplateSyntaxError(reason: description, token: token, template: template, parentError: nil)
|
||||
let range = template.templateString.range(of: token)!
|
||||
let rangeLine = template.templateString.rangeLine(range)
|
||||
let sourceMap = SourceMap(filename: template.name, line: rangeLine)
|
||||
let token = Token.block(value: token, at: sourceMap)
|
||||
return TemplateSyntaxError(reason: description, token: token, stackTrace: [])
|
||||
}
|
||||
|
||||
func expectError(reason: String, token: String) throws {
|
||||
let expectedError = expectedSyntaxError(token: token, template: template, description: reason)
|
||||
|
||||
let error = try expect(environment.render(template: template, context: ["names": ["Bob", "Alice"], "name": "Bob"]))
|
||||
.toThrow(expectedError)
|
||||
let error = try expect(environment.render(template: template, context: ["names": ["Bob", "Alice"], "name": "Bob"])).toThrow() as TemplateSyntaxError
|
||||
try expect(environment.errorReporter.renderError(error)) == environment.errorReporter.renderError(expectedError)
|
||||
}
|
||||
|
||||
@@ -200,10 +202,10 @@ func testEnvironment() {
|
||||
|
||||
func expectError(reason: String, token: String, includedToken: String) throws {
|
||||
var expectedError = expectedSyntaxError(token: token, template: template, description: reason)
|
||||
expectedError.parentError = expectedSyntaxError(token: includedToken, template: includedTemplate, description: reason)
|
||||
expectedError.stackTrace = [expectedSyntaxError(token: includedToken, template: includedTemplate, description: reason).token!]
|
||||
|
||||
let error = try expect(environment.render(template: template, context: ["target": "World"]))
|
||||
.toThrow(expectedError)
|
||||
.toThrow() as TemplateSyntaxError
|
||||
try expect(environment.errorReporter.renderError(error)) == environment.errorReporter.renderError(expectedError)
|
||||
}
|
||||
|
||||
@@ -249,11 +251,10 @@ func testEnvironment() {
|
||||
func expectError(reason: String, childToken: String, baseToken: String?) throws {
|
||||
var expectedError = expectedSyntaxError(token: childToken, template: childTemplate, description: reason)
|
||||
if let baseToken = baseToken {
|
||||
expectedError.parentError = expectedSyntaxError(token: baseToken, template: baseTemplate, description: reason)
|
||||
expectedError.stackTrace = [expectedSyntaxError(token: baseToken, template: baseTemplate, description: reason).token!]
|
||||
}
|
||||
|
||||
let error = try expect(environment.render(template: childTemplate, context: ["target": "World"]))
|
||||
.toThrow(expectedError)
|
||||
.toThrow() as TemplateSyntaxError
|
||||
try expect(environment.errorReporter.renderError(error)) == environment.errorReporter.renderError(expectedError)
|
||||
}
|
||||
|
||||
@@ -312,7 +313,7 @@ func testEnvironment() {
|
||||
|
||||
private extension Expectation {
|
||||
@discardableResult
|
||||
func toThrow<T: Error & Equatable>(_ error: T) throws -> T {
|
||||
func toThrow<T: Error>() throws -> T {
|
||||
var thrownError: Error? = nil
|
||||
|
||||
do {
|
||||
@@ -323,12 +324,9 @@ private extension Expectation {
|
||||
|
||||
if let thrownError = thrownError {
|
||||
if let thrownError = thrownError as? T {
|
||||
if error != thrownError {
|
||||
throw failure("\(thrownError) is not \(error)")
|
||||
}
|
||||
return thrownError
|
||||
} else {
|
||||
throw failure("\(thrownError) is not \(error)")
|
||||
throw failure("\(thrownError) is not \(T.self)")
|
||||
}
|
||||
} else {
|
||||
throw failure("expression did not throw an error")
|
||||
|
||||
@@ -62,7 +62,7 @@ func testFilter() {
|
||||
}
|
||||
|
||||
let context = Context(dictionary: context, environment: Environment(extensions: [repeatExtension]))
|
||||
try expect(try template.render(context)).toThrow(TemplateSyntaxError("No Repeat"))
|
||||
try expect(try template.render(context)).toThrow(TemplateSyntaxError(reason: "No Repeat", token: template.tokens.first))
|
||||
}
|
||||
|
||||
$0.it("allows you to override a default filter") {
|
||||
@@ -91,7 +91,7 @@ func testFilter() {
|
||||
|
||||
|
||||
describe("capitalize filter") {
|
||||
let template = Template(templateString: "{{ name|capitalize }}")
|
||||
let template = Template(templateString: "{{ name|capitalize }}")
|
||||
|
||||
$0.it("capitalizes a string") {
|
||||
let result = try template.render(Context(dictionary: ["name": "kyle"]))
|
||||
|
||||
@@ -169,11 +169,9 @@ func testForNode() {
|
||||
}
|
||||
|
||||
$0.it("handles invalid input") {
|
||||
let tokens: [Token] = [
|
||||
.block(value: "for i", at: .unknown),
|
||||
]
|
||||
let tokens: [Token] = [.block(value: "for i", at: .unknown)]
|
||||
let parser = TokenParser(tokens: tokens, environment: Environment())
|
||||
let error = TemplateSyntaxError("'for' statements should use the following syntax 'for x in y where condition'.")
|
||||
let error = TemplateSyntaxError(reason: "'for' statements should use the following syntax 'for x in y where condition'.", token: tokens.first)
|
||||
try expect(try parser.parse()).toThrow(error)
|
||||
}
|
||||
|
||||
|
||||
@@ -179,22 +179,18 @@ func testIfNode() {
|
||||
}
|
||||
|
||||
$0.it("throws an error when parsing an if block without an endif") {
|
||||
let tokens: [Token] = [
|
||||
.block(value: "if value", at: .unknown),
|
||||
]
|
||||
let tokens: [Token] = [.block(value: "if value", at: .unknown)]
|
||||
|
||||
let parser = TokenParser(tokens: tokens, environment: Environment())
|
||||
let error = TemplateSyntaxError("`endif` was not found.")
|
||||
let error = TemplateSyntaxError(reason: "`endif` was not found.", token: tokens.first)
|
||||
try expect(try parser.parse()).toThrow(error)
|
||||
}
|
||||
|
||||
$0.it("throws an error when parsing an ifnot without an endif") {
|
||||
let tokens: [Token] = [
|
||||
.block(value: "ifnot value", at: .unknown),
|
||||
]
|
||||
let tokens: [Token] = [.block(value: "ifnot value", at: .unknown)]
|
||||
|
||||
let parser = TokenParser(tokens: tokens, environment: Environment())
|
||||
let error = TemplateSyntaxError("`endif` was not found.")
|
||||
let error = TemplateSyntaxError(reason: "`endif` was not found.", token: tokens.first)
|
||||
try expect(try parser.parse()).toThrow(error)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ func testInclude() {
|
||||
let tokens: [Token] = [ .block(value: "include", at: .unknown) ]
|
||||
let parser = TokenParser(tokens: tokens, environment: Environment())
|
||||
|
||||
let error = TemplateSyntaxError("'include' tag takes one argument, the template file to be included")
|
||||
let error = TemplateSyntaxError(reason: "'include' tag takes one argument, the template file to be included", token: tokens.first)
|
||||
try expect(try parser.parse()).toThrow(error)
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ func testLexer() {
|
||||
let tokens = lexer.tokenize()
|
||||
|
||||
try expect(tokens.count) == 1
|
||||
try expect(tokens.first) == .text(value: "Hello World", at: "Hello World".range)
|
||||
try expect(tokens.first) == .text(value: "Hello World", at: SourceMap(line: ("Hello World", 1, 0)))
|
||||
}
|
||||
|
||||
$0.it("can tokenize a comment") {
|
||||
@@ -17,7 +17,7 @@ func testLexer() {
|
||||
let tokens = lexer.tokenize()
|
||||
|
||||
try expect(tokens.count) == 1
|
||||
try expect(tokens.first) == .comment(value: "Comment", at: "{# Comment #}".range)
|
||||
try expect(tokens.first) == .comment(value: "Comment", at: SourceMap(line: ("{# Comment #}", 1, 3)))
|
||||
}
|
||||
|
||||
$0.it("can tokenize a variable") {
|
||||
@@ -25,7 +25,7 @@ func testLexer() {
|
||||
let tokens = lexer.tokenize()
|
||||
|
||||
try expect(tokens.count) == 1
|
||||
try expect(tokens.first) == .variable(value: "Variable", at: "{{ Variable }}".range)
|
||||
try expect(tokens.first) == .variable(value: "Variable", at: SourceMap(line: ("{{ Variable }}", 1, 3)))
|
||||
}
|
||||
|
||||
$0.it("can tokenize unclosed tag by ignoring it") {
|
||||
@@ -34,18 +34,18 @@ func testLexer() {
|
||||
let tokens = lexer.tokenize()
|
||||
|
||||
try expect(tokens.count) == 1
|
||||
try expect(tokens.first) == .text(value: "", at: "".range)
|
||||
try expect(tokens.first) == .text(value: "", at: SourceMap(line: ("{{ thing", 1, 0)))
|
||||
}
|
||||
|
||||
$0.it("can tokenize a mixture of content") {
|
||||
let templateString = "My name is {{ name }}."
|
||||
let templateString = "My name is {{ myname }}."
|
||||
let lexer = Lexer(templateString: templateString)
|
||||
let tokens = lexer.tokenize()
|
||||
|
||||
try expect(tokens.count) == 3
|
||||
try expect(tokens[0]) == Token.text(value: "My name is ", at: templateString.range(of: "My name is ")!)
|
||||
try expect(tokens[1]) == Token.variable(value: "name", at: templateString.range(of: "{{ name }}")!)
|
||||
try expect(tokens[2]) == Token.text(value: ".", at: templateString.range(of: ".")!)
|
||||
try expect(tokens[0]) == Token.text(value: "My name is ", at: SourceMap(line: templateString.rangeLine(templateString.range(of: "My name is ")!)))
|
||||
try expect(tokens[1]) == Token.variable(value: "myname", at: SourceMap(line: templateString.rangeLine(templateString.range(of: "myname")!)))
|
||||
try expect(tokens[2]) == Token.text(value: ".", at: SourceMap(line: templateString.rangeLine(templateString.range(of: ".")!)))
|
||||
}
|
||||
|
||||
$0.it("can tokenize two variables without being greedy") {
|
||||
@@ -54,8 +54,8 @@ func testLexer() {
|
||||
let tokens = lexer.tokenize()
|
||||
|
||||
try expect(tokens.count) == 2
|
||||
try expect(tokens[0]) == Token.variable(value: "thing", at: templateString.range(of: "{{ thing }}")!)
|
||||
try expect(tokens[1]) == Token.variable(value: "name", at: templateString.range(of: "{{ name }}")!)
|
||||
try expect(tokens[0]) == Token.variable(value: "thing", at: SourceMap(line: templateString.rangeLine(templateString.range(of: "thing")!)))
|
||||
try expect(tokens[1]) == Token.variable(value: "name", at: SourceMap(line: templateString.rangeLine(templateString.range(of: "name")!)))
|
||||
}
|
||||
|
||||
$0.it("can tokenize an unclosed block") {
|
||||
|
||||
@@ -52,11 +52,10 @@ func testTokenParser() {
|
||||
}
|
||||
|
||||
$0.it("errors when parsing an unknown tag") {
|
||||
let parser = TokenParser(tokens: [
|
||||
.block(value: "unknown", at: .unknown),
|
||||
], environment: Environment())
|
||||
let tokens: [Token] = [.block(value: "unknown", at: .unknown)]
|
||||
let parser = TokenParser(tokens: tokens, environment: Environment())
|
||||
|
||||
try expect(try parser.parse()).toThrow(TemplateSyntaxError("Unknown template tag 'unknown'"))
|
||||
try expect(try parser.parse()).toThrow(TemplateSyntaxError(reason: "Unknown template tag 'unknown'", token: tokens.first))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user