| // Copyright 2017 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "components/exo/data_source.h" |
| |
| #include <atomic> |
| |
| #include "base/barrier_closure.h" |
| #include "base/files/file_util.h" |
| #include "base/functional/bind.h" |
| #include "base/functional/callback_helpers.h" |
| #include "base/test/bind.h" |
| #include "base/test/task_environment.h" |
| #include "components/exo/data_source_delegate.h" |
| #include "components/exo/test/exo_test_base.h" |
| #include "components/exo/test/test_data_source_delegate.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| namespace exo { |
| namespace { |
| |
| using test::TestDataSourceDelegate; |
| |
| constexpr char kTestData[] = "Test Data"; |
| |
| class DataSourceTest : public testing::Test { |
| protected: |
| base::test::TaskEnvironment task_environment_{ |
| base::test::TaskEnvironment::MainThreadType::DEFAULT, |
| base::test::TaskEnvironment::ThreadPoolExecutionMode::ASYNC}; |
| }; |
| |
| void CheckMimeType(const std::string& expected, |
| base::OnceClosure counter, |
| const std::string& mime_type, |
| const std::vector<uint8_t>& data) { |
| EXPECT_FALSE(expected.empty()); |
| EXPECT_EQ(expected, mime_type); |
| std::move(counter).Run(); |
| } |
| |
| void CheckTextMimeType(const std::string& expected, |
| base::OnceClosure counter, |
| const std::string& mime_type, |
| std::u16string data) { |
| EXPECT_FALSE(expected.empty()); |
| EXPECT_EQ(expected, mime_type); |
| std::move(counter).Run(); |
| } |
| |
| struct FileContents { |
| std::string mime_type; |
| std::string parsed_filename; |
| }; |
| |
| void CheckFileContentsMimeType(const FileContents& file_contents, |
| base::OnceClosure counter, |
| const std::string& mime_type, |
| const base::FilePath& filename, |
| const std::vector<uint8_t>& data) { |
| EXPECT_FALSE(file_contents.mime_type.empty()); |
| EXPECT_EQ(file_contents.mime_type, mime_type); |
| EXPECT_EQ(file_contents.parsed_filename, filename.value()); |
| std::move(counter).Run(); |
| } |
| |
| void CheckWebCustomDataMimeType(const std::string& expected, |
| base::OnceClosure counter, |
| const std::string& mime_type, |
| const std::vector<uint8_t>& data) { |
| EXPECT_FALSE(mime_type.empty()); |
| EXPECT_EQ(expected, mime_type); |
| std::move(counter).Run(); |
| } |
| |
| void IncrementFailureCounter(std::atomic_int* failure_count, |
| base::RepeatingClosure counter) { |
| ++(*failure_count); |
| std::move(counter).Run(); |
| } |
| |
| void CheckMimeTypesReceived( |
| DataSource* data_source, |
| const std::string& text_mime, |
| const std::string& rtf_mime, |
| const std::string& html_mime, |
| const std::string& image_mime, |
| const std::string& filenames_mime, |
| const FileContents& file_contents, |
| const std::string& web_custom_data_mime = std::string()) { |
| base::RunLoop run_loop; |
| base::RepeatingClosure counter = |
| base::BarrierClosure(DataSource::kMaxDataTypes, run_loop.QuitClosure()); |
| std::atomic_int failure_count; |
| failure_count.store(0); |
| data_source->GetDataForPreferredMimeTypes( |
| base::BindOnce(&CheckTextMimeType, text_mime, counter), |
| base::BindOnce(&CheckMimeType, rtf_mime, counter), |
| base::BindOnce(&CheckTextMimeType, html_mime, counter), |
| base::BindOnce(&CheckMimeType, image_mime, counter), |
| base::BindOnce(&CheckMimeType, filenames_mime, counter), |
| base::BindOnce(&CheckFileContentsMimeType, file_contents, counter), |
| base::BindOnce(&CheckWebCustomDataMimeType, web_custom_data_mime, |
| counter), |
| base::BindRepeating(&IncrementFailureCounter, &failure_count, counter)); |
| run_loop.Run(); |
| |
| int expected_failure_count = 0; |
| for (const auto& mime_type : |
| {text_mime, rtf_mime, html_mime, image_mime, filenames_mime, |
| file_contents.mime_type, web_custom_data_mime}) { |
| if (mime_type.empty()) |
| ++expected_failure_count; |
| } |
| EXPECT_EQ(expected_failure_count, failure_count.load()); |
| } |
| |
| TEST_F(DataSourceTest, ReadData) { |
| TestDataSourceDelegate delegate; |
| DataSource data_source(&delegate); |
| std::string mime_type("text/plain;charset=utf-8"); |
| delegate.SetData(mime_type, kTestData); |
| data_source.Offer(mime_type.c_str()); |
| |
| data_source.ReadDataForTesting( |
| mime_type, base::BindOnce([](const std::string& mime_type, |
| const std::vector<uint8_t>& data) { |
| std::string string_data(data.begin(), data.end()); |
| EXPECT_EQ(std::string(kTestData), string_data); |
| })); |
| task_environment_.RunUntilIdle(); |
| } |
| |
| TEST_F(DataSourceTest, ReadDataArbitraryMimeType) { |
| TestDataSourceDelegate delegate; |
| DataSource data_source(&delegate); |
| std::string mime_type("abc/def;key=value"); |
| delegate.SetData(mime_type, kTestData); |
| data_source.Offer(mime_type.c_str()); |
| |
| data_source.ReadDataForTesting( |
| mime_type, base::BindOnce([](const std::string& mime_type, |
| const std::vector<uint8_t>& data) { |
| std::string string_data(data.begin(), data.end()); |
| EXPECT_EQ(std::string(kTestData), string_data); |
| })); |
| task_environment_.RunUntilIdle(); |
| } |
| |
| TEST_F(DataSourceTest, ReadData_UnknownMimeType) { |
| TestDataSourceDelegate delegate; |
| DataSource data_source(&delegate); |
| data_source.Offer("text/plain;charset=utf-8"); |
| |
| std::string unknown_type("text/unknown"); |
| data_source.ReadDataForTesting( |
| unknown_type, base::BindOnce([](const std::string& mime_type, |
| const std::vector<uint8_t>& data) { |
| FAIL() << "Callback should not be invoked when known " |
| "mimetype is not offerred"; |
| })); |
| task_environment_.RunUntilIdle(); |
| } |
| |
| TEST_F(DataSourceTest, ReadData_Destroyed) { |
| TestDataSourceDelegate delegate; |
| { |
| DataSource data_source(&delegate); |
| std::string mime_type("text/plain;charset=utf-8"); |
| data_source.Offer(mime_type); |
| |
| data_source.ReadDataForTesting( |
| mime_type, base::BindOnce([](const std::string& mime_type, |
| const std::vector<uint8_t>& data) { |
| FAIL() << "Callback should not be invoked after " |
| "data source is destroyed"; |
| })); |
| } |
| task_environment_.RunUntilIdle(); |
| } |
| |
| TEST_F(DataSourceTest, ReadData_Cancelled) { |
| TestDataSourceDelegate delegate; |
| DataSource data_source(&delegate); |
| std::string mime_type("text/plain;charset=utf-8"); |
| data_source.Offer(mime_type); |
| |
| data_source.ReadDataForTesting( |
| mime_type, base::BindOnce([](const std::string& mime_type, |
| const std::vector<uint8_t>& data) { |
| FAIL() << "Callback should not be invoked after cancelled"; |
| })); |
| data_source.Cancelled(); |
| task_environment_.RunUntilIdle(); |
| } |
| |
| TEST_F(DataSourceTest, ReadData_Deleted) { |
| TestDataSourceDelegate delegate; |
| auto data_source = std::make_unique<DataSource>(&delegate); |
| std::string mime_type("text/plain;charset=utf-8"); |
| data_source->Offer(mime_type); |
| |
| base::RunLoop run_loop; |
| data_source->ReadDataForTesting(mime_type, base::DoNothing(), |
| run_loop.QuitClosure()); |
| data_source.reset(); |
| run_loop.Run(); |
| } |
| |
| TEST_F(DataSourceTest, PreferredMimeTypeUTF16) { |
| TestDataSourceDelegate delegate; |
| DataSource data_source(&delegate); |
| data_source.Offer("text/plain;charset=utf-16"); |
| data_source.Offer("text/plain;charset=UTF-8"); |
| data_source.Offer("text/html;charset=UTF-16"); |
| data_source.Offer("text/html;charset=utf-8"); |
| |
| CheckMimeTypesReceived(&data_source, "text/plain;charset=utf-16", "", |
| "text/html;charset=UTF-16", "", "", {}); |
| } |
| |
| TEST_F(DataSourceTest, PreferredMimeTypeUTF16LE) { |
| TestDataSourceDelegate delegate; |
| DataSource data_source(&delegate); |
| data_source.Offer("text/plain;charset=utf-16le"); |
| data_source.Offer("text/plain;charset=utf8"); |
| data_source.Offer("text/html;charset=utf16le"); |
| data_source.Offer("text/html;charset=utf-8"); |
| |
| CheckMimeTypesReceived(&data_source, "text/plain;charset=utf-16le", "", |
| "text/html;charset=utf16le", "", "", {}); |
| } |
| |
| TEST_F(DataSourceTest, PreferredMimeTypeUTF16BE) { |
| TestDataSourceDelegate delegate; |
| DataSource data_source(&delegate); |
| data_source.Offer("text/plain;charset=utf-16be"); |
| data_source.Offer("text/plain;charset=UTF8"); |
| data_source.Offer("text/html;charset=UTF16be"); |
| data_source.Offer("text/html;charset=utf-8"); |
| |
| CheckMimeTypesReceived(&data_source, "text/plain;charset=utf-16be", "", |
| "text/html;charset=UTF16be", "", "", {}); |
| } |
| |
| TEST_F(DataSourceTest, PreferredMimeTypeUTFToOther) { |
| TestDataSourceDelegate delegate; |
| DataSource data_source(&delegate); |
| data_source.Offer("text/plain;charset=utf-8"); |
| data_source.Offer("text/plain;charset=iso-8859-1"); |
| data_source.Offer("text/html;charset=utf-8"); |
| data_source.Offer("text/html;charset=iso-8859-1"); |
| |
| CheckMimeTypesReceived(&data_source, "text/plain;charset=utf-8", "", |
| "text/html;charset=utf-8", "", "", {}); |
| } |
| |
| TEST_F(DataSourceTest, RecogniseUTF8Legaccy) { |
| TestDataSourceDelegate delegate; |
| DataSource data_source(&delegate); |
| data_source.Offer("UTF8_STRING"); |
| data_source.Offer("text/plain;charset=iso-8859-1"); |
| |
| CheckMimeTypesReceived(&data_source, "UTF8_STRING", "", "", "", "", {}); |
| } |
| |
| TEST_F(DataSourceTest, PreferredMimeTypeOtherToAscii) { |
| TestDataSourceDelegate delegate; |
| DataSource data_source(&delegate); |
| data_source.Offer("text/plain;charset=iso-8859-1"); |
| data_source.Offer("text/plain;charset=ASCII"); |
| data_source.Offer("text/html;charset=iso-8859-1"); |
| data_source.Offer("text/html;charset=ascii"); |
| |
| CheckMimeTypesReceived(&data_source, "text/plain;charset=iso-8859-1", "", |
| "text/html;charset=iso-8859-1", "", "", {}); |
| } |
| |
| TEST_F(DataSourceTest, PreferredMimeTypeOtherToUnspecified) { |
| TestDataSourceDelegate delegate; |
| DataSource data_source(&delegate); |
| data_source.Offer("text/plain;charset=iso-8859-1"); |
| data_source.Offer("text/plain"); |
| data_source.Offer("text/html;charset=iso-8859-1"); |
| data_source.Offer("text/html"); |
| |
| CheckMimeTypesReceived(&data_source, "text/plain;charset=iso-8859-1", "", |
| "text/html;charset=iso-8859-1", "", "", {}); |
| } |
| |
| TEST_F(DataSourceTest, PreferredMimeTypeRTF) { |
| TestDataSourceDelegate delegate; |
| DataSource data_source(&delegate); |
| data_source.Offer("text/rtf"); |
| |
| CheckMimeTypesReceived(&data_source, "", "text/rtf", "", "", "", {}); |
| } |
| |
| TEST_F(DataSourceTest, PreferredMimeTypePNGtoBitmap) { |
| TestDataSourceDelegate delegate; |
| DataSource data_source(&delegate); |
| data_source.Offer("image/bmp"); |
| data_source.Offer("image/png"); |
| |
| CheckMimeTypesReceived(&data_source, "", "", "", "image/png", "", {}); |
| } |
| |
| TEST_F(DataSourceTest, PreferredMimeTypePNGToJPEG) { |
| TestDataSourceDelegate delegate; |
| DataSource data_source(&delegate); |
| data_source.Offer("image/png"); |
| data_source.Offer("image/jpeg"); |
| data_source.Offer("image/jpg"); |
| |
| CheckMimeTypesReceived(&data_source, "", "", "", "image/png", "", {}); |
| } |
| |
| TEST_F(DataSourceTest, PreferredMimeTypeBitmaptoJPEG) { |
| TestDataSourceDelegate delegate; |
| DataSource data_source(&delegate); |
| data_source.Offer("image/bmp"); |
| data_source.Offer("image/jpeg"); |
| data_source.Offer("image/jpg"); |
| |
| CheckMimeTypesReceived(&data_source, "", "", "", "image/bmp", "", {}); |
| } |
| |
| TEST_F(DataSourceTest, PreferredMimeTypeTextUriList) { |
| TestDataSourceDelegate delegate; |
| DataSource data_source(&delegate); |
| data_source.Offer("text/uri-list"); |
| |
| CheckMimeTypesReceived(&data_source, "", "", "", "", "text/uri-list", {}); |
| } |
| |
| TEST_F(DataSourceTest, PreferredMimeTypeOctetStream) { |
| TestDataSourceDelegate delegate; |
| DataSource data_source(&delegate); |
| data_source.Offer("application/octet-stream;name=test.jpg"); |
| |
| CheckMimeTypesReceived( |
| &data_source, "", "", "", "", "", |
| {"application/octet-stream;name=test.jpg", "test.jpg"}); |
| } |
| |
| TEST_F(DataSourceTest, OctetStreamWithoutName) { |
| TestDataSourceDelegate delegate; |
| DataSource data_source(&delegate); |
| data_source.Offer("application/octet-stream"); |
| |
| CheckMimeTypesReceived(&data_source, "", "", "", "", "", {}); |
| } |
| |
| TEST_F(DataSourceTest, OctetStreamWithQuotedName) { |
| TestDataSourceDelegate delegate; |
| DataSource data_source(&delegate); |
| data_source.Offer("application/octet-stream;name=\"t\\\\est\\\".jpg\""); |
| |
| CheckMimeTypesReceived( |
| &data_source, "", "", "", "", "", |
| {"application/octet-stream;name=\"t\\\\est\\\".jpg\"", "t\\est\".jpg"}); |
| } |
| |
| TEST_F(DataSourceTest, WebCustomDataMime) { |
| TestDataSourceDelegate delegate; |
| DataSource data_source(&delegate); |
| std::string web_custom_data_mime("chromium/x-web-custom-data"); |
| data_source.Offer(web_custom_data_mime); |
| |
| CheckMimeTypesReceived(&data_source, "", "", "", "", "", {}, |
| web_custom_data_mime); |
| } |
| |
| } // namespace |
| } // namespace exo |