Changes/Additional to crash dumper

This commit is contained in:
khanhduytran0 2020-11-11 19:39:05 +07:00
parent 13a63edf8a
commit fce46f1614
37 changed files with 3866 additions and 7 deletions

View file

@ -1,7 +1,7 @@
LOCAL_PATH := $(call my-dir)
HERE_PATH := $(LOCAL_PATH)
# include $(HERE_PATH)/crash_dump/libunwind/Android.mk
include $(HERE_PATH)/crash_dump/libbase/Android.mk
include $(HERE_PATH)/crash_dump/libbacktrace/Android.mk
include $(HERE_PATH)/crash_dump/debuggerd/Android.mk
@ -27,7 +27,7 @@ include $(BUILD_SHARED_LIBRARY)
# LOCAL_SRC_FILES := thread_helper.cpp
# include $(BUILD_SHARED_LIBRARY)
# libawt_xawt without X11
# libawt_xawt without X11, used to get Caciocavallo working
LOCAL_PATH := $(HERE_PATH)/awt_xawt
include $(CLEAR_VARS)
LOCAL_MODULE := awt_xawt

View file

@ -37,7 +37,7 @@ endif
LOCAL_LDLIBS := -llog
LOCAL_SHARED_LIBRARIES := \
libbacktrace \
libbase
libcrashdumpbase
LOCAL_CLANG := true

View file

@ -56,10 +56,8 @@ libbacktrace_src_files := \
UnwindMap.cpp \
UnwindPtrace.cpp \
libbacktrace_shared_ldlibs := -llog -lunwind
# -lbase
# libbacktrace_shared_libraries := libunwind
libbacktrace_shared_ldlibs := -llog
libbacktrace_shared_libraries := libunwind libcrashdumpbase
module := libbacktrace
module_tag := optional

View file

@ -0,0 +1,11 @@
BasedOnStyle: Google
AllowShortBlocksOnASingleLine: false
AllowShortFunctionsOnASingleLine: false
CommentPragmas: NOLINT:.*
DerivePointerAlignment: false
IndentWidth: 2
PointerAlignment: Left
TabWidth: 2
UseTab: Never
PenaltyExcessCharacter: 32

View file

@ -0,0 +1,59 @@
#
# Copyright (C) 2015 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.
#
LOCAL_PATH := $(call my-dir)
libbase_src_files := \
file.cpp \
logging.cpp \
parsenetaddress.cpp \
stringprintf.cpp \
strings.cpp \
test_utils.cpp \
libbase_cppflags := \
-Wall \
-Wextra \
-Werror \
libbase_linux_cppflags := \
-Wexit-time-destructors \
libbase_darwin_cppflags := \
-Wexit-time-destructors \
# Device
# ------------------------------------------------------------------------------
include $(CLEAR_VARS)
LOCAL_MODULE := libcrashdumpbase
LOCAL_CLANG := true
LOCAL_SRC_FILES := $(libbase_src_files) $(libbase_linux_src_files)
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
LOCAL_CPPFLAGS := $(libbase_cppflags) $(libbase_linux_cppflags)
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
LOCAL_STATIC_LIBRARIES := liblog
LOCAL_MULTILIB := both
include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := libcrashdumpbase
LOCAL_CLANG := true
LOCAL_WHOLE_STATIC_LIBRARIES := libcrashdumpbase
LOCAL_SHARED_LIBRARIES := liblog
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
LOCAL_MULTILIB := both
include $(BUILD_SHARED_LIBRARY)

View file

@ -0,0 +1,2 @@
set noparent
filter=-build/header_guard,-build/include,-build/c++11,-whitespace/operators

View file

@ -0,0 +1,34 @@
/*
* Copyright (C) 2016 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 "android-base/errors.h"
#include <gtest/gtest.h>
namespace android {
namespace base {
// Error strings aren't consistent enough across systems to test the output,
// just make sure we can compile correctly and nothing crashes even if we send
// it possibly bogus error codes.
TEST(ErrorsTest, TestSystemErrorString) {
SystemErrorCodeToString(-1);
SystemErrorCodeToString(0);
SystemErrorCodeToString(1);
}
} // namespace base
} // namespace android

View file

@ -0,0 +1,29 @@
/*
* Copyright (C) 2016 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 "android-base/errors.h"
#include <errno.h>
namespace android {
namespace base {
std::string SystemErrorCodeToString(int error_code) {
return strerror(error_code);
}
} // namespace base
} // namespace android

View file

@ -0,0 +1,68 @@
/*
* Copyright (C) 2016 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 "android-base/errors.h"
#include <windows.h>
#include "android-base/stringprintf.h"
#include "android-base/strings.h"
#include "android-base/utf8.h"
// A Windows error code is a DWORD. It's simpler to use an int error code for
// both Unix and Windows if possible, but if this fails we'll need a different
// function signature for each.
static_assert(sizeof(int) >= sizeof(DWORD),
"Windows system error codes are too large to fit in an int.");
namespace android {
namespace base {
static constexpr DWORD kErrorMessageBufferSize = 256;
std::string SystemErrorCodeToString(int int_error_code) {
WCHAR msgbuf[kErrorMessageBufferSize];
DWORD error_code = int_error_code;
DWORD flags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS;
DWORD len = FormatMessageW(flags, nullptr, error_code, 0, msgbuf,
kErrorMessageBufferSize, nullptr);
if (len == 0) {
return android::base::StringPrintf(
"Error %lu while retrieving message for error %lu", GetLastError(),
error_code);
}
// Convert UTF-16 to UTF-8.
std::string msg;
if (!android::base::WideToUTF8(msgbuf, &msg)) {
return android::base::StringPrintf(
"Error %lu while converting message for error %lu from UTF-16 to UTF-8",
GetLastError(), error_code);
}
// Messages returned by the system end with line breaks.
msg = android::base::Trim(msg);
// There are many Windows error messages compared to POSIX, so include the
// numeric error code for easier, quicker, accurate identification. Use
// decimal instead of hex because there are decimal ranges like 10000-11999
// for Winsock.
android::base::StringAppendF(&msg, " (%lu)", error_code);
return msg;
}
} // namespace base
} // namespace android

View file

@ -0,0 +1,176 @@
/*
* Copyright (C) 2015 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 "android-base/file.h"
#include <errno.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <string>
#include "android-base/macros.h" // For TEMP_FAILURE_RETRY on Darwin.
#include "android-base/utf8.h"
#define LOG_TAG "base.file"
#include "cutils/log.h"
#include "utils/Compat.h"
namespace android {
namespace base {
// Versions of standard library APIs that support UTF-8 strings.
using namespace android::base::utf8;
bool ReadFdToString(int fd, std::string* content) {
content->clear();
char buf[BUFSIZ];
ssize_t n;
while ((n = TEMP_FAILURE_RETRY(read(fd, &buf[0], sizeof(buf)))) > 0) {
content->append(buf, n);
}
return (n == 0) ? true : false;
}
bool ReadFileToString(const std::string& path, std::string* content) {
content->clear();
int fd = TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_BINARY));
if (fd == -1) {
return false;
}
bool result = ReadFdToString(fd, content);
close(fd);
return result;
}
bool WriteStringToFd(const std::string& content, int fd) {
const char* p = content.data();
size_t left = content.size();
while (left > 0) {
ssize_t n = TEMP_FAILURE_RETRY(write(fd, p, left));
if (n == -1) {
return false;
}
p += n;
left -= n;
}
return true;
}
static bool CleanUpAfterFailedWrite(const std::string& path) {
// Something went wrong. Let's not leave a corrupt file lying around.
int saved_errno = errno;
unlink(path.c_str());
errno = saved_errno;
return false;
}
#if !defined(_WIN32)
bool WriteStringToFile(const std::string& content, const std::string& path,
mode_t mode, uid_t owner, gid_t group) {
int flags = O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW | O_BINARY;
int fd = TEMP_FAILURE_RETRY(open(path.c_str(), flags, mode));
if (fd == -1) {
ALOGE("android::WriteStringToFile open failed: %s", strerror(errno));
return false;
}
// We do an explicit fchmod here because we assume that the caller really
// meant what they said and doesn't want the umask-influenced mode.
if (fchmod(fd, mode) == -1) {
ALOGE("android::WriteStringToFile fchmod failed: %s", strerror(errno));
return CleanUpAfterFailedWrite(path);
}
if (fchown(fd, owner, group) == -1) {
ALOGE("android::WriteStringToFile fchown failed: %s", strerror(errno));
return CleanUpAfterFailedWrite(path);
}
if (!WriteStringToFd(content, fd)) {
ALOGE("android::WriteStringToFile write failed: %s", strerror(errno));
return CleanUpAfterFailedWrite(path);
}
close(fd);
return true;
}
#endif
bool WriteStringToFile(const std::string& content, const std::string& path) {
int flags = O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW | O_BINARY;
int fd = TEMP_FAILURE_RETRY(open(path.c_str(), flags, DEFFILEMODE));
if (fd == -1) {
return false;
}
bool result = WriteStringToFd(content, fd);
close(fd);
return result || CleanUpAfterFailedWrite(path);
}
bool ReadFully(int fd, void* data, size_t byte_count) {
uint8_t* p = reinterpret_cast<uint8_t*>(data);
size_t remaining = byte_count;
while (remaining > 0) {
ssize_t n = TEMP_FAILURE_RETRY(read(fd, p, remaining));
if (n <= 0) return false;
p += n;
remaining -= n;
}
return true;
}
bool WriteFully(int fd, const void* data, size_t byte_count) {
const uint8_t* p = reinterpret_cast<const uint8_t*>(data);
size_t remaining = byte_count;
while (remaining > 0) {
ssize_t n = TEMP_FAILURE_RETRY(write(fd, p, remaining));
if (n == -1) return false;
p += n;
remaining -= n;
}
return true;
}
bool RemoveFileIfExists(const std::string& path, std::string* err) {
struct stat st;
#if defined(_WIN32)
//TODO: Windows version can't handle symbol link correctly.
int result = stat(path.c_str(), &st);
bool file_type_removable = (result == 0 && S_ISREG(st.st_mode));
#else
int result = lstat(path.c_str(), &st);
bool file_type_removable = (result == 0 && (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)));
#endif
if (result == 0) {
if (!file_type_removable) {
if (err != nullptr) {
*err = "is not a regular or symbol link file";
}
return false;
}
if (unlink(path.c_str()) == -1) {
if (err != nullptr) {
*err = strerror(errno);
}
return false;
}
}
return true;
}
} // namespace base
} // namespace android

View file

@ -0,0 +1,112 @@
/*
* Copyright (C) 2013 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 "android-base/file.h"
#include <gtest/gtest.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <string>
#include "android-base/test_utils.h"
TEST(file, ReadFileToString_ENOENT) {
std::string s("hello");
errno = 0;
ASSERT_FALSE(android::base::ReadFileToString("/proc/does-not-exist", &s));
EXPECT_EQ(ENOENT, errno);
EXPECT_EQ("", s); // s was cleared.
}
TEST(file, ReadFileToString_WriteStringToFile) {
TemporaryFile tf;
ASSERT_TRUE(tf.fd != -1);
ASSERT_TRUE(android::base::WriteStringToFile("abc", tf.path))
<< strerror(errno);
std::string s;
ASSERT_TRUE(android::base::ReadFileToString(tf.path, &s))
<< strerror(errno);
EXPECT_EQ("abc", s);
}
// WriteStringToFile2 is explicitly for setting Unix permissions, which make no
// sense on Windows.
#if !defined(_WIN32)
TEST(file, WriteStringToFile2) {
TemporaryFile tf;
ASSERT_TRUE(tf.fd != -1);
ASSERT_TRUE(android::base::WriteStringToFile("abc", tf.path, 0660,
getuid(), getgid()))
<< strerror(errno);
struct stat sb;
ASSERT_EQ(0, stat(tf.path, &sb));
ASSERT_EQ(0660U, static_cast<unsigned int>(sb.st_mode & ~S_IFMT));
ASSERT_EQ(getuid(), sb.st_uid);
ASSERT_EQ(getgid(), sb.st_gid);
std::string s;
ASSERT_TRUE(android::base::ReadFileToString(tf.path, &s))
<< strerror(errno);
EXPECT_EQ("abc", s);
}
#endif
TEST(file, WriteStringToFd) {
TemporaryFile tf;
ASSERT_TRUE(tf.fd != -1);
ASSERT_TRUE(android::base::WriteStringToFd("abc", tf.fd));
ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_SET)) << strerror(errno);
std::string s;
ASSERT_TRUE(android::base::ReadFdToString(tf.fd, &s)) << strerror(errno);
EXPECT_EQ("abc", s);
}
TEST(file, WriteFully) {
TemporaryFile tf;
ASSERT_TRUE(tf.fd != -1);
ASSERT_TRUE(android::base::WriteFully(tf.fd, "abc", 3));
ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_SET)) << strerror(errno);
std::string s;
s.resize(3);
ASSERT_TRUE(android::base::ReadFully(tf.fd, &s[0], s.size()))
<< strerror(errno);
EXPECT_EQ("abc", s);
ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_SET)) << strerror(errno);
s.resize(1024);
ASSERT_FALSE(android::base::ReadFully(tf.fd, &s[0], s.size()));
}
TEST(file, RemoveFileIfExist) {
TemporaryFile tf;
ASSERT_TRUE(tf.fd != -1);
close(tf.fd);
tf.fd = -1;
std::string err;
ASSERT_TRUE(android::base::RemoveFileIfExists(tf.path, &err)) << err;
ASSERT_TRUE(android::base::RemoveFileIfExists(tf.path));
TemporaryDir td;
ASSERT_FALSE(android::base::RemoveFileIfExists(td.path));
ASSERT_FALSE(android::base::RemoveFileIfExists(td.path, &err));
ASSERT_EQ("is not a regular or symbol link file", err);
}

View file

@ -0,0 +1,46 @@
/*
* Copyright (C) 2016 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.
*/
// Portable error handling functions. This is only necessary for host-side
// code that needs to be cross-platform; code that is only run on Unix should
// just use errno and strerror() for simplicity.
//
// There is some complexity since Windows has (at least) three different error
// numbers, not all of which share the same type:
// * errno: for C runtime errors.
// * GetLastError(): Windows non-socket errors.
// * WSAGetLastError(): Windows socket errors.
// errno can be passed to strerror() on all platforms, but the other two require
// special handling to get the error string. Refer to Microsoft documentation
// to determine which error code to check for each function.
#ifndef ANDROID_BASE_ERRORS_H
#define ANDROID_BASE_ERRORS_H
#include <string>
namespace android {
namespace base {
// Returns a string describing the given system error code. |error_code| must
// be errno on Unix or GetLastError()/WSAGetLastError() on Windows. Passing
// errno on Windows has undefined behavior.
std::string SystemErrorCodeToString(int error_code);
} // namespace base
} // namespace android
#endif // ANDROID_BASE_ERRORS_H

