#include "base/native_library.h"
#include "base/files/file_path.h"
#include "base/path_service.h"
#include "base/test/native_library_test_utils.h"
#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace base {
const FilePath::CharType kDummyLibraryPath[] =
FILE_PATH_LITERAL("dummy_library");
TEST(NativeLibraryTest, LoadFailure) {
NativeLibraryLoadError error;
EXPECT_FALSE(LoadNativeLibrary(FilePath(kDummyLibraryPath), &error));
EXPECT_FALSE(error.ToString().empty());
}
TEST(NativeLibraryTest, LoadFailureWithNullError) {
EXPECT_FALSE(LoadNativeLibrary(FilePath(kDummyLibraryPath), nullptr));
}
#if BUILDFLAG(IS_FUCHSIA)
TEST(NativeLibraryTest, LoadAbsolutePath) {
EXPECT_TRUE(LoadNativeLibrary(FilePath("/pkg/lib/libtest_shared_library.so"),
nullptr));
}
TEST(NativeLibraryTest, LoadAbsolutePath_OutsideLibraryRoot) {
NativeLibraryLoadError error;
EXPECT_FALSE(LoadNativeLibrary(FilePath("/pkg/tmp/libtest_shared_library.so"),
&error));
std::string expected_error =
"Absolute library paths must begin with /pkg/lib";
EXPECT_EQ(error.ToString(), expected_error);
}
#endif
TEST(NativeLibraryTest, GetNativeLibraryName) {
const char kExpectedName[] =
#if BUILDFLAG(IS_WIN)
"mylib.dll";
#elif BUILDFLAG(IS_IOS)
"mylib";
#elif BUILDFLAG(IS_MAC)
"libmylib.dylib";
#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
"libmylib.so";
#endif
EXPECT_EQ(kExpectedName, GetNativeLibraryName("mylib"));
}
TEST(NativeLibraryTest, GetLoadableModuleName) {
const char kExpectedName[] =
#if BUILDFLAG(IS_WIN)
"mylib.dll";
#elif BUILDFLAG(IS_IOS)
"mylib";
#elif BUILDFLAG(IS_MAC)
"mylib.so";
#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
"libmylib.so";
#endif
EXPECT_EQ(kExpectedName, GetLoadableModuleName("mylib"));
}
#if !BUILDFLAG(IS_IOS) && !defined(ADDRESS_SANITIZER)
const char kTestLibraryName[] =
#if BUILDFLAG(IS_WIN)
"test_shared_library.dll";
#elif BUILDFLAG(IS_MAC)
"libtest_shared_library.dylib";
#elif BUILDFLAG(IS_ANDROID) && defined(COMPONENT_BUILD)
"libtest_shared_library.cr.so";
#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
"libtest_shared_library.so";
#endif
class TestLibrary {
public:
TestLibrary() : TestLibrary(NativeLibraryOptions()) {}
explicit TestLibrary(const NativeLibraryOptions& options)
: library_(nullptr) {
base::FilePath exe_path;
#if !BUILDFLAG(IS_FUCHSIA)
CHECK(base::PathService::Get(base::DIR_EXE, &exe_path));
#endif
library_ = LoadNativeLibraryWithOptions(
exe_path.AppendASCII(kTestLibraryName), options, nullptr);
CHECK(library_);
}
TestLibrary(const TestLibrary&) = delete;
TestLibrary& operator=(const TestLibrary&) = delete;
~TestLibrary() { UnloadNativeLibrary(library_); }
template <typename ReturnType, typename... Args>
ReturnType Call(const char* function_name, Args... args) {
return reinterpret_cast<ReturnType (*)(Args...)>(
GetFunctionPointerFromNativeLibrary(library_, function_name))(args...);
}
private:
NativeLibrary library_;
};
#if !BUILDFLAG(IS_ANDROID)
TEST(NativeLibraryTest, LoadLibrary) {
TestLibrary library;
EXPECT_EQ(5, library.Call<int>("GetSimpleTestValue"));
}
#endif
#if !BUILDFLAG(IS_ANDROID) && !defined(THREAD_SANITIZER) && \
!defined(MEMORY_SANITIZER)
TEST(NativeLibraryTest, LoadLibraryPreferOwnSymbols) {
NativeLibraryOptions options;
options.prefer_own_symbols = true;
TestLibrary library(options);
g_native_library_exported_value = 1;
library.Call<void>("SetExportedValue", 2);
EXPECT_EQ(1, g_native_library_exported_value);
g_native_library_exported_value = 3;
EXPECT_EQ(2, library.Call<int>("GetExportedValue"));
EXPECT_EQ(1, library.Call<int>("GetIncrementValue"));
EXPECT_EQ(1, NativeLibraryTestIncrement());
EXPECT_EQ(2, library.Call<int>("GetIncrementValue"));
EXPECT_EQ(3, library.Call<int>("GetIncrementValue"));
EXPECT_EQ(4, library.Call<int>("NativeLibraryTestIncrement"));
EXPECT_EQ(2, NativeLibraryTestIncrement());
EXPECT_EQ(3, NativeLibraryTestIncrement());
}
#endif
// !defined(MEMORY_SANITIZER)
#endif
}