summaryrefslogtreecommitdiff
path: root/pyuno
diff options
context:
space:
mode:
authorStephan Bergmann <sbergman@redhat.com>2018-09-06 17:13:54 +0200
committerStephan Bergmann <sbergman@redhat.com>2018-09-07 07:31:48 +0200
commite7a3329fd0a68c95f00e6cdfdc3e40e6afa5411c (patch)
treea79054d20a3904d73347dcd6af696dcbb9897a78 /pyuno
parentdbb444e4ed7c19a11733ce8438bbb6546d42f852 (diff)
DeInitVCL in PythonTest
After b9757f5cfdb62b24e79eeb4c0ef0c8b98056cecf "loplugin:useuniqueptr in vcl/svdata" ASan/UBSan builds started to fail (like <https://ci.libreoffice.org//job/lo_ubsan/1025/>) at the end of PythonTest_dbaccess_python (and probably other PythonTests), when during exit the static utl::ConfigManager instance already happens to be destroyed by the time the static ImplSVData's mpSettingsConfigItem is destroyed (which would normally be cleared during DeInitVCL, if PythonTests would call that, and which in the past had thus simply been leaked in PythonTests when that mpSettingsConfigItem was a plain pointer instead of std::unique_ptr). So ensure that PythonTests that initialize VCL also call DeInitVCL, via a new private_deinitTestEnvironment, complementing the existing private_initTestEnvironment. However, while private_initTestEnvironment is called once (typically via UnoInProcess.setUp, which internally makes sure to only call it once) as soon as the first executed test needs it, private_deinitTestEnvironment must be called once after the lasts test needing it has executed. The only way that I found to do that is to override unittest.TextTestResult's stopTestRun method, which is called once after all tests have been executed. Hence a new test runner setup in unotest/source/python/org/libreoffice/unittest.py that is now called from solenv/gbuild/PythonTest.mk. That revealed a few places in PythonTests that didn't yet close/delete documents that they had opened, which has now been added. One remaining problem then is that classes like SwXTextDocument and friends call Application::GetSolarMutex from their dtors, via sw::UnoImplPtrDeleter (a "Smart pointer class ensuring that the pointed object is deleted with a locked SolarMutex", sw/inc/unobaseclass.hxx). That means that any PyUNO proxies to such C++ objects that remain alive after private_deinitTestEnvironment will cause issues at exit, when Python does a final garbage collection of those objects. The ultimate fix will be to remove that unhelpful UnoImplPtrDeleter and its locking of SolarMutex from the dtors of UNO objects; until then, the Python code is now sprinkled with some HACKs to make sure all those PyUNO proxies are released in a timely fashion (see the comment in unotest/source/python/org/libreoffice/unittest.py for details). (Also, it would probably help if UnoInProcess didn't keep a local self.xDoc around referencing (just) the last result of calling one of its open* methods, confusingly making it the responsibility of UnoInProcess to close that one document while making it the responsibility of the test code making the other UnoInProcess.open* calls to close any other documents.) Change-Id: Ief27c81e2b763e9be20cbf3234b68924315f13be Reviewed-on: https://gerrit.libreoffice.org/60100 Tested-by: Jenkins Reviewed-by: Stephan Bergmann <sbergman@redhat.com>
Diffstat (limited to 'pyuno')
-rw-r--r--pyuno/qa/pytests/testcollections_XCellRange.py34
-rw-r--r--pyuno/qa/pytests/testcollections_XEnumeration.py11
-rw-r--r--pyuno/qa/pytests/testcollections_XEnumerationAccess.py15
-rw-r--r--pyuno/qa/pytests/testcollections_XIndexAccess.py24
-rw-r--r--pyuno/qa/pytests/testcollections_XIndexContainer.py2
-rw-r--r--pyuno/qa/pytests/testcollections_XIndexReplace.py18
-rw-r--r--pyuno/qa/pytests/testcollections_XNameAccess.py22
-rw-r--r--pyuno/qa/pytests/testcollections_XNameContainer.py12
-rw-r--r--pyuno/qa/pytests/testcollections_XNameReplace.py6
-rw-r--r--pyuno/qa/pytests/testcollections_misc.py8
-rw-r--r--pyuno/qa/pytests/testcollections_mixednameindex.py2
-rw-r--r--pyuno/source/module/pyuno_module.cxx33
12 files changed, 187 insertions, 0 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},