View file

@ -0,0 +1,49 @@
/*
* Copyright (C) 2015 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.
*/
#ifndef ANDROID_BASE_FILE_H
#define ANDROID_BASE_FILE_H
#include <sys/stat.h>
#include <string>
#if !defined(_WIN32) && !defined(O_BINARY)
#define O_BINARY 0
#endif
namespace android {
namespace base {
bool ReadFdToString(int fd, std::string* content);
bool ReadFileToString(const std::string& path, std::string* content);
bool WriteStringToFile(const std::string& content, const std::string& path);
bool WriteStringToFd(const std::string& content, int fd);
#if !defined(_WIN32)
bool WriteStringToFile(const std::string& content, const std::string& path,
mode_t mode, uid_t owner, gid_t group);
#endif
bool ReadFully(int fd, void* data, size_t byte_count);
bool WriteFully(int fd, const void* data, size_t byte_count);
bool RemoveFileIfExists(const std::string& path, std::string* err = nullptr);
} // namespace base
} // namespace android
#endif // ANDROID_BASE_FILE_H

View file

@ -0,0 +1,338 @@
/*
* Copyright (C) 2015 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.
*/
#ifndef ANDROID_BASE_LOGGING_H
#define ANDROID_BASE_LOGGING_H
// NOTE: For Windows, you must include logging.h after windows.h to allow the
// following code to suppress the evil ERROR macro:
#ifdef _WIN32
// windows.h includes wingdi.h which defines an evil macro ERROR.
#ifdef ERROR
#undef ERROR
#endif
#endif
#include <functional>
#include <memory>
#include <ostream>
#include "android-base/macros.h"
namespace android {
namespace base {
enum LogSeverity {
VERBOSE,
DEBUG,
INFO,
WARNING,
ERROR,
FATAL,
};
enum LogId {
DEFAULT,
MAIN,
SYSTEM,
};
typedef std::function<void(LogId, LogSeverity, const char*, const char*,
unsigned int, const char*)> LogFunction;
extern void StderrLogger(LogId, LogSeverity, const char*, const char*,
unsigned int, const char*);
#ifdef __ANDROID__
// We expose this even though it is the default because a user that wants to
// override the default log buffer will have to construct this themselves.
class LogdLogger {
public:
explicit LogdLogger(LogId default_log_id = android::base::MAIN);
void operator()(LogId, LogSeverity, const char* tag, const char* file,
unsigned int line, const char* message);
private:
LogId default_log_id_;
};
#endif
// Configure logging based on ANDROID_LOG_TAGS environment variable.
// We need to parse a string that looks like
//
// *:v jdwp:d dalvikvm:d dalvikvm-gc:i dalvikvmi:i
//
// The tag (or '*' for the global level) comes first, followed by a colon and a
// letter indicating the minimum priority level we're expected to log. This can
// be used to reveal or conceal logs with specific tags.
extern void InitLogging(char* argv[], LogFunction&& logger);
// Configures logging using the default logger (logd for the device, stderr for
// the host).
extern void InitLogging(char* argv[]);
// Replace the current logger.
extern void SetLogger(LogFunction&& logger);
// Get the minimum severity level for logging.
extern LogSeverity GetMinimumLogSeverity();
class ErrnoRestorer {
public:
ErrnoRestorer()
: saved_errno_(errno) {
}
~ErrnoRestorer() {
errno = saved_errno_;
}
// Allow this object to be used as part of && operation.
operator bool() const {
return true;
}
private:
const int saved_errno_;
DISALLOW_COPY_AND_ASSIGN(ErrnoRestorer);
};
// Logs a message to logcat on Android otherwise to stderr. If the severity is
// FATAL it also causes an abort. For example:
//
// LOG(FATAL) << "We didn't expect to reach here";
#define LOG(severity) LOG_TO(DEFAULT, severity)
// Logs a message to logcat with the specified log ID on Android otherwise to
// stderr. If the severity is FATAL it also causes an abort.
// Use an if-else statement instead of just an if statement here. So if there is a
// else statement after LOG() macro, it won't bind to the if statement in the macro.
// do-while(0) statement doesn't work here. Because we need to support << operator
// following the macro, like "LOG(DEBUG) << xxx;".
#define LOG_TO(dest, severity) \
UNLIKELY(::android::base::severity >= ::android::base::GetMinimumLogSeverity()) && \
::android::base::ErrnoRestorer() && \
::android::base::LogMessage(__FILE__, __LINE__, \
::android::base::dest, \
::android::base::severity, -1).stream()
// A variant of LOG that also logs the current errno value. To be used when
// library calls fail.
#define PLOG(severity) PLOG_TO(DEFAULT, severity)
// Behaves like PLOG, but logs to the specified log ID.
#define PLOG_TO(dest, severity) \
UNLIKELY(::android::base::severity >= ::android::base::GetMinimumLogSeverity()) && \
::android::base::ErrnoRestorer() && \
::android::base::LogMessage(__FILE__, __LINE__, \
::android::base::dest, \
::android::base::severity, errno).stream()
// Marker that code is yet to be implemented.
#define UNIMPLEMENTED(level) \
LOG(level) << __PRETTY_FUNCTION__ << " unimplemented "
// Check whether condition x holds and LOG(FATAL) if not. The value of the
// expression x is only evaluated once. Extra logging can be appended using <<
// after. For example:
//
// CHECK(false == true) results in a log message of
// "Check failed: false == true".
#define CHECK(x) \
LIKELY((x)) || \
::android::base::LogMessage(__FILE__, __LINE__, ::android::base::DEFAULT, \
::android::base::FATAL, -1).stream() \
<< "Check failed: " #x << " "
// Helper for CHECK_xx(x,y) macros.
#define CHECK_OP(LHS, RHS, OP) \
for (auto _values = ::android::base::MakeEagerEvaluator(LHS, RHS); \
UNLIKELY(!(_values.lhs OP _values.rhs)); \
/* empty */) \
::android::base::LogMessage(__FILE__, __LINE__, ::android::base::DEFAULT, \
::android::base::FATAL, -1).stream() \
<< "Check failed: " << #LHS << " " << #OP << " " << #RHS \
<< " (" #LHS "=" << _values.lhs << ", " #RHS "=" << _values.rhs << ") "
// Check whether a condition holds between x and y, LOG(FATAL) if not. The value
// of the expressions x and y is evaluated once. Extra logging can be appended
// using << after. For example:
//
// CHECK_NE(0 == 1, false) results in
// "Check failed: false != false (0==1=false, false=false) ".
#define CHECK_EQ(x, y) CHECK_OP(x, y, == )
#define CHECK_NE(x, y) CHECK_OP(x, y, != )
#define CHECK_LE(x, y) CHECK_OP(x, y, <= )
#define CHECK_LT(x, y) CHECK_OP(x, y, < )
#define CHECK_GE(x, y) CHECK_OP(x, y, >= )
#define CHECK_GT(x, y) CHECK_OP(x, y, > )
// Helper for CHECK_STRxx(s1,s2) macros.
#define CHECK_STROP(s1, s2, sense) \
if (LIKELY((strcmp(s1, s2) == 0) == sense)) \
; \
else \
LOG(FATAL) << "Check failed: " \
<< "\"" << s1 << "\"" \
<< (sense ? " == " : " != ") << "\"" << s2 << "\""
// Check for string (const char*) equality between s1 and s2, LOG(FATAL) if not.
#define CHECK_STREQ(s1, s2) CHECK_STROP(s1, s2, true)
#define CHECK_STRNE(s1, s2) CHECK_STROP(s1, s2, false)
// Perform the pthread function call(args), LOG(FATAL) on error.
#define CHECK_PTHREAD_CALL(call, args, what) \
do { \
int rc = call args; \
if (rc != 0) { \
errno = rc; \
PLOG(FATAL) << #call << " failed for " << what; \
} \
} while (false)
// CHECK that can be used in a constexpr function. For example:
//
// constexpr int half(int n) {
// return
// DCHECK_CONSTEXPR(n >= 0, , 0)
// CHECK_CONSTEXPR((n & 1) == 0),
// << "Extra debugging output: n = " << n, 0)
// n / 2;
// }
#define CHECK_CONSTEXPR(x, out, dummy) \
(UNLIKELY(!(x))) \
? (LOG(FATAL) << "Check failed: " << #x out, dummy) \
:
// DCHECKs are debug variants of CHECKs only enabled in debug builds. Generally
// CHECK should be used unless profiling identifies a CHECK as being in
// performance critical code.
#if defined(NDEBUG)
static constexpr bool kEnableDChecks = false;
#else
static constexpr bool kEnableDChecks = true;
#endif
#define DCHECK(x) \
if (::android::base::kEnableDChecks) CHECK(x)
#define DCHECK_EQ(x, y) \
if (::android::base::kEnableDChecks) CHECK_EQ(x, y)
#define DCHECK_NE(x, y) \
if (::android::base::kEnableDChecks) CHECK_NE(x, y)
#define DCHECK_LE(x, y) \
if (::android::base::kEnableDChecks) CHECK_LE(x, y)
#define DCHECK_LT(x, y) \
if (::android::base::kEnableDChecks) CHECK_LT(x, y)
#define DCHECK_GE(x, y) \
if (::android::base::kEnableDChecks) CHECK_GE(x, y)
#define DCHECK_GT(x, y) \
if (::android::base::kEnableDChecks) CHECK_GT(x, y)
#define DCHECK_STREQ(s1, s2) \
if (::android::base::kEnableDChecks) CHECK_STREQ(s1, s2)
#define DCHECK_STRNE(s1, s2) \
if (::android::base::kEnableDChecks) CHECK_STRNE(s1, s2)
#if defined(NDEBUG)
#define DCHECK_CONSTEXPR(x, out, dummy)
#else
#define DCHECK_CONSTEXPR(x, out, dummy) CHECK_CONSTEXPR(x, out, dummy)
#endif
// Temporary class created to evaluate the LHS and RHS, used with
// MakeEagerEvaluator to infer the types of LHS and RHS.
template <typename LHS, typename RHS>
struct EagerEvaluator {
EagerEvaluator(LHS l, RHS r) : lhs(l), rhs(r) {
}
LHS lhs;
RHS rhs;
};
// Helper function for CHECK_xx.
template <typename LHS, typename RHS>
static inline EagerEvaluator<LHS, RHS> MakeEagerEvaluator(LHS lhs, RHS rhs) {
return EagerEvaluator<LHS, RHS>(lhs, rhs);
}
// Explicitly instantiate EagerEvalue for pointers so that char*s aren't treated
// as strings. To compare strings use CHECK_STREQ and CHECK_STRNE. We rely on
// signed/unsigned warnings to protect you against combinations not explicitly
// listed below.
#define EAGER_PTR_EVALUATOR(T1, T2) \
template <> \
struct EagerEvaluator<T1, T2> { \
EagerEvaluator(T1 l, T2 r) \
: lhs(reinterpret_cast<const void*>(l)), \
rhs(reinterpret_cast<const void*>(r)) { \
} \
const void* lhs; \
const void* rhs; \
}
EAGER_PTR_EVALUATOR(const char*, const char*);
EAGER_PTR_EVALUATOR(const char*, char*);
EAGER_PTR_EVALUATOR(char*, const char*);
EAGER_PTR_EVALUATOR(char*, char*);
EAGER_PTR_EVALUATOR(const unsigned char*, const unsigned char*);
EAGER_PTR_EVALUATOR(const unsigned char*, unsigned char*);
EAGER_PTR_EVALUATOR(unsigned char*, const unsigned char*);
EAGER_PTR_EVALUATOR(unsigned char*, unsigned char*);
EAGER_PTR_EVALUATOR(const signed char*, const signed char*);
EAGER_PTR_EVALUATOR(const signed char*, signed char*);
EAGER_PTR_EVALUATOR(signed char*, const signed char*);
EAGER_PTR_EVALUATOR(signed char*, signed char*);
// Data for the log message, not stored in LogMessage to avoid increasing the
// stack size.
class LogMessageData;
// A LogMessage is a temporarily scoped object used by LOG and the unlikely part
// of a CHECK. The destructor will abort if the severity is FATAL.
class LogMessage {
public:
LogMessage(const char* file, unsigned int line, LogId id,
LogSeverity severity, int error);
~LogMessage();
// Returns the stream associated with the message, the LogMessage performs
// output when it goes out of scope.
std::ostream& stream();
// The routine that performs the actual logging.
static void LogLine(const char* file, unsigned int line, LogId id,
LogSeverity severity, const char* msg);
private:
const std::unique_ptr<LogMessageData> data_;
DISALLOW_COPY_AND_ASSIGN(LogMessage);
};
// Allows to temporarily change the minimum severity level for logging.
class ScopedLogSeverity {
public:
explicit ScopedLogSeverity(LogSeverity level);
~ScopedLogSeverity();
private:
LogSeverity old_;
};
} // namespace base
} // namespace android
#endif // ANDROID_BASE_LOGGING_H

View file

@ -0,0 +1,188 @@
/*
* Copyright (C) 2015 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.
*/
#ifndef ANDROID_BASE_MACROS_H
#define ANDROID_BASE_MACROS_H
#include <stddef.h> // for size_t
#include <unistd.h> // for TEMP_FAILURE_RETRY
// bionic and glibc both have TEMP_FAILURE_RETRY, but eg Mac OS' libc doesn't.
#ifndef TEMP_FAILURE_RETRY
#define TEMP_FAILURE_RETRY(exp) \
({ \
decltype(exp) _rc; \
do { \
_rc = (exp); \
} while (_rc == -1 && errno == EINTR); \
_rc; \
})
#endif
// A macro to disallow the copy constructor and operator= functions
// This must be placed in the private: declarations for a class.
//
// For disallowing only assign or copy, delete the relevant operator or
// constructor, for example:
// void operator=(const TypeName&) = delete;
// Note, that most uses of DISALLOW_ASSIGN and DISALLOW_COPY are broken
// semantically, one should either use disallow both or neither. Try to
// avoid these in new code.
//
// When building with C++11 toolchains, just use the language support
// for explicitly deleted methods.
#if __cplusplus >= 201103L
#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
TypeName(const TypeName&) = delete; \
void operator=(const TypeName&) = delete
#else
#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
TypeName(const TypeName&); \
void operator=(const TypeName&)
#endif
// A macro to disallow all the implicit constructors, namely the
// default constructor, copy constructor and operator= functions.
//
// This should be used in the private: declarations for a class
// that wants to prevent anyone from instantiating it. This is
// especially useful for classes containing only static methods.
#define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \
TypeName(); \
DISALLOW_COPY_AND_ASSIGN(TypeName)
// The arraysize(arr) macro returns the # of elements in an array arr.
// The expression is a compile-time constant, and therefore can be
// used in defining new arrays, for example. If you use arraysize on
// a pointer by mistake, you will get a compile-time error.
//
// One caveat is that arraysize() doesn't accept any array of an
// anonymous type or a type defined inside a function. In these rare
// cases, you have to use the unsafe ARRAYSIZE_UNSAFE() macro below. This is
// due to a limitation in C++'s template system. The limitation might
// eventually be removed, but it hasn't happened yet.
// This template function declaration is used in defining arraysize.
// Note that the function doesn't need an implementation, as we only
// use its type.
template <typename T, size_t N>
char(&ArraySizeHelper(T(&array)[N]))[N]; // NOLINT(readability/casting)
#define arraysize(array) (sizeof(ArraySizeHelper(array)))
// ARRAYSIZE_UNSAFE performs essentially the same calculation as arraysize,
// but can be used on anonymous types or types defined inside
// functions. It's less safe than arraysize as it accepts some
// (although not all) pointers. Therefore, you should use arraysize
// whenever possible.
//
// The expression ARRAYSIZE_UNSAFE(a) is a compile-time constant of type
// size_t.
//
// ARRAYSIZE_UNSAFE catches a few type errors. If you see a compiler error
//
// "warning: division by zero in ..."
//
// when using ARRAYSIZE_UNSAFE, you are (wrongfully) giving it a pointer.
// You should only use ARRAYSIZE_UNSAFE on statically allocated arrays.
//
// The following comments are on the implementation details, and can
// be ignored by the users.
//
// ARRAYSIZE_UNSAFE(arr) works by inspecting sizeof(arr) (the # of bytes in
// the array) and sizeof(*(arr)) (the # of bytes in one array
// element). If the former is divisible by the latter, perhaps arr is
// indeed an array, in which case the division result is the # of
// elements in the array. Otherwise, arr cannot possibly be an array,
// and we generate a compiler error to prevent the code from
// compiling.
//
// Since the size of bool is implementation-defined, we need to cast
// !(sizeof(a) & sizeof(*(a))) to size_t in order to ensure the final
// result has type size_t.
//
// This macro is not perfect as it wrongfully accepts certain
// pointers, namely where the pointer size is divisible by the pointee
// size. Since all our code has to go through a 32-bit compiler,
// where a pointer is 4 bytes, this means all pointers to a type whose
// size is 3 or greater than 4 will be (righteously) rejected.
#define ARRAYSIZE_UNSAFE(a) \
((sizeof(a) / sizeof(*(a))) / \
static_cast<size_t>(!(sizeof(a) % sizeof(*(a)))))
#define LIKELY(x) __builtin_expect((x), true)
#define UNLIKELY(x) __builtin_expect((x), false)
#define WARN_UNUSED __attribute__((warn_unused_result))
// A deprecated function to call to create a false use of the parameter, for
// example:
// int foo(int x) { UNUSED(x); return 10; }
// to avoid compiler warnings. Going forward we prefer ATTRIBUTE_UNUSED.
template <typename... T>
void UNUSED(const T&...) {
}
// An attribute to place on a parameter to a function, for example:
// int foo(int x ATTRIBUTE_UNUSED) { return 10; }
// to avoid compiler warnings.
#define ATTRIBUTE_UNUSED __attribute__((__unused__))
// The FALLTHROUGH_INTENDED macro can be used to annotate implicit fall-through
// between switch labels:
// switch (x) {
// case 40:
// case 41:
// if (truth_is_out_there) {
// ++x;
// FALLTHROUGH_INTENDED; // Use instead of/along with annotations in
// // comments.
// } else {
// return x;
// }
// case 42:
// ...
//
// As shown in the example above, the FALLTHROUGH_INTENDED macro should be
// followed by a semicolon. It is designed to mimic control-flow statements
// like 'break;', so it can be placed in most places where 'break;' can, but
// only if there are no statements on the execution path between it and the
// next switch label.
//
// When compiled with clang in C++11 mode, the FALLTHROUGH_INTENDED macro is
// expanded to [[clang::fallthrough]] attribute, which is analysed when
// performing switch labels fall-through diagnostic ('-Wimplicit-fallthrough').
// See clang documentation on language extensions for details:
// http://clang.llvm.org/docs/LanguageExtensions.html#clang__fallthrough
//
// When used with unsupported compilers, the FALLTHROUGH_INTENDED macro has no
// effect on diagnostics.
//
// In either case this macro has no effect on runtime behavior and performance
// of code.
#if defined(__clang__) && __cplusplus >= 201103L && defined(__has_warning)
#if __has_feature(cxx_attributes) && __has_warning("-Wimplicit-fallthrough")
#define FALLTHROUGH_INTENDED [[clang::fallthrough]] // NOLINT
#endif
#endif
#ifndef FALLTHROUGH_INTENDED
#define FALLTHROUGH_INTENDED \
do { \
} while (0)
#endif
#endif // ANDROID_BASE_MACROS_H

View file

@ -0,0 +1,47 @@
/*
* Copyright (C) 2015 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.
*/
#ifndef ANDROID_BASE_MEMORY_H
#define ANDROID_BASE_MEMORY_H
namespace android {
namespace base {
// Use packed structures for access to unaligned data on targets with alignment
// restrictions. The compiler will generate appropriate code to access these
// structures without generating alignment exceptions.
template <typename T>
static inline T get_unaligned(const T* address) {
struct unaligned {
T v;
} __attribute__((packed));
const unaligned* p = reinterpret_cast<const unaligned*>(address);
return p->v;
}
template <typename T>
static inline void put_unaligned(T* address, T v) {
struct unaligned {
T v;
} __attribute__((packed));
unaligned* p = reinterpret_cast<unaligned*>(address);
p->v = v;
}
} // namespace base
} // namespace android
#endif // ANDROID_BASE_MEMORY_H

View file

@ -0,0 +1,73 @@
/*
* Copyright (C) 2015 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.
*/
#ifndef ANDROID_BASE_PARSEINT_H
#define ANDROID_BASE_PARSEINT_H
#include <errno.h>
#include <stdlib.h>
#include <limits>
namespace android {
namespace base {
// Parses the unsigned decimal integer in the string 's' and sets 'out' to
// that value. Optionally allows the caller to define a 'max' beyond which
// otherwise valid values will be rejected. Returns boolean success.
template <typename T>
bool ParseUint(const char* s, T* out,
T max = std::numeric_limits<T>::max()) {
int base = (s[0] == '0' && s[1] == 'x') ? 16 : 10;
errno = 0;
char* end;
unsigned long long int result = strtoull(s, &end, base);
if (errno != 0 || s == end || *end != '\0') {
return false;
}
if (max < result) {
return false;
}
*out = static_cast<T>(result);
return true;
}
// Parses the signed decimal integer in the string 's' and sets 'out' to
// that value. Optionally allows the caller to define a 'min' and 'max
// beyond which otherwise valid values will be rejected. Returns boolean
// success.
template <typename T>
bool ParseInt(const char* s, T* out,
T min = std::numeric_limits<T>::min(),
T max = std::numeric_limits<T>::max()) {
int base = (s[0] == '0' && s[1] == 'x') ? 16 : 10;
errno = 0;
char* end;
long long int result = strtoll(s, &end, base);
if (errno != 0 || s == end || *end != '\0') {
return false;
}
if (result < min || max < result) {
return false;
}
*out = static_cast<T>(result);
return true;
}
} // namespace base
} // namespace android
#endif // ANDROID_BASE_PARSEINT_H

View file

@ -0,0 +1,38 @@
/*
* Copyright (C) 2016 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.
*/
#ifndef ANDROID_BASE_PARSENETADDRESS_H
#define ANDROID_BASE_PARSENETADDRESS_H
#include <string>
namespace android {
namespace base {
// Parses |address| into |host| and |port|.
//
// If |address| doesn't contain a port number, the default value is taken from
// |port|. If |canonical_address| is non-null it will be set to "host:port" or
// "[host]:port" as appropriate.
//
// On failure, returns false and fills |error|.
bool ParseNetAddress(const std::string& address, std::string* host, int* port,
std::string* canonical_address, std::string* error);
} // namespace base
} // namespace android
#endif // ANDROID_BASE_PARSENETADDRESS_H

View file

@ -0,0 +1,56 @@
/*
* Copyright (C) 2011 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.
*/
#ifndef ANDROID_BASE_STRINGPRINTF_H
#define ANDROID_BASE_STRINGPRINTF_H
#include <stdarg.h>
#include <string>
namespace android {
namespace base {
// These printf-like functions are implemented in terms of vsnprintf, so they
// use the same attribute for compile-time format string checking. On Windows,
// if the mingw version of vsnprintf is used, use `gnu_printf' which allows z
// in %zd and PRIu64 (and related) to be recognized by the compile-time
// checking.
#define FORMAT_ARCHETYPE __printf__
#ifdef __USE_MINGW_ANSI_STDIO
#if __USE_MINGW_ANSI_STDIO
#undef FORMAT_ARCHETYPE
#define FORMAT_ARCHETYPE gnu_printf
#endif
#endif
// Returns a string corresponding to printf-like formatting of the arguments.
std::string StringPrintf(const char* fmt, ...)
__attribute__((__format__(FORMAT_ARCHETYPE, 1, 2)));
// Appends a printf-like formatting of the arguments to 'dst'.
void StringAppendF(std::string* dst, const char* fmt, ...)
__attribute__((__format__(FORMAT_ARCHETYPE, 2, 3)));
// Appends a printf-like formatting of the arguments to 'dst'.
void StringAppendV(std::string* dst, const char* format, va_list ap)
__attribute__((__format__(FORMAT_ARCHETYPE, 2, 0)));
#undef FORMAT_ARCHETYPE
} // namespace base
} // namespace android
#endif // ANDROID_BASE_STRINGPRINTF_H

View file

@ -0,0 +1,68 @@
/*
* Copyright (C) 2015 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.
*/
#ifndef ANDROID_BASE_STRINGS_H
#define ANDROID_BASE_STRINGS_H
#include <sstream>
#include <string>
#include <vector>
namespace android {
namespace base {
// Splits a string into a vector of strings.
//
// The string is split at each occurrence of a character in delimiters.
//
// The empty string is not a valid delimiter list.
std::vector<std::string> Split(const std::string& s,
const std::string& delimiters);
// Trims whitespace off both ends of the given string.
std::string Trim(const std::string& s);
// Joins a container of things into a single string, using the given separator.
template <typename ContainerT, typename SeparatorT>
std::string Join(const ContainerT& things, SeparatorT separator) {
if (things.empty()) {
return "";
}
std::ostringstream result;
result << *things.begin();
for (auto it = std::next(things.begin()); it != things.end(); ++it) {
result << separator << *it;
}
return result.str();
}
// We instantiate the common cases in strings.cpp.
extern template std::string Join(const std::vector<std::string>&, char);
extern template std::string Join(const std::vector<const char*>&, char);
extern template std::string Join(const std::vector<std::string>&, const std::string&);
extern template std::string Join(const std::vector<const char*>&, const std::string&);
// Tests whether 's' starts with 'prefix'.
bool StartsWith(const std::string& s, const char* prefix);
// Tests whether 's' ends with 'suffix'.
bool EndsWith(const std::string& s, const char* suffix);
} // namespace base
} // namespace android
#endif // ANDROID_BASE_STRINGS_H

View file

@ -0,0 +1,51 @@
/*
* Copyright (C) 2015 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.
*/
#ifndef ANDROID_BASE_TEST_UTILS_H
#define ANDROID_BASE_TEST_UTILS_H
#include <string>
#include <android-base/macros.h>
class TemporaryFile {
public:
TemporaryFile();
~TemporaryFile();
int fd;
char path[1024];
private:
void init(const std::string& tmp_dir);
DISALLOW_COPY_AND_ASSIGN(TemporaryFile);
};
class TemporaryDir {
public:
TemporaryDir();
~TemporaryDir();
char path[1024];
private:
bool init(const std::string& tmp_dir);
DISALLOW_COPY_AND_ASSIGN(TemporaryDir);
};
#endif // ANDROID_BASE_TEST_UTILS_H

View file

@ -0,0 +1,83 @@
/*
* Copyright (C) 2016 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.
*/
#ifndef ANDROID_BASE_THREAD_ANNOTATIONS_H
#define ANDROID_BASE_THREAD_ANNOTATIONS_H
#if defined(__SUPPORT_TS_ANNOTATION__) || defined(__clang__)
#define THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x))
#else
#define THREAD_ANNOTATION_ATTRIBUTE__(x) // no-op
#endif
#define CAPABILITY(x) \
THREAD_ANNOTATION_ATTRIBUTE__(capability(x))
#define SCOPED_CAPABILITY \
THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable)
#define GUARDED_BY(x) \
THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(x))
#define PT_GUARDED_BY(x) \
THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded_by(x))
#define ACQUIRED_BEFORE(...) \
THREAD_ANNOTATION_ATTRIBUTE__(acquired_before(__VA_ARGS__))
#define ACQUIRED_AFTER(...) \
THREAD_ANNOTATION_ATTRIBUTE__(acquired_after(__VA_ARGS__))
#define REQUIRES(...) \
THREAD_ANNOTATION_ATTRIBUTE__(requires_capability(__VA_ARGS__))
#define REQUIRES_SHARED(...) \
THREAD_ANNOTATION_ATTRIBUTE__(requires_shared_capability(__VA_ARGS__))
#define ACQUIRE(...) \
THREAD_ANNOTATION_ATTRIBUTE__(acquire_capability(__VA_ARGS__))
#define ACQUIRE_SHARED(...) \
THREAD_ANNOTATION_ATTRIBUTE__(acquire_shared_capability(__VA_ARGS__))
#define RELEASE(...) \
THREAD_ANNOTATION_ATTRIBUTE__(release_capability(__VA_ARGS__))
#define RELEASE_SHARED(...) \
THREAD_ANNOTATION_ATTRIBUTE__(release_shared_capability(__VA_ARGS__))
#define TRY_ACQUIRE(...) \
THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_capability(__VA_ARGS__))
#define TRY_ACQUIRE_SHARED(...) \
THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_shared_capability(__VA_ARGS__))
#define EXCLUDES(...) \
THREAD_ANNOTATION_ATTRIBUTE__(locks_excluded(__VA_ARGS__))
#define ASSERT_CAPABILITY(x) \
THREAD_ANNOTATION_ATTRIBUTE__(assert_capability(x))
#define ASSERT_SHARED_CAPABILITY(x) \
THREAD_ANNOTATION_ATTRIBUTE__(assert_shared_capability(x))
#define RETURN_CAPABILITY(x) \
THREAD_ANNOTATION_ATTRIBUTE__(lock_returned(x))
#define NO_THREAD_SAFETY_ANALYSIS \
THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis)
#endif // ANDROID_BASE_THREAD_ANNOTATIONS_H

