| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188 |
- /*
- * Copyright © 2025 Pierre Le Marre <dev@wismill.eu>
- * SPDX-License-Identifier: MIT
- */
- #include "config.h"
- #include "test-config.h"
- #include "test.h"
- #ifdef _WIN32
- int
- main(void)
- {
- test_init();
- return SKIP_TEST;
- }
- #else
- #include <assert.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <sys/wait.h>
- #include "xkbcommon/xkbcommon-keysyms.h"
- #include "xkbcommon/xkbcommon.h"
- #include "utils.h"
- #include "src/keysym.h"
- static void
- test_unicode_keysyms_consistency(uint32_t start, uint32_t end)
- {
- static_assert(XKB_KEYSYM_NAME_MAX_SIZE > XKB_KEYSYM_UTF8_MAX_SIZE,
- "Buffer too small");
- char buffer[XKB_KEYSYM_NAME_MAX_SIZE] = {0};
- char utf8[XKB_KEYSYM_UTF8_MAX_SIZE] = {0};
- for (uint32_t cp = start; cp <= end; cp++) {
- xkb_keysym_t unicode = XKB_KEYSYM_UNICODE_OFFSET + cp;
- xkb_keysym_t canonical = xkb_utf32_to_keysym(cp);
- int count = xkb_keysym_get_name(unicode, buffer, sizeof(buffer));
- assert(count > 0);
- if (cp == 0 || is_surrogate(cp)) {
- /*
- * Invalid code points
- */
- /* No conversion from code point */
- assert(canonical == XKB_KEY_NoSymbol);
- /* No conversion to code point */
- assert(xkb_keysym_to_utf32(unicode) == 0);
- char *end_ptr = NULL;
- if (cp == 0) {
- /* Corresponding name hexadecimal format, unchanged */
- assert(strtoull(buffer, &end_ptr, 16) == unicode);
- } else {
- /* Unicode notation */
- assert(count == 5 && buffer[0] == 'U');
- assert(strtoull(buffer + 1, &end_ptr, 16) == cp);
- }
- assert(*end_ptr == '\0');
- /* Roundtrip hexadecimal name */
- xkb_keysym_t ks = xkb_keysym_from_name(buffer, XKB_KEYSYM_NO_FLAGS);
- assert(ks == unicode);
- /* Check Unicode format */
- snprintf(buffer, sizeof(buffer), "U%"PRIX32, cp);
- ks = xkb_keysym_from_name(buffer, XKB_KEYSYM_NO_FLAGS);
- assert((cp == 0 && ks == XKB_KEY_NoSymbol) ^
- (is_surrogate(cp) && ks == unicode));
- /* Cannot convert to UTF-8 */
- count = xkb_keysym_to_utf8(unicode, buffer, sizeof(buffer));
- assert(count == 0);
- } else {
- /*
- * Valid code points
- */
- /* Canonical keysym may be different but is set */
- assert_printf((canonical == unicode) ^
- ((0x20 <= cp && cp <= 0x100 && cp != 0x7f && canonical == cp) ||
- (canonical != unicode &&
- canonical != XKB_KEY_NoSymbol &&
- (canonical != cp || canonical == XKB_KEY_EuroSign))),
- "Code point: U+%04"PRIX32", Unicode: %#"PRIx32", "
- "canonical: %#"PRIx32"\n",
- cp, unicode, canonical);
- /* Conversion to code point has the same expected result */
- assert(xkb_keysym_to_utf32(unicode) == cp);
- assert(xkb_keysym_to_utf32(canonical) == cp); /* roundtrip */
- /* Check name roundtrip */
- xkb_keysym_t ks = xkb_keysym_from_name(buffer, XKB_KEYSYM_NO_FLAGS);
- assert((unicode != canonical && ks == canonical) ^ (ks == unicode));
- /* Can use Unicode format */
- if (buffer[0] == 'U' && count > 4 && is_digit(buffer[1])) {
- /* Name already a Unicode notation: skip.
- * Note that the heuristic may fail to detect a Unicode notation,
- * but it is only meant to make the overall test faster. */
- } else {
- snprintf(buffer, sizeof(buffer), "U%"PRIX32, cp);
- ks = xkb_keysym_from_name(buffer, XKB_KEYSYM_NO_FLAGS);
- assert((unicode != canonical && ks == canonical) ^ (ks == unicode));
- }
- /* Roundtrip: numeric hexadecimal format for Unicode keysym */
- assert(snprintf(buffer, sizeof(buffer), "%#"PRIx32, unicode) == 9);
- ks = xkb_keysym_from_name(buffer, XKB_KEYSYM_NO_FLAGS);
- assert(ks == unicode);
- /* Can convert to UTF-8 (Unicode keysym) */
- count = xkb_keysym_to_utf8(unicode, buffer, sizeof(buffer));
- assert(count > 0);
- if (canonical != unicode) {
- /* Canonical keysym convert to same UTF-8 */
- const int count2 = xkb_keysym_to_utf8(canonical, utf8, sizeof(utf8));
- assert(count2 == count);
- assert(strcmp(buffer, utf8) == 0);
- /* Roundtrip: numeric hexadecimal format for canonical keysym */
- count = xkb_keysym_get_name(canonical, buffer, sizeof(buffer));
- assert(count > 0);
- assert(xkb_keysym_from_name(buffer, XKB_KEYSYM_NO_FLAGS) == canonical);
- assert(snprintf(buffer, sizeof(buffer), "%#"PRIx32, canonical) > 2);
- assert(xkb_keysym_from_name(buffer, XKB_KEYSYM_NO_FLAGS) == canonical);
- }
- }
- }
- }
- int
- main(int argc, char *argv[])
- {
- test_init();
- unsigned long int NUM_PROCESSES = 0;
- if (argc > 1) {
- NUM_PROCESSES = strtoul(argv[1], NULL, 10);
- }
- if (NUM_PROCESSES == 0 || NUM_PROCESSES > 32)
- NUM_PROCESSES = 4;
- const uint32_t max_codepoint = 0x10ffff;
- const uint32_t chunk = max_codepoint / NUM_PROCESSES;
- pid_t pids[NUM_PROCESSES];
- for (unsigned long int i = 0; i < NUM_PROCESSES; i++) {
- pid_t pid = fork();
- if (pid == 0) {
- /* Child */
- const uint32_t start = (uint32_t)i * chunk;
- const uint32_t end = (i == NUM_PROCESSES - 1)
- ? max_codepoint
- : start + chunk;
- test_unicode_keysyms_consistency(start, end);
- exit(EXIT_SUCCESS);
- } else if (pid > 0) {
- /* Parent */
- pids[i] = pid;
- } else {
- perror("fork");
- return TEST_SETUP_FAILURE;
- }
- }
- /* Wait for children */
- int exit_code = EXIT_SUCCESS;
- for (unsigned long int i = 0; i < NUM_PROCESSES; i++) {
- int status;
- if (waitpid(pids[i], &status, 0) == -1) {
- perror("waitpid");
- exit_code = EXIT_FAILURE;
- } else if (WIFEXITED(status)) {
- int code = WEXITSTATUS(status);
- if (code != EXIT_SUCCESS) {
- fprintf(stderr,
- "Child PID %d exited with code %d\n",
- pids[i], code);
- exit_code = EXIT_FAILURE;
- }
- } else if (WIFSIGNALED(status)) {
- fprintf(stderr,
- "Child PID %d terminated by signal %d\n",
- pids[i], WTERMSIG(status));
- exit_code = EXIT_FAILURE;
- }
- }
- return exit_code;
- }
- #endif
|