diff --git a/Tests/GRPCCoreTests/TimeoutTests.swift b/Tests/GRPCCoreTests/TimeoutTests.swift index 80be5ea1f..a22bb32be 100644 --- a/Tests/GRPCCoreTests/TimeoutTests.swift +++ b/Tests/GRPCCoreTests/TimeoutTests.swift @@ -13,193 +13,72 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import XCTest -@testable import GRPCCore - -@available(macOS 13, iOS 16, tvOS 16, watchOS 9, *) -final class TimeoutTests: XCTestCase { - func testDecodeInvalidTimeout_Empty() { - let timeoutHeader = "" - XCTAssertNil(Timeout(decoding: timeoutHeader)) - } - - func testDecodeInvalidTimeout_NoAmount() { - let timeoutHeader = "H" - XCTAssertNil(Timeout(decoding: timeoutHeader)) - } - - func testDecodeInvalidTimeout_NoUnit() { - let timeoutHeader = "123" - XCTAssertNil(Timeout(decoding: timeoutHeader)) - } - - func testDecodeInvalidTimeout_TooLongAmount() { - let timeoutHeader = "100000000S" - XCTAssertNil(Timeout(decoding: timeoutHeader)) - } - - func testDecodeInvalidTimeout_InvalidUnit() { - let timeoutHeader = "123j" - XCTAssertNil(Timeout(decoding: timeoutHeader)) - } - - func testDecodeValidTimeout_Hours() throws { - let timeoutHeader = "123H" - let timeout = Timeout(decoding: timeoutHeader) - let unwrappedTimeout = try XCTUnwrap(timeout) - XCTAssertEqual(unwrappedTimeout.duration, Duration.hours(123)) - XCTAssertEqual(unwrappedTimeout.wireEncoding, timeoutHeader) - } - - func testDecodeValidTimeout_Minutes() throws { - let timeoutHeader = "123M" - let timeout = Timeout(decoding: timeoutHeader) - let unwrappedTimeout = try XCTUnwrap(timeout) - XCTAssertEqual(unwrappedTimeout.duration, Duration.minutes(123)) - XCTAssertEqual(unwrappedTimeout.wireEncoding, timeoutHeader) - } - - func testDecodeValidTimeout_Seconds() throws { - let timeoutHeader = "123S" - let timeout = Timeout(decoding: timeoutHeader) - let unwrappedTimeout = try XCTUnwrap(timeout) - XCTAssertEqual(unwrappedTimeout.duration, Duration.seconds(123)) - XCTAssertEqual(unwrappedTimeout.wireEncoding, timeoutHeader) - } - - func testDecodeValidTimeout_Milliseconds() throws { - let timeoutHeader = "123m" - let timeout = Timeout(decoding: timeoutHeader) - let unwrappedTimeout = try XCTUnwrap(timeout) - XCTAssertEqual(unwrappedTimeout.duration, Duration.milliseconds(123)) - XCTAssertEqual(unwrappedTimeout.wireEncoding, timeoutHeader) - } - - func testDecodeValidTimeout_Microseconds() throws { - let timeoutHeader = "123u" - let timeout = Timeout(decoding: timeoutHeader) - let unwrappedTimeout = try XCTUnwrap(timeout) - XCTAssertEqual(unwrappedTimeout.duration, Duration.microseconds(123)) - XCTAssertEqual(unwrappedTimeout.wireEncoding, timeoutHeader) - } - - func testDecodeValidTimeout_Nanoseconds() throws { - let timeoutHeader = "123n" - let timeout = Timeout(decoding: timeoutHeader) - let unwrappedTimeout = try XCTUnwrap(timeout) - XCTAssertEqual(unwrappedTimeout.duration, Duration.nanoseconds(123)) - XCTAssertEqual(unwrappedTimeout.wireEncoding, timeoutHeader) - } +import Testing - func testEncodeValidTimeout_Hours() { - let duration = Duration.hours(123) - let timeout = Timeout(duration: duration) - XCTAssertEqual(timeout.duration.components.seconds, duration.components.seconds) - XCTAssertEqual(timeout.duration.components.attoseconds, duration.components.attoseconds) - } - - func testEncodeValidTimeout_Minutes() { - let duration = Duration.minutes(43) - let timeout = Timeout(duration: duration) - XCTAssertEqual(timeout.duration.components.seconds, duration.components.seconds) - XCTAssertEqual(timeout.duration.components.attoseconds, duration.components.attoseconds) - } - - func testEncodeValidTimeout_Seconds() { - let duration = Duration.seconds(12345) - let timeout = Timeout(duration: duration) - XCTAssertEqual(timeout.duration.components.seconds, duration.components.seconds) - XCTAssertEqual(timeout.duration.components.attoseconds, duration.components.attoseconds) - } - - func testEncodeValidTimeout_Seconds_TooLong_Minutes() { - let duration = Duration.seconds(111_111_111) - let timeout = Timeout(duration: duration) - // The conversion from seconds to minutes results in a loss of precision. - // 111,111,111 seconds / 60 = 1,851,851.85 minutes -rounding up-> 1,851,852 minutes * 60 = 111,111,120 seconds - let expectedRoundedDuration = Duration.minutes(1_851_852) - XCTAssertEqual(timeout.duration.components.seconds, expectedRoundedDuration.components.seconds) - XCTAssertEqual( - timeout.duration.components.attoseconds, - expectedRoundedDuration.components.attoseconds - ) - } - - func testEncodeValidTimeout_Seconds_TooLong_Hours() { - let duration = Duration.seconds(9_999_999_999 as Int64) - let timeout = Timeout(duration: duration) - // The conversion from seconds to hours results in a loss of precision. - // 9,999,999,999 seconds / 60 = 166,666,666.65 minutes -rounding up-> - // 166,666,667 minutes / 60 = 2,777,777.78 hours -rounding up-> - // 2,777,778 hours * 60 -> 166,666,680 minutes * 60 = 10,000,000,800 seconds - let expectedRoundedDuration = Duration.hours(2_777_778) - XCTAssertEqual(timeout.duration.components.seconds, expectedRoundedDuration.components.seconds) - XCTAssertEqual( - timeout.duration.components.attoseconds, - expectedRoundedDuration.components.attoseconds - ) - } - - func testEncodeValidTimeout_Seconds_TooLong_MaxAmount() { - let duration = Duration.seconds(999_999_999_999 as Int64) - let timeout = Timeout(duration: duration) - // The conversion from seconds to hours results in a number that still has - // more than the maximum allowed 8 digits, so we must clamp it. - // Make sure that `Timeout.maxAmount` is the amount used for the resulting timeout. - let expectedRoundedDuration = Duration.hours(Timeout.maxAmount) - XCTAssertEqual(timeout.duration.components.seconds, expectedRoundedDuration.components.seconds) - XCTAssertEqual( - timeout.duration.components.attoseconds, - expectedRoundedDuration.components.attoseconds - ) - } - - func testEncodeValidTimeout_SecondsAndMilliseconds() { - let duration = Duration(secondsComponent: 100, attosecondsComponent: Int64(1e+17)) - let timeout = Timeout(duration: duration) - XCTAssertEqual(timeout.duration.components.seconds, duration.components.seconds) - XCTAssertEqual(timeout.duration.components.attoseconds, duration.components.attoseconds) - } - - func testEncodeValidTimeout_SecondsAndMicroseconds() { - let duration = Duration(secondsComponent: 1, attosecondsComponent: Int64(1e+14)) - let timeout = Timeout(duration: duration) - XCTAssertEqual(timeout.duration.components.seconds, duration.components.seconds) - XCTAssertEqual(timeout.duration.components.attoseconds, duration.components.attoseconds) - } - - func testEncodeValidTimeout_SecondsAndNanoseconds() { - let duration = Duration(secondsComponent: 1, attosecondsComponent: Int64(1e+11)) - let timeout = Timeout(duration: duration) - // We can't convert seconds to nanoseconds because that would require at least - // 9 digits, and the maximum allowed is 8: we expect to simply drop the nanoseconds. - let expectedRoundedDuration = Duration.seconds(1) - XCTAssertEqual(timeout.duration.components.seconds, expectedRoundedDuration.components.seconds) - XCTAssertEqual( - timeout.duration.components.attoseconds, - expectedRoundedDuration.components.attoseconds - ) - } - - func testEncodeValidTimeout_Milliseconds() { - let duration = Duration.milliseconds(100) - let timeout = Timeout(duration: duration) - XCTAssertEqual(timeout.duration.components.seconds, duration.components.seconds) - XCTAssertEqual(timeout.duration.components.attoseconds, duration.components.attoseconds) - } - - func testEncodeValidTimeout_Microseconds() { - let duration = Duration.microseconds(100) - let timeout = Timeout(duration: duration) - XCTAssertEqual(timeout.duration.components.seconds, duration.components.seconds) - XCTAssertEqual(timeout.duration.components.attoseconds, duration.components.attoseconds) - } +@testable import GRPCCore - func testEncodeValidTimeout_Nanoseconds() { - let duration = Duration.nanoseconds(100) - let timeout = Timeout(duration: duration) - XCTAssertEqual(timeout.duration.components.seconds, duration.components.seconds) - XCTAssertEqual(timeout.duration.components.attoseconds, duration.components.attoseconds) +struct TimeoutTests { + @Test("Initialize from invalid String value", arguments: ["", "H", "123", "100000000S", "123j"]) + func initFromStringWithInvalidValue(_ value: String) throws { + #expect(Timeout(decoding: value) == nil) + } + + @Test( + "Initialize from String", + arguments: [ + ("123H", .hours(123)), + ("123M", .minutes(123)), + ("123S", .seconds(123)), + ("123m", .milliseconds(123)), + ("123u", .microseconds(123)), + ("123n", .nanoseconds(123)), + ] as [(String, Duration)] + ) + func initFromString(_ value: String, expected: Duration) throws { + let timeout = try #require(Timeout(decoding: value)) + #expect(timeout.duration == expected) + } + + @Test( + "Initialize from Duration", + arguments: [ + .hours(123), + .minutes(43), + .seconds(12345), + .milliseconds(100), + .microseconds(100), + .nanoseconds(100), + ] as [Duration] + ) + func initFromDuration(_ value: Duration) { + let timeout = Timeout(duration: value) + #expect(timeout.duration == value) + } + + @Test( + "Initialize from Duration with loss of precision", + arguments: [ + // 111,111,111 seconds / 60 = 1,851,851.85 minutes -rounding up-> 1,851,852 minutes * 60 = 111,111,120 seconds + (.seconds(111_111_111), .minutes(1_851_852)), + + // 9,999,999,999 seconds / 60 = 166,666,666.65 minutes -rounding up-> + // 166,666,667 minutes / 60 = 2,777,777.78 hours -rounding up-> + // 2,777,778 hours * 60 -> 166,666,680 minutes * 60 = 10,000,000,800 seconds + (.seconds(9_999_999_999 as Int64), .hours(2_777_778)), + + // The conversion from seconds to hours results in a number that still has + // more than the maximum allowed 8 digits, so we must clamp it. + // Make sure that `Timeout.maxAmount` is the amount used for the resulting timeout. + (.seconds(999_999_999_999 as Int64), .hours(Timeout.maxAmount)), + + // We can't convert seconds to nanoseconds because that would require at least + // 9 digits, and the maximum allowed is 8: we expect to simply drop the nanoseconds. + (Duration(secondsComponent: 1, attosecondsComponent: Int64(1e11)), .seconds(1)), + ] as [(Duration, Duration)] + ) + func initFromDurationWithLossOfPrecision(original: Duration, rounded: Duration) { + let timeout = Timeout(duration: original) + #expect(timeout.duration == rounded) } }