View file

@ -0,0 +1,98 @@
/*
* Copyright (C) 2015 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.
*/
#ifndef ANDROID_BASE_UNIQUE_FD_H
#define ANDROID_BASE_UNIQUE_FD_H
#include <unistd.h>
// DO NOT INCLUDE OTHER LIBBASE HEADERS!
// This file gets used in libbinder, and libbinder is used everywhere.
// Including other headers from libbase frequently results in inclusion of
// android-base/macros.h, which causes macro collisions.
// Container for a file descriptor that automatically closes the descriptor as
// it goes out of scope.
//
// unique_fd ufd(open("/some/path", "r"));
// if (ufd.get() == -1) return error;
//
// // Do something useful, possibly including 'return'.
//
// return 0; // Descriptor is closed for you.
//
// unique_fd is also known as ScopedFd/ScopedFD/scoped_fd; mentioned here to help
// you find this class if you're searching for one of those names.
namespace android {
namespace base {
struct DefaultCloser {
static void Close(int fd) {
// Even if close(2) fails with EINTR, the fd will have been closed.
// Using TEMP_FAILURE_RETRY will either lead to EBADF or closing someone
// else's fd.
// http://lkml.indiana.edu/hypermail/linux/kernel/0509.1/0877.html
::close(fd);
}
};
template <typename Closer>
class unique_fd_impl final {
public:
unique_fd_impl() : value_(-1) {}
explicit unique_fd_impl(int value) : value_(value) {}
~unique_fd_impl() { clear(); }
unique_fd_impl(unique_fd_impl&& other) : value_(other.release()) {}
unique_fd_impl& operator=(unique_fd_impl&& s) {
reset(s.release());
return *this;
}
void reset(int new_value) {
if (value_ != -1) {
Closer::Close(value_);
}
value_ = new_value;
}
void clear() {
reset(-1);
}
int get() const { return value_; }
operator int() const { return get(); }
int release() __attribute__((warn_unused_result)) {
int ret = value_;
value_ = -1;
return ret;
}
private:
int value_;
unique_fd_impl(const unique_fd_impl&);
void operator=(const unique_fd_impl&);
};
using unique_fd = unique_fd_impl<DefaultCloser>;
} // namespace base
} // namespace android
#endif // ANDROID_BASE_UNIQUE_FD_H

