199 lines
4.3 KiB
Python
199 lines
4.3 KiB
Python
from dataclasses import dataclass
|
|
from typing import NamedTuple
|
|
from unittest.mock import MagicMock
|
|
|
|
import pytest
|
|
from gears import Gear
|
|
from gears.connections import connect
|
|
from gears.effect import Effect, effect_of, effect_of_2
|
|
|
|
|
|
def test_get_set():
|
|
g = Gear(1)
|
|
assert g.get() == 1
|
|
assert g() == 1
|
|
g.set(3)
|
|
|
|
assert g.get() == 3
|
|
assert g() == 3
|
|
|
|
|
|
def test_basic_effect():
|
|
g = Gear("E")
|
|
|
|
last_arg: str | None = None
|
|
|
|
@effect_of(g)
|
|
def value_changed(v: str):
|
|
nonlocal last_arg
|
|
last_arg = v
|
|
|
|
assert last_arg == "E"
|
|
|
|
g.set("hello")
|
|
assert last_arg == "hello"
|
|
|
|
|
|
def test_effect_of_2():
|
|
g1 = Gear("E")
|
|
g2 = Gear(3)
|
|
|
|
last_arg: tuple[str, int] | None = None
|
|
|
|
@effect_of_2(g1, g2)
|
|
def value_changed(v1: str, v2: int):
|
|
nonlocal last_arg
|
|
last_arg = (v1, v2)
|
|
|
|
assert last_arg == ("E", 3)
|
|
g2.set(4)
|
|
assert last_arg == ("E", 4)
|
|
|
|
|
|
def test_connect():
|
|
my_str = Gear("123")
|
|
my_int = connect(my_str, lambda s: int(s), lambda _, i: str(i))
|
|
|
|
assert my_int() == 123
|
|
my_int.set(321)
|
|
assert my_str() == "321"
|
|
|
|
|
|
# def test_dualis():
|
|
# val_both: Gear[tuple[int, int]] = Gear((5, 6))
|
|
# val0 = connect(val_both, lambda both: both[0], lambda both, val0: (val0, both[1]))
|
|
# val1 = connect(val_both, lambda both: both[1], lambda both, val1: (both[0], val1))
|
|
|
|
|
|
def test_watts():
|
|
volts = Gear(3.0)
|
|
amps = Gear(5.0)
|
|
|
|
@effect_of_2(volts, amps)
|
|
def on_watts_changed(volts: float, amps: float):
|
|
watts = volts * amps
|
|
if watts > 100:
|
|
raise ValueError("OMG ITS BURNING")
|
|
|
|
volts.set(5.0)
|
|
with pytest.raises(ValueError):
|
|
volts.set(50.0)
|
|
|
|
|
|
def test_led():
|
|
battery_voltage = Gear(3.0)
|
|
switch: Gear[bool] = Gear(True) # true means circuit closed
|
|
# ohms_circuit = Gear(1.0)
|
|
ohms_circuit = connect(
|
|
switch, lambda x: 1.0 if x else 100000000.0, lambda _, y: y < 100
|
|
)
|
|
|
|
log: list[str] = []
|
|
|
|
@effect_of_2(battery_voltage, ohms_circuit)
|
|
def on_led_inputs_changed(volts: float, ohms: float):
|
|
amps = volts / ohms
|
|
if amps > 1:
|
|
print("LED ACTIVE!")
|
|
log.append("LED ACTIVE!")
|
|
else:
|
|
print("LED INACTIVE!")
|
|
log.append("LED INACTIVE!")
|
|
|
|
# Effect(on_led_inputs_changed, battery_voltage, led_ohms)
|
|
|
|
assert log == ["LED ACTIVE!"]
|
|
switch.set(False)
|
|
assert log == ["LED ACTIVE!", "LED INACTIVE!"]
|
|
|
|
|
|
def test_connect_multiplication():
|
|
mul1 = Gear(10.0)
|
|
mul2 = connect(mul1, lambda x: x * 2.0, lambda _, y: y / 2.0)
|
|
mul4 = connect(mul2, lambda x: x * 2.0, lambda _, y: y / 2.0)
|
|
mul3 = connect(mul1, lambda x: x * 3.0, lambda _, y: y / 3.0)
|
|
assert mul2() == 20
|
|
assert mul3() == 30
|
|
mul2.set(30)
|
|
assert mul1() == 15
|
|
assert mul3() == 45
|
|
assert mul4() == 60
|
|
|
|
# mul1
|
|
# |> mul2
|
|
# |> mul4
|
|
# |> mul3
|
|
#
|
|
|
|
|
|
class Person:
|
|
name: str
|
|
|
|
|
|
class HouseHold:
|
|
people: list[Person]
|
|
|
|
|
|
class NameEntry:
|
|
def __init__(self, name: Gear[str]):
|
|
# self.name = name
|
|
textBox = TextBox(...)
|
|
effect_of(name)(textBox.setValue)
|
|
textBox.onChange = name.set
|
|
|
|
|
|
def test_connect_property():
|
|
class Foo(NamedTuple):
|
|
bar: int
|
|
baz: int
|
|
|
|
foo = Gear(Foo(bar=1, baz=2))
|
|
bar = connect(
|
|
foo,
|
|
lambda foo: foo.bar,
|
|
lambda foo, bar: Foo(bar=bar, baz=foo.baz),
|
|
# TODO: look into dataclasses.replace
|
|
)
|
|
|
|
assert bar() == 1
|
|
bar.set(5)
|
|
assert bar() == 5
|
|
assert foo() == Foo(5, 2)
|
|
|
|
# class IntEntryOld:
|
|
# on_value_changed: Signal[int]
|
|
# _val: int
|
|
|
|
# def get_val(self, val: int): ...
|
|
# def set_val(self, val: int): ...
|
|
|
|
# class IntEntry:
|
|
# def __init__(self, value: Gear[int]): ...
|
|
|
|
# int_entry = IntEntry()
|
|
|
|
# effect_of(bar)(int_entry.set_val)
|
|
# int_entry.on_value_changed.connect(bar.set)
|
|
|
|
# @effect_of(bar)
|
|
# def update_ui(bar: int):
|
|
# int_entry.set_val(bar)
|
|
|
|
# def update_model(bar_val: int):
|
|
# bar.set(bar_val)
|
|
|
|
# int_entry.on_value_changed.connect(update_model)
|
|
|
|
|
|
def hello(my_callback):
|
|
my_callback(5)
|
|
|
|
|
|
def test_demonstrate_magicmock():
|
|
m = MagicMock()
|
|
# print(f"{m.foo(4).bar[0]=}")
|
|
# m.
|
|
hello(m)
|
|
# assert m.call_count == 1
|
|
m.assert_called_once_with(5)
|