Skip to content

Commit

Permalink
Make GeneralizedTime and UTCTime Comparable. (#29)
Browse files Browse the repository at this point in the history
In many cases it's useful to be able to place these into a total order.
This patch adds support for ordering them.
  • Loading branch information
Lukasa authored May 18, 2023
1 parent c43fef6 commit 1c5387a
Show file tree
Hide file tree
Showing 4 changed files with 142 additions and 0 deletions.
13 changes: 13 additions & 0 deletions Sources/SwiftASN1/Basic ASN1 Types/GeneralizedTime.swift
Original file line number Diff line number Diff line change
Expand Up @@ -196,3 +196,16 @@ public struct GeneralizedTime: DERImplicitlyTaggable, Hashable, Sendable {
}
}
}

extension GeneralizedTime: Comparable {
@inlinable
public static func <(lhs: GeneralizedTime, rhs: GeneralizedTime) -> Bool {
if lhs.year < rhs.year { return true }
if lhs.month < rhs.month { return true }
if lhs.day < rhs.day { return true }
if lhs.hours < rhs.hours { return true }
if lhs.minutes < rhs.minutes { return true }
if lhs.seconds < rhs.seconds { return true }
return lhs.fractionalSeconds < rhs.fractionalSeconds
}
}
12 changes: 12 additions & 0 deletions Sources/SwiftASN1/Basic ASN1 Types/UTCTime.swift
Original file line number Diff line number Diff line change
Expand Up @@ -180,3 +180,15 @@ public struct UTCTime: DERImplicitlyTaggable, Hashable, Sendable {
}
}
}

extension UTCTime: Comparable {
@inlinable
public static func <(lhs: UTCTime, rhs: UTCTime) -> Bool {
if lhs.year < rhs.year { return true }
if lhs.month < rhs.month { return true }
if lhs.day < rhs.day { return true }
if lhs.hours < rhs.hours { return true }
if lhs.minutes < rhs.minutes { return true }
return lhs.seconds < rhs.seconds
}
}
51 changes: 51 additions & 0 deletions Tests/SwiftASN1Tests/GeneralizedTimeTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -177,4 +177,55 @@ final class GeneralizedTimeTests: XCTestCase {

XCTAssertThrowsError(try GeneralizedTime(derEncoded: invalidBytes))
}

func testComparisons() throws {
enum ExpectedComparisonResult {
case lessThan
case equal
case greaterThan
}

let original = try GeneralizedTime(year: 2020, month: 03, day: 03, hours: 03, minutes: 03, seconds: 03, fractionalSeconds: 0.105)

func modify<Modifiable: AdditiveArithmetic>(_ field: WritableKeyPath<GeneralizedTime, Modifiable>, of time: GeneralizedTime, by modifier: Modifiable) -> GeneralizedTime {
var copy = time
copy[keyPath: field] += modifier
return copy
}

let integerTransformable: [WritableKeyPath<GeneralizedTime, Int>] = [
\.year, \.month, \.day, \.hours, \.minutes, \.seconds
]

var transformationsAndResults: [(GeneralizedTime, ExpectedComparisonResult)] = []
transformationsAndResults.append((original, .equal))

for transform in integerTransformable {
transformationsAndResults.append((modify(transform, of: original, by: 1), .greaterThan))
transformationsAndResults.append((modify(transform, of: original, by: -1), .lessThan))
}

transformationsAndResults.append((modify(\.fractionalSeconds, of: original, by: 0.1), .greaterThan))
transformationsAndResults.append((modify(\.fractionalSeconds, of: original, by: -0.1), .lessThan))

for (newValue, expectedResult) in transformationsAndResults {
switch expectedResult {
case .lessThan:
XCTAssertLessThan(newValue, original)
XCTAssertLessThanOrEqual(newValue, original)
XCTAssertGreaterThan(original, newValue)
XCTAssertGreaterThanOrEqual(original, newValue)
case .equal:
XCTAssertGreaterThanOrEqual(newValue, original)
XCTAssertGreaterThanOrEqual(original, newValue)
XCTAssertLessThanOrEqual(newValue, original)
XCTAssertLessThanOrEqual(original, newValue)
case .greaterThan:
XCTAssertGreaterThan(newValue, original)
XCTAssertGreaterThanOrEqual(newValue, original)
XCTAssertLessThan(original, newValue)
XCTAssertLessThanOrEqual(original, newValue)
}
}
}
}
66 changes: 66 additions & 0 deletions Tests/SwiftASN1Tests/UTCTimeTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the SwiftASN1 open source project
//
// Copyright (c) 2023 Apple Inc. and the SwiftASN1 project authors
// Licensed under Apache License v2.0
//
// See LICENSE.txt for license information
// See CONTRIBUTORS.txt for the list of SwiftASN1 project authors
//
// SPDX-License-Identifier: Apache-2.0
//
//===----------------------------------------------------------------------===//
import XCTest

@testable import SwiftASN1

final class UTCTimeTests: XCTestCase {
func testComparisons() throws {
enum ExpectedComparisonResult {
case lessThan
case equal
case greaterThan
}

let original = try UTCTime(year: 2020, month: 03, day: 03, hours: 03, minutes: 03, seconds: 03)

func modify(_ field: WritableKeyPath<UTCTime, Int>, of time: UTCTime, by modifier: Int) -> UTCTime {
var copy = time
copy[keyPath: field] += modifier
return copy
}

let integerTransformable: [WritableKeyPath<UTCTime, Int>] = [
\.year, \.month, \.day, \.hours, \.minutes, \.seconds
]

var transformationsAndResults: [(UTCTime, ExpectedComparisonResult)] = []
transformationsAndResults.append((original, .equal))

for transform in integerTransformable {
transformationsAndResults.append((modify(transform, of: original, by: 1), .greaterThan))
transformationsAndResults.append((modify(transform, of: original, by: -1), .lessThan))
}

for (newValue, expectedResult) in transformationsAndResults {
switch expectedResult {
case .lessThan:
XCTAssertLessThan(newValue, original)
XCTAssertLessThanOrEqual(newValue, original)
XCTAssertGreaterThan(original, newValue)
XCTAssertGreaterThanOrEqual(original, newValue)
case .equal:
XCTAssertGreaterThanOrEqual(newValue, original)
XCTAssertGreaterThanOrEqual(original, newValue)
XCTAssertLessThanOrEqual(newValue, original)
XCTAssertLessThanOrEqual(original, newValue)
case .greaterThan:
XCTAssertGreaterThan(newValue, original)
XCTAssertGreaterThanOrEqual(newValue, original)
XCTAssertLessThan(original, newValue)
XCTAssertLessThanOrEqual(original, newValue)
}
}
}
}

0 comments on commit 1c5387a

Please sign in to comment.