chromium/components/download/internal/common/download_file_unittest.cc

// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifdef UNSAFE_BUFFERS_BUILD
// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
#pragma allow_unsafe_buffers
#endif

#include <stddef.h>
#include <stdint.h>

#include <memory>
#include <string_view>
#include <utility>
#include <vector>

#include "base/files/file.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/functional/bind.h"
#include "base/location.h"
#include "base/memory/raw_ptr.h"
#include "base/run_loop.h"
#include "base/strings/string_number_conversions.h"
#include "base/task/sequenced_task_runner.h"
#include "base/task/single_thread_task_runner.h"
#include "base/test/task_environment.h"
#include "base/test/test_file_util.h"
#include "build/build_config.h"
#include "components/download/public/common/download_create_info.h"
#include "components/download/public/common/download_destination_observer.h"
#include "components/download/public/common/download_file_impl.h"
#include "components/download/public/common/download_interrupt_reasons.h"
#include "components/download/public/common/mock_input_stream.h"
#include "net/base/net_errors.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"

#if BUILDFLAG(IS_WIN)
#include "base/win/scoped_com_initializer.h"
#endif

_;
AnyNumber;
DoAll;
InSequence;
Return;
Sequence;
SetArgPointee;
StrictMock;

namespace download {
namespace {

// Struct for SourceStream states verification.
struct SourceStreamTestData {};

int64_t GetBuffersLength(const char** buffers, size_t num_buffer) {}

std::string GetHexEncodedHashValue(crypto::SecureHash* hash_state) {}

class MockDownloadDestinationObserver : public DownloadDestinationObserver {};

enum DownloadFileRenameMethodType {};

// This is a test DownloadFileImpl that has no retry delay and, on Posix,
// retries renames failed due to ACCESS_DENIED.
class TestDownloadFileImpl : public DownloadFileImpl {};

}  // namespace

class DownloadFileTest : public testing::Test {};

// DownloadFile::RenameAndAnnotate and DownloadFile::RenameAndUniquify have a
// considerable amount of functional overlap. In order to re-use test logic, we
// are going to introduce this value parameterized test fixture. It will take a
// DownloadFileRenameMethodType value which can be either of the two rename
// methods.
class DownloadFileTestWithRename
    : public DownloadFileTest,
      public ::testing::WithParamInterface<DownloadFileRenameMethodType> {};

// And now instantiate all DownloadFileTestWithRename tests using both
// DownloadFile rename methods. Each test of the form
// DownloadFileTestWithRename.<FooTest> will be instantiated once with
// RenameAndAnnotate as the value parameter and once with RenameAndUniquify as
// the value parameter.
INSTANTIATE_TEST_SUITE_P();

const char DownloadFileTest::kTestData1[] =;
const char DownloadFileTest::kTestData2[] =;
const char DownloadFileTest::kTestData3[] =;
const char DownloadFileTest::kTestData4[] =;
const char DownloadFileTest::kTestData5[] =;
const char* DownloadFileTest::kTestData6[] =;
const char* DownloadFileTest::kTestData7[] =;
const char* DownloadFileTest::kTestData8[] =;

const char DownloadFileTest::kDataHash[] =;
const char DownloadFileTest::kEmptyHash[] =;

const uint32_t DownloadFileTest::kDummyDownloadId =;
const int DownloadFileTest::kDummyChildId =;
const int DownloadFileTest::kDummyRequestId =;

// Rename the file before any data is downloaded, after some has, after it all
// has, and after it's closed.
TEST_P(DownloadFileTestWithRename, RenameFileFinal) {}

// Test to make sure the rename overwrites when requested. This is separate from
// the above test because it only applies to RenameAndAnnotate().
// RenameAndUniquify() doesn't overwrite by design.
TEST_F(DownloadFileTest, RenameOverwrites) {}

// Test to make sure the rename uniquifies if we aren't overwriting
// and there's a file where we're aiming. As above, not a
// DownloadFileTestWithRename test because this only applies to
// RenameAndUniquify().
TEST_F(DownloadFileTest, RenameUniquifies) {}

// Test that RenameAndUniquify doesn't try to uniquify in the case where the
// target filename is the same as the current filename.
TEST_F(DownloadFileTest, RenameRecognizesSelfConflict) {}

#if BUILDFLAG(IS_MAC)
// Test that RenameAndUniquify will remove file hidden flag.
TEST_F(DownloadFileTest, RenameRemovesHiddenFlag) {
  ASSERT_TRUE(CreateDownloadFile(true));
  base::FilePath initial_path(download_file_->FullPath());
  EXPECT_TRUE(base::PathExists(initial_path));
  // Set the file hidden.
  base::stat_wrapper_t stat;
  base::File::Stat(initial_path, &stat);
  // Update the file's hidden flags.
  chflags(initial_path.value().c_str(), stat.st_flags | UF_HIDDEN);

  base::FilePath target_path =
      initial_path.DirName().Append(FILE_PATH_LITERAL("foo"));
  base::FilePath new_path;
  EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE,
            RenameAndUniquify(target_path, &new_path));
  EXPECT_TRUE(base::PathExists(target_path));
  base::File::Stat(initial_path, &stat);
  EXPECT_FALSE(stat.st_flags & UF_HIDDEN);

