116 lines
3.6 KiB
Python
116 lines
3.6 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""
|
|
This program has been developed by students from the bachelor Computer Science at Utrecht
|
|
University within the Software Project course.
|
|
© Copyright Utrecht University (Department of Information and Computing Sciences)
|
|
"""
|
|
|
|
import threading
|
|
import signal
|
|
import pytest
|
|
import mock
|
|
|
|
from robot_interface.state import State
|
|
|
|
|
|
def test_initialize_does_not_reinitialize():
|
|
"""
|
|
Check that calling `initialize` on an already initialized state does not change existing
|
|
attributes.
|
|
"""
|
|
state = State()
|
|
|
|
# Mock qi_session to avoid real session creation
|
|
mock_session = mock.MagicMock()
|
|
state.qi_session = mock_session
|
|
|
|
# Set state as already initialized
|
|
state.is_initialized = True
|
|
old_exit_event = state.exit_event
|
|
|
|
# Call initialize
|
|
state.initialize()
|
|
|
|
# Ensure existing attributes were not overwritten
|
|
assert state.exit_event == old_exit_event # exit_event should not be recreated
|
|
assert state.qi_session == mock_session # qi_session should not be replaced
|
|
assert state.is_initialized is True # is_initialized should remain True
|
|
|
|
|
|
def test_deinitialize_behavior():
|
|
"""Check that deinitialize closes sockets and updates the initialization state correctly."""
|
|
state = State()
|
|
|
|
# Case 1: Initialized with sockets
|
|
state.is_initialized = True
|
|
mock_socket_1 = mock.Mock()
|
|
mock_socket_2 = mock.Mock()
|
|
state.sockets = [mock_socket_1, mock_socket_2]
|
|
state.deinitialize()
|
|
|
|
# Sockets should be closed
|
|
mock_socket_1.close.assert_called_once()
|
|
mock_socket_2.close.assert_called_once()
|
|
# State should be marked as not initialized
|
|
assert not state.is_initialized
|
|
|
|
# Case 2: Not initialized, should not raise
|
|
state.is_initialized = False
|
|
state.sockets = []
|
|
state.deinitialize()
|
|
assert not state.is_initialized
|
|
|
|
|
|
def test_access_control_before_initialization():
|
|
"""Verify that accessing certain attributes before initialization raises RuntimeError."""
|
|
state = State()
|
|
|
|
with pytest.raises(RuntimeError, match=".*sockets.*"):
|
|
_ = state.sockets
|
|
|
|
with pytest.raises(RuntimeError, match=".*qi_session.*"):
|
|
_ = state.qi_session
|
|
|
|
|
|
def test_exit_event_before_initialized_returns_if_set():
|
|
"""Check that exit_event can be accessed even if state is not initialized,
|
|
but only if it is set."""
|
|
state = State()
|
|
|
|
# Manually create and set the exit_event
|
|
object.__setattr__(state, "exit_event", threading.Event())
|
|
object.__getattribute__(state, "exit_event").set()
|
|
|
|
# Should return the event without raising
|
|
assert state.exit_event.is_set()
|
|
|
|
|
|
def test_getattribute_allowed_attributes_before_init():
|
|
"""Ensure attributes allowed before initialization can be accessed without error."""
|
|
state = State()
|
|
|
|
assert callable(state.initialize)
|
|
assert callable(state.deinitialize)
|
|
assert state.is_initialized is False
|
|
assert state.__dict__ is not None
|
|
assert state.__class__.__name__ == "State"
|
|
assert state.__doc__ is not None
|
|
|
|
|
|
def test_signal_handler_sets_exit_event(monkeypatch):
|
|
"""Ensure SIGINT triggers the exit_event via signal handler."""
|
|
state = State()
|
|
|
|
# Patch get_qi_session to prevent real session creation
|
|
monkeypatch.setattr("robot_interface.state.get_qi_session", lambda: "dummy_session")
|
|
|
|
# Initialize state to set up signal handlers
|
|
state.initialize()
|
|
|
|
# Simulate SIGINT
|
|
signal_handler = signal.getsignal(signal.SIGINT)
|
|
signal_handler(None, None)
|
|
|
|
# Exit event should be set
|
|
assert state.exit_event.is_set()
|