blob: ba1e793510d6ea7684b6b220fd9c7f46bde14797 [file] [log] [blame]
kjellander@webrtc.org7951e812011-10-13 12:24:41 +00001/*
andrew@webrtc.org7a281a52012-06-27 03:22:37 +00002 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
kjellander@webrtc.org7951e812011-10-13 12:24:41 +00003 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#include "test/testsupport/fileutils.h"
kjellander@webrtc.org7951e812011-10-13 12:24:41 +000012
kjellander@webrtc.org7de47bc2014-04-16 08:04:26 +000013#include <assert.h>
henrike@webrtc.orgf2aafe42014-04-29 17:54:17 +000014
Patrik Höglund8434aeb2018-10-05 14:52:11 +020015#if defined(WEBRTC_POSIX)
16#include <unistd.h>
17#endif
18
19#if defined(WEBRTC_WIN)
kjellander@webrtc.org7951e812011-10-13 12:24:41 +000020#include <direct.h>
kjellander@webrtc.org7de47bc2014-04-16 08:04:26 +000021#include <tchar.h>
22#include <windows.h>
kjellander@webrtc.orgde499662013-08-29 11:26:41 +000023#include <algorithm>
Patrik Höglund8434aeb2018-10-05 14:52:11 +020024#include <codecvt>
25#include <locale>
kjellander@webrtc.org7de47bc2014-04-16 08:04:26 +000026
ehmaldonado00f2ee02016-11-18 07:06:41 -080027#include "Shlwapi.h"
ehmaldonado37535bf2016-12-05 06:42:45 -080028#include "WinDef.h"
ehmaldonado00f2ee02016-11-18 07:06:41 -080029
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020030#include "rtc_base/win32.h"
kjellander@webrtc.org7951e812011-10-13 12:24:41 +000031#define GET_CURRENT_DIR _getcwd
kjellander@webrtc.org7951e812011-10-13 12:24:41 +000032#else
alessiob00b16f42017-06-01 03:29:40 -070033#include <dirent.h>
kjellander@webrtc.org7951e812011-10-13 12:24:41 +000034#include <unistd.h>
kjellander@webrtc.org7de47bc2014-04-16 08:04:26 +000035
kjellander@webrtc.org7951e812011-10-13 12:24:41 +000036#define GET_CURRENT_DIR getcwd
kjellander@webrtc.org4d8cd9d2011-11-09 11:24:14 +000037#endif
38
39#include <sys/stat.h> // To check for directory existence.
Yves Gerey665174f2018-06-19 15:03:05 +020040#ifndef S_ISDIR // Not defined in stat.h on Windows.
41#define S_ISDIR(mode) (((mode)&S_IFMT) == S_IFDIR)
kjellander@webrtc.org7951e812011-10-13 12:24:41 +000042#endif
43
pbos@webrtc.org12dc1a32013-08-05 16:22:53 +000044#include <stdio.h>
kjellander@webrtc.org7de47bc2014-04-16 08:04:26 +000045#include <stdlib.h>
pbos@webrtc.org12dc1a32013-08-05 16:22:53 +000046#include <string.h>
kjellander@webrtc.org7951e812011-10-13 12:24:41 +000047
kwibergbfefb032016-05-01 14:53:46 -070048#include <memory>
alessiob00b16f42017-06-01 03:29:40 -070049#include <utility>
kwibergbfefb032016-05-01 14:53:46 -070050
Patrik Höglund8434aeb2018-10-05 14:52:11 +020051#if defined(WEBRTC_IOS)
52#include "test/testsupport/iosfileutils.h"
53#endif
54
55#if defined(WEBRTC_MAC)
56#include "test/testsupport/macfileutils.h"
57#endif
58
59#include "rtc_base/arraysize.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020060#include "rtc_base/checks.h"
Niels Möllerd7b91312018-05-24 11:21:34 +020061#include "rtc_base/stringutils.h"
kjellander@webrtc.org4ed4f242011-12-05 16:31:12 +000062
kjellander@webrtc.org7951e812011-10-13 12:24:41 +000063namespace webrtc {
64namespace test {
65
henrike@webrtc.org34773d92013-07-08 14:55:23 +000066namespace {
67
Patrik Höglund8434aeb2018-10-05 14:52:11 +020068#if defined(WEBRTC_WIN)
henrike@webrtc.org34773d92013-07-08 14:55:23 +000069const char* kPathDelimiter = "\\";
kjellander@webrtc.org4d8cd9d2011-11-09 11:24:14 +000070#else
henrike@webrtc.org34773d92013-07-08 14:55:23 +000071const char* kPathDelimiter = "/";
kjellander@webrtc.org4d8cd9d2011-11-09 11:24:14 +000072#endif
leozwang@webrtc.org363efef2012-10-16 04:31:20 +000073
Patrik Höglund8434aeb2018-10-05 14:52:11 +020074#if defined(WEBRTC_ANDROID)
75// This is a special case in Chrome infrastructure. See
76// base/test/test_support_android.cc.
77const char* kAndroidChromiumTestsRoot = "/sdcard/chromium_tests_root/";
kjellander@webrtc.org72fd3392014-11-05 06:28:50 +000078#endif
kjellander02060002016-02-16 22:06:12 -080079
henrika1d34fe92015-06-16 10:04:20 +020080#if !defined(WEBRTC_IOS)
kjellander@webrtc.org72fd3392014-11-05 06:28:50 +000081const char* kResourcesDirName = "resources";
henrika1d34fe92015-06-16 10:04:20 +020082#endif
kjellander@webrtc.org72fd3392014-11-05 06:28:50 +000083
henrike@webrtc.org34773d92013-07-08 14:55:23 +000084} // namespace
85
86const char* kCannotFindProjectRootDir = "ERROR_CANNOT_FIND_PROJECT_ROOT_DIR";
87
Patrik Höglund8434aeb2018-10-05 14:52:11 +020088std::string DirName(const std::string& path) {
89 if (path.empty())
90 return "";
91 if (path == kPathDelimiter)
92 return path;
93
94 std::string result = path;
95 if (result.back() == *kPathDelimiter)
96 result.pop_back(); // Remove trailing separator.
97
98 return result.substr(0, result.find_last_of(kPathDelimiter));
99}
100
ehmaldonado88df0bc2017-02-10 09:27:14 -0800101bool FileExists(const std::string& file_name) {
kjellander@webrtc.org83b767b2012-10-15 18:14:12 +0000102 struct stat file_info = {0};
103 return stat(file_name.c_str(), &file_info) == 0;
104}
105
alessiobe49fede2017-03-15 06:04:59 -0700106bool DirExists(const std::string& directory_name) {
107 struct stat directory_info = {0};
Yves Gerey665174f2018-06-19 15:03:05 +0200108 return stat(directory_name.c_str(), &directory_info) == 0 &&
109 S_ISDIR(directory_info.st_mode);
alessiobe49fede2017-03-15 06:04:59 -0700110}
111
Patrik Höglund8434aeb2018-10-05 14:52:11 +0200112// Finds the WebRTC src dir.
113// The returned path always ends with a path separator.
leozwang@webrtc.org363efef2012-10-16 04:31:20 +0000114std::string ProjectRootPath() {
Patrik Höglund8434aeb2018-10-05 14:52:11 +0200115#if defined(WEBRTC_ANDROID)
116 return kAndroidChromiumTestsRoot;
117#elif defined WEBRTC_IOS
Kári Tristan Helgason470c0882016-10-03 13:13:29 +0200118 return IOSRootPath();
Patrik Höglund8434aeb2018-10-05 14:52:11 +0200119#elif defined(WEBRTC_MAC)
120 std::string path;
121 GetNSExecutablePath(&path);
122 std::string exe_dir = DirName(path);
123 // On Mac, tests execute in out/Whatever, so src is two levels up except if
124 // the test is bundled (which our tests are not), in which case it's 5 levels.
125 return DirName(DirName(exe_dir)) + kPathDelimiter;
126#elif defined(WEBRTC_POSIX)
127 char buf[PATH_MAX];
128 ssize_t count = ::readlink("/proc/self/exe", buf, arraysize(buf));
129 if (count <= 0) {
130 RTC_NOTREACHED() << "Unable to resolve /proc/self/exe.";
kjellander@webrtc.org7951e812011-10-13 12:24:41 +0000131 return kCannotFindProjectRootDir;
132 }
Patrik Höglund8434aeb2018-10-05 14:52:11 +0200133 // On POSIX, tests execute in out/Whatever, so src is two levels up.
134 std::string exe_dir = DirName(std::string(buf, count));
135 return DirName(DirName(exe_dir)) + kPathDelimiter;
136#elif defined(WEBRTC_WIN)
137 wchar_t buf[MAX_PATH];
138 buf[0] = 0;
139 if (GetModuleFileName(NULL, buf, MAX_PATH) == 0)
ehmaldonado00f2ee02016-11-18 07:06:41 -0800140 return kCannotFindProjectRootDir;
Patrik Höglund8434aeb2018-10-05 14:52:11 +0200141
142 std::string exe_path = rtc::ToUtf8(std::wstring(buf));
143 std::string exe_dir = DirName(exe_path);
144 return DirName(DirName(exe_dir)) + kPathDelimiter;
Kári Tristan Helgason470c0882016-10-03 13:13:29 +0200145#endif
kjellander@webrtc.org7951e812011-10-13 12:24:41 +0000146}
147
andrew@webrtc.org0db7dc62011-11-13 01:34:05 +0000148std::string OutputPath() {
kjellander02060002016-02-16 22:06:12 -0800149#if defined(WEBRTC_IOS)
150 return IOSOutputPath();
Patrik Höglund8434aeb2018-10-05 14:52:11 +0200151#elif defined(WEBRTC_ANDROID)
152 return kAndroidChromiumTestsRoot;
kjellander02060002016-02-16 22:06:12 -0800153#else
kjellander@webrtc.org72fd3392014-11-05 06:28:50 +0000154 std::string path = ProjectRootPath();
Patrik Höglund8434aeb2018-10-05 14:52:11 +0200155 RTC_DCHECK_NE(path, kCannotFindProjectRootDir);
156 path += "out";
kjellander@webrtc.org72fd3392014-11-05 06:28:50 +0000157 if (!CreateDir(path)) {
Patrik Höglund8434aeb2018-10-05 14:52:11 +0200158 return "./";
kjellander@webrtc.org72fd3392014-11-05 06:28:50 +0000159 }
160 return path + kPathDelimiter;
kjellander02060002016-02-16 22:06:12 -0800161#endif
kjellander@webrtc.org4d8cd9d2011-11-09 11:24:14 +0000162}
kjellander@webrtc.org4ed4f242011-12-05 16:31:12 +0000163
164std::string WorkingDir() {
Patrik Höglund8434aeb2018-10-05 14:52:11 +0200165#if defined(WEBRTC_ANDROID)
166 return kAndroidChromiumTestsRoot;
167#endif
kjellander@webrtc.org4ed4f242011-12-05 16:31:12 +0000168 char path_buffer[FILENAME_MAX];
169 if (!GET_CURRENT_DIR(path_buffer, sizeof(path_buffer))) {
170 fprintf(stderr, "Cannot get current directory!\n");
Patrik Höglund8434aeb2018-10-05 14:52:11 +0200171 return "./";
kjellander@webrtc.org5b97b122011-12-08 07:42:18 +0000172 } else {
kjellander@webrtc.org4ed4f242011-12-05 16:31:12 +0000173 return std::string(path_buffer);
174 }
175}
176
kjellander@webrtc.org7de47bc2014-04-16 08:04:26 +0000177// Generate a temporary filename in a safe way.
178// Largely copied from talk/base/{unixfilesystem,win32filesystem}.cc.
Yves Gerey665174f2018-06-19 15:03:05 +0200179std::string TempFilename(const std::string& dir, const std::string& prefix) {
kjellander@webrtc.org7de47bc2014-04-16 08:04:26 +0000180#ifdef WIN32
181 wchar_t filename[MAX_PATH];
Yves Gerey665174f2018-06-19 15:03:05 +0200182 if (::GetTempFileName(rtc::ToUtf16(dir).c_str(), rtc::ToUtf16(prefix).c_str(),
183 0, filename) != 0)
nisse07b83882017-03-14 01:32:50 -0700184 return rtc::ToUtf8(filename);
kjellander@webrtc.org7de47bc2014-04-16 08:04:26 +0000185 assert(false);
186 return "";
187#else
188 int len = dir.size() + prefix.size() + 2 + 6;
kwibergbfefb032016-05-01 14:53:46 -0700189 std::unique_ptr<char[]> tempname(new char[len]);
kjellander@webrtc.org7de47bc2014-04-16 08:04:26 +0000190
Yves Gerey665174f2018-06-19 15:03:05 +0200191 snprintf(tempname.get(), len, "%s/%sXXXXXX", dir.c_str(), prefix.c_str());
kjellander@webrtc.org7de47bc2014-04-16 08:04:26 +0000192 int fd = ::mkstemp(tempname.get());
193 if (fd == -1) {
194 assert(false);
195 return "";
196 } else {
197 ::close(fd);
198 }
199 std::string ret(tempname.get());
200 return ret;
201#endif
202}
203
Artem Titove62f6002018-03-19 15:40:00 +0100204std::string GenerateTempFilename(const std::string& dir,
205 const std::string& prefix) {
206 std::string filename = TempFilename(dir, prefix);
207 RemoveFile(filename);
208 return filename;
209}
210
Danil Chapovalov431abd92018-06-18 12:54:17 +0200211absl::optional<std::vector<std::string>> ReadDirectory(std::string path) {
alessiob00b16f42017-06-01 03:29:40 -0700212 if (path.length() == 0)
Danil Chapovalov431abd92018-06-18 12:54:17 +0200213 return absl::optional<std::vector<std::string>>();
alessiob00b16f42017-06-01 03:29:40 -0700214
215#if defined(WEBRTC_WIN)
216 // Append separator character if needed.
217 if (path.back() != '\\')
218 path += '\\';
219
220 // Init.
221 WIN32_FIND_DATA data;
222 HANDLE handle = ::FindFirstFile(rtc::ToUtf16(path + '*').c_str(), &data);
223 if (handle == INVALID_HANDLE_VALUE)
Danil Chapovalov431abd92018-06-18 12:54:17 +0200224 return absl::optional<std::vector<std::string>>();
alessiob00b16f42017-06-01 03:29:40 -0700225
226 // Populate output.
227 std::vector<std::string> found_entries;
228 do {
229 const std::string name = rtc::ToUtf8(data.cFileName);
230 if (name != "." && name != "..")
231 found_entries.emplace_back(path + name);
232 } while (::FindNextFile(handle, &data) == TRUE);
233
234 // Release resources.
235 if (handle != INVALID_HANDLE_VALUE)
236 ::FindClose(handle);
237#else
238 // Append separator character if needed.
239 if (path.back() != '/')
240 path += '/';
241
242 // Init.
243 DIR* dir = ::opendir(path.c_str());
244 if (dir == nullptr)
Danil Chapovalov431abd92018-06-18 12:54:17 +0200245 return absl::optional<std::vector<std::string>>();
alessiob00b16f42017-06-01 03:29:40 -0700246
247 // Populate output.
248 std::vector<std::string> found_entries;
249 while (dirent* dirent = readdir(dir)) {
250 const std::string& name = dirent->d_name;
251 if (name != "." && name != "..")
252 found_entries.emplace_back(path + name);
253 }
254
255 // Release resources.
256 closedir(dir);
257#endif
258
Danil Chapovalov431abd92018-06-18 12:54:17 +0200259 return absl::optional<std::vector<std::string>>(std::move(found_entries));
alessiob00b16f42017-06-01 03:29:40 -0700260}
261
ehmaldonado88df0bc2017-02-10 09:27:14 -0800262bool CreateDir(const std::string& directory_name) {
kjellander@webrtc.org4ed4f242011-12-05 16:31:12 +0000263 struct stat path_info = {0};
264 // Check if the path exists already:
265 if (stat(directory_name.c_str(), &path_info) == 0) {
266 if (!S_ISDIR(path_info.st_mode)) {
Yves Gerey665174f2018-06-19 15:03:05 +0200267 fprintf(stderr,
268 "Path %s exists but is not a directory! Remove this "
kjellander@webrtc.org4ed4f242011-12-05 16:31:12 +0000269 "file and re-run to create the directory.\n",
270 directory_name.c_str());
271 return false;
272 }
273 } else {
274#ifdef WIN32
275 return _mkdir(directory_name.c_str()) == 0;
276#else
Yves Gerey665174f2018-06-19 15:03:05 +0200277 return mkdir(directory_name.c_str(), S_IRWXU | S_IRWXG | S_IRWXO) == 0;
kjellander@webrtc.org4ed4f242011-12-05 16:31:12 +0000278#endif
279 }
280 return true;
281}
282
nisse57efb032017-05-18 03:55:59 -0700283bool RemoveDir(const std::string& directory_name) {
284#ifdef WIN32
Yves Gerey665174f2018-06-19 15:03:05 +0200285 return RemoveDirectoryA(directory_name.c_str()) != FALSE;
nisse57efb032017-05-18 03:55:59 -0700286#else
Yves Gerey665174f2018-06-19 15:03:05 +0200287 return rmdir(directory_name.c_str()) == 0;
nisse57efb032017-05-18 03:55:59 -0700288#endif
289}
290
291bool RemoveFile(const std::string& file_name) {
292#ifdef WIN32
293 return DeleteFileA(file_name.c_str()) != FALSE;
294#else
295 return unlink(file_name.c_str()) == 0;
296#endif
297}
298
ehmaldonado88df0bc2017-02-10 09:27:14 -0800299std::string ResourcePath(const std::string& name,
300 const std::string& extension) {
henrika1d34fe92015-06-16 10:04:20 +0200301#if defined(WEBRTC_IOS)
302 return IOSResourcePath(name, extension);
303#else
Yves Gerey665174f2018-06-19 15:03:05 +0200304 std::string resources_path =
305 ProjectRootPath() + kResourcesDirName + kPathDelimiter;
kjellander@webrtc.org4ed4f242011-12-05 16:31:12 +0000306 return resources_path + name + "." + extension;
Patrik Höglund77301932018-10-09 15:09:51 +0200307#endif
kjellander@webrtc.org4ed4f242011-12-05 16:31:12 +0000308}
309
Niels Möller392f8d02018-06-01 10:14:44 +0200310std::string JoinFilename(const std::string& dir, const std::string& name) {
311 RTC_CHECK(!dir.empty()) << "Special cases not implemented.";
312 return dir + kPathDelimiter + name;
313}
314
ehmaldonado88df0bc2017-02-10 09:27:14 -0800315size_t GetFileSize(const std::string& filename) {
kjellander@webrtc.org5b97b122011-12-08 07:42:18 +0000316 FILE* f = fopen(filename.c_str(), "rb");
317 size_t size = 0;
318 if (f != NULL) {
319 if (fseek(f, 0, SEEK_END) == 0) {
320 size = ftell(f);
321 }
322 fclose(f);
323 }
324 return size;
325}
326
kjellander@webrtc.org7951e812011-10-13 12:24:41 +0000327} // namespace test
kjellander@webrtc.org4d8cd9d2011-11-09 11:24:14 +0000328} // namespace webrtc