Utils: Document new utilities
g0dil [Wed, 21 May 2008 21:41:58 +0000 (21:41 +0000)]
Console: Implement LinkNode

git-svn-id: https://svn.berlios.de/svnroot/repos/senf/trunk@851 270642c3-0616-0410-b53a-bc976706d245

19 files changed:
Console/Config.cc
Console/Config.test.cc
Console/Executor.cc
Console/Executor.hh
Console/Executor.test.cc
Console/Node.cc
Console/Node.cci
Console/Node.hh
Console/Node.test.cc
Console/ScopedDirectory.cci
Console/ScopedDirectory.hh
Console/Server.cci
Utils/Backtrace.hh
Utils/Mainpage.dox
Utils/Range.cti [copied from Console/Node.ct with 57% similarity]
Utils/Range.hh [moved from Console/Node.ct with 57% similarity]
Utils/String.hh
Utils/auto_unit_test.hh
Utils/preprocessor.hh

index afb365f..3d2200b 100644 (file)
@@ -82,11 +82,8 @@ prefix_ void senf::console::ConfigFile::policyCallback(DirectoryNode::ptr restri
 {
     if (dir.hasChild(name)) {
         GenericNode & item (dir.get(name));
-        if (restrict && ! item.isChildOf(*restrict)) {
-            DirectoryNode * itemdir (dynamic_cast<DirectoryNode*>(&item));
-            if (! itemdir || ! restrict->isChildOf(*itemdir))
-                throw Executor::IgnoreCommandException();
-        }
+        if (restrict && ! item.isChildOf(*restrict) && ! item.isDirectory())
+            throw Executor::IgnoreCommandException();
         if (parsed(item))
             throw Executor::IgnoreCommandException();
     }
index 2215cce..df3383b 100644 (file)
@@ -168,6 +168,40 @@ BOOST_AUTO_UNIT_TEST(configFileSkipGroup)
     }
 }
 
+BOOST_AUTO_UNIT_TEST(configRestrictAndLink)
+{
+    TempFile cfgf ("test.cfg");
+    cfgf << "dir1/fun1 10;\n"
+         << "link1 { dir3 { fun2; } fun1 5; }"
+         << TempFile::close;
+    
+    senf::console::ScopedDirectory<> dir1;
+    senf::console::root().add("dir1", dir1);
+    dir1.add("fun1",&fun1);
+    
+    senf::console::ScopedDirectory<> dir2;
+    dir1.add("dir2", dir2);
+    
+    dir2.mkdir("dir3").add("fun2", &fun2);
+    dir2.add("fun1", &fun1);
+
+    senf::console::ScopedDirectory<> dir4;
+    senf::console::root().add("dir4", dir4);
+    dir4.link("link1", dir2);
+
+    {
+        senf::console::ConfigFile cfg (cfgf.name(), dir4);
+
+        var1 = 0;
+        var2 = false;
+        SENF_CHECK_NO_THROW( cfg.parse(dir2["dir3"]) );
+        BOOST_CHECK_EQUAL( var1, 0 );
+        BOOST_CHECK_EQUAL( var2, true );
+
+        BOOST_CHECK_THROW( cfg.parse(), senf::console::SyntaxErrorException );
+    }
+}
+
 ///////////////////////////////cc.e////////////////////////////////////////
 #undef prefix_
 
index d40f69d..d5f56fb 100644 (file)
 
 // Custom includes
 #include <boost/utility.hpp>
+#include <boost/range/iterator_range.hpp>
+#include <boost/bind.hpp>
 #include "../Utils/senfassert.hh"
+#include "../Utils/Range.hh"
+#include "../Utils/String.hh"
 
 //#include "Executor.mpp"
 #define prefix_
@@ -57,6 +61,18 @@ prefix_ senf::console::DirectoryNode & senf::console::Executor::cwd()
     return * cwd_.back().lock();
 }
 
+prefix_ std::string senf::console::Executor::cwdPath()
+    const
+{
+    if (skipping())
+        return "";
+    return "/" + senf::stringJoin(
+        senf::make_transform_range(
+            boost::make_iterator_range(boost::next(cwd_.begin()), cwd_.end()),
+            boost::bind(&DirectoryNode::name, boost::bind(&DirectoryNode::weak_ptr::lock, _1))),
+        "/" );
+}
+
 prefix_ void senf::console::Executor::execute(std::ostream & output,
                                               ParseCommandInfo const & command)
 {
@@ -122,13 +138,13 @@ prefix_ void senf::console::Executor::execute(std::ostream & output,
         }
     }
     catch (InvalidPathException &) {
-        output << "invalid path" << std::endl;
+        throw SyntaxErrorException("invalid path");
     }
     catch (InvalidDirectoryException &) {
-        output << "invalid directory" << std::endl;
+        throw SyntaxErrorException("invalid directory");
     }
     catch (InvalidCommandException &) {
-        output << "invalid command" << std::endl;
+        throw SyntaxErrorException("invalid command");
     }
     catch (IgnoreCommandException &) {}
 }
