backend.tests.unit.components.camera_verification.qrcode.test_qrcode_service

  1import pytest
  2import numpy as np
  3from unittest.mock import patch, MagicMock
  4
  5from backend.components.camera_verification.qrcode.qrcodeService import (
  6    generate_qr_code,
  7    decode_qr_image,
  8    MultipleCodesError,
  9    NoCodeFoundError
 10)
 11
 12
 13# --------------------------------------------------------------------------
 14# Fixtures
 15# --------------------------------------------------------------------------
 16
 17@pytest.fixture
 18def fake_image():
 19    """Tworzy pustą tablicę numpy udającą obraz (dla decode)."""
 20    return np.zeros((100, 100, 3), dtype=np.uint8)
 21
 22
 23# --------------------------------------------------------------------------
 24# Testy generate_qr_code
 25# --------------------------------------------------------------------------
 26
 27@patch('backend.components.camera_verification.qrcode.qrcodeService.encode_image')
 28@patch('backend.components.camera_verification.qrcode.qrcodeService.cv2')
 29def test_generate_qr_code_success(mock_cv2, mock_encode_image):
 30    """
 31    Testuje generowanie kodu QR.
 32    Sprawdza, czy wywoływane są odpowiednie metody z biblioteki cv2 oraz funkcja kodująca wynik.
 33    """
 34    # Setup
 35    secret = "my_secret_code"
 36
 37    # Mockowanie łańcucha wywołań cv2
 38    mock_encoder = MagicMock()
 39    mock_cv2.QRCodeEncoder.return_value.create.return_value = mock_encoder
 40
 41    # Mockowanie wyników operacji na obrazie
 42    # encode zwraca surowy obraz QR
 43    mock_encoder.encode.return_value = np.zeros((10, 10), dtype=np.uint8)
 44    # resize zwraca przeskalowany obraz
 45    mock_cv2.resize.return_value = np.zeros((100, 100), dtype=np.uint8)
 46    # copyMakeBorder dodaje ramkę
 47    mock_cv2.copyMakeBorder.return_value = np.zeros((120, 120), dtype=np.uint8)
 48    # threshold zwraca (retval, image)
 49    mock_cv2.threshold.return_value = (127, np.zeros((120, 120), dtype=np.uint8))
 50
 51    # Mock encode_image (zwraca bytes)
 52    expected_bytes = b'fake_png_bytes'
 53    mock_encode_image.return_value = expected_bytes
 54
 55    # Action
 56    result = generate_qr_code(secret)
 57
 58    # Assert
 59    assert result == expected_bytes
 60
 61    # Weryfikacja czy encoder został utworzony i użyty z sekretem
 62    mock_cv2.QRCodeEncoder.return_value.create.assert_called_once()
 63    mock_encoder.encode.assert_called_once_with(secret)
 64
 65    # Weryfikacja czy zakodowano ostateczny obraz
 66    mock_encode_image.assert_called_once()
 67
 68
 69# --------------------------------------------------------------------------
 70# Testy decode_qr_image
 71# --------------------------------------------------------------------------
 72
 73@patch('backend.components.camera_verification.qrcode.qrcodeService.pyzbar.decode')
 74def test_decode_qr_image_success(mock_decode, fake_image):
 75    """
 76    Scenariusz pozytywny: Wykryto dokładnie jeden kod QR.
 77    """
 78    # Setup
 79    mock_qr_obj = MagicMock()
 80    mock_qr_obj.data = b"decoded_secret_123"
 81
 82    # pyzbar.decode zwraca listę znalezionych obiektów
 83    mock_decode.return_value = [mock_qr_obj]
 84
 85    # Action
 86    result = decode_qr_image(fake_image)
 87
 88    # Assert
 89    assert result == "decoded_secret_123"
 90    mock_decode.assert_called_once_with(fake_image)
 91
 92
 93@patch('backend.components.camera_verification.qrcode.qrcodeService.pyzbar.decode')
 94def test_decode_qr_image_multiple_codes(mock_decode, fake_image):
 95    """
 96    Negative scenario: More than one QR code detected.
 97    Expected exception: MultipleCodesError.
 98    """
 99    # Setup
