+/*
+ * Image Library -- Simple automatic tests
+ *
+ * (c) 2006 Pavel Charvat <pchar@ucw.cz>
+ *
+ * This software may be freely distributed and used according to the terms
+ * of the GNU Lesser General Public License.
+ */
+
#undef LOCAL_DEBUG
-#include "sherlock/sherlock.h"
-#include "lib/fastbuf.h"
-#include "images/images.h"
-#include "images/image-sig.h"
-#include "images/kd-tree.h"
-#include "sherlock/index.h"
+#include "lib/lib.h"
#include "lib/mempool.h"
-#include "sherlock/object.h"
-#include "sherlock/lizard-fb.h"
-#include <fcntl.h>
-#include <stdio.h>
-
-#include "sherlock/sherlock.h"
#include "lib/fastbuf.h"
+#include "lib/threads.h"
#include "images/images.h"
-#include "sherlock/index.h"
+#include "images/color.h"
-#include <stdio.h>
-#include <fcntl.h>
-#include <alloca.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pthread.h>
+#include <time.h>
+#include <unistd.h>
-#define BEST_CNT 30
+static uns want_image_iface;
+static uns want_threads;
-struct image_tree image_tree;
+#define TRY(x) do { if (!(x)) ASSERT(0); } while (0)
static void
-image_tree_init(void)
+test_image_iface(void)
{
- DBG("Initializing image search structures");
- struct fastbuf *fb = bopen("index/image-tree", O_RDONLY, 1 << 16); /* FIXME: filename hack */
- image_tree.count = bgetl(fb);
- image_tree.depth = bgetl(fb);
- ASSERT(image_tree.count < 0x80000000 && image_tree.depth > 0 && image_tree.depth < 30);
- image_tree.nodes = xmalloc((1 << image_tree.depth) * sizeof(struct image_node));
- image_tree.leaves = xmalloc(image_tree.count * sizeof(struct image_leaf));
- bread(fb, &image_tree.bbox, sizeof(struct image_bbox));
- bread(fb, image_tree.nodes + 1, ((1 << image_tree.depth) - 1) * sizeof(struct image_node));
- bread(fb, image_tree.leaves, image_tree.count * sizeof(struct image_leaf));
- DBG("Search tree with depth %d and %d leaves loaded", image_tree.depth, image_tree.count);
- bclose(fb);
-}
+ struct mempool *pool;
+ struct image_context ctx;
+ struct image *i1, *i2;
+ struct image s1;
-static void
-image_tree_done(void)
-{
- DBG("Freeing image search structures");
- xfree(image_tree.nodes);
- xfree(image_tree.leaves);
+ pool = mp_new(1024);
+ image_context_init(&ctx);
+
+ /* Image allocation */
+ i1 = image_new(&ctx, 731, 327, COLOR_SPACE_RGB, NULL);
+ ASSERT(i1);
+ ASSERT(i1->pixel_size == 3);
+ image_destroy(i1);
+
+ /* Test invalid image size */
+ ctx.msg_callback = image_context_msg_silent;
+ i1 = image_new(&ctx, 2214, 0, COLOR_SPACE_RGB, NULL);
+ ASSERT(!i1);
+ i1 = image_new(&ctx, 0xffffff, 0xffffff, COLOR_SPACE_RGB, NULL);
+ ASSERT(!i1);
+ ctx.msg_callback = image_context_msg_default;
+
+ /* Various image allocatio parameters */
+ i1 = image_new(&ctx, 370, 100, COLOR_SPACE_GRAYSCALE, pool);
+ ASSERT(i1);
+ ASSERT(i1->pixel_size == 1);
+ image_destroy(i1);
+ mp_flush(pool);
+
+ i1 = image_new(&ctx, 373, 101, COLOR_SPACE_RGB | IMAGE_ALIGNED, NULL);
+ ASSERT(i1);
+ ASSERT(i1->pixel_size == 4);
+ ASSERT(IMAGE_SSE_ALIGN_SIZE >= 16);
+ ASSERT(!(i1->row_size & (IMAGE_SSE_ALIGN_SIZE - 1)));
+ ASSERT(!((uintptr_t)i1->pixels & (IMAGE_SSE_ALIGN_SIZE - 1)));
+ image_destroy(i1);
+
+ i1 = image_new(&ctx, 283, 329, COLOR_SPACE_RGB, NULL);
+ ASSERT(i1);
+ ASSERT(i1->pixel_size == 3);
+
+ /* Image structures cloning */
+ i2 = image_clone(&ctx, i1, COLOR_SPACE_RGB, NULL);
+ ASSERT(i2);
+ ASSERT(i2->pixel_size == 3);
+ image_destroy(i2);
+
+ i2 = image_clone(&ctx, i1, COLOR_SPACE_RGB | IMAGE_PIXELS_ALIGNED, NULL);
+ ASSERT(i2);
+ ASSERT(i2->pixel_size == 4);
+ image_destroy(i2);
+
+ /* Subimages */
+ i2 = image_init_subimage(&ctx, &s1, i1, 29, 39, 283 - 29, 100);
+ ASSERT(i2);
+ image_destroy(&s1);
+
+ image_destroy(i1);
+
+ image_context_cleanup(&ctx);
+ mp_delete(pool);
}
-
-int
-main(int argc, char **argv)
+
+#ifdef CONFIG_UCW_THREADS
+
+#define TEST_THREADS_COUNT 4
+
+static void *
+test_threads_thread(void *param UNUSED)
{
- struct image_vector query;
- if (argc != IMAGE_VEC_K + 1)
- die("Invalid number of arguments");
+ DBG("Starting thread");
+ struct image_context ctx;
+ struct image_io io;
+ image_context_init(&ctx);
+ TRY(image_io_init(&ctx, &io));
- for (uns i = 0; i < IMAGE_VEC_K; i++)
- {
- uns v;
- if (sscanf(argv[i + 1], "%d", &v) != 1)
- die("Invalid numeric format");
- query.f[i] = v;
- }
-
-
- struct image_search is;
- oid_t best[BEST_CNT];
- uns dist[BEST_CNT];
- uns cardpos[BEST_CNT];
- uns best_n = 0;
-
- image_tree_init();
- log(L_INFO, "Executing query (%s)", stk_print_image_vector(&query));
- image_search_init(&is, &image_tree, &query, IMAGE_SEARCH_DIST_UNLIMITED);
- for (uns i = 0; i < BEST_CNT; i++)
+ for (uns num = 0; num < 200; num++)
{
- if (!image_search_next(&is, best + i, dist + i))
+ int r0 = random_max(100);
+
+ /* realloc context */
+ if ((r0 -= 2) < 0)
{
- log(L_INFO, "No more images");
- break;
- }
- DBG("*** Found %d. best image with oid=%d", i + 1, best[i]);
- best_n++;
- }
- image_search_done(&is);
- image_tree_done();
-
- log(L_INFO, "Resolving URLs");
- struct mempool *pool = mp_new(1 << 16);
- struct buck2obj_buf *bob = buck2obj_alloc();
- struct fastbuf *fb = bopen("index/card-attrs", O_RDONLY, 1 << 10);
- for (uns i = 0; i < best_n; i++)
- {
- bsetpos(fb, best[i] * sizeof(struct card_attr));
- struct card_attr ca;
- bread(fb, &ca, sizeof(ca));
- cardpos[i] = ca.card;
+ image_io_cleanup(&io);
+ image_context_cleanup(&ctx);
+ image_context_init(&ctx);
+ TRY(image_io_init(&ctx, &io));
+ }
+
+ /* realloc I/O */
+ else if ((r0 -= 2) < 0)
+ {
+ image_io_cleanup(&io);
+ TRY(image_io_init(&ctx, &io));
+ }
+
+ /* encode and decode random image */
+ else
+ {
+ struct image *img;
+
+ TRY(img = image_new(&ctx, 10 + random_max(140), 10 + random_max(140), COLOR_SPACE_RGB, NULL));
+ image_clear(&ctx, img);
+
+#if defined(CONFIG_IMAGES_LIBJPEG) || defined(CONFIG_IMAGES_LIBPNG) || defined(CONFIG_IMAGES_LIBMAGICK)
+
+ struct fastbuf *wfb = fbmem_create(10000);
+ struct fastbuf *rfb;
+ uns format = 0;
+ while (!format)
+ {
+ switch (random_max(3))
+ {
+ case 0:
+#if defined(CONFIG_IMAGES_LIBJPEG) || defined(CONFIG_IMAGES_LIBMAGICK)
+ format = IMAGE_FORMAT_JPEG;
+#endif
+ break;
+ case 1:
+#if defined(CONFIG_IMAGES_LIBPNG) || defined(CONFIG_IMAGES_LIBMAGICK)
+ format = IMAGE_FORMAT_PNG;
+#endif
+ break;
+ case 2:
+#if defined(CONFIG_IMAGES_LIBMAGICK)
+ format = IMAGE_FORMAT_GIF;
+#endif
+ break;
+ default:
+ ASSERT(0);
+ }
+ }
+
+ io.format = format;
+ io.fastbuf = wfb;
+ io.image = img;
+ TRY(image_io_write(&io));
+ image_io_reset(&io);
+
+ rfb = fbmem_clone_read(wfb);
+ io.format = format;
+ io.fastbuf = rfb;
+ TRY(image_io_read(&io, 0));
+ image_io_reset(&io);
+
+ bclose(rfb);
+ bclose(wfb);
+
+#endif
+ image_destroy(img);
+ }
}
- bclose(fb);
- fb = bopen("index/cards", O_RDONLY, 1 << 14);
- for (uns i = 0; i < best_n; i++)
+
+ image_io_cleanup(&io);
+ image_context_cleanup(&ctx);
+ DBG("Stopping thread");
+ return NULL;
+}
+
+#endif
+
+static void
+test_threads(void)
+{
+#ifdef CONFIG_UCW_THREADS
+ pthread_t threads[TEST_THREADS_COUNT - 1];
+ pthread_attr_t attr;
+ if (pthread_attr_init(&attr) < 0 ||
+ pthread_attr_setstacksize(&attr, default_thread_stack_size) < 0)
+ ASSERT(0);
+ for (uns i = 0; i < TEST_THREADS_COUNT - 1; i++)
{
- bsetpos(fb, (sh_off_t)cardpos[i] << CARD_POS_SHIFT);
- uns buck_len = bgetl(fb) - (LIZARD_COMPRESS_HEADER - 1);
- uns buck_type = bgetc(fb) + BUCKET_TYPE_PLAIN;
- mp_flush(pool);
- struct odes *obj = obj_read_bucket(bob, pool, buck_type, buck_len, fb, NULL);
-
- printf("%2d. match: dist=%-8d oid=%-8d url=%s\n", i + 1, dist[i], best[i],
- obj_find_aval(obj_find_attr(obj, 'U' + OBJ_ATTR_SON)->son, 'U'));
+ if (pthread_create(threads + i, &attr, test_threads_thread, NULL) < 0)
+ die("Unable to create thread: %m");
}
- bclose(fb);
- buck2obj_free(bob);
- mp_delete(pool);
-
+ test_threads_thread(NULL);
+ for (uns i = 0; i < TEST_THREADS_COUNT - 1; i++)
+ if (pthread_join(threads[i], NULL) < 0)
+ die("Cannot join thread: %m");
+#else
+ msg(L_WARN, "Disabled CONFIG_UCW_THREADS, threaded tests skipped");
+#endif
+}
+
+int
+main(int argc, char **argv)
+{
+ for (int i = 1; i < argc; i++)
+ if (!strcmp(argv[i], "image-iface"))
+ want_image_iface++;
+ else if (!strcmp(argv[i], "threads"))
+ want_threads++;
+ else
+ die("Invalid parameter");
+
+ srandom(time(NULL) ^ getpid());
+
+ if (want_image_iface)
+ test_image_iface();
+ if (want_threads)
+ test_threads();
+
return 0;
}