Skip to content

Commit 527a569

Browse files
author
David Pech
committed
+ better test coverage
1 parent a28fe34 commit 527a569

File tree

6 files changed

+2067
-0
lines changed

6 files changed

+2067
-0
lines changed

tests/test_fs_utils_coverage.py

Lines changed: 310 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,310 @@
1+
#!/usr/bin/env python3
2+
# -*- coding: utf-8 -*- #
3+
#
4+
# Copyright 2025 Wrike Inc.
5+
#
6+
7+
import pytest
8+
import yaml
9+
import json
10+
import sys
11+
import tempfile
12+
from pathlib import Path
13+
from unittest.mock import patch, mock_open, MagicMock
14+
from io import StringIO
15+
16+
# Add src to path for imports
17+
sys.path.insert(0, str(Path(__file__).parent.parent / "src"))
18+
19+
from promabbix.core.fs_utils import DataLoader, DataSaver
20+
21+
22+
class TestDataLoaderCoverageImprovements:
23+
"""Test additional scenarios for DataLoader to improve coverage."""
24+
25+
def test_load_from_file_import_error_fallback(self, temp_directory):
26+
"""Test YAML loading with CLoader import error fallback."""
27+
test_file = temp_directory / "test.yaml"
28+
test_data = {"test": "data", "number": 123}
29+
test_file.write_text(yaml.dump(test_data))
30+
31+
# Mock the import to simulate CLoader not available
32+
with patch('promabbix.core.fs_utils.CLoader', side_effect=ImportError):
33+
# Reload the module to test the import fallback
34+
import importlib
35+
import promabbix.core.fs_utils
36+
importlib.reload(promabbix.core.fs_utils)
37+
38+
loader = DataLoader()
39+
result = loader.load_from_file(str(test_file))
40+
assert result == test_data
41+
42+
def test_load_from_stdin_with_yaml_data(self):
43+
"""Test loading YAML data from stdin."""
44+
yaml_data = {"test": "data", "yaml": True}
45+
yaml_content = yaml.dump(yaml_data)
46+
47+
with patch('sys.stdin', StringIO(yaml_content)):
48+
loader = DataLoader()
49+
result = loader.load_from_stdin()
50+
assert result == yaml_data
51+
52+
def test_load_from_stdin_with_json_data(self):
53+
"""Test loading JSON data from stdin."""
54+
json_data = {"test": "data", "json": True}
55+
json_content = json.dumps(json_data)
56+
57+
with patch('sys.stdin', StringIO(json_content)):
58+
loader = DataLoader()
59+
result = loader.load_from_stdin()
60+
assert result == json_data
61+
62+
def test_load_from_stdin_yaml_error_fallback_to_json(self):
63+
"""Test stdin loading with YAML error falling back to JSON."""
64+
# This is valid JSON but invalid YAML due to quoted keys
65+
json_content = '{"test": "data", "json": true}'
66+
67+
with patch('sys.stdin', StringIO(json_content)):
68+
loader = DataLoader()
69+
result = loader.load_from_stdin()
70+
assert result == {"test": "data", "json": True}
71+
72+
def test_load_from_stdin_both_yaml_and_json_error(self):
73+
"""Test stdin loading when both YAML and JSON parsing fail."""
74+
invalid_content = "invalid: yaml: and json content: [unclosed"
75+
76+
with patch('sys.stdin', StringIO(invalid_content)):
77+
loader = DataLoader()
78+
with pytest.raises(ValueError) as excinfo:
79+
loader.load_from_stdin()
80+
assert "Could not parse data from STDIN" in str(excinfo.value)
81+
82+
def test_load_from_file_permission_error_different_exception(self, temp_directory):
83+
"""Test file loading with different permission error types."""
84+
test_file = temp_directory / "test.yaml"
85+
test_file.write_text("test: data")
86+
87+
# Mock to raise PermissionError
88+
with patch('builtins.open', side_effect=PermissionError("Access denied")):
89+
loader = DataLoader()
90+
with pytest.raises(ValueError) as excinfo:
91+
loader.load_from_file(str(test_file))
92+
assert "Permission denied to read file" in str(excinfo.value)
93+
94+
95+
class TestDataSaverCoverageImprovements:
96+
"""Test additional scenarios for DataSaver to improve coverage."""
97+
98+
def test_save_to_stdout_string_content(self):
99+
"""Test saving string content to stdout."""
100+
test_content = "This is a test string"
101+
102+
with patch('sys.stdout', new_callable=StringIO) as mock_stdout:
103+
saver = DataSaver()
104+
saver.save_to_stdout(test_content)
105+
assert mock_stdout.getvalue() == test_content
106+
107+
def test_save_to_stdout_dict_content(self):
108+
"""Test saving dict content to stdout (should serialize to JSON)."""
109+
test_data = {"test": "data", "number": 123}
110+
111+
with patch('sys.stdout', new_callable=StringIO) as mock_stdout:
112+
saver = DataSaver()
113+
saver.save_to_stdout(test_data)
114+
output = mock_stdout.getvalue()
115+
# Should be valid JSON
116+
parsed = json.loads(output)
117+
assert parsed == test_data
118+
119+
def test_save_to_file_directory_creation_failure(self, temp_directory):
120+
"""Test save to file when directory creation fails."""
121+
test_file = temp_directory / "subdir" / "test.json"
122+
test_data = {"test": "data"}
123+
124+
# Mock Path.mkdir to raise PermissionError
125+
with patch.object(Path, 'mkdir', side_effect=PermissionError("Permission denied")):
126+
saver = DataSaver()
127+
with pytest.raises(ValueError) as excinfo:
128+
saver.save_to_file(test_data, str(test_file))
129+
assert "Failed to create directory" in str(excinfo.value)
130+
131+
def test_save_to_file_write_permission_error(self, temp_directory):
132+
"""Test save to file when write operation fails due to permissions."""
133+
test_file = temp_directory / "test.json"
134+
test_data = {"test": "data"}
135+
136+
# Mock open to raise PermissionError during write
137+
with patch('builtins.open', side_effect=PermissionError("Write permission denied")):
138+
saver = DataSaver()
139+
with pytest.raises(ValueError) as excinfo:
140+
saver.save_to_file(test_data, str(test_file))
141+
assert "Failed to write to file" in str(excinfo.value)
142+
143+
def test_save_to_file_json_encoding_error(self, temp_directory):
144+
"""Test save to file when JSON encoding fails."""
145+
test_file = temp_directory / "test.json"
146+
# Create an object that can't be JSON serialized
147+
test_data = {"test": set([1, 2, 3])} # sets are not JSON serializable
148+
149+
saver = DataSaver()
150+
with pytest.raises(ValueError) as excinfo:
151+
saver.save_to_file(test_data, str(test_file))
152+
assert "Failed to serialize data to JSON" in str(excinfo.value)
153+
154+
def test_save_to_file_yaml_encoding_error(self, temp_directory):
155+
"""Test save to file when YAML encoding fails."""
156+
test_file = temp_directory / "test.yaml"
157+
158+
# Mock yaml.dump to raise an exception
159+
with patch('yaml.dump', side_effect=yaml.YAMLError("YAML encoding failed")):
160+
saver = DataSaver()
161+
test_data = {"test": "data"}
162+
with pytest.raises(ValueError) as excinfo:
163+
saver.save_to_file(test_data, str(test_file))
164+
assert "Failed to serialize data to YAML" in str(excinfo.value)
165+
166+
def test_save_text_to_file_encoding_error(self, temp_directory):
167+
"""Test save text to file when encoding fails."""
168+
test_file = temp_directory / "test.txt"
169+
test_content = "test content"
170+
171+
# Mock open to raise UnicodeEncodeError
172+
with patch('builtins.open', side_effect=UnicodeEncodeError('utf-8', b'', 0, 1, "encoding error")):
173+
saver = DataSaver()
174+
with pytest.raises(ValueError) as excinfo:
175+
saver.save_text_to_file(test_content, str(test_file))
176+
assert "Failed to write text to file" in str(excinfo.value)
177+
178+
def test_save_to_file_dict_unknown_extension(self, temp_directory):
179+
"""Test saving dict to file with unknown extension defaults to YAML."""
180+
test_file = temp_directory / "test.unknown"
181+
test_data = {"test": "data", "number": 123}
182+
183+
saver = DataSaver()
184+
saver.save_to_file(test_data, str(test_file))
185+
186+
# Should default to YAML format
187+
with open(test_file, 'r') as f:
188+
content = f.read()
189+
# Check if it looks like YAML (contains : but not {})
190+
assert "test: data" in content
191+
assert "{" not in content
192+
193+
def test_save_to_file_list_unknown_extension(self, temp_directory):
194+
"""Test saving list to file with unknown extension defaults to YAML."""
195+
test_file = temp_directory / "test.unknown"
196+
test_data = [{"test": "data"}, {"number": 123}]
197+
198+
saver = DataSaver()
199+
saver.save_to_file(test_data, str(test_file))
200+
201+
# Should default to YAML format
202+
with open(test_file, 'r') as f:
203+
content = f.read()
204+
# Check if it looks like YAML (contains - for list items)
205+
assert "- test: data" in content or "test: data" in content
206+
207+
def test_save_to_file_string_unknown_extension(self, temp_directory):
208+
"""Test saving string to file with unknown extension saves as text."""
209+
test_file = temp_directory / "test.unknown"
210+
test_content = "This is plain text content"
211+
212+
saver = DataSaver()
213+
saver.save_to_file(test_content, str(test_file))
214+
215+
with open(test_file, 'r') as f:
216+
content = f.read()
217+
assert content == test_content
218+
219+
def test_save_to_file_unsupported_type(self, temp_directory):
220+
"""Test saving unsupported data type to file."""
221+
test_file = temp_directory / "test.json"
222+
# Use a custom class that's not serializable
223+
class CustomClass:
224+
def __init__(self):
225+
self.value = "test"
226+
227+
test_data = CustomClass()
228+
229+
saver = DataSaver()
230+
with pytest.raises(ValueError) as excinfo:
231+
saver.save_to_file(test_data, str(test_file))
232+
assert "Unsupported data type" in str(excinfo.value)
233+
234+
def test_determine_format_from_extension_edge_cases(self):
235+
"""Test format determination with various file extensions."""
236+
saver = DataSaver()
237+
238+
# Test case sensitivity
239+
assert saver._determine_format_from_extension("test.JSON") == "json"
240+
assert saver._determine_format_from_extension("test.YAML") == "yaml"
241+
assert saver._determine_format_from_extension("test.YML") == "yaml"
242+
243+
# Test with multiple dots
244+
assert saver._determine_format_from_extension("test.backup.json") == "json"
245+
assert saver._determine_format_from_extension("test.old.yaml") == "yaml"
246+
247+
# Test with no extension
248+
assert saver._determine_format_from_extension("test") == "yaml" # default
249+
250+
# Test with unknown extension
251+
assert saver._determine_format_from_extension("test.txt") == "yaml" # default
252+
253+
def test_save_to_file_complex_yaml_data(self, temp_directory):
254+
"""Test saving complex YAML data structures."""
255+
test_file = temp_directory / "complex.yaml"
256+
complex_data = {
257+
"simple_string": "value",
258+
"multiline_string": "line1\nline2\nline3",
259+
"list_of_dicts": [
260+
{"name": "item1", "value": 1},
261+
{"name": "item2", "value": 2}
262+
],
263+
"nested_dict": {
264+
"level1": {
265+
"level2": {
266+
"level3": "deep_value"
267+
}
268+
}
269+
},
270+
"special_chars": "Special chars: åäö, 中文, 🚀"
271+
}
272+
273+
saver = DataSaver()
274+
saver.save_to_file(complex_data, str(test_file))
275+
276+
# Verify the data can be loaded back correctly
277+
loader = DataLoader()
278+
loaded_data = loader.load_from_file(str(test_file))
279+
assert loaded_data == complex_data
280+
281+
def test_save_to_file_complex_json_data(self, temp_directory):
282+
"""Test saving complex JSON data structures."""
283+
test_file = temp_directory / "complex.json"
284+
complex_data = {
285+
"string": "value",
286+
"number": 42,
287+
"float": 3.14159,
288+
"boolean": True,
289+
"null_value": None,
290+
"list": [1, 2, 3, "four", 5.0],
291+
"nested": {
292+
"inner_list": [{"a": 1}, {"b": 2}],
293+
"inner_dict": {"x": "y"}
294+
}
295+
}
296+
297+
saver = DataSaver()
298+
saver.save_to_file(complex_data, str(test_file))
299+
300+
# Verify the data can be loaded back correctly
301+
loader = DataLoader()
302+
loaded_data = loader.load_from_file(str(test_file))
303+
assert loaded_data == complex_data
304+
305+
306+
@pytest.fixture
307+
def temp_directory():
308+
"""Create a temporary directory for test files."""
309+
with tempfile.TemporaryDirectory() as tmpdir:
310+
yield Path(tmpdir)

0 commit comments

Comments
 (0)