Viewing is open to everyone. Downloading and starring need a GitHub sign-in.
Sign in with GitHub
bridge_test.cpp
v0.1.0-build.85
Latest
Commit ede38f5
Sign in with GitHub to download. Each download is recorded with your GitHub username.
| 1 | // Native test of the Web SDK bridge (sdk/web/src/ckey_web.cpp), compiled with |
| 2 | // the system C++ compiler against the same core sources the wasm build uses. |
| 3 | // It exercises every function the JavaScript wrapper calls, so the bridge |
| 4 | // logic is verified even where Emscripten is not installed. |
| 5 | // scripts/test-native.sh (or see .github/workflows/sdk-web.yml) |
| 6 | |
| 7 | "ckey/ckey.h" |
| 8 | "ckey/telemetry.h" |
| 9 | |
| 10 | <cstdint> |
| 11 | <cstdio> |
| 12 | <cstdlib> |
| 13 | <cstring> |
| 14 | <string> |
| 15 | <vector> |
| 16 | |
| 17 | extern "C" { |
| 18 | void ckw_free(void *); |
| 19 | const char *ckw_last_error(void); |
| 20 | uint32_t ckw_last_len(void); |
| 21 | const char *ckw_software_version(void); |
| 22 | uint32_t ckw_scalable_capacity(uint32_t, uint32_t, uint32_t); |
| 23 | void *ckw_encode(const uint8_t *, uint32_t, uint32_t, uint32_t, uint32_t); |
| 24 | void ckw_symbol_free(void *); |
| 25 | void ckw_symbol_info(const void *, uint32_t *); |
| 26 | void *ckw_style_new(uint32_t); |
| 27 | void ckw_style_free(void *); |
| 28 | int ckw_style_set_rgb(void *, uint32_t, uint32_t, uint32_t, uint32_t); |
| 29 | int ckw_style_set_num(void *, uint32_t, double); |
| 30 | int ckw_style_check(const void *, const void *); |
| 31 | uint8_t *ckw_render_raster(const void *, const void *, uint32_t, uint32_t, uint32_t, uint32_t, double, uint32_t, |
| 32 | uint32_t, const uint8_t *, uint32_t, uint32_t); |
| 33 | uint8_t *ckw_encode_png_rgba(const uint8_t *, uint32_t, uint32_t, double); |
| 34 | char *ckw_render_svg(const void *, const void *, uint32_t); |
| 35 | uint8_t *ckw_render_pdf(const void *, const void *, double, uint32_t); |
| 36 | uint8_t *ckw_decode_rgba(const uint8_t *, uint32_t, uint32_t, uint32_t, uint32_t *); |
| 37 | uint8_t *ckw_decode_gray(const uint8_t *, uint32_t, uint32_t, uint32_t, uint32_t *); |
| 38 | char *ckw_safe_action(const uint8_t *, uint32_t, const uint8_t *, double, uint32_t); |
| 39 | int ckw_tel_set_mode(int); |
| 40 | int ckw_tel_get_mode(void); |
| 41 | int ckw_tel_set_client(const char *, const char *, const char *); |
| 42 | void ckw_tel_session_begin(double); |
| 43 | void ckw_tel_frame(double, double); |
| 44 | int ckw_tel_session_success(double, uint32_t); |
| 45 | void ckw_tel_session_end(double); |
| 46 | int ckw_tel_should_send(double); |
| 47 | char *ckw_tel_take_batch(const char *); |
| 48 | double ckw_tel_last_batch_id(void); |
| 49 | int ckw_tel_batch_result(double, int, double); |
| 50 | int ckw_tel_snapshot(double *); |
| 51 | void ckw_tel_reset_for_testing(void); |
| 52 | uint32_t ckw_has_certify(void); |
| 53 | int ckw_certify(const void *, const void *, uint32_t, const uint8_t *, uint32_t, const uint8_t *, uint32_t, uint32_t, |
| 54 | double, double, double, double, uint32_t, double *, void *); |
| 55 | } |
| 56 | |
| 57 | static int failures = 0; |
| 58 | (c) \ |
| 59 | do { \ |
| 60 | if (!(c)) { std::(stderr, "FAIL %s:%d: %s\n",,, #c); ++failures; } \ |
| 61 | } while (0) |
| 62 | |
| 63 | // Places an RGBA render in the middle of a larger white frame, like a photo. |
| 64 | static std::vector<uint8_t> pad(const uint8_t *px, uint32_t size, uint32_t margin, uint32_t &side) { |
| 65 | side = size + 2 * margin; |
| 66 | std::vector<uint8_t> f(static_cast<size_t>(side) * side * 4, 255); |
| 67 | for (uint32_t y = 0; y < size; ++y) |
| 68 | std::memcpy(&f[(static_cast<size_t>(y + margin) * side + margin) * 4], px + static_cast<size_t>(y) * size * 4, size * 4); |
| 69 | return f; |
| 70 | } |
| 71 | |
| 72 | static bool roundtrip(const std::string &text, uint32_t layout, uint32_t transparent, const void *style) { |
| 73 | void *sym = ckw_encode(reinterpret_cast<const uint8_t *>(text.data()), static_cast<uint32_t>(text.size()), 0, 1, layout); |
| 74 | if (!sym) { std::fprintf(stderr, "encode: %s\n", ckw_last_error()); return false; } |
| 75 | uint8_t *px = ckw_render_raster(sym, style, 512, 0, transparent, 4, 1.0, 1, 0, nullptr, 0, 0); |
| 76 | if (!px) { std::fprintf(stderr, "raster: %s\n", ckw_last_error()); ckw_symbol_free(sym); return false; } |
| 77 | uint32_t side = 0; |
| 78 | auto frame = pad(px, 512, 64, side); |
| 79 | uint32_t info[4] = {9, 9, 9, 9}; |
| 80 | uint8_t *out = ckw_decode_rgba(frame.data(), side, side, 0, info); |
| 81 | bool ok = out && ckw_last_len() == text.size() && std::memcmp(out, text.data(), text.size()) == 0 && |
| 82 | info[0] == (layout ? 1u : 0u) && info[2] == layout && info[1] >= 1; |
| 83 | if (!out) std::fprintf(stderr, "decode: %s (borders %u)\n", ckw_last_error(), info[3]); |
| 84 | ckw_free(out); |
| 85 | ckw_free(px); |
| 86 | ckw_symbol_free(sym); |
| 87 | return ok; |
| 88 | } |
| 89 | |
| 90 | int main() { |
| 91 | CHECK(std::strcmp(ckw_software_version(), CKEY_SOFTWARE_VERSION) == 0); |
| 92 | |
| 93 | // Encode + info. |
| 94 | const std::string url = "https://openckey.org"; |
| 95 | void *sym = ckw_encode(reinterpret_cast<const uint8_t *>(url.data()), static_cast<uint32_t>(url.size()), 0, 1, 0); |
| 96 | CHECK(sym != nullptr); |
| 97 | uint32_t info[5] = {}; |
| 98 | ckw_symbol_info(sym, info); |
| 99 | CHECK(info[0] >= 1 && info[0] <= 31); |
| 100 | CHECK(info[1] == 1 && info[2] == 0 && info[3] == url.size()); |
| 101 | CHECK(ckw_scalable_capacity(info[0], 1, 0) >= url.size()); |
| 102 | |
| 103 | // Encode failure carries the core's message. |
| 104 | std::vector<uint8_t> big(20000, 'x'); |
| 105 | CHECK(ckw_encode(big.data(), static_cast<uint32_t>(big.size()), 0, 1, 0) == nullptr); |
| 106 | CHECK(std::strlen(ckw_last_error()) > 0); |
| 107 | std::printf("oversize message: %s\n", ckw_last_error()); |
| 108 | |
| 109 | // Round trips through the reader pipeline (standard, print, transparent, concept). |
| 110 | CHECK(roundtrip(url, 0, 0, nullptr)); |
| 111 | CHECK(roundtrip("Hello, CKey! Grüße", 1, 0, nullptr)); |
| 112 | CHECK(roundtrip(url, 0, 1, nullptr)); |
| 113 | void *concept_style = ckw_style_new(1); |
| 114 | CHECK(concept_style != nullptr); |
| 115 | CHECK(roundtrip(url, 0, 0, concept_style)); |
| 116 | |
| 117 | // Transparent corner has alpha 0; opaque corner is white. |
| 118 | uint8_t *px = ckw_render_raster(sym, nullptr, 64, 0, 1, 4, 1.0, 1, 0, nullptr, 0, 0); |
| 119 | CHECK(px && ckw_last_len() == 64u * 64u * 4u && px[3] == 0); |
| 120 | ckw_free(px); |
| 121 | px = ckw_render_raster(sym, nullptr, 64, 1, 0, 4, 1.0, 1, 0, nullptr, 0, 0); |
| 122 | CHECK(px && px[0] == 255 && px[3] == 255); |
| 123 | uint8_t *png = ckw_encode_png_rgba(px, 64, 64, 0); |
| 124 | CHECK(png && ckw_last_len() > 8 && std::memcmp(png, "\x89PNG\r\n\x1a\n", 8) == 0); |
| 125 | ckw_free(png); |
| 126 | ckw_free(px); |
| 127 | CHECK(ckw_render_raster(sym, nullptr, 8, 0, 0, 4, 1.0, 1, 0, nullptr, 0, 0) == nullptr); // size < 16 |
| 128 | |
| 129 | char *svg = ckw_render_svg(sym, nullptr, 16); |
| 130 | CHECK(svg && std::strncmp(svg, "<svg", 4) == 0 && std::strlen(svg) == ckw_last_len()); |
| 131 | ckw_free(svg); |
| 132 | uint8_t *pdf = ckw_render_pdf(sym, nullptr, 144, 0); |
| 133 | CHECK(pdf && std::memcmp(pdf, "%PDF-", 5) == 0); |
| 134 | ckw_free(pdf); |
| 135 | |
| 136 | // A low-contrast style is refused with an explanation. |
| 137 | void *bad = ckw_style_new(0); |
| 138 | CHECK(ckw_style_set_rgb(bad, 2, 250, 250, 250) == 1); |
| 139 | CHECK(ckw_style_set_rgb(bad, 3, 250, 250, 250) == 1); |
| 140 | CHECK(ckw_style_check(sym, bad) != 0); |
| 141 | std::printf("bad style message: %s\n", ckw_last_error()); |
| 142 | CHECK(ckw_render_svg(sym, bad, 16) == nullptr); |
| 143 | CHECK(ckw_style_set_num(bad, 2, 7) == 0); |
| 144 | >= 4 |
| 145 | // Override draws the refused style as given; the check still reports it. |
| 146 | CHECK(ckw_style_set_num(bad, 10, 2) == 1); |
| 147 | char *over = ckw_render_svg(sym, bad, 16); |
| 148 | CHECK(over != nullptr); |
| 149 | ckw_free(over); |
| 150 | CHECK(ckw_style_check(sym, bad) == 0 && std::strncmp(ckw_last_error(), "override", 8) == 0); |
| 151 | CHECK(ckw_style_set_num(bad, 10, 0) == 1); |
| 152 | |
| 153 | if (ckw_has_certify()) { |
| 154 | double cert[8] = {}; |
| 155 | CHECK(ckw_certify(sym, nullptr, 0, nullptr, 0, nullptr, 0, 0, -1, -1, -1, -1, 0, cert, nullptr) == 0); |
| 156 | CHECK(cert[0] == 1 && cert[3] >= 1); |
| 157 | std::printf("certify default: certified=%g trials=%g/%g msg=%s\n", cert[0], cert[4], cert[3], ckw_last_error()); |
| 158 | // Transparent with no backdrop: background unknown, never certified. |
| 159 | CHECK(ckw_certify(sym, nullptr, 1, nullptr, 0, nullptr, 0, 0, -1, -1, -1, -1, 0, cert, nullptr) != 0 || cert[0] == 0); |
| 160 | std::printf("certify transparent/no backdrop: certified=%g msg=%s\n", cert[0], ckw_last_error()); |
| 161 | const uint8_t grey[3] = {40, 40, 40}; |
| 162 | ckw_certify(sym, nullptr, 1, grey, 1, nullptr, 0, 0, -1, -1, -1, -1, 0, cert, nullptr); |
| 163 | std::printf("certify transparent on dark grey: certified=%g msg=%s\n", cert[0], ckw_last_error()); |
| 164 | } |
| 165 | ckw_style_free(bad); |
| 166 | CHECK(ckw_style_new(9) == nullptr); |
| 167 | ckw_style_free(concept_style); |
| 168 | |
| 169 | // Blank frame: nothing decoded. |
| 170 | std::vector<uint8_t> blank(100 * 100, 255); |
| 171 | uint32_t dinfo[4]; |
| 172 | CHECK(ckw_decode_gray(blank.data(), 100, 100, 0, dinfo) == nullptr); |
| 173 | |
| 174 | // Telemetry wrappers. |
| 175 | ckw_tel_reset_for_testing(); |
| 176 | CHECK(ckw_tel_get_mode() == 1); |
| 177 | CHECK(ckw_tel_set_mode(3) != 0 && ckw_tel_get_mode() == 1); |
| 178 | CHECK(ckw_tel_set_client("web", CKEY_SOFTWARE_VERSION, "web") == 0); |
| 179 | ckw_tel_session_begin(1000); |
| 180 | ckw_tel_frame(1010, 7.6); |
| 181 | CHECK(ckw_tel_session_success(1020, 0) == 0); |
| 182 | ckw_tel_session_end(1030); |
| 183 | double snap[33] = {}; |
| 184 | CHECK(ckw_tel_snapshot(snap) == 0); |
| 185 | CHECK(snap[0] == 1 && snap[1] == 1 && snap[3] == 1 && snap[4] == 1); |
| 186 | CHECK(ckw_tel_should_send(2000) == 0); // delta younger than a minute |
| 187 | CHECK(ckw_tel_should_send(1000 + 60000) != 0); |
| 188 | char *json = ckw_tel_take_batch("2026-11-05"); |
| 189 | CHECK(json && std::strstr(json, "\"sdk\":\"web\"") && std::strstr(json, "\"platform\":\"web\"")); |
| 190 | const double id = ckw_tel_last_batch_id(); |
| 191 | CHECK(id > 0); |
| 192 | std::printf("batch: %s\n", json ? json : "(null)"); |
| 193 | ckw_free(json); |
| 194 | CHECK(ckw_tel_take_batch("2026-11-05") == nullptr); // one in flight |
| 195 | CHECK(ckw_tel_batch_result(id, 204, 62000) == 0); |
| 196 | CHECK(ckw_tel_batch_result(id, 204, 62000) != 0); // reported once |
| 197 | ckw_tel_reset_for_testing(); |
| 198 | |
| 199 | { // Safe Actions: sign with the core, then parse and verify through the bridge. |
| 200 | uint8_t seed[32] = {0x9d, 0x61, 0xb1, 0x9d, 0xef, 0xfd, 0x5a, 0x60, 0xba, 0x84, 0x4a, 0xf4, 0x92, 0xec, 0x2c, 0xc4, |
| 201 | 0x44, 0x49, 0xc5, 0x69, 0x7b, 0x32, 0x69, 0x19, 0x70, 0x3b, 0xac, 0x03, 0x1c, 0xae, 0x7f, 0x60}; |
| 202 | uint8_t pk[32]; |
| 203 | ckey_ed25519_public_key(seed, pk); |
| 204 | ckey_safe_action f{}; |
| 205 | f.scope = CKEY_SCOPE_SAME_DEVICE; |
| 206 | std::strcpy(f.issuer, "citeory.com"); std::strcpy(f.app, "com.viadere"); std::strcpy(f.action, "open.library"); |
| 207 | std::strcpy(f.key_id, "k1"); std::strcpy(f.request_id, "req-12345678"); |
| 208 | f.issued_at = 1000; f.expires_at = 1100; f.params[0] = 'h'; f.params[1] = 'i'; f.params_len = 2; |
| 209 | char text[1024]; size_t n = 0; ckey_diagnostics diag{}; |
| 210 | CHECK(ckey_safe_action_sign(&f, seed, text, sizeof text, &n, &diag) == CKEY_OK); |
| 211 | const auto *t = reinterpret_cast<const uint8_t *>(text); |
| 212 | char *parsed = ckw_safe_action(t, static_cast<uint32_t>(n), nullptr, 0, 0); |
| 213 | CHECK(parsed && std::strstr(parsed, "\"action\":\"open.library\"") && std::strstr(parsed, "\"params\":\"6869\"")); |
| 214 | ckw_free(parsed); |
| 215 | char *ok = ckw_safe_action(t, static_cast<uint32_t>(n), pk, 1050, 600); |
| 216 | CHECK(ok && std::strstr(ok, "\"request_id\":\"req-12345678\"") && std::strstr(ok, "\"scope\":0")); |
| 217 | ckw_free(ok); |
| 218 | CHECK(ckw_safe_action(t, static_cast<uint32_t>(n), pk, 1200, 600) == nullptr); |
| 219 | CHECK(std::strstr(ckw_last_error(), "expired") != nullptr); |
| 220 | uint8_t other[32] = {1}; |
| 221 | CHECK(ckw_safe_action(t, static_cast<uint32_t>(n), other, 1050, 600) == nullptr); |
| 222 | } |
| 223 | |
| 224 | ckw_symbol_free(sym); |
| 225 | if (failures) { std::fprintf(stderr, "%d failure(s)\n", failures); return 1; } |
| 226 | std::printf("bridge native tests passed\n"); |
| 227 | return 0; |
| 228 | } |