diff --git a/pyproject.toml b/pyproject.toml index 21d5da6..0cd09a2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -11,3 +11,6 @@ dependencies = [ "pydantic>=2.10.6", "python-dotenv>=1.0.1", ] + +[dependency-groups] +dev = ["pytest>=8.3.5"] diff --git a/src/tests/conftest.py b/src/tests/conftest.py new file mode 100644 index 0000000..a154f98 --- /dev/null +++ b/src/tests/conftest.py @@ -0,0 +1,4 @@ +import sys +import os + +sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))) diff --git a/src/tests/github_test.py b/src/tests/github_test.py new file mode 100644 index 0000000..7dbd817 --- /dev/null +++ b/src/tests/github_test.py @@ -0,0 +1,33 @@ +import apis.github as ghapi + + +def test_can_fetch_user(): + ghapi.get_user("ghost") + + +def test_can_fetch_repo(): + ghapi.get_repo("octocat/Spoon-Knife") + + +def test_repo_is_accurate(): + repo = ghapi.get_repo("octocat/Spoon-Knife") + assert repo.full_name == "octocat/Spoon-Knife" + assert repo.description == "This repo is for demonstration purposes only." + assert repo.owner.login == "octocat" + + +def test_repo_is_case_insensitive(): + repo = ghapi.get_repo("OCTOCAT/SPOON-KNIFE") + assert repo.full_name == "octocat/Spoon-Knife" + assert repo.description == "This repo is for demonstration purposes only." + assert repo.owner.login == "octocat" + + repo = ghapi.get_repo("octocat/spoon-knife") + assert repo.full_name == "octocat/Spoon-Knife" + assert repo.description == "This repo is for demonstration purposes only." + assert repo.owner.login == "octocat" + + repo = ghapi.get_repo("OCTOCAT/spoon-knife") + assert repo.full_name == "octocat/Spoon-Knife" + assert repo.description == "This repo is for demonstration purposes only." + assert repo.owner.login == "octocat" diff --git a/src/tests/tictactoe_test.py b/src/tests/tictactoe_test.py new file mode 100644 index 0000000..24aec26 --- /dev/null +++ b/src/tests/tictactoe_test.py @@ -0,0 +1,59 @@ +import games.tictactoe as ttt +import pytest + + +def test_initializes_correctly(): + game = ttt.TicTacToe() + assert game.playfield == [[ttt.Players.Nothing] * 3] * 3 + assert game.current_turn == ttt.Players.Knots + + +def test_does_not_allow_placing_twice(): + game = ttt.TicTacToe() + game.play_move(0, 0) + + with pytest.raises(ValueError): + game.play_move(0, 0) + + +def test_switches_turns_correctly(): + game = ttt.TicTacToe() + game.play_move(0, 0) + assert game.current_turn == ttt.Players.Crosses + game.play_move(1, 1) + assert game.current_turn == ttt.Players.Knots + + +def test_detects_winner(): + game = ttt.TicTacToe() + game.play_move(0, 0) # Knots + game.play_move(1, 0) # Crosses + game.play_move(0, 1) # Knots + game.play_move(1, 1) # Crosses + game.play_move(0, 2) # Knots wins + assert game.checkpoint.win_state == ttt.WinState.Knots + + +def test_detects_crosses_winner(): + game = ttt.TicTacToe() + game.play_move(0, 0) # Knots + game.play_move(1, 0) # Crosses + game.play_move(0, 1) # Knots + game.play_move(1, 1) # Crosses + game.play_move(2, 2) # Knots + game.play_move(1, 2) # Crosses wins + assert game.checkpoint.win_state == ttt.WinState.Crosses + + +def test_detects_draw(): + game = ttt.TicTacToe() + game.play_move(0, 0) # Knots + game.play_move(0, 1) # Crosses + game.play_move(0, 2) # Knots + game.play_move(1, 1) # Crosses + game.play_move(1, 0) # Knots + game.play_move(1, 2) # Crosses + game.play_move(2, 1) # Knots + game.play_move(2, 0) # Crosses + game.play_move(2, 2) # Knots - Draw + assert game.checkpoint.win_state == ttt.WinState.Draw diff --git a/src/tests/toki_pona_test.py b/src/tests/toki_pona_test.py new file mode 100644 index 0000000..695d86c --- /dev/null +++ b/src/tests/toki_pona_test.py @@ -0,0 +1,17 @@ +import apis.sona as sonaapi + + +def test_can_get_word(): + sonaapi.get_word("toki") + + +def test_word_type_is_correct(): + assert type(sonaapi.get_word("toki")) is sonaapi.Word + + +def test_word_has_stats(): + word = sonaapi.get_word("toki") + assert word.word == "toki" + assert word.book == sonaapi.Book.Pu + assert word.coined_era == sonaapi.CoinedEra.PrePu + assert word.creator == ["jan Sonja"] diff --git a/src/tests/xkcd_test.py b/src/tests/xkcd_test.py new file mode 100644 index 0000000..6b08fb6 --- /dev/null +++ b/src/tests/xkcd_test.py @@ -0,0 +1,15 @@ +import apis.xkcd as xkcdapi + + +def test_can_fetch(): + xkcdapi.get_comic(353) + + +def test_is_comic(): + assert type(xkcdapi.get_comic(353)) is xkcdapi.Comic + + +def test_comic_has_stats(): + comic = xkcdapi.get_comic(353) + assert comic.num == 353 + assert comic.title == "Python" diff --git a/uv.lock b/uv.lock index 0db911f..9455720 100644 --- a/uv.lock +++ b/uv.lock @@ -170,6 +170,11 @@ dependencies = [ { name = "python-dotenv" }, ] +[package.dev-dependencies] +dev = [ + { name = "pytest" }, +] + [package.metadata] requires-dist = [ { name = "discord-py", specifier = ">=2.5.2" }, @@ -179,6 +184,9 @@ requires-dist = [ { name = "python-dotenv", specifier = ">=1.0.1" }, ] +[package.metadata.requires-dev] +dev = [{ name = "pytest", specifier = ">=8.3.5" }] + [[package]] name = "frozenlist" version = "1.5.0" @@ -249,6 +257,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442 }, ] +[[package]] +name = "iniconfig" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d7/4b/cbd8e699e64a6f16ca3a8220661b5f83792b3017d0f79807cb8708d33913/iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3", size = 4646 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374", size = 5892 }, +] + [[package]] name = "loguru" version = "0.7.3" @@ -286,6 +303,24 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/99/b7/b9e70fde2c0f0c9af4cc5277782a89b66d35948ea3369ec9f598358c3ac5/multidict-6.1.0-py3-none-any.whl", hash = "sha256:48e171e52d1c4d33888e529b999e5900356b9ae588c2f09a52dcefb158b27506", size = 10051 }, ] +[[package]] +name = "packaging" +version = "24.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d0/63/68dbb6eb2de9cb10ee4c9c14a0148804425e13c4fb20d61cce69f53106da/packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f", size = 163950 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/88/ef/eb23f262cca3c0c4eb7ab1933c3b1f03d021f2c48f54763065b6f0e321be/packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759", size = 65451 }, +] + +[[package]] +name = "pluggy" +version = "1.5.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/96/2d/02d4312c973c6050a18b314a5ad0b3210edb65a906f868e31c111dede4a6/pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1", size = 67955 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669", size = 20556 }, +] + [[package]] name = "propcache" version = "0.3.0" @@ -366,6 +401,21 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/51/b2/b2b50d5ecf21acf870190ae5d093602d95f66c9c31f9d5de6062eb329ad1/pydantic_core-2.27.2-cp313-cp313-win_arm64.whl", hash = "sha256:ac4dbfd1691affb8f48c2c13241a2e3b60ff23247cbcf981759c768b6633cf8b", size = 1885186 }, ] +[[package]] +name = "pytest" +version = "8.3.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "iniconfig" }, + { name = "packaging" }, + { name = "pluggy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ae/3c/c9d525a414d506893f0cd8a8d0de7706446213181570cdbd766691164e40/pytest-8.3.5.tar.gz", hash = "sha256:f4efe70cc14e511565ac476b57c279e12a855b11f48f212af1080ef2263d3845", size = 1450891 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/30/3d/64ad57c803f1fa1e963a7946b6e0fea4a70df53c1a7fed304586539c2bac/pytest-8.3.5-py3-none-any.whl", hash = "sha256:c69214aa47deac29fad6c2a4f590b9c4a9fdb16a403176fe154b79c0b4d4d820", size = 343634 }, +] + [[package]] name = "python-dotenv" version = "1.0.1"