Home Libraries Author Links

smartptrtest.cpp

This example is a CLI based console C++ program demonstrating the usage and testing the implementation of the SysToMath Aids C++ Library module SmartptrAids: Smart Pointer Aids.

/* ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is the SysToMath C++ Libraries package (LibStmCpp).
 *
 * The Initial Developer of the Original Code is
 * Tom Michaelis, SysToMath.
 * Portions created by the Initial Developer are Copyright (C) 2006-2008
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the MPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the MPL, the GPL or the LGPL.
 *
 * ***** END LICENSE BLOCK ***** */

/******************************************************************************
 *                       First Release 2006-09-24
 ******************************************************************************/


const char *Copyright = "(C) 2006-2008 Tom Michaelis, SysToMath";
const char *Version   = "1.10-r347";

static const char *man [] =
{
"NAME                                                                         ",
"       smartptrtest - test classes and class templates of smartptraids.hpp   ",
"                                                                             ",
"SYNOPSIS                                                                     ",
"       smartptrtest [--load-only] [--type=<test-type>] [--mode=<test-mode>]  ",
"                    [--archive=<archive-type>] [--dir=<directory>]           ",
"       smartptrtest --help [<option-name>...]                                ",
"       smartptrtest --version                                                ",
"                                                                             ",
"DESCRIPTION                                                                  ",
"       The command 'smartptrtest' tests classes and class templates of the   "
"       SysToMath library 'libstmaids' declared in the C++ header file        "
"       'stm/smartptraids.hpp'.                                               ",
"       Unless option --load-only is used, at first boost serialization       "
"       archives of the types configured by option --archive containing       "
"       reference data of test types selected by option --type in the modes   "
"       given by option --mode are created.  Then these archives are loaded   "
"       and their contents are compared with the reference data used to create"
"       the archives.                                                         ",
"       The archive files are stored in the directory supplied by option --dir"
"       and are named 'test-<test-mode>_<test-type>.<archive-type>'.          ",
"       The test protocol is written to standard output.                      "
"                                                                             ",
"OPTIONS                                                                      ",
"       --help                                                                ",
"       -h     If no argument <option-name> follows, print the command man    "
"              page on standard output, else the description of the options   "
"              <option-name> and exit with exit code 2.  The arguments        "
"              <option-name> shall be stated without leading '-' or '--'.     ",
"                                                                             ",
"       --version                                                             ",
"       -V     Print version info on standard output and exit with exit code  "
"              2.                                                             ",
"                                                                             ",
"       --load-only                                                           ",
"       -l                                                                    ",
"              Do not create boost serialization archives before loading them."
"              Assume that the archives to be loaded already exist.           ",
"              By default all archives needed are created before loading them "
"              again.                                                         ",
"                                                                             ",
"       --type=<test-type>                                                    ",
"       -t test-type                                                          ",
"              Test type templates to be handled: <test-type> is one of the   "
"              following arguments:                                           ",
"              'ptr': TestPtr test type template                              ",
"              'set': TestSet test type template,                             ",
"              'all': all of the above test type templates (default).         ",
"                                                                             ",
"       --mode=<test-mode>                                                    ",
"       -m test-mode                                                          ",
"              Test modes to be handled: <test-mode> is one of the following  "
"              arguments:                                                     ",
"              'injective' or 'inj': injective_ptr based test mode,           ",
"              'bijective' or 'bij': bijective_ptr based test mode,           ",
"              'all': all of the above test modes (default).                  ",
"                                                                             ",
"       --archive=<archive-type>                                              ",
"       -a <archive-type>                                                     ",
"              Boost serialization archive types to be handled: <archive-type>"
"              is one of the following arguments:                             ",
"              'txt': text archive type                                       ",
"              'bin': binary archive type,                                    ",
"              'xml': XML archive type,                                       ",
"              'all': all of the above archive types (default).               ",
"                                                                             ",
"       --dir=<directory>                                                     ",
"       -d <directory>                                                        ",
"              Set <directory> as the directory where archive files are       "
"              created and loaded from.  By default this is the current       "
"              directory.                                                     "
};


#include <string>
#include <iostream>
#include <exception>
#include <stdexcept>

#include <stm/smartptraids.hpp>
#include <stm/filesysaids.hpp>
#include <stm/divaids.hpp>
#include <stm/debugaids.hpp>
#include <stm/loggeraids.hpp>
#include <stm/getopts.h>


// Example for stm::injective_ptr showing the definition of a pointer
// variable of an incomplete element type.
struct Xyz;
typedef stm::injective_ptr<Xyz> XyzPtr;     // Xyz needs not be complete here.
XyzPtr ptr1;                                // Xyz needs not be complete here.

bool operator< (const Xyz &e1, const Xyz &e2);

struct Xyz
{
    Xyz (stm::dword id = 0, XyzPtr ptr = XyzPtr ()) :
        id (id),
        ptr (ptr)
    {}

    stm::dword id;
    XyzPtr ptr;
};

XyzPtr ptr2 = Xyz (3);                      // Xyz has to be complete here.
Xyz xyz1 = *ptr2;
Xyz xyz2 (7, ptr1);
const Xyz *p = xyz2.ptr.get ();

bool operator< (const Xyz &e1, const Xyz &e2)
{
    return
        e1.id < e2.id ||
        e1.id == e2.id && e1.ptr < e2.ptr;
}


// Example for stm::injective_set showing the definition of a set
// variable of an incomplete value type.
class Node;
typedef stm::bijective<Node>::set NodeSet;  // Node needs not be complete here.
NodeSet nodes;                              // Node needs not be complete here.

class Slot
{
public:
    Slot (stm::dword disp = 0) :
        disp_ (disp)
    {}

    Slot child (stm::dword index) const
    {
        return children_ [index];
    }

    stm::dword disp (stm::dword index) const
    {
        return children_ [index].disp_;
    }

    bool operator< (const Slot &other) const
    {
        return
            children_.size () <  other.children_.size () ||
            children_.size () == other.children_.size () &&
            disp_ < other.disp_;
    }

private:
    std::vector<Slot> children_;
    stm::dword disp_;
};

class Node
{
public:
    typedef NodeSet::accessor Ptr;

    Node (const Slot &root) :
        index_ (0),
        slot_ (root),
        offset_ (0)
    {}

    Node (Ptr parent, stm::dword index) :
        parent_ (parent),
        index_ (index)
    {
        StmDebugAidsVerify (parent_);
        slot_ = parent_ -> slot ().child (index_);
        offset_ = parent_ -> offset () + parent_ -> slot ().disp (index_);
    }

    const Slot &slot () const
    {
        return slot_;
    }

    stm::dword offset () const
    {
        return offset_;
    }

    bool operator< (const Node &other) const
    {
        return
            offset () <  other.offset () ||
            offset () == other.offset () &&
            slot () < other.slot ();
    }

private:
    Ptr parent_;
    stm::dword index_;
    Slot slot_;
    stm::dword offset_;
};

Slot rootSlot;
Node::Ptr rootNode = nodes.insert (Node (rootSlot));  // Node must be complete here.


// Functional tests.
struct Operation
{
    struct Type
    {
        enum
        {
            Ptr = 0x00000001,
            Set = 0x00000002,
            All = Ptr | Set
        };
    };

    struct Mode
    {
        enum
        {
            Inj = 0x00000001,
            Bij = 0x00000002,
            All = Inj | Bij
        };
    };

    struct Archive
    {
        enum
        {
            Txt = 0x00000001,
            Bin = 0x00000002,
            Xml = 0x00000004,
            All = Txt | Bin | Xml
        };
    };

    Operation () :
        loadOnly (false),
        type (Type::All),
        mode (Mode::All),
        archive (Archive::All),
        dir (boost::filesystem::initial_path ())
    {}

    bool loadOnly;
    stm::dword type;
    stm::dword mode;
    stm::dword archive;
    stm::path<> dir;
};


template <class Policy>
struct TestPtr
{
    typedef typename stm::injective
    <
        stm::dword,
        std::less<stm::dword>,
        std::allocator<stm::dword>,
        Policy
    >::ptr DwordPtr;

    typedef typename stm::injective
    <
        std::string,
        std::less<std::string>,
        std::allocator<std::string>,
        Policy
    >::ptr StrPtr;

    TestPtr () {}

    TestPtr
    (
        stm::dword dw0,
        stm::dword dw1,
        const std::string &str0,
        const std::string &str1
    ) :
        dwptr0 (dw0),
        dwptr1 (dw1),
        strptr0 (str0),
        strptr1 (str1)
    {
        strptr2 = strptr0;
    }

