""" Unit tests for reactor modules: Phaser, Procession, Fission, States """ import pytest from datetime import datetime, timezone from enum import Enum from src.heurams.kernel.reactor.phaser import Phaser from src.heurams.kernel.reactor.procession import Procession from src.heurams.kernel.reactor.fission import Fission from src.heurams.kernel.reactor.states import States from src.heurams.kernel.particles.atom import Atom from src.heurams.kernel.particles.nucleon import Nucleon from src.heurams.kernel.particles.electron import Electron from src.heurams.kernel.particles.orbital import Orbital class TestStates: """Test cases for States enum.""" def test_states_enum_values(self): """Test that States enum has correct values.""" assert States.IDLE.value == "idle" assert States.LEARNING.value == "learning" assert States.REVIEW.value == "review" assert States.FINISHED.value == "finished" def test_states_enum_membership(self): """Test States enum membership.""" assert isinstance(States.IDLE, Enum) assert States.LEARNING in States assert States.REVIEW in States assert States.FINISHED in States class TestPhaser: """Test cases for Phaser class.""" def test_phaser_creation(self): """Test Phaser creation.""" phaser = Phaser() assert phaser.current_state == States.IDLE assert phaser.atom is None assert phaser.puzzle is None def test_phaser_initialize(self): """Test Phaser initialization with atom.""" phaser = Phaser() nucleon = Nucleon(content="Test", answer="Answer") electron = Electron() orbital = Orbital() atom = Atom(nucleon=nucleon, electron=electron, orbital=orbital) phaser.initialize(atom) assert phaser.atom == atom assert phaser.current_state == States.LEARNING def test_phaser_transition_to_review(self): """Test transition to review state.""" phaser = Phaser() nucleon = Nucleon(content="Test", answer="Answer") electron = Electron() orbital = Orbital() atom = Atom(nucleon=nucleon, electron=electron, orbital=orbital) phaser.initialize(atom) phaser.transition_to_review() assert phaser.current_state == States.REVIEW def test_phaser_transition_to_finished(self): """Test transition to finished state.""" phaser = Phaser() nucleon = Nucleon(content="Test", answer="Answer") electron = Electron() orbital = Orbital() atom = Atom(nucleon=nucleon, electron=electron, orbital=orbital) phaser.initialize(atom) phaser.transition_to_finished() assert phaser.current_state == States.FINISHED def test_phaser_reset(self): """Test Phaser reset.""" phaser = Phaser() nucleon = Nucleon(content="Test", answer="Answer") electron = Electron() orbital = Orbital() atom = Atom(nucleon=nucleon, electron=electron, orbital=orbital) phaser.initialize(atom) phaser.transition_to_review() phaser.reset() assert phaser.current_state == States.IDLE assert phaser.atom is None assert phaser.puzzle is None def test_phaser_set_puzzle(self): """Test setting puzzle in Phaser.""" phaser = Phaser() test_puzzle = {"question": "Test?", "answer": "Test", "type": "test"} phaser.set_puzzle(test_puzzle) assert phaser.puzzle == test_puzzle def test_phaser_validation(self): """Test input validation for Phaser.""" phaser = Phaser() # Test initialize with None with pytest.raises(TypeError): phaser.initialize(None) # Test initialize with invalid type with pytest.raises(TypeError): phaser.initialize("not an atom") class TestProcession: """Test cases for Procession class.""" def test_procession_creation(self): """Test Procession creation.""" procession = Procession() assert procession.queue == [] assert procession.current_index == 0 def test_procession_add_atom(self): """Test adding atom to procession.""" procession = Procession() nucleon = Nucleon(content="Test", answer="Answer") electron = Electron() orbital = Orbital() atom = Atom(nucleon=nucleon, electron=electron, orbital=orbital) procession.add_atom(atom) assert len(procession.queue) == 1 assert procession.queue[0] == atom def test_procession_add_multiple_atoms(self): """Test adding multiple atoms to procession.""" procession = Procession() atoms = [] for i in range(3): nucleon = Nucleon(content=f"Test{i}", answer=f"Answer{i}") electron = Electron() orbital = Orbital() atom = Atom(nucleon=nucleon, electron=electron, orbital=orbital) atoms.append(atom) for atom in atoms: procession.add_atom(atom) assert len(procession.queue) == 3 assert procession.queue == atoms def test_procession_get_current_atom(self): """Test getting current atom.""" procession = Procession() nucleon = Nucleon(content="Test", answer="Answer") electron = Electron() orbital = Orbital() atom = Atom(nucleon=nucleon, electron=electron, orbital=orbital) procession.add_atom(atom) current_atom = procession.get_current_atom() assert current_atom == atom def test_procession_get_current_atom_empty(self): """Test getting current atom from empty procession.""" procession = Procession() current_atom = procession.get_current_atom() assert current_atom is None def test_procession_move_next(self): """Test moving to next atom.""" procession = Procession() atoms = [] for i in range(3): nucleon = Nucleon(content=f"Test{i}", answer=f"Answer{i}") electron = Electron() orbital = Orbital() atom = Atom(nucleon=nucleon, electron=electron, orbital=orbital) atoms.append(atom) procession.add_atom(atom) # Start at first atom assert procession.get_current_atom() == atoms[0] assert procession.current_index == 0 # Move to next procession.move_next() assert procession.get_current_atom() == atoms[1] assert procession.current_index == 1 # Move to next again procession.move_next() assert procession.get_current_atom() == atoms[2] assert procession.current_index == 2 # Move beyond end procession.move_next() assert procession.get_current_atom() is None assert procession.current_index == 3 def test_procession_has_next(self): """Test checking if there are more atoms.""" procession = Procession() nucleon = Nucleon(content="Test", answer="Answer") electron = Electron() orbital = Orbital() atom = Atom(nucleon=nucleon, electron=electron, orbital=orbital) procession.add_atom(atom) # Initially has next (current is first, can move to next) assert procession.has_next() is True # Move to next (beyond the only atom) procession.move_next() assert procession.has_next() is False def test_procession_is_empty(self): """Test checking if procession is empty.""" procession = Procession() assert procession.is_empty() is True nucleon = Nucleon(content="Test", answer="Answer") electron = Electron() orbital = Orbital() atom = Atom(nucleon=nucleon, electron=electron, orbital=orbital) procession.add_atom(atom) assert procession.is_empty() is False def test_procession_clear(self): """Test clearing procession.""" procession = Procession() nucleon = Nucleon(content="Test", answer="Answer") electron = Electron() orbital = Orbital() atom = Atom(nucleon=nucleon, electron=electron, orbital=orbital) procession.add_atom(atom) procession.clear() assert procession.queue == [] assert procession.current_index == 0 def test_procession_validation(self): """Test input validation for Procession.""" procession = Procession() # Test add_atom with None with pytest.raises(TypeError): procession.add_atom(None) # Test add_atom with invalid type with pytest.raises(TypeError): procession.add_atom("not an atom") class TestFission: """Test cases for Fission class.""" def test_fission_creation(self): """Test Fission creation.""" fission = Fission() assert fission.phaser is not None assert isinstance(fission.phaser, Phaser) def test_fission_initialize(self): """Test Fission initialization.""" fission = Fission() nucleon = Nucleon(content="Test", answer="Answer") electron = Electron() orbital = Orbital() atom = Atom(nucleon=nucleon, electron=electron, orbital=orbital) fission.initialize(atom) assert fission.phaser.atom == atom assert fission.phaser.current_state == States.LEARNING def test_fission_generate_learning_puzzle_cloze(self): """Test generating learning puzzle with cloze content.""" fission = Fission() nucleon = Nucleon( content="The capital of {{c1::France}} is Paris.", answer="France" ) electron = Electron() orbital = Orbital() atom = Atom(nucleon=nucleon, electron=electron, orbital=orbital) fission.initialize(atom) puzzle = fission.generate_learning_puzzle() assert puzzle is not None assert "question" in puzzle assert "answer" in puzzle assert "type" in puzzle def test_fission_generate_learning_puzzle_mcq(self): """Test generating learning puzzle with MCQ content.""" fission = Fission() nucleon = Nucleon( content="What is the capital of France?", answer="Paris" ) electron = Electron() orbital = Orbital() atom = Atom(nucleon=nucleon, electron=electron, orbital=orbital) fission.initialize(atom) puzzle = fission.generate_learning_puzzle() assert puzzle is not None assert "question" in puzzle assert "options" in puzzle assert "correct_index" in puzzle assert "type" in puzzle def test_fission_generate_review_puzzle(self): """Test generating review puzzle.""" fission = Fission() nucleon = Nucleon( content="What is the capital of France?", answer="Paris" ) electron = Electron(interval=10, repetitions=5) # In review phase orbital = Orbital() atom = Atom(nucleon=nucleon, electron=electron, orbital=orbital) fission.initialize(atom) fission.phaser.transition_to_review() puzzle = fission.generate_review_puzzle() assert puzzle is not None assert "question" in puzzle def test_fission_process_answer_correct(self): """Test processing correct answer.""" fission = Fission() nucleon = Nucleon(content="Test", answer="Answer") electron = Electron() orbital = Orbital() atom = Atom(nucleon=nucleon, electron=electron, orbital=orbital) fission.initialize(atom) result = fission.process_answer("Answer") assert "success" in result assert "quality" in result assert "next_state" in result assert result["success"] is True def test_fission_process_answer_incorrect(self): """Test processing incorrect answer.""" fission = Fission() nucleon = Nucleon(content="Test", answer="Answer") electron = Electron() orbital = Orbital() atom = Atom(nucleon=nucleon, electron=electron, orbital=orbital) fission.initialize(atom) result = fission.process_answer("Wrong") assert result["success"] is False def test_fission_get_current_state(self): """Test getting current state.""" fission = Fission() nucleon = Nucleon(content="Test", answer="Answer") electron = Electron() orbital = Orbital() atom = Atom(nucleon=nucleon, electron=electron, orbital=orbital) fission.initialize(atom) state = fission.get_current_state() assert state == States.LEARNING def test_fission_validation(self): """Test input validation for Fission.""" fission = Fission() # Test initialize with None with pytest.raises(TypeError): fission.initialize(None) # Test process_answer without initialization with pytest.raises(RuntimeError): fission.process_answer("test") # Test generate_learning_puzzle without initialization with pytest.raises(RuntimeError): fission.generate_learning_puzzle() # Test generate_review_puzzle without initialization with pytest.raises(RuntimeError): fission.generate_review_puzzle()