backend.tests.unit.components.utils.test_image_utils

  1import pytest
  2import numpy as np
  3import cv2
  4from backend.components.utils.imageUtils import parse_image, encode_image
  5from backend.components.utils import imageUtils
  6
  7
  8# --------------------------------------------------------------------------
  9# Testy funkcji parse_image (Bytes -> Array)
 10# --------------------------------------------------------------------------
 11
 12def test_parse_image_success():
 13    """
 14    Checks whether valid image bytes are converted to a numpy matrix.
 15    It also verifies that the result is of the correct shape.
 16    """
 17    original_img = np.zeros((10, 10, 3), dtype=np.uint8)
 18
 19    _, buffer = cv2.imencode('.png', original_img)
 20    image_bytes = buffer.tobytes()
 21
 22    result_img = parse_image(image_bytes)
 23
 24    assert isinstance(result_img, np.ndarray)
 25    assert result_img.shape == (10, 10, 3)
 26
 27
 28def test_parse_image_color_conversion():
 29    """
 30    Checks whether the function correctly converts the color format from BGR to RGB.
 31    """
 32    # Tworzymy obraz 1x1 piksel w kolorze NIEBIESKIM.
 33    # W OpenCV (BGR) niebieski to [255, 0, 0].
 34    bgr_pixel = np.array([[[255, 0, 0]]], dtype=np.uint8)
 35
 36    # Kodujemy do PNG
 37    _, buffer = cv2.imencode('.png', bgr_pixel)
 38    image_bytes = buffer.tobytes()
 39
 40    # Parsujemy (funkcja powinna zamienić BGR -> RGB)
 41    rgb_pixel = parse_image(image_bytes)
 42
 43    # W RGB niebieski to [0, 0, 255].
 44    # Sprawdzamy, czy kanały zostały odwrócone.
 45    assert rgb_pixel[0, 0, 0] == 0  # R
 46    assert rgb_pixel[0, 0, 1] == 0  # G
 47    assert rgb_pixel[0, 0, 2] == 255  # B
 48
 49
 50def test_parse_image_invalid_bytes():
 51    """
 52    Checks whether a function throws a ValueError when it receives invalid bytes
 53    (e.g., a text file instead of an image).
 54    """
 55    garbage_bytes = b"to nie jest obrazek, tylko losowy tekst"
 56
 57    with pytest.raises(ValueError, match="Nie udało się przetworzyć pliku jako obrazu"):
 58        parse_image(garbage_bytes)
 59
 60
 61# --------------------------------------------------------------------------
 62# Testy funkcji encode_image (Array -> Bytes)
 63# --------------------------------------------------------------------------
 64
 65def test_encode_image_default_png():
 66    """
 67    Checks default encoding to PNG format.
 68    """
 69    # Tworzymy prosty obraz RGB
 70    img = np.zeros((10, 10, 3), dtype=np.uint8)
 71
 72    # Wywołanie bez podania formatu (domyślnie .png)
 73    result_bytes = encode_image(img)
 74
 75    assert isinstance(result_bytes, bytes)
 76    assert len(result_bytes) > 0
 77
 78    # Magiczne bajty PNG to: 89 50 4E 47
 79    # Sprawdzamy nagłówek, żeby upewnić się, że to PNG
 80    assert result_bytes.startswith(b'\x89PNG')
 81
 82
 83def test_encode_image_custom_format_jpg():
 84    """
 85    Checks encoding to JPG format.
 86    """
 87    img = np.zeros((10, 10, 3), dtype=np.uint8)
 88
 89    result_bytes = encode_image(img, encode_format=".jpg")
 90
 91    assert isinstance(result_bytes, bytes)
 92    assert len(result_bytes) > 0
 93    # Magiczne bajty JPEG zaczynają się zazwyczaj od FF D8
 94    assert result_bytes.startswith(b'\xff\xd8')
 95
 96
 97def test_encode_image_failure():
 98    """
 99    Checks whether the function throws a ValueError when OpenCV fails to encode an image.
100    We simulate this by providing an invalid file format or an empty array in a way that causes the cv2.
101    imencode function to fail.
102    """
103    # Pusta tablica lub tablica o złym kształcie zazwyczaj zwróci False w imencode
104    bad_img = np.zeros((0, 0, 0), dtype=np.uint8)
105
106    with pytest.raises(ValueError, match="Nie udało się zenkodować obrazu"):
107        encode_image(bad_img)
108
109
110# ============================================================================
111# Test parse_image - Success Cases
112# ============================================================================
113
114def test_parse_image_valid_png():
115    """Test parsing valid PNG image from bytes."""
116    # Create a simple test image
117    test_array = np.random.randint(0, 256, (100, 100, 3), dtype=np.uint8)
118    test_array_bgr = cv2.cvtColor(test_array, cv2.COLOR_RGB2BGR)
119
120    # Encode to PNG bytes
121    success, buffer = cv2.imencode(".png", test_array_bgr)
122    image_bytes = buffer.tobytes()
123
124    # Parse back
125    result = imageUtils.parse_image(image_bytes)
126
127    assert isinstance(result, np.ndarray)
128    assert result.shape == (100, 100, 3)
129    assert result.dtype == np.uint8
130
131
132def test_parse_image_valid_jpg():
133    """Test parsing valid JPG image from bytes."""
134    test_array = np.random.randint(0, 256, (200, 150, 3), dtype=np.uint8)
135    test_array_bgr = cv2.cvtColor(test_array, cv2.COLOR_RGB2BGR)
136
137    success, buffer = cv2.imencode(".jpg", test_array_bgr)
138    image_bytes = buffer.tobytes()
139
140    result = imageUtils.parse_image(image_bytes)
141
142    assert isinstance(result, np.ndarray)
143    assert result.shape[2] == 3  # RGB channels
144    assert result.dtype == np.uint8
145
146
147# ============================================================================
148# Test encode_image - Success Cases
149# ============================================================================
150
151def test_encode_image_default_png():
152    """Test encoding image to PNG (default format)."""
153    test_array = np.random.randint(0, 256, (100, 100, 3), dtype=np.uint8)
154
155    result = imageUtils.encode_image(test_array)
156
157    assert isinstance(result, bytes)
158    assert len(result) > 0
159    # PNG files start with specific magic bytes
160    assert result[:8] == b'\x89PNG\r\n\x1a\n'
161
162
163def test_encode_image_to_jpg():
164    """Test encoding image to JPG format."""
165    test_array = np.random.randint(0, 256, (100, 100, 3), dtype=np.uint8)
166
167    result = imageUtils.encode_image(test_array, encode_format=".jpg")
168
169    assert isinstance(result, bytes)
170    assert len(result) > 0
171    # JPG files start with FFD8FF
172    assert result[:2] == b'\xff\xd8'
173
174
175def test_encode_image_various_sizes():
176    """Test encoding images of various sizes."""
177    sizes = [(50, 50), (100, 200), (800, 600)]
178
179    for height, width in sizes:
180        test_array = np.random.randint(0, 256, (height, width, 3), dtype=np.uint8)
181        result = imageUtils.encode_image(test_array)
182
183        assert isinstance(result, bytes)
184        assert len(result) > 0
185
186
187def test_encode_image_preserves_content():
188    """Test that encoded image can be decoded back."""
189    original = np.random.randint(0, 256, (100, 100, 3), dtype=np.uint8)
190
191    # Encode
192    encoded_bytes = imageUtils.encode_image(original)
193
194    # Decode back
195    decoded = imageUtils.parse_image(encoded_bytes)
196
197    assert isinstance(decoded, np.ndarray)
198    # Allow for compression artifacts
199    assert decoded.shape == original.shape
200
201
202# ============================================================================
203# Test Round-trip Conversion
204# ============================================================================
205
206def test_parse_and_encode():
207    """Test parse -> encode -> parse produces same dimensions."""
208    original = np.random.randint(0, 256, (150, 200, 3), dtype=np.uint8)
209    original_bgr = cv2.cvtColor(original, cv2.COLOR_RGB2BGR)
210
211    # Create initial bytes
212    success, buffer = cv2.imencode(".png", original_bgr)
213    image_bytes = buffer.tobytes()
214
215    # Parse
216    parsed = imageUtils.parse_image(image_bytes)
217
218    # Encode back
219    re_encoded = imageUtils.encode_image(parsed)
220
221    # Parse again
222    re_parsed = imageUtils.parse_image(re_encoded)
223
224    assert parsed.shape == re_parsed.shape
225    assert parsed.dtype == re_parsed.dtype
226
227
228def test_encode_and_parse():
229    """Test encode -> parse produces same dimensions."""
230    original = np.random.randint(0, 256, (100, 100, 3), dtype=np.uint8)
231
232    # Encode
233    encoded = imageUtils.encode_image(original)
234
235    # Parse
236    parsed = imageUtils.parse_image(encoded)
237
238    assert parsed.shape == original.shape
239    assert parsed.dtype == original.dtype
def test_parse_image_success():
13def test_parse_image_success():
14    """
15    Checks whether valid image bytes are converted to a numpy matrix.
16    It also verifies that the result is of the correct shape.
17    """
18    original_img = np.zeros((10, 10, 3), dtype=np.uint8)
19
20    _, buffer = cv2.imencode('.png', original_img)
21    image_bytes = buffer.tobytes()
22
23    result_img = parse_image(image_bytes)
24
25    assert isinstance(result_img, np.ndarray)
26    assert result_img.shape == (10, 10, 3)

