unittest: Make unit tests capable of using swig and python, convert stattest
authorNathan Binkert <nate@binkert.org>
Fri, 15 Apr 2011 17:45:11 +0000 (10:45 -0700)
committerNathan Binkert <nate@binkert.org>
Fri, 15 Apr 2011 17:45:11 +0000 (10:45 -0700)
src/SConscript
src/unittest/SConscript
src/unittest/stattest.cc
src/unittest/stattest.i [new file with mode: 0644]
src/unittest/stattestmain.py [new file with mode: 0644]

index 52de673dcdf54d957100a60ef4b2178202350cbf..7982eaeb474cc04760177f5755f2e5f2ad67d1c6 100755 (executable)
@@ -233,15 +233,26 @@ class SwigSource(SourceFile):
         self.cc_source = Source(cc_file, swig=True, parent=self)
         self.py_source = PySource(package, py_file, parent=self)
 
-unit_tests = []
-def UnitTest(target, sources):
-    '''Create a unit test, specify the target name and a source or
-    list of sources'''
-    if not isinstance(sources, (list, tuple)):
-        sources = [ sources ]
-
-    sources = [ Source(src, skip_lib=True) for src in sources ]
-    unit_tests.append((target, sources))
+class UnitTest(object):
+    '''Create a UnitTest'''
+
+    all = []
+    def __init__(self, target, *sources):
+        '''Specify the target name and any sources.  Sources that are
+        not SourceFiles are evalued with Source().  All files are
+        guarded with a guard of the same name as the UnitTest
+        target.'''
+
+        srcs = []
+        for src in sources:
+            if not isinstance(src, SourceFile):
+                src = Source(src, skip_lib=True)
+            src.guards[target] = True
+            srcs.append(src)
+
+        self.sources = srcs
+        self.target = target
+        UnitTest.all.append(self)
 
 # Children should have access
 Export('Source')
@@ -673,10 +684,11 @@ for swig in SwigSource.all:
     env.Command([swig.cc_source.tnode, swig.py_source.tnode], swig.tnode,
                 MakeAction('$SWIG $SWIGFLAGS -outdir ${TARGETS[1].dir} '
                 '-o ${TARGETS[0]} $SOURCES', Transform("SWIG")))
-    init_file = 'python/swig/init_%s.cc' % swig.module
+    cc_file = str(swig.tnode)
+    init_file = '%s/init_%s.cc' % (dirname(cc_file), basename(cc_file))
     env.Command(init_file, Value(swig.module),
                 MakeAction(makeEmbeddedSwigInit, Transform("EMBED SW")))
-    Source(init_file)
+    Source(init_file, **swig.guards)
 
 #
 # Handle debug flags
@@ -904,13 +916,16 @@ def makeEnv(label, objsfx, strip = False, **kwargs):
     static_lib = new_env.StaticLibrary(libname, static_objs)
     shared_lib = new_env.SharedLibrary(libname, shared_objs)
 
-    for target, sources in unit_tests:
-        objs = [ make_obj(s, static=True) for s in sources ]
-        new_env.Program("unittest/%s.%s" % (target, label), objs + static_objs)
-
     # Now link a stub with main() and the static library.
     main_objs = [ make_obj(s, True) for s in Source.get(main=True) ]
 
+    for test in UnitTest.all:
+        flags = { test.target : True }
+        test_sources = Source.get(**flags)
+        test_objs = [ make_obj(s, static=True) for s in test_sources ]
+        testname = "unittest/%s.%s" % (test.target, label)
+        new_env.Program(testname, main_objs + test_objs + static_objs)
+
     progname = exename
     if strip:
         progname += '.unstripped'
index 09286dac360ae93415b56be5d5ba7710025d66ca..606bffd05a7c4788ebfdddc4a4a6a2049bcc4671 100644 (file)
@@ -47,8 +47,12 @@ UnitTest('rangetest', 'rangetest.cc')
 UnitTest('rangemaptest', 'rangemaptest.cc')
 UnitTest('rangemultimaptest', 'rangemultimaptest.cc')
 UnitTest('refcnttest', 'refcnttest.cc')
-UnitTest('stattest', 'stattest.cc')
 UnitTest('strnumtest', 'strnumtest.cc')
+
+stattest_py = PySource('m5', 'stattestmain.py', skip_lib=True)
+stattest_swig = SwigSource('m5.internal', 'stattest.i', skip_lib=True)
+UnitTest('stattest', 'stattest.cc', stattest_py, stattest_swig)
+
 UnitTest('symtest', 'symtest.cc')
 UnitTest('tokentest', 'tokentest.cc')
 UnitTest('tracetest', 'tracetest.cc')
