Skip to content

Commit 59a394f

Browse files
committed
Re-enable StatsWidgetsStoreTests
1 parent d1328e2 commit 59a394f

File tree

4 files changed

+134
-51
lines changed

4 files changed

+134
-51
lines changed

WordPress/Classes/Stores/StatsWidgetsStore.swift

+77-33
Original file line numberDiff line numberDiff line change
@@ -27,17 +27,17 @@ class StatsWidgetsStore {
2727
initializeStatsWidgetsIfNeeded()
2828

2929
if let newTodayData = refreshStats(type: HomeWidgetTodayData.self) {
30-
HomeWidgetTodayData.write(items: newTodayData)
30+
setCachedItems(newTodayData)
3131
WidgetCenter.shared.reloadTodayTimelines()
3232
}
3333

3434
if let newAllTimeData = refreshStats(type: HomeWidgetAllTimeData.self) {
35-
HomeWidgetAllTimeData.write(items: newAllTimeData)
35+
setCachedItems(newAllTimeData)
3636
WidgetCenter.shared.reloadAllTimeTimelines()
3737
}
3838

3939
if let newThisWeekData = refreshStats(type: HomeWidgetThisWeekData.self) {
40-
HomeWidgetThisWeekData.write(items: newThisWeekData)
40+
setCachedItems(newThisWeekData)
4141
WidgetCenter.shared.reloadThisWeekTimelines()
4242
}
4343
}
@@ -51,21 +51,21 @@ class StatsWidgetsStore {
5151

5252
var isReloadRequired = false
5353

54-
if !HomeWidgetTodayData.cacheDataExists() {
54+
if !hasCachedItems(for: HomeWidgetTodayData.self) {
5555
DDLogInfo("StatsWidgets: Writing initialization data into HomeWidgetTodayData.plist")
56-
HomeWidgetTodayData.write(items: initializeHomeWidgetData(type: HomeWidgetTodayData.self))
56+
setCachedItems(initializeHomeWidgetData(type: HomeWidgetTodayData.self))
5757
isReloadRequired = true
5858
}
5959

60-
if !HomeWidgetThisWeekData.cacheDataExists() {
60+
if !hasCachedItems(for: HomeWidgetThisWeekData.self) {
6161
DDLogInfo("StatsWidgets: Writing initialization data into HomeWidgetThisWeekData.plist")
62-
HomeWidgetThisWeekData.write(items: initializeHomeWidgetData(type: HomeWidgetThisWeekData.self))
62+
setCachedItems(initializeHomeWidgetData(type: HomeWidgetThisWeekData.self))
6363
isReloadRequired = true
6464
}
6565

66-
if !HomeWidgetAllTimeData.cacheDataExists() {
66+
if !hasCachedItems(for: HomeWidgetAllTimeData.self) {
6767
DDLogInfo("StatsWidgets: Writing initialization data into HomeWidgetAllTimeData.plist")
68-
HomeWidgetAllTimeData.write(items: initializeHomeWidgetData(type: HomeWidgetAllTimeData.self))
68+
setCachedItems(initializeHomeWidgetData(type: HomeWidgetAllTimeData.self))
6969
isReloadRequired = true
7070
}
7171

@@ -83,7 +83,7 @@ class StatsWidgetsStore {
8383
return
8484
}
8585

86-
var homeWidgetCache = T.read() ?? initializeHomeWidgetData(type: widgetType)
86+
var homeWidgetCache = getCachedItems(for: T.self) ?? initializeHomeWidgetData(type: widgetType)
8787
guard let oldData = homeWidgetCache[siteID.intValue] else {
8888
DDLogError("StatsWidgets: Failed to find a matching site")
8989
return
@@ -93,7 +93,7 @@ class StatsWidgetsStore {
9393
DDLogError("StatsWidgets: the site does not exist anymore")
9494
// if for any reason that site does not exist anymore, remove it from the cache.
9595
homeWidgetCache.removeValue(forKey: siteID.intValue)
96-
T.write(items: homeWidgetCache)
96+
setCachedItems(homeWidgetCache)
9797
return
9898
}
9999

@@ -102,37 +102,81 @@ class StatsWidgetsStore {
102102
if widgetType == HomeWidgetTodayData.self, let stats = stats as? TodayWidgetStats {
103103
widgetReload = WidgetCenter.shared.reloadTodayTimelines
104104

105-
homeWidgetCache[siteID.intValue] = HomeWidgetTodayData(siteID: siteID.intValue,
106-
siteName: blog.title ?? oldData.siteName,
107-
url: blog.url ?? oldData.url,
108-
timeZone: blog.timeZone ?? TimeZone.current,
109-
date: Date(),
110-
stats: stats) as? T
105+
homeWidgetCache[siteID.intValue] = HomeWidgetTodayData(
106+
siteID: siteID.intValue,
107+
siteName: blog.title ?? oldData.siteName,
108+
url: blog.url ?? oldData.url,
109+
timeZone: blog.timeZone ?? TimeZone.current,
110+
date: Date(),
111+
stats: stats
112+
) as? T
111113

112114
} else if widgetType == HomeWidgetAllTimeData.self, let stats = stats as? AllTimeWidgetStats {
113115
widgetReload = WidgetCenter.shared.reloadAllTimeTimelines
114116

115-
homeWidgetCache[siteID.intValue] = HomeWidgetAllTimeData(siteID: siteID.intValue,
116-
siteName: blog.title ?? oldData.siteName,
117-
url: blog.url ?? oldData.url,
118-
timeZone: blog.timeZone ?? TimeZone.current,
119-
date: Date(),
120-
stats: stats) as? T
117+
homeWidgetCache[siteID.intValue] = HomeWidgetAllTimeData(
118+
siteID: siteID.intValue,
119+
siteName: blog.title ?? oldData.siteName,
120+
url: blog.url ?? oldData.url,
121+
timeZone: blog.timeZone ?? TimeZone.current,
122+
date: Date(),
123+
stats: stats
124+
) as? T
121125

122126
} else if widgetType == HomeWidgetThisWeekData.self, let stats = stats as? ThisWeekWidgetStats {
123127
widgetReload = WidgetCenter.shared.reloadThisWeekTimelines
124128

125-
homeWidgetCache[siteID.intValue] = HomeWidgetThisWeekData(siteID: siteID.intValue,
126-
siteName: blog.title ?? oldData.siteName,
127-
url: blog.url ?? oldData.url,
128-
timeZone: blog.timeZone ?? TimeZone.current,
129-
date: Date(),
130-
stats: stats) as? T
129+
homeWidgetCache[siteID.intValue] = HomeWidgetThisWeekData(
130+
siteID: siteID.intValue,
131+
siteName: blog.title ?? oldData.siteName,
132+
url: blog.url ?? oldData.url,
133+
timeZone: blog.timeZone ?? TimeZone.current,
134+
date: Date(),
135+
stats: stats
136+
) as? T
131137
}
132138

133-
T.write(items: homeWidgetCache)
139+
setCachedItems(homeWidgetCache)
134140
widgetReload?()
135141
}
142+
143+
// MARK: HomeWidgetCache (Helpers)
144+
145+
private func getCachedItems<T: HomeWidgetData>(for type: T.Type) -> [Int: T]? {
146+
do {
147+
return try makeCache(for: type).read()
148+
} catch {
149+
DDLogError("HomeWidgetCache: failed to read items: \(error)")
150+
return nil
151+
}
152+
}
153+
154+
private func hasCachedItems<T: HomeWidgetData>(for type: T.Type) -> Bool {
155+
guard let items = getCachedItems(for: type) else {
156+
return false
157+
}
158+
return !items.isEmpty
159+
}
160+
161+
private func deleteCachedItems<T: HomeWidgetData>(for type: T.Type) {
162+
do {
163+
try makeCache(for: T.self).delete()
164+
} catch {
165+
DDLogError("HomeWidgetCache: failed to delete items: \(error)")
166+
}
167+
}
168+
169+
private func setCachedItems<T: HomeWidgetData>(_ items: [Int: T]) {
170+
do {
171+
try makeCache(for: T.self).write(items: items)
172+
} catch {
173+
DDLogError("HomeWidgetCache: failed to write items: \(error)")
174+
}
175+
}
176+
177+
private func makeCache<T: HomeWidgetData>(for type: T.Type) -> HomeWidgetCache<T> {
178+
HomeWidgetCache<T>(appGroup: appGroupName)
179+
}
136180
}
137181

138182
// MARK: - Helper methods
@@ -283,9 +327,9 @@ private extension StatsWidgetsStore {
283327

284328
guard !isLoggedIn else { return }
285329

286-
HomeWidgetTodayData.delete()
287-
HomeWidgetThisWeekData.delete()
288-
HomeWidgetAllTimeData.delete()
330+
deleteCachedItems(for: HomeWidgetTodayData.self)
331+
deleteCachedItems(for: HomeWidgetThisWeekData.self)
332+
deleteCachedItems(for: HomeWidgetAllTimeData.self)
289333

290334
userDefaults?.setValue(nil, forKey: WidgetStatsConfiguration.userDefaultsSiteIdKey)
291335

WordPress/JetpackStatsWidgets/Cache/HomeWidgetCache.swift

+19-2
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,27 @@ import JetpackStatsWidgetsCore
44
/// Cache manager that stores `HomeWidgetData` values in a plist file, contained in the specified security application group and with the specified file name.
55
/// The corresponding dictionary is always in the form `[Int: T]`, where the `Int` key is the SiteID, and the `T` value is any `HomeWidgetData` instance.
66
struct HomeWidgetCache<T: HomeWidgetData> {
7-
87
let fileName: String
98
let appGroup: String
109

10+
init(fileName: String = T.filename, appGroup: String) {
11+
self.fileName = fileName
12+
self.appGroup = appGroup
13+
}
14+
1115
private var fileURL: URL? {
12-
FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: appGroup)?.appendingPathComponent(fileName)
16+
if appGroup.hasPrefix(Self.testAppGroupNamePrefix) {
17+
return makeTestingFileURL()
18+
}
19+
return FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: appGroup)?.appendingPathComponent(fileName)
20+
}
21+
22+
/// Tests are not eligible to write to shared secure groups.
23+
private func makeTestingFileURL() -> URL? {
24+
let directoryURL = FileManager.default.temporaryDirectory
25+
.appendingPathComponent(appGroup)
26+
try? FileManager.default.createDirectory(at: directoryURL, withIntermediateDirectories: true, attributes: nil)
27+
return directoryURL.appendingPathComponent(fileName)
1328
}
1429

1530
func read() throws -> [Int: T]? {
@@ -48,4 +63,6 @@ struct HomeWidgetCache<T: HomeWidgetData> {
4863
}
4964
try FileManager.default.removeItem(at: fileURL)
5065
}
66+
67+
static var testAppGroupNamePrefix: String { "xctest" }
5168
}

WordPress/JetpackStatsWidgets/Model/HomeWidgetData.swift

-5
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,4 @@ extension HomeWidgetData {
5050
DDLogError("HomeWidgetToday: Failed writing data item: \(error.localizedDescription)")
5151
}
5252
}
53-
54-
static func cacheDataExists() -> Bool {
55-
let data = read()
56-
return data != nil && data?.isEmpty == false
57-
}
5853
}

WordPress/WordPressTest/Classes/Stores/StatsWidgetsStoreTests.swift

+38-11
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,32 @@ import JetpackStatsWidgetsCore
33

44
@testable import WordPress
55

6-
// TODO: rewrite this system to avoid using BuildSettings.current (hardcoded all over the place)
76
class StatsWidgetsStoreTests: CoreDataTestCase {
87
private var sut: StatsWidgetsStore!
8+
private var appGroupName: String!
9+
private let appKeychainAccessGroup = "xctest_appKeychainAccessGroup"
910

1011
override func setUp() {
12+
super.setUp()
13+
14+
let prefix = HomeWidgetCache<HomeWidgetTodayData>.testAppGroupNamePrefix
15+
appGroupName = "\(prefix)_\(UUID().uuidString)"
1116
deleteHomeWidgetData()
12-
sut = StatsWidgetsStore(coreDataStack: contextManager)
17+
sut = StatsWidgetsStore(
18+
coreDataStack: contextManager,
19+
appGroupName: appGroupName,
20+
appKeychainAccessGroup: appKeychainAccessGroup
21+
)
1322
}
1423

1524
override func tearDown() {
25+
super.tearDown()
26+
1627
deleteHomeWidgetData()
1728
sut = nil
1829
}
1930

20-
func xTestStatsWidgetsDataInitializedAfterSignDidFinish() {
31+
func testStatsWidgetsDataInitializedAfterSignDidFinish() {
2132
BlogBuilder(contextManager.mainContext)
2233
.withAnAccount()
2334
.isHostedAtWPcom()
@@ -29,7 +40,7 @@ class StatsWidgetsStoreTests: CoreDataTestCase {
2940
XCTAssertTrue(statsWidgetsHaveData())
3041
}
3142

32-
func xTestStatsWidgetsDeletedAfterDefaultWPAccountRemoved() {
43+
func testStatsWidgetsDeletedAfterDefaultWPAccountRemoved() {
3344
BlogBuilder(contextManager.mainContext)
3445
.withAnAccount()
3546
.isHostedAtWPcom()
@@ -41,20 +52,36 @@ class StatsWidgetsStoreTests: CoreDataTestCase {
4152
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(50)) {
4253
XCTAssertFalse(self.statsWidgetsHaveData())
4354
}
44-
4555
}
4656
}
4757

4858
private extension StatsWidgetsStoreTests {
4959
private func statsWidgetsHaveData() -> Bool {
50-
return HomeWidgetTodayData.read() != nil
51-
|| HomeWidgetThisWeekData.read() != nil
52-
|| HomeWidgetAllTimeData.read() != nil
60+
hasData(for: HomeWidgetTodayData.self) &&
61+
hasData(for: HomeWidgetThisWeekData.self) &&
62+
hasData(for: HomeWidgetAllTimeData.self)
5363
}
5464

5565
private func deleteHomeWidgetData() {
56-
HomeWidgetTodayData.delete()
57-
HomeWidgetThisWeekData.delete()
58-
HomeWidgetAllTimeData.delete()
66+
do {
67+
try makeCache(for: HomeWidgetTodayData.self).delete()
68+
try makeCache(for: HomeWidgetThisWeekData.self).delete()
69+
try makeCache(for: HomeWidgetAllTimeData.self).delete()
70+
} catch {
71+
// OK if it doesn't exist
72+
}
73+
}
74+
75+
private func hasData<T: HomeWidgetData>(for type: T.Type) -> Bool {
76+
do {
77+
return try makeCache(for: type).read() != nil
78+
} catch {
79+
XCTFail("failed to read cache: \(error)")
80+
return false
81+
}
82+
}
83+
84+
private func makeCache<T: HomeWidgetData>(for type: T.Type) -> HomeWidgetCache<T> {
85+
HomeWidgetCache<T>(appGroup: appGroupName)
5986
}
6087
}

0 commit comments

Comments
 (0)