/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "FileSystemHashSource.h" #include "FileSystemParentTypes.h" #include "TestHelpers.h" #include "gtest/gtest.h" #include "mozilla/Array.h" #include "mozilla/dom/FileSystemTypes.h" #include "nsContentUtils.h" #include "nsLiteralString.h" #include "nsString.h" #include "nsStringFwd.h" #include "nsTArray.h" #include "nsTHashSet.h" namespace mozilla::dom::fs::test { using mozilla::dom::fs::data::FileSystemHashSource; namespace { constexpr size_t sha256ByteLength = 32u; constexpr size_t kExpectedLength = 52u; std::wstring asWide(const nsString& aStr) { std::wstring result; result.reserve(aStr.Length()); for (const auto* it = aStr.BeginReading(); it != aStr.EndReading(); ++it) { result.push_back(static_cast(*it)); } return result; } } // namespace TEST(TestFileSystemHashSource, isHashLengthAsExpected) { EntryId parent = "a"_ns; Name name = u"b"_ns; TEST_TRY_UNWRAP(EntryId result, FileSystemHashSource::GenerateHash(parent, name)); ASSERT_EQ(sha256ByteLength, result.Length()); }; TEST(TestFileSystemHashSource, areNestedNameHashesValidAndUnequal) { EntryId emptyParent = ""_ns; Name name = u"a"_ns; const size_t nestingNumber = 500u; nsTHashSet results; nsTHashSet names; auto previousParent = emptyParent; for (size_t i = 0; i < nestingNumber; ++i) { TEST_TRY_UNWRAP(EntryId result, FileSystemHashSource::GenerateHash(previousParent, name)); TEST_TRY_UNWRAP(Name encoded, FileSystemHashSource::EncodeHash(FileId(result))); // Validity checks ASSERT_TRUE(mozilla::IsAscii(encoded)) << encoded; Name upperCaseVersion; nsContentUtils::ASCIIToUpper(encoded, upperCaseVersion); ASSERT_STREQ(asWide(upperCaseVersion).c_str(), asWide(encoded).c_str()); // Is the same hash encountered? ASSERT_FALSE(results.Contains(result)); ASSERT_TRUE(results.Insert(result, mozilla::fallible)); // Is the same name encountered? ASSERT_FALSE(names.Contains(encoded)); ASSERT_TRUE(names.Insert(encoded, mozilla::fallible)); previousParent = result; } }; TEST(TestFileSystemHashSource, areNameCombinationHashesUnequal) { EntryId emptyParent = ""_ns; mozilla::Array inputs = {u"a"_ns, u"b"_ns}; nsTArray results; nsTArray names; for (const auto& name : inputs) { TEST_TRY_UNWRAP(EntryId result, FileSystemHashSource::GenerateHash(emptyParent, name)); TEST_TRY_UNWRAP(Name encoded, FileSystemHashSource::EncodeHash(FileId(result))); // Validity checks ASSERT_TRUE(mozilla::IsAscii(encoded)) << encoded; Name upperCaseVersion; nsContentUtils::ASCIIToUpper(encoded, upperCaseVersion); ASSERT_STREQ(asWide(upperCaseVersion).c_str(), asWide(encoded).c_str()); results.AppendElement(result); names.AppendElement(encoded); } nsTArray more_results; nsTArray more_names; for (const auto& parent : results) { for (const auto& name : inputs) { TEST_TRY_UNWRAP(EntryId result, FileSystemHashSource::GenerateHash(parent, name)); TEST_TRY_UNWRAP(Name encoded, FileSystemHashSource::EncodeHash(FileId(result))); // Validity checks ASSERT_TRUE(mozilla::IsAscii(encoded)) << encoded; Name upperCaseVersion; nsContentUtils::ASCIIToUpper(encoded, upperCaseVersion); ASSERT_STREQ(asWide(upperCaseVersion).c_str(), asWide(encoded).c_str()); more_results.AppendElement(result); more_names.AppendElement(encoded); } } results.AppendElements(more_results); names.AppendElements(more_names); // Is the same hash encountered? for (size_t i = 0; i < results.Length(); ++i) { for (size_t j = i + 1; j < results.Length(); ++j) { ASSERT_STRNE(results[i].get(), results[j].get()); } } // Is the same name encountered? for (size_t i = 0; i < names.Length(); ++i) { for (size_t j = i + 1; j < names.Length(); ++j) { ASSERT_STRNE(asWide(names[i]).c_str(), asWide(names[j]).c_str()); } } }; TEST(TestFileSystemHashSource, encodeGeneratedHash) { Name expected = u"HF6FOFV72G3NMDEJKYMVRIFJO4X5ZNZCF2GM7Q4Y5Q3E7NPQKSLA"_ns; ASSERT_EQ(kExpectedLength, expected.Length()); EntryId parent = "a"_ns; Name name = u"b"_ns; TEST_TRY_UNWRAP(EntryId entry, FileSystemHashSource::GenerateHash(parent, name)); ASSERT_EQ(sha256ByteLength, entry.Length()); TEST_TRY_UNWRAP(Name result, FileSystemHashSource::EncodeHash(FileId(entry))); ASSERT_EQ(kExpectedLength, result.Length()); ASSERT_STREQ(asWide(expected).c_str(), asWide(result).c_str()); // Generate further hashes TEST_TRY_UNWRAP(entry, FileSystemHashSource::GenerateHash(entry, result)); ASSERT_EQ(sha256ByteLength, entry.Length()); TEST_TRY_UNWRAP(result, FileSystemHashSource::EncodeHash(FileId(entry))); // Always the same length ASSERT_EQ(kExpectedLength, result.Length()); // Encoded versions should differ ASSERT_STRNE(asWide(expected).c_str(), asWide(result).c_str()); // Padding length should have been stripped char16_t padding = u"="_ns[0]; const int32_t paddingStart = result.FindChar(padding); ASSERT_EQ(-1, paddingStart); }; } // namespace mozilla::dom::fs::test