Simplify tests to prepare for a more complicated remote

This commit is contained in:
Sven van Heugten 2026-01-14 19:49:17 +01:00
parent a4b11e1ffa
commit 6ecb6d07ac
3 changed files with 24 additions and 26 deletions

View file

@ -6,14 +6,17 @@ open NightLight.Core.Models
open FsToolkit.ErrorHandling open FsToolkit.ErrorHandling
open FSharp.Data open FSharp.Data
type HumanInteraction = type RemoteInteraction =
| LightPoweredOn of Light
| LightPoweredOff of Light
| RemotePressedOnButton | RemotePressedOnButton
| RemotePressedOffButton | RemotePressedOffButton
type HumanInteraction =
| LightPoweredOn of Light
| LightPoweredOff of Light
type Interaction = type Interaction =
| HumanInteraction of HumanInteraction | HumanInteraction of HumanInteraction
| RemoteInteraction of RemoteInteraction
| TimeChanged of DateTime | TimeChanged of DateTime
type Color = type Color =
@ -120,12 +123,12 @@ type FakeHome() =
|> ReceivedZigbeeEvent |> ReceivedZigbeeEvent
|> onEventPublished.Trigger |> onEventPublished.Trigger
| HumanInteraction(LightPoweredOff light) -> friendlyNameToFakeLight[light.FriendlyName].PowerOff() | HumanInteraction(LightPoweredOff light) -> friendlyNameToFakeLight[light.FriendlyName].PowerOff()
| HumanInteraction RemotePressedOnButton -> | RemoteInteraction RemotePressedOnButton ->
{ Topic = $"zigbee2mqtt/{remoteControlFriendlyName.Get}" { Topic = $"zigbee2mqtt/{remoteControlFriendlyName.Get}"
Payload = @"{ ""action"": ""on"" }" } Payload = @"{ ""action"": ""on"" }" }
|> ReceivedZigbeeEvent |> ReceivedZigbeeEvent
|> onEventPublished.Trigger |> onEventPublished.Trigger
| HumanInteraction RemotePressedOffButton -> | RemoteInteraction RemotePressedOffButton ->
{ Topic = $"zigbee2mqtt/{remoteControlFriendlyName.Get}" { Topic = $"zigbee2mqtt/{remoteControlFriendlyName.Get}"
Payload = @"{ ""action"": ""off"" }" } Payload = @"{ ""action"": ""off"" }" }
|> ReceivedZigbeeEvent |> ReceivedZigbeeEvent

View file

@ -6,16 +6,14 @@ open NightLight.Core.Tests.TimeChangedGenerators
open FsCheck open FsCheck
let private genHumanInteraction biasTowardsLight = let private genHumanInteraction biasTowardsLight =
let genLightInteraction =
Gen.oneof [ Gen.constant biasTowardsLight; Gen.elements lights ] Gen.oneof [ Gen.constant biasTowardsLight; Gen.elements lights ]
|> Gen.bind (fun light -> Gen.elements [ LightPoweredOn light; LightPoweredOff light ]) |> Gen.bind (fun light -> Gen.elements [ LightPoweredOn light; LightPoweredOff light ])
let genRemoteInteraction =
Gen.elements [ RemotePressedOnButton; RemotePressedOffButton ]
Gen.oneof [ genLightInteraction; genRemoteInteraction ]
|> Gen.map Interaction.HumanInteraction |> Gen.map Interaction.HumanInteraction
let private genRemoteInteraction =
Gen.elements [ RemotePressedOnButton; RemotePressedOffButton ]
|> Gen.map RemoteInteraction
let private genInteraction biasTowardsLight = let private genInteraction biasTowardsLight =
Gen.oneof [ genTimeChanged; genHumanInteraction biasTowardsLight ] Gen.oneof [ genTimeChanged; genHumanInteraction biasTowardsLight ]

View file

