Skip to content

Commit

Permalink
Merge pull request #61 from ReneeVandervelde/master
Browse files Browse the repository at this point in the history
Fix null crash for updatestate lastInstall field
  • Loading branch information
ReneeVandervelde authored Sep 12, 2020
2 parents ad44e74 + 6806aa3 commit 03464c5
Show file tree
Hide file tree
Showing 6 changed files with 120 additions and 3 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
Change Log
==========

1.1.3
-----

### Fixed:

- Handle null `lastInstall` fields on hue lights' update state.

1.1.2
-----

Expand Down
2 changes: 2 additions & 0 deletions lights/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,6 @@ dependencies {
kapt(moshi("moshi-kotlin-codegen"))
compile(okHttp())
compile(threeTen())

testImplementation(jUnit())
}
Original file line number Diff line number Diff line change
Expand Up @@ -285,10 +285,23 @@ data class ControlCapabilities(
* of this aren't documented anywhere I can find.
* @property lastInstall Timestamp of the last firmware update.
*/
@JsonClass(generateAdapter = true)
data class UpdateState(
val state: String,
@Json(name="lastinstall") val lastInstall: Instant
@Deprecated(
message = "Use lastKnownInstall to handle optional cases.",
replaceWith = ReplaceWith("lastKnownInstall")
)
val lastInstall: Instant,
val lastKnownInstall: Instant? = lastInstall
)

/**
* Internal representation of the [UpdateState] class for Json Transformation.
*/
@JsonClass(generateAdapter = true)
internal data class HueUpdateState(
val state: String,
@Json(name="lastinstall") val lastInstall: Instant?
)

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package inkapplications.shade.lights

import com.squareup.moshi.FromJson
import com.squareup.moshi.ToJson
import org.threeten.bp.Instant

internal object HueUpdateStateTransformer {
@ToJson
fun toHueFormat(state: UpdateState): HueUpdateState = HueUpdateState(
state = state.state,
lastInstall = state.lastKnownInstall.takeIf { it != Instant.MIN }
)

@FromJson
fun fromHueFormat(state: HueUpdateState): UpdateState = UpdateState(
state = state.state,
lastInstall = state.lastInstall ?: Instant.MIN,
lastKnownInstall = state.lastInstall
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ class ShadeLightsModule {
TemperatureRangeTransformer,
BrightnessTransformer,
DurationTransformer,
HueLightStateTransformer
HueLightStateTransformer,
HueUpdateStateTransformer
)

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package inkapplications.shade.lights

import junit.framework.TestCase.assertEquals
import junit.framework.TestCase.assertNull
import org.junit.Test
import org.threeten.bp.Instant

class HueUpdateStateTransformerTest {
@Test
fun fromHueFormat() {
val now = Instant.now()
val given = HueUpdateState("fake", now)

val result = HueUpdateStateTransformer.fromHueFormat(given)

assertEquals("State is not modified", "fake", result.state)
assertEquals("Last install is used in nullable", now, result.lastKnownInstall)
assertEquals("Last install is used in non-nullable field", now, result.lastInstall)
}

@Test
fun fromNullHueFormat() {
val given = HueUpdateState("fake", null)

val result = HueUpdateStateTransformer.fromHueFormat(given)

assertEquals("State is not modified", "fake", result.state)
assertNull("Nullable field should reflect null last install", result.lastKnownInstall)
assertEquals("Non-nullable field should use MIN as timestamp", Instant.MIN, result.lastInstall)
}

@Test
fun toHueFormatCompat() {
val now = Instant.now()
val given = UpdateState("fake", now)

val result = HueUpdateStateTransformer.toHueFormat(given)

assertEquals("State is not modified", "fake", result.state)
assertEquals("Nullable last install should be passed along", now, result.lastInstall)
}

@Test
fun toHueFormatCompatSpecified() {
val now = Instant.now()
val given = UpdateState("fake", Instant.MIN, now)

val result = HueUpdateStateTransformer.toHueFormat(given)

assertEquals("State is not modified", "fake", result.state)
assertEquals("Nullable field should take precedent if specified", now, result.lastInstall)
}

@Test
fun toHueFormatCompatNull() {
val now = Instant.now()
val given = UpdateState("fake", now, null)

val result = HueUpdateStateTransformer.toHueFormat(given)

assertEquals("State is not modified", "fake", result.state)
assertNull("Nullable field should take precedent if specified, even if null", result.lastInstall)
}

@Test
fun toHueFormatCompatNullFromMin() {
val given = UpdateState("fake", Instant.MIN)

val result = HueUpdateStateTransformer.toHueFormat(given)

assertEquals("State is not modified", "fake", result.state)
assertNull("Min instants should be interpreted as null for compatibility", result.lastInstall)
}
}

0 comments on commit 03464c5

Please sign in to comment.