Checks whether valid image bytes are converted to a numpy matrix. It also verifies that the result is of the correct shape.

def test_parse_image_color_conversion():
29def test_parse_image_color_conversion():
30    """
31    Checks whether the function correctly converts the color format from BGR to RGB.
32    """
33    # Tworzymy obraz 1x1 piksel w kolorze NIEBIESKIM.
34    # W OpenCV (BGR) niebieski to [255, 0, 0].
35    bgr_pixel = np.array([[[255, 0, 0]]], dtype=np.uint8)
36
37    # Kodujemy do PNG
38    _, buffer = cv2.imencode('.png', bgr_pixel)
39    image_bytes = buffer.tobytes()
40
41    # Parsujemy (funkcja powinna zamienić BGR -> RGB)
42    rgb_pixel = parse_image(image_bytes)
43
44    # W RGB niebieski to [0, 0, 255].
45    # Sprawdzamy, czy kanały zostały odwrócone.
46    assert rgb_pixel[0, 0, 0] == 0  # R
47    assert rgb_pixel[0, 0, 1] == 0  # G
48    assert rgb_pixel[0, 0, 2] == 255  # B

Checks whether the function correctly converts the color format from BGR to RGB.

def test_parse_image_invalid_bytes():
51def test_parse_image_invalid_bytes():
52    """
53    Checks whether a function throws a ValueError when it receives invalid bytes
54    (e.g., a text file instead of an image).
55    """
56    garbage_bytes = b"to nie jest obrazek, tylko losowy tekst"
57
58    with pytest.raises(ValueError, match="Nie udało się przetworzyć pliku jako obrazu"):
59        parse_image(garbage_bytes)

