KINDNICK ff71886fd7 v2.7.0: i18n 100% + 런타임 retranslate + 테스트 +47 + 폴리싱
- i18n 사전 100% (break/overtime/leave/clockin) — 50+ 신규 키
- 런타임 재번역 인프라 (ui/i18n_runtime.py) — 재시작 없이 메인 UI 적용
- MealController 분리 — 점심/저녁 토글을 컨트롤러로 추출
- 통합 테스트 +15 (S36-S52: 온보딩/salary/CSV/notification dedupe 등)
- pytest 신규 4종 + i18n_runtime 테스트 (총 122 케이스, 90→122)
- README/INSTALL/CLAUDE/AGENTS v2.6+ 아키텍처 반영
2026-04-30 19:30:47 +09:00

99 lines
3.3 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
core.salary 단위 테스트 — 포괄임금제 외 시급 추정.
"""
import os
import sys
import pytest
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from core.salary import estimate_pay, format_won
class TestEstimatePay:
def test_zero_wage_returns_zero(self):
out = estimate_pay([{'total_hours': 8, 'overtime_minutes': 30}], 0)
assert out['base'] == 0
assert out['overtime'] == 0
assert out['total'] == 0
def test_negative_wage_returns_zero(self):
out = estimate_pay([{'total_hours': 8, 'overtime_minutes': 0}], -1000)
assert out['total'] == 0
def test_empty_records(self):
out = estimate_pay([], 10000)
assert out['base'] == 0
assert out['overtime'] == 0
assert out['total'] == 0
def test_basic_8h_no_overtime(self):
# 8h 정규 × 10000 = 80000
out = estimate_pay([{'total_hours': 8.0, 'overtime_minutes': 0}], 10000)
assert out['base'] == 80000
assert out['overtime'] == 0
assert out['total'] == 80000
def test_8h_with_30min_overtime(self):
# 정규 = 7.5h × 10000 = 75000
# 연장 = 0.5h × 10000 × 1.5 = 7500
out = estimate_pay(
[{'total_hours': 8.0, 'overtime_minutes': 30}],
hourly_wage=10000,
overtime_rate=1.5,
)
assert out['base'] == pytest.approx(75000)
assert out['overtime'] == pytest.approx(7500)
assert out['total'] == pytest.approx(82500)
def test_custom_overtime_rate(self):
# 연장 = 1h × 10000 × 2.0 = 20000
out = estimate_pay(
[{'total_hours': 9.0, 'overtime_minutes': 60}],
hourly_wage=10000,
overtime_rate=2.0,
)
assert out['overtime'] == pytest.approx(20000)
assert out['base'] == pytest.approx(80000)
def test_aggregated_multiple_records(self):
records = [
{'total_hours': 8.0, 'overtime_minutes': 0},
{'total_hours': 9.0, 'overtime_minutes': 60},
{'total_hours': 8.5, 'overtime_minutes': 30},
]
out = estimate_pay(records, hourly_wage=10000)
# base_hours = 8 + 8 + 8 = 24h
# overtime_hours = 0 + 1 + 0.5 = 1.5h
assert out['base_hours'] == pytest.approx(24.0)
assert out['overtime_hours'] == pytest.approx(1.5)
assert out['base'] == pytest.approx(240000)
assert out['overtime'] == pytest.approx(22500) # 1.5 * 10000 * 1.5
def test_missing_keys_default_zero(self):
out = estimate_pay([{}], 10000)
assert out['total'] == 0
def test_overtime_minutes_zero_when_negative_total(self):
# total - overtime이 음수가 되면 base는 0으로 클램프
out = estimate_pay(
[{'total_hours': 0.3, 'overtime_minutes': 60}], # 0.3h - 1h = -0.7
hourly_wage=10000,
)
assert out['base'] == 0
assert out['overtime'] == pytest.approx(15000)
class TestFormatWon:
@pytest.mark.parametrize("amount,expected", [
(0, '0원'),
(1000, '1,000원'),
(1234567, '1,234,567원'),
(999, '999원'),
(82500.4, '82,500원'), # round
(82500.6, '82,501원'),
])
def test_format(self, amount, expected):
assert format_won(amount) == expected