import unittest from pathlib import Path import os from sia.entry.single_entry import SingleEntry class SingleEntryTest(unittest.TestCase): def setUp(self): """Set up test cases with fixed id""" self.test_id = "test-id-1234" self.work_dir = Path(os.getcwd()) # Use current directory for tests # Create a temporary file for testing self.test_filename = "test_output.txt" self.cleanup_files() def tearDown(self): """Clean up any test files""" self.cleanup_files() def cleanup_files(self): """Helper to remove test files""" if os.path.exists(self.test_filename): os.remove(self.test_filename) def test_initialization(self): """Test entry initialization""" script = "echo test" entry = SingleEntry(self.test_id, self.work_dir, script, None, None) self.assertEqual(entry.script, script) self.assertEqual(entry.stdout, "") self.assertEqual(entry.stderr, "") self.assertIsNone(entry.exit_code) self.assertEqual(entry.id, self.test_id) self.assertFalse(entry.executed) self.assertFalse(entry.timed_out) def test_successful_execution(self): """Test successful script execution""" script = "echo 'test'" entry = SingleEntry(self.test_id, self.work_dir, script, None, None) entry.update() # Verify entry state self.assertEqual(entry.stdout.strip(), "test") self.assertEqual(entry.stderr, "") self.assertEqual(entry.exit_code, 0) self.assertTrue(entry.executed) def test_failed_execution(self): """Test failed script execution with invalid command""" entry = SingleEntry(self.test_id, self.work_dir, "nonexistentcommand", None, None) entry.update() # Verify entry state self.assertEqual(entry.stdout, "") self.assertTrue(len(entry.stderr) > 0) # Error message will vary by OS self.assertNotEqual(entry.exit_code, 0) # Exit code will be non-zero self.assertTrue(entry.executed) def test_file_creation(self): """Test script that creates a file""" script = f"echo 'test' > {self.test_filename}" entry = SingleEntry(self.test_id, self.work_dir, script, None, None) entry.update() # Verify file was created and contains expected content self.assertTrue(os.path.exists(self.test_filename)) with open(self.test_filename, 'r') as f: content = f.read().strip() self.assertEqual(content, "test") def test_single_execution(self): """Test that script only executes once""" script = f"echo 'test' >> {self.test_filename}" entry = SingleEntry(self.test_id, self.work_dir, script, None, None) # Run update multiple times entry.update() entry.update() entry.update() # Verify file only contains one line with open(self.test_filename, 'r') as f: lines = f.readlines() self.assertEqual(len(lines), 1) self.assertEqual(lines[0].strip(), "test") def test_generate_context_before_execution(self): """Test XML context generation before execution""" entry = SingleEntry(self.test_id, self.work_dir, "echo test", None, None) element = entry.generate_context() # Verify XML structure self.assertEqual(element.tag, "single") self.assertEqual(element.get("id"), self.test_id) self.assertEqual(element.text, "echo test") # Verify no output elements exist self.assertIsNone(element.find("stdout")) self.assertIsNone(element.find("stderr")) self.assertIsNone(element.get("exit_code")) def test_generate_context_after_execution(self): """Test XML context generation after execution""" script = "echo 'test'" entry = SingleEntry(self.test_id, self.work_dir, script, None, None) entry.update() element = entry.generate_context() # Verify XML structure self.assertEqual(element.tag, "single") self.assertEqual(element.get("id"), self.test_id) self.assertEqual(element.text, script) # Get stdout and verify content stdout_text = element.find("stdout").text self.assertEqual(stdout_text, "test\n") self.assertEqual(element.find("stderr").text, "") self.assertEqual(element.get("exit_code"), "0") def test_multiple_commands(self): """Test executing multiple commands in one script""" script = f"echo 'first' > {self.test_filename} && echo 'second' >> {self.test_filename}" entry = SingleEntry(self.test_id, self.work_dir, script, None, None) entry.update() # Verify file contains both lines with open(self.test_filename, 'r') as f: lines = f.readlines() self.assertEqual(len(lines), 2) self.assertEqual(lines[0].strip(), "first") self.assertEqual(lines[1].strip(), "second") def test_reset(self): """Test resetting the entry allows for reexecution""" script = f"echo 'test' > {self.test_filename}" entry = SingleEntry(self.test_id, self.work_dir, script, None, None) entry.update() # Verify initial execution self.assertTrue(entry.executed) self.assertTrue(os.path.exists(self.test_filename)) # Clean up file for retest os.remove(self.test_filename) # Reset and verify state entry.reset() self.assertFalse(entry.executed) self.assertFalse(entry.timed_out) self.assertEqual(entry.stdout, "") self.assertEqual(entry.stderr, "") self.assertIsNone(entry.exit_code) # Run again and verify second execution works entry.update() self.assertTrue(entry.executed) self.assertTrue(os.path.exists(self.test_filename)) def test_serialize(self): """Test serialization of the entry""" script = "echo 'test'" entry = SingleEntry(self.test_id, self.work_dir, script, None, None) # Check initial serialized state serialized = entry.serialize() self.assertEqual(serialized["type"], "single") self.assertEqual(serialized["id"], self.test_id) self.assertEqual(serialized["script"], script) self.assertEqual(serialized["executed"], False) # Update and check updated serialized state entry.update() serialized = entry.serialize() self.assertEqual(serialized["executed"], True) self.assertEqual(serialized["exit_code"], 0)