    template <class ArchiveT>
    void save (const std::string &file) const
    {
        std::ofstream ofs (file.c_str ());
        ArchiveT oa (ofs);
        oa << BOOST_SERIALIZATION_NVP (dwptr0);
        oa << BOOST_SERIALIZATION_NVP (dwptr1);
        oa << BOOST_SERIALIZATION_NVP (strptr0);
        oa << BOOST_SERIALIZATION_NVP (strptr1);
        oa << BOOST_SERIALIZATION_NVP (strptr2);
        return;
    }

    template <class ArchiveT>
    void load (const std::string &file)
    {
        std::ifstream ifs (file.c_str ());
        ArchiveT ia (ifs);
        ia >> BOOST_SERIALIZATION_NVP (dwptr0);
        ia >> BOOST_SERIALIZATION_NVP (dwptr1);
        ia >> BOOST_SERIALIZATION_NVP (strptr0);
        ia >> BOOST_SERIALIZATION_NVP (strptr1);
        ia >> BOOST_SERIALIZATION_NVP (strptr2);
        return;
    }

    void tell (const std::string &title) const
    {
        std::cout << title
                  << std::endl;
        if (dwptr0)
        {
            std::cout << "    DwordPtr dwptr0: value = "
                      << *dwptr0
                      << ", addr = "
                      << dwptr0
                      << std::endl;
        }
        if (dwptr1)
        {
            std::cout << "    DwordPtr dwptr1: value = "
                      << *dwptr1
                      << ", addr = "
                      << dwptr1
                      << std::endl;
        }
        if (strptr0)
        {
            std::cout << "    StrPtr strptr0: str = '"
                      << *strptr0
                      << "', len = "
                      << stm::dword (strptr0 -> size ())
                      << ", addr = "
                      << strptr0
                      << std::endl;
        }
        if (strptr1)
        {
            std::cout << "    StrPtr strptr1: str = '"
                      << *strptr1
                      << "', len = "
                      << stm::dword (strptr1 -> size ())
                      << ", addr = "
                      << strptr1
                      << std::endl;
        }
        if (strptr2)
        {
            std::cout << "    StrPtr strptr2: str = '"
                      << *strptr2
                      << "', len = "
                      << stm::dword (strptr2 -> size ())
                      << ", addr = "
                      << strptr2
                      << std::endl;
        }
        const typename DwordPtr::range_type &dwRange = dwptr0.range ();
        StmDebugAidsVerify (dwptr1.range () == dwRange);
        std::cout << "    DwordPtr range: addr = "
                  << stm::hexfmt<const typename DwordPtr::range_type *> (&dwRange)
                  << ", "
                  << stm::dword (dwRange.size ())
                  << (dwRange.size () ?
                          dwRange.size () > 1 ? " entries:" :
                          " entry:" : " entries")
                  << std::endl;
        for (typename DwordPtr::range_type::iterator it = dwRange.begin ();
             it != dwRange.end ();
             ++ it)
        {
            std::cout << "        value = "
                      << *it
                      << ", addr = "
                      << stm::hexfmt<const stm::dword *> (&*it)
                      << std::endl;
        }
        const typename StrPtr::range_type &strRange = strptr0.range ();
        StmDebugAidsVerify (strptr1.range () == strRange);
        StmDebugAidsVerify (strptr2.range () == strRange);
        std::cout << "    StrPtr range: addr = "
                  << stm::hexfmt<const typename StrPtr::range_type *> (&strRange)
                  << ", "
                  << stm::dword (strRange.size ())
                  << (strRange.size () ?
                          strRange.size () > 1 ? " entries:" :
                          " entry:" : " entries")
                  << std::endl;
        for (typename StrPtr::range_type::iterator it = strRange.begin ();
             it != strRange.end ();
             ++ it)
        {
            std::cout << "        value = '"
                      << *it
                      << "', addr = "
                      << stm::hexfmt<const std::string *> (&*it)
                      << std::endl;
        }
        std::cout << std::endl;
        return;
    }

    bool operator== (const TestPtr &other)
    {
        return
            *dwptr0 == *other.dwptr0 &&
            *dwptr1 == *other.dwptr1 &&
            *strptr0 == *other.strptr0 &&
            *strptr1 == *other.strptr1 &&
            *strptr2 == *other.strptr2;
    }

