Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: add auto testing of examples #854

Merged
merged 13 commits into from
Sep 14, 2023
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
45 changes: 45 additions & 0 deletions .github/workflows/test-docs-examples.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
name: Test compile documentation examples
on:
push:
branches:
- 'dev'
files:
- '**Doxyfile'
- '**docpages/example_code/**'
pull_request:
files:
- '**Doxyfile'
- '**docpages/example_code/**'
workflow_dispatch:

jobs:
test_docs_examples:
name: Test build examples
runs-on: ubuntu-22.04

steps:
- name: Harden Runner
uses: step-security/harden-runner@8ca2b8b2ece13480cda6dacd3511b49857a23c09 # v2.5.1
with:
egress-policy: audit

- name: Checkout D++
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
with:
submodules: recursive

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

- name: Generate CMake
run: mkdir build && cd build && cmake -DDPP_NO_VCPKG=ON -DAVX_TYPE=T_fallback -DDPP_CORO=ON -DCMAKE_BUILD_TYPE=Debug ..
env:
CXX: g++-12

- name: Build Project
run: cd build && make -j2 && sudo make install

- name: Test compile examples
run: cd docpages/example_code && mkdir build && cd build && cmake .. && make -j2
env:
CXX: g++-12
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ build
buildtools/composer.phar
src/build
cmake-build-debug
docpages/example_code/build

# tests
test
Expand All @@ -28,4 +29,4 @@ core
config.json
.misspell-fixer.ignore
compile_commands.json
src/dpp/dpp.rc
src/dpp/dpp.rc
6 changes: 4 additions & 2 deletions Doxyfile
Original file line number Diff line number Diff line change
Expand Up @@ -790,7 +790,8 @@ EXCLUDE = deps \
build \
include/dpp/format \
include/dpp/nlohmann \
docpages/include
docpages/include \
docpages/example_code

# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
# directories that are symbolic links (a Unix file system feature) are excluded
Expand Down Expand Up @@ -830,7 +831,8 @@ EXCLUDE_SYMBOLS = nlohmann::* \
# that contain example code fragments that are included (see the \include
# command).

EXAMPLE_PATH =docpages/include
EXAMPLE_PATH = docpages/include \
docpages/example_code

# If the value of the EXAMPLE_PATH tag contains directories, you can use the
# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
Expand Down
45 changes: 45 additions & 0 deletions docpages/example_code/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#
# D++ (DPP), The Lightweight C++ Discord Library
#
# Copyright 2021 Craig Edwards <[email protected]>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

# Example programs test compilation
# This build script is executed by a GitHub action to ensure all example
# programs compile correctly. It does not attempt to run them, as there
# is no way to know if the program successfully did its thing, plus
# examples do not have a valid token. This build script assumes the
# following system dependencies are available:
#
# g++-12 or later
# liboggz-dev
# libmpg123-dev
# dpp latest master with -DDPP_CORO=ON installed sytemwide

cmake_minimum_required (VERSION 3.16)
project(documentation_tests)

string(ASCII 27 Esc)

set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DDPP_CORO -std=c++20 -pthread -O0 -fPIC -rdynamic -DFMT_HEADER_ONLY -Wall -Wextra -Wpedantic -Werror -Wno-unused-parameter")
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O0")

file(GLOB example_list ./*.cpp)
foreach (example ${example_list})
get_filename_component(examplename ${example} NAME)
message(STATUS "Found example '${Esc}[1;34m${examplename}${Esc}[m'")
add_executable(${examplename}_out ${example})
target_link_libraries(${examplename}_out dl dpp mpg123 oggz)
endforeach(example)
34 changes: 34 additions & 0 deletions docpages/example_code/attachments1.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#include <dpp/dpp.h>

int main() {
dpp::cluster bot("token");

bot.on_log(dpp::utility::cout_logger());

/* The event is fired when someone issues your commands */
bot.on_slashcommand([&bot](const dpp::slashcommand_t& event) {
/* Check which command they ran */
if (event.command.get_command_name() == "file") {

dpp::message msg(event.command.channel_id, "Hey there, I've got a new file!");

/* attach the file to the message */
msg.add_file("foobar.txt", dpp::utility::read_file("path_to_your_file.txt"));

/* Reply to the user with the message, with our file attached. */
event.reply(msg);
}
});

bot.on_ready([&bot](const dpp::ready_t& event) {
if (dpp::run_once<struct register_bot_commands>()) {

/* Create and register a command when the bot is ready */
bot.global_command_create(dpp::slashcommand("file", "Send a message with a file attached!", bot.me.id));
}
});

bot.start(dpp::st_wait);

return 0;
}
41 changes: 41 additions & 0 deletions docpages/example_code/attachments2.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#include <dpp/dpp.h>

int main() {
dpp::cluster bot("token");

bot.on_log(dpp::utility::cout_logger());

/* The event is fired when someone issues your commands */
bot.on_slashcommand([&bot](const dpp::slashcommand_t& event) {
/* Check which command they ran */
if (event.command.get_command_name() == "file") {

/* Request the image from the URL specified and capture the event in a lambda. */
bot.request("https://dpp.dev/DPP-Logo.png", dpp::m_get, [event](const dpp::http_request_completion_t & httpRequestCompletion) {

/* Create a message */
dpp::message msg(event.command.channel_id, "This is my new attachment:");

/* Attach the image to the message, only on success (Code 200). */
if (httpRequestCompletion.status == 200) {
msg.add_file("logo.png", httpRequestCompletion.body);
}

/* Send the message, with our attachment. */
event.reply(msg);
});
}
});

bot.on_ready([&bot](const dpp::ready_t& event) {
if (dpp::run_once<struct register_bot_commands>()) {

/* Create and register a command when the bot is ready */
bot.global_command_create(dpp::slashcommand("file", "Send a message with an image attached from the internet!", bot.me.id));
}
});

bot.start(dpp::st_wait);

return 0;
}
41 changes: 41 additions & 0 deletions docpages/example_code/attachments3.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#include <dpp/dpp.h>

int main() {
dpp::cluster bot("token");

bot.on_log(dpp::utility::cout_logger());

/* The event is fired when someone issues your commands */
bot.on_slashcommand([&bot](const dpp::slashcommand_t& event) {
/* Check which command they ran */
if (event.command.get_command_name() == "file") {

/* Create a message. */
dpp::message msg(event.command.channel_id, "");

/* Attach the image to the message we just created. */
msg.add_file("image.jpg", dpp::utility::read_file("path_to_your_image.jpg"));

/* Create an embed. */
dpp::embed embed;
embed.set_image("attachment://image.jpg"); /* Set the image of the embed to the attached image. */

/* Add the embed to the message. */
msg.add_embed(embed);

event.reply(msg);
}
});

bot.on_ready([&bot](const dpp::ready_t& event) {
if (dpp::run_once<struct register_bot_commands>()) {

/* Create and register a command when the bot is ready */
bot.global_command_create(dpp::slashcommand("file", "Send a local image along with an embed with the image!", bot.me.id));
}
});

bot.start(dpp::st_wait);

return 0;
}
67 changes: 67 additions & 0 deletions docpages/example_code/autocomplete.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
#include <dpp/dpp.h>

