Boost logo

Boost :

From: Chad Maron (cmaron_at_[hidden])
Date: 2007-05-07 14:53:55


Hey everyone,

I'm new to the Boost libraries but *love* everything I've seen so far.

I am having some trouble running my code on OS X. Up until today I've been working in CentOS 4 on an older PIII server. I moved my code over to my Intel Mac workstation so I can use a fancier text editor (yea yea...). I made it through some linkage hurdles with Jam and everything compiled without issue. What happens now is I receive a Bus Error when running my unit tests. I've written a separate test app without using the Boost Unit Test Framework and I am error free.

I would not be surprised if this was the result of my not quite understanding the caveats of the Boost testing framework. I am using boost version 1.33.1 from Darwin Ports.

I understand it might be tricky to provide feedback given I am not including all the source. I am fairly certain the issue I am having is with the testing framework and not my code BUT I will send it along if you want to take a look. It also appears that the test app fails *after* running the test cases:

----------
# echo "SELECT attribute_id from attributes where interface_name = 'Login';" | ./sql_parse_test
Running 2 test cases...

-----1.38998
SELECT attribute_id from attributes where interface_name = 'Login';
SELECT : attributes
Bus error
----------

Even when I pipe millions of SQL statements to the test it will not die until after it's finished. NOTE: The second test case is a function that spits out some timing information (all the timing code is crappy and temporary). Even without the timing output the error takes place after running the proper test cases.

GDB provides this tidbit:
----------
Program received signal EXC_BAD_ACCESS, Could not access memory.
Reason: KERN_PROTECTION_FAILURE at address: 0x00000000
0x00812b22 in boost::unit_test::framework::get ()
----------

Here is my Jamfile (I'm also a Jam newbie):
----------
if $(OS) = MACOSX
{
    C++ = "c++" ;
    C++FLAGS = "-g" ;
    LINK = "c++" ;
    HDRS = /opt/local/include/boost-1_33_1/ ;
    LINKLIBS = -lboost_unit_test_framework -lboost_thread ;
    LINKFLAGS += "-L/opt/local/lib" ;
} else {
    HDRS = /usr/local/include/boost-1_33_1/ ;
    LINKLIBS = -lboost_unit_test_framework-gcc -lboost_thread-gcc-mt ;
}

Main sql_parse_test : SQLParser.cpp SQLDataCollector.cpp GenericSQLGrammar.cpp SQLParserTest.cpp ;
----------

Here is my (broken) test code:
----------
#include <sys/time.h>
#include <unistd.h>
#include <stdio.h>

#include <iostream>
#include <map>
#include <string>

// Boost.Test
#include <boost/test/unit_test.hpp>
#include <boost/test/parameterized_test.hpp>
#include <boost/test/included/unit_test_framework.hpp>

#include "SQLParser.h"

using boost::unit_test::test_suite;

int count = 0;

SQLParser p;

std::map<std::string,int> table_names;
std::map<std::string,int> query_types;

struct timeval tv;
struct timezone tz;

double total_time = 0.0;
double start_time = 0.0;
double end_time = 0.0;
double execute_time = 0.0;
double max_time = 0.0;
double min_time = 1000000.0;

void parse_test(const std::string& q) {
    gettimeofday(&tv, &tz);
    start_time = tv.tv_sec + (tv.tv_usec/1000000.0);

    BOOST_CHECK_MESSAGE(p.parse(q).full, "Statement: " << q);

    gettimeofday(&tv, &tz);
    end_time = tv.tv_sec + (tv.tv_usec/1000000.0);
    execute_time = end_time - start_time;
    if(execute_time > max_time) { max_time = execute_time; };
    if(execute_time < min_time) { min_time = execute_time; };
    total_time += execute_time;
    count++;

    // Output results of parse
    query_types = p.getQueryTypes();
    table_names = p.getTableNames();

    std::cout << "\n-----" << (execute_time*1000.0) << "\n" << q << "\n";
    std::map<std::string,int>::iterator iter;
    for(iter = query_types.begin(); iter != query_types.end(); iter++ ) {
        std::cout << (*iter).first << " ";
    }
    std::cout << ": ";
    for(iter = table_names.begin(); iter != table_names.end(); iter++ ) {
        std::cout << (*iter).first << " ";
    }
    std::cout << std::endl;
}

void weee() {
    std::cout << "\n\ntotal: " << total_time << " count: " << count << " avg(ms): " << ((total_time / count)*1000) << " max(ms): " << (max_time*1000) << " min(ms): " << (min_time*1000) << std::endl;
}

struct sub_test_suite : public test_suite {
    sub_test_suite() {
        while(std::cin) {
            getline(std::cin, input_line);
            if(input_line.size() > 0) {
                queries.push_back(input_line);
            }
        }
        add( BOOST_PARAM_TEST_CASE( &parse_test, queries.begin(), queries.end() ), 0);
    }
    std::string input_line;
    std::vector<std::string> queries;
};

test_suite*
init_unit_test_suite( int, char* [] ) {
    test_suite* test= BOOST_TEST_SUITE( "Spirit SQL parser" );

    test->add(new sub_test_suite);
    test->add(BOOST_TEST_CASE(&weee));

    return test;
}
----------

The working test code is quite similar:
----------
#include <sys/time.h>
#include <unistd.h>
#include <stdio.h>

#include <iostream>
#include <map>
#include <string>

#include "SQLParser.h"

int count = 0;

SQLParser p;

struct timeval tv;
struct timezone tz;

double total_time = 0.0;
double start_time = 0.0;
double end_time = 0.0;
double execute_time = 0.0;
double max_time = 0.0;
double min_time = 1000000.0;

void parse_test(const std::string& q) {

    gettimeofday(&tv, &tz);
    start_time = tv.tv_sec + (tv.tv_usec/1000000.0);

    if(!p.parse(q).full) {
        std::cout << "Parse failed" << std::endl;
    }

    gettimeofday(&tv, &tz);
    end_time = tv.tv_sec + (tv.tv_usec/1000000.0);
    execute_time = end_time - start_time;
    if(execute_time > max_time) { max_time = execute_time; };
    if(execute_time < min_time) { min_time = execute_time; };
    total_time += execute_time;
    count++;

    // Output results of parse
    query_types = p.getQueryTypes();
    table_names = p.getTableNames();

    std::cout << "\n-----" << (execute_time*1000.0) << "\n" << q << "\n";
    std::map<std::string,int>::iterator iter;
    for(iter = query_types.begin(); iter != query_types.end(); iter++ ) {
        std::cout << (*iter).first << " ";
    }
    std::cout << ": ";
    for(iter = table_names.begin(); iter != table_names.end(); iter++ ) {
        std::cout << (*iter).first << " ";
    }
    std::cout << std::endl;
}

int main() {
    std::string input_line;

    while(std::cin) {
        getline(std::cin, input_line);
        if(input_line.size() > 0) {
            parse_test(input_line);
        }
    }

    std::cout << "\n\ntotal: " << total_time << " count: " << count << " avg(ms): " << ((total_time / count)*1000) << " max(ms): " << (max_time*1000) << " min(ms): " << (min_time*1000) << std::endl;
    return 0;
}
----------

Thanks in advance, any feedback would be greatly appreciated.

Chad


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk