/*
This file is part of hugin.
hugin is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
hugin is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with hugin. If not, see .
*/
/**
* @file test_util.cpp
* @brief Useful functions for testers.
* Created on: Jul 27, 2010
* @author Florian Achleitner
*/
#include
#include
#include
#include
#include
#include
#include "Makefile.h"
#include "test_util.h"
#include
#include
#include
using namespace makefile;
namespace fs = boost::filesystem;
namespace io = boost::iostreams;
namespace makefile { namespace tester {
/**
* Executes make with capturing stderr and stdout and feeding the makefile via stdin.
* @param argv as required by execvp (execvp takes a NULL-terminated array of null-terminated strings.) See manpage.
* @param makeoutbuf stdout of make goes here.
* @param makeerrbuf stderr of make goes here.
* @return return value of make. Uses macros to extract the value from wait(). See man wait.
*/
int exec_make(std::stringbuf& makeoutbuf, std::stringbuf& makeerrbuf)
{
// store 2 fd per pipe {read, write}
int fdmakein[2];
int fdmakeout[2];
int fdmakeerr[2];
if(pipe(fdmakein) || pipe(fdmakeout) || pipe(fdmakeerr))
{
std::cerr << "pipe() failed." << std::endl;
return false;
}
if(fork())
{ // parent
close(fdmakein[0]);
close(fdmakeout[1]);
close(fdmakeerr[1]);
// boost gives us a way to use those pipes in C++ style.
// the code_converter allows wchar mode Makefile to be written to a char-pipe
#ifdef USE_WCHAR
io::stream< io::code_converter > makein(fdmakein[1]);
#else
io::stream makein(fdmakein[1]);
#endif
io::stream makeout(fdmakeout[0]);
io::stream makeerr(fdmakeerr[0]);
// Write the makefile to make's stdin
Makefile::getSingleton().writeMakefile(makein);
Makefile::getSingleton().clean();
makein.close();
makeout.get(makeoutbuf, '\0'); // delimiter \0 should read until eof.
makeerr.get(makeerrbuf, '\0');
int status;
wait(&status); // status contains return value an some other flags
if(WIFEXITED(status)) // that can be evaluated by these macros (man wait)
{
return WEXITSTATUS(status);
}
// If WIFEXITED is false, something complicated happened (signal etc..).
std::cerr << "Command terminated abnormally. status=" << std::hex << status << std::endl;
return status;
} else { // child
close(fdmakein[1]);
close(fdmakeout[0]);
close(fdmakeerr[0]);
// replace stdin and stdout
if(dup2(fdmakein[0], 0) == -1 || dup2(fdmakeout[1], 1) == -1 || dup2(fdmakeerr[1], 2) == -1)
{
std::cerr << "Failed to switch std stream" << std::endl;
exit(-1);
}
// execvp takes a NULL-terminated array of null-terminated strings. cool ;)
const char* const argv[] = {"make", "-f-", (char*) NULL};
execvp(argv[0], (char* const*)argv);
return -1; // exec should never return
}
}
bool Test::run()
{
int status = exec_make(makeoutbuf, makeerrbuf);
std::cout << std::setw(30) << std::left << name;
if(eval())
{
std::cout << "PASS" << std::endl;
return true;
}
std::cout << "FAIL" << std::endl;
std::cout << "ret: " << status << std::endl;
std::cout << "out: " << makeoutbuf.str() << std::endl;
std::cout << "cmp: " << goodout << std::endl;
std::cout << "err: " << makeerrbuf.str() << std::endl;
return false;
}
}}