File: test_file_util.cc

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (135 lines) | stat: -rw-r--r-- 4,066 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/test/test_file_util.h"

#include <vector>

#include "base/files/file_enumerator.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/logging.h"
#include "base/test/test_timeouts.h"
#include "base/threading/platform_thread.h"
#include "base/threading/thread_restrictions.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace base {

namespace {

constexpr FilePath::CharType kDirPrefix[] =
    FILE_PATH_LITERAL("test_scoped_temp_dir");

// Deletes all registered file paths upon test completion. There can only be
// one instance at a time.
class PathDeleterOnTestEnd : public testing::EmptyTestEventListener {
 public:
  PathDeleterOnTestEnd() {
    DCHECK(!instance_);
    instance_ = this;
  }

  ~PathDeleterOnTestEnd() override {
    DCHECK_EQ(instance_, this);
    instance_ = nullptr;
  }

  PathDeleterOnTestEnd(const PathDeleterOnTestEnd&) = delete;
  PathDeleterOnTestEnd& operator=(const PathDeleterOnTestEnd&) = delete;

  static PathDeleterOnTestEnd* GetInstance() { return instance_; }

  void DeletePathRecursivelyUponTestEnd(const FilePath& path) {
    file_paths_to_delete_.push_back(path);
  }

  // EmptyTestEventListener overrides.
  void OnTestEnd(const testing::TestInfo& test_info) override {
    if (file_paths_to_delete_.empty()) {
      // Nothing to delete since the last test ended.
      return;
    }

    ScopedAllowBlockingForTesting allow_blocking;
    for (const FilePath& file_path : file_paths_to_delete_) {
      if (!DieFileDie(file_path, /*recurse=*/true)) {
        base::FileEnumerator enumerator(
            file_path, true,
            base::FileEnumerator::FILES | FileEnumerator::DIRECTORIES);
        for (base::FilePath failed_to_delete = enumerator.Next();
             !failed_to_delete.empty(); failed_to_delete = enumerator.Next()) {
          LOG(WARNING) << "failed to delete " << failed_to_delete;
        }
        ADD_FAILURE() << "Failed to delete temporary directory for testing: "
                      << file_path;
      }
    }
    file_paths_to_delete_.clear();
  }

 private:
  static PathDeleterOnTestEnd* instance_;
  std::vector<FilePath> file_paths_to_delete_;
};

// static
PathDeleterOnTestEnd* PathDeleterOnTestEnd::instance_ = nullptr;

FilePath RegisterPathDeleter(const FilePath& path) {
  if (!PathDeleterOnTestEnd::GetInstance()) {
    // Append() transfers ownership of the listener. This means
    // PathDeleterOnTestEnd::GetInstance() will return non-null until all tests
    // are run and the test suite destroyed.
    testing::UnitTest::GetInstance()->listeners().Append(
        new PathDeleterOnTestEnd());
    DCHECK(PathDeleterOnTestEnd::GetInstance());
  }

  PathDeleterOnTestEnd::GetInstance()->DeletePathRecursivelyUponTestEnd(path);

  return path;
}

}  // namespace

bool EvictFileFromSystemCacheWithRetry(const FilePath& path) {
  const int kCycles = 10;
  const TimeDelta kDelay = TestTimeouts::action_timeout() / kCycles;
  for (int i = 0; i < kCycles; i++) {
    if (EvictFileFromSystemCache(path)) {
      return true;
    }
    PlatformThread::Sleep(kDelay);
  }
  return false;
}

FilePath GetTempDirForTesting() {
  FilePath path;
  CHECK(GetTempDir(&path));
  return path;
}

FilePath CreateUniqueTempDirectoryScopedToTest() {
  ScopedAllowBlockingForTesting allow_blocking;
  FilePath path;
  if (!CreateNewTempDirectory(kDirPrefix, &path)) {
    ADD_FAILURE() << "Failed to create unique temporary directory for testing.";
    return FilePath();
  }
  return RegisterPathDeleter(path);
}

FilePath CreateUniqueTempDirectoryScopedToTestInDir(const base::FilePath& dir) {
  ScopedAllowBlockingForTesting allow_blocking;
  FilePath path;
  if (!CreateTemporaryDirInDir(dir, kDirPrefix, &path)) {
    ADD_FAILURE() << "Failed to create unique temporary directory for testing.";
    return FilePath();
  }
  return RegisterPathDeleter(path);
}

}  // namespace base