/*
 * Copyright 2019 Bloomberg Finance LP
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <buildboxcommon_digestgenerator.h>
#include <buildboxrun_hosttools.h>

#include <gtest/gtest.h>

using namespace buildboxcommon;
using namespace buildboxrun;
using namespace hosttools;

HostToolsRunner testRunner()
{
    buildboxcommon::DigestGenerator::resetState();
    return HostToolsRunner();
}

TEST(ArgumentParsingTests, TestCustomParser)
{
    HostToolsRunner runner = testRunner();
    EXPECT_TRUE(runner.parseArg("--prefix-staged-dir"));
    EXPECT_TRUE(runner.parseArg("--allow-executable=gcc"));
    EXPECT_FALSE(runner.parseArg("--some-other-argument"));
    EXPECT_FALSE(runner.parseArg("--verbose"));
}

TEST(AllowListTests, ExecutableNotInAllowList)
{
    HostToolsRunner runner = testRunner();
    runner.parseArg("--allow-executable=nothing");

    EXPECT_FALSE(runner.executableInAllowedExecutables("/usr/bin/gcc"));
}

TEST(AllowListTests, ExecutableInAllowList)
{
    HostToolsRunner runner = testRunner();
    runner.parseArg("--allow-executable=/usr/bin/gcc");

    EXPECT_TRUE(runner.executableInAllowedExecutables("/usr/bin/gcc"));
}

TEST(AllowListTests, ExecutableInImplicitlyEmptyAllowList)
{
    HostToolsRunner runner = testRunner();

    EXPECT_TRUE(runner.executableInAllowedExecutables("/usr/bin/gcc"));
}

TEST(AllowListTests, ExecutableInExplicitlyEmptyAllowList)
{
    HostToolsRunner runner = testRunner();
    runner.parseArg("--allow-executable=");

    EXPECT_FALSE(runner.executableInAllowedExecutables("/usr/bin/gcc"));
}

TEST(CommandLineTests, TestPathLookup)
{
    Command command;
    *command.add_arguments() = "echo";
    *command.add_arguments() = "hello, world";

    HostToolsRunner runner = testRunner();

    std::vector<std::string> commandLine =
        runner.generateCommandLine(command, "");

    EXPECT_EQ(commandLine.size(), 2);
    EXPECT_EQ(commandLine[0][0], '/'); // Resolved to absolute path
    EXPECT_EQ(commandLine[1], command.arguments(1));
}

TEST(CommandLineTests, TestRelativePath)
{
    Command command;
    *command.add_arguments() = "./echo";
    *command.add_arguments() = "hello, world";

    HostToolsRunner runner = testRunner();

    std::vector<std::string> commandLine =
        runner.generateCommandLine(command, "");

    EXPECT_EQ(commandLine.size(), 2);
    EXPECT_EQ(commandLine[0], command.arguments(0)); // No path lookup
    EXPECT_EQ(commandLine[1], command.arguments(1));
}

TEST(CommandLineTests, TestAbsolutePath)
{
    Command command;
    *command.add_arguments() = "/bin/echo";
    *command.add_arguments() = "hello, world";

    HostToolsRunner runner = testRunner();

    std::vector<std::string> commandLine =
        runner.generateCommandLine(command, "");

    EXPECT_EQ(commandLine.size(), 2);
    EXPECT_EQ(commandLine[0], command.arguments(0)); // No path lookup
    EXPECT_EQ(commandLine[1], command.arguments(1));
}

TEST(CommandLineTests, TestRelativePathNotFound)
{
    Command command;
    *command.add_arguments() = "fakecommand";
    *command.add_arguments() = "--some-argument";
    HostToolsRunner runner = testRunner();

    std::vector<std::string> commandLine =
        runner.generateCommandLine(command, "");
    EXPECT_EQ(commandLine.size(), 2);
    EXPECT_EQ(commandLine[0],
              command.arguments(0)); // If path lookup fails it's left alone
    EXPECT_EQ(commandLine[1], command.arguments(1));
}

TEST(CommandLineTests, TestClearEnv)
{
    HostToolsRunner runner = testRunner();
    EXPECT_TRUE(runner.parseArg("--clearenv"));

    const auto env = runner.getEnvironment();
    EXPECT_TRUE(env.has_value());
    if (env.has_value()) {
        EXPECT_EQ(env->size(), 0);
    }
}

TEST(CommandLineTests, TestEnvFile)
{
    HostToolsRunner runner = testRunner();
    EXPECT_TRUE(runner.parseArg("--env-file=test.env"));

    const auto env = runner.getEnvironment();
    EXPECT_TRUE(env.has_value());
    if (env.has_value()) {
        EXPECT_EQ(env->size(), 2);
        EXPECT_EQ(env->at("FOO"), "bar");
        EXPECT_EQ(env->at("BAR"), "baz");
    }
}

TEST(CommandLineTests, TestActionDigestEnv)
{
    HostToolsRunner runner = testRunner();
    ASSERT_TRUE(runner.parseArg("--action-digest-env=MY_ACTION_DIGEST"));

    const auto &actionDigestEnv = runner.getActionDigestEnv();
    ASSERT_TRUE(actionDigestEnv.has_value());
    if (actionDigestEnv.has_value()) {
        EXPECT_EQ(*actionDigestEnv, "MY_ACTION_DIGEST");
    }
}
