Skip to content

Commit abb9c8a

Browse files
Merge branch 'main' into ms-250908
2 parents 103f219 + 2cca6c5 commit abb9c8a

File tree

1 file changed

+238
-0
lines changed

1 file changed

+238
-0
lines changed

tests/test_image_converter.cpp

Lines changed: 238 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <filesystem>
1212
#include <fstream>
1313
#include <iostream>
14+
#include <nlohmann/json.hpp>
1415
#include <vector>
1516
#include <sys/stat.h> // for mkfifo
1617
#include <ctime>
@@ -60,6 +61,10 @@ class TestDirectory
6061
std::to_string( std::time( nullptr ) ) ) )
6162
.string();
6263
std::filesystem::create_directories( test_dir );
64+
65+
// Create database directory for test data
66+
database_dir = test_dir + "/test-database";
67+
std::filesystem::create_directories( database_dir );
6368
}
6469

6570
~TestDirectory() { std::filesystem::remove_all( test_dir ); }
@@ -69,6 +74,7 @@ class TestDirectory
6974
TestDirectory &operator=( const TestDirectory & ) = delete;
7075

7176
const std::string &path() const { return test_dir; }
77+
const std::string &get_database_path() const { return database_dir; }
7278

7379
void create_test_files()
7480
{
@@ -119,8 +125,51 @@ class TestDirectory
119125
}
120126
}
121127

128+
/// Creates a test data file (camera or illuminant) with the specified header data
129+
/// @param type The type of test data to create (e.g. camera or illuminant)
130+
/// @param header_data JSON object containing the header data to include
131+
/// @return The full path to the created file
132+
std::string create_test_data_file(
133+
const std::string &type, const nlohmann::json &header_data )
134+
{
135+
// Generate random filename
136+
static int file_counter = 0;
137+
std::string filename = "test_data_" + std::to_string( ++file_counter ) +
138+
"_" + std::to_string( std::time( nullptr ) ) +
139+
".json";
140+
141+
// Create target directory dynamically based on type
142+
std::string target_dir = database_dir + "/" + type;
143+
std::filesystem::create_directories( target_dir );
144+
std::string file_path = target_dir + "/" + filename;
145+
146+
// Create JSON object using nlohmann/json
147+
nlohmann::json json_data;
148+
149+
// Start with default header and merge user data
150+
nlohmann::json header = header_data;
151+
152+
// Build spectral_data object
153+
nlohmann::json spectral_data = { { "units", "relative" },
154+
{ "index",
155+
{ { "main", { "R", "G", "B" } } } },
156+
{ "data", nlohmann::json::object() } };
157+
158+
// Assemble final JSON
159+
json_data["header"] = header;
160+
json_data["spectral_data"] = spectral_data;
161+
162+
// Write to file with pretty formatting
163+
std::ofstream file( file_path );
164+
file << json_data.dump( 4 ) << std::endl;
165+
file.close();
166+
167+
return file_path;
168+
}
169+
122170
private:
123171
std::string test_dir;
172+
std::string database_dir;
124173
};
125174

126175
/// Verifies that collect_image_files can traverse a directory, identify valid RAW image files,
@@ -522,6 +571,191 @@ void test_fix_metadata_unsupported_type()
522571
OIIO_CHECK_EQUAL( spec.find_attribute( "Make" ), nullptr );
523572
}
524573

