Skip to content

Commit cc1e8db

Browse files
Add modules unit test
1 parent 213bdb8 commit cc1e8db

File tree

8 files changed

+219
-52
lines changed

8 files changed

+219
-52
lines changed

.github/workflows/test-docs-examples.yml

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ permissions:
1818
jobs:
1919
test_docs_examples:
2020
name: Test build examples
21-
runs-on: ubuntu-22.04
21+
runs-on: ubuntu-25.10
2222
concurrency:
2323
group: ${{ github.workflow }}-${{ github.ref }}
2424
cancel-in-progress: true
@@ -35,17 +35,17 @@ jobs:
3535
submodules: recursive
3636

3737
- name: Install apt packages
38-
run: sudo sed -i 's/azure\.//' /etc/apt/sources.list && sudo apt-get update && sudo apt-get install -y g++-12 libopus-dev zlib1g-dev libmpg123-dev liboggz-dev cmake libfmt-dev libopusfile-dev
38+
run: sudo sed -i 's/azure\.//' /etc/apt/sources.list && sudo apt-get update && sudo apt-get install -y g++-15 libopus-dev ninja-build zlib1g-dev libmpg123-dev liboggz-dev cmake libfmt-dev libopusfile-dev
3939

4040
- name: Generate CMake
41-
run: mkdir build && cd build && cmake -DDPP_NO_VCPKG=ON -DAVX_TYPE=T_fallback -DDPP_CORO=ON -DCMAKE_BUILD_TYPE=Debug ..
41+
run: mkdir build && cd build && cmake -G Ninja -DDPP_NO_VCPKG=ON -DDPP_MODULES=ON -DAVX_TYPE=T_fallback -DDPP_CORO=ON -DCMAKE_BUILD_TYPE=Debug ..
4242
env:
43-
CXX: g++-12
43+
CXX: g++-15
4444

4545
- name: Build Project
46-
run: cd build && make -j2 && sudo make install
46+
run: cd build && cmake --build . -j2 && sudo ninja install
4747

4848
- name: Test compile examples
49-
run: cd docpages/example_code && mkdir build && cd build && cmake .. && make -j2
49+
run: cd docpages/example_code && mkdir build && cd build && cmake -G Ninja .. && cmake --build . -j2
5050
env:
51-
CXX: g++-12
51+
CXX: g++-15

CMakeLists.txt

Lines changed: 0 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -161,38 +161,3 @@ if (NOT WIN32)
161161
target_link_libraries(dpp PRIVATE std::filesystem)
162162
endif()
163163

164-
if (DPP_MODULES)
165-
message("-- C++20 Modules support: ${Green}ENABLED${ColourReset}")
166-
add_library(dpp_module)
167-
168-
target_sources(dpp_module
169-
PUBLIC
170-
FILE_SET CXX_MODULES
171-
FILES "${CMAKE_CURRENT_SOURCE_DIR}/include/dpp/dpp.cppm"
172-
)
173-
174-
target_compile_features(dpp_module PUBLIC cxx_std_20)
175-
176-
target_include_directories(dpp_module PUBLIC
177-
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
178-
$<INSTALL_INTERFACE:include>
179-
)
180-
181-
target_link_libraries(dpp_module PUBLIC dpp)
182-
183-
add_library(dpp::module ALIAS dpp_module)
184-
185-
# Installation
186-
install(TARGETS dpp_module
187-
EXPORT ${PROJECT_NAME}Targets
188-
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
189-
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
190-
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
191-
FILE_SET CXX_MODULES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/dpp/include
192-
)
193-
194-
target_compile_definitions(dpp PUBLIC DPP_MODULES)
195-
else()
196-
message("-- C++20 Modules support: ${Red}DISABLED${ColourReset} (enable with -DDPP_MODULES=ON)")
197-
endif()
198-
Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,21 @@
1-
/* If import std; is supported, use it instead */
2-
#include <cstdlib>
3-
41
import dpp;
52

63
using dpp::cluster;
4+
using std::ready_t;
75
using dpp::slashcommand;
6+
using dpp::slashcommand_t;
87
using dpp::start_type;
98

