From 8346fdc15eab8b07d2331924f8c8773f43654ab2 Mon Sep 17 00:00:00 2001 From: Andrew Farquharson Date: Thu, 2 Nov 2023 12:09:47 +1300 Subject: [PATCH] Add models --- .github/workflows/swiftlint.yml | 16 ++ .github/workflows/test.yml | 15 ++ .gitignore | 12 ++ Package.resolved | 187 ++++++++++++++++++ Package.swift | 23 +++ Sources/rc-kit/Models/RCCancelReason.swift | 17 ++ Sources/rc-kit/Models/RCEntitlement.swift | 22 +++ Sources/rc-kit/Models/RCEnvironment.swift | 13 ++ Sources/rc-kit/Models/RCEvent.swift | 93 +++++++++ Sources/rc-kit/Models/RCEventBody.swift | 18 ++ Sources/rc-kit/Models/RCEventType.swift | 22 +++ Sources/rc-kit/Models/RCPeriodType.swift | 15 ++ Sources/rc-kit/Models/RCStore.swift | 16 ++ Sources/rc-kit/Models/RCSubscriber.swift | 28 +++ .../rc-kit/Models/RCSubscriberRequest.swift | 12 ++ .../rc-kit/RevenueCatClient+Application.swift | 46 +++++ Sources/rc-kit/RevenueCatClient.swift | 55 ++++++ Sources/rc-kit/RevenueCatConfiguration.swift | 12 ++ Tests/LinuxMain.swift | 7 + Tests/RCKitTests/VaporToolKitTests.swift | 11 ++ Tests/RCKitTests/XCTestManifests.swift | 9 + 21 files changed, 649 insertions(+) create mode 100644 .github/workflows/swiftlint.yml create mode 100644 .github/workflows/test.yml create mode 100644 .gitignore create mode 100644 Package.resolved create mode 100644 Package.swift create mode 100644 Sources/rc-kit/Models/RCCancelReason.swift create mode 100644 Sources/rc-kit/Models/RCEntitlement.swift create mode 100644 Sources/rc-kit/Models/RCEnvironment.swift create mode 100644 Sources/rc-kit/Models/RCEvent.swift create mode 100644 Sources/rc-kit/Models/RCEventBody.swift create mode 100644 Sources/rc-kit/Models/RCEventType.swift create mode 100644 Sources/rc-kit/Models/RCPeriodType.swift create mode 100644 Sources/rc-kit/Models/RCStore.swift create mode 100644 Sources/rc-kit/Models/RCSubscriber.swift create mode 100644 Sources/rc-kit/Models/RCSubscriberRequest.swift create mode 100644 Sources/rc-kit/RevenueCatClient+Application.swift create mode 100644 Sources/rc-kit/RevenueCatClient.swift create mode 100644 Sources/rc-kit/RevenueCatConfiguration.swift create mode 100644 Tests/LinuxMain.swift create mode 100644 Tests/RCKitTests/VaporToolKitTests.swift create mode 100644 Tests/RCKitTests/XCTestManifests.swift diff --git a/.github/workflows/swiftlint.yml b/.github/workflows/swiftlint.yml new file mode 100644 index 0000000..0d7fd1c --- /dev/null +++ b/.github/workflows/swiftlint.yml @@ -0,0 +1,16 @@ +name: SwiftLint + +on: + push: + paths: + - '.github/workflows/swiftlint.yml' + - '.swiftlint.yml' + - '**/*.swift' + +jobs: + SwiftLint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + - name: Run SwiftLint + uses: norio-nomura/action-swiftlint@3.1.0 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..b5e8e98 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,15 @@ +name: Swift Tests + +on: + push: + pull_request: + branches: [ develop ] + +jobs: + test_focal: + container: + image: swift:5.7-focal + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + - run: swift test --enable-test-discovery --sanitize=thread diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9e99441 --- /dev/null +++ b/.gitignore @@ -0,0 +1,12 @@ +Packages +.build +xcuserdata +*.xcodeproj +DerivedData/ +.DS_Store +db.sqlite +.swiftpm +Public/images/* +Public/presskits/* + +!.gitkeep \ No newline at end of file diff --git a/Package.resolved b/Package.resolved new file mode 100644 index 0000000..5374c63 --- /dev/null +++ b/Package.resolved @@ -0,0 +1,187 @@ +{ + "object": { + "pins": [ + { + "package": "async-http-client", + "repositoryURL": "https://github.com/swift-server/async-http-client.git", + "state": { + "branch": null, + "revision": "16f7e62c08c6969899ce6cc277041e868364e5cf", + "version": "1.19.0" + } + }, + { + "package": "async-kit", + "repositoryURL": "https://github.com/vapor/async-kit.git", + "state": { + "branch": null, + "revision": "7ece208cd401687641c88367a00e3ea2b04311f1", + "version": "1.19.0" + } + }, + { + "package": "console-kit", + "repositoryURL": "https://github.com/vapor/console-kit.git", + "state": { + "branch": null, + "revision": "ccd0773b3ad3c67a19918aaef6903678592bb087", + "version": "4.9.0" + } + }, + { + "package": "multipart-kit", + "repositoryURL": "https://github.com/vapor/multipart-kit.git", + "state": { + "branch": null, + "revision": "1adfd69df2da08f7931d4281b257475e32c96734", + "version": "4.5.4" + } + }, + { + "package": "routing-kit", + "repositoryURL": "https://github.com/vapor/routing-kit.git", + "state": { + "branch": null, + "revision": "88077f2c9d12777dcc89562fa581888ff7ba14ae", + "version": "4.8.1" + } + }, + { + "package": "swift-algorithms", + "repositoryURL": "https://github.com/apple/swift-algorithms.git", + "state": { + "branch": null, + "revision": "bcd4f369ac962bc3e5244c9df778739f8f5bdbf1", + "version": "1.1.0" + } + }, + { + "package": "swift-atomics", + "repositoryURL": "https://github.com/apple/swift-atomics.git", + "state": { + "branch": null, + "revision": "cd142fd2f64be2100422d658e7411e39489da985", + "version": "1.2.0" + } + }, + { + "package": "swift-collections", + "repositoryURL": "https://github.com/apple/swift-collections.git", + "state": { + "branch": null, + "revision": "a902f1823a7ff3c9ab2fba0f992396b948eda307", + "version": "1.0.5" + } + }, + { + "package": "swift-crypto", + "repositoryURL": "https://github.com/apple/swift-crypto.git", + "state": { + "branch": null, + "revision": "b51f1d6845b353a2121de1c6a670738ec33561a6", + "version": "3.1.0" + } + }, + { + "package": "swift-http-types", + "repositoryURL": "https://github.com/apple/swift-http-types", + "state": { + "branch": null, + "revision": "99d066e29effa8845e4761dd3f2f831edfdf8925", + "version": "1.0.0" + } + }, + { + "package": "swift-log", + "repositoryURL": "https://github.com/apple/swift-log.git", + "state": { + "branch": null, + "revision": "532d8b529501fb73a2455b179e0bbb6d49b652ed", + "version": "1.5.3" + } + }, + { + "package": "swift-metrics", + "repositoryURL": "https://github.com/apple/swift-metrics.git", + "state": { + "branch": null, + "revision": "971ba26378ab69c43737ee7ba967a896cb74c0d1", + "version": "2.4.1" + } + }, + { + "package": "swift-nio", + "repositoryURL": "https://github.com/apple/swift-nio.git", + "state": { + "branch": null, + "revision": "853522d90871b4b63262843196685795b5008c46", + "version": "2.61.1" + } + }, + { + "package": "swift-nio-extras", + "repositoryURL": "https://github.com/apple/swift-nio-extras.git", + "state": { + "branch": null, + "revision": "798c962495593a23fdea0c0c63fd55571d8dff51", + "version": "1.20.0" + } + }, + { + "package": "swift-nio-http2", + "repositoryURL": "https://github.com/apple/swift-nio-http2.git", + "state": { + "branch": null, + "revision": "3bd9004b9d685ed6b629760fc84903e48efec806", + "version": "1.29.0" + } + }, + { + "package": "swift-nio-ssl", + "repositoryURL": "https://github.com/apple/swift-nio-ssl.git", + "state": { + "branch": null, + "revision": "320bd978cceb8e88c125dcbb774943a92f6286e9", + "version": "2.25.0" + } + }, + { + "package": "swift-nio-transport-services", + "repositoryURL": "https://github.com/apple/swift-nio-transport-services.git", + "state": { + "branch": null, + "revision": "ebf8b9c365a6ce043bf6e6326a04b15589bd285e", + "version": "1.20.0" + } + }, + { + "package": "swift-numerics", + "repositoryURL": "https://github.com/apple/swift-numerics.git", + "state": { + "branch": null, + "revision": "0a5bc04095a675662cf24757cc0640aa2204253b", + "version": "1.0.2" + } + }, + { + "package": "vapor", + "repositoryURL": "https://github.com/vapor/vapor.git", + "state": { + "branch": null, + "revision": "3bf4e73955d029743c233f127f4259a101a764f5", + "version": "4.85.0" + } + }, + { + "package": "websocket-kit", + "repositoryURL": "https://github.com/vapor/websocket-kit.git", + "state": { + "branch": null, + "revision": "53fe0639a98903858d0196b699720decb42aee7b", + "version": "2.14.0" + } + } + ] + }, + "version": 1 +} diff --git a/Package.swift b/Package.swift new file mode 100644 index 0000000..bf46ba5 --- /dev/null +++ b/Package.swift @@ -0,0 +1,23 @@ +// swift-tools-version:5.5 +// The swift-tools-version declares the minimum version of Swift required to build this package. + +import PackageDescription + +let package = Package( + name: "rc-kit", + platforms: [ + .macOS(.v12) + ], + products: [ + .library(name: "rc-kit", targets: ["rc-kit"]), + ], + dependencies: [ + .package(url: "https://github.com/vapor/vapor.git", from: "4.0.0") + ], + targets: [ + .target( name: "rc-kit", dependencies: [ + .product(name: "Vapor", package: "vapor") + ]), + .testTarget(name: "RCKitTests", dependencies: ["rc-kit"]), + ] +) diff --git a/Sources/rc-kit/Models/RCCancelReason.swift b/Sources/rc-kit/Models/RCCancelReason.swift new file mode 100644 index 0000000..80ce1c0 --- /dev/null +++ b/Sources/rc-kit/Models/RCCancelReason.swift @@ -0,0 +1,17 @@ +// +// RCCancelReason.swift +// +// +// Created by Andrew Farquharson on 29/05/21. +// + +import Foundation + +enum RCCancelReason: String, Decodable { + case unsubscribe = "UNSUBSCRIBE" + case billingError = "BILLING_ERROR" + case developerInitiated = "DEVELOPER_INITIATED" + case priceIncrease = "PRICE_INCREASE" + case customerSupport = "CUSTOMER_SUPPORT" + case unknown +} diff --git a/Sources/rc-kit/Models/RCEntitlement.swift b/Sources/rc-kit/Models/RCEntitlement.swift new file mode 100644 index 0000000..56a8ec6 --- /dev/null +++ b/Sources/rc-kit/Models/RCEntitlement.swift @@ -0,0 +1,22 @@ +// +// RCEntitlement.swift +// +// +// Created by Andrew Farquharson on 7/09/21. +// + +import Vapor + +struct RCEntitlement: Content { + let expiresAt: Date + let gracePeriodExpiresAt: Date? + let productIdentifier: String + let purchasedAt: Date + + enum CodingKeys: String, CodingKey { + case expiresAt = "expires_date" + case gracePeriodExpiresAt = "grace_period_expires_date" + case productIdentifier = "product_identifier" + case purchasedAt = "purchase_date" + } +} diff --git a/Sources/rc-kit/Models/RCEnvironment.swift b/Sources/rc-kit/Models/RCEnvironment.swift new file mode 100644 index 0000000..52904b1 --- /dev/null +++ b/Sources/rc-kit/Models/RCEnvironment.swift @@ -0,0 +1,13 @@ +// +// RCEnvironment.swift +// +// +// Created by Andrew Farquharson on 29/05/21. +// + +import Foundation + +enum RCEnvironment: String, Decodable { + case sandbox = "SANDBOX" + case production = "PRODUCTION" +} diff --git a/Sources/rc-kit/Models/RCEvent.swift b/Sources/rc-kit/Models/RCEvent.swift new file mode 100644 index 0000000..6863f27 --- /dev/null +++ b/Sources/rc-kit/Models/RCEvent.swift @@ -0,0 +1,93 @@ +// +// RCEvent.swift +// +// +// Created by Andrew Farquharson on 29/05/21. +// + +import Foundation + +struct RCEvent { + let id: String + let aliases: [String]? + let appUserId: String? + let currency: String? + let entitlementId: String? // Deprecated. See entitlement_ids. + let entitlementIds: [String]? + let environment: RCEnvironment + let eventTimestamp: Date + let expirationAt: Date? + let isFamilyShare: Bool? + let originalAppUserId: String? + let originalTransactionId: String? + let periodType: RCPeriodType? + let presentedOfferingId: String? + let price: Double? + let priceInPurchasedCurrency: Double? + let productId: String? + let purchasedAt: Date + let store: RCStore + let takehomePercentage: Float? + let transactionId: String? + let type: RCEventType + let cancelReason: RCCancelReason? +} + +extension RCEvent: Decodable { + enum CodingKeys: String, CodingKey { + case id + case aliases + case appUserId = "app_user_id" + case currency + case entitlementId = "entitlement_id" + case entitlementIds = "entitlement_ids" + case environment + case eventTimestamp = "event_timestamp_ms" + case expirationAt = "expiration_at_ms" + case isFamilyShare = "is_family_share" + case originalAppUserId = "original_app_user_id" + case originalTransactionId = "original_transaction_id" + case periodType = "period_type" + case presentedOfferingId = "presented_offering_id" + case price + case priceInPurchasedCurrency = "price_in_purchased_currency" + case productId = "product_id" + case purchasedAt = "purchased_at_ms" + case store + case takehomePercentage = "takehome_percentage" + case transactionId = "transaction_id" + case type + case cancelReason = "cancel_reason" + } + + init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + self.id = try container.decode(String.self, forKey: .id) + self.aliases = try container.decodeIfPresent([String].self, forKey: .aliases) + self.appUserId = try container.decodeIfPresent(String.self, forKey: .appUserId) + self.currency = try container.decodeIfPresent(String.self, forKey: .currency) + self.entitlementId = try container.decodeIfPresent(String.self, forKey: .entitlementId) + self.entitlementIds = try container.decodeIfPresent([String].self, forKey: .entitlementIds) + self.environment = try container.decode(RCEnvironment.self, forKey: .environment) + self.eventTimestamp = Date(timeIntervalSince1970: try container.decode(TimeInterval.self, forKey: .eventTimestamp) / 1000) + if let expirationAtInterval = try container.decodeIfPresent(TimeInterval.self, forKey: .expirationAt) { + self.expirationAt = Date(timeIntervalSince1970: expirationAtInterval / 1000) + } else { + self.expirationAt = nil + } + self.isFamilyShare = try container.decodeIfPresent(Bool.self, forKey: .isFamilyShare) + self.originalAppUserId = try container.decodeIfPresent(String.self, forKey: .originalAppUserId) + self.originalTransactionId = try container.decodeIfPresent(String.self, forKey: .originalTransactionId) + self.periodType = try container.decodeIfPresent(RCPeriodType.self, forKey: .periodType) + self.presentedOfferingId = try container.decodeIfPresent(String.self, forKey: .presentedOfferingId) + self.price = try container.decodeIfPresent(Double.self, forKey: .price) + self.priceInPurchasedCurrency = try container.decodeIfPresent(Double.self, forKey: .priceInPurchasedCurrency) + self.productId = try container.decodeIfPresent(String.self, forKey: .productId) + self.purchasedAt = Date(timeIntervalSince1970: try container.decode(TimeInterval.self, forKey: .purchasedAt) / 1000) + self.store = try container.decode(RCStore.self, forKey: .store) + self.takehomePercentage = try container.decodeIfPresent(Float.self, forKey: .takehomePercentage) + self.transactionId = try container.decodeIfPresent(String.self, forKey: .transactionId) + self.type = try container.decode(RCEventType.self, forKey: .type) + self.cancelReason = try container.decodeIfPresent(RCCancelReason.self, forKey: .cancelReason) + } +} diff --git a/Sources/rc-kit/Models/RCEventBody.swift b/Sources/rc-kit/Models/RCEventBody.swift new file mode 100644 index 0000000..44f9478 --- /dev/null +++ b/Sources/rc-kit/Models/RCEventBody.swift @@ -0,0 +1,18 @@ +// +// RCEventBody.swift +// +// +// Created by Andrew Farquharson on 29/05/21. +// + +import Foundation + +struct RCEventBody: Decodable { + let version: String + let event: RCEvent + + enum CodingKeys: String, CodingKey { + case version = "api_version" + case event + } +} diff --git a/Sources/rc-kit/Models/RCEventType.swift b/Sources/rc-kit/Models/RCEventType.swift new file mode 100644 index 0000000..8a5c34d --- /dev/null +++ b/Sources/rc-kit/Models/RCEventType.swift @@ -0,0 +1,22 @@ +// +// RCEventType.swift +// +// +// Created by Andrew Farquharson on 29/05/21. +// + +import Foundation + +enum RCEventType: String, Decodable, CaseIterable { + case test = "TEST" + case expiration = "EXPIRATION" + case initialPurchase = "INITIAL_PURCHASE" + case nonRenewingPurchase = "NON_RENEWING_PURCHASE" + case renewal = "RENEWAL" + case productChange = "PRODUCT_CHANGE" + case cancellation = "CANCELLATION" + case uncancellation = "UNCANCELLATION" + case billingIssue = "BILLING_ISSUE" + case subscriberAlias = "SUBSCRIBER_ALIAS" + case subscriptionPaused = "SUBSCRIPTION_PAUSED" +} diff --git a/Sources/rc-kit/Models/RCPeriodType.swift b/Sources/rc-kit/Models/RCPeriodType.swift new file mode 100644 index 0000000..d5536d4 --- /dev/null +++ b/Sources/rc-kit/Models/RCPeriodType.swift @@ -0,0 +1,15 @@ +// +// RCPeriodType.swift +// +// +// Created by Andrew Farquharson on 29/05/21. +// + +import Foundation + +enum RCPeriodType: String, Decodable { + case trial = "TRIAL" + case intro = "INTRO" + case normal = "NORMAL" + case promotional = "PROMOTIONAL" +} diff --git a/Sources/rc-kit/Models/RCStore.swift b/Sources/rc-kit/Models/RCStore.swift new file mode 100644 index 0000000..9585856 --- /dev/null +++ b/Sources/rc-kit/Models/RCStore.swift @@ -0,0 +1,16 @@ +// +// RCStore.swift +// +// +// Created by Andrew Farquharson on 29/05/21. +// + +import Foundation + +enum RCStore: String, Decodable { + case playStore = "PLAY_STORE" + case appStore = "APP_STORE" + case stripe = "STRIPE" + case macAppStore = "MAC_APP_STORE" + case promotional = "PROMOTIONAL" +} diff --git a/Sources/rc-kit/Models/RCSubscriber.swift b/Sources/rc-kit/Models/RCSubscriber.swift new file mode 100644 index 0000000..ac9d900 --- /dev/null +++ b/Sources/rc-kit/Models/RCSubscriber.swift @@ -0,0 +1,28 @@ +// +// RCSubscriber.swift +// +// +// Created by Andrew Farquharson on 7/09/21. +// + +import Vapor + +struct RCSubscriber: Content { + let entitlements: E + let firstSeen: Date? + let lastSeen: Date? + let managementUrl: String? + let originalAppUserId: String? + let originalApplicationVersion: String? + let originalPurchaseDate: Date? + + enum CodingKeys: String, CodingKey { + case entitlements + case firstSeen = "first_seen" + case lastSeen = "last_seen" + case managementUrl = "management_url" + case originalAppUserId = "original_app_user_id" + case originalApplicationVersion = "original_application_version" + case originalPurchaseDate = "original_purchase_date" + } +} diff --git a/Sources/rc-kit/Models/RCSubscriberRequest.swift b/Sources/rc-kit/Models/RCSubscriberRequest.swift new file mode 100644 index 0000000..60c2b7c --- /dev/null +++ b/Sources/rc-kit/Models/RCSubscriberRequest.swift @@ -0,0 +1,12 @@ +// +// RCSubscriberRequest.swift +// +// +// Created by Andrew Farquharson on 7/09/21. +// + +import Vapor + +struct RCSubscriberRequest: Content { + let subscriber: RCSubscriber +} diff --git a/Sources/rc-kit/RevenueCatClient+Application.swift b/Sources/rc-kit/RevenueCatClient+Application.swift new file mode 100644 index 0000000..fc4cd05 --- /dev/null +++ b/Sources/rc-kit/RevenueCatClient+Application.swift @@ -0,0 +1,46 @@ +// +// RevenueCatClient+Application.swift +// +// +// Created by Andrew Farquharson on 7/09/21. +// + +import Vapor + +extension Application { + public var revenueCat: RevenueCat { + .init(application: self) + } + + public struct RevenueCat { + let application: Application + + struct ConfigurationKey: StorageKey { + typealias Value = RevenueCatConfiguration + } + + public var configuration: RevenueCatConfiguration? { + get { + self.application.storage[ConfigurationKey.self] + } + nonmutating set { + self.application.storage[ConfigurationKey.self] = newValue + } + } + + private var client: RevenueCatClient { + guard let configuration = self.configuration else { + fatalError("RevenueCatClient not configured. Use app.revenuecat.configuration = ...") + } + return .init(configuration: configuration, client: application.client) + } + } +} + +// MARK: - RevenueCat + +extension Application.RevenueCat { + func getSubscriber(_ revenueCatID: String) async throws -> RCSubscriber { + return try await client.getSubscriber(revenueCatID) + } +} diff --git a/Sources/rc-kit/RevenueCatClient.swift b/Sources/rc-kit/RevenueCatClient.swift new file mode 100644 index 0000000..466df83 --- /dev/null +++ b/Sources/rc-kit/RevenueCatClient.swift @@ -0,0 +1,55 @@ +// +// RevenueCatClient.swift +// +// +// Created by Andrew Farquharson on 7/09/21. +// + +import Vapor + +class RevenueCatClient { + + // MARK: - Properties + + private let configuration: RevenueCatConfiguration + + private let client: Client + + // MARK: - Init + + init(configuration: RevenueCatConfiguration, client: Client) { + self.configuration = configuration + self.client = client + } + + // MARK: - Functions + + private func headers() -> HTTPHeaders { + var result: HTTPHeaders = .init() + result.add(name: "Authorization", value: "Bearer " + configuration.token) + result.add(name: .contentType, value: "application/json") + result.add(name: .accept, value: "application/json") + return result + } + + func getSubscriber(_ revenueCatID: String) async throws -> RCSubscriber { + return try await client.get(createUri(revenueCatID: revenueCatID)) { req in + req.headers = self.headers() + } + .flatMapThrowing { res -> RCSubscriberRequest in + do { + return try res.content.decode(RCSubscriberRequest.self) + } catch let error { + throw error + } + } + .map(\.subscriber).get() + } +} + +private extension RevenueCatClient { + func createUri(revenueCatID: String) -> URI { + let urlString: String = "https://api.revenuecat.com/v1/subscribers/\(revenueCatID)" + return URI(string: urlString) + } +} diff --git a/Sources/rc-kit/RevenueCatConfiguration.swift b/Sources/rc-kit/RevenueCatConfiguration.swift new file mode 100644 index 0000000..e15064e --- /dev/null +++ b/Sources/rc-kit/RevenueCatConfiguration.swift @@ -0,0 +1,12 @@ +// +// RevenueCatConfiguration.swift +// +// +// Created by Andrew Farquharson on 7/09/21. +// + +import Vapor + +public struct RevenueCatConfiguration: Content { + let token: String +} diff --git a/Tests/LinuxMain.swift b/Tests/LinuxMain.swift new file mode 100644 index 0000000..9bf87b1 --- /dev/null +++ b/Tests/LinuxMain.swift @@ -0,0 +1,7 @@ +import XCTest + +import VaporToolKitTests + +var tests = [XCTestCaseEntry]() +tests += VaporToolKitTests.allTests() +XCTMain(tests) diff --git a/Tests/RCKitTests/VaporToolKitTests.swift b/Tests/RCKitTests/VaporToolKitTests.swift new file mode 100644 index 0000000..e57c77c --- /dev/null +++ b/Tests/RCKitTests/VaporToolKitTests.swift @@ -0,0 +1,11 @@ +import XCTest + +final class VaporToolKitTests: XCTestCase { + func testNothing() { + XCTAssert(true) + } + + static var allTests = [ + ("testNothing", testNothing), + ] +} diff --git a/Tests/RCKitTests/XCTestManifests.swift b/Tests/RCKitTests/XCTestManifests.swift new file mode 100644 index 0000000..655a823 --- /dev/null +++ b/Tests/RCKitTests/XCTestManifests.swift @@ -0,0 +1,9 @@ +import XCTest + +#if !canImport(ObjectiveC) +public func allTests() -> [XCTestCaseEntry] { + return [ + testCase(VaporToolKitTests.allTests), + ] +} +#endif