# Path: cbus/common.py
# def check_ga(group_addr: int) -> None:
#     """
#     Validates a given group address, throwing ValueError if not.
# 
#     :param group_addr: Input group address to validate.
#     :raises ValueError: If group address is invalid
# 
#     """
#     if not validate_ga(group_addr):
#         raise ValueError(
#             'Group Address out of range ({}..{}), got {}'.format(
#                 MIN_GROUP_ADDR, MAX_GROUP_ADDR, group_addr))
# 
# Path: cbus/daemon/cmqttd.py
#     async def create_serial_connection(*_, **__):
# def ga_range():
# def get_topic_group_address(topic: Text) -> int:
# def set_topic(group_addr: int) -> Text:
# def state_topic(group_addr: int) -> Text:
# def conf_topic(group_addr: int) -> Text:
# def bin_sensor_state_topic(group_addr: int) -> Text:
# def bin_sensor_conf_topic(group_addr: int) -> Text:
#     def __init__(self, labels: Optional[Dict[int, Text]], *args, **kwargs):
#     def on_lighting_group_ramp(self, source_addr, group_addr, duration, level):
#     def on_lighting_group_on(self, source_addr, group_addr):
#     def on_lighting_group_off(self, source_addr, group_addr):
#     def on_clock_request(self, source_addr):
#     def on_connect(self, client, userdata: CBusHandler, flags, rc):
#     def on_message(self, client, userdata: CBusHandler, msg: mqtt.MQTTMessage):
#     def publish(self, topic: Text, payload: Dict[Text, Any]):
#     def publish_all_lights(self, labels: Dict[int, Text]):
#     def publish_binary_sensor(self, group_addr: int, state: bool):
#     def lighting_group_on(self, source_addr: Optional[int], group_addr: int):
#     def lighting_group_off(self, source_addr: Optional[int], group_addr: int):
#     def lighting_group_ramp(self, source_addr: Optional[int], group_addr: int,
#                             duration: int, level: int):
# def read_auth(client: mqtt.Client, auth_file: TextIO):
# def read_cbz_labels(cbz_file: BinaryIO) -> Dict[int, Text]:
# async def _main():
#     def factory():
# def main():
# _BINSENSOR_TOPIC_PREFIX = 'homeassistant/binary_sensor/cbus_'
# _LIGHT_TOPIC_PREFIX = 'homeassistant/light/cbus_'
# _TOPIC_SET_SUFFIX = '/set'
# _TOPIC_CONF_SUFFIX = '/config'
# _TOPIC_STATE_SUFFIX = '/state'
# _META_TOPIC = 'homeassistant/binary_sensor/cbus_cmqttd'
# class CBusHandler(PCIProtocol):
# class MqttClient(mqtt.Client):


from dataclasses import dataclass
from parameterized import parameterized
from typing import Optional, Text, cast
from cbus.common import check_ga
from cbus.daemon import cmqttd
import io
import unittest
        self.password = password


class CmqttdUtilityTest(unittest.TestCase):

    def test_ga_range(self):
        """Tests for ga_range()"""
        valid_ga = list(cmqttd.ga_range())

        # Should be 256 valid GAs, and they should each appear once.
        self.assertEqual(256, len(valid_ga))
        self.assertEqual(256, len(set(valid_ga)))

        for ga in valid_ga:
            check_ga(ga)  # throws exception on error

    @parameterized.expand([(ga,) for ga in cmqttd.ga_range()])
    def test_valid_topic_group_address(self, ga):
        # name is also the expected group address number
        light_topic = f'homeassistant/light/cbus_{ga}'
        light_topic_len = len(light_topic)
        bin_topic = f'homeassistant/binary_sensor/cbus_{ga}'
        bin_topic_len = len(bin_topic)

        # base topic path -> ga
        self.assertEqual(ga, cmqttd.get_topic_group_address(light_topic))

        # Generating a set topic
        set_topic = cmqttd.set_topic(ga)
        self.assertEqual(light_topic, set_topic[:light_topic_len])

