From 858247b9a262dae0eea9b544f55d8a9bdacafa33 Mon Sep 17 00:00:00 2001 From: Jairon Terrero Date: Mon, 9 Sep 2024 13:19:59 -0600 Subject: [PATCH] feature: Adds a unitless `percent` unit --- Sources/Units/Registry.swift | 4 ++ Sources/Units/Unit/DefaultUnits.swift | 9 ++++ Sources/Units/Unit/Unit+DefaultUnits.swift | 4 ++ Tests/UnitsTests/MeasurementTests.swift | 58 ++++++++++++++++++++++ 4 files changed, 75 insertions(+) diff --git a/Sources/Units/Registry.swift b/Sources/Units/Registry.swift index 34d44a8..a6ace57 100644 --- a/Sources/Units/Registry.swift +++ b/Sources/Units/Registry.swift @@ -379,5 +379,9 @@ class Registry { DefaultUnits.imperialGallon, DefaultUnits.imperialPeck, DefaultUnits.metricCup, + + // MARK: Unitless + + DefaultUnits.percent ] } diff --git a/Sources/Units/Unit/DefaultUnits.swift b/Sources/Units/Unit/DefaultUnits.swift index fde7e7e..e87d857 100644 --- a/Sources/Units/Unit/DefaultUnits.swift +++ b/Sources/Units/Unit/DefaultUnits.swift @@ -1271,4 +1271,13 @@ enum DefaultUnits { dimension: [.Length: 3], coefficient: 0.00025 ) + + // MARK: Unitless + + static let percent = try! DefinedUnit( + name: "percent", + symbol: "%", + dimension: [:], + coefficient: 0.01 + ) } diff --git a/Sources/Units/Unit/Unit+DefaultUnits.swift b/Sources/Units/Unit/Unit+DefaultUnits.swift index 0da43d2..3807b1a 100644 --- a/Sources/Units/Unit/Unit+DefaultUnits.swift +++ b/Sources/Units/Unit/Unit+DefaultUnits.swift @@ -278,4 +278,8 @@ public extension Unit { static let imperialGallon = Unit(definedBy: DefaultUnits.imperialGallon) static let imperialPeck = Unit(definedBy: DefaultUnits.imperialPeck) static let metricCup = Unit(definedBy: DefaultUnits.metricCup) + + // MARK: Unitless + + static let percent = Unit(definedBy: DefaultUnits.percent) } diff --git a/Tests/UnitsTests/MeasurementTests.swift b/Tests/UnitsTests/MeasurementTests.swift index c26f943..ddafedc 100644 --- a/Tests/UnitsTests/MeasurementTests.swift +++ b/Tests/UnitsTests/MeasurementTests.swift @@ -210,6 +210,64 @@ final class MeasurementTests: XCTestCase { ) } + func testPercent() throws { + XCTAssertEqual( + 1.measured(in: .percent), + 1.measured(in: .percent) + ) + + XCTAssertNotEqual( + 100.measured(in: .percent), + 1.measured(in: .none) + ) + + try { + let percent1 = 5.measured(in: .percent) + let percent2 = 5.measured(in: .percent) + XCTAssertEqual( + try percent1 + percent2, + 10.measured(in: .percent), + accuracy: accuracy + ) + }() + + try { + let percent1 = 5.measured(in: .percent) + let value2 = 5.measured(in: .none) + XCTAssertThrowsError(try percent1 + value2) + }() + + XCTAssertTrue( + 2.measured(in: .percent).isDimensionallyEquivalent( + to: 2.measured(in: .percent) + ) + ) + + XCTAssertTrue( + 2.measured(in: .percent).isDimensionallyEquivalent( + to: 2.measured(in: .none) + ) + ) + + XCTAssertEqual( + try 1.measured(in: .percent).convert(to: .none), + 0.01.measured(in: .none), + accuracy: accuracy + ) + + XCTAssertEqual( + try 1.measured(in: .none).convert(to: .percent), + 100.measured(in: .percent), + accuracy: accuracy + ) + + _ = { + let measurement = 1.measured(in: .percent) / 2.measured(in: .second) + XCTAssertEqual(measurement.unit, Unit.percent / Unit.second) + XCTAssertEqual(measurement.value, 0.5, accuracy: accuracy) + }() + } + func testComplexArithmetic() throws { XCTAssertEqual( try 1.measured(in: .mile / .mile) * 1.measured(in: .mile) - 1.measured(in: .mile),