  FinishStream(DOWNLOAD_INTERRUPT_REASON_NONE, true, kEmptyHash);
  base::RunLoop().RunUntilIdle();

  DestroyDownloadFile(0);
  EXPECT_EQ(target_path.value(), new_path.value());
}
#endif

#if BUILDFLAG(IS_FUCHSIA)
// TODO(crbug.com/40221273): Re-enable when RenameError works on Fuchsia.
#define MAYBE_RenameError
#else
#define MAYBE_RenameError
#endif
// Test to make sure we get the proper error on failure.
TEST_P(DownloadFileTestWithRename, MAYBE_RenameError) {}

namespace {

void TestRenameCompletionCallback(base::OnceClosure closure,
                                  bool* did_run_callback,
                                  DownloadInterruptReason interrupt_reason,
                                  const base::FilePath& new_path) {}

}  // namespace

#if BUILDFLAG(IS_FUCHSIA)
// TODO(crbug.com/40221274): Re-enable when RenameWithErrorRetry works on
// Fuchsia.
#define MAYBE_RenameWithErrorRetry
#else
#define MAYBE_RenameWithErrorRetry
#endif
// Test that the retry logic works. This test assumes that DownloadFileImpl will
// post tasks to the current message loop (acting as the download sequence)
// asynchronously to retry the renames. We will stuff RunLoop::QuitClosures()
// in between the retry tasks to stagger them and then allow the rename to
// succeed.
//
// Note that there is only one queue of tasks to run, and that is in the tests'
// base::CurrentThread::Get(). Each RunLoop processes that queue until it
// sees a QuitClosure() targeted at itself, at which point it stops processing.
TEST_P(DownloadFileTestWithRename, MAYBE_RenameWithErrorRetry) {}

// Various tests of the StreamActive method.
TEST_F(DownloadFileTest, StreamEmptySuccess) {}

TEST_F(DownloadFileTest, StreamEmptyError) {}

TEST_F(DownloadFileTest, StreamNonEmptySuccess) {}

TEST_F(DownloadFileTest, StreamNonEmptyError) {}

// Tests that if file content validation succeeds, all the remaining data will
// be writing to the file.
TEST_F(DownloadFileTest, FileContentValidationSuccess) {}

// Tests that if file content validation fails, an error will occur and no data
// will be written.
TEST_F(DownloadFileTest, FileContentValidationFail) {}

// Tests for concurrent streams handling, used for parallel download.
//
// Activate both streams at the same time.
TEST_F(DownloadFileTest, MultipleStreamsWrite) {}

// 3 streams write to one sink, the second stream has a limited length.
TEST_F(DownloadFileTest, MultipleStreamsLimitedLength) {}

// Activate and deplete one stream, later add the second stream.
TEST_F(DownloadFileTest, MultipleStreamsFirstStreamWriteAllData) {}

// While one stream is writing, kick off another stream with an offset that has
// been written by the first one.
TEST_F(DownloadFileTest, SecondStreamStartingOffsetAlreadyWritten) {}

// The second stream successfully reads the data from its offset. However,
// before it is able to write the data, the same block was written by
// the first stream.
TEST_F(DownloadFileTest, SecondStreamReadsOffsetWrittenByFirst) {}

}  // namespace download