Skip to content

Instantly share code, notes, and snippets.

@keea
Created May 15, 2024 21:21
Show Gist options
  • Save keea/d8555d004ac6345bf0c5c88edc0f5757 to your computer and use it in GitHub Desktop.
Save keea/d8555d004ac6345bf0c5c88edc0f5757 to your computer and use it in GitHub Desktop.
이 테스트 스위트는 Emscripten을 사용하여 구현된 웹어셈블리 바인딩의 기능을 확인합니다. 제공된 C++ 코드는 Emscripten의 바인딩 기능을 사용하여 C++ 함수 및 클래스를 JavaScript에 노출하는 방법을 보여줍니다.

WebAssembly Test Suite

이 테스트 스위트는 Emscripten을 사용하여 구현된 웹어셈블리 바인딩의 기능을 확인합니다. 제공된 C++ 코드는 Emscripten의 바인딩 기능을 사용하여 C++ 함수 및 클래스를 JavaScript에 노출하는 방법을 보여줍니다.

빌드 방법

도커 빌드:

  • 필수 조건: Docker
docker run --rm -v$(pwd):/src -u$(id -u)$(id -g) emscripten/emsdk bash -c "emcmake cmake -B build-web -DCMAKE_BUILD_TYPE=Release && cmake --build build-web"

CMake 빌드:

  • 필수 조건:
    • Emscripten SDK가 설치되어 있고 환경 변수가 구성되어 있어야 합니다.
    • CMake
emcmake cmake -B build-web
cmake --build build-web

Running Tests

테스트를 실행할 때는 Google Chrome이 필요합니다.

./run_test.sh ./build-web/gtestEmscripten.html

Tests

  • Add: add 함수를 테스트하여 올바른 덧셈을 확인합니다.
  • Exclaim: exclaim 함수를 테스트하여 문자열 연결이 올바른지 확인합니다.
  • ProcessMessage: 사용자 정의 옵션으로 processMessage 함수를 테스트합니다.
  • Counter: Counter 클래스를 테스트하여 올바른 초기화 및 메서드를 확인합니다.

레퍼런스

더 자세한 정보를 원하시면 다음 문서를 참고하세요:

cmake_minimum_required( VERSION 3.10.2 )
set(TARGET gtestEmscripten)
project( ${TARGET} )
set(CMAKE_CXX_STANDARD 17)
include_directories(
${CMAKE_CURRENT_SOURCE_DIR}/
)
add_executable(${TARGET} ${CMAKE_CURRENT_SOURCE_DIR}/embind.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp)
include(FetchContent)
FetchContent_Declare(
googletest
GIT_REPOSITORY https://github.com/google/googletest.git
GIT_TAG v1.14.0
)
FetchContent_MakeAvailable(googletest)
include(GoogleTest)
set(LOPTS "${LOPTS} -lembind -O3 -std=c++11 -s ASYNCIFY")
set_property(TARGET ${TARGET} PROPERTY SUFFIX ".html")
link_libraries("-lembind")
target_link_options(${TARGET} PRIVATE "--emrun")
set(LOPTS "${LOPTS} -s EXPORTED_RUNTIME_METHODS='[\"ccall\", \"cwrap\", \"addFunction\", \"getValue\"]'")
set_target_properties(${TARGET}
PROPERTIES
LINK_FLAGS ${LOPTS}
)
target_link_libraries(${TARGET} PRIVATE gtest_main)
#include <emscripten/bind.h>
#include <string>
using namespace emscripten;
double add(double a, double b) { return a + b; }
std::string exclaim(std::string message) { return message + "!"; }
struct ProcessMessageOpts {
bool reverse;
bool exclaim;
int repeat;
};
std::string processMessage(std::string message, ProcessMessageOpts opts) {
std::string copy = std::string(message);
if (opts.reverse) {
std::reverse(copy.begin(), copy.end());
}
if (opts.exclaim) {
copy += "!";
}
std::string acc = std::string("");
for (int i = 0; i < opts.repeat; i++) {
acc += copy;
}
return acc;
}
class Counter {
public:
int counter;
Counter(int init) : counter(init) {}
void increase() { counter++; }
int squareCounter() { return counter * counter; }
};
EMSCRIPTEN_BINDINGS(my_module) {
function("add", &add);
function("exclaim", &exclaim);
value_object<ProcessMessageOpts>("ProcessMessageOpts")
.field("reverse", &ProcessMessageOpts::reverse)
.field("exclaim", &ProcessMessageOpts::exclaim)
.field("repeat", &ProcessMessageOpts::repeat);
function("processMessage", &processMessage);
class_<Counter>("Counter")
.constructor<int>()
.function("increase", &Counter::increase)
.function("squareCounter", &Counter::squareCounter)
.property("counter", &Counter::counter);
};
#!/bin/bash
HTML=$1
shift
# Chrome
exec emrun --browser chrome --browser_args="--headless --disable-gpu --remote-debugging-port=9222" --kill_exit ${HTML} -- "$@" 2>/dev/null
#include <emscripten.h>
#include <emscripten/bind.h>
#include <emscripten/val.h>
#include <string>
#include "gtest/gtest.h"
using namespace emscripten;
TEST(WebTest, Add) {
val Module = val::global("Module");
double add_result = Module.call<double>("add", 1, 2);
EXPECT_DOUBLE_EQ(1 + 2, add_result);
}
TEST(WebTest, Exclaim) {
val Module = val::global("Module");
std::string result =
Module.call<std::string>("exclaim", std::string("hello"));
EXPECT_EQ("hello!", result);
}
TEST(WebTest, ProcessMessage) {
val Module = val::global("Module");
emscripten::val opts = emscripten::val::object();
opts.set("reverse", false);
opts.set("exclaim", true);
opts.set("repeat", 3);
std::string result = Module.call<std::string>(
"processMessage", std::string("hello world"), opts);
EXPECT_EQ("hello world!hello world!hello world!", result);
}
TEST(WebTest, Counter) {
val Module = val::global("Module");
val counter = Module["Counter"].new_(22);
EXPECT_EQ(22, counter["counter"].as<int>());
counter.call<void>("increase");
EXPECT_EQ(23, counter["counter"].as<int>());
EXPECT_EQ(529, counter.call<int>("squareCounter"));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment