Никогда не используйте boost::serialize! Никогда...
Ну нельзя так работать, ну честное слово! Или может быть у них какие колебания в проекте, нехорошие? Не знаю...
Мы используем сериализацию...
"Мыши плакали, кололись, но продолжали есть кактус!.."
Много загадочного и непонятного скрывает в себе мир вообще и мир программирования в частности.
Не запутаться бы.
namespace hidden {
#include "CBigApp.h"
}Если мы этого не сделаем, то оно заинклюдится из сишного файла, который мы хотим заинклюдить к себе. Но для начала мы опишем свою версию класса, и делать это мы будем в cьюте, чтобы изолировать его от взаимозависимостей, ведь у нас как бы появятся свои версии функций. Неизбежны проблемы при линковке тестового приложения. Сьют позволяет изолировать эти манипуляции.BOOST_AUTO_TEST_SUITE(suiteCBiGApp_ImportConfig)
struct CBigApp {
void import_config(const archive &aconfig, const std::string &config_file);
void convert_config(const std::string &config_file, u_int version);
void fix_10_value(const std::string &value &);
void fix_21_value(const std::string &value &);
void fix_22_value(const std::string &value &);
};Это собственно наше тестовое видение класса. Оно еще не окончательное и нам еще придется с ним повозиться. Прототипы мы без искажений скопировали из CBigApp.h. Ну а теперь подтягиваем реализацию.#include "Import.cpp"Может так сложиться, что помимо вышеописанных функций в этом файле реализуются и другие. Тогда и их прототипы необходимо вписать в тестовый класс.
void create_minimal_config(const std::string &)
{ throw logic_error("Не используется"); }Помимо того наверняка будет так, что в этом файле включаются и другие инклюды - все эти включения, в том числе и стандартные необходимо перенести в начало нашего юниттест-файла, чтобы они первый раз включились в глобальном пространстве имен, второй раз они уже не будут включаться.BOOST_AUTO_TEST_CASE(testImport10)
{
CBigApp app;
BOOST_REQUIRE_NO_THROW(app.import_config(cfg10, "config_file-1.0.cfg"));
::unlink("config_file-1.0.cfg");
}Да, я знаю, что использовать файловую систему в юниттестах - плохо... но лучше иметь юниттесты, которые используют файловую систему (базы данных, подключения по сети), чем не иметь никаких. Для успокоения совсети их можно назвать функциональными. :)BOOST_AUTO_TEST_CASE(testImport21)
{
struct inCBigApp : public CBigApp {
virual fix_10_value(const std::string &value &)
{ throw logic_error("Не должен вызываться"); }
} app;
BOOST_REQUIRE_NO_THROW(app.import_config(cfg21, "config_file-2.1.cfg"));
::unlink("config_file-2.1.cfg");
}ostream &. Это позволяет в тестах подсунуть вместо cout что-то другое, например ostringstream. И проверить что же собственно вывелось на консоль после вызова метода.std::cout.exceptions(std::ios::goodbit); std::cout.setstate(std::ios::failbit); std::cout << 1; // ignore... мне совершенно не нравится. Да и для тестов он не очень удобен. Каждый раз глушить и разглушать обратно? Нет, нам нужен объект, наследник ostream, который просто не делает ничего. Сделать так можно. Решение приводить не буду, сошлюсь. Но давайте посмотрим что есть на эту тему в boost. Решение #3, найденное в интернете:
struct null_sink : boost::io::sink {
void write(const char*, std::streamsize) { }
};
typedef boost::io::stream_facade<null_sink> null_ostream;... сейчас не работает. Не скажу точно когда работало, не важно.
Решение #4:
typedef boost::iostreams::stream<boost::iostreams::null_sink> null_ostream;... работает, но для того, чтобы все было гладко, перед использованием надо вызвать
out.open(boost::iostreams::null_sink());, что не совсем удобно.
И последнее...
onullstream описан в файле boost/test/utils/nullstream.hpp.
Одного только не понимаю, почему я не могу создавать его непосредственно при вызове?
int foo(ostream &out); BOOST_CHECK_EQUAL(foo(onullstream()), 1)... возвращает ошибку, о том, что нет метода foo, в который можно было бы передать onullstream... но если создать onullstream заранее, то никаких возражений у компилятора не возникает.
onullstream out; BOOST_CHECK_EQUAL(foo(oot), 1)... Успешно. Что-то я наверное делаю не так? :)
program_options::command_line_parser. Устроен он следующим образом:vector<program_options::option>), обработанных им на данном этапе. Это может быть пустой список, одна или много опций, хотя парсить много опций за раз нет необходимости, там цикл и остатки командной строки обязательно снова пройдут через каждый парсер. Обработка заканчивается после того, как командная строка опустевает.extra_style_parser. Дополниельный парсер стиля - это отдельная функция. Её задачей будет при обнаружении первого неопционального слова, предположительно команды, оставшуюся часть строки без разбора загнать в результат. Cлайды:
vector<program_options::option> stop_on_command (vector<string> &args)
{
vector<program_options::option> result;
const string &tok = args[0];
if (tok[0] != '-') {
BOOST_FOREACH (string &arg, args) {
program_options::option opt;
opt.value.push_back(arg);
result.push_back(opt);
}
args.clear();
}
return result;
}
program_options::command_line_parser parser (argc, argv);
parser.extra_style_parser (stop_on_command);
...
program_options::store(parser.run(), vm);