summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/Makefile9
-rw-r--r--test/assert.c19
-rw-r--r--test/corestrings.c12
-rw-r--r--test/data/Choices5
-rw-r--r--test/data/Choices-all11
-rw-r--r--test/hashmap.c571
-rw-r--r--test/js/class-list.html29
-rw-r--r--test/js/index.html3
-rw-r--r--test/js/life.html175
-rw-r--r--test/js/mandelbrot.html31
-rw-r--r--test/messages.c3
-rwxr-xr-xtest/monkey-see-monkey-do139
-rw-r--r--test/monkey-tests/start-stop-no-js.yaml5
-rw-r--r--test/monkey-tests/state-test.yaml69
-rwxr-xr-xtest/monkey_driver.py171
-rw-r--r--test/monkeyfarmer.py120
-rw-r--r--test/nsoption.c10
-rw-r--r--test/utils.c33
18 files changed, 1194 insertions, 221 deletions
diff --git a/test/Makefile b/test/Makefile
index e92ece75d..82ffee6fa 100644
--- a/test/Makefile
+++ b/test/Makefile
@@ -7,6 +7,7 @@ TESTS := \
nsoption \
bloom \
hashtable \
+ hashmap \
urlescape \
utils \
messages \
@@ -52,6 +53,10 @@ bloom_SRCS := utils/bloom.c test/bloom.c
# hash table test sources
hashtable_SRCS := utils/hashtable.c test/log.c test/hashtable.c
+# hashmap test sources
+hashmap_SRCS := $(NSURL_SOURCES) utils/hashmap.c utils/corestrings.c test/log.c test/hashmap.c
+hashmap_LD := -lmalloc_fig
+
# url escape test sources
urlescape_SRCS := utils/url.c test/log.c test/urlescape.c
@@ -143,6 +148,8 @@ BASE_TESTCFLAGS := -std=c99 -g \
-Dnsgtk \
-DNETSURF_BUILTIN_LOG_FILTER=\"level:WARNING\" \
-DNETSURF_BUILTIN_VERBOSE_FILTER=\"level:DEBUG\" \
+ -DTESTROOT=\"$(TESTROOT)\" \
+ -DWITH_UTF8PROC \
$(SAN_FLAGS) \
$(shell pkg-config --cflags libcurl libparserutils libwapcaplet libdom libnsutils libutf8proc) \
$(LIB_CFLAGS)
@@ -158,7 +165,7 @@ TESTLDFLAGS := -L$(TESTROOT) \
# malloc faliure injection generator
$(TESTROOT)/libmalloc_fig.so:test/malloc_fig.c
- $(CC) -shared -fPIC -I. -std=c99 $(TEST_WARNFLAGS) $^ -o $@
+ $(CC) -shared -fPIC -I. -std=c99 $(TEST_WARNFLAGS) $^ -ldl -o $@
# Source files for all tests being compiled
TESTSOURCES :=
diff --git a/test/assert.c b/test/assert.c
index d21926e5e..fb4db8cc9 100644
--- a/test/assert.c
+++ b/test/assert.c
@@ -30,7 +30,23 @@ __ns_assert_fail(const char *__assertion, const char *__file,
unsigned int __line, const char *__function)
__THROW __attribute__ ((__noreturn__));
-/* We use this to flush coverage data */
+#if __GNUC__ > 10
+
+/* We use this to dump coverage data in gcc 11 and later */
+extern void __gcov_dump(void);
+
+/* And here's our entry point */
+void
+__ns_assert_fail(const char *__assertion, const char *__file,
+ unsigned int __line, const char *__function)
+{
+ __gcov_dump();
+ __assert_fail(__assertion, __file, __line, __function);
+}
+
+#else
+
+/* We use this to flush coverage data before gcc 11 */
extern void __gcov_flush(void);
/* And here's our entry point */
@@ -41,3 +57,4 @@ __ns_assert_fail(const char *__assertion, const char *__file,
__gcov_flush();
__assert_fail(__assertion, __file, __line, __function);
}
+#endif
diff --git a/test/corestrings.c b/test/corestrings.c
index 02640c953..c3c4e93eb 100644
--- a/test/corestrings.c
+++ b/test/corestrings.c
@@ -40,7 +40,7 @@
*
* This is used to test all the out of memory paths in initialisation.
*/
-#define CORESTRING_TEST_COUNT 435
+#define CORESTRING_TEST_COUNT 488
START_TEST(corestrings_test)
{
@@ -53,8 +53,12 @@ START_TEST(corestrings_test)
res = corestrings_fini();
malloc_limit(UINT_MAX);
-
- ck_assert_int_eq(ires, NSERROR_NOMEM);
+
+ if (_i < CORESTRING_TEST_COUNT) {
+ ck_assert_int_eq(ires, NSERROR_NOMEM);
+ } else {
+ ck_assert_int_eq(ires, NSERROR_OK);
+ }
ck_assert_int_eq(res, NSERROR_OK);
}
END_TEST
@@ -65,7 +69,7 @@ static TCase *corestrings_case_create(void)
TCase *tc;
tc = tcase_create("corestrings");
- tcase_add_loop_test(tc, corestrings_test, 0, CORESTRING_TEST_COUNT);
+ tcase_add_loop_test(tc, corestrings_test, 0, CORESTRING_TEST_COUNT + 1);
return tc;
}
diff --git a/test/data/Choices b/test/data/Choices
index bd946f77b..511ecf87e 100644
--- a/test/data/Choices
+++ b/test/data/Choices
@@ -30,7 +30,6 @@ disc_cache_size:1073741824
disc_cache_age:28
block_advertisements:0
do_not_track:0
-minimum_gif_delay:10
send_referer:1
foreground_images:1
background_images:1
@@ -50,8 +49,6 @@ window_x:0
window_y:0
window_width:0
window_height:0
-window_screen_width:0
-window_screen_height:0
toolbar_status_size:6667
scale:100
incremental_reflow:1
@@ -101,7 +98,6 @@ sys_colour_ThreeDShadow:000000
sys_colour_Window:000000
sys_colour_WindowFrame:000000
sys_colour_WindowText:000000
-render_resample:1
downloads_clear:0
request_overwrite:1
downloads_directory:/home/vince
@@ -109,7 +105,6 @@ url_file:/home/vince/.netsurf/URLs
show_single_tab:1
button_type:1
disable_popups:0
-disable_plugins:0
history_age:0
hover_urls:0
focus_new:0
diff --git a/test/data/Choices-all b/test/data/Choices-all
index d16c67568..5c26f2887 100644
--- a/test/data/Choices-all
+++ b/test/data/Choices-all
@@ -16,16 +16,17 @@ font_fantasy:Serif
accept_language:en
accept_charset:
memory_cache_size:12582912
+disc_cache_path:
disc_cache_size:1073741824
disc_cache_age:28
block_advertisements:0
do_not_track:0
-minimum_gif_delay:10
send_referer:1
foreground_images:1
background_images:1
animate_images:1
enable_javascript:1
+author_level_css:1
script_timeout:10
expire_url:28
font_default:0
@@ -41,8 +42,6 @@ window_x:0
window_y:0
window_width:0
window_height:0
-window_screen_width:0
-window_screen_height:0
toolbar_status_size:6667
scale:100
incremental_reflow:1
@@ -67,6 +66,7 @@ remove_backgrounds:0
enable_loosening:1
enable_PDF_compression:1
enable_PDF_password:0
+prefer_dark_mode:0
sys_colour_ActiveBorder:d3d3d3
sys_colour_ActiveCaption:f1f1f1
sys_colour_AppWorkspace:f1f1f1
@@ -97,7 +97,6 @@ sys_colour_WindowFrame:4e4e4e
sys_colour_WindowText:000000
log_filter:level:WARNING
verbose_filter:level:DEBUG
-render_resample:1
downloads_clear:0
request_overwrite:1
downloads_directory:/home/vince
@@ -105,7 +104,6 @@ url_file:/home/vince/.netsurf/URLs
show_single_tab:1
button_type:1
disable_popups:0
-disable_plugins:0
history_age:0
hover_urls:0
focus_new:0
@@ -113,4 +111,5 @@ new_blank:0
hotlist_path:/home/vince/.netsurf/Hotlist
developer_view:0
position_tab:0
-toolbar_order:
+toolbar_items:
+bar_show:
diff --git a/test/hashmap.c b/test/hashmap.c
new file mode 100644
index 000000000..ed951e9a7
--- /dev/null
+++ b/test/hashmap.c
@@ -0,0 +1,571 @@
+/*
+ * Copyright 2020 Daniel Silverstone <dsilvers@netsurf-browser.org>
+ * Copyright 2016 Vincent Sanders <vince@netsurf-browser.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file
+ * Tests for hashmap.
+ *
+ * In part, borrows from the corestrings tests
+ */
+
+#include "utils/config.h"
+
+#include <assert.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <check.h>
+#include <limits.h>
+
+#include <libwapcaplet/libwapcaplet.h>
+
+#include "utils/nsurl.h"
+#include "utils/corestrings.h"
+#include "utils/hashmap.h"
+
+#include "test/malloc_fig.h"
+
+/* Low level fixtures */
+
+static void
+corestring_create(void)
+{
+ ck_assert(corestrings_init() == NSERROR_OK);
+}
+
+/**
+ * iterator for any remaining strings in teardown fixture
+ */
+static void
+netsurf_lwc_iterator(lwc_string *str, void *pw)
+{
+ fprintf(stderr,
+ "[%3u] %.*s",
+ str->refcnt,
+ (int)lwc_string_length(str),
+ lwc_string_data(str));
+}
+
+static void
+corestring_teardown(void)
+{
+ corestrings_fini();
+
+ lwc_iterate_strings(netsurf_lwc_iterator, NULL);
+}
+
+/* Infra */
+
+static ssize_t keys;
+static ssize_t values;
+
+typedef struct {
+ nsurl *key;
+} hashmap_test_value_t;
+
+static void *
+key_clone(void *key)
+{
+ /* Pretend cloning costs memory so that it can fail for
+ * testing error return pathways
+ */
+ void *temp = malloc(1);
+ if (temp == NULL) return NULL;
+ free(temp);
+ /* In reality we just ref the nsurl */
+ keys++;
+ return nsurl_ref((nsurl *)key);
+}
+
+static void
+key_destroy(void *key)
+{
+ keys--;
+ nsurl_unref((nsurl *)key);
+}
+
+static uint32_t
+key_hash(void *key)
+{
+ /* Deliberately bad hash.
+ * returns 0, 1, 2, or 3 to force bucket chaining
+ */
+ return nsurl_hash((nsurl *)key) & 3;
+}
+
+static bool
+key_eq(void *key1, void *key2)
+{
+ return nsurl_compare((nsurl *)key1, (nsurl*)key2, NSURL_COMPLETE);
+}
+
+static void *
+value_alloc(void *key)
+{
+ hashmap_test_value_t *ret = malloc(sizeof(hashmap_test_value_t));
+
+ if (ret == NULL)
+ return NULL;
+
+ ret->key = (nsurl *)key;
+
+ values++;
+
+ return ret;
+}
+
+static void
+value_destroy(void *value)
+{
+ hashmap_test_value_t *val = value;
+
+ /* Do nothing for now */
+
+ free(val);
+ values--;
+}
+
+static hashmap_parameters_t test_params = {
+ .key_clone = key_clone,
+ .key_hash = key_hash,
+ .key_eq = key_eq,
+ .key_destroy = key_destroy,
+ .value_alloc = value_alloc,
+ .value_destroy = value_destroy,
+};
+
+/* Iteration helpers */
+
+static size_t iteration_counter = 0;
+static size_t iteration_stop = 0;
+static char iteration_ctx = 0;
+
+static bool
+hashmap_test_iterator_cb(void *key, void *value, void *ctx)
+{
+ ck_assert(ctx == &iteration_ctx);
+ iteration_counter++;
+ return iteration_counter == iteration_stop;
+}
+
+/* Fixtures for basic tests */
+
+static hashmap_t *test_hashmap = NULL;
+
+static void
+basic_fixture_create(void)
+{
+ corestring_create();
+
+ test_hashmap = hashmap_create(&test_params);
+
+ ck_assert(test_hashmap != NULL);
+ ck_assert_int_eq(keys, 0);
+ ck_assert_int_eq(values, 0);
+}
+
+static void
+basic_fixture_teardown(void)
+{
+ hashmap_destroy(test_hashmap);
+ test_hashmap = NULL;
+
+ ck_assert_int_eq(keys, 0);
+ ck_assert_int_eq(values, 0);
+
+ corestring_teardown();
+}
+
+/* basic api tests */
+
+START_TEST(empty_hashmap_create_destroy)
+{
+ ck_assert_int_eq(hashmap_count(test_hashmap), 0);
+}
+END_TEST
+
+START_TEST(check_not_present)
+{
+ /* We're checking for a key which should not be present */
+ ck_assert(hashmap_lookup(test_hashmap, corestring_nsurl_about_blank) == NULL);
+}
+END_TEST
+
+START_TEST(insert_works)
+{
+ hashmap_test_value_t *value = hashmap_insert(test_hashmap, corestring_nsurl_about_blank);
+ ck_assert(value != NULL);
+ ck_assert(value->key == corestring_nsurl_about_blank);
+ ck_assert_int_eq(hashmap_count(test_hashmap), 1);
+}
+END_TEST
+
+START_TEST(remove_not_present)
+{
+ ck_assert(hashmap_remove(test_hashmap, corestring_nsurl_about_blank) == false);
+}
+END_TEST
+
+START_TEST(insert_then_remove)
+{
+ hashmap_test_value_t *value = hashmap_insert(test_hashmap, corestring_nsurl_about_blank);
+ ck_assert(value != NULL);
+ ck_assert(value->key == corestring_nsurl_about_blank);
+ ck_assert_int_eq(keys, 1);
+ ck_assert_int_eq(values, 1);
+ ck_assert_int_eq(hashmap_count(test_hashmap), 1);
+ ck_assert(hashmap_remove(test_hashmap, corestring_nsurl_about_blank) == true);
+ ck_assert_int_eq(keys, 0);
+ ck_assert_int_eq(values, 0);
+ ck_assert_int_eq(hashmap_count(test_hashmap), 0);
+}
+END_TEST
+
+START_TEST(insert_then_lookup)
+{
+ hashmap_test_value_t *value = hashmap_insert(test_hashmap, corestring_nsurl_about_blank);
+ ck_assert(value != NULL);
+ ck_assert(value->key == corestring_nsurl_about_blank);
+ ck_assert(hashmap_lookup(test_hashmap, corestring_nsurl_about_blank) == value);
+}
+END_TEST
+
+START_TEST(iterate_empty)
+{
+ iteration_stop = iteration_counter = 0;
+ ck_assert(hashmap_iterate(test_hashmap, hashmap_test_iterator_cb, &iteration_ctx) == false);
+ ck_assert_int_eq(iteration_counter, 0);
+}
+END_TEST
+
+START_TEST(iterate_one)
+{
+ iteration_stop = iteration_counter = 0;
+ hashmap_test_value_t *value = hashmap_insert(test_hashmap, corestring_nsurl_about_blank);
+ ck_assert(value != NULL);
+ ck_assert(hashmap_iterate(test_hashmap, hashmap_test_iterator_cb, &iteration_ctx) == false);
+ ck_assert_int_eq(iteration_counter, 1);
+}
+END_TEST
+
+START_TEST(iterate_one_and_stop)
+{
+ iteration_stop = 1;
+ iteration_counter = 0;
+ hashmap_test_value_t *value = hashmap_insert(test_hashmap, corestring_nsurl_about_blank);
+ ck_assert(value != NULL);
+ ck_assert(hashmap_iterate(test_hashmap, hashmap_test_iterator_cb, &iteration_ctx) == true);
+ ck_assert_int_eq(iteration_counter, 1);
+}
+END_TEST
+
+static TCase *basic_api_case_create(void)
+{
+ TCase *tc;
+ tc = tcase_create("Basic API");
+
+ tcase_add_unchecked_fixture(tc,
+ basic_fixture_create,
+ basic_fixture_teardown);
+
+ tcase_add_test(tc, empty_hashmap_create_destroy);
+ tcase_add_test(tc, check_not_present);
+ tcase_add_test(tc, insert_works);
+ tcase_add_test(tc, remove_not_present);
+ tcase_add_test(tc, insert_then_remove);
+ tcase_add_test(tc, insert_then_lookup);
+
+ tcase_add_test(tc, iterate_empty);
+ tcase_add_test(tc, iterate_one);
+ tcase_add_test(tc, iterate_one_and_stop);
+
+ return tc;
+}
+
+/* Chain verification test suite */
+
+typedef struct {
+ const char *url;
+ nsurl *nsurl;
+} case_pair;
+
+/* The hobbled hash has only 4 values
+ * By having at least 12 test cases, we can be confident that
+ * at worst they'll all be on one chain, but at best there'll
+ * be four chains of 3 entries which means we should be able
+ * to validate prevptr and next in all cases.
+ */
+static case_pair chain_pairs[] = {
+ { "https://www.google.com/", NULL },
+ { "https://www.google.co.uk/", NULL },
+ { "https://www.netsurf-browser.org/", NULL },
+ { "http://www.google.com/", NULL },
+ { "http://www.google.co.uk/", NULL },
+ { "http://www.netsurf-browser.org/", NULL },
+ { "file:///tmp/test.html", NULL },
+ { "file:///tmp/inner.html", NULL },
+ { "about:blank", NULL },
+ { "about:welcome", NULL },
+ { "about:testament", NULL },
+ { "resources:default.css", NULL },
+ { NULL, NULL }
+};
+
+static void
+chain_fixture_create(void)
+{
+ case_pair *chain_case = chain_pairs;
+ basic_fixture_create();
+
+ while (chain_case->url != NULL) {
+ ck_assert(nsurl_create(chain_case->url, &chain_case->nsurl) == NSERROR_OK);
+ chain_case++;
+ }
+
+}
+
+static void
+chain_fixture_teardown(void)
+{
+ case_pair *chain_case = chain_pairs;
+
+ while (chain_case->url != NULL) {
+ nsurl_unref(chain_case->nsurl);
+ chain_case->nsurl = NULL;
+ chain_case++;
+ }
+
+ basic_fixture_teardown();
+}
+
+START_TEST(chain_add_remove_all)
+{
+ case_pair *chain_case;
+
+ for (chain_case = chain_pairs;
+ chain_case->url != NULL;
+ chain_case++) {
+ ck_assert(hashmap_lookup(test_hashmap, chain_case->nsurl) == NULL);
+ ck_assert(hashmap_insert(test_hashmap, chain_case->nsurl) != NULL);
+ ck_assert(hashmap_lookup(test_hashmap, chain_case->nsurl) != NULL);
+ ck_assert(hashmap_remove(test_hashmap, chain_case->nsurl) == true);
+ }
+
+ ck_assert_int_eq(keys, 0);
+ ck_assert_int_eq(values, 0);
+}
+END_TEST
+
+START_TEST(chain_add_all_remove_all)
+{
+ case_pair *chain_case;
+
+ for (chain_case = chain_pairs;
+ chain_case->url != NULL;
+ chain_case++) {
+ ck_assert(hashmap_lookup(test_hashmap, chain_case->nsurl) == NULL);
+ ck_assert(hashmap_insert(test_hashmap, chain_case->nsurl) != NULL);
+ }
+
+ for (chain_case = chain_pairs;
+ chain_case->url != NULL;
+ chain_case++) {
+ ck_assert(hashmap_remove(test_hashmap, chain_case->nsurl) == true);
+ }
+
+ ck_assert_int_eq(keys, 0);
+ ck_assert_int_eq(values, 0);
+}
+END_TEST
+
+START_TEST(chain_add_all_twice_remove_all)
+{
+ case_pair *chain_case;
+
+ for (chain_case = chain_pairs;
+ chain_case->url != NULL;
+ chain_case++) {
+ ck_assert(hashmap_lookup(test_hashmap, chain_case->nsurl) == NULL);
+ ck_assert(hashmap_insert(test_hashmap, chain_case->nsurl) != NULL);
+ }
+
+ for (chain_case = chain_pairs;
+ chain_case->url != NULL;
+ chain_case++) {
+ ck_assert(hashmap_lookup(test_hashmap, chain_case->nsurl) != NULL);
+ ck_assert(hashmap_insert(test_hashmap, chain_case->nsurl) != NULL);
+ }
+
+ for (chain_case = chain_pairs;
+ chain_case->url != NULL;
+ chain_case++) {
+ ck_assert(hashmap_remove(test_hashmap, chain_case->nsurl) == true);
+ }
+
+ ck_assert_int_eq(keys, 0);
+ ck_assert_int_eq(values, 0);
+}
+END_TEST
+
+START_TEST(chain_add_all_twice_remove_all_iterate)
+{
+ case_pair *chain_case;
+ size_t chain_count = 0;
+
+ for (chain_case = chain_pairs;
+ chain_case->url != NULL;
+ chain_case++) {
+ ck_assert(hashmap_lookup(test_hashmap, chain_case->nsurl) == NULL);
+ ck_assert(hashmap_insert(test_hashmap, chain_case->nsurl) != NULL);
+ chain_count++;
+ }
+
+ iteration_counter = 0;
+ iteration_stop = 0;
+ ck_assert(hashmap_iterate(test_hashmap, hashmap_test_iterator_cb, &iteration_ctx) == false);
+ ck_assert_int_eq(iteration_counter, chain_count);
+
+ for (chain_case = chain_pairs;
+ chain_case->url != NULL;
+ chain_case++) {
+ ck_assert(hashmap_lookup(test_hashmap, chain_case->nsurl) != NULL);
+ ck_assert(hashmap_insert(test_hashmap, chain_case->nsurl) != NULL);
+ }
+
+ iteration_counter = 0;
+ iteration_stop = 0;
+ ck_assert(hashmap_iterate(test_hashmap, hashmap_test_iterator_cb, &iteration_ctx) == false);
+ ck_assert_int_eq(iteration_counter, chain_count);
+ ck_assert_int_eq(hashmap_count(test_hashmap), chain_count);
+
+ iteration_counter = 0;
+ iteration_stop = chain_count;
+ ck_assert(hashmap_iterate(test_hashmap, hashmap_test_iterator_cb, &iteration_ctx) == true);
+ ck_assert_int_eq(iteration_counter, chain_count);
+
+ for (chain_case = chain_pairs;
+ chain_case->url != NULL;
+ chain_case++) {
+ ck_assert(hashmap_remove(test_hashmap, chain_case->nsurl) == true);
+ }
+
+ iteration_counter = 0;
+ iteration_stop = chain_count;
+ ck_assert(hashmap_iterate(test_hashmap, hashmap_test_iterator_cb, &iteration_ctx) == false);
+ ck_assert_int_eq(iteration_counter, 0);
+
+ ck_assert_int_eq(keys, 0);
+ ck_assert_int_eq(values, 0);
+ ck_assert_int_eq(hashmap_count(test_hashmap), 0);
+}
+END_TEST
+
+#define CHAIN_TEST_MALLOC_COUNT_MAX 60
+
+START_TEST(chain_add_all_remove_all_alloc)
+{
+ bool failed = false;
+ case_pair *chain_case;
+
+ malloc_limit(_i);
+
+ for (chain_case = chain_pairs;
+ chain_case->url != NULL;
+ chain_case++) {
+ if (hashmap_insert(test_hashmap, chain_case->nsurl) == NULL) {
+ failed = true;
+ }
+ }
+
+ for (chain_case = chain_pairs;
+ chain_case->url != NULL;
+ chain_case++) {
+ if (hashmap_insert(test_hashmap, chain_case->nsurl) == NULL) {
+ failed = true;
+ }
+ }
+
+ for (chain_case = chain_pairs;
+ chain_case->url != NULL;
+ chain_case++) {
+ hashmap_remove(test_hashmap, chain_case->nsurl);
+ }
+
+ malloc_limit(UINT_MAX);
+
+ ck_assert_int_eq(keys, 0);
+ ck_assert_int_eq(values, 0);
+
+ if (_i < CHAIN_TEST_MALLOC_COUNT_MAX) {
+ ck_assert(failed);
+ } else {
+ ck_assert(!failed);
+ }
+
+}
+END_TEST
+
+static TCase *chain_case_create(void)
+{
+ TCase *tc;
+ tc = tcase_create("Bucket Chain tests");
+
+ tcase_add_unchecked_fixture(tc,
+ chain_fixture_create,
+ chain_fixture_teardown);
+
+ tcase_add_test(tc, chain_add_remove_all);
+ tcase_add_test(tc, chain_add_all_remove_all);
+ tcase_add_test(tc, chain_add_all_twice_remove_all);
+ tcase_add_test(tc, chain_add_all_twice_remove_all_iterate);
+
+ tcase_add_loop_test(tc, chain_add_all_remove_all_alloc, 0, CHAIN_TEST_MALLOC_COUNT_MAX + 1);
+
+ return tc;
+}
+
+/*
+ * hashmap test suite creation
+ */
+static Suite *hashmap_suite_create(void)
+{
+ Suite *s;
+ s = suite_create("Hashmap");
+
+ suite_add_tcase(s, basic_api_case_create());
+ suite_add_tcase(s, chain_case_create());
+
+ return s;
+}
+
+int main(int argc, char **argv)
+{
+ int number_failed;
+ SRunner *sr;
+
+ sr = srunner_create(hashmap_suite_create());
+
+ srunner_run_all(sr, CK_ENV);
+
+ number_failed = srunner_ntests_failed(sr);
+ srunner_free(sr);
+
+ return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/test/js/class-list.html b/test/js/class-list.html
new file mode 100644
index 000000000..4c73283e5
--- /dev/null
+++ b/test/js/class-list.html
@@ -0,0 +1,29 @@
+<html>
+ <head>
+ <title>Class List (and other token lists?)</title>
+ <style>
+ .bad { background-color: red; }
+ .ok { background-color: green; }
+ </style>
+ </head>
+ <body>
+ <h1>This is a set of demonstrators for the token list Element.classList</h1>
+ <h2>This first is taken from the MDN for DOMTokenList</h2>
+ <span id="demo1" class=" d d e f bad"></span>
+ <script>
+ var span = document.getElementById("demo1");
+ var classes = span.classList;
+ classes.add("x", "d", "g");
+ classes.remove("e", "g");
+ classes.toggle("d"); // Toggles d off
+ classes.toggle("q", false); // Forces q off (won't be present)
+ classes.toggle("d"); // Toggles d on
+ classes.toggle("d", true); // Forces d on (won't toggle it off again)
+ if (classes.contains("d")) {
+ classes.add("ok")
+ classes.remove("bad")
+ span.textContent = "span classList is \"" + classes + '"';
+ }
+ </script>
+ </body>
+</html>
diff --git a/test/js/index.html b/test/js/index.html
index 2abe954e5..6d2c6541e 100644
--- a/test/js/index.html
+++ b/test/js/index.html
@@ -104,6 +104,9 @@
<li><a href="assorted-log-doc-write.html">console.log and document.write</a></li>
<li><a href="wikipedia-lcm.html">Example from wikipedia</a></li>
<li><a href="verify-instanceofness.html">Check instanceof behaviour</a></li>
+<li><a href="class-list.html">Class list (and other token lists?)</a></li>
+<li><a href="mandelbrot.html">Canvas/ImageData Mandelbrot ploter</a></li>
+<li><a href="life.html">Game of Life</a></li>
</ul>
</body>
diff --git a/test/js/life.html b/test/js/life.html
new file mode 100644
index 000000000..de54d0aae
--- /dev/null
+++ b/test/js/life.html
@@ -0,0 +1,175 @@
+<html>
+ <head>
+ <meta charset="UTF-8" />
+ <title>Conway's Game of Life</title>
+ <link rel="stylesheet" type="text/css" href="resource:internal.css" />
+ <style>
+ canvas#surface {
+ width: 50vmin;
+ height: 50vmin;
+ border: 2px solid black;
+ }
+ </style>
+ </head>
+ <body class="ns-even-bg ns-even-fg ns-border">
+ <h1 class="ns-border">Conway's Game of Life</h1>
+ <div style="margin: 1em;">
+ <div>
+ Run: <input id="running" type="checkbox" checked/><br />
+ Set Size: <input id="width" type="text" size="4" value="50" /> x
+ <input id="height" type="text" size="4" value="50" />
+ <button id="commitsize">Commit</button><br />
+ </div>
+ <div>
+ <canvas id="surface" width="50" height="50">
+ Sorry, you can't play Game of Life if JavaScript is turned off
+ </canvas>
+ </div>
+ <div>
+ <button id="random">Randomise</button>
+ </div>
+ </div>
+ </body>
+ <script>
+ (function () {
+ const running = document.getElementById("running");
+ const iwidth = document.getElementById("width");
+ const iheight = document.getElementById("height");
+ const surface = document.getElementById("surface");
+ const context = surface.getContext("2d");
+ var width = surface.width - 10;
+ var height = surface.height - 10;
+ var frame = context.createImageData(width, height);
+ var drawto = context.createImageData(width, height);
+ var greyto = context.createImageData(width, height);
+ const greylevel = 31;
+
+ function getOffset(x, y) {
+ if (x < 0) {
+ x = width + x;
+ }
+ if (y < 0) {
+ y = height + y;
+ }
+ if (x >= width) {
+ x = x - width;
+ }
+ if (y >= height) {
+ y = y - height;
+ }
+ return (y * width + x) * 4;
+ }
+ function getCell(x, y) {
+ const offset = getOffset(x, y);
+ return frame.data[offset + 3] != 0;
+ }
+ function setCell(x, y) {
+ const offset = getOffset(x, y);
+ drawto.data[offset + 3] = 255;
+ greyto.data[offset + 3] = greylevel;
+ }
+ function clearCell(x, y) {
+ const offset = getOffset(x, y);
+ drawto.data[offset + 3] = 0;
+ greyto.data[offset + 3] = 0;
+ }
+ function countNeighbours(x, y) {
+ return (
+ getCell(x - 1, y - 1) +
+ getCell(x, y - 1) +
+ getCell(x + 1, y - 1) +
+ getCell(x - 1, y) +
+ getCell(x + 1, y) +
+ getCell(x - 1, y + 1) +
+ getCell(x, y + 1) +
+ getCell(x + 1, y + 1)
+ );
+ }
+ function flip() {
+ var temp = frame;
+ context.putImageData(drawto, 5, 5);
+ context.putImageData(greyto, 5 - width, 5 - height); /* top left */
+ context.putImageData(greyto, 5 - width, 5); /* left */
+ context.putImageData(greyto, 5, 5 - height); /* top */
+ context.putImageData(greyto, 5 + width, 5 + height); /* bottom right */
+ context.putImageData(greyto, 5 + width, 5); /* right */
+ context.putImageData(greyto, 5, 5 + height); /* bottom */
+ context.putImageData(greyto, 5 + width, 5 - height); /* top right */
+ context.putImageData(greyto, 5 - width, 5 + height); /* bottom left */
+ frame = drawto;
+ drawto = temp;
+ }
+ /* Game of life is run on a timer */
+ setInterval(function () {
+ if (!running.checked) {
+ return;
+ }
+ console.log("Frame");
+ /* To do a frame of GoL we compute by consuming frame and writing to drawto */
+ for (var y = 0; y < height; y++) {
+ for (var x = 0; x < width; x++) {
+ const neighbours = countNeighbours(x, y);
+ if (getCell(x, y)) {
+ if (neighbours == 2 || neighbours == 3) {
+ setCell(x, y); // live, 2/3 neigh => stay alive
+ } else {
+ clearCell(x, y); // live, <2/>3 neigh => dies
+ }
+ } else {
+ if (neighbours == 3) {
+ setCell(x, y); // dead, 3 neigh => born
+ } else {
+ clearCell(x, y); // dead, !3 neigh => stay dead
+ }
+ }
+ }
+ }
+ flip();
+ }, 100);
+ const randomise = function () {
+ var ofs = 3;
+ for (var y = 0; y < height; y++) {
+ for (var x = 0; x < width; x++) {
+ if (Math.random() < 0.5) {
+ drawto.data[ofs] = 0;
+ } else {
+ drawto.data[ofs] = 255;
+ greyto.data[ofs] = greylevel;
+ }
+ ofs += 4;
+ }
+ }
+ flip();
+ };
+ document.getElementById("random").addEventListener("click", randomise);
+ document
+ .getElementById("commitsize")
+ .addEventListener("click", function () {
+ const iwval = parseInt(iwidth.value, 10);
+ const ihval = parseInt(iheight.value, 10);
+ console.log(width, height, "->", iwval, ihval);
+ if (
+ (iwval != width || ihval != height) &&
+ iwval >= 10 &&
+ iwval <= 200 &&
+ ihval >= 10 &&
+ ihval <= 200
+ ) {
+ console.log("yes");
+ surface.height = ihval + 10;
+ context.height = ihval + 10;
+ height = ihval;
+ surface.width = iwval + 10;
+ context.width = iwval + 10;
+ width = iwval;
+ frame = context.createImageData(width, height);
+ drawto = context.createImageData(width, height);
+ greyto = context.createImageData(width, height);
+ resetGrey();
+ randomise();
+ }
+ });
+ randomise();
+ })();
+ </script>
+</html>
diff --git a/test/js/mandelbrot.html b/test/js/mandelbrot.html
new file mode 100644
index 000000000..38f77eff5
--- /dev/null
+++ b/test/js/mandelbrot.html
@@ -0,0 +1,31 @@
+<html>
+ <head>
+ <title>JS Mandelbrot</title>
+ <script src="https://nerget.com/mandelbrot.js"></script>
+ <script>
+ var drawn = false;
+ var dimension = 2;
+ var cx = -dimension / 2 + 0.5;
+ var cy = -dimension / 2;
+
+ function log(msg) {
+ document.getElementById("log").innerHTML += msg + "<br/>";
+ }
+
+ function draw() {
+ var forceSlowPath = document.getElementById('forceSlowPath').checked;
+ drawMandelbrot(document.getElementById('canvas').getContext('2d'), 200, 200,
+ cx + dimension / 2, cy + dimension / 2, dimension, 500, forceSlowPath);
+ drawn = true;
+ }
+
+ </script>
+ </head>
+ <body>
+ <canvas id="canvas" width="200" height="200" style="border: 1px solid black;"></canvas>
+ <br />
+ <input id="forceSlowPath" type="checkbox">Use slow path.</input> <br />
+ <a href="javascript:draw()">Start</a>
+ <div id="log"></div>
+ </body>
+</html>
diff --git a/test/messages.c b/test/messages.c
index ae82d1ede..3ec770a56 100644
--- a/test/messages.c
+++ b/test/messages.c
@@ -118,8 +118,7 @@ START_TEST(message_get_buff_test)
ck_assert_int_eq(res, NSERROR_OK);
buf = messages_get_buff("DefinitelyNotAKey");
- ck_assert_str_eq(buf, "DefinitelyNotAKey");
- free(buf);
+ ck_assert(buf == NULL);
buf = messages_get_buff("NoMemory");
ck_assert_str_eq(buf, "NetSurf is running out of memory. Please free some memory and try again.");
diff --git a/test/monkey-see-monkey-do b/test/monkey-see-monkey-do
index 8de29fa53..72b8685ec 100755
--- a/test/monkey-see-monkey-do
+++ b/test/monkey-see-monkey-do
@@ -1,26 +1,52 @@
#!/usr/bin/python3
-# If you have any poo, fling it now!
+'''
+NetSurf automated test runner
-BASE_PATH="https://test.netsurf-browser.org/cgi-bin/monkey-index.cgi"
-MONKEY_PATH="./nsmonkey"
+This script retrives a test plan from the NetSurf infrastructure and
+ executes it using the monkey frontend
+'''
-# Otherwise let's begin...
+# If you have any poo, fling it now!
import sys
import getopt
-import yaml
-
import multiprocessing as mp
-
-from urllib import request
+from urllib import request, parse
from io import StringIO
-
+import yaml
import monkey_driver as driver
+# Otherwise let's begin...
+
+BASE_PATH = "https://test.netsurf-browser.org/cgi-bin/monkey-index.cgi"
+MONKEY_PATH = "./nsmonkey"
+
mp.set_start_method('fork')
-def child_run_test(parts):
+def decode_trace_line(l):
+ from re import findall, match
+ from subprocess import getstatusoutput
+
+ caps = findall(r'./nsmonkey\(\+(0x[0-9a-f]+)\)', l);
+ if not caps:
+ return l
+
+ exitcode, output = getstatusoutput(
+ "addr2line -e {} -a -p -f -C {} 2>/dev/null".format(
+ MONKEY_PATH, caps[0]))
+ if exitcode != 0:
+ return './nsmonkey(+{})'.format(caps[0])
+
+ m = match(r'0x(.+): (.+) at (.+):(.+)', output)
+
+ return '{}:{}({})[0x{}]'.format(
+ m.group(3), m.group(4), m.group(2), m.group(1))
+
+def decode_trace(s):
+ return "\n".join(decode_trace_line(l) for l in s.split("\n"))
+
+def child_run_test(verbose, parts):
outcapture = StringIO()
errcapture = StringIO()
oldout = sys.stdout
@@ -34,29 +60,31 @@ def child_run_test(parts):
sys.stderr = olderr
print("FAIL:")
print("STDOUT:\n{}\n".format(outcapture.getvalue()))
- print("STDERR:\n{}\n".format(errcapture.getvalue()))
+ print("STDERR:\n{}\n".format(decode_trace(errcapture.getvalue())))
print("RERAISE:")
raise
else:
sys.stdout = oldout
sys.stderr = olderr
- if verbose == True:
+ if verbose:
print("STDOUT:\n{}\n".format(outcapture.getvalue()))
-def run_test(parts):
- p = mp.Process(target=child_run_test, args=(parts, ))
+def run_test(verbose, parts):
+ p = mp.Process(target=child_run_test, args=(verbose, parts, ))
p.start()
p.join()
return p.exitcode
def print_usage():
print('Usage:')
- print(' ' + sys.argv[0] + ' [-v] [-h]')
+ print(' ' + sys.argv[0] + ' [-v] [-h] [-d <division>] [-g group]')
def parse_argv(argv):
- verbose=False
+ verbose = False
+ division = None
+ group = None
try:
- opts, args = getopt.getopt(argv,"hv",[])
+ opts, args = getopt.getopt(argv, "hvd:g:", [])
except getopt.GetoptError:
print_usage()
sys.exit(2)
@@ -65,32 +93,51 @@ def parse_argv(argv):
print_usage()
sys.exit()
elif opt in ("-v", "--verbose"):
- verbose=True
- return verbose
-
-verbose = parse_argv(sys.argv[1:])
-
-print("Fetching tests...")
-index = request.urlopen(BASE_PATH)
-index = index.read()
-print("Parsing tests...")
-test_set = yaml.load_all(index)
-
-print("Running tests...")
-ret = 0
-for test in test_set:
- if test["kind"] == 'group':
- print("Start group: {}".format(test["group"]))
- print(" [ {} ]".format(test["description"]))
- elif test["kind"] == 'test':
- print(" => Run test: {}".format(test["filename"]))
- ret = run_test(test["content"])
- if ret != 0:
- break
-
-if ret != 0:
- print("FAIL")
- sys.exit(1)
-else:
- print("PASS")
- sys.exit(0)
+ verbose = True
+ elif opt == '-d':
+ division = arg
+ elif opt == '-g':
+ group = arg
+
+ return verbose, division, group
+
+def main():
+ verbose, division, group = parse_argv(sys.argv[1:])
+
+ print("Fetching tests...")
+ data_dict = {}
+ if division is not None:
+ data_dict['division'] = division
+ if group is not None:
+ data_dict['group'] = group
+
+ data = parse.urlencode(data_dict).encode()
+ req = request.Request(BASE_PATH, data=data)
+ index = request.urlopen(req)
+ index = index.read()
+
+ print("Parsing tests...")
+ test_set = yaml.load_all(index, Loader=yaml.SafeLoader)
+
+ print("Running tests...")
+ ret = 0
+ for test in test_set:
+ if test["kind"] == 'group':
+ print("Start group: {}".format(test["group"]))
+ print(" [ {} ]".format(test["description"]))
+ elif test["kind"] == 'test':
+ print(" => Run test: {}".format(test["filename"]))
+ ret = run_test(verbose, test["content"])
+ if ret != 0:
+ break
+
+ if ret != 0:
+ print("FAIL")
+ sys.exit(1)
+ else:
+ print("PASS")
+ sys.exit(0)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/test/monkey-tests/start-stop-no-js.yaml b/test/monkey-tests/start-stop-no-js.yaml
index 0a681cffc..028e08f8e 100644
--- a/test/monkey-tests/start-stop-no-js.yaml
+++ b/test/monkey-tests/start-stop-no-js.yaml
@@ -1,8 +1,7 @@
title: start and stop browser without JS
-group: basic
+group: initial
steps:
- action: launch
- args:
+ options:
- enable_javascript=0
- action: quit
-
diff --git a/test/monkey-tests/state-test.yaml b/test/monkey-tests/state-test.yaml
new file mode 100644
index 000000000..6f25a78d4
--- /dev/null
+++ b/test/monkey-tests/state-test.yaml
@@ -0,0 +1,69 @@
+title: Page state info test
+group: basic
+steps:
+- action: launch
+ language: en
+- action: window-new
+ tag: win1
+- action: navigate
+ window: win1
+ url: about:config
+- action: block
+ conditions:
+ - window: win1
+ status: complete
+- action: page-info-state
+ window: win1
+ match: INTERNAL
+- action: navigate
+ window: win1
+ url: file:///
+- action: block
+ conditions:
+ - window: win1
+ status: complete
+- action: page-info-state
+ window: win1
+ match: LOCAL
+- action: navigate
+ window: win1
+ url: http://test.netsurf-browser.org/html/trivial-document.html
+- action: block
+ conditions:
+ - window: win1
+ status: complete
+- action: page-info-state
+ window: win1
+ match: INSECURE
+- action: navigate
+ window: win1
+ url: https://test.netsurf-browser.org/html/trivial-document.html
+- action: block
+ conditions:
+ - window: win1
+ status: complete
+- action: page-info-state
+ window: win1
+ match: SECURE
+- action: navigate
+ window: win1
+ url: https://test.netsurf-browser.org/html/trivial-document-with-png.html
+- action: block
+ conditions:
+ - window: win1
+ status: complete
+- action: page-info-state
+ window: win1
+ match: SECURE
+- action: navigate
+ window: win1
+ url: https://test.netsurf-browser.org/html/trivial-document-with-http-png.html
+- action: block
+ conditions:
+ - window: win1
+ status: complete
+- action: page-info-state
+ window: win1
+ match: SECURE_ISSUES
+- action: quit
+
diff --git a/test/monkey_driver.py b/test/monkey_driver.py
index 7f8a430c0..9b810d2a6 100755
--- a/test/monkey_driver.py
+++ b/test/monkey_driver.py
@@ -22,6 +22,7 @@ runs tests in monkey as defined in a yaml file
# pylint: disable=locally-disabled, missing-docstring
+import os
import sys
import getopt
import time
@@ -34,7 +35,6 @@ class DriverBrowser(Browser):
def __init__(self, *args, **kwargs):
super(DriverBrowser, self).__init__(*args, **kwargs)
self.auth = []
- self.cert = []
def add_auth(self, url, realm, username, password):
self.auth.append((url, realm, username, password))
@@ -86,46 +86,6 @@ class DriverBrowser(Browser):
print("401: No candidate found, cancelling login box")
logwin.destroy()
- def add_cert(self, url):
- # add sll certificate error exception
- self.cert.append(url)
-
- def remove_cert(self, url):
- keep = []
-
- def matches(first, second):
- if first is None or second is None:
- return True
- return first == second
-
- for iurl in self.cert:
- if not matches(url, iurl):
- keep.append(iurl)
- self.cert = keep
-
- def handle_ready_sslcert(self, cwin):
-
- def matches(first, second):
- if first is None or second is None:
- return True
- return first == second
-
- candidates = []
- for url in self.cert:
- score = 0
- if matches(url, cwin.url):
- score += 1
- if score > 0:
- candidates.append((score, url))
- if candidates:
- candidates.sort()
- (score, url) = candidates[-1]
- print("SSLCert: Found candidate {} with score {}".format(url, score))
- cwin.go()
- else:
- print("SSLCert: No candidate found, cancelling sslcert box")
- cwin.destroy()
-
def print_usage():
print('Usage:')
@@ -174,7 +134,7 @@ def load_test_plan(path):
plan = []
with open(path, 'r') as stream:
try:
- plan = (yaml.load(stream))
+ plan = (yaml.load(stream, Loader=yaml.CSafeLoader))
except Exception as exc:
print(exc)
return plan
@@ -211,18 +171,20 @@ def conds_met(ctx, conds):
elif 'window' in cond.keys():
status = cond['status']
window = cond['window']
- assert status == "complete" # TODO: Add more status support?
+ assert status == "complete" or status == "loading" # TODO: Add more status support?
if window == "*all*":
- # all windows must be not throbbing
+ # all windows must be complete, or any still loading
throbbing = False
for win in ctx['windows'].items():
if win[1].throbbing:
throbbing = True
- if not throbbing:
+ # throbbing and want loading => true
+ # not throbbing and want complete => true
+ if (status == "loading") == throbbing:
return True
else:
win = ctx['windows'][window]
- if win.throbbing is False:
+ if win.throbbing == (status == "loading"):
return True
else:
raise AssertionError("Unknown condition: {}".format(repr(cond)))
@@ -232,14 +194,35 @@ def conds_met(ctx, conds):
def run_test_step_action_launch(ctx, step):
print(get_indent(ctx) + "Action: " + step["action"])
+
+ # ensure browser is not already launched
assert ctx.get('browser') is None
assert ctx.get('windows') is None
+
+ # build command line switches list
+ monkey_cmd = [ctx["monkey"]]
+ for option in step.get('launch-options', []):
+ monkey_cmd.append("--{}".format(option))
+ print(get_indent(ctx) + " " + "Command line: " + repr(monkey_cmd))
+
+ # build command environment
+ monkey_env = os.environ.copy()
+ for envkey, envvalue in step.get('environment', {}).items():
+ monkey_env[envkey] = envvalue
+ print(get_indent(ctx) + " " + envkey + "=" + envvalue)
+ if 'language' in step.keys():
+ monkey_env['LANGUAGE'] = step['language']
+
+ # create browser object
ctx['browser'] = DriverBrowser(
- monkey_cmd=[ctx["monkey"]],
+ monkey_cmd=monkey_cmd,
+ monkey_env=monkey_env,
quiet=True,
wrapper=ctx.get("wrapper"))
assert_browser(ctx)
ctx['windows'] = dict()
+
+ # set user options
for option in step.get('options', []):
print(get_indent(ctx) + " " + option)
ctx['browser'].pass_options(option)
@@ -265,7 +248,7 @@ def run_test_step_action_window_close(ctx, step):
tag = step['window']
assert ctx['windows'].get(tag) is not None
win = ctx['windows'].pop(tag)
- timeout = int(step.get('timeout', 5))
+ timeout = int(step.get('timeout', 30))
win.kill()
win.wait_until_dead(timeout=timeout)
assert not win.alive
@@ -311,7 +294,7 @@ def run_test_step_action_reload(ctx, step):
def run_test_step_action_sleep_ms(ctx, step):
print(get_indent(ctx) + "Action: " + step["action"])
- conds = step['conditions']
+ conds = step.get('conditions', {})
sleep_time = step['time']
sleep = 0
have_repeat = False
@@ -352,32 +335,50 @@ def run_test_step_action_repeat(ctx, step):
print(get_indent(ctx) + "Action: " + step["action"])
tag = step['tag']
assert ctx['repeats'].get(tag) is None
+ # initialise the loop continue conditional
ctx['repeats'][tag] = {"loop": True, }
- if 'min' in step.keys():
- ctx['repeats'][tag]["i"] = step["min"]
- else:
- ctx['repeats'][tag]["i"] = 0
-
- if 'step' in step.keys():
- ctx['repeats'][tag]["step"] = step["step"]
- else:
- ctx['repeats'][tag]["step"] = 1
-
if 'values' in step.keys():
+ # value iterator
ctx['repeats'][tag]['values'] = step["values"]
+ ctx['repeats'][tag]["max"] = len(step["values"])
+ ctx['repeats'][tag]["i"] = 0
+ ctx['repeats'][tag]["step"] = 1
else:
+ # numeric iterator
ctx['repeats'][tag]['values'] = None
+ if 'min' in step.keys():
+ ctx['repeats'][tag]["i"] = step["min"]
+ else:
+ ctx['repeats'][tag]["i"] = 0
+
+ if 'step' in step.keys():
+ ctx['repeats'][tag]["step"] = step["step"]
+ else:
+ ctx['repeats'][tag]["step"] = 1
+
+ if 'max' in step.keys():
+ ctx['repeats'][tag]["max"] = step["max"]
+ else:
+ ctx['repeats'][tag]["max"] = None
+
while ctx['repeats'][tag]["loop"]:
ctx['repeats'][tag]["start"] = time.time()
ctx["depth"] += 1
+
+ # run through steps for this iteration
for stp in step["steps"]:
run_test_step(ctx, stp)
+
+ # increment iterator
ctx['repeats'][tag]["i"] += ctx['repeats'][tag]["step"]
- if ctx['repeats'][tag]['values'] is not None:
- if ctx['repeats'][tag]["i"] >= len(ctx['repeats'][tag]['values']):
+
+ # check for end condition
+ if ctx['repeats'][tag]["max"] is not None:
+ if ctx['repeats'][tag]["i"] >= ctx['repeats'][tag]["max"]:
ctx['repeats'][tag]["loop"] = False
+
ctx["depth"] -= 1
@@ -435,13 +436,26 @@ def run_test_step_action_plot_check(ctx, step):
print(get_indent(ctx) + "Action: " + step["action"])
assert_browser(ctx)
win = ctx['windows'][step['window']]
+
+ if 'area' in step.keys():
+ if step["area"] == "extent":
+ # ought to capture the extent updates and use that, instead use a
+ # big area and have the browser clip it
+ area=["0","0","1000","1000000"]
+ else:
+ area = [step["area"]]
+ else:
+ area = None
+
+ # get the list of checks
if 'checks' in step.keys():
checks = step['checks']
else:
checks = {}
+
all_text_list = []
bitmaps = []
- for plot in win.redraw():
+ for plot in win.redraw(coords=area):
if plot[0] == 'TEXT':
all_text_list.extend(plot[6:])
if plot[0] == 'BITMAP':
@@ -536,23 +550,6 @@ def run_test_step_action_remove_auth(ctx, step):
step.get("username"), step.get("password"))
-def run_test_step_action_add_cert(ctx, step):
- print(get_indent(ctx) + "Action:" + step["action"])
- assert_browser(ctx)
- browser = ctx['browser']
- browser.add_cert(step.get("url"))
-
-
-def run_test_step_action_remove_cert(ctx, step):
-
- # pylint: disable=locally-disabled, invalid-name
-
- print(get_indent(ctx) + "Action:" + step["action"])
- assert_browser(ctx)
- browser = ctx['browser']
- browser.remove_cert(step.get("url"))
-
-
def run_test_step_action_clear_log(ctx, step):
print(get_indent(ctx) + "Action: " + step["action"])
assert_browser(ctx)
@@ -588,11 +585,23 @@ def run_test_step_action_js_exec(ctx, step):
win.js_exec(cmd)
+def run_test_step_action_page_info_state(ctx, step):
+ print(get_indent(ctx) + "Action: " + step["action"])
+ assert_browser(ctx)
+ tag = step['window']
+ win = ctx['windows'].get(tag)
+ assert win is not None
+ match = step['match']
+ assert win.page_info_state == match
+
+
def run_test_step_action_quit(ctx, step):
print(get_indent(ctx) + "Action: " + step["action"])
assert_browser(ctx)
browser = ctx.pop('browser')
assert browser.quit_and_wait()
+ # clean up context as all windows have gone away after browser quit
+ ctx.pop('windows')
STEP_HANDLERS = {
@@ -614,11 +623,11 @@ STEP_HANDLERS = {
"wait-loading": run_test_step_action_wait_loading,
"add-auth": run_test_step_action_add_auth,
"remove-auth": run_test_step_action_remove_auth,
- "add-cert": run_test_step_action_add_cert,
- "remove-cert": run_test_step_action_remove_cert,
"clear-log": run_test_step_action_clear_log,
"wait-log": run_test_step_action_wait_log,
"js-exec": run_test_step_action_js_exec,
+ "page-info-state":
+ run_test_step_action_page_info_state,
"quit": run_test_step_action_quit,
}
diff --git a/test/monkeyfarmer.py b/test/monkeyfarmer.py
index dcc32175f..905fd9a81 100644
--- a/test/monkeyfarmer.py
+++ b/test/monkeyfarmer.py
@@ -32,16 +32,58 @@ import socket
import subprocess
import time
import errno
+import sys
+
+class StderrEcho(asyncore.dispatcher):
+ def __init__(self, sockend):
+ asyncore.dispatcher.__init__(self, sock=sockend)
+ self.incoming = b""
+
+ def handle_connect(self):
+ pass
+
+ def handle_close(self):
+ # the pipe to the monkey process has closed
+ self.close()
+
+ def handle_read(self):
+ try:
+ got = self.recv(8192)
+ if not got:
+ return
+ except socket.error as error:
+ if error.errno == errno.EAGAIN or error.errno == errno.EWOULDBLOCK:
+ return
+ else:
+ raise
+
+ self.incoming += got
+ if b"\n" in self.incoming:
+ lines = self.incoming.split(b"\n")
+ self.incoming = lines.pop()
+ for line in lines:
+ try:
+ line = line.decode('utf-8')
+ except UnicodeDecodeError:
+ print("WARNING: Unicode decode error")
+ line = line.decode('utf-8', 'replace')
+
+ sys.stderr.write("{}\n".format(line))
+
class MonkeyFarmer(asyncore.dispatcher):
# pylint: disable=locally-disabled, too-many-instance-attributes
- def __init__(self, monkey_cmd, online, quiet=False, *, wrapper=None):
+ def __init__(self, monkey_cmd, monkey_env, online, quiet=False, *, wrapper=None):
(mine, monkeys) = socket.socketpair()
asyncore.dispatcher.__init__(self, sock=mine)
+ (mine2, monkeyserr) = socket.socketpair()
+
+ self._errwrapper = StderrEcho(mine2)
+
if wrapper is not None:
new_cmd = list(wrapper)
new_cmd.extend(monkey_cmd)
@@ -49,11 +91,14 @@ class MonkeyFarmer(asyncore.dispatcher):
self.monkey = subprocess.Popen(
monkey_cmd,
+ env=monkey_env,
stdin=monkeys,
stdout=monkeys,
- close_fds=[mine])
+ stderr=monkeyserr,
+ close_fds=[mine, mine2])
monkeys.close()
+ monkeyserr.close()
self.buffer = b""
self.incoming = b""
@@ -115,7 +160,11 @@ class MonkeyFarmer(asyncore.dispatcher):
self.buffer += cmd.encode('utf-8')
def monkey_says(self, line):
- line = line.decode('utf-8')
+ try:
+ line = line.decode('utf-8')
+ except UnicodeDecodeError:
+ print("WARNING: Unicode decode error")
+ line = line.decode('utf-8', 'replace')
if not self.quiet:
print("<<< {}".format(line))
self.discussion.append(("<", line))
@@ -158,15 +207,15 @@ class Browser:
# pylint: disable=locally-disabled, too-many-instance-attributes, dangerous-default-value, invalid-name
- def __init__(self, monkey_cmd=["./nsmonkey"], quiet=False, *, wrapper=None):
+ def __init__(self, monkey_cmd=["./nsmonkey"], monkey_env=None, quiet=False, *, wrapper=None):
self.farmer = MonkeyFarmer(
monkey_cmd=monkey_cmd,
+ monkey_env=monkey_env,
online=self.on_monkey_line,
quiet=quiet,
wrapper=wrapper)
self.windows = {}
self.logins = {}
- self.sslcerts = {}
self.current_draw_target = None
self.started = False
self.stopped = False
@@ -238,18 +287,6 @@ class Browser:
if win.alive and win.ready:
self.handle_ready_login(win)
- def handle_SSLCERT(self, action, _lwin, winid, *args):
- if action == "VERIFY":
- new_win = SSLCertWindow(self, winid, *args)
- self.sslcerts[winid] = new_win
- self.handle_ready_sslcert(new_win)
- else:
- win = self.sslcerts.get(winid, None)
- if win is None:
- print(" Unknown ssl cert window id {}".format(winid))
- else:
- win.handle(action, *args)
-
def handle_PLOT(self, *args):
if self.current_draw_target is not None:
self.current_draw_target.handle_plot(*args)
@@ -272,44 +309,6 @@ class Browser:
# Override this method to do useful stuff
lwin.destroy()
- def handle_ready_sslcert(self, cwin):
-
- # pylint: disable=locally-disabled, no-self-use
-
- # Override this method to do useful stuff
- cwin.destroy()
-
-
-class SSLCertWindow:
-
- # pylint: disable=locally-disabled, invalid-name
-
- def __init__(self, browser, winid, _url, *url):
- self.alive = True
- self.browser = browser
- self.winid = winid
- self.url = " ".join(url)
-
- def handle(self, action, _str="STR"):
- if action == "DESTROY":
- self.alive = False
- else:
- raise AssertionError("Unknown action {} for sslcert window".format(action))
-
- def _wait_dead(self):
- while self.alive:
- self.browser.farmer.loop(once=True)
-
- def go(self):
- assert self.alive
- self.browser.farmer.tell_monkey("SSLCERT GO {}".format(self.winid))
- self._wait_dead()
-
- def destroy(self):
- assert self.alive
- self.browser.farmer.tell_monkey("SSLCERT DESTROY {}".format(self.winid))
- self._wait_dead()
-
class LoginWindow:
@@ -406,6 +405,7 @@ class BrowserWindow:
self.plotted = []
self.plotting = False
self.log_entries = []
+ self.page_info_state = "UNKNOWN"
def kill(self):
self.browser.farmer.tell_monkey("WINDOW DESTROY %s" % self.winid)
@@ -415,6 +415,10 @@ class BrowserWindow:
while self.alive:
self.browser.farmer.loop(once=True)
if (time.time() - now) > timeout:
+ print("*** Timed out waiting for window to be destroyed")
+ print("*** URL was: {}".format(self.url))
+ print("*** Title was: {}".format(self.title))
+ print("*** Status was: {}".format(self.status))
break
def go(self, url, referer=None):
@@ -519,6 +523,9 @@ class BrowserWindow:
def handle_window_CONSOLE_LOG(self, _src, src, folding, level, *msg):
self.log_entries.append((src, folding == "FOLDABLE", level, " ".join(msg)))
+ def handle_window_PAGE_STATUS(self, _status, status):
+ self.page_info_state = status
+
def load_page(self, url=None, referer=None):
if url is not None:
self.go(url, referer)
@@ -622,9 +629,6 @@ def farmer_test():
lwin.send_password("bar")
lwin.go()
- def handle_ready_sslcert(self, cwin):
- cwin.destroy()
-
fbbrowser = FooBarLogin(quiet=True)
win = fbbrowser.new_window()
win.load_page("https://httpbin.org/basic-auth/foo/bar")
diff --git a/test/nsoption.c b/test/nsoption.c
index 8f2388a5b..33da1f7e0 100644
--- a/test/nsoption.c
+++ b/test/nsoption.c
@@ -33,6 +33,10 @@
#include "utils/log.h"
#include "utils/nsoption.h"
+#ifndef TESTROOT
+#define TESTROOT "/tmp"
+#endif
+
const char *test_choices_path = "test/data/Choices";
const char *test_choices_short_path = "test/data/Choices-short";
const char *test_choices_all_path = "test/data/Choices-all";
@@ -49,7 +53,9 @@ static char *testnam(char *out)
{
static int count = 0;
static char name[64];
- snprintf(name, 64, "/tmp/nsoptiontest%d", count);
+ int pid;
+ pid=getpid();
+ snprintf(name, 64, TESTROOT"/nsoptiontest%d%d", pid, count);
count++;
return name;
}
@@ -241,7 +247,7 @@ struct format_test_vec_s format_test_vec[] = {
},
{
NSOPTION_sys_colour_ActiveBorder,
- "<tr><th>sys_colour_ActiveBorder</th><td>colour</td><td>default</td><td><span style=\"background-color: #d3d3d3; color: #000000; font-family:Monospace; \">#D3D3D3</span></td></tr>",
+ "<tr><th>sys_colour_ActiveBorder</th><td>colour</td><td>default</td><td><span style=\"font-family:Monospace;\">#D3D3D3</span> <span style=\"background-color: #d3d3d3; border: 1px solid #000000; display: inline-block; width: 1em; height: 1em;\"></span></td></tr>",
"sys_colour_ActiveBorder:d3d3d3"
},
};
diff --git a/test/utils.c b/test/utils.c
index 3d5319a28..9fe6747c3 100644
--- a/test/utils.c
+++ b/test/utils.c
@@ -37,22 +37,31 @@
#define SLEN(x) (sizeof((x)) - 1)
struct test_pairs {
- const unsigned long test;
+ const unsigned long long int test;
const char* res;
};
static const struct test_pairs human_friendly_bytesize_test_vec[] = {
- { 0, "0.00Bytes" },
- { 1024, "1024.00Bytes" },
- { 1025, "1.00kBytes" },
- { 1048576, "1024.00kBytes" },
- { 1048577, "1.00MBytes" },
- { 1073741824, "1024.00MBytes" },
- { 1073741888, "1024.00MBytes" }, /* spot the rounding error */
- { 1073741889, "1.00GBytes" },
- { 2147483648, "2.00GBytes" },
- { 3221225472, "3.00GBytes" },
- { 4294967295, "4.00GBytes" },
+ { 0ULL, "0Bytes" },
+ { 0x2AULL, "42Bytes" },
+ { 0x400ULL, "1024Bytes" },
+ { 0x401ULL, "1.00KiBytes" },
+ { 0xA9AEULL, "42.42KiBytes" },
+ { 0x100000ULL, "1024.00KiBytes" },
+ { 0x100001ULL, "1.00MiBytes" },
+ { 0x2A6B852ULL, "42.42MiBytes" },
+ { 0x40000000ULL, "1024.00MiBytes" },
+ { 0x40000001ULL, "1.00GiBytes" },
+ { 0x80000000ULL, "2.00GiBytes" },
+ { 0xC0000000ULL, "3.00GiBytes" },
+ { 0x100000000ULL, "4.00GiBytes" },
+ { 0x10000000000ULL, "1024.00GiBytes" },
+ { 0x10000000001ULL, "1.00TiBytes" },
+ { 0x4000000000000ULL, "1024.00TiBytes" },
+ { 0x4000000000001ULL, "1.00PiBytes" },
+ { 0x1000000000000000ULL, "1024.00PiBytes" },
+ { 0x1000000000000100ULL, "1.00EiBytes" }, /* precision loss */
+ { 0xFFFFFFFFFFFFFFFFULL, "16.00EiBytes" },
};
/**