Tests: move remaining gtests into their own module folders

And make them part of the blender_test runner. The one exception is blenlib
performance tests, which we don't want to run by default. They remain in their
own executable.

Differential Revision: https://developer.blender.org/D8498
This commit is contained in:
Brecht Van Lommel
2020-08-07 16:43:42 +02:00
parent af77bf1f0f
commit 53d203dea8
54 changed files with 143 additions and 494 deletions

View File

@@ -3,19 +3,9 @@ if(WITH_GTESTS)
# Otherwise we get warnings here that we cant fix in external projects
remove_strict_flags()
# Build common test runner
# Build common test executable used by most tests
add_subdirectory(runner)
# Build tests not yet ported to the common runner
# Build utility library used by test executables
add_subdirectory(testing)
add_subdirectory(blenlib)
add_subdirectory(blenloader)
add_subdirectory(guardedalloc)
add_subdirectory(bmesh)
if(WITH_CODEC_FFMPEG)
add_subdirectory(ffmpeg)
endif()
if(WITH_ALEMBIC)
add_subdirectory(alembic)
endif()
endif()

View File

@@ -1,63 +0,0 @@
# ***** 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.
#
# The Original Code is Copyright (C) 2014, Blender Foundation
# All rights reserved.
# ***** END GPL LICENSE BLOCK *****
set(INC
.
..
../../../source/blender/blenlib
../../../source/blender/blenkernel
../../../source/blender/io/alembic
../../../source/blender/io/common
../../../source/blender/io/usd/intern
../../../source/blender/makesdna
../../../source/blender/depsgraph
${ALEMBIC_INCLUDE_DIRS}
${BOOST_INCLUDE_DIR}
${HDF5_INCLUDE_DIRS}
${OPENEXR_INCLUDE_DIRS}
)
set(LIB
bf_blenloader # Should not be needed but gives linking error without it.
bf_intern_opencolorio # Should not be needed but gives windows linker errors if the ocio libs are linked before this
bf_gpu # Should not be needed but gives windows linker errors if the ocio libs are linked before this
bf_alembic
${OPENEXR_LIBRARIES}
${BOOST_LIBRARIES}
)
include_directories(${INC})
setup_libdirs()
get_property(BLENDER_SORTED_LIBS GLOBAL PROPERTY BLENDER_SORTED_LIBS_PROP)
if(WITH_BUILDINFO)
set(_buildinfo_src "$<TARGET_OBJECTS:buildinfoobj>")
else()
set(_buildinfo_src "")
endif()
# For motivation on doubling BLENDER_SORTED_LIBS, see ../bmesh/CMakeLists.txt
BLENDER_SRC_GTEST(alembic "abc_matrix_test.cc;abc_export_test.cc;${_buildinfo_src}" "${LIB}")
unset(_buildinfo_src)
setup_liblinks(alembic_test)

View File

@@ -1,161 +0,0 @@
#include "testing/testing.h"
// Keep first since utildefines defines AT which conflicts with STL
#include "exporter/abc_archive.h"
#include "intern/abc_util.h"
#include "BKE_main.h"
#include "BLI_fileops.h"
#include "BLI_math.h"
#include "BLI_utildefines.h"
#include "DNA_scene_types.h"
#include "DEG_depsgraph.h"
namespace blender {
namespace io {
namespace alembic {
class AlembicExportTest : public testing::Test {
protected:
ABCArchive *abc_archive;
AlembicExportParams params;
Scene scene;
Depsgraph *depsgraph;
Main *bmain;
virtual void SetUp()
{
abc_archive = nullptr;
/* Fake a 25 FPS scene with a nonzero base (because that's sometimes forgotten) */
scene.r.frs_sec = 50;
scene.r.frs_sec_base = 2;
strcpy(scene.id.name, "SCTestScene");
bmain = BKE_main_new();
/* TODO(sergey): Pass scene layer somehow? */
ViewLayer *view_layer = (ViewLayer *)scene.view_layers.first;
depsgraph = DEG_graph_new(bmain, &scene, view_layer, DAG_EVAL_RENDER);
}
virtual void TearDown()
{
BKE_main_free(bmain);
DEG_graph_free(depsgraph);
deleteArchive();
}
// Call after setting up the parameters.
void createArchive()
{
if (abc_archive != nullptr) {
deleteArchive();
}
abc_archive = new ABCArchive(bmain, &scene, params, "somefile.abc");
}
void deleteArchive()
{
delete abc_archive;
if (BLI_exists("somefile.abc")) {
BLI_delete("somefile.abc", false, false);
}
abc_archive = nullptr;
}
};
TEST_F(AlembicExportTest, TimeSamplesFullShutterUniform)
{
/* Test 5 samples per frame, for 2 frames. */
params.shutter_open = 0.0;
params.shutter_close = 1.0;
params.frame_start = 31.0;
params.frame_end = 32.0;
params.frame_samples_xform = params.frame_samples_shape = 5;
createArchive();
std::vector<double> frames(abc_archive->frames_begin(), abc_archive->frames_end());
EXPECT_EQ(10, frames.size());
EXPECT_NEAR(31.0, frames[0], 1e-5);
EXPECT_NEAR(31.2, frames[1], 1e-5);
EXPECT_NEAR(31.4, frames[2], 1e-5);
EXPECT_NEAR(31.6, frames[3], 1e-5);
EXPECT_NEAR(31.8, frames[4], 1e-5);
EXPECT_NEAR(32.0, frames[5], 1e-5);
EXPECT_NEAR(32.2, frames[6], 1e-5);
EXPECT_NEAR(32.4, frames[7], 1e-5);
EXPECT_NEAR(32.6, frames[8], 1e-5);
EXPECT_NEAR(32.8, frames[9], 1e-5);
for (double frame : frames) {
EXPECT_TRUE(abc_archive->is_xform_frame(frame));
EXPECT_TRUE(abc_archive->is_shape_frame(frame));
}
}
TEST_F(AlembicExportTest, TimeSamplesFullShutterDifferent)
{
/* Test 3 samples per frame for transforms, and 2 per frame for shapes, for 2 frames. */
params.shutter_open = 0.0;
params.shutter_close = 1.0;
params.frame_start = 31.0;
params.frame_end = 32.0;
params.frame_samples_xform = 3;
params.frame_samples_shape = 2;
createArchive();
std::vector<double> frames(abc_archive->frames_begin(), abc_archive->frames_end());
EXPECT_EQ(8, frames.size());
EXPECT_NEAR(31.0, frames[0], 1e-5); // transform + shape
EXPECT_TRUE(abc_archive->is_xform_frame(frames[0]));
EXPECT_TRUE(abc_archive->is_shape_frame(frames[0]));
EXPECT_NEAR(31.33333, frames[1], 1e-5); // transform
EXPECT_TRUE(abc_archive->is_xform_frame(frames[1]));
EXPECT_FALSE(abc_archive->is_shape_frame(frames[1]));
EXPECT_NEAR(31.5, frames[2], 1e-5); // shape
EXPECT_FALSE(abc_archive->is_xform_frame(frames[2]));
EXPECT_TRUE(abc_archive->is_shape_frame(frames[2]));
EXPECT_NEAR(31.66666, frames[3], 1e-5); // transform
EXPECT_TRUE(abc_archive->is_xform_frame(frames[3]));
EXPECT_FALSE(abc_archive->is_shape_frame(frames[3]));
EXPECT_NEAR(32.0, frames[4], 1e-5); // transform + shape
EXPECT_TRUE(abc_archive->is_xform_frame(frames[4]));
EXPECT_TRUE(abc_archive->is_shape_frame(frames[4]));
EXPECT_NEAR(32.33333, frames[5], 1e-5); // transform
EXPECT_TRUE(abc_archive->is_xform_frame(frames[5]));
EXPECT_FALSE(abc_archive->is_shape_frame(frames[5]));
EXPECT_NEAR(32.5, frames[6], 1e-5); // shape
EXPECT_FALSE(abc_archive->is_xform_frame(frames[6]));
EXPECT_TRUE(abc_archive->is_shape_frame(frames[6]));
EXPECT_NEAR(32.66666, frames[7], 1e-5); // transform
EXPECT_TRUE(abc_archive->is_xform_frame(frames[7]));
EXPECT_FALSE(abc_archive->is_shape_frame(frames[7]));
}
TEST_F(AlembicExportTest, TimeSamples180degShutter)
{
/* Test 5 samples per frame, for 2 frames. */
params.shutter_open = -0.25;
params.shutter_close = 0.25;
params.frame_start = 31.0;
params.frame_end = 32.0;
params.frame_samples_xform = params.frame_samples_shape = 5;
createArchive();
std::vector<double> frames(abc_archive->frames_begin(), abc_archive->frames_end());
EXPECT_EQ(10, frames.size());
EXPECT_NEAR(31 - 0.25, frames[0], 1e-5);
EXPECT_NEAR(31 - 0.15, frames[1], 1e-5);
EXPECT_NEAR(31 - 0.05, frames[2], 1e-5);
EXPECT_NEAR(31 + 0.05, frames[3], 1e-5);
EXPECT_NEAR(31 + 0.15, frames[4], 1e-5);
EXPECT_NEAR(32 - 0.25, frames[5], 1e-5);
EXPECT_NEAR(32 - 0.15, frames[6], 1e-5);
EXPECT_NEAR(32 - 0.05, frames[7], 1e-5);
EXPECT_NEAR(32 + 0.05, frames[8], 1e-5);
EXPECT_NEAR(32 + 0.15, frames[9], 1e-5);
}
} // namespace alembic
} // namespace io
} // namespace blender

View File

@@ -1,292 +0,0 @@
#include "testing/testing.h"
// Keep first since utildefines defines AT which conflicts with STL
#include "intern/abc_axis_conversion.h"
#include "BLI_math.h"
#include "BLI_utildefines.h"
namespace blender {
namespace io {
namespace alembic {
TEST(abc_matrix, CreateRotationMatrixY_YfromZ)
{
// Input variables
float rot_x_mat[3][3];
float rot_y_mat[3][3];
float rot_z_mat[3][3];
float euler[3] = {0.f, M_PI_4, 0.f};
// Construct expected matrices
float unit[3][3];
float rot_z_min_quart_pi[3][3]; // rotation of -pi/4 radians over z-axis
unit_m3(unit);
unit_m3(rot_z_min_quart_pi);
rot_z_min_quart_pi[0][0] = M_SQRT1_2;
rot_z_min_quart_pi[0][1] = -M_SQRT1_2;
rot_z_min_quart_pi[1][0] = M_SQRT1_2;
rot_z_min_quart_pi[1][1] = M_SQRT1_2;
// Run tests
create_swapped_rotation_matrix(rot_x_mat, rot_y_mat, rot_z_mat, euler, ABC_YUP_FROM_ZUP);
EXPECT_M3_NEAR(rot_x_mat, unit, 1e-5f);
EXPECT_M3_NEAR(rot_y_mat, unit, 1e-5f);
EXPECT_M3_NEAR(rot_z_mat, rot_z_min_quart_pi, 1e-5f);
}
TEST(abc_matrix, CreateRotationMatrixZ_YfromZ)
{
// Input variables
float rot_x_mat[3][3];
float rot_y_mat[3][3];
float rot_z_mat[3][3];
float euler[3] = {0.f, 0.f, M_PI_4};
// Construct expected matrices
float unit[3][3];
float rot_y_quart_pi[3][3]; // rotation of pi/4 radians over y-axis
unit_m3(unit);
unit_m3(rot_y_quart_pi);
rot_y_quart_pi[0][0] = M_SQRT1_2;
rot_y_quart_pi[0][2] = -M_SQRT1_2;
rot_y_quart_pi[2][0] = M_SQRT1_2;
rot_y_quart_pi[2][2] = M_SQRT1_2;
// Run tests
create_swapped_rotation_matrix(rot_x_mat, rot_y_mat, rot_z_mat, euler, ABC_YUP_FROM_ZUP);
EXPECT_M3_NEAR(rot_x_mat, unit, 1e-5f);
EXPECT_M3_NEAR(rot_y_mat, rot_y_quart_pi, 1e-5f);
EXPECT_M3_NEAR(rot_z_mat, unit, 1e-5f);
}
TEST(abc_matrix, CreateRotationMatrixXYZ_YfromZ)
{
// Input variables
float rot_x_mat[3][3];
float rot_y_mat[3][3];
float rot_z_mat[3][3];
// in degrees: X=10, Y=20, Z=30
float euler[3] = {0.17453292012214f, 0.34906581044197f, 0.52359879016876f};
// Construct expected matrices
float rot_x_p10[3][3]; // rotation of +10 degrees over x-axis
float rot_y_p30[3][3]; // rotation of +30 degrees over y-axis
float rot_z_m20[3][3]; // rotation of -20 degrees over z-axis
unit_m3(rot_x_p10);
rot_x_p10[1][1] = 0.9848077297210693f;
rot_x_p10[1][2] = 0.1736481785774231f;
rot_x_p10[2][1] = -0.1736481785774231f;
rot_x_p10[2][2] = 0.9848077297210693f;
unit_m3(rot_y_p30);
rot_y_p30[0][0] = 0.8660253882408142f;
rot_y_p30[0][2] = -0.5f;
rot_y_p30[2][0] = 0.5f;
rot_y_p30[2][2] = 0.8660253882408142f;
unit_m3(rot_z_m20);
rot_z_m20[0][0] = 0.9396926164627075f;
rot_z_m20[0][1] = -0.3420201241970062f;
rot_z_m20[1][0] = 0.3420201241970062f;
rot_z_m20[1][1] = 0.9396926164627075f;
// Run tests
create_swapped_rotation_matrix(rot_x_mat, rot_y_mat, rot_z_mat, euler, ABC_YUP_FROM_ZUP);
EXPECT_M3_NEAR(rot_x_mat, rot_x_p10, 1e-5f);
EXPECT_M3_NEAR(rot_y_mat, rot_y_p30, 1e-5f);
EXPECT_M3_NEAR(rot_z_mat, rot_z_m20, 1e-5f);
}
TEST(abc_matrix, CreateRotationMatrixXYZ_ZfromY)
{
// Input variables
float rot_x_mat[3][3];
float rot_y_mat[3][3];
float rot_z_mat[3][3];
// in degrees: X=10, Y=20, Z=30
float euler[3] = {0.1745329201221466f, 0.3490658104419708f, 0.5235987901687622f};
// Construct expected matrices
float rot_x_p10[3][3]; // rotation of +10 degrees over x-axis
float rot_y_m30[3][3]; // rotation of -30 degrees over y-axis
float rot_z_p20[3][3]; // rotation of +20 degrees over z-axis
unit_m3(rot_x_p10);
rot_x_p10[1][1] = 0.9848077297210693f;
rot_x_p10[1][2] = 0.1736481785774231f;
rot_x_p10[2][1] = -0.1736481785774231f;
rot_x_p10[2][2] = 0.9848077297210693f;
unit_m3(rot_y_m30);
rot_y_m30[0][0] = 0.8660253882408142f;
rot_y_m30[0][2] = 0.5f;
rot_y_m30[2][0] = -0.5f;
rot_y_m30[2][2] = 0.8660253882408142f;
unit_m3(rot_z_p20);
rot_z_p20[0][0] = 0.9396926164627075f;
rot_z_p20[0][1] = 0.3420201241970062f;
rot_z_p20[1][0] = -0.3420201241970062f;
rot_z_p20[1][1] = 0.9396926164627075f;
// Run tests
create_swapped_rotation_matrix(rot_x_mat, rot_y_mat, rot_z_mat, euler, ABC_ZUP_FROM_YUP);
EXPECT_M3_NEAR(rot_x_mat, rot_x_p10, 1e-5f);
EXPECT_M3_NEAR(rot_y_mat, rot_y_m30, 1e-5f);
EXPECT_M3_NEAR(rot_z_mat, rot_z_p20, 1e-5f);
}
TEST(abc_matrix, CopyM44AxisSwap_YfromZ)
{
float result[4][4];
/* Construct an input matrix that performs a rotation like the tests
* above. This matrix was created by rotating a cube in Blender over
* (X=10, Y=20, Z=30 degrees in XYZ order) and translating over (1, 2, 3) */
float input[4][4] = {
{0.81379765272f, 0.4698463380336f, -0.342020124197f, 0.f},
{-0.44096961617f, 0.8825641274452f, 0.163175910711f, 0.f},
{0.37852230668f, 0.0180283170193f, 0.925416588783f, 0.f},
{1.f, 2.f, 3.f, 1.f},
};
copy_m44_axis_swap(result, input, ABC_YUP_FROM_ZUP);
/* Check the resulting rotation & translation. */
float trans[4] = {1.f, 3.f, -2.f, 1.f};
EXPECT_V4_NEAR(trans, result[3], 1e-5f);
/* This matrix was created by rotating a cube in Blender over
* (X=10, Y=30, Z=-20 degrees in XZY order) and translating over (1, 3, -2) */
float expect[4][4] = {
{0.813797652721f, -0.342020124197f, -0.469846338033f, 0.f},
{0.378522306680f, 0.925416588783f, -0.018028317019f, 0.f},
{0.440969616174f, -0.163175910711f, 0.882564127445f, 0.f},
{1.f, 3.f, -2.f, 1.f},
};
EXPECT_M4_NEAR(expect, result, 1e-5f);
}
TEST(abc_matrix, CopyM44AxisSwapWithScale_YfromZ)
{
float result[4][4];
/* Construct an input matrix that performs a rotation like the tests
* above. This matrix was created by rotating a cube in Blender over
* (X=10, Y=20, Z=30 degrees in XYZ order), translating over (1, 2, 3),
* and scaling by (4, 5, 6). */
float input[4][4] = {
{3.25519061088f, 1.8793853521347f, -1.368080496788f, 0.f},
{-2.20484805107f, 4.4128208160400f, 0.815879583358f, 0.f},
{2.27113389968f, 0.1081698983907f, 5.552499771118f, 0.f},
{1.f, 2.f, 3.f, 1.f},
};
copy_m44_axis_swap(result, input, ABC_YUP_FROM_ZUP);
/* This matrix was created by rotating a cube in Blender over
* (X=10, Y=30, Z=-20 degrees in XZY order), translating over (1, 3, -2)
* and scaling over (4, 6, 5). */
float expect[4][4] = {
{3.255190610885f, -1.368080496788f, -1.879385352134f, 0.f},
{2.271133899688f, 5.552499771118f, -0.108169898390f, 0.f},
{2.204848051071f, -0.815879583358f, 4.412820816040f, 0.f},
{1.f, 3.f, -2.f, 1.f},
};
EXPECT_M4_NEAR(expect, result, 1e-5f);
}
TEST(abc_matrix, CopyM44AxisSwap_ZfromY)
{
float result[4][4];
/* This matrix was created by rotating a cube in Blender over
* (X=10, Y=30, Z=-20 degrees in XZY order) and translating over (1, 3, -2) */
float input[4][4] = {
{0.813797652721f, -0.342020124197f, -0.469846338033f, 0.f},
{0.378522306680f, 0.925416588783f, -0.018028317019f, 0.f},
{0.440969616174f, -0.163175910711f, 0.882564127445f, 0.f},
{1.f, 3.f, -2.f, 1.f},
};
copy_m44_axis_swap(result, input, ABC_ZUP_FROM_YUP);
/* This matrix was created by rotating a cube in Blender over
* (X=10, Y=20, Z=30 degrees in XYZ order) and translating over (1, 2, 3) */
float expect[4][4] = {
{0.813797652721f, 0.469846338033f, -0.342020124197f, 0.f},
{-0.44096961617f, 0.882564127445f, 0.163175910711f, 0.f},
{0.378522306680f, 0.018028317019f, 0.925416588783f, 0.f},
{1.f, 2.f, 3.f, 1.f},
};
EXPECT_M4_NEAR(expect, result, 1e-5f);
}
TEST(abc_matrix, CopyM44AxisSwapWithScale_ZfromY)
{
float result[4][4];
/* This matrix was created by rotating a cube in Blender over
* (X=10, Y=30, Z=-20 degrees in XZY order), translating over (1, 3, -2)
* and scaling over (4, 6, 5). */
float input[4][4] = {
{3.2551906108f, -1.36808049678f, -1.879385352134f, 0.f},
{2.2711338996f, 5.55249977111f, -0.108169898390f, 0.f},
{2.2048480510f, -0.81587958335f, 4.412820816040f, 0.f},
{1.f, 3.f, -2.f, 1.f},
};
copy_m44_axis_swap(result, input, ABC_ZUP_FROM_YUP);
/* This matrix was created by rotating a cube in Blender over
* (X=10, Y=20, Z=30 degrees in XYZ order), translating over (1, 2, 3),
* and scaling by (4, 5, 6). */
float expect[4][4] = {
{3.25519061088f, 1.879385352134f, -1.36808049678f, 0.f},
{-2.2048480510f, 4.412820816040f, 0.81587958335f, 0.f},
{2.27113389968f, 0.108169898390f, 5.55249977111f, 0.f},
{1.f, 2.f, 3.f, 1.f},
};
EXPECT_M4_NEAR(expect, result, 1e-5f);
}
TEST(abc_matrix, CopyM44AxisSwapWithScale_gimbal_ZfromY)
{
float result[4][4];
/* This matrix represents a rotation over (-90, -0, -0) degrees,
* and a translation over (-0, -0.1, -0). It is in Y=up. */
float input[4][4] = {
{1.000f, 0.000f, 0.000f, 0.000f},
{0.000f, 0.000f, -1.000f, 0.000f},
{0.000f, 1.000f, 0.000f, 0.000f},
{-0.000f, -0.100f, -0.000f, 1.000f},
};
copy_m44_axis_swap(result, input, ABC_ZUP_FROM_YUP);
/* Since the rotation is only over the X-axis, it should not change.
* The translation does change. */
float expect[4][4] = {
{1.000f, 0.000f, 0.000f, 0.000f},
{0.000f, 0.000f, -1.000f, 0.000f},
{0.000f, 1.000f, 0.000f, 0.000f},
{-0.000f, 0.000f, -0.100f, 1.000f},
};
EXPECT_M4_NEAR(expect, result, 1e-5f);
}
} // namespace alembic
} // namespace io
} // namespace blender

View File

@@ -1,884 +0,0 @@
/* Apache License, Version 2.0 */
#include "testing/testing.h"
#include "MEM_guardedalloc.h"
#include "BLI_array_store.h"
#include "BLI_array_utils.h"
#include "BLI_listbase.h"
#include "BLI_rand.h"
#include "BLI_ressource_strings.h"
#include "BLI_string.h"
#include "BLI_sys_types.h"
#include "BLI_utildefines.h"
/* print memory savings */
// #define DEBUG_PRINT
/* -------------------------------------------------------------------- */
/* Helper functions */
#ifdef DEBUG_PRINT
static void print_mem_saved(const char *id, const BArrayStore *bs)
{
const double size_real = BLI_array_store_calc_size_compacted_get(bs);
const double size_expand = BLI_array_store_calc_size_expanded_get(bs);
const double percent = size_expand ? ((size_real / size_expand) * 100.0) : -1.0;
printf("%s: %.8f%%\n", id, percent);
}
#endif
/* -------------------------------------------------------------------- */
/* Test Chunks (building data from list of chunks) */
typedef struct TestChunk {
struct TestChunk *next, *prev;
const void *data;
size_t data_len;
} TestChunk;
static TestChunk *testchunk_list_add(ListBase *lb, const void *data, size_t data_len)
{
TestChunk *tc = (TestChunk *)MEM_mallocN(sizeof(*tc), __func__);
tc->data = data;
tc->data_len = data_len;
BLI_addtail(lb, tc);
return tc;
}
#if 0
static TestChunk *testchunk_list_add_copydata(ListBase *lb, const void *data, size_t data_len)
{
void *data_copy = MEM_mallocN(data_len, __func__);
memcpy(data_copy, data, data_len);
return testchunk_list_add(lb, data_copy, data_len);
}
#endif
static void testchunk_list_free(ListBase *lb)
{
for (TestChunk *tc = (TestChunk *)lb->first, *tb_next; tc; tc = tb_next) {
tb_next = tc->next;
MEM_freeN((void *)tc->data);
MEM_freeN(tc);
}
BLI_listbase_clear(lb);
}
#if 0
static char *testchunk_as_data(ListBase *lb, size_t *r_data_len)
{
size_t data_len = 0;
for (TestChunk *tc = (TestChunk *)lb->first; tc; tc = tc->next) {
data_len += tc->data_len;
}
char *data = (char *)MEM_mallocN(data_len, __func__);
size_t i = 0;
for (TestChunk *tc = (TestChunk *)lb->first; tc; tc = tc->next) {
memcpy(&data[i], tc->data, tc->data_len);
data_len += tc->data_len;
i += tc->data_len;
}
if (r_data_len) {
*r_data_len = i;
}
return data;
}
#endif
static char *testchunk_as_data_array(TestChunk **tc_array, int tc_array_len, size_t *r_data_len)
{
size_t data_len = 0;
for (int tc_index = 0; tc_index < tc_array_len; tc_index++) {
data_len += tc_array[tc_index]->data_len;
}
char *data = (char *)MEM_mallocN(data_len, __func__);
size_t i = 0;
for (int tc_index = 0; tc_index < tc_array_len; tc_index++) {
TestChunk *tc = tc_array[tc_index];
memcpy(&data[i], tc->data, tc->data_len);
i += tc->data_len;
}
if (r_data_len) {
*r_data_len = i;
}
return data;
}
/* -------------------------------------------------------------------- */
/* Test Buffer */
/* API to handle local allocation of data so we can compare it with the data in the array_store */
typedef struct TestBuffer {
struct TestBuffer *next, *prev;
const void *data;
size_t data_len;
/* for reference */
BArrayState *state;
} TestBuffer;
static TestBuffer *testbuffer_list_add(ListBase *lb, const void *data, size_t data_len)
{
TestBuffer *tb = (TestBuffer *)MEM_mallocN(sizeof(*tb), __func__);
tb->data = data;
tb->data_len = data_len;
tb->state = NULL;
BLI_addtail(lb, tb);
return tb;
}
static TestBuffer *testbuffer_list_add_copydata(ListBase *lb, const void *data, size_t data_len)
{
void *data_copy = MEM_mallocN(data_len, __func__);
memcpy(data_copy, data, data_len);
return testbuffer_list_add(lb, data_copy, data_len);
}
static void testbuffer_list_state_from_data(ListBase *lb, const char *data, const size_t data_len)
{
testbuffer_list_add_copydata(lb, (const void *)data, data_len);
}
/**
* A version of testbuffer_list_state_from_data that expand data by stride,
* handy so we can test data at different strides.
*/
static void testbuffer_list_state_from_data__stride_expand(ListBase *lb,
const char *data,
const size_t data_len,
const size_t stride)
{
if (stride == 1) {
testbuffer_list_state_from_data(lb, data, data_len);
}
else {
const size_t data_stride_len = data_len * stride;
char *data_stride = (char *)MEM_mallocN(data_stride_len, __func__);
for (size_t i = 0, i_stride = 0; i < data_len; i += 1, i_stride += stride) {
memset(&data_stride[i_stride], data[i], stride);
}
testbuffer_list_add(lb, (const void *)data_stride, data_stride_len);
}
}
#define testbuffer_list_state_from_string_array(lb, data_array) \
{ \
unsigned int i_ = 0; \
const char *data; \
while ((data = data_array[i_++])) { \
testbuffer_list_state_from_data(lb, data, strlen(data)); \
} \
} \
((void)0)
//
#define TESTBUFFER_STRINGS_CREATE(lb, ...) \
{ \
BLI_listbase_clear(lb); \
const char *data_array[] = {__VA_ARGS__ NULL}; \
testbuffer_list_state_from_string_array((lb), data_array); \
} \
((void)0)
/* test in both directions */
#define TESTBUFFER_STRINGS_EX(bs, ...) \
{ \
ListBase lb; \
TESTBUFFER_STRINGS_CREATE(&lb, __VA_ARGS__); \
\
testbuffer_run_tests(bs, &lb); \
\
testbuffer_list_free(&lb); \
} \
((void)0)
#define TESTBUFFER_STRINGS(stride, chunk_count, ...) \
{ \
ListBase lb; \
TESTBUFFER_STRINGS_CREATE(&lb, __VA_ARGS__); \
\
testbuffer_run_tests_simple(&lb, stride, chunk_count); \
\
testbuffer_list_free(&lb); \
} \
((void)0)
static bool testbuffer_item_validate(TestBuffer *tb)
{
size_t data_state_len;
bool ok = true;
void *data_state = BLI_array_store_state_data_get_alloc(tb->state, &data_state_len);
if (tb->data_len != data_state_len) {
ok = false;
}
else if (memcmp(data_state, tb->data, data_state_len) != 0) {
ok = false;
}
MEM_freeN(data_state);
return ok;
}
static bool testbuffer_list_validate(const ListBase *lb)
{
for (TestBuffer *tb = (TestBuffer *)lb->first; tb; tb = tb->next) {
if (!testbuffer_item_validate(tb)) {
return false;
}
}
return true;
}
static void testbuffer_list_data_randomize(ListBase *lb, unsigned int random_seed)
{
for (TestBuffer *tb = (TestBuffer *)lb->first; tb; tb = tb->next) {
BLI_array_randomize((void *)tb->data, 1, tb->data_len, random_seed++);
}
}
static void testbuffer_list_store_populate(BArrayStore *bs, ListBase *lb)
{
for (TestBuffer *tb = (TestBuffer *)lb->first, *tb_prev = NULL; tb;
tb_prev = tb, tb = tb->next) {
tb->state = BLI_array_store_state_add(
bs, tb->data, tb->data_len, (tb_prev ? tb_prev->state : NULL));
}
}
static void testbuffer_list_store_clear(BArrayStore *bs, ListBase *lb)
{
for (TestBuffer *tb = (TestBuffer *)lb->first; tb; tb = tb->next) {
BLI_array_store_state_remove(bs, tb->state);
tb->state = NULL;
}
}
static void testbuffer_list_free(ListBase *lb)
{
for (TestBuffer *tb = (TestBuffer *)lb->first, *tb_next; tb; tb = tb_next) {
tb_next = tb->next;
MEM_freeN((void *)tb->data);
MEM_freeN(tb);
}
BLI_listbase_clear(lb);
}
static void testbuffer_run_tests_single(BArrayStore *bs, ListBase *lb)
{
testbuffer_list_store_populate(bs, lb);
EXPECT_TRUE(testbuffer_list_validate(lb));
EXPECT_TRUE(BLI_array_store_is_valid(bs));
#ifdef DEBUG_PRINT
print_mem_saved("data", bs);
#endif
}
/* avoid copy-paste code to run tests */
static void testbuffer_run_tests(BArrayStore *bs, ListBase *lb)
{
/* forwards */
testbuffer_run_tests_single(bs, lb);
testbuffer_list_store_clear(bs, lb);
BLI_listbase_reverse(lb);
/* backwards */
testbuffer_run_tests_single(bs, lb);
testbuffer_list_store_clear(bs, lb);
}
static void testbuffer_run_tests_simple(ListBase *lb, const int stride, const int chunk_count)
{
BArrayStore *bs = BLI_array_store_create(stride, chunk_count);
testbuffer_run_tests(bs, lb);
BLI_array_store_destroy(bs);
}
/* -------------------------------------------------------------------- */
/* Basic Tests */
TEST(array_store, Nop)
{
BArrayStore *bs = BLI_array_store_create(1, 32);
BLI_array_store_destroy(bs);
}
TEST(array_store, NopState)
{
BArrayStore *bs = BLI_array_store_create(1, 32);
const unsigned char data[] = "test";
BArrayState *state = BLI_array_store_state_add(bs, data, sizeof(data) - 1, NULL);
EXPECT_EQ(BLI_array_store_state_size_get(state), sizeof(data) - 1);
BLI_array_store_state_remove(bs, state);
BLI_array_store_destroy(bs);
}
TEST(array_store, Single)
{
BArrayStore *bs = BLI_array_store_create(1, 32);
const char data_src[] = "test";
const char *data_dst;
BArrayState *state = BLI_array_store_state_add(bs, data_src, sizeof(data_src), NULL);
size_t data_dst_len;
data_dst = (char *)BLI_array_store_state_data_get_alloc(state, &data_dst_len);
EXPECT_STREQ(data_src, data_dst);
EXPECT_EQ(data_dst_len, sizeof(data_src));
BLI_array_store_destroy(bs);
MEM_freeN((void *)data_dst);
}
TEST(array_store, DoubleNop)
{
BArrayStore *bs = BLI_array_store_create(1, 32);
const char data_src[] = "test";
const char *data_dst;
BArrayState *state_a = BLI_array_store_state_add(bs, data_src, sizeof(data_src), NULL);
BArrayState *state_b = BLI_array_store_state_add(bs, data_src, sizeof(data_src), state_a);
EXPECT_EQ(BLI_array_store_calc_size_compacted_get(bs), sizeof(data_src));
EXPECT_EQ(BLI_array_store_calc_size_expanded_get(bs), sizeof(data_src) * 2);
size_t data_dst_len;
data_dst = (char *)BLI_array_store_state_data_get_alloc(state_a, &data_dst_len);
EXPECT_STREQ(data_src, data_dst);
MEM_freeN((void *)data_dst);
data_dst = (char *)BLI_array_store_state_data_get_alloc(state_b, &data_dst_len);
EXPECT_STREQ(data_src, data_dst);
MEM_freeN((void *)data_dst);
EXPECT_EQ(data_dst_len, sizeof(data_src));
BLI_array_store_destroy(bs);
}
TEST(array_store, DoubleDiff)
{
BArrayStore *bs = BLI_array_store_create(1, 32);
const char data_src_a[] = "test";
const char data_src_b[] = "####";
const char *data_dst;
BArrayState *state_a = BLI_array_store_state_add(bs, data_src_a, sizeof(data_src_a), NULL);
BArrayState *state_b = BLI_array_store_state_add(bs, data_src_b, sizeof(data_src_b), state_a);
size_t data_dst_len;
EXPECT_EQ(BLI_array_store_calc_size_compacted_get(bs), sizeof(data_src_a) * 2);
EXPECT_EQ(BLI_array_store_calc_size_expanded_get(bs), sizeof(data_src_a) * 2);
data_dst = (char *)BLI_array_store_state_data_get_alloc(state_a, &data_dst_len);
EXPECT_STREQ(data_src_a, data_dst);
MEM_freeN((void *)data_dst);
data_dst = (char *)BLI_array_store_state_data_get_alloc(state_b, &data_dst_len);
EXPECT_STREQ(data_src_b, data_dst);
MEM_freeN((void *)data_dst);
BLI_array_store_destroy(bs);
}
TEST(array_store, TextMixed)
{
TESTBUFFER_STRINGS(1, 4, "", );
TESTBUFFER_STRINGS(1, 4, "test", );
TESTBUFFER_STRINGS(1, 4, "", "test", );
TESTBUFFER_STRINGS(1, 4, "test", "", );
TESTBUFFER_STRINGS(1, 4, "test", "", "test", );
TESTBUFFER_STRINGS(1, 4, "", "test", "", );
}
TEST(array_store, TextDupeIncreaseDecrease)
{
ListBase lb;
#define D "#1#2#3#4"
TESTBUFFER_STRINGS_CREATE(&lb, D, D D, D D D, D D D D, );
BArrayStore *bs = BLI_array_store_create(1, 8);
/* forward */
testbuffer_list_store_populate(bs, &lb);
EXPECT_TRUE(testbuffer_list_validate(&lb));
EXPECT_TRUE(BLI_array_store_is_valid(bs));
EXPECT_EQ(BLI_array_store_calc_size_compacted_get(bs), strlen(D));
testbuffer_list_store_clear(bs, &lb);
BLI_listbase_reverse(&lb);
/* backwards */
testbuffer_list_store_populate(bs, &lb);
EXPECT_TRUE(testbuffer_list_validate(&lb));
EXPECT_TRUE(BLI_array_store_is_valid(bs));
/* larger since first block doesn't de-duplicate */
EXPECT_EQ(BLI_array_store_calc_size_compacted_get(bs), strlen(D) * 4);
#undef D
testbuffer_list_free(&lb);
BLI_array_store_destroy(bs);
}
/* -------------------------------------------------------------------- */
/* Plain Text Tests */
/**
* Test that uses text input with different params for the array-store
* to ensure no corner cases fail.
*/
static void plain_text_helper(const char *words,
int words_len,
const char word_delim,
const int stride,
const int chunk_count,
const int random_seed)
{
ListBase lb;
BLI_listbase_clear(&lb);
for (int i = 0, i_prev = 0; i < words_len; i++) {
if (ELEM(words[i], word_delim, '\0')) {
if (i != i_prev) {
testbuffer_list_state_from_data__stride_expand(&lb, &words[i_prev], i - i_prev, stride);
}
i_prev = i;
}
}
if (random_seed) {
testbuffer_list_data_randomize(&lb, random_seed);
}
testbuffer_run_tests_simple(&lb, stride, chunk_count);
testbuffer_list_free(&lb);
}
/* split by '.' (multiple words) */
#define WORDS words10k, sizeof(words10k)
TEST(array_store, TextSentences_Chunk1)
{
plain_text_helper(WORDS, '.', 1, 1, 0);
}
TEST(array_store, TextSentences_Chunk2)
{
plain_text_helper(WORDS, '.', 1, 2, 0);
}
TEST(array_store, TextSentences_Chunk8)
{
plain_text_helper(WORDS, '.', 1, 8, 0);
}
TEST(array_store, TextSentences_Chunk32)
{
plain_text_helper(WORDS, '.', 1, 32, 0);
}
TEST(array_store, TextSentences_Chunk128)
{
plain_text_helper(WORDS, '.', 1, 128, 0);
}
TEST(array_store, TextSentences_Chunk1024)
{
plain_text_helper(WORDS, '.', 1, 1024, 0);
}
/* odd numbers */
TEST(array_store, TextSentences_Chunk3)
{
plain_text_helper(WORDS, '.', 1, 3, 0);
}
TEST(array_store, TextSentences_Chunk13)
{
plain_text_helper(WORDS, '.', 1, 13, 0);
}
TEST(array_store, TextSentences_Chunk131)
{
plain_text_helper(WORDS, '.', 1, 131, 0);
}
/* split by ' ', individual words */
TEST(array_store, TextWords_Chunk1)
{
plain_text_helper(WORDS, ' ', 1, 1, 0);
}
TEST(array_store, TextWords_Chunk2)
{
plain_text_helper(WORDS, ' ', 1, 2, 0);
}
TEST(array_store, TextWords_Chunk8)
{
plain_text_helper(WORDS, ' ', 1, 8, 0);
}
TEST(array_store, TextWords_Chunk32)
{
plain_text_helper(WORDS, ' ', 1, 32, 0);
}
TEST(array_store, TextWords_Chunk128)
{
plain_text_helper(WORDS, ' ', 1, 128, 0);
}
TEST(array_store, TextWords_Chunk1024)
{
plain_text_helper(WORDS, ' ', 1, 1024, 0);
}
/* odd numbers */
TEST(array_store, TextWords_Chunk3)
{
plain_text_helper(WORDS, ' ', 1, 3, 0);
}
TEST(array_store, TextWords_Chunk13)
{
plain_text_helper(WORDS, ' ', 1, 13, 0);
}
TEST(array_store, TextWords_Chunk131)
{
plain_text_helper(WORDS, ' ', 1, 131, 0);
}
/* various tests with different strides & randomizing */
TEST(array_store, TextSentencesRandom_Stride3_Chunk3)
{
plain_text_helper(WORDS, 'q', 3, 3, 7337);
}
TEST(array_store, TextSentencesRandom_Stride8_Chunk8)
{
plain_text_helper(WORDS, 'n', 8, 8, 5667);
}
TEST(array_store, TextSentencesRandom_Stride32_Chunk1)
{
plain_text_helper(WORDS, 'a', 1, 32, 1212);
}
TEST(array_store, TextSentencesRandom_Stride12_Chunk512)
{
plain_text_helper(WORDS, 'g', 12, 512, 9999);
}
TEST(array_store, TextSentencesRandom_Stride128_Chunk6)
{
plain_text_helper(WORDS, 'b', 20, 6, 1000);
}
#undef WORDS
/* -------------------------------------------------------------------- */
/* Random Data Tests */
static unsigned int rand_range_i(RNG *rng,
unsigned int min_i,
unsigned int max_i,
unsigned int step)
{
if (min_i == max_i) {
return min_i;
}
BLI_assert(min_i <= max_i);
BLI_assert(((min_i % step) == 0) && ((max_i % step) == 0));
unsigned int range = (max_i - min_i);
unsigned int value = BLI_rng_get_uint(rng) % range;
value = (value / step) * step;
return min_i + value;
}
static void testbuffer_list_state_random_data(ListBase *lb,
const size_t stride,
const size_t data_min_len,
const size_t data_max_len,
const unsigned int mutate,
RNG *rng)
{
size_t data_len = rand_range_i(rng, data_min_len, data_max_len + stride, stride);
char *data = (char *)MEM_mallocN(data_len, __func__);
if (lb->last == NULL) {
BLI_rng_get_char_n(rng, data, data_len);
}
else {
TestBuffer *tb_last = (TestBuffer *)lb->last;
if (tb_last->data_len >= data_len) {
memcpy(data, tb_last->data, data_len);
}
else {
memcpy(data, tb_last->data, tb_last->data_len);
BLI_rng_get_char_n(rng, &data[tb_last->data_len], data_len - tb_last->data_len);
}
/* perform multiple small mutations to the array. */
for (int i = 0; i < mutate; i++) {
enum {
MUTATE_NOP = 0,
MUTATE_ADD,
MUTATE_REMOVE,
MUTATE_ROTATE,
MUTATE_RANDOMIZE,
MUTATE_TOTAL,
};
switch ((BLI_rng_get_uint(rng) % MUTATE_TOTAL)) {
case MUTATE_NOP: {
break;
}
case MUTATE_ADD: {
const unsigned int offset = rand_range_i(rng, 0, data_len, stride);
if (data_len < data_max_len) {
data_len += stride;
data = (char *)MEM_reallocN((void *)data, data_len);
memmove(&data[offset + stride], &data[offset], data_len - (offset + stride));
BLI_rng_get_char_n(rng, &data[offset], stride);
}
break;
}
case MUTATE_REMOVE: {
const unsigned int offset = rand_range_i(rng, 0, data_len, stride);
if (data_len > data_min_len) {
memmove(&data[offset], &data[offset + stride], data_len - (offset + stride));
data_len -= stride;
}
break;
}
case MUTATE_ROTATE: {
int items = data_len / stride;
if (items > 1) {
_bli_array_wrap(data, items, stride, (BLI_rng_get_uint(rng) % 2) ? -1 : 1);
}
break;
}
case MUTATE_RANDOMIZE: {
if (data_len > 0) {
const unsigned int offset = rand_range_i(rng, 0, data_len - stride, stride);
BLI_rng_get_char_n(rng, &data[offset], stride);
}
break;
}
default:
BLI_assert(0);
}
}
}
testbuffer_list_add(lb, (const void *)data, data_len);
}
static void random_data_mutate_helper(const int items_size_min,
const int items_size_max,
const int items_total,
const int stride,
const int chunk_count,
const int random_seed,
const int mutate)
{
ListBase lb;
BLI_listbase_clear(&lb);
const size_t data_min_len = items_size_min * stride;
const size_t data_max_len = items_size_max * stride;
{
RNG *rng = BLI_rng_new(random_seed);
for (int i = 0; i < items_total; i++) {
testbuffer_list_state_random_data(&lb, stride, data_min_len, data_max_len, mutate, rng);
}
BLI_rng_free(rng);
}
testbuffer_run_tests_simple(&lb, stride, chunk_count);
testbuffer_list_free(&lb);
}
TEST(array_store, TestData_Stride1_Chunk32_Mutate2)
{
random_data_mutate_helper(0, 100, 400, 1, 32, 9779, 2);
}
TEST(array_store, TestData_Stride8_Chunk512_Mutate2)
{
random_data_mutate_helper(0, 128, 400, 8, 512, 1001, 2);
}
TEST(array_store, TestData_Stride12_Chunk48_Mutate2)
{
random_data_mutate_helper(200, 256, 400, 12, 48, 1331, 2);
}
TEST(array_store, TestData_Stride32_Chunk64_Mutate1)
{
random_data_mutate_helper(0, 256, 200, 32, 64, 3112, 1);
}
TEST(array_store, TestData_Stride32_Chunk64_Mutate8)
{
random_data_mutate_helper(0, 256, 200, 32, 64, 7117, 8);
}
/* -------------------------------------------------------------------- */
/* Randomized Chunks Test */
static void random_chunk_generate(ListBase *lb,
const int chunks_per_buffer,
const int stride,
const int chunk_count,
const int random_seed)
{
RNG *rng = BLI_rng_new(random_seed);
const size_t chunk_size_bytes = stride * chunk_count;
for (int i = 0; i < chunks_per_buffer; i++) {
char *data_chunk = (char *)MEM_mallocN(chunk_size_bytes, __func__);
BLI_rng_get_char_n(rng, data_chunk, chunk_size_bytes);
testchunk_list_add(lb, data_chunk, chunk_size_bytes);
}
BLI_rng_free(rng);
}
/**
* Add random chunks, then re-order them to ensure chunk de-duplication is working.
*/
static void random_chunk_mutate_helper(const int chunks_per_buffer,
const int items_total,
const int stride,
const int chunk_count,
const int random_seed)
{
/* generate random chunks */
ListBase random_chunks;
BLI_listbase_clear(&random_chunks);
random_chunk_generate(&random_chunks, chunks_per_buffer, stride, chunk_count, random_seed);
TestChunk **chunks_array = (TestChunk **)MEM_mallocN(chunks_per_buffer * sizeof(TestChunk *),
__func__);
{
TestChunk *tc = (TestChunk *)random_chunks.first;
for (int i = 0; i < chunks_per_buffer; i++, tc = tc->next) {
chunks_array[i] = tc;
}
}
/* add and re-order each time */
ListBase lb;
BLI_listbase_clear(&lb);
{
RNG *rng = BLI_rng_new(random_seed);
for (int i = 0; i < items_total; i++) {
BLI_rng_shuffle_array(rng, chunks_array, sizeof(TestChunk *), chunks_per_buffer);
size_t data_len;
char *data = testchunk_as_data_array(chunks_array, chunks_per_buffer, &data_len);
BLI_assert(data_len == chunks_per_buffer * chunk_count * stride);
testbuffer_list_add(&lb, (const void *)data, data_len);
}
BLI_rng_free(rng);
}
testchunk_list_free(&random_chunks);
MEM_freeN(chunks_array);
BArrayStore *bs = BLI_array_store_create(stride, chunk_count);
testbuffer_run_tests_single(bs, &lb);
size_t expected_size = chunks_per_buffer * chunk_count * stride;
EXPECT_EQ(BLI_array_store_calc_size_compacted_get(bs), expected_size);
BLI_array_store_destroy(bs);
testbuffer_list_free(&lb);
}
TEST(array_store, TestChunk_Rand8_Stride1_Chunk64)
{
random_chunk_mutate_helper(8, 100, 1, 64, 9779);
}
TEST(array_store, TestChunk_Rand32_Stride1_Chunk64)
{
random_chunk_mutate_helper(32, 100, 1, 64, 1331);
}
TEST(array_store, TestChunk_Rand64_Stride8_Chunk32)
{
random_chunk_mutate_helper(64, 100, 8, 32, 2772);
}
TEST(array_store, TestChunk_Rand31_Stride11_Chunk21)
{
random_chunk_mutate_helper(31, 100, 11, 21, 7117);
}
#if 0
/* -------------------------------------------------------------------- */
/* Test From Files (disabled, keep for local tests.) */
void *file_read_binary_as_mem(const char *filepath, size_t pad_bytes, size_t *r_size)
{
FILE *fp = fopen(filepath, "rb");
void *mem = NULL;
if (fp) {
long int filelen_read;
fseek(fp, 0L, SEEK_END);
const long int filelen = ftell(fp);
if (filelen == -1) {
goto finally;
}
fseek(fp, 0L, SEEK_SET);
mem = MEM_mallocN(filelen + pad_bytes, __func__);
if (mem == NULL) {
goto finally;
}
filelen_read = fread(mem, 1, filelen, fp);
if ((filelen_read != filelen) || ferror(fp)) {
MEM_freeN(mem);
mem = NULL;
goto finally;
}
*r_size = filelen_read;
finally:
fclose(fp);
}
return mem;
}
TEST(array_store, PlainTextFiles)
{
ListBase lb;
BLI_listbase_clear(&lb);
BArrayStore *bs = BLI_array_store_create(1, 128);
for (int i = 0; i < 629; i++) {
char str[512];
BLI_snprintf(str, sizeof(str), "/src/py_array_cow/test_data/xz_data/%04d.c.xz", i);
// BLI_snprintf(str, sizeof(str), "/src/py_array_cow/test_data/c_code/%04d.c", i);
// printf("%s\n", str);
size_t data_len;
void *data;
data = file_read_binary_as_mem(str, 0, &data_len);
testbuffer_list_add(&lb, (const void *)data, data_len);
}
/* forwards */
testbuffer_list_store_populate(bs, &lb);
EXPECT_TRUE(testbuffer_list_validate(&lb));
EXPECT_TRUE(BLI_array_store_is_valid(bs));
# ifdef DEBUG_PRINT
print_mem_saved("source code forward", bs);
# endif
testbuffer_list_store_clear(bs, &lb);
BLI_listbase_reverse(&lb);
/* backwards */
testbuffer_list_store_populate(bs, &lb);
EXPECT_TRUE(testbuffer_list_validate(&lb));
EXPECT_TRUE(BLI_array_store_is_valid(bs));
# ifdef DEBUG_PRINT
print_mem_saved("source code backwards", bs);
# endif
testbuffer_list_free(&lb);
BLI_array_store_destroy(bs);
}
#endif

View File

@@ -1,191 +0,0 @@
/* Apache License, Version 2.0 */
#include "testing/testing.h"
#include "BLI_array_utils.h"
#include "BLI_utildefines.h"
#include "BLI_utildefines_stack.h"
/* -------------------------------------------------------------------- */
/* tests */
/* BLI_array_reverse */
TEST(array_utils, ReverseStringEmpty)
{
char data[] = "";
BLI_array_reverse(data, ARRAY_SIZE(data) - 1);
EXPECT_STREQ("", data);
}
TEST(array_utils, ReverseStringSingle)
{
char data[] = "0";
BLI_array_reverse(data, ARRAY_SIZE(data) - 1);
EXPECT_STREQ("0", data);
}
TEST(array_utils, ReverseString4)
{
char data[] = "0123";
BLI_array_reverse(data, ARRAY_SIZE(data) - 1);
EXPECT_STREQ("3210", data);
}
TEST(array_utils, ReverseInt4)
{
const int data_cmp[] = {3, 2, 1, 0};
int data[] = {0, 1, 2, 3};
BLI_array_reverse(data, ARRAY_SIZE(data));
EXPECT_EQ_ARRAY(data_cmp, data, ARRAY_SIZE(data));
}
/* BLI_array_findindex */
TEST(array_utils, FindIndexStringEmpty)
{
char data[] = "", find = '0';
EXPECT_EQ(BLI_array_findindex(data, ARRAY_SIZE(data) - 1, &find), -1);
EXPECT_EQ(BLI_array_rfindindex(data, ARRAY_SIZE(data) - 1, &find), -1);
}
TEST(array_utils, FindIndexStringSingle)
{
char data[] = "0", find = '0';
EXPECT_EQ(BLI_array_findindex(data, ARRAY_SIZE(data) - 1, &find), 0);
EXPECT_EQ(BLI_array_rfindindex(data, ARRAY_SIZE(data) - 1, &find), 0);
}
TEST(array_utils, FindIndexStringSingleMissing)
{
char data[] = "1", find = '0';
EXPECT_EQ(BLI_array_findindex(data, ARRAY_SIZE(data) - 1, &find), -1);
EXPECT_EQ(BLI_array_rfindindex(data, ARRAY_SIZE(data) - 1, &find), -1);
}
TEST(array_utils, FindIndexString4)
{
char data[] = "0123", find = '3';
EXPECT_EQ(BLI_array_findindex(data, ARRAY_SIZE(data) - 1, &find), 3);
EXPECT_EQ(BLI_array_rfindindex(data, ARRAY_SIZE(data) - 1, &find), 3);
}
TEST(array_utils, FindIndexInt4)
{
int data[] = {0, 1, 2, 3}, find = 3;
EXPECT_EQ(BLI_array_findindex(data, ARRAY_SIZE(data), &find), 3);
EXPECT_EQ(BLI_array_rfindindex(data, ARRAY_SIZE(data), &find), 3);
}
TEST(array_utils, FindIndexInt4_DupeEnd)
{
int data[] = {0, 1, 2, 0}, find = 0;
EXPECT_EQ(BLI_array_findindex(data, ARRAY_SIZE(data), &find), 0);
EXPECT_EQ(BLI_array_rfindindex(data, ARRAY_SIZE(data), &find), 3);
}
TEST(array_utils, FindIndexInt4_DupeMid)
{
int data[] = {1, 0, 0, 3}, find = 0;
EXPECT_EQ(BLI_array_findindex(data, ARRAY_SIZE(data), &find), 1);
EXPECT_EQ(BLI_array_rfindindex(data, ARRAY_SIZE(data), &find), 2);
}
TEST(array_utils, FindIndexPointer)
{
const char *data[4] = {NULL};
STACK_DECLARE(data);
STACK_INIT(data, ARRAY_SIZE(data));
const char *a = "a", *b = "b", *c = "c", *d = "d";
#define STACK_PUSH_AND_CHECK_FORWARD(v, i) \
{ \
STACK_PUSH(data, v); \
EXPECT_EQ(BLI_array_findindex(data, STACK_SIZE(data), &(v)), i); \
} \
((void)0)
#define STACK_PUSH_AND_CHECK_BACKWARD(v, i) \
{ \
STACK_PUSH(data, v); \
EXPECT_EQ(BLI_array_rfindindex(data, STACK_SIZE(data), &(v)), i); \
} \
((void)0)
#define STACK_PUSH_AND_CHECK_BOTH(v, i) \
{ \
STACK_PUSH(data, v); \
EXPECT_EQ(BLI_array_findindex(data, STACK_SIZE(data), &(v)), i); \
EXPECT_EQ(BLI_array_rfindindex(data, STACK_SIZE(data), &(v)), i); \
} \
((void)0)
STACK_PUSH_AND_CHECK_BOTH(a, 0);
STACK_PUSH_AND_CHECK_BOTH(b, 1);
STACK_PUSH_AND_CHECK_BOTH(c, 2);
STACK_PUSH_AND_CHECK_BOTH(d, 3);
STACK_POP(data);
STACK_PUSH_AND_CHECK_BACKWARD(a, 3);
STACK_POP(data);
STACK_PUSH_AND_CHECK_FORWARD(a, 0);
STACK_POP(data);
STACK_POP(data);
STACK_PUSH_AND_CHECK_BACKWARD(b, 2);
STACK_PUSH_AND_CHECK_BACKWARD(a, 3);
#undef STACK_PUSH_AND_CHECK_FORWARD
#undef STACK_PUSH_AND_CHECK_BACKWARD
#undef STACK_PUSH_AND_CHECK_BOTH
}
/* BLI_array_binary_and */
#define BINARY_AND_TEST(data_cmp, data_a, data_b, data_combine, length) \
{ \
BLI_array_binary_and(data_combine, data_a, data_b, length); \
EXPECT_EQ_ARRAY(data_cmp, data_combine, length); \
} \
((void)0)
TEST(array_utils, BinaryAndInt4Zero)
{
const int data_cmp[] = {0, 0, 0, 0};
int data_a[] = {0, 1, 0, 1}, data_b[] = {1, 0, 1, 0};
int data_combine[ARRAY_SIZE(data_cmp)];
BINARY_AND_TEST(data_cmp, data_a, data_b, data_combine, ARRAY_SIZE(data_cmp));
}
TEST(array_utils, BinaryAndInt4Mix)
{
const int data_cmp[] = {1, 0, 1, 0};
int data_a[] = {1, 1, 1, 1}, data_b[] = {1, 0, 1, 0};
int data_combine[ARRAY_SIZE(data_cmp)];
BINARY_AND_TEST(data_cmp, data_a, data_b, data_combine, ARRAY_SIZE(data_cmp));
}
#undef BINARY_AND_TEST
/* BLI_array_binary_or */
#define BINARY_OR_TEST(data_cmp, data_a, data_b, data_combine, length) \
{ \
BLI_array_binary_or(data_combine, data_a, data_b, length); \
EXPECT_EQ_ARRAY(data_combine, data_cmp, length); \
} \
((void)0)
TEST(array_utils, BinaryOrInt4Alternate)
{
int data_a[] = {0, 1, 0, 1}, data_b[] = {1, 0, 1, 0}, data_cmp[] = {1, 1, 1, 1};
int data_combine[ARRAY_SIZE(data_cmp)];
BINARY_OR_TEST(data_cmp, data_a, data_b, data_combine, ARRAY_SIZE(data_cmp));
}
TEST(array_utils, BinaryOrInt4Mix)
{
int data_a[] = {1, 1, 0, 0}, data_b[] = {0, 0, 1, 0}, data_cmp[] = {1, 1, 1, 0};
int data_combine[ARRAY_SIZE(data_cmp)];
BINARY_OR_TEST(data_cmp, data_a, data_b, data_combine, ARRAY_SIZE(data_cmp));
}
#undef BINARY_OR_TEST

View File

@@ -1,1758 +0,0 @@
/* Apache License, Version 2.0 */
#include "testing/testing.h"
#include "MEM_guardedalloc.h"
#include "BLI_math.h"
#include "BLI_rand.h"
#include "PIL_time.h"
#include "BLI_delaunay_2d.h"
#include <fstream>
#include <iostream>
#include <sstream>
#define DO_REGULAR_TESTS 1
#define DO_RANDOM_TESTS 0
#define DO_FILE_TESTS 0
static void fill_input_verts(CDT_input *r_input, float (*vcos)[2], int nverts)
{
r_input->verts_len = nverts;
r_input->edges_len = 0;
r_input->faces_len = 0;
r_input->vert_coords = vcos;
r_input->edges = NULL;
r_input->faces = NULL;
r_input->faces_start_table = NULL;
r_input->faces_len_table = NULL;
r_input->epsilon = 1e-5f;
r_input->skip_input_modify = false;
}
static void add_input_edges(CDT_input *r_input, int (*edges)[2], int nedges)
{
r_input->edges_len = nedges;
r_input->edges = edges;
}
static void add_input_faces(
CDT_input *r_input, int *faces, int *faces_start_table, int *faces_len_table, int nfaces)
{
r_input->faces_len = nfaces;
r_input->faces = faces;
r_input->faces_start_table = faces_start_table;
r_input->faces_len_table = faces_len_table;
}
/* The spec should have the form:
* #verts #edges #faces
* <float> <float> [#verts lines)
* <int> <int> [#edges lines]
* <int> <int> ... <int> [#faces lines]
*/
static void fill_input_from_string(CDT_input *r_input, const char *spec)
{
std::string line;
std::vector<std::vector<int>> faces;
int i, j;
int nverts, nedges, nfaces;
float(*p)[2];
int(*e)[2];
int *farr;
int *flen;
int *fstart;
std::istringstream ss(spec);
getline(ss, line);
std::istringstream hdrss(line);
hdrss >> nverts >> nedges >> nfaces;
if (nverts == 0) {
return;
}
p = (float(*)[2])MEM_malloc_arrayN(nverts, 2 * sizeof(float), __func__);
if (nedges > 0) {
e = (int(*)[2])MEM_malloc_arrayN(nedges, 2 * sizeof(int), __func__);
}
if (nfaces > 0) {
flen = (int *)MEM_malloc_arrayN(nfaces, sizeof(int), __func__);
fstart = (int *)MEM_malloc_arrayN(nfaces, sizeof(int), __func__);
}
i = 0;
while (i < nverts && getline(ss, line)) {
std::istringstream iss(line);
iss >> p[i][0] >> p[i][1];
i++;
}
i = 0;
while (i < nedges && getline(ss, line)) {
std::istringstream ess(line);
ess >> e[i][0] >> e[i][1];
i++;
}
i = 0;
while (i < nfaces && getline(ss, line)) {
std::istringstream fss(line);
int v;
faces.push_back(std::vector<int>());
while (fss >> v) {
faces[i].push_back(v);
}
i++;
}
fill_input_verts(r_input, p, nverts);
if (nedges > 0) {
add_input_edges(r_input, e, nedges);
}
if (nfaces > 0) {
for (i = 0; i < nfaces; i++) {
flen[i] = (int)faces[i].size();
if (i == 0) {
fstart[i] = 0;
}
else {
fstart[i] = fstart[i - 1] + flen[i - 1];
}
}
farr = (int *)MEM_malloc_arrayN(fstart[nfaces - 1] + flen[nfaces - 1], sizeof(int), __func__);
for (i = 0; i < nfaces; i++) {
for (j = 0; j < (int)faces[i].size(); j++) {
farr[fstart[i] + j] = faces[i][j];
}
}
add_input_faces(r_input, farr, fstart, flen, nfaces);
}
}
static void fill_input_from_file(CDT_input *in, const char *filename)
{
std::FILE *fp = std::fopen(filename, "rb");
if (fp) {
std::string contents;
std::fseek(fp, 0, SEEK_END);
contents.resize(std::ftell(fp));
std::rewind(fp);
std::fread(&contents[0], 1, contents.size(), fp);
std::fclose(fp);
fill_input_from_string(in, contents.c_str());
}
else {
printf("couldn't open file %s\n", filename);
}
}
static void free_spec_arrays(CDT_input *in)
{
if (in->vert_coords) {
MEM_freeN(in->vert_coords);
}
if (in->edges) {
MEM_freeN(in->edges);
}
if (in->faces_len_table) {
MEM_freeN(in->faces_len_table);
MEM_freeN(in->faces_start_table);
MEM_freeN(in->faces);
}
}
/* which output vert index goes with given input vertex? -1 if not found */
static int get_output_vert_index(const CDT_result *r, int in_index)
{
int i, j;
for (i = 0; i < r->verts_len; i++) {
for (j = 0; j < r->verts_orig_len_table[i]; j++) {
if (r->verts_orig[r->verts_orig_start_table[i] + j] == in_index) {
return i;
}
}
}
return -1;
}
/* which output edge index is for given output vert indices? */
static int get_edge(const CDT_result *r, int out_index_1, int out_index_2)
{
int i;
for (i = 0; i < r->edges_len; i++) {
if ((r->edges[i][0] == out_index_1 && r->edges[i][1] == out_index_2) ||
(r->edges[i][0] == out_index_2 && r->edges[i][1] == out_index_1))
return i;
}
return -1;
}
/* return true if given output edge has given input edge id in its originals list */
static bool out_edge_has_input_id(const CDT_result *r, int out_edge_index, int in_edge_index)
{
if (r->edges_orig == NULL)
return false;
if (out_edge_index < 0 || out_edge_index >= r->edges_len)
return false;
for (int i = 0; i < r->edges_orig_len_table[out_edge_index]; i++) {
if (r->edges_orig[r->edges_orig_start_table[out_edge_index] + i] == in_edge_index)
return true;
}
return false;
}
/* which face is for given output vertex ngon? */
static int get_face(const CDT_result *r, int *out_indices, int nverts)
{
int f, cycle_start, k, fstart;
bool ok;
if (r->faces_len == 0)
return -1;
for (f = 0; f < r->faces_len; f++) {
if (r->faces_len_table[f] != nverts)
continue;
fstart = r->faces_start_table[f];
for (cycle_start = 0; cycle_start < nverts; cycle_start++) {
ok = true;
for (k = 0; ok && k < nverts; k++) {
if (r->faces[fstart + ((cycle_start + k) % nverts)] != out_indices[k]) {
ok = false;
}
}
if (ok) {
return f;
}
}
}
return -1;
}
static int get_face_tri(const CDT_result *r, int out_index_1, int out_index_2, int out_index_3)
{
int tri[3];
tri[0] = out_index_1;
tri[1] = out_index_2;
tri[2] = out_index_3;
return get_face(r, tri, 3);
}
/* return true if given otuput face has given input face id in its originals list */
static bool out_face_has_input_id(const CDT_result *r, int out_face_index, int in_face_index)
{
if (r->faces_orig == NULL)
return false;
if (out_face_index < 0 || out_face_index >= r->faces_len)
return false;
for (int i = 0; i < r->faces_orig_len_table[out_face_index]; i++) {
if (r->faces_orig[r->faces_orig_start_table[out_face_index] + i] == in_face_index)
return true;
}
return false;
}
/* for debugging */
static void dump_result(CDT_result *r)
{
int i, j;
fprintf(stderr, "\nRESULT\n");
fprintf(stderr,
"verts_len=%d edges_len=%d faces_len=%d\n",
r->verts_len,
r->edges_len,
r->faces_len);
fprintf(stderr, "\nvert coords:\n");
for (i = 0; i < r->verts_len; i++)
fprintf(stderr, "%d: (%f,%f)\n", i, r->vert_coords[i][0], r->vert_coords[i][1]);
fprintf(stderr, "vert orig:\n");
for (i = 0; i < r->verts_len; i++) {
fprintf(stderr, "%d:", i);
for (j = 0; j < r->verts_orig_len_table[i]; j++)
fprintf(stderr, " %d", r->verts_orig[r->verts_orig_start_table[i] + j]);
fprintf(stderr, "\n");
}
fprintf(stderr, "\nedges:\n");
for (i = 0; i < r->edges_len; i++)
fprintf(stderr, "%d: (%d,%d)\n", i, r->edges[i][0], r->edges[i][1]);
if (r->edges_orig) {
fprintf(stderr, "edge orig:\n");
for (i = 0; i < r->edges_len; i++) {
fprintf(stderr, "%d:", i);
for (j = 0; j < r->edges_orig_len_table[i]; j++)
fprintf(stderr, " %d", r->edges_orig[r->edges_orig_start_table[i] + j]);
fprintf(stderr, "\n");
}
}
fprintf(stderr, "\nfaces:\n");
for (i = 0; i < r->faces_len; i++) {
fprintf(stderr, "%d: ", i);
for (j = 0; j < r->faces_len_table[i]; j++)
fprintf(stderr, " %d", r->faces[r->faces_start_table[i] + j]);
fprintf(stderr, "\n");
}
if (r->faces_orig) {
fprintf(stderr, "face orig:\n");
for (i = 0; i < r->faces_len; i++) {
fprintf(stderr, "%d:", i);
for (j = 0; j < r->faces_orig_len_table[i]; j++)
fprintf(stderr, " %d", r->faces_orig[r->faces_orig_start_table[i] + j]);
fprintf(stderr, "\n");
}
}
}
#if DO_REGULAR_TESTS
TEST(delaunay, Empty)
{
CDT_input in;
CDT_result *out;
fill_input_verts(&in, NULL, 0);
out = BLI_delaunay_2d_cdt_calc(&in, CDT_FULL);
EXPECT_NE((CDT_result *)NULL, out);
EXPECT_EQ(out->verts_len, 0);
EXPECT_EQ(out->edges_len, 0);
EXPECT_EQ(out->faces_len, 0);
BLI_delaunay_2d_cdt_free(out);
}
TEST(delaunay, OnePt)
{
CDT_input in;
CDT_result *out;
const char *spec = R"(1 0 0
0.0 0.0
)";
fill_input_from_string(&in, spec);
out = BLI_delaunay_2d_cdt_calc(&in, CDT_FULL);
EXPECT_EQ(out->verts_len, 1);
EXPECT_EQ(out->edges_len, 0);
EXPECT_EQ(out->faces_len, 0);
if (out->verts_len >= 1) {
EXPECT_EQ(out->vert_coords[0][0], 0.0f);
EXPECT_EQ(out->vert_coords[0][1], 0.0f);
}
free_spec_arrays(&in);
BLI_delaunay_2d_cdt_free(out);
}
TEST(delaunay, TwoPt)
{
CDT_input in;
CDT_result *out;
int v0_out, v1_out, e0_out;
const char *spec = R"(2 0 0
0.0 -0.75
0.0 0.75
)";
fill_input_from_string(&in, spec);
out = BLI_delaunay_2d_cdt_calc(&in, CDT_FULL);
EXPECT_EQ(out->verts_len, 2);
EXPECT_EQ(out->edges_len, 1);
EXPECT_EQ(out->faces_len, 0);
v0_out = get_output_vert_index(out, 0);
v1_out = get_output_vert_index(out, 1);
EXPECT_NE(v0_out, -1);
EXPECT_NE(v1_out, -1);
EXPECT_NE(v0_out, v1_out);
if (out->verts_len >= 2) {
EXPECT_NEAR(out->vert_coords[v0_out][0], 0.0, in.epsilon);
EXPECT_NEAR(out->vert_coords[v0_out][1], -0.75, in.epsilon);
EXPECT_NEAR(out->vert_coords[v1_out][0], 0.0, in.epsilon);
EXPECT_NEAR(out->vert_coords[v1_out][1], 0.75, in.epsilon);
}
e0_out = get_edge(out, v0_out, v1_out);
EXPECT_EQ(e0_out, 0);
free_spec_arrays(&in);
BLI_delaunay_2d_cdt_free(out);
}
TEST(delaunay, ThreePt)
{
CDT_input in;
CDT_result *out;
int v0_out, v1_out, v2_out;
int e0_out, e1_out, e2_out;
int f0_out;
const char *spec = R"(3 0 0
-0.1 -0.75
0.1 0.75
0.5 0.5
)";
fill_input_from_string(&in, spec);
out = BLI_delaunay_2d_cdt_calc(&in, CDT_FULL);
EXPECT_EQ(out->verts_len, 3);
EXPECT_EQ(out->edges_len, 3);
EXPECT_EQ(out->faces_len, 1);
v0_out = get_output_vert_index(out, 0);
v1_out = get_output_vert_index(out, 1);
v2_out = get_output_vert_index(out, 2);
EXPECT_TRUE(v0_out != -1 && v1_out != -1 && v2_out != -1);
EXPECT_TRUE(v0_out != v1_out && v0_out != v2_out && v1_out != v2_out);
e0_out = get_edge(out, v0_out, v1_out);
e1_out = get_edge(out, v1_out, v2_out);
e2_out = get_edge(out, v2_out, v0_out);
EXPECT_TRUE(e0_out != -1 && e1_out != -1 && e2_out != -1);
EXPECT_TRUE(e0_out != e1_out && e0_out != e2_out && e1_out != e2_out);
f0_out = get_face_tri(out, v0_out, v2_out, v1_out);
EXPECT_EQ(f0_out, 0);
free_spec_arrays(&in);
BLI_delaunay_2d_cdt_free(out);
}
TEST(delaunay, ThreePtsMerge)
{
CDT_input in;
CDT_result *out;
int v0_out, v1_out, v2_out;
const char *spec = R"(3 0 0
-0.05 -0.05
0.05 -0.05
0.0 0.03660254
)";
/* First with epsilon such that points are within that distance of each other */
fill_input_from_string(&in, spec);
in.epsilon = 0.21f;
out = BLI_delaunay_2d_cdt_calc(&in, CDT_FULL);
EXPECT_EQ(out->verts_len, 1);
EXPECT_EQ(out->edges_len, 0);
EXPECT_EQ(out->faces_len, 0);
v0_out = get_output_vert_index(out, 0);
v1_out = get_output_vert_index(out, 1);
v2_out = get_output_vert_index(out, 2);
EXPECT_EQ(v0_out, 0);
EXPECT_EQ(v1_out, 0);
EXPECT_EQ(v2_out, 0);
BLI_delaunay_2d_cdt_free(out);
/* Now with epsilon such that points are farther away than that.
* Note that the points won't merge with each other if distance is
* less than .01, but that they may merge with points on the Delaunay
* triangulation lines, so make epsilon even smaller to avoid that for
* this test.
*/
in.epsilon = 0.05f;
out = BLI_delaunay_2d_cdt_calc(&in, CDT_FULL);
EXPECT_EQ(out->verts_len, 3);
EXPECT_EQ(out->edges_len, 3);
EXPECT_EQ(out->faces_len, 1);
free_spec_arrays(&in);
BLI_delaunay_2d_cdt_free(out);
}
TEST(delaunay, MixedPts)
{
CDT_input in;
CDT_result *out;
int v0_out, v1_out, v2_out, v3_out;
int e0_out, e1_out, e2_out;
const char *spec = R"(4 3 0
0.0 0.0
-0.5 -0.5
-0.4 -0.25
-0.3 0.8
0 1
1 2
2 3
)";
fill_input_from_string(&in, spec);
out = BLI_delaunay_2d_cdt_calc(&in, CDT_FULL);
EXPECT_EQ(out->verts_len, 4);
EXPECT_EQ(out->edges_len, 6);
v0_out = get_output_vert_index(out, 0);
v1_out = get_output_vert_index(out, 1);
v2_out = get_output_vert_index(out, 2);
v3_out = get_output_vert_index(out, 3);
EXPECT_TRUE(v0_out != -1 && v1_out != -1 && v2_out != -1 && v3_out != -1);
e0_out = get_edge(out, v0_out, v1_out);
e1_out = get_edge(out, v1_out, v2_out);
e2_out = get_edge(out, v2_out, v3_out);
EXPECT_TRUE(e0_out != -1 && e1_out != -1 && e2_out != -1);
EXPECT_TRUE(out_edge_has_input_id(out, e0_out, 0));
EXPECT_TRUE(out_edge_has_input_id(out, e1_out, 1));
EXPECT_TRUE(out_edge_has_input_id(out, e2_out, 2));
free_spec_arrays(&in);
BLI_delaunay_2d_cdt_free(out);
}
TEST(delaunay, Quad0)
{
CDT_input in;
CDT_result *out;
int e_diag_out;
const char *spec = R"(4 0 0
0.0 1.0
1.0 0.0
2.0 0.1
2.25 0.5
)";
fill_input_from_string(&in, spec);
out = BLI_delaunay_2d_cdt_calc(&in, CDT_FULL);
EXPECT_EQ(out->verts_len, 4);
EXPECT_EQ(out->edges_len, 5);
e_diag_out = get_edge(out, 1, 3);
EXPECT_NE(e_diag_out, -1);
free_spec_arrays(&in);
BLI_delaunay_2d_cdt_free(out);
}
TEST(delaunay, Quad1)
{
CDT_input in;
CDT_result *out;
int e_diag_out;
const char *spec = R"(4 0 0
0.0 0.0
0.9 -1.0
2.0 0.0
0.9 3.0
)";
fill_input_from_string(&in, spec);
out = BLI_delaunay_2d_cdt_calc(&in, CDT_FULL);
EXPECT_EQ(out->verts_len, 4);
EXPECT_EQ(out->edges_len, 5);
e_diag_out = get_edge(out, 0, 2);
EXPECT_NE(e_diag_out, -1);
free_spec_arrays(&in);
BLI_delaunay_2d_cdt_free(out);
}
TEST(delaunay, Quad2)
{
CDT_input in;
CDT_result *out;
int e_diag_out;
const char *spec = R"(4 0 0
0.5 0.0
0.15 0.2
0.3 0.4
.45 0.35
)";
fill_input_from_string(&in, spec);
out = BLI_delaunay_2d_cdt_calc(&in, CDT_FULL);
EXPECT_EQ(out->verts_len, 4);
EXPECT_EQ(out->edges_len, 5);
e_diag_out = get_edge(out, 1, 3);
EXPECT_NE(e_diag_out, -1);
free_spec_arrays(&in);
BLI_delaunay_2d_cdt_free(out);
}
TEST(delaunay, Quad3)
{
CDT_input in;
CDT_result *out;
int e_diag_out;
const char *spec = R"(4 0 0
0.5 0.0
0.0 0.0
0.3 0.4
.45 0.35
)";
fill_input_from_string(&in, spec);
out = BLI_delaunay_2d_cdt_calc(&in, CDT_FULL);
EXPECT_EQ(out->verts_len, 4);
EXPECT_EQ(out->edges_len, 5);
e_diag_out = get_edge(out, 0, 2);
EXPECT_NE(e_diag_out, -1);
free_spec_arrays(&in);
BLI_delaunay_2d_cdt_free(out);
}
TEST(delaunay, Quad4)
{
CDT_input in;
CDT_result *out;
int e_diag_out;
const char *spec = R"(4 0 0
1.0 1.0
0.0 0.0
1.0 -3.0
0.0 1.0
)";
fill_input_from_string(&in, spec);
out = BLI_delaunay_2d_cdt_calc(&in, CDT_FULL);
EXPECT_EQ(out->verts_len, 4);
EXPECT_EQ(out->edges_len, 5);
e_diag_out = get_edge(out, 0, 1);
EXPECT_NE(e_diag_out, -1);
free_spec_arrays(&in);
BLI_delaunay_2d_cdt_free(out);
}
TEST(delaunay, LineInSquare)
{
CDT_input in;
CDT_result *out;
const char *spec = R"(6 1 1
-0.5 -0.5
0.5 -0.5
-0.5 0.5
0.5 0.5
-0.25 0.0
0.25 0.0
4 5
0 1 3 2
)";
fill_input_from_string(&in, spec);
out = BLI_delaunay_2d_cdt_calc(&in, CDT_CONSTRAINTS);
EXPECT_EQ(out->verts_len, 6);
EXPECT_EQ(out->faces_len, 1);
free_spec_arrays(&in);
BLI_delaunay_2d_cdt_free(out);
}
TEST(delaunay, CrossSegs)
{
CDT_input in;
CDT_result *out;
int v0_out, v1_out, v2_out, v3_out, v_intersect;
int i;
const char *spec = R"(4 2 0
-0.5 0.0
0.5 0.0
-0.4 -0.5
0.4 0.5
0 1
2 3
)";
fill_input_from_string(&in, spec);
out = BLI_delaunay_2d_cdt_calc(&in, CDT_FULL);
EXPECT_EQ(out->verts_len, 5);
EXPECT_EQ(out->edges_len, 8);
EXPECT_EQ(out->faces_len, 4);
v0_out = get_output_vert_index(out, 0);
v1_out = get_output_vert_index(out, 1);
v2_out = get_output_vert_index(out, 2);
v3_out = get_output_vert_index(out, 3);
EXPECT_TRUE(v0_out != -1 && v1_out != -1 && v2_out != -1 && v3_out != -1);
v_intersect = -1;
for (i = 0; i < out->verts_len; i++) {
if (i != v0_out && i != v1_out && i != v2_out && i != v3_out) {
EXPECT_EQ(v_intersect, -1);
v_intersect = i;
}
}
EXPECT_NE(v_intersect, -1);
if (v_intersect != -1) {
EXPECT_NEAR(out->vert_coords[v_intersect][0], 0.0f, in.epsilon);
EXPECT_NEAR(out->vert_coords[v_intersect][1], 0.0f, in.epsilon);
}
free_spec_arrays(&in);
BLI_delaunay_2d_cdt_free(out);
}
TEST(delaunay, DiamondCross)
{
CDT_input in;
CDT_result *out;
const char *spec = R"(7 5 0
0.0 0.0
1.0 3.0
2.0 0.0
1.0 -3.0
0.0 0.0
1.0 -3.0
1.0 3.0
0 1
1 2
2 3
3 4
5 6
)";
fill_input_from_string(&in, spec);
out = BLI_delaunay_2d_cdt_calc(&in, CDT_FULL);
EXPECT_EQ(out->verts_len, 4);
EXPECT_EQ(out->edges_len, 5);
EXPECT_EQ(out->faces_len, 2);
free_spec_arrays(&in);
BLI_delaunay_2d_cdt_free(out);
}
TEST(delaunay, TwoDiamondsCrossed)
{
CDT_input in;
CDT_result *out;
/* Input has some repetition of vertices, on purpose */
int e[][2] = {{0, 1}, {1, 2}, {2, 3}, {3, 4}, {5, 6}, {6, 7}, {7, 8}, {8, 9}, {10, 11}};
int v_out[12];
int e_out[9], e_cross_1, e_cross_2, e_cross_3;
int i;
const char *spec = R"(12 9 0
0.0 0.0
1.0 2.0
2.0 0.0
1.0 -2.0
0.0 0.0
3.0 0.0
4.0 2.0
5.0 0.0
4.0 -2.0
3.0 0.0
0.0 0.0
5.0 0.0
0 1
1 2
2 3
3 4
5 6
6 7
7 8
8 9
10 11
)";
fill_input_from_string(&in, spec);
out = BLI_delaunay_2d_cdt_calc(&in, CDT_FULL);
EXPECT_EQ(out->verts_len, 8);
EXPECT_EQ(out->edges_len, 15);
EXPECT_EQ(out->faces_len, 8);
for (i = 0; i < 12; i++) {
v_out[i] = get_output_vert_index(out, i);
EXPECT_NE(v_out[i], -1);
}
EXPECT_EQ(v_out[0], v_out[4]);
EXPECT_EQ(v_out[0], v_out[10]);
EXPECT_EQ(v_out[5], v_out[9]);
EXPECT_EQ(v_out[7], v_out[11]);
for (i = 0; i < 8; i++) {
e_out[i] = get_edge(out, v_out[e[i][0]], v_out[e[i][1]]);
EXPECT_NE(e_out[i], -1);
}
/* there won't be a single edge for the input cross edge, but rather 3 */
EXPECT_EQ(get_edge(out, v_out[10], v_out[11]), -1);
e_cross_1 = get_edge(out, v_out[0], v_out[2]);
e_cross_2 = get_edge(out, v_out[2], v_out[5]);
e_cross_3 = get_edge(out, v_out[5], v_out[7]);
EXPECT_TRUE(e_cross_1 != -1 && e_cross_2 != -1 && e_cross_3 != -1);
EXPECT_TRUE(out_edge_has_input_id(out, e_cross_1, 8));
EXPECT_TRUE(out_edge_has_input_id(out, e_cross_2, 8));
EXPECT_TRUE(out_edge_has_input_id(out, e_cross_3, 8));
free_spec_arrays(&in);
BLI_delaunay_2d_cdt_free(out);
}
TEST(delaunay, ManyCross)
{
CDT_input in;
CDT_result *out;
/* Input has some repetition of vertices, on purpose */
const char *spec = R"(27 21 0
0.0 0.0
6.0 9.0
15.0 18.0
35.0 13.0
43.0 18.0
57.0 12.0
69.0 10.0
78.0 0.0
91.0 0.0
107.0 22.0
123.0 0.0
0.0 0.0
10.0 -14.0
35.0 -8.0
43.0 -12.0
64.0 -13.0
78.0 0.0
91.0 0.0
102.0 -9.0
116.0 -9.0
123.0 0.0
43.0 18.0
43.0 -12.0
107.0 22.0
102.0 -9.0
0.0 0.0
123.0 0.0
0 1
1 2
2 3
3 4
4 5
5 6
6 7
7 8
8 9
9 10
11 12
12 13
13 14
14 15
15 16
17 18
18 19
19 20
21 22
23 24
25 26
)";
fill_input_from_string(&in, spec);
out = BLI_delaunay_2d_cdt_calc(&in, CDT_FULL);
EXPECT_EQ(out->verts_len, 19);
EXPECT_EQ(out->edges_len, 46);
EXPECT_EQ(out->faces_len, 28);
free_spec_arrays(&in);
BLI_delaunay_2d_cdt_free(out);
}
TEST(delaunay, TwoFace)
{
CDT_input in;
CDT_result *out;
int v_out[6], f0_out, f1_out, e0_out, e1_out, e2_out;
int i;
const char *spec = R"(6 0 2
0.0 0.0
1.0 0.0
0.5 1.0
1.1 1.0
1.1 0.0
1.6 1.0
0 1 2
3 4 5
)";
fill_input_from_string(&in, spec);
out = BLI_delaunay_2d_cdt_calc(&in, CDT_FULL);
EXPECT_EQ(out->verts_len, 6);
EXPECT_EQ(out->edges_len, 9);
EXPECT_EQ(out->faces_len, 4);
for (i = 0; i < 6; i++) {
v_out[i] = get_output_vert_index(out, i);
EXPECT_NE(v_out[i], -1);
}
f0_out = get_face(out, &v_out[0], 3);
f1_out = get_face(out, &v_out[3], 3);
EXPECT_NE(f0_out, -1);
EXPECT_NE(f1_out, -1);
e0_out = get_edge(out, v_out[0], v_out[1]);
e1_out = get_edge(out, v_out[1], v_out[2]);
e2_out = get_edge(out, v_out[2], v_out[0]);
EXPECT_NE(e0_out, -1);
EXPECT_NE(e1_out, -1);
EXPECT_NE(e2_out, -1);
EXPECT_TRUE(out_edge_has_input_id(out, e0_out, out->face_edge_offset + 0));
EXPECT_TRUE(out_edge_has_input_id(out, e1_out, out->face_edge_offset + 1));
EXPECT_TRUE(out_edge_has_input_id(out, e2_out, out->face_edge_offset + 2));
EXPECT_TRUE(out_face_has_input_id(out, f0_out, 0));
EXPECT_TRUE(out_face_has_input_id(out, f1_out, 1));
free_spec_arrays(&in);
BLI_delaunay_2d_cdt_free(out);
}
TEST(delaunay, OverlapFaces)
{
CDT_input in;
CDT_result *out;
int v_out[12], v_int1, v_int2, f0_out, f1_out, f2_out;
int i;
const char *spec = R"(12 0 3
0.0 0.0
1.0 0.0
1.0 1.0
0.0 1.0
0.5 0.5
1.5 0.5
1.5 1.3
0.5 1.3
0.1 0.1
0.3 0.1
0.3 0.3
0.1 0.3
0 1 2 3
4 5 6 7
8 9 10 11
)";
fill_input_from_string(&in, spec);
out = BLI_delaunay_2d_cdt_calc(&in, CDT_FULL);
EXPECT_EQ(out->verts_len, 14);
EXPECT_EQ(out->edges_len, 33);
EXPECT_EQ(out->faces_len, 20);
for (i = 0; i < 12; i++) {
v_out[i] = get_output_vert_index(out, i);
EXPECT_NE(v_out[i], -1);
}
v_int1 = 12;
v_int2 = 13;
if (out->verts_len > 13) {
if (fabsf(out->vert_coords[v_int1][0] - 1.0f) > in.epsilon) {
v_int1 = 13;
v_int2 = 12;
}
EXPECT_NEAR(out->vert_coords[v_int1][0], 1.0, in.epsilon);
EXPECT_NEAR(out->vert_coords[v_int1][1], 0.5, in.epsilon);
EXPECT_NEAR(out->vert_coords[v_int2][0], 0.5, in.epsilon);
EXPECT_NEAR(out->vert_coords[v_int2][1], 1.0, in.epsilon);
EXPECT_EQ(out->verts_orig_len_table[v_int1], 0);
EXPECT_EQ(out->verts_orig_len_table[v_int2], 0);
}
f0_out = get_face_tri(out, v_out[1], v_int1, v_out[4]);
EXPECT_NE(f0_out, -1);
EXPECT_TRUE(out_face_has_input_id(out, f0_out, 0));
f1_out = get_face_tri(out, v_out[4], v_int1, v_out[2]);
EXPECT_NE(f1_out, -1);
EXPECT_TRUE(out_face_has_input_id(out, f1_out, 0));
EXPECT_TRUE(out_face_has_input_id(out, f1_out, 1));
f2_out = get_face_tri(out, v_out[8], v_out[9], v_out[10]);
if (f2_out == -1)
f2_out = get_face_tri(out, v_out[8], v_out[9], v_out[11]);
EXPECT_NE(f2_out, -1);
EXPECT_TRUE(out_face_has_input_id(out, f2_out, 0));
EXPECT_TRUE(out_face_has_input_id(out, f2_out, 2));
BLI_delaunay_2d_cdt_free(out);
/* Different output types */
out = BLI_delaunay_2d_cdt_calc(&in, CDT_INSIDE);
EXPECT_EQ(out->faces_len, 18);
BLI_delaunay_2d_cdt_free(out);
out = BLI_delaunay_2d_cdt_calc(&in, CDT_CONSTRAINTS);
EXPECT_EQ(out->faces_len, 4);
BLI_delaunay_2d_cdt_free(out);
out = BLI_delaunay_2d_cdt_calc(&in, CDT_CONSTRAINTS_VALID_BMESH);
EXPECT_EQ(out->faces_len, 5);
free_spec_arrays(&in);
BLI_delaunay_2d_cdt_free(out);
}
TEST(delaunay, TwoSquaresOverlap)
{
CDT_input in;
CDT_result *out;
const char *spec = R"(8 0 2
1.0 -1.0
-1.0 -1.0
-1.0 1.0
1.0 1.0
-1.5 1.5
0.5 1.5
0.5 -0.5
-1.5 -0.5
7 6 5 4
3 2 1 0
)";
fill_input_from_string(&in, spec);
out = BLI_delaunay_2d_cdt_calc(&in, CDT_CONSTRAINTS_VALID_BMESH);
EXPECT_EQ(out->verts_len, 10);
EXPECT_EQ(out->edges_len, 12);
EXPECT_EQ(out->faces_len, 3);
free_spec_arrays(&in);
BLI_delaunay_2d_cdt_free(out);
}
TEST(delaunay, TwoFaceEdgeOverlap)
{
CDT_input in;
CDT_result *out;
int i, v_out[6], v_int;
int e01, e1i, ei2, e20, e24, e4i, ei0;
int f02i, f24i, f10i;
const char *spec = R"(6 0 2
5.657 0.0
-1.414 -5.831
0.0 0.0
5.657 0.0
-2.121 -2.915
0.0 0.0
2 1 0
5 4 3
)";
fill_input_from_string(&in, spec);
out = BLI_delaunay_2d_cdt_calc(&in, CDT_CONSTRAINTS);
EXPECT_EQ(out->verts_len, 5);
EXPECT_EQ(out->edges_len, 7);
EXPECT_EQ(out->faces_len, 3);
if (out->verts_len == 5 && out->edges_len == 7 && out->faces_len == 3) {
v_int = 4;
for (i = 0; i < 6; i++) {
v_out[i] = get_output_vert_index(out, i);
EXPECT_NE(v_out[i], -1);
EXPECT_NE(v_out[i], v_int);
}
EXPECT_EQ(v_out[0], v_out[3]);
EXPECT_EQ(v_out[2], v_out[5]);
e01 = get_edge(out, v_out[0], v_out[1]);
EXPECT_TRUE(out_edge_has_input_id(out, e01, 1));
e1i = get_edge(out, v_out[1], v_int);
EXPECT_TRUE(out_edge_has_input_id(out, e1i, 0));
ei2 = get_edge(out, v_int, v_out[2]);
EXPECT_TRUE(out_edge_has_input_id(out, ei2, 0));
e20 = get_edge(out, v_out[2], v_out[0]);
EXPECT_TRUE(out_edge_has_input_id(out, e20, 2));
EXPECT_TRUE(out_edge_has_input_id(out, e20, 5));
e24 = get_edge(out, v_out[2], v_out[4]);
EXPECT_TRUE(out_edge_has_input_id(out, e24, 3));
e4i = get_edge(out, v_out[4], v_int);
EXPECT_TRUE(out_edge_has_input_id(out, e4i, 4));
ei0 = get_edge(out, v_int, v_out[0]);
EXPECT_TRUE(out_edge_has_input_id(out, ei0, 4));
f02i = get_face_tri(out, v_out[0], v_out[2], v_int);
EXPECT_NE(f02i, -1);
EXPECT_TRUE(out_face_has_input_id(out, f02i, 0));
EXPECT_TRUE(out_face_has_input_id(out, f02i, 1));
f24i = get_face_tri(out, v_out[2], v_out[4], v_int);
EXPECT_NE(f24i, -1);
EXPECT_TRUE(out_face_has_input_id(out, f24i, 1));
EXPECT_FALSE(out_face_has_input_id(out, f24i, 0));
f10i = get_face_tri(out, v_out[1], v_out[0], v_int);
EXPECT_NE(f10i, -1);
EXPECT_TRUE(out_face_has_input_id(out, f10i, 0));
EXPECT_FALSE(out_face_has_input_id(out, f10i, 1));
}
free_spec_arrays(&in);
BLI_delaunay_2d_cdt_free(out);
}
TEST(delaunay, TriInTri)
{
CDT_input in;
CDT_result *out;
const char *spec = R"(6 0 2
-5.65685 0.0
1.41421 -5.83095
0.0 0.0
-2.47487 -1.45774
-0.707107 -2.91548
-1.06066 -1.45774
0 1 2
3 4 5
)";
fill_input_from_string(&in, spec);
out = BLI_delaunay_2d_cdt_calc(&in, CDT_CONSTRAINTS_VALID_BMESH);
EXPECT_EQ(out->verts_len, 6);
EXPECT_EQ(out->edges_len, 8);
EXPECT_EQ(out->faces_len, 3);
free_spec_arrays(&in);
BLI_delaunay_2d_cdt_free(out);
}
TEST(delaunay, DiamondInSquare)
{
CDT_input in;
CDT_result *out;
const char *spec = R"(8 0 2
0.0 0.0
1.0 0.0
1.0 1.0
0.0 1.0
0.14644660940672627 0.5
0.5 0.14644660940672627
0.8535533905932737 0.5
0.5 0.8535533905932737
0 1 2 3
4 5 6 7
)";
fill_input_from_string(&in, spec);
out = BLI_delaunay_2d_cdt_calc(&in, CDT_CONSTRAINTS_VALID_BMESH);
EXPECT_EQ(out->verts_len, 8);
EXPECT_EQ(out->edges_len, 10);
EXPECT_EQ(out->faces_len, 3);
free_spec_arrays(&in);
BLI_delaunay_2d_cdt_free(out);
}
TEST(delaunay, DiamondInSquareWire)
{
CDT_input in;
CDT_result *out;
const char *spec = R"(8 8 0
0.0 0.0
1.0 0.0
1.0 1.0
0.0 1.0
0.14644660940672627 0.5
0.5 0.14644660940672627
0.8535533905932737 0.5
0.5 0.8535533905932737
0 1
1 2
2 3
3 0
4 5
5 6
6 7
7 4
)";
fill_input_from_string(&in, spec);
out = BLI_delaunay_2d_cdt_calc(&in, CDT_CONSTRAINTS);
EXPECT_EQ(out->verts_len, 8);
EXPECT_EQ(out->edges_len, 8);
EXPECT_EQ(out->faces_len, 2);
free_spec_arrays(&in);
BLI_delaunay_2d_cdt_free(out);
}
TEST(delaunay, TinyEdge)
{
CDT_input in;
CDT_result *out;
/* An intersect with triangle would be at (0.8, 0.2). */
const char *spec = R"(4 1 1
0.0 0.0
1.0 0.0
0.5 0.5
0.84 0.21
0 3
0 1 2
)";
fill_input_from_string(&in, spec);
in.epsilon = 0.1;
out = BLI_delaunay_2d_cdt_calc(&in, CDT_CONSTRAINTS);
EXPECT_EQ(out->verts_len, 4);
EXPECT_EQ(out->edges_len, 5);
EXPECT_EQ(out->faces_len, 2);
free_spec_arrays(&in);
BLI_delaunay_2d_cdt_free(out);
}
TEST(delaunay, TinyEdge2)
{
CDT_input in;
CDT_result *out;
/* An intersect with triangle would be at (0.8, 0.2). */
const char *spec = R"(6 1 1
0.0 0.0
0.2 -0.2
1.0 0.0
0.5 0.5
0.2 0.4
0.84 0.21
0 5
0 1 2 3 4
)";
fill_input_from_string(&in, spec);
in.epsilon = 0.1;
out = BLI_delaunay_2d_cdt_calc(&in, CDT_CONSTRAINTS);
EXPECT_EQ(out->verts_len, 6);
EXPECT_EQ(out->edges_len, 7);
EXPECT_EQ(out->faces_len, 2);
free_spec_arrays(&in);
BLI_delaunay_2d_cdt_free(out);
}
TEST(delaunay, repeatededge)
{
CDT_input in;
CDT_result *out;
const char *spec = R"(5 3 0
0.0 0.0
0.0 1.0
1.0 1.1
0.5 -0.5
0.5 2.5
0 1
2 3
2 3
)";
fill_input_from_string(&in, spec);
out = BLI_delaunay_2d_cdt_calc(&in, CDT_CONSTRAINTS);
EXPECT_EQ(out->edges_len, 2);
free_spec_arrays(&in);
BLI_delaunay_2d_cdt_free(out);
}
TEST(delaunay, NearSeg)
{
CDT_input in;
CDT_result *out;
int v[4], e0, e1, e2, i;
const char *spec = R"(4 2 0
0.0 0.0
1.0 0.0
0.25 0.09
0.25 1.0
0 1
2 3
)";
fill_input_from_string(&in, spec);
in.epsilon = 0.1;
out = BLI_delaunay_2d_cdt_calc(&in, CDT_CONSTRAINTS);
EXPECT_EQ(out->verts_len, 4);
EXPECT_EQ(out->edges_len, 3);
EXPECT_EQ(out->faces_len, 0);
if (out->edges_len == 3) {
for (i = 0; i < 4; i++) {
v[i] = get_output_vert_index(out, i);
EXPECT_NE(v[i], -1);
}
e0 = get_edge(out, v[0], v[2]);
e1 = get_edge(out, v[2], v[1]);
e2 = get_edge(out, v[2], v[3]);
EXPECT_TRUE(out_edge_has_input_id(out, e0, 0));
EXPECT_TRUE(out_edge_has_input_id(out, e1, 0));
EXPECT_TRUE(out_edge_has_input_id(out, e2, 1));
}
free_spec_arrays(&in);
BLI_delaunay_2d_cdt_free(out);
}
TEST(delaunay, OverlapSegs)
{
CDT_input in;
CDT_result *out;
int v[4], e0, e1, e2, i;
const char *spec = R"(4 2 0
0.0 0.0
1.0 0.0
0.4 0.09
1.4 0.09
0 1
2 3
)";
fill_input_from_string(&in, spec);
in.epsilon = 0.1;
out = BLI_delaunay_2d_cdt_calc(&in, CDT_CONSTRAINTS);
EXPECT_EQ(out->verts_len, 4);
EXPECT_EQ(out->edges_len, 3);
EXPECT_EQ(out->faces_len, 0);
if (out->edges_len == 3) {
for (i = 0; i < 4; i++) {
v[i] = get_output_vert_index(out, i);
EXPECT_NE(v[i], -1);
}
e0 = get_edge(out, v[0], v[2]);
e1 = get_edge(out, v[2], v[1]);
e2 = get_edge(out, v[1], v[3]);
EXPECT_TRUE(out_edge_has_input_id(out, e0, 0));
EXPECT_TRUE(out_edge_has_input_id(out, e1, 0));
EXPECT_TRUE(out_edge_has_input_id(out, e1, 1));
EXPECT_TRUE(out_edge_has_input_id(out, e2, 1));
}
free_spec_arrays(&in);
BLI_delaunay_2d_cdt_free(out);
}
TEST(delaunay, NearSegWithDup)
{
CDT_input in;
CDT_result *out;
int v[5], e0, e1, e2, e3, i;
const char *spec = R"(5 3 0
0.0 0.0
1.0 0.0
0.25 0.09
0.25 1.0
0.75 0.09
0 1
2 3
2 4
)";
fill_input_from_string(&in, spec);
in.epsilon = 0.1;
out = BLI_delaunay_2d_cdt_calc(&in, CDT_CONSTRAINTS);
EXPECT_EQ(out->verts_len, 5);
EXPECT_EQ(out->edges_len, 4);
EXPECT_EQ(out->faces_len, 0);
if (out->edges_len == 5) {
for (i = 0; i < 5; i++) {
v[i] = get_output_vert_index(out, i);
EXPECT_NE(v[i], -1);
}
e0 = get_edge(out, v[0], v[2]);
e1 = get_edge(out, v[2], v[4]);
e2 = get_edge(out, v[4], v[1]);
e3 = get_edge(out, v[3], v[2]);
EXPECT_TRUE(out_edge_has_input_id(out, e0, 0));
EXPECT_TRUE(out_edge_has_input_id(out, e1, 0));
EXPECT_TRUE(out_edge_has_input_id(out, e1, 2));
EXPECT_TRUE(out_edge_has_input_id(out, e2, 0));
EXPECT_TRUE(out_edge_has_input_id(out, e3, 1));
}
free_spec_arrays(&in);
BLI_delaunay_2d_cdt_free(out);
}
TEST(delaunay, TwoNearSeg)
{
CDT_input in;
CDT_result *out;
int v[5], e0, e1, e2, e3, e4, i;
const char *spec = R"(5 3 0
0.0 0.0
1.0 0.0
0.25 0.09
0.25 1.0
0.75 0.09
0 1
3 2
3 4
)";
fill_input_from_string(&in, spec);
in.epsilon = 0.1;
out = BLI_delaunay_2d_cdt_calc(&in, CDT_CONSTRAINTS);
EXPECT_EQ(out->verts_len, 5);
EXPECT_EQ(out->edges_len, 5);
EXPECT_EQ(out->faces_len, 1);
if (out->edges_len == 5) {
for (i = 0; i < 5; i++) {
v[i] = get_output_vert_index(out, i);
EXPECT_NE(v[i], -1);
}
e0 = get_edge(out, v[0], v[2]);
e1 = get_edge(out, v[2], v[4]);
e2 = get_edge(out, v[4], v[1]);
e3 = get_edge(out, v[3], v[2]);
e4 = get_edge(out, v[3], v[4]);
EXPECT_TRUE(out_edge_has_input_id(out, e0, 0));
EXPECT_TRUE(out_edge_has_input_id(out, e1, 0));
EXPECT_TRUE(out_edge_has_input_id(out, e2, 0));
EXPECT_TRUE(out_edge_has_input_id(out, e3, 1));
EXPECT_TRUE(out_edge_has_input_id(out, e4, 2));
}
free_spec_arrays(&in);
BLI_delaunay_2d_cdt_free(out);
}
TEST(delaunay, FaceNearSegs)
{
CDT_input in;
CDT_result *out;
int v[9], e0, e1, e2, e3, i;
const char *spec = R"(8 1 2
0.0 0.0
2.0 0.0
1.0 1.0
0.21 0.2
1.79 0.2
0.51 0.5
1.49 0.5
1.0 0.19
2 7
0 1 2
3 4 6 5
)";
fill_input_from_string(&in, spec);
in.epsilon = 0.05;
out = BLI_delaunay_2d_cdt_calc(&in, CDT_CONSTRAINTS);
EXPECT_EQ(out->verts_len, 9);
EXPECT_EQ(out->edges_len, 13);
EXPECT_EQ(out->faces_len, 5);
if (out->verts_len == 9 && out->edges_len == 13) {
for (i = 0; i < 8; i++) {
v[i] = get_output_vert_index(out, i);
EXPECT_NE(v[i], -1);
}
v[8] = 8;
e0 = get_edge(out, v[0], v[1]);
e1 = get_edge(out, v[4], v[6]);
e2 = get_edge(out, v[3], v[0]);
e3 = get_edge(out, v[2], v[8]);
EXPECT_TRUE(out_edge_has_input_id(out, e0, 1));
EXPECT_TRUE(out_edge_has_input_id(out, e1, 2));
EXPECT_TRUE(out_edge_has_input_id(out, e1, 5));
EXPECT_TRUE(out_edge_has_input_id(out, e2, 3));
EXPECT_TRUE(out_edge_has_input_id(out, e3, 0));
}
free_spec_arrays(&in);
BLI_delaunay_2d_cdt_free(out);
}
TEST(delaunay, ChainNearIntersects)
{
CDT_input in;
CDT_result *out;
const char *spec = R"(6 10 0
0.8 1.25
1.25 0.75
3.25 1.25
5.0 1.9
2.5 4.0
1.0 2.25
0 1
1 2
2 3
3 4
4 5
5 0
0 2
5 2
4 2
1 3
)";
fill_input_from_string(&in, spec);
in.epsilon = 0.05;
out = BLI_delaunay_2d_cdt_calc(&in, CDT_CONSTRAINTS);
EXPECT_EQ(out->verts_len, 9);
EXPECT_EQ(out->edges_len, 16);
BLI_delaunay_2d_cdt_free(out);
in.epsilon = 0.11;
/* The chaining we want to test happens prematurely if modify input. */
in.skip_input_modify = true;
out = BLI_delaunay_2d_cdt_calc(&in, CDT_CONSTRAINTS);
EXPECT_EQ(out->verts_len, 6);
EXPECT_EQ(out->edges_len, 9);
free_spec_arrays(&in);
BLI_delaunay_2d_cdt_free(out);
}
#endif
#if DO_RANDOM_TESTS
enum {
RANDOM_PTS,
RANDOM_SEGS,
RANDOM_POLY,
RANDOM_TILTED_GRID,
RANDOM_CIRCLE,
RANDOM_TRI_BETWEEN_CIRCLES,
};
# define DO_TIMING
static void rand_delaunay_test(int test_kind,
int start_lg_size,
int max_lg_size,
int reps_per_size,
double param,
CDT_output_type otype)
{
CDT_input in;
CDT_result *out;
int lg_size, size, rep, i, j, size_max, npts_max, nedges_max, nfaces_max, npts, nedges, nfaces;
int ia, ib, ic;
float(*p)[2];
int(*e)[2];
int *faces, *faces_start_table, *faces_len_table;
double start_angle, angle_delta, angle1, angle2, angle3;
float orient;
double tstart;
double *times;
RNG *rng;
rng = BLI_rng_new(0);
e = NULL;
faces = NULL;
faces_start_table = NULL;
faces_len_table = NULL;
nedges_max = 0;
nfaces_max = 0;
/* Set up npts, nedges, nfaces, and allocate needed arrays at max length needed. */
size_max = 1 << max_lg_size;
switch (test_kind) {
case RANDOM_PTS:
case RANDOM_SEGS:
case RANDOM_POLY:
npts_max = size_max;
if (test_kind == RANDOM_SEGS) {
nedges_max = npts_max - 1;
}
else if (test_kind == RANDOM_POLY) {
nedges_max = npts_max;
}
break;
case RANDOM_TILTED_GRID:
/* A 'size' x 'size' grid of points, tilted by angle 'param'.
* Edges will go from left ends to right ends and tops to bottoms, so 2 x size of them.
* Depending on epsilon, the vertical-ish edges may or may not go through the intermediate
* vertices, but the horizontal ones always should.
*/
npts_max = size_max * size_max;
nedges_max = 2 * size_max;
break;
case RANDOM_CIRCLE:
/* A circle with 'size' points, a random start angle, and equal spacing thereafter.
* Will be input as one face.
*/
npts_max = size_max;
nfaces_max = 1;
break;
case RANDOM_TRI_BETWEEN_CIRCLES:
/* A set of 'size' triangles, each has two random points on the unit circle,
* and the third point is a random point on the circle with radius 'param'.
* Each triangle will be input as a face.
*/
npts_max = 3 * size_max;
nfaces_max = size_max;
break;
default:
fprintf(stderr, "unknown random delaunay test kind\n");
return;
}
p = (float(*)[2])MEM_malloc_arrayN(npts_max, 2 * sizeof(float), __func__);
if (nedges_max > 0) {
e = (int(*)[2])MEM_malloc_arrayN(nedges_max, 2 * sizeof(int), __func__);
}
if (nfaces_max > 0) {
faces_start_table = (int *)MEM_malloc_arrayN(nfaces_max, sizeof(int), __func__);
faces_len_table = (int *)MEM_malloc_arrayN(nfaces_max, sizeof(int), __func__);
faces = (int *)MEM_malloc_arrayN(npts_max, sizeof(int), __func__);
}
times = (double *)MEM_malloc_arrayN(max_lg_size + 1, sizeof(double), __func__);
/* For powers of 2 sizes up to max_lg_size power of 2. */
for (lg_size = start_lg_size; lg_size <= max_lg_size; lg_size++) {
size = 1 << lg_size;
nedges = 0;
nfaces = 0;
times[lg_size] = 0.0;
if (size == 1 && test_kind != RANDOM_PTS) {
continue;
}
/* Do 'rep' repetitions. */
for (rep = 0; rep < reps_per_size; rep++) {
/* Make vertices and edges or faces. */
switch (test_kind) {
case RANDOM_PTS:
case RANDOM_SEGS:
case RANDOM_POLY:
npts = size;
if (test_kind == RANDOM_SEGS) {
nedges = npts - 1;
}
else if (test_kind == RANDOM_POLY) {
nedges = npts;
}
for (i = 0; i < size; i++) {
p[i][0] = (float)BLI_rng_get_double(rng); /* will be in range in [0,1) */
p[i][1] = (float)BLI_rng_get_double(rng);
if (test_kind != RANDOM_PTS) {
if (i > 0) {
e[i - 1][0] = i - 1;
e[i - 1][1] = i;
}
}
}
if (test_kind == RANDOM_POLY) {
e[size - 1][0] = size - 1;
e[size - 1][1] = 0;
}
break;
case RANDOM_TILTED_GRID:
/* 'param' is slope of tilt of vertical lines. */
npts = size * size;
nedges = 2 * size;
for (i = 0; i < size; i++) {
for (j = 0; j < size; j++) {
p[i * size + j][0] = i * param + j;
p[i * size + j][1] = i;
}
}
for (i = 0; i < size; i++) {
/* Horizontal edges: connect p(i,0) to p(i,size-1). */
e[i][0] = i * size;
e[i][1] = i * size + size - 1;
/* Vertical edges: conntect p(0,i) to p(size-1,i). */
e[size + i][0] = i;
e[size + i][1] = (size - 1) * size + i;
}
break;
case RANDOM_CIRCLE:
npts = size;
nfaces = 1;
faces_start_table[0] = 0;
faces_len_table[0] = npts;
start_angle = BLI_rng_get_double(rng) * 2.0 * M_PI;
angle_delta = 2.0 * M_PI / size;
for (i = 0; i < size; i++) {
p[i][0] = (float)cos(start_angle + i * angle_delta);
p[i][1] = (float)sin(start_angle + i * angle_delta);
faces[i] = i;
}
break;
case RANDOM_TRI_BETWEEN_CIRCLES:
npts = 3 * size;
nfaces = size;
for (i = 0; i < size; i++) {
/* Get three random angles in [0, 2pi). */
angle1 = BLI_rng_get_double(rng) * 2.0 * M_PI;
angle2 = BLI_rng_get_double(rng) * 2.0 * M_PI;
angle3 = BLI_rng_get_double(rng) * 2.0 * M_PI;
ia = 3 * i;
ib = 3 * i + 1;
ic = 3 * i + 2;
p[ia][0] = (float)cos(angle1);
p[ia][1] = (float)sin(angle1);
p[ib][0] = (float)cos(angle2);
p[ib][1] = (float)sin(angle2);
p[ic][0] = (float)(param * cos(angle3));
p[ic][1] = (float)(param * sin(angle3));
faces_start_table[i] = 3 * i;
faces_len_table[i] = 3;
/* Put the coordinates in ccw order. */
faces[ia] = ia;
orient = (p[ia][0] - p[ic][0]) * (p[ib][1] - p[ic][1]) -
(p[ib][0] - p[ic][0]) * (p[ia][1] - p[ic][1]);
if (orient >= 0.0f) {
faces[ib] = ib;
faces[ic] = ic;
}
else {
faces[ib] = ic;
faces[ic] = ib;
}
}
break;
}
fill_input_verts(&in, p, npts);
if (nedges > 0) {
add_input_edges(&in, e, nedges);
}
if (nfaces > 0) {
add_input_faces(&in, faces, faces_start_table, faces_len_table, nfaces);
}
/* Run the test. */
tstart = PIL_check_seconds_timer();
out = BLI_delaunay_2d_cdt_calc(&in, otype);
EXPECT_NE(out->verts_len, 0);
BLI_delaunay_2d_cdt_free(out);
times[lg_size] += PIL_check_seconds_timer() - tstart;
}
}
# ifdef DO_TIMING
fprintf(stderr, "size,time\n");
for (lg_size = 0; lg_size <= max_lg_size; lg_size++) {
fprintf(stderr, "%d,%f\n", 1 << lg_size, times[lg_size] / reps_per_size);
}
# endif
MEM_freeN(p);
if (e) {
MEM_freeN(e);
}
if (faces) {
MEM_freeN(faces);
MEM_freeN(faces_start_table);
MEM_freeN(faces_len_table);
}
MEM_freeN(times);
BLI_rng_free(rng);
}
TEST(delaunay, randompts)
{
rand_delaunay_test(RANDOM_PTS, 0, 7, 1, 0.0, CDT_FULL);
}
TEST(delaunay, randomsegs)
{
rand_delaunay_test(RANDOM_SEGS, 1, 7, 1, 0.0, CDT_FULL);
}
TEST(delaunay, randompoly)
{
rand_delaunay_test(RANDOM_POLY, 1, 7, 1, 0.0, CDT_FULL);
}
TEST(delaunay, randompoly_inside)
{
rand_delaunay_test(RANDOM_POLY, 1, 7, 1, 0.0, CDT_INSIDE);
}
TEST(delaunay, randompoly_constraints)
{
rand_delaunay_test(RANDOM_POLY, 1, 7, 1, 0.0, CDT_CONSTRAINTS);
}
TEST(delaunay, randompoly_validbmesh)
{
rand_delaunay_test(RANDOM_POLY, 1, 7, 1, 0.0, CDT_CONSTRAINTS_VALID_BMESH);
}
TEST(delaunay, grid)
{
rand_delaunay_test(RANDOM_TILTED_GRID, 1, 6, 1, 0.0, CDT_FULL);
}
TEST(delaunay, tilted_grid_a)
{
rand_delaunay_test(RANDOM_TILTED_GRID, 1, 6, 1, 1.0, CDT_FULL);
}
TEST(delaunay, tilted_grid_b)
{
rand_delaunay_test(RANDOM_TILTED_GRID, 1, 6, 1, 0.01, CDT_FULL);
}
TEST(delaunay, randomcircle)
{
rand_delaunay_test(RANDOM_CIRCLE, 1, 7, 1, 0.0, CDT_FULL);
}
TEST(delaunay, random_tris_circle)
{
rand_delaunay_test(RANDOM_TRI_BETWEEN_CIRCLES, 1, 6, 1, 0.25, CDT_FULL);
}
TEST(delaunay, random_tris_circle_b)
{
rand_delaunay_test(RANDOM_TRI_BETWEEN_CIRCLES, 1, 6, 1, 1e-4, CDT_FULL);
}
#endif
#if DO_FILE_TESTS
/* For timing large examples of points only.
* See fill_input_from_file for file format.
*/
static void points_from_file_test(const char *filename)
{
CDT_input in;
CDT_result *out;
double tstart;
fill_input_from_file(&in, filename);
tstart = PIL_check_seconds_timer();
out = BLI_delaunay_2d_cdt_calc(&in, CDT_FULL);
fprintf(stderr, "time to triangulate=%f seconds\n", PIL_check_seconds_timer() - tstart);
BLI_delaunay_2d_cdt_free(out);
free_spec_arrays(&in);
}
# if 0
TEST(delaunay, debug)
{
CDT_input in;
CDT_result *out;
fill_input_from_file(&in, "/tmp/cdtinput.txt");
out = BLI_delaunay_2d_cdt_calc(&in, CDT_CONSTRAINTS);
BLI_delaunay_2d_cdt_free(out);
free_spec_arrays(&in);
}
# endif
# if 1
# define POINTFILEROOT "/tmp/"
TEST(delaunay, terrain1)
{
points_from_file_test(POINTFILEROOT "points1.txt");
}
TEST(delaunay, terrain2)
{
points_from_file_test(POINTFILEROOT "points2.txt");
}
TEST(delaunay, terrain3)
{
points_from_file_test(POINTFILEROOT "points3.txt");
}
# endif
#endif

View File

@@ -1,363 +0,0 @@
/* Apache License, Version 2.0 */
#include "testing/testing.h"
#include <string.h>
#include "BLI_expr_pylike_eval.h"
#include "BLI_math.h"
#define TRUE_VAL 1.0
#define FALSE_VAL 0.0
static void expr_pylike_parse_fail_test(const char *str)
{
ExprPyLike_Parsed *expr = BLI_expr_pylike_parse(str, NULL, 0);
EXPECT_FALSE(BLI_expr_pylike_is_valid(expr));
BLI_expr_pylike_free(expr);
}
static void expr_pylike_const_test(const char *str, double value, bool force_const)
{
ExprPyLike_Parsed *expr = BLI_expr_pylike_parse(str, NULL, 0);
if (force_const) {
EXPECT_TRUE(BLI_expr_pylike_is_constant(expr));
}
else {
EXPECT_TRUE(BLI_expr_pylike_is_valid(expr));
EXPECT_FALSE(BLI_expr_pylike_is_constant(expr));
}
double result;
eExprPyLike_EvalStatus status = BLI_expr_pylike_eval(expr, NULL, 0, &result);
EXPECT_EQ(status, EXPR_PYLIKE_SUCCESS);
EXPECT_EQ(result, value);
BLI_expr_pylike_free(expr);
}
static ExprPyLike_Parsed *parse_for_eval(const char *str, bool nonconst)
{
const char *names[1] = {"x"};
ExprPyLike_Parsed *expr = BLI_expr_pylike_parse(str, names, ARRAY_SIZE(names));
EXPECT_TRUE(BLI_expr_pylike_is_valid(expr));
if (nonconst) {
EXPECT_FALSE(BLI_expr_pylike_is_constant(expr));
}
return expr;
}
static void verify_eval_result(ExprPyLike_Parsed *expr, double x, double value)
{
double result;
eExprPyLike_EvalStatus status = BLI_expr_pylike_eval(expr, &x, 1, &result);
EXPECT_EQ(status, EXPR_PYLIKE_SUCCESS);
EXPECT_EQ(result, value);
}
static void expr_pylike_eval_test(const char *str, double x, double value)
{
ExprPyLike_Parsed *expr = parse_for_eval(str, true);
verify_eval_result(expr, x, value);
BLI_expr_pylike_free(expr);
}
static void expr_pylike_error_test(const char *str, double x, eExprPyLike_EvalStatus error)
{
ExprPyLike_Parsed *expr = parse_for_eval(str, false);
double result;
eExprPyLike_EvalStatus status = BLI_expr_pylike_eval(expr, &x, 1, &result);
EXPECT_EQ(status, error);
BLI_expr_pylike_free(expr);
}
#define TEST_PARSE_FAIL(name, str) \
TEST(expr_pylike, ParseFail_##name) \
{ \
expr_pylike_parse_fail_test(str); \
}
TEST_PARSE_FAIL(Empty, "")
TEST_PARSE_FAIL(ConstHex, "0x0")
TEST_PARSE_FAIL(ConstOctal, "01")
TEST_PARSE_FAIL(Tail, "0 0")
TEST_PARSE_FAIL(ConstFloatExp, "0.5e+")
TEST_PARSE_FAIL(BadId, "Pi")
TEST_PARSE_FAIL(BadArgCount0, "sqrt")
TEST_PARSE_FAIL(BadArgCount1, "sqrt()")
TEST_PARSE_FAIL(BadArgCount2, "sqrt(1,2)")
TEST_PARSE_FAIL(BadArgCount3, "pi()")
TEST_PARSE_FAIL(BadArgCount4, "max()")
TEST_PARSE_FAIL(BadArgCount5, "min()")
TEST_PARSE_FAIL(Truncated1, "(1+2")
TEST_PARSE_FAIL(Truncated2, "1 if 2")
TEST_PARSE_FAIL(Truncated3, "1 if 2 else")
TEST_PARSE_FAIL(Truncated4, "1 < 2 <")
TEST_PARSE_FAIL(Truncated5, "1 +")
TEST_PARSE_FAIL(Truncated6, "1 *")
TEST_PARSE_FAIL(Truncated7, "1 and")
TEST_PARSE_FAIL(Truncated8, "1 or")
TEST_PARSE_FAIL(Truncated9, "sqrt(1")
TEST_PARSE_FAIL(Truncated10, "fmod(1,")
/* Constant expression with working constant folding */
#define TEST_CONST(name, str, value) \
TEST(expr_pylike, Const_##name) \
{ \
expr_pylike_const_test(str, value, true); \
}
/* Constant expression but constant folding is not supported */
#define TEST_RESULT(name, str, value) \
TEST(expr_pylike, Result_##name) \
{ \
expr_pylike_const_test(str, value, false); \
}
/* Expression with an argument */
#define TEST_EVAL(name, str, x, value) \
TEST(expr_pylike, Eval_##name) \
{ \
expr_pylike_eval_test(str, x, value); \
}
TEST_CONST(Zero, "0", 0.0)
TEST_CONST(Zero2, "00", 0.0)
TEST_CONST(One, "1", 1.0)
TEST_CONST(OneF, "1.0", 1.0)
TEST_CONST(OneF2, "1.", 1.0)
TEST_CONST(OneE, "1e0", 1.0)
TEST_CONST(TenE, "1.e+1", 10.0)
TEST_CONST(Half, ".5", 0.5)
TEST_CONST(Pi, "pi", M_PI)
TEST_CONST(True, "True", TRUE_VAL)
TEST_CONST(False, "False", FALSE_VAL)
TEST_CONST(Sqrt, "sqrt(4)", 2.0)
TEST_EVAL(Sqrt, "sqrt(x)", 4.0, 2.0)
TEST_CONST(FMod, "fmod(3.5, 2)", 1.5)
TEST_EVAL(FMod, "fmod(x, 2)", 3.5, 1.5)
TEST_CONST(Pow, "pow(4, 0.5)", 2.0)
TEST_EVAL(Pow, "pow(4, x)", 0.5, 2.0)
TEST_CONST(Log2_1, "log(4, 2)", 2.0)
TEST_CONST(Round1, "round(-0.5)", -1.0)
TEST_CONST(Round2, "round(-0.4)", 0.0)
TEST_CONST(Round3, "round(0.4)", 0.0)
TEST_CONST(Round4, "round(0.5)", 1.0)
TEST_CONST(Clamp1, "clamp(-0.1)", 0.0)
TEST_CONST(Clamp2, "clamp(0.5)", 0.5)
TEST_CONST(Clamp3, "clamp(1.5)", 1.0)
TEST_CONST(Clamp4, "clamp(0.5, 0.2, 0.3)", 0.3)
TEST_CONST(Clamp5, "clamp(0.0, 0.2, 0.3)", 0.2)
TEST_CONST(Lerp1, "lerp(-10,10,-1)", -30.0)
TEST_CONST(Lerp2, "lerp(-10,10,0.25)", -5.0)
TEST_CONST(Lerp3, "lerp(-10,10,1)", 10.0)
TEST_EVAL(Lerp1, "lerp(-10,10,x)", 0, -10.0)
TEST_EVAL(Lerp2, "lerp(-10,10,x)", 0.75, 5.0)
TEST_CONST(Smoothstep1, "smoothstep(-10,10,-20)", 0.0)
TEST_CONST(Smoothstep2, "smoothstep(-10,10,-10)", 0.0)
TEST_CONST(Smoothstep3, "smoothstep(-10,10,10)", 1.0)
TEST_CONST(Smoothstep4, "smoothstep(-10,10,20)", 1.0)
TEST_CONST(Smoothstep5, "smoothstep(-10,10,-5)", 0.15625)
TEST_EVAL(Smoothstep1, "smoothstep(-10,10,x)", 5, 0.84375)
TEST_RESULT(Min1, "min(3,1,2)", 1.0)
TEST_RESULT(Max1, "max(3,1,2)", 3.0)
TEST_RESULT(Min2, "min(1,2,3)", 1.0)
TEST_RESULT(Max2, "max(1,2,3)", 3.0)
TEST_RESULT(Min3, "min(2,3,1)", 1.0)
TEST_RESULT(Max3, "max(2,3,1)", 3.0)
TEST_CONST(UnaryPlus, "+1", 1.0)
TEST_CONST(UnaryMinus, "-1", -1.0)
TEST_EVAL(UnaryMinus, "-x", 1.0, -1.0)
TEST_CONST(BinaryPlus, "1+2", 3.0)
TEST_EVAL(BinaryPlus, "x+2", 1, 3.0)
TEST_CONST(BinaryMinus, "1-2", -1.0)
TEST_EVAL(BinaryMinus, "1-x", 2, -1.0)
TEST_CONST(BinaryMul, "2*3", 6.0)
TEST_EVAL(BinaryMul, "x*3", 2, 6.0)
TEST_CONST(BinaryDiv, "3/2", 1.5)
TEST_EVAL(BinaryDiv, "3/x", 2, 1.5)
TEST_CONST(Arith1, "1 + -2 * 3", -5.0)
TEST_CONST(Arith2, "(1 + -2) * 3", -3.0)
TEST_CONST(Arith3, "-1 + 2 * 3", 5.0)
TEST_CONST(Arith4, "3 * (-2 + 1)", -3.0)
TEST_EVAL(Arith1, "1 + -x * 3", 2, -5.0)
TEST_CONST(Eq1, "1 == 1.0", TRUE_VAL)
TEST_CONST(Eq2, "1 == 2.0", FALSE_VAL)
TEST_CONST(Eq3, "True == 1", TRUE_VAL)
TEST_CONST(Eq4, "False == 0", TRUE_VAL)
TEST_EVAL(Eq1, "1 == x", 1.0, TRUE_VAL)
TEST_EVAL(Eq2, "1 == x", 2.0, FALSE_VAL)
TEST_CONST(NEq1, "1 != 1.0", FALSE_VAL)
TEST_CONST(NEq2, "1 != 2.0", TRUE_VAL)
TEST_EVAL(NEq1, "1 != x", 1.0, FALSE_VAL)
TEST_EVAL(NEq2, "1 != x", 2.0, TRUE_VAL)
TEST_CONST(Lt1, "1 < 1", FALSE_VAL)
TEST_CONST(Lt2, "1 < 2", TRUE_VAL)
TEST_CONST(Lt3, "2 < 1", FALSE_VAL)
TEST_CONST(Le1, "1 <= 1", TRUE_VAL)
TEST_CONST(Le2, "1 <= 2", TRUE_VAL)
TEST_CONST(Le3, "2 <= 1", FALSE_VAL)
TEST_CONST(Gt1, "1 > 1", FALSE_VAL)
TEST_CONST(Gt2, "1 > 2", FALSE_VAL)
TEST_CONST(Gt3, "2 > 1", TRUE_VAL)
TEST_CONST(Ge1, "1 >= 1", TRUE_VAL)
TEST_CONST(Ge2, "1 >= 2", FALSE_VAL)
TEST_CONST(Ge3, "2 >= 1", TRUE_VAL)
TEST_CONST(Cmp1, "3 == 1 + 2", TRUE_VAL)
TEST_EVAL(Cmp1, "3 == x + 2", 1, TRUE_VAL)
TEST_EVAL(Cmp1b, "3 == x + 2", 1.5, FALSE_VAL)
TEST_RESULT(CmpChain1, "1 < 2 < 3", TRUE_VAL)
TEST_RESULT(CmpChain2, "1 < 2 == 2", TRUE_VAL)
TEST_RESULT(CmpChain3, "1 < 2 > -1", TRUE_VAL)
TEST_RESULT(CmpChain4, "1 < 2 < 2 < 3", FALSE_VAL)
TEST_RESULT(CmpChain5, "1 < 2 <= 2 < 3", TRUE_VAL)
TEST_EVAL(CmpChain1a, "1 < x < 3", 2, TRUE_VAL)
TEST_EVAL(CmpChain1b, "1 < x < 3", 1, FALSE_VAL)
TEST_EVAL(CmpChain1c, "1 < x < 3", 3, FALSE_VAL)
TEST_CONST(Not1, "not 2", FALSE_VAL)
TEST_CONST(Not2, "not 0", TRUE_VAL)
TEST_CONST(Not3, "not not 2", TRUE_VAL)
TEST_EVAL(Not1, "not x", 2, FALSE_VAL)
TEST_EVAL(Not2, "not x", 0, TRUE_VAL)
TEST_RESULT(And1, "2 and 3", 3.0)
TEST_RESULT(And2, "0 and 3", 0.0)
TEST_RESULT(Or1, "2 or 3", 2.0)
TEST_RESULT(Or2, "0 or 3", 3.0)
TEST_RESULT(Bool1, "2 or 3 and 4", 2.0)
TEST_RESULT(Bool2, "not 2 or 3 and 4", 4.0)
TEST(expr_pylike, Eval_Ternary1)
{
ExprPyLike_Parsed *expr = parse_for_eval("x / 2 if x < 4 else x - 2 if x < 8 else x*2 - 12",
true);
for (int i = 0; i <= 10; i++) {
double x = i;
double v = (x < 4) ? (x / 2) : (x < 8) ? (x - 2) : (x * 2 - 12);
verify_eval_result(expr, x, v);
}
BLI_expr_pylike_free(expr);
}
TEST(expr_pylike, MultipleArgs)
{
const char *names[3] = {"x", "y", "x"};
double values[3] = {1.0, 2.0, 3.0};
ExprPyLike_Parsed *expr = BLI_expr_pylike_parse("x*10 + y", names, ARRAY_SIZE(names));
EXPECT_TRUE(BLI_expr_pylike_is_valid(expr));
double result;
eExprPyLike_EvalStatus status = BLI_expr_pylike_eval(expr, values, 3, &result);
EXPECT_EQ(status, EXPR_PYLIKE_SUCCESS);
EXPECT_EQ(result, 32.0);
BLI_expr_pylike_free(expr);
}
TEST(expr_pylike, UsingParam)
{
const char *names[3] = {"x", "y", "z"};
ExprPyLike_Parsed *expr = BLI_expr_pylike_parse("x + z", names, ARRAY_SIZE(names));
EXPECT_TRUE(BLI_expr_pylike_is_using_param(expr, 0));
EXPECT_FALSE(BLI_expr_pylike_is_using_param(expr, 1));
EXPECT_TRUE(BLI_expr_pylike_is_using_param(expr, 2));
BLI_expr_pylike_free(expr);
}
#define TEST_ERROR(name, str, x, code) \
TEST(expr_pylike, Error_##name) \
{ \
expr_pylike_error_test(str, x, code); \
}
TEST_ERROR(DivZero1, "0 / 0", 0.0, EXPR_PYLIKE_MATH_ERROR)
TEST_ERROR(DivZero2, "1 / 0", 0.0, EXPR_PYLIKE_DIV_BY_ZERO)
TEST_ERROR(DivZero3, "1 / x", 0.0, EXPR_PYLIKE_DIV_BY_ZERO)
TEST_ERROR(DivZero4, "1 / x", 1.0, EXPR_PYLIKE_SUCCESS)
TEST_ERROR(SqrtDomain1, "sqrt(-1)", 0.0, EXPR_PYLIKE_MATH_ERROR)
TEST_ERROR(SqrtDomain2, "sqrt(x)", -1.0, EXPR_PYLIKE_MATH_ERROR)
TEST_ERROR(SqrtDomain3, "sqrt(x)", 0.0, EXPR_PYLIKE_SUCCESS)
TEST_ERROR(PowDomain1, "pow(-1, 0.5)", 0.0, EXPR_PYLIKE_MATH_ERROR)
TEST_ERROR(PowDomain2, "pow(-1, x)", 0.5, EXPR_PYLIKE_MATH_ERROR)
TEST_ERROR(PowDomain3, "pow(-1, x)", 2.0, EXPR_PYLIKE_SUCCESS)
TEST_ERROR(Mixed1, "sqrt(x) + 1 / max(0, x)", -1.0, EXPR_PYLIKE_MATH_ERROR)
TEST_ERROR(Mixed2, "sqrt(x) + 1 / max(0, x)", 0.0, EXPR_PYLIKE_DIV_BY_ZERO)
TEST_ERROR(Mixed3, "sqrt(x) + 1 / max(0, x)", 1.0, EXPR_PYLIKE_SUCCESS)
TEST(expr_pylike, Error_Invalid)
{
ExprPyLike_Parsed *expr = BLI_expr_pylike_parse("", NULL, 0);
double result;
EXPECT_EQ(BLI_expr_pylike_eval(expr, NULL, 0, &result), EXPR_PYLIKE_INVALID);
BLI_expr_pylike_free(expr);
}
TEST(expr_pylike, Error_ArgumentCount)
{
ExprPyLike_Parsed *expr = parse_for_eval("x", false);
double result;
EXPECT_EQ(BLI_expr_pylike_eval(expr, NULL, 0, &result), EXPR_PYLIKE_FATAL_ERROR);
BLI_expr_pylike_free(expr);
}

View File

@@ -1,625 +0,0 @@
/* Apache License, Version 2.0 */
#include "BLI_ressource_strings.h"
#include "testing/testing.h"
#define GHASH_INTERNAL_API
#include "MEM_guardedalloc.h"
#include "BLI_ghash.h"
#include "BLI_rand.h"
#include "BLI_string.h"
#include "BLI_utildefines.h"
#include "PIL_time_utildefines.h"
/* Using http://corpora.uni-leipzig.de/downloads/eng_wikipedia_2010_1M-text.tar.gz
* (1 million of words, about 122MB of text) from
* http://corpora.informatik.uni-leipzig.de/download.html */
#if 0
# define TEXT_CORPUS_PATH \
"/path/to/Téléchargements/eng_wikipedia_2010_1M-text/eng_wikipedia_2010_1M-sentences.txt"
#endif
/* Resizing the hash has a huge cost over global filling operation! */
//#define GHASH_RESERVE
/* Run the longest tests! */
//#define GHASH_RUN_BIG
/* Size of 'small case' ghash (number of entries). */
#define TESTCASE_SIZE_SMALL 17
#define PRINTF_GHASH_STATS(_gh) \
{ \
double q, lf, var, pempty, poverloaded; \
int bigb; \
q = BLI_ghash_calc_quality_ex((_gh), &lf, &var, &pempty, &poverloaded, &bigb); \
printf( \
"GHash stats (%u entries):\n\t" \
"Quality (the lower the better): %f\n\tVariance (the lower the better): %f\n\tLoad: " \
"%f\n\t" \
"Empty buckets: %.2f%%\n\tOverloaded buckets: %.2f%% (biggest bucket: %d)\n", \
BLI_ghash_len(_gh), \
q, \
var, \
lf, \
pempty * 100.0, \
poverloaded * 100.0, \
bigb); \
} \
void(0)
/* Str: whole text, lines and words from a 'corpus' text. */
static void str_ghash_tests(GHash *ghash, const char *id)
{
printf("\n========== STARTING %s ==========\n", id);
#ifdef TEXT_CORPUS_PATH
size_t sz = 0;
char *data;
{
struct stat st;
if (stat(TEXT_CORPUS_PATH, &st) == 0)
sz = st.st_size;
}
if (sz != 0) {
FILE *f = fopen(TEXT_CORPUS_PATH, "r");
data = (char *)MEM_mallocN(sz + 1, __func__);
if (fread(data, sizeof(*data), sz, f) != sz) {
printf("ERROR in reading file %s!", TEXT_CORPUS_PATH);
MEM_freeN(data);
data = BLI_strdup(words10k);
}
data[sz] = '\0';
fclose(f);
}
else {
data = BLI_strdup(words10k);
}
#else
char *data = BLI_strdup(words10k);
#endif
char *data_p = BLI_strdup(data);
char *data_w = BLI_strdup(data);
char *data_bis = BLI_strdup(data);
{
char *p, *w, *c_p, *c_w;
TIMEIT_START(string_insert);
#ifdef GHASH_RESERVE
BLI_ghash_reserve(ghash, strlen(data) / 32); /* rough estimation... */
#endif
BLI_ghash_insert(ghash, data, POINTER_FROM_INT(data[0]));
for (p = c_p = data_p, w = c_w = data_w; *c_w; c_w++, c_p++) {
if (*c_p == '.') {
*c_p = *c_w = '\0';
if (!BLI_ghash_haskey(ghash, p)) {
BLI_ghash_insert(ghash, p, POINTER_FROM_INT(p[0]));
}
if (!BLI_ghash_haskey(ghash, w)) {
BLI_ghash_insert(ghash, w, POINTER_FROM_INT(w[0]));
}
p = c_p + 1;
w = c_w + 1;
}
else if (*c_w == ' ') {
*c_w = '\0';
if (!BLI_ghash_haskey(ghash, w)) {
BLI_ghash_insert(ghash, w, POINTER_FROM_INT(w[0]));
}
w = c_w + 1;
}
}
TIMEIT_END(string_insert);
}
PRINTF_GHASH_STATS(ghash);
{
char *p, *w, *c;
void *v;
TIMEIT_START(string_lookup);
v = BLI_ghash_lookup(ghash, data_bis);
EXPECT_EQ(POINTER_AS_INT(v), data_bis[0]);
for (p = w = c = data_bis; *c; c++) {
if (*c == '.') {
*c = '\0';
v = BLI_ghash_lookup(ghash, w);
EXPECT_EQ(POINTER_AS_INT(v), w[0]);
v = BLI_ghash_lookup(ghash, p);
EXPECT_EQ(POINTER_AS_INT(v), p[0]);
p = w = c + 1;
}
else if (*c == ' ') {
*c = '\0';
v = BLI_ghash_lookup(ghash, w);
EXPECT_EQ(POINTER_AS_INT(v), w[0]);
w = c + 1;
}
}
TIMEIT_END(string_lookup);
}
BLI_ghash_free(ghash, NULL, NULL);
MEM_freeN(data);
MEM_freeN(data_p);
MEM_freeN(data_w);
MEM_freeN(data_bis);
printf("========== ENDED %s ==========\n\n", id);
}
TEST(ghash, TextGHash)
{
GHash *ghash = BLI_ghash_new(BLI_ghashutil_strhash_p, BLI_ghashutil_strcmp, __func__);
str_ghash_tests(ghash, "StrGHash - GHash");
}
TEST(ghash, TextMurmur2a)
{
GHash *ghash = BLI_ghash_new(BLI_ghashutil_strhash_p_murmur, BLI_ghashutil_strcmp, __func__);
str_ghash_tests(ghash, "StrGHash - Murmur");
}
/* Int: uniform 100M first integers. */
static void int_ghash_tests(GHash *ghash, const char *id, const unsigned int nbr)
{
printf("\n========== STARTING %s ==========\n", id);
{
unsigned int i = nbr;
TIMEIT_START(int_insert);
#ifdef GHASH_RESERVE
BLI_ghash_reserve(ghash, nbr);
#endif
while (i--) {
BLI_ghash_insert(ghash, POINTER_FROM_UINT(i), POINTER_FROM_UINT(i));
}
TIMEIT_END(int_insert);
}
PRINTF_GHASH_STATS(ghash);
{
unsigned int i = nbr;
TIMEIT_START(int_lookup);
while (i--) {
void *v = BLI_ghash_lookup(ghash, POINTER_FROM_UINT(i));
EXPECT_EQ(POINTER_AS_UINT(v), i);
}
TIMEIT_END(int_lookup);
}
{
void *k, *v;
TIMEIT_START(int_pop);
GHashIterState pop_state = {0};
while (BLI_ghash_pop(ghash, &pop_state, &k, &v)) {
EXPECT_EQ(k, v);
}
TIMEIT_END(int_pop);
}
EXPECT_EQ(BLI_ghash_len(ghash), 0);
BLI_ghash_free(ghash, NULL, NULL);
printf("========== ENDED %s ==========\n\n", id);
}
TEST(ghash, IntGHash12000)
{
GHash *ghash = BLI_ghash_new(BLI_ghashutil_inthash_p, BLI_ghashutil_intcmp, __func__);
int_ghash_tests(ghash, "IntGHash - GHash - 12000", 12000);
}
#ifdef GHASH_RUN_BIG
TEST(ghash, IntGHash100000000)
{
GHash *ghash = BLI_ghash_new(BLI_ghashutil_inthash_p, BLI_ghashutil_intcmp, __func__);
int_ghash_tests(ghash, "IntGHash - GHash - 100000000", 100000000);
}
#endif
TEST(ghash, IntMurmur2a12000)
{
GHash *ghash = BLI_ghash_new(BLI_ghashutil_inthash_p_murmur, BLI_ghashutil_intcmp, __func__);
int_ghash_tests(ghash, "IntGHash - Murmur - 12000", 12000);
}
#ifdef GHASH_RUN_BIG
TEST(ghash, IntMurmur2a100000000)
{
GHash *ghash = BLI_ghash_new(BLI_ghashutil_inthash_p_murmur, BLI_ghashutil_intcmp, __func__);
int_ghash_tests(ghash, "IntGHash - Murmur - 100000000", 100000000);
}
#endif
/* Int: random 50M integers. */
static void randint_ghash_tests(GHash *ghash, const char *id, const unsigned int nbr)
{
printf("\n========== STARTING %s ==========\n", id);
unsigned int *data = (unsigned int *)MEM_mallocN(sizeof(*data) * (size_t)nbr, __func__);
unsigned int *dt;
unsigned int i;
{
RNG *rng = BLI_rng_new(1);
for (i = nbr, dt = data; i--; dt++) {
*dt = BLI_rng_get_uint(rng);
}
BLI_rng_free(rng);
}
{
TIMEIT_START(int_insert);
#ifdef GHASH_RESERVE
BLI_ghash_reserve(ghash, nbr);
#endif
for (i = nbr, dt = data; i--; dt++) {
BLI_ghash_insert(ghash, POINTER_FROM_UINT(*dt), POINTER_FROM_UINT(*dt));
}
TIMEIT_END(int_insert);
}
PRINTF_GHASH_STATS(ghash);
{
TIMEIT_START(int_lookup);
for (i = nbr, dt = data; i--; dt++) {
void *v = BLI_ghash_lookup(ghash, POINTER_FROM_UINT(*dt));
EXPECT_EQ(POINTER_AS_UINT(v), *dt);
}
TIMEIT_END(int_lookup);
}
BLI_ghash_free(ghash, NULL, NULL);
printf("========== ENDED %s ==========\n\n", id);
}
TEST(ghash, IntRandGHash12000)
{
GHash *ghash = BLI_ghash_new(BLI_ghashutil_inthash_p, BLI_ghashutil_intcmp, __func__);
randint_ghash_tests(ghash, "RandIntGHash - GHash - 12000", 12000);
}
#ifdef GHASH_RUN_BIG
TEST(ghash, IntRandGHash50000000)
{
GHash *ghash = BLI_ghash_new(BLI_ghashutil_inthash_p, BLI_ghashutil_intcmp, __func__);
randint_ghash_tests(ghash, "RandIntGHash - GHash - 50000000", 50000000);
}
#endif
TEST(ghash, IntRandMurmur2a12000)
{
GHash *ghash = BLI_ghash_new(BLI_ghashutil_inthash_p_murmur, BLI_ghashutil_intcmp, __func__);
randint_ghash_tests(ghash, "RandIntGHash - Murmur - 12000", 12000);
}
#ifdef GHASH_RUN_BIG
TEST(ghash, IntRandMurmur2a50000000)
{
GHash *ghash = BLI_ghash_new(BLI_ghashutil_inthash_p_murmur, BLI_ghashutil_intcmp, __func__);
randint_ghash_tests(ghash, "RandIntGHash - Murmur - 50000000", 50000000);
}
#endif
static unsigned int ghashutil_tests_nohash_p(const void *p)
{
return POINTER_AS_UINT(p);
}
static bool ghashutil_tests_cmp_p(const void *a, const void *b)
{
return a != b;
}
TEST(ghash, Int4NoHash12000)
{
GHash *ghash = BLI_ghash_new(ghashutil_tests_nohash_p, ghashutil_tests_cmp_p, __func__);
randint_ghash_tests(ghash, "RandIntGHash - No Hash - 12000", 12000);
}
#ifdef GHASH_RUN_BIG
TEST(ghash, Int4NoHash50000000)
{
GHash *ghash = BLI_ghash_new(ghashutil_tests_nohash_p, ghashutil_tests_cmp_p, __func__);
randint_ghash_tests(ghash, "RandIntGHash - No Hash - 50000000", 50000000);
}
#endif
/* Int_v4: 20M of randomly-generated integer vectors. */
static void int4_ghash_tests(GHash *ghash, const char *id, const unsigned int nbr)
{
printf("\n========== STARTING %s ==========\n", id);
void *data_v = MEM_mallocN(sizeof(unsigned int[4]) * (size_t)nbr, __func__);
unsigned int(*data)[4] = (unsigned int(*)[4])data_v;
unsigned int(*dt)[4];
unsigned int i, j;
{
RNG *rng = BLI_rng_new(1);
for (i = nbr, dt = data; i--; dt++) {
for (j = 4; j--;) {
(*dt)[j] = BLI_rng_get_uint(rng);
}
}
BLI_rng_free(rng);
}
{
TIMEIT_START(int_v4_insert);
#ifdef GHASH_RESERVE
BLI_ghash_reserve(ghash, nbr);
#endif
for (i = nbr, dt = data; i--; dt++) {
BLI_ghash_insert(ghash, *dt, POINTER_FROM_UINT(i));
}
TIMEIT_END(int_v4_insert);
}
PRINTF_GHASH_STATS(ghash);
{
TIMEIT_START(int_v4_lookup);
for (i = nbr, dt = data; i--; dt++) {
void *v = BLI_ghash_lookup(ghash, (void *)(*dt));
EXPECT_EQ(POINTER_AS_UINT(v), i);
}
TIMEIT_END(int_v4_lookup);
}
BLI_ghash_free(ghash, NULL, NULL);
MEM_freeN(data);
printf("========== ENDED %s ==========\n\n", id);
}
TEST(ghash, Int4GHash2000)
{
GHash *ghash = BLI_ghash_new(
BLI_ghashutil_uinthash_v4_p, BLI_ghashutil_uinthash_v4_cmp, __func__);
int4_ghash_tests(ghash, "Int4GHash - GHash - 2000", 2000);
}
#ifdef GHASH_RUN_BIG
TEST(ghash, Int4GHash20000000)
{
GHash *ghash = BLI_ghash_new(
BLI_ghashutil_uinthash_v4_p, BLI_ghashutil_uinthash_v4_cmp, __func__);
int4_ghash_tests(ghash, "Int4GHash - GHash - 20000000", 20000000);
}
#endif
TEST(ghash, Int4Murmur2a2000)
{
GHash *ghash = BLI_ghash_new(
BLI_ghashutil_uinthash_v4_p_murmur, BLI_ghashutil_uinthash_v4_cmp, __func__);
int4_ghash_tests(ghash, "Int4GHash - Murmur - 2000", 2000);
}
#ifdef GHASH_RUN_BIG
TEST(ghash, Int4Murmur2a20000000)
{
GHash *ghash = BLI_ghash_new(
BLI_ghashutil_uinthash_v4_p_murmur, BLI_ghashutil_uinthash_v4_cmp, __func__);
int4_ghash_tests(ghash, "Int4GHash - Murmur - 20000000", 20000000);
}
#endif
/* GHash inthash_v2 tests */
TEST(ghash, Int2NoHash12000)
{
GHash *ghash = BLI_ghash_new(ghashutil_tests_nohash_p, ghashutil_tests_cmp_p, __func__);
randint_ghash_tests(ghash, "RandIntGHash - No Hash - 12000", 12000);
}
#ifdef GHASH_RUN_BIG
TEST(ghash, Int2NoHash50000000)
{
GHash *ghash = BLI_ghash_new(ghashutil_tests_nohash_p, ghashutil_tests_cmp_p, __func__);
randint_ghash_tests(ghash, "RandIntGHash - No Hash - 50000000", 50000000);
}
#endif
/* Int_v2: 20M of randomly-generated integer vectors. */
static void int2_ghash_tests(GHash *ghash, const char *id, const unsigned int nbr)
{
printf("\n========== STARTING %s ==========\n", id);
void *data_v = MEM_mallocN(sizeof(unsigned int[2]) * (size_t)nbr, __func__);
unsigned int(*data)[2] = (unsigned int(*)[2])data_v;
unsigned int(*dt)[2];
unsigned int i, j;
{
RNG *rng = BLI_rng_new(1);
for (i = nbr, dt = data; i--; dt++) {
for (j = 2; j--;) {
(*dt)[j] = BLI_rng_get_uint(rng);
}
}
BLI_rng_free(rng);
}
{
TIMEIT_START(int_v2_insert);
#ifdef GHASH_RESERVE
BLI_ghash_reserve(ghash, nbr);
#endif
for (i = nbr, dt = data; i--; dt++) {
BLI_ghash_insert(ghash, *dt, POINTER_FROM_UINT(i));
}
TIMEIT_END(int_v2_insert);
}
PRINTF_GHASH_STATS(ghash);
{
TIMEIT_START(int_v2_lookup);
for (i = nbr, dt = data; i--; dt++) {
void *v = BLI_ghash_lookup(ghash, (void *)(*dt));
EXPECT_EQ(POINTER_AS_UINT(v), i);
}
TIMEIT_END(int_v2_lookup);
}
BLI_ghash_free(ghash, NULL, NULL);
MEM_freeN(data);
printf("========== ENDED %s ==========\n\n", id);
}
/* MultiSmall: create and manipulate a lot of very small ghashes
* (90% < 10 items, 9% < 100 items, 1% < 1000 items). */
static void multi_small_ghash_tests_one(GHash *ghash, RNG *rng, const unsigned int nbr)
{
unsigned int *data = (unsigned int *)MEM_mallocN(sizeof(*data) * (size_t)nbr, __func__);
unsigned int *dt;
unsigned int i;
for (i = nbr, dt = data; i--; dt++) {
*dt = BLI_rng_get_uint(rng);
}
#ifdef GHASH_RESERVE
BLI_ghash_reserve(ghash, nbr);
#endif
for (i = nbr, dt = data; i--; dt++) {
BLI_ghash_insert(ghash, POINTER_FROM_UINT(*dt), POINTER_FROM_UINT(*dt));
}
for (i = nbr, dt = data; i--; dt++) {
void *v = BLI_ghash_lookup(ghash, POINTER_FROM_UINT(*dt));
EXPECT_EQ(POINTER_AS_UINT(v), *dt);
}
BLI_ghash_clear(ghash, NULL, NULL);
}
static void multi_small_ghash_tests(GHash *ghash, const char *id, const unsigned int nbr)
{
printf("\n========== STARTING %s ==========\n", id);
RNG *rng = BLI_rng_new(1);
TIMEIT_START(multi_small_ghash);
unsigned int i = nbr;
while (i--) {
const int nbr = 1 + (BLI_rng_get_int(rng) % TESTCASE_SIZE_SMALL) *
(!(i % 100) ? 100 : (!(i % 10) ? 10 : 1));
multi_small_ghash_tests_one(ghash, rng, nbr);
}
TIMEIT_END(multi_small_ghash);
TIMEIT_START(multi_small2_ghash);
unsigned int i = nbr;
while (i--) {
const int nbr = 1 + (BLI_rng_get_int(rng) % TESTCASE_SIZE_SMALL) / 2 *
(!(i % 100) ? 100 : (!(i % 10) ? 10 : 1));
multi_small_ghash_tests_one(ghash, rng, nbr);
}
TIMEIT_END(multi_small2_ghash);
BLI_ghash_free(ghash, NULL, NULL);
BLI_rng_free(rng);
printf("========== ENDED %s ==========\n\n", id);
}
TEST(ghash, MultiRandIntGHash2000)
{
GHash *ghash = BLI_ghash_new(BLI_ghashutil_inthash_p, BLI_ghashutil_intcmp, __func__);
multi_small_ghash_tests(ghash, "MultiSmall RandIntGHash - GHash - 2000", 2000);
}
TEST(ghash, MultiRandIntGHash200000)
{
GHash *ghash = BLI_ghash_new(BLI_ghashutil_inthash_p, BLI_ghashutil_intcmp, __func__);
multi_small_ghash_tests(ghash, "MultiSmall RandIntGHash - GHash - 200000", 200000);
}
TEST(ghash, MultiRandIntMurmur2a2000)
{
GHash *ghash = BLI_ghash_new(BLI_ghashutil_inthash_p_murmur, BLI_ghashutil_intcmp, __func__);
multi_small_ghash_tests(ghash, "MultiSmall RandIntGHash - Murmur2a - 2000", 2000);
}
TEST(ghash, MultiRandIntMurmur2a200000)
{
GHash *ghash = BLI_ghash_new(BLI_ghashutil_inthash_p_murmur, BLI_ghashutil_intcmp, __func__);
multi_small_ghash_tests(ghash, "MultiSmall RandIntGHash - Murmur2a - 200000", 200000);
}

View File

@@ -1,209 +0,0 @@
/* Apache License, Version 2.0 */
#include "testing/testing.h"
#define GHASH_INTERNAL_API
#include "BLI_ghash.h"
#include "BLI_rand.h"
#include "BLI_utildefines.h"
#define TESTCASE_SIZE 10000
/* Only keeping this in case here, for now. */
#define PRINTF_GHASH_STATS(_gh) \
{ \
double q, lf, var, pempty, poverloaded; \
int bigb; \
q = BLI_ghash_calc_quality_ex((_gh), &lf, &var, &pempty, &poverloaded, &bigb); \
printf( \
"GHash stats (%d entries):\n\t" \
"Quality (the lower the better): %f\n\tVariance (the lower the better): %f\n\tLoad: " \
"%f\n\t" \
"Empty buckets: %.2f%%\n\tOverloaded buckets: %.2f%% (biggest bucket: %d)\n", \
BLI_ghash_len(_gh), \
q, \
var, \
lf, \
pempty * 100.0, \
poverloaded * 100.0, \
bigb); \
} \
void(0)
/* Note: for pure-ghash testing, nature of the keys and data have absolutely no importance! So here
* we just use mere random integers stored in pointers. */
static void init_keys(unsigned int keys[TESTCASE_SIZE], const int seed)
{
RNG *rng = BLI_rng_new(seed);
unsigned int *k;
int i;
for (i = 0, k = keys; i < TESTCASE_SIZE;) {
/* Risks of collision are low, but they do exist.
* And we cannot use a GSet, since we test that here! */
int j, t = BLI_rng_get_uint(rng);
for (j = i; j--;) {
if (keys[j] == t) {
continue;
}
}
*k = t;
i++;
k++;
}
BLI_rng_free(rng);
}
/* Here we simply insert and then lookup all keys, ensuring we do get back the expected stored
* 'data'. */
TEST(ghash, InsertLookup)
{
GHash *ghash = BLI_ghash_new(BLI_ghashutil_inthash_p, BLI_ghashutil_intcmp, __func__);
unsigned int keys[TESTCASE_SIZE], *k;
int i;
init_keys(keys, 0);
for (i = TESTCASE_SIZE, k = keys; i--; k++) {
BLI_ghash_insert(ghash, POINTER_FROM_UINT(*k), POINTER_FROM_UINT(*k));
}
EXPECT_EQ(BLI_ghash_len(ghash), TESTCASE_SIZE);
for (i = TESTCASE_SIZE, k = keys; i--; k++) {
void *v = BLI_ghash_lookup(ghash, POINTER_FROM_UINT(*k));
EXPECT_EQ(POINTER_AS_UINT(v), *k);
}
BLI_ghash_free(ghash, NULL, NULL);
}
/* Here we simply insert and then remove all keys, ensuring we do get an empty, unshrinked ghash.
*/
TEST(ghash, InsertRemove)
{
GHash *ghash = BLI_ghash_new(BLI_ghashutil_inthash_p, BLI_ghashutil_intcmp, __func__);
unsigned int keys[TESTCASE_SIZE], *k;
int i, bkt_size;
init_keys(keys, 10);
for (i = TESTCASE_SIZE, k = keys; i--; k++) {
BLI_ghash_insert(ghash, POINTER_FROM_UINT(*k), POINTER_FROM_UINT(*k));
}
EXPECT_EQ(BLI_ghash_len(ghash), TESTCASE_SIZE);
bkt_size = BLI_ghash_buckets_len(ghash);
for (i = TESTCASE_SIZE, k = keys; i--; k++) {
void *v = BLI_ghash_popkey(ghash, POINTER_FROM_UINT(*k), NULL);
EXPECT_EQ(POINTER_AS_UINT(v), *k);
}
EXPECT_EQ(BLI_ghash_len(ghash), 0);
EXPECT_EQ(BLI_ghash_buckets_len(ghash), bkt_size);
BLI_ghash_free(ghash, NULL, NULL);
}
/* Same as above, but this time we allow ghash to shrink. */
TEST(ghash, InsertRemoveShrink)
{
GHash *ghash = BLI_ghash_new(BLI_ghashutil_inthash_p, BLI_ghashutil_intcmp, __func__);
unsigned int keys[TESTCASE_SIZE], *k;
int i, bkt_size;
BLI_ghash_flag_set(ghash, GHASH_FLAG_ALLOW_SHRINK);
init_keys(keys, 20);
for (i = TESTCASE_SIZE, k = keys; i--; k++) {
BLI_ghash_insert(ghash, POINTER_FROM_UINT(*k), POINTER_FROM_UINT(*k));
}
EXPECT_EQ(BLI_ghash_len(ghash), TESTCASE_SIZE);
bkt_size = BLI_ghash_buckets_len(ghash);
for (i = TESTCASE_SIZE, k = keys; i--; k++) {
void *v = BLI_ghash_popkey(ghash, POINTER_FROM_UINT(*k), NULL);
EXPECT_EQ(POINTER_AS_UINT(v), *k);
}
EXPECT_EQ(BLI_ghash_len(ghash), 0);
EXPECT_LT(BLI_ghash_buckets_len(ghash), bkt_size);
BLI_ghash_free(ghash, NULL, NULL);
}
/* Check copy. */
TEST(ghash, Copy)
{
GHash *ghash = BLI_ghash_new(BLI_ghashutil_inthash_p, BLI_ghashutil_intcmp, __func__);
GHash *ghash_copy;
unsigned int keys[TESTCASE_SIZE], *k;
int i;
init_keys(keys, 30);
for (i = TESTCASE_SIZE, k = keys; i--; k++) {
BLI_ghash_insert(ghash, POINTER_FROM_UINT(*k), POINTER_FROM_UINT(*k));
}
EXPECT_EQ(BLI_ghash_len(ghash), TESTCASE_SIZE);
ghash_copy = BLI_ghash_copy(ghash, NULL, NULL);
EXPECT_EQ(BLI_ghash_len(ghash_copy), TESTCASE_SIZE);
EXPECT_EQ(BLI_ghash_buckets_len(ghash_copy), BLI_ghash_buckets_len(ghash));
for (i = TESTCASE_SIZE, k = keys; i--; k++) {
void *v = BLI_ghash_lookup(ghash_copy, POINTER_FROM_UINT(*k));
EXPECT_EQ(POINTER_AS_UINT(v), *k);
}
BLI_ghash_free(ghash, NULL, NULL);
BLI_ghash_free(ghash_copy, NULL, NULL);
}
/* Check pop. */
TEST(ghash, Pop)
{
GHash *ghash = BLI_ghash_new(BLI_ghashutil_inthash_p, BLI_ghashutil_intcmp, __func__);
unsigned int keys[TESTCASE_SIZE], *k;
int i;
BLI_ghash_flag_set(ghash, GHASH_FLAG_ALLOW_SHRINK);
init_keys(keys, 30);
for (i = TESTCASE_SIZE, k = keys; i--; k++) {
BLI_ghash_insert(ghash, POINTER_FROM_UINT(*k), POINTER_FROM_UINT(*k));
}
EXPECT_EQ(BLI_ghash_len(ghash), TESTCASE_SIZE);
GHashIterState pop_state = {0};
for (i = TESTCASE_SIZE / 2; i--;) {
void *k, *v;
bool success = BLI_ghash_pop(ghash, &pop_state, &k, &v);
EXPECT_EQ(k, v);
EXPECT_TRUE(success);
if (i % 2) {
BLI_ghash_insert(ghash, POINTER_FROM_UINT(i * 4), POINTER_FROM_UINT(i * 4));
}
}
EXPECT_EQ(BLI_ghash_len(ghash), (TESTCASE_SIZE - TESTCASE_SIZE / 2 + TESTCASE_SIZE / 4));
{
void *k, *v;
while (BLI_ghash_pop(ghash, &pop_state, &k, &v)) {
EXPECT_EQ(k, v);
}
}
EXPECT_EQ(BLI_ghash_len(ghash), 0);
BLI_ghash_free(ghash, NULL, NULL);
}

View File

@@ -1,74 +0,0 @@
/* Apache License, Version 2.0 */
#include "testing/testing.h"
#include "BLI_hash_mm2a.h"
/* Note: Reference results are taken from reference implementation
* (cpp code, CMurmurHash2A variant):
* https://smhasher.googlecode.com/svn-history/r130/trunk/MurmurHash2.cpp
*/
TEST(hash_mm2a, MM2ABasic)
{
BLI_HashMurmur2A mm2;
const char *data = "Blender";
BLI_hash_mm2a_init(&mm2, 0);
BLI_hash_mm2a_add(&mm2, (const unsigned char *)data, strlen(data));
#ifdef __LITTLE_ENDIAN__
EXPECT_EQ(BLI_hash_mm2a_end(&mm2), 1633988145);
#else
EXPECT_EQ(BLI_hash_mm2a_end(&mm2), 959283772);
#endif
}
TEST(hash_mm2a, MM2AConcatenateStrings)
{
BLI_HashMurmur2A mm2;
uint32_t hash;
const char *data1 = "Blender";
const char *data2 = " is ";
const char *data3 = "FaNtAsTiC";
const char *data123 = "Blender is FaNtAsTiC";
BLI_hash_mm2a_init(&mm2, 0);
BLI_hash_mm2a_add(&mm2, (const unsigned char *)data1, strlen(data1));
BLI_hash_mm2a_add(&mm2, (const unsigned char *)data2, strlen(data2));
BLI_hash_mm2a_add(&mm2, (const unsigned char *)data3, strlen(data3));
hash = BLI_hash_mm2a_end(&mm2);
BLI_hash_mm2a_init(&mm2, 0);
BLI_hash_mm2a_add(&mm2, (const unsigned char *)data123, strlen(data123));
#ifdef __LITTLE_ENDIAN__
EXPECT_EQ(hash, 1545105348);
#else
EXPECT_EQ(hash, 2604964730);
#endif
EXPECT_EQ(BLI_hash_mm2a_end(&mm2), hash);
}
TEST(hash_mm2a, MM2AIntegers)
{
BLI_HashMurmur2A mm2;
uint32_t hash;
const int ints[4] = {1, 2, 3, 4};
BLI_hash_mm2a_init(&mm2, 0);
BLI_hash_mm2a_add_int(&mm2, ints[0]);
BLI_hash_mm2a_add_int(&mm2, ints[1]);
BLI_hash_mm2a_add_int(&mm2, ints[2]);
BLI_hash_mm2a_add_int(&mm2, ints[3]);
hash = BLI_hash_mm2a_end(&mm2);
BLI_hash_mm2a_init(&mm2, 0);
BLI_hash_mm2a_add(&mm2, (const unsigned char *)ints, sizeof(ints));
/* Yes, same hash here on little and big endian. */
#ifdef __LITTLE_ENDIAN__
EXPECT_EQ(hash, 405493096);
#else
EXPECT_EQ(hash, 405493096);
#endif
EXPECT_EQ(BLI_hash_mm2a_end(&mm2), hash);
}

View File

@@ -1,121 +0,0 @@
/* Apache License, Version 2.0 */
#include "testing/testing.h"
#include <string.h>
#include "MEM_guardedalloc.h"
#include "BLI_compiler_attrs.h"
#include "BLI_heap_simple.h"
#include "BLI_rand.h"
#include "BLI_sys_types.h"
#include "BLI_utildefines.h"
#define SIZE 1024
static void range_fl(float *array_tar, const int size)
{
float *array_pt = array_tar + (size - 1);
int i = size;
while (i--) {
*(array_pt--) = (float)i;
}
}
TEST(heap, SimpleEmpty)
{
HeapSimple *heap;
heap = BLI_heapsimple_new();
EXPECT_TRUE(BLI_heapsimple_is_empty(heap));
EXPECT_EQ(BLI_heapsimple_len(heap), 0);
BLI_heapsimple_free(heap, NULL);
}
TEST(heap, SimpleOne)
{
HeapSimple *heap;
const char *in = "test";
heap = BLI_heapsimple_new();
BLI_heapsimple_insert(heap, 0.0f, (void *)in);
EXPECT_FALSE(BLI_heapsimple_is_empty(heap));
EXPECT_EQ(BLI_heapsimple_len(heap), 1);
EXPECT_EQ(in, BLI_heapsimple_pop_min(heap));
EXPECT_TRUE(BLI_heapsimple_is_empty(heap));
EXPECT_EQ(BLI_heapsimple_len(heap), 0);
BLI_heapsimple_free(heap, NULL);
}
TEST(heap, SimpleRange)
{
const int items_total = SIZE;
HeapSimple *heap = BLI_heapsimple_new();
for (int in = 0; in < items_total; in++) {
BLI_heapsimple_insert(heap, (float)in, POINTER_FROM_INT(in));
}
for (int out_test = 0; out_test < items_total; out_test++) {
EXPECT_EQ(out_test, POINTER_AS_INT(BLI_heapsimple_pop_min(heap)));
}
EXPECT_TRUE(BLI_heapsimple_is_empty(heap));
BLI_heapsimple_free(heap, NULL);
}
TEST(heap, SimpleRangeReverse)
{
const int items_total = SIZE;
HeapSimple *heap = BLI_heapsimple_new();
for (int in = 0; in < items_total; in++) {
BLI_heapsimple_insert(heap, (float)-in, POINTER_FROM_INT(-in));
}
for (int out_test = items_total - 1; out_test >= 0; out_test--) {
EXPECT_EQ(-out_test, POINTER_AS_INT(BLI_heapsimple_pop_min(heap)));
}
EXPECT_TRUE(BLI_heapsimple_is_empty(heap));
BLI_heapsimple_free(heap, NULL);
}
TEST(heap, SimpleDuplicates)
{
const int items_total = SIZE;
HeapSimple *heap = BLI_heapsimple_new();
for (int in = 0; in < items_total; in++) {
BLI_heapsimple_insert(heap, 1.0f, 0);
}
for (int out_test = 0; out_test < items_total; out_test++) {
EXPECT_EQ(0, POINTER_AS_INT(BLI_heapsimple_pop_min(heap)));
}
EXPECT_TRUE(BLI_heapsimple_is_empty(heap));
BLI_heapsimple_free(heap, NULL);
}
static void random_heapsimple_helper(const int items_total, const int random_seed)
{
HeapSimple *heap = BLI_heapsimple_new();
float *values = (float *)MEM_mallocN(sizeof(float) * items_total, __func__);
range_fl(values, items_total);
BLI_array_randomize(values, sizeof(float), items_total, random_seed);
for (int i = 0; i < items_total; i++) {
BLI_heapsimple_insert(heap, values[i], POINTER_FROM_INT((int)values[i]));
}
for (int out_test = 0; out_test < items_total; out_test++) {
EXPECT_EQ(out_test, POINTER_AS_INT(BLI_heapsimple_pop_min(heap)));
}
EXPECT_TRUE(BLI_heapsimple_is_empty(heap));
BLI_heapsimple_free(heap, NULL);
MEM_freeN(values);
}
TEST(heap, SimpleRand1)
{
random_heapsimple_helper(1, 1234);
}
TEST(heap, SimpleRand2)
{
random_heapsimple_helper(2, 1234);
}
TEST(heap, SimpleRand100)
{
random_heapsimple_helper(100, 4321);
}

View File

@@ -1,207 +0,0 @@
/* Apache License, Version 2.0 */
#include "testing/testing.h"
#include <string.h>
#include "MEM_guardedalloc.h"
#include "BLI_compiler_attrs.h"
#include "BLI_heap.h"
#include "BLI_rand.h"
#include "BLI_utildefines.h"
#define SIZE 1024
static void range_fl(float *array_tar, const int size)
{
float *array_pt = array_tar + (size - 1);
int i = size;
while (i--) {
*(array_pt--) = (float)i;
}
}
TEST(heap, Empty)
{
Heap *heap;
heap = BLI_heap_new();
EXPECT_TRUE(BLI_heap_is_empty(heap));
EXPECT_EQ(BLI_heap_len(heap), 0);
BLI_heap_free(heap, NULL);
}
TEST(heap, One)
{
Heap *heap;
const char *in = "test";
heap = BLI_heap_new();
BLI_heap_insert(heap, 0.0f, (void *)in);
EXPECT_FALSE(BLI_heap_is_empty(heap));
EXPECT_EQ(BLI_heap_len(heap), 1);
EXPECT_EQ(in, BLI_heap_pop_min(heap));
EXPECT_TRUE(BLI_heap_is_empty(heap));
EXPECT_EQ(BLI_heap_len(heap), 0);
BLI_heap_free(heap, NULL);
}
TEST(heap, Range)
{
const int items_total = SIZE;
Heap *heap = BLI_heap_new();
for (int in = 0; in < items_total; in++) {
BLI_heap_insert(heap, (float)in, POINTER_FROM_INT(in));
}
for (int out_test = 0; out_test < items_total; out_test++) {
EXPECT_EQ(out_test, POINTER_AS_INT(BLI_heap_pop_min(heap)));
}
EXPECT_TRUE(BLI_heap_is_empty(heap));
BLI_heap_free(heap, NULL);
}
TEST(heap, RangeReverse)
{
const int items_total = SIZE;
Heap *heap = BLI_heap_new();
for (int in = 0; in < items_total; in++) {
BLI_heap_insert(heap, (float)-in, POINTER_FROM_INT(-in));
}
for (int out_test = items_total - 1; out_test >= 0; out_test--) {
EXPECT_EQ(-out_test, POINTER_AS_INT(BLI_heap_pop_min(heap)));
}
EXPECT_TRUE(BLI_heap_is_empty(heap));
BLI_heap_free(heap, NULL);
}
TEST(heap, RangeRemove)
{
const int items_total = SIZE;
Heap *heap = BLI_heap_new();
HeapNode **nodes = (HeapNode **)MEM_mallocN(sizeof(HeapNode *) * items_total, __func__);
for (int in = 0; in < items_total; in++) {
nodes[in] = BLI_heap_insert(heap, (float)in, POINTER_FROM_INT(in));
}
for (int i = 0; i < items_total; i += 2) {
BLI_heap_remove(heap, nodes[i]);
nodes[i] = NULL;
}
for (int out_test = 1; out_test < items_total; out_test += 2) {
EXPECT_EQ(out_test, POINTER_AS_INT(BLI_heap_pop_min(heap)));
}
EXPECT_TRUE(BLI_heap_is_empty(heap));
BLI_heap_free(heap, NULL);
MEM_freeN(nodes);
}
TEST(heap, Duplicates)
{
const int items_total = SIZE;
Heap *heap = BLI_heap_new();
for (int in = 0; in < items_total; in++) {
BLI_heap_insert(heap, 1.0f, 0);
}
for (int out_test = 0; out_test < items_total; out_test++) {
EXPECT_EQ(0, POINTER_AS_INT(BLI_heap_pop_min(heap)));
}
EXPECT_TRUE(BLI_heap_is_empty(heap));
BLI_heap_free(heap, NULL);
}
static void random_heap_helper(const int items_total, const int random_seed)
{
Heap *heap = BLI_heap_new();
float *values = (float *)MEM_mallocN(sizeof(float) * items_total, __func__);
range_fl(values, items_total);
BLI_array_randomize(values, sizeof(float), items_total, random_seed);
for (int i = 0; i < items_total; i++) {
BLI_heap_insert(heap, values[i], POINTER_FROM_INT((int)values[i]));
}
for (int out_test = 0; out_test < items_total; out_test++) {
EXPECT_EQ(out_test, POINTER_AS_INT(BLI_heap_pop_min(heap)));
}
EXPECT_TRUE(BLI_heap_is_empty(heap));
BLI_heap_free(heap, NULL);
MEM_freeN(values);
}
TEST(heap, Rand1)
{
random_heap_helper(1, 1234);
}
TEST(heap, Rand2)
{
random_heap_helper(2, 1234);
}
TEST(heap, Rand100)
{
random_heap_helper(100, 4321);
}
TEST(heap, ReInsertSimple)
{
const int items_total = SIZE;
Heap *heap = BLI_heap_new();
HeapNode **nodes = (HeapNode **)MEM_mallocN(sizeof(HeapNode *) * items_total, __func__);
for (int in = 0; in < items_total; in++) {
nodes[in] = BLI_heap_insert(heap, (float)in, POINTER_FROM_INT(in));
}
for (int i = 0; i < items_total; i++) {
BLI_heap_node_value_update(heap, nodes[i], (float)(items_total + i));
}
for (int out_test = 0; out_test < items_total; out_test++) {
EXPECT_EQ(out_test, POINTER_AS_INT(BLI_heap_pop_min(heap)));
}
EXPECT_TRUE(BLI_heap_is_empty(heap));
BLI_heap_free(heap, NULL);
MEM_freeN(nodes);
}
static void random_heap_reinsert_helper(const int items_total, const int random_seed)
{
Heap *heap = BLI_heap_new();
HeapNode **nodes = (HeapNode **)MEM_mallocN(sizeof(HeapNode *) * items_total, __func__);
for (int in = 0; in < items_total; in++) {
nodes[in] = BLI_heap_insert(heap, (float)in, POINTER_FROM_INT(in));
}
BLI_array_randomize(nodes, sizeof(HeapNode *), items_total, random_seed);
for (int i = 0; i < items_total; i++) {
BLI_heap_node_value_update(heap, nodes[i], (float)i);
}
EXPECT_TRUE(BLI_heap_is_valid(heap));
for (int out_test = 0; out_test < items_total; out_test++) {
HeapNode *node_top = BLI_heap_top(heap);
float out = BLI_heap_node_value(node_top);
EXPECT_EQ(out, BLI_heap_top_value(heap));
EXPECT_EQ((float)out_test, out);
BLI_heap_pop_min(heap);
}
EXPECT_TRUE(BLI_heap_is_empty(heap));
BLI_heap_free(heap, NULL);
MEM_freeN(nodes);
}
TEST(heap, ReInsertRandom1)
{
random_heap_reinsert_helper(1, 1234);
}
TEST(heap, ReInsertRandom2)
{
random_heap_reinsert_helper(2, 1234);
}
TEST(heap, ReInsertRandom100)
{
random_heap_reinsert_helper(100, 4321);
}
TEST(heap, ReInsertRandom1024)
{
random_heap_reinsert_helper(1024, 9876);
}
TEST(heap, ReInsertRandom2048)
{
random_heap_reinsert_helper(2048, 5321);
}

View File

@@ -1,136 +0,0 @@
/* Apache License, Version 2.0 */
#include "testing/testing.h"
/* TODO: ray intersection, overlap ... etc.*/
#include "MEM_guardedalloc.h"
#include "BLI_compiler_attrs.h"
#include "BLI_kdopbvh.h"
#include "BLI_math_vector.h"
#include "BLI_rand.h"
#include "stubs/bf_intern_eigen_stubs.h"
/* -------------------------------------------------------------------- */
/* Helper Functions */
static void rng_v3_round(float *coords, int coords_len, struct RNG *rng, int round, float scale)
{
for (int i = 0; i < coords_len; i++) {
float f = BLI_rng_get_float(rng) * 2.0f - 1.0f;
coords[i] = ((float)((int)(f * round)) / (float)round) * scale;
}
}
/* -------------------------------------------------------------------- */
/* Tests */
TEST(kdopbvh, Empty)
{
BVHTree *tree = BLI_bvhtree_new(0, 0.0, 8, 8);
BLI_bvhtree_balance(tree);
EXPECT_EQ(0, BLI_bvhtree_get_len(tree));
BLI_bvhtree_free(tree);
}
TEST(kdopbvh, Single)
{
BVHTree *tree = BLI_bvhtree_new(1, 0.0, 8, 8);
{
float co[3] = {0};
BLI_bvhtree_insert(tree, 0, co, 1);
}
EXPECT_EQ(BLI_bvhtree_get_len(tree), 1);
BLI_bvhtree_balance(tree);
BLI_bvhtree_free(tree);
}
static void optimal_check_callback(void *userdata,
int index,
const float co[3],
BVHTreeNearest *nearest)
{
float(*points)[3] = (float(*)[3])userdata;
/* BVH_NEAREST_OPTIMAL_ORDER should hit the right node on the first try */
EXPECT_EQ(nearest->index, -1);
EXPECT_EQ_ARRAY(co, points[index], 3);
nearest->index = index;
nearest->dist_sq = len_squared_v3v3(co, points[index]);
}
/**
* Note that a small epsilon is added to the BVH nodes bounds, even if we pass in zero.
* Use rounding to ensure very close nodes don't cause the wrong node to be found as nearest.
*/
static void find_nearest_points_test(
int points_len, float scale, int round, int random_seed, bool optimal = false)
{
struct RNG *rng = BLI_rng_new(random_seed);
BVHTree *tree = BLI_bvhtree_new(points_len, 0.0, 8, 8);
void *mem = MEM_mallocN(sizeof(float[3]) * points_len, __func__);
float(*points)[3] = (float(*)[3])mem;
for (int i = 0; i < points_len; i++) {
rng_v3_round(points[i], 3, rng, round, scale);
BLI_bvhtree_insert(tree, i, points[i], 1);
}
BLI_bvhtree_balance(tree);
/* first find each point */
BVHTree_NearestPointCallback callback = optimal ? optimal_check_callback : NULL;
int flags = optimal ? BVH_NEAREST_OPTIMAL_ORDER : 0;
for (int i = 0; i < points_len; i++) {
const int j = BLI_bvhtree_find_nearest_ex(tree, points[i], NULL, callback, points, flags);
if (j != i) {
#if 0
const float dist = len_v3v3(points[i], points[j]);
if (dist > (1.0f / (float)round)) {
printf("%.15f (%d %d)\n", dist, i, j);
print_v3_id(points[i]);
print_v3_id(points[j]);
fflush(stdout);
}
#endif
EXPECT_GE(j, 0);
EXPECT_LT(j, points_len);
EXPECT_EQ_ARRAY(points[i], points[j], 3);
}
}
BLI_bvhtree_free(tree);
BLI_rng_free(rng);
MEM_freeN(points);
}
TEST(kdopbvh, FindNearest_1)
{
find_nearest_points_test(1, 1.0, 1000, 1234);
}
TEST(kdopbvh, FindNearest_2)
{
find_nearest_points_test(2, 1.0, 1000, 123);
}
TEST(kdopbvh, FindNearest_500)
{
find_nearest_points_test(500, 1.0, 1000, 12);
}
TEST(kdopbvh, OptimalFindNearest_1)
{
find_nearest_points_test(1, 1.0, 1000, 1234, true);
}
TEST(kdopbvh, OptimalFindNearest_2)
{
find_nearest_points_test(2, 1.0, 1000, 123, true);
}
TEST(kdopbvh, OptimalFindNearest_500)
{
find_nearest_points_test(500, 1.0, 1000, 12, true);
}

View File

@@ -1,111 +0,0 @@
/* Apache License, Version 2.0 */
#include "testing/testing.h"
#include "MEM_guardedalloc.h"
#include "BLI_linklist_lockfree.h"
#include "BLI_task.h"
#include "BLI_threads.h"
#include "BLI_utildefines.h"
TEST(LockfreeLinkList, Init)
{
LockfreeLinkList list;
BLI_linklist_lockfree_init(&list);
EXPECT_EQ(list.head, &list.dummy_node);
EXPECT_EQ(list.tail, &list.dummy_node);
BLI_linklist_lockfree_free(&list, NULL);
}
TEST(LockfreeLinkList, InsertSingle)
{
LockfreeLinkList list;
LockfreeLinkNode node;
BLI_linklist_lockfree_init(&list);
BLI_linklist_lockfree_insert(&list, &node);
EXPECT_EQ(list.head, &list.dummy_node);
EXPECT_EQ(list.head->next, &node);
EXPECT_EQ(list.tail, &node);
BLI_linklist_lockfree_free(&list, NULL);
}
TEST(LockfreeLinkList, InsertMultiple)
{
static const int num_nodes = 128;
LockfreeLinkList list;
LockfreeLinkNode nodes[num_nodes];
BLI_linklist_lockfree_init(&list);
/* Insert all the nodes. */
for (int i = 0; i < num_nodes; ++i) {
BLI_linklist_lockfree_insert(&list, &nodes[i]);
}
/* Check head and tail. */
EXPECT_EQ(list.head, &list.dummy_node);
EXPECT_EQ(list.tail, &nodes[num_nodes - 1]);
/* Check rest of the nodes. */
int node_index = 0;
for (LockfreeLinkNode *node = BLI_linklist_lockfree_begin(&list); node != NULL;
node = node->next, ++node_index) {
EXPECT_EQ(node, &nodes[node_index]);
if (node_index != num_nodes - 1) {
EXPECT_EQ(node->next, &nodes[node_index + 1]);
}
}
/* Free list. */
BLI_linklist_lockfree_free(&list, NULL);
}
namespace {
struct IndexedNode {
IndexedNode *next;
int index;
};
void concurrent_insert(TaskPool *__restrict pool, void *taskdata)
{
LockfreeLinkList *list = (LockfreeLinkList *)BLI_task_pool_user_data(pool);
CHECK_NOTNULL(list);
IndexedNode *node = (IndexedNode *)MEM_mallocN(sizeof(IndexedNode), "test node");
node->index = POINTER_AS_INT(taskdata);
BLI_linklist_lockfree_insert(list, (LockfreeLinkNode *)node);
}
} // namespace
TEST(LockfreeLinkList, InsertMultipleConcurrent)
{
static const int num_nodes = 655360;
/* Initialize list. */
LockfreeLinkList list;
BLI_linklist_lockfree_init(&list);
/* Initialize task scheduler and pool. */
TaskPool *pool = BLI_task_pool_create_suspended(&list, TASK_PRIORITY_HIGH);
/* Push tasks to the pool. */
for (int i = 0; i < num_nodes; ++i) {
BLI_task_pool_push(pool, concurrent_insert, POINTER_FROM_INT(i), false, NULL);
}
/* Run all the tasks. */
BLI_task_pool_work_and_wait(pool);
/* Verify we've got all the data properly inserted. */
EXPECT_EQ(list.head, &list.dummy_node);
bool *visited_nodes = (bool *)MEM_callocN(sizeof(bool) * num_nodes, "visited nodes");
/* First, we make sure that none of the nodes are added twice. */
for (LockfreeLinkNode *node_v = BLI_linklist_lockfree_begin(&list); node_v != NULL;
node_v = node_v->next) {
IndexedNode *node = (IndexedNode *)node_v;
EXPECT_GE(node->index, 0);
EXPECT_LT(node->index, num_nodes);
EXPECT_FALSE(visited_nodes[node->index]);
visited_nodes[node->index] = true;
}
/* Then we make sure node was added. */
for (int node_index = 0; node_index < num_nodes; ++node_index) {
EXPECT_TRUE(visited_nodes[node_index]);
}
MEM_freeN(visited_nodes);
/* Cleanup data. */
BLI_linklist_lockfree_free(&list, MEM_freeN);
BLI_task_pool_free(pool);
}

View File

@@ -1,255 +0,0 @@
/* Apache License, Version 2.0 */
#include "testing/testing.h"
#include "MEM_guardedalloc.h"
#include "BLI_array_utils.h"
#include "BLI_listbase.h"
#include "BLI_path_util.h"
#include "BLI_ressource_strings.h"
#include "BLI_string.h"
/* local validation function */
static bool listbase_is_valid(const ListBase *listbase)
{
#define TESTFAIL(test) \
if (!(test)) { \
goto fail; \
} \
((void)0)
if (listbase->first) {
const Link *prev, *link;
link = (Link *)listbase->first;
TESTFAIL(link->prev == NULL);
link = (Link *)listbase->last;
TESTFAIL(link->next == NULL);
prev = NULL;
link = (Link *)listbase->first;
do {
TESTFAIL(link->prev == prev);
} while ((void)(prev = link), (link = link->next));
TESTFAIL(prev == listbase->last);
prev = NULL;
link = (Link *)listbase->last;
do {
TESTFAIL(link->next == prev);
} while ((void)(prev = link), (link = link->prev));
TESTFAIL(prev == listbase->first);
}
else {
TESTFAIL(listbase->last == NULL);
}
#undef TESTFAIL
return true;
fail:
return false;
}
static int char_switch(char *string, char ch_src, char ch_dst)
{
int tot = 0;
while (*string != 0) {
if (*string == ch_src) {
*string = ch_dst;
tot++;
}
string++;
}
return tot;
}
TEST(listbase, FindLinkOrIndex)
{
ListBase lb;
void *link1 = MEM_callocN(sizeof(Link), "link1");
void *link2 = MEM_callocN(sizeof(Link), "link2");
/* Empty list */
BLI_listbase_clear(&lb);
EXPECT_EQ(BLI_findlink(&lb, -1), (void *)NULL);
EXPECT_EQ(BLI_findlink(&lb, 0), (void *)NULL);
EXPECT_EQ(BLI_findlink(&lb, 1), (void *)NULL);
EXPECT_EQ(BLI_rfindlink(&lb, -1), (void *)NULL);
EXPECT_EQ(BLI_rfindlink(&lb, 0), (void *)NULL);
EXPECT_EQ(BLI_rfindlink(&lb, 1), (void *)NULL);
EXPECT_EQ(BLI_findindex(&lb, link1), -1);
/* One link */
BLI_addtail(&lb, link1);
EXPECT_EQ(BLI_findlink(&lb, 0), link1);
EXPECT_EQ(BLI_rfindlink(&lb, 0), link1);
EXPECT_EQ(BLI_findindex(&lb, link1), 0);
/* Two links */
BLI_addtail(&lb, link2);
EXPECT_EQ(BLI_findlink(&lb, 1), link2);
EXPECT_EQ(BLI_rfindlink(&lb, 0), link2);
EXPECT_EQ(BLI_findindex(&lb, link2), 1);
BLI_freelistN(&lb);
}
/* -------------------------------------------------------------------- */
/* Sort utilities & test */
static int testsort_array_str_cmp(const void *a, const void *b)
{
int i = strcmp(*(const char **)a, *(const char **)b);
return (i > 0) ? 1 : (i < 0) ? -1 : 0;
}
static int testsort_listbase_str_cmp(const void *a, const void *b)
{
const LinkData *link_a = (LinkData *)a;
const LinkData *link_b = (LinkData *)b;
int i = strcmp((const char *)link_a->data, (const char *)link_b->data);
return (i > 0) ? 1 : (i < 0) ? -1 : 0;
}
static int testsort_array_str_cmp_reverse(const void *a, const void *b)
{
return -testsort_array_str_cmp(a, b);
}
static int testsort_listbase_str_cmp_reverse(const void *a, const void *b)
{
return -testsort_listbase_str_cmp(a, b);
}
/* check array and listbase compare */
static bool testsort_listbase_array_str_cmp(ListBase *lb, char **arr, int arr_tot)
{
LinkData *link_step;
int i;
link_step = (LinkData *)lb->first;
for (i = 0; i < arr_tot; i++) {
if (strcmp(arr[i], (char *)link_step->data) != 0) {
return false;
}
link_step = link_step->next;
}
if (link_step) {
return false;
}
return true;
}
/* assumes nodes are allocated in-order */
static bool testsort_listbase_sort_is_stable(ListBase *lb, bool forward)
{
LinkData *link_step;
link_step = (LinkData *)lb->first;
while (link_step && link_step->next) {
if (strcmp((const char *)link_step->data, (const char *)link_step->next->data) == 0) {
if ((link_step < link_step->next) != forward) {
return false;
}
}
link_step = link_step->next;
}
return true;
}
TEST(listbase, Sort)
{
const int words_len = sizeof(words10k) - 1;
char *words = BLI_strdupn(words10k, words_len);
int words_tot;
char **words_arr; /* qsort for comparison */
int i;
char *w_step;
ListBase words_lb;
LinkData *words_linkdata_arr;
/* delimit words */
words_tot = 1 + char_switch(words, ' ', '\0');
words_arr = (char **)MEM_mallocN(sizeof(*words_arr) * words_tot, __func__);
words_linkdata_arr = (LinkData *)MEM_mallocN(sizeof(*words_linkdata_arr) * words_tot, __func__);
/* create array */
w_step = words;
for (i = 0; i < words_tot; i++) {
words_arr[i] = w_step;
w_step += strlen(w_step) + 1;
}
/* sort empty list */
{
BLI_listbase_clear(&words_lb);
BLI_listbase_sort(&words_lb, testsort_listbase_str_cmp);
EXPECT_TRUE(listbase_is_valid(&words_lb));
}
/* sort single single */
{
LinkData link;
link.data = words;
BLI_addtail(&words_lb, &link);
BLI_listbase_sort(&words_lb, testsort_listbase_str_cmp);
EXPECT_TRUE(listbase_is_valid(&words_lb));
BLI_listbase_clear(&words_lb);
}
/* create listbase */
BLI_listbase_clear(&words_lb);
w_step = words;
for (i = 0; i < words_tot; i++) {
LinkData *link = &words_linkdata_arr[i];
link->data = w_step;
BLI_addtail(&words_lb, link);
w_step += strlen(w_step) + 1;
}
EXPECT_TRUE(listbase_is_valid(&words_lb));
/* sort (forward) */
{
qsort(words_arr, words_tot, sizeof(*words_arr), testsort_array_str_cmp);
BLI_listbase_sort(&words_lb, testsort_listbase_str_cmp);
EXPECT_TRUE(listbase_is_valid(&words_lb));
EXPECT_TRUE(testsort_listbase_array_str_cmp(&words_lb, words_arr, words_tot));
EXPECT_TRUE(testsort_listbase_sort_is_stable(&words_lb, true));
}
/* sort (reverse) */
{
qsort(words_arr, words_tot, sizeof(*words_arr), testsort_array_str_cmp_reverse);
BLI_listbase_sort(&words_lb, testsort_listbase_str_cmp_reverse);
EXPECT_TRUE(listbase_is_valid(&words_lb));
EXPECT_TRUE(testsort_listbase_array_str_cmp(&words_lb, words_arr, words_tot));
EXPECT_TRUE(testsort_listbase_sort_is_stable(&words_lb, true));
}
/* sort (forward but after reversing, test stability in alternate direction) */
{
BLI_array_reverse(words_arr, words_tot);
BLI_listbase_reverse(&words_lb);
EXPECT_TRUE(listbase_is_valid(&words_lb));
EXPECT_TRUE(testsort_listbase_array_str_cmp(&words_lb, words_arr, words_tot));
EXPECT_TRUE(testsort_listbase_sort_is_stable(&words_lb, false));
/* and again */
BLI_array_reverse(words_arr, words_tot);
BLI_listbase_sort(&words_lb, testsort_listbase_str_cmp_reverse);
EXPECT_TRUE(testsort_listbase_array_str_cmp(&words_lb, words_arr, words_tot));
EXPECT_TRUE(testsort_listbase_sort_is_stable(&words_lb, false));
}
MEM_freeN(words);
MEM_freeN(words_arr);
MEM_freeN(words_linkdata_arr);
}

View File

@@ -1,115 +0,0 @@
/* Apache License, Version 2.0 */
#include "testing/testing.h"
#include "BLI_math.h"
/* In tests below, when we are using -1.0f as max_diff value, we actually turn the function into a
* pure-ULP one. */
/* Put this here, since we cannot use BLI_assert() in inline math files it seems... */
TEST(math_base, CompareFFRelativeValid)
{
EXPECT_TRUE(sizeof(float) == sizeof(int));
}
TEST(math_base, CompareFFRelativeNormal)
{
float f1 = 1.99999988f; /* *(float *)&(*(int *)&f2 - 1) */
float f2 = 2.00000000f;
float f3 = 2.00000048f; /* *(float *)&(*(int *)&f2 + 2) */
float f4 = 2.10000000f; /* *(float *)&(*(int *)&f2 + 419430) */
const float max_diff = FLT_EPSILON * 0.1f;
EXPECT_TRUE(compare_ff_relative(f1, f2, max_diff, 1));
EXPECT_TRUE(compare_ff_relative(f2, f1, max_diff, 1));
EXPECT_TRUE(compare_ff_relative(f3, f2, max_diff, 2));
EXPECT_TRUE(compare_ff_relative(f2, f3, max_diff, 2));
EXPECT_FALSE(compare_ff_relative(f3, f2, max_diff, 1));
EXPECT_FALSE(compare_ff_relative(f2, f3, max_diff, 1));
EXPECT_FALSE(compare_ff_relative(f3, f2, -1.0f, 1));
EXPECT_FALSE(compare_ff_relative(f2, f3, -1.0f, 1));
EXPECT_TRUE(compare_ff_relative(f3, f2, -1.0f, 2));
EXPECT_TRUE(compare_ff_relative(f2, f3, -1.0f, 2));
EXPECT_FALSE(compare_ff_relative(f4, f2, max_diff, 64));
EXPECT_FALSE(compare_ff_relative(f2, f4, max_diff, 64));
EXPECT_TRUE(compare_ff_relative(f1, f3, max_diff, 64));
EXPECT_TRUE(compare_ff_relative(f3, f1, max_diff, 64));
}
TEST(math_base, CompareFFRelativeZero)
{
float f0 = 0.0f;
float f1 = 4.2038954e-045f; /* *(float *)&(*(int *)&f0 + 3) */
float fn0 = -0.0f;
float fn1 = -2.8025969e-045f; /* *(float *)&(*(int *)&fn0 - 2) */
const float max_diff = FLT_EPSILON * 0.1f;
EXPECT_TRUE(compare_ff_relative(f0, f1, -1.0f, 3));
EXPECT_TRUE(compare_ff_relative(f1, f0, -1.0f, 3));
EXPECT_FALSE(compare_ff_relative(f0, f1, -1.0f, 1));
EXPECT_FALSE(compare_ff_relative(f1, f0, -1.0f, 1));
EXPECT_TRUE(compare_ff_relative(fn0, fn1, -1.0f, 8));
EXPECT_TRUE(compare_ff_relative(fn1, fn0, -1.0f, 8));
EXPECT_TRUE(compare_ff_relative(f0, f1, max_diff, 1));
EXPECT_TRUE(compare_ff_relative(f1, f0, max_diff, 1));
EXPECT_TRUE(compare_ff_relative(fn0, f0, max_diff, 1));
EXPECT_TRUE(compare_ff_relative(f0, fn0, max_diff, 1));
EXPECT_TRUE(compare_ff_relative(f0, fn1, max_diff, 1));
EXPECT_TRUE(compare_ff_relative(fn1, f0, max_diff, 1));
/* Note: in theory, this should return false, since 0.0f and -0.0f have 0x80000000 diff,
* but overflow in subtraction seems to break something here
* (abs(*(int *)&fn0 - *(int *)&f0) == 0x80000000 == fn0), probably because int32 cannot
* hold this abs value. this is yet another illustration of why one shall never use (near-)zero
* floats in pure-ULP comparison. */
// EXPECT_FALSE(compare_ff_relative(fn0, f0, -1.0f, 1024));
// EXPECT_FALSE(compare_ff_relative(f0, fn0, -1.0f, 1024));
EXPECT_FALSE(compare_ff_relative(fn0, f1, -1.0f, 1024));
EXPECT_FALSE(compare_ff_relative(f1, fn0, -1.0f, 1024));
}
TEST(math_base, Log2FloorU)
{
EXPECT_EQ(log2_floor_u(0), 0);
EXPECT_EQ(log2_floor_u(1), 0);
EXPECT_EQ(log2_floor_u(2), 1);
EXPECT_EQ(log2_floor_u(3), 1);
EXPECT_EQ(log2_floor_u(4), 2);
EXPECT_EQ(log2_floor_u(5), 2);
EXPECT_EQ(log2_floor_u(6), 2);
EXPECT_EQ(log2_floor_u(7), 2);
EXPECT_EQ(log2_floor_u(8), 3);
EXPECT_EQ(log2_floor_u(9), 3);
EXPECT_EQ(log2_floor_u(123456), 16);
}
TEST(math_base, Log2CeilU)
{
EXPECT_EQ(log2_ceil_u(0), 0);
EXPECT_EQ(log2_ceil_u(1), 0);
EXPECT_EQ(log2_ceil_u(2), 1);
EXPECT_EQ(log2_ceil_u(3), 2);
EXPECT_EQ(log2_ceil_u(4), 2);
EXPECT_EQ(log2_ceil_u(5), 3);
EXPECT_EQ(log2_ceil_u(6), 3);
EXPECT_EQ(log2_ceil_u(7), 3);
EXPECT_EQ(log2_ceil_u(8), 3);
EXPECT_EQ(log2_ceil_u(9), 4);
EXPECT_EQ(log2_ceil_u(123456), 17);
}

View File

@@ -1,50 +0,0 @@
/* Apache License, Version 2.0 */
#include "BLI_math_bits.h"
#include "testing/testing.h"
#include <iostream>
TEST(math_bits, BitscanReverseClearUint)
{
uint a = 1234;
EXPECT_EQ(bitscan_reverse_clear_uint(&a), 21);
EXPECT_EQ(a, 210);
EXPECT_EQ(bitscan_reverse_clear_uint(&a), 24);
EXPECT_EQ(a, 82);
EXPECT_EQ(bitscan_reverse_clear_uint(&a), 25);
EXPECT_EQ(a, 18);
EXPECT_EQ(bitscan_reverse_clear_uint(&a), 27);
EXPECT_EQ(a, 2);
EXPECT_EQ(bitscan_reverse_clear_uint(&a), 30);
EXPECT_EQ(a, 0);
a = 3563987529;
EXPECT_EQ(bitscan_reverse_clear_uint(&a), 0);
EXPECT_EQ(a, 1416503881);
EXPECT_EQ(bitscan_reverse_clear_uint(&a), 1);
EXPECT_EQ(a, 342762057);
EXPECT_EQ(bitscan_reverse_clear_uint(&a), 3);
EXPECT_EQ(a, 74326601);
EXPECT_EQ(bitscan_reverse_clear_uint(&a), 5);
EXPECT_EQ(a, 7217737);
EXPECT_EQ(bitscan_reverse_clear_uint(&a), 9);
EXPECT_EQ(a, 3023433);
EXPECT_EQ(bitscan_reverse_clear_uint(&a), 10);
EXPECT_EQ(a, 926281);
EXPECT_EQ(bitscan_reverse_clear_uint(&a), 12);
EXPECT_EQ(a, 401993);
EXPECT_EQ(bitscan_reverse_clear_uint(&a), 13);
EXPECT_EQ(a, 139849);
EXPECT_EQ(bitscan_reverse_clear_uint(&a), 14);
EXPECT_EQ(a, 8777);
EXPECT_EQ(bitscan_reverse_clear_uint(&a), 18);
EXPECT_EQ(a, 585);
EXPECT_EQ(bitscan_reverse_clear_uint(&a), 22);
EXPECT_EQ(a, 73);
EXPECT_EQ(bitscan_reverse_clear_uint(&a), 25);
EXPECT_EQ(a, 9);
EXPECT_EQ(bitscan_reverse_clear_uint(&a), 28);
EXPECT_EQ(a, 1);
EXPECT_EQ(bitscan_reverse_clear_uint(&a), 31);
EXPECT_EQ(a, 0);
}

View File

@@ -1,76 +0,0 @@
/* Apache License, Version 2.0 */
#include "testing/testing.h"
#include "BLI_math.h"
TEST(math_color, RGBToHSVRoundtrip)
{
float orig_rgb[3] = {0.1f, 0.2f, 0.3f};
float hsv[3], rgb[3];
rgb_to_hsv_v(orig_rgb, hsv);
hsv_to_rgb_v(hsv, rgb);
EXPECT_V3_NEAR(orig_rgb, rgb, 1e-5);
}
TEST(math_color, RGBToHSLRoundtrip)
{
float orig_rgb[3] = {0.1f, 0.2f, 0.3f};
float hsl[3], rgb[3];
rgb_to_hsl_v(orig_rgb, hsl);
hsl_to_rgb_v(hsl, rgb);
EXPECT_V3_NEAR(orig_rgb, rgb, 1e-5);
}
TEST(math_color, RGBToYUVRoundtrip)
{
float orig_rgb[3] = {0.1f, 0.2f, 0.3f};
float yuv[3], rgb[3];
rgb_to_yuv(orig_rgb[0], orig_rgb[1], orig_rgb[2], &yuv[0], &yuv[1], &yuv[2], BLI_YUV_ITU_BT709);
yuv_to_rgb(yuv[0], yuv[1], yuv[2], &rgb[0], &rgb[1], &rgb[2], BLI_YUV_ITU_BT709);
EXPECT_V3_NEAR(orig_rgb, rgb, 1e-4);
}
TEST(math_color, RGBToYCCRoundtrip)
{
float orig_rgb[3] = {0.1f, 0.2f, 0.3f};
float ycc[3], rgb[3];
rgb_to_ycc(orig_rgb[0], orig_rgb[1], orig_rgb[2], &ycc[0], &ycc[1], &ycc[2], BLI_YCC_ITU_BT601);
ycc_to_rgb(ycc[0], ycc[1], ycc[2], &rgb[0], &rgb[1], &rgb[2], BLI_YCC_ITU_BT601);
EXPECT_V3_NEAR(orig_rgb, rgb, 1e-3);
rgb_to_ycc(orig_rgb[0], orig_rgb[1], orig_rgb[2], &ycc[0], &ycc[1], &ycc[2], BLI_YCC_ITU_BT709);
ycc_to_rgb(ycc[0], ycc[1], ycc[2], &rgb[0], &rgb[1], &rgb[2], BLI_YCC_ITU_BT709);
EXPECT_V3_NEAR(orig_rgb, rgb, 1e-3);
rgb_to_ycc(orig_rgb[0], orig_rgb[1], orig_rgb[2], &ycc[0], &ycc[1], &ycc[2], BLI_YCC_JFIF_0_255);
ycc_to_rgb(ycc[0], ycc[1], ycc[2], &rgb[0], &rgb[1], &rgb[2], BLI_YCC_JFIF_0_255);
EXPECT_V3_NEAR(orig_rgb, rgb, 1e-3);
}
TEST(math_color, LinearRGBTosRGBNearZero)
{
float linear_color = 0.002f;
float srgb_color = linearrgb_to_srgb(linear_color);
EXPECT_NEAR(0.02584f, srgb_color, 1e-5);
}
TEST(math_color, LinearRGBTosRGB)
{
float linear_color = 0.75f;
float srgb_color = linearrgb_to_srgb(linear_color);
EXPECT_NEAR(0.880824f, srgb_color, 1e-5);
}
TEST(math_color, LinearRGBTosRGBRoundtrip)
{
const int N = 50;
int i;
for (i = 0; i < N; ++i) {
float orig_linear_color = (float)i / N;
float srgb_color = linearrgb_to_srgb(orig_linear_color);
float linear_color = srgb_to_linearrgb(srgb_color);
EXPECT_NEAR(orig_linear_color, linear_color, 1e-5);
}
}

View File

@@ -1,21 +0,0 @@
/* Apache License, Version 2.0 */
#include "testing/testing.h"
#include "BLI_math.h"
#include "stubs/bf_intern_eigen_stubs.h"
TEST(math_geom, DistToLine2DSimple)
{
float p[2] = {5.0f, 1.0f}, a[2] = {0.0f, 0.0f}, b[2] = {2.0f, 0.0f};
float distance = dist_to_line_v2(p, a, b);
EXPECT_NEAR(1.0f, distance, 1e-6);
}
TEST(math_geom, DistToLineSegment2DSimple)
{
float p[2] = {3.0f, 1.0f}, a[2] = {0.0f, 0.0f}, b[2] = {2.0f, 0.0f};
float distance = dist_to_line_segment_v2(p, a, b);
EXPECT_NEAR(sqrtf(2.0f), distance, 1e-6);
}

View File

@@ -1,99 +0,0 @@
/* Apache License, Version 2.0 */
#include "testing/testing.h"
#include "BLI_math_matrix.h"
TEST(math_matrix, interp_m4_m4m4_regular)
{
/* Test 4x4 matrix interpolation without singularity, i.e. without axis flip. */
/* Transposed matrix, so that the code here is written in the same way as print_m4() outputs. */
/* This matrix represents T=(0.1, 0.2, 0.3), R=(40, 50, 60) degrees, S=(0.7, 0.8, 0.9) */
float matrix_a[4][4] = {
{0.224976f, -0.333770f, 0.765074f, 0.100000f},
{0.389669f, 0.647565f, 0.168130f, 0.200000f},
{-0.536231f, 0.330541f, 0.443163f, 0.300000f},
{0.000000f, 0.000000f, 0.000000f, 1.000000f},
};
transpose_m4(matrix_a);
float matrix_i[4][4];
unit_m4(matrix_i);
float result[4][4];
const float epsilon = 1e-6;
interp_m4_m4m4(result, matrix_i, matrix_a, 0.0f);
EXPECT_M4_NEAR(result, matrix_i, epsilon);
interp_m4_m4m4(result, matrix_i, matrix_a, 1.0f);
EXPECT_M4_NEAR(result, matrix_a, epsilon);
/* This matrix is based on the current implementation of the code, and isn't guaranteed to be
* correct. It's just consistent with the current implementation. */
float matrix_halfway[4][4] = {
{0.690643f, -0.253244f, 0.484996f, 0.050000f},
{0.271924f, 0.852623f, 0.012348f, 0.100000f},
{-0.414209f, 0.137484f, 0.816778f, 0.150000f},
{0.000000f, 0.000000f, 0.000000f, 1.000000f},
};
transpose_m4(matrix_halfway);
interp_m4_m4m4(result, matrix_i, matrix_a, 0.5f);
EXPECT_M4_NEAR(result, matrix_halfway, epsilon);
}
TEST(math_matrix, interp_m3_m3m3_singularity)
{
/* A singluarity means that there is an axis mirror in the rotation component of the matrix. This
* is reflected in its negative determinant.
*
* The interpolation of 4x4 matrices performs linear interpolation on the translation component,
* and then uses the 3x3 interpolation function to handle rotation and scale. As a result, this
* test for a singularity in the rotation matrix only needs to test the 3x3 case. */
/* Transposed matrix, so that the code here is written in the same way as print_m4() outputs. */
/* This matrix represents R=(4, 5, 6) degrees, S=(-1, 1, 1) */
float matrix_a[3][3] = {
{-0.990737f, -0.098227f, 0.093759f},
{-0.104131f, 0.992735f, -0.060286f},
{0.087156f, 0.069491f, 0.993768f},
};
transpose_m3(matrix_a);
EXPECT_NEAR(-1.0f, determinant_m3_array(matrix_a), 1e-6);
/* This matrix represents R=(0, 0, 0), S=(-1, 0, 0) */
float matrix_b[3][3] = {
{-1.0f, 0.0f, 0.0f},
{0.0f, 1.0f, 0.0f},
{0.0f, 0.0f, 1.0f},
};
transpose_m3(matrix_b);
float result[3][3];
interp_m3_m3m3(result, matrix_a, matrix_b, 0.0f);
EXPECT_M3_NEAR(result, matrix_a, 1e-5);
interp_m3_m3m3(result, matrix_a, matrix_b, 1.0f);
EXPECT_M3_NEAR(result, matrix_b, 1e-5);
interp_m3_m3m3(result, matrix_a, matrix_b, 0.5f);
float expect[3][3] = {
{-0.997681f, -0.049995f, 0.046186f},
{-0.051473f, 0.998181f, -0.031385f},
{0.044533f, 0.033689f, 0.998440f},
};
transpose_m3(expect);
EXPECT_M3_NEAR(result, expect, 1e-5);
/* Interpolating between a matrix with and without axis flip can cause it to go through a zero
* point. The determinant det(A) of a matrix represents the change in volume; interpolating
* between matrices with det(A)=-1 and det(B)=1 will have to go through a point where
* det(result)=0, so where the volume becomes zero. */
float matrix_i[3][3];
unit_m3(matrix_i);
zero_m3(expect);
interp_m3_m3m3(result, matrix_a, matrix_i, 0.5f);
EXPECT_NEAR(0.0f, determinant_m3_array(result), 1e-5);
EXPECT_M3_NEAR(result, expect, 1e-5);
}

View File

@@ -1,47 +0,0 @@
/* Apache License, Version 2.0 */
#include "testing/testing.h"
#include "BLI_math.h"
TEST(math_vector, ClampVecWithFloats)
{
const float min = 0.0f;
const float max = 1.0f;
float a[2] = {-1.0f, -1.0f};
clamp_v2(a, min, max);
EXPECT_FLOAT_EQ(0.0f, a[0]);
EXPECT_FLOAT_EQ(0.0f, a[1]);
float b[2] = {0.5f, 0.5f};
clamp_v2(b, min, max);
EXPECT_FLOAT_EQ(0.5f, b[0]);
EXPECT_FLOAT_EQ(0.5f, b[1]);
float c[2] = {2.0f, 2.0f};
clamp_v2(c, min, max);
EXPECT_FLOAT_EQ(1.0f, c[0]);
EXPECT_FLOAT_EQ(1.0f, c[1]);
}
TEST(math_vector, ClampVecWithVecs)
{
const float min[2] = {0.0f, 2.0f};
const float max[2] = {1.0f, 3.0f};
float a[2] = {-1.0f, -1.0f};
clamp_v2_v2v2(a, min, max);
EXPECT_FLOAT_EQ(0.0f, a[0]);
EXPECT_FLOAT_EQ(2.0f, a[1]);
float b[2] = {0.5f, 2.5f};
clamp_v2_v2v2(b, min, max);
EXPECT_FLOAT_EQ(0.5f, b[0]);
EXPECT_FLOAT_EQ(2.5f, b[1]);
float c[2] = {2.0f, 4.0f};
clamp_v2_v2v2(c, min, max);
EXPECT_FLOAT_EQ(1.0f, c[0]);
EXPECT_FLOAT_EQ(3.0f, c[1]);
}

View File

@@ -1,277 +0,0 @@
/* Apache License, Version 2.0 */
#include "testing/testing.h"
#include "MEM_guardedalloc.h"
#include "BLI_array_utils.h"
#include "BLI_memiter.h"
#include "BLI_ressource_strings.h"
#include "BLI_string.h"
TEST(memiter, Nop)
{
BLI_memiter *mi = BLI_memiter_create(64);
BLI_memiter_destroy(mi);
}
static void memiter_empty_test(int num_elems, const int chunk_size)
{
BLI_memiter *mi = BLI_memiter_create(chunk_size);
void *data;
for (int index = 0; index < num_elems; index++) {
data = BLI_memiter_alloc(mi, 0);
}
int index = 0, total_size = 0;
BLI_memiter_handle it;
BLI_memiter_iter_init(mi, &it);
uint elem_size;
while ((data = BLI_memiter_iter_step_size(&it, &elem_size))) {
index += 1;
total_size += elem_size;
}
EXPECT_EQ(0, total_size);
EXPECT_EQ(num_elems, index);
BLI_memiter_destroy(mi);
}
#define MEMITER_NUMBER_TEST_FN(fn, number_type) \
static void fn(int num_elems, const int chunk_size) \
{ \
BLI_memiter *mi = BLI_memiter_create(chunk_size); \
number_type *data; \
for (int index = 0; index < num_elems; index++) { \
data = (number_type *)BLI_memiter_alloc(mi, sizeof(number_type)); \
*data = index; \
} \
BLI_memiter_handle it; \
BLI_memiter_iter_init(mi, &it); \
uint elem_size; \
int index = 0; \
while ((data = (number_type *)BLI_memiter_iter_step_size(&it, &elem_size))) { \
EXPECT_EQ(sizeof(number_type), elem_size); \
EXPECT_EQ(index, *data); \
index += 1; \
} \
BLI_memiter_destroy(mi); \
}
/* generate number functions */
MEMITER_NUMBER_TEST_FN(memiter_char_test, char)
MEMITER_NUMBER_TEST_FN(memiter_short_test, short)
MEMITER_NUMBER_TEST_FN(memiter_int_test, int)
MEMITER_NUMBER_TEST_FN(memiter_long_test, int64_t)
static void memiter_string_test(const char *strings[], const int chunk_size)
{
BLI_memiter *mi = BLI_memiter_create(chunk_size);
char *data;
int index = 0;
int total_size_expect = 0;
while (strings[index]) {
const int size = strlen(strings[index]) + 1;
BLI_memiter_alloc_from(mi, size, strings[index]);
total_size_expect += size;
index += 1;
}
const int strings_len = index;
int total_size = 0;
BLI_memiter_handle it;
BLI_memiter_iter_init(mi, &it);
uint elem_size;
index = 0;
while ((data = (char *)BLI_memiter_iter_step_size(&it, &elem_size))) {
EXPECT_EQ(strlen(strings[index]) + 1, elem_size);
EXPECT_STREQ(strings[index], data);
total_size += elem_size;
index += 1;
}
EXPECT_EQ(total_size_expect, total_size);
EXPECT_EQ(strings_len, index);
BLI_memiter_destroy(mi);
}
static void memiter_words10k_test(const char split_char, const int chunk_size)
{
const int words_len = sizeof(words10k) - 1;
char *words = BLI_strdupn(words10k, words_len);
BLI_str_replace_char(words, split_char, '\0');
BLI_memiter *mi = BLI_memiter_create(chunk_size);
char *data;
int index;
char *c_end, *c;
c_end = words + words_len;
c = words;
index = 0;
while (c < c_end) {
int elem_size = strlen(c) + 1;
data = (char *)BLI_memiter_alloc(mi, elem_size);
memcpy(data, c, elem_size);
c += elem_size;
index += 1;
}
const int len_expect = index;
c = words;
uint size;
BLI_memiter_handle it;
BLI_memiter_iter_init(mi, &it);
index = 0;
while ((data = (char *)BLI_memiter_iter_step_size(&it, &size))) {
int size_expect = strlen(c) + 1;
EXPECT_EQ(size_expect, size);
EXPECT_STREQ(c, data);
c += size;
index += 1;
}
EXPECT_EQ(len_expect, index);
BLI_memiter_destroy(mi);
MEM_freeN(words);
}
#define TEST_EMPTY_AT_CHUNK_SIZE(chunk_size) \
TEST(memiter, Empty0_##chunk_size) \
{ \
memiter_empty_test(0, chunk_size); \
} \
TEST(memiter, Empty1_##chunk_size) \
{ \
memiter_empty_test(1, chunk_size); \
} \
TEST(memiter, Empty2_##chunk_size) \
{ \
memiter_empty_test(2, chunk_size); \
} \
TEST(memiter, Empty3_##chunk_size) \
{ \
memiter_empty_test(3, chunk_size); \
} \
TEST(memiter, Empty13_##chunk_size) \
{ \
memiter_empty_test(13, chunk_size); \
} \
TEST(memiter, Empty256_##chunk_size) \
{ \
memiter_empty_test(256, chunk_size); \
}
TEST_EMPTY_AT_CHUNK_SIZE(1)
TEST_EMPTY_AT_CHUNK_SIZE(2)
TEST_EMPTY_AT_CHUNK_SIZE(3)
TEST_EMPTY_AT_CHUNK_SIZE(13)
TEST_EMPTY_AT_CHUNK_SIZE(256)
#define TEST_NUMBER_AT_CHUNK_SIZE(chunk_size) \
TEST(memiter, Char1_##chunk_size) \
{ \
memiter_char_test(1, chunk_size); \
} \
TEST(memiter, Short1_##chunk_size) \
{ \
memiter_short_test(1, chunk_size); \
} \
TEST(memiter, Int1_##chunk_size) \
{ \
memiter_int_test(1, chunk_size); \
} \
TEST(memiter, Long1_##chunk_size) \
{ \
memiter_long_test(1, chunk_size); \
} \
\
TEST(memiter, Char2_##chunk_size) \
{ \
memiter_char_test(2, chunk_size); \
} \
TEST(memiter, Short2_##chunk_size) \
{ \
memiter_short_test(2, chunk_size); \
} \
TEST(memiter, Int2_##chunk_size) \
{ \
memiter_int_test(2, chunk_size); \
} \
TEST(memiter, Long2_##chunk_size) \
{ \
memiter_long_test(2, chunk_size); \
} \
\
TEST(memiter, Char3_##chunk_size) \
{ \
memiter_char_test(3, chunk_size); \
} \
TEST(memiter, Short3_##chunk_size) \
{ \
memiter_short_test(3, chunk_size); \
} \
TEST(memiter, Int3_##chunk_size) \
{ \
memiter_int_test(3, chunk_size); \
} \
TEST(memiter, Long3_##chunk_size) \
{ \
memiter_long_test(3, chunk_size); \
} \
\
TEST(memiter, Char256_##chunk_size) \
{ \
memiter_char_test(256, chunk_size); \
} \
TEST(memiter, Short256_##chunk_size) \
{ \
memiter_short_test(256, chunk_size); \
} \
TEST(memiter, Int256_##chunk_size) \
{ \
memiter_int_test(256, chunk_size); \
} \
TEST(memiter, Long256_##chunk_size) \
{ \
memiter_long_test(256, chunk_size); \
}
TEST_NUMBER_AT_CHUNK_SIZE(1)
TEST_NUMBER_AT_CHUNK_SIZE(2)
TEST_NUMBER_AT_CHUNK_SIZE(3)
TEST_NUMBER_AT_CHUNK_SIZE(13)
TEST_NUMBER_AT_CHUNK_SIZE(256)
#define STRINGS_TEST(chunk_size, ...) \
{ \
const char *data[] = {__VA_ARGS__, NULL}; \
memiter_string_test(data, chunk_size); \
}
#define TEST_STRINGS_AT_CHUNK_SIZE(chunk_size) \
TEST(memiter, Strings_##chunk_size) \
{ \
STRINGS_TEST(chunk_size, ""); \
STRINGS_TEST(chunk_size, "test", "me"); \
STRINGS_TEST(chunk_size, "more", "test", "data", "to", "follow"); \
}
TEST_STRINGS_AT_CHUNK_SIZE(1)
TEST_STRINGS_AT_CHUNK_SIZE(2)
TEST_STRINGS_AT_CHUNK_SIZE(3)
TEST_STRINGS_AT_CHUNK_SIZE(13)
TEST_STRINGS_AT_CHUNK_SIZE(256)
#define TEST_WORDS10K_AT_CHUNK_SIZE(chunk_size) \
TEST(memiter, Words10kSentence_##chunk_size) \
{ \
memiter_words10k_test('.', chunk_size); \
} \
TEST(memiter, Words10kWords_##chunk_size) \
{ \
memiter_words10k_test(' ', chunk_size); \
}
TEST_WORDS10K_AT_CHUNK_SIZE(1)
TEST_WORDS10K_AT_CHUNK_SIZE(2)
TEST_WORDS10K_AT_CHUNK_SIZE(3)
TEST_WORDS10K_AT_CHUNK_SIZE(13)
TEST_WORDS10K_AT_CHUNK_SIZE(256)

View File

@@ -1,647 +0,0 @@
/* Apache License, Version 2.0 */
#include "testing/testing.h"
#include "../../../source/blender/imbuf/IMB_imbuf.h"
#include "BLI_fileops.h"
#include "BLI_path_util.h"
#include "BLI_string.h"
#ifdef _WIN32
# include "../../../source/blender/blenkernel/BKE_global.h"
#endif
/* -------------------------------------------------------------------- */
/* stubs */
extern "C" {
#if _WIN32
Global G = {0};
#endif
const char *GHOST_getUserDir(int version, const char *versionstr);
const char *GHOST_getSystemDir(int version, const char *versionstr);
#ifdef __linux__
char *zLhm65070058860608_br_find_exe(const char *default_exe);
#endif
const char *GHOST_getUserDir(int version, const char *versionstr)
{
return "/home/user";
}
const char *GHOST_getSystemDir(int version, const char *versionstr)
{
return "/system/path";
}
struct ImBuf;
void IMB_freeImBuf(struct ImBuf *ibuf)
{
}
struct ImBuf *IMB_dupImBuf(const ImBuf *ibuf)
{
return NULL;
}
#ifdef __linux__
char *zLhm65070058860608_br_find_exe(const char *default_exe)
{
return NULL;
}
#endif
}
/* -------------------------------------------------------------------- */
/* tests */
/* BLI_path_normalize */
#ifndef _WIN32
TEST(path_util, Clean)
{
/* "/./" -> "/" */
{
char path[FILE_MAX] = "/a/./b/./c/./";
BLI_path_normalize(NULL, path);
EXPECT_STREQ("/a/b/c/", path);
}
{
char path[FILE_MAX] = "/./././";
BLI_path_normalize(NULL, path);
EXPECT_STREQ("/", path);
}
{
char path[FILE_MAX] = "/a/./././b/";
BLI_path_normalize(NULL, path);
EXPECT_STREQ("/a/b/", path);
}
/* "//" -> "/" */
{
char path[FILE_MAX] = "a////";
BLI_path_normalize(NULL, path);
EXPECT_STREQ("a/", path);
}
if (0) /* FIXME */
{
char path[FILE_MAX] = "./a////";
BLI_path_normalize(NULL, path);
EXPECT_STREQ("./a/", path);
}
/* "foo/bar/../" -> "foo/" */
{
char path[FILE_MAX] = "/a/b/c/../../../";
BLI_path_normalize(NULL, path);
EXPECT_STREQ("/", path);
}
{
char path[FILE_MAX] = "/a/../a/b/../b/c/../c/";
BLI_path_normalize(NULL, path);
EXPECT_STREQ("/a/b/c/", path);
}
{
char path[FILE_MAX] = "//../";
BLI_path_normalize("/a/b/c/", path);
EXPECT_STREQ("/a/b/", path);
}
}
#endif
#define AT_INDEX(str_input, index_input, str_expect) \
{ \
char path[] = str_input; \
const char *expect = str_expect; \
int index_output, len_output; \
const bool ret = BLI_path_name_at_index(path, index_input, &index_output, &len_output); \
if (expect == NULL) { \
EXPECT_FALSE(ret); \
} \
else { \
EXPECT_TRUE(ret); \
EXPECT_EQ(strlen(expect), len_output); \
path[index_output + len_output] = '\0'; \
EXPECT_STREQ(&path[index_output], expect); \
} \
} \
((void)0)
/* BLI_path_name_at_index */
TEST(path_util, NameAtIndex_Single)
{
AT_INDEX("/a", 0, "a");
AT_INDEX("/a/", 0, "a");
AT_INDEX("a/", 0, "a");
AT_INDEX("//a//", 0, "a");
AT_INDEX("a/b", 0, "a");
AT_INDEX("/a", 1, NULL);
AT_INDEX("/a/", 1, NULL);
AT_INDEX("a/", 1, NULL);
AT_INDEX("//a//", 1, NULL);
}
TEST(path_util, NameAtIndex_SingleNeg)
{
AT_INDEX("/a", -1, "a");
AT_INDEX("/a/", -1, "a");
AT_INDEX("a/", -1, "a");
AT_INDEX("//a//", -1, "a");
AT_INDEX("a/b", -1, "b");
AT_INDEX("/a", -2, NULL);
AT_INDEX("/a/", -2, NULL);
AT_INDEX("a/", -2, NULL);
AT_INDEX("//a//", -2, NULL);
}
TEST(path_util, NameAtIndex_Double)
{
AT_INDEX("/ab", 0, "ab");
AT_INDEX("/ab/", 0, "ab");
AT_INDEX("ab/", 0, "ab");
AT_INDEX("//ab//", 0, "ab");
AT_INDEX("ab/c", 0, "ab");
AT_INDEX("/ab", 1, NULL);
AT_INDEX("/ab/", 1, NULL);
AT_INDEX("ab/", 1, NULL);
AT_INDEX("//ab//", 1, NULL);
}
TEST(path_util, NameAtIndex_DoublNeg)
{
AT_INDEX("/ab", -1, "ab");
AT_INDEX("/ab/", -1, "ab");
AT_INDEX("ab/", -1, "ab");
AT_INDEX("//ab//", -1, "ab");
AT_INDEX("ab/c", -1, "c");
AT_INDEX("/ab", -2, NULL);
AT_INDEX("/ab/", -2, NULL);
AT_INDEX("ab/", -2, NULL);
AT_INDEX("//ab//", -2, NULL);
}
TEST(path_util, NameAtIndex_Misc)
{
AT_INDEX("/how/now/brown/cow", 0, "how");
AT_INDEX("/how/now/brown/cow", 1, "now");
AT_INDEX("/how/now/brown/cow", 2, "brown");
AT_INDEX("/how/now/brown/cow", 3, "cow");
AT_INDEX("/how/now/brown/cow", 4, NULL);
AT_INDEX("/how/now/brown/cow/", 4, NULL);
}
TEST(path_util, NameAtIndex_MiscNeg)
{
AT_INDEX("/how/now/brown/cow", 0, "how");
AT_INDEX("/how/now/brown/cow", 1, "now");
AT_INDEX("/how/now/brown/cow", 2, "brown");
AT_INDEX("/how/now/brown/cow", 3, "cow");
AT_INDEX("/how/now/brown/cow", 4, NULL);
AT_INDEX("/how/now/brown/cow/", 4, NULL);
}
TEST(path_util, NameAtIndex_MiscComplex)
{
AT_INDEX("how//now/brown/cow", 0, "how");
AT_INDEX("//how///now\\/brown/cow", 1, "now");
AT_INDEX("/how/now\\//brown\\/cow", 2, "brown");
AT_INDEX("/how/now/brown/cow//\\", 3, "cow");
AT_INDEX("/how/now/brown/\\cow", 4, NULL);
AT_INDEX("how/now/brown/\\cow\\", 4, NULL);
}
TEST(path_util, NameAtIndex_MiscComplexNeg)
{
AT_INDEX("how//now/brown/cow", -4, "how");
AT_INDEX("//how///now\\/brown/cow", -3, "now");
AT_INDEX("/how/now\\//brown\\/cow", -2, "brown");
AT_INDEX("/how/now/brown/cow//\\", -1, "cow");
AT_INDEX("/how/now/brown/\\cow", -5, NULL);
AT_INDEX("how/now/brown/\\cow\\", -5, NULL);
}
TEST(path_util, NameAtIndex_NoneComplex)
{
AT_INDEX("", 0, NULL);
AT_INDEX("/", 0, NULL);
AT_INDEX("//", 0, NULL);
AT_INDEX("///", 0, NULL);
}
TEST(path_util, NameAtIndex_NoneComplexNeg)
{
AT_INDEX("", -1, NULL);
AT_INDEX("/", -1, NULL);
AT_INDEX("//", -1, NULL);
AT_INDEX("///", -1, NULL);
}
#undef AT_INDEX
#define JOIN(str_expect, out_size, ...) \
{ \
const char *expect = str_expect; \
char result[(out_size) + 1024]; \
/* check we don't write past the last byte */ \
result[out_size] = '\0'; \
BLI_path_join(result, out_size, __VA_ARGS__, NULL); \
/* simplify expected string */ \
BLI_str_replace_char(result, '\\', '/'); \
EXPECT_STREQ(result, expect); \
EXPECT_EQ(result[out_size], '\0'); \
} \
((void)0)
/* BLI_path_join */
TEST(path_util, JoinNop)
{
JOIN("", 100, "");
JOIN("", 100, "", "");
JOIN("", 100, "", "", "");
JOIN("/", 100, "/", "", "");
JOIN("/", 100, "/", "/");
JOIN("/", 100, "/", "", "/");
JOIN("/", 100, "/", "", "/", "");
}
TEST(path_util, JoinSingle)
{
JOIN("test", 100, "test");
JOIN("", 100, "");
JOIN("a", 100, "a");
JOIN("/a", 100, "/a");
JOIN("a/", 100, "a/");
JOIN("/a/", 100, "/a/");
JOIN("/a/", 100, "/a//");
JOIN("//a/", 100, "//a//");
}
TEST(path_util, JoinTriple)
{
JOIN("/a/b/c", 100, "/a", "b", "c");
JOIN("/a/b/c", 100, "/a/", "/b/", "/c");
JOIN("/a/b/c", 100, "/a/b/", "/c");
JOIN("/a/b/c", 100, "/a/b/c");
JOIN("/a/b/c", 100, "/", "a/b/c");
JOIN("/a/b/c/", 100, "/a/", "/b/", "/c/");
JOIN("/a/b/c/", 100, "/a/b/c/");
JOIN("/a/b/c/", 100, "/a/b/", "/c/");
JOIN("/a/b/c/", 100, "/a/b/c", "/");
JOIN("/a/b/c/", 100, "/", "a/b/c", "/");
}
TEST(path_util, JoinTruncateShort)
{
JOIN("", 1, "/");
JOIN("/", 2, "/");
JOIN("a", 2, "", "aa");
JOIN("a", 2, "", "a/");
JOIN("a/b", 4, "a", "bc");
JOIN("ab/", 4, "ab", "c");
JOIN("/a/", 4, "/a", "b");
JOIN("/a/", 4, "/a/", "b/");
JOIN("/a/", 4, "/a", "/b/");
JOIN("/a/", 4, "/", "a/b/");
JOIN("//a", 4, "//", "a/b/");
JOIN("/a/b", 5, "/a", "b", "c");
}
TEST(path_util, JoinTruncateLong)
{
JOIN("", 1, "//", "//longer", "path");
JOIN("/", 2, "//", "//longer", "path");
JOIN("//", 3, "//", "//longer", "path");
JOIN("//l", 4, "//", "//longer", "path");
/* snip */
JOIN("//longe", 8, "//", "//longer", "path");
JOIN("//longer", 9, "//", "//longer", "path");
JOIN("//longer/", 10, "//", "//longer", "path");
JOIN("//longer/p", 11, "//", "//longer", "path");
JOIN("//longer/pa", 12, "//", "//longer", "path");
JOIN("//longer/pat", 13, "//", "//longer", "path");
JOIN("//longer/path", 14, "//", "//longer", "path"); // not truncated
JOIN("//longer/path", 14, "//", "//longer", "path/");
JOIN("//longer/path/", 15, "//", "//longer", "path/"); // not truncated
JOIN("//longer/path/", 15, "//", "//longer", "path/", "trunc");
JOIN("//longer/path/t", 16, "//", "//longer", "path/", "trunc");
}
TEST(path_util, JoinComplex)
{
JOIN("/a/b/c/d/e/f/g/", 100, "/", "\\a/b", "//////c/d", "", "e\\\\", "f", "g//");
JOIN("/aa/bb/cc/dd/ee/ff/gg/", 100, "/", "\\aa/bb", "//////cc/dd", "", "ee\\\\", "ff", "gg//");
JOIN("1/2/3/", 100, "1", "////////", "", "2", "3\\");
}
#undef JOIN
/* BLI_path_frame */
TEST(path_util, Frame)
{
bool ret;
{
char path[FILE_MAX] = "";
ret = BLI_path_frame(path, 123, 1);
EXPECT_TRUE(ret);
EXPECT_STREQ("123", path);
}
{
char path[FILE_MAX] = "";
ret = BLI_path_frame(path, 123, 12);
EXPECT_TRUE(ret);
EXPECT_STREQ("000000000123", path);
}
{
char path[FILE_MAX] = "test_";
ret = BLI_path_frame(path, 123, 1);
EXPECT_TRUE(ret);
EXPECT_STREQ("test_123", path);
}
{
char path[FILE_MAX] = "test_";
ret = BLI_path_frame(path, 1, 12);
EXPECT_TRUE(ret);
EXPECT_STREQ("test_000000000001", path);
}
{
char path[FILE_MAX] = "test_############";
ret = BLI_path_frame(path, 1, 0);
EXPECT_TRUE(ret);
EXPECT_STREQ("test_000000000001", path);
}
{
char path[FILE_MAX] = "test_#_#_middle";
ret = BLI_path_frame(path, 123, 0);
EXPECT_TRUE(ret);
EXPECT_STREQ("test_#_123_middle", path);
}
/* intentionally fail */
{
char path[FILE_MAX] = "";
ret = BLI_path_frame(path, 123, 0);
EXPECT_FALSE(ret);
EXPECT_STREQ("", path);
}
{
char path[FILE_MAX] = "test_middle";
ret = BLI_path_frame(path, 123, 0);
EXPECT_FALSE(ret);
EXPECT_STREQ("test_middle", path);
}
/* negative frame numbers */
{
char path[FILE_MAX] = "test_####";
ret = BLI_path_frame(path, -1, 4);
EXPECT_TRUE(ret);
EXPECT_STREQ("test_-0001", path);
}
{
char path[FILE_MAX] = "test_####";
ret = BLI_path_frame(path, -100, 4);
EXPECT_TRUE(ret);
EXPECT_STREQ("test_-0100", path);
}
}
/* BLI_split_dirfile */
TEST(path_util, SplitDirfile)
{
{
const char *path = "";
char dir[FILE_MAX], file[FILE_MAX];
BLI_split_dirfile(path, dir, file, sizeof(dir), sizeof(file));
EXPECT_STREQ("", dir);
EXPECT_STREQ("", file);
}
{
const char *path = "/";
char dir[FILE_MAX], file[FILE_MAX];
BLI_split_dirfile(path, dir, file, sizeof(dir), sizeof(file));
EXPECT_STREQ("/", dir);
EXPECT_STREQ("", file);
}
{
const char *path = "fileonly";
char dir[FILE_MAX], file[FILE_MAX];
BLI_split_dirfile(path, dir, file, sizeof(dir), sizeof(file));
EXPECT_STREQ("", dir);
EXPECT_STREQ("fileonly", file);
}
{
const char *path = "dironly/";
char dir[FILE_MAX], file[FILE_MAX];
BLI_split_dirfile(path, dir, file, sizeof(dir), sizeof(file));
EXPECT_STREQ("dironly/", dir);
EXPECT_STREQ("", file);
}
{
const char *path = "/a/b";
char dir[FILE_MAX], file[FILE_MAX];
BLI_split_dirfile(path, dir, file, sizeof(dir), sizeof(file));
EXPECT_STREQ("/a/", dir);
EXPECT_STREQ("b", file);
}
{
const char *path = "/dirtoobig/filetoobig";
char dir[5], file[5];
BLI_split_dirfile(path, dir, file, sizeof(dir), sizeof(file));
EXPECT_STREQ("/dir", dir);
EXPECT_STREQ("file", file);
BLI_split_dirfile(path, dir, file, 1, 1);
EXPECT_STREQ("", dir);
EXPECT_STREQ("", file);
}
}
#define PATH_FRAME_STRIP(input_path, expect_path, expect_ext) \
{ \
char path[FILE_MAX]; \
char ext[FILE_MAX]; \
BLI_strncpy(path, (input_path), FILE_MAX); \
BLI_path_frame_strip(path, ext); \
EXPECT_STREQ(path, expect_path); \
EXPECT_STREQ(ext, expect_ext); \
} \
((void)0)
/* BLI_path_frame_strip */
TEST(path_util, PathFrameStrip)
{
PATH_FRAME_STRIP("", "", "");
PATH_FRAME_STRIP("nonum.abc", "nonum", ".abc");
PATH_FRAME_STRIP("fileonly.001.abc", "fileonly.###", ".abc");
PATH_FRAME_STRIP("/abspath/to/somefile.001.abc", "/abspath/to/somefile.###", ".abc");
PATH_FRAME_STRIP("/ext/longer/somefile.001.alembic", "/ext/longer/somefile.###", ".alembic");
PATH_FRAME_STRIP("/ext/shorter/somefile.123001.abc", "/ext/shorter/somefile.######", ".abc");
}
#undef PATH_FRAME_STRIP
#define PATH_EXTENSION_CHECK(input_path, input_ext, expect_ext) \
{ \
const bool ret = BLI_path_extension_check(input_path, input_ext); \
if (strcmp(input_ext, expect_ext) == 0) { \
EXPECT_TRUE(ret); \
} \
else { \
EXPECT_FALSE(ret); \
} \
} \
((void)0)
/* BLI_path_extension_check */
TEST(path_util, PathExtensionCheck)
{
PATH_EXTENSION_CHECK("a/b/c.exe", ".exe", ".exe");
PATH_EXTENSION_CHECK("correct/path/to/file.h", ".h", ".h");
PATH_EXTENSION_CHECK("correct/path/to/file.BLEND", ".BLEND", ".BLEND");
PATH_EXTENSION_CHECK("../tricky/path/to/file.h", ".h", ".h");
PATH_EXTENSION_CHECK("../dirty//../path\\to/file.h", ".h", ".h");
PATH_EXTENSION_CHECK("a/b/c.veryveryverylonglonglongextension",
".veryveryverylonglonglongextension",
".veryveryverylonglonglongextension");
PATH_EXTENSION_CHECK("filename.PNG", "pnG", "pnG");
PATH_EXTENSION_CHECK("a/b/c.h.exe", ".exe", ".exe");
PATH_EXTENSION_CHECK("a/b/c.h.exe", "exe", "exe");
PATH_EXTENSION_CHECK("a/b/c.exe", "c.exe", "c.exe");
PATH_EXTENSION_CHECK("a/b/noext", "noext", "noext");
PATH_EXTENSION_CHECK("a/b/c.exe", ".png", ".exe");
PATH_EXTENSION_CHECK("a/b/c.exe", "c.png", ".exe");
PATH_EXTENSION_CHECK("a/b/s.l", "l.s", "s.l");
PATH_EXTENSION_CHECK(".hiddenfolder", "", ".hiddenfolder");
PATH_EXTENSION_CHECK("../dirty//../path\\to/actual.h.file.ext", ".h", ".ext");
PATH_EXTENSION_CHECK("..\\dirty//../path//to/.hiddenfile.JPEG", ".hiddenfile", ".JPEG");
}
#undef PATH_EXTENSION_CHECK
#define PATH_FRAME_CHECK_CHARS(input_path, expect_hasChars) \
{ \
const bool ret = BLI_path_frame_check_chars(input_path); \
if (expect_hasChars) { \
EXPECT_TRUE(ret); \
} \
else { \
EXPECT_FALSE(ret); \
} \
} \
((void)0)
/* BLI_path_frame_check_chars */
TEST(path_util, PathFrameCheckChars)
{
PATH_FRAME_CHECK_CHARS("a#", true);
PATH_FRAME_CHECK_CHARS("aaaaa#", true);
PATH_FRAME_CHECK_CHARS("#aaaaa", true);
PATH_FRAME_CHECK_CHARS("a##.###", true);
PATH_FRAME_CHECK_CHARS("####.abc#", true);
PATH_FRAME_CHECK_CHARS("path/to/chars/a#", true);
PATH_FRAME_CHECK_CHARS("path/to/chars/123#123.exe", true);
PATH_FRAME_CHECK_CHARS("&", false);
PATH_FRAME_CHECK_CHARS("\35", false);
PATH_FRAME_CHECK_CHARS("path#/to#/chars#/$.h", false);
PATH_FRAME_CHECK_CHARS("path#/to#/chars#/nochars.h", false);
PATH_FRAME_CHECK_CHARS("..\\dirty\\path#/..//to#\\chars#/nochars.h", false);
PATH_FRAME_CHECK_CHARS("..\\dirty\\path#/..//to#/chars#\\nochars.h", false);
}
#undef PATH_FRAME_CHECK_CHARS
#define PATH_FRAME_RANGE(input_path, sta, end, digits, expect_outpath) \
{ \
char path[FILE_MAX]; \
bool ret; \
BLI_strncpy(path, input_path, FILE_MAX); \
ret = BLI_path_frame_range(path, sta, end, digits); \
if (expect_outpath == NULL) { \
EXPECT_FALSE(ret); \
} \
else { \
EXPECT_TRUE(ret); \
EXPECT_STREQ(path, expect_outpath); \
} \
} \
((void)0)
/* BLI_path_frame_range */
TEST(path_util, PathFrameRange)
{
int dummy = -1;
PATH_FRAME_RANGE("#", 1, 2, dummy, "1-2");
PATH_FRAME_RANGE("##", 1, 2, dummy, "01-02");
PATH_FRAME_RANGE("##", 1000, 2000, dummy, "1000-2000");
PATH_FRAME_RANGE("###", 100, 200, dummy, "100-200");
PATH_FRAME_RANGE("###", 8, 9, dummy, "008-009");
PATH_FRAME_RANGE("", 100, 200, 1, "100-200");
PATH_FRAME_RANGE("", 123, 321, 4, "0123-0321");
PATH_FRAME_RANGE("", 1, 0, 20, "00000000000000000001-00000000000000000000");
}
#undef PATH_FRAME_RANGE
#define PATH_FRAME_GET(input_path, expect_frame, expect_numdigits, expect_pathisvalid) \
{ \
char path[FILE_MAX]; \
int out_frame = -1, out_numdigits = -1; \
BLI_strncpy(path, input_path, FILE_MAX); \
const bool ret = BLI_path_frame_get(path, &out_frame, &out_numdigits); \
if (expect_pathisvalid) { \
EXPECT_TRUE(ret); \
} \
else { \
EXPECT_FALSE(ret); \
} \
EXPECT_EQ(out_frame, expect_frame); \
EXPECT_EQ(out_numdigits, expect_numdigits); \
} \
((void)0)
/* BLI_path_frame_get */
TEST(path_util, PathFrameGet)
{
PATH_FRAME_GET("001.avi", 1, 3, true);
PATH_FRAME_GET("0000299.ext", 299, 7, true);
PATH_FRAME_GET("path/to/frame_2810.dummy_quite_long_extension", 2810, 4, true);
PATH_FRAME_GET("notframe_7_frame00018.bla", 18, 5, true);
PATH_FRAME_GET("", -1, -1, false);
}
#undef PATH_FRAME_GET
/* BLI_path_extension */
TEST(path_util, PathExtension)
{
EXPECT_EQ(NULL, BLI_path_extension("some.def/file"));
EXPECT_EQ(NULL, BLI_path_extension("Text"));
EXPECT_EQ(NULL, BLI_path_extension("Text…001"));
EXPECT_STREQ(".", BLI_path_extension("some/file."));
EXPECT_STREQ(".gz", BLI_path_extension("some/file.tar.gz"));
EXPECT_STREQ(".abc", BLI_path_extension("some.def/file.abc"));
EXPECT_STREQ(".abc", BLI_path_extension("C:\\some.def\\file.abc"));
EXPECT_STREQ(".001", BLI_path_extension("Text.001"));
}

View File

@@ -1,753 +0,0 @@
/* Apache License, Version 2.0 */
#include "testing/testing.h"
/* Use to write out OBJ files, handy for checking output */
// #define USE_OBJ_PREVIEW
/* test every possible offset and reverse */
#define USE_COMBINATIONS_ALL
#define USE_BEAUTIFY
#include "MEM_guardedalloc.h"
#include "BLI_array_utils.h"
#include "BLI_edgehash.h"
#include "BLI_math.h"
#include "BLI_polyfill_2d.h"
#include "BLI_utildefines.h"
#ifdef USE_OBJ_PREVIEW
# include "BLI_string.h"
#endif
#ifdef USE_BEAUTIFY
# include "BLI_heap.h"
# include "BLI_memarena.h"
# include "BLI_polyfill_2d_beautify.h"
#endif
#include "stubs/bf_intern_eigen_stubs.h"
static void polyfill_to_obj(const char *id,
const float poly[][2],
const unsigned int poly_tot,
const unsigned int tris[][3],
const unsigned int tris_tot);
/* -------------------------------------------------------------------- */
/* test utility functions */
#define TRI_ERROR_VALUE (unsigned int)-1
static void test_valid_polyfill_prepare(unsigned int tris[][3], unsigned int tris_tot)
{
unsigned int i;
for (i = 0; i < tris_tot; i++) {
unsigned int j;
for (j = 0; j < 3; j++) {
tris[i][j] = TRI_ERROR_VALUE;
}
}
}
/**
* Basic check for face index values:
*
* - no duplicates.
* - all tris set.
* - all verts used at least once.
*/
static void test_polyfill_simple(const float poly[][2],
const unsigned int poly_tot,
const unsigned int tris[][3],
const unsigned int tris_tot)
{
unsigned int i;
int *tot_used = (int *)MEM_callocN(poly_tot * sizeof(int), __func__);
for (i = 0; i < tris_tot; i++) {
unsigned int j;
for (j = 0; j < 3; j++) {
EXPECT_NE(TRI_ERROR_VALUE, tris[i][j]);
tot_used[tris[i][j]] += 1;
}
EXPECT_NE(tris[i][0], tris[i][1]);
EXPECT_NE(tris[i][1], tris[i][2]);
EXPECT_NE(tris[i][2], tris[i][0]);
}
for (i = 0; i < poly_tot; i++) {
EXPECT_NE(0, tot_used[i]);
}
MEM_freeN(tot_used);
}
static void test_polyfill_topology(const float poly[][2],
const unsigned int poly_tot,
const unsigned int tris[][3],
const unsigned int tris_tot)
{
EdgeHash *edgehash = BLI_edgehash_new(__func__);
EdgeHashIterator *ehi;
unsigned int i;
for (i = 0; i < tris_tot; i++) {
unsigned int j;
for (j = 0; j < 3; j++) {
const unsigned int v1 = tris[i][j];
const unsigned int v2 = tris[i][(j + 1) % 3];
void **p = BLI_edgehash_lookup_p(edgehash, v1, v2);
if (p) {
*p = (void *)((intptr_t)*p + (intptr_t)1);
}
else {
BLI_edgehash_insert(edgehash, v1, v2, (void *)(intptr_t)1);
}
}
}
EXPECT_EQ(BLI_edgehash_len(edgehash), poly_tot + (poly_tot - 3));
for (i = 0; i < poly_tot; i++) {
const unsigned int v1 = i;
const unsigned int v2 = (i + 1) % poly_tot;
void **p = BLI_edgehash_lookup_p(edgehash, v1, v2);
EXPECT_NE((void *)p, nullptr);
EXPECT_EQ((intptr_t)*p, 1);
}
for (ehi = BLI_edgehashIterator_new(edgehash), i = 0; BLI_edgehashIterator_isDone(ehi) == false;
BLI_edgehashIterator_step(ehi), i++) {
void **p = BLI_edgehashIterator_getValue_p(ehi);
EXPECT_TRUE(ELEM((intptr_t)*p, 1, 2));
}
BLI_edgehashIterator_free(ehi);
BLI_edgehash_free(edgehash, NULL);
}
/**
* Check all faces are flipped the same way
*/
static void test_polyfill_winding(const float poly[][2],
const unsigned int poly_tot,
const unsigned int tris[][3],
const unsigned int tris_tot)
{
unsigned int i;
unsigned int count[2] = {0, 0};
for (i = 0; i < tris_tot; i++) {
float winding_test = cross_tri_v2(poly[tris[i][0]], poly[tris[i][1]], poly[tris[i][2]]);
if (fabsf(winding_test) > FLT_EPSILON) {
count[winding_test < 0.0f] += 1;
}
}
EXPECT_TRUE(ELEM(0, count[0], count[1]));
}
/**
* Check the accumulated triangle area is close to the original area.
*/
static void test_polyfill_area(const float poly[][2],
const unsigned int poly_tot,
const unsigned int tris[][3],
const unsigned int tris_tot)
{
unsigned int i;
const float area_tot = area_poly_v2(poly, poly_tot);
float area_tot_tris = 0.0f;
const float eps_abs = 0.00001f;
const float eps = area_tot > 1.0f ? (area_tot * eps_abs) : eps_abs;
for (i = 0; i < tris_tot; i++) {
area_tot_tris += area_tri_v2(poly[tris[i][0]], poly[tris[i][1]], poly[tris[i][2]]);
}
EXPECT_NEAR(area_tot, area_tot_tris, eps);
}
/* -------------------------------------------------------------------- */
/* Macro and helpers to manage checking */
/**
* Main template for polyfill testing.
*/
static void test_polyfill_template_check(const char *id,
bool is_degenerate,
const float poly[][2],
const unsigned int poly_tot,
const unsigned int tris[][3],
const unsigned int tris_tot)
{
test_polyfill_simple(poly, poly_tot, tris, tris_tot);
test_polyfill_topology(poly, poly_tot, tris, tris_tot);
if (!is_degenerate) {
test_polyfill_winding(poly, poly_tot, tris, tris_tot);
test_polyfill_area(poly, poly_tot, tris, tris_tot);
}
polyfill_to_obj(id, poly, poly_tot, tris, tris_tot);
}
static void test_polyfill_template(const char *id,
bool is_degenerate,
const float poly[][2],
const unsigned int poly_tot,
unsigned int tris[][3],
const unsigned int tris_tot)
{
test_valid_polyfill_prepare(tris, tris_tot);
BLI_polyfill_calc(poly, poly_tot, 0, tris);
/* check all went well */
test_polyfill_template_check(id, is_degenerate, poly, poly_tot, tris, tris_tot);
#ifdef USE_BEAUTIFY
/* check beautify gives good results too */
{
MemArena *pf_arena = BLI_memarena_new(BLI_POLYFILL_ARENA_SIZE, __func__);
Heap *pf_heap = BLI_heap_new_ex(BLI_POLYFILL_ALLOC_NGON_RESERVE);
BLI_polyfill_beautify(poly, poly_tot, tris, pf_arena, pf_heap);
test_polyfill_template_check(id, is_degenerate, poly, poly_tot, tris, tris_tot);
BLI_memarena_free(pf_arena);
BLI_heap_free(pf_heap, NULL);
}
#endif
}
static void test_polyfill_template_flip_sign(const char *id,
bool is_degenerate,
const float poly[][2],
const unsigned int poly_tot,
unsigned int tris[][3],
const unsigned int tris_tot)
{
float(*poly_copy)[2] = (float(*)[2])MEM_mallocN(sizeof(float[2]) * poly_tot, id);
for (int flip_x = 0; flip_x < 2; flip_x++) {
for (int flip_y = 0; flip_y < 2; flip_y++) {
float sign_x = flip_x ? -1.0f : 1.0f;
float sign_y = flip_y ? -1.0f : 1.0f;
for (int i = 0; i < poly_tot; i++) {
poly_copy[i][0] = poly[i][0] * sign_x;
poly_copy[i][1] = poly[i][1] * sign_y;
}
test_polyfill_template(id, is_degenerate, poly_copy, poly_tot, tris, tris_tot);
}
}
MEM_freeN(poly_copy);
}
#ifdef USE_COMBINATIONS_ALL
static void test_polyfill_template_main(const char *id,
bool is_degenerate,
const float poly[][2],
const unsigned int poly_tot,
unsigned int tris[][3],
const unsigned int tris_tot)
{
/* overkill? - try at _every_ offset & reverse */
unsigned int poly_reverse;
float(*poly_copy)[2] = (float(*)[2])MEM_mallocN(sizeof(float[2]) * poly_tot, id);
float tmp[2];
memcpy(poly_copy, poly, sizeof(float[2]) * poly_tot);
for (poly_reverse = 0; poly_reverse < 2; poly_reverse++) {
unsigned int poly_cycle;
if (poly_reverse) {
BLI_array_reverse(poly_copy, poly_tot);
}
for (poly_cycle = 0; poly_cycle < poly_tot; poly_cycle++) {
// printf("polytest %s ofs=%d, reverse=%d\n", id, poly_cycle, poly_reverse);
test_polyfill_template_flip_sign(id, is_degenerate, poly, poly_tot, tris, tris_tot);
/* cycle */
copy_v2_v2(tmp, poly_copy[0]);
memmove(&poly_copy[0], &poly_copy[1], (poly_tot - 1) * sizeof(float[2]));
copy_v2_v2(poly_copy[poly_tot - 1], tmp);
}
}
MEM_freeN(poly_copy);
}
#else /* USE_COMBINATIONS_ALL */
static void test_polyfill_template_main(const char *id,
bool is_degenerate,
const float poly[][2],
const unsigned int poly_tot,
unsigned int tris[][3],
const unsigned int tris_tot)
{
test_polyfill_template_flip_sign(id, is_degenerate, poly, poly_tot, tris, tris_tot);
}
#endif /* USE_COMBINATIONS_ALL */
#define TEST_POLYFILL_TEMPLATE_STATIC(poly, is_degenerate) \
{ \
unsigned int tris[POLY_TRI_COUNT(ARRAY_SIZE(poly))][3]; \
const unsigned int poly_tot = ARRAY_SIZE(poly); \
const unsigned int tris_tot = ARRAY_SIZE(tris); \
const char *id = typeid(*this).name(); \
\
test_polyfill_template_main(id, is_degenerate, poly, poly_tot, tris, tris_tot); \
} \
(void)0
/* -------------------------------------------------------------------- */
/* visualisation functions (not needed for testing) */
#ifdef USE_OBJ_PREVIEW
static void polyfill_to_obj(const char *id,
const float poly[][2],
const unsigned int poly_tot,
const unsigned int tris[][3],
const unsigned int tris_tot)
{
char path[1024];
FILE *f;
unsigned int i;
BLI_snprintf(path, sizeof(path), "%s.obj", id);
f = fopen(path, "w");
if (!f) {
return;
}
for (i = 0; i < poly_tot; i++) {
fprintf(f, "v %f %f 0.0\n", UNPACK2(poly[i]));
}
for (i = 0; i < tris_tot; i++) {
fprintf(f, "f %u %u %u\n", UNPACK3_EX(1 +, tris[i], ));
}
fclose(f);
}
#else
static void polyfill_to_obj(const char *id,
const float poly[][2],
const unsigned int poly_tot,
const unsigned int tris[][3],
const unsigned int tris_tot)
{
(void)id;
(void)poly, (void)poly_tot;
(void)tris, (void)tris_tot;
}
#endif /* USE_OBJ_PREVIEW */
/* -------------------------------------------------------------------- */
/* tests */
/**
* Script to generate the data below:
*
* \code{.py}
* # This example assumes we have a mesh object in edit-mode
*
* import bpy
* import bmesh
*
* obj = bpy.context.edit_object
* me = obj.data
* bm = bmesh.from_edit_mesh(me)
*
* def clean_float(num):
* if int(num) == num:
* return str(int(num))
* prec = 1
* while True:
* text = f"{num:.{prec}f}"
* if float(text) == num:
* return text
* prec += 1
*
* for f in bm.faces:
* if f.select:
* print(f"\t// data for face: {f.index}")
* print("\tconst float poly[][2] = {", end="")
* coords = [[clean_float(num) for num in l.vert.co[0:2]] for l in f.loops]
* print("\t ", end="")
* for i, (x, y) in enumerate(coords):
* if (i % 2) == 0:
* print("\n\t ", end="")
* print(f"{{{x}, {y}}}", end=",")
* print("\n\t};")
* \endcode
*/
#define POLY_TRI_COUNT(len) ((len)-2)
/* A counterclockwise triangle */
TEST(polyfill2d, TriangleCCW)
{
const float poly[][2] = {{0, 0}, {0, 1}, {1, 0}};
TEST_POLYFILL_TEMPLATE_STATIC(poly, false);
}
/* A counterclockwise square */
TEST(polyfill2d, SquareCCW)
{
const float poly[][2] = {{0, 0}, {0, 1}, {1, 1}, {1, 0}};
TEST_POLYFILL_TEMPLATE_STATIC(poly, false);
}
/* A clockwise square */
TEST(polyfill2d, SquareCW)
{
const float poly[][2] = {{0, 0}, {1, 0}, {1, 1}, {0, 1}};
TEST_POLYFILL_TEMPLATE_STATIC(poly, false);
}
/* Starfleet insigna */
TEST(polyfill2d, Starfleet)
{
const float poly[][2] = {{0, 0}, {0.6f, 0.4f}, {1, 0}, {0.5f, 1}};
TEST_POLYFILL_TEMPLATE_STATIC(poly, false);
}
/* Starfleet insigna with repeated point */
TEST(polyfill2d, StarfleetDegenerate)
{
const float poly[][2] = {{0, 0}, {0.6f, 0.4f}, {0.6f, 0.4f}, {1, 0}, {0.5f, 1}};
TEST_POLYFILL_TEMPLATE_STATIC(poly, false);
}
/* Three collinear points */
TEST(polyfill2d, 3Colinear)
{
const float poly[][2] = {{0, 0}, {1, 0}, {2, 0}};
TEST_POLYFILL_TEMPLATE_STATIC(poly, false);
}
/* Four collinear points */
TEST(polyfill2d, 4Colinear)
{
const float poly[][2] = {{0, 0}, {1, 0}, {2, 0}, {3, 0}};
TEST_POLYFILL_TEMPLATE_STATIC(poly, false);
}
/* Non-consecutive collinear points */
TEST(polyfill2d, UnorderedColinear)
{
const float poly[][2] = {{0, 0}, {1, 1}, {2, 0}, {3, 1}, {4, 0}};
TEST_POLYFILL_TEMPLATE_STATIC(poly, false);
}
/* Plus shape */
TEST(polyfill2d, PlusShape)
{
const float poly[][2] = {
{1, 0},
{2, 0},
{2, 1},
{3, 1},
{3, 2},
{2, 2},
{2, 3},
{1, 3},
{1, 2},
{0, 2},
{0, 1},
{1, 1},
};
TEST_POLYFILL_TEMPLATE_STATIC(poly, false);
}
/* Star shape */
TEST(polyfill2d, StarShape)
{
const float poly[][2] = {{4, 0}, {5, 3}, {8, 4}, {5, 5}, {4, 8}, {3, 5}, {0, 4}, {3, 3}};
TEST_POLYFILL_TEMPLATE_STATIC(poly, false);
}
/* U shape */
TEST(polyfill2d, UShape)
{
const float poly[][2] = {
{1, 0}, {2, 0}, {3, 1}, {3, 3}, {2, 3}, {2, 1}, {1, 1}, {1, 3}, {0, 3}, {0, 1}};
TEST_POLYFILL_TEMPLATE_STATIC(poly, false);
}
/* Spiral */
TEST(polyfill2d, Spiral)
{
const float poly[][2] = {
{1, 0},
{4, 0},
{5, 1},
{5, 4},
{4, 5},
{1, 5},
{0, 4},
{0, 3},
{1, 2},
{2, 2},
{3, 3},
{1, 3},
{1, 4},
{4, 4},
{4, 1},
{0, 1},
};
TEST_POLYFILL_TEMPLATE_STATIC(poly, false);
}
/* Test case from http:# www.flipcode.com/archives/Efficient_Polygon_Triangulation.shtml */
TEST(polyfill2d, TestFlipCode)
{
const float poly[][2] = {
{0, 6},
{0, 0},
{3, 0},
{4, 1},
{6, 1},
{8, 0},
{12, 0},
{13, 2},
{8, 2},
{8, 4},
{11, 4},
{11, 6},
{6, 6},
{4, 3},
{2, 6},
};
TEST_POLYFILL_TEMPLATE_STATIC(poly, false);
}
/* Self-intersection */
TEST(polyfill2d, SelfIntersect)
{
const float poly[][2] = {{0, 0}, {1, 1}, {2, -1}, {3, 1}, {4, 0}};
TEST_POLYFILL_TEMPLATE_STATIC(poly, true);
}
/* Self-touching */
TEST(polyfill2d, SelfTouch)
{
const float poly[][2] = {
{0, 0},
{4, 0},
{4, 4},
{2, 4},
{2, 3},
{3, 3},
{3, 1},
{1, 1},
{1, 3},
{2, 3},
{2, 4},
{0, 4},
};
TEST_POLYFILL_TEMPLATE_STATIC(poly, false);
}
/* Self-overlapping */
TEST(polyfill2d, SelfOverlap)
{
const float poly[][2] = {
{0, 0},
{4, 0},
{4, 4},
{1, 4},
{1, 3},
{3, 3},
{3, 1},
{1, 1},
{1, 3},
{3, 3},
{3, 4},
{0, 4},
};
TEST_POLYFILL_TEMPLATE_STATIC(poly, true);
}
/* Test case from http:# www.davdata.nl/math/polygons.html */
TEST(polyfill2d, TestDavData)
{
const float poly[][2] = {
{190, 480}, {140, 180}, {310, 100}, {330, 390}, {290, 390}, {280, 260}, {220, 260},
{220, 430}, {370, 430}, {350, 30}, {50, 30}, {160, 560}, {730, 510}, {710, 20},
{410, 30}, {470, 440}, {640, 410}, {630, 140}, {590, 140}, {580, 360}, {510, 370},
{510, 60}, {650, 70}, {660, 450}, {190, 480},
};
TEST_POLYFILL_TEMPLATE_STATIC(poly, false);
}
/* Issue 815, http:# code.google.com/p/libgdx/issues/detail?id=815 */
TEST(polyfill2d, Issue815)
{
const float poly[][2] = {
{-2.0f, 0.0f},
{-2.0f, 0.5f},
{0.0f, 1.0f},
{0.5f, 2.875f},
{1.0f, 0.5f},
{1.5f, 1.0f},
{2.0f, 1.0f},
{2.0f, 0.0f},
};
TEST_POLYFILL_TEMPLATE_STATIC(poly, false);
}
/* Issue 207, comment #1, http:# code.google.com/p/libgdx/issues/detail?id=207#c1 */
TEST(polyfill2d, Issue207_1)
{
const float poly[][2] = {
{72.42465f, 197.07095f},
{78.485535f, 189.92776f},
{86.12059f, 180.92929f},
{99.68253f, 164.94557f},
{105.24325f, 165.79604f},
{107.21862f, 166.09814f},
{112.41958f, 162.78253f},
{113.73238f, 161.94562f},
{123.29477f, 167.93805f},
{126.70667f, 170.07617f},
{73.22717f, 199.51062f},
};
TEST_POLYFILL_TEMPLATE_STATIC(poly, true);
}
/* Issue 207, comment #11, http:# code.google.com/p/libgdx/issues/detail?id=207#c11 */
/* Also on issue 1081, http:# code.google.com/p/libgdx/issues/detail?id=1081 */
TEST(polyfill2d, Issue207_11)
{
const float poly[][2] = {
{2400.0f, 480.0f}, {2400.0f, 176.0f}, {1920.0f, 480.0f},
{1920.0459f, 484.22314f}, {1920.1797f, 487.91016f}, {1920.3955f, 491.0874f},
{1920.6875f, 493.78125f}, {1921.0498f, 496.01807f}, {1921.4766f, 497.82422f},
{1921.9619f, 499.22607f}, {1922.5f, 500.25f}, {1923.085f, 500.92236f},
{1923.7109f, 501.26953f}, {1924.3721f, 501.31787f}, {1925.0625f, 501.09375f},
{1925.7764f, 500.62354f}, {1926.5078f, 499.9336f}, {1927.251f, 499.0503f},
{1928.0f, 498.0f}, {1928.749f, 496.80908f}, {1929.4922f, 495.5039f},
{1930.2236f, 494.11084f}, {1930.9375f, 492.65625f}, {1931.6279f, 491.1665f},
{1932.2891f, 489.66797f}, {1932.915f, 488.187f}, {1933.5f, 486.75f},
{1934.0381f, 485.3833f}, {1934.5234f, 484.11328f}, {1934.9502f, 482.9663f},
{1935.3125f, 481.96875f}, {1935.6045f, 481.14697f}, {1935.8203f, 480.52734f},
{1935.9541f, 480.13623f}, {1936.0f, 480.0f}};
TEST_POLYFILL_TEMPLATE_STATIC(poly, false);
}
/* Issue 1407, http:# code.google.com/p/libgdx/issues/detail?id=1407 */
TEST(polyfill2d, Issue1407)
{
const float poly[][2] = {
{3.914329f, 1.9008259f},
{4.414321f, 1.903619f},
{4.8973203f, 1.9063174f},
{5.4979978f, 1.9096732f},
};
TEST_POLYFILL_TEMPLATE_STATIC(poly, false);
}
/* Issue 1407, http:# code.google.com/p/libgdx/issues/detail?id=1407, */
/* with an additional point to show what is happening. */
TEST(polyfill2d, Issue1407_pt)
{
const float poly[][2] = {
{3.914329f, 1.9008259f},
{4.414321f, 1.903619f},
{4.8973203f, 1.9063174f},
{5.4979978f, 1.9096732f},
{4, 4},
};
TEST_POLYFILL_TEMPLATE_STATIC(poly, false);
}
/* Simplified from Blender bug T40777 */
TEST(polyfill2d, IssueT40777_colinear)
{
const float poly[][2] = {
{0.7, 0.37}, {0.7, 0}, {0.76, 0}, {0.76, 0.4}, {0.83, 0.4}, {0.83, 0}, {0.88, 0},
{0.88, 0.4}, {0.94, 0.4}, {0.94, 0}, {1, 0}, {1, 0.4}, {0.03, 0.62}, {0.03, 0.89},
{0.59, 0.89}, {0.03, 1}, {0, 1}, {0, 0}, {0.03, 0}, {0.03, 0.37},
};
TEST_POLYFILL_TEMPLATE_STATIC(poly, false);
}
/* Blender bug T41986 */
TEST(polyfill2d, IssueT41986_axis_align)
{
const float poly[][2] = {
{-0.25, -0.07}, {-0.25, 0.27}, {-1.19, 0.14}, {-0.06, 0.73}, {0.17, 1.25},
{-0.25, 1.07}, {-0.38, 1.02}, {-0.25, 0.94}, {-0.40, 0.90}, {-0.41, 0.86},
{-0.34, 0.83}, {-0.25, 0.82}, {-0.66, 0.73}, {-0.56, 1.09}, {-0.25, 1.10},
{0.00, 1.31}, {-0.03, 1.47}, {-0.25, 1.53}, {0.12, 1.62}, {0.36, 1.07},
{0.12, 0.67}, {0.29, 0.57}, {0.44, 0.45}, {0.57, 0.29}, {0.66, 0.12},
{0.68, 0.06}, {0.57, -0.36}, {-0.25, -0.37}, {0.49, -0.74}, {-0.59, -1.21},
{-0.25, -0.15}, {-0.46, -0.52}, {-1.08, -0.83}, {-1.45, -0.33}, {-1.25, -0.04}};
TEST_POLYFILL_TEMPLATE_STATIC(poly, false);
}
/* Blender bug T52834 */
TEST(polyfill2d, IssueT52834_axis_align_co_linear)
{
const float poly[][2] = {
{40, 0}, {36, 0}, {36, 5}, {35, 5}, {35, 0}, {30, 0}, {30, 5}, {29, 5},
{29, 0}, {24, 0}, {24, 3}, {23, 4}, {23, 0}, {18, 0}, {18, 5}, {17, 5},
{17, 0}, {12, 0}, {12, 5}, {11, 5}, {11, 0}, {6, 0}, {6, 5}, {5, 5},
{5, 0}, {0, 0}, {0, 5}, {-1, 5}, {-1, 0}, {-6, 0}, {-9, -3}, {-6, -3},
{-6, -2}, {-1, -2}, {0, -2}, {5, -2}, {6, -2}, {11, -2}, {12, -2}, {17, -2},
{18, -2}, {23, -2}, {24, -2}, {29, -2}, {30, -2}, {35, -2}, {36, -2}, {40, -2},
};
TEST_POLYFILL_TEMPLATE_STATIC(poly, false);
}
/* Blender bug T67109 (version a). */
/* Multiple versions are offset & rotated, this fails in cases where others works. */
TEST(polyfill2d, IssueT67109_axis_align_co_linear_a)
{
const float poly[][2] = {
{3.2060661, -11.438997},
{2.8720665, -5.796999},
{-2.8659325, -5.796999},
{-2.8659325, -8.307999},
{-3.2549324, -11.438997},
{-2.8659325, -5.4869995},
{2.8720665, -5.4869995},
{2.8720665, -2.9759989},
{2.8720665, -2.6659985},
{2.8720665, -0.15499878},
};
TEST_POLYFILL_TEMPLATE_STATIC(poly, false);
}
/* Blender bug T67109, (version b). */
TEST(polyfill2d, IssueT67109_axis_align_co_linear_b)
{
const float poly[][2] = {
{32.41416, -12.122593},
{28.094929, -8.477332},
{24.141455, -12.636018},
{25.96133, -14.366093},
{27.96254, -16.805279},
{23.916779, -12.422427},
{27.870255, -8.263744},
{26.050375, -6.533667},
{25.825695, -6.320076},
{24.00582, -4.5899982},
};
TEST_POLYFILL_TEMPLATE_STATIC(poly, false);
}
/* Blender bug T67109 (version c). */
TEST(polyfill2d, IssueT67109_axis_align_co_linear_c)
{
const float poly[][2] = {
{-67.10034, 43.677097},
{-63.253956, 61.399143},
{-80.98382, 66.36057},
{-83.15499, 58.601795},
{-87.06422, 49.263668},
{-80.71576, 67.31843},
{-62.985912, 62.35701},
{-60.81475, 70.11576},
{-60.546703, 71.07365},
{-58.37554, 78.83239},
};
TEST_POLYFILL_TEMPLATE_STATIC(poly, false);
}

View File

@@ -1,610 +0,0 @@
/* Apache License, Version 2.0 */
#ifndef __BLENDER_TESTING_BLI_RESSOURCE_STRING_H__
#define __BLENDER_TESTING_BLI_RESSOURCE_STRING_H__
/* Data file, don't format. */
/* clang-format off */
const char words10k[] =
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam auctor ultrices purus tincidunt mollis. Vestibulum "
"tincidunt imperdiet molestie. Vivamus posuere, risus ut mollis rutrum, lacus nulla mollis velit, consectetur auctor "
"erat est in odio. Proin quis lobortis ex. Ut id quam lacus. Morbi ultrices orci quis sem suscipit tincidunt. Nullam "
"ut molestie justo, vulputate placerat diam. Nunc tincidunt auctor venenatis. Phasellus placerat, odio ac dictum "
"pretium, nisi odio tristique sem, sit amet hendrerit odio tortor eu felis. Duis placerat tristique neque, sit amet "
"ornare nulla fermentum vel. Vivamus vitae rhoncus ante. Sed a dolor mauris. Nullam bibendum vehicula semper. Duis ut "
"commodo nibh. Nulla sit amet eros feugiat, accumsan nisl a, ornare quam. In non magna orci. Curabitur finibus tempus "
"semper. Aliquam fringilla arcu consectetur blandit vestibulum. Mauris mollis est arcu. Praesent pellentesque lacus "
"bibendum massa commodo commodo. Aenean facilisis lobortis varius. Ut semper ullamcorper dui, at pellentesque felis. "
"Duis accumsan sapien ut malesuada lacinia. Praesent elementum venenatis arcu in mattis. Nunc sagittis mauris risus, "
"quis rutrum nisi egestas quis. Maecenas pharetra posuere auctor. Suspendisse mollis sollicitudin elit, id cursus "
"massa bibendum eu. Integer tincidunt dolor non porttitor tempus. Donec lacinia sapien eu enim feugiat suscipit non "
"malesuada diam. Suspendisse nec convallis elit. Nulla eu augue ultrices, consequat lorem at, malesuada magna. "
"Aliquam sed tempor ipsum. Sed hendrerit nec lectus et pharetra. In felis sem, cursus at nunc in, tristique convallis "
"purus. Praesent augue turpis, porttitor consequat risus ornare, laoreet commodo dui. Nulla congue ultrices sapien a "
"cursus. Nulla facilisi. Integer lacinia enim sodales sem mattis, sit amet egestas lectus tincidunt. Ut quis nisl ut "
"ex luctus fermentum quis et diam. Maecenas lectus leo, hendrerit eu facilisis et, mattis ut sem. Duis imperdiet nisl "
"vitae urna consequat suscipit. Suspendisse sed viverra massa, dapibus condimentum sem. Morbi suscipit congue odio. "
"Nullam eleifend fringilla nisl et semper. Sed eu neque ante. Sed eget viverra urna. Duis tempor laoreet interdum. "
"Nunc fringilla aliquet urna sit amet commodo. Curabitur non orci nec libero egestas ullamcorper nec nec velit. Nam "
"vitae ligula lobortis, vehicula nulla id, lacinia urna. Morbi id dignissim eros. Etiam eu risus in sem vestibulum "
"dapibus ut mollis sem. Quisque ultricies pulvinar maximus. Proin risus turpis, auctor eget molestie nec, molestie a "
"ipsum. Donec dapibus dui in lorem rhoncus, non rutrum neque convallis. Donec at tincidunt turpis, nec scelerisque "
"lorem. Donec ac sapien mi. Sed commodo efficitur tempus. Maecenas eu lobortis diam. Phasellus enim nulla, ornare ac "
"laoreet egestas, vestibulum ac arcu. Pellentesque ultrices mauris sem, a iaculis diam tristique id. Proin sed "
"facilisis mauris. Aliquam nibh ex, varius in consequat laoreet, sollicitudin id diam. Vivamus semper ultrices sem "
"non tempor. Sed hendrerit maximus malesuada. In ex orci, elementum non magna eget, congue sagittis tellus. Donec "
"malesuada sem leo, quis malesuada risus blandit et. Praesent porta malesuada metus eget pretium. Vestibulum "
"venenatis tempor tellus at varius. Donec mauris arcu, elementum vitae aliquet nec, ullamcorper vitae neque. Nunc eu "
"viverra justo, sit amet viverra elit. Proin urna elit, luctus ut placerat quis, blandit vitae diam. Vestibulum id "
"fringilla enim. Ut eleifend augue ante, ac euismod sapien luctus sit amet. Pellentesque mattis tortor ac rutrum "
"malesuada. Sed et nulla id metus faucibus condimentum. Vestibulum cursus posuere vestibulum. Proin auctor arcu erat, "
"quis porta sem dignissim a. Donec sed finibus ante. Integer porttitor pretium nunc, eu semper elit. Nam sit amet "
"ornare urna. Suspendisse porta augue id massa luctus maximus. Fusce tellus ligula, finibus sed lacus eget, tristique "
"mollis libero. Vivamus velit diam, faucibus vel fringilla vitae, ornare id lacus. Pellentesque vel sem quis nunc "
"semper porta ut sit amet sapien. Integer nec leo at tortor ullamcorper pulvinar at ut ante. Fusce velit nisl, "
"fermentum in tempus ac, gravida ac tellus. In aliquet sollicitudin erat, non vestibulum diam aliquam in. Duis purus "
"justo, aliquet ut libero vel, egestas mollis nibh. Praesent sed tempor mauris, vel tempor augue. Morbi eu eros vel "
"velit condimentum porttitor nec sit amet odio. Nunc suscipit risus at ex aliquam, in pretium mi maximus. Mauris "
"sollicitudin sit amet arcu luctus maximus. Curabitur vehicula condimentum porta. Nunc consequat vitae urna vel "
"gravida. Vivamus vitae mattis augue, sit amet blandit enim. Phasellus odio leo, cursus eget lacus sit amet, "
"facilisis mattis tortor. Duis venenatis ante libero, eu condimentum urna viverra fermentum. Suspendisse libero leo, "
"pretium eu leo at, imperdiet ultricies nunc. Fusce ante neque, feugiat id lacus sed, fringilla suscipit ligula. "
"Phasellus cursus malesuada urna, vel ullamcorper massa suscipit vitae. In eu bibendum augue. Duis auctor posuere "
"turpis nec vestibulum. Vestibulum nec dui in mi consequat auctor sed at nisl. Suspendisse tellus elit, congue ut "
"facilisis vel, ornare id mauris. Integer rutrum fermentum neque, vitae pharetra metus consectetur in. Duis vitae "
"lacus scelerisque, rhoncus nisl id, sagittis elit. Praesent lacinia libero ac ultricies tempus. Etiam ut maximus "
"sapien. Maecenas sit amet ante auctor, feugiat diam non, vulputate diam. Nulla facilisi. Vestibulum id augue velit. "
"Donec at elementum urna. Morbi elementum nunc in neque ornare, sit amet tempor mauris vulputate. Nunc mauris mauris, "
"lobortis non nibh sed, gravida sollicitudin nunc. Nunc vel dolor non augue venenatis semper vitae non turpis. "
"Praesent mattis elit eu interdum porttitor. Etiam quis magna magna. Praesent a ipsum est. Aenean at ligula vel leo "
"faucibus pulvinar sed eget mauris. Nam accumsan blandit nibh, nec tincidunt nisl eleifend sit amet. Etiam ornare, "
"arcu nec dictum volutpat, nulla orci porttitor orci, vel venenatis mi massa at erat. Maecenas eget accumsan nisl, "
"quis ullamcorper turpis. Pellentesque sit amet mi aliquet, feugiat felis in, dictum urna. Cras nulla leo, congue vel "
"consequat gravida, aliquet a nulla. Nulla commodo, nisi eu ultricies feugiat, justo velit tempor ligula, a tincidunt "
"nisi tellus ut sapien. Sed eget ornare magna. Cras ut vehicula sapien. Quisque id malesuada urna, vitae congue ante. "
"Donec nec leo pretium, finibus nibh a, porta lectus. Fusce arcu tellus, tempor semper sem id, aliquam fringilla "
"ipsum. Ut massa ante, placerat quis sapien quis, sollicitudin blandit turpis. Aenean posuere ullamcorper massa. Nam "
"faucibus egestas arcu. Vivamus vehicula auctor diam, eu placerat diam ullamcorper at. Nulla eu consequat elit, vel "
"semper turpis. Curabitur rhoncus nunc vel vestibulum interdum. Nam augue neque, pharetra vel nisi dignissim, "
"vehicula dapibus risus. Cras eget mattis nisi. Sed tempor posuere gravida. Proin sagittis a nisl eget gravida. "
"Curabitur viverra dapibus arcu, sit amet rutrum nibh fringilla euismod. Donec vitae risus non lorem facilisis cursus "
"eu eu quam. Donec quis lacus blandit, consectetur elit ut, sagittis ligula. Etiam dapibus ex sit amet elit commodo "
"finibus. Suspendisse non finibus felis, non cursus libero. Vivamus semper aliquet velit vel elementum. Phasellus "
"dictum, tortor id sagittis ultrices, ex dui porttitor tortor, nec mattis dolor sem nec mi. Ut aliquam consequat eros "
"sit amet mollis. Nullam mollis venenatis porttitor. Donec sit amet velit at velit luctus auctor dictum in neque. Ut "
"vulputate ultricies mollis. Pellentesque elementum augue dolor, non varius ligula tristique ac. Nullam eget mauris "
"urna. Integer elementum eleifend pulvinar. Morbi gravida ante eget ornare faucibus. Mauris pulvinar consequat nunc "
"vel accumsan. Curabitur egestas urna elit, ut accumsan magna dictum in. Nam neque mi, ornare sed leo at, tempor "
"vulputate nunc. Nunc dignissim mauris id dui iaculis fringilla. Praesent malesuada tellus in dapibus feugiat. "
"Vivamus posuere, nisi et consequat euismod, lorem augue iaculis velit, eget iaculis neque quam eu mi. Nullam ac "
"hendrerit felis, non elementum ipsum. Aliquam erat volutpat. Proin vel molestie felis. Nullam luctus vel ante nec "
"facilisis. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Duis et metus "
"justo. Interdum et malesuada fames ac ante ipsum primis in faucibus. Ut tristique sit amet elit et congue. Aenean "
"quis elementum enim, vitae pharetra sem. Vestibulum vel finibus nisl, at consequat eros. In vitae mollis lacus, et "
"pharetra elit. Mauris varius sapien quis tincidunt blandit. Proin non semper nibh. Aliquam non elit id felis laoreet "
"interdum eget a risus. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. "
"Suspendisse nisl tellus, mollis id erat vel, hendrerit volutpat nunc. Quisque scelerisque cursus tellus, nec "
"placerat quam imperdiet in. Sed porttitor arcu vel ligula finibus, a vestibulum enim ultrices. Fusce imperdiet augue "
"eget est vehicula porttitor. Quisque convallis odio vitae lorem porttitor iaculis. Ut dictum velit ac tortor "
"lobortis ultrices. Vestibulum tincidunt vestibulum mauris, at fermentum elit imperdiet nec. Nunc finibus ornare "
"lorem vel malesuada. Praesent arcu turpis, pulvinar sit amet accumsan quis, tincidunt vel justo. Pellentesque "
"volutpat nec enim sit amet pulvinar. Nam eu libero dignissim, volutpat elit ut, semper tortor. Morbi pellentesque "
"nisl lectus. In vel tellus sed sem luctus lobortis ut nec diam. Phasellus id semper sem. Phasellus in purus "
"consequat, rhoncus mi mollis, finibus ligula. Fusce feugiat dictum consequat. Mauris egestas, est ut euismod "
"consequat, arcu dui dignissim quam, pharetra dignissim orci dolor quis nisl. Nunc dapibus blandit urna non feugiat. "
"Suspendisse non maximus augue. Quisque ut orci aliquet, vulputate massa eget, mattis diam. Etiam efficitur "
"consectetur viverra. Nulla massa augue, elementum at turpis et, cursus ultricies risus. Suspendisse vel nibh "
"placerat, imperdiet elit et, viverra ligula. Donec lorem lorem, hendrerit nec aliquam sit amet, scelerisque sit amet "
"massa. Mauris convallis ullamcorper tortor sed malesuada. Fusce ultricies a turpis eu ornare. Suspendisse potenti. "
"Sed non nulla condimentum, vulputate nisi nec, tincidunt arcu. Morbi erat leo, lobortis id odio ac, hendrerit "
"sodales sem. Ut malesuada, lectus at posuere molestie, orci metus vehicula justo, mattis tincidunt arcu risus quis "
"odio. Fusce non sem sed nisi consectetur finibus vitae quis diam. Vivamus a lacinia nisl. Praesent tempus nunc "
"gravida, lacinia lacus in, lobortis massa. Aliquam gravida consequat nisi at fringilla. Quisque tortor tortor, "
"tincidunt cursus lorem eget, ultrices ultricies lacus. Phasellus mattis iaculis elit, eget mattis nisl bibendum sed. "
"Integer faucibus gravida nisl, ac consequat ex tempor at. Sed tempus elementum vestibulum. Suspendisse vitae enim "
"semper, pulvinar diam eget, suscipit turpis. Maecenas ultricies, diam sed consectetur sagittis, diam sem cursus "
"nisl, nec aliquet tellus augue quis ipsum. Cras vel lorem convallis, mattis risus at, placerat massa. Curabitur vel "
"rutrum ligula. Quisque in nibh libero. Pellentesque diam tellus, consectetur eget quam ac, faucibus imperdiet odio. "
"Sed tortor nulla, scelerisque non turpis nec, fringilla bibendum est. Etiam a urna eget erat tincidunt ultrices. "
"Maecenas lorem odio, volutpat nec ligula id, hendrerit aliquam nulla. Aenean congue lacinia fermentum. Suspendisse "
"sed interdum lacus. Fusce scelerisque posuere sagittis. Ut at semper tellus. Donec condimentum orci nunc, non "
"fermentum purus volutpat eget. Maecenas elementum dapibus ante, eu suscipit quam imperdiet ut. Integer non congue "
"elit. Sed venenatis, turpis varius commodo euismod, libero magna fringilla lacus, quis venenatis velit lectus sed "
"augue. Morbi gravida orci odio, ut ornare massa sollicitudin a. Donec convallis mi et sapien tempor, non dapibus "
"dolor fringilla. Aenean euismod rutrum turpis, et facilisis orci porttitor eu. Suspendisse in neque leo. Nulla "
"facilisi. Etiam mollis orci nisl, quis scelerisque metus efficitur vehicula. Nam porta molestie tortor, sit amet "
"consectetur leo vestibulum vel. Pellentesque a volutpat augue. Maecenas vel elementum ex, eget elementum leo. "
"Curabitur at maximus metus, quis porttitor orci. Praesent auctor commodo elit, a dapibus tortor volutpat et. "
"Praesent dictum posuere dolor sit amet molestie. Sed viverra augue nec eros mattis blandit. In quis sodales dolor. "
"Donec sed purus ex. Fusce erat magna, efficitur ac tempus ac, lacinia quis augue. Aliquam porta efficitur est vel "
"placerat. Phasellus egestas vel nunc eu consequat. Maecenas ligula arcu, molestie ut dui ut, ornare finibus felis. "
"Duis condimentum non augue ut posuere. Aenean mattis eros ut ligula ornare finibus. Aliquam feugiat ut turpis a "
"feugiat. Vestibulum eget sollicitudin orci, nec fermentum justo. Praesent efficitur est a metus bibendum, eget "
"feugiat diam suscipit. Suspendisse sit amet ipsum ut purus feugiat pretium. Morbi nisl risus, ultricies sit amet "
"ullamcorper euismod, commodo eu libero. Aenean fringilla ipsum nec orci rutrum aliquet. Aenean lacus ante, eleifend "
"eu eleifend fringilla, elementum ac justo. Vestibulum tincidunt interdum lectus sit amet fermentum. Etiam rhoncus eu "
"ante lacinia sagittis. Maecenas iaculis ut erat quis feugiat. Maecenas sed est vel tellus bibendum rutrum volutpat "
"nec odio. Vivamus euismod augue nec purus euismod, mattis finibus nisi finibus. Donec quis ultrices massa. Quisque "
"at nisl faucibus, facilisis tellus ut, ultricies dui. Class aptent taciti sociosqu ad litora torquent per conubia "
"nostra, per inceptos himenaeos. Donec et arcu eros. Etiam dapibus bibendum felis eu viverra. Integer a lacus "
"venenatis elit lacinia facilisis non non felis. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed "
"ultricies augue at sapien mattis aliquam. Quisque nec semper purus. Cras auctor aliquet lacus, sed facilisis urna "
"sollicitudin non. Vivamus eget erat purus. Sed a risus augue. Donec non sem sed sapien accumsan lacinia. Ut mauris "
"odio, vehicula id accumsan at, tincidunt non odio. Nunc porttitor luctus ante ac cursus. Cras et dapibus ex, id "
"pretium ligula. Proin volutpat rhoncus ex vitae venenatis. Pellentesque imperdiet, magna non tempus auctor, metus "
"dolor scelerisque dui, id tempor purus est in risus. Suspendisse vehicula imperdiet sapien, nec pulvinar dolor "
"ornare ac. Nulla luctus, nisl in aliquam blandit, risus orci placerat nunc, id tempus sem neque vitae leo. Aenean at "
"elit elit. Suspendisse finibus dictum interdum. Nunc consectetur eget quam vitae egestas. Pellentesque tellus augue, "
"aliquet at faucibus ac, imperdiet ut nulla. Maecenas quis lorem velit. Donec porta ligula et suscipit luctus. "
"Aliquam sed pretium nunc. Nunc quis posuere tortor. Fusce in lectus nec turpis rhoncus pellentesque eu at quam. "
"Nulla facilisi. Sed ante nulla, posuere ac ullamcorper vel, rhoncus vitae nisl. Nam non pellentesque arcu. Vivamus "
"nibh leo, pellentesque a mollis non, gravida ut erat. Donec purus urna, pulvinar eu iaculis blandit, rutrum eget "
"nulla. Fusce quis fermentum diam, faucibus volutpat lorem. Maecenas aliquet nisi nisl, eget sollicitudin ipsum "
"facilisis at. Mauris nec sapien nisi. Duis ac laoreet sapien, a condimentum nisi. Nam vitae sapien sed sem convallis "
"ornare. Pellentesque neque diam, ullamcorper et dolor sit amet, faucibus venenatis tortor. Nunc vel erat malesuada, "
"vulputate odio sit amet, aliquam dui. Donec tincidunt arcu ut risus laoreet, id malesuada leo ultrices. Praesent a "
"scelerisque libero, vitae suscipit massa. Quisque faucibus mauris rhoncus turpis vestibulum rhoncus. Donec vel "
"molestie magna. Aenean et lorem dui. Nam iaculis ante sapien, semper tincidunt tortor hendrerit id. Nulla sed orci "
"mi. Aliquam hendrerit libero erat, ac aliquam massa rutrum non. Suspendisse eleifend, elit in aliquet hendrerit, "
"tellus erat sodales neque, quis rhoncus tellus sem vitae est. Interdum et malesuada fames ac ante ipsum primis in "
"faucibus. Etiam quis mauris non ipsum tristique interdum sit amet eget mi. Ut velit risus, gravida ut efficitur sit "
"amet, commodo at diam. Sed consectetur dui porttitor quam feugiat, et auctor mauris maximus. Nullam lobortis ac mi "
"lacinia egestas. Proin ante massa, malesuada ut nulla elementum, venenatis mollis ante. Cum sociis natoque penatibus "
"et magnis dis parturient montes, nascetur ridiculus mus. Mauris eget gravida eros, non varius velit. Integer "
"consectetur lectus nec arcu scelerisque, scelerisque vulputate mauris suscipit. Aliquam orci dui, faucibus et rutrum "
"in, rhoncus quis dolor. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; "
"Maecenas ante nunc, placerat id lectus sit amet, luctus cursus ante. Nulla nec placerat arcu. Fusce ac dictum ex. "
"Vivamus semper nulla vitae neque volutpat, auctor vestibulum arcu tempus. Pellentesque aliquam tincidunt arcu, et "
"pharetra neque. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Nunc "
"risus augue, malesuada quis risus a, suscipit semper metus. Suspendisse ac rhoncus felis. Aliquam orci lectus, "
"elementum at nulla at, ullamcorper pellentesque leo. Quisque nisi tellus, pharetra in pellentesque in, facilisis "
"vitae velit. In ex ex, sagittis at dolor vel, congue ultricies velit. Duis quis gravida mi. Aenean tempor efficitur "
"lectus. Fusce sodales, ex eu efficitur iaculis, metus sem eleifend purus, ut commodo arcu tortor eget urna. Etiam "
"nisi nisl, malesuada convallis ex at, malesuada elementum nunc. Vivamus commodo mi id ligula tincidunt posuere. "
"Integer eget arcu cursus, sagittis quam eu, aliquam leo. In auctor eget mauris et elementum. Aenean sagittis euismod "
"tellus sed accumsan. Aliquam erat volutpat. Aliquam erat volutpat. Ut consectetur porta ipsum sit amet porttitor. "
"Nam ut nunc a turpis auctor finibus. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac "
"turpis egestas. Donec non nisl condimentum, fermentum augue in, egestas libero. Pellentesque ut odio rhoncus, "
"sollicitudin felis vitae, pellentesque est. Suspendisse tincidunt eros eget ex vestibulum elementum. Vivamus mollis "
"scelerisque diam, quis dignissim dolor venenatis at. Ut gravida sapien vitae risus efficitur, ut auctor justo "
"gravida. Cras arcu elit, interdum vel purus sit amet, venenatis molestie tellus. Integer consectetur tempor velit a "
"varius. Praesent congue, massa non congue blandit, tortor purus imperdiet elit, sit amet pharetra arcu lacus egestas "
"neque. Maecenas in erat arcu. In varius, risus vitae mollis sodales, nisi velit bibendum tortor, vitae sagittis "
"augue tortor quis nunc. Fusce posuere dolor ac tincidunt facilisis. Phasellus in lacus diam. Fusce mattis sapien "
"tellus, scelerisque pharetra leo eleifend nec. Cras libero diam, convallis in luctus a, iaculis a ipsum. Duis arcu "
"leo, volutpat non mauris et, scelerisque suscipit diam. Ut vulputate placerat velit quis placerat. Duis commodo non "
"turpis et convallis. Duis nec pulvinar metus, ac tristique leo. Fusce vehicula augue ac placerat elementum. Nulla "
"dapibus nisi pretium lectus sodales, ac congue sapien ornare. Vestibulum sagittis orci ut purus efficitur, eu mollis "
"libero placerat. Vestibulum ullamcorper odio non quam mollis, eget rhoncus metus eleifend. Mauris scelerisque, massa "
"rutrum sodales malesuada, elit dolor blandit lectus, quis faucibus felis odio feugiat lacus. Nunc bibendum congue "
"efficitur. Nunc a purus neque. In lobortis metus nisi, vel pellentesque mi facilisis sed. Donec in pretium neque, in "
"maximus metus. Integer faucibus diam sed tristique sagittis. Nullam eget maximus leo, eget malesuada leo. Vestibulum "
"ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Aenean porttitor risus eget eros "
"euismod molestie. Integer tristique tincidunt elit, non posuere libero pretium vel. Fusce dapibus, nisi nec egestas "
"dapibus, lectus arcu maximus leo, a finibus diam arcu ut mauris. Vivamus tincidunt lectus ut augue ultrices, et "
"cursus sem cursus. Proin in quam mauris. Maecenas vel magna dapibus, interdum ipsum mattis, posuere tortor. Cras eu "
"massa ex. Donec eget massa vel dui gravida luctus vel a quam. Etiam eu lobortis neque. Etiam ligula dui, dictum ut "
"turpis ac, eleifend pretium turpis. Vestibulum convallis finibus commodo. Morbi fermentum ante nunc, a rhoncus lacus "
"ultricies quis. Suspendisse finibus quam blandit odio elementum, non efficitur diam laoreet. Cras aliquet ligula "
"eget magna scelerisque, ut ornare nisi elementum. Duis nisl massa, suscipit id nibh a, venenatis auctor risus. Nulla "
"luctus eget odio quis ultrices. Etiam consequat sapien ut nisl mollis cursus. Pellentesque a lacinia odio, id varius "
"lorem. Curabitur scelerisque in urna eget pretium. Class aptent taciti sociosqu ad litora torquent per conubia "
"nostra, per inceptos himenaeos. Sed leo metus, fermentum vitae quam ut, suscipit efficitur purus. Sed facilisis "
"dapibus pulvinar. Cras sed eleifend mi. Sed quis nibh in sapien venenatis interdum ac nec orci. Sed non tortor urna. "
"Nam rutrum lacinia diam id vehicula. Quisque vitae lobortis nibh, at tempor purus. Suspendisse dictum interdum nisi, "
"quis maximus ipsum commodo tempus. Nulla semper congue gravida. Aenean at nibh in eros aliquam egestas. Nulla "
"fermentum efficitur laoreet. Donec non lorem nec augue porttitor cursus eu in quam. Aenean laoreet quam neque, at "
"tempus nisi ultrices id. Quisque in diam lacinia nulla scelerisque rhoncus vitae eget nulla. Donec vel est metus. "
"Nullam suscipit odio eu enim lacinia facilisis eget in tellus. Vestibulum vehicula risus nec odio consectetur, a "
"cursus massa imperdiet. Duis facilisis felis quis nunc mattis, nec volutpat libero tempor. Nulla nec leo sed tellus "
"maximus lobortis. Suspendisse at urna nibh. Vestibulum eget turpis nisl. Donec scelerisque neque auctor erat tempor "
"elementum sed id lacus. Sed metus nulla, dictum non luctus vel, suscipit et ex. Quisque laoreet sapien non neque "
"iaculis, at aliquam massa viverra. Nullam nibh diam, imperdiet eu nunc sed, congue cursus leo. Morbi tristique diam "
"metus, at faucibus magna mollis at. Sed eget nibh nunc. Nam nec elementum sem, sit amet tincidunt lorem. In viverra "
"elit et interdum fermentum. Integer imperdiet orci ac justo molestie ullamcorper. Pellentesque fringilla tortor "
"erat, scelerisque maximus nisl sollicitudin a. Integer nisi elit, pharetra eget lacinia non, congue sit amet ex. "
"Phasellus tempus suscipit ultrices. Quisque ac nibh dignissim erat bibendum cursus vel a enim. Curabitur a augue sit "
"amet lorem pharetra feugiat. Donec euismod, massa at venenatis bibendum, elit libero pellentesque velit, eget congue "
"metus risus a enim. Aenean pretium vestibulum enim, sit amet vulputate urna auctor vitae. Praesent porttitor erat eu "
"mi cursus venenatis. Maecenas ut ultrices neque, ac feugiat libero. Nulla finibus sit amet sem in auctor. Nam "
"fermentum maximus ex, et consequat velit lobortis id. Aliquam eu feugiat est. Donec quis leo ex. Suspendisse "
"convallis eget nulla eu aliquet. Quisque aliquet tortor vitae ipsum fermentum tristique. Sed convallis rutrum augue, "
"ac viverra est pharetra quis. Ut porttitor magna massa, placerat maximus lectus scelerisque quis. Sed viverra urna "
"in neque feugiat rhoncus. Donec ut viverra odio, laoreet dignissim dui. Aenean tristique feugiat diam vel luctus. "
"Cras sit amet condimentum neque, ut faucibus ante. Aenean vitae elit id est laoreet efficitur in sit amet magna. "
"Praesent ante felis, blandit id nisl ut, porta fringilla orci. Aenean vel accumsan metus, vel vehicula metus. Nulla "
"placerat nibh et auctor convallis. Maecenas magna metus, pretium ac sodales ac, eleifend quis eros. Praesent "
"volutpat quam a pulvinar pharetra. Sed arcu dolor, aliquet nec magna in, faucibus consequat lorem. In tincidunt, ex "
"a finibus rutrum, metus dui fringilla ex, ac mollis elit leo eget augue. Nunc vehicula facilisis nibh, quis "
"ultricies sem. Praesent nulla est, finibus in lorem in, mattis placerat urna. Proin hendrerit risus nunc, id congue "
"ex posuere id. Aenean ullamcorper tortor quis lorem consectetur, et euismod leo fermentum. Praesent vulputate congue "
"lectus sit amet pulvinar. Vestibulum vel vestibulum quam, in convallis diam. Maecenas sollicitudin magna odio, eget "
"mollis purus posuere eu. Curabitur molestie mattis ligula, a maximus dui fermentum ut. Fusce justo velit, eleifend "
"ut tellus vitae, volutpat maximus risus. Pellentesque suscipit mauris non purus placerat porta. Nunc in malesuada "
"mi, vel bibendum felis. Aenean pretium nunc id efficitur porttitor. Mauris malesuada, tortor sit amet blandit "
"tincidunt, tellus est ullamcorper diam, sit amet aliquet ex velit interdum quam. In hac habitasse platea dictumst. "
"Sed vitae est eu elit posuere mattis nec a mauris. Morbi id ligula sed nunc sagittis finibus vitae eu nisi. Cras "
"dignissim sagittis tellus a suscipit. Nunc semper erat nec libero vestibulum, at mattis purus scelerisque. "
"Pellentesque egestas volutpat eleifend. Nullam venenatis erat id diam venenatis, sed rhoncus felis hendrerit. Nullam "
"luctus facilisis risus. Mauris sed urna nisi. Ut tempus feugiat metus. Integer at purus velit. Praesent neque felis, "
"pellentesque vitae sem nec, tempor commodo urna. Morbi malesuada ante sit amet purus tincidunt pellentesque. Aenean "
"commodo lectus sit amet dignissim hendrerit. Phasellus auctor tellus ligula, eu ultrices ex egestas non. Mauris eget "
"nisl dictum, scelerisque sapien et, dapibus felis. Aenean in dignissim leo. Sed semper, ex at euismod molestie, ex "
"odio ullamcorper nisi, et facilisis lectus eros non magna. In hac habitasse platea dictumst. Pellentesque sed "
"maximus mauris. Cras luctus dapibus nunc, sit amet suscipit dui viverra nec. Donec gravida tortor porttitor orci "
"malesuada porttitor. Nunc condimentum eu libero sit amet varius. Curabitur mollis urna eu porta tincidunt. Nullam "
"ultricies magna libero, et dapibus tellus tempus eu. Nullam pretium lectus nec iaculis pretium. Maecenas at arcu "
"lobortis, ornare ante nec, euismod metus. Pellentesque volutpat tellus nulla. Aenean mattis efficitur velit vitae "
"blandit. Duis vel egestas eros. Pellentesque aliquam placerat elit, eu congue sem ullamcorper sit amet. Ut erat "
"nisl, luctus vitae pellentesque ut, tristique eu odio. Pellentesque nec fermentum ex, rhoncus varius dui. Mauris "
"lobortis nunc nec dui volutpat consequat. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur "
"ridiculus mus. Aliquam dignissim purus sed ligula pretium placerat. In vestibulum ultricies mauris. Curabitur "
"aliquet lorem quis libero auctor, ut rhoncus purus lobortis. Nulla elementum erat nec rhoncus posuere. Integer "
"faucibus quam sed elementum fringilla. In in lobortis sapien, nec commodo tortor. Aenean euismod ipsum nisi, vitae "
"fringilla leo imperdiet ut. Donec a semper odio, et tempor magna. Cras cursus vel augue quis egestas. Nam nec tortor "
"blandit, mattis quam imperdiet, finibus quam. Pellentesque tincidunt eros urna, ut tristique diam faucibus "
"condimentum. Ut dictum risus mi, non sollicitudin turpis facilisis sit amet. Morbi finibus scelerisque mattis. Fusce "
"vel tempor purus, nec pharetra augue. Curabitur dapibus, orci eu consectetur ultrices, diam mauris sodales urna, non "
"euismod diam lacus luctus risus. Mauris commodo accumsan sapien. Proin vel blandit sapien. Donec porta tortor vel "
"nibh faucibus molestie. Pellentesque placerat justo erat, vitae tristique felis fringilla eget. Quisque facilisis "
"justo at orci lobortis, ut commodo diam egestas. Etiam non tristique nisl. Cras varius, massa a sollicitudin ornare, "
"turpis arcu fringilla leo, non euismod ligula arcu id lacus. Suspendisse potenti. Morbi pharetra dolor eget porta "
"tristique. Nullam sem tortor, lobortis eget hendrerit a, efficitur sit amet sapien. Fusce sit amet condimentum odio, "
"aliquet rutrum velit. Morbi vel rhoncus ante. In blandit eros ut lectus varius, quis tempor arcu iaculis. In massa "
"leo, venenatis nec lobortis non, pulvinar non nunc. Nunc vehicula, erat vitae placerat eleifend, eros ipsum "
"consectetur odio, eu ornare velit mauris nec sapien. Integer a consequat libero. Quisque velit augue, blandit eu "
"luctus sit amet, laoreet sit amet odio. Etiam in enim lacus. Interdum et malesuada fames ac ante ipsum primis in "
"faucibus. In rutrum a tortor id pulvinar. Donec pretium lorem sed sem eleifend fringilla. Fusce sollicitudin ac "
"ligula eget pharetra. Sed cursus diam non sem ullamcorper efficitur. Vivamus congue ligula iaculis justo iaculis "
"elementum. Integer tempor nisl arcu, ut tincidunt erat vestibulum et. Suspendisse rutrum aliquet eros non "
"pellentesque. Mauris laoreet, diam id tincidunt faucibus, risus velit venenatis risus, in venenatis justo diam et "
"orci. Etiam pulvinar pulvinar nisi, id efficitur erat vulputate ut. Sed suscipit sodales ante, a blandit orci "
"maximus vel. Vestibulum at aliquet orci. Proin tincidunt nisi quis eros consequat consectetur. Praesent congue "
"lobortis laoreet. Donec imperdiet risus erat, eu volutpat justo posuere id. Fusce placerat sollicitudin eros vitae "
"tincidunt. Sed orci ante, ultricies sed dapibus vel, sagittis ac massa. Pellentesque vel mauris nec est hendrerit "
"posuere. Integer sagittis diam sed felis facilisis ultrices. Aliquam erat volutpat. Nulla pharetra justo in ipsum "
"dapibus, nec viverra nunc euismod. Nulla massa ante, euismod at interdum vel, dapibus ut ex. Etiam consequat mauris "
"a suscipit lobortis. Donec commodo convallis velit, eget commodo urna vulputate ac. Sed molestie vel dui ut feugiat. "
"Donec orci purus, placerat vitae egestas sed, sodales nec ex. Sed egestas turpis non malesuada semper. Donec et mi a "
"nisi volutpat sagittis. Suspendisse potenti. Phasellus mollis sapien ac tellus imperdiet tempus. Praesent nec sapien "
"sit amet ipsum interdum interdum non eget nunc. Aenean fringilla lorem a viverra rutrum. Donec at maximus nibh. "
"Phasellus facilisis justo sit amet metus pharetra sagittis. Quisque mollis metus laoreet ipsum tincidunt "
"sollicitudin. Maecenas sit amet dictum ligula. Fusce molestie iaculis dui, et gravida libero hendrerit in. Praesent "
"euismod libero metus, vitae rhoncus velit ultrices eget. Vestibulum ac massa bibendum, gravida dolor vel, dapibus "
"est. Etiam non elit varius, mollis purus eget, placerat velit. Nullam lectus dui, mattis at pulvinar eu, elementum "
"et lorem. Sed vel auctor orci, nec semper neque. Nullam cursus commodo quam, in ultricies tellus rhoncus vulputate. "
"Mauris dapibus ipsum ipsum, dapibus euismod purus pellentesque at. Nullam euismod lectus non risus consequat "
"vulputate. Quisque finibus a turpis eu convallis. Nam magna turpis, feugiat ut urna in, tempus facilisis elit. Duis "
"dignissim purus sagittis porttitor posuere. Suspendisse varius ligula at egestas scelerisque. Duis placerat sagittis "
"nisi, et molestie tortor posuere condimentum. Morbi hendrerit, ante ornare tempus finibus, ex ipsum laoreet dui, vel "
"ornare felis tortor sit amet metus. Vivamus laoreet placerat massa, non suscipit nisl faucibus eget. Vestibulum ante "
"ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Pellentesque orci lacus, vulputate cursus ex "
"eu, porta aliquam massa. Proin dolor massa, faucibus vel rhoncus et, venenatis a nisi. Vivamus venenatis enim mi. "
"Sed viverra augue vitae lectus lobortis vulputate. Phasellus ac ligula congue, sagittis est non, aliquet tortor. "
"Suspendisse faucibus euismod neque, ac congue felis. Curabitur maximus neque sit amet odio varius gravida. Proin "
"egestas nulla eget mi bibendum luctus. Ut non mollis mi. Quisque finibus, eros non lobortis interdum, diam nisi "
"faucibus diam, non imperdiet leo velit et dolor. Nam est massa, vehicula sed diam sed, laoreet convallis nisi. Donec "
"enim ligula, dignissim non sem ut, pulvinar cursus mi. In at dignissim nulla, ac fringilla neque. In hac habitasse "
"platea dictumst. Quisque luctus mattis orci, consequat egestas nisi. Vivamus et metus et quam porttitor elementum. "
"Suspendisse auctor mauris eu sollicitudin sagittis. Vivamus ac ante non augue iaculis consectetur quis quis dui. In "
"bibendum risus tristique ligula iaculis finibus. Phasellus non ante risus. Maecenas ac leo cursus, molestie purus "
"sed, tristique purus. Etiam sem nulla, aliquam nec laoreet nec, iaculis quis nulla. Maecenas id dui id neque "
"venenatis gravida. Etiam vestibulum felis at diam porta ultrices. Ut finibus tortor et augue ornare, et efficitur "
"purus scelerisque. Phasellus et ultricies arcu, vel lacinia lacus. Aenean tincidunt eleifend nunc, sit amet mattis "
"purus venenatis sit amet. Curabitur eleifend sem nisl, et feugiat diam pharetra sit amet. Mauris ullamcorper mi vel "
"condimentum egestas. Nulla pulvinar purus vel sagittis posuere. Nulla quis enim bibendum, iaculis quam in, tincidunt "
"quam. Vestibulum rhoncus volutpat risus. Nulla ultricies bibendum est non malesuada. Nunc porta erat est, a "
"tincidunt magna gravida vel. Maecenas sit amet aliquet odio. Vestibulum egestas, tortor scelerisque consectetur "
"pharetra, nisi tellus feugiat justo, et bibendum libero mi in diam. Aliquam tempus sapien nec tristique convallis. "
"Nullam congue, lacus quis bibendum dignissim, nisl purus molestie dolor, a tempor dolor nibh pretium tellus. In hac "
"habitasse platea dictumst. Cras at est turpis. Nam nec lacus posuere, mattis mi eu, viverra ex. Nullam eleifend "
"ornare orci, vel tempor tellus. Ut nec eros eget tortor tempus tristique commodo sed lorem. Donec quis scelerisque "
"nibh, non tincidunt velit. Fusce in eleifend sapien. Nunc sodales sem ut nunc pellentesque, eget pharetra justo "
"tempor. Proin pretium velit et vehicula interdum. Maecenas luctus venenatis tincidunt. Donec hendrerit, ligula non "
"volutpat porta, dui ante facilisis massa, at congue orci mi sed quam. Donec lorem ipsum, malesuada quis purus in, "
"commodo malesuada justo. Etiam luctus, lorem vel rutrum tristique, mauris urna volutpat felis, a laoreet urna nunc "
"et neque. Morbi a diam tincidunt augue cursus commodo nec ut ligula. Maecenas ultrices purus fermentum ullamcorper "
"aliquet. Maecenas mi enim, semper nec metus at, posuere tristique ligula. Suspendisse est elit, porta quis massa id, "
"gravida commodo ante. Nullam maximus mauris sit amet dolor tempus posuere. Phasellus purus mi, interdum in ipsum "
"quis, tristique venenatis dolor. Suspendisse potenti. Phasellus odio erat, varius sed aliquet vestibulum, laoreet "
"sed mauris. Vivamus sapien erat, maximus tristique elementum ac, eleifend in enim. Morbi accumsan elementum neque, a "
"facilisis enim laoreet non. Donec auctor condimentum fringilla. Proin id urna nec tellus maximus maximus tincidunt "
"et libero. Integer ultricies venenatis odio, ut volutpat odio laoreet non. Donec in scelerisque justo. Integer "
"mauris libero, fringilla vel sapien sit amet, laoreet tincidunt dolor. Nam efficitur sagittis arcu, vel lobortis dui "
"gravida non. Curabitur lobortis feugiat finibus. Vestibulum dictum tortor nec magna fringilla blandit. Nulla "
"facilisi. Sed cursus laoreet neque vitae pulvinar. Ut iaculis euismod ullamcorper. Nunc in hendrerit lectus, sed "
"venenatis mi. Suspendisse et est dui. Sed elementum augue non ornare cursus. Quisque varius facilisis magna nec "
"laoreet. Suspendisse consequat, risus sed tempus egestas, velit felis faucibus erat, eu pharetra erat nisl sed "
"turpis. Sed ultricies ac quam id mollis. In consequat et erat vitae interdum. Pellentesque malesuada feugiat ligula "
"eu consectetur. Vestibulum tempor mi quis purus luctus dictum. Etiam condimentum ac ligula eget imperdiet. Ut "
"placerat, tortor eu lacinia imperdiet, enim nibh aliquam nibh, quis faucibus enim odio eu arcu. Nullam sagittis, "
"diam a ornare congue, ipsum eros scelerisque est, sit amet sagittis nisl tellus in felis. Nam eget ornare turpis. "
"Sed tempor ac enim a vestibulum. Pellentesque eleifend lacus non libero accumsan, ut consectetur sapien lacinia. "
"Etiam ut arcu non mi feugiat accumsan ut sit amet risus. Donec consequat eros sapien, malesuada imperdiet justo "
"bibendum sit amet. Nulla pretium varius lectus, in eleifend quam fringilla in. Quisque eu pretium velit. Sed eget "
"lectus sit amet tortor blandit tempus vel at sapien. Sed at velit porta, venenatis lorem sed, dapibus arcu. Donec "
"pellentesque tortor id massa interdum pretium. Praesent id diam quis nunc dictum finibus quis quis ipsum. Quisque "
"consectetur risus eu elit viverra, eget laoreet odio efficitur. In congue turpis iaculis ullamcorper bibendum. Duis "
"at elit et velit varius vulputate ut ac turpis. Nunc posuere, urna id lobortis ornare, neque ex ultricies erat, id "
"sollicitudin ante quam sed magna. Nunc ultrices quam erat, eget dictum libero sollicitudin in. Nulla facilisi. "
"Pellentesque eleifend risus non justo imperdiet aliquet. Donec finibus auctor ornare. Duis in arcu lacinia, "
"fermentum tellus vel, efficitur justo. Morbi nec nunc leo. Proin lacinia erat vel elementum dapibus. Proin diam "
"ipsum, mollis eu lobortis a, facilisis consectetur est. Vestibulum rutrum pellentesque urna, a laoreet justo dictum "
"vitae. Nullam dictum, mi elementum dictum interdum, sem nisl fermentum est, nec mattis enim ante aliquam tortor. "
"Phasellus eu quam magna. Vivamus augue enim, dictum in nibh non, condimentum tristique lorem. Suspendisse potenti. "
"Sed nibh lacus, auctor ut arcu sollicitudin, posuere tempor urna. Phasellus at odio euismod ipsum congue auctor. "
"Fusce vestibulum elementum nunc, vel feugiat nibh bibendum at. Quisque felis ligula, fermentum a metus ac, pulvinar "
"hendrerit est. Proin vitae tincidunt purus, vestibulum eleifend ipsum. Ut rhoncus et elit ut varius. Praesent eu "
"pharetra tellus. Suspendisse varius, dui quis efficitur fermentum, est lectus ultricies ex, a fermentum orci nunc eu "
"lorem. Integer aliquet nunc ullamcorper lacinia elementum. In cursus tortor nisi, ut pharetra tortor venenatis eu. "
"Duis tincidunt, libero sed varius dictum, neque velit facilisis enim, eget bibendum mi eros et nisl. Nam turpis "
"neque, lobortis eget ante ac, tristique congue lacus. Aenean dictum vitae tortor sed tristique. Donec sodales in "
"arcu ut tristique. Curabitur in facilisis nisi, non vulputate odio. Phasellus ut fringilla nunc, nec dapibus turpis. "
"Sed ut erat tempor sem vulputate gravida at at dui. Aenean id dolor ante. Morbi auctor interdum nisi, id pretium "
"eros ultrices vel. Nulla eget justo fringilla, finibus quam et, accumsan ex. In nisl neque, pharetra nec volutpat "
"at, mattis nec odio. Nam et sapien sed libero lacinia tempor sit amet vitae turpis. Praesent vel porta lacus, porta "
"dignissim nunc. Aenean vitae vulputate purus. Ut at elit arcu. Integer risus neque, varius ac elit maximus, "
"ultricies sagittis nisi. Pellentesque sapien magna, malesuada tincidunt ornare sed, malesuada tempor odio. Morbi id "
"neque velit. Pellentesque at velit sed elit eleifend auctor. Quisque tincidunt tempus justo, venenatis dapibus sem "
"pellentesque quis. Suspendisse finibus feugiat est id consectetur. Nulla commodo, massa auctor vulputate egestas, "
"arcu massa tincidunt leo, quis ullamcorper sapien augue in nibh. Pellentesque ultrices ligula tincidunt urna "
"fringilla, ac ultricies eros convallis. Ut nec massa diam. Maecenas justo nulla, dapibus id justo sollicitudin, "
"fermentum tempor dui. Vivamus laoreet auctor mi non venenatis. Nulla commodo libero ac ex volutpat tincidunt. Donec "
"vestibulum blandit purus bibendum laoreet. Morbi in porta orci. Nam commodo ex eget diam maximus cursus. Proin "
"bibendum quis felis eget euismod. Praesent neque neque, pulvinar eu sem non, gravida ornare tortor. Ut tortor nisi, "
"suscipit in lectus ac, volutpat pretium nisi. Nam rutrum nec dui quis vulputate. Duis in velit enim. Fusce porttitor "
"vitae nisi a tincidunt. Ut enim purus, venenatis ut purus ut, iaculis dignissim ex. Aliquam erat volutpat. "
"Suspendisse potenti. Maecenas ut malesuada elit. Maecenas tellus neque, pulvinar non metus ut, viverra finibus diam. "
"Sed ac porttitor dui. Fusce sit amet ligula metus. Integer id aliquet libero. Sed tempor nisl in porttitor "
"ultricies. Maecenas molestie orci sed sapien molestie interdum non id felis. Nullam sagittis elementum erat in "
"pretium. Nunc pellentesque, ex sit amet fringilla dignissim, augue quam dictum leo, eget tristique turpis mauris sed "
"metus. Praesent vel mauris risus. Etiam eleifend metus ut risus tempor, ac ultrices dolor dictum. Nulla sagittis non "
"urna vitae feugiat. In venenatis arcu vel finibus volutpat. Nam non bibendum magna, nec eleifend ex. Etiam sit amet "
"nisl euismod, mattis nisi quis, commodo nisl. Nunc eget mauris vulputate, cursus neque in, hendrerit ante. Cras non "
"nisl in nisl laoreet aliquam. Sed vestibulum, nunc vitae molestie varius, lectus justo vehicula est, nec placerat "
"ipsum lectus quis leo. Maecenas efficitur semper eros, sed pretium arcu blandit eu. Aliquam eget purus cursus, "
"sollicitudin augue quis, cursus purus. Maecenas sed finibus ligula. Curabitur at diam quis eros mollis semper. Nulla "
"commodo nisi libero, id feugiat nisl tincidunt bibendum. Mauris convallis tincidunt justo eu sodales. Quisque arcu "
"lacus, finibus sed hendrerit at, convallis ut diam. Nulla enim nulla, efficitur quis tincidunt et, pulvinar sit amet "
"enim. Aenean mattis urna id mauris maximus tincidunt. In hac habitasse platea dictumst. Morbi ornare porta congue. "
"Aliquam hendrerit efficitur mi at aliquet. Vivamus rutrum lectus vel turpis volutpat, consectetur congue sem "
"consectetur. Sed rhoncus elit sed orci tincidunt, ut condimentum diam ornare. Nulla facilisi. Ut placerat et massa "
"nec malesuada. Praesent dapibus condimentum augue, at imperdiet lacus facilisis sed. Praesent at metus nunc. Morbi "
"accumsan eros et turpis viverra, nec sagittis odio iaculis. Aenean rhoncus, nibh a consectetur sodales, massa lorem "
"commodo dui, sit amet consequat ex arcu eget augue. Praesent quis nibh urna. Cras eu congue ligula, in ultricies "
"ante. Etiam interdum, est tincidunt euismod sollicitudin, lectus felis mollis ex, pretium fringilla magna lorem non "
"libero. Fusce aliquam tellus eget sodales commodo. Sed sapien lectus, dapibus quis elit at, ultricies tincidunt "
"eros. Nulla suscipit orci sit amet aliquam pellentesque. Cras sed eleifend ligula, quis vehicula ligula. Integer "
"quis tortor in mauris dictum malesuada sed non turpis. Nulla faucibus quis arcu molestie vulputate. Proin fermentum "
"tellus feugiat, imperdiet mi sit amet, tempor sem. Mauris hendrerit augue a vulputate vulputate. Vivamus sagittis at "
"odio non venenatis. Nunc a molestie dolor. Nunc erat nisi, consequat et tristique in, blandit non tortor. Vivamus "
"euismod bibendum augue, ut aliquam lorem mattis quis. Duis laoreet odio at justo ultricies, nec scelerisque enim "
"euismod. Sed eu turpis a lorem cursus feugiat. Duis ultrices molestie nulla non pharetra. Morbi faucibus est auctor "
"faucibus placerat. Donec blandit quis ex ac pulvinar. Vestibulum a consequat quam. Fusce vitae facilisis ex. Etiam a "
"risus eu orci tincidunt interdum. Proin interdum eros nec nibh venenatis, sed luctus sapien tincidunt. In cursus, "
"ante nec dapibus bibendum, augue tortor venenatis felis, eu aliquam erat est vitae diam. Cras lacinia placerat quam, "
"eu finibus purus. Aenean et augue purus. Praesent efficitur ornare magna in cursus. Nunc quis tempor ante, ac "
"accumsan ligula. Nullam elit diam, tempus in sollicitudin at, fermentum tincidunt mi. Vestibulum accumsan, nisi at "
"rutrum scelerisque, justo mauris cursus nulla, finibus cursus nulla elit quis augue. Aliquam lacus ante, ullamcorper "
"quis varius vitae, ullamcorper eget magna. Phasellus mollis nisl eu nulla eleifend, non tempus tellus faucibus. "
"Curabitur molestie eros id eleifend accumsan. Suspendisse tristique sem ante, non blandit eros accumsan ac. Ut sit "
"amet ante justo. Nam condimentum felis quis urna sagittis hendrerit. Cras condimentum est ac massa aliquet finibus. "
"Donec faucibus malesuada fermentum. Aliquam malesuada augue vitae dolor rutrum pellentesque. Nullam vulputate "
"rhoncus porta. Quisque vulputate dignissim felis sit amet aliquet. Nam elementum odio velit, eget fringilla mi "
"dignissim at. Mauris mollis diam orci, vel porta risus tempor a. Nullam quis dolor volutpat, ornare est at, "
"fermentum urna. Fusce mollis nisl a augue condimentum, eu dictum dolor posuere. Mauris et egestas sem. Sed pretium "
"lectus laoreet velit feugiat luctus. Nullam sodales at augue vel semper. Pellentesque vehicula dictum augue, eget "
"tristique orci interdum a. Aenean non est eleifend, tristique urna sed, elementum nunc. Sed consectetur id lorem "
"quis mollis. Ut et blandit velit, et lobortis dolor. Quisque nec odio sed mi ullamcorper pellentesque. Ut vitae "
"eleifend nisi, vitae dapibus est. Vivamus ornare eleifend volutpat. Sed et tincidunt nisi. Praesent maximus risus a "
"bibendum consequat. Vestibulum quis ex vitae ante ultricies ultricies. Maecenas dictum tellus eget enim tincidunt "
"imperdiet. Quisque vel libero gravida, mollis erat id, placerat dolor. Etiam ante eros, bibendum vitae ultricies in, "
"rhoncus nec turpis. Pellentesque gravida nunc sit amet iaculis condimentum. Phasellus in ultricies libero, et "
"maximus justo. Donec ut ultrices elit. Interdum et malesuada fames ac ante ipsum primis in faucibus. Pellentesque "
"rhoncus, nunc at iaculis dictum, magna lectus rhoncus augue, vel aliquam sem mauris in metus. Morbi commodo purus "
"mi, ut faucibus dui luctus et. Suspendisse accumsan placerat tortor. Cras dignissim blandit leo, non tincidunt leo. "
"Nulla euismod turpis ac malesuada aliquam. Ut ultrices bibendum elit sed elementum. Donec auctor aliquam vehicula. "
"Mauris lacinia dignissim leo, ullamcorper egestas nibh rutrum eget. In semper sit amet libero eget ultricies. Proin "
"et imperdiet odio. In hac habitasse platea dictumst. In hac habitasse platea dictumst. Integer sed dolor quis tortor "
"pretium euismod at vel dolor. Donec aliquet et urna at porta. Vestibulum tincidunt eget sapien elementum mattis. "
"Proin lacinia faucibus orci, sed eleifend augue mollis et. Vestibulum ante ipsum primis in faucibus orci luctus et "
"ultrices posuere cubilia Curae; Cras pellentesque, dolor eget bibendum tincidunt, turpis ante pharetra tortor, quis "
"interdum tellus tellus sit amet nisl. Nulla convallis tempus egestas. Curabitur quis condimentum metus, eu placerat "
"metus. Nunc ligula nunc, posuere at iaculis nec, convallis id tellus. Curabitur pretium libero lorem, quis placerat "
"nunc fringilla interdum. Vestibulum et finibus ante. Duis quis nisi neque. Curabitur ornare lorem nec ex fringilla, "
"et porta massa consequat. Nulla malesuada turpis nec eleifend tincidunt. Praesent ultricies dolor vitae mauris "
"lacinia tempor. Sed blandit sapien a odio scelerisque consequat. Mauris non dictum eros. Vestibulum ante ipsum "
"primis in faucibus orci luctus et ultrices posuere cubilia Curae; Pellentesque habitant morbi tristique senectus et "
"netus et malesuada fames ac turpis egestas. In ut sollicitudin tellus. Suspendisse ultrices vitae erat non pharetra. "
"Nulla pellentesque at diam venenatis sollicitudin. Vestibulum sed finibus sapien. Curabitur a metus convallis, "
"euismod est id, iaculis nunc. Vestibulum laoreet ornare turpis. Integer rhoncus, felis nec fermentum suscipit, dui "
"lacus sagittis ligula, vitae vestibulum urna elit aliquam est. Sed sit amet mi tortor. Suspendisse a dapibus velit. "
"Cras eget imperdiet turpis. Maecenas at lorem condimentum, elementum augue mattis, rutrum purus. Duis imperdiet "
"pellentesque nunc, eu tristique lectus malesuada commodo. Vivamus aliquet congue eros ac dapibus. Nunc quis "
"porttitor odio. Nulla quis dui luctus, vestibulum enim malesuada, imperdiet elit. Donec facilisis mollis diam ut "
"posuere. Nulla facilisi. Duis nec magna lacus. Vestibulum consequat ut tortor ut ornare. Curabitur nec felis sit "
"amet dui finibus rutrum. Phasellus sit amet lectus nec nisl egestas posuere. Etiam nec euismod magna, vitae "
"ullamcorper enim. Vestibulum pretium cursus semper. Cras vel lorem ut urna molestie elementum. Mauris luctus vel "
"arcu quis egestas. Suspendisse potenti. Nullam viverra sollicitudin lacus luctus sodales. Maecenas eget diam cursus "
"quam tincidunt ultricies vitae nec lacus. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec urna "
"sapien, porta a efficitur vitae, imperdiet vel ligula. Nulla volutpat massa sit amet est aliquet, ut iaculis tellus "
"convallis. Sed justo tortor, sodales non nisi quis, laoreet commodo quam. Cras tempus purus a tempor malesuada. "
"Curabitur enim nibh, viverra in enim eget, viverra euismod nunc. Mauris nunc leo, faucibus blandit condimentum nec, "
"rutrum sit amet leo. Quisque nec tortor sed felis pretium imperdiet. Morbi lobortis, dolor nec lobortis maximus, "
"turpis justo aliquet massa, eget aliquet nunc mauris a lectus. Phasellus dignissim, est nec luctus consequat, ex "
"nisi euismod lacus, a viverra nulla eros et est. Suspendisse in egestas dolor. Etiam non placerat lorem. "
"Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Aliquam ut enim "
"tristique, porta nulla quis, placerat eros. Integer eget feugiat mi, ac condimentum felis. Fusce auctor ligula ut "
"est placerat efficitur. Nam hendrerit condimentum ante eget tincidunt. Phasellus vel convallis neque. Vivamus sit "
"amet elit eu enim iaculis scelerisque. Donec imperdiet lacus id magna luctus, vitae dapibus quam condimentum. Donec "
"laoreet vehicula tellus. Nullam nec neque at massa ultricies dignissim. Suspendisse potenti. Cras convallis nunc "
"urna, a tempor metus volutpat ut. Fusce viverra lorem vitae quam ullamcorper cursus. Mauris maximus et mi eget "
"tincidunt. Proin molestie suscipit felis at ultricies. Duis varius rhoncus metus vehicula bibendum. Aliquam "
"consequat non tellus at aliquam. Vivamus nec turpis facilisis, dapibus lacus in, congue tortor. Curabitur at "
"interdum mi, sed rhoncus nibh. Morbi facilisis purus laoreet, tincidunt justo sit amet, elementum lectus. Vestibulum "
"pellentesque sem lacus, in condimentum purus consequat at. Integer pharetra rhoncus aliquam. Duis nec sem ac elit "
"suscipit laoreet. Integer vel est commodo, feugiat sapien eget, cursus quam. Aenean elit leo, interdum a posuere "
"nec, laoreet eu magna. Nam sit amet felis faucibus, porttitor justo eget, commodo mi. Maecenas a eleifend nibh. "
"Donec ut ornare augue. Aliquam pellentesque aliquet eros in hendrerit. Nullam consectetur odio id lectus ullamcorper "
"facilisis. Donec pulvinar, magna non sollicitudin commodo, erat lacus egestas massa, a egestas nibh nulla ac lorem. "
"Maecenas at mi posuere, fringilla lectus sed, fringilla eros. Vivamus mattis at magna ac suscipit. Proin varius mi a "
"quam efficitur ullamcorper. Curabitur venenatis turpis lacus, vitae volutpat velit ultricies sed. Sed faucibus id "
"neque in consequat. Nulla imperdiet fermentum placerat. Donec rutrum libero ac lorem commodo pellentesque in tempor "
"augue. Maecenas sodales cursus ex, ac elementum felis consectetur vel. Cras ante nulla, porttitor nec ex non, "
"venenatis consectetur justo. Nam vitae enim eget augue euismod suscipit et in nulla. Morbi eu sollicitudin libero, "
"ut lobortis purus. Pellentesque sodales tempor diam, a luctus dui vehicula tempus. Cum sociis natoque penatibus et "
"magnis dis parturient montes, nascetur ridiculus mus. Vestibulum dignissim sagittis diam ac aliquam. Integer iaculis "
"ac est eu molestie. Vivamus convallis arcu nec rutrum molestie. Vestibulum mollis ipsum neque. Vestibulum "
"condimentum neque quis tellus elementum, in facilisis neque venenatis. Donec quis ultrices risus. Cras mattis felis "
"eget erat iaculis, id scelerisque mauris pharetra. Vivamus condimentum tempor ipsum, porta commodo erat dictum ut. "
"Fusce et ligula sed arcu tincidunt efficitur nec ut felis. Donec eu justo pellentesque, finibus diam quis, iaculis "
"erat. Fusce a tempus urna, at fermentum est. Sed pretium orci dapibus ante laoreet, a consequat erat scelerisque. "
"Etiam nisi tortor, vulputate quis sapien sit amet, lobortis blandit felis. Morbi urna purus, pellentesque quis orci "
"id, suscipit consequat velit. Donec vehicula ipsum felis. Donec at elit ipsum. Fusce purus sapien, convallis quis "
"faucibus et, tempus at dolor. Vivamus commodo sem ac congue imperdiet. Vivamus convallis eget est eu vulputate. "
"Aliquam vehicula augue ac urna imperdiet interdum. Praesent euismod arcu quis purus vestibulum, et placerat metus "
"hendrerit. Fusce semper lacus sit amet ligula scelerisque scelerisque. Vestibulum neque ex, aliquam non lorem a, "
"aliquam fringilla enim. Aenean consectetur vestibulum tortor. Donec et elit consectetur, tincidunt augue feugiat, "
"condimentum diam. In luctus tellus at massa euismod faucibus. Ut tempus dui hendrerit, vehicula ex ut, facilisis "
"lacus. Pellentesque bibendum enim auctor, vulputate justo vel, ultricies est. Praesent interdum turpis in convallis "
"luctus. Duis vel enim venenatis, mollis elit vitae, mattis velit. In eu posuere nibh. Duis a est est. Nam semper "
"tincidunt nulla id dignissim. Fusce consectetur maximus eros quis posuere. Sed efficitur, enim quis ultrices "
"eleifend, est diam commodo dui, nec euismod augue velit sit amet ante. Integer fringilla vehicula faucibus. "
"Curabitur non placerat turpis. Integer malesuada quam eget sapien tristique aliquet. In hac habitasse platea "
"dictumst. Cras dignissim mauris neque, in facilisis nulla pulvinar ac. Phasellus sagittis ligula non sem aliquet "
"iaculis. Integer interdum elit in dolor vehicula, non condimentum justo pretium. Aliquam eget feugiat tellus. "
"Suspendisse condimentum dui at erat elementum semper. Aliquam vitae cursus lorem. Ut vestibulum porttitor purus ut "
"dapibus. Curabitur posuere nunc quis nisi rhoncus, ac mollis enim eleifend. Aenean tristique at justo ut tempor. "
"Proin posuere condimentum arcu ac lobortis. Proin euismod posuere ipsum, nec dignissim velit eleifend gravida. "
"Quisque quis sem mi. Proin scelerisque consequat lectus nec sodales. Fusce id sapien a erat cursus sodales. Morbi ac "
"magna vitae lorem dictum luctus in et lacus. Morbi imperdiet mi interdum, molestie sem in, accumsan leo. Sed lacinia "
"enim et sem egestas, a pulvinar velit ullamcorper. Aenean laoreet, erat eu viverra dictum, eros odio venenatis mi, "
"tincidunt blandit odio mauris id augue. Donec pretium mauris nibh, ut eleifend velit auctor vitae. Morbi tincidunt "
"lacus id ullamcorper egestas. Proin vel porttitor purus, eu fermentum dui. Aliquam a interdum mi. Aliquam ut rhoncus "
"nibh. Morbi nulla libero, commodo quis eros eu, scelerisque gravida ligula. Aliquam sed arcu nunc. Sed egestas "
"hendrerit orci, nec rhoncus arcu fringilla quis. Pellentesque lobortis nulla arcu. Integer aliquam vel quam sed "
"tempor. Morbi viverra tempus risus vel convallis. Cras eget neque ex. Mauris porta, risus at rhoncus hendrerit, "
"libero metus pharetra sapien, quis viverra tortor nunc tincidunt magna. Aenean a tellus ullamcorper, convallis urna "
"quis, suscipit sem. Vivamus eu eleifend est. Duis venenatis metus eget ex consequat molestie. In ullamcorper a dolor "
"vitae feugiat. Morbi ultrices vestibulum venenatis. Phasellus luctus enim id aliquet pharetra. Aenean mauris felis, "
"finibus eu dolor at, tempor sodales diam. Sed nisl nibh, tincidunt quis fringilla vel, congue eu dui. Duis viverra "
"justo eu sem ultricies dignissim. Morbi et sollicitudin erat. Proin id porttitor odio, et sagittis ex. Aenean "
"laoreet leo sit amet risus vestibulum, mollis ultrices tortor porttitor. Sed vestibulum varius ligula quis accumsan. "
"Duis fermentum, dolor iaculis condimentum tincidunt, purus nunc bibendum nibh, ac sodales tortor odio non ante. Sed "
"leo mauris, consequat molestie quam eu, vulputate volutpat metus. Cras fringilla risus sed arcu consequat luctus. "
"Nam malesuada, turpis at luctus blandit, velit elit fringilla metus, eu mollis odio felis id tortor. Aliquam erat "
"tellus, pulvinar nec iaculis et, consequat sit amet diam. Sed vestibulum, leo ut vehicula suscipit, quam justo "
"maximus lectus, nec lobortis urna tortor nec nisi. Vestibulum eget ornare arcu, sed viverra turpis. Sed posuere "
"tellus iaculis, scelerisque dui id, convallis lectus. Aliquam sodales at mi consectetur dignissim. In fringilla, "
"urna id placerat mattis, diam magna commodo dui, at elementum arcu elit et libero. Duis venenatis vulputate nisl "
"congue pharetra. Fusce sapien velit, cursus a consectetur quis, auctor gravida sem. Maecenas malesuada metus quis "
"elit congue accumsan. Vivamus scelerisque euismod malesuada. Vestibulum purus metus, tempor eget faucibus a, cursus "
"eu arcu. Morbi dictum urna vitae velit pellentesque facilisis. Sed arcu est, tempor ac turpis sit amet, ultricies "
"venenatis augue. Nunc laoreet leo gravida facilisis dapibus. Aliquam convallis ullamcorper felis, sit amet tempor "
"libero euismod sit amet. Quisque leo augue, finibus et euismod non, venenatis sed libero. Cras pharetra rhoncus "
"odio, in pharetra lacus porttitor scelerisque. Maecenas eleifend felis vitae diam blandit viverra. Fusce at "
"ultricies arcu, pharetra finibus enim. Etiam pellentesque semper ligula, sed tincidunt purus. Sed fermentum metus "
"varius, aliquet libero eget, vehicula erat. Sed ac finibus metus. Pellentesque libero leo, semper et eros nec, "
"gravida condimentum urna. Cras nec turpis convallis, efficitur lacus at, ultricies ex. Fusce eu neque elementum leo "
"gravida semper. Duis sed tellus vitae magna fringilla maximus ac ut nisl. Integer id ligula ullamcorper, ultricies "
"quam sit amet, ullamcorper diam. Maecenas rhoncus nulla eu dui vulputate scelerisque. Vestibulum porttitor eget nibh "
"a mattis. Mauris tempus at urna blandit dignissim. Proin turpis leo, mattis ut turpis eget, aliquet tempor ante. "
"Nunc in mollis nunc, et interdum nisi. Cras tristique sollicitudin tortor sit amet ultrices. Proin rhoncus neque "
"urna. Maecenas bibendum, massa sit amet suscipit suscipit, justo tortor maximus dolor, posuere facilisis nisi tellus "
"elementum diam. Quisque id eros vel lectus malesuada tincidunt. Donec at orci ac ligula venenatis dignissim sit amet "
"nec purus. Sed eu neque finibus, tristique ex a, feugiat ante. Pellentesque tincidunt luctus mollis. Nullam blandit "
"faucibus gravida. Ut sit amet malesuada nibh, vel tincidunt ipsum. Donec suscipit lorem in dui luctus, viverra "
"imperdiet magna placerat. Pellentesque venenatis eros quis urna efficitur facilisis. Cras ligula magna, tempus "
"facilisis tincidunt at, varius quis lectus. Sed quam neque, facilisis vel facilisis vel, lobortis ac orci. Nullam "
"pretium interdum erat ac ultrices. Etiam enim mauris, vehicula nec rhoncus quis, volutpat vel erat. Morbi imperdiet "
"rhoncus rutrum. Nullam auctor condimentum diam nec faucibus. Etiam sit amet porta nulla, sit amet lobortis enim. "
"Aenean tincidunt condimentum accumsan. Vestibulum mollis diam risus, vitae ornare enim iaculis non. Nullam vitae "
"risus tristique, imperdiet augue ut, egestas dolor. Sed sit amet leo eu diam commodo vestibulum id in dolor. Vivamus "
"tristique molestie faucibus. Duis tempor porttitor turpis ac consectetur. Curabitur condimentum, ipsum eu dignissim "
"semper, ipsum erat pretium quam, ut maximus erat ligula eu felis. Sed viverra, mauris id tempus tempor, nisi leo "
"consectetur arcu, ac vulputate lorem mauris non sapien. Maecenas rhoncus magna mauris, in luctus nulla dapibus at. "
"Sed magna est, ultrices sit amet erat nec, dapibus lacinia massa. Morbi cursus ex in elit auctor egestas. Quisque id "
"placerat nibh, at mollis tortor. Proin fringilla sodales sapien, ac ullamcorper sem bibendum eget. Donec dui ligula, "
"viverra eget leo ac, tincidunt fringilla mauris. Quisque vel lectus eget metus feugiat laoreet. Morbi eget "
"vestibulum enim, ac ultricies lorem. Nam at mollis magna. Etiam vitae orci eu leo facilisis vestibulum. Ut sed "
"turpis ut nibh iaculis rhoncus. Phasellus sit amet risus pellentesque, gravida eros a, porta nibh. Suspendisse at "
"tincidunt ligula. Vivamus id libero diam. Morbi viverra ipsum turpis, in ullamcorper enim pellentesque nec. Sed "
"ultricies, lectus quis pellentesque sodales, arcu diam commodo massa, a vestibulum purus sapien eget risus. Duis "
"rhoncus in velit in dignissim. Aliquam sit amet metus in quam finibus cursus. Pellentesque eget aliquam justo. Fusce "
"imperdiet, tellus non venenatis facilisis, diam mi lobortis dolor, at consectetur est massa id elit. Vivamus ante "
"ex, faucibus et mollis eget, dignissim vel massa. Duis ultricies diam commodo purus facilisis pharetra. Curabitur "
"pretium massa sed enim vehicula, id vehicula neque vehicula. In quis lectus non mauris pulvinar fermentum. Aliquam "
"condimentum aliquet dui et congue. Maecenas quis augue eget leo gravida aliquet. Praesent sit amet fermentum odio, "
"ut placerat nulla. Curabitur sit amet iaculis erat, eu volutpat odio. Ut iaculis ex quis tempus commodo. "
"Pellentesque cursus eros at velit vulputate, id luctus massa pretium. Morbi ex dui, sodales id finibus id, aliquet a "
"justo. Maecenas semper leo eget dolor rutrum, at imperdiet nibh eleifend. Aliquam eget purus tortor. Cras rutrum "
"tortor massa, vel bibendum nunc aliquam vel. Nullam vestibulum, metus vel fermentum elementum, nulla sapien egestas "
"justo, ac feugiat ex justo nec eros. Donec sit amet nibh mollis, commodo quam sit amet, semper magna. In tortor "
"magna, elementum nec auctor sed, pellentesque at augue. Sed gravida arcu ac aliquet convallis. Nulla facilisi. Duis "
"nunc quam, gravida non interdum id, cursus ac leo. Suspendisse vel ipsum nisl. Aliquam at gravida libero. Maecenas "
"sit amet efficitur orci. Fusce id vehicula sapien. Proin euismod diam non laoreet ultricies. Nunc ullamcorper, nibh "
"id cursus vehicula, ex purus tempor urna, et euismod orci est sed elit. Duis ut blandit mauris. Ut blandit cursus "
"eros, sed laoreet nisl efficitur ac. Phasellus dui elit, fringilla sit amet cursus nec, pharetra quis odio. Ut ut "
"lorem sit amet sem dapibus accumsan. Aenean a laoreet dolor. Donec eu laoreet velit. Etiam id nisi vel nibh dapibus "
"congue a quis odio. Donec velit risus, semper quis porta non, elementum quis lorem. Interdum et malesuada fames ac "
"ante ipsum primis in faucibus. Nullam sit amet dolor magna. Maecenas quis sapien sit amet est pulvinar lobortis "
"efficitur cursus orci. Phasellus tristique mauris lorem, eu ultricies justo ornare condimentum. Integer urna enim, "
"lobortis id malesuada ut, mattis eget libero. Sed commodo tincidunt eleifend. Fusce sed velit ut dui pellentesque "
"pellentesque eget vel diam. Aenean nec turpis at tortor consectetur consectetur. Vestibulum ultrices elit at nisl "
"pellentesque molestie. Maecenas diam dolor, faucibus eget posuere ut, sodales ut eros. Nam vulputate mollis diam nec "
"gravida. Nam et ullamcorper diam. Aenean non nulla non lorem ullamcorper sagittis non quis erat. Pellentesque "
"habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. In hac habitasse platea dictumst. "
"Donec quis mauris ac nibh vestibulum eleifend placerat sed lacus. Suspendisse mi elit, viverra non velit ut, "
"tincidunt tempus felis. Fusce ullamcorper, arcu nec aliquet porttitor, odio lacus mollis mi, id malesuada tortor "
"velit aliquet turpis. Sed hendrerit felis nec faucibus ornare. Nulla ut metus eget augue malesuada posuere eget eu "
"tortor. Cras ultrices odio sit amet porttitor vehicula. Sed vulputate leo vitae justo viverra, nec volutpat eros "
"consectetur. Nunc nunc tellus, porta in arcu in, vulputate ultricies tellus. Fusce commodo efficitur lorem, sit amet "
"lacinia sapien sollicitudin at. Etiam aliquet non mi vitae ornare. Cras condimentum imperdiet elit eu dictum. Donec "
"sed enim sed massa tempor porta et sit amet felis. Nam interdum ornare sem, in tincidunt risus consectetur vel. Ut "
"convallis purus mauris, in consequat ligula ullamcorper ut. Quisque elit ipsum, accumsan eget ligula vitae, "
"sollicitudin luctus tellus. Nunc pretium turpis ligula, id dignissim lorem suscipit eu. Nulla facilisi. Sed lectus "
"odio, vehicula vel vulputate id, ultrices non ipsum. Donec arcu quam, consequat eget aliquet sit amet, ullamcorper "
"non nibh. Etiam finibus, mi id lobortis sagittis, leo leo lobortis lectus, sit amet aliquam dui odio sit amet massa. "
"Suspendisse iaculis urna ac lectus gravida, iaculis efficitur tellus hendrerit. Sed tellus enim, condimentum in "
"augue eget, sagittis ullamcorper sem. Suspendisse vitae aliquet libero. Aenean quis purus in sapien dapibus "
"suscipit. Sed commodo nunc in lacus bibendum, vel tincidunt ante ornare. Ut tristique luctus volutpat. Class aptent "
"taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Quisque a ultricies orci, eu porta "
"odio. Vivamus sapien arcu, ultrices vel dui ut, luctus viverra purus. Praesent fringilla sed odio quis pretium. "
"Vestibulum ullamcorper nisi tortor, id sollicitudin lectus tempor a. Ut malesuada sapien eu sapien posuere, non "
"euismod eros porta. Nunc vel tincidunt ligula. Cras dolor ante, tristique tempor metus quis, mollis vulputate orci. "
"Curabitur vitae nisl euismod, elementum purus vel, dictum lorem. Nunc eu mauris at metus porttitor dignissim ut eu "
"neque. In tempor rhoncus neque sit amet commodo. Maecenas sed lacus semper, tempus enim ac, fermentum lorem. Nullam "
"sollicitudin convallis turpis. Curabitur finibus placerat viverra. Pellentesque convallis condimentum tortor id "
"efficitur. Proin semper pretium est, et vehicula ex cursus a. Nam ut felis purus. Phasellus eget felis eget leo "
"dapibus vestibulum. Nulla eleifend malesuada turpis, quis faucibus eros. Nam aliquet euismod viverra. Ut quis semper "
"felis. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Pellentesque at nulla "
"arcu. Integer ut tellus ac sapien maximus tincidunt sed vitae risus. Nulla viverra, nibh eget eleifend aliquam, quam "
"quam tempor massa, eu semper ipsum lacus in turpis. Nulla sed purus enim. Nullam sed fermentum ipsum. Sed dui nisi, "
"elementum a auctor at, ultrices et nibh. Phasellus aliquam nulla ut lacinia accumsan. Phasellus sed arcu ligula. "
#ifndef _MSC_VER
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam fermentum magna vitae dui sagittis tempor. Vivamus "
"eu ligula blandit, imperdiet arcu at, rutrum sem. Aliquam erat volutpat. Quisque luctus enim quis volutpat lobortis. "
"Vestibulum eget sodales libero. Aenean at condimentum est. Proin eget massa vel nulla efficitur tempor eget at enim. "
"Integer enim sapien, ornare luctus nisl non, pretium facilisis ex. Donec pretium ligula ligula, a facilisis turpis "
"hendrerit at. Nullam eget malesuada justo, at molestie quam. Sed consequat massa eu faucibus maximus. Curabitur "
"placerat orci sapien, sit amet semper magna sodales non. Ut fermentum accumsan odio in consectetur. Morbi neque mi, "
"vulputate nec mi ut, cursus scelerisque lectus. Nulla sapien enim, finibus id ipsum luctus, consequat ullamcorper "
"lectus. Sed volutpat sed massa in sodales. Morbi lacinia diam eu commodo vulputate. Fusce aliquet pulvinar dolor in "
"egestas. Fusce molestie commodo leo eu ultricies. Nulla mollis rhoncus pharetra. Pellentesque rutrum mauris ac lorem "
"posuere, a eleifend mi rutrum. Nulla porta turpis aliquet felis congue rutrum. Fusce quis arcu in sem placerat "
"condimentum a ut turpis. Quisque quis porttitor nulla. Donec sit amet quam tincidunt, pulvinar erat id, molestie "
"dolor. Praesent luctus vitae nunc vitae pellentesque. Praesent faucibus sed urna ut lacinia. Vivamus id justo quis "
"dolor porta rutrum nec nec odio. Cras euismod tortor quis diam ultrices, eu mattis nisi consectetur. Fusce mattis "
"nisi vel condimentum molestie. Fusce fringilla ut nibh volutpat elementum. Mauris posuere consectetur leo a aliquet. "
"Donec quis sodales sapien. Maecenas ut felis tempus, eleifend mauris et, faucibus mi. Quisque fringilla orci arcu, "
"sit amet porta risus hendrerit non. Aenean id sem nisi. Nullam non nisl vestibulum, pellentesque nisl et, imperdiet "
"ligula. Sed laoreet fringilla felis. Proin ac dolor viverra tellus mollis aliquet eget et neque. Suspendisse mattis "
"nulla vitae nulla sagittis blandit. Sed at tortor rutrum, ornare magna nec, pellentesque nisi. Etiam non aliquet "
"tellus. Aliquam at ex suscipit, posuere sem sit amet, tincidunt."
#endif
;
/* clang-format on */
#endif /* __BLENDER_TESTING_BLI_RESSOURCE_STRING_H__ */

View File

@@ -1,20 +0,0 @@
/* Apache License, Version 2.0 */
#include "testing/testing.h"
#include "BLI_session_uuid.h"
TEST(SessionUUID, GenerateBasic)
{
{
const SessionUUID uuid = BLI_session_uuid_generate();
EXPECT_TRUE(BLI_session_uuid_is_generated(&uuid));
}
{
const SessionUUID uuid1 = BLI_session_uuid_generate();
const SessionUUID uuid2 = BLI_session_uuid_generate();
EXPECT_FALSE(BLI_session_uuid_is_equal(&uuid1, &uuid2));
}
}

View File

@@ -1,216 +0,0 @@
/* Apache License, Version 2.0 */
#include "testing/testing.h"
#include <string.h>
#include "BLI_array.h"
#include "BLI_stack.h"
#include "BLI_utildefines.h"
#define SIZE 1024
/* number of items per chunk. use a small value to expose bugs */
#define STACK_CHUNK_SIZE 8
/* Ensure block size is set to #STACK_NEW_EX_ARGS */
#define BLI_stack_new(esize, descr) BLI_stack_new_ex(esize, descr, esize *STACK_CHUNK_SIZE)
TEST(stack, Empty)
{
BLI_Stack *stack;
stack = BLI_stack_new(sizeof(int), __func__);
EXPECT_TRUE(BLI_stack_is_empty(stack));
EXPECT_EQ(BLI_stack_count(stack), 0);
BLI_stack_free(stack);
}
TEST(stack, One)
{
BLI_Stack *stack;
unsigned int in = -1, out = 1;
stack = BLI_stack_new(sizeof(in), __func__);
BLI_stack_push(stack, (void *)&in);
EXPECT_FALSE(BLI_stack_is_empty(stack));
EXPECT_EQ(BLI_stack_count(stack), 1);
BLI_stack_pop(stack, (void *)&out);
EXPECT_EQ(out, in);
EXPECT_TRUE(BLI_stack_is_empty(stack));
EXPECT_EQ(BLI_stack_count(stack), 0);
BLI_stack_free(stack);
}
TEST(stack, Range)
{
const int tot = SIZE;
BLI_Stack *stack;
int in, out;
stack = BLI_stack_new(sizeof(in), __func__);
for (in = 0; in < tot; in++) {
BLI_stack_push(stack, (void *)&in);
}
for (in = tot - 1; in >= 0; in--) {
EXPECT_FALSE(BLI_stack_is_empty(stack));
BLI_stack_pop(stack, (void *)&out);
EXPECT_EQ(out, in);
}
EXPECT_TRUE(BLI_stack_is_empty(stack));
BLI_stack_free(stack);
}
TEST(stack, String)
{
const int tot = SIZE;
int i;
BLI_Stack *stack;
char in[] = "hello world!";
char out[sizeof(in)];
stack = BLI_stack_new(sizeof(in), __func__);
for (i = 0; i < tot; i++) {
*((int *)in) = i;
BLI_stack_push(stack, (void *)in);
}
for (i = tot - 1; i >= 0; i--) {
EXPECT_FALSE(BLI_stack_is_empty(stack));
*((int *)in) = i;
BLI_stack_pop(stack, (void *)&out);
EXPECT_STREQ(in, out);
}
EXPECT_TRUE(BLI_stack_is_empty(stack));
BLI_stack_free(stack);
}
TEST(stack, Peek)
{
const int tot = SIZE;
int i;
BLI_Stack *stack;
const short in[] = {1, 10, 100, 1000};
stack = BLI_stack_new(sizeof(*in), __func__);
for (i = 0; i < tot; i++) {
BLI_stack_push(stack, &in[i % ARRAY_SIZE(in)]);
}
for (i = tot - 1; i >= 0; i--, BLI_stack_discard(stack)) {
short *ret = (short *)BLI_stack_peek(stack);
EXPECT_EQ(*ret, in[i % ARRAY_SIZE(in)]);
}
EXPECT_TRUE(BLI_stack_is_empty(stack));
BLI_stack_free(stack);
}
/* Check that clearing the stack leaves in it a correct state. */
TEST(stack, Clear)
{
const int tot_rerun = 4;
int rerun;
/* based on range test */
int tot = SIZE;
BLI_Stack *stack;
int in, out;
/* use a small chunk size to ensure we test */
stack = BLI_stack_new(sizeof(in), __func__);
for (rerun = 0; rerun < tot_rerun; rerun++) {
for (in = 0; in < tot; in++) {
BLI_stack_push(stack, (void *)&in);
}
BLI_stack_clear(stack);
EXPECT_TRUE(BLI_stack_is_empty(stack));
/* and again, this time check its valid */
for (in = 0; in < tot; in++) {
BLI_stack_push(stack, (void *)&in);
}
for (in = tot - 1; in >= 0; in--) {
EXPECT_FALSE(BLI_stack_is_empty(stack));
BLI_stack_pop(stack, (void *)&out);
EXPECT_EQ(out, in);
}
EXPECT_TRUE(BLI_stack_is_empty(stack));
/* without this, we wont test case when mixed free/used */
tot /= 2;
}
BLI_stack_free(stack);
}
TEST(stack, Reuse)
{
const int sizes[] = {3, 11, 81, 400, 999, 12, 1, 9721, 7, 99, 5, 0};
int sizes_test[ARRAY_SIZE(sizes)];
const int *s;
int out, i;
int sum, sum_test;
BLI_Stack *stack;
stack = BLI_stack_new(sizeof(i), __func__);
/* add a bunch of numbers, ensure we get same sum out */
sum = 0;
for (s = sizes; *s; s++) {
for (i = *s; i != 0; i--) {
BLI_stack_push(stack, (void *)&i);
sum += i;
}
}
sum_test = 0;
while (!BLI_stack_is_empty(stack)) {
BLI_stack_pop(stack, (void *)&out);
sum_test += out;
}
EXPECT_EQ(sum, sum_test);
/* add and remove all except last */
for (s = sizes; *s; s++) {
for (i = *s; i >= 0; i--) {
BLI_stack_push(stack, (void *)&i);
}
for (i = *s; i > 0; i--) {
BLI_stack_pop(stack, (void *)&out);
}
}
i = ARRAY_SIZE(sizes) - 1;
while (!BLI_stack_is_empty(stack)) {
i--;
BLI_stack_pop(stack, (void *)&sizes_test[i]);
EXPECT_EQ(sizes_test[i], sizes[i]);
EXPECT_GT(i, -1);
}
EXPECT_EQ(0, i);
EXPECT_EQ(memcmp(sizes, sizes_test, sizeof(sizes) - sizeof(int)), 0);
/* finally test BLI_stack_pop_n */
for (i = ARRAY_SIZE(sizes); i--;) {
BLI_stack_push(stack, (void *)&sizes[i]);
}
EXPECT_EQ(BLI_stack_count(stack), ARRAY_SIZE(sizes));
BLI_stack_pop_n(stack, (void *)sizes_test, ARRAY_SIZE(sizes));
EXPECT_EQ(memcmp(sizes, sizes_test, sizeof(sizes) - sizeof(int)), 0);
BLI_stack_free(stack);
}

View File

@@ -1,813 +0,0 @@
/* Apache License, Version 2.0 */
#include "testing/testing.h"
#include <array>
#include <initializer_list>
#include <ostream> // NOLINT
#include <string>
#include <utility>
#include <vector>
#include "BLI_string.h"
#include "BLI_string_utf8.h"
#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
using std::initializer_list;
using std::pair;
using std::string;
using std::vector;
/* -------------------------------------------------------------------- */
/* stubs */
extern "C" {
int mk_wcwidth(wchar_t ucs);
int mk_wcswidth(const wchar_t *pwcs, size_t n);
int mk_wcwidth(wchar_t ucs)
{
return 0;
}
int mk_wcswidth(const wchar_t *pwcs, size_t n)
{
return 0;
}
}
/* -------------------------------------------------------------------- */
/* tests */
/* BLI_str_partition */
TEST(string, StrPartition)
{
const char delim[] = {'-', '.', '_', '~', '\\', '\0'};
const char *sep, *suf;
size_t pre_ln;
{
const char *str = "mat.e-r_ial";
/* "mat.e-r_ial" -> "mat", '.', "e-r_ial", 3 */
pre_ln = BLI_str_partition(str, delim, &sep, &suf);
EXPECT_EQ(pre_ln, 3);
EXPECT_EQ(&str[3], sep);
EXPECT_STREQ("e-r_ial", suf);
}
/* Corner cases. */
{
const char *str = ".mate-rial--";
/* ".mate-rial--" -> "", '.', "mate-rial--", 0 */
pre_ln = BLI_str_partition(str, delim, &sep, &suf);
EXPECT_EQ(pre_ln, 0);
EXPECT_EQ(&str[0], sep);
EXPECT_STREQ("mate-rial--", suf);
}
{
const char *str = ".__.--_";
/* ".__.--_" -> "", '.', "__.--_", 0 */
pre_ln = BLI_str_partition(str, delim, &sep, &suf);
EXPECT_EQ(pre_ln, 0);
EXPECT_EQ(&str[0], sep);
EXPECT_STREQ("__.--_", suf);
}
{
const char *str = "";
/* "" -> "", NULL, NULL, 0 */
pre_ln = BLI_str_partition(str, delim, &sep, &suf);
EXPECT_EQ(pre_ln, 0);
EXPECT_EQ(sep, (void *)NULL);
EXPECT_EQ(suf, (void *)NULL);
}
{
const char *str = "material";
/* "material" -> "material", NULL, NULL, 8 */
pre_ln = BLI_str_partition(str, delim, &sep, &suf);
EXPECT_EQ(pre_ln, 8);
EXPECT_EQ(sep, (void *)NULL);
EXPECT_EQ(suf, (void *)NULL);
}
}
/* BLI_str_rpartition */
TEST(string, StrRPartition)
{
const char delim[] = {'-', '.', '_', '~', '\\', '\0'};
const char *sep, *suf;
size_t pre_ln;
{
const char *str = "mat.e-r_ial";
/* "mat.e-r_ial" -> "mat.e-r", '_', "ial", 7 */
pre_ln = BLI_str_rpartition(str, delim, &sep, &suf);
EXPECT_EQ(pre_ln, 7);
EXPECT_EQ(&str[7], sep);
EXPECT_STREQ("ial", suf);
}
/* Corner cases. */
{
const char *str = ".mate-rial--";
/* ".mate-rial--" -> ".mate-rial-", '-', "", 11 */
pre_ln = BLI_str_rpartition(str, delim, &sep, &suf);
EXPECT_EQ(pre_ln, 11);
EXPECT_EQ(&str[11], sep);
EXPECT_STREQ("", suf);
}
{
const char *str = ".__.--_";
/* ".__.--_" -> ".__.--", '_', "", 6 */
pre_ln = BLI_str_rpartition(str, delim, &sep, &suf);
EXPECT_EQ(pre_ln, 6);
EXPECT_EQ(&str[6], sep);
EXPECT_STREQ("", suf);
}
{
const char *str = "";
/* "" -> "", NULL, NULL, 0 */
pre_ln = BLI_str_rpartition(str, delim, &sep, &suf);
EXPECT_EQ(pre_ln, 0);
EXPECT_EQ(sep, (void *)NULL);
EXPECT_EQ(suf, (void *)NULL);
}
{
const char *str = "material";
/* "material" -> "material", NULL, NULL, 8 */
pre_ln = BLI_str_rpartition(str, delim, &sep, &suf);
EXPECT_EQ(pre_ln, 8);
EXPECT_EQ(sep, (void *)NULL);
EXPECT_EQ(suf, (void *)NULL);
}
}
/* BLI_str_partition_ex */
TEST(string, StrPartitionEx)
{
const char delim[] = {'-', '.', '_', '~', '\\', '\0'};
const char *sep, *suf;
size_t pre_ln;
/* Only considering 'from_right' cases here. */
{
const char *str = "mat.e-r_ia.l";
/* "mat.e-r_ia.l" over "mat.e-r" -> "mat.e", '.', "r_ia.l", 3 */
pre_ln = BLI_str_partition_ex(str, str + 6, delim, &sep, &suf, true);
EXPECT_EQ(pre_ln, 5);
EXPECT_EQ(&str[5], sep);
EXPECT_STREQ("r_ia.l", suf);
}
/* Corner cases. */
{
const char *str = "mate.rial";
/* "mate.rial" over "mate" -> "mate.rial", NULL, NULL, 4 */
pre_ln = BLI_str_partition_ex(str, str + 4, delim, &sep, &suf, true);
EXPECT_EQ(pre_ln, 4);
EXPECT_EQ(sep, (void *)NULL);
EXPECT_EQ(suf, (void *)NULL);
}
}
/* BLI_str_partition_utf8 */
TEST(string, StrPartitionUtf8)
{
const unsigned int delim[] = {'-', '.', '_', 0x00F1 /* n tilde */, 0x262F /* ying-yang */, '\0'};
const char *sep, *suf;
size_t pre_ln;
{
const char *str = "ma\xc3\xb1te-r\xe2\x98\xafial";
/* "ma\xc3\xb1te-r\xe2\x98\xafial" -> "ma", '\xc3\xb1', "te-r\xe2\x98\xafial", 2 */
pre_ln = BLI_str_partition_utf8(str, delim, &sep, &suf);
EXPECT_EQ(pre_ln, 2);
EXPECT_EQ(&str[2], sep);
EXPECT_STREQ("te-r\xe2\x98\xafial", suf);
}
/* Corner cases. */
{
const char *str = "\xe2\x98\xafmate-rial-\xc3\xb1";
/* "\xe2\x98\xafmate-rial-\xc3\xb1" -> "", '\xe2\x98\xaf', "mate-rial-\xc3\xb1", 0 */
pre_ln = BLI_str_partition_utf8(str, delim, &sep, &suf);
EXPECT_EQ(pre_ln, 0);
EXPECT_EQ(&str[0], sep);
EXPECT_STREQ("mate-rial-\xc3\xb1", suf);
}
{
const char *str = "\xe2\x98\xaf.\xc3\xb1_.--\xc3\xb1";
/* "\xe2\x98\xaf.\xc3\xb1_.--\xc3\xb1" -> "", '\xe2\x98\xaf', ".\xc3\xb1_.--\xc3\xb1", 0 */
pre_ln = BLI_str_partition_utf8(str, delim, &sep, &suf);
EXPECT_EQ(pre_ln, 0);
EXPECT_EQ(&str[0], sep);
EXPECT_STREQ(".\xc3\xb1_.--\xc3\xb1", suf);
}
{
const char *str = "";
/* "" -> "", NULL, NULL, 0 */
pre_ln = BLI_str_partition_utf8(str, delim, &sep, &suf);
EXPECT_EQ(pre_ln, 0);
EXPECT_EQ(sep, (void *)NULL);
EXPECT_EQ(suf, (void *)NULL);
}
{
const char *str = "material";
/* "material" -> "material", NULL, NULL, 8 */
pre_ln = BLI_str_partition_utf8(str, delim, &sep, &suf);
EXPECT_EQ(pre_ln, 8);
EXPECT_EQ(sep, (void *)NULL);
EXPECT_EQ(suf, (void *)NULL);
}
}
/* BLI_str_rpartition_utf8 */
TEST(string, StrRPartitionUtf8)
{
const unsigned int delim[] = {'-', '.', '_', 0x00F1 /* n tilde */, 0x262F /* ying-yang */, '\0'};
const char *sep, *suf;
size_t pre_ln;
{
const char *str = "ma\xc3\xb1te-r\xe2\x98\xafial";
/* "ma\xc3\xb1te-r\xe2\x98\xafial" -> "mat\xc3\xb1te-r", '\xe2\x98\xaf', "ial", 8 */
pre_ln = BLI_str_rpartition_utf8(str, delim, &sep, &suf);
EXPECT_EQ(pre_ln, 8);
EXPECT_EQ(&str[8], sep);
EXPECT_STREQ("ial", suf);
}
/* Corner cases. */
{
const char *str = "\xe2\x98\xafmate-rial-\xc3\xb1";
/* "\xe2\x98\xafmate-rial-\xc3\xb1" -> "\xe2\x98\xafmate-rial-", '\xc3\xb1', "", 13 */
pre_ln = BLI_str_rpartition_utf8(str, delim, &sep, &suf);
EXPECT_EQ(pre_ln, 13);
EXPECT_EQ(&str[13], sep);
EXPECT_STREQ("", suf);
}
{
const char *str = "\xe2\x98\xaf.\xc3\xb1_.--\xc3\xb1";
/* "\xe2\x98\xaf.\xc3\xb1_.--\xc3\xb1" -> "\xe2\x98\xaf.\xc3\xb1_.--", '\xc3\xb1', "", 10 */
pre_ln = BLI_str_rpartition_utf8(str, delim, &sep, &suf);
EXPECT_EQ(pre_ln, 10);
EXPECT_EQ(&str[10], sep);
EXPECT_STREQ("", suf);
}
{
const char *str = "";
/* "" -> "", NULL, NULL, 0 */
pre_ln = BLI_str_rpartition_utf8(str, delim, &sep, &suf);
EXPECT_EQ(pre_ln, 0);
EXPECT_EQ(sep, (void *)NULL);
EXPECT_EQ(suf, (void *)NULL);
}
{
const char *str = "material";
/* "material" -> "material", NULL, NULL, 8 */
pre_ln = BLI_str_rpartition_utf8(str, delim, &sep, &suf);
EXPECT_EQ(pre_ln, 8);
EXPECT_EQ(sep, (void *)NULL);
EXPECT_EQ(suf, (void *)NULL);
}
}
/* BLI_str_partition_ex_utf8 */
TEST(string, StrPartitionExUtf8)
{
const unsigned int delim[] = {'-', '.', '_', 0x00F1 /* n tilde */, 0x262F /* ying-yang */, '\0'};
const char *sep, *suf;
size_t pre_ln;
/* Only considering 'from_right' cases here. */
{
const char *str = "ma\xc3\xb1te-r\xe2\x98\xafial";
/* "ma\xc3\xb1te-r\xe2\x98\xafial" over
* "ma\xc3\xb1te" -> "ma", '\xc3\xb1', "te-r\xe2\x98\xafial", 2 */
pre_ln = BLI_str_partition_ex_utf8(str, str + 6, delim, &sep, &suf, true);
EXPECT_EQ(pre_ln, 2);
EXPECT_EQ(&str[2], sep);
EXPECT_STREQ("te-r\xe2\x98\xafial", suf);
}
/* Corner cases. */
{
const char *str = "mate\xe2\x98\xafrial";
/* "mate\xe2\x98\xafrial" over "mate" -> "mate\xe2\x98\xafrial", NULL, NULL, 4 */
pre_ln = BLI_str_partition_ex_utf8(str, str + 4, delim, &sep, &suf, true);
EXPECT_EQ(pre_ln, 4);
EXPECT_EQ(sep, (void *)NULL);
EXPECT_EQ(suf, (void *)NULL);
}
}
/* BLI_str_format_int_grouped */
TEST(string, StrFormatIntGrouped)
{
char num_str[16];
int num;
BLI_str_format_int_grouped(num_str, num = 0);
EXPECT_STREQ("0", num_str);
BLI_str_format_int_grouped(num_str, num = 1);
EXPECT_STREQ("1", num_str);
BLI_str_format_int_grouped(num_str, num = -1);
EXPECT_STREQ("-1", num_str);
BLI_str_format_int_grouped(num_str, num = -2147483648);
EXPECT_STREQ("-2,147,483,648", num_str);
BLI_str_format_int_grouped(num_str, num = 2147483647);
EXPECT_STREQ("2,147,483,647", num_str);
BLI_str_format_int_grouped(num_str, num = 1000);
EXPECT_STREQ("1,000", num_str);
BLI_str_format_int_grouped(num_str, num = -1000);
EXPECT_STREQ("-1,000", num_str);
BLI_str_format_int_grouped(num_str, num = 999);
EXPECT_STREQ("999", num_str);
BLI_str_format_int_grouped(num_str, num = -999);
EXPECT_STREQ("-999", num_str);
}
/* BLI_str_format_byte_unit */
TEST(string, StrFormatByteUnits)
{
char size_str[15];
long long int size;
/* Base 10 */
BLI_str_format_byte_unit(size_str, size = 0, true);
EXPECT_STREQ("0 B", size_str);
BLI_str_format_byte_unit(size_str, size = -0, true);
EXPECT_STREQ("0 B", size_str);
BLI_str_format_byte_unit(size_str, size = 1, true);
EXPECT_STREQ("1 B", size_str);
BLI_str_format_byte_unit(size_str, size = -1, true);
EXPECT_STREQ("-1 B", size_str);
BLI_str_format_byte_unit(size_str, size = 1000, true);
EXPECT_STREQ("1 KB", size_str);
BLI_str_format_byte_unit(size_str, size = -1000, true);
EXPECT_STREQ("-1 KB", size_str);
BLI_str_format_byte_unit(size_str, size = 1024, true);
EXPECT_STREQ("1 KB", size_str);
BLI_str_format_byte_unit(size_str, size = -1024, true);
EXPECT_STREQ("-1 KB", size_str);
/* LLONG_MAX - largest possible value */
BLI_str_format_byte_unit(size_str, size = 9223372036854775807, true);
EXPECT_STREQ("9223.372 PB", size_str);
BLI_str_format_byte_unit(size_str, size = -9223372036854775807, true);
EXPECT_STREQ("-9223.372 PB", size_str);
/* Base 2 */
BLI_str_format_byte_unit(size_str, size = 0, false);
EXPECT_STREQ("0 B", size_str);
BLI_str_format_byte_unit(size_str, size = -0, false);
EXPECT_STREQ("0 B", size_str);
BLI_str_format_byte_unit(size_str, size = 1, false);
EXPECT_STREQ("1 B", size_str);
BLI_str_format_byte_unit(size_str, size = -1, false);
EXPECT_STREQ("-1 B", size_str);
BLI_str_format_byte_unit(size_str, size = 1000, false);
EXPECT_STREQ("1000 B", size_str);
BLI_str_format_byte_unit(size_str, size = -1000, false);
EXPECT_STREQ("-1000 B", size_str);
BLI_str_format_byte_unit(size_str, size = 1024, false);
EXPECT_STREQ("1 KiB", size_str);
BLI_str_format_byte_unit(size_str, size = -1024, false);
EXPECT_STREQ("-1 KiB", size_str);
/* LLONG_MAX - largest possible value */
BLI_str_format_byte_unit(size_str, size = 9223372036854775807, false);
EXPECT_STREQ("8192.0 PiB", size_str);
BLI_str_format_byte_unit(size_str, size = -9223372036854775807, false);
EXPECT_STREQ("-8192.0 PiB", size_str);
/* Test maximum string length. */
BLI_str_format_byte_unit(size_str, size = -9223200000000000000, false);
EXPECT_STREQ("-8191.8472 PiB", size_str);
}
struct WordInfo {
WordInfo()
{
}
WordInfo(int start, int end) : start(start), end(end)
{
}
bool operator==(const WordInfo &other) const
{
return start == other.start && end == other.end;
}
int start, end;
};
static std::ostream &operator<<(std::ostream &os, const WordInfo &word_info)
{
os << "start: " << word_info.start << ", end: " << word_info.end;
return os;
}
class StringFindSplitWords : public testing::Test {
protected:
StringFindSplitWords()
{
}
/* If max_words is -1 it will be initialized from the number of expected
* words +1. This way there is no need to pass an explicit number of words,
* but is also making it possible to catch situation when too many words
* are being returned. */
void testStringFindSplitWords(const string &str,
const size_t max_length,
initializer_list<WordInfo> expected_words_info_init,
int max_words = -1)
{
const vector<WordInfo> expected_words_info = expected_words_info_init;
if (max_words != -1) {
CHECK_LE(max_words, expected_words_info.size() - 1);
}
/* Since number of word info is used here, this makes it so we allow one
* extra word to be collected from the input. This allows to catch possible
* issues with word splitting not doing a correct thing. */
const int effective_max_words = (max_words == -1) ? expected_words_info.size() : max_words;
/* One extra element for the {-1, -1}. */
vector<WordInfo> actual_word_info(effective_max_words + 1, WordInfo(-1, -1));
const int actual_word_num = BLI_string_find_split_words(
str.c_str(),
max_length,
' ',
reinterpret_cast<int(*)[2]>(actual_word_info.data()),
effective_max_words);
/* Schrink actual array to an actual number of words, so we can compare
* vectors as-is. */
EXPECT_LE(actual_word_num, actual_word_info.size() - 1);
actual_word_info.resize(actual_word_num + 1);
/* Perform actual comparison. */
EXPECT_EQ_VECTOR(actual_word_info, expected_words_info);
}
void testStringFindSplitWords(const string &str,
initializer_list<WordInfo> expected_words_info_init)
{
testStringFindSplitWords(str, str.length(), expected_words_info_init);
}
};
/* BLI_string_find_split_words */
TEST_F(StringFindSplitWords, Simple)
{
testStringFindSplitWords("t", {{0, 1}, {-1, -1}});
testStringFindSplitWords("test", {{0, 4}, {-1, -1}});
}
TEST_F(StringFindSplitWords, Triple)
{
testStringFindSplitWords("f t w", {{0, 1}, {2, 1}, {4, 1}, {-1, -1}});
testStringFindSplitWords("find three words", {{0, 4}, {5, 5}, {11, 5}, {-1, -1}});
}
TEST_F(StringFindSplitWords, Spacing)
{
testStringFindSplitWords("# ## ### ####", {{0, 1}, {2, 2}, {5, 3}, {9, 4}, {-1, -1}});
testStringFindSplitWords("# # # #", {{0, 1}, {3, 1}, {7, 1}, {12, 1}, {-1, -1}});
}
TEST_F(StringFindSplitWords, Trailing_Left)
{
testStringFindSplitWords(" t", {{3, 1}, {-1, -1}});
testStringFindSplitWords(" test", {{3, 4}, {-1, -1}});
}
TEST_F(StringFindSplitWords, Trailing_Right)
{
testStringFindSplitWords("t ", {{0, 1}, {-1, -1}});
testStringFindSplitWords("test ", {{0, 4}, {-1, -1}});
}
TEST_F(StringFindSplitWords, Trailing_LeftRight)
{
testStringFindSplitWords(" surrounding space test 123 ",
{{3, 11}, {15, 5}, {21, 4}, {28, 3}, {-1, -1}});
}
TEST_F(StringFindSplitWords, Blank)
{
testStringFindSplitWords("", {{-1, -1}});
}
TEST_F(StringFindSplitWords, Whitespace)
{
testStringFindSplitWords(" ", {{-1, -1}});
testStringFindSplitWords(" ", {{-1, -1}});
}
TEST_F(StringFindSplitWords, LimitWords)
{
const string words = "too many chars";
const int words_len = words.length();
testStringFindSplitWords(words, words_len, {{0, 3}, {4, 4}, {9, 5}, {-1, -1}}, 3);
testStringFindSplitWords(words, words_len, {{0, 3}, {4, 4}, {-1, -1}}, 2);
testStringFindSplitWords(words, words_len, {{0, 3}, {-1, -1}}, 1);
testStringFindSplitWords(words, words_len, {{-1, -1}}, 0);
}
TEST_F(StringFindSplitWords, LimitChars)
{
const string words = "too many chars";
const int words_len = words.length();
testStringFindSplitWords(words, words_len, {{0, 3}, {4, 4}, {9, 5}, {-1, -1}});
testStringFindSplitWords(words, words_len - 1, {{0, 3}, {4, 4}, {9, 4}, {-1, -1}});
testStringFindSplitWords(words, words_len - 5, {{0, 3}, {4, 4}, {-1, -1}});
testStringFindSplitWords(words, 1, {{0, 1}, {-1, -1}});
testStringFindSplitWords(words, 0, {{-1, -1}});
}
/* BLI_strncasestr */
TEST(string, StringStrncasestr)
{
const char *str_test0 = "search here";
const char *res;
res = BLI_strncasestr(str_test0, "", 0);
EXPECT_EQ(res, str_test0);
res = BLI_strncasestr(str_test0, " ", 1);
EXPECT_EQ(res, str_test0 + 6);
res = BLI_strncasestr(str_test0, "her", 3);
EXPECT_EQ(res, str_test0 + 7);
res = BLI_strncasestr(str_test0, "ARCh", 4);
EXPECT_EQ(res, str_test0 + 2);
res = BLI_strncasestr(str_test0, "earcq", 4);
EXPECT_EQ(res, str_test0 + 1);
res = BLI_strncasestr(str_test0, "not there", 9);
EXPECT_EQ(res, (void *)NULL);
}
/* BLI_string_is_decimal */
TEST(string, StrIsDecimal)
{
EXPECT_FALSE(BLI_string_is_decimal(""));
EXPECT_FALSE(BLI_string_is_decimal("je moeder"));
EXPECT_FALSE(BLI_string_is_decimal("je møder"));
EXPECT_FALSE(BLI_string_is_decimal("Agent 327"));
EXPECT_FALSE(BLI_string_is_decimal("Agent\000327"));
EXPECT_FALSE(BLI_string_is_decimal("\000327"));
EXPECT_FALSE(BLI_string_is_decimal("0x16"));
EXPECT_FALSE(BLI_string_is_decimal("16.4"));
EXPECT_FALSE(BLI_string_is_decimal("-1"));
EXPECT_TRUE(BLI_string_is_decimal("0"));
EXPECT_TRUE(BLI_string_is_decimal("1"));
EXPECT_TRUE(BLI_string_is_decimal("001"));
EXPECT_TRUE(BLI_string_is_decimal("11342908713948713498745980171334059871345098713405981734"));
}
/* BLI_strcasecmp_natural */
class StringCasecmpNatural : public testing::Test {
protected:
StringCasecmpNatural() = default;
using CompareWordsArray = vector<std::array<const char *, 2>>;
void testReturnsZeroForAll(const CompareWordsArray &items)
{
for (auto &item : items) {
int res = BLI_strcasecmp_natural(item[0], item[1]);
EXPECT_EQ(res, 0);
}
}
void testReturnsLessThanZeroForAll(const CompareWordsArray &items)
{
for (auto &item : items) {
int res = BLI_strcasecmp_natural(item[0], item[1]);
EXPECT_LT(res, 0);
}
}
void testReturnsMoreThanZeroForAll(const CompareWordsArray &items)
{
for (auto &item : items) {
int res = BLI_strcasecmp_natural(item[0], item[1]);
EXPECT_GT(res, 0);
}
}
CompareWordsArray copyWithSwappedWords(const CompareWordsArray &items)
{
CompareWordsArray ret_array;
/* E.g. {{"a", "b"}, {"ab", "cd"}} becomes {{"b", "a"}, {"cd", "ab"}} */
ret_array.reserve(items.size());
for (auto &item : items) {
ret_array.push_back({item[1], item[0]});
}
return ret_array;
}
};
TEST_F(StringCasecmpNatural, Empty)
{
const CompareWordsArray equal{
{"", ""},
};
const CompareWordsArray negative{
{"", "a"},
{"", "A"},
};
CompareWordsArray positive = copyWithSwappedWords(negative);
testReturnsZeroForAll(equal);
testReturnsLessThanZeroForAll(negative);
testReturnsMoreThanZeroForAll(positive);
}
TEST_F(StringCasecmpNatural, Whitespace)
{
const CompareWordsArray equal{
{" ", " "},
{" a", " a"},
{" a ", " a "},
};
const CompareWordsArray negative{
{"", " "},
{"", " a"},
{"", " a "},
{" ", " a"},
};
CompareWordsArray positive = copyWithSwappedWords(negative);
testReturnsZeroForAll(equal);
testReturnsLessThanZeroForAll(negative);
testReturnsMoreThanZeroForAll(positive);
}
TEST_F(StringCasecmpNatural, TextOnlyLowerCase)
{
const CompareWordsArray equal{
{"a", "a"},
{"aa", "aa"},
{"ab", "ab"},
{"ba", "ba"},
{"je møder", "je møder"},
};
const CompareWordsArray negative{
{"a", "b"},
{"a", "aa"},
{"a", "ab"},
{"aa", "b"},
{"je møda", "je møder"},
};
CompareWordsArray positive = copyWithSwappedWords(negative);
testReturnsZeroForAll(equal);
testReturnsLessThanZeroForAll(negative);
testReturnsMoreThanZeroForAll(positive);
}
TEST_F(StringCasecmpNatural, TextMixedCase)
{
const CompareWordsArray equal{
{"A", "A"},
{"AA", "AA"},
{"AB", "AB"},
{"Ab", "Ab"},
{"aB", "aB"},
};
const CompareWordsArray negative{
{"A", "a"},
{"A", "B"},
{"A", "b"},
{"a", "B"},
{"AA", "aA"},
{"AA", "aA"},
{"Ab", "ab"},
{"AB", "Ab"},
/* Different lengths */
{"A", "ab"},
{"Aa", "b"},
{"aA", "b"},
{"AA", "b"},
{"A", "Ab"},
{"A", "aB"},
{"Aa", "B"},
{"aA", "B"},
{"AA", "B"},
};
CompareWordsArray positive = copyWithSwappedWords(negative);
testReturnsZeroForAll(equal);
testReturnsLessThanZeroForAll(negative);
testReturnsMoreThanZeroForAll(positive);
}
TEST_F(StringCasecmpNatural, Period)
{
const CompareWordsArray equal{
{".", "."},
{". ", ". "},
{" .", " ."},
{" . ", " . "},
};
const CompareWordsArray negative{
{".", ". "},
{" .", " . "},
{"foo.bar", "foo 1.bar"},
};
CompareWordsArray positive = copyWithSwappedWords(negative);
testReturnsZeroForAll(equal);
testReturnsLessThanZeroForAll(negative);
testReturnsMoreThanZeroForAll(positive);
}
TEST_F(StringCasecmpNatural, OnlyNumbers)
{
const CompareWordsArray equal{
{"0", "0"},
{"0001", "0001"},
{"42", "42"},
{"0042", "0042"},
};
const CompareWordsArray negative{
/* If numeric values are equal, number of leading zeros is used as tiebreaker. */
{"1", "0001"},
{"01", "001"},
{"0042", "0043"},
{"0042", "43"},
};
const CompareWordsArray positive = copyWithSwappedWords(negative);
testReturnsZeroForAll(equal);
testReturnsLessThanZeroForAll(negative);
testReturnsMoreThanZeroForAll(positive);
}
TEST_F(StringCasecmpNatural, TextAndNumbers)
{
const CompareWordsArray equal{
{"00je møder1", "00je møder1"},
{".0 ", ".0 "},
{" 1.", " 1."},
{" .0 ", " .0 "},
};
const CompareWordsArray negative{
{"00je møder0", "00je møder1"},
{"05je møder0", "06je møder1"},
{"Cube", "Cube.001"},
{"Cube.001", "Cube.002"},
{"CUbe.001", "Cube.002"},
{"CUbe.002", "Cube.002"},
};
const CompareWordsArray positive = copyWithSwappedWords(negative);
testReturnsZeroForAll(equal);
testReturnsLessThanZeroForAll(negative);
testReturnsMoreThanZeroForAll(positive);
}

View File

@@ -1,305 +0,0 @@
/* Apache License, Version 2.0 */
#include "testing/testing.h"
#include "BLI_string.h"
#include "BLI_string_utf8.h"
#include "BLI_utildefines.h"
/* Note that 'common' utf-8 variants of string functions (like copy, etc.) are tested in
* BLI_string_test.cc However, tests below are specific utf-8 conformance ones, and since they eat
* quite their share of lines, they deserved their own file. */
/* -------------------------------------------------------------------- */
/* stubs */
extern "C" {
int mk_wcwidth(wchar_t ucs);
int mk_wcswidth(const wchar_t *pwcs, size_t n);
int mk_wcwidth(wchar_t ucs)
{
return 0;
}
int mk_wcswidth(const wchar_t *pwcs, size_t n)
{
return 0;
}
}
/* -------------------------------------------------------------------- */
/* tests */
/* Breaking strings is confusing here, prefer over-long lines. */
/* clang-format off */
/* Each test is made of a 79 bytes (80 with NULL char) string to test, expected string result after
* stripping invalid utf8 bytes, and a single-byte string encoded with expected number of errors.
*
* Based on utf-8 decoder stress-test (https://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt)
* by Markus Kuhn <http://www.cl.cam.ac.uk/~mgk25/> - 2015-08-28 - CC BY 4.0
*/
const char *utf8_invalid_tests[][3] = {
// 1 Some correct UTF-8 text
{"You should see the Greek word 'kosme': \"\xce\xba\xe1\xbd\xb9\xcf\x83\xce\xbc\xce\xb5\" |",
"You should see the Greek word 'kosme': \"\xce\xba\xe1\xbd\xb9\xcf\x83\xce\xbc\xce\xb5\" |", "\x00"},
// 2 Boundary condition test cases
// Note that those will pass for us, those are not erronéous unicode code points
// (asside from \x00, which is only valid as string terminator).
// 2.1 First possible sequence of a certain length
{"2.1.1 1 byte (U-00000000): \"\x00\" |",
"2.1.1 1 byte (U-00000000): \"\" |", "\x01"},
{"2.1.2 2 bytes (U-00000080): \"\xc2\x80\" |",
"2.1.2 2 bytes (U-00000080): \"\xc2\x80\" |", "\x00"},
{"2.1.3 3 bytes (U-00000800): \"\xe0\xa0\x80\" |",
"2.1.3 3 bytes (U-00000800): \"\xe0\xa0\x80\" |", "\x00"},
{"2.1.4 4 bytes (U-00010000): \"\xf0\x90\x80\x80\" |",
"2.1.4 4 bytes (U-00010000): \"\xf0\x90\x80\x80\" |", "\x00"},
{"2.1.5 5 bytes (U-00200000): \"\xf8\x88\x80\x80\x80\" |",
"2.1.5 5 bytes (U-00200000): \"\xf8\x88\x80\x80\x80\" |", "\x00"},
{"2.1.6 6 bytes (U-04000000): \"\xfc\x84\x80\x80\x80\x80\" |",
"2.1.6 6 bytes (U-04000000): \"\xfc\x84\x80\x80\x80\x80\" |", "\x00"},
// 2.2 Last possible sequence of a certain length
{"2.2.1 1 byte (U-0000007F): \"\x7f\" |",
"2.2.1 1 byte (U-0000007F): \"\x7f\" |", "\x00"},
{"2.2.2 2 bytes (U-000007FF): \"\xdf\xbf\" |",
"2.2.2 2 bytes (U-000007FF): \"\xdf\xbf\" |", "\x00"},
{"2.2.3 3 bytes (U-0000FFFF): \"\xef\xbf\xbf\" |",
"2.2.3 3 bytes (U-0000FFFF): \"\" |", "\x03"}, /* matches one of 5.3 sequences... */
{"2.2.4 4 bytes (U-001FFFFF): \"\xf7\xbf\xbf\xbf\" |",
"2.2.4 4 bytes (U-001FFFFF): \"\xf7\xbf\xbf\xbf\" |", "\x00"},
{"2.2.5 5 bytes (U-03FFFFFF): \"\xfb\xbf\xbf\xbf\xbf\" |",
"2.2.5 5 bytes (U-03FFFFFF): \"\xfb\xbf\xbf\xbf\xbf\" |", "\x00"},
{"2.2.6 6 bytes (U-7FFFFFFF): \"\xfd\xbf\xbf\xbf\xbf\xbf\" |",
"2.2.6 6 bytes (U-7FFFFFFF): \"\xfd\xbf\xbf\xbf\xbf\xbf\" |", "\x00"},
// 2.3 Other boundary conditions
{"2.3.1 U-0000D7FF = ed 9f bf = \"\xed\x9f\xbf\" |",
"2.3.1 U-0000D7FF = ed 9f bf = \"\xed\x9f\xbf\" |", "\x00"},
{"2.3.2 U-0000E000 = ee 80 80 = \"\xee\x80\x80\" |",
"2.3.2 U-0000E000 = ee 80 80 = \"\xee\x80\x80\" |", "\x00"},
{"2.3.3 U-0000FFFD = ef bf bd = \"\xef\xbf\xbd\" |",
"2.3.3 U-0000FFFD = ef bf bd = \"\xef\xbf\xbd\" |", "\x00"},
{"2.3.4 U-0010FFFF = f4 8f bf bf = \"\xf4\x8f\xbf\xbf\" |",
"2.3.4 U-0010FFFF = f4 8f bf bf = \"\xf4\x8f\xbf\xbf\" |", "\x00"},
{"2.3.5 U-00110000 = f4 90 80 80 = \"\xf4\x90\x80\x80\" |",
"2.3.5 U-00110000 = f4 90 80 80 = \"\xf4\x90\x80\x80\" |", "\x00"},
// 3 Malformed sequences
// 3.1 Unexpected continuation bytes
// Each unexpected continuation byte should be separately signaled as a malformed sequence of its own.
{"3.1.1 First continuation byte 0x80: \"\x80\" |",
"3.1.1 First continuation byte 0x80: \"\" |", "\x01"},
{"3.1.2 Last continuation byte 0xbf: \"\xbf\" |",
"3.1.2 Last continuation byte 0xbf: \"\" |", "\x01"},
{"3.1.3 2 continuation bytes: \"\x80\xbf\" |",
"3.1.3 2 continuation bytes: \"\" |", "\x02"},
{"3.1.4 3 continuation bytes: \"\x80\xbf\x80\" |",
"3.1.4 3 continuation bytes: \"\" |", "\x03"},
{"3.1.5 4 continuation bytes: \"\x80\xbf\x80\xbf\" |",
"3.1.5 4 continuation bytes: \"\" |", "\x04"},
{"3.1.6 5 continuation bytes: \"\x80\xbf\x80\xbf\x80\" |",
"3.1.6 5 continuation bytes: \"\" |", "\x05"},
{"3.1.7 6 continuation bytes: \"\x80\xbf\x80\xbf\x80\xbf\" |",
"3.1.7 6 continuation bytes: \"\" |", "\x06"},
{"3.1.8 7 continuation bytes: \"\x80\xbf\x80\xbf\x80\xbf\x80\" |",
"3.1.8 7 continuation bytes: \"\" |", "\x07"},
// 3.1.9 Sequence of all 64 possible continuation bytes (0x80-0xbf): |
{"3.1.9 \"\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
"\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
"\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
"\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\" |",
"3.1.9 \"\" |", "\x40"},
// 3.2 Lonely start characters
// 3.2.1 All 32 first bytes of 2-byte sequences (0xc0-0xdf), each followed by a space character:
{"3.2.1 \"\xc0 \xc1 \xc2 \xc3 \xc4 \xc5 \xc6 \xc7 \xc8 \xc9 \xca \xcb \xcc \xcd \xce \xcf "
"\xd0 \xd1 \xd2 \xd3 \xd4 \xd5 \xd6 \xd7 \xd8 \xd9 \xda \xdb \xdc \xdd \xde \xdf \" |",
"3.2.1 \" \" |", "\x20"},
// 3.2.2 All 16 first bytes of 3-byte sequences (0xe0-0xef), each followed by a space character:
{"3.2.2 \"\xe0 \xe1 \xe2 \xe3 \xe4 \xe5 \xe6 \xe7 \xe8 \xe9 \xea \xeb \xec \xed \xee \xef \" |",
"3.2.2 \" \" |", "\x10"},
// 3.2.3 All 8 first bytes of 4-byte sequences (0xf0-0xf7), each followed by a space character:
{"3.2.3 \"\xf0 \xf1 \xf2 \xf3 \xf4 \xf5 \xf6 \xf7 \" |",
"3.2.3 \" \" |", "\x08"},
// 3.2.4 All 4 first bytes of 5-byte sequences (0xf8-0xfb), each followed by a space character:
{"3.2.4 \"\xf8 \xf9 \xfa \xfb \" |",
"3.2.4 \" \" |", "\x04"},
// 3.2.5 All 2 first bytes of 6-byte sequences (0xfc-0xfd), each followed by a space character:
{"3.2.4 \"\xfc \xfd \" |",
"3.2.4 \" \" |", "\x02"},
// 3.3 Sequences with last continuation byte missing
// All bytes of an incomplete sequence should be signaled as a single malformed sequence,
// i.e., you should see only a single replacement character in each of the next 10 tests.
// (Characters as in section 2)
{"3.3.1 2-byte sequence with last byte missing (U+0000): \"\xc0\" |",
"3.3.1 2-byte sequence with last byte missing (U+0000): \"\" |", "\x01"},
{"3.3.2 3-byte sequence with last byte missing (U+0000): \"\xe0\x80\" |",
"3.3.2 3-byte sequence with last byte missing (U+0000): \"\" |", "\x02"},
{"3.3.3 4-byte sequence with last byte missing (U+0000): \"\xf0\x80\x80\" |",
"3.3.3 4-byte sequence with last byte missing (U+0000): \"\" |", "\x03"},
{"3.3.4 5-byte sequence with last byte missing (U+0000): \"\xf8\x80\x80\x80\" |",
"3.3.4 5-byte sequence with last byte missing (U+0000): \"\" |", "\x04"},
{"3.3.5 6-byte sequence with last byte missing (U+0000): \"\xfc\x80\x80\x80\x80\" |",
"3.3.5 6-byte sequence with last byte missing (U+0000): \"\" |", "\x05"},
{"3.3.6 2-byte sequence with last byte missing (U-000007FF): \"\xdf\" |",
"3.3.6 2-byte sequence with last byte missing (U-000007FF): \"\" |", "\x01"},
{"3.3.7 3-byte sequence with last byte missing (U-0000FFFF): \"\xef\xbf\" |",
"3.3.7 3-byte sequence with last byte missing (U-0000FFFF): \"\" |", "\x02"},
{"3.3.8 4-byte sequence with last byte missing (U-001FFFFF): \"\xf7\xbf\xbf\" |",
"3.3.8 4-byte sequence with last byte missing (U-001FFFFF): \"\" |", "\x03"},
{"3.3.9 5-byte sequence with last byte missing (U-03FFFFFF): \"\xfb\xbf\xbf\xbf\" |",
"3.3.9 5-byte sequence with last byte missing (U-03FFFFFF): \"\" |", "\x04"},
{"3.3.10 6-byte sequence with last byte missing (U-7FFFFFFF): \"\xfd\xbf\xbf\xbf\xbf\" |",
"3.3.10 6-byte sequence with last byte missing (U-7FFFFFFF): \"\" |", "\x05"},
// 3.4 Concatenation of incomplete sequences
// All the 10 sequences of 3.3 concatenated, you should see 10 malformed sequences being signaled:
{"3.4 \"\xc0\xe0\x80\xf0\x80\x80\xf8\x80\x80\x80\xfc\x80\x80\x80\x80"
"\xdf\xef\xbf\xf7\xbf\xbf\xfb\xbf\xbf\xbf\xfd\xbf\xbf\xbf\xbf\""
" |",
"3.4 \"\" |", "\x1e"},
// 3.5 Impossible bytes
// The following two bytes cannot appear in a correct UTF-8 string
{"3.5.1 fe = \"\xfe\" |",
"3.5.1 fe = \"\" |", "\x01"},
{"3.5.2 ff = \"\xff\" |",
"3.5.2 ff = \"\" |", "\x01"},
{"3.5.3 fe fe ff ff = \"\xfe\xfe\xff\xff\" |",
"3.5.3 fe fe ff ff = \"\" |", "\x04"},
// 4 Overlong sequences
// The following sequences are not malformed according to the letter of the Unicode 2.0 standard.
// However, they are longer then necessary and a correct UTF-8 encoder is not allowed to produce them.
// A "safe UTF-8 decoder" should reject them just like malformed sequences for two reasons:
// (1) It helps to debug applications if overlong sequences are not treated as valid representations
// of characters, because this helps to spot problems more quickly. (2) Overlong sequences provide
// alternative representations of characters, that could maliciously be used to bypass filters that check
// only for ASCII characters. For instance, a 2-byte encoded line feed (LF) would not be caught by a
// line counter that counts only 0x0a bytes, but it would still be processed as a line feed by an unsafe
// UTF-8 decoder later in the pipeline. From a security point of view, ASCII compatibility of UTF-8
// sequences means also, that ASCII characters are *only* allowed to be represented by ASCII bytes
// in the range 0x00-0x7f. To ensure this aspect of ASCII compatibility, use only "safe UTF-8 decoders"
// that reject overlong UTF-8 sequences for which a shorter encoding exists.
//
// 4.1 Examples of an overlong ASCII character
// With a safe UTF-8 decoder, all of the following five overlong representations of the ASCII character
// slash ("/") should be rejected like a malformed UTF-8 sequence, for instance by substituting it with
// a replacement character. If you see a slash below, you do not have a safe UTF-8 decoder!
{"4.1.1 U+002F = c0 af = \"\xc0\xaf\" |",
"4.1.1 U+002F = c0 af = \"\" |", "\x02"},
{"4.1.2 U+002F = e0 80 af = \"\xe0\x80\xaf\" |",
"4.1.2 U+002F = e0 80 af = \"\" |", "\x03"},
{"4.1.3 U+002F = f0 80 80 af = \"\xf0\x80\x80\xaf\" |",
"4.1.3 U+002F = f0 80 80 af = \"\" |", "\x04"},
{"4.1.4 U+002F = f8 80 80 80 af = \"\xf8\x80\x80\x80\xaf\" |",
"4.1.4 U+002F = f8 80 80 80 af = \"\" |", "\x05"},
{"4.1.5 U+002F = fc 80 80 80 80 af = \"\xfc\x80\x80\x80\x80\xaf\" |",
"4.1.5 U+002F = fc 80 80 80 80 af = \"\" |", "\x06"},
// 4.2 Maximum overlong sequences
// Below you see the highest Unicode value that is still resulting in an overlong sequence if represented
// with the given number of bytes. This is a boundary test for safe UTF-8 decoders. All five characters
// should be rejected like malformed UTF-8 sequences.
{"4.2.1 U-0000007F = c1 bf = \"\xc1\xbf\" |",
"4.2.1 U-0000007F = c1 bf = \"\" |", "\x02"},
{"4.2.2 U-000007FF = e0 9f bf = \"\xe0\x9f\xbf\" |",
"4.2.2 U-000007FF = e0 9f bf = \"\" |", "\x03"},
{"4.2.3 U-0000FFFF = f0 8f bf bf = \"\xf0\x8f\xbf\xbf\" |",
"4.2.3 U-0000FFFF = f0 8f bf bf = \"\" |", "\x04"},
{"4.2.4 U-001FFFFF = f8 87 bf bf bf = \"\xf8\x87\xbf\xbf\xbf\" |",
"4.2.4 U-001FFFFF = f8 87 bf bf bf = \"\" |", "\x05"},
{"4.2.5 U+0000 = fc 83 bf bf bf bf = \"\xfc\x83\xbf\xbf\xbf\xbf\" |",
"4.2.5 U+0000 = fc 83 bf bf bf bf = \"\" |", "\x06"},
// 4.3 Overlong representation of the NUL character
// The following five sequences should also be rejected like malformed UTF-8 sequences and should not be
// treated like the ASCII NUL character.
{"4.3.1 U+0000 = c0 80 = \"\xc0\x80\" |",
"4.3.1 U+0000 = c0 80 = \"\" |", "\x02"},
{"4.3.2 U+0000 = e0 80 80 = \"\xe0\x80\x80\" |",
"4.3.2 U+0000 = e0 80 80 = \"\" |", "\x03"},
{"4.3.3 U+0000 = f0 80 80 80 = \"\xf0\x80\x80\x80\" |",
"4.3.3 U+0000 = f0 80 80 80 = \"\" |", "\x04"},
{"4.3.4 U+0000 = f8 80 80 80 80 = \"\xf8\x80\x80\x80\x80\" |",
"4.3.4 U+0000 = f8 80 80 80 80 = \"\" |", "\x05"},
{"4.3.5 U+0000 = fc 80 80 80 80 80 = \"\xfc\x80\x80\x80\x80\x80\" |",
"4.3.5 U+0000 = fc 80 80 80 80 80 = \"\" |", "\x06"},
// 5 Illegal code positions
// The following UTF-8 sequences should be rejected like malformed sequences, because they never represent
// valid ISO 10646 characters and a UTF-8 decoder that accepts them might introduce security problems
// comparable to overlong UTF-8 sequences.
// 5.1 Single UTF-16 surrogates
{"5.1.1 U+D800 = ed a0 80 = \"\xed\xa0\x80\" |",
"5.1.1 U+D800 = ed a0 80 = \"\" |", "\x03"},
{"5.1.2 U+DB7F = ed ad bf = \"\xed\xad\xbf\" |",
"5.1.2 U+DB7F = ed ad bf = \"\" |", "\x03"},
{"5.1.3 U+DB80 = ed ae 80 = \"\xed\xae\x80\" |",
"5.1.3 U+DB80 = ed ae 80 = \"\" |", "\x03"},
{"5.1.4 U+DBFF = ed af bf = \"\xed\xaf\xbf\" |",
"5.1.4 U+DBFF = ed af bf = \"\" |", "\x03"},
{"5.1.5 U+DC00 = ed b0 80 = \"\xed\xb0\x80\" |",
"5.1.5 U+DC00 = ed b0 80 = \"\" |", "\x03"},
{"5.1.6 U+DF80 = ed be 80 = \"\xed\xbe\x80\" |",
"5.1.6 U+DF80 = ed be 80 = \"\" |", "\x03"},
{"5.1.7 U+DFFF = ed bf bf = \"\xed\xbf\xbf\" |",
"5.1.7 U+DFFF = ed bf bf = \"\" |", "\x03"},
// 5.2 Paired UTF-16 surrogates
{"5.2.1 U+D800 U+DC00 = ed a0 80 ed b0 80 = \"\xed\xa0\x80\xed\xb0\x80\" |",
"5.2.1 U+D800 U+DC00 = ed a0 80 ed b0 80 = \"\" |", "\x06"},
{"5.2.2 U+D800 U+DFFF = ed a0 80 ed bf bf = \"\xed\xa0\x80\xed\xbf\xbf\" |",
"5.2.2 U+D800 U+DFFF = ed a0 80 ed bf bf = \"\" |", "\x06"},
{"5.2.3 U+DB7F U+DC00 = ed ad bf ed b0 80 = \"\xed\xad\xbf\xed\xb0\x80\" |",
"5.2.3 U+DB7F U+DC00 = ed ad bf ed b0 80 = \"\" |", "\x06"},
{"5.2.4 U+DB7F U+DFFF = ed ad bf ed bf bf = \"\xed\xad\xbf\xed\xbf\xbf\" |",
"5.2.4 U+DB7F U+DFFF = ed ad bf ed bf bf = \"\" |", "\x06"},
{"5.2.5 U+DB80 U+DC00 = ed ae 80 ed b0 80 = \"\xed\xae\x80\xed\xb0\x80\" |",
"5.2.5 U+DB80 U+DC00 = ed ae 80 ed b0 80 = \"\" |", "\x06"},
{"5.2.6 U+DB80 U+DFFF = ed ae 80 ed bf bf = \"\xed\xae\x80\xed\xbf\xbf\" |",
"5.2.6 U+DB80 U+DFFF = ed ae 80 ed bf bf = \"\" |", "\x06"},
{"5.2.7 U+DBFF U+DC00 = ed af bf ed b0 80 = \"\xed\xaf\xbf\xed\xb0\x80\" |",
"5.2.7 U+DBFF U+DC00 = ed af bf ed b0 80 = \"\" |", "\x06"},
{"5.2.8 U+DBFF U+DFFF = ed af bf ed bf bf = \"\xed\xaf\xbf\xed\xbf\xbf\" |",
"5.2.8 U+DBFF U+DFFF = ed af bf ed bf bf = \"\" |", "\x06"},
// 5.3 Noncharacter code positions
// The following "noncharacters" are "reserved for internal use" by applications, and according to older versions
// of the Unicode Standard "should never be interchanged". Unicode Corrigendum #9 dropped the latter restriction.
// Nevertheless, their presence in incoming UTF-8 data can remain a potential security risk, depending
// on what use is made of these codes subsequently. Examples of such internal use:
// - Some file APIs with 16-bit characters may use the integer value -1 = U+FFFF to signal
// an end-of-file (EOF) or error condition.
// - In some UTF-16 receivers, code point U+FFFE might trigger a byte-swap operation
// (to convert between UTF-16LE and UTF-16BE).
// With such internal use of noncharacters, it may be desirable and safer to block those code points in
// UTF-8 decoders, as they should never occur legitimately in incoming UTF-8 data, and could trigger
// unsafe behavior in subsequent processing.
//
// Particularly problematic noncharacters in 16-bit applications:
{"5.3.1 U+FFFE = ef bf be = \"\xef\xbf\xbe\" |",
"5.3.1 U+FFFE = ef bf be = \"\" |", "\x03"},
{"5.3.2 U+FFFF = ef bf bf = \"\xef\xbf\xbf\" |",
"5.3.2 U+FFFF = ef bf bf = \"\" |", "\x03"},
/* Fo now, we ignore those, they do not seem to be crucial anyway... */
// 5.3.3 U+FDD0 .. U+FDEF
// 5.3.4 U+nFFFE U+nFFFF (for n = 1..10)
{NULL, NULL, NULL},
};
/* clang-format on */
/* BLI_utf8_invalid_strip (and indirectly, BLI_utf8_invalid_byte). */
TEST(string, Utf8InvalidBytes)
{
for (int i = 0; utf8_invalid_tests[i][0] != NULL; i++) {
const char *tst = utf8_invalid_tests[i][0];
const char *tst_stripped = utf8_invalid_tests[i][1];
const int num_errors = (int)utf8_invalid_tests[i][2][0];
char buff[80];
memcpy(buff, tst, sizeof(buff));
const int num_errors_found = BLI_utf8_invalid_strip(buff, sizeof(buff) - 1);
printf("[%02d] -> [%02d] \"%s\" -> \"%s\"\n", num_errors, num_errors_found, tst, buff);
EXPECT_EQ(num_errors_found, num_errors);
EXPECT_STREQ(buff, tst_stripped);
}
}

View File

@@ -1,188 +0,0 @@
/* Apache License, Version 2.0 */
#include "testing/testing.h"
#include "MEM_guardedalloc.h"
#include "BLI_task.h"
struct TaskData {
int value;
int store;
};
static void TaskData_increase_value(void *taskdata)
{
TaskData *data = (TaskData *)taskdata;
data->value += 1;
}
static void TaskData_decrease_value(void *taskdata)
{
TaskData *data = (TaskData *)taskdata;
data->value -= 1;
}
static void TaskData_multiply_by_two_value(void *taskdata)
{
TaskData *data = (TaskData *)taskdata;
data->value *= 2;
}
static void TaskData_multiply_by_two_store(void *taskdata)
{
TaskData *data = (TaskData *)taskdata;
data->store *= 2;
}
static void TaskData_store_value(void *taskdata)
{
TaskData *data = (TaskData *)taskdata;
data->store = data->value;
}
static void TaskData_square_value(void *taskdata)
{
TaskData *data = (TaskData *)taskdata;
data->value *= data->value;
}
/* Sequential Test for using `BLI_task_graph` */
TEST(task, GraphSequential)
{
TaskData data = {0};
TaskGraph *graph = BLI_task_graph_create();
/* 0 => 1 */
TaskNode *node_a = BLI_task_graph_node_create(graph, TaskData_increase_value, &data, NULL);
/* 1 => 2 */
TaskNode *node_b = BLI_task_graph_node_create(
graph, TaskData_multiply_by_two_value, &data, NULL);
/* 2 => 1 */
TaskNode *node_c = BLI_task_graph_node_create(graph, TaskData_decrease_value, &data, NULL);
/* 2 => 1 */
TaskNode *node_d = BLI_task_graph_node_create(graph, TaskData_square_value, &data, NULL);
/* 1 => 1 */
TaskNode *node_e = BLI_task_graph_node_create(graph, TaskData_increase_value, &data, NULL);
/* 1 => 2 */
const int expected_value = 2;
BLI_task_graph_edge_create(node_a, node_b);
BLI_task_graph_edge_create(node_b, node_c);
BLI_task_graph_edge_create(node_c, node_d);
BLI_task_graph_edge_create(node_d, node_e);
EXPECT_TRUE(BLI_task_graph_node_push_work(node_a));
BLI_task_graph_work_and_wait(graph);
EXPECT_EQ(expected_value, data.value);
BLI_task_graph_free(graph);
}
TEST(task, GraphStartAtAnyNode)
{
TaskData data = {4};
TaskGraph *graph = BLI_task_graph_create();
TaskNode *node_a = BLI_task_graph_node_create(graph, TaskData_increase_value, &data, NULL);
TaskNode *node_b = BLI_task_graph_node_create(
graph, TaskData_multiply_by_two_value, &data, NULL);
TaskNode *node_c = BLI_task_graph_node_create(graph, TaskData_decrease_value, &data, NULL);
TaskNode *node_d = BLI_task_graph_node_create(graph, TaskData_square_value, &data, NULL);
TaskNode *node_e = BLI_task_graph_node_create(graph, TaskData_increase_value, &data, NULL);
// ((4 - 1) * (4 - 1)) + 1
const int expected_value = 10;
BLI_task_graph_edge_create(node_a, node_b);
BLI_task_graph_edge_create(node_b, node_c);
BLI_task_graph_edge_create(node_c, node_d);
BLI_task_graph_edge_create(node_d, node_e);
EXPECT_TRUE(BLI_task_graph_node_push_work(node_c));
BLI_task_graph_work_and_wait(graph);
EXPECT_EQ(expected_value, data.value);
BLI_task_graph_free(graph);
}
TEST(task, GraphSplit)
{
TaskData data = {1};
TaskGraph *graph = BLI_task_graph_create();
TaskNode *node_a = BLI_task_graph_node_create(graph, TaskData_increase_value, &data, NULL);
TaskNode *node_b = BLI_task_graph_node_create(graph, TaskData_store_value, &data, NULL);
TaskNode *node_c = BLI_task_graph_node_create(graph, TaskData_increase_value, &data, NULL);
TaskNode *node_d = BLI_task_graph_node_create(
graph, TaskData_multiply_by_two_store, &data, NULL);
BLI_task_graph_edge_create(node_a, node_b);
BLI_task_graph_edge_create(node_b, node_c);
BLI_task_graph_edge_create(node_b, node_d);
EXPECT_TRUE(BLI_task_graph_node_push_work(node_a));
BLI_task_graph_work_and_wait(graph);
EXPECT_EQ(3, data.value);
EXPECT_EQ(4, data.store);
BLI_task_graph_free(graph);
}
TEST(task, GraphForest)
{
TaskData data1 = {1};
TaskData data2 = {3};
TaskGraph *graph = BLI_task_graph_create();
{
TaskNode *tree1_node_a = BLI_task_graph_node_create(
graph, TaskData_increase_value, &data1, NULL);
TaskNode *tree1_node_b = BLI_task_graph_node_create(graph, TaskData_store_value, &data1, NULL);
TaskNode *tree1_node_c = BLI_task_graph_node_create(
graph, TaskData_increase_value, &data1, NULL);
TaskNode *tree1_node_d = BLI_task_graph_node_create(
graph, TaskData_multiply_by_two_store, &data1, NULL);
BLI_task_graph_edge_create(tree1_node_a, tree1_node_b);
BLI_task_graph_edge_create(tree1_node_b, tree1_node_c);
BLI_task_graph_edge_create(tree1_node_b, tree1_node_d);
EXPECT_TRUE(BLI_task_graph_node_push_work(tree1_node_a));
}
{
TaskNode *tree2_node_a = BLI_task_graph_node_create(
graph, TaskData_increase_value, &data2, NULL);
TaskNode *tree2_node_b = BLI_task_graph_node_create(graph, TaskData_store_value, &data2, NULL);
TaskNode *tree2_node_c = BLI_task_graph_node_create(
graph, TaskData_increase_value, &data2, NULL);
TaskNode *tree2_node_d = BLI_task_graph_node_create(
graph, TaskData_multiply_by_two_store, &data2, NULL);
BLI_task_graph_edge_create(tree2_node_a, tree2_node_b);
BLI_task_graph_edge_create(tree2_node_b, tree2_node_c);
BLI_task_graph_edge_create(tree2_node_b, tree2_node_d);
EXPECT_TRUE(BLI_task_graph_node_push_work(tree2_node_a));
}
BLI_task_graph_work_and_wait(graph);
EXPECT_EQ(3, data1.value);
EXPECT_EQ(4, data1.store);
EXPECT_EQ(5, data2.value);
EXPECT_EQ(8, data2.store);
BLI_task_graph_free(graph);
}
TEST(task, GraphTaskData)
{
TaskData data = {0};
TaskGraph *graph = BLI_task_graph_create();
TaskNode *node_a = BLI_task_graph_node_create(
graph, TaskData_store_value, &data, TaskData_increase_value);
TaskNode *node_b = BLI_task_graph_node_create(graph, TaskData_store_value, &data, NULL);
BLI_task_graph_edge_create(node_a, node_b);
EXPECT_TRUE(BLI_task_graph_node_push_work(node_a));
BLI_task_graph_work_and_wait(graph);
EXPECT_EQ(0, data.value);
EXPECT_EQ(0, data.store);
BLI_task_graph_free(graph);
/* data should be freed once */
EXPECT_EQ(1, data.value);
EXPECT_EQ(0, data.store);
}

View File

@@ -1,210 +0,0 @@
/* Apache License, Version 2.0 */
#include "BLI_ressource_strings.h"
#include "testing/testing.h"
#include "atomic_ops.h"
#define GHASH_INTERNAL_API
#include "MEM_guardedalloc.h"
#include "BLI_utildefines.h"
#include "BLI_listbase.h"
#include "BLI_mempool.h"
#include "BLI_task.h"
#include "PIL_time.h"
#define NUM_RUN_AVERAGED 100
static uint gen_pseudo_random_number(uint num)
{
/* Note: this is taken from BLI_ghashutil_uinthash(), don't want to depend on external code that
* might change here... */
num += ~(num << 16);
num ^= (num >> 5);
num += (num << 3);
num ^= (num >> 13);
num += ~(num << 9);
num ^= (num >> 17);
/* Make final number in [65 - 16385] range. */
return ((num & 255) << 6) + 1;
}
/* *** Parallel iterations over double-linked list items. *** */
static void task_listbase_light_iter_func(void *UNUSED(userdata),
void *item,
int index,
const TaskParallelTLS *__restrict UNUSED(tls))
{
LinkData *data = (LinkData *)item;
data->data = POINTER_FROM_INT(POINTER_AS_INT(data->data) + index);
}
static void task_listbase_light_membarrier_iter_func(void *userdata,
void *item,
int index,
const TaskParallelTLS *__restrict UNUSED(tls))
{
LinkData *data = (LinkData *)item;
int *count = (int *)userdata;
data->data = POINTER_FROM_INT(POINTER_AS_INT(data->data) + index);
atomic_sub_and_fetch_uint32((uint32_t *)count, 1);
}
static void task_listbase_heavy_iter_func(void *UNUSED(userdata),
void *item,
int index,
const TaskParallelTLS *__restrict UNUSED(tls))
{
LinkData *data = (LinkData *)item;
/* 'Random' number of iterations. */
const uint num = gen_pseudo_random_number((uint)index);
for (uint i = 0; i < num; i++) {
data->data = POINTER_FROM_INT(POINTER_AS_INT(data->data) + ((i % 2) ? -index : index));
}
}
static void task_listbase_heavy_membarrier_iter_func(void *userdata,
void *item,
int index,
const TaskParallelTLS *__restrict UNUSED(tls))
{
LinkData *data = (LinkData *)item;
int *count = (int *)userdata;
/* 'Random' number of iterations. */
const uint num = gen_pseudo_random_number((uint)index);
for (uint i = 0; i < num; i++) {
data->data = POINTER_FROM_INT(POINTER_AS_INT(data->data) + ((i % 2) ? -index : index));
}
atomic_sub_and_fetch_uint32((uint32_t *)count, 1);
}
static void task_listbase_test_do(ListBase *list,
const int num_items,
int *num_items_tmp,
const char *id,
TaskParallelIteratorFunc func,
const bool use_threads,
const bool check_num_items_tmp)
{
TaskParallelSettings settings;
BLI_parallel_range_settings_defaults(&settings);
settings.use_threading = use_threads;
double averaged_timing = 0.0;
for (int i = 0; i < NUM_RUN_AVERAGED; i++) {
const double init_time = PIL_check_seconds_timer();
BLI_task_parallel_listbase(list, num_items_tmp, func, &settings);
averaged_timing += PIL_check_seconds_timer() - init_time;
/* Those checks should ensure us all items of the listbase were processed once, and only once -
* as expected. */
if (check_num_items_tmp) {
EXPECT_EQ(*num_items_tmp, 0);
}
LinkData *item;
int j;
for (j = 0, item = (LinkData *)list->first; j < num_items && item != NULL;
j++, item = item->next) {
EXPECT_EQ(POINTER_AS_INT(item->data), j);
item->data = POINTER_FROM_INT(0);
}
EXPECT_EQ(num_items, j);
*num_items_tmp = num_items;
}
printf("\t%s: done in %fs on average over %d runs\n",
id,
averaged_timing / NUM_RUN_AVERAGED,
NUM_RUN_AVERAGED);
}
static void task_listbase_test(const char *id, const int nbr, const bool use_threads)
{
printf("\n========== STARTING %s ==========\n", id);
ListBase list = {NULL, NULL};
LinkData *items_buffer = (LinkData *)MEM_calloc_arrayN(nbr, sizeof(*items_buffer), __func__);
BLI_threadapi_init();
int num_items = 0;
for (int i = 0; i < nbr; i++) {
BLI_addtail(&list, &items_buffer[i]);
num_items++;
}
int num_items_tmp = num_items;
task_listbase_test_do(&list,
num_items,
&num_items_tmp,
"Light iter",
task_listbase_light_iter_func,
use_threads,
false);
task_listbase_test_do(&list,
num_items,
&num_items_tmp,
"Light iter with mem barrier",
task_listbase_light_membarrier_iter_func,
use_threads,
true);
task_listbase_test_do(&list,
num_items,
&num_items_tmp,
"Heavy iter",
task_listbase_heavy_iter_func,
use_threads,
false);
task_listbase_test_do(&list,
num_items,
&num_items_tmp,
"Heavy iter with mem barrier",
task_listbase_heavy_membarrier_iter_func,
use_threads,
true);
MEM_freeN(items_buffer);
BLI_threadapi_exit();
printf("========== ENDED %s ==========\n\n", id);
}
TEST(task, ListBaseIterNoThread10k)
{
task_listbase_test("ListBase parallel iteration - Single thread - 10000 items", 10000, false);
}
TEST(task, ListBaseIter10k)
{
task_listbase_test("ListBase parallel iteration - Threaded - 10000 items", 10000, true);
}
TEST(task, ListBaseIterNoThread100k)
{
task_listbase_test("ListBase parallel iteration - Single thread - 100000 items", 100000, false);
}
TEST(task, ListBaseIter100k)
{
task_listbase_test("ListBase parallel iteration - Threaded - 100000 items", 100000, true);
}

View File

@@ -1,183 +0,0 @@
/* Apache License, Version 2.0 */
#include "testing/testing.h"
#include <string.h>
#include "atomic_ops.h"
#include "MEM_guardedalloc.h"
#include "BLI_utildefines.h"
#include "BLI_listbase.h"
#include "BLI_mempool.h"
#include "BLI_task.h"
#define NUM_ITEMS 10000
/* *** Parallel iterations over range of integer values. *** */
static void task_range_iter_func(void *userdata, int index, const TaskParallelTLS *__restrict tls)
{
int *data = (int *)userdata;
data[index] = index;
*((int *)tls->userdata_chunk) += index;
// printf("%d, %d, %d\n", index, data[index], *((int *)tls->userdata_chunk));
}
static void task_range_iter_reduce_func(const void *__restrict UNUSED(userdata),
void *__restrict join_v,
void *__restrict userdata_chunk)
{
int *join = (int *)join_v;
int *chunk = (int *)userdata_chunk;
*join += *chunk;
// printf("%d, %d\n", data[NUM_ITEMS], *((int *)userdata_chunk));
}
TEST(task, RangeIter)
{
int data[NUM_ITEMS] = {0};
int sum = 0;
BLI_threadapi_init();
TaskParallelSettings settings;
BLI_parallel_range_settings_defaults(&settings);
settings.min_iter_per_thread = 1;
settings.userdata_chunk = &sum;
settings.userdata_chunk_size = sizeof(sum);
settings.func_reduce = task_range_iter_reduce_func;
BLI_task_parallel_range(0, NUM_ITEMS, data, task_range_iter_func, &settings);
/* Those checks should ensure us all items of the listbase were processed once, and only once
* as expected. */
int expected_sum = 0;
for (int i = 0; i < NUM_ITEMS; i++) {
EXPECT_EQ(data[i], i);
expected_sum += i;
}
EXPECT_EQ(sum, expected_sum);
BLI_threadapi_exit();
}
/* *** Parallel iterations over mempool items. *** */
static void task_mempool_iter_func(void *userdata, MempoolIterData *item)
{
int *data = (int *)item;
int *count = (int *)userdata;
EXPECT_TRUE(data != NULL);
*data += 1;
atomic_sub_and_fetch_uint32((uint32_t *)count, 1);
}
TEST(task, MempoolIter)
{
int *data[NUM_ITEMS];
BLI_threadapi_init();
BLI_mempool *mempool = BLI_mempool_create(
sizeof(*data[0]), NUM_ITEMS, 32, BLI_MEMPOOL_ALLOW_ITER);
int i;
/* 'Randomly' add and remove some items from mempool, to create a non-homogenous one. */
int num_items = 0;
for (i = 0; i < NUM_ITEMS; i++) {
data[i] = (int *)BLI_mempool_alloc(mempool);
*data[i] = i - 1;
num_items++;
}
for (i = 0; i < NUM_ITEMS; i += 3) {
BLI_mempool_free(mempool, data[i]);
data[i] = NULL;
num_items--;
}
for (i = 0; i < NUM_ITEMS; i += 7) {
if (data[i] == NULL) {
data[i] = (int *)BLI_mempool_alloc(mempool);
*data[i] = i - 1;
num_items++;
}
}
for (i = 0; i < NUM_ITEMS - 5; i += 23) {
for (int j = 0; j < 5; j++) {
if (data[i + j] != NULL) {
BLI_mempool_free(mempool, data[i + j]);
data[i + j] = NULL;
num_items--;
}
}
}
BLI_task_parallel_mempool(mempool, &num_items, task_mempool_iter_func, true);
/* Those checks should ensure us all items of the mempool were processed once, and only once - as
* expected. */
EXPECT_EQ(num_items, 0);
for (i = 0; i < NUM_ITEMS; i++) {
if (data[i] != NULL) {
EXPECT_EQ(*data[i], i);
}
}
BLI_mempool_destroy(mempool);
BLI_threadapi_exit();
}
/* *** Parallel iterations over double-linked list items. *** */
static void task_listbase_iter_func(void *userdata,
void *item,
int index,
const TaskParallelTLS *__restrict UNUSED(tls))
{
LinkData *data = (LinkData *)item;
int *count = (int *)userdata;
data->data = POINTER_FROM_INT(POINTER_AS_INT(data->data) + index);
atomic_sub_and_fetch_uint32((uint32_t *)count, 1);
}
TEST(task, ListBaseIter)
{
ListBase list = {NULL, NULL};
LinkData *items_buffer = (LinkData *)MEM_calloc_arrayN(
NUM_ITEMS, sizeof(*items_buffer), __func__);
BLI_threadapi_init();
int i;
int num_items = 0;
for (i = 0; i < NUM_ITEMS; i++) {
BLI_addtail(&list, &items_buffer[i]);
num_items++;
}
TaskParallelSettings settings;
BLI_parallel_range_settings_defaults(&settings);
BLI_task_parallel_listbase(&list, &num_items, task_listbase_iter_func, &settings);
/* Those checks should ensure us all items of the listbase were processed once, and only once -
* as expected. */
EXPECT_EQ(num_items, 0);
LinkData *item;
for (i = 0, item = (LinkData *)list.first; i < NUM_ITEMS && item != NULL;
i++, item = item->next) {
EXPECT_EQ(POINTER_AS_INT(item->data), i);
}
EXPECT_EQ(NUM_ITEMS, i);
MEM_freeN(items_buffer);
BLI_threadapi_exit();
}

View File

@@ -1,72 +0,0 @@
# ***** 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.
#
# The Original Code is Copyright (C) 2014, Blender Foundation
# All rights reserved.
# ***** END GPL LICENSE BLOCK *****
set(INC
.
..
../../../source/blender/blenlib
../../../source/blender/makesdna
../../../intern/guardedalloc
../../../intern/atomic
)
setup_libdirs()
include_directories(${INC})
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${PLATFORM_LINKFLAGS}")
set(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} ${PLATFORM_LINKFLAGS_DEBUG}")
if(WIN32)
set(BLI_path_util_extra_libs "bf_blenlib;bf_intern_utfconv;extern_wcwidth;${ZLIB_LIBRARIES}")
else()
set(BLI_path_util_extra_libs "bf_blenlib;extern_wcwidth;${ZLIB_LIBRARIES}")
endif()
BLENDER_TEST(BLI_array_store "bf_blenlib")
BLENDER_TEST(BLI_array_utils "bf_blenlib")
BLENDER_TEST(BLI_delaunay_2d "bf_blenlib")
BLENDER_TEST(BLI_expr_pylike_eval "bf_blenlib")
BLENDER_TEST(BLI_ghash "bf_blenlib")
BLENDER_TEST(BLI_hash_mm2a "bf_blenlib")
BLENDER_TEST(BLI_heap "bf_blenlib")
BLENDER_TEST(BLI_heap_simple "bf_blenlib")
BLENDER_TEST(BLI_kdopbvh "bf_blenlib;bf_intern_numaapi")
BLENDER_TEST(BLI_linklist_lockfree "bf_blenlib;bf_intern_numaapi")
BLENDER_TEST(BLI_listbase "bf_blenlib")
BLENDER_TEST(BLI_math_base "bf_blenlib")
BLENDER_TEST(BLI_math_bits "bf_blenlib")
BLENDER_TEST(BLI_math_color "bf_blenlib")
BLENDER_TEST(BLI_math_geom "bf_blenlib")
BLENDER_TEST(BLI_math_matrix "bf_blenlib")
BLENDER_TEST(BLI_math_vector "bf_blenlib")
BLENDER_TEST(BLI_memiter "bf_blenlib")
BLENDER_TEST(BLI_path_util "${BLI_path_util_extra_libs}")
BLENDER_TEST(BLI_polyfill_2d "bf_blenlib")
BLENDER_TEST(BLI_session_uuid "bf_blenlib")
BLENDER_TEST(BLI_stack "bf_blenlib")
BLENDER_TEST(BLI_string "bf_blenlib")
BLENDER_TEST(BLI_string_utf8 "bf_blenlib")
BLENDER_TEST(BLI_task "bf_blenlib;bf_intern_numaapi")
BLENDER_TEST(BLI_task_graph "bf_blenlib;bf_intern_numaapi")
BLENDER_TEST_PERFORMANCE(BLI_ghash_performance "bf_blenlib")
BLENDER_TEST_PERFORMANCE(BLI_task_performance "bf_blenlib")
unset(BLI_path_util_extra_libs)

View File

@@ -1,27 +0,0 @@
/* Apache License, Version 2.0 */
extern "C" {
void EIG_svd_square_matrix(
const int size, const float *matrix, float *r_U, float *r_S, float *r_V);
bool EIG_self_adjoint_eigen_solve(const int size,
const float *matrix,
float *r_eigen_values,
float *r_eigen_vectors);
bool EIG_self_adjoint_eigen_solve(const int size,
const float *matrix,
float *r_eigen_values,
float *r_eigen_vectors)
{
BLI_assert(0);
UNUSED_VARS(size, matrix, r_eigen_values, r_eigen_vectors);
return false;
}
void EIG_svd_square_matrix(const int size, const float *matrix, float *r_U, float *r_S, float *r_V)
{
BLI_assert(0);
UNUSED_VARS(size, matrix, r_U, r_S, r_V);
}
}

View File

@@ -1,92 +0,0 @@
# ***** 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.
#
# The Original Code is Copyright (C) 2019 by Blender Foundation.
# ***** END GPL LICENSE BLOCK *****
set(INC
.
..
../../../source/blender/blenkernel
../../../source/blender/blenlib
../../../source/blender/blenloader
../../../source/blender/depsgraph
../../../source/blender/imbuf
../../../source/blender/makesdna
../../../source/blender/makesrna
../../../source/blender/windowmanager
../../../intern/guardedalloc
${GLOG_INCLUDE_DIRS}
${GFLAGS_INCLUDE_DIRS}
../../../extern/gtest/include
)
set(SRC
blendfile_loading_base_test.cc
blendfile_loading_base_test.h
)
set(LIB
)
blender_add_lib(bf_blenloader_test "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
set(INC
.
..
../../../source/blender/blenlib
../../../source/blender/blenloader
../../../source/blender/blenkernel
../../../source/blender/makesdna
../../../source/blender/makesrna
../../../source/blender/depsgraph
../../../intern/guardedalloc
)
set(LIB
bf_blenloader_test
bf_blenloader
# Should not be needed but gives windows linker errors if the ocio libs are linked before this:
bf_intern_opencolorio
bf_gpu
)
include_directories(${INC})
setup_libdirs()
get_property(BLENDER_SORTED_LIBS GLOBAL PROPERTY BLENDER_SORTED_LIBS_PROP)
set(SRC
blendfile_load_test.cc
)
if(WITH_BUILDINFO)
list(APPEND SRC
"$<TARGET_OBJECTS:buildinfoobj>"
)
endif()
BLENDER_SRC_GTEST_EX(
NAME blenloader
SRC "${SRC}"
EXTRA_LIBS "${LIB}"
COMMAND_ARGS --test-assets-dir "${CMAKE_SOURCE_DIR}/../lib/tests")
unset(_buildinfo_src)
setup_liblinks(blenloader_test)

View File

@@ -1,31 +0,0 @@
/*
* 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.
*
* The Original Code is Copyright (C) 2019 by Blender Foundation.
*/
#include "blendfile_loading_base_test.h"
class BlendfileLoadingTest : public BlendfileLoadingBaseTest {
};
TEST_F(BlendfileLoadingTest, CanaryTest)
{
/* Load the smallest blend file we have in the SVN lib/tests directory. */
if (!blendfile_load("modifier_stack/array_test.blend")) {
return;
}
depsgraph_create(DAG_EVAL_RENDER);
EXPECT_NE(nullptr, this->depsgraph);
}

View File

@@ -1,162 +0,0 @@
/*
* 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.
*
* The Original Code is Copyright (C) 2019 by Blender Foundation.
*/
#include "blendfile_loading_base_test.h"
#include "MEM_guardedalloc.h"
#include "BKE_appdir.h"
#include "BKE_blender.h"
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_idtype.h"
#include "BKE_image.h"
#include "BKE_main.h"
#include "BKE_modifier.h"
#include "BKE_node.h"
#include "BKE_scene.h"
#include "BLI_path_util.h"
#include "BLI_threads.h"
#include "BLO_readfile.h"
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
#include "DNA_genfile.h" /* for DNA_sdna_current_init() */
#include "DNA_windowmanager_types.h"
#include "IMB_imbuf.h"
#include "RNA_define.h"
#include "WM_api.h"
#include "wm.h"
BlendfileLoadingBaseTest::~BlendfileLoadingBaseTest()
{
}
void BlendfileLoadingBaseTest::SetUpTestCase()
{
testing::Test::SetUpTestCase();
/* Minimal code to make loading a blendfile and constructing a depsgraph not crash, copied from
* main() in creator.c. */
BLI_threadapi_init();
DNA_sdna_current_init();
BKE_blender_globals_init();
BKE_idtype_init();
IMB_init();
BKE_images_init();
BKE_modifier_init();
DEG_register_node_types();
RNA_init();
init_nodesystem();
G.background = true;
G.factory_startup = true;
/* Allocate a dummy window manager. The real window manager will try and load Python scripts from
* the release directory, which it won't be able to find. */
ASSERT_EQ(G.main->wm.first, nullptr);
G.main->wm.first = MEM_callocN(sizeof(wmWindowManager), __func__);
}
void BlendfileLoadingBaseTest::TearDownTestCase()
{
if (G.main->wm.first != nullptr) {
MEM_freeN(G.main->wm.first);
G.main->wm.first = nullptr;
}
/* Copied from WM_exit_ex() in wm_init_exit.c, and cherry-picked those lines that match the
* allocation/initialization done in SetUpTestCase(). */
BKE_blender_free();
RNA_exit();
DEG_free_node_types();
DNA_sdna_current_free();
BLI_threadapi_exit();
BKE_blender_atexit();
BKE_tempdir_session_purge();
testing::Test::TearDownTestCase();
}
void BlendfileLoadingBaseTest::TearDown()
{
depsgraph_free();
blendfile_free();
testing::Test::TearDown();
}
bool BlendfileLoadingBaseTest::blendfile_load(const char *filepath)
{
const std::string &test_assets_dir = blender::tests::flags_test_asset_dir();
if (test_assets_dir.empty()) {
return false;
}
char abspath[FILENAME_MAX];
BLI_path_join(abspath, sizeof(abspath), test_assets_dir.c_str(), filepath, NULL);
bfile = BLO_read_from_file(abspath, BLO_READ_SKIP_NONE, NULL /* reports */);
if (bfile == nullptr) {
ADD_FAILURE() << "Unable to load file '" << filepath << "' from test assets dir '"
<< test_assets_dir << "'";
return false;
}
return true;
}
void BlendfileLoadingBaseTest::blendfile_free()
{
if (bfile == nullptr) {
return;
}
wmWindowManager *wm = static_cast<wmWindowManager *>(bfile->main->wm.first);
if (wm != nullptr) {
wm_close_and_free(NULL, wm);
}
BLO_blendfiledata_free(bfile);
bfile = nullptr;
}
void BlendfileLoadingBaseTest::depsgraph_create(eEvaluationMode depsgraph_evaluation_mode)
{
depsgraph = DEG_graph_new(
bfile->main, bfile->curscene, bfile->cur_view_layer, depsgraph_evaluation_mode);
DEG_graph_build_from_view_layer(depsgraph, bfile->main, bfile->curscene, bfile->cur_view_layer);
BKE_scene_graph_update_tagged(depsgraph, bfile->main);
}
void BlendfileLoadingBaseTest::depsgraph_free()
{
if (depsgraph == nullptr) {
return;
}
DEG_graph_free(depsgraph);
depsgraph = nullptr;
}

View File

@@ -1,64 +0,0 @@
/*
* 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.
*
* The Original Code is Copyright (C) 2019 by Blender Foundation.
*/
#ifndef __BLENDFILE_LOADING_BASE_TEST_H__
#define __BLENDFILE_LOADING_BASE_TEST_H__
#include "DEG_depsgraph.h"
#include "testing/testing.h"
struct BlendFileData;
struct Depsgraph;
class BlendfileLoadingBaseTest : public testing::Test {
protected:
struct BlendFileData *bfile = nullptr;
struct Depsgraph *depsgraph = nullptr;
public:
virtual ~BlendfileLoadingBaseTest();
/* Sets up Blender just enough to not crash on loading
* a blendfile and constructing a depsgraph. */
static void SetUpTestCase();
static void TearDownTestCase();
protected:
/* Frees the depsgraph & blendfile. */
virtual void TearDown();
/* Loads a blend file from the lib/tests directory from SVN.
* Returns 'ok' flag (true=good, false=bad) and sets this->bfile.
* Fails the test if the file cannot be loaded (still returns though).
* Requires the CLI argument --test-asset-dir to point to ../../lib/tests.
*
* WARNING: only files saved with Blender 2.80+ can be loaded. Since Blender
* is only partially initialized (most importantly, without window manager),
* the space types are not registered, so any versioning code that handles
* those will SEGFAULT.
*/
bool blendfile_load(const char *filepath);
/* Free bfile if it is not nullptr. */
void blendfile_free();
/* Create a depsgraph. Assumes a blend file has been loaded to this->bfile. */
void depsgraph_create(eEvaluationMode depsgraph_evaluation_mode);
/* Free the depsgraph if it's not nullptr. */
void depsgraph_free();
};
#endif /* __BLENDFILE_LOADING_BASE_TEST_H__ */

View File

@@ -1,49 +0,0 @@
# ***** 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.
#
# The Original Code is Copyright (C) 2014, Blender Foundation
# All rights reserved.
# ***** END GPL LICENSE BLOCK *****
set(INC
.
..
../../../source/blender/blenlib
../../../source/blender/makesdna
../../../source/blender/bmesh
../../../intern/guardedalloc
)
set(LIB
bf_blenloader # Should not be needed but gives linking error without it.
bf_intern_opencolorio # Should not be needed but gives windows linker errors if the ocio libs are linked before this
bf_gpu # Should not be needed but gives windows linker errors if the ocio libs are linked before this
bf_bmesh
)
include_directories(${INC})
setup_libdirs()
if(WITH_BUILDINFO)
set(_buildinfo_src "$<TARGET_OBJECTS:buildinfoobj>")
else()
set(_buildinfo_src "")
endif()
BLENDER_SRC_GTEST(bmesh_core "bmesh_core_test.cc;${_buildinfo_src}" "${LIB}")
unset(_buildinfo_src)
setup_liblinks(bmesh_core_test)

View File

@@ -1,40 +0,0 @@
#include "testing/testing.h"
#include "BLI_math.h"
#include "BLI_utildefines.h"
#include "bmesh.h"
TEST(bmesh_core, BMVertCreate)
{
BMesh *bm;
BMVert *bv1, *bv2, *bv3;
const float co1[3] = {1.0f, 2.0f, 0.0f};
BMeshCreateParams bm_params;
bm_params.use_toolflags = true;
bm = BM_mesh_create(&bm_mesh_allocsize_default, &bm_params);
EXPECT_EQ(bm->totvert, 0);
/* make a custom layer so we can see if it is copied properly */
BM_data_layer_add(bm, &bm->vdata, CD_PROP_FLOAT);
bv1 = BM_vert_create(bm, co1, NULL, BM_CREATE_NOP);
ASSERT_TRUE(bv1 != NULL);
EXPECT_EQ(bv1->co[0], 1.0f);
EXPECT_EQ(bv1->co[1], 2.0f);
EXPECT_EQ(bv1->co[2], 0.0f);
EXPECT_TRUE(is_zero_v3(bv1->no));
EXPECT_EQ(bv1->head.htype, (char)BM_VERT);
EXPECT_EQ(bv1->head.hflag, 0);
EXPECT_EQ(bv1->head.api_flag, 0);
bv2 = BM_vert_create(bm, NULL, NULL, BM_CREATE_NOP);
ASSERT_TRUE(bv2 != NULL);
EXPECT_TRUE(is_zero_v3(bv2->co));
/* create with example should copy custom data but not select flag */
BM_vert_select_set(bm, bv2, true);
BM_elem_float_data_set(&bm->vdata, bv2, CD_PROP_FLOAT, 1.5f);
bv3 = BM_vert_create(bm, co1, bv2, BM_CREATE_NOP);
ASSERT_TRUE(bv3 != NULL);
EXPECT_FALSE(BM_elem_flag_test((BMElem *)bv3, BM_ELEM_SELECT));
EXPECT_EQ(BM_elem_float_data_get(&bm->vdata, bv3, CD_PROP_FLOAT), 1.5f);
EXPECT_EQ(BM_mesh_elem_count(bm, BM_VERT), 3);
BM_mesh_free(bm);
}

View File

@@ -1,44 +0,0 @@
# ***** 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.
#
# The Original Code is Copyright (C) 2014, Blender Foundation
# All rights reserved.
# ***** END GPL LICENSE BLOCK *****
set(INC
.
..
${FFMPEG_INCLUDE_DIRS}
${PNG_INCLUDE_DIRS}
${ZLIB_INCLUDE_DIRS}
)
set(LIB
${PNG_LIBRARIES}
${FFMPEG_LIBRARIES}
${ZLIB_LIBRARIES}
)
if(WITH_IMAGE_OPENJPEG)
set(LIB ${LIB} ${OPENJPEG_LIBRARIES})
endif()
setup_platform_linker_flags()
link_directories(${FFMPEG_LIBPATH} ${PNG_LIBPATH} ${ZLIB_LIBPATH})
include_directories(${INC})
BLENDER_SRC_GTEST(ffmpeg "ffmpeg_codecs.cc" "${LIB}")

View File

@@ -1,147 +0,0 @@
#include "testing/testing.h"
extern "C" {
#include <libavcodec/avcodec.h>
#include <libavutil/log.h>
}
bool test_vcodec(AVCodec *codec, AVPixelFormat pixelformat)
{
av_log_set_level(AV_LOG_QUIET);
bool result = false;
if (codec) {
AVCodecContext *ctx = avcodec_alloc_context3(codec);
if (ctx) {
ctx->time_base.num = 1;
ctx->time_base.den = 25;
ctx->pix_fmt = pixelformat;
ctx->width = 720;
ctx->height = 576;
int open = avcodec_open2(ctx, codec, NULL);
if (open >= 0) {
avcodec_free_context(&ctx);
result = true;
}
}
}
return result;
}
bool test_acodec(AVCodec *codec, AVSampleFormat fmt)
{
av_log_set_level(AV_LOG_QUIET);
bool result = false;
if (codec) {
AVCodecContext *ctx = avcodec_alloc_context3(codec);
if (ctx) {
ctx->sample_fmt = fmt;
ctx->sample_rate = 48000;
ctx->channel_layout = AV_CH_LAYOUT_MONO;
ctx->bit_rate = 128000;
int open = avcodec_open2(ctx, codec, NULL);
if (open >= 0) {
avcodec_free_context(&ctx);
result = true;
}
}
}
return result;
}
bool test_codec_video_by_codecid(AVCodecID codec_id, AVPixelFormat pixelformat)
{
bool result = false;
AVCodec *codec = avcodec_find_encoder(codec_id);
if (codec)
result = test_vcodec(codec, pixelformat);
return result;
}
bool test_codec_video_by_name(const char *codecname, AVPixelFormat pixelformat)
{
bool result = false;
AVCodec *codec = avcodec_find_encoder_by_name(codecname);
if (codec)
result = test_vcodec(codec, pixelformat);
return result;
}
bool test_codec_audio_by_codecid(AVCodecID codec_id, AVSampleFormat fmt)
{
bool result = false;
AVCodec *codec = avcodec_find_encoder(codec_id);
if (codec)
result = test_acodec(codec, fmt);
return result;
}
bool test_codec_audio_by_name(const char *codecname, AVSampleFormat fmt)
{
bool result = false;
AVCodec *codec = avcodec_find_encoder_by_name(codecname);
if (codec)
result = test_acodec(codec, fmt);
return result;
}
#define str(s) #s
#define FFMPEG_TEST_VCODEC_ID(codec, fmt) \
TEST(CheckCodec, codec##_##fmt) \
{ \
EXPECT_TRUE(test_codec_video_by_codecid(codec, fmt)); \
}
#define FFMPEG_TEST_VCODEC_NAME(codec, fmt) \
TEST(CheckCodec, codec##_##fmt) \
{ \
EXPECT_TRUE(test_codec_video_by_name(str(codec), fmt)); \
}
#define FFMPEG_TEST_ACODEC_ID(codec, fmt) \
TEST(CheckCodec, codec##_##fmt) \
{ \
EXPECT_TRUE(test_codec_audio_by_codecid(codec, fmt)); \
}
#define FFMPEG_TEST_ACODEC_NAME(codec, fmt) \
TEST(CheckCodec, codec) \
{ \
EXPECT_TRUE(test_codec_audio_by_name(str(codec), fmt)); \
}
/* generic codec ID's used in blender */
FFMPEG_TEST_VCODEC_ID(AV_CODEC_ID_HUFFYUV, AV_PIX_FMT_BGRA)
FFMPEG_TEST_VCODEC_ID(AV_CODEC_ID_HUFFYUV, AV_PIX_FMT_RGB32)
FFMPEG_TEST_VCODEC_ID(AV_CODEC_ID_FFV1, AV_PIX_FMT_RGB32)
FFMPEG_TEST_VCODEC_ID(AV_CODEC_ID_QTRLE, AV_PIX_FMT_ARGB)
FFMPEG_TEST_VCODEC_ID(AV_CODEC_ID_VP9, AV_PIX_FMT_YUVA420P)
FFMPEG_TEST_VCODEC_ID(AV_CODEC_ID_PNG, AV_PIX_FMT_RGBA)
FFMPEG_TEST_VCODEC_ID(AV_CODEC_ID_H264, AV_PIX_FMT_YUV420P)
FFMPEG_TEST_VCODEC_ID(AV_CODEC_ID_MPEG4, AV_PIX_FMT_YUV420P)
FFMPEG_TEST_VCODEC_ID(AV_CODEC_ID_THEORA, AV_PIX_FMT_YUV420P)
FFMPEG_TEST_VCODEC_ID(AV_CODEC_ID_DVVIDEO, AV_PIX_FMT_YUV420P)
FFMPEG_TEST_VCODEC_ID(AV_CODEC_ID_MPEG1VIDEO, AV_PIX_FMT_YUV420P)
FFMPEG_TEST_VCODEC_ID(AV_CODEC_ID_MPEG2VIDEO, AV_PIX_FMT_YUV420P)
FFMPEG_TEST_VCODEC_ID(AV_CODEC_ID_FLV1, AV_PIX_FMT_YUV420P)
/* Audio codecs */
FFMPEG_TEST_ACODEC_ID(AV_CODEC_ID_AAC, AV_SAMPLE_FMT_FLTP)
FFMPEG_TEST_ACODEC_ID(AV_CODEC_ID_AC3, AV_SAMPLE_FMT_FLTP)
FFMPEG_TEST_ACODEC_ID(AV_CODEC_ID_FLAC, AV_SAMPLE_FMT_S16)
FFMPEG_TEST_ACODEC_ID(AV_CODEC_ID_MP2, AV_SAMPLE_FMT_S16)
FFMPEG_TEST_ACODEC_ID(AV_CODEC_ID_MP3, AV_SAMPLE_FMT_FLTP)
FFMPEG_TEST_ACODEC_ID(AV_CODEC_ID_OPUS, AV_SAMPLE_FMT_FLT)
FFMPEG_TEST_ACODEC_ID(AV_CODEC_ID_PCM_S16LE, AV_SAMPLE_FMT_S16)
FFMPEG_TEST_ACODEC_ID(AV_CODEC_ID_VORBIS, AV_SAMPLE_FMT_FLTP)
/* Libraries we count on ffmpeg being linked against */
FFMPEG_TEST_VCODEC_NAME(libtheora, AV_PIX_FMT_YUV420P)
FFMPEG_TEST_VCODEC_NAME(libx264, AV_PIX_FMT_YUV420P)
FFMPEG_TEST_VCODEC_NAME(libvpx, AV_PIX_FMT_YUV420P)
FFMPEG_TEST_VCODEC_NAME(libopenjpeg, AV_PIX_FMT_YUV420P)
FFMPEG_TEST_VCODEC_NAME(libxvid, AV_PIX_FMT_YUV420P)
FFMPEG_TEST_ACODEC_NAME(libvorbis, AV_SAMPLE_FMT_FLTP)
FFMPEG_TEST_ACODEC_NAME(libopus, AV_SAMPLE_FMT_FLT)
FFMPEG_TEST_ACODEC_NAME(libmp3lame, AV_SAMPLE_FMT_FLTP)

View File

@@ -1,35 +0,0 @@
# ***** 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.
#
# The Original Code is Copyright (C) 2014, Blender Foundation
# All rights reserved.
# ***** END GPL LICENSE BLOCK *****
set(INC
.
..
../../../intern/guardedalloc
../../../source/blender/blenlib
)
include_directories(${INC})
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${PLATFORM_LINKFLAGS}")
set(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} ${PLATFORM_LINKFLAGS_DEBUG}")
BLENDER_TEST(guardedalloc_alignment "")
BLENDER_TEST(guardedalloc_overflow "")

View File

@@ -1,121 +0,0 @@
/* Apache License, Version 2.0 */
#include "testing/testing.h"
#include "BLI_utildefines.h"
#include "MEM_guardedalloc.h"
#define CHECK_ALIGNMENT(ptr, align) EXPECT_EQ((size_t)ptr % align, 0)
namespace {
void DoBasicAlignmentChecks(const int alignment)
{
int *foo, *bar;
foo = (int *)MEM_mallocN_aligned(sizeof(int) * 10, alignment, "test");
CHECK_ALIGNMENT(foo, alignment);
bar = (int *)MEM_dupallocN(foo);
CHECK_ALIGNMENT(bar, alignment);
MEM_freeN(bar);
foo = (int *)MEM_reallocN(foo, sizeof(int) * 5);
CHECK_ALIGNMENT(foo, alignment);
foo = (int *)MEM_recallocN(foo, sizeof(int) * 5);
CHECK_ALIGNMENT(foo, alignment);
MEM_freeN(foo);
}
} // namespace
TEST(guardedalloc, LockfreeAlignedAlloc1)
{
DoBasicAlignmentChecks(1);
}
TEST(guardedalloc, GuardedAlignedAlloc1)
{
MEM_use_guarded_allocator();
DoBasicAlignmentChecks(1);
}
TEST(guardedalloc, LockfreeAlignedAlloc2)
{
DoBasicAlignmentChecks(2);
}
TEST(guardedalloc, GuardedAlignedAlloc2)
{
MEM_use_guarded_allocator();
DoBasicAlignmentChecks(2);
}
TEST(guardedalloc, LockfreeAlignedAlloc4)
{
DoBasicAlignmentChecks(4);
}
TEST(guardedalloc, GuardedAlignedAlloc4)
{
MEM_use_guarded_allocator();
DoBasicAlignmentChecks(4);
}
TEST(guardedalloc, LockfreeAlignedAlloc8)
{
DoBasicAlignmentChecks(8);
}
TEST(guardedalloc, GuardedAlignedAlloc8)
{
MEM_use_guarded_allocator();
DoBasicAlignmentChecks(8);
}
TEST(guardedalloc, LockfreeAlignedAlloc16)
{
DoBasicAlignmentChecks(16);
}
TEST(guardedalloc, GuardedAlignedAlloc16)
{
MEM_use_guarded_allocator();
DoBasicAlignmentChecks(16);
}
TEST(guardedalloc, LockfreeAlignedAlloc32)
{
DoBasicAlignmentChecks(32);
}
TEST(guardedalloc, GuardedAlignedAlloc32)
{
MEM_use_guarded_allocator();
DoBasicAlignmentChecks(32);
}
TEST(guardedalloc, LockfreeAlignedAlloc256)
{
DoBasicAlignmentChecks(256);
}
TEST(guardedalloc, GuardedAlignedAlloc256)
{
MEM_use_guarded_allocator();
DoBasicAlignmentChecks(256);
}
TEST(guardedalloc, LockfreeAlignedAlloc512)
{
DoBasicAlignmentChecks(512);
}
TEST(guardedalloc, GuardedAlignedAlloc512)
{
MEM_use_guarded_allocator();
DoBasicAlignmentChecks(512);
}

View File

@@ -1,60 +0,0 @@
/* Apache License, Version 2.0 */
#include "testing/testing.h"
#include "MEM_guardedalloc.h"
/* We expect to abort on integer overflow, to prevent possible exploits. */
#ifdef _WIN32
# define ABORT_PREDICATE ::testing::ExitedWithCode(3)
#else
# define ABORT_PREDICATE ::testing::KilledBySignal(SIGABRT)
#endif
namespace {
void MallocArray(size_t len, size_t size)
{
void *mem = MEM_malloc_arrayN(len, size, "MallocArray");
if (mem) {
MEM_freeN(mem);
}
}
void CallocArray(size_t len, size_t size)
{
void *mem = MEM_calloc_arrayN(len, size, "CallocArray");
if (mem) {
MEM_freeN(mem);
}
}
} // namespace
TEST(guardedalloc, LockfreeIntegerOverflow)
{
MallocArray(1, SIZE_MAX);
CallocArray(SIZE_MAX, 1);
MallocArray(SIZE_MAX / 2, 2);
CallocArray(SIZE_MAX / 1234567, 1234567);
EXPECT_EXIT(MallocArray(SIZE_MAX, 2), ABORT_PREDICATE, "");
EXPECT_EXIT(CallocArray(7, SIZE_MAX), ABORT_PREDICATE, "");
EXPECT_EXIT(MallocArray(SIZE_MAX, 12345567), ABORT_PREDICATE, "");
EXPECT_EXIT(CallocArray(SIZE_MAX, SIZE_MAX), ABORT_PREDICATE, "");
}
TEST(guardedalloc, GuardedIntegerOverflow)
{
MEM_use_guarded_allocator();
MallocArray(1, SIZE_MAX);
CallocArray(SIZE_MAX, 1);
MallocArray(SIZE_MAX / 2, 2);
CallocArray(SIZE_MAX / 1234567, 1234567);
EXPECT_EXIT(MallocArray(SIZE_MAX, 2), ABORT_PREDICATE, "");
EXPECT_EXIT(CallocArray(7, SIZE_MAX), ABORT_PREDICATE, "");
EXPECT_EXIT(MallocArray(SIZE_MAX, 12345567), ABORT_PREDICATE, "");
EXPECT_EXIT(CallocArray(SIZE_MAX, SIZE_MAX), ABORT_PREDICATE, "");
}