Improve test framework: create_file()

New executable in Makefile 'all' target: tfw_createfile.

New str.h function: str_to_ll_scaled().
This commit is contained in:
Andrew Bettison 2012-10-31 18:13:33 +10:30
parent aba7e417c4
commit d38ce66c95
6 changed files with 189 additions and 15 deletions

1
.gitignore vendored
View File

@ -19,6 +19,7 @@ nacl/nacllib.txt
serval.c
/servald
/directory_service
/tfw_createfile
*.so
test.*.log
testlog

View File

@ -54,7 +54,7 @@ CFLAGS+=-D_DARWIN_C_SOURCE
DEFS= @DEFS@
all: servald libmonitorclient.so libmonitorclient.a
all: servald libmonitorclient.so libmonitorclient.a tfw_createfile
sqlite-amalgamation-3070900/sqlite3.o: sqlite-amalgamation-3070900/sqlite3.c
@echo CC $<
@ -72,6 +72,10 @@ directory_service: $(MDPCLIENTOBJS) directory_service.o
@echo LINK $@
@$(CC) $(CFLAGS) -Wall -o $@ $(MDPCLIENTOBJS) directory_service.o $(LDFLAGS)
tfw_createfile: tfw_createfile.o str.o
@echo LINK $@
@$(CC) $(CFLAGS) -Wall -o $@ tfw_createfile.o str.o
# This does not build on 64 bit elf platforms as NaCL isn't built with -fPIC
# DOC 20120615
libservald.so: $(OBJS)

27
str.c
View File

@ -17,6 +17,7 @@
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
@ -76,3 +77,29 @@ char *str_str(char *haystack, const char *needle, int haystack_len)
}
return NULL;
}
int str_to_ll_scaled(const char *str, int base, long long *result, char **afterp)
{
if (!(isdigit(*str) || *str == '-' || *str == '+'))
return 0;
char *end;
long long value = strtoll(str, &end, base);
if (end == str)
return 0;
switch (*end) {
case '\0': break;
case 'k': value *= 1000LL; ++end; break;
case 'K': value *= 1024LL; ++end; break;
case 'm': value *= 1000LL * 1000LL; ++end; break;
case 'M': value *= 1024LL * 1024LL; ++end; break;
case 'g': value *= 1000LL * 1000LL * 1000LL; ++end; break;
case 'G': value *= 1024LL * 1024LL * 1024LL; ++end; break;
default: return 0;
}
if (afterp)
*afterp = end;
else if (*end)
return 0;
*result = value;
return 1;
}

44
str.h
View File

@ -21,15 +21,17 @@
#define __STR_H__
/* Check if a given string starts with a given sub-string. If so, return 1 and, if afterp is not
NULL, set *afterp to point to the character immediately following the substring. Otherwise
return 0.
This function is used to parse HTTP headers and responses, which are typically not
nul-terminated, but are held in a buffer which has an associated length. To avoid this function
running past the end of the buffer, the caller must ensure that the buffer contains a sub-string
that is not part of the sub-string being sought, eg, "\r\n\r\n" as detected by
http_header_complete(). This guarantees that this function will return nonzero before running
past the end of the buffer.
@author Andrew Bettison <andrew@servalproject.com>
* NULL, set *afterp to point to the character immediately following the substring. Otherwise
* return 0.
*
* This function is used to parse HTTP headers and responses, which are typically not
* nul-terminated, but are held in a buffer which has an associated length. To avoid this function
* running past the end of the buffer, the caller must ensure that the buffer contains a sub-string
* that is not part of the sub-string being sought, eg, "\r\n\r\n" as detected by
* http_header_complete(). This guarantees that this function will return nonzero before running
* past the end of the buffer.
*
* @author Andrew Bettison <andrew@servalproject.com>
*/
int str_startswith(char *str, const char *substring, char **afterp);
@ -37,12 +39,30 @@ int str_startswith(char *str, const char *substring, char **afterp);
*/
int strcase_startswith(char *str, const char *substring, char **afterp);
/* like strstr(), but doesn't depend on null termination.
@author Paul Gardner-Stephen <paul@servalproject.org>
@author Andrew Bettison <andrew@servalproject.com>
/* like strstr(3), but doesn't depend on null termination.
*
* @author Paul Gardner-Stephen <paul@servalproject.org>
* @author Andrew Bettison <andrew@servalproject.com>
*/
char *str_str(char *haystack, const char *needle, int haystack_len);
/* Parse a string as an integer in ASCII radix notation in the given 'base' (eg, base=10 means
* decimal) and scale the result by a factor given by an optional suffix "scaling" character in the
* set {kKmMgG}: 'k' = 1e3, 'K' = 1<<10, 'm' = 1e6, 'M' = 1<<20, 'g' = 1e9, 'G' = * 1<<30.
*
* Return 1 if a valid scaled integer was parsed, storing the value in *result (unless result is
* NULL) and storing a pointer to the immediately succeeding character in *afterp (unless afterp is
* NULL, in which case returns 1 only if the immediately succeeding character is a nul '\0').
* Returns 0 otherwise, leaving *result and *afterp unchanged.
*
* NOTE: an argument base > 16 will cause any trailing 'g' or 'G' character to be parsed as part of
* the integer, not as a scale suffix. Ditto for base > 20 and 'k' 'K', and base > 22 and 'm' 'M'.
*
* @author Andrew Bettison <andrew@servalproject.com>
*/
int str_to_ll_scaled(const char *str, int base, long long *result, char **afterp);
int parse_argv(char *cmdline, char delim, char **argv, int max_argv);
#endif

