test extract_otps_from_camera()

pull/37/head
scito 1 year ago committed by Roland Kurmann
parent 851cb6532c
commit b215b78dad

@ -220,42 +220,6 @@ def extract_otps(args: Args) -> Otps:
return extract_otps_from_files(args) return extract_otps_from_files(args)
def get_color(new_otps_count: int, otp_url: str) -> ColorBGR:
if new_otps_count:
return SUCCESS_COLOR
else:
if otp_url:
return FAILURE_COLOR
else:
return NORMAL_COLOR
# TODO use cv2 types if available
def cv2_draw_box(img: Any, raw_pts: Any, color: ColorBGR) -> Any:
pts = np.array([raw_pts], np.int32)
pts = pts.reshape((-1, 1, 2))
cv2.polylines(img, [pts], True, color, BOX_THICKNESS)
return pts
# TODO use cv2 types if available
def cv2_print_text(img: Any, text: str, line_number: int, position: TextPosition, color: ColorBGR, opposite_len: Optional[int] = None) -> None:
window_dim = cv2.getWindowImageRect(WINDOW_NAME)
out_text = text
if opposite_len:
text_dim, _ = cv2.getTextSize(out_text, FONT, FONT_SCALE, FONT_THICKNESS)
actual_width = text_dim[TEXT_WIDTH] + opposite_len * CHAR_DX + 4 * BORDER
if actual_width >= window_dim[WINDOW_WIDTH]:
out_text = out_text[:(window_dim[WINDOW_WIDTH] - actual_width) // CHAR_DX] + '.'
text_dim, _ = cv2.getTextSize(out_text, FONT, FONT_SCALE, FONT_THICKNESS)
if position == TextPosition.LEFT:
pos = BORDER, START_Y + line_number * FONT_DY
else:
pos = window_dim[WINDOW_WIDTH] - text_dim[TEXT_WIDTH] - BORDER, START_Y + line_number * FONT_DY
cv2.putText(img, out_text, pos, FONT, FONT_SCALE, color, FONT_THICKNESS, FONT_LINE_STYLE)
def extract_otps_from_camera(args: Args) -> Otps: def extract_otps_from_camera(args: Args) -> Otps:
if verbose: print("Capture QR codes from camera") if verbose: print("Capture QR codes from camera")
otp_urls: OtpUrls = [] otp_urls: OtpUrls = []
@ -325,6 +289,42 @@ def extract_otps_from_camera(args: Args) -> Otps:
return otps return otps
def get_color(new_otps_count: int, otp_url: str) -> ColorBGR:
if new_otps_count:
return SUCCESS_COLOR
else:
if otp_url:
return FAILURE_COLOR
else:
return NORMAL_COLOR
# TODO use cv2 types if available
def cv2_draw_box(img: Any, raw_pts: Any, color: ColorBGR) -> Any:
pts = np.array([raw_pts], np.int32)
pts = pts.reshape((-1, 1, 2))
cv2.polylines(img, [pts], True, color, BOX_THICKNESS)
return pts
# TODO use cv2 types if available
def cv2_print_text(img: Any, text: str, line_number: int, position: TextPosition, color: ColorBGR, opposite_len: Optional[int] = None) -> None:
window_dim = cv2.getWindowImageRect(WINDOW_NAME)
out_text = text
if opposite_len:
text_dim, _ = cv2.getTextSize(out_text, FONT, FONT_SCALE, FONT_THICKNESS)
actual_width = text_dim[TEXT_WIDTH] + opposite_len * CHAR_DX + 4 * BORDER
if actual_width >= window_dim[WINDOW_WIDTH]:
out_text = out_text[:(window_dim[WINDOW_WIDTH] - actual_width) // CHAR_DX] + '.'
text_dim, _ = cv2.getTextSize(out_text, FONT, FONT_SCALE, FONT_THICKNESS)
if position == TextPosition.LEFT:
pos = BORDER, START_Y + line_number * FONT_DY
else:
pos = window_dim[WINDOW_WIDTH] - text_dim[TEXT_WIDTH] - BORDER, START_Y + line_number * FONT_DY
cv2.putText(img, out_text, pos, FONT, FONT_SCALE, color, FONT_THICKNESS, FONT_LINE_STYLE)
def cv2_handle_pressed_keys(qr_mode: QRMode) -> Tuple[bool, QRMode]: def cv2_handle_pressed_keys(qr_mode: QRMode) -> Tuple[bool, QRMode]:
key = cv2.waitKey(1) & 0xFF key = cv2.waitKey(1) & 0xFF
quit = False quit = False

@ -26,7 +26,8 @@ import pathlib
import re import re
import sys import sys
import time import time
from typing import Optional from enum import Enum
from typing import Any, List, Optional, Tuple
import colorama import colorama
import pytest import pytest
@ -37,6 +38,12 @@ from utils import (count_files_in_dir, file_exits, read_binary_file_as_stream,
import extract_otp_secrets import extract_otp_secrets
try:
import cv2 # type: ignore
except ImportError:
# ignore
pass
qreader_available: bool = extract_otp_secrets.qreader_available qreader_available: bool = extract_otp_secrets.qreader_available
@ -494,6 +501,89 @@ def test_extract_no_arguments(capsys: pytest.CaptureFixture[str], mocker: Mocker
assert e.type == SystemExit assert e.type == SystemExit
MockMode = Enum('MockMode', ['REPEAT_FIRST_ENDLESS', 'LOOP_LIST'])
class MockCam:
read_counter: int = 0
read_files: List[str] = []
mock_mode: MockMode
def __init__(self, files: List[str] = ['example_export.png'], mock_mode: MockMode = MockMode.REPEAT_FIRST_ENDLESS):
self.read_files = files
self.image_mode = mock_mode
def read(self) -> Tuple[bool, Any]:
if self.image_mode == MockMode.REPEAT_FIRST_ENDLESS:
file = self.read_files[0]
elif self.image_mode == MockMode.LOOP_LIST:
file = self.read_files[self.read_counter]
self.read_counter += 1
if file:
img = cv2.imread(file)
return True, img
else:
return False, None
def release(self) -> None:
# ignore
pass
@pytest.mark.parametrize("qr_reader", [
None,
'ZBAR',
'QREADER',
'QREADER_DEEP',
'CV2',
'CV2_WECHAT'
])
def test_extract_otps_from_camera(qr_reader: Optional[str], capsys: pytest.CaptureFixture[str], mocker: MockerFixture) -> None:
if qreader_available:
# Arrange
mockCam = MockCam()
mocker.patch('cv2.VideoCapture', return_value=mockCam)
mocker.patch('cv2.namedWindow')
mocker.patch('cv2.rectangle')
mocker.patch('cv2.polylines')
mocker.patch('cv2.imshow')
mocker.patch('cv2.getTextSize', return_value=([8, 200], False))
mocker.patch('cv2.putText')
mocker.patch('cv2.getWindowImageRect', return_value=[0, 0, 640, 480])
mocker.patch('cv2.waitKey', return_value=27)
mocker.patch('cv2.getWindowProperty', return_value=False)
mocker.patch('cv2.destroyAllWindows')
args = []
if qr_reader:
args.append('-Q')
args.append(qr_reader)
# Act
extract_otp_secrets.main(args)
# Assert
captured = capsys.readouterr()
assert captured.out == EXPECTED_STDOUT_FROM_EXAMPLE_EXPORT_PNG
assert captured.err == ''
else:
# Act
with pytest.raises(SystemExit) as e:
extract_otp_secrets.main([])
# Assert
captured = capsys.readouterr()
expected_err_msg = 'error: the following arguments are required: infile'
assert expected_err_msg in captured.err
assert captured.out == ''
assert e.value.code == 2
assert e.type == SystemExit
def test_verbose_and_quiet(capsys: pytest.CaptureFixture[str]) -> None: def test_verbose_and_quiet(capsys: pytest.CaptureFixture[str]) -> None:
with pytest.raises(SystemExit) as e: with pytest.raises(SystemExit) as e:
# Act # Act

Loading…
Cancel
Save