Skip to content

Commit 224f6b7

Browse files
authored
Add CI & Unit Tests (#6)
* add googletest submodule to externals * add gtest in cmake * fix typo * update .gitignore * remove tests folder * ignore ds_store files * add old tests fixed, sort of * fix linked SystemConfiguration framework * fix bug with arrayOfStrings. empty value inside string should fail validation * Fix Progression Validation * add ci * Update cmake.yml * fix linux build issue * Update GALinux.cpp * update fix uts * fix uts * Update GAValidatorTests.cpp * Update GAValidator.cpp * Update GAValidatorTests.cpp * Update cmake.yml * Update cmake.yml * Update main.cpp * update ci tests * fix tests for windows
1 parent a6cb476 commit 224f6b7

File tree

17 files changed

+523
-41
lines changed

17 files changed

+523
-41
lines changed

.github/workflows/cmake.yml

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
# This workflow is for a CMake project running on multiple platforms.
2+
# See: https://github.com/actions/starter-workflows/blob/main/ci/cmake-multi-platform.yml
3+
name: CMake Build and Test
4+
5+
on: [push, workflow_dispatch]
6+
7+
jobs:
8+
build:
9+
runs-on: ${{ matrix.os }}
10+
11+
strategy:
12+
# Set fail-fast to false to ensure that feedback is delivered for all matrix combinations. Consider changing this to true when your workflow is stable.
13+
fail-fast: false
14+
15+
# Set up a matrix to run the following 3 configurations:
16+
# 1. <Windows, Release, latest MSVC compiler toolchain on the default runner image, default generator>
17+
# 2. <Linux, Release, latest GCC compiler toolchain on the default runner image, default generator>
18+
# 3. <Linux, Release, latest Clang compiler toolchain on the default runner image, default generator>
19+
#
20+
# To add more build types (Release, Debug, RelWithDebInfo, etc.) customize the build_type list.
21+
matrix:
22+
os: [ubuntu-latest, windows-latest]
23+
build_type: [Release]
24+
c_compiler: [gcc, clang, cl]
25+
include:
26+
- os: windows-latest
27+
c_compiler: cl
28+
cpp_compiler: cl
29+
- os: ubuntu-latest
30+
c_compiler: gcc
31+
cpp_compiler: g++
32+
- os: ubuntu-latest
33+
c_compiler: clang
34+
cpp_compiler: clang++
35+
exclude:
36+
- os: windows-latest
37+
c_compiler: gcc
38+
- os: windows-latest
39+
c_compiler: clang
40+
- os: ubuntu-latest
41+
c_compiler: cl
42+
43+
steps:
44+
- uses: actions/checkout@v4
45+
with:
46+
submodules: true
47+
48+
- name: Set reusable strings
49+
# Turn repeated input strings (such as the build output directory) into step outputs. These step outputs can be used throughout the workflow file.
50+
id: strings
51+
shell: bash
52+
run: |
53+
echo "build-output-dir=${{ github.workspace }}/build" >> "$GITHUB_OUTPUT"
54+
55+
- name: Configure CMake
56+
# Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make.
57+
# See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type
58+
run: >
59+
cmake -B ${{ steps.strings.outputs.build-output-dir }}
60+
-DCMAKE_CXX_COMPILER=${{ matrix.cpp_compiler }}
61+
-DCMAKE_C_COMPILER=${{ matrix.c_compiler }}
62+
-DCMAKE_BUILD_TYPE=${{ matrix.build_type }}
63+
-S ${{ github.workspace }}
64+
65+
- name: Build
66+
# Build your program with the given configuration. Note that --config is needed because the default Windows generator is a multi-config generator (Visual Studio generator).
67+
run: cmake --build ${{ steps.strings.outputs.build-output-dir }} --config ${{ matrix.build_type }}
68+
69+
- name: Test
70+
working-directory: ${{ steps.strings.outputs.build-output-dir }}
71+
# Execute tests defined by the CMake configuration. Note that --build-config is needed because the default Windows generator is a multi-config generator (Visual Studio generator).
72+
# See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail
73+
run: ctest --build-config ${{ matrix.build_type }} --verbose

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,5 @@
3434
# build folders
3535
[Bb]uild/
3636
[Bb]uild_old/
37+
/gtest_build
38+
.DS_Store

.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[submodule "externals/googletest"]
2+
path = externals/googletest
3+
url = https://github.com/google/googletest.git

CMakeLists.txt

Lines changed: 76 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,43 @@ FILE(GLOB_RECURSE CPP_SOURCES
6969

7070
create_source_groups(CPP_SOURCES)
7171

72+
# --------------------------- Detect Platform Automatically --------------------------- #
73+
# Check if the PLATFORM variable was passed in from the command line
74+
if(NOT DEFINED PLATFORM)
75+
message(STATUS "PLATFORM not set. Detecting platform...")
76+
77+
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
78+
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
79+
set(PLATFORM "linux_x64")
80+
else()
81+
set(PLATFORM "linux_x86")
82+
endif()
83+
84+
elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
85+
# macOS
86+
set(PLATFORM "osx")
87+
88+
elseif(CMAKE_SYSTEM_NAME STREQUAL "Windows")
89+
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
90+
set(PLATFORM "win64")
91+
elseif(CMAKE_SYSTEM_VERSION MATCHES "10.0")
92+
# UWP platform
93+
set(PLATFORM "uwp")
94+
else()
95+
set(PLATFORM "win32")
96+
endif()
97+
98+
else()
99+
message(FATAL_ERROR "Unsupported platform: ${CMAKE_SYSTEM_NAME}")
100+
endif()
101+
102+
message(STATUS "Auto-detected platform: ${PLATFORM}")
103+
else()
104+
message(STATUS "Using user-specified PLATFORM: ${PLATFORM}")
105+
endif()
106+
107+
# --------------------------- END --------------------------- #
108+
72109
if(${GA_USE_PACKAGE})
73110

74111
find_package(CURL REQUIRED PATHS ${EXTERNALS_DIR}/curl)
@@ -122,7 +159,7 @@ elseif(APPLE)
122159
"-framework CoreFoundation"
123160
"-framework Foundation"
124161
"-framework CoreServices"
125-
"-framework systemconfiguration"
162+
"-framework SystemConfiguration"
126163
)
127164

128165
create_source_groups(MACOS_SOURCES)
@@ -137,3 +174,41 @@ endif()
137174

138175
add_library(GameAnalytics ${LIB_TYPE} ${CPP_SOURCES})
139176
target_link_libraries(GameAnalytics PRIVATE ${LIBS} PUBLIC ${PUBLIC_LIBS})
177+
178+
# --------------------------- Google Test Setup --------------------------- #
179+
180+
# Set Project Name
181+
set(UT_PROJECT_NAME "${PROJECT_NAME}UnitTests")
182+
183+
# Add Google Test
184+
set(GTEST_DIR "${EXTERNALS_DIR}/googletest")
185+
add_subdirectory(${GTEST_DIR} ${PROJECT_SOURCE_DIR}/gtest_build)
186+
187+
# Add tests
188+
enable_testing()
189+
190+
########################################
191+
# Test files
192+
########################################
193+
194+
file(GLOB_RECURSE TEST_SRC_FILES "${PROJECT_SOURCE_DIR}/test/*.cpp")
195+
196+
########################################
197+
# Unit Tests
198+
#######################################
199+
add_executable(${UT_PROJECT_NAME} ${TEST_SRC_FILES})
200+
201+
########################################
202+
# Standard linking to gtest and gmock components
203+
########################################
204+
target_link_libraries(${UT_PROJECT_NAME} gtest gtest_main gmock_main)
205+
206+
########################################
207+
# Linking to GA SDK
208+
########################################
209+
target_link_libraries(${UT_PROJECT_NAME} ${PROJECT_NAME})
210+
211+
########################################
212+
213+
add_test(NAME ${UT_PROJECT_NAME} COMMAND GameAnalyticsUnitTests)
214+

externals/googletest

Submodule googletest added at a1e255a

source/gameanalytics/GAValidator.cpp

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -288,7 +288,7 @@ namespace gameanalytics
288288

289289
if (!GAValidator::validateEventPartCharacters(progression))
290290
{
291-
logging::GALogger::w("Validation fail - progression event - progression0%d: Cannot contain other characters than A-z, 0-9, -_., ()!?. String: %s", progressionLvl + 1, progression.c_str());
291+
logging::GALogger::w("Validation fail - progression event - progression0%d: Cannot contain other characters than A-z, 0-9, -_., ()!?. String:\"%s\"", progressionLvl + 1, progression.c_str());
292292
out.category = http::EGASdkErrorCategory::EventValidation;
293293
out.area = http::EGASdkErrorArea::ProgressionEvent;
294294
out.action = http::EGASdkErrorAction::InvalidEventPartCharacters;
@@ -332,16 +332,12 @@ namespace gameanalytics
332332
return;
333333
}
334334

335-
if(!validateProgressionString(progression01, out, 0))
336-
return;
337-
338-
if(!validateProgressionString(progression02, out, 1))
339-
return;
340-
341-
if(!validateProgressionString(progression03, out, 2))
342-
return;
335+
bool isProgression01Valid = validateProgressionString(progression01, out, 0);
336+
bool isProgression02Valid = validateProgressionString(progression02, out, 1);
337+
bool isProgression03Valid = validateProgressionString(progression03, out, 2);
338+
339+
out.result = isProgression01Valid || (isProgression01Valid && isProgression02Valid) || (isProgression01Valid && isProgression02Valid && isProgression03Valid);
343340

344-
out.result = true;
345341
}
346342

