diff --git a/Demo/BuildConfigSwiftDemo/Sources/Data/BaseEntities.swift b/Demo/BuildConfigSwiftDemo/Sources/Data/BaseEntities.swift new file mode 100644 index 0000000..fbdb9ef --- /dev/null +++ b/Demo/BuildConfigSwiftDemo/Sources/Data/BaseEntities.swift @@ -0,0 +1,15 @@ +// +// BaseEntities.swift +// BuildConfigSwiftDemo +// +// Created by 417.72KI on 2023/10/05. +// Copyright © 2023 417.72KI. All rights reserved. +// + +import Foundation + +protocol Request: Encodable, Hashable { +} + +protocol Response: Decodable, Hashable { +} diff --git a/Demo/BuildConfigSwiftDemo/Sources/Data/LoginRequest.swift b/Demo/BuildConfigSwiftDemo/Sources/Data/LoginRequest.swift new file mode 100644 index 0000000..c5cb40a --- /dev/null +++ b/Demo/BuildConfigSwiftDemo/Sources/Data/LoginRequest.swift @@ -0,0 +1,14 @@ +// +// LoginRequest.swift +// BuildConfigSwiftDemo +// +// Created by 417.72KI on 2023/10/05. +// Copyright © 2023 417.72KI. All rights reserved. +// + +import Foundation + +struct LoginRequest: Request { + var id: String + var password: String +} diff --git a/Demo/BuildConfigSwiftDemo/Sources/Data/LoginResponse.swift b/Demo/BuildConfigSwiftDemo/Sources/Data/LoginResponse.swift new file mode 100644 index 0000000..e675750 --- /dev/null +++ b/Demo/BuildConfigSwiftDemo/Sources/Data/LoginResponse.swift @@ -0,0 +1,14 @@ +// +// LoginResponse.swift +// BuildConfigSwiftDemo +// +// Created by 417.72KI on 2023/10/05. +// Copyright © 2023 417.72KI. All rights reserved. +// + +import Foundation + +struct LoginResponse: Response { + var accessToken: String + var refreshToken: String +} diff --git a/Demo/BuildConfigSwiftDemo/Sources/Data/SearchResponse.swift b/Demo/BuildConfigSwiftDemo/Sources/Data/SearchResponse.swift new file mode 100644 index 0000000..6a3ccd7 --- /dev/null +++ b/Demo/BuildConfigSwiftDemo/Sources/Data/SearchResponse.swift @@ -0,0 +1,19 @@ +// +// SearchResponse.swift +// BuildConfigSwiftDemo +// +// Created by 417.72KI on 2023/10/05. +// Copyright © 2023 417.72KI. All rights reserved. +// + +import Foundation + +struct SearchResponse: Response { + var items: [Item] +} + +extension SearchResponse { + struct Item: Response { + var name: String + } +} diff --git a/Demo/BuildConfigSwiftDemo/Sources/Repository/APIClient.swift b/Demo/BuildConfigSwiftDemo/Sources/Repository/APIClient.swift new file mode 100644 index 0000000..f776370 --- /dev/null +++ b/Demo/BuildConfigSwiftDemo/Sources/Repository/APIClient.swift @@ -0,0 +1,61 @@ +// +// APIClient.swift +// BuildConfigSwiftDemo +// +// Created by 417.72KI on 2023/10/05. +// Copyright © 2023 417.72KI. All rights reserved. +// + +import Foundation + +struct APIClient { + var config: BuildConfig.Api + var session: URLSession +} + +extension APIClient { + var host: URL { URL(string: "https://\(config.host)")! } + + var decoder: JSONDecoder { + let decoder = JSONDecoder() + decoder.keyDecodingStrategy = .convertFromSnakeCase + return decoder + } + + var encoder: JSONEncoder { + let encoder = JSONEncoder() + encoder.keyEncodingStrategy = .convertToSnakeCase + return encoder + } +} + +extension APIClient { + func endpoint(_ keyPath: KeyPath) -> E { + config.endpoint[keyPath: keyPath] + } +} + +extension APIClient { + func login(id: String, password: String) async throws -> LoginResponse { + let endpoint = endpoint(\.login) + let url = host.appendingPathComponent(endpoint.path) + var request = URLRequest(url: url) + request.httpMethod = endpoint.method + request.httpBody = try encoder.encode(LoginRequest(id: id, password: password)) + let (data, _) = try await session.data(for: request) + return try decoder.decode(LoginResponse.self, from: data) + } + + @available(iOS 16.0, *) + func search(_ text: String) async throws -> SearchResponse { + let endpoint = endpoint(\.search) + let url = host.appendingPathComponent(endpoint.path) + .appending(queryItems: [ + URLQueryItem(name: "text", value: text) + ]) + var request = URLRequest(url: url) + request.httpMethod = endpoint.method + let (data, _) = try await session.data(for: request) + return try decoder.decode(SearchResponse.self, from: data) + } +} diff --git a/Demo/BuildConfigSwiftDemo/Sources/UI/ContentView.swift b/Demo/BuildConfigSwiftDemo/Sources/UI/ContentView.swift index bdfcc90..a0f7cee 100644 --- a/Demo/BuildConfigSwiftDemo/Sources/UI/ContentView.swift +++ b/Demo/BuildConfigSwiftDemo/Sources/UI/ContentView.swift @@ -9,13 +9,13 @@ import SwiftUI struct ContentView: View { - var config: BuildConfig = .default + @Environment(\.buildConfig) var config: BuildConfig var body: some View { VStack { Text("isDebug: \(String(config.isDebug))") Text("Environment: \(config.environment)") - Text("API version: \(config.apiVersion, format: .number)") + Text("API version: \(config.api.version, format: .number)") Text("PI: \(config.pi, format: .number)") } } diff --git a/Demo/BuildConfigSwiftDemo/Sources/UI/DemoApp.swift b/Demo/BuildConfigSwiftDemo/Sources/UI/DemoApp.swift index 3f48f7c..07dad3b 100644 --- a/Demo/BuildConfigSwiftDemo/Sources/UI/DemoApp.swift +++ b/Demo/BuildConfigSwiftDemo/Sources/UI/DemoApp.swift @@ -8,20 +8,13 @@ import SwiftUI -@main struct DemoApp: App { + static var buildConfig: BuildConfig = .default + var body: some Scene { WindowGroup { ContentView() + .environment(\.buildConfig, Self.buildConfig) } } } - -// MARK: - For Debug -#if DEBUG -private extension DemoApp { - var isTesting: Bool { - ProcessInfo.processInfo.environment["XCTestConfigurationFilePath"] != nil - } -} -#endif diff --git a/Demo/BuildConfigSwiftDemo/Sources/Util/BuildConfig+Environment.swift b/Demo/BuildConfigSwiftDemo/Sources/Util/BuildConfig+Environment.swift new file mode 100644 index 0000000..fa36ac2 --- /dev/null +++ b/Demo/BuildConfigSwiftDemo/Sources/Util/BuildConfig+Environment.swift @@ -0,0 +1,20 @@ +// +// BuildConfig+Environment.swift +// BuildConfigSwiftDemo +// +// Created by 417.72KI on 2023/10/09. +// Copyright © 2023 417.72KI. All rights reserved. +// + +import SwiftUI + +struct BuildConfigKey: EnvironmentKey { + static let defaultValue = BuildConfig.default +} + +extension EnvironmentValues { + var buildConfig: BuildConfig { + get { self[BuildConfigKey.self] } + set { self[BuildConfigKey.self] = newValue } + } +} diff --git a/Demo/BuildConfigSwiftDemo/Sources/main.swift b/Demo/BuildConfigSwiftDemo/Sources/main.swift new file mode 100644 index 0000000..68838ae --- /dev/null +++ b/Demo/BuildConfigSwiftDemo/Sources/main.swift @@ -0,0 +1,15 @@ +// +// main.swift +// BuildConfigSwiftDemo +// +// Created by 417.72KI on 2023/10/09. +// Copyright © 2023 417.72KI. All rights reserved. +// + +import SwiftUI + +if let clazz = NSClassFromString("FakeApp") as? any App.Type { + clazz.main() +} else { + DemoApp.main() +} diff --git a/Demo/BuildConfigSwiftDemoTests/APIClientTests.swift b/Demo/BuildConfigSwiftDemoTests/APIClientTests.swift new file mode 100644 index 0000000..f9940bd --- /dev/null +++ b/Demo/BuildConfigSwiftDemoTests/APIClientTests.swift @@ -0,0 +1,64 @@ +// +// APIClientTests.swift +// BuildConfigSwiftDemoTests +// +// Created by 417.72KI on 2023/10/05. +// Copyright © 2023 417.72KI. All rights reserved. +// + +import XCTest +import StubNetworkKit + +@testable import BuildConfigSwiftDemo + +final class APIClientTests: XCTestCase { + var config = BuildConfig.fake.api + + var apiClient: APIClient! + + override func setUpWithError() throws { + apiClient = APIClient(config: config, + session: defaultStubSession) + } + + override func tearDownWithError() throws { + clearStubs() + } + + func testLogin() async throws { + stub { + Scheme.is("https") + Host.is("localhost") + Path.is("/login") + Method.isPost() + Body.isJson(["id": "john_doe", "password": "password"]) + }.responseJson(["access_token": "foo", "refresh_token": "bar"]) + + let response = try await apiClient.login(id: "john_doe", + password: "password") + XCTAssertEqual("foo", response.accessToken) + XCTAssertEqual("bar", response.refreshToken) + } + + @available(iOS 16.0, *) + func testSearch() async throws { + stub { + Scheme.is("https") + Host.is("localhost") + Path.is("/search") + Method.isGet() + QueryParams.contains(["text": "寿限無"]) + }.responseJson([ + "items": [ + ["name": "foo"], + ["name": "bar"], + ["name": "baz"], + ] + ]) + + let response = try await apiClient.search("寿限無") + XCTAssertEqual(3, response.items.count) + XCTAssertEqual("foo", response.items.first?.name) + XCTAssertEqual("baz", response.items.last?.name) + } +} diff --git a/Demo/BuildConfigSwiftDemoTests/BuildConfigSwiftDemoTests.swift b/Demo/BuildConfigSwiftDemoTests/BuildConfigSwiftDemoTests.swift index 54f6399..5e2c5f0 100644 --- a/Demo/BuildConfigSwiftDemoTests/BuildConfigSwiftDemoTests.swift +++ b/Demo/BuildConfigSwiftDemoTests/BuildConfigSwiftDemoTests.swift @@ -12,26 +12,19 @@ import XCTest final class BuildConfigTests: XCTestCase { func testDefault() { let buildConfig = BuildConfig.default - XCTAssertEqual(1, buildConfig.apiVersion) - XCTAssertEqual("develop", buildConfig.environment) - XCTAssertFalse(buildConfig.isDebug) + XCTAssertEqual(1, buildConfig.api.version) + XCTAssertEqual("api-dev.example.com", buildConfig.api.host) + XCTAssertEqual("debug", buildConfig.environment) + XCTAssertTrue(buildConfig.isDebug) XCTAssertEqual(3.14, buildConfig.pi, accuracy: 0.01) } - func testLoad() { - let buildConfig = BuildConfig.load( - from: #""" - { - "api_version": 100, - "environment": "staging", - "is_debug": true, - "pi": 3.14 - } - """#.data(using: .utf8)! - ) - XCTAssertEqual(100, buildConfig.apiVersion) + func testLoad() throws { + let buildConfig = BuildConfig.fake + XCTAssertEqual(100, buildConfig.api.version) + XCTAssertEqual("localhost", buildConfig.api.host) XCTAssertEqual("staging", buildConfig.environment) - XCTAssertTrue(buildConfig.isDebug) + XCTAssertFalse(buildConfig.isDebug) XCTAssertEqual(3.14, buildConfig.pi, accuracy: 0.01) } } diff --git a/Demo/BuildConfigSwiftDemoTests/FakeApp.swift b/Demo/BuildConfigSwiftDemoTests/FakeApp.swift new file mode 100644 index 0000000..bdd4428 --- /dev/null +++ b/Demo/BuildConfigSwiftDemoTests/FakeApp.swift @@ -0,0 +1,25 @@ +// +// FakeApp.swift +// BuildConfigSwiftDemoTests +// +// Created by 417.72KI on 2023/10/09. +// Copyright © 2023 417.72KI. All rights reserved. +// + +import SwiftUI + +@objc(FakeApp) +final class FakeApp: NSObject, App { + override init() { super.init() } + + var body: some Scene { + WindowGroup { + Text("This is a fake app.") + .foregroundStyle(Color.white) + .frame(maxWidth: .infinity, maxHeight: .infinity) + .background { + Color.black + } + } + } +} diff --git a/Demo/BuildConfigSwiftDemoTests/TestHelper.swift b/Demo/BuildConfigSwiftDemoTests/TestHelper.swift new file mode 100644 index 0000000..e8f06d3 --- /dev/null +++ b/Demo/BuildConfigSwiftDemoTests/TestHelper.swift @@ -0,0 +1,30 @@ +// +// TestHelper.swift +// BuildConfigSwiftDemoTests +// +// Created by 417.72KI on 2023/10/05. +// Copyright © 2023 417.72KI. All rights reserved. +// + +import Foundation +@testable import BuildConfigSwiftDemo + +final class TestHelper { + private init() {} +} + +extension TestHelper { + static var bundle: Bundle { Bundle(for: self.self) } +} + +extension TestHelper { + static func path(forResource name: String, ofType ext: String) -> String? { + bundle.path(forResource: name, ofType: ext) + } +} + +extension BuildConfig { + static var fake: Self { + .load(from: TestHelper.path(forResource: "test_config", ofType: "json")!) + } +} diff --git a/Demo/BuildConfigSwiftDemoTests/test_config.json b/Demo/BuildConfigSwiftDemoTests/test_config.json new file mode 100644 index 0000000..209b487 --- /dev/null +++ b/Demo/BuildConfigSwiftDemoTests/test_config.json @@ -0,0 +1,23 @@ +{ + "api": { + "version": 100, + "host": "localhost", + "endpoint": { + "login": { + "path": "/login", + "method": "POST" + }, + "profile": { + "path": "/profile", + "method": "GET" + }, + "search": { + "path": "/search", + "method": "GET" + } + } + }, + "environment": "staging", + "is_debug": false, + "pi": 3.14 +} diff --git a/Demo/Resources/BuildConfig/.env/debug.yml b/Demo/Resources/BuildConfig/.env/debug.yml deleted file mode 100644 index 09b6da3..0000000 --- a/Demo/Resources/BuildConfig/.env/debug.yml +++ /dev/null @@ -1,2 +0,0 @@ -is_debug: false -environment: develop diff --git a/Demo/Resources/BuildConfig/api.yml b/Demo/Resources/BuildConfig/api.yml new file mode 100644 index 0000000..fea282a --- /dev/null +++ b/Demo/Resources/BuildConfig/api.yml @@ -0,0 +1,13 @@ +api: + version: 1 + host: localhost + endpoint: + login: + method: POST + path: /login + profile: + method: GET + path: /profile + search: + method: GET + path: /search diff --git a/Demo/Resources/BuildConfig/base.yml b/Demo/Resources/BuildConfig/config.yml similarity index 74% rename from Demo/Resources/BuildConfig/base.yml rename to Demo/Resources/BuildConfig/config.yml index ffdd767..0824541 100644 --- a/Demo/Resources/BuildConfig/base.yml +++ b/Demo/Resources/BuildConfig/config.yml @@ -1,4 +1,3 @@ is_debug: true environment: debug -api_version: 1 pi: 3.14 diff --git a/Demo/Resources/BuildConfig/debug/api.yml b/Demo/Resources/BuildConfig/debug/api.yml new file mode 100644 index 0000000..f6b147b --- /dev/null +++ b/Demo/Resources/BuildConfig/debug/api.yml @@ -0,0 +1,2 @@ +api: + host: api-dev.example.com diff --git a/Demo/Resources/BuildConfig/debug/config.yml b/Demo/Resources/BuildConfig/debug/config.yml new file mode 100644 index 0000000..3e0d81f --- /dev/null +++ b/Demo/Resources/BuildConfig/debug/config.yml @@ -0,0 +1,2 @@ +is_debug: true +environment: debug diff --git a/Demo/Resources/BuildConfig/integration_test/api.yml b/Demo/Resources/BuildConfig/integration_test/api.yml new file mode 100644 index 0000000..ff729de --- /dev/null +++ b/Demo/Resources/BuildConfig/integration_test/api.yml @@ -0,0 +1,2 @@ +api: + host: api-staging.example.com diff --git a/Demo/Resources/BuildConfig/.env/integration_test.yml b/Demo/Resources/BuildConfig/integration_test/config.yml similarity index 100% rename from Demo/Resources/BuildConfig/.env/integration_test.yml rename to Demo/Resources/BuildConfig/integration_test/config.yml diff --git a/Demo/Resources/BuildConfig/release/api.yml b/Demo/Resources/BuildConfig/release/api.yml new file mode 100644 index 0000000..44a1411 --- /dev/null +++ b/Demo/Resources/BuildConfig/release/api.yml @@ -0,0 +1,2 @@ +api: + host: api.example.com diff --git a/Demo/Resources/BuildConfig/.env/release.yml b/Demo/Resources/BuildConfig/release/config.yml similarity index 100% rename from Demo/Resources/BuildConfig/.env/release.yml rename to Demo/Resources/BuildConfig/release/config.yml diff --git a/Demo/project.yml b/Demo/project.yml index 2e2a39b..c09b77b 100644 --- a/Demo/project.yml +++ b/Demo/project.yml @@ -17,6 +17,9 @@ packages: XCGLogger: url: https://github.com/DaveWoodCom/XCGLogger from: 7.0.1 + StubNetworkKit: + url: https://github.com/417-72KI/StubNetworkKit.git + from: 0.3.0 # SwiftLint: # url: https://github.com/realm/SwiftLint # from: 0.53.0 @@ -94,3 +97,4 @@ targets: DEVELOPMENT_TEAM: "" dependencies: - target: BuildConfigSwiftDemo + - package: StubNetworkKit diff --git a/Sources/Common/File+Path.swift b/Sources/Common/File+Path.swift index f520357..71a0b98 100644 --- a/Sources/Common/File+Path.swift +++ b/Sources/Common/File+Path.swift @@ -16,6 +16,10 @@ public extension File { ["json"].contains(pathExtension) } + var isYamlOrJson: Bool { + isYaml || isJson + } + var isExcludedFile: Bool { ["xcfilelist"].contains(pathExtension) } diff --git a/Sources/Parser/Parser.swift b/Sources/Parser/Parser.swift index 23b00ff..7399905 100644 --- a/Sources/Parser/Parser.swift +++ b/Sources/Parser/Parser.swift @@ -14,20 +14,18 @@ public struct Parser { public extension Parser { func run(environment: String?, skipInvalidFile: Bool = true) throws -> Data { - let filePaths = try getFileList(at: directoryPath, environment: environment) - let environmentFiles = filePaths.filter { $0.components.contains(envDirComponent) } - .compactMap { File(path: $0) } - if let environment, - environmentFiles.isEmpty { + let files = try getFileList(at: directoryPath, + environment: environment) + if let environment, files.env.isEmpty { dumpWarn("No file for environment `\(environment)` in `\(directoryPath)`.") } - let otherFiles = filePaths.filter { !$0.components.contains(envDirComponent) } - .compactMap { File(path: $0) } - let environmentData = try parse(files: environmentFiles, skipInvalidFile: skipInvalidFile) + let baseData = try parse(files: files.base, + skipInvalidFile: skipInvalidFile) .reduce(AnyParsable()) { $0 + $1 } - let defaultData = try parse(files: otherFiles, skipInvalidFile: skipInvalidFile) + let environmentData = try parse(files: files.env, + skipInvalidFile: skipInvalidFile) .reduce(AnyParsable()) { $0 + $1 } - let result = defaultData + environmentData + let result = baseData + environmentData return try JSONSerialization.data( withJSONObject: result.rawValue, options: [] @@ -36,18 +34,17 @@ public extension Parser { } extension Parser { - func getFileList(at path: Path, environment: String? = nil) throws -> [Path] { - if path.lastComponent == envDirComponent { - if let environment { - return try path.children().filter { $0.lastComponentWithoutExtension == environment } - } - return [] - } - return try path.children() + func getFileList(at path: Path, environment: String? = nil) throws -> (base: [File], env: [File]) { + let files = try path.children() .lazy - .filter { $0.lastComponent != dsStoreFileName } - .compactMap { $0.isDirectory ? try getFileList(at: $0, environment: environment) : [$0] } - .flatMap { $0 } + .filter(\.isValidFile) + .compactMap(File.init(path:)) + .filter(\.isYamlOrJson) as [File] + guard let environment else { return (files, []) } + let envFiles = (path + environment).lazy + .compactMap(File.init(path:)) + .filter(\.isYamlOrJson) as [File] + return (files, envFiles) } func detectParser(_ file: File) throws -> FileParser { diff --git a/Sources/Parser/Util/Path+Extension.swift b/Sources/Parser/Util/Path+Extension.swift new file mode 100644 index 0000000..4ab5ef7 --- /dev/null +++ b/Sources/Parser/Util/Path+Extension.swift @@ -0,0 +1,12 @@ +import Foundation +import PathKit + +extension Path { + var isDsStore: Bool { + lastComponent == dsStoreFileName + } + + var isValidFile: Bool { + isFile && !isDsStore + } +} diff --git a/Tests/ParserTests/ParserTests.swift b/Tests/ParserTests/ParserTests.swift index 92b50b8..da131f9 100644 --- a/Tests/ParserTests/ParserTests.swift +++ b/Tests/ParserTests/ParserTests.swift @@ -18,7 +18,7 @@ final class ParserTests: XCTestCase { XCTAssertNotNil(try parser.detectParser(file) as? JSonParser) } try context("invalid") { - let file = File(path: path + "test.txt")! + let file = File(path: path + "ignored.txt")! XCTAssertThrowsError(try parser.detectParser(file)) { if let e = $0 as? ParserError { XCTAssertEqual(e, ParserError.invalidFile(file.path!)) @@ -35,27 +35,91 @@ final class ParserTests: XCTestCase { try context("\(path)") { try context("environment is nil") { try context("detects 6 files") { - let files = ["test.yaml", "test.json", "test.txt", - "d1/test.txt", "d2/test.txt", "d2/d1/test.txt"] - let expected = files.map { path + $0 }.sorted() - let actual = try parser.getFileList(at: path).sorted() - XCTAssertEqual(try parser.getFileList(at: path).sorted(), expected, diff(between: expected, and: actual)) + let expected = ( + base: ["test.yaml", "test.json"], + env: [] as [String] + ) + let actual = try parser.getFileList(at: path) + context("base") { + let expected = expected.base + .map(path.appending(_:)) + .sorted() + let actual = actual.base + .compactMap(\.path) + .compactMap(Path.init(_:)) + .sorted() + XCTAssertEqual(expected, actual, diff(between: expected.map(\.lastComponent), and: actual.map(\.lastComponent))) + } + context("env") { + let expected = expected.env + .map(path.appending(_:)) + .sorted() + let actual = actual.env + .compactMap(\.path) + .compactMap(Path.init(_:)) + .sorted() + XCTAssertEqual(expected, actual, diff(between: expected.map(\.lastComponent), and: actual.map(\.lastComponent))) + } } } try context("environment is staging") { try context("detects 7 files") { - let files = ["test.yaml", "test.json", "test.txt", - "d1/test.txt", "d2/test.txt", "d2/d1/test.txt", ".env/staging.json"] - let expected = files.map { path + $0 }.sorted() - XCTAssertEqual(try parser.getFileList(at: path, environment: "staging").sorted(), expected) + let expected = ( + base: ["test.yaml", "test.json"], + env: ["staging/test.json"] + ) + let actual = try parser.getFileList(at: path, + environment: "staging") + context("base") { + let expected = expected.base + .map(path.appending(_:)) + .sorted() + let actual = actual.base + .compactMap(\.path) + .compactMap(Path.init(_:)) + .sorted() + XCTAssertEqual(expected, actual, diff(between: expected.map(\.lastComponent), and: actual.map(\.lastComponent))) + } + context("env") { + let expected = expected.env + .map(path.appending(_:)) + .sorted() + let actual = actual.env + .compactMap(\.path) + .compactMap(Path.init(_:)) + .sorted() + XCTAssertEqual(expected, actual, diff(between: expected.map(\.lastComponent), and: actual.map(\.lastComponent))) + } } } try context("environment is production") { try context("detects 7 files") { - let files = ["test.yaml", "test.json", "test.txt", - "d1/test.txt", "d2/test.txt", "d2/d1/test.txt", ".env/production.yaml"] - let expected = files.map { path + $0 }.sorted() - XCTAssertEqual(try parser.getFileList(at: path, environment: "production").sorted(), expected) + let expected = ( + base: ["test.yaml", "test.json"], + env: ["production/test.yaml"] + ) + let actual = try parser.getFileList(at: path, + environment: "production") + context("base") { + let expected = expected.base + .map(path.appending(_:)) + .sorted() + let actual = actual.base + .compactMap(\.path) + .compactMap(Path.init(_:)) + .sorted() + XCTAssertEqual(expected, actual, diff(between: expected.map(\.lastComponent), and: actual.map(\.lastComponent))) + } + context("env") { + let expected = expected.env + .map(path.appending(_:)) + .sorted() + let actual = actual.env + .compactMap(\.path) + .compactMap(Path.init(_:)) + .sorted() + XCTAssertEqual(expected, actual, diff(between: expected.map(\.lastComponent), and: actual.map(\.lastComponent))) + } } } } diff --git a/Tests/ParserTests/Resources/d1/test.txt b/Tests/ParserTests/Resources/debug/d1/ignored.yml similarity index 100% rename from Tests/ParserTests/Resources/d1/test.txt rename to Tests/ParserTests/Resources/debug/d1/ignored.yml diff --git a/Tests/ParserTests/Resources/d2/d1/test.txt b/Tests/ParserTests/Resources/debug/test.yml similarity index 100% rename from Tests/ParserTests/Resources/d2/d1/test.txt rename to Tests/ParserTests/Resources/debug/test.yml diff --git a/Tests/ParserTests/Resources/d2/test.txt b/Tests/ParserTests/Resources/ignored.txt similarity index 100% rename from Tests/ParserTests/Resources/d2/test.txt rename to Tests/ParserTests/Resources/ignored.txt diff --git a/Tests/ParserTests/Resources/test.txt b/Tests/ParserTests/Resources/invalid_env/ignored.yml similarity index 100% rename from Tests/ParserTests/Resources/test.txt rename to Tests/ParserTests/Resources/invalid_env/ignored.yml diff --git a/Tests/ParserTests/Resources/.env/production.yaml b/Tests/ParserTests/Resources/production/test.yaml similarity index 100% rename from Tests/ParserTests/Resources/.env/production.yaml rename to Tests/ParserTests/Resources/production/test.yaml diff --git a/Tests/ParserTests/Resources/.env/staging.json b/Tests/ParserTests/Resources/staging/test.json similarity index 100% rename from Tests/ParserTests/Resources/.env/staging.json rename to Tests/ParserTests/Resources/staging/test.json diff --git a/Tests/ParserTests/Util.swift b/Tests/ParserTests/Util.swift index 85abcd4..19930e1 100644 --- a/Tests/ParserTests/Util.swift +++ b/Tests/ParserTests/Util.swift @@ -8,6 +8,12 @@ var path: Path { return Path(resourcePath) } +extension Path { + func appending(_ path: String) -> Path { + self + path + } +} + extension XCTestCase { func context(_ name: String, block: () throws -> Void) rethrows { if let _ = ProcessInfo().environment["XCTestConfigurationFilePath"] { diff --git a/Tests/buildconfigswiftTests/Resources/src/.env/production.yaml b/Tests/buildconfigswiftTests/Resources/src/production/API.yaml similarity index 100% rename from Tests/buildconfigswiftTests/Resources/src/.env/production.yaml rename to Tests/buildconfigswiftTests/Resources/src/production/API.yaml diff --git a/Tests/buildconfigswiftTests/Resources/src/.env/staging.json b/Tests/buildconfigswiftTests/Resources/src/staging/API.json similarity index 100% rename from Tests/buildconfigswiftTests/Resources/src/.env/staging.json rename to Tests/buildconfigswiftTests/Resources/src/staging/API.json