import unittest, gc

from ctypes import *

from ctypes.wintypes import *



################################################################



class PROCESS_MEMORY_COUNTERS(Structure):

    _fields_ = [("cb", DWORD),

                ("PageFaultCount", DWORD),

                ("PeakWorkingSetSize", c_size_t),

                ("WorkingSetSize", c_size_t),

                ("QuotaPeakPagedPoolUsage", c_size_t),

                ("QuotaPagedPoolUsage", c_size_t),

                ("QuotaPeakNonPagedPoolUsage", c_size_t),

                ("QuotaNonPagedPoolUsage", c_size_t),

                ("PagefileUsage", c_size_t),

                ("PeakPagefileUsage", c_size_t)]

    def __init__(self):

        self.cb = sizeof(self)



    def dump(self):

        for n, _ in self._fields_[2:]:

            print(n, getattr(self, n)/1e6)



try:

    windll.psapi.GetProcessMemoryInfo.argtypes = (HANDLE, POINTER(PROCESS_MEMORY_COUNTERS), DWORD)

except WindowsError:

    # cannot search for memory leaks on Windows CE

    def find_memleak(func, loops=None):

        return 0

else:

    def wss():

        # Return the working set size (memory used by process)

        pmi = PROCESS_MEMORY_COUNTERS()

        if not windll.psapi.GetProcessMemoryInfo(-1, byref(pmi), sizeof(pmi)):

            raise WinError()

        return pmi.WorkingSetSize



    LOOPS = 10, 1000



    def find_memleak(func, loops=LOOPS):

        # call 'func' several times, so that memory consumption

        # stabilizes:

        for j in range(loops[0]):

            for k in range(loops[1]):

                func()

        gc.collect(); gc.collect(); gc.collect()

        bytes = wss()

        # call 'func' several times, recording the difference in

        # memory consumption before and after the call.  Repeat this a

        # few times, and return a list containing the memory

        # consumption differences.

        for j in range(loops[0]):

            for k in range(loops[1]):

                func()

        gc.collect(); gc.collect(); gc.collect()

        # return the increased in process size

        result = wss() - bytes

        # Sometimes the process size did decrease, we do not report leaks

        # in this case:

        return max(result, 0)

