Initial commit
This commit is contained in:
commit
087645848b
9
.gitignore
vendored
Normal file
9
.gitignore
vendored
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
# Build files
|
||||||
|
/build
|
||||||
|
|
||||||
|
# Qt Creator files
|
||||||
|
/CMakeLists.txt.user*
|
||||||
|
/liberty.config
|
||||||
|
/liberty.files
|
||||||
|
/liberty.creator*
|
||||||
|
/liberty.includes
|
18
.travis.yml
Normal file
18
.travis.yml
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
language: c
|
||||||
|
notifications:
|
||||||
|
irc:
|
||||||
|
channels: "anathema.us.nu#anathema"
|
||||||
|
use_notice: true
|
||||||
|
skip_join: true
|
||||||
|
compiler:
|
||||||
|
- clang
|
||||||
|
- gcc
|
||||||
|
before_install:
|
||||||
|
- sudo apt-get update -qq
|
||||||
|
before_script:
|
||||||
|
- mkdir build
|
||||||
|
- cd build
|
||||||
|
script:
|
||||||
|
- cmake .. -DCMAKE_INSTALL_PREFIX=/usr
|
||||||
|
- make
|
||||||
|
- ctest -V
|
34
CMakeLists.txt
Normal file
34
CMakeLists.txt
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
project (liberty C)
|
||||||
|
cmake_minimum_required (VERSION 2.8.5)
|
||||||
|
|
||||||
|
# Moar warnings
|
||||||
|
if ("${CMAKE_C_COMPILER_ID}" MATCHES "GNU" OR CMAKE_COMPILER_IS_GNUC)
|
||||||
|
# -Wunused-function is pretty annoying here, as everything is static
|
||||||
|
set (CMAKE_C_FLAGS "-std=c99 -Wall -Wextra -Wno-unused-function")
|
||||||
|
endif ("${CMAKE_C_COMPILER_ID}" MATCHES "GNU" OR CMAKE_COMPILER_IS_GNUC)
|
||||||
|
|
||||||
|
# Dependencies
|
||||||
|
find_package (PkgConfig REQUIRED)
|
||||||
|
pkg_check_modules (libssl REQUIRED libssl libcrypto)
|
||||||
|
|
||||||
|
# -lpthread is only there for debugging (gdb & errno)
|
||||||
|
# -lrt is only for glibc < 2.17
|
||||||
|
set (common_libraries ${libssl_LIBRARIES} rt pthread)
|
||||||
|
include_directories (${libssl_INCLUDE_DIRS})
|
||||||
|
link_directories (${libssl_LIBRARY_DIRS})
|
||||||
|
|
||||||
|
# Generate a configuration file
|
||||||
|
# TODO: actualy use the configuration file for something; so far we allow
|
||||||
|
# for direct inclusion without running this CMakeLists.txt
|
||||||
|
configure_file (${PROJECT_SOURCE_DIR}/liberty-config.h.in
|
||||||
|
${PROJECT_BINARY_DIR}/liberty-config.h)
|
||||||
|
include_directories (${PROJECT_SOURCE_DIR} ${PROJECT_BINARY_DIR})
|
||||||
|
set (common_sources ${PROJECT_BINARY_DIR}/liberty-config.h)
|
||||||
|
|
||||||
|
# Build some unit tests
|
||||||
|
enable_testing ()
|
||||||
|
foreach (name liberty)
|
||||||
|
add_executable (test-${name} tests/${name}.c ${common_sources})
|
||||||
|
target_link_libraries (test-${name} ${common_libraries})
|
||||||
|
add_test (test-${name} test-${name})
|
||||||
|
endforeach (name)
|
14
LICENSE
Normal file
14
LICENSE
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
Copyright (c) 2014 - 2015, Přemysl Janouch <p.janouch@gmail.com>
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||||
|
SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
|
||||||
|
OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
20
README
Normal file
20
README
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
liberty
|
||||||
|
=======
|
||||||
|
|
||||||
|
`liberty' is a pseudolibrary of all the common C code I have written for various
|
||||||
|
projects. It can be thought of as a successor to my other C library, libxtnd.
|
||||||
|
|
||||||
|
You are supposed to import it as a git submodule and include the main source
|
||||||
|
file directly everywhere you need it. Everything is declared "static". I have
|
||||||
|
come to the conclusion that this style of C programming suits me the best, as it
|
||||||
|
allows me to nearly forget about the mess that are header files.
|
||||||
|
|
||||||
|
License
|
||||||
|
-------
|
||||||
|
`liberty' is written by Přemysl Janouch <p.janouch@gmail.com>.
|
||||||
|
|
||||||
|
You may use the software under the terms of the ISC license, the text of which
|
||||||
|
is included within the package, or, at your option, you may relicense the work
|
||||||
|
under the MIT or the Modified BSD License, as listed at the following site:
|
||||||
|
|
||||||
|
http://www.gnu.org/licenses/license-list.html
|
0
liberty-config.h.in
Normal file
0
liberty-config.h.in
Normal file
87
siphash.c
Normal file
87
siphash.c
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
// Code taken from https://github.com/floodyberry/siphash with some edits.
|
||||||
|
//
|
||||||
|
// To the extent possible under law, the author(s) have dedicated all copyright
|
||||||
|
// and related and neighboring rights to this software to the public domain
|
||||||
|
// worldwide. This software is distributed without any warranty.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the CC0 Public Domain Dedication along
|
||||||
|
// with this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
|
||||||
|
|
||||||
|
#include "siphash.h"
|
||||||
|
|
||||||
|
inline static uint64_t
|
||||||
|
u8to64_le (const unsigned char *p)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
(uint64_t) p[0] |
|
||||||
|
(uint64_t) p[1] << 8 |
|
||||||
|
(uint64_t) p[2] << 16 |
|
||||||
|
(uint64_t) p[3] << 24 |
|
||||||
|
(uint64_t) p[4] << 32 |
|
||||||
|
(uint64_t) p[5] << 40 |
|
||||||
|
(uint64_t) p[6] << 48 |
|
||||||
|
(uint64_t) p[7] << 56 ;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t
|
||||||
|
siphash (const unsigned char key[16], const unsigned char *m, size_t len)
|
||||||
|
{
|
||||||
|
uint64_t v0, v1, v2, v3;
|
||||||
|
uint64_t mi, k0, k1;
|
||||||
|
uint64_t last7;
|
||||||
|
size_t i, blocks;
|
||||||
|
|
||||||
|
k0 = u8to64_le (key + 0);
|
||||||
|
k1 = u8to64_le (key + 8);
|
||||||
|
v0 = k0 ^ 0x736f6d6570736575ull;
|
||||||
|
v1 = k1 ^ 0x646f72616e646f6dull;
|
||||||
|
v2 = k0 ^ 0x6c7967656e657261ull;
|
||||||
|
v3 = k1 ^ 0x7465646279746573ull;
|
||||||
|
|
||||||
|
last7 = (uint64_t) (len & 0xff) << 56;
|
||||||
|
|
||||||
|
#define ROTL64(a,b) (((a)<<(b))|((a)>>(64-b)))
|
||||||
|
|
||||||
|
#define COMPRESS \
|
||||||
|
v0 += v1; v2 += v3; \
|
||||||
|
v1 = ROTL64 (v1,13); v3 = ROTL64 (v3,16); \
|
||||||
|
v1 ^= v0; v3 ^= v2; \
|
||||||
|
v0 = ROTL64 (v0,32); \
|
||||||
|
v2 += v1; v0 += v3; \
|
||||||
|
v1 = ROTL64 (v1,17); v3 = ROTL64 (v3,21); \
|
||||||
|
v1 ^= v2; v3 ^= v0; \
|
||||||
|
v2 = ROTL64(v2,32);
|
||||||
|
|
||||||
|
for (i = 0, blocks = (len & ~(size_t) 7); i < blocks; i += 8)
|
||||||
|
{
|
||||||
|
mi = u8to64_le (m + i);
|
||||||
|
v3 ^= mi;
|
||||||
|
COMPRESS
|
||||||
|
COMPRESS
|
||||||
|
v0 ^= mi;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (len - blocks)
|
||||||
|
{
|
||||||
|
case 7: last7 |= (uint64_t) m[i + 6] << 48;
|
||||||
|
case 6: last7 |= (uint64_t) m[i + 5] << 40;
|
||||||
|
case 5: last7 |= (uint64_t) m[i + 4] << 32;
|
||||||
|
case 4: last7 |= (uint64_t) m[i + 3] << 24;
|
||||||
|
case 3: last7 |= (uint64_t) m[i + 2] << 16;
|
||||||
|
case 2: last7 |= (uint64_t) m[i + 1] << 8;
|
||||||
|
case 1: last7 |= (uint64_t) m[i + 0] ;
|
||||||
|
default:;
|
||||||
|
};
|
||||||
|
v3 ^= last7;
|
||||||
|
COMPRESS
|
||||||
|
COMPRESS
|
||||||
|
v0 ^= last7;
|
||||||
|
v2 ^= 0xff;
|
||||||
|
COMPRESS
|
||||||
|
COMPRESS
|
||||||
|
COMPRESS
|
||||||
|
COMPRESS
|
||||||
|
|
||||||
|
return v0 ^ v1 ^ v2 ^ v3;
|
||||||
|
}
|
||||||
|
|
10
siphash.h
Normal file
10
siphash.h
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#ifndef SIPHASH_H
|
||||||
|
#define SIPHASH_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
uint64_t siphash (const unsigned char key[16],
|
||||||
|
const unsigned char *m, size_t len);
|
||||||
|
|
||||||
|
#endif // SIPHASH_H
|
345
tests/liberty.c
Normal file
345
tests/liberty.c
Normal file
@ -0,0 +1,345 @@
|
|||||||
|
/*
|
||||||
|
* tests/liberty.c
|
||||||
|
*
|
||||||
|
* Copyright (c) 2015, Přemysl Janouch <p.janouch@gmail.com>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||||
|
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
|
||||||
|
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define PROGRAM_NAME "test"
|
||||||
|
#define PROGRAM_VERSION "0"
|
||||||
|
|
||||||
|
#include "../liberty.c"
|
||||||
|
|
||||||
|
// --- Memory ------------------------------------------------------------------
|
||||||
|
|
||||||
|
#define KILO 1024
|
||||||
|
#define MEGA 1048576
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_memory (void)
|
||||||
|
{
|
||||||
|
void *m = xmalloc (MEGA);
|
||||||
|
memset (m, 0, MEGA);
|
||||||
|
|
||||||
|
void *n = xcalloc (KILO, KILO);
|
||||||
|
soft_assert (!memcmp (n, m, MEGA));
|
||||||
|
|
||||||
|
m = xrealloc (m, 1024);
|
||||||
|
n = xreallocarray (n, KILO, 1);
|
||||||
|
soft_assert (!memcmp (n, m, KILO));
|
||||||
|
|
||||||
|
free (m);
|
||||||
|
free (n);
|
||||||
|
|
||||||
|
char *s = xstrdup ("test");
|
||||||
|
char *t = xstrndup ("testing", 4);
|
||||||
|
soft_assert (!strcmp (s, t));
|
||||||
|
|
||||||
|
free (s);
|
||||||
|
free (t);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Linked lists ------------------------------------------------------------
|
||||||
|
|
||||||
|
struct my_link
|
||||||
|
{
|
||||||
|
LIST_HEADER (struct my_link)
|
||||||
|
int n;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct my_link *
|
||||||
|
make_link (int value)
|
||||||
|
{
|
||||||
|
struct my_link *link = xcalloc (1, sizeof *link);
|
||||||
|
link->n = value;
|
||||||
|
return link;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
check_linked_list (struct my_link *list, struct my_link **a, int n)
|
||||||
|
{
|
||||||
|
// The linked list must contain items from the array, in that order
|
||||||
|
struct my_link *iter = list;
|
||||||
|
for (int i = 0; i < n; i++)
|
||||||
|
{
|
||||||
|
if (!a[i])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
hard_assert (iter != NULL);
|
||||||
|
soft_assert (iter->n == i);
|
||||||
|
iter = iter->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
// And nothing more
|
||||||
|
soft_assert (iter == NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_list (void)
|
||||||
|
{
|
||||||
|
struct my_link *list = NULL;
|
||||||
|
struct my_link *a[10];
|
||||||
|
|
||||||
|
// Prepare a linked list
|
||||||
|
for (int i = N_ELEMENTS (a); i--; )
|
||||||
|
{
|
||||||
|
a[i] = make_link (i);
|
||||||
|
LIST_PREPEND (list, a[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove a few entries
|
||||||
|
LIST_UNLINK (list, a[0]); a[0] = NULL;
|
||||||
|
LIST_UNLINK (list, a[3]); a[3] = NULL;
|
||||||
|
LIST_UNLINK (list, a[4]); a[4] = NULL;
|
||||||
|
LIST_UNLINK (list, a[6]); a[6] = NULL;
|
||||||
|
|
||||||
|
// Prepend one more item
|
||||||
|
a[0] = make_link (0);
|
||||||
|
LIST_PREPEND (list, a[0]);
|
||||||
|
|
||||||
|
// Check the contents
|
||||||
|
check_linked_list (list, a, N_ELEMENTS (a));
|
||||||
|
|
||||||
|
// Destroy the linked list
|
||||||
|
LIST_FOR_EACH (struct my_link, iter, list)
|
||||||
|
free (iter);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_list_with_tail (void)
|
||||||
|
{
|
||||||
|
struct my_link *list = NULL;
|
||||||
|
struct my_link *tail = NULL;
|
||||||
|
struct my_link *a[10];
|
||||||
|
|
||||||
|
// Prepare a linked list
|
||||||
|
for (int i = 0; i < (int) N_ELEMENTS (a); i++)
|
||||||
|
{
|
||||||
|
a[i] = make_link (i);
|
||||||
|
LIST_APPEND_WITH_TAIL (list, tail, a[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove a few entries
|
||||||
|
LIST_UNLINK_WITH_TAIL (list, tail, a[0]); a[0] = NULL;
|
||||||
|
LIST_UNLINK_WITH_TAIL (list, tail, a[3]); a[3] = NULL;
|
||||||
|
LIST_UNLINK_WITH_TAIL (list, tail, a[4]); a[4] = NULL;
|
||||||
|
LIST_UNLINK_WITH_TAIL (list, tail, a[6]); a[6] = NULL;
|
||||||
|
LIST_UNLINK_WITH_TAIL (list, tail, a[9]); a[9] = NULL;
|
||||||
|
|
||||||
|
// Append one more item
|
||||||
|
a[9] = make_link (9);
|
||||||
|
LIST_APPEND_WITH_TAIL (list, tail, a[9]);
|
||||||
|
|
||||||
|
// Check the contents
|
||||||
|
check_linked_list (list, a, N_ELEMENTS (a));
|
||||||
|
|
||||||
|
// Destroy the linked list
|
||||||
|
LIST_FOR_EACH (struct my_link, iter, list)
|
||||||
|
free (iter);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Strings -----------------------------------------------------------------
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_str_vector (void)
|
||||||
|
{
|
||||||
|
struct str_vector v;
|
||||||
|
str_vector_init (&v);
|
||||||
|
|
||||||
|
str_vector_add_owned (&v, xstrdup ("xkcd"));
|
||||||
|
str_vector_reset (&v);
|
||||||
|
|
||||||
|
const char *a[] =
|
||||||
|
{ "123", "456", "a", "bc", "def", "ghij", "klmno", "pqrstu" };
|
||||||
|
|
||||||
|
// Add the first two items via another vector
|
||||||
|
struct str_vector w;
|
||||||
|
str_vector_init (&w);
|
||||||
|
str_vector_add_args (&w, a[0], a[1], NULL);
|
||||||
|
str_vector_add_vector (&v, w.vector);
|
||||||
|
str_vector_free (&w);
|
||||||
|
|
||||||
|
// Add an item and delete it right after
|
||||||
|
str_vector_add (&v, "test");
|
||||||
|
str_vector_remove (&v, v.len - 1);
|
||||||
|
|
||||||
|
// Add the rest of the list properly
|
||||||
|
for (int i = 2; i < (int) N_ELEMENTS (a); i++)
|
||||||
|
str_vector_add (&v, a[i]);
|
||||||
|
|
||||||
|
// Check the contents
|
||||||
|
soft_assert (v.len == N_ELEMENTS (a));
|
||||||
|
for (int i = 0; i < (int) N_ELEMENTS (a); i++)
|
||||||
|
soft_assert (!strcmp (v.vector[i], a[i]));
|
||||||
|
soft_assert (v.vector[v.len] == NULL);
|
||||||
|
|
||||||
|
str_vector_free (&v);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_str (void)
|
||||||
|
{
|
||||||
|
uint8_t x[] = { 0x12, 0x34, 0x56, 0x78, 0x11, 0x22, 0x33, 0x44 };
|
||||||
|
|
||||||
|
struct str s;
|
||||||
|
str_init (&s);
|
||||||
|
str_ensure_space (&s, MEGA);
|
||||||
|
str_append_data (&s, x, sizeof x);
|
||||||
|
str_remove_slice (&s, 4, 4);
|
||||||
|
soft_assert (s.len == 4);
|
||||||
|
|
||||||
|
struct str t;
|
||||||
|
str_init (&t);
|
||||||
|
str_append_str (&t, &s);
|
||||||
|
str_append (&t, "abc");
|
||||||
|
str_append_c (&t, 'd');
|
||||||
|
str_append_printf (&t, "efg");
|
||||||
|
|
||||||
|
char *y = str_steal (&t);
|
||||||
|
soft_assert (!strcmp (y, "\x12\x34\x56\x78" "abcdefg"));
|
||||||
|
free (y);
|
||||||
|
|
||||||
|
str_reset (&s);
|
||||||
|
str_free (&s);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Errors ------------------------------------------------------------------
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_error (void)
|
||||||
|
{
|
||||||
|
const char *m = "something fucked up";
|
||||||
|
|
||||||
|
struct error *e = NULL;
|
||||||
|
error_set (&e, "%s", m);
|
||||||
|
|
||||||
|
struct error *f = NULL;
|
||||||
|
error_propagate (&f, e);
|
||||||
|
|
||||||
|
soft_assert (f != NULL);
|
||||||
|
soft_assert (!strcmp (f->message, m));
|
||||||
|
error_free (f);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Hash map ----------------------------------------------------------------
|
||||||
|
|
||||||
|
static int
|
||||||
|
tolower_ascii (int c)
|
||||||
|
{
|
||||||
|
return c >= 'A' && c <= 'Z' ? c + ('a' - 'A') : c;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t
|
||||||
|
tolower_strxfrm (char *dest, const char *src, size_t n)
|
||||||
|
{
|
||||||
|
size_t len = strlen (src);
|
||||||
|
while (n-- && (*dest++ = tolower_ascii (*src++)))
|
||||||
|
;
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
free_counter (void *data)
|
||||||
|
{
|
||||||
|
int *counter = data;
|
||||||
|
if (!--*counter)
|
||||||
|
free (data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int *
|
||||||
|
make_counter (void)
|
||||||
|
{
|
||||||
|
int *counter = xmalloc (sizeof *counter);
|
||||||
|
*counter = 1;
|
||||||
|
return counter;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int *
|
||||||
|
ref_counter (int *counter)
|
||||||
|
{
|
||||||
|
(*counter)++;
|
||||||
|
return counter;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_str_map (void)
|
||||||
|
{
|
||||||
|
// Put two reference counted objects in the map under case-insensitive keys
|
||||||
|
struct str_map m;
|
||||||
|
str_map_init (&m);
|
||||||
|
m.key_xfrm = tolower_strxfrm;
|
||||||
|
m.free = free_counter;
|
||||||
|
|
||||||
|
int *a = make_counter ();
|
||||||
|
int *b = make_counter ();
|
||||||
|
|
||||||
|
str_map_set (&m, "abc", ref_counter (a));
|
||||||
|
soft_assert (str_map_find (&m, "ABC") == a);
|
||||||
|
soft_assert (!str_map_find (&m, "DEFghi"));
|
||||||
|
|
||||||
|
str_map_set (&m, "defghi", ref_counter (b));
|
||||||
|
soft_assert (str_map_find (&m, "ABC") == a);
|
||||||
|
soft_assert (str_map_find (&m, "DEFghi") == b);
|
||||||
|
|
||||||
|
// Check that we can iterate over both of them
|
||||||
|
struct str_map_iter iter;
|
||||||
|
str_map_iter_init (&iter, &m);
|
||||||
|
|
||||||
|
bool met_a = false;
|
||||||
|
bool met_b = false;
|
||||||
|
void *iter_data;
|
||||||
|
while ((iter_data = str_map_iter_next (&iter)))
|
||||||
|
{
|
||||||
|
if (iter_data == a) { soft_assert (!met_a); met_a = true; }
|
||||||
|
if (iter_data == b) { soft_assert (!met_b); met_b = true; }
|
||||||
|
soft_assert (met_a || met_b);
|
||||||
|
}
|
||||||
|
soft_assert (met_a && met_b);
|
||||||
|
|
||||||
|
// Remove one of the keys
|
||||||
|
str_map_set (&m, "abc", NULL);
|
||||||
|
soft_assert (!str_map_find (&m, "ABC"));
|
||||||
|
soft_assert (str_map_find (&m, "DEFghi") == b);
|
||||||
|
|
||||||
|
str_map_free (&m);
|
||||||
|
|
||||||
|
// Check that the objects have been destroyed exactly once
|
||||||
|
soft_assert (*a == 1);
|
||||||
|
soft_assert (*b == 1);
|
||||||
|
free_counter (a);
|
||||||
|
free_counter (b);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Main --------------------------------------------------------------------
|
||||||
|
|
||||||
|
int
|
||||||
|
main (int argc, char *argv[])
|
||||||
|
{
|
||||||
|
struct test test;
|
||||||
|
test_init (&test, argc, argv);
|
||||||
|
|
||||||
|
test_add_simple (&test, "/memory", NULL, test_memory);
|
||||||
|
test_add_simple (&test, "/list", NULL, test_list);
|
||||||
|
test_add_simple (&test, "/list-with-tail", NULL, test_list_with_tail);
|
||||||
|
test_add_simple (&test, "/str-vector", NULL, test_str_vector);
|
||||||
|
test_add_simple (&test, "/str", NULL, test_str);
|
||||||
|
test_add_simple (&test, "/error", NULL, test_error);
|
||||||
|
test_add_simple (&test, "/str-map", NULL, test_str_map);
|
||||||
|
|
||||||
|
// TODO: write tests for the rest of the library
|
||||||
|
|
||||||
|
return test_run (&test);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user