Warnings--
This commit is contained in:
@@ -4,35 +4,35 @@ import XCTest
|
||||
|
||||
final class ContextTests: XCTestCase {
|
||||
func testContextSubscripting() {
|
||||
describe("Context Subscripting") {
|
||||
describe("Context Subscripting") { test in
|
||||
var context = Context()
|
||||
$0.before {
|
||||
test.before {
|
||||
context = Context(dictionary: ["name": "Kyle"])
|
||||
}
|
||||
|
||||
$0.it("allows you to get a value via subscripting") {
|
||||
test.it("allows you to get a value via subscripting") {
|
||||
try expect(context["name"] as? String) == "Kyle"
|
||||
}
|
||||
|
||||
$0.it("allows you to set a value via subscripting") {
|
||||
test.it("allows you to set a value via subscripting") {
|
||||
context["name"] = "Katie"
|
||||
|
||||
try expect(context["name"] as? String) == "Katie"
|
||||
}
|
||||
|
||||
$0.it("allows you to remove a value via subscripting") {
|
||||
test.it("allows you to remove a value via subscripting") {
|
||||
context["name"] = nil
|
||||
|
||||
try expect(context["name"]).to.beNil()
|
||||
}
|
||||
|
||||
$0.it("allows you to retrieve a value from a parent") {
|
||||
test.it("allows you to retrieve a value from a parent") {
|
||||
try context.push {
|
||||
try expect(context["name"] as? String) == "Kyle"
|
||||
}
|
||||
}
|
||||
|
||||
$0.it("allows you to override a parent's value") {
|
||||
test.it("allows you to override a parent's value") {
|
||||
try context.push {
|
||||
context["name"] = "Katie"
|
||||
try expect(context["name"] as? String) == "Katie"
|
||||
@@ -42,13 +42,13 @@ final class ContextTests: XCTestCase {
|
||||
}
|
||||
|
||||
func testContextRestoration() {
|
||||
describe("Context Restoration") {
|
||||
describe("Context Restoration") { test in
|
||||
var context = Context()
|
||||
$0.before {
|
||||
test.before {
|
||||
context = Context(dictionary: ["name": "Kyle"])
|
||||
}
|
||||
|
||||
$0.it("allows you to pop to restore previous state") {
|
||||
test.it("allows you to pop to restore previous state") {
|
||||
context.push {
|
||||
context["name"] = "Katie"
|
||||
}
|
||||
@@ -56,7 +56,7 @@ final class ContextTests: XCTestCase {
|
||||
try expect(context["name"] as? String) == "Kyle"
|
||||
}
|
||||
|
||||
$0.it("allows you to remove a parent's value in a level") {
|
||||
test.it("allows you to remove a parent's value in a level") {
|
||||
try context.push {
|
||||
context["name"] = nil
|
||||
try expect(context["name"]).to.beNil()
|
||||
@@ -65,7 +65,7 @@ final class ContextTests: XCTestCase {
|
||||
try expect(context["name"] as? String) == "Kyle"
|
||||
}
|
||||
|
||||
$0.it("allows you to push a dictionary and run a closure then restoring previous state") {
|
||||
test.it("allows you to push a dictionary and run a closure then restoring previous state") {
|
||||
var didRun = false
|
||||
|
||||
try context.push(dictionary: ["name": "Katie"]) {
|
||||
@@ -77,7 +77,7 @@ final class ContextTests: XCTestCase {
|
||||
try expect(context["name"] as? String) == "Kyle"
|
||||
}
|
||||
|
||||
$0.it("allows you to flatten the context contents") {
|
||||
test.it("allows you to flatten the context contents") {
|
||||
try context.push(dictionary: ["test": "abc"]) {
|
||||
let flattened = context.flatten()
|
||||
|
||||
|
||||
125
Tests/StencilTests/EnvironmentBaseAndChildTemplateSpec.swift
Normal file
125
Tests/StencilTests/EnvironmentBaseAndChildTemplateSpec.swift
Normal file
@@ -0,0 +1,125 @@
|
||||
import PathKit
|
||||
import Spectre
|
||||
@testable import Stencil
|
||||
import XCTest
|
||||
|
||||
final class EnvironmentBaseAndChildTemplateTests: XCTestCase {
|
||||
private var environment = Environment(loader: ExampleLoader())
|
||||
private var childTemplate: Template = ""
|
||||
private var baseTemplate: Template = ""
|
||||
|
||||
override func setUp() {
|
||||
super.setUp()
|
||||
|
||||
let path = Path(#file as String) + ".." + "fixtures"
|
||||
let loader = FileSystemLoader(paths: [path])
|
||||
environment = Environment(loader: loader)
|
||||
childTemplate = ""
|
||||
baseTemplate = ""
|
||||
}
|
||||
|
||||
override func tearDown() {
|
||||
super.tearDown()
|
||||
}
|
||||
|
||||
func testSyntaxErrorInBaseTemplate() throws {
|
||||
childTemplate = try environment.loadTemplate(name: "invalid-child-super.html")
|
||||
baseTemplate = try environment.loadTemplate(name: "invalid-base.html")
|
||||
|
||||
try expectError(
|
||||
reason: "Unknown filter 'unknown'. Found similar filters: 'uppercase'.",
|
||||
childToken: "extends \"invalid-base.html\"",
|
||||
baseToken: "target|unknown"
|
||||
)
|
||||
}
|
||||
|
||||
func testRuntimeErrorInBaseTemplate() throws {
|
||||
let filterExtension = Extension()
|
||||
filterExtension.registerFilter("unknown") { (_: Any?) in
|
||||
throw TemplateSyntaxError("filter error")
|
||||
}
|
||||
environment.extensions += [filterExtension]
|
||||
|
||||
childTemplate = try environment.loadTemplate(name: "invalid-child-super.html")
|
||||
baseTemplate = try environment.loadTemplate(name: "invalid-base.html")
|
||||
|
||||
try expectError(
|
||||
reason: "filter error",
|
||||
childToken: "extends \"invalid-base.html\"",
|
||||
baseToken: "target|unknown"
|
||||
)
|
||||
}
|
||||
|
||||
func testSyntaxErrorInChildTemplate() throws {
|
||||
childTemplate = Template(
|
||||
templateString: """
|
||||
{% extends "base.html" %}
|
||||
{% block body %}Child {{ target|unknown }}{% endblock %}
|
||||
""",
|
||||
environment: environment,
|
||||
name: nil
|
||||
)
|
||||
|
||||
try expectError(
|
||||
reason: "Unknown filter 'unknown'. Found similar filters: 'uppercase'.",
|
||||
childToken: "target|unknown",
|
||||
baseToken: nil
|
||||
)
|
||||
}
|
||||
|
||||
func testRuntimeErrorInChildTemplate() throws {
|
||||
let filterExtension = Extension()
|
||||
filterExtension.registerFilter("unknown") { (_: Any?) in
|
||||
throw TemplateSyntaxError("filter error")
|
||||
}
|
||||
environment.extensions += [filterExtension]
|
||||
|
||||
childTemplate = Template(
|
||||
templateString: """
|
||||
{% extends "base.html" %}
|
||||
{% block body %}Child {{ target|unknown }}{% endblock %}
|
||||
""",
|
||||
environment: environment,
|
||||
name: nil
|
||||
)
|
||||
|
||||
try expectError(
|
||||
reason: "filter error",
|
||||
childToken: "target|unknown",
|
||||
baseToken: nil
|
||||
)
|
||||
}
|
||||
|
||||
private func expectError(
|
||||
reason: String,
|
||||
childToken: String,
|
||||
baseToken: String?,
|
||||
file: String = #file,
|
||||
line: Int = #line,
|
||||
function: String = #function
|
||||
) throws {
|
||||
var expectedError = expectedSyntaxError(token: childToken, template: childTemplate, description: reason)
|
||||
if let baseToken = baseToken {
|
||||
expectedError.stackTrace = [
|
||||
expectedSyntaxError(
|
||||
token: baseToken,
|
||||
template: baseTemplate,
|
||||
description: reason
|
||||
).token
|
||||
].compactMap { $0 }
|
||||
}
|
||||
let error = try expect(
|
||||
self.environment.render(template: self.childTemplate, context: ["target": "World"]),
|
||||
file: file,
|
||||
line: line,
|
||||
function: function
|
||||
).toThrow() as TemplateSyntaxError
|
||||
let reporter = SimpleErrorReporter()
|
||||
try expect(
|
||||
reporter.renderError(error),
|
||||
file: file,
|
||||
line: line,
|
||||
function: function
|
||||
) == reporter.renderError(expectedError)
|
||||
}
|
||||
}
|
||||
88
Tests/StencilTests/EnvironmentIncludeTemplateSpec.swift
Normal file
88
Tests/StencilTests/EnvironmentIncludeTemplateSpec.swift
Normal file
@@ -0,0 +1,88 @@
|
||||
import PathKit
|
||||
import Spectre
|
||||
@testable import Stencil
|
||||
import XCTest
|
||||
|
||||
final class EnvironmentIncludeTemplateTests: XCTestCase {
|
||||
private var environment = Environment(loader: ExampleLoader())
|
||||
private var template: Template = ""
|
||||
private var includedTemplate: Template = ""
|
||||
|
||||
override func setUp() {
|
||||
super.setUp()
|
||||
|
||||
let path = Path(#file as String) + ".." + "fixtures"
|
||||
let loader = FileSystemLoader(paths: [path])
|
||||
environment = Environment(loader: loader)
|
||||
template = ""
|
||||
includedTemplate = ""
|
||||
}
|
||||
|
||||
override func tearDown() {
|
||||
super.tearDown()
|
||||
}
|
||||
|
||||
func testSyntaxError() throws {
|
||||
template = Template(templateString: """
|
||||
{% include "invalid-include.html" %}
|
||||
""", environment: environment)
|
||||
includedTemplate = try environment.loadTemplate(name: "invalid-include.html")
|
||||
|
||||
try expectError(
|
||||
reason: "Unknown filter 'unknown'. Found similar filters: 'uppercase'.",
|
||||
token: #"include "invalid-include.html""#,
|
||||
includedToken: "target|unknown"
|
||||
)
|
||||
}
|
||||
|
||||
func testRuntimeError() throws {
|
||||
let filterExtension = Extension()
|
||||
filterExtension.registerFilter("unknown") { (_: Any?) in
|
||||
throw TemplateSyntaxError("filter error")
|
||||
}
|
||||
environment.extensions += [filterExtension]
|
||||
|
||||
template = Template(templateString: """
|
||||
{% include "invalid-include.html" %}
|
||||
""", environment: environment)
|
||||
includedTemplate = try environment.loadTemplate(name: "invalid-include.html")
|
||||
|
||||
try expectError(
|
||||
reason: "filter error",
|
||||
token: "include \"invalid-include.html\"",
|
||||
includedToken: "target|unknown"
|
||||
)
|
||||
}
|
||||
|
||||
private func expectError(
|
||||
reason: String,
|
||||
token: String,
|
||||
includedToken: String,
|
||||
file: String = #file,
|
||||
line: Int = #line,
|
||||
function: String = #function
|
||||
) throws {
|
||||
var expectedError = expectedSyntaxError(token: token, template: template, description: reason)
|
||||
expectedError.stackTrace = [
|
||||
expectedSyntaxError(
|
||||
token: includedToken,
|
||||
template: includedTemplate,
|
||||
description: reason
|
||||
).token
|
||||
].compactMap { $0 }
|
||||
|
||||
let error = try expect(
|
||||
self.environment.render(template: self.template, context: ["target": "World"]),
|
||||
file: file,
|
||||
line: line,
|
||||
function: function
|
||||
).toThrow() as TemplateSyntaxError
|
||||
let reporter = SimpleErrorReporter()
|
||||
try expect(
|
||||
reporter.renderError(error),
|
||||
file: file,
|
||||
line: line,
|
||||
function: function
|
||||
) == reporter.renderError(expectedError)
|
||||
}
|
||||
}
|
||||
@@ -4,8 +4,8 @@ import Spectre
|
||||
import XCTest
|
||||
|
||||
final class EnvironmentTests: XCTestCase {
|
||||
var environment = Environment(loader: ExampleLoader())
|
||||
var template: Template = ""
|
||||
private var environment = Environment(loader: ExampleLoader())
|
||||
private var template: Template = ""
|
||||
|
||||
override func setUp() {
|
||||
super.setUp()
|
||||
@@ -26,6 +26,10 @@ final class EnvironmentTests: XCTestCase {
|
||||
template = ""
|
||||
}
|
||||
|
||||
override func tearDown() {
|
||||
super.tearDown()
|
||||
}
|
||||
|
||||
func testLoading() {
|
||||
it("can load a template from a name") {
|
||||
let template = try self.environment.loadTemplate(name: "example.html")
|
||||
@@ -207,242 +211,11 @@ final class EnvironmentTests: XCTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
final class EnvironmentIncludeTemplateTests: XCTestCase {
|
||||
var environment = Environment(loader: ExampleLoader())
|
||||
var template: Template = ""
|
||||
var includedTemplate: Template = ""
|
||||
|
||||
override func setUp() {
|
||||
super.setUp()
|
||||
|
||||
let path = Path(#file as String) + ".." + "fixtures"
|
||||
let loader = FileSystemLoader(paths: [path])
|
||||
environment = Environment(loader: loader)
|
||||
template = ""
|
||||
includedTemplate = ""
|
||||
}
|
||||
|
||||
func testSyntaxError() throws {
|
||||
template = Template(templateString: """
|
||||
{% include "invalid-include.html" %}
|
||||
""", environment: environment)
|
||||
includedTemplate = try environment.loadTemplate(name: "invalid-include.html")
|
||||
|
||||
try expectError(reason: "Unknown filter 'unknown'. Found similar filters: 'uppercase'.",
|
||||
token: """
|
||||
include "invalid-include.html"
|
||||
""",
|
||||
includedToken: "target|unknown")
|
||||
}
|
||||
|
||||
func testRuntimeError() throws {
|
||||
let filterExtension = Extension()
|
||||
filterExtension.registerFilter("unknown") { (_: Any?) in
|
||||
throw TemplateSyntaxError("filter error")
|
||||
}
|
||||
environment.extensions += [filterExtension]
|
||||
|
||||
template = Template(templateString: """
|
||||
{% include "invalid-include.html" %}
|
||||
""", environment: environment)
|
||||
includedTemplate = try environment.loadTemplate(name: "invalid-include.html")
|
||||
|
||||
try expectError(reason: "filter error",
|
||||
token: "include \"invalid-include.html\"",
|
||||
includedToken: "target|unknown")
|
||||
}
|
||||
|
||||
private func expectError(
|
||||
reason: String,
|
||||
token: String,
|
||||
includedToken: String,
|
||||
file: String = #file,
|
||||
line: Int = #line,
|
||||
function: String = #function
|
||||
) throws {
|
||||
var expectedError = expectedSyntaxError(token: token, template: template, description: reason)
|
||||
expectedError.stackTrace = [
|
||||
expectedSyntaxError(
|
||||
token: includedToken,
|
||||
template: includedTemplate,
|
||||
description: reason
|
||||
).token
|
||||
].compactMap { $0 }
|
||||
|
||||
let error = try expect(
|
||||
self.environment.render(template: self.template, context: ["target": "World"]),
|
||||
file: file,
|
||||
line: line,
|
||||
function: function
|
||||
).toThrow() as TemplateSyntaxError
|
||||
let reporter = SimpleErrorReporter()
|
||||
try expect(
|
||||
reporter.renderError(error),
|
||||
file: file,
|
||||
line: line,
|
||||
function: function
|
||||
) == reporter.renderError(expectedError)
|
||||
}
|
||||
}
|
||||
|
||||
final class EnvironmentBaseAndChildTemplateTests: XCTestCase {
|
||||
var environment = Environment(loader: ExampleLoader())
|
||||
var childTemplate: Template = ""
|
||||
var baseTemplate: Template = ""
|
||||
|
||||
override func setUp() {
|
||||
super.setUp()
|
||||
|
||||
let path = Path(#file as String) + ".." + "fixtures"
|
||||
let loader = FileSystemLoader(paths: [path])
|
||||
environment = Environment(loader: loader)
|
||||
childTemplate = ""
|
||||
baseTemplate = ""
|
||||
}
|
||||
|
||||
func testSyntaxErrorInBaseTemplate() throws {
|
||||
childTemplate = try environment.loadTemplate(name: "invalid-child-super.html")
|
||||
baseTemplate = try environment.loadTemplate(name: "invalid-base.html")
|
||||
|
||||
try expectError(reason: "Unknown filter 'unknown'. Found similar filters: 'uppercase'.",
|
||||
childToken: "extends \"invalid-base.html\"",
|
||||
baseToken: "target|unknown")
|
||||
}
|
||||
|
||||
func testRuntimeErrorInBaseTemplate() throws {
|
||||
let filterExtension = Extension()
|
||||
filterExtension.registerFilter("unknown") { (_: Any?) in
|
||||
throw TemplateSyntaxError("filter error")
|
||||
}
|
||||
environment.extensions += [filterExtension]
|
||||
|
||||
childTemplate = try environment.loadTemplate(name: "invalid-child-super.html")
|
||||
baseTemplate = try environment.loadTemplate(name: "invalid-base.html")
|
||||
|
||||
try expectError(reason: "filter error",
|
||||
childToken: "extends \"invalid-base.html\"",
|
||||
baseToken: "target|unknown")
|
||||
}
|
||||
|
||||
func testSyntaxErrorInChildTemplate() throws {
|
||||
childTemplate = Template(
|
||||
templateString: """
|
||||
{% extends "base.html" %}
|
||||
{% block body %}Child {{ target|unknown }}{% endblock %}
|
||||
""",
|
||||
environment: environment,
|
||||
name: nil
|
||||
)
|
||||
|
||||
try expectError(reason: "Unknown filter 'unknown'. Found similar filters: 'uppercase'.",
|
||||
childToken: "target|unknown",
|
||||
baseToken: nil)
|
||||
}
|
||||
|
||||
func testRuntimeErrorInChildTemplate() throws {
|
||||
let filterExtension = Extension()
|
||||
filterExtension.registerFilter("unknown") { (_: Any?) in
|
||||
throw TemplateSyntaxError("filter error")
|
||||
}
|
||||
environment.extensions += [filterExtension]
|
||||
|
||||
childTemplate = Template(
|
||||
templateString: """
|
||||
{% extends "base.html" %}
|
||||
{% block body %}Child {{ target|unknown }}{% endblock %}
|
||||
""",
|
||||
environment: environment,
|
||||
name: nil
|
||||
)
|
||||
|
||||
try expectError(reason: "filter error",
|
||||
childToken: "target|unknown",
|
||||
baseToken: nil)
|
||||
}
|
||||
|
||||
private func expectError(
|
||||
reason: String,
|
||||
childToken: String,
|
||||
baseToken: String?,
|
||||
file: String = #file,
|
||||
line: Int = #line,
|
||||
function: String = #function
|
||||
) throws {
|
||||
var expectedError = expectedSyntaxError(token: childToken, template: childTemplate, description: reason)
|
||||
if let baseToken = baseToken {
|
||||
expectedError.stackTrace = [
|
||||
expectedSyntaxError(
|
||||
token: baseToken,
|
||||
template: baseTemplate,
|
||||
description: reason
|
||||
).token
|
||||
].compactMap { $0 }
|
||||
}
|
||||
let error = try expect(
|
||||
self.environment.render(template: self.childTemplate, context: ["target": "World"]),
|
||||
file: file,
|
||||
line: line,
|
||||
function: function
|
||||
).toThrow() as TemplateSyntaxError
|
||||
let reporter = SimpleErrorReporter()
|
||||
try expect(
|
||||
reporter.renderError(error),
|
||||
file: file,
|
||||
line: line,
|
||||
function: function
|
||||
) == reporter.renderError(expectedError)
|
||||
}
|
||||
}
|
||||
|
||||
extension Expectation {
|
||||
@discardableResult
|
||||
func toThrow<T: Error>() throws -> T {
|
||||
var thrownError: Error?
|
||||
|
||||
do {
|
||||
_ = try expression()
|
||||
} catch {
|
||||
thrownError = error
|
||||
}
|
||||
|
||||
if let thrownError = thrownError {
|
||||
if let thrownError = thrownError as? T {
|
||||
return thrownError
|
||||
} else {
|
||||
throw failure("\(thrownError) is not \(T.self)")
|
||||
}
|
||||
} else {
|
||||
throw failure("expression did not throw an error")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension XCTestCase {
|
||||
func expectedSyntaxError(token: String, template: Template, description: String) -> TemplateSyntaxError {
|
||||
guard let range = template.templateString.range(of: token) else {
|
||||
fatalError("Can't find '\(token)' in '\(template)'")
|
||||
}
|
||||
let lexer = Lexer(templateString: template.templateString)
|
||||
let location = lexer.rangeLocation(range)
|
||||
let sourceMap = SourceMap(filename: template.name, location: location)
|
||||
let token = Token.block(value: token, at: sourceMap)
|
||||
return TemplateSyntaxError(reason: description, token: token, stackTrace: [])
|
||||
}
|
||||
}
|
||||
|
||||
private class ExampleLoader: Loader {
|
||||
func loadTemplate(name: String, environment: Environment) throws -> Template {
|
||||
if name == "example.html" {
|
||||
return Template(templateString: "Hello World!", environment: environment, name: name)
|
||||
}
|
||||
|
||||
throw TemplateDoesNotExist(templateNames: [name], loader: self)
|
||||
}
|
||||
}
|
||||
// MARK: - Helpers
|
||||
|
||||
private class CustomTemplate: Template {
|
||||
// swiftlint:disable discouraged_optional_collection
|
||||
override func render(_ dictionary: [String: Any]? = nil) throws -> String {
|
||||
return "here"
|
||||
"here"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ import Spectre
|
||||
import XCTest
|
||||
|
||||
final class ExpressionsTests: XCTestCase {
|
||||
let parser = TokenParser(tokens: [], environment: Environment())
|
||||
private let parser = TokenParser(tokens: [], environment: Environment())
|
||||
|
||||
private func makeExpression(_ components: [String]) -> Expression {
|
||||
do {
|
||||
|
||||
@@ -103,30 +103,30 @@ final class FilterTests: XCTestCase {
|
||||
}
|
||||
|
||||
it("allows you to register a custom filter which accepts several arguments") {
|
||||
let template = Template(templateString: """
|
||||
{{ name|repeat:'value"1"',"value'2'",'(key, value)' }}
|
||||
""")
|
||||
let template = Template(templateString: """
|
||||
{{ name|repeat:'value"1"',"value'2'",'(key, value)' }}
|
||||
""")
|
||||
|
||||
let repeatExtension = Extension()
|
||||
repeatExtension.registerFilter("repeat") { value, arguments in
|
||||
guard let value = value else { return nil }
|
||||
let args = arguments.compactMap { $0 }
|
||||
return "\(value) \(value) with args 0: \(args[0]), 1: \(args[1]), 2: \(args[2])"
|
||||
}
|
||||
let repeatExtension = Extension()
|
||||
repeatExtension.registerFilter("repeat") { value, arguments in
|
||||
guard let value = value else { return nil }
|
||||
let args = arguments.compactMap { $0 }
|
||||
return "\(value) \(value) with args 0: \(args[0]), 1: \(args[1]), 2: \(args[2])"
|
||||
}
|
||||
|
||||
let result = try template.render(Context(
|
||||
dictionary: context,
|
||||
environment: Environment(extensions: [repeatExtension])
|
||||
))
|
||||
try expect(result) == """
|
||||
Kyle Kyle with args 0: value"1", 1: value'2', 2: (key, value)
|
||||
"""
|
||||
let result = try template.render(Context(
|
||||
dictionary: context,
|
||||
environment: Environment(extensions: [repeatExtension])
|
||||
))
|
||||
try expect(result) == """
|
||||
Kyle Kyle with args 0: value"1", 1: value'2', 2: (key, value)
|
||||
"""
|
||||
}
|
||||
|
||||
it("allows whitespace in expression") {
|
||||
let template = Template(templateString: """
|
||||
{{ value | join : ", " }}
|
||||
""")
|
||||
{{ value | join : ", " }}
|
||||
""")
|
||||
let result = try template.render(Context(dictionary: ["value": ["One", "Two"]]))
|
||||
try expect(result) == "One, Two"
|
||||
}
|
||||
@@ -363,10 +363,12 @@ final class FilterTests: XCTestCase {
|
||||
Two
|
||||
"""
|
||||
]))
|
||||
// swiftlint:disable indentation_width
|
||||
try expect(result) == """
|
||||
One
|
||||
Two
|
||||
"""
|
||||
// swiftlint:enable indentation_width
|
||||
}
|
||||
|
||||
func testIndentNotEmptyLines() throws {
|
||||
@@ -383,6 +385,7 @@ final class FilterTests: XCTestCase {
|
||||
|
||||
"""
|
||||
]))
|
||||
// swiftlint:disable indentation_width
|
||||
try expect(result) == """
|
||||
One
|
||||
|
||||
@@ -391,6 +394,7 @@ final class FilterTests: XCTestCase {
|
||||
|
||||
|
||||
"""
|
||||
// swiftlint:enable indentation_width
|
||||
}
|
||||
|
||||
func testDynamicFilters() throws {
|
||||
|
||||
@@ -23,9 +23,9 @@ final class FilterTagTests: XCTestCase {
|
||||
|
||||
it("can render filters with arguments") {
|
||||
let ext = Extension()
|
||||
ext.registerFilter("split") {
|
||||
guard let value = $0 as? String,
|
||||
let argument = $1.first as? String else { return $0 }
|
||||
ext.registerFilter("split") { value, args in
|
||||
guard let value = value as? String,
|
||||
let argument = args.first as? String else { return value }
|
||||
return value.components(separatedBy: argument)
|
||||
}
|
||||
let env = Environment(extensions: [ext])
|
||||
@@ -37,11 +37,11 @@ final class FilterTagTests: XCTestCase {
|
||||
|
||||
it("can render filters with quote as an argument") {
|
||||
let ext = Extension()
|
||||
ext.registerFilter("replace") {
|
||||
guard let value = $0 as? String,
|
||||
$1.count == 2,
|
||||
let search = $1.first as? String,
|
||||
let replacement = $1.last as? String else { return $0 }
|
||||
ext.registerFilter("replace") { value, args in
|
||||
guard let value = value as? String,
|
||||
args.count == 2,
|
||||
let search = args.first as? String,
|
||||
let replacement = args.last as? String else { return value }
|
||||
return value.replacingOccurrences(of: search, with: replacement)
|
||||
}
|
||||
let env = Environment(extensions: [ext])
|
||||
|
||||
@@ -3,9 +3,10 @@ import Spectre
|
||||
import XCTest
|
||||
|
||||
final class ForNodeTests: XCTestCase {
|
||||
let context = Context(dictionary: [
|
||||
private let context = Context(dictionary: [
|
||||
"items": [1, 2, 3],
|
||||
"anyItems": [1, 2, 3] as [Any],
|
||||
// swiftlint:disable:next legacy_objc_type
|
||||
"nsItems": NSArray(array: [1, 2, 3]),
|
||||
"emptyItems": [Int](),
|
||||
"dict": [
|
||||
@@ -313,6 +314,8 @@ final class ForNodeTests: XCTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Helpers
|
||||
|
||||
private struct MyStruct {
|
||||
let string: String
|
||||
let number: Int
|
||||
|
||||
63
Tests/StencilTests/Helpers.swift
Normal file
63
Tests/StencilTests/Helpers.swift
Normal file
@@ -0,0 +1,63 @@
|
||||
import PathKit
|
||||
import Spectre
|
||||
@testable import Stencil
|
||||
import XCTest
|
||||
|
||||
extension Expectation {
|
||||
@discardableResult
|
||||
func toThrow<T: Error>() throws -> T {
|
||||
var thrownError: Error?
|
||||
|
||||
do {
|
||||
_ = try expression()
|
||||
} catch {
|
||||
thrownError = error
|
||||
}
|
||||
|
||||
if let thrownError = thrownError {
|
||||
if let thrownError = thrownError as? T {
|
||||
return thrownError
|
||||
} else {
|
||||
throw failure("\(thrownError) is not \(T.self)")
|
||||
}
|
||||
} else {
|
||||
throw failure("expression did not throw an error")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension XCTestCase {
|
||||
func expectedSyntaxError(token: String, template: Template, description: String) -> TemplateSyntaxError {
|
||||
guard let range = template.templateString.range(of: token) else {
|
||||
fatalError("Can't find '\(token)' in '\(template)'")
|
||||
}
|
||||
let lexer = Lexer(templateString: template.templateString)
|
||||
let location = lexer.rangeLocation(range)
|
||||
let sourceMap = SourceMap(filename: template.name, location: location)
|
||||
let token = Token.block(value: token, at: sourceMap)
|
||||
return TemplateSyntaxError(reason: description, token: token, stackTrace: [])
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Test Types
|
||||
|
||||
class ExampleLoader: Loader {
|
||||
func loadTemplate(name: String, environment: Environment) throws -> Template {
|
||||
if name == "example.html" {
|
||||
return Template(templateString: "Hello World!", environment: environment, name: name)
|
||||
}
|
||||
|
||||
throw TemplateDoesNotExist(templateNames: [name], loader: self)
|
||||
}
|
||||
}
|
||||
|
||||
class ErrorNode: NodeType {
|
||||
let token: Token?
|
||||
init(token: Token? = nil) {
|
||||
self.token = token
|
||||
}
|
||||
|
||||
func render(_ context: Context) throws -> String {
|
||||
throw TemplateSyntaxError("Custom Error")
|
||||
}
|
||||
}
|
||||
@@ -2,10 +2,6 @@ import Spectre
|
||||
@testable import Stencil
|
||||
import XCTest
|
||||
|
||||
private struct SomeType {
|
||||
let value: String? = nil
|
||||
}
|
||||
|
||||
final class IfNodeTests: XCTestCase {
|
||||
func testParseIf() {
|
||||
it("can parse an if block") {
|
||||
@@ -286,3 +282,9 @@ final class IfNodeTests: XCTestCase {
|
||||
try expect(renderNodes(nodes, Context(dictionary: ["value": 4]))) == "false"
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Helpers
|
||||
|
||||
private struct SomeType {
|
||||
let value: String? = nil
|
||||
}
|
||||
|
||||
@@ -4,9 +4,9 @@ import Spectre
|
||||
import XCTest
|
||||
|
||||
final class IncludeTests: XCTestCase {
|
||||
let path = Path(#file as String) + ".." + "fixtures"
|
||||
lazy var loader = FileSystemLoader(paths: [path])
|
||||
lazy var environment = Environment(loader: loader)
|
||||
private let path = Path(#file as String) + ".." + "fixtures"
|
||||
private lazy var loader = FileSystemLoader(paths: [path])
|
||||
private lazy var environment = Environment(loader: loader)
|
||||
|
||||
func testParsing() {
|
||||
it("throws an error when no template is given") {
|
||||
|
||||
@@ -4,9 +4,9 @@ import Stencil
|
||||
import XCTest
|
||||
|
||||
final class InheritanceTests: XCTestCase {
|
||||
let path = Path(#file as String) + ".." + "fixtures"
|
||||
lazy var loader = FileSystemLoader(paths: [path])
|
||||
lazy var environment = Environment(loader: loader)
|
||||
private let path = Path(#file as String) + ".." + "fixtures"
|
||||
private lazy var loader = FileSystemLoader(paths: [path])
|
||||
private lazy var environment = Environment(loader: loader)
|
||||
|
||||
func testInheritance() {
|
||||
it("can inherit from another template") {
|
||||
|
||||
@@ -82,6 +82,7 @@ final class LexerTests: XCTestCase {
|
||||
}
|
||||
|
||||
func testNewlines() throws {
|
||||
// swiftlint:disable indentation_width
|
||||
let templateString = """
|
||||
My name is {%
|
||||
if name
|
||||
@@ -92,6 +93,7 @@ final class LexerTests: XCTestCase {
|
||||
}}{%
|
||||
endif %}.
|
||||
"""
|
||||
// swiftlint:enable indentation_width
|
||||
let lexer = Lexer(templateString: templateString)
|
||||
let tokens = lexer.tokenize()
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ final class TemplateLoaderTests: XCTestCase {
|
||||
|
||||
func testDictionaryLoader() {
|
||||
let loader = DictionaryLoader(templates: [
|
||||
"index.html": "Hello World"
|
||||
"index.html": "Hello World"
|
||||
])
|
||||
let environment = Environment(loader: loader)
|
||||
|
||||
|
||||
@@ -2,19 +2,8 @@ import Spectre
|
||||
@testable import Stencil
|
||||
import XCTest
|
||||
|
||||
class ErrorNode: NodeType {
|
||||
let token: Token?
|
||||
init(token: Token? = nil) {
|
||||
self.token = token
|
||||
}
|
||||
|
||||
func render(_ context: Context) throws -> String {
|
||||
throw TemplateSyntaxError("Custom Error")
|
||||
}
|
||||
}
|
||||
|
||||
final class NodeTests: XCTestCase {
|
||||
let context = Context(dictionary: [
|
||||
private let context = Context(dictionary: [
|
||||
"name": "Kyle",
|
||||
"age": 27,
|
||||
"items": [1, 2, 3]
|
||||
|
||||
@@ -5,9 +5,9 @@ import XCTest
|
||||
final class NowNodeTests: XCTestCase {
|
||||
func testParsing() {
|
||||
it("parses default format without any now arguments") {
|
||||
#if os(Linux)
|
||||
#if os(Linux)
|
||||
throw skip()
|
||||
#else
|
||||
#else
|
||||
let tokens: [Token] = [ .block(value: "now", at: .unknown) ]
|
||||
let parser = TokenParser(tokens: tokens, environment: Environment())
|
||||
|
||||
@@ -15,36 +15,36 @@ final class NowNodeTests: XCTestCase {
|
||||
let node = nodes.first as? NowNode
|
||||
try expect(nodes.count) == 1
|
||||
try expect(node?.format.variable) == "\"yyyy-MM-dd 'at' HH:mm\""
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
it("parses now with a format") {
|
||||
#if os(Linux)
|
||||
#if os(Linux)
|
||||
throw skip()
|
||||
#else
|
||||
#else
|
||||
let tokens: [Token] = [ .block(value: "now \"HH:mm\"", at: .unknown) ]
|
||||
let parser = TokenParser(tokens: tokens, environment: Environment())
|
||||
let nodes = try parser.parse()
|
||||
let node = nodes.first as? NowNode
|
||||
try expect(nodes.count) == 1
|
||||
try expect(node?.format.variable) == "\"HH:mm\""
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
func testRendering() {
|
||||
it("renders the date") {
|
||||
#if os(Linux)
|
||||
#if os(Linux)
|
||||
throw skip()
|
||||
#else
|
||||
#else
|
||||
let node = NowNode(format: Variable("\"yyyy-MM-dd\""))
|
||||
|
||||
let formatter = DateFormatter()
|
||||
formatter.dateFormat = "yyyy-MM-dd"
|
||||
let date = formatter.string(from: NSDate() as Date)
|
||||
let date = formatter.string(from: Date())
|
||||
|
||||
try expect(try node.render(Context())) == date
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,8 +57,8 @@ final class TokenParserTests: XCTestCase {
|
||||
|
||||
try expect(try parser.parse()).toThrow(TemplateSyntaxError(
|
||||
reason: "Unknown template tag 'unknown'",
|
||||
token: tokens.first)
|
||||
)
|
||||
token: tokens.first
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,20 +2,8 @@ import Spectre
|
||||
import Stencil
|
||||
import XCTest
|
||||
|
||||
private struct CustomNode: NodeType {
|
||||
let token: Token?
|
||||
func render(_ context: Context) throws -> String {
|
||||
return "Hello World"
|
||||
}
|
||||
}
|
||||
|
||||
private struct Article {
|
||||
let title: String
|
||||
let author: String
|
||||
}
|
||||
|
||||
final class StencilTests: XCTestCase {
|
||||
lazy var environment: Environment = {
|
||||
private lazy var environment: Environment = {
|
||||
let exampleExtension = Extension()
|
||||
exampleExtension.registerSimpleTag("simpletag") { _ in
|
||||
"Hello World"
|
||||
@@ -32,7 +20,7 @@ final class StencilTests: XCTestCase {
|
||||
There are {{ articles.count }} articles.
|
||||
|
||||
{% for article in articles %}\
|
||||
- {{ article.title }} by {{ article.author }}.
|
||||
- {{ article.title }} by {{ article.author }}.
|
||||
{% endfor %}
|
||||
"""
|
||||
|
||||
@@ -49,8 +37,8 @@ final class StencilTests: XCTestCase {
|
||||
try expect(result) == """
|
||||
There are 2 articles.
|
||||
|
||||
- Migrating from OCUnit to XCTest by Kyle Fuller.
|
||||
- Memory Management with ARC by Kyle Fuller.
|
||||
- Migrating from OCUnit to XCTest by Kyle Fuller.
|
||||
- Memory Management with ARC by Kyle Fuller.
|
||||
|
||||
"""
|
||||
}
|
||||
@@ -66,3 +54,17 @@ final class StencilTests: XCTestCase {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Helpers
|
||||
|
||||
private struct CustomNode: NodeType {
|
||||
let token: Token?
|
||||
func render(_ context: Context) throws -> String {
|
||||
"Hello World"
|
||||
}
|
||||
}
|
||||
|
||||
private struct Article {
|
||||
let title: String
|
||||
let author: String
|
||||
}
|
||||
|
||||
@@ -11,9 +11,9 @@ final class TemplateTests: XCTestCase {
|
||||
}
|
||||
|
||||
it("can render a template from a string literal") {
|
||||
let template: Template = "Hello World"
|
||||
let result = try template.render([ "name": "Kyle" ])
|
||||
try expect(result) == "Hello World"
|
||||
let template: Template = "Hello World"
|
||||
let result = try template.render([ "name": "Kyle" ])
|
||||
try expect(result) == "Hello World"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,47 +2,8 @@ import Spectre
|
||||
@testable import Stencil
|
||||
import XCTest
|
||||
|
||||
#if os(OSX)
|
||||
@objc
|
||||
class Superclass: NSObject {
|
||||
@objc let name = "Foo"
|
||||
}
|
||||
@objc
|
||||
class Object: Superclass {
|
||||
@objc let title = "Hello World"
|
||||
}
|
||||
#endif
|
||||
|
||||
private struct Person {
|
||||
let name: String
|
||||
}
|
||||
|
||||
private struct Article {
|
||||
let author: Person
|
||||
}
|
||||
|
||||
private class WebSite {
|
||||
let url: String = "blog.com"
|
||||
}
|
||||
|
||||
private class Blog: WebSite {
|
||||
let articles: [Article] = [Article(author: Person(name: "Kyle"))]
|
||||
let featuring: Article? = Article(author: Person(name: "Jhon"))
|
||||
}
|
||||
|
||||
@dynamicMemberLookup
|
||||
private struct DynamicStruct: DynamicMemberLookup {
|
||||
subscript(dynamicMember member: String) -> Any? {
|
||||
member == "test" ? "this is a dynamic response" : nil
|
||||
}
|
||||
}
|
||||
|
||||
private enum DynamicEnum: String, DynamicMemberLookup {
|
||||
case someValue = "this is raw value"
|
||||
}
|
||||
|
||||
final class VariableTests: XCTestCase {
|
||||
let context: Context = {
|
||||
private let context: Context = {
|
||||
let ext = Extension()
|
||||
ext.registerFilter("incr") { arg in
|
||||
(arg.flatMap { toNumber(value: $0) } ?? 0) + 1
|
||||
@@ -66,9 +27,9 @@ final class VariableTests: XCTestCase {
|
||||
"struct": DynamicStruct()
|
||||
]
|
||||
], environment: environment)
|
||||
#if os(OSX)
|
||||
#if os(OSX)
|
||||
context["object"] = Object()
|
||||
#endif
|
||||
#endif
|
||||
return context
|
||||
}()
|
||||
|
||||
@@ -145,9 +106,9 @@ final class VariableTests: XCTestCase {
|
||||
let result = try variable.resolve(self.context) as? String
|
||||
try expect(result) == "Katie"
|
||||
|
||||
let variable1 = Variable("contacts.1")
|
||||
let result1 = try variable1.resolve(self.context) as? String
|
||||
try expect(result1) == "Carlton"
|
||||
let variable1 = Variable("contacts.1")
|
||||
let result1 = try variable1.resolve(self.context) as? String
|
||||
try expect(result1) == "Carlton"
|
||||
}
|
||||
|
||||
it("can resolve an item from an array via unknown index") {
|
||||
@@ -214,7 +175,7 @@ final class VariableTests: XCTestCase {
|
||||
}
|
||||
|
||||
func testKVO() {
|
||||
#if os(OSX)
|
||||
#if os(OSX)
|
||||
it("can resolve a value via KVO") {
|
||||
let variable = Variable("object.title")
|
||||
let result = try variable.resolve(self.context) as? String
|
||||
@@ -232,7 +193,7 @@ final class VariableTests: XCTestCase {
|
||||
let result = try variable.resolve(self.context) as? String
|
||||
try expect(result).to.beNil()
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
func testTuple() {
|
||||
@@ -285,7 +246,7 @@ final class VariableTests: XCTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
#if os(OSX)
|
||||
#if os(OSX)
|
||||
it("can resolve a subscript via KVO") {
|
||||
try self.context.push(dictionary: ["property": "name"]) {
|
||||
let variable = Variable("object[property]")
|
||||
@@ -293,7 +254,7 @@ final class VariableTests: XCTestCase {
|
||||
try expect(result) == "Foo"
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
it("can resolve an optional subscript via reflection") {
|
||||
try self.context.push(dictionary: ["property": "featuring"]) {
|
||||
@@ -394,3 +355,44 @@ final class VariableTests: XCTestCase {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Helpers
|
||||
|
||||
#if os(OSX)
|
||||
@objc
|
||||
class Superclass: NSObject {
|
||||
@objc let name = "Foo"
|
||||
}
|
||||
@objc
|
||||
class Object: Superclass {
|
||||
@objc let title = "Hello World"
|
||||
}
|
||||
#endif
|
||||
|
||||
private struct Person {
|
||||
let name: String
|
||||
}
|
||||
|
||||
private struct Article {
|
||||
let author: Person
|
||||
}
|
||||
|
||||
private class WebSite {
|
||||
let url: String = "blog.com"
|
||||
}
|
||||
|
||||
private class Blog: WebSite {
|
||||
let articles: [Article] = [Article(author: Person(name: "Kyle"))]
|
||||
let featuring: Article? = Article(author: Person(name: "Jhon"))
|
||||
}
|
||||
|
||||
@dynamicMemberLookup
|
||||
private struct DynamicStruct: DynamicMemberLookup {
|
||||
subscript(dynamicMember member: String) -> Any? {
|
||||
member == "test" ? "this is a dynamic response" : nil
|
||||
}
|
||||
}
|
||||
|
||||
private enum DynamicEnum: String, DynamicMemberLookup {
|
||||
case someValue = "this is raw value"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user