int main()
{
dpp::cluster bot("token");

bot.on_log(dpp::utility::cout_logger());

bot.on_ready([&bot](const dpp::ready_t & event) {
if (dpp::run_once<struct register_bot_commands>()) {

/* Create a new global command once on ready event */
bot.global_command_create(dpp::slashcommand("blep", "Send a random adorable animal photo", bot.me.id)
.add_option(
/* If you set the auto complete setting on a command option, it will trigger the on_autocomplete
* event whenever discord needs to fill information for the choices. You cannot set any choices
* here if you set the auto complete value to true.
*/
dpp::command_option(dpp::co_string, "animal", "The type of animal").set_auto_complete(true)
)
);
}
});

/* The interaction create event is fired when someone issues your commands */
bot.on_slashcommand([&bot](const dpp::slashcommand_t & event) {

/* Check which command they ran */
if (event.command.get_command_name() == "blep") {
/* Fetch a parameter value from the command parameters */
std::string animal = std::get<std::string>(event.get_parameter("animal"));
/* Reply to the command. There is an overloaded version of this
* call that accepts a dpp::message so you can send embeds.
*/
event.reply("Blep! You chose " + animal);
}
});

/* The on_autocomplete event is fired whenever discord needs information to fill in a command options's choices.
* You must reply with a REST event within 500ms, so make it snappy!
*/
bot.on_autocomplete([&bot](const dpp::autocomplete_t & event) {
for (auto & opt : event.options) {
/* The option which has focused set to true is the one the user is typing in */
if (opt.focused) {
/* In a real world usage of this function you should return values that loosely match
* opt.value, which contains what the user has typed so far. The opt.value is a variant
* and will contain the type identical to that of the slash command parameter.
* Here we can safely know it is string.
*/
std::string uservalue = std::get<std::string>(opt.value);
bot.interaction_response_create(event.command.id, event.command.token, dpp::interaction_response(dpp::ir_autocomplete_reply)
.add_autocomplete_choice(dpp::command_option_choice("squids", "lots of squids"))
.add_autocomplete_choice(dpp::command_option_choice("cats", "a few cats"))
.add_autocomplete_choice(dpp::command_option_choice("dogs", "bucket of dogs"))
.add_autocomplete_choice(dpp::command_option_choice("elephants", "bottle of elephants"))
);
bot.log(dpp::ll_debug, "Autocomplete " + opt.name + " with value '" + uservalue + "' in field " + event.name);
break;
}
}
});

bot.start(dpp::st_wait);

return 0;
}
60 changes: 60 additions & 0 deletions docpages/example_code/cache_messages.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#include <dpp/dpp.h>
#include <sstream>

int main() {
/* Create bot */
dpp::cluster bot("token", dpp::i_default_intents | dpp::i_message_content); /* Because we're handling messages, we need to use the "i_message_content" intent! */

/* Create a cache to contain types of dpp::message */
dpp::cache<dpp::message> message_cache;

bot.on_log(dpp::utility::cout_logger());

/* Message handler */
bot.on_message_create([&](const dpp::message_create_t &event) {
/* Make a permanent pointer using new, for each message to be cached */
dpp::message* m = new dpp::message();

/* Store the message into the pointer by copying it */
*m = event.msg;

/* Store the new pointer to the cache using the store() method */
message_cache.store(m);
});

/* The event is fired when someone issues your commands */
bot.on_slashcommand([&bot, &message_cache](const dpp::slashcommand_t& event) {
/* Check which command they ran */
if (event.command.get_command_name() == "get") {

dpp::message* find_msg = message_cache.find(std::get<std::string>(event.get_parameter("message_id")));

/* If find_msg is null, tell the user and return. */
if (!find_msg) {
event.reply("There is no message cached with this ID");
return;
}

event.reply("This message had the following content: " + find_msg->content);
}
});

bot.on_ready([&bot](const dpp::ready_t& event) {
if (dpp::run_once<struct register_bot_commands>()) {

/* Create a new command. */
dpp::slashcommand newcommand("get", "Get the contents of a message that was cached via an id", bot.me.id);

/* Add a parameter option. */
newcommand.add_option(dpp::command_option(dpp::co_string, "message_id", "The ID of the message you want to find", true));

/* Register the command */
bot.global_command_create(newcommand);
}
});

/* Start bot */
bot.start(dpp::st_wait);

return 0;
}
Loading