    DwordPtr dwptr0;
    DwordPtr dwptr1;
    StrPtr strptr0;
    StrPtr strptr1;
    StrPtr strptr2;
};


template <class Policy>
void testptr (const Operation &op);


template <class Policy>
struct TestSet
{
    typedef typename stm::injective
    <
        stm::dword,
        std::less<stm::dword>,
        std::allocator<stm::dword>,
        Policy
    >::set DwordSet;

    typedef typename stm::injective
    <
        std::string,
        std::less<std::string>,
        std::allocator<std::string>,
        Policy
    >::set StrSet;

    TestSet () :
        dwset (),
        strset (),
        dwptr0 (dwset.nil ()),
        dwptr1 (dwset.nil ()),
        strptr0 (strset.nil ()),
        strptr1 (strset.nil ())
    {}

    void define
    (
        stm::dword dw0 = 0,
        stm::dword dw1 = 0,
        const std::string &str0 = std::string (),
        const std::string &str1 = std::string ()
    )
    {
        dwptr0 = dwset.insert (dw0);
        dwptr1 = dwset.insert (dw1);
        strptr0 = strset.insert (str0);
        strptr1 = strset.insert (str1);
        long str0count = strptr0.use_count ();
        {
            bool inserted = true;
            typename StrSet::accessor strptr2 = strset.insert (str0, inserted);
            StmDebugAidsVerify (dwptr0 && *dwptr0 == dw0);
            StmDebugAidsVerify (dwptr1 && *dwptr1 == dw1);
            StmDebugAidsVerify (strptr0 && *strptr0 == str0);
            StmDebugAidsVerify (strptr1 && *strptr1 == str1);
            StmDebugAidsVerify (strptr2.get () == strptr0.get () && !inserted);
            StmDebugAidsVerify (!StrSet::accessor::is_surjective () ||
                                strptr0.use_count () == str0count + 1);
        }
        StmDebugAidsVerify (!StrSet::accessor::is_surjective () ||
                            strptr0.use_count () == str0count);
        return;
    }

    template <class ArchiveT>
    void save (const std::string &file) const
    {
        std::ofstream ofs (file.c_str ());
        ArchiveT oa (ofs);
        oa << BOOST_SERIALIZATION_NVP (dwptr0);
        oa << BOOST_SERIALIZATION_NVP (dwptr1);
        oa << BOOST_SERIALIZATION_NVP (strptr0);
        oa << BOOST_SERIALIZATION_NVP (strptr1);
        return;
    }

    template <class ArchiveT>
    void load (const std::string &file)
    {
        std::ifstream ifs (file.c_str ());
        ArchiveT ia (ifs);
        ia >> BOOST_SERIALIZATION_NVP (dwptr0);
        ia >> BOOST_SERIALIZATION_NVP (dwptr1);
        ia >> BOOST_SERIALIZATION_NVP (strptr0);
        ia >> BOOST_SERIALIZATION_NVP (strptr1);
        return;
    }

