31 #include "gtest/internal/gtest-port.h"
44 # include <sys/stat.h>
51 #endif // GTEST_OS_WINDOWS
54 # include <mach/mach_init.h>
55 # include <mach/task.h>
56 # include <mach/vm_map.h>
57 #endif // GTEST_OS_MAC
59 #if GTEST_OS_DRAGONFLY || GTEST_OS_FREEBSD || GTEST_OS_GNU_KFREEBSD || \
60 GTEST_OS_NETBSD || GTEST_OS_OPENBSD
61 # include <sys/sysctl.h>
62 # if GTEST_OS_DRAGONFLY || GTEST_OS_FREEBSD || GTEST_OS_GNU_KFREEBSD
63 # include <sys/user.h>
70 # include <sys/procfs.h>
71 #endif // GTEST_OS_QNX
74 # include <procinfo.h>
75 # include <sys/types.h>
76 #endif // GTEST_OS_AIX
79 # include <zircon/process.h>
80 # include <zircon/syscalls.h>
81 #endif // GTEST_OS_FUCHSIA
83 #include "gtest/gtest-spi.h"
84 #include "gtest/gtest-message.h"
85 #include "gtest/internal/gtest-internal.h"
86 #include "gtest/internal/gtest-string.h"
87 #include "src/gtest-internal-inl.h"
92 #if defined(_MSC_VER) || defined(__BORLANDC__)
101 #if GTEST_OS_LINUX || GTEST_OS_GNU_HURD
104 template <
typename T>
108 while (
field-- > 0) {
121 return ReadProcFileField<size_t>(
filename, 19);
127 const task_t task = mach_task_self();
128 mach_msg_type_number_t thread_count;
129 thread_act_array_t thread_list;
130 const kern_return_t
status = task_threads(task, &thread_list, &thread_count);
131 if (
status == KERN_SUCCESS) {
135 reinterpret_cast<vm_address_t
>(thread_list),
136 sizeof(thread_t) * thread_count);
137 return static_cast<size_t>(thread_count);
143 #elif GTEST_OS_DRAGONFLY || GTEST_OS_FREEBSD || GTEST_OS_GNU_KFREEBSD || \
148 #define KERN_PROC KERN_PROC2
149 #define kinfo_proc kinfo_proc2
152 #if GTEST_OS_DRAGONFLY
153 #define KP_NLWP(kp) (kp.kp_nthreads)
154 #elif GTEST_OS_FREEBSD || GTEST_OS_GNU_KFREEBSD
155 #define KP_NLWP(kp) (kp.ki_numthreads)
156 #elif GTEST_OS_NETBSD
157 #define KP_NLWP(kp) (kp.p_nlwps)
169 sizeof(
struct kinfo_proc),
173 u_int miblen =
sizeof(mib) /
sizeof(mib[0]);
174 struct kinfo_proc info;
175 size_t size =
sizeof(info);
176 if (sysctl(mib, miblen, &info, &
size, NULL, 0)) {
179 return static_cast<size_t>(KP_NLWP(info));
181 #elif GTEST_OS_OPENBSD
189 KERN_PROC_PID | KERN_PROC_SHOW_THREADS,
191 sizeof(
struct kinfo_proc),
194 u_int miblen =
sizeof(mib) /
sizeof(mib[0]);
198 if (sysctl(mib, miblen, NULL, &
size, NULL, 0)) {
202 mib[5] =
static_cast<int>(
size /
static_cast<size_t>(mib[4]));
205 struct kinfo_proc info[mib[5]];
206 if (sysctl(mib, miblen, &info, &
size, NULL, 0)) {
212 for (
size_t i = 0;
i <
size /
static_cast<size_t>(mib[4]);
i++) {
213 if (info[
i].p_tid != -1)
224 const int fd =
open(
"/proc/self/as", O_RDONLY);
228 procfs_info process_info;
230 devctl(fd, DCMD_PROC_INFO, &process_info,
sizeof(process_info),
nullptr);
233 return static_cast<size_t>(process_info.num_threads);
242 struct procentry64 entry;
243 pid_t pid = getpid();
244 int status = getprocs64(&entry,
sizeof(entry),
nullptr, 0, &pid, 1);
246 return entry.pi_thcount;
252 #elif GTEST_OS_FUCHSIA
257 zx_status_t
status = zx_object_get_info(
259 ZX_INFO_PROCESS_THREADS,
279 #endif // GTEST_OS_LINUX
281 #if GTEST_IS_THREADSAFE && GTEST_OS_WINDOWS
283 AutoHandle::AutoHandle()
286 AutoHandle::AutoHandle(Handle
handle)
289 AutoHandle::~AutoHandle() {
310 <<
"Resetting a valid handle to itself is likely a programmer error "
311 "and thus not allowed.";
315 bool AutoHandle::IsCloseable()
const {
322 : owner_thread_id_(0),
324 critical_section_init_phase_(0),
325 critical_section_(
new CRITICAL_SECTION) {
326 ::InitializeCriticalSection(critical_section_);
332 if (
type_ == kDynamic) {
333 ::DeleteCriticalSection(critical_section_);
334 delete critical_section_;
335 critical_section_ =
nullptr;
340 ThreadSafeLazyInit();
341 ::EnterCriticalSection(critical_section_);
342 owner_thread_id_ = ::GetCurrentThreadId();
345 void Mutex::Unlock() {
346 ThreadSafeLazyInit();
350 owner_thread_id_ = 0;
351 ::LeaveCriticalSection(critical_section_);
356 void Mutex::AssertHeld() {
357 ThreadSafeLazyInit();
358 GTEST_CHECK_(owner_thread_id_ == ::GetCurrentThreadId())
359 <<
"The current thread is not holding the mutex @" <<
this;
373 class MemoryIsNotDeallocated
376 MemoryIsNotDeallocated() : old_crtdbg_flag_(0) {
377 old_crtdbg_flag_ = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
380 (void)_CrtSetDbgFlag(old_crtdbg_flag_ & ~_CRTDBG_ALLOC_MEM_DF);
383 ~MemoryIsNotDeallocated() {
385 (void)_CrtSetDbgFlag(old_crtdbg_flag_);
389 int old_crtdbg_flag_;
398 void Mutex::ThreadSafeLazyInit() {
400 if (
type_ == kStatic) {
402 ::InterlockedCompareExchange(&critical_section_init_phase_, 1L, 0L)) {
406 owner_thread_id_ = 0;
410 MemoryIsNotDeallocated memory_is_not_deallocated;
412 critical_section_ =
new CRITICAL_SECTION;
414 ::InitializeCriticalSection(critical_section_);
418 &critical_section_init_phase_, 2L, 1L) ==
424 while (::InterlockedCompareExchange(&critical_section_init_phase_,
438 <<
"Unexpected value of critical_section_init_phase_ "
439 <<
"while initializing a static mutex.";
446 class ThreadWithParamSupport :
public ThreadWithParamBase {
448 static HANDLE CreateThread(Runnable* runnable,
449 Notification* thread_can_start) {
450 ThreadMainParam* param =
new ThreadMainParam(runnable, thread_can_start);
452 HANDLE thread_handle = ::CreateThread(
455 &ThreadWithParamSupport::ThreadMain,
460 <<
"CreateThread failed with error " << ::GetLastError() <<
".";
461 if (thread_handle ==
nullptr) {
464 return thread_handle;
468 struct ThreadMainParam {
469 ThreadMainParam(Runnable* runnable, Notification* thread_can_start)
470 : runnable_(runnable),
471 thread_can_start_(thread_can_start) {
473 std::unique_ptr<Runnable> runnable_;
475 Notification* thread_can_start_;
478 static DWORD WINAPI ThreadMain(
void*
ptr) {
480 std::unique_ptr<ThreadMainParam> param(
static_cast<ThreadMainParam*
>(
ptr));
481 if (param->thread_can_start_ !=
nullptr)
482 param->thread_can_start_->WaitForNotification();
483 param->runnable_->Run();
488 ThreadWithParamSupport();
495 ThreadWithParamBase::ThreadWithParamBase(Runnable *runnable,
496 Notification* thread_can_start)
497 :
thread_(ThreadWithParamSupport::CreateThread(runnable,
501 ThreadWithParamBase::~ThreadWithParamBase() {
507 <<
"Failed to join the thread with error " << ::GetLastError() <<
".";
514 class ThreadLocalRegistryImpl {
518 static ThreadLocalValueHolderBase* GetValueOnCurrentThread(
519 const ThreadLocalBase* thread_local_instance) {
521 MemoryIsNotDeallocated memory_is_not_deallocated;
523 DWORD current_thread = ::GetCurrentThreadId();
525 ThreadIdToThreadLocals*
const thread_to_thread_locals =
526 GetThreadLocalsMapLocked();
528 thread_to_thread_locals->find(current_thread);
529 if (thread_local_pos == thread_to_thread_locals->end()) {
530 thread_local_pos = thread_to_thread_locals->insert(
531 std::make_pair(current_thread, ThreadLocalValues())).first;
532 StartWatcherThreadFor(current_thread);
534 ThreadLocalValues& thread_local_values = thread_local_pos->second;
536 thread_local_values.find(thread_local_instance);
537 if (value_pos == thread_local_values.end()) {
540 .insert(std::make_pair(
541 thread_local_instance,
542 std::shared_ptr<ThreadLocalValueHolderBase>(
543 thread_local_instance->NewValueForCurrentThread())))
546 return value_pos->second.get();
549 static void OnThreadLocalDestroyed(
550 const ThreadLocalBase* thread_local_instance) {
551 std::vector<std::shared_ptr<ThreadLocalValueHolderBase> > value_holders;
556 ThreadIdToThreadLocals*
const thread_to_thread_locals =
557 GetThreadLocalsMapLocked();
559 thread_to_thread_locals->begin();
560 it != thread_to_thread_locals->end();
562 ThreadLocalValues& thread_local_values =
it->second;
564 thread_local_values.find(thread_local_instance);
565 if (value_pos != thread_local_values.end()) {
566 value_holders.push_back(value_pos->second);
567 thread_local_values.erase(value_pos);
577 static void OnThreadExit(DWORD
thread_id) {
579 std::vector<std::shared_ptr<ThreadLocalValueHolderBase> > value_holders;
584 ThreadIdToThreadLocals*
const thread_to_thread_locals =
585 GetThreadLocalsMapLocked();
587 thread_to_thread_locals->find(
thread_id);
588 if (thread_local_pos != thread_to_thread_locals->end()) {
589 ThreadLocalValues& thread_local_values = thread_local_pos->second;
591 thread_local_values.begin();
592 value_pos != thread_local_values.end();
594 value_holders.push_back(value_pos->second);
596 thread_to_thread_locals->erase(thread_local_pos);
605 typedef std::map<
const ThreadLocalBase*,
606 std::shared_ptr<ThreadLocalValueHolderBase> >
610 typedef std::map<DWORD, ThreadLocalValues> ThreadIdToThreadLocals;
614 typedef std::pair<DWORD, HANDLE> ThreadIdAndHandle;
616 static void StartWatcherThreadFor(DWORD
thread_id) {
619 HANDLE
thread = ::OpenThread(SYNCHRONIZE | THREAD_QUERY_INFORMATION,
625 DWORD watcher_thread_id;
626 HANDLE watcher_thread = ::CreateThread(
629 &ThreadLocalRegistryImpl::WatcherThreadFunc,
631 CREATE_SUSPENDED, &watcher_thread_id);
633 <<
"CreateThread failed with error " << ::GetLastError() <<
".";
636 ::SetThreadPriority(watcher_thread,
637 ::GetThreadPriority(::GetCurrentThread()));
638 ::ResumeThread(watcher_thread);
639 ::CloseHandle(watcher_thread);
644 static DWORD WINAPI WatcherThreadFunc(LPVOID param) {
645 const ThreadIdAndHandle* tah =
646 reinterpret_cast<const ThreadIdAndHandle*
>(param);
648 ::WaitForSingleObject(tah->second, INFINITE) == WAIT_OBJECT_0);
649 OnThreadExit(tah->first);
650 ::CloseHandle(tah->second);
656 static ThreadIdToThreadLocals* GetThreadLocalsMapLocked() {
659 MemoryIsNotDeallocated memory_is_not_deallocated;
661 static ThreadIdToThreadLocals*
map =
new ThreadIdToThreadLocals();
668 static Mutex thread_map_mutex_;
672 Mutex ThreadLocalRegistryImpl::thread_map_mutex_(Mutex::kStaticMutex);
674 ThreadLocalValueHolderBase* ThreadLocalRegistry::GetValueOnCurrentThread(
675 const ThreadLocalBase* thread_local_instance) {
676 return ThreadLocalRegistryImpl::GetValueOnCurrentThread(
677 thread_local_instance);
680 void ThreadLocalRegistry::OnThreadLocalDestroyed(
681 const ThreadLocalBase* thread_local_instance) {
682 ThreadLocalRegistryImpl::OnThreadLocalDestroyed(thread_local_instance);
685 #endif // GTEST_IS_THREADSAFE && GTEST_OS_WINDOWS
687 #if GTEST_USES_POSIX_RE
697 regfree(&partial_regex_);
698 regfree(&full_regex_);
700 free(
const_cast<char*
>(pattern_));
704 bool RE::FullMatch(
const char*
str,
const RE& re) {
705 if (!re.is_valid_)
return false;
708 return regexec(&re.full_regex_,
str, 1, &
match, 0) == 0;
713 bool RE::PartialMatch(
const char*
str,
const RE& re) {
714 if (!re.is_valid_)
return false;
717 return regexec(&re.partial_regex_,
str, 1, &
match, 0) == 0;
726 const size_t full_regex_len = strlen(regex) + 10;
727 char*
const full_pattern =
new char[full_regex_len];
729 snprintf(full_pattern, full_regex_len,
"^(%s)$", regex);
730 is_valid_ = regcomp(&full_regex_, full_pattern, REG_EXTENDED) == 0;
740 const char*
const partial_regex = (*regex ==
'\0') ?
"()" : regex;
741 is_valid_ = regcomp(&partial_regex_, partial_regex, REG_EXTENDED) == 0;
744 <<
"Regular expression \"" << regex
745 <<
"\" is not a valid POSIX Extended regular expression.";
747 delete[] full_pattern;
750 #elif GTEST_USES_SIMPLE_RE
754 bool IsInSet(
char ch,
const char*
str) {
755 return ch !=
'\0' && strchr(
str,
ch) !=
nullptr;
761 bool IsAsciiDigit(
char ch) {
return '0' <=
ch &&
ch <=
'9'; }
762 bool IsAsciiPunct(
char ch) {
763 return IsInSet(
ch,
"^-!\"#$%&'()*+,./:;<=>?@[\\]_`{|}~");
765 bool IsRepeat(
char ch) {
return IsInSet(
ch,
"?*+"); }
766 bool IsAsciiWhiteSpace(
char ch) {
return IsInSet(
ch,
" \f\n\r\t\v"); }
767 bool IsAsciiWordChar(
char ch) {
768 return (
'a' <=
ch &&
ch <=
'z') || (
'A' <=
ch &&
ch <=
'Z') ||
769 (
'0' <=
ch &&
ch <=
'9') ||
ch ==
'_';
773 bool IsValidEscape(
char c) {
774 return (IsAsciiPunct(c) || IsInSet(c,
"dDfnrsStvwW"));
779 bool AtomMatchesChar(
bool escaped,
char pattern_char,
char ch) {
781 switch (pattern_char) {
782 case 'd':
return IsAsciiDigit(
ch);
783 case 'D':
return !IsAsciiDigit(
ch);
784 case 'f':
return ch ==
'\f';
785 case 'n':
return ch ==
'\n';
786 case 'r':
return ch ==
'\r';
787 case 's':
return IsAsciiWhiteSpace(
ch);
788 case 'S':
return !IsAsciiWhiteSpace(
ch);
789 case 't':
return ch ==
'\t';
790 case 'v':
return ch ==
'\v';
791 case 'w':
return IsAsciiWordChar(
ch);
792 case 'W':
return !IsAsciiWordChar(
ch);
794 return IsAsciiPunct(pattern_char) && pattern_char ==
ch;
797 return (pattern_char ==
'.' &&
ch !=
'\n') || pattern_char ==
ch;
803 <<
" in simple regular expression \"" << regex <<
"\": ").GetString();
808 bool ValidateRegex(
const char* regex) {
809 if (regex ==
nullptr) {
810 ADD_FAILURE() <<
"NULL is not a valid simple regular expression.";
814 bool is_valid =
true;
817 bool prev_repeatable =
false;
818 for (
int i = 0; regex[
i];
i++) {
819 if (regex[i] ==
'\\') {
821 if (regex[i] ==
'\0') {
822 ADD_FAILURE() << FormatRegexSyntaxError(regex, i - 1)
823 <<
"'\\' cannot appear at the end.";
827 if (!IsValidEscape(regex[i])) {
828 ADD_FAILURE() << FormatRegexSyntaxError(regex, i - 1)
829 <<
"invalid escape sequence \"\\" << regex[
i] <<
"\".";
832 prev_repeatable =
true;
834 const char ch = regex[
i];
836 if (
ch ==
'^' && i > 0) {
838 <<
"'^' can only appear at the beginning.";
840 }
else if (
ch ==
'$' && regex[i + 1] !=
'\0') {
842 <<
"'$' can only appear at the end.";
844 }
else if (IsInSet(
ch,
"()[]{}|")) {
846 <<
"'" <<
ch <<
"' is unsupported.";
848 }
else if (IsRepeat(
ch) && !prev_repeatable) {
850 <<
"'" <<
ch <<
"' can only follow a repeatable token.";
854 prev_repeatable = !IsInSet(
ch,
"^$?*+");
868 bool MatchRepetitionAndRegexAtHead(
869 bool escaped,
char c,
char repeat,
const char* regex,
871 const size_t min_count = (repeat ==
'+') ? 1 : 0;
872 const size_t max_count = (repeat ==
'?') ? 1 :
873 static_cast<size_t>(-1) - 1;
877 for (
size_t i = 0;
i <= max_count; ++
i) {
879 if (i >= min_count && MatchRegexAtHead(regex,
str + i)) {
886 if (
str[i] ==
'\0' || !AtomMatchesChar(escaped, c,
str[i]))
895 bool MatchRegexAtHead(
const char* regex,
const char*
str) {
905 const bool escaped = *regex ==
'\\';
908 if (IsRepeat(regex[1])) {
912 return MatchRepetitionAndRegexAtHead(
913 escaped, regex[0], regex[1], regex + 2,
str);
918 return (*
str !=
'\0') && AtomMatchesChar(escaped, *regex, *
str) &&
919 MatchRegexAtHead(regex + 1,
str + 1);
931 bool MatchRegexAnywhere(
const char* regex,
const char*
str) {
932 if (regex ==
nullptr ||
str ==
nullptr)
return false;
935 return MatchRegexAtHead(regex + 1,
str);
939 if (MatchRegexAtHead(regex,
str))
941 }
while (*
str++ !=
'\0');
948 free(
const_cast<char*
>(pattern_));
949 free(
const_cast<char*
>(full_pattern_));
953 bool RE::FullMatch(
const char*
str,
const RE& re) {
954 return re.is_valid_ && MatchRegexAnywhere(re.full_pattern_,
str);
959 bool RE::PartialMatch(
const char*
str,
const RE& re) {
960 return re.is_valid_ && MatchRegexAnywhere(re.pattern_,
str);
965 pattern_ = full_pattern_ =
nullptr;
966 if (regex !=
nullptr) {
970 is_valid_ = ValidateRegex(regex);
976 const size_t len = strlen(regex);
980 char*
buffer =
static_cast<char*
>(malloc(
len + 3));
991 if (
len == 0 || regex[
len - 1] !=
'$')
997 #endif // GTEST_USES_POSIX_RE
1007 return file_name +
":";
1033 const char*
const marker =
1037 GetStream() << ::std::endl << marker <<
" "
1042 GTestLog::~GTestLog() {
1043 GetStream() << ::std::endl;
1054 #if GTEST_HAS_STREAM_REDIRECTION
1057 class CapturedStream {
1060 explicit CapturedStream(
int fd) : fd_(fd), uncaptured_fd_(dup(fd)) {
1061 # if GTEST_OS_WINDOWS
1062 char temp_dir_path[MAX_PATH + 1] = {
'\0' };
1063 char temp_file_path[MAX_PATH + 1] = {
'\0' };
1065 ::GetTempPathA(
sizeof(temp_dir_path), temp_dir_path);
1066 const UINT success = ::GetTempFileNameA(temp_dir_path,
1071 <<
"Unable to create a temporary file in " << temp_dir_path;
1072 const int captured_fd = creat(temp_file_path, _S_IREAD | _S_IWRITE);
1073 GTEST_CHECK_(captured_fd != -1) <<
"Unable to open temporary file "
1075 filename_ = temp_file_path;
1081 # if GTEST_OS_LINUX_ANDROID
1093 name_template =
"/data/local/tmp/";
1095 char user_temp_dir[PATH_MAX + 1];
1110 ::confstr(_CS_DARWIN_USER_TEMP_DIR, user_temp_dir,
sizeof(user_temp_dir));
1112 name_template = user_temp_dir;
1116 name_template =
"/tmp/";
1118 name_template.append(
"gtest_captured_stream.XXXXXX");
1126 const int captured_fd = ::mkstemp(
const_cast<char*
>(name_template.data()));
1127 if (captured_fd == -1) {
1129 <<
"Failed to create tmp file " << name_template
1130 <<
" for test; does the test have access to the /tmp directory?";
1133 # endif // GTEST_OS_WINDOWS
1135 dup2(captured_fd, fd_);
1140 remove(filename_.c_str());
1144 if (uncaptured_fd_ != -1) {
1147 dup2(uncaptured_fd_, fd_);
1148 close(uncaptured_fd_);
1149 uncaptured_fd_ = -1;
1153 if (
file ==
nullptr) {
1155 <<
" for capturing stream.";
1178 CapturedStream**
stream) {
1179 if (*
stream !=
nullptr) {
1181 <<
" capturer can exist at a time.";
1183 *
stream =
new CapturedStream(fd);
1190 delete *captured_stream;
1191 *captured_stream =
nullptr;
1216 #endif // GTEST_HAS_STREAM_REDIRECTION
1224 return static_cast<size_t>(ftell(
file));
1229 char*
const buffer =
new char[file_size];
1231 size_t bytes_last_read = 0;
1241 }
while (bytes_last_read > 0 &&
bytes_read < file_size);
1249 #if GTEST_HAS_DEATH_TEST
1250 static const std::vector<std::string>* g_injected_test_argvs =
1253 std::vector<std::string> GetInjectableArgvs() {
1254 if (g_injected_test_argvs !=
nullptr) {
1255 return *g_injected_test_argvs;
1260 void SetInjectableArgvs(
const std::vector<std::string>* new_argvs) {
1261 if (g_injected_test_argvs != new_argvs)
delete g_injected_test_argvs;
1262 g_injected_test_argvs = new_argvs;
1265 void SetInjectableArgvs(
const std::vector<std::string>& new_argvs) {
1267 new std::vector<std::string>(new_argvs.begin(), new_argvs.end()));
1270 void ClearInjectableArgvs() {
1271 delete g_injected_test_argvs;
1272 g_injected_test_argvs =
nullptr;
1274 #endif // GTEST_HAS_DEATH_TEST
1276 #if GTEST_OS_WINDOWS_MOBILE
1280 TerminateProcess(GetCurrentProcess(), 1);
1283 #endif // GTEST_OS_WINDOWS_MOBILE
1293 for (
size_t i = 0;
i != full_flag.length();
i++) {
1305 char*
end =
nullptr;
1306 const long long_value = strtol(
str, &
end, 10);
1312 msg <<
"WARNING: " << src_text
1313 <<
" is expected to be a 32-bit integer, but actually"
1314 <<
" has value \"" <<
str <<
"\".\n";
1322 if (long_value == LONG_MAX || long_value == LONG_MIN ||
1329 msg <<
"WARNING: " << src_text
1330 <<
" is expected to be a 32-bit integer, but actually"
1331 <<
" has value " <<
str <<
", which overflows.\n";
1346 #if defined(GTEST_GET_BOOL_FROM_ENV_)
1347 return GTEST_GET_BOOL_FROM_ENV_(
flag, default_value);
1351 return string_value ==
nullptr ? default_value
1352 : strcmp(string_value,
"0") != 0;
1353 #endif // defined(GTEST_GET_BOOL_FROM_ENV_)
1360 #if defined(GTEST_GET_INT32_FROM_ENV_)
1361 return GTEST_GET_INT32_FROM_ENV_(
flag, default_value);
1365 if (string_value ==
nullptr) {
1367 return default_value;
1372 string_value, &
result)) {
1373 printf(
"The default value %s is used.\n",
1376 return default_value;
1380 #endif // defined(GTEST_GET_INT32_FROM_ENV_)
1393 const char* xml_output_file_env =
posix::GetEnv(
"XML_OUTPUT_FILE");
1394 if (
nullptr != xml_output_file_env) {
1395 default_value_for_output_flag =
std::string(
"xml:") + xml_output_file_env;
1397 return default_value_for_output_flag;
1403 #if defined(GTEST_GET_STRING_FROM_ENV_)
1404 return GTEST_GET_STRING_FROM_ENV_(
flag, default_value);
1408 return value ==
nullptr ? default_value :
value;
1409 #endif // defined(GTEST_GET_STRING_FROM_ENV_)