# Path: robel/components/robot/hardware_robot.py
# DEFAULT_ERROR_TOL = 1. * np.pi / 180
# class HardwareRobotGroupConfig(RobotGroupConfig):
# class HardwareRobotComponent(RobotComponent, metaclass=abc.ABCMeta):
#     def __init__(self,
#                  *args,
#                  calib_scale: Optional[Iterable[float]] = None,
#                  calib_offset: Optional[Iterable[float]] = None,
#                  **kwargs):
#     def __init__(self, *args, **kwargs):
#     def is_hardware(self) -> bool:
#     def time(self) -> float:
#     def reset_time(self):
#     def _process_group(self, **config_kwargs) -> HardwareRobotGroupConfig:
#     def _calibrate_state(self, state: RobotState,
#                          group_config: HardwareRobotGroupConfig):
#     def _decalibrate_qpos(self, qpos: np.ndarray,
#                           group_config: HardwareRobotGroupConfig) -> np.ndarray:
#     def _synchronize_timestep(self, minimum_sleep: float = 1e-4):
#     def _wait_for_desired_states(
#             self,
#             desired_states: Iterable[Tuple[RobotGroupConfig, RobotState]],
#             error_tol: float = DEFAULT_ERROR_TOL,
#             timeout: float = 3.0,
#             poll_interval: float = 0.25,
#             initial_sleep: Optional[float] = 0.25,
#             last_diff_tol: Optional[float] = DEFAULT_ERROR_TOL,
#             last_diff_ticks: int = 2,
#     ):
#         def all_states_close(states_a, states_b, tol):
#     def _copy_to_simulation_state(
#             self, group_states: Iterable[Tuple[RobotGroupConfig, RobotState]]):
# 
# Path: robel/utils/testing/mock_sim_scene.py
# class MockSimScene:
#     """Mock object that implements the SimScene interface."""
# 
#     @staticmethod
#     def create(*unused_args, **unused_kwargs):
#         raise NotImplementedError('`patch_sim_scene` must be called.')
# 
#     def __init__(self, *args, step_duration: float = 1, **kwargs):
#         """Initializes a new mock SimScene."""
#         self.sim = mock.Mock()
#         self.sim.model = MockMjModel(*args, **kwargs)
# 
#         self.model = self.sim.model
#         self.sim.data = self.model
#         self.data = self.model.data
# 
#         self.step_duration = step_duration
# 
#         self.close = mock.Mock()
#         self.advance = mock.Mock()
# 
#         self.renderer = mock.Mock()
#         self.renderer.render_offscreen = lambda w, h, **_: np.zeros((w, h))
# 
# Path: robel/utils/testing/mock_time.py
# def patch_time(module_path: str, **kwargs):
#     return mock.patch(module_path, MockTime(**kwargs))


from typing import Any
from absl.testing import absltest
from robel.components.robot.hardware_robot import (HardwareRobotComponent,
                                                        RobotState)
from robel.utils.testing.mock_sim_scene import MockSimScene
from robel.utils.testing.mock_time import patch_time
import numpy as np



class DummyHardwareRobotComponent(HardwareRobotComponent):
    """Test implementation of HardwareRobotComponent."""

    def calibrate_state(self, state: RobotState, group_name: str):
        self._calibrate_state(state, self.get_config(group_name))

    def decalibrate_qpos(self, qpos: np.ndarray, group_name: str):
        return self._decalibrate_qpos(qpos, self.get_config(group_name))

    def do_timestep(self):
        self._synchronize_timestep()


class HardwareRobotComponentTest(absltest.TestCase):
    """Unit test class for HardwareRobotComponent."""

    def test_calibrate_state(self):
        """Converts a state to component space."""
        sim_scene = MockSimScene(nq=1)  # type: Any
        robot = DummyHardwareRobotComponent(
            sim_scene,
            groups={
                'a': {
                    'calib_scale': [0.5, -1, 1],
                    'calib_offset': [2, 0, -0.5],
                }
            })