    void tell (const std::string &title) const
    {
        std::cout << title
                  << std::endl;
        if (strptr0)
        {
            typename StrSet::accessor strptr2 = strset.find (*strptr0);
            StmDebugAidsVerify (strptr2);
            StmDebugAidsVerify (*strptr2 == *strptr0);
        }
        if (dwptr0)
        {
            std::cout << "    DwordSet::accessor dwptr0: value = "
                      << *dwptr0
                      << ", addr = "
                      << stm::hexfmt<const stm::dword *> (dwptr0.get ())
                      << std::endl;
        }
        if (dwptr1)
        {
            std::cout << "    DwordSet::accessor dwptr1: value = "
                      << *dwptr1
                      << ", addr = "
                      << stm::hexfmt<const stm::dword *> (dwptr1.get ())
                      << std::endl;
        }
        if (strptr0)
        {
            std::cout << "    StrSet::accessor strptr0: str = '"
                      << *strptr0
                      << "', len = "
                      << stm::dword (strptr0 -> size ())
                      << ", addr = "
                      << stm::hexfmt<const std::string *> (strptr0.get ())
                      << std::endl;
        }
        if (strptr1)
        {
            std::cout << "    StrSet::accessor strptr1: str = '"
                      << *strptr1
                      << "', len = "
                      << stm::dword (strptr1 -> size ())
                      << ", addr = "
                      << stm::hexfmt<const std::string *> (strptr1.get ())
                      << std::endl;
        }
        std::cout << "    dwset: addr = "
                  << stm::hexfmt<const DwordSet *> (&dwset)
                  << ", "
                  << stm::dword (dwset.size ())
                  << (dwset.size () ? dwset.size () > 1 ? " entries:" : " entry:" : " entries")
                  << std::endl;
        for (typename DwordSet::range_type::iterator it = dwset.begin ();
             it != dwset.end ();
             ++ it)
        {
            std::cout << "        value = "
                      << *it
                      << ", addr = "
                      << stm::hexfmt<const stm::dword *> (&*it)
                      << std::endl;
        }
        std::cout << "    strset: addr = "
                  << stm::hexfmt<const StrSet *> (&strset)
                  << ", "
                  << stm::dword (strset.size ())
                  << (strset.size () ? strset.size () > 1 ? " entries:" : " entry:" : " entries")
                  << std::endl;
        for (typename StrSet::range_type::iterator it = strset.begin ();
             it != strset.end ();
             ++ it)
        {
            std::cout << "        value = '"
                      << *it
                      << "', addr = "
                      << stm::hexfmt<const std::string *> (&*it)
                      << std::endl;
        }
        std::cout << std::endl;
        return;
    }

    bool operator== (const TestSet &other)
    {
        return
            dwptr0 == other.dwptr0 &&
            dwptr1 == other.dwptr1 &&
            strptr0 == other.strptr0 &&
            strptr1 == other.strptr1;
    }

    DwordSet dwset;
    StrSet strset;
    typename DwordSet::accessor dwptr0;
    typename DwordSet::accessor dwptr1;
    typename StrSet::accessor strptr0;
    typename StrSet::accessor strptr1;
};


template <class Policy>
void testset (const Operation &op);


