Skip to content

Commit

Permalink
Merge pull request #3 from Matzey/main
Browse files Browse the repository at this point in the history
Improved unit tests to mock requests
  • Loading branch information
K0ntr4 authored Apr 22, 2024
2 parents e135b49 + ba99123 commit 5acf07a
Show file tree
Hide file tree
Showing 8 changed files with 164 additions and 47 deletions.
4 changes: 0 additions & 4 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,5 @@ jobs:
pip install -r requirements.txt
- name: Run unit tests
env:
NLTK_DATA: ${{ secrets.NLTK_DATA }}
TWITCH_CLIENT_ID: ${{ secrets.TWITCH_CLIENT_ID }}
TWITCH_CLIENT_SECRET: ${{ secrets.TWITCH_CLIENT_SECRET }}
run: |
python -m unittest discover -s src/tests -p 'test_*.py'
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ thefuzz==0.22.1
torch==2.2.2
transformers==4.39.2
accelerate==0.28.0
mock==5.1.0
5 changes: 4 additions & 1 deletion resources/form.scss
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ $font-size: 16px;

.QLineEdit {
color: $secondary-accent-color;
border:none;
border: none;
border-bottom: 2px solid $accent-color;
padding-bottom: 2px;
background: $main-color;
Expand All @@ -27,14 +27,17 @@ $font-size: 16px;
border-radius: 5px;
color: $accent-color;
background-color: $main-color;

&:hover {
border: 2px solid $secondary-color;
background-color: $secondary-color;
}

&:pressed {
border: 2px solid $accent-color;
background-color: $accent-color;
}

&:disabled {
color: $main-color;
background-color: $main-color;
Expand Down
9 changes: 5 additions & 4 deletions src/image/character_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,14 @@
"/animagine-xl-3.1/raw/main/wildcard/characterfull.txt")


def get_all_characters():
def get_all_characters() -> list[str]:
"""
Get all characters from the character list.
"""
with requests.get(CHARACTER_LIST_URL, timeout=3) as response:
response.raise_for_status()
return response.text.split("\n")
response = requests.get(CHARACTER_LIST_URL, timeout=3)
response.raise_for_status()
text: list[str] = response.text.split("\n")
return text


def get_closest_character(name):
Expand Down
2 changes: 1 addition & 1 deletion src/image/game_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,6 @@ def authenticate(self):
"""
if self.token and time.time() - self.authentication_time < self.token['expires_in']:
return

url = "https://id.twitch.tv/oauth2/token"
payload = {
"client_id": self.client_id,
Expand All @@ -84,6 +83,7 @@ def authenticate(self):
response.raise_for_status()
self.token = response.json()
self.authentication_time = time.time()
return

def get_game_info(self, name):
"""
Expand Down
3 changes: 3 additions & 0 deletions src/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -194,8 +194,10 @@ def generate_image(self):
"Please enter an anime character name.")
return
self.input_controls["generate_button"].setDisabled(True)

input_values = {key: widget.text().lower().replace(',', ' ').lstrip().rstrip()
for key, widget in self.inputs.items()}

threading.Thread(target=self.image_generator.process_image,
args=(input_values, self)).start()

Expand All @@ -215,6 +217,7 @@ def show_image(self):

for item in self.image_controls.values():
item.show()

if len(self.image_generator.images) != 1:
for item in self.image_navigation_buttons.values():
item.show()
Expand Down
71 changes: 64 additions & 7 deletions src/tests/test_character_info.py
Original file line number Diff line number Diff line change
@@ -1,33 +1,90 @@
import unittest
from unittest.mock import patch, Mock
from src.image.character_info import (
get_all_characters, get_closest_character, get_closest_characters
)


class TestCharacterFunctions(unittest.TestCase):
@classmethod
def setUpClass(cls):
cls.character_list = ["souryuu asuka langley", "warrior of light (ff14)"]
def __init__(self, methodName: str = "runTest") -> None:
super().__init__(methodName)
self.character_list = ["souryuu asuka langley", "warrior of light (ff14)"]

