Skip to content

Commit 4408237

Browse files
authored
Merge pull request #83 from rryam/facade-tests
Add facade request configuration tests
2 parents 777d915 + 7c8c13e commit 4408237

File tree

8 files changed

+262
-25
lines changed

8 files changed

+262
-25
lines changed

Sources/MusadoraKit/History/MHistory+RecentlyPlayed.swift

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,14 @@ public extension MHistory {
1212
static func recentlyPlayed(limit: Int? = nil) async throws -> MusicItemCollection<
1313
RecentlyPlayedMusicItem
1414
> {
15-
var request = MusicRecentlyPlayedContainerRequest()
16-
request.limit = limit
15+
let request = recentlyPlayedContainerRequest(limit: limit)
1716
let response = try await request.response()
1817
return try await response.items.collectingAll(upTo: limit)
1918
}
2019

2120
@available(iOS 16.0, macOS 13.0, tvOS 16.0, watchOS 9.0, *)
2221
static func recentlyPlayedSongs(limit: Int? = nil) async throws -> Songs {
23-
var request = MusicRecentlyPlayedRequest<Song>()
24-
request.limit = limit
22+
let request = recentlyPlayedSongsRequest(limit: limit)
2523
let response = try await request.response()
2624
return response.items
2725
}
@@ -43,11 +41,34 @@ public extension MHistory {
4341
/// ```
4442
@available(iOS 16.0, tvOS 16.0, watchOS 9.0, *, macOS 14.0, macCatalyst 17.0, *)
4543
static func mostPlayedSongs(limit: Int = 100) async throws -> Songs {
44+
let request = mostPlayedSongsRequest(limit: limit)
45+
let response = try await request.response()
46+
return try await response.items.collectingAll(upTo: limit)
47+
}
48+
}
49+
50+
@available(iOS 16.0, macOS 13.0, tvOS 16.0, watchOS 9.0, *)
51+
extension MHistory {
52+
internal static func recentlyPlayedContainerRequest(limit: Int?) -> MusicRecentlyPlayedContainerRequest {
53+
var request = MusicRecentlyPlayedContainerRequest()
54+
request.limit = limit
55+
return request
56+
}
57+
58+
internal static func recentlyPlayedSongsRequest(limit: Int?) -> MusicRecentlyPlayedRequest<Song> {
59+
var request = MusicRecentlyPlayedRequest<Song>()
60+
request.limit = limit
61+
return request
62+
}
63+
}
64+
65+
@available(iOS 16.0, tvOS 16.0, watchOS 9.0, *, macOS 14.0, macCatalyst 17.0, *)
66+
extension MHistory {
67+
internal static func mostPlayedSongsRequest(limit: Int) -> MusicLibraryRequest<Song> {
4668
var request = MusicLibraryRequest<Song>()
4769
request.limit = limit
4870
request.sort(by: \.playCount, ascending: false)
49-
let response = try await request.response()
50-
return try await response.items.collectingAll(upTo: limit)
71+
return request
5172
}
5273
}
5374

Sources/MusadoraKit/MusadoraKit.swift

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -58,12 +58,7 @@ extension MusadoraKit {
5858
/// }
5959
/// ```
6060
public static func test() async throws {
61-
var components = AppleMusicURLComponents()
62-
components.path = "test"
63-
64-
guard let url = components.url else {
65-
throw URLError(.badURL)
66-
}
61+
let url = try testEndpointURL()
6762

6863
let urlRequest = URLRequest(url: url)
6964
let request = MusicDataRequest(urlRequest: urlRequest)
@@ -89,4 +84,15 @@ extension MusadoraKit {
8984
throw error
9085
}
9186
}
87+
88+
internal static func testEndpointURL(components: MusicURLComponents = AppleMusicURLComponents()) throws -> URL {
89+
var components = components
90+
components.path = "test"
91+
92+
guard let url = components.url else {
93+
throw URLError(.badURL)
94+
}
95+
96+
return url
97+
}
9298
}

Sources/MusadoraKit/MusicSummaries/MSummary+Replay.swift

Lines changed: 87 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,13 @@ public extension MSummary {
2424
include: [String]? = nil,
2525
extend: [String]? = nil
2626
) async throws -> MusicSummaryResponse {
27-
try await response(for: .latestYear, views: views, languageTag: languageTag, include: include, extend: extend)
27+
let request = requestForLatest(
28+
views: views,
29+
languageTag: languageTag,
30+
include: include,
31+
extend: extend
32+
)
33+
return try await request.response()
2834
}
2935

3036
/// Fetch the user's latest monthly Replay summary (previous calendar month).
@@ -45,17 +51,15 @@ public extension MSummary {
4551
now: Date = .now,
4652
timeZone: TimeZone = TimeZone(secondsFromGMT: 0) ?? .current
4753
) async throws -> MusicSummaryResponse {
48-
guard let period = MusicSummaryPeriod.latestMonth(calendar: calendar, now: now, timeZone: timeZone) else {
49-
throw MusadoraKitError.invalidSummaryPeriod
50-
}
51-
52-
return try await response(
53-
for: period,
54+
let context = LatestMonthContext(calendar: calendar, now: now, timeZone: timeZone)
55+
let request = try requestForLatestMonth(
5456
views: views,
5557
languageTag: languageTag,
5658
include: include,
57-
extend: extend
59+
extend: extend,
60+
context: context
5861
)
62+
return try await request.response()
5963
}
6064

6165
/// Fetch the user's latest Replay top artists for the most recent eligible year.
@@ -161,20 +165,92 @@ public extension MSummary {
161165
}
162166
}
163167

164-
private extension MSummary {
165-
static func response(
168+
extension MSummary {
169+
internal struct LatestMonthContext {
170+
let calendar: Calendar
171+
let now: Date
172+
let timeZone: TimeZone
173+
174+
init(
175+
calendar: Calendar = .init(identifier: .gregorian),
176+
now: Date = .now,
177+
timeZone: TimeZone = TimeZone(secondsFromGMT: 0) ?? .current
178+
) {
179+
self.calendar = calendar
180+
self.now = now
181+
self.timeZone = timeZone
182+
}
183+
}
184+
185+
internal static func requestForLatest(
186+
views: Set<MusicSummaryView>,
187+
languageTag: String?,
188+
include: [String]?,
189+
extend: [String]?
190+
) -> MusicSummaryRequest {
191+
makeRequest(
192+
period: .latestYear,
193+
views: views,
194+
languageTag: languageTag,
195+
include: include,
196+
extend: extend
197+
)
198+
}
199+
200+
internal static func requestForLatestMonth(
201+
views: Set<MusicSummaryView>,
202+
languageTag: String?,
203+
include: [String]?,
204+
extend: [String]?,
205+
context: LatestMonthContext
206+
) throws -> MusicSummaryRequest {
207+
guard let period = MusicSummaryPeriod.latestMonth(
208+
calendar: context.calendar,
209+
now: context.now,
210+
timeZone: context.timeZone
211+
) else {
212+
throw MusadoraKitError.invalidSummaryPeriod
213+
}
214+
215+
return makeRequest(
216+
period: period,
217+
views: views,
218+
languageTag: languageTag,
219+
include: include,
220+
extend: extend
221+
)
222+
}
223+
224+
private static func response(
166225
for period: MusicSummaryPeriod,
167226
views: Set<MusicSummaryView>,
168227
languageTag: String?,
169228
include: [String]? = nil,
170229
extend: [String]? = nil
171230
) async throws -> MusicSummaryResponse {
231+
let request = makeRequest(
232+
period: period,
233+
views: views,
234+
languageTag: languageTag,
235+
include: include,
236+
extend: extend
237+
)
238+
return try await request.response()
239+
}
240+
241+
internal static func makeRequest(
242+
period: MusicSummaryPeriod,
243+
views: Set<MusicSummaryView>,
244+
languageTag: String?,
245+
include: [String]? = nil,
246+
extend: [String]? = nil
247+
) -> MusicSummaryRequest {
172248
var request = MusicSummaryRequest()
173249
request.period = period
174250
request.views = views
175251
request.languageTag = languageTag
176252
request.include = include
177253
request.extend = extend
178-
return try await request.response()
254+
return request
179255
}
180256
}

Sources/MusadoraKit/Recommendations/MRecommendation+personal.swift

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,9 +92,14 @@ public extension MRecommendation {
9292
@available(iOS 16.0, macOS 13.0, tvOS 16.0, watchOS 9.0, visionOS 1.0, *)
9393
extension MRecommendation {
9494
private static func personalRecommendations(_ limit: Int? = nil) async throws -> PersonalRecommendations {
95-
var request = MusicPersonalRecommendationsRequest()
96-
request.limit = limit
95+
let request = personalRecommendationsRequest(limit: limit)
9796
let response = try await request.response()
9897
return try await response.recommendations.collectingAll(upTo: limit)
9998
}
99+
100+
internal static func personalRecommendationsRequest(limit: Int?) -> MusicPersonalRecommendationsRequest {
101+
var request = MusicPersonalRecommendationsRequest()
102+
request.limit = limit
103+
return request
104+
}
100105
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
@testable import MusadoraKit
2+
import MusicKit
3+
import Testing
4+
5+
@Suite
6+
struct MHistoryRecentlyPlayedRequestTests {
7+
@available(iOS 16.0, macOS 13.0, tvOS 16.0, watchOS 9.0, *)
8+
@Test
9+
func recentlyPlayedContainerRequestSetsLimit() {
10+
let request = MHistory.recentlyPlayedContainerRequest(limit: 25)
11+
#expect(request.limit == 25)
12+
}
13+
14+
@available(iOS 16.0, macOS 13.0, tvOS 16.0, watchOS 9.0, *)
15+
@Test
16+
func recentlyPlayedSongsRequestSetsLimit() {
17+
let request = MHistory.recentlyPlayedSongsRequest(limit: 10)
18+
#expect(request.limit == 10)
19+
}
20+
21+
@available(iOS 16.0, tvOS 16.0, watchOS 9.0, macOS 14.0, macCatalyst 17.0, *)
22+
@Test
23+
func mostPlayedSongsRequestSetsLimit() {
24+
let request = MHistory.mostPlayedSongsRequest(limit: 100)
25+
#expect(request.limit == 100)
26+
}
27+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import Foundation
2+
@testable import MusadoraKit
3+
import Testing
4+
5+
private struct BadURLMusicComponents: MusicURLComponents {
6+
var queryItems: [URLQueryItem]?
7+
var path: String = ""
8+
9+
var url: URL? {
10+
nil
11+
}
12+
}
13+
14+
@Suite
15+
struct MusadoraKitTestEndpointTests {
16+
@Test
17+
func testEndpointURLBuilds() throws {
18+
let url = try MusadoraKit.testEndpointURL()
19+
expectEndpoint(url, equals: "https://api.music.apple.com/v1/test")
20+
}
21+
22+
@Test
23+
func testEndpointURLWithBadComponentsThrows() throws {
24+
let error = #expect(throws: URLError.self) {
25+
try MusadoraKit.testEndpointURL(components: BadURLMusicComponents())
26+
}
27+
28+
#expect(error == URLError(.badURL))
29+
}
30+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
@testable import MusadoraKit
2+
import MusicKit
3+
import Testing
4+
5+
@Suite
6+
struct MRecommendationPersonalTests {
7+
@Test
8+
func personalRecommendationsRequestSetsLimit() {
9+
let request = MRecommendation.personalRecommendationsRequest(limit: 12)
10+
#expect(request.limit == 12)
11+
}
12+
13+
@Test
14+
func personalRecommendationsRequestAllowsNilLimit() {
15+
let request = MRecommendation.personalRecommendationsRequest(limit: nil)
16+
#expect(request.limit == nil)
17+
}
18+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import Foundation
2+
@testable import MusadoraKit
3+
import Testing
4+
5+
@Suite
6+
struct MSummaryFacadeTests {
7+
@Test
8+
func latestRequestUsesDefaults() throws {
9+
let request = MSummary.requestForLatest(
10+
views: [.topAlbums, .topArtists, .topSongs],
11+
languageTag: nil,
12+
include: nil,
13+
extend: nil
14+
)
15+
16+
#expect(request.period == .latestYear)
17+
#expect(request.views == [.topAlbums, .topArtists, .topSongs])
18+
#expect(request.languageTag == nil)
19+
#expect(request.include == nil)
20+
#expect(request.extend == nil)
21+
}
22+
23+
@Test
24+
func latestMonthRequestBuildsExpectedPeriod() throws {
25+
let calendar = Calendar(identifier: .gregorian)
26+
let timeZone = TimeZone(secondsFromGMT: 0) ?? .current
27+
var components = DateComponents()
28+
components.calendar = calendar
29+
components.timeZone = timeZone
30+
components.year = 2025
31+
components.month = 2
32+
components.day = 15
33+
let now = try #require(components.date)
34+
35+
let context = MSummary.LatestMonthContext(
36+
calendar: calendar,
37+
now: now,
38+
timeZone: timeZone
39+
)
40+
let request = try MSummary.requestForLatestMonth(
41+
views: [.topSongs],
42+
languageTag: "en-US",
43+
include: ["relationships"],
44+
extend: ["extended-attributes"],
45+
context: context
46+
)
47+
48+
#expect(request.period == .month(year: 2025, month: 1))
49+
#expect(request.views == [.topSongs])
50+
#expect(request.languageTag == "en-US")
51+
#expect(request.include == ["relationships"])
52+
#expect(request.extend == ["extended-attributes"])
53+
}
54+
}

0 commit comments

Comments
 (0)