diff --git a/libwvdrmengine/cdm/util/include/file_store.h b/libwvdrmengine/cdm/util/include/file_store.h index 9563b5eb..73de53d9 100644 --- a/libwvdrmengine/cdm/util/include/file_store.h +++ b/libwvdrmengine/cdm/util/include/file_store.h @@ -7,7 +7,8 @@ #ifndef WVCDM_UTIL_FILE_STORE_H_ #define WVCDM_UTIL_FILE_STORE_H_ -#include +#include + #include #include #include @@ -18,16 +19,35 @@ namespace wvutil { +// Fixed filename for ATSC DRM certificate pre-installed +// on ATSC devices for ATSC licenses. static const std::string kAtscCertificateFileName = "atsccert.bin"; +// General filename for either global or unmapped app-origin +// DRM certificates. static const std::string kCertificateFileName = "cert1.bin"; +// File extension for DRM and OEM certificate files. static const std::string kCertificateFileNameExt = ".bin"; -static const std::string kCertificateFileNamePrefix = "cert1_"; +// Filename prefix for mapped (scoped) DRM certificate filenames +// specific to a particular app-origin. +static const std::string kScopedCertificateFilenamePrefix = "cert1_"; +// TODO(b/376533901): Replace this constant with +// kScopedCertificateFilenamePrefix in source code.. +static const std::string kCertificateFileNamePrefix = + kScopedCertificateFilenamePrefix; +// Legacy general filename for either global or unmapped app-origin +// DRM certificates. static const std::string kLegacyCertificateFileName = "cert.bin"; -static const std::string kLegacyCertificateFileNamePrefix = "cert"; +// Legacy filename prefix for mapped (scoped) DRM certificate filenames +// specific to a particular app-origin. +static const std::string kLegacyScopedCertificateFilenamePrefix = "cert"; +// TODO(b/376533901): Replace this constant with +// kLegacyScopedCertificateFilenamePrefix in source code.. +static const std::string kLegacyCertificateFileNamePrefix = + kLegacyScopedCertificateFilenamePrefix; +// Filename for global OEM certificates. static const std::string kOemCertificateFileName = "oemcert.bin"; -static const std::string kOemCertificateFileNamePrefix = "oemcert_"; -// File class. The implementation is platform dependent. +// File interface. The implementation is platform dependent. class File { public: File() {} @@ -35,35 +55,70 @@ class File { virtual ssize_t Read(char* buffer, size_t bytes) = 0; virtual ssize_t Write(const char* buffer, size_t bytes) = 0; - friend class FileSystem; CORE_DISALLOW_COPY_AND_ASSIGN(File); }; +// File system base class. The implementation is platform dependent. class FileSystem { public: FileSystem(); FileSystem(const std::string& origin, void* extra_data); virtual ~FileSystem(); + // Concreate implementation of FileSystem. + // Depending on the platform, this may be vendor or Widevine implemented. class Impl; - // defines as bit flag - enum OpenFlags { - kNoFlags = 0, - kCreate = 1, - kReadOnly = 2, // defaults to read and write access - kTruncate = 4 - }; + // Flags for calls to Open. + static constexpr int kNoFlags = 0; + // Create file if does not already exist, open file if it does exist. + static constexpr int kCreate = (1 << 0); + // Open file as read-only; typically should not be used with kCreate. + static constexpr int kReadOnly = (1 << 1); + // Open file and truncated. May be used with kCreate; should not + // be used with kReadOnly. + static constexpr int kTruncate = (1 << 2); virtual std::unique_ptr Open(const std::string& file_path, int flags); - virtual bool Exists(const std::string& file_path); - virtual bool Exists(const std::string& file_path, int* errno_value); - virtual bool Remove(const std::string& file_path); + // Checks if the |path| exists. The |path| may be a file or directory. + // Return true if an entry in the file system exists; false otherwise. + virtual bool Exists(const std::string& path); + // Same as above, except the optional parameter of |errno_value| should + // be set to 0 or the value of C errno when attempting to check + // the existence of a file. + virtual bool Exists(const std::string& path, int* errno_value); + + // Removes the specified |path|. + // + // If |path| is a regular file, the file should be removed. + // If |path| is a directory, both the directory and the directory + // contents should be removed. + // + // Implementation must support a |path| containing a single wildcard + // character in the filename component of the path. + // + // Return value: + // - true : File/directory was removed, or file/directory did not exist + // - false : File/directory could not be removed, or other error. + virtual bool Remove(const std::string& path); + + // Obtain the size of a file in bytes. |file_path| must be a file, + // and not a directory. + // + // Return value: + // - non-negative : size of file in bytes if file exists + // - negative : file does not exist, or error occurred. virtual ssize_t FileSize(const std::string& file_path); - // Return the filenames stored at dir_path. - // dir_path will be stripped from the returned names. + // Return the entries stored at |dir_path| (includes both files + // and directories). + // + // Return value: + // - true : Directory exists, and directory entry names are stored + // in |names|; |names| may be empty if directory was empty. + // - false : Directory does not exist, |dir_path| is not a directory, + // or error was encountered. virtual bool List(const std::string& dir_path, std::vector* names); diff --git a/libwvdrmengine/cdm/util/test/file_store_unittest.cpp b/libwvdrmengine/cdm/util/test/file_store_unittest.cpp index a62bfc03..ad30ac26 100644 --- a/libwvdrmengine/cdm/util/test/file_store_unittest.cpp +++ b/libwvdrmengine/cdm/util/test/file_store_unittest.cpp @@ -1,9 +1,14 @@ // Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary // source code may only be used and distributed under the Widevine License // Agreement. - #include "file_store.h" +#include + +#include +#include +#include + #include #include @@ -11,18 +16,20 @@ #include "test_vectors.h" namespace wvutil { - namespace { -const std::string kTestDirName = "test_dir"; -const std::string kTestFileName = "test.txt"; -const std::string kTestFileName2 = "test2.txt"; -const std::string kTestFileName3 = "test3.other"; -const std::string kTestFileNameExt = ".txt"; -const std::string kTestFileNameExt3 = ".other"; -const std::string kTestIdentifier1 = "some_identifier"; -const std::string kTestIdentifier2 = "some_other_identifier"; -const std::string kWildcard = "*"; -const std::string kUnderscore = "_"; +constexpr char kTestFilename[] = "sample.txt"; + +constexpr char kTestIdentifier1[] = "some_identifier"; +constexpr char kTestIdentifier2[] = "some_other_identifier"; + +constexpr int kNoError = 0; +constexpr int kEntryDoesNotExist = ENOENT; + +bool StartsWith(const std::string& haystack, const std::string& needle) { + if (needle.empty()) return true; + if (haystack.size() < needle.size()) return false; + return haystack.find(needle) == 0; +} } // namespace class FileTest : public testing::Test { @@ -32,7 +39,19 @@ class FileTest : public testing::Test { void TearDown() override { RemoveTestDir(); } void RemoveTestDir() { - EXPECT_TRUE(file_system_.Remove(wvcdm::test_vectors::kTestDir)); + ASSERT_TRUE(file_system_.Remove(wvcdm::test_vectors::kTestDir)) + << "Failed to update test directory: " << wvcdm::test_vectors::kTestDir; + } + + std::string PathJoin(const std::string& base_path, + const std::string& add_path) { + if (base_path.empty()) return add_path; + std::string path = base_path; + if (path.back() != '/') { + path.push_back('/'); + } + path.append(add_path); + return path; } FileSystem file_system_; @@ -40,336 +59,505 @@ class FileTest : public testing::Test { TEST_F(FileTest, FileExists) { int errno_value = -1; - EXPECT_TRUE(file_system_.Exists(wvcdm::test_vectors::kExistentFile)); + EXPECT_TRUE(file_system_.Exists(wvcdm::test_vectors::kExistentFile)) + << "path = " << wvcdm::test_vectors::kExistentFile; EXPECT_TRUE( - file_system_.Exists(wvcdm::test_vectors::kExistentFile, &errno_value)); - EXPECT_EQ(0, errno_value); - EXPECT_TRUE(file_system_.Exists(wvcdm::test_vectors::kExistentDir)); + file_system_.Exists(wvcdm::test_vectors::kExistentFile, &errno_value)) + << "path = " << wvcdm::test_vectors::kExistentFile; + EXPECT_EQ(kNoError, errno_value); +} - EXPECT_FALSE(file_system_.Exists(wvcdm::test_vectors::kNonExistentFile)); +TEST_F(FileTest, FileDoesNotExist) { + int errno_value = -1; + EXPECT_FALSE(file_system_.Exists(wvcdm::test_vectors::kNonExistentFile)) + << "path = " << wvcdm::test_vectors::kNonExistentFile; EXPECT_FALSE( - file_system_.Exists(wvcdm::test_vectors::kNonExistentFile, &errno_value)); - EXPECT_EQ(ENOENT, errno_value); - EXPECT_FALSE(file_system_.Exists(wvcdm::test_vectors::kNonExistentDir)); + file_system_.Exists(wvcdm::test_vectors::kNonExistentFile, &errno_value)) + << "path = " << wvcdm::test_vectors::kNonExistentFile; + EXPECT_EQ(kEntryDoesNotExist, errno_value); +} + +TEST_F(FileTest, DirectoryExists) { + int errno_value = -1; + EXPECT_TRUE(file_system_.Exists(wvcdm::test_vectors::kExistentDir)) + << "path = " << wvcdm::test_vectors::kExistentDir; + EXPECT_TRUE( + file_system_.Exists(wvcdm::test_vectors::kExistentDir, &errno_value)) + << "path = " << wvcdm::test_vectors::kExistentDir; + EXPECT_EQ(kNoError, errno_value); +} + +TEST_F(FileTest, DirectoryDoesNotExist) { + int errno_value = -1; + EXPECT_FALSE(file_system_.Exists(wvcdm::test_vectors::kNonExistentDir)) + << "path = " << wvcdm::test_vectors::kNonExistentDir; + EXPECT_FALSE( + file_system_.Exists(wvcdm::test_vectors::kNonExistentDir, &errno_value)) + << "path = " << wvcdm::test_vectors::kNonExistentDir; + EXPECT_EQ(kEntryDoesNotExist, errno_value); } TEST_F(FileTest, RemoveDir) { - EXPECT_TRUE(file_system_.Remove(wvcdm::test_vectors::kTestDir)); - EXPECT_FALSE(file_system_.Exists(wvcdm::test_vectors::kTestDir)); + EXPECT_TRUE(file_system_.Remove(wvcdm::test_vectors::kTestDir)) + << "path = " << wvcdm::test_vectors::kTestDir; + EXPECT_FALSE(file_system_.Exists(wvcdm::test_vectors::kTestDir)) + << "path = " << wvcdm::test_vectors::kTestDir; } TEST_F(FileTest, OpenFile) { - std::string path = wvcdm::test_vectors::kTestDir + kTestFileName; - EXPECT_TRUE(file_system_.Remove(path)); + const std::string path = + PathJoin(wvcdm::test_vectors::kTestDir, kTestFilename); + EXPECT_TRUE(file_system_.Remove(path)) << "path = " << path; std::unique_ptr file = file_system_.Open(path, FileSystem::kCreate); - ASSERT_TRUE(file); + ASSERT_TRUE(file) << "Failed to create file: " << path; - EXPECT_TRUE(file_system_.Exists(path)); + EXPECT_TRUE(file_system_.Exists(path)) << "path = " << path; } TEST_F(FileTest, RemoveDirAndFile) { - std::string path = wvcdm::test_vectors::kTestDir + kTestFileName; + const std::string path = + PathJoin(wvcdm::test_vectors::kTestDir, kTestFilename); std::unique_ptr file = file_system_.Open(path, FileSystem::kCreate); - ASSERT_TRUE(file); + ASSERT_TRUE(file) << "Failed to create file: " << path; - EXPECT_TRUE(file_system_.Exists(path)); - EXPECT_TRUE(file_system_.Remove(path)); - EXPECT_FALSE(file_system_.Exists(path)); + EXPECT_TRUE(file_system_.Exists(path)) << "path = " << path; + EXPECT_TRUE(file_system_.Remove(path)) << "path = " << path; + EXPECT_FALSE(file_system_.Exists(path)) << "path = " << path; file = file_system_.Open(path, FileSystem::kCreate); - ASSERT_TRUE(file); + ASSERT_TRUE(file) << "Failed to create file: " << path; - EXPECT_TRUE(file_system_.Exists(path)); - RemoveTestDir(); - EXPECT_FALSE(file_system_.Exists(wvcdm::test_vectors::kTestDir)); - EXPECT_FALSE(file_system_.Exists(path)); + EXPECT_TRUE(file_system_.Exists(path)) << "path = " << path; + ASSERT_NO_FATAL_FAILURE(RemoveTestDir()); + EXPECT_FALSE(file_system_.Exists(wvcdm::test_vectors::kTestDir)) + << "path = " << path; + EXPECT_FALSE(file_system_.Exists(path)) << "path = " << path; } TEST_F(FileTest, RemoveWildcardFiles) { - std::string path1 = wvcdm::test_vectors::kTestDir + kTestFileName; - std::string path2 = wvcdm::test_vectors::kTestDir + kTestFileName2; - std::string wildcard_path = - wvcdm::test_vectors::kTestDir + kWildcard + kTestFileNameExt; + const std::string path1 = + PathJoin(wvcdm::test_vectors::kTestDir, "first.txt"); + const std::string path2 = + PathJoin(wvcdm::test_vectors::kTestDir, "second.txt"); + const std::string wildcard_path = + PathJoin(wvcdm::test_vectors::kTestDir, "*.txt"); std::unique_ptr file = file_system_.Open(path1, FileSystem::kCreate); - ASSERT_TRUE(file); + ASSERT_TRUE(file) << "Failed to create file (1): " << path1; file = file_system_.Open(path2, FileSystem::kCreate); - ASSERT_TRUE(file); + ASSERT_TRUE(file) << "Failed to create file (2): " << path2; - EXPECT_TRUE(file_system_.Exists(path1)); - EXPECT_TRUE(file_system_.Exists(path2)); - EXPECT_TRUE(file_system_.Remove(wildcard_path)); - EXPECT_FALSE(file_system_.Exists(path1)); - EXPECT_FALSE(file_system_.Exists(path2)); + EXPECT_TRUE(file_system_.Exists(path1)) << "path = " << path1; + EXPECT_TRUE(file_system_.Exists(path2)) << "path = " << path2; + EXPECT_TRUE(file_system_.Remove(wildcard_path)) + << "wildcard_path = " << wildcard_path; + EXPECT_FALSE(file_system_.Exists(path1)) << "path = " << path1; + EXPECT_FALSE(file_system_.Exists(path2)) << "path = " << path2; } TEST_F(FileTest, FileSize) { - std::string path = wvcdm::test_vectors::kTestDir + kTestFileName; + const std::string path = + PathJoin(wvcdm::test_vectors::kTestDir, kTestFilename); file_system_.Remove(path); - std::string write_data = CdmRandom::RandomData(600); - size_t write_data_size = write_data.size(); - std::unique_ptr file = file_system_.Open(path, FileSystem::kCreate); - ASSERT_TRUE(file); - EXPECT_EQ(file->Write(write_data.data(), write_data_size), write_data_size); - EXPECT_TRUE(file_system_.Exists(path)); + constexpr size_t kDataSize = 600; + const std::string write_data = CdmRandom::RandomData(kDataSize); + ASSERT_EQ(write_data.size(), kDataSize); - EXPECT_EQ(static_cast(write_data_size), file_system_.FileSize(path)); + std::unique_ptr file = file_system_.Open(path, FileSystem::kCreate); + ASSERT_TRUE(file) << "Failed to create file: " << path; + + EXPECT_EQ(file->Write(write_data.data(), write_data.size()), + write_data.size()); + file.reset(); // Close file. + + EXPECT_TRUE(file_system_.Exists(path)) << "path = " << path; + + EXPECT_EQ(static_cast(kDataSize), file_system_.FileSize(path)) + << "path = " << path; } TEST_F(FileTest, WriteReadBinaryFile) { - std::string path = wvcdm::test_vectors::kTestDir + kTestFileName; + const std::string path = + PathJoin(wvcdm::test_vectors::kTestDir, kTestFilename); file_system_.Remove(path); - std::string write_data = CdmRandom::RandomData(600); - size_t write_data_size = write_data.size(); - std::unique_ptr file = file_system_.Open(path, FileSystem::kCreate); - ASSERT_TRUE(file); - EXPECT_EQ(file->Write(write_data.data(), write_data_size), write_data_size); - EXPECT_TRUE(file_system_.Exists(path)); + constexpr size_t kDataSize = 600; + const std::string write_data = CdmRandom::RandomData(kDataSize); + ASSERT_EQ(write_data.size(), kDataSize); + + std::unique_ptr file = file_system_.Open(path, FileSystem::kCreate); + ASSERT_TRUE(file) << "Failed to create file: " << path; + + constexpr ssize_t kExpectedFileSizeResult = static_cast(kDataSize); + EXPECT_EQ(file->Write(write_data.data(), write_data.size()), + kExpectedFileSizeResult) + << "path = " << path; + file.reset(); // Close file. + + EXPECT_TRUE(file_system_.Exists(path)) << "path = " << path; - std::string read_data; - read_data.resize(file_system_.FileSize(path)); - size_t read_data_size = read_data.size(); file = file_system_.Open(path, FileSystem::kReadOnly); - ASSERT_TRUE(file); - EXPECT_EQ(file->Read(&read_data[0], read_data_size), read_data_size); + ASSERT_TRUE(file) << "Failed to re-open file: " << path; + + std::string read_data(kDataSize, '\0'); + ; + ASSERT_EQ(file->Read(&read_data[0], read_data.size()), + kExpectedFileSizeResult) + << "path = " << path; EXPECT_EQ(write_data, read_data); } TEST_F(FileTest, ListFiles) { - std::vector names; + const std::string kTxtFilename1 = "data.txt"; + const std::string kTxtFilename2 = "other.txt"; + const std::string kBinFilename = "sample.bin"; - std::string not_path("zzz"); - std::string path1 = wvcdm::test_vectors::kTestDir + kTestFileName; - std::string path2 = wvcdm::test_vectors::kTestDir + kTestFileName2; - std::string path3 = wvcdm::test_vectors::kTestDir + kTestFileName3; - std::string path_dir = wvcdm::test_vectors::kTestDir; + const std::string dir_path = wvcdm::test_vectors::kTestDir; + const std::string path1 = PathJoin(dir_path, kTxtFilename1); + const std::string path2 = PathJoin(dir_path, kTxtFilename2); + const std::string path3 = PathJoin(dir_path, kBinFilename); + // Create files. std::unique_ptr file = file_system_.Open(path1, FileSystem::kCreate); - ASSERT_TRUE(file); + ASSERT_TRUE(file) << "Failed to create file (1): " << path1; file = file_system_.Open(path2, FileSystem::kCreate); - ASSERT_TRUE(file); + ASSERT_TRUE(file) << "Failed to create file (2): " << path2; file = file_system_.Open(path3, FileSystem::kCreate); - ASSERT_TRUE(file); + ASSERT_TRUE(file) << "Failed to create file (3): " << path3; + file.reset(); // Close file EXPECT_TRUE(file_system_.Exists(path1)); EXPECT_TRUE(file_system_.Exists(path2)); EXPECT_TRUE(file_system_.Exists(path3)); - // Ask for non-existent path. - EXPECT_FALSE(file_system_.List(not_path, &names)); + std::vector names; + ASSERT_TRUE(file_system_.List(dir_path, &names)) << "dir_path = " << dir_path; - // Valid path, but no way to return names. - EXPECT_FALSE(file_system_.List(path_dir, nullptr)); + size_t expected_file_count = 3; + EXPECT_EQ(names.size(), expected_file_count); - // Valid path, valid return. - EXPECT_TRUE(file_system_.List(path_dir, &names)); - - // Should find three files. Order not important. - EXPECT_EQ(3u, names.size()); + // Should find the three files. Order not important. EXPECT_THAT(names, ::testing::UnorderedElementsAre( - kTestFileName, kTestFileName2, kTestFileName3)); + kTxtFilename1, kTxtFilename2, kBinFilename)); - std::string wild_card_path = path_dir + kWildcard + kTestFileNameExt; - EXPECT_TRUE(file_system_.Remove(wild_card_path)); - EXPECT_TRUE(file_system_.List(path_dir, &names)); + // Remove .txt files. + const std::string txt_wildcard_path = PathJoin(dir_path, "*.txt"); - EXPECT_EQ(1u, names.size()); - EXPECT_TRUE(names[0].compare(kTestFileName3) == 0); + EXPECT_TRUE(file_system_.Remove(txt_wildcard_path)) + << "txt_wildcard_path = " << txt_wildcard_path; + EXPECT_TRUE(file_system_.List(dir_path, &names)) << "dir_path = " << dir_path; - std::string wild_card_path2 = path_dir + kWildcard + kTestFileNameExt3; - EXPECT_TRUE(file_system_.Remove(wild_card_path2)); - EXPECT_TRUE(file_system_.List(path_dir, &names)); + expected_file_count = 1; + ASSERT_EQ(names.size(), expected_file_count); + EXPECT_EQ(names.front(), kBinFilename); - EXPECT_EQ(0u, names.size()); + const std::string bin_wildcard_path = PathJoin(dir_path, "*.bin"); + EXPECT_TRUE(file_system_.Remove(bin_wildcard_path)) + << "bin_wildcard_path = " << bin_wildcard_path; + + // All files should be removed, but listing should still succeed. + EXPECT_TRUE(file_system_.List(dir_path, &names)) << "dir_path = " << dir_path; + expected_file_count = 0; + EXPECT_EQ(expected_file_count, names.size()); } -TEST_F(FileTest, CreateGlobalCertificates) { - // Clear directory +TEST_F(FileTest, ListFiles_NotAPath) { + const std::string not_path("zzz/xxx"); std::vector names; - std::string path_dir = wvcdm::test_vectors::kTestDir; - std::string wild_card_path = path_dir + kWildcard; - file_system_.Remove(wild_card_path); - if (file_system_.List(path_dir, &names)) { - EXPECT_EQ(0u, names.size()); + // Ask for non-existent path. + EXPECT_FALSE(file_system_.List(not_path, &names)); +} + +TEST_F(FileTest, ListFiles_NullParameter) { + const std::string dir_path = wvcdm::test_vectors::kTestDir; + const std::string path = PathJoin(dir_path, kTestFilename); + + std::unique_ptr file = file_system_.Open(path, FileSystem::kCreate); + ASSERT_TRUE(file) << "Failed to create file: " << path; + file.reset(); // Close file. + + // Valid path, but no way to return names. + EXPECT_FALSE(file_system_.List(dir_path, nullptr)); +} + +// On certain platforms, the FileSystem may perform special +// name translations on certificate filenames which make them behave +// differently from non-certificate filenames. +TEST_F(FileTest, CreateGlobalCertificates) { + ASSERT_TRUE(file_system_.IsGlobal()) + << "Test case requires global file system"; + + const std::string dir_path = wvcdm::test_vectors::kTestDir; + + // Clear directory + const std::string all_file_wildcard_path = PathJoin(dir_path, "*"); + file_system_.Remove(all_file_wildcard_path); + // Ensure directory is empty. + std::vector names; + if (file_system_.List(dir_path, &names)) { + constexpr size_t kZero = 0; + ASSERT_EQ(kZero, names.size()) << "Test requires empty directory"; } - // Create certificates and verify that they exist - std::string certificate_path = - wvcdm::test_vectors::kTestDir + kCertificateFileName; - std::string legacy_certificate_path = - wvcdm::test_vectors::kTestDir + kLegacyCertificateFileName; + const std::string certificate_path = PathJoin(dir_path, kCertificateFileName); + const std::string legacy_certificate_path = + PathJoin(dir_path, kLegacyCertificateFileName); + // Create certificates and verify that they exist std::unique_ptr file = file_system_.Open(certificate_path, FileSystem::kCreate); - ASSERT_TRUE(file); + ASSERT_TRUE(file) << "Failed to create certificate file: " + << certificate_path; + file = file_system_.Open(legacy_certificate_path, FileSystem::kCreate); - ASSERT_TRUE(file); - EXPECT_TRUE(file_system_.IsGlobal()); + ASSERT_TRUE(file) << "Failed to create legacy certificate file: " + << legacy_certificate_path; + file.reset(); // Close file. - EXPECT_TRUE(file_system_.Exists(certificate_path)); - EXPECT_TRUE(file_system_.Exists(legacy_certificate_path)); + EXPECT_TRUE(file_system_.Exists(certificate_path)) + << "certificate_path = " << certificate_path; + EXPECT_TRUE(file_system_.Exists(legacy_certificate_path)) + << "legacy_certificate_path = " << legacy_certificate_path; - EXPECT_TRUE(file_system_.List(path_dir, &names)); + ASSERT_TRUE(file_system_.List(dir_path, &names)); // Should find two files. Order not important. - EXPECT_EQ(2u, names.size()); + constexpr size_t kExpectedCount = 2; + EXPECT_EQ(kExpectedCount, names.size()); EXPECT_THAT(names, ::testing::UnorderedElementsAre( kCertificateFileName, kLegacyCertificateFileName)); } +// On certain platforms, the FileSystem may perform special +// name translations on certificate filenames which make them behave +// differently from non-certificate filenames. TEST_F(FileTest, CreateCertificates) { + ASSERT_TRUE(file_system_.IsGlobal()) + << "Test case requires starting with a global file system"; + const std::string dir_path = wvcdm::test_vectors::kTestDir; + // Clear directory + const std::string all_file_wildcard_path = PathJoin(dir_path, "*"); + file_system_.Remove(all_file_wildcard_path); + // Ensure directory is empty. std::vector names; - std::string path_dir = wvcdm::test_vectors::kTestDir; - std::string wild_card_path = path_dir + kWildcard; - file_system_.Remove(wild_card_path); - if (file_system_.List(path_dir, &names)) { - EXPECT_EQ(0u, names.size()); + if (file_system_.List(dir_path, &names)) { + constexpr size_t kZero = 0; + ASSERT_EQ(kZero, names.size()) << "Test requires empty directory"; } - std::string certificate_path = - wvcdm::test_vectors::kTestDir + kCertificateFileName; - std::string legacy_certificate_path = - wvcdm::test_vectors::kTestDir + kLegacyCertificateFileName; + const std::string certificate_path = PathJoin(dir_path, kCertificateFileName); + const std::string legacy_certificate_path = + PathJoin(dir_path, kLegacyCertificateFileName); - // Create Global certificates + // Create Global certificates. std::unique_ptr file = file_system_.Open(certificate_path, FileSystem::kCreate); - ASSERT_TRUE(file); + ASSERT_TRUE(file) << "Failed to create global certificate: " + << certificate_path; file = file_system_.Open(legacy_certificate_path, FileSystem::kCreate); - ASSERT_TRUE(file); - EXPECT_TRUE(file_system_.IsGlobal()); + ASSERT_TRUE(file) << "Failed to create global legacy certificate: " + << legacy_certificate_path; + file.reset(); // Close file. + + EXPECT_TRUE(file_system_.Exists(certificate_path)) + << "Global certificate: " << certificate_path; + EXPECT_TRUE(file_system_.Exists(legacy_certificate_path)) + << "Global legacy certificate: " << legacy_certificate_path; + + // Switch to first identifier. + file_system_.set_identifier(kTestIdentifier1); + ASSERT_FALSE(file_system_.IsGlobal()) << "identifier = " << kTestIdentifier1; + + // Global certificates should not be visible once identifier has been + // specified. + EXPECT_FALSE(file_system_.Exists(certificate_path)) + << kTestIdentifier1 << " certificate: " << certificate_path; + EXPECT_FALSE(file_system_.Exists(legacy_certificate_path)) + << kTestIdentifier1 << " legacy certificate: " << legacy_certificate_path; // Create certificates with first identifier - file_system_.set_identifier(kTestIdentifier1); file = file_system_.Open(certificate_path, FileSystem::kCreate); - ASSERT_TRUE(file); + ASSERT_TRUE(file) << "Failed to create " << kTestIdentifier1 + << " certificate: " << certificate_path; file = file_system_.Open(legacy_certificate_path, FileSystem::kCreate); - ASSERT_TRUE(file); - EXPECT_TRUE(!file_system_.IsGlobal()); + ASSERT_TRUE(file) << "Failed to create " << kTestIdentifier1 + << " legacy certificate: " << legacy_certificate_path; + file.reset(); // Close file. + + // Verify they now exist. + EXPECT_TRUE(file_system_.Exists(certificate_path)) + << kTestIdentifier1 << " certificate: " << certificate_path; + EXPECT_TRUE(file_system_.Exists(legacy_certificate_path)) + << kTestIdentifier1 << " legacy certificate: " << legacy_certificate_path; + + // Switch to second identifier. + file_system_.set_identifier(kTestIdentifier2); + ASSERT_FALSE(file_system_.IsGlobal()) << "identifier = " << kTestIdentifier2; + + // Global and first identifier certificates should not be + // visible. + EXPECT_FALSE(file_system_.Exists(certificate_path)) + << kTestIdentifier2 << " certificate: " << certificate_path; + EXPECT_FALSE(file_system_.Exists(legacy_certificate_path)) + << kTestIdentifier2 << " legacy certificate: " << legacy_certificate_path; // Create certificates with second identifier - file_system_.set_identifier(kTestIdentifier2); file = file_system_.Open(certificate_path, FileSystem::kCreate); - ASSERT_TRUE(file); + ASSERT_TRUE(file) << "Failed to create " << kTestIdentifier2 + << " certificate: " << certificate_path; file = file_system_.Open(legacy_certificate_path, FileSystem::kCreate); - ASSERT_TRUE(file); - EXPECT_TRUE(!file_system_.IsGlobal()); + ASSERT_TRUE(file) << "Failed to create " << kTestIdentifier2 + << " legacy certificate: " << legacy_certificate_path; + file.reset(); // Close file. - EXPECT_TRUE(file_system_.Exists(certificate_path)); - EXPECT_TRUE(file_system_.Exists(legacy_certificate_path)); + // Verify they now exist. + EXPECT_TRUE(file_system_.Exists(certificate_path)) + << kTestIdentifier2 << " certificate: " << certificate_path; + EXPECT_TRUE(file_system_.Exists(legacy_certificate_path)) + << kTestIdentifier2 << " legacy certificate: " << legacy_certificate_path; - EXPECT_TRUE(file_system_.List(path_dir, &names)); + // FileSystem::List is expected to still return all certificate files + // (both global and scoped). + ASSERT_TRUE(file_system_.List(dir_path, &names)) << "dir_path = " << dir_path; // Should find six files. Order not important. + constexpr size_t kExpectedTotalCertCount = 6; + ASSERT_EQ(names.size(), kExpectedTotalCertCount); + bool is_global_certificate_present = false; bool is_global_legacy_certificate_present = false; size_t certificate_count = 0; size_t legacy_certificate_count = 0; - EXPECT_EQ(6u, names.size()); - for (size_t i = 0; i < names.size(); ++i) { - if (names[i].size() > kCertificateFileName.size()) { - if (names[i].compare(0, kCertificateFileNamePrefix.size(), - kCertificateFileNamePrefix) == 0) - ++certificate_count; - else if (names[i].compare(0, kLegacyCertificateFileNamePrefix.size(), - kLegacyCertificateFileNamePrefix) == 0) - ++legacy_certificate_count; - } else if (names[i].compare(kCertificateFileName) == 0) { - is_global_certificate_present = true; - } else if (names[i].compare(kLegacyCertificateFileName) == 0) { + for (const auto& filename : names) { + if (filename == kLegacyCertificateFileName) { is_global_legacy_certificate_present = true; + } else if (filename == kCertificateFileName) { + is_global_certificate_present = true; + } else if (StartsWith(filename, kScopedCertificateFilenamePrefix)) { + certificate_count++; + } else if (StartsWith(filename, kLegacyScopedCertificateFilenamePrefix)) { + legacy_certificate_count++; } else { - EXPECT_TRUE(false); + ADD_FAILURE() << "Unexpected filename: " << filename; } } - EXPECT_EQ(2, certificate_count); - EXPECT_EQ(2, legacy_certificate_count); - EXPECT_TRUE(is_global_certificate_present); - EXPECT_TRUE(is_global_legacy_certificate_present); + constexpr size_t kExpectedScopedCertCount = 2; + EXPECT_EQ(certificate_count, kExpectedScopedCertCount) + << "Missing certificates"; + EXPECT_EQ(legacy_certificate_count, kExpectedScopedCertCount) + << "Missing legacy certificates"; + EXPECT_TRUE(is_global_certificate_present) + << "Missing global certificate: " << kCertificateFileName; + EXPECT_TRUE(is_global_legacy_certificate_present) + << "Missing legacy global certificate: " << kLegacyCertificateFileName; } +// On certain platforms, the FileSystem may perform special +// name translations on certificate file names which make them behave +// differently from non-certificate file names. TEST_F(FileTest, RemoveCertificates) { + ASSERT_TRUE(file_system_.IsGlobal()) + << "Test case requires starting with a global file system"; + const std::string dir_path = wvcdm::test_vectors::kTestDir; + // Clear directory + const std::string all_file_wildcard_path = PathJoin(dir_path, "*"); + file_system_.Remove(all_file_wildcard_path); + // Ensure directory is empty. std::vector names; - std::string path_dir = wvcdm::test_vectors::kTestDir; - std::string wild_card_path = path_dir + kWildcard; - file_system_.Remove(wild_card_path); - if (file_system_.List(path_dir, &names)) { - EXPECT_EQ(0u, names.size()); + if (file_system_.List(dir_path, &names)) { + constexpr size_t kZero = 0; + ASSERT_EQ(kZero, names.size()) << "Test requires empty directory"; } - std::string certificate_path = - wvcdm::test_vectors::kTestDir + kCertificateFileName; - std::string legacy_certificate_path = - wvcdm::test_vectors::kTestDir + kLegacyCertificateFileName; + const std::string certificate_path = PathJoin(dir_path, kCertificateFileName); + const std::string legacy_certificate_path = + PathJoin(dir_path, kLegacyCertificateFileName); - // Create Global certificates + // Create Global certificates. std::unique_ptr file = file_system_.Open(certificate_path, FileSystem::kCreate); - ASSERT_TRUE(file); + ASSERT_TRUE(file) << "Failed to create global certificate: " + << certificate_path; file = file_system_.Open(legacy_certificate_path, FileSystem::kCreate); - ASSERT_TRUE(file); - EXPECT_TRUE(file_system_.IsGlobal()); + ASSERT_TRUE(file) << "Failed to create global legacy certificate: " + << legacy_certificate_path; + file.reset(); // Close file. + + // Switch to first identifier. + file_system_.set_identifier(kTestIdentifier1); + ASSERT_FALSE(file_system_.IsGlobal()) << "identifier = " << kTestIdentifier1; // Create certificates with first identifier - file_system_.set_identifier(kTestIdentifier1); file = file_system_.Open(certificate_path, FileSystem::kCreate); - ASSERT_TRUE(file); + ASSERT_TRUE(file) << "Failed to create " << kTestIdentifier1 + << " certificate: " << certificate_path; file = file_system_.Open(legacy_certificate_path, FileSystem::kCreate); - ASSERT_TRUE(file); - EXPECT_TRUE(!file_system_.IsGlobal()); + ASSERT_TRUE(file) << "Failed to create " << kTestIdentifier1 + << " legacy certificate: " << legacy_certificate_path; + file.reset(); // Close file. + + // Switch to second identifier. + file_system_.set_identifier(kTestIdentifier2); + ASSERT_FALSE(file_system_.IsGlobal()) << "identifier = " << kTestIdentifier2; // Create certificates with second identifier - file_system_.set_identifier(kTestIdentifier2); file = file_system_.Open(certificate_path, FileSystem::kCreate); - ASSERT_TRUE(file); + ASSERT_TRUE(file) << "Failed to create " << kTestIdentifier2 + << " certificate: " << certificate_path; file = file_system_.Open(legacy_certificate_path, FileSystem::kCreate); - ASSERT_TRUE(file); - EXPECT_TRUE(!file_system_.IsGlobal()); + ASSERT_TRUE(file) << "Failed to create " << kTestIdentifier2 + << " legacy certificate: " << legacy_certificate_path; + file.reset(); // Close file. - EXPECT_TRUE(file_system_.Exists(certificate_path)); - EXPECT_TRUE(file_system_.Exists(legacy_certificate_path)); - - EXPECT_TRUE(file_system_.List(path_dir, &names)); - - EXPECT_EQ(6u, names.size()); + // FileSystem::List is expected to still return all certificate files + // (both global and scoped). + ASSERT_TRUE(file_system_.List(dir_path, &names)) << "dir_path = " << dir_path; + // Should find six files. Order not important. + constexpr size_t kExpectedTotalCertCount = 6; + ASSERT_EQ(names.size(), kExpectedTotalCertCount); + std::set removed_certs; // Remove all even number listed files for (size_t i = 0; i < names.size(); ++i) { - if (i % 2 == 0) { - EXPECT_TRUE( - file_system_.Remove(wvcdm::test_vectors::kTestDir + names[i])); - } + if ((i % 2) != 0) continue; + const std::string& cert_filename = names[i]; + const std::string cert_path = PathJoin(dir_path, cert_filename); + ASSERT_TRUE(file_system_.Remove(cert_path)) + << "Failed to remove cert: " << cert_path; + removed_certs.insert(cert_filename); } // Verify that they have been removed - for (size_t i = 0; i < names.size(); ++i) { - if (i % 2 == 1) { - EXPECT_TRUE( - file_system_.Exists(wvcdm::test_vectors::kTestDir + names[i])); + for (const std::string& cert_filename : names) { + const std::string cert_path = PathJoin(dir_path, cert_filename); + if (removed_certs.find(cert_filename) == removed_certs.end()) { + // Ensure still exists. + ASSERT_TRUE(file_system_.Exists(cert_path)) + << "Cert missing: " << cert_filename; } else { - EXPECT_FALSE( - file_system_.Exists(wvcdm::test_vectors::kTestDir + names[i])); + ASSERT_FALSE(file_system_.Exists(cert_path)) + << "Cert not removed: " << cert_filename; } } - // Remove all odd number listed files - for (size_t i = 0; i < names.size(); ++i) { - if (i % 2 == 1) { - EXPECT_TRUE( - file_system_.Remove(wvcdm::test_vectors::kTestDir + names[i])); - } + // Remove all remaining. + for (const std::string& cert_filename : names) { + if (removed_certs.find(cert_filename) != removed_certs.end()) continue; + const std::string cert_path = PathJoin(dir_path, cert_filename); + ASSERT_TRUE(file_system_.Remove(cert_path)) + << "Failed to remove cert: " << cert_path; } // Verify that all have been removed - for (size_t i = 0; i < names.size(); ++i) { - EXPECT_FALSE(file_system_.Exists(wvcdm::test_vectors::kTestDir + names[i])); + for (const std::string& cert_filename : names) { + const std::string cert_path = PathJoin(dir_path, cert_filename); + EXPECT_FALSE(file_system_.Exists(cert_path)) + << "Cert not removed: " << cert_filename; } } - } // namespace wvutil