Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 12 additions & 14 deletions Sources/ScreamURITemplate/Internal/Scanner.swift
Original file line number Diff line number Diff line change
Expand Up @@ -48,26 +48,22 @@ struct Scanner {
}
}

private func checkUnterminated() throws(URITemplate.Error) {
if currentIndex == unicodeScalars.endIndex {
throw URITemplate.Error(type: .malformedTemplate, position: currentIndex, reason: "Unterminated Expression")
}
}

private mutating func scanExpressionComponent() throws(URITemplate.Error) -> Component {
assert(unicodeScalars[currentIndex] == "{")
let expressionStartIndex = currentIndex
currentIndex = unicodeScalars.index(after: currentIndex)
try checkUnterminated()

let expressionOperator = try scanExpressionOperator()
try checkUnterminated()
let variableList = try scanVariableList()

return ExpressionComponent(expressionOperator: expressionOperator, variableList: variableList, templatePosition: expressionStartIndex)
}

private mutating func scanExpressionOperator() throws(URITemplate.Error) -> ExpressionOperator {
guard currentIndex < unicodeScalars.endIndex else {
return .simple
}

let expressionOperator: ExpressionOperator
if expressionOperatorCharacterSet.contains(unicodeScalars[currentIndex]) {
guard let `operator` = ExpressionOperator(rawValue: unicodeScalars[currentIndex]) else {
Expand All @@ -87,15 +83,13 @@ struct Scanner {
var complete = false
while !complete {
let variableName = try scanVariableName()

try checkUnterminated()

let modifier = try scanVariableModifier()

try checkUnterminated()

variableList.append(VariableSpec(name: variableName, modifier: modifier))

guard currentIndex < unicodeScalars.endIndex else {
throw URITemplate.Error(type: .malformedTemplate, position: currentIndex, reason: "Unterminated Expression")
}

switch unicodeScalars[currentIndex] {
case ",":
currentIndex = unicodeScalars.index(after: currentIndex)
Expand Down Expand Up @@ -134,6 +128,10 @@ struct Scanner {
}

private mutating func scanVariableModifier() throws(URITemplate.Error) -> VariableSpec.Modifier {
guard currentIndex < unicodeScalars.endIndex else {
return .none
}

switch unicodeScalars[currentIndex] {
case "*":
currentIndex = unicodeScalars.index(after: currentIndex)
Expand Down
8 changes: 6 additions & 2 deletions Tests/ScreamURITemplateTests/Tests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,13 @@ private struct TestVariableProvider: VariableProvider {
}

class Tests: XCTestCase {
func testUncompleteNotCrashing() throws {
// Use case: the user enters a template. This should not crash.
func testUnterminatedExpression() throws {
XCTAssertThrowsError(try URITemplate(string: "https://api.github.com/repos/{"))
XCTAssertThrowsError(try URITemplate(string: "https://api.github.com/repos/{owner"))
XCTAssertThrowsError(try URITemplate(string: "https://api.github.com/repos/{owner,"))
XCTAssertThrowsError(try URITemplate(string: "https://api.github.com/repos/{owner*"))
XCTAssertThrowsError(try URITemplate(string: "https://api.github.com/repos/{owner:"))
XCTAssertThrowsError(try URITemplate(string: "https://api.github.com/repos/{owner:3"))
}

func testIncompletePercentEncodedTriplet() throws {
Expand Down