From 873742220702da22288d2828fe16474fe2934e11 Mon Sep 17 00:00:00 2001 From: YR Chen Date: Sun, 5 Feb 2023 12:06:15 +0800 Subject: [PATCH 1/4] Adds testing infrastructure --- .github/workflows/build.yml | 9 ++++- Package.swift | 5 +++ .../AssertBuilder.swift | 38 +++++++++++++++++++ 3 files changed, 50 insertions(+), 2 deletions(-) create mode 100644 Sources/TecoCodeGeneratorTestHelpers/AssertBuilder.swift diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index dc943de..90c05a0 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,7 +1,9 @@ name: Build on: - - push - - pull_request + push: + branches: + - main + pull_request: jobs: build: @@ -17,3 +19,6 @@ jobs: uses: actions/checkout@v3 - name: Build run: swift build -c ${{ matrix.build-config }} + - name: Test + if: ${{ matrix.build-config == 'debug' }} + run: swift test diff --git a/Package.swift b/Package.swift index 86b4f82..e3bdc48 100644 --- a/Package.swift +++ b/Package.swift @@ -76,5 +76,10 @@ let package = Package( dependencies: [ .byName(name: "TecoCodeGeneratorCommons"), ]), + .target( + name: "TecoCodeGeneratorTestHelpers", + dependencies: [ + .byName(name: "TecoCodeGeneratorCommons"), + ]), ] ) diff --git a/Sources/TecoCodeGeneratorTestHelpers/AssertBuilder.swift b/Sources/TecoCodeGeneratorTestHelpers/AssertBuilder.swift new file mode 100644 index 0000000..ddd885b --- /dev/null +++ b/Sources/TecoCodeGeneratorTestHelpers/AssertBuilder.swift @@ -0,0 +1,38 @@ +import SwiftSyntax +@_implementationOnly import TecoCodeGeneratorCommons +import XCTest + +private func buildSyntax(_ buildable: some SyntaxProtocol) -> [String] { + // Format the code. + let source = buildable.formatted(using: CodeGenerationFormat()) + + // Work around styling issues regarding blank lines. + let code = source.description.trimmingCharacters(in: .whitespacesAndNewlines) + + // Work around styling issues regarding trailing whitespaces. + return code.split(omittingEmptySubsequences: false, whereSeparator: \.isNewline).map { + var line = $0 + while line.last?.isWhitespace == true { + line.removeLast() + } + return String(line) + } +} + +public func AssertBuilder(_ buildable: some SyntaxProtocol, _ result: String) { + // Format the code. + let code = buildSyntax(buildable).joined(separator: "\n") + + // Assert build result + XCTAssertEqual(code, result) +} + +public func AssertBuilder(_ buildable: some SyntaxProtocol, contains lines: [String]) { + // Format the code. + let code = buildSyntax(buildable) + + // Assert build result + for line in lines { + XCTAssertTrue(code.contains(line)) + } +} From f37f38f0b75ac2c59edcddbf17f5038190fd3a05 Mon Sep 17 00:00:00 2001 From: YR Chen Date: Sun, 5 Feb 2023 12:07:42 +0800 Subject: [PATCH 2/4] Adds tests for `TecoDateWrapperGenerator` --- Package.swift | 6 ++++ .../TecoDateWrapperGeneratorTests.swift | 30 +++++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 Tests/TecoDateWrapperGeneratorTests/TecoDateWrapperGeneratorTests.swift diff --git a/Package.swift b/Package.swift index e3bdc48..114803d 100644 --- a/Package.swift +++ b/Package.swift @@ -81,5 +81,11 @@ let package = Package( dependencies: [ .byName(name: "TecoCodeGeneratorCommons"), ]), + .testTarget( + name: "TecoDateWrapperGeneratorTests", + dependencies: [ + .byName(name: "TecoCodeGeneratorTestHelpers"), + .byName(name: "TecoDateWrapperGenerator"), + ]), ] ) diff --git a/Tests/TecoDateWrapperGeneratorTests/TecoDateWrapperGeneratorTests.swift b/Tests/TecoDateWrapperGeneratorTests/TecoDateWrapperGeneratorTests.swift new file mode 100644 index 0000000..ab89cce --- /dev/null +++ b/Tests/TecoDateWrapperGeneratorTests/TecoDateWrapperGeneratorTests.swift @@ -0,0 +1,30 @@ +import TecoCodeGeneratorTestHelpers +import XCTest + +#if Xcode // Works around FB11980900 +@testable import teco_date_wrapper_generator +#else +@testable import TecoDateWrapperGenerator +#endif + +final class TecoDateWrapperGeneratorTests: XCTestCase { + func testImportDeclsBuilder() { + AssertBuilder(buildImportDecls(for: .date), contains: [ + "import struct Foundation.Date", + "import class Foundation.DateFormatter" + ]) + AssertBuilder(buildImportDecls(for: .timestamp), contains: [ + "import struct Foundation.Date", + "import class Foundation.DateFormatter" + ]) + AssertBuilder(buildImportDecls(for: .timestamp_iso8601), contains: [ + "import struct Foundation.Date", + "import class Foundation.ISO8601DateFormatter" + ]) + } + + func testDateWrapperNames() { + let expected: Set = ["TCDateEncoding", "TCTimestampEncoding", "TCTimestampISO8601Encoding"] + XCTAssertEqual(Set(DateEncoding.all.map(\.rawValue)), expected) + } +} From bdd082f9129b1ed3f5de8615166cfabde26766cd Mon Sep 17 00:00:00 2001 From: YR Chen Date: Thu, 9 Feb 2023 12:15:52 +0800 Subject: [PATCH 3/4] Adds tests for `TecoCommonErrorGenerator` --- Package.swift | 6 + .../TecoCommonErrorGeneratorTests.swift | 103 ++++++++++++++++++ 2 files changed, 109 insertions(+) create mode 100644 Tests/TecoCommonErrorGeneratorTests/TecoCommonErrorGeneratorTests.swift diff --git a/Package.swift b/Package.swift index 114803d..1425402 100644 --- a/Package.swift +++ b/Package.swift @@ -87,5 +87,11 @@ let package = Package( .byName(name: "TecoCodeGeneratorTestHelpers"), .byName(name: "TecoDateWrapperGenerator"), ]), + .testTarget( + name: "TecoCommonErrorGeneratorTests", + dependencies: [ + .byName(name: "TecoCodeGeneratorTestHelpers"), + .byName(name: "TecoCommonErrorGenerator"), + ]), ] ) diff --git a/Tests/TecoCommonErrorGeneratorTests/TecoCommonErrorGeneratorTests.swift b/Tests/TecoCommonErrorGeneratorTests/TecoCommonErrorGeneratorTests.swift new file mode 100644 index 0000000..0de6ad3 --- /dev/null +++ b/Tests/TecoCommonErrorGeneratorTests/TecoCommonErrorGeneratorTests.swift @@ -0,0 +1,103 @@ +import TecoCodeGeneratorTestHelpers +import XCTest + +#if Xcode // Works around FB11980900 +@testable import teco_common_error_generator +#else +@testable import TecoCommonErrorGenerator +#endif + +final class TecoCommonErrorGeneratorTests: XCTestCase { + func testCommonErrorStructDeclBuilder() { + let errors = [ + CommonError(code: "ActionOffline", description: "This API has been deprecated.\n接口已下线。", solution: nil), + CommonError( + code: "AuthFailure.SecretIdNotFound", + description: """ + Key does not exist. Check if the key has been deleted or disabled in the console, and if not, check if the key is correctly entered. Note that whitespaces should not exist before or after the key. + 密钥不存在。请在[控制台](https://console.cloud.tencent.com/cam/capi)检查密钥是否已被删除或者禁用,如状态正常,请检查密钥是否填写正确,注意前后不得有空格。 + """, + solution: """ + - The SecretId is not found, please ensure that your SecretId is correct. + SecretId不存在,请输入正确的密钥。 + + 当您接口返回这些错误时,说明您调接口时用的密钥信息不存在,请在控制台检查密钥是否已被删除或者禁用,如状态正常,请检查密钥是否填写正确,注意前后不得有空格。 + """ + ), + ] + AssertBuilder(buildCommonErrorStructDecl(from: errors), """ + /// Common error type returned by Tencent Cloud. + public struct TCCommonError: TCServiceErrorType { + enum Code: String { + case actionOffline = "ActionOffline" + case authFailure_SecretIdNotFound = "AuthFailure.SecretIdNotFound" + } + + private let error: Code + + public let context: TCErrorContext? + + public var errorCode: String { + self.error.rawValue + } + + public init?(errorCode: String, context: TCErrorContext) { + guard let error = Code(rawValue: errorCode) else { + return nil + } + self.error = error + self.context = context + } + + public func asCommonError() -> TCCommonError? { + return self + } + + internal init(_ error: Code, context: TCErrorContext? = nil) { + self.error = error + self.context = context + } + + /// This API has been deprecated. + /// 接口已下线。 + public static var actionOffline: TCCommonError { + TCCommonError(.actionOffline) + } + + /// Key does not exist. Check if the key has been deleted or disabled in the console, and if not, check if the key is correctly entered. Note that whitespaces should not exist before or after the key. + /// 密钥不存在。请在[控制台](https://console.cloud.tencent.com/cam/capi)检查密钥是否已被删除或者禁用,如状态正常,请检查密钥是否填写正确,注意前后不得有空格。 + /// + /// - The SecretId is not found, please ensure that your SecretId is correct. + /// SecretId不存在,请输入正确的密钥。 + /// + /// 当您接口返回这些错误时,说明您调接口时用的密钥信息不存在,请在控制台检查密钥是否已被删除或者禁用,如状态正常,请检查密钥是否填写正确,注意前后不得有空格。 + public static var authFailure_SecretIdNotFound: TCCommonError { + TCCommonError(.authFailure_SecretIdNotFound) + } + } + """) + } + + func testFormatErrorSolution() { + let solution = """ + The provided credentials could not be validated. Please check your signature is correct. + 请求签名验证失败,请检查您的签名计算是否正确。 + The provided credentials could not be validated because of exceeding request size limit, please use new signature method `TC3-HMAC-SHA256`. + 由于请求包大小超过限制,请求签名验证失败,请使用新的签名方法 `TC3-HMAC-SHA256`。 + + 当您看到此类错误信息,说明此次请求签名计算错误,强烈建议使用官网提供的 SDK 调用,自己计算签名比较容易出错,SDK 屏蔽了计算签名的细节,调用者只需关注接口参数。 + 如果仍然想自己计算签名,参照官网签名文档,可以在API Explorer【签名串生成】处进行签名验证。 + 此外,SecretKey输入错误也可能会导致签名计算错误。 + """ + XCTAssertEqual(formatErrorSolution(solution), """ + - The provided credentials could not be validated. Please check your signature is correct. + 请求签名验证失败,请检查您的签名计算是否正确。 + - The provided credentials could not be validated because of exceeding request size limit, please use new signature method `TC3-HMAC-SHA256`. + 由于请求包大小超过限制,请求签名验证失败,请使用新的签名方法 `TC3-HMAC-SHA256`。 + + 当您看到此类错误信息,说明此次请求签名计算错误,强烈建议使用官网提供的 SDK 调用,自己计算签名比较容易出错,SDK 屏蔽了计算签名的细节,调用者只需关注接口参数。 + 如果仍然想自己计算签名,参照官网签名文档,可以在API Explorer【签名串生成】处进行签名验证。 + 此外,SecretKey输入错误也可能会导致签名计算错误。 + """) + } +} From df6dfca1ebe3c72c7c1af1d18d60d12ba17920ee Mon Sep 17 00:00:00 2001 From: YR Chen Date: Thu, 9 Feb 2023 13:06:32 +0800 Subject: [PATCH 4/4] Adds tests for `TecoPackageGenerator` --- Package.swift | 6 +++ .../TecoPackageGeneratorTests.swift | 48 +++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 Tests/TecoPackageGeneratorTests/TecoPackageGeneratorTests.swift diff --git a/Package.swift b/Package.swift index 1425402..0f7a224 100644 --- a/Package.swift +++ b/Package.swift @@ -93,5 +93,11 @@ let package = Package( .byName(name: "TecoCodeGeneratorTestHelpers"), .byName(name: "TecoCommonErrorGenerator"), ]), + .testTarget( + name: "TecoPackageGeneratorTests", + dependencies: [ + .byName(name: "TecoCodeGeneratorTestHelpers"), + .byName(name: "TecoPackageGenerator"), + ]), ] ) diff --git a/Tests/TecoPackageGeneratorTests/TecoPackageGeneratorTests.swift b/Tests/TecoPackageGeneratorTests/TecoPackageGeneratorTests.swift new file mode 100644 index 0000000..5d9b4f9 --- /dev/null +++ b/Tests/TecoPackageGeneratorTests/TecoPackageGeneratorTests.swift @@ -0,0 +1,48 @@ +import TecoCodeGeneratorTestHelpers +import XCTest + +#if Xcode // Works around FB11980900 +@testable import teco_package_generator +#else +@testable import TecoPackageGenerator +#endif + +final class TecoPackageGeneratorTests: XCTestCase { + private let services: [(service: String, version: String)] = [ + ("Aa", "V20200224"), ("Ams", "V20200608"), ("Ams", "V20201229"), + ] + + func testProductExprBuilder() { + AssertBuilder(buildProductExpr(name: "TecoDemo"), """ + .library(name: "TecoDemo", targets: ["TecoDemo"]) + """) + AssertBuilder(buildProductExpr(name: "TecoDemo", trailingComma: true), """ + .library(name: "TecoDemo", targets: ["TecoDemo"]), + """) + } + + func testProductExprListBuilder() { + AssertBuilder(buildProductListExpr(for: services), contains: [ + #" .library(name: "TecoAaV20200224", targets: ["TecoAaV20200224"]),"#, + #" .library(name: "TecoAmsV20200608", targets: ["TecoAmsV20200608"]),"#, + #" .library(name: "TecoAmsV20201229", targets: ["TecoAmsV20201229"]),"#, + ]) + } + + func testTargetExprBuilder() { + AssertBuilder(buildTargetExpr(name: "TecoDemo", path: "./Demo"), """ + .target(name: "TecoDemo", dependencies: [.product(name: "TecoCore", package: "teco-core")], path: "./Demo") + """) + AssertBuilder(buildTargetExpr(name: "TecoDemo", path: "./Demo", trailingComma: true), """ + .target(name: "TecoDemo", dependencies: [.product(name: "TecoCore", package: "teco-core")], path: "./Demo"), + """) + } + + func testTargetExprListBuilder() { + AssertBuilder(buildTargetListExpr(for: services), contains: [ + #" .target(name: "TecoAaV20200224", dependencies: [.product(name: "TecoCore", package: "teco-core")], path: "./Sources/Teco/Aa/V20200224"),"#, + #" .target(name: "TecoAmsV20201229", dependencies: [.product(name: "TecoCore", package: "teco-core")], path: "./Sources/Teco/Ams/V20201229"),"#, + #" .target(name: "TecoAmsV20200608", dependencies: [.product(name: "TecoCore", package: "teco-core")], path: "./Sources/Teco/Ams/V20200608"),"#, + ]) + } +}