diff --git a/Modules/Sources/WordPressKit/PluginDirectoryServiceRemote.swift b/Modules/Sources/WordPressKit/PluginDirectoryServiceRemote.swift index abc04b82b3a0..133ebe8cf38f 100644 --- a/Modules/Sources/WordPressKit/PluginDirectoryServiceRemote.swift +++ b/Modules/Sources/WordPressKit/PluginDirectoryServiceRemote.swift @@ -4,7 +4,7 @@ private struct PluginDirectoryRemoteConstants { static let dateFormatter: DateFormatter = { let formatter = DateFormatter() formatter.locale = Locale(identifier: "en_US_POSIX") - formatter.dateFormat = "YYYY-MM-dd h:mma z" + formatter.dateFormat = "yyyy-MM-dd h:mma z" return formatter }() diff --git a/Tests/KeystoneTests/Tests/Features/Misc/PluginDirectoryEntryLookupTests.swift b/Tests/KeystoneTests/Tests/Features/Misc/PluginDirectoryEntryLookupTests.swift new file mode 100644 index 000000000000..75ba98e3d42c --- /dev/null +++ b/Tests/KeystoneTests/Tests/Features/Misc/PluginDirectoryEntryLookupTests.swift @@ -0,0 +1,93 @@ +import Testing +import WordPressKit +@testable import WordPress + +struct PluginDirectoryEntryLookupTests { + + /// The directory entries dictionary in PluginStoreState is keyed by slug. + /// PluginViewModel must use `plugin.state.slug` (not `plugin.id`) to look + /// up entries, because `id` and `slug` are different values. + /// + /// Example: id = "jetpack/jetpack.php", slug = "jetpack" + @Test + func pluginIdDiffersFromSlug() { + let state = PluginState( + id: "jetpack/jetpack.php", + slug: "jetpack", + active: true, + name: "Jetpack", + author: "Automattic", + version: "5.5", + updateState: .updated, + autoupdate: false, + automanaged: false, + url: nil, + settingsURL: nil + ) + let plugin = Plugin(state: state, directoryEntry: nil) + + #expect(plugin.id != plugin.state.slug, + "plugin.id and plugin.state.slug should differ") + #expect(plugin.id == "jetpack/jetpack.php") + #expect(plugin.state.slug == "jetpack") + } + + @Test + func directoryEntryLookupBySlugSucceeds() { + let entry = makeDirectoryEntry(slug: "jetpack") + + // Simulate the directoryEntries dictionary (keyed by slug) + var directoryEntries = [String: PluginDirectoryEntryState]() + directoryEntries["jetpack"] = .present(entry) + + // Looking up by slug succeeds + #expect(directoryEntries["jetpack"]?.entry != nil) + } + + @Test + func directoryEntryLookupByIdFails() { + let entry = makeDirectoryEntry(slug: "jetpack") + + // Simulate the directoryEntries dictionary (keyed by slug) + var directoryEntries = [String: PluginDirectoryEntryState]() + directoryEntries["jetpack"] = .present(entry) + + // Looking up by plugin.id (the bug) fails because id != slug + let pluginId = "jetpack/jetpack.php" + #expect(directoryEntries[pluginId]?.entry == nil, + "Looking up by plugin.id should fail since entries are keyed by slug") + } + + @Test + func pluginStoreGetPluginDirectoryEntryUsesSlugKey() { + let store = PluginStore() + let entry = makeDirectoryEntry(slug: "jetpack") + + // Populate the store's directoryEntries via its state + store.state.directoryEntries["jetpack"] = .present(entry) + + // Lookup by slug succeeds + #expect(store.getPluginDirectoryEntry(slug: "jetpack") != nil) + + // Lookup by id fails + #expect(store.getPluginDirectoryEntry(slug: "jetpack/jetpack.php") == nil) + } + + // MARK: - Helpers + + private func makeDirectoryEntry(slug: String) -> PluginDirectoryEntry { + let json = """ + { + "name": "Test Plugin", + "slug": "\(slug)", + "version": "1.0", + "author": "Test", + "rating": 80, + "icons": {}, + "sections": {} + } + """.data(using: .utf8)! + + return try! JSONDecoder().decode(PluginDirectoryEntry.self, from: json) + } +} diff --git a/Tests/KeystoneTests/Tests/Features/Stats/DonutChartViewTests.swift b/Tests/KeystoneTests/Tests/Features/Stats/DonutChartViewTests.swift new file mode 100644 index 000000000000..3941961ea37c --- /dev/null +++ b/Tests/KeystoneTests/Tests/Features/Stats/DonutChartViewTests.swift @@ -0,0 +1,48 @@ +import Testing +import UIKit +@testable import WordPress + +struct DonutChartViewTests { + + @Test + func configureWithEmptySegmentsDoesNotCrash() { + let chartView = DonutChartView(frame: CGRect(x: 0, y: 0, width: 200, height: 200)) + + // When totalCount > 0 but all segment values are 0, normalizedSegments() + // filters them all out, leaving an empty array. Previously this caused + // a crash on `0..