aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordec05eba <dec05eba@protonmail.com>2018-01-03 21:17:49 +0100
committerdec05eba <dec05eba@protonmail.com>2018-01-03 21:42:51 +0100
commit8b052110d8802eda3d4d76700bde8ecc80dbf79a (patch)
tree13d9248067ba61c159e61f6083e090b26916c22f
parent469a67628f3eb18236ee44e948d1ae0f0e6b1a4a (diff)
Add "sibs test" command. Tests are only run when that command is invoked
-rw-r--r--backend/ninja/Ninja.cpp9
-rw-r--r--include/Conf.hpp22
-rw-r--r--src/Conf.cpp8
-rw-r--r--src/GlobalLib.cpp2
-rw-r--r--src/main.cpp208
-rw-r--r--tests/src/confTest/confTest.cpp8
6 files changed, 169 insertions, 88 deletions
diff --git a/backend/ninja/Ninja.cpp b/backend/ninja/Ninja.cpp
index a5fdb0d..04669f7 100644
--- a/backend/ninja/Ninja.cpp
+++ b/backend/ninja/Ninja.cpp
@@ -814,7 +814,7 @@ namespace backend
Result<bool> Ninja::buildTests(const std::string &projectGeneratedBinary, const SibsConfig &config, const _tinydir_char_t *savePath)
{
- if(testSourceDirs.empty())
+ if(testSourceDirs.empty() || !config.shouldBuildTests())
return Result<bool>::Ok(true);
// Tests need parent project as dependency. Executables can't be included as dependency so we build it as dynamic library.
@@ -888,6 +888,13 @@ namespace backend
Result<bool> buildResult = ninja.compile(buildPath.c_str());
if (!buildResult)
return buildResult;
+
+ FileString testExecutableName = buildPath;
+ testExecutableName += TINYDIR_STRING("/");
+ testExecutableName += toFileString(sibsTestConfig.getPackageName());
+ Result<ExecResult> runTestResult = exec(testExecutableName.c_str(), true);
+ if(!runTestResult)
+ return Result<bool>::Err(runTestResult);
}
}
diff --git a/include/Conf.hpp b/include/Conf.hpp
index 476e38b..de63eae 100644
--- a/include/Conf.hpp
+++ b/include/Conf.hpp
@@ -169,13 +169,14 @@ namespace sibs
class SibsConfig : public ConfigCallback
{
public:
- SibsConfig(Compiler _compiler, const FileString &_projectPath, OptimizationLevel _optimizationLevel = OPT_LEV_DEBUG) :
+ SibsConfig(Compiler _compiler, const FileString &_projectPath, OptimizationLevel _optimizationLevel, bool _buildTests) :
compiler(_compiler),
projectPath(_projectPath),
packageType((PackageType)-1),
optimizationLevel(_optimizationLevel),
finishedProcessing(false),
- useCmake(false)
+ useCmake(false),
+ buildTests(_buildTests)
{
cmakeDirGlobal = projectPath;
cmakeDirStatic = cmakeDirGlobal;
@@ -214,6 +215,11 @@ namespace sibs
{
return testPath;
}
+
+ void setTestPath(const FileString &testPath)
+ {
+ this->testPath = testPath;
+ }
virtual const std::vector<Dependency>& getDependencies() const
{
@@ -267,12 +273,12 @@ namespace sibs
const FileString& getCmakeDirStatic() const
{
- return cmakeDirStatic;
+ return !cmakeDirStatic.empty() ? cmakeDirStatic : cmakeDirGlobal;
}
const FileString& getCmakeDirDynamic() const
{
- return cmakeDirDynamic;
+ return !cmakeDirDynamic.empty() ? cmakeDirDynamic : cmakeDirGlobal;
}
// Get cmake args for all builds. This is args under [cmake] only
@@ -308,6 +314,11 @@ namespace sibs
return useCmake;
}
+ bool shouldBuildTests() const
+ {
+ return buildTests;
+ }
+
void setPackageType(PackageType packageType)
{
this->packageType = packageType;
@@ -351,13 +362,14 @@ namespace sibs
std::string cmakeArgsStatic;
std::string cmakeArgsDynamic;
bool useCmake;
+ bool buildTests;
bool finishedProcessing;
};
class SibsTestConfig : public SibsConfig
{
public:
- SibsTestConfig(Compiler _compiler, const FileString &_projectPath, OptimizationLevel _optimizationLevel) : SibsConfig(_compiler, _projectPath, _optimizationLevel)
+ SibsTestConfig(Compiler _compiler, const FileString &_projectPath, OptimizationLevel _optimizationLevel) : SibsConfig(_compiler, _projectPath, _optimizationLevel, true)
{
packageName = "test";
}
diff --git a/src/Conf.cpp b/src/Conf.cpp
index 1697d9f..0bbbf7b 100644
--- a/src/Conf.cpp
+++ b/src/Conf.cpp
@@ -867,24 +867,24 @@ namespace sibs
if(useCmake)
{
- switch(getPackageType())
+ switch(packageType)
{
case PackageType::EXECUTABLE:
{
- if(!getCmakeDir().empty())
+ if(getCmakeDir().empty())
throw ParserException("Missing required config cmake.dir");
break;
}
case PackageType::STATIC:
{
- if(!getCmakeDirStatic().empty())
+ if(getCmakeDirStatic().empty())
throw ParserException("Missing required config cmake.static");
break;
}
case PackageType::DYNAMIC:
case PackageType::LIBRARY:
{
- if(!getCmakeDirDynamic().empty())
+ if(getCmakeDirDynamic().empty())
throw ParserException("Missing required config cmake.dynamic");
break;
}
diff --git a/src/GlobalLib.cpp b/src/GlobalLib.cpp
index 9083354..d3131a1 100644
--- a/src/GlobalLib.cpp
+++ b/src/GlobalLib.cpp
@@ -123,7 +123,7 @@ namespace sibs
}
}
- SibsConfig sibsConfig(parentConfig.getCompiler(), packageDir, parentConfig.getOptimizationLevel());
+ SibsConfig sibsConfig(parentConfig.getCompiler(), packageDir, parentConfig.getOptimizationLevel(), false);
Result<bool> result = Config::readFromFile(projectConfFilePath.c_str(), sibsConfig);
if (result.isErr())
return result;
diff --git a/src/main.cpp b/src/main.cpp
index e2df0fe..f16bf64 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -56,6 +56,7 @@ void usage()
printf("Commands:\n");
printf(" build\t\tBuild a project that contains a project.conf file\n");
printf(" new\t\tCreate a new project\n");
+ printf(" test\t\tBuild and run tests for a sibs project\n");
exit(1);
}
@@ -88,6 +89,18 @@ void usageNew()
exit(1);
}
+void usageTest()
+{
+ printf("Usage: sibs test [project_path]\n\n");
+ printf("Build and run tests for a sibs project\n\n");
+ printf("Options:\n");
+ printf(" project_path\t\t The directory containing a project.conf file - Optional (default: current working directory)\n");
+ printf("Examples:\n");
+ printf(" sibs test\n");
+ printf(" sibs test dirA/dirB\n");
+ exit(1);
+}
+
void validateDirectoryPath(const _tinydir_char_t *projectPath)
{
FileType projectPathFileType = getFileType(projectPath);
@@ -142,78 +155,8 @@ bool isPathSubPathOf(const FileString &path, const FileString &subPathOf)
return _tinydir_strncmp(path.c_str(), subPathOf.c_str(), subPathOf.size()) == 0;
}
-int buildProject(int argc, const _tinydir_char_t **argv)
+int buildProject(const FileString &projectPath, const FileString &projectConfFilePath, const SibsConfig &sibsConfig)
{
- if(argc > 2)
- usageBuild();
-
- OptimizationLevel optimizationLevel = OPT_LEV_NONE;
- FileString projectPath;
-
- for(int i = 0; i < argc; ++i)
- {
- const _tinydir_char_t *arg = argv[i];
- if(_tinydir_strcmp(arg, TINYDIR_STRING("--debug")) == 0)
- {
- if(optimizationLevel != OPT_LEV_NONE)
- {
- ferr << "Error: Optimization level defined more than once. First defined as " << asString(optimizationLevel) << " then as debug" << endl;
- usageBuild();
- }
- optimizationLevel = OPT_LEV_DEBUG;
- }
- else if(_tinydir_strcmp(arg, TINYDIR_STRING("--release")) == 0)
- {
- if(optimizationLevel != OPT_LEV_NONE)
- {
- ferr << "Error: Optimization level defined more than once. First defined as " << asString(optimizationLevel) << " then as release" << endl;
- usageBuild();
- }
- optimizationLevel = OPT_LEV_RELEASE;
- }
- else
- {
- if(!projectPath.empty())
- {
- ferr << "Error: Project path was defined more than once. First defined as " << projectPath << " then as " << arg << endl;
- usageBuild();
- }
- projectPath = arg;
- }
- }
-
- if(optimizationLevel == OPT_LEV_NONE)
- optimizationLevel = OPT_LEV_DEBUG;
-
- // TODO: If projectPath is not defined and working directory does not contain project.conf, then search every parent directory until one is found
- if(projectPath.empty())
- projectPath = TINYDIR_STRING(".");
-
- validateDirectoryPath(projectPath.c_str());
- if(projectPath.back() != '/')
- projectPath += TINYDIR_STRING("/");
-
- Result<FileString> projectRealPathResult = getRealPath(projectPath.c_str());
- if(!projectRealPathResult)
- {
- ferr << "Failed to get real path for: '" << projectPath.c_str() << "': " << toFileString(projectRealPathResult.getErrMsg()) << endl;
- exit(40);
- }
- projectPath = projectRealPathResult.unwrap();
-
- FileString projectConfFilePath = projectPath;
- projectConfFilePath += TINYDIR_STRING("/project.conf");
- validateFilePath(projectConfFilePath.c_str());
-
- // TODO: Detect compiler to use at runtime. Should also be configurable
- // by passing argument to `sibs build`
-#if OS_FAMILY == OS_FAMILY_POSIX
- Compiler compiler = Compiler::GCC;
-#else
- Compiler compiler = Compiler::MSVC;
-#endif
-
- SibsConfig sibsConfig(compiler, projectPath, optimizationLevel);
Result<bool> result = Config::readFromFile(projectConfFilePath.c_str(), sibsConfig);
if(result.isErr())
{
@@ -285,7 +228,6 @@ int buildProject(int argc, const _tinydir_char_t **argv)
}
else
{
- // TODO: If compiling without "test" option, do not add test source dir to ninja. Ninja logic will then not build tests
if (!sibsConfig.getTestPath().empty() && isPathSubPathOf(pathNative.c_str(), sibsConfig.getTestPath()))
{
string filePathUtf8 = toUtf8(pathNative.c_str());
@@ -305,11 +247,127 @@ int buildProject(int argc, const _tinydir_char_t **argv)
}
}
auto elapsedTime = duration_cast<duration<double>>(high_resolution_clock::now() - startTime);
- printf("Build finished in %fs\n", elapsedTime.count());
+ printf("Finished in %fs\n", elapsedTime.count());
return 0;
}
+int buildProject(int argc, const _tinydir_char_t **argv)
+{
+ if(argc > 2)
+ usageBuild();
+
+ OptimizationLevel optimizationLevel = OPT_LEV_NONE;
+ FileString projectPath;
+
+ for(int i = 0; i < argc; ++i)
+ {
+ const _tinydir_char_t *arg = argv[i];
+ if(_tinydir_strcmp(arg, TINYDIR_STRING("--debug")) == 0)
+ {
+ if(optimizationLevel != OPT_LEV_NONE)
+ {
+ ferr << "Error: Optimization level defined more than once. First defined as " << asString(optimizationLevel) << " then as debug" << endl;
+ usageBuild();
+ }
+ optimizationLevel = OPT_LEV_DEBUG;
+ }
+ else if(_tinydir_strcmp(arg, TINYDIR_STRING("--release")) == 0)
+ {
+ if(optimizationLevel != OPT_LEV_NONE)
+ {
+ ferr << "Error: Optimization level defined more than once. First defined as " << asString(optimizationLevel) << " then as release" << endl;
+ usageBuild();
+ }
+ optimizationLevel = OPT_LEV_RELEASE;
+ }
+ else
+ {
+ if(!projectPath.empty())
+ {
+ ferr << "Error: Project path was defined more than once. First defined as " << projectPath << " then as " << arg << endl;
+ usageBuild();
+ }
+ projectPath = arg;
+ }
+ }
+
+ if(optimizationLevel == OPT_LEV_NONE)
+ optimizationLevel = OPT_LEV_DEBUG;
+
+ // TODO: If projectPath is not defined and working directory does not contain project.conf, then search every parent directory until one is found
+ if(projectPath.empty())
+ projectPath = TINYDIR_STRING(".");
+
+ validateDirectoryPath(projectPath.c_str());
+ if(projectPath.back() != '/')
+ projectPath += TINYDIR_STRING("/");
+
+ Result<FileString> projectRealPathResult = getRealPath(projectPath.c_str());
+ if(!projectRealPathResult)
+ {
+ ferr << "Failed to get real path for: '" << projectPath.c_str() << "': " << toFileString(projectRealPathResult.getErrMsg()) << endl;
+ exit(40);
+ }
+ projectPath = projectRealPathResult.unwrap();
+
+ FileString projectConfFilePath = projectPath;
+ projectConfFilePath += TINYDIR_STRING("/project.conf");
+ validateFilePath(projectConfFilePath.c_str());
+
+ // TODO: Detect compiler to use at runtime. Should also be configurable
+ // by passing argument to `sibs build`
+#if OS_FAMILY == OS_FAMILY_POSIX
+ Compiler compiler = Compiler::GCC;
+#else
+ Compiler compiler = Compiler::MSVC;
+#endif
+
+ SibsConfig sibsConfig(compiler, projectPath, optimizationLevel, false);
+ return buildProject(projectPath, projectConfFilePath, sibsConfig);
+}
+
+int testProject(int argc, const _tinydir_char_t **argv)
+{
+ if(argc > 1)
+ usageTest();
+
+ FileString projectPath;
+ if(argc == 1)
+ projectPath = argv[0];
+
+ // TODO: If projectPath is not defined and working directory does not contain project.conf, then search every parent directory until one is found
+ if(projectPath.empty())
+ projectPath = TINYDIR_STRING(".");
+
+ validateDirectoryPath(projectPath.c_str());
+ if(projectPath.back() != '/')
+ projectPath += TINYDIR_STRING("/");
+
+ Result<FileString> projectRealPathResult = getRealPath(projectPath.c_str());
+ if(!projectRealPathResult)
+ {
+ ferr << "Failed to get real path for: '" << projectPath.c_str() << "': " << toFileString(projectRealPathResult.getErrMsg()) << endl;
+ exit(40);
+ }
+ projectPath = projectRealPathResult.unwrap();
+
+ FileString projectConfFilePath = projectPath;
+ projectConfFilePath += TINYDIR_STRING("/project.conf");
+ validateFilePath(projectConfFilePath.c_str());
+
+ // TODO: Detect compiler to use at runtime. Should also be configurable
+ // by passing argument to `sibs build`
+#if OS_FAMILY == OS_FAMILY_POSIX
+ Compiler compiler = Compiler::GCC;
+#else
+ Compiler compiler = Compiler::MSVC;
+#endif
+
+ SibsConfig sibsConfig(compiler, projectPath, OPT_LEV_DEBUG, true);
+ return buildProject(projectPath, projectConfFilePath, sibsConfig);
+}
+
void newProjectCreateMainDir(const FileString &projectPath)
{
Result<bool> createProjectDirResult = createDirectoryRecursive(projectPath.c_str());
@@ -451,6 +509,10 @@ int wmain(int argc, const _tinydir_char_t **argv)
{
return newProject(subCommandArgCount, subCommandArgPtr);
}
+ else if(_tinydir_strcmp(arg, TINYDIR_STRING("test")) == 0)
+ {
+ return testProject(subCommandArgCount, subCommandArgPtr);
+ }
else
{
ferr << "Expected command to be either 'build' or 'new', was: " << arg << endl << endl;
diff --git a/tests/src/confTest/confTest.cpp b/tests/src/confTest/confTest.cpp
index 94cdb11..44bcab0 100644
--- a/tests/src/confTest/confTest.cpp
+++ b/tests/src/confTest/confTest.cpp
@@ -5,7 +5,7 @@ using namespace sibs;
TEST_CASE("parse config")
{
- SibsConfig sibsConfig(Compiler::GCC, TINYDIR_STRING("tests/src/confTest"));
+ SibsConfig sibsConfig(Compiler::GCC, TINYDIR_STRING("tests/src/confTest"), OPT_LEV_DEBUG, false);
Result<bool> result = Config::readFromFile(TINYDIR_STRING("tests/src/confTest/validProject.conf"), sibsConfig);
if(result.isErr())
{
@@ -42,7 +42,7 @@ TEST_CASE("parse config")
TEST_CASE("parse config - invalid object")
{
- SibsConfig sibsConfig(Compiler::GCC, TINYDIR_STRING("tests/src/confTest"));
+ SibsConfig sibsConfig(Compiler::GCC, TINYDIR_STRING("tests/src/confTest"), OPT_LEV_DEBUG, false);
Result<bool> result = Config::readFromFile(TINYDIR_STRING("tests/src/confTest/invalidObject.conf"), sibsConfig);
REQUIRE(result.isErr());
REQUIRE(result.getErrMsg() == "Invalid config object \"invalidObj\"");
@@ -50,7 +50,7 @@ TEST_CASE("parse config - invalid object")
TEST_CASE("parse config - invalid field")
{
- SibsConfig sibsConfig(Compiler::GCC, TINYDIR_STRING("tests/src/confTest"));
+ SibsConfig sibsConfig(Compiler::GCC, TINYDIR_STRING("tests/src/confTest"), OPT_LEV_DEBUG, false);
Result<bool> result = Config::readFromFile(TINYDIR_STRING("tests/src/confTest/invalidField.conf"), sibsConfig);
REQUIRE(result.isErr());
REQUIRE(result.getErrMsg() == "Invalid field \"invalidField\" under object \"package\"");
@@ -58,7 +58,7 @@ TEST_CASE("parse config - invalid field")
TEST_CASE("parse config - use different config for different platforms")
{
- SibsConfig sibsConfig(Compiler::GCC, TINYDIR_STRING("tests/src/confTest"));
+ SibsConfig sibsConfig(Compiler::GCC, TINYDIR_STRING("tests/src/confTest"), OPT_LEV_DEBUG, false);
Result<bool> result = Config::readFromFile(TINYDIR_STRING("tests/src/confTest/platformConfig.conf"), sibsConfig);
if(result.isErr())
{