Merge branch 'blender-v4.5-release'
This commit is contained in:
@@ -73,8 +73,8 @@ function(add_blender_test_io testname)
|
||||
endfunction()
|
||||
|
||||
if(WITH_UI_TESTS)
|
||||
set(_blender_headless_env_vars "BLENDER_BIN=${TEST_BLENDER_EXE}")
|
||||
if(WITH_UI_TESTS_HEADLESS)
|
||||
set(_blender_headless_env_vars "BLENDER_BIN=${TEST_BLENDER_EXE}")
|
||||
|
||||
# Currently only WAYLAND is supported, support for others may be added later.
|
||||
# In this case none of the WESTON environment variables will be used.
|
||||
@@ -104,43 +104,29 @@ if(WITH_UI_TESTS)
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
function(add_blender_test_ui testname)
|
||||
# Remove `--background` so headless execution uses a GUI
|
||||
# (within a headless graphical environment).
|
||||
set(EXE_PARAMS ${TEST_BLENDER_EXE_PARAMS})
|
||||
list(REMOVE_ITEM EXE_PARAMS --background)
|
||||
add_blender_test_impl(
|
||||
"${testname}"
|
||||
"${_blender_headless_env_vars}"
|
||||
"${TEST_PYTHON_EXE}"
|
||||
"${CMAKE_SOURCE_DIR}/tests/utils/blender_headless.py"
|
||||
# NOTE: attempting to maximize the window causes problems with a headless `weston`,
|
||||
# while this could be investigated, use windowed mode instead.
|
||||
# Use a window size that balances software GPU rendering with enough room to use the UI.
|
||||
--factory-startup
|
||||
-p 0 0 800 600
|
||||
"${EXE_PARAMS}"
|
||||
"${ARGN}"
|
||||
)
|
||||
endfunction()
|
||||
else()
|
||||
function(add_blender_test_ui testname)
|
||||
# Remove `--background`
|
||||
set(EXE_PARAMS ${TEST_BLENDER_EXE_PARAMS})
|
||||
list(REMOVE_ITEM EXE_PARAMS --background)
|
||||
|
||||
add_blender_test_impl(
|
||||
"${testname}"
|
||||
""
|
||||
"${TEST_BLENDER_EXE}"
|
||||
--factory-startup
|
||||
-p 0 0 800 600
|
||||
${EXE_PARAMS}
|
||||
${ARGN}
|
||||
)
|
||||
endfunction()
|
||||
list(APPEND _blender_headless_env_vars
|
||||
"PASS_THROUGH=1"
|
||||
)
|
||||
endif()
|
||||
function(add_blender_test_ui testname)
|
||||
# Remove `--background`a
|
||||
set(EXE_PARAMS ${TEST_BLENDER_EXE_PARAMS})
|
||||
list(REMOVE_ITEM EXE_PARAMS --background)
|
||||
add_blender_test_impl(
|
||||
"${testname}"
|
||||
"${_blender_headless_env_vars}"
|
||||
"${TEST_PYTHON_EXE}"
|
||||
"${CMAKE_SOURCE_DIR}/tests/utils/blender_headless.py"
|
||||
# NOTE: attempting to maximize the window causes problems with a headless `weston`,
|
||||
# while this could be investigated, use windowed mode instead.
|
||||
# Use a window size that balances software GPU rendering with enough room to use the UI.
|
||||
--factory-startup
|
||||
-p 0 0 800 600
|
||||
"${EXE_PARAMS}"
|
||||
"${ARGN}"
|
||||
)
|
||||
endfunction()
|
||||
endif()
|
||||
|
||||
# Run Python script outside Blender.
|
||||
@@ -1298,7 +1284,12 @@ if(WITH_UI_TESTS)
|
||||
# This could be generated with:
|
||||
# `"${TEST_PYTHON_EXE}" "${CMAKE_CURRENT_LIST_DIR}/ui_simulate/run.py" --list-tests`
|
||||
# list explicitly so changes bisecting/updated are sure to re-run CMake.
|
||||
set(_undo_tests
|
||||
set(_ui_tests
|
||||
test_workspace.sanity_check_general
|
||||
test_workspace.sanity_check_2d_animation
|
||||
test_workspace.sanity_check_sculpting
|
||||
test_workspace.sanity_check_vfx
|
||||
test_workspace.sanity_check_video_editing
|
||||
test_undo.text_editor_edit_mode_mix
|
||||
test_undo.text_editor_simple
|
||||
test_undo.view3d_edit_mode_multi_window
|
||||
@@ -1316,7 +1307,7 @@ if(WITH_UI_TESTS)
|
||||
test_undo.view3d_texture_paint_complex
|
||||
test_undo.view3d_texture_paint_simple
|
||||
)
|
||||
foreach(ui_test ${_undo_tests})
|
||||
foreach(ui_test ${_ui_tests})
|
||||
add_blender_test_ui(
|
||||
"ui_${ui_test}"
|
||||
--enable-event-simulate
|
||||
@@ -1325,7 +1316,7 @@ if(WITH_UI_TESTS)
|
||||
--tests "${ui_test}"
|
||||
)
|
||||
endforeach()
|
||||
unset(_undo_tests)
|
||||
unset(_ui_tests)
|
||||
endif()
|
||||
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ For an editor to follow the tests:
|
||||
|
||||
import os
|
||||
import sys
|
||||
import tempfile
|
||||
|
||||
|
||||
def create_parser():
|
||||
@@ -137,7 +138,7 @@ def _process_test_id_fn(env, args, test_id):
|
||||
return test_id, callproc.returncode == 0
|
||||
|
||||
|
||||
def main():
|
||||
def run(empty_user_dir):
|
||||
directory = os.path.dirname(__file__)
|
||||
if "--list-tests" in sys.argv:
|
||||
list_tests(directory)
|
||||
@@ -164,6 +165,7 @@ def main():
|
||||
env = os.environ.copy()
|
||||
env.update({
|
||||
"LSAN_OPTIONS": "exitcode=0",
|
||||
"BLENDER_USER_RESOURCES": empty_user_dir,
|
||||
})
|
||||
|
||||
# We could support multiple tests per Blender session.
|
||||
@@ -188,6 +190,13 @@ def main():
|
||||
for test_id, ok in results:
|
||||
print("OK: " if ok else "FAIL:", test_id)
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
def main():
|
||||
with tempfile.TemporaryDirectory() as empty_user_dir:
|
||||
sys.exit(run(empty_user_dir))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
174
tests/python/ui_simulate/test_workspace.py
Normal file
174
tests/python/ui_simulate/test_workspace.py
Normal file
@@ -0,0 +1,174 @@
|
||||
# SPDX-FileCopyrightText: 2025 Blender Authors
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
"""
|
||||
This file does not run anything, it's methods are accessed for tests by: ``run.py``.
|
||||
"""
|
||||
|
||||
|
||||
def _test_window(windows_exclude=None):
|
||||
import bpy
|
||||
wm = bpy.data.window_managers[0]
|
||||
if windows_exclude is None:
|
||||
return wm.windows[0]
|
||||
for window in wm.windows:
|
||||
if window not in windows_exclude:
|
||||
return window
|
||||
return None
|
||||
|
||||
|
||||
def _test_vars(window):
|
||||
import unittest
|
||||
from modules.easy_keys import EventGenerate
|
||||
return (
|
||||
EventGenerate(window),
|
||||
unittest.TestCase(),
|
||||
)
|
||||
|
||||
|
||||
def _call_by_name(e, text: str):
|
||||
yield e.f3()
|
||||
yield e.text(text)
|
||||
yield e.ret()
|
||||
|
||||
|
||||
def _call_menu(e, text: str):
|
||||
yield e.f3()
|
||||
yield e.text_unicode(text.replace(" -> ", " \u25b8 "))
|
||||
yield e.ret()
|
||||
|
||||
|
||||
def sanity_check_general():
|
||||
e, t = _test_vars(window := _test_window())
|
||||
|
||||
yield from _call_by_name(e, "Add Workspace")
|
||||
yield e.g() # General
|
||||
yield e.a() # Animation
|
||||
t.assertEqual(window.workspace.name_full.split(".", 1)[0], "Animation")
|
||||
|
||||
yield from _call_by_name(e, "Add Workspace")
|
||||
yield e.g() # General
|
||||
yield e.c() # Compositing
|
||||
t.assertEqual(window.workspace.name_full.split(".", 1)[0], "Compositing")
|
||||
|
||||
yield from _call_by_name(e, "Add Workspace")
|
||||
yield e.g() # General
|
||||
yield e.g() # Geometry Nodes
|
||||
t.assertEqual(window.workspace.name_full.split(".", 1)[0], "Geometry Nodes")
|
||||
|
||||
yield from _call_by_name(e, "Add Workspace")
|
||||
yield e.g() # General
|
||||
yield e.l() # Layout
|
||||
t.assertEqual(window.workspace.name_full.split(".", 1)[0], "Layout")
|
||||
|
||||
yield from _call_by_name(e, "Add Workspace")
|
||||
yield e.g() # General
|
||||
yield e.m() # Modeling
|
||||
t.assertEqual(window.workspace.name_full.split(".", 1)[0], "Modeling")
|
||||
|
||||
yield from _call_by_name(e, "Add Workspace")
|
||||
yield e.g() # General
|
||||
yield e.r() # Rendering
|
||||
t.assertEqual(window.workspace.name_full.split(".", 1)[0], "Rendering")
|
||||
|
||||
yield from _call_by_name(e, "Add Workspace")
|
||||
yield e.g() # General
|
||||
yield e.s() # Scripting
|
||||
t.assertEqual(window.workspace.name_full.split(".", 1)[0], "Scripting")
|
||||
|
||||
yield from _call_by_name(e, "Add Workspace")
|
||||
yield e.g() # General
|
||||
yield e.p() # Sculpting
|
||||
t.assertEqual(window.workspace.name_full.split(".", 1)[0], "Sculpting")
|
||||
|
||||
yield from _call_by_name(e, "Add Workspace")
|
||||
yield e.g() # General
|
||||
yield e.h() # Shading
|
||||
t.assertEqual(window.workspace.name_full.split(".", 1)[0], "Shading")
|
||||
|
||||
yield from _call_by_name(e, "Add Workspace")
|
||||
yield e.g() # General
|
||||
yield e.t() # Texture Paint
|
||||
t.assertEqual(window.workspace.name_full.split(".", 1)[0], "Texture Paint")
|
||||
|
||||
yield from _call_by_name(e, "Add Workspace")
|
||||
yield e.g() # General
|
||||
yield e.u() # UV Editing
|
||||
t.assertEqual(window.workspace.name_full.split(".", 1)[0], "UV Editing")
|
||||
|
||||
|
||||
def sanity_check_2d_animation():
|
||||
e, t = _test_vars(window := _test_window())
|
||||
|
||||
yield from _call_by_name(e, "Add Workspace")
|
||||
yield e.d() # 2D Animation
|
||||
yield e.d() # 2D Animation
|
||||
t.assertEqual(window.workspace.name_full.split(".", 1)[0], "2D Animation")
|
||||
|
||||
yield from _call_by_name(e, "Add Workspace")
|
||||
yield e.d() # 2D Animation
|
||||
yield e.f() # 2D Full Canvas
|
||||
t.assertEqual(window.workspace.name_full.split(".", 1)[0], "2D Full Canvas")
|
||||
|
||||
yield from _call_by_name(e, "Add Workspace")
|
||||
yield e.d() # 2D Animation
|
||||
yield e.c() # Compositing
|
||||
t.assertEqual(window.workspace.name_full.split(".", 1)[0], "Compositing")
|
||||
|
||||
yield from _call_by_name(e, "Add Workspace")
|
||||
yield e.d() # 2D Animation
|
||||
yield e.r() # Rendering
|
||||
t.assertEqual(window.workspace.name_full.split(".", 1)[0], "Rendering")
|
||||
|
||||
|
||||
def sanity_check_sculpting():
|
||||
e, t = _test_vars(window := _test_window())
|
||||
|
||||
yield from _call_by_name(e, "Add Workspace")
|
||||
yield e.s() # Sculpting
|
||||
yield e.s() # Sculpting
|
||||
t.assertEqual(window.workspace.name_full.split(".", 1)[0], "Sculpting")
|
||||
|
||||
yield from _call_by_name(e, "Add Workspace")
|
||||
yield e.s() # Sculpting
|
||||
yield e.h() # Shading
|
||||
t.assertEqual(window.workspace.name_full.split(".", 1)[0], "Shading")
|
||||
|
||||
|
||||
def sanity_check_vfx():
|
||||
e, t = _test_vars(window := _test_window())
|
||||
|
||||
yield from _call_by_name(e, "Add Workspace")
|
||||
yield e.v() # VFX
|
||||
yield e.c() # Compositing
|
||||
t.assertEqual(window.workspace.name_full.split(".", 1)[0], "Compositing")
|
||||
|
||||
yield from _call_by_name(e, "Add Workspace")
|
||||
yield e.v() # VFX
|
||||
yield e.m() # Masking
|
||||
t.assertEqual(window.workspace.name_full.split(".", 1)[0], "Masking")
|
||||
|
||||
yield from _call_by_name(e, "Add Workspace")
|
||||
yield e.v() # VFX
|
||||
yield e.t() # Motion Tracking
|
||||
t.assertEqual(window.workspace.name_full.split(".", 1)[0], "Motion Tracking")
|
||||
|
||||
yield from _call_by_name(e, "Add Workspace")
|
||||
yield e.v() # VFX
|
||||
yield e.r() # Rendering
|
||||
t.assertEqual(window.workspace.name_full.split(".", 1)[0], "Rendering")
|
||||
|
||||
|
||||
def sanity_check_video_editing():
|
||||
e, t = _test_vars(window := _test_window())
|
||||
|
||||
yield from _call_by_name(e, "Add Workspace")
|
||||
yield e.e() # Video Editing
|
||||
yield e.r() # Rendering
|
||||
t.assertEqual(window.workspace.name_full.split(".", 1)[0], "Rendering")
|
||||
|
||||
yield from _call_by_name(e, "Add Workspace")
|
||||
yield e.e() # Video Editing
|
||||
yield e.v() # Video Editing
|
||||
t.assertEqual(window.workspace.name_full.split(".", 1)[0], "Video Editing")
|
||||
Reference in New Issue
Block a user