View File

@ -1,7 +1,7 @@
#!/bin/bash
#
# Serval Project testing framework for Bash shell
# Copyright 2012 Paul Gardner-Stephen
# Copyright 2012 Serval Project, Inc.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
@ -62,7 +62,6 @@ TSFMT='+%Y-%m-%d %H:%M:%S'
SYSTYPE=`uname -s`
if [ $SYSTYPE = "SunOS" ]; then
abspath () { case "$1" in /*)printf "%s\n" "$1";; *)printf "%s\n" "$PWD/$1";; esac; }
AWK=gawk
SED=gsed
GREP=ggrep
@ -133,7 +132,9 @@ runTests() {
_tfw_stdout=1
_tfw_stderr=2
_tfw_checkBashVersion
export PATH="$(_tfw_abspath "${BASH_SOURCE%/*}"):$PATH"
_tfw_checkTerminfo
_tfw_checkCommandInPATH tfw_createfile
_tfw_invoking_script=$(abspath "${BASH_SOURCE[1]}")
_tfw_suite_name="${_tfw_invoking_script##*/}"
_tfw_cwd=$(abspath "$PWD")
@ -484,6 +485,15 @@ matches_rexp() {
_tfw_matches_rexp "$@"
}
# Create a file with the given size (default 0).
# Usage: create_file <path> [<size>]
# where: <size> is of the form Nu
# N is decimal integer
# u is one of kKmMgG (k=10^3, K=2^10, m=10^6, M=2^20, g=10^9, G=2^30)
create_file() {
tfw_createfile --label="$1" ${2:+--size=$2} >"$1" || error "failed command: create_file $@"
}
# Executes its arguments as a command:
# - captures the standard output and error in temporary files for later
# examination
@ -1214,6 +1224,13 @@ _tfw_checkTerminfo() {
esac
}
_tfw_checkCommandInPATH() {
case $(type -p "$1") in
*/"${1##*/}") ;;
*) _tfw_fatal "command not found: $1 (PATH=$PATH)"
esac
}
# Return a list of test names in the _tfw_tests array variable, in the order
# that the test_TestName functions were defined. Test names must start with
# an alphabetic character (not numeric or '_').

105
tfw_createfile.c Normal file
View File

@ -0,0 +1,105 @@
/*
Serval Project testing framework utility - create fixture file
Copyright (C) 2012 Serval Project, Inc.
This program 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; either version 2
of the License, or (at your option) any later version.
This program 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, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdarg.h>
#include "str.h"
static const char *argv0 = "test_createfile";
static void fatal(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
char buf[1024];
setbuffer(stderr, buf, sizeof buf);
fprintf(stderr, "%s: ", argv0);
vfprintf(stderr, fmt, ap);
fputc('\n', stderr);
va_end(ap);
fflush(stderr);
setbuf(stderr, NULL);
exit(1);
}
static inline char stripe(int i)
{
return (i >= ' ' && i <= '~') ? i : '.';
}
int main(int argc, char **argv)
{
argv0 = argv[0];
long long size = 0;
const char *label = "";
int i;
for (i = 1; i < argc; ++i) {
char *arg = argv[i];
if (str_startswith(arg, "--size=", &arg)) {
if (!str_to_ll_scaled(arg, 10, &size, NULL) || size < 0)
fatal("illegal --size= argument: %s", arg);
}
else if (str_startswith(arg, "--label=", &arg))
label = arg;
else
fatal("unrecognised argument: %s", arg);
}
long long offset = 0;
char buf[127];
for (i = 0; i != sizeof buf; ++i)
buf[i] = stripe(i);
const size_t labellen = strlen(label);
int bouncemax = sizeof buf - labellen;
if (bouncemax < 0)
bouncemax = sizeof buf;
int bounce = 3;
int bouncedelta = 1;
while (!ferror(stdout) && offset < size) {
int n = sprintf(buf, "%lld", offset);
buf[n] = stripe(n);
size_t labelsiz = labellen;
if (labelsiz && bounce < sizeof buf) {
if (labelsiz > sizeof buf - bounce)
labelsiz = sizeof buf - bounce;
memcpy(buf + bounce, label, labelsiz);
}
int remain = size - offset - 1;
if (remain > sizeof buf)
remain = sizeof buf;
fwrite(buf, remain, 1, stdout);
fputc('\n', stdout);
offset += remain + 1;
if (bounce <= n || bounce >= bouncemax)
bouncedelta *= -1;
if (labelsiz) {
if (bouncedelta > 0)
buf[bounce] = stripe(bounce);
else
buf[bounce + labelsiz - 1] = stripe(bounce + labelsiz - 1);
}
bounce += bouncedelta;
}
fflush(stdout);
if (ferror(stdout))
fatal("write error: %s [errno=%d]", strerror(errno), errno);
exit(0);
}