Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/tests/compatibility_test/src/compat_checker.c
20977 views
1
/**************************************************************************/
2
/* compat_checker.c */
3
/**************************************************************************/
4
/* This file is part of: */
5
/* GODOT ENGINE */
6
/* https://godotengine.org */
7
/**************************************************************************/
8
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10
/* */
11
/* Permission is hereby granted, free of charge, to any person obtaining */
12
/* a copy of this software and associated documentation files (the */
13
/* "Software"), to deal in the Software without restriction, including */
14
/* without limitation the rights to use, copy, modify, merge, publish, */
15
/* distribute, sublicense, and/or sell copies of the Software, and to */
16
/* permit persons to whom the Software is furnished to do so, subject to */
17
/* the following conditions: */
18
/* */
19
/* The above copyright notice and this permission notice shall be */
20
/* included in all copies or substantial portions of the Software. */
21
/* */
22
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29
/**************************************************************************/
30
31
#include "compat_checker.h"
32
#include <stdbool.h>
33
#include <stdio.h>
34
#include <string.h>
35
36
GDExtensionInterfaceClassdbGetMethodBind classdb_get_method_bind = NULL;
37
GDExtensionInterfaceVariantGetPtrBuiltinMethod variant_get_ptr_builtin_method = NULL;
38
GDExtensionInterfaceVariantGetPtrUtilityFunction variant_get_ptr_utility_function = NULL;
39
40
GDExtensionPtrDestructor string_name_destructor = NULL;
41
GDExtensionInterfaceStringNameNewWithLatin1Chars string_name_new_with_latin1_chars = NULL;
42
43
typedef struct
44
{
45
uint8_t data[8];
46
} StringName;
47
48
/**
49
* Platform APIs are being registered only after extensions, making them unavailable during initialization (on any level).
50
*
51
* Due to that we run the tests in Mainloop `startup_callback` (available since Godot 4.5), called after the initialization.
52
*/
53
void startup_func() {
54
bool success = (builtin_methods_compatibility_test() && class_methods_compatibility_test() && utility_functions_compatibility_test());
55
if (success) {
56
fprintf(stdout, "Outcome = SUCCESS\n");
57
} else {
58
fprintf(stderr, "Outcome = FAILURE\n");
59
}
60
fprintf(stdout, "COMPATIBILITY TEST FINISHED.\n");
61
}
62
63
GDExtensionMainLoopCallbacks callbacks = {
64
(GDExtensionMainLoopStartupCallback)startup_func,
65
NULL,
66
NULL
67
};
68
69
void initialize_compatibility_test(void *p_userdata, GDExtensionInitializationLevel p_level) {}
70
71
void deinitialize_compatibility_test(void *p_userdata, GDExtensionInitializationLevel p_level) {}
72
73
GDExtensionBool builtin_methods_compatibility_test() {
74
FILE *file = fopen("./builtin_methods.txt", "r");
75
if (file == NULL) {
76
fprintf(stderr, "Failed to open file `builtin_methods.txt` \n");
77
return false;
78
}
79
80
bool ret = true;
81
char line[512];
82
83
while (fgets(line, sizeof line, file) != NULL) {
84
int variant_type;
85
char method_name[128];
86
GDExtensionInt hash;
87
if (sscanf(line, "%d %s %ld", &variant_type, method_name, &hash) != 3) {
88
continue;
89
}
90
91
StringName method_stringname;
92
string_name_new_with_latin1_chars(&method_stringname, method_name, false);
93
GDExtensionPtrBuiltInMethod method_bind = variant_get_ptr_builtin_method(variant_type, &method_stringname, hash);
94
95
if (method_bind == NULL) {
96
fprintf(stderr, "Method bind not found: %d::%s (hash: %ld)\n", variant_type, method_name, hash);
97
ret = false;
98
}
99
100
string_name_destructor(&method_stringname);
101
}
102
103
fclose(file);
104
return ret;
105
}
106
107
GDExtensionBool utility_functions_compatibility_test() {
108
FILE *file = fopen("./utility_functions.txt", "r");
109
if (file == NULL) {
110
fprintf(stderr, "Failed to open file `utility_functions.txt` \n");
111
return false;
112
}
113
114
bool ret = true;
115
char line[256];
116
117
while (fgets(line, sizeof line, file) != NULL) {
118
char method_name[128];
119
GDExtensionInt hash;
120
if (sscanf(line, "%s %ld", method_name, &hash) != 2) {
121
continue;
122
}
123
124
StringName method_stringname;
125
string_name_new_with_latin1_chars(&method_stringname, method_name, false);
126
GDExtensionPtrUtilityFunction function_bind = variant_get_ptr_utility_function(&method_stringname, hash);
127
128
if (function_bind == NULL) {
129
fprintf(stderr, "Utility function not found: %s (hash: %ld)\n", method_name, hash);
130
ret = false;
131
}
132
133
string_name_destructor(&method_stringname);
134
}
135
136
fclose(file);
137
return ret;
138
}
139
140
GDExtensionBool class_methods_compatibility_test() {
141
FILE *file = fopen("./class_methods.txt", "r");
142
if (file == NULL) {
143
fprintf(stderr, "Failed to open file `class_methods.txt` \n");
144
return false;
145
}
146
147
char current_class_name[128] = "";
148
bool ret = true;
149
char line[512];
150
bool has_class_string = false;
151
StringName p_classname;
152
153
while (fgets(line, sizeof(line), file) != NULL) {
154
GDExtensionInt hash;
155
StringName p_methodname;
156
char class_name[128];
157
char method_name[128];
158
159
if (sscanf(line, "%s %s %ld", class_name, method_name, &hash) != 3) {
160
continue;
161
}
162
163
if (strcmp(current_class_name, class_name) != 0) {
164
if (has_class_string) {
165
string_name_destructor(&p_classname);
166
}
167
strcpy(current_class_name, class_name);
168
169
string_name_new_with_latin1_chars(&p_classname, current_class_name, false);
170
171
has_class_string = true;
172
}
173
174
string_name_new_with_latin1_chars(&p_methodname, method_name, false);
175
GDExtensionMethodBindPtr method_bind = classdb_get_method_bind(&p_classname, &p_methodname, hash);
176
177
if (method_bind == NULL) {
178
fprintf(stderr, "Method bind not found: %s.%s (hash: %ld)\n", class_name, method_name, hash);
179
ret = false;
180
}
181
182
string_name_destructor(&p_methodname);
183
}
184
185
if (has_class_string) {
186
string_name_destructor(&p_classname);
187
}
188
189
fclose(file);
190
return ret;
191
}
192
193
GDExtensionBool __attribute__((visibility("default"))) compatibility_test_init(GDExtensionInterfaceGetProcAddress p_get_proc_address, GDExtensionClassLibraryPtr p_library, GDExtensionInitialization *r_initialization) {
194
classdb_get_method_bind = (GDExtensionInterfaceClassdbGetMethodBind)p_get_proc_address("classdb_get_method_bind");
195
if (classdb_get_method_bind == NULL) {
196
fprintf(stderr, "Failed to load interface method `classdb_get_method_bind`\n");
197
return false;
198
}
199
200
variant_get_ptr_builtin_method = (GDExtensionInterfaceVariantGetPtrBuiltinMethod)p_get_proc_address("variant_get_ptr_builtin_method");
201
if (variant_get_ptr_builtin_method == NULL) {
202
fprintf(stderr, "Failed to load interface method `variant_get_ptr_builtin_method`\n");
203
return false;
204
}
205
206
variant_get_ptr_utility_function = (GDExtensionInterfaceVariantGetPtrUtilityFunction)p_get_proc_address("variant_get_ptr_utility_function");
207
if (variant_get_ptr_utility_function == NULL) {
208
fprintf(stderr, "Failed to load interface method `variant_get_ptr_utility_function`\n");
209
return false;
210
}
211
212
GDExtensionInterfaceVariantGetPtrDestructor variant_get_ptr_destructor = (GDExtensionInterfaceVariantGetPtrDestructor)p_get_proc_address("variant_get_ptr_destructor");
213
if (variant_get_ptr_destructor == NULL) {
214
fprintf(stderr, "Failed to load interface method `variant_get_ptr_destructor`\n");
215
return false;
216
}
217
string_name_destructor = variant_get_ptr_destructor(GDEXTENSION_VARIANT_TYPE_STRING_NAME);
218
219
string_name_new_with_latin1_chars = (GDExtensionInterfaceStringNameNewWithLatin1Chars)p_get_proc_address("string_name_new_with_latin1_chars");
220
if (classdb_get_method_bind == NULL) {
221
fprintf(stderr, "Failed to load interface method `string_name_new_with_latin1_chars`\n");
222
return false;
223
}
224
225
GDExtensionInterfaceRegisterMainLoopCallbacks register_main_loop_callbacks = (GDExtensionInterfaceRegisterMainLoopCallbacks)p_get_proc_address("register_main_loop_callbacks");
226
if (register_main_loop_callbacks == NULL) {
227
fprintf(stderr, "Failed to load interface method `register_main_loop_callbacks`\n");
228
return false;
229
}
230
231
register_main_loop_callbacks(p_library, &callbacks);
232
233
r_initialization->initialize = initialize_compatibility_test;
234
r_initialization->deinitialize = deinitialize_compatibility_test;
235
r_initialization->userdata = NULL;
236
r_initialization->minimum_initialization_level = GDEXTENSION_INITIALIZATION_EDITOR;
237
238
return true;
239
}
240
241