@patch('requests.get')
def test_get_all_characters(self, mock_get):
mock_response = Mock()
response_body = ("1girl, souryuu asuka langley, neon genesis evangelion\n"
"1girl, warrior of light \\(ff14\\), final fantasy\n"
"1girl, akiyama mio, k-on!\n"
"1girl, tifa lockhart, final fantasy\n"
"1girl, 2b \\(nier:automata\\), nier \\(series\\)\n"
"1girl, nakano azusa, k-on!\n"
"1girl, rem \\(re:zero\\), re:zero kara hajimeru isekai seikatsu\n"
"1girl, hirasawa yui, k-on!\n"
"1girl, gotoh hitori, bocchi the rock!\n"
"1girl, ayanami rei, neon genesis evangelion\n"
"1boy, male focus, joseph joestar, jojo no kimyou na bouken\n"
"1girl, matoi ryuuko, kill la kill\n"
"1girl, yor briar, spy x family\n"
"1girl, tainaka ritsu, k-on!\n")
mock_response.text = response_body
mock_get.return_value = mock_response

def test_get_all_characters(self):
characters = get_all_characters()

self.assertIsInstance(characters, list)
self.assertTrue(all(isinstance(c, str) for c in characters))

def test_get_closest_character(self):
@patch('requests.get')
def test_get_closest_character(self, mock_get):
mock_response = Mock()
response_body = ("1girl, souryuu asuka langley, neon genesis evangelion\n"
"1girl, warrior of light \\(ff14\\), final fantasy\n"
"1girl, akiyama mio, k-on!\n"
"1girl, tifa lockhart, final fantasy\n"
"1girl, 2b \\(nier:automata\\), nier \\(series\\)\n"
"1girl, nakano azusa, k-on!\n"
"1girl, rem \\(re:zero\\), re:zero kara hajimeru isekai seikatsu\n"
"1girl, hirasawa yui, k-on!\n"
"1girl, gotoh hitori, bocchi the rock!\n"
"1girl, ayanami rei, neon genesis evangelion\n"
"1boy, male focus, joseph joestar, jojo no kimyou na bouken\n"
"1girl, matoi ryuuko, kill la kill\n"
"1girl, yor briar, spy x family\n"
"1girl, tainaka ritsu, k-on!\n")
mock_response.text = response_body
mock_get.return_value = mock_response
closest_name = get_closest_character("Asuka Langley")

self.assertEqual(closest_name, "1girl, souryuu asuka langley, neon genesis evangelion")

def test_get_closest_characters(self):
@patch('requests.get')
def test_get_closest_characters(self, mock_get):
mock_response = Mock()
response_body = ("1boy, male focus, uzumaki naruto, naruto \\(series\\)\n"
"1boy, male focus, uzumaki boruto, naruto \\(series\\)\n"
"1girl, uzumaki himawari, naruto \\(series\\)\n"
"1girl, carrot \\(one piece\\), one piece\n"
"1girl, uzumaki kushina, naruto \\(series\\)\n")
mock_response.text = response_body
mock_get.return_value = mock_response

closest_names = get_closest_characters("Naruto Uzumaki", 3)

self.assertEqual(closest_names, ['1boy, male focus, uzumaki naruto, naruto \\(series\\)',
'1boy, male focus, uzumaki boruto, naruto \\(series\\)',
'1girl, uzumaki himawari, naruto \\(series\\)'])

def test_get_closest_character_not_found(self):
@patch('requests.get')
def test_get_closest_character_not_found(self, mock_get):
mock_response = Mock()
response_body = ("1boy, male focus, uzumaki naruto, naruto \\(series\\)\n"
"1boy, male focus, uzumaki boruto, naruto \\(series\\)\n"
"1girl, uzumaki himawari, naruto \\(series\\)\n"
"1girl, carrot \\(one piece\\), one piece\n"
"1girl, uzumaki kushina, naruto \\(series\\)\n")
mock_response.text = response_body
mock_get.return_value = mock_response
closest_name = get_closest_character("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")

self.assertIsNone(closest_name)
Expand Down
116 changes: 86 additions & 30 deletions src/tests/test_game_info.py
Original file line number Diff line number Diff line change
@@ -1,51 +1,107 @@
import time
import unittest
from unittest.mock import patch, Mock
from src.image.game_info import (
GameInfo, get_year_recency,
get_summary_keywords, is_relevant_adjective
)

