Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add unit tests for CLI driver #570

Merged
merged 2 commits into from
May 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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