[Unit Test] Server version mismatch
[Unit Test] Empty required server version API and curl changes
This commit is contained in:
@@ -3,9 +3,10 @@
|
|||||||
|
|
||||||
using namespace Sia::Api;
|
using namespace Sia::Api;
|
||||||
|
|
||||||
CSiaApi::CSiaApi(const String& host, const std::uint16_t& port) :
|
CSiaApi::CSiaApi(const SiaHostConfig& hostConfig) :
|
||||||
_wallet(new CSiaWallet())
|
_wallet(new CSiaWallet(_siaCurl))
|
||||||
{
|
{
|
||||||
|
_siaCurl.SetHostConfig(hostConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
CSiaApi::~CSiaApi()
|
CSiaApi::~CSiaApi()
|
||||||
@@ -13,6 +14,11 @@ CSiaApi::~CSiaApi()
|
|||||||
_wallet->Unlock();
|
_wallet->Unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String CSiaApi::GetServerVersion() const
|
||||||
|
{
|
||||||
|
return _siaCurl.GetServerVersion();
|
||||||
|
}
|
||||||
|
|
||||||
CSiaWalletPtr CSiaApi::GetWallet() const
|
CSiaWalletPtr CSiaApi::GetWallet() const
|
||||||
{
|
{
|
||||||
return _wallet;
|
return _wallet;
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "SiaCommon.h"
|
#include "SiaCommon.h"
|
||||||
|
#include "SiaCurl.h"
|
||||||
|
|
||||||
NS_BEGIN(Sia)
|
NS_BEGIN(Sia)
|
||||||
NS_BEGIN(Api)
|
NS_BEGIN(Api)
|
||||||
@@ -7,7 +8,8 @@ NS_BEGIN(Api)
|
|||||||
class AFX_EXT_CLASS CSiaApi
|
class AFX_EXT_CLASS CSiaApi
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
enum class _SiaApiError {
|
enum class _SiaApiError
|
||||||
|
{
|
||||||
Success,
|
Success,
|
||||||
NotImplemented,
|
NotImplemented,
|
||||||
WalletLocked,
|
WalletLocked,
|
||||||
@@ -19,11 +21,14 @@ public:
|
|||||||
{
|
{
|
||||||
friend CSiaApi;
|
friend CSiaApi;
|
||||||
private:
|
private:
|
||||||
_CSiaWallet();
|
_CSiaWallet(CSiaCurl& siaCurl);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
~_CSiaWallet();
|
~_CSiaWallet();
|
||||||
|
|
||||||
|
private:
|
||||||
|
CSiaCurl& _siaCurl;
|
||||||
|
|
||||||
// Properties
|
// Properties
|
||||||
Property(bool, Created, public, private)
|
Property(bool, Created, public, private)
|
||||||
Property(bool, Locked, public, private)
|
Property(bool, Locked, public, private)
|
||||||
@@ -36,22 +41,23 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CSiaApi(const String& host, const std::uint16_t& port);
|
CSiaApi(const SiaHostConfig& hostConfig);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
~CSiaApi();
|
~CSiaApi();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
CSiaCurl _siaCurl;
|
||||||
std::shared_ptr<_CSiaWallet> _wallet;
|
std::shared_ptr<_CSiaWallet> _wallet;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
std::shared_ptr<_CSiaWallet> GetWallet() const;
|
std::shared_ptr<_CSiaWallet> GetWallet() const;
|
||||||
|
String GetServerVersion() const;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef CSiaApi::_SiaApiError SiaApiError;
|
typedef CSiaApi::_SiaApiError SiaApiError;
|
||||||
typedef CSiaApi::_CSiaWallet CSiaWallet;
|
typedef CSiaApi::_CSiaWallet CSiaWallet;
|
||||||
typedef std::shared_ptr<CSiaApi::_CSiaWallet> CSiaWalletPtr;
|
typedef std::shared_ptr<CSiaApi::_CSiaWallet> CSiaWalletPtr;
|
||||||
#define API_SUCCESS(x) (x == SiaApiError::Success)
|
|
||||||
|
|
||||||
NS_END(2)
|
NS_END(2)
|
@@ -32,6 +32,9 @@ set_access:\
|
|||||||
|
|
||||||
struct SiaHostConfig
|
struct SiaHostConfig
|
||||||
{
|
{
|
||||||
std::string HostName;
|
String HostName;
|
||||||
std::uint16_t HostPort;
|
std::uint16_t HostPort;
|
||||||
};
|
String RequiredVersion;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define API_SUCCESS(t, x) (x == t::Success)
|
@@ -1,12 +1,13 @@
|
|||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
#include "SiaCurl.h"
|
#include "SiaCurl.h"
|
||||||
#include <curl\curl.h>
|
#include <curl/curl.h>
|
||||||
using namespace Sia::Api;
|
using namespace Sia::Api;
|
||||||
|
|
||||||
CSiaCurl::CSiaCurl() :
|
CSiaCurl::CSiaCurl() :
|
||||||
_curlHandle(curl_easy_init())
|
_curlHandle(curl_easy_init())
|
||||||
{
|
{
|
||||||
SetHostConfig({ "localhost", 9980 });
|
SetHostConfig({ L"localhost", 9980, L""});
|
||||||
|
curl_easy_setopt(_curlHandle, CURLOPT_USERAGENT, "Sia-Agent");
|
||||||
}
|
}
|
||||||
|
|
||||||
CSiaCurl::~CSiaCurl()
|
CSiaCurl::~CSiaCurl()
|
||||||
@@ -14,31 +15,73 @@ CSiaCurl::~CSiaCurl()
|
|||||||
curl_easy_cleanup(_curlHandle);
|
curl_easy_cleanup(_curlHandle);
|
||||||
}
|
}
|
||||||
|
|
||||||
CStringA CSiaCurl::ConstructPath(const CString& relativePath) const
|
SiaCurlError CSiaCurl::_Get(const String& path, json& response) const
|
||||||
{
|
{
|
||||||
const CStringA ret = CStringA("http://") + GetHostConfig().HostName.c_str() + ":" + std::to_string(GetHostConfig().HostPort).c_str() + CW2A(relativePath);
|
std::string result;
|
||||||
|
SiaCurlError ret = SiaCurlError::Success;
|
||||||
|
if (API_SUCCESS(SiaCurlError, ret))
|
||||||
|
{
|
||||||
|
curl_easy_setopt(_curlHandle, CURLOPT_URL, ConstructPath(path).c_str());
|
||||||
|
curl_easy_setopt(_curlHandle, CURLOPT_WRITEFUNCTION, static_cast<size_t(*)(char*, size_t, size_t, void *)>([](char *buffer, size_t size, size_t nitems, void *outstream) -> size_t
|
||||||
|
{
|
||||||
|
(*reinterpret_cast<std::string*>(outstream)) += std::string(reinterpret_cast<LPCSTR>(buffer), size * nitems);
|
||||||
|
return size * nitems;
|
||||||
|
}));
|
||||||
|
curl_easy_setopt(_curlHandle, CURLOPT_WRITEDATA, &result);
|
||||||
|
const CURLcode res = curl_easy_perform(_curlHandle);
|
||||||
|
if (res != CURLE_OK)
|
||||||
|
{
|
||||||
|
ret = SiaCurlError::Failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
response = json::parse(result.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
SiaCurlError CSiaCurl::Get(const CString& path, json& response)
|
bool CSiaCurl::CheckVersion(SiaCurlError& error) const
|
||||||
{
|
{
|
||||||
CStringA result;
|
error = SiaCurlError::InvalidRequiredVersion;
|
||||||
SiaCurlError ret = SiaCurlError::Success;
|
if (GetHostConfig().RequiredVersion.length())
|
||||||
curl_easy_setopt(_curlHandle, CURLOPT_USERAGENT, "Sia-Agent");
|
|
||||||
curl_easy_setopt(_curlHandle, CURLOPT_URL, static_cast<LPCSTR>(ConstructPath(path)));
|
|
||||||
curl_easy_setopt(_curlHandle, CURLOPT_WRITEFUNCTION, static_cast<size_t(*)(char*, size_t, size_t, void *)>([](char *buffer, size_t size, size_t nitems, void *outstream) -> size_t
|
|
||||||
{
|
{
|
||||||
(*reinterpret_cast<CStringA*>(outstream)) += CString(reinterpret_cast<LPCSTR>(buffer), size * nitems);
|
error = SiaCurlError::NoResponse;
|
||||||
return size * nitems;
|
const String serverVersion = GetServerVersion();
|
||||||
}));
|
if (serverVersion.length())
|
||||||
curl_easy_setopt(_curlHandle, CURLOPT_WRITEDATA, &result);
|
{
|
||||||
const CURLcode res = curl_easy_perform(_curlHandle);
|
error = (serverVersion == GetHostConfig().RequiredVersion) ? SiaCurlError::Success : SiaCurlError::ServerVersionMismatch;
|
||||||
if (res != CURLE_OK)
|
}
|
||||||
{
|
|
||||||
ret = SiaCurlError::Failed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
response = json::parse((LPCSTR)result);
|
return API_SUCCESS(SiaCurlError, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string CSiaCurl::ConstructPath(const String& relativePath) const
|
||||||
|
{
|
||||||
|
const std::string ret = "http://" + std::string(CW2A(GetHostConfig().HostName.c_str()))+ ":" + std::to_string(GetHostConfig().HostPort) + std::string(CW2A(relativePath.c_str()));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
String CSiaCurl::GetServerVersion() const
|
||||||
|
{
|
||||||
|
json response;
|
||||||
|
if (API_SUCCESS(SiaCurlError, _Get(L"/daemon/version", response)))
|
||||||
|
{
|
||||||
|
return String(CA2W(response["version"].get<std::string>().c_str()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return L"";
|
||||||
|
}
|
||||||
|
|
||||||
|
SiaCurlError CSiaCurl::Get(const String& path, json& response) const
|
||||||
|
{
|
||||||
|
std::string result;
|
||||||
|
|
||||||
|
SiaCurlError ret;
|
||||||
|
if (CheckVersion(ret))
|
||||||
|
{
|
||||||
|
ret = _Get(path, response);
|
||||||
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
@@ -12,6 +12,9 @@ public:
|
|||||||
enum class _SiaCurlError
|
enum class _SiaCurlError
|
||||||
{
|
{
|
||||||
Success,
|
Success,
|
||||||
|
ServerVersionMismatch,
|
||||||
|
InvalidRequiredVersion,
|
||||||
|
NoResponse,
|
||||||
Failed
|
Failed
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -27,10 +30,13 @@ private:
|
|||||||
Property(SiaHostConfig, HostConfig, public, public)
|
Property(SiaHostConfig, HostConfig, public, public)
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CStringA ConstructPath(const CString& relativePath) const;
|
std::string ConstructPath(const String& relativePath) const;
|
||||||
|
_SiaCurlError _Get(const String& path, json& response) const;
|
||||||
|
bool CheckVersion(_SiaCurlError& error) const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
_SiaCurlError Get(const CString& path, json& result);
|
String GetServerVersion() const;
|
||||||
|
_SiaCurlError Get(const String& path, json& result) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef CSiaCurl::_SiaCurlError SiaCurlError;
|
typedef CSiaCurl::_SiaCurlError SiaCurlError;
|
||||||
|
@@ -3,7 +3,10 @@
|
|||||||
|
|
||||||
using namespace Sia::Api;
|
using namespace Sia::Api;
|
||||||
|
|
||||||
CSiaApi::_CSiaWallet::_CSiaWallet()
|
CSiaApi::_CSiaWallet::_CSiaWallet(CSiaCurl& siaCurl) :
|
||||||
|
_siaCurl(siaCurl),
|
||||||
|
_Created(false),
|
||||||
|
_Locked(false)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -28,7 +31,7 @@ SiaApiError CSiaApi::_CSiaWallet::Restore(const String& seed)
|
|||||||
SiaApiError CSiaApi::_CSiaWallet::Lock()
|
SiaApiError CSiaApi::_CSiaWallet::Lock()
|
||||||
{
|
{
|
||||||
SiaApiError error = GetCreated() ? (GetLocked() ? SiaApiError::WalletLocked : SiaApiError::Success) : SiaApiError::WalletNotCreated;
|
SiaApiError error = GetCreated() ? (GetLocked() ? SiaApiError::WalletLocked : SiaApiError::Success) : SiaApiError::WalletNotCreated;
|
||||||
if (API_SUCCESS(error))
|
if (API_SUCCESS(SiaApiError, error))
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -38,7 +41,7 @@ SiaApiError CSiaApi::_CSiaWallet::Lock()
|
|||||||
SiaApiError CSiaApi::_CSiaWallet::Unlock()
|
SiaApiError CSiaApi::_CSiaWallet::Unlock()
|
||||||
{
|
{
|
||||||
SiaApiError error = GetCreated() ? (GetLocked() ? SiaApiError::Success : SiaApiError::WalletUnlocked) : SiaApiError::WalletNotCreated;
|
SiaApiError error = GetCreated() ? (GetLocked() ? SiaApiError::Success : SiaApiError::WalletUnlocked) : SiaApiError::WalletNotCreated;
|
||||||
if (API_SUCCESS(error))
|
if (API_SUCCESS(SiaApiError, error))
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -29,6 +29,12 @@ SOFTWARE.
|
|||||||
#ifndef NLOHMANN_JSON_HPP
|
#ifndef NLOHMANN_JSON_HPP
|
||||||
#define NLOHMANN_JSON_HPP
|
#define NLOHMANN_JSON_HPP
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#ifdef max
|
||||||
|
#undef max
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <algorithm> // all_of, for_each, transform
|
#include <algorithm> // all_of, for_each, transform
|
||||||
#include <array> // array
|
#include <array> // array
|
||||||
#include <cassert> // assert
|
#include <cassert> // assert
|
||||||
|
@@ -13,12 +13,31 @@ namespace UnitTests
|
|||||||
TEST_METHOD(GetBasicTest)
|
TEST_METHOD(GetBasicTest)
|
||||||
{
|
{
|
||||||
CSiaCurl s;
|
CSiaCurl s;
|
||||||
s.SetHostConfig({ "localhost", 9980 });
|
s.SetHostConfig({ L"localhost", 9980, L"1.1.0" });
|
||||||
|
|
||||||
json result;
|
json result;
|
||||||
SiaCurlError err = s.Get(L"/daemon/version", result);
|
SiaCurlError err = s.Get(L"/daemon/version", result);
|
||||||
Assert::IsTrue(err == SiaCurlError::Success);
|
Assert::IsTrue(err == SiaCurlError::Success);
|
||||||
Assert::IsTrue(result["version"].is_string());
|
}
|
||||||
|
|
||||||
|
TEST_METHOD(EmptyHostConfigRequiredVersion)
|
||||||
|
{
|
||||||
|
CSiaCurl s;
|
||||||
|
s.SetHostConfig({ L"localhost", 9980, L"" });
|
||||||
|
|
||||||
|
json result;
|
||||||
|
SiaCurlError err = s.Get(L"/daemon/version", result);
|
||||||
|
Assert::IsTrue(err == SiaCurlError::InvalidRequiredVersion);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_METHOD(ServerVersionDoesNotMatchRequiredVersion)
|
||||||
|
{
|
||||||
|
CSiaCurl s;
|
||||||
|
s.SetHostConfig({ L"localhost", 9980, L"ouaoeuaoeuaoeu" });
|
||||||
|
|
||||||
|
json result;
|
||||||
|
SiaCurlError err = s.Get(L"/daemon/version", result);
|
||||||
|
Assert::IsTrue(err == SiaCurlError::ServerVersionMismatch);
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@@ -45,7 +45,7 @@
|
|||||||
<UseDebugLibraries>true</UseDebugLibraries>
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
<PlatformToolset>v140</PlatformToolset>
|
<PlatformToolset>v140</PlatformToolset>
|
||||||
<CharacterSet>Unicode</CharacterSet>
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
<UseOfMfc>false</UseOfMfc>
|
<UseOfMfc>Dynamic</UseOfMfc>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||||
@@ -53,7 +53,7 @@
|
|||||||
<PlatformToolset>v140</PlatformToolset>
|
<PlatformToolset>v140</PlatformToolset>
|
||||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
<CharacterSet>Unicode</CharacterSet>
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
<UseOfMfc>false</UseOfMfc>
|
<UseOfMfc>Dynamic</UseOfMfc>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||||
<ImportGroup Label="ExtensionSettings">
|
<ImportGroup Label="ExtensionSettings">
|
||||||
@@ -90,7 +90,7 @@
|
|||||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||||
<WarningLevel>Level3</WarningLevel>
|
<WarningLevel>Level3</WarningLevel>
|
||||||
<Optimization>Disabled</Optimization>
|
<Optimization>Disabled</Optimization>
|
||||||
<AdditionalIncludeDirectories>..\SiaDrive.Api;$(VCInstallDir)UnitTest\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>..\SiaDrive.Api;..\SiaDrive.Api;$(VCInstallDir)UnitTest\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
<PreprocessorDefinitions>WIN32;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>WIN32;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
<UseFullPaths>true</UseFullPaths>
|
<UseFullPaths>true</UseFullPaths>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
@@ -106,7 +106,7 @@
|
|||||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||||
<WarningLevel>Level3</WarningLevel>
|
<WarningLevel>Level3</WarningLevel>
|
||||||
<Optimization>Disabled</Optimization>
|
<Optimization>Disabled</Optimization>
|
||||||
<AdditionalIncludeDirectories>$(VCInstallDir)UnitTest\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>..\SiaDrive.Api;$(VCInstallDir)UnitTest\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
<UseFullPaths>true</UseFullPaths>
|
<UseFullPaths>true</UseFullPaths>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
@@ -122,7 +122,7 @@
|
|||||||
<Optimization>MaxSpeed</Optimization>
|
<Optimization>MaxSpeed</Optimization>
|
||||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
<AdditionalIncludeDirectories>..\SiaDrive.Api;$(VCInstallDir)UnitTest\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>..\SiaDrive.Api;..\SiaDrive.Api;$(VCInstallDir)UnitTest\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
<PreprocessorDefinitions>WIN32;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>WIN32;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
<UseFullPaths>true</UseFullPaths>
|
<UseFullPaths>true</UseFullPaths>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
@@ -142,7 +142,7 @@
|
|||||||
<Optimization>MaxSpeed</Optimization>
|
<Optimization>MaxSpeed</Optimization>
|
||||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
<AdditionalIncludeDirectories>$(VCInstallDir)UnitTest\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>..\SiaDrive.Api;$(VCInstallDir)UnitTest\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
<UseFullPaths>true</UseFullPaths>
|
<UseFullPaths>true</UseFullPaths>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
Reference in New Issue
Block a user