@ -69,10 +69,8 @@ type NightLightTests() =
fakeHome.LightShouldHaveState light _.IsOn fakeHome.LightShouldHaveState light _.IsOn
[<Property(Arbitrary = [| typeof<ArbitraryRemotelyControlledLight> |])>] [<Property(Arbitrary = [| typeof<ArbitraryRemotelyControlledLight> |])>]
let ``All remote controlled lights with power should be on if the 'Off' button on the remote was never pressed`` let ``All remote controlled lights with power should be on if the remote was never used`` (light: Light) =
(light: Light) genRandomInteractionsExcept light _.IsRemoteInteraction
=
genRandomInteractionsExcept light ((=) (HumanInteraction RemotePressedOffButton))
|> ensureStartsWithTimeChanged |> ensureStartsWithTimeChanged
|> ensureLightHasPower light |> ensureLightHasPower light
|> Arb.fromGen |> Arb.fromGen
@ -82,13 +80,13 @@ type NightLightTests() =
fakeHome.LightShouldHaveState light _.IsOn fakeHome.LightShouldHaveState light _.IsOn
[<Property(Arbitrary = [| typeof<ArbitraryRemotelyControlledLight> |])>] [<Property(Arbitrary = [| typeof<ArbitraryRemotelyControlledLight> |])>]
let ``After pressing 'On' on the remote, if the 'Off' button isn't pressed, all remotely controlled lights with power should be on`` let ``After pressing 'On' on the remote, if the remote isn't used again, all remotely controlled lights with power should be on``
(light: Light) (light: Light)
= =
concatGens concatGens
[ genRandomInteractions light [ genRandomInteractions light
HumanInteraction RemotePressedOnButton |> List.singleton |> Gen.constant RemoteInteraction RemotePressedOnButton |> List.singleton |> Gen.constant
genRandomInteractionsExcept light ((=) (HumanInteraction RemotePressedOffButton)) ] genRandomInteractionsExcept light _.IsRemoteInteraction ]
|> ensureStartsWithTimeChanged |> ensureStartsWithTimeChanged
|> ensureLightHasPower light |> ensureLightHasPower light
|> Arb.fromGen |> Arb.fromGen
@ -98,7 +96,7 @@ type NightLightTests() =
fakeHome.LightShouldHaveState light _.IsOn fakeHome.LightShouldHaveState light _.IsOn
[<Property(Arbitrary = [| typeof<ArbitraryRemotelyControlledLight> |])>] [<Property(Arbitrary = [| typeof<ArbitraryRemotelyControlledLight> |])>]
let ``After a new day starts, if the 'Off' button isn't pressed, all remotely controlled lights with power should be on`` let ``After a new day starts, if the remote isn't used, all remotely controlled lights with power should be on``
(light: Light) (light: Light)
= =
concatGens concatGens
@ -106,7 +104,7 @@ type NightLightTests() =
genTimeChangedToRandomNightTime |> Gen.map List.singleton genTimeChangedToRandomNightTime |> Gen.map List.singleton
genRandomInteractionsExcept light isTimeChangedToAnyDayTime genRandomInteractionsExcept light isTimeChangedToAnyDayTime
genTimeChangedToRandomDayTime |> Gen.map List.singleton genTimeChangedToRandomDayTime |> Gen.map List.singleton
genRandomInteractionsExcept light ((=) (HumanInteraction RemotePressedOffButton)) ] genRandomInteractionsExcept light _.IsRemoteInteraction ]
|> ensureStartsWithTimeChanged |> ensureStartsWithTimeChanged
|> ensureLightHasPower light |> ensureLightHasPower light
|> Arb.fromGen |> Arb.fromGen
@ -116,15 +114,14 @@ type NightLightTests() =
fakeHome.LightShouldHaveState light _.IsOn fakeHome.LightShouldHaveState light _.IsOn
[<Property(Arbitrary = [| typeof<ArbitraryRemotelyControlledLight> |])>] [<Property(Arbitrary = [| typeof<ArbitraryRemotelyControlledLight> |])>]
let ``After pressing 'Off' on the remote, if the 'On' button isn't pressed and a new day doesn't start, all remotely controlled lights should be off`` let ``After pressing 'Off' on the remote, if the remote isn't used again and a new day doesn't start, all remotely controlled lights should be off``
(light: Light) (light: Light)
= =
concatGens concatGens
[ genRandomInteractions light [ genRandomInteractions light
HumanInteraction RemotePressedOffButton |> List.singleton |> Gen.constant RemoteInteraction RemotePressedOffButton |> List.singleton |> Gen.constant
genRandomInteractionsExcept light (fun interaction -> genRandomInteractionsExcept light (fun interaction ->
interaction = HumanInteraction RemotePressedOnButton interaction.IsRemoteInteraction || interaction |> isTimeChangedToAnyDayTime) ]
|| interaction |> isTimeChangedToAnyDayTime) ]
|> ensureStartsWithTimeChanged |> ensureStartsWithTimeChanged
|> Arb.fromGen |> Arb.fromGen
|> Prop.forAll |> Prop.forAll