diff options
Diffstat (limited to 'tests')
27 files changed, 2805 insertions, 65 deletions
diff --git a/tests/gtests/blenlib/BLI_ghash_performance_test.cc b/tests/gtests/blenlib/BLI_ghash_performance_test.cc new file mode 100644 index 00000000000..fcee72466b7 --- /dev/null +++ b/tests/gtests/blenlib/BLI_ghash_performance_test.cc @@ -0,0 +1,415 @@ +/* Apache License, Version 2.0 */ + +#include "testing/testing.h" +#include "BLI_ressource_strings.h" + +#define GHASH_INTERNAL_API + +extern "C" { +#include "MEM_guardedalloc.h" +#include "BLI_utildefines.h" +#include "BLI_ghash.h" +#include "BLI_rand.h" +#include "BLI_string.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 */ +//#define TEXT_CORPUS_PATH "/path/to/Téléchargements/eng_wikipedia_2010_1M-text/eng_wikipedia_2010_1M-sentences.txt" + +/* Resizing the hash has a huge cost over global filling operation! */ +//#define GHASH_RESERVE + +#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_size(_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, SET_INT_IN_POINTER(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, SET_INT_IN_POINTER(p[0])); + } + if (!BLI_ghash_haskey(ghash, w)) { + BLI_ghash_insert(ghash, w, SET_INT_IN_POINTER(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, SET_INT_IN_POINTER(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(data_bis[0], GET_INT_FROM_POINTER(v)); + + for (p = w = c = data_bis; *c; c++) { + if (*c == '.') { + *c = '\0'; + v = BLI_ghash_lookup(ghash, w); + EXPECT_EQ(w[0], GET_INT_FROM_POINTER(v)); + v = BLI_ghash_lookup(ghash, p); + EXPECT_EQ(p[0], GET_INT_FROM_POINTER(v)); + p = w = c + 1; + } + else if (*c == ' ') { + *c = '\0'; + v = BLI_ghash_lookup(ghash, w); + EXPECT_EQ(w[0], GET_INT_FROM_POINTER(v)); + 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, SET_UINT_IN_POINTER(i), SET_UINT_IN_POINTER(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, SET_UINT_IN_POINTER(i)); + EXPECT_EQ(i, GET_UINT_FROM_POINTER(v)); + } + + TIMEIT_END(int_lookup); + } + + 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); +} + +TEST(ghash, IntGHash100000000) +{ + GHash *ghash = BLI_ghash_new(BLI_ghashutil_inthash_p, BLI_ghashutil_intcmp, __func__); + + int_ghash_tests(ghash, "IntGHash - GHash - 100000000", 100000000); +} + +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); +} + +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); +} + + +/* 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(0); + 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, SET_UINT_IN_POINTER(*dt), SET_UINT_IN_POINTER(*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, SET_UINT_IN_POINTER(*dt)); + EXPECT_EQ(*dt, GET_UINT_FROM_POINTER(v)); + } + + 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); +} + +TEST(ghash, IntRandGHash50000000) +{ + GHash *ghash = BLI_ghash_new(BLI_ghashutil_inthash_p, BLI_ghashutil_intcmp, __func__); + + randint_ghash_tests(ghash, "RandIntGHash - GHash - 50000000", 50000000); +} + +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); +} + +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); +} + +static unsigned int ghashutil_tests_nohash_p(const void *p) +{ + return GET_UINT_FROM_POINTER(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); +} + +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); +} + + +/* 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); + + unsigned int (*data)[4] = (unsigned int (*)[4])MEM_mallocN(sizeof(*data) * (size_t)nbr, __func__); + unsigned int (*dt)[4]; + unsigned int i, j; + + { + RNG *rng = BLI_rng_new(0); + 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, SET_UINT_IN_POINTER(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(i, GET_UINT_FROM_POINTER(v)); + } + + 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); +} + +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); +} + +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); +} + +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); +} diff --git a/tests/gtests/blenlib/BLI_ghash_test.cc b/tests/gtests/blenlib/BLI_ghash_test.cc new file mode 100644 index 00000000000..5fe43d14cbe --- /dev/null +++ b/tests/gtests/blenlib/BLI_ghash_test.cc @@ -0,0 +1,158 @@ +/* Apache License, Version 2.0 */ + +#include "testing/testing.h" + +#define GHASH_INTERNAL_API + +extern "C" { +#include "BLI_utildefines.h" +#include "BLI_ghash.h" +#include "BLI_rand.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_size(_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, SET_UINT_IN_POINTER(*k), SET_UINT_IN_POINTER(*k)); + } + + EXPECT_EQ(TESTCASE_SIZE, BLI_ghash_size(ghash)); + + for (i = TESTCASE_SIZE, k = keys; i--; k++) { + void *v = BLI_ghash_lookup(ghash, SET_UINT_IN_POINTER(*k)); + EXPECT_EQ(*k, GET_UINT_FROM_POINTER(v)); + } + + 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, SET_UINT_IN_POINTER(*k), SET_UINT_IN_POINTER(*k)); + } + + EXPECT_EQ(TESTCASE_SIZE, BLI_ghash_size(ghash)); + bkt_size = BLI_ghash_buckets_size(ghash); + + for (i = TESTCASE_SIZE, k = keys; i--; k++) { + void *v = BLI_ghash_popkey(ghash, SET_UINT_IN_POINTER(*k), NULL); + EXPECT_EQ(*k, GET_UINT_FROM_POINTER(v)); + } + + EXPECT_EQ(0, BLI_ghash_size(ghash)); + EXPECT_EQ(bkt_size, BLI_ghash_buckets_size(ghash)); + + 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, SET_UINT_IN_POINTER(*k), SET_UINT_IN_POINTER(*k)); + } + + EXPECT_EQ(TESTCASE_SIZE, BLI_ghash_size(ghash)); + bkt_size = BLI_ghash_buckets_size(ghash); + + for (i = TESTCASE_SIZE, k = keys; i--; k++) { + void *v = BLI_ghash_popkey(ghash, SET_UINT_IN_POINTER(*k), NULL); + EXPECT_EQ(*k, GET_UINT_FROM_POINTER(v)); + } + + EXPECT_EQ(0, BLI_ghash_size(ghash)); + EXPECT_LT(BLI_ghash_buckets_size(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, SET_UINT_IN_POINTER(*k), SET_UINT_IN_POINTER(*k)); + } + + EXPECT_EQ(TESTCASE_SIZE, BLI_ghash_size(ghash)); + + ghash_copy = BLI_ghash_copy(ghash, NULL, NULL); + + EXPECT_EQ(TESTCASE_SIZE, BLI_ghash_size(ghash_copy)); + EXPECT_EQ(BLI_ghash_buckets_size(ghash), BLI_ghash_buckets_size(ghash_copy)); + + for (i = TESTCASE_SIZE, k = keys; i--; k++) { + void *v = BLI_ghash_lookup(ghash_copy, SET_UINT_IN_POINTER(*k)); + EXPECT_EQ(*k, GET_UINT_FROM_POINTER(v)); + } + + BLI_ghash_free(ghash, NULL, NULL); + BLI_ghash_free(ghash_copy, NULL, NULL); +} diff --git a/tests/gtests/blenlib/BLI_hash_mm2a_test.cc b/tests/gtests/blenlib/BLI_hash_mm2a_test.cc new file mode 100644 index 00000000000..b35a1a809d6 --- /dev/null +++ b/tests/gtests/blenlib/BLI_hash_mm2a_test.cc @@ -0,0 +1,75 @@ +/* Apache License, Version 2.0 */ + +#include "testing/testing.h" + +extern "C" { +#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(1633988145, BLI_hash_mm2a_end(&mm2)); +#else + EXPECT_EQ(959283772, BLI_hash_mm2a_end(&mm2)); +#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(1545105348, hash); +#else + EXPECT_EQ(2604964730, hash); +#endif + EXPECT_EQ(hash, BLI_hash_mm2a_end(&mm2)); +} + +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(405493096, hash); +#else + EXPECT_EQ(405493096, hash); +#endif + EXPECT_EQ(hash, BLI_hash_mm2a_end(&mm2)); +} diff --git a/tests/gtests/blenlib/BLI_listbase_test.cc b/tests/gtests/blenlib/BLI_listbase_test.cc index 4b4d5d80a43..994b8f74541 100644 --- a/tests/gtests/blenlib/BLI_listbase_test.cc +++ b/tests/gtests/blenlib/BLI_listbase_test.cc @@ -3,10 +3,69 @@ #include "testing/testing.h" extern "C" { +#include "BLI_array_utils.h" #include "BLI_listbase.h" #include "MEM_guardedalloc.h" + +#include "BLI_string.h" +#include "BLI_path_util.h" +#include "BLI_ressource_strings.h" +} + + +/* local validation function */ +static bool listbase_is_valid(const ListBase *listbase) +{ +#define TESTFAIL(test) \ + if (!(test)) goto fail; + + 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 ((prev = link), (link = link->next)); + TESTFAIL(prev == listbase->last); + + prev = NULL; + link = (Link *)listbase->last; + do { + TESTFAIL(link->next == prev); + } while ((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; @@ -37,3 +96,162 @@ TEST(listbase, FindLinkOrIndex) 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); +} diff --git a/tests/gtests/blenlib/BLI_math_base_test.cc b/tests/gtests/blenlib/BLI_math_base_test.cc new file mode 100644 index 00000000000..0059eb54482 --- /dev/null +++ b/tests/gtests/blenlib/BLI_math_base_test.cc @@ -0,0 +1,87 @@ +/* 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 substraction 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)); +} diff --git a/tests/gtests/blenlib/BLI_path_util_test.cc b/tests/gtests/blenlib/BLI_path_util_test.cc index ea761bcf32e..c4ef7c2c970 100644 --- a/tests/gtests/blenlib/BLI_path_util_test.cc +++ b/tests/gtests/blenlib/BLI_path_util_test.cc @@ -31,6 +31,7 @@ const char *GHOST_getSystemDir(int version, const char *versionstr) struct ImBuf; void IMB_freeImBuf(struct ImBuf *ibuf) {} +struct ImBuf *IMB_dupImBuf(struct ImBuf *ibuf) {return NULL;} #ifdef __linux__ char *zLhm65070058860608_br_find_exe(const char *default_exe) diff --git a/tests/gtests/blenlib/BLI_polyfill2d_test.cc b/tests/gtests/blenlib/BLI_polyfill2d_test.cc new file mode 100644 index 00000000000..8ca19b11632 --- /dev/null +++ b/tests/gtests/blenlib/BLI_polyfill2d_test.cc @@ -0,0 +1,518 @@ +/* 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 + +extern "C" { +#include "BLI_array_utils.h" +#include "BLI_polyfill2d.h" +#include "BLI_math.h" +#include "BLI_edgehash.h" +#include "MEM_guardedalloc.h" + +#ifdef USE_OBJ_PREVIEW +# include "BLI_string.h" +#endif + +#ifdef USE_BEAUTIFY +#include "BLI_polyfill2d_beautify.h" +#include "BLI_memarena.h" +#include "BLI_heap.h" +#endif +} + +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(poly_tot + (poly_tot - 3), BLI_edgehash_size(edgehash)); + + 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_EQ(1, (void *)p != NULL); + EXPECT_EQ(1, (intptr_t)*p); + } + + 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_EQ(true, ELEM((intptr_t)*p, 1, 2)); + } + + 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_EQ(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); + EdgeHash *pf_ehash = BLI_edgehash_new_ex(__func__, BLI_POLYFILL_ALLOC_NGON_RESERVE); + + BLI_polyfill_beautify( + poly, poly_tot, tris, + pf_arena, pf_heap, pf_ehash); + + test_polyfill_template_check(id, is_degenerate, poly, poly_tot, tris, tris_tot); + + BLI_memarena_free(pf_arena); + BLI_heap_free(pf_heap, NULL); + BLI_edgehash_free(pf_ehash, NULL); + } +#endif +} + +#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(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(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 */ + +#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); +} diff --git a/tests/gtests/blenlib/BLI_ressource_strings.h b/tests/gtests/blenlib/BLI_ressource_strings.h new file mode 100644 index 00000000000..d7002d748c9 --- /dev/null +++ b/tests/gtests/blenlib/BLI_ressource_strings.h @@ -0,0 +1,602 @@ +/* Apache License, Version 2.0 */ + +#ifndef __BLENDER_TESTING_BLI_RESSOURCE_STRING_H__ +#define __BLENDER_TESTING_BLI_RESSOURCE_STRING_H__ + +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. " +"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 /* __BLENDER_TESTING_BLI_RESSOURCE_STRING_H__ */ diff --git a/tests/gtests/blenlib/BLI_stack_test.cc b/tests/gtests/blenlib/BLI_stack_test.cc index c4884cb8940..44956a589dc 100644 --- a/tests/gtests/blenlib/BLI_stack_test.cc +++ b/tests/gtests/blenlib/BLI_stack_test.cc @@ -11,6 +11,14 @@ extern "C" { #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; @@ -88,17 +96,82 @@ TEST(stack, String) 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_EQ(BLI_stack_is_empty(stack), true); +} + +/* 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_EQ(BLI_stack_is_empty(stack), true); + + /* 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_EQ(BLI_stack_is_empty(stack), false); + BLI_stack_pop(stack, (void *)&out); + EXPECT_EQ(in, out); + } + + EXPECT_EQ(BLI_stack_is_empty(stack), true); + + /* 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 in, out, i; + int out, i; int sum, sum_test; BLI_Stack *stack; - stack = BLI_stack_new(sizeof(in), __func__); + stack = BLI_stack_new(sizeof(i), __func__); /* add a bunch of numbers, ensure we get same sum out */ sum = 0; diff --git a/tests/gtests/blenlib/BLI_string_test.cc b/tests/gtests/blenlib/BLI_string_test.cc index 4c5c410dcb2..fa10e21730b 100644 --- a/tests/gtests/blenlib/BLI_string_test.cc +++ b/tests/gtests/blenlib/BLI_string_test.cc @@ -36,7 +36,7 @@ int mk_wcswidth(const wchar_t *pwcs, size_t n) TEST(string, StrPartition) { const char delim[] = {'-', '.', '_', '~', '\\', '\0'}; - char *sep, *suf; + const char *sep, *suf; size_t pre_ln; { @@ -95,7 +95,7 @@ TEST(string, StrPartition) TEST(string, StrRPartition) { const char delim[] = {'-', '.', '_', '~', '\\', '\0'}; - char *sep, *suf; + const char *sep, *suf; size_t pre_ln; { @@ -150,11 +150,42 @@ TEST(string, StrRPartition) } } +/* 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(5, pre_ln); + 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(4, pre_ln); + EXPECT_EQ(NULL, sep); + EXPECT_EQ(NULL, suf); + } +} + /* BLI_str_partition_utf8 */ TEST(string, StrPartitionUtf8) { const unsigned int delim[] = {'-', '.', '_', 0x00F1 /* n tilde */, 0x262F /* ying-yang */, '\0'}; - char *sep, *suf; + const char *sep, *suf; size_t pre_ln; { @@ -213,7 +244,7 @@ TEST(string, StrPartitionUtf8) TEST(string, StrRPartitionUtf8) { const unsigned int delim[] = {'-', '.', '_', 0x00F1 /* n tilde */, 0x262F /* ying-yang */, '\0'}; - char *sep, *suf; + const char *sep, *suf; size_t pre_ln; { @@ -268,6 +299,37 @@ TEST(string, StrRPartitionUtf8) } } +/* 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(2, pre_ln); + 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(4, pre_ln); + EXPECT_EQ(NULL, sep); + EXPECT_EQ(NULL, suf); + } +} + /* BLI_str_format_int_grouped */ TEST(string, StrFormatIntGrouped) { diff --git a/tests/gtests/blenlib/CMakeLists.txt b/tests/gtests/blenlib/CMakeLists.txt index 07b89a9042e..acd9f944e4c 100644 --- a/tests/gtests/blenlib/CMakeLists.txt +++ b/tests/gtests/blenlib/CMakeLists.txt @@ -38,6 +38,12 @@ set(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} ${PLATFORM_LIN BLENDER_TEST(BLI_stack "bf_blenlib") BLENDER_TEST(BLI_math_color "bf_blenlib") BLENDER_TEST(BLI_math_geom "bf_blenlib") +BLENDER_TEST(BLI_math_base "bf_blenlib") BLENDER_TEST(BLI_string "bf_blenlib") BLENDER_TEST(BLI_path_util "bf_blenlib;extern_wcwidth;${ZLIB_LIBRARIES}") +BLENDER_TEST(BLI_polyfill2d "bf_blenlib") BLENDER_TEST(BLI_listbase "bf_blenlib") +BLENDER_TEST(BLI_hash_mm2a "bf_blenlib") +BLENDER_TEST(BLI_ghash "bf_blenlib") + +BLENDER_TEST_PERFORMANCE(BLI_ghash_performance "bf_blenlib") diff --git a/tests/gtests/testing/testing_main.cc b/tests/gtests/testing/testing_main.cc index ef8e743b642..b2dcc445aca 100644 --- a/tests/gtests/testing/testing_main.cc +++ b/tests/gtests/testing/testing_main.cc @@ -28,7 +28,7 @@ int main(int argc, char **argv) { testing::InitGoogleTest(&argc, argv); - google::ParseCommandLineFlags(&argc, &argv, true); + gflags::ParseCommandLineFlags(&argc, &argv, true); google::InitGoogleLogging(argv[0]); return RUN_ALL_TESTS(); diff --git a/tests/python/CMakeLists.txt b/tests/python/CMakeLists.txt index 85c68693792..fd2176e64d7 100644 --- a/tests/python/CMakeLists.txt +++ b/tests/python/CMakeLists.txt @@ -48,6 +48,7 @@ else() endif() # for testing with valgrind prefix: valgrind --track-origins=yes --error-limit=no +set(TEST_BLENDER_EXE_BARE ${TEST_BLENDER_EXE}) set(TEST_BLENDER_EXE ${TEST_BLENDER_EXE} --background -noaudio --factory-startup --env-system-scripts ${CMAKE_SOURCE_DIR}/release/scripts) @@ -72,6 +73,16 @@ if(USE_EXPERIMENTAL_TESTS) ) endif() +# ------------------------------------------------------------------------------ +# PY API TESTS +add_test(script_pyapi_bpy_path ${TEST_BLENDER_EXE} + --python ${CMAKE_CURRENT_LIST_DIR}/bl_pyapi_bpy_path.py +) + +add_test(script_pyapi_bpy_utils_units ${TEST_BLENDER_EXE} + --python ${CMAKE_CURRENT_LIST_DIR}/bl_pyapi_bpy_utils_units.py +) + # test running mathutils testing script add_test(script_pyapi_mathutils ${TEST_BLENDER_EXE} --python ${CMAKE_CURRENT_LIST_DIR}/bl_pyapi_mathutils.py @@ -88,6 +99,8 @@ add_test(bevel ${TEST_BLENDER_EXE} # IO TESTS # OBJ Import tests +# disabled until updated & working +if(FALSE) add_test(import_obj_cube ${TEST_BLENDER_EXE} --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py -- --run={'FINISHED'}&bpy.ops.import_scene.obj\(filepath='${TEST_SRC_DIR}/io_tests/obj/cube.obj'\) @@ -108,6 +121,7 @@ add_test(import_obj_makehuman ${TEST_BLENDER_EXE} --md5=c9f78b185e58358daa4ecaecfa75464e --md5_method=SCENE --write-blend=${TEST_OUT_DIR}/import_obj_makehuman.blend ) +endif() # OBJ Export tests add_test(export_obj_cube ${TEST_BLENDER_EXE} @@ -116,7 +130,7 @@ add_test(export_obj_cube ${TEST_BLENDER_EXE} --run={'FINISHED'}&bpy.ops.export_scene.obj\(filepath='${TEST_OUT_DIR}/export_obj_cube.obj',use_selection=False\) --md5_source=${TEST_OUT_DIR}/export_obj_cube.obj --md5_source=${TEST_OUT_DIR}/export_obj_cube.mtl - --md5=70bdc394c2726203ad26c085176e3484 --md5_method=FILE + --md5=e776c6f8e9e0afba346e85bcd10b8e99 --md5_method=FILE ) add_test(export_obj_nurbs ${TEST_BLENDER_EXE} @@ -128,6 +142,8 @@ add_test(export_obj_nurbs ${TEST_BLENDER_EXE} --md5=a733ae4fa4a591ea9b0912da3af042de --md5_method=FILE ) +# disabled until updated & working +if(FALSE) add_test(export_obj_all_objects ${TEST_BLENDER_EXE} ${TEST_SRC_DIR}/io_tests/blend_scene/all_objects.blend --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py -- @@ -136,6 +152,7 @@ add_test(export_obj_all_objects ${TEST_BLENDER_EXE} --md5_source=${TEST_OUT_DIR}/export_obj_all_objects.mtl --md5=04b3ed97cede07a19548fc518ce9f8ca --md5_method=FILE ) +endif() @@ -162,6 +179,8 @@ add_test(import_ply_small_holes ${TEST_BLENDER_EXE} ) # PLY Export +# disabled until updated & working +if(FALSE) add_test(export_ply_cube_all_data ${TEST_BLENDER_EXE} ${TEST_SRC_DIR}/io_tests/blend_geometry/cube_all_data.blend --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py -- @@ -177,6 +196,7 @@ add_test(export_ply_suzanne_all_data ${TEST_BLENDER_EXE} --md5_source=${TEST_OUT_DIR}/export_ply_suzanne_all_data.ply --md5=68ba23f02efd6511bfd093f45f703221 --md5_method=FILE ) +endif() add_test(export_ply_vertices ${TEST_BLENDER_EXE} # lame, add a better one ${TEST_SRC_DIR}/io_tests/blend_geometry/vertices.blend @@ -188,6 +208,8 @@ add_test(export_ply_vertices ${TEST_BLENDER_EXE} # lame, add a better one # STL Import tests +# disabled until updated & working +if(FALSE) add_test(import_stl_cube ${TEST_BLENDER_EXE} --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py -- --run={'FINISHED'}&bpy.ops.import_mesh.stl\(filepath='${TEST_SRC_DIR}/io_tests/stl/cube.stl'\) @@ -208,8 +230,11 @@ add_test(import_stl_knot_max_simplified ${TEST_BLENDER_EXE} --md5=baf82803f45a84ec4ddbad9cef57dd3e --md5_method=SCENE --write-blend=${TEST_OUT_DIR}/import_stl_knot_max_simplified.blend ) +endif() # STL Export +# disabled until updated & working +if(FALSE) add_test(export_stl_cube_all_data ${TEST_BLENDER_EXE} ${TEST_SRC_DIR}/io_tests/blend_geometry/cube_all_data.blend --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py -- @@ -233,9 +258,12 @@ add_test(export_stl_vertices ${TEST_BLENDER_EXE} # lame, add a better one --md5_source=${TEST_OUT_DIR}/export_stl_vertices.stl --md5=3fd3c877e573beeebc782532cc005820 --md5_method=FILE ) +endif() # X3D Import +# disabled until updated & working +if(FALSE) add_test(import_x3d_cube ${TEST_BLENDER_EXE} --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py -- --run={'FINISHED'}&bpy.ops.import_scene.x3d\(filepath='${TEST_SRC_DIR}/io_tests/x3d/color_cube.x3d'\) @@ -281,10 +309,13 @@ add_test(export_x3d_all_objects ${TEST_BLENDER_EXE} --md5_source=${TEST_OUT_DIR}/export_x3d_all_objects.x3d --md5=f5f9fa4c5619a0eeab66685aafd2f7f0 --md5_method=FILE ) +endif() # 3DS Import +# disabled until updated & working +if(FALSE) add_test(import_3ds_cube ${TEST_BLENDER_EXE} --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py -- --run={'FINISHED'}&bpy.ops.import_scene.autodesk_3ds\(filepath='${TEST_SRC_DIR}/io_tests/3ds/cube.3ds'\) @@ -305,8 +336,11 @@ add_test(import_3ds_hierarchy_greek_trireme ${TEST_BLENDER_EXE} --md5=b62ee30101e8999cb91ef4f8a8760056 --md5_method=SCENE --write-blend=${TEST_OUT_DIR}/import_3ds_hierarchy_greek_trireme.blend ) +endif() # 3DS Export +# disabled until updated & working +if(FALSE) add_test(export_3ds_cube ${TEST_BLENDER_EXE} ${TEST_SRC_DIR}/io_tests/blend_geometry/all_quads.blend --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py -- @@ -330,11 +364,14 @@ add_test(export_3ds_all_objects ${TEST_BLENDER_EXE} --md5_source=${TEST_OUT_DIR}/export_3ds_all_objects.3ds --md5=68447761ab0ca38e1e22e7c177ed48a8 --md5_method=FILE ) +endif() # FBX Export # 'use_metadata=False' for reliable md5's +# disabled until updated & working +if(FALSE) add_test(export_fbx_cube ${TEST_BLENDER_EXE} ${TEST_SRC_DIR}/io_tests/blend_geometry/all_quads.blend --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py -- @@ -358,3 +395,29 @@ add_test(export_fbx_all_objects ${TEST_BLENDER_EXE} --md5_source=${TEST_OUT_DIR}/export_fbx_all_objects.fbx --md5=b35eb2a9d0e73762ecae2278c25a38ac --md5_method=FILE ) +endif() + +if(WITH_CYCLES) + if(OPENIMAGEIO_IDIFF AND EXISTS "${TEST_SRC_DIR}/cycles/ctests/shader") + add_test(cycles_reports_test + ${CMAKE_CURRENT_LIST_DIR}/cycles_render_tests.py + -blender "${TEST_BLENDER_EXE_BARE}" + -testdir "${TEST_SRC_DIR}/cycles/ctests/reports" + -idiff "${OPENIMAGEIO_IDIFF}" + ) + add_test(cycles_render_test + ${CMAKE_CURRENT_LIST_DIR}/cycles_render_tests.py + -blender "${TEST_BLENDER_EXE_BARE}" + -testdir "${TEST_SRC_DIR}/cycles/ctests/render" + -idiff "${OPENIMAGEIO_IDIFF}" + ) + add_test(cycles_shaders_test + ${CMAKE_CURRENT_LIST_DIR}/cycles_render_tests.py + -blender "${TEST_BLENDER_EXE_BARE}" + -testdir "${TEST_SRC_DIR}/cycles/ctests/shader" + -idiff "${OPENIMAGEIO_IDIFF}" + ) + else() + MESSAGE(STATUS "Disabling Cycles tests because tests folder does not exist") + endif() +endif() diff --git a/tests/python/batch_import.py b/tests/python/batch_import.py index dea08b45c3a..8fc679a7c15 100644 --- a/tests/python/batch_import.py +++ b/tests/python/batch_import.py @@ -78,7 +78,9 @@ def batch_import(operator="", path = os.path.abspath(path) match_upper = match.upper() - pattern_match = lambda a: fnmatch.fnmatchcase(a.upper(), match_upper) + + def pattern_match(a): + return fnmatch.fnmatchcase(a.upper(), match_upper) def file_generator(path): for dirpath, dirnames, filenames in os.walk(path): diff --git a/tests/python/bl_load_addons.py b/tests/python/bl_load_addons.py index f04ae64ee73..29304400005 100644 --- a/tests/python/bl_load_addons.py +++ b/tests/python/bl_load_addons.py @@ -20,24 +20,57 @@ # simple script to enable all addons, and disable +""" +./blender.bin --background -noaudio --factory-startup --python tests/python/bl_load_addons.py +""" + import bpy import addon_utils +import os import sys import imp +BLACKLIST_DIRS = ( + os.path.join(bpy.utils.resource_path('USER'), "scripts"), + ) + tuple(addon_utils.paths()[1:]) +BLACKLIST_ADDONS = set() + + +def _init_addon_blacklist(): + + # in case we built without cycles + if not bpy.app.build_options.cycles: + BLACKLIST_ADDONS.add("cycles") + + # in case we built without freestyle + if not bpy.app.build_options.freestyle: + BLACKLIST_ADDONS.add("render_freestyle_svg") + + # netrender has known problems re-registering + BLACKLIST_ADDONS.add("netrender") + + +def addon_modules_sorted(): + modules = addon_utils.modules({}) + modules[:] = [ + mod for mod in modules + if not (mod.__file__.startswith(BLACKLIST_DIRS)) + if not (mod.__name__ in BLACKLIST_ADDONS)] + modules.sort(key=lambda mod: mod.__name__) + return modules + def disable_addons(): # first disable all addons = bpy.context.user_preferences.addons for mod_name in list(addons.keys()): - addon_utils.disable(mod_name) + addon_utils.disable(mod_name, default_set=True) assert(bool(addons) is False) def test_load_addons(): - modules = addon_utils.modules({}) - modules.sort(key=lambda mod: mod.__name__) + modules = addon_modules_sorted() disable_addons() @@ -48,8 +81,8 @@ def test_load_addons(): for mod in modules: mod_name = mod.__name__ print("\tenabling:", mod_name) - addon_utils.enable(mod_name) - if mod_name not in addons: + addon_utils.enable(mod_name, default_set=True) + if (mod_name not in addons) and (mod_name not in BLACKLIST_ADDONS): addons_fail.append(mod_name) if addons_fail: @@ -62,8 +95,7 @@ def test_load_addons(): def reload_addons(do_reload=True, do_reverse=True): - modules = addon_utils.modules({}) - modules.sort(key=lambda mod: mod.__name__) + modules = addon_modules_sorted() addons = bpy.context.user_preferences.addons disable_addons() @@ -73,25 +105,28 @@ def reload_addons(do_reload=True, do_reverse=True): for mod in modules: mod_name = mod.__name__ print("\tenabling:", mod_name) - addon_utils.enable(mod_name) + addon_utils.enable(mod_name, default_set=True) assert(mod_name in addons) - for mod in addon_utils.modules({}): + for mod in modules: mod_name = mod.__name__ print("\tdisabling:", mod_name) - addon_utils.disable(mod_name) + addon_utils.disable(mod_name, default_set=True) assert(not (mod_name in addons)) # now test reloading if do_reload: imp.reload(sys.modules[mod_name]) - if do_reverse: - # in case order matters when it shouldn't - modules.reverse() + if do_reverse: + # in case order matters when it shouldn't + modules.reverse() def main(): + + _init_addon_blacklist() + # first load addons, print a list of all addons that fail test_load_addons() diff --git a/tests/python/bl_load_py_modules.py b/tests/python/bl_load_py_modules.py index 9677397e01d..4256cba0933 100644 --- a/tests/python/bl_load_py_modules.py +++ b/tests/python/bl_load_py_modules.py @@ -20,6 +20,10 @@ # simple script to enable all addons, and disable +""" +./blender.bin --background -noaudio --factory-startup --python tests/python/bl_load_py_modules.py +""" + import bpy import addon_utils @@ -28,10 +32,26 @@ import os BLACKLIST = { "bl_i18n_utils", + "bl_previews_utils", "cycles", "io_export_dxf", # TODO, check on why this fails + 'io_import_dxf', # Because of cydxfentity.so dependency } +if not bpy.app.build_options.freestyle: + BLACKLIST.add("render_freestyle_svg") + +BLACKLIST_DIRS = ( + os.path.join(bpy.utils.resource_path('USER'), "scripts"), + ) + tuple(addon_utils.paths()[1:]) + + +def addon_modules_sorted(): + modules = addon_utils.modules({}) + modules[:] = [mod for mod in modules if not mod.__file__.startswith(BLACKLIST_DIRS)] + modules.sort(key=lambda mod: mod.__name__) + return modules + def source_list(path, filename_check=None): from os.path import join @@ -47,20 +67,22 @@ def source_list(path, filename_check=None): def load_addons(): - modules = addon_utils.modules({}) - modules.sort(key=lambda mod: mod.__name__) + modules = addon_modules_sorted() addons = bpy.context.user_preferences.addons # first disable all for mod_name in list(addons.keys()): - addon_utils.disable(mod_name) + addon_utils.disable(mod_name, default_set=True) assert(bool(addons) is False) for mod in modules: mod_name = mod.__name__ - addon_utils.enable(mod_name) - assert(mod_name in addons) + if mod_name in BLACKLIST: + continue + addon_utils.enable(mod_name, default_set=True) + if not (mod_name in addons): + raise Exception("'addon_utils.enable(%r)' call failed" % mod_name) def load_modules(): @@ -79,9 +101,10 @@ def load_modules(): for script_path in paths: for mod_dir in sys.path: if mod_dir.startswith(script_path): - if mod_dir not in module_paths: - if os.path.exists(mod_dir): - module_paths.append(mod_dir) + if not mod_dir.startswith(BLACKLIST_DIRS): + if mod_dir not in module_paths: + if os.path.exists(mod_dir): + module_paths.append(mod_dir) # # collect modules from our paths. @@ -140,7 +163,8 @@ def load_modules(): ignore_paths = [ os.sep + "presets" + os.sep, os.sep + "templates" + os.sep, - ] + [(os.sep + f + os.sep) for f in BLACKLIST] + ] + ([(os.sep + f + os.sep) for f in BLACKLIST] + + [(os.sep + f + ".py") for f in BLACKLIST]) for f in source_files: ok = False diff --git a/tests/python/bl_mesh_modifiers.py b/tests/python/bl_mesh_modifiers.py index 2db38895f9b..0121be29dd6 100644 --- a/tests/python/bl_mesh_modifiers.py +++ b/tests/python/bl_mesh_modifiers.py @@ -197,8 +197,9 @@ def defaults_object(obj): obj.show_wire = True if obj.type == 'MESH': + obj.show_all_edges = True + mesh = obj.data - mesh.show_all_edges = True mesh.show_normal_vertex = True diff --git a/tests/python/bl_pyapi_bpy_path.py b/tests/python/bl_pyapi_bpy_path.py new file mode 100644 index 00000000000..2d6019fbb07 --- /dev/null +++ b/tests/python/bl_pyapi_bpy_path.py @@ -0,0 +1,41 @@ +# Apache License, Version 2.0 + +# ./blender.bin --background -noaudio --python tests/python/bl_pyapi_bpy_path.py -- --verbose +import unittest + + +class TestBpyPath(unittest.TestCase): + def test_ensure_ext(self): + from bpy.path import ensure_ext + + # Should work with both strings and bytes. + self.assertEqual(ensure_ext('demo', '.blend'), 'demo.blend') + self.assertEqual(ensure_ext(b'demo', b'.blend'), b'demo.blend') + + # Test different cases. + self.assertEqual(ensure_ext('demo.blend', '.blend'), 'demo.blend') + self.assertEqual(ensure_ext('demo.BLEND', '.blend'), 'demo.BLEND') + self.assertEqual(ensure_ext('demo.blend', '.BLEND'), 'demo.blend') + + # Test empty extensions, compound extensions etc. + self.assertEqual(ensure_ext('demo', 'blend'), 'demoblend') + self.assertEqual(ensure_ext('demo', ''), 'demo') + self.assertEqual(ensure_ext('demo', '.json.gz'), 'demo.json.gz') + self.assertEqual(ensure_ext('demo.json.gz', '.json.gz'), 'demo.json.gz') + self.assertEqual(ensure_ext('demo.json', '.json.gz'), 'demo.json.json.gz') + self.assertEqual(ensure_ext('', ''), '') + self.assertEqual(ensure_ext('', '.blend'), '.blend') + + # Test case-sensitive behaviour. + self.assertEqual(ensure_ext('demo', '.blend', True), 'demo.blend') + self.assertEqual(ensure_ext('demo.BLEND', '.blend', True), 'demo.BLEND.blend') + self.assertEqual(ensure_ext('demo', 'Blend', True), 'demoBlend') + self.assertEqual(ensure_ext('demoBlend', 'blend', True), 'demoBlendblend') + self.assertEqual(ensure_ext('demo', '', True), 'demo') + + +if __name__ == '__main__': + import sys + + sys.argv = [__file__] + (sys.argv[sys.argv.index("--") + 1:] if "--" in sys.argv else []) + unittest.main() diff --git a/tests/python/bl_pyapi_units.py b/tests/python/bl_pyapi_bpy_utils_units.py index 128cc100b25..f40dab4b5eb 100644 --- a/tests/python/bl_pyapi_units.py +++ b/tests/python/bl_pyapi_bpy_utils_units.py @@ -1,6 +1,6 @@ # Apache License, Version 2.0 -# ./blender.bin --background -noaudio --python tests/python/bl_pyapi_units.py -- --verbose +# ./blender.bin --background -noaudio --python tests/python/bl_pyapi_bpy_utils_units.py -- --verbose import unittest from bpy.utils import units diff --git a/tests/python/bl_pyapi_mathutils.py b/tests/python/bl_pyapi_mathutils.py index 85232e465d7..b7f61df0e40 100644 --- a/tests/python/bl_pyapi_mathutils.py +++ b/tests/python/bl_pyapi_mathutils.py @@ -2,7 +2,7 @@ # ./blender.bin --background -noaudio --python tests/python/bl_pyapi_mathutils.py -- --verbose import unittest -from mathutils import Matrix, Vector +from mathutils import Matrix, Vector, Quaternion from mathutils import kdtree import math @@ -210,6 +210,35 @@ class VectorTesting(unittest.TestCase): self.assertAlmostEqual(v.angle(v.orthogonal()), angle_90d) +class QuaternionTesting(unittest.TestCase): + + def test_to_expmap(self): + q = Quaternion((0, 0, 1), math.radians(90)) + + e = q.to_exponential_map() + self.assertAlmostEqual(e.x, 0) + self.assertAlmostEqual(e.y, 0) + self.assertAlmostEqual(e.z, math.radians(90), 6) + + def test_expmap_axis_normalization(self): + q = Quaternion((1, 1, 0), 2) + e = q.to_exponential_map() + + self.assertAlmostEqual(e.x, 2 * math.sqrt(0.5), 6) + self.assertAlmostEqual(e.y, 2 * math.sqrt(0.5), 6) + self.assertAlmostEqual(e.z, 0) + + def test_from_expmap(self): + e = Vector((1, 1, 0)) + q = Quaternion(e) + axis, angle = q.to_axis_angle() + + self.assertAlmostEqual(angle, math.sqrt(2), 6) + self.assertAlmostEqual(axis.x, math.sqrt(0.5), 6) + self.assertAlmostEqual(axis.y, math.sqrt(0.5), 6) + self.assertAlmostEqual(axis.z, 0) + + class KDTreeTesting(unittest.TestCase): @staticmethod diff --git a/tests/python/bl_rna_defaults.py b/tests/python/bl_rna_defaults.py new file mode 100644 index 00000000000..1d6f82b06c2 --- /dev/null +++ b/tests/python/bl_rna_defaults.py @@ -0,0 +1,117 @@ +# Apache License, Version 2.0 + +# ./blender.bin --background -noaudio --factory-startup --python tests/python/bl_rna_defaults.py + +import bpy + +DUMMY_NAME = "Untitled" +DUMMY_PATH = __file__ +GLOBALS = { + "error_num": 0, + } + + +def validate_defaults(test_id, o): + + def warning(prop_id, val_real, val_default): + print("Error %s: '%s.%s' is:%r, expected:%r" % + (test_id, o.__class__.__name__, prop_id, val_real, val_default)) + GLOBALS["error_num"] += 1 + + properties = type(o).bl_rna.properties.items() + for prop_id, prop in properties: + if prop_id == "rna_type": + continue + prop_type = prop.type + if prop_type in {'STRING', 'COLLECTION'}: + continue + + if prop_type == 'POINTER': + # traverse down pointers if they're set + val_real = getattr(o, prop_id) + if (val_real is not None) and (not isinstance(val_real, bpy.types.ID)): + validate_defaults("%s.%s" % (test_id, prop_id), val_real) + elif prop_type in {'INT', 'BOOL'}: + array_length = prop.array_length + if array_length == 0: + val_real = getattr(o, prop_id) + val_default = prop.default + if val_real != val_default: + warning(prop_id, val_real, val_default) + else: + pass # TODO, array defaults + elif prop_type == 'FLOAT': + array_length = prop.array_length + if array_length == 0: + val_real = getattr(o, prop_id) + val_default = prop.default + if val_real != val_default: + warning(prop_id, val_real, val_default) + else: + pass # TODO, array defaults + elif prop_type == 'ENUM': + val_real = getattr(o, prop_id) + if prop.is_enum_flag: + val_default = prop.default_flag + else: + val_default = prop.default + if val_real != val_default: + warning(prop_id, val_real, val_default) + + # print(prop_id, prop_type) + + +def _test_id_gen(data_attr, args_create=(DUMMY_NAME,), create_method="new"): + def test_gen(test_id): + id_collection = getattr(bpy.data, data_attr) + create_fn = getattr(id_collection, create_method) + o = create_fn(*args_create) + o.user_clear() + validate_defaults(test_id, o) + id_collection.remove(o) + return test_gen + + +test_Action = _test_id_gen("actions") +test_Armature = _test_id_gen("armatures") +test_Camera = _test_id_gen("cameras") +test_Group = _test_id_gen("groups") +test_Lattice = _test_id_gen("lattices") +test_LineStyle = _test_id_gen("linestyles") +test_Mask = _test_id_gen("masks") +test_Material = _test_id_gen("materials") +test_Mesh = _test_id_gen("meshes") +test_MetaBall = _test_id_gen("metaballs") +test_MovieClip = _test_id_gen("movieclips", args_create=(DUMMY_PATH,), create_method="load") +test_Object = _test_id_gen("objects", args_create=(DUMMY_NAME, None)) +test_Palette = _test_id_gen("palettes") +test_Particle = _test_id_gen("particles") +test_Scene = _test_id_gen("scenes") +test_Sound = _test_id_gen("sounds", args_create=(DUMMY_PATH,), create_method="load") +test_Speaker = _test_id_gen("speakers") +test_Text = _test_id_gen("texts") +test_VectorFont = _test_id_gen("fonts", args_create=("<builtin>",), create_method="load") +test_World = _test_id_gen("worlds") + +ns = globals() +for t in bpy.data.curves.bl_rna.functions["new"].parameters["type"].enum_items.keys(): + ns["test_Curve_%s" % t] = _test_id_gen("curves", args_create=(DUMMY_NAME, t)) +for t in bpy.data.lamps.bl_rna.functions["new"].parameters["type"].enum_items.keys(): + ns["test_Lamp_%s" % t] = _test_id_gen("lamps", args_create=(DUMMY_NAME, t)) +# types are a dynamic enum, have to hard-code. +for t in "ShaderNodeTree", "CompositorNodeTree", "TextureNodeTree": + ns["test_NodeGroup_%s" % t] = _test_id_gen("node_groups", args_create=(DUMMY_NAME, t)) +for t in bpy.data.textures.bl_rna.functions["new"].parameters["type"].enum_items.keys(): + ns["test_Texture_%s" % t] = _test_id_gen("textures", args_create=(DUMMY_NAME, t)) +del ns + + +def main(): + for fn_id, fn_val in sorted(globals().items()): + if fn_id.startswith("test_") and callable(fn_val): + fn_val(fn_id) + + print("Error (total): %d" % GLOBALS["error_num"]) + +if __name__ == "__main__": + main() diff --git a/tests/python/bl_rna_wiki_reference.py b/tests/python/bl_rna_manual_reference.py index 5781c53c045..c67b6c1532b 100644 --- a/tests/python/bl_rna_wiki_reference.py +++ b/tests/python/bl_rna_manual_reference.py @@ -18,8 +18,8 @@ # <pep8 compliant> -# Use for validating our wiki interlinking. -# ./blender.bin --background -noaudio --python tests/python/bl_rna_wiki_reference.py +# Use for validating our manual interlinking. +# ./blender.bin --background -noaudio --python tests/python/bl_rna_manual_reference.py # # 1) test_data() -- ensure the data we have is correct format # 2) test_lookup_coverage() -- ensure that we have lookups for _every_ RNA path @@ -31,10 +31,10 @@ import bpy def test_data(): - import rna_wiki_reference + import rna_manual_reference - assert(isinstance(rna_wiki_reference.url_manual_mapping, tuple)) - for i, value in enumerate(rna_wiki_reference.url_manual_mapping): + assert(isinstance(rna_manual_reference.url_manual_mapping, tuple)) + for i, value in enumerate(rna_manual_reference.url_manual_mapping): try: assert(len(value) == 2) assert(isinstance(value[0], str)) @@ -92,14 +92,19 @@ def test_language_coverage(): def test_urls(): + import os import sys - import rna_wiki_reference + import rna_manual_reference import urllib.error from urllib.request import urlopen - prefix = rna_wiki_reference.url_manual_prefix - urls = {suffix for (rna_id, suffix) in rna_wiki_reference.url_manual_mapping} + # avoid URL lookups if possible + LOCAL_PREFIX = os.environ.get("LOCAL_PREFIX") + if LOCAL_PREFIX is None: + prefix = rna_manual_reference.url_manual_prefix + + urls = {suffix for (rna_id, suffix) in rna_manual_reference.url_manual_mapping} urls_len = "%d" % len(urls) print("") @@ -113,16 +118,26 @@ def test_urls(): urls_fail = [] - for url in sorted(urls): - url_full = prefix + url - print(" %s ... " % url_full, end="") - sys.stdout.flush() - try: - urlopen(url_full) - print(color_green + "OK" + color_normal) - except urllib.error.HTTPError: - print(color_red + "FAIL!" + color_normal) - urls_fail.append(url) + if LOCAL_PREFIX: + for url in sorted(urls): + url_full = os.path.join(LOCAL_PREFIX, url.partition("#")[0]) + print(" %s ... " % url_full, end="") + if os.path.exists(url_full): + print(color_green + "OK" + color_normal) + else: + print(color_red + "FAIL!" + color_normal) + urls_fail.append(url) + else: + for url in sorted(urls): + url_full = prefix + url + print(" %s ... " % url_full, end="") + sys.stdout.flush() + try: + urlopen(url_full) + print(color_green + "OK" + color_normal) + except urllib.error.HTTPError: + print(color_red + "FAIL!" + color_normal) + urls_fail.append(url) if urls_fail: urls_len = "%d" % len(urls_fail) diff --git a/tests/python/bl_rst_completeness.py b/tests/python/bl_rst_completeness.py index d0ba2c552cf..d8dfac66d13 100644 --- a/tests/python/bl_rst_completeness.py +++ b/tests/python/bl_rst_completeness.py @@ -62,7 +62,7 @@ def is_directive_pydata(filepath, directive): return True elif directive.type in {"module", "note", "warning", "code-block", "hlist", "seealso"}: return False - elif directive.type in {"literalinclude"}: # TODO + elif directive.type == "literalinclude": # TODO return False else: print(directive_to_str(filepath, directive), end=" ") diff --git a/tests/python/bl_run_operators.py b/tests/python/bl_run_operators.py index f7fafe833aa..f3c553cf3ef 100644 --- a/tests/python/bl_run_operators.py +++ b/tests/python/bl_run_operators.py @@ -34,6 +34,10 @@ RANDOM_SEED = [1] # so we can redo crashes RANDOM_RESET = 0.1 # 10% chance of resetting on each new operator RANDOM_MULTIPLY = 10 +STATE = { + "counter": 0, + } + op_blacklist = ( "script.reload", @@ -75,6 +79,7 @@ op_blacklist = ( "wm.properties_context_change", "wm.operator_cheat_sheet", "wm.interface_theme_*", + "wm.previews_ensure", # slow - but harmless "wm.appconfig_*", # just annoying - but harmless "wm.keyitem_add", # just annoying - but harmless "wm.keyconfig_activate", # just annoying - but harmless @@ -158,7 +163,7 @@ if USE_ATTRSET: if issubclass(cls, skip_classes): continue - ## to support skip-save we cant get all props + # # to support skip-save we cant get all props # properties = cls.bl_rna.properties.keys() properties = [] for prop_id, prop in cls.bl_rna.properties.items(): @@ -248,7 +253,8 @@ def run_ops(operators, setup_func=None, reset=True): # first invoke for op_id, op in operators: if op.poll(): - print(" operator:", op_id) + print(" operator: %4d, %s" % (STATE["counter"], op_id)) + STATE["counter"] += 1 sys.stdout.flush() # in case of crash # disable will get blender in a bad state and crash easy! diff --git a/tests/python/cycles_render_tests.py b/tests/python/cycles_render_tests.py new file mode 100755 index 00000000000..36fad175cfa --- /dev/null +++ b/tests/python/cycles_render_tests.py @@ -0,0 +1,166 @@ +#!/usr/bin/env python3 +# Apache License, Version 2.0 + +import argparse +import os +import subprocess +import sys +import tempfile + + +def render_file(filepath): + command = ( + BLENDER, + "--background", + "-noaudio", + "--factory-startup", + filepath, + "-E", "CYCLES", + "-o", TEMP_FILE_MASK, + "-F", "PNG", + "-f", "1", + ) + try: + output = subprocess.check_output(command) + if VERBOSE: + print(output.decode("utf-8")) + return None + except subprocess.CalledProcessError as e: + if os.path.exists(TEMP_FILE): + os.remove(TEMP_FILE) + if VERBOSE: + print(e.output.decode("utf-8")) + if b"Error: engine not found" in e.output: + return "NO_CYCLES" + elif b"blender probably wont start" in e.output: + return "NO_START" + return "CRASH" + except: + if os.path.exists(TEMP_FILE): + os.remove(TEMP_FILE) + if VERBOSE: + print(e.output.decode("utf-8")) + return "CRASH" + + +def test_get_name(filepath): + filename = os.path.basename(filepath) + return os.path.splitext(filename)[0] + + +def verify_output(filepath): + testname = test_get_name(filepath) + dirpath = os.path.dirname(filepath) + reference_dirpath = os.path.join(dirpath, "reference_renders") + reference_image = os.path.join(reference_dirpath, testname + ".png") + if not os.path.exists(reference_image): + return False + command = ( + IDIFF, + "-fail", "0.01", + "-failpercent", "1", + reference_image, + TEMP_FILE, + ) + try: + subprocess.check_output(command) + return True + except subprocess.CalledProcessError as e: + if VERBOSE: + print(e.output.decode("utf-8")) + return e.returncode == 1 + + +def run_test(filepath): + testname = test_get_name(filepath) + spacer = "." * (32 - len(testname)) + print(testname, spacer, end="") + sys.stdout.flush() + error = render_file(filepath) + if not error: + if verify_output(filepath): + print("PASS") + else: + error = "VERIFY" + if error: + print("FAIL", error) + return error + + +def blend_list(path): + for dirpath, dirnames, filenames in os.walk(path): + for filename in filenames: + if filename.lower().endswith(".blend"): + filepath = os.path.join(dirpath, filename) + yield filepath + + +def run_all_tests(dirpath): + failed_tests = [] + all_files = list(blend_list(dirpath)) + all_files.sort() + for filepath in all_files: + error = run_test(filepath) + if error: + if error == "NO_CYCLES": + print("Can't perform tests because Cycles failed to load!") + return False + elif error == "NO_START": + print('Can not perform tests because blender fails to start.', + 'Make sure INSTALL target was run.') + return False + elif error == 'VERIFY': + pass + else: + print("Unknown error %r" % error) + testname = test_get_name(filepath) + failed_tests.append(testname) + if failed_tests: + failed_tests.sort() + print("\n\nFAILED tests:") + for test in failed_tests: + print(" ", test) + return False + return True + + +def create_argparse(): + parser = argparse.ArgumentParser() + parser.add_argument("-blender", nargs="+") + parser.add_argument("-testdir", nargs=1) + parser.add_argument("-idiff", nargs=1) + return parser + + +def main(): + parser = create_argparse() + args = parser.parse_args() + + global BLENDER, ROOT, IDIFF + global TEMP_FILE, TEMP_FILE_MASK, TEST_SCRIPT + global VERBOSE + + BLENDER = args.blender[0] + ROOT = args.testdir[0] + IDIFF = args.idiff[0] + + TEMP = tempfile.mkdtemp() + TEMP_FILE_MASK = os.path.join(TEMP, "test") + TEMP_FILE = TEMP_FILE_MASK + "0001.png" + + TEST_SCRIPT = os.path.join(os.path.dirname(__file__), "runtime_check.py") + + VERBOSE = os.environ.get("BLENDER_VERBOSE") is not None + + ok = run_all_tests(ROOT) + + # Cleanup temp files and folders + if os.path.exists(TEMP_FILE): + os.remove(TEMP_FILE) + os.rmdir(TEMP) + + sys.exit(not ok) + + +if __name__ == "__main__": + main() diff --git a/tests/python/pep8.py b/tests/python/pep8.py index 7713ffeaaa4..0d6db729767 100644 --- a/tests/python/pep8.py +++ b/tests/python/pep8.py @@ -95,19 +95,40 @@ def main(): print(" %s" % f) # strict imports - print("\n\n\n# running pep8...") + print("\n\n\n# checking imports...") import re import_check = re.compile(r"\s*from\s+[A-z\.]+\s+import \*\s*") for f, pep8_type in files: for i, l in enumerate(open(f, 'r', encoding='utf8')): if import_check.match(l): print("%s:%d:0: global import bad practice" % (f, i + 1)) + del re, import_check + + print("\n\n\n# checking class definitions...") + import re + class_check = re.compile(r"\s*class\s+.*\(\):.*") + for f, pep8_type in files: + for i, l in enumerate(open(f, 'r', encoding='utf8')): + if class_check.match(l): + print("%s:%d:0: empty class (), remove" % (f, i + 1)) + del re, class_check print("\n\n\n# running pep8...") # these are very picky and often hard to follow # while keeping common script formatting. - ignore = "E122", "E123", "E124", "E125", "E126", "E127", "E128" + ignore = ( + "E122", + "E123", + "E124", + "E125", + "E126", + "E127", + "E128", + # "imports not at top of file." + # prefer to load as needed (lazy load addons etc). + "E402", + ) for f, pep8_type in files: diff --git a/tests/python/rst_to_doctree_mini.py b/tests/python/rst_to_doctree_mini.py index 6a885a108f8..dfc6cd57db6 100644 --- a/tests/python/rst_to_doctree_mini.py +++ b/tests/python/rst_to_doctree_mini.py @@ -28,13 +28,14 @@ import collections -Directive = collections.namedtuple('Directive', - ("type", - "value", - "value_strip", - "line", - "indent", - "members")) +Directive = collections.namedtuple( + "Directive", + ("type", + "value", + "value_strip", + "line", + "indent", + "members")) def parse_rst_py(filepath): @@ -80,7 +81,7 @@ def parse_rst_py(filepath): return tree[0] -if __name__ == "__main__": +def main(): # not intended use, but may as well print rst files passed as a test. import sys for arg in sys.argv: @@ -88,3 +89,7 @@ if __name__ == "__main__": items = parse_rst_py(arg) for i in items: print(i) + + +if __name__ == "__main__": + main() |