bitwes / Gut

Godot Unit Test. Unit testing tool for Godot Game Engine.
1.8k stars 99 forks source link

InputSender does not have a class name #572

Open ghost opened 6 months ago

ghost commented 6 months ago

InputSender is a variable in GutTest which refers to an anonymous class in addons/gut/input_sender.gd. Since this class has no name, there is no way to refer to it in a static typing context, requiring copious amounts of ignore annotations:

@warning_ignore("unsafe_method_access", "untyped_declaration")
var sender = InputSender.new(resizable)
@warning_ignore("unsafe_method_access")
sender.mouse_left_button_down()

As an added side effect, it seems that code completion is also broken on the sender variable in Godot 4.

I'm unsure what the right fix would be, as presumably adding a class name to input_sender.gd would clash with the variable name. Maybe the class could be named GutInputSender?

bitwes commented 6 months ago

GutInputSender is a perfect name. I've been hesitant to add class_name to stuff, but this seems like a perfectly good one to get a name.

ghost commented 6 months ago

@bitwes what's actually the reason for using the load() function instead of referring to classes by name? Is it a Godot 3 thing? (I just started using Godot with 4)

dreed-sd commented 5 months ago

@bitwes what's actually the reason for using the load() function instead of referring to classes by name? Is it a Godot 3 thing? (I just started using Godot with 4)

Curious about this too. We are starting with Godot 4, and decide to turn on 'warn as error' to require type hints wherever possible. We just want the added level of safety to catch bugs sooner. But then working with libraries that don't use any type hints becomes extremely difficult.

bitwes commented 5 months ago

One reason is that class_name came around sometime in 3.x. I'm not sure when, but I started GUT in Godot 2.x. So, there was a lot of GUT code before class_name was even a thing.

Another is that Godot doesn't have any way to do name-spacing for class_name (I can't make a class named Gut.Test). So when I use a class_name I have to be pretty sure it will be unique and not clash with a name a user might already be using. This is why GutTest exists and not Gut. Putting all your classes in an autoload or static script, and using load gets you name-spacing.

I've started using class_name a lot in my personal projects, but with GUT I try not to so users' auto-complete isn't polluted with a bunch of classes not meant to be used by the end users.

Finally, I've gotten pretty used to not using strict typing or class_name over the years, so I don't notice it that much when it is missing.

dreed-sd commented 5 months ago

Thanks for that context. I think you should be able to code how you see fit in your project. I wonder if Godot contributors would consider adding a scope hint of some kind. So that you can have class names that are only resolvable from within your directory, or something to that effect, and allow you to explicitly export your intended public API. Javascript has a similar problem where packages might conflict, but it's very rare so no one really worries about it, and if you do run into it there's a way to just assign an alias to it as part of the declared reference (e.g. import { Actions as Navigator } from 'react-native-router-flux';).

Even with that though there's the issue of your public API not having type hints being awkward to use in a project that requires them. Ideally the 'warn as error' setting would know it's referring to an addon, and apply the 'dont apply to addons' setting. But that's probably a lot more complicated than the current behavior, which is just path based. You could provide an alternative base class that has type hints perhaps, but that's maintenance on you.

bitwes commented 5 months ago

Some name-spacing would be great to have. One workaround might be to make your own scripts that extend scripts that do not have class names. This would work with InputSender, but there a lot of cases where it wouldn't work. Like when something creates the instance for you.

InputSenderWrapper.gd

class_name InputSender
extends 'res://addons/gut/input_sender.gd'

I'll be adding in the name in the next release as GutInputSender. So until then, you can add it manually to addons/gut/input_sender.gd if you want to start using it earlier.

bitwes commented 1 month ago

I said I would do this. I didn't. I'm doing this now and it will be in a point release in a week or so.