Skip to content

Commit

Permalink
Adopt swift-testing for Timeout tests (#2051)
Browse files Browse the repository at this point in the history
Motivation:

swift-testing has a number of advantages over XCTest (parameterisation,
organisation, failure messages etc.), we should start using it instead
of XCTest.

Modifications:

- Convert the Timeout tests

Results:

Better tests
  • Loading branch information
glbrntt authored Sep 11, 2024
1 parent b036fb7 commit c51784e
Showing 1 changed file with 64 additions and 185 deletions.
249 changes: 64 additions & 185 deletions Tests/GRPCCoreTests/TimeoutTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}

0 comments on commit c51784e

Please sign in to comment.