-
Notifications
You must be signed in to change notification settings - Fork 0
/
webview_test.cc
148 lines (138 loc) · 4.65 KB
/
webview_test.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
//bin/echo; [ $(uname) = "Darwin" ] && FLAGS="-framework Webkit" || FLAGS="$(pkg-config --cflags --libs gtk+-3.0 webkit2gtk-4.0)" ; c++ "$0" $FLAGS -std=c++11 -Wall -Wextra -pedantic -g -o webview_test && ./webview_test ; exit
// +build ignore
#include "webview.h"
#include <cassert>
#include <cstring>
#include <iostream>
#include <thread>
#include <unordered_map>
// =================================================================
// TEST: start app loop and terminate it.
// =================================================================
static void test_terminate() {
webview::webview w(false, nullptr);
w.dispatch([&]() { w.terminate(); });
w.run();
}
// =================================================================
// TEST: use C API to create a window, run app and terminate it.
// =================================================================
static void cb_assert_arg(webview_t w, void *arg) {
assert(w != nullptr);
assert(memcmp(arg, "arg", 3) == 0);
}
static void cb_terminate(webview_t w, void *arg) {
assert(arg == nullptr);
webview_terminate(w);
}
static void test_c_api() {
webview_t w;
w = webview_create(false, nullptr);
webview_set_size(w, 480, 320, 0);
webview_set_title(w, "Test");
webview_navigate(w, "https://github.com/zserge/webview");
webview_dispatch(w, cb_assert_arg, (void *)"arg");
webview_dispatch(w, cb_terminate, nullptr);
webview_run(w);
webview_destroy(w);
}
// =================================================================
// TEST: ensure that JS code can call native code and vice versa.
// =================================================================
struct test_webview : webview::browser_engine {
using cb_t = std::function<void(test_webview *, int, const std::string &)>;
test_webview(cb_t cb) : webview::browser_engine(true, nullptr), m_cb(cb) {}
void on_message(const std::string &msg) override { m_cb(this, i++, msg); }
int i = 0;
cb_t m_cb;
};
static void test_bidir_comms() {
test_webview browser([](test_webview *w, int i, const std::string &msg) {
std::cout << msg << std::endl;
switch (i) {
case 0:
assert(msg == "loaded");
w->eval("window.external.invoke('exiting ' + window.x)");
break;
case 1:
assert(msg == "exiting 42");
w->terminate();
break;
default:
assert(0);
}
});
browser.init(R"(
window.x = 42;
window.onload = () => {
window.external.invoke('loaded');
};
)");
browser.navigate("data:text/html,%3Chtml%3Ehello%3C%2Fhtml%3E");
browser.run();
}
// =================================================================
// TEST: ensure that JSON parsing works.
// =================================================================
static void test_json() {
auto J = webview::json_parse;
assert(J(R"({"foo":"bar"})", "foo", -1) == "bar");
assert(J(R"({"foo":""})", "foo", -1) == "");
assert(J(R"({"foo": {"bar": 1}})", "foo", -1) == R"({"bar": 1})");
assert(J(R"(["foo", "bar", "baz"])", "", 0) == "foo");
assert(J(R"(["foo", "bar", "baz"])", "", 2) == "baz");
}
static void run_with_timeout(std::function<void()> fn, int timeout_ms) {
std::atomic_flag flag_running = ATOMIC_FLAG_INIT;
flag_running.test_and_set();
std::thread timeout_thread([&]() {
for (int i = 0; i < timeout_ms / 100; i++) {
if (!flag_running.test_and_set()) {
return;
}
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
std::cout << "Exiting due to a timeout." << std::endl;
exit(1);
});
fn();
flag_running.clear();
timeout_thread.join();
}
int main(int argc, char *argv[]) {
std::unordered_map<std::string, std::function<void()>> all_tests = {
{"terminate", test_terminate},
{"c_api", test_c_api},
{"bidir_comms", test_bidir_comms},
{"json", test_json},
};
// Without arguments run all tests, one-by-one by forking itself.
// With a single argument - run the requested test
if (argc == 1) {
int failed = 0;
for (const auto &test : all_tests) {
std::cout << "TEST: " << test.first << std::endl;
int status = system((std::string(argv[0]) + " " + test.first).c_str());
if (status == 0) {
std::cout << " PASS " << std::endl;
} else {
std::cout << " FAIL: " << status << std::endl;
failed = 1;
}
}
return failed;
}
if (argc == 2) {
auto it = all_tests.find(argv[1]);
if (it != all_tests.end()) {
run_with_timeout(it->second, 5000);
return 0;
}
}
std::cout << "USAGE: " << argv[0] << " [test name]" << std::endl;
std::cout << "Tests: " << std::endl;
for (const auto &test : all_tests) {
std::cout << " " << test.first << std::endl;
}
return 1;
}