cli: harden tool output and tests
This commit is contained in:
@@ -23,6 +23,8 @@ namespace tools {
|
|||||||
*/
|
*/
|
||||||
class FileSystemToolBase : public resources::CommandHandler {
|
class FileSystemToolBase : public resources::CommandHandler {
|
||||||
protected:
|
protected:
|
||||||
|
bool RequiresRom() const override { return false; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Validate and normalize a path for safe access
|
* @brief Validate and normalize a path for safe access
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -212,6 +212,13 @@ int VisualAnalysisBase::GetTileCountForSheet(int sheet_index) const {
|
|||||||
std::string VisualAnalysisBase::FormatMatchesAsJson(
|
std::string VisualAnalysisBase::FormatMatchesAsJson(
|
||||||
const std::vector<TileSimilarityMatch>& matches) const {
|
const std::vector<TileSimilarityMatch>& matches) const {
|
||||||
std::ostringstream json;
|
std::ostringstream json;
|
||||||
|
if (matches.empty()) {
|
||||||
|
json << "{\n \"matches\": [],\n";
|
||||||
|
json << " \"total_matches\": 0\n";
|
||||||
|
json << "}\n";
|
||||||
|
return json.str();
|
||||||
|
}
|
||||||
|
|
||||||
json << "{\n \"matches\": [\n";
|
json << "{\n \"matches\": [\n";
|
||||||
|
|
||||||
for (size_t i = 0; i < matches.size(); ++i) {
|
for (size_t i = 0; i < matches.size(); ++i) {
|
||||||
@@ -238,6 +245,14 @@ std::string VisualAnalysisBase::FormatMatchesAsJson(
|
|||||||
std::string VisualAnalysisBase::FormatRegionsAsJson(
|
std::string VisualAnalysisBase::FormatRegionsAsJson(
|
||||||
const std::vector<UnusedRegion>& regions) const {
|
const std::vector<UnusedRegion>& regions) const {
|
||||||
std::ostringstream json;
|
std::ostringstream json;
|
||||||
|
if (regions.empty()) {
|
||||||
|
json << "{\n \"unused_regions\": [],\n";
|
||||||
|
json << " \"total_regions\": 0,\n";
|
||||||
|
json << " \"total_free_tiles\": 0\n";
|
||||||
|
json << "}\n";
|
||||||
|
return json.str();
|
||||||
|
}
|
||||||
|
|
||||||
json << "{\n \"unused_regions\": [\n";
|
json << "{\n \"unused_regions\": [\n";
|
||||||
|
|
||||||
for (size_t i = 0; i < regions.size(); ++i) {
|
for (size_t i = 0; i < regions.size(); ++i) {
|
||||||
@@ -939,4 +954,3 @@ double ComputeSSIM(const std::vector<uint8_t>& tile_a,
|
|||||||
} // namespace agent
|
} // namespace agent
|
||||||
} // namespace cli
|
} // namespace cli
|
||||||
} // namespace yaze
|
} // namespace yaze
|
||||||
|
|
||||||
|
|||||||
@@ -270,8 +270,15 @@ void OutputFormatter::BeginObject(const std::string& title) {
|
|||||||
|
|
||||||
void OutputFormatter::EndObject() {
|
void OutputFormatter::EndObject() {
|
||||||
if (IsJson()) {
|
if (IsJson()) {
|
||||||
buffer_ += "\n";
|
|
||||||
indent_level_--;
|
indent_level_--;
|
||||||
|
if (first_field_) {
|
||||||
|
if (!buffer_.empty() && buffer_.back() == '\n') {
|
||||||
|
buffer_.pop_back();
|
||||||
|
}
|
||||||
|
buffer_ += "}";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
buffer_ += "\n";
|
||||||
AddIndent();
|
AddIndent();
|
||||||
buffer_ += "}";
|
buffer_ += "}";
|
||||||
}
|
}
|
||||||
@@ -292,6 +299,10 @@ void OutputFormatter::AddField(const std::string& key,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OutputFormatter::AddField(const std::string& key, const char* value) {
|
||||||
|
AddField(key, value != nullptr ? std::string(value) : std::string());
|
||||||
|
}
|
||||||
|
|
||||||
void OutputFormatter::AddField(const std::string& key, int value) {
|
void OutputFormatter::AddField(const std::string& key, int value) {
|
||||||
if (IsJson()) {
|
if (IsJson()) {
|
||||||
if (!first_field_) {
|
if (!first_field_) {
|
||||||
@@ -368,8 +379,15 @@ void OutputFormatter::EndArray() {
|
|||||||
in_array_ = false;
|
in_array_ = false;
|
||||||
|
|
||||||
if (IsJson()) {
|
if (IsJson()) {
|
||||||
buffer_ += "\n";
|
|
||||||
indent_level_--;
|
indent_level_--;
|
||||||
|
if (array_item_count_ == 0) {
|
||||||
|
if (!buffer_.empty() && buffer_.back() == '\n') {
|
||||||
|
buffer_.pop_back();
|
||||||
|
}
|
||||||
|
buffer_ += "]";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
buffer_ += "\n";
|
||||||
AddIndent();
|
AddIndent();
|
||||||
buffer_ += "]";
|
buffer_ += "]";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -144,6 +144,7 @@ class OutputFormatter {
|
|||||||
* @brief Add a key-value pair
|
* @brief Add a key-value pair
|
||||||
*/
|
*/
|
||||||
void AddField(const std::string& key, const std::string& value);
|
void AddField(const std::string& key, const std::string& value);
|
||||||
|
void AddField(const std::string& key, const char* value);
|
||||||
void AddField(const std::string& key, int value);
|
void AddField(const std::string& key, int value);
|
||||||
void AddField(const std::string& key, uint64_t value);
|
void AddField(const std::string& key, uint64_t value);
|
||||||
void AddField(const std::string& key, bool value);
|
void AddField(const std::string& key, bool value);
|
||||||
|
|||||||
@@ -239,10 +239,10 @@ TEST_F(OutputFormatterTest, GeneratesValidText) {
|
|||||||
std::string output = formatter.GetOutput();
|
std::string output = formatter.GetOutput();
|
||||||
|
|
||||||
EXPECT_THAT(output, ::testing::HasSubstr("=== Test Object ==="));
|
EXPECT_THAT(output, ::testing::HasSubstr("=== Test Object ==="));
|
||||||
EXPECT_THAT(output, ::testing::HasSubstr("string_field : value"));
|
EXPECT_THAT(output, ::testing::HasSubstr("string_field : value"));
|
||||||
EXPECT_THAT(output, ::testing::HasSubstr("int_field : 42"));
|
EXPECT_THAT(output, ::testing::HasSubstr("int_field : 42"));
|
||||||
EXPECT_THAT(output, ::testing::HasSubstr("bool_field : yes"));
|
EXPECT_THAT(output, ::testing::HasSubstr("bool_field : yes"));
|
||||||
EXPECT_THAT(output, ::testing::HasSubstr("hex_field : 0x1234"));
|
EXPECT_THAT(output, ::testing::HasSubstr("hex_field : 0x1234"));
|
||||||
EXPECT_THAT(output, ::testing::HasSubstr("array_field:"));
|
EXPECT_THAT(output, ::testing::HasSubstr("array_field:"));
|
||||||
EXPECT_THAT(output, ::testing::HasSubstr("- item1"));
|
EXPECT_THAT(output, ::testing::HasSubstr("- item1"));
|
||||||
EXPECT_THAT(output, ::testing::HasSubstr("- item2"));
|
EXPECT_THAT(output, ::testing::HasSubstr("- item2"));
|
||||||
|
|||||||
@@ -35,12 +35,27 @@ TEST(ResourceCatalogTest, RomSchemaExposesActionsAndMetadata) {
|
|||||||
ASSERT_TRUE(rom_schema.ok());
|
ASSERT_TRUE(rom_schema.ok());
|
||||||
|
|
||||||
const auto& actions = rom_schema->actions;
|
const auto& actions = rom_schema->actions;
|
||||||
ASSERT_EQ(actions.size(), 3);
|
ASSERT_EQ(actions.size(), 4);
|
||||||
EXPECT_EQ(actions[0].name, "validate");
|
auto has_info = std::find_if(
|
||||||
EXPECT_FALSE(actions[0].effects.empty());
|
actions.begin(), actions.end(),
|
||||||
EXPECT_FALSE(actions[0].returns.empty());
|
[](const auto& action) { return action.name == "info"; });
|
||||||
EXPECT_EQ(actions[1].name, "diff");
|
EXPECT_NE(has_info, actions.end());
|
||||||
EXPECT_EQ(actions[2].name, "generate-golden");
|
auto has_validate = std::find_if(
|
||||||
|
actions.begin(), actions.end(),
|
||||||
|
[](const auto& action) { return action.name == "validate"; });
|
||||||
|
EXPECT_NE(has_validate, actions.end());
|
||||||
|
if (has_validate != actions.end()) {
|
||||||
|
EXPECT_FALSE(has_validate->effects.empty());
|
||||||
|
EXPECT_FALSE(has_validate->returns.empty());
|
||||||
|
}
|
||||||
|
auto has_diff = std::find_if(
|
||||||
|
actions.begin(), actions.end(),
|
||||||
|
[](const auto& action) { return action.name == "diff"; });
|
||||||
|
EXPECT_NE(has_diff, actions.end());
|
||||||
|
auto has_generate = std::find_if(
|
||||||
|
actions.begin(), actions.end(),
|
||||||
|
[](const auto& action) { return action.name == "generate-golden"; });
|
||||||
|
EXPECT_NE(has_generate, actions.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(ResourceCatalogTest, PatchSchemaIncludesAsarAndCreateActions) {
|
TEST(ResourceCatalogTest, PatchSchemaIncludesAsarAndCreateActions) {
|
||||||
|
|||||||
@@ -235,8 +235,8 @@ TEST_F(ResourcePanelTest, ResourceLifecycle) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResourcePanelTest, AlwaysEditorBound) {
|
TEST_F(ResourcePanelTest, AlwaysEditorBound) {
|
||||||
// Resource panels are always EditorBound
|
// Resource panels are CrossEditor by default
|
||||||
EXPECT_EQ(panel_->GetPanelCategory(), PanelCategory::EditorBound);
|
EXPECT_EQ(panel_->GetPanelCategory(), PanelCategory::CrossEditor);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ResourcePanelTest, AllowMultipleInstancesDefault) {
|
TEST_F(ResourcePanelTest, AllowMultipleInstancesDefault) {
|
||||||
|
|||||||
@@ -26,12 +26,25 @@ namespace {
|
|||||||
using ::testing::HasSubstr;
|
using ::testing::HasSubstr;
|
||||||
using ::testing::Not;
|
using ::testing::Not;
|
||||||
|
|
||||||
|
std::filesystem::path FindProjectRoot() {
|
||||||
|
std::filesystem::path root = std::filesystem::current_path();
|
||||||
|
while (!root.empty() && root != root.root_path()) {
|
||||||
|
if (std::filesystem::exists(root / "CMakeLists.txt") &&
|
||||||
|
std::filesystem::exists(root / "src" / "cli")) {
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
root = root.parent_path();
|
||||||
|
}
|
||||||
|
return std::filesystem::current_path();
|
||||||
|
}
|
||||||
|
|
||||||
// Test fixture for FileSystemTool tests
|
// Test fixture for FileSystemTool tests
|
||||||
class FileSystemToolTest : public ::testing::Test {
|
class FileSystemToolTest : public ::testing::Test {
|
||||||
protected:
|
protected:
|
||||||
void SetUp() override {
|
void SetUp() override {
|
||||||
// Create test directories and files
|
// Create test directories and files
|
||||||
test_dir_ = std::filesystem::temp_directory_path() / "yaze_fs_tool_test";
|
test_dir_ =
|
||||||
|
FindProjectRoot() / "test_temp" / "yaze_fs_tool_test";
|
||||||
std::filesystem::create_directories(test_dir_ / "subdir");
|
std::filesystem::create_directories(test_dir_ / "subdir");
|
||||||
|
|
||||||
// Create test files
|
// Create test files
|
||||||
|
|||||||
@@ -166,7 +166,7 @@ TEST(MemoryAnalyzeToolTest, GetUsageContainsLength) {
|
|||||||
|
|
||||||
TEST(MemoryAnalyzeToolTest, GetDescriptionIsNotEmpty) {
|
TEST(MemoryAnalyzeToolTest, GetDescriptionIsNotEmpty) {
|
||||||
MemoryAnalyzeTool tool;
|
MemoryAnalyzeTool tool;
|
||||||
EXPECT_THAT(tool.GetDescription(), Not(HasSubstr("")));
|
EXPECT_FALSE(tool.GetDescription().empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(MemoryAnalyzeToolTest, DoesNotRequireLabels) {
|
TEST(MemoryAnalyzeToolTest, DoesNotRequireLabels) {
|
||||||
@@ -197,7 +197,7 @@ TEST(MemorySearchToolTest, GetUsageContainsStartEnd) {
|
|||||||
|
|
||||||
TEST(MemorySearchToolTest, GetDescriptionIsNotEmpty) {
|
TEST(MemorySearchToolTest, GetDescriptionIsNotEmpty) {
|
||||||
MemorySearchTool tool;
|
MemorySearchTool tool;
|
||||||
EXPECT_THAT(tool.GetDescription(), Not(HasSubstr("")));
|
EXPECT_FALSE(tool.GetDescription().empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(MemorySearchToolTest, DoesNotRequireLabels) {
|
TEST(MemorySearchToolTest, DoesNotRequireLabels) {
|
||||||
@@ -226,7 +226,7 @@ TEST(MemoryCompareToolTest, GetUsageContainsExpected) {
|
|||||||
|
|
||||||
TEST(MemoryCompareToolTest, GetDescriptionIsNotEmpty) {
|
TEST(MemoryCompareToolTest, GetDescriptionIsNotEmpty) {
|
||||||
MemoryCompareTool tool;
|
MemoryCompareTool tool;
|
||||||
EXPECT_THAT(tool.GetDescription(), Not(HasSubstr("")));
|
EXPECT_FALSE(tool.GetDescription().empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(MemoryCompareToolTest, DoesNotRequireLabels) {
|
TEST(MemoryCompareToolTest, DoesNotRequireLabels) {
|
||||||
@@ -250,7 +250,7 @@ TEST(MemoryCheckToolTest, GetUsageContainsRegion) {
|
|||||||
|
|
||||||
TEST(MemoryCheckToolTest, GetDescriptionIsNotEmpty) {
|
TEST(MemoryCheckToolTest, GetDescriptionIsNotEmpty) {
|
||||||
MemoryCheckTool tool;
|
MemoryCheckTool tool;
|
||||||
EXPECT_THAT(tool.GetDescription(), Not(HasSubstr("")));
|
EXPECT_FALSE(tool.GetDescription().empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(MemoryCheckToolTest, DoesNotRequireLabels) {
|
TEST(MemoryCheckToolTest, DoesNotRequireLabels) {
|
||||||
@@ -279,7 +279,7 @@ TEST(MemoryRegionsToolTest, GetUsageContainsFormat) {
|
|||||||
|
|
||||||
TEST(MemoryRegionsToolTest, GetDescriptionIsNotEmpty) {
|
TEST(MemoryRegionsToolTest, GetDescriptionIsNotEmpty) {
|
||||||
MemoryRegionsTool tool;
|
MemoryRegionsTool tool;
|
||||||
EXPECT_THAT(tool.GetDescription(), Not(HasSubstr("")));
|
EXPECT_FALSE(tool.GetDescription().empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(MemoryRegionsToolTest, DoesNotRequireLabels) {
|
TEST(MemoryRegionsToolTest, DoesNotRequireLabels) {
|
||||||
@@ -359,4 +359,3 @@ TEST(ALTTPMemoryMapTest, SRAMRegionSizeIsCorrect) {
|
|||||||
} // namespace agent
|
} // namespace agent
|
||||||
} // namespace cli
|
} // namespace cli
|
||||||
} // namespace yaze
|
} // namespace yaze
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user