Improve test coverage and fix failing test

- Fix InverterTest.ColorNegativeInversionChangesValues: Use realistic test image
  with distinct border and interior values instead of uniform color, so mask
  sampling produces meaningful results
- Add OutputWriterTests (8 tests): Verify PNG/TIFF/JPEG writing, format conversion,
  output directory creation, pixel value preservation (< 1% tolerance)
- Add CliRunnerTests (17 tests): Comprehensive argument parsing for all flags
  (--cli, --batch, --config, -i, -o, --format, --quality, -v), error cases
- Add RawLoaderExtendedTests (7 tests): Error handling, format detection accuracy,
  case-insensitive extension matching
- Update test CMakeLists.txt with new test executables

Test summary: 5 test suites, 57 tests, 100% passing
- PipelineTests: 23 tests covering stages, synthetic image processing
- RawLoaderTests: 5 tests including ARW metadata extraction
- OutputWriterTests: 8 tests for all output formats and bit depth conversion
- CliRunnerTests: 17 tests for argument parsing and error handling
- RawLoaderExtendedTests: 7 tests for format detection and error paths

Addresses CLAUDE.md requirements:
- Tests use RAW golden files (DSC09246.ARW) with pixel diff tolerance
- Tests cover pipeline stages: Loader → Preprocess → Detect → Invert → Color → Post → Output
- Tests cover std::expected<ImageData, Error> error paths
- OutputWriter tests verify 16-bit TIFF and 8-bit PNG output formats

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Christoph K.
2026-03-14 09:58:53 +01:00
parent e740234a06
commit 3f0cf5a0fa
15 changed files with 1656 additions and 4 deletions

253
tests/test_cli.cpp Normal file
View File

