#include #include #include #include #include #include #include namespace lcamera_dev { namespace { constexpr const char *dellLaptopMachineTag = "dell-laptop"; static CameraIdentityRecord makeRecord( const std::string& id, const std::string& model = "", const std::string& locationLabel = "") { CameraIdentityRecord record; record.id = id; record.model = model; record.locationLabel = locationLabel; return record; } static std::vector syntheticAmbiguityRecords() { return { makeRecord("/base/cam0", "imx219", "back"), makeRecord("/base/cam1", "Logitech C920", "external"), makeRecord("/base/cam2", "imx219", "front"), }; } TEST(FormatCameraListForDiagnosticsTest, ListsIndexedCameras) { const std::vector records = tests::bakedProfilesAsRecords(dellLaptopMachineTag); const std::string text = formatCameraListForDiagnostics(records); EXPECT_NE(text.find("Known cameras:"), std::string::npos); EXPECT_NE(text.find("HDMI USB Camera"), std::string::npos); EXPECT_NE(text.find("location=external"), std::string::npos); EXPECT_NE(text.find("Integrated_Webcam_HD"), std::string::npos); EXPECT_NE(text.find("location=front"), std::string::npos); } TEST(ResolveDeviceSelectorAgainstRecordsTest, BakedUsbHdmiCameraMatchesExampleSelector) { const std::vector records = tests::bakedProfilesAsRecords(dellLaptopMachineTag); const CameraIdentityRecord resolved = resolveDeviceSelectorAgainstRecords( "model-substr:HDMI;location:EXTERNAL", records); EXPECT_EQ( resolved.id, "\\_SB_.PCI0.XHC_.RHUB.HS01-1:1.0-32e4:9415"); EXPECT_EQ(resolved.locationLabel, "external"); } TEST(ResolveSelectorAgainstRecordsTest, BakedUsbHdmiCameraMatchesExampleSelector) { const std::vector records = tests::bakedProfilesAsRecords(dellLaptopMachineTag); const std::vector criteria = parseDeviceSelector("model-substr:HDMI;location:EXTERNAL"); const CameraIdentityRecord resolved = resolveSelectorAgainstRecords(criteria, records); EXPECT_EQ( resolved.id, "\\_SB_.PCI0.XHC_.RHUB.HS01-1:1.0-32e4:9415"); EXPECT_EQ(resolved.locationLabel, "external"); } TEST(ResolveSelectorAgainstRecordsTest, BakedIntegratedWebcamMatchesExampleSelector) { const std::vector records = tests::bakedProfilesAsRecords(dellLaptopMachineTag); const std::vector criteria = parseDeviceSelector("model-substr:Integrated;location:front"); const CameraIdentityRecord resolved = resolveSelectorAgainstRecords(criteria, records); EXPECT_EQ( resolved.id, "\\_SB_.PCI0.XHC_.RHUB.HS04-4:1.0-1bcf:2b8a"); EXPECT_EQ(resolved.locationLabel, "front"); } TEST(ResolveSelectorAgainstRecordsTest, BakedUsbCameraMatchesLibcameraId) { const std::vector records = tests::bakedProfilesAsRecords(dellLaptopMachineTag); const std::vector criteria = parseDeviceSelector( "lcamera-id:\\_SB_.PCI0.XHC_.RHUB.HS01-1:1.0-32e4:9415"); const CameraIdentityRecord resolved = resolveSelectorAgainstRecords(criteria, records); EXPECT_EQ( resolved.id, "\\_SB_.PCI0.XHC_.RHUB.HS01-1:1.0-32e4:9415"); } TEST(ResolveSelectorAgainstRecordsTest, MatchesLibcameraId) { const std::vector records = syntheticAmbiguityRecords(); const std::vector criteria = parseDeviceSelector("lcamera-id:/base/cam1"); const CameraIdentityRecord resolved = resolveSelectorAgainstRecords(criteria, records); EXPECT_EQ(resolved.id, "/base/cam1"); } TEST(ResolveSelectorAgainstRecordsTest, MatchesModelSubstrAndLocation) { const std::vector records = syntheticAmbiguityRecords(); const std::vector criteria = parseDeviceSelector("model-substr:Logitech;location:EXTERNAL"); const CameraIdentityRecord resolved = resolveSelectorAgainstRecords(criteria, records); EXPECT_EQ(resolved.id, "/base/cam1"); } TEST(ResolveSelectorAgainstRecordsTest, IndexSelectsNthCamera) { const std::vector records = syntheticAmbiguityRecords(); const std::vector criteria = parseDeviceSelector("index:2"); const CameraIdentityRecord resolved = resolveSelectorAgainstRecords(criteria, records); EXPECT_EQ(resolved.id, "/base/cam2"); } TEST(ResolveSelectorAgainstRecordsTest, IndexCombinedWithModel) { const std::vector records = syntheticAmbiguityRecords(); const std::vector criteria = parseDeviceSelector("index:0;model:imx219"); const CameraIdentityRecord resolved = resolveSelectorAgainstRecords(criteria, records); EXPECT_EQ(resolved.id, "/base/cam0"); } TEST(ResolveSelectorAgainstRecordsTest, ZeroMatchesThrowsWithDiagnostics) { const std::vector records = syntheticAmbiguityRecords(); const std::vector criteria = parseDeviceSelector("model:does-not-exist"); try { resolveSelectorAgainstRecords(criteria, records); FAIL() << "Expected std::runtime_error"; } catch (const std::runtime_error& exc) { EXPECT_NE( std::string(exc.what()).find("No camera matches deviceSelector"), std::string::npos); EXPECT_NE( std::string(exc.what()).find("Known cameras:"), std::string::npos); } } TEST(ResolveSelectorAgainstRecordsTest, AmbiguousSelectorThrows) { const std::vector records = syntheticAmbiguityRecords(); const std::vector criteria = parseDeviceSelector("model:imx219"); EXPECT_THROW( resolveSelectorAgainstRecords(criteria, records), std::runtime_error); } TEST(ResolveSelectorAgainstRecordsTest, IndexOutOfRangeThrows) { const std::vector records = syntheticAmbiguityRecords(); const std::vector criteria = parseDeviceSelector("index:9"); EXPECT_THROW( resolveSelectorAgainstRecords(criteria, records), std::runtime_error); } TEST(ResolveSelectorAgainstRecordsTest, IndexConflictsWithOtherClauses) { const std::vector records = syntheticAmbiguityRecords(); const std::vector criteria = parseDeviceSelector("index:0;location:front"); EXPECT_THROW( resolveSelectorAgainstRecords(criteria, records), std::runtime_error); } TEST(ResolveSelectorAgainstRecordsTest, InvalidIndexValueThrows) { const std::vector records = syntheticAmbiguityRecords(); const std::vector criteria = parseDeviceSelector("index:not-a-number"); EXPECT_THROW( resolveSelectorAgainstRecords(criteria, records), std::runtime_error); } } // namespace } // namespace lcamera_dev