Edit

kc3-lang/libxkbcommon/test/keysym-unicode.c

Branch :

  • Show log

    Commit

  • Author : Benjamin Gilbert
    Date : 2025-04-28 08:37:31
    Hash : 0bfd097c
    Message : test: Fix main() function prototype Fix compilation error when building for Windows with clang-cl: ../subprojects/libxkbcommon-xkbcommon-1.9.0/test/keysym-unicode.c:11:1: error: return type defaults to 'int' [-Wimplicit-int] ../subprojects/libxkbcommon-xkbcommon-1.9.0/test/keysym-unicode.c:11:1: warning: function declaration isn't a prototype [-Wstrict-prototypes]

  • test/keysym-unicode.c
  • /*
     * Copyright © 2025 Pierre Le Marre <dev@wismill.eu>
     * SPDX-License-Identifier: MIT
     */
    #include "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 "test.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 = 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