"""Tests for JSON schemas / Pydantic models.""" import json import pytest from datetime import datetime from src.network.schemas import ( ChannelSchema, MasterBusSchema, MixerStateSchema, PluginSchema, TransportSchema, RoutingSchema, AuxBusSchema, SubgroupSchema, VCASchema, EQSchema, EQBandSchema, CompressorSchema, GateSchema, FXSendsSchema, ParameterUpdateSchema, ParameterUpdateBatchSchema, ParameterSetRequest, WSMessage, WSMessageType, MixerParameterSchema, ParameterCategoryEnum, ParameterTypeEnum, RouteNodeSchema, RoutingEdgeSchema, NodeTypeEnum, APIResponse, PluginParamMapSchema, ) class TestChannelSchema: """Tests for ChannelSchema.""" def test_default_channel(self): ch = ChannelSchema(channel=0) assert ch.channel == 0 assert ch.volume_db == 0.0 assert ch.pan == 0.0 assert not ch.mute assert not ch.solo def test_channel_with_eq(self): ch = ChannelSchema( channel=3, volume_db=-6.0, eq=EQSchema( enabled=True, low=EQBandSchema(freq_hz=80.0, gain_db=3.0, q=1.0), ), ) assert ch.eq.enabled assert ch.eq.low.freq_hz == 80.0 assert ch.eq.low.gain_db == 3.0 def test_serialize_deserialize(self): ch = ChannelSchema(channel=5, volume_db=-3.0, pan=0.5) data = ch.model_dump() ch2 = ChannelSchema.model_validate(data) assert ch2.channel == 5 assert ch2.volume_db == -3.0 assert ch2.pan == 0.5 def test_json_roundtrip(self): ch = ChannelSchema(channel=0, mute=True) json_str = ch.model_dump_json() data = json.loads(json_str) assert data["channel"] == 0 assert data["mute"] is True class TestMasterBusSchema: """Tests for MasterBusSchema.""" def test_default_master(self): m = MasterBusSchema() assert m.volume_db == 0.0 assert not m.muted assert not m.dim_active assert m.aux_buses == [] def test_with_buses(self): m = MasterBusSchema( volume_db=-10.0, aux_buses=[ AuxBusSchema(index=0, label="Reverb"), AuxBusSchema(index=1, label="Delay"), ], subgroups=[ SubgroupSchema(index=0, label="Drums", members=[0, 1, 2]), ], vca_groups=[ VCASchema(index=0, label="All Vocals", master_db=-3.0, members=[3, 4, 5]), ], ) assert len(m.aux_buses) == 2 assert m.aux_buses[0].label == "Reverb" assert len(m.subgroups) == 1 assert m.subgroups[0].members == [0, 1, 2] assert m.vca_groups[0].master_db == -3.0 class TestTransportSchema: """Tests for TransportSchema.""" def test_defaults(self): t = TransportSchema() assert not t.playing assert not t.recording assert t.tempo_bpm == 120.0 assert t.position_sec == 0.0 def test_playing_state(self): t = TransportSchema(playing=True, tempo_bpm=142.0, position_sec=35.2) assert t.playing assert not t.recording assert t.tempo_bpm == 142.0 class TestMixerStateSchema: """Tests for full MixerStateSchema.""" def test_empty_state(self): state = MixerStateSchema() assert state.channels == [] assert state.master.volume_db == 0.0 assert state.transport.tempo_bpm == 120.0 def test_full_state(self): state = MixerStateSchema( channels=[ ChannelSchema(channel=0, volume_db=-6.0), ChannelSchema(channel=1, mute=True), ], master=MasterBusSchema(volume_db=-3.0), transport=TransportSchema(playing=True), scenes=["Intro", "Verse", "Chorus"], uptime_seconds=3600.0, ) assert len(state.channels) == 2 assert state.scenes == ["Intro", "Verse", "Chorus"] assert state.uptime_seconds == 3600.0 def test_json_roundtrip(self): state = MixerStateSchema( channels=[ChannelSchema(channel=0)], uptime_seconds=10.0, ) json_str = state.model_dump_json() data = json.loads(json_str) assert data["uptime_seconds"] == 10.0 assert len(data["channels"]) == 1 class TestParameterUpdate: """Tests for parameter update schemas.""" def test_single_update(self): update = ParameterUpdateSchema( param_type=ParameterTypeEnum.VOLUME, value=-3.0, channel=2, ) assert update.param_type == ParameterTypeEnum.VOLUME assert update.value == -3.0 assert update.channel == 2 def test_batch_update(self): batch = ParameterUpdateBatchSchema(updates=[ ParameterUpdateSchema(param_type=ParameterTypeEnum.VOLUME, value=-6.0, channel=0), ParameterUpdateSchema(param_type=ParameterTypeEnum.MUTE, value=1.0, channel=0), ParameterUpdateSchema(param_type=ParameterTypeEnum.MASTER_VOLUME, value=-3.0), ]) assert len(batch.updates) == 3 assert batch.updates[2].param_type == ParameterTypeEnum.MASTER_VOLUME class TestWSMessage: """Tests for WebSocket message schemas.""" def test_parameter_update_message(self): msg = WSMessage( type=WSMessageType.PARAMETER_UPDATE, payload={"param_type": "volume", "value": -3.0, "channel": 1}, ) assert msg.type == WSMessageType.PARAMETER_UPDATE assert msg.payload["param_type"] == "volume" def test_full_state_message(self): msg = WSMessage( type=WSMessageType.FULL_STATE, payload={"channels": []}, ) data = msg.model_dump() assert data["type"] == "full_state" def test_error_message(self): msg = WSMessage( type=WSMessageType.ERROR, payload={"message": "Something went wrong"}, ) assert msg.payload["message"] == "Something went wrong" class TestParameterSetRequest: """Tests for ParameterSetRequest.""" def test_default_param_type(self): req = ParameterSetRequest(value=-3.0) assert req.param_type == "volume" assert req.value == -3.0 def test_explicit_param_type(self): req = ParameterSetRequest(param_type="mute", value=1.0) assert req.param_type == "mute" def test_json_parse(self): json_str = '{"param_type": "pan", "value": 0.5}' req = ParameterSetRequest.model_validate_json(json_str) assert req.param_type == "pan" assert req.value == 0.5 class TestPluginSchema: """Tests for PluginSchema.""" def test_plugin(self): p = PluginSchema( plugin_id=1, name="Ch1 Gate", role="gate", channel=0, params=[ PluginParamMapSchema(name="threshold", index=0, value=0.5), PluginParamMapSchema(name="ratio", index=1, value=0.3), ], ) assert p.plugin_id == 1 assert len(p.params) == 2 assert p.params[0].name == "threshold" class TestRoutingSchema: """Tests for RoutingSchema.""" def test_empty_routing(self): r = RoutingSchema() assert r.nodes == [] assert r.edges == [] def test_with_nodes_and_edges(self): r = RoutingSchema( nodes=[ RouteNodeSchema(node_id="sys_in_1", type=NodeTypeEnum.SYSTEM_INPUT, jack_port="system:capture_1"), RouteNodeSchema(node_id="ch_0_input", type=NodeTypeEnum.CHANNEL_INPUT, channel=0), ], edges=[ RoutingEdgeSchema(source="sys_in_1", dest="ch_0_input"), ], solo_nodes=["ch_0_input"], ) assert len(r.nodes) == 2 assert len(r.edges) == 1 assert r.edges[0].source == "sys_in_1" assert r.solo_nodes == ["ch_0_input"]