Skip to content

Commit d8775b5

Browse files
committed
Add a test for leaking memory in the C extension. Windows only for now, kind of experimental.
1 parent 411d194 commit d8775b5

File tree

3 files changed

+72
-1
lines changed

3 files changed

+72
-1
lines changed

test/coveragetest.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,7 @@ def check_coverage(self, text, lines=None, missing="", excludes=None,
214214
cov.report(mod, file=frep)
215215
rep = " ".join(frep.getvalue().split("\n")[2].split()[1:])
216216
self.assertEqual(report, rep)
217-
217+
218218
def assert_raises_msg(self, excClass, msg, callableObj, *args, **kwargs):
219219
""" Just like unittest.TestCase.assertRaises,
220220
but checks that the message is right too.

test/osinfo.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
"""OS information for testing."""
2+
3+
import sys
4+
5+
if sys.hexversion >= 0x02050000 and sys.platform == 'win32':
6+
# Windows implementation
7+
def process_ram():
8+
"""How much RAM is this process using? (Windows)"""
9+
import ctypes
10+
# lifted from:
11+
# lists.ubuntu.com/archives/bazaar-commits/2009-February/011990.html
12+
class PROCESS_MEMORY_COUNTERS_EX(ctypes.Structure):
13+
"""Used by GetProcessMemoryInfo"""
14+
_fields_ = [('cb', ctypes.c_ulong),
15+
('PageFaultCount', ctypes.c_ulong),
16+
('PeakWorkingSetSize', ctypes.c_size_t),
17+
('WorkingSetSize', ctypes.c_size_t),
18+
('QuotaPeakPagedPoolUsage', ctypes.c_size_t),
19+
('QuotaPagedPoolUsage', ctypes.c_size_t),
20+
('QuotaPeakNonPagedPoolUsage', ctypes.c_size_t),
21+
('QuotaNonPagedPoolUsage', ctypes.c_size_t),
22+
('PagefileUsage', ctypes.c_size_t),
23+
('PeakPagefileUsage', ctypes.c_size_t),
24+
('PrivateUsage', ctypes.c_size_t),
25+
]
26+
27+
mem_struct = PROCESS_MEMORY_COUNTERS_EX()
28+
ret = ctypes.windll.psapi.GetProcessMemoryInfo(
29+
ctypes.windll.kernel32.GetCurrentProcess(),
30+
ctypes.byref(mem_struct),
31+
ctypes.sizeof(mem_struct)
32+
)
33+
if not ret:
34+
return 0
35+
return mem_struct.PrivateUsage
36+
37+
else:
38+
def process_ram():
39+
"""How much RAM is this process using? (no implementation)"""
40+
return 0

test/test_coverage.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
sys.path.insert(0, os.path.split(__file__)[0]) # Force relative import for Py3k
1111
from coveragetest import CoverageTest
12+
import osinfo
1213

1314

1415
class BasicCoverageTest(CoverageTest):
@@ -1730,6 +1731,36 @@ def recur(n):
17301731
[1,2,3,5,7], "")
17311732

17321733

1734+
class MemoryLeakTest(CoverageTest):
1735+
"""Attempt the impossible: test that memory doesn't leak."""
1736+
1737+
def test_for_leaks(self):
1738+
lines = list(range(301, 315))
1739+
lines.remove(306)
1740+
baseline_ram = osinfo.process_ram()
1741+
# Ugly string mumbo jumbo to get 300 blank lines at the beginning..
1742+
self.check_coverage("""\
1743+
# blank line\n""" * 300 + """\
1744+
def once(x):
1745+
if x % 100 == 0:
1746+
raise Exception("100!")
1747+
elif x % 2:
1748+
return 10
1749+
else:
1750+
return 11
1751+
i = 0 # Portable loop without alloc'ing memory.
1752+
while i < 10000:
1753+
try:
1754+
once(i)
1755+
except:
1756+
pass
1757+
i += 1
1758+
""",
1759+
lines, "")
1760+
ram_growth = osinfo.process_ram() - baseline_ram
1761+
self.assert_(ram_growth < 100000, "RAM grew by %d" % (ram_growth))
1762+
1763+
17331764
class PyexpatTest(CoverageTest):
17341765
"""Pyexpat screws up tracing. Make sure we've counter-defended properly."""
17351766

0 commit comments

Comments
 (0)