diff --git a/.gitignore b/.gitignore index f45b47b5..0e0879d1 100644 --- a/.gitignore +++ b/.gitignore @@ -27,3 +27,5 @@ var/ .idea/ .vscode/ venv +env39 +tests/validation_images/*.png \ No newline at end of file diff --git a/src/repositories/gameWindow/core.py b/src/repositories/gameWindow/core.py index 58d6e881..e3f8aed2 100644 --- a/src/repositories/gameWindow/core.py +++ b/src/repositories/gameWindow/core.py @@ -1,13 +1,19 @@ -from typing import Tuple, Union +from typing import Tuple, Union, Dict from src.shared.typings import BBox, Coordinate, GrayImage, Slot from src.utils.core import hashit, locate from .config import arrowsImagesHashes, gameWindowCache, images +def get_global_game_cache_window_cache() -> Dict: + """ + function to ease mocking the cache + """ + global gameWindowCache + return gameWindowCache # TODO: add unit tests # TODO: add perf def getLeftArrowPosition(screenshot: GrayImage) -> Union[BBox, None]: - global gameWindowCache + gameWindowCache = get_global_game_cache_window_cache() if gameWindowCache['left']['position'] is not None: leftArrowImage = images['arrows'][gameWindowCache['left']['arrow']] leftArrowImageHash = hashit(leftArrowImage) @@ -38,7 +44,7 @@ def getLeftArrowPosition(screenshot: GrayImage) -> Union[BBox, None]: # TODO: add unit tests # TODO: add perf def getRightArrowPosition(screenshot: GrayImage) -> Union[BBox, None]: - global gameWindowCache + gameWindowCache = get_global_game_cache_window_cache() if gameWindowCache['right']['position'] is not None: images['arrows'][gameWindowCache['right']['arrow']] rightArrowImage = images['arrows'][gameWindowCache['right']['arrow']] diff --git a/src/utils/camera.py b/src/utils/camera.py new file mode 100644 index 00000000..0ed9b7a2 --- /dev/null +++ b/src/utils/camera.py @@ -0,0 +1,16 @@ + +import pyautogui +import cv2 +import numpy as np + +class PyCamera(): + is_capturing = True + + def get_latest_frame(self, path='screen.png'): + img = pyautogui.screenshot() + img = cv2.cvtColor(np.array(img), cv2.COLOR_RGB2GRAY) + if path: + # import cv2; cv2.imwrite('screen_test.png', screenshot) + cv2.imwrite(path, img) + return img + \ No newline at end of file diff --git a/tests/unit/repositories/actionBar/core/hasCooldownByImage/test_hasCooldownByImage.py b/tests/unit/repositories/actionBar/core/hasCooldownByImage/test_hasCooldownByImage.py index 74ce29ab..a7dedaa4 100644 --- a/tests/unit/repositories/actionBar/core/hasCooldownByImage/test_hasCooldownByImage.py +++ b/tests/unit/repositories/actionBar/core/hasCooldownByImage/test_hasCooldownByImage.py @@ -3,7 +3,7 @@ from src.utils.image import loadFromRGBToGray -actionBarPath = 'src/features/actionBar' +actionBarPath = 'src/repositories/actionBar' currentPath = pathlib.Path(__file__).parent.resolve() screenshotImage = loadFromRGBToGray(f'{currentPath}/screenshot.png') listOfCooldownsImage = loadFromRGBToGray(f'{currentPath}/listOfCooldownsImage.png') @@ -11,7 +11,7 @@ def test_should_return_None_when_getCooldownsImage_return_None(mocker): - getCooldownsImageSpy = mocker.patch('src.repositories.actionBar.extractors.getCooldownsImage', return_value=None) + getCooldownsImageSpy = mocker.patch('src.repositories.actionBar.core.getCooldownsImage', return_value=None) locateSpy = mocker.patch('src.utils.core.locate', return_value=None) hasCooldown = hasCooldownByImage(screenshotImage, cooldownImage) expectedHasCooldownByImage = None @@ -21,8 +21,8 @@ def test_should_return_None_when_getCooldownsImage_return_None(mocker): def test_should_return_False_when_locate_return_None(mocker): - getCooldownsImageSpy = mocker.patch('src.repositories.actionBar.extractors.getCooldownsImage', return_value=listOfCooldownsImage) - locateSpy = mocker.patch('src.utils.core.locate', return_value=None) + getCooldownsImageSpy = mocker.patch('src.repositories.actionBar.core.getCooldownsImage', return_value=listOfCooldownsImage) + locateSpy = mocker.patch('src.repositories.actionBar.core.locate', return_value=None) hasCooldown = hasCooldownByImage(screenshotImage, cooldownImage) expectedHasCooldownByImage = False assert hasCooldown == expectedHasCooldownByImage diff --git a/tests/unit/repositories/actionBar/extractors/test_getCooldownsImage.py b/tests/unit/repositories/actionBar/extractors/test_getCooldownsImage.py index d583af20..5cfb965b 100644 --- a/tests/unit/repositories/actionBar/extractors/test_getCooldownsImage.py +++ b/tests/unit/repositories/actionBar/extractors/test_getCooldownsImage.py @@ -1,3 +1,4 @@ + import numpy as np import pathlib from src.repositories.actionBar.extractors import getCooldownsImage @@ -10,10 +11,8 @@ def test_should_return_None_when_cannot_get_left_arrows_position(mocker): - getLeftArrowsPositionSpy = mocker.patch( - 'actionBar.locators.getLeftArrowsPosition', return_value=None) - getRightArrowsPositionSpy = mocker.patch( - 'actionBar.locators.getRightArrowsPosition', return_value=None) + getLeftArrowsPositionSpy = mocker.patch('src.repositories.actionBar.extractors.getLeftArrowsPosition', return_value=None) + getRightArrowsPositionSpy = mocker.patch('src.repositories.actionBar.extractors.getRightArrowsPosition', return_value=None) cooldownsImage = getCooldownsImage(screenshotImage) expectedCooldownsImage = None assert cooldownsImage is expectedCooldownsImage @@ -23,9 +22,9 @@ def test_should_return_None_when_cannot_get_left_arrows_position(mocker): def test_should_return_None_when_cannot_get_right_arrows_position(mocker): getLeftArrowsPositionSpy = mocker.patch( - 'actionBar.locators.getLeftArrowsPosition', return_value=(0, 392, 17, 34)) + 'src.repositories.actionBar.extractors.getLeftArrowsPosition', return_value=(0, 392, 17, 34)) getRightArrowsPositionSpy = mocker.patch( - 'actionBar.locators.getRightArrowsPosition', return_value=None) + 'src.repositories.actionBar.extractors.getRightArrowsPosition', return_value=None) result = getCooldownsImage(screenshotImage) assert result == None getLeftArrowsPositionSpy.assert_called_once_with(screenshotImage) diff --git a/tests/unit/repositories/battleList/core/getCreatures/test_getCreatures.py b/tests/unit/repositories/battleList/core/getCreatures/test_getCreatures.py index 91b953ca..50121084 100644 --- a/tests/unit/repositories/battleList/core/getCreatures/test_getCreatures.py +++ b/tests/unit/repositories/battleList/core/getCreatures/test_getCreatures.py @@ -4,9 +4,9 @@ def test_should_return_an_empty_array_when_filled_slots_count_is_zero(mocker): - getFilledSlotsCountSpy = mocker.patch('battleList.core.getFilledSlotsCount', return_value=0) - getBeingAttackedCreaturesSpy = mocker.patch('battleList.core.getBeingAttackedCreatures') - getCreaturesNamesSpy = mocker.patch('battleList.core.getCreaturesNames') + getFilledSlotsCountSpy = mocker.patch('src.repositories.battleList.core.getFilledSlotsCount', return_value=0) + getBeingAttackedCreaturesSpy = mocker.patch('src.repositories.battleList.core.getBeingAttackedCreatures') + getCreaturesNamesSpy = mocker.patch('src.repositories.battleList.core.getCreaturesNames') content = np.array([], dtype=np.uint8) creatures = getCreatures(content) expectedCreatures = np.array([], dtype=Creature) @@ -18,9 +18,9 @@ def test_should_return_an_empty_array_when_filled_slots_count_is_zero(mocker): def test_should_return_an_array_of_creatures_when_filled_slots_count_is_greater_than_zero(mocker): creature = ('Rat', True) - getFilledSlotsCountSpy = mocker.patch('battleList.core.getFilledSlotsCount', return_value=1) - getBeingAttackedCreaturesSpy = mocker.patch('battleList.core.getBeingAttackedCreatures', return_value=[True]) - getCreaturesNamesSpy = mocker.patch('battleList.core.getCreaturesNames', return_value=['Rat']) + getFilledSlotsCountSpy = mocker.patch('src.repositories.battleList.core.getFilledSlotsCount', return_value=1) + getBeingAttackedCreaturesSpy = mocker.patch('src.repositories.battleList.core.getBeingAttackedCreatures', return_value=[True]) + getCreaturesNamesSpy = mocker.patch('src.repositories.battleList.core.getCreaturesNames', return_value=['Rat']) content = np.array([], dtype=np.uint8) creatures = getCreatures(content) expectedCreatures = np.array([creature], dtype=Creature) diff --git a/tests/unit/repositories/battleList/extractors/getContent/test_getContent.py b/tests/unit/repositories/battleList/extractors/getContent/test_getContent.py index e62972f1..88370ec7 100644 --- a/tests/unit/repositories/battleList/extractors/getContent/test_getContent.py +++ b/tests/unit/repositories/battleList/extractors/getContent/test_getContent.py @@ -9,8 +9,8 @@ def test_should_return_None_when_container_top_bar_position_is_None(mocker): - getContainerTopBarPositionSpy = mocker.patch('battleList.extractors.getContainerTopBarPosition', return_value=None) - getContainerBottomBarPositionSpy = mocker.patch('battleList.extractors.getContainerBottomBarPosition', return_value=None) + getContainerTopBarPositionSpy = mocker.patch('src.repositories.battleList.extractors.getContainerTopBarPosition', return_value=None) + getContainerBottomBarPositionSpy = mocker.patch('src.repositories.battleList.extractors.getContainerBottomBarPosition', return_value=None) content = getContent(screenshotImage) expectedContent = None assert content == expectedContent @@ -19,8 +19,8 @@ def test_should_return_None_when_container_top_bar_position_is_None(mocker): def test_should_return_None_when_container_bottom_bar_position_is_None(mocker): - getContainerTopBarPositionSpy = mocker.patch('battleList.extractors.getContainerTopBarPosition', return_value=(1572, 25, 81, 13)) - getContainerBottomBarPositionSpy = mocker.patch('battleList.extractors.getContainerBottomBarPosition', return_value=None) + getContainerTopBarPositionSpy = mocker.patch('src.repositories.battleList.extractors.getContainerTopBarPosition', return_value=(1572, 25, 81, 13)) + getContainerBottomBarPositionSpy = mocker.patch('src.repositories.battleList.extractors.getContainerBottomBarPosition', return_value=None) content = getContent(screenshotImage) expectedContent = None assert content == expectedContent diff --git a/tests/unit/repositories/battleList/locators/getContainerBottomBarPosition/test_getContainerBottomBarPosition.py b/tests/unit/repositories/battleList/locators/getContainerBottomBarPosition/test_getContainerBottomBarPosition.py index 9510cee3..3f4f07aa 100644 --- a/tests/unit/repositories/battleList/locators/getContainerBottomBarPosition/test_getContainerBottomBarPosition.py +++ b/tests/unit/repositories/battleList/locators/getContainerBottomBarPosition/test_getContainerBottomBarPosition.py @@ -2,6 +2,8 @@ from src.repositories.battleList.locators import getContainerBottomBarPosition from src.utils.image import loadFromRGBToGray +from tests.utils import result_pos_draw + currentPath = pathlib.Path(__file__).parent.resolve() @@ -10,5 +12,8 @@ def test_should_get_container_bottom_bar_pos(): screenshotImage = loadFromRGBToGray(f'{currentPath}/screenshot.png') containerBottomBarPos = getContainerBottomBarPosition(screenshotImage) - expectedContainerBottomBarPos = (1748, 621, 156, 4) + # save for conference + result_pos_draw(screenshotImage, containerBottomBarPos, 'test_should_get_container_bottom_bar_pos.png') + + expectedContainerBottomBarPos = (1572, 1036, 156, 4) assert containerBottomBarPos == expectedContainerBottomBarPos diff --git a/tests/unit/repositories/gameWindow/screenshot01.png b/tests/unit/repositories/gameWindow/screenshot01.png new file mode 100644 index 00000000..fc70f7a7 Binary files /dev/null and b/tests/unit/repositories/gameWindow/screenshot01.png differ diff --git a/tests/unit/repositories/gameWindow/screenshot02_gray.png b/tests/unit/repositories/gameWindow/screenshot02_gray.png new file mode 100644 index 00000000..d6cc1164 Binary files /dev/null and b/tests/unit/repositories/gameWindow/screenshot02_gray.png differ diff --git a/tests/unit/repositories/gameWindow/screenshot03.png b/tests/unit/repositories/gameWindow/screenshot03.png new file mode 100644 index 00000000..42d8af9b Binary files /dev/null and b/tests/unit/repositories/gameWindow/screenshot03.png differ diff --git a/tests/unit/repositories/gameWindow/screenshot04.png b/tests/unit/repositories/gameWindow/screenshot04.png new file mode 100644 index 00000000..8de7a60b Binary files /dev/null and b/tests/unit/repositories/gameWindow/screenshot04.png differ diff --git a/tests/unit/repositories/gameWindow/test_arrows.py b/tests/unit/repositories/gameWindow/test_arrows.py new file mode 100644 index 00000000..c3d22e81 --- /dev/null +++ b/tests/unit/repositories/gameWindow/test_arrows.py @@ -0,0 +1,84 @@ +import pathlib +import cv2 +import numpy as np +import pytest + +from src.repositories.gameWindow.core import getLeftArrowPosition, getRightArrowPosition + +from tests.utils import result_pos_draw + + +currentPath = pathlib.Path(__file__).parent.resolve() +img01 = f'{currentPath}/screenshot01.png' +img02_gray = f'{currentPath}/screenshot02_gray.png' +img03 = f'{currentPath}/screenshot03.png' +img04 = f'{currentPath}/screenshot04.png' + + +def rgb_to_gray(img_path: str, is_gray=False): + img = cv2.imread(img_path) + if is_gray: + return cv2.cvtColor(np.array(img), cv2.COLOR_RGB2GRAY) + else: + return cv2.cvtColor(np.array(img), cv2.COLOR_RGB2GRAY) + + +@pytest.mark.parametrize("img, is_gray", [ + (img01, False), + (img02_gray, True), + (img03, False), + (img04, False), +]) +def test_getLeftArrowPosition(mocker, img, is_gray): + # clean preview test + this_gameWindowCache = { + 'left': {'arrow': None, 'position': None}, + 'right': {'arrow': None, 'position': None}, + } + mocker.patch('src.repositories.gameWindow.core.get_global_game_cache_window_cache', return_value=this_gameWindowCache) + # ---------------------------------- + img_gray = rgb_to_gray(img, is_gray) + result = getLeftArrowPosition(img_gray) + assert result is not None + assert result == (2, 23, 7, 54) + + +@pytest.mark.parametrize("img, is_gray", [ + (img01, False), + (img02_gray, True), + (img03, False), +]) +def test_getRightArrowPosition(mocker, img, is_gray): + # clean preview test + this_gameWindowCache = { + 'left': {'arrow': None, 'position': None}, + 'right': {'arrow': None, 'position': None}, + } + mocker.patch('src.repositories.gameWindow.core.get_global_game_cache_window_cache', return_value=this_gameWindowCache) + # ---------------------------------- + img_gray = rgb_to_gray(img, is_gray) + result = getRightArrowPosition(img_gray) + # result == x, y, width, height + assert result is not None + # img04 should be differrent + result_pos_draw(img_gray,result,f"test_getRightArrowPosition__{img[-15:]}") + assert result == (1561, 23, 7, 54) + +def test_getRightArrowPosition_04(mocker, img=img04, is_gray=False): + # clean preview test + this_gameWindowCache = { + 'left': {'arrow': None, 'position': None}, + 'right': {'arrow': None, 'position': None}, + } + mocker.patch('src.repositories.gameWindow.core.get_global_game_cache_window_cache', return_value=this_gameWindowCache) + # ---------------------------------- + + from src.repositories.gameWindow.config import gameWindowCache + + img_gray = rgb_to_gray(img, is_gray) + result = getRightArrowPosition(img_gray) + # result == x, y, width, height + assert result is not None + # img04 should be differrent + result_pos_draw(img_gray,result,"test_getRightArrowPosition__04.png") + assert result == (1385, 23, 7, 54) \ No newline at end of file diff --git a/tests/unit/repositories/radar/core/test_getClosestWaypointIndexFromCoordinate.py b/tests/unit/repositories/radar/core/test_getClosestWaypointIndexFromCoordinate.py index 28de8541..33a3b2fe 100644 --- a/tests/unit/repositories/radar/core/test_getClosestWaypointIndexFromCoordinate.py +++ b/tests/unit/repositories/radar/core/test_getClosestWaypointIndexFromCoordinate.py @@ -5,10 +5,22 @@ def test_should_return_2_when_closest_waypoint_is_in_index_2(): currentCoordinate = (33094, 32790, 7) - closestWaypoint = ('walk', (33099, 32790, 7), 0) - closestDiagonalWaypoint = ('walk', (33098, 32794, 7), 0) - closestWaypointFromAnotherFloor = ('walk', (33099, 32790, 6), 0) - furthestWaypoint = ('walk', (33082, 32790, 7), 0) + closestWaypoint = ('', 'walk', (33099, 32790, 7), 0) + closestDiagonalWaypoint = ('', 'walk', (33098, 32794, 7), 0) + closestWaypointFromAnotherFloor = ('', 'walk', (33099, 32790, 6), 0) + furthestWaypoint = ('', 'walk', (33082, 32790, 7), 0) + waypoints = np.array( + [furthestWaypoint, closestWaypointFromAnotherFloor, closestWaypoint, closestDiagonalWaypoint], dtype=Waypoint) + result = getClosestWaypointIndexFromCoordinate( + currentCoordinate, waypoints) + assert result == 2 + +def test_should_return_2_when_closest_waypoint_is_in_index_2_optioons_dict(): + currentCoordinate = (33094, 32790, 7) + closestWaypoint = ('', 'walk', (33099, 32790, 7), {}) + closestDiagonalWaypoint = ('', 'walk', (33098, 32794, 7), {}) + closestWaypointFromAnotherFloor = ('', 'walk', (33099, 32790, 6), {}) + furthestWaypoint = ('', 'walk', (33082, 32790, 7), {}) waypoints = np.array( [furthestWaypoint, closestWaypointFromAnotherFloor, closestWaypoint, closestDiagonalWaypoint], dtype=Waypoint) result = getClosestWaypointIndexFromCoordinate( diff --git a/tests/utils.py b/tests/utils.py new file mode 100644 index 00000000..5201def6 --- /dev/null +++ b/tests/utils.py @@ -0,0 +1,12 @@ + +import cv2 +import pathlib + +currentPath = pathlib.Path(__file__).parent.resolve() +import cv2 + +def result_pos_draw(image, result_position, name, color_bgr = (255, 255, 0), thickness=2): + path = f"{currentPath}/validation_images/{name}" + x, y, width, height = result_position + cv2.rectangle(image, (x, y), (x+width, y+height), color_bgr, thickness) + cv2.imwrite(path, image) \ No newline at end of file diff --git a/tests/validation_images/.keep b/tests/validation_images/.keep new file mode 100644 index 00000000..e69de29b