Checks whether a function throws a ValueError when it receives invalid bytes (e.g., a text file instead of an image).

def test_encode_image_default_png():
152def test_encode_image_default_png():
153    """Test encoding image to PNG (default format)."""
154    test_array = np.random.randint(0, 256, (100, 100, 3), dtype=np.uint8)
155
156    result = imageUtils.encode_image(test_array)
157
158    assert isinstance(result, bytes)
159    assert len(result) > 0
160    # PNG files start with specific magic bytes
161    assert result[:8] == b'\x89PNG\r\n\x1a\n'

Test encoding image to PNG (default format).

def test_encode_image_custom_format_jpg():
84def test_encode_image_custom_format_jpg():
85    """
86    Checks encoding to JPG format.
87    """
88    img = np.zeros((10, 10, 3), dtype=np.uint8)
89
90    result_bytes = encode_image(img, encode_format=".jpg")
91
92    assert isinstance(result_bytes, bytes)
93    assert len(result_bytes) > 0
94    # Magiczne bajty JPEG zaczynają się zazwyczaj od FF D8
95    assert result_bytes.startswith(b'\xff\xd8')

Checks encoding to JPG format.

def test_encode_image_failure():
 98def test_encode_image_failure():
 99    """
100    Checks whether the function throws a ValueError when OpenCV fails to encode an image.
101    We simulate this by providing an invalid file format or an empty array in a way that causes the cv2.
102    imencode function to fail.
103    """
104    # Pusta tablica lub tablica o złym kształcie zazwyczaj zwróci False w imencode
105    bad_img = np.zeros((0, 0, 0), dtype=np.uint8)
106
107    with pytest.raises(ValueError, match="Nie udało się zenkodować obrazu"):
108        encode_image(bad_img)

Checks whether the function throws a ValueError when OpenCV fails to encode an image. We simulate this by providing an invalid file format or an empty array in a way that causes the cv2. imencode function to fail.

