From dfd4db6b7e89700a670a13b2226ae37af2e9804a Mon Sep 17 00:00:00 2001 From: devedbox <862099730@qq.com> Date: Sat, 13 Oct 2018 00:32:14 +0800 Subject: [PATCH] test: Adds tests for GlobalOptions. --- Commander.xcodeproj/project.pbxproj | 4 + Tests/CommanderTests/GlobalOptionsTests.swift | 140 ++++++++++++++++++ 2 files changed, 144 insertions(+) create mode 100644 Tests/CommanderTests/GlobalOptionsTests.swift diff --git a/Commander.xcodeproj/project.pbxproj b/Commander.xcodeproj/project.pbxproj index 3734d57..f43df4c 100644 --- a/Commander.xcodeproj/project.pbxproj +++ b/Commander.xcodeproj/project.pbxproj @@ -31,6 +31,7 @@ DC1DF5FD216DF777002EB271 /* CommandDescriber.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC1DF5FC216DF777002EB271 /* CommandDescriber.swift */; }; DC1DF5FF216F5662002EB271 /* CommandPath.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC1DF5FE216F5662002EB271 /* CommandPath.swift */; }; DC1DF603216F6357002EB271 /* CommandPathTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC1DF602216F6357002EB271 /* CommandPathTests.swift */; }; + DC71F3212170E774002DA345 /* GlobalOptionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC71F3202170E774002DA345 /* GlobalOptionsTests.swift */; }; OBJ_42 /* Commander.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_11 /* Commander.swift */; }; OBJ_43 /* Error.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_13 /* Error.swift */; }; OBJ_46 /* CommandRepresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_18 /* CommandRepresentable.swift */; }; @@ -81,6 +82,7 @@ DC1DF5FC216DF777002EB271 /* CommandDescriber.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommandDescriber.swift; sourceTree = ""; }; DC1DF5FE216F5662002EB271 /* CommandPath.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommandPath.swift; sourceTree = ""; }; DC1DF602216F6357002EB271 /* CommandPathTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommandPathTests.swift; sourceTree = ""; }; + DC71F3202170E774002DA345 /* GlobalOptionsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GlobalOptionsTests.swift; sourceTree = ""; }; OBJ_11 /* Commander.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Commander.swift; sourceTree = ""; }; OBJ_13 /* Error.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Error.swift; sourceTree = ""; }; OBJ_18 /* CommandRepresentable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommandRepresentable.swift; sourceTree = ""; }; @@ -173,6 +175,7 @@ children = ( OBJ_30 /* CommanderTests.swift */, DC0B9BA4216882D100C87253 /* CommandTests.swift */, + DC71F3202170E774002DA345 /* GlobalOptionsTests.swift */, DC0B9B9C2163B56B00C87253 /* OptionsDecoderTests.swift */, DC1DF602216F6357002EB271 /* CommandPathTests.swift */, OBJ_32 /* XCTestManifests.swift */, @@ -360,6 +363,7 @@ OBJ_72 /* CommanderTests.swift in Sources */, OBJ_74 /* XCTestManifests.swift in Sources */, DC0B9B9D2163B56B00C87253 /* OptionsDecoderTests.swift in Sources */, + DC71F3212170E774002DA345 /* GlobalOptionsTests.swift in Sources */, DC1DF603216F6357002EB271 /* CommandPathTests.swift in Sources */, DC0B9BA5216882D200C87253 /* CommandTests.swift in Sources */, ); diff --git a/Tests/CommanderTests/GlobalOptionsTests.swift b/Tests/CommanderTests/GlobalOptionsTests.swift new file mode 100644 index 0000000..3e1f1ab --- /dev/null +++ b/Tests/CommanderTests/GlobalOptionsTests.swift @@ -0,0 +1,140 @@ +// +// GlobalOptionsTests.swift +// CommanderTests +// +// Created by devedbox on 2018/10/12. +// +// 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. +// + +import XCTest +@testable import Commander + +class MockCommander: CommanderRepresentable { + struct TestsCommand: CommandRepresentable { + struct Options: OptionsRepresentable { + typealias GlobalOptions = MockCommander.Options + enum CodingKeys: String, CodingKeysRepresentable { + case target + } + static var keys: [TestsCommand.Options.CodingKeys : Character] = [ + .target: "T" + ] + static var descriptions: [TestsCommand.Options.CodingKeys: OptionDescription] = [ + .target: .default(value: "Default", usage: "The target of the test command") + ] + let target: String + } + + static let symbol: String = "test" + static var usage: String = "Mocked command for tests" + + static func main(_ options: TestsCommand.Options) throws { + + } + } + + struct TestsArgsCommand: CommandRepresentable { + struct Options: OptionsRepresentable { + typealias GlobalOptions = MockCommander.Options + typealias ArgumentsResolver = AnyArgumentsResolver<[String: UInt8]> + enum CodingKeys: String, CodingKeysRepresentable { + case target + } + static var keys: [TestsArgsCommand.Options.CodingKeys : Character] = [ + .target: "T" + ] + static var descriptions: [Options.CodingKeys: OptionDescription] = [ + .target: .default(value: "Default", usage: "The target of the test command") + ] + let target: String + } + static let subcommands: [AnyCommandRepresentable.Type] = [ + TestsCommand.self + ] + static let symbol: String = "test-args" + static var usage: String = "Mocked command for tests args" + + static func main(_ options: Options) throws { + + } + } + + struct Options: OptionsRepresentable { + enum CodingKeys: String, CodingKeysRepresentable { + case mockDir = "mock-dir" + case verbose + } + + static var keys: [MockCommander.Options.CodingKeys : Character] = [ + .mockDir: "C", + .verbose: "v" + ] + + static var descriptions: [MockCommander.Options.CodingKeys : OptionDescription] = [ + .verbose: .default(value: false, usage: "") + ] + + let mockDir: String + let verbose: Bool + } + static var errorHandler: ((Error) -> Void)? = nil + static var commands: [AnyCommandRepresentable.Type] = [ + MockCommander.TestsCommand.self, + MockCommander.TestsArgsCommand.self + ] + + static var usage: String = "Mocked usage" +} + +class GlobalOptionsTests: XCTestCase { + static let allTests = [ + ("testGlobalOptions", testGlobalOptions) + ] + + func testGlobalOptions() { + XCTAssertNoThrow(try MockCommander().dispatch(with: ["commander", "test"])) + XCTAssertNoThrow(try MockCommander().dispatch(with: ["commander", "test", "-C=path"])) + XCTAssertNoThrow(try MockCommander().dispatch(with: ["commander", "test", "-C=path", "-v"])) + XCTAssertNoThrow(try MockCommander().dispatch(with: ["commander", "test", "--mock-dir", "path"])) + XCTAssertNoThrow(try MockCommander().dispatch(with: ["commander", "test", "--mock-dir", "path", "--verbose"])) + + do { + try MockCommander().dispatch(with: ["commander", "test", "--verbose"]) + XCTFail() + } catch OptionsDecoder.Error.decodingError(DecodingError.keyNotFound(let key, let ctx)) { + XCTAssertEqual(key.stringValue, "mock-dir") + XCTAssertFalse(OptionsDecoder.Error.decodingError(DecodingError.keyNotFound(key, ctx)).description.isEmpty) + } catch { + XCTFail() + } + + do { + try MockCommander().dispatch(with: ["commander", "test", "-C=path", "--verbose", "-s", "-r"]) + XCTFail() + } catch CommanderError.unrecognizedOptions(let options, path: let path) { + XCTAssertEqual(options.set, ["s", "r"]) + XCTAssertTrue(path.command == MockCommander.TestsCommand.self) + XCTAssertEqual(path.paths.set, ["commander"]) + XCTAssertFalse(CommanderError.unrecognizedOptions(options, path: path).description.isEmpty) + } catch { + XCTFail() + } + } +}