index e7654ae5b2c09f0db8833c3615411ecf331bca47..c5e39888d87970b1e1a15b34a7db49273e026fdc 100644 (file)
@@ -32,8 +32,6 @@
 #include <iostream>
 #include <string>
 
-#include "base/stats/mysql.hh"
-#include "base/stats/text.hh"
 #include "base/cprintf.hh"
 #include "base/misc.hh"
 #include "base/statistics.hh"
 #include "sim/core.hh"
 #include "sim/stat_control.hh"
 
+// override the default main() code for this unittest
+const char *m5MainCommands[] = {
+    "import m5.stattestmain",
+    "m5.stattestmain.main()",
+    0 // sentinel is required
+};
+
 using namespace std;
 using namespace Stats;
 
@@ -55,67 +60,8 @@ class TestClass {
     double operator()() { return 9.7; }
 };
 
-const char *progname = "";
-
-void
-usage()
+struct StatTest
 {
-    panic("incorrect usage.\n"
-          "usage:\n"
-          "\t%s [-t [-c] [-d]]\n", progname);
-}
-
-int
-main(int argc, char *argv[])
-{
-    bool descriptions = false;
-    bool text = false;
-
-#if USE_MYSQL
-    string mysql_name;
-    string mysql_db;
-    string mysql_host;
-    string mysql_user = "binkertn";
-    string mysql_passwd;
-#endif
-
-    char c;
-    progname = argv[0];
-    while ((c = getopt(argc, argv, "cD:dh:P:p:s:tu:")) != -1) {
-        switch (c) {
-          case 'd':
-            descriptions = true;
-            break;
-          case 't':
-            text = true;
-            break;
-#if USE_MYSQL
-          case 'D':
-            mysql_db = optarg;
-            break;
-          case 'h':
-            mysql_host = optarg;
-            break;
-          case 'P':
-            mysql_passwd = optarg;
-            break;
-          case 's':
-            mysql_name = optarg;
-            break;
-          case 'u':
-            mysql_user = optarg;
-            break;
-#endif
-          default:
-            usage();
-        }
-    }
-
-    if (!text && descriptions)
-        usage();
-
-    initSimStats();
-
     Scalar s1;
     Scalar s2;
     Average s3;
@@ -153,6 +99,26 @@ main(int argc, char *argv[])
     Formula f4;
     Formula f5;
 
+    void run();
+    void init();
+};
+
+StatTest __stattest;
+void
+stattest_init()
+{
+    __stattest.init();
+}
+
+void
+stattest_run()
+{
+    __stattest.run();
+}
+
+void
+StatTest::init()
+{
     cprintf("sizeof(Scalar) = %d\n", sizeof(Scalar));
     cprintf("sizeof(Vector) = %d\n", sizeof(Vector));
     cprintf("sizeof(Distribution) = %d\n", sizeof(Distribution));
@@ -386,10 +352,11 @@ main(int argc, char *argv[])
     f4 += constant(10.0);
     f4 += s5[3];
     f5 = constant(1);
+}
 
-    enable();
-    reset();
-
+void
+StatTest::run()
+{
     s16[1][0] = 1;
     s16[0][1] = 3;
     s16[0][0] = 2;
@@ -656,23 +623,4 @@ main(int argc, char *argv[])
         h11.sample(i);
         h12.sample(i);
     }
-
-    prepare();
-
-    if (text) {
-        Text out(cout);
-        out.descriptions = descriptions;
-        out();
-    }
-
-#if USE_MYSQL
-    if (!mysql_name.empty()) {
-        MySql out;
-        out.connect(mysql_host, mysql_db, mysql_user, mysql_passwd, "test",
-                    mysql_name, "test");
-        out();
-    }
-#endif
-
-    return 0;
 }
diff --git a/src/unittest/stattest.i b/src/unittest/stattest.i
new file mode 100644 (file)
index 0000000..0cc9192
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2010 The Hewlett-Packard Development Company
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Nathan Binkert
+ */
+
+%module(package="m5.internal") stattest
+
+%inline %{
+extern void stattest_init();
+extern void stattest_run();
+%}
diff --git a/src/unittest/stattestmain.py b/src/unittest/stattestmain.py
new file mode 100644 (file)
index 0000000..2c0a4a9
--- /dev/null
@@ -0,0 +1,19 @@
+def main():
+    from m5.internal.stattest import stattest_init, stattest_run
+    import m5.stats
+
+    stattest_init()
+
+    # Initialize the global statistics
+    m5.stats.initSimStats()
+    m5.stats.initText("cout")
+
+    # We're done registering statistics.  Enable the stats package now.
+    m5.stats.enable()
+
+    # Reset to put the stats in a consistent state.
+    m5.stats.reset()
+
+    stattest_run()
+
+    m5.stats.dump()