Integrating latest 47acbe8

This commit is contained in:
alexpete
2021-03-25 13:57:57 -07:00
parent 448c549698
commit 75dc720198
10312 changed files with 2711566 additions and 671451 deletions
@@ -0,0 +1,33 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
import os
import sys
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
from ActorSplitsAfterDamage import Tests
def run():
from ActorSplitsAfterDamage import run as internal_run
from Utils import Constants
def CapsuleDamage(target_id, position0):
position1 = azlmbr.object.construct('Vector3', position0.x + 1.0, position0.y, position0.z)
azlmbr.destruction.BlastFamilyDamageRequestBus(azlmbr.bus.Event, "Capsule Damage", target_id,
position0, position1,
Constants.DAMAGE_MIN_RADIUS,
Constants.DAMAGE_MAX_RADIUS, Constants.DAMAGE_AMOUNT)
internal_run(CapsuleDamage)
if __name__ == "__main__":
run()
@@ -0,0 +1,110 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
# fmt: off
class Tests():
enter_game_mode = ("Entered game mode", "Failed to enter game mode")
find_moving = ("Moving entity found", "Moving entity not found")
find_destructable = ("Destructable entity found", "Destructable entity not found")
find_root_actor = ("Root actor of destructable entity found", "Root actor of destructable entity not found")
collisions = ("Collision occurred between entities", "Collision did not occur between entities")
root_actor_destroyed = ("Root actor destroyed", "Root actor was not destroyed")
child_actors_created = ("Child actors created", "Child actors were not created")
exit_game_mode = ("Exited game mode", "Couldn't exit game mode")
# fmt: on
def run():
"""
Summary:
Open a Project that already has 1 rigid sphere entity and 1 destructable entity and verify collision and damage
to destructable entity.
Level Description:
Moving Sphere and Destructable entities are created in level with same collision layer and same collision group.
Moving Sphere entity is placed above the Destructable entity.
Expected Behavior:
Moving Sphere has to collide with Destructable entity under the effect of gravity. Destructable entity root actor
should be destroyed and 2 child actors should be created to replace it.
Test Steps:
1) Open level and Enter game mode
2) Retrieve and validate Entities
3) Get the entity representing root actor of destructable entity
4) Check moving sphere collides with root actor of destructable entity due to gravity
5) Check root actor is destroyed
6) Check child actors of root actor are created
7) Exit game mode
8) Close the editor
:return: None
"""
import ImportPathHelper as imports
imports.init()
from utils import Report
from utils import TestHelper as helper
import azlmbr.legacy.general as general
import azlmbr.bus
from Utils import CollisionHandler
from Utils import BlastNotificationHandler
# Constants
TIMEOUT = 2.0
helper.init_idle()
# 1) Open level and Enter game mode
helper.open_level("Blast", "Blast_ActorSplitsAfterCollision")
helper.enter_game_mode(Tests.enter_game_mode)
# 2) Retrieve and validate Entities
moving_id = general.find_game_entity("Sphere_Moving")
Report.critical_result(Tests.find_moving, moving_id.IsValid())
destructable_id = general.find_game_entity("Destructable_Box")
Report.critical_result(Tests.find_destructable, destructable_id.IsValid())
# 3) Get the entity representing root actor of destructable entity
destructable_initial_actors = azlmbr.destruction.BlastFamilyComponentRequestBus(azlmbr.bus.Event, "Get Actors Data", destructable_id)
Report.critical_result(Tests.find_root_actor, len(destructable_initial_actors) == 1)
destructable_initial_actor_id = destructable_initial_actors[0].EntityId
collision = CollisionHandler(destructable_initial_actor_id, moving_id)
family_handler = BlastNotificationHandler(destructable_id)
# 4) Check moving sphere collides with root actor of destructable entity due to gravity
helper.wait_for_condition(lambda: collision.collision_happened, TIMEOUT)
Report.result(Tests.collisions, collision.collision_happened)
# 5) Check root actor is destroyed
helper.wait_for_condition(lambda: family_handler.actors_destroyed == 1, TIMEOUT)
Report.result(Tests.root_actor_destroyed, family_handler.actors_destroyed == 1)
# 6) Check child actors of root actor are created
helper.wait_for_condition(lambda: family_handler.actors_created == 2, TIMEOUT)
Report.result(Tests.child_actors_created, family_handler.actors_created == 2)
# 7) Exit game mode
helper.exit_game_mode(Tests.exit_game_mode)
# 8) Close the editor
helper.close_editor()
if __name__ == "__main__":
run()
@@ -0,0 +1,97 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
# fmt: off
class Tests():
enter_game_mode = ("Entered game mode", "Failed to enter game mode")
find_destructable = ("Destructable entity found", "Destructable entity not found")
find_root_actor = ("Root actor of destructable entity found", "Root actor of destructable entity not found")
root_actor_destroyed = ("Root actor destroyed", "Root actor was not destroyed")
child_actors_created = ("Child actors created", "Child actors were not created")
exit_game_mode = ("Exited game mode", "Couldn't exit game mode")
# fmt: on
def run(damage_func):
"""
Summary:
Open a Project that already has 1 destructable entity and verify damage destructs it.
Level Description:
Destructable entity is in a level.
Expected Behavior:
Damage is applied to destructable entity. Destructable entity root actor
should be destroyed and 2 child actors should be created to replace it.
Test Steps:
1) Open level and Enter game mode
2) Retrieve and validate Entities
3) Get the entity representing root actor of destructable entity
4) Apply damage to the destructable entity
5) Check root actor is destroyed
6) Check child actors of root actor are created
7) Exit game mode
8) Close the editor
:return: None
"""
import ImportPathHelper as imports
imports.init()
from utils import Report
from utils import TestHelper as helper
import azlmbr.legacy.general as general
import azlmbr.bus
from Utils import BlastNotificationHandler
# Constants
TIMEOUT = 2.0
helper.init_idle()
# 1) Open level and Enter game mode
helper.open_level("Blast", "Blast_ActorSplitsAfterDamage")
helper.enter_game_mode(Tests.enter_game_mode)
# 2) Retrieve and validate Entities
destructable_id = general.find_game_entity("Destructable_Box")
Report.critical_result(Tests.find_destructable, destructable_id.IsValid())
# 3) Get the entity representing root actor of destructable entity
destructable_initial_actors = azlmbr.destruction.BlastFamilyComponentRequestBus(azlmbr.bus.Event, "Get Actors Data", destructable_id)
Report.critical_result(Tests.find_root_actor, len(destructable_initial_actors) == 1)
destructable_initial_actor_id = destructable_initial_actors[0].EntityId
initial_actor_position = azlmbr.components.TransformBus(azlmbr.bus.Event, "GetWorldTranslation", destructable_initial_actor_id)
# 4) Apply damage to the destructable entity
damage_func(destructable_id, initial_actor_position)
family_handler = BlastNotificationHandler(destructable_id)
# 5) Check root actor is destroyed
helper.wait_for_condition(lambda: family_handler.actors_destroyed == 1, TIMEOUT)
Report.result(Tests.root_actor_destroyed, family_handler.actors_destroyed == 1)
# 6) Check child actors of root actor are created
helper.wait_for_condition(lambda: family_handler.actors_created == 2, TIMEOUT)
Report.result(Tests.child_actors_created, family_handler.actors_created == 2)
# 7) Exit game mode
helper.exit_game_mode(Tests.exit_game_mode)
# 8) Close the editor
helper.close_editor()
@@ -0,0 +1,31 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
import os
import sys
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
from ActorSplitsAfterDamage import Tests
def run():
from ActorSplitsAfterDamage import run as internal_run
from Utils import Constants
def ImpactSpreadDamage(target_id, position):
azlmbr.destruction.BlastFamilyDamageRequestBus(azlmbr.bus.Event, "Impact Spread Damage", target_id,
position, Constants.DAMAGE_MIN_RADIUS,
Constants.DAMAGE_MAX_RADIUS, Constants.DAMAGE_AMOUNT)
internal_run(ImpactSpreadDamage)
if __name__ == "__main__":
run()
@@ -0,0 +1,31 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
import os
import sys
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
from ActorSplitsAfterDamage import Tests
def run():
from ActorSplitsAfterDamage import run as internal_run
from Utils import Constants
def RadialDamage(target_id, position):
azlmbr.destruction.BlastFamilyDamageRequestBus(azlmbr.bus.Event, "Radial Damage", target_id,
position, Constants.DAMAGE_MIN_RADIUS,
Constants.DAMAGE_MAX_RADIUS, Constants.DAMAGE_AMOUNT)
internal_run(RadialDamage)
if __name__ == "__main__":
run()
@@ -0,0 +1,32 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
import os
import sys
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
from ActorSplitsAfterDamage import Tests
def run():
from ActorSplitsAfterDamage import run as internal_run
from Utils import Constants
def ShearDamage(target_id, position):
normal = azlmbr.object.construct('Vector3', 1.0, 0.0, 0.0)
azlmbr.destruction.BlastFamilyDamageRequestBus(azlmbr.bus.Event, "Shear Damage", target_id,
position, normal, Constants.DAMAGE_MIN_RADIUS,
Constants.DAMAGE_MAX_RADIUS, Constants.DAMAGE_AMOUNT)
internal_run(ShearDamage)
if __name__ == "__main__":
run()
@@ -0,0 +1,31 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
import os
import sys
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
from ActorSplitsAfterDamage import Tests
def run():
from ActorSplitsAfterDamage import run as internal_run
from Utils import Constants
def StressDamage(target_id, position):
force = azlmbr.object.construct('Vector3', 0.0, 0.0, -100.0) # Should be enough to break `brittle` objects
azlmbr.destruction.BlastFamilyDamageRequestBus(azlmbr.bus.Event, "Stress Damage", target_id,
position, force)
internal_run(StressDamage)
if __name__ == "__main__":
run()
@@ -0,0 +1,35 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
import os
import sys
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
from ActorSplitsAfterDamage import Tests
def run():
from ActorSplitsAfterDamage import run as internal_run
from Utils import Constants
def TriangleDamage(target_id, position):
# Some points that form a triangle that contains the given position
position0 = azlmbr.object.construct('Vector3', position.x, position.y + 1.0, position.z)
position1 = azlmbr.object.construct('Vector3', position.x + 1.0, position.y - 1.0, position.z)
position2 = azlmbr.object.construct('Vector3', position.x - 1.0, position.y - 1.0, position.z)
azlmbr.destruction.BlastFamilyDamageRequestBus(azlmbr.bus.Event, "Triangle Damage", target_id,
position0, position1, position2,
Constants.DAMAGE_AMOUNT)
internal_run(TriangleDamage)
if __name__ == "__main__":
run()
@@ -0,0 +1,15 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
def init():
import os
import sys
sys.path.append(os.path.dirname(os.path.abspath(__file__)) + '/../automatedtesting_shared')
@@ -0,0 +1,54 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
# This suite consists of all test cases that are passing and have been verified.
import pytest
import os
import sys
from ly_test_tools import LAUNCHERS
sys.path.append(os.path.dirname(os.path.abspath(__file__)) + '/../automatedtesting_shared')
from base import TestAutomationBase
@pytest.mark.SUITE_periodic
@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
@pytest.mark.parametrize("project", ["AutomatedTesting"])
class TestAutomation(TestAutomationBase):
def test_ActorSplitsAfterCollision(self, request, workspace, editor, launcher_platform):
from . import ActorSplitsAfterCollision as test_module
self._run_test(request, workspace, editor, test_module, expected_lines=[], unexpected_lines=["Assert"])
def test_ActorSplitsAfterRadialDamage(self, request, workspace, editor, launcher_platform):
from . import ActorSplitsAfterRadialDamage as test_module
self._run_test(request, workspace, editor, test_module, expected_lines=[], unexpected_lines=["Assert"])
def test_ActorSplitsAfterCapsuleDamage(self, request, workspace, editor, launcher_platform):
from . import ActorSplitsAfterCapsuleDamage as test_module
self._run_test(request, workspace, editor, test_module, expected_lines=[], unexpected_lines=["Assert"])
def test_ActorSplitsAfterImpactSpreadDamage(self, request, workspace, editor, launcher_platform):
from . import ActorSplitsAfterImpactSpreadDamage as test_module
self._run_test(request, workspace, editor, test_module, expected_lines=[], unexpected_lines=["Assert"])
def test_ActorSplitsAfterShearDamage(self, request, workspace, editor, launcher_platform):
from . import ActorSplitsAfterShearDamage as test_module
self._run_test(request, workspace, editor, test_module, expected_lines=[], unexpected_lines=["Assert"])
def test_ActorSplitsAfterTriangleDamage(self, request, workspace, editor, launcher_platform):
from . import ActorSplitsAfterTriangleDamage as test_module
self._run_test(request, workspace, editor, test_module, expected_lines=[], unexpected_lines=["Assert"])
def test_ActorSplitsAfterStressDamage(self, request, workspace, editor, launcher_platform):
from . import ActorSplitsAfterStressDamage as test_module
self._run_test(request, workspace, editor, test_module, expected_lines=[], unexpected_lines=["Assert"])
@@ -0,0 +1,55 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
import azlmbr
from enum import Enum
class Constants():
DAMAGE_MIN_RADIUS = 1.0
DAMAGE_MAX_RADIUS = 1.0
DAMAGE_AMOUNT = 10.0 # Enough to break a `brittle` object
class CollisionHandler:
def __init__(self, id, target_id):
self.id = id
self.target_id = target_id
self.collision_happened = False
self.create_collision_handler()
def on_collision_begin(self, args):
if args[0].Equal(self.target_id):
self.collision_happened = True
def create_collision_handler(self):
self.handler = azlmbr.physics.CollisionNotificationBusHandler()
self.handler.connect(self.id)
self.handler.add_callback("OnCollisionBegin", self.on_collision_begin)
class BlastNotificationHandler:
def __init__(self, id):
self.id = id
self.actors_destroyed = 0
self.actors_created = 0
self.create_collision_handler()
def on_actor_created(self, args):
self.actors_created += 1
def on_actor_destroyed(self, args):
self.actors_destroyed += 1
def create_collision_handler(self):
self.handler = azlmbr.destruction.BlastFamilyComponentNotificationBusHandler()
self.handler.connect(self.id)
self.handler.add_callback("On Actor Created", self.on_actor_created)
self.handler.add_callback("On Actor Destroyed", self.on_actor_destroyed)
@@ -0,0 +1,10 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
@@ -0,0 +1,259 @@
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
################################################################################
# Automated Tests
################################################################################
ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME})
add_subdirectory(assetpipeline)
## Physics ##
if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS)
ly_add_pytest(
NAME AutomatedTesting::PhysicsTests
TEST_SUITE main
TEST_SERIAL
PATH ${CMAKE_CURRENT_LIST_DIR}/physics/TestSuite_Active.py
TIMEOUT 3600
RUNTIME_DEPENDENCIES
Legacy::Editor
Legacy::CryRenderNULL
AZ::AssetProcessor
AutomatedTesting.Assets
)
ly_add_pytest(
NAME AutomatedTesting::PhysicsTests_Sandbox
TEST_SUITE sandbox
TEST_SERIAL
PATH ${CMAKE_CURRENT_LIST_DIR}/physics/TestSuite_Sandbox.py
TIMEOUT 3600
RUNTIME_DEPENDENCIES
Legacy::Editor
Legacy::CryRenderNULL
AZ::AssetProcessor
AutomatedTesting.Assets
)
endif()
## ScriptCanvas ##
if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS)
ly_add_pytest(
NAME AutomatedTesting::ScriptCanvasTests
TEST_SUITE main
TEST_SERIAL
PATH ${CMAKE_CURRENT_LIST_DIR}/scripting/TestSuite_Active.py
TIMEOUT 3600
RUNTIME_DEPENDENCIES
Legacy::Editor
Legacy::CryRenderNULL
AZ::AssetProcessor
AutomatedTesting.Assets
)
endif()
## White Box ##
if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS)
ly_add_pytest(
NAME AutomatedTesting::WhiteBoxTests
TEST_SUITE main
TEST_SERIAL
PATH ${CMAKE_CURRENT_LIST_DIR}/WhiteBox/TestSuite_Active.py
TIMEOUT 3600
RUNTIME_DEPENDENCIES
Legacy::Editor
Legacy::CryRenderNULL
AZ::AssetProcessor
AutomatedTesting.Assets
)
endif()
## NvCloth ##
# [TODO LYN-1928] Enable when AutomatedTesting runs with Atom
#if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS)
# ly_add_pytest(
# NAME AutomatedTesting::NvClothTests
# TEST_SUITE main
# TEST_SERIAL
# PATH ${CMAKE_CURRENT_LIST_DIR}/NvCloth/TestSuite_Active.py
# TIMEOUT 3600
# RUNTIME_DEPENDENCIES
# Legacy::Editor
# Legacy::CryRenderNULL
# AZ::AssetProcessor
# AutomatedTesting.Assets
# )
#endif()
## Editor Python Bindings ##
if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS)
ly_add_pytest(
NAME AutomatedTesting::EditorPythonBindings
TEST_SUITE sandbox
TEST_SERIAL
PATH ${CMAKE_CURRENT_LIST_DIR}/EditorPythonBindings
TIMEOUT 3600
RUNTIME_DEPENDENCIES
Legacy::Editor
Legacy::CryRenderNULL
AZ::AssetProcessor
AutomatedTesting.Assets
Gem::EditorPythonBindings.Editor
COMPONENT TestTools
)
endif()
## Blast ##
# Disabled until AutomatedTesting runs with Atom.
# if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS)
# ly_add_pytest(
# NAME AutomatedTesting::BlastTests
# TEST_SERIAL TRUE
# PATH ${CMAKE_CURRENT_LIST_DIR}/Blast/TestSuite_Active.py
# TIMEOUT 500
# RUNTIME_DEPENDENCIES
# Legacy::Editor
# Legacy::CryRenderNULL
# AZ::AssetProcessor
# AutomatedTesting.Assets
# )
# endif()
#############
## Large Worlds ##
include(${pal_dir}/PAL_traits_${PAL_PLATFORM_NAME_LOWERCASE}.cmake)
if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS AND PAL_TRAIT_LARGE_WORLDS_TEST_SUPPORTED)
## DynVeg ##
ly_add_pytest(
NAME DynamicVegetationTests_Main_NoGPU
TEST_SERIAL
TEST_SUITE main
PATH ${CMAKE_CURRENT_LIST_DIR}/largeworlds/dyn_veg
PYTEST_MARKS "not REQUIRES_gpu"
TIMEOUT 36000
RUNTIME_DEPENDENCIES
AZ::AssetProcessor
Legacy::Editor
AutomatedTesting.GameLauncher
AutomatedTesting.Assets
Legacy::CryRenderNULL
)
ly_add_pytest(
NAME DynamicVegetationTests_Sandbox_NoGPU
TEST_SERIAL
TEST_SUITE sandbox
PATH ${CMAKE_CURRENT_LIST_DIR}/largeworlds/dyn_veg
PYTEST_MARKS "not REQUIRES_gpu"
TIMEOUT 36000
RUNTIME_DEPENDENCIES
AZ::AssetProcessor
Legacy::Editor
AutomatedTesting.GameLauncher
AutomatedTesting.Assets
Legacy::CryRenderNULL
)
ly_add_pytest(
NAME DynamicVegetationTests_Periodic_NoGPU
TEST_SERIAL
TEST_SUITE periodic
PATH ${CMAKE_CURRENT_LIST_DIR}/largeworlds/dyn_veg
PYTEST_MARKS "not REQUIRES_gpu"
TIMEOUT 3600
RUNTIME_DEPENDENCIES
AZ::AssetProcessor
Legacy::Editor
AutomatedTesting.Assets
Legacy::CryRenderNULL
)
## LandscapeCanvas ##
ly_add_pytest(
NAME LandscapeCanvasTests_Main
TEST_SERIAL
TEST_SUITE main
PATH ${CMAKE_CURRENT_LIST_DIR}/largeworlds/landscape_canvas
TIMEOUT 3600
RUNTIME_DEPENDENCIES
AZ::AssetProcessor
Legacy::Editor
AutomatedTesting.Assets
Legacy::CryRenderNULL
)
## GradientSignal ##
ly_add_pytest(
NAME GradientSignalTests_Main
TEST_SERIAL
TEST_SUITE main
PATH ${CMAKE_CURRENT_LIST_DIR}/largeworlds/gradient_signal
TIMEOUT 3600
RUNTIME_DEPENDENCIES
AZ::AssetProcessor
Legacy::Editor
AutomatedTesting.Assets
Legacy::CryRenderNULL
)
ly_add_pytest(
NAME GradientSignalTests_Periodic
TEST_SERIAL
TEST_SUITE periodic
PATH ${CMAKE_CURRENT_LIST_DIR}/largeworlds/gradient_signal
TIMEOUT 3600
RUNTIME_DEPENDENCIES
AZ::AssetProcessor
Legacy::Editor
AutomatedTesting.Assets
Legacy::CryRenderNULL
)
endif()
## Editor ##
if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS AND PAL_TRAIT_FOUNDATION_TEST_SUPPORTED)
ly_add_pytest(
NAME EditorTests_Periodic
TEST_SUITE periodic
TEST_SERIAL
PATH ${CMAKE_CURRENT_LIST_DIR}/editor
TIMEOUT 3600
RUNTIME_DEPENDENCIES
Legacy::Editor
Legacy::CryRenderNULL
AZ::AssetProcessor
AutomatedTesting.Assets
)
endif()
if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS)
# Unstable, SPEC-3838 will restore
#ly_add_pytest(
# NAME asset_load_benchmark_test
# TEST_SERIAL
# TEST_SUITE benchmark
# PATH ${CMAKE_CURRENT_LIST_DIR}/streaming/benchmark/asset_load_benchmark_test.py
# RUNTIME_DEPENDENCIES
# AZ::AssetProcessor
# AZ::AssetProcessorBatch
# AutomatedTesting.GameLauncher
# Legacy::CryRenderNULL
#)
endif()
@@ -0,0 +1,49 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
#
# This is a pytest module to test the in-Editor Python API from PythonEditorFuncs
#
import pytest
pytest.importorskip('ly_test_tools')
import sys
import os
sys.path.append(os.path.dirname(__file__))
from hydra_utils import launch_test_case
@pytest.mark.SUITE_sandbox
@pytest.mark.parametrize('launcher_platform', ['windows_editor'])
@pytest.mark.parametrize('project', ['AutomatedTesting'])
@pytest.mark.parametrize('level', ['Simple'])
class TestGradientRequiresShape(object):
def test_ComponentAsset(self, request, editor, level, launcher_platform):
unexpected_lines=[]
expected_lines = [
"New entity with no parent created: SUCCESS",
"Mesh component added to entity: SUCCESS",
"Entity has a Mesh component: SUCCESS",
"GetSetCompare Test MeshComponentRenderNode|Mesh asset: SUCCESS",
"GetSetCompare Clear MeshComponentRenderNode|Mesh asset: SUCCESS",
"PTE Test MeshComponentRenderNode|Mesh asset: SUCCESS",
"PTE Clear MeshComponentRenderNode|Mesh asset: SUCCESS",
"GetSetCompare Test MeshComponentRenderNode|Material override: SUCCESS",
"GetSetCompare Clear MeshComponentRenderNode|Material override: SUCCESS",
"PTE Test MeshComponentRenderNode|Material override: SUCCESS",
"PTE Clear MeshComponentRenderNode|Material override: SUCCESS",
]
test_case_file = os.path.join(os.path.dirname(__file__), 'ComponentAssetCommands_test_case.py')
launch_test_case(editor, test_case_file, expected_lines, unexpected_lines)
@@ -0,0 +1,141 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
# Tests a portion of the Component Property Get/Set Python API while the Editor is running
import azlmbr.bus as bus
import azlmbr.editor as editor
import azlmbr.entity as entity
import azlmbr.math as math
import azlmbr.asset as asset
# Open a level (any level should work)
editor.EditorToolsApplicationRequestBus(bus.Broadcast, 'OpenLevelNoPrompt', 'WaterSample')
def GetSetCompareTest(component, path, assetId):
# Test Get/Set (get old value, set new value, check that new value was set correctly)
oldObj = editor.EditorComponentAPIBus(bus.Broadcast, 'GetComponentProperty', component, path)
if(oldObj.IsSuccess()):
oldValue = oldObj.GetValue()
oldValueCompared = editor.EditorComponentAPIBus(bus.Broadcast, 'CompareComponentProperty', component, path, oldValue)
editor.EditorComponentAPIBus(bus.Broadcast, 'SetComponentProperty', component, path, assetId)
newObj = editor.EditorComponentAPIBus(bus.Broadcast, 'GetComponentProperty', component, path)
if(newObj.IsSuccess()):
newValue = newObj.GetValue()
newValueCompared = editor.EditorComponentAPIBus(bus.Broadcast, 'CompareComponentProperty', component, path, newValue)
isOldNewValueSame = editor.EditorComponentAPIBus(bus.Broadcast, 'CompareComponentProperty', component, path, oldValue)
if not(newValue == oldValue) and oldValueCompared and newValueCompared and not isOldNewValueSame:
print("GetSetCompare Test " + path + ": SUCCESS")
else:
print("GetSetCompare Test " + path + ": FAILURE")
# Test Clear (set an invalid AssetId, check that the field was cleared correctly)
editor.EditorComponentAPIBus(bus.Broadcast, 'SetComponentProperty', component, path, asset.AssetId())
clearObj = editor.EditorComponentAPIBus(bus.Broadcast, 'GetComponentProperty', component, path)
if(clearObj.IsSuccess()):
clearValue = clearObj.GetValue()
clearedValueCompared = editor.EditorComponentAPIBus(bus.Broadcast, 'CompareComponentProperty', component, path, clearValue)
isNewClearedValueSame = editor.EditorComponentAPIBus(bus.Broadcast, 'CompareComponentProperty', component, path, newValue)
if (clearValue == asset.AssetId()) and clearedValueCompared and not isNewClearedValueSame:
print("GetSetCompare Clear " + path + ": SUCCESS")
else:
print("GetSetCompare Clear " + path + ": FAILURE")
def PteTest(pte, path, value):
# Test Get/Set (get old value, set new value, check that new value was set correctly)
oldObj = pte.get_value(path)
if(oldObj.IsSuccess()):
oldValue = oldObj.GetValue()
oldValueCompared = pte.compare_value(path, oldValue)
pte.set_value(path, value)
newObj = pte.get_value(path)
if(newObj.IsSuccess()):
newValue = newObj.GetValue()
newValueCompared = pte.compare_value(path, newValue)
isOldNewValueSame = pte.compare_value(path, oldValue)
if not(newValue == oldValue) and oldValueCompared and newValueCompared and not isOldNewValueSame:
print("PTE Test " + path + ": SUCCESS")
else:
print("PTE Test " + path + ": FAILURE")
# Test Clear (set an invalid AssetId, check that the field was cleared correctly)
pte.set_value(path, asset.AssetId())
clearObj = pte.get_value(path)
if(clearObj.IsSuccess()):
clearValue = clearObj.GetValue()
clearedValueCompared = pte.compare_value(path, clearValue)
isNewClearedValueSame = pte.compare_value(path, newValue)
if (clearValue == asset.AssetId()) and clearedValueCompared and not isNewClearedValueSame:
print("PTE Clear " + path + ": SUCCESS")
else:
print("PTE Clear " + path + ": FAILURE")
# Create new Entity
entityId = editor.ToolsApplicationRequestBus(bus.Broadcast, 'CreateNewEntity', entity.EntityId())
if (entityId):
print("New entity with no parent created: SUCCESS")
# Get Component Type for Mesh
typeIdsList = editor.EditorComponentAPIBus(bus.Broadcast, 'FindComponentTypeIdsByEntityType', ["Mesh"], entity.EntityType().Game)
componentOutcome = editor.EditorComponentAPIBus(bus.Broadcast, 'AddComponentsOfType', entityId, typeIdsList)
if (componentOutcome.IsSuccess()):
print("Mesh component added to entity: SUCCESS")
components = componentOutcome.GetValue()
component = components[0]
hasComponent = editor.EditorComponentAPIBus(bus.Broadcast, 'HasComponentOfType', entityId, typeIdsList[0])
if(hasComponent):
print("Entity has a Mesh component: SUCCESS")
# Get the PTE from the Mesh Component
pteObj = editor.EditorComponentAPIBus(bus.Broadcast, 'BuildComponentPropertyTreeEditor', component)
if(pteObj.IsSuccess()):
pte = pteObj.GetValue()
# Tests for the Asset<> case
cubeId = asset.AssetCatalogRequestBus(bus.Broadcast, 'GetAssetIdByPath', 'objects/default/primitive_cube.cgf', math.Uuid(), False)
GetSetCompareTest(component, "MeshComponentRenderNode|Mesh asset", cubeId)
PteTest(pte, "MeshComponentRenderNode|Mesh asset", cubeId)
# Tests for the SimpleAssetReference case
materialId = asset.AssetCatalogRequestBus(bus.Broadcast, 'GetAssetIdByPath', 'engineassets/texturemsg/defaultsolids.mtl', math.Uuid(), False)
GetSetCompareTest(component, "MeshComponentRenderNode|Material override", materialId)
PteTest(pte, "MeshComponentRenderNode|Material override", materialId)
editor.EditorToolsApplicationRequestBus(bus.Broadcast, 'ExitNoPrompt')
@@ -0,0 +1,63 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
#
# This is a pytest module to test the in-Editor Python API from PythonEditorFuncs
#
import pytest
pytest.importorskip('ly_test_tools')
import sys
import os
sys.path.append(os.path.dirname(__file__))
from hydra_utils import launch_test_case
@pytest.mark.skip # SPEC-4102
@pytest.mark.SUITE_sandbox
@pytest.mark.parametrize('launcher_platform', ['windows_editor'])
@pytest.mark.parametrize('project', ['AutomatedTesting'])
@pytest.mark.parametrize('level', ['Simple'])
class TestComponentCommands(object):
def test_MeshComponentBasics(self, request, editor, level, launcher_platform):
unexpected_lines=[]
expected_lines = [
"Type Ids List returned correctly",
"Type Names List returned correctly",
"New entity with no parent created",
"Entity does not have a Mesh component",
"Mesh component added to entity",
"EntityId on the meshComponent EntityComponentIdPair matches",
"EntityComponentIdPair to_string works",
"Entity has a Mesh component",
"Mesh component is active",
"Mesh component is not active",
"Mesh component is valid",
"Comment components added to entity",
"Got both Comment components",
"GetComponent works",
"Entity has two Comment components",
"Disabled both Comment components",
"Enabled both Comment components",
"Mesh Component removed",
"Mesh component is no longer valid",
"Single comment component added to entity",
"Entity has three Comment components",
"Mesh Collider component added to entity",
"Mesh Collider component retrieved from entity",
"Mesh Collider component removed from entity"
]
test_case_file = os.path.join(os.path.dirname(__file__), 'ComponentCommands_test_case.py')
launch_test_case(editor, test_case_file, expected_lines, unexpected_lines)
@@ -0,0 +1,193 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
# Tests a portion of the Component CRUD Python API while the Editor is running
import azlmbr.bus as bus
import azlmbr.entity as entity
import azlmbr.editor as editor
import azlmbr.object
import azlmbr.math
from azlmbr.entity import EntityId
def CompareComponentEntityIdPairs(component1, component2):
return component1.Equal(component2)
# Open a level (any level should work)
editor.EditorToolsApplicationRequestBus(bus.Broadcast, 'OpenLevelNoPrompt', 'WaterSample')
# Get Component Types for Mesh and Comment
typeIdsList = editor.EditorComponentAPIBus(bus.Broadcast, 'FindComponentTypeIdsByEntityType', ["Mesh", "Comment", "Mesh Collider"], entity.EntityType().Game)
if(len(typeIdsList) > 0):
print("Type Ids List returned correctly")
meshComponentTypeId = typeIdsList[0]
commentComponentTypeId = typeIdsList[1]
meshColliderComponentTypeId = typeIdsList[2]
# Get Component Ids from Component Types
typeNamesList = editor.EditorComponentAPIBus(bus.Broadcast, 'FindComponentTypeNames', typeIdsList)
if(typeNamesList[0] == "Mesh") and (typeNamesList[1] == "Comment") and (typeNamesList[2] == "Mesh Collider"):
print("Type Names List returned correctly")
# Test Component API
newEntityId = editor.ToolsApplicationRequestBus(bus.Broadcast, 'CreateNewEntity', EntityId())
if (newEntityId):
print("New entity with no parent created")
hadComponent = editor.EditorComponentAPIBus(bus.Broadcast, 'HasComponentOfType', newEntityId, meshComponentTypeId)
if not(hadComponent):
print("Entity does not have a Mesh component")
meshComponentOutcome = editor.EditorComponentAPIBus(bus.Broadcast, 'AddComponentsOfType', newEntityId, [meshComponentTypeId])
if (meshComponentOutcome.IsSuccess()):
print("Mesh component added to entity")
meshComponents = meshComponentOutcome.GetValue()
meshComponent = meshComponents[0]
if(meshComponent.get_entity_id() == newEntityId):
print("EntityId on the meshComponent EntityComponentIdPair matches")
if not(meshComponent.to_string() == ""):
print("EntityComponentIdPair to_string works")
hasComponent = editor.EditorComponentAPIBus(bus.Broadcast, 'HasComponentOfType', newEntityId, meshComponentTypeId)
if(hasComponent):
print("Entity has a Mesh component")
isActive = editor.EditorComponentAPIBus(bus.Broadcast, 'IsComponentEnabled', meshComponent)
if(isActive):
print("Mesh component is active")
editor.EditorComponentAPIBus(bus.Broadcast, 'DisableComponents', [meshComponent])
isNotActive = editor.EditorComponentAPIBus(bus.Broadcast, 'IsComponentEnabled', meshComponent)
if not(isNotActive):
print("Mesh component is not active")
if(editor.EditorComponentAPIBus(bus.Broadcast, 'IsValid', meshComponent)):
print("Mesh component is valid")
CommentComponentsOutcome = editor.EditorComponentAPIBus(bus.Broadcast, 'AddComponentsOfType', newEntityId, [commentComponentTypeId, commentComponentTypeId])
if (CommentComponentsOutcome.IsSuccess()):
print("Comment components added to entity")
CommentComponents = CommentComponentsOutcome.GetValue()
GetCommentComponentsOutcome = editor.EditorComponentAPIBus(bus.Broadcast, 'GetComponentsOfType', newEntityId, commentComponentTypeId)
if(GetCommentComponentsOutcome.IsSuccess()):
GetCommentComponents = GetCommentComponentsOutcome.GetValue()
if(CompareComponentEntityIdPairs(CommentComponents[0], GetCommentComponents[0]) and CompareComponentEntityIdPairs(CommentComponents[1], GetCommentComponents[1])):
print("Got both Comment components")
if(CompareComponentEntityIdPairs(CommentComponents[0], GetCommentComponents[1]) and CompareComponentEntityIdPairs(CommentComponents[1], GetCommentComponents[0])):
print("Got both Comment components")
GetComponentOutcome = editor.EditorComponentAPIBus(bus.Broadcast, 'GetComponentOfType', newEntityId, meshComponentTypeId)
if(GetComponentOutcome.IsSuccess() and CompareComponentEntityIdPairs(GetComponentOutcome.GetValue(), meshComponent)):
print("GetComponent works")
commentsCount = editor.EditorComponentAPIBus(bus.Broadcast, 'CountComponentsOfType', newEntityId, commentComponentTypeId)
if(commentsCount == 2):
print("Entity has two Comment components")
editor.EditorComponentAPIBus(bus.Broadcast, 'DisableComponents', CommentComponents)
isCActive = editor.EditorComponentAPIBus(bus.Broadcast, 'IsComponentEnabled', CommentComponents[0])
isC2Active = editor.EditorComponentAPIBus(bus.Broadcast, 'IsComponentEnabled', CommentComponents[1])
if not(isCActive) and not(isC2Active):
print("Disabled both Comment components")
editor.EditorComponentAPIBus(bus.Broadcast, 'EnableComponents', CommentComponents)
isCActive = editor.EditorComponentAPIBus(bus.Broadcast, 'IsComponentEnabled', CommentComponents[0])
isC2Active = editor.EditorComponentAPIBus(bus.Broadcast, 'IsComponentEnabled', CommentComponents[1])
if (isCActive) and (isC2Active):
print("Enabled both Comment components")
editor.EditorComponentAPIBus(bus.Broadcast, 'RemoveComponents', [meshComponent])
hasMesh = editor.EditorComponentAPIBus(bus.Broadcast, 'HasComponentOfType', newEntityId, meshComponentTypeId)
componentSingleOutcome = editor.EditorComponentAPIBus(bus.Broadcast, 'AddComponentOfType', newEntityId, commentComponentTypeId)
if (componentSingleOutcome.IsSuccess()):
print("Single comment component added to entity")
commentsCount = editor.EditorComponentAPIBus(bus.Broadcast, 'CountComponentsOfType', newEntityId, commentComponentTypeId)
if (commentsCount == 3):
print("Entity has three Comment components")
if not(hasMesh):
print("Mesh Component removed")
if not(editor.EditorComponentAPIBus(bus.Broadcast, 'IsValid', meshComponent)):
print("Mesh component is no longer valid")
# Test that it is possible to access Components with no Editor Component (for example, the legacy mesh collider)
meshColliderComponentOutcome = editor.EditorComponentAPIBus(bus.Broadcast, 'AddComponentsOfType', newEntityId, [meshColliderComponentTypeId])
if (meshColliderComponentOutcome.IsSuccess()):
print("Mesh Collider component added to entity")
meshColliderComponent = meshColliderComponentOutcome.GetValue()
getMeshColliderComponentOutcome = editor.EditorComponentAPIBus(bus.Broadcast, 'GetComponentOfType', newEntityId, meshComponentTypeId)
if(getMeshColliderComponentOutcome.IsSuccess() and CompareComponentEntityIdPairs(meshColliderComponent, getMeshColliderComponentOutcome.GetValue())):
print("Mesh Collider component retrieved from entity")
editor.EditorComponentAPIBus(bus.Broadcast, 'RemoveComponents', [meshColliderComponent])
hasMeshCollider = editor.EditorComponentAPIBus(bus.Broadcast, 'HasComponentOfType', newEntityId, meshColliderComponentTypeId)
if not(hasMeshCollider):
print("Mesh Collider Component removed")
# Test that it is possible to access Components with no Editor Component(for example, the legacy mesh collider) via GetComponentOfType
meshColliderComponentOutcome = editor.EditorComponentAPIBus(bus.Broadcast, 'AddComponentsOfType', newEntityId, [meshColliderComponentTypeId])
if (meshColliderComponentOutcome.IsSuccess()):
print("Mesh Collider component added to entity")
meshColliderComponent = meshColliderComponentOutcome.GetValue()[0]
getMeshColliderComponentOutcome = editor.EditorComponentAPIBus(bus.Broadcast, 'GetComponentOfType', newEntityId, meshColliderComponentTypeId)
if(getMeshColliderComponentOutcome.IsSuccess() and CompareComponentEntityIdPairs(meshColliderComponent, getMeshColliderComponentOutcome.GetValue())):
print("Mesh Collider component retrieved from entity")
meshColliderRemoved = False;
meshColliderRemoved = editor.EditorComponentAPIBus(bus.Broadcast, 'RemoveComponents', [meshColliderComponent])
if meshColliderRemoved:
print("Mesh Collider component removed from entity")
editor.EditorToolsApplicationRequestBus(bus.Broadcast, 'ExitNoPrompt')
@@ -0,0 +1,28 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
# LY-107818 reported a crash with this code snippet
# This new test will be used to regress test the issue
import azlmbr.bus as bus
import azlmbr.editor as editor
try:
componentList = editor.EditorComponentAPIBus(bus.Broadcast, 'BuildComponentTypeNameList')
if(componentList is not None and len(componentList) > 0):
print("BuildComponentTypeNameList returned a valid list: SUCCESS")
print("BuildComponentTypeNameList ran: SUCCESS")
except:
print("BuildComponentTypeNameList usage threw an exception: FAILURE")
editor.EditorToolsApplicationRequestBus(bus.Broadcast, 'ExitNoPrompt')
@@ -0,0 +1,120 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
#
# This is a pytest module to test the in-Editor Python API from PythonEditorFuncs
#
import pytest
pytest.importorskip('ly_test_tools')
import sys
import os
sys.path.append(os.path.dirname(__file__))
from hydra_utils import launch_test_case
@pytest.mark.SUITE_sandbox
@pytest.mark.parametrize('launcher_platform', ['windows_editor'])
@pytest.mark.parametrize('project', ['AutomatedTesting'])
@pytest.mark.parametrize('level', ['Simple'])
class TestGradientRequiresShape(object):
@pytest.mark.skip # SPEC-4102
def test_ComponentProperty(self, request, editor, level, launcher_platform):
unexpected_lines=[]
expected_lines = [
"New entity with no parent created",
"Environment Probe component added to entity",
"Entity has an Environment Probe component",
"get_paths_list works",
"GetSetCompareTest Settings|General Settings|Visible: SUCCESS",
"GetSetCompareTest Settings|Animation|Style: SUCCESS",
"GetSetCompareTest Settings|Environment Probe Settings|Box height: SUCCESS",
"GetSetCompareTest Settings|General Settings|Color: SUCCESS",
"GetSetCompareTest Settings|Environment Probe Settings|Area dimensions: SUCCESS",
"PteTest Settings|General Settings|Visible: SUCCESS",
"PteTest Settings|Animation|Style: SUCCESS",
"PteTest Settings|Environment Probe Settings|Box height: SUCCESS",
"PteTest Settings|General Settings|Color: SUCCESS",
"PteTest Settings|Environment Probe Settings|Area dimensions: SUCCESS",
]
test_case_file = os.path.join(os.path.dirname(__file__), 'ComponentPropertyCommands_test_case.py')
launch_test_case(editor, test_case_file, expected_lines, unexpected_lines)
@pytest.mark.skip # SPEC-4102
def test_SetDistance_Between_FilterBound_Mode(self, request, editor, level, launcher_platform):
unexpected_lines = ['FAILURE', 'script failure']
expected_lines = [
"New entity with no parent created: SUCCESS",
"Components added to entity: SUCCESS",
"Found Vegetation Distance Between Filter: SUCCESS",
"CompareComponentProperty - Configuration|Bound Mode: SUCCESS",
"GetSetCompareTest - Configuration|Bound Mode: SUCCESS"
]
test_case_file = os.path.join(os.path.dirname(__file__), 'ComponentPropertyCommands_test_enum.py')
launch_test_case(editor, test_case_file, expected_lines, unexpected_lines)
@pytest.mark.skip # LYN-1951
def test_PropertyTreeVisibility(self, request, editor, level, launcher_platform):
unexpected_lines = ['FAILURE', 'script failure']
expected_lines = [
"oceanEntityId was found: SUCCESS",
"Found Infinite Ocean component ID: SUCCESS",
"Created a PropertyTreeEditor for the infiniteOceanId: SUCCESS",
"Found proprety hidden node in path: SUCCESS",
"Proprety node is now a hidden path: SUCCESS",
"Property path enforcement of visibility: SUCCESS"
]
test_case_file = os.path.join(os.path.dirname(__file__), 'ComponentPropertyCommands_test_case_visibility.py')
launch_test_case(editor, test_case_file, expected_lines, unexpected_lines)
@pytest.mark.skip # SPEC-4102
def test_PropertyContainerOpeartions(self, request, editor, level, launcher_platform):
unexpected_lines = ['FAILURE', 'script failure']
expected_lines = [
"New entity with no parent created: SUCCESS",
"GradientSurfaceDataComponent added to entity :SUCCESS",
"Has zero items: SUCCESS",
"Add an item 0: SUCCESS",
"Has one item 0: SUCCESS",
"Add an item 1: SUCCESS",
"Add an item 2: SUCCESS",
"Add an item 3: SUCCESS",
"Has four items: SUCCESS",
"Updated an item: SUCCESS",
"itemTag equals tagFour: SUCCESS",
"Removed one item 0: SUCCESS",
"Removed one item 1: SUCCESS",
"Has two items: SUCCESS",
"Reset items: SUCCESS",
"Has cleared the items: SUCCESS"
]
test_case_file = os.path.join(os.path.dirname(__file__), 'ComponentPropertyCommands_test_containers.py')
launch_test_case(editor, test_case_file, expected_lines, unexpected_lines)
@pytest.mark.skip # LYN-1951
def test_PropertyContainerOpeartionWithNone(self, request, editor, level, launcher_platform):
unexpected_lines = ['FAILURE', 'script failure']
expected_lines = [
"material current is valid - True: SUCCESS",
"material set to None: SUCCESS",
"material has been set to None: SUCCESS"
]
test_case_file = os.path.join(os.path.dirname(__file__), 'ComponentPropertyCommands_test_case_set_none.py')
launch_test_case(editor, test_case_file, expected_lines, unexpected_lines)
@@ -0,0 +1,142 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
# Tests a portion of the Component Property Get/Set Python API while the Editor is running
import azlmbr.bus as bus
import azlmbr.editor as editor
import azlmbr.entity as entity
import azlmbr.math as math
# Open a level (any level should work)
editor.EditorToolsApplicationRequestBus(bus.Broadcast, 'OpenLevelNoPrompt', 'WaterSample')
def GetSetCompareTest(component, path, value):
oldObj = editor.EditorComponentAPIBus(bus.Broadcast, 'GetComponentProperty', component, path)
if(oldObj.IsSuccess()):
oldValue = oldObj.GetValue()
oldValueCompared = editor.EditorComponentAPIBus(bus.Broadcast, 'CompareComponentProperty', component, path, oldValue)
editor.EditorComponentAPIBus(bus.Broadcast, 'SetComponentProperty', component, path, value)
newObj = editor.EditorComponentAPIBus(bus.Broadcast, 'GetComponentProperty', component, path)
if(newObj.IsSuccess()):
newValue = newObj.GetValue()
newValueCompared = editor.EditorComponentAPIBus(bus.Broadcast, 'CompareComponentProperty', component, path, newValue)
isOldNewValueSame = editor.EditorComponentAPIBus(bus.Broadcast, 'CompareComponentProperty', component, path, oldValue)
if not(newValue == oldValue and oldValueCompared and newValueCompared and not isOldNewValueSame):
print("GetSetCompareTest " + path + ": SUCCESS")
else:
print("GetSetCompareTest " + path + ": FAILURE")
def PteTest(pte, path, value):
oldObj = pte.get_value(path)
if(oldObj.IsSuccess()):
oldValue = oldObj.GetValue()
oldValueCompared = pte.compare_value(path, oldValue)
pte.set_value(path, value)
newObj = pte.get_value(path)
if(newObj.IsSuccess()):
newValue = newObj.GetValue()
newValueCompared = pte.compare_value(path, newValue)
isOldNewValueSame = pte.compare_value(path, oldValue)
if not(newValue == oldValue and oldValueCompared and newValueCompared and not isOldNewValueSame):
print("PteTest " + path + ": SUCCESS")
else:
print("PteTest " + path + ": FAILURE")
# Create new Entity
entityId = editor.ToolsApplicationRequestBus(bus.Broadcast, 'CreateNewEntity', entity.EntityId())
if (entityId):
print("New entity with no parent created")
# Get Component Type for Environment Probe
typeIdsList = editor.EditorComponentAPIBus(bus.Broadcast, 'FindComponentTypeIdsByEntityType', ["Environment Probe"], entity.EntityType().Game)
componentOutcome = editor.EditorComponentAPIBus(bus.Broadcast, 'AddComponentsOfType', entityId, typeIdsList)
if (componentOutcome.IsSuccess()):
print("Environment Probe component added to entity")
components = componentOutcome.GetValue()
component = components[0]
hasComponent = editor.EditorComponentAPIBus(bus.Broadcast, 'HasComponentOfType', entityId, typeIdsList[0])
if(hasComponent):
print("Entity has an Environment Probe component")
# Test BuildComponentPropertyList
paths = editor.EditorComponentAPIBus(bus.Broadcast, 'BuildComponentPropertyList', component)
if(len(paths) > 0):
print("get_paths_list works")
# Tests for GetComponentProperty/SetComponentProperty
GetSetCompareTest(component, "Settings|General Settings|Visible", False)
GetSetCompareTest(component, "Settings|Animation|Style", 2.0)
GetSetCompareTest(component, "Settings|Environment Probe Settings|Box height", 42)
color = math.Color()
color.r = 0.4
color.g = 0.5
color.b = 0.6
GetSetCompareTest(component, "Settings|General Settings|Color", color)
vec3 = math.Vector3()
vec3.x = 1.0
vec3.y = 2.0
vec3.z = 3.0
GetSetCompareTest(component, "Settings|Environment Probe Settings|Area dimensions", vec3)
# Tests for BuildComponentPropertyTreeEditor
pteObj = editor.EditorComponentAPIBus(bus.Broadcast, 'BuildComponentPropertyTreeEditor', component)
if(pteObj.IsSuccess()):
print("")
pte = pteObj.GetValue()
PteTest(pte, "Settings|General Settings|Visible", True)
PteTest(pte, "Settings|Animation|Style", 4)
PteTest(pte, "Settings|Environment Probe Settings|Box height", 48.0)
color = math.Color()
color.r = 0.9
color.g = 0.1
color.b = 0.3
PteTest(pte, "Settings|General Settings|Color", color)
vec3 = math.Vector3()
vec3.x = 7.0
vec3.y = 4.0
vec3.z = 1.0
PteTest(pte, "Settings|Environment Probe Settings|Area dimensions", vec3)
editor.EditorToolsApplicationRequestBus(bus.Broadcast, 'ExitNoPrompt')
@@ -0,0 +1,86 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
# Tests setting property values that are not 32 or 64 bit such as a u8
import azlmbr.bus as bus
import azlmbr.editor as editor
import azlmbr.entity as entity
import azlmbr.math as math
# Open a level
editor.EditorToolsApplicationRequestBus(bus.Broadcast, 'OpenLevelNoPrompt', 'ocean_component')
# toggle the entity system to use visibility enforcement rules
editor.EditorComponentAPIBus(bus.Broadcast, 'SetVisibleEnforcement', True)
def print_result(message, result):
if result:
print(message + ": SUCCESS")
else:
print(message + ": FAILURE")
def get_entity_by_name(name):
searchFilter = entity.SearchFilter()
searchFilter.names = [name]
searchResult = entity.SearchBus(bus.Broadcast, 'SearchEntities', searchFilter)
if(len(searchResult) > 0):
return searchResult
print_result("get_entity_by_name - {}".format(name), False)
return None
def get_component_type_by_name(name):
gameType = entity.EntityType().Game
listOfTypeIds = editor.EditorComponentAPIBus(bus.Broadcast, 'FindComponentTypeIdsByEntityType', [name], gameType)
if(len(listOfTypeIds) > 0):
return listOfTypeIds[0]
print_result("get_component_type_by_name - {}".format(name), False)
return None
def get_component_of_type(entity, componentTypeId):
outcome = editor.EditorComponentAPIBus(bus.Broadcast, 'GetComponentOfType', entity, componentTypeId)
if(outcome.IsSuccess()):
return outcome.GetValue()
print_result("get_component_of_type - {} for type {}".format(entity, componentTypeId), False)
return None
def get_component_property(component, path):
outcome = editor.EditorComponentAPIBus(bus.Broadcast, 'GetComponentProperty', component, path)
if(outcome.IsSuccess()):
return outcome.GetValue()
print_result("get_component_property - {}".format(path), False)
return None
def set_component_property(component, path, value):
outcome = editor.EditorComponentAPIBus(bus.Broadcast, 'SetComponentProperty', component, path, value)
if(outcome.IsSuccess()):
return True
print_result("set_component_property - {} with value {}".format(path, value), False)
return False
# fetch the ocean entity and its 'ocean' component
entityId = get_entity_by_name('the_ocean')[0]
riverComponentTypeId = get_component_type_by_name('Infinite Ocean')
riverComponent = get_component_of_type(entityId, riverComponentTypeId)
# this series tests that a material can be fetched, mutated with a None, and reverts to an 'empty asset'
materialPropertPath = 'General|Water Material'
material = get_component_property(riverComponent, materialPropertPath)
print_result("material current is valid - {}".format(material.is_valid()), material.is_valid())
materialUpdateResult = set_component_property(riverComponent, materialPropertPath, None)
print_result("material set to None", materialUpdateResult)
material = get_component_property(riverComponent, materialPropertPath)
print_result("material has been set to None", material.is_valid() is False)
# All Done!
editor.EditorToolsApplicationRequestBus(bus.Broadcast, 'ExitNoPrompt')
@@ -0,0 +1,61 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
# ComponentPropertyCommands test case visibility
import azlmbr.bus as bus
import azlmbr.editor as editor
import azlmbr.entity as entity
# Open a level
editor.EditorToolsApplicationRequestBus(bus.Broadcast, 'OpenLevelNoPrompt', 'ocean_component')
def print_result(result, message):
if result:
print(message + ": SUCCESS")
else:
print(message + ": FAILURE")
def add_componet(typename, entityId):
typeIdsList = editor.EditorComponentAPIBus(bus.Broadcast, 'FindComponentTypeIdsByEntityType', [typename], entity.EntityType().Game)
componentOutcome = editor.EditorComponentAPIBus(bus.Broadcast, 'AddComponentsOfType', entityId, typeIdsList)
print_result(componentOutcome.IsSuccess(), "{} component added to entity".format(typename))
return componentOutcome.GetValue()
# Find ocean entity
searchFilter = entity.SearchFilter()
searchFilter.names = ["the_ocean"]
oceanEntityId = entity.SearchBus(bus.Broadcast, 'SearchEntities', searchFilter)[0]
print_result(oceanEntityId, "oceanEntityId was found")
# Find Infinite Ocean component
typeIdsList = editor.EditorComponentAPIBus(bus.Broadcast, 'FindComponentTypeIdsByEntityType', ['Infinite Ocean'], entity.EntityType().Game)
getComponentOutcome = editor.EditorComponentAPIBus(bus.Broadcast, 'GetComponentOfType', oceanEntityId, typeIdsList[0])
print_result(getComponentOutcome.IsSuccess(), "Found Infinite Ocean component ID")
infiniteOceanId = getComponentOutcome.GetValue()
# Get the PTE from the Mesh Component
pteObj = editor.EditorComponentAPIBus(bus.Broadcast, 'BuildComponentPropertyTreeEditor', infiniteOceanId)
print_result(pteObj.IsSuccess(), "Created a PropertyTreeEditor for the infiniteOceanId")
pte = pteObj.GetValue()
# test for visibility (default all nodes are exposed)
print_result(pte.get_value('m_data|General|General|Enable Ocean Bottom').IsSuccess(), "Found proprety hidden node in path")
# enable visibility enforcement
pte.set_visible_enforcement(True)
print_result(pte.get_value('m_data|General|General|Enable Ocean Bottom').IsSuccess() is not True, "Proprety node is now a hidden path")
# test for visibility (missing some properties now)
print_result(pte.get_value('General|Enable Ocean Bottom').IsSuccess(), "Property path enforcement of visibility")
# All Done!
editor.EditorToolsApplicationRequestBus(bus.Broadcast, 'ExitNoPrompt')
@@ -0,0 +1,130 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
# Tests component properties that are containers
import azlmbr.bus as bus
import azlmbr.editor as editor
import azlmbr.entity as entity
import azlmbr.surface_data
import azlmbr.globals
# Open a level
editor.EditorToolsApplicationRequestBus(bus.Broadcast, 'OpenLevelNoPrompt', 'auto_test')
def print_result(message, result):
if result:
print(message + ": SUCCESS")
else:
print(message + ": FAILURE")
def is_container(pte, path):
return pte.is_container(path)
def get_container_count(pte, path):
outcome = pte.get_container_count(path)
if(outcome.IsSuccess()):
return outcome.GetValue()
return False
def reset_container(pte, path):
outcome = pte.reset_container(path)
if(outcome.IsSuccess()):
return outcome.GetValue()
return False
def add_container_item(pte, path, key, item):
outcome = pte.add_container_item(path, key, item)
if(outcome.IsSuccess()):
return outcome.GetValue()
return False
def remove_container_item(pte, path, key):
outcome = pte.remove_container_item(path, key)
if(outcome.IsSuccess()):
return outcome.GetValue()
return False
def update_container_item(pte, path, key, value):
outcome = pte.update_container_item(path, key, value)
if(outcome.IsSuccess()):
return outcome.GetValue()
return False
def get_container_item(pte, path, key):
outcome = pte.get_container_item(path, key)
if(outcome.IsSuccess()):
return outcome.GetValue()
return False
# Create new Entity
entityId = editor.ToolsApplicationRequestBus(bus.Broadcast, 'CreateNewEntity', entity.EntityId())
print_result("New entity with no parent created", entityId)
tagOne = azlmbr.surface_data.SurfaceTag()
tagOne.SetTag('one')
tagTwo = azlmbr.surface_data.SurfaceTag()
tagTwo.SetTag('two')
tagThree = azlmbr.surface_data.SurfaceTag()
tagThree.SetTag('three')
tagFour = azlmbr.surface_data.SurfaceTag()
tagFour.SetTag('four')
# create a component with a TagSurface container
typeIdsList = [azlmbr.globals.property.GradientSurfaceDataComponentTypeId]
componentOutcome = editor.EditorComponentAPIBus(bus.Broadcast, 'AddComponentsOfType', entityId, typeIdsList)
if (componentOutcome.IsSuccess()):
print("GradientSurfaceDataComponent added to entity :SUCCESS")
else:
raise Exception('FAILURE FATAL: AddComponentsOfType')
components = componentOutcome.GetValue()
tagList = components[0]
pteOutcome = editor.EditorComponentAPIBus(bus.Broadcast, 'BuildComponentPropertyTreeEditor', tagList)
if(pteOutcome.IsSuccess()):
pte = pteOutcome.GetValue()
print("Created a PropertyTreeEditor :SUCCESS")
else:
raise Exception('FAILURE FATAL: BuildComponentPropertyTreeEditor')
# Test BuildComponentPropertyList
paths = pte.build_paths_list()
for p in paths:
print('>> {}'.format(p))
tagListPropertyPath = 'm_template|Extended Tags'
print_result('Has a container', is_container(pte, tagListPropertyPath))
print_result('Has zero items', get_container_count(pte, tagListPropertyPath) == 0)
print_result('Add an item 0', add_container_item(pte, tagListPropertyPath, 0, tagOne))
print_result('Has one item 0', get_container_count(pte, tagListPropertyPath) == 1)
print_result('Add an item 1', add_container_item(pte, tagListPropertyPath, 1, tagOne))
print_result('Add an item 2', add_container_item(pte, tagListPropertyPath, 2, tagTwo))
print_result('Add an item 3', add_container_item(pte, tagListPropertyPath, 3, tagThree))
print_result('Has four items', get_container_count(pte, tagListPropertyPath) == 4)
print_result('Updated an item', update_container_item(pte, tagListPropertyPath, 2, tagFour))
itemTag = get_container_item(pte, tagListPropertyPath, 2)
print_result ('itemTag equals tagFour', itemTag.Equal(tagFour))
print_result('Removed one item 0', remove_container_item(pte, tagListPropertyPath, 0))
print_result('Removed one item 1', remove_container_item(pte, tagListPropertyPath, 0))
print_result('Has two items', get_container_count(pte, tagListPropertyPath) == 2)
print_result('Reset items', reset_container(pte, tagListPropertyPath))
print_result('Has cleared the items', get_container_count(pte, tagListPropertyPath) == 0)
# All Done!
editor.EditorToolsApplicationRequestBus(bus.Broadcast, 'ExitNoPrompt')
@@ -0,0 +1,68 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
# Tests setting property values that are not 32 or 64 bit such as a u8
import azlmbr.bus as bus
import azlmbr.editor as editor
import azlmbr.entity as entity
import azlmbr.math as math
# Open a level
editor.EditorToolsApplicationRequestBus(bus.Broadcast, 'OpenLevelNoPrompt', 'auto_test')
def print_result(message, result):
if result:
print(message + ": SUCCESS")
else:
print(message + ": FAILURE")
def GetSetCompareTest(component, path, value):
oldObj = editor.EditorComponentAPIBus(bus.Broadcast, 'GetComponentProperty', component, path)
if(oldObj.IsSuccess()):
oldValue = oldObj.GetValue()
oldValueCompared = editor.EditorComponentAPIBus(bus.Broadcast, 'CompareComponentProperty', component, path, oldValue)
print_result("CompareComponentProperty - {}".format(path), oldValueCompared)
editor.EditorComponentAPIBus(bus.Broadcast, 'SetComponentProperty', component, path, value)
newObj = editor.EditorComponentAPIBus(bus.Broadcast, 'GetComponentProperty', component, path)
if(newObj.IsSuccess()):
newValue = newObj.GetValue()
newValueCompared = editor.EditorComponentAPIBus(bus.Broadcast, 'CompareComponentProperty', component, path, newValue)
isOldNewValueSame = editor.EditorComponentAPIBus(bus.Broadcast, 'CompareComponentProperty', component, path, oldValue)
result = not(newValue == oldValue and newValueCompared and not isOldNewValueSame)
print_result("GetSetCompareTest - {}".format(path), result)
# Create new Entity
entity_position = math.Vector3(125.0,136.0,32.0)
entityId = editor.ToolsApplicationRequestBus(bus.Broadcast, 'CreateNewEntityAtPosition', entity_position, entity.EntityId())
print_result("New entity with no parent created", entityId is not None)
# create a vegetation layer with a box shape and distance filter
typenameList = ["Vegetation Layer Spawner", "Vegetation Asset List", "Box Shape", "Vegetation Distance Between Filter"]
typeIdsList = editor.EditorComponentAPIBus(bus.Broadcast, 'FindComponentTypeIdsByEntityType', typenameList, entity.EntityType().Game)
addComponentsOutcome = editor.EditorComponentAPIBus(bus.Broadcast, 'AddComponentsOfType', entityId, typeIdsList)
print_result("Components added to entity", addComponentsOutcome.IsSuccess())
# fetch the Vegetation Distance Between Filter
vegDistTypeIdList = editor.EditorComponentAPIBus(bus.Broadcast, 'FindComponentTypeIdsByEntityType', ["Vegetation Distance Between Filter"], entity.EntityType().Game)
componentOutcome = editor.EditorComponentAPIBus(bus.Broadcast, 'GetComponentsOfType', entityId, vegDistTypeIdList[0])
print_result('Found Vegetation Distance Between Filter', componentOutcome.IsSuccess())
paths = editor.EditorComponentAPIBus(bus.Broadcast, 'BuildComponentPropertyList', componentOutcome.GetValue()[0])
# update the bound box type
pathToBoundMode = "Configuration|Bound Mode"
GetSetCompareTest(componentOutcome.GetValue()[0], pathToBoundMode, 1)
# All Done!
editor.EditorToolsApplicationRequestBus(bus.Broadcast, 'ExitNoPrompt')
@@ -0,0 +1,43 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
#
# This is a pytest module to test the in-Editor Python API from PythonEditorFuncs
#
import pytest
pytest.importorskip('ly_test_tools')
import sys
import os
sys.path.append(os.path.dirname(__file__))
from hydra_utils import launch_test_case
@pytest.mark.SUITE_sandbox
@pytest.mark.parametrize('launcher_platform', ['windows_editor'])
@pytest.mark.parametrize('project', ['AutomatedTesting'])
@pytest.mark.parametrize('level', ['Simple'])
class TestComponentAssetAutomation(object):
def test_ComponentAsset(self, request, editor, level, launcher_platform):
unexpected_lines=[]
expected_lines = [
'Set EditorDescriptorListComponent Embedded Assets as List',
'Set EditorDescriptorListComponent Embedded Assets 0 Descriptor Mesh Asset ID',
'Set EditorDescriptorListComponent Embedded Assets 1 Descriptor Mesh Asset ID',
'Set EditorDescriptorListComponent Embedded Assets 2 Descriptor Mesh Asset ID',
'Set EditorDescriptorListComponent Embedded Assets 3 Descriptor Mesh Asset ID'
]
test_case_file = os.path.join(os.path.dirname(__file__), 'ComponentUpdateListProperty_test_case.py')
launch_test_case(editor, test_case_file, expected_lines, unexpected_lines)
@@ -0,0 +1,78 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
import azlmbr.object as object
import azlmbr.legacy.general as general
import azlmbr.editor as editor
import azlmbr.bus as bus
import azlmbr.entity as entity
import azlmbr.math as math
import azlmbr.asset as asset
def add_component_with_uuid(entityId, typeId):
componentOutcome = editor.EditorComponentAPIBus(bus.Broadcast, 'AddComponentsOfType', entityId, [typeId])
if (componentOutcome.IsSuccess()):
return componentOutcome.GetValue()[0]
def set_component_property(component, path, value):
outcome = editor.EditorComponentAPIBus(bus.Broadcast, 'SetComponentProperty', component, path, value)
return outcome.IsSuccess()
def get_component_property(component, path):
outcome = editor.EditorComponentAPIBus(bus.Broadcast, 'GetComponentProperty', component, path)
if (outcome.IsSuccess()):
return outcome.GetValue()
return None
try:
# Open a level
print ('Test started')
general.open_level_no_prompt('auto_test')
newEntityId = editor.ToolsApplicationRequestBus(bus.Broadcast, 'CreateNewEntity', entity.EntityId())
editorDescriptorListComponentId = math.Uuid_CreateString('{3AF9BE58-6D2D-44FB-AB4D-CA1182F6C78F}', 0)
descListComponent = add_component_with_uuid(newEntityId, editorDescriptorListComponentId)
print ('descListComponent added')
primitiveCubeId = asset.AssetCatalogRequestBus(bus.Broadcast, 'GetAssetIdByPath', 'objects/default/primitive_cube.cgf', math.Uuid(), False)
primitiveSphereId = asset.AssetCatalogRequestBus(bus.Broadcast, 'GetAssetIdByPath', 'objects/default/primitive_sphere.cgf', math.Uuid(), False)
primitiveCapsuleId = asset.AssetCatalogRequestBus(bus.Broadcast, 'GetAssetIdByPath', 'objects/default/primitive_capsule.cgf', math.Uuid(), False)
primitivePlaneId = asset.AssetCatalogRequestBus(bus.Broadcast, 'GetAssetIdByPath', 'objects/default/primitive_plane.cgf', math.Uuid(), False)
print ('fetched asset ids')
# expand the list of veg descriptors to 4 elements
descList = get_component_property(descListComponent, 'Configuration|Embedded Assets')
print('Got the veg descriptor list')
descElem = descList[0]
descList.append(descElem)
descList.append(descElem)
descList.append(descElem)
set_component_property(descListComponent, 'Configuration|Embedded Assets', descList)
print('Set EditorDescriptorListComponent Embedded Assets as List')
set_component_property(descListComponent, 'Configuration|Embedded Assets|[0]|Instance|Mesh Asset', primitiveCubeId)
print('Set EditorDescriptorListComponent Embedded Assets 0 Descriptor Mesh Asset ID')
set_component_property(descListComponent, 'Configuration|Embedded Assets|[1]|Instance|Mesh Asset', primitiveSphereId)
print('Set EditorDescriptorListComponent Embedded Assets 1 Descriptor Mesh Asset ID')
set_component_property(descListComponent, 'Configuration|Embedded Assets|[2]|Instance|Mesh Asset', primitiveCapsuleId)
print('Set EditorDescriptorListComponent Embedded Assets 2 Descriptor Mesh Asset ID')
set_component_property(descListComponent, 'Configuration|Embedded Assets|[3]|Instance|Mesh Asset', primitivePlaneId)
print('Set EditorDescriptorListComponent Embedded Assets 3 Descriptor Mesh Asset ID')
except:
print ('Test failed.')
finally:
print ('Test done.')
general.exit_no_prompt()
@@ -0,0 +1,75 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
#
# This is a pytest module to test the in-Editor Python API from ViewPane.h
#
import pytest
pytest.importorskip('ly_test_tools')
import sys
import os
sys.path.append(os.path.dirname(__file__))
from hydra_utils import launch_test_case
@pytest.mark.SUITE_sandbox
@pytest.mark.parametrize('launcher_platform', ['windows_editor'])
@pytest.mark.parametrize('project', ['AutomatedTesting'])
@pytest.mark.parametrize('level', ['auto_test'])
class TestLegacyCryMaterialsCommandsAutomation(object):
def test_Legacy_CryMaterials(self, request, editor, level, launcher_platform):
unexpected_lines=[]
expected_lines = [
# "Material Settings/Shader updated correctly", # Disabled, SPEC-3590
# "Material Settings/Surface Type updated correctly", # Disabled, SPEC-3590
"Texture Maps/Diffuse/Tiling/IsTileU updated correctly",
"Texture Maps/Diffuse/Tiling/TileU updated correctly",
"Texture Maps/Diffuse/Rotator/Type updated correctly",
"Texture Maps/Diffuse/Rotator/Amplitude updated correctly",
"Texture Maps/Diffuse/Oscillator/AmplitudeU updated correctly",
"Opacity Settings/Opacity updated correctly",
"Opacity Settings/AlphaTest updated correctly",
"Opacity Settings/Additive updated correctly",
"Lighting Settings/Diffuse Color updated correctly",
"Lighting Settings/Specular Color updated correctly",
"Lighting Settings/Emissive Intensity updated correctly",
"Lighting Settings/Emissive Color updated correctly",
"Advanced/Allow layer activation updated correctly",
"Advanced/2 Sided updated correctly",
"Advanced/No Shadow updated correctly",
"Advanced/Use Scattering updated correctly",
"Advanced/Hide After Breaking updated correctly",
"Advanced/Fog Volume Shading Quality High updated correctly",
"Advanced/Blend Terrain Color updated correctly",
"Advanced/Voxel Coverage updated correctly",
"Advanced/Propagate Opacity Settings updated correctly",
"Advanced/Propagate Lighting Settings updated correctly",
"Advanced/Propagate Advanced Settings updated correctly",
"Advanced/Propagate Texture Maps updated correctly",
"Advanced/Propagate Shader Params updated correctly",
"Advanced/Propagate Shader Generation updated correctly",
"Advanced/Propagate Vertex Deformation updated correctly",
# "Shader Params/Blend Factor updated correctly", # Disabled, SPEC-3590
# "Shader Params/Indirect bounce color updated correctly", # Disabled, SPEC-3590
"Vertex Deformation/Type updated correctly",
"Vertex Deformation/Wave Length X updated correctly",
"Vertex Deformation/Wave X/Level updated correctly",
"Vertex Deformation/Wave X/Amplitude updated correctly",
"Vertex Deformation/Wave X/Phase updated correctly",
"Vertex Deformation/Wave X/Frequency updated correctly"
]
test_case_file = os.path.join(os.path.dirname(__file__), 'CryMaterialsCommands_test_case.py')
launch_test_case(editor, test_case_file, expected_lines, unexpected_lines)
@@ -0,0 +1,116 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
# Tests the legacy Python API for CryMaterials while the Editor is running
import azlmbr.bus as bus
import azlmbr.editor as editor
import azlmbr.legacy.material as material
import azlmbr.math as math
materialName = 'materials/ter_layer_green'
print(f'Starting CryMaterial test case using material {materialName}')
def MaterialPropertyTest(property, value, doReset=True):
try:
# get old value and attempt to set new value
oldValue = material.get_property(materialName, property)
if oldValue == value:
print(f'>>> `{property}` already set to {oldValue}')
return
material.set_property(materialName, property, value)
# test that the set new value worked
newValue = material.get_property(materialName, property)
if oldValue != newValue:
print(f"{property} updated correctly")
# reset back to old value
if doReset:
material.set_property(materialName, property, oldValue)
except:
print(f'!!! hit an exception when setting `{property}` to {value}')
color = math.Color()
color.r = 255.0
color.g = 128.0
color.b = 64.0
color.a = 0.0
# Material Settings
# MaterialPropertyTest("Material Settings/Shader", "Geometrybeam") # Disabled, SPEC-3590
# MaterialPropertyTest("Material Settings/Surface Type", "grass") # Disabled, SPEC-3590
# Texture Maps
MaterialPropertyTest("Texture Maps/Diffuse/Tiling/IsTileU", False)
MaterialPropertyTest("Texture Maps/Diffuse/Tiling/IsTileV", False)
MaterialPropertyTest("Texture Maps/Diffuse/Tiling/TileU", 0.42)
MaterialPropertyTest("Texture Maps/Diffuse/Rotator/Type", 'Oscillated Rotation')
MaterialPropertyTest("Texture Maps/Diffuse/Rotator/Amplitude", 42.0)
MaterialPropertyTest("Texture Maps/Diffuse/Oscillator/TypeU", 'Fixed Moving')
MaterialPropertyTest("Texture Maps/Diffuse/Oscillator/AmplitudeU", 42.0)
# Vertex Deformation
MaterialPropertyTest("Vertex Deformation/Type", 'Sin Wave')
MaterialPropertyTest("Vertex Deformation/Wave Length X", 42.0)
MaterialPropertyTest("Vertex Deformation/Type", 'Perlin 3D')
MaterialPropertyTest("Vertex Deformation/Noise Scale", math.Vector3(1.1, 2.2, 3.3))
# Opacity Settings
MaterialPropertyTest("Opacity Settings/Opacity", 42)
MaterialPropertyTest("Opacity Settings/AlphaTest", 2)
MaterialPropertyTest("Opacity Settings/Additive", True)
# Lighting Settings
MaterialPropertyTest("Lighting Settings/Diffuse Color", color)
MaterialPropertyTest("Lighting Settings/Specular Color", color)
MaterialPropertyTest("Lighting Settings/Emissive Intensity", 42.0)
MaterialPropertyTest("Lighting Settings/Emissive Color", color)
MaterialPropertyTest("Lighting Settings/Specular Level", 2.0)
# Advanced
MaterialPropertyTest("Advanced/Allow layer activation", False)
MaterialPropertyTest("Advanced/2 Sided", True)
MaterialPropertyTest("Advanced/No Shadow", True)
MaterialPropertyTest("Advanced/Use Scattering", True)
MaterialPropertyTest("Advanced/Hide After Breaking", True)
MaterialPropertyTest("Advanced/Fog Volume Shading Quality High", True)
MaterialPropertyTest("Advanced/Blend Terrain Color", True)
MaterialPropertyTest("Advanced/Voxel Coverage", 0.42)
# --- MaterialPropertyTest("Advanced/Link to Material", "materials/ter_layer_blue") # Works, but clears on UI refresh
MaterialPropertyTest("Advanced/Propagate Opacity Settings", True)
MaterialPropertyTest("Advanced/Propagate Lighting Settings", True)
MaterialPropertyTest("Advanced/Propagate Advanced Settings", True)
MaterialPropertyTest("Advanced/Propagate Texture Maps", True)
MaterialPropertyTest("Advanced/Propagate Shader Params", True)
MaterialPropertyTest("Advanced/Propagate Shader Generation", True)
MaterialPropertyTest("Advanced/Propagate Vertex Deformation", True)
# Shader parameters vary with each Shader, just testing a couple of them...
# MaterialPropertyTest("Shader Params/Blend Factor", 7.0, False) # Disabled, SPEC-3590
# MaterialPropertyTest("Shader Params/Indirect bounce color", color, False) # Disabled, SPEC-3590
### These values are reset to False when set. Left them here commented for reference.
# MaterialPropertyTest("Shader Generation Params/Dust & Turbulence", True)
# MaterialPropertyTest("Shader Generation Params/Receive Shadows", True)
# MaterialPropertyTest("Shader Generation Params/UV Vignetting", True)
# Vertex Deformation
MaterialPropertyTest("Vertex Deformation/Type", "Sin Wave")
MaterialPropertyTest("Vertex Deformation/Wave Length X", 42.0)
MaterialPropertyTest("Vertex Deformation/Wave X/Level", 42.0)
MaterialPropertyTest("Vertex Deformation/Wave X/Amplitude", 42.0)
MaterialPropertyTest("Vertex Deformation/Wave X/Phase", 42.0)
MaterialPropertyTest("Vertex Deformation/Wave X/Frequency", 42.0)
editor.EditorToolsApplicationRequestBus(bus.Broadcast, 'ExitNoPrompt')
@@ -0,0 +1,38 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
#
# This is a pytest module to test the in-Editor Python API from ViewPane.h
#
import pytest
pytest.importorskip('ly_test_tools')
import sys
import os
sys.path.append(os.path.dirname(__file__))
from .hydra_utils import launch_test_case
@pytest.mark.SUITE_sandbox
@pytest.mark.parametrize('launcher_platform', ['windows_editor'])
@pytest.mark.parametrize('project', ['AutomatedTesting'])
@pytest.mark.parametrize('level', ['Simple'])
class TestDisplaySettingsAutomation(object):
def test_DisplaySettings(self, request, editor, level, launcher_platform):
unexpected_lines=[]
expected_lines = [
"display settings were changed correctly"
]
test_case_file = os.path.join(os.path.dirname(__file__), 'DisplaySettingsBus_test_case.py')
launch_test_case(editor, test_case_file, expected_lines, unexpected_lines)
@@ -0,0 +1,50 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
# Tests the Python API from DisplaySettingsPythonFuncs.cpp while the Editor is running
import azlmbr.bus as bus
import azlmbr.editor as editor
import azlmbr.display_settings as display_settings
# Retrieve current settings
existingState = display_settings.DisplaySettingsBus(bus.Broadcast, 'GetSettingsState')
# Alter settings
alteredState = azlmbr.object.create('DisplaySettingsState')
alteredState.no_collision = False
alteredState.no_labels = False
alteredState.simulate = True
alteredState.hide_tracks = False
alteredState.hide_links = False
alteredState.hide_helpers = False
alteredState.show_dimension_figures = True
# Set altered settings
display_settings.DisplaySettingsBus(bus.Broadcast, 'SetSettingsState', alteredState)
# Get settings again
newState = display_settings.DisplaySettingsBus(bus.Broadcast, 'GetSettingsState')
# Check if the setter worked
if alteredState.no_collision == newState.no_collision and \
alteredState.no_labels == newState.no_labels and \
alteredState.simulate == newState.simulate and \
alteredState.hide_tracks == newState.hide_tracks and \
alteredState.hide_links == newState.hide_links and \
alteredState.hide_helpers == newState.hide_helpers and \
alteredState.show_dimension_figures == newState.show_dimension_figures:
print("display settings were changed correctly")
# Restore previous settings
display_settings.DisplaySettingsBus(bus.Broadcast, 'SetSettingsState', existingState)
editor.EditorToolsApplicationRequestBus(bus.Broadcast, 'ExitNoPrompt')
@@ -0,0 +1,38 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
#
# This is a pytest module to test the in-Editor Python API from ViewPane.h
#
import pytest
pytest.importorskip('ly_test_tools')
import sys
import os
sys.path.append(os.path.dirname(__file__))
from hydra_utils import launch_test_case
@pytest.mark.SUITE_sandbox
@pytest.mark.parametrize('launcher_platform', ['windows_editor'])
@pytest.mark.parametrize('project', ['AutomatedTesting'])
@pytest.mark.parametrize('level', ['Simple'])
class TestDisplaySettingsAutomation(object):
def test_DisplaySettings(self, request, editor, level, launcher_platform):
unexpected_lines=[]
expected_lines = [
"display settings were changed correctly"
]
test_case_file = os.path.join(os.path.dirname(__file__), 'DisplaySettingsCommands_test_case.py')
launch_test_case(editor, test_case_file, expected_lines, unexpected_lines)
@@ -0,0 +1,37 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
# Tests the Python API from DisplaySettingsPythonFuncs.cpp while the Editor is running
import azlmbr.bus as bus
import azlmbr.editor as editor
import azlmbr.legacy.settings as settings
# Retrieve current settings
existingSettings = settings.get_misc_editor_settings()
# Alter settings
alteredSettings = existingSettings + 12
# Set altered settings
settings.set_misc_editor_settings(alteredSettings)
# Get settings again
newSettings = settings.get_misc_editor_settings()
# Check if the setter worked
if(alteredSettings == newSettings):
print("display settings were changed correctly")
# Restore previous settings
settings.set_misc_editor_settings(existingSettings)
editor.EditorToolsApplicationRequestBus(bus.Broadcast, 'ExitNoPrompt')
@@ -0,0 +1,55 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
#
# This is a pytest module to test the in-Editor Python API from PythonEditorFuncs
#
import pytest
pytest.importorskip('ly_test_tools')
import sys
import os
sys.path.append(os.path.dirname(__file__))
from hydra_utils import launch_test_case, launch_test_case_with_args
@pytest.mark.SUITE_sandbox
@pytest.mark.parametrize('launcher_platform', ['windows_editor'])
@pytest.mark.parametrize('project', ['AutomatedTesting'])
@pytest.mark.parametrize('level', ['Simple'])
class TestEditorAutomation(object):
def test_EditorNoArgs(self, request, editor, level, launcher_platform):
unexpected_lines=[]
expected_lines = [
"editor command line works",
]
test_case_file = os.path.join(os.path.dirname(__file__), 'EditorCommandLine_test_case.py')
launch_test_case(editor, test_case_file, expected_lines, unexpected_lines)
def test_EditorWithArgs(self, request, editor, level, launcher_platform):
unexpected_lines=[]
expected_lines = [
"editor command line works",
"editor command line arg foo",
"editor command line arg bar",
"editor command line arg baz",
"editor engroot set",
"editor devroot set",
"path resolved worked"
]
extra_args = ['foo bar baz']
test_case_file = os.path.join(os.path.dirname(__file__), 'EditorCommandLine_test_case.py')
launch_test_case_with_args(editor, test_case_file, expected_lines, unexpected_lines, extra_args)
@@ -0,0 +1,39 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
import sys
import azlmbr.bus as bus
import azlmbr.editor as editor
print ('editor command line works')
for x in range(len(sys.argv)):
print ('editor command line arg {}'.format(sys.argv[x]))
# make sure the @engroot@ exists as a azlmbr.paths property
engroot = azlmbr.paths.engroot
if (engroot is not None and len(engroot) is not 0):
print ('engroot is {}'.format(engroot))
print ('editor engroot set')
# make sure the @devroot@ exists as a azlmbr.paths property
devroot = azlmbr.paths.devroot
if (devroot is not None and len(devroot) != 0):
print ('devroot is {}'.format(devroot))
print ('editor devroot set')
# resolving a basic path
path = azlmbr.paths.resolve_path('@engroot@/engineassets/texturemsg/defaultsolids.mtl')
if (len(path) != 0 and path.find('@engroot@') == -1):
print ('path resolved to {}'.format(path))
print ('path resolved worked')
editor.EditorToolsApplicationRequestBus(bus.Broadcast, 'ExitNoPrompt')
@@ -0,0 +1,82 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
# Tests the Python API from PythonEditorFuncs.cpp while the Editor is running
import azlmbr.bus as bus
import azlmbr.editor as editor
import azlmbr.legacy.general as general
import azlmbr.globals
import math
def testing_cvar(setMethod, methodName, label, value, compare):
try:
setMethod(label, value)
test_value = general.get_cvar(label)
if(compare(test_value, value)):
print('{} worked'.format(methodName))
except:
print('{} failed'.format(methodName))
def testing_edit_mode(mode):
general.set_edit_mode(mode)
if (general.get_edit_mode(mode)):
return True
return False
def testing_axis_constraints(constraint):
general.set_axis_constraint(constraint)
if (general.get_axis_constraint(constraint)):
return True
return False
# ----- Test cvar
compare = lambda lhs, rhs: rhs == float(lhs)
testing_cvar(general.set_cvar_float, 'set_cvar_float', 'sys_LocalMemoryOuterViewDistance', 501.0, compare)
compare = lambda lhs, rhs: rhs == lhs
testing_cvar(general.set_cvar_string, 'set_cvar_string', 'e_ScreenShotFileFormat', 'jpg', compare)
compare = lambda lhs, rhs: rhs == int(lhs)
testing_cvar(general.set_cvar_integer, 'set_cvar_integer', 'sys_LocalMemoryGeometryLimit', 33, compare)
# ----- Test Edit Mode
if (testing_edit_mode("SELECT") and testing_edit_mode('SELECTAREA') and
testing_edit_mode("MOVE") and testing_edit_mode("ROTATE") and
testing_edit_mode("SCALE") and testing_edit_mode("TOOL")):
print("edit mode works")
# ----- Test Axis Constraints
if (testing_axis_constraints("X") and testing_axis_constraints("Y") and
testing_axis_constraints("Z") and testing_axis_constraints("XY") and
testing_axis_constraints("XZ") and testing_axis_constraints("YZ") and
testing_axis_constraints("XYZ") and testing_axis_constraints("TERRAIN") and
testing_axis_constraints("TERRAINSNAP")):
print("axis constraint works")
print("end of editor utility tests")
editor.EditorToolsApplicationRequestBus(bus.Broadcast, 'ExitNoPrompt')
@@ -0,0 +1,57 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
#
# This is a pytest module to test the in-Editor Python API from PythonEditorFuncs
#
import pytest
pytest.importorskip('ly_test_tools')
import sys
import os
sys.path.append(os.path.dirname(__file__))
from hydra_utils import launch_test_case
@pytest.mark.SUITE_sandbox
@pytest.mark.parametrize('launcher_platform', ['windows_editor'])
@pytest.mark.parametrize('project', ['AutomatedTesting'])
@pytest.mark.parametrize('level', ['Simple'])
class TestEditorAutomation(object):
def test_Editor(self, request, editor, level, launcher_platform):
unexpected_lines = []
expected_lines = [
"SetCVarFromFloat worked",
"SetCVarFromString worked",
"SetCVarFromInteger worked",
"edit mode works",
"axis constraint works",
"end of editor utility tests"
]
test_case_file = os.path.join(os.path.dirname(__file__), 'EditorUtilityCommands_test_case.py')
launch_test_case(editor, test_case_file, expected_lines, unexpected_lines)
def test_Legacy_Editor(self, request, editor, level, launcher_platform):
unexpected_lines=[]
expected_lines = [
"set_cvar_float worked",
"set_cvar_string worked",
"set_cvar_integer worked",
"edit mode works",
"axis constraint works",
"end of editor utility tests"
]
test_case_file = os.path.join(os.path.dirname(__file__), 'EditorUtilityCommands_legacy_test_case.py')
launch_test_case(editor, test_case_file, expected_lines, unexpected_lines)
@@ -0,0 +1,81 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
# Tests the Python API from PythonEditorFuncs.cpp while the Editor is running
import azlmbr.bus as bus
import azlmbr.editor as editor
import azlmbr.python_editor_funcs as python_editor_funcs
import azlmbr.globals
import math
def testing_cvar(setMethod, methodName, label, value, compare):
try:
python_editor_funcs.PythonEditorBus(bus.Broadcast, setMethod, label, value)
test_value = python_editor_funcs.PythonEditorBus(bus.Broadcast, 'GetCVar', label)
if compare(test_value, value):
print('{} worked'.format(methodName))
except:
print('{} failed'.format(methodName))
def testing_edit_mode(mode):
python_editor_funcs.PythonEditorBus(bus.Broadcast, 'SetEditMode', mode)
if mode == python_editor_funcs.PythonEditorBus(bus.Broadcast, 'GetEditMode'):
return True
return False
def testing_axis_constraints(constraint):
python_editor_funcs.PythonEditorBus(bus.Broadcast, 'SetAxisConstraint', constraint)
if constraint == python_editor_funcs.PythonEditorBus(bus.Broadcast, 'GetAxisConstraint'):
return True
return False
# ----- Test cvar
compare = lambda lhs, rhs: rhs == float(lhs)
testing_cvar('SetCVarFromFloat', 'SetCVarFromFloat', 'sys_LocalMemoryOuterViewDistance', 501.0, compare)
compare = lambda lhs, rhs: rhs == lhs
testing_cvar('SetCVarFromString', 'SetCVarFromString', 'e_ScreenShotFileFormat', 'jpg', compare)
compare = lambda lhs, rhs: rhs == int(lhs)
testing_cvar('SetCVarFromInteger', 'SetCVarFromInteger', 'sys_LocalMemoryGeometryLimit', 33, compare)
# ----- Test Edit Mode
if (testing_edit_mode("SELECT") and testing_edit_mode('SELECTAREA') and
testing_edit_mode("MOVE") and testing_edit_mode("ROTATE") and
testing_edit_mode("SCALE") and testing_edit_mode("TOOL")):
print("edit mode works")
# ----- Test Axis Constraints
if (testing_axis_constraints("X") and testing_axis_constraints("Y") and
testing_axis_constraints("Z") and testing_axis_constraints("XY") and
testing_axis_constraints("XZ") and testing_axis_constraints("YZ") and
testing_axis_constraints("XYZ") and testing_axis_constraints("TERRAIN") and
testing_axis_constraints("TERRAINSNAP")):
print("axis constraint works")
# ----- End
print("end of editor utility tests")
editor.EditorToolsApplicationRequestBus(bus.Broadcast, 'ExitNoPrompt')
@@ -0,0 +1,40 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
#
# This is a pytest module to test the in-Editor Python API from PythonEditorFuncs
#
import pytest
pytest.importorskip('ly_test_tools')
import sys
import os
sys.path.append(os.path.dirname(__file__))
from hydra_utils import launch_test_case
@pytest.mark.SUITE_sandbox
@pytest.mark.parametrize('launcher_platform', ['windows_editor'])
@pytest.mark.parametrize('project', ['AutomatedTesting'])
@pytest.mark.parametrize('level', ['Simple'])
class TestEditorViewAutomation(object):
def test_EditorView(self, request, editor, level, launcher_platform):
unexpected_lines=[]
expected_lines = [
"set_current_view_position works",
"set_current_view_rotation works"
]
test_case_file = os.path.join(os.path.dirname(__file__), 'EditorViewCommands_test_case.py')
launch_test_case(editor, test_case_file, expected_lines, unexpected_lines)
@@ -0,0 +1,54 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
# Tests a portion of the Editor View Python API from CryEdit.cpp while the Editor is running
import azlmbr.bus as bus
import azlmbr.editor as editor
import azlmbr.math
import azlmbr.legacy.general as general
def fetch_vector3_parts(vec3):
x = vec3.get_property('x')
y = vec3.get_property('y')
z = vec3.get_property('z')
return (x, y, z)
pos = general.get_current_view_position()
rot = general.get_current_view_rotation()
px, py, pz = fetch_vector3_parts(pos)
rx, ry, rz = fetch_vector3_parts(rot)
px = px + 5.0
py = py - 2.0
pz = pz + 1.0
rx = rx + 2.0
ry = ry + 3.0
rz = rz - 5.0
general.set_current_view_position(px, py, pz)
general.set_current_view_rotation(rx, ry, rz)
pos2 = general.get_current_view_position()
rot2 = general.get_current_view_rotation()
p2x, p2y, p2z = fetch_vector3_parts(pos2)
r2x, r2y, r2z = fetch_vector3_parts(rot2)
if not (px == p2x) and not (py == p2y) and not (pz == p2z):
print("set_current_view_position works")
if not (rx == r2x) and not (ry == r2y) and not (rz == r2z):
print("set_current_view_rotation works")
editor.EditorToolsApplicationRequestBus(bus.Broadcast, 'ExitNoPrompt')
@@ -0,0 +1,55 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
#
# This is a pytest module to test the in-Editor Python API for Entity CRUD
#
import pytest
pytest.importorskip('ly_test_tools')
import sys
import os
sys.path.append(os.path.dirname(__file__))
from hydra_utils import launch_test_case
@pytest.mark.SUITE_sandbox
@pytest.mark.parametrize('launcher_platform', ['windows_editor'])
@pytest.mark.parametrize('project', ['AutomatedTesting'])
@pytest.mark.parametrize('level', ['Simple'])
class TestEntityCRUDCommandsAutomation(object):
def test_EntityCRUDCommands(self, request, editor, level, launcher_platform):
unexpected_lines=[]
expected_lines = [
"childEntity is parented to the Root",
"childEntity is now parented to the parentEntity",
"parentEntityId isn't locked",
"parentEntityId is now locked",
"childEntityId is now locked too",
"parentEntityId is visible",
"parentEntityId isn't hidden",
"parentEntityId is now hidden",
"childEntityId is now hidden too",
"parentEntityId isn't set to Editor Only",
"parentEntityId is now set to Editor Only",
"childEntityId does not inherit Editor Only",
"parentEntityId isn't set to Start Inactive",
"parentEntityId is now set to Start Inactive",
"childEntityId does not inherit Start Inactive",
"parentEntityId isn't set to Start Active",
"parentEntityId is now set to Start Active",
"childEntityId should still be set to Start Active by default"
]
test_case_file = os.path.join(os.path.dirname(__file__), 'EntityCRUDCommands_test_case.py')
launch_test_case(editor, test_case_file, expected_lines, unexpected_lines)
@@ -0,0 +1,134 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
# Tests a portion of the Entity CRUD Python API while the Editor is running
import azlmbr.bus as bus
import azlmbr.editor as editor
from azlmbr.entity import EntityId
# Open a level (any level should work)
editor.EditorToolsApplicationRequestBus(bus.Broadcast, 'OpenLevelNoPrompt', 'WaterSample')
parentEntityId = editor.ToolsApplicationRequestBus(bus.Broadcast, 'CreateNewEntity', EntityId())
childEntityId = editor.ToolsApplicationRequestBus(bus.Broadcast, 'CreateNewEntity', EntityId())
# Test SetParent/GetParent
queryParent = editor.EditorEntityInfoRequestBus(bus.Event, 'GetParent', childEntityId)
if(queryParent.ToString() == EntityId().ToString()):
print("childEntity is parented to the Root")
editor.EditorEntityAPIBus(bus.Event, 'SetParent', childEntityId, parentEntityId)
queryParent = editor.EditorEntityInfoRequestBus(bus.Event, 'GetParent', childEntityId)
if(queryParent.ToString() == parentEntityId.ToString()):
print("childEntity is now parented to the parentEntity")
# Test SetLockState and IsLocked
queryLock = editor.EditorEntityInfoRequestBus(bus.Event, 'IsLocked', parentEntityId)
if(queryLock == False):
print("parentEntityId isn't locked")
editor.EditorEntityAPIBus(bus.Event, 'SetLockState', parentEntityId, True)
queryLock = editor.EditorEntityInfoRequestBus(bus.Event, 'IsLocked', parentEntityId)
if(queryLock == True):
print("parentEntityId is now locked")
queryLock = editor.EditorEntityInfoRequestBus(bus.Event, 'IsLocked', childEntityId)
if(queryLock == True):
print("childEntityId is now locked too")
# Test SetVisibilityState, IsVisible and IsHidden
queryVisibility = editor.EditorEntityInfoRequestBus(bus.Event, 'IsVisible', parentEntityId)
if(queryVisibility == True):
print("parentEntityId is visible")
queryHidden = editor.EditorEntityInfoRequestBus(bus.Event, 'IsHidden', parentEntityId)
if(queryHidden == False):
print("parentEntityId isn't hidden")
editor.EditorEntityAPIBus(bus.Event, 'SetVisibilityState', parentEntityId, False)
queryVisibility = editor.EditorEntityInfoRequestBus(bus.Event, 'IsVisible', parentEntityId)
if(queryVisibility == False):
print("parentEntityId is now hidden")
queryVisibility = editor.EditorEntityInfoRequestBus(bus.Event, 'IsVisible', childEntityId)
if(queryVisibility == False):
print("childEntityId is now hidden too")
# Test EditorOnly
queryStatus = editor.EditorEntityInfoRequestBus(bus.Event, 'GetStartStatus', parentEntityId)
print("EditorOnly before queryStatus: " + str(queryStatus))
if not(queryStatus == azlmbr.globals.property.EditorEntityStartStatus_EditorOnly):
print("parentEntityId isn't set to Editor Only")
editor.EditorEntityAPIBus(bus.Event, 'SetStartStatus', parentEntityId, azlmbr.globals.property.EditorEntityStartStatus_EditorOnly)
queryStatus = editor.EditorEntityInfoRequestBus(bus.Event, 'GetStartStatus', parentEntityId)
print("EditorOnly after queryStatus: " + str(queryStatus))
if (queryStatus == azlmbr.globals.property.EditorEntityStartStatus_EditorOnly):
print("parentEntityId is now set to Editor Only")
queryStatus = editor.EditorEntityInfoRequestBus(bus.Event, 'GetStartStatus', childEntityId)
if not(queryStatus == azlmbr.globals.property.EditorEntityStartStatus_EditorOnly):
print("childEntityId does not inherit Editor Only")
# Test StartInactive
queryStatus = editor.EditorEntityInfoRequestBus(bus.Event, 'GetStartStatus', parentEntityId)
print("queryStatus: " + str(queryStatus))
if not(queryStatus == azlmbr.globals.property.EditorEntityStartStatus_StartInactive):
print("parentEntityId isn't set to Start Inactive")
editor.EditorEntityAPIBus(bus.Event, 'SetStartStatus', parentEntityId, azlmbr.globals.property.EditorEntityStartStatus_StartInactive)
queryStatus = editor.EditorEntityInfoRequestBus(bus.Event, 'GetStartStatus', parentEntityId)
if (queryStatus == azlmbr.globals.property.EditorEntityStartStatus_StartInactive):
print("parentEntityId is now set to Start Inactive")
queryStatus = editor.EditorEntityInfoRequestBus(bus.Event, 'GetStartStatus', childEntityId)
if not(queryStatus == azlmbr.globals.property.EditorEntityStartStatus_StartInactive):
print("childEntityId does not inherit Start Inactive")
# Test StartActive
queryStatus = editor.EditorEntityInfoRequestBus(bus.Event, 'GetStartStatus', parentEntityId)
print("queryStatus: " + str(queryStatus))
if not(queryStatus == azlmbr.globals.property.EditorEntityStartStatus_StartActive):
print("parentEntityId isn't set to Start Active")
editor.EditorEntityAPIBus(bus.Event, 'SetStartStatus', parentEntityId, azlmbr.globals.property.EditorEntityStartStatus_StartActive)
queryStatus = editor.EditorEntityInfoRequestBus(bus.Event, 'GetStartStatus', parentEntityId)
if (queryStatus == azlmbr.globals.property.EditorEntityStartStatus_StartActive):
print("parentEntityId is now set to Start Active")
queryStatus = editor.EditorEntityInfoRequestBus(bus.Event, 'GetStartStatus', childEntityId)
if (queryStatus == azlmbr.globals.property.EditorEntityStartStatus_StartActive):
print("childEntityId should still be set to Start Active by default")
editor.EditorToolsApplicationRequestBus(bus.Broadcast, 'ExitNoPrompt')
@@ -0,0 +1,49 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
#
# This is a pytest module to test the in-Editor Python API for Entity CRUD
#
import pytest
pytest.importorskip('ly_test_tools')
import sys
import os
sys.path.append(os.path.dirname(__file__))
from hydra_utils import launch_test_case
@pytest.mark.SUITE_sandbox
@pytest.mark.parametrize('launcher_platform', ['windows_editor'])
@pytest.mark.parametrize('project', ['AutomatedTesting'])
@pytest.mark.parametrize('level', ['Simple'])
class TestEntityCommandsAutomation(object):
def test_EntityCommands(self, request, editor, level, launcher_platform):
unexpected_lines=[]
expected_lines = [
"New entity with no parent created",
"New root entity matches entity received from notification",
"New entity with valid parent created",
"First child entity matches entity received from notification",
"Another new entity with valid parent created",
"Second child entity matches entity received from notification",
"Deleted all entities we created",
"GetName and SetName work",
"GetParent works",
"TestName entity found",
"TestChild entity found",
"Test* 3 entities found"
]
test_case_file = os.path.join(os.path.dirname(__file__), 'EntityCommands_test_case.py')
launch_test_case(editor, test_case_file, expected_lines, unexpected_lines)
@@ -0,0 +1,152 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
# Tests the Python API for Entity CRUD while the Editor is running
import azlmbr.bus as bus
import azlmbr.editor as editor
from azlmbr.entity import EntityId
createdEntityIds = []
def onEditorEntityCreated(parameters):
global createdEntityIds
entityId = parameters[0]
createdEntityIds.append(entityId)
def onEditorEntityDeleted(parameters):
global createdEntityIds
deletedEntityId = parameters[0]
for entityId in createdEntityIds:
if (entityId.invoke("Equal", deletedEntityId)):
createdEntityIds.remove(entityId)
break
# Open a level (any level should work)
editor.EditorToolsApplicationRequestBus(bus.Broadcast, 'OpenLevelNoPrompt', 'WaterSample')
# Listen for notifications when entities are created/deleted
handler = bus.NotificationHandler('EditorEntityContextNotificationBus')
handler.connect()
handler.add_callback('OnEditorEntityCreated', onEditorEntityCreated)
handler.add_callback('OnEditorEntityDeleted', onEditorEntityDeleted)
# Create a new Entity at the root level
rootEntityId = editor.ToolsApplicationRequestBus(bus.Broadcast, 'CreateNewEntity', EntityId())
if (rootEntityId):
print("New entity with no parent created")
if (rootEntityId.invoke("Equal", createdEntityIds[0])):
print("New root entity matches entity received from notification")
# Create a new Entity parented to the first Entity we created
firstChildEntityId = editor.ToolsApplicationRequestBus(bus.Broadcast, 'CreateNewEntity', rootEntityId)
if (firstChildEntityId):
print("New entity with valid parent created")
if (firstChildEntityId.invoke("Equal", createdEntityIds[1])):
print("First child entity matches entity received from notification")
# Create another Entity parented to the first Entity we created
secondChildEntityId = editor.ToolsApplicationRequestBus(bus.Broadcast, 'CreateNewEntity', rootEntityId)
if (secondChildEntityId):
print("Another new entity with valid parent created")
if (secondChildEntityId.invoke("Equal", createdEntityIds[2])):
print("Second child entity matches entity received from notification")
# Create two more entities and then delete them using the API that takes a list instead of a single entity
thirdChildEntityId = editor.ToolsApplicationRequestBus(bus.Broadcast, 'CreateNewEntity', secondChildEntityId)
fourthChildEntityId = editor.ToolsApplicationRequestBus(bus.Broadcast, 'CreateNewEntity', secondChildEntityId)
editor.ToolsApplicationRequestBus(bus.Broadcast, 'DeleteEntities', [thirdChildEntityId, fourthChildEntityId])
# Delete the second child Entity we created
editor.ToolsApplicationRequestBus(bus.Broadcast, 'DeleteEntityById', secondChildEntityId)
# Delete the root Entity we created and all its children (so this should also delete the firstChildEntityId)
editor.ToolsApplicationRequestBus(bus.Broadcast, 'DeleteEntityAndAllDescendants', rootEntityId)
# There should be no more entities left that we created
if (len(createdEntityIds) == 0):
print("Deleted all entities we created")
# Stop listening for entity creation/deletion notifications
handler.disconnect()
# Create new Entity
entityId = editor.ToolsApplicationRequestBus(bus.Broadcast, 'CreateNewEntity', EntityId())
# Get current name
oldName = editor.EditorEntityInfoRequestBus(bus.Event, 'GetName', entityId);
# Set a new name
editor.EditorEntityAPIBus(bus.Event, 'SetName', entityId, "TestName")
# Get new name
newName = editor.EditorEntityInfoRequestBus(bus.Event, 'GetName', entityId);
if not(oldName == newName):
print("GetName and SetName work")
# Create new Entity
parentId = editor.ToolsApplicationRequestBus(bus.Broadcast, 'CreateNewEntity', EntityId())
# Create new Entity with parentId as parent
childId = editor.ToolsApplicationRequestBus(bus.Broadcast, 'CreateNewEntity', parentId)
getId = editor.EditorEntityInfoRequestBus(bus.Event, 'GetParent', childId);
if(getId.Equal(parentId)):
print("GetParent works")
# Find the entity in the scene
import azlmbr.bus as bus
import azlmbr.entity
searchFilter = azlmbr.entity.SearchFilter()
searchFilter.names = ['TestName']
# Search by name
searchEntityIdList = azlmbr.entity.SearchBus(bus.Broadcast, 'SearchEntities', searchFilter)
for entityId in searchEntityIdList:
entityName = editor.EditorEntityInfoRequestBus(bus.Event, 'GetName', entityId)
if(entityName == 'TestName'):
print("TestName entity found")
# Search by name path (DAG)
editor.EditorEntityAPIBus(bus.Event, 'SetName', parentId, "TestParent")
editor.EditorEntityAPIBus(bus.Event, 'SetName', childId, "TestChild")
searchFilter = azlmbr.entity.SearchFilter()
searchFilter.names = ['TestParent|TestChild']
searchEntityIdList = azlmbr.entity.SearchBus(bus.Broadcast, 'SearchEntities', searchFilter)
for entityId in searchEntityIdList:
entityName = editor.EditorEntityInfoRequestBus(bus.Event, 'GetName', entityId)
if(entityName == 'TestChild'):
print("TestChild entity found")
# Search using wildcard
searchFilter = azlmbr.entity.SearchFilter()
searchFilter.names = ['Test*']
searchEntityIdList = azlmbr.entity.SearchBus(bus.Broadcast, 'SearchEntities', searchFilter)
if(len(searchEntityIdList) == 3):
print("Test* 3 entities found")
# Close Editor
editor.EditorToolsApplicationRequestBus(bus.Broadcast, 'ExitNoPrompt')
@@ -0,0 +1,81 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
#
# This is a pytest module to test the in-Editor Python API for Entity Search
#
import pytest
pytest.importorskip('ly_test_tools')
import sys
import os
sys.path.append(os.path.dirname(__file__))
from hydra_utils import launch_test_case
@pytest.mark.SUITE_sandbox
@pytest.mark.parametrize('launcher_platform', ['windows_editor'])
@pytest.mark.parametrize('project', ['AutomatedTesting'])
@pytest.mark.parametrize('level', ['Simple'])
class TestEntitySearchAutomation(object):
def test_EntitySearch(self, request, editor, level, launcher_platform):
unexpected_lines=[]
expected_lines = [
"SUCCESS: Root Entities",
"SUCCESS: No filters - return all entities",
"SUCCESS: Filter by name - single entity",
"SUCCESS: Filter by name - multiple entities",
"SUCCESS: Filter by name - multiple names",
"SUCCESS: Filter by name - wildcard 01",
"SUCCESS: Filter by name - wildcard 02",
"SUCCESS: Filter by name - wildcard 03",
"SUCCESS: Filter by name - wildcard 04",
"SUCCESS: Filter by name - wildcard 05",
"SUCCESS: Filter by name - case sensitive 01",
"SUCCESS: Filter by name - case sensitive 02",
"SUCCESS: Filter by name - case sensitive 03",
"SUCCESS: Filter by name - case sensitive 04",
"SUCCESS: Filter by path - base 01",
"SUCCESS: Filter by path - base 02",
"SUCCESS: Filter by path - wildcard 01",
"SUCCESS: Filter by path - wildcard 02",
"SUCCESS: Filter by path - wildcard 03",
"SUCCESS: Filter by path - wildcard 04",
"SUCCESS: Filter by path - case sensitive 01",
"SUCCESS: Filter by path - case sensitive 02",
"SUCCESS: Filter by path - case sensitive 03",
"SUCCESS: Filter by path - case sensitive 04",
"SUCCESS: Filter by component - base 01",
"SUCCESS: Filter by component - base 02",
"SUCCESS: Filter by component - multiple 01",
"SUCCESS: Filter by component - multiple 02",
"SUCCESS: Filter with roots - base 01",
"SUCCESS: Filter with roots - base 02",
"SUCCESS: Filter with roots - base 03",
"SUCCESS: Filter with roots - base 04",
"SUCCESS: Filter with roots - base 05",
"SUCCESS: Filter with roots - NameIsRootBased 01",
"SUCCESS: Filter with roots - NameIsRootBased 02",
"SUCCESS: Filter with roots - NameIsRootBased 03",
"SUCCESS: Filter with roots - NameIsRootBased 04",
"SUCCESS: Filter with roots - NameIsRootBased 05",
"SUCCESS: Search with Multiple Filters",
"SUCCESS: Filter by AABB - base 01",
"SUCCESS: Filter by AABB - base 02",
"SUCCESS: Filter by Component Properties - base 01",
"SUCCESS: Filter by Component Properties - base 02",
"SUCCESS: Filter by Component Properties - base 03"
]
test_case_file = os.path.join(os.path.dirname(__file__), 'EntitySearchCommands_test_case.py')
launch_test_case(editor, test_case_file, expected_lines, unexpected_lines)
@@ -0,0 +1,408 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
# Tests the Entity Search Python API while the Editor is running
import azlmbr.editor as editor
import azlmbr.entity as entity
import azlmbr.bus as bus
import azlmbr.math as math
import azlmbr.components as components
# Open a level (any level should work)
editor.EditorToolsApplicationRequestBus(bus.Broadcast, 'OpenLevelNoPrompt', 'WaterSample')
# Save Root Entities and Total Entity number
root = entity.SearchBus(bus.Broadcast, 'GetRootEditorEntities')
rootNum = len(root)
all = entity.SearchBus(bus.Broadcast, 'SearchEntities', entity.SearchFilter())
allNum = len(all)
# Create Hierarchy
#
# City
# |_ Street (2)
# |_ Car
# | |_ Passenger (1, 2)
# | |_ Passenger
# |_ Car (1)
# | |_ Passenger
# |_ SportsCar
# |_ Passenger (2)
# |_ Passenger
#
def CreateEntity(name, parentId):
newEntityId = editor.ToolsApplicationRequestBus(bus.Broadcast, 'CreateNewEntity', parentId)
editor.EditorEntityAPIBus(bus.Event, 'SetName', newEntityId, name)
testName = editor.EditorEntityInfoRequestBus(bus.Event, 'GetName', newEntityId)
if (testName != name):
print("FAILURE: testName {} does not equal set name {}".format(testName, name))
return newEntityId
# Entities
cityId = CreateEntity('City', entity.EntityId())
streetId = CreateEntity('Street', cityId)
carId1 = CreateEntity('Car', streetId)
passengerId1 = CreateEntity('Passenger', carId1)
passengerId2 = CreateEntity('Passenger', carId1)
carId2 = CreateEntity('Car', streetId)
passengerId3 = CreateEntity('Passenger', carId2)
sportsCarId = CreateEntity('SportsCar', streetId)
passengerId4 = CreateEntity('Passenger', sportsCarId)
passengerId5 = CreateEntity('Passenger', sportsCarId)
# Components
typeIdsList = editor.EditorComponentAPIBus(bus.Broadcast, 'FindComponentTypeIdsByEntityType', ["Comment", "Actor"], entity.EntityType().Game)
editor.EditorComponentAPIBus(bus.Broadcast, 'AddComponentsOfType', passengerId1, [typeIdsList[0]])
editor.EditorComponentAPIBus(bus.Broadcast, 'AddComponentsOfType', carId2, [typeIdsList[0]])
editor.EditorComponentAPIBus(bus.Broadcast, 'AddComponentsOfType', streetId, [typeIdsList[1]])
editor.EditorComponentAPIBus(bus.Broadcast, 'AddComponentsOfType', passengerId1, [typeIdsList[1]])
editor.EditorComponentAPIBus(bus.Broadcast, 'AddComponentsOfType', passengerId4, [typeIdsList[1]])
# Test the Entity Search API
def CompareEntityIds(id1, id2):
return (id1.ToString() == id2.ToString())
def SearchResultCheck(searchFilter, testName, resultId):
entities = entity.SearchBus(bus.Broadcast, 'SearchEntities', searchFilter)
if(len(entities) == 1) and (CompareEntityIds(entities[0], resultId)):
print("SUCCESS: " + testName)
else:
print("FAILURE: " + testName)
def SearchResultsCheck(searchFilter, testName, resultSize):
entities = entity.SearchBus(bus.Broadcast, 'SearchEntities', searchFilter)
if(len(entities) == resultSize):
print("SUCCESS: " + testName)
else:
print("FAILURE: " + testName + " (size is " + str(len(entities)) + ", should be " + str(resultSize) + ")")
# Get Root Entities
rootEntities = entity.SearchBus(bus.Broadcast, 'GetRootEditorEntities')
if(len(rootEntities) == 1 + rootNum):
print("SUCCESS: Root Entities")
else:
print("FAILURE: Root Entities")
# Search by Name - Base
# No filters - return all entities
searchFilter1 = entity.SearchFilter()
SearchResultsCheck(searchFilter1, "No filters - return all entities", (10 + allNum))
# Filter by name - single entity
searchFilter2 = entity.SearchFilter()
searchFilter2.names = ["Street"]
SearchResultCheck(searchFilter2, "Filter by name - single entity", streetId)
# Filter by name - multiple entities
searchFilter3 = entity.SearchFilter()
searchFilter3.names = ["Passenger"]
SearchResultsCheck(searchFilter3, "Filter by name - multiple entities", 5)
# Filter by name - multiple names
searchFilter4 = entity.SearchFilter()
searchFilter4.names = ["Passenger", "Street"]
SearchResultsCheck(searchFilter4, "Filter by name - multiple names", 6)
# Search by Name - Wildcard
# Filter by name - wildcard 01
searchFilter5 = entity.SearchFilter()
searchFilter5.names = ["Str*et"]
SearchResultCheck(searchFilter5, "Filter by name - wildcard 01", streetId)
# Filter by name - wildcard 02
searchFilter6 = entity.SearchFilter()
searchFilter6.names = ["St*et"]
SearchResultCheck(searchFilter6, "Filter by name - wildcard 02", streetId)
# Filter by name - wildcard 03
searchFilter7 = entity.SearchFilter()
searchFilter7.names = ["Str?et"]
SearchResultCheck(searchFilter7, "Filter by name - wildcard 03", streetId)
# Filter by name - wildcard 04
searchFilter8 = entity.SearchFilter()
searchFilter8.names = ["Str?t"]
SearchResultsCheck(searchFilter8, "Filter by name - wildcard 04", 0)
# Filter by name - wildcard 05
searchFilter10 = entity.SearchFilter()
searchFilter10.names = ["*"]
SearchResultsCheck(searchFilter10, "Filter by name - wildcard 05", (10 + allNum))
# Search by Name - Case Sensitive
# Filter by name - case sensitive 01
searchFilter11 = entity.SearchFilter()
searchFilter11.names = ["Street"]
searchFilter11.names_case_sensitive = False # default
SearchResultCheck(searchFilter11, "Filter by name - case sensitive 01", streetId)
# Filter by name - case sensitive 02
searchFilter12 = entity.SearchFilter()
searchFilter12.names = ["street"]
searchFilter12.names_case_sensitive = False
SearchResultCheck(searchFilter12, "Filter by name - case sensitive 02", streetId)
# Filter by name - case sensitive 03
searchFilter13 = entity.SearchFilter()
searchFilter13.names = ["Street"]
searchFilter13.names_case_sensitive = True
SearchResultCheck(searchFilter13, "Filter by name - case sensitive 03", streetId)
# Filter by name - case sensitive 04
searchFilter14 = entity.SearchFilter()
searchFilter14.names = ["street"]
searchFilter14.names_case_sensitive = True # default
SearchResultsCheck(searchFilter14, "Filter by name - case sensitive 04", 0)
# Search by Path - Base
# Filter by path - base 01
searchFilter15 = entity.SearchFilter()
searchFilter15.names = ["City|Street|SportsCar"]
SearchResultCheck(searchFilter15, "Filter by path - base 01", sportsCarId)
# Filter by path - base 02
searchFilter16 = entity.SearchFilter()
searchFilter16.names = ["City|Street|Car|Passenger"]
SearchResultsCheck(searchFilter16, "Filter by path - base 02", 3)
# Search by Path - Wildcard
# Filter by path - wildcard 01
searchFilter17 = entity.SearchFilter()
searchFilter17.names = ["City|*|SportsCar"]
SearchResultCheck(searchFilter17, "Filter by path - wildcard 01", sportsCarId)
# Filter by path - wildcard 02
searchFilter18 = entity.SearchFilter()
searchFilter18.names = ["City|Street|*|Passenger"]
SearchResultsCheck(searchFilter18, "Filter by path - wildcard 02", 5)
# Filter by path - wildcard 03
searchFilter19 = entity.SearchFilter()
searchFilter19.names = ["City|Street|*Car|Passenger"]
SearchResultsCheck(searchFilter19, "Filter by path - wildcard 03", 5)
# Filter by path - wildcard 04
searchFilter20 = entity.SearchFilter()
searchFilter20.names = ["City|Street|Sport*|Passenger"]
SearchResultsCheck(searchFilter20, "Filter by path - wildcard 04", 2)
# Search by Path - Case Sensitive
# Filter by path - case sensitive 01
searchFilter21 = entity.SearchFilter()
searchFilter21.names = ["City|Street"]
searchFilter21.names_case_sensitive = False # default
SearchResultCheck(searchFilter21, "Filter by path - case sensitive 01", streetId)
# Filter by path - case sensitive 02
searchFilter22 = entity.SearchFilter()
searchFilter22.names = ["city|street"]
searchFilter22.names_case_sensitive = False # default
SearchResultCheck(searchFilter22, "Filter by path - case sensitive 02", streetId)
# Filter by path - case sensitive 03
searchFilter23 = entity.SearchFilter()
searchFilter23.names = ["City|Street"]
searchFilter23.names_case_sensitive = True
SearchResultCheck(searchFilter23, "Filter by path - case sensitive 03", streetId)
# Filter by path - case sensitive 04
searchFilter24 = entity.SearchFilter()
searchFilter24.names = ["city|street"]
searchFilter24.names_case_sensitive = True
SearchResultsCheck(searchFilter24, "Filter by path - case sensitive 04", 0)
# Search by Component - Base
# Filter by component - base 01
searchFilter25 = entity.SearchFilter()
searchFilter25.components = { typeIdsList[0]:{} }
SearchResultsCheck(searchFilter25, "Filter by component - base 01", 2)
# Filter by component - base 02
searchFilter26 = entity.SearchFilter()
searchFilter26.components = { typeIdsList[1]:{} }
SearchResultsCheck(searchFilter26, "Filter by component - base 02", 3)
# Search by Component - Multiple
# Filter by component - multiple 01
searchFilter27 = entity.SearchFilter()
searchFilter27.components = { typeIdsList[0]: {} , typeIdsList[1]: {} }
searchFilter27.components_match_all = False # default
SearchResultsCheck(searchFilter27, "Filter by component - multiple 01", 4)
# Filter by component - multiple 02
searchFilter28 = entity.SearchFilter()
searchFilter28.components = { typeIdsList[0]: {} , typeIdsList[1]: {} }
searchFilter28.components_match_all = True
SearchResultCheck(searchFilter28, "Filter by component - multiple 02", passengerId1)
# Search with Roots - Base
# Filter with roots - base 01
searchFilter29 = entity.SearchFilter()
searchFilter29.names = ["Passenger"]
searchFilter29.roots = [carId1]
SearchResultsCheck(searchFilter29, "Filter with roots - base 01", 2)
# Filter with roots - base 02
searchFilter30 = entity.SearchFilter()
searchFilter30.names = ["Passenger"]
searchFilter30.roots = [carId2]
SearchResultCheck(searchFilter30, "Filter with roots - base 02", passengerId3)
# Filter with roots - base 03
searchFilter31 = entity.SearchFilter()
searchFilter31.names = ["SportsCar"]
searchFilter31.roots = [carId1]
SearchResultsCheck(searchFilter31, "Filter with roots - base 03", 0)
# Filter with roots - base 04
searchFilter32 = entity.SearchFilter()
searchFilter32.names = ["City|Street|SportsCar|Passenger"]
searchFilter32.roots = [carId1]
SearchResultsCheck(searchFilter32, "Filter with roots - base 04", 0)
# Filter with roots - base 05
searchFilter33 = entity.SearchFilter()
searchFilter33.names = ["Car|Passenger"]
searchFilter33.roots = [carId1]
SearchResultsCheck(searchFilter33, "Filter with roots - base 05", 2)
# Search with Roots - NameIsRootBased
# Filter with roots - NameIsRootBased 01
searchFilter34 = entity.SearchFilter()
searchFilter34.names = ["Car|Passenger"]
searchFilter34.names_are_root_based = False # default
SearchResultsCheck(searchFilter34, "Filter with roots - NameIsRootBased 01", 3)
# Filter with roots - NameIsRootBased 02
searchFilter35 = entity.SearchFilter()
searchFilter35.names = ["Car|Passenger"]
searchFilter35.names_are_root_based = True
SearchResultsCheck(searchFilter35, "Filter with roots - NameIsRootBased 02", 0)
# Filter with roots - NameIsRootBased 03
searchFilter36 = entity.SearchFilter()
searchFilter36.names = ["Car|Passenger"]
searchFilter36.roots = [streetId]
searchFilter36.names_are_root_based = False # default
SearchResultsCheck(searchFilter36, "Filter with roots - NameIsRootBased 03", 3)
# Filter with roots - NameIsRootBased 04
searchFilter37 = entity.SearchFilter()
searchFilter37.names = ["Car|Passenger"]
searchFilter37.roots = [streetId]
searchFilter37.names_are_root_based = True
SearchResultsCheck(searchFilter37, "Filter with roots - NameIsRootBased 04", 3)
# Filter with roots - NameIsRootBased 05
searchFilter38 = entity.SearchFilter()
searchFilter38.names = ["Car|Passenger"]
searchFilter38.roots = [carId2]
searchFilter38.names_are_root_based = True
SearchResultsCheck(searchFilter38, "Filter with roots - NameIsRootBased 05", 0)
# Search with Multiple Filters
searchFilter39 = entity.SearchFilter()
searchFilter39.names = ["Pass*"]
searchFilter39.roots = [sportsCarId]
searchFilter39.components = { typeIdsList[1]:{} }
searchFilter39.names_are_root_based = True
searchFilter39.names_case_sensitive = True
SearchResultCheck(searchFilter39, "Search with Multiple Filters", passengerId4)
# Search with Aabb - Base
aabb = math.Aabb()
cityPosition = components.TransformBus(bus.Event, "GetWorldTranslation", cityId)
print("City Position: ( " + str(cityPosition.x) + ", " + str(cityPosition.y) + ", " + str(cityPosition.z) + " )")
# Filter by AABB - base 01
searchFilter40 = entity.SearchFilter()
aabbMin = math.Vector3(cityPosition.x - 1000.0, cityPosition.y - 1000.0, cityPosition.z - 1000.0)
aabbMax = math.Vector3(cityPosition.x + 1000.0, cityPosition.y + 1000.0, cityPosition.z + 1000.0)
aabb.Set(aabbMin, aabbMax)
searchFilter40.aabb = aabb
searchFilter40.names = ["City", "Street", "SportsCar", "Car", "Passenger"]
searchFilter40.names_case_sensitive = True
SearchResultsCheck(searchFilter40, "Filter by AABB - base 01", 10)
# Filter by AABB - base 02
searchFilter41 = entity.SearchFilter()
aabbMin = math.Vector3(cityPosition.x - 1000.0, cityPosition.y - 1000.0, cityPosition.z - 1000.0)
aabbMax = math.Vector3(cityPosition.x - 100.0, cityPosition.y - 100.0, cityPosition.z - 100.0)
aabb.Set(aabbMin, aabbMax)
searchFilter41.aabb = aabb
searchFilter41.names = ["City", "Street", "SportsCar", "Car", "Passenger"]
searchFilter41.names_case_sensitive = True
SearchResultsCheck(searchFilter41, "Filter by AABB - base 02", 0)
# Search with Component Properties - Base
# Filter by Component Properties - base 01
searchFilter42 = entity.SearchFilter()
searchFilter42.components = { typeIdsList[1]:{'Render options|Draw character': True} }
searchFilter42.names = ["City", "Street", "SportsCar", "Car", "Passenger"]
SearchResultsCheck(searchFilter42, "Filter by Component Properties - base 01", 3)
# Filter by Component Properties - base 02
searchFilter43 = entity.SearchFilter()
searchFilter43.components = { typeIdsList[0]:{}, typeIdsList[1]:{'Render options|Draw character': True} }
searchFilter43.components_match_all = False
searchFilter43.names = ["City", "Street", "SportsCar", "Car", "Passenger"]
SearchResultsCheck(searchFilter43, "Filter by Component Properties - base 02", 4)
# Filter by Component Properties - base 03
searchFilter44 = entity.SearchFilter()
searchFilter44.components = { typeIdsList[0]:{}, typeIdsList[1]:{'Render options|Draw character': True} }
searchFilter44.components_match_all = True
searchFilter44.names = ["City", "Street", "SportsCar", "Car", "Passenger"]
SearchResultsCheck(searchFilter44, "Filter by Component Properties - base 03", 1)
editor.EditorToolsApplicationRequestBus(bus.Broadcast, 'ExitNoPrompt')
@@ -0,0 +1,43 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
#
# This is a pytest module to test the in-Editor Python API for Entity Selection
#
import pytest
pytest.importorskip('ly_test_tools')
import sys
import os
sys.path.append(os.path.dirname(__file__))
from hydra_utils import launch_test_case
@pytest.mark.SUITE_sandbox
@pytest.mark.parametrize('launcher_platform', ['windows_editor'])
@pytest.mark.parametrize('project', ['AutomatedTesting'])
@pytest.mark.parametrize('level', ['Simple'])
class TestEntitySelectionAutomation(object):
def test_EntitySelection(self, request, editor, level, launcher_platform):
unexpected_lines=[]
expected_lines = [
"SUCCESS: All Test Entities Selected",
"SUCCESS: One Test Entity Marked as DeSelected",
"SUCCESS: One New Test Entity Marked as Selected",
"SUCCESS: Half of Test Entity Marked as DeSelected",
"SUCCESS: All Test Entities Marked as Selected",
"SUCCESS: Clear All Test Entities Selected",
]
test_case_file = os.path.join(os.path.dirname(__file__), 'EntitySelectionCommands_test_case.py')
launch_test_case(editor, test_case_file, expected_lines, unexpected_lines)
@@ -0,0 +1,89 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
# Tests the Entity Selection Python API while the Editor is running
import azlmbr.bus as bus
import azlmbr.editor as editor
from azlmbr.entity import EntityId
def createTestEntities(count):
testEntityIds = []
for i in range(count):
entityId = editor.ToolsApplicationRequestBus(bus.Broadcast, 'CreateNewEntity', EntityId())
testEntityIds.append(entityId)
print("Entity " + str(i) + " created.")
editor.EditorEntityAPIBus(bus.Event, 'SetName', entityId, "TestEntity")
return testEntityIds
# Open a level (any level should work)
editor.EditorToolsApplicationRequestBus(bus.Broadcast, 'OpenLevelNoPrompt', 'WaterSample')
# Create new test entities at the root level
numTestEntities = 10
testEntityIds = createTestEntities(numTestEntities)
# Select all test entities
editor.ToolsApplicationRequestBus(bus.Broadcast, 'SetSelectedEntities', testEntityIds)
# Get all test entities selected and check if any entity selected
selectedTestEntityIds = editor.ToolsApplicationRequestBus(bus.Broadcast, 'GetSelectedEntities')
areAnyEntitiesSelected = editor.ToolsApplicationRequestBus(bus.Broadcast, 'AreAnyEntitiesSelected')
if(len(testEntityIds) == len(selectedTestEntityIds) and areAnyEntitiesSelected):
print("SUCCESS: All Test Entities Selected")
# Mark first test entity deselected
editor.ToolsApplicationRequestBus(bus.Broadcast, 'MarkEntityDeselected', testEntityIds[0])
selectedTestEntityIds = editor.ToolsApplicationRequestBus(bus.Broadcast, 'GetSelectedEntities')
isSelected = editor.ToolsApplicationRequestBus(bus.Broadcast, 'IsSelected', testEntityIds[0])
if(len(testEntityIds) - 1 == len(selectedTestEntityIds) and not isSelected):
print("SUCCESS: One Test Entity Marked as DeSelected")
# Mark first test entity selected
editor.ToolsApplicationRequestBus(bus.Broadcast, 'MarkEntitySelected', testEntityIds[0])
selectedTestEntityIds = editor.ToolsApplicationRequestBus(bus.Broadcast, 'GetSelectedEntities')
isSelected = editor.ToolsApplicationRequestBus(bus.Broadcast, 'IsSelected', testEntityIds[0])
if(len(testEntityIds) == len(selectedTestEntityIds) and isSelected):
print("SUCCESS: One New Test Entity Marked as Selected")
# Mark first half of test entities as deselected
halfNumTestEntities = len(testEntityIds)//2
editor.ToolsApplicationRequestBus(bus.Broadcast, 'MarkEntitiesDeselected', testEntityIds[:halfNumTestEntities])
selectedTestEntityIds = editor.ToolsApplicationRequestBus(bus.Broadcast, 'GetSelectedEntities')
if(len(testEntityIds) - halfNumTestEntities == len(selectedTestEntityIds)):
print("SUCCESS: Half of Test Entity Marked as DeSelected")
# Mark first half test entity as selected
editor.ToolsApplicationRequestBus(bus.Broadcast, 'MarkEntitiesSelected', testEntityIds[:halfNumTestEntities])
selectedTestEntityIds = editor.ToolsApplicationRequestBus(bus.Broadcast, 'GetSelectedEntities')
if(len(testEntityIds) == len(selectedTestEntityIds)):
print("SUCCESS: All Test Entities Marked as Selected")
# Clear all test entities selected
editor.ToolsApplicationRequestBus(bus.Broadcast, 'SetSelectedEntities', [])
selectedTestEntityIds = editor.ToolsApplicationRequestBus(bus.Broadcast, 'GetSelectedEntities')
areAnyEntitiesSelected = editor.ToolsApplicationRequestBus(bus.Broadcast, 'AreAnyEntitiesSelected')
if(len(selectedTestEntityIds) == 0 and not areAnyEntitiesSelected):
print("SUCCESS: Clear All Test Entities Selected")
# Close Editor
editor.EditorToolsApplicationRequestBus(bus.Broadcast, 'ExitNoPrompt')
@@ -0,0 +1,39 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
#
# This is a pytest module to test the in-Editor Python API from ViewPane.h
#
import pytest
pytest.importorskip('ly_test_tools')
import sys
import os
sys.path.append(os.path.dirname(__file__))
from hydra_utils import launch_test_case
@pytest.mark.SUITE_sandbox
@pytest.mark.parametrize('launcher_platform', ['windows_editor'])
@pytest.mark.parametrize('project', ['AutomatedTesting'])
@pytest.mark.parametrize('level', ['Simple'])
class TestLegacyGameModeAutomation(object):
def test_Legacy_GameMode(self, request, editor, level, launcher_platform):
unexpected_lines=[]
expected_lines = [
"Game Mode is On",
"Game Mode is Off"
]
test_case_file = os.path.join(os.path.dirname(__file__), 'GameModeCommands_test_case.py')
launch_test_case(editor, test_case_file, expected_lines, unexpected_lines)
@@ -0,0 +1,38 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
# Tests the Python Game Mode API from PythonEditorFuncs.cpp while the Editor is running
import azlmbr.bus as bus
import azlmbr.editor as editor
import azlmbr.legacy.general as general
general.idle_enable(True)
general.idle_wait(0.125)
general.enter_game_mode()
general.idle_wait(1.0)
if(general.is_in_game_mode()):
print("Game Mode is On")
general.idle_wait(0.125)
general.exit_game_mode()
general.idle_wait(1.0)
if not (general.is_in_game_mode()):
print("Game Mode is Off")
editor.EditorToolsApplicationRequestBus(bus.Broadcast, 'ExitNoPrompt')
@@ -0,0 +1,44 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
#
# This is a pytest module to test the in-Editor Python API from PythonEditorFuncs
#
import pytest
pytest.importorskip('ly_test_tools')
import sys
import os
sys.path.append(os.path.dirname(__file__))
from hydra_utils import launch_test_case
@pytest.mark.SUITE_sandbox
@pytest.mark.parametrize('launcher_platform', ['windows_editor'])
@pytest.mark.parametrize('project', ['AutomatedTesting'])
@pytest.mark.parametrize('level', ['Simple'])
class TestLevelAutomation(object):
def test_LevelCommands(self, request, editor, level, launcher_platform):
unexpected_lines=[]
expected_lines = [
"WaterSample level has already been created",
"Editor with WaterSample level opened closed",
"WaterSample level opened",
"Level name is correct",
"The level is in the Levels folder",
"Game folder is correct"
]
test_case_file = os.path.join(os.path.dirname(__file__), 'LevelCommands_test_case.py')
launch_test_case(editor, test_case_file, expected_lines, unexpected_lines)
@@ -0,0 +1,59 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
# Tests a portion of the Python API from CryEdit.cpp while the Editor is running
import os
import azlmbr.editor as editor
import azlmbr.bus as bus
# Try to create WaterSample level (return 1 means level with given name existed)
levelAlreadyExisted = 1
if (editor.EditorToolsApplicationRequestBus(bus.Broadcast, 'CreateLevelNoPrompt', 'WaterSample', 1024, False) is levelAlreadyExisted):
print("WaterSample level has already been created")
# Open WaterSample level
if (editor.EditorToolsApplicationRequestBus(bus.Broadcast, 'OpenLevelNoPrompt', 'WaterSample') is True):
print("WaterSample level opened")
# Get level path
levelpath = editor.EditorToolsApplicationRequestBus(bus.Broadcast, 'GetCurrentLevelPath')
# Split level path and get level name
path, filename = os.path.split(levelpath)
# Get level name
levelname = editor.EditorToolsApplicationRequestBus(bus.Broadcast, 'GetCurrentLevelName')
# Compare level name gotten from path to levelname
if (filename == levelname):
print("Level name is correct")
# Remove Levels folder from path
parent, levels = os.path.split(path)
if (levels == "Levels"):
print("The level is in the Levels folder")
# Get game folder
gamefolder = editor.EditorToolsApplicationRequestBus(bus.Broadcast, 'GetGameFolder')
# Compare game folder - normalize first because of the different formats
norm_gamefolder = os.path.normcase(gamefolder)
norm_parent = os.path.normcase(parent)
if (norm_parent == norm_gamefolder):
print("Game folder is correct")
# Close editor
editor.EditorToolsApplicationRequestBus(bus.Broadcast, 'ExitNoPrompt')
print("Editor with WaterSample level opened closed")
@@ -0,0 +1,2 @@
# this file is copied to $/dev/editor_autoexec.cfg so the the Editor automation runs for this Hydra test
pyRunFile @devroot@/Tests/hydra/LevelComponentCommands_test_case.py exit_when_done
@@ -0,0 +1,69 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
#
# This is a pytest module to test the in-Editor Python API from EditorLevelComponentAPIBus
#
import pytest
pytest.importorskip('test_tools')
import time
import logging
import os
import shutil
from test_tools import WINDOWS_LAUNCHER
import test_tools.shared.log_monitor
import test_tools.launchers.phase
import test_tools.builtin.fixtures as fixtures
import shared.file_utils as file_utils
# Use the built-in workspace and editor fixtures.
# These will configure the requested project and run the editor.
workspace = fixtures.use_fixture(fixtures.builtin_workspace_fixture, scope='function')
editor = fixtures.use_fixture(fixtures.editor, scope='function')
logger = logging.getLogger(__name__)
@pytest.mark.parametrize("platform,configuration,project,spec", [
pytest.param("win_x64_vs2017", "profile", "AutomatedTesting", "all", marks=pytest.mark.skipif(not WINDOWS_LAUNCHER, reason="Only supported on Windows hosts")),
])
class TestLevelComponentAutomation(object):
@pytest.fixture(autouse=True)
def setup_teardown(self, request, workspace, editor):
def teardown():
editor.ensure_stopped()
file_utils.delete_level(editor, "LevelComponentTest")
request.addfinalizer(teardown)
def test_Component(self, request, editor, project):
logger.debug("Running automated test")
request.addfinalizer(editor.ensure_stopped)
editor.deploy()
editor.launch(["--exec", "@engroot@/Tests/hydra/LevelComponentCommands.cfg"])
editorlog_file = os.path.join(editor.workspace.release.paths.project_log(), 'Editor.log')
expected_lines = [
"Component List returned correctly",
"Type Ids List returned correctly",
"Type Names List returned correctly",
"Level Component API validated"
]
test_tools.shared.log_monitor.monitor_for_expected_lines(editor, editorlog_file, expected_lines)
# Rely on the test script to quit after running
editor.run(test_tools.launchers.phase.WaitForLauncherToQuit(editor, 10))
@@ -0,0 +1,177 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
# Tests a portion of the Component CRUD Python API while the Editor is running
import sys
import azlmbr.legacy.general as general
import azlmbr.bus as bus
import azlmbr.editor as editor
from azlmbr.entity import EntityType
def validate_component_property_apis(levelEntityComponentIdPair, componentName, componentUuid):
propertyTreeOutcome = editor.EditorComponentAPIBus(bus.Broadcast, 'BuildComponentPropertyTreeEditor', levelEntityComponentIdPair)
if not propertyTreeOutcome.IsSuccess():
print("ERROR: BuildComponentPropertyTreeEditor failed for component with name={}, uuid={}".format(componentName, componentUuid))
return False
pte = propertyTreeOutcome.GetValue()
propList = pte.build_paths_list()
propList2 = editor.EditorComponentAPIBus(bus.Broadcast, 'BuildComponentPropertyList', levelEntityComponentIdPair)
if len(propList) != len(propList2):
print("ERROR: len(propList)={} != len(propList2)={} for component with name={}, uuid={}".format(len(propList), len(propList2), componentName, componentUuid))
return False
for propName in propList2:
#Some components like the Comment component have empty string property.
if propName == "":
continue
propOutcome = editor.EditorComponentAPIBus(bus.Broadcast, 'GetComponentProperty', levelEntityComponentIdPair, propName)
if not propOutcome.IsSuccess():
print("ERROR: Failed to get component property={} for component with name={}, uuid={}".format(propName, componentName, componentUuid))
return False
if not propName in propList2:
print("ERROR: Failed to find component property={} in propList2 for component with name={}, uuid={}".format(propName, componentName, componentUuid))
return False
return True
def validate_level_component_api(componentName, componentUuid):
if componentName == "PhysX Terrain":
#Skip physX. It has issues now that the Legacy Terrain is a component.
return True
if editor.EditorLevelComponentAPIBus(bus.Broadcast, 'HasComponentOfType', componentUuid):
print("ERROR: Component with name={}, uuid={} was already present".format(componentName, componentUuid))
return False
if editor.EditorLevelComponentAPIBus(bus.Broadcast, 'CountComponentsOfType', componentUuid) > 0:
print("ERROR: Component with name={}, uuid={} was already present".format(componentName, componentUuid))
return False
addComponentsOutcome = editor.EditorLevelComponentAPIBus(bus.Broadcast, 'AddComponentsOfType', [componentUuid])
if not addComponentsOutcome.IsSuccess():
print("ERROR: Failed to add Component with name={}, uuid={}".format(componentName, componentUuid))
return False
componentIds = addComponentsOutcome.GetValue()
if len(componentIds) != 1:
print("ERROR: Expecting 1 added Component with name={}, uuid={}".format(componentName, componentUuid))
return False
print("SUCCESS: Added 1 Component with name={}, uuid={}".format(componentName, componentUuid))
general.idle_wait(3.0)
if not editor.EditorLevelComponentAPIBus(bus.Broadcast, 'HasComponentOfType', componentUuid):
print("ERROR: Component with name={}, uuid={} was not present".format(componentName, componentUuid))
return False
if editor.EditorLevelComponentAPIBus(bus.Broadcast, 'CountComponentsOfType', componentUuid) != 1:
print("ERROR: Was expecting 1 Component with name={}, uuid={}".format(componentName, componentUuid))
return False
getComponentOutcome = editor.EditorLevelComponentAPIBus(bus.Broadcast, 'GetComponentOfType', componentUuid)
if not getComponentOutcome.IsSuccess():
print("ERROR: Failed to get added component with name={}, uuid={}".format(componentName, componentUuid))
return False
componentId = getComponentOutcome.GetValue()
if not componentId.Equal(componentIds[0]):
print("ERROR. GetComponentOfType no matching for component with name={}, uuid={}".format(componentName, componentUuid))
return False
getComponentsOutcome = editor.EditorLevelComponentAPIBus(bus.Broadcast, 'GetComponentsOfType', componentUuid)
newComponentIds = getComponentsOutcome.GetValue()
if len(newComponentIds) != 1:
print("ERROR: Expecting to get 1 Component with name={}, uuid={}".format(componentName, componentUuid))
return False
if not componentIds[0].Equal(newComponentIds[0]):
print("ERROR. GetComponentsOfType no matching for component with name={}, uuid={}".format(componentName, componentUuid))
return False
if not editor.EditorComponentAPIBus(bus.Broadcast, 'IsValid', componentId):
print("ERROR. expecting valid component with name={}, uuid={}".format(componentName, componentUuid))
return False
if not editor.EditorComponentAPIBus(bus.Broadcast, 'IsComponentEnabled', componentId):
if not editor.EditorComponentAPIBus(bus.Broadcast, 'EnableComponents', [componentId]):
print("ERROR. Failed to pre-enable component with name={}, uuid={}".format(componentName, componentUuid))
return False
print("SUCCESS: pre-enabled component with name={}, uuid={} ".format(componentName, componentUuid))
general.idle_wait(3.0)
if not editor.EditorComponentAPIBus(bus.Broadcast, 'IsComponentEnabled', componentId):
print("ERROR. Expecting enabled component with name={}, uuid={}".format(componentName, componentUuid))
return False
if not editor.EditorComponentAPIBus(bus.Broadcast, 'DisableComponents', [componentId]):
print("ERROR. Failed to disable component with name={}, uuid={}".format(componentName, componentUuid))
return False
print("SUCCESS: Disabled component with name={}, uuid={} ".format(componentName, componentUuid))
general.idle_wait(1.0)
if editor.EditorComponentAPIBus(bus.Broadcast, 'IsComponentEnabled', componentId):
print("ERROR. Expecting disabled component with name={}, uuid={}".format(componentName, componentUuid))
return False
if not editor.EditorComponentAPIBus(bus.Broadcast, 'EnableComponents', [componentId]):
print("ERROR. Failed to re-enable component with name={}, uuid={}".format(componentName, componentUuid))
return False
print("SUCCESS: Re-enabled component with name={}, uuid={} ".format(componentName, componentUuid))
general.idle_wait(3.0)
if not validate_component_property_apis(componentId, componentName, componentUuid):
print("ERROR. Failed to validate_component_property_apis for component with name={}, uuid={}".format(componentName, componentUuid))
return False
if not editor.EditorComponentAPIBus(bus.Broadcast, 'RemoveComponents', [componentId]):
print("ERROR. Failed to remove component with name={}, uuid={}".format(componentName, componentUuid))
return False
print("SUCCESS: Removed component with name={}, uuid={} ".format(componentName, componentUuid))
general.idle_wait(1.0)
if editor.EditorLevelComponentAPIBus(bus.Broadcast, 'HasComponentOfType', componentUuid):
print("ERROR: Was not expecting to have Component with name={}, uuid={}".format(componentName, componentUuid))
return False
print("SUCCESS: validated API with component with name={}, uuid={} ".format(componentName, componentUuid))
return True
exitWhenDone = False
if len(sys.argv) > 1:
if sys.argv[1] == "exit_when_done":
exitWhenDone = True
# Open a level (any level should work)
general.create_level_no_prompt('LevelComponentTest', 128, 1, 512, True)
# Make sure the default slices get a chance to initialize.
general.idle_wait(1.0)
# Generate List of Component Types
componentList = editor.EditorComponentAPIBus(bus.Broadcast, 'BuildComponentTypeNameListByEntityType', EntityType().Level)
if(len(componentList) > 0):
print("Component List returned correctly")
# Get Component Types for all level components
typeIdsList = editor.EditorComponentAPIBus(bus.Broadcast, 'FindComponentTypeIdsByEntityType', componentList, EntityType().Level)
if len(typeIdsList) != len(componentList):
print("ERROR: length of typeIdsList={} and length of componentList={}".format(len(typeIdsList), len(componentList)))
general.exit_no_prompt()
print("Type Ids List returned correctly")
# Get Component names from Component Types
typeNamesList = editor.EditorComponentAPIBus(bus.Broadcast, 'FindComponentTypeNames', typeIdsList)
if len(typeIdsList) != len(typeNamesList):
print("ERROR: length of typeIdsList={} and length of typeNamesList={}".format(len(typeIdsList), len(typeNamesList)))
general.exit_no_prompt()
for i in range(len(componentList)):
if componentList[i] != typeNamesList[i]:
print("ERROR: componentList[{}]({}) != typeNamesList=[{}]({})".format(i, componentList[i], i, typeNamesList[i]))
general.exit_no_prompt()
print("Type Names List returned correctly")
#Let's add each level component, one at a time, wait, remove component
for i in range(len(componentList)):
if validate_level_component_api(componentList[i], typeIdsList[i]):
continue
print("ERROR: Failed to validate_level_component_api for component with name={}, uuid={}".format(componentList[i], typeIdsList[i]))
general.exit_no_prompt()
print("Level Component API validated")
if exitWhenDone:
general.exit_no_prompt()
@@ -0,0 +1,40 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
#
# This is a pytest module to test the in-Editor Python API from PythonEditorFuncs
#
import pytest
pytest.importorskip('ly_test_tools')
import sys
import os
sys.path.append(os.path.dirname(__file__))
from hydra_utils import launch_test_case
@pytest.mark.SUITE_sandbox
@pytest.mark.parametrize('launcher_platform', ['windows_editor'])
@pytest.mark.parametrize('project', ['AutomatedTesting'])
@pytest.mark.parametrize('level', ['Simple'])
class TestLevelPathsAutomation(object):
def test_Legacy_LevelPaths(self, request, editor, level, launcher_platform):
unexpected_lines=[]
expected_lines = [
"Level name is correct",
"The level is in the Levels folder",
"Game folder is correct"
]
test_case_file = os.path.join(os.path.dirname(__file__), 'LevelPathsCommands_test_case.py')
launch_test_case(editor, test_case_file, expected_lines, unexpected_lines)
@@ -0,0 +1,51 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
# Tests a portion of the Python API from CryEdit.cpp while the Editor is running
import os
import azlmbr.bus as bus
import azlmbr.editor as editor
import azlmbr.legacy.general as general
# Open a level (any level should work)
editor.EditorToolsApplicationRequestBus(bus.Broadcast, 'OpenLevelNoPrompt', 'WaterSample')
# Get level path
levelpath = general.get_current_level_path()
# Split level path and get level name
path, level = os.path.split(levelpath)
# Get level name
levelname = general.get_current_level_name()
# Compare level name gotten from path to levelname
if(level == levelname):
print("Level name is correct")
# Remove Levels folder from path
parent, levels = os.path.split(path)
if(levels == "Levels"):
print("The level is in the Levels folder")
# Get game folder
gamefolder = general.get_game_folder()
# Compare game folder - normalize first because of the different formats
norm_gamefolder = os.path.normcase(gamefolder)
norm_parent = os.path.normcase(parent)
if(norm_parent == norm_gamefolder):
print("Game folder is correct")
editor.EditorToolsApplicationRequestBus(bus.Broadcast, 'ExitNoPrompt')
@@ -0,0 +1,41 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
#
# This is a pytest module to test the in-Editor Python API from PythonEditorFuncs
#
import pytest
pytest.importorskip('ly_test_tools')
import sys
import os
sys.path.append(os.path.dirname(__file__))
from hydra_utils import launch_test_case
@pytest.mark.SUITE_sandbox
@pytest.mark.parametrize('launcher_platform', ['windows_editor'])
@pytest.mark.parametrize('project', ['AutomatedTesting'])
@pytest.mark.parametrize('level', ['Simple'])
class TestMainWindowAutomation(object):
def test_MainWindow(self, request, editor, level, launcher_platform):
unexpected_lines=[]
expected_lines = [
"get_pane_class_names worked",
"open_pane worked",
"close_pane worked"
]
test_case_file = os.path.join(os.path.dirname(__file__), 'MainWindowCommands_test_case.py')
launch_test_case(editor, test_case_file, expected_lines, unexpected_lines)
@@ -0,0 +1,37 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
# Tests the Python API from MainWindow.cpp while the Editor is running
import azlmbr.bus as bus
import azlmbr.editor as editor
import azlmbr.legacy.general as general
# Get all pane names
panes = general.get_pane_class_names()
if(len(panes) > 0):
print('get_pane_class_names worked')
# Get any element from the panes list
test_pane = panes[4]
general.open_pane(test_pane)
if (general.is_pane_visible(test_pane)) :
print('open_pane worked')
general.close_pane(test_pane)
if not (general.is_pane_visible(test_pane)) :
print('close_pane worked')
editor.EditorToolsApplicationRequestBus(bus.Broadcast, 'ExitNoPrompt')
@@ -0,0 +1,54 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
#
# This is a pytest module to test the in-Editor Python API from PythonEditorFuncs
#
import pytest
pytest.importorskip('ly_test_tools')
import sys
import os
sys.path.append(os.path.dirname(__file__))
from hydra_utils import launch_test_case
@pytest.mark.SUITE_sandbox
@pytest.mark.parametrize('launcher_platform', ['windows_editor'])
@pytest.mark.parametrize('project', ['AutomatedTesting'])
@pytest.mark.parametrize('level', ['Simple'])
class TestObjectManagerAutomation(object):
def test_ViewPane(self, request, editor, level, launcher_platform):
unexpected_lines=[]
expected_lines = [
"get_all_objects works",
"get_names_of_selected_objects works",
"select_objects works",
"sel_position and sel_aabb both work",
"get_num_selected and unselect_objects both work",
"clear_selection works",
"hide_all_objects works",
"unhide_object works",
"hide_object works",
"freeze_object works",
"position setter/getter works",
"rotation setter/getter works",
"scale setter/getter works",
"delete_selected works",
"delete_object works",
"rename_object works"
]
test_case_file = os.path.join(os.path.dirname(__file__), 'ObjectManagerCommands_test_case.py')
launch_test_case(editor, test_case_file, expected_lines, unexpected_lines)
@@ -0,0 +1,145 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
# Tests a portion of the Python API from ObjectManager.cpp while the Editor is running
import azlmbr.bus as bus
import azlmbr.editor as editor
import azlmbr.math
import azlmbr.legacy.general as general
def fetch_vector3_parts(vec3):
x = vec3.get_property('x')
y = vec3.get_property('y')
z = vec3.get_property('z')
return (x, y, z)
general.idle_enable(True)
# Try to open the WaterSample level. If not, fail the test.
# We need to rely on an existing level since the API does not provide
# a way to create entities, but only lets us manipulate them.
editor.EditorToolsApplicationRequestBus(bus.Broadcast, 'OpenLevelNoPrompt', 'WaterSample')
if (editor.EditorToolsApplicationRequestBus(bus.Broadcast, 'GetCurrentLevelName') == 'WaterSample'):
objs_list = general.get_all_objects()
if(len(objs_list) > 0):
print("get_all_objects works")
general.clear_selection()
general.select_object(objs_list[0])
selected_objs_list = general.get_names_of_selected_objects()
if(len(selected_objs_list) == 1):
print("get_names_of_selected_objects works")
select = [objs_list[1], objs_list[2]]
general.select_objects(select)
selected_objs_list = general.get_names_of_selected_objects()
if(len(selected_objs_list) == 3):
print("select_objects works")
sel_position = general.get_selection_center()
sel_aabb = general.get_selection_aabb()
centerX = sel_position.get_property("x")
cornerX = sel_aabb.get_property("min").get_property("x")
if not(centerX == cornerX):
print("sel_position and sel_aabb both work")
unselect = [objs_list[0], objs_list[2]]
general.unselect_objects(unselect)
if(general.get_num_selected() == 1):
print("get_num_selected and unselect_objects both work")
general.clear_selection()
if(general.get_num_selected() == 0):
print("clear_selection works")
general.hide_all_objects()
if(general.is_object_hidden(objs_list[1])):
print("hide_all_objects works")
general.unhide_object(objs_list[1])
if not(general.is_object_hidden(objs_list[1])):
print("unhide_object works")
general.hide_object(objs_list[1])
if(general.is_object_hidden(objs_list[1])):
print("hide_object works")
general.unhide_all_objects()
general.freeze_object(objs_list[1])
if(general.is_object_frozen(objs_list[1])):
print("freeze_object works")
general.unfreeze_object(objs_list[1])
position = general.get_position(objs_list[1])
px1, py1, pz1 = fetch_vector3_parts(position)
general.set_position(objs_list[1], px1 + 10, py1 - 4, pz1 + 3)
new_position = general.get_position(objs_list[1])
px2, py2, pz2 = fetch_vector3_parts(new_position)
if(px2 > px1) and (py2 < py1) and (pz2 > pz1):
print("position setter/getter works")
rotation = general.get_rotation(objs_list[1])
rx1, ry1, rz1 = fetch_vector3_parts(rotation)
general.set_rotation(objs_list[1], rx1 + 10, ry1 - 4, rz1 + 3)
new_rotation = general.get_rotation(objs_list[1])
rx2, ry2, rz2 = fetch_vector3_parts(new_rotation)
if(rx2 > rx1) and (ry2 < ry1) and (rz2 > rz1):
print("rotation setter/getter works")
scale = general.get_scale(objs_list[1])
sx1, sy1, sz1 = fetch_vector3_parts(scale)
general.set_scale(objs_list[1], sx1 + 10, sy1 + 4, sz1 + 3)
new_scale = general.get_scale(objs_list[1])
sx2, sy2, sz2 = fetch_vector3_parts(new_scale)
if(sx2 > sx1) and (sy2 > sy1) and (sz2 > sz1):
print("scale setter/getter works")
general.select_object(objs_list[2])
general.delete_selected()
new_objs_list = general.get_all_objects()
if(len(new_objs_list) < len(objs_list)):
print("delete_selected works")
general.delete_object(objs_list[0])
new_objs_list = general.get_all_objects()
if(len(new_objs_list) < len(objs_list)):
print("delete_object works")
general.rename_object(objs_list[1], "some_test_name")
new_objs_list = general.get_all_objects()
for elem in new_objs_list:
if(elem == "some_test_name"):
print("rename_object works")
editor.EditorToolsApplicationRequestBus(bus.Broadcast, 'ExitNoPrompt')
@@ -0,0 +1,40 @@
''
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
#
# This is a pytest module to test the in-Editor Python API Object Representation
#
import pytest
pytest.importorskip('ly_test_tools')
import sys
import os
sys.path.append(os.path.dirname(__file__))
from hydra_utils import launch_test_case
@pytest.mark.SUITE_sandbox
@pytest.mark.parametrize('launcher_platform', ['windows_editor'])
@pytest.mark.parametrize('project', ['AutomatedTesting'])
@pytest.mark.parametrize('level', ['Simple'])
class TestObjectStringRepresentation(object):
def test_ObjectReprStr(self, request, editor, level, launcher_platform):
unexpected_lines=[]
expected_lines = [
"repr() returned expected value",
"str() returned expected value"
]
test_case_file = os.path.join(os.path.dirname(__file__), 'ObjectStringRepresentation_test_case.py')
launch_test_case(editor, test_case_file, expected_lines, unexpected_lines)
@@ -0,0 +1,34 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
# Tests the PythonProxyObject __str__ and __repr__
import azlmbr.bus as bus
import azlmbr.editor as editor
import azlmbr.entity as entity
import azlmbr.object
test_id = entity.EntityId()
test_id_repr = repr(test_id)
if test_id_repr.startswith('<EntityId via PythonProxyObject at'):
print("repr() returned expected value")
test_id_str = str(test_id)
test_id_to_string = test_id.ToString()
print(test_id_str)
print(test_id_to_string)
if test_id_str == test_id_to_string:
print("str() returned expected value")
editor.EditorToolsApplicationRequestBus(bus.Broadcast, 'ExitNoPrompt')
@@ -0,0 +1,39 @@
''
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
#
# This test shows how to use PySide2 inside an Editor Python Bindings test.
#
import pytest
import sys
import os
from .hydra_utils import launch_test_case
@pytest.mark.SUITE_sandbox
@pytest.mark.parametrize('launcher_platform', ['windows_editor'])
@pytest.mark.parametrize('project', ['AutomatedTesting'])
@pytest.mark.parametrize('level', ['Simple'])
class TestPySideExample(object):
def test_PySideExample(self, request, editor, level, launcher_platform):
unexpected_lines = []
expected_lines = [
'New entity with no parent created',
'Environment Probe component added to entity',
'ComboBox Values retrieved:'
]
test_case_file = os.path.join(os.path.dirname(__file__), 'PySide_Example_test_case.py')
launch_test_case(editor, test_case_file, expected_lines, unexpected_lines)
@@ -0,0 +1,62 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
#
# This test shows how to use PySide2 inside an Editor Python Bindings test.
# For PySide details see automatedtesting_shared/pyside_utils.py and automatedtesting_shared/pyside_component_utils.py
#
import sys
import os
import PySide2
sys.path.append(os.path.dirname(os.path.abspath(__file__)) + '/../automatedtesting_shared')
import azlmbr.bus as bus
import azlmbr.entity as entity
import azlmbr.editor as editor
import azlmbr.legacy.general as general
import pyside_component_utils
def PySide_Example_test_case():
# Open level, any level should work
editor.EditorToolsApplicationRequestBus(bus.Broadcast, 'OpenLevelNoPrompt', os.path.join('WhiteBox', 'EmptyLevel'))
entityId = editor.ToolsApplicationRequestBus(bus.Broadcast, 'CreateNewEntity', entity.EntityId())
if entityId:
print('New entity with no parent created')
# Get Component Type for Environment Probe and attach to entity
typeIdsList = editor.EditorComponentAPIBus(bus.Broadcast, 'FindComponentTypeIdsByEntityType', ["Environment Probe"],
entity.EntityType().Game)
componentOutcome = editor.EditorComponentAPIBus(bus.Broadcast, 'AddComponentsOfType', entityId, typeIdsList)
if componentOutcome.IsSuccess():
print('Environment Probe component added to entity')
# Waiting for one frame so that the widgets in the UI are updated with the new component information
general.idle_enable(True)
general.idle_wait_frames(1)
values = pyside_component_utils.get_component_combobox_values('Environment Probe', 'Resolution', print)
if values:
print(f'ComboBox Values retrieved: {values}.')
else:
print('Could not retrieve ComboBox values')
editor.EditorToolsApplicationRequestBus(bus.Broadcast, 'ExitNoPrompt')
if __name__ == '__main__':
PySide_Example_test_case()
@@ -0,0 +1,48 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
#
# This is a pytest module to test the in-Editor Python API from VertexMode.h
#
import pytest
pytest.importorskip('ly_test_tools')
import sys
import os
sys.path.append(os.path.dirname(__file__))
from .hydra_utils import launch_test_case
@pytest.mark.SUITE_sandbox
@pytest.mark.parametrize('launcher_platform', ['windows_editor'])
@pytest.mark.parametrize('project', ['AutomatedTesting'])
@pytest.mark.parametrize('level', ['Simple'])
class TestTrackViewAutomation(object):
def test_Supported_TrackView(self, request, editor, level, launcher_platform):
unexpected_lines = []
expected_lines = [
'[PASS] GetNumSequences returned the expected number of sequences [2].',
'[PASS] GetSequenceName returned the expected name [Test Sequence 01]',
'[PASS] SetSequenceTimeRange modified time range successfully.',
'[PASS] DeleteSequence ran with no error thrown.',
'[PASS] SetCurrentSequence ran with no error thrown.',
'[PASS] PlaySequence ran with no error thrown.',
'[PASS] AddNode ran with no error thrown.',
'[PASS] Found the expected number of nodes [2].',
'[PASS] GetNodeName returned the expected name [Test Node 01].',
'[PASS] DeleteNode ran with no error thrown.',
'[PASS] Found the expected number of nodes [1].',
'[PASS] DeleteSequence ran with no error thrown.'
]
test_case_file = os.path.join(os.path.dirname(__file__), 'TrackViewCommands_test_case.py')
launch_test_case(editor, test_case_file, expected_lines, unexpected_lines)
@@ -0,0 +1,101 @@
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
# Tests the track view
import azlmbr.bus as bus
import azlmbr.editor as editor
import azlmbr.track_view as track_view
import azlmbr.legacy.general as general
print ('Start of track view tests.')
general.idle_wait(1.0)
editor.EditorToolsApplicationRequestBus(bus.Broadcast, 'OpenLevelNoPrompt', 'ocean_trackview')
general.idle_wait(1.0)
num_sequences = track_view.EditorLayerTrackViewRequestBus(bus.Broadcast, 'GetNumSequences')
test_sequence_name = 'Test Sequence 01'
track_view.EditorLayerTrackViewRequestBus(bus.Broadcast, 'NewSequence', test_sequence_name, 1)
new_num_sequences = track_view.EditorLayerTrackViewRequestBus(bus.Broadcast, 'GetNumSequences')
if new_num_sequences == num_sequences + 1:
print('[PASS] GetNumSequences returned the expected number of sequences [{}].'.format(new_num_sequences))
else:
print('[FAIL] GetNumSequences returned an unexpected number of sequences, was [{}] and expected [{}].'.
format(new_num_sequences, num_sequences + 1))
returned_name = track_view.EditorLayerTrackViewRequestBus(bus.Broadcast, 'GetSequenceName', 0)
if returned_name == test_sequence_name:
print('[PASS] GetSequenceName returned the expected name [{}]'.format(test_sequence_name))
else:
print('[FAIL] GetSequenceName returned an unexpected name, was [{}] and expected [{}].'.
format(returned_name, test_sequence_name))
# Test modifying the sequence time range
time_range = track_view.EditorLayerTrackViewRequestBus(bus.Broadcast, 'GetSequenceTimeRange', test_sequence_name)
start = time_range.start + 5.0
end = time_range.end + 10.0
track_view.EditorLayerTrackViewRequestBus(bus.Broadcast, 'SetSequenceTimeRange', test_sequence_name, start, end)
new_time_range = track_view.EditorLayerTrackViewRequestBus(bus.Broadcast, 'GetSequenceTimeRange', test_sequence_name)
if (int(new_time_range.start) != int(time_range.start)) and (int(new_time_range.end) != int(time_range.end)):
print('[PASS] SetSequenceTimeRange modified time range successfully.')
else:
print('[FAIL] SetSequenceTimeRange did not modify the time range as expected.')
test_sequence_name_2 = 'Test Sequence 02'
track_view.EditorLayerTrackViewRequestBus(bus.Broadcast, 'NewSequence', test_sequence_name_2, 1)
track_view.EditorLayerTrackViewRequestBus(bus.Broadcast, 'DeleteSequence', test_sequence_name_2)
print('[PASS] DeleteSequence ran with no error thrown.')
track_view.EditorLayerTrackViewRequestBus(bus.Broadcast, 'SetCurrentSequence', test_sequence_name)
print('[PASS] SetCurrentSequence ran with no error thrown.')
track_view.EditorLayerTrackViewRequestBus(bus.Broadcast, 'PlaySequence')
print('[PASS] PlaySequence ran with no error thrown.')
track_view.EditorLayerTrackViewRequestBus(bus.Broadcast, 'AddNode', 'Director', 'Test Director')
test_node_name = 'Test Node 01'
track_view.EditorLayerTrackViewRequestBus(bus.Broadcast, 'AddNode', 'Event', test_node_name)
print('[PASS] AddNode ran with no error thrown.')
new_num_nodes = track_view.EditorLayerTrackViewRequestBus(bus.Broadcast, 'GetNumNodes', '')
num_expected_nodes = 2
if new_num_nodes == num_expected_nodes:
print('[PASS] Found the expected number of nodes [{}].'.format(num_expected_nodes))
else:
print('[FAIL] Found [{}] instead of [{}] nodes.'.format(new_num_nodes, num_expected_nodes))
returned_node_name = track_view.EditorLayerTrackViewRequestBus(bus.Broadcast, 'GetNodeName', 1, '')
if returned_node_name == test_node_name:
print('[PASS] GetNodeName returned the expected name [{}].'.format(test_node_name))
else:
print('[FAIL] GetNodeName returned [{}] and expected [{}].'.format(test_node_name, returned_node_name))
track_view.EditorLayerTrackViewRequestBus(bus.Broadcast, 'DeleteNode', test_node_name, '')
print('[PASS] DeleteNode ran with no error thrown.')
new_num_nodes = track_view.EditorLayerTrackViewRequestBus(bus.Broadcast, 'GetNumNodes', '')
num_expected_nodes = 1
if new_num_nodes == num_expected_nodes:
print('[PASS] Found the expected number of nodes [{}].'.format(num_expected_nodes))
else:
print('[FAIL] Found [{}] instead of [{}] nodes.'.format(new_num_nodes, num_expected_nodes))
track_view.EditorLayerTrackViewRequestBus(bus.Broadcast, 'DeleteSequence', test_sequence_name)
print('[PASS] DeleteSequence ran with no error thrown.')
print ('End of track view tests.')
@@ -0,0 +1,46 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
#
# This is a pytest module to test the in-Editor Python API from PythonEditorFuncs
#
import pytest
pytest.importorskip('ly_test_tools')
import sys
import os
sys.path.append(os.path.dirname(__file__))
from hydra_utils import launch_test_case
@pytest.mark.SUITE_sandbox
@pytest.mark.parametrize('launcher_platform', ['windows_editor'])
@pytest.mark.parametrize('project', ['AutomatedTesting'])
@pytest.mark.parametrize('level', ['Simple'])
class TestViewPaneAutomation(object):
def test_ViewPane(self, request, editor, level, launcher_platform):
unexpected_lines=[]
expected_lines = [
"set_viewport_size works",
"resize_viewport works",
"get_viewport_expansion_policy works",
"set_viewport_expansion_policy works",
"get_view_pane_layout works",
"set_view_pane_layout works",
"get_viewport_count works",
"get_active_viewport works",
"set_active_viewport works"
]
test_case_file = os.path.join(os.path.dirname(__file__), 'ViewPaneCommands_test_case.py')
launch_test_case(editor, test_case_file, expected_lines, unexpected_lines)
@@ -0,0 +1,103 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
# Tests a portion of the View Pane Python API from ViewPane.cpp while the Editor is running
import azlmbr.bus as bus
import azlmbr.editor as editor
import azlmbr.math
import azlmbr.legacy.general as general
# Open a level (any level should work)
editor.EditorToolsApplicationRequestBus(bus.Broadcast, 'OpenLevelNoPrompt', 'WaterSample')
general.idle_wait(0.5)
viewport_size = general.get_viewport_size()
view_width = int(viewport_size.x)
view_height = int(viewport_size.y)
general.set_viewport_size(320, 240)
new_viewport_size = general.get_viewport_size()
new_view_width = int(new_viewport_size.x)
new_view_height = int(new_viewport_size.y)
if not (view_width == new_view_width) and not (view_height == new_view_height):
print("set_viewport_size works")
general.resize_viewport(int(view_width), int(view_height))
newer_viewport_size = general.get_viewport_size()
newer_view_width = int(newer_viewport_size.x)
newer_view_height = int(newer_viewport_size.y)
if not (newer_view_width == new_view_width) and not (newer_view_height == new_view_height):
print("resize_viewport works")
def set_and_validate_viewport_size(width, height):
general.set_viewport_size(width, height)
general.update_viewport()
general.idle_wait(1.0)
new_viewport_size = general.get_viewport_size()
if (new_viewport_size.x != width) or (new_viewport_size.y != height):
return False
return True
# Perform some simple validation of get/set viewport expansion policy
general.set_viewport_expansion_policy('FixedSize')
if (general.get_viewport_expansion_policy() == 'FixedSize'):
print("get_viewport_expansion_policy works")
general.set_viewport_expansion_policy('AutoExpand')
if (general.get_viewport_expansion_policy() == 'AutoExpand'):
print("get_viewport_expansion_policy works")
# Validate that setting it to an invalid value doesn't change the setting.
general.set_viewport_expansion_policy('XXXXX')
if (general.get_viewport_expansion_policy() == 'AutoExpand'):
print("get_viewport_expansion_policy works")
# Set a series of viewport sizes (smaller to larger than display resolution sizes) and verify they all work.
general.set_viewport_expansion_policy('FixedSize')
if (set_and_validate_viewport_size(150, 300)):
print("set_viewport_expansion_policy works")
# Set different view pane layouts and verify it works
success = True
general.set_view_pane_layout(0)
general.idle_wait(0.5)
success = success and (general.get_view_pane_layout() == 0)
success = success and (general.get_viewport_count() == 1)
general.set_view_pane_layout(1)
general.idle_wait(0.5)
success = success and (general.get_view_pane_layout() == 1)
success = success and (general.get_viewport_count() == 2)
if success:
print("get_view_pane_layout works")
print("set_view_pane_layout works")
print("get_viewport_count works")
success = True
general.set_active_viewport(0)
general.idle_wait(0.5)
success = success and (general.get_active_viewport() == 0)
general.set_active_viewport(1)
general.idle_wait(0.5)
success = success and (general.get_active_viewport() == 1)
if success:
print("get_active_viewport works")
print("set_active_viewport works")
general.set_view_pane_layout(0)
general.idle_wait(0.5)
editor.EditorToolsApplicationRequestBus(bus.Broadcast, 'ExitNoPrompt')
@@ -0,0 +1,2 @@
# this file is copied to $/dev/editor_autoexec.cfg so the the Editor automation runs for this Hydra test
pyRunFile @devroot@/Tests/hydra/ViewportTitleDlgCommands_test_case.py
@@ -0,0 +1,60 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
#
# This is a pytest module to test the in-Editor Python API from ViewportTitleDlg
#
import pytest
pytest.importorskip('test_tools')
import time
import logging
import os
import shutil
from test_tools import WINDOWS_LAUNCHER
import test_tools.shared.log_monitor
import test_tools.launchers.phase
import test_tools.builtin.fixtures as fixtures
# Use the built-in workspace and editor fixtures.
# These will configure the requested project and run the editor.
workspace = fixtures.use_fixture(fixtures.builtin_workspace_fixture, scope='function')
editor = fixtures.use_fixture(fixtures.editor, scope='function')
logger = logging.getLogger(__name__)
@pytest.mark.SUITE_sandbox
@pytest.mark.parametrize("platform,configuration,project,spec", [
pytest.param("win_x64_vs2017", "profile", "AutomatedTesting", "all", marks=pytest.mark.skipif(not WINDOWS_LAUNCHER, reason="Only supported on Windows hosts")),
])
class TestViewportTitleDlgAutomation(object):
def test_ViewportTitleDlg_API(self, request, editor, project):
logger.debug("Running automated test for ViewportTitleDlg")
request.addfinalizer(editor.ensure_stopped)
editor.deploy()
editor.launch(["--exec", "@engroot@/Tests/hydra/ViewportTitleDlgCommands.cfg"])
editorlog_file = os.path.join(editor.workspace.release.paths.project_log(), 'Editor.log')
expected_lines = [
"toggle_helpers works",
"is_helpers_shown works"
]
test_tools.shared.log_monitor.monitor_for_expected_lines(editor, editorlog_file, expected_lines)
# Rely on the test script to quit after running
editor.run(test_tools.launchers.phase.WaitForLauncherToQuit(editor, 10))
@@ -0,0 +1,40 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
# Tests the ViewportTitleDlg Python API from ViewportTitleDlg.cpp while the Editor is running
import azlmbr.math
import azlmbr.legacy.general as general
# Open a level (any level should work)
general.open_level_no_prompt('WaterSample')
general.idle_wait(0.5)
test_success = True
# Get the current state of our helpers toggle.
initial_state = general.is_helpers_shown()
# Toggle it once and verify it changed
general.toggle_helpers()
test_success = test_success and (initial_state != general.is_helpers_shown())
# Toggle it a second time and verify it changed back to the original setting.
# Note: We specifically choose an even number of times so we leave the Editor
# in the same state as we found it. :)
general.toggle_helpers()
test_success = test_success and (initial_state == general.is_helpers_shown())
if test_success:
print('toggle_helpers works')
print('is_helpers_shown works')
general.exit_no_prompt()
@@ -0,0 +1,40 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
#
# This is a pytest module to test the in-Editor Python API for Entity CRUD
#
import pytest
pytest.importorskip('ly_test_tools')
import sys
import os
sys.path.append(os.path.dirname(__file__))
from hydra_utils import launch_test_case
@pytest.mark.SUITE_sandbox
@pytest.mark.parametrize('launcher_platform', ['windows_editor'])
@pytest.mark.parametrize('project', ['AutomatedTesting'])
@pytest.mark.parametrize('level', ['Simple'])
class TestEntityCommandsAutomation(object):
def test_EntityCommands(self, request, editor, level, launcher_platform):
unexpected_lines=[]
expected_lines = [
"Time is bigger after frames",
"Exact frames elapsed"
]
test_case_file = os.path.join(os.path.dirname(__file__), 'WaitCommands_test_case.py')
launch_test_case(editor, test_case_file, expected_lines, unexpected_lines)
@@ -0,0 +1,51 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
import azlmbr.bus as bus
import azlmbr.editor as editor
import azlmbr.math
import azlmbr.legacy.general as general
# open any level
general.idle_enable(True)
general.idle_wait(0.5)
preTimePoint = azlmbr.components.TickRequestBus(bus.Broadcast, "GetTimeAtCurrentTick")
preTimeMs = preTimePoint.GetMilliseconds()
TICKS_TO_WAIT = 5
numTicks = 0
def onTick(args):
global numTicks
numTicks += 1
handler = bus.NotificationHandler('TickBus')
handler.connect(None)
handler.add_callback('OnTick', onTick)
general.idle_wait_frames(TICKS_TO_WAIT)
postTimePoint = azlmbr.components.TickRequestBus(bus.Broadcast, "GetTimeAtCurrentTick")
postTimeMs = postTimePoint.GetMilliseconds()
if postTimeMs > preTimeMs:
print("Time is bigger after frames")
if numTicks == TICKS_TO_WAIT:
print("Exact frames elapsed")
handler.disconnect()
editor.EditorToolsApplicationRequestBus(bus.Broadcast, 'ExitNoPrompt')
@@ -0,0 +1,10 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
@@ -0,0 +1,62 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
#
# Helpful functions to simplify running the Hydra tests
#
import pytest
pytest.importorskip('ly_test_tools')
import os
import ly_test_tools.log.log_monitor
import ly_test_tools.environment.waiter as waiter
import logging
logger = logging.getLogger(__name__)
def launch_test_case(editor, test_case, expected_lines, unexpected_lines):
timeout=180
halt_on_unexpected=False
logger.debug("Running automated test: {}".format(test_case))
editor.args.extend(['-NullRenderer', "--skipWelcomeScreenDialog", "--autotest_mode", "--runpythontest", test_case])
print ('editor.args = {}'.format(editor.args))
with editor.start():
editorlog_file = os.path.join(editor.workspace.paths.project_log(), 'Editor.log')
log_monitor = ly_test_tools.log.log_monitor.LogMonitor(editor, editorlog_file)
logger.debug("Waiting for log file '{}' to be opened by another process.".format(editorlog_file))
waiter.wait_for(
lambda: editor.is_alive(),
timeout,
exc=("Log file '{}' was never opened by another process.".format(editorlog_file)),
interval=1)
log_monitor.monitor_log_for_lines(expected_lines, unexpected_lines, halt_on_unexpected, timeout)
def launch_test_case_with_args(editor, test_case, expected_lines, unexpected_lines, extra_args):
timeout=180
halt_on_unexpected=False
logger.debug("Running automated test: {}".format(test_case))
editor.args.extend(['-NullRenderer', "--skipWelcomeScreenDialog", "--autotest_mode", "--runpythontest", test_case, '--runpythonargs'])
editor.args.extend(extra_args)
print ('editor.args = {}'.format(editor.args))
with editor.start():
editorlog_file = os.path.join(editor.workspace.paths.project_log(), 'Editor.log')
log_monitor = ly_test_tools.log.log_monitor.LogMonitor(editor, editorlog_file)
logger.debug("Waiting for log file '{}' to be opened by another process.".format(editorlog_file))
waiter.wait_for(
lambda: editor.is_alive(),
timeout,
exc=("Log file '{}' was never opened by another process.".format(editorlog_file)),
interval=1)
log_monitor.monitor_log_for_lines(expected_lines, unexpected_lines, halt_on_unexpected, timeout)
@@ -0,0 +1,51 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
#
# This is a pytest module to test the in-Editor Python API for Entity CRUD
#
import pytest
pytest.importorskip('ly_test_tools')
import sys
import os
sys.path.append(os.path.dirname(__file__))
from .hydra_utils import launch_test_case
@pytest.mark.SUITE_sandbox
@pytest.mark.parametrize('launcher_platform', ['windows_editor'])
@pytest.mark.parametrize('project', ['AutomatedTesting'])
@pytest.mark.parametrize('level', ['Simple'])
class TestLayerEntityAutomation(object):
def test_LayerEntity(self, request, editor, level, launcher_platform):
unexpected_lines=[]
expected_lines = [
"[PASS] layer has been created",
"[PASS] successfully changed status: 0",
"[PASS] successfully changed status: 1",
"[PASS] successfully changed status: 2",
"[PASS] Get name request succeeded",
"[PASS] Layer name changed",
"[PASS] Layer color changed",
"[PASS] layer child entity has been created",
"[PASS] Query parent returned layer ID",
"[PASS] EditorEntityInfoRequestBus GetChildren return list of decendants",
"[PASS] comment component has been added",
"[PASS] layer has been locked",
"[PASS] layer children are hidden",
"[PASS] Layer entity not found after delete request"
]
test_case_file = os.path.join(os.path.dirname(__file__), 'layerEntity_test_case.py')
launch_test_case(editor, test_case_file, expected_lines, unexpected_lines)
@@ -0,0 +1,143 @@
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
# Tests AZ Layer creation, property modification and interaction with entity CRUD operations in the editor
import sys
import azlmbr.layers as layers
import azlmbr.editor as editor
import azlmbr.bus as bus
import azlmbr.entity as entity
import azlmbr.math as math
def add_component(typename, entityId):
typeIdsList = editor.EditorComponentAPIBus(bus.Broadcast, 'FindComponentTypeIdsByEntityType', [typename], entity.EntityType().Game)
componentOutcome = editor.EditorComponentAPIBus(bus.Broadcast, 'AddComponentsOfType', entityId, typeIdsList)
return componentOutcome.IsSuccess()
def change_entity_status(desiredStatusProperty, entityId):
editor.EditorEntityAPIBus(bus.Event, 'SetStartStatus', entityId, desiredStatusProperty)
status = editor.EditorEntityInfoRequestBus(bus.Event, 'GetStartStatus', entityId)
if (status == desiredStatusProperty):
print('[PASS] successfully changed status: ' + str(desiredStatusProperty))
else:
print('[FAIL] unable to set status: ' + str(desiredStatusProperty))
return
# Test creating layer entity
layerId = layers.EditorLayerComponent_CreateLayerEntityFromName('testLayer')
if(layerId):
print('[PASS] layer has been created')
else:
print('[FAIL] layer was not created')
azlmbr.framework.Terminate(1)
# Test getting and setting the name property for the layer
name = editor.EditorEntityInfoRequestBus(bus.Event, 'GetName', layerId);
if(name):
print('[PASS] Get name request succeeded')
else:
print('[FAIL] Get name request failed')
editor.EditorEntityAPIBus(bus.Event, 'SetName', layerId, "test_layer")
name = editor.EditorEntityInfoRequestBus(bus.Event, 'GetName', layerId)
if(name == 'test_layer'):
print('[PASS] Layer name changed')
else:
print('[FAIL] Did not complete layer name change')
# Test Getting and Setting the color for the layer
color = math.Color_ConstructFromValues(255,255,0,1)
oldColor = layers.EditorLayerComponentRequestBus(bus.Event, 'GetColorPropertyValue', layerId)
layers.EditorLayerComponentRequestBus(bus.Event, 'SetLayerColor', layerId, color)
newColor = layers.EditorLayerComponentRequestBus(bus.Event, 'GetColorPropertyValue', layerId)
if(oldColor and newColor):
if (oldColor != newColor):
print('[PASS] Layer color changed')
else:
print('[FAIL] Was unable to change layer color property')
else:
print('[FAIL] Was unable to get color property of layer')
# Test creating child entity in layer entity
layerChild = editor.ToolsApplicationRequestBus(bus.Broadcast, 'CreateNewEntity', layerId)
if (layerChild):
print('[PASS] layer child entity has been created')
else:
print('[FAIL] layer child entity was not created')
queryParent = editor.EditorEntityInfoRequestBus(bus.Event, 'GetParent', layerChild)
if(queryParent.ToString() == layerId.ToString()):
print('[PASS] Query parent returned layer ID')
else:
print('[FAIL] layer is not parented to entity')
# Test getting child entity IDs
childList = editor.EditorEntityInfoRequestBus(bus.Event, 'GetChildren', layerId)
if(childList):
print('[PASS] EditorEntityInfoRequestBus GetChildren return list of decendants')
else:
print('[FAILL] EditorEntityInfoRequestBus GetChildren did not return list of decendants')
# Test adding component to layer entity
result = add_component('Comment', layerId)
if(result == True):
print('[PASS] comment component has been added')
else:
print('[FAIL] comment component was not added to layer')
# Test locking layer entity. Note: layers themselves are not locked or unlocked;
# setting lock on a layer effectively sets the lock for all child entities
queryLock = editor.EditorEntityInfoRequestBus(bus.Event, 'IsLocked', layerId)
if(queryLock == False):
print('[INFO] layer is not locked')
editor.EditorEntityAPIBus(bus.Event, 'SetLockState', layerId, True)
queryLock = editor.EditorEntityInfoRequestBus(bus.Event, 'IsLocked', layerId)
if(queryLock == True):
print('[PASS] layer has been locked')
else:
print('[FAIL] layer was no locked')
# Test layer visibility. Note: layers themselves are not visible or invisible;
# setting visibility on a layer effectively sets visibility for all child entities
queryVisibility = editor.EditorEntityInfoRequestBus(bus.Event, 'IsVisible', layerChild)
if(queryVisibility == True):
print('[INFO] layer children are visible')
layers.EditorLayerComponentRequestBus(azlmbr.bus.Event, 'SetVisibility', layerId, False)
queryVisibility = editor.EditorEntityInfoRequestBus(bus.Event, 'IsVisible', layerChild)
if(queryVisibility == False):
print('[PASS] layer children are hidden')
else:
print('[FAIL] unable to set layer visibility to hidden')
# Test layer status property
# start active
change_entity_status(azlmbr.globals.property.EditorEntityStartStatus_StartActive, layerId)
# start inactive
change_entity_status(azlmbr.globals.property.EditorEntityStartStatus_StartInactive, layerId)
# editor only
change_entity_status(azlmbr.globals.property.EditorEntityStartStatus_EditorOnly, layerId)
# Test deleting layer
editor.ToolsApplicationRequestBus(bus.Broadcast, 'DeleteEntityAndAllDescendants', layerId)
entityName = editor.EditorEntityInfoRequestBus(bus.Event, 'GetName', layerId)
if (entityName):
print('[FAIL] Layer entity found after delete request')
else:
print('[PASS] Layer entity not found after delete request')
# Close editor without saving
editor.EditorToolsApplicationRequestBus(bus.Broadcast, 'ExitNoPrompt')
@@ -0,0 +1,4 @@
All the Hydra tests use the AutomatedTesting project.
The all use the hydra_utils.py file to launch the auto Editor tests.
The <Test_Type>_test.py file is run using LYTT
The <Test_Type>_test_case.py file is executed in the Editor
@@ -0,0 +1,91 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
# Test case ID : C18977329
# Test Case Title : Add cloth simulation to a Mesh
# URL of the test case : https://testrail.agscollab.com/index.php?/cases/view/18977329
# fmt: off
class Tests:
enter_game_mode = ("Entered game mode", "Failed to enter game mode")
no_errors_and_warnings_found = ("No errors and warnings found", "Found errors and warnings")
exit_game_mode = ("Exited game mode", "Failed to exit game mode")
# fmt: on
def run():
"""
Summary:
Load level with Entity having Mesh and Cloth components already setup. Verify that editor remains stable in Game mode.
Expected Behavior:
The Editor is stable there are no warnings or errors.
Test Steps:
1) Load the level
2) Start the Tracer to catch any errors and warnings
3) Enter game mode
4) Wait in game mode some frames to let cloth simulation run
5) Verify there are no errors and warnings in the logs
6) Exit game mode
7) Close the editor
Note:
At the time of writing this test it was not possible to set a component property
with a dropdown, which is necessary to setup a Cloth component. Because of this limitation
the components of this test are not setup by the script and a level was provided instead.
:return: None
"""
import azlmbr.legacy.general as general
# Helper file Imports
import ImportPathHelper as imports
imports.init()
from utils import Report
from utils import TestHelper as helper
from utils import Tracer
from editor_entity_utils import EditorEntity
# Constants
FRAMES_IN_GAME_MODE = 200
helper.init_idle()
# 1) Load the level
helper.open_level("NvCloth", "C18977329_NvCloth_AddClothSimulationToMesh")
# 2) Start the Tracer to catch any errors and warnings
with Tracer() as section_tracer:
# 3) Enter game mode
helper.enter_game_mode(Tests.enter_game_mode)
# 4) Wait in game mode some frames to let cloth simulation run
general.idle_wait_frames(FRAMES_IN_GAME_MODE)
# 5) Verify there are no errors and warnings in the logs
success_condition = not (section_tracer.has_errors or section_tracer.has_warnings)
Report.result(Tests.no_errors_and_warnings_found, success_condition)
if not success_condition:
if section_tracer.has_warnings:
Report.info(f"Warnings found: {section_tracer.warnings}")
if section_tracer.has_errors:
Report.info(f"Errors found: {section_tracer.errors}")
Report.failure(Tests.no_errors_and_warnings_found)
# 6) Exit game mode
helper.exit_game_mode(Tests.exit_game_mode)
# 7) Close the editor
helper.close_editor()
if __name__ == "__main__":
run()
@@ -0,0 +1,91 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
# Test case ID : C18977330
# Test Case Title : Add cloth simulation to an Actor
# URL of the test case : https://testrail.agscollab.com/index.php?/cases/view/18977330
# fmt: off
class Tests:
enter_game_mode = ("Entered game mode", "Failed to enter game mode")
no_errors_and_warnings_found = ("No errors and warnings found", "Found errors and warnings")
exit_game_mode = ("Exited game mode", "Failed to exit game mode")
# fmt: on
def run():
"""
Summary:
Load level with Entity having Actor and Cloth components already setup. Verify that editor remains stable in Game mode.
Expected Behavior:
The Editor is stable there are no warnings or errors.
Test Steps:
1) Load the level
2) Start the Tracer to catch any errors and warnings
3) Enter game mode
4) Wait in game mode some frames to let cloth simulation run
5) Verify there are no errors and warnings in the logs
6) Exit game mode
7) Close the editor
Note:
At the time of writing this test it was not possible to set a component property
with a dropdown, which is necessary to setup a Cloth component. Because of this limitation
the components of this test are not setup by the script and a level was provided instead.
:return: None
"""
import azlmbr.legacy.general as general
# Helper file Imports
import ImportPathHelper as imports
imports.init()
from utils import Report
from utils import TestHelper as helper
from utils import Tracer
from editor_entity_utils import EditorEntity
# Constants
FRAMES_IN_GAME_MODE = 200
helper.init_idle()
# 1) Load the level
helper.open_level("NvCloth", "C18977330_NvCloth_AddClothSimulationToActor")
# 2) Start the Tracer to catch any errors and warnings
with Tracer() as section_tracer:
# 3) Enter game mode
helper.enter_game_mode(Tests.enter_game_mode)
# 4) Wait in game mode some frames to let cloth simulation run
general.idle_wait_frames(FRAMES_IN_GAME_MODE)
# 5) Verify there are no errors and warnings in the logs
success_condition = not (section_tracer.has_errors or section_tracer.has_warnings)
Report.result(Tests.no_errors_and_warnings_found, success_condition)
if not success_condition:
if section_tracer.has_warnings:
Report.info(f"Warnings found: {section_tracer.warnings}")
if section_tracer.has_errors:
Report.info(f"Errors found: {section_tracer.errors}")
Report.failure(Tests.no_errors_and_warnings_found)
# 6) Exit game mode
helper.exit_game_mode(Tests.exit_game_mode)
# 7) Close the editor
helper.close_editor()
if __name__ == "__main__":
run()
@@ -0,0 +1,15 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
def init():
import os
import sys
sys.path.append(os.path.dirname(os.path.abspath(__file__)) + '/../automatedtesting_shared')
@@ -0,0 +1,34 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
# This suite consists of all test cases that are passing and have been verified.
import pytest
import os
import sys
from ly_test_tools import LAUNCHERS
sys.path.append(os.path.dirname(os.path.abspath(__file__)) + '/../automatedtesting_shared')
from base import TestAutomationBase
@pytest.mark.SUITE_main
@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
@pytest.mark.parametrize("project", ["AutomatedTesting"])
class TestAutomation(TestAutomationBase):
def test_C18977329_NvCloth_AddClothSimulationToMesh(self, request, workspace, editor, launcher_platform):
from . import C18977329_NvCloth_AddClothSimulationToMesh as test_module
self._run_test(request, workspace, editor, test_module)
def test_C18977330_NvCloth_AddClothSimulationToActor(self, request, workspace, editor, launcher_platform):
from . import C18977330_NvCloth_AddClothSimulationToActor as test_module
self._run_test(request, workspace, editor, test_module)
@@ -0,0 +1,10 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
@@ -0,0 +1,13 @@
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
set(PAL_TRAIT_LARGE_WORLDS_TEST_SUPPORTED FALSE)
set(PAL_TRAIT_FOUNDATION_TEST_SUPPORTED FALSE)
@@ -0,0 +1,13 @@
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
set(PAL_TRAIT_LARGE_WORLDS_TEST_SUPPORTED FALSE)
set(PAL_TRAIT_FOUNDATION_TEST_SUPPORTED FALSE)
@@ -0,0 +1,13 @@
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
set(PAL_TRAIT_LARGE_WORLDS_TEST_SUPPORTED FALSE)
set(PAL_TRAIT_FOUNDATION_TEST_SUPPORTED FALSE)
@@ -0,0 +1,13 @@
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
set(PAL_TRAIT_LARGE_WORLDS_TEST_SUPPORTED TRUE)
set(PAL_TRAIT_FOUNDATION_TEST_SUPPORTED TRUE)
@@ -0,0 +1,13 @@
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
set(PAL_TRAIT_LARGE_WORLDS_TEST_SUPPORTED FALSE)
set(PAL_TRAIT_FOUNDATION_TEST_SUPPORTED FALSE)
@@ -0,0 +1,60 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
# Test case ID : C28798177
# Test Case Title : White Box Tool Component can be added to an Entity
# URL of the test case : https://testrail.agscollab.com/index.php?/cases/view/28798177
# fmt:off
class Tests():
white_box_entity_created = ("White box entity created", "Failed to create white box entity")
white_box_component_enabled = ("White box component enabled", "Failed to enable white box component")
# fmt:on
def run():
import os
import sys
import WhiteBoxInit as init
import ImportPathHelper as imports
imports.init()
import azlmbr.bus as bus
import azlmbr.editor as editor
import azlmbr.legacy.general as general
from utils import Report
from utils import TestHelper as helper
# open level
helper.init_idle()
general.open_level("EmptyLevel")
# create white box entity and attach component
white_box_entity = init.create_white_box_entity()
white_box_mesh_component = init.create_white_box_component(white_box_entity)
init.create_white_box_handle(white_box_mesh_component)
# verify results
entity_id = general.find_editor_entity('WhiteBox')
Report.result(Tests.white_box_entity_created, entity_id.IsValid())
component_enabled = editor.EditorComponentAPIBus(bus.Broadcast, 'IsComponentEnabled', white_box_mesh_component)
Report.result(Tests.white_box_component_enabled, component_enabled)
# close editor
helper.close_editor()
if __name__ == "__main__":
run()
@@ -0,0 +1,70 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
# Test case ID : C28798205
# Test Case Title : From the White Box Component Card the White Box Mesh can be set to be invisible in Game View
# URL of the test case : https://testrail.agscollab.com/index.php?/cases/view/28798205
# fmt:off
class Tests():
white_box_initially_visible = ("White box initially invisible", "White box not initially invisible")
white_box_set_to_invisible = ("White box set to invisible", "Failed to set white box to invisible")
# fmt:on
def run():
# note: This automated test does not fully replicate the test case in Test Rail as it's
# not currently possible using the Hydra API to get an EntityComponentIdPair at runtime,
# in future game_mode will be activated and a runtime White Box Component queried
import os
import sys
import WhiteBoxInit as init
import ImportPathHelper as imports
import Tests.ly_shared.hydra_editor_utils as hydra
imports.init()
import azlmbr.whitebox.api as api
import azlmbr.whitebox
import azlmbr.bus as bus
import azlmbr.editor as editor
import azlmbr.entity as entity
import azlmbr.legacy.general as general
from utils import Report
from utils import TestHelper as helper
# open level
helper.init_idle()
general.open_level("EmptyLevel")
white_box_entity_name = 'WhiteBox-Visibility'
white_box_visibility_path = 'White Box Material|Visible'
# create white box entity and attach component
white_box_entity = init.create_white_box_entity(white_box_entity_name)
white_box_mesh_component = init.create_white_box_component(white_box_entity)
# verify preconditions
visible_property = hydra.get_component_property_value(white_box_mesh_component, white_box_visibility_path)
Report.result(Tests.white_box_initially_visible, visible_property)
# verify setting visibility
editor.EditorComponentAPIBus(bus.Broadcast, "SetComponentProperty", white_box_mesh_component, white_box_visibility_path, False)
visible_property = hydra.get_component_property_value(white_box_mesh_component, white_box_visibility_path)
Report.result(Tests.white_box_set_to_invisible, not visible_property)
helper.close_editor()
if __name__ == "__main__":
run()
@@ -0,0 +1,109 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
# Test case ID : C29279329
# Test Case Title : White Box mesh shape can be changed with the Default Shape dropdown on the Component
# URL of the test case : https://testrail.agscollab.com/index.php?/cases/view/29279329
# fmt:off
class Tests():
default_shape_cube = ("Default shape set to cube", "Default shape is not set to cube")
default_shape_tetrahedron = ("Default shape changed to tetrahedron", "Failed to change default shape to tetrahedron")
default_shape_icosahedron = ("Default shape changed to icosahedron", "Failed to change default shape to icosahedron")
default_shape_cylinder = ("Default shape changed to cylinder", "Failed to change default shape to cylinder")
default_shape_sphere = ("Default shape changed to sphere", "Failed to change default shape to sphere")
# fmt:on
critical_shape_check = ("Default shape has more than 0 sides", "default shape has 0 sides")
def run():
import os
import sys
import WhiteBoxInit as init
import ImportPathHelper as imports
imports.init()
import azlmbr.whitebox.api as api
import azlmbr.bus as bus
import azlmbr.legacy.general as general
from utils import Report
from utils import TestHelper as helper
def check_shape_result(success_fail_tuple, condition):
result = Report.result(success_fail_tuple, condition)
if not result:
face_count = white_box_handle.MeshFaceCount()
Report.critical_result(critical_shape_check, face_count > 0)
Report.info(f"Face count = {face_count}")
shape_types = azlmbr.globals.property
# expected results
expected_results = {
shape_types.CUBE: 12,
shape_types.TETRAHEDRON: 4,
shape_types.ICOSAHEDRON: 20,
shape_types.CYLINDER: 64,
shape_types.SPHERE: 320
}
# open level
helper.init_idle()
general.open_level("EmptyLevel")
# create white box entity and attach component
white_box_entity = init.create_white_box_entity()
white_box_mesh_component = init.create_white_box_component(white_box_entity)
white_box_handle = init.create_white_box_handle(white_box_mesh_component)
# verify results
# cube
check_shape_result(
Tests.default_shape_cube,
white_box_handle.MeshFaceCount() == expected_results.get(shape_types.CUBE))
# tetrahedron
azlmbr.whitebox.request.bus.EditorWhiteBoxComponentRequestBus(
bus.Event, 'SetDefaultShape', white_box_mesh_component, shape_types.TETRAHEDRON)
check_shape_result(
Tests.default_shape_tetrahedron,
white_box_handle.MeshFaceCount() == expected_results.get(shape_types.TETRAHEDRON))
# icosahedron
azlmbr.whitebox.request.bus.EditorWhiteBoxComponentRequestBus(
bus.Event, 'SetDefaultShape', white_box_mesh_component, shape_types.ICOSAHEDRON)
check_shape_result(
Tests.default_shape_icosahedron,
white_box_handle.MeshFaceCount() == expected_results.get(shape_types.ICOSAHEDRON))
# cylinder
azlmbr.whitebox.request.bus.EditorWhiteBoxComponentRequestBus(
bus.Event, 'SetDefaultShape', white_box_mesh_component, shape_types.CYLINDER)
check_shape_result(
Tests.default_shape_cylinder,
white_box_handle.MeshFaceCount() == expected_results.get(shape_types.CYLINDER))
# sphere
azlmbr.whitebox.request.bus.EditorWhiteBoxComponentRequestBus(
bus.Event, 'SetDefaultShape', white_box_mesh_component, shape_types.SPHERE)
check_shape_result(
Tests.default_shape_sphere,
white_box_handle.MeshFaceCount() == expected_results.get(shape_types.SPHERE))
# close editor
helper.close_editor()
if __name__ == "__main__":
run()
@@ -0,0 +1,354 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
# Imports
import os
import shutil
import json
import logging
import ly_test_tools.environment.file_system as fs
class FileManagement:
"""
File Management static class: Handles file backup and restoration.
Organizes backing up files into a single directory and
mapping the back up files to their original files.
Features accessible via the exposed decorator functions.
"""
# Static variables
MAX_BACKUPS = 10000 # Arbitrary number to cap same-file-name name generating
backup_folder_name = ".backup"
backup_folder_path = os.path.join(os.path.split(__file__)[0], backup_folder_name) # CWD plus backup folder name
file_map_name = "_filebackup_map.json" # JSON file to store original to back up file mappings
@staticmethod
def _load_file_map():
# type: () -> {str: str}
"""
Loads the FileManagement's json file map.
The returned dictionary has key: value sets such that:
keys: full path to an original file currently being backed up
values: name of the original file's backup file. Uses a numbering system for
storing multiple file names that are identical but located in different directories.
If there is no current json file or the file cannot be parsed, an empty dictionary is returned.
:return: Dictionary to map original file's to their back up file names.
"""
json_file_path = os.path.join(FileManagement.backup_folder_path, FileManagement.file_map_name)
if os.path.exists(json_file_path):
try:
with open(json_file_path, "r") as f:
return json.load(f)
except ValueError:
logging.info("Decoding JSON file {} failed. Empty dictionary used".format(json_file_path))
return {}
@staticmethod
def _save_file_map(file_map):
# type: ({str: str}) -> None
"""
Saves the [file_map] dictionary as a json file.
If [file_map] is empty, deletes the json file.
:param file_map: A dictionary mapping original file paths to their back up file names.
:return: None
"""
file_path = os.path.join(FileManagement.backup_folder_path, FileManagement.file_map_name)
if os.path.exists(file_path):
fs.unlock_file(file_path)
if len(file_map) > 0:
with open(file_path, "w") as f:
json.dump(file_map, f)
fs.lock_file(file_path)
else:
fs.delete([file_path], True, False)
@staticmethod
def _next_available_name(file_name, file_map):
# type: (str, {str: str}) -> str or None
"""
Generates the next available backup file name using a FILE_NAME_x.ext naming convention
where x is a number. Returns None if we've maxed out the numbering system.
:param file_name: The base file to generate a back up file name for.
:param file_map: The file_map for the FileManagement system
:return: str
"""
suffix, extension = file_name.split(".", 1)
for i in range(FileManagement.MAX_BACKUPS):
potential_name = suffix + "_" + str(i) + "." + extension
if potential_name not in file_map.values():
return potential_name
return None
@staticmethod
def _backup_file(file_name, file_path):
# type: (str, str) -> None
"""
Backs up the [file_name] located at [file_path] into the FileManagement's backup folder.
Leaves the backup file locked from writing privileges.
:param file_name: The file's name that will be backed up
:param file_path: The path to the file to back up
:return: None
"""
file_map = FileManagement._load_file_map()
backup_path = FileManagement.backup_folder_path
backup_file_name = "{}.bak".format(file_name)
backup_file = os.path.join(backup_path, backup_file_name)
# If backup directory DNE, make one
if not os.path.exists(backup_path):
os.mkdir(backup_path)
# If "traditional" backup file exists, delete it (myFile.txt.bak)
if os.path.exists(backup_file):
fs.delete([backup_file], True, False)
# Find my next storage name (myFile_1.txt.bak)
backup_storage_file_name = FileManagement._next_available_name(backup_file_name, file_map)
if backup_storage_file_name is None:
# If _next_available_name returns None, we have backed up MAX_BACKUPS of files name [file_name]
raise Exception(
"FileManagement class ran out of backups per name. Max: {}".format(FileManagement.MAX_BACKUPS)
)
backup_storage_file = os.path.join(backup_path, backup_storage_file_name)
if os.path.exists(backup_storage_file):
# This file should not exists, but if it does it's about to get clobbered!
fs.unlock_file(backup_storage_file)
# Create "traditional" backup file (myFile.txt.bak)
fs.create_backup(os.path.join(file_path, file_name), backup_path)
# Copy "traditional" backup file into storage backup (myFile_1.txt.bak)
FileManagement._copy_file(backup_file_name, backup_path, backup_storage_file_name, backup_path)
fs.lock_file(backup_storage_file)
# Delete "traditional" back up file
fs.unlock_file(backup_file)
fs.delete([backup_file], True, False)
# Update file map with new file
file_map[os.path.join(file_path, file_name)] = backup_storage_file_name
FileManagement._save_file_map(file_map)
# Unlock original file to get it ready to be edited by the test
fs.unlock_file(os.path.join(file_path, file_name))
@staticmethod
def _restore_file(file_name, file_path):
# type: (str, str) -> None
"""
Restores the [file_name] located at [file_path] which is backed up in FileManagement's backup folder.
Locks [file_name] from writing privileges when done restoring.
:param file_name: The Original file that was backed up, and now restored
:param file_path: The location of the original file that was backed up
:return: None
"""
file_map = FileManagement._load_file_map()
backup_path = FileManagement.backup_folder_path
src_file = os.path.join(file_path, file_name)
if src_file in file_map:
backup_file = os.path.join(backup_path, file_map[src_file])
if os.path.exists(backup_file):
fs.unlock_file(backup_file)
fs.unlock_file(src_file)
# Make temporary copy of backed up file to restore from
temp_file = "{}.bak".format(file_name)
FileManagement._copy_file(file_map[src_file], backup_path, temp_file, backup_path)
fs.restore_backup(src_file, backup_path)
fs.lock_file(src_file)
# Delete backup file
fs.delete([os.path.join(backup_path, temp_file)], True, False)
fs.delete([backup_file], True, False)
# Remove from file map
del file_map[src_file]
FileManagement._save_file_map(file_map)
if not os.listdir(backup_path):
# Delete backup folder if it's empty now
os.rmdir(backup_path)
@staticmethod
def _find_files(file_names, root_dir, search_subdirs=False):
# type: ([str], str, bool) -> {str:str}
"""
Searches the [root_dir] directory tree for each of the file names in [file_names]. Returns a dictionary
where keys = the entries in file_names, and their values are the paths they were found at.
Raises a runtime warning if not exactly one copy of each file is found.
:param file_names: A list of file_names to look for
:param root_dir: The root directory to begin the search
collect all file paths matching that file_name
:param search_subdirs: Optional boolean flag for searching sub-directories of [parent_path]
:return: A dictionary where keys are file names, and values are the file's path.
"""
file_list = {}
found_count = 0
for file_name in file_names:
file_list[file_name] = None
if search_subdirs:
# Search parent path for all file name arguments
for dir_path, _, dir_files in os.walk(root_dir):
for dir_file in dir_files:
if dir_file in file_list.keys():
if file_list[dir_file] is None:
file_list[dir_file] = dir_path
found_count += 1
else:
# Found multiple files with same name. Raise warning.
raise RuntimeWarning("Found multiple files with the name {}.".format(dir_file))
else:
for dir_file in os.listdir(root_dir):
if os.path.isfile(os.path.join(root_dir, dir_file)) and dir_file in file_names:
file_list[dir_file] = root_dir
not_found = [file_name for file_name in file_names if file_list[file_name] is None]
if not_found:
raise RuntimeWarning("Could not find the following files: {}".format(not_found))
return file_list
@staticmethod
def _copy_file(src_file, src_path, target_file, target_path):
# type: (str, str, str, str) -> None
"""
Copies the [src_file] at located in [src_path] to the [target_file] located at [target_path].
Leaves the [target_file] unlocked for reading and writing privileges
:param src_file: The source file to copy (file name)
:param src_path: The source file's path
:param target_file: The target file to copy into (file name)
:param target_path: The target file's path
:return: None
"""
target_file_path = os.path.join(target_path, target_file)
src_file_path = os.path.join(src_path, src_file)
if os.path.exists(target_file_path):
fs.unlock_file(target_file_path)
shutil.copyfile(src_file_path, target_file_path)
@staticmethod
def file_revert(file_name, parent_path=None, search_subdirs=False):
# type: (str, str, bool) -> function
"""
Function decorator:
Convenience version of file_revert_list for passing a single file
Calls file_revert_list on a list one [file_name]
:param file_name: The name of a file to backup (not path)
:param parent_path: The root directory to search for the [file_names] (relative to the dev folder).
Defaults to the project folder described by the inner function's workspace fixture
:param search_subdirs: A boolean option for searching sub-directories for the files in [file_names]
:return: function as per the function decorator pattern
"""
return FileManagement.file_revert_list([file_name], parent_path, search_subdirs)
@staticmethod
def file_revert_list(file_names, parent_path=None, search_subdirs=False):
# type: ([str], str, bool) -> function
"""
Function decorator:
Collects file names specified in [file_names] in the [parent_path] directory.
Backs up these files before executing the parameter to the "wrap" function.
If the search_subdirs flag is True, searches all subdirectories of [parent_path] for files.
:param file_names: A list of file names (not paths)
:param parent_path: The root directory to search for the [file_names] (relative to the dev folder).
Defaults to the project folder described by the inner function's workspace fixture
:param search_subdirs: A boolean option for searching sub-directories for the files in [file_names]
:return: function as per the function decorator pattern
"""
def wrap(func):
# type: (function) -> function
def inner(self, request, workspace, editor, launcher_platform):
# type: (...) -> None
"""
Inner function to wrap around decorated function. Function being decorated must match this
functions parameter order.
"""
root_path = parent_path
if root_path is not None:
root_path = os.path.join(workspace.paths.dev(), root_path)
else:
# Default to project folder (AutomatedTesting)
root_path = workspace.paths.project()
# Try to locate files
try:
file_list = FileManagement._find_files(file_names, root_path, search_subdirs)
except RuntimeWarning as w:
assert False, (
w.message
+ " Please check use of search_subdirs; make sure you are using the correct parent directory."
)
# Restore from backups
for file_name, file_path in file_list.items():
FileManagement._restore_file(file_name, file_path)
# Create backups for each discovered path for each specified filename
for file_name, file_path in file_list.items():
FileManagement._backup_file(file_name, file_path)
try:
# Run the test
func(self, request, workspace, editor, launcher_platform)
finally:
# Restore backups for each discovered path for each specified filename if they exist
for file_name, file_path in file_list.items():
FileManagement._restore_file(file_name, file_path)
return inner
return wrap
@staticmethod
def file_override(target_file, src_file, parent_path=None, search_subdirs=False):
# type: (str, str, str, bool) -> function
"""
Function decorator:
Searches for [target_file] and [src_file] in [parent_path](relative to the project dev folder)
and performs backup and file swapping. [target_file] is backed up and replaced with [src_file] before the
decorated function executes.
After the decorated function is executed [target_file] is restored to the state before being swapped.
If [parent_path] is not specified, the project folder described by the current workspace will be used.
If the search_subdirs flag is True, searches all subdirectories of [parent_path] for files.
:param target_file: The name of the file being backed up and swapped into
:param src_file: The name of the file to swap into [target_file]
:param parent_path: The root directory to search for the [file_names] (relative to the dev folder).
Defaults to the project folder described by the inner function's workspace fixture
:param search_subdirs: A boolean option for searching sub-directories for the files in [file_names]
:return: The decorated function
"""
def wrap(func):
def inner(self, request, workspace, editor, launcher_platform):
"""
Inner function to wrap around decorated function. Function being decorated must match this
functions parameter order.
"""
root_path = parent_path
if root_path is not None:
root_path = os.path.join(workspace.paths.dev(), root_path)
else:
# Default to project folder (AutomatedTesting)
root_path = workspace.paths.project()
# Try to locate both target and source files
try:
file_list = FileManagement._find_files([target_file, src_file], root_path, search_subdirs)
except RuntimeWarning as w:
assert False, (
w.message
+ " Please check use of search_subdirs; make sure you are using the correct parent directory."
)
FileManagement._restore_file(target_file, file_list[target_file])
FileManagement._backup_file(target_file, file_list[target_file])
FileManagement._copy_file(src_file, file_list[src_file], target_file, file_list[target_file])
try:
# Run Test
func(self, request, workspace, editor, launcher_platform)
finally:
FileManagement._restore_file(target_file, file_list[target_file])
return inner
return wrap
@@ -0,0 +1,15 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
def init():
import os
import sys
sys.path.append(os.path.dirname(os.path.abspath(__file__)) + '/../automatedtesting_shared')
@@ -0,0 +1,40 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
# This suite consists of all test cases that are passing and have been verified.
import pytest
import sys
import os
from .FileManagement import FileManagement as fm
from ly_test_tools import LAUNCHERS
sys.path.append(os.path.dirname(os.path.abspath(__file__)) + '/../automatedtesting_shared')
from base import TestAutomationBase
@pytest.mark.SUITE_main
@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
@pytest.mark.parametrize("project", ["AutomatedTesting"])
class TestAutomation(TestAutomationBase):
def test_C28798177_WhiteBox_AddComponentToEntity(self, request, workspace, editor, launcher_platform):
from . import C28798177_WhiteBox_AddComponentToEntity as test_module
self._run_test(request, workspace, editor, test_module)
def test_C29279329_WhiteBox_SetDefaultShape(self, request, workspace, editor, launcher_platform):
from . import C29279329_WhiteBox_SetDefaultShape as test_module
self._run_test(request, workspace, editor, test_module)
def test_C28798205_WhiteBox_SetInvisible(self, request, workspace, editor, launcher_platform):
from . import C28798205_WhiteBox_SetInvisible as test_module
self._run_test(request, workspace, editor, test_module)
@@ -0,0 +1,10 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
@@ -0,0 +1,36 @@
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
add_subdirectory(asset_processor_tests)
if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS)
## AP Python Tests ##
ly_add_pytest(
NAME AssetPipelineTests.AuxiliaryContent
PATH ${CMAKE_CURRENT_LIST_DIR}/auxiliary_content_tests/auxiliary_content_tests.py
EXCLUDE_TEST_RUN_TARGET_FROM_IDE
TEST_SUITE periodic
)
ly_add_pytest(
NAME AssetPipelineTests.BankInfoParser
PATH ${CMAKE_CURRENT_LIST_DIR}/wwise_bank_dependency_tests/bank_info_parser_tests.py
EXCLUDE_TEST_RUN_TARGET_FROM_IDE
TEST_SUITE periodic
RUNTIME_DEPENDENCIES
AZ::AssetProcessorBatch
)
endif()
@@ -0,0 +1,10 @@
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
@@ -0,0 +1,10 @@
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
@@ -0,0 +1,43 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Fixture for organizing directories associated with tests that involve assets for all platforms
"""
# Import builtin libraries
import pytest
import os
from typing import Dict
from . import ap_setup_fixture as ap_setup_fixture
@pytest.fixture
def ap_all_platforms_setup_fixture(request, workspace, ap_setup_fixture) -> Dict[str, str]:
dev_dir = os.path.join(workspace.paths.dev())
cache_dir = os.path.join(dev_dir, "Cache")
# add some useful locations
resources = ap_setup_fixture
# Current project's current platform's cache
resources["platform_cache"] = os.path.join(workspace.paths.platform_cache(), workspace.project.lower())
# Specific platform cache locations
resources["pc_cache_location"] = os.path.join(cache_dir, workspace.project, "pc")
resources["es3_cache_location"] = os.path.join(cache_dir, workspace.project, "es3")
resources["ios_cache_location"] = os.path.join(cache_dir, workspace.project, "ios")
resources["osx_gl_cache_location"] = os.path.join(cache_dir, workspace.project, "osx_gl")
resources["provo_cache_location"] = os.path.join(cache_dir, workspace.project, "provo")
resources["all_platforms"] = ["pc", "es3", "ios", "osx_gl", "provo"]
return resources
@@ -0,0 +1,27 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Fixture for backing up and restoring dev/AssetProcessorPlatformConfig.ini
"""
# Import builtin libraries
import pytest
@pytest.fixture
def ap_config_backup_fixture(request, workspace) -> None:
workspace.settings._backup_settings(workspace.paths.asset_processor_config_file(), None)
def teardown():
workspace.settings._restore_settings(workspace.paths.asset_processor_config_file(), None)
request.addfinalizer(teardown)

Some files were not shown because too many files have changed in this diff Show More