Files @ 8fc5da221688
Branch filter:

Location: light9/light9/effect/effecteval_test.py

drewp@bigasterisk.com
checkpoint show data
from typing import List, Tuple

import pytest

from light9.effect.effect_function_library import EffectFunctionLibrary
from light9.effect.effecteval2 import EffectEval2
from light9.effect.settings import DeviceSettings, EffectSettings
from light9.mock_syncedgraph import MockSyncedGraph
from light9.namespaces import DEV, L9
from light9.newtypes import (DeviceAttr, DeviceUri, EffectAttr, EffectUri, HexColor, VTUnion)

PREFIX = '''
    @prefix : <http://light9.bigasterisk.com/> .
    @prefix dev: <http://light9.bigasterisk.com/device/> .
    @prefix effect: <http://light9.bigasterisk.com/effect/> .
    @prefix func: <http://light9.bigasterisk.com/effectFunction/> .
    @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
'''

GRAPH = PREFIX + '''

    func:scale
        a :EffectFunction;
        rdfs:label "a submaster- scales :deviceSettings";
        :input
            [ :effectAttr :strength; :defaultValue 0.0 ],
            [ :effectAttr :deviceSettings; ] . # e.g. "par2 at color=red; par3 at color=white"

    func:strobe
        a :EffectFunction;
        rdfs:label "blink specified devices";
        :input
            [ :effectAttr :strength; :defaultValue 0.0 ],
            [ :effectAttr :period; :defaultValue 0.5 ],
            [ :effectAttr :onTime; :defaultValue 0.1 ],
            [ :effectAttr :deviceSettings ] .

    func:image
        a :EffectFunction;
        rdfs:label "sample image at x=time";
        :input
            [ :effectAttr :strength; :defaultValue 0.0 ],
            [ :effectAttr :period; :defaultValue 2.0 ],
            [ :effectAttr :image; :defaultValue "specks.png" ],
            [ :effectAttr :deviceSettings; rdfs:comment "these might have a :sort key or a :y value" ] .


    :effectSub
        a :Effect;
        :effectFunction func:scale;
        :publishAttr :strength;
        :setting [ :effectAttr :deviceSettings; :value [
                   :setting [ :device dev:light1; :deviceAttr :color; :value "#ff0000" ]  ] ].

    :effectDefaultStrobe
        a :Effect;
        :effectFunction func:strobe;
        :publishAttr :strength;
        :setting [ :effectAttr :deviceSettings; :value [
                   :setting [ :device dev:light1; :deviceAttr :color; :value "#ff0000" ] ] ].

    :effectCustomStrobe
        a :Effect;
        :effectFunction func:strobe;
        :publishAttr :strength;
        :setting
            [ :effectAttr :period; :value 3.0],
            [ :effectAttr :onTime; :value 0.5],
            [ :effectAttr :deviceSettings; :value [
              :setting [ :device dev:light1; :deviceAttr :color; :value "#ff0000" ] ] ].
'''

effectSub = EffectUri(L9['effectSub'])
effectDefaultStrobe = EffectUri(L9['effectDefaultStrobe'])
effectCustomStrobe = EffectUri(L9['effectCustomStrobe'])


def light1At(col: str) -> List[Tuple[DeviceUri, DeviceAttr, VTUnion]]:
    return [(DeviceUri(DEV['light1']), DeviceAttr(L9['color']), HexColor(col))]


@pytest.fixture
def effectFunctions():
    g = MockSyncedGraph(GRAPH)
    return EffectFunctionLibrary(g)


class TestEffectEval:

    def test_scalesColors(self, effectFunctions):
        g = effectFunctions.graph
        ee = EffectEval2(g, effectSub, effectFunctions)
        s = EffectSettings(g, [(effectSub, EffectAttr(L9['strength']), 0.5)])
        ds = ee.compute(songTime=0, inputs=s)
        assert ds == DeviceSettings(g, light1At('#7f0000'))

    def test_cullsZeroOutputs(self, effectFunctions):
        g = effectFunctions.graph
        ee = EffectEval2(g, effectSub, effectFunctions)
        s = EffectSettings(g, [(effectSub, EffectAttr(L9['strength']), 0.0)])
        ds = ee.compute(songTime=0, inputs=s)
        assert ds == DeviceSettings(g, [])

    def test_strobeDefaults(self, effectFunctions):
        g = effectFunctions.graph
        ee = EffectEval2(g, effectDefaultStrobe, effectFunctions)
        s = EffectSettings(g, [(effectDefaultStrobe, EffectAttr(L9['strength']), 1.0)])
        assert ee.compute(songTime=0, inputs=s) == DeviceSettings(g, light1At('#ff0000'))
        assert ee.compute(songTime=.25, inputs=s) == DeviceSettings(g, [])

    def strobeMultsStrength(self, effectFunctions):
        g = effectFunctions.graph
        ee = EffectEval2(g, effectDefaultStrobe, effectFunctions)
        s = EffectSettings(g, [(effectDefaultStrobe, EffectAttr(L9['strength']), 0.5)])
        assert ee.compute(songTime=0, inputs=s) == DeviceSettings(g, light1At('#7f0000'))

    def test_strobeCustom(self, effectFunctions):
        g = effectFunctions.graph
        ee = EffectEval2(g, effectCustomStrobe, effectFunctions)
        s = EffectSettings(g, [(effectCustomStrobe, EffectAttr(L9['strength']), 1.0)])
        assert ee.compute(songTime=0, inputs=s) == DeviceSettings(g, light1At('#ff0000'))
        assert ee.compute(songTime=.25, inputs=s) == DeviceSettings(g, light1At('#ff0000'))
        assert ee.compute(songTime=.6, inputs=s) == DeviceSettings(g, [])