View file

@ -0,0 +1,87 @@
/*
* Copyright (C) 2015 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.
*/
#ifndef ANDROID_BASE_UTF8_H
#define ANDROID_BASE_UTF8_H
#ifdef _WIN32
#include <string>
#else
// Bring in prototypes for standard APIs so that we can import them into the utf8 namespace.
#include <fcntl.h> // open
#include <unistd.h> // unlink
#endif
namespace android {
namespace base {
// Only available on Windows because this is only needed on Windows.
#ifdef _WIN32
// Convert size number of UTF-16 wchar_t's to UTF-8. Returns whether the
// conversion was done successfully.
bool WideToUTF8(const wchar_t* utf16, const size_t size, std::string* utf8);
// Convert a NULL-terminated string of UTF-16 characters to UTF-8. Returns
// whether the conversion was done successfully.
bool WideToUTF8(const wchar_t* utf16, std::string* utf8);
// Convert a UTF-16 std::wstring (including any embedded NULL characters) to
// UTF-8. Returns whether the conversion was done successfully.
bool WideToUTF8(const std::wstring& utf16, std::string* utf8);
// Convert size number of UTF-8 char's to UTF-16. Returns whether the conversion
// was done successfully.
bool UTF8ToWide(const char* utf8, const size_t size, std::wstring* utf16);
// Convert a NULL-terminated string of UTF-8 characters to UTF-16. Returns
// whether the conversion was done successfully.
bool UTF8ToWide(const char* utf8, std::wstring* utf16);
// Convert a UTF-8 std::string (including any embedded NULL characters) to
// UTF-16. Returns whether the conversion was done successfully.
bool UTF8ToWide(const std::string& utf8, std::wstring* utf16);
#endif
// The functions in the utf8 namespace take UTF-8 strings. For Windows, these
// are wrappers, for non-Windows these just expose existing APIs. To call these
// functions, use:
//
// // anonymous namespace to avoid conflict with existing open(), unlink(), etc.
// namespace {
// // Import functions into anonymous namespace.
// using namespace android::base::utf8;
//
// void SomeFunction(const char* name) {
// int fd = open(name, ...); // Calls android::base::utf8::open().
// ...
// unlink(name); // Calls android::base::utf8::unlink().
// }
// }
namespace utf8 {
#ifdef _WIN32
int open(const char* name, int flags, ...);
int unlink(const char* name);
#else
using ::open;
using ::unlink;
#endif
} // namespace utf8
} // namespace base
} // namespace android
#endif // ANDROID_BASE_UTF8_H

View file

@ -0,0 +1,428 @@
/*
* Copyright (C) 2015 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.
*/
#ifdef _WIN32
#include <windows.h>
#endif
#include "android-base/logging.h"
#include <libgen.h>
// For getprogname(3) or program_invocation_short_name.
#if defined(__ANDROID__) || defined(__APPLE__)
#include <stdlib.h>
#elif defined(__GLIBC__)
#include <errno.h>
#endif
#include <iostream>
#include <limits>
#include <sstream>
#include <string>
#include <utility>
#include <vector>
#ifndef _WIN32
#include <mutex>
#endif
#include "android-base/macros.h"
#include "android-base/strings.h"
#include "cutils/threads.h"
// Headers for LogMessage::LogLine.
#ifdef __ANDROID__
#include <android/set_abort_message.h>
#include "cutils/log.h"
#else
#include <sys/types.h>
#include <unistd.h>
#endif
// For gettid.
#if defined(__APPLE__)
#include "AvailabilityMacros.h" // For MAC_OS_X_VERSION_MAX_ALLOWED
#include <stdint.h>
#include <stdlib.h>
#include <sys/syscall.h>
#include <sys/time.h>
#include <unistd.h>
#elif defined(__linux__) && !defined(__ANDROID__)
#include <syscall.h>
#include <unistd.h>
#elif defined(_WIN32)
#include <windows.h>
#endif
#if defined(_WIN32)
typedef uint32_t thread_id;
#else
typedef pid_t thread_id;
#endif
static thread_id GetThreadId() {
#if defined(__BIONIC__)
return gettid();
#elif defined(__APPLE__)
return syscall(SYS_thread_selfid);
#elif defined(__linux__)
return syscall(__NR_gettid);
#elif defined(_WIN32)
return GetCurrentThreadId();
#endif
}
namespace {
#ifndef _WIN32
using std::mutex;
using std::lock_guard;
#if defined(__GLIBC__)
const char* getprogname() {
return program_invocation_short_name;
}
#endif
#else
const char* getprogname() {
static bool first = true;
static char progname[MAX_PATH] = {};
if (first) {
CHAR longname[MAX_PATH];
DWORD nchars = GetModuleFileNameA(nullptr, longname, arraysize(longname));
if ((nchars >= arraysize(longname)) || (nchars == 0)) {
// String truncation or some other error.
strcpy(progname, "<unknown>");
} else {
strcpy(progname, basename(longname));
}
first = false;
}
return progname;
}
class mutex {
public:
mutex() {
InitializeCriticalSection(&critical_section_);
}
~mutex() {
DeleteCriticalSection(&critical_section_);
}
void lock() {
EnterCriticalSection(&critical_section_);
}
void unlock() {
LeaveCriticalSection(&critical_section_);
}
private:
CRITICAL_SECTION critical_section_;
};
template <typename LockT>
class lock_guard {
public:
explicit lock_guard(LockT& lock) : lock_(lock) {
lock_.lock();
}
~lock_guard() {
lock_.unlock();
}
private:
LockT& lock_;
DISALLOW_COPY_AND_ASSIGN(lock_guard);
};
#endif
} // namespace
namespace android {
namespace base {
static auto& logging_lock = *new mutex();
#ifdef __ANDROID__
static auto& gLogger = *new LogFunction(LogdLogger());
#else
static auto& gLogger = *new LogFunction(StderrLogger);
#endif
static bool gInitialized = false;
static LogSeverity gMinimumLogSeverity = INFO;
static auto& gProgramInvocationName = *new std::unique_ptr<std::string>();
LogSeverity GetMinimumLogSeverity() {
return gMinimumLogSeverity;
}
static const char* ProgramInvocationName() {
if (gProgramInvocationName == nullptr) {
gProgramInvocationName.reset(new std::string(getprogname()));
}
return gProgramInvocationName->c_str();
}
void StderrLogger(LogId, LogSeverity severity, const char*, const char* file,
unsigned int line, const char* message) {
static const char log_characters[] = "VDIWEF";
static_assert(arraysize(log_characters) - 1 == FATAL + 1,
"Mismatch in size of log_characters and values in LogSeverity");
char severity_char = log_characters[severity];
fprintf(stderr, "%s %c %5d %5d %s:%u] %s\n", ProgramInvocationName(),
severity_char, getpid(), GetThreadId(), file, line, message);
}
#ifdef __ANDROID__
LogdLogger::LogdLogger(LogId default_log_id) : default_log_id_(default_log_id) {
}
static const android_LogPriority kLogSeverityToAndroidLogPriority[] = {
ANDROID_LOG_VERBOSE, ANDROID_LOG_DEBUG, ANDROID_LOG_INFO,
ANDROID_LOG_WARN, ANDROID_LOG_ERROR, ANDROID_LOG_FATAL,
};
static_assert(arraysize(kLogSeverityToAndroidLogPriority) == FATAL + 1,
"Mismatch in size of kLogSeverityToAndroidLogPriority and values "
"in LogSeverity");
static const log_id kLogIdToAndroidLogId[] = {
LOG_ID_MAX, LOG_ID_MAIN, LOG_ID_SYSTEM,
};
static_assert(arraysize(kLogIdToAndroidLogId) == SYSTEM + 1,
"Mismatch in size of kLogIdToAndroidLogId and values in LogId");
void LogdLogger::operator()(LogId id, LogSeverity severity, const char* tag,
const char* file, unsigned int line,
const char* message) {
int priority = kLogSeverityToAndroidLogPriority[severity];
if (id == DEFAULT) {
id = default_log_id_;
}
log_id lg_id = kLogIdToAndroidLogId[id];
if (priority == ANDROID_LOG_FATAL) {
__android_log_buf_print(lg_id, priority, tag, "%s:%u] %s", file, line,
message);
} else {
__android_log_buf_print(lg_id, priority, tag, "%s", message);
}
}
#endif
void InitLogging(char* argv[], LogFunction&& logger) {
SetLogger(std::forward<LogFunction>(logger));
InitLogging(argv);
}
void InitLogging(char* argv[]) {
if (gInitialized) {
return;
}
gInitialized = true;
// Stash the command line for later use. We can use /proc/self/cmdline on
// Linux to recover this, but we don't have that luxury on the Mac/Windows,
// and there are a couple of argv[0] variants that are commonly used.
if (argv != nullptr) {
gProgramInvocationName.reset(new std::string(basename(argv[0])));
}
const char* tags = getenv("ANDROID_LOG_TAGS");
if (tags == nullptr) {
return;
}
std::vector<std::string> specs = Split(tags, " ");
for (size_t i = 0; i < specs.size(); ++i) {
// "tag-pattern:[vdiwefs]"
std::string spec(specs[i]);
if (spec.size() == 3 && StartsWith(spec, "*:")) {
switch (spec[2]) {
case 'v':
gMinimumLogSeverity = VERBOSE;
continue;
case 'd':
gMinimumLogSeverity = DEBUG;
continue;
case 'i':
gMinimumLogSeverity = INFO;
continue;
case 'w':
gMinimumLogSeverity = WARNING;
continue;
case 'e':
gMinimumLogSeverity = ERROR;
continue;
case 'f':
gMinimumLogSeverity = FATAL;
continue;
// liblog will even suppress FATAL if you say 's' for silent, but that's
// crazy!
case 's':
gMinimumLogSeverity = FATAL;
continue;
}
}
LOG(FATAL) << "unsupported '" << spec << "' in ANDROID_LOG_TAGS (" << tags
<< ")";
}
}
void SetLogger(LogFunction&& logger) {
lock_guard<mutex> lock(logging_lock);
gLogger = std::move(logger);
}
static const char* GetFileBasename(const char* file) {
// We can't use basename(3) even on Unix because the Mac doesn't
// have a non-modifying basename.
const char* last_slash = strrchr(file, '/');
if (last_slash != nullptr) {
return last_slash + 1;
}
#if defined(_WIN32)
const char* last_backslash = strrchr(file, '\\');
if (last_backslash != nullptr) {
return last_backslash + 1;
}
#endif
return file;
}
// This indirection greatly reduces the stack impact of having lots of
// checks/logging in a function.
class LogMessageData {
public:
LogMessageData(const char* file, unsigned int line, LogId id,
LogSeverity severity, int error)
: file_(GetFileBasename(file)),
line_number_(line),
id_(id),
severity_(severity),
error_(error) {
}
const char* GetFile() const {
return file_;
}
unsigned int GetLineNumber() const {
return line_number_;
}
LogSeverity GetSeverity() const {
return severity_;
}
LogId GetId() const {
return id_;
}
int GetError() const {
return error_;
}
std::ostream& GetBuffer() {
return buffer_;
}
std::string ToString() const {
return buffer_.str();
}
private:
std::ostringstream buffer_;
const char* const file_;
const unsigned int line_number_;
const LogId id_;
const LogSeverity severity_;
const int error_;
DISALLOW_COPY_AND_ASSIGN(LogMessageData);
};
LogMessage::LogMessage(const char* file, unsigned int line, LogId id,
LogSeverity severity, int error)
: data_(new LogMessageData(file, line, id, severity, error)) {
}
LogMessage::~LogMessage() {
// Finish constructing the message.
if (data_->GetError() != -1) {
data_->GetBuffer() << ": " << strerror(data_->GetError());
}
std::string msg(data_->ToString());
{
// Do the actual logging with the lock held.
lock_guard<mutex> lock(logging_lock);
if (msg.find('\n') == std::string::npos) {
LogLine(data_->GetFile(), data_->GetLineNumber(), data_->GetId(),
data_->GetSeverity(), msg.c_str());
} else {
msg += '\n';
size_t i = 0;
while (i < msg.size()) {
size_t nl = msg.find('\n', i);
msg[nl] = '\0';
LogLine(data_->GetFile(), data_->GetLineNumber(), data_->GetId(),
data_->GetSeverity(), &msg[i]);
i = nl + 1;
}
}
}
// Abort if necessary.
if (data_->GetSeverity() == FATAL) {
#ifdef __ANDROID__
android_set_abort_message(msg.c_str());
#endif
abort();
}
}
std::ostream& LogMessage::stream() {
return data_->GetBuffer();
}
void LogMessage::LogLine(const char* file, unsigned int line, LogId id,
LogSeverity severity, const char* message) {
const char* tag = ProgramInvocationName();
gLogger(id, severity, tag, file, line, message);
}
ScopedLogSeverity::ScopedLogSeverity(LogSeverity level) {
old_ = gMinimumLogSeverity;
gMinimumLogSeverity = level;
}
ScopedLogSeverity::~ScopedLogSeverity() {
gMinimumLogSeverity = old_;
}
} // namespace base
} // namespace android

