Add tests for empty/unnamed arguments to ClassDB, Variant, GDScript
This commit is contained in:
parent
beceba85da
commit
1362bc22bd
17 changed files with 436 additions and 335 deletions
|
|
@ -71,6 +71,7 @@ struct ArgumentData {
|
|||
String name;
|
||||
bool has_defval = false;
|
||||
Variant defval;
|
||||
int position;
|
||||
};
|
||||
|
||||
struct MethodData {
|
||||
|
|
@ -371,6 +372,39 @@ void validate_property(const Context &p_context, const ExposedClass &p_class, co
|
|||
}
|
||||
}
|
||||
|
||||
void validate_argument(const Context &p_context, const ExposedClass &p_class, const String &p_owner_name, const String &p_owner_type, const ArgumentData &p_arg) {
|
||||
TEST_COND((p_arg.name.is_empty() || p_arg.name.begins_with("_unnamed_arg")),
|
||||
vformat("Unnamed argument in position %d of %s '%s.%s'.", p_arg.position, p_owner_type, p_class.name, p_owner_name));
|
||||
|
||||
const ExposedClass *arg_class = p_context.find_exposed_class(p_arg.type);
|
||||
if (arg_class) {
|
||||
TEST_COND(arg_class->is_singleton,
|
||||
vformat("Argument type is a singleton: '%s' of %s '%s.%s'.", p_arg.name, p_owner_type, p_class.name, p_owner_name));
|
||||
|
||||
if (p_class.api_type == ClassDB::API_CORE) {
|
||||
TEST_COND(arg_class->api_type == ClassDB::API_EDITOR,
|
||||
vformat("Argument '%s' of %s '%s.%s' has type '%s' from the editor API. Core API cannot have dependencies on the editor API.",
|
||||
p_arg.name, p_owner_type, p_class.name, p_owner_name, arg_class->name));
|
||||
}
|
||||
} else {
|
||||
// Look for types that don't inherit Object.
|
||||
TEST_FAIL_COND(!p_context.has_type(p_arg.type),
|
||||
vformat("Argument type '%s' not found: '%s' of %s '%s.%s'.", p_arg.type.name, p_arg.name, p_owner_type, p_class.name, p_owner_name));
|
||||
}
|
||||
|
||||
if (p_arg.has_defval) {
|
||||
String type_error_msg;
|
||||
bool arg_defval_assignable_to_type = arg_default_value_is_assignable_to_type(p_context, p_arg.defval, p_arg.type, &type_error_msg);
|
||||
|
||||
String err_msg = vformat("Invalid default value for parameter '%s' of %s '%s.%s'.", p_arg.name, p_owner_type, p_class.name, p_owner_name);
|
||||
if (!type_error_msg.is_empty()) {
|
||||
err_msg += " " + type_error_msg;
|
||||
}
|
||||
|
||||
TEST_COND(!arg_defval_assignable_to_type, err_msg.utf8().get_data());
|
||||
}
|
||||
}
|
||||
|
||||
void validate_method(const Context &p_context, const ExposedClass &p_class, const MethodData &p_method) {
|
||||
if (p_method.return_type.name != StringName()) {
|
||||
const ExposedClass *return_class = p_context.find_exposed_class(p_method.return_type);
|
||||
|
|
@ -392,54 +426,14 @@ void validate_method(const Context &p_context, const ExposedClass &p_class, cons
|
|||
|
||||
for (const ArgumentData &F : p_method.arguments) {
|
||||
const ArgumentData &arg = F;
|
||||
|
||||
const ExposedClass *arg_class = p_context.find_exposed_class(arg.type);
|
||||
if (arg_class) {
|
||||
TEST_COND(arg_class->is_singleton,
|
||||
"Argument type is a singleton: '", arg.name, "' of method '", p_class.name, ".", p_method.name, "'.");
|
||||
|
||||
if (p_class.api_type == ClassDB::API_CORE) {
|
||||
TEST_COND(arg_class->api_type == ClassDB::API_EDITOR,
|
||||
"Argument '", arg.name, "' of method '", p_class.name, ".", p_method.name, "' has type '",
|
||||
arg_class->name, "' from the editor API. Core API cannot have dependencies on the editor API.");
|
||||
}
|
||||
} else {
|
||||
// Look for types that don't inherit Object
|
||||
TEST_FAIL_COND(!p_context.has_type(arg.type),
|
||||
"Argument type '", arg.type.name, "' not found: '", arg.name, "' of method", p_class.name, ".", p_method.name, "'.");
|
||||
}
|
||||
|
||||
if (arg.has_defval) {
|
||||
String type_error_msg;
|
||||
bool arg_defval_assignable_to_type = arg_default_value_is_assignable_to_type(p_context, arg.defval, arg.type, &type_error_msg);
|
||||
String err_msg = vformat("Invalid default value for parameter '%s' of method '%s.%s'.", arg.name, p_class.name, p_method.name);
|
||||
if (!type_error_msg.is_empty()) {
|
||||
err_msg += " " + type_error_msg;
|
||||
}
|
||||
TEST_COND(!arg_defval_assignable_to_type, err_msg.utf8().get_data());
|
||||
}
|
||||
validate_argument(p_context, p_class, p_method.name, "method", arg);
|
||||
}
|
||||
}
|
||||
|
||||
void validate_signal(const Context &p_context, const ExposedClass &p_class, const SignalData &p_signal) {
|
||||
for (const ArgumentData &F : p_signal.arguments) {
|
||||
const ArgumentData &arg = F;
|
||||
|
||||
const ExposedClass *arg_class = p_context.find_exposed_class(arg.type);
|
||||
if (arg_class) {
|
||||
TEST_COND(arg_class->is_singleton,
|
||||
"Argument class is a singleton: '", arg.name, "' of signal '", p_class.name, ".", p_signal.name, "'.");
|
||||
|
||||
if (p_class.api_type == ClassDB::API_CORE) {
|
||||
TEST_COND(arg_class->api_type == ClassDB::API_EDITOR,
|
||||
"Argument '", arg.name, "' of signal '", p_class.name, ".", p_signal.name, "' has type '",
|
||||
arg_class->name, "' from the editor API. Core API cannot have dependencies on the editor API.");
|
||||
}
|
||||
} else {
|
||||
// Look for types that don't inherit Object
|
||||
TEST_FAIL_COND(!p_context.has_type(arg.type),
|
||||
"Argument type '", arg.type.name, "' not found: '", arg.name, "' of signal", p_class.name, ".", p_signal.name, "'.");
|
||||
}
|
||||
validate_argument(p_context, p_class, p_signal.name, "signal", arg);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -625,6 +619,7 @@ void add_exposed_classes(Context &r_context) {
|
|||
|
||||
ArgumentData arg;
|
||||
arg.name = orig_arg_name;
|
||||
arg.position = i;
|
||||
|
||||
if (arg_info.type == Variant::INT && arg_info.usage & (PROPERTY_USAGE_CLASS_IS_ENUM | PROPERTY_USAGE_CLASS_IS_BITFIELD)) {
|
||||
arg.type.name = arg_info.class_name;
|
||||
|
|
@ -693,6 +688,7 @@ void add_exposed_classes(Context &r_context) {
|
|||
|
||||
ArgumentData arg;
|
||||
arg.name = orig_arg_name;
|
||||
arg.position = i;
|
||||
|
||||
if (arg_info.type == Variant::INT && arg_info.usage & (PROPERTY_USAGE_CLASS_IS_ENUM | PROPERTY_USAGE_CLASS_IS_BITFIELD)) {
|
||||
arg.type.name = arg_info.class_name;
|
||||
|
|
@ -841,7 +837,7 @@ TEST_SUITE("[ClassDB]") {
|
|||
add_builtin_types(context);
|
||||
add_global_enums(context);
|
||||
|
||||
SUBCASE("[ClassDB] Find exposed class") {
|
||||
SUBCASE("[ClassDB] Validate exposed classes") {
|
||||
const ExposedClass *object_class = context.find_exposed_class(context.names_cache.object_class);
|
||||
TEST_FAIL_COND(!object_class, "Object class not found.");
|
||||
TEST_FAIL_COND(object_class->base != StringName(),
|
||||
|
|
|
|||
|
|
@ -719,6 +719,7 @@ TEST_CASE("[Variant] Assignment To Color from Bool,Int,Float,String,Vec2,Vec2i,V
|
|||
vec3i_v = col_v;
|
||||
CHECK(vec3i_v.get_type() == Variant::COLOR);
|
||||
}
|
||||
|
||||
TEST_CASE("[Variant] Writer and parser array") {
|
||||
Array a = build_array(1, String("hello"), build_array(Variant()));
|
||||
String a_str;
|
||||
|
|
@ -911,6 +912,67 @@ TEST_CASE("[Variant] Nested dictionary comparison") {
|
|||
CHECK_FALSE(v_d1 == v_d_other_val);
|
||||
}
|
||||
|
||||
struct ArgumentData {
|
||||
Variant::Type type;
|
||||
String name;
|
||||
bool has_defval = false;
|
||||
Variant defval;
|
||||
int position;
|
||||
};
|
||||
|
||||
struct MethodData {
|
||||
StringName name;
|
||||
Variant::Type return_type;
|
||||
List<ArgumentData> arguments;
|
||||
bool is_virtual = false;
|
||||
bool is_vararg = false;
|
||||
};
|
||||
|
||||
TEST_CASE("[Variant] Utility functions") {
|
||||
List<MethodData> functions;
|
||||
|
||||
List<StringName> function_names;
|
||||
Variant::get_utility_function_list(&function_names);
|
||||
function_names.sort_custom<StringName::AlphCompare>();
|
||||
|
||||
for (const StringName &E : function_names) {
|
||||
MethodData md;
|
||||
md.name = E;
|
||||
|
||||
// Utility function's return type.
|
||||
if (Variant::has_utility_function_return_value(E)) {
|
||||
md.return_type = Variant::get_utility_function_return_type(E);
|
||||
}
|
||||
|
||||
// Utility function's arguments.
|
||||
if (Variant::is_utility_function_vararg(E)) {
|
||||
md.is_vararg = true;
|
||||
} else {
|
||||
for (int i = 0; i < Variant::get_utility_function_argument_count(E); i++) {
|
||||
ArgumentData arg;
|
||||
arg.type = Variant::get_utility_function_argument_type(E, i);
|
||||
arg.name = Variant::get_utility_function_argument_name(E, i);
|
||||
arg.position = i;
|
||||
|
||||
md.arguments.push_back(arg);
|
||||
}
|
||||
}
|
||||
|
||||
functions.push_back(md);
|
||||
}
|
||||
|
||||
SUBCASE("[Variant] Validate utility functions") {
|
||||
for (const MethodData &E : functions) {
|
||||
for (const ArgumentData &F : E.arguments) {
|
||||
const ArgumentData &arg = F;
|
||||
|
||||
TEST_COND((arg.name.is_empty() || arg.name.begins_with("_unnamed_arg")),
|
||||
vformat("Unnamed argument in position %d of function '%s'.", arg.position, E.name));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace TestVariant
|
||||
|
||||
#endif // TEST_VARIANT_H
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue