2026-07-05 15:45:09 +02:00
|
|
|
import Foundation
|
|
|
|
|
import Notifying
|
|
|
|
|
import Recording
|
|
|
|
|
import Testing
|
|
|
|
|
|
|
|
|
|
@testable import Attendi
|
|
|
|
|
|
|
|
|
|
@Suite("Content view model")
|
|
|
|
|
struct ContentViewModelTests {
|
|
|
|
|
|
|
|
|
|
typealias Model = ContentView.Model
|
|
|
|
|
|
|
|
|
|
// MARK: Load
|
|
|
|
|
|
|
|
|
|
@MainActor
|
|
|
|
|
@Suite("Load")
|
|
|
|
|
struct Load {
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
func `load fills the supported locales and aligns the picked locale`() async {
|
|
|
|
|
let preinstaller = PreinstallingMock()
|
|
|
|
|
|
|
|
|
|
preinstaller.localesSupported = [.dutch, .english]
|
|
|
|
|
preinstaller.equivalents = [.current: .english]
|
|
|
|
|
|
|
|
|
|
let model = Model(preinstaller: preinstaller)
|
|
|
|
|
|
2026-07-05 21:04:29 +02:00
|
|
|
await model.load(identifier: "")
|
2026-07-05 15:45:09 +02:00
|
|
|
|
|
|
|
|
#expect(model.locale == .english)
|
|
|
|
|
#expect(model.locales.count == 2)
|
|
|
|
|
#expect(model.locales.contains(.dutch))
|
|
|
|
|
#expect(model.locales.contains(.english))
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-05 21:04:29 +02:00
|
|
|
@Test
|
|
|
|
|
func `load restores the persisted locale`() async {
|
|
|
|
|
let preinstaller = PreinstallingMock()
|
|
|
|
|
|
|
|
|
|
preinstaller.localesSupported = [.dutch, .english]
|
|
|
|
|
preinstaller.equivalents = [.dutch: .dutch]
|
|
|
|
|
|
|
|
|
|
let model = Model(preinstaller: preinstaller)
|
|
|
|
|
|
|
|
|
|
await model.load(identifier: Locale.dutch.identifier)
|
|
|
|
|
|
|
|
|
|
#expect(model.locale == .dutch)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
func `load falls back to the default locale when the persisted locale is unsupported`() async {
|
|
|
|
|
let preinstaller = PreinstallingMock()
|
|
|
|
|
|
|
|
|
|
preinstaller.localesSupported = [.dutch, .english]
|
|
|
|
|
preinstaller.equivalents = [.byDefault: .english]
|
|
|
|
|
|
|
|
|
|
let model = Model(preinstaller: preinstaller)
|
|
|
|
|
|
|
|
|
|
await model.load(identifier: "fr-FR")
|
|
|
|
|
|
|
|
|
|
#expect(model.locale == .english)
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-05 15:45:09 +02:00
|
|
|
@Test
|
|
|
|
|
func `load preinstalls the aligned locale`() async throws {
|
|
|
|
|
let preinstaller = PreinstallingMock()
|
|
|
|
|
|
|
|
|
|
preinstaller.localesSupported = [.dutch, .english]
|
|
|
|
|
preinstaller.equivalents = [.current: .english]
|
|
|
|
|
|
|
|
|
|
let model = Model(preinstaller: preinstaller)
|
|
|
|
|
|
2026-07-05 21:04:29 +02:00
|
|
|
await model.load(identifier: "")
|
2026-07-05 15:45:09 +02:00
|
|
|
|
|
|
|
|
try await Task.sleep(for: .seconds(0.1))
|
|
|
|
|
|
|
|
|
|
#expect(preinstaller.localesPreinstalled == [.english])
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// MARK: Preinstall
|
|
|
|
|
|
|
|
|
|
@MainActor
|
|
|
|
|
@Suite("Preinstall")
|
|
|
|
|
struct Preinstall {
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
func `preinstalling the same locale twice runs once`() async throws {
|
|
|
|
|
let preinstaller = PreinstallingMock()
|
|
|
|
|
let model = Model(preinstaller: preinstaller)
|
|
|
|
|
|
|
|
|
|
model.locale = .dutch
|
|
|
|
|
|
|
|
|
|
model.preinstall()
|
|
|
|
|
model.preinstall()
|
|
|
|
|
|
|
|
|
|
try await Task.sleep(for: .seconds(0.1))
|
|
|
|
|
|
|
|
|
|
#expect(preinstaller.localesPreinstalled == [.dutch])
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
func `preinstalling a newly picked locale runs again`() async throws {
|
|
|
|
|
let preinstaller = PreinstallingMock()
|
|
|
|
|
let model = Model(preinstaller: preinstaller)
|
|
|
|
|
|
|
|
|
|
model.locale = .dutch
|
|
|
|
|
model.preinstall()
|
|
|
|
|
|
|
|
|
|
model.locale = .english
|
|
|
|
|
model.preinstall()
|
|
|
|
|
|
|
|
|
|
try await Task.sleep(for: .seconds(0.1))
|
|
|
|
|
|
|
|
|
|
#expect(preinstaller.localesPreinstalled == [.dutch, .english])
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// MARK: Events
|
|
|
|
|
|
|
|
|
|
@MainActor
|
|
|
|
|
@Suite("Events")
|
|
|
|
|
struct Events {
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
func `a started event posts an info notification`() async throws {
|
|
|
|
|
let preinstaller = PreinstallingMock()
|
|
|
|
|
let model = Model(preinstaller: preinstaller)
|
|
|
|
|
|
|
|
|
|
model.locale = .dutch
|
|
|
|
|
model.preinstall()
|
|
|
|
|
|
|
|
|
|
try await Task.sleep(for: .seconds(0.1))
|
|
|
|
|
|
|
|
|
|
preinstaller.emit(.started(.dutch))
|
|
|
|
|
|
|
|
|
|
try await Task.sleep(for: .seconds(0.1))
|
|
|
|
|
|
|
|
|
|
#expect(model.notifier.notifications.count == 1)
|
|
|
|
|
#expect(model.notifier.notifications.first?.kind == .info)
|
|
|
|
|
#expect(model.notifier.notifications.first?.symbol == "arrow.down.circle")
|
|
|
|
|
#expect(model.notifier.notifications.first?.message == String(localized: .viewRecordingNotificationDownloadStarted(model.name(for: .dutch))))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
func `a cancelled event posts a warning notification`() async throws {
|
|
|
|
|
let preinstaller = PreinstallingMock()
|
|
|
|
|
let model = Model(preinstaller: preinstaller)
|
|
|
|
|
|
|
|
|
|
model.locale = .dutch
|
|
|
|
|
model.preinstall()
|
|
|
|
|
|
|
|
|
|
try await Task.sleep(for: .seconds(0.1))
|
|
|
|
|
|
|
|
|
|
preinstaller.emit(.cancelled(.dutch))
|
|
|
|
|
|
|
|
|
|
try await Task.sleep(for: .seconds(0.1))
|
|
|
|
|
|
|
|
|
|
#expect(model.notifier.notifications.first?.kind == .warning)
|
|
|
|
|
#expect(model.notifier.notifications.first?.symbol == "xmark.circle")
|
|
|
|
|
#expect(model.notifier.notifications.first?.message == String(localized: .viewRecordingNotificationDownloadCancelled(model.name(for: .dutch))))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
func `a failed event posts an error notification`() async throws {
|
|
|
|
|
let preinstaller = PreinstallingMock()
|
|
|
|
|
let model = Model(preinstaller: preinstaller)
|
|
|
|
|
|
|
|
|
|
model.locale = .dutch
|
|
|
|
|
model.preinstall()
|
|
|
|
|
|
|
|
|
|
try await Task.sleep(for: .seconds(0.1))
|
|
|
|
|
|
|
|
|
|
preinstaller.emit(.failed(.dutch))
|
|
|
|
|
|
|
|
|
|
try await Task.sleep(for: .seconds(0.1))
|
|
|
|
|
|
|
|
|
|
#expect(model.notifier.notifications.first?.kind == .error)
|
|
|
|
|
#expect(model.notifier.notifications.first?.symbol == "exclamationmark.triangle")
|
|
|
|
|
#expect(model.notifier.notifications.first?.message == String(localized: .viewRecordingNotificationDownloadFailed(model.name(for: .dutch))))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
func `a cancellation of the current locale lets a re-pick retry`() async throws {
|
|
|
|
|
let preinstaller = PreinstallingMock()
|
|
|
|
|
let model = Model(preinstaller: preinstaller)
|
|
|
|
|
|
|
|
|
|
model.locale = .dutch
|
|
|
|
|
model.preinstall()
|
|
|
|
|
|
|
|
|
|
try await Task.sleep(for: .seconds(0.1))
|
|
|
|
|
|
|
|
|
|
preinstaller.emit(.cancelled(.dutch))
|
|
|
|
|
|
|
|
|
|
try await Task.sleep(for: .seconds(0.1))
|
|
|
|
|
|
|
|
|
|
model.preinstall()
|
|
|
|
|
|
|
|
|
|
try await Task.sleep(for: .seconds(0.1))
|
|
|
|
|
|
|
|
|
|
#expect(preinstaller.localesPreinstalled == [.dutch, .dutch])
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
func `a cancellation of another locale keeps the current preinstallation`() async throws {
|
|
|
|
|
let preinstaller = PreinstallingMock()
|
|
|
|
|
let model = Model(preinstaller: preinstaller)
|
|
|
|
|
|
|
|
|
|
model.locale = .english
|
|
|
|
|
model.preinstall()
|
|
|
|
|
|
|
|
|
|
try await Task.sleep(for: .seconds(0.1))
|
|
|
|
|
|
|
|
|
|
preinstaller.emit(.cancelled(.dutch))
|
|
|
|
|
|
|
|
|
|
try await Task.sleep(for: .seconds(0.1))
|
|
|
|
|
|
|
|
|
|
model.preinstall()
|
|
|
|
|
|
|
|
|
|
try await Task.sleep(for: .seconds(0.1))
|
|
|
|
|
|
|
|
|
|
#expect(preinstaller.localesPreinstalled == [.english])
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// MARK: - Constants
|
|
|
|
|
|
|
|
|
|
private extension Locale {
|
2026-07-05 21:04:29 +02:00
|
|
|
/// The locale the model falls back to when no equivalent of the current locale is supported.
|
|
|
|
|
static let byDefault = Locale(identifier: "en_US")
|
2026-07-05 15:45:09 +02:00
|
|
|
/// A supported locale to preinstall in the tests.
|
|
|
|
|
static let dutch = Locale(identifier: "nl-NL")
|
|
|
|
|
/// Another supported locale to preinstall in the tests.
|
|
|
|
|
static let english = Locale(identifier: "en-US")
|
|
|
|
|
}
|