diff --git a/.github/workflows/python.yml b/.github/workflows/python.yml index 79c133e..506742a 100644 --- a/.github/workflows/python.yml +++ b/.github/workflows/python.yml @@ -31,4 +31,4 @@ jobs: - name: Type checks run: uv run ty check . - name: Tests - run: uv run python -m unittest discover --verbose . + run: uv run pytest diff --git a/LICENSE b/LICENSE index deac713..40266d7 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2016 The py_cppmodel Authors. All Rights Reserved. +Copyright (c) 2016 The py-cppmodel Authors. All Rights Reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in diff --git a/README.md b/README.md index 85a9eb9..de04512 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ uv sync To run the tests, run: ```sh -uv run python -m unittest discover --verbose . +uv run pytest ``` To run type checking: diff --git a/pyproject.toml b/pyproject.toml index c454199..cc20262 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -18,11 +18,15 @@ Repository = "https://github.com/jbcoe/py_cppmodel" dev = [ "ipython>=8.12.3", "jupyter>=1.1.1", - "parameterized>=0.9.0", "pre-commit>=4.5.1", + "pytest>=9.0.2", + "pytest-xdist>=3.8.0", "ty>=0.0.14", ] +[tool.pytest.ini_options] +addopts = "-n auto -v" + [build-system] requires = ["hatchling"] build-backend = "hatchling.build" diff --git a/test.macos.sh b/test.macos.sh index 0b271a1..8014f92 100755 --- a/test.macos.sh +++ b/test.macos.sh @@ -7,4 +7,4 @@ uv sync uv run ty check . # Unit tests -uv run python -m unittest discover --verbose . +uv run pytest diff --git a/test_parse_standard_library_includes.py b/test_parse_standard_library_includes.py index 218af70..716f7d4 100644 --- a/test_parse_standard_library_includes.py +++ b/test_parse_standard_library_includes.py @@ -1,7 +1,5 @@ -import unittest - +import pytest from clang.cindex import TranslationUnit -from parameterized import parameterized import py_cppmodel @@ -14,50 +12,41 @@ ] -def _custom_name_func(testcase_func, _, param): - return "%s_%s" % (testcase_func.__name__, parameterized.to_safe_name(param.args[0])) - - -class TestStandardLibraryIncludes(unittest.TestCase): - @parameterized.expand( - [ - "algorithm", - "any", - "array", - "deque", - "forward_list", - "functional", - "iterator", - "list", - "map", - "memory", - "numeric", - "optional", - "queue", - "set", - "stack", - "string", - "tuple", - "type_traits", - "unordered_map", - "unordered_set", - "utility", - "variant", - "vector", - ], - name_func=_custom_name_func, +@pytest.mark.parametrize( + "include", + [ + "algorithm", + "any", + "array", + "deque", + "forward_list", + "functional", + "iterator", + "list", + "map", + "memory", + "numeric", + "optional", + "queue", + "set", + "stack", + "string", + "tuple", + "type_traits", + "unordered_map", + "unordered_set", + "utility", + "variant", + "vector", + ], +) +def test_include(include): + source = f"#include <{include}>" + tu = TranslationUnit.from_source( + "t.cc", + COMPILER_ARGS, + unsaved_files=[("t.cc", source)], ) - def test_include(self, include): - source = f"#include <{include}>" - tu = TranslationUnit.from_source( - "t.cc", - COMPILER_ARGS, - unsaved_files=[("t.cc", source)], - ) - - # This should not raise an exception. - self.model = py_cppmodel.Model(tu) - -if __name__ == "__main__": - unittest.main() + # This should not raise an exception. + py_cppmodel.Model(tu) diff --git a/test_py_cppmodel.py b/test_py_cppmodel.py index 92ee415..908262b 100644 --- a/test_py_cppmodel.py +++ b/test_py_cppmodel.py @@ -1,5 +1,4 @@ -import unittest - +import pytest from clang.cindex import TranslationUnit import py_cppmodel @@ -35,59 +34,53 @@ class B { """ -class TestCppModel(unittest.TestCase): - def setUp(self): - tu = TranslationUnit.from_source( - "sample.cc", - COMPILER_ARGS, - unsaved_files=[("sample.cc", SOURCE)], - ) - self.model = py_cppmodel.Model(tu) - - def test_filename(self): - self.assertEqual(self.model.filename, "sample.cc") - - def test_functions(self): - self.assertEqual(len(self.model.functions), 2) - self.assertEqual(str(self.model.functions[0]), "") - self.assertEqual(str(self.model.functions[1]), "") - - def test_classes(self): - self.assertEqual(len(self.model.classes), 1) - self.assertEqual(str(self.model.classes[0]), "") - - self.assertEqual(len(self.model.classes[0].annotations), 1) - self.assertEqual(self.model.classes[0].annotations[0], "A") - - self.assertEqual(len(self.model.classes[0].members), 3) - self.assertEqual( - str(self.model.classes[0].members[0]), - " a>", - ) - self.assertEqual( - str(self.model.classes[0].members[1]), - " b>", - ) - self.assertEqual( - str(self.model.classes[0].members[2]), - " c>", - ) - - self.assertEqual(len(self.model.classes[0].methods), 1) - self.assertEqual(str(self.model.classes[0].methods[0]), "") - self.assertEqual(len(self.model.classes[0].methods[0].annotations), 1) - self.assertEqual(self.model.classes[0].methods[0].annotations[0], "foo") - - self.assertEqual(len(self.model.unmodelled_nodes), 2) - self.assertEqual( - str(self.model.unmodelled_nodes[0]), - ">", - ) - self.assertEqual( - str(self.model.unmodelled_nodes[1]), - " >", - ) - - -if __name__ == "__main__": - unittest.main() +@pytest.fixture +def model(): + tu = TranslationUnit.from_source( + "sample.cc", + COMPILER_ARGS, + unsaved_files=[("sample.cc", SOURCE)], + ) + return py_cppmodel.Model(tu) + + +def test_filename(model): + assert model.filename == "sample.cc" + + +def test_functions(model): + assert len(model.functions) == 2 + assert str(model.functions[0]) == "" + assert str(model.functions[1]) == "" + + +def test_classes(model): + assert len(model.classes) == 1 + assert str(model.classes[0]) == "" + + assert len(model.classes[0].annotations) == 1 + assert model.classes[0].annotations[0] == "A" + + +def test_class_members(model): + assert len(model.classes[0].members) == 3 + assert str(model.classes[0].members[0]) == " a>" + assert str(model.classes[0].members[1]) == " b>" + assert str(model.classes[0].members[2]) == " c>" + + assert len(model.classes[0].methods) == 1 + assert str(model.classes[0].methods[0]) == "" + assert len(model.classes[0].methods[0].annotations) == 1 + assert model.classes[0].methods[0].annotations[0] == "foo" + + +def test_unmodelled_nodes(model): + assert len(model.unmodelled_nodes) == 2 + assert ( + str(model.unmodelled_nodes[0]) + == ">" + ) + assert ( + str(model.unmodelled_nodes[1]) + == " >" + ) diff --git a/uv.lock b/uv.lock index bd4be30..5be05d7 100644 --- a/uv.lock +++ b/uv.lock @@ -445,6 +445,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl", hash = "sha256:a7a39a3bd276781e98394987d3a5701d0c4edffb633bb7a5144577f82c773598", size = 16740, upload-time = "2025-11-21T23:01:53.443Z" }, ] +[[package]] +name = "execnet" +version = "2.1.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/bf/89/780e11f9588d9e7128a3f87788354c7946a9cbb1401ad38a48c4db9a4f07/execnet-2.1.2.tar.gz", hash = "sha256:63d83bfdd9a23e35b9c6a3261412324f964c2ec8dcd8d3c6916ee9373e0befcd", size = 166622, upload-time = "2025-11-12T09:56:37.75Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ab/84/02fc1827e8cdded4aa65baef11296a9bbe595c474f0d6d758af082d849fd/execnet-2.1.2-py3-none-any.whl", hash = "sha256:67fba928dd5a544b783f6056f449e5e3931a5c378b128bc18501f7ea79e296ec", size = 40708, upload-time = "2025-11-12T09:56:36.333Z" }, +] + [[package]] name = "executing" version = "2.2.1" @@ -536,6 +545,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea", size = 71008, upload-time = "2025-10-12T14:55:18.883Z" }, ] +[[package]] +name = "iniconfig" +version = "2.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size = 20503, upload-time = "2025-10-18T21:55:43.219Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" }, +] + [[package]] name = "ipykernel" version = "7.1.0" @@ -1239,6 +1257,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/cb/28/3bfe2fa5a7b9c46fe7e13c97bda14c895fb10fa2ebf1d0abb90e0cea7ee1/platformdirs-4.5.1-py3-none-any.whl", hash = "sha256:d03afa3963c806a9bed9d5125c8f4cb2fdaf74a55ab60e5d59b3fde758104d31", size = 18731, upload-time = "2025-12-05T13:52:56.823Z" }, ] +[[package]] +name = "pluggy" +version = "1.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" }, +] + [[package]] name = "pre-commit" version = "4.5.1" @@ -1338,6 +1365,8 @@ dev = [ { name = "jupyter" }, { name = "parameterized" }, { name = "pre-commit" }, + { name = "pytest" }, + { name = "pytest-xdist" }, { name = "ty" }, ] @@ -1353,6 +1382,8 @@ dev = [ { name = "jupyter", specifier = ">=1.1.1" }, { name = "parameterized", specifier = ">=0.9.0" }, { name = "pre-commit", specifier = ">=4.5.1" }, + { name = "pytest", specifier = ">=9.0.2" }, + { name = "pytest-xdist", specifier = ">=3.8.0" }, { name = "ty", specifier = ">=0.0.14" }, ] @@ -1374,6 +1405,37 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" }, ] +[[package]] +name = "pytest" +version = "9.0.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, + { name = "iniconfig" }, + { name = "packaging" }, + { name = "pluggy" }, + { name = "pygments" }, + { name = "tomli", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d1/db/7ef3487e0fb0049ddb5ce41d3a49c235bf9ad299b6a25d5780a89f19230f/pytest-9.0.2.tar.gz", hash = "sha256:75186651a92bd89611d1d9fc20f0b4345fd827c41ccd5c299a868a05d70edf11", size = 1568901, upload-time = "2025-12-06T21:30:51.014Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3b/ab/b3226f0bd7cdcf710fbede2b3548584366da3b19b5021e74f5bde2a8fa3f/pytest-9.0.2-py3-none-any.whl", hash = "sha256:711ffd45bf766d5264d487b917733b453d917afd2b0ad65223959f59089f875b", size = 374801, upload-time = "2025-12-06T21:30:49.154Z" }, +] + +[[package]] +name = "pytest-xdist" +version = "3.8.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "execnet" }, + { name = "pytest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/78/b4/439b179d1ff526791eb921115fca8e44e596a13efeda518b9d845a619450/pytest_xdist-3.8.0.tar.gz", hash = "sha256:7e578125ec9bc6050861aa93f2d59f1d8d085595d6551c2c90b6f4fad8d3a9f1", size = 88069, upload-time = "2025-07-01T13:30:59.346Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ca/31/d4e37e9e550c2b92a9cbc2e4d0b7420a27224968580b5a447f420847c975/pytest_xdist-3.8.0-py3-none-any.whl", hash = "sha256:202ca578cfeb7370784a8c33d6d05bc6e13b4f25b5053c30a152269fd10f0b88", size = 46396, upload-time = "2025-07-01T13:30:56.632Z" }, +] + [[package]] name = "python-dateutil" version = "2.9.0.post0"