Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Double a PackedScene created via code #666

Open
gabahulk opened this issue Oct 22, 2024 · 6 comments
Open

Double a PackedScene created via code #666

gabahulk opened this issue Oct 22, 2024 · 6 comments
Labels

Comments

@gabahulk
Copy link

Versions

What versions of Godot do you want to use this feature in?
4.3

The Feature

In my code I have a resource that has a PackedScene, and I want to test if some code gets that resource, instantiates the PackedScene, and calls some methods from the instance. I've tried to double an empty packed scene and stub return the double of the class in the PackedScene instantiate method like the code below, but that breaks the get_scene_script_object from GUT utils. I'm not sure if I'm doing it correctly, but if this isn't possible, it would be nice.

var instance= double(InstanceClass).new()
stub(instance, 'initialize').to_return("I'm stubbed!")
var doubled_scene = double(PackedScene).new()
stub(doubled_scene , 'instantiate').to_return(instance)
@bitwes
Copy link
Owner

bitwes commented Oct 22, 2024

I'm not sure I follow what you are trying to do. Sounds like:

# MyResource.gd
var scene_to_make = load('res://some_packed_scene.tscn')

func get_instance():
    var to_return = scene_to_make.instantiate()
    to_return.foo()
    return to_return

If that's the case you could do something like:

func test_it():
    var my_resource = MyResource.new()
    my_resource.scene_to_make = double(load('res://some_packed_scene.tscn'))
    var doubled_scene_from_resource = my_resource.get_instance()
    
    assert_called(doubled_scene_from_resource, "foo")

@gabahulk
Copy link
Author

gabahulk commented Oct 22, 2024

I was afraid I wasn't clear enough, but what you wrote is similar. The difference is that in my code there's a third class (which is what I'm testing) that does the instantiating and that call foo, something like

# MyResource.gd
@export var scene_to_make : SceneType
# SceneType.gd
extends Node2D

func foo():
 pass
SceneTypeSpawner.gd
extends Node

func spawn(resource:MyResource):
    var instance : SceneType = resource.scene_to_make.instantiate()
    instance.foo()
    return instance

I changed my test to be somewhat close to your suggestion, but the test crashes saying that instance is null when calling instance.foo()

func test_it():
    var my_resource = MyResource.new()
    my_resource.scene_to_make = double(load('res://SceneType.tscn'))
    var spawner = SceneTypeSpawner.new()
    
    var doubled_scene_from_resource = spawner.spawn(my_resource)
    
    assert_called(doubled_scene_from_resource, "foo")

But with your response, I've either done something wrong (most likely) or stumbled upon a bug, I'm unsure if I should close this and create a new issue.

@gabahulk gabahulk reopened this Oct 22, 2024
@bitwes
Copy link
Owner

bitwes commented Oct 22, 2024

Any other errors in the log?

@gabahulk
Copy link
Author

The engine error is:

E 0:00:01:0461   enemy_spawner.gd:14 @ spawn_enemy(): Failed to instantiate scene state of "", node count is 0. Make sure the PackedScene resource is valid.
  <C++ Error>    Condition "nc == 0" is true. Returning: nullptr
  <C++ Source>   scene/resources/packed_scene.cpp:142 @ instantiate()
  <Stack Trace>  enemy_spawner.gd:14 @ spawn_enemy()
                 test_enemy_spawner.gd:33 @ test_spawn_enemy_should_initialize_enemy()
                 gut.gd:580 @ _run_test()
                 gut.gd:757 @ _test_the_scripts()
                 gut.gd:959 @ test_scripts()
                 GutRunner.gd:129 @ run_tests()

The method then returns null which results in this test error:

* test_spawn_enemy_should_initialize_enemy
    [Failed]:  An instance of a Double was expected, you passed:  <null>
      at line 36

@bitwes
Copy link
Owner

bitwes commented Oct 23, 2024

I've been able to replicate the error in my own game that has a similar setup. I have a scene that spawn resources could use:

@export var scene : PackedScene = null

If you remove the type (PackedScene) it works. That makes the resource useless in the editor, but it is some info. Something about doubling the scene is making it an invalid PackedScene. I'll have to dig into that a bit. I'm not 100% sure what the problem might be.

One way to work around this might be to create a method on your resource to instantiate the scene with an optional parameter for the scene to be used. This way you could test the method with anything and not be restricted by this issue.

func create_instance(which = scene_to_make):
    var inst = which.instantiate()
    # do stuff to it
    return which.instantiate()

@bitwes bitwes added the bug label Oct 23, 2024
@gabahulk
Copy link
Author

I'm glad you were able to replicate it! I think I'll use the workaround you suggested. Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants