Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
//
// EnvironmentConfigurableFormatter.swift
// OpenSwiftUICore
//
// Audited for 6.5.4
// Status: Complete

public import Foundation

// MARK: - EnvironmentConfigurableFormatter

/// A formatter that can apply text-related environment values before use.
///
/// OpenSwiftUI calls this hook for Foundation formatters whose output depends
Comment thread
Kyle-Ye marked this conversation as resolved.
/// on environment-provided formatting state, such as locale, calendar, or time
/// zone. Conforming formatters update only the environment-dependent properties
/// they support.
///
/// - Note: Some Foundation formatter types are only available on Apple
/// platforms.
protocol EnvironmentConfigurableFormatter: AnyObject {
/// Updates the formatter with values from the current environment.
///
/// - Parameter environment: The environment values that should influence
/// the formatter's output.
func configure(in environment: EnvironmentValues)
}

// MARK: - DateFormatter + EnvironmentConfigurableFormatter

extension DateFormatter: EnvironmentConfigurableFormatter {
func configure(in environment: EnvironmentValues) {
locale = environment.locale
calendar = environment.calendar
timeZone = environment.timeZone
}
}

// MARK: - ISO8601DateFormatter + EnvironmentConfigurableFormatter

extension ISO8601DateFormatter: EnvironmentConfigurableFormatter {
func configure(in environment: EnvironmentValues) {
timeZone = environment.timeZone
}
}

// MARK: - DateComponentsFormatter + EnvironmentConfigurableFormatter

#if canImport(Darwin)
extension DateComponentsFormatter: EnvironmentConfigurableFormatter {
func configure(in environment: EnvironmentValues) {
calendar = environment.calendar
}
}
#endif

// MARK: - DateIntervalFormatter + EnvironmentConfigurableFormatter

extension DateIntervalFormatter: EnvironmentConfigurableFormatter {
func configure(in environment: EnvironmentValues) {
calendar = environment.calendar
locale = environment.locale
timeZone = environment.timeZone
}
}

// MARK: - NumberFormatter + EnvironmentConfigurableFormatter

extension NumberFormatter: EnvironmentConfigurableFormatter {
func configure(in environment: EnvironmentValues) {
locale = environment.locale
}
}

// MARK: - MeasurementFormatter + EnvironmentConfigurableFormatter

#if canImport(Darwin)
extension MeasurementFormatter: EnvironmentConfigurableFormatter {
func configure(in environment: EnvironmentValues) {
locale = environment.locale
numberFormatter.locale = environment.locale
}
}
#endif

// MARK: - MassFormatter + EnvironmentConfigurableFormatter

extension MassFormatter: EnvironmentConfigurableFormatter {
func configure(in environment: EnvironmentValues) {
numberFormatter.locale = environment.locale
}
}

// MARK: - LengthFormatter + EnvironmentConfigurableFormatter

extension LengthFormatter: EnvironmentConfigurableFormatter {
func configure(in environment: EnvironmentValues) {
numberFormatter.locale = environment.locale
}
}

// MARK: - EnergyFormatter + EnvironmentConfigurableFormatter

extension EnergyFormatter: EnvironmentConfigurableFormatter {
func configure(in environment: EnvironmentValues) {
numberFormatter.locale = environment.locale
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
//
// EnvironmentConfigurableFormatterTests.swift
// OpenSwiftUICoreTests

import Foundation
@testable import OpenSwiftUICore
import Testing

struct EnvironmentConfigurableFormatterTests {
@Test
func dateFormatterConfigureAppliesEnvironmentValues() {
let env = makeEnvironmentValues()

let formatter = DateFormatter()
formatter.configure(in: env)
#expect(formatter.locale == env.locale)
#expect(formatter.calendar == env.calendar)
#expect(formatter.timeZone == env.timeZone)
}

@Test
func iso8601DateFormatterConfigureAppliesEnvironmentValues() {
let env = makeEnvironmentValues()

let formatter = ISO8601DateFormatter()
formatter.configure(in: env)
#expect(formatter.timeZone == env.timeZone)
}

#if canImport(Darwin)
@Test
func dateComponentsFormatterConfigureAppliesEnvironmentValues() {
let env = makeEnvironmentValues()

let formatter = DateComponentsFormatter()
formatter.configure(in: env)
#expect(formatter.calendar == env.calendar)
}
#endif

@Test
func dateIntervalFormatterConfigureAppliesEnvironmentValues() {
let env = makeEnvironmentValues()

let formatter = DateIntervalFormatter()
formatter.configure(in: env)
#expect(formatter.calendar == env.calendar)
#expect(formatter.locale == env.locale)
#expect(formatter.timeZone == env.timeZone)
}

@Test
func numberFormatterConfigureAppliesEnvironmentValues() {
let env = makeEnvironmentValues()

let formatter = NumberFormatter()
formatter.configure(in: env)
#expect(formatter.locale == env.locale)
}

#if canImport(Darwin)
@Test
func measurementFormatterConfigureAppliesEnvironmentValues() {
let env = makeEnvironmentValues()

let formatter = MeasurementFormatter()
formatter.configure(in: env)
#expect(formatter.locale == env.locale)
#expect(formatter.numberFormatter.locale == env.locale)
}
#endif

@Test
func massFormatterConfigureAppliesEnvironmentValues() {
let env = makeEnvironmentValues()

let formatter = MassFormatter()
formatter.configure(in: env)
#expect(formatter.numberFormatter.locale == env.locale)
}

@Test
func lengthFormatterConfigureAppliesEnvironmentValues() {
let env = makeEnvironmentValues()

let formatter = LengthFormatter()
formatter.configure(in: env)
#expect(formatter.numberFormatter.locale == env.locale)
}

@Test
func energyFormatterConfigureAppliesEnvironmentValues() {
let env = makeEnvironmentValues()

let formatter = EnergyFormatter()
formatter.configure(in: env)
#expect(formatter.numberFormatter.locale == env.locale)
}

private func makeEnvironmentValues() -> EnvironmentValues {
let locale = Locale(identifier: "fr_FR")
var calendar = Calendar(identifier: .buddhist)
calendar.timeZone = TimeZone(secondsFromGMT: 9 * 3600)!
let timeZone = TimeZone(secondsFromGMT: 5 * 3600)!

var environment = EnvironmentValues()
environment.locale = locale
environment.calendar = calendar
environment.timeZone = timeZone
return environment
}
}
Loading