100    obj1 = MagicMock()
101    obj1.data = b"code1"
102    obj2 = MagicMock()
103    obj2.data = b"code2"
104
105    mock_decode.return_value = [obj1, obj2]
106
107    # Action & Assert
108    with pytest.raises(MultipleCodesError, match="Wykryto 2 kodów QR"):
109        decode_qr_image(fake_image)
110
111
112@patch('backend.components.camera_verification.qrcode.qrcodeService.pyzbar.decode')
113def test_decode_qr_image_no_code_empty_list(mock_decode, fake_image):
114    """
115    Negative scenario: The library returns an empty list (no codes).
116    Expected exception: NoCodeFoundError.
117    """
118    # Setup
119    mock_decode.return_value = []
120
121    # Action & Assert
122    with pytest.raises(NoCodeFoundError, match="Nie wykryto kodu QR"):
123        decode_qr_image(fake_image)
124
125
126@patch('backend.components.camera_verification.qrcode.qrcodeService.pyzbar.decode')
127def test_decode_qr_image_no_code_none(mock_decode, fake_image):
128    """
129    Negative scenario: The library returns None (theoretical case of a library error).
130    Expected exception: NoCodeFoundError.
131    """
132    # Setup
133    mock_decode.return_value = None
134
135    # Action & Assert
136    with pytest.raises(NoCodeFoundError, match="Nie wykryto kodu QR"):
137        decode_qr_image(fake_image)
138
139
140@patch('backend.components.camera_verification.qrcode.qrcodeService.pyzbar.decode')
141def test_decode_qr_image_decoding_utf8_error(mock_decode, fake_image):
142    """
143    Sprawdza, czy błąd dekodowania bajtów (np. złe kodowanie) rzuci standardowy błąd Pythonowy
144    lub czy przejdzie (zależnie od implementacji, tutaj testujemy domyślne zachowanie .decode()).
145    """
146    # Setup
147    mock_qr_obj = MagicMock()
148    # Niepoprawna sekwencja UTF-8
149    mock_qr_obj.data = b'\xff\xfe\xfa'
150
151    mock_decode.return_value = [mock_qr_obj]
152
153    # Action & Assert
154    with pytest.raises(UnicodeDecodeError):
155        decode_qr_image(fake_image)
@pytest.fixture
def fake_image():
18@pytest.fixture
19def fake_image():
20    """Tworzy pustą tablicę numpy udającą obraz (dla decode)."""
21    return np.zeros((100, 100, 3), dtype=np.uint8)

Tworzy pustą tablicę numpy udającą obraz (dla decode).

@patch('backend.components.camera_verification.qrcode.qrcodeService.encode_image')
@patch('backend.components.camera_verification.qrcode.qrcodeService.cv2')
def test_generate_qr_code_success(mock_cv2, mock_encode_image):
28@patch('backend.components.camera_verification.qrcode.qrcodeService.encode_image')
29@patch('backend.components.camera_verification.qrcode.qrcodeService.cv2')
30def test_generate_qr_code_success(mock_cv2, mock_encode_image):
31    """
32    Testuje generowanie kodu QR.
33    Sprawdza, czy wywoływane są odpowiednie metody z biblioteki cv2 oraz funkcja kodująca wynik.
34    """
35    # Setup
36    secret = "my_secret_code"
37
38    # Mockowanie łańcucha wywołań cv2
39    mock_encoder = MagicMock()
40    mock_cv2.QRCodeEncoder.return_value.create.return_value = mock_encoder
41
42    # Mockowanie wyników operacji na obrazie
43    # encode zwraca surowy obraz QR
44    mock_encoder.encode.return_value = np.zeros((10, 10), dtype=np.uint8)
45    # resize zwraca przeskalowany obraz
46    mock_cv2.resize.return_value = np.zeros((100, 100), dtype=np.uint8)
47    # copyMakeBorder dodaje ramkę
48    mock_cv2.copyMakeBorder.return_value = np.zeros((120, 120), dtype=np.uint8)
49    # threshold zwraca (retval, image)
50    mock_cv2.threshold.return_value = (127, np.zeros((120, 120), dtype=np.uint8))
51
52    # Mock encode_image (zwraca bytes)
53    expected_bytes = b'fake_png_bytes'
54    mock_encode_image.return_value = expected_bytes
55
56    # Action
57    result = generate_qr_code(secret)
58
59    # Assert
60    assert result == expected_bytes
61
62    # Weryfikacja czy encoder został utworzony i użyty z sekretem
63    mock_cv2.QRCodeEncoder.return_value.create.assert_called_once()
64    mock_encoder.encode.assert_called_once_with(secret)
65
66    # Weryfikacja czy zakodowano ostateczny obraz
67    mock_encode_image.assert_called_once()

Testuje generowanie kodu QR. Sprawdza, czy wywoływane są odpowiednie metody z biblioteki cv2 oraz funkcja kodująca wynik.

