diff options
Diffstat (limited to 'source/tests')
-rw-r--r-- | source/tests/CMakeLists.txt | 253 | ||||
-rw-r--r-- | source/tests/bl_test.py | 195 | ||||
-rw-r--r-- | source/tests/pep8.py | 101 | ||||
-rw-r--r-- | source/tests/rna_array.py | 297 | ||||
-rw-r--r-- | source/tests/rna_info_dump.py | 131 |
5 files changed, 977 insertions, 0 deletions
diff --git a/source/tests/CMakeLists.txt b/source/tests/CMakeLists.txt new file mode 100644 index 00000000000..f0771f5fa0f --- /dev/null +++ b/source/tests/CMakeLists.txt @@ -0,0 +1,253 @@ +# -*- mode: cmake; indent-tabs-mode: t; -*- +# $Id: CMakeLists.txt 34198 2011-01-09 15:12:08Z campbellbarton $ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# Contributor(s): Jacques Beaurain. +# +# ***** END GPL LICENSE BLOCK ***** + +# --env-system-scripts allows to run without WITH_INSTALL + +# Use '--write-blend=/tmp/test.blend' to view output + + +set(TEST_SRC_DIR ${CMAKE_SOURCE_DIR}/../lib/tests) +set(TEST_OUT_DIR ${CMAKE_BINARY_DIR}/tests) + +#~ if(NOT IS_DIRECTORY ${TEST_SRC_DIR}) +#~ message(FATAL_ERROR "CMake test directory not found!") +#~ endif() + +# all calls to blender use this +set(GENERIC_ARGS --background --factory-startup --env-system-scripts ${CMAKE_SOURCE_DIR}/release/scripts) + + +# OBJ Import tests +add_test(import_obj_cube ${EXECUTABLE_OUTPUT_PATH}/blender ${GENERIC_ARGS} + --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py -- + --run={'FINISHED'}&bpy.ops.import_scene.obj\(filepath='${TEST_SRC_DIR}/io_tests/obj/cube.obj'\) + --md5=4d090508b812b5e08168aa2614746bda --md5_method=SCENE +) + +add_test(import_obj_nurbs_cyclic ${EXECUTABLE_OUTPUT_PATH}/blender ${GENERIC_ARGS} + --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py -- + --run={'FINISHED'}&bpy.ops.import_scene.obj\(filepath='${TEST_SRC_DIR}/io_tests/obj/nurbs_cyclic.obj'\) + --md5=9e0da7b65b4c4f818a203d56af2d3a4b --md5_method=SCENE + --write-blend=/root/foo99.blend +) + +add_test(import_obj_makehuman ${EXECUTABLE_OUTPUT_PATH}/blender ${GENERIC_ARGS} + --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py -- + --run={'FINISHED'}&bpy.ops.import_scene.obj\(filepath='${TEST_SRC_DIR}/io_tests/obj/makehuman.obj'\) + --md5=e0829dc078b0789e1d81f1071235bc4f --md5_method=SCENE +) + +# OBJ Export tests +add_test(export_obj_cube ${EXECUTABLE_OUTPUT_PATH}/blender ${GENERIC_ARGS} + ${TEST_SRC_DIR}/io_tests/blend_geometry/all_quads.blend + --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py -- + --run={'FINISHED'}&bpy.ops.export_scene.obj\(filepath='${TEST_OUT_DIR}/export_obj_cube.obj',use_selection=False\) + --md5_source=${TEST_OUT_DIR}/export_obj_cube.obj + --md5_source=${TEST_OUT_DIR}/export_obj_cube.mtl + --md5=70bdc394c2726203ad26c085176e3484 --md5_method=FILE +) + +add_test(export_obj_nurbs ${EXECUTABLE_OUTPUT_PATH}/blender ${GENERIC_ARGS} + ${TEST_SRC_DIR}/io_tests/blend_geometry/nurbs.blend + --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py -- + --run={'FINISHED'}&bpy.ops.export_scene.obj\(filepath='${TEST_OUT_DIR}/export_obj_nurbs.obj',use_selection=False,use_nurbs=True\) + --md5_source=${TEST_OUT_DIR}/export_obj_nurbs.obj + --md5_source=${TEST_OUT_DIR}/export_obj_nurbs.mtl + --md5=a733ae4fa4a591ea9b0912da3af042de --md5_method=FILE +) + +add_test(export_obj_all_objects ${EXECUTABLE_OUTPUT_PATH}/blender ${GENERIC_ARGS} + ${TEST_SRC_DIR}/io_tests/blend_scene/all_objects.blend + --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py -- + --run={'FINISHED'}&bpy.ops.export_scene.obj\(filepath='${TEST_OUT_DIR}/export_obj_all_objects.obj',use_selection=False,use_nurbs=True\) + --md5_source=${TEST_OUT_DIR}/export_obj_all_objects.obj + --md5_source=${TEST_OUT_DIR}/export_obj_all_objects.mtl + --md5=6e033a6a9c923d7aa3613b36e373f55b --md5_method=FILE +) + + + +# PLY Import tests +add_test(import_ply_cube ${EXECUTABLE_OUTPUT_PATH}/blender ${GENERIC_ARGS} + --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py -- + --run={'FINISHED'}&bpy.ops.import_mesh.ply\(filepath='${TEST_SRC_DIR}/io_tests/ply/cube_ascii.ply'\) + --md5=527134343c27fc0ea73115b85fbfd3ac --md5_method=SCENE +) + +add_test(import_ply_bunny ${EXECUTABLE_OUTPUT_PATH}/blender ${GENERIC_ARGS} + --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py -- + --run={'FINISHED'}&bpy.ops.import_mesh.ply\(filepath='${TEST_SRC_DIR}/io_tests/ply/bunny2.ply'\) + --md5=6ea5b8533400a17accf928b8fd024eaa --md5_method=SCENE +) + +add_test(import_ply_small_holes ${EXECUTABLE_OUTPUT_PATH}/blender ${GENERIC_ARGS} + --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py -- + --run={'FINISHED'}&bpy.ops.import_mesh.ply\(filepath='${TEST_SRC_DIR}/io_tests/ply/many_small_holes.ply'\) + --md5=c3093e26ecae5b6d59fbbcf2a0d0b39f --md5_method=SCENE +) + +# PLY Export tests (TODO) + + + +# STL Import tests +add_test(import_stl_cube ${EXECUTABLE_OUTPUT_PATH}/blender ${GENERIC_ARGS} + --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py -- + --run={'FINISHED'}&bpy.ops.import_mesh.stl\(filepath='${TEST_SRC_DIR}/io_tests/stl/cube.stl'\) + --md5=8ceb5bb7e1cb5f4342fa1669988c66b4 --md5_method=SCENE +) + +add_test(import_stl_conrod ${EXECUTABLE_OUTPUT_PATH}/blender ${GENERIC_ARGS} + --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py -- + --run={'FINISHED'}&bpy.ops.import_mesh.stl\(filepath='${TEST_SRC_DIR}/io_tests/stl/conrod.stl'\) + --md5=690a4b8eb9002dcd8631c5a575ea7348 --md5_method=SCENE +) + +add_test(import_stl_knot_max_simplified ${EXECUTABLE_OUTPUT_PATH}/blender ${GENERIC_ARGS} + --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py -- + --run={'FINISHED'}&bpy.ops.import_mesh.stl\(filepath='${TEST_SRC_DIR}/io_tests/stl/knot_max_simplified.stl'\) + --md5=baf82803f45a84ec4ddbad9cef57dd3e --md5_method=SCENE +) + +# STL Export tests (TODO) + + + +# X3D Import +add_test(import_x3d_cube ${EXECUTABLE_OUTPUT_PATH}/blender ${GENERIC_ARGS} + --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py -- + --run={'FINISHED'}&bpy.ops.import_scene.x3d\(filepath='${TEST_SRC_DIR}/io_tests/x3d/color_cube.x3d'\) + --md5=c80538e272812c9d765d43df269d8a9b --md5_method=SCENE +) + +add_test(import_x3d_teapot ${EXECUTABLE_OUTPUT_PATH}/blender ${GENERIC_ARGS} + --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py -- + --run={'FINISHED'}&bpy.ops.import_scene.x3d\(filepath='${TEST_SRC_DIR}/io_tests/x3d/teapot.x3d'\) + --md5=fa19713ff71d4b3893dcbe0ab3a73955 --md5_method=SCENE + --write-blend=/root/foo99.blend +) + +add_test(import_x3d_suzanne_material ${EXECUTABLE_OUTPUT_PATH}/blender ${GENERIC_ARGS} + --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py -- + --run={'FINISHED'}&bpy.ops.import_scene.x3d\(filepath='${TEST_SRC_DIR}/io_tests/x3d/suzanne_material.x3d'\) + --md5=52a59dcf731904ac49953dd82c020ae5 --md5_method=SCENE +) + +# X3D Export +add_test(export_x3d_cube ${EXECUTABLE_OUTPUT_PATH}/blender ${GENERIC_ARGS} + ${TEST_SRC_DIR}/io_tests/blend_geometry/all_quads.blend + --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py -- + --run={'FINISHED'}&bpy.ops.export_scene.x3d\(filepath='${TEST_OUT_DIR}/export_x3d_cube.x3d',use_selection=False\) + --md5_source=${TEST_OUT_DIR}/export_x3d_cube.x3d + --md5=560ba3762a6604669994f661235ef93c --md5_method=FILE +) + +add_test(export_x3d_nurbs ${EXECUTABLE_OUTPUT_PATH}/blender ${GENERIC_ARGS} + ${TEST_SRC_DIR}/io_tests/blend_geometry/nurbs.blend + --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py -- + --run={'FINISHED'}&bpy.ops.export_scene.x3d\(filepath='${TEST_OUT_DIR}/export_x3d_nurbs.x3d',use_selection=False\) + --md5_source=${TEST_OUT_DIR}/export_x3d_nurbs.x3d + --md5=078c0ca5a08f123cd2cdac48afb54853 --md5_method=FILE +) + +add_test(export_x3d_all_objects ${EXECUTABLE_OUTPUT_PATH}/blender ${GENERIC_ARGS} + ${TEST_SRC_DIR}/io_tests/blend_scene/all_objects.blend + --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py -- + --run={'FINISHED'}&bpy.ops.export_scene.x3d\(filepath='${TEST_OUT_DIR}/export_x3d_all_objects.x3d',use_selection=False\) + --md5_source=${TEST_OUT_DIR}/export_x3d_all_objects.x3d + --md5=b4bddb55efd8e34af673ffb42bf4c372 --md5_method=FILE +) + + + +# 3DS Import +add_test(import_3ds_cube ${EXECUTABLE_OUTPUT_PATH}/blender ${GENERIC_ARGS} + --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py -- + --run={'FINISHED'}&bpy.ops.import_scene.autodesk_3ds\(filepath='${TEST_SRC_DIR}/io_tests/3ds/cube.3ds'\) + --md5=cb5a45c35a343c3f5beca2a918472951 --md5_method=SCENE +) + +add_test(import_3ds_hierarchy_lara ${EXECUTABLE_OUTPUT_PATH}/blender ${GENERIC_ARGS} + --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py -- + --run={'FINISHED'}&bpy.ops.import_scene.autodesk_3ds\(filepath='${TEST_SRC_DIR}/io_tests/3ds/hierarchy_lara.3ds'\) + --md5=2e9812099b26ad607fdcf4c7be918c71 --md5_method=SCENE + --write-blend=/root/foo99.blend +) + +add_test(import_3ds_hierarchy_greek_trireme ${EXECUTABLE_OUTPUT_PATH}/blender ${GENERIC_ARGS} + --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py -- + --run={'FINISHED'}&bpy.ops.import_scene.autodesk_3ds\(filepath='${TEST_SRC_DIR}/io_tests/3ds/hierarchy_greek_trireme.3ds'\) + --md5=d05b922d7be20356d8409d1f768a3a9a --md5_method=SCENE +) + +# 3DS Export +add_test(export_3ds_cube ${EXECUTABLE_OUTPUT_PATH}/blender ${GENERIC_ARGS} + ${TEST_SRC_DIR}/io_tests/blend_geometry/all_quads.blend + --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py -- + --run={'FINISHED'}&bpy.ops.export_scene.autodesk_3ds\(filepath='${TEST_OUT_DIR}/export_3ds_cube.3ds',use_selection=False\) + --md5_source=${TEST_OUT_DIR}/export_3ds_cube.3ds + --md5=0df6cfb130052d01e31ef77d391d4cc0 --md5_method=FILE +) + +add_test(export_3ds_nurbs ${EXECUTABLE_OUTPUT_PATH}/blender ${GENERIC_ARGS} + ${TEST_SRC_DIR}/io_tests/blend_geometry/nurbs.blend + --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py -- + --run={'FINISHED'}&bpy.ops.export_scene.autodesk_3ds\(filepath='${TEST_OUT_DIR}/export_3ds_nurbs.3ds',use_selection=False\) + --md5_source=${TEST_OUT_DIR}/export_3ds_nurbs.3ds + --md5=ba1a6d43346fee3bcadc7e30e3c95935 --md5_method=FILE +) + +add_test(export_3ds_all_objects ${EXECUTABLE_OUTPUT_PATH}/blender ${GENERIC_ARGS} + ${TEST_SRC_DIR}/io_tests/blend_scene/all_objects.blend + --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py -- + --run={'FINISHED'}&bpy.ops.export_scene.autodesk_3ds\(filepath='${TEST_OUT_DIR}/export_3ds_all_objects.3ds',use_selection=False\) + --md5_source=${TEST_OUT_DIR}/export_3ds_all_objects.3ds + --md5=1523ca2e31cf7d781c7de1e17bd14520 --md5_method=FILE +) + + + +# FBX Export +# 'use_metadata=False' for reliable md5's +add_test(export_fbx_cube ${EXECUTABLE_OUTPUT_PATH}/blender ${GENERIC_ARGS} + ${TEST_SRC_DIR}/io_tests/blend_geometry/all_quads.blend + --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py -- + --run={'FINISHED'}&bpy.ops.export_scene.fbx\(filepath='${TEST_OUT_DIR}/export_fbx_cube.fbx',use_selection=False,use_metadata=False\) + --md5_source=${TEST_OUT_DIR}/export_fbx_cube.fbx + --md5=ce937e605e493958464d62e6de4a2f9f --md5_method=FILE +) + +add_test(export_fbx_nurbs ${EXECUTABLE_OUTPUT_PATH}/blender ${GENERIC_ARGS} + ${TEST_SRC_DIR}/io_tests/blend_geometry/nurbs.blend + --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py -- + --run={'FINISHED'}&bpy.ops.export_scene.fbx\(filepath='${TEST_OUT_DIR}/export_fbx_nurbs.fbx',use_selection=False,use_metadata=False\) + --md5_source=${TEST_OUT_DIR}/export_fbx_nurbs.fbx + --md5=e02f0147afba2a4ce1ae110567ac3531 --md5_method=FILE +) + +add_test(export_fbx_all_objects ${EXECUTABLE_OUTPUT_PATH}/blender ${GENERIC_ARGS} + ${TEST_SRC_DIR}/io_tests/blend_scene/all_objects.blend + --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py -- + --run={'FINISHED'}&bpy.ops.export_scene.fbx\(filepath='${TEST_OUT_DIR}/export_fbx_all_objects.fbx',use_selection=False,use_metadata=False\) + --md5_source=${TEST_OUT_DIR}/export_fbx_all_objects.fbx + --md5=c29a3aa600d2e432e4a521cc1e513ba8 --md5_method=FILE +) diff --git a/source/tests/bl_test.py b/source/tests/bl_test.py new file mode 100644 index 00000000000..86c5cf81e79 --- /dev/null +++ b/source/tests/bl_test.py @@ -0,0 +1,195 @@ +# ##### BEGIN GPL LICENSE BLOCK ##### +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ##### END GPL LICENSE BLOCK ##### + +# <pep8 compliant> + +import sys +import os + + +# may split this out into a new file +def replace_bpy_app_version(): + """ So MD5's are pradictable from output which uses blenders versions. + """ + + import bpy + + app = bpy.app + app_fake = type(bpy)("bpy.app") + + for attr in dir(app): + if not attr.startswith("_"): + setattr(app_fake, attr, getattr(app, attr)) + + app_fake.version = 0, 0, 0 + app_fake.version_string = "0.00 (sub 0)" + bpy.app = app_fake + + +def clear_startup_blend(): + import bpy + + for scene in bpy.data.scenes: + for obj in scene.objects: + scene.objects.unlink(obj) + + +def blend_to_md5(): + import bpy + scene = bpy.context.scene + ROUND = 4 + + def matrix2str(matrix): + return "".join([str(round(axis, ROUND)) for vector in matrix for axis in vector]).encode('ASCII') + + def coords2str(seq, attr): + return "".join([str(round(axis, ROUND)) for vertex in seq for axis in getattr(vertex, attr)]).encode('ASCII') + + import hashlib + + md5 = hashlib.new("md5") + md5_update = md5.update + + for obj in scene.objects: + md5_update(matrix2str(obj.matrix_world)) + data = obj.data + + if type(data) == bpy.types.Mesh: + md5_update(coords2str(data.vertices, "co")) + elif type(data) == bpy.types.Curve: + for spline in data.splines: + md5_update(coords2str(spline.bezier_points, "co")) + md5_update(coords2str(spline.points, "co")) + + return md5.hexdigest() + + +def main(): + argv = sys.argv + print(" args:", " ".join(argv)) + argv = argv[argv.index("--") + 1:] + + def arg_extract(arg, optional=True, array=False): + arg += "=" + if array: + value = [] + else: + value = None + + i = 0 + while i < len(argv): + if argv[i].startswith(arg): + item = argv[i][len(arg):] + del argv[i] + i -= 1 + + if array: + value.append(item) + else: + value = item + break + + i += 1 + + if (not value) and (not optional): + print(" '%s' not set" % arg) + sys.exit(1) + + return value + + run = arg_extract("--run", optional=False) + md5 = arg_extract("--md5", optional=False) + md5_method = arg_extract("--md5_method", optional=False) # 'SCENE' / 'FILE' + + # only when md5_method is 'FILE' + md5_source = arg_extract("--md5_source", optional=True, array=True) + + # save blend file, for testing + write_blend = arg_extract("--write-blend", optional=True) + + # ensure files are written anew + for f in md5_source: + if os.path.exists(f): + os.remove(f) + + import bpy + + replace_bpy_app_version() + if not bpy.data.filepath: + clear_startup_blend() + + print(" Running: '%s'" % run) + print(" MD5: '%s'!" % md5) + + try: + result = eval(run) + except: + import traceback + traceback.print_exc() + sys.exit(1) + + if write_blend is not None: + print(" Writing Blend: %s" % write_blend) + bpy.ops.wm.save_mainfile(filepath=write_blend, check_existing=False) + + print(" Result: '%s'" % str(result)) + if not result: + print(" Running: %s -> False" % run) + sys.exit(1) + + if md5_method == 'SCENE': + md5_new = blend_to_md5() + elif md5_method == 'FILE': + if not md5_source: + print(" Missing --md5_source argument") + sys.exit(1) + + for f in md5_source: + if not os.path.exists(f): + print(" Missing --md5_source=%r argument does not point to a file") + sys.exit(1) + + import hashlib + + md5_instance = hashlib.new("md5") + md5_update = md5_instance.update + + for f in md5_source: + md5_update(open(f, "rb").read()) + + md5_new = md5_instance.hexdigest() + + else: + print(" Invalid --md5_method=%s argument is not a valid source") + sys.exit(1) + + if md5 != md5_new: + print(" Running: %s\n MD5 Recieved: %s\n MD5 Expected: %s" % (run, md5_new, md5)) + sys.exit(1) + + print(" Success: %s" % run) + + +if __name__ == "__main__": + # So a python error exits(1) + try: + main() + except: + import traceback + traceback.print_exc() + sys.exit(1) diff --git a/source/tests/pep8.py b/source/tests/pep8.py new file mode 100644 index 00000000000..3ccd7dd79b6 --- /dev/null +++ b/source/tests/pep8.py @@ -0,0 +1,101 @@ +# ##### BEGIN GPL LICENSE BLOCK ##### +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ##### END GPL LICENSE BLOCK ##### + +# <pep8 compliant> + +import os + +# depends on pep8, pyflakes, pylint +# for ubuntu +# +# sudo apt-get install pylint pyflakes +# +# sudo apt-get install python-setuptools python-pip +# sudo pip install pep8 +# +# in debian install pylint pyflakes pep8 with apt-get/aptitude/etc +# +# on *nix run +# python release/test/pep8.py > pep8_error.txt 2>&1 + +# how many lines to read into the file, pep8 comment +# should be directly after the licence header, ~20 in most cases +PEP8_SEEK_COMMENT = 40 +SKIP_PREFIX = "./tools", "./config", "./scons", "./extern" + + +def file_list_py(path): + for dirpath, dirnames, filenames in os.walk(path): + for filename in filenames: + if filename.endswith(".py"): + yield os.path.join(dirpath, filename) + + +def is_pep8(path): + print(path) + f = open(path, 'r', encoding="utf8") + for i in range(PEP8_SEEK_COMMENT): + line = f.readline() + if line.startswith("# <pep8"): + if line.startswith("# <pep8 compliant>"): + return 1 + elif line.startswith("# <pep8-80 compliant>"): + return 2 + f.close() + return 0 + + +def main(): + files = [] + files_skip = [] + for f in file_list_py("."): + if [None for prefix in SKIP_PREFIX if f.startswith(prefix)]: + continue + + pep8_type = is_pep8(f) + + if pep8_type: + # so we can batch them for each tool. + files.append((os.path.abspath(f), pep8_type)) + else: + files_skip.append(f) + + print("\nSkipping...") + for f in files_skip: + print(" %s" % f) + + # pyflakes + print("\n\n\n# running pep8...") + for f, pep8_type in files: + if pep8_type == 1: + # E501:80 line length + os.system("pep8 --repeat --ignore=E501 '%s'" % (f)) + else: + os.system("pep8 --repeat '%s'" % (f)) + + print("\n\n\n# running pyflakes...") + for f, pep8_type in files: + os.system("pyflakes '%s'" % f) + + print("\n\n\n# running pylint...") + for f, pep8_type in files: + # let pep8 complain about line length + os.system("pylint --reports=n --max-line-length=1000 '%s'" % f) + +if __name__ == "__main__": + main() diff --git a/source/tests/rna_array.py b/source/tests/rna_array.py new file mode 100644 index 00000000000..06b4735cc0d --- /dev/null +++ b/source/tests/rna_array.py @@ -0,0 +1,297 @@ +# ##### BEGIN GPL LICENSE BLOCK ##### +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ##### END GPL LICENSE BLOCK ##### + +import unittest +import random + +test= bpy.data.test + +# farr - 1-dimensional array of float +# fdarr - dynamic 1-dimensional array of float +# fmarr - 3-dimensional ([3][4][5]) array of float +# fdmarr - dynamic 3-dimensional (ditto size) array of float + +# same as above for other types except that the first letter is "i" for int and "b" for bool + +class TestArray(unittest.TestCase): + # test that assignment works by: assign -> test value + # - rvalue = list of float + # - rvalue = list of numbers + # test.object + # bpy.data.test.farr[3], iarr[3], barr[...], fmarr, imarr, bmarr + + def setUp(self): + test.farr= (1.0, 2.0, 3.0) + test.iarr= (7, 8, 9) + test.barr= (False, True, False) + + # test access + # test slice access, negative indices + def test_access(self): + rvals= ([1.0, 2.0, 3.0], [7, 8, 9], [False, True, False]) + for arr, rval in zip((test.farr, test.iarr, test.barr), rvals): + self.assertEqual(prop_to_list(arr), rval) + self.assertEqual(arr[0:3], rval) + self.assertEqual(arr[1:2], rval[1:2]) + self.assertEqual(arr[-1], arr[2]) + self.assertEqual(arr[-2], arr[1]) + self.assertEqual(arr[-3], arr[0]) + + # fail when index out of bounds + def test_access_fail(self): + for arr in (test.farr, test.iarr, test.barr): + self.assertRaises(IndexError, lambda : arr[4]) + + # test assignment of a whole array + def test_assign_array(self): + # should accept int as float + test.farr= (1, 2, 3) + + # fail when: unexpected no. of items, invalid item type + def test_assign_array_fail(self): + def assign_empty_list(arr): + setattr(test, arr, ()) + + for arr in ("farr", "iarr", "barr"): + self.assertRaises(ValueError, assign_empty_list, arr) + + def assign_invalid_float(): + test.farr= (1.0, 2.0, "3.0") + + def assign_invalid_int(): + test.iarr= ("1", 2, 3) + + def assign_invalid_bool(): + test.barr= (True, 0.123, False) + + for func in [assign_invalid_float, assign_invalid_int, assign_invalid_bool]: + self.assertRaises(TypeError, func) + + # shouldn't accept float as int + def assign_float_as_int(): + test.iarr= (1, 2, 3.0) + self.assertRaises(TypeError, assign_float_as_int) + + # non-dynamic arrays cannot change size + def assign_different_size(arr, val): + setattr(test, arr, val) + for arr, val in zip(("iarr", "farr", "barr"), ((1, 2), (1.0, 2.0), (True, False))): + self.assertRaises(ValueError, assign_different_size, arr, val) + + # test assignment of specific items + def test_assign_item(self): + for arr, rand_func in zip((test.farr, test.iarr, test.barr), (rand_float, rand_int, rand_bool)): + for i in range(len(arr)): + val= rand_func() + arr[i]= val + + self.assertEqual(arr[i], val) + + # float prop should accept also int + for i in range(len(test.farr)): + val= rand_int() + test.farr[i]= val + self.assertEqual(test.farr[i], float(val)) + + # + + def test_assign_item_fail(self): + def assign_bad_index(arr): + arr[4] = 1.0 + + def assign_bad_type(arr): + arr[1]= "123" + + for arr in [test.farr, test.iarr, test.barr]: + self.assertRaises(IndexError, assign_bad_index, arr) + + # not testing bool because bool allows not only (True|False) + for arr in [test.farr, test.iarr]: + self.assertRaises(TypeError, assign_bad_type, arr) + + def test_dynamic_assign_array(self): + # test various lengths here + for arr, rand_func in zip(("fdarr", "idarr", "bdarr"), (rand_float, rand_int, rand_bool)): + for length in range(1, 64): + rval= make_random_array(length, rand_func) + setattr(test, arr, rval) + self.assertEqual(prop_to_list(getattr(test, arr)), rval) + + def test_dynamic_assign_array_fail(self): + # could also test too big length here + + def assign_empty_list(arr): + setattr(test, arr, ()) + + for arr in ("fdarr", "idarr", "bdarr"): + self.assertRaises(ValueError, assign_empty_list, arr) + + +class TestMArray(unittest.TestCase): + def setUp(self): + # reset dynamic array sizes + for arr, func in zip(("fdmarr", "idmarr", "bdmarr"), (rand_float, rand_int, rand_bool)): + setattr(test, arr, make_random_3d_array((3, 4, 5), func)) + + # test assignment + def test_assign_array(self): + for arr, func in zip(("fmarr", "imarr", "bmarr"), (rand_float, rand_int, rand_bool)): + # assignment of [3][4][5] + rval= make_random_3d_array((3, 4, 5), func) + setattr(test, arr, rval) + self.assertEqual(prop_to_list(getattr(test, arr)), rval) + + # test assignment of [2][4][5], [1][4][5] should work on dynamic arrays + + def test_assign_array_fail(self): + def assign_empty_array(): + test.fmarr= () + self.assertRaises(ValueError, assign_empty_array) + + def assign_invalid_size(arr, rval): + setattr(test, arr, rval) + + # assignment of 3,4,4 or 3,3,5 should raise ex + for arr, func in zip(("fmarr", "imarr", "bmarr"), (rand_float, rand_int, rand_bool)): + rval= make_random_3d_array((3, 4, 4), func) + self.assertRaises(ValueError, assign_invalid_size, arr, rval) + + rval= make_random_3d_array((3, 3, 5), func) + self.assertRaises(ValueError, assign_invalid_size, arr, rval) + + rval= make_random_3d_array((3, 3, 3), func) + self.assertRaises(ValueError, assign_invalid_size, arr, rval) + + def test_assign_item(self): + # arr[i] = x + for arr, func in zip(("fmarr", "imarr", "bmarr", "fdmarr", "idmarr", "bdmarr"), (rand_float, rand_int, rand_bool) * 2): + rval= make_random_2d_array((4, 5), func) + + for i in range(3): + getattr(test, arr)[i]= rval + self.assertEqual(prop_to_list(getattr(test, arr)[i]), rval) + + # arr[i][j] = x + for arr, func in zip(("fmarr", "imarr", "bmarr", "fdmarr", "idmarr", "bdmarr"), (rand_float, rand_int, rand_bool) * 2): + + arr= getattr(test, arr) + rval= make_random_array(5, func) + + for i in range(3): + for j in range(4): + arr[i][j]= rval + self.assertEqual(prop_to_list(arr[i][j]), rval) + + + def test_assign_item_fail(self): + def assign_wrong_size(arr, i, rval): + getattr(test, arr)[i]= rval + + # assign wrong size at level 2 + for arr, func in zip(("fmarr", "imarr", "bmarr"), (rand_float, rand_int, rand_bool)): + rval1= make_random_2d_array((3, 5), func) + rval2= make_random_2d_array((4, 3), func) + + for i in range(3): + self.assertRaises(ValueError, assign_wrong_size, arr, i, rval1) + self.assertRaises(ValueError, assign_wrong_size, arr, i, rval2) + + def test_dynamic_assign_array(self): + for arr, func in zip(("fdmarr", "idmarr", "bdmarr"), (rand_float, rand_int, rand_bool)): + # assignment of [3][4][5] + rval= make_random_3d_array((3, 4, 5), func) + setattr(test, arr, rval) + self.assertEqual(prop_to_list(getattr(test, arr)), rval) + + # [2][4][5] + rval= make_random_3d_array((2, 4, 5), func) + setattr(test, arr, rval) + self.assertEqual(prop_to_list(getattr(test, arr)), rval) + + # [1][4][5] + rval= make_random_3d_array((1, 4, 5), func) + setattr(test, arr, rval) + self.assertEqual(prop_to_list(getattr(test, arr)), rval) + + + # test access + def test_access(self): + pass + + # test slice access, negative indices + def test_access_fail(self): + pass + +random.seed() + +def rand_int(): + return random.randint(-1000, 1000) + +def rand_float(): + return float(rand_int()) + +def rand_bool(): + return bool(random.randint(0, 1)) + +def make_random_array(len, rand_func): + arr= [] + for i in range(len): + arr.append(rand_func()) + + return arr + +def make_random_2d_array(dimsize, rand_func): + marr= [] + for i in range(dimsize[0]): + marr.append([]) + + for j in range(dimsize[1]): + marr[-1].append(rand_func()) + + return marr + +def make_random_3d_array(dimsize, rand_func): + marr= [] + for i in range(dimsize[0]): + marr.append([]) + + for j in range(dimsize[1]): + marr[-1].append([]) + + for k in range(dimsize[2]): + marr[-1][-1].append(rand_func()) + + return marr + +def prop_to_list(prop): + ret= [] + + for x in prop: + if type(x) not in (bool, int, float): + ret.append(prop_to_list(x)) + else: + ret.append(x) + + return ret + +def suite(): + return unittest.TestSuite([unittest.TestLoader().loadTestsFromTestCase(TestArray), unittest.TestLoader().loadTestsFromTestCase(TestMArray)]) + +if __name__ == "__main__": + unittest.TextTestRunner(verbosity=2).run(suite()) + diff --git a/source/tests/rna_info_dump.py b/source/tests/rna_info_dump.py new file mode 100644 index 00000000000..62c1248d733 --- /dev/null +++ b/source/tests/rna_info_dump.py @@ -0,0 +1,131 @@ +# ##### BEGIN GPL LICENSE BLOCK ##### +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ##### END GPL LICENSE BLOCK ##### + +# <pep8 compliant> + +# Used for generating API diff's between releases +# ./blender.bin --background --python release/test/rna_info_dump.py + +import bpy + + +def api_dump(use_properties=True, use_functions=True): + + def prop_type(prop): + if prop.type == "pointer": + return prop.fixed_type.identifier + else: + return prop.type + + def func_to_str(struct_id_str, func_id, func): + + args = [] + for prop in func.args: + data_str = "%s %s" % (prop_type(prop), prop.identifier) + if prop.array_length: + data_str += "[%d]" % prop.array_length + if not prop.is_required: + data_str += "=%s" % prop.default_str + args.append(data_str) + + data_str = "%s.%s(%s)" % (struct_id_str, func_id, ", ".join(args)) + if func.return_values: + return_args = ", ".join(prop_type(arg) for arg in func.return_values) + if len(func.return_values) > 1: + data_str += " --> (%s)" % return_args + else: + data_str += " --> %s" % return_args + return data_str + + def prop_to_str(struct_id_str, prop_id, prop): + + prop_str = " <-- %s" % prop_type(prop) + if prop.array_length: + prop_str += "[%d]" % prop.array_length + + data_str = "%s.%s %s" % (struct_id_str, prop_id, prop_str) + return data_str + + def struct_full_id(v): + struct_id_str = v.identifier # "".join(sid for sid in struct_id if struct_id) + + for base in v.get_bases(): + struct_id_str = base.identifier + "|" + struct_id_str + + return struct_id_str + + def dump_funcs(): + data = [] + for struct_id, v in sorted(struct.items()): + struct_id_str = struct_full_id(v) + + funcs = [(func.identifier, func) for func in v.functions] + + for func_id, func in funcs: + data.append(func_to_str(struct_id_str, func_id, func)) + + for prop in v.properties: + if prop.collection_type: + funcs = [(prop.identifier + "." + func.identifier, func) for func in prop.collection_type.functions] + for func_id, func in funcs: + data.append(func_to_str(struct_id_str, func_id, func)) + data.sort() + data.append("# * functions *") + return data + + def dump_props(): + data = [] + for struct_id, v in sorted(struct.items()): + struct_id_str = struct_full_id(v) + + props = [(prop.identifier, prop) for prop in v.properties] + + for prop_id, prop in props: + data.append(prop_to_str(struct_id_str, prop_id, prop)) + + for prop in v.properties: + if prop.collection_type: + props = [(prop.identifier + "." + prop_sub.identifier, prop_sub) for prop_sub in prop.collection_type.properties] + for prop_sub_id, prop_sub in props: + data.append(prop_to_str(struct_id_str, prop_sub_id, prop_sub)) + data.sort() + data.insert(0, "# * properties *") + return data + + import rna_info + struct = rna_info.BuildRNAInfo()[0] + data = [] + + if use_functions: + data.extend(dump_funcs()) + + if use_properties: + data.extend(dump_props()) + + if bpy.app.background: + import sys + sys.stderr.write("\n".join(data)) + sys.stderr.write("\n\nEOF\n") + else: + text = bpy.data.texts.new(name="api.py") + text.from_string(data) + + print("END") + +if __name__ == "__main__": + api_dump() |