Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -71,3 +71,8 @@ mwg_add_runtime_data_target()

add_subdirectory(src/MapWinGIS.Core)
add_subdirectory(src/MapWinGIS.ActiveX)

if(MWG_BUILD_TESTS)
enable_testing()
add_subdirectory(tests/MapWinGIS.Core.Tests)
endif()
1 change: 1 addition & 0 deletions build/scripts/Compare-CompileCommands.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ $explainedLinkDifferences = [ordered]@{

# Compile differences that are deliberate (docs/CMAKE-MIGRATION.md).
$explainedCompileDifferences = [ordered]@{
'^/I<repo>/obj/MapWinGIS\.ActiveX/[^/]+/[^/]+$' = 'MSBuild ActiveX intdir replaced by the CMake MIDL directory (D3)'
'^/I<intdir>$' = 'MIDL output moved from the intermediate directory to <build>/.../midl (D3)'
'^/I<builddir>/.*/midl$' = 'MIDL output directory (D3)'
'^/I<vcpkg_installed>/[^/]+/include$' = 'vcpkg auto-include; targets without a vcpkg dependency do not get it, the others get it from imported targets'
Expand Down
15 changes: 8 additions & 7 deletions docs/BUILDING.md
Original file line number Diff line number Diff line change
Expand Up @@ -198,19 +198,20 @@ MSBuild settings and the decisions the CMake build follows are in

### Building with CMake

The CMake build currently covers `MapWinGIS.Core.dll` and `MapWinGIS.ocx`; the
tests and samples follow. The OCX needs the **C++ ATL for latest v145 build
tools** component for each architecture you build, and `midl.exe` needs `cl.exe`
on `PATH`, so configure and build from a Visual Studio toolchain (CLion) or a
Developer PowerShell. CMake 3.28 or later and Ninja are required; both ship
with Visual Studio 2026 and CLion. Run the bootstrap script first, then
configure from a VS 2026 Developer PowerShell (or any shell after
The CMake build covers `MapWinGIS.Core.dll`, `MapWinGIS.ocx`, and the native
GoogleTest suite; the samples follow. The OCX needs the **C++ ATL for latest
v145 build tools** component for each architecture you build. `midl.exe` needs
`cl.exe` on `PATH`, so configure and build from a Visual Studio toolchain
(CLion) or a Developer PowerShell. CMake 3.28 or later and Ninja are required;
both ship with Visual Studio 2026 and CLion. Run the bootstrap script first,
then configure from a VS 2026 Developer PowerShell (or any shell after
`vcvarsall.bat x64`):

```powershell
pwsh -File build\scripts\bootstrap-vcpkg.ps1
cmake --preset x64-debug
cmake --build --preset x64-debug
ctest --preset x64-debug --output-on-failure -LE interactive
```

| Preset | Generator | Build directory |
Expand Down
61 changes: 57 additions & 4 deletions docs/TESTING.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
# Testing

- Framework: GoogleTest, provided by the vcpkg `tests` feature (enabled by
default through `MwgVcpkgFeatures`).
- Test project: `tests/MapWinGIS.Core.Tests`, built with the solution.
- Framework: GoogleTest from the vcpkg `tests` feature (enabled by the MSBuild
default and when `MWG_BUILD_TESTS` is on for CMake).
- Test project: `tests/MapWinGIS.Core.Tests`, built with the MSBuild solution
or CMake.
- Shared fixtures and helpers live in `TestData.h/.cpp` (`TempDirectory`,
`MakeSampleShapefile`, `MakeProvincesDataset`, and layer constants). Extend
these instead of writing per-file fixture code.
Expand All @@ -17,7 +18,59 @@ bin\Release\x64\MapWinGIS.Core.Tests.exe --gtest_output=xml:testresults.xml #
Also runnable from Visual Studio Test Explorer (GoogleTest adapter picks it
up automatically).

## ActiveX host integration checks
### CMake and CTest

The CMake test target uses the same GoogleTest sources and fixtures:

```powershell
cmake --preset x64-debug
cmake --build --preset x64-debug
ctest --preset x64-debug --output-on-failure -LE interactive
```

`gtest_discover_tests()` discovers individual cases before CTest runs them.
Each test runs from the build's runtime directory, which contains the OCX,
dependent DLLs, and GDAL/PROJ data. GoogleTest writes per-test XML files under
`test-results` in the build directory. CTest can also write a single JUnit
report with `ctest --test-dir out/b/x64d --output-junit out/b/x64d/ctest.xml`.

To run one case from CTest, match its fully qualified GoogleTest name:

```powershell
ctest --test-dir out/b/x64d -R 'VectorDatasetTest.ReportsTheDriverAndPath' --output-on-failure
```

## ActiveX integration checks

### Registered native control check

The native verification script registers the control for the current user,
creates it through its ProgID, checks the automation boundary, and removes
the per-user registration. It checks both per-user registry views first and
refuses to run if the control's CLSID or either ProgID is already registered.
Run it from a PowerShell process that matches the target architecture:

```powershell
pwsh -File tests\MapWinGIS.Core.Tests\Verify-ActiveXActivation.ps1 -Configuration Debug -Platform x64
```

For a CMake build, pass its runtime directory:

```powershell
pwsh -File tests\MapWinGIS.Core.Tests\Verify-ActiveXActivation.ps1 `
-Configuration Debug -Platform x64 -BinDirectory out\b\x64d\bin
```

CTest registers this registration-based check with the `interactive` label
when a matching PowerShell process is available. It changes the per-user COM
registration and is excluded from the CTest presets and CI; run it explicitly
from an interactive desktop when needed:

```powershell
ctest --test-dir out/b/x64d -R '^Verify-ActiveXActivation$' --output-on-failure
```

### C# ActiveX test host

The .NET 10 WinForms host exercises the real ActiveX control through `AxHost`
using registration-free COM activation from its embedded application
Expand Down
112 changes: 112 additions & 0 deletions tests/MapWinGIS.Core.Tests/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
# SPDX-License-Identifier: MPL-2.0
#
# Native GoogleTest suite for the Core API and ActiveX rendering components.

find_package(GDAL CONFIG REQUIRED)
find_package(GTest CONFIG REQUIRED)
include(GoogleTest)

# vcpkg marks GoogleTest headers as system, conflicting with /external:W4.
set_property(TARGET GTest::gtest PROPERTY INTERFACE_SYSTEM_INCLUDE_DIRECTORIES "")

set(MWG_CORE_TEST_HEADERS
TestData.h
)

set(MWG_CORE_TEST_SOURCES
ActiveXActivationTests.cpp
ComConversionTests.cpp
GdalAlgorithmRunnerTests.cpp
GdalEnvironmentTests.cpp
GdalModernCapabilitiesTests.cpp
GdalOperationDispatcherTests.cpp
GdalRuntimeTests.cpp
GdalTypedOptionsTests.cpp
GdalUtilsTests.cpp
Main.cpp
RenderingBaselineTests.cpp
TestData.cpp
VectorDatasetTests.cpp
VectorLayerRendererTests.cpp
VectorLayerTests.cpp
VectorRenderSceneTests.cpp
)

add_executable(MapWinGIS.Core.Tests)
target_sources(MapWinGIS.Core.Tests PRIVATE
${MWG_CORE_TEST_HEADERS}
${MWG_CORE_TEST_SOURCES}
${MWG_ACTIVEX_SHARED_SOURCES}
)
source_group(TREE "${CMAKE_CURRENT_SOURCE_DIR}" FILES
${MWG_CORE_TEST_HEADERS}
${MWG_CORE_TEST_SOURCES}
)
source_group("ActiveX Test Sources" FILES ${MWG_ACTIVEX_SHARED_SOURCES})

target_include_directories(MapWinGIS.Core.Tests PRIVATE
"${PROJECT_SOURCE_DIR}/src/MapWinGIS.ActiveX"
)

target_compile_definitions(MapWinGIS.Core.Tests PRIVATE
MWG_ENABLE_RENDERER_TEST_HOOKS
)

target_link_libraries(MapWinGIS.Core.Tests PRIVATE
MapWinGIS::Core
MapWinGIS.ActiveX.Interface.Generated
GDAL::GDAL
GTest::gtest
ole32
oleaut32
uuid
gdi32
user32
opengl32
psapi
)

mwg_apply_common_options(MapWinGIS.Core.Tests)
target_link_options(MapWinGIS.Core.Tests PRIVATE /SUBSYSTEM:CONSOLE)
set_target_properties(MapWinGIS.Core.Tests PROPERTIES FOLDER "tests")

add_dependencies(MapWinGIS.Core.Tests
MapWinGIS.ActiveX
MapWinGIS.RuntimeData
)

file(MAKE_DIRECTORY "${PROJECT_BINARY_DIR}/test-results")
gtest_discover_tests(MapWinGIS.Core.Tests
DISCOVERY_MODE PRE_TEST
DISCOVERY_TIMEOUT 120
WORKING_DIRECTORY "${MWG_RUNTIME_DIR}"
XML_OUTPUT_DIR "${PROJECT_BINARY_DIR}/test-results"
)

if(MWG_PLATFORM STREQUAL "Win32")
set(_mwg_activation_shell
"$ENV{WINDIR}/SysWOW64/WindowsPowerShell/v1.0/powershell.exe")
if(NOT EXISTS "${_mwg_activation_shell}")
unset(_mwg_activation_shell)
endif()
else()
find_program(_mwg_activation_shell NAMES pwsh powershell)
endif()

if(_mwg_activation_shell)
add_test(NAME Verify-ActiveXActivation
COMMAND "${_mwg_activation_shell}" -NoProfile -File
"${CMAKE_CURRENT_SOURCE_DIR}/Verify-ActiveXActivation.ps1"
-Configuration "$<CONFIG>"
-Platform "${MWG_PLATFORM}"
-BinDirectory "${MWG_RUNTIME_DIR}"
)
set_tests_properties(Verify-ActiveXActivation PROPERTIES
LABELS "interactive"
WORKING_DIRECTORY "${MWG_RUNTIME_DIR}"
)
else()
message(STATUS
"Skipping the interactive ActiveX activation CTest entry: no PowerShell process "
"matching ${MWG_PLATFORM} was found.")
endif()
19 changes: 12 additions & 7 deletions tests/MapWinGIS.Core.Tests/Verify-ActiveXActivation.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ param(
[string]$Configuration = 'Debug',

[ValidateSet('Win32', 'x64')]
[string]$Platform = 'x64'
[string]$Platform = 'x64',

[string]$BinDirectory = ''
)

$ErrorActionPreference = 'Stop'
Expand All @@ -13,9 +15,14 @@ if ([IntPtr]::Size -ne $expectedPointerSize) {
throw "Run this script in a $Platform PowerShell process to match the control."
}

$controlPath = [System.IO.Path]::GetFullPath(
(Join-Path $PSScriptRoot "..\..\bin\$Configuration\$Platform\MapWinGIS.ocx")
)
$binDirectory = if ([string]::IsNullOrWhiteSpace($BinDirectory)) {
Join-Path $PSScriptRoot "..\..\bin\$Configuration\$Platform"
} else {
$BinDirectory
}
$binDirectory = [System.IO.Path]::GetFullPath($binDirectory)

$controlPath = Join-Path $binDirectory 'MapWinGIS.ocx'
if (-not (Test-Path -LiteralPath $controlPath -PathType Leaf)) {
throw "The ActiveX control was not found at '$controlPath'. Build the solution first."
}
Expand Down Expand Up @@ -78,9 +85,7 @@ try {
[void][System.Runtime.InteropServices.Marshal]::ReleaseComObject($control)
$control = $null

$testExecutable = [System.IO.Path]::GetFullPath(
(Join-Path $PSScriptRoot "..\..\bin\$Configuration\$Platform\MapWinGIS.Core.Tests.exe")
)
$testExecutable = Join-Path $binDirectory 'MapWinGIS.Core.Tests.exe'
if (-not (Test-Path -LiteralPath $testExecutable -PathType Leaf)) {
throw "The ActiveX hosting test executable was not found at '$testExecutable'. Build the solution first."
}
Expand Down