574+
/// Helper function to set up test environment and capture output for parse_parameters tests
575+
struct ParseParametersTestResult
576+
{
577+
bool success;
578+
std::string output;
579+
};
580+
581+
/// Executes a parse_parameters test with the given command-line arguments and captures its output.
582+
///
583+
/// This helper function encapsulates all the common setup required for testing ImageConverter::parse_parameters,
584+
/// including environment configuration, argument parsing, stdout capture, and cleanup.
585+
///
586+
/// @param args Vector of command-line arguments to pass to parse_parameters (excluding program name).
587+
/// For example, {"--list-cameras"} or {"--list-illuminants", "--verbose"}.
588+
/// @param database_path Path to the test database directory (optional, uses default if not provided)
589+
///
590+
/// @return ParseParametersTestResult containing:
591+
/// - success: true if parse_parameters executed successfully, false if argument parsing failed
592+
/// - output: captured stdout output from the parse_parameters execution
593+
ParseParametersTestResult run_parse_parameters_test(
594+
const std::vector<std::string> &args,
595+
const std::string &database_path = "" )
596+
{
597+
// Set up test data path to use the provided database path or default
598+
set_env_var( "RAWTOACES_DATA_PATH", database_path.c_str() );
599+
600+
// Create ImageConverter instance
601+
rta::util::ImageConverter converter;
602+
603+
// Create argument parser and initialize it
604+
OIIO::ArgParse arg_parser;
605+
converter.init_parser( arg_parser );
606+
607+
// Convert args to char* array for parsing
608+
std::vector<const char *> argv;
609+
argv.push_back( "rawtoaces" ); // Program name
610+
for ( const auto &arg: args )
611+
{
612+
argv.push_back( arg.c_str() );
613+
}
614+
615+
// Parse the arguments
616+
int parse_result =
617+
arg_parser.parse_args( static_cast<int>( argv.size() ), argv.data() );
618+
if ( parse_result != 0 )
619+
{
620+
unset_env_var( "RAWTOACES_DATA_PATH" );
621+
return { false, "" };
622+
}
623+
624+
// Capture stdout to verify the output
625+
std::ostringstream captured_output;
626+
std::streambuf *original_cout = std::cout.rdbuf();
627+
std::cout.rdbuf( captured_output.rdbuf() );
628+
629+
// Call parse_parameters
630+
bool result = converter.parse_parameters( arg_parser );
631+
632+
// Restore original cout
633+
std::cout.rdbuf( original_cout );
634+
635+
// Clean up environment variable
636+
unset_env_var( "RAWTOACES_DATA_PATH" );
637+
638+
return { result, captured_output.str() };
639+
}
640+
641+
/// This test verifies that when --list-cameras is provided, the method
642+
/// calls supported_cameras() and outputs the camera list, then exits
643+
void test_parse_parameters_list_cameras()
644+
{
645+
std::cout << std::endl
646+
<< "test_parse_parameters_list_cameras()" << std::endl;
647+
648+
// Create test directory with dynamic database
649+
TestDirectory test_dir;
650+
651+
// Create test camera data files
652+
test_dir.create_test_data_file(
653+
"camera", { { "manufacturer", "Canon" }, { "model", "EOS R6" } } );
654+
test_dir.create_test_data_file(
655+
"camera", { { "manufacturer", "Mamiya" }, { "model", "Mamiya 7" } } );
656+
657+
// Run the test with --list-cameras argument using the dynamic database
658+
auto result = run_parse_parameters_test(
659+
{ "--list-cameras" }, test_dir.get_database_path() );
660+
661+
// The method should return true (though it calls exit in real usage)
662+
OIIO_CHECK_EQUAL( result.success, true );
663+
664+
// Verify the output contains expected camera list information
665+
OIIO_CHECK_EQUAL(
666+
result.output.find(
667+
"Spectral sensitivity data is available for the following cameras:" ) !=
668+
std::string::npos,
669+
true );
670+
671+
// Verify that actual camera names from test data are present
672+
// The format is "manufacturer / model" as defined in supported_cameras()
673+
OIIO_CHECK_EQUAL(
674+
result.output.find( "Canon / EOS R6" ) != std::string::npos, true );
675+
OIIO_CHECK_EQUAL(
676+
result.output.find( "Mamiya / Mamiya 7" ) != std::string::npos, true );
677+
678+
// Count occurrences of " / " to verify we have 2 camera entries
679+
size_t camera_count = 0;
680+
size_t pos = 0;
681+
while ( ( pos = result.output.find( " / ", pos ) ) != std::string::npos )
682+
{
683+
camera_count++;
684+
pos += 3; // Move past " / "
685+
}
686+
OIIO_CHECK_EQUAL( camera_count, 2 );
687+
}
688+
689+
/// This test verifies that when --list-illuminants is provided, the method
690+
/// calls supported_illuminants() and outputs the illuminant list, then exits
691+
void test_parse_parameters_list_illuminants()
692+
{
693+
std::cout << std::endl
694+
<< "test_parse_parameters_list_illuminants()" << std::endl;
695+
696+
// Create test directory with dynamic database
697+
TestDirectory test_dir;
698+
699+
// Create test illuminant data file
700+
test_dir.create_test_data_file(
701+
"illuminant", { { "illuminant", "my-illuminant" } } );
702+
703+
// Run the test with --list-illuminants argument using the dynamic database
704+
auto result = run_parse_parameters_test(
705+
{ "--list-illuminants" }, test_dir.get_database_path() );
706+
707+
// The method should return true (though it calls exit in real usage)
708+
OIIO_CHECK_EQUAL( result.success, true );
709+
710+
// Verify the output contains expected illuminant list information
711+
OIIO_CHECK_EQUAL(
712+
result.output.find( "The following illuminants are supported:" ) !=
713+
std::string::npos,
714+
true );
715+
716+
// Verify that actual illuminant names from test data are present
717+
// The hardcoded illuminant types should be present
718+
OIIO_CHECK_EQUAL(
719+
result.output.find( "Day-light (e.g., D60, D6025)" ) !=
720+
std::string::npos,
721+
true );
722+
OIIO_CHECK_EQUAL(
723+
result.output.find( "Blackbody (e.g., 3200K)" ) != std::string::npos,
724+
true );
725+
726+
// Verify that the specific illuminant from our test data is present
727+
OIIO_CHECK_EQUAL(
728+
result.output.find( "my-illuminant" ) != std::string::npos, true );
729+
730+
// Verify we have exactly 3 illuminants total (2 hardcoded + 1 from test data)
731+
// Count newlines in the illuminant list section to verify count
732+
size_t illuminant_count = 0;
733+
size_t start_pos =
734+
result.output.find( "The following illuminants are supported:" );
735+
if ( start_pos != std::string::npos )
736+
{
737+
size_t end_pos = result.output.find(
738+
"\n\n", start_pos ); // Look for double newline (end of list)
739+
if ( end_pos == std::string::npos )
740+
{
741+
end_pos = result.output.length(); // If no double newline, go to end
742+
}
743+
744+
std::string illuminant_section =
745+
result.output.substr( start_pos, end_pos - start_pos );
746+
size_t pos = 0;
747+
while ( ( pos = illuminant_section.find( "\n", pos ) ) !=
748+
std::string::npos )
749+
{
750+
illuminant_count++;
751+
pos += 1;
752+
}
753+
// Subtract 1 for the header line
754+
illuminant_count = ( illuminant_count > 0 ) ? illuminant_count - 1 : 0;
755+
}
756+
OIIO_CHECK_EQUAL( illuminant_count, 3 );
757+
}
758+
525759
int main( int, char ** )
526760
{
527761
try
@@ -547,6 +781,10 @@ int main( int, char ** )
547781
test_fix_metadata_source_missing();
548782
test_fix_metadata_source_missing();
549783
test_fix_metadata_unsupported_type();
784+
785+
// Tests for parse_parameters
786+
test_parse_parameters_list_cameras();
787+
test_parse_parameters_list_illuminants();
550788
}
551789
catch ( const std::exception &e )
552790
{

0 commit comments

Comments
 (0)