aboutsummaryrefslogblamecommitdiffstats
path: root/common.h
blob: 5bfac1e476f23cf98a3993bde175ebaed7b3468a (plain) (tree)
1
2
3
4
5
6
7
8
9
                                                         





                                                            

                       
                   

                   
 





                                           







































































                                                                                                            







                                                                                                                   




































                                                                                                              
                                                                        

                                                 

                                                                  




























                                                                                                   

                                                                                             
                                                               

                                                                                          
                                                    

                                                                              
                    

                                                                                                                        




                            
                             




                                                                                   

















                                                                                                            
/* See LICENSE file for copyright and license details. */
#if defined(__clang__)
# pragma clang diagnostic ignored "-Wunsafe-buffer-usage"
# pragma clang diagnostic ignored "-Wpadded"
# pragma clang diagnostic ignored "-Wcomma"
# pragma clang diagnostic ignored "-Wcovered-switch-default"
#endif
#include "libhashsum.h"
#include <errno.h>
#include <limits.h>
#include <string.h>


#if defined(__GNUC__)
__attribute__((__const__))
#endif
uint8_t libhashsum_reverse_byte__(uint8_t);


#ifdef TEST
# include <stdlib.h>
# include <stdio.h>

struct testcase {
	size_t input_repeat;
	unsigned extra_bits;
	const char *input;
	const char *output;
};

static void
hex(char *out, const unsigned char *in, size_t n)
{
        for (; n--; in++) {
                *out++ = "0123456789abcdef"[(*in >> 4) & 15];
                *out++ = "0123456789abcdef"[(*in >> 0) & 15];
        }
        *out = '\0';
}

static char *
escape(const char *s, size_t n)
{
	char *ret, *p;

	ret = malloc(n * 4U + 1U);
	if (!ret) {
		perror("malloc");
		exit(2);
	}

	for (p = ret; n--; s++) {
		if (*s == '"' || *s == '\\') {
			*p++ = '\\';
			*p++ = *s;
		} else if (*s == '\n') {
			*p++ = '\\';
			*p++ = 'n';
		} else if (*s < ' ' || *s >= 127) {
			*p++ = '\\';
			*p++ = 'x';
			*p++ = "0123456789abcdef"[(*s >> 4) & 15];
			*p++ = "0123456789abcdef"[(*s >> 0) & 15];
		} else {
			*p++ = *s;
		}
	}
	*p = '\0';

	return ret;
}

