Skip to content
This repository was archived by the owner on Feb 4, 2025. It is now read-only.

Commit c78d940

Browse files
authored
Merge pull request #2943 from wordpress-mobile/issue/10515-fix-visitors-cast-exception
Fix visitors cast exception
2 parents 33afe23 + 7139ed6 commit c78d940

File tree

3 files changed

+199
-8
lines changed

3 files changed

+199
-8
lines changed

example/src/test/java/org/wordpress/android/fluxc/wc/stats/WCStatsStoreTest.kt

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import org.robolectric.RuntimeEnvironment
2020
import org.robolectric.annotation.Config
2121
import org.wordpress.android.fluxc.Dispatcher
2222
import org.wordpress.android.fluxc.SingleStoreWellSqlConfigForTests
23+
import org.wordpress.android.fluxc.UnitTestUtils
2324
import org.wordpress.android.fluxc.generated.WCStatsActionBuilder
2425
import org.wordpress.android.fluxc.model.SiteModel
2526
import org.wordpress.android.fluxc.model.WCNewVisitorStatsModel
@@ -1948,4 +1949,45 @@ class WCStatsStoreTest {
19481949
assertTrue(customMonthVisitorStats2.isNotEmpty())
19491950
assertTrue(customMonthVisitorStats.isNotEmpty())
19501951
}
1952+
1953+
@Test
1954+
fun testGetNewVisitorStatsWithInvalidData(){
1955+
// wrong-visitor-stats-data.json includes different wrong formatted data to ensure
1956+
// that getNewVisitorStats is resilient and can recover from unexpected data
1957+
//
1958+
val defaultWeekVisitorStatsModel = WCStatsTestUtils.generateSampleNewVisitorStatsModel(
1959+
granularity = WEEKS.toString(),
1960+
data = UnitTestUtils.getStringFromResourceFile(this.javaClass, "wc/wrong-visitor-stats-data.json")
1961+
)
1962+
val site = SiteModel().apply { id = defaultWeekVisitorStatsModel.localSiteId }
1963+
WCVisitorStatsSqlUtils.insertOrUpdateNewVisitorStats(defaultWeekVisitorStatsModel)
1964+
1965+
val defaultWeekVisitorStats = wcStatsStore.getNewVisitorStats(site, WEEKS)
1966+
assertTrue(defaultWeekVisitorStats.isNotEmpty())
1967+
assertEquals(defaultWeekVisitorStats["2019-06-23"],10)
1968+
assertEquals(defaultWeekVisitorStats["2019-06-22"],20)
1969+
assertEquals(defaultWeekVisitorStats["2019-07-16"],0)
1970+
assertEquals(defaultWeekVisitorStats["2019-07-17"],0)
1971+
assertEquals(defaultWeekVisitorStats["2019-07-18"],0)
1972+
}
1973+
1974+
@Test
1975+
fun testGetVisitorStatsWithInvalidData(){
1976+
// wrong-visitor-stats-data.json includes different wrong formatted data to ensure
1977+
// that getNewVisitorStats is resilient and can recover from unexpected data
1978+
//
1979+
val defaultWeekVisitorStatsModel = WCStatsTestUtils.generateSampleVisitorStatsModel(
1980+
data = UnitTestUtils.getStringFromResourceFile(this.javaClass, "wc/wrong-visitor-stats-data.json")
1981+
)
1982+
val site = SiteModel().apply { id = defaultWeekVisitorStatsModel.localSiteId }
1983+
WCVisitorStatsSqlUtils.insertOrUpdateVisitorStats(defaultWeekVisitorStatsModel)
1984+
1985+
val defaultWeekVisitorStats = wcStatsStore.getVisitorStats(site, DAYS)
1986+
assertTrue(defaultWeekVisitorStats.isNotEmpty())
1987+
assertEquals(defaultWeekVisitorStats["2019-06-23"],10)
1988+
assertEquals(defaultWeekVisitorStats["2019-06-22"],20)
1989+
assertEquals(defaultWeekVisitorStats["2019-07-16"],0)
1990+
assertEquals(defaultWeekVisitorStats["2019-07-17"],0)
1991+
assertEquals(defaultWeekVisitorStats["2019-07-18"],0)
1992+
}
19511993
}
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
[
2+
[
3+
"2019-06-19",
4+
1
5+
],
6+
[
7+
"2019-06-20",
8+
1
9+
],
10+
[
11+
"2019-06-21",
12+
0
13+
],
14+
[
15+
"2019-06-22",
16+
"20"
17+
],
18+
[
19+
"2019-06-23",
20+
"10.0"
21+
],
22+
[
23+
"2019-06-24",
24+
0
25+
],
26+
[
27+
"2019-06-25",
28+
1
29+
],
30+
[
31+
"2019-06-26",
32+
0
33+
],
34+
[
35+
"2019-06-27",
36+
0
37+
],
38+
[
39+
"2019-06-28",
40+
0
41+
],
42+
[
43+
"2019-06-29",
44+
0
45+
],
46+
[
47+
"2019-06-30",
48+
0
49+
],
50+
[
51+
"2019-07-01",
52+
0
53+
],
54+
[
55+
"2019-07-02",
56+
0
57+
],
58+
[
59+
"2019-07-03",
60+
0
61+
],
62+
[
63+
"2019-07-04",
64+
0
65+
],
66+
[
67+
"2019-07-05",
68+
0
69+
],
70+
[
71+
"2019-07-06",
72+
0
73+
],
74+
[
75+
"2019-07-07",
76+
0
77+
],
78+
[
79+
"2019-07-08",
80+
0
81+
],
82+
[
83+
"2019-07-09",
84+
1
85+
],
86+
[
87+
"2019-07-10",
88+
0
89+
],
90+
[
91+
"2019-07-11",
92+
0
93+
],
94+
[
95+
"2019-07-12",
96+
0
97+
],
98+
[
99+
"2019-07-13",
100+
0
101+
],
102+
[
103+
"2019-07-14",
104+
0
105+
],
106+
[
107+
"2019-07-15",
108+
0
109+
],
110+
[
111+
"2019-07-16",
112+
null
113+
],
114+
[
115+
"2019-07-17",
116+
"null"
117+
],
118+
[
119+
"2019-07-18",
120+
"this is not a number"
121+
]
122+
]