@patch('backend.components.camera_verification.qrcode.qrcodeService.pyzbar.decode')
def test_decode_qr_image_success(mock_decode, fake_image):
74@patch('backend.components.camera_verification.qrcode.qrcodeService.pyzbar.decode')
75def test_decode_qr_image_success(mock_decode, fake_image):
76    """
77    Scenariusz pozytywny: Wykryto dokładnie jeden kod QR.
78    """
79    # Setup
80    mock_qr_obj = MagicMock()
81    mock_qr_obj.data = b"decoded_secret_123"
82
83    # pyzbar.decode zwraca listę znalezionych obiektów
84    mock_decode.return_value = [mock_qr_obj]
85
86    # Action
87    result = decode_qr_image(fake_image)
88
89    # Assert
90    assert result == "decoded_secret_123"
91    mock_decode.assert_called_once_with(fake_image)

Scenariusz pozytywny: Wykryto dokładnie jeden kod QR.

@patch('backend.components.camera_verification.qrcode.qrcodeService.pyzbar.decode')
def test_decode_qr_image_multiple_codes(mock_decode, fake_image):
 94@patch('backend.components.camera_verification.qrcode.qrcodeService.pyzbar.decode')
 95def test_decode_qr_image_multiple_codes(mock_decode, fake_image):
 96    """
 97    Negative scenario: More than one QR code detected.
 98    Expected exception: MultipleCodesError.
 99    """
100    # Setup
101    obj1 = MagicMock()
102    obj1.data = b"code1"
103    obj2 = MagicMock()
104    obj2.data = b"code2"
105
106    mock_decode.return_value = [obj1, obj2]
107
108    # Action & Assert
109    with pytest.raises(MultipleCodesError, match="Wykryto 2 kodów QR"):
110        decode_qr_image(fake_image)

Negative scenario: More than one QR code detected. Expected exception: MultipleCodesError.

@patch('backend.components.camera_verification.qrcode.qrcodeService.pyzbar.decode')
def test_decode_qr_image_no_code_empty_list(mock_decode, fake_image):
113@patch('backend.components.camera_verification.qrcode.qrcodeService.pyzbar.decode')
114def test_decode_qr_image_no_code_empty_list(mock_decode, fake_image):
115    """
116    Negative scenario: The library returns an empty list (no codes).
117    Expected exception: NoCodeFoundError.
118    """
119    # Setup
120    mock_decode.return_value = []
121
122    # Action & Assert
123    with pytest.raises(NoCodeFoundError, match="Nie wykryto kodu QR"):
124        decode_qr_image(fake_image)

Negative scenario: The library returns an empty list (no codes). Expected exception: NoCodeFoundError.

@patch('backend.components.camera_verification.qrcode.qrcodeService.pyzbar.decode')
def test_decode_qr_image_no_code_none(mock_decode, fake_image):
127@patch('backend.components.camera_verification.qrcode.qrcodeService.pyzbar.decode')
128def test_decode_qr_image_no_code_none(mock_decode, fake_image):
129    """
130    Negative scenario: The library returns None (theoretical case of a library error).
131    Expected exception: NoCodeFoundError.
132    """
133    # Setup
134    mock_decode.return_value = None
135
136    # Action & Assert
137    with pytest.raises(NoCodeFoundError, match="Nie wykryto kodu QR"):
138        decode_qr_image(fake_image)

Negative scenario: The library returns None (theoretical case of a library error). Expected exception: NoCodeFoundError.

@patch('backend.components.camera_verification.qrcode.qrcodeService.pyzbar.decode')
def test_decode_qr_image_decoding_utf8_error(mock_decode, fake_image):
141@patch('backend.components.camera_verification.qrcode.qrcodeService.pyzbar.decode')
142def test_decode_qr_image_decoding_utf8_error(mock_decode, fake_image):
143    """
144    Sprawdza, czy błąd dekodowania bajtów (np. złe kodowanie) rzuci standardowy błąd Pythonowy
145    lub czy przejdzie (zależnie od implementacji, tutaj testujemy domyślne zachowanie .decode()).
146    """
147    # Setup
148    mock_qr_obj = MagicMock()
149    # Niepoprawna sekwencja UTF-8
150    mock_qr_obj.data = b'\xff\xfe\xfa'
151
152    mock_decode.return_value = [mock_qr_obj]
153
154    # Action & Assert
155    with pytest.raises(UnicodeDecodeError):
156        decode_qr_image(fake_image)

Sprawdza, czy błąd dekodowania bajtów (np. złe kodowanie) rzuci standardowy błąd Pythonowy lub czy przejdzie (zależnie od implementacji, tutaj testujemy domyślne zachowanie .decode()).