|
| 1 | +"""Functional tests for the genio module. |
| 2 | +
|
| 3 | +These tests validate the genio module in real-world file system scenarios, |
| 4 | +including cross-module interactions and integration patterns. |
| 5 | +""" |
| 6 | + |
| 7 | +import os |
| 8 | +import tempfile |
| 9 | +import unittest |
| 10 | + |
| 11 | +from avocado.utils import genio |
| 12 | +from selftests.utils import TestCaseTmpDir |
| 13 | + |
| 14 | + |
| 15 | +class TestGenioFileOperations(TestCaseTmpDir): |
| 16 | + """Functional tests for genio file read/write operations.""" |
| 17 | + |
| 18 | + def test_write_read_roundtrip(self): |
| 19 | + """Test writing and reading back produces identical content.""" |
| 20 | + test_file = os.path.join(self.tmpdir.name, "roundtrip.txt") |
| 21 | + original_content = "Line 1\nLine 2\nLine 3\n" |
| 22 | + genio.write_file(test_file, original_content) |
| 23 | + read_content = genio.read_file(test_file) |
| 24 | + self.assertEqual(read_content, original_content) |
| 25 | + |
| 26 | + def test_write_one_line_read_one_line_roundtrip(self): |
| 27 | + """Test write_one_line and read_one_line roundtrip.""" |
| 28 | + test_file = os.path.join(self.tmpdir.name, "one_line.txt") |
| 29 | + genio.write_one_line(test_file, "Single line content") |
| 30 | + line = genio.read_one_line(test_file) |
| 31 | + self.assertEqual(line, "Single line content") |
| 32 | + |
| 33 | + def test_append_builds_file_incrementally(self): |
| 34 | + """Test building a file incrementally with append operations.""" |
| 35 | + test_file = os.path.join(self.tmpdir.name, "incremental.txt") |
| 36 | + lines_to_add = ["First line", "Second line", "Third line"] |
| 37 | + for line in lines_to_add: |
| 38 | + genio.append_one_line(test_file, line) |
| 39 | + result_lines = genio.read_all_lines(test_file) |
| 40 | + self.assertEqual(result_lines, lines_to_add) |
| 41 | + |
| 42 | + def test_large_file_operations(self): |
| 43 | + """Test operations on larger files.""" |
| 44 | + test_file = os.path.join(self.tmpdir.name, "large.txt") |
| 45 | + # Create a file with 1000 lines |
| 46 | + lines = [f"Line {i}: {'x' * 80}" for i in range(1000)] |
| 47 | + content = "\n".join(lines) |
| 48 | + genio.write_file(test_file, content) |
| 49 | + read_content = genio.read_file(test_file) |
| 50 | + self.assertEqual(read_content, content) |
| 51 | + |
| 52 | + def test_unicode_file_operations(self): |
| 53 | + """Test file operations with unicode content.""" |
| 54 | + test_file = os.path.join(self.tmpdir.name, "unicode.txt") |
| 55 | + unicode_content = "日本語テスト\nПривет мир\n🎉 Emoji test 🚀\n" |
| 56 | + genio.write_file(test_file, unicode_content) |
| 57 | + read_content = genio.read_file(test_file) |
| 58 | + self.assertEqual(read_content, unicode_content) |
| 59 | + |
| 60 | + def test_special_characters_in_content(self): |
| 61 | + """Test file operations with special characters.""" |
| 62 | + test_file = os.path.join(self.tmpdir.name, "special.txt") |
| 63 | + special_content = "Tab:\tNewline:\\n\nBackslash:\\\nQuotes:\"'`\n" |
| 64 | + genio.write_file(test_file, special_content) |
| 65 | + read_content = genio.read_file(test_file) |
| 66 | + self.assertEqual(read_content, special_content) |
| 67 | + |
| 68 | + |
| 69 | +class TestGenioPatternMatching(TestCaseTmpDir): |
| 70 | + """Functional tests for genio pattern matching operations.""" |
| 71 | + |
| 72 | + def setUp(self): |
| 73 | + super().setUp() |
| 74 | + # Create a log-like test file |
| 75 | + self.log_file = os.path.join(self.tmpdir.name, "test.log") |
| 76 | + log_content = """2024-01-01 10:00:00 INFO Starting application |
| 77 | +2024-01-01 10:00:01 DEBUG Loading configuration |
| 78 | +2024-01-01 10:00:02 ERROR Failed to connect to database |
| 79 | +2024-01-01 10:00:03 INFO Retrying connection |
| 80 | +2024-01-01 10:00:04 ERROR Connection timeout |
| 81 | +2024-01-01 10:00:05 INFO Connection established |
| 82 | +""" |
| 83 | + genio.write_file(self.log_file, log_content) |
| 84 | + |
| 85 | + def test_find_error_lines(self): |
| 86 | + """Test finding all error lines in a log file.""" |
| 87 | + error_lines = genio.read_line_with_matching_pattern(self.log_file, "ERROR") |
| 88 | + self.assertEqual(len(error_lines), 2) |
| 89 | + self.assertTrue(all("ERROR" in line for line in error_lines)) |
| 90 | + |
| 91 | + def test_pattern_in_file_regex(self): |
| 92 | + """Test regex pattern matching in file.""" |
| 93 | + # Match timestamp pattern |
| 94 | + self.assertTrue(genio.is_pattern_in_file(self.log_file, r"\d{4}-\d{2}-\d{2}")) |
| 95 | + # Match INFO followed by any word |
| 96 | + self.assertTrue(genio.is_pattern_in_file(self.log_file, r"INFO \w+")) |
| 97 | + |
| 98 | + def test_pattern_not_in_file(self): |
| 99 | + """Test that non-existent pattern returns False.""" |
| 100 | + self.assertFalse(genio.is_pattern_in_file(self.log_file, "CRITICAL")) |
| 101 | + |
| 102 | + def test_pattern_matching_on_config_file(self): |
| 103 | + """Test pattern matching on a config-like file.""" |
| 104 | + config_file = os.path.join(self.tmpdir.name, "config.ini") |
| 105 | + config_content = """[database] |
| 106 | +host=localhost |
| 107 | +port=5432 |
| 108 | +name=testdb |
| 109 | +
|
| 110 | +[server] |
| 111 | +host=0.0.0.0 |
| 112 | +port=8080 |
| 113 | +""" |
| 114 | + genio.write_file(config_file, config_content) |
| 115 | + # Find all host settings |
| 116 | + host_lines = genio.read_line_with_matching_pattern(config_file, "host=") |
| 117 | + self.assertEqual(len(host_lines), 2) |
| 118 | + # Verify we can find specific section |
| 119 | + self.assertTrue(genio.is_pattern_in_file(config_file, r"\[database\]")) |
| 120 | + |
| 121 | + |
| 122 | +class TestGenioFileComparison(TestCaseTmpDir): |
| 123 | + """Functional tests for genio file comparison operations.""" |
| 124 | + |
| 125 | + def test_are_files_equal_identical_content(self): |
| 126 | + """Test that files with identical content are equal.""" |
| 127 | + file1 = os.path.join(self.tmpdir.name, "file1.txt") |
| 128 | + file2 = os.path.join(self.tmpdir.name, "file2.txt") |
| 129 | + content = "Same content in both files\n" |
| 130 | + genio.write_file(file1, content) |
| 131 | + genio.write_file(file2, content) |
| 132 | + self.assertTrue(genio.are_files_equal(file1, file2)) |
| 133 | + |
| 134 | + def test_are_files_equal_different_content(self): |
| 135 | + """Test that files with different content are not equal.""" |
| 136 | + file1 = os.path.join(self.tmpdir.name, "file1.txt") |
| 137 | + file2 = os.path.join(self.tmpdir.name, "file2.txt") |
| 138 | + genio.write_file(file1, "Content A") |
| 139 | + genio.write_file(file2, "Content B") |
| 140 | + self.assertFalse(genio.are_files_equal(file1, file2)) |
| 141 | + |
| 142 | + def test_copy_verification(self): |
| 143 | + """Test using are_files_equal to verify file copy.""" |
| 144 | + source = os.path.join(self.tmpdir.name, "source.txt") |
| 145 | + dest = os.path.join(self.tmpdir.name, "dest.txt") |
| 146 | + genio.write_file(source, "Original content\n") |
| 147 | + # Simulate a copy by reading and writing |
| 148 | + content = genio.read_file(source) |
| 149 | + genio.write_file(dest, content) |
| 150 | + self.assertTrue(genio.are_files_equal(source, dest)) |
| 151 | + |
| 152 | + |
| 153 | +class TestGenioErrorHandling(TestCaseTmpDir): |
| 154 | + """Functional tests for genio error handling.""" |
| 155 | + |
| 156 | + def test_write_file_or_fail_permission_error(self): |
| 157 | + """Test write_file_or_fail raises GenIOError on permission issues.""" |
| 158 | + # Try to write to a non-existent directory |
| 159 | + bad_path = "/nonexistent/directory/file.txt" |
| 160 | + with self.assertRaises(genio.GenIOError) as context: |
| 161 | + genio.write_file_or_fail(bad_path, "test content") |
| 162 | + self.assertIn(bad_path, str(context.exception)) |
| 163 | + |
| 164 | + def test_is_pattern_in_file_directory_error(self): |
| 165 | + """Test is_pattern_in_file raises GenIOError for directories.""" |
| 166 | + with self.assertRaises(genio.GenIOError): |
| 167 | + genio.is_pattern_in_file(self.tmpdir.name, "pattern") |
| 168 | + |
| 169 | + def test_read_all_lines_graceful_failure(self): |
| 170 | + """Test read_all_lines returns empty list on error.""" |
| 171 | + result = genio.read_all_lines("/nonexistent/file.txt") |
| 172 | + self.assertEqual(result, []) |
| 173 | + |
| 174 | + |
| 175 | +class TestGenioRealWorldScenarios(TestCaseTmpDir): |
| 176 | + """Functional tests simulating real-world usage scenarios.""" |
| 177 | + |
| 178 | + def test_config_file_modification(self): |
| 179 | + """Test modifying a value in a config file.""" |
| 180 | + config_file = os.path.join(self.tmpdir.name, "app.conf") |
| 181 | + initial_config = "debug=false\nport=8080\nhost=localhost\n" |
| 182 | + genio.write_file(config_file, initial_config) |
| 183 | + |
| 184 | + # Read, modify, write pattern |
| 185 | + content = genio.read_file(config_file) |
| 186 | + modified_content = content.replace("debug=false", "debug=true") |
| 187 | + genio.write_file(config_file, modified_content) |
| 188 | + |
| 189 | + # Verify modification |
| 190 | + self.assertTrue(genio.is_pattern_in_file(config_file, "debug=true")) |
| 191 | + self.assertFalse(genio.is_pattern_in_file(config_file, "debug=false")) |
| 192 | + |
| 193 | + def test_log_file_analysis(self): |
| 194 | + """Test analyzing a log file for specific patterns.""" |
| 195 | + log_file = os.path.join(self.tmpdir.name, "app.log") |
| 196 | + log_entries = [ |
| 197 | + "[2024-01-01 10:00:00] INFO: Application started", |
| 198 | + "[2024-01-01 10:00:01] WARNING: Low memory", |
| 199 | + "[2024-01-01 10:00:02] ERROR: Database connection failed", |
| 200 | + "[2024-01-01 10:00:03] INFO: Retrying...", |
| 201 | + "[2024-01-01 10:00:04] INFO: Connection restored", |
| 202 | + ] |
| 203 | + genio.write_file(log_file, "\n".join(log_entries) + "\n") |
| 204 | + |
| 205 | + # Count different log levels |
| 206 | + errors = genio.read_line_with_matching_pattern(log_file, "ERROR:") |
| 207 | + warnings = genio.read_line_with_matching_pattern(log_file, "WARNING:") |
| 208 | + infos = genio.read_line_with_matching_pattern(log_file, "INFO:") |
| 209 | + |
| 210 | + self.assertEqual(len(errors), 1) |
| 211 | + self.assertEqual(len(warnings), 1) |
| 212 | + self.assertEqual(len(infos), 3) |
| 213 | + |
| 214 | + def test_append_logging_simulation(self): |
| 215 | + """Test simulating log appending behavior.""" |
| 216 | + log_file = os.path.join(self.tmpdir.name, "events.log") |
| 217 | + events = ["Event 1 occurred", "Event 2 occurred", "Event 3 occurred"] |
| 218 | + |
| 219 | + for event in events: |
| 220 | + genio.append_one_line(log_file, event) |
| 221 | + |
| 222 | + all_events = genio.read_all_lines(log_file) |
| 223 | + self.assertEqual(all_events, events) |
| 224 | + |
| 225 | + def test_file_content_verification(self): |
| 226 | + """Test verifying file content matches expected pattern.""" |
| 227 | + data_file = os.path.join(self.tmpdir.name, "data.csv") |
| 228 | + csv_content = "name,age,city\nAlice,30,NYC\nBob,25,LA\nCharlie,35,Chicago\n" |
| 229 | + genio.write_file(data_file, csv_content) |
| 230 | + |
| 231 | + # Verify header exists |
| 232 | + first_line = genio.read_one_line(data_file) |
| 233 | + self.assertEqual(first_line, "name,age,city") |
| 234 | + |
| 235 | + # Verify data patterns |
| 236 | + self.assertTrue(genio.is_pattern_in_file(data_file, r"^\w+,\d+,\w+$")) |
| 237 | + |
| 238 | + |
| 239 | +if __name__ == "__main__": |
| 240 | + unittest.main() |
0 commit comments