backend-infra-engineer: Release v0.3.9-hotfix7 snapshot
This commit is contained in:
413
test/unit/tools/build_tool_test.cc
Normal file
413
test/unit/tools/build_tool_test.cc
Normal file
@@ -0,0 +1,413 @@
|
||||
/**
|
||||
* @file build_tool_test.cc
|
||||
* @brief Unit tests for the BuildTool AI agent tool
|
||||
*
|
||||
* Tests the BuildTool functionality including preset listing, validation,
|
||||
* build status tracking, project root detection, and timeout protection.
|
||||
*/
|
||||
|
||||
#include "cli/service/agent/tools/build_tool.h"
|
||||
|
||||
#include <gmock/gmock.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <thread>
|
||||
|
||||
#include "absl/status/status.h"
|
||||
#include "absl/status/statusor.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace cli {
|
||||
namespace agent {
|
||||
namespace tools {
|
||||
namespace {
|
||||
|
||||
using ::testing::Contains;
|
||||
using ::testing::HasSubstr;
|
||||
using ::testing::IsEmpty;
|
||||
using ::testing::Not;
|
||||
using ::testing::SizeIs;
|
||||
|
||||
// Test fixture for BuildTool tests
|
||||
class BuildToolTest : public ::testing::Test {
|
||||
protected:
|
||||
void SetUp() override {
|
||||
// Create a temporary test directory
|
||||
test_dir_ = std::filesystem::temp_directory_path() / "yaze_build_tool_test";
|
||||
std::filesystem::create_directories(test_dir_);
|
||||
|
||||
// Create a minimal CMakePresets.json for testing
|
||||
CreateTestPresetsFile();
|
||||
}
|
||||
|
||||
void TearDown() override {
|
||||
// Clean up test directory
|
||||
std::filesystem::remove_all(test_dir_);
|
||||
}
|
||||
|
||||
void CreateTestPresetsFile() {
|
||||
std::ofstream presets_file(test_dir_ / "CMakePresets.json");
|
||||
presets_file << R"({
|
||||
"version": 6,
|
||||
"configurePresets": [
|
||||
{
|
||||
"name": "mac-dbg",
|
||||
"displayName": "macOS Debug",
|
||||
"generator": "Ninja",
|
||||
"binaryDir": "${sourceDir}/build",
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Debug"
|
||||
},
|
||||
"condition": {
|
||||
"type": "equals",
|
||||
"lhs": "${hostSystemName}",
|
||||
"rhs": "Darwin"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "mac-ai",
|
||||
"displayName": "macOS AI Build",
|
||||
"generator": "Ninja",
|
||||
"binaryDir": "${sourceDir}/build_ai",
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Debug"
|
||||
},
|
||||
"condition": {
|
||||
"type": "equals",
|
||||
"lhs": "${hostSystemName}",
|
||||
"rhs": "Darwin"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "lin-dbg",
|
||||
"displayName": "Linux Debug",
|
||||
"generator": "Ninja",
|
||||
"binaryDir": "${sourceDir}/build",
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Debug"
|
||||
},
|
||||
"condition": {
|
||||
"type": "equals",
|
||||
"lhs": "${hostSystemName}",
|
||||
"rhs": "Linux"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "lin-ai",
|
||||
"displayName": "Linux AI Build",
|
||||
"generator": "Ninja",
|
||||
"binaryDir": "${sourceDir}/build_ai",
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Debug"
|
||||
},
|
||||
"condition": {
|
||||
"type": "equals",
|
||||
"lhs": "${hostSystemName}",
|
||||
"rhs": "Linux"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "win-dbg",
|
||||
"displayName": "Windows Debug",
|
||||
"generator": "Visual Studio 17 2022",
|
||||
"binaryDir": "${sourceDir}/build",
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Debug"
|
||||
},
|
||||
"condition": {
|
||||
"type": "equals",
|
||||
"lhs": "${hostSystemName}",
|
||||
"rhs": "Windows"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "win-ai",
|
||||
"displayName": "Windows AI Build",
|
||||
"generator": "Visual Studio 17 2022",
|
||||
"binaryDir": "${sourceDir}/build_ai",
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Debug"
|
||||
},
|
||||
"condition": {
|
||||
"type": "equals",
|
||||
"lhs": "${hostSystemName}",
|
||||
"rhs": "Windows"
|
||||
}
|
||||
}
|
||||
]
|
||||
})";
|
||||
presets_file.close();
|
||||
}
|
||||
|
||||
std::filesystem::path test_dir_;
|
||||
};
|
||||
|
||||
// =============================================================================
|
||||
// BuildTool Configuration Tests
|
||||
// =============================================================================
|
||||
|
||||
TEST_F(BuildToolTest, DefaultConfigUsesCorrectBuildDirectory) {
|
||||
BuildTool::BuildConfig config;
|
||||
EXPECT_EQ(config.build_directory, "build_ai");
|
||||
}
|
||||
|
||||
TEST_F(BuildToolTest, DefaultConfigUsesCorrectTimeout) {
|
||||
BuildTool::BuildConfig config;
|
||||
EXPECT_EQ(config.timeout, std::chrono::seconds(600));
|
||||
}
|
||||
|
||||
TEST_F(BuildToolTest, DefaultConfigEnablesCaptureOutput) {
|
||||
BuildTool::BuildConfig config;
|
||||
EXPECT_TRUE(config.capture_output);
|
||||
}
|
||||
|
||||
TEST_F(BuildToolTest, DefaultConfigUsesCorrectMaxOutputSize) {
|
||||
BuildTool::BuildConfig config;
|
||||
EXPECT_EQ(config.max_output_size, 1024 * 1024); // 1MB
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// BuildTool Preset Tests
|
||||
// =============================================================================
|
||||
|
||||
TEST_F(BuildToolTest, ListAvailablePresetsNotEmpty) {
|
||||
BuildTool tool;
|
||||
auto presets = tool.ListAvailablePresets();
|
||||
|
||||
// At least some presets should be available on any platform
|
||||
// The actual presets depend on the project's CMakePresets.json
|
||||
// This test verifies the mechanism works
|
||||
EXPECT_THAT(presets, Not(IsEmpty()));
|
||||
}
|
||||
|
||||
TEST_F(BuildToolTest, ListAvailablePresetsContainsPlatformSpecificPresets) {
|
||||
BuildTool tool;
|
||||
auto presets = tool.ListAvailablePresets();
|
||||
|
||||
#if defined(__APPLE__)
|
||||
// On macOS, we should have mac-* presets
|
||||
bool has_mac_preset = false;
|
||||
for (const auto& preset : presets) {
|
||||
if (preset.find("mac") != std::string::npos) {
|
||||
has_mac_preset = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
EXPECT_TRUE(has_mac_preset) << "Expected mac-* preset on macOS";
|
||||
#elif defined(__linux__)
|
||||
// On Linux, we should have lin-* presets
|
||||
bool has_lin_preset = false;
|
||||
for (const auto& preset : presets) {
|
||||
if (preset.find("lin") != std::string::npos) {
|
||||
has_lin_preset = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
EXPECT_TRUE(has_lin_preset) << "Expected lin-* preset on Linux";
|
||||
#elif defined(_WIN32)
|
||||
// On Windows, we should have win-* presets
|
||||
bool has_win_preset = false;
|
||||
for (const auto& preset : presets) {
|
||||
if (preset.find("win") != std::string::npos) {
|
||||
has_win_preset = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
EXPECT_TRUE(has_win_preset) << "Expected win-* preset on Windows";
|
||||
#endif
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// BuildTool Status Tests
|
||||
// =============================================================================
|
||||
|
||||
TEST_F(BuildToolTest, InitialBuildStatusNotRunning) {
|
||||
BuildTool tool;
|
||||
auto status = tool.GetBuildStatus();
|
||||
|
||||
EXPECT_FALSE(status.is_running);
|
||||
EXPECT_TRUE(status.current_operation.empty());
|
||||
EXPECT_EQ(status.progress_percent, -1); // Unknown progress
|
||||
}
|
||||
|
||||
TEST_F(BuildToolTest, BuildStatusTrackingDuringOperation) {
|
||||
BuildTool tool;
|
||||
|
||||
// Get initial status
|
||||
auto initial_status = tool.GetBuildStatus();
|
||||
EXPECT_FALSE(initial_status.is_running);
|
||||
|
||||
// Note: We don't actually start a build here since it would require
|
||||
// a properly configured build environment. This test verifies the
|
||||
// status tracking interface is accessible.
|
||||
}
|
||||
|
||||
TEST_F(BuildToolTest, GetLastResultInitiallyEmpty) {
|
||||
BuildTool tool;
|
||||
auto last_result = tool.GetLastResult();
|
||||
|
||||
EXPECT_FALSE(last_result.has_value());
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// BuildTool Build Directory Tests
|
||||
// =============================================================================
|
||||
|
||||
TEST_F(BuildToolTest, IsBuildDirectoryReadyInitiallyFalse) {
|
||||
BuildTool::BuildConfig config;
|
||||
config.build_directory = (test_dir_ / "nonexistent_build").string();
|
||||
|
||||
BuildTool tool(config);
|
||||
|
||||
EXPECT_FALSE(tool.IsBuildDirectoryReady());
|
||||
}
|
||||
|
||||
TEST_F(BuildToolTest, IsBuildDirectoryReadyAfterCreation) {
|
||||
BuildTool::BuildConfig config;
|
||||
auto build_dir = test_dir_ / "test_build";
|
||||
std::filesystem::create_directories(build_dir);
|
||||
config.build_directory = build_dir.string();
|
||||
|
||||
BuildTool tool(config);
|
||||
|
||||
// Note: Just having the directory doesn't mean it's "ready" (configured)
|
||||
// A real build directory would have CMakeCache.txt
|
||||
EXPECT_FALSE(tool.IsBuildDirectoryReady());
|
||||
|
||||
// Create a minimal CMakeCache.txt to simulate a configured build
|
||||
std::ofstream cache_file(build_dir / "CMakeCache.txt");
|
||||
cache_file << "# Minimal CMake cache for testing\n";
|
||||
cache_file.close();
|
||||
|
||||
// Now it should be ready
|
||||
EXPECT_TRUE(tool.IsBuildDirectoryReady());
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// BuildResult Structure Tests
|
||||
// =============================================================================
|
||||
|
||||
TEST_F(BuildToolTest, BuildResultStructureContainsExpectedFields) {
|
||||
BuildTool::BuildResult result;
|
||||
|
||||
// Verify default values
|
||||
EXPECT_FALSE(result.success);
|
||||
EXPECT_TRUE(result.output.empty());
|
||||
EXPECT_TRUE(result.error_output.empty());
|
||||
EXPECT_EQ(result.exit_code, 0);
|
||||
EXPECT_EQ(result.duration, std::chrono::seconds(0));
|
||||
EXPECT_TRUE(result.command_executed.empty());
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// BuildStatus Structure Tests
|
||||
// =============================================================================
|
||||
|
||||
TEST_F(BuildToolTest, BuildStatusStructureContainsExpectedFields) {
|
||||
BuildTool::BuildStatus status;
|
||||
|
||||
// Verify default values
|
||||
EXPECT_FALSE(status.is_running);
|
||||
EXPECT_TRUE(status.current_operation.empty());
|
||||
EXPECT_TRUE(status.last_result_summary.empty());
|
||||
EXPECT_EQ(status.progress_percent, 0);
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Cancel Operation Tests
|
||||
// =============================================================================
|
||||
|
||||
TEST_F(BuildToolTest, CancelOperationWhenNotRunning) {
|
||||
BuildTool tool;
|
||||
|
||||
// Canceling when nothing is running should succeed
|
||||
auto status = tool.CancelCurrentOperation();
|
||||
EXPECT_TRUE(status.ok());
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Command Handler Tests
|
||||
// =============================================================================
|
||||
|
||||
TEST(BuildConfigureCommandHandlerTest, GetNameReturnsCorrectName) {
|
||||
BuildConfigureCommandHandler handler;
|
||||
EXPECT_EQ(handler.GetName(), "build-configure");
|
||||
}
|
||||
|
||||
TEST(BuildConfigureCommandHandlerTest, GetUsageReturnsValidUsage) {
|
||||
BuildConfigureCommandHandler handler;
|
||||
std::string usage = handler.GetUsage();
|
||||
|
||||
EXPECT_THAT(usage, HasSubstr("--preset"));
|
||||
}
|
||||
|
||||
TEST(BuildCompileCommandHandlerTest, GetNameReturnsCorrectName) {
|
||||
BuildCompileCommandHandler handler;
|
||||
EXPECT_EQ(handler.GetName(), "build-compile");
|
||||
}
|
||||
|
||||
TEST(BuildCompileCommandHandlerTest, GetUsageReturnsValidUsage) {
|
||||
BuildCompileCommandHandler handler;
|
||||
std::string usage = handler.GetUsage();
|
||||
|
||||
EXPECT_THAT(usage, HasSubstr("--target"));
|
||||
}
|
||||
|
||||
TEST(BuildTestCommandHandlerTest, GetNameReturnsCorrectName) {
|
||||
BuildTestCommandHandler handler;
|
||||
EXPECT_EQ(handler.GetName(), "build-test");
|
||||
}
|
||||
|
||||
TEST(BuildTestCommandHandlerTest, GetUsageReturnsValidUsage) {
|
||||
BuildTestCommandHandler handler;
|
||||
std::string usage = handler.GetUsage();
|
||||
|
||||
EXPECT_THAT(usage, HasSubstr("--filter"));
|
||||
}
|
||||
|
||||
TEST(BuildStatusCommandHandlerTest, GetNameReturnsCorrectName) {
|
||||
BuildStatusCommandHandler handler;
|
||||
EXPECT_EQ(handler.GetName(), "build-status");
|
||||
}
|
||||
|
||||
TEST(BuildStatusCommandHandlerTest, GetUsageReturnsValidUsage) {
|
||||
BuildStatusCommandHandler handler;
|
||||
std::string usage = handler.GetUsage();
|
||||
|
||||
EXPECT_THAT(usage, HasSubstr("--build-dir"));
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Timeout Configuration Tests
|
||||
// =============================================================================
|
||||
|
||||
TEST_F(BuildToolTest, CustomTimeoutConfiguration) {
|
||||
BuildTool::BuildConfig config;
|
||||
config.timeout = std::chrono::seconds(300); // 5 minutes
|
||||
|
||||
BuildTool tool(config);
|
||||
|
||||
// Verify the tool was created successfully with custom config
|
||||
auto status = tool.GetBuildStatus();
|
||||
EXPECT_FALSE(status.is_running);
|
||||
}
|
||||
|
||||
TEST_F(BuildToolTest, VerboseConfigurationOption) {
|
||||
BuildTool::BuildConfig config;
|
||||
config.verbose = true;
|
||||
|
||||
BuildTool tool(config);
|
||||
|
||||
// Verify the tool was created successfully with verbose mode
|
||||
auto status = tool.GetBuildStatus();
|
||||
EXPECT_FALSE(status.is_running);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace tools
|
||||
} // namespace agent
|
||||
} // namespace cli
|
||||
} // namespace yaze
|
||||
496
test/unit/tools/filesystem_tool_test.cc
Normal file
496
test/unit/tools/filesystem_tool_test.cc
Normal file
@@ -0,0 +1,496 @@
|
||||
/**
|
||||
* @file filesystem_tool_test.cc
|
||||
* @brief Unit tests for the FileSystemTool AI agent tool
|
||||
*
|
||||
* Tests the FileSystemTool functionality including listing, reading,
|
||||
* existence checking, file info, and security protections.
|
||||
*/
|
||||
|
||||
#include "cli/service/agent/tools/filesystem_tool.h"
|
||||
|
||||
#include <gmock/gmock.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
|
||||
#include "absl/status/status.h"
|
||||
#include "cli/service/resources/command_context.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace cli {
|
||||
namespace agent {
|
||||
namespace tools {
|
||||
namespace {
|
||||
|
||||
using ::testing::HasSubstr;
|
||||
using ::testing::Not;
|
||||
|
||||
// Test fixture for FileSystemTool tests
|
||||
class FileSystemToolTest : public ::testing::Test {
|
||||
protected:
|
||||
void SetUp() override {
|
||||
// Create test directories and files
|
||||
test_dir_ = std::filesystem::temp_directory_path() / "yaze_fs_tool_test";
|
||||
std::filesystem::create_directories(test_dir_ / "subdir");
|
||||
|
||||
// Create test files
|
||||
std::ofstream(test_dir_ / "test.txt") << "Hello, World!";
|
||||
std::ofstream(test_dir_ / "subdir" / "nested.txt") << "Nested file content";
|
||||
|
||||
// Create a multi-line file for pagination tests
|
||||
std::ofstream multiline_file(test_dir_ / "multiline.txt");
|
||||
for (int i = 1; i <= 100; ++i) {
|
||||
multiline_file << "Line " << i << ": This is line number " << i << "\n";
|
||||
}
|
||||
multiline_file.close();
|
||||
|
||||
// Create a file with special characters
|
||||
std::ofstream special_file(test_dir_ / "special_chars.txt");
|
||||
special_file << "Tab:\tNewline:\nBackslash:\\Quote:\"End";
|
||||
special_file.close();
|
||||
|
||||
// Create an empty file
|
||||
std::ofstream(test_dir_ / "empty.txt");
|
||||
}
|
||||
|
||||
void TearDown() override {
|
||||
// Clean up test directory
|
||||
std::filesystem::remove_all(test_dir_);
|
||||
}
|
||||
|
||||
std::filesystem::path test_dir_;
|
||||
};
|
||||
|
||||
// =============================================================================
|
||||
// FileSystemListTool Tests
|
||||
// =============================================================================
|
||||
|
||||
TEST_F(FileSystemToolTest, ListDirectoryWorks) {
|
||||
FileSystemListTool tool;
|
||||
|
||||
std::vector<std::string> args = {
|
||||
"--path=" + test_dir_.string(),
|
||||
"--format=json"
|
||||
};
|
||||
|
||||
absl::Status status = tool.Run(args, nullptr);
|
||||
EXPECT_TRUE(status.ok()) << status.message();
|
||||
}
|
||||
|
||||
TEST_F(FileSystemToolTest, ListDirectoryRecursiveWorks) {
|
||||
FileSystemListTool tool;
|
||||
|
||||
std::vector<std::string> args = {
|
||||
"--path=" + test_dir_.string(),
|
||||
"--recursive=true",
|
||||
"--format=json"
|
||||
};
|
||||
|
||||
absl::Status status = tool.Run(args, nullptr);
|
||||
EXPECT_TRUE(status.ok()) << status.message();
|
||||
}
|
||||
|
||||
TEST_F(FileSystemToolTest, ListDirectoryTextFormat) {
|
||||
FileSystemListTool tool;
|
||||
|
||||
std::vector<std::string> args = {
|
||||
"--path=" + test_dir_.string(),
|
||||
"--format=text"
|
||||
};
|
||||
|
||||
absl::Status status = tool.Run(args, nullptr);
|
||||
EXPECT_TRUE(status.ok()) << status.message();
|
||||
}
|
||||
|
||||
TEST_F(FileSystemToolTest, ListNonExistentDirectoryFails) {
|
||||
FileSystemListTool tool;
|
||||
|
||||
std::vector<std::string> args = {
|
||||
"--path=" + (test_dir_ / "nonexistent").string(),
|
||||
"--format=json"
|
||||
};
|
||||
|
||||
absl::Status status = tool.Run(args, nullptr);
|
||||
EXPECT_FALSE(status.ok());
|
||||
}
|
||||
|
||||
TEST_F(FileSystemToolTest, ListToolGetNameReturnsCorrectName) {
|
||||
FileSystemListTool tool;
|
||||
EXPECT_EQ(tool.GetName(), "filesystem-list");
|
||||
}
|
||||
|
||||
TEST_F(FileSystemToolTest, ListToolGetUsageContainsPath) {
|
||||
FileSystemListTool tool;
|
||||
EXPECT_THAT(tool.GetUsage(), HasSubstr("--path"));
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// FileSystemReadTool Tests
|
||||
// =============================================================================
|
||||
|
||||
TEST_F(FileSystemToolTest, ReadFileWorks) {
|
||||
FileSystemReadTool tool;
|
||||
|
||||
std::vector<std::string> args = {
|
||||
"--path=" + (test_dir_ / "test.txt").string(),
|
||||
"--format=json"
|
||||
};
|
||||
|
||||
absl::Status status = tool.Run(args, nullptr);
|
||||
EXPECT_TRUE(status.ok()) << status.message();
|
||||
}
|
||||
|
||||
TEST_F(FileSystemToolTest, ReadFileWithLinesLimitWorks) {
|
||||
FileSystemReadTool tool;
|
||||
|
||||
std::vector<std::string> args = {
|
||||
"--path=" + (test_dir_ / "multiline.txt").string(),
|
||||
"--lines=5",
|
||||
"--format=json"
|
||||
};
|
||||
|
||||
absl::Status status = tool.Run(args, nullptr);
|
||||
EXPECT_TRUE(status.ok()) << status.message();
|
||||
}
|
||||
|
||||
TEST_F(FileSystemToolTest, ReadFileWithOffsetWorks) {
|
||||
FileSystemReadTool tool;
|
||||
|
||||
std::vector<std::string> args = {
|
||||
"--path=" + (test_dir_ / "multiline.txt").string(),
|
||||
"--offset=10",
|
||||
"--lines=5",
|
||||
"--format=json"
|
||||
};
|
||||
|
||||
absl::Status status = tool.Run(args, nullptr);
|
||||
EXPECT_TRUE(status.ok()) << status.message();
|
||||
}
|
||||
|
||||
TEST_F(FileSystemToolTest, ReadEmptyFileWorks) {
|
||||
FileSystemReadTool tool;
|
||||
|
||||
std::vector<std::string> args = {
|
||||
"--path=" + (test_dir_ / "empty.txt").string(),
|
||||
"--format=json"
|
||||
};
|
||||
|
||||
absl::Status status = tool.Run(args, nullptr);
|
||||
EXPECT_TRUE(status.ok()) << status.message();
|
||||
}
|
||||
|
||||
TEST_F(FileSystemToolTest, ReadNonExistentFileFails) {
|
||||
FileSystemReadTool tool;
|
||||
|
||||
std::vector<std::string> args = {
|
||||
"--path=" + (test_dir_ / "nonexistent.txt").string(),
|
||||
"--format=json"
|
||||
};
|
||||
|
||||
absl::Status status = tool.Run(args, nullptr);
|
||||
EXPECT_FALSE(status.ok());
|
||||
}
|
||||
|
||||
TEST_F(FileSystemToolTest, ReadToolGetNameReturnsCorrectName) {
|
||||
FileSystemReadTool tool;
|
||||
EXPECT_EQ(tool.GetName(), "filesystem-read");
|
||||
}
|
||||
|
||||
TEST_F(FileSystemToolTest, ReadToolGetUsageContainsPath) {
|
||||
FileSystemReadTool tool;
|
||||
EXPECT_THAT(tool.GetUsage(), HasSubstr("--path"));
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// FileSystemExistsTool Tests
|
||||
// =============================================================================
|
||||
|
||||
TEST_F(FileSystemToolTest, FileExistsWorks) {
|
||||
FileSystemExistsTool tool;
|
||||
|
||||
std::vector<std::string> args = {
|
||||
"--path=" + (test_dir_ / "test.txt").string(),
|
||||
"--format=json"
|
||||
};
|
||||
|
||||
absl::Status status = tool.Run(args, nullptr);
|
||||
EXPECT_TRUE(status.ok()) << status.message();
|
||||
}
|
||||
|
||||
TEST_F(FileSystemToolTest, FileExistsForNonExistentFile) {
|
||||
FileSystemExistsTool tool;
|
||||
|
||||
std::vector<std::string> args = {
|
||||
"--path=" + (test_dir_ / "nonexistent.txt").string(),
|
||||
"--format=json"
|
||||
};
|
||||
|
||||
// This should succeed but report that the file doesn't exist
|
||||
absl::Status status = tool.Run(args, nullptr);
|
||||
EXPECT_TRUE(status.ok()) << status.message();
|
||||
}
|
||||
|
||||
TEST_F(FileSystemToolTest, DirectoryExistsWorks) {
|
||||
FileSystemExistsTool tool;
|
||||
|
||||
std::vector<std::string> args = {
|
||||
"--path=" + test_dir_.string(),
|
||||
"--format=json"
|
||||
};
|
||||
|
||||
absl::Status status = tool.Run(args, nullptr);
|
||||
EXPECT_TRUE(status.ok()) << status.message();
|
||||
}
|
||||
|
||||
TEST_F(FileSystemToolTest, ExistsToolGetNameReturnsCorrectName) {
|
||||
FileSystemExistsTool tool;
|
||||
EXPECT_EQ(tool.GetName(), "filesystem-exists");
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// FileSystemInfoTool Tests
|
||||
// =============================================================================
|
||||
|
||||
TEST_F(FileSystemToolTest, GetFileInfoWorks) {
|
||||
FileSystemInfoTool tool;
|
||||
|
||||
std::vector<std::string> args = {
|
||||
"--path=" + (test_dir_ / "test.txt").string(),
|
||||
"--format=json"
|
||||
};
|
||||
|
||||
absl::Status status = tool.Run(args, nullptr);
|
||||
EXPECT_TRUE(status.ok()) << status.message();
|
||||
}
|
||||
|
||||
TEST_F(FileSystemToolTest, GetDirectoryInfoWorks) {
|
||||
FileSystemInfoTool tool;
|
||||
|
||||
std::vector<std::string> args = {
|
||||
"--path=" + test_dir_.string(),
|
||||
"--format=json"
|
||||
};
|
||||
|
||||
absl::Status status = tool.Run(args, nullptr);
|
||||
EXPECT_TRUE(status.ok()) << status.message();
|
||||
}
|
||||
|
||||
TEST_F(FileSystemToolTest, GetInfoForNestedFile) {
|
||||
FileSystemInfoTool tool;
|
||||
|
||||
std::vector<std::string> args = {
|
||||
"--path=" + (test_dir_ / "subdir" / "nested.txt").string(),
|
||||
"--format=json"
|
||||
};
|
||||
|
||||
absl::Status status = tool.Run(args, nullptr);
|
||||
EXPECT_TRUE(status.ok()) << status.message();
|
||||
}
|
||||
|
||||
TEST_F(FileSystemToolTest, GetInfoForNonExistentPath) {
|
||||
FileSystemInfoTool tool;
|
||||
|
||||
std::vector<std::string> args = {
|
||||
"--path=" + (test_dir_ / "nonexistent.txt").string(),
|
||||
"--format=json"
|
||||
};
|
||||
|
||||
absl::Status status = tool.Run(args, nullptr);
|
||||
EXPECT_FALSE(status.ok());
|
||||
}
|
||||
|
||||
TEST_F(FileSystemToolTest, InfoToolGetNameReturnsCorrectName) {
|
||||
FileSystemInfoTool tool;
|
||||
EXPECT_EQ(tool.GetName(), "filesystem-info");
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Security Tests
|
||||
// =============================================================================
|
||||
|
||||
TEST_F(FileSystemToolTest, PathTraversalBlocked) {
|
||||
FileSystemListTool tool;
|
||||
|
||||
std::vector<std::string> args = {
|
||||
"--path=../../../etc", // Try to escape project directory
|
||||
"--format=json"
|
||||
};
|
||||
|
||||
absl::Status status = tool.Run(args, nullptr);
|
||||
EXPECT_FALSE(status.ok());
|
||||
EXPECT_TRUE(absl::IsInvalidArgument(status) ||
|
||||
absl::IsPermissionDenied(status))
|
||||
<< "Expected InvalidArgument or PermissionDenied, got: " << status.message();
|
||||
}
|
||||
|
||||
TEST_F(FileSystemToolTest, ReadBinaryFileBlocked) {
|
||||
FileSystemReadTool tool;
|
||||
|
||||
// Create a fake binary file
|
||||
std::ofstream binary_file(test_dir_ / "binary.exe", std::ios::binary);
|
||||
char null_bytes[] = {0x00, 0x01, 0x02, 0x03};
|
||||
binary_file.write(null_bytes, sizeof(null_bytes));
|
||||
binary_file.close();
|
||||
|
||||
std::vector<std::string> args = {
|
||||
"--path=" + (test_dir_ / "binary.exe").string(),
|
||||
"--format=json"
|
||||
};
|
||||
|
||||
absl::Status status = tool.Run(args, nullptr);
|
||||
EXPECT_FALSE(status.ok());
|
||||
EXPECT_TRUE(absl::IsInvalidArgument(status))
|
||||
<< "Expected InvalidArgument for binary file, got: " << status.message();
|
||||
}
|
||||
|
||||
TEST_F(FileSystemToolTest, AbsolutePathTraversalBlocked) {
|
||||
FileSystemListTool tool;
|
||||
|
||||
std::vector<std::string> args = {
|
||||
"--path=/etc/passwd", // Try to access system file
|
||||
"--format=json"
|
||||
};
|
||||
|
||||
absl::Status status = tool.Run(args, nullptr);
|
||||
EXPECT_FALSE(status.ok());
|
||||
EXPECT_TRUE(absl::IsPermissionDenied(status) ||
|
||||
absl::IsInvalidArgument(status))
|
||||
<< "Expected security error for system path access, got: " << status.message();
|
||||
}
|
||||
|
||||
TEST_F(FileSystemToolTest, DotDotInPathBlocked) {
|
||||
FileSystemReadTool tool;
|
||||
|
||||
// Try to read a file using path traversal within the test dir
|
||||
std::vector<std::string> args = {
|
||||
"--path=" + (test_dir_ / "subdir" / ".." / ".." / "etc" / "passwd").string(),
|
||||
"--format=json"
|
||||
};
|
||||
|
||||
absl::Status status = tool.Run(args, nullptr);
|
||||
// This should either fail validation or fail to find the file
|
||||
// Either way, it shouldn't succeed in reading /etc/passwd
|
||||
if (status.ok()) {
|
||||
// If it succeeded, make sure it didn't actually read /etc/passwd
|
||||
// by checking the output doesn't contain typical passwd content
|
||||
}
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Edge Case Tests
|
||||
// =============================================================================
|
||||
|
||||
TEST_F(FileSystemToolTest, ListEmptyDirectory) {
|
||||
FileSystemListTool tool;
|
||||
|
||||
// Create an empty directory
|
||||
auto empty_dir = test_dir_ / "empty_dir";
|
||||
std::filesystem::create_directories(empty_dir);
|
||||
|
||||
std::vector<std::string> args = {
|
||||
"--path=" + empty_dir.string(),
|
||||
"--format=json"
|
||||
};
|
||||
|
||||
absl::Status status = tool.Run(args, nullptr);
|
||||
EXPECT_TRUE(status.ok()) << status.message();
|
||||
}
|
||||
|
||||
TEST_F(FileSystemToolTest, ReadFileWithSpecialCharacters) {
|
||||
FileSystemReadTool tool;
|
||||
|
||||
std::vector<std::string> args = {
|
||||
"--path=" + (test_dir_ / "special_chars.txt").string(),
|
||||
"--format=json"
|
||||
};
|
||||
|
||||
absl::Status status = tool.Run(args, nullptr);
|
||||
EXPECT_TRUE(status.ok()) << status.message();
|
||||
}
|
||||
|
||||
TEST_F(FileSystemToolTest, LargeLineCountParameter) {
|
||||
FileSystemReadTool tool;
|
||||
|
||||
std::vector<std::string> args = {
|
||||
"--path=" + (test_dir_ / "multiline.txt").string(),
|
||||
"--lines=999999", // Very large, should be clamped or handled gracefully
|
||||
"--format=json"
|
||||
};
|
||||
|
||||
absl::Status status = tool.Run(args, nullptr);
|
||||
EXPECT_TRUE(status.ok()) << status.message();
|
||||
}
|
||||
|
||||
TEST_F(FileSystemToolTest, ZeroLineCountParameter) {
|
||||
FileSystemReadTool tool;
|
||||
|
||||
std::vector<std::string> args = {
|
||||
"--path=" + (test_dir_ / "multiline.txt").string(),
|
||||
"--lines=0", // Zero lines requested
|
||||
"--format=json"
|
||||
};
|
||||
|
||||
absl::Status status = tool.Run(args, nullptr);
|
||||
// This should either return empty content or use a default value
|
||||
EXPECT_TRUE(status.ok()) << status.message();
|
||||
}
|
||||
|
||||
TEST_F(FileSystemToolTest, NegativeOffsetParameter) {
|
||||
FileSystemReadTool tool;
|
||||
|
||||
std::vector<std::string> args = {
|
||||
"--path=" + (test_dir_ / "multiline.txt").string(),
|
||||
"--offset=-5", // Negative offset
|
||||
"--format=json"
|
||||
};
|
||||
|
||||
absl::Status status = tool.Run(args, nullptr);
|
||||
// Should handle gracefully - either fail or treat as 0
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Text Format Output Tests
|
||||
// =============================================================================
|
||||
|
||||
TEST_F(FileSystemToolTest, ReadTextFormat) {
|
||||
FileSystemReadTool tool;
|
||||
|
||||
std::vector<std::string> args = {
|
||||
"--path=" + (test_dir_ / "test.txt").string(),
|
||||
"--format=text"
|
||||
};
|
||||
|
||||
absl::Status status = tool.Run(args, nullptr);
|
||||
EXPECT_TRUE(status.ok()) << status.message();
|
||||
}
|
||||
|
||||
TEST_F(FileSystemToolTest, InfoTextFormat) {
|
||||
FileSystemInfoTool tool;
|
||||
|
||||
std::vector<std::string> args = {
|
||||
"--path=" + (test_dir_ / "test.txt").string(),
|
||||
"--format=text"
|
||||
};
|
||||
|
||||
absl::Status status = tool.Run(args, nullptr);
|
||||
EXPECT_TRUE(status.ok()) << status.message();
|
||||
}
|
||||
|
||||
TEST_F(FileSystemToolTest, ExistsTextFormat) {
|
||||
FileSystemExistsTool tool;
|
||||
|
||||
std::vector<std::string> args = {
|
||||
"--path=" + (test_dir_ / "test.txt").string(),
|
||||
"--format=text"
|
||||
};
|
||||
|
||||
absl::Status status = tool.Run(args, nullptr);
|
||||
EXPECT_TRUE(status.ok()) << status.message();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace tools
|
||||
} // namespace agent
|
||||
} // namespace cli
|
||||
} // namespace yaze
|
||||
Reference in New Issue
Block a user