Skip to content

Commit

Permalink
Add unit tests for CLI driver (#570)
Browse files Browse the repository at this point in the history
  • Loading branch information
marcauberer committed May 26, 2024
1 parent ccaa8fa commit ec6de68
Show file tree
Hide file tree
Showing 7 changed files with 194 additions and 10 deletions.
2 changes: 0 additions & 2 deletions docs/docs/cli/test.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@ You can apply following options to the `test` subcommand:

| Option | Long | Description |
|--------------|----------------------|---------------------------------------------------------------------------------------------|
| `-a` | `--run-all` | Print compiler output for debugging. |
| `-t` | `--test` | Runs a single test case by its name |
| `-d` | `--debug-output` | Print compiler output for debugging. |
| `-cst` | `--dump-cst` | Dump CST as serialized string and SVG image |
| `-ast` | `--dump-ast` | Dump AST as serialized string and SVG image |
Expand Down
7 changes: 4 additions & 3 deletions src/driver/Driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ void Driver::init() {
// Prepare the installation path
std::filesystem::path installPath = FileUtil::getSpiceBinDir();
installPath /= cliOptions.mainSourceFile.stem();
std::filesystem::create_directories(installPath);
if (!dryRun)
std::filesystem::create_directories(installPath);
#if OS_WINDOWS
installPath.replace_extension("exe");
#endif
Expand All @@ -50,7 +51,7 @@ void Driver::init() {
cliOptions.outputPath = installPath;

// If the binary should be uninstalled, check if the executable exists and uninstall it
if (shouldUninstall) {
if (shouldUninstall && !dryRun) {
if (std::filesystem::exists(installPath) && std::filesystem::remove(installPath))
std::cout << "Successfully uninstalled.\n";
else
Expand Down Expand Up @@ -107,7 +108,7 @@ void Driver::init() {
* @param argv Argument vector
* @return Return code
*/
int Driver::parse(int argc, char **argv) {
int Driver::parse(int argc, const char *argv[]) {
try {
app.parse(argc, argv);
return EXIT_SUCCESS;
Expand Down
6 changes: 4 additions & 2 deletions src/driver/Driver.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,12 +79,13 @@ struct CliOptions {
class Driver {
public:
// Constructors
explicit Driver() = default;
Driver() = default;
explicit Driver(bool dryRun) : dryRun(dryRun) {}
Driver(const Driver &) = delete;

// Public methods
void init();
int parse(int argc, char **argv);
int parse(int argc, const char *argv[]);
void enrich();
void runBinary() const;

Expand All @@ -94,6 +95,7 @@ class Driver {
bool shouldInstall = false;
bool shouldUninstall = false;
bool shouldExecute = false;
bool dryRun = false; // For unit testing purposes

private:
// Private methods
Expand Down
3 changes: 2 additions & 1 deletion src/irgenerator/GenImplicit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,8 @@ void IRGenerator::generateCtorOrDtorCall(SymbolTableEntry *entry, const Function
generateCtorOrDtorCall(structAddr, ctorOrDtor, args);
}

void IRGenerator::generateCtorOrDtorCall(llvm::Value *structAddr, const Function *ctorOrDtor, const std::vector<llvm::Value *> &args) const {
void IRGenerator::generateCtorOrDtorCall(llvm::Value *structAddr, const Function *ctorOrDtor,
const std::vector<llvm::Value *> &args) const {
assert(ctorOrDtor != nullptr);

// Retrieve metadata for the function
Expand Down
2 changes: 1 addition & 1 deletion src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ bool compileProject(CliOptions &cliOptions) {
* @param argv Argument vector
* @return Return code
*/
int main(int argc, char **argv) {
int main(int argc, const char *argv[]) {
// Initialize command line parser
Driver driver;
driver.init();
Expand Down
3 changes: 2 additions & 1 deletion test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ set(SOURCES
util/TestUtil.cpp
util/TestUtil.h
unittest/UnitBlockAllocator.cpp
unittest/UnitCommonUtil.cpp)
unittest/UnitCommonUtil.cpp
unittest/UnitDriver.cpp)

add_executable(spicetest ${SOURCES} ${ANTLR_Spice_CXX_OUTPUTS})

Expand Down
181 changes: 181 additions & 0 deletions test/unittest/UnitDriver.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
// Copyright (c) 2021-2024 ChilliBits. All rights reserved.

#include <gtest/gtest.h>

#include <driver/Driver.h>

namespace spice::testing {

using namespace spice::compiler;

TEST(DriverTest, TestBuildSubcommandMinimal) {
const char *argv[] = {"spice", "build", "../../media/test-project/test.spice"};
const int argc = sizeof(argv) / sizeof(argv[0]);
Driver driver = Driver(true);
driver.init();
ASSERT_EQ(EXIT_SUCCESS, driver.parse(argc, argv));
driver.enrich();

ASSERT_TRUE(driver.shouldCompile);
ASSERT_FALSE(driver.shouldInstall);
ASSERT_FALSE(driver.shouldUninstall);
ASSERT_FALSE(driver.shouldExecute);
ASSERT_FALSE(driver.cliOptions.execute);
ASSERT_EQ("../../media/test-project/test.spice", driver.cliOptions.mainSourceFile.relative_path().string());
ASSERT_EQ(OptLevel::O0, driver.cliOptions.optLevel);
ASSERT_EQ(BuildMode::DEBUG, driver.cliOptions.buildMode);
ASSERT_FALSE(driver.cliOptions.generateTestMain);
ASSERT_FALSE(driver.cliOptions.testMode);
ASSERT_FALSE(driver.cliOptions.noEntryFct);
}

TEST(DriverTest, TestBuildSubcommandComplex) {
const char *argv[] = {"spice", "b", "-d", "-ir", "-g", "-Os", "-m", "release", "-lto", "../../media/test-project/test.spice"};
const int argc = sizeof(argv) / sizeof(argv[0]);
Driver driver = Driver(true);
driver.init();
ASSERT_EQ(EXIT_SUCCESS, driver.parse(argc, argv));
driver.enrich();

ASSERT_TRUE(driver.shouldCompile);
ASSERT_FALSE(driver.shouldInstall);
ASSERT_FALSE(driver.shouldUninstall);
ASSERT_FALSE(driver.shouldExecute);
ASSERT_FALSE(driver.cliOptions.execute);
ASSERT_EQ("../../media/test-project/test.spice", driver.cliOptions.mainSourceFile.relative_path().string());
ASSERT_EQ(OptLevel::Os, driver.cliOptions.optLevel); // -Os
ASSERT_EQ(BuildMode::RELEASE, driver.cliOptions.buildMode); // -m release
ASSERT_FALSE(driver.cliOptions.generateTestMain);
ASSERT_FALSE(driver.cliOptions.testMode);
ASSERT_FALSE(driver.cliOptions.noEntryFct);
ASSERT_TRUE(driver.cliOptions.generateDebugInfo); // -g
ASSERT_TRUE(driver.cliOptions.useLTO); // -lto
ASSERT_TRUE(driver.cliOptions.printDebugOutput); // -d
ASSERT_TRUE(driver.cliOptions.dumpSettings.dumpIR); // -ir
}

TEST(DriverTest, TestRunSubcommandMinimal) {
const char *argv[] = {"spice", "run", "../../media/test-project/test.spice"};
const int argc = sizeof(argv) / sizeof(argv[0]);
Driver driver = Driver(true);
driver.init();
ASSERT_EQ(EXIT_SUCCESS, driver.parse(argc, argv));
driver.enrich();

ASSERT_TRUE(driver.shouldCompile);
ASSERT_FALSE(driver.shouldInstall);
ASSERT_FALSE(driver.shouldUninstall);
ASSERT_TRUE(driver.shouldExecute);
ASSERT_TRUE(driver.cliOptions.execute);
ASSERT_EQ("../../media/test-project/test.spice", driver.cliOptions.mainSourceFile.relative_path().string());
ASSERT_EQ(OptLevel::O0, driver.cliOptions.optLevel);
ASSERT_FALSE(driver.cliOptions.generateTestMain);
ASSERT_FALSE(driver.cliOptions.testMode);
ASSERT_FALSE(driver.cliOptions.noEntryFct);
}

TEST(DriverTest, TestRunSubcommandComplex) {
const char *argv[] = {"spice", "r", "-O2", "-j", "8", "-ast", "../../media/test-project/test.spice"};
const int argc = sizeof(argv) / sizeof(argv[0]);
Driver driver = Driver(true);
driver.init();
ASSERT_EQ(EXIT_SUCCESS, driver.parse(argc, argv));
driver.enrich();

ASSERT_TRUE(driver.shouldCompile);
ASSERT_FALSE(driver.shouldInstall);
ASSERT_FALSE(driver.shouldUninstall);
ASSERT_TRUE(driver.shouldExecute);
ASSERT_TRUE(driver.cliOptions.execute);
ASSERT_EQ("../../media/test-project/test.spice", driver.cliOptions.mainSourceFile.relative_path().string());
ASSERT_EQ(OptLevel::O2, driver.cliOptions.optLevel); // -O2
ASSERT_FALSE(driver.cliOptions.generateTestMain);
ASSERT_FALSE(driver.cliOptions.testMode);
ASSERT_FALSE(driver.cliOptions.noEntryFct);
ASSERT_EQ(8, driver.cliOptions.compileJobCount); // -j 8
ASSERT_TRUE(driver.cliOptions.dumpSettings.dumpAST); // -ast
}

TEST(DriverTest, TestTestSubcommandMinimal) {
const char *argv[] = {"spice", "test", "../../media/test-project/test.spice"};
const int argc = sizeof(argv) / sizeof(argv[0]);
Driver driver = Driver(true);
driver.init();
ASSERT_EQ(EXIT_SUCCESS, driver.parse(argc, argv));
driver.enrich();

ASSERT_TRUE(driver.shouldCompile);
ASSERT_FALSE(driver.shouldInstall);
ASSERT_FALSE(driver.shouldUninstall);
ASSERT_TRUE(driver.shouldExecute);
ASSERT_TRUE(driver.cliOptions.execute);
ASSERT_EQ("../../media/test-project/test.spice", driver.cliOptions.mainSourceFile.relative_path().string());
ASSERT_EQ(OptLevel::O0, driver.cliOptions.optLevel);
ASSERT_TRUE(driver.cliOptions.generateTestMain);
ASSERT_TRUE(driver.cliOptions.testMode);
ASSERT_TRUE(driver.cliOptions.noEntryFct);
}

TEST(DriverTest, TestTestSubcommandComplex) {
const char *argv[] = {"spice", "t", "-s", "-cst", "../../media/test-project/test.spice"};
const int argc = sizeof(argv) / sizeof(argv[0]);
Driver driver = Driver(true);
driver.init();
ASSERT_EQ(EXIT_SUCCESS, driver.parse(argc, argv));
driver.enrich();

ASSERT_TRUE(driver.shouldCompile);
ASSERT_FALSE(driver.shouldInstall);
ASSERT_FALSE(driver.shouldUninstall);
ASSERT_TRUE(driver.shouldExecute);
ASSERT_TRUE(driver.cliOptions.execute);
ASSERT_EQ("../../media/test-project/test.spice", driver.cliOptions.mainSourceFile.relative_path().string());
ASSERT_EQ(OptLevel::O0, driver.cliOptions.optLevel);
ASSERT_TRUE(driver.cliOptions.generateTestMain);
ASSERT_TRUE(driver.cliOptions.testMode);
ASSERT_TRUE(driver.cliOptions.noEntryFct);
ASSERT_TRUE(driver.cliOptions.dumpSettings.dumpCST); // -cst
ASSERT_TRUE(driver.cliOptions.dumpSettings.dumpAssembly); // -s
}

TEST(DriverTest, TestInstallSubcommandMinimal) {
const char *argv[] = {"spice", "install", "../../media/test-project/test.spice"};
const int argc = sizeof(argv) / sizeof(argv[0]);
Driver driver = Driver(true);
driver.init();
ASSERT_EQ(EXIT_SUCCESS, driver.parse(argc, argv));
driver.enrich();

ASSERT_TRUE(driver.shouldCompile);
ASSERT_TRUE(driver.shouldInstall);
ASSERT_FALSE(driver.shouldUninstall);
ASSERT_FALSE(driver.shouldExecute);
ASSERT_FALSE(driver.cliOptions.execute);
ASSERT_EQ("../../media/test-project/test.spice", driver.cliOptions.mainSourceFile.relative_path().string());
ASSERT_EQ(OptLevel::O0, driver.cliOptions.optLevel);
ASSERT_FALSE(driver.cliOptions.generateTestMain);
ASSERT_FALSE(driver.cliOptions.testMode);
ASSERT_FALSE(driver.cliOptions.noEntryFct);
}

TEST(DriverTest, TestUninstallSubcommandMinimal) {
const char *argv[] = {"spice", "uninstall", "../../media/test-project/test.spice"};
const int argc = sizeof(argv) / sizeof(argv[0]);
Driver driver = Driver(true);
driver.init();
ASSERT_EQ(EXIT_SUCCESS, driver.parse(argc, argv));
driver.enrich();

ASSERT_FALSE(driver.shouldCompile);
ASSERT_FALSE(driver.shouldInstall);
ASSERT_TRUE(driver.shouldUninstall);
ASSERT_FALSE(driver.shouldExecute);
ASSERT_FALSE(driver.cliOptions.execute);
ASSERT_EQ("../../media/test-project/test.spice", driver.cliOptions.mainSourceFile.relative_path().string());
ASSERT_EQ(OptLevel::O0, driver.cliOptions.optLevel);
ASSERT_FALSE(driver.cliOptions.generateTestMain);
ASSERT_FALSE(driver.cliOptions.testMode);
ASSERT_FALSE(driver.cliOptions.noEntryFct);
}

} // namespace spice::testing

0 comments on commit ec6de68

Please sign in to comment.