Add initial support for gtest

Bug: 138738352
Change-Id: Ifa8b7eabe3faf5cea2c2bf6bce41fd41075d2be8
diff --git a/lib/googletest/include/trusty-gtest.h b/lib/googletest/include/trusty-gtest.h
new file mode 100644
index 0000000..f2d0972
--- /dev/null
+++ b/lib/googletest/include/trusty-gtest.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <gtest/gtest.h>
+#include <lib/unittest/unittest.h>
+#include <lk/compiler.h>
+
+#define PORT_GTEST(suite_name, port_name_string)          \
+    __BEGIN_CDECLS                                        \
+    static bool run_##suite_name(struct unittest* test) { \
+        return RUN_ALL_TESTS();                           \
+    }                                                     \
+                                                          \
+    int main(int argc, char** argv) {                     \
+        static struct unittest test = {                   \
+                .port_name = port_name_string,            \
+                .run_test = run_##suite_name,             \
+        };                                                \
+        struct unittest* tests = &test;                   \
+        /* gtest requires argc > 1 */                     \
+        int fake_argc = 1;                                \
+        char* fake_argv[] = {(char*)"test", NULL};        \
+        testing::InitGoogleTest(&fake_argc, fake_argv);   \
+        return unittest_main(&tests, 1);                  \
+    }                                                     \
+    __END_CDECLS
diff --git a/lib/googletest/rules.mk b/lib/googletest/rules.mk
new file mode 100644
index 0000000..d69278c
--- /dev/null
+++ b/lib/googletest/rules.mk
@@ -0,0 +1,54 @@
+LOCAL_DIR := $(GET_LOCAL_DIR)
+
+MODULE := $(LOCAL_DIR)
+
+MODULE_STATIC_LIB := true
+
+GTEST_DIR := external/googletest/googletest
+
+# Export gtest headers.
+GLOBAL_INCLUDES += $(GTEST_DIR)/include
+
+# gtest has internal includes relative to its root directory.
+MODULE_INCLUDES += $(GTEST_DIR)
+
+# Disable optional features.
+MODULE_COMPILEFLAGS += \
+	-DGTEST_HAS_CLONE=0 \
+	-DGTEST_HAS_EXCEPTIONS=0 \
+	-DGTEST_HAS_POSIX_RE=0 \
+	-DGTEST_HAS_PTHREAD=0 \
+	-DGTEST_HAS_RTTI=0 \
+	-DGTEST_HAS_STD_WSTRING=0 \
+	-DGTEST_HAS_SEH=0 \
+	-DGTEST_HAS_STREAM_REDIRECTION=0 \
+	-DGTEST_LINKED_AS_SHARED_LIBRARY=0 \
+	-DGTEST_CREATE_SHARED_LIBRARY=0 \
+	-DGTEST_HAS_DEATH_TEST=0 \
+
+# Horrible hack for preventing OS detection.
+# If we don't prevent OS detection, gtest-port.h will try to enable death tests.
+MODULE_COMPILEFLAGS += -DGTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_ARCH_H_=1
+
+# After disabling a bunch of features, there are dead constants.
+MODULE_COMPILEFLAGS += -Wno-unused-const-variable
+
+# Explicitly list the files instead of using gtest-all.cc so the build can be
+# parallelized. Note we need to build all the files because of how command line
+# flags are handled. For example, we don't support death tests, but still need
+# to compile gtest-death-test.cc because gtest.cc references
+# GTEST_FLAG(death_test_style).
+MODULE_SRCS := \
+	$(GTEST_DIR)/src/gtest.cc \
+	$(GTEST_DIR)/src/gtest-death-test.cc \
+	$(GTEST_DIR)/src/gtest-filepath.cc \
+	$(GTEST_DIR)/src/gtest-matchers.cc \
+	$(GTEST_DIR)/src/gtest-port.cc \
+	$(GTEST_DIR)/src/gtest-printers.cc \
+	$(GTEST_DIR)/src/gtest-test-part.cc \
+	$(GTEST_DIR)/src/gtest-typed-test.cc \
+
+MODULE_DEPS := \
+        trusty/user/base/lib/libstdc++-trusty \
+
+include make/module.mk
diff --git a/lib/libc-trusty/file_stubs.c b/lib/libc-trusty/file_stubs.c
new file mode 100644
index 0000000..af1d32a
--- /dev/null
+++ b/lib/libc-trusty/file_stubs.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+/* These stubs exist mostly to support gtest. */
+
+FILE* fopen(const char* restrict filename, const char* restrict mode) {
+    errno = ENOENT;
+    return NULL;
+}
+
+/*
+ * gtest expects getcwd to return a non-empty string, otherwise it will error
+ * internally.
+ */
+char* getcwd(char* buf, size_t size) {
+    strncpy(buf, "/", size);
+    return buf;
+}
+
+int isatty(int fd) {
+    return 0;
+}
+
+int remove(const char* pathname) {
+    errno = EACCES;
+    return -1;
+}
+
+int mkdir(const char* pathname, mode_t mode) {
+    errno = EACCES;
+    return -1;
+}
+
+int stat(const char* path, struct stat* buf) {
+    errno = EACCES;
+    return -1;
+}
diff --git a/lib/libc-trusty/include/sys/wait.h b/lib/libc-trusty/include/sys/wait.h
new file mode 100644
index 0000000..29bd9c1
--- /dev/null
+++ b/lib/libc-trusty/include/sys/wait.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+/*
+ * The standard version of this file defines "wait" which conflicts with
+ * Trusty's "wait". This causes a problem when compiling gtest.
+ * Trusty's wait function should probally be renamed, but since naming is
+ * difficult we're adding this file to punt and mask the standard version.
+ */
diff --git a/lib/libc-trusty/rules.mk b/lib/libc-trusty/rules.mk
index 3cfb45b..aa903a4 100644
--- a/lib/libc-trusty/rules.mk
+++ b/lib/libc-trusty/rules.mk
@@ -72,6 +72,19 @@
 MODULE_COMPILEFLAGS += \
 	-Wno-unknown-pragmas \
 
+# Musl will do something like this:
+# weak_alias(a, b); weak_alias(b, c);
+# But it appears the second statement will get eagerly evaluated to:
+# weak_alias(a, c);
+# and overriding b will not affect c.  This is likely not intended behavior, but
+# it does not matter for us so ignore it.
+MODULE_COMPILEFLAGS += \
+	-Wno-ignored-attributes \
+
+# The are compares that make sense in 64-bit but do not make sense in 32-bit.
+MODULE_COMPILEFLAGS += \
+	-Wno-tautological-constant-compare
+
 # NOTE eabi_unwind_stubs.c because libgcc pulls in unwinding stuff.
 # NOTE using dlmalloc because it's difficult to guarentee Musl's malloc will
 # work without mmap.
@@ -79,6 +92,7 @@
 	external/lk/lib/libc/eabi_unwind_stubs.c \
 	$(LOCAL_DIR)/__dso_handle.c \
 	$(LOCAL_DIR)/__set_thread_area.c \
+	$(LOCAL_DIR)/file_stubs.c \
 	$(LOCAL_DIR)/locale_stubs.c \
 	$(LOCAL_DIR)/malloc.c \
 	$(LOCAL_DIR)/time_stubs.c \
@@ -261,14 +275,20 @@
 	$(MUSL_DIR)/src/string/wmemmove.c \
 	$(MUSL_DIR)/src/string/wmemset.c \
 	$(MUSL_DIR)/src/stdio/asprintf.c \
+	$(MUSL_DIR)/src/stdio/fclose.c \
 	$(MUSL_DIR)/src/stdio/fflush.c \
+	$(MUSL_DIR)/src/stdio/fileno.c \
 	$(MUSL_DIR)/src/stdio/fputc.c \
 	$(MUSL_DIR)/src/stdio/fputs.c \
 	$(MUSL_DIR)/src/stdio/fprintf.c \
+	$(MUSL_DIR)/src/stdio/fread.c \
+	$(MUSL_DIR)/src/stdio/fseek.c \
+	$(MUSL_DIR)/src/stdio/ftell.c \
 	$(MUSL_DIR)/src/stdio/fwrite.c \
 	$(MUSL_DIR)/src/stdio/getc.c \
 	$(MUSL_DIR)/src/stdio/ofl.c \
 	$(MUSL_DIR)/src/stdio/printf.c \
+	$(MUSL_DIR)/src/stdio/putc_unlocked.c \
 	$(MUSL_DIR)/src/stdio/putchar.c \
 	$(MUSL_DIR)/src/stdio/puts.c \
 	$(MUSL_DIR)/src/stdio/sscanf.c \
@@ -279,6 +299,7 @@
 	$(MUSL_DIR)/src/stdio/stdout.c \
 	$(MUSL_DIR)/src/stdio/ungetc.c \
 	$(MUSL_DIR)/src/stdio/vasprintf.c \
+	$(MUSL_DIR)/src/stdio/vprintf.c \
 	$(MUSL_DIR)/src/stdio/vfprintf.c \
 	$(MUSL_DIR)/src/stdio/vsnprintf.c \
 	$(MUSL_DIR)/src/stdio/vsprintf.c \
@@ -300,6 +321,10 @@
 	$(MUSL_DIR)/src/thread/default_attr.c \
 	$(MUSL_DIR)/src/thread/pthread_once.c \
 	$(MUSL_DIR)/src/thread/pthread_cleanup_push.c \
+	$(MUSL_DIR)/src/time/gettimeofday.c \
+	$(MUSL_DIR)/src/time/localtime.c \
+	$(MUSL_DIR)/src/time/localtime_r.c \
+	$(MUSL_DIR)/src/time/__secs_to_tm.c \
 
 # Math
 MODULE_SRCS += \
diff --git a/lib/libc-trusty/time_stubs.c b/lib/libc-trusty/time_stubs.c
index 1ca4daa..b2c124c 100644
--- a/lib/libc-trusty/time_stubs.c
+++ b/lib/libc-trusty/time_stubs.c
@@ -37,3 +37,18 @@
                 const struct tm* restrict tm) {
     return strftime_l(s, n, f, tm, 0);
 }
+
+/* Mock Musl function for timezone information - no databases available. */
+void __secs_to_zone(long long t,
+                    int local,
+                    int* isdst,
+                    long* offset,
+                    long* oppoff,
+                    const char** zonename) {
+    /* UTC+0 */
+    *isdst = 0;
+    *offset = 0;
+    if (oppoff)
+        *oppoff = 0;
+    *zonename = "UTC";
+}