From 2cf870014ba48250a1b5319fa8f43479e26642d2 Mon Sep 17 00:00:00 2001 From: John Szumski Date: Mon, 13 Feb 2017 23:09:14 -0500 Subject: [PATCH] Initial implementation of MassFormatter. --- Docs/Status.md | 2 +- Foundation.xcodeproj/project.pbxproj | 6 + Foundation/NSLengthFormatter.swift | 20 +-- Foundation/NSMassFormatter.swift | 221 ++++++++++++++++++++++++- TestFoundation/TestMassFormatter.swift | 140 ++++++++++++++++ TestFoundation/main.swift | 1 + 6 files changed, 365 insertions(+), 25 deletions(-) create mode 100644 TestFoundation/TestMassFormatter.swift diff --git a/Docs/Status.md b/Docs/Status.md index 69c03ac336..13c9cfd2ab 100644 --- a/Docs/Status.md +++ b/Docs/Status.md @@ -98,7 +98,7 @@ There is no _Complete_ status for test coverage because there are always additio | `EnergyFormatter` | Unimplemented | None | | | `ISO8601DateFormatter` | Unimplemented | None | | | `LengthFormatter` | Complete | Substantial | | - | `MassFormatter` | Unimplemented | None | | + | `MassFormatter` | Complete | Substantial | Needs localization | | `NumberFormatter` | Mostly Complete | Substantial | `objectValue(_:range:)` remains unimplemented | | `PersonNameComponentsFormatter` | Unimplemented | None | | | `ByteCountFormatter` | Mostly Complete | Substantial | `init?(coder:)` remains unimplemented | diff --git a/Foundation.xcodeproj/project.pbxproj b/Foundation.xcodeproj/project.pbxproj index 99f3978b01..3a7edc437b 100644 --- a/Foundation.xcodeproj/project.pbxproj +++ b/Foundation.xcodeproj/project.pbxproj @@ -315,6 +315,7 @@ 7900433B1CACD33E00ECCBF1 /* TestNSCompoundPredicate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 790043391CACD33E00ECCBF1 /* TestNSCompoundPredicate.swift */; }; 7900433C1CACD33E00ECCBF1 /* TestNSPredicate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7900433A1CACD33E00ECCBF1 /* TestNSPredicate.swift */; }; 90E645DF1E4C89A400D0D47C /* TestNSCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 90E645DE1E4C89A400D0D47C /* TestNSCache.swift */; }; + A058C2021E529CF100B07AA1 /* TestMassFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = A058C2011E529CF100B07AA1 /* TestMassFormatter.swift */; }; AE35A1861CBAC85E0042DB84 /* SwiftFoundation.h in Headers */ = {isa = PBXBuildFile; fileRef = AE35A1851CBAC85E0042DB84 /* SwiftFoundation.h */; settings = {ATTRIBUTES = (Public, ); }; }; BD8042161E09857800487EB8 /* TestNSLengthFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD8042151E09857800487EB8 /* TestNSLengthFormatter.swift */; }; BDBB65901E256BFA001A7286 /* TestNSEnergyFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = BDBB658F1E256BFA001A7286 /* TestNSEnergyFormatter.swift */; }; @@ -763,6 +764,7 @@ 84BA558D1C16F90900F48C54 /* TestNSTimeZone.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestNSTimeZone.swift; sourceTree = ""; }; 88D28DE61C13AE9000494606 /* TestNSGeometry.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestNSGeometry.swift; sourceTree = ""; }; 90E645DE1E4C89A400D0D47C /* TestNSCache.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestNSCache.swift; sourceTree = ""; }; + A058C2011E529CF100B07AA1 /* TestMassFormatter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestMassFormatter.swift; sourceTree = ""; }; A5A34B551C18C85D00FD972B /* TestNSByteCountFormatter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestNSByteCountFormatter.swift; sourceTree = ""; }; AE35A1851CBAC85E0042DB84 /* SwiftFoundation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SwiftFoundation.h; sourceTree = ""; }; BD8042151E09857800487EB8 /* TestNSLengthFormatter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestNSLengthFormatter.swift; sourceTree = ""; }; @@ -1404,6 +1406,7 @@ D3047AEB1C38BC3300295652 /* TestNSValue.swift */, 5B6F17951C48631C00935030 /* TestNSXMLDocument.swift */, 5B40F9F11C125187000E72E3 /* TestNSXMLParser.swift */, + A058C2011E529CF100B07AA1 /* TestMassFormatter.swift */, CC5249BF1D341D23007CB54D /* TestUnitConverter.swift */, 5B6F17961C48631C00935030 /* TestUtils.swift */, 0383A1741D2E558A0052E5D1 /* TestNSStream.swift */, @@ -2251,6 +2254,9 @@ 1520469B1D8AEABE00D02E36 /* HTTPServer.swift in Sources */, 5B13B3471C582D4C00651CE2 /* TestThread.swift in Sources */, 5B13B32E1C582D4C00651CE2 /* TestFileManager.swift in Sources */, + 5B13B3471C582D4C00651CE2 /* TestNSThread.swift in Sources */, + 5B13B32E1C582D4C00651CE2 /* TestNSFileManager.swift in Sources */, + A058C2021E529CF100B07AA1 /* TestMassFormatter.swift in Sources */, 5B13B3381C582D4C00651CE2 /* TestNSNotificationQueue.swift in Sources */, CC5249C01D341D23007CB54D /* TestUnitConverter.swift in Sources */, 5B13B3331C582D4C00651CE2 /* TestNSJSONSerialization.swift in Sources */, diff --git a/Foundation/NSLengthFormatter.swift b/Foundation/NSLengthFormatter.swift index f508a7617b..a3c6bb9ab5 100644 --- a/Foundation/NSLengthFormatter.swift +++ b/Foundation/NSLengthFormatter.swift @@ -69,7 +69,7 @@ open class LengthFormatter : Formatter { //Extract the number from the measurement let numberInUnit = unitMeasurement.value - if isForPersonHeightUse && !LengthFormatter.isMetricSystemLocale(numberFormatter.locale) { + if isForPersonHeightUse && !numberFormatter.locale.sr3202_fix_isMetricSystemLocale() { let feet = numberInUnit.rounded(.towardZero) let feetString = string(fromValue: feet, unit: .foot) @@ -123,7 +123,7 @@ open class LengthFormatter : Formatter { /// - Parameter numberInMeters: the magnitude in terms of meters /// - Returns: Returns the appropriate unit private func unit(fromMeters numberInMeters: Double) -> Unit { - if LengthFormatter.isMetricSystemLocale(numberFormatter.locale) { + if numberFormatter.locale.sr3202_fix_isMetricSystemLocale() { //Person height is always returned in cm for metric system if isForPersonHeightUse { return .centimeter } @@ -152,22 +152,6 @@ open class LengthFormatter : Formatter { } } - /// TODO: Replace calls to the below function to use Locale.usesMetricSystem - /// Temporary workaround due to unpopulated Locale attributes - /// See https://bugs.swift.org/browse/SR-3202 - private static func isMetricSystemLocale(_ locale: Locale) -> Bool { - switch locale.identifier { - case "en_US": return false - case "en_US_POSIX": return false - case "haw_US": return false - case "es_US": return false - case "chr_US": return false - case "my_MM": return false - case "en_LR": return false - case "vai_LR": return false - default: return true - } - } /// - Experiment: This is a draft API currently under consideration for official import into Foundation as a suitable alternative /// - Note: Since this API is under consideration it may be either removed or revised in the near future diff --git a/Foundation/NSMassFormatter.swift b/Foundation/NSMassFormatter.swift index 6306c14a07..101856ac35 100644 --- a/Foundation/NSMassFormatter.swift +++ b/Foundation/NSMassFormatter.swift @@ -10,7 +10,6 @@ extension MassFormatter { public enum Unit : Int { - case gram case kilogram case ounce @@ -21,28 +20,238 @@ extension MassFormatter { open class MassFormatter : Formatter { + public override init() { + numberFormatter = NumberFormatter() + numberFormatter.numberStyle = .decimal + unitStyle = .medium + isForPersonMassUse = false + super.init() + } + public required init?(coder: NSCoder) { - NSUnimplemented() + numberFormatter = NumberFormatter() + numberFormatter.numberStyle = .decimal + unitStyle = .medium + isForPersonMassUse = false + super.init(coder:coder) } /*@NSCopying*/ open var numberFormatter: NumberFormatter! // default is NSNumberFormatter with NSNumberFormatterDecimalStyle open var unitStyle: UnitStyle // default is NSFormattingUnitStyleMedium + open var isForPersonMassUse: Bool // default is NO; if it is set to YES, the number argument for -stringFromKilograms: and -unitStringFromKilograms: is considered as a person’s mass // Format a combination of a number and an unit to a localized string. - open func string(fromValue value: Double, unit: Unit) -> String { NSUnimplemented() } + open func string(fromValue value: Double, unit: Unit) -> String { + // special case: stone shows fractional values in pounds + if unit == .stone { + let stone = value.rounded(.towardZero) + let stoneString = singlePartString(fromValue: stone, unit: unit) // calling `string(fromValue: stone, unit: .stone)` would infinitely recur + let pounds = abs(value.truncatingRemainder(dividingBy: 1.0)) * MassFormatter.poundsPerStone + + // if we don't have any fractional component, don't append anything + if pounds == 0 { + return stoneString + } else { + let poundsString = string(fromValue: pounds, unit: .pound) + let separator = unitStyle == MassFormatter.UnitStyle.short ? " " : ", " + + return ("\(stoneString)\(separator)\(poundsString)") + } + } + + // normal case: kilograms and pounds + return singlePartString(fromValue: value, unit: unit) + } // Format a number in kilograms to a localized string with the locale-appropriate unit and an appropriate scale (e.g. 1.2kg = 2.64lb in the US locale). - open func string(fromKilograms numberInKilograms: Double) -> String { NSUnimplemented() } + open func string(fromKilograms numberInKilograms: Double) -> String { + //Convert to the locale-appropriate unit + let unitFromKilograms = convertedUnit(fromKilograms: numberInKilograms) + + //Map the unit to UnitMass type for conversion later + let unitMassFromKilograms = MassFormatter.unitMass[unitFromKilograms]! + + //Create a measurement object based on the value in kilograms + let kilogramMeasurement = Measurement(value:numberInKilograms, unit: .kilograms) + + //Convert the object to the locale-appropriate unit determined above + let unitMeasurement = kilogramMeasurement.converted(to: unitMassFromKilograms) + + //Extract the number from the measurement + let numberInUnit = unitMeasurement.value + + return string(fromValue: numberInUnit, unit: unitFromKilograms) + } // Return a localized string of the given unit, and if the unit is singular or plural is based on the given number. - open func unitString(fromValue value: Double, unit: Unit) -> String { NSUnimplemented() } + open func unitString(fromValue value: Double, unit: Unit) -> String { + if unitStyle == .short { + return MassFormatter.shortSymbol[unit]! + } else if unitStyle == .medium { + return MassFormatter.mediumSymbol[unit]! + } else if unit == .stone { // special case, see `unitStringDisplayedAdjacent(toValue:, unit:)` + return MassFormatter.largeSingularSymbol[unit]! + } else if value == 1.0 { + return MassFormatter.largeSingularSymbol[unit]! + } else { + return MassFormatter.largePluralSymbol[unit]! + } + } // Return the locale-appropriate unit, the same unit used by -stringFromKilograms:. - open func unitString(fromKilograms numberInKilograms: Double, usedUnit unitp: UnsafeMutablePointer?) -> String { NSUnimplemented() } + open func unitString(fromKilograms numberInKilograms: Double, usedUnit unitp: UnsafeMutablePointer?) -> String { + //Convert to the locale-appropriate unit + let unitFromKilograms = convertedUnit(fromKilograms: numberInKilograms) + unitp?.pointee = unitFromKilograms + + //Map the unit to UnitMass type for conversion later + let unitMassFromKilograms = MassFormatter.unitMass[unitFromKilograms]! + + //Create a measurement object based on the value in kilograms + let kilogramMeasurement = Measurement(value:numberInKilograms, unit: .kilograms) + + //Convert the object to the locale-appropriate unit determined above + let unitMeasurement = kilogramMeasurement.converted(to: unitMassFromKilograms) + + //Extract the number from the measurement + let numberInUnit = unitMeasurement.value + + //Return the appropriate representation of the unit based on the selected unit style + return unitString(fromValue: numberInUnit, unit: unitFromKilograms) + } /// - Experiment: This is a draft API currently under consideration for official import into Foundation as a suitable alternative /// - Note: Since this API is under consideration it may be either removed or revised in the near future open override func objectValue(_ string: String) throws -> Any? { return nil } + + + // MARK: - Private + + /// This method selects the appropriate unit based on the formatter’s locale, + /// the magnitude of the value, and isForPersonMassUse property. + /// + /// - Parameter numberInKilograms: the magnitude in terms of kilograms + /// - Returns: Returns the appropriate unit + private func convertedUnit(fromKilograms numberInKilograms: Double) -> Unit { + if numberFormatter.locale.sr3202_fix_isMetricSystemLocale() { + if numberInKilograms > 1.0 || numberInKilograms <= 0.0 { + return .kilogram + } else { + return .gram + } + } else { + let metricMeasurement = Measurement(value:numberInKilograms, unit: .kilograms) + let imperialMeasurement = metricMeasurement.converted(to: .pounds) + let numberInPounds = imperialMeasurement.value + + if numberInPounds >= 1.0 || numberInPounds <= 0.0 { + return .pound + } else { + return .ounce + } + } + } + + /// Formats the given value and unit into a string containing one logical + /// value. This is intended for units like kilogram and pound where + /// fractional values are represented as a decimal instead of converted + /// values in another unit. + /// + /// - Parameter value: The mass's value in the given unit. + /// - Parameter unit: The unit used in the resulting mass string. + /// - Returns: A properly formatted mass string for the given value and unit. + private func singlePartString(fromValue value: Double, unit: Unit) -> String { + guard let formattedValue = numberFormatter.string(from:NSNumber(value: value)) else { + fatalError("Cannot format \(value) as string") + } + + let separator = unitStyle == MassFormatter.UnitStyle.short ? "" : " " + + return "\(formattedValue)\(separator)\(unitStringDisplayedAdjacent(toValue: value, unit: unit))" + } + + /// Return the locale-appropriate unit to be shown adjacent to the given + /// value. In most cases this will match `unitStringDisplayedAdjacent(toValue:, unit:)` + /// however there are a few special cases: + /// - Imperial pounds with a short representation use "lb" in the + /// abstract and "#" only when shown with a numeral. + /// - Stones are are singular in the abstract and only plural when + /// shown with a numeral. + /// + /// - Parameter value: The mass's value in the given unit. + /// - Parameter unit: The unit used in the resulting mass string. + /// - Returns: The locale-appropriate unit + open func unitStringDisplayedAdjacent(toValue value: Double, unit: Unit) -> String { + if unit == .pound && unitStyle == .short { + return "#" + } else if unit == .stone && unitStyle == .long { + if value == 1.0 { + return MassFormatter.largeSingularSymbol[unit]! + } else { + return MassFormatter.largePluralSymbol[unit]! + } + } else { + return unitString(fromValue: value, unit: unit) + } + } + + + + /// The number of pounds in 1 stone + private static let poundsPerStone = 14.0 + + /// Maps MassFormatter.Unit enum to UnitMass class. Used for measurement conversion. + private static let unitMass: [Unit: UnitMass] = [.gram: .grams, + .kilogram: .kilograms, + .ounce: .ounces, + .pound: .pounds, + .stone: .stones] + + /// Maps a unit to its short symbol. Reuses strings from UnitMass. + private static let shortSymbol: [Unit: String] = [.gram: UnitMass.grams.symbol, + .kilogram: UnitMass.kilograms.symbol, + .ounce: UnitMass.ounces.symbol, + .pound: UnitMass.pounds.symbol, // see `unitStringDisplayedAdjacent(toValue:, unit:)` + .stone: UnitMass.stones.symbol] + + /// Maps a unit to its medium symbol. Reuses strings from UnitMass. + private static let mediumSymbol: [Unit: String] = [.gram: UnitMass.grams.symbol, + .kilogram: UnitMass.kilograms.symbol, + .ounce: UnitMass.ounces.symbol, + .pound: UnitMass.pounds.symbol, + .stone: UnitMass.stones.symbol] + + /// Maps a unit to its large, singular symbol. + private static let largeSingularSymbol: [Unit: String] = [.gram: "gram", + .kilogram: "kilogram", + .ounce: "ounce", + .pound: "pound", + .stone: "stone"] + + /// Maps a unit to its large, plural symbol. + private static let largePluralSymbol: [Unit: String] = [.gram: "grams", + .kilogram: "kilograms", + .ounce: "ounces", + .pound: "pounds", + .stone: "stones"] } +internal extension Locale { + /// TODO: Replace calls to the below function to use Locale.usesMetricSystem + /// Temporary workaround due to unpopulated Locale attributes + /// See https://bugs.swift.org/browse/SR-3202 + internal func sr3202_fix_isMetricSystemLocale() -> Bool { + switch self.identifier { + case "en_US": return false + case "en_US_POSIX": return false + case "haw_US": return false + case "es_US": return false + case "chr_US": return false + case "my_MM": return false + case "en_LR": return false + case "vai_LR": return false + default: return true + } + } +} diff --git a/TestFoundation/TestMassFormatter.swift b/TestFoundation/TestMassFormatter.swift new file mode 100644 index 0000000000..e465b1e121 --- /dev/null +++ b/TestFoundation/TestMassFormatter.swift @@ -0,0 +1,140 @@ +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See http://swift.org/LICENSE.txt for license information +// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// + +#if DEPLOYMENT_RUNTIME_OBJC || os(Linux) + import Foundation + import XCTest +#else + import SwiftFoundation + import SwiftXCTest +#endif + +class TestMassFormatter: XCTestCase { + let formatter: MassFormatter = MassFormatter() + + static var allTests: [(String, (TestMassFormatter) -> () throws -> Void)] { + return [ + ("test_stringFromKilogramsImperialRegion", test_stringFromKilogramsImperialRegion), + ("test_stringFromKilogramsMetricRegion", test_stringFromKilogramsMetricRegion), + ("test_stringFromKilogramsMetricRegionPersonMassUse", test_stringFromKilogramsMetricRegionPersonMassUse), + ("test_stringFromValue", test_stringFromValue), + ("test_unitStringFromKilograms", test_unitStringFromKilograms), + ("test_unitStringFromValue", test_unitStringFromValue), + ] + } + + override func setUp() { + formatter.numberFormatter.locale = Locale(identifier: "en_US") + formatter.isForPersonMassUse = false + super.setUp() + } + + func test_stringFromKilogramsImperialRegion() { + XCTAssertEqual(formatter.string(fromKilograms: -100), "-220.462 lb") + XCTAssertEqual(formatter.string(fromKilograms: 0.00001), "0 oz") + XCTAssertEqual(formatter.string(fromKilograms: 0.0001), "0.004 oz") + XCTAssertEqual(formatter.string(fromKilograms: 1), "2.205 lb") + XCTAssertEqual(formatter.string(fromKilograms: 100), "220.462 lb") + } + + func test_stringFromKilogramsMetricRegion() { + formatter.numberFormatter.locale = Locale(identifier: "de_DE") + XCTAssertEqual(formatter.string(fromKilograms: -100), "-100 kg") + XCTAssertEqual(formatter.string(fromKilograms: -1), "-1 kg") + XCTAssertEqual(formatter.string(fromKilograms: 1000), "1.000 kg") + } + + func test_stringFromKilogramsMetricRegionPersonMassUse() { + formatter.numberFormatter.locale = Locale(identifier: "en_GB") + formatter.isForPersonMassUse = true + XCTAssertEqual(formatter.string(fromKilograms: -100), "-100 kg") + XCTAssertEqual(formatter.string(fromKilograms: -1), "-1 kg") + XCTAssertEqual(formatter.string(fromKilograms: 1000), "1,000 kg") + } + + func test_stringFromValue() { + formatter.unitStyle = Formatter.UnitStyle.long + XCTAssertEqual(formatter.string(fromValue: 0.002, unit: MassFormatter.Unit.kilogram),"0.002 kilograms") + XCTAssertEqual(formatter.string(fromValue: 0, unit:MassFormatter.Unit.stone), "0 stones") + XCTAssertEqual(formatter.string(fromValue: 1, unit:MassFormatter.Unit.stone), "1 stone") + XCTAssertEqual(formatter.string(fromValue: 2.4, unit: MassFormatter.Unit.stone), "2 stones, 5.6 pounds") + + formatter.unitStyle = Formatter.UnitStyle.short + XCTAssertEqual(formatter.string(fromValue: 0.00000001, unit:MassFormatter.Unit.kilogram), "0kg") + XCTAssertEqual(formatter.string(fromValue: 6, unit:MassFormatter.Unit.pound), "6#") + XCTAssertEqual(formatter.string(fromValue: 2.4, unit: MassFormatter.Unit.stone), "2st 5.6#") + XCTAssertEqual(formatter.string(fromValue: 123456, unit: MassFormatter.Unit.stone), "123,456st") + + formatter.unitStyle = Formatter.UnitStyle.medium + XCTAssertEqual(formatter.string(fromValue: 0.00000001, unit:MassFormatter.Unit.kilogram), "0 kg") + XCTAssertEqual(formatter.string(fromValue: 2.4, unit: MassFormatter.Unit.stone), "2 st, 5.6 lb") + XCTAssertEqual(formatter.string(fromValue: 2.0, unit: MassFormatter.Unit.stone), "2 st") + XCTAssertEqual(formatter.string(fromValue: 123456.78, unit: MassFormatter.Unit.stone), "123,456 st, 10.92 lb") + } + + func test_unitStringFromKilograms() { + var unit = MassFormatter.Unit.kilogram + + // imperial + XCTAssertEqual(formatter.unitString(fromKilograms: -100000, usedUnit: &unit), "lb") + XCTAssertEqual(unit, MassFormatter.Unit.pound) + + XCTAssertEqual(formatter.unitString(fromKilograms: 0, usedUnit: &unit), "lb") + XCTAssertEqual(unit, MassFormatter.Unit.pound) + + XCTAssertEqual(formatter.unitString(fromKilograms: 0.0001, usedUnit: &unit), "oz") + XCTAssertEqual(unit, MassFormatter.Unit.ounce) + + XCTAssertEqual(formatter.unitString(fromKilograms: 0.4535, usedUnit: &unit), "oz") + XCTAssertEqual(unit, MassFormatter.Unit.ounce) + + XCTAssertEqual(formatter.unitString(fromKilograms: 0.4536, usedUnit: &unit), "lb") + XCTAssertEqual(unit, MassFormatter.Unit.pound) + + // metric + formatter.numberFormatter.locale = Locale(identifier: "de_DE") + XCTAssertEqual(formatter.unitString(fromKilograms: -100000, usedUnit: &unit), "kg") + XCTAssertEqual(unit, MassFormatter.Unit.kilogram) + + XCTAssertEqual(formatter.unitString(fromKilograms: 0, usedUnit: &unit), "kg") + XCTAssertEqual(unit, MassFormatter.Unit.kilogram) + + XCTAssertEqual(formatter.unitString(fromKilograms: 0.0001, usedUnit: &unit), "g") + XCTAssertEqual(unit, MassFormatter.Unit.gram) + + XCTAssertEqual(formatter.unitString(fromKilograms: 1.000, usedUnit: &unit), "g") + XCTAssertEqual(unit, MassFormatter.Unit.gram) + + XCTAssertEqual(formatter.unitString(fromKilograms: 1.001, usedUnit: &unit), "kg") + XCTAssertEqual(unit, MassFormatter.Unit.kilogram) + } + + func test_unitStringFromValue() { + formatter.unitStyle = Formatter.UnitStyle.long + XCTAssertEqual(formatter.unitString(fromValue: 0.002, unit: MassFormatter.Unit.kilogram), "kilograms") + XCTAssertEqual(formatter.unitString(fromValue: 0.100, unit: MassFormatter.Unit.gram), "grams") + XCTAssertEqual(formatter.unitString(fromValue: 2.000, unit: MassFormatter.Unit.pound), "pounds") + XCTAssertEqual(formatter.unitString(fromValue: 2.002, unit: MassFormatter.Unit.ounce), "ounces") + XCTAssertEqual(formatter.unitString(fromValue: 2.002, unit: MassFormatter.Unit.stone), "stone") + + formatter.unitStyle = Formatter.UnitStyle.medium + XCTAssertEqual(formatter.unitString(fromValue: 0.002, unit: MassFormatter.Unit.kilogram), "kg") + XCTAssertEqual(formatter.unitString(fromValue: 0.100, unit: MassFormatter.Unit.gram), "g") + XCTAssertEqual(formatter.unitString(fromValue: 2.000, unit: MassFormatter.Unit.pound), "lb") + XCTAssertEqual(formatter.unitString(fromValue: 2.002, unit: MassFormatter.Unit.ounce), "oz") + XCTAssertEqual(formatter.unitString(fromValue: 2.002, unit: MassFormatter.Unit.stone), "st") + + formatter.unitStyle = Formatter.UnitStyle.short + XCTAssertEqual(formatter.unitString(fromValue: 0.002, unit: MassFormatter.Unit.kilogram), "kg") + XCTAssertEqual(formatter.unitString(fromValue: 0.100, unit: MassFormatter.Unit.gram), "g") + XCTAssertEqual(formatter.unitString(fromValue: 2.000, unit: MassFormatter.Unit.pound), "lb") + XCTAssertEqual(formatter.unitString(fromValue: 2.002, unit: MassFormatter.Unit.ounce), "oz") + XCTAssertEqual(formatter.unitString(fromValue: 2.002, unit: MassFormatter.Unit.stone), "st") + } +} diff --git a/TestFoundation/main.swift b/TestFoundation/main.swift index 5b832cbc3d..3aebdc5018 100644 --- a/TestFoundation/main.swift +++ b/TestFoundation/main.swift @@ -96,4 +96,5 @@ XCTMain([ testCase(TestObjCRuntime.allTests), testCase(TestNotification.allTests), testCase(TestNSISO8601DateFormatter.allTests), + testCase(TestMassFormatter.allTests), ])