/*
* simplecpp - A simple and high-fidelity C/C++ preprocessor library
* Copyright (C) 2016-2023 simplecpp team
*/
#include "simplecpp.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#ifndef SIMPLECPP_TEST_SOURCE_DIR
#error "SIMPLECPP_TEST_SOURCE_DIR is not defined."
#endif
#define STRINGIZE_(x) #x
#define STRINGIZE(x) STRINGIZE_(x)
static const std::string testSourceDir = SIMPLECPP_TEST_SOURCE_DIR;
static int numberOfFailedAssertions = 0;
#define ASSERT_EQUALS(expected, actual) (assertEquals((expected), (actual), __LINE__))
#define ASSERT_THROW_EQUALS(stmt, e, expected) do { try { stmt; assertThrowFailed(__LINE__); } catch (const e& ex) { assertEquals((expected), (ex.what()), __LINE__); } } while (false)
static std::string pprint(const std::string &in)
{
std::string ret;
for (std::string::size_type i = 0; i < in.size(); ++i) {
if (in[i] == '\n')
ret += "\\n";
ret += in[i];
}
return ret;
}
static int assertEquals(const std::string &expected, const std::string &actual, int line)
{
if (expected != actual) {
numberOfFailedAssertions++;
std::cerr type);
ASSERT_EQUALS("bad macro syntax. macroname=\" value=1", outputList.cbegin()->msg);
}
static void ifCond()
{
{
const char code[] = "int i;";
std::list ifCond;
ASSERT_EQUALS("int i ;", preprocess(code, &ifCond));
ASSERT_EQUALS(0, ifCond.size());
}
{
const char code[] = "#if 0\n"
"# elif __GNUC__ == 1\n"
"# elif defined(__APPLE__)\n"
"#endif\n";
std::list ifCond;
ASSERT_EQUALS("", preprocess(code, &ifCond));
ASSERT_EQUALS(3, ifCond.size());
auto it = ifCond.cbegin();
ASSERT_EQUALS(0, it->location.fileIndex);
ASSERT_EQUALS(1, it->location.line);
ASSERT_EQUALS(2, it->location.col);
ASSERT_EQUALS("0", it->E);
ASSERT_EQUALS(0, it->result);
++it;
ASSERT_EQUALS(0, it->location.fileIndex);
ASSERT_EQUALS(2, it->location.line);
ASSERT_EQUALS(3, it->location.col);
ASSERT_EQUALS("__GNUC__ == 1", it->E);
ASSERT_EQUALS(0, it->result);
++it;
ASSERT_EQUALS(0, it->location.fileIndex);
ASSERT_EQUALS(3, it->location.line);
ASSERT_EQUALS(4, it->location.col);
ASSERT_EQUALS("0", it->E);
ASSERT_EQUALS(0, it->result);
}
}
static void macroUsage()
{
{
const char code[] = "int i;";
std::list macroUsage;
ASSERT_EQUALS("int i ;", preprocess(code, ¯oUsage));
ASSERT_EQUALS(0, macroUsage.size());
}
{
const char code[] = "#define DEF_1\n"
"#ifdef DEF_1\n"
"#endif\n";
std::list macroUsage;
ASSERT_EQUALS("", preprocess(code, ¯oUsage));
ASSERT_EQUALS(1, macroUsage.size());
auto it = macroUsage.cbegin();
ASSERT_EQUALS("DEF_1", it->macroName);
ASSERT_EQUALS(0, it->macroLocation.fileIndex);
ASSERT_EQUALS(1, it->macroLocation.line);
ASSERT_EQUALS(9, it->macroLocation.col);
ASSERT_EQUALS(true, it->macroValueKnown);
ASSERT_EQUALS(0, it->useLocation.fileIndex);
ASSERT_EQUALS(2, it->useLocation.line);
ASSERT_EQUALS(8, it->useLocation.col);
}
}
static void isAbsolutePath() {
#ifdef _WIN32
ASSERT_EQUALS(true, simplecpp::isAbsolutePath("C:\\foo\\bar"));
ASSERT_EQUALS(true, simplecpp::isAbsolutePath("C:/foo/bar"));
ASSERT_EQUALS(true, simplecpp::isAbsolutePath("\\\\foo\\bar"));
ASSERT_EQUALS(false, simplecpp::isAbsolutePath("foo\\bar"));
ASSERT_EQUALS(false, simplecpp::isAbsolutePath("foo/bar"));
ASSERT_EQUALS(false, simplecpp::isAbsolutePath("foo.cpp"));
ASSERT_EQUALS(false, simplecpp::isAbsolutePath("C:foo.cpp"));
ASSERT_EQUALS(false, simplecpp::isAbsolutePath("C:foo\\bar.cpp"));
ASSERT_EQUALS(false, simplecpp::isAbsolutePath("bar.cpp"));
//ASSERT_EQUALS(true, simplecpp::isAbsolutePath("\\")); // TODO
ASSERT_EQUALS(false, simplecpp::isAbsolutePath("0:\\foo\\bar"));
ASSERT_EQUALS(false, simplecpp::isAbsolutePath("0:/foo/bar"));
ASSERT_EQUALS(false, simplecpp::isAbsolutePath("\\foo\\bar"));
//ASSERT_EQUALS(false, simplecpp::isAbsolutePath("\\\\")); // TODO
//ASSERT_EQUALS(false, simplecpp::isAbsolutePath("//")); // TODO
ASSERT_EQUALS(false, simplecpp::isAbsolutePath("/foo/bar"));
ASSERT_EQUALS(false, simplecpp::isAbsolutePath("/"));
#else
ASSERT_EQUALS(true, simplecpp::isAbsolutePath("/foo/bar"));
ASSERT_EQUALS(true, simplecpp::isAbsolutePath("/"));
ASSERT_EQUALS(true, simplecpp::isAbsolutePath("//host/foo/bar"));
ASSERT_EQUALS(false, simplecpp::isAbsolutePath("foo/bar"));
ASSERT_EQUALS(false, simplecpp::isAbsolutePath("foo.cpp"));
ASSERT_EQUALS(false, simplecpp::isAbsolutePath("C:\\foo\\bar"));
ASSERT_EQUALS(false, simplecpp::isAbsolutePath("C:/foo/bar"));
ASSERT_EQUALS(false, simplecpp::isAbsolutePath("\\\\foo\\bar"));
#endif
}
// crashes detected by fuzzer
static void fuzz_crash()
{
{
const char code[] = "#define n __VA_OPT__(u\n"
"n\n";
(void)preprocess(code, simplecpp::DUI()); // do not crash
}
{ // #346
const char code[] = "#define foo(intp)f##oo(intp\n"
"foo(f##oo(intp))\n";
(void)preprocess(code, simplecpp::DUI()); // do not crash
}
{ // #546
const char code[] = "#if __has_include 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}