Path: blob/master/tests/compatibility_test/src/compat_checker.c
20977 views
/**************************************************************************/1/* compat_checker.c */2/**************************************************************************/3/* This file is part of: */4/* GODOT ENGINE */5/* https://godotengine.org */6/**************************************************************************/7/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */8/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */9/* */10/* Permission is hereby granted, free of charge, to any person obtaining */11/* a copy of this software and associated documentation files (the */12/* "Software"), to deal in the Software without restriction, including */13/* without limitation the rights to use, copy, modify, merge, publish, */14/* distribute, sublicense, and/or sell copies of the Software, and to */15/* permit persons to whom the Software is furnished to do so, subject to */16/* the following conditions: */17/* */18/* The above copyright notice and this permission notice shall be */19/* included in all copies or substantial portions of the Software. */20/* */21/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */22/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */23/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */24/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */25/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */26/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */27/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */28/**************************************************************************/2930#include "compat_checker.h"31#include <stdbool.h>32#include <stdio.h>33#include <string.h>3435GDExtensionInterfaceClassdbGetMethodBind classdb_get_method_bind = NULL;36GDExtensionInterfaceVariantGetPtrBuiltinMethod variant_get_ptr_builtin_method = NULL;37GDExtensionInterfaceVariantGetPtrUtilityFunction variant_get_ptr_utility_function = NULL;3839GDExtensionPtrDestructor string_name_destructor = NULL;40GDExtensionInterfaceStringNameNewWithLatin1Chars string_name_new_with_latin1_chars = NULL;4142typedef struct43{44uint8_t data[8];45} StringName;4647/**48* Platform APIs are being registered only after extensions, making them unavailable during initialization (on any level).49*50* Due to that we run the tests in Mainloop `startup_callback` (available since Godot 4.5), called after the initialization.51*/52void startup_func() {53bool success = (builtin_methods_compatibility_test() && class_methods_compatibility_test() && utility_functions_compatibility_test());54if (success) {55fprintf(stdout, "Outcome = SUCCESS\n");56} else {57fprintf(stderr, "Outcome = FAILURE\n");58}59fprintf(stdout, "COMPATIBILITY TEST FINISHED.\n");60}6162GDExtensionMainLoopCallbacks callbacks = {63(GDExtensionMainLoopStartupCallback)startup_func,64NULL,65NULL66};6768void initialize_compatibility_test(void *p_userdata, GDExtensionInitializationLevel p_level) {}6970void deinitialize_compatibility_test(void *p_userdata, GDExtensionInitializationLevel p_level) {}7172GDExtensionBool builtin_methods_compatibility_test() {73FILE *file = fopen("./builtin_methods.txt", "r");74if (file == NULL) {75fprintf(stderr, "Failed to open file `builtin_methods.txt` \n");76return false;77}7879bool ret = true;80char line[512];8182while (fgets(line, sizeof line, file) != NULL) {83int variant_type;84char method_name[128];85GDExtensionInt hash;86if (sscanf(line, "%d %s %ld", &variant_type, method_name, &hash) != 3) {87continue;88}8990StringName method_stringname;91string_name_new_with_latin1_chars(&method_stringname, method_name, false);92GDExtensionPtrBuiltInMethod method_bind = variant_get_ptr_builtin_method(variant_type, &method_stringname, hash);9394if (method_bind == NULL) {95fprintf(stderr, "Method bind not found: %d::%s (hash: %ld)\n", variant_type, method_name, hash);96ret = false;97}9899string_name_destructor(&method_stringname);100}101102fclose(file);103return ret;104}105106GDExtensionBool utility_functions_compatibility_test() {107FILE *file = fopen("./utility_functions.txt", "r");108if (file == NULL) {109fprintf(stderr, "Failed to open file `utility_functions.txt` \n");110return false;111}112113bool ret = true;114char line[256];115116while (fgets(line, sizeof line, file) != NULL) {117char method_name[128];118GDExtensionInt hash;119if (sscanf(line, "%s %ld", method_name, &hash) != 2) {120continue;121}122123StringName method_stringname;124string_name_new_with_latin1_chars(&method_stringname, method_name, false);125GDExtensionPtrUtilityFunction function_bind = variant_get_ptr_utility_function(&method_stringname, hash);126127if (function_bind == NULL) {128fprintf(stderr, "Utility function not found: %s (hash: %ld)\n", method_name, hash);129ret = false;130}131132string_name_destructor(&method_stringname);133}134135fclose(file);136return ret;137}138139GDExtensionBool class_methods_compatibility_test() {140FILE *file = fopen("./class_methods.txt", "r");141if (file == NULL) {142fprintf(stderr, "Failed to open file `class_methods.txt` \n");143return false;144}145146char current_class_name[128] = "";147bool ret = true;148char line[512];149bool has_class_string = false;150StringName p_classname;151152while (fgets(line, sizeof(line), file) != NULL) {153GDExtensionInt hash;154StringName p_methodname;155char class_name[128];156char method_name[128];157158if (sscanf(line, "%s %s %ld", class_name, method_name, &hash) != 3) {159continue;160}161162if (strcmp(current_class_name, class_name) != 0) {163if (has_class_string) {164string_name_destructor(&p_classname);165}166strcpy(current_class_name, class_name);167168string_name_new_with_latin1_chars(&p_classname, current_class_name, false);169170has_class_string = true;171}172173string_name_new_with_latin1_chars(&p_methodname, method_name, false);174GDExtensionMethodBindPtr method_bind = classdb_get_method_bind(&p_classname, &p_methodname, hash);175176if (method_bind == NULL) {177fprintf(stderr, "Method bind not found: %s.%s (hash: %ld)\n", class_name, method_name, hash);178ret = false;179}180181string_name_destructor(&p_methodname);182}183184if (has_class_string) {185string_name_destructor(&p_classname);186}187188fclose(file);189return ret;190}191192GDExtensionBool __attribute__((visibility("default"))) compatibility_test_init(GDExtensionInterfaceGetProcAddress p_get_proc_address, GDExtensionClassLibraryPtr p_library, GDExtensionInitialization *r_initialization) {193classdb_get_method_bind = (GDExtensionInterfaceClassdbGetMethodBind)p_get_proc_address("classdb_get_method_bind");194if (classdb_get_method_bind == NULL) {195fprintf(stderr, "Failed to load interface method `classdb_get_method_bind`\n");196return false;197}198199variant_get_ptr_builtin_method = (GDExtensionInterfaceVariantGetPtrBuiltinMethod)p_get_proc_address("variant_get_ptr_builtin_method");200if (variant_get_ptr_builtin_method == NULL) {201fprintf(stderr, "Failed to load interface method `variant_get_ptr_builtin_method`\n");202return false;203}204205variant_get_ptr_utility_function = (GDExtensionInterfaceVariantGetPtrUtilityFunction)p_get_proc_address("variant_get_ptr_utility_function");206if (variant_get_ptr_utility_function == NULL) {207fprintf(stderr, "Failed to load interface method `variant_get_ptr_utility_function`\n");208return false;209}210211GDExtensionInterfaceVariantGetPtrDestructor variant_get_ptr_destructor = (GDExtensionInterfaceVariantGetPtrDestructor)p_get_proc_address("variant_get_ptr_destructor");212if (variant_get_ptr_destructor == NULL) {213fprintf(stderr, "Failed to load interface method `variant_get_ptr_destructor`\n");214return false;215}216string_name_destructor = variant_get_ptr_destructor(GDEXTENSION_VARIANT_TYPE_STRING_NAME);217218string_name_new_with_latin1_chars = (GDExtensionInterfaceStringNameNewWithLatin1Chars)p_get_proc_address("string_name_new_with_latin1_chars");219if (classdb_get_method_bind == NULL) {220fprintf(stderr, "Failed to load interface method `string_name_new_with_latin1_chars`\n");221return false;222}223224GDExtensionInterfaceRegisterMainLoopCallbacks register_main_loop_callbacks = (GDExtensionInterfaceRegisterMainLoopCallbacks)p_get_proc_address("register_main_loop_callbacks");225if (register_main_loop_callbacks == NULL) {226fprintf(stderr, "Failed to load interface method `register_main_loop_callbacks`\n");227return false;228}229230register_main_loop_callbacks(p_library, &callbacks);231232r_initialization->initialize = initialize_compatibility_test;233r_initialization->deinitialize = deinitialize_compatibility_test;234r_initialization->userdata = NULL;235r_initialization->minimum_initialization_level = GDEXTENSION_INITIALIZATION_EDITOR;236237return true;238}239240241