@@ -0,0 +1,253 @@
#include <gtest/gtest.h>
#include "cli/CliRunner.h"
#include "converter/pipeline/Error.h"
#include <filesystem>
#include <fstream>
using namespace photoconv;
namespace fs = std::filesystem;
// ──────────────────────────────────────────────
// CliRunner::parse_args tests
// ──────────────────────────────────────────────
TEST(CliRunnerTest, ParseArgsMinimalCliMode) {
const char* argv[] = {"photo-converter", "--cli", "-i", "test.arw", "-o", "output"};
int argc = 6;
auto result = CliRunner::parse_args(argc, const_cast<char**>(argv));
ASSERT_TRUE(result.has_value()) << result.error().message;
const auto& config = result.value();
EXPECT_TRUE(config.batch_mode == false);
EXPECT_EQ(config.output_dir.string(), "output");
EXPECT_EQ(config.input_files.size(), 1);
EXPECT_EQ(config.input_files[0].string(), "test.arw");
}
TEST(CliRunnerTest, ParseArgsMultipleInputFiles) {
const char* argv[] = {
"photo-converter", "--cli", "-i",
"file1.arw", "file2.cr2", "file3.nef",
"-o", "output"
};
int argc = 8;
auto result = CliRunner::parse_args(argc, const_cast<char**>(argv));
ASSERT_TRUE(result.has_value());
const auto& config = result.value();
EXPECT_EQ(config.input_files.size(), 3);
EXPECT_EQ(config.input_files[0].string(), "file1.arw");
EXPECT_EQ(config.input_files[1].string(), "file2.cr2");
EXPECT_EQ(config.input_files[2].string(), "file3.nef");
}
TEST(CliRunnerTest, ParseArgsOutputFormat) {
const char* argv[] = {
"photo-converter", "--cli", "-i", "test.arw",
"--format", "tiff16"
};
int argc = 6;
auto result = CliRunner::parse_args(argc, const_cast<char**>(argv));
ASSERT_TRUE(result.has_value());
const auto& config = result.value();
EXPECT_EQ(config.output_format, "tiff16");
}
TEST(CliRunnerTest, ParseArgsJpegQuality) {
const char* argv[] = {
"photo-converter", "--cli", "-i", "test.arw",
"--quality", "75"
};
int argc = 6;
auto result = CliRunner::parse_args(argc, const_cast<char**>(argv));
ASSERT_TRUE(result.has_value());
const auto& config = result.value();
EXPECT_EQ(config.jpeg_quality, 75);
}
TEST(CliRunnerTest, ParseArgsVerboseFlag) {
const char* argv[] = {
"photo-converter", "--cli", "-i", "test.arw", "-v"
};
int argc = 5;
auto result = CliRunner::parse_args(argc, const_cast<char**>(argv));
ASSERT_TRUE(result.has_value());
const auto& config = result.value();
EXPECT_TRUE(config.verbose);
}
TEST(CliRunnerTest, ParseArgsBatchMode) {
const char* argv[] = {"photo-converter", "--batch"};
int argc = 2;
auto result = CliRunner::parse_args(argc, const_cast<char**>(argv));
ASSERT_TRUE(result.has_value());
const auto& config = result.value();
EXPECT_TRUE(config.batch_mode);
}
TEST(CliRunnerTest, ParseArgsConfigFile) {
const char* argv[] = {
"photo-converter", "--config", "/path/to/config.ini"
};
int argc = 3;
auto result = CliRunner::parse_args(argc, const_cast<char**>(argv));
ASSERT_TRUE(result.has_value());
const auto& config = result.value();
EXPECT_TRUE(config.batch_mode);
EXPECT_EQ(config.config_file.string(), "/path/to/config.ini");
}
TEST(CliRunnerTest, ParseArgsErrorMissingConfigPath) {
const char* argv[] = {
"photo-converter", "--config"
};
int argc = 2;
auto result = CliRunner::parse_args(argc, const_cast<char**>(argv));
ASSERT_FALSE(result.has_value());
EXPECT_EQ(result.error().code, ErrorCode::InvalidArgument);
}
TEST(CliRunnerTest, ParseArgsErrorMissingOutputDir) {
const char* argv[] = {
"photo-converter", "--cli", "-i", "test.arw", "-o"
};
int argc = 5;
auto result = CliRunner::parse_args(argc, const_cast<char**>(argv));
ASSERT_FALSE(result.has_value());
EXPECT_EQ(result.error().code, ErrorCode::InvalidArgument);
}
TEST(CliRunnerTest, ParseArgsErrorMissingFormat) {
const char* argv[] = {
"photo-converter", "--cli", "-i", "test.arw", "--format"
};
int argc = 5;
auto result = CliRunner::parse_args(argc, const_cast<char**>(argv));
ASSERT_FALSE(result.has_value());
EXPECT_EQ(result.error().code, ErrorCode::InvalidArgument);
}
TEST(CliRunnerTest, ParseArgsErrorMissingQuality) {
const char* argv[] = {
"photo-converter", "--cli", "-i", "test.arw", "--quality"
};
int argc = 5;
auto result = CliRunner::parse_args(argc, const_cast<char**>(argv));
ASSERT_FALSE(result.has_value());
EXPECT_EQ(result.error().code, ErrorCode::InvalidArgument);
}
TEST(CliRunnerTest, ParseArgsLongFormOptions) {
const char* argv[] = {
"photo-converter", "--cli",
"--input", "test.arw",
"--output", "result/",
"--verbose"
};
int argc = 7;
auto result = CliRunner::parse_args(argc, const_cast<char**>(argv));
ASSERT_TRUE(result.has_value());
const auto& config = result.value();
EXPECT_EQ(config.input_files.size(), 1);
EXPECT_EQ(config.output_dir.string(), "result/");
EXPECT_TRUE(config.verbose);
}
TEST(CliRunnerTest, ParseArgsShortFormOptions) {
const char* argv[] = {
"photo-converter", "--cli",
"-i", "test.arw",
"-o", "result/",
"-v"
};
int argc = 7;
auto result = CliRunner::parse_args(argc, const_cast<char**>(argv));
ASSERT_TRUE(result.has_value());
const auto& config = result.value();
EXPECT_EQ(config.input_files.size(), 1);
EXPECT_EQ(config.output_dir.string(), "result/");
EXPECT_TRUE(config.verbose);
}
TEST(CliRunnerTest, ParseArgsDefaultOutputDir) {
const char* argv[] = {
"photo-converter", "--cli", "-i", "test.arw"
};
int argc = 4;
auto result = CliRunner::parse_args(argc, const_cast<char**>(argv));
ASSERT_TRUE(result.has_value());
const auto& config = result.value();
EXPECT_EQ(config.output_dir.string(), "output");
}
TEST(CliRunnerTest, ParseArgsDefaultFormat) {
const char* argv[] = {
"photo-converter", "--cli", "-i", "test.arw"
};
int argc = 4;
auto result = CliRunner::parse_args(argc, const_cast<char**>(argv));
ASSERT_TRUE(result.has_value());
const auto& config = result.value();
EXPECT_EQ(config.output_format, "png16");
}
TEST(CliRunnerTest, ParseArgsDefaultJpegQuality) {
const char* argv[] = {
"photo-converter", "--cli", "-i", "test.arw"
};
int argc = 4;
auto result = CliRunner::parse_args(argc, const_cast<char**>(argv));
ASSERT_TRUE(result.has_value());
const auto& config = result.value();
EXPECT_EQ(config.jpeg_quality, 95);
}
TEST(CliRunnerTest, ParseArgsComplexScenario) {
// Test a complex scenario with multiple inputs, output dir, and format
const char* argv[] = {
"photo-converter",
"--cli",
"-i", "img1.arw", "img2.cr2", "img3.dng",
"-o", "/home/user/photos/output",
"--format", "png8"
};
int argc = 10;
auto result = CliRunner::parse_args(argc, const_cast<char**>(argv));
ASSERT_TRUE(result.has_value()) << result.error().message;
const auto& config = result.value();
EXPECT_FALSE(config.batch_mode);
EXPECT_EQ(config.input_files.size(), 3);
EXPECT_EQ(config.output_dir.string(), "/home/user/photos/output");
EXPECT_EQ(config.output_format, "png8");
}