mirror of
https://github.com/Yonokid/PyTaiko.git
synced 2026-02-04 19:50:12 +01:00
290 lines
11 KiB
Python
290 lines
11 KiB
Python
import unittest
|
|
from unittest.mock import Mock, patch
|
|
|
|
from libs.global_data import PlayerNum
|
|
from libs.global_objects import (
|
|
AllNetIcon,
|
|
CoinOverlay,
|
|
EntryOverlay,
|
|
Indicator,
|
|
Nameplate,
|
|
Timer,
|
|
)
|
|
|
|
|
|
class TestNameplate(unittest.TestCase):
|
|
"""Test cases for the Nameplate class."""
|
|
|
|
def setUp(self):
|
|
"""Set up test fixtures."""
|
|
# Mock global_tex and its methods
|
|
self.mock_tex = Mock()
|
|
self.mock_tex.skin_config = {
|
|
"nameplate_text_name": Mock(font_size=20, x=100, y=50, width=200),
|
|
"nameplate_text_title": Mock(font_size=16, x=100, y=80, width=150),
|
|
"nameplate_title_offset": Mock(x=10),
|
|
"nameplate_dan_offset": Mock(x=20)
|
|
}
|
|
self.mock_tex.get_animation = Mock(return_value=Mock(start=Mock(), update=Mock(), is_finished=False))
|
|
|
|
@patch('libs.global_objects.global_tex')
|
|
@patch('libs.global_objects.OutlinedText')
|
|
def test_initialization_basic(self, mock_text, mock_global_tex):
|
|
"""Test basic nameplate initialization."""
|
|
mock_global_tex.skin_config = self.mock_tex.skin_config
|
|
|
|
nameplate = Nameplate("TestPlayer", "TestTitle", PlayerNum.P1, 5, False, False, 0)
|
|
|
|
self.assertEqual(nameplate.dan_index, 5)
|
|
self.assertEqual(nameplate.player_num, 1)
|
|
self.assertFalse(nameplate.is_gold)
|
|
self.assertFalse(nameplate.is_rainbow)
|
|
self.assertEqual(nameplate.title_bg, 0)
|
|
|
|
@patch('libs.global_objects.global_tex')
|
|
@patch('libs.global_objects.OutlinedText')
|
|
def test_initialization_rainbow(self, mock_text, mock_global_tex):
|
|
"""Test rainbow nameplate initialization."""
|
|
mock_global_tex.skin_config = self.mock_tex.skin_config
|
|
mock_animation = Mock()
|
|
mock_global_tex.get_animation.return_value = mock_animation
|
|
|
|
nameplate = Nameplate("Player", "Title", PlayerNum.P1, 3, False, True, 0)
|
|
|
|
self.assertTrue(nameplate.is_rainbow)
|
|
mock_global_tex.get_animation.assert_called_once_with(12)
|
|
mock_animation.start.assert_called_once()
|
|
|
|
@patch('libs.global_objects.global_tex')
|
|
def test_update_rainbow_animation(self, mock_global_tex):
|
|
"""Test rainbow animation update logic."""
|
|
mock_animation = Mock(is_finished=False, update=Mock())
|
|
mock_global_tex.get_animation.return_value = mock_animation
|
|
mock_global_tex.skin_config = self.mock_tex.skin_config
|
|
|
|
with patch('libs.global_objects.OutlinedText'):
|
|
nameplate = Nameplate("P", "T", PlayerNum.P1, 0, False, True, 0)
|
|
nameplate.update(1000.0)
|
|
|
|
mock_animation.update.assert_called_once_with(1000.0)
|
|
|
|
@patch('libs.global_objects.global_tex')
|
|
def test_update_rainbow_restart(self, mock_global_tex):
|
|
"""Test rainbow animation restarts when finished."""
|
|
mock_animation = Mock(is_finished=True, update=Mock(), restart=Mock())
|
|
mock_global_tex.get_animation.return_value = mock_animation
|
|
mock_global_tex.skin_config = self.mock_tex.skin_config
|
|
|
|
with patch('libs.global_objects.OutlinedText'):
|
|
nameplate = Nameplate("P", "T", PlayerNum.P1, 0, False, True, 0)
|
|
nameplate.update(1000.0)
|
|
|
|
mock_animation.restart.assert_called_once()
|
|
|
|
@patch('libs.global_objects.global_tex')
|
|
def test_unload(self, mock_global_tex):
|
|
"""Test nameplate resource cleanup."""
|
|
mock_global_tex.skin_config = self.mock_tex.skin_config
|
|
|
|
with patch('libs.global_objects.OutlinedText') as mock_text:
|
|
mock_name = Mock()
|
|
mock_title = Mock()
|
|
mock_text.side_effect = [mock_name, mock_title]
|
|
|
|
nameplate = Nameplate("P", "T", PlayerNum.P1, 0, False, False, 0)
|
|
nameplate.unload()
|
|
|
|
mock_name.unload.assert_called_once()
|
|
mock_title.unload.assert_called_once()
|
|
|
|
|
|
class TestIndicator(unittest.TestCase):
|
|
"""Test cases for the Indicator class."""
|
|
|
|
@patch('libs.global_objects.global_tex')
|
|
@patch('libs.global_objects.OutlinedText')
|
|
def test_initialization(self, mock_text, mock_global_tex):
|
|
"""Test indicator initialization with different states."""
|
|
mock_global_tex.get_animation.return_value = Mock()
|
|
mock_global_tex.skin_config = {"indicator_text": Mock(text={"en": "Select"}, font_size=20)}
|
|
|
|
with patch('libs.global_objects.global_data') as mock_data:
|
|
mock_data.config = {"general": {"language": "en"}}
|
|
|
|
indicator = Indicator(Indicator.State.SELECT)
|
|
|
|
self.assertEqual(indicator.state, Indicator.State.SELECT)
|
|
self.assertEqual(mock_global_tex.get_animation.call_count, 3)
|
|
|
|
@patch('libs.global_objects.global_tex')
|
|
def test_update_animations(self, mock_global_tex):
|
|
"""Test that all animations update correctly."""
|
|
mock_don_fade = Mock()
|
|
mock_arrow_move = Mock()
|
|
mock_arrow_fade = Mock()
|
|
mock_global_tex.get_animation.side_effect = [mock_don_fade, mock_arrow_move, mock_arrow_fade]
|
|
mock_global_tex.skin_config = {"indicator_text": Mock(text={"en": "S"}, font_size=20)}
|
|
|
|
with patch('libs.global_objects.global_data.config', {"general": {"language": "en"}}):
|
|
with patch('libs.global_objects.OutlinedText'):
|
|
indicator = Indicator(Indicator.State.SKIP)
|
|
indicator.update(500.0)
|
|
|
|
mock_don_fade.update.assert_called_once_with(500.0)
|
|
mock_arrow_move.update.assert_called_once_with(500.0)
|
|
mock_arrow_fade.update.assert_called_once_with(500.0)
|
|
|
|
|
|
class TestTimer(unittest.TestCase):
|
|
"""Test cases for the Timer class."""
|
|
|
|
@patch('libs.global_objects.get_config')
|
|
@patch('libs.global_objects.global_tex')
|
|
def test_initialization(self, mock_tex, mock_config):
|
|
"""Test timer initialization."""
|
|
mock_config.return_value = {"general": {"timer_frozen": False}}
|
|
mock_tex.get_animation.return_value = Mock()
|
|
mock_func = Mock()
|
|
|
|
timer = Timer(30, 0.0, mock_func)
|
|
|
|
self.assertEqual(timer.time, 30)
|
|
self.assertEqual(timer.counter, "30")
|
|
self.assertFalse(timer.is_finished)
|
|
self.assertFalse(timer.is_frozen)
|
|
|
|
@patch('libs.global_objects.audio')
|
|
@patch('libs.global_objects.get_config')
|
|
@patch('libs.global_objects.global_tex')
|
|
def test_countdown_normal(self, mock_tex, mock_config, mock_audio):
|
|
"""Test normal countdown behavior."""
|
|
mock_config.return_value = {"general": {"timer_frozen": False}}
|
|
mock_tex.get_animation.return_value = Mock(update=Mock(), start=Mock())
|
|
mock_func = Mock()
|
|
|
|
timer = Timer(15, 0.0, mock_func)
|
|
timer.update(1000.0)
|
|
|
|
self.assertEqual(timer.time, 14)
|
|
self.assertEqual(timer.counter, "14")
|
|
|
|
@patch('libs.global_objects.audio')
|
|
@patch('libs.global_objects.get_config')
|
|
@patch('libs.global_objects.global_tex')
|
|
def test_countdown_below_ten(self, mock_tex, mock_config, mock_audio):
|
|
"""Test countdown triggers animations below 10."""
|
|
mock_config.return_value = {"general": {"timer_frozen": False}}
|
|
mock_animation = Mock(update=Mock(), start=Mock())
|
|
mock_tex.get_animation.return_value = mock_animation
|
|
mock_func = Mock()
|
|
|
|
timer = Timer(10, 0.0, mock_func)
|
|
timer.update(1000.0)
|
|
|
|
self.assertEqual(timer.time, 9)
|
|
mock_audio.play_sound.assert_called_with('timer_blip', 'sound')
|
|
self.assertEqual(mock_animation.start.call_count, 3)
|
|
|
|
@patch('libs.global_objects.audio')
|
|
@patch('libs.global_objects.get_config')
|
|
@patch('libs.global_objects.global_tex')
|
|
def test_voice_triggers(self, mock_tex, mock_config, mock_audio):
|
|
"""Test voice announcements at specific times."""
|
|
mock_config.return_value = {"general": {"timer_frozen": False}}
|
|
mock_tex.get_animation.return_value = Mock(update=Mock(), start=Mock())
|
|
mock_func = Mock()
|
|
|
|
# Test 10 second voice
|
|
timer = Timer(11, 0.0, mock_func)
|
|
timer.update(1000.0)
|
|
mock_audio.play_sound.assert_called_with('voice_timer_10', 'voice')
|
|
|
|
# Test 5 second voice
|
|
timer = Timer(6, 0.0, mock_func)
|
|
timer.update(1000.0)
|
|
mock_audio.play_sound.assert_called_with('voice_timer_5', 'voice')
|
|
|
|
@patch('libs.global_objects.audio')
|
|
@patch('libs.global_objects.get_config')
|
|
@patch('libs.global_objects.global_tex')
|
|
def test_timer_finish_callback(self, mock_tex, mock_config, mock_audio):
|
|
"""Test callback is triggered when timer reaches zero."""
|
|
mock_config.return_value = {"general": {"timer_frozen": False}}
|
|
mock_tex.get_animation.return_value = Mock(update=Mock(), start=Mock())
|
|
mock_audio.is_sound_playing.return_value = False
|
|
mock_func = Mock()
|
|
|
|
timer = Timer(1, 0.0, mock_func)
|
|
timer.update(1000.0)
|
|
timer.update(2000.0)
|
|
|
|
mock_func.assert_called_once()
|
|
self.assertTrue(timer.is_finished)
|
|
|
|
@patch('libs.global_objects.get_config')
|
|
@patch('libs.global_objects.global_tex')
|
|
def test_timer_frozen(self, mock_tex, mock_config):
|
|
"""Test frozen timer doesn't count down."""
|
|
mock_config.return_value = {"general": {"timer_frozen": True}}
|
|
mock_tex.get_animation.return_value = Mock(update=Mock())
|
|
mock_func = Mock()
|
|
|
|
timer = Timer(10, 0.0, mock_func)
|
|
initial_time = timer.time
|
|
timer.update(1000.0)
|
|
|
|
self.assertEqual(timer.time, initial_time)
|
|
|
|
|
|
class TestCoinOverlay(unittest.TestCase):
|
|
"""Test cases for the CoinOverlay class."""
|
|
|
|
@patch('libs.global_objects.global_tex')
|
|
@patch('libs.global_objects.global_data')
|
|
@patch('libs.global_objects.OutlinedText')
|
|
def test_initialization(self, mock_text, mock_data, mock_tex):
|
|
"""Test coin overlay initialization."""
|
|
mock_tex.skin_config = {
|
|
"free_play": Mock(text={"en": "Free Play"}, font_size=24, y=100)
|
|
}
|
|
mock_data.config = {"general": {"language": "en"}}
|
|
|
|
_ = CoinOverlay()
|
|
|
|
mock_text.assert_called_once()
|
|
|
|
|
|
class TestAllNetIcon(unittest.TestCase):
|
|
"""Test cases for the AllNetIcon class."""
|
|
|
|
@patch('libs.global_objects.get_config')
|
|
def test_initialization_offline(self, mock_config):
|
|
"""Test AllNet icon initializes offline."""
|
|
mock_config.return_value = {"general": {"fake_online": False}}
|
|
|
|
icon = AllNetIcon()
|
|
|
|
self.assertFalse(icon.online)
|
|
|
|
@patch('libs.global_objects.get_config')
|
|
def test_initialization_online(self, mock_config):
|
|
"""Test AllNet icon initializes online."""
|
|
mock_config.return_value = {"general": {"fake_online": True}}
|
|
|
|
icon = AllNetIcon()
|
|
|
|
self.assertTrue(icon.online)
|
|
|
|
|
|
class TestEntryOverlay(unittest.TestCase):
|
|
"""Test cases for the EntryOverlay class."""
|
|
|
|
@patch('libs.global_objects.get_config')
|
|
def test_initialization(self, mock_config):
|
|
"""Test entry overlay initialization."""
|
|
mock_config.return_value = {"general": {"fake_online": False}}
|
|
|
|
overlay = EntryOverlay()
|
|
|
|
self.assertFalse(overlay.online)
|