109
int main() {
11-
cluster bot(std::getenv("BOT_TOKEN"));
10+
cluster bot("YOUR_BOT_TOKEN_HERE");
1211

13-
bot.on_slashcommand([](auto event) {
12+
bot.on_slashcommand([](const slashcommand_t& event) -> void {
1413
if (event.command.get_command_name() == "ping") {
1514
event.reply("Pong!");
1615
}
1716
});
1817

19-
bot.on_ready([&bot](auto event) {
18+
bot.on_ready([&bot](const ready_t& event) -> void {
2019
if (dpp::run_once<struct register_bot_commands>()) {
2120
bot.global_command_create(
2221
slashcommand("ping", "Ping pong!", bot.me.id)
@@ -26,4 +25,4 @@ int main() {
2625

2726
bot.start(start_type::st_wait);
2827
return 0;
29-
}
28+
}

docpages/example_programs/misc/using_modules.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
D++ is offered as a C++ module, which offers improved compile times over a traditional header.
44

5-
In order to enable support, you should be using C++20+ with any module-supporting compiler. To activate the feature, pass the `DPP_MODULES` flag to CMake. Ensure that the generated build system supports modules (for CMake, this is usually Ninja).
5+
In order to enable support, you must use C++20 (or later) with any module-supporting compiler. To activate the feature, pass the `DPP_MODULES` flag to CMake. Ensure that the generated build system supports modules (for CMake, this is usually Ninja; note CMake does not currently support modules with Makefile).
66

77
Once this is done, simply `import dpp;` and we're good to go!
88

library/CMakeLists.txt

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -459,6 +459,42 @@ if (NOT BUILD_SHARED_LIBS)
459459
endif()
460460
endif()
461461

462+
if (DPP_MODULES)
463+
message("-- ${Green}Modules are enabled!${ColourReset}")
464+
add_library(dpp_module)
465+
466+
target_sources(dpp_module
467+
PUBLIC
468+
FILE_SET CXX_MODULES
469+
BASE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/../include"
470+
FILES "${CMAKE_CURRENT_SOURCE_DIR}/../include/dpp/dpp.cppm"
471+
)
472+
473+
target_compile_features(dpp_module PUBLIC cxx_std_20)
474+
475+
target_include_directories(dpp_module PUBLIC
476+
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
477+
$<INSTALL_INTERFACE:include>
478+
)
479+
480+
target_link_libraries(dpp_module PUBLIC dpp)
481+
482+
add_library(dpp::module ALIAS dpp_module)
483+
484+
target_compile_definitions(dpp PUBLIC DPP_MODULES)
485+
486+
# Installation
487+
install(TARGETS dpp_module
488+
EXPORT ${PROJECT_NAME}Targets
489+
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
490+
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
491+
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
492+
FILE_SET CXX_MODULES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/dpp/include
493+
)
494+
else()
495+
message("-- ${Yellow}Modules are disabled.${ColourReset}")
496+
endif()
497+
462498
if (DPP_BUILD_TEST)
463499
enable_testing(${CMAKE_CURRENT_SOURCE_DIR}/..)
464500
file(GLOB testnamelist "${CMAKE_CURRENT_SOURCE_DIR}/../src/*")
@@ -469,15 +505,24 @@ if (DPP_BUILD_TEST)
469505
set (testsrc "")
470506
file(GLOB testsrc "${modules_dir}/${testname}/*.cpp")
471507
add_executable(${testname} ${testsrc})
472-
if ((NOT DPP_NO_CORO) OR DPP_FORMATTERS)
508+
if ((NOT DPP_NO_CORO) OR DPP_FORMATTERS OR DPP_MODULES)
473509
target_compile_features(${testname} PRIVATE cxx_std_20)
474510
else()
475511
target_compile_features(${testname} PRIVATE cxx_std_17)
476512
endif()
477513
if (MSVC)
478514
target_compile_options(${testname} PRIVATE /utf-8)
479515
endif()
480-
if(BUILD_SHARED_LIBS)
516+
if (DPP_MODULES)
517+
target_link_libraries(${testname} PUBLIC dpp_module)
518+
add_dependencies(${testname} dpp_module)
519+
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
520+
target_compile_options(${testname} PRIVATE -fmodules-ts)
521+
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
522+
target_compile_options(${testname} PRIVATE -fmodules)
523+
endif()
524+
set_target_properties(${testname} PROPERTIES CXX_SCAN_FOR_MODULES ON)
525+
elseif(BUILD_SHARED_LIBS)
481526
target_link_libraries(${testname} PUBLIC ${modname})
482527
else()
483528
target_link_libraries(${testname} PUBLIC dppstatic)

src/unittest/module_test.cpp

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
/************************************************************************************
2+
*
3+
* D++, A Lightweight C++ library for Discord
4+
*
5+
* SPDX-License-Identifier: Apache-2.0
6+
* Copyright 2021 Craig Edwards and D++ contributors
7+
* (https://github.com/brainboxdotcc/DPP/graphs/contributors)
8+
*
9+
* Licensed under the Apache License, Version 2.0 (the "License");
10+
* you may not use this file except in compliance with the License.
11+
* You may obtain a copy of the License at
12+
*
13+
* http://www.apache.org/licenses/LICENSE-2.0
14+
*
15+
* Unless required by applicable law or agreed to in writing, software
16+
* distributed under the License is distributed on an "AS IS" BASIS,
17+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18+
* See the License for the specific language governing permissions and
19+
* limitations under the License.
20+
*
21+
************************************************************************************/
22+
23+
#ifdef DPP_MODULES
24+
#include "test.h"
25+
26+
import dpp;
27+
28+
/**
29+
* @brief Test basic dpp types and functionality via module import
30+
*/
31+
void test_dpp_module_basic() {
32+
start_test(MODULE_IMPORT_BASIC);
33+
34+
dpp::snowflake test_id = 825411104208977952ULL;
35+
time_t extracted_timestamp = test_id.get_creation_time();
36+
if (extracted_timestamp != 1616978723) {
37+
set_status(MODULE_IMPORT_BASIC, ts_failed, "snowflake timestamp extraction");
38+
return;
39+
}
40+
41+
// User object creation test
42+
dpp::user test_user;
43+
test_user.id = 987654321;
44+
test_user.username = "ModuleTestUser";
45+
if (test_user.id != 987654321 || test_user.username != "ModuleTestUser") {
46+
set_status(MODULE_IMPORT_BASIC, ts_failed, "user object creation");
47+
return;
48+
}
49+
50+
// Testing ts_to_string
51+
std::string test_time = dpp::ts_to_string(1642611864);
52+
if (test_time != "2022-01-19T17:04:24Z") {
53+
set_status(MODULE_IMPORT_BASIC, ts_failed, "timestamp conversion");
54+
return;
55+
}
56+
57+
// Message object creation test
58+
dpp::message test_msg;
59+
test_msg.content = "Test message from module";
60+
test_msg.id = 111222333;
61+
62+
auto is_valid_message = [](const dpp::message& msg, std::string_view s, int test_id) -> bool {
63+
return msg.content == s && msg.id == test_id;
64+
};
65+
66+
if (!is_valid_message(test_msg, "Test message from module")) {
67+
set_status(MODULE_IMPORT_BASIC, ts_failed, "message object creation");
68+
return;
69+
}
70+
71+
// URL encoding test
72+
std::string encoded = dpp::utility::url_encode("test value");
73+
if (encoded != "test%20value") {
74+
set_status(MODULE_IMPORT_BASIC, ts_failed, "URL encoding");
75+
return;
76+
}
77+
78+
// Markdown escaping test
79+
std::string markdown = "**bold** _italic_";
80+
std::string escaped = dpp::utility::markdown_escape(markdown);
81+
if (escaped != "\\*\\*bold\\*\\* \\_italic\\_") {
82+
set_status(MODULE_IMPORT_BASIC, ts_failed, "markdown escaping");
83+
return;
84+
}
85+
86+
// Role comparison test
87+
dpp::role r1;
88+
dpp::role r2;
89+
r1.id = 100;
90+
r1.position = 1;
91+
r1.guild_id = 500;
92+
r2.id = 200;
93+
r2.position = 2;
94+
r2.guild_id = 500;
95+
96+
auto role_comparison_1 = [](const dpp::role& r1, const dpp::role& r2) -> bool {
97+
return (r1 < r2);
98+
};
99+
100+
auto role_comparison_2 = [](const dpp::role& r1, const dpp::role& r2) -> bool {
101+
return !(r1 > r2);
102+
}
103+
104+
if (!role_comparison_1(r1, r2) || !role_comparison_2(r1, r2)) {
105+
set_status(MODULE_IMPORT_BASIC, ts_failed, "role comparison");
106+
return;
107+
}
108+
109+
set_status(MODULE_IMPORT_BASIC, ts_success);
110+
}
111+
112+
/**
113+
* @brief Test dpp module coroutine support (if enabled)
114+
*/
115+
void test_dpp_module_coro() {
116+
start_test(MODULE_IMPORT_CORO);
117+
118+
#ifndef DPP_NO_CORO
119+
dpp::promise<int> test_promise;
120+
test_promise.set_value(42);
121+
122+
if constexpr (!requires { dpp::task<void>{}; }) {
123+
set_status(MODULE_IMPORT_CORO, ts_failed, "coroutine types not accessible");
124+
return;
125+
}
126+
127+
set_status(MODULE_IMPORT_CORO, ts_success);
128+
#else
129+
set_status(MODULE_IMPORT_CORO, ts_skipped, "coroutines disabled");
130+
#endif
131+
}
132+
133+
/**
134+
* @brief Main entry point for module tests
135+
*/
136+
void run_module_tests() {
137+
test_dpp_module_basic();
138+
test_dpp_module_coro();
139+
}
140+
141+
#endif

src/unittest/test.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,11 @@ Markdown lol \\|\\|spoiler\\|\\| \\~\\~strikethrough\\~\\~ \\`small \\*code\\* b
334334
set_test(WEBHOOK, false);
335335
}
336336

337+
// Test C++ module import
338+
#ifdef DPP_MODULES
339+
run_module_tests();
340+
#endif
341+
337342
{ // test dpp::snowflake
338343
start_test(SNOWFLAKE);
339344
bool success = true;

src/unittest/test.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,11 @@ DPP_TEST(FORUM_CHANNEL_DELETE, "delete the created forum channel", tf_online);
157157
DPP_TEST(ERRORS, "Human readable error translation", tf_offline);
158158
DPP_TEST(INVALIDUTF8, "Invalid UTF-8 handling", tf_online);
159159

160+
#ifdef DPP_MODULES
161+
DPP_TEST(MODULE_IMPORT_BASIC, "C++ module import: basic types", tf_offline);
162+
DPP_TEST(MODULE_IMPORT_CORO, "C++ module import: coroutines", tf_offline);
163+
#endif
164+
160165
DPP_TEST(GUILD_EDIT, "cluster::guild_edit", tf_online);
161166
DPP_TEST(GUILD_BAN_CREATE, "cluster::guild_ban_add ban three well-known discord accounts", tf_online);
162167
DPP_TEST(GUILD_BAN_GET, "cluster::guild_get_ban getting one of the banned accounts", tf_online);
@@ -570,6 +575,13 @@ inline constexpr auto is_owner = [](auto &&user) noexcept {
570575
return get_user_snowflake(user) == TEST_USER_ID;
571576
};
572577

578+
#ifdef DPP_MODULES
579+
/**
580+
* @brief Main entry point for module tests
581+
*/
582+
void run_module_tests();
583+
#endif
584+
573585
#define DPP_RUNTIME_CHECK(test, check, var) if (!check) { var = false; set_status(test, ts_failed, "check failed: " #check); }
574586
#define DPP_COMPILETIME_CHECK(test, check, var) static_assert(check, #test ": " #check)
575587

0 commit comments

Comments
 (0)