Skip to content
Merged
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
14 changes: 14 additions & 0 deletions unittests/webgpu_engine/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ alp_add_unittest(unittests_webgpu_engine
UnittestWebgpuContext.h UnittestWebgpuContext.cpp
test_GpuShaderFunctions.cpp
test_ShaderPreprocessor.cpp
test_wgpu_string.cpp
)

target_link_libraries(unittests_webgpu_engine PUBLIC webgpu_engine)
Expand All @@ -47,5 +48,18 @@ if (WIN32 AND NOT EMSCRIPTEN)
COMMENT "Copying SDL2.dll to unittests"
)
endif()

# Copy DXC DLLs (dxcompiler.dll, dxil.dll) required by prebuilt Dawn's D3D12 backend
include("${CMAKE_SOURCE_DIR}/cmake/alp_provide_dawn_dxc.cmake")
alp_provide_dawn_dxc_dlls(ALP_DAWN_DXC_DLLS)
foreach(ALP_DAWN_DXC_DLL IN LISTS ALP_DAWN_DXC_DLLS)
get_filename_component(ALP_DAWN_DXC_DLL_NAME "${ALP_DAWN_DXC_DLL}" NAME)
add_custom_command(TARGET unittests_webgpu_engine POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
"${ALP_DAWN_DXC_DLL}"
"$<TARGET_FILE_DIR:unittests_webgpu_engine>"
COMMENT "Copying ${ALP_DAWN_DXC_DLL_NAME} to unittests"
)
endforeach()
endif()

117 changes: 117 additions & 0 deletions unittests/webgpu_engine/test_wgpu_string.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
/*****************************************************************************
* weBIGeo
* Copyright (C) 2026 Matthias Huerbe
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*****************************************************************************/

#include <catch2/catch_test_macros.hpp>
#include <cstring>
#include <string>
#include <string_view>
#include <webgpu/base/wgpu_string.h>

using namespace webgpu;

static_assert(""_wsv.length == 0);
static_assert("hello"_wsv.length == 5);
static_assert("a\0b"_wsv.length == 3);

TEST_CASE("wsv literal - construct", "[wgpu_string]")
{
auto str = "hello"_wsv;
CHECK(str.length == 5);
CHECK(std::memcmp(str.data, "hello", 5) == 0);
}

TEST_CASE("wsv literal - empty", "[wgpu_string]")
{
CHECK(""_wsv.length == 0);
}

TEST_CASE("wsv literal - keeps embedded NUL", "[wgpu_string]")
{
auto str = "a\0b"_wsv;
CHECK(str.length == 3);
CHECK(std::memcmp(str.data, "a\0b", 3) == 0);
}

TEST_CASE("wsv() - from string_view / string / const char*", "[wgpu_string]")
{
std::string_view sv = "hello";
CHECK(wsv(sv) == "hello"_wsv);

std::string str = "world";
CHECK(wsv(str) == "world"_wsv);

CHECK(wsv("literal") == "literal"_wsv);

CHECK(wsv(std::string_view("hello", 3)).length == 3);
CHECK(wsv(std::string_view("hello", 3)) == "hel"_wsv);
}

TEST_CASE("wsv() - empty", "[wgpu_string]")
{
CHECK(wsv(std::string_view {}).length == 0);
CHECK(wsv("") == ""_wsv);
}

TEST_CASE("wsv_length - explicit length returned as-is", "[wgpu_string]")
{
CHECK(wsv_length(WGPUStringView { "hello", 5 }) == 5);
CHECK(wsv_length(WGPUStringView { "hello", 2 }) == 2);
CHECK(wsv_length(WGPUStringView { "abc", 0 }) == 0);
}

TEST_CASE("wsv_length - WGPU_STRLEN sentinel uses strlen", "[wgpu_string]")
{
CHECK(wsv_length(WGPUStringView { "hello", WGPU_STRLEN }) == 5);
CHECK(wsv_length(WGPUStringView { "", WGPU_STRLEN }) == 0);
}

TEST_CASE("wsv_length - sentinel with null data is 0", "[wgpu_string]")
{
CHECK(wsv_length(WGPUStringView { nullptr, WGPU_STRLEN }) == 0);
}

TEST_CASE("operator== - equal content", "[wgpu_string]")
{
CHECK("hello"_wsv == WGPUStringView { "hello", 5 });
CHECK("hello"_wsv == WGPUStringView { "hello", WGPU_STRLEN });
}

TEST_CASE("operator== - different content, same length", "[wgpu_string]")
{
CHECK_FALSE("hello"_wsv == "world"_wsv);
CHECK("hello"_wsv != "world"_wsv);
}

TEST_CASE("operator== - different length", "[wgpu_string]")
{
CHECK_FALSE("hello"_wsv == "hell"_wsv);
CHECK_FALSE("hello"_wsv == "hello!"_wsv);
}

TEST_CASE("operator== - empty views", "[wgpu_string]")
{
CHECK(""_wsv == ""_wsv);
CHECK(WGPUStringView { nullptr, WGPU_STRLEN } == ""_wsv);
CHECK_FALSE(""_wsv == "x"_wsv);
}

TEST_CASE("operator== - NUL-safe, not strlen-based", "[wgpu_string]")
{
CHECK("a\0b"_wsv == WGPUStringView { "a\0b", 3 });
CHECK_FALSE("a\0b"_wsv == WGPUStringView { "a\0c", 3 });
}
2 changes: 1 addition & 1 deletion webgpu/base/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ set(SOURCES
Context.h
RenderResourceRegistry.h RenderResourceRegistry.cpp
gpu_utils.h gpu_utils.cpp

wgpu_string.h
webgpu_interface.hpp webgpu_interface.cpp)

add_library(webgpu STATIC ${SOURCES})
Expand Down
57 changes: 57 additions & 0 deletions webgpu/base/wgpu_string.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*****************************************************************************
* weBIGeo
* Copyright (C) 2026 Matthias Huerbe
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*****************************************************************************/

#pragma once

#include <webgpu/webgpu.h>
#include <cstring> // std::strlen & std::memcmp
#include <string_view>

namespace webgpu
{

// utility to create a webgpu string view from the string literal
inline constexpr WGPUStringView operator""_wsv(const char* s, size_t l) noexcept
{
return { s, l };
}

// utility to create a webgpu string view from std::string, std::string_view, const char*
inline constexpr WGPUStringView wsv(std::string_view s) noexcept

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The name of the method can be improved. If it is used in the code base, people understand it, but nobody will ever find it on its own.

to_wsv() or something

{
return { s.data(), s.size() };
}

// length of a possibly WGPU_STRLEN-sentinel string view
inline constexpr size_t wsv_length(WGPUStringView s) noexcept
{
return (s.length == WGPU_STRLEN) ? (s.data ? std::strlen(s.data) : 0) : s.length;
}

// content equality of two string views
inline constexpr bool operator==(WGPUStringView a, WGPUStringView b) noexcept
{
size_t na = wsv_length(a), nb = wsv_length(b);
return na == nb && (na == 0 || std::memcmp(a.data, b.data, na) == 0);
}

} // namespace webgpu

// usable by include
using webgpu::operator""_wsv;
using webgpu::operator==;
Loading