#include "maxminddb_test_helper.h"
void test_all_data_types(MMDB_lookup_result_s *result, const char *ip,
const char *UNUSED(filename), const char *mode_desc)
{
{
char description[500];
snprintf(description, 500, "utf8_string field for %s - %s", ip,
mode_desc);
MMDB_entry_data_s data =
data_ok(result, MMDB_DATA_TYPE_UTF8_STRING, description,
"utf8_string", NULL);
const char *string = strndup(data.utf8_string, data.data_size);
// This is hex for "unicode! ☯ - ♫" as bytes
char expect[19] =
{ 0x75, 0x6e, 0x69, 0x63, 0x6f, 0x64, 0x65, 0x21, 0x20, 0xe2, 0x98,
0xaf, 0x20, 0x2d, 0x20, 0xe2, 0x99, 0xab, 0x00 };
is(string, expect, "got expected utf8_string value");
free((char *)string);
}
{
char description[500];
snprintf(description, 500, "double field for %s - %s", ip, mode_desc);
MMDB_entry_data_s data =
data_ok(result, MMDB_DATA_TYPE_DOUBLE, description, "double", NULL);
compare_double(data.double_value, 42.123456);
}
{
char description[500];
snprintf(description, 500, "float field for %s - %s", ip, mode_desc);
MMDB_entry_data_s data =
data_ok(result, MMDB_DATA_TYPE_FLOAT, description, "float", NULL);
compare_float(data.float_value, 1.1F);
}
{
char description[500];
snprintf(description, 500, "bytes field for %s - %s", ip, mode_desc);
MMDB_entry_data_s data =
data_ok(result, MMDB_DATA_TYPE_BYTES, description, "bytes", NULL);
uint8_t expect[] = { 0x00, 0x00, 0x00, 0x2a };
ok(memcmp((uint8_t *)data.bytes, expect, 4) == 0,
"bytes field has expected value");
}
{
char description[500];
snprintf(description, 500, "uint16 field for %s - %s", ip, mode_desc);
MMDB_entry_data_s data =
data_ok(result, MMDB_DATA_TYPE_UINT16, description, "uint16", NULL);
uint16_t expect = 100;
ok(data.uint16 == expect, "uint16 field is 100");
}
{
char description[500];
snprintf(description, 500, "uint32 field for %s - %s", ip, mode_desc);
MMDB_entry_data_s data =
data_ok(result, MMDB_DATA_TYPE_UINT32, description, "uint32", NULL);
uint32_t expect = 1 << 28;
ok(data.uint32 == expect, "uint32 field is 2**28");
}
{
char description[500];
snprintf(description, 500, "int32 field for %s - %s", ip, mode_desc);
MMDB_entry_data_s data =
data_ok(result, MMDB_DATA_TYPE_INT32, description, "int32", NULL);
int32_t expect = 1 << 28;
expect *= -1;
cmp_ok(data.int32, "==", expect, "int32 field is -(2**28)");
}
{
char description[500];
snprintf(description, 500, "uint64 field for %s - %s", ip, mode_desc);
MMDB_entry_data_s data =
data_ok(result, MMDB_DATA_TYPE_UINT64, description, "uint64", NULL);
uint64_t expect = 1;
expect <<= 60;
ok(data.uint64 == expect, "uint64 field is 2**60");
}
{
char description[500];
snprintf(description, 500, "uint128 field for %s - %s", ip, mode_desc);
MMDB_entry_data_s data =
data_ok(result, MMDB_DATA_TYPE_UINT128, description, "uint128",
NULL);
#if MMDB_UINT128_IS_BYTE_ARRAY
uint8_t expect[16] = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
ok(memcmp(data.uint128, expect, 16) == 0, "uint128 field is 2**120");
#else
mmdb_uint128_t expect = 1;
expect <<= 120;
ok(data.uint128 == expect, "uint128 field is 2**120");
#endif
}
{
char description[500];
snprintf(description, 500, "boolean field for %s - %s", ip, mode_desc);
MMDB_entry_data_s data =
data_ok(result, MMDB_DATA_TYPE_BOOLEAN, description, "boolean",
NULL);
cmp_ok(data.boolean, "==", true, "boolean field is true");
}
{
char description[500];
snprintf(description, 500, "array field for %s - %s", ip, mode_desc);
MMDB_entry_data_s data =
data_ok(result, MMDB_DATA_TYPE_ARRAY, description, "array", NULL);
ok(data.data_size == 3, "array field has 3 elements");
snprintf(description, 500, "array[0] for %s - %s", ip, mode_desc);
data =
data_ok(result, MMDB_DATA_TYPE_UINT32, description, "array", "0",
NULL);
ok(data.uint32 == 1, "array[0] is 1");
snprintf(description, 500, "array[1] for %s - %s", ip, mode_desc);
data =
data_ok(result, MMDB_DATA_TYPE_UINT32, description, "array", "1",
NULL);
ok(data.uint32 == 2, "array[1] is 1");
snprintf(description, 500, "array[2] for %s - %s", ip, mode_desc);
data =
data_ok(result, MMDB_DATA_TYPE_UINT32, description, "array", "2",
NULL);
ok(data.uint32 == 3, "array[2] is 1");
}
{
char description[500];
snprintf(description, 500, "map field for %s - %s", ip, mode_desc);
MMDB_entry_data_s data =
data_ok(result, MMDB_DATA_TYPE_MAP, description, "map", NULL);
ok(data.data_size == 1, "map field has 1 element");
snprintf(description, 500, "map{mapX} for %s - %s", ip, mode_desc);
data =
data_ok(result, MMDB_DATA_TYPE_MAP, description, "map", "mapX",
NULL);
ok(data.data_size == 2, "map{mapX} field has 2 elements");
snprintf(description, 500, "map{mapX}{utf8_stringX} for %s - %s", ip,
mode_desc);
data =
data_ok(result, MMDB_DATA_TYPE_UTF8_STRING, description, "map",
"mapX", "utf8_stringX", NULL);
const char *string = strndup(data.utf8_string, data.data_size);
is(string, "hello", "map{mapX}{utf8_stringX} is 'hello'");
free((char *)string);
snprintf(description, 500, "map{mapX}{arrayX} for %s - %s", ip,
mode_desc);
data =
data_ok(result, MMDB_DATA_TYPE_ARRAY, description, "map", "mapX",
"arrayX", NULL);
ok(data.data_size == 3, "map{mapX}{arrayX} field has 3 elements");
snprintf(description, 500, "map{mapX}{arrayX}[0] for %s - %s", ip,
mode_desc);
data =
data_ok(result, MMDB_DATA_TYPE_UINT32, description, "map", "mapX",
"arrayX", "0", NULL);
ok(data.uint32 == 7, "map{mapX}{arrayX}[0] is 7");
snprintf(description, 500, "map{mapX}{arrayX}[1] for %s - %s", ip,
mode_desc);
data =
data_ok(result, MMDB_DATA_TYPE_UINT32, description, "map", "mapX",
"arrayX", "1", NULL);
ok(data.uint32 == 8, "map{mapX}{arrayX}[1] is 8");
snprintf(description, 500, "map{mapX}{arrayX}[2] for %s - %s", ip,
mode_desc);
data =
data_ok(result, MMDB_DATA_TYPE_UINT32, description, "map", "mapX",
"arrayX", "2", NULL);
ok(data.uint32 == 9, "map{mapX}{arrayX}[2] is 9");
}
}
void test_all_data_types_as_zero(MMDB_lookup_result_s *result, const char *ip,
const char *UNUSED(
filename), const char *mode_desc)
{
{
char description[500];
snprintf(description, 500, "utf8_string field for %s - %s", ip,
mode_desc);
MMDB_entry_data_s data =
data_ok(result, MMDB_DATA_TYPE_UTF8_STRING, description,
"utf8_string", NULL);
is(data.utf8_string, "", "got expected utf8_string value (NULL)");
}
{
char description[500];
snprintf(description, 500, "double field for %s - %s", ip, mode_desc);
MMDB_entry_data_s data =
data_ok(result, MMDB_DATA_TYPE_DOUBLE, description, "double", NULL);
compare_double(data.double_value, 0.0);
}
{
char description[500];
snprintf(description, 500, "float field for %s - %s", ip, mode_desc);
MMDB_entry_data_s data =
data_ok(result, MMDB_DATA_TYPE_FLOAT, description, "float", NULL);
compare_float(data.float_value, 0.0F);
}
{
char description[500];
snprintf(description, 500, "bytes field for %s - %s", ip, mode_desc);
MMDB_entry_data_s data =
data_ok(result, MMDB_DATA_TYPE_BYTES, description, "bytes", NULL);
ok(data.data_size == 0, "bytes field data_size is 0");
/* In C does it makes sense to write something like this?
uint8_t expect[0] = {};
ok(memcmp(data.bytes, expect, 0) == 0, "got expected bytes value (NULL)"); */
}
{
char description[500];
snprintf(description, 500, "uint16 field for %s - %s", ip, mode_desc);
MMDB_entry_data_s data =
data_ok(result, MMDB_DATA_TYPE_UINT16, description, "uint16", NULL);
uint16_t expect = 0;
ok(data.uint16 == expect, "uint16 field is 0");
}
{
char description[500];
snprintf(description, 500, "uint32 field for %s - %s", ip, mode_desc);
MMDB_entry_data_s data =
data_ok(result, MMDB_DATA_TYPE_UINT32, description, "uint32", NULL);
uint32_t expect = 0;
ok(data.uint32 == expect, "uint32 field is 0");
}
{
char description[500];
snprintf(description, 500, "int32 field for %s - %s", ip, mode_desc);
MMDB_entry_data_s data =
data_ok(result, MMDB_DATA_TYPE_INT32, description, "int32", NULL);
int32_t expect = 0;
expect *= -1;
cmp_ok(data.int32, "==", expect, "int32 field is 0");
}
{
char description[500];
snprintf(description, 500, "uint64 field for %s - %s", ip, mode_desc);
MMDB_entry_data_s data =
data_ok(result, MMDB_DATA_TYPE_UINT64, description, "uint64", NULL);
uint64_t expect = 0;
ok(data.uint64 == expect, "uint64 field is 0");
}
{
char description[500];
snprintf(description, 500, "uint128 field for %s - %s", ip, mode_desc);
MMDB_entry_data_s data =
data_ok(result, MMDB_DATA_TYPE_UINT128, description, "uint128",
NULL);
#if MMDB_UINT128_IS_BYTE_ARRAY
uint8_t expect[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
ok(memcmp(data.uint128, expect, 16) == 0, "uint128 field is 0");
#else
mmdb_uint128_t expect = 0;
ok(data.uint128 == expect, "uint128 field is 0");
#endif
}
{
char description[500];
snprintf(description, 500, "boolean field for %s - %s", ip, mode_desc);
MMDB_entry_data_s data =
data_ok(result, MMDB_DATA_TYPE_BOOLEAN, description, "boolean",
NULL);
cmp_ok(data.boolean, "==", false, "boolean field is false");
}
{
char description[500];
snprintf(description, 500, "array field for %s - %s", ip, mode_desc);
MMDB_entry_data_s data =
data_ok(result, MMDB_DATA_TYPE_ARRAY, description, "array", NULL);
ok(data.data_size == 0, "array field has 0 elements");
}
{
char description[500];
snprintf(description, 500, "map field for %s - %s", ip, mode_desc);
MMDB_entry_data_s data =
data_ok(result, MMDB_DATA_TYPE_MAP, description, "map", NULL);
ok(data.data_size == 0, "map field has 0 elements");
}
}
void run_tests(int mode, const char *mode_desc)
{
const char *filename = "MaxMind-DB-test-decoder.mmdb";
const char *path = test_database_path(filename);
MMDB_s *mmdb = open_ok(path, mode, mode_desc);
// All of the remaining tests require an open mmdb
if (NULL == mmdb) {
diag("could not open %s - skipping remaining tests", path);
return;
}
free((void *)path);
{
const char *ip = "not an ip";
int gai_error, mmdb_error;
MMDB_lookup_result_s result =
MMDB_lookup_string(mmdb, ip, &gai_error, &mmdb_error);
cmp_ok(gai_error, "==", EAI_NONAME,
"MMDB_lookup populates getaddrinfo error properly - %s", ip);
ok(!result.found_entry,
"no result entry struct returned for invalid IP address '%s'", ip);
}
{
const char *ip = "e900::";
MMDB_lookup_result_s result =
lookup_string_ok(mmdb, ip, filename, mode_desc);
ok(
!result.found_entry,
"no result entry struct returned for IP address not in the database - %s - %s - %s",
ip, filename, mode_desc);
}
{
const char *ip = "::1.1.1.1";
MMDB_lookup_result_s result =
lookup_string_ok(mmdb, ip, filename, mode_desc);
ok(
result.found_entry,
"got a result entry struct for IP address in the database - %s - %s - %s",
ip, filename, mode_desc);
cmp_ok(
result.entry.offset, ">", 0,
"result.entry.offset > 0 for address in the database - %s - %s - %s",
ip, filename, mode_desc);
test_all_data_types(&result, ip, filename, mode_desc);
}
{
const char *ip = "::4.5.6.7";
MMDB_lookup_result_s result =
lookup_string_ok(mmdb, ip, filename, mode_desc);
ok(
result.found_entry,
"got a result entry struct for IP address in the database - %s - %s - %s",
ip, filename, mode_desc);
cmp_ok(
result.entry.offset, ">", 0,
"result.entry.offset > 0 for address in the database - %s - %s - %s",
ip, filename, mode_desc);
test_all_data_types(&result, ip, filename, mode_desc);
}
{
const char *ip = "::0.0.0.0";
MMDB_lookup_result_s result =
lookup_string_ok(mmdb, ip, filename, mode_desc);
ok(
result.found_entry,
"got a result entry struct for IP address in the database - %s - %s - %s",
ip, filename, mode_desc);
test_all_data_types_as_zero(&result, ip, filename, mode_desc);
}
MMDB_close(mmdb);
free(mmdb);
}
int main(void)
{
plan(NO_PLAN);
for_all_modes(&run_tests);
done_testing();
}