int main (int argc, char *argv [])
{
    int ret = 0;
    typedef stm::logger<> Logger;
    Logger logger;
    logger.setConsole ();

    // Prepare the command line.
    const StmCmdOptSpec optSpec [] =
    {
        {StmId (h), "h\0help\0", StmCmdOptSpecOnlyOption},
        {StmId (V), "V\0version\0", StmCmdOptSpecOnlyOption},
        {StmId (l), "l\0load-only\0"},
        {StmId (t), "t\0type\0", StmCmdOptSpecRequiresArg},
        {StmId (m), "m\0mode\0", StmCmdOptSpecRequiresArg},
        {StmId (a), "a\0archive\0", StmCmdOptSpecRequiresArg},
        {StmId (t), "d\0dir\0", StmCmdOptSpecRequiresArg},
        {0, NULL}
    };
    StmCmdLine cmdLine = stmCmdLineCreate (argc, const_cast<const char **> (argv), optSpec);
    const char *prog = stmCmdLineGetProg (cmdLine);

    try
    {
        //  Initialize boost::filesystem::path.
        boost::filesystem::initial_path ();
        boost::filesystem::path::default_name_check (boost::filesystem::native);

        // Evaluate command line options.
        StmDword optId;
        bool printHelp = false;
        bool printVersion = false;
        Operation op;
        for (optId = stmCmdLineGetFirstOptionId (cmdLine);
             optId;
             optId = stmCmdLineGetNextOptionId (cmdLine))
        {
            if (optId == StmId (h))
            {
                printHelp = true;
                continue;
            }
            if (optId == StmId (V))
            {
                printVersion = true;
                continue;
            }
            if (optId == StmId (l))
            {
                op.loadOnly = true;
                continue;
            }
            if (optId == StmId (t))
            {
                const char *optarg = stmCmdLineGetCurrentOptionArg (cmdLine);
                StmDebugAidsVerify (optarg);
                if (!strcmp (optarg, "ptr"))
                {
                    op.type = Operation::Type::Ptr;
                }
                else if (!strcmp (optarg, "set"))
                {
                    op.type = Operation::Type::Set;
                }
                else if (!strcmp (optarg, "all"))
                {
                    op.type = Operation::Type::All;
                }
                else
                {
                    if (stmCmdLinePrintfErrbuf
                        (
                            cmdLine,
                            "%s: option %s: "
                            "'%s' designates no legal test type: aborted.\n",
                            prog,
                            stmCmdLineGetCurrentOptionName (cmdLine),
                            optarg
                        ) < 0)
                    {
                        throw std::runtime_error
                        (
                            StmDebugAidsErrmsg ("stmCmdLinePrintfErrbuf failed")
                        );
                    }
                    stmCmdLineSetOpterr (cmdLine, StmCmdLineOptionArgError);
                }
                continue;
            }
            if (optId == StmId (m))
            {
                const char *optarg = stmCmdLineGetCurrentOptionArg (cmdLine);
                StmDebugAidsVerify (optarg);
                if (!strcmp (optarg, "inj") || !strcmp (optarg, "injective"))
                {
                    op.mode = Operation::Mode::Inj;
                }
                if (!strcmp (optarg, "bij") || !strcmp (optarg, "bijective"))
                {
                    op.mode = Operation::Mode::Bij;
                }
                else if (!strcmp (optarg, "all"))
                {
                    op.mode = Operation::Mode::All;
                }
                else
                {
                    if (stmCmdLinePrintfErrbuf
                        (
                            cmdLine,
                            "%s: option %s: "
                            "'%s' designates no legal test type: aborted.\n",
                            prog,
                            stmCmdLineGetCurrentOptionName (cmdLine),
                            optarg
                        ) < 0)
                    {
                        throw std::runtime_error
                        (
                            StmDebugAidsErrmsg ("stmCmdLinePrintfErrbuf failed")
                        );
                    }
                    stmCmdLineSetOpterr (cmdLine, StmCmdLineOptionArgError);
                }
                continue;
            }
            if (optId == StmId (a))
            {
                const char *optarg = stmCmdLineGetCurrentOptionArg (cmdLine);
                StmDebugAidsVerify (optarg);
                if (!strcmp (optarg, "txt"))
                {
                    op.archive = Operation::Archive::Txt;
                }
                else if (!strcmp (optarg, "bin"))
                {
                    op.archive = Operation::Archive::Bin;
                }
                else if (!strcmp (optarg, "xml"))
                {
                    op.archive = Operation::Archive::Xml;
                }
                else if (!strcmp (optarg, "all"))
                {
                    op.archive = Operation::Archive::All;
                }
                else
                {
                    if (stmCmdLinePrintfErrbuf
                        (
                            cmdLine,
                            "%s: option %s: "
                            "'%s' designates no legal archive type: aborted.\n",
                            prog,
                            stmCmdLineGetCurrentOptionName (cmdLine),
                            optarg
                        ) < 0)
                    {
                        throw std::runtime_error
                        (
                            StmDebugAidsErrmsg ("stmCmdLinePrintfErrbuf failed")
                        );
                    }
                    stmCmdLineSetOpterr (cmdLine, StmCmdLineOptionArgError);
                }
                continue;
            }
            if (optId == StmId (d))
            {
                const char *optarg = stmCmdLineGetCurrentOptionArg (cmdLine);
                StmDebugAidsVerify (optarg);
                op.dir = optarg;
                if (!boost::filesystem::exists (op.dir) ||
                    !boost::filesystem::is_directory (op.dir))
                {
                    if (stmCmdLinePrintfErrbuf
                        (
                            cmdLine,
                            "%s: option %s: "
                            "'%s' designates no accessible directory: aborted.\n",
                            prog,
                            stmCmdLineGetCurrentOptionName (cmdLine),
                            optarg
                        ) < 0)
                    {
                        throw std::runtime_error
                        (
                            StmDebugAidsErrmsg ("stmCmdLinePrintfErrbuf failed")
                        );
                    }
                    stmCmdLineSetOpterr (cmdLine, StmCmdLineOptionArgError);
                }
                continue;
            }
        }

        // Exit on option error.
        if (stmCmdLineGetOpterr (cmdLine))
        {
            std::string what (stmCmdLineGetErrbuf (cmdLine));
            if (what.find (prog))
            {
                what = std::string (prog) + ": " + what;
            }
            Logger elogger (std::cerr);
            elogger << what << std::endl;
            elogger (Logger::AutoInd | Logger::NoPara);
            stmPrintSynopsis (stderr, 79, StmElements (man), man);
            return 1;
        }

        // Handle help option.
        if (printHelp)
        {
            FILE *pp;
            ret = 2;
            if (! (pp = popen ("more", "w")))
            {
                throw std::runtime_error
                (
                    StmDebugAidsErrmsg ("popen failed")
                );
            }
            if (stmCmdLineGetCurrentArgIndex (cmdLine) ==
                stmCmdLineGetArgCount (cmdLine))
            {
                ret =
                    stmPrintManual
                    (
                        pp,
                        79,
                        Version,
                        Copyright,
                        StmElements (man),
                        man
                    ) < 0 ?
                        1 :  // Error.
                        2;   // Success.
            }
            else
            {
                if ((ret = stmPrintManualHeader
                        (
                            pp,
                            79,
                            Version,
                            StmElements (man),
                            man
                        )) >= 0 &&
                    (ret = stmPrintSynopsis
                        (
                            pp,
                            79,
                            StmElements (man),
                            man
                        )) >= 0)
                {
                    bool first = true;
                    for (size_t i = stmCmdLineGetCurrentArgIndex (cmdLine);
                            i < stmCmdLineGetArgCount (cmdLine);
                            ++ i)
                    {
                        fprintf (pp, "\n");
                        if (first)
                        {
                            fprintf (pp, "OPTIONS HELP\n");
                            first = false;
                        }
                        if ((ret = stmPrintOptionHelp
                                (
                                    pp,
                                    79,
                                    stmCmdLineGetArg (cmdLine, i),
                                    StmElements (man),
                                    man
                                )) < 0)
                        {
                            break;
                        }
                    }
                }
                ret =
                    ret < 0 ||
                    (ret = stmPrintManualFooter
                        (
                            pp,
                            79,
                            ret,
                            Copyright
                        )) < 0 ?
                        1 :  // Error.
                        2;   // Success.
            }
            if (pclose (pp))
            {
                throw std::runtime_error
                (
                    StmDebugAidsErrmsg ("pclose failed")
                );
            }
            return ret;
        }

        // Handle print version
        if (printVersion)
        {
            std::cout << Version << std::endl;
            return 2;
        }

        if (stmCmdLineGetArgCount (cmdLine) -
            stmCmdLineGetCurrentArgIndex (cmdLine) != 0)
        {
            if (stmCmdLinePrintfErrbuf
                (
                    cmdLine,
                    "%s: for now no arguments are allowed: aborted",
                    prog
                ) < 0)
            {
                throw std::runtime_error
                (
                    StmDebugAidsErrmsg ("stmCmdLinePrintfErrbuf failed")
                );
            }
            stmCmdLineSetOpterr (cmdLine, StmCmdLineOptionArgError);
        }

        // Exit on error.
        if (stmCmdLineGetOpterr (cmdLine))
        {
            std::string what (stmCmdLineGetErrbuf (cmdLine));
            if (what.find (prog))
            {
                what = std::string (prog) + ": " + what;
            }
            Logger elogger (std::cerr);
            elogger << what << std::endl;
            elogger (Logger::AutoInd | Logger::NoPara);
            stmPrintSynopsis (stderr, 79, StmElements (man), man);
            return 1;
        }

        // Do the command operation.
        if (op.type & Operation::Type::Ptr)
        {
            if (op.mode & Operation::Mode::Inj)
            {
                testptr<stm::smartptr::policy<> > (op);
            }
            if (op.mode & Operation::Mode::Bij)
            {
                testptr<stm::smartptr::policy<stm::smartptr::Surjective> > (op);
            }
        }
        if (op.type & Operation::Type::Set)
        {
            if (op.mode & Operation::Mode::Inj)
            {
                testset<stm::smartptr::policy<> > (op);
            }
            if (op.mode & Operation::Mode::Bij)
            {
                testset<stm::smartptr::policy<stm::smartptr::Surjective> > (op);
            }
        }
    }
    catch (std::exception &exc)
    {
        ret = 1;
        std::string what (exc.what ());
        if (what.empty ()) what = "Unspecified error";
        else if (what [what.size () - 1] == '.') what.erase (what.size () - 1);
        logger.paragraph ();
        logger << "  - " << what << ": " << prog << " aborted.\n";
        logger (Logger::Indent | Logger::NoPara);
    }
    catch (...)
    {
        ret = 1;
        logger.paragraph ();
        logger << "  - Unknown error: " << prog << " aborted.\n";
        logger (Logger::Indent | Logger::NoPara);
    }
    stmCmdLineDestroy (cmdLine);
    return ret;
}


