Initial commit

This commit is contained in:
alexpete
2021-03-05 11:26:34 -08:00
commit a10351f38d
27091 changed files with 5521199 additions and 0 deletions
+50
View File
@@ -0,0 +1,50 @@
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME})
include(${pal_dir}/platform_traits_${PAL_PLATFORM_NAME_LOWERCASE}.cmake)
ly_add_target(
NAME AzTestRunner ${PAL_TRAIT_AZTESTRUNNER_LAUNCHER_TYPE}
NAMESPACE AZ
FILES_CMAKE
aztestrunner_files.cmake
${pal_dir}/platform_${PAL_PLATFORM_NAME_LOWERCASE}_files.cmake
PLATFORM_INCLUDE_FILES
${pal_dir}/platform_${PAL_PLATFORM_NAME_LOWERCASE}.cmake
INCLUDE_DIRECTORIES
PRIVATE
src
BUILD_DEPENDENCIES
PRIVATE
AZ::AzCore
AZ::AzTest
AZ::AzFramework
)
ly_add_target(
NAME AzTestRunner.Tests ${PAL_TRAIT_TEST_TARGET_TYPE}
NAMESPACE AZ
FILES_CMAKE
aztestrunner_test_files.cmake
BUILD_DEPENDENCIES
PRIVATE
AZ::AzTest
)
ly_add_googletest(
NAME AZ::AzTestRunner.Tests
)
endif()
@@ -0,0 +1,12 @@
{
"product_name" : "AzTestRunner Project",
"android_settings": {
"package_name" : "com.lumberyard.tests",
"version_number": 1,
"version_name" : "1.0.0",
"orientation" : "landscape",
"app_obfuscator_salt" : "MY_OBFUSCATOR_SALT_BASE_64",
"use_main_obb" : "false",
"use_patch_obb" : "false"
}
}
@@ -0,0 +1,15 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Include the required native app glue source from the configured NDK path directly
#include <android_native_app_glue.c>
@@ -0,0 +1,15 @@
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
set(LY_INCLUDE_DIRECTORIES
PRIVATE
${LY_NDK_NATIVE_APP_GLUE_SRC_DIR}
)
@@ -0,0 +1,456 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <atomic>
#include <chrono>
#include <thread>
#include <AzTest/AzTest.h>
#include <AzTest/Platform.h>
#include <AzCore/IO/SystemFile.h> // for AZ_MAX_PATH_LEN
#include <AzCore/StringFunc/StringFunc.h>
#include <AzCore/Utils/Utils.h>
#include <AzCore/std/functional.h>
#include <AzCore/Android/AndroidEnv.h>
#include <AzCore/Android/Utils.h>
#include <AzCore/Android/JNI/JNI.h>
#include <AzCore/Android/JNI/Object.h>
#include <AzCore/Android/JNI/scoped_ref.h>
#include <AzCore/Component/TickBus.h>
#include <AzFramework/API/ApplicationAPI_Platform.h>
#include <AzFramework/Input/Buses/Notifications/RawInputNotificationBus_Platform.h>
#include "aztestrunner.h"
#include <android/asset_manager_jni.h>
#include <android/log.h>
#include <android/native_activity.h>
#include <android/native_window.h>
#include <android_native_app_glue.h>
#include <sys/resource.h>
#include <sys/types.h>
constexpr const char* s_logTag = "LMBR";
#define MAIN_EXIT_FAILURE(_appState, ...) \
__android_log_print(ANDROID_LOG_INFO, s_logTag, "****************************************************************"); \
__android_log_print(ANDROID_LOG_INFO, s_logTag, "STARTUP FAILURE - EXITING"); \
__android_log_print(ANDROID_LOG_INFO, s_logTag, "REASON:"); \
__android_log_print(ANDROID_LOG_INFO, s_logTag, __VA_ARGS__); \
__android_log_print(ANDROID_LOG_INFO, s_logTag, "****************************************************************"); \
_appState->userData = nullptr; \
ANativeActivity_finish(_appState->activity); \
while (_appState->destroyRequested == 0) { \
g_eventDispatcher.PumpAllEvents(); \
} \
return;
namespace AzTestRunner
{
void set_quiet_mode()
{
}
const char* get_current_working_directory()
{
static char cwd_buffer[AZ_MAX_PATH_LEN] = { '\0' };
AZ::Utils::ExecutablePathResult result = AZ::Utils::GetExecutableDirectory(cwd_buffer, AZ_ARRAY_SIZE(cwd_buffer));
AZ_Assert(result == AZ::Utils::ExecutablePathResult::Success, "Error retrieving executable path");
return static_cast<const char*>(cwd_buffer);
}
void pause_on_completion()
{
}
}
static AZ::EnvironmentInstance s_envInst = nullptr;
AZTEST_EXPORT AZ::EnvironmentInstance GetTestRunnerEnvironment()
{
return s_envInst;
}
namespace
{
class NativeEventDispatcher
: public AzFramework::AndroidEventDispatcher
{
public:
NativeEventDispatcher()
: m_appState(nullptr)
{
}
~NativeEventDispatcher()
{
}
void PumpAllEvents() override
{
bool continueRunning = true;
while (continueRunning)
{
continueRunning = PumpEvents(&ALooper_pollAll);
}
}
void PumpEventLoopOnce() override
{
PumpEvents(&ALooper_pollOnce);
}
void SetAppState(android_app* appState)
{
m_appState = appState;
}
private:
// signature of ALooper_pollOnce and ALooper_pollAll -> int timeoutMillis, int* outFd, int* outEvents, void** outData
typedef int (*EventPumpFunc)(int, int*, int*, void**);
bool PumpEvents(EventPumpFunc looperFunc)
{
if (!m_appState)
{
return false;
}
int events = 0;
android_poll_source* source = nullptr;
const AZ::Android::AndroidEnv* androidEnv = AZ::Android::AndroidEnv::Get();
// when timeout is negative, the function will block until an event is received
const int result = looperFunc(androidEnv->IsRunning() ? 0 : -1, nullptr, &events, reinterpret_cast<void**>(&source));
// the value returned from the looper poll func is either:
// 1. the identifier associated with the event source (>= 0) and has event data that needs to be processed manually
// 2. an ALOOPER_POLL_* enum (< 0) indicating there is no data to be processed due to error or callback(s) registered
// with the event source were called
const bool validIdentifier = (result >= 0);
if (validIdentifier && source)
{
source->process(m_appState, source);
}
const bool destroyRequested = (m_appState->destroyRequested != 0);
return (validIdentifier && !destroyRequested);
}
android_app* m_appState;
};
NativeEventDispatcher g_eventDispatcher;
bool g_windowInitialized = false;
int32_t HandleInputEvents(android_app* app, AInputEvent* event)
{
AzFramework::RawInputNotificationBusAndroid::Broadcast(&AzFramework::RawInputNotificationsAndroid::OnRawInputEvent, event);
return 0;
}
void HandleApplicationLifecycleEvents(android_app* appState, int32_t command)
{
AZ::Android::AndroidEnv* androidEnv = static_cast<AZ::Android::AndroidEnv*>(appState->userData);
if (!androidEnv)
{
return;
}
switch (command)
{
case APP_CMD_GAINED_FOCUS:
{
AzFramework::AndroidLifecycleEvents::Bus::Broadcast(
&AzFramework::AndroidLifecycleEvents::Bus::Events::OnGainedFocus);
}
break;
case APP_CMD_LOST_FOCUS:
{
AzFramework::AndroidLifecycleEvents::Bus::Broadcast(
&AzFramework::AndroidLifecycleEvents::Bus::Events::OnLostFocus);
}
break;
case APP_CMD_PAUSE:
{
AzFramework::AndroidLifecycleEvents::Bus::Broadcast(
&AzFramework::AndroidLifecycleEvents::Bus::Events::OnPause);
androidEnv->SetIsRunning(false);
}
break;
case APP_CMD_RESUME:
{
androidEnv->SetIsRunning(true);
AzFramework::AndroidLifecycleEvents::Bus::Broadcast(
&AzFramework::AndroidLifecycleEvents::Bus::Events::OnResume);
}
break;
case APP_CMD_DESTROY:
{
AzFramework::AndroidLifecycleEvents::Bus::Broadcast(
&AzFramework::AndroidLifecycleEvents::Bus::Events::OnDestroy);
}
break;
case APP_CMD_INIT_WINDOW:
{
g_windowInitialized = true;
androidEnv->SetWindow(appState->window);
AzFramework::AndroidLifecycleEvents::Bus::Broadcast(
&AzFramework::AndroidLifecycleEvents::Bus::Events::OnWindowInit);
}
break;
case APP_CMD_TERM_WINDOW:
{
AzFramework::AndroidLifecycleEvents::Bus::Broadcast(
&AzFramework::AndroidLifecycleEvents::Bus::Events::OnWindowDestroy);
androidEnv->SetWindow(nullptr);
}
break;
case APP_CMD_LOW_MEMORY:
{
AzFramework::AndroidLifecycleEvents::Bus::Broadcast(
&AzFramework::AndroidLifecycleEvents::Bus::Events::OnLowMemory);
}
break;
case APP_CMD_CONFIG_CHANGED:
{
androidEnv->UpdateConfiguration();
}
break;
case APP_CMD_WINDOW_REDRAW_NEEDED:
{
AzFramework::AndroidLifecycleEvents::Bus::Broadcast(
&AzFramework::AndroidLifecycleEvents::Bus::Events::OnWindowRedrawNeeded);
}
break;
}
}
void OnWindowRedrawNeeded(ANativeActivity* activity, ANativeWindow* rect)
{
android_app* app = static_cast<android_app*>(activity->instance);
int8_t cmd = APP_CMD_WINDOW_REDRAW_NEEDED;
if (write(app->msgwrite, &cmd, sizeof(cmd)) != sizeof(cmd))
{
__android_log_print(ANDROID_LOG_ERROR, s_logTag, "Failure writing android_app cmd: %s\n", strerror(errno));
}
}
}
// In order to read the logcat from adb, stdout and stderr needs to be redirected custom handles and we will need
// to spawn a thread to read from the custom handles and pass the output of those streams through __android_log_print
// to a specia 'LMBR' tag
static int s_pfd[2];
static std::atomic_bool s_testRunComplete { false };
static void *thread_logger_func(void*)
{
ssize_t readSize;
char logBuffer[256] = {'\0'};
while (!s_testRunComplete)
{
readSize = read(s_pfd[0], logBuffer, sizeof(logBuffer)-1);
if (readSize>0) {
// Trim the tailing return character
if (logBuffer[readSize - 1] == '\n') {
--readSize;
}
logBuffer[readSize] = '\0';
((void) __android_log_print(ANDROID_LOG_INFO, s_logTag, logBuffer));
}
}
return 0;
}
constexpr const char* s_defaultAppName = "AzTestRunner";
constexpr size_t s_maxArgCount = 8;
constexpr size_t s_maxArgLength = 64;
void android_main(android_app* appState)
{
// Adding a start up banner so you can see when the test runner is starting up in amongst the logcat spam
__android_log_print(ANDROID_LOG_INFO, s_logTag, "****************************************************************");
__android_log_print(ANDROID_LOG_INFO, s_logTag, " Starting %s", s_defaultAppName);
__android_log_print(ANDROID_LOG_INFO, s_logTag, "****************************************************************");
// setup the android environment
AZ::AllocatorInstance<AZ::OSAllocator>::Create();
s_envInst = AZ::Environment::GetInstance();
// setup the system command handler which are guaranteed to be called on the same
// thread the events are pumped
appState->onAppCmd = HandleApplicationLifecycleEvents;
appState->onInputEvent = HandleInputEvents;
g_eventDispatcher.SetAppState(appState);
// This callback will notify us when the orientation of the device changes.
// While Android does have an onNativeWindowResized callback, it is never called in android_native_app_glue when the window size changes.
// The onNativeConfigChanged callback is called too early(before the window size has changed), so we won't have the correct window size at that point.
appState->activity->callbacks->onNativeWindowRedrawNeeded = OnWindowRedrawNeeded;
{
AZ::Android::AndroidEnv::Descriptor descriptor;
descriptor.m_jvm = appState->activity->vm;
descriptor.m_activityRef = appState->activity->clazz;
descriptor.m_assetManager = appState->activity->assetManager;
descriptor.m_configuration = appState->config;
descriptor.m_appPrivateStoragePath = appState->activity->internalDataPath;
descriptor.m_appPublicStoragePath = appState->activity->externalDataPath;
descriptor.m_obbStoragePath = appState->activity->obbPath;
if (!AZ::Android::AndroidEnv::Create(descriptor))
{
AZ::Android::AndroidEnv::Destroy();
AZ::AllocatorInstance<AZ::OSAllocator>::Destroy();
MAIN_EXIT_FAILURE(appState, "Failed to create the AndroidEnv");
}
AZ::Android::AndroidEnv* androidEnv = AZ::Android::AndroidEnv::Get();
appState->userData = androidEnv;
androidEnv->SetIsRunning(true);
}
g_eventDispatcher.PumpAllEvents();
// Prepare the command line args to pass to main
char commandLineArgs[s_maxArgCount][s_maxArgLength] = { {'\0'} };
size_t currentCommandLineIndex = 0;
// Always add the app as the first arg to mimic the way other platforms start with the executable name.
const char* packageName = AZ::Android::Utils::GetPackageName();
const char* appName = (packageName) ? packageName : s_defaultAppName;
size_t appNameLen = strlen(appName);
azstrncpy(commandLineArgs[currentCommandLineIndex++], s_maxArgLength, appName, appNameLen + 1);
// "activityObject" and "intent" need to be destroyed before we call Destroy() on the allocator to ensure graceful shutdown.
{
// Get the string extras and pass them along as cmd line params
AZ::Android::JNI::Internal::Object<AZ::OSAllocator> activityObject(AZ::Android::JNI::GetEnv()->GetObjectClass(appState->activity->clazz), appState->activity->clazz);
activityObject.RegisterMethod("getIntent", "()Landroid/content/Intent;");
jobject intent = activityObject.InvokeObjectMethod<jobject>("getIntent");
AZ::Android::JNI::Internal::Object<AZ::OSAllocator> intentObject(AZ::Android::JNI::GetEnv()->GetObjectClass(intent), intent);
intentObject.RegisterMethod("getStringExtra", "(Ljava/lang/String;)Ljava/lang/String;");
intentObject.RegisterMethod("getExtras", "()Landroid/os/Bundle;");
jobject extras = intentObject.InvokeObjectMethod<jobject>("getExtras");
int start_delay = 0;
if (extras)
{
// Get the set of keys
AZ::Android::JNI::Internal::Object<AZ::OSAllocator> extrasObject(AZ::Android::JNI::GetEnv()->GetObjectClass(extras), extras);
extrasObject.RegisterMethod("keySet", "()Ljava/util/Set;");
jobject extrasKeySet = extrasObject.InvokeObjectMethod<jobject>("keySet");
// get the array of string objects
AZ::Android::JNI::Internal::Object<AZ::OSAllocator> extrasKeySetObject(AZ::Android::JNI::GetEnv()->GetObjectClass(extrasKeySet), extrasKeySet);
extrasKeySetObject.RegisterMethod("toArray", "()[Ljava/lang/Object;");
jobjectArray extrasKeySetArray = extrasKeySetObject.InvokeObjectMethod<jobjectArray>("toArray");
int extrasKeySetArraySize = AZ::Android::JNI::GetEnv()->GetArrayLength(extrasKeySetArray);
for (int x = 0; x < extrasKeySetArraySize; x++)
{
jstring keyObject = static_cast<jstring>(AZ::Android::JNI::GetEnv()->GetObjectArrayElement(extrasKeySetArray, x));
AZ::OSString value = intentObject.InvokeStringMethod("getStringExtra", keyObject);
const char* keyChars = AZ::Android::JNI::GetEnv()->GetStringUTFChars(keyObject, 0);
if (azstricmp("startdelay", keyChars) == 0)
{
start_delay = strtol(value.c_str(), nullptr, 10);
}
else if (azstricmp("gtest_filter", keyChars) == 0)
{
azsnprintf(commandLineArgs[currentCommandLineIndex++], s_maxArgLength, "--gtest_filter=%.*s", aznumeric_cast<int>(value.size()), value.c_str());
}
else
{
azstrncpy(commandLineArgs[currentCommandLineIndex++], s_maxArgLength, keyChars, strlen(keyChars) + 1);
azstrncpy(commandLineArgs[currentCommandLineIndex++], s_maxArgLength, value.c_str(), value.length() + 1);
}
AZ::Android::JNI::GetEnv()->ReleaseStringUTFChars(keyObject, keyChars);
}
}
if (start_delay > 0)
{
std::this_thread::sleep_for(std::chrono::seconds(start_delay));
}
}
char* argv[s_maxArgCount];
for (size_t index = 0; index < s_maxArgCount; index++)
{
argv[index] = commandLineArgs[index];
}
// Redirect stdout and stderr to custom handles and prepare the thread to read from the custom handles
pthread_t log_thread;
setvbuf(stdout, 0, _IOLBF, 0);
setvbuf(stderr, 0, _IONBF, 0);
pipe(s_pfd);
dup2(s_pfd[1], 1);
dup2(s_pfd[1], 2);
if (pthread_create(&log_thread, 0, thread_logger_func, 0) == -1)
{
((void)__android_log_print(ANDROID_LOG_INFO, s_logTag, "[FAILURE] Unable to spawn logging thread"));
return;
}
// Execute the unit test main
int result = AzTestRunner::wrapped_main(aznumeric_cast<int>(currentCommandLineIndex), argv);
g_eventDispatcher.PumpAllEvents();
s_testRunComplete = true;
std::this_thread::sleep_for(std::chrono::seconds(1));
if (result == 0)
{
((void)__android_log_print(ANDROID_LOG_INFO, s_logTag, "[SUCCESS]"));
}
else
{
((void)__android_log_print(ANDROID_LOG_INFO, s_logTag, "[FAILURE]"));
}
AZ::Android::AndroidEnv::Destroy();
AZ::AllocatorInstance<AZ::OSAllocator>::Destroy();
}
@@ -0,0 +1,15 @@
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
set(FILES
platform_android.cpp
native_app_glue_include.c
)
@@ -0,0 +1,13 @@
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
set(PAL_TRAIT_AZTESTRUNNER_LAUNCHER_TYPE MODULE)
@@ -0,0 +1,22 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include "aztestrunner.h"
#include <iostream>
int main(int argc, char** argv)
{
int result = AzTestRunner::wrapped_main(argc, argv);
std::cout << "Returning code: " << result << std::endl;
return result;
}
@@ -0,0 +1,34 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <stdio.h> // for freopen
#include <unistd.h> // for getcwd
#include <AzCore/IO/SystemFile.h> // for AZ_MAX_PATH_LEN
namespace AzTestRunner
{
void set_quiet_mode()
{
freopen("/dev/null", "a", stdout);
}
const char* get_current_working_directory()
{
static char cwd_buffer[AZ_MAX_PATH_LEN] = { '\0' };
return getcwd(cwd_buffer, sizeof(cwd_buffer));
}
void pause_on_completion()
{
system("pause");
}
}
@@ -0,0 +1,11 @@
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
@@ -0,0 +1,15 @@
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
set(FILES
../Common/platform_host_main.cpp
../Common/platform_host_posix.cpp
)
@@ -0,0 +1,13 @@
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
set(PAL_TRAIT_AZTESTRUNNER_LAUNCHER_TYPE EXECUTABLE)
@@ -0,0 +1,11 @@
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
@@ -0,0 +1,15 @@
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
set(FILES
../Common/platform_host_main.cpp
../Common/platform_host_posix.cpp
)
@@ -0,0 +1,13 @@
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
set(PAL_TRAIT_AZTESTRUNNER_LAUNCHER_TYPE EXECUTABLE)
@@ -0,0 +1,13 @@
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
set(PAL_TRAIT_AZTESTRUNNER_LAUNCHER_TYPE EXECUTABLE)
@@ -0,0 +1,11 @@
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
@@ -0,0 +1,35 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <sstream> // for freopen_s
#include <direct.h> // for _getcwd
#include <AzCore/IO/SystemFile.h> // for AZ_MAX_PATH_LEN
namespace AzTestRunner
{
void set_quiet_mode()
{
FILE* stream;
freopen_s(&stream, "nul", "w", stdout);
}
const char* get_current_working_directory()
{
static char cwd_buffer[AZ_MAX_PATH_LEN] = { '\0' };
return _getcwd(cwd_buffer, sizeof(cwd_buffer));
}
void pause_on_completion()
{
system("pause");
}
}
@@ -0,0 +1,15 @@
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
set(FILES
../Common/platform_host_main.cpp
platform_windows.cpp
)
@@ -0,0 +1,24 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#import <UIKit/UIKit.h>
int main(int argc, char* argv[])
{
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
UIApplicationMain(argc,
argv,
nil,
nil);
[pool release];
return 0;
}
@@ -0,0 +1,116 @@
{
"images" : [
{
"size" : "20x20",
"idiom" : "iphone",
"filename" : "iPhoneNotificationIcon40x40.png",
"scale" : "2x"
},
{
"size" : "20x20",
"idiom" : "iphone",
"filename" : "iPhoneNotificationIcon40x40.png",
"scale" : "3x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "iPhoneNotificationIcon40x40.png",
"scale" : "2x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "iPhoneNotificationIcon40x40.png",
"scale" : "3x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "iPhoneNotificationIcon40x40.png",
"scale" : "2x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "iPhoneNotificationIcon40x40.png",
"scale" : "3x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "iPhoneNotificationIcon40x40.png",
"scale" : "2x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "iPhoneNotificationIcon40x40.png",
"scale" : "3x"
},
{
"size" : "20x20",
"idiom" : "ipad",
"filename" : "iPhoneNotificationIcon40x40.png",
"scale" : "1x"
},
{
"size" : "20x20",
"idiom" : "ipad",
"filename" : "iPhoneNotificationIcon40x40.png",
"scale" : "2x"
},
{
"size" : "29x29",
"idiom" : "ipad",
"filename" : "iPhoneNotificationIcon40x40.png",
"scale" : "1x"
},
{
"size" : "29x29",
"idiom" : "ipad",
"filename" : "iPhoneNotificationIcon40x40.png",
"scale" : "2x"
},
{
"size" : "40x40",
"idiom" : "ipad",
"filename" : "iPhoneNotificationIcon40x40.png",
"scale" : "1x"
},
{
"size" : "40x40",
"idiom" : "ipad",
"filename" : "iPhoneNotificationIcon40x40.png",
"scale" : "2x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "iPhoneNotificationIcon40x40.png",
"scale" : "1x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "iPhoneNotificationIcon40x40.png",
"scale" : "2x"
},
{
"size" : "83.5x83.5",
"idiom" : "ipad",
"filename" : "iPhoneNotificationIcon40x40.png",
"scale" : "2x"
},
{
"size" : "1024x1024",
"idiom" : "ios-marketing",
"filename" : "iPhoneNotificationIcon40x40.png",
"scale" : "1x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:0c25ffb1af8160b3202977de8c32aaa235e22c643ffd8004e4546c96868ef3b9
size 18317
@@ -0,0 +1,169 @@
{
"images" : [
{
"extent" : "full-screen",
"idiom" : "iphone",
"subtype" : "2436h",
"filename" : "iPadLaunchImage1024x768.png",
"minimum-system-version" : "11.0",
"orientation" : "portrait",
"scale" : "3x"
},
{
"extent" : "full-screen",
"idiom" : "iphone",
"subtype" : "2436h",
"filename" : "iPadLaunchImage1024x768.png",
"minimum-system-version" : "11.0",
"orientation" : "landscape",
"scale" : "3x"
},
{
"extent" : "full-screen",
"idiom" : "iphone",
"subtype" : "736h",
"filename" : "iPadLaunchImage1024x768.png",
"minimum-system-version" : "8.0",
"orientation" : "portrait",
"scale" : "3x"
},
{
"extent" : "full-screen",
"idiom" : "iphone",
"subtype" : "736h",
"filename" : "iPadLaunchImage1024x768.png",
"minimum-system-version" : "8.0",
"orientation" : "landscape",
"scale" : "3x"
},
{
"extent" : "full-screen",
"idiom" : "iphone",
"subtype" : "667h",
"filename" : "iPadLaunchImage1024x768.png",
"minimum-system-version" : "8.0",
"orientation" : "portrait",
"scale" : "2x"
},
{
"orientation" : "portrait",
"idiom" : "iphone",
"filename" : "iPadLaunchImage1024x768.png",
"extent" : "full-screen",
"minimum-system-version" : "7.0",
"scale" : "2x"
},
{
"extent" : "full-screen",
"idiom" : "iphone",
"subtype" : "retina4",
"filename" : "iPadLaunchImage1024x768.png",
"minimum-system-version" : "7.0",
"orientation" : "portrait",
"scale" : "2x"
},
{
"orientation" : "portrait",
"idiom" : "ipad",
"filename" : "iPadLaunchImage1024x768.png",
"extent" : "full-screen",
"minimum-system-version" : "7.0",
"scale" : "1x"
},
{
"orientation" : "landscape",
"idiom" : "ipad",
"filename" : "iPadLaunchImage1024x768.png",
"extent" : "full-screen",
"minimum-system-version" : "7.0",
"scale" : "1x"
},
{
"orientation" : "portrait",
"idiom" : "ipad",
"filename" : "iPadLaunchImage1024x768.png",
"extent" : "full-screen",
"minimum-system-version" : "7.0",
"scale" : "2x"
},
{
"orientation" : "landscape",
"idiom" : "ipad",
"filename" : "iPadLaunchImage1024x768.png",
"extent" : "full-screen",
"minimum-system-version" : "7.0",
"scale" : "2x"
},
{
"orientation" : "portrait",
"idiom" : "iphone",
"extent" : "full-screen",
"scale" : "1x"
},
{
"orientation" : "portrait",
"idiom" : "iphone",
"extent" : "full-screen",
"scale" : "2x"
},
{
"orientation" : "portrait",
"idiom" : "iphone",
"extent" : "full-screen",
"subtype" : "retina4",
"scale" : "2x"
},
{
"orientation" : "portrait",
"idiom" : "ipad",
"extent" : "to-status-bar",
"scale" : "1x"
},
{
"orientation" : "portrait",
"idiom" : "ipad",
"extent" : "full-screen",
"scale" : "1x"
},
{
"orientation" : "landscape",
"idiom" : "ipad",
"extent" : "to-status-bar",
"scale" : "1x"
},
{
"orientation" : "landscape",
"idiom" : "ipad",
"extent" : "full-screen",
"scale" : "1x"
},
{
"orientation" : "portrait",
"idiom" : "ipad",
"extent" : "to-status-bar",
"scale" : "2x"
},
{
"orientation" : "portrait",
"idiom" : "ipad",
"extent" : "full-screen",
"scale" : "2x"
},
{
"orientation" : "landscape",
"idiom" : "ipad",
"extent" : "to-status-bar",
"scale" : "2x"
},
{
"orientation" : "landscape",
"idiom" : "ipad",
"extent" : "full-screen",
"scale" : "2x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:31afa7ed44c5d9844c8d6ce08beccac482c3f43590869a3d190d06e2df377ccc
size 137472
@@ -0,0 +1,45 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleDisplayName</key>
<string>AzTestRunner</string>
<key>CFBundleExecutable</key>
<string>AzTestRunner</string>
<key>CFBundleIdentifier</key>
<string>com.lumberyard.tests</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>AzTestRunner</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.0</string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>arm64</string>
<string>metal</string>
</array>
<key>UIRequiresFullScreen</key>
<true/>
<key>UIStatusBarHidden</key>
<true/>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationLandscapeRight</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationLandscapeRight</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
</array>
</dict>
</plist>
@@ -0,0 +1,90 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#import <XCTest/XCTest.h>
#include <AzCore/IO/SystemFile.h>
#include <AzCore/Utils/Utils.h>
#include "aztestrunner.h"
constexpr size_t s_maxArgCount = 8;
constexpr size_t s_maxArgLength = 256;
namespace AzTestRunner
{
void set_quiet_mode()
{
}
const char* get_current_working_directory()
{
static char cwd_buffer[AZ_MAX_PATH_LEN] = { '\0' };
AZ::Utils::ExecutablePathResult result = AZ::Utils::GetExecutableDirectory(cwd_buffer, AZ_ARRAY_SIZE(cwd_buffer));
AZ_Assert(result == AZ::Utils::ExecutablePathResult::Success, "Error retrieving executable path");
return static_cast<const char*>(cwd_buffer);
}
void pause_on_completion()
{
}
}
@interface TestLauncherTarget : XCTestCase
@property(strong) NSArray* commandLineArgs;
@property size_t argCount;
@property bool testSuccessful;
@end
@implementation TestLauncherTarget
-(void) setUp
{
NSLog(@"TEST STARTED");
self.commandLineArgs = [[NSProcessInfo processInfo] arguments];
self.argCount = [self.commandLineArgs count];
self.testSuccessful = false;
}
-(void) tearDown
{
if (self.testSuccessful)
{
NSLog(@"TEST SUCCEEDED");
}
else
{
NSLog(@"TEST FAILED");
}
}
-(void) testLibrary
{
char args[s_maxArgCount][s_maxArgLength] = { {'\0'} };
char *argv[s_maxArgCount];
size_t argc = self.argCount;
for (size_t argIndex = 0; argIndex < s_maxArgCount && argIndex < argc; ++argIndex)
{
const char* arg = [self.commandLineArgs[argIndex] UTF8String];
azstrncpy(args[argIndex], s_maxArgLength, arg, strlen(arg));
argv[argIndex] = args[argIndex];
}
int status = AzTestRunner::wrapped_main(argc, argv);
self.testSuccessful = (status == 0);
XCTAssert(self.testSuccessful);
}
@end
@@ -0,0 +1,47 @@
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
set(TEST_LAUNCHER_BUILD_DEPENDENCIES AzCore AzTest)
set(LY_LINK_OPTIONS
PRIVATE
-ObjC
)
set(ly_game_resource_folder ${CMAKE_CURRENT_LIST_DIR}/Resources)
if (NOT EXISTS ${ly_game_resource_folder})
message(FATAL_ERROR "Missing expected resources folder")
endif()
target_sources(AzTestRunner PRIVATE ${ly_game_resource_folder}/Images.xcassets)
set_target_properties(AzTestRunner PROPERTIES
MACOSX_BUNDLE_INFO_PLIST ${ly_game_resource_folder}/Info.plist
RESOURCE ${ly_game_resource_folder}/Images.xcassets
XCODE_ATTRIBUTE_ASSETCATALOG_COMPILER_APPICON_NAME AzTestRunnerAppIcon
)
find_package(XCTest REQUIRED)
xctest_add_bundle(TestLauncherTarget AzTestRunner
${ly_game_resource_folder}/Info.plist
${CMAKE_CURRENT_LIST_DIR}/TestLauncherTarget.mm
${CMAKE_CURRENT_SOURCE_DIR}/src/main.cpp)
# XCTest adds the test as a target, but we still need to set dependencies.
set(include_directories "${CMAKE_CURRENT_SOURCE_DIR}/src")
foreach(dependency ${TEST_LAUNCHER_BUILD_DEPENDENCIES})
get_target_property(includes ${dependency} INCLUDE_DIRECTORIES)
LIST(APPEND include_directories ${includes})
target_link_libraries(TestLauncherTarget PRIVATE ${dependency})
endforeach()
set_property(TARGET TestLauncherTarget PROPERTY INCLUDE_DIRECTORIES ${include_directories})
@@ -0,0 +1,15 @@
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
set(FILES
Resources/Info.plist
Launcher_iOS.mm
)
@@ -0,0 +1,13 @@
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
set(PAL_TRAIT_AZTESTRUNNER_LAUNCHER_TYPE EXECUTABLE)
@@ -0,0 +1,15 @@
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
set(FILES
src/aztestrunner.h
src/main.cpp
)
@@ -0,0 +1,14 @@
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
set(FILES
test/RunnerTest.cpp
)
@@ -0,0 +1,30 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
namespace AzTestRunner
{
// Set the console output stream to stream to null in order to suppress output from stdout
void set_quiet_mode();
// Get the current working directory
const char* get_current_working_directory();
// Pause the execution upon completion where supported
void pause_on_completion();
// Execute the AZ test runner logic with arguments collected from the command line on platforms
// that support it. If the current platform does not support command line arguments, set argc
// to 0.
int wrapped_main(int argc, char** argv);
}
+274
View File
@@ -0,0 +1,274 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <AzTest/AzTest.h>
#include <AzTest/Platform.h>
#include "aztestrunner.h"
namespace AzTestRunner
{
const int INCORRECT_USAGE = 101;
const int LIB_NOT_FOUND = 102;
const int SYMBOL_NOT_FOUND = 103;
// note that MODULE_SKIPPED is not an error condition, but not 0 to indicate its not the
// same as successfully running tests and finding them.
const int MODULE_SKIPPED = 104;
const char* INTEG_BOOTSTRAP = "AzTestIntegBootstrap";
//! display proper usage of the application
void usage([[maybe_unused]] AZ::Test::Platform& platform)
{
std::stringstream ss;
ss <<
"AzTestRunner\n"
"Runs AZ unit and integration tests. Exit code is the result from GoogleTest.\n"
"\n"
"Usage:\n"
" AzTestRunner.exe <lib> (AzRunUnitTests|AzRunIntegTests) [--integ] [--wait-for-debugger] [--pause-on-completion] [google-test-args]\n"
"\n"
"Options:\n"
" <lib>: the module to test\n"
" <hook>: the name of the aztest hook function to run in the <lib>\n"
" 'AzRunUnitTests' will hook into unit tests\n"
" 'AzRunIntegTests' will hook into integration tests\n"
" --integ: tells runner to bootstrap the engine, needed for integration tests\n"
" Note: you can run unit tests with a bootstrapped engine (AzRunUnitTests --integ),\n"
" but running integration tests without a bootstrapped engine (AzRunIntegTests w/ no --integ) might not work.\n"
" --wait-for-debugger: tells runner to wait for debugger to attach to process (on supported platforms)\n"
" --pause-on-completion: tells the runner to pause after running the tests\n"
" --quiet: disables stdout for minimal output while running tests\n"
"\n"
"Example:\n"
" AzTestRunner.exe CrySystem.dll AzRunUnitTests --pause-on-completion\n"
" AzTestRunner.exe CrySystem.dll AzRunIntegTests --integ\n"
"\n"
"Exit Codes:\n"
" 0 - all tests pass\n"
" 1 - test failure\n"
<< " " << INCORRECT_USAGE << " - incorrect usage (see above)\n"
<< " " << LIB_NOT_FOUND << " - library/dll could not be loaded\n"
<< " " << SYMBOL_NOT_FOUND << " - export symbol not found\n"
<< " " << MODULE_SKIPPED << " - non-integ module was skipped (not an error)\n";
std::cerr << ss.str() << std::endl;
}
//! attempt to run the int X() method exported by the specified library
int wrapped_command_arg_main(int argc, char** argv)
{
AZ::Test::Platform& platform = AZ::Test::GetPlatform();
if (argc < 3)
{
usage(platform);
return INCORRECT_USAGE;
}
// capture positional arguments
// [0] is the program name
std::string lib = argv[1];
std::string symbol = argv[2];
// shift argv parameters down as we don't need lib or symbol anymore
AZ::Test::RemoveParameters(argc, argv, 1, 2);
// capture optional arguments
bool waitForDebugger = false;
bool isInteg = false;
bool pauseOnCompletion = false;
bool quiet = false;
for (int i = 0; i < argc; i++)
{
if (strcmp(argv[i], "--wait-for-debugger") == 0)
{
waitForDebugger = true;
AZ::Test::RemoveParameters(argc, argv, i, i);
i--;
}
else if (strcmp(argv[i], "--integ") == 0)
{
isInteg = true;
AZ::Test::RemoveParameters(argc, argv, i, i);
i--;
}
else if (strcmp(argv[i], "--pause-on-completion") == 0)
{
pauseOnCompletion = true;
AZ::Test::RemoveParameters(argc, argv, i, i);
i--;
}
else if (strcmp(argv[i], "--quiet") == 0)
{
quiet = true;
AZ::Test::RemoveParameters(argc, argv, i, i);
i--;
}
}
if (quiet)
{
AzTestRunner::set_quiet_mode();
}
else
{
const char* cwd = AzTestRunner::get_current_working_directory();
std::cout << "cwd = " << cwd << std::endl;
for (int i = 0; i < argc; i++)
{
std::cout << "arg[" << i << "] " << argv[i] << std::endl;
}
std::cout << "LIB: " << lib << std::endl;
}
// Wait for debugger
if (waitForDebugger)
{
if (platform.SupportsWaitForDebugger())
{
std::cout << "Waiting for debugger..." << std::endl;
platform.WaitForDebugger();
}
else
{
std::cerr << "Warning - platform does not support --wait-for-debugger feature" << std::endl;
}
}
// make sure the module actually has the expected entry point before proceeding.
// it is very expensive to start the bootstrapper.
std::shared_ptr<AZ::Test::IFunctionHandle> testMainFunction;
std::cout << "Loading: " << lib << std::endl;
std::shared_ptr<AZ::Test::IModuleHandle> module = platform.GetModule(lib);
int result = 0;
if (module->IsValid())
{
std::cout << "OKAY Library loaded: " << lib << std::endl;
testMainFunction = module->GetFunction(symbol);
if (!testMainFunction->IsValid())
{
std::cerr << "FAILED to find symbol: " << symbol << std::endl;
result = SYMBOL_NOT_FOUND;
}
else
{
std::cout << "OKAY Symbol found: " << symbol << std::endl;
}
}
else
{
std::cerr << "FAILED to load library: " << lib << std::endl;
result = LIB_NOT_FOUND;
}
// bail out early if the module does not contain the expected entry point or the module could not be loaded.
if (result != 0)
{
module.reset();
if ((isInteg) && (result == SYMBOL_NOT_FOUND))
{
// special case: It is not required to put an INTEG test inside every DLL - so if
// we failed to find the INTEG entry point in this DLL, its not an error.
// its only an error if we find it and there are no tests, or we find it and tests actually
// fail.
std::cerr << "INTEG module has no entry point and will be skipped: " << lib << std::endl;
return MODULE_SKIPPED;
}
return result;
}
platform.SuppressPopupWindows();
// Grab a bootstrapper library if requested
std::shared_ptr<AZ::Test::IModuleHandle> bootstrap;
if (isInteg)
{
bootstrap = platform.GetModule(INTEG_BOOTSTRAP);
if (!bootstrap->IsValid())
{
std::cerr << "FAILED to load bootstrapper" << std::endl;
return LIB_NOT_FOUND;
}
// Initialize the bootstrapper
auto init = bootstrap->GetFunction("Initialize");
if (init->IsValid())
{
int initResult = (*init)();
if (initResult != 0)
{
std::cerr << "Bootstrapper Initialize failed with code " << initResult << ", exiting" << std::endl;
return initResult;
}
}
}
// run the test main function.
if (testMainFunction->IsValid())
{
result = (*testMainFunction)(argc, argv);
std::cout << "OKAY " << symbol << "() returned " << result << std::endl;
testMainFunction.reset();
}
// unload and reset the module here, because it needs to release resources that were used / activated in
// system allocator / etc.
module.reset();
// Shutdown the bootstrapper
if (bootstrap)
{
auto shutdown = bootstrap->GetFunction("Shutdown");
if (shutdown->IsValid())
{
int shutdownResult = (*shutdown)();
if (shutdownResult != 0)
{
std::cerr << "Bootstrapper shutdown failed with code " << shutdownResult << ", exiting" << std::endl;
return shutdownResult;
}
}
bootstrap.reset();
}
if (pauseOnCompletion)
{
AzTestRunner::pause_on_completion();
}
return result;
}
int wrapped_main(int argc/*=0*/, char** argv/*=nullptr*/)
{
if (argc>0 && argv!=nullptr)
{
return wrapped_command_arg_main(argc, argv);
}
else
{
return 0;
}
}
}
+205
View File
@@ -0,0 +1,205 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <AzTest/AzTest.h>
#include <AzTest/Utils.h>
class AzTestRunnerTest
: public ::testing::Test
{
};
//-------------------------------------------------------------------------------------------------
struct EndsWithParam
{
EndsWithParam(std::string arg, std::string ending, bool expected)
: m_arg(arg)
, m_ending(ending)
, m_expected(expected)
{
}
const std::string m_arg;
const std::string m_ending;
const bool m_expected;
};
void PrintTo(const EndsWithParam& p, std::ostream* os)
{
*os << "arg:" << p.m_arg << ", ending:" << p.m_ending << ", expected:" << p.m_expected;
}
class EndsWithTest
: public ::testing::TestWithParam<EndsWithParam>
{
};
TEST_P(EndsWithTest, CallEndsWith)
{
EndsWithParam p = GetParam();
bool b = AZ::Test::EndsWith(p.m_arg, p.m_ending);
ASSERT_EQ(p.m_expected, b);
}
INSTANTIATE_TEST_CASE_P(All, EndsWithTest, ::testing::Values(
EndsWithParam("foo.dll", ".dll", true),
EndsWithParam("foo.dll", ".dxx", false),
EndsWithParam("abcdef", "bcd", false), // value found in middle
EndsWithParam("a", "bcd", false), // pattern too long
EndsWithParam("abc", "", true), // empty pattern
EndsWithParam("", "abc", false), // empty value
EndsWithParam("", "", true) // both empty
));
//-------------------------------------------------------------------------------------------------
struct RemoveParam
{
std::vector<std::string> before;
int startIndex;
int endIndex;
std::vector<std::string> expected;
};
std::ostream& operator<< (std::ostream& os, const RemoveParam& param)
{
os << "before:{";
bool first = true;
for (auto b : param.before)
{
if (!first)
{
os << ", ";
}
os << b;
first = false;
}
os << "}, startIndex:" << param.startIndex << ", endIndex:" << param.endIndex << ", expected:{";
first = true;
for (auto e : param.expected)
{
if (!first)
{
os << ", ";
}
os << e;
first = false;
}
os << "}";
return os;
}
class RemoveParametersTest
: public ::testing::TestWithParam<RemoveParam>
{};
TEST_P(RemoveParametersTest, Foo)
{
const RemoveParam& p = GetParam();
// create "main"-like parameters
int argc = (int)p.before.size();
char** argv = new char*[argc];
for (int i = 0; i < argc; i++)
{
argv[i] = const_cast<char*>(p.before[i].c_str());
}
AZ::Test::RemoveParameters(argc, argv, p.startIndex, p.endIndex);
ASSERT_EQ(p.expected.size(), argc);
for (int i = 0; i < p.expected.size(); i++)
{
std::string actual(argv[i]);
EXPECT_EQ(p.expected[i], actual);
}
// everything beyond the end of the original data is nulled out if it was removed
for (int j = (int)p.expected.size(); j < p.before.size(); j++)
{
EXPECT_TRUE(nullptr == argv[j]);
}
delete[] argv;
}
INSTANTIATE_TEST_CASE_P(All, RemoveParametersTest, ::testing::Values(
RemoveParam { { "a", "b" }, 0, 0, { "b" } } // remove from start
,RemoveParam { { "a", "b" }, 1, 1, { "a" } } // remove from end
,RemoveParam { { "a", "b", "c" }, 1, 1, { "a", "c" } } // remove from middle
,RemoveParam { { "a", "b", "c" }, 1, 99, { "a" } } // remove beyond end
,RemoveParam { { "a", "b", "c" }, -99, 1, { "c" } } // remove before begin
,RemoveParam { { "a", "b", "c" }, -99, 99, { } } // remove all
,RemoveParam { { "a", "b", "c" }, 2, 0, {"a", "b", "c"} } // inverted range doesn't remove anything
));
class AzTestRunnnerGlobalParamsTest
: public ::testing::Test
{
public:
void SetUp() override
{
::testing::Test::SetUp();
m_priorFilter = ::testing::GTEST_FLAG(filter);
::testing::GTEST_FLAG(filter) = "*"; // emulate no command line filter args
}
void TearDown() override
{
::testing::GTEST_FLAG(filter) = m_priorFilter;
::testing::Test::TearDown();
}
std::string m_priorFilter; // std::string to emulate same environment as gtest, not AZ
};
// saves args into compatible with other platforms format (clang is picky)
// but also restores GTEST_FLAG(filter) before and after applying changes to them,
// allowing us to test the effect params have on GTEST_FLAG(filter)
class ScopedArgs
{
public:
ScopedArgs(int argc, const char** const argv)
{
m_savedParams = ::testing::GTEST_FLAG(filter);
m_argc = argc;
m_argv = new char*[argc];
for (int i = 0; i < m_argc; i++)
{
m_argv[i] = const_cast<char*>(argv[i]);
}
}
~ScopedArgs()
{
delete[] m_argv;
::testing::GTEST_FLAG(filter) = m_savedParams;
}
int m_argc = 0;
char **m_argv = nullptr;
std::string m_savedParams; // intentional std::string, exists outside of memory alloc area.
private:
ScopedArgs() = delete;
AZ_DISABLE_COPY_MOVE(ScopedArgs);
};
TEST_F(AzTestRunnnerGlobalParamsTest, ApplyGlobalParameters_NothingSpecial_RemainsUnchanged)
{
const char* argv[] = { "hello", "--world", "test" };
ScopedArgs args(static_cast<int>(AZ_ARRAY_SIZE(argv)), argv );
AZ::Test::ApplyGlobalParameters(&args.m_argc, args.m_argv);
EXPECT_EQ(args.m_argc, 3);
}
AZ_UNIT_TEST_HOOK(DEFAULT_UNIT_TEST_ENV);