diff --git a/docker/Tests/legacy.tests.ps1 b/docker/Tests/legacy.tests.ps1
index 7629a37..c8229b1 100644
--- a/docker/Tests/legacy.tests.ps1
+++ b/docker/Tests/legacy.tests.ps1
@@ -85,9 +85,11 @@ Describe 'vswhere -legacy' {
$instances[0].installationPath | Should Be 'C:\VisualStudio\14.0'
}
- It '-version is not supported' {
- C:\bin\vswhere.exe -legacy -version 14.0
- $LASTEXITCODE | Should Be 87
+ It '-version is supported' {
+ $instances = C:\bin\vswhere.exe -legacy -latest -format json | ConvertFrom-Json
+ $instances.Count | Should Be 1
+ $instances[0].instanceId | Should Be 'VisualStudio.14.0'
+ $instances[0].installationPath | Should Be 'C:\VisualStudio\14.0'
}
}
diff --git a/src/vswhere.lib/VersionRange.cpp b/src/vswhere.lib/VersionRange.cpp
new file mode 100644
index 0000000..9d3b8c1
--- /dev/null
+++ b/src/vswhere.lib/VersionRange.cpp
@@ -0,0 +1,284 @@
+//
+// Copyright (C) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT license. See LICENSE.txt in the project root for license information.
+//
+
+#include "stdafx.h"
+
+#define _nameof(x) #x
+#define ExitOnFailure(x, s, ...) if (FAILED(x)) { goto Exit; }
+#define ExitOnNull(p, x, e, s, ...) if (NULL == p) { x = e; goto Exit; }
+
+using namespace std;
+
+static locale neutral_locale("C", LC_ALL);
+
+STDMETHODIMP VersionRange::ParseVersion(
+ _In_ LPCOLESTR pwszVersion,
+ _Out_ PULONGLONG pullVersion
+) noexcept
+{
+ HRESULT hr = S_OK;
+ LPWSTR pwszVersionEnd = NULL;
+
+ ExitOnNull(pwszVersion, hr, E_INVALIDARG, "Missing required parameter: %hs", _nameof(pwszVersion));
+ ExitOnNull(pullVersion, hr, E_POINTER, "Output parameter is NULL.");
+
+ *pullVersion = 0;
+
+ LPWSTR pwszVersionRangeEnd = NULL;
+ pwszVersion = Trim(pwszVersion, &pwszVersionEnd);
+
+ if (pwszVersion > pwszVersionEnd)
+ {
+ // Should not be possible but check anyway.
+ ExitOnFailure(hr = E_UNEXPECTED, "Invalid string.");
+ }
+
+ const size_t cchVersion = pwszVersionEnd - pwszVersion;
+ ExitOnNull(cchVersion, hr, E_INVALIDARG, "Version required.");
+
+ hr = ParseVersionString(pwszVersion, pwszVersionEnd, pullVersion);
+ ExitOnFailure(hr, "Failed to parse version: %ls", pwszVersion);
+
+Exit:
+ return hr;
+}
+
+STDMETHODIMP VersionRange::ParseVersionRange(
+ _In_ LPCOLESTR pwszVersionRange,
+ _Out_ PULONGLONG pullMinVersion,
+ _Out_ PULONGLONG pullMaxVersion
+)
+{
+ HRESULT hr = S_OK;
+ ULONGLONG ullMinVersion = MinVersion;
+ ULONGLONG ullMaxVersion = MaxVersion;
+ LPCWSTR pwszVersionStart = NULL;
+ LPCWSTR pwszVersionEnd = NULL;
+ bool sep = false;
+ bool single = false;
+ bool isMinInclusive = true;
+ bool isMaxInclusive = true;
+
+ ExitOnNull(pwszVersionRange, hr, E_INVALIDARG, "Missing required parameter: %hs", _nameof(pwszVersionRange));
+ ExitOnNull(pullMinVersion, hr, E_POINTER, "Output parameter is NULL.");
+ ExitOnNull(pullMaxVersion, hr, E_POINTER, "Output parameter is NULL.");
+
+ *pullMinVersion = 0;
+ *pullMaxVersion = 0;
+
+ LPWSTR pwszVersionRangeEnd = NULL;
+ pwszVersionRange = Trim(pwszVersionRange, &pwszVersionRangeEnd);
+
+ if (pwszVersionRange > pwszVersionRangeEnd)
+ {
+ // Should not be possible but check anyway.
+ ExitOnFailure(hr = E_UNEXPECTED, "Invalid string.");
+ }
+
+ const size_t cchVersionRange = pwszVersionRangeEnd - pwszVersionRange;
+ ExitOnNull(cchVersionRange, hr, E_INVALIDARG, "Version range required.");
+
+ for (size_t i = 0; i < cchVersionRange; ++i)
+ {
+ const auto pwsz = &pwszVersionRange[i];
+ const auto ch = *pwsz;
+
+ if (L'(' == ch || L'[' == ch)
+ {
+ if (0 != i)
+ {
+ ExitOnFailure(hr = E_INVALIDARG, "Invalid format.");
+ }
+ else if (L'(' == ch)
+ {
+ isMinInclusive = false;
+ }
+ }
+ else if (L')' == ch || L']' == ch)
+ {
+ if (cchVersionRange - 1 != i)
+ {
+ ExitOnFailure(hr = E_INVALIDARG, "Invalid format.");
+ }
+ else if (L')' == ch)
+ {
+ isMaxInclusive = false;
+ }
+
+ // Only a single version if the separator was not yet parsed.
+ single = !sep;
+ }
+ else if (L',' == ch)
+ {
+ if (sep)
+ {
+ // Already parsed a separator.
+ ExitOnFailure(hr = E_INVALIDARG, "Invalid format.");
+ }
+
+ sep = true;
+
+ if (pwszVersionEnd > pwszVersionStart)
+ {
+ hr = ParseVersionString(pwszVersionStart, pwszVersionEnd, &ullMinVersion);
+ ExitOnFailure(hr, "Failed to parse version.");
+ }
+
+ pwszVersionStart = NULL;
+ pwszVersionEnd = NULL;
+ }
+ else if (isspace(ch, neutral_locale))
+ {
+ continue;
+ }
+ else if (!pwszVersionStart)
+ {
+ pwszVersionStart = pwsz;
+ pwszVersionEnd = pwsz + 1;
+ }
+ else
+ {
+ pwszVersionEnd = pwsz + 1;
+ }
+ }
+
+ if (pwszVersionEnd > pwszVersionStart)
+ {
+ auto pullVersion = sep ? &ullMaxVersion : &ullMinVersion;
+
+ hr = ParseVersionString(pwszVersionStart, pwszVersionEnd, pullVersion);
+ ExitOnFailure(hr, "Failed to parse version.");
+
+ if (single)
+ {
+ ullMaxVersion = ullMinVersion;
+ }
+ }
+
+ if (!isMinInclusive)
+ {
+ if (_UI64_MAX == ullMinVersion)
+ {
+ ExitOnFailure(hr = E_INVALIDARG, "Arithmetic overflow.");
+ }
+
+ ullMinVersion++;
+ }
+
+ if (!isMaxInclusive)
+ {
+ if (0 == ullMaxVersion)
+ {
+ ExitOnFailure(hr = E_INVALIDARG, "Arithmetic underflow.");
+ }
+
+ ullMaxVersion--;
+ }
+
+ if (ullMinVersion > ullMaxVersion)
+ {
+ ExitOnFailure(hr = E_INVALIDARG, "Min greater than max.");
+ }
+
+ *pullMinVersion = ullMinVersion;
+ *pullMaxVersion = ullMaxVersion;
+
+Exit:
+ return hr;
+}
+
+HRESULT VersionRange::ParseVersionString(
+ _In_ const LPCWSTR pwszVersionBegin,
+ _In_ const LPCWSTR pwszVersionEnd,
+ _Out_ PULONGLONG pullVersion
+)
+{
+ _ASSERT(pwszVersionBegin);
+ _ASSERT(pwszVersionEnd);
+ _ASSERT(pullVersion);
+
+ HRESULT hr = S_OK;
+ LPWSTR pwszFieldBegin = const_cast(pwszVersionBegin);
+ LPWSTR pwszFieldEnd = const_cast(pwszVersionBegin);
+ WORD cFields = 0;
+ ULONG ulField = 0;
+ ULONGLONG ullVersion = 0;
+
+ *pullVersion = 0;
+
+ for (;;)
+ {
+ if (4 <= cFields)
+ {
+ ExitOnFailure(hr = E_INVALIDARG, "Too many version fields.");
+ }
+
+ while (pwszFieldEnd < pwszVersionEnd && L'.' != *pwszFieldEnd)
+ {
+ if (isspace(*pwszFieldEnd, neutral_locale))
+ {
+ ExitOnFailure(hr = E_INVALIDARG, "Space in version field.");
+ }
+
+ ++pwszFieldEnd;
+ }
+
+ if (pwszFieldBegin == pwszFieldEnd)
+ {
+ ExitOnFailure(hr = E_INVALIDARG, "Empty version field.");
+ }
+
+ LPWSTR pwszEnd = NULL;
+ ulField = ::wcstoul(pwszFieldBegin, &pwszEnd, 10);
+
+ if (USHRT_MAX < ulField)
+ {
+ ExitOnFailure(hr = E_INVALIDARG, "Version field too large.");
+ }
+ else if (0 == ulField && pwszEnd != pwszFieldEnd)
+ {
+ ExitOnFailure(hr = E_INVALIDARG, "NaN");
+ }
+
+ pwszFieldEnd = pwszEnd;
+
+ ullVersion |= (ULONGLONG)ulField << ((3 - cFields) * 16);
+ ++cFields;
+
+ if (pwszFieldEnd >= pwszVersionEnd)
+ {
+ break;
+ }
+
+ pwszFieldBegin = ++pwszFieldEnd;
+ }
+
+ *pullVersion = ullVersion;
+
+Exit:
+ return hr;
+}
+
+LPWSTR VersionRange::Trim(
+ _In_ const LPCWSTR pwszValue,
+ _Out_ LPWSTR* ppwszEnd
+) noexcept
+{
+ auto pwszResult = const_cast(pwszValue);
+
+ // Trim left.
+ while (isspace(*pwszResult, neutral_locale))
+ {
+ ++pwszResult;
+ }
+
+ // Trim right.
+ auto cchResult = ::wcslen(pwszResult);
+ for (; cchResult > 0 && isspace(pwszResult[cchResult - 1], neutral_locale); --cchResult);
+
+ // Set end to where terminating null is or would be.
+ *ppwszEnd = &pwszResult[cchResult];
+ return pwszResult;
+}
diff --git a/src/vswhere.lib/VersionRange.h b/src/vswhere.lib/VersionRange.h
new file mode 100644
index 0000000..b3e236c
--- /dev/null
+++ b/src/vswhere.lib/VersionRange.h
@@ -0,0 +1,105 @@
+//
+// Copyright (C) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT license. See LICENSE.txt in the project root for license information.
+//
+
+#pragma once
+
+class VersionRange :
+ public ISetupHelper
+{
+public:
+ VersionRange() noexcept :
+ m_ulRef(1)
+ {
+ }
+
+private:
+ ~VersionRange()
+ {
+ }
+
+public:
+ // IUnknown
+ STDMETHODIMP QueryInterface(
+ _In_ REFIID iid,
+ _Out_ LPVOID* ppUnk
+ )
+ {
+ HRESULT hr = S_OK;
+ IUnknown* pUnk = NULL;
+
+ if (!ppUnk)
+ {
+ return E_POINTER;
+ }
+
+ *ppUnk = NULL;
+ if (iid == __uuidof(ISetupHelper))
+ {
+ pUnk = static_cast(this);
+ }
+ else if (iid == IID_IUnknown)
+ {
+ pUnk = static_cast(this);
+ }
+ else
+ {
+ hr = E_NOINTERFACE;
+ }
+
+ if (pUnk)
+ {
+ pUnk->AddRef();
+ *ppUnk = pUnk;
+ }
+
+ return hr;
+ }
+
+ STDMETHODIMP_(ULONG) AddRef()
+ {
+ return ::InterlockedIncrement(&m_ulRef);
+ }
+
+ STDMETHODIMP_(ULONG) Release()
+ {
+ ULONG ulRef = ::InterlockedDecrement(&m_ulRef);
+ if (ulRef == 0)
+ {
+ delete this;
+ }
+
+ return ulRef;
+ }
+
+public:
+ // ISetupHelper
+ STDMETHOD(ParseVersion)(
+ _In_ LPCOLESTR pwszVersion,
+ _Out_ PULONGLONG pullVersion
+ ) noexcept;
+
+ STDMETHOD(ParseVersionRange)(
+ _In_ LPCOLESTR pwszVersionRange,
+ _Out_ PULONGLONG pullMinVersion,
+ _Out_ PULONGLONG pullMaxVersion
+ );
+
+ static const ULONGLONG MinVersion = 0;
+ static const ULONGLONG MaxVersion = 18446744073709551615;
+
+private:
+ static HRESULT ParseVersionString(
+ _In_ const LPCWSTR pwszVersionBegin,
+ _In_ const LPCWSTR pwszVersionEnd,
+ _Out_ PULONGLONG pullVersion
+ );
+
+ static LPWSTR Trim(
+ _In_ const LPCWSTR pwszValue,
+ _Out_ LPWSTR* ppwszEnd
+ ) noexcept;
+
+ ULONG m_ulRef;
+};
diff --git a/src/vswhere.lib/resource.h b/src/vswhere.lib/resource.h
index 644095f..8b50a12 100644
Binary files a/src/vswhere.lib/resource.h and b/src/vswhere.lib/resource.h differ
diff --git a/src/vswhere.lib/stdafx.h b/src/vswhere.lib/stdafx.h
index 041c8a4..5dc19d7 100644
--- a/src/vswhere.lib/stdafx.h
+++ b/src/vswhere.lib/stdafx.h
@@ -28,6 +28,7 @@
// STL headers
#include
+#include
#include
#include
#include
@@ -69,5 +70,6 @@ _COM_SMARTPTR_TYPEDEF(ISetupInstanceCatalog, __uuidof(ISetupInstanceCatalog));
#include "SafeArray.h"
#include "TextFormatter.h"
#include "ValueFormatter.h"
+#include "VersionRange.h"
#include "XmlScope.h"
#include "XmlFormatter.h"
diff --git a/src/vswhere.lib/vswhere.lib.rc b/src/vswhere.lib/vswhere.lib.rc
index f474f09..3448dd2 100644
Binary files a/src/vswhere.lib/vswhere.lib.rc and b/src/vswhere.lib/vswhere.lib.rc differ
diff --git a/src/vswhere.lib/vswhere.lib.vcxproj b/src/vswhere.lib/vswhere.lib.vcxproj
index 34f6b4f..544d291 100644
--- a/src/vswhere.lib/vswhere.lib.vcxproj
+++ b/src/vswhere.lib/vswhere.lib.vcxproj
@@ -120,6 +120,7 @@
+
@@ -143,6 +144,7 @@
+
diff --git a/src/vswhere.lib/vswhere.lib.vcxproj.filters b/src/vswhere.lib/vswhere.lib.vcxproj.filters
index af05dde..cc144cb 100644
--- a/src/vswhere.lib/vswhere.lib.vcxproj.filters
+++ b/src/vswhere.lib/vswhere.lib.vcxproj.filters
@@ -87,6 +87,9 @@
Header Files
+
+ Header Files
+
@@ -140,6 +143,9 @@
Source Files
+
+ Source Files
+
diff --git a/src/vswhere/Program.cpp b/src/vswhere/Program.cpp
index 92616fd..0afec6b 100644
--- a/src/vswhere/Program.cpp
+++ b/src/vswhere/Program.cpp
@@ -50,11 +50,10 @@ int wmain(_In_ int argc, _In_ LPCWSTR argv[])
{
query->QueryInterface(&helper);
}
-
- if (!args.get_Version().empty() && !query)
+ // Fall back to a copy of the current implementation.
+ else
{
- auto message = ResourceManager::GetString(IDS_E_VERSION);
- throw win32_error(ERROR_INVALID_PARAMETER, message);
+ helper.Attach(new VersionRange);
}
IEnumSetupInstancesPtr e;
diff --git a/test/vswhere.test/VersionRangeTests.cpp b/test/vswhere.test/VersionRangeTests.cpp
new file mode 100644
index 0000000..9a34765
--- /dev/null
+++ b/test/vswhere.test/VersionRangeTests.cpp
@@ -0,0 +1,206 @@
+//
+// Copyright (C) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT license. See LICENSE.txt in the project root for license information.
+//
+
+#include "stdafx.h"
+
+using namespace std;
+using namespace Microsoft::VisualStudio::CppUnitTestFramework;
+
+TEST_CLASS(VersionRangeTests)
+{
+public:
+
+ TEST_METHOD(ParseVersion_pwszVersion_Null)
+ {
+ auto pHelper = new VersionRange;
+ ISetupHelperPtr sut(pHelper, false);
+
+ Assert::AreEqual(E_INVALIDARG, sut->ParseVersion(NULL, NULL));
+ }
+
+ TEST_METHOD(ParseVersion_pullVersion_Null)
+ {
+ auto pHelper = new VersionRange;
+ ISetupHelperPtr sut(pHelper, false);
+
+ Assert::AreEqual(E_POINTER, sut->ParseVersion(L"1.0", NULL));
+ }
+
+ TEST_METHOD(ParseVersion_Major)
+ {
+ auto pHelper = new VersionRange;
+ ISetupHelperPtr sut(pHelper, false);
+
+ ULONGLONG ullVersion = 0;
+ Assert::AreEqual(S_OK, sut->ParseVersion(L"1", &ullVersion));
+ Assert::AreEqual(281474976710656ULL, ullVersion);
+ }
+
+ TEST_METHOD(ParseVersion_MajorMinor)
+ {
+ auto pHelper = new VersionRange;
+ ISetupHelperPtr sut(pHelper, false);
+
+ ULONGLONG ullVersion = 0;
+ Assert::AreEqual(S_OK, sut->ParseVersion(L"1.2", &ullVersion));
+ Assert::AreEqual(281483566645248ULL, ullVersion);
+ }
+
+ TEST_METHOD(ParseVersion_MajorMinorBuild)
+ {
+ auto pHelper = new VersionRange;
+ ISetupHelperPtr sut(pHelper, false);
+
+ ULONGLONG ullVersion = 0;
+ Assert::AreEqual(S_OK, sut->ParseVersion(L"1.2.3", &ullVersion));
+ Assert::AreEqual(281483566841856ULL, ullVersion);
+ }
+
+ TEST_METHOD(ParseVersion_MajorMinorBuildRevision)
+ {
+ auto pHelper = new VersionRange;
+ ISetupHelperPtr sut(pHelper, false);
+
+ ULONGLONG ullVersion = 0;
+ Assert::AreEqual(S_OK, sut->ParseVersion(L"1.2.3.4", &ullVersion));
+ Assert::AreEqual(281483566841860ULL, ullVersion);
+ }
+
+ TEST_METHOD(ParseVersion_Too_Many_Fields)
+ {
+ auto pHelper = new VersionRange;
+ ISetupHelperPtr sut(pHelper, false);
+
+ ULONGLONG ullVersion = 0;
+ Assert::AreEqual(E_INVALIDARG, sut->ParseVersion(L"1.2.3.4.5", &ullVersion));
+ Assert::AreEqual(0ULL, ullVersion);
+ }
+
+ TEST_METHOD(ParseVersion_Empty_Field)
+ {
+ auto pHelper = new VersionRange;
+ ISetupHelperPtr sut(pHelper, false);
+
+ ULONGLONG ullVersion = 0;
+ Assert::AreEqual(E_INVALIDARG, sut->ParseVersion(L"1..0", &ullVersion));
+ Assert::AreEqual(0ULL, ullVersion);
+ }
+
+ TEST_METHOD(ParseVersion_Overflow)
+ {
+ auto pHelper = new VersionRange;
+ ISetupHelperPtr sut(pHelper, false);
+
+ ULONGLONG ullVersion = 0;
+ Assert::AreEqual(E_INVALIDARG, sut->ParseVersion(L"65536", &ullVersion));
+ }
+
+ TEST_METHOD(ParseVersion_NaN)
+ {
+ auto pHelper = new VersionRange;
+ ISetupHelperPtr sut(pHelper, false);
+
+ ULONGLONG ullVersion = 0;
+ Assert::AreEqual(E_INVALIDARG, sut->ParseVersion(L"NaN", &ullVersion));
+ }
+
+ TEST_METHOD(ParseVersion_only_Spaces)
+ {
+ auto pHelper = new VersionRange;
+ ISetupHelperPtr sut(pHelper, false);
+
+ ULONGLONG ullVersion = 0;
+ Assert::AreEqual(E_INVALIDARG, sut->ParseVersion(L" ", &ullVersion));
+ }
+
+ TEST_METHOD(ParseVersion_with_Spaces)
+ {
+ auto pHelper = new VersionRange;
+ ISetupHelperPtr sut(pHelper, false);
+
+ ULONGLONG ullVersion = 0;
+ Assert::AreEqual(S_OK, sut->ParseVersion(L" 1.0 ", &ullVersion));
+ Assert::AreEqual(281474976710656ULL, ullVersion);
+ }
+
+ TEST_METHOD(ParseVersionRange_pwszVersionRange_Null)
+ {
+ auto pHelper = new VersionRange;
+ ISetupHelperPtr sut(pHelper, false);
+
+ Assert::AreEqual(E_INVALIDARG, sut->ParseVersionRange(NULL, NULL, NULL));
+ }
+
+ TEST_METHOD(ParseVersionRange_pullMinVersion_Null)
+ {
+ auto pHelper = new VersionRange;
+ ISetupHelperPtr sut(pHelper, false);
+
+ Assert::AreEqual(E_POINTER, sut->ParseVersionRange(L"[1.0,)", NULL, NULL));
+ }
+
+ TEST_METHOD(ParseVersionRange_pullMaxVersion_Null)
+ {
+ auto pHelper = new VersionRange;
+ ISetupHelperPtr sut(pHelper, false);
+
+ ULONGLONG ullMinVersion = 0;
+ Assert::AreEqual(E_POINTER, sut->ParseVersionRange(L"[1.0,)", &ullMinVersion, NULL));
+ }
+
+ TEST_METHOD(ParseVersionRange)
+ {
+ typedef tuple theory_datum;
+ typedef vector theory_data;
+
+ auto pHelper = new VersionRange;
+ ISetupHelperPtr sut(pHelper, false);
+
+ theory_data data =
+ {
+ make_tuple(__LINE__, S_OK, L"1.0", 281474976710656, 18446744073709551615),
+ make_tuple(__LINE__, S_OK, L"[1.0]", 281474976710656, 281474976710656),
+ make_tuple(__LINE__, E_INVALIDARG, L"[1.0)", 0, 0),
+ make_tuple(__LINE__, S_OK, L"[1.0,)", 281474976710656, 18446744073709551614),
+ make_tuple(__LINE__, S_OK, L"[1.0,2.0)", 281474976710656, 562949953421311),
+ make_tuple(__LINE__, S_OK, L"[1,2)", 281474976710656, 562949953421311),
+ make_tuple(__LINE__, S_OK, L"[1,2]", 281474976710656, 562949953421312),
+ make_tuple(__LINE__, S_OK, L"(1.0,2.0]", 281474976710657, 562949953421312),
+ make_tuple(__LINE__, S_OK, L"[1.0", 281474976710656, 18446744073709551615),
+ make_tuple(__LINE__, S_OK, L",2.0)", 0, 562949953421311),
+ make_tuple(__LINE__, E_INVALIDARG, L"NaN", 0, 0),
+ make_tuple(__LINE__, E_INVALIDARG, L"[1,2,3)", 0, 0),
+ make_tuple(__LINE__, E_INVALIDARG, L"", 0, 0),
+ make_tuple(__LINE__, E_INVALIDARG, L"1[,2)", 0, 0),
+ make_tuple(__LINE__, E_INVALIDARG, L"[1,)2", 0, 0),
+ make_tuple(__LINE__, E_INVALIDARG, L"(65535.65535.65535.65535]", 0, 0),
+ make_tuple(__LINE__, E_INVALIDARG, L"[0,0)", 0, 0),
+ make_tuple(__LINE__, E_INVALIDARG, L"[2,1)", 0, 0),
+ make_tuple(__LINE__, E_INVALIDARG, L"(1.65535.65535.65535,2.0)", 0, 0),
+ make_tuple(__LINE__, S_OK, L"[1.0, )", 281474976710656, 18446744073709551614),
+ make_tuple(__LINE__, S_OK, L" [ 1.0 , ) ", 281474976710656, 18446744073709551614),
+ make_tuple(__LINE__, E_INVALIDARG, L" [ 1. 0 , ) ", 0, 0),
+ };
+
+ UINT uiLine;
+ HRESULT hrActual;
+ HRESULT hrExpected;
+ LPCWSTR pwszVersionRange;
+ ULONGLONG ullMinVersionActual;
+ ULONGLONG ullMinVersionExpected;
+ ULONGLONG ullMaxVersionActual;
+ ULONGLONG ullMaxVersionExpected;
+
+ for (auto datum : data)
+ {
+ tie(uiLine, hrExpected, pwszVersionRange, ullMinVersionExpected, ullMaxVersionExpected) = datum;
+
+ hrActual = sut->ParseVersionRange(pwszVersionRange, &ullMinVersionActual, &ullMaxVersionActual);
+ Assert::AreEqual(hrExpected, hrActual, format(L"Unexpected result parsing '%ls' from line %d, expected: 0x%08x, actual: 0x%08x", pwszVersionRange, uiLine, hrExpected, hrActual).c_str());
+ Assert::AreEqual(ullMinVersionExpected, ullMinVersionActual, format(L"Unexpected minimum version parsing '%ls'", pwszVersionRange).c_str());
+ Assert::AreEqual(ullMaxVersionExpected, ullMaxVersionActual, format(L"Unexpected maximum version parsing '%ls'", pwszVersionRange).c_str());
+ }
+ }
+};
diff --git a/test/vswhere.test/vswhere.test.vcxproj b/test/vswhere.test/vswhere.test.vcxproj
index e1aab34..b6a973e 100644
--- a/test/vswhere.test/vswhere.test.vcxproj
+++ b/test/vswhere.test/vswhere.test.vcxproj
@@ -124,6 +124,7 @@
+
diff --git a/test/vswhere.test/vswhere.test.vcxproj.filters b/test/vswhere.test/vswhere.test.vcxproj.filters
index a5fcf0a..7429f1a 100644
--- a/test/vswhere.test/vswhere.test.vcxproj.filters
+++ b/test/vswhere.test/vswhere.test.vcxproj.filters
@@ -92,6 +92,9 @@
Source Files
+
+ Source Files
+