index f771e3b..882792a 100644 (file)
@@ -91,7 +91,8 @@ namespace console {
                                         /**< Output will be written to \a output. 
                                              Same as execute(). */
         DirectoryNode & cwd() const;    ///< Current working directory
-        bool skipping() const;
+        std::string cwdPath() const;    ///< Return pathname of current directory
+        bool skipping() const;          ///< \c true, if currently skipping a directory group
 
         bool autocd() const;            ///< Get current autocd status
                                         /**< if autocd is enabled, specifying a directory name as
index 0e751f1..36f9dcf 100644 (file)
@@ -62,7 +62,8 @@ BOOST_AUTO_UNIT_TEST(executor)
         parser.parse("cd dir1", &setCommand);
         executor(os, commands.back());
         BOOST_CHECK_EQUAL( commands.back().builtin(), senf::console::ParseCommandInfo::BuiltinCD );
-        BOOST_CHECK( &executor.cwd() == &senf::console::root()["dir1"] );
+        BOOST_CHECK( executor.cwd() == senf::console::root()["dir1"] );
+        BOOST_CHECK_EQUAL( executor.cwdPath(), "/dir1" );
         BOOST_CHECK_EQUAL( os.str(), "" );
     }
 
@@ -78,10 +79,10 @@ BOOST_AUTO_UNIT_TEST(executor)
     {
         std::stringstream os;
         parser.parse("cd dir1", &setCommand);
-        executor(os, commands.back());
+        BOOST_CHECK_THROW( executor(os, commands.back()), senf::console::SyntaxErrorException );
         BOOST_CHECK_EQUAL( commands.back().builtin(), senf::console::ParseCommandInfo::BuiltinCD );
         BOOST_CHECK( &executor.cwd() == &senf::console::root()["dir2"] );
-        BOOST_CHECK_EQUAL( os.str(), "invalid directory\n" );
+        BOOST_CHECK_EQUAL( os.str(), "" );
     }
 
     {
@@ -112,9 +113,9 @@ BOOST_AUTO_UNIT_TEST(executor)
     {
         std::stringstream os;
         parser.parse("ls dir3", &setCommand);
-        executor(os, commands.back());
+        BOOST_CHECK_THROW( executor(os, commands.back()), senf::console::SyntaxErrorException );
         BOOST_CHECK_EQUAL( commands.back().builtin(), senf::console::ParseCommandInfo::BuiltinLS );
-        BOOST_CHECK_EQUAL( os.str(), "invalid directory\n" );
+        BOOST_CHECK_EQUAL( os.str(), "" );
     }
     
     {
index 3e16667..42086bb 100644 (file)
@@ -89,6 +89,16 @@ prefix_ bool senf::console::GenericNode::isChildOf(DirectoryNode & parent)
 }
 
 ///////////////////////////////////////////////////////////////////////////
+// senf::console::LinkNode
+
+prefix_ void senf::console::LinkNode::v_help(std::ostream & os)
+    const
+{
+    os << "link to ";
+    follow().help(os);
+}
+
+///////////////////////////////////////////////////////////////////////////
 //senf::console::DirectoryNode
 
 prefix_ senf::console::GenericNode::ptr
@@ -127,7 +137,7 @@ prefix_ void senf::console::DirectoryNode::add(GenericNode::ptr node)
 }
 
 prefix_ senf::console::GenericNode &
-senf::console::DirectoryNode::get(std::string const & name)
+senf::console::DirectoryNode::getLink(std::string const & name)
     const
 {
     ChildMap::const_iterator i (children_.find(name));
index 108902a..242881f 100644 (file)
@@ -96,6 +96,45 @@ prefix_ bool senf::console::GenericNode::operator!=(GenericNode & other)
     return this != & other;
 }
 
+prefix_ bool senf::console::GenericNode::isDirectory()
+    const
+{
+    return dynamic_cast<DirectoryNode const *>(this);
+}
+
+prefix_ bool senf::console::GenericNode::isLink()
+    const
+{
+    return dynamic_cast<LinkNode const *>(this);
+}
+
+prefix_ bool senf::console::GenericNode::isCommand()
+    const
+{
+    return dynamic_cast<CommandNode const *>(this);
+}
+
+///////////////////////////////////////////////////////////////////////////
+// senf::console::LinkNode
+
+prefix_ senf::console::LinkNode::ptr senf::console::LinkNode::create(GenericNode & node)
+{
+    GenericNode::ptr p (node.thisptr());
+    while ( p->isLink() )
+        p = dynamic_cast<LinkNode&>(*p).follow().thisptr();
+    return ptr(new LinkNode(*p));
+}
+
+prefix_ senf::console::GenericNode & senf::console::LinkNode::follow()
+    const
+{
+    return *node_;
+}
+
+prefix_ senf::console::LinkNode::LinkNode(GenericNode & node)
+    : node_ (node.thisptr())
+{}
+
 ///////////////////////////////////////////////////////////////////////////
 // senf::console::DirectoryNode
 
@@ -111,6 +150,16 @@ prefix_ bool senf::console::DirectoryNode::hasChild(std::string const & name)
     return i != children_.end();
 }
 
+prefix_ senf::console::GenericNode &
+senf::console::DirectoryNode::get(std::string const & name)
+    const
+{
+    GenericNode & node (getLink(name));
+    return node.isLink()
+        ? dynamic_cast<LinkNode&>(node).follow()
+        : node;
+}
+
 prefix_ senf::console::DirectoryNode &
 senf::console::DirectoryNode::getDirectory(std::string const & name)
     const
@@ -165,6 +214,11 @@ senf::console::DirectoryNode::completions(std::string const & s)
                                       children_.lower_bound(s + "\xff"));
 }
 
+prefix_ void senf::console::DirectoryNode::link(std::string const & name, GenericNode & target)
+{
+    add(name, LinkNode::create(target));
+}
+
 prefix_ senf::console::DirectoryNode::DirectoryNode()
 {}
 
index ca57da1..939113b 100644 (file)
 namespace senf {
 namespace console {
 
+    class LinkNode;
     class DirectoryNode;
     class CommandNode;
 
@@ -288,6 +289,10 @@ namespace console {
         bool operator!= (GenericNode & other) const;
                                         /// \c true, if this and \a other are different nodes
 
+        bool isDirectory() const;       ///< \c true, if this is a drectory node
+        bool isLink() const;            ///< \c true, if this is a link node
+        bool isCommand() const;         ///< \c true, if this is a command node
+
     protected:
         GenericNode();
 
@@ -310,6 +315,47 @@ namespace console {
         friend class DirectoryNode;
     };
 
+    /** \brief Config/console tree link node
+
+        A LinkNode references another node and provides an additional alias name for that node. A
+        LinkNode works like a mixture of UNIX symlinks and hardlinks: It is an explicit link like a
+        UNIX symlink but references another node directly (not via it's path) like a UNIX
+        hardlink. Therefore, a LinkNode works across chroot().
+      */
+    class LinkNode
+        : public GenericNode
+    {
+    public:
+        ///////////////////////////////////////////////////////////////////////////
+        // Types
+
+        typedef boost::shared_ptr<LinkNode> ptr;
+        typedef boost::shared_ptr<LinkNode const> cptr;
+        typedef boost::weak_ptr<LinkNode> weak_ptr;
+
+        ///////////////////////////////////////////////////////////////////////////
+        ///\name Structors and default members
+        ///@{
+        
+        static ptr create(GenericNode & node); ///< Create new link node.
+                                        /**< You should normally use DirectoryNode::link() to
+                                             create a link node. */
+        
+        ///@}
+        ///////////////////////////////////////////////////////////////////////////
+
+        GenericNode & follow() const;   ///< Access the referenced node
+
+    protected:
+
+    private:
+        explicit LinkNode(GenericNode & node);
+
+        virtual void v_help(std::ostream &) const;
+
+        GenericNode::ptr node_;
+    };
+
     class SimpleCommandNode;
 
     /** \brief Internal: Node creation helper traits
@@ -445,6 +491,10 @@ namespace console {
                                         ///< Get child node
                                         /**< \throws UnknownNodeNameException if a child \a name
                                                  does not exist */
+        GenericNode & getLink(std::string const & name) const;
+                                        ///< Get child node without dereferencing links
+                                        /**< \throws UnknownNodeNameException if a child \a name
+                                                 does not exist */
 
         DirectoryNode & getDirectory(std::string const & name) const;
                                         ///< Get directory child node
@@ -488,28 +538,12 @@ namespace console {
                                         ///< Return iterator range of completions for \a s
                                         /**< The returned range is sorted by child name. */
 
+        void link(std::string const & name, GenericNode & target);
+
         ///\}
         ///////////////////////////////////////////////////////////////////////////
 
-        template <class ForwardRange>
-        GenericNode & traverse(ForwardRange const & range, bool autocomplete=false,
-                               DirectoryNode & root = root());
-                                        ///< Traverse node path starting at this node
-                                        /**< The <tt>ForwardRange::value_type</tt> must be
-                                             (convertible to) std::string. Each range element
-                                             constitutes a step along the node traversal.
-
-                                             If the range starts with an empty element, the
-                                             traversal is started at the root() node, otherwise it
-                                             is started at \a this node. The traversal supports '.',
-                                             '..' and ignores further empty elements. 
-
-                                             If \a autocomplete is set to \c true, invalid path
-                                             components which can be uniquely completed will be
-                                             completed automatically while traversing the tree. */
-
-        DirectoryNode & doc(std::string const & doc);
-                                        ///< Set node documentation
+        DirectoryNode & doc(std::string const & doc); ///< Set node documentation
 
         ptr thisptr();
         cptr thisptr() const;
@@ -668,7 +702,7 @@ BOOST_TYPEOF_REGISTER_TYPE(senf::console::SimpleCommandNode)
 
 ///////////////////////////////hh.e////////////////////////////////////////
 #include "Node.cci"
-#include "Node.ct"
+//#include "Node.ct"
 #include "Node.cti"
 #endif
 
index 0e0668d..cab82e3 100644 (file)
@@ -37,7 +37,7 @@
 #define prefix_
 ///////////////////////////////cc.p////////////////////////////////////////
 
-BOOST_AUTO_UNIT_TEST(gnericNode)
+BOOST_AUTO_UNIT_TEST(genericNode)
 {
     senf::console::GenericNode & node (
         senf::console::root().mkdir("dir1").mkdir("dir2").doc("help info"));
@@ -107,19 +107,6 @@ BOOST_AUTO_UNIT_TEST(directoryNode)
         completions, 
         completions+sizeof(completions)/sizeof(completions[0]) );
 
-    char const * const path[] = { "..", "dir2", "dir3" };
-    BOOST_CHECK( &senf::console::root()["dir1"].traverse( boost::make_iterator_range(
-                                                              path, 
-                                                              path+sizeof(path)/sizeof(path[0])) )
-                 == &senf::console::root()["dir2"]["dir3"] );
-
-    char const * const incompletePath[] = { "d" };
-    BOOST_CHECK( &senf::console::root()["dir2"].traverse( boost::make_iterator_range(
-                                                              incompletePath, 
-                                                              incompletePath+sizeof(incompletePath)/sizeof(incompletePath[0])),
-                                                          true )
-                 == &senf::console::root()["dir2"]["dir3"] );
-
     p->doc("test doc");
     std::stringstream ss;
     p->help(ss);
@@ -132,6 +119,17 @@ BOOST_AUTO_UNIT_TEST(directoryNode)
     BOOST_CHECK_EQUAL( senf::console::root().children().size(), 0u );
 }
 
+BOOST_AUTO_UNIT_TEST(linkNode)
+{
+    senf::console::root().mkdir("dir1");
+    senf::console::root().link("link1", senf::console::root()["dir1"]);
+
+    BOOST_CHECK( senf::console::root()["dir1"] == senf::console::root()["link1"] );
+
+    senf::console::root().remove("dir1");
+    senf::console::root().remove("link1");
+}
+
 namespace {
     struct Functor {
         void operator()(std::ostream & os, senf::console::ParseCommandInfo const &) {
index c94e1c0..6f868b7 100644 (file)
@@ -98,6 +98,12 @@ senf::console::ScopedDirectoryBase::mkdir(std::string const & name)
     return node().mkdir(name);
 }
 
+prefix_ void senf::console::ScopedDirectoryBase::link(std::string const & name,
+                                                      GenericNode & target)
+{
+    return node().link(name, target);
+}
+
 prefix_ senf::console::DirectoryNode::ChildrenRange
 senf::console::ScopedDirectoryBase::children()
     const
index 89da74b..04a33ec 100644 (file)
@@ -83,6 +83,7 @@ namespace console {
         CommandNode & operator()(std::string const & name) const;
         GenericNode & get(std::string const & name) const;
         DirectoryNode & mkdir(std::string const & name);
+        void link(std::string const & name, GenericNode & node);
         DirectoryNode::ChildrenRange children() const;
         DirectoryNode & doc(std::string const & doc);
 
index b684439..78387d6 100644 (file)
@@ -139,7 +139,7 @@ prefix_ std::string const & senf::console::Client::name()
 prefix_ std::string senf::console::Client::promptString()
     const
 {
-    return name_ + ":" + executor_.cwd().path() + "$ ";
+    return name_ + ":" + executor_.cwdPath() + "$ ";
 }
 
 prefix_ senf::console::Client & senf::console::Client::get(std::ostream & os)
index 4861a3b..ccc1d97 100644 (file)
 ///////////////////////////////hh.p////////////////////////////////////////
 
 namespace senf {
+    /** \defgroup backtraces Backtrace formatting and parsing
 
+        These functions help format and barse backtrace information as returned by the glibc
+        ::backtrace function.
+     */
+
+    /** \brief Formnat a given backtrace
+
+        This functions will write \a backtrace formatted to \a os. This includes demangling symbol
+        names and interpreting some additional kernel symbols.
+
+        \ingroup backtraces
+     */
     void formatBacktrace(std::ostream & os, void ** backtrace, unsigned numEntries);
+
+    /** \brief Write a backtrace to \a os
+
+        backtrace() will write a backtrace of the current call stack to \a os.
+
+        \ingroup backtraces
+     */
     void backtrace(std::ostream & os, unsigned numEntries);
 
 }
index cc20df8..3c0c53f 100644 (file)
@@ -99,13 +99,27 @@ namespace senf {
     specification</td></tr>
 
     <tr><td>\ref utils_tags</td><td>Miscellaneous type tags</td></tr>
+
+    <tr><td>stringJoin()</td><td>Utility to join a string range into
+    a single string (with separator)</td><?tr>
+    
+    <tr><td>make_transform_range()</td><td>\c boost::make_transform_iterator() with support for
+    ranges</td></tr>
+
+    <tr><td>\ref backtraces</td><td>Utilities to parse and format backtrace information as provided
+    by the GNU libc</td></tr>
     </table>
 
-    \section compatibility Compatibility
+
+    \section testing Correctness and testing
 
     <table class="listing">
     <tr><td>\ref auto_unit_test.hh</td><td>Boost auto unit test compatibility across Boost versions
     1.33 and 1.34</td></tr>
+
+    <tr><td>\ref SENF_ASSERT()</td><td>SENF specific assertion macro</td></tr>
+
+    <tr><td>\ref unittest</td><td>Additional unit test extension for Boost.Test</td></tr>
     </table>
  */
 
similarity index 57%
copy from Console/Node.ct
copy to Utils/Range.cti
index c9516c0..0444e42 100644 (file)
 // 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
 /** \file
-    \brief Node non-inline template implementation  */
+    \brief Range inline template implementation */
 
-#include "Node.ih"
+//#include "Range.ih"
 
 // Custom includes
-#include <boost/range.hpp>
 
-#define prefix_
-///////////////////////////////ct.p////////////////////////////////////////
+#define prefix_ inline
+///////////////////////////////cti.p///////////////////////////////////////
 
-///////////////////////////////////////////////////////////////////////////
-// senf::console::DirectoryNode
-
-template <class ForwardRange>
-prefix_ senf::console::GenericNode &
-senf::console::DirectoryNode::traverse(ForwardRange const & range, bool autocomplete,
-                                       DirectoryNode & root)
+template <class Range, class Fn>
+prefix_ boost::iterator_range< 
+        boost::transform_iterator< Fn,
+                                   typename boost::range_const_iterator<Range>::type > >
+senf::make_transform_range(Range const & range, Fn const & fn)
 {
-    typedef typename boost::range_const_iterator<ForwardRange>::type const_iterator;
-    detail::NodeTraverser traverser (root, *this, autocomplete);
-    const_iterator i (boost::begin(range));
-    const_iterator const i_end (boost::end(range));
-    for (; i != i_end; ++i)
-        traverser( *i );
-    return traverser.node();
+    return boost::make_iterator_range(
+        boost::make_transform_iterator(boost::begin(range), fn),
+        boost::make_transform_iterator(boost::end(range), fn) );
 }
 
-///////////////////////////////ct.e////////////////////////////////////////
+///////////////////////////////cti.e///////////////////////////////////////
 #undef prefix_
 
 \f
similarity index 57%
rename from Console/Node.ct
rename to Utils/Range.hh
index c9516c0..db6d63e 100644 (file)
 // 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
 /** \file
-    \brief Node non-inline template implementation  */
+    \brief Range public header */
 
-#include "Node.ih"
+#ifndef HH_Range_
+#define HH_Range_ 1
 
 // Custom includes
-#include <boost/range.hpp>
-
-#define prefix_
-///////////////////////////////ct.p////////////////////////////////////////
-
-///////////////////////////////////////////////////////////////////////////
-// senf::console::DirectoryNode
-
-template <class ForwardRange>
-prefix_ senf::console::GenericNode &
-senf::console::DirectoryNode::traverse(ForwardRange const & range, bool autocomplete,
-                                       DirectoryNode & root)
-{
-    typedef typename boost::range_const_iterator<ForwardRange>::type const_iterator;
-    detail::NodeTraverser traverser (root, *this, autocomplete);
-    const_iterator i (boost::begin(range));
-    const_iterator const i_end (boost::end(range));
-    for (; i != i_end; ++i)
-        traverser( *i );
-    return traverser.node();
+#include <boost/range/iterator_range.hpp>
+#include <boost/iterator/transform_iterator.hpp>
+
+//#include "Range.mpp"
+///////////////////////////////hh.p////////////////////////////////////////
+
+namespace senf {
+    
+    /** \brief Make a \c boost::iterator_range from \c boost::trasform_iterator
+
+        This helper is like \c boost::make_transform_iterator, however for ranges instead of
+        iterators. 
+     */
+    template <class Range, class Fn>
+    boost::iterator_range< 
+        boost::transform_iterator< Fn,
+                                   typename boost::range_const_iterator<Range>::type > >
+    make_transform_range(Range const & range, Fn const & fn);
+
 }
 
-///////////////////////////////ct.e////////////////////////////////////////
-#undef prefix_
+///////////////////////////////hh.e////////////////////////////////////////
+//#include "Range.cci"
+//#include "Range.ct"
+#include "Range.cti"
+#endif
 
 \f
 // Local Variables:
index 0b8028f..1bdf93e 100644 (file)
 
 namespace senf {
     
+    /** \brief Join string range with separator into single string
+
+        This utility will build string by joining all elements of \a range into a single string
+        using \a sep as separator. The \a range may contain values of any streamable type.
+     */
     template <class ForwardReadableRange>
     std::string stringJoin(ForwardReadableRange const & range, std::string sep);
 
index a126692..b2e60ae 100644 (file)
 
 #include <boost/test/auto_unit_test.hpp>
 
+/** \defgroup unittest Boost.Test extensions
+
+    This module defines some additional extensions to Boost.Test
+ */
+
+/** \brief Check for compile failure
+
+    COMPILE_RAIL() is used to check, that a certain piece of code will produce a compile time
+    failure.
+
+    \code
+    #ifdef COMPILE_CHECK
+
+    COMPILE_FAIL(foo)
+    {
+        // fails to compile ....
+        int x = "foo";
+    }
+    
+    COMPILE_FAIL(bar)
+    { ... }
+
+    #endif
+    \endcode
+
+    This check is performed by the extended unit-test builder in \c senfscons.
+    
+    \ingroup unittest
+ */
 #define COMPILE_FAIL(n) void n()
 
+/** \brief Show exception information
+
+    \ref SENF_CHECK_NO_THROW() is an extension to \c BOOST_CHECK_NO_THROW() which will write out the
+    unabridged exception information when an exception is thrown in addition to signaling an error.
+
+    \ingroup unittest
+ */
 #define SENF_CHECK_NO_THROW(expr)                                                                 \
     BOOST_CHECK_NO_THROW(                                                                         \
         try { (void) expr ; }                                                                     \
index 55a3fa8..0567d78 100644 (file)
@@ -34,7 +34,7 @@
 //#include "preprocessor.mpp"
 ///////////////////////////////hh.p////////////////////////////////////////
 
-/** \defgroup senfpp Preprocessor meta programming macros
+/** \defgroup senfpp Preprocessor meta programming
 
     preprocessor.hh provides some additional helper macros based on the Boost.Preprocessor library.
  */