From 17f0be4ad2c942d0ecc061f074954e3a0cb41f95 Mon Sep 17 00:00:00 2001 From: Zbigniew Skowron Date: Sun, 15 Aug 2021 14:37:59 +0200 Subject: [PATCH] Added FlaxNativeTests target, with initial suite of tests for String and StingView. --- Source/Engine/TestsMain/Linux/main.cpp | 14 + Source/Engine/TestsMain/StringTests.cpp | 334 +++++++++++++++++++++ Source/Engine/TestsMain/TestsMain.Build.cs | 56 ++++ Source/Engine/TestsMain/Windows/main.cpp | 37 +++ Source/FlaxNativeTests.Build.cs | 60 ++++ 5 files changed, 501 insertions(+) create mode 100644 Source/Engine/TestsMain/Linux/main.cpp create mode 100644 Source/Engine/TestsMain/StringTests.cpp create mode 100644 Source/Engine/TestsMain/TestsMain.Build.cs create mode 100644 Source/Engine/TestsMain/Windows/main.cpp create mode 100644 Source/FlaxNativeTests.Build.cs diff --git a/Source/Engine/TestsMain/Linux/main.cpp b/Source/Engine/TestsMain/Linux/main.cpp new file mode 100644 index 000000000..a3cb4cc41 --- /dev/null +++ b/Source/Engine/TestsMain/Linux/main.cpp @@ -0,0 +1,14 @@ +// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. + +#if PLATFORM_LINUX + +#define CATCH_CONFIG_RUNNER +#include + +int main(int argc, char* argv[]) +{ + int result = Catch::Session().run(argc, argv); + return result; +} + +#endif diff --git a/Source/Engine/TestsMain/StringTests.cpp b/Source/Engine/TestsMain/StringTests.cpp new file mode 100644 index 000000000..c90239b71 --- /dev/null +++ b/Source/Engine/TestsMain/StringTests.cpp @@ -0,0 +1,334 @@ +// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. + + +#include "Engine/Core/Types/String.h" +#include "Engine/Core/Types/StringView.h" + +#include + + +TEST_CASE("String Replace works") { + SECTION("Char, case sensitive") { + String str("hello HELLO"); + CHECK(str.Replace('l', 'x', StringSearchCase::CaseSensitive) == 2); + CHECK(str == String("hexxo HELLO")); + } + + SECTION("Char, ignore case") { + String str("hello HELLO"); + CHECK(str.Replace('l', 'x', StringSearchCase::IgnoreCase) == 4); + CHECK(str == String("hexxo HExxO")); + } + + SECTION("case sensitive") { + String str("hello HELLO this is me saying hello"); + CHECK(str.Replace(TEXT("hello"), TEXT("hi"), StringSearchCase::CaseSensitive) == 2); + CHECK(str == String("hi HELLO this is me saying hi")); + } + + SECTION("ignore case") { + String str("hello HELLO this is me saying hello"); + CHECK(str.Replace(TEXT("hello"), TEXT("hi"), StringSearchCase::IgnoreCase) == 3); + CHECK(str == String("hi hi this is me saying hi")); + } + + SECTION("case sensitive, search and replace texts identical") { + String str("hello HELLO this is me saying hello"); + CHECK(str.Replace(TEXT("hello"), TEXT("hello"), StringSearchCase::CaseSensitive) == 2); + CHECK(str == String("hello HELLO this is me saying hello")); + } + + SECTION("ignore case, search and replace texts identical") { + String str("hello HELLO this is me saying hello"); + CHECK(str.Replace(TEXT("hello"), TEXT("hello"), StringSearchCase::IgnoreCase) == 3); + CHECK(str == String("hello hello this is me saying hello")); + } + + SECTION("case sensitive, replace text empty") { + String str("hello HELLO this is me saying hello"); + CHECK(str.Replace(TEXT("hello"), TEXT(""), StringSearchCase::CaseSensitive) == 2); + CHECK(str == String(" HELLO this is me saying ")); + } + + SECTION("ignore case, replace text empty") { + String str("hello HELLO this is me saying hello"); + CHECK(str.Replace(TEXT("hello"), TEXT(""), StringSearchCase::IgnoreCase) == 3); + CHECK(str == String(" this is me saying ")); + } + + SECTION("no finds") { + String str("hello HELLO this is me saying hello"); + CHECK(str.Replace(TEXT("bye"), TEXT("hi"), StringSearchCase::CaseSensitive) == 0); + CHECK(str.Replace(TEXT("bye"), TEXT("hi"), StringSearchCase::IgnoreCase) == 0); + CHECK(str == String("hello HELLO this is me saying hello")); + } + + SECTION("empty input") { + String str(""); + CHECK(str.Replace(TEXT("bye"), TEXT("hi"), StringSearchCase::CaseSensitive) == 0); + CHECK(str.Replace(TEXT("bye"), TEXT("hi"), StringSearchCase::IgnoreCase) == 0); + CHECK(str == String("")); + } +} + +TEST_CASE("String Starts/EndsWith works") { + SECTION("StartsWith, case sensitive") { + SECTION("Char") { + CHECK(String("").StartsWith('h', StringSearchCase::CaseSensitive) == false); + CHECK(String("hello HELLO").StartsWith('h', StringSearchCase::CaseSensitive) == true); + CHECK(String("hello HELLO").StartsWith('H', StringSearchCase::CaseSensitive) == false); + } + + SECTION("String") { + CHECK(String("hello HELLO").StartsWith(String(TEXT("hello")), StringSearchCase::CaseSensitive) == true); + CHECK(String("hello HELLO").StartsWith(String(TEXT("HELLO")), StringSearchCase::CaseSensitive) == false); + CHECK(String("hello HELLO").StartsWith(String(TEXT("")), StringSearchCase::CaseSensitive) == true); + CHECK(String("hello HELLO").StartsWith(String(TEXT("xxx")), StringSearchCase::CaseSensitive) == false); + + CHECK(String("").StartsWith(String(TEXT("x")), StringSearchCase::CaseSensitive) == false); + CHECK(String("hello HELLO").StartsWith(String(TEXT("hello HELLOx")), StringSearchCase::CaseSensitive) == false); + CHECK(String("hello HELLO").StartsWith(String(TEXT("xhello HELLO")), StringSearchCase::CaseSensitive) == false); + } + + SECTION("StringView") { + CHECK(String("hello HELLO").StartsWith(StringView(TEXT("hello")), StringSearchCase::CaseSensitive) == true); + CHECK(String("hello HELLO").StartsWith(StringView(TEXT("HELLO")), StringSearchCase::CaseSensitive) == false); + CHECK(String("hello HELLO").StartsWith(StringView(), StringSearchCase::CaseSensitive) == true); + CHECK(String("hello HELLO").StartsWith(StringView(TEXT("")), StringSearchCase::CaseSensitive) == true); + CHECK(String("hello HELLO").StartsWith(StringView(TEXT("xxx")), StringSearchCase::CaseSensitive) == false); + + CHECK(String("").StartsWith(StringView(TEXT("x")), StringSearchCase::CaseSensitive) == false); + CHECK(String("hello HELLO").StartsWith(StringView(TEXT("hello HELLOx")), StringSearchCase::CaseSensitive) == false); + CHECK(String("hello HELLO").StartsWith(StringView(TEXT("xhello HELLO")), StringSearchCase::CaseSensitive) == false); + } + } + + SECTION("StartsWith, ignore case") { + SECTION("Char") { + CHECK(String("").StartsWith('h', StringSearchCase::IgnoreCase) == false); + CHECK(String("hello HELLO").StartsWith('h', StringSearchCase::IgnoreCase) == true); + CHECK(String("hello HELLO").StartsWith('H', StringSearchCase::IgnoreCase) == true); + } + + SECTION("String") { + CHECK(String("hello HELLO").StartsWith(String(TEXT("hello")), StringSearchCase::IgnoreCase) == true); + CHECK(String("hello HELLO").StartsWith(String(TEXT("HELLO")), StringSearchCase::IgnoreCase) == true); + CHECK(String("hello HELLO").StartsWith(String(TEXT("")), StringSearchCase::IgnoreCase) == true); + CHECK(String("hello HELLO").StartsWith(String(TEXT("xxx")), StringSearchCase::IgnoreCase) == false); + + CHECK(String("").StartsWith(String(TEXT("x")), StringSearchCase::IgnoreCase) == false); + CHECK(String("hello HELLO").StartsWith(String(TEXT("hello HELLOx")), StringSearchCase::IgnoreCase) == false); + CHECK(String("hello HELLO").StartsWith(String(TEXT("xhello HELLO")), StringSearchCase::IgnoreCase) == false); + } + + SECTION("StringView") { + CHECK(String("hello HELLO").StartsWith(StringView(TEXT("hello")), StringSearchCase::IgnoreCase) == true); + CHECK(String("hello HELLO").StartsWith(StringView(TEXT("HELLO")), StringSearchCase::IgnoreCase) == true); + CHECK(String("hello HELLO").StartsWith(StringView(), StringSearchCase::IgnoreCase) == true); + CHECK(String("hello HELLO").StartsWith(StringView(TEXT("")), StringSearchCase::IgnoreCase) == true); + CHECK(String("hello HELLO").StartsWith(StringView(TEXT("xxx")), StringSearchCase::IgnoreCase) == false); + + CHECK(String("").StartsWith(StringView(TEXT("x")), StringSearchCase::IgnoreCase) == false); + CHECK(String("hello HELLO").StartsWith(StringView(TEXT("hello HELLOx")), StringSearchCase::IgnoreCase) == false); + CHECK(String("hello HELLO").StartsWith(StringView(TEXT("xhello HELLO")), StringSearchCase::IgnoreCase) == false); + } + } + + SECTION("EndsWith, case sensitive") { + SECTION("Char") { + CHECK(String("").EndsWith('h', StringSearchCase::CaseSensitive) == false); + CHECK(String("hello HELLO").EndsWith('O', StringSearchCase::CaseSensitive) == true); + CHECK(String("hello HELLO").EndsWith('o', StringSearchCase::CaseSensitive) == false); + } + + SECTION("String") { + CHECK(String("hello HELLO").EndsWith(String(TEXT("HELLO")), StringSearchCase::CaseSensitive) == true); + CHECK(String("hello HELLO").EndsWith(String(TEXT("hello")), StringSearchCase::CaseSensitive) == false); + CHECK(String("hello HELLO").EndsWith(String(TEXT("")), StringSearchCase::CaseSensitive) == true); + CHECK(String("hello HELLO").EndsWith(String(TEXT("xxx")), StringSearchCase::CaseSensitive) == false); + + CHECK(String("").EndsWith(String(TEXT("x")), StringSearchCase::CaseSensitive) == false); + CHECK(String("hello HELLO").EndsWith(String(TEXT("hello HELLOx")), StringSearchCase::CaseSensitive) == false); + CHECK(String("hello HELLO").EndsWith(String(TEXT("xhello HELLO")), StringSearchCase::CaseSensitive) == false); + } + + SECTION("StringView") { + CHECK(String("hello HELLO").EndsWith(StringView(TEXT("HELLO")), StringSearchCase::CaseSensitive) == true); + CHECK(String("hello HELLO").EndsWith(StringView(TEXT("hello")), StringSearchCase::CaseSensitive) == false); + CHECK(String("hello HELLO").EndsWith(StringView(), StringSearchCase::CaseSensitive) == true); + CHECK(String("hello HELLO").EndsWith(StringView(TEXT("")), StringSearchCase::CaseSensitive) == true); + CHECK(String("hello HELLO").EndsWith(StringView(TEXT("xxx")), StringSearchCase::CaseSensitive) == false); + + CHECK(String("").EndsWith(StringView(TEXT("x")), StringSearchCase::CaseSensitive) == false); + CHECK(String("hello HELLO").EndsWith(StringView(TEXT("hello HELLOx")), StringSearchCase::CaseSensitive) == false); + CHECK(String("hello HELLO").EndsWith(StringView(TEXT("xhello HELLO")), StringSearchCase::CaseSensitive) == false); + } + } + + SECTION("EndsWith, ignore case") { + SECTION("Char") { + CHECK(String("").EndsWith('h', StringSearchCase::IgnoreCase) == false); + CHECK(String("hello HELLO").EndsWith('O', StringSearchCase::IgnoreCase) == true); + CHECK(String("hello HELLO").EndsWith('o', StringSearchCase::IgnoreCase) == true); + } + + SECTION("String") { + CHECK(String("hello HELLO").EndsWith(String(TEXT("HELLO")), StringSearchCase::IgnoreCase) == true); + CHECK(String("hello HELLO").EndsWith(String(TEXT("hello")), StringSearchCase::IgnoreCase) == true); + CHECK(String("hello HELLO").EndsWith(String(TEXT("")), StringSearchCase::IgnoreCase) == true); + CHECK(String("hello HELLO").EndsWith(String(TEXT("xxx")), StringSearchCase::IgnoreCase) == false); + + CHECK(String("").EndsWith(String(TEXT("x")), StringSearchCase::IgnoreCase) == false); + CHECK(String("hello HELLO").EndsWith(String(TEXT("hello HELLOx")), StringSearchCase::IgnoreCase) == false); + CHECK(String("hello HELLO").EndsWith(String(TEXT("xhello HELLO")), StringSearchCase::IgnoreCase) == false); + } + + SECTION("StringView") { + CHECK(String("hello HELLO").EndsWith(StringView(TEXT("HELLO")), StringSearchCase::IgnoreCase) == true); + CHECK(String("hello HELLO").EndsWith(StringView(TEXT("hello")), StringSearchCase::IgnoreCase) == true); + CHECK(String("hello HELLO").EndsWith(StringView(), StringSearchCase::IgnoreCase) == true); + CHECK(String("hello HELLO").EndsWith(StringView(TEXT("")), StringSearchCase::IgnoreCase) == true); + CHECK(String("hello HELLO").EndsWith(StringView(TEXT("xxx")), StringSearchCase::IgnoreCase) == false); + + CHECK(String("").EndsWith(StringView(TEXT("x")), StringSearchCase::IgnoreCase) == false); + CHECK(String("hello HELLO").EndsWith(StringView(TEXT("hello HELLOx")), StringSearchCase::IgnoreCase) == false); + CHECK(String("hello HELLO").EndsWith(StringView(TEXT("xhello HELLO")), StringSearchCase::IgnoreCase) == false); + } + } +} + +TEST_CASE("String Compare works") { + SECTION("String") { + SECTION("case sensitive") { + // Empty strings + CHECK(String("").Compare(String(TEXT("")), StringSearchCase::CaseSensitive) == 0); + CHECK(String("").Compare(String(TEXT("xxx")), StringSearchCase::CaseSensitive) < 0); + CHECK(String("xxx").Compare(String(TEXT("")), StringSearchCase::CaseSensitive) > 0); + + // Equal lengths, difference at end + CHECK(String("xxx").Compare(String(TEXT("xxx")), StringSearchCase::CaseSensitive) == 0); + CHECK(String("abc").Compare(String(TEXT("abd")), StringSearchCase::CaseSensitive) < 0); + CHECK(String("abd").Compare(String(TEXT("abc")), StringSearchCase::CaseSensitive) > 0); + + // Equal lengths, difference in the middle + CHECK(String("abcx").Compare(String(TEXT("abdx")), StringSearchCase::CaseSensitive) < 0); + CHECK(String("abdx").Compare(String(TEXT("abcx")), StringSearchCase::CaseSensitive) > 0); + + // Different lengths, same prefix + CHECK(String("abcxx").Compare(String(TEXT("abc")), StringSearchCase::CaseSensitive) > 0); + CHECK(String("abc").Compare(String(TEXT("abcxx")), StringSearchCase::CaseSensitive) < 0); + + // Different lengths, different prefix + CHECK(String("abcx").Compare(String(TEXT("abd")), StringSearchCase::CaseSensitive) < 0); + CHECK(String("abd").Compare(String(TEXT("abcx")), StringSearchCase::CaseSensitive) > 0); + CHECK(String("abc").Compare(String(TEXT("abdx")), StringSearchCase::CaseSensitive) < 0); + CHECK(String("abdx").Compare(String(TEXT("abc")), StringSearchCase::CaseSensitive) > 0); + + // Case differences + CHECK(String("a").Compare(String(TEXT("A")), StringSearchCase::CaseSensitive) > 0); + CHECK(String("A").Compare(String(TEXT("a")), StringSearchCase::CaseSensitive) < 0); + } + + SECTION("ignore case") { + // Empty strings + CHECK(String("").Compare(String(TEXT("")), StringSearchCase::IgnoreCase) == 0); + CHECK(String("").Compare(String(TEXT("xxx")), StringSearchCase::IgnoreCase) < 0); + CHECK(String("xxx").Compare(String(TEXT("")), StringSearchCase::IgnoreCase) > 0); + + // Equal lengths, difference at end + CHECK(String("xxx").Compare(String(TEXT("xxx")), StringSearchCase::IgnoreCase) == 0); + CHECK(String("abc").Compare(String(TEXT("abd")), StringSearchCase::IgnoreCase) < 0); + CHECK(String("abd").Compare(String(TEXT("abc")), StringSearchCase::IgnoreCase) > 0); + + // Equal lengths, difference in the middle + CHECK(String("abcx").Compare(String(TEXT("abdx")), StringSearchCase::IgnoreCase) < 0); + CHECK(String("abdx").Compare(String(TEXT("abcx")), StringSearchCase::IgnoreCase) > 0); + + // Different lengths, same prefix + CHECK(String("abcxx").Compare(String(TEXT("abc")), StringSearchCase::IgnoreCase) > 0); + CHECK(String("abc").Compare(String(TEXT("abcxx")), StringSearchCase::IgnoreCase) < 0); + + // Different lengths, different prefix + CHECK(String("abcx").Compare(String(TEXT("abd")), StringSearchCase::IgnoreCase) < 0); + CHECK(String("abd").Compare(String(TEXT("abcx")), StringSearchCase::IgnoreCase) > 0); + CHECK(String("abc").Compare(String(TEXT("abdx")), StringSearchCase::IgnoreCase) < 0); + CHECK(String("abdx").Compare(String(TEXT("abc")), StringSearchCase::IgnoreCase) > 0); + + // Case differences + CHECK(String("a").Compare(String(TEXT("A")), StringSearchCase::IgnoreCase) == 0); + CHECK(String("A").Compare(String(TEXT("a")), StringSearchCase::IgnoreCase) == 0); + } + } + + SECTION("StringView") { + SECTION("case sensitive") { + // Null string views + CHECK(StringView().Compare(StringView(), StringSearchCase::CaseSensitive) == 0); + CHECK(StringView().Compare(StringView(TEXT("xxx")), StringSearchCase::CaseSensitive) < 0); + CHECK(StringView(TEXT("xxx")).Compare(StringView(), StringSearchCase::CaseSensitive) > 0); + + // Empty strings + CHECK(StringView(TEXT("")).Compare(StringView(TEXT("")), StringSearchCase::CaseSensitive) == 0); + CHECK(StringView(TEXT("")).Compare(StringView(TEXT("xxx")), StringSearchCase::CaseSensitive) < 0); + CHECK(StringView(TEXT("xxx")).Compare(StringView(TEXT("")), StringSearchCase::CaseSensitive) > 0); + + // Equal lengths, difference at end + CHECK(StringView(TEXT("xxx")).Compare(StringView(TEXT("xxx")), StringSearchCase::CaseSensitive) == 0); + CHECK(StringView(TEXT("abc")).Compare(StringView(TEXT("abd")), StringSearchCase::CaseSensitive) < 0); + CHECK(StringView(TEXT("abd")).Compare(StringView(TEXT("abc")), StringSearchCase::CaseSensitive) > 0); + + // Equal lengths, difference in the middle + CHECK(StringView(TEXT("abcx")).Compare(StringView(TEXT("abdx")), StringSearchCase::CaseSensitive) < 0); + CHECK(StringView(TEXT("abdx")).Compare(StringView(TEXT("abcx")), StringSearchCase::CaseSensitive) > 0); + + // Different lengths, same prefix + CHECK(StringView(TEXT("abcxx")).Compare(StringView(TEXT("abc")), StringSearchCase::CaseSensitive) > 0); + CHECK(StringView(TEXT("abc")).Compare(StringView(TEXT("abcxx")), StringSearchCase::CaseSensitive) < 0); + + // Different lengths, different prefix + CHECK(StringView(TEXT("abcx")).Compare(StringView(TEXT("abd")), StringSearchCase::CaseSensitive) < 0); + CHECK(StringView(TEXT("abd")).Compare(StringView(TEXT("abcx")), StringSearchCase::CaseSensitive) > 0); + CHECK(StringView(TEXT("abc")).Compare(StringView(TEXT("abdx")), StringSearchCase::CaseSensitive) < 0); + CHECK(StringView(TEXT("abdx")).Compare(StringView(TEXT("abc")), StringSearchCase::CaseSensitive) > 0); + + // Case differences + CHECK(StringView(TEXT("a")).Compare(StringView(TEXT("A")), StringSearchCase::CaseSensitive) > 0); + CHECK(StringView(TEXT("A")).Compare(StringView(TEXT("a")), StringSearchCase::CaseSensitive) < 0); + } + + SECTION("ignore case") { + //Null string views + CHECK(StringView().Compare(StringView(), StringSearchCase::IgnoreCase) == 0); + CHECK(StringView().Compare(StringView(TEXT("xxx")), StringSearchCase::IgnoreCase) < 0); + CHECK(StringView(TEXT("xxx")).Compare(StringView(), StringSearchCase::IgnoreCase) > 0); + + // Empty strings + CHECK(StringView(TEXT("")).Compare(StringView(TEXT("")), StringSearchCase::IgnoreCase) == 0); + CHECK(StringView(TEXT("")).Compare(StringView(TEXT("xxx")), StringSearchCase::IgnoreCase) < 0); + CHECK(StringView(TEXT("xxx")).Compare(StringView(TEXT("")), StringSearchCase::IgnoreCase) > 0); + + // Equal lengths, difference at end + CHECK(StringView(TEXT("xxx")).Compare(StringView(TEXT("xxx")), StringSearchCase::IgnoreCase) == 0); + CHECK(StringView(TEXT("abc")).Compare(StringView(TEXT("abd")), StringSearchCase::IgnoreCase) < 0); + CHECK(StringView(TEXT("abd")).Compare(StringView(TEXT("abc")), StringSearchCase::IgnoreCase) > 0); + + // Equal lengths, difference in the middle + CHECK(StringView(TEXT("abcx")).Compare(StringView(TEXT("abdx")), StringSearchCase::IgnoreCase) < 0); + CHECK(StringView(TEXT("abdx")).Compare(StringView(TEXT("abcx")), StringSearchCase::IgnoreCase) > 0); + + // Different lengths, same prefix + CHECK(StringView(TEXT("abcxx")).Compare(StringView(TEXT("abc")), StringSearchCase::IgnoreCase) > 0); + CHECK(StringView(TEXT("abc")).Compare(StringView(TEXT("abcxx")), StringSearchCase::IgnoreCase) < 0); + + // Different lengths, different prefix + CHECK(StringView(TEXT("abcx")).Compare(StringView(TEXT("abd")), StringSearchCase::IgnoreCase) < 0); + CHECK(StringView(TEXT("abd")).Compare(StringView(TEXT("abcx")), StringSearchCase::IgnoreCase) > 0); + CHECK(StringView(TEXT("abc")).Compare(StringView(TEXT("abdx")), StringSearchCase::IgnoreCase) < 0); + CHECK(StringView(TEXT("abdx")).Compare(StringView(TEXT("abc")), StringSearchCase::IgnoreCase) > 0); + + // Case differences + CHECK(StringView(TEXT("a")).Compare(StringView(TEXT("A")), StringSearchCase::IgnoreCase) == 0); + CHECK(StringView(TEXT("A")).Compare(StringView(TEXT("a")), StringSearchCase::IgnoreCase) == 0); + } + } +} diff --git a/Source/Engine/TestsMain/TestsMain.Build.cs b/Source/Engine/TestsMain/TestsMain.Build.cs new file mode 100644 index 000000000..1bb84cefd --- /dev/null +++ b/Source/Engine/TestsMain/TestsMain.Build.cs @@ -0,0 +1,56 @@ +// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. + +using System.Collections.Generic; +using System.IO; +using Flax.Build; +using Flax.Build.NativeCpp; + +/// +/// Application startup module. +/// +public class TestsMain : EngineModule +{ + /// + public override void Setup(BuildOptions options) + { + base.Setup(options); + + // Use source folder per platform group + switch (options.Platform.Target) + { + case TargetPlatform.Windows: + options.SourcePaths.Add(Path.Combine(FolderPath, "Windows")); + + // Visual Leak Detector (https://kinddragon.github.io/vld/) + /*{ + var vldPath = @"C:\Program Files (x86)\Visual Leak Detector"; + var vldBinaries = options.Toolchain.Architecture == TargetArchitecture.x64 ? "Win64" : "Win32"; + var vldBinariesPostfix = options.Toolchain.Architecture == TargetArchitecture.x64 ? "x64" : "x86"; + options.PrivateDefinitions.Add("USE_VLD_MEM_LEAKS_CHECK"); + options.PrivateDefinitions.Add("VLD_FORCE_ENABLE"); + options.PrivateIncludePaths.Add(Path.Combine(vldPath, "include")); + options.OutputFiles.Add(Path.Combine(vldPath, "lib", vldBinaries, "vld.lib")); + options.DependencyFiles.Add(Path.Combine(vldPath, "bin", vldBinaries, "vld_" + vldBinariesPostfix + ".dll")); + options.DependencyFiles.Add(Path.Combine(vldPath, "bin", vldBinaries, "vld_" + vldBinariesPostfix + ".pdb")); + options.DependencyFiles.Add(Path.Combine(vldPath, "bin", vldBinaries, "dbghelp.dll")); + options.DependencyFiles.Add(Path.Combine(vldPath, "bin", vldBinaries, "Microsoft.DTfW.DHL.manifest")); + }*/ + + // Visual Studio memory leaks detection + /*{ + options.PrivateDefinitions.Add("USE_VS_MEM_LEAKS_CHECK"); + }*/ + + break; + case TargetPlatform.Linux: + options.SourcePaths.Add(Path.Combine(FolderPath, "Linux")); + break; + default: throw new InvalidPlatformException(options.Platform.Target); + } + } + + /// + public override void GetFilesToDeploy(List files) + { + } +} diff --git a/Source/Engine/TestsMain/Windows/main.cpp b/Source/Engine/TestsMain/Windows/main.cpp new file mode 100644 index 000000000..21a40090a --- /dev/null +++ b/Source/Engine/TestsMain/Windows/main.cpp @@ -0,0 +1,37 @@ +// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. + +#if PLATFORM_WINDOWS + +#ifdef USE_VLD_MEM_LEAKS_CHECK +#include +#endif +#ifdef USE_VS_MEM_LEAKS_CHECK +#define _CRTDBG_MAP_ALLOC +#include +#include +#else +#include +#endif + +#define CATCH_CONFIG_RUNNER +#include + + +int main(int argc, char* argv[]) +{ +#ifdef USE_VS_MEM_LEAKS_CHECK + // Memory leaks detect inside VS + int flag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG); + flag |= _CRTDBG_LEAK_CHECK_DF | _CRTDBG_ALLOC_MEM_DF; + _CrtSetDbgFlag(flag); +#endif + +#ifdef USE_VLD_MEM_LEAKS_CHECK + VLDGlobalEnable(); +#endif + + int result = Catch::Session().run(argc, argv); + return result; +} + +#endif diff --git a/Source/FlaxNativeTests.Build.cs b/Source/FlaxNativeTests.Build.cs new file mode 100644 index 000000000..4fb9ef0f9 --- /dev/null +++ b/Source/FlaxNativeTests.Build.cs @@ -0,0 +1,60 @@ +// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. + +using System; +using System.IO; +using System.Linq; +using Flax.Build; +using Flax.Build.NativeCpp; + +/// +/// The Flax Editor target that builds standalone tests. +/// +public class FlaxNativeTestsTarget : EngineTarget +{ + /// + public override void Init() + { + base.Init(); + + // Initialize + OutputName = "FlaxNativeTests"; + ConfigurationName = "Tests"; + Platforms = new[] + { + TargetPlatform.Windows, + TargetPlatform.Linux, + }; + Architectures = new[] + { + TargetArchitecture.x64, + TargetArchitecture.x86, + }; + + Modules.Remove("Main"); + Modules.Add("TestsMain"); + } + + /// + public override void SetupTargetEnvironment(BuildOptions options) + { + base.SetupTargetEnvironment(options); + + options.LinkEnv.LinkAsConsoleProgram = true; + + // Setup output folder for Test binaries + var platformName = options.Platform.Target.ToString(); + var architectureName = options.Architecture.ToString(); + var configurationName = options.Configuration.ToString(); + options.OutputFolder = Path.Combine(options.WorkingDirectory, "Binaries", "Tests", platformName, architectureName, configurationName); + } + + /// + public override Target SelectReferencedTarget(ProjectInfo project, Target[] projectTargets) + { + var testTargetName = "FlaxNativeTests"; + var result = projectTargets.FirstOrDefault(x => x.Name == testTargetName); + if (result == null) + throw new Exception("Invalid or missing test target {testTargetName} specified in project {project.Name} (referenced by project {Project.Name})."); + return result; + } +}