plugins/woocommerce/src/main/kotlin/org/wordpress/android/fluxc/store/WCStatsStore.kt

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import org.wordpress.android.fluxc.Dispatcher
66
import org.wordpress.android.fluxc.Payload
77
import org.wordpress.android.fluxc.action.WCStatsAction
88
import org.wordpress.android.fluxc.annotations.action.Action
9+
import org.wordpress.android.fluxc.logging.FluxCCrashLoggerProvider.crashLogger
910
import org.wordpress.android.fluxc.model.SiteModel
1011
import org.wordpress.android.fluxc.model.WCNewVisitorStatsModel
1112
import org.wordpress.android.fluxc.model.WCOrderStatsModel
@@ -27,6 +28,7 @@ import org.wordpress.android.fluxc.utils.SiteUtils
2728
import org.wordpress.android.util.AppLog
2829
import org.wordpress.android.util.AppLog.T
2930
import org.wordpress.android.util.AppLog.T.API
31+
import java.lang.NumberFormatException
3032
import java.util.Calendar
3133
import java.util.Locale
3234
import javax.inject.Inject
@@ -364,10 +366,11 @@ class WCStatsStore @Inject constructor(
364366
return if (periodIndex == -1 || fieldIndex == -1) {
365367
mapOf()
366368
} else {
367-
// Years are returned as numbers by the API, and Gson interprets them as floats - clean up the decimal
368-
visitorStatsModel.dataList.map {
369-
it[periodIndex].toString().removeSuffix(".0") to (it[fieldIndex] as Number).toInt()
370-
}.toMap()
369+
getVisitorsMap(
370+
periodIndex = periodIndex,
371+
fieldIndex = fieldIndex,
372+
dataList = visitorStatsModel.dataList
373+
)
371374
}
372375
} ?: return mapOf()
373376
}
@@ -392,14 +395,38 @@ class WCStatsStore @Inject constructor(
392395
return if (periodIndex == -1 || fieldIndex == -1) {
393396
mapOf()
394397
} else {
395-
// Years are returned as numbers by the API, and Gson interprets them as floats - clean up the decimal
396-
visitorStatsModel.dataList.map {
397-
it[periodIndex].toString().removeSuffix(".0") to (it[fieldIndex] as Number).toInt()
398-
}.toMap()
398+
getVisitorsMap(
399+
periodIndex = periodIndex,
400+
fieldIndex = fieldIndex,
401+
dataList = visitorStatsModel.dataList
402+
)
399403
}
400404
} ?: return mapOf()
401405
}
402406

407+
private fun getVisitorsMap(
408+
periodIndex: Int, fieldIndex: Int, dataList: List<List<Any>>
409+
): Map<String, Int> {
410+
return dataList.associate {
411+
// Years are returned as numbers by the API, and Gson interprets them as floats - clean up the decimal
412+
val period = it[periodIndex].toString().removeSuffix(".0")
413+
414+
// Some plugins can change the field type
415+
val visitsRawValue = it[fieldIndex]
416+
val visits = if (visitsRawValue is Number) {
417+
visitsRawValue.toInt()
418+
} else {
419+
crashLogger?.recordException(
420+
exception = NumberFormatException("$visitsRawValue is not a valid number"),
421+
category = null
422+
)
423+
(visitsRawValue as? String)?.toDoubleOrNull()?.toInt() ?: 0
424+
}
425+
426+
period to visits
427+
}
428+
}
429+
403430
/**
404431
* Returns the currency code associated with stored stats for the [site], as an ISO 4217 currency code (eg. USD).
405432
*/

0 commit comments

Comments
 (0)