def test_parse_image_valid_png():
115def test_parse_image_valid_png():
116    """Test parsing valid PNG image from bytes."""
117    # Create a simple test image
118    test_array = np.random.randint(0, 256, (100, 100, 3), dtype=np.uint8)
119    test_array_bgr = cv2.cvtColor(test_array, cv2.COLOR_RGB2BGR)
120
121    # Encode to PNG bytes
122    success, buffer = cv2.imencode(".png", test_array_bgr)
123    image_bytes = buffer.tobytes()
124
125    # Parse back
126    result = imageUtils.parse_image(image_bytes)
127
128    assert isinstance(result, np.ndarray)
129    assert result.shape == (100, 100, 3)
130    assert result.dtype == np.uint8

Test parsing valid PNG image from bytes.

def test_parse_image_valid_jpg():
133def test_parse_image_valid_jpg():
134    """Test parsing valid JPG image from bytes."""
135    test_array = np.random.randint(0, 256, (200, 150, 3), dtype=np.uint8)
136    test_array_bgr = cv2.cvtColor(test_array, cv2.COLOR_RGB2BGR)
137
138    success, buffer = cv2.imencode(".jpg", test_array_bgr)
139    image_bytes = buffer.tobytes()
140
141    result = imageUtils.parse_image(image_bytes)
142
143    assert isinstance(result, np.ndarray)
144    assert result.shape[2] == 3  # RGB channels
145    assert result.dtype == np.uint8

Test parsing valid JPG image from bytes.

def test_encode_image_to_jpg():
164def test_encode_image_to_jpg():
165    """Test encoding image to JPG format."""
166    test_array = np.random.randint(0, 256, (100, 100, 3), dtype=np.uint8)
167
168    result = imageUtils.encode_image(test_array, encode_format=".jpg")
169
170    assert isinstance(result, bytes)
171    assert len(result) > 0
172    # JPG files start with FFD8FF
173    assert result[:2] == b'\xff\xd8'

Test encoding image to JPG format.

def test_encode_image_various_sizes():
176def test_encode_image_various_sizes():
177    """Test encoding images of various sizes."""
178    sizes = [(50, 50), (100, 200), (800, 600)]
179
180    for height, width in sizes:
181        test_array = np.random.randint(0, 256, (height, width, 3), dtype=np.uint8)
182        result = imageUtils.encode_image(test_array)
183
184        assert isinstance(result, bytes)
185        assert len(result) > 0

Test encoding images of various sizes.

def test_encode_image_preserves_content():
188def test_encode_image_preserves_content():
189    """Test that encoded image can be decoded back."""
190    original = np.random.randint(0, 256, (100, 100, 3), dtype=np.uint8)
191
192    # Encode
193    encoded_bytes = imageUtils.encode_image(original)
194
195    # Decode back
196    decoded = imageUtils.parse_image(encoded_bytes)
197
198    assert isinstance(decoded, np.ndarray)
199    # Allow for compression artifacts
200    assert decoded.shape == original.shape

Test that encoded image can be decoded back.

def test_parse_and_encode():
207def test_parse_and_encode():
208    """Test parse -> encode -> parse produces same dimensions."""
209    original = np.random.randint(0, 256, (150, 200, 3), dtype=np.uint8)
210    original_bgr = cv2.cvtColor(original, cv2.COLOR_RGB2BGR)
211
212    # Create initial bytes
213    success, buffer = cv2.imencode(".png", original_bgr)
214    image_bytes = buffer.tobytes()
215
216    # Parse
217    parsed = imageUtils.parse_image(image_bytes)
218
219    # Encode back
220    re_encoded = imageUtils.encode_image(parsed)
221
222    # Parse again
223    re_parsed = imageUtils.parse_image(re_encoded)
224
225    assert parsed.shape == re_parsed.shape
226    assert parsed.dtype == re_parsed.dtype

Test parse -> encode -> parse produces same dimensions.

def test_encode_and_parse():
229def test_encode_and_parse():
230    """Test encode -> parse produces same dimensions."""
231    original = np.random.randint(0, 256, (100, 100, 3), dtype=np.uint8)
232
233    # Encode
234    encoded = imageUtils.encode_image(original)
235
236    # Parse
237    parsed = imageUtils.parse_image(encoded)
238
239    assert parsed.shape == original.shape
240    assert parsed.dtype == original.dtype

Test encode -> parse produces same dimensions.