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 : . @prefix dev: . @prefix effect: . @prefix func: . @prefix rdfs: . ''' 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, [])