"""Unit tests for attendance processor."""
import unittest
from datetime import datetime
from attendance_app.processor import AttendanceProcessor
from attendance_app.database import MockUserDatabase
class TestAttendanceProcessor(unittest.TestCase):
"""Test AttendanceProcessor class."""
def setUp(self):
"""Set up test fixtures."""
# Mock user database
self.mock_users = {
'user123': ('S001', 'Taro Yamada', 'ヤマダ タロウ', 'CS', '01'),
'user456': ('S002', 'Hanako Tanaka', 'タナカ ハナコ', 'AM', '01'),
'staff1': ('M001', 'Ken Sato', 'サトウ ケン', 'Staff', '02'),
}
self.db = MockUserDatabase(self.mock_users)
self.processor = AttendanceProcessor(self.db.lookup_user)
def test_simple_login_logout(self):
"""Test simple login and logout."""
events = {
'GRL-01': [
[datetime(2024, 11, 27, 14, 30), 'on:user123'],
[datetime(2024, 11, 27, 16, 30), 'off:user123'],
]
}
from_time = datetime(2024, 11, 27, 14, 0)
to_time = datetime(2024, 11, 27, 17, 0)
results = self.processor.process_events(events, from_time, to_time)
self.assertEqual(len(results), 1)
record = results[0]
self.assertEqual(record[0], 'GRL-01') # machine
self.assertEqual(record[1], '14:30〜16:30') # time range
self.assertEqual(record[4], 'user123') # user_id
self.assertEqual(record[5], 'S001') # student_no
self.assertEqual(record[6], 'Taro Yamada') # name
def test_login_without_logout(self):
"""Test login without matching logout."""
events = {
'GRL-01': [
[datetime(2024, 11, 27, 14, 30), 'on:user123'],
]
}
from_time = datetime(2024, 11, 27, 14, 0)
to_time = datetime(2024, 11, 27, 17, 0)
results = self.processor.process_events(events, from_time, to_time)
self.assertEqual(len(results), 1)
record = results[0]
self.assertEqual(record[2], '---') # logout time missing
def test_orphaned_logout(self):
"""Test logout without matching login."""
events = {
'GRL-01': [
[datetime(2024, 11, 27, 16, 30), 'off:user123'],
]
}
from_time = datetime(2024, 11, 27, 14, 0)
to_time = datetime(2024, 11, 27, 17, 0)
results = self.processor.process_events(events, from_time, to_time)
self.assertEqual(len(results), 1)
record = results[0]
self.assertTrue(record[1].startswith('?〜')) # login time unknown
def test_double_login_rejection(self):
"""Test double login rejection."""
events = {
'GRL-01': [
[datetime(2024, 11, 27, 14, 30), 'on:user123'],
[datetime(2024, 11, 27, 14, 35), 'reject:user123:GRL-02'],
]
}
from_time = datetime(2024, 11, 27, 14, 0)
to_time = datetime(2024, 11, 27, 17, 0)
results = self.processor.process_events(events, from_time, to_time)
# Login should be rejected (removed)
self.assertEqual(len(results), 0)
def test_startup_as_implicit_logout(self):
"""Test startup event as implicit logout."""
events = {
'GRL-01': [
[datetime(2024, 11, 27, 14, 30), 'on:user123'],
[datetime(2024, 11, 27, 16, 0), 'startup'],
]
}
from_time = datetime(2024, 11, 27, 14, 0)
to_time = datetime(2024, 11, 27, 17, 0)
results = self.processor.process_events(events, from_time, to_time)
self.assertEqual(len(results), 1)
record = results[0]
self.assertEqual(record[2], '16:00') # logout from startup
def test_shutdown_as_implicit_logout(self):
"""Test shutdown event as implicit logout."""
events = {
'GRL-01': [
[datetime(2024, 11, 27, 14, 30), 'on:user123'],
[datetime(2024, 11, 27, 18, 0), 'shutdown'],
]
}
from_time = datetime(2024, 11, 27, 14, 0)
to_time = datetime(2024, 11, 27, 19, 0)
results = self.processor.process_events(events, from_time, to_time)
self.assertEqual(len(results), 1)
record = results[0]
self.assertEqual(record[2], '18:00')
def test_unknown_user(self):
"""Test handling of unknown user."""
events = {
'GRL-01': [
[datetime(2024, 11, 27, 14, 30), 'on:unknown'],
]
}
from_time = datetime(2024, 11, 27, 14, 0)
to_time = datetime(2024, 11, 27, 17, 0)
results = self.processor.process_events(events, from_time, to_time)
self.assertEqual(len(results), 1)
record = results[0]
self.assertEqual(record[5], '????') # unknown student number
self.assertEqual(record[6], 'unknown') # user_id as name
def test_multiple_machines(self):
"""Test events from multiple machines."""
events = {
'GRL-01': [
[datetime(2024, 11, 27, 14, 30), 'on:user123'],
[datetime(2024, 11, 27, 16, 30), 'off:user123'],
],
'ML1-05': [
[datetime(2024, 11, 27, 15, 0), 'on:user456'],
[datetime(2024, 11, 27, 16, 0), 'off:user456'],
]
}
from_time = datetime(2024, 11, 27, 14, 0)
to_time = datetime(2024, 11, 27, 17, 0)
results = self.processor.process_events(events, from_time, to_time)
self.assertEqual(len(results), 2)
machines = [r[0] for r in results]
self.assertIn('GRL-01', machines)
self.assertIn('ML1-05', machines)
class TestFilterByRooms(unittest.TestCase):
"""Test room filtering."""
def setUp(self):
"""Set up test fixtures."""
mock_users = {'user123': ('S001', 'Test User', 'テスト', 'CS', '01')}
self.db = MockUserDatabase(mock_users)
self.processor = AttendanceProcessor(self.db.lookup_user)
def test_filter_grl_room(self):
"""Test filtering by GRL room."""
records = [
['GRL-01', '14:30', '16:30', 'on', 'user123', 'S001', 'Test', 'テスト', 'CS', '01', ''],
['ML1-01', '14:30', '16:30', 'on', 'user123', 'S001', 'Test', 'テスト', 'CS', '01', ''],
]
room_filters = {'GRL': True, 'ML1': False, 'ML2': False, 'IML-A': False, 'IML-B': False}
filtered = self.processor.filter_by_rooms(records, room_filters)
self.assertEqual(len(filtered), 1)
self.assertEqual(filtered[0][0], 'GRL-01')
def test_filter_iml_subrooms(self):
"""Test filtering IML sub-rooms."""
records = [
['IML-01', '14:30', '16:30', 'on', 'user123', 'S001', 'Test', 'テスト', 'CS', '01', ''], # Room A
['IML-62', '14:30', '16:30', 'on', 'user123', 'S001', 'Test', 'テスト', 'CS', '01', ''], # Room B
]
# Test IML-A only
room_filters = {'GRL': False, 'ML1': False, 'ML2': False, 'IML-A': True, 'IML-B': False}
filtered = self.processor.filter_by_rooms(records, room_filters)
self.assertEqual(len(filtered), 1)
self.assertEqual(filtered[0][0], 'IML-01')
# Test IML-B only
room_filters = {'GRL': False, 'ML1': False, 'ML2': False, 'IML-A': False, 'IML-B': True}
filtered = self.processor.filter_by_rooms(records, room_filters)
self.assertEqual(len(filtered), 1)
self.assertEqual(filtered[0][0], 'IML-62')
def test_unique_users_filter(self):
"""Test unique users filtering."""
records = [
['GRL-01', '14:30', '15:30', 'on', 'user123', 'S001', 'Test', 'テスト', 'CS', '01', ''],
['GRL-02', '15:45', '16:30', 'on', 'user123', 'S001', 'Test', 'テスト', 'CS', '01', ''],
]
room_filters = {'GRL': True, 'ML1': False, 'ML2': False, 'IML-A': False, 'IML-B': False}
# Without unique filter
filtered = self.processor.filter_by_rooms(records, room_filters, unique_users=False)
self.assertEqual(len(filtered), 2)
# With unique filter
filtered = self.processor.filter_by_rooms(records, room_filters, unique_users=True)
self.assertEqual(len(filtered), 1)
if __name__ == '__main__':
unittest.main()