netsurf/test/bloom.c

248 lines
4.7 KiB
C

/*
* Copyright 2015 Vincent Sanders <vince@netsurf-browser.org>
* Copyright 2013 Rob Kendrick <rjek@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
* Test bloom filter operations.
*
* Implementation taken from original test rig in bloom filter code
*/
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <check.h>
#include "utils/bloom.h"
#define BLOOM_SIZE 8192
#define FALSE_POSITIVE_RATE 15 /* acceptable false positive percentage rate */
static struct bloom_filter *dict_bloom;
/* Fixtures */
/**
* create dictionary bloom
*
* bloom constructed from the first BLOOM_SIZE entries of the
* dictionary
*/
static void dict_bloom_create(void)
{
FILE *dictf;
char buf[BUFSIZ];
int i;
dictf = fopen("/usr/share/dict/words", "r");
ck_assert(dictf != NULL);
dict_bloom = bloom_create(BLOOM_SIZE);
ck_assert(dict_bloom != NULL);
for (i = 0; i < BLOOM_SIZE; i++) {
fscanf(dictf, "%s", buf);
bloom_insert_str(dict_bloom, buf, strlen(buf));
}
fclose(dictf);
}
static void dict_bloom_teardown(void)
{
bloom_destroy(dict_bloom);
}
/* Tests */
/**
* Test blooom filter creation
*
* Create a bloom filter, add a single entry and test for presece and
* absence of that entry (single entry cannot have false positives).
*
*/
START_TEST(bloom_create_test)
{
struct bloom_filter *b;
b = bloom_create(BLOOM_SIZE);
ck_assert(b != NULL);
bloom_insert_str(b, "NetSurf", 7);
ck_assert(bloom_search_str(b, "NetSurf", 7));
ck_assert(!bloom_search_str(b, "NotSurf", 7));
ck_assert(bloom_items(b) == 1);
bloom_destroy(b);
}
END_TEST
/**
* insert empty string test
*/
START_TEST(bloom_insert_empty_str_test)
{
struct bloom_filter *b;
b = bloom_create(BLOOM_SIZE);
ck_assert(b != NULL);
bloom_insert_str(b, NULL, 7);
ck_assert(bloom_items(b) == 1);
bloom_destroy(b);
}
END_TEST
/**
* Basic API creation test case
*/
static TCase *bloom_api_case_create(void)
{
TCase *tc;
tc = tcase_create("Creation");
tcase_add_test(tc, bloom_create_test);
tcase_add_test(tc, bloom_insert_empty_str_test);
return tc;
}
START_TEST(bloom_match_test)
{
FILE *dictf;
char buf[BUFSIZ];
int i;
dictf = fopen("/usr/share/dict/words", "r");
ck_assert(dictf != NULL);
for (i = 0; i < BLOOM_SIZE; i++) {
fscanf(dictf, "%s", buf);
ck_assert(bloom_search_str(dict_bloom, buf, strlen(buf)));
}
fclose(dictf);
}
END_TEST
/**
* Matching entry test case
*/
static TCase *bloom_match_case_create(void)
{
TCase *tc;
tc = tcase_create("Match");
tcase_add_checked_fixture(tc,
dict_bloom_create,
dict_bloom_teardown);
tcase_add_test(tc, bloom_match_test);
return tc;
}
START_TEST(bloom_falsepositive_test)
{
FILE *dictf;
char buf[BUFSIZ];
int i;
int false_positives = 0;
dictf = fopen("/usr/share/dict/words", "r");
ck_assert(dictf != NULL);
/* skip elements known presnent */
for (i = 0; i < BLOOM_SIZE; i++) {
fscanf(dictf, "%s", buf);
}
/* false positives are possible we are checking for low rate */
for (i = 0; i < BLOOM_SIZE; i++) {
fscanf(dictf, "%s", buf);
if (bloom_search_str(dict_bloom, buf, strlen(buf)) == true)
false_positives++;
}
fclose(dictf);
printf("false positive rate %d%%/%d%%\n",
(false_positives * 100)/BLOOM_SIZE,
FALSE_POSITIVE_RATE);
ck_assert(false_positives < ((BLOOM_SIZE * FALSE_POSITIVE_RATE) / 100));
}
END_TEST
/**
* Not matching test case
*/
static TCase *bloom_rate_case_create(void)
{
TCase *tc;
tc = tcase_create("False positive rate");
tcase_add_checked_fixture(tc,
dict_bloom_create,
dict_bloom_teardown);
tcase_add_test(tc, bloom_falsepositive_test);
return tc;
}
static Suite *bloom_suite(void)
{
Suite *s;
s = suite_create("Bloom filter");
suite_add_tcase(s, bloom_api_case_create());
suite_add_tcase(s, bloom_match_case_create());
suite_add_tcase(s, bloom_rate_case_create());
return s;
}
int main(int argc, char **argv)
{
int number_failed;
Suite *s;
SRunner *sr;
s = bloom_suite();
sr = srunner_create(s);
srunner_run_all(sr, CK_ENV);
number_failed = srunner_ntests_failed(sr);
srunner_free(sr);
return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
}