import Foundation @testable import BearWaveCore try checkRadioBrowserDecoding() checkPercentEncoding() checkNormalizedSearch() await checkStationLibrary() print("BearWave checks passed") private func checkRadioBrowserDecoding() throws { let url = Bundle.module.url(forResource: "stations", withExtension: "json")! let stations = try RadioBrowserClient.decodeStations(from: Data(contentsOf: url)) expect(stations.count == 2, "decode should filter invalid stations") expect(stations[0].id == "alpha", "station id should prefer UUID") expect(stations[0].playbackURLString == "https://example.test/alpha-resolved", "resolved URL should be playback URL") expect(stations[1].bitrate == 96, "bitrate should decode from string") expect(stations[1].votes == 50, "votes should decode from string") } private func checkPercentEncoding() { expect(RadioBrowserClient.percentEncodePathComponent("classic rock") == "classic%20rock", "path values should be percent encoded") } private func checkNormalizedSearch() { expect(RadioBrowserClient.normalizedSearchText("SLAM!") == "slam", "normalization should ignore punctuation") expect(RadioBrowserClient.normalizedSearchText("SLÁM Radio") == "slamradio", "normalization should fold accents and separators") expect(RadioBrowserClient.normalizedSearchTokens("Radio Islamabad").contains("slam") == false, "tokens should not match inside another word") expect(RadioBrowserClient.normalizedSearchTokens("SLAM! Radio").contains("slam"), "tokens should match punctuation-separated station names") } @MainActor private func checkStationLibrary() { let library = makeLibrary() let favorite = RadioStation(uuid: "one", name: "One", resolvedURL: "https://example.test/one") library.toggleFavorite(favorite) library.toggleFavorite(favorite) expect(library.favorites.isEmpty, "favorites should deduplicate by UUID") for index in 0..<25 { library.recordPlayback(RadioStation(uuid: "\(index)", name: "Station \(index)", resolvedURL: "https://example.test/\(index)")) } library.recordPlayback(RadioStation(uuid: "24", name: "Station 24", resolvedURL: "https://example.test/24")) expect(library.recentStations.count == 20, "recent stations should be limited to 20") expect(library.recentStations.first?.uuid == "24", "recent stations should move duplicates to the front") expect(Set(library.recentStations.map(\.uuid)).count == 20, "recent stations should stay unique") library.stations = [ RadioStation(name: "Zoo News", resolvedURL: "https://example.test/zoo", tags: "news", bitrate: 96, votes: 3), RadioStation(name: "Alpha Rock", resolvedURL: "https://example.test/alpha", tags: "rock", bitrate: 192, votes: 1) ] library.filterQuery = "rock" expect(library.visibleStations.map(\.name) == ["Alpha Rock"], "filter should match tags") library.filterQuery = "" library.sortMode = .bitrate expect(library.visibleStations.map(\.name) == ["Alpha Rock", "Zoo News"], "bitrate sort should be descending") } @MainActor private func makeLibrary() -> StationLibrary { let root = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString) let persistence = PersistenceStore( applicationSupportDirectory: root.appendingPathComponent("ApplicationSupport"), cacheDirectory: root.appendingPathComponent("Caches"), linuxConfigDirectory: root.appendingPathComponent("Linux") ) let client = RadioBrowserClient(cacheDirectory: persistence.apiCacheDirectory, session: MockSession()) return StationLibrary(client: client, persistence: persistence) } private func expect(_ condition: @autoclosure () -> Bool, _ message: String) { if !condition() { fatalError(message) } } struct MockSession: URLSessionProtocol { func data(for request: URLRequest) async throws -> (Data, URLResponse) { let data = "[]".data(using: .utf8)! let response = HTTPURLResponse(url: request.url!, statusCode: 200, httpVersion: nil, headerFields: nil)! return (data, response) } }