Clock_out_Time_Calculator/_i18n_gui_test.py

159 lines
4.9 KiB
Python

"""
i18n GUI 검증: 언어 전환 시 UI 라벨이 실제로 바뀌는지.
동일 SettingsView를 한국어로 만들고 확인 → 영어로 만들고 확인.
(런타임 언어 전환은 위젯 재생성을 요구하므로 새 인스턴스로 검증)
"""
import os
import sys
import tempfile
os.environ['QT_QPA_PLATFORM'] = 'offscreen'
os.environ['CLOCKOUT_DISABLE_HOLIDAY_SYNC'] = '1'
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
from PyQt5.QtWidgets import QApplication, QPushButton, QGroupBox
app = QApplication.instance() or QApplication(sys.argv)
from core.database import Database
from core.i18n import set_language
db_path = os.path.join(tempfile.gettempdir(), 'clockout_i18n.db')
if os.path.exists(db_path):
os.remove(db_path)
db = Database(db_path)
PASS, FAIL = [], []
def case(label, fn):
try:
fn()
PASS.append(label)
print(f"[PASS] {label}")
except Exception as e:
FAIL.append((label, f"{type(e).__name__}: {e}"))
print(f"[FAIL] {label}: {type(e).__name__}: {e}")
def find_button_text(widget, text_substring):
for btn in widget.findChildren(QPushButton):
if text_substring in btn.text():
return btn
return None
def find_groupbox_title(widget, title_substring):
for gb in widget.findChildren(QGroupBox):
if title_substring in gb.title():
return gb
return None
def test_settings_korean_labels():
"""한국어 모드에서 SettingsView 라벨 검증."""
set_language('ko')
from ui.settings_view import SettingsView
dlg = SettingsView(db=db)
# 윈도우 제목
assert '설정' in dlg.windowTitle(), f"title: {dlg.windowTitle()}"
# 그룹박스
assert find_groupbox_title(dlg, '근무 시간') is not None
assert find_groupbox_title(dlg, '연장근무') is not None
assert find_groupbox_title(dlg, '데이터') is not None
# 저장 버튼
save_btn = find_button_text(dlg, '저장')
assert save_btn is not None
dlg.deleteLater()
def test_settings_english_labels():
"""영어 모드에서 SettingsView 라벨 검증."""
set_language('en')
from ui.settings_view import SettingsView
dlg = SettingsView(db=db)
assert 'Settings' in dlg.windowTitle()
assert find_groupbox_title(dlg, 'Work Time') is not None
assert find_groupbox_title(dlg, 'Overtime') is not None
assert find_groupbox_title(dlg, 'Data') is not None
save_btn = find_button_text(dlg, 'Save')
assert save_btn is not None
dlg.deleteLater()
set_language('ko') # 원복
def test_main_window_language():
"""MainWindow 라벨 — 한국어 / 영어"""
set_language('ko')
from ui.main_window import MainWindow
w = MainWindow()
assert '퇴근시간' in w.windowTitle()
# 메뉴 버튼: 통계/캘린더/일일보고/도움말/설정/퇴근하기
assert find_button_text(w, '통계') is not None
assert find_button_text(w, '캘린더') is not None
assert find_button_text(w, '도움말') is not None
assert find_button_text(w, '점심') is not None
w.deleteLater()
def test_mini_widget_language():
set_language('ko')
from ui.mini_widget import MiniWidget
w = MiniWidget()
assert '남은 시간' in w.title_label.text()
w.update_remaining('+00:30:00')
assert '추가' in w.title_label.text()
w.deleteLater()
set_language('en')
w2 = MiniWidget()
assert 'Remaining' in w2.title_label.text()
w2.update_remaining('+00:30:00')
assert 'Overtime' in w2.title_label.text()
w2.deleteLater()
set_language('ko')
def test_notifier_language():
"""알림 메시지가 언어에 맞춰 나오는지"""
set_language('ko')
from core.notifier import Notifier
from datetime import datetime, timedelta
n = Notifier(db=db)
fired = []
n.notification_signal.connect(lambda t, m: fired.append((t, m)))
n.check_clock_out_soon(datetime.now() + timedelta(minutes=20), datetime.now())
assert len(fired) == 1
assert '퇴근' in fired[0][0]
set_language('en')
n2 = Notifier(db=db)
fired2 = []
n2.notification_signal.connect(lambda t, m: fired2.append((t, m)))
n2.check_clock_out_soon(datetime.now() + timedelta(minutes=20), datetime.now())
assert len(fired2) == 1
assert 'Clock-out' in fired2[0][0]
set_language('ko')
case("I18N-1. SettingsView 한국어 라벨", test_settings_korean_labels)
case("I18N-2. SettingsView 영어 라벨", test_settings_english_labels)
case("I18N-3. MainWindow 한국어 (메뉴/버튼)", test_main_window_language)
case("I18N-4. MiniWidget ko/en 전환 후 라벨", test_mini_widget_language)
case("I18N-5. Notifier 알림 메시지 ko/en", test_notifier_language)
print()
print("=" * 60)
print(f"PASS: {len(PASS)} FAIL: {len(FAIL)}")
if FAIL:
print("\nFAILED:")
for label, err in FAIL:
print(f" - {label}: {err}")
if os.path.exists(db_path):
try: os.remove(db_path)
except: pass
sys.exit(1 if FAIL else 0)