TEKKEN_GAME_INFO = {
'id': 7498,
'first_release_date': 1424217600,
'genres': [4],
'name': 'Tekken 7',
'summary': ('Experience the epic conclusion of the Mishima clan and unravel '
'the reasons behind each step of their ceaseless fight. '
'Powered by Unreal Engine 4, Tekken 7 features stunning '
'story-driven cinematic battles and intense duels that '
'can be enjoyed with friends and rivals alike through '
'innovative fight mechanics.')
}


class TestGameInfo(unittest.TestCase):
def setUp(self):
def __init__(self, methodName: str = "runTest") -> None:
super().__init__(methodName)
self.game_info = GameInfo()

def test_authenticate(self):
@patch('requests.post')
def test_authenticate(self, mock_post):
"""
Test Twitch API Authentication
"""
mock_response = Mock()
response_body = {
"access_token": "someAccessToken",
"expires_in": 9112004,
"token_type": "bearer"
}
mock_response.json.return_value = response_body
mock_post.return_value = mock_response

self.game_info.authenticate()

self.assertIsNotNone(self.game_info.token)
self.assertIsNotNone(self.game_info.authentication_time)
self.assertTrue(time.time() - self.game_info.authentication_time
< self.game_info.token['expires_in'])

def test_get_game_info(self):
game_data = self.game_info.get_game_info('Tekken 7')

self.assertIsNotNone(game_data)
self.assertEqual(game_data['name'], 'Tekken 7')
self.assertEqual(game_data['first_release_date'], 1424217600)
self.assertEqual(game_data['genres'], [4])
self.assertEqual(game_data['summary'], 'Experience the epic conclusion of the '
'Mishima clan and unravel the '
'reasons behind each step of their ceaseless fight. '
'Powered by Unreal '
'Engine 4, Tekken 7 features stunning story-driven '
'cinematic battles '
'and intense duels that can be enjoyed with friends '
'and rivals alike '
'through innovative fight mechanics.')

def test_get_genres(self):
genres = self.game_info.get_genres([4])

self.assertEqual(genres, ['Fighting'])
self.assertTrue(time.time() - response_body["expires_in"]
< self.game_info.authentication_time)

@patch("requests.post")
@patch("src.image.game_info.GameInfo.authenticate", Mock())
def test_get_game_info(self, mock_post_info):
"""
Test IGDB Response on https://api.igdb.com/v4/games
"""
mock_response = Mock()
response_body = [TEKKEN_GAME_INFO, {}]
mock_response.json.return_value = response_body
mock_post_info.return_value = mock_response
self.game_info.token = {
"access_token": "someAccessToken",
"expires_in": 9112004,
"token_type": "bearer"
}
info = self.game_info.get_game_info("Tekken 7")

self.assertEqual(response_body[0], info)

@patch("requests.post")
@patch("src.image.game_info.GameInfo.authenticate", Mock())
def test_get_genres(self, mock_post):
"""
Test IGDB Response on https://api.igdb.com/v4/genres
"""
mock_response = Mock()
response_body = [{
"id": 4,
"name": "Fighting"
}]
mock_response.json.return_value = response_body
mock_post.return_value = mock_response
self.game_info.token = {
"access_token": "someAccessToken",
"expires_in": 9112004,
"token_type": "bearer"
}
self.game_info.get_genres([4])

self.assertEqual(response_body[0]["name"], 'Fighting')

@patch("src.image.game_info.GameInfo.get_game_info", Mock(return_value=TEKKEN_GAME_INFO))
@patch("src.image.game_info.GameInfo.get_genres", Mock(return_value=['Fighting']))
@patch("src.image.game_info.GameInfo.authenticate", Mock())
def test_get_game_keywords(self):
"""
Test IGDB Response on https://api.igdb.com/v4/genres
"""
self.game_info.token = {
"access_token": "someAccessToken",
"expires_in": 9112004,
"token_type": "bearer"
}
keywords = self.game_info.get_game_keywords('Tekken 7')

self.assertIsNotNone(keywords)
self.assertEqual(keywords[0], 'mid')
# The order of the keywords may vary
self.assertIn('Fighting', keywords[1])
self.assertIn("Fighting", keywords[1])

def test_get_year_recency(self):
self.assertEqual(get_year_recency(time.time()), 'newest')
Expand Down

0 comments on commit 5acf07a

Please sign in to comment.