# Path: robel/components/robot/hardware_robot.py
# DEFAULT_ERROR_TOL = 1. * np.pi / 180
# class HardwareRobotGroupConfig(RobotGroupConfig):
# class HardwareRobotComponent(RobotComponent, metaclass=abc.ABCMeta):
#     def __init__(self,
#                  *args,
#                  calib_scale: Optional[Iterable[float]] = None,
#                  calib_offset: Optional[Iterable[float]] = None,
#                  **kwargs):
#     def __init__(self, *args, **kwargs):
#     def is_hardware(self) -> bool:
#     def time(self) -> float:
#     def reset_time(self):
#     def _process_group(self, **config_kwargs) -> HardwareRobotGroupConfig:
#     def _calibrate_state(self, state: RobotState,
#                          group_config: HardwareRobotGroupConfig):
#     def _decalibrate_qpos(self, qpos: np.ndarray,
#                           group_config: HardwareRobotGroupConfig) -> np.ndarray:
#     def _synchronize_timestep(self, minimum_sleep: float = 1e-4):
#     def _wait_for_desired_states(
#             self,
#             desired_states: Iterable[Tuple[RobotGroupConfig, RobotState]],
#             error_tol: float = DEFAULT_ERROR_TOL,
#             timeout: float = 3.0,
#             poll_interval: float = 0.25,
#             initial_sleep: Optional[float] = 0.25,
#             last_diff_tol: Optional[float] = DEFAULT_ERROR_TOL,
#             last_diff_ticks: int = 2,
#     ):
#         def all_states_close(states_a, states_b, tol):
#     def _copy_to_simulation_state(
#             self, group_states: Iterable[Tuple[RobotGroupConfig, RobotState]]):
# 
# Path: robel/utils/testing/mock_sim_scene.py
# class MockSimScene:
#     """Mock object that implements the SimScene interface."""
# 
#     @staticmethod
#     def create(*unused_args, **unused_kwargs):
#         raise NotImplementedError('`patch_sim_scene` must be called.')
# 
#     def __init__(self, *args, step_duration: float = 1, **kwargs):
#         """Initializes a new mock SimScene."""
#         self.sim = mock.Mock()
#         self.sim.model = MockMjModel(*args, **kwargs)
# 
#         self.model = self.sim.model
#         self.sim.data = self.model
#         self.data = self.model.data
# 
#         self.step_duration = step_duration
# 
#         self.close = mock.Mock()
#         self.advance = mock.Mock()
# 
#         self.renderer = mock.Mock()
#         self.renderer.render_offscreen = lambda w, h, **_: np.zeros((w, h))
# 
# Path: robel/utils/testing/mock_time.py
# def patch_time(module_path: str, **kwargs):
#     return mock.patch(module_path, MockTime(**kwargs))


# Path: robel/components/robot/hardware_robot_test.py
from typing import Any
from absl.testing import absltest
from robel.components.robot.hardware_robot import (HardwareRobotComponent,
                                                        RobotState)
from robel.utils.testing.mock_sim_scene import MockSimScene
from robel.utils.testing.mock_time import patch_time
import numpy as np




class DummyHardwareRobotComponent(HardwareRobotComponent):
    """Test implementation of HardwareRobotComponent."""

    def calibrate_state(self, state: RobotState, group_name: str):
        self._calibrate_state(state, self.get_config(group_name))

    def decalibrate_qpos(self, qpos: np.ndarray, group_name: str):
        return self._decalibrate_qpos(qpos, self.get_config(group_name))

    def do_timestep(self):
        self._synchronize_timestep()


class HardwareRobotComponentTest(absltest.TestCase):
    """Unit test class for HardwareRobotComponent."""

    def test_calibrate_state(self):
        """Converts a state to component space."""
        sim_scene = MockSimScene(nq=1)  # type: Any
        robot = DummyHardwareRobotComponent(
            sim_scene,
            groups={
                'a': {
                    'calib_scale': [0.5, -1, 1],
                    'calib_offset': [2, 0, -0.5],
                }
            })

        state = RobotState(