├── Sources ├── Beton │ ├── URL │ │ ├── URL+append#linux.swift │ │ └── URL+ExpressibleByStringLiteral.swift │ ├── Operators │ │ ├── wtf │ │ │ ├── wtf.swift │ │ │ └── wtf+throwIfOptional.swift │ │ └── pipe.swift │ ├── Beton.swift │ ├── Notifications │ │ └── Notification.Name+ExpressibleByStringLiteral.swift │ ├── Measurement │ │ ├── Measurement+AdditiveArithmetic.swift │ │ ├── ConvenienceInitializers │ │ │ ├── Measurement+convenienceInit+whenUnitIlluminance.swift │ │ │ ├── Measurement+convenienceInit+whenUnitDispersion.swift │ │ │ ├── Measurement+convenienceInit+whenUnitAcceleration.swift │ │ │ ├── Measurement+convenienceInit+whenUnitDuration.swift │ │ │ ├── Measurement+convenienceInit+whenUnitTemperature.swift │ │ │ ├── Measurement+convenienceInit+whenUnitFuelEfficiency.swift │ │ │ ├── Measurement+convenienceInit+whenUnitSpeed.swift │ │ │ ├── Measurement+convenienceInit+whenUnitConcentrationMass.swift │ │ │ ├── Measurement+convenienceInit+whenUnitElectricResistance.swift │ │ │ ├── Measurement+convenienceInit+whenUnitEnergy.swift │ │ │ ├── Measurement+convenienceInit+whenUnitElectricCurrent.swift │ │ │ ├── Measurement+convenienceInit+whenUnitElectricPotentialDifference.swift │ │ │ ├── Measurement+convenienceInit+whenUnitAngle.swift │ │ │ ├── Measurement+convenienceInit+whenUnitElectricCharge.swift │ │ │ ├── Measurement+convenienceInit+whenUnitFrequency.swift │ │ │ ├── Measurement+convenienceInit+whenUnitPressure.swift │ │ │ ├── Measurement+convenienceInit+whenUnitPower.swift │ │ │ ├── Measurement+convenienceInit+whenUnitArea.swift │ │ │ ├── Measurement+convenienceInit+whenUnitMass.swift │ │ │ ├── Measurement+convenienceInit+whenUnitInformationStorage.swift │ │ │ ├── Measurement+convenienceInit+whenUnitLength.swift │ │ │ └── Measurement+convenienceInit+whenUnitVolume.swift │ │ ├── Measurement+ExpressibleByFloatLiteral.swift │ │ ├── Measurement+ExpressibleByIntegerLiteral.swift │ │ ├── Unit │ │ │ ├── UnitMass+default.swift │ │ │ ├── UnitPower+default.swift │ │ │ ├── UnitAngle+default.swift │ │ │ ├── UnitEnergy+default.swift │ │ │ ├── UnitLength+default.swift │ │ │ ├── UnitVolume+default.swift │ │ │ ├── UnitArea+default.swift │ │ │ ├── UnitPressure+default.swift │ │ │ ├── UnitDuration+default.swift │ │ │ ├── UnitFrequency+default.swift │ │ │ ├── UnitIlluminance+default.swift │ │ │ ├── UnitSpeed+default.swift │ │ │ ├── UnitTemperature+default.swift │ │ │ ├── UnitDispersion+default.swift │ │ │ ├── UnitElectricCurrent+default.swift │ │ │ ├── UnitElectricCharge+default.swift │ │ │ ├── UnitElectricResistance+default.swift │ │ │ ├── UnitInformationStorage+default.swift │ │ │ ├── UnitAcceleration+default.swift │ │ │ ├── UnitConcentrationMass+default.swift │ │ │ ├── UnitFuelEfficiency+default.swift │ │ │ ├── UnitElectricPotentialDifference+default.swift │ │ │ └── Unit.swift │ │ ├── sqrt+measurement.swift │ │ ├── pow+measurement.swift │ │ └── Measurement+convenienceInit.swift │ ├── Bundle │ │ ├── BundleAware.swift │ │ ├── Bundle+localizationBundles.swift │ │ └── Bundle+localizedString.swift │ ├── UUID │ │ ├── Array+init+fromUuid+whenUint8.swift │ │ └── Data+UUID+convenienceBridge.swift │ ├── Locale │ │ ├── LocaleAware.swift │ │ └── Locale+ExpressibleByStringLiteral.swift │ ├── Sequence │ │ └── Sequence+sum.swift │ └── Collections │ │ └── repeating.swift └── XCTBeton │ ├── Performance │ ├── XCTMeasureOptions.swift │ └── XCTMetric │ │ ├── XCTMetric.swift │ │ ├── XCTMetric+measurementStorage.swift │ │ ├── XCTCPUMetric.swift │ │ ├── XCTClockMetric.swift │ │ ├── XCTMemoryMetric.swift │ │ └── XCTStorageMetric.swift │ ├── XCTestCase │ ├── XCTAssertMetricIdentifier.swift │ ├── XCTAssertMetric │ │ ├── XCTAssertDiskIdentifier.swift │ │ ├── XCTAssertMemoryIdentifier.swift │ │ ├── XCTAssertClockIdentifier.swift │ │ ├── XCTAssertCpuIdentifier.swift │ │ ├── XCTAssertMetric.swift │ │ └── XCTestCase+XCTAssertMetric.swift │ ├── XCTestCase.swift │ └── XCTestCase+measure.swift │ ├── XCTBeton.docc │ └── XCTBeton.md │ └── XCTBeton.swift ├── Tests ├── UnitTests │ ├── Resources │ │ ├── en_US.lproj │ │ │ └── Test.strings │ │ └── hu_HU.lproj │ │ │ └── Test.strings │ ├── Beton │ │ ├── Operators │ │ │ ├── wtf │ │ │ │ ├── wtfTests.swift │ │ │ │ └── wtfTests+throwIfOptional.swift │ │ │ └── PipeTests.swift │ │ ├── Bundle │ │ │ ├── BundleTest.swift │ │ │ ├── BundleTest+localiztationBundles.swift │ │ │ └── BundleTest+localizedString.swift │ │ ├── URL │ │ │ ├── URLTest.swift │ │ │ └── URLTest+ExpressibleByStringLiteral.swift │ │ ├── Sequence │ │ │ ├── SequenceTest.swift │ │ │ └── SequenceTest+testSum.swift │ │ ├── Measurement │ │ │ ├── MeasurementTest.swift │ │ │ ├── Unit │ │ │ │ ├── UnitMassTest.swift │ │ │ │ ├── UnitAngleTest.swift │ │ │ │ ├── UnitPowerTest.swift │ │ │ │ ├── UnitAreaTest.swift │ │ │ │ ├── UnitEnergyTest.swift │ │ │ │ ├── UnitLengthTest.swift │ │ │ │ ├── UnitPressureTest.swift │ │ │ │ ├── UnitVolumeTest.swift │ │ │ │ ├── UnitDurationTest.swift │ │ │ │ ├── UnitFrequencyTest.swift │ │ │ │ ├── UnitSpeedTest.swift │ │ │ │ ├── UnitIlluminanceTest.swift │ │ │ │ ├── UnitTemperatureTest.swift │ │ │ │ ├── UnitDispersionTest.swift │ │ │ │ ├── UnitElectricChargeTest.swift │ │ │ │ ├── UnitElectricCurrentTest.swift │ │ │ │ ├── UnitAccelerationTest.swift │ │ │ │ ├── UnitElectricResistanceTest.swift │ │ │ │ ├── UnitInformationStorageTest.swift │ │ │ │ ├── UnitConcentrationMassTest.swift │ │ │ │ ├── UnitFuelEfficiencyTest.swift │ │ │ │ └── UnitElectricPotentialDifferenceTest.swift │ │ │ ├── MeasurementTest+ExpressibleByIntegerLiteral.swift │ │ │ ├── MeasurementTest+ExpressibleByFloatLiteral.swift │ │ │ └── MeasurementTest+AdditiveArithmetic.swift │ │ ├── Locale │ │ │ └── LocaleTest+ExpressibleByStringLiteral.swift │ │ ├── Notifications │ │ │ └── Notification_NameTests.swift │ │ ├── MathTest.swift │ │ ├── UUID │ │ │ ├── ArrayInitFromUuidTest.swift │ │ │ └── DataInitFromUuidTest.swift │ │ └── Collections │ │ │ └── repeatingTests.swift │ └── XCTBeton │ │ ├── Performance │ │ ├── XCTMetric │ │ │ ├── XCTCPUMetricTest.swift │ │ │ ├── XCTClockMetricTest.swift │ │ │ ├── XCTMemoryMetricTest.swift │ │ │ ├── XCTStorageMetricTest.swift │ │ │ └── XCTMetricTest.swift │ │ ├── XCTAssertMetric │ │ │ ├── XCTAssertDiskIdentifierTest.swift │ │ │ ├── XCTAssertClockIdentifierTest.swift │ │ │ ├── XCTAssertMemoryIdentifierTest.swift │ │ │ ├── XCTAssertCpuIdentifierTest.swift │ │ │ └── XCTAssertMetric.AspectTest.swift │ │ └── XCTestCase+numberOfMeasurements.swift │ │ └── XCTestCaseTest.swift ├── PerformanceTests │ ├── Resources │ │ ├── en_US.lproj │ │ │ └── Test.strings │ │ └── hu_HU.lproj │ │ │ └── Test.strings │ └── Beton │ │ └── Bundle │ │ └── BundleTest.swift ├── RegressionTests │ ├── Resources │ │ ├── en_US.lproj │ │ │ └── Test.strings │ │ └── hu_HU.lproj │ │ │ └── Test.strings │ └── RegressionTests.swift └── UserAcceptanceTests │ ├── Resources │ ├── en_US.lproj │ │ └── Test.strings │ └── hu_HU.lproj │ │ └── Test.strings │ ├── Beton │ ├── Measurement │ │ ├── MeasurementTests.swift │ │ ├── MeasurementTests+sqrt.swift │ │ └── MeasurementTests+pow.swift │ ├── Bundle │ │ └── BundleTests.swift │ ├── Sequence │ │ └── SequenceTests+sum.swift │ └── Operators │ │ └── wtfTests.swift │ └── XCTBeton │ └── XCTBetonExamples.swift ├── spi.yml ├── .gitignore ├── .vscode └── extensions.json ├── CHANGELOG.md ├── LICENSE ├── Package.resolved ├── Package.swift └── README.md /Sources/Beton/URL/URL+append#linux.swift: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Sources/Beton/Operators/wtf/wtf.swift: -------------------------------------------------------------------------------- 1 | infix operator ?! 2 | -------------------------------------------------------------------------------- /Tests/UnitTests/Resources/en_US.lproj/Test.strings: -------------------------------------------------------------------------------- 1 | "Test" = "Test"; -------------------------------------------------------------------------------- /Tests/UnitTests/Resources/hu_HU.lproj/Test.strings: -------------------------------------------------------------------------------- 1 | "Test" = "Teszt"; -------------------------------------------------------------------------------- /Tests/PerformanceTests/Resources/en_US.lproj/Test.strings: -------------------------------------------------------------------------------- 1 | "Test" = "Test"; -------------------------------------------------------------------------------- /Tests/RegressionTests/Resources/en_US.lproj/Test.strings: -------------------------------------------------------------------------------- 1 | "Test" = "Test"; -------------------------------------------------------------------------------- /Tests/RegressionTests/Resources/hu_HU.lproj/Test.strings: -------------------------------------------------------------------------------- 1 | "Test" = "Teszt"; -------------------------------------------------------------------------------- /Tests/PerformanceTests/Resources/hu_HU.lproj/Test.strings: -------------------------------------------------------------------------------- 1 | "Test" = "Teszt"; -------------------------------------------------------------------------------- /Tests/UserAcceptanceTests/Resources/en_US.lproj/Test.strings: -------------------------------------------------------------------------------- 1 | "Test" = "Test"; -------------------------------------------------------------------------------- /spi.yml: -------------------------------------------------------------------------------- 1 | version: 1 2 | builder: 3 | configs: 4 | - documentation_targets: [Beton, XCTBeton] -------------------------------------------------------------------------------- /Tests/UserAcceptanceTests/Resources/hu_HU.lproj/Test.strings: -------------------------------------------------------------------------------- 1 | "Test" = "Teszt"; 2 | "Apple" = "Alma"; 3 | -------------------------------------------------------------------------------- /Tests/UnitTests/Beton/Operators/wtf/wtfTests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | 3 | class WtfOperatorTest: XCTestCase {} 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | /.build 3 | /Packages 4 | /*.xcodeproj 5 | xcuserdata/ 6 | DerivedData/ 7 | .swiftpm 8 | .netrc 9 | -------------------------------------------------------------------------------- /Tests/UnitTests/Beton/Bundle/BundleTest.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import XCTest 3 | 4 | class BundleTest: XCTestCase {} 5 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "sswg.swift-lang", 4 | "vknabel.vscode-apple-swift-format" 5 | ] 6 | } -------------------------------------------------------------------------------- /Tests/UserAcceptanceTests/Beton/Measurement/MeasurementTests.swift: -------------------------------------------------------------------------------- 1 | import Beton 2 | import XCTBeton 3 | 4 | class MeasurementTests: XCTestCase {} 5 | -------------------------------------------------------------------------------- /Tests/UnitTests/Beton/URL/URLTest.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import XCTest 3 | 4 | @testable import Beton 5 | 6 | class URLTest: XCTestCase { 7 | } 8 | -------------------------------------------------------------------------------- /Tests/UnitTests/Beton/Sequence/SequenceTest.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import XCTest 3 | 4 | @testable import Beton 5 | 6 | class SequenceTest: XCTestCase { 7 | } 8 | -------------------------------------------------------------------------------- /Tests/UnitTests/Beton/Measurement/MeasurementTest.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import XCTest 3 | 4 | @testable import Beton 5 | 6 | class MeasurementTest: XCTestCase { 7 | } 8 | -------------------------------------------------------------------------------- /Sources/XCTBeton/Performance/XCTMeasureOptions.swift: -------------------------------------------------------------------------------- 1 | import Beton 2 | 3 | import class XCTest.XCTMeasureOptions 4 | 5 | open class XCTMeasureOptions: XCTest.XCTMeasureOptions {} 6 | -------------------------------------------------------------------------------- /Tests/RegressionTests/RegressionTests.swift: -------------------------------------------------------------------------------- 1 | import XCTBeton 2 | 3 | class RegressionTests: XCTestCase { 4 | func testNothing() { 5 | XCTAssertTrue(true, "Nothing to regret yet.") 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /Sources/Beton/Beton.swift: -------------------------------------------------------------------------------- 1 | @_exported import Foundation 2 | 3 | #if canImport(FoundationNetworking) 4 | @_exported import FoundationNetworking 5 | #endif 6 | #if canImport(UUID) 7 | @_exported import UUID 8 | #endif 9 | -------------------------------------------------------------------------------- /Sources/Beton/Notifications/Notification.Name+ExpressibleByStringLiteral.swift: -------------------------------------------------------------------------------- 1 | extension Notification.Name: ExpressibleByStringLiteral { 2 | public init(stringLiteral value: String) { self.init(String(value)) } 3 | } 4 | -------------------------------------------------------------------------------- /Tests/UnitTests/XCTBeton/Performance/XCTMetric/XCTCPUMetricTest.swift: -------------------------------------------------------------------------------- 1 | import Beton 2 | import XCTBeton 3 | 4 | class XCTCPUMetricTest: XCTMetricTest { 5 | override func setUp() { unit = .init() } 6 | } 7 | -------------------------------------------------------------------------------- /Tests/UnitTests/XCTBeton/Performance/XCTMetric/XCTClockMetricTest.swift: -------------------------------------------------------------------------------- 1 | import Beton 2 | import XCTBeton 3 | 4 | class XCTClockMetricTest: XCTMetricTest { 5 | override func setUp() { unit = .init() } 6 | } 7 | -------------------------------------------------------------------------------- /Tests/UnitTests/XCTBeton/Performance/XCTMetric/XCTMemoryMetricTest.swift: -------------------------------------------------------------------------------- 1 | import Beton 2 | import XCTBeton 3 | 4 | class XCTMemoryMetricTest: XCTMetricTest { 5 | override func setUp() { unit = .init() } 6 | } 7 | -------------------------------------------------------------------------------- /Tests/UnitTests/XCTBeton/Performance/XCTMetric/XCTStorageMetricTest.swift: -------------------------------------------------------------------------------- 1 | import Beton 2 | import XCTBeton 3 | 4 | class XCTStorageMetricTest: XCTMetricTest { 5 | override func setUp() { unit = .init() } 6 | } 7 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # 1.5.0 2 | 3 | ## Minor Changes 4 | 5 | * Strict concurrency related changes 6 | 7 | ## Patch Changes 8 | 9 | * Reorganized tests to make them easier to comprehend and 10 | match contemporary best practices. 11 | -------------------------------------------------------------------------------- /Sources/Beton/Measurement/Measurement+AdditiveArithmetic.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | extension Measurement: AdditiveArithmetic where UnitType: Unit, UnitType.U == UnitType { 4 | public static var zero: Self { Self.init(value: 0.0, unit: .default) } 5 | } 6 | -------------------------------------------------------------------------------- /Tests/UnitTests/Beton/Sequence/SequenceTest+testSum.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import XCTest 3 | 4 | @testable import Beton 5 | 6 | extension SequenceTest { 7 | func testSum() { 8 | XCTAssertEqual([1, 2, 3, 4, 5, 6].sum(), 21) 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Tests/UnitTests/Beton/Measurement/Unit/UnitMassTest.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import XCTest 3 | 4 | @testable import Beton 5 | 6 | class UnitMassTest: XCTestCase { 7 | func testDefault() { 8 | XCTAssertEqual(UnitMass.default, .grams) 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Sources/Beton/Measurement/ConvenienceInitializers/Measurement+convenienceInit+whenUnitIlluminance.swift: -------------------------------------------------------------------------------- 1 | extension Measurement where UnitType == UnitIlluminance { 2 | public static func lux(_ value: Double) -> Self { 3 | .init(value: value, unit: .lux) 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /Tests/UnitTests/Beton/Measurement/Unit/UnitAngleTest.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import XCTest 3 | 4 | @testable import Beton 5 | 6 | class UnitAngleTest: XCTestCase { 7 | func testDefault() { 8 | XCTAssertEqual(UnitAngle.default, .degrees) 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Tests/UnitTests/Beton/Measurement/Unit/UnitPowerTest.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import XCTest 3 | 4 | @testable import Beton 5 | 6 | class UnitPowerTest: XCTestCase { 7 | func testDefault() { 8 | XCTAssertEqual(UnitPower.default, .watts) 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Tests/UnitTests/Beton/Measurement/Unit/UnitAreaTest.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import XCTest 3 | 4 | @testable import Beton 5 | 6 | class UnitAreaTest: XCTestCase { 7 | func testDefault() { 8 | XCTAssertEqual(UnitArea.default, .squareMeters) 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Tests/UnitTests/Beton/Measurement/Unit/UnitEnergyTest.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import XCTest 3 | 4 | @testable import Beton 5 | 6 | class UnitEnergyTest: XCTestCase { 7 | func testDefault() { 8 | XCTAssertEqual(UnitEnergy.default, .joules) 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Tests/UnitTests/Beton/Measurement/Unit/UnitLengthTest.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import XCTest 3 | 4 | @testable import Beton 5 | 6 | class UnitLengthTest: XCTestCase { 7 | func testDefault() { 8 | XCTAssertEqual(UnitLength.default, .meters) 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Tests/UnitTests/Beton/Measurement/Unit/UnitPressureTest.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import XCTest 3 | 4 | @testable import Beton 5 | 6 | class UnitPressureTest: XCTestCase { 7 | func testDefault() { 8 | XCTAssertEqual(UnitPressure.default, .bars) 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Tests/UnitTests/Beton/Measurement/Unit/UnitVolumeTest.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import XCTest 3 | 4 | @testable import Beton 5 | 6 | class UnitVolumeTest: XCTestCase { 7 | func testDefault() { 8 | XCTAssertEqual(UnitVolume.default, .liters) 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Tests/UnitTests/Beton/Measurement/Unit/UnitDurationTest.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import XCTest 3 | 4 | @testable import Beton 5 | 6 | class UnitDurationTest: XCTestCase { 7 | func testDefault() { 8 | XCTAssertEqual(UnitDuration.default, .seconds) 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Tests/UnitTests/Beton/Measurement/Unit/UnitFrequencyTest.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import XCTest 3 | 4 | @testable import Beton 5 | 6 | class UnitFrequencyTest: XCTestCase { 7 | func testDefault() { 8 | XCTAssertEqual(UnitFrequency.default, .hertz) 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Tests/UnitTests/Beton/Measurement/Unit/UnitSpeedTest.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import XCTest 3 | 4 | @testable import Beton 5 | 6 | class UnitSpeedTest: XCTestCase { 7 | func testDefault() { 8 | XCTAssertEqual(UnitSpeed.default, .kilometersPerHour) 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Tests/UnitTests/Beton/Measurement/Unit/UnitIlluminanceTest.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import XCTest 3 | 4 | @testable import Beton 5 | 6 | class UnitIlluminanceTest: XCTestCase { 7 | func testDefault() { 8 | XCTAssertEqual(UnitIlluminance.default, .lux) 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Sources/Beton/Measurement/ConvenienceInitializers/Measurement+convenienceInit+whenUnitDispersion.swift: -------------------------------------------------------------------------------- 1 | extension Measurement where UnitType == UnitDispersion { 2 | public static func partsPerMillion(_ value: Double) -> Self { 3 | .init(value: value, unit: .partsPerMillion) 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /Tests/UnitTests/Beton/Measurement/Unit/UnitTemperatureTest.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import XCTest 3 | 4 | @testable import Beton 5 | 6 | class UnitTemperatureTest: XCTestCase { 7 | func testDefault() { 8 | XCTAssertEqual(UnitTemperature.default, .celsius) 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Tests/UnitTests/Beton/Measurement/Unit/UnitDispersionTest.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import XCTest 3 | 4 | @testable import Beton 5 | 6 | class UnitDispersionTest: XCTestCase { 7 | func testDefault() { 8 | XCTAssertEqual(UnitDispersion.default, .partsPerMillion) 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Sources/Beton/Measurement/Measurement+ExpressibleByFloatLiteral.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | extension Measurement: ExpressibleByFloatLiteral where UnitType: Unit, UnitType.U == UnitType { 4 | public init(floatLiteral value: Double) { 5 | self.init(value: value, unit: .default) 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /Sources/Beton/Operators/pipe.swift: -------------------------------------------------------------------------------- 1 | infix operator |> : MultiplicationPrecedence 2 | 3 | @inlinable 4 | @discardableResult 5 | public func |> ( 6 | lhs: @autoclosure () throws -> Input, 7 | rhs: (Input) throws -> Output 8 | ) rethrows -> Output { 9 | try rhs(lhs()) 10 | } 11 | -------------------------------------------------------------------------------- /Tests/UnitTests/Beton/Measurement/Unit/UnitElectricChargeTest.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import XCTest 3 | 4 | @testable import Beton 5 | 6 | class UnitElectricChargeTest: XCTestCase { 7 | func testDefault() { 8 | XCTAssertEqual(UnitElectricCharge.default, .ampereHours) 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Tests/UnitTests/Beton/Measurement/Unit/UnitElectricCurrentTest.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import XCTest 3 | 4 | @testable import Beton 5 | 6 | class UnitElectricCurrentTest: XCTestCase { 7 | func testDefault() { 8 | XCTAssertEqual(UnitElectricCurrent.default, .default) 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Tests/UnitTests/Beton/Measurement/Unit/UnitAccelerationTest.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import XCTest 3 | 4 | @testable import Beton 5 | 6 | class UnitAccelerationTest: XCTestCase { 7 | func testDefault() { 8 | XCTAssertEqual(UnitAcceleration.default, .metersPerSecondSquared) 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Tests/UnitTests/Beton/Measurement/Unit/UnitElectricResistanceTest.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import XCTest 3 | 4 | @testable import Beton 5 | 6 | class UnitElectricResistanceTest: XCTestCase { 7 | func testDefault() { 8 | XCTAssertEqual(UnitElectricResistance.default, .ohms) 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Tests/UnitTests/Beton/Measurement/Unit/UnitInformationStorageTest.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import XCTest 3 | 4 | @testable import Beton 5 | 6 | class UnitInformationStorageTest: XCTestCase { 7 | func testDefault() { 8 | XCTAssertEqual(UnitInformationStorage.default, .bits) 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Tests/UnitTests/Beton/URL/URLTest+ExpressibleByStringLiteral.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import XCTest 3 | 4 | @testable import Beton 5 | 6 | extension URLTest { 7 | func testInitStringLiteral() { 8 | XCTAssertEqual("https://google.com", URL(string: "https://google.com")) 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Sources/Beton/Measurement/Measurement+ExpressibleByIntegerLiteral.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | extension Measurement: ExpressibleByIntegerLiteral where UnitType: Unit, UnitType.U == UnitType { 4 | public init(integerLiteral value: Int) { 5 | self.init(value: Double(value), unit: .default) 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /Tests/UnitTests/Beton/Measurement/Unit/UnitConcentrationMassTest.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import XCTest 3 | 4 | @testable import Beton 5 | 6 | class UnitConcentrationMassTest: XCTestCase { 7 | func testDefault() { 8 | XCTAssertEqual(UnitConcentrationMass.default, .gramsPerLiter) 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Tests/UnitTests/Beton/Measurement/Unit/UnitFuelEfficiencyTest.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import XCTest 3 | 4 | @testable import Beton 5 | 6 | class UnitFuelEfficiencyTest: XCTestCase { 7 | func testDefault() { 8 | XCTAssertEqual(UnitFuelEfficiency.default, .litersPer100Kilometers) 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Tests/UnitTests/Beton/Locale/LocaleTest+ExpressibleByStringLiteral.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import XCTest 3 | 4 | @testable import Beton 5 | 6 | class LocaleTest: XCTestCase { 7 | func testLocaleFromStringLiteral() { 8 | let locale: Locale = "hu_HU" 9 | XCTAssertEqual("hu_HU", locale.identifier) 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Tests/UnitTests/Beton/Measurement/Unit/UnitElectricPotentialDifferenceTest.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import XCTest 3 | 4 | @testable import Beton 5 | 6 | class UnitElectricPotentialDifferenceTest: XCTestCase { 7 | func testDefault() { 8 | XCTAssertEqual(UnitElectricPotentialDifference.default, .volts) 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Tests/UnitTests/Beton/Notifications/Notification_NameTests.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import XCTest 3 | 4 | @testable import Beton 5 | 6 | class Notification_NameTests: XCTestCase { 7 | func test_init_stringLiteral() { 8 | let name: Notification.Name = "test" 9 | XCTAssertEqual(name.rawValue, "test") 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Tests/UnitTests/XCTBeton/Performance/XCTMetric/XCTMetricTest.swift: -------------------------------------------------------------------------------- 1 | import Beton 2 | import XCTBeton 3 | 4 | class XCTMetricTest: XCTestCase where Unit: XCTMetric { 5 | var unit: Unit! = nil 6 | 7 | func testMeasurementEmptyByDefault() { 8 | XCTAssertTrue(unit.measurements.isEmpty, "Measurements should be empty by default.") 9 | } 10 | 11 | } 12 | -------------------------------------------------------------------------------- /Tests/UnitTests/XCTBeton/Performance/XCTAssertMetric/XCTAssertDiskIdentifierTest.swift: -------------------------------------------------------------------------------- 1 | import Beton 2 | 3 | @testable import XCTBeton 4 | 5 | class XCTAssertDiskIdentifierTest: XCTestCase { 6 | func testIdentifier() { 7 | XCTAssertEqual( 8 | XCTAssertDiskIdentifier.logicalWrites.identifier, "com.apple.dt.XCTMetric_Disk.logical_writes" 9 | ) 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Sources/Beton/Measurement/Unit/UnitMass+default.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /// Defines the ``default`` unit for 4 | /// [`UnitMass`](https://developer.apple.com/documentation/foundation/unitmass) 5 | extension UnitMass: Unit { 6 | /// Returns [grams](https://developer.apple.com/documentation/foundation/unitmass/1855976-grams). 7 | public static var `default`: UnitMass { .grams } 8 | } 9 | -------------------------------------------------------------------------------- /Sources/Beton/Measurement/Unit/UnitPower+default.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /// Defines the ``default`` unit for 4 | /// [`UnitPower`](https://developer.apple.com/documentation/foundation/unitpower) 5 | extension UnitPower: Unit { 6 | /// Returns [watts](https://developer.apple.com/documentation/foundation/unitpower/1856075-watts). 7 | public static var `default`: UnitPower { .watts } 8 | } 9 | -------------------------------------------------------------------------------- /Tests/UnitTests/XCTBeton/Performance/XCTAssertMetric/XCTAssertClockIdentifierTest.swift: -------------------------------------------------------------------------------- 1 | import Beton 2 | 3 | @testable import XCTBeton 4 | 5 | class XCTAssertClockIdentifierTest: XCTestCase { 6 | func testIdentifier() { 7 | XCTAssertEqual( 8 | XCTAssertClockIdentifier.timeMonotonic.identifier, 9 | "com.apple.dt.XCTMetric_Clock.time.monotonic" 10 | ) 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Sources/Beton/Measurement/Unit/UnitAngle+default.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /// Defines the ``default`` unit for 4 | /// [`UnitAngle`](https://developer.apple.com/documentation/foundation/unitangle) 5 | extension UnitAngle: Unit { 6 | /// Returns [degrees](https://developer.apple.com/documentation/foundation/unitangle/1856083-degrees). 7 | public static var `default`: UnitAngle { .degrees } 8 | } 9 | -------------------------------------------------------------------------------- /Sources/Beton/Measurement/Unit/UnitEnergy+default.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /// Defines the ``default`` unit for 4 | /// [`UnitEnergy`](https://developer.apple.com/documentation/foundation/unitenergy) 5 | extension UnitEnergy: Unit { 6 | /// Returns [joules](https://developer.apple.com/documentation/foundation/unitenergy/1855987-joules). 7 | public static var `default`: UnitEnergy { .joules } 8 | } 9 | -------------------------------------------------------------------------------- /Sources/Beton/Measurement/Unit/UnitLength+default.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /// Defines the ``default`` unit for 4 | /// [`UnitLength`](https://developer.apple.com/documentation/foundation/unitlength) 5 | extension UnitLength: Unit { 6 | /// Returns [meters](https://developer.apple.com/documentation/foundation/unitlength/1855995-meters). 7 | public static var `default`: UnitLength { .meters } 8 | } 9 | -------------------------------------------------------------------------------- /Sources/Beton/Measurement/Unit/UnitVolume+default.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /// Defines the ``default`` unit for 4 | /// [`UnitVolume`](https://developer.apple.com/documentation/foundation/unitvolume) 5 | extension UnitVolume: Unit { 6 | /// Returns [liters](https://developer.apple.com/documentation/foundation/unitvolume/1856011-liters). 7 | public static var `default`: UnitVolume { .liters } 8 | } 9 | -------------------------------------------------------------------------------- /Sources/Beton/Measurement/Unit/UnitArea+default.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /// Defines the ``default`` unit for 4 | /// [`UnitArea`](https://developer.apple.com/documentation/foundation/unitarea) 5 | extension UnitArea: Unit { 6 | /// Returns [squareMeters](https://developer.apple.com/documentation/foundation/unitarea/1855985-squaremeters). 7 | public static var `default`: UnitArea { .squareMeters } 8 | } 9 | -------------------------------------------------------------------------------- /Sources/Beton/Measurement/Unit/UnitPressure+default.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /// Defines the ``default`` unit for 4 | /// [`UnitPressure`](https://developer.apple.com/documentation/foundation/unitpressure) 5 | extension UnitPressure: Unit { 6 | /// Returns [bars](https://developer.apple.com/documentation/foundation/unitpressure/1856109-bars). 7 | public static var `default`: UnitPressure { .bars } 8 | } 9 | -------------------------------------------------------------------------------- /Tests/UserAcceptanceTests/Beton/Bundle/BundleTests.swift: -------------------------------------------------------------------------------- 1 | import Beton 2 | import XCTest 3 | 4 | class BundleTests: XCTestCase { 5 | func testLocalizedStringExample() { 6 | let bundle = Bundle.module.localizationBundles["hu_HU"] 7 | XCTAssertEqual(bundle?.localizedString("Apple", from: "Test"), "Alma") 8 | XCTAssertEqual(bundle?.localizedString("Banana", from: "Test"), "Banana") 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Sources/Beton/Measurement/Unit/UnitDuration+default.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /// Defines the ``default`` unit for 4 | /// [`UnitDuration`](https://developer.apple.com/documentation/foundation/unitduration) 5 | extension UnitDuration: Unit { 6 | /// Returns [seconds](https://developer.apple.com/documentation/foundation/unitduration/1856005-seconds). 7 | public static var `default`: UnitDuration { .seconds } 8 | } 9 | -------------------------------------------------------------------------------- /Sources/Beton/Measurement/Unit/UnitFrequency+default.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /// Defines the ``default`` unit for 4 | /// [`UnitFrequency`](https://developer.apple.com/documentation/foundation/unitfrequency) 5 | extension UnitFrequency: Unit { 6 | /// Returns [hertz](https://developer.apple.com/documentation/foundation/unitfrequency/1690670-hertz). 7 | public static var `default`: UnitFrequency { .hertz } 8 | } 9 | -------------------------------------------------------------------------------- /Sources/Beton/Measurement/Unit/UnitIlluminance+default.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /// Defines the ``default`` unit for 4 | /// [`UnitIlluminance`](https://developer.apple.com/documentation/foundation/unitilluminance) 5 | extension UnitIlluminance: Unit { 6 | /// Returns [lux](https://developer.apple.com/documentation/foundation/unitilluminance/1823716-lux). 7 | public static var `default`: UnitIlluminance { .lux } 8 | } 9 | -------------------------------------------------------------------------------- /Sources/Beton/Bundle/BundleAware.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /// A utility protocol for any value that can be associated with a bundle. 4 | /// 5 | /// This is useful for values that need to be associated with a bundle, but 6 | /// don't have a bundle of their own. 7 | /// 8 | /// Typically this is handy in server-side environments. 9 | 10 | public protocol BundleAware { 11 | var bundle: Bundle? { get set } 12 | } 13 | -------------------------------------------------------------------------------- /Sources/Beton/Measurement/ConvenienceInitializers/Measurement+convenienceInit+whenUnitAcceleration.swift: -------------------------------------------------------------------------------- 1 | extension Measurement where UnitType == UnitAcceleration { 2 | public static func metersPerSecondSquared(_ value: Double) -> Self { 3 | .init(value: value, unit: .metersPerSecondSquared) 4 | } 5 | 6 | public static func gravity(_ value: Double) -> Self { 7 | .init(value: value, unit: .gravity) 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Sources/Beton/Measurement/Unit/UnitSpeed+default.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /// Defines the ``default`` unit for 4 | /// [`UnitSpeed`](https://developer.apple.com/documentation/foundation/unitspeed) 5 | extension UnitSpeed: Unit { 6 | /// Returns [kilometersPerHour](https://developer.apple.com/documentation/foundation/unitspeed/1856044-kilometersperhour). 7 | public static var `default`: UnitSpeed { .kilometersPerHour } 8 | } 9 | -------------------------------------------------------------------------------- /Sources/Beton/Measurement/Unit/UnitTemperature+default.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /// Defines the ``default`` unit for 4 | /// [`UnitTemperature`](https://developer.apple.com/documentation/foundation/unittemperature) 5 | extension UnitTemperature: Unit { 6 | /// Returns [celsius](https://developer.apple.com/documentation/foundation/unittemperature/1690835-celsius). 7 | public static var `default`: UnitTemperature { .celsius } 8 | } 9 | -------------------------------------------------------------------------------- /Sources/Beton/Measurement/Unit/UnitDispersion+default.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /// Defines the ``default`` unit for 4 | /// [`UnitDispersion`](https://developer.apple.com/documentation/foundation/unitdispersion) 5 | extension UnitDispersion: Unit { 6 | /// Returns [partsPerMillion](https://developer.apple.com/documentation/foundation/unitdispersion/1690700-partspermillion). 7 | public static var `default`: UnitDispersion { .partsPerMillion } 8 | } 9 | -------------------------------------------------------------------------------- /Sources/Beton/Measurement/Unit/UnitElectricCurrent+default.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /// Defines the ``default`` unit for 4 | /// [`UnitElectricCurrent`](https://developer.apple.com/documentation/foundation/unitelectriccurrent) 5 | extension UnitElectricCurrent: Unit { 6 | /// Returns [amperes](https://developer.apple.com/documentation/foundation/unitelectriccurrent/1855973-amperes). 7 | public static var `default`: UnitElectricCurrent { .amperes } 8 | } 9 | -------------------------------------------------------------------------------- /Sources/Beton/Measurement/Unit/UnitElectricCharge+default.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /// Defines the ``default`` unit for 4 | /// [`UnitElectricCharge`](https://developer.apple.com/documentation/foundation/unitelectriccharge) 5 | extension UnitElectricCharge: Unit { 6 | /// Returns [ampereHours](https://developer.apple.com/documentation/foundation/unitelectriccharge/1856117-amperehours). 7 | public static var `default`: UnitElectricCharge { .ampereHours } 8 | } 9 | -------------------------------------------------------------------------------- /Sources/Beton/Measurement/Unit/UnitElectricResistance+default.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /// Defines the ``default`` unit for 4 | /// [`UnitElectricResistance`](https://developer.apple.com/documentation/foundation/unitelectricresistance) 5 | extension UnitElectricResistance: Unit { 6 | /// Returns [ohms](https://developer.apple.com/documentation/foundation/unitelectricresistance/1856110-ohms). 7 | public static var `default`: UnitElectricResistance { .ohms } 8 | } 9 | -------------------------------------------------------------------------------- /Sources/Beton/Measurement/Unit/UnitInformationStorage+default.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /// Defines the ``default`` unit for 4 | /// [`UnitInformationStorage`](https://developer.apple.com/documentation/foundation/unitinformationstorage) 5 | extension UnitInformationStorage: Unit { 6 | /// Returns [bits](https://developer.apple.com/documentation/foundation/unitinformationstorage/3172544-bits). 7 | public static var `default`: UnitInformationStorage { .bits } 8 | } 9 | -------------------------------------------------------------------------------- /Sources/Beton/UUID/Array+init+fromUuid+whenUint8.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | extension Array where Element == UInt8 { 4 | public init(_ uuid: UUID) { 5 | let (u1, u2, u3, u4, u5, u6, u7, u8, u9, u10, u11, u12, u13, u14, u15, u16) = uuid.uuid 6 | self = [u1, u2, u3, u4, u5, u6, u7, u8, u9, u10, u11, u12, u13, u14, u15, u16] 7 | } 8 | 9 | public init?(_ uuid: UUID?) { 10 | guard let uuid = uuid else { return nil } 11 | self = .init(uuid) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Sources/Beton/Measurement/Unit/UnitAcceleration+default.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /// Defines the ``default`` unit for 4 | /// [`UnitAcceleration`](https://developer.apple.com/documentation/foundation/unitacceleration). 5 | extension UnitAcceleration: Unit { 6 | /// Returns [metersPerSecondSquared](https://developer.apple.com/documentation/foundation/unitacceleration/1856015-meterspersecondsquared). 7 | public static var `default`: UnitAcceleration { .metersPerSecondSquared } 8 | } 9 | -------------------------------------------------------------------------------- /Sources/Beton/Measurement/Unit/UnitConcentrationMass+default.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /// Defines the ``default`` unit for 4 | /// [`UnitConcentrationMass`](https://developer.apple.com/documentation/foundation/unitconcentrationmass) 5 | extension UnitConcentrationMass: Unit { 6 | /// Returns [gramsPerLiter](https://developer.apple.com/documentation/foundation/unitconcentrationmass/1856019-gramsperliter). 7 | public static var `default`: UnitConcentrationMass { .gramsPerLiter } 8 | } 9 | -------------------------------------------------------------------------------- /Sources/Beton/Measurement/Unit/UnitFuelEfficiency+default.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /// Defines the ``default`` unit for 4 | /// [`UnitFuelEfficiency`](https://developer.apple.com/documentation/foundation/unitfuelefficiency) 5 | extension UnitFuelEfficiency: Unit { 6 | /// Returns [litersPer100Kilometers](https://developer.apple.com/documentation/foundation/unitfuelefficiency/1856054-litersper100kilometers). 7 | public static var `default`: UnitFuelEfficiency { .litersPer100Kilometers } 8 | } 9 | -------------------------------------------------------------------------------- /Sources/Beton/Measurement/ConvenienceInitializers/Measurement+convenienceInit+whenUnitDuration.swift: -------------------------------------------------------------------------------- 1 | extension Measurement where UnitType == UnitDuration { 2 | public static func seconds(_ value: Double) -> Self { 3 | .init(value: value, unit: .seconds) 4 | } 5 | 6 | public static func minutes(_ value: Double) -> Self { 7 | .init(value: value, unit: .minutes) 8 | } 9 | 10 | public static func hours(_ value: Double) -> Self { 11 | .init(value: value, unit: .hours) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Tests/UnitTests/XCTBeton/Performance/XCTAssertMetric/XCTAssertMemoryIdentifierTest.swift: -------------------------------------------------------------------------------- 1 | import Beton 2 | 3 | @testable import XCTBeton 4 | 5 | class XCTAssertMemoryIdentifierTest: XCTestCase { 6 | func testIdentifier() { 7 | XCTAssertEqual( 8 | XCTAssertMemoryIdentifier.physical.identifier, "com.apple.dt.XCTMetric_Memory.physical") 9 | XCTAssertEqual( 10 | XCTAssertMemoryIdentifier.physicalPeak.identifier, 11 | "com.apple.dt.XCTMetric_Memory.physical_peak") 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Sources/Beton/Measurement/ConvenienceInitializers/Measurement+convenienceInit+whenUnitTemperature.swift: -------------------------------------------------------------------------------- 1 | extension Measurement where UnitType == UnitTemperature { 2 | public static func kelvin(_ value: Double) -> Self { 3 | .init(value: value, unit: .kelvin) 4 | } 5 | 6 | public static func celsius(_ value: Double) -> Self { 7 | .init(value: value, unit: .celsius) 8 | } 9 | 10 | public static func fahrenheit(_ value: Double) -> Self { 11 | .init(value: value, unit: .fahrenheit) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Tests/UnitTests/Beton/Bundle/BundleTest+localiztationBundles.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import XCTest 3 | 4 | @testable import Beton 5 | 6 | extension BundleTest { 7 | func testLocalizationBundles() { 8 | XCTAssertTrue(Bundle.module.localizationBundles.keys.contains(Locale(identifier: "en_US"))) 9 | XCTAssertTrue(Bundle.module.localizationBundles.keys.contains(Locale(identifier: "hu_HU"))) 10 | XCTAssertFalse(Bundle.module.localizationBundles.keys.contains(Locale(identifier: "de_DE"))) 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Sources/Beton/Measurement/Unit/UnitElectricPotentialDifference+default.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /// Defines the ``default`` unit for 4 | /// [`UnitElectricPotentialDifference`](https://developer.apple.com/documentation/foundation/unitelectricpotentialdifference) 5 | extension UnitElectricPotentialDifference: Unit { 6 | /// Returns [volts](https://developer.apple.com/documentation/foundation/unitelectricpotentialdifference/1856095-volts). 7 | public static var `default`: UnitElectricPotentialDifference { .volts } 8 | } 9 | -------------------------------------------------------------------------------- /Sources/Beton/Measurement/Unit/Unit.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /// Represents a [Unit](https://developer.apple.com/documentation/foundation/unit) of measure with a ``default`` unit. 4 | public protocol Unit: Foundation.Unit { 5 | associatedtype U = Self 6 | /// The default unit. For example 7 | /// [`meters`](https://developer.apple.com/documentation/foundation/unitlength/1855995-meters) for 8 | /// [`UnitLength`](https://developer.apple.com/documentation/foundation/unitlength). 9 | static var `default`: U { get } 10 | } 11 | -------------------------------------------------------------------------------- /Tests/UserAcceptanceTests/Beton/Measurement/MeasurementTests+sqrt.swift: -------------------------------------------------------------------------------- 1 | import Beton 2 | import XCTest 3 | 4 | extension MeasurementTests { 5 | func testSqrt() { 6 | let measurement = sqrt(Measurement(value: 64, unit: .bits)) 7 | let limit = Measurement(value: 1, unit: .bytes) 8 | if measurement <= limit { 9 | XCTAssertEqual("Small enough data: \(measurement)", "Small enough data: 8.0 bit") 10 | } else { 11 | XCTAssertLessThanOrEqual(measurement, limit) 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Sources/Beton/Locale/LocaleAware.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /// A utility protocol for any value that can be associated with a locale. 4 | /// 5 | /// This is useful for values that represent localized 6 | //// constructs, are locale loaders, or operate with 7 | /// locales in any way. 8 | /// By extending this protocol, you can have decoupled units 9 | /// carrying their own Localization info with them. 10 | /// 11 | /// Typically this is handy in server-side environments. 12 | public protocol LocaleAware { 13 | var locale: Locale? { get set } 14 | } 15 | -------------------------------------------------------------------------------- /Tests/UserAcceptanceTests/Beton/Measurement/MeasurementTests+pow.swift: -------------------------------------------------------------------------------- 1 | import Beton 2 | import XCTest 3 | 4 | extension MeasurementTests { 5 | func testPow() { 6 | let measurement = pow(Measurement(value: 2, unit: .bits), 3) 7 | let limit = Measurement(value: 1, unit: .bytes) 8 | if limit <= measurement { 9 | XCTAssertEqual("Large enough data: \(measurement)", "Large enough data: 8.0 bit") 10 | } else { 11 | XCTAssertGreaterThanOrEqual(measurement, limit) 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Tests/UnitTests/XCTBeton/Performance/XCTAssertMetric/XCTAssertCpuIdentifierTest.swift: -------------------------------------------------------------------------------- 1 | import Beton 2 | 3 | @testable import XCTBeton 4 | 5 | class XCTAssertCpuIdentifierTest: XCTestCase { 6 | func testIdentifier() { 7 | XCTAssertEqual(XCTAssertCpuIdentifier.time.identifier, "com.apple.dt.XCTMetric_CPU.time") 8 | XCTAssertEqual(XCTAssertCpuIdentifier.cycles.identifier, "com.apple.dt.XCTMetric_CPU.cycles") 9 | XCTAssertEqual( 10 | XCTAssertCpuIdentifier.instructionsRetired.identifier, 11 | "com.apple.dt.XCTMetric_CPU.instructions_retired") 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Tests/UnitTests/XCTBeton/XCTestCaseTest.swift: -------------------------------------------------------------------------------- 1 | import Beton 2 | 3 | @testable import XCTBeton 4 | 5 | class XCTestCaseTest: XCTestCase { 6 | func testLastRunMetrics() { 7 | let testCase = XCTestCase() 8 | XCTAssertTrue(testCase.lastRunMetrics.isEmpty, "Should initially be empty.") 9 | } 10 | 11 | func testDefaultMetrics() { 12 | XCTAssertEqual(XCTestCase.defaultMetrics.count, 1, "Should have only one default metric.") 13 | XCTAssertTrue( 14 | XCTestCase.defaultMetrics[0] is XCTClockMetric, "First item should be an XCTClockMetric.") 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /Sources/Beton/Measurement/ConvenienceInitializers/Measurement+convenienceInit+whenUnitFuelEfficiency.swift: -------------------------------------------------------------------------------- 1 | extension Measurement where UnitType == UnitFuelEfficiency { 2 | public static func litersPer100Kilometers(_ value: Double) -> Self { 3 | .init(value: value, unit: .litersPer100Kilometers) 4 | } 5 | 6 | public static func milesPerGallon(_ value: Double) -> Self { 7 | .init(value: value, unit: .milesPerGallon) 8 | } 9 | 10 | public static func milesPerImperialGallon(_ value: Double) -> Self { 11 | .init(value: value, unit: .milesPerImperialGallon) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Tests/UnitTests/Beton/MathTest.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import XCTest 3 | 4 | @testable import Beton 5 | 6 | class MathTest: XCTestCase { 7 | 8 | func testPow() { 9 | XCTAssertEqual( 10 | pow(Measurement(value: 2, unit: .bits), 3), 11 | Measurement(value: 1, unit: .bytes) 12 | ) 13 | } 14 | 15 | func testSqrt() { 16 | XCTAssertEqual( 17 | sqrt(Measurement(value: 8, unit: .bits)), 18 | Measurement(value: sqrt(8), unit: .bits) 19 | ) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Sources/Beton/Locale/Locale+ExpressibleByStringLiteral.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | extension Locale: ExpressibleByStringLiteral { 4 | /// A convenience initializer that allows you to express a 5 | /// [`Locale`](https://developer.apple.com/documentation/foundation/locale) using a string literal. 6 | /// 7 | /// ```swift 8 | /// let locales: [Locale] = ["en_US", "en_GB", "hu_HU"] 9 | /// for locale in locales { 10 | /// print("Currency symbol: \(locale.currencySymbol ?? "N/A")") 11 | /// } 12 | /// ``` 13 | public init(stringLiteral locale: String) { self.init(identifier: locale) } 14 | } 15 | -------------------------------------------------------------------------------- /Sources/XCTBeton/Performance/XCTMetric/XCTMetric.swift: -------------------------------------------------------------------------------- 1 | import Beton 2 | 3 | import protocol XCTest.XCTMetric 4 | import class XCTest.XCTPerformanceMeasurement 5 | 6 | /// Extends [`XCTest.XCTMetric`](https://developer.apple.com/documentation/xctest/xctmetric) with 7 | /// ``XCTMetric/measurements-swift.property`` holding recorded performance metrics. 8 | public protocol XCTMetric: XCTest.XCTMetric { 9 | /// Holds recorded performance metrics. 10 | /// 11 | /// Use ``XCTestCase/XCTAssertMetric(_:_:_:_:file:line:)`` to make assertions for the measurements. 12 | var measurements: [XCTPerformanceMeasurement] { get } 13 | } 14 | -------------------------------------------------------------------------------- /Sources/Beton/Measurement/ConvenienceInitializers/Measurement+convenienceInit+whenUnitSpeed.swift: -------------------------------------------------------------------------------- 1 | extension Measurement where UnitType == UnitSpeed { 2 | public static func metersPerSecond(_ value: Double) -> Self { 3 | .init(value: value, unit: .metersPerSecond) 4 | } 5 | 6 | public static func kilometersPerHour(_ value: Double) -> Self { 7 | .init(value: value, unit: .kilometersPerHour) 8 | } 9 | 10 | public static func milesPerHour(_ value: Double) -> Self { 11 | .init(value: value, unit: .milesPerHour) 12 | } 13 | 14 | public static func knots(_ value: Double) -> Self { 15 | .init(value: value, unit: .knots) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Sources/Beton/Bundle/Bundle+localizationBundles.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | extension Bundle { 4 | public var localizationBundles: [Locale: Bundle] { 5 | localizations 6 | .compactMap { [self] in 7 | guard let path = path(forResource: $0, ofType: "lproj") else { return nil } 8 | guard let bundle = Bundle(path: path) else { return nil } 9 | return (key: Locale(identifier: $0), value: bundle) 10 | } 11 | .reduce([:]) { (bundles: [Locale: Bundle], entry: (key: Locale, value: Bundle)) in 12 | var bundles = bundles 13 | bundles[entry.key] = entry.value 14 | return bundles 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Sources/Beton/Measurement/ConvenienceInitializers/Measurement+convenienceInit+whenUnitConcentrationMass.swift: -------------------------------------------------------------------------------- 1 | extension Measurement where UnitType == UnitConcentrationMass { 2 | public static func gramsPerLiter(_ value: Double) -> Self { 3 | .init(value: value, unit: .gramsPerLiter) 4 | } 5 | 6 | public static func milligramsPerDeciliter(_ value: Double) -> Self { 7 | .init(value: value, unit: .milligramsPerDeciliter) 8 | } 9 | 10 | public static func millimolesPerLiter( 11 | withGramsPerMole: Double, 12 | _ value: Double 13 | ) -> Self { 14 | .init(value: value, unit: .millimolesPerLiter(withGramsPerMole: withGramsPerMole)) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Sources/XCTBeton/XCTestCase/XCTAssertMetricIdentifier.swift: -------------------------------------------------------------------------------- 1 | import Beton 2 | 3 | /// Identifies the type of ``XCTMetric/measurements-70hq6`` when making assertions. 4 | /// 5 | /// For example when measuring CPU performance you can specify what type of characteristics of metrics do you want to 6 | /// make assertions for, e.g. ``XCTAssertCpuIdentifier/time`` or ``XCTAssertCpuIdentifier/cycles``. 7 | public protocol XCTAssertMetricIdentifier { 8 | /// The ``XCTMetric`` the identifier is associated with. 9 | associatedtype RelatedMetric: XCTMetric 10 | /// The characteristic you want to make assertion for using ``XCTestCase/XCTAssertMetric(_:_:_:_:file:line:)``. 11 | var identifier: String { get } 12 | } 13 | -------------------------------------------------------------------------------- /Sources/Beton/Measurement/sqrt+measurement.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /// Returns the square root of a measurement. 4 | /// 5 | /// Square root of a measurement affects only its value and keeps the original unit. 6 | /// 7 | /// ```swift 8 | /// let measurement = sqrt(Measurement(value: 64, unit: .bits)) 9 | /// let limit = Measurement(value: 1, unit: .bytes) 10 | /// if measurement <= limit { 11 | /// print("Small enough data: \(measurement)") // Prints: Small enough data: 8.0 bit 12 | /// } 13 | /// ``` 14 | public func sqrt(_ x: Measurement) -> Measurement { 15 | Measurement( 16 | value: sqrt(x.value), 17 | unit: x.unit 18 | ) 19 | } 20 | -------------------------------------------------------------------------------- /Sources/Beton/Measurement/pow+measurement.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /// Returns a measurement raised to the given power. 4 | /// 5 | /// Raising a measurement affects only its value and keeps the original unit. 6 | /// 7 | /// ```swift 8 | /// let measurement = pow(Measurement(value: 2, unit: .bits), 3) 9 | /// let limit = Measurement(value: 1, unit: .bytes) 10 | /// if limit <= measurement { 11 | /// print("Large enough data: \(measurement)") // Prints: Large enough data: 8.0 bit 12 | /// } 13 | /// ``` 14 | public func pow(_ x: Measurement, _ y: Double) -> Measurement { 15 | Measurement( 16 | value: pow(x.value, y), 17 | unit: x.unit 18 | ) 19 | } 20 | -------------------------------------------------------------------------------- /Sources/Beton/URL/URL+ExpressibleByStringLiteral.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | extension URL: ExpressibleByStringLiteral { 4 | /// A convenience initializer that allows you to express a 5 | /// [`URL`](https://developer.apple.com/documentation/foundation/url) using a string literal. 6 | /// 7 | /// ```swift 8 | /// let assignmentExample: URL = "https://www.21gram.consulting/en-US" 9 | /// let (pageDownloadExample, _) = try await URLSession.shared.data(from: "https://www.21gram.consulting/en-US") 10 | /// ``` 11 | public init(stringLiteral value: String) { 12 | guard let url = URL(string: value) else { 13 | preconditionFailure("Couldn't initialize URL from literal as it resolved to nil.") 14 | } 15 | self = url 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Sources/Beton/Measurement/ConvenienceInitializers/Measurement+convenienceInit+whenUnitElectricResistance.swift: -------------------------------------------------------------------------------- 1 | extension Measurement where UnitType == UnitElectricResistance { 2 | public static func megaohms(_ value: Double) -> Self { 3 | .init(value: value, unit: .megaohms) 4 | } 5 | 6 | public static func kiloohms(_ value: Double) -> Self { 7 | .init(value: value, unit: .kiloohms) 8 | } 9 | 10 | public static func ohms(_ value: Double) -> Self { 11 | .init(value: value, unit: .ohms) 12 | } 13 | 14 | public static func milliohms(_ value: Double) -> Self { 15 | .init(value: value, unit: .milliohms) 16 | } 17 | 18 | public static func microohms(_ value: Double) -> Self { 19 | .init(value: value, unit: .microohms) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Sources/Beton/Measurement/ConvenienceInitializers/Measurement+convenienceInit+whenUnitEnergy.swift: -------------------------------------------------------------------------------- 1 | extension Measurement where UnitType == UnitEnergy { 2 | public static func kilojoules(_ value: Double) -> Self { 3 | .init(value: value, unit: .kilojoules) 4 | } 5 | 6 | public static func joules(_ value: Double) -> Self { 7 | .init(value: value, unit: .joules) 8 | } 9 | 10 | public static func kilocalories(_ value: Double) -> Self { 11 | .init(value: value, unit: .kilocalories) 12 | } 13 | 14 | public static func calories(_ value: Double) -> Self { 15 | .init(value: value, unit: .calories) 16 | } 17 | 18 | public static func kilowattHours(_ value: Double) -> Self { 19 | .init(value: value, unit: .kilowattHours) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Sources/Beton/Measurement/ConvenienceInitializers/Measurement+convenienceInit+whenUnitElectricCurrent.swift: -------------------------------------------------------------------------------- 1 | extension Measurement where UnitType == UnitElectricCurrent { 2 | public static func megaamperes(_ value: Double) -> Self { 3 | .init(value: value, unit: .megaamperes) 4 | } 5 | 6 | public static func kiloamperes(_ value: Double) -> Self { 7 | .init(value: value, unit: .kiloamperes) 8 | } 9 | 10 | public static func amperes(_ value: Double) -> Self { 11 | .init(value: value, unit: .amperes) 12 | } 13 | 14 | public static func milliamperes(_ value: Double) -> Self { 15 | .init(value: value, unit: .milliamperes) 16 | } 17 | 18 | public static func microamperes(_ value: Double) -> Self { 19 | .init(value: value, unit: .microamperes) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Sources/Beton/Measurement/ConvenienceInitializers/Measurement+convenienceInit+whenUnitElectricPotentialDifference.swift: -------------------------------------------------------------------------------- 1 | extension Measurement where UnitType == UnitElectricPotentialDifference { 2 | public static func megavolts(_ value: Double) -> Self { 3 | .init(value: value, unit: .megavolts) 4 | } 5 | 6 | public static func kilovolts(_ value: Double) -> Self { 7 | .init(value: value, unit: .kilovolts) 8 | } 9 | 10 | public static func volts(_ value: Double) -> Self { 11 | .init(value: value, unit: .volts) 12 | } 13 | 14 | public static func millivolts(_ value: Double) -> Self { 15 | .init(value: value, unit: .millivolts) 16 | } 17 | 18 | public static func microvolts(_ value: Double) -> Self { 19 | .init(value: value, unit: .microvolts) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Tests/UnitTests/Beton/UUID/ArrayInitFromUuidTest.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import XCTest 3 | 4 | @testable import Beton 5 | 6 | class ArrayInitFromUuidTest: XCTestCase { 7 | let uuid = UUID(uuidString: "123e4567-e89b-12d3-a456-426614174000") 8 | let array: [UInt8] = [ 9 | 0x12, 0x3e, 0x45, 0x67, 0xe8, 0x9b, 0x12, 0xd3, 0xa4, 0x56, 0x42, 0x66, 0x14, 0x17, 0x40, 0x00, 10 | ] 11 | 12 | func testInitNonOptionalUUID() { 13 | let array = Array(uuid!) 14 | XCTAssertEqual(array, self.array) 15 | } 16 | 17 | func testInitSucessfullyOptionalUUID() { 18 | guard let array = Array(uuid) else { return XCTFail("Resolved nil while expecting some.") } 19 | XCTAssertEqual(array, self.array) 20 | } 21 | 22 | func testInitNilOptionalUUID() { 23 | XCTAssertNil(Array(Optional.none)) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Tests/UnitTests/XCTBeton/Performance/XCTestCase+numberOfMeasurements.swift: -------------------------------------------------------------------------------- 1 | @testable import XCTBeton 2 | 3 | extension XCTestCaseTest { 4 | func testNumberOfMeasurementsEqualToIterationCount() { 5 | iterationCountTest(iterations: 3) 6 | } 7 | 8 | func testIterationCountCanBeZero() { 9 | iterationCountTest(iterations: 0) 10 | } 11 | 12 | func testIterationCountCanBeOne() { 13 | iterationCountTest(iterations: 1) 14 | } 15 | 16 | private func iterationCountTest(iterations: Int) { 17 | let options = XCTMeasureOptions() 18 | options.iterationCount = iterations 19 | 20 | measure(metrics: [XCTClockMetric()], options: options) {} 21 | let measurements = fetchMeasurement(for: XCTAssertClockIdentifier.timeMonotonic) 22 | 23 | XCTAssertEqual(measurements.count, iterations) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Tests/UnitTests/Beton/Bundle/BundleTest+localizedString.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import XCTest 3 | 4 | @testable import Beton 5 | 6 | extension BundleTest { 7 | func testLocalizedStringKeyOnly() { 8 | XCTAssertEqual( 9 | Bundle.module.localizedString("Test"), 10 | Bundle.module.localizedString(forKey: "Test", value: nil, table: nil) 11 | ) 12 | } 13 | 14 | func testLocalizedStringKeyAndTableOnly() { 15 | XCTAssertEqual( 16 | Bundle.module.localizedString("Test", from: "Test"), 17 | Bundle.module.localizedString(forKey: "Test", value: nil, table: "Test") 18 | ) 19 | } 20 | 21 | func testLocalizedStringKeyAndValueOnly() { 22 | XCTAssertEqual( 23 | Bundle.module.localizedString("Test", fallback: "Test"), 24 | Bundle.module.localizedString(forKey: "Test", value: "Test", table: nil) 25 | ) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Sources/Beton/Measurement/ConvenienceInitializers/Measurement+convenienceInit+whenUnitAngle.swift: -------------------------------------------------------------------------------- 1 | extension Measurement where UnitType == UnitAngle { 2 | public static func degrees(_ value: Double) -> Self { 3 | .init(value: value, unit: .degrees) 4 | } 5 | 6 | public static func arcMinutes(_ value: Double) -> Self { 7 | .init(value: value, unit: .arcMinutes) 8 | } 9 | 10 | public static func arcSeconds(_ value: Double) -> Self { 11 | .init(value: value, unit: .arcSeconds) 12 | } 13 | 14 | public static func radians(_ value: Double) -> Self { 15 | .init(value: value, unit: .radians) 16 | } 17 | 18 | public static func gradians(_ value: Double) -> Self { 19 | .init(value: value, unit: .gradians) 20 | } 21 | 22 | public static func revolutions(_ value: Double) -> Self { 23 | .init(value: value, unit: .revolutions) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Sources/Beton/Sequence/Sequence+sum.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | extension Sequence where Self.Element: AdditiveArithmetic { 4 | /// Returns the sum of all elements in the sequence. 5 | /// 6 | /// The following examples show how to use `@CodeVoice(sum)` on different sequences. 7 | /// 8 | /// ```swift 9 | /// let arraySum = [1.1, 2.2, 3.3, 4.4, 5.5].sum() 10 | /// // arraySum == 16.5 11 | /// 12 | /// let rangeSum = (1..<10).sum() 13 | /// // rangeSum == 45 14 | /// 15 | /// let setSum = Set(arrayLiteral: 1, 2, 3, 2, 3).sum() 16 | /// // setSum == 6 17 | /// ``` 18 | /// 19 | /// - Returns: The total of the elements. If the sequence has no elements, returns 20 | /// `@Link(identifier: "https://developer.apple.com/documentation/swift/additivearithmetic/3126829-zero", text: "zero")`. 21 | 22 | public func sum() -> Element { reduce(.zero, +) } 23 | } 24 | -------------------------------------------------------------------------------- /Sources/Beton/UUID/Data+UUID+convenienceBridge.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | extension Data { 4 | public init(_ uuid: UUID) { self.init(Array(uuid)) } 5 | public init?(_ uuid: UUID?) { 6 | guard let uuid = uuid else { return nil } 7 | self.init(uuid) 8 | } 9 | } 10 | 11 | extension UUID { 12 | public init?(_ data: Data?) { 13 | guard let data = data else { return nil } 14 | guard data.count == 16 else { return nil } 15 | let bytes = [UInt8](data) 16 | self = .init( 17 | uuid: ( 18 | bytes[0], bytes[1], bytes[2], bytes[3], 19 | bytes[4], bytes[5], bytes[6], bytes[7], 20 | bytes[8], bytes[9], bytes[10], bytes[11], 21 | bytes[12], bytes[13], bytes[14], bytes[15] 22 | )) 23 | } 24 | } 25 | 26 | extension UUID { public var data: Data { .init(self) } } 27 | extension Data { public var uuid: UUID? { .init(self) } } 28 | -------------------------------------------------------------------------------- /Sources/XCTBeton/XCTestCase/XCTAssertMetric/XCTAssertDiskIdentifier.swift: -------------------------------------------------------------------------------- 1 | import Beton 2 | 3 | /// Identifies the type of disk usage you want to make assertion for in a performance test. 4 | /// 5 | /// ``XCTStorageMetric`` records the amount of data logically written to the disk in the block argument to 6 | /// ``XCTestCase/measure(metrics:block:)``.To make assertion to these statistics use any of the values of 7 | /// ``XCTAssertDiskIdentifier``. 8 | /// 9 | /// - SeeAlso: https://developer.apple.com/documentation/xctest/xctstoragemetric 10 | public enum XCTAssertDiskIdentifier { 11 | case logicalWrites 12 | } 13 | 14 | extension XCTAssertDiskIdentifier: XCTAssertMetricIdentifier { 15 | public typealias RelatedMetric = XCTStorageMetric 16 | 17 | public var identifier: String { 18 | switch self { 19 | case .logicalWrites: return "com.apple.dt.XCTMetric_Disk.logical_writes" 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Sources/Beton/Measurement/ConvenienceInitializers/Measurement+convenienceInit+whenUnitElectricCharge.swift: -------------------------------------------------------------------------------- 1 | extension Measurement where UnitType == UnitElectricCharge { 2 | public static func coulombs(_ value: Double) -> Self { 3 | .init(value: value, unit: .coulombs) 4 | } 5 | 6 | public static func megaampereHours(_ value: Double) -> Self { 7 | .init(value: value, unit: .megaampereHours) 8 | } 9 | 10 | public static func kiloampereHours(_ value: Double) -> Self { 11 | .init(value: value, unit: .kiloampereHours) 12 | } 13 | 14 | public static func ampereHours(_ value: Double) -> Self { 15 | .init(value: value, unit: .ampereHours) 16 | } 17 | 18 | public static func milliampereHours(_ value: Double) -> Self { 19 | .init(value: value, unit: .milliampereHours) 20 | } 21 | 22 | public static func microampereHours(_ value: Double) -> Self { 23 | .init(value: value, unit: .microampereHours) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Tests/UnitTests/Beton/Operators/PipeTests.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import XCTest 3 | 4 | @testable import Beton 5 | 6 | class PipeTests: XCTestCase { 7 | enum TestError: Error { case test } 8 | 9 | private func double(_ value: Int) -> Int { 10 | return value * 2 11 | } 12 | 13 | func testPipe_returnsTheEndResult() { 14 | let increment = { $0 + 1 } 15 | XCTAssertEqual(2 |> increment, 3) 16 | XCTAssertEqual( 17 | 1 18 | |> increment 19 | |> increment 20 | |> increment, 21 | 4 22 | ) 23 | XCTAssertEqual( 24 | 1 25 | |> increment 26 | |> double 27 | |> increment 28 | |> double, 29 | 10 30 | ) 31 | } 32 | 33 | func testPipe_rethrowsErrors() { 34 | let increment = { $0 + 1 } 35 | let failing = { (_: Int) throws -> Int in throw TestError.test } 36 | XCTAssertThrowsError(try 1 |> increment |> failing) 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /Tests/UserAcceptanceTests/Beton/Sequence/SequenceTests+sum.swift: -------------------------------------------------------------------------------- 1 | import Beton 2 | import XCTBeton 3 | 4 | class SequenceTests { 5 | fileprivate struct InvalidValue: Error { let value: String } 6 | 7 | func testSequenceSumWithThrowIfOptional() throws { 8 | func parseMeter(_ s: String) throws -> Measurement { 9 | Measurement(value: try Double(s) ?! InvalidValue(value: s), unit: .meters) 10 | } 11 | 12 | let sum = try ["1", "2", "3"].map(parseMeter).sum() 13 | XCTAssertEqual(sum.description, "6.0 m") 14 | 15 | XCTAssertThrowsError(try ["1", "bad number", "3"].map(parseMeter).sum()) 16 | } 17 | 18 | func testSequenceSum() { 19 | let arraySum = [1.1, 2.2, 3.3, 4.4, 5.5].sum() 20 | XCTAssertEqual(arraySum, 16.5) 21 | 22 | let rangeSum = (1..<10).sum() 23 | XCTAssertEqual(rangeSum, 45) 24 | 25 | let setSum = Set(arrayLiteral: 1, 2, 3, 2, 3).sum() 26 | XCTAssertEqual(setSum, 6) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Sources/XCTBeton/XCTestCase/XCTAssertMetric/XCTAssertMemoryIdentifier.swift: -------------------------------------------------------------------------------- 1 | import Beton 2 | 3 | /// Identifies the type of memory usage you want to make assertion for in a performance test. 4 | /// 5 | /// ``XCTMemoryMetric`` compares the memory use before and after running the block argument to a 6 | /// ``XCTestCase/measure(metrics:block:)``, and reports the difference. To make assertion to these statistics 7 | /// use any of the values of ``XCTAssertMemoryIdentifier``. 8 | /// 9 | /// - SeeAlso: https://developer.apple.com/documentation/xctest/xctmemorymetric 10 | public enum XCTAssertMemoryIdentifier { 11 | case physical 12 | case physicalPeak 13 | } 14 | 15 | extension XCTAssertMemoryIdentifier: XCTAssertMetricIdentifier { 16 | public typealias RelatedMetric = XCTMemoryMetric 17 | 18 | public var identifier: String { 19 | switch self { 20 | case .physical: return "com.apple.dt.XCTMetric_Memory.physical" 21 | case .physicalPeak: return "com.apple.dt.XCTMetric_Memory.physical_peak" 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Sources/XCTBeton/XCTestCase/XCTAssertMetric/XCTAssertClockIdentifier.swift: -------------------------------------------------------------------------------- 1 | import Beton 2 | 3 | /// Identifies the type of time you want to make assertion for in a performance test. 4 | /// 5 | /// ``XCTClockMetric`` measures the total elapsed time during execution of the block argument to 6 | /// ``XCTestCase/measure(metrics:block:)``. To make assertion to these statistics use any of the values of 7 | /// ``XCTAssertClockIdentifier``. 8 | /// 9 | /// - SeeAlso: https://developer.apple.com/documentation/xctest/xctclockmetric 10 | public enum XCTAssertClockIdentifier { 11 | /// Represents monotonic records of time, regardless of changes to the system clock. These result includes time spent 12 | /// executing code under test, and time when the CPU is idle or running other code. 13 | case timeMonotonic 14 | } 15 | 16 | extension XCTAssertClockIdentifier: XCTAssertMetricIdentifier { 17 | public typealias RelatedMetric = XCTClockMetric 18 | 19 | public var identifier: String { 20 | switch self { 21 | case .timeMonotonic: return "com.apple.dt.XCTMetric_Clock.time.monotonic" 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Sources/Beton/Measurement/ConvenienceInitializers/Measurement+convenienceInit+whenUnitFrequency.swift: -------------------------------------------------------------------------------- 1 | extension Measurement where UnitType == UnitFrequency { 2 | public static func terahertz(_ value: Double) -> Self { 3 | .init(value: value, unit: .terahertz) 4 | } 5 | 6 | public static func gigahertz(_ value: Double) -> Self { 7 | .init(value: value, unit: .gigahertz) 8 | } 9 | 10 | public static func megahertz(_ value: Double) -> Self { 11 | .init(value: value, unit: .megahertz) 12 | } 13 | 14 | public static func kilohertz(_ value: Double) -> Self { 15 | .init(value: value, unit: .kilohertz) 16 | } 17 | 18 | public static func hertz(_ value: Double) -> Self { 19 | .init(value: value, unit: .hertz) 20 | } 21 | 22 | public static func millihertz(_ value: Double) -> Self { 23 | .init(value: value, unit: .millihertz) 24 | } 25 | 26 | public static func microhertz(_ value: Double) -> Self { 27 | .init(value: value, unit: .microhertz) 28 | } 29 | 30 | public static func nanohertz(_ value: Double) -> Self { 31 | .init(value: value, unit: .nanohertz) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Tests/UnitTests/Beton/Operators/wtf/wtfTests+throwIfOptional.swift: -------------------------------------------------------------------------------- 1 | import Beton 2 | import Foundation 3 | import XCTest 4 | 5 | extension WtfOperatorTest { 6 | func testThrowIfOptionalReturnsValue() throws { 7 | let url = try URL(string: "https://21gram.consulting") ?! GenericError() 8 | XCTAssertEqual(url.description, "https://21gram.consulting") 9 | } 10 | 11 | func testThrowIfOptionalThrowsGivenError() throws { 12 | XCTAssertThrowsError(try Optional.none ?! GenericError()) { error in 13 | XCTAssertEqual(error as? GenericError, GenericError()) 14 | } 15 | } 16 | 17 | func testThrowIfOptionalDoesShortCircuiting() throws { 18 | var called = false 19 | func error() -> Error { 20 | called = true 21 | return GenericError() 22 | } 23 | 24 | let goodNumber = try Int("100") ?! error() 25 | 26 | XCTAssertEqual(goodNumber, 100) 27 | XCTAssertFalse(called) 28 | 29 | do { 30 | let _ = try Int("invalid-input") ?! error() 31 | } catch { 32 | XCTAssertTrue(called) 33 | } 34 | } 35 | } 36 | 37 | private struct GenericError: Error, Equatable {} 38 | -------------------------------------------------------------------------------- /Sources/XCTBeton/Performance/XCTMetric/XCTMetric+measurementStorage.swift: -------------------------------------------------------------------------------- 1 | import Beton 2 | 3 | private var results: [ObjectIdentifier: [XCTPerformanceMeasurement]] = [:] 4 | private var copyMap: [ObjectIdentifier: ObjectIdentifier] = [:] 5 | 6 | extension XCTMetric { 7 | public var measurements: [XCTPerformanceMeasurement] { results[id] ?? [] } 8 | } 9 | 10 | extension XCTMetric { 11 | func storing(measurements: [XCTPerformanceMeasurement]) -> [XCTPerformanceMeasurement] { 12 | results[originId, default: []].append(contentsOf: measurements) 13 | return measurements 14 | } 15 | 16 | func remembering(copy: Copy) -> Copy { 17 | if let copy = copy as? Self { copyMap[copy.id] = id } 18 | return copy 19 | } 20 | 21 | func forgetSelf() { 22 | results[id] = nil 23 | copyMap[id] = nil 24 | } 25 | } 26 | 27 | extension XCTMetric { 28 | fileprivate var id: ObjectIdentifier { ObjectIdentifier(self) } 29 | 30 | fileprivate var originId: ObjectIdentifier { 31 | var originId = id 32 | while copyMap[originId] != nil { originId = copyMap[originId]! } 33 | return originId 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 21Gram Consulting 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /Tests/UnitTests/XCTBeton/Performance/XCTAssertMetric/XCTAssertMetric.AspectTest.swift: -------------------------------------------------------------------------------- 1 | import Beton 2 | 3 | @testable import XCTBeton 4 | 5 | class XCTAssertMetric_AspectTest: XCTestCase { 6 | private func assertMaximum( 7 | of: XCTAssertMetric, 8 | aspect: XCTAssertMetric.Aspect, 9 | equals: Double 10 | ) { 11 | XCTAssertEqual(aspect.maximum, equals) 12 | } 13 | 14 | func testMaximum() { 15 | assertMaximum(of: .clock, aspect: .relativeStandardDeviation(maximum: 123), equals: 123) 16 | assertMaximum(of: .clock, aspect: .average(maximum: 123), equals: 123) 17 | assertMaximum(of: .disk, aspect: .relativeStandardDeviation(maximum: 123), equals: 123) 18 | assertMaximum(of: .disk, aspect: .average(maximum: 123), equals: 123) 19 | assertMaximum(of: .memory, aspect: .relativeStandardDeviation(maximum: 123), equals: 123) 20 | assertMaximum(of: .memory, aspect: .average(maximum: 123), equals: 123) 21 | assertMaximum(of: .cpu, aspect: .relativeStandardDeviation(maximum: 123), equals: 123) 22 | assertMaximum(of: .cpu, aspect: .average(maximum: 123), equals: 123) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Tests/UserAcceptanceTests/XCTBeton/XCTBetonExamples.swift: -------------------------------------------------------------------------------- 1 | import XCTBeton 2 | 3 | class XCTBetonExamples: XCTestCase { 4 | func testMeasureWithAssertionsUsingDefaults() { 5 | measure { 6 | let _ = (1..<1000).reduce(0, +) 7 | } 8 | XCTAssertMetric(.clock, .timeMonotonic, .average(maximum: 0.002)) 9 | } 10 | 11 | func testMeasureWithAssertionsUsingAdditionalMetrics() { 12 | let options = XCTMeasureOptions() 13 | options.iterationCount = 100 14 | measure(metrics: [XCTCPUMetric(), XCTMemoryMetric()], options: options) { 15 | let _ = (1..<1000).reduce(0, +) 16 | } 17 | XCTAssertMetric(.cpu, .time, .average(maximum: 0.003)) 18 | XCTAssertMetric(.cpu, .cycles, .average(maximum: 7000)) 19 | XCTAssertMetric(.memory, .physical, .average(maximum: 20)) 20 | } 21 | 22 | func testMeasureWithUnconfiguredMetric() { 23 | measure(metrics: [XCTCPUMetric()]) { 24 | let _ = (1..<1000).reduce(0, +) 25 | } 26 | XCTAssertMetric(.cpu, .time, .average(maximum: 0.003)) 27 | // The following assertion would fail, no memory results collected. 28 | // XCTAssertMetric(.memory, .physical, .average(maximum: 20)) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Sources/XCTBeton/XCTBeton.docc/XCTBeton.md: -------------------------------------------------------------------------------- 1 | # ``XCTBeton`` 2 | 3 | XCTBeton is a Swift library that extends XCTest with additional 4 | features and utilities. 5 | 6 | ## Overview 7 | 8 | XCTBeton provides a set of generic functionalities that may 9 | be useful for any Swift application, client or server, such 10 | as **Performance test assertions** 11 | 12 | XCTBeton is designed to seamlessly serve as a drop-in 13 | replacement to your `import XCTest` statements. 14 | 15 | ### Note 16 | 17 | #### Extended Modules 18 | First, make sure you check the "Extended Modules" sections. 19 | That's where Beton's most features will hang out. 20 | 21 | #### No Serious "Articles" 22 | We were sloppy on Documentations that are descriptive/article-like. 23 | Sure, admittedly it's a bit of a shame, but in the coming 24 | months we'll be working on it, since now there's AI to do the 25 | grunt work. Just a bit of patience please :) 26 | 27 | > Important: **ON THE FLIP SIDE** all of our GitHub notifications are tuned to scream realtime. So, if oyu have questions, confusions, issues, need trainin', anythin', just open a ticket. Yes, a ticket please, because then we'll smack a Documentation tag on it, and come back to it asap. 28 | -------------------------------------------------------------------------------- /Sources/XCTBeton/Performance/XCTMetric/XCTCPUMetric.swift: -------------------------------------------------------------------------------- 1 | import Beton 2 | 3 | import class XCTest.XCTCPUMetric 4 | 5 | /// A metric to record information about CPU activity during a performance test. 6 | /// 7 | /// ``XCTCPUMetric`` is a wrapper to 8 | /// [`XCTest.XCTCPUMetric`](https://developer.apple.com/documentation/xctest/xctcpumetric). 9 | public class XCTCPUMetric: XCTest.XCTCPUMetric, XCTMetric { 10 | deinit { forgetSelf() } 11 | 12 | /// Reports the measurements gathered for a metric between specific timestamps. 13 | /// 14 | /// Stores the measurement results of 15 | /// [`reportMeasurements(from:to:)`](https://developer.apple.com/documentation/xctest/xctmetric/3194241-reportmeasurements) 16 | /// allowing you to make assertions to them. 17 | public override func reportMeasurements( 18 | from startTime: XCTPerformanceMeasurementTimestamp, 19 | to endTime: XCTPerformanceMeasurementTimestamp 20 | ) throws -> [XCTPerformanceMeasurement] { 21 | storing(measurements: try super.reportMeasurements(from: startTime, to: endTime)) 22 | } 23 | 24 | override public func copy(with zone: NSZone? = nil) -> Any { 25 | remembering(copy: super.copy(with: zone)) 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /Sources/XCTBeton/Performance/XCTMetric/XCTClockMetric.swift: -------------------------------------------------------------------------------- 1 | import Beton 2 | 3 | import class XCTest.XCTClockMetric 4 | 5 | /// A metric to record the time that elapses during a performance test. 6 | /// 7 | /// ``XCTClockMetric`` is a wrapper to 8 | /// [`XCTest.XCTClockMetric`](https://developer.apple.com/documentation/xctest/xctclockmetric). 9 | public class XCTClockMetric: XCTest.XCTClockMetric, XCTMetric { 10 | deinit { forgetSelf() } 11 | 12 | /// Reports the measurements gathered for a metric between specific timestamps. 13 | /// 14 | /// Stores the measurement results of 15 | /// [`reportMeasurements(from:to:)`](https://developer.apple.com/documentation/xctest/xctmetric/3194241-reportmeasurements) 16 | /// allowing you to make assertions to them. 17 | public override func reportMeasurements( 18 | from startTime: XCTPerformanceMeasurementTimestamp, 19 | to endTime: XCTPerformanceMeasurementTimestamp 20 | ) throws -> [XCTPerformanceMeasurement] { 21 | storing(measurements: try super.reportMeasurements(from: startTime, to: endTime)) 22 | } 23 | 24 | override public func copy(with zone: NSZone? = nil) -> Any { 25 | remembering(copy: super.copy(with: zone)) 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /Sources/XCTBeton/Performance/XCTMetric/XCTMemoryMetric.swift: -------------------------------------------------------------------------------- 1 | import Beton 2 | 3 | import class XCTest.XCTMemoryMetric 4 | 5 | /// A metric to record the physical memory that a performance test uses. 6 | /// 7 | /// ``XCTMemoryMetric`` is a wrapper to 8 | /// [`XCTest.XCTMemoryMetric`](https://developer.apple.com/documentation/xctest/xctmemorymetric). 9 | public class XCTMemoryMetric: XCTest.XCTMemoryMetric, XCTMetric { 10 | deinit { forgetSelf() } 11 | 12 | /// Reports the measurements gathered for a metric between specific timestamps. 13 | /// 14 | /// Stores the measurement results of 15 | /// [`reportMeasurements(from:to:)`](https://developer.apple.com/documentation/xctest/xctmetric/3194241-reportmeasurements) 16 | /// allowing you to make assertions to them. 17 | public override func reportMeasurements( 18 | from startTime: XCTPerformanceMeasurementTimestamp, 19 | to endTime: XCTPerformanceMeasurementTimestamp 20 | ) throws -> [XCTPerformanceMeasurement] { 21 | storing(measurements: try super.reportMeasurements(from: startTime, to: endTime)) 22 | } 23 | 24 | override public func copy(with zone: NSZone? = nil) -> Any { 25 | remembering(copy: super.copy(with: zone)) 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /Sources/XCTBeton/Performance/XCTMetric/XCTStorageMetric.swift: -------------------------------------------------------------------------------- 1 | import Beton 2 | 3 | import class XCTest.XCTStorageMetric 4 | 5 | /// A metric to record the amount of data that a performance test logically writes to storage. 6 | /// 7 | /// ``XCTStorageMetric`` is a wrapper to 8 | /// [`XCTest.XCTStorageMetric`](https://developer.apple.com/documentation/xctest/xctstoragemetric). 9 | public class XCTStorageMetric: XCTest.XCTStorageMetric, XCTMetric { 10 | 11 | deinit { forgetSelf() } 12 | 13 | /// Reports the measurements gathered for a metric between specific timestamps. 14 | /// 15 | /// Stores the measurement results of 16 | /// [`reportMeasurements(from:to:)`](https://developer.apple.com/documentation/xctest/xctmetric/3194241-reportmeasurements) 17 | /// allowing you to make assertions to them. 18 | public override func reportMeasurements( 19 | from startTime: XCTPerformanceMeasurementTimestamp, 20 | to endTime: XCTPerformanceMeasurementTimestamp 21 | ) throws -> [XCTPerformanceMeasurement] { 22 | storing(measurements: try super.reportMeasurements(from: startTime, to: endTime)) 23 | } 24 | 25 | override public func copy(with zone: NSZone? = nil) -> Any { 26 | remembering(copy: super.copy(with: zone)) 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /Package.resolved: -------------------------------------------------------------------------------- 1 | { 2 | "pins" : [ 3 | { 4 | "identity" : "swift-async-algorithms", 5 | "kind" : "remoteSourceControl", 6 | "location" : "https://github.com/apple/swift-async-algorithms.git", 7 | "state" : { 8 | "revision" : "6ae9a051f76b81cc668305ceed5b0e0a7fd93d20", 9 | "version" : "1.0.1" 10 | } 11 | }, 12 | { 13 | "identity" : "swift-collections", 14 | "kind" : "remoteSourceControl", 15 | "location" : "https://github.com/apple/swift-collections.git", 16 | "state" : { 17 | "revision" : "3d2dc41a01f9e49d84f0a3925fb858bed64f702d", 18 | "version" : "1.1.2" 19 | } 20 | }, 21 | { 22 | "identity" : "swift-docc-plugin", 23 | "kind" : "remoteSourceControl", 24 | "location" : "https://github.com/apple/swift-docc-plugin", 25 | "state" : { 26 | "revision" : "26ac5758409154cc448d7ab82389c520fa8a8247", 27 | "version" : "1.3.0" 28 | } 29 | }, 30 | { 31 | "identity" : "swift-docc-symbolkit", 32 | "kind" : "remoteSourceControl", 33 | "location" : "https://github.com/apple/swift-docc-symbolkit", 34 | "state" : { 35 | "revision" : "b45d1f2ed151d057b54504d653e0da5552844e34", 36 | "version" : "1.0.0" 37 | } 38 | } 39 | ], 40 | "version" : 2 41 | } 42 | -------------------------------------------------------------------------------- /Sources/Beton/Bundle/Bundle+localizedString.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | extension Bundle { 4 | /// A convenience API for 5 | /// [`localizedString(forKey:value:table:)`](https://developer.apple.com/documentation/foundation/bundle/1417694-localizedstring). 6 | /// 7 | /// Equivalent to calling `localizedString(forKey: key, value: nil, table: nil)`. 8 | public func localizedString(_ key: String) -> String { 9 | self.localizedString(forKey: key, value: nil, table: nil) 10 | } 11 | 12 | /// A convenience API for 13 | /// [`localizedString(forKey:value:table:)`](https://developer.apple.com/documentation/foundation/bundle/1417694-localizedstring). 14 | /// 15 | /// Equivalent to calling `localizedString(forKey: key, value: nil, table: table)`. 16 | public func localizedString(_ key: String, from table: String) -> String { 17 | self.localizedString(forKey: key, value: nil, table: table) 18 | } 19 | 20 | /// A convenience API for 21 | /// [`localizedString(forKey:value:table:)`](https://developer.apple.com/documentation/foundation/bundle/1417694-localizedstring). 22 | /// 23 | /// Equivalent to calling `localizedString(forKey: key, value: fallback, table: nil)`. 24 | public func localizedString(_ key: String, fallback: String) -> String { 25 | self.localizedString(forKey: key, value: fallback, table: nil) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Sources/XCTBeton/XCTestCase/XCTestCase.swift: -------------------------------------------------------------------------------- 1 | import Beton 2 | 3 | import class XCTest.XCTestCase 4 | 5 | /// The primary class to define tests in XCTBeton. 6 | /// 7 | /// Extends the capabilities of [`XCTestCase`](https://developer.apple.com/documentation/xctest/xctestcase) with 8 | /// ``measure(metrics:options:block:)`` and ``XCTAssertMetric(_:_:_:_:file:line:)``. You can use these features if you 9 | /// want to write performance tests with assertions. 10 | /// 11 | /// The following example shows how you can write a simple assertion: 12 | /// 13 | /// ```swift 14 | /// import XCTBeton 15 | /// 16 | /// class PerformanceTests: XCTestCase { 17 | /// func test_measureSum() { 18 | /// measure { 19 | /// let _ = (1..<1000).reduce(0, +) 20 | /// } 21 | /// XCTAssertMetric(.clock, .timeMonotonic, .average(maximum: 0.001)) 22 | /// } 23 | /// } 24 | /// ``` 25 | open class XCTestCase: XCTest.XCTestCase { 26 | internal var lastRunMetrics: [XCTMetric] = [] 27 | /// Default options for ``XCTestCase/measure(_:)``. The default instance specifies 5 iteration counts. 28 | open class override var defaultMeasureOptions: XCTMeasureOptions { XCTMeasureOptions() } 29 | } 30 | 31 | extension XCTest.XCTestCase { 32 | /// Default metrics for ``XCTestCase/measure(_:)``, returns only ``XCTClockMetric``. 33 | public class var defaultMetrics: [XCTMetric] { [XCTClockMetric()] } 34 | } 35 | -------------------------------------------------------------------------------- /Sources/Beton/Measurement/ConvenienceInitializers/Measurement+convenienceInit+whenUnitPressure.swift: -------------------------------------------------------------------------------- 1 | extension Measurement where UnitType == UnitPressure { 2 | public static func newtonsPerMetersSquared(_ value: Double) -> Self { 3 | .init(value: value, unit: .newtonsPerMetersSquared) 4 | } 5 | 6 | public static func gigapascals(_ value: Double) -> Self { 7 | .init(value: value, unit: .gigapascals) 8 | } 9 | 10 | public static func megapascals(_ value: Double) -> Self { 11 | .init(value: value, unit: .megapascals) 12 | } 13 | 14 | public static func kilopascals(_ value: Double) -> Self { 15 | .init(value: value, unit: .kilopascals) 16 | } 17 | 18 | public static func hectopascals(_ value: Double) -> Self { 19 | .init(value: value, unit: .hectopascals) 20 | } 21 | 22 | public static func inchesOfMercury(_ value: Double) -> Self { 23 | .init(value: value, unit: .inchesOfMercury) 24 | } 25 | 26 | public static func bars(_ value: Double) -> Self { 27 | .init(value: value, unit: .bars) 28 | } 29 | 30 | public static func millibars(_ value: Double) -> Self { 31 | .init(value: value, unit: .millibars) 32 | } 33 | 34 | public static func millimetersOfMercury(_ value: Double) -> Self { 35 | .init(value: value, unit: .millimetersOfMercury) 36 | } 37 | 38 | public static func poundsForcePerSquareInch(_ value: Double) -> Self { 39 | .init(value: value, unit: .poundsForcePerSquareInch) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Sources/Beton/Measurement/ConvenienceInitializers/Measurement+convenienceInit+whenUnitPower.swift: -------------------------------------------------------------------------------- 1 | extension Measurement where UnitType == UnitPower { 2 | public static func terawatts(_ value: Double) -> Self { 3 | .init(value: value, unit: .terawatts) 4 | } 5 | 6 | public static func gigawatts(_ value: Double) -> Self { 7 | .init(value: value, unit: .gigawatts) 8 | } 9 | 10 | public static func megawatts(_ value: Double) -> Self { 11 | .init(value: value, unit: .megawatts) 12 | } 13 | 14 | public static func kilowatts(_ value: Double) -> Self { 15 | .init(value: value, unit: .kilowatts) 16 | } 17 | 18 | public static func watts(_ value: Double) -> Self { 19 | .init(value: value, unit: .watts) 20 | } 21 | 22 | public static func milliwatts(_ value: Double) -> Self { 23 | .init(value: value, unit: .milliwatts) 24 | } 25 | 26 | public static func microwatts(_ value: Double) -> Self { 27 | .init(value: value, unit: .microwatts) 28 | } 29 | 30 | public static func nanowatts(_ value: Double) -> Self { 31 | .init(value: value, unit: .nanowatts) 32 | } 33 | 34 | public static func picowatts(_ value: Double) -> Self { 35 | .init(value: value, unit: .picowatts) 36 | } 37 | 38 | public static func femtowatts(_ value: Double) -> Self { 39 | .init(value: value, unit: .femtowatts) 40 | } 41 | 42 | public static func horsepower(_ value: Double) -> Self { 43 | .init(value: value, unit: .horsepower) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Sources/XCTBeton/XCTestCase/XCTAssertMetric/XCTAssertCpuIdentifier.swift: -------------------------------------------------------------------------------- 1 | import Beton 2 | 3 | /// Identifies the type of CPU statistic you want to make assertion for in a performance test. 4 | /// 5 | /// ``XCTCPUMetric`` captures statistics about CPU activity while the block argument to a 6 | /// ``XCTestCase/measure(metrics:block:)`` call runs in a performance test. To make assertion to these statistics 7 | /// use any of the values of ``XCTAssertCpuIdentifier``. 8 | /// 9 | /// - SeeAlso: https://developer.apple.com/documentation/xctest/xctcpumetric 10 | public enum XCTAssertCpuIdentifier { 11 | /// CPU time is the length of time, in seconds, that the CPU is active and executing instructions for the measured 12 | /// target. 13 | case time 14 | /// CPU cycles is the number of clock cycles that occur while the CPU is active and executing instructions for the 15 | /// measured target. 16 | case cycles 17 | /// CPU instructions retired is the number of processor instructions that run to completion during execution of the 18 | /// measured target. 19 | case instructionsRetired 20 | } 21 | 22 | extension XCTAssertCpuIdentifier: XCTAssertMetricIdentifier { 23 | public typealias RelatedMetric = XCTCPUMetric 24 | 25 | public var identifier: String { 26 | switch self { 27 | case .time: return "com.apple.dt.XCTMetric_CPU.time" 28 | case .cycles: return "com.apple.dt.XCTMetric_CPU.cycles" 29 | case .instructionsRetired: return "com.apple.dt.XCTMetric_CPU.instructions_retired" 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Tests/UnitTests/Beton/UUID/DataInitFromUuidTest.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import XCTest 3 | 4 | @testable import Beton 5 | 6 | class DataInitFromUuidTest: XCTestCase { 7 | let uuid = UUID(uuidString: "123e4567-e89b-12d3-a456-426614174000") 8 | let data = Data([ 9 | 0x12, 0x3e, 0x45, 0x67, 0xe8, 0x9b, 0x12, 0xd3, 0xa4, 0x56, 0x42, 0x66, 0x14, 0x17, 0x40, 0x00, 10 | ]) 11 | 12 | func testInitDataNonOptionalUUID() { 13 | let data = Data(uuid!) 14 | XCTAssertEqual(data, self.data) 15 | } 16 | 17 | func testInitDataSucessfullyOptionalUUID() { 18 | guard let data = Data(uuid) else { return XCTFail("Resolved nil while expecting some.") } 19 | XCTAssertEqual(data, self.data) 20 | } 21 | 22 | func testInitDataNilOptionalUUID() { 23 | XCTAssertNil(Data(Optional.none)) 24 | } 25 | 26 | func testInitUUIDSucessfullyOptionalData() { 27 | guard let uuid = UUID(data) else { return XCTFail("Resolved nil while expecting some.") } 28 | XCTAssertEqual(UUID(Optional.some(data)), self.uuid) 29 | XCTAssertEqual(uuid, self.uuid) 30 | } 31 | 32 | func testInitUUIDNilOptionalData() { 33 | XCTAssertNil(UUID(Optional.none)) 34 | } 35 | 36 | func testInitUUIDNilInsufficientByteCount() { 37 | XCTAssertNil(UUID(Data())) 38 | repeating(count: 15) { XCTAssertNil(UUID(Data(repeating: 0, count: $0))) } 39 | repeating(count: 15) { XCTAssertNil(UUID(Data(repeating: 0, count: 17 + $0))) } 40 | } 41 | 42 | func testConveniencePropertyAccessorDataFromUuid() { 43 | XCTAssertEqual(uuid!.data, data) 44 | } 45 | 46 | func testConveniencePropertyAccessorUuidFromData() { 47 | XCTAssertEqual(data.uuid, uuid) 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /Tests/PerformanceTests/Beton/Bundle/BundleTest.swift: -------------------------------------------------------------------------------- 1 | import Beton 2 | import XCTBeton 3 | 4 | // TODO: It is a shit idea to do perf assertions in the teardown. The tests break left and right with reasonable expectations.... I temporarily modified the expectations to pass, but it's shit, gotta come back. 5 | 6 | class BundleTest: XCTestCase { 7 | override func tearDown() { 8 | super.tearDown() 9 | XCTAssertMetric(.cpu, .cycles, .average(maximum: 5000)) 10 | XCTAssertMetric(.cpu, .instructionsRetired, .average(maximum: 10_000)) 11 | XCTAssertMetric(.cpu, .time, .average(maximum: 0.002)) 12 | XCTAssertMetric(.memory, .physical, .average(maximum: 60)) 13 | XCTAssertMetric(.memory, .physicalPeak, .average(maximum: 30000)) 14 | XCTAssertMetric(.disk, .logicalWrites, .average(maximum: 0)) 15 | XCTAssertMetric(.clock, .timeMonotonic, .average(maximum: 0.005)) 16 | } 17 | 18 | func testLocalizationBundles() { 19 | measure(metrics: .defaults) { 20 | let _ = Bundle.module.localizationBundles 21 | } 22 | } 23 | 24 | func testLocalizedStringKeyOnly() { 25 | measure(metrics: .defaults) { 26 | let _ = Bundle.module.localizedString("Test") 27 | } 28 | } 29 | 30 | func testLocalizedStringKeyAndTableOnly() { 31 | measure(metrics: .defaults) { 32 | let _ = Bundle.module.localizedString("Test", from: "Test") 33 | } 34 | } 35 | 36 | func testLocalizedStringKeyAndValueOnly() { 37 | measure(metrics: .defaults) { 38 | let _ = Bundle.module.localizedString("Test", fallback: "Test") 39 | } 40 | } 41 | 42 | } 43 | 44 | extension Array where Self.Element == XCTMetric { 45 | static var defaults: [Element] { 46 | [ 47 | XCTCPUMetric(), 48 | XCTMemoryMetric(), 49 | XCTStorageMetric(), 50 | XCTClockMetric(), 51 | ] 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /Sources/Beton/Measurement/ConvenienceInitializers/Measurement+convenienceInit+whenUnitArea.swift: -------------------------------------------------------------------------------- 1 | extension Measurement where UnitType == UnitArea { 2 | public static func squareMegameters(_ value: Double) -> Self { 3 | .init(value: value, unit: .squareMegameters) 4 | } 5 | 6 | public static func squareKilometers(_ value: Double) -> Self { 7 | .init(value: value, unit: .squareKilometers) 8 | } 9 | 10 | public static func squareMeters(_ value: Double) -> Self { 11 | .init(value: value, unit: .squareMeters) 12 | } 13 | 14 | public static func squareCentimeters(_ value: Double) -> Self { 15 | .init(value: value, unit: .squareCentimeters) 16 | } 17 | 18 | public static func squareMillimeters(_ value: Double) -> Self { 19 | .init(value: value, unit: .squareMillimeters) 20 | } 21 | 22 | public static func squareMicrometers(_ value: Double) -> Self { 23 | .init(value: value, unit: .squareMicrometers) 24 | } 25 | 26 | public static func squareNanometers(_ value: Double) -> Self { 27 | .init(value: value, unit: .squareNanometers) 28 | } 29 | 30 | public static func squareInches(_ value: Double) -> Self { 31 | .init(value: value, unit: .squareInches) 32 | } 33 | 34 | public static func squareFeet(_ value: Double) -> Self { 35 | .init(value: value, unit: .squareFeet) 36 | } 37 | 38 | public static func squareYards(_ value: Double) -> Self { 39 | .init(value: value, unit: .squareYards) 40 | } 41 | 42 | public static func squareMiles(_ value: Double) -> Self { 43 | .init(value: value, unit: .squareMiles) 44 | } 45 | 46 | public static func acres(_ value: Double) -> Self { 47 | .init(value: value, unit: .acres) 48 | } 49 | 50 | public static func ares(_ value: Double) -> Self { 51 | .init(value: value, unit: .ares) 52 | } 53 | 54 | public static func hectares(_ value: Double) -> Self { 55 | .init(value: value, unit: .hectares) 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.9 2 | 3 | import PackageDescription 4 | 5 | let package = Package( 6 | name: "Beton", 7 | defaultLocalization: LanguageTag("en_US"), 8 | platforms: [ 9 | .macOS(.v12), 10 | .iOS(.v15), 11 | .tvOS(.v15), 12 | .watchOS(.v8), 13 | .visionOS(.v1), 14 | ], 15 | products: [ 16 | .library(name: "Beton", targets: ["Beton"]), 17 | .library(name: "XCTBeton", targets: ["XCTBeton"]), 18 | ], 19 | dependencies: [ 20 | .package(url: "https://github.com/apple/swift-async-algorithms.git", from: "1.0.0"), 21 | .package(url: "https://github.com/apple/swift-docc-plugin", from: "1.3.0"), 22 | ], 23 | targets: [ 24 | .target( 25 | name: "Beton", 26 | dependencies: [ 27 | .product(name: "AsyncAlgorithms", package: "swift-async-algorithms") 28 | ], 29 | swiftSettings: swiftSettings 30 | ), 31 | .target( 32 | name: "XCTBeton", 33 | dependencies: [ 34 | .byName(name: "Beton") 35 | ], 36 | swiftSettings: swiftSettings 37 | ), 38 | .testTarget(type: .unit), 39 | .testTarget(type: .performance), 40 | .testTarget(type: .regression), 41 | .testTarget(type: .userAcceptance), 42 | ] 43 | ) 44 | 45 | /// MARK: Convenience units 46 | 47 | extension PackageDescription.Target { 48 | enum TestType: String { 49 | case unit = "Unit" 50 | case performance = "Performance" 51 | case regression = "Regression" 52 | case userAcceptance = "UserAcceptance" 53 | } 54 | 55 | static func testTarget(type: TestType) -> PackageDescription.Target { 56 | .testTarget( 57 | name: "\(type.rawValue)Tests", 58 | dependencies: [ 59 | .byName(name: "Beton"), 60 | .byName(name: "XCTBeton"), 61 | ], 62 | resources: [.process("Resources")] 63 | ) 64 | } 65 | } 66 | 67 | let swiftSettings: [SwiftSetting] = [ 68 | .enableExperimentalFeature("StrictConcurrency") 69 | ] 70 | -------------------------------------------------------------------------------- /Sources/Beton/Measurement/ConvenienceInitializers/Measurement+convenienceInit+whenUnitMass.swift: -------------------------------------------------------------------------------- 1 | extension Measurement where UnitType == UnitMass { 2 | public static func kilograms(_ value: Double) -> Self { 3 | .init(value: value, unit: .kilograms) 4 | } 5 | 6 | public static func grams(_ value: Double) -> Self { 7 | .init(value: value, unit: .grams) 8 | } 9 | 10 | public static func decigrams(_ value: Double) -> Self { 11 | .init(value: value, unit: .decigrams) 12 | } 13 | 14 | public static func centigrams(_ value: Double) -> Self { 15 | .init(value: value, unit: .centigrams) 16 | } 17 | 18 | public static func milligrams(_ value: Double) -> Self { 19 | .init(value: value, unit: .milligrams) 20 | } 21 | 22 | public static func micrograms(_ value: Double) -> Self { 23 | .init(value: value, unit: .micrograms) 24 | } 25 | 26 | public static func nanograms(_ value: Double) -> Self { 27 | .init(value: value, unit: .nanograms) 28 | } 29 | 30 | public static func picograms(_ value: Double) -> Self { 31 | .init(value: value, unit: .picograms) 32 | } 33 | 34 | public static func ounces(_ value: Double) -> Self { 35 | .init(value: value, unit: .ounces) 36 | } 37 | 38 | public static func pounds(_ value: Double) -> Self { 39 | .init(value: value, unit: .pounds) 40 | } 41 | 42 | public static func stones(_ value: Double) -> Self { 43 | .init(value: value, unit: .stones) 44 | } 45 | 46 | public static func metricTons(_ value: Double) -> Self { 47 | .init(value: value, unit: .metricTons) 48 | } 49 | 50 | public static func shortTons(_ value: Double) -> Self { 51 | .init(value: value, unit: .shortTons) 52 | } 53 | 54 | public static func carats(_ value: Double) -> Self { 55 | .init(value: value, unit: .carats) 56 | } 57 | 58 | public static func ouncesTroy(_ value: Double) -> Self { 59 | .init(value: value, unit: .ouncesTroy) 60 | } 61 | 62 | public static func slugs(_ value: Double) -> Self { 63 | .init(value: value, unit: .slugs) 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /Sources/XCTBeton/XCTestCase/XCTAssertMetric/XCTAssertMetric.swift: -------------------------------------------------------------------------------- 1 | import Beton 2 | 3 | /// Represents the type of metric you can make assertions for, like ``cpu`` or ``memory``. 4 | /// 5 | /// Use ``XCTestCase/XCTAssertMetric(_:_:_:_:file:line:)`` to write assertions for performance metrics you measured 6 | /// using for example ``XCTestCase/measure(metrics:block:)``. 7 | public struct XCTAssertMetric where Identifier: XCTAssertMetricIdentifier {} 8 | extension XCTAssertMetric { 9 | /// Can be used to make assertions for the collected ``XCTCPUMetric``s. 10 | public static var cpu: XCTAssertMetric { .init() } 11 | /// Can be used to make assertions for the collected ``XCTMemoryMetric``s. 12 | public static var memory: XCTAssertMetric { .init() } 13 | /// Can be used to make assertions for the collected ``XCTStorageMetric``s. 14 | public static var disk: XCTAssertMetric { .init() } 15 | /// Can be used to make assertions for the collected ``XCTClockMetric``s. 16 | public static var clock: XCTAssertMetric { .init() } 17 | } 18 | 19 | extension XCTAssertMetric { 20 | /// Represents the type of value what you can assert for. 21 | /// 22 | /// The following example makes an assertion for the ``average(maximum:)`` of the time a code takes to run. 23 | /// ```swift 24 | /// measure { 25 | /// let _ = (1..<1000).reduce(0, +) 26 | /// } 27 | /// XCTAssertMetric(.clock, .timeMonotonic, .average(maximum: 0.001)) 28 | /// ``` 29 | public enum Aspect { 30 | /// Represents the average maximum of the collected ``XCTMetric/measurements-70hq6``. 31 | case average(maximum: Double) 32 | /// Represents the relative standard deviation of the collected ``XCTMetric/measurements-70hq6``. 33 | case relativeStandardDeviation(maximum: Double) 34 | } 35 | } 36 | 37 | extension XCTAssertMetric.Aspect { 38 | var maximum: Double { 39 | switch self { 40 | case .average(let maximum): return maximum 41 | case .relativeStandardDeviation(let maximum): return maximum 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /Sources/Beton/Measurement/ConvenienceInitializers/Measurement+convenienceInit+whenUnitInformationStorage.swift: -------------------------------------------------------------------------------- 1 | extension Measurement where UnitType == UnitInformationStorage { 2 | public static func kilobits(_ value: Double) -> Self { 3 | .init(value: value, unit: .kilobits) 4 | } 5 | 6 | public static func megabits(_ value: Double) -> Self { 7 | .init(value: value, unit: .megabits) 8 | } 9 | 10 | public static func gigabits(_ value: Double) -> Self { 11 | .init(value: value, unit: .gigabits) 12 | } 13 | 14 | public static func terabits(_ value: Double) -> Self { 15 | .init(value: value, unit: .terabits) 16 | } 17 | 18 | public static func petabits(_ value: Double) -> Self { 19 | .init(value: value, unit: .petabits) 20 | } 21 | 22 | public static func exabits(_ value: Double) -> Self { 23 | .init(value: value, unit: .exabits) 24 | } 25 | 26 | public static func zettabits(_ value: Double) -> Self { 27 | .init(value: value, unit: .zettabits) 28 | } 29 | 30 | public static func yottabits(_ value: Double) -> Self { 31 | .init(value: value, unit: .yottabits) 32 | } 33 | } 34 | 35 | extension Measurement where UnitType == UnitInformationStorage { 36 | public static func kibibits(_ value: Double) -> Self { 37 | .init(value: value, unit: .kibibits) 38 | } 39 | 40 | public static func mebibits(_ value: Double) -> Self { 41 | .init(value: value, unit: .mebibits) 42 | } 43 | 44 | public static func gibibits(_ value: Double) -> Self { 45 | .init(value: value, unit: .gibibits) 46 | } 47 | 48 | public static func tebibits(_ value: Double) -> Self { 49 | .init(value: value, unit: .tebibits) 50 | } 51 | 52 | public static func pebibits(_ value: Double) -> Self { 53 | .init(value: value, unit: .pebibits) 54 | } 55 | 56 | public static func exbibits(_ value: Double) -> Self { 57 | .init(value: value, unit: .exbibits) 58 | } 59 | 60 | public static func zebibits(_ value: Double) -> Self { 61 | .init(value: value, unit: .zebibits) 62 | } 63 | 64 | public static func yobibits(_ value: Double) -> Self { 65 | .init(value: value, unit: .yobibits) 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /Tests/UnitTests/Beton/Measurement/MeasurementTest+ExpressibleByIntegerLiteral.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import XCTest 3 | 4 | @testable import Beton 5 | 6 | extension MeasurementTest { 7 | func testInitIntegerLiteral() { 8 | XCTAssertEqual(123, Measurement(value: 123, unit: UnitAcceleration.default)) 9 | XCTAssertEqual(123, Measurement(value: 123, unit: UnitAngle.default)) 10 | XCTAssertEqual(123, Measurement(value: 123, unit: UnitArea.default)) 11 | XCTAssertEqual( 12 | 123, Measurement(value: 123, unit: UnitConcentrationMass.default)) 13 | XCTAssertEqual(123, Measurement(value: 123, unit: UnitDispersion.default)) 14 | XCTAssertEqual(123, Measurement(value: 123, unit: UnitDuration.default)) 15 | XCTAssertEqual( 16 | 123, Measurement(value: 123, unit: UnitElectricCharge.default)) 17 | XCTAssertEqual( 18 | 123, Measurement(value: 123, unit: UnitElectricCurrent.default)) 19 | XCTAssertEqual( 20 | 123, 21 | Measurement( 22 | value: 123, unit: UnitElectricPotentialDifference.default)) 23 | XCTAssertEqual( 24 | 123, Measurement(value: 123, unit: UnitElectricResistance.default)) 25 | XCTAssertEqual(123, Measurement(value: 123, unit: UnitEnergy.default)) 26 | XCTAssertEqual(123, Measurement(value: 123, unit: UnitFrequency.default)) 27 | XCTAssertEqual( 28 | 123, Measurement(value: 123, unit: UnitFuelEfficiency.default)) 29 | XCTAssertEqual(123, Measurement(value: 123, unit: UnitIlluminance.default)) 30 | XCTAssertEqual( 31 | 123, Measurement(value: 123, unit: UnitInformationStorage.default)) 32 | XCTAssertEqual(123, Measurement(value: 123, unit: UnitLength.default)) 33 | XCTAssertEqual(123, Measurement(value: 123, unit: UnitMass.default)) 34 | XCTAssertEqual(123, Measurement(value: 123, unit: UnitPower.default)) 35 | XCTAssertEqual(123, Measurement(value: 123, unit: UnitPressure.default)) 36 | XCTAssertEqual(123, Measurement(value: 123, unit: UnitSpeed.default)) 37 | XCTAssertEqual(123, Measurement(value: 123, unit: UnitTemperature.default)) 38 | XCTAssertEqual(123, Measurement(value: 123, unit: UnitVolume.default)) 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Tests/UnitTests/Beton/Measurement/MeasurementTest+ExpressibleByFloatLiteral.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import XCTest 3 | 4 | @testable import Beton 5 | 6 | extension MeasurementTest { 7 | func testInitFloatLiteral() { 8 | XCTAssertEqual(123.0, Measurement(value: 123, unit: UnitAcceleration.default)) 9 | XCTAssertEqual(123.0, Measurement(value: 123, unit: UnitAngle.default)) 10 | XCTAssertEqual(123.0, Measurement(value: 123, unit: UnitArea.default)) 11 | XCTAssertEqual( 12 | 123.0, Measurement(value: 123, unit: UnitConcentrationMass.default)) 13 | XCTAssertEqual(123.0, Measurement(value: 123, unit: UnitDispersion.default)) 14 | XCTAssertEqual(123.0, Measurement(value: 123, unit: UnitDuration.default)) 15 | XCTAssertEqual( 16 | 123.0, Measurement(value: 123, unit: UnitElectricCharge.default)) 17 | XCTAssertEqual( 18 | 123.0, Measurement(value: 123, unit: UnitElectricCurrent.default)) 19 | XCTAssertEqual( 20 | 123.0, 21 | Measurement( 22 | value: 123, unit: UnitElectricPotentialDifference.default)) 23 | XCTAssertEqual( 24 | 123.0, Measurement(value: 123, unit: UnitElectricResistance.default)) 25 | XCTAssertEqual(123.0, Measurement(value: 123, unit: UnitEnergy.default)) 26 | XCTAssertEqual(123.0, Measurement(value: 123, unit: UnitFrequency.default)) 27 | XCTAssertEqual( 28 | 123.0, Measurement(value: 123, unit: UnitFuelEfficiency.default)) 29 | XCTAssertEqual(123.0, Measurement(value: 123, unit: UnitIlluminance.default)) 30 | XCTAssertEqual( 31 | 123.0, Measurement(value: 123, unit: UnitInformationStorage.default)) 32 | XCTAssertEqual(123.0, Measurement(value: 123, unit: UnitLength.default)) 33 | XCTAssertEqual(123.0, Measurement(value: 123, unit: UnitMass.default)) 34 | XCTAssertEqual(123.0, Measurement(value: 123, unit: UnitPower.default)) 35 | XCTAssertEqual(123.0, Measurement(value: 123, unit: UnitPressure.default)) 36 | XCTAssertEqual(123.0, Measurement(value: 123, unit: UnitSpeed.default)) 37 | XCTAssertEqual(123.0, Measurement(value: 123, unit: UnitTemperature.default)) 38 | XCTAssertEqual(123.0, Measurement(value: 123, unit: UnitVolume.default)) 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Sources/Beton/Measurement/ConvenienceInitializers/Measurement+convenienceInit+whenUnitLength.swift: -------------------------------------------------------------------------------- 1 | extension Measurement where UnitType == UnitLength { 2 | public static func megameters(_ value: Double) -> Self { 3 | .init(value: value, unit: .megameters) 4 | } 5 | 6 | public static func kilometers(_ value: Double) -> Self { 7 | .init(value: value, unit: .kilometers) 8 | } 9 | 10 | public static func hectometers(_ value: Double) -> Self { 11 | .init(value: value, unit: .hectometers) 12 | } 13 | 14 | public static func decameters(_ value: Double) -> Self { 15 | .init(value: value, unit: .decameters) 16 | } 17 | 18 | public static func meters(_ value: Double) -> Self { 19 | .init(value: value, unit: .meters) 20 | } 21 | 22 | public static func decimeters(_ value: Double) -> Self { 23 | .init(value: value, unit: .decimeters) 24 | } 25 | 26 | public static func centimeters(_ value: Double) -> Self { 27 | .init(value: value, unit: .centimeters) 28 | } 29 | 30 | public static func millimeters(_ value: Double) -> Self { 31 | .init(value: value, unit: .millimeters) 32 | } 33 | 34 | public static func micrometers(_ value: Double) -> Self { 35 | .init(value: value, unit: .micrometers) 36 | } 37 | 38 | public static func nanometers(_ value: Double) -> Self { 39 | .init(value: value, unit: .nanometers) 40 | } 41 | 42 | public static func picometers(_ value: Double) -> Self { 43 | .init(value: value, unit: .picometers) 44 | } 45 | 46 | public static func inches(_ value: Double) -> Self { 47 | .init(value: value, unit: .inches) 48 | } 49 | 50 | public static func feet(_ value: Double) -> Self { 51 | .init(value: value, unit: .feet) 52 | } 53 | 54 | public static func yards(_ value: Double) -> Self { 55 | .init(value: value, unit: .yards) 56 | } 57 | 58 | public static func miles(_ value: Double) -> Self { 59 | .init(value: value, unit: .miles) 60 | } 61 | 62 | public static func scandinavianMiles(_ value: Double) -> Self { 63 | .init(value: value, unit: .scandinavianMiles) 64 | } 65 | 66 | public static func lightyears(_ value: Double) -> Self { 67 | .init(value: value, unit: .lightyears) 68 | } 69 | 70 | public static func nauticalMiles(_ value: Double) -> Self { 71 | .init(value: value, unit: .nauticalMiles) 72 | } 73 | 74 | public static func fathoms(_ value: Double) -> Self { 75 | .init(value: value, unit: .fathoms) 76 | } 77 | 78 | public static func furlongs(_ value: Double) -> Self { 79 | .init(value: value, unit: .furlongs) 80 | } 81 | 82 | public static func astronomicalUnits(_ value: Double) -> Self { 83 | .init(value: value, unit: .astronomicalUnits) 84 | } 85 | 86 | public static func parsecs(_ value: Double) -> Self { 87 | .init(value: value, unit: .parsecs) 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /Sources/XCTBeton/XCTestCase/XCTestCase+measure.swift: -------------------------------------------------------------------------------- 1 | import Beton 2 | 3 | extension XCTestCase { 4 | /// Measures the performance of a block of code. 5 | /// 6 | /// Call this method from within a test method to measure the performance of a block of code. By default, this method 7 | /// measures the number of seconds the block of code takes to execute. Use ``measure(metrics:block:)`` for example 8 | /// to change the default metrics measured by this method. 9 | /// 10 | /// After using this method you can make assertions to the collected metrics using 11 | /// ``XCTAssertMetric(_:_:_:_:file:line:)``. 12 | /// 13 | /// - Parameter block: A block whose performance is measured. 14 | @nonobjc public override func measure(_ block: () -> Void) { 15 | self.measure(metrics: Self.defaultMetrics, options: Self.defaultMeasureOptions, block: block) 16 | } 17 | 18 | /// Records the selected metrics for a block of code. 19 | /// 20 | /// After using this method you can make assertions to the collected metrics using 21 | /// ``XCTAssertMetric(_:_:_:_:file:line:)``. 22 | /// 23 | /// - Parameters: 24 | /// - metrics: An array of metrics to measure, like CPU, memory, or elapsed time. 25 | /// - block: A block whose performance is measured. 26 | @nonobjc public func measure(metrics: [XCTMetric], block: () -> Void) { 27 | self.measure(metrics: metrics, options: Self.defaultMeasureOptions, block: block) 28 | } 29 | 30 | /// Records the performance, using the specified measurement options, for a block of code. 31 | /// 32 | /// After using this method you can make assertions to the collected metrics using 33 | /// ``XCTAssertMetric(_:_:_:_:file:line:)``. 34 | /// 35 | /// - Parameters: 36 | /// - options: Options to control the gathering of performance measurements. 37 | /// - block: A block whose performance is measured. 38 | @nonobjc public func measure(options: XCTMeasureOptions, block: () -> Void) { 39 | self.measure(metrics: Self.defaultMetrics, options: options, block: block) 40 | } 41 | 42 | /// Records the selected metrics, using the specified measurement options, for a block of code. 43 | /// 44 | /// After using this method you can make assertions to the collected metrics using 45 | /// ``XCTAssertMetric(_:_:_:_:file:line:)``. 46 | /// 47 | /// - Parameters: 48 | /// - metrics: An array of metrics to measure, like CPU, memory, or elapsed time. 49 | /// - options: Options to control the gathering of performance measurements. 50 | /// - block: A block whose performance is measured. 51 | @nonobjc public func measure(metrics: [XCTMetric], options: XCTMeasureOptions, block: () -> Void) 52 | { 53 | super.measure(metrics: metrics, options: options, block: block) 54 | precondition(lastRunMetrics.isEmpty, "Must not have performed measurements yet!") 55 | lastRunMetrics = metrics 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Sources/Beton/Collections/repeating.swift: -------------------------------------------------------------------------------- 1 | import AsyncAlgorithms 2 | import Foundation 3 | 4 | @discardableResult 5 | @inlinable 6 | public func repeating( 7 | count: Int, 8 | _ function: (Int) throws -> T 9 | ) rethrows -> [T] { 10 | var result = [T]() 11 | result.reserveCapacity(count) 12 | try (0.. = ((Int) -> T) -> [T] 19 | @discardableResult 20 | @inlinable 21 | public func repeating( 22 | count: Int 23 | ) -> RepeatingMapper { 24 | { function in repeating(count: count, function) } 25 | } 26 | 27 | public typealias ThrowingRepeatingMap = ((Int) throws -> T) throws -> [T] 28 | @discardableResult 29 | @inlinable 30 | public func repeating( 31 | count: Int 32 | ) -> ThrowingRepeatingMap { 33 | { try repeating(count: count, $0) } 34 | } 35 | 36 | public typealias AsyncRepeatingChannel = AsyncChannel<(iteration: Int, result: T)> 37 | @discardableResult 38 | @inlinable 39 | public func repeating( 40 | count: Int, 41 | _ function: @Sendable @escaping (Int) async -> T 42 | ) async -> AsyncRepeatingChannel { 43 | let channel = AsyncRepeatingChannel() 44 | 45 | Task { 46 | await withTaskGroup(of: Void.self) { group in 47 | for i in 0..( 60 | count: Int, 61 | _ function: @autoclosure @escaping () throws -> T 62 | ) rethrows -> [T] { 63 | try repeating(count: count) { _ in try function() } 64 | } 65 | 66 | @discardableResult 67 | @inlinable 68 | public func repeating( 69 | count: Int, 70 | _ function: @escaping () throws -> T 71 | ) rethrows -> [T] { 72 | try repeating(count: count) { _ in try function() } 73 | } 74 | 75 | public typealias RepeatingResolver = (@escaping @autoclosure () -> T) -> [T] 76 | @discardableResult 77 | @inlinable 78 | public func repeating( 79 | count: Int 80 | ) -> RepeatingResolver { 81 | { f in repeating(count: count) { _ in f() } } 82 | } 83 | 84 | public typealias ThrowingRepeatingResolver = ( 85 | @escaping () throws -> T 86 | ) throws -> [T] 87 | @discardableResult 88 | @inlinable 89 | public func repeating( 90 | count: Int 91 | ) -> ThrowingRepeatingResolver { 92 | { f in try repeating(count: count) { _ in try f() } } 93 | } 94 | 95 | @discardableResult 96 | @inlinable 97 | public func repeating( 98 | count: Int, 99 | _ function: @Sendable @escaping @autoclosure () async -> T 100 | ) async -> AsyncRepeatingChannel { 101 | await repeating(count: count) { _ in await function() } 102 | } 103 | -------------------------------------------------------------------------------- /Tests/UnitTests/Beton/Measurement/MeasurementTest+AdditiveArithmetic.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import XCTest 3 | 4 | @testable import Beton 5 | 6 | extension MeasurementTest { 7 | func testZero() { 8 | XCTAssertEqual( 9 | Measurement.zero, 10 | Measurement(value: 0, unit: UnitAcceleration.default)) 11 | XCTAssertEqual( 12 | Measurement.zero, Measurement(value: 0, unit: UnitAngle.default)) 13 | XCTAssertEqual( 14 | Measurement.zero, Measurement(value: 0, unit: UnitArea.default)) 15 | XCTAssertEqual( 16 | Measurement.zero, 17 | Measurement(value: 0, unit: UnitConcentrationMass.default)) 18 | XCTAssertEqual( 19 | Measurement.zero, 20 | Measurement(value: 0, unit: UnitDispersion.default)) 21 | XCTAssertEqual( 22 | Measurement.zero, 23 | Measurement(value: 0, unit: UnitDuration.default)) 24 | XCTAssertEqual( 25 | Measurement.zero, 26 | Measurement(value: 0, unit: UnitElectricCharge.default)) 27 | XCTAssertEqual( 28 | Measurement.zero, 29 | Measurement(value: 0, unit: UnitElectricCurrent.default)) 30 | XCTAssertEqual( 31 | Measurement.zero, 32 | Measurement( 33 | value: 0, unit: UnitElectricPotentialDifference.default)) 34 | XCTAssertEqual( 35 | Measurement.zero, 36 | Measurement(value: 0, unit: UnitElectricResistance.default)) 37 | XCTAssertEqual( 38 | Measurement.zero, Measurement(value: 0, unit: UnitEnergy.default)) 39 | XCTAssertEqual( 40 | Measurement.zero, 41 | Measurement(value: 0, unit: UnitFrequency.default)) 42 | XCTAssertEqual( 43 | Measurement.zero, 44 | Measurement(value: 0, unit: UnitFuelEfficiency.default)) 45 | XCTAssertEqual( 46 | Measurement.zero, 47 | Measurement(value: 0, unit: UnitIlluminance.default)) 48 | XCTAssertEqual( 49 | Measurement.zero, 50 | Measurement(value: 0, unit: UnitInformationStorage.default)) 51 | XCTAssertEqual( 52 | Measurement.zero, Measurement(value: 0, unit: UnitLength.default)) 53 | XCTAssertEqual( 54 | Measurement.zero, Measurement(value: 0, unit: UnitMass.default)) 55 | XCTAssertEqual( 56 | Measurement.zero, Measurement(value: 0, unit: UnitPower.default)) 57 | XCTAssertEqual( 58 | Measurement.zero, 59 | Measurement(value: 0, unit: UnitPressure.default)) 60 | XCTAssertEqual( 61 | Measurement.zero, Measurement(value: 0, unit: UnitSpeed.default)) 62 | XCTAssertEqual( 63 | Measurement.zero, 64 | Measurement(value: 0, unit: UnitTemperature.default)) 65 | XCTAssertEqual( 66 | Measurement.zero, Measurement(value: 0, unit: UnitVolume.default)) 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /Sources/Beton/Operators/wtf/wtf+throwIfOptional.swift: -------------------------------------------------------------------------------- 1 | // MARK: From Optional To Error 2 | 3 | /// Performs a `nil` checking operation, returning the wrapped value of an 4 | /// [`Optional`](https://developer.apple.com/documentation/docc) instance or throwing the given error. 5 | /// 6 | /// The `@Name(?!)` operator unwraps the left-hand side if it has a value, or it throws the right-hand side. The result of 7 | /// this operation will have the non-optional type of the left-hand side’s `Wrapped` type. 8 | /// 9 | /// Like the `??` operator, this operator uses short-circuit evaluation. For example: 10 | /// 11 | /// ```swift 12 | /// struct GenericError: Error {} 13 | /// 14 | /// var called = false 15 | /// func error() -> Error { 16 | /// called = true 17 | /// return GenericError() 18 | /// } 19 | /// 20 | /// let goodNumber = try Int("100") ?! error() 21 | /// // goodNumber == 100 22 | /// // called == false 23 | /// 24 | /// do { 25 | /// let _ = try Int("invalid-input") ?! error() // Throws GenericError 26 | /// } catch { 27 | /// // called == true 28 | /// } 29 | /// ``` 30 | /// - Parameters: 31 | /// - optional: An optional value. 32 | /// - error: The error to throw if the optional value is `nil`. 33 | public func ?! ( 34 | optional: @autoclosure () -> Value?, 35 | error: @autoclosure () -> Error 36 | ) throws -> Value where Error: Swift.Error { 37 | switch optional() { 38 | case .none: throw error() 39 | case .some(let value): return value 40 | } 41 | } 42 | 43 | public func ?! ( 44 | optional: @autoclosure () async -> Value?, 45 | error: @autoclosure () -> Error 46 | ) async throws -> Value where Error: Swift.Error { 47 | switch await optional() { 48 | case .none: throw error() 49 | case .some(let value): return value 50 | } 51 | } 52 | 53 | // MARK: From Error To Error 54 | 55 | public func ?! ( 56 | perform: @autoclosure () throws -> Value, 57 | error: @autoclosure () -> Error 58 | ) throws -> Value where Error: Swift.Error { 59 | do { return try perform() } catch _ { throw error() } 60 | } 61 | 62 | public func ?! ( 63 | perform: @autoclosure () throws -> Value, 64 | wrap: (any Swift.Error) -> Error 65 | ) throws -> Value where Error: Swift.Error { 66 | do { return try perform() } catch { throw wrap(error) } 67 | } 68 | 69 | public func ?! ( 70 | perform: @autoclosure () throws -> Value, 71 | wrap: (Source) -> Destination 72 | ) throws -> Value where Source: Error, Destination: Error { 73 | do { return try perform() } catch let error as Source { throw wrap(error) } 74 | } 75 | 76 | public func ?! ( 77 | perform: @autoclosure () async throws -> Value, 78 | error: @autoclosure () -> Error 79 | ) async throws -> Value where Error: Swift.Error { 80 | do { return try await perform() } catch _ { throw error() } 81 | } 82 | 83 | public func ?! ( 84 | perform: @autoclosure () async throws -> Value, 85 | wrap: (Swift.Error) -> Error 86 | ) async throws -> Value where Error: Swift.Error { 87 | do { return try await perform() } catch { throw wrap(error) } 88 | } 89 | 90 | public func ?! ( 91 | perform: @autoclosure () async throws -> Value, 92 | wrap: (Source) -> Destination 93 | ) async throws -> Value where Source: Error, Destination: Error { 94 | do { return try await perform() } catch let error as Source { throw wrap(error) } 95 | } 96 | -------------------------------------------------------------------------------- /Sources/XCTBeton/XCTestCase/XCTAssertMetric/XCTestCase+XCTAssertMetric.swift: -------------------------------------------------------------------------------- 1 | import Beton 2 | import XCTest 3 | 4 | extension XCTestCase { 5 | /// Asserts that the given metric has the expected aspect. 6 | /// 7 | /// You can make assertions to performance metrics if you measured your code using some variant of ``measure(_:)``. 8 | /// Make sure to assert only for ``XCTMetric``s you configured, otherwise you get an assertion error. 9 | /// 10 | /// ```swift 11 | /// measure(metrics: [XCTCPUMetric()]) { 12 | /// let _ = (1..<1000).reduce(0, +) 13 | /// } 14 | /// XCTAssertMetric(.cpu, .time, .average(maximum: 0.002)) 15 | /// // The following assertion would fail, no memory results collected. 16 | /// // XCTAssertMetric(.memory, .physical, .average(maximum: 20)) 17 | /// ``` 18 | /// - Parameters: 19 | /// - metric: The asserted performance metric. 20 | /// - identifier: Part of the metric to make assertion for. 21 | /// - aspect: The aspect to compare the performance metrics with. 22 | /// - message: An optional description of a failure. 23 | /// - file: The file where the failure occurs. The default is the filename of the test case where you call this function. 24 | /// - line: The line number where the failure occurs. The default is the line number where you call this function. 25 | // swift-format-ignore 26 | public final func XCTAssertMetric( 27 | _ metric: XCTAssertMetric, 28 | _ identifier: Identifier, 29 | _ aspect: XCTAssertMetric.Aspect, 30 | _ message: @autoclosure () -> String = "", 31 | file: StaticString = #filePath, 32 | line: UInt = #line 33 | ) { 34 | let measurements: [Double] = fetchMeasurement(for: identifier).map(\.value).map(\.value) 35 | XCTAssertLessThanOrEqual( 36 | measurements[keyPath: aspect.measurementKeyPath], 37 | aspect.maximum, 38 | errorMessage(for: identifier, message: message()), 39 | file: file, 40 | line: line 41 | ) 42 | XCTAssertFalse( 43 | measurements.isEmpty, 44 | errorMessage( 45 | for: identifier, 46 | message: "No measurement results found." 47 | ), 48 | file: file, 49 | line: line 50 | ) 51 | } 52 | 53 | private func errorMessage(for identifier: Identifier, message: String) -> String { 54 | message.isEmpty 55 | ? #"XCTAssertMetric<\#(Identifier.self).\#(identifier)>"# 56 | : #"XCTAssertMetric<\#(Identifier.self).\#(identifier)> - \#(message)"# 57 | } 58 | 59 | internal func fetchMeasurement(for identifier: Identifier) 60 | -> [XCTPerformanceMeasurement] where Identifier: XCTAssertMetricIdentifier 61 | { 62 | let measurements = 63 | lastRunMetrics 64 | .compactMap { $0 as? Identifier.RelatedMetric } 65 | .map(\.measurements) 66 | .reduce([], +) 67 | .filter { $0.identifier == identifier.identifier } // TODO: this naming is fucking dumb 68 | return Array(measurements.dropFirst()) 69 | } 70 | } 71 | 72 | extension Array where Element == Double { 73 | fileprivate var average: Element { sum() / Double(count) } 74 | 75 | fileprivate var standardDeviation: Element { 76 | let squaredDifferences = map { pow($0 - average, 2.0) } 77 | let variance = squaredDifferences.reduce(.zero, +) / Double(count - 1) 78 | return sqrt(variance) 79 | } 80 | 81 | fileprivate var relativeStandardDeviation: Double { standardDeviation / average } 82 | 83 | } 84 | 85 | extension XCTAssertMetric.Aspect { 86 | fileprivate var measurementKeyPath: KeyPath<[Double], Double> { 87 | switch self { 88 | case .average: return \.average 89 | case .relativeStandardDeviation: return \.relativeStandardDeviation 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /Tests/UnitTests/Beton/Collections/repeatingTests.swift: -------------------------------------------------------------------------------- 1 | import XCTBeton 2 | 3 | @testable import Beton 4 | 5 | class RepeatingTests: XCTestCase { 6 | enum TestError: Error { case test } 7 | func testRepeatingSyncMapper() { 8 | XCTAssertEqual(repeating(count: 3) { $0 + 5 }, [5, 6, 7]) 9 | XCTAssertEqual(repeating(count: 3) { $0 + 10 }, [10, 11, 12]) 10 | XCTAssertEqual(repeating(count: 5) { $0 + 5 }, [5, 6, 7, 8, 9]) 11 | XCTAssertEqual(repeating(count: 5) { $0 + 10 }, [10, 11, 12, 13, 14]) 12 | } 13 | 14 | func testRepeatingSyncMapper_rethrows() { 15 | XCTAssertThrowsError(try repeating(count: 3) { _ in throw TestError.test }) 16 | } 17 | 18 | func testRepeatingSyncMapper_currying() { 19 | let threeTimes: RepeatingMapper = repeating(count: 3) 20 | let fiveTimes: RepeatingMapper = repeating(count: 5) 21 | XCTAssertEqual(threeTimes({ $0 + 5 }), [5, 6, 7]) 22 | XCTAssertEqual(threeTimes({ $0 + 10 }), [10, 11, 12]) 23 | XCTAssertEqual(fiveTimes({ $0 + 5 }), [5, 6, 7, 8, 9]) 24 | XCTAssertEqual(fiveTimes({ $0 + 10 }), [10, 11, 12, 13, 14]) 25 | } 26 | 27 | func testRepeatingSyncMapper_currying_rethrows() { 28 | let threeTimes: ThrowingRepeatingMap = repeating(count: 3) 29 | XCTAssertThrowsError(try threeTimes { _ in throw TestError.test }) 30 | } 31 | 32 | func testRepeatingSyncResolver() { 33 | XCTAssertEqual(repeating(count: 3, 5), [5, 5, 5]) 34 | XCTAssertEqual(repeating(count: 3, 10), [10, 10, 10]) 35 | XCTAssertEqual(repeating(count: 5, 5), [5, 5, 5, 5, 5]) 36 | XCTAssertEqual(repeating(count: 5, 10), [10, 10, 10, 10, 10]) 37 | } 38 | 39 | func testRepeatingResolver_rethrows() { 40 | XCTAssertThrowsError(try repeating(count: 3, { throw TestError.test })) 41 | } 42 | 43 | func testRepeatingResolver_currying() { 44 | let threeTimes: RepeatingResolver = repeating(count: 3) 45 | let fiveTimes: RepeatingResolver = repeating(count: 5) 46 | XCTAssertEqual(threeTimes(5), [5, 5, 5]) 47 | XCTAssertEqual(threeTimes(10), [10, 10, 10]) 48 | XCTAssertEqual(fiveTimes(5), [5, 5, 5, 5, 5]) 49 | XCTAssertEqual(fiveTimes(10), [10, 10, 10, 10, 10]) 50 | } 51 | 52 | func testRepeatingResolver_currying_rethrows() { 53 | let threeTimes: ThrowingRepeatingResolver = repeating(count: 3) 54 | XCTAssertThrowsError( 55 | try threeTimes { 56 | throw TestError.test 57 | } 58 | ) 59 | } 60 | 61 | func testRepeatingSync_sideEffectFocused() { 62 | var counter = 0 63 | 64 | // swift-format-ignore 65 | repeating(count: 3, counter += 1) 66 | XCTAssertEqual(counter, 3) 67 | 68 | // swift-format-ignore 69 | repeating(count: 5, counter += 2) 70 | XCTAssertEqual(counter, 13) 71 | } 72 | 73 | func testRepeatingSync_sideEffectFocused_rethrows() { 74 | let throwingCallback: () throws -> Void = { throw TestError.test } 75 | XCTAssertThrowsError( 76 | try repeating(count: 3) { 77 | try throwingCallback() 78 | } 79 | ) 80 | } 81 | 82 | func testRepeatingAsyncMapper() async throws { 83 | let map = await repeating(count: 10) { (value: Int) async -> Int in 84 | value + 5 85 | } 86 | for try await item in map { 87 | XCTAssertEqual(item.result, item.iteration + 5) 88 | } 89 | } 90 | 91 | func testRepeatingAsyncResolver() async throws { 92 | for try await item in await repeating(count: 10, 100) { 93 | XCTAssertEqual(item.result, 100) 94 | } 95 | } 96 | 97 | func testRepeatingAsync_sideEffectFocused() async throws { 98 | actor Counter { 99 | var count = 0 100 | func increment() { count += 1 } 101 | } 102 | let counter = Counter() 103 | await repeating(count: 13, await counter.increment()) 104 | let result = await counter.count 105 | XCTAssertEqual(result, 13) 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /Sources/Beton/Measurement/ConvenienceInitializers/Measurement+convenienceInit+whenUnitVolume.swift: -------------------------------------------------------------------------------- 1 | extension Measurement where UnitType == UnitVolume { 2 | public static func megaliters(_ value: Double) -> Self { 3 | .init(value: value, unit: .megaliters) 4 | } 5 | 6 | public static func kiloliters(_ value: Double) -> Self { 7 | .init(value: value, unit: .kiloliters) 8 | } 9 | 10 | public static func liters(_ value: Double) -> Self { 11 | .init(value: value, unit: .liters) 12 | } 13 | 14 | public static func deciliters(_ value: Double) -> Self { 15 | .init(value: value, unit: .deciliters) 16 | } 17 | 18 | public static func centiliters(_ value: Double) -> Self { 19 | .init(value: value, unit: .centiliters) 20 | } 21 | 22 | public static func milliliters(_ value: Double) -> Self { 23 | .init(value: value, unit: .milliliters) 24 | } 25 | 26 | public static func cubicKilometers(_ value: Double) -> Self { 27 | .init(value: value, unit: .cubicKilometers) 28 | } 29 | 30 | public static func cubicMeters(_ value: Double) -> Self { 31 | .init(value: value, unit: .cubicMeters) 32 | } 33 | 34 | public static func cubicDecimeters(_ value: Double) -> Self { 35 | .init(value: value, unit: .cubicDecimeters) 36 | } 37 | 38 | public static func cubicMillimeters(_ value: Double) -> Self { 39 | .init(value: value, unit: .cubicMillimeters) 40 | } 41 | 42 | public static func cubicInches(_ value: Double) -> Self { 43 | .init(value: value, unit: .cubicInches) 44 | } 45 | 46 | public static func cubicFeet(_ value: Double) -> Self { 47 | .init(value: value, unit: .cubicFeet) 48 | } 49 | 50 | public static func cubicYards(_ value: Double) -> Self { 51 | .init(value: value, unit: .cubicYards) 52 | } 53 | 54 | public static func cubicMiles(_ value: Double) -> Self { 55 | .init(value: value, unit: .cubicMiles) 56 | } 57 | 58 | public static func acreFeet(_ value: Double) -> Self { 59 | .init(value: value, unit: .acreFeet) 60 | } 61 | 62 | public static func bushels(_ value: Double) -> Self { 63 | .init(value: value, unit: .bushels) 64 | } 65 | 66 | public static func teaspoons(_ value: Double) -> Self { 67 | .init(value: value, unit: .teaspoons) 68 | } 69 | 70 | public static func tablespoons(_ value: Double) -> Self { 71 | .init(value: value, unit: .tablespoons) 72 | } 73 | 74 | public static func fluidOunces(_ value: Double) -> Self { 75 | .init(value: value, unit: .fluidOunces) 76 | } 77 | 78 | public static func cups(_ value: Double) -> Self { 79 | .init(value: value, unit: .cups) 80 | } 81 | 82 | public static func pints(_ value: Double) -> Self { 83 | .init(value: value, unit: .pints) 84 | } 85 | 86 | public static func quarts(_ value: Double) -> Self { 87 | .init(value: value, unit: .quarts) 88 | } 89 | 90 | public static func gallons(_ value: Double) -> Self { 91 | .init(value: value, unit: .gallons) 92 | } 93 | 94 | public static func imperialTeaspoons(_ value: Double) -> Self { 95 | .init(value: value, unit: .imperialTeaspoons) 96 | } 97 | 98 | public static func imperialTablespoons(_ value: Double) -> Self { 99 | .init(value: value, unit: .imperialTablespoons) 100 | } 101 | 102 | public static func imperialFluidOunces(_ value: Double) -> Self { 103 | .init(value: value, unit: .imperialFluidOunces) 104 | } 105 | 106 | public static func imperialPints(_ value: Double) -> Self { 107 | .init(value: value, unit: .imperialPints) 108 | } 109 | 110 | public static func imperialQuarts(_ value: Double) -> Self { 111 | .init(value: value, unit: .imperialQuarts) 112 | } 113 | 114 | public static func imperialGallons(_ value: Double) -> Self { 115 | .init(value: value, unit: .imperialGallons) 116 | } 117 | 118 | public static func metricCups(_ value: Double) -> Self { 119 | .init(value: value, unit: .metricCups) 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /Sources/Beton/Measurement/Measurement+convenienceInit.swift: -------------------------------------------------------------------------------- 1 | extension Measurement { 2 | public static func acceleration( 3 | _ value: Double, 4 | _ unit: UnitAcceleration 5 | ) -> Measurement { .init(value: value, unit: unit) } 6 | 7 | public static func angle( 8 | _ value: Double, 9 | _ unit: UnitAngle 10 | ) -> Measurement { .init(value: value, unit: unit) } 11 | 12 | public static func area( 13 | _ value: Double, 14 | _ unit: UnitArea 15 | ) -> Measurement { .init(value: value, unit: unit) } 16 | 17 | public static func concentrationMass( 18 | _ value: Double, 19 | _ unit: UnitConcentrationMass 20 | ) -> Measurement { .init(value: value, unit: unit) } 21 | 22 | public static func dispersion( 23 | _ value: Double, 24 | _ unit: UnitDispersion 25 | ) -> Measurement { .init(value: value, unit: unit) } 26 | 27 | public static func duration( 28 | _ value: Double, 29 | _ unit: UnitDuration 30 | ) -> Measurement { .init(value: value, unit: unit) } 31 | 32 | public static func electricCharge( 33 | _ value: Double, 34 | _ unit: UnitElectricCharge 35 | ) -> Measurement { .init(value: value, unit: unit) } 36 | 37 | public static func electricCurrent( 38 | _ value: Double, 39 | _ unit: UnitElectricCurrent 40 | ) -> Measurement { .init(value: value, unit: unit) } 41 | 42 | public static func electricPotentialDifference( 43 | _ value: Double, 44 | _ unit: UnitElectricPotentialDifference 45 | ) -> Measurement { .init(value: value, unit: unit) } 46 | 47 | public static func electricResistance( 48 | _ value: Double, 49 | _ unit: UnitElectricResistance 50 | ) -> Measurement { .init(value: value, unit: unit) } 51 | 52 | public static func energy( 53 | _ value: Double, 54 | _ unit: UnitEnergy 55 | ) -> Measurement { .init(value: value, unit: unit) } 56 | 57 | public static func frequency( 58 | _ value: Double, 59 | _ unit: UnitFrequency 60 | ) -> Measurement { .init(value: value, unit: unit) } 61 | 62 | public static func fuelEfficiency( 63 | _ value: Double, 64 | _ unit: UnitFuelEfficiency 65 | ) -> Measurement { .init(value: value, unit: unit) } 66 | 67 | public static func illuminance( 68 | _ value: Double, 69 | _ unit: UnitIlluminance 70 | ) -> Measurement { .init(value: value, unit: unit) } 71 | 72 | public static func informationStorage( 73 | _ value: Double, 74 | _ unit: UnitInformationStorage 75 | ) -> Measurement { .init(value: value, unit: unit) } 76 | 77 | public static func length( 78 | _ value: Double, 79 | _ unit: UnitLength 80 | ) -> Measurement { .init(value: value, unit: unit) } 81 | 82 | public static func mass( 83 | _ value: Double, 84 | _ unit: UnitMass 85 | ) -> Measurement { .init(value: value, unit: unit) } 86 | 87 | public static func power( 88 | _ value: Double, 89 | _ unit: UnitPower 90 | ) -> Measurement { .init(value: value, unit: unit) } 91 | 92 | public static func pressure( 93 | _ value: Double, 94 | _ unit: UnitPressure 95 | ) -> Measurement { .init(value: value, unit: unit) } 96 | 97 | public static func speed( 98 | _ value: Double, 99 | _ unit: UnitSpeed 100 | ) -> Measurement { .init(value: value, unit: unit) } 101 | 102 | public static func temperature( 103 | _ value: Double, 104 | _ unit: UnitTemperature 105 | ) -> Measurement { .init(value: value, unit: unit) } 106 | 107 | public static func volume( 108 | _ value: Double, 109 | _ unit: UnitVolume 110 | ) -> Measurement { .init(value: value, unit: unit) } 111 | 112 | } 113 | -------------------------------------------------------------------------------- /Sources/XCTBeton/XCTBeton.swift: -------------------------------------------------------------------------------- 1 | @_exported import protocol XCTest.XCTActivity 2 | @_exported import class XCTest.XCTApplicationLaunchMetric 3 | @_exported import func XCTest.XCTAssert 4 | @_exported import func XCTest.XCTAssertEqual 5 | @_exported import func XCTest.XCTAssertEqualWithAccuracy 6 | @_exported import func XCTest.XCTAssertFalse 7 | @_exported import func XCTest.XCTAssertGreaterThan 8 | @_exported import func XCTest.XCTAssertGreaterThanOrEqual 9 | @_exported import func XCTest.XCTAssertIdentical 10 | @_exported import func XCTest.XCTAssertLessThan 11 | @_exported import func XCTest.XCTAssertLessThanOrEqual 12 | @_exported import func XCTest.XCTAssertNil 13 | @_exported import func XCTest.XCTAssertNoThrow 14 | @_exported import func XCTest.XCTAssertNotEqual 15 | @_exported import func XCTest.XCTAssertNotEqualWithAccuracy 16 | @_exported import func XCTest.XCTAssertNotIdentical 17 | @_exported import func XCTest.XCTAssertNotNil 18 | @_exported import func XCTest.XCTAssertThrowsError 19 | @_exported import func XCTest.XCTAssertTrue 20 | @_exported import class XCTest.XCTAttachment 21 | @_exported import class XCTest.XCTContext 22 | @_exported import class XCTest.XCTDarwinNotificationExpectation 23 | @_exported import func XCTest.XCTExpectFailure 24 | @_exported import class XCTest.XCTExpectedFailure 25 | @_exported import func XCTest.XCTFail 26 | @_exported import struct XCTest.XCTIssue 27 | @_exported import class XCTest.XCTIssueReference 28 | @_exported import class XCTest.XCTKVOExpectation 29 | @_exported import class XCTest.XCTMutableIssue 30 | @_exported import class XCTest.XCTNSNotificationExpectation 31 | @_exported import class XCTest.XCTNSPredicateExpectation 32 | @_exported import class XCTest.XCTOSSignpostMetric 33 | @_exported import class XCTest.XCTPerformanceMeasurement 34 | @_exported import class XCTest.XCTPerformanceMeasurementTimestamp 35 | @_exported import struct XCTest.XCTPerformanceMetric 36 | @_exported import func XCTest.XCTSelfTestMain 37 | @_exported import struct XCTest.XCTSkip 38 | @_exported import func XCTest.XCTSkipIf 39 | @_exported import func XCTest.XCTSkipUnless 40 | @_exported import class XCTest.XCTSourceCodeContext 41 | @_exported import class XCTest.XCTSourceCodeFrame 42 | @_exported import class XCTest.XCTSourceCodeLocation 43 | @_exported import class XCTest.XCTSourceCodeSymbolInfo 44 | @_exported import func XCTest.XCTUnwrap 45 | @_exported import class XCTest.XCTWaiter 46 | @_exported import protocol XCTest.XCTWaiterDelegate 47 | @_exported import var XCTest.XCT_UI_TESTING_AVAILABLE 48 | import class XCTest.XCTest 49 | @_exported import class XCTest.XCTestCaseRun 50 | @_exported import struct XCTest.XCTestError 51 | @_exported import let XCTest.XCTestErrorDomain 52 | @_exported import class XCTest.XCTestExpectation 53 | @_exported import class XCTest.XCTestLog 54 | @_exported import protocol XCTest.XCTestObservation 55 | @_exported import class XCTest.XCTestObservationCenter 56 | @_exported import class XCTest.XCTestObserver 57 | @_exported import let XCTest.XCTestObserverClassKey 58 | @_exported import class XCTest.XCTestProbe 59 | @_exported import class XCTest.XCTestRun 60 | @_exported import let XCTest.XCTestScopeAll 61 | @_exported import let XCTest.XCTestScopeKey 62 | @_exported import let XCTest.XCTestScopeNone 63 | @_exported import let XCTest.XCTestScopeSelf 64 | @_exported import class XCTest.XCTestSuite 65 | @_exported import class XCTest.XCTestSuiteRun 66 | @_exported import let XCTest.XCTestToolKey 67 | @_exported import let XCTest.XCTestedUnitPath 68 | @_exported import class XCTest.XCUIApplication 69 | @_exported import class XCTest.XCUICoordinate 70 | @_exported import class XCTest.XCUIElement 71 | @_exported import protocol XCTest.XCUIElementAttributes 72 | @_exported import class XCTest.XCUIElementQuery 73 | @_exported import protocol XCTest.XCUIElementSnapshot 74 | @_exported import protocol XCTest.XCUIElementSnapshotProviding 75 | @_exported import protocol XCTest.XCUIElementTypeQueryProvider 76 | @_exported import struct XCTest.XCUIGestureVelocity 77 | @_exported import let XCTest.XCUIIdentifierCloseWindow 78 | @_exported import let XCTest.XCUIIdentifierFullScreenWindow 79 | @_exported import let XCTest.XCUIIdentifierMinimizeWindow 80 | @_exported import let XCTest.XCUIIdentifierZoomWindow 81 | @_exported import struct XCTest.XCUIKeyboardKey 82 | @_exported import enum XCTest.XCUIProtectedResource 83 | @_exported import enum XCTest.XCUIRemoteButton 84 | @_exported import class XCTest.XCUIScreen 85 | @_exported import class XCTest.XCUIScreenshot 86 | @_exported import protocol XCTest.XCUIScreenshotProviding 87 | @_exported import typealias XCTest.XCWaitCompletionHandler 88 | @_exported import enum XCTest._XCTAssertionType 89 | @_exported import func XCTest._XCTDescriptionForValue 90 | @_exported import func XCTest._XCTFailureFormat 91 | @_exported import func XCTest._XCTPreformattedFailureHandler 92 | @_exported import class XCTest._XCTSkipFailureException 93 | @_exported import class XCTest._XCTestCaseInterruptionException 94 | 95 | public typealias XCTBeton = XCTest 96 | -------------------------------------------------------------------------------- /Tests/UserAcceptanceTests/Beton/Operators/wtfTests.swift: -------------------------------------------------------------------------------- 1 | import Beton 2 | import Foundation 3 | import XCTest 4 | 5 | class WtfOperatorTest: XCTestCase { 6 | func testThrowsIfNil() { 7 | XCTAssertThrowsError(try stub(nil) ?! StubError.error) { 8 | XCTAssertEqual($0 as? StubError, StubError.error) 9 | } 10 | } 11 | 12 | func testReturnsIfNotNil() { 13 | XCTAssertEqual(try stub(123) ?! StubError.error, 123) 14 | } 15 | 16 | func testThrowsIfNil() async throws { 17 | do { 18 | let _ = try await (await stub(nil)) ?! StubError.error 19 | XCTFail("Must have thrown.") 20 | } catch let error as StubError { 21 | XCTAssertEqual(error, StubError.error) 22 | } 23 | } 24 | 25 | func testReturnsIfNotNil() async throws { 26 | let actual = try await (await stub(123)) ?! StubError.error 27 | XCTAssertEqual(actual, 123) 28 | } 29 | 30 | // MARK: Synchronous WTF Operator without a wrapper 31 | func testWtfOperatorSyncNoWrapResolves() throws { 32 | XCTAssertEqual(try throwingStub(123) ?! StubError.error, 123) 33 | } 34 | func testWtfOperatorSyncNoWrapFails() throws { 35 | XCTAssertThrowsError(try throwingStub(StubError.error) ?! StubError.error) { 36 | XCTAssertEqual($0 as? StubError, StubError.error) 37 | } 38 | } 39 | 40 | // MARK: Synchronous WTF Operator with an any wrapper 41 | func testWtfOperatorSyncWrapAnyResolves() throws { 42 | XCTAssertEqual(try throwingStub(123) ?! { _ in AnotherStubError.anotherError }, 123) 43 | } 44 | func testWtfOperatorSyncWrapAnyFails() throws { 45 | XCTAssertThrowsError( 46 | try throwingStub(StubError.error) ?! { _ in AnotherStubError.anotherError } 47 | ) { 48 | XCTAssertEqual($0 as? AnotherStubError, .anotherError) 49 | } 50 | } 51 | 52 | // MARK: Synchronous WTF Operator with a specialized wrapper 53 | func testWtfOperatorSyncWrapSpecializedResolves() throws { 54 | XCTAssertEqual(try throwingStub(123) ?! StubError.init, 123) 55 | } 56 | func testWtfOperatorSyncWrapSpecializedFailsCanWrap() throws { 57 | XCTAssertThrowsError(try throwingStub(StubError.error) ?! StubError.init) { 58 | XCTAssertEqual($0 as? StubError, .wrappedError(StubError.error)) 59 | } 60 | } 61 | func testWtfOperatorSyncWrapSpecializedFailsCantWrap() throws { 62 | XCTAssertThrowsError(try throwingStub(AnotherStubError.anotherError) ?! StubError.init) { 63 | XCTAssertEqual($0 as? AnotherStubError, .anotherError) 64 | } 65 | } 66 | 67 | // MARK: Asynchronous WTF Operator without a wrapper 68 | func testWtfOperatorAsyncNoWrapResolves() async throws { 69 | let actual = try await (await stub(123)) ?! StubError.error 70 | XCTAssertEqual(actual, 123) 71 | } 72 | func testWtfOperatorAsyncNoWrapFails() async throws { 73 | do { 74 | let _ = try await (await throwingStub(AnotherStubError.anotherError)) ?! StubError.error 75 | XCTFail("Must have thrown.") 76 | } catch let error as StubError { 77 | XCTAssertEqual(error, StubError.error) 78 | } 79 | } 80 | 81 | // MARK: Asynchronous WTF Operator with an any wrapper 82 | func testWtfOperatorAsyncWrapAnyResolves() async throws { 83 | let actual = try await (await stub(123)) ?! { _ in StubError.error } 84 | XCTAssertEqual(actual, 123) 85 | } 86 | func testWtfOperatorAsyncWrapAnyFails() async throws { 87 | do { 88 | let _ = 89 | try await (await throwingStub(StubError.error)) ?! { _ in AnotherStubError.anotherError } 90 | XCTFail("Must have thrown.") 91 | } catch let error as AnotherStubError { 92 | XCTAssertEqual(error, .anotherError) 93 | } 94 | } 95 | 96 | // MARK: Asynchronous WTF Operator with a specialized wrapper 97 | func testWtfOperatorAsyncWrapSpecializedResolves() async throws { 98 | let actual = try await (await stub(123)) ?! StubError.init 99 | XCTAssertEqual(actual, 123) 100 | } 101 | func testWtfOperatorAsyncWrapSpecializedFailsCanWrap() async throws { 102 | do { 103 | let _ = try await (await throwingStub(StubError.error)) ?! StubError.init 104 | XCTFail("Must have thrown.") 105 | } catch let error as StubError { 106 | XCTAssertEqual(error, .wrappedError(.error)) 107 | } 108 | } 109 | func testWtfOperatorAsyncWrapSpecializedFailsCantWrap() async throws { 110 | do { 111 | let _ = try await (await throwingStub(AnotherStubError.anotherError)) ?! StubError.init 112 | XCTFail("Must have thrown.") 113 | } catch let error as AnotherStubError { 114 | XCTAssertEqual(error, .anotherError) 115 | } 116 | } 117 | } 118 | 119 | private enum StubError: Error, Equatable { 120 | case error 121 | indirect case wrappedError(StubError) 122 | 123 | init() { self = .error } 124 | init(_ error: StubError) { self = .wrappedError(error) } 125 | } 126 | 127 | private enum AnotherStubError: Error { case anotherError } 128 | 129 | private func stub(_ value: Int?) -> Int? { value } 130 | private func stub(_ value: Int?) async -> Int? { value } 131 | 132 | private func throwingStub(_ value: Int) throws -> Int { value } 133 | private func throwingStub(_ value: Int) async throws -> Int { value } 134 | private func throwingStub(_ error: Error) throws -> Int { throw error } 135 | private func throwingStub(_ error: Error) async throws -> Int { throw error } 136 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Beton 2 | 3 | [![](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2F21GramConsulting%2FBeton%2Fbadge%3Ftype%3Dswift-versions)](https://swiftpackageindex.com/21GramConsulting/Beton) 4 | 5 | [![](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2F21GramConsulting%2FBeton%2Fbadge%3Ftype%3Dplatforms)](https://swiftpackageindex.com/21GramConsulting/Beton) 6 | 7 | `Beton` is a [Swift](http://docs.swift.org) library built on top of 8 | the [Foundation](https://developer.apple.com/documentation/foundation) framework, that provides an additional layer of 9 | functionality, including easy localization, performance test measurement support, and convenience functionality. 10 | For us, `Beton` is primarily, but not exclusively, useful for server-side Swift engineering. 11 | 12 | ## Modules 13 | 14 | - [Beton](#using-the-beton-module): Generic purpose functionalities that may be useful for every application. 15 | - [XCTBeton](#using-the-xctbeton-module): Extends the capabilities of [XCTest](https://developer.apple.com/documentation/xctest) by 16 | providing assertions for performance measurements. 17 | 18 | ## Using the Beton Module 19 | 20 | ### Importing 21 | 22 | To use `Beton` simply import it. If you need anything 23 | from [Foundation](https://developer.apple.com/documentation/foundation) you do not need to explicitly import it. You get 24 | it for free by importing `Beton.` 25 | 26 | ```swift 27 | import Beton 28 | ``` 29 | 30 | ### Convenience API for [`Bundle`](https://developer.apple.com/documentation/foundation/bundle) 31 | 32 | Using `Beton` it is quite easy to get localized bundles and values from them. 33 | 34 | Suppose you have a localization bundle in your project for the `hu_HU` locale, with a translation for `"Apple" = "Alma"` 35 | , but you don't have one for `"Banana"` (which would be `"Banán"`). The following example finds the bundle, gets the 36 | localized version of `"Apple"`, and falls back to the given key `"Banana"`. 37 | 38 | ```swift 39 | let bundle = Bundle.module.localizationBundles["hu_HU"] 40 | let localizedApple = bundle?.localizedString("Apple") 41 | // localizedApple == "Alma" 42 | let localizedBanana = bundle?.localizedString("Banana") 43 | // localizedBanana == "Banana" 44 | ``` 45 | 46 | ### Convenience API for [`Locale`](https://developer.apple.com/documentation/foundation/locale) 47 | 48 | Locales in `Beton` are expressible by string literals. 49 | 50 | ```swift 51 | let locales: [Locale] = ["en_US", "en_GB", "hu_HU"] 52 | for locale in locales { 53 | print("Currency symbol: \(locale.currencySymbol ?? "N/A")") 54 | } 55 | // Prints: 56 | // Currency symbol: $ 57 | // Currency symbol: £ 58 | // Currency symbol: Ft 59 | ``` 60 | 61 | ### ``?!`` operator 62 | 63 | The ``?!`` operator unwraps an [`Optional`](https://developer.apple.com/documentation/swift/optional) value if is 64 | not `nil`, otherwise throws the given error. 65 | 66 | ```swift 67 | struct GenericError: Error {} 68 | 69 | let answer = try Int("42") ?! GenericError() 70 | // answer == 42 71 | 72 | try Int("NaN") ?! GenericError() 73 | // Throws: GenericError() 74 | ``` 75 | 76 | ### ``sum`` extension on [`Sequence`](https://developer.apple.com/documentation/swift/sequence)s 77 | 78 | Calculates the total of all elements in a sequence. Available on any sequence with values that conform 79 | to [`AdditiveArithmetic`](https://developer.apple.com/documentation/swift/additivearithmetic) 80 | 81 | ```swift 82 | let arraySum = [1.1, 2.2, 3.3, 4.4, 5.5].sum() 83 | // arraySum == 16.5 84 | 85 | let rangeSum = (1..<10).sum() 86 | // rangeSum == 45 87 | 88 | let setSum = Set(arrayLiteral: 1, 2, 3, 2, 3).sum() 89 | // setSum == 6 90 | ``` 91 | 92 | ### Convenience for [`Measurement`](https://developer.apple.com/documentation/foundation/measurement)s 93 | 94 | In `Beton` measurements have default units and they conform 95 | to [`AdditiveArithmetic`](https://developer.apple.com/documentation/swift/additivearithmetic). 96 | 97 | ```swift 98 | let sum = [1, 2, 3].map { Measurement(value: $0, unit: .default) }.sum() 99 | // sum == 6.0 m 100 | ``` 101 | 102 | ## Using the XCTBeton Module 103 | 104 | Let's say you have a simple performance test that measures some code. 105 | Using [XCTest](https://developer.apple.com/documentation/xctest/xctestcase/3194265-measure) there is no easy, 106 | straightforward way to make assertions to the performance results. 107 | 108 | ```swift 109 | import XCTest 110 | 111 | class PerformanceTests: XCTestCase { 112 | func test_measureSum() { 113 | measure { 114 | let _ = (1..<1000).reduce(0, +) 115 | } 116 | // Performance assertions needed! 117 | } 118 | } 119 | ``` 120 | 121 | You can turn this code into an `XCTBeton` test by simply changing the import. Yes, that's it. You can now make 122 | assertions! 123 | 124 | ```swift 125 | import XCTBeton 126 | 127 | class PerformanceTests: XCTestCase { 128 | func test_measureSum() { 129 | measure { 130 | let _ = (1..<1000).reduce(0, +) 131 | } 132 | XCTAssertMetric(.clock, .timeMonotonic, .average(maximum: 0.001)) 133 | } 134 | } 135 | ``` 136 | 137 | If you want to control the type of measurements, and how many times the tests run you can do that using the same API as 138 | you would in regular [XCTest](https://developer.apple.com/documentation/xctest/xctestcase/3194265-measure). 139 | 140 | ```swift 141 | import XCTBeton 142 | 143 | class PerformanceTests: XCTestCase { 144 | func test_measureSum() { 145 | let options = XCTMeasureOptions() 146 | options.iterationCount = 100 147 | measure(metrics: [XCTCPUMetric(), XCTMemoryMetric()], options: options) { 148 | let _ = (1..<1000).reduce(0, +) 149 | } 150 | XCTAssertMetric(.cpu, .time, .average(maximum: 0.002)) 151 | XCTAssertMetric(.cpu, .cycles, .average(maximum: 2000)) 152 | XCTAssertMetric(.memory, .physical, .average(maximum: 20)) 153 | } 154 | } 155 | ``` 156 | 157 | ## Adding `Beton` as a Dependency 158 | 159 | To use the `Beton` library in a SwiftPM project, add it to the dependencies for your package and your target. Your 160 | target can depend on either the `Beton` or `XCTBeton` modules, or both. 161 | 162 | ```swift 163 | // swift-tools-version:5.5.0 164 | 165 | import PackageDescription 166 | 167 | let package = Package( 168 | name: "MyApplication", 169 | dependencies: [ 170 | .package(url: "https://github.com/21GramConsulting/Beton", from: "1.0.0"), 171 | ], 172 | targets: [ 173 | .target(name: "MyApplication", dependencies: [ 174 | .product(name: "Beton", package: "Beton"), 175 | .product(name: "XCTBeton", package: "Beton"), 176 | ]) 177 | ] 178 | ) 179 | ``` 180 | --------------------------------------------------------------------------------