diff --git a/Cartfile b/Cartfile new file mode 100644 index 0000000..5429909 --- /dev/null +++ b/Cartfile @@ -0,0 +1 @@ +github "kylef/URITemplate.swift" ~> 2.0.3 \ No newline at end of file diff --git a/Cartfile.resolved b/Cartfile.resolved new file mode 100644 index 0000000..31660d7 --- /dev/null +++ b/Cartfile.resolved @@ -0,0 +1,2 @@ +github "apple/swift-corelibs-xctest" "swift-DEVELOPMENT-SNAPSHOT-2018-03-17-a" +github "kylef/URITemplate.swift" "2.0.3" diff --git a/Carthage/Checkouts/URITemplate.swift/.gitignore b/Carthage/Checkouts/URITemplate.swift/.gitignore new file mode 100644 index 0000000..2c56ce5 --- /dev/null +++ b/Carthage/Checkouts/URITemplate.swift/.gitignore @@ -0,0 +1,3 @@ +.build/ +Packages/ +*.xcodeproj/ diff --git a/Carthage/Checkouts/URITemplate.swift/.gitmodules b/Carthage/Checkouts/URITemplate.swift/.gitmodules new file mode 100644 index 0000000..90e60d6 --- /dev/null +++ b/Carthage/Checkouts/URITemplate.swift/.gitmodules @@ -0,0 +1,3 @@ +[submodule "Tests/URITemplateTests/Cases"] + path = Tests/URITemplateTests/Cases + url = https://github.com/uri-templates/uritemplate-test diff --git a/Carthage/Checkouts/URITemplate.swift/.travis.yml b/Carthage/Checkouts/URITemplate.swift/.travis.yml new file mode 100644 index 0000000..114ead1 --- /dev/null +++ b/Carthage/Checkouts/URITemplate.swift/.travis.yml @@ -0,0 +1,13 @@ +matrix: + include: + - os: osx + osx_image: xcode8.3 + - os: osx + osx_image: xcode9 +language: generic +sudo: required +dist: trusty +install: +- eval "$(curl -sL https://gist.githubusercontent.com/kylef/5c0475ff02b7c7671d2a/raw/9f442512a46d7a2af7b850d65a7e9bd31edfb09b/swiftenv-install.sh)" +script: +- swift test diff --git a/Carthage/Checkouts/URITemplate.swift/CHANGELOG.md b/Carthage/Checkouts/URITemplate.swift/CHANGELOG.md new file mode 100644 index 0000000..8b91ebc --- /dev/null +++ b/Carthage/Checkouts/URITemplate.swift/CHANGELOG.md @@ -0,0 +1,17 @@ +# Changelog for URITemplate + +## 2.0.3 + +### Bug Fixes + +- Prevents using deprecated APIs when building on Swift 4. + +## 2.0.2 + +### Enhancements + +- Adds support for Swift 4.0. + +## 2.0.1 + +Internal refactoring to prevent use of deprecated system APIs. diff --git a/Carthage/Checkouts/URITemplate.swift/LICENSE b/Carthage/Checkouts/URITemplate.swift/LICENSE new file mode 100644 index 0000000..702ed21 --- /dev/null +++ b/Carthage/Checkouts/URITemplate.swift/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2014 Kyle Fuller + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/Carthage/Checkouts/URITemplate.swift/Package.resolved b/Carthage/Checkouts/URITemplate.swift/Package.resolved new file mode 100644 index 0000000..544cdb7 --- /dev/null +++ b/Carthage/Checkouts/URITemplate.swift/Package.resolved @@ -0,0 +1,25 @@ +{ + "object": { + "pins": [ + { + "package": "PathKit", + "repositoryURL": "https://github.com/kylef/PathKit", + "state": { + "branch": null, + "revision": "4e02bcd2951fb4b7f60dbcaf6f3f47957bcfe0be", + "version": "0.7.1" + } + }, + { + "package": "Spectre", + "repositoryURL": "https://github.com/kylef/Spectre", + "state": { + "branch": null, + "revision": "e46b75cf03ad5e563b4b0a5068d3d6f04d77d80b", + "version": "0.7.2" + } + } + ] + }, + "version": 1 +} diff --git a/Carthage/Checkouts/URITemplate.swift/Package.swift b/Carthage/Checkouts/URITemplate.swift/Package.swift new file mode 100644 index 0000000..1f674fe --- /dev/null +++ b/Carthage/Checkouts/URITemplate.swift/Package.swift @@ -0,0 +1,10 @@ +import PackageDescription + +let package = Package( + name: "URITemplate", + dependencies: [ + .Package(url: "https://github.com/kylef/Spectre", majorVersion: 0, minor: 7), + .Package(url: "https://github.com/kylef/PathKit", majorVersion: 0, minor: 7), + ], + swiftLanguageVersions: [3, 4] +) diff --git a/Carthage/Checkouts/URITemplate.swift/README.md b/Carthage/Checkouts/URITemplate.swift/README.md new file mode 100644 index 0000000..aaef3a9 --- /dev/null +++ b/Carthage/Checkouts/URITemplate.swift/README.md @@ -0,0 +1,49 @@ +URITemplate +=========== + +Swift implementation of URI Template ([RFC6570](https://tools.ietf.org/html/rfc6570)). + +## Installation + +[CocoaPods](http://cocoapods.org/) is the recommended installation method. + +```ruby +pod 'URITemplate' +``` + +## Example + +### Expanding a URI Template + +```swift +let template = URITemplate(template: "https://api.github.com/repos/{owner}/{repo}/") +let url = template.expand(["owner": "kylef", "repo": "URITemplate.swift"]) +=> "https://api.github.com/repos/kylef/URITemplate.swift/" +``` + +### Determine which variables are in a template + +```swift +let variables = template.variables +=> ["owner", "repo"] +``` + +### Extract the variables used in a given URL + +```swift +let variables = template.extract("https://api.github.com/repos/kylef/PathKit/") +=> ["owner":"kylef", "repo":"PathKit"] +``` + +## [RFC6570](https://tools.ietf.org/html/rfc6570) + +The URITemplate library follows the [test suite](https://github.com/uri-templates/uritemplate-test). + +We have full support for level 4 of RFC6570 when expanding a template and retrieving the variables in a template. + +For extraction of variables from an already expanded template, level 3 is supported. + +## License + +URITemplate is licensed under the MIT license. See [LICENSE](LICENSE) for more +info. diff --git a/Carthage/Checkouts/URITemplate.swift/Sources/URITemplate.swift b/Carthage/Checkouts/URITemplate.swift/Sources/URITemplate.swift new file mode 100644 index 0000000..802b301 --- /dev/null +++ b/Carthage/Checkouts/URITemplate.swift/Sources/URITemplate.swift @@ -0,0 +1,638 @@ +// +// URITemplate.swift +// URITemplate +// +// Created by Kyle Fuller on 25/11/2014. +// Copyright (c) 2014 Kyle Fuller. All rights reserved. +// + +import Foundation + +// MARK: URITemplate + +/// A data structure to represent an RFC6570 URI template. +public struct URITemplate : CustomStringConvertible, Equatable, Hashable, ExpressibleByStringLiteral, ExpressibleByExtendedGraphemeClusterLiteral, ExpressibleByUnicodeScalarLiteral { + /// The underlying URI template + public let template:String + + var regex:NSRegularExpression { + let expression: NSRegularExpression? + do { + expression = try NSRegularExpression(pattern: "\\{([^\\}]+)\\}", options: NSRegularExpression.Options(rawValue: 0)) + } catch let error as NSError { + fatalError("Invalid Regex \(error)") + } + return expression! + } + + var operators:[Operator] { + return [ + StringExpansion(), + ReservedExpansion(), + FragmentExpansion(), + LabelExpansion(), + PathSegmentExpansion(), + PathStyleParameterExpansion(), + FormStyleQueryExpansion(), + FormStyleQueryContinuation(), + ] + } + + /// Initialize a URITemplate with the given template + public init(template:String) { + self.template = template + } + + public typealias ExtendedGraphemeClusterLiteralType = StringLiteralType + public init(extendedGraphemeClusterLiteral value: ExtendedGraphemeClusterLiteralType) { + template = value + } + + public typealias UnicodeScalarLiteralType = StringLiteralType + public init(unicodeScalarLiteral value: UnicodeScalarLiteralType) { + template = value + } + + public init(stringLiteral value: StringLiteralType) { + template = value + } + + /// Returns a description of the URITemplate + public var description: String { + return template + } + + public var hashValue: Int { + return template.hashValue + } + + /// Returns the set of keywords in the URI Template + public var variables: [String] { + let expressions = regex.matches(template).map { expression -> String in + // Removes the { and } from the expression +#if swift(>=4.0) + return String(expression[expression.characters.index(after: expression.startIndex).. [String] in + var expression = expression + + for op in self.operators { + if let op = op.op { + if expression.hasPrefix(op) { +#if swift(>=4.0) + expression = String(expression[expression.characters.index(after: expression.startIndex)...]) +#else + expression = expression.substring(from: expression.characters.index(after: expression.startIndex)) +#endif + break + } + } + } + + return expression.components(separatedBy: ",").map { component in + if component.hasSuffix("*") { +#if swift(>=4.0) + return String(component[.. String { + return regex.substitute(template) { string in +#if swift(>=4.0) + var expression = String(string[string.characters.index(after: string.startIndex)..=4.0) + expression = String(expression[expression.characters.index(after: expression.startIndex)...]) +#else + expression = expression.substring(from: expression.characters.index(after: expression.startIndex)) +#endif + } else { + op = self.operators.first + } + + let rawExpansions = expression.components(separatedBy: ",").map { vari -> String? in + var variable = vari + var prefix:Int? + + if let range = variable.range(of: ":") { +#if swift(>=4.0) + prefix = Int(String(variable[range.upperBound...])) + variable = String(variable[..=4.0) + variable = String(variable[.. [String] in + if let expansion = expansion { + return accumulator + [expansion] + } + + return accumulator + }) + + if expansions.count > 0 { + return op!.prefix + expansions.joined(separator: op!.joiner) + } + + return "" + } + } + + func regexForVariable(_ variable:String, op:Operator?) -> String { + if op != nil { + return "(.*)" + } else { + return "([A-z0-9%_\\-]+)" + } + } + + func regexForExpression(_ expression:String) -> String { + var expression = expression + + let op = operators.filter { + $0.op != nil && expression.hasPrefix($0.op!) + }.first + + if op != nil { +#if swift(>=4.0) + expression = String(expression[expression.characters.index(after: expression.startIndex).. String in + return self.regexForVariable(variable, op: op) + } + + return regexes.joined(separator: (op ?? StringExpansion()).joiner) + } + + var extractionRegex:NSRegularExpression? { + let regex = try! NSRegularExpression(pattern: "(\\{([^\\}]+)\\})|[^(.*)]", options: NSRegularExpression.Options(rawValue: 0)) + + let pattern = regex.substitute(self.template) { expression in + if expression.hasPrefix("{") && expression.hasSuffix("}") { + let startIndex = expression.characters.index(after: expression.startIndex) + let endIndex = expression.characters.index(before: expression.endIndex) +#if swift(>=4.0) + return self.regexForExpression(String(expression[startIndex.. [String:String]? { + if let expression = extractionRegex { + let input = url as NSString + let range = NSRange(location: 0, length: input.length) + let results = expression.matches(in: url, options: NSRegularExpression.MatchingOptions(rawValue: 0), range: range) + + if let result = results.first { + var extractedVariables:[String: String] = [:] + + for (index, variable) in variables.enumerated() { +#if swift(>=4.0) + let range = result.range(at: index + 1) +#else + let range = result.rangeAt(index + 1) +#endif + let value = NSString(string: input.substring(with: range)).removingPercentEncoding + extractedVariables[variable] = value + } + + return extractedVariables + } + } + + return nil + } +} + +/// Determine if two URITemplate's are equivalent +public func ==(lhs:URITemplate, rhs:URITemplate) -> Bool { + return lhs.template == rhs.template +} + +// MARK: Extensions + +extension NSRegularExpression { + func substitute(_ string:String, block:((String) -> (String))) -> String { + let oldString = string as NSString + let range = NSRange(location: 0, length: oldString.length) + var newString = string as NSString + + let matches = self.matches(in: string, options: NSRegularExpression.MatchingOptions(rawValue: 0), range: range) + for match in Array(matches.reversed()) { + let expression = oldString.substring(with: match.range) + let replacement = block(expression) + newString = newString.replacingCharacters(in: match.range, with: replacement) as NSString + } + + return newString as String + } + + func matches(_ string:String) -> [String] { + let input = string as NSString + let range = NSRange(location: 0, length: input.length) + let results = self.matches(in: string, options: NSRegularExpression.MatchingOptions(rawValue: 0), range: range) + + return results.map { result -> String in + return input.substring(with: result.range) + } + } +} + +extension String { + func percentEncoded() -> String { + return addingPercentEncoding(withAllowedCharacters: CharacterSet.URITemplate.unreserved)! + } +} + +// MARK: Operators + +protocol Operator { + /// Operator + var op:String? { get } + + /// Prefix for the expanded string + var prefix:String { get } + + /// Character to use to join expanded components + var joiner:String { get } + + func expand(_ variable:String, value: Any?, explode:Bool, prefix:Int?) -> String? +} + +class BaseOperator { + var joiner:String { return "," } + + func expand(_ variable:String, value: Any?, explode:Bool, prefix:Int?) -> String? { + if let value = value { + if let values = value as? [String: Any] { + return expand(variable:variable, value: values, explode: explode) + } else if let values = value as? [Any] { + return expand(variable:variable, value: values, explode: explode) + } else if let _ = value as? NSNull { + return expand(variable:variable) + } else { + return expand(variable:variable, value:"\(value)", prefix:prefix) + } + } + + return expand(variable:variable) + } + + // Point to overide to expand a value (i.e, perform encoding) + func expand(value:String) -> String { + return value + } + + // Point to overide to expanding a string + func expand(variable:String, value:String, prefix:Int?) -> String { + if let prefix = prefix { + if value.characters.count > prefix { + let index = value.characters.index(value.startIndex, offsetBy: prefix, limitedBy: value.endIndex) +#if swift(>=4.0) + return expand(value: String(value[.. String? { + let joiner = explode ? self.joiner : "," + return value.map { self.expand(value: "\($0)") }.joined(separator: joiner) + } + + // Point to overide to expanding a dictionary + func expand(variable: String, value: [String: Any], explode: Bool) -> String? { + let joiner = explode ? self.joiner : "," + let keyValueJoiner = explode ? "=" : "," + let elements = value.map({ (key, value) -> String in + let expandedKey = self.expand(value: key) + let expandedValue = self.expand(value: "\(value)") + return "\(expandedKey)\(keyValueJoiner)\(expandedValue)" + }) + + return elements.joined(separator: joiner) + } + + // Point to overide when value not found + func expand(variable: String) -> String? { + return nil + } +} + +/// RFC6570 (3.2.2) Simple String Expansion: {var} +class StringExpansion : BaseOperator, Operator { + var op:String? { return nil } + var prefix:String { return "" } + override var joiner:String { return "," } + + override func expand(value:String) -> String { + return value.percentEncoded() + } +} + +/// RFC6570 (3.2.3) Reserved Expansion: {+var} +class ReservedExpansion : BaseOperator, Operator { + var op:String? { return "+" } + var prefix:String { return "" } + override var joiner:String { return "," } + + override func expand(value:String) -> String { + return value.addingPercentEncoding(withAllowedCharacters: CharacterSet.uriTemplateReservedAllowed)! + } +} + +/// RFC6570 (3.2.4) Fragment Expansion {#var} +class FragmentExpansion : BaseOperator, Operator { + var op:String? { return "#" } + var prefix:String { return "#" } + override var joiner:String { return "," } + + override func expand(value:String) -> String { + return value.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlFragmentAllowed)! + } +} + +/// RFC6570 (3.2.5) Label Expansion with Dot-Prefix: {.var} +class LabelExpansion : BaseOperator, Operator { + var op:String? { return "." } + var prefix:String { return "." } + override var joiner:String { return "." } + + override func expand(value:String) -> String { + return value.percentEncoded() + } + + override func expand(variable:String, value:[Any], explode:Bool) -> String? { + if value.count > 0 { + return super.expand(variable: variable, value: value, explode: explode) + } + + return nil + } +} + +/// RFC6570 (3.2.6) Path Segment Expansion: {/var} +class PathSegmentExpansion : BaseOperator, Operator { + var op:String? { return "/" } + var prefix:String { return "/" } + override var joiner:String { return "/" } + + override func expand(value:String) -> String { + return value.percentEncoded() + } + + override func expand(variable:String, value:[Any], explode:Bool) -> String? { + if value.count > 0 { + return super.expand(variable: variable, value: value, explode: explode) + } + + return nil + } +} + +/// RFC6570 (3.2.7) Path-Style Parameter Expansion: {;var} +class PathStyleParameterExpansion : BaseOperator, Operator { + var op:String? { return ";" } + var prefix:String { return ";" } + override var joiner:String { return ";" } + + override func expand(value:String) -> String { + return value.percentEncoded() + } + + override func expand(variable:String, value:String, prefix:Int?) -> String { + if value.characters.count > 0 { + let expandedValue = super.expand(variable: variable, value: value, prefix: prefix) + return "\(variable)=\(expandedValue)" + } + + return variable + } + + override func expand(variable:String, value:[Any], explode:Bool) -> String? { + let joiner = explode ? self.joiner : "," + let expandedValue = value.map { + let expandedValue = self.expand(value: "\($0)") + + if explode { + return "\(variable)=\(expandedValue)" + } + + return expandedValue + }.joined(separator: joiner) + + if !explode { + return "\(variable)=\(expandedValue)" + } + + return expandedValue + } + + override func expand(variable: String, value: [String: Any], explode: Bool) -> String? { + let expandedValue = super.expand(variable: variable, value: value, explode: explode) + + if let expandedValue = expandedValue { + if (!explode) { + return "\(variable)=\(expandedValue)" + } + } + + return expandedValue + } +} + +/// RFC6570 (3.2.8) Form-Style Query Expansion: {?var} +class FormStyleQueryExpansion : BaseOperator, Operator { + var op:String? { return "?" } + var prefix:String { return "?" } + override var joiner:String { return "&" } + + override func expand(value:String) -> String { + return value.percentEncoded() + } + + override func expand(variable:String, value:String, prefix:Int?) -> String { + let expandedValue = super.expand(variable: variable, value: value, prefix: prefix) + return "\(variable)=\(expandedValue)" + } + + override func expand(variable: String, value: [Any], explode: Bool) -> String? { + if value.count > 0 { + let joiner = explode ? self.joiner : "," + let expandedValue = value.map { + let expandedValue = self.expand(value: "\($0)") + + if explode { + return "\(variable)=\(expandedValue)" + } + + return expandedValue + }.joined(separator: joiner) + + if !explode { + return "\(variable)=\(expandedValue)" + } + + return expandedValue + } + + return nil + } + + override func expand(variable: String, value: [String: Any], explode: Bool) -> String? { + if value.count > 0 { + let expandedVariable = self.expand(value: variable) + let expandedValue = super.expand(variable: variable, value: value, explode: explode) + + if let expandedValue = expandedValue { + if (!explode) { + return "\(expandedVariable)=\(expandedValue)" + } + } + + return expandedValue + } + + return nil + } +} + +/// RFC6570 (3.2.9) Form-Style Query Continuation: {&var} +class FormStyleQueryContinuation : BaseOperator, Operator { + var op:String? { return "&" } + var prefix:String { return "&" } + override var joiner:String { return "&" } + + override func expand(value:String) -> String { + return value.percentEncoded() + } + + override func expand(variable:String, value:String, prefix:Int?) -> String { + let expandedValue = super.expand(variable: variable, value: value, prefix: prefix) + return "\(variable)=\(expandedValue)" + } + + override func expand(variable: String, value: [Any], explode: Bool) -> String? { + let joiner = explode ? self.joiner : "," + let expandedValue = value.map { + let expandedValue = self.expand(value: "\($0)") + + if explode { + return "\(variable)=\(expandedValue)" + } + + return expandedValue + }.joined(separator: joiner) + + if !explode { + return "\(variable)=\(expandedValue)" + } + + return expandedValue + } + + override func expand(variable: String, value: [String: Any], explode: Bool) -> String? { + let expandedValue = super.expand(variable: variable, value: value, explode: explode) + + if let expandedValue = expandedValue { + if (!explode) { + return "\(variable)=\(expandedValue)" + } + } + + return expandedValue + } +} + +private extension CharacterSet { + struct URITemplate { + static let digits = CharacterSet(charactersIn: "0"..."9") + static let genDelims = CharacterSet(charactersIn: ":/?#[]@") + static let subDelims = CharacterSet(charactersIn: "!$&'()*+,;=") + static let unreservedSymbols = CharacterSet(charactersIn: "-._~") + + static let unreserved = { + return alpha.union(digits).union(unreservedSymbols) + }() + + static let reserved = { + return genDelims.union(subDelims) + }() + + static let alpha = { () -> CharacterSet in + let upperAlpha = CharacterSet(charactersIn: "A"..."Z") + let lowerAlpha = CharacterSet(charactersIn: "a"..."z") + return upperAlpha.union(lowerAlpha) + }() + } + + static let uriTemplateReservedAllowed = { + return URITemplate.unreserved.union(URITemplate.reserved) + }() +} diff --git a/Carthage/Checkouts/URITemplate.swift/Tests/LinuxMain.swift b/Carthage/Checkouts/URITemplate.swift/Tests/LinuxMain.swift new file mode 100644 index 0000000..a29558b --- /dev/null +++ b/Carthage/Checkouts/URITemplate.swift/Tests/LinuxMain.swift @@ -0,0 +1,3 @@ +import URITemplateTests + +testURITemplate() diff --git a/Carthage/Checkouts/URITemplate.swift/Tests/URITemplateTests/Cases/README.md b/Carthage/Checkouts/URITemplate.swift/Tests/URITemplateTests/Cases/README.md new file mode 100644 index 0000000..3eb519d --- /dev/null +++ b/Carthage/Checkouts/URITemplate.swift/Tests/URITemplateTests/Cases/README.md @@ -0,0 +1,90 @@ + +URI Template Tests +================== + +This is a set of tests for implementations of +[RFC6570](http://tools.ietf.org/html/rfc6570) - URI Template. It is designed +to be reused by any implementation, to improve interoperability and +implementation quality. + +If your project uses Git for version control, you can make uritemplate-tests into a [submodule](http://help.github.com/submodules/). + +Test Format +----------- + +Each test file is a [JSON](http://tools.ietf.org/html/RFC6627) document +containing an object whose properties are groups of related tests. +Alternatively, all tests are available in XML as well, with the XML files +being generated by transform-json-tests.xslt which uses json2xml.xslt as a +general-purpose JSON-to-XML parsing library. + +Each group, in turn, is an object with three children: + +* level - the level of the tests covered, as per the RFC (optional; if absent, + assume level 4). +* variables - an object representing the variables that are available to the + tests in the suite +* testcases - a list of testcases, where each case is a two-member list, the + first being the template, the second being the result of expanding the + template with the provided variables. + +Note that the result string can be a few different things: + +* string - if the second member is a string, the result of expansion is + expected to match it, character-for-character. +* list - if the second member is a list of strings, the result of expansion + is expected to match one of them; this allows for templates that can + expand into different, equally-acceptable URIs. +* false - if the second member is boolean false, expansion is expected to + fail (i.e., the template was invalid). + +For example: + + { + "Level 1 Examples" : + { + "level": 1, + "variables": { + "var" : "value", + "hello" : "Hello World!" + }, + "testcases" : [ + ["{var}", "value"], + ["{hello}", "Hello%20World%21"] + ] + } + } + + +Tests Included +-------------- + +The following test files are included: + +* spec-examples.json - The complete set of example templates from the RFC +* spec-examples-by-section.json - The examples, section by section +* extended-tests.json - more complex test cases +* negative-tests.json - invalid templates + +For all these test files, XML versions with the names *.xml can be +generated with the transform-json-tests.xslt XSLT stylesheet. The XSLT +contains the names of the above test files as a parameter, and can be +started with any XML as input (i.e., the XML input is ignored). + +License +------- + + Copyright 2011-2012 The Authors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + diff --git a/Carthage/Checkouts/URITemplate.swift/Tests/URITemplateTests/Cases/extended-tests.json b/Carthage/Checkouts/URITemplate.swift/Tests/URITemplateTests/Cases/extended-tests.json new file mode 100644 index 0000000..fd69744 --- /dev/null +++ b/Carthage/Checkouts/URITemplate.swift/Tests/URITemplateTests/Cases/extended-tests.json @@ -0,0 +1,118 @@ +{ + "Additional Examples 1":{ + "level":4, + "variables":{ + "id" : "person", + "token" : "12345", + "fields" : ["id", "name", "picture"], + "format" : "json", + "q" : "URI Templates", + "page" : "5", + "lang" : "en", + "geocode" : ["37.76","-122.427"], + "first_name" : "John", + "last.name" : "Doe", + "Some%20Thing" : "foo", + "number" : 6, + "long" : 37.76, + "lat" : -122.427, + "group_id" : "12345", + "query" : "PREFIX dc: SELECT ?book ?who WHERE { ?book dc:creator ?who }", + "uri" : "http://example.org/?uri=http%3A%2F%2Fexample.org%2F", + "word" : "drücken", + "Stra%C3%9Fe" : "Grüner Weg", + "random" : "šö䟜ñꀣ¥‡ÑÒÓÔÕÖ×ØÙÚàáâãäåæçÿ", + "assoc_special_chars" : + { "šö䟜ñꀣ¥‡ÑÒÓÔÕ" : "Ö×ØÙÚàáâãäåæçÿ" } + }, + "testcases":[ + + [ "{/id*}" , "/person" ], + [ "{/id*}{?fields,first_name,last.name,token}" , [ + "/person?fields=id,name,picture&first_name=John&last.name=Doe&token=12345", + "/person?fields=id,picture,name&first_name=John&last.name=Doe&token=12345", + "/person?fields=picture,name,id&first_name=John&last.name=Doe&token=12345", + "/person?fields=picture,id,name&first_name=John&last.name=Doe&token=12345", + "/person?fields=name,picture,id&first_name=John&last.name=Doe&token=12345", + "/person?fields=name,id,picture&first_name=John&last.name=Doe&token=12345"] + ], + ["/search.{format}{?q,geocode,lang,locale,page,result_type}", + [ "/search.json?q=URI%20Templates&geocode=37.76,-122.427&lang=en&page=5", + "/search.json?q=URI%20Templates&geocode=-122.427,37.76&lang=en&page=5"] + ], + ["/test{/Some%20Thing}", "/test/foo" ], + ["/set{?number}", "/set?number=6"], + ["/loc{?long,lat}" , "/loc?long=37.76&lat=-122.427"], + ["/base{/group_id,first_name}/pages{/page,lang}{?format,q}","/base/12345/John/pages/5/en?format=json&q=URI%20Templates"], + ["/sparql{?query}", "/sparql?query=PREFIX%20dc%3A%20%3Chttp%3A%2F%2Fpurl.org%2Fdc%2Felements%2F1.1%2F%3E%20SELECT%20%3Fbook%20%3Fwho%20WHERE%20%7B%20%3Fbook%20dc%3Acreator%20%3Fwho%20%7D"], + ["/go{?uri}", "/go?uri=http%3A%2F%2Fexample.org%2F%3Furi%3Dhttp%253A%252F%252Fexample.org%252F"], + ["/service{?word}", "/service?word=dr%C3%BCcken"], + ["/lookup{?Stra%C3%9Fe}", "/lookup?Stra%C3%9Fe=Gr%C3%BCner%20Weg"], + ["{random}" , "%C5%A1%C3%B6%C3%A4%C5%B8%C5%93%C3%B1%C3%AA%E2%82%AC%C2%A3%C2%A5%E2%80%A1%C3%91%C3%92%C3%93%C3%94%C3%95%C3%96%C3%97%C3%98%C3%99%C3%9A%C3%A0%C3%A1%C3%A2%C3%A3%C3%A4%C3%A5%C3%A6%C3%A7%C3%BF"], + ["{?assoc_special_chars*}", "?%C5%A1%C3%B6%C3%A4%C5%B8%C5%93%C3%B1%C3%AA%E2%82%AC%C2%A3%C2%A5%E2%80%A1%C3%91%C3%92%C3%93%C3%94%C3%95=%C3%96%C3%97%C3%98%C3%99%C3%9A%C3%A0%C3%A1%C3%A2%C3%A3%C3%A4%C3%A5%C3%A6%C3%A7%C3%BF"] + ] + }, + "Additional Examples 2":{ + "level":4, + "variables":{ + "id" : ["person","albums"], + "token" : "12345", + "fields" : ["id", "name", "picture"], + "format" : "atom", + "q" : "URI Templates", + "page" : "10", + "start" : "5", + "lang" : "en", + "geocode" : ["37.76","-122.427"] + }, + "testcases":[ + + [ "{/id*}" , ["/person/albums","/albums/person"] ], + [ "{/id*}{?fields,token}" , [ + "/person/albums?fields=id,name,picture&token=12345", + "/person/albums?fields=id,picture,name&token=12345", + "/person/albums?fields=picture,name,id&token=12345", + "/person/albums?fields=picture,id,name&token=12345", + "/person/albums?fields=name,picture,id&token=12345", + "/person/albums?fields=name,id,picture&token=12345", + "/albums/person?fields=id,name,picture&token=12345", + "/albums/person?fields=id,picture,name&token=12345", + "/albums/person?fields=picture,name,id&token=12345", + "/albums/person?fields=picture,id,name&token=12345", + "/albums/person?fields=name,picture,id&token=12345", + "/albums/person?fields=name,id,picture&token=12345"] + ] + ] + }, + "Additional Examples 3: Empty Variables":{ + "variables" : { + "empty_list" : [], + "empty_assoc" : {} + }, + "testcases":[ + [ "{/empty_list}", [ "" ] ], + [ "{/empty_list*}", [ "" ] ], + [ "{?empty_list}", [ ""] ], + [ "{?empty_list*}", [ "" ] ], + [ "{?empty_assoc}", [ "" ] ], + [ "{?empty_assoc*}", [ "" ] ] + ] + }, + "Additional Examples 4: Numeric Keys":{ + "variables" : { + "42" : "The Answer to the Ultimate Question of Life, the Universe, and Everything", + "1337" : ["leet", "as","it", "can","be"], + "german" : { + "11": "elf", + "12": "zwölf" + } + }, + "testcases":[ + [ "{42}", "The%20Answer%20to%20the%20Ultimate%20Question%20of%20Life%2C%20the%20Universe%2C%20and%20Everything"], + [ "{?42}", "?42=The%20Answer%20to%20the%20Ultimate%20Question%20of%20Life%2C%20the%20Universe%2C%20and%20Everything"], + [ "{1337}", "leet,as,it,can,be"], + [ "{?1337*}", "?1337=leet&1337=as&1337=it&1337=can&1337=be"], + [ "{?german*}", [ "?11=elf&12=zw%C3%B6lf", "?12=zw%C3%B6lf&11=elf"] ] + ] + } +} diff --git a/Carthage/Checkouts/URITemplate.swift/Tests/URITemplateTests/Cases/json2xml.xslt b/Carthage/Checkouts/URITemplate.swift/Tests/URITemplateTests/Cases/json2xml.xslt new file mode 100644 index 0000000..59b3548 --- /dev/null +++ b/Carthage/Checkouts/URITemplate.swift/Tests/URITemplateTests/Cases/json2xml.xslt @@ -0,0 +1,201 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \b + + + + + + + + + + + \v + + + + + \f + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Carthage/Checkouts/URITemplate.swift/Tests/URITemplateTests/Cases/negative-tests.json b/Carthage/Checkouts/URITemplate.swift/Tests/URITemplateTests/Cases/negative-tests.json new file mode 100644 index 0000000..552a6bf --- /dev/null +++ b/Carthage/Checkouts/URITemplate.swift/Tests/URITemplateTests/Cases/negative-tests.json @@ -0,0 +1,57 @@ +{ + "Failure Tests":{ + "level":4, + "variables":{ + "id" : "thing", + "var" : "value", + "hello" : "Hello World!", + "with space" : "fail", + " leading_space" : "Hi!", + "trailing_space " : "Bye!", + "empty" : "", + "path" : "/foo/bar", + "x" : "1024", + "y" : "768", + "list" : ["red", "green", "blue"], + "keys" : { "semi" : ";", "dot" : ".", "comma" : ","}, + "example" : "red", + "searchTerms" : "uri templates", + "~thing" : "some-user", + "default-graph-uri" : ["http://www.example/book/","http://www.example/papers/"], + "query" : "PREFIX dc: SELECT ?book ?who WHERE { ?book dc:creator ?who }" + + }, + "testcases":[ + [ "{/id*", false ], + [ "/id*}", false ], + [ "{/?id}", false ], + [ "{var:prefix}", false ], + [ "{hello:2*}", false ] , + [ "{??hello}", false ] , + [ "{!hello}", false ] , + [ "{with space}", false], + [ "{ leading_space}", false], + [ "{trailing_space }", false], + [ "{=path}", false ] , + [ "{$var}", false ], + [ "{|var*}", false ], + [ "{*keys?}", false ], + [ "{?empty=default,var}", false ], + [ "{var}{-prefix|/-/|var}" , false ], + [ "?q={searchTerms}&c={example:color?}" , false ], + [ "x{?empty|foo=none}" , false ], + [ "/h{#hello+}" , false ], + [ "/h#{hello+}" , false ], + [ "{keys:1}", false ], + [ "{+keys:1}", false ], + [ "{;keys:1*}", false ], + [ "?{-join|&|var,list}" , false ], + [ "/people/{~thing}", false], + [ "/{default-graph-uri}", false ], + [ "/sparql{?query,default-graph-uri}", false ], + [ "/sparql{?query){&default-graph-uri*}", false ], + [ "/resolution{?x, y}" , false ] + + ] + } +} \ No newline at end of file diff --git a/Carthage/Checkouts/URITemplate.swift/Tests/URITemplateTests/Cases/spec-examples-by-section.json b/Carthage/Checkouts/URITemplate.swift/Tests/URITemplateTests/Cases/spec-examples-by-section.json new file mode 100644 index 0000000..5aef182 --- /dev/null +++ b/Carthage/Checkouts/URITemplate.swift/Tests/URITemplateTests/Cases/spec-examples-by-section.json @@ -0,0 +1,439 @@ +{ + "3.2.1 Variable Expansion" : + { + "variables": { + "count" : ["one", "two", "three"], + "dom" : ["example", "com"], + "dub" : "me/too", + "hello" : "Hello World!", + "half" : "50%", + "var" : "value", + "who" : "fred", + "base" : "http://example.com/home/", + "path" : "/foo/bar", + "list" : ["red", "green", "blue"], + "keys" : { "semi" : ";", "dot" : ".", "comma" : ","}, + "v" : "6", + "x" : "1024", + "y" : "768", + "empty" : "", + "empty_keys" : [], + "undef" : null + }, + "testcases" : [ + ["{count}", "one,two,three"], + ["{count*}", "one,two,three"], + ["{/count}", "/one,two,three"], + ["{/count*}", "/one/two/three"], + ["{;count}", ";count=one,two,three"], + ["{;count*}", ";count=one;count=two;count=three"], + ["{?count}", "?count=one,two,three"], + ["{?count*}", "?count=one&count=two&count=three"], + ["{&count*}", "&count=one&count=two&count=three"] + ] + }, + "3.2.2 Simple String Expansion" : + { + "variables": { + "count" : ["one", "two", "three"], + "dom" : ["example", "com"], + "dub" : "me/too", + "hello" : "Hello World!", + "half" : "50%", + "var" : "value", + "who" : "fred", + "base" : "http://example.com/home/", + "path" : "/foo/bar", + "list" : ["red", "green", "blue"], + "keys" : { "semi" : ";", "dot" : ".", "comma" : ","}, + "v" : "6", + "x" : "1024", + "y" : "768", + "empty" : "", + "empty_keys" : [], + "undef" : null + }, + "testcases" : [ + ["{var}", "value"], + ["{hello}", "Hello%20World%21"], + ["{half}", "50%25"], + ["O{empty}X", "OX"], + ["O{undef}X", "OX"], + ["{x,y}", "1024,768"], + ["{x,hello,y}", "1024,Hello%20World%21,768"], + ["?{x,empty}", "?1024,"], + ["?{x,undef}", "?1024"], + ["?{undef,y}", "?768"], + ["{var:3}", "val"], + ["{var:30}", "value"], + ["{list}", "red,green,blue"], + ["{list*}", "red,green,blue"], + ["{keys}", [ + "comma,%2C,dot,.,semi,%3B", + "comma,%2C,semi,%3B,dot,.", + "dot,.,comma,%2C,semi,%3B", + "dot,.,semi,%3B,comma,%2C", + "semi,%3B,comma,%2C,dot,.", + "semi,%3B,dot,.,comma,%2C" + ]], + ["{keys*}", [ + "comma=%2C,dot=.,semi=%3B", + "comma=%2C,semi=%3B,dot=.", + "dot=.,comma=%2C,semi=%3B", + "dot=.,semi=%3B,comma=%2C", + "semi=%3B,comma=%2C,dot=.", + "semi=%3B,dot=.,comma=%2C" + ]] + ] + }, + "3.2.3 Reserved Expansion" : + { + "variables": { + "count" : ["one", "two", "three"], + "dom" : ["example", "com"], + "dub" : "me/too", + "hello" : "Hello World!", + "half" : "50%", + "var" : "value", + "who" : "fred", + "base" : "http://example.com/home/", + "path" : "/foo/bar", + "list" : ["red", "green", "blue"], + "keys" : { "semi" : ";", "dot" : ".", "comma" : ","}, + "v" : "6", + "x" : "1024", + "y" : "768", + "empty" : "", + "empty_keys" : [], + "undef" : null + }, + "testcases" : [ + ["{+var}", "value"], + ["{/var,empty}", "/value/"], + ["{/var,undef}", "/value"], + ["{+hello}", "Hello%20World!"], + ["{+half}", "50%25"], + ["{base}index", "http%3A%2F%2Fexample.com%2Fhome%2Findex"], + ["{+base}index", "http://example.com/home/index"], + ["O{+empty}X", "OX"], + ["O{+undef}X", "OX"], + ["{+path}/here", "/foo/bar/here"], + ["{+path:6}/here", "/foo/b/here"], + ["here?ref={+path}", "here?ref=/foo/bar"], + ["up{+path}{var}/here", "up/foo/barvalue/here"], + ["{+x,hello,y}", "1024,Hello%20World!,768"], + ["{+path,x}/here", "/foo/bar,1024/here"], + ["{+list}", "red,green,blue"], + ["{+list*}", "red,green,blue"], + ["{+keys}", [ + "comma,,,dot,.,semi,;", + "comma,,,semi,;,dot,.", + "dot,.,comma,,,semi,;", + "dot,.,semi,;,comma,,", + "semi,;,comma,,,dot,.", + "semi,;,dot,.,comma,," + ]], + ["{+keys*}", [ + "comma=,,dot=.,semi=;", + "comma=,,semi=;,dot=.", + "dot=.,comma=,,semi=;", + "dot=.,semi=;,comma=,", + "semi=;,comma=,,dot=.", + "semi=;,dot=.,comma=," + ]] + ] + }, + "3.2.4 Fragment Expansion" : + { + "variables": { + "count" : ["one", "two", "three"], + "dom" : ["example", "com"], + "dub" : "me/too", + "hello" : "Hello World!", + "half" : "50%", + "var" : "value", + "who" : "fred", + "base" : "http://example.com/home/", + "path" : "/foo/bar", + "list" : ["red", "green", "blue"], + "keys" : { "semi" : ";", "dot" : ".", "comma" : ","}, + "v" : "6", + "x" : "1024", + "y" : "768", + "empty" : "", + "empty_keys" : [], + "undef" : null + }, + "testcases" : [ + ["{#var}", "#value"], + ["{#hello}", "#Hello%20World!"], + ["{#half}", "#50%25"], + ["foo{#empty}", "foo#"], + ["foo{#undef}", "foo"], + ["{#x,hello,y}", "#1024,Hello%20World!,768"], + ["{#path,x}/here", "#/foo/bar,1024/here"], + ["{#path:6}/here", "#/foo/b/here"], + ["{#list}", "#red,green,blue"], + ["{#list*}", "#red,green,blue"], + ["{#keys}", [ + "#comma,,,dot,.,semi,;", + "#comma,,,semi,;,dot,.", + "#dot,.,comma,,,semi,;", + "#dot,.,semi,;,comma,,", + "#semi,;,comma,,,dot,.", + "#semi,;,dot,.,comma,," + ]] + ] + }, + "3.2.5 Label Expansion with Dot-Prefix" : + { + "variables": { + "count" : ["one", "two", "three"], + "dom" : ["example", "com"], + "dub" : "me/too", + "hello" : "Hello World!", + "half" : "50%", + "var" : "value", + "who" : "fred", + "base" : "http://example.com/home/", + "path" : "/foo/bar", + "list" : ["red", "green", "blue"], + "keys" : { "semi" : ";", "dot" : ".", "comma" : ","}, + "v" : "6", + "x" : "1024", + "y" : "768", + "empty" : "", + "empty_keys" : [], + "undef" : null + }, + "testcases" : [ + ["{.who}", ".fred"], + ["{.who,who}", ".fred.fred"], + ["{.half,who}", ".50%25.fred"], + ["www{.dom*}", "www.example.com"], + ["X{.var}", "X.value"], + ["X{.var:3}", "X.val"], + ["X{.empty}", "X."], + ["X{.undef}", "X"], + ["X{.list}", "X.red,green,blue"], + ["X{.list*}", "X.red.green.blue"], + ["{#keys}", [ + "#comma,,,dot,.,semi,;", + "#comma,,,semi,;,dot,.", + "#dot,.,comma,,,semi,;", + "#dot,.,semi,;,comma,,", + "#semi,;,comma,,,dot,.", + "#semi,;,dot,.,comma,," + ]], + ["{#keys*}", [ + "#comma=,,dot=.,semi=;", + "#comma=,,semi=;,dot=.", + "#dot=.,comma=,,semi=;", + "#dot=.,semi=;,comma=,", + "#semi=;,comma=,,dot=.", + "#semi=;,dot=.,comma=," + ]], + ["X{.empty_keys}", "X"], + ["X{.empty_keys*}", "X"] + ] + }, + "3.2.6 Path Segment Expansion" : + { + "variables": { + "count" : ["one", "two", "three"], + "dom" : ["example", "com"], + "dub" : "me/too", + "hello" : "Hello World!", + "half" : "50%", + "var" : "value", + "who" : "fred", + "base" : "http://example.com/home/", + "path" : "/foo/bar", + "list" : ["red", "green", "blue"], + "keys" : { "semi" : ";", "dot" : ".", "comma" : ","}, + "v" : "6", + "x" : "1024", + "y" : "768", + "empty" : "", + "empty_keys" : [], + "undef" : null + }, + "testcases" : [ + ["{/who}", "/fred"], + ["{/who,who}", "/fred/fred"], + ["{/half,who}", "/50%25/fred"], + ["{/who,dub}", "/fred/me%2Ftoo"], + ["{/var}", "/value"], + ["{/var,empty}", "/value/"], + ["{/var,undef}", "/value"], + ["{/var,x}/here", "/value/1024/here"], + ["{/var:1,var}", "/v/value"], + ["{/list}", "/red,green,blue"], + ["{/list*}", "/red/green/blue"], + ["{/list*,path:4}", "/red/green/blue/%2Ffoo"], + ["{/keys}", [ + "/comma,%2C,dot,.,semi,%3B", + "/comma,%2C,semi,%3B,dot,.", + "/dot,.,comma,%2C,semi,%3B", + "/dot,.,semi,%3B,comma,%2C", + "/semi,%3B,comma,%2C,dot,.", + "/semi,%3B,dot,.,comma,%2C" + ]], + ["{/keys*}", [ + "/comma=%2C/dot=./semi=%3B", + "/comma=%2C/semi=%3B/dot=.", + "/dot=./comma=%2C/semi=%3B", + "/dot=./semi=%3B/comma=%2C", + "/semi=%3B/comma=%2C/dot=.", + "/semi=%3B/dot=./comma=%2C" + ]] + ] + }, + "3.2.7 Path-Style Parameter Expansion" : + { + "variables": { + "count" : ["one", "two", "three"], + "dom" : ["example", "com"], + "dub" : "me/too", + "hello" : "Hello World!", + "half" : "50%", + "var" : "value", + "who" : "fred", + "base" : "http://example.com/home/", + "path" : "/foo/bar", + "list" : ["red", "green", "blue"], + "keys" : { "semi" : ";", "dot" : ".", "comma" : ","}, + "v" : "6", + "x" : "1024", + "y" : "768", + "empty" : "", + "empty_keys" : [], + "undef" : null + }, + "testcases" : [ + ["{;who}", ";who=fred"], + ["{;half}", ";half=50%25"], + ["{;empty}", ";empty"], + ["{;hello:5}", ";hello=Hello"], + ["{;v,empty,who}", ";v=6;empty;who=fred"], + ["{;v,bar,who}", ";v=6;who=fred"], + ["{;x,y}", ";x=1024;y=768"], + ["{;x,y,empty}", ";x=1024;y=768;empty"], + ["{;x,y,undef}", ";x=1024;y=768"], + ["{;list}", ";list=red,green,blue"], + ["{;list*}", ";list=red;list=green;list=blue"], + ["{;keys}", [ + ";keys=comma,%2C,dot,.,semi,%3B", + ";keys=comma,%2C,semi,%3B,dot,.", + ";keys=dot,.,comma,%2C,semi,%3B", + ";keys=dot,.,semi,%3B,comma,%2C", + ";keys=semi,%3B,comma,%2C,dot,.", + ";keys=semi,%3B,dot,.,comma,%2C" + ]], + ["{;keys*}", [ + ";comma=%2C;dot=.;semi=%3B", + ";comma=%2C;semi=%3B;dot=.", + ";dot=.;comma=%2C;semi=%3B", + ";dot=.;semi=%3B;comma=%2C", + ";semi=%3B;comma=%2C;dot=.", + ";semi=%3B;dot=.;comma=%2C" + ]] + ] + }, + "3.2.8 Form-Style Query Expansion" : + { + "variables": { + "count" : ["one", "two", "three"], + "dom" : ["example", "com"], + "dub" : "me/too", + "hello" : "Hello World!", + "half" : "50%", + "var" : "value", + "who" : "fred", + "base" : "http://example.com/home/", + "path" : "/foo/bar", + "list" : ["red", "green", "blue"], + "keys" : { "semi" : ";", "dot" : ".", "comma" : ","}, + "v" : "6", + "x" : "1024", + "y" : "768", + "empty" : "", + "empty_keys" : [], + "undef" : null + }, + "testcases" : [ + ["{?who}", "?who=fred"], + ["{?half}", "?half=50%25"], + ["{?x,y}", "?x=1024&y=768"], + ["{?x,y,empty}", "?x=1024&y=768&empty="], + ["{?x,y,undef}", "?x=1024&y=768"], + ["{?var:3}", "?var=val"], + ["{?list}", "?list=red,green,blue"], + ["{?list*}", "?list=red&list=green&list=blue"], + ["{?keys}", [ + "?keys=comma,%2C,dot,.,semi,%3B", + "?keys=comma,%2C,semi,%3B,dot,.", + "?keys=dot,.,comma,%2C,semi,%3B", + "?keys=dot,.,semi,%3B,comma,%2C", + "?keys=semi,%3B,comma,%2C,dot,.", + "?keys=semi,%3B,dot,.,comma,%2C" + ]], + ["{?keys*}", [ + "?comma=%2C&dot=.&semi=%3B", + "?comma=%2C&semi=%3B&dot=.", + "?dot=.&comma=%2C&semi=%3B", + "?dot=.&semi=%3B&comma=%2C", + "?semi=%3B&comma=%2C&dot=.", + "?semi=%3B&dot=.&comma=%2C" + ]] + ] + }, + "3.2.9 Form-Style Query Continuation" : + { + "variables": { + "count" : ["one", "two", "three"], + "dom" : ["example", "com"], + "dub" : "me/too", + "hello" : "Hello World!", + "half" : "50%", + "var" : "value", + "who" : "fred", + "base" : "http://example.com/home/", + "path" : "/foo/bar", + "list" : ["red", "green", "blue"], + "keys" : { "semi" : ";", "dot" : ".", "comma" : ","}, + "v" : "6", + "x" : "1024", + "y" : "768", + "empty" : "", + "empty_keys" : [], + "undef" : null + }, + "testcases" : [ + ["{&who}", "&who=fred"], + ["{&half}", "&half=50%25"], + ["?fixed=yes{&x}", "?fixed=yes&x=1024"], + ["{&var:3}", "&var=val"], + ["{&x,y,empty}", "&x=1024&y=768&empty="], + ["{&x,y,undef}", "&x=1024&y=768"], + ["{&list}", "&list=red,green,blue"], + ["{&list*}", "&list=red&list=green&list=blue"], + ["{&keys}", [ + "&keys=comma,%2C,dot,.,semi,%3B", + "&keys=comma,%2C,semi,%3B,dot,.", + "&keys=dot,.,comma,%2C,semi,%3B", + "&keys=dot,.,semi,%3B,comma,%2C", + "&keys=semi,%3B,comma,%2C,dot,.", + "&keys=semi,%3B,dot,.,comma,%2C" + ]], + ["{&keys*}", [ + "&comma=%2C&dot=.&semi=%3B", + "&comma=%2C&semi=%3B&dot=.", + "&dot=.&comma=%2C&semi=%3B", + "&dot=.&semi=%3B&comma=%2C", + "&semi=%3B&comma=%2C&dot=.", + "&semi=%3B&dot=.&comma=%2C" + ]] + ] + } +} diff --git a/Carthage/Checkouts/URITemplate.swift/Tests/URITemplateTests/Cases/spec-examples.json b/Carthage/Checkouts/URITemplate.swift/Tests/URITemplateTests/Cases/spec-examples.json new file mode 100644 index 0000000..2e8e942 --- /dev/null +++ b/Carthage/Checkouts/URITemplate.swift/Tests/URITemplateTests/Cases/spec-examples.json @@ -0,0 +1,218 @@ +{ + "Level 1 Examples" : + { + "level": 1, + "variables": { + "var" : "value", + "hello" : "Hello World!" + }, + "testcases" : [ + ["{var}", "value"], + ["{hello}", "Hello%20World%21"] + ] + }, + "Level 2 Examples" : + { + "level": 2, + "variables": { + "var" : "value", + "hello" : "Hello World!", + "path" : "/foo/bar" + }, + "testcases" : [ + ["{+var}", "value"], + ["{+hello}", "Hello%20World!"], + ["{+path}/here", "/foo/bar/here"], + ["here?ref={+path}", "here?ref=/foo/bar"] + ] + }, + "Level 3 Examples" : + { + "level": 3, + "variables": { + "var" : "value", + "hello" : "Hello World!", + "empty" : "", + "path" : "/foo/bar", + "x" : "1024", + "y" : "768" + }, + "testcases" : [ + ["map?{x,y}", "map?1024,768"], + ["{x,hello,y}", "1024,Hello%20World%21,768"], + ["{+x,hello,y}", "1024,Hello%20World!,768"], + ["{+path,x}/here", "/foo/bar,1024/here"], + ["{#x,hello,y}", "#1024,Hello%20World!,768"], + ["{#path,x}/here", "#/foo/bar,1024/here"], + ["X{.var}", "X.value"], + ["X{.x,y}", "X.1024.768"], + ["{/var}", "/value"], + ["{/var,x}/here", "/value/1024/here"], + ["{;x,y}", ";x=1024;y=768"], + ["{;x,y,empty}", ";x=1024;y=768;empty"], + ["{?x,y}", "?x=1024&y=768"], + ["{?x,y,empty}", "?x=1024&y=768&empty="], + ["?fixed=yes{&x}", "?fixed=yes&x=1024"], + ["{&x,y,empty}", "&x=1024&y=768&empty="] + ] + }, + "Level 4 Examples" : + { + "level": 4, + "variables": { + "var": "value", + "hello": "Hello World!", + "path": "/foo/bar", + "list": ["red", "green", "blue"], + "keys": {"semi": ";", "dot": ".", "comma":","} + }, + "testcases": [ + ["{var:3}", "val"], + ["{var:30}", "value"], + ["{list}", "red,green,blue"], + ["{list*}", "red,green,blue"], + ["{keys}", [ + "comma,%2C,dot,.,semi,%3B", + "comma,%2C,semi,%3B,dot,.", + "dot,.,comma,%2C,semi,%3B", + "dot,.,semi,%3B,comma,%2C", + "semi,%3B,comma,%2C,dot,.", + "semi,%3B,dot,.,comma,%2C" + ]], + ["{keys*}", [ + "comma=%2C,dot=.,semi=%3B", + "comma=%2C,semi=%3B,dot=.", + "dot=.,comma=%2C,semi=%3B", + "dot=.,semi=%3B,comma=%2C", + "semi=%3B,comma=%2C,dot=.", + "semi=%3B,dot=.,comma=%2C" + ]], + ["{+path:6}/here", "/foo/b/here"], + ["{+list}", "red,green,blue"], + ["{+list*}", "red,green,blue"], + ["{+keys}", [ + "comma,,,dot,.,semi,;", + "comma,,,semi,;,dot,.", + "dot,.,comma,,,semi,;", + "dot,.,semi,;,comma,,", + "semi,;,comma,,,dot,.", + "semi,;,dot,.,comma,," + ]], + ["{+keys*}", [ + "comma=,,dot=.,semi=;", + "comma=,,semi=;,dot=.", + "dot=.,comma=,,semi=;", + "dot=.,semi=;,comma=,", + "semi=;,comma=,,dot=.", + "semi=;,dot=.,comma=," + ]], + ["{#path:6}/here", "#/foo/b/here"], + ["{#list}", "#red,green,blue"], + ["{#list*}", "#red,green,blue"], + ["{#keys}", [ + "#comma,,,dot,.,semi,;", + "#comma,,,semi,;,dot,.", + "#dot,.,comma,,,semi,;", + "#dot,.,semi,;,comma,,", + "#semi,;,comma,,,dot,.", + "#semi,;,dot,.,comma,," + ]], + ["{#keys*}", [ + "#comma=,,dot=.,semi=;", + "#comma=,,semi=;,dot=.", + "#dot=.,comma=,,semi=;", + "#dot=.,semi=;,comma=,", + "#semi=;,comma=,,dot=.", + "#semi=;,dot=.,comma=," + ]], + ["X{.var:3}", "X.val"], + ["X{.list}", "X.red,green,blue"], + ["X{.list*}", "X.red.green.blue"], + ["X{.keys}", [ + "X.comma,%2C,dot,.,semi,%3B", + "X.comma,%2C,semi,%3B,dot,.", + "X.dot,.,comma,%2C,semi,%3B", + "X.dot,.,semi,%3B,comma,%2C", + "X.semi,%3B,comma,%2C,dot,.", + "X.semi,%3B,dot,.,comma,%2C" + ]], + ["{/var:1,var}", "/v/value"], + ["{/list}", "/red,green,blue"], + ["{/list*}", "/red/green/blue"], + ["{/list*,path:4}", "/red/green/blue/%2Ffoo"], + ["{/keys}", [ + "/comma,%2C,dot,.,semi,%3B", + "/comma,%2C,semi,%3B,dot,.", + "/dot,.,comma,%2C,semi,%3B", + "/dot,.,semi,%3B,comma,%2C", + "/semi,%3B,comma,%2C,dot,.", + "/semi,%3B,dot,.,comma,%2C" + ]], + ["{/keys*}", [ + "/comma=%2C/dot=./semi=%3B", + "/comma=%2C/semi=%3B/dot=.", + "/dot=./comma=%2C/semi=%3B", + "/dot=./semi=%3B/comma=%2C", + "/semi=%3B/comma=%2C/dot=.", + "/semi=%3B/dot=./comma=%2C" + ]], + ["{;hello:5}", ";hello=Hello"], + ["{;list}", ";list=red,green,blue"], + ["{;list*}", ";list=red;list=green;list=blue"], + ["{;keys}", [ + ";keys=comma,%2C,dot,.,semi,%3B", + ";keys=comma,%2C,semi,%3B,dot,.", + ";keys=dot,.,comma,%2C,semi,%3B", + ";keys=dot,.,semi,%3B,comma,%2C", + ";keys=semi,%3B,comma,%2C,dot,.", + ";keys=semi,%3B,dot,.,comma,%2C" + ]], + ["{;keys*}", [ + ";comma=%2C;dot=.;semi=%3B", + ";comma=%2C;semi=%3B;dot=.", + ";dot=.;comma=%2C;semi=%3B", + ";dot=.;semi=%3B;comma=%2C", + ";semi=%3B;comma=%2C;dot=.", + ";semi=%3B;dot=.;comma=%2C" + ]], + ["{?var:3}", "?var=val"], + ["{?list}", "?list=red,green,blue"], + ["{?list*}", "?list=red&list=green&list=blue"], + ["{?keys}", [ + "?keys=comma,%2C,dot,.,semi,%3B", + "?keys=comma,%2C,semi,%3B,dot,.", + "?keys=dot,.,comma,%2C,semi,%3B", + "?keys=dot,.,semi,%3B,comma,%2C", + "?keys=semi,%3B,comma,%2C,dot,.", + "?keys=semi,%3B,dot,.,comma,%2C" + ]], + ["{?keys*}", [ + "?comma=%2C&dot=.&semi=%3B", + "?comma=%2C&semi=%3B&dot=.", + "?dot=.&comma=%2C&semi=%3B", + "?dot=.&semi=%3B&comma=%2C", + "?semi=%3B&comma=%2C&dot=.", + "?semi=%3B&dot=.&comma=%2C" + ]], + ["{&var:3}", "&var=val"], + ["{&list}", "&list=red,green,blue"], + ["{&list*}", "&list=red&list=green&list=blue"], + ["{&keys}", [ + "&keys=comma,%2C,dot,.,semi,%3B", + "&keys=comma,%2C,semi,%3B,dot,.", + "&keys=dot,.,comma,%2C,semi,%3B", + "&keys=dot,.,semi,%3B,comma,%2C", + "&keys=semi,%3B,comma,%2C,dot,.", + "&keys=semi,%3B,dot,.,comma,%2C" + ]], + ["{&keys*}", [ + "&comma=%2C&dot=.&semi=%3B", + "&comma=%2C&semi=%3B&dot=.", + "&dot=.&comma=%2C&semi=%3B", + "&dot=.&semi=%3B&comma=%2C", + "&semi=%3B&comma=%2C&dot=.", + "&semi=%3B&dot=.&comma=%2C" + ]] + ] + } +} diff --git a/Carthage/Checkouts/URITemplate.swift/Tests/URITemplateTests/Cases/transform-json-tests.xslt b/Carthage/Checkouts/URITemplate.swift/Tests/URITemplateTests/Cases/transform-json-tests.xslt new file mode 100644 index 0000000..d956b6b --- /dev/null +++ b/Carthage/Checkouts/URITemplate.swift/Tests/URITemplateTests/Cases/transform-json-tests.xslt @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Carthage/Checkouts/URITemplate.swift/Tests/URITemplateTests/URITemplateCases.swift b/Carthage/Checkouts/URITemplate.swift/Tests/URITemplateTests/URITemplateCases.swift new file mode 100644 index 0000000..9cd1364 --- /dev/null +++ b/Carthage/Checkouts/URITemplate.swift/Tests/URITemplateTests/URITemplateCases.swift @@ -0,0 +1,108 @@ +import Foundation +import Spectre +import PathKit +import URITemplate + + +let testCases: ((ContextType) -> Void) = { + let files = [ + "extended-tests", + "spec-examples-by-section", + "spec-examples" + ] + + let supportedExpansionLevel = 4 + let supportedExtractionLevel = 3 + + for file in files { + $0.describe("Test Case File \(file)") { + let path = Path(#file) + ".." + "Cases" + "\(file).json" + let content = try! JSONSerialization.jsonObject(with: try! path.read(), options: []) as! [String: AnyObject] + let suites = content + .map { Suite(name: $0.0, testSuite: $0.1 as! [String: AnyObject]) } + + for suite in suites { + $0.describe("Suite \(suite.name)") { + let expansionDescribe = (supportedExpansionLevel >= suite.level) ? $0.describe : $0.xdescribe + expansionDescribe("expansion") { + for (index, testcase) in suite.cases.enumerated() { + $0.it("can expand case \(index + 1) (\(testcase.uriTemplate))") { + let expanded = testcase.uriTemplate.expand(suite.variables) + try expect(testcase.expected.contains(expanded)).to.beTrue() + } + } + } + + let extractionDescribe = (supportedExtractionLevel >= suite.level) ? $0.describe : $0.xdescribe + extractionDescribe("extraction") { + for (index, testcase) in suite.cases.enumerated() { + $0.describe("can extract case \(index + 1) (\(testcase.uriTemplate))") { + let template = testcase.uriTemplate + + for (index, uri) in testcase.expected.enumerated() { + $0.it("URI \(index + 1)") { + if let variables = template.extract(uri) { + var expectedVariables: [String: String] = [:] + + for variable in template.variables { + if let value:AnyObject = variables[variable] as AnyObject? { + expectedVariables[variable] = "\(value)" + } else { + throw failure("Missing Variable \(variable) from `\(uri)` with template `\(template)`") + } + } + + try expect(variables as NSDictionary) == expectedVariables as NSDictionary + } else { + throw failure("Extracted no match template: \(template) with uri: \(uri)") + } + } + } + } + } + } + } + } + } + } +} + +// MARK: Suite Structures + +struct Suite { + let name:String + let variables:Dictionary + let cases:[Case] + let level:Int + + init(name:String, testSuite:Dictionary) { + self.name = name + variables = testSuite["variables"] as! Dictionary + let testcases = testSuite["testcases"] as! [[AnyObject]] + cases = testcases.map { Case(object:$0) } + + if let testLevel = testSuite["level"] as? Int { + level = testLevel + } else { + level = 4 + } + } +} + +struct Case { + let template:String + let expected:[String] + + init(object:[AnyObject]) { + template = object[0] as! String + if let expected = object[1] as? [String] { + self.expected = expected + } else { + expected = [object[1] as! String] + } + } + + var uriTemplate:URITemplate { + return URITemplate(template:template) + } +} diff --git a/Carthage/Checkouts/URITemplate.swift/Tests/URITemplateTests/URITemplateExpansionTests.swift b/Carthage/Checkouts/URITemplate.swift/Tests/URITemplateTests/URITemplateExpansionTests.swift new file mode 100644 index 0000000..2f33642 --- /dev/null +++ b/Carthage/Checkouts/URITemplate.swift/Tests/URITemplateTests/URITemplateExpansionTests.swift @@ -0,0 +1,87 @@ +import Spectre +import URITemplate + + +let testExpansion: ((ContextType) -> Void) = { + $0.it("can expand basic template") { + let template = URITemplate(template:"{name}") + let expanded = template.expand(["name": "Kyle's"]) + try expect(expanded) == "Kyle%27s" + } + + $0.it("can expand reserve extensions") { + let template = URITemplate(template:"{+path}/here") + let expanded = template.expand(["path": "/its"]) + try expect(expanded) == "/its/here" + } + + $0.it("can expand fragments") { + let template = URITemplate(template:"{#value}") + let expanded = template.expand(["value": "Hello World!"]) + try expect(expanded) == "#Hello%20World!" + } + + $0.it("can expand labels") { + let template = URITemplate(template:"{.who}") + let expanded = template.expand(["who": "kyle"]) + try expect(expanded) == ".kyle" + } + + $0.it("can expand path style parameters") { + let template = URITemplate(template:"{;who}") + let expanded = template.expand(["who": "kyle"]) + try expect(expanded) == ";who=kyle" + } + + $0.it("can expand form style query") { + let template = URITemplate(template:"{?who}") + let expanded = template.expand(["who": "kyle"]) + try expect(expanded) == "?who=kyle" + } + + $0.it("can expand form style query continuation") { + let template = URITemplate(template:"{&who}") + let expanded = template.expand(["who": "kyle"]) + try expect(expanded) == "&who=kyle" + } + + $0.it("truncates length during prefix expansion") { + let template = URITemplate(template:"{name:1}") + let expanded = template.expand(["name": "Kyle's"]) + try expect(expanded) == "K" + } + + $0.describe("array joining") { + $0.it("can join basic array") { + let template = URITemplate(template:"{names}") + let expanded = template.expand(["names": ["Kyle", "Katie"]]) + try expect(expanded) == "Kyle,Katie" + } + + $0.it("can join exploded array") { + let template = URITemplate(template:"{.names*}") + let expanded = template.expand(["names": ["Kyle", "Maxine"]]) + try expect(expanded) == ".Kyle.Maxine" + } + } + + $0.describe("URL Encoding") { + $0.it("encodes spaces") { + let template = URITemplate(template:"{?postal}") + let expanded = template.expand(["postal": "V3N 2R2"]) + try expect(expanded) == "?postal=V3N%202R2" + } + + $0.it("encodes quotes") { + let template = URITemplate(template:"{?test}") + let expanded = template.expand(["test": "\"V3N\""]) + try expect(expanded) == "?test=%22V3N%22" + } + + $0.it("encodes carrots") { + let template = URITemplate(template:"{?test}") + let expanded = template.expand(["test": "V3N^2R2"]) + try expect(expanded) == "?test=V3N%5E2R2" + } + } +} diff --git a/Carthage/Checkouts/URITemplate.swift/Tests/URITemplateTests/URITemplateExtractTests.swift b/Carthage/Checkouts/URITemplate.swift/Tests/URITemplateTests/URITemplateExtractTests.swift new file mode 100644 index 0000000..8bc2ffe --- /dev/null +++ b/Carthage/Checkouts/URITemplate.swift/Tests/URITemplateTests/URITemplateExtractTests.swift @@ -0,0 +1,32 @@ +import Spectre +import URITemplate + + +let testExtract: ((ContextType) -> Void) = { + $0.it("can extract a basic variable") { + let template = URITemplate(template: "{variable}") + let values = template.extract("value") + + try expect(values) == ["variable": "value"] + } + + $0.it("handles composite values") { + let template = URITemplate(template: "https://api.github.com/repos/{owner}/{repo}/") + try expect(template.extract("https://api.github.com/repos/kylef/PathKit/")) == ["owner":"kylef", "repo":"PathKit"] + } + + $0.it("matches without variables") { + let template = URITemplate(template:"https://api.github.com/repos/kylef/URITemplate") + try expect(template.extract("https://api.github.com/repos/kylef/URITemplate")?.count) == 0 + } + + $0.it("doesn't match with different URL without variables") { + let template = URITemplate(template:"https://api.github.com/repos/kylef/URITemplate") + try expect(template.extract("https://api.github.com/repos/kylef/PatkKit")).to.beNil() + } + + $0.it("doesn't match with different URL with variables") { + let template = URITemplate(template:"https://api.github.com/repos/{owner}") + try expect(template.extract("https://api.github.com/repos/kylef/WebLinking")).to.beNil() + } +} diff --git a/Carthage/Checkouts/URITemplate.swift/Tests/URITemplateTests/URITemplateVariablesTests.swift b/Carthage/Checkouts/URITemplate.swift/Tests/URITemplateTests/URITemplateVariablesTests.swift new file mode 100644 index 0000000..88d3187 --- /dev/null +++ b/Carthage/Checkouts/URITemplate.swift/Tests/URITemplateTests/URITemplateVariablesTests.swift @@ -0,0 +1,60 @@ +import Spectre +import URITemplate + + +let testVariables: ((ContextType) -> Void) = { + $0.it("can extract variables") { + let template = URITemplate(template:"{scheme}://{hostname}/") + try expect(template.variables) == ["scheme", "hostname"] + } + + $0.it("can extract multiple variables in an expression") { + let template = URITemplate(template:"test/{a,b}") + try expect(template.variables) == ["a", "b"] + } + + $0.it("can extract reserved variables in an expression") { + let template = URITemplate(template:"test/{+reserved}") + try expect(template.variables) == ["reserved"] + } + + $0.it("can extract label variables in an expression") { + let template = URITemplate(template:"test/{.label}") + try expect(template.variables) == ["label"] + } + + $0.it("can extract fragment variables in an expression") { + let template = URITemplate(template:"test/{#fragment}") + try expect(template.variables) == ["fragment"] + } + + $0.it("can extract segment variables in an expression") { + let template = URITemplate(template:"test/{/segment}") + try expect(template.variables) == ["segment"] + } + + $0.it("can extract parameter variables in an expression") { + let template = URITemplate(template:"test/{;parameter}") + try expect(template.variables) == ["parameter"] + } + + $0.it("can form style query variables in an expression") { + let template = URITemplate(template:"test/{?query}") + try expect(template.variables) == ["query"] + } + + $0.it("can extract form style query continuation variables in an expression") { + let template = URITemplate(template:"test/{&continuation}") + try expect(template.variables) == ["continuation"] + } + + $0.it("can extract composite values") { + let template = URITemplate(template:"{/list*}") + try expect(template.variables) == ["list"] + } + + $0.it("can extract mixed query/parameter variables") { + let template = URITemplate(template:"{scheme}://{hostname}/endpoint.json{?query,list*}") + try expect(template.variables.contains("hostname")).to.beTrue() + } +} diff --git a/Carthage/Checkouts/URITemplate.swift/Tests/URITemplateTests/XCTest.swift b/Carthage/Checkouts/URITemplate.swift/Tests/URITemplateTests/XCTest.swift new file mode 100644 index 0000000..3475220 --- /dev/null +++ b/Carthage/Checkouts/URITemplate.swift/Tests/URITemplateTests/XCTest.swift @@ -0,0 +1,57 @@ +import Foundation +import XCTest +import Spectre +import URITemplate + + +public func testURITemplate() { + describe("URI Template") { + $0.it("exposes the template as a property") { + let uri = URITemplate(template:"{scheme}://{hostname}/") + try expect(uri.template) == "{scheme}://{hostname}/" + } + + $0.it("is printable") { + let template = URITemplate(template:"{scheme}://{hostname}/") + try expect("\(template)") == "{scheme}://{hostname}/" + } + + $0.describe("Equatable") { + $0.it("compares two equal templates") { + let template1 = URITemplate(template:"{scheme}://{hostname}/") + let template2 = URITemplate(template:"{scheme}://{hostname}/") + try expect(template1) == template2 + } + + $0.it("compares two different templates") { + let template1 = URITemplate(template:"{scheme}://{hostname}/") + let template2 = URITemplate(template:"{scheme}://{hostname}{path}") + try expect(template1) != template2 + } + } + + $0.it("has a hashValue") { + let template1 = URITemplate(template:"{scheme}://{hostname}/") + let template2 = URITemplate(template:"{scheme}://{hostname}/") + try expect(template1.hashValue) == template2.hashValue + } + + $0.it("is StringLiteralConvertible") { + let literalTemplate:URITemplate = "{scheme}://{hostname}/" + let template = URITemplate(template:"{scheme}://{hostname}/") + + try expect(literalTemplate) == template + } + + $0.describe("expansion", closure: testExpansion) + $0.describe("variables", closure: testVariables) + $0.describe("integration", closure: testCases) + } +} + + +class URITemplateTests: XCTestCase { + func testRunURITemplate() { + testURITemplate() + } +} diff --git a/Carthage/Checkouts/URITemplate.swift/URITemplate.podspec b/Carthage/Checkouts/URITemplate.swift/URITemplate.podspec new file mode 100644 index 0000000..e271b91 --- /dev/null +++ b/Carthage/Checkouts/URITemplate.swift/URITemplate.podspec @@ -0,0 +1,17 @@ +Pod::Spec.new do |spec| + spec.name = 'URITemplate' + spec.version = '2.0.3' + spec.summary = 'Swift library for dealing with URI Templates (RFC6570)' + spec.homepage = 'https://github.com/kylef/URITemplate.swift' + spec.license = { :type => 'MIT', :file => 'LICENSE' } + spec.author = { 'Kyle Fuller' => 'kyle@fuller.li' } + spec.social_media_url = 'http://twitter.com/kylefuller' + spec.source = { :git => 'https://github.com/kylef/URITemplate.swift.git', :tag => "#{spec.version}" } + spec.source_files = 'Sources/*.{h,swift}' + spec.ios.deployment_target = '8.0' + spec.osx.deployment_target = '10.9' + spec.watchos.deployment_target = '2.0' + spec.tvos.deployment_target = '9.0' + spec.requires_arc = true +end + diff --git a/Mockingjay.xcodeproj/project.pbxproj b/Mockingjay.xcodeproj/project.pbxproj index 12eb78f..2c82d40 100644 --- a/Mockingjay.xcodeproj/project.pbxproj +++ b/Mockingjay.xcodeproj/project.pbxproj @@ -8,7 +8,6 @@ /* Begin PBXBuildFile section */ 2705946B1C4FA7A6002A3AA9 /* MockingjayXCTestTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2705946A1C4FA7A6002A3AA9 /* MockingjayXCTestTests.swift */; }; - 2715FACF1D8C81AB00A89DF7 /* URITemplate.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2715FAC91D8C818C00A89DF7 /* URITemplate.framework */; }; 274367921AA27A7C0030C97B /* Mockingjay.swift in Sources */ = {isa = PBXBuildFile; fileRef = 274367911AA27A7C0030C97B /* Mockingjay.swift */; }; 274367941AA27AAD0030C97B /* MockingjayProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 274367931AA27AAD0030C97B /* MockingjayProtocol.swift */; }; 274367961AA27B170030C97B /* MockingjayProtocolTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 274367951AA27B170030C97B /* MockingjayProtocolTests.swift */; }; @@ -23,50 +22,50 @@ 27703A631CE2560600194732 /* MockingjayURLSessionConfiguration.m in Sources */ = {isa = PBXBuildFile; fileRef = 27703A621CE2560600194732 /* MockingjayURLSessionConfiguration.m */; }; 444EA6091C5261DE000C3A9F /* MockingjayAsyncProtocolTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 444EA6081C5261DE000C3A9F /* MockingjayAsyncProtocolTests.swift */; }; 444EA60C1C52666D000C3A9F /* TestAudio.m4a in Resources */ = {isa = PBXBuildFile; fileRef = 444EA60B1C52666D000C3A9F /* TestAudio.m4a */; }; - A1E3C5701AA4EA130069C998 /* XCTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2743679B1AA28D4D0030C97B /* XCTest.swift */; }; + 532D00DA2060B91A0009340F /* URITemplate.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 532D00D42060B90D0009340F /* URITemplate.framework */; }; + 532D00E62060C1260009340F /* XCTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2743679B1AA28D4D0030C97B /* XCTest.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ - 2715FAC41D8C818C00A89DF7 /* PBXContainerItemProxy */ = { + 2746CDCC1A702F7800719B66 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; - containerPortal = 2715FABD1D8C818C00A89DF7 /* URITemplate.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = "_____Product_Spectre"; - remoteInfo = Spectre; + containerPortal = 2746CDB61A702F7800719B66 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 2746CDBE1A702F7800719B66; + remoteInfo = Mockingjay; }; - 2715FAC61D8C818C00A89DF7 /* PBXContainerItemProxy */ = { + 532D00D12060B90D0009340F /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; - containerPortal = 2715FABD1D8C818C00A89DF7 /* URITemplate.xcodeproj */; + containerPortal = 532D00C62060B90C0009340F /* URITemplate.xcodeproj */; proxyType = 2; - remoteGlobalIDString = "_____Product_PathKit"; - remoteInfo = PathKit; + remoteGlobalIDString = "URITemplate::URITemplateTests::Product"; + remoteInfo = URITemplateTests; }; - 2715FAC81D8C818C00A89DF7 /* PBXContainerItemProxy */ = { + 532D00D32060B90D0009340F /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; - containerPortal = 2715FABD1D8C818C00A89DF7 /* URITemplate.xcodeproj */; + containerPortal = 532D00C62060B90C0009340F /* URITemplate.xcodeproj */; proxyType = 2; - remoteGlobalIDString = "_____Product_URITemplate"; + remoteGlobalIDString = "URITemplate::URITemplate::Product"; remoteInfo = URITemplate; }; - 2715FACA1D8C818C00A89DF7 /* PBXContainerItemProxy */ = { + 532D00D52060B90D0009340F /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; - containerPortal = 2715FABD1D8C818C00A89DF7 /* URITemplate.xcodeproj */; + containerPortal = 532D00C62060B90C0009340F /* URITemplate.xcodeproj */; proxyType = 2; - remoteGlobalIDString = "_____Product_URITemplateTests"; - remoteInfo = URITemplateTests; + remoteGlobalIDString = "PathKit::PathKit::Product"; + remoteInfo = PathKit; }; - 2746CDCC1A702F7800719B66 /* PBXContainerItemProxy */ = { + 532D00D72060B90D0009340F /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; - containerPortal = 2746CDB61A702F7800719B66 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 2746CDBE1A702F7800719B66; - remoteInfo = Mockingjay; + containerPortal = 532D00C62060B90C0009340F /* URITemplate.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = "Spectre::Spectre::Product"; + remoteInfo = Spectre; }; /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ 2705946A1C4FA7A6002A3AA9 /* MockingjayXCTestTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MockingjayXCTestTests.swift; sourceTree = ""; }; - 2715FABD1D8C818C00A89DF7 /* URITemplate.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = URITemplate.xcodeproj; path = URITemplate/URITemplate.xcodeproj; sourceTree = ""; }; 274367911AA27A7C0030C97B /* Mockingjay.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Mockingjay.swift; sourceTree = ""; }; 274367931AA27AAD0030C97B /* MockingjayProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MockingjayProtocol.swift; sourceTree = ""; }; 274367951AA27B170030C97B /* MockingjayProtocolTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MockingjayProtocolTests.swift; sourceTree = ""; }; @@ -88,6 +87,7 @@ 27703A621CE2560600194732 /* MockingjayURLSessionConfiguration.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MockingjayURLSessionConfiguration.m; sourceTree = ""; }; 444EA6081C5261DE000C3A9F /* MockingjayAsyncProtocolTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MockingjayAsyncProtocolTests.swift; sourceTree = ""; }; 444EA60B1C52666D000C3A9F /* TestAudio.m4a */ = {isa = PBXFileReference; lastKnownFileType = file; path = TestAudio.m4a; sourceTree = ""; }; + 532D00C62060B90C0009340F /* URITemplate.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = URITemplate.xcodeproj; path = Carthage/Checkouts/URITemplate.swift/URITemplate.xcodeproj; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -95,7 +95,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 2715FACF1D8C81AB00A89DF7 /* URITemplate.framework in Frameworks */, + 532D00DA2060B91A0009340F /* URITemplate.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -110,25 +110,15 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ - 2715FABE1D8C818C00A89DF7 /* Products */ = { - isa = PBXGroup; - children = ( - 2715FACB1D8C818C00A89DF7 /* URITemplateTests.xctest */, - 2715FAC91D8C818C00A89DF7 /* URITemplate.framework */, - 2715FAC71D8C818C00A89DF7 /* PathKit.framework */, - 2715FAC51D8C818C00A89DF7 /* Spectre.framework */, - ); - name = Products; - sourceTree = ""; - }; 2746CDB51A702F7800719B66 = { isa = PBXGroup; children = ( - 2715FABD1D8C818C00A89DF7 /* URITemplate.xcodeproj */, + 532D00C62060B90C0009340F /* URITemplate.xcodeproj */, 2746CDDB1A702FC100719B66 /* Configurations */, 2746CDC11A702F7800719B66 /* Mockingjay */, 2746CDCE1A702F7800719B66 /* MockingjayTests */, 2746CDC01A702F7800719B66 /* Products */, + 532D00D92060B91A0009340F /* Frameworks */, ); indentWidth = 2; sourceTree = ""; @@ -210,6 +200,24 @@ name = Resources; sourceTree = ""; }; + 532D00C72060B90C0009340F /* Products */ = { + isa = PBXGroup; + children = ( + 532D00D22060B90D0009340F /* URITemplateTests.xctest */, + 532D00D42060B90D0009340F /* URITemplate.framework */, + 532D00D62060B90D0009340F /* PathKit.framework */, + 532D00D82060B90D0009340F /* Spectre.framework */, + ); + name = Products; + sourceTree = ""; + }; + 532D00D92060B91A0009340F /* Frameworks */ = { + isa = PBXGroup; + children = ( + ); + name = Frameworks; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ @@ -293,8 +301,8 @@ projectDirPath = ""; projectReferences = ( { - ProductGroup = 2715FABE1D8C818C00A89DF7 /* Products */; - ProjectRef = 2715FABD1D8C818C00A89DF7 /* URITemplate.xcodeproj */; + ProductGroup = 532D00C72060B90C0009340F /* Products */; + ProjectRef = 532D00C62060B90C0009340F /* URITemplate.xcodeproj */; }, ); projectRoot = ""; @@ -306,32 +314,32 @@ /* End PBXProject section */ /* Begin PBXReferenceProxy section */ - 2715FAC51D8C818C00A89DF7 /* Spectre.framework */ = { + 532D00D22060B90D0009340F /* URITemplateTests.xctest */ = { isa = PBXReferenceProxy; - fileType = wrapper.framework; - path = Spectre.framework; - remoteRef = 2715FAC41D8C818C00A89DF7 /* PBXContainerItemProxy */; + fileType = wrapper.cfbundle; + path = URITemplateTests.xctest; + remoteRef = 532D00D12060B90D0009340F /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; - 2715FAC71D8C818C00A89DF7 /* PathKit.framework */ = { + 532D00D42060B90D0009340F /* URITemplate.framework */ = { isa = PBXReferenceProxy; fileType = wrapper.framework; - path = PathKit.framework; - remoteRef = 2715FAC61D8C818C00A89DF7 /* PBXContainerItemProxy */; + path = URITemplate.framework; + remoteRef = 532D00D32060B90D0009340F /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; - 2715FAC91D8C818C00A89DF7 /* URITemplate.framework */ = { + 532D00D62060B90D0009340F /* PathKit.framework */ = { isa = PBXReferenceProxy; fileType = wrapper.framework; - path = URITemplate.framework; - remoteRef = 2715FAC81D8C818C00A89DF7 /* PBXContainerItemProxy */; + path = PathKit.framework; + remoteRef = 532D00D52060B90D0009340F /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; - 2715FACB1D8C818C00A89DF7 /* URITemplateTests.xctest */ = { + 532D00D82060B90D0009340F /* Spectre.framework */ = { isa = PBXReferenceProxy; - fileType = file; - path = URITemplateTests.xctest; - remoteRef = 2715FACA1D8C818C00A89DF7 /* PBXContainerItemProxy */; + fileType = wrapper.framework; + path = Spectre.framework; + remoteRef = 532D00D72060B90D0009340F /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXReferenceProxy section */ @@ -362,7 +370,6 @@ 274367981AA28AFC0030C97B /* Matchers.swift in Sources */, 27703A631CE2560600194732 /* MockingjayURLSessionConfiguration.m in Sources */, 274367921AA27A7C0030C97B /* Mockingjay.swift in Sources */, - A1E3C5701AA4EA130069C998 /* XCTest.swift in Sources */, 274367C61AA35FD00030C97B /* NSURLSessionConfiguration.swift in Sources */, 274367941AA27AAD0030C97B /* MockingjayProtocol.swift in Sources */, 274367B01AA29E510030C97B /* Builders.swift in Sources */, @@ -378,6 +385,7 @@ 444EA6091C5261DE000C3A9F /* MockingjayAsyncProtocolTests.swift in Sources */, 274367B21AA29E620030C97B /* BuildersTests.swift in Sources */, 2705946B1C4FA7A6002A3AA9 /* MockingjayXCTestTests.swift in Sources */, + 532D00E62060C1260009340F /* XCTest.swift in Sources */, 2746CDD21A702F7800719B66 /* MockingjayTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/README.md b/README.md index b8d5418..b5d60f7 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,16 @@ An elegant library for stubbing HTTP requests in Swift, allowing you to stub any pod 'Mockingjay' ``` +[Carthage](https://github.com/Carthage/Carthage) + +```bash +carthage update +cd Carthage/Checkouts/URITemplate.swift +swift package generate-xcodeproj +cd ../../.. +carthage build --cache-builds --no-skip-current --platform ios +``` + ## Usage Mockingjay has full integration to XCTest and you simply just need to register a stub, it will automatically be unloaded at the end of your test case. It will also work with the [Quick](https://github.com/Quick/Quick) behaviour-driven development framework.