# Path: cbus/common.py
# def check_ga(group_addr: int) -> None:
#     """
#     Validates a given group address, throwing ValueError if not.
# 
#     :param group_addr: Input group address to validate.
#     :raises ValueError: If group address is invalid
# 
#     """
#     if not validate_ga(group_addr):
#         raise ValueError(
#             'Group Address out of range ({}..{}), got {}'.format(
#                 MIN_GROUP_ADDR, MAX_GROUP_ADDR, group_addr))
# 
# Path: cbus/daemon/cmqttd.py
#     async def create_serial_connection(*_, **__):
# def ga_range():
# def get_topic_group_address(topic: Text) -> int:
# def set_topic(group_addr: int) -> Text:
# def state_topic(group_addr: int) -> Text:
# def conf_topic(group_addr: int) -> Text:
# def bin_sensor_state_topic(group_addr: int) -> Text:
# def bin_sensor_conf_topic(group_addr: int) -> Text:
#     def __init__(self, labels: Optional[Dict[int, Text]], *args, **kwargs):
#     def on_lighting_group_ramp(self, source_addr, group_addr, duration, level):
#     def on_lighting_group_on(self, source_addr, group_addr):
#     def on_lighting_group_off(self, source_addr, group_addr):
#     def on_clock_request(self, source_addr):
#     def on_connect(self, client, userdata: CBusHandler, flags, rc):
#     def on_message(self, client, userdata: CBusHandler, msg: mqtt.MQTTMessage):
#     def publish(self, topic: Text, payload: Dict[Text, Any]):
#     def publish_all_lights(self, labels: Dict[int, Text]):
#     def publish_binary_sensor(self, group_addr: int, state: bool):
#     def lighting_group_on(self, source_addr: Optional[int], group_addr: int):
#     def lighting_group_off(self, source_addr: Optional[int], group_addr: int):
#     def lighting_group_ramp(self, source_addr: Optional[int], group_addr: int,
#                             duration: int, level: int):
# def read_auth(client: mqtt.Client, auth_file: TextIO):
# def read_cbz_labels(cbz_file: BinaryIO) -> Dict[int, Text]:
# async def _main():
#     def factory():
# def main():
# _BINSENSOR_TOPIC_PREFIX = 'homeassistant/binary_sensor/cbus_'
# _LIGHT_TOPIC_PREFIX = 'homeassistant/light/cbus_'
# _TOPIC_SET_SUFFIX = '/set'
# _TOPIC_CONF_SUFFIX = '/config'
# _TOPIC_STATE_SUFFIX = '/state'
# _META_TOPIC = 'homeassistant/binary_sensor/cbus_cmqttd'
# class CBusHandler(PCIProtocol):
# class MqttClient(mqtt.Client):


# Path: tests/test_cmqttd.py
from dataclasses import dataclass
from parameterized import parameterized
from typing import Optional, Text, cast
from cbus.common import check_ga
from cbus.daemon import cmqttd
import io
import unittest

        self.password = password


class CmqttdUtilityTest(unittest.TestCase):

    def test_ga_range(self):
        """Tests for ga_range()"""
        valid_ga = list(cmqttd.ga_range())

        # Should be 256 valid GAs, and they should each appear once.
        self.assertEqual(256, len(valid_ga))
        self.assertEqual(256, len(set(valid_ga)))

        for ga in valid_ga:
            check_ga(ga)  # throws exception on error

    @parameterized.expand([(ga,) for ga in cmqttd.ga_range()])
    def test_valid_topic_group_address(self, ga):
        # name is also the expected group address number
        light_topic = f'homeassistant/light/cbus_{ga}'
        light_topic_len = len(light_topic)
        bin_topic = f'homeassistant/binary_sensor/cbus_{ga}'
        bin_topic_len = len(bin_topic)

        # base topic path -> ga
        self.assertEqual(ga, cmqttd.get_topic_group_address(light_topic))

        # Generating a set topic
        set_topic = cmqttd.set_topic(ga)
        self.assertEqual(light_topic, set_topic[:light_topic_len])

        self.assertEqual(ga, cmqttd.get_topic_group_address(set_topic))