/*
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_filenames.cpp
* @brief Tester that tries to feed a lot of possible characters
* as filenames into the makefilelib, make, and the filesystem.
*
* Created on: Jul 16, 2010
* @author Florian Achleitner
*/
#include "char_type.h"
#include "Comment.h"
#include "Variable.h"
#include "VariableDef.h"
#include "VariableRef.h"
#include "MakefileItem.h"
#include "Makefile.h"
#include "AutoVariable.h"
#include "Newline.h"
#include "Rule.h"
#include "Conditional.h"
#include "StringAdapter.h"
#include "test_util.h"
#include
#include
using namespace makefile;
using namespace makefile::tester;
namespace fs = boost::filesystem;
#ifdef USE_WCHAR
ostream& cout = std::wcout;
ostream& cerr = std::wcerr;
#else
ostream& cout = std::cout;
ostream& cerr = std::cerr;
#endif
#define START 0x20
/**
* Prints the tested characters.
* @param out
* @param limit
*/
void printchars(ostream& out, wchar_t limit)
{
char_type c;
for(c = 0x20; c < limit; c++)
{
out << c;
}
}
/**
* Tries to create files with names from 0x20 to limit using boost::filesystem.
* @param dir
* @param limit Upper limit for filenames
* @return Filenames that couldn't be found after creation.
*/
std::vector createfiles_direct(const path dir, uchar_type limit)
{
std::vector miss;
char_type c[] = cstr("X.1");
for(*c = START; static_cast(*c) < limit; (*c)++)
{
path filename(c);
ofstream file(dir / filename);
file.close();
if(!fs::exists(dir / filename))
{
miss.push_back(filename);
}
}
return miss;
}
/**
* Tries to create files with names from 0x20 to limit by calling make.
* It first writes a makefile of this structure:
@verbatim
FILENAME=X.1
all :
@touch $(FILENAME)
@endverbatim
* Afterwards make is called with system() and creates the file by executing touch.
*
* @param dir
* @param limit Upper limit for filenames
* @return Filenames that couldn't be found after creation.
*/
std::vector createfiles_make(const path dir, uchar_type limit)
{
const path makefile(cstr("makefile"));
std::vector miss;
char_type c[] = cstr("X.1");
for(*c = START; static_cast(*c) < limit; (*c)++)
{
path filename(c);
// If the filename cannot be stored in a Variable, theres no chance to bring it through.
try {
makefile::Variable mffilename(cstr("FILENAME"), (dir / filename).string(), makefile::Makefile::SHELL);
makefile::Rule touch;
touch.addTarget(cstr("all"));
touch.addCommand(cstr("@touch ") + mffilename.getRef().toString());
mffilename.getDef().add();
touch.add();
string dirstring = dir.string();
std::stringbuf makeout, makeerr;
int ret = exec_make(makeout, makeerr);
if(ret)
{
std::cerr << "make returned " << ret << std::endl;
std::cout << makeout.str();
std::cerr << makeerr.str();
}
}
catch(std::exception& e) {
std::cerr << "Variable exception: " << e.what() << std::endl;
}
if(!fs::exists(dir / filename))
{
miss.push_back(filename);
}
}
return miss;
}
/**
* Removes and recreates the output directories.
* @param dir
* @return 0 on success, 1 on error.
*/
int cleandir(path dir)
{
if(fs::is_directory(dir))
fs::remove_all(dir);
if(!fs::create_directories(dir))
{
cerr << cstr("Error creating directory ") << dir.string() << std::endl;
return 1;
}
return 0;
}
void printmiss(std::vector::iterator start, std::vector::iterator end)
{
for(std::vector::iterator i = start; i != end; i++)
{
string s = i->string();
unsigned long first = 0;
first = static_cast(s[0]);
cout << s << cstr("\t (0x") << std::hex << first << cstr(")\n");
}
}
int main(int argc, char *argv[])
{
uchar_type limit;
if(argc != 2)
{
std::cerr << "Specify a limit as first argument" << std::endl;
return 1;
}else{
limit = std::atoi(argv[1]);
}
std::cout << "Creating " << static_cast(limit) - START << " files in" << std::endl;
path basepath(fs::initial_path() / cstr("chartest_direct"));
path basepathmake(fs::initial_path() / cstr("chartest_make"));
cout << basepath.string() << std::endl;
cout << basepathmake.string() << std::endl;
if(cleandir(basepath) || cleandir(basepathmake))
return 1;
// ofstream outfile(basepath / cstr("tf.out"));
// printchars(outfile, limit);
std::vector miss_direct = createfiles_direct(basepath, limit);
cout << cstr("Direct: Missing files ") << miss_direct.size() << std::endl;
printmiss(miss_direct.begin(), miss_direct.end());
cout << std::endl;
std::vector miss_make = createfiles_make(basepathmake, limit);
cout << cstr("Make: Missing files ") << miss_make.size() << std::endl;
printmiss(miss_make.begin(), miss_make.end());
cout << std::endl;
return 0;
}