diff --git a/.gitlab/Fedora-Linux-CI.yml b/.gitlab/Fedora-Linux-CI.yml index 0e0ebc9243..782f0bb276 100644 --- a/.gitlab/Fedora-Linux-CI.yml +++ b/.gitlab/Fedora-Linux-CI.yml @@ -142,11 +142,11 @@ fedora_report_metrics_public: - .unit_test - .only_code before_script: - - if [ "$TEST" == "cli" ]; then python3 -m pip install -r qa/tests/requirements.txt; fi + - if [ "$TEST" == "cli" ] || [ "$TEST" == "python" ]; then python3 -m pip install -r qa/tests/requirements.txt; fi parallel: matrix: # The name of the test without the qa_ prefix - - TEST: [python, common, gerbview, pcbnew, eeschema, kimath, sexpr, kicad2step, spice, cli] + - TEST: [python, cli, common, gerbview, pcbnew, eeschema, kimath, sexpr, kicad2step, spice] fedora_qa_kicad: extends: .fedora_qa diff --git a/qa/tests/CMakeLists.txt b/qa/tests/CMakeLists.txt index e00c3e263c..d077d30593 100644 --- a/qa/tests/CMakeLists.txt +++ b/qa/tests/CMakeLists.txt @@ -32,7 +32,7 @@ endif() if( KICAD_TEST_XML_OUTPUT ) # To do this, you will need xmlrunner - set( PYTEST_ARGS_QAPYTHON --xml=${CMAKE_CURRENT_BINARY_DIR}/qapython.xunit-results.xml ) + set( PYTEST_ARGS_QAPYTHON --junitxml=${CMAKE_CURRENT_BINARY_DIR}/qapython.junit-results.xml ) set( PYTEST_ARGS_QACLI --junitxml=${CMAKE_CURRENT_BINARY_DIR}/qacli.junit-results.xml ) endif() @@ -51,8 +51,8 @@ if( NOT (MSVC AND CMAKE_BUILD_TYPE STREQUAL "Debug") ) # qa_python will never work under MSVC + Debug because we only have the Release mode python.exe # but the kicad binaries are linked to the debug mode python # Test that runs the QA tests through scripting -add_test( NAME qa_python - COMMAND ${PYTHON_EXECUTABLE} test-pcbnewswig.py ${PYTEST_ARGS_QAPYTHON} +add_test(NAME qa_python + COMMAND ${PYTHON_EXECUTABLE} -m pytest ${CMAKE_CURRENT_SOURCE_DIR}/pcbnewswig ${PYTEST_ARGS_QACLI} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) diff --git a/qa/tests/pcbnewswig/test_000_qa_works.py b/qa/tests/pcbnewswig/test_000_qa_works.py deleted file mode 100644 index 3757c1944f..0000000000 --- a/qa/tests/pcbnewswig/test_000_qa_works.py +++ /dev/null @@ -1,17 +0,0 @@ -import unittest - -class TestQAWorks(unittest.TestCase): - - def setUp(self): - self.pcb = None - - def test_assert_true( self ): - self.assertTrue( True ) - - def test_assert_equal( self ): - self.assertEqual(2, 1+1) - - -if __name__ == '__main__': - unittest.main() - \ No newline at end of file diff --git a/qa/tests/pcbnewswig/test_001_pcb_load.py b/qa/tests/pcbnewswig/test_001_pcb_load.py index 212a14d7f6..fc86d62489 100644 --- a/qa/tests/pcbnewswig/test_001_pcb_load.py +++ b/qa/tests/pcbnewswig/test_001_pcb_load.py @@ -1,23 +1,23 @@ -import code -import unittest import pcbnew -import pdb +import pytest -class TestPCBLoad(unittest.TestCase): - def setUp(self): +class TestPCBLoad: + pcb : pcbnew.BOARD = None + + def setup_method(self): self.pcb = pcbnew.LoadBoard("../data/pcbnew/complex_hierarchy.kicad_pcb") def test_pcb_load(self): - self.assertNotEqual(self.pcb,None) + assert self.pcb is not None def test_pcb_track_count(self): tracks = list(self.pcb.GetTracks()) - self.assertEqual(len(tracks),361) + assert len(tracks) == 361 def test_pcb_modules(self): modules = list(self.pcb.GetFootprints()) - self.assertEqual(len(modules), 72) + assert len(modules) == 72 def test_pcb_module_references(self): board_refs = list(module.GetReference() for @@ -35,10 +35,10 @@ class TestPCBLoad(unittest.TestCase): u'R26', u'R27', u'R28'] for ref in known_refs: - self.assertTrue(ref in board_refs) + assert ref in board_refs def test_pcb_netcount(self): - self.assertEqual(self.pcb.GetNetCount(),51) + assert self.pcb.GetNetCount() == 51 def test_pcb_shapes(self): drawings = list(self.pcb.GetDrawings()) @@ -50,7 +50,7 @@ class TestPCBLoad(unittest.TestCase): [[188595000, 51816000], [188595000, 131826000]], [[188595000, 131826000], [88265000, 131826000]] ] - self.assertEqual(sorted(coordinates), sorted(expected_coordinates)) + assert sorted(coordinates) == sorted(expected_coordinates) def test_pcb_text(self): drawings = list(self.pcb.GetDrawings()) @@ -61,12 +61,6 @@ class TestPCBLoad(unittest.TestCase): u'Actionneur\nPiezo New Amp\nV02') def verify_text(self, text, x, y, layer, s): - self.assertEquals(list(text.GetPosition()), [x, y]) - self.assertEquals(text.GetLayer(), layer) - self.assertEquals(text.GetText(), s) - - #def test_interactive(self): - # code.interact(local=locals()) - -if __name__ == '__main__': - unittest.main() + assert list(text.GetPosition()) == [x, y] + assert text.GetLayer() == layer + assert text.GetText() == s diff --git a/qa/tests/pcbnewswig/test_002_board_class.py b/qa/tests/pcbnewswig/test_002_board_class.py index a0539f1b92..f7de6e6e6a 100644 --- a/qa/tests/pcbnewswig/test_002_board_class.py +++ b/qa/tests/pcbnewswig/test_002_board_class.py @@ -1,8 +1,6 @@ -import code -import unittest +import pytest import os import pcbnew -import pdb import tempfile @@ -14,9 +12,10 @@ B_CU = 'B.Cu' NEW_NAME = 'My_Fancy_Layer_Name' -class TestBoardClass(unittest.TestCase): +class TestBoardClass: + pcb : pcbnew.BOARD = None - def setUp(self): + def setup_method(self): self.pcb = LoadBoard("../data/pcbnew/complex_hierarchy.kicad_pcb") self.TITLE="Test Board" self.COMMENT1="For load/save test" @@ -24,20 +23,20 @@ class TestBoardClass(unittest.TestCase): def test_pcb_find_module(self): module = self.pcb.FindFootprintByReference('P1') - self.assertEqual(module.GetReference(),'P1') + assert module.GetReference() =='P1' def test_pcb_get_track_count(self): pcb = BOARD() - self.assertEqual(pcb.Tracks().size(),0) + assert pcb.Tracks().size() == 0 track0 = PCB_TRACK(pcb) pcb.Add(track0) - self.assertEqual(pcb.Tracks().size(),1) + assert pcb.Tracks().size() == 1 track1 = PCB_TRACK(pcb) pcb.Add(track1) - self.assertEqual(pcb.Tracks().size(),2) + assert pcb.Tracks().size() == 2 def test_pcb_bounding_box(self): pcb = BOARD() @@ -55,8 +54,8 @@ class TestBoardClass(unittest.TestCase): height, width = ToMM(bounding_box.GetSize()) margin = 0 # margin around bounding boxes (currently 0) - self.assertAlmostEqual(width, (30-10) + 0.5 + margin, 2) - self.assertAlmostEqual(height, (20-10) + 0.5 + margin, 2) + assert width == pytest.approx((30-10) + 0.5 + margin, 2) + assert height == pytest.approx((20-10) + 0.5 + margin, 2) def test_pcb_get_pad(self): pcb = BOARD() @@ -80,35 +79,35 @@ class TestBoardClass(unittest.TestCase): # TODO: get pad == p1 evaluated as true instead # of relying in the internal C++ object pointer - self.assertEqual(pad.this, p1.this) - self.assertEqual(pad.this, p2.this) - self.assertEqual(pad.this, p3.this) + assert pad.this == p1.this + assert pad.this == p2.this + assert pad.this == p3.this def test_pcb_save_and_load(self): pcb = BOARD() pcb.GetTitleBlock().SetTitle(self.TITLE) pcb.GetTitleBlock().SetComment(0,self.COMMENT1) result = SaveBoard(self.FILENAME,pcb) - self.assertTrue(result) + assert result pcb2 = LoadBoard(self.FILENAME) - self.assertNotEqual(pcb2,None) + assert pcb2 is not None tb = pcb2.GetTitleBlock() - self.assertEqual(tb.GetTitle(),self.TITLE) - self.assertEqual(tb.GetComment(0),self.COMMENT1) + assert tb.GetTitle() == self.TITLE + assert tb.GetComment(0) == self.COMMENT1 os.remove(self.FILENAME) def test_pcb_layer_name_set_get(self): pcb = BOARD() pcb.SetLayerName(31, BACK_COPPER) - self.assertEqual(pcb.GetLayerName(31), BACK_COPPER) + assert pcb.GetLayerName(31) == BACK_COPPER def test_pcb_layer_name_set_get(self): pcb = BOARD() pcb.SetLayerName(31, BACK_COPPER) - self.assertEqual(pcb.GetLayerName(31), BACK_COPPER) + assert pcb.GetLayerName(31) == BACK_COPPER def test_pcb_layer_id_get(self): pcb = BOARD() @@ -116,10 +115,10 @@ class TestBoardClass(unittest.TestCase): pcb.SetLayerName(b_cu_id, NEW_NAME) # ensure we can get the ID for the new name - self.assertEqual(pcb.GetLayerID(NEW_NAME), b_cu_id) + assert pcb.GetLayerID(NEW_NAME) == b_cu_id # ensure we can get to the ID via the STD name too - self.assertEqual(pcb.GetLayerID(B_CU), b_cu_id) + assert pcb.GetLayerID(B_CU) == b_cu_id def test_footprint_properties(self): pcb = LoadBoard("../data/pcbnew/custom_fields.kicad_pcb") @@ -129,17 +128,10 @@ class TestBoardClass(unittest.TestCase): 'Sheet name': '', 'myfield': 'myvalue' } - self.assertEquals(footprint.GetProperties(), expected_properties) - self.assertEquals(footprint.GetProperty('myfield'), 'myvalue') - self.assertEquals(footprint.HasProperty('myfield'), True) - self.assertEquals(footprint.HasProperty('abcd'), False) + assert footprint.GetProperties() == expected_properties + assert footprint.GetProperty('myfield') == 'myvalue' + assert footprint.HasProperty('myfield') == True + assert footprint.HasProperty('abcd') == False footprint.SetProperty('abcd', 'efgh') - self.assertEquals(footprint.HasProperty('abcd'), True) - self.assertEquals(footprint.GetProperty('abcd'), 'efgh') - - #def test_interactive(self): - # code.interact(local=locals()) - -if __name__ == '__main__': - unittest.main() - + assert footprint.HasProperty('abcd') == True + assert footprint.GetProperty('abcd') == 'efgh' diff --git a/qa/tests/pcbnewswig/test_003_pads.py b/qa/tests/pcbnewswig/test_003_pads.py index 37fd61f63d..21f40651e1 100644 --- a/qa/tests/pcbnewswig/test_003_pads.py +++ b/qa/tests/pcbnewswig/test_003_pads.py @@ -1,9 +1,10 @@ -import unittest +import pytest import pcbnew -class TestPads(unittest.TestCase): +class TestPads: + pcb : pcbnew.BOARD = None - def setUp(self): + def setup_method(self): self.pcb = pcbnew.LoadBoard("../data/pcbnew/custom_pads.kicad_pcb") def test_custom_pads_outline(self): @@ -17,10 +18,11 @@ class TestPads(unittest.TestCase): ]] # test accessor without layer polygon_set = custom_pad1.GetCustomShapeAsPolygon() - self.assertEqual(expected_polygons, self.parse_polygon_set(polygon_set)) + assert expected_polygons == self.parse_polygon_set(polygon_set) + # test accessor with layer polygon_set = custom_pad1.GetCustomShapeAsPolygon(pcbnew.F_Cu) - self.assertEqual(expected_polygons, self.parse_polygon_set(polygon_set)) + assert expected_polygons == self.parse_polygon_set(polygon_set) def parse_polygon_set(self, polygon_set): result = [] diff --git a/qa/tests/pcbnewswig/test_004_tracks.py b/qa/tests/pcbnewswig/test_004_tracks.py index d285c4f291..c7c5f69975 100644 --- a/qa/tests/pcbnewswig/test_004_tracks.py +++ b/qa/tests/pcbnewswig/test_004_tracks.py @@ -1,42 +1,43 @@ -import unittest +import pytest import pcbnew -class TestTracks(unittest.TestCase): +class TestTracks: + pcb : pcbnew.BOARD = None - def setUp(self): + def setup_method(self): self.pcb = pcbnew.LoadBoard("../data/pcbnew/tracks_arcs_vias.kicad_pcb") def test_tracks(self): tracks = [t for t in self.pcb.Tracks() if t.GetClass() == 'PCB_TRACK'] - self.assertEqual(16, len(tracks)) + assert 16 == len(tracks) track = sorted(tracks, key=lambda t: [t.GetStart()[0], t.GetStart()[1]])[0] - self.assertEqual([27000000, 27585787], [track.GetStart()[0], track.GetStart()[1]]) - self.assertEqual([27000000, 26500000], [track.GetEnd()[0], track.GetEnd()[1]]) - self.assertEqual(250000, track.GetWidth()) - self.assertEqual('McNetty', track.GetNetname()) + assert [27000000, 27585787] == [track.GetStart()[0], track.GetStart()[1]] + assert [27000000, 26500000] == [track.GetEnd()[0], track.GetEnd()[1]] + assert 250000 == track.GetWidth() + assert 'McNetty' == track.GetNetname() dup_track = track.Duplicate() - self.assertTrue( dup_track.m_Uuid != track.m_Uuid ) + assert dup_track.m_Uuid != track.m_Uuid def test_arcs(self): arcs = [t.Cast() for t in self.pcb.Tracks() if t.GetClass() == 'PCB_ARC'] - self.assertEqual(13, len(arcs)) + assert 13 == len(arcs) arc = sorted(arcs, key=lambda t: [t.GetStart()[0], t.GetStart()[1]])[0] - self.assertEqual([29414200, 26500000], [arc.GetCenter()[0], arc.GetCenter()[1]]) - self.assertEqual([1800, 2250], [round(arc.GetArcAngleStart().AsTenthsOfADegree()), - round(arc.GetArcAngleEnd().AsTenthsOfADegree())]) - self.assertEqual(2414200, round(arc.GetRadius())) + assert [29414200, 26500000] == [arc.GetCenter()[0], arc.GetCenter()[1]] + assert [1800, 2250] == [round(arc.GetArcAngleStart().AsTenthsOfADegree()), + round(arc.GetArcAngleEnd().AsTenthsOfADegree())] + assert 2414200 == round(arc.GetRadius()) dup_arc = arc.Duplicate() - self.assertTrue( dup_arc.m_Uuid != arc.m_Uuid ) + assert dup_arc.m_Uuid != arc.m_Uuid def test_vias(self): vias = [t.Cast() for t in self.pcb.Tracks() if t.GetClass() == 'PCB_VIA'] - self.assertEqual(2, len(vias)) + assert 2 == len(vias) via = sorted(vias, key=lambda t: [t.GetStart()[0], t.GetStart()[1]])[0] - self.assertEqual([29000000, 41000000], [via.GetStart()[0], via.GetStart()[1]]) - self.assertEqual(400000, via.GetDrillValue()) + assert [29000000, 41000000] == [via.GetStart()[0], via.GetStart()[1]] + assert 400000 == via.GetDrillValue() dup_via = via.Duplicate() - self.assertTrue( dup_via.m_Uuid != via.m_Uuid ) + assert dup_via.m_Uuid != via.m_Uuid diff --git a/qa/tests/pcbnewswig/test_005_connectivity_data.py b/qa/tests/pcbnewswig/test_005_connectivity_data.py index 7adf528e6b..04eef7f6d2 100644 --- a/qa/tests/pcbnewswig/test_005_connectivity_data.py +++ b/qa/tests/pcbnewswig/test_005_connectivity_data.py @@ -1,14 +1,14 @@ """Unit-test parts of the CONNECTIVITY_DATA Python API.""" -import unittest - +import pytest import pcbnew -class TestConnectivity(unittest.TestCase): +class TestConnectivity: """Test that calls on BOARD.Connectivity() are functional.""" + pcb : pcbnew.BOARD = None - def setUp(self): + def setup_method(self): """Setup shared attributes.""" self.pcb = pcbnew.LoadBoard("../data/pcbnew/complex_hierarchy.kicad_pcb") self.connectivity = self.pcb.GetConnectivity() @@ -17,7 +17,7 @@ class TestConnectivity(unittest.TestCase): def test_get_connectivity_returns_connectivity_data_object(self): """Verify: GetConnectivity() returns a CONNECTIVITY_DATA object.""" connectivity = self.pcb.GetConnectivity() - self.assertEqual(type(connectivity).__name__, "CONNECTIVITY_DATA") + assert type(connectivity).__name__ == "CONNECTIVITY_DATA" def test_get_connected_pads_on_track_returns_iterable_of_pads(self): """Verify: GetConnectedPads(track) returns an iterable of pads.""" @@ -25,8 +25,8 @@ class TestConnectivity(unittest.TestCase): tracks = list(self.pcb.TracksInNet(net.GetNetCode())) track_with_pad = tracks[1] pads = self.connectivity.GetConnectedPads(track_with_pad) - self.assertGreater(len(pads), 0) - self.assertTrue(all(pad.GetClass() == "PAD" for pad in pads)) + assert len(pads) > 0 + assert all(pad.GetClass() == "PAD" for pad in pads) def test_get_connected_tracks_returns_iterable_of_tracks(self): """Verify: GetConnectedTracks(track) returns an iterable of tracks.""" @@ -34,7 +34,5 @@ class TestConnectivity(unittest.TestCase): net_tracks = self.pcb.TracksInNet(net.GetNetCode()) net_track = list(net_tracks)[0] connected_tracks = self.connectivity.GetConnectedTracks(net_track) - self.assertGreater(len(connected_tracks), 1) - self.assertTrue( - all(track.GetClass() == "PCB_TRACK" for track in connected_tracks) - ) + assert len(connected_tracks) > 1 + assert all(track.GetClass() == "PCB_TRACK" for track in connected_tracks) diff --git a/qa/tests/test-pcbnewswig.py b/qa/tests/test-pcbnewswig.py deleted file mode 100644 index 04862803b2..0000000000 --- a/qa/tests/test-pcbnewswig.py +++ /dev/null @@ -1,50 +0,0 @@ -import unittest -import platform -import sys -import argparse -import locale - -if platform.python_version() < '2.7': - unittest = __import__('unittest2') -else: - import unittest - -try: - import xmlrunner - have_xml = True -except ImportError: - have_xml = False - - -if __name__ == '__main__': - - parser = argparse.ArgumentParser( - description='Test suit for KiCad Python functions') - parser.add_argument('--xml', action="store", type=str, - help='Output XML test results to the given directory') - - args = parser.parse_args() - - if args.xml and not have_xml: - print("XML test reporting not available") - print("Install the xmlrunner package.") - sys.exit(2) - - # Useful in some non English installs (using a comma as load number separator) to avoid - # wxWidgets alerts when running the test code - locale.setlocale(locale.LC_ALL, 'C') - - testsuite = unittest.TestLoader().discover('pcbnewswig', pattern="*.py") - - if args.xml: - # Dump XML results to the right directory - runner = xmlrunner.XMLTestRunner(output=args.xml) - else: - # Use a normal text runner - runner = unittest.TextTestRunner(verbosity=100) - - results = runner.run(testsuite) - - # Return an error code if any of the testsuite tests fail - if not results.wasSuccessful(): - sys.exit(1)