>From 6a8ac43618b8b969dd62c6da70fac2bf5e6115d7 Mon Sep 17 00:00:00 2001
From: Martin Nagy <mnagy@redhat.com>
Date: Wed, 21 Oct 2009 17:24:13 +0200
Subject: [PATCH 6/7] Add a new set of helpful common functions for tests

The leak_check_setup() and leak_check_teardown() functions can be added
to a test case with tcase_add_checked_fixture(). They will make sure
that all tests are checked for memory leaks. However, since talloc is
hierarchical and automatically frees the children, this will not catch
all cases, but might still be helpful.

The check_leaks(ctx, bytes) function takes a talloc context as an
argument and the number of bytes it should be using up (children
included). The total byte size used up by the context is determined by
the talloc_total_size() function. If the size doesn't agree,
check_leaks() will print out a talloc report on the context and makes
the current test fail.

The check_leaks_push() and check_leaks_pop() both take a talloc context
as an argument. Every time push is called, the context is "pushed" onto
an internal stack and it's current size is noted. When the context is
later "poped", the pop function will make sure that the size is the same
as when it was pushed. It will also check that it's not called
out-of-order or if the stack isn't empty.
---
 server/Makefile.am    |    3 +-
 server/tests/common.c |  104 +++++++++++++++++++++++++++++++++++++++++++++++++
 server/tests/common.h |   19 +++++++++
 3 files changed, 125 insertions(+), 1 deletions(-)
 create mode 100644 server/tests/common.c
 create mode 100644 server/tests/common.h

diff --git a/server/Makefile.am b/server/Makefile.am
index 81f438d..a2c3687 100644
--- a/server/Makefile.am
+++ b/server/Makefile.am
@@ -270,7 +270,8 @@ dist_noinst_HEADERS = \
     tools/sss_sync_ops.h \
     resolv/async_resolv.h \
     resolv/ares/ares_parse_srv_reply.h \
-    resolv/ares/ares_parse_txt_reply.h
+    resolv/ares/ares_parse_txt_reply.h \
+    tests/common.h
 
 
 ####################
diff --git a/server/tests/common.c b/server/tests/common.c
new file mode 100644
index 0000000..5b341ab
--- /dev/null
+++ b/server/tests/common.c
@@ -0,0 +1,104 @@
+/*
+   SSSD
+
+   Common utilities for check-based tests using talloc.
+
+   Authors:
+        Martin Nagy <mnagy@redhat.com>
+
+   Copyright (C) Red Hat, Inc 2009
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <check.h>
+#include <stdio.h>
+
+#include "tests/common.h"
+#include "util/dlinklist.h"
+#include "util/util.h"
+
+struct size_snapshot {
+    struct size_snapshot *prev;
+    struct size_snapshot *next;
+
+    TALLOC_CTX *ctx;
+    size_t bytes_allocated;
+};
+
+static struct size_snapshot *snapshot_stack;
+
+void
+_check_leaks(TALLOC_CTX *ctx, size_t bytes, const char *location)
+{
+    size_t bytes_allocated;
+
+    bytes_allocated = talloc_total_size(ctx);
+    if (bytes_allocated != bytes) {
+        fprintf(stderr, "Leak report for %s:\n", location);
+        talloc_report_full(NULL, stderr);
+        fail("%s: memory leaks detected, %d bytes still allocated",
+             location, bytes_allocated - bytes);
+    }
+}
+
+void
+check_leaks_push(TALLOC_CTX *ctx)
+{
+    struct size_snapshot *snapshot;
+
+    snapshot = talloc(NULL, struct size_snapshot);
+    snapshot->ctx = ctx;
+    snapshot->bytes_allocated = talloc_total_size(ctx);
+    DLIST_ADD(snapshot_stack, snapshot);
+}
+
+void
+_check_leaks_pop(TALLOC_CTX *ctx, const char *location)
+{
+    struct size_snapshot *snapshot;
+    TALLOC_CTX *old_ctx;
+    size_t bytes_allocated;
+
+    if (snapshot_stack == NULL) {
+        fail("%s: trying to pop an empty stack");
+    }
+
+    snapshot = snapshot_stack;
+    DLIST_REMOVE(snapshot_stack, snapshot);
+
+    old_ctx = snapshot->ctx;
+    bytes_allocated = snapshot->bytes_allocated;
+
+    fail_if(old_ctx != ctx, "Bad push/pop order");
+
+    talloc_zfree(snapshot);
+    _check_leaks(old_ctx, bytes_allocated, location);
+}
+
+void
+leak_check_setup(void)
+{
+    talloc_enable_null_tracking();
+}
+
+void
+leak_check_teardown(void)
+{
+    if (snapshot_stack != NULL) {
+        fail("Exiting with a non-empty stack");
+    }
+    talloc_free(talloc_autofree_context());
+    check_leaks(NULL, 0);
+}
diff --git a/server/tests/common.h b/server/tests/common.h
new file mode 100644
index 0000000..39a2b8e
--- /dev/null
+++ b/server/tests/common.h
@@ -0,0 +1,19 @@
+#ifndef __TESTS_COMMON_H__
+#define __TESTS_COMMON_H__
+
+#include <talloc.h>
+
+#define check_leaks(ctx, bytes) _check_leaks((ctx), (bytes), __location__)
+void _check_leaks(TALLOC_CTX *ctx,
+                  size_t bytes,
+                  const char *location);
+
+void check_leaks_push(TALLOC_CTX *ctx);
+
+#define check_leaks_pop(ctx) _check_leaks_pop((ctx), __location__)
+void _check_leaks_pop(TALLOC_CTX *ctx, const char *location);
+
+void leak_check_setup(void);
+void leak_check_teardown(void);
+
+#endif /* !__TESTS_COMMON_H__ */
-- 
1.6.2.5