347343

@@ -704,7 +700,8 @@ namespace gameanalytics
704700
{
705701
if(str.empty())
706702
{
707-
logging::GALogger::w("[%s] Failed array validation, empty value inside the array", logTag.c_str());
703+
logging::GALogger::w("[%s] Failed array validation, empty value inside the array", logTag.c_str());
704+
return false;
708705
}
709706

710707
if(str.length() > maxStringLength)
@@ -720,6 +717,9 @@ namespace gameanalytics
720717
bool GAValidator::validateClientTs(int64_t clientTs)
721718
{
722719
constexpr int64_t k_maxTs = 99999999999;
720+
721+
logging::GALogger::d("clientTs = %lld", clientTs);
722+
723723
if (clientTs < 0 || clientTs > k_maxTs)
724724
{
725725
return false;

source/gameanalytics/Platform/GALinux.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,7 @@
55
#include "GAState.h"
66

77
#include <execinfo.h>
8-
#include <sys/sysctl.h>
98
#include <sys/utsname.h>
10-
#include <mach/mach.h>
119
#include <sys/stat.h>
1210
#include <unistd.h>
1311
#include <sys/sysinfo.h>

source/gameanalytics/Platform/GALinux.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
#include <signal.h>
88
#include <sys/types.h>
99
#include <sys/stat.h>
10-
#include <sys/sysctl.h>
10+
#include <linux/sysctl.h>
1111
#include <sys/utsname.h>
1212

1313
namespace gameanalytics

test/GAStateTests.cpp

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
//
2+
// GA-SDK-CPP
3+
// Copyright 2015 GameAnalytics. All rights reserved.
4+
//
5+
6+
#include <gtest/gtest.h>
7+
#include <gmock/gmock.h>
8+
9+
#include <GAState.h>
10+
//#include "rapidjson/document.h"
11+
//
12+
//#include "helpers/GATestHelpers.h"
13+
//
14+
//TEST(GAStateTest, testValidateAndCleanCustomFields)
15+
//{
16+
// rapidjson::Document map;
17+
// rapidjson::Value v;
18+
//
19+
// {
20+
// v = rapidjson::Value();
21+
// map.SetObject();
22+
// rapidjson::Document::AllocatorType& a = map.GetAllocator();
23+
// while(map.MemberCount() < 100)
24+
// {
25+
// map.AddMember(rapidjson::Value(GATestHelpers::getRandomString(4).c_str(), a), rapidjson::Value(GATestHelpers::getRandomString(4).c_str(), a), a);
26+
// }
27+
// }
28+
// ASSERT_EQ(100, map.MemberCount());
29+
// gameanalytics::state::GAState::validateAndCleanCustomFields(map, v);
30+
// ASSERT_TRUE(v.MemberCount() == 50);
31+
//
32+
// {
33+
// v = rapidjson::Value();
34+
// map.SetObject();
35+
// rapidjson::Document::AllocatorType& a = map.GetAllocator();
36+
// while(map.MemberCount() < 50)
37+
// {
38+
// map.AddMember(rapidjson::Value(GATestHelpers::getRandomString(4).c_str(), a), rapidjson::Value(GATestHelpers::getRandomString(4).c_str(), a), a);
39+
// }
40+
// }
41+
// ASSERT_EQ(50, map.MemberCount());
42+
// gameanalytics::state::GAState::validateAndCleanCustomFields(map, v);
43+
// ASSERT_EQ(50, v.MemberCount());
44+
//
45+
// {
46+
// v = rapidjson::Value();
47+
// map.SetObject();
48+
// rapidjson::Document::AllocatorType& a = map.GetAllocator();
49+
// map.AddMember(rapidjson::Value(GATestHelpers::getRandomString(4).c_str(), a), rapidjson::Value("", a), a);
50+
// }
51+
// gameanalytics::state::GAState::validateAndCleanCustomFields(map, v);
52+
// ASSERT_TRUE(v.MemberCount() == 0);
53+
//
54+
// {
55+
// v = rapidjson::Value();
56+
// map.SetObject();
57+
// rapidjson::Document::AllocatorType& a = map.GetAllocator();
58+
// map.AddMember(rapidjson::Value(GATestHelpers::getRandomString(4).c_str(), a), rapidjson::Value(GATestHelpers::getRandomString(257).c_str(), a), a);
59+
// }
60+
// gameanalytics::state::GAState::validateAndCleanCustomFields(map, v);
61+
// ASSERT_TRUE(v.MemberCount() == 0);
62+
//
63+
// {
64+
// v = rapidjson::Value();
65+
// map.SetObject();
66+
// rapidjson::Document::AllocatorType& a = map.GetAllocator();
67+
// map.AddMember("", rapidjson::Value(GATestHelpers::getRandomString(4).c_str(), a), a);
68+
// }
69+
// gameanalytics::state::GAState::validateAndCleanCustomFields(map, v);
70+
// ASSERT_TRUE(v.MemberCount() == 0);
71+
//
72+
// {
73+
// v = rapidjson::Value();
74+
// map.SetObject();
75+
// rapidjson::Document::AllocatorType& a = map.GetAllocator();
76+
// map.AddMember(rapidjson::Value("___", a), rapidjson::Value(GATestHelpers::getRandomString(4).c_str(), a), a);
77+
// }
78+
// gameanalytics::state::GAState::validateAndCleanCustomFields(map, v);
79+
// ASSERT_TRUE(v.MemberCount() == 1);
80+
//
81+
// {
82+
// v = rapidjson::Value();
83+
// map.SetObject();
84+
// rapidjson::Document::AllocatorType& a = map.GetAllocator();
85+
// map.AddMember(rapidjson::Value("_&_", a), rapidjson::Value(GATestHelpers::getRandomString(4).c_str(), a), a);
86+
// }
87+
// gameanalytics::state::GAState::validateAndCleanCustomFields(map, v);
88+
// ASSERT_TRUE(v.MemberCount() == 0);
89+
//
90+
// {
91+
// v = rapidjson::Value();
92+
// map.SetObject();
93+
// rapidjson::Document::AllocatorType& a = map.GetAllocator();
94+
// map.AddMember(rapidjson::Value(GATestHelpers::getRandomString(65).c_str(), a), rapidjson::Value(GATestHelpers::getRandomString(4).c_str(), a), a);
95+
// }
96+
// gameanalytics::state::GAState::validateAndCleanCustomFields(map, v);
97+
// ASSERT_TRUE(v.MemberCount() == 0);
98+
//
99+
// {
100+
// v = rapidjson::Value();
101+
// map.SetObject();
102+
// rapidjson::Document::AllocatorType& a = map.GetAllocator();
103+
// map.AddMember(rapidjson::Value(GATestHelpers::getRandomString(4).c_str(), a), rapidjson::Value(100), a);
104+
// }
105+
// gameanalytics::state::GAState::validateAndCleanCustomFields(map, v);
106+
// ASSERT_TRUE(v.MemberCount() == 1);
107+
//
108+
// {
109+
// v = rapidjson::Value();
110+
// map.SetObject();
111+
// rapidjson::Document::AllocatorType& a = map.GetAllocator();
112+
// map.AddMember(rapidjson::Value(GATestHelpers::getRandomString(4).c_str(), a), rapidjson::Value(true), a);
113+
// }
114+
// gameanalytics::state::GAState::validateAndCleanCustomFields(map, v);
115+
// ASSERT_TRUE(v.MemberCount() == 0);
116+
//}
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@
33
// Copyright 2015 GameAnalytics. All rights reserved.
44
//
55

6-
#include <gtest/gtest.h>
76
#include <gmock/gmock.h>
7+
#include <gtest/gtest.h>
8+
89
#include <string>
910
#include <vector>
1011

0 commit comments

Comments
 (0)