static int
run_tests(const char *name, enum libhashsum_algorithm algorithm, size_t hash_size,
          struct testcase *testcases, size_t ntestcases, char hexsum[])
{
	struct libhashsum_hasher hasher;
	char *input, *p, bitstr[sizeof(" + b\"1234567\"")];
	unsigned char extra_bit;
	int ok = 1, caseok;
	size_t i, j, input_string_len, input_total_len, input_size;
	size_t bits;
	for (i = 0; i < ntestcases; i++) {
		if (libhashsum_init_hasher(&hasher, algorithm)) {
			perror("libhashsum_init_hasher");
			return 2;
		}
		if (hasher.algorithm != algorithm) {
			fprintf(stderr, "libhashsum_init_hasher returned unexpected value in .algorithm\n");
			return 2;
		}
		if (!hasher.algorithm_string) {
			fprintf(stderr, "libhashsum_init_hasher returned NULL pointer in .algorithm_string\n");
			return 2;
		}
		if (strcmp(hasher.algorithm_string, name)) {
			fprintf(stderr, "libhashsum_init_hasher returned unexpected value in .algorithm_string\n");
			return 2;
		}
		if (hasher.hash_size != hash_size) {
			fprintf(stderr, "libhashsum_init_hasher returned unexpected value in .hash_size\n");
			return 2;
		}
		if (hasher.hash_output) {
			fprintf(stderr, "libhashsum_init_hasher returned non-NULL pointer in .hash_output\n");
			return 2;
		}
		if (!hasher.process) {
			fprintf(stderr, "libhashsum_init_hasher returned NULL pointer in .process\n");
			return 2;
		}
		if (!hasher.finalise_const) {
			fprintf(stderr, "libhashsum_init_hasher returned NULL pointer in .finalise_const\n");
			return 2;
		}
		if (!hasher.finalise) {
			fprintf(stderr, "libhashsum_init_hasher returned NULL pointer in .finalise\n");
			return 2;
		}
		input_string_len = strlen(testcases[i].input);
		bits = testcases[i].extra_bits;
		if (bits) {
			if (input_string_len < (bits + 7U) / 8U)
				input_string_len = (bits + 7U) / 8U;
			bits %= 8U;
			if (bits)
				input_string_len -= 1U;
		}
		input_total_len = testcases[i].input_repeat * input_string_len;
		input_size = input_total_len + hasher.input_block_size + 1U;
		p = input = malloc(input_size);
		if (!input) {
			perror("malloc");
			return 2;
		}
		for (j = 0; j < testcases[i].input_repeat; j++) {
			memcpy(p, testcases[i].input, input_string_len);
			p = &p[input_string_len];
		}
		if (bits)
			*p = testcases[i].input[input_string_len];
		if (hasher.finalise(&hasher, input, input_total_len, (unsigned)bits, input_size)) {
			perror("hasher.finalise");
			return 2;
		}
		if (!hasher.hash_output) {
			fprintf(stderr, "hasher.finalise did not set hasher.hash_output\n");
			return 2;
		}
		free(input);
		hex(hexsum, hasher.hash_output, hasher.hash_size);
		ok &= caseok = !testcases[i].output || !strcmp(hexsum, testcases[i].output);
		input = escape(testcases[i].input, input_string_len);
		bitstr[0] = '\0';
		if (bits) {
			extra_bit = (unsigned char)testcases[i].input[input_string_len];
			p = bitstr;
			*p++ = ' ';
			*p++ = '+';
			*p++ = ' ';
			*p++ = 'b';
			*p++ = '"';
			while (bits--) {
				*p++ = "01"[(extra_bit >> 7) & 1U];
				extra_bit <<= 1;
			}
			*p++ = '"';
			*p = '\0';
		}
		if (testcases[i].input_repeat == 1)
			fprintf(stderr, "[\033[1;%s\033[m] %s(\"%s\"%s) = %s\n",
			        caseok ? "32mPASS" : "31mFAIL", name, input, bitstr, hexsum);
		else if (!testcases[i].input_repeat && *bitstr)
			fprintf(stderr, "[\033[1;%s\033[m] %s(%s) = %s\n",
			        caseok ? "32mPASS" : "31mFAIL", name, &bitstr[3], hexsum);
		else if (!testcases[i].input_repeat)
			fprintf(stderr, "[\033[1;%s\033[m] %s(\"\") = %s\n",
			        caseok ? "32mPASS" : "31mFAIL", name, hexsum);
		else
			fprintf(stderr, "[\033[1;%s\033[m] %s(%zu * \"%s\"%s) = %s\n",
			        caseok ? "32mPASS" : "31mFAIL", name, testcases[i].input_repeat, input, bitstr, hexsum);
		free(input);
	}
	return !ok;
}

# define TEST_MAIN(NAME, ID)\
	char hexsum[LIBHASHSUM_##ID##_HASH_SIZE * 2 + 1];\
	return run_tests(NAME, LIBHASHSUM_##ID, LIBHASHSUM_##ID##_HASH_SIZE,\
	                 testcases, sizeof(testcases) / sizeof(*testcases), hexsum)

#endif


#ifdef TEST_UNSUPPORTED
# include <stdio.h>

# define TEST_MAIN(NAME, ID)\
	struct libhashsum_hasher hasher;\
	if (!libhashsum_init_hasher(&hasher, LIBHASHSUM_##ID)) {\
		fprintf(stderr, "expected libhashsum_init_hasher to fail, but it returned successfully\n");\
		return 2;\
	}\
	if (errno != ENOSYS) {\
		perror("expected libhashsum_init_hasher to set errno to ENOSYS, but got");\
		return 2;\
	}\
	return 0;

#endif