diff options
30 files changed, 266 insertions, 21 deletions
diff --git a/pyuno/qa/pytests/testcollections_XCellRange.py b/pyuno/qa/pytests/testcollections_XCellRange.py index 6754ef52814c..2e0ef8a7d3d7 100644 --- a/pyuno/qa/pytests/testcollections_XCellRange.py +++ b/pyuno/qa/pytests/testcollections_XCellRange.py @@ -43,6 +43,8 @@ class TestXCellRange(CollectionsTestBase): self.assertEqual(0, cell.CellAddress.Row) self.assertEqual(0, cell.CellAddress.Column) + spr.close(True) + # Tests syntax: # cell = cellrange[0,0] # Access cell by indices # For: @@ -63,6 +65,8 @@ class TestXCellRange(CollectionsTestBase): # Then self.assertEqual('A1', cell.CellName) + doc.close(True) + # Tests syntax: # cell = cellrange[0,0] # Access cell by indices # For: @@ -81,6 +85,8 @@ class TestXCellRange(CollectionsTestBase): self.assertEqual(3, rng.CellAddress.Row) self.assertEqual(7, rng.CellAddress.Column) + spr.close(True) + # Tests syntax: # cell = cellrange[0,0] # Access cell by indices # For: @@ -101,6 +107,8 @@ class TestXCellRange(CollectionsTestBase): # Then self.assertEqual('H4', cell.CellName) + doc.close(True) + # Tests syntax: # rng = cellrange[0,1:2] # Access cell range by index,slice # For: @@ -120,6 +128,8 @@ class TestXCellRange(CollectionsTestBase): self.assertEqual(0, rng.RangeAddress.EndRow) self.assertEqual(2, rng.RangeAddress.EndColumn) + spr.close(True) + # Tests syntax: # rng = cellrange[0,1:2] # Access cell range by index,slice # For: @@ -142,6 +152,8 @@ class TestXCellRange(CollectionsTestBase): # Then self.assertEqual((('101', '102'),), rng.DataArray) + doc.close(True) + # Tests syntax: # rng = cellrange[1:2,0] # Access cell range by slice,index # For: @@ -161,6 +173,8 @@ class TestXCellRange(CollectionsTestBase): self.assertEqual(2, rng.RangeAddress.EndRow) self.assertEqual(0, rng.RangeAddress.EndColumn) + spr.close(True) + # Tests syntax: # rng = cellrange[1:2,0] # Access cell range by index,slice # For: @@ -183,6 +197,8 @@ class TestXCellRange(CollectionsTestBase): # Then self.assertEqual((('110',), ('120',)), rng.DataArray) + doc.close(True) + # Tests syntax: # rng = cellrange[0:1,2:3] # Access cell range by slices # For: @@ -202,6 +218,8 @@ class TestXCellRange(CollectionsTestBase): self.assertEqual(2, rng.RangeAddress.EndRow) self.assertEqual(4, rng.RangeAddress.EndColumn) + spr.close(True) + # Tests syntax: # rng = cellrange[0:1,2:3] # Access cell range by slices # For: @@ -218,6 +236,8 @@ class TestXCellRange(CollectionsTestBase): with self.assertRaises(KeyError): rng = sht[1:3, 3:3] + spr.close(True) + # Tests syntax: # rng = cellrange[0:1,2:3] # Access cell range by slices # For: @@ -240,6 +260,8 @@ class TestXCellRange(CollectionsTestBase): # Then self.assertEqual((('113', '114'), ('123', '124')), rng.DataArray) + doc.close(True) + # Tests syntax: # rng = cellrange['A1:B2'] # Access cell range by descriptor # For: @@ -259,6 +281,8 @@ class TestXCellRange(CollectionsTestBase): self.assertEqual(3, rng.RangeAddress.EndRow) self.assertEqual(1, rng.RangeAddress.EndColumn) + spr.close(True) + # Tests syntax: # rng = cellrange['A1:B2'] # Access cell range by descriptor # For: @@ -281,6 +305,8 @@ class TestXCellRange(CollectionsTestBase): # Then self.assertEqual((('120', '121'), ('130', '131')), rng.DataArray) + doc.close(True) + # Tests syntax: # rng = cellrange['Name'] # Access cell range by name # For: @@ -303,6 +329,8 @@ class TestXCellRange(CollectionsTestBase): self.assertEqual(9, rng.RangeAddress.EndRow) self.assertEqual(5, rng.RangeAddress.EndColumn) + spr.close(True) + # Tests syntax: # rng = cellrange[0] # Access cell range by row index # For: @@ -322,6 +350,8 @@ class TestXCellRange(CollectionsTestBase): self.assertEqual(0, rng.RangeAddress.EndRow) self.assertEqual(1023, rng.RangeAddress.EndColumn) + spr.close(True) + # Tests syntax: # rng = cellrange[0,:] # Access cell range by row index # For: @@ -341,6 +371,8 @@ class TestXCellRange(CollectionsTestBase): self.assertEqual(0, rng.RangeAddress.EndRow) self.assertEqual(1023, rng.RangeAddress.EndColumn) + spr.close(True) + # Tests syntax: # rng = cellrange[:,0] # Access cell range by column index # For: @@ -360,6 +392,8 @@ class TestXCellRange(CollectionsTestBase): self.assertEqual(1048575, rng.RangeAddress.EndRow) self.assertEqual(0, rng.RangeAddress.EndColumn) + spr.close(True) + if __name__ == '__main__': unittest.main() diff --git a/pyuno/qa/pytests/testcollections_XEnumeration.py b/pyuno/qa/pytests/testcollections_XEnumeration.py index 6edc77f44952..8d1f8eece046 100644 --- a/pyuno/qa/pytests/testcollections_XEnumeration.py +++ b/pyuno/qa/pytests/testcollections_XEnumeration.py @@ -38,6 +38,8 @@ class TestXEnumeration(CollectionsTestBase): # Then self.assertEqual(1, len(paragraphs)) + doc.close(True) + # Tests syntax: # if val in itr: ... # Test value presence # For: @@ -54,6 +56,8 @@ class TestXEnumeration(CollectionsTestBase): # Then self.assertTrue(result) + doc.close(True) + # Tests syntax: # if val in itr: ... # Test value presence # For: @@ -71,6 +75,9 @@ class TestXEnumeration(CollectionsTestBase): # Then self.assertFalse(result) + doc1.close(True) + doc2.close(True) + # Tests syntax: # if val in itr: ... # Test value presence # For: @@ -86,6 +93,8 @@ class TestXEnumeration(CollectionsTestBase): # Then self.assertFalse(result) + doc.close(True) + # Tests syntax: # if val in itr: ... # Test value presence # For: @@ -104,6 +113,8 @@ class TestXEnumeration(CollectionsTestBase): # Then self.assertFalse(result) + doc.close(True) + if __name__ == '__main__': unittest.main() diff --git a/pyuno/qa/pytests/testcollections_XEnumerationAccess.py b/pyuno/qa/pytests/testcollections_XEnumerationAccess.py index dc5a52f54537..a62b05ce9c5f 100644 --- a/pyuno/qa/pytests/testcollections_XEnumerationAccess.py +++ b/pyuno/qa/pytests/testcollections_XEnumerationAccess.py @@ -37,6 +37,8 @@ class TestXEnumerationAccess(CollectionsTestBase): # Then self.assertEqual(1, len(paragraphs)) + doc.close(True) + # Tests syntax: # itr = iter(obj) # Named iterator # For: @@ -53,6 +55,8 @@ class TestXEnumerationAccess(CollectionsTestBase): with self.assertRaises(StopIteration): next(itr) + doc.close(True) + # Tests syntax: # if val in obj: ... # Test value presence # For: @@ -68,6 +72,8 @@ class TestXEnumerationAccess(CollectionsTestBase): # Then self.assertTrue(result) + doc.close(True) + # Tests syntax: # if val in obj: ... # Test value presence # For: @@ -84,6 +90,9 @@ class TestXEnumerationAccess(CollectionsTestBase): # Then self.assertFalse(result) + doc1.close(True) + doc2.close(True) + # Tests syntax: # if val in obj: ... # Test value presence # For: @@ -98,6 +107,8 @@ class TestXEnumerationAccess(CollectionsTestBase): # Then self.assertFalse(result) + doc.close(True) + # Tests syntax: # if val in obj: ... # Test value presence # For: @@ -112,6 +123,8 @@ class TestXEnumerationAccess(CollectionsTestBase): # Then self.assertFalse(result) + doc.close(True) + # Tests syntax: # if val in obj: ... # Test value presence # For: @@ -124,6 +137,8 @@ class TestXEnumerationAccess(CollectionsTestBase): with self.assertRaises(TypeError): result = {} in doc.Text + doc.close(True) + if __name__ == '__main__': unittest.main() diff --git a/pyuno/qa/pytests/testcollections_XIndexAccess.py b/pyuno/qa/pytests/testcollections_XIndexAccess.py index 4631ca3706ed..7228ed87336b 100644 --- a/pyuno/qa/pytests/testcollections_XIndexAccess.py +++ b/pyuno/qa/pytests/testcollections_XIndexAccess.py @@ -77,6 +77,8 @@ class TestXIndexAccess(CollectionsTestBase): # Then self.assertEqual(0, count) + doc.close(True); + # Tests syntax: # num = len(obj) # Number of elements # For: @@ -94,6 +96,8 @@ class TestXIndexAccess(CollectionsTestBase): # Then self.assertEqual(1, count) + doc.close(True); + # Tests syntax: # val = obj[0] # Access by index # For: @@ -117,6 +121,7 @@ class TestXIndexAccess(CollectionsTestBase): self.readValuesTestFixture(doc, 2, 1, 1) self.readValuesTestFixture(doc, 2, 2, IndexError) self.readValuesTestFixture(doc, 2, 3, IndexError) + doc.close(True); def test_XIndexAccess_ReadIndex_Single_Invalid(self): doc = self.createBlankTextDocument() @@ -126,6 +131,7 @@ class TestXIndexAccess(CollectionsTestBase): self.readValuesTestFixture(doc, 0, (0, 1), TypeError) self.readValuesTestFixture(doc, 0, [0, 1], TypeError) self.readValuesTestFixture(doc, 0, {'a': 'b'}, TypeError) + doc.close(True); # Tests syntax: # val1,val2 = obj[2:4] # Access by slice @@ -139,6 +145,7 @@ class TestXIndexAccess(CollectionsTestBase): key = slice(j, k) expected = t[key] self.readValuesTestFixture(doc, i, key, expected) + doc.close(True); # Tests syntax: # val1,val2 = obj[0:3:2] # Access by extended slice @@ -153,6 +160,7 @@ class TestXIndexAccess(CollectionsTestBase): key = slice(j, k, l) expected = t[key] self.readValuesTestFixture(doc, i, key, expected) + doc.close(True); # Tests syntax: # if val in obj: ... # Test value presence @@ -173,6 +181,8 @@ class TestXIndexAccess(CollectionsTestBase): # Then self.assertTrue(present) + doc.close(True); + # Tests syntax: # if val in obj: ... # Test value presence # For: @@ -187,6 +197,8 @@ class TestXIndexAccess(CollectionsTestBase): # Then self.assertFalse(present) + doc.close(True); + # Tests syntax: # if val in obj: ... # Test value presence # For: @@ -201,6 +213,8 @@ class TestXIndexAccess(CollectionsTestBase): # Then self.assertFalse(present) + doc.close(True); + # Tests syntax: # if val in obj: ... # Test value presence # For: @@ -213,6 +227,8 @@ class TestXIndexAccess(CollectionsTestBase): with self.assertRaises(TypeError): present = {} in doc.Footnotes + doc.close(True); + # Tests syntax: # for val in obj: ... # Implicit iterator (values) # For: @@ -229,6 +245,8 @@ class TestXIndexAccess(CollectionsTestBase): # Then self.assertEqual(0, len(read_footnotes)) + doc.close(True); + # Tests syntax: # for val in obj: ... # Implicit iterator (values) # For: @@ -250,6 +268,8 @@ class TestXIndexAccess(CollectionsTestBase): self.assertEqual(1, len(read_footnotes)) self.assertEqual('foo', read_footnotes[0].Label) + doc.close(True); + # Tests syntax: # for val in obj: ... # Implicit iterator (values) # For: @@ -275,6 +295,8 @@ class TestXIndexAccess(CollectionsTestBase): self.assertEqual('foo', read_footnotes[0].Label) self.assertEqual('bar', read_footnotes[1].Label) + doc.close(True); + # Tests syntax: # itr = iter(obj) # Named iterator (values) # For: @@ -295,6 +317,8 @@ class TestXIndexAccess(CollectionsTestBase): with self.assertRaises(StopIteration): next(itr) + doc.close(True); + if __name__ == '__main__': unittest.main() diff --git a/pyuno/qa/pytests/testcollections_XIndexContainer.py b/pyuno/qa/pytests/testcollections_XIndexContainer.py index 7bf9e5223039..73be6b57c25d 100644 --- a/pyuno/qa/pytests/testcollections_XIndexContainer.py +++ b/pyuno/qa/pytests/testcollections_XIndexContainer.py @@ -145,6 +145,8 @@ class TestXIndexContainer(CollectionsTestBase): # Then self.assertEqual('foo', doc.DrawPage.Forms[0].Name) + doc.close(True) + # Tests syntax: # obj[0:3:2] = val1,val2 # Replace by extended slice # For: diff --git a/pyuno/qa/pytests/testcollections_XIndexReplace.py b/pyuno/qa/pytests/testcollections_XIndexReplace.py index 45d1cc075f33..bbf424f0bdfb 100644 --- a/pyuno/qa/pytests/testcollections_XIndexReplace.py +++ b/pyuno/qa/pytests/testcollections_XIndexReplace.py @@ -78,6 +78,8 @@ class TestXIndexReplace(CollectionsTestBase): # Then self.assertEqual(('Caption',), index.LevelParagraphStyles[0]) + doc.close(True) + # Tests syntax: # obj[0] = val # Replace by index # For: @@ -91,6 +93,8 @@ class TestXIndexReplace(CollectionsTestBase): with self.assertRaises(TypeError): index.LevelParagraphStyles[0] = None + doc.close(True) + # Tests syntax: # obj[0] = val # Replace by index # For: @@ -104,6 +108,8 @@ class TestXIndexReplace(CollectionsTestBase): with self.assertRaises(TypeError): index.LevelParagraphStyles[0] = 'foo' + doc.close(True) + # Tests syntax: # obj[0] = val # Replace by index # For: @@ -117,6 +123,8 @@ class TestXIndexReplace(CollectionsTestBase): with self.assertRaises(TypeError): index.LevelParagraphStyles[0] = 12.34 + doc.close(True) + # Tests syntax: # obj[0] = val # Replace by index # For: @@ -130,6 +138,8 @@ class TestXIndexReplace(CollectionsTestBase): with self.assertRaises(TypeError): index.LevelParagraphStyles[0] = [0, 1] + doc.close(True) + # Tests syntax: # obj[0] = val # Replace by index # For: @@ -143,6 +153,8 @@ class TestXIndexReplace(CollectionsTestBase): with self.assertRaises(TypeError): index.LevelParagraphStyles[0] = {'a': 'b'} + doc.close(True) + # Tests syntax: # obj[0] = val # Replace by index # For: @@ -156,6 +168,8 @@ class TestXIndexReplace(CollectionsTestBase): with self.assertRaises(TypeError): index.LevelParagraphStyles[0] = ('Caption', ()) + doc.close(True) + # Tests syntax: # obj[2:4] = val1,val2 # Replace by slice # For: @@ -177,6 +191,7 @@ class TestXIndexReplace(CollectionsTestBase): if (len(expected) != 10): expected = ValueError() self.assignValuesTestFixture(doc, key, assign, expected) + doc.close(True) # Tests syntax: # obj[2:4] = val1,val2 # Replace by slice @@ -194,6 +209,8 @@ class TestXIndexReplace(CollectionsTestBase): 12.34 ) + doc.close(True) + # Tests syntax: # obj[0:3:2] = val1,val2 # Replace by extended slice # For: @@ -214,6 +231,7 @@ class TestXIndexReplace(CollectionsTestBase): except Exception as e: expected = e self.assignValuesTestFixture(doc, key, assign, expected) + doc.close(True) if __name__ == '__main__': diff --git a/pyuno/qa/pytests/testcollections_XNameAccess.py b/pyuno/qa/pytests/testcollections_XNameAccess.py index a93064e78bb1..7f987a370077 100644 --- a/pyuno/qa/pytests/testcollections_XNameAccess.py +++ b/pyuno/qa/pytests/testcollections_XNameAccess.py @@ -35,6 +35,8 @@ class TestXNameAccess(CollectionsTestBase): # Then self.assertEqual(2, length) + drw.close(True) + # Tests syntax: # val = obj[key] # Access by key # For: @@ -50,6 +52,8 @@ class TestXNameAccess(CollectionsTestBase): # Then self.assertEqual('foo', link.getName()) + drw.close(True) + # Tests syntax: # val = obj[key] # Access by key # For: @@ -62,6 +66,8 @@ class TestXNameAccess(CollectionsTestBase): with self.assertRaises(KeyError): link = drw.Links['foo'] + drw.close(True) + # Tests syntax: # val = obj[key] # Access by key # For: @@ -74,6 +80,8 @@ class TestXNameAccess(CollectionsTestBase): with self.assertRaises(TypeError): link = drw.Links[None] + drw.close(True) + # Tests syntax: # val = obj[key] # Access by key # For: @@ -86,6 +94,8 @@ class TestXNameAccess(CollectionsTestBase): with self.assertRaises(TypeError): link = drw.Links[12.34] + drw.close(True) + # Tests syntax: # val = obj[key] # Access by key # For: @@ -98,6 +108,8 @@ class TestXNameAccess(CollectionsTestBase): with self.assertRaises(TypeError): link = drw.Links[(1, 2)] + drw.close(True) + # Tests syntax: # val = obj[key] # Access by key # For: @@ -110,6 +122,8 @@ class TestXNameAccess(CollectionsTestBase): with self.assertRaises(TypeError): link = drw.Links[[1, 2]] + drw.close(True) + # Tests syntax: # val = obj[key] # Access by key # For: @@ -122,6 +136,8 @@ class TestXNameAccess(CollectionsTestBase): with self.assertRaises(TypeError): link = drw.Links[{'a': 'b'}] + drw.close(True) + # Tests syntax: # if key in obj: ... # Test key presence # For: @@ -137,6 +153,8 @@ class TestXNameAccess(CollectionsTestBase): # Then self.assertTrue(present) + drw.close(True) + # Tests syntax: # for key in obj: ... # Implicit iterator (keys) # For: @@ -157,6 +175,8 @@ class TestXNameAccess(CollectionsTestBase): # Then self.assertEqual(['foo0', 'foo1'], read_links) + drw.close(True) + # Tests syntax: # itr = iter(obj) # Named iterator (keys) # For: @@ -174,6 +194,8 @@ class TestXNameAccess(CollectionsTestBase): with self.assertRaises(StopIteration): next(itr) + drw.close(True) + if __name__ == '__main__': unittest.main() diff --git a/pyuno/qa/pytests/testcollections_XNameContainer.py b/pyuno/qa/pytests/testcollections_XNameContainer.py index 48b63a786f7e..5c8b676c0f6e 100644 --- a/pyuno/qa/pytests/testcollections_XNameContainer.py +++ b/pyuno/qa/pytests/testcollections_XNameContainer.py @@ -41,6 +41,8 @@ class TestXNameContainer(CollectionsTestBase): # Then self.assertEqual(1, len(ranges.ElementNames)) + spr.close(True) + # Tests syntax: # obj[key] = val # Insert by key # For: @@ -55,6 +57,8 @@ class TestXNameContainer(CollectionsTestBase): with self.assertRaises(TypeError): ranges[12.34] = new_range + spr.close(True) + # Tests syntax: # obj[key] = val # Replace by key def test_XNameContainer_ReplaceName(self): @@ -73,6 +77,8 @@ class TestXNameContainer(CollectionsTestBase): read_range = ranges['foo'] self.assertEqual(6, read_range.CellAddress.Column) + spr.close(True) + # Tests syntax: # del obj[key] # Delete by key # For: @@ -89,6 +95,8 @@ class TestXNameContainer(CollectionsTestBase): self.assertEqual(1, len(spr.Sheets)) self.assertFalse('foo' in spr.Sheets) + spr.close(True) + # Tests syntax: # del obj[key] # Delete by key # For: @@ -101,6 +109,8 @@ class TestXNameContainer(CollectionsTestBase): with self.assertRaises(KeyError): del spr.Sheets['foo'] + spr.close(True) + # Tests syntax: # del obj[key] # Delete by key # For: @@ -113,6 +123,8 @@ class TestXNameContainer(CollectionsTestBase): with self.assertRaises(TypeError): del spr.Sheets[12.34] + spr.close(True) + if __name__ == '__main__': unittest.main() diff --git a/pyuno/qa/pytests/testcollections_XNameReplace.py b/pyuno/qa/pytests/testcollections_XNameReplace.py index 2176f935d9dc..18476fd2b447 100644 --- a/pyuno/qa/pytests/testcollections_XNameReplace.py +++ b/pyuno/qa/pytests/testcollections_XNameReplace.py @@ -40,6 +40,8 @@ class TestXNameReplace(CollectionsTestBase): on_save = [p.Value for p in doc.Events['OnSave'] if p.Name == 'Script'][0] self.assertEqual(getScriptName(), on_save) + doc.close(True) + # Tests syntax: # obj[key] = val # Replace by key # For: @@ -53,6 +55,8 @@ class TestXNameReplace(CollectionsTestBase): with self.assertRaises(KeyError): doc.Events['qqqqq'] = event_properties + doc.close(True) + # Tests syntax: # obj[key] = val # Replace by key # For: @@ -66,6 +70,8 @@ class TestXNameReplace(CollectionsTestBase): with self.assertRaises(TypeError): doc.Events[12.34] = event_properties + doc.close(True) + if __name__ == '__main__': unittest.main() diff --git a/pyuno/qa/pytests/testcollections_misc.py b/pyuno/qa/pytests/testcollections_misc.py index 04dcf595931a..1dba098eeccd 100644 --- a/pyuno/qa/pytests/testcollections_misc.py +++ b/pyuno/qa/pytests/testcollections_misc.py @@ -32,6 +32,8 @@ class TestMisc(CollectionsTestBase): for val in doc.UIConfigurationManager: pass + doc.close(True) + # Tests syntax: # if val in itr: ... # Test value presence # For: @@ -44,6 +46,8 @@ class TestMisc(CollectionsTestBase): with self.assertRaises(TypeError): foo = "bar" in doc.UIConfigurationManager + doc.close(True) + # Tests syntax: # num = len(obj) # Number of elements # For: @@ -56,6 +60,8 @@ class TestMisc(CollectionsTestBase): with self.assertRaises(TypeError): len(doc.UIConfigurationManager) + doc.close(True) + # Tests syntax: # val = obj[0] # Access by index # For: @@ -68,6 +74,8 @@ class TestMisc(CollectionsTestBase): with self.assertRaises(TypeError): doc.UIConfigurationManager[0] + doc.close(True) + if __name__ == '__main__': unittest.main() diff --git a/pyuno/qa/pytests/testcollections_mixednameindex.py b/pyuno/qa/pytests/testcollections_mixednameindex.py index 67e97a88dd90..b4c7958c6996 100644 --- a/pyuno/qa/pytests/testcollections_mixednameindex.py +++ b/pyuno/qa/pytests/testcollections_mixednameindex.py @@ -41,6 +41,8 @@ class TestMixedNameIndex(CollectionsTestBase): self.assertEqual('foo', table_by_index.Name) self.assertEqual(table_by_name, table_by_index) + doc.close(True) + if __name__ == '__main__': unittest.main() diff --git a/pyuno/source/module/pyuno_module.cxx b/pyuno/source/module/pyuno_module.cxx index e212e8de9f8d..0f08ebc53367 100644 --- a/pyuno/source/module/pyuno_module.cxx +++ b/pyuno/source/module/pyuno_module.cxx @@ -22,6 +22,7 @@ #include "pyuno_impl.hxx" +#include <cassert> #include <unordered_map> #include <utility> @@ -318,12 +319,22 @@ static PyObject* getComponentContext( return ret.getAcquired(); } +// While pyuno.private_initTestEnvironment is called from individual Python tests (e.g., from +// UnoInProcess in unotest/source/python/org/libreoffice/unotest.py, which makes sure to call it +// only once), pyuno.private_deinitTestEnvironment is called centrally from +// unotest/source/python/org/libreoffice/unittest.py at the end of every PythonTest (to DeInitVCL +// exactly once near the end of the process, if InitVCL has ever been called via +// pyuno.private_initTestEnvironment): + +static osl::Module * testModule = nullptr; + static PyObject* initTestEnvironment( SAL_UNUSED_PARAMETER PyObject*, SAL_UNUSED_PARAMETER PyObject*) { // this tries to bootstrap enough of the soffice from python to run // unit tests, which is only possible indirectly because pyuno is URE // so load "test" library and invoke a function there to do the work + assert(testModule == nullptr); try { PyObject *const ctx(getComponentContext(nullptr, nullptr)); @@ -353,6 +364,7 @@ static PyObject* initTestEnvironment( mod.getFunctionSymbol("test_init")); if (!pFunc) { abort(); } reinterpret_cast<void (SAL_CALL *)(XMultiServiceFactory*)>(pFunc)(xMSF.get()); + testModule = &mod; } catch (const css::uno::Exception &) { @@ -361,6 +373,26 @@ static PyObject* initTestEnvironment( return Py_None; } +static PyObject* deinitTestEnvironment( + SAL_UNUSED_PARAMETER PyObject*, SAL_UNUSED_PARAMETER PyObject*) +{ + if (testModule != nullptr) + { + try + { + oslGenericFunction const pFunc( + testModule->getFunctionSymbol("test_deinit")); + if (!pFunc) { abort(); } + reinterpret_cast<void (SAL_CALL *)()>(pFunc)(); + } + catch (const css::uno::Exception &) + { + abort(); + } + } + return Py_None; +} + PyObject * extractOneStringArg( PyObject *args, char const *funcName ) { if( !PyTuple_Check( args ) || PyTuple_Size( args) != 1 ) @@ -843,6 +875,7 @@ static PyObject *sal_debug( struct PyMethodDef PyUNOModule_methods [] = { {"private_initTestEnvironment", initTestEnvironment, METH_VARARGS, nullptr}, + {"private_deinitTestEnvironment", deinitTestEnvironment, METH_VARARGS, nullptr}, {"getComponentContext", getComponentContext, METH_VARARGS, nullptr}, {"_createUnoStructHelper", reinterpret_cast<PyCFunction>(createUnoStructHelper), METH_VARARGS | METH_KEYWORDS, nullptr}, {"getTypeByName", getTypeByName, METH_VARARGS, nullptr}, diff --git a/sfx2/qa/python/check_sidebar.py b/sfx2/qa/python/check_sidebar.py index e8fd50338b27..59cc955b8016 100644 --- a/sfx2/qa/python/check_sidebar.py +++ b/sfx2/qa/python/check_sidebar.py @@ -24,7 +24,6 @@ class CheckSidebar(unittest.TestCase): def setUpClass(cls): cls._uno = UnoInProcess() cls._uno.setUp() - cls._xDoc = cls._uno.openEmptyDoc( url = "private:factory/scalc", bHidden = False, bReadOnly = False) @classmethod def tearDownClass(cls): @@ -32,7 +31,7 @@ class CheckSidebar(unittest.TestCase): def test_check_sidebar(self): - xDoc = self.__class__._xDoc + xDoc = self.__class__._uno.openEmptyDoc( url = "private:factory/scalc", bHidden = False, bReadOnly = False) xController = xDoc.getCurrentController() xSidebar = xController.getSidebar() diff --git a/sfx2/qa/python/check_sidebar_registry.py b/sfx2/qa/python/check_sidebar_registry.py index 86f22f4fd44a..47b8eecdefb9 100644 --- a/sfx2/qa/python/check_sidebar_registry.py +++ b/sfx2/qa/python/check_sidebar_registry.py @@ -19,7 +19,6 @@ class CheckSidebarRegistry(unittest.TestCase): def setUpClass(cls): cls._uno = UnoInProcess() cls._uno.setUp() - cls._xDoc = cls._uno.openEmptyDoc( url = "private:factory/scalc", bHidden = False, bReadOnly = False) @classmethod def tearDownClass(cls): diff --git a/solenv/gbuild/PythonTest.mk b/solenv/gbuild/PythonTest.mk index a2bac3819e02..329009c4b1d2 100644 --- a/solenv/gbuild/PythonTest.mk +++ b/solenv/gbuild/PythonTest.mk @@ -21,7 +21,7 @@ gb_PythonTest_EXECUTABLE_GDB := $(PYTHON_FOR_BUILD) gb_PythonTest_DEPS := endif -gb_PythonTest_COMMAND := $(gb_PythonTest_EXECUTABLE) -m unittest +gb_PythonTest_COMMAND := $(gb_PythonTest_EXECUTABLE) -m org.libreoffice.unittest .PHONY : $(call gb_PythonTest_get_clean_target,%) $(call gb_PythonTest_get_clean_target,%) : @@ -31,7 +31,10 @@ $(call gb_PythonTest_get_clean_target,%) : ifneq ($(DISABLE_PYTHON),TRUE) .PHONY : $(call gb_PythonTest_get_target,%) -$(call gb_PythonTest_get_target,%) :| $(gb_PythonTest_DEPS) +$(call gb_PythonTest_get_target,%) :\ + $(call gb_Library_get_target,pyuno) \ + $(if $(filter-out WNT,$(OS)),$(call gb_Library_get_target,pyuno_wrapper)) \ + | $(gb_PythonTest_DEPS) ifneq ($(gb_SUPPRESS_TESTS),) @true else diff --git a/sw/qa/python/check_bookmarks.py b/sw/qa/python/check_bookmarks.py index 73fd9bb6b98e..8210b4eb005a 100644 --- a/sw/qa/python/check_bookmarks.py +++ b/sw/qa/python/check_bookmarks.py @@ -47,6 +47,10 @@ class CheckBookmarks(unittest.TestCase): @classmethod def tearDownClass(cls): cls._uno.tearDown() + # HACK in case cls._xDoc holds a UNO proxy to an SwXTextDocument (whose dtor calls + # Application::GetSolarMutex via sw::UnoImplPtrDeleter), which would potentially only be + # garbage-collected after VCL has already been deinitialized: + cls._xDoc = None def test_bookmarks(self): self.xDoc = self.__class__._xDoc diff --git a/sw/qa/python/check_change_color.py b/sw/qa/python/check_change_color.py index d8562bc77b52..07b622031a61 100644 --- a/sw/qa/python/check_change_color.py +++ b/sw/qa/python/check_change_color.py @@ -27,7 +27,6 @@ class CheckChangeColor(unittest.TestCase): def setUpClass(cls): cls._uno = UnoInProcess() cls._uno.setUp() - cls._xEmptyDoc = cls._uno.openEmptyWriterDoc() cls.RED = 0xFF0000 cls.BLUE = 0x0000FF cls.GREEN = 0x008000 diff --git a/sw/qa/python/check_cross_references.py b/sw/qa/python/check_cross_references.py index 742cc0d94ad5..6aad1c47ca3a 100644 --- a/sw/qa/python/check_cross_references.py +++ b/sw/qa/python/check_cross_references.py @@ -46,6 +46,10 @@ class CheckCrossReferences(unittest.TestCase): @classmethod def tearDownClass(cls): cls._uno.tearDown() + # HACK in case cls.document holds a UNO proxy to an SwXTextDocument (whose dtor calls + # Application::GetSolarMutex via sw::UnoImplPtrDeleter), which would potentially only be + # garbage-collected after VCL has already been deinitialized: + cls.document = None def getNextField(self): while True: diff --git a/sw/qa/python/check_fields.py b/sw/qa/python/check_fields.py index 60418a93001d..eb6dd2dc1c8a 100644 --- a/sw/qa/python/check_fields.py +++ b/sw/qa/python/check_fields.py @@ -17,8 +17,6 @@ class CheckFields(unittest.TestCase): def setUpClass(cls): cls._uno = UnoInProcess() cls._uno.setUp() - cls._xDoc = cls._uno.openTemplateFromTDOC("fdo39694.ott") - cls._xEmptyDoc = cls._uno.openEmptyWriterDoc() @classmethod def tearDownClass(cls): @@ -26,7 +24,7 @@ class CheckFields(unittest.TestCase): def test_fdo39694_load(self): placeholders = ["<Kadr1>", "<Kadr2>", "<Kadr3>", "<Kadr4>", "<Pnname>", "<Pvname>", "<Pgeboren>"] - xDoc = self.__class__._xDoc + xDoc = self.__class__._uno.openTemplateFromTDOC("fdo39694.ott") xEnumerationAccess = xDoc.getTextFields() xFieldEnum = xEnumerationAccess.createEnumeration() for xField in xFieldEnum: @@ -35,9 +33,10 @@ class CheckFields(unittest.TestCase): read_content = xAnchor.getString() self.assertTrue(read_content in placeholders, "field %s is not contained: " % read_content) + xDoc.close(True) def test_fdo42073(self): - xDoc = self.__class__._xEmptyDoc + xDoc = self.__class__._uno.openEmptyWriterDoc() xBodyText = xDoc.getText() xCursor = xBodyText.createTextCursor() xTextField = xDoc.createInstance("com.sun.star.text.TextField.Input") @@ -48,6 +47,7 @@ class CheckFields(unittest.TestCase): xTextField.setPropertyValue("Content", content) read_content = xTextField.getPropertyValue("Content") self.assertEqual(content, read_content) + xDoc.close(True) if __name__ == '__main__': unittest.main() diff --git a/sw/qa/python/check_flies.py b/sw/qa/python/check_flies.py index 6353ccda150d..0e60b2195e89 100644 --- a/sw/qa/python/check_flies.py +++ b/sw/qa/python/check_flies.py @@ -26,18 +26,18 @@ class CheckFlies(unittest.TestCase): def setUpClass(cls): cls._uno = UnoInProcess() cls._uno.setUp() - cls.document = cls._uno.openDocFromTDOC("CheckFlies.odt") @classmethod def tearDownClass(cls): cls._uno.tearDown() def test_checkFlies(self): - xTFS = self.__class__.document + document = self.__class__._uno.openDocFromTDOC("CheckFlies.odt") + xTFS = document self.checkTextFrames(xTFS) - xTGOS = self.__class__.document + xTGOS = document self.checkGraphicFrames(xTGOS) - xTEOS = self.__class__.document + xTEOS = document self.checkEmbeddedFrames(xTEOS) def checkEmbeddedFrames(self, xTGOS): diff --git a/sw/qa/python/check_indexed_property_values.py b/sw/qa/python/check_indexed_property_values.py index 5609aa4225cb..ceaf82a6cac6 100644 --- a/sw/qa/python/check_indexed_property_values.py +++ b/sw/qa/python/check_indexed_property_values.py @@ -34,7 +34,6 @@ class CheckIndexedPropertyValues(unittest.TestCase): cls._uno = UnoInProcess() cls._uno.setUp() cls.xContext = cls._uno.getContext() - cls.xDoc = cls._uno.openEmptyWriterDoc() @classmethod def tearDownClass(cls): diff --git a/sw/qa/python/check_named_property_values.py b/sw/qa/python/check_named_property_values.py index dd06adc60313..1a81d13a6323 100644 --- a/sw/qa/python/check_named_property_values.py +++ b/sw/qa/python/check_named_property_values.py @@ -36,7 +36,6 @@ class CheckNamedPropertyValues(unittest.TestCase): cls._uno = UnoInProcess() cls._uno.setUp() cls.xContext = cls._uno.getContext() - cls.xDoc = cls._uno.openEmptyWriterDoc() @classmethod def tearDownClass(cls): diff --git a/sw/qa/python/check_table.py b/sw/qa/python/check_table.py index 35da08fe8195..8fd888f187bd 100644 --- a/sw/qa/python/check_table.py +++ b/sw/qa/python/check_table.py @@ -583,6 +583,8 @@ class CheckTable(unittest.TestCase): xCellRangeString = xChartDataProvider.convertRangeFromXML("Table1.$A$1:.$C$3") self.assertEqual("Table1.A1:C3", xCellRangeString) + xDoc.dispose() + def test_splitRangeHorizontal(self): xDoc = CheckTable._uno.openEmptyWriterDoc() xTable = xDoc.createInstance("com.sun.star.text.TextTable") @@ -600,6 +602,7 @@ class CheckTable(unittest.TestCase): self.assertTrue(math.isnan(xTable.Data[1][1])) self.assertTrue(math.isnan(xTable.Data[2][0])) self.assertTrue(math.isnan(xTable.Data[2][1])) + xDoc.dispose() def test_mergeRangeHorizontal(self): xDoc = CheckTable._uno.openEmptyWriterDoc() @@ -618,6 +621,7 @@ class CheckTable(unittest.TestCase): self.assertEqual(xTable.Data[1][1], float(5)) self.assertEqual(xTable.Data[1][2], float(6)) self.assertEqual(xTable.Data[2], (float(7), float(8), float(9))) + xDoc.dispose() if __name__ == '__main__': unittest.main() diff --git a/sw/qa/python/get_expression.py b/sw/qa/python/get_expression.py index 7462db68a730..98e9402bb602 100644 --- a/sw/qa/python/get_expression.py +++ b/sw/qa/python/get_expression.py @@ -22,6 +22,10 @@ class TestGetExpression(unittest.TestCase): @classmethod def tearDownClass(cls): cls._uno.tearDown() + # HACK in case cls._xDoc holds a UNO proxy to an SwXTextDocument (whose dtor calls + # Application::GetSolarMutex via sw::UnoImplPtrDeleter), which would potentially only be + # garbage-collected after VCL has already been deinitialized: + cls._xDoc = None def test_get_expression(self): self.__class__._uno.checkProperties( diff --git a/sw/qa/python/set_expression.py b/sw/qa/python/set_expression.py index 220952536fea..c5dc5e6ae2e9 100644 --- a/sw/qa/python/set_expression.py +++ b/sw/qa/python/set_expression.py @@ -18,15 +18,15 @@ class TestSetExpression(unittest.TestCase): def setUpClass(cls): cls._uno = UnoInProcess() cls._uno.setUp() - cls._xDoc = cls._uno.openEmptyWriterDoc() @classmethod def tearDownClass(cls): cls._uno.tearDown() def test_set_expression(self): + xDoc = self.__class__._uno.openEmptyWriterDoc() self.__class__._uno.checkProperties( - self.__class__._xDoc.createInstance("com.sun.star.text.textfield.SetExpression"), + xDoc.createInstance("com.sun.star.text.textfield.SetExpression"), {"NumberingType": 0, "Content": "foo", "CurrentPresentation": "bar", diff --git a/sw/qa/python/text_portion_enumeration_test.py b/sw/qa/python/text_portion_enumeration_test.py index 3a7e9d8586be..c379138db303 100644 --- a/sw/qa/python/text_portion_enumeration_test.py +++ b/sw/qa/python/text_portion_enumeration_test.py @@ -934,6 +934,11 @@ class TextPortionEnumerationTest(unittest.TestCase): @classmethod def tearDownClass(cls): cls.xDoc.close(True) + cls._uno.tearDown() + # HACK in case cls.xDoc holds a UNO proxy to an SwXTextDocument (whose dtor calls + # Application::GetSolarMutex via sw::UnoImplPtrDeleter), which would potentially only be + # garbage-collected after VCL has already been deinitialized: + cls.xDoc = None def test_text(self): root = TreeNode() diff --git a/sw/qa/python/var_fields.py b/sw/qa/python/var_fields.py index c2af7a40f408..52fe3ddd6938 100644 --- a/sw/qa/python/var_fields.py +++ b/sw/qa/python/var_fields.py @@ -19,7 +19,6 @@ class TestVarFields(unittest.TestCase): def setUpClass(cls): cls._uno = UnoInProcess() cls._uno.setUp() - cls._xDoc = cls._uno.openEmptyWriterDoc() @classmethod def tearDownClass(cls): @@ -32,7 +31,7 @@ class TestVarFields(unittest.TestCase): sw/qa/complex/writer/VarFields.java """ - xDoc = self.__class__._xDoc + xDoc = self.__class__._uno.openEmptyWriterDoc() xBodyText = xDoc.getText() xCursor = xBodyText.createTextCursor() # 0. create text field diff --git a/test/source/bootstrapfixture.cxx b/test/source/bootstrapfixture.cxx index a26b79a00c10..a8da11caed92 100644 --- a/test/source/bootstrapfixture.cxx +++ b/test/source/bootstrapfixture.cxx @@ -99,6 +99,12 @@ SAL_DLLPUBLIC_EXPORT void test_init(lang::XMultiServiceFactory *pFactory) catch (...) { abort(); } } +// this is called from pyuno +SAL_DLLPUBLIC_EXPORT void test_deinit() +{ + DeInitVCL(); +} + } // extern "C" void test::BootstrapFixture::setUp() diff --git a/unotest/source/python/org/libreoffice/unittest.py b/unotest/source/python/org/libreoffice/unittest.py new file mode 100644 index 000000000000..364462ed3827 --- /dev/null +++ b/unotest/source/python/org/libreoffice/unittest.py @@ -0,0 +1,29 @@ +# -*- tab-width: 4; indent-tabs-mode: nil; py-indent-offset: 4 -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +import gc +import pyuno +import unittest + +class LoTestResult(unittest.TextTestResult): + def stopTestRun(self): + # HACK calling gc.collect() to get rid of as many still existing UNO proxies to + # SwXTextDocument and friends as possible; those C++ classes' dtors call + # Application::GetSolarMutex via sw::UnoImplPtrDeleter, so the dtors must be called before + # DeInitVCL in the call to pyuno.private_deinitTestEnvironment(); any remainging proxies + # that are still referenced (UnoInProcess' self.xDoc in + # unotest/source/python/org/libreoffice/unotest.py, or per-class variables in the various + # PythonTests) need to be individually released (each marked as "HACK" in the code): + gc.collect() + pyuno.private_deinitTestEnvironment() + +if __name__ == '__main__': + unittest.main(module=None, testRunner=unittest.TextTestRunner(resultclass=LoTestResult)) + +# vim: set shiftwidth=4 softtabstop=4 expandtab: diff --git a/unotest/source/python/org/libreoffice/unotest.py b/unotest/source/python/org/libreoffice/unotest.py index 000a148b353f..804ddafc5518 100644 --- a/unotest/source/python/org/libreoffice/unotest.py +++ b/unotest/source/python/org/libreoffice/unotest.py @@ -246,7 +246,12 @@ class UnoInProcess: def postTest(self): assert(self.xContext) def tearDown(self): - self.xDoc.close(True) + if hasattr(self, 'xDoc'): + self.xDoc.close(True) + # HACK in case self.xDoc holds a UNO proxy to an SwXTextDocument (whose dtor calls + # Application::GetSolarMutex via sw::UnoImplPtrDeleter), which would potentially only be + # garbage-collected after VCL has already been deinitialized: + self.xDoc = None def simpleInvoke(connection, test): try: |