/* * Copyright (C) 2016 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "metadata.h" #include <memory> #include <set> #include <vector> #include <camera/CameraMetadata.h> #include <gmock/gmock.h> #include <gtest/gtest.h> #include "metadata_common.h" #include "partial_metadata_interface_mock.h" using testing::AtMost; using testing::Return; using testing::Test; using testing::_; namespace v4l2_camera_hal { class MetadataTest : public Test { protected: virtual void SetUp() { // Clear the DUT. AddComponents must be called before using it. dut_.reset(); component1_.reset(new PartialMetadataInterfaceMock()); component2_.reset(new PartialMetadataInterfaceMock()); metadata_.reset(new android::CameraMetadata()); non_empty_metadata_.reset(new android::CameraMetadata()); uint8_t val = 1; non_empty_metadata_->update(ANDROID_COLOR_CORRECTION_MODE, &val, 1); } // Once the component mocks have had expectations set, // add them to the device under test. virtual void AddComponents() { // Don't mind moving; Gmock/Gtest fails on leaked mocks unless disabled by // runtime flags. PartialMetadataSet components; components.insert(std::move(component1_)); components.insert(std::move(component2_)); dut_.reset(new Metadata(std::move(components))); } virtual void CompareTags(const std::set<int32_t>& expected, const camera_metadata_entry_t& actual) { ASSERT_EQ(expected.size(), actual.count); for (size_t i = 0; i < actual.count; ++i) { EXPECT_NE(expected.find(actual.data.i32[i]), expected.end()); } } // Device under test. std::unique_ptr<Metadata> dut_; // Mocks. std::unique_ptr<PartialMetadataInterfaceMock> component1_; std::unique_ptr<PartialMetadataInterfaceMock> component2_; // Metadata. std::unique_ptr<android::CameraMetadata> metadata_; std::unique_ptr<android::CameraMetadata> non_empty_metadata_; // An empty vector to use as necessary. std::vector<int32_t> empty_tags_; }; TEST_F(MetadataTest, FillStaticSuccess) { // Should populate all the component static pieces. EXPECT_CALL(*component1_, PopulateStaticFields(_)).WillOnce(Return(0)); EXPECT_CALL(*component2_, PopulateStaticFields(_)).WillOnce(Return(0)); // Should populate the meta keys, by polling each component's keys. std::vector<int32_t> static_tags_1({1, 2}); std::vector<int32_t> static_tags_2({3, 4}); std::vector<int32_t> control_tags_1({5, 6}); std::vector<int32_t> control_tags_2({7, 8}); std::vector<int32_t> dynamic_tags_1({9, 10}); std::vector<int32_t> dynamic_tags_2({11, 12}); EXPECT_CALL(*component1_, StaticTags()).WillOnce(Return(static_tags_1)); EXPECT_CALL(*component1_, ControlTags()).WillOnce(Return(control_tags_1)); EXPECT_CALL(*component1_, DynamicTags()).WillOnce(Return(dynamic_tags_1)); EXPECT_CALL(*component2_, StaticTags()).WillOnce(Return(static_tags_2)); EXPECT_CALL(*component2_, ControlTags()).WillOnce(Return(control_tags_2)); EXPECT_CALL(*component2_, DynamicTags()).WillOnce(Return(dynamic_tags_2)); AddComponents(); // Should succeed. If it didn't, no reason to continue checking output. ASSERT_EQ(dut_->FillStaticMetadata(metadata_.get()), 0); // Meta keys should be filled correctly. // Note: sets are used here, but it is undefined behavior if // the class has multiple componenets reporting overlapping tags. // Get the expected tags = combined tags of all components. std::set<int32_t> static_tags(static_tags_1.begin(), static_tags_1.end()); static_tags.insert(static_tags_2.begin(), static_tags_2.end()); std::set<int32_t> control_tags(control_tags_1.begin(), control_tags_1.end()); control_tags.insert(control_tags_2.begin(), control_tags_2.end()); std::set<int32_t> dynamic_tags(dynamic_tags_1.begin(), dynamic_tags_1.end()); dynamic_tags.insert(dynamic_tags_2.begin(), dynamic_tags_2.end()); // Static tags includes not only all component static tags, but also // the meta AVAILABLE_*_KEYS (* = [REQUEST, RESULT, CHARACTERISTICS]). static_tags.emplace(ANDROID_REQUEST_AVAILABLE_REQUEST_KEYS); static_tags.emplace(ANDROID_REQUEST_AVAILABLE_RESULT_KEYS); static_tags.emplace(ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS); // Check against what was filled in in the metadata. CompareTags(static_tags, metadata_->find(ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS)); CompareTags(control_tags, metadata_->find(ANDROID_REQUEST_AVAILABLE_REQUEST_KEYS)); CompareTags(dynamic_tags, metadata_->find(ANDROID_REQUEST_AVAILABLE_RESULT_KEYS)); } TEST_F(MetadataTest, FillStaticFail) { int err = -99; // Order undefined, and may or may not exit early; use AtMost. EXPECT_CALL(*component1_, PopulateStaticFields(_)) .Times(AtMost(1)) .WillOnce(Return(0)); EXPECT_CALL(*component2_, PopulateStaticFields(_)).WillOnce(Return(err)); // May or may not exit early, may still try to populate meta tags. EXPECT_CALL(*component1_, StaticTags()) .Times(AtMost(1)) .WillOnce(Return(empty_tags_)); EXPECT_CALL(*component1_, ControlTags()) .Times(AtMost(1)) .WillOnce(Return(empty_tags_)); EXPECT_CALL(*component1_, DynamicTags()) .Times(AtMost(1)) .WillOnce(Return(empty_tags_)); EXPECT_CALL(*component2_, StaticTags()) .Times(AtMost(1)) .WillOnce(Return(empty_tags_)); EXPECT_CALL(*component2_, ControlTags()) .Times(AtMost(1)) .WillOnce(Return(empty_tags_)); EXPECT_CALL(*component2_, DynamicTags()) .Times(AtMost(1)) .WillOnce(Return(empty_tags_)); AddComponents(); // If any component errors, error should be returned EXPECT_EQ(dut_->FillStaticMetadata(metadata_.get()), err); } TEST_F(MetadataTest, FillStaticNull) { AddComponents(); EXPECT_EQ(dut_->FillStaticMetadata(nullptr), -EINVAL); } TEST_F(MetadataTest, IsValidSuccess) { // Should check if all the component request values are valid. EXPECT_CALL(*component1_, SupportsRequestValues(_)).WillOnce(Return(true)); EXPECT_CALL(*component2_, SupportsRequestValues(_)).WillOnce(Return(true)); AddComponents(); // Should succeed. // Note: getAndLock is a lock against pointer invalidation, not concurrency, // and unlocks on object destruction. EXPECT_TRUE(dut_->IsValidRequest(*non_empty_metadata_)); } TEST_F(MetadataTest, IsValidFail) { // Should check if all the component request values are valid. // Order undefined, and may or may not exit early; use AtMost. EXPECT_CALL(*component1_, SupportsRequestValues(_)) .Times(AtMost(1)) .WillOnce(Return(true)); EXPECT_CALL(*component2_, SupportsRequestValues(_)).WillOnce(Return(false)); AddComponents(); // Should fail since one of the components failed. // Note: getAndLock is a lock against pointer invalidation, not concurrency, // and unlocks on object destruction. EXPECT_FALSE(dut_->IsValidRequest(*non_empty_metadata_)); } TEST_F(MetadataTest, IsValidEmpty) { // Setting null settings is a special case indicating to use the // previous (valid) settings. As such it is inherently valid. // Should not try to check any components. EXPECT_CALL(*component1_, SupportsRequestValues(_)).Times(0); EXPECT_CALL(*component2_, SupportsRequestValues(_)).Times(0); AddComponents(); EXPECT_TRUE(dut_->IsValidRequest(*metadata_)); } TEST_F(MetadataTest, GetTemplateSuccess) { int template_type = 3; // Should check if all the components fill the template successfully. EXPECT_CALL(*component1_, PopulateTemplateRequest(template_type, _)) .WillOnce(Return(0)); EXPECT_CALL(*component2_, PopulateTemplateRequest(template_type, _)) .WillOnce(Return(0)); AddComponents(); // Should succeed. EXPECT_EQ(dut_->GetRequestTemplate(template_type, metadata_.get()), 0); } TEST_F(MetadataTest, GetTemplateFail) { int err = -99; int template_type = 3; // Should check if all the components fill the template successfully. // Order undefined, and may or may not exit early; use AtMost. EXPECT_CALL(*component1_, PopulateTemplateRequest(template_type, _)) .Times(AtMost(1)) .WillOnce(Return(0)); EXPECT_CALL(*component2_, PopulateTemplateRequest(template_type, _)) .WillOnce(Return(err)); AddComponents(); // Should fail since one of the components failed. EXPECT_EQ(dut_->GetRequestTemplate(template_type, metadata_.get()), err); } TEST_F(MetadataTest, GetTemplateNull) { AddComponents(); EXPECT_EQ(dut_->GetRequestTemplate(1, nullptr), -EINVAL); } TEST_F(MetadataTest, GetTemplateInvalid) { int template_type = 99; // Invalid template type. AddComponents(); // Should fail fast since template type is invalid. EXPECT_EQ(dut_->GetRequestTemplate(template_type, metadata_.get()), -EINVAL); } TEST_F(MetadataTest, SetSettingsSuccess) { // Should check if all the components set successfully. EXPECT_CALL(*component1_, SetRequestValues(_)).WillOnce(Return(0)); EXPECT_CALL(*component2_, SetRequestValues(_)).WillOnce(Return(0)); AddComponents(); // Should succeed. // Note: getAndLock is a lock against pointer invalidation, not concurrency, // and unlocks on object destruction. EXPECT_EQ(dut_->SetRequestSettings(*non_empty_metadata_), 0); } TEST_F(MetadataTest, SetSettingsFail) { int err = -99; // Should check if all the components set successfully. // Order undefined, and may or may not exit early; use AtMost. EXPECT_CALL(*component1_, SetRequestValues(_)) .Times(AtMost(1)) .WillOnce(Return(0)); EXPECT_CALL(*component2_, SetRequestValues(_)).WillOnce(Return(err)); AddComponents(); // Should fail since one of the components failed. // Note: getAndLock is a lock against pointer invalidation, not concurrency, // and unlocks on object destruction. EXPECT_EQ(dut_->SetRequestSettings(*non_empty_metadata_), err); } TEST_F(MetadataTest, SetSettingsEmpty) { // Setting null settings is a special case indicating to use the // previous settings. Should not try to set any components. EXPECT_CALL(*component1_, SetRequestValues(_)).Times(0); EXPECT_CALL(*component2_, SetRequestValues(_)).Times(0); AddComponents(); // Should succeed. EXPECT_EQ(dut_->SetRequestSettings(*metadata_), 0); } TEST_F(MetadataTest, FillResultSuccess) { // Should check if all the components fill results successfully. EXPECT_CALL(*component1_, PopulateDynamicFields(_)).WillOnce(Return(0)); EXPECT_CALL(*component2_, PopulateDynamicFields(_)).WillOnce(Return(0)); AddComponents(); // Should succeed. EXPECT_EQ(dut_->FillResultMetadata(metadata_.get()), 0); } TEST_F(MetadataTest, FillResultFail) { int err = -99; // Should check if all the components fill results successfully. // Order undefined, and may or may not exit early; use AtMost. EXPECT_CALL(*component1_, PopulateDynamicFields(_)) .Times(AtMost(1)) .WillOnce(Return(0)); EXPECT_CALL(*component2_, PopulateDynamicFields(_)).WillOnce(Return(err)); AddComponents(); // Should fail since one of the components failed. EXPECT_EQ(dut_->FillResultMetadata(metadata_.get()), err); } TEST_F(MetadataTest, FillResultNull) { AddComponents(); EXPECT_EQ(dut_->FillResultMetadata(nullptr), -EINVAL); } } // namespace v4l2_camera_hal