improve tests
This commit is contained in:
+43
-12
@@ -26,18 +26,6 @@ int get_int_from_float(double from_float, int multiplier)
|
||||
return (int) from_float*multiplier;
|
||||
}
|
||||
|
||||
char *return_c_string_to_be_freed()
|
||||
{
|
||||
char *test = (char *)malloc(12 * sizeof(char));
|
||||
strcpy(test, "testingonly");
|
||||
return test;
|
||||
}
|
||||
|
||||
ToBeFreed *return_class_to_be_freed()
|
||||
{
|
||||
return new ToBeFreed();
|
||||
}
|
||||
|
||||
std::string SomeObject::staticData = std::string("Hello Static World!");
|
||||
|
||||
SomeObject::~SomeObject ()
|
||||
@@ -568,3 +556,46 @@ test_args_kwargs(const char *args, const char *kwargs)
|
||||
return (int) (kwargs - args);
|
||||
}
|
||||
|
||||
ToBeFreed::ToBeFreed(int size) {
|
||||
m_size = size;
|
||||
m = return_c_string_to_be_freed(size);
|
||||
}
|
||||
|
||||
ToBeFreed::~ToBeFreed() {
|
||||
free(m);
|
||||
m = nullptr;
|
||||
}
|
||||
|
||||
ToBeFreed::ToBeFreed(const ToBeFreed& from) {
|
||||
m_size = from.m_size;
|
||||
m = return_c_string_to_be_freed(m_size);
|
||||
}
|
||||
|
||||
char *ToBeFreed::value() {
|
||||
return m;
|
||||
}
|
||||
|
||||
char *return_c_string_to_be_freed(int size)
|
||||
{
|
||||
char *test = (char *)malloc(size * sizeof(char));
|
||||
strcpy(test, "testingonly");
|
||||
return test;
|
||||
}
|
||||
|
||||
ToBeFreed *
|
||||
return_class_to_be_freed(int size)
|
||||
{
|
||||
return new ToBeFreed(size);
|
||||
}
|
||||
|
||||
char *
|
||||
return_c_string_to_not_be_freed(int size)
|
||||
{
|
||||
return return_c_string_to_be_freed(size);
|
||||
}
|
||||
|
||||
ToBeFreed *
|
||||
return_class_to_not_be_freed(int size)
|
||||
{
|
||||
return new ToBeFreed(size);
|
||||
}
|
||||
+12
-5
@@ -1370,20 +1370,27 @@ private:
|
||||
};
|
||||
|
||||
// -#- name=return_c_string_to_be_freed; @return(free_after_copy=true) -#-
|
||||
char *return_c_string_to_be_freed();
|
||||
char *return_c_string_to_be_freed(int size);
|
||||
|
||||
// -#- name=return_c_string_to_not_be_freed; @return(free_after_copy=false) -#-
|
||||
char *return_c_string_to_not_be_freed(int size);
|
||||
|
||||
class ToBeFreed
|
||||
{
|
||||
public:
|
||||
ToBeFreed() { m = return_c_string_to_be_freed(); }
|
||||
~ToBeFreed() { free(m); }
|
||||
|
||||
ToBeFreed(int size);
|
||||
~ToBeFreed();
|
||||
ToBeFreed(const ToBeFreed&);
|
||||
char *value();
|
||||
private:
|
||||
char *m;
|
||||
int m_size;
|
||||
};
|
||||
|
||||
// -#- name=return_class_to_be_freed; @return(free_after_copy=true) -#-
|
||||
ToBeFreed *return_class_to_be_freed();
|
||||
ToBeFreed *return_class_to_be_freed(int size);
|
||||
|
||||
// -#- name=return_class_to_not_be_freed; @return(free_after_copy=false) -#-
|
||||
ToBeFreed *return_class_to_not_be_freed(int size);
|
||||
|
||||
#endif /* !FOO_H_ */
|
||||
|
||||
+11
-3
@@ -116,14 +116,22 @@ int %s::custom_method_added_by_a_hook(int x)
|
||||
|
||||
## test free_after_copy.
|
||||
mod.add_function('return_c_string_to_be_freed',
|
||||
ReturnValue.new('char *', free_after_copy=True ),
|
||||
[])
|
||||
ReturnValue.new('char *', free_after_copy=True),
|
||||
[Parameter.new('int', 'size')])
|
||||
mod.add_function('return_c_string_to_not_be_freed',
|
||||
ReturnValue.new('char *', free_after_copy=False),
|
||||
[Parameter.new('int', 'size')])
|
||||
|
||||
ToBeFreed = mod.add_class('ToBeFreed')
|
||||
ToBeFreed.add_constructor([Parameter.new('int', 'size')])
|
||||
ToBeFreed.add_copy_constructor()
|
||||
ToBeFreed.add_method('value', ReturnValue.new('char *'), [])
|
||||
mod.add_function('return_class_to_be_freed',
|
||||
ReturnValue.new('ToBeFreed *', free_after_copy=True),
|
||||
[])
|
||||
[Parameter.new('int', 'size')])
|
||||
mod.add_function('return_class_to_not_be_freed',
|
||||
ReturnValue.new('ToBeFreed *', free_after_copy=False),
|
||||
[Parameter.new('int', 'size')])
|
||||
|
||||
SomeObject = mod.add_class('SomeObject', allow_subclassing=True)
|
||||
|
||||
|
||||
+40
-1
@@ -4,6 +4,8 @@ import weakref
|
||||
import gc
|
||||
import os.path
|
||||
import copy
|
||||
import resource
|
||||
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)),
|
||||
'..', 'build', 'tests'))
|
||||
|
||||
@@ -1536,7 +1538,7 @@ class TestFoo(unittest.TestCase):
|
||||
value = x.ReturnMyAStruct()
|
||||
self.assertEqual(value.a, 123)
|
||||
|
||||
def test_free_after_copy_string(self):
|
||||
def test_free_after_copy_string_examine_code(self):
|
||||
seen_free_comment = False
|
||||
seen_free = False
|
||||
seen_delete_comment = False
|
||||
@@ -1556,5 +1558,42 @@ class TestFoo(unittest.TestCase):
|
||||
self.assertTrue(seen_free)
|
||||
self.assertTrue(seen_delete)
|
||||
|
||||
def test_free_after_copy(self):
|
||||
v = foo.return_c_string_to_be_freed(20)
|
||||
self.assertEqual(v, "testingonly")
|
||||
c = foo.return_class_to_be_freed(20)
|
||||
self.assertEqual(c.value(), "testingonly")
|
||||
|
||||
|
||||
def _runner(self, n, size, fn):
|
||||
while gc.collect():
|
||||
pass
|
||||
before = resource.getrusage(resource.RUSAGE_SELF).ru_maxrss
|
||||
for i in range(n):
|
||||
fn(size)
|
||||
|
||||
while gc.collect():
|
||||
pass
|
||||
after = resource.getrusage(resource.RUSAGE_SELF).ru_maxrss
|
||||
# maxrss is in kB.
|
||||
return (after - before) * 1024
|
||||
|
||||
def test_free_after_copy_leak(self):
|
||||
n = 200
|
||||
size = 1024*32
|
||||
# run once to bump up overall maxrss if's going to be bumped up.
|
||||
self._runner(n, size, foo.return_c_string_to_be_freed)
|
||||
diff = self._runner(n, size, foo.return_c_string_to_be_freed)
|
||||
#diff += self._runner(n, size, foo.return_class_to_be_freed)
|
||||
# maxrss should only grow marginally here.
|
||||
self.assertTrue(diff < (size*2))
|
||||
|
||||
leaky = self._runner(n, size, foo.return_c_string_to_not_be_freed)
|
||||
leaky += self._runner(n, size, foo.return_class_to_not_be_freed)
|
||||
# maxrss should have grown significantly
|
||||
self.assertTrue(diff < leaky)
|
||||
self.assertTrue(leaky > size * 10)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
||||
Reference in New Issue
Block a user