[tests] Overhauled generator test suite to re-use "managed" shared test project.
Additionally the test logic is now driven by a Makefile instead of just Premake.
This commit is contained in:
Родитель
88077be14c
Коммит
6fc2759ede
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
local supportdir = path.getabsolute("../support")
|
local supportdir = path.getabsolute("../support")
|
||||||
local catchdir = path.getabsolute("../external/catch")
|
local catchdir = path.getabsolute("../external/catch")
|
||||||
local exepath = path.join("../../build/lib/Debug/MonoEmbeddinator4000.exe")
|
local exepath = "../../../build/lib/Debug/MonoEmbeddinator4000.exe"
|
||||||
|
|
||||||
function SetupTestProject(name, extraFiles)
|
function SetupTestProject(name, extraFiles)
|
||||||
objdir("!obj")
|
objdir("!obj")
|
||||||
|
@ -12,6 +12,7 @@ function SetupTestProject(name, extraFiles)
|
||||||
SetupTestProjectC(name)
|
SetupTestProjectC(name)
|
||||||
SetupTestProjectObjC(name)
|
SetupTestProjectObjC(name)
|
||||||
SetupTestProjectsCSharp(name, nil, extraFiles)
|
SetupTestProjectsCSharp(name, nil, extraFiles)
|
||||||
|
SetupTestProjectsRunner(name)
|
||||||
end
|
end
|
||||||
|
|
||||||
function SetupManagedTestProject()
|
function SetupManagedTestProject()
|
||||||
|
@ -19,7 +20,7 @@ function SetupManagedTestProject()
|
||||||
language "C#"
|
language "C#"
|
||||||
clr "Unsafe"
|
clr "Unsafe"
|
||||||
SetupManagedProject()
|
SetupManagedProject()
|
||||||
location "."
|
location "mk"
|
||||||
end
|
end
|
||||||
|
|
||||||
function SetupTestProjectGenerator()
|
function SetupTestProjectGenerator()
|
||||||
|
@ -30,17 +31,21 @@ function SetupTestProjectGenerator()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function SetupTestProjectGeneratorMake()
|
function SetupTestProjectGeneratorMake(name, dll)
|
||||||
project (name .. ".Gen")
|
project (name .. ".Gen")
|
||||||
location "."
|
location "mk"
|
||||||
kind "Makefile"
|
kind "Makefile"
|
||||||
dependson (name .. ".Managed")
|
dependson (name .. ".Managed")
|
||||||
|
|
||||||
|
if dll == nil then
|
||||||
|
dll = name .. "Managed.dll"
|
||||||
|
end
|
||||||
|
|
||||||
buildcommands
|
buildcommands
|
||||||
{
|
{
|
||||||
"mono --debug " .. exepath .. " -gen=c -out=c -p=macos -compile -target=shared " .. name .. ".Managed.dll",
|
"mono --debug " .. exepath .. " -gen=c -out=c -p=macos -compile -target=shared " .. dll,
|
||||||
"mono --debug " .. exepath .. " -gen=objc -out=objc -p=macos -compile -target=shared " .. name .. ".Managed.dll",
|
"mono --debug " .. exepath .. " -gen=objc -out=objc -p=macos -compile -target=shared " .. dll,
|
||||||
"mono --debug " .. exepath .. " -gen=java -out=java -p=macos -target=shared " .. name .. ".Managed.dll"
|
"mono --debug " .. exepath .. " -gen=java -out=java -p=macos -target=shared " .. dll
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -114,8 +119,7 @@ function SetupTestProjectC(name, depends)
|
||||||
end
|
end
|
||||||
|
|
||||||
project(name .. ".C")
|
project(name .. ".C")
|
||||||
SetupNativeProject()
|
location "mk"
|
||||||
location "."
|
|
||||||
|
|
||||||
kind "SharedLib"
|
kind "SharedLib"
|
||||||
language "C"
|
language "C"
|
||||||
|
@ -125,10 +129,8 @@ function SetupTestProjectC(name, depends)
|
||||||
flags { common_flags }
|
flags { common_flags }
|
||||||
files
|
files
|
||||||
{
|
{
|
||||||
path.join("c", name .. ".Managed.h"),
|
path.join("c", "*.h"),
|
||||||
path.join("c", name .. ".Managed.c"),
|
path.join("c", "*.c"),
|
||||||
path.join(supportdir, "*.h"),
|
|
||||||
path.join(supportdir, "*.c"),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
includedirs { supportdir }
|
includedirs { supportdir }
|
||||||
|
@ -153,21 +155,19 @@ function SetupTestProjectObjC(name, depends)
|
||||||
end
|
end
|
||||||
|
|
||||||
project(name .. ".ObjC")
|
project(name .. ".ObjC")
|
||||||
SetupNativeProject()
|
location "mk"
|
||||||
location "."
|
|
||||||
|
|
||||||
kind "SharedLib"
|
kind "SharedLib"
|
||||||
language "C++"
|
language "C"
|
||||||
|
|
||||||
defines { "MONO_DLL_IMPORT", "MONO_M2N_DLL_EXPORT" }
|
defines { "MONO_DLL_IMPORT", "MONO_M2N_DLL_EXPORT" }
|
||||||
|
|
||||||
flags { common_flags }
|
flags { common_flags }
|
||||||
files
|
files
|
||||||
{
|
{
|
||||||
path.join("objc", name .. ".Managed.h"),
|
path.join("objc", "*.h"),
|
||||||
path.join("objc", name .. ".Managed.mm"),
|
path.join("objc", "*.mm"),
|
||||||
path.join(supportdir, "*.h"),
|
path.join("objc", "*.c"),
|
||||||
path.join(supportdir, "*.c"),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
links { "objc" }
|
links { "objc" }
|
||||||
|
@ -199,11 +199,11 @@ function SetupTestProjectsCSharp(name, depends, extraFiles)
|
||||||
table.insert(linktable, depends .. ".Managed")
|
table.insert(linktable, depends .. ".Managed")
|
||||||
end
|
end
|
||||||
|
|
||||||
links(linktable)
|
links(linktable)
|
||||||
|
end
|
||||||
|
|
||||||
|
function SetupTestProjectsRunner(name)
|
||||||
project(name .. ".Tests")
|
project(name .. ".Tests")
|
||||||
SetupNativeProject()
|
|
||||||
location "."
|
|
||||||
|
|
||||||
language "C++"
|
language "C++"
|
||||||
kind "ConsoleApp"
|
kind "ConsoleApp"
|
||||||
|
@ -229,5 +229,5 @@ function SetupTestProjectsCSharp(name, depends, extraFiles)
|
||||||
filter { "action:vs*" }
|
filter { "action:vs*" }
|
||||||
buildoptions { "/wd4018" } -- eglib signed/unsigned warnings
|
buildoptions { "/wd4018" } -- eglib signed/unsigned warnings
|
||||||
|
|
||||||
filter {}
|
filter {}
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
mk/
|
||||||
|
mk/bin/
|
||||||
|
mk/obj
|
|
@ -1,10 +1,10 @@
|
||||||
#define CATCH_CONFIG_MAIN
|
#define CATCH_CONFIG_MAIN
|
||||||
#include <catch.hpp>
|
#include <catch.hpp>
|
||||||
|
|
||||||
#include "Basic.Managed.h"
|
#include "managed.h"
|
||||||
#include "glib.h"
|
#include "glib.h"
|
||||||
|
|
||||||
TEST_CASE("BuiltinTypes.C", "[C][BuiltinTypes]") {
|
TEST_CASE("Types.C", "[C][Types]") {
|
||||||
BuiltinTypes* bt = BuiltinTypes_new();
|
BuiltinTypes* bt = BuiltinTypes_new();
|
||||||
BuiltinTypes_ReturnsVoid(bt);
|
BuiltinTypes_ReturnsVoid(bt);
|
||||||
REQUIRE(BuiltinTypes_ReturnsBool(bt) == true);
|
REQUIRE(BuiltinTypes_ReturnsBool(bt) == true);
|
||||||
|
@ -48,48 +48,49 @@ TEST_CASE("BuiltinTypes.C", "[C][BuiltinTypes]") {
|
||||||
REQUIRE(strcmp(RefStr->str, "Mono") == 0);
|
REQUIRE(strcmp(RefStr->str, "Mono") == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("ClassTypes", "[C][ClassTypes]") {
|
TEST_CASE("Properties", "[C][Properties]") {
|
||||||
ClassProperties* prop = ClassProperties_new();
|
REQUIRE(Properties_Query_get_UniversalAnswer() == 42);
|
||||||
REQUIRE(ClassProperties_get_Int(prop) == 0);
|
|
||||||
ClassProperties_set_Int(prop, 10);
|
|
||||||
REQUIRE(ClassProperties_get_Int(prop) == 10);
|
|
||||||
|
|
||||||
REQUIRE(ClassProperties_get_ReadOnlyInt(prop) == 0);
|
Properties_Query* prop = Properties_Query_new();
|
||||||
|
REQUIRE(Properties_Query_get_IsGood(prop) == true);
|
||||||
|
REQUIRE(Properties_Query_get_IsBad(prop) == false);
|
||||||
|
|
||||||
|
REQUIRE(Properties_Query_get_Answer(prop) == 42);
|
||||||
|
Properties_Query_set_Answer(prop, 10);
|
||||||
|
REQUIRE(Properties_Query_get_Answer(prop) == 10);
|
||||||
|
|
||||||
|
Properties_Query_set_Secret(prop, 10);
|
||||||
|
REQUIRE(Properties_Query_get_IsSecret(prop) == true);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("StaticTypes.C", "[C][StaticTypes]") {
|
TEST_CASE("Enums.C", "[C][Enums]") {
|
||||||
REQUIRE(NonStaticClass_StaticMethod() == 0);
|
REQUIRE(Enums_EnumTypes_PassEnum(Enum_Two) == 2);
|
||||||
REQUIRE(StaticClass_StaticMethod() == 0);
|
REQUIRE(Enums_EnumTypes_PassEnum(Enum_Three) == 3);
|
||||||
|
|
||||||
|
REQUIRE(Enums_EnumTypes_PassEnumByte(EnumByte_Two) == 2);
|
||||||
|
REQUIRE(Enums_EnumTypes_PassEnumByte(EnumByte_Three) == 3);
|
||||||
|
|
||||||
|
REQUIRE(Enums_EnumTypes_PassEnumFlags(EnumFlags_FlagOne) == (1 << 0));
|
||||||
|
REQUIRE(Enums_EnumTypes_PassEnumFlags(EnumFlags_FlagTwo) == (1 << 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("EnumTypes.C", "[C][EnumTypes]") {
|
TEST_CASE("Arrays.C", "[C][Arrays]") {
|
||||||
REQUIRE(EnumTypes_PassEnum(Enum_Two) == 2);
|
|
||||||
REQUIRE(EnumTypes_PassEnum(Enum_Three) == 3);
|
|
||||||
|
|
||||||
REQUIRE(EnumTypes_PassEnumByte(EnumByte_Two) == 2);
|
|
||||||
REQUIRE(EnumTypes_PassEnumByte(EnumByte_Three) == 3);
|
|
||||||
|
|
||||||
REQUIRE(EnumTypes_PassEnumFlags(EnumFlags_FlagOne) == (1 << 0));
|
|
||||||
REQUIRE(EnumTypes_PassEnumFlags(EnumFlags_FlagTwo) == (1 << 2));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("ArrayTypes.C", "[C][ArrayTypes]") {
|
|
||||||
char _byte_arr[] = { 1, 2, 3 };
|
char _byte_arr[] = { 1, 2, 3 };
|
||||||
_UnsignedcharArray _byte;
|
_UnsignedcharArray _byte;
|
||||||
_byte.array = g_array_sized_new(/*zero_terminated=*/false,
|
_byte.array = g_array_sized_new(/*zero_terminated=*/false,
|
||||||
/*clear=*/true, sizeof(char), G_N_ELEMENTS(_byte_arr));
|
/*clear=*/true, sizeof(char), G_N_ELEMENTS(_byte_arr));
|
||||||
g_array_append_vals (_byte.array, _byte_arr, G_N_ELEMENTS(_byte_arr));
|
g_array_append_vals (_byte.array, _byte_arr, G_N_ELEMENTS(_byte_arr));
|
||||||
|
|
||||||
int _sum = ArrayTypes_SumByteArray(_byte);
|
int _sum = Arrays_ArrayTypes_SumByteArray(_byte);
|
||||||
REQUIRE(_sum == 6);
|
REQUIRE(_sum == 6);
|
||||||
|
|
||||||
_IntArray _int = ArrayTypes_ReturnsIntArray();
|
_IntArray _int = Arrays_ArrayTypes_ReturnsIntArray();
|
||||||
REQUIRE(_int.array->len == 3);
|
REQUIRE(_int.array->len == 3);
|
||||||
REQUIRE(g_array_index(_int.array, int, 0) == 1);
|
REQUIRE(g_array_index(_int.array, int, 0) == 1);
|
||||||
REQUIRE(g_array_index(_int.array, int, 1) == 2);
|
REQUIRE(g_array_index(_int.array, int, 1) == 2);
|
||||||
REQUIRE(g_array_index(_int.array, int, 2) == 3);
|
REQUIRE(g_array_index(_int.array, int, 2) == 3);
|
||||||
|
|
||||||
_CharArray _string = ArrayTypes_ReturnsStringArray();
|
_CharArray _string = Arrays_ArrayTypes_ReturnsStringArray();
|
||||||
REQUIRE(_string.array->len == 3);
|
REQUIRE(_string.array->len == 3);
|
||||||
REQUIRE(strcmp(g_array_index(_string.array, gchar*, 0), "1") == 0);
|
REQUIRE(strcmp(g_array_index(_string.array, gchar*, 0), "1") == 0);
|
||||||
REQUIRE(strcmp(g_array_index(_string.array, gchar*, 1), "2") == 0);
|
REQUIRE(strcmp(g_array_index(_string.array, gchar*, 1), "2") == 0);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#include <catch.hpp>
|
#include <catch.hpp>
|
||||||
|
|
||||||
#include "Basic.Managed.h"
|
#include "managed.h"
|
||||||
#include "glib.h"
|
#include "glib.h"
|
||||||
|
|
||||||
TEST_CASE("BuiltinTypes.ObjC", "[ObjC][BuiltinTypes]") {
|
TEST_CASE("BuiltinTypes.ObjC", "[ObjC][BuiltinTypes]") {
|
||||||
|
|
|
@ -1,120 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
#region Builtin types
|
|
||||||
|
|
||||||
public class BuiltinTypes
|
|
||||||
{
|
|
||||||
public void ReturnsVoid() { }
|
|
||||||
public bool ReturnsBool() { return true; }
|
|
||||||
public sbyte ReturnsSByte() { return -5; }
|
|
||||||
public byte ReturnsByte() { return 5; }
|
|
||||||
public short ReturnsShort() { return -5; }
|
|
||||||
public ushort ReturnsUShort() { return 5; }
|
|
||||||
public int ReturnsInt() { return -5; }
|
|
||||||
public uint ReturnsUInt() { return 5; }
|
|
||||||
public long ReturnsLong() { return -5; }
|
|
||||||
public ulong ReturnsULong() { return 5; }
|
|
||||||
public char ReturnsChar() { return 'a'; }
|
|
||||||
public string ReturnsString() { return "Mono"; }
|
|
||||||
|
|
||||||
public bool PassAndReturnsBool(bool v) { return v; }
|
|
||||||
public sbyte PassAndReturnsSByte(sbyte v) { return v; }
|
|
||||||
public byte PassAndReturnsByte(byte v) { return v; }
|
|
||||||
public short PassAndReturnsShort(short v) { return v; }
|
|
||||||
public ushort PassAndReturnsUShort(ushort v) { return v; }
|
|
||||||
public int PassAndReturnsInt(int v) { return v; }
|
|
||||||
public uint PassAndReturnsUInt(uint v) { return v; }
|
|
||||||
public long PassAndReturnsLong(long v) { return v; }
|
|
||||||
public ulong PassAndReturnsULong(ulong v) { return v; }
|
|
||||||
public char PassAndReturnsChar(char v) { return v; }
|
|
||||||
public string PassAndReturnsString(string v) { return v; }
|
|
||||||
|
|
||||||
public void PassOutInt(out int v) { v = 5; }
|
|
||||||
public void PassRefInt(ref int v) { v = 10; }
|
|
||||||
|
|
||||||
public void PassOutString (out string v) { v = "Mono"; }
|
|
||||||
public void PassRefString (ref string v) { v = "Mono"; }
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Arrays
|
|
||||||
|
|
||||||
public static class ArrayTypes
|
|
||||||
{
|
|
||||||
public static int SumByteArray(byte[] array) { return array.Sum(n => n); }
|
|
||||||
|
|
||||||
public static int[] ReturnsIntArray() { return new int[] { 1, 2, 3 }; }
|
|
||||||
|
|
||||||
public static string[] ReturnsStringArray() { return new string[] { "1", "2", "3" }; }
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Enums
|
|
||||||
|
|
||||||
public enum Enum
|
|
||||||
{
|
|
||||||
Two = 2,
|
|
||||||
Three
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum EnumByte : byte
|
|
||||||
{
|
|
||||||
Two = 2,
|
|
||||||
Three
|
|
||||||
}
|
|
||||||
|
|
||||||
[Flags]
|
|
||||||
public enum EnumFlags
|
|
||||||
{
|
|
||||||
FlagOne = 1 << 0,
|
|
||||||
FlagTwo = 1 << 2
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class EnumTypes
|
|
||||||
{
|
|
||||||
public static int PassEnum(Enum e) { return (int)e; }
|
|
||||||
public static byte PassEnumByte(EnumByte e) { return (byte)e; }
|
|
||||||
public static int PassEnumFlags(EnumFlags e) { return (int)e; }
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Classes
|
|
||||||
|
|
||||||
public class ClassProperties
|
|
||||||
{
|
|
||||||
public int Int { get; set; }
|
|
||||||
public int ReadOnlyInt { get; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public class NonStaticClass
|
|
||||||
{
|
|
||||||
public static int StaticMethod() { return 0; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class StaticClass
|
|
||||||
{
|
|
||||||
public static int StaticMethod() { return 0; }
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace NS1
|
|
||||||
{
|
|
||||||
public class NamespacedClass
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace NS2
|
|
||||||
{
|
|
||||||
public class NamespacedClass
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
.PHONY: all binder managed gen compile run clean
|
||||||
|
MAKEFLAGS += --no-builtin-rules
|
||||||
|
|
||||||
|
all: binder managed gen compile run
|
||||||
|
|
||||||
|
binder:
|
||||||
|
msbuild /nologo /v:minimal ../../build/MonoEmbeddinator4000.sln || xbuild /nologo /v:minimal ../../build/MonoEmbeddinator4000.sln
|
||||||
|
|
||||||
|
EMBEDDINATOR_EXE=../../build/lib/Debug/MonoEmbeddinator4000.exe
|
||||||
|
MANAGED_DLL=../managed/bin/Debug/managed.dll
|
||||||
|
|
||||||
|
gen:
|
||||||
|
mono --debug $(EMBEDDINATOR_EXE) -gen=c -out=c -p=macos -compile -target=shared $(MANAGED_DLL)
|
||||||
|
mono --debug $(EMBEDDINATOR_EXE) -gen=objc -out=objc -p=macos -compile -target=shared $(MANAGED_DLL)
|
||||||
|
mono --debug $(EMBEDDINATOR_EXE) -gen=java -out=java -p=macos -target=shared $(MANAGED_DLL)
|
||||||
|
|
||||||
|
BUILD_FLAGS=/v:minimal /p:DefineConstants="NON_OBJC_SUPPORTED_TESTS"
|
||||||
|
|
||||||
|
managed:
|
||||||
|
BUILD_FLAGS="$(BUILD_FLAGS)" make -C ../managed clean all
|
||||||
|
mkdir -p mk/bin/Debug
|
||||||
|
cp ../managed/bin/Debug/managed.dll* mk/bin/Debug
|
||||||
|
|
||||||
|
compile:
|
||||||
|
../../external/CppSharp/build/premake5-osx gmake
|
||||||
|
make -C mk
|
||||||
|
|
||||||
|
run:
|
||||||
|
mk/bin/Debug/Basic.Tests
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf mk *.dylib Basic.Tests
|
|
@ -1,4 +1,12 @@
|
||||||
group "Tests/Basic"
|
include "Helpers.lua"
|
||||||
name="Basic"
|
include "../../build/Tests.lua"
|
||||||
|
|
||||||
SetupTestProject("Basic")
|
workspace "Basic"
|
||||||
|
configurations { "Debug" }
|
||||||
|
symbols "On"
|
||||||
|
location "mk"
|
||||||
|
|
||||||
|
--SetupTestProjectGeneratorMake("Basic", "managed.dll")
|
||||||
|
SetupTestProjectC("Basic")
|
||||||
|
SetupTestProjectObjC("Basic")
|
||||||
|
SetupTestProjectsRunner("Basic")
|
|
@ -5,17 +5,8 @@ This directory contains the test suite for Embeddinator.
|
||||||
|
|
||||||
To run the test suite, run `RunTestsuite.sh` inside this directory.
|
To run the test suite, run `RunTestsuite.sh` inside this directory.
|
||||||
|
|
||||||
The test suite is composed by a few different projects:
|
The test suite is composed by a few different projects/directories:
|
||||||
|
|
||||||
|
* Basic: common test driver
|
||||||
|
* objc-cli: Objective-C specific test driver
|
||||||
The test suite build files are automatically generated from Premake build scripts.
|
* managed: Managed code test types
|
||||||
|
|
||||||
This makes sure the test suite can be run as part of an MSBuild-based system (VS on Windows)
|
|
||||||
as well as a POSIX-based Make system.
|
|
||||||
|
|
||||||
To re-generate the test suite Make build files, run:
|
|
||||||
|
|
||||||
```
|
|
||||||
../external/CppSharp/build/premake5-osx gmake
|
|
||||||
```
|
|
||||||
|
|
|
@ -1,4 +1,2 @@
|
||||||
CUR_DIR=$(dirname -- $0)
|
CUR_DIR=$(dirname -- $0)
|
||||||
msbuild /nologo /v:minimal $CUR_DIR/../build/MonoEmbeddinator4000.sln || xbuild /nologo /v:minimal $CUR_DIR/../build/MonoEmbeddinator4000.sln
|
make -C $CUR_DIR/Basic
|
||||||
make -C $CUR_DIR
|
|
||||||
$CUR_DIR/Basic/Basic.Tests
|
|
||||||
|
|
|
@ -1,6 +0,0 @@
|
||||||
include "Helpers.lua"
|
|
||||||
include "../build/Tests.lua"
|
|
||||||
|
|
||||||
workspace "EmbeddinatorTestsuite"
|
|
||||||
configurations { "Release" }
|
|
||||||
IncludeDir("../tests")
|
|
Загрузка…
Ссылка в новой задаче