template <class Policy>
void testptr (const Operation &op)
{
    TestPtr<Policy> test, tref (87654321, 12345678, "zzz", "yyy");

    std::string type = Policy::surjective::value ? "bijective_ptr" : "injective_ptr";
    stm::path<> astub = op.dir / ("test-" + type);
    std::string title = "Testing type " + type;
    if (op.loadOnly)
    {
        title += " (loadonly)";
    }
    else
    {
        const TestPtr<Policy> &t = tref;
        if (op.archive & Operation::Archive::Txt)
        {
            t.template save<boost::archive::text_oarchive> (astub.string () + ".txt");
        }
        if (op.archive & Operation::Archive::Bin)
        {
            t.template save<boost::archive::binary_oarchive> (astub.string () + ".bin");
        }
        if (op.archive & Operation::Archive::Xml)
        {
            t.template save<boost::archive::xml_oarchive> (astub.string () + ".xml");
        }
    }
    std::cout << title + "\n" + std::string (title.size (), '=') + "\n\n";

    test.tell ("Test item (initially empty)");
    tref.tell ("Reference item");

    if (op.archive & Operation::Archive::Txt)
    {
        test.template load<boost::archive::text_iarchive> (astub.string () + ".txt");
        test.tell ("Test item (loaded from text archive)");
        StmDebugAidsVerify (test == tref);
    }

    if (op.archive & Operation::Archive::Bin)
    {
        test.template load<boost::archive::binary_iarchive> (astub.string () + ".bin");
        test.tell ("Test item (loaded from binary archive)");
        StmDebugAidsVerify (test == tref);
    }

    if (op.archive & Operation::Archive::Xml)
    {
        test.template load<boost::archive::xml_iarchive> (astub.string () + ".xml");
        test.tell ("Test item (loaded from XML archive)");
        StmDebugAidsVerify (test == tref);
    }

    std::cout << std::endl;
    return;
}

template <class Policy>
void testset (const Operation &op)
{
    TestSet<Policy> test, tref;
    tref.define (87654321, 12345678, "zzz", "yyy");

    std::string type = Policy::surjective::value ? "bijective_set" : "injective_set";
    stm::path<> astub = op.dir / ("test-" + type);
    std::string title = "Testing type " + type;
    if (op.loadOnly)
    {
        title += " (loadonly)";
    }
    else
    {
        test.define (*tref.dwptr0, *tref.dwptr1, *tref.strptr0, *tref.strptr1);
        const TestSet<Policy> &t = test;
        if (op.archive & Operation::Archive::Txt)
        {
            t.template save<boost::archive::text_oarchive> (astub.string () + ".txt");
        }
        if (op.archive & Operation::Archive::Bin)
        {
            t.template save<boost::archive::binary_oarchive> (astub.string () + ".bin");
        }
        if (op.archive & Operation::Archive::Xml)
        {
            t.template save<boost::archive::xml_oarchive> (astub.string () + ".xml");
        }
        test.define ();
    }
    std::cout << title + "\n" + std::string (title.size (), '=') + "\n\n";

    test.tell ("Test item (initially empty)");
    tref.tell ("Reference item");

    if (op.archive & Operation::Archive::Txt)
    {
        test.template load<boost::archive::text_iarchive> (astub.string () + ".txt");
        test.tell ("Test item (loaded from text archive)");
        StmDebugAidsVerify (test == tref);
    }

    if (op.archive & Operation::Archive::Bin)
    {
        test.template load<boost::archive::binary_iarchive> (astub.string () + ".bin");
        test.tell ("Test item (loaded from binary archive)");
        StmDebugAidsVerify (test == tref);
    }

    if (op.archive & Operation::Archive::Xml)
    {
        test.template load<boost::archive::xml_iarchive> (astub.string () + ".xml");
        test.tell ("Test item (loaded from XML archive)");
        StmDebugAidsVerify (test == tref);
    }

    std::cout << std::endl;
    return;
}

© Copyright Tom Michaelis 2002-2007

Distributed under the SysToMath Software License (See the accompanying file license.txt or a copy at www.SysToMath.com).