View file

@ -0,0 +1,281 @@
/*
* Copyright (C) 2015 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 "android-base/logging.h"
#include <libgen.h>
#if defined(_WIN32)
#include <signal.h>
#endif
#include <regex>
#include <string>
#include "android-base/file.h"
#include "android-base/stringprintf.h"
#include "android-base/test_utils.h"
#include <gtest/gtest.h>
#ifdef __ANDROID__
#define HOST_TEST(suite, name) TEST(suite, DISABLED_ ## name)
#else
#define HOST_TEST(suite, name) TEST(suite, name)
#endif
class CapturedStderr {
public:
CapturedStderr() : old_stderr_(-1) {
init();
}
~CapturedStderr() {
reset();
}
int fd() const {
return temp_file_.fd;
}
private:
void init() {
#if defined(_WIN32)
// On Windows, stderr is often buffered, so make sure it is unbuffered so
// that we can immediately read back what was written to stderr.
ASSERT_EQ(0, setvbuf(stderr, NULL, _IONBF, 0));
#endif
old_stderr_ = dup(STDERR_FILENO);
ASSERT_NE(-1, old_stderr_);
ASSERT_NE(-1, dup2(fd(), STDERR_FILENO));
}
void reset() {
ASSERT_NE(-1, dup2(old_stderr_, STDERR_FILENO));
ASSERT_EQ(0, close(old_stderr_));
// Note: cannot restore prior setvbuf() setting.
}
TemporaryFile temp_file_;
int old_stderr_;
};
#if defined(_WIN32)
static void ExitSignalAbortHandler(int) {
_exit(3);
}
#endif
static void SuppressAbortUI() {
#if defined(_WIN32)
// We really just want to call _set_abort_behavior(0, _CALL_REPORTFAULT) to
// suppress the Windows Error Reporting dialog box, but that API is not
// available in the OS-supplied C Runtime, msvcrt.dll, that we currently
// use (it is available in the Visual Studio C runtime).
//
// Instead, we setup a SIGABRT handler, which is called in abort() right
// before calling Windows Error Reporting. In the handler, we exit the
// process just like abort() does.
ASSERT_NE(SIG_ERR, signal(SIGABRT, ExitSignalAbortHandler));
#endif
}
TEST(logging, CHECK) {
ASSERT_DEATH({SuppressAbortUI(); CHECK(false);}, "Check failed: false ");
CHECK(true);
ASSERT_DEATH({SuppressAbortUI(); CHECK_EQ(0, 1);}, "Check failed: 0 == 1 ");
CHECK_EQ(0, 0);
ASSERT_DEATH({SuppressAbortUI(); CHECK_STREQ("foo", "bar");},
R"(Check failed: "foo" == "bar")");
CHECK_STREQ("foo", "foo");
// Test whether CHECK() and CHECK_STREQ() have a dangling if with no else.
bool flag = false;
if (true)
CHECK(true);
else
flag = true;
EXPECT_FALSE(flag) << "CHECK macro probably has a dangling if with no else";
flag = false;
if (true)
CHECK_STREQ("foo", "foo");
else
flag = true;
EXPECT_FALSE(flag) << "CHECK_STREQ probably has a dangling if with no else";
}
std::string make_log_pattern(android::base::LogSeverity severity,
const char* message) {
static const char* log_characters = "VDIWEF";
char log_char = log_characters[severity];
std::string holder(__FILE__);
return android::base::StringPrintf(
"%c[[:space:]]+[[:digit:]]+[[:space:]]+[[:digit:]]+ %s:[[:digit:]]+] %s",
log_char, basename(&holder[0]), message);
}
TEST(logging, LOG) {
ASSERT_DEATH({SuppressAbortUI(); LOG(FATAL) << "foobar";}, "foobar");
// We can't usefully check the output of any of these on Windows because we
// don't have std::regex, but we can at least make sure we printed at least as
// many characters are in the log message.
{
CapturedStderr cap;
LOG(WARNING) << "foobar";
ASSERT_EQ(0, lseek(cap.fd(), 0, SEEK_SET));
std::string output;
android::base::ReadFdToString(cap.fd(), &output);
ASSERT_GT(output.length(), strlen("foobar"));
#if !defined(_WIN32)
std::regex message_regex(
make_log_pattern(android::base::WARNING, "foobar"));
ASSERT_TRUE(std::regex_search(output, message_regex)) << output;
#endif
}
{
CapturedStderr cap;
LOG(INFO) << "foobar";
ASSERT_EQ(0, lseek(cap.fd(), 0, SEEK_SET));
std::string output;
android::base::ReadFdToString(cap.fd(), &output);
ASSERT_GT(output.length(), strlen("foobar"));
#if !defined(_WIN32)
std::regex message_regex(
make_log_pattern(android::base::INFO, "foobar"));
ASSERT_TRUE(std::regex_search(output, message_regex)) << output;
#endif
}
{
CapturedStderr cap;
LOG(DEBUG) << "foobar";
ASSERT_EQ(0, lseek(cap.fd(), 0, SEEK_SET));
std::string output;
android::base::ReadFdToString(cap.fd(), &output);
ASSERT_TRUE(output.empty());
}
{
android::base::ScopedLogSeverity severity(android::base::DEBUG);
CapturedStderr cap;
LOG(DEBUG) << "foobar";
ASSERT_EQ(0, lseek(cap.fd(), 0, SEEK_SET));
std::string output;
android::base::ReadFdToString(cap.fd(), &output);
ASSERT_GT(output.length(), strlen("foobar"));
#if !defined(_WIN32)
std::regex message_regex(
make_log_pattern(android::base::DEBUG, "foobar"));
ASSERT_TRUE(std::regex_search(output, message_regex)) << output;
#endif
}
// Test whether LOG() saves and restores errno.
{
CapturedStderr cap;
errno = 12345;
LOG(INFO) << (errno = 67890);
EXPECT_EQ(12345, errno) << "errno was not restored";
ASSERT_EQ(0, lseek(cap.fd(), 0, SEEK_SET));
std::string output;
android::base::ReadFdToString(cap.fd(), &output);
EXPECT_NE(nullptr, strstr(output.c_str(), "67890")) << output;
#if !defined(_WIN32)
std::regex message_regex(
make_log_pattern(android::base::INFO, "67890"));
ASSERT_TRUE(std::regex_search(output, message_regex)) << output;
#endif
}
// Test whether LOG() has a dangling if with no else.
{
CapturedStderr cap;
// Do the test two ways: once where we hypothesize that LOG()'s if
// will evaluate to true (when severity is high enough) and once when we
// expect it to evaluate to false (when severity is not high enough).
bool flag = false;
if (true)
LOG(INFO) << "foobar";
else
flag = true;
EXPECT_FALSE(flag) << "LOG macro probably has a dangling if with no else";
flag = false;
if (true)
LOG(VERBOSE) << "foobar";
else
flag = true;
EXPECT_FALSE(flag) << "LOG macro probably has a dangling if with no else";
}
}
TEST(logging, PLOG) {
{
CapturedStderr cap;
errno = ENOENT;
PLOG(INFO) << "foobar";
ASSERT_EQ(0, lseek(cap.fd(), 0, SEEK_SET));
std::string output;
android::base::ReadFdToString(cap.fd(), &output);
ASSERT_GT(output.length(), strlen("foobar"));
#if !defined(_WIN32)
std::regex message_regex(make_log_pattern(
android::base::INFO, "foobar: No such file or directory"));
ASSERT_TRUE(std::regex_search(output, message_regex)) << output;
#endif
}
}
TEST(logging, UNIMPLEMENTED) {
{
CapturedStderr cap;
errno = ENOENT;
UNIMPLEMENTED(ERROR);
ASSERT_EQ(0, lseek(cap.fd(), 0, SEEK_SET));
std::string output;
android::base::ReadFdToString(cap.fd(), &output);
ASSERT_GT(output.length(), strlen("unimplemented"));
#if !defined(_WIN32)
std::string expected_message =
android::base::StringPrintf("%s unimplemented ", __PRETTY_FUNCTION__);
std::regex message_regex(
make_log_pattern(android::base::ERROR, expected_message.c_str()));
ASSERT_TRUE(std::regex_search(output, message_regex)) << output;
#endif
}
}

View file

@ -0,0 +1,78 @@
/*
* Copyright (C) 2015 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 "android-base/parseint.h"
#include <gtest/gtest.h>
TEST(parseint, signed_smoke) {
int i;
ASSERT_FALSE(android::base::ParseInt("x", &i));
ASSERT_FALSE(android::base::ParseInt("123x", &i));
ASSERT_TRUE(android::base::ParseInt("123", &i));
ASSERT_EQ(123, i);
ASSERT_TRUE(android::base::ParseInt("-123", &i));
ASSERT_EQ(-123, i);
short s;
ASSERT_TRUE(android::base::ParseInt("1234", &s));
ASSERT_EQ(1234, s);
ASSERT_TRUE(android::base::ParseInt("12", &i, 0, 15));
ASSERT_EQ(12, i);
ASSERT_FALSE(android::base::ParseInt("-12", &i, 0, 15));
ASSERT_FALSE(android::base::ParseInt("16", &i, 0, 15));
}
TEST(parseint, unsigned_smoke) {
unsigned int i;
ASSERT_FALSE(android::base::ParseUint("x", &i));
ASSERT_FALSE(android::base::ParseUint("123x", &i));
ASSERT_TRUE(android::base::ParseUint("123", &i));
ASSERT_EQ(123u, i);
ASSERT_FALSE(android::base::ParseUint("-123", &i));
unsigned short s;
ASSERT_TRUE(android::base::ParseUint("1234", &s));
ASSERT_EQ(1234u, s);
ASSERT_TRUE(android::base::ParseUint("12", &i, 15u));
ASSERT_EQ(12u, i);
ASSERT_FALSE(android::base::ParseUint("-12", &i, 15u));
ASSERT_FALSE(android::base::ParseUint("16", &i, 15u));
}
TEST(parseint, no_implicit_octal) {
int i;
ASSERT_TRUE(android::base::ParseInt("0123", &i));
ASSERT_EQ(123, i);
unsigned int u;
ASSERT_TRUE(android::base::ParseUint("0123", &u));
ASSERT_EQ(123u, u);
}
TEST(parseint, explicit_hex) {
int i;
ASSERT_TRUE(android::base::ParseInt("0x123", &i));
ASSERT_EQ(0x123, i);
unsigned int u;
ASSERT_TRUE(android::base::ParseUint("0x123", &u));
ASSERT_EQ(0x123u, u);
}

View file

@ -0,0 +1,82 @@
/*
* Copyright (C) 2016 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 "android-base/parsenetaddress.h"
#include <algorithm>
#include "android-base/stringprintf.h"
#include "android-base/strings.h"
namespace android {
namespace base {
bool ParseNetAddress(const std::string& address, std::string* host, int* port,
std::string* canonical_address, std::string* error) {
host->clear();
bool ipv6 = true;
bool saw_port = false;
size_t colons = std::count(address.begin(), address.end(), ':');
size_t dots = std::count(address.begin(), address.end(), '.');
std::string port_str;
if (address[0] == '[') {
// [::1]:123
if (address.rfind("]:") == std::string::npos) {
*error = StringPrintf("bad IPv6 address '%s'", address.c_str());
return false;
}
*host = address.substr(1, (address.find("]:") - 1));
port_str = address.substr(address.rfind("]:") + 2);
saw_port = true;
} else if (dots == 0 && colons >= 2 && colons <= 7) {
// ::1
*host = address;
} else if (colons <= 1) {
// 1.2.3.4 or some.accidental.domain.com
ipv6 = false;
std::vector<std::string> pieces = Split(address, ":");
*host = pieces[0];
if (pieces.size() > 1) {
port_str = pieces[1];
saw_port = true;
}
}
if (host->empty()) {
*error = StringPrintf("no host in '%s'", address.c_str());
return false;
}
if (saw_port) {
if (sscanf(port_str.c_str(), "%d", port) != 1 || *port <= 0 ||
*port > 65535) {
*error = StringPrintf("bad port number '%s' in '%s'", port_str.c_str(),
address.c_str());
return false;
}
}
if (canonical_address != nullptr) {
*canonical_address =
StringPrintf(ipv6 ? "[%s]:%d" : "%s:%d", host->c_str(), *port);
}
return true;
}
} // namespace base
} // namespace android

View file

@ -0,0 +1,127 @@
/*
* Copyright (C) 2016 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 "android-base/parsenetaddress.h"
#include <gtest/gtest.h>
using android::base::ParseNetAddress;
TEST(ParseNetAddressTest, TestUrl) {
std::string canonical, host, error;
int port = 123;
EXPECT_TRUE(
ParseNetAddress("www.google.com", &host, &port, &canonical, &error));
EXPECT_EQ("www.google.com:123", canonical);
EXPECT_EQ("www.google.com", host);
EXPECT_EQ(123, port);
EXPECT_TRUE(
ParseNetAddress("www.google.com:666", &host, &port, &canonical, &error));
EXPECT_EQ("www.google.com:666", canonical);
EXPECT_EQ("www.google.com", host);
EXPECT_EQ(666, port);
}
TEST(ParseNetAddressTest, TestIpv4) {
std::string canonical, host, error;
int port = 123;
EXPECT_TRUE(ParseNetAddress("1.2.3.4", &host, &port, &canonical, &error));
EXPECT_EQ("1.2.3.4:123", canonical);
EXPECT_EQ("1.2.3.4", host);
EXPECT_EQ(123, port);
EXPECT_TRUE(ParseNetAddress("1.2.3.4:666", &host, &port, &canonical, &error));
EXPECT_EQ("1.2.3.4:666", canonical);
EXPECT_EQ("1.2.3.4", host);
EXPECT_EQ(666, port);
}
TEST(ParseNetAddressTest, TestIpv6) {
std::string canonical, host, error;
int port = 123;
EXPECT_TRUE(ParseNetAddress("::1", &host, &port, &canonical, &error));
EXPECT_EQ("[::1]:123", canonical);
EXPECT_EQ("::1", host);
EXPECT_EQ(123, port);
EXPECT_TRUE(ParseNetAddress("fe80::200:5aee:feaa:20a2", &host, &port,
&canonical, &error));
EXPECT_EQ("[fe80::200:5aee:feaa:20a2]:123", canonical);
EXPECT_EQ("fe80::200:5aee:feaa:20a2", host);
EXPECT_EQ(123, port);
EXPECT_TRUE(ParseNetAddress("[::1]:666", &host, &port, &canonical, &error));
EXPECT_EQ("[::1]:666", canonical);
EXPECT_EQ("::1", host);
EXPECT_EQ(666, port);
EXPECT_TRUE(ParseNetAddress("[fe80::200:5aee:feaa:20a2]:666", &host, &port,
&canonical, &error));
EXPECT_EQ("[fe80::200:5aee:feaa:20a2]:666", canonical);
EXPECT_EQ("fe80::200:5aee:feaa:20a2", host);
EXPECT_EQ(666, port);
}
TEST(ParseNetAddressTest, TestInvalidAddress) {
std::string canonical, host;
int port;
std::string failure_cases[] = {
// Invalid IPv4.
"1.2.3.4:",
"1.2.3.4::",
":123",
// Invalid IPv6.
":1",
"::::::::1",
"[::1",
"[::1]",
"[::1]:",
"[::1]::",
// Invalid port.
"1.2.3.4:-1",
"1.2.3.4:0",
"1.2.3.4:65536"
"1.2.3.4:hello",
"[::1]:-1",
"[::1]:0",
"[::1]:65536",
"[::1]:hello",
};
for (const auto& address : failure_cases) {
// Failure should give some non-empty error string.
std::string error;
EXPECT_FALSE(ParseNetAddress(address, &host, &port, &canonical, &error));
EXPECT_NE("", error);
}
}
// Null canonical address argument.
TEST(ParseNetAddressTest, TestNullCanonicalAddress) {
std::string host, error;
int port = 42;
EXPECT_TRUE(ParseNetAddress("www.google.com", &host, &port, nullptr, &error));
EXPECT_TRUE(ParseNetAddress("1.2.3.4", &host, &port, nullptr, &error));
EXPECT_TRUE(ParseNetAddress("::1", &host, &port, nullptr, &error));
}

View file

@ -0,0 +1,85 @@
/*
* Copyright (C) 2011 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 "android-base/stringprintf.h"
#include <stdio.h>
#include <string>
namespace android {
namespace base {
void StringAppendV(std::string* dst, const char* format, va_list ap) {
// First try with a small fixed size buffer
char space[1024];
// It's possible for methods that use a va_list to invalidate
// the data in it upon use. The fix is to make a copy
// of the structure before using it and use that copy instead.
va_list backup_ap;
va_copy(backup_ap, ap);
int result = vsnprintf(space, sizeof(space), format, backup_ap);
va_end(backup_ap);
if (result < static_cast<int>(sizeof(space))) {
if (result >= 0) {
// Normal case -- everything fit.
dst->append(space, result);
return;
}
if (result < 0) {
// Just an error.
return;
}
}
// Increase the buffer size to the size requested by vsnprintf,
// plus one for the closing \0.
int length = result + 1;
char* buf = new char[length];
// Restore the va_list before we use it again
va_copy(backup_ap, ap);
result = vsnprintf(buf, length, format, backup_ap);
va_end(backup_ap);
if (result >= 0 && result < length) {
// It fit
dst->append(buf, result);
}
delete[] buf;
}
std::string StringPrintf(const char* fmt, ...) {
va_list ap;
va_start(ap, fmt);
std::string result;
StringAppendV(&result, fmt, ap);
va_end(ap);
return result;
}
void StringAppendF(std::string* dst, const char* format, ...) {
va_list ap;
va_start(ap, format);
StringAppendV(dst, format, ap);
va_end(ap);
}
} // namespace base
} // namespace android

View file

@ -0,0 +1,60 @@
/*
* Copyright (C) 2011 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 "android-base/stringprintf.h"
#include <gtest/gtest.h>
#include <string>
TEST(StringPrintfTest, HexSizeT) {
size_t size = 0x00107e59;
EXPECT_EQ("00107e59", android::base::StringPrintf("%08zx", size));
EXPECT_EQ("0x00107e59", android::base::StringPrintf("0x%08zx", size));
}
TEST(StringPrintfTest, StringAppendF) {
std::string s("a");
android::base::StringAppendF(&s, "b");
EXPECT_EQ("ab", s);
}
TEST(StringPrintfTest, Errno) {
errno = 123;
android::base::StringPrintf("hello %s", "world");
EXPECT_EQ(123, errno);
}
void TestN(size_t n) {
char* buf = new char[n + 1];
memset(buf, 'x', n);
buf[n] = '\0';
std::string s(android::base::StringPrintf("%s", buf));
EXPECT_EQ(buf, s);
delete[] buf;
}
TEST(StringPrintfTest, At1023) {
TestN(1023);
}
TEST(StringPrintfTest, At1024) {
TestN(1024);
}
TEST(StringPrintfTest, At1025) {
TestN(1025);
}

View file

@ -0,0 +1,104 @@
/*
* Copyright (C) 2015 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 "android-base/strings.h"
#include <stdlib.h>
#include <string.h>
#include <string>
#include <vector>
namespace android {
namespace base {
#define CHECK_NE(a, b) \
if ((a) == (b)) abort();
std::vector<std::string> Split(const std::string& s,
const std::string& delimiters) {
CHECK_NE(delimiters.size(), 0U);
std::vector<std::string> result;
size_t base = 0;
size_t found;
do {
found = s.find_first_of(delimiters, base);
result.push_back(s.substr(base, found - base));
base = found + 1;
} while (found != s.npos);
return result;
}
std::string Trim(const std::string& s) {
std::string result;
if (s.size() == 0) {
return result;
}
size_t start_index = 0;
size_t end_index = s.size() - 1;
// Skip initial whitespace.
while (start_index < s.size()) {
if (!isspace(s[start_index])) {
break;
}
start_index++;
}
// Skip terminating whitespace.
while (end_index >= start_index) {
if (!isspace(s[end_index])) {
break;
}
end_index--;
}
// All spaces, no beef.
if (end_index < start_index) {
return "";
}
// Start_index is the first non-space, end_index is the last one.
return s.substr(start_index, end_index - start_index + 1);
}
// These cases are probably the norm, so we mark them extern in the header to
// aid compile time and binary size.
template std::string Join(const std::vector<std::string>&, char);
template std::string Join(const std::vector<const char*>&, char);
template std::string Join(const std::vector<std::string>&, const std::string&);
template std::string Join(const std::vector<const char*>&, const std::string&);
bool StartsWith(const std::string& s, const char* prefix) {
return s.compare(0, strlen(prefix), prefix) == 0;
}
bool EndsWith(const std::string& s, const char* suffix) {
size_t suffix_length = strlen(suffix);
size_t string_length = s.size();
if (suffix_length > string_length) {
return false;
}
size_t offset = string_length - suffix_length;
return s.compare(offset, suffix_length, suffix) == 0;
}
} // namespace base
} // namespace android

View file

@ -0,0 +1,177 @@
/*
* Copyright (C) 2015 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 "android-base/strings.h"
#include <gtest/gtest.h>
#include <string>
#include <vector>
#include <set>
#include <unordered_set>
TEST(strings, split_empty) {
std::vector<std::string> parts = android::base::Split("", ",");
ASSERT_EQ(1U, parts.size());
ASSERT_EQ("", parts[0]);
}
TEST(strings, split_single) {
std::vector<std::string> parts = android::base::Split("foo", ",");
ASSERT_EQ(1U, parts.size());
ASSERT_EQ("foo", parts[0]);
}
TEST(strings, split_simple) {
std::vector<std::string> parts = android::base::Split("foo,bar,baz", ",");
ASSERT_EQ(3U, parts.size());
ASSERT_EQ("foo", parts[0]);
ASSERT_EQ("bar", parts[1]);
ASSERT_EQ("baz", parts[2]);
}
TEST(strings, split_with_empty_part) {
std::vector<std::string> parts = android::base::Split("foo,,bar", ",");
ASSERT_EQ(3U, parts.size());
ASSERT_EQ("foo", parts[0]);
ASSERT_EQ("", parts[1]);
ASSERT_EQ("bar", parts[2]);
}
TEST(strings, split_null_char) {
std::vector<std::string> parts =
android::base::Split(std::string("foo\0bar", 7), std::string("\0", 1));
ASSERT_EQ(2U, parts.size());
ASSERT_EQ("foo", parts[0]);
ASSERT_EQ("bar", parts[1]);
}
TEST(strings, split_any) {
std::vector<std::string> parts = android::base::Split("foo:bar,baz", ",:");
ASSERT_EQ(3U, parts.size());
ASSERT_EQ("foo", parts[0]);
ASSERT_EQ("bar", parts[1]);
ASSERT_EQ("baz", parts[2]);
}
TEST(strings, split_any_with_empty_part) {
std::vector<std::string> parts = android::base::Split("foo:,bar", ",:");
ASSERT_EQ(3U, parts.size());
ASSERT_EQ("foo", parts[0]);
ASSERT_EQ("", parts[1]);
ASSERT_EQ("bar", parts[2]);
}
TEST(strings, trim_empty) {
ASSERT_EQ("", android::base::Trim(""));
}
TEST(strings, trim_already_trimmed) {
ASSERT_EQ("foo", android::base::Trim("foo"));
}
TEST(strings, trim_left) {
ASSERT_EQ("foo", android::base::Trim(" foo"));
}
TEST(strings, trim_right) {
ASSERT_EQ("foo", android::base::Trim("foo "));
}
TEST(strings, trim_both) {
ASSERT_EQ("foo", android::base::Trim(" foo "));
}
TEST(strings, trim_no_trim_middle) {
ASSERT_EQ("foo bar", android::base::Trim("foo bar"));
}
TEST(strings, trim_other_whitespace) {
ASSERT_EQ("foo", android::base::Trim("\v\tfoo\n\f"));
}
TEST(strings, join_nothing) {
std::vector<std::string> list = {};
ASSERT_EQ("", android::base::Join(list, ','));
}
TEST(strings, join_single) {
std::vector<std::string> list = {"foo"};
ASSERT_EQ("foo", android::base::Join(list, ','));
}
TEST(strings, join_simple) {
std::vector<std::string> list = {"foo", "bar", "baz"};
ASSERT_EQ("foo,bar,baz", android::base::Join(list, ','));
}
TEST(strings, join_separator_in_vector) {
std::vector<std::string> list = {",", ","};
ASSERT_EQ(",,,", android::base::Join(list, ','));
}
TEST(strings, join_simple_ints) {
std::set<int> list = {1, 2, 3};
ASSERT_EQ("1,2,3", android::base::Join(list, ','));
}
TEST(strings, join_unordered_set) {
std::unordered_set<int> list = {1, 2};
ASSERT_TRUE("1,2" == android::base::Join(list, ',') ||
"2,1" == android::base::Join(list, ','));
}
TEST(strings, startswith_empty) {
ASSERT_FALSE(android::base::StartsWith("", "foo"));
ASSERT_TRUE(android::base::StartsWith("", ""));
}
TEST(strings, startswith_simple) {
ASSERT_TRUE(android::base::StartsWith("foo", ""));
ASSERT_TRUE(android::base::StartsWith("foo", "f"));
ASSERT_TRUE(android::base::StartsWith("foo", "fo"));
ASSERT_TRUE(android::base::StartsWith("foo", "foo"));
}
TEST(strings, startswith_prefix_too_long) {
ASSERT_FALSE(android::base::StartsWith("foo", "foobar"));
}
TEST(strings, startswith_contains_prefix) {
ASSERT_FALSE(android::base::StartsWith("foobar", "oba"));
ASSERT_FALSE(android::base::StartsWith("foobar", "bar"));
}
TEST(strings, endswith_empty) {
ASSERT_FALSE(android::base::EndsWith("", "foo"));
ASSERT_TRUE(android::base::EndsWith("", ""));
}
TEST(strings, endswith_simple) {
ASSERT_TRUE(android::base::EndsWith("foo", ""));
ASSERT_TRUE(android::base::EndsWith("foo", "o"));
ASSERT_TRUE(android::base::EndsWith("foo", "oo"));
ASSERT_TRUE(android::base::EndsWith("foo", "foo"));
}
TEST(strings, endswith_prefix_too_long) {
ASSERT_FALSE(android::base::EndsWith("foo", "foobar"));
}
TEST(strings, endswith_contains_prefix) {
ASSERT_FALSE(android::base::EndsWith("foobar", "oba"));
ASSERT_FALSE(android::base::EndsWith("foobar", "foo"));
}

View file

@ -0,0 +1,25 @@
/*
* Copyright (C) 2015 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 <gtest/gtest.h>
#include "android-base/logging.h"
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
android::base::InitLogging(argv, android::base::StderrLogger);
return RUN_ALL_TESTS();
}

View file

@ -0,0 +1,102 @@
/*
* Copyright (C) 2015 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 "android-base/logging.h"
#include "android-base/test_utils.h"
#include "utils/Compat.h" // For OS_PATH_SEPARATOR.
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <unistd.h>
#if defined(_WIN32)
#include <windows.h>
#include <direct.h>
#endif
#include <string>
#ifdef _WIN32
int mkstemp(char* template_name) {
if (_mktemp(template_name) == nullptr) {
return -1;
}
// Use open() to match the close() that TemporaryFile's destructor does.
// Use O_BINARY to match base file APIs.
return open(template_name, O_CREAT | O_EXCL | O_RDWR | O_BINARY,
S_IRUSR | S_IWUSR);
}
char* mkdtemp(char* template_name) {
if (_mktemp(template_name) == nullptr) {
return nullptr;
}
if (_mkdir(template_name) == -1) {
return nullptr;
}
return template_name;
}
#endif
static std::string GetSystemTempDir() {
#if defined(__ANDROID__)
return "/data/local/tmp";
#elif defined(_WIN32)
char tmp_dir[MAX_PATH];
DWORD result = GetTempPathA(sizeof(tmp_dir), tmp_dir);
CHECK_NE(result, 0ul) << "GetTempPathA failed, error: " << GetLastError();
CHECK_LT(result, sizeof(tmp_dir)) << "path truncated to: " << result;
// GetTempPath() returns a path with a trailing slash, but init()
// does not expect that, so remove it.
CHECK_EQ(tmp_dir[result - 1], '\\');
tmp_dir[result - 1] = '\0';
return tmp_dir;
#else
return "/tmp";
#endif
}
TemporaryFile::TemporaryFile() {
init(GetSystemTempDir());
}
TemporaryFile::~TemporaryFile() {
close(fd);
unlink(path);
}
void TemporaryFile::init(const std::string& tmp_dir) {
snprintf(path, sizeof(path), "%s%cTemporaryFile-XXXXXX", tmp_dir.c_str(),
OS_PATH_SEPARATOR);
fd = mkstemp(path);
}
TemporaryDir::TemporaryDir() {
init(GetSystemTempDir());
}
TemporaryDir::~TemporaryDir() {
rmdir(path);
}
bool TemporaryDir::init(const std::string& tmp_dir) {
snprintf(path, sizeof(path), "%s%cTemporaryDir-XXXXXX", tmp_dir.c_str(),
OS_PATH_SEPARATOR);
return (mkdtemp(path) != nullptr);
}

View file

@ -0,0 +1,187 @@
/*
* Copyright (C) 2015 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 <windows.h>
#include "android-base/utf8.h"
#include <fcntl.h>
#include <string>
#include "android-base/logging.h"
namespace android {
namespace base {
// Helper to set errno based on GetLastError() after WideCharToMultiByte()/MultiByteToWideChar().
static void SetErrnoFromLastError() {
switch (GetLastError()) {
case ERROR_NO_UNICODE_TRANSLATION:
errno = EILSEQ;
break;
default:
errno = EINVAL;
break;
}
}
bool WideToUTF8(const wchar_t* utf16, const size_t size, std::string* utf8) {
utf8->clear();
if (size == 0) {
return true;
}
// TODO: Consider using std::wstring_convert once libcxx is supported on
// Windows.
// Only Vista or later has this flag that causes WideCharToMultiByte() to
// return an error on invalid characters.
const DWORD flags =
#if (WINVER >= 0x0600)
WC_ERR_INVALID_CHARS;
#else
0;
#endif
const int chars_required = WideCharToMultiByte(CP_UTF8, flags, utf16, size,
NULL, 0, NULL, NULL);
if (chars_required <= 0) {
SetErrnoFromLastError();
return false;
}
// This could potentially throw a std::bad_alloc exception.
utf8->resize(chars_required);
const int result = WideCharToMultiByte(CP_UTF8, flags, utf16, size,
&(*utf8)[0], chars_required, NULL,
NULL);
if (result != chars_required) {
SetErrnoFromLastError();
CHECK_LE(result, chars_required) << "WideCharToMultiByte wrote " << result
<< " chars to buffer of " << chars_required << " chars";
utf8->clear();
return false;
}
return true;
}
bool WideToUTF8(const wchar_t* utf16, std::string* utf8) {
// Compute string length of NULL-terminated string with wcslen().
return WideToUTF8(utf16, wcslen(utf16), utf8);
}
bool WideToUTF8(const std::wstring& utf16, std::string* utf8) {
// Use the stored length of the string which allows embedded NULL characters
// to be converted.
return WideToUTF8(utf16.c_str(), utf16.length(), utf8);
}
// Internal helper function that takes MultiByteToWideChar() flags.
static bool UTF8ToWideWithFlags(const char* utf8, const size_t size, std::wstring* utf16,
const DWORD flags) {
utf16->clear();
if (size == 0) {
return true;
}
// TODO: Consider using std::wstring_convert once libcxx is supported on
// Windows.
const int chars_required = MultiByteToWideChar(CP_UTF8, flags, utf8, size,
NULL, 0);
if (chars_required <= 0) {
SetErrnoFromLastError();
return false;
}
// This could potentially throw a std::bad_alloc exception.
utf16->resize(chars_required);
const int result = MultiByteToWideChar(CP_UTF8, flags, utf8, size,
&(*utf16)[0], chars_required);
if (result != chars_required) {
SetErrnoFromLastError();
CHECK_LE(result, chars_required) << "MultiByteToWideChar wrote " << result
<< " chars to buffer of " << chars_required << " chars";
utf16->clear();
return false;
}
return true;
}
bool UTF8ToWide(const char* utf8, const size_t size, std::wstring* utf16) {
// If strictly interpreting as UTF-8 succeeds, return success.
if (UTF8ToWideWithFlags(utf8, size, utf16, MB_ERR_INVALID_CHARS)) {
return true;
}
const int saved_errno = errno;
// Fallback to non-strict interpretation, allowing invalid characters and
// converting as best as possible, and return false to signify a problem.
(void)UTF8ToWideWithFlags(utf8, size, utf16, 0);
errno = saved_errno;
return false;
}
bool UTF8ToWide(const char* utf8, std::wstring* utf16) {
// Compute string length of NULL-terminated string with strlen().
return UTF8ToWide(utf8, strlen(utf8), utf16);
}
bool UTF8ToWide(const std::string& utf8, std::wstring* utf16) {
// Use the stored length of the string which allows embedded NULL characters
// to be converted.
return UTF8ToWide(utf8.c_str(), utf8.length(), utf16);
}
// Versions of standard library APIs that support UTF-8 strings.
namespace utf8 {
int open(const char* name, int flags, ...) {
std::wstring name_utf16;
if (!UTF8ToWide(name, &name_utf16)) {
return -1;
}
int mode = 0;
if ((flags & O_CREAT) != 0) {
va_list args;
va_start(args, flags);
mode = va_arg(args, int);
va_end(args);
}
return _wopen(name_utf16.c_str(), flags, mode);
}
int unlink(const char* name) {
std::wstring name_utf16;
if (!UTF8ToWide(name, &name_utf16)) {
return -1;
}
return _wunlink(name_utf16.c_str());
}
} // namespace utf8
} // namespace base
} // namespace android

View file

@ -0,0 +1,412 @@
/*
* Copyright (C) 2015 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 "android-base/utf8.h"
#include <gtest/gtest.h>
#include "android-base/macros.h"
namespace android {
namespace base {
TEST(UTFStringConversionsTest, ConvertInvalidUTF8) {
std::wstring wide;
errno = 0;
// Standalone \xa2 is an invalid UTF-8 sequence, so this should return an
// error. Concatenate two C/C++ literal string constants to prevent the
// compiler from giving an error about "\xa2af" containing a "hex escape
// sequence out of range".
EXPECT_FALSE(android::base::UTF8ToWide("before\xa2" "after", &wide));
EXPECT_EQ(EILSEQ, errno);
// Even if an invalid character is encountered, UTF8ToWide() should still do
// its best to convert the rest of the string. sysdeps_win32.cpp:
// _console_write_utf8() depends on this behavior.
//
// Thus, we verify that the valid characters are converted, but we ignore the
// specific replacement character that UTF8ToWide() may replace the invalid
// UTF-8 characters with because we want to allow that to change if the
// implementation changes.
EXPECT_EQ(0U, wide.find(L"before"));
const wchar_t after_wide[] = L"after";
EXPECT_EQ(wide.length() - (arraysize(after_wide) - 1), wide.find(after_wide));
}
// Below is adapted from https://chromium.googlesource.com/chromium/src/+/master/base/strings/utf_string_conversions_unittest.cc
// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// The tests below from utf_string_conversions_unittest.cc check for this
// preprocessor symbol, so define it, as it is appropriate for Windows.
#define WCHAR_T_IS_UTF16
static_assert(sizeof(wchar_t) == 2, "wchar_t is not 2 bytes");
// The tests below from utf_string_conversions_unittest.cc call versions of
// UTF8ToWide() and WideToUTF8() that don't return success/failure, so these are
// stub implementations with that signature. These are just for testing and
// should not be moved to base because they assert/expect no errors which is
// probably not a good idea (or at least it is something that should be left
// up to the caller, not a base library).
static std::wstring UTF8ToWide(const std::string& utf8) {
std::wstring utf16;
EXPECT_TRUE(UTF8ToWide(utf8, &utf16));
return utf16;
}
static std::string WideToUTF8(const std::wstring& utf16) {
std::string utf8;
EXPECT_TRUE(WideToUTF8(utf16, &utf8));
return utf8;
}
namespace {
const wchar_t* const kConvertRoundtripCases[] = {
L"Google Video",
// "网页 图片 资讯更多 »"
L"\x7f51\x9875\x0020\x56fe\x7247\x0020\x8d44\x8baf\x66f4\x591a\x0020\x00bb",
// "Παγκόσμιος Ιστός"
L"\x03a0\x03b1\x03b3\x03ba\x03cc\x03c3\x03bc\x03b9"
L"\x03bf\x03c2\x0020\x0399\x03c3\x03c4\x03cc\x03c2",
// "Поиск страниц на русском"
L"\x041f\x043e\x0438\x0441\x043a\x0020\x0441\x0442"
L"\x0440\x0430\x043d\x0438\x0446\x0020\x043d\x0430"
L"\x0020\x0440\x0443\x0441\x0441\x043a\x043e\x043c",
// "전체서비스"
L"\xc804\xccb4\xc11c\xbe44\xc2a4",
// Test characters that take more than 16 bits. This will depend on whether
// wchar_t is 16 or 32 bits.
#if defined(WCHAR_T_IS_UTF16)
L"\xd800\xdf00",
// ????? (Mathematical Alphanumeric Symbols (U+011d40 - U+011d44 : A,B,C,D,E)
L"\xd807\xdd40\xd807\xdd41\xd807\xdd42\xd807\xdd43\xd807\xdd44",
#elif defined(WCHAR_T_IS_UTF32)
L"\x10300",
// ????? (Mathematical Alphanumeric Symbols (U+011d40 - U+011d44 : A,B,C,D,E)
L"\x11d40\x11d41\x11d42\x11d43\x11d44",
#endif
};
} // namespace
TEST(UTFStringConversionsTest, ConvertUTF8AndWide) {
// we round-trip all the wide strings through UTF-8 to make sure everything
// agrees on the conversion. This uses the stream operators to test them
// simultaneously.
for (size_t i = 0; i < arraysize(kConvertRoundtripCases); ++i) {
std::ostringstream utf8;
utf8 << WideToUTF8(kConvertRoundtripCases[i]);
std::wostringstream wide;
wide << UTF8ToWide(utf8.str());
EXPECT_EQ(kConvertRoundtripCases[i], wide.str());
}
}
TEST(UTFStringConversionsTest, ConvertUTF8AndWideEmptyString) {
// An empty std::wstring should be converted to an empty std::string,
// and vice versa.
std::wstring wempty;
std::string empty;
EXPECT_EQ(empty, WideToUTF8(wempty));
EXPECT_EQ(wempty, UTF8ToWide(empty));
}
TEST(UTFStringConversionsTest, ConvertUTF8ToWide) {
struct UTF8ToWideCase {
const char* utf8;
const wchar_t* wide;
bool success;
} convert_cases[] = {
// Regular UTF-8 input.
{"\xe4\xbd\xa0\xe5\xa5\xbd", L"\x4f60\x597d", true},
// Non-character is passed through.
{"\xef\xbf\xbfHello", L"\xffffHello", true},
// Truncated UTF-8 sequence.
{"\xe4\xa0\xe5\xa5\xbd", L"\xfffd\x597d", false},
// Truncated off the end.
{"\xe5\xa5\xbd\xe4\xa0", L"\x597d\xfffd", false},
// Non-shortest-form UTF-8.
{"\xf0\x84\xbd\xa0\xe5\xa5\xbd", L"\xfffd\x597d", false},
// This UTF-8 character decodes to a UTF-16 surrogate, which is illegal.
// Note that for whatever reason, this test fails on Windows XP.
{"\xed\xb0\x80", L"\xfffd", false},
// Non-BMP characters. The second is a non-character regarded as valid.
// The result will either be in UTF-16 or UTF-32.
#if defined(WCHAR_T_IS_UTF16)
{"A\xF0\x90\x8C\x80z", L"A\xd800\xdf00z", true},
{"A\xF4\x8F\xBF\xBEz", L"A\xdbff\xdffez", true},
#elif defined(WCHAR_T_IS_UTF32)
{"A\xF0\x90\x8C\x80z", L"A\x10300z", true},
{"A\xF4\x8F\xBF\xBEz", L"A\x10fffez", true},
#endif
};
for (size_t i = 0; i < arraysize(convert_cases); i++) {
std::wstring converted;
errno = 0;
const bool success = UTF8ToWide(convert_cases[i].utf8,
strlen(convert_cases[i].utf8),
&converted);
EXPECT_EQ(convert_cases[i].success, success);
// The original test always compared expected and converted, but don't do
// that because our implementation of UTF8ToWide() does not guarantee to
// produce the same output in error situations.
if (success) {
std::wstring expected(convert_cases[i].wide);
EXPECT_EQ(expected, converted);
} else {
EXPECT_EQ(EILSEQ, errno);
}
}
// Manually test an embedded NULL.
std::wstring converted;
EXPECT_TRUE(UTF8ToWide("\00Z\t", 3, &converted));
ASSERT_EQ(3U, converted.length());
EXPECT_EQ(static_cast<wchar_t>(0), converted[0]);
EXPECT_EQ('Z', converted[1]);
EXPECT_EQ('\t', converted[2]);
// Make sure that conversion replaces, not appends.
EXPECT_TRUE(UTF8ToWide("B", 1, &converted));
ASSERT_EQ(1U, converted.length());
EXPECT_EQ('B', converted[0]);
}
#if defined(WCHAR_T_IS_UTF16)
// This test is only valid when wchar_t == UTF-16.
TEST(UTFStringConversionsTest, ConvertUTF16ToUTF8) {
struct WideToUTF8Case {
const wchar_t* utf16;
const char* utf8;
bool success;
} convert_cases[] = {
// Regular UTF-16 input.
{L"\x4f60\x597d", "\xe4\xbd\xa0\xe5\xa5\xbd", true},
// Test a non-BMP character.
{L"\xd800\xdf00", "\xF0\x90\x8C\x80", true},
// Non-characters are passed through.
{L"\xffffHello", "\xEF\xBF\xBFHello", true},
{L"\xdbff\xdffeHello", "\xF4\x8F\xBF\xBEHello", true},
// The first character is a truncated UTF-16 character.
// Note that for whatever reason, this test fails on Windows XP.
{L"\xd800\x597d", "\xef\xbf\xbd\xe5\xa5\xbd",
#if (WINVER >= 0x0600)
// Only Vista and later has a new API/flag that correctly returns false.
false
#else
true
#endif
},
// Truncated at the end.
// Note that for whatever reason, this test fails on Windows XP.
{L"\x597d\xd800", "\xe5\xa5\xbd\xef\xbf\xbd",
#if (WINVER >= 0x0600)
// Only Vista and later has a new API/flag that correctly returns false.
false
#else
true
#endif
},
};
for (size_t i = 0; i < arraysize(convert_cases); i++) {
std::string converted;
errno = 0;
const bool success = WideToUTF8(convert_cases[i].utf16,
wcslen(convert_cases[i].utf16),
&converted);
EXPECT_EQ(convert_cases[i].success, success);
// The original test always compared expected and converted, but don't do
// that because our implementation of WideToUTF8() does not guarantee to
// produce the same output in error situations.
if (success) {
std::string expected(convert_cases[i].utf8);
EXPECT_EQ(expected, converted);
} else {
EXPECT_EQ(EILSEQ, errno);
}
}
}
#elif defined(WCHAR_T_IS_UTF32)
// This test is only valid when wchar_t == UTF-32.
TEST(UTFStringConversionsTest, ConvertUTF32ToUTF8) {
struct WideToUTF8Case {
const wchar_t* utf32;
const char* utf8;
bool success;
} convert_cases[] = {
// Regular 16-bit input.
{L"\x4f60\x597d", "\xe4\xbd\xa0\xe5\xa5\xbd", true},
// Test a non-BMP character.
{L"A\x10300z", "A\xF0\x90\x8C\x80z", true},
// Non-characters are passed through.
{L"\xffffHello", "\xEF\xBF\xBFHello", true},
{L"\x10fffeHello", "\xF4\x8F\xBF\xBEHello", true},
// Invalid Unicode code points.
{L"\xfffffffHello", "\xEF\xBF\xBDHello", false},
// The first character is a truncated UTF-16 character.
{L"\xd800\x597d", "\xef\xbf\xbd\xe5\xa5\xbd", false},
{L"\xdc01Hello", "\xef\xbf\xbdHello", false},
};
for (size_t i = 0; i < arraysize(convert_cases); i++) {
std::string converted;
EXPECT_EQ(convert_cases[i].success,
WideToUTF8(convert_cases[i].utf32,
wcslen(convert_cases[i].utf32),
&converted));
std::string expected(convert_cases[i].utf8);
EXPECT_EQ(expected, converted);
}
}
#endif // defined(WCHAR_T_IS_UTF32)
// The test below uses these types and functions, so just do enough to get the
// test running.
typedef wchar_t char16;
typedef std::wstring string16;
template<typename T>
static void* WriteInto(T* t, size_t size) {
// std::(w)string::resize() already includes space for a NULL terminator.
t->resize(size - 1);
return &(*t)[0];
}
// A stub implementation that calls a helper from above, just to get the test
// below working. This is just for testing and should not be moved to base
// because this ignores errors which is probably not a good idea, plus it takes
// a string16 type which we don't really have.
static std::string UTF16ToUTF8(const string16& utf16) {
return WideToUTF8(utf16);
}
TEST(UTFStringConversionsTest, ConvertMultiString) {
static char16 multi16[] = {
'f', 'o', 'o', '\0',
'b', 'a', 'r', '\0',
'b', 'a', 'z', '\0',
'\0'
};
static char multi[] = {
'f', 'o', 'o', '\0',
'b', 'a', 'r', '\0',
'b', 'a', 'z', '\0',
'\0'
};
string16 multistring16;
memcpy(WriteInto(&multistring16, arraysize(multi16)), multi16,
sizeof(multi16));
EXPECT_EQ(arraysize(multi16) - 1, multistring16.length());
std::string expected;
memcpy(WriteInto(&expected, arraysize(multi)), multi, sizeof(multi));
EXPECT_EQ(arraysize(multi) - 1, expected.length());
const std::string& converted = UTF16ToUTF8(multistring16);
EXPECT_EQ(arraysize(multi) - 1, converted.length());
EXPECT_EQ(expected, converted);
}
// The tests below from sys_string_conversions_unittest.cc call SysWideToUTF8()
// and SysUTF8ToWide(), so these are stub implementations that call the helpers
// above. These are just for testing and should not be moved to base because
// they ignore errors which is probably not a good idea.
static std::string SysWideToUTF8(const std::wstring& utf16) {
return WideToUTF8(utf16);
}
static std::wstring SysUTF8ToWide(const std::string& utf8) {
return UTF8ToWide(utf8);
}
// Below is adapted from https://chromium.googlesource.com/chromium/src/+/master/base/strings/sys_string_conversions_unittest.cc
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifdef WCHAR_T_IS_UTF32
static const std::wstring kSysWideOldItalicLetterA = L"\x10300";
#else
static const std::wstring kSysWideOldItalicLetterA = L"\xd800\xdf00";
#endif
TEST(SysStrings, SysWideToUTF8) {
EXPECT_EQ("Hello, world", SysWideToUTF8(L"Hello, world"));
EXPECT_EQ("\xe4\xbd\xa0\xe5\xa5\xbd", SysWideToUTF8(L"\x4f60\x597d"));
// >16 bits
EXPECT_EQ("\xF0\x90\x8C\x80", SysWideToUTF8(kSysWideOldItalicLetterA));
// Error case. When Windows finds a UTF-16 character going off the end of
// a string, it just converts that literal value to UTF-8, even though this
// is invalid.
//
// This is what XP does, but Vista has different behavior, so we don't bother
// verifying it:
// EXPECT_EQ("\xE4\xBD\xA0\xED\xA0\x80zyxw",
// SysWideToUTF8(L"\x4f60\xd800zyxw"));
// Test embedded NULLs.
std::wstring wide_null(L"a");
wide_null.push_back(0);
wide_null.push_back('b');
std::string expected_null("a");
expected_null.push_back(0);
expected_null.push_back('b');
EXPECT_EQ(expected_null, SysWideToUTF8(wide_null));
}
TEST(SysStrings, SysUTF8ToWide) {
EXPECT_EQ(L"Hello, world", SysUTF8ToWide("Hello, world"));
EXPECT_EQ(L"\x4f60\x597d", SysUTF8ToWide("\xe4\xbd\xa0\xe5\xa5\xbd"));
// >16 bits
EXPECT_EQ(kSysWideOldItalicLetterA, SysUTF8ToWide("\xF0\x90\x8C\x80"));
// Error case. When Windows finds an invalid UTF-8 character, it just skips
// it. This seems weird because it's inconsistent with the reverse conversion.
//
// This is what XP does, but Vista has different behavior, so we don't bother
// verifying it:
// EXPECT_EQ(L"\x4f60zyxw", SysUTF8ToWide("\xe4\xbd\xa0\xe5\xa5zyxw"));
// Test embedded NULLs.
std::string utf8_null("a");
utf8_null.push_back(0);
utf8_null.push_back('b');
std::wstring expected_null(L"a");
expected_null.push_back(0);
expected_null.push_back('b');
EXPECT_EQ(expected_null, SysUTF8ToWide(utf8_null));
}
} // namespace base
} // namespace android