summaryrefslogtreecommitdiffstats
path: root/test
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 06:30:05 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 06:30:05 +0000
commita1e354165254cd9e346751e6c2ddc554feeb0e6d (patch)
tree5fd273cc604fd00efd630eb387a6f79ce102f4e3 /test
parentInitial commit. (diff)
downloadapr-util-a1e354165254cd9e346751e6c2ddc554feeb0e6d.tar.xz
apr-util-a1e354165254cd9e346751e6c2ddc554feeb0e6d.zip
Adding upstream version 1.6.3.upstream/1.6.3upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'test')
-rw-r--r--test/Makefile.in90
-rw-r--r--test/Makefile.win171
-rw-r--r--test/NWGNUaputest282
-rw-r--r--test/NWGNUmakefile258
-rw-r--r--test/abts.c423
-rw-r--r--test/abts.h101
-rw-r--r--test/abts_tests.h48
-rw-r--r--test/data/billion-laughs.xml36
-rw-r--r--test/dbd.c407
-rw-r--r--test/nw_misc.c23
-rw-r--r--test/test_apu.h100
-rw-r--r--test/testall.dsw513
-rw-r--r--test/testbuckets.c535
-rw-r--r--test/testcrypto.c1545
-rw-r--r--test/testdate.c202
-rw-r--r--test/testdbd.c245
-rw-r--r--test/testdbm.c221
-rw-r--r--test/testldap.c250
-rw-r--r--test/testmd4.c119
-rw-r--r--test/testmd5.c103
-rw-r--r--test/testmemcache.c626
-rw-r--r--test/testpass.c217
-rw-r--r--test/testqueue.c135
-rw-r--r--test/testredis.c552
-rw-r--r--test/testreslist.c311
-rw-r--r--test/testrmm.c191
-rw-r--r--test/testsiphash.c148
-rw-r--r--test/teststrmatch.c92
-rw-r--r--test/testuri.c331
-rw-r--r--test/testutil.c60
-rw-r--r--test/testutil.h73
-rw-r--r--test/testutildll.dsp270
-rw-r--r--test/testutillib.dsp270
-rw-r--r--test/testuuid.c56
-rw-r--r--test/testxlate.c134
-rw-r--r--test/testxml.c205
36 files changed, 9343 insertions, 0 deletions
diff --git a/test/Makefile.in b/test/Makefile.in
new file mode 100644
index 0000000..73a92e5
--- /dev/null
+++ b/test/Makefile.in
@@ -0,0 +1,90 @@
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+# PROGRAMS includes all test programs built on this platform.
+# STDTEST_PORTABLE
+# test programs invoked via standard user interface, run on all platforms
+# ALL_TESTS
+# test modules invoked through the abts suite (./testall)
+# OTHER_PROGRAMS
+# programs such as sockperf, that have to be invoked in a special sequence
+# or with special parameters
+
+INCLUDES = @APRUTIL_PRIV_INCLUDES@ @APR_INCLUDES@ @APRUTIL_INCLUDES@
+
+STDTEST_PORTABLE = dbd testall
+
+TESTS = teststrmatch.lo testuri.lo testuuid.lo testbuckets.lo testpass.lo \
+ testmd4.lo testmd5.lo testldap.lo testdate.lo testdbm.lo testdbd.lo \
+ testxml.lo testrmm.lo testreslist.lo testqueue.lo testxlate.lo \
+ testmemcache.lo testcrypto.lo testsiphash.lo testredis.lo
+
+PROGRAMS = $(STDTEST_PORTABLE)
+
+TARGETS = $(PROGRAMS)
+
+LOCAL_LIBS = ../lib@APRUTIL_LIBNAME@@APRUTIL_MAJOR_VERSION@.la
+
+CLEAN_TARGETS = manyfile.bin testfile.txt data/sqlite*.db
+
+# bring in rules.mk for standard functionality
+@INCLUDE_RULES@
+APRUTIL_LIBS = @APRUTIL_LIBS@
+APRUTIL_LDFLAGS = $(ALL_LDFLAGS) @LT_NO_INSTALL@ @APRUTIL_LDFLAGS@
+
+# link programs using -no-install to get real executables not
+# libtool wrapper scripts which link an executable when first run.
+LINK_PROG = $(LIBTOOL) $(LTFLAGS) --mode=link --tag=CC $(COMPILE) $(LT_LDFLAGS) \
+ $(APRUTIL_LDFLAGS) -o $@
+
+# STDTEST_PORTABLE;
+
+abts.lo: $(srcdir)/abts.c $(srcdir)/abts.h $(srcdir)/abts_tests.h \
+ $(srcdir)/testutil.h
+
+testutil.lo: $(srcdir)/abts.c $(srcdir)/abts.h $(srcdir)/abts_tests.h \
+ $(srcdir)/testutil.h
+
+OBJECTS_testall = abts.lo testutil.lo $(TESTS) $(LOCAL_LIBS)
+testall: $(OBJECTS_testall)
+ $(LINK_PROG) $(OBJECTS_testall) $(APRUTIL_LIBS) @LDADD_ldap@
+# For VPATH builds; where we have no ./data, copy us some data
+# if we wait until 'make check', then 'make; ./testall' fails;
+ if test ! -d "./data"; then cp -r $(srcdir)/data data; fi
+
+OBJECTS_dbd = dbd.lo $(LOCAL_LIBS)
+dbd: $(OBJECTS_dbd)
+ $(LINK_PROG) $(OBJECTS_dbd) $(APRUTIL_LIBS)
+
+check: $(TESTALL_COMPONENTS) $(STDTEST_PORTABLE) $(STDTEST_NONPORTABLE)
+ teststatus=0; \
+ progfailed=""; \
+ for prog in $(STDTEST_NONPORTABLE) $(STDTEST_PORTABLE); do \
+ if test "$$prog" = 'dbd'; then \
+ for driver in none @apu_dbd_tests@; do \
+ if test "$$driver" != 'none'; then \
+ @apr_shlibpath_var@="`echo "../crypto/.libs:../dbm/.libs:../dbd/.libs:../ldap/.libs:$$@apr_shlibpath_var@" | sed -e 's/::*$$//'`" \
+ ./$$prog $$driver; \
+ status=$$?; \
+ if test $$status != 0; then \
+ teststatus=$$status; \
+ progfailed="$$progfailed '$$prog $$driver'"; \
+ fi; \
+ fi; \
+ done; \
+ else \
+ @apr_shlibpath_var@="`echo "../crypto/.libs:../dbm/.libs:../dbd/.libs:../ldap/.libs:$$@apr_shlibpath_var@" | sed -e 's/::*$$//'`" \
+ ./$$prog; \
+ status=$$?; \
+ if test $$status != 0; then \
+ teststatus=$$status; \
+ progfailed="$$progfailed $$prog"; \
+ fi; \
+ fi; \
+ done; \
+ if test $$teststatus != 0; then \
+ echo "Programs failed:$$progfailed"; \
+ fi; \
+ exit $$teststatus
+
+# DO NOT REMOVE
diff --git a/test/Makefile.win b/test/Makefile.win
new file mode 100644
index 0000000..fa3d2eb
--- /dev/null
+++ b/test/Makefile.win
@@ -0,0 +1,171 @@
+# PROGRAMS
+# test programs invoked via standard user interface, run on all platforms
+# ALL_TESTS
+# test modules invoked through the abts suite (./testall)
+# OTHER_PROGRAMS
+# programs such as sendfile, that have to be invoked in a special sequence
+# or with special parameters
+
+# Windows Specific;
+# MODEL
+# dynamic or static - refers to which set of bindings are desired
+# and controls which libraries (apr-1 or libapr-1) will be linked.
+# OUTDIR
+# the library path of the libraries, and also the path within test/
+# where all of the tests for that library will be built
+# APROUTDIR
+# The library path of apr (if different from OUTDIR)
+# APR_PATH
+# relative or absolute path to locate apr libs and includes
+# API_PATH
+# relative or absolute path to locate apr-iconv libs and includes
+
+!IFNDEF MODEL
+MODEL=dynamic
+!ENDIF
+
+!IFNDEF OUTDIR
+!IF "$(MODEL)" == "static"
+OUTDIR=LibR
+!ELSE
+OUTDIR=Release
+!ENDIF
+
+!IF [$(COMSPEC) /c cl /nologo /? \
+ | $(SystemRoot)\System32\find.exe "x64" >NUL ] == 0
+OUTDIR=x64\$(OUTDIR)
+!ENDIF
+!ENDIF
+
+!IF !EXIST("$(OUTDIR)\.")
+!IF ([$(COMSPEC) /C mkdir $(OUTDIR)] == 0)
+!ENDIF
+!ENDIF
+
+!IFNDEF INTDIR
+INTDIR=$(OUTDIR)
+!ELSE
+!IF !EXIST("$(INTDIR)\.")
+!IF ([$(COMSPEC) /C mkdir $(INTDIR)] == 0)
+!ENDIF
+!ENDIF
+!ENDIF
+
+!MESSAGE Building tests into $(OUTDIR) for $(MODEL)
+
+ALL_TESTS = $(INTDIR)\teststrmatch.obj $(INTDIR)\testuri.obj \
+ $(INTDIR)\testuuid.obj $(INTDIR)\testutil.obj \
+ $(INTDIR)\testbuckets.obj $(INTDIR)\testpass.obj \
+ $(INTDIR)\testmd4.obj $(INTDIR)\testmd5.obj \
+ $(INTDIR)\testldap.obj $(INTDIR)\testdbd.obj \
+ $(INTDIR)\testdbm.obj $(INTDIR)\testreslist.obj \
+ $(INTDIR)\testxml.obj $(INTDIR)\testqueue.obj \
+ $(INTDIR)\testrmm.obj $(INTDIR)\testxlate.obj \
+ $(INTDIR)\testdate.obj $(INTDIR)\testmemcache.obj \
+ $(INTDIR)\testredis.obj $(INTDIR)\testsiphash.obj \
+ $(INTDIR)\testcrypto.obj
+
+CLEAN_DATA = manyfile.bin testfile.txt data\sqlite*.db
+
+CLEAN_BUILDDIRS = Debug Release LibD LibR 9x x64
+
+PROGRAMS = \
+ $(OUTDIR)\testall.exe
+
+OTHER_PROGRAMS = \
+ $(OUTDIR)\dbd.exe
+
+# bring in rules.mk for standard functionality
+ALL: $(PROGRAMS) $(OTHER_PROGRAMS)
+
+CL = cl.exe
+LD = link.exe
+
+APR_PATH = ..\..\apr
+API_PATH = ..\..\apr-iconv
+
+APROUTDIR=$(OUTDIR)
+
+!IF "$(MODEL)" == "static"
+PROGRAM_DEPENDENCIES = \
+ $(APR_PATH)\$(APROUTDIR)\apr-1.lib \
+ $(API_PATH)\$(OUTDIR)\apriconv-1.lib \
+ ..\$(OUTDIR)\aprutil-1.lib
+STATIC_CFLAGS = /D APR_DECLARE_STATIC /D APU_DECLARE_STATIC
+STATIC_LIBS = libexpatMT.lib odbc32.lib odbccp32.lib wldap32.lib
+!ELSE
+PROGRAM_DEPENDENCIES = \
+ $(APR_PATH)\$(APROUTDIR)\libapr-1.lib \
+ ..\$(OUTDIR)\libaprutil-1.lib
+STATIC_CFLAGS =
+# APR 1.3 doesn't fully abstract ldap_ calls to permit switching providers;
+STATIC_LIBS = wldap32.lib
+!ENDIF
+
+!IFDEF _DEBUG
+DEBUG_CFLAGS = /MDd
+!ELSE
+DEBUG_CFLAGS = /MD
+!ENDIF
+
+INCLUDES=/I "../include" /I "$(API_PATH)/include" /I "$(APR_PATH)/include"
+
+CFLAGS = /nologo /c /W3 /Gm /EHsc /Zi /Od $(INCLUDES) \
+ $(STATIC_CFLAGS) $(DEBUG_CFLAGS) /D "BINPATH=$(OUTDIR:\=/)" \
+ /D _DEBUG /D WIN32 /Fo"$(INTDIR)/" /FD
+
+LD_LIBS = kernel32.lib advapi32.lib ws2_32.lib wsock32.lib \
+ ole32.lib shell32.lib rpcrt4.lib $(STATIC_LIBS)
+
+LDFLAGS = /nologo /debug /subsystem:console /incremental:no
+SHLDFLAGS = /nologo /dll /debug /subsystem:windows /incremental:no
+
+.c{$(INTDIR)}.obj::
+ $(CL) $(CFLAGS) -c $< -Fd$(INTDIR)\ $(INCLUDES)
+
+# PROGRAMS;
+
+abts.c: abts.h abts_tests.h testutil.h
+
+testutil.c: abts.h abts_tests.h testutil.h
+
+$(OUTDIR)\testall.exe: $(ALL_TESTS) $(INTDIR)\abts.obj $(PROGRAM_DEPENDENCIES)
+ $(LD) $(LDFLAGS) /out:"$@" $** $(LD_LIBS)
+ @if exist "$@.manifest" \
+ mt.exe -manifest "$@.manifest" -outputresource:$@;1
+
+# OTHER_PROGRAMS;
+
+$(OUTDIR)\dbd.exe: $(INTDIR)\dbd.obj $(PROGRAM_DEPENDENCIES)
+ $(LD) $(LDFLAGS) /out:"$@" $** $(LD_LIBS)
+ @if exist "$@.manifest" \
+ mt.exe -manifest "$@.manifest" -outputresource:$@;1
+
+
+cleandata:
+ @for %f in ($(CLEAN_DATA)) do @if EXIST %f del /f %f
+
+clean: cleandata
+ @if EXIST $(INTDIR)\. rmdir /s /q $(INTDIR)
+ @if EXIST $(OUTDIR)\. rmdir /s /q $(OUTDIR)
+
+cleanall:
+ @for %d in ($(CLEAN_BUILDDIRS) $(INTDIR) $(OUTDIR)) do \
+ @if EXIST %d\. rmdir /s /q %d
+
+
+!IF "$(MODEL)" != "static"
+PATH=$(OUTDIR);..\$(OUTDIR);..\ldap\$(OUTDIR);..\dbd\$(OUTDIR);$(API_PATH)\$(OUTDIR);$(APR_PATH)\$(APROUTDIR);$(PATH)
+!ENDIF
+APR_ICONV1_PATH=$(API_PATH)\$(OUTDIR)\iconv
+
+check: $(PROGRAMS) $(OTHER_PROGRAMS)
+ echo Testing dbd sqlite2 && $(OUTDIR)\dbd.exe sqlite2 || echo Failed
+ echo Testing dbd sqlite3 && $(OUTDIR)\dbd.exe sqlite3 || echo Failed
+ @for %p in ($(PROGRAMS)) do @( \
+ echo Testing %p && %p -v || echo %p failed \
+ )
+
+checkall: check
+
+# DO NOT REMOVE
diff --git a/test/NWGNUaputest b/test/NWGNUaputest
new file mode 100644
index 0000000..caf3cd4
--- /dev/null
+++ b/test/NWGNUaputest
@@ -0,0 +1,282 @@
+#
+# Make sure all needed macro's are defined
+#
+
+#
+# Get the 'head' of the build environment if necessary. This includes default
+# targets and paths to tools
+#
+
+ifndef EnvironmentDefined
+include $(APR_WORK)/build/NWGNUhead.inc
+endif
+
+#
+# These directories will be at the beginning of the include list, followed by
+# INCDIRS
+#
+XINCDIRS += \
+ $(APR)/include \
+ $(APR)/include/arch/NetWare \
+ $(APU)/include \
+ $(LDAPSDK)/inc \
+ $(EOLIST)
+
+#
+# These flags will come after CFLAGS
+#
+XCFLAGS += \
+ $(EOLIST)
+
+#
+# These defines will come after DEFINES
+#
+XDEFINES += \
+ $(EOLIST)
+
+#
+# These flags will be added to the link.opt file
+#
+XLFLAGS += \
+ $(EOLIST)
+
+#
+# These values will be appended to the correct variables based on the value of
+# RELEASE
+#
+ifeq "$(RELEASE)" "debug"
+XINCDIRS += \
+ $(EOLIST)
+
+XCFLAGS += \
+ $(EOLIST)
+
+XDEFINES += \
+ $(EOLIST)
+
+XLFLAGS += \
+ $(EOLIST)
+endif
+
+ifeq "$(RELEASE)" "noopt"
+XINCDIRS += \
+ $(EOLIST)
+
+XCFLAGS += \
+ $(EOLIST)
+
+XDEFINES += \
+ $(EOLIST)
+
+XLFLAGS += \
+ $(EOLIST)
+endif
+
+ifeq "$(RELEASE)" "release"
+XINCDIRS += \
+ $(EOLIST)
+
+XCFLAGS += \
+ $(EOLIST)
+
+XDEFINES += \
+ $(EOLIST)
+
+XLFLAGS += \
+ $(EOLIST)
+endif
+
+#
+# These are used by the link target if an NLM is being generated
+# This is used by the link 'name' directive to name the nlm. If left blank
+# TARGET_nlm (see below) will be used.
+#
+NLM_NAME = aputest
+#
+# This is used by the link '-desc ' directive.
+# If left blank, NLM_NAME will be used.
+#
+NLM_DESCRIPTION = NLM is to test the apu layer
+
+#
+# This is used by the '-threadname' directive. If left blank,
+# NLM_NAME Thread will be used.
+#
+NLM_THREAD_NAME = aputest
+
+#
+# This is used by the '-screenname' directive. If left blank,
+# 'Apache for NetWare' Thread will be used.
+#
+NLM_SCREEN_NAME = aputest
+
+#
+# If this is specified, it will override VERSION value in
+# $(APR_WORK)/build/NWGNUenvironment.inc
+#
+NLM_VERSION =
+
+#
+# If this is specified, it will override the default of 64K
+#
+NLM_STACK_SIZE = 524288
+
+#
+# If this is specified it will be used by the link '-entry' directive
+#
+NLM_ENTRY_SYM =
+
+#
+# If this is specified it will be used by the link '-exit' directive
+#
+NLM_EXIT_SYM =
+
+#
+# If this is specified it will be used by the link '-check' directive
+#
+NLM_CHECK_SYM =
+
+#
+# If this is specified it will be used by the link '-flags' directive
+#
+NLM_FLAGS =
+
+#
+# If this is specified it will be linked in with the XDCData option in the def
+# file instead of the default of $(APR)/misc/netware/apache.xdc. XDCData can
+# be disabled by setting APACHE_UNIPROC in the environment
+#
+XDCDATA =
+
+#
+# Declare all target files (you must add your files here)
+#
+
+#
+# If there is an NLM target, put it here
+#
+TARGET_nlm = \
+ $(OBJDIR)/aputest.nlm \
+ $(EOLIST)
+
+#
+# If there is an LIB target, put it here
+#
+TARGET_lib = \
+ $(EOLIST)
+
+#
+# These are the OBJ files needed to create the NLM target above.
+# Paths must all use the '/' character
+#
+
+FILES_nlm_objs = \
+ $(OBJDIR)/abts.o \
+ $(OBJDIR)/testbuckets.o \
+ $(OBJDIR)/testcrypto.o \
+ $(OBJDIR)/testdate.o \
+ $(OBJDIR)/testdbd.o \
+ $(OBJDIR)/testdbm.o \
+ $(OBJDIR)/testmemcache.o \
+ $(OBJDIR)/testmd4.o \
+ $(OBJDIR)/testmd5.o \
+ $(OBJDIR)/testldap.o \
+ $(OBJDIR)/testpass.o \
+ $(OBJDIR)/testqueue.o \
+ $(OBJDIR)/testreslist.o \
+ $(OBJDIR)/testrmm.o \
+ $(OBJDIR)/testsiphash.o \
+ $(OBJDIR)/teststrmatch.o \
+ $(OBJDIR)/testuri.o \
+ $(OBJDIR)/testutil.o \
+ $(OBJDIR)/testuuid.o \
+ $(OBJDIR)/testxml.o \
+ $(OBJDIR)/testxlate.o \
+ $(OBJDIR)/nw_misc.o \
+ $(EOLIST)
+
+# Pending tests
+
+#
+# These are the LIB files needed to create the NLM target above.
+# These will be added as a library command in the link.opt file.
+#
+FILES_nlm_libs = \
+ $(PRELUDE) \
+ $(EOLIST)
+
+#
+# These are the modules that the above NLM target depends on to load.
+# These will be added as a module command in the link.opt file.
+#
+FILES_nlm_modules = \
+ Libc \
+ APRLIB \
+ lldapsdk \
+ lldapssl \
+ $(EOLIST)
+
+#
+# If the nlm has a msg file, put it's path here
+#
+FILE_nlm_msg =
+
+#
+# If the nlm has a hlp file put it's path here
+#
+FILE_nlm_hlp =
+
+#
+# If this is specified, it will override the default copyright.
+#
+FILE_nlm_copyright =
+
+#
+# Any additional imports go here
+#
+FILES_nlm_Ximports = \
+ @libc.imp \
+ @aprlib.imp \
+ @lldapsdk.imp \
+ @lldapssl.imp \
+ $(EOLIST)
+
+#
+# Any symbols exported to here
+#
+FILES_nlm_exports = \
+ $(EOLIST)
+
+#
+# These are the OBJ files needed to create the LIB target above.
+# Paths must all use the '/' character
+#
+FILES_lib_objs = \
+ $(EOLIST)
+
+#
+# implement targets and dependancies (leave this section alone)
+#
+
+libs :: $(OBJDIR) $(TARGET_lib)
+
+nlms :: libs $(TARGET_nlm)
+
+#
+# Updated this target to create necessary directories and copy files to the
+# correct place. (See $(APR_WORK)/build/NWGNUhead.inc for examples)
+#
+install :: nlms FORCE
+
+#
+# Any specialized rules here
+#
+
+
+#
+# Include the 'tail' makefile that has targets that depend on variables defined
+# in this makefile
+#
+
+include $(APRBUILD)/NWGNUtail.inc
+
diff --git a/test/NWGNUmakefile b/test/NWGNUmakefile
new file mode 100644
index 0000000..a955f2c
--- /dev/null
+++ b/test/NWGNUmakefile
@@ -0,0 +1,258 @@
+#
+# Declare the sub-directories to be built here
+#
+
+SUBDIRS = \
+ $(EOLIST)
+
+#
+# Get the 'head' of the build environment. This includes default targets and
+# paths to tools
+#
+
+include $(APR_WORK)/build/NWGNUhead.inc
+
+#
+# build this level's files
+
+#
+# Make sure all needed macro's are defined
+#
+
+
+#
+# These directories will be at the beginning of the include list, followed by
+# INCDIRS
+#
+XINCDIRS += \
+ $(APR)/include \
+ $(APR)/include/arch/NetWare \
+ $(EOLIST)
+
+#
+# These flags will come after CFLAGS
+#
+XCFLAGS += \
+ $(EOLIST)
+
+#
+# These defines will come after DEFINES
+#
+XDEFINES += \
+ $(EOLIST)
+
+#
+# These flags will be added to the link.opt file
+#
+XLFLAGS += \
+ $(EOLIST)
+
+#
+# These values will be appended to the correct variables based on the value of
+# RELEASE
+#
+ifeq "$(RELEASE)" "debug"
+XINCDIRS += \
+ $(EOLIST)
+
+XCFLAGS += \
+ $(EOLIST)
+
+XDEFINES += \
+ $(EOLIST)
+
+XLFLAGS += \
+ $(EOLIST)
+endif
+
+ifeq "$(RELEASE)" "noopt"
+XINCDIRS += \
+ $(EOLIST)
+
+XCFLAGS += \
+ $(EOLIST)
+
+XDEFINES += \
+ $(EOLIST)
+
+XLFLAGS += \
+ $(EOLIST)
+endif
+
+ifeq "$(RELEASE)" "release"
+XINCDIRS += \
+ $(EOLIST)
+
+XCFLAGS += \
+ $(EOLIST)
+
+XDEFINES += \
+ $(EOLIST)
+
+XLFLAGS += \
+ $(EOLIST)
+endif
+
+#
+# These are used by the link target if an NLM is being generated
+# This is used by the link 'name' directive to name the nlm. If left blank
+# TARGET_nlm (see below) will be used.
+#
+NLM_NAME =
+
+#
+# This is used by the link '-desc ' directive.
+# If left blank, NLM_NAME will be used.
+#
+NLM_DESCRIPTION =
+
+#
+# This is used by the '-threadname' directive. If left blank,
+# NLM_NAME Thread will be used.
+#
+NLM_THREAD_NAME =
+
+#
+# This is used by the '-screenname' directive. If left blank,
+# 'Apache for NetWare' Thread will be used.
+#
+NLM_SCREEN_NAME =
+
+#
+# If this is specified, it will override VERSION value in
+# $(APR_WORK)/build/NWGNUenvironment.inc
+#
+NLM_VERSION =
+
+#
+# If this is specified, it will override the default of 64K
+#
+NLM_STACK_SIZE =
+
+#
+# If this is specified it will be used by the link '-entry' directive
+#
+NLM_ENTRY_SYM =
+
+#
+# If this is specified it will be used by the link '-exit' directive
+#
+NLM_EXIT_SYM =
+
+#
+# If this is specified it will be used by the link '-check' directive
+#
+NLM_CHECK_SYM =
+
+#
+# If this is specified it will be used by the link '-flags' directive
+#
+NLM_FLAGS =
+
+#
+# If this is specified it will be linked in with the XDCData option in the def
+# file instead of the default of $(APR)/misc/netware/apache.xdc. XDCData can
+# be disabled by setting APACHE_UNIPROC in the environment
+#
+XDCDATA =
+
+#
+# Declare all target files (you must add your files here)
+#
+
+#
+# If there is an NLM target, put it here
+#
+TARGET_nlm = \
+ $(OBJDIR)/aputest.nlm \
+ $(OBJDIR)/aputest.nlm \
+ $(EOLIST)
+#
+# If there is an LIB target, put it here
+#
+TARGET_lib = \
+ $(EOLIST)
+
+#
+# These are the OBJ files needed to create the NLM target above.
+# Paths must all use the '/' character
+#
+FILES_nlm_objs = \
+ $(EOLIST)
+
+#
+# These are the LIB files needed to create the NLM target above.
+# These will be added as a library command in the link.opt file.
+#
+FILES_nlm_libs = \
+ $(EOLIST)
+
+#
+# These are the modules that the above NLM target depends on to load.
+# These will be added as a module command in the link.opt file.
+#
+FILES_nlm_modules = \
+ aprlib \
+ $(EOLIST)
+
+#
+# If the nlm has a msg file, put it's path here
+#
+FILE_nlm_msg =
+
+#
+# If the nlm has a hlp file put it's path here
+#
+FILE_nlm_hlp =
+
+#
+# If this is specified, it will override the default copyright.
+#
+FILE_nlm_copyright =
+
+#
+# Any additional imports go here
+#
+FILES_nlm_Ximports = \
+ $(EOLIST)
+
+#
+# Any symbols exported to here
+#
+FILES_nlm_exports = \
+ $(EOLIST)
+
+#
+# These are the OBJ files needed to create the LIB target above.
+# Paths must all use the '/' character
+#
+FILES_lib_objs = \
+ $(EOLIST)
+
+#
+# implement targets and dependancies (leave this section alone)
+#
+
+libs :: $(OBJDIR) $(TARGET_lib)
+
+nlms :: libs $(TARGET_nlm)
+
+#
+# Updated this target to create necessary directories and copy files to the
+# correct place. (See $(APR_WORK)/build/NWGNUhead.inc for examples)
+#
+install :: nlms FORCE
+ $(call COPY,$(OBJDIR)/*.nlm,$(INSTALLBASE))
+ $(call COPYR,data,$(INSTALLBASE)/data/)
+
+#
+# Any specialized rules here
+#
+
+#
+# Include the 'tail' makefile that has targets that depend on variables defined
+# in this makefile
+#
+
+include $(APRBUILD)/NWGNUtail.inc
+
diff --git a/test/abts.c b/test/abts.c
new file mode 100644
index 0000000..da0097d
--- /dev/null
+++ b/test/abts.c
@@ -0,0 +1,423 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "abts.h"
+#include "abts_tests.h"
+#include "testutil.h"
+
+#define ABTS_STAT_SIZE 6
+static char status[ABTS_STAT_SIZE] = {'|', '/', '-', '|', '\\', '-'};
+static int curr_char;
+static int verbose = 0;
+static int exclude = 0;
+static int quiet = 0;
+static int list_tests = 0;
+
+const char **testlist = NULL;
+
+static int find_test_name(const char *testname) {
+ int i;
+ for (i = 0; testlist[i] != NULL; i++) {
+ if (!strcmp(testlist[i], testname)) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/* Determine if the test should be run at all */
+static int should_test_run(const char *testname) {
+ int found = 0;
+ if (list_tests == 1) {
+ return 0;
+ }
+ if (testlist == NULL) {
+ return 1;
+ }
+ found = find_test_name(testname);
+ if ((found && !exclude) || (!found && exclude)) {
+ return 1;
+ }
+ return 0;
+}
+
+static void reset_status(void)
+{
+ curr_char = 0;
+}
+
+static void update_status(void)
+{
+ if (!quiet) {
+ curr_char = (curr_char + 1) % ABTS_STAT_SIZE;
+ fprintf(stdout, "\b%c", status[curr_char]);
+ fflush(stdout);
+ }
+}
+
+static void end_suite(abts_suite *suite)
+{
+ if (suite != NULL) {
+ sub_suite *last = suite->tail;
+ if (!quiet) {
+ fprintf(stdout, "\b");
+ fflush(stdout);
+ }
+ if (last->failed == 0) {
+ fprintf(stdout, "SUCCESS\n");
+ fflush(stdout);
+ }
+ else {
+ fprintf(stdout, "FAILED %d of %d\n", last->failed, last->num_test);
+ fflush(stdout);
+ }
+ }
+}
+
+abts_suite *abts_add_suite(abts_suite *suite, const char *suite_name_full)
+{
+ sub_suite *subsuite;
+ char *p;
+ const char *suite_name;
+ curr_char = 0;
+
+ /* Only end the suite if we actually ran it */
+ if (suite && suite->tail &&!suite->tail->not_run) {
+ end_suite(suite);
+ }
+
+ subsuite = malloc(sizeof(*subsuite));
+ subsuite->num_test = 0;
+ subsuite->failed = 0;
+ subsuite->next = NULL;
+ /* suite_name_full may be an absolute path depending on __FILE__
+ * expansion */
+ suite_name = strrchr(suite_name_full, '/');
+ if (!suite_name) {
+ suite_name = strrchr(suite_name_full, '\\');
+ }
+ if (suite_name) {
+ suite_name++;
+ } else {
+ suite_name = suite_name_full;
+ }
+ p = strrchr(suite_name, '.');
+ if (p) {
+ subsuite->name = memcpy(calloc(p - suite_name + 1, 1),
+ suite_name, p - suite_name);
+ }
+ else {
+ subsuite->name = suite_name;
+ }
+
+ if (list_tests) {
+ fprintf(stdout, "%s\n", subsuite->name);
+ }
+
+ subsuite->not_run = 0;
+
+ if (suite == NULL) {
+ suite = malloc(sizeof(*suite));
+ suite->head = subsuite;
+ suite->tail = subsuite;
+ }
+ else {
+ suite->tail->next = subsuite;
+ suite->tail = subsuite;
+ }
+
+ if (!should_test_run(subsuite->name)) {
+ subsuite->not_run = 1;
+ return suite;
+ }
+
+ reset_status();
+ fprintf(stdout, "%-20s: ", subsuite->name);
+ update_status();
+ fflush(stdout);
+
+ return suite;
+}
+
+void abts_run_test(abts_suite *ts, test_func f, void *value)
+{
+ abts_case *tc;
+ sub_suite *ss;
+
+ if (!should_test_run(ts->tail->name)) {
+ return;
+ }
+ ss = ts->tail;
+
+ tc = malloc(sizeof(*tc));
+ tc->failed = 0;
+ tc->suite = ss;
+
+ ss->num_test++;
+ update_status();
+
+ f(tc, value);
+
+ if (tc->failed) {
+ ss->failed++;
+ }
+ free(tc);
+}
+
+static int report(abts_suite *suite)
+{
+ int count = 0;
+ sub_suite *dptr;
+
+ if (suite && suite->tail &&!suite->tail->not_run) {
+ end_suite(suite);
+ }
+
+ for (dptr = suite->head; dptr; dptr = dptr->next) {
+ count += dptr->failed;
+ }
+
+ if (list_tests) {
+ return 0;
+ }
+
+ if (count == 0) {
+ printf("All tests passed.\n");
+ return 0;
+ }
+
+ dptr = suite->head;
+ fprintf(stdout, "%-15s\t\tTotal\tFail\tFailed %%\n", "Failed Tests");
+ fprintf(stdout, "===================================================\n");
+ while (dptr != NULL) {
+ if (dptr->failed != 0) {
+ float percent = ((float)dptr->failed / (float)dptr->num_test);
+ fprintf(stdout, "%-15s\t\t%5d\t%4d\t%6.2f%%\n", dptr->name,
+ dptr->num_test, dptr->failed, percent * 100);
+ }
+ dptr = dptr->next;
+ }
+ return 1;
+}
+
+void abts_log_message(const char *fmt, ...)
+{
+ va_list args;
+ update_status();
+
+ if (verbose) {
+ va_start(args, fmt);
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+ fprintf(stderr, "\n");
+ fflush(stderr);
+ }
+}
+
+void abts_int_equal(abts_case *tc, const int expected, const int actual, int lineno)
+{
+ update_status();
+ if (tc->failed) return;
+
+ if (expected == actual) return;
+
+ tc->failed = TRUE;
+ if (verbose) {
+ fprintf(stderr, "Line %d: expected <%d>, but saw <%d>\n", lineno, expected, actual);
+ fflush(stderr);
+ }
+}
+
+void abts_int_nequal(abts_case *tc, const int expected, const int actual, int lineno)
+{
+ update_status();
+ if (tc->failed) return;
+
+ if (expected != actual) return;
+
+ tc->failed = TRUE;
+ if (verbose) {
+ fprintf(stderr, "Line %d: expected something other than <%d>, but saw <%d>\n",
+ lineno, expected, actual);
+ fflush(stderr);
+ }
+}
+
+void abts_str_equal(abts_case *tc, const char *expected, const char *actual, int lineno)
+{
+ update_status();
+ if (tc->failed) return;
+
+ /* If both are NULL, match is good */
+ if (!expected && !actual) return;
+ if (expected && actual)
+ if (!strcmp(expected, actual)) return;
+
+ tc->failed = TRUE;
+ if (verbose) {
+ fprintf(stderr, "Line %d: expected <%s>, but saw <%s>\n", lineno, expected, actual);
+ fflush(stderr);
+ }
+}
+
+void abts_str_nequal(abts_case *tc, const char *expected, const char *actual,
+ size_t n, int lineno)
+{
+ update_status();
+ if (tc->failed) return;
+
+ if (!strncmp(expected, actual, n)) return;
+
+ tc->failed = TRUE;
+ if (verbose) {
+ fprintf(stderr, "Line %d: expected something other than <%s>, but saw <%s>\n",
+ lineno, expected, actual);
+ fflush(stderr);
+ }
+}
+
+void abts_ptr_notnull(abts_case *tc, const void *ptr, int lineno)
+{
+ update_status();
+ if (tc->failed) return;
+
+ if (ptr != NULL) return;
+
+ tc->failed = TRUE;
+ if (verbose) {
+ fprintf(stderr, "Line %d: expected non-NULL, but saw NULL\n", lineno);
+ fflush(stderr);
+ }
+}
+
+void abts_ptr_equal(abts_case *tc, const void *expected, const void *actual, int lineno)
+{
+ update_status();
+ if (tc->failed) return;
+
+ if (expected == actual) return;
+
+ tc->failed = TRUE;
+ if (verbose) {
+ fprintf(stderr, "Line %d: expected <%p>, but saw <%p>\n", lineno, expected, actual);
+ fflush(stderr);
+ }
+}
+
+void abts_fail(abts_case *tc, const char *message, int lineno)
+{
+ update_status();
+ if (tc->failed) return;
+
+ tc->failed = TRUE;
+ if (verbose) {
+ fprintf(stderr, "Line %d: %s\n", lineno, message);
+ fflush(stderr);
+ }
+}
+
+void abts_assert(abts_case *tc, const char *message, int condition, int lineno)
+{
+ update_status();
+ if (tc->failed) return;
+
+ if (condition) return;
+
+ tc->failed = TRUE;
+ if (verbose) {
+ fprintf(stderr, "Line %d: %s\n", lineno, message);
+ fflush(stderr);
+ }
+}
+
+void abts_true(abts_case *tc, int condition, int lineno)
+{
+ update_status();
+ if (tc->failed) return;
+
+ if (condition) return;
+
+ tc->failed = TRUE;
+ if (verbose) {
+ fprintf(stderr, "Line %d: Condition is false, but expected true\n", lineno);
+ fflush(stderr);
+ }
+}
+
+void abts_not_impl(abts_case *tc, const char *message, int lineno)
+{
+ update_status();
+
+ tc->suite->not_impl++;
+ if (verbose) {
+ fprintf(stderr, "Line %d: %s\n", lineno, message);
+ fflush(stderr);
+ }
+}
+
+int main(int argc, const char *const argv[]) {
+ int i;
+ int rv;
+ int list_provided = 0;
+ abts_suite *suite = NULL;
+
+ initialize();
+
+ quiet = !isatty(STDOUT_FILENO);
+
+ for (i = 1; i < argc; i++) {
+ if (!strcmp(argv[i], "-v")) {
+ verbose = 1;
+ continue;
+ }
+ if (!strcmp(argv[i], "-x")) {
+ exclude = 1;
+ continue;
+ }
+ if (!strcmp(argv[i], "-l")) {
+ list_tests = 1;
+ continue;
+ }
+ if (!strcmp(argv[i], "-q")) {
+ quiet = 1;
+ continue;
+ }
+ if (argv[i][0] == '-') {
+ fprintf(stderr, "Invalid option: `%s'\n", argv[i]);
+ exit(1);
+ }
+ list_provided = 1;
+ }
+
+ if (list_provided) {
+ /* Waste a little space here, because it is easier than counting the
+ * number of tests listed. Besides it is at most three char *.
+ */
+ testlist = calloc(argc + 1, sizeof(char *));
+ for (i = 1; i < argc; i++) {
+ testlist[i - 1] = argv[i];
+ }
+ }
+
+ for (i = 0; i < (sizeof(alltests) / sizeof(struct testlist *)); i++) {
+ suite = alltests[i].func(suite);
+ apr_pool_clear(p);
+ }
+
+ rv = report(suite);
+ return rv;
+}
+
diff --git a/test/abts.h b/test/abts.h
new file mode 100644
index 0000000..a31def7
--- /dev/null
+++ b/test/abts.h
@@ -0,0 +1,101 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef WIN32
+#include <io.h>
+#else
+#include <unistd.h>
+#endif
+
+#ifndef ABTS_H
+#define ABTS_H
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+struct sub_suite {
+ const char *name;
+ int num_test;
+ int failed;
+ int not_run;
+ int not_impl;
+ struct sub_suite *next;
+};
+typedef struct sub_suite sub_suite;
+
+struct abts_suite {
+ sub_suite *head;
+ sub_suite *tail;
+};
+typedef struct abts_suite abts_suite;
+
+struct abts_case {
+ int failed;
+ sub_suite *suite;
+};
+typedef struct abts_case abts_case;
+
+typedef void (*test_func)(abts_case *tc, void *data);
+
+#define ADD_SUITE(suite) abts_add_suite(suite, __FILE__);
+
+abts_suite *abts_add_suite(abts_suite *suite, const char *suite_name);
+void abts_run_test(abts_suite *ts, test_func f, void *value);
+void abts_log_message(const char *fmt, ...);
+
+void abts_int_equal(abts_case *tc, const int expected, const int actual, int lineno);
+void abts_int_nequal(abts_case *tc, const int expected, const int actual, int lineno);
+void abts_str_equal(abts_case *tc, const char *expected, const char *actual, int lineno);
+void abts_str_nequal(abts_case *tc, const char *expected, const char *actual,
+ size_t n, int lineno);
+void abts_ptr_notnull(abts_case *tc, const void *ptr, int lineno);
+void abts_ptr_equal(abts_case *tc, const void *expected, const void *actual, int lineno);
+void abts_true(abts_case *tc, int condition, int lineno);
+void abts_fail(abts_case *tc, const char *message, int lineno);
+void abts_not_impl(abts_case *tc, const char *message, int lineno);
+void abts_assert(abts_case *tc, const char *message, int condition, int lineno);
+
+/* Convenience macros. Ryan hates these! */
+#define ABTS_INT_EQUAL(a, b, c) abts_int_equal(a, b, c, __LINE__)
+#define ABTS_INT_NEQUAL(a, b, c) abts_int_nequal(a, b, c, __LINE__)
+#define ABTS_STR_EQUAL(a, b, c) abts_str_equal(a, b, c, __LINE__)
+#define ABTS_STR_NEQUAL(a, b, c, d) abts_str_nequal(a, b, c, d, __LINE__)
+#define ABTS_PTR_NOTNULL(a, b) abts_ptr_notnull(a, b, __LINE__)
+#define ABTS_PTR_EQUAL(a, b, c) abts_ptr_equal(a, b, c, __LINE__)
+#define ABTS_TRUE(a, b) abts_true(a, b, __LINE__);
+#define ABTS_FAIL(a, b) abts_fail(a, b, __LINE__);
+#define ABTS_NOT_IMPL(a, b) abts_not_impl(a, b, __LINE__);
+#define ABTS_ASSERT(a, b, c) abts_assert(a, b, c, __LINE__);
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/test/abts_tests.h b/test/abts_tests.h
new file mode 100644
index 0000000..cb4e113
--- /dev/null
+++ b/test/abts_tests.h
@@ -0,0 +1,48 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef APR_TEST_INCLUDES
+#define APR_TEST_INCLUDES
+
+#include "abts.h"
+#include "testutil.h"
+
+const struct testlist {
+ abts_suite *(*func)(abts_suite *suite);
+} alltests[] = {
+ {teststrmatch},
+ {testuri},
+ {testuuid},
+ {testbuckets},
+ {testpass},
+ {testmd4},
+ {testmd5},
+ {testcrypto},
+ {testldap},
+ {testdbd},
+ {testdate},
+ {testmemcache},
+ {testredis},
+ {testxml},
+ {testxlate},
+ {testrmm},
+ {testdbm},
+ {testqueue},
+ {testreslist},
+ {testsiphash}
+};
+
+#endif /* APR_TEST_INCLUDES */
diff --git a/test/data/billion-laughs.xml b/test/data/billion-laughs.xml
new file mode 100644
index 0000000..3af89ae
--- /dev/null
+++ b/test/data/billion-laughs.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0"?>
+<!DOCTYPE billion [
+<!ELEMENT billion (#PCDATA)>
+<!ENTITY laugh0 "ha">
+<!ENTITY laugh1 "&laugh0;&laugh0;">
+<!ENTITY laugh2 "&laugh1;&laugh1;">
+<!ENTITY laugh3 "&laugh2;&laugh2;">
+<!ENTITY laugh4 "&laugh3;&laugh3;">
+<!ENTITY laugh5 "&laugh4;&laugh4;">
+<!ENTITY laugh6 "&laugh5;&laugh5;">
+<!ENTITY laugh7 "&laugh6;&laugh6;">
+<!ENTITY laugh8 "&laugh7;&laugh7;">
+<!ENTITY laugh9 "&laugh8;&laugh8;">
+<!ENTITY laugh10 "&laugh9;&laugh9;">
+<!ENTITY laugh11 "&laugh10;&laugh10;">
+<!ENTITY laugh12 "&laugh11;&laugh11;">
+<!ENTITY laugh13 "&laugh12;&laugh12;">
+<!ENTITY laugh14 "&laugh13;&laugh13;">
+<!ENTITY laugh15 "&laugh14;&laugh14;">
+<!ENTITY laugh16 "&laugh15;&laugh15;">
+<!ENTITY laugh17 "&laugh16;&laugh16;">
+<!ENTITY laugh18 "&laugh17;&laugh17;">
+<!ENTITY laugh19 "&laugh18;&laugh18;">
+<!ENTITY laugh20 "&laugh19;&laugh19;">
+<!ENTITY laugh21 "&laugh20;&laugh20;">
+<!ENTITY laugh22 "&laugh21;&laugh21;">
+<!ENTITY laugh23 "&laugh22;&laugh22;">
+<!ENTITY laugh24 "&laugh23;&laugh23;">
+<!ENTITY laugh25 "&laugh24;&laugh24;">
+<!ENTITY laugh26 "&laugh25;&laugh25;">
+<!ENTITY laugh27 "&laugh26;&laugh26;">
+<!ENTITY laugh28 "&laugh27;&laugh27;">
+<!ENTITY laugh29 "&laugh28;&laugh28;">
+<!ENTITY laugh30 "&laugh29;&laugh29;">
+]>
+<billion>&laugh30;</billion>
diff --git a/test/dbd.c b/test/dbd.c
new file mode 100644
index 0000000..61f49ab
--- /dev/null
+++ b/test/dbd.c
@@ -0,0 +1,407 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "apu.h"
+#include "apr_pools.h"
+#include "apr_dbd.h"
+
+#include <stdio.h>
+
+#define TEST(msg,func) \
+ printf("======== %s ========\n", msg); \
+ rv = func(pool, sql, driver); \
+ if (rv != 0) { \
+ printf("Error in %s: rc=%d\n\n", msg, rv); \
+ } \
+ else { \
+ printf("%s test successful\n\n", msg); \
+ } \
+ fflush(stdout);
+
+static int create_table(apr_pool_t* pool, apr_dbd_t* handle,
+ const apr_dbd_driver_t* driver)
+{
+ int rv = 0;
+ int nrows;
+ const char *statement = "CREATE TABLE apr_dbd_test ("
+ "col1 varchar(40) not null,"
+ "col2 varchar(40),"
+ "col3 integer)" ;
+ rv = apr_dbd_query(driver, handle, &nrows, statement);
+ return rv;
+}
+static int drop_table(apr_pool_t* pool, apr_dbd_t* handle,
+ const apr_dbd_driver_t* driver)
+{
+ int rv = 0;
+ int nrows;
+ const char *statement = "DROP TABLE apr_dbd_test" ;
+ rv = apr_dbd_query(driver, handle, &nrows, statement);
+ return rv;
+}
+static int insert_rows(apr_pool_t* pool, apr_dbd_t* handle,
+ const apr_dbd_driver_t* driver)
+{
+ int i;
+ int rv = 0;
+ int nrows;
+ int nerrors = 0;
+ const char *statement =
+ "INSERT into apr_dbd_test (col1) values ('foo');"
+ "INSERT into apr_dbd_test values ('wibble', 'other', 5);"
+ "INSERT into apr_dbd_test values ('wibble', 'nothing', 5);"
+ "INSERT into apr_dbd_test values ('qwerty', 'foo', 0);"
+ "INSERT into apr_dbd_test values ('asdfgh', 'bar', 1);"
+ ;
+ rv = apr_dbd_query(driver, handle, &nrows, statement);
+ if (rv) {
+ const char* stmt[] = {
+ "INSERT into apr_dbd_test (col1) values ('foo');",
+ "INSERT into apr_dbd_test values ('wibble', 'other', 5);",
+ "INSERT into apr_dbd_test values ('wibble', 'nothing', 5);",
+ "INSERT into apr_dbd_test values ('qwerty', 'foo', 0);",
+ "INSERT into apr_dbd_test values ('asdfgh', 'bar', 1);",
+ NULL
+ };
+ printf("Compound insert failed; trying statements one-by-one\n") ;
+ for (i=0; stmt[i] != NULL; ++i) {
+ statement = stmt[i];
+ rv = apr_dbd_query(driver, handle, &nrows, statement);
+ if (rv) {
+ nerrors++;
+ }
+ }
+ if (nerrors) {
+ printf("%d single inserts failed too.\n", nerrors) ;
+ }
+ }
+ return rv;
+}
+static int invalid_op(apr_pool_t* pool, apr_dbd_t* handle,
+ const apr_dbd_driver_t* driver)
+{
+ int rv = 0;
+ int nrows;
+ const char *statement = "INSERT into apr_dbd_test1 (col2) values ('foo')" ;
+ rv = apr_dbd_query(driver, handle, &nrows, statement);
+ printf("invalid op returned %d (should be nonzero). Error msg follows\n", rv);
+ printf("'%s'\n", apr_dbd_error(driver, handle, rv));
+ statement = "INSERT into apr_dbd_test (col1, col2) values ('bar', 'foo')" ;
+ rv = apr_dbd_query(driver, handle, &nrows, statement);
+ printf("valid op returned %d (should be zero; error shouldn't affect subsequent ops)\n", rv);
+ return rv;
+}
+static int select_sequential(apr_pool_t* pool, apr_dbd_t* handle,
+ const apr_dbd_driver_t* driver)
+{
+ int rv = 0;
+ int i = 0;
+ int n;
+ const char* entry;
+ const char* statement = "SELECT * FROM apr_dbd_test ORDER BY col1, col2";
+ apr_dbd_results_t *res = NULL;
+ apr_dbd_row_t *row = NULL;
+ rv = apr_dbd_select(driver,pool,handle,&res,statement,0);
+ if (rv) {
+ printf("Select failed: %s", apr_dbd_error(driver, handle, rv));
+ return rv;
+ }
+ for (rv = apr_dbd_get_row(driver, pool, res, &row, -1);
+ rv == 0;
+ rv = apr_dbd_get_row(driver, pool, res, &row, -1)) {
+ printf("ROW %d: ", ++i) ;
+ for (n = 0; n < apr_dbd_num_cols(driver, res); ++n) {
+ entry = apr_dbd_get_entry(driver, row, n);
+ if (entry == NULL) {
+ printf("(null) ") ;
+ }
+ else {
+ printf("%s ", entry);
+ }
+ }
+ fputs("\n", stdout);
+ }
+ return (rv == -1) ? 0 : 1;
+}
+static int select_random(apr_pool_t* pool, apr_dbd_t* handle,
+ const apr_dbd_driver_t* driver)
+{
+ int rv = 0;
+ int n;
+ const char* entry;
+ const char* statement = "SELECT * FROM apr_dbd_test ORDER BY col1, col2";
+ apr_dbd_results_t *res = NULL;
+ apr_dbd_row_t *row = NULL;
+ rv = apr_dbd_select(driver,pool,handle,&res,statement,1);
+ if (rv) {
+ printf("Select failed: %s", apr_dbd_error(driver, handle, rv));
+ return rv;
+ }
+ rv = apr_dbd_get_row(driver, pool, res, &row, 5) ;
+ if (rv) {
+ printf("get_row failed: %s", apr_dbd_error(driver, handle, rv));
+ return rv;
+ }
+ printf("ROW 5: ");
+ for (n = 0; n < apr_dbd_num_cols(driver, res); ++n) {
+ entry = apr_dbd_get_entry(driver, row, n);
+ if (entry == NULL) {
+ printf("(null) ") ;
+ }
+ else {
+ printf("%s ", entry);
+ }
+ }
+ fputs("\n", stdout);
+ rv = apr_dbd_get_row(driver, pool, res, &row, 1) ;
+ if (rv) {
+ printf("get_row failed: %s", apr_dbd_error(driver, handle, rv));
+ return rv;
+ }
+ printf("ROW 1: ");
+ for (n = 0; n < apr_dbd_num_cols(driver, res); ++n) {
+ entry = apr_dbd_get_entry(driver, row, n);
+ if (entry == NULL) {
+ printf("(null) ") ;
+ }
+ else {
+ printf("%s ", entry);
+ }
+ }
+ fputs("\n", stdout);
+ rv = apr_dbd_get_row(driver, pool, res, &row, 11) ;
+ if (rv != -1) {
+ printf("Oops! get_row out of range but thinks it succeeded!\n%s\n",
+ apr_dbd_error(driver, handle, rv));
+ return -1;
+ }
+ rv = 0;
+
+ return rv;
+}
+static int test_transactions(apr_pool_t* pool, apr_dbd_t* handle,
+ const apr_dbd_driver_t* driver)
+{
+ int rv = 0;
+ int nrows;
+ apr_dbd_transaction_t *trans = NULL;
+ const char* statement;
+
+ /* trans 1 - error out early */
+ printf("Transaction 1\n");
+ rv = apr_dbd_transaction_start(driver, pool, handle, &trans);
+ if (rv) {
+ printf("Start transaction failed!\n%s\n",
+ apr_dbd_error(driver, handle, rv));
+ return rv;
+ }
+ statement = "UPDATE apr_dbd_test SET col2 = 'failed'";
+ rv = apr_dbd_query(driver, handle, &nrows, statement);
+ if (rv) {
+ printf("Update failed: '%s'\n", apr_dbd_error(driver, handle, rv));
+ apr_dbd_transaction_end(driver, pool, trans);
+ return rv;
+ }
+ printf("%d rows updated\n", nrows);
+
+ statement = "INSERT INTO apr_dbd_test1 (col3) values (3)";
+ rv = apr_dbd_query(driver, handle, &nrows, statement);
+ if (!rv) {
+ printf("Oops, invalid op succeeded but shouldn't!\n");
+ }
+ statement = "INSERT INTO apr_dbd_test values ('zzz', 'aaa', 3)";
+ rv = apr_dbd_query(driver, handle, &nrows, statement);
+ printf("Valid insert returned %d. Should be nonzero (fail) because transaction is bad\n", rv) ;
+
+ rv = apr_dbd_transaction_end(driver, pool, trans);
+ if (rv) {
+ printf("End transaction failed!\n%s\n",
+ apr_dbd_error(driver, handle, rv));
+ return rv;
+ }
+ printf("Transaction ended (should be rollback) - viewing table\n"
+ "A column of \"failed\" indicates transaction failed (no rollback)\n");
+ select_sequential(pool, handle, driver);
+
+ /* trans 2 - complete successfully */
+ printf("Transaction 2\n");
+ rv = apr_dbd_transaction_start(driver, pool, handle, &trans);
+ if (rv) {
+ printf("Start transaction failed!\n%s\n",
+ apr_dbd_error(driver, handle, rv));
+ return rv;
+ }
+ statement = "UPDATE apr_dbd_test SET col2 = 'success'";
+ rv = apr_dbd_query(driver, handle, &nrows, statement);
+ if (rv) {
+ printf("Update failed: '%s'\n", apr_dbd_error(driver, handle, rv));
+ apr_dbd_transaction_end(driver, pool, trans);
+ return rv;
+ }
+ printf("%d rows updated\n", nrows);
+ statement = "INSERT INTO apr_dbd_test values ('aaa', 'zzz', 3)";
+ rv = apr_dbd_query(driver, handle, &nrows, statement);
+ printf("Valid insert returned %d. Should be zero (OK)\n", rv) ;
+ rv = apr_dbd_transaction_end(driver, pool, trans);
+ if (rv) {
+ printf("End transaction failed!\n%s\n",
+ apr_dbd_error(driver, handle, rv));
+ return rv;
+ }
+ printf("Transaction ended (should be commit) - viewing table\n");
+ select_sequential(pool, handle, driver);
+ return rv;
+}
+static int test_pselect(apr_pool_t* pool, apr_dbd_t* handle,
+ const apr_dbd_driver_t* driver)
+{
+ int rv = 0;
+ int i, n;
+ const char *query =
+ "SELECT * FROM apr_dbd_test WHERE col3 <= %s or col1 = 'bar'" ;
+ const char *label = "lowvalues";
+ apr_dbd_prepared_t *statement = NULL;
+ apr_dbd_results_t *res = NULL;
+ apr_dbd_row_t *row = NULL;
+ const char *entry = NULL;
+
+ rv = apr_dbd_prepare(driver, pool, handle, query, label, &statement);
+ if (rv) {
+ printf("Prepare statement failed!\n%s\n",
+ apr_dbd_error(driver, handle, rv));
+ return rv;
+ }
+ rv = apr_dbd_pvselect(driver, pool, handle, &res, statement, 0, "3", NULL);
+ if (rv) {
+ printf("Exec of prepared statement failed!\n%s\n",
+ apr_dbd_error(driver, handle, rv));
+ return rv;
+ }
+ i = 0;
+ printf("Selecting rows where col3 <= 3 and bar row where it's unset.\nShould show four rows.\n");
+ for (rv = apr_dbd_get_row(driver, pool, res, &row, -1);
+ rv == 0;
+ rv = apr_dbd_get_row(driver, pool, res, &row, -1)) {
+ printf("ROW %d: ", ++i) ;
+ for (n = 0; n < apr_dbd_num_cols(driver, res); ++n) {
+ entry = apr_dbd_get_entry(driver, row, n);
+ if (entry == NULL) {
+ printf("(null) ") ;
+ }
+ else {
+ printf("%s ", entry);
+ }
+ }
+ fputs("\n", stdout);
+ }
+ return (rv == -1) ? 0 : 1;
+}
+static int test_pquery(apr_pool_t* pool, apr_dbd_t* handle,
+ const apr_dbd_driver_t* driver)
+{
+ int rv = 0;
+ const char *query = "INSERT INTO apr_dbd_test VALUES (%s, %s, %d)";
+ apr_dbd_prepared_t *statement = NULL;
+ const char *label = "testpquery";
+ int nrows;
+ apr_dbd_transaction_t *trans =0;
+
+ rv = apr_dbd_prepare(driver, pool, handle, query, label, &statement);
+ /* rv = apr_dbd_prepare(driver, pool, handle, query, NULL, &statement); */
+ if (rv) {
+ printf("Prepare statement failed!\n%s\n",
+ apr_dbd_error(driver, handle, rv));
+ return rv;
+ }
+ apr_dbd_transaction_start(driver, pool, handle, &trans);
+ rv = apr_dbd_pvquery(driver, pool, handle, &nrows, statement,
+ "prepared", "insert", "2", NULL);
+ apr_dbd_transaction_end(driver, pool, trans);
+ if (rv) {
+ printf("Exec of prepared statement failed!\n%s\n",
+ apr_dbd_error(driver, handle, rv));
+ return rv;
+ }
+ printf("Showing table (should now contain row \"prepared insert 2\")\n");
+ select_sequential(pool, handle, driver);
+ return rv;
+}
+int main(int argc, char** argv)
+{
+ const char *name;
+ const char *params;
+ apr_pool_t *pool = NULL;
+ apr_dbd_t *sql = NULL;
+ const apr_dbd_driver_t *driver = NULL;
+ int rv;
+
+ apr_initialize();
+ apr_pool_create(&pool, NULL);
+
+ if (argc >= 2 && argc <= 3) {
+ name = argv[1];
+ params = ( argc == 3 ) ? argv[2] : "";
+ apr_dbd_init(pool);
+ setbuf(stdout,NULL);
+ rv = apr_dbd_get_driver(pool, name, &driver);
+ switch (rv) {
+ case APR_SUCCESS:
+ printf("Loaded %s driver OK.\n", name);
+ break;
+ case APR_EDSOOPEN:
+ printf("Failed to load driver file apr_dbd_%s.so\n", name);
+ goto finish;
+ case APR_ESYMNOTFOUND:
+ printf("Failed to load driver apr_dbd_%s_driver.\n", name);
+ goto finish;
+ case APR_ENOTIMPL:
+ printf("No driver available for %s.\n", name);
+ goto finish;
+ default: /* it's a bug if none of the above happen */
+ printf("Internal error loading %s.\n", name);
+ goto finish;
+ }
+ rv = apr_dbd_open(driver, pool, params, &sql);
+ switch (rv) {
+ case APR_SUCCESS:
+ printf("Opened %s[%s] OK\n", name, params);
+ break;
+ case APR_EGENERAL:
+ printf("Failed to open %s[%s]\n", name, params);
+ goto finish;
+ default: /* it's a bug if none of the above happen */
+ printf("Internal error opening %s[%s]\n", name, params);
+ goto finish;
+ }
+ TEST("create table", create_table);
+ TEST("insert rows", insert_rows);
+ TEST("invalid op", invalid_op);
+ TEST("select random", select_random);
+ TEST("select sequential", select_sequential);
+ TEST("transactions", test_transactions);
+ TEST("prepared select", test_pselect);
+ TEST("prepared query", test_pquery);
+ TEST("drop table", drop_table);
+ apr_dbd_close(driver, sql);
+ }
+ else {
+ fprintf(stderr, "Usage: %s driver-name [params]\n", argv[0]);
+ }
+finish:
+ apr_pool_destroy(pool);
+ apr_terminate();
+ return 0;
+}
diff --git a/test/nw_misc.c b/test/nw_misc.c
new file mode 100644
index 0000000..b45f951
--- /dev/null
+++ b/test/nw_misc.c
@@ -0,0 +1,23 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <screen.h>
+/*
+#include "testutil.h"
+*/
+
+/* function to keep the screen open if not launched from bash */
+void _NonAppStop( void )
+{
+ if (getenv("_IN_NETWARE_BASH_") == NULL) {
+ printf("\r\n<Press any key to close screen> ");
+ getcharacter();
+ }
+}
+
+/*
+static void test_not_impl(CuTest *tc)
+{
+ CuNotImpl(tc, "Test not implemented on this platform yet");
+}
+*/
+
diff --git a/test/test_apu.h b/test/test_apu.h
new file mode 100644
index 0000000..642edec
--- /dev/null
+++ b/test/test_apu.h
@@ -0,0 +1,100 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* Some simple functions to make the test apps easier to write and
+ * a bit more consistent...
+ * this is a >copy< of apr_test.h
+ */
+
+/* Things to bear in mind when using these...
+ *
+ * If you include '\t' within the string passed in it won't be included
+ * in the spacing, so use spaces instead :)
+ *
+ */
+
+#ifndef APU_TEST_INCLUDES
+#define APU_TEST_INCLUDES
+
+#include "apr_strings.h"
+#include "apr_time.h"
+
+#define TEST_EQ(str, func, value, good, bad) \
+ printf("%-60s", str); \
+ { \
+ apr_status_t rv; \
+ if ((rv = func) == value){ \
+ char errmsg[200]; \
+ printf("%s\n", bad); \
+ fprintf(stderr, "Error was %d : %s\n", rv, \
+ apr_strerror(rv, (char*)&errmsg, 200)); \
+ exit(-1); \
+ } \
+ printf("%s\n", good); \
+ }
+
+#define TEST_NEQ(str, func, value, good, bad) \
+ printf("%-60s", str); \
+ { \
+ apr_status_t rv; \
+ if ((rv = func) != value){ \
+ char errmsg[200]; \
+ printf("%s\n", bad); \
+ fprintf(stderr, "Error was %d : %s\n", rv, \
+ apr_strerror(rv, (char*)&errmsg, 200)); \
+ exit(-1); \
+ } \
+ printf("%s\n", good); \
+ }
+
+#define TEST_STATUS(str, func, testmacro, good, bad) \
+ printf("%-60s", str); \
+ { \
+ apr_status_t rv = func; \
+ if (!testmacro(rv)) { \
+ char errmsg[200]; \
+ printf("%s\n", bad); \
+ fprintf(stderr, "Error was %d : %s\n", rv, \
+ apr_strerror(rv, (char*)&errmsg, 200)); \
+ exit(-1); \
+ } \
+ printf("%s\n", good); \
+ }
+
+#define STD_TEST_NEQ(str, func) \
+ TEST_NEQ(str, func, APR_SUCCESS, "OK", "Failed");
+
+#define PRINT_ERROR(rv) \
+ { \
+ char errmsg[200]; \
+ fprintf(stderr, "Error was %d : %s\n", rv, \
+ apr_strerror(rv, (char*)&errmsg, 200)); \
+ exit(-1); \
+ }
+
+#define MSG_AND_EXIT(msg) \
+ printf("%s\n", msg); \
+ exit (-1);
+
+#define TIME_FUNCTION(time, function) \
+ { \
+ apr_time_t tt = apr_time_now(); \
+ function; \
+ time = apr_time_now() - tt; \
+ }
+
+
+#endif /* APU_TEST_INCLUDES */
diff --git a/test/testall.dsw b/test/testall.dsw
new file mode 100644
index 0000000..7fde202
--- /dev/null
+++ b/test/testall.dsw
@@ -0,0 +1,513 @@
+Microsoft Developer Studio Workspace File, Format Version 6.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "apr"="..\..\apr\apr.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "aprapp"="..\..\apr\build\aprapp.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name preaprapp
+ End Project Dependency
+}}}
+
+
+###############################################################################
+
+Project: "apr_dbd_mysql"="..\dbd\apr_dbd_mysql.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name libapr
+ End Project Dependency
+ Begin Project Dependency
+ Project_Dep_Name libaprutil
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "apr_dbd_odbc"="..\dbd\apr_dbd_odbc.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name libaprutil
+ End Project Dependency
+ Begin Project Dependency
+ Project_Dep_Name libapr
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "apr_dbd_oracle"="..\dbd\apr_dbd_oracle.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name libapr
+ End Project Dependency
+ Begin Project Dependency
+ Project_Dep_Name libaprutil
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "apr_dbd_pgsql"="..\dbd\apr_dbd_pgsql.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name libapr
+ End Project Dependency
+ Begin Project Dependency
+ Project_Dep_Name libaprutil
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "apr_dbd_sqlite2"="..\dbd\apr_dbd_sqlite2.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name libapr
+ End Project Dependency
+ Begin Project Dependency
+ Project_Dep_Name libaprutil
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "apr_dbd_sqlite3"="..\dbd\apr_dbd_sqlite3.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name libapr
+ End Project Dependency
+ Begin Project Dependency
+ Project_Dep_Name libaprutil
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "apr_dbm_db"="..\dbm\apr_dbm_db.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name libaprutil
+ End Project Dependency
+ Begin Project Dependency
+ Project_Dep_Name libapr
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "apr_dbm_gdbm"="..\dbm\apr_dbm_gdbm.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name libaprutil
+ End Project Dependency
+ Begin Project Dependency
+ Project_Dep_Name libapr
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "apr_ldap"="..\ldap\apr_ldap.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name libapr
+ End Project Dependency
+ Begin Project Dependency
+ Project_Dep_Name libaprutil
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "apriconv"="..\..\apr-iconv\apriconv.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name preapriconv
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "aprutil"="..\aprutil.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name preaprutil
+ End Project Dependency
+ Begin Project Dependency
+ Project_Dep_Name apriconv
+ End Project Dependency
+ Begin Project Dependency
+ Project_Dep_Name xml
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "libapr"="..\..\apr\libapr.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "libaprapp"="..\..\apr\build\libaprapp.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name prelibaprapp
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "libapriconv"="..\..\apr-iconv\libapriconv.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name libapr
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "libapriconv_ccs_modules"="..\..\apr-iconv\ccs\libapriconv_ccs_modules.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name libapr
+ End Project Dependency
+ Begin Project Dependency
+ Project_Dep_Name libapriconv
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "libapriconv_ces_modules"="..\..\apr-iconv\ces\libapriconv_ces_modules.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name libapr
+ End Project Dependency
+ Begin Project Dependency
+ Project_Dep_Name libapriconv
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "libaprutil"="..\libaprutil.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name libapr
+ End Project Dependency
+ Begin Project Dependency
+ Project_Dep_Name libaprapp
+ End Project Dependency
+ Begin Project Dependency
+ Project_Dep_Name libapriconv
+ End Project Dependency
+ Begin Project Dependency
+ Project_Dep_Name libapriconv_ccs_modules
+ End Project Dependency
+ Begin Project Dependency
+ Project_Dep_Name libapriconv_ces_modules
+ End Project Dependency
+ Begin Project Dependency
+ Project_Dep_Name xml
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "preaprapp"="..\..\apr\build\preaprapp.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name apr
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "preapriconv"="..\..\apr-iconv\build\preapriconv.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name apr
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "preaprutil"="..\build\preaprutil.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name apr
+ End Project Dependency
+ Begin Project Dependency
+ Project_Dep_Name aprapp
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "prelibaprapp"="..\..\apr\build\prelibaprapp.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name libapr
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "testdll"="..\..\apr\test\testdll.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name apr_ldap
+ End Project Dependency
+ Begin Project Dependency
+ Project_Dep_Name libapr
+ End Project Dependency
+ Begin Project Dependency
+ Project_Dep_Name libaprapp
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "testlib"="..\..\apr\test\testlib.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name apr
+ End Project Dependency
+ Begin Project Dependency
+ Project_Dep_Name aprapp
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "testutildll"=".\testutildll.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name libapr
+ End Project Dependency
+ Begin Project Dependency
+ Project_Dep_Name libaprapp
+ End Project Dependency
+ Begin Project Dependency
+ Project_Dep_Name libapriconv
+ End Project Dependency
+ Begin Project Dependency
+ Project_Dep_Name libaprutil
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "testutillib"=".\testutillib.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name apr
+ End Project Dependency
+ Begin Project Dependency
+ Project_Dep_Name aprapp
+ End Project Dependency
+ Begin Project Dependency
+ Project_Dep_Name apriconv
+ End Project Dependency
+ Begin Project Dependency
+ Project_Dep_Name aprutil
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "xml"="..\xml\expat\lib\xml.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/test/testbuckets.c b/test/testbuckets.c
new file mode 100644
index 0000000..3d0d46d
--- /dev/null
+++ b/test/testbuckets.c
@@ -0,0 +1,535 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "abts.h"
+#include "testutil.h"
+#include "apr_buckets.h"
+#include "apr_strings.h"
+
+static void test_create(abts_case *tc, void *data)
+{
+ apr_bucket_alloc_t *ba;
+ apr_bucket_brigade *bb;
+
+ ba = apr_bucket_alloc_create(p);
+ bb = apr_brigade_create(p, ba);
+
+ ABTS_ASSERT(tc, "new brigade not NULL", bb != NULL);
+ ABTS_ASSERT(tc, "new brigade is empty", APR_BRIGADE_EMPTY(bb));
+
+ apr_brigade_destroy(bb);
+ apr_bucket_alloc_destroy(ba);
+}
+
+static void test_simple(abts_case *tc, void *data)
+{
+ apr_bucket_alloc_t *ba;
+ apr_bucket_brigade *bb;
+ apr_bucket *fb, *tb;
+
+ ba = apr_bucket_alloc_create(p);
+ bb = apr_brigade_create(p, ba);
+
+ fb = APR_BRIGADE_FIRST(bb);
+ ABTS_ASSERT(tc, "first bucket of empty brigade is sentinel",
+ fb == APR_BRIGADE_SENTINEL(bb));
+
+ fb = apr_bucket_flush_create(ba);
+ APR_BRIGADE_INSERT_HEAD(bb, fb);
+
+ ABTS_ASSERT(tc, "first bucket of brigade is flush",
+ APR_BRIGADE_FIRST(bb) == fb);
+
+ ABTS_ASSERT(tc, "bucket after flush is sentinel",
+ APR_BUCKET_NEXT(fb) == APR_BRIGADE_SENTINEL(bb));
+
+ tb = apr_bucket_transient_create("aaa", 3, ba);
+ APR_BUCKET_INSERT_BEFORE(fb, tb);
+
+ ABTS_ASSERT(tc, "bucket before flush now transient",
+ APR_BUCKET_PREV(fb) == tb);
+ ABTS_ASSERT(tc, "bucket after transient is flush",
+ APR_BUCKET_NEXT(tb) == fb);
+ ABTS_ASSERT(tc, "bucket before transient is sentinel",
+ APR_BUCKET_PREV(tb) == APR_BRIGADE_SENTINEL(bb));
+
+ apr_brigade_cleanup(bb);
+
+ ABTS_ASSERT(tc, "cleaned up brigade was empty", APR_BRIGADE_EMPTY(bb));
+
+ apr_brigade_destroy(bb);
+ apr_bucket_alloc_destroy(ba);
+}
+
+static apr_bucket_brigade *make_simple_brigade(apr_bucket_alloc_t *ba,
+ const char *first,
+ const char *second)
+{
+ apr_bucket_brigade *bb = apr_brigade_create(p, ba);
+ apr_bucket *e;
+
+ e = apr_bucket_transient_create(first, strlen(first), ba);
+ APR_BRIGADE_INSERT_TAIL(bb, e);
+
+ e = apr_bucket_transient_create(second, strlen(second), ba);
+ APR_BRIGADE_INSERT_TAIL(bb, e);
+
+ return bb;
+}
+
+/* tests that 'bb' flattens to string 'expect'. */
+static void flatten_match(abts_case *tc, const char *ctx,
+ apr_bucket_brigade *bb,
+ const char *expect)
+{
+ apr_size_t elen = strlen(expect);
+ char *buf = malloc(elen);
+ apr_size_t len = elen;
+ char msg[200];
+
+ sprintf(msg, "%s: flatten brigade", ctx);
+ apr_assert_success(tc, msg, apr_brigade_flatten(bb, buf, &len));
+ sprintf(msg, "%s: length match (%ld not %ld)", ctx,
+ (long)len, (long)elen);
+ ABTS_ASSERT(tc, msg, len == elen);
+ sprintf(msg, "%s: result match", msg);
+ ABTS_STR_NEQUAL(tc, expect, buf, len);
+ free(buf);
+}
+
+static void test_flatten(abts_case *tc, void *data)
+{
+ apr_bucket_alloc_t *ba = apr_bucket_alloc_create(p);
+ apr_bucket_brigade *bb;
+
+ bb = make_simple_brigade(ba, "hello, ", "world");
+
+ flatten_match(tc, "flatten brigade", bb, "hello, world");
+
+ apr_brigade_destroy(bb);
+ apr_bucket_alloc_destroy(ba);
+}
+
+static int count_buckets(apr_bucket_brigade *bb)
+{
+ apr_bucket *e;
+ int count = 0;
+
+ for (e = APR_BRIGADE_FIRST(bb);
+ e != APR_BRIGADE_SENTINEL(bb);
+ e = APR_BUCKET_NEXT(e)) {
+ count++;
+ }
+
+ return count;
+}
+
+static void test_split(abts_case *tc, void *data)
+{
+ apr_bucket_alloc_t *ba = apr_bucket_alloc_create(p);
+ apr_bucket_brigade *bb, *bb2;
+ apr_bucket *e;
+
+ bb = make_simple_brigade(ba, "hello, ", "world");
+
+ /* split at the "world" bucket */
+ e = APR_BRIGADE_LAST(bb);
+ bb2 = apr_brigade_split(bb, e);
+
+ ABTS_ASSERT(tc, "split brigade contains one bucket",
+ count_buckets(bb2) == 1);
+ ABTS_ASSERT(tc, "original brigade contains one bucket",
+ count_buckets(bb) == 1);
+
+ flatten_match(tc, "match original brigade", bb, "hello, ");
+ flatten_match(tc, "match split brigade", bb2, "world");
+
+ apr_brigade_destroy(bb2);
+ apr_brigade_destroy(bb);
+ apr_bucket_alloc_destroy(ba);
+}
+
+#define COUNT 3000
+#define THESTR "hello"
+
+static void test_bwrite(abts_case *tc, void *data)
+{
+ apr_bucket_alloc_t *ba = apr_bucket_alloc_create(p);
+ apr_bucket_brigade *bb = apr_brigade_create(p, ba);
+ apr_off_t length;
+ int n;
+
+ for (n = 0; n < COUNT; n++) {
+ apr_assert_success(tc, "brigade_write",
+ apr_brigade_write(bb, NULL, NULL,
+ THESTR, sizeof THESTR));
+ }
+
+ apr_assert_success(tc, "determine brigade length",
+ apr_brigade_length(bb, 1, &length));
+
+ ABTS_ASSERT(tc, "brigade has correct length",
+ length == (COUNT * sizeof THESTR));
+
+ apr_brigade_destroy(bb);
+ apr_bucket_alloc_destroy(ba);
+}
+
+static void test_splitline(abts_case *tc, void *data)
+{
+ apr_bucket_alloc_t *ba = apr_bucket_alloc_create(p);
+ apr_bucket_brigade *bin, *bout;
+
+ bin = make_simple_brigade(ba, "blah blah blah-",
+ "end of line.\nfoo foo foo");
+ bout = apr_brigade_create(p, ba);
+
+ apr_assert_success(tc, "split line",
+ apr_brigade_split_line(bout, bin,
+ APR_BLOCK_READ, 100));
+
+ flatten_match(tc, "split line", bout, "blah blah blah-end of line.\n");
+ flatten_match(tc, "remainder", bin, "foo foo foo");
+
+ apr_brigade_destroy(bout);
+ apr_brigade_destroy(bin);
+ apr_bucket_alloc_destroy(ba);
+}
+
+/* Test that bucket E has content EDATA of length ELEN. */
+static void test_bucket_content(abts_case *tc,
+ apr_bucket *e,
+ const char *edata,
+ apr_size_t elen)
+{
+ const char *adata;
+ apr_size_t alen;
+
+ apr_assert_success(tc, "read from bucket",
+ apr_bucket_read(e, &adata, &alen,
+ APR_BLOCK_READ));
+
+ ABTS_ASSERT(tc, "read expected length", alen == elen);
+ ABTS_STR_NEQUAL(tc, edata, adata, elen);
+}
+
+static void test_splits(abts_case *tc, void *ctx)
+{
+ apr_bucket_alloc_t *ba = apr_bucket_alloc_create(p);
+ apr_bucket_brigade *bb;
+ apr_bucket *e;
+ char *str = "alphabeta";
+ int n;
+
+ bb = apr_brigade_create(p, ba);
+
+ APR_BRIGADE_INSERT_TAIL(bb,
+ apr_bucket_immortal_create(str, 9, ba));
+ APR_BRIGADE_INSERT_TAIL(bb,
+ apr_bucket_transient_create(str, 9, ba));
+ APR_BRIGADE_INSERT_TAIL(bb,
+ apr_bucket_heap_create(strdup(str), 9, free, ba));
+ APR_BRIGADE_INSERT_TAIL(bb,
+ apr_bucket_pool_create(apr_pstrdup(p, str), 9, p,
+ ba));
+
+ ABTS_ASSERT(tc, "four buckets inserted", count_buckets(bb) == 4);
+
+ /* now split each of the buckets after byte 5 */
+ for (n = 0, e = APR_BRIGADE_FIRST(bb); n < 4; n++) {
+ ABTS_ASSERT(tc, "reached end of brigade",
+ e != APR_BRIGADE_SENTINEL(bb));
+ ABTS_ASSERT(tc, "split bucket OK",
+ apr_bucket_split(e, 5) == APR_SUCCESS);
+ e = APR_BUCKET_NEXT(e);
+ ABTS_ASSERT(tc, "split OK", e != APR_BRIGADE_SENTINEL(bb));
+ e = APR_BUCKET_NEXT(e);
+ }
+
+ ABTS_ASSERT(tc, "four buckets split into eight",
+ count_buckets(bb) == 8);
+
+ for (n = 0, e = APR_BRIGADE_FIRST(bb); n < 4; n++) {
+ const char *data;
+ apr_size_t len;
+
+ apr_assert_success(tc, "read alpha from bucket",
+ apr_bucket_read(e, &data, &len, APR_BLOCK_READ));
+ ABTS_ASSERT(tc, "read 5 bytes", len == 5);
+ ABTS_STR_NEQUAL(tc, "alpha", data, 5);
+
+ e = APR_BUCKET_NEXT(e);
+
+ apr_assert_success(tc, "read beta from bucket",
+ apr_bucket_read(e, &data, &len, APR_BLOCK_READ));
+ ABTS_ASSERT(tc, "read 4 bytes", len == 4);
+ ABTS_STR_NEQUAL(tc, "beta", data, 5);
+
+ e = APR_BUCKET_NEXT(e);
+ }
+
+ /* now delete the "alpha" buckets */
+ for (n = 0, e = APR_BRIGADE_FIRST(bb); n < 4; n++) {
+ apr_bucket *f;
+
+ ABTS_ASSERT(tc, "reached end of brigade",
+ e != APR_BRIGADE_SENTINEL(bb));
+ f = APR_BUCKET_NEXT(e);
+ apr_bucket_delete(e);
+ e = APR_BUCKET_NEXT(f);
+ }
+
+ ABTS_ASSERT(tc, "eight buckets reduced to four",
+ count_buckets(bb) == 4);
+
+ flatten_match(tc, "flatten beta brigade", bb,
+ "beta" "beta" "beta" "beta");
+
+ apr_brigade_destroy(bb);
+ apr_bucket_alloc_destroy(ba);
+}
+
+#define TIF_FNAME "testfile.txt"
+
+static void test_insertfile(abts_case *tc, void *ctx)
+{
+ apr_bucket_alloc_t *ba = apr_bucket_alloc_create(p);
+ apr_bucket_brigade *bb;
+ const apr_off_t bignum = (APR_INT64_C(2) << 32) + 424242;
+ apr_off_t count;
+ apr_file_t *f;
+ apr_bucket *e;
+
+ ABTS_ASSERT(tc, "open test file",
+ apr_file_open(&f, TIF_FNAME,
+ APR_FOPEN_WRITE | APR_FOPEN_TRUNCATE
+ | APR_FOPEN_CREATE | APR_FOPEN_SPARSE,
+ APR_OS_DEFAULT, p) == APR_SUCCESS);
+
+ if (apr_file_trunc(f, bignum)) {
+ apr_file_close(f);
+ apr_file_remove(TIF_FNAME, p);
+ ABTS_NOT_IMPL(tc, "Skipped: could not create large file");
+ return;
+ }
+
+ bb = apr_brigade_create(p, ba);
+
+ e = apr_brigade_insert_file(bb, f, 0, bignum, p);
+
+ ABTS_ASSERT(tc, "inserted file was not at end of brigade",
+ e == APR_BRIGADE_LAST(bb));
+
+ /* check that the total size of inserted buckets is equal to the
+ * total size of the file. */
+ count = 0;
+
+ for (e = APR_BRIGADE_FIRST(bb);
+ e != APR_BRIGADE_SENTINEL(bb);
+ e = APR_BUCKET_NEXT(e)) {
+ ABTS_ASSERT(tc, "bucket size sane", e->length != (apr_size_t)-1);
+ count += e->length;
+ }
+
+ ABTS_ASSERT(tc, "total size of buckets incorrect", count == bignum);
+
+ apr_brigade_destroy(bb);
+
+ /* Truncate the file to zero size before close() so that we don't
+ * actually write out the large file if we are on a non-sparse file
+ * system - like Mac OS X's HFS. Otherwise, pity the poor user who
+ * has to wait for the 8GB file to be written to disk.
+ */
+ apr_file_trunc(f, 0);
+
+ apr_file_close(f);
+ apr_bucket_alloc_destroy(ba);
+ apr_file_remove(TIF_FNAME, p);
+}
+
+/* Make a test file named FNAME, and write CONTENTS to it. */
+static apr_file_t *make_test_file(abts_case *tc, const char *fname,
+ const char *contents)
+{
+ apr_file_t *f;
+
+ ABTS_ASSERT(tc, "create test file",
+ apr_file_open(&f, fname,
+ APR_FOPEN_READ|APR_FOPEN_WRITE|APR_FOPEN_TRUNCATE|APR_FOPEN_CREATE,
+ APR_OS_DEFAULT, p) == APR_SUCCESS);
+
+ ABTS_ASSERT(tc, "write test file contents",
+ apr_file_puts(contents, f) == APR_SUCCESS);
+
+ return f;
+}
+
+static void test_manyfile(abts_case *tc, void *data)
+{
+ apr_bucket_alloc_t *ba = apr_bucket_alloc_create(p);
+ apr_bucket_brigade *bb = apr_brigade_create(p, ba);
+ apr_file_t *f;
+
+ f = make_test_file(tc, "manyfile.bin",
+ "world" "hello" "brave" " ,\n");
+
+ apr_brigade_insert_file(bb, f, 5, 5, p);
+ apr_brigade_insert_file(bb, f, 16, 1, p);
+ apr_brigade_insert_file(bb, f, 15, 1, p);
+ apr_brigade_insert_file(bb, f, 10, 5, p);
+ apr_brigade_insert_file(bb, f, 15, 1, p);
+ apr_brigade_insert_file(bb, f, 0, 5, p);
+ apr_brigade_insert_file(bb, f, 17, 1, p);
+
+ /* can you tell what it is yet? */
+ flatten_match(tc, "file seek test", bb,
+ "hello, brave world\n");
+
+ apr_file_close(f);
+ apr_brigade_destroy(bb);
+ apr_bucket_alloc_destroy(ba);
+}
+
+/* Regression test for PR 34708, where a file bucket will keep
+ * duplicating itself on being read() when EOF is reached
+ * prematurely. */
+static void test_truncfile(abts_case *tc, void *data)
+{
+ apr_bucket_alloc_t *ba = apr_bucket_alloc_create(p);
+ apr_bucket_brigade *bb = apr_brigade_create(p, ba);
+ apr_file_t *f = make_test_file(tc, "testfile.txt", "hello");
+ apr_bucket *e;
+ const char *buf;
+ apr_size_t len;
+
+ apr_brigade_insert_file(bb, f, 0, 5, p);
+
+ apr_file_trunc(f, 0);
+
+ e = APR_BRIGADE_FIRST(bb);
+
+ ABTS_ASSERT(tc, "single bucket in brigade",
+ APR_BUCKET_NEXT(e) == APR_BRIGADE_SENTINEL(bb));
+
+ apr_bucket_file_enable_mmap(e, 0);
+
+ ABTS_ASSERT(tc, "read gave APR_EOF",
+ apr_bucket_read(e, &buf, &len, APR_BLOCK_READ) == APR_EOF);
+
+ ABTS_ASSERT(tc, "read length 0", len == 0);
+
+ ABTS_ASSERT(tc, "still a single bucket in brigade",
+ APR_BUCKET_NEXT(e) == APR_BRIGADE_SENTINEL(bb));
+
+ apr_file_close(f);
+ apr_brigade_destroy(bb);
+ apr_bucket_alloc_destroy(ba);
+}
+
+static const char hello[] = "hello, world";
+
+static void test_partition(abts_case *tc, void *data)
+{
+ apr_bucket_alloc_t *ba = apr_bucket_alloc_create(p);
+ apr_bucket_brigade *bb = apr_brigade_create(p, ba);
+ apr_bucket *e;
+
+ e = apr_bucket_immortal_create(hello, strlen(hello), ba);
+ APR_BRIGADE_INSERT_HEAD(bb, e);
+
+ apr_assert_success(tc, "partition brigade",
+ apr_brigade_partition(bb, 5, &e));
+
+ test_bucket_content(tc, APR_BRIGADE_FIRST(bb),
+ "hello", 5);
+
+ test_bucket_content(tc, APR_BRIGADE_LAST(bb),
+ ", world", 7);
+
+ ABTS_ASSERT(tc, "partition returns APR_INCOMPLETE",
+ apr_brigade_partition(bb, 8192, &e));
+
+ ABTS_ASSERT(tc, "APR_INCOMPLETE partition returned sentinel",
+ e == APR_BRIGADE_SENTINEL(bb));
+
+ apr_brigade_destroy(bb);
+ apr_bucket_alloc_destroy(ba);
+}
+
+static void test_write_split(abts_case *tc, void *data)
+{
+ apr_bucket_alloc_t *ba = apr_bucket_alloc_create(p);
+ apr_bucket_brigade *bb1 = apr_brigade_create(p, ba);
+ apr_bucket_brigade *bb2;
+ apr_bucket *e;
+
+ e = apr_bucket_heap_create(hello, strlen(hello), NULL, ba);
+ APR_BRIGADE_INSERT_HEAD(bb1, e);
+ apr_bucket_split(e, strlen("hello, "));
+ bb2 = apr_brigade_split(bb1, APR_BRIGADE_LAST(bb1));
+ apr_brigade_write(bb1, NULL, NULL, "foo", strlen("foo"));
+ test_bucket_content(tc, APR_BRIGADE_FIRST(bb2), "world", 5);
+
+ apr_brigade_destroy(bb1);
+ apr_brigade_destroy(bb2);
+ apr_bucket_alloc_destroy(ba);
+}
+
+static void test_write_putstrs(abts_case *tc, void *data)
+{
+ apr_bucket_alloc_t *ba = apr_bucket_alloc_create(p);
+ apr_bucket_brigade *bb = apr_brigade_create(p, ba);
+ apr_bucket *e;
+ char buf[30];
+ apr_size_t len = sizeof(buf);
+ const char *expect = "123456789abcdefghij";
+
+ e = apr_bucket_heap_create("1", 1, NULL, ba);
+ APR_BRIGADE_INSERT_HEAD(bb, e);
+
+ apr_brigade_putstrs(bb, NULL, NULL, "2", "34", "567", "8", "9a", "bcd",
+ "e", "f", "gh", "i", NULL);
+ apr_brigade_putstrs(bb, NULL, NULL, "j", NULL);
+ apr_assert_success(tc, "apr_brigade_flatten",
+ apr_brigade_flatten(bb, buf, &len));
+ ABTS_STR_NEQUAL(tc, expect, buf, strlen(expect));
+
+ apr_brigade_destroy(bb);
+ apr_bucket_alloc_destroy(ba);
+}
+
+abts_suite *testbuckets(abts_suite *suite)
+{
+ suite = ADD_SUITE(suite);
+
+ abts_run_test(suite, test_create, NULL);
+ abts_run_test(suite, test_simple, NULL);
+ abts_run_test(suite, test_flatten, NULL);
+ abts_run_test(suite, test_split, NULL);
+ abts_run_test(suite, test_bwrite, NULL);
+ abts_run_test(suite, test_splitline, NULL);
+ abts_run_test(suite, test_splits, NULL);
+ abts_run_test(suite, test_insertfile, NULL);
+ abts_run_test(suite, test_manyfile, NULL);
+ abts_run_test(suite, test_truncfile, NULL);
+ abts_run_test(suite, test_partition, NULL);
+ abts_run_test(suite, test_write_split, NULL);
+ abts_run_test(suite, test_write_putstrs, NULL);
+
+ return suite;
+}
+
+
diff --git a/test/testcrypto.c b/test/testcrypto.c
new file mode 100644
index 0000000..865cffc
--- /dev/null
+++ b/test/testcrypto.c
@@ -0,0 +1,1545 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "testutil.h"
+#include "apr.h"
+#include "apu.h"
+#include "apu_errno.h"
+#include "apr_pools.h"
+#include "apr_dso.h"
+#include "apr_crypto.h"
+#include "apr_strings.h"
+
+#if APU_HAVE_CRYPTO
+
+#define TEST_STRING "12345"
+#define ALIGNED_STRING "123456789012345"
+
+static const apr_crypto_driver_t *get_driver(abts_case *tc, apr_pool_t *pool,
+ const char *name, const char *params)
+{
+
+ const apr_crypto_driver_t *driver = NULL;
+ const apu_err_t *result = NULL;
+ apr_status_t rv;
+
+ rv = apr_crypto_init(pool);
+ ABTS_ASSERT(tc, "failed to init apr_crypto", rv == APR_SUCCESS);
+
+ rv = apr_crypto_get_driver(&driver, name, params, &result, pool);
+ if (APR_ENOTIMPL == rv) {
+ ABTS_NOT_IMPL(tc,
+ apr_psprintf(pool, "Crypto driver '%s' not implemented", (char *)name));
+ return NULL;
+ }
+ if (APR_EDSOOPEN == rv) {
+ ABTS_NOT_IMPL(tc,
+ apr_psprintf(pool, "Crypto driver '%s' DSO could not be opened", (char *)name));
+ return NULL;
+ }
+ if (APR_SUCCESS != rv && result) {
+ char err[1024];
+ apr_strerror(rv, err, sizeof(err) - 1);
+ fprintf(stderr, "get_driver error %d: %s: '%s' native error %d: %s (%s),",
+ rv, err, name, result->rc, result->reason ? result->reason : "",
+ result->msg ? result->msg : "");
+ }
+ ABTS_ASSERT(tc, apr_psprintf(pool, "failed to apr_crypto_get_driver for '%s' with %d",
+ name, rv), rv == APR_SUCCESS);
+ ABTS_ASSERT(tc, "apr_crypto_get_driver returned NULL", driver != NULL);
+ if (!driver || rv) {
+ return NULL;
+ }
+
+ return driver;
+
+}
+
+static const apr_crypto_driver_t *get_nss_driver(abts_case *tc,
+ apr_pool_t *pool)
+{
+
+ /* initialise NSS */
+ return get_driver(tc, pool, "nss", "");
+
+}
+
+static const apr_crypto_driver_t *get_openssl_driver(abts_case *tc,
+ apr_pool_t *pool)
+{
+
+ return get_driver(tc, pool, "openssl", NULL);
+
+}
+
+static const apr_crypto_driver_t *get_commoncrypto_driver(abts_case *tc,
+ apr_pool_t *pool)
+{
+
+ return get_driver(tc, pool, "commoncrypto", NULL);
+
+}
+
+static apr_crypto_t *make(abts_case *tc, apr_pool_t *pool,
+ const apr_crypto_driver_t *driver)
+{
+
+ apr_crypto_t *f = NULL;
+
+ if (!driver) {
+ return NULL;
+ }
+
+ /* get the context */
+ apr_crypto_make(&f, driver, "engine=openssl", pool);
+ ABTS_ASSERT(tc, "apr_crypto_make returned NULL", f != NULL);
+
+ return f;
+
+}
+
+static const apr_crypto_key_t *keysecret(abts_case *tc, apr_pool_t *pool,
+ const apr_crypto_driver_t *driver, const apr_crypto_t *f,
+ apr_crypto_block_key_type_e type, apr_crypto_block_key_mode_e mode,
+ int doPad, apr_size_t secretLen, const char *description)
+{
+ apr_crypto_key_t *key = NULL;
+ const apu_err_t *result = NULL;
+ apr_crypto_key_rec_t *rec = apr_pcalloc(pool, sizeof(apr_crypto_key_rec_t));
+ apr_status_t rv;
+
+ if (!f) {
+ return NULL;
+ }
+
+ rec->ktype = APR_CRYPTO_KTYPE_SECRET;
+ rec->type = type;
+ rec->mode = mode;
+ rec->pad = doPad;
+ rec->k.secret.secret = apr_pcalloc(pool, secretLen);
+ rec->k.secret.secretLen = secretLen;
+
+ /* init the passphrase */
+ rv = apr_crypto_key(&key, rec, f, pool);
+ if (APR_ENOCIPHER == rv) {
+ apr_crypto_error(&result, f);
+ ABTS_NOT_IMPL(tc,
+ apr_psprintf(pool, "skipped: %s %s key return APR_ENOCIPHER: error %d: %s (%s)\n", description, apr_crypto_driver_name(driver), result->rc, result->reason ? result->reason : "", result->msg ? result->msg : ""));
+ return NULL;
+ }
+ else {
+ if (APR_SUCCESS != rv) {
+ apr_crypto_error(&result, f);
+ fprintf(stderr, "key: %s %s apr error %d / native error %d: %s (%s)\n",
+ description, apr_crypto_driver_name(driver), rv, result->rc,
+ result->reason ? result->reason : "",
+ result->msg ? result->msg : "");
+ }
+ ABTS_ASSERT(tc, "apr_crypto_key returned APR_EKEYLENGTH", rv != APR_EKEYLENGTH);
+ ABTS_ASSERT(tc, "apr_crypto_key returned APR_ENOKEY", rv != APR_ENOKEY);
+ ABTS_ASSERT(tc, "apr_crypto_key returned APR_EPADDING",
+ rv != APR_EPADDING);
+ ABTS_ASSERT(tc, "apr_crypto_key returned APR_EKEYTYPE",
+ rv != APR_EKEYTYPE);
+ ABTS_ASSERT(tc, "failed to apr_crypto_key", rv == APR_SUCCESS);
+ ABTS_ASSERT(tc, "apr_crypto_key returned NULL context", key != NULL);
+ }
+ if (rv) {
+ return NULL;
+ }
+ return key;
+
+}
+
+static const apr_crypto_key_t *passphrase(abts_case *tc, apr_pool_t *pool,
+ const apr_crypto_driver_t *driver, const apr_crypto_t *f,
+ apr_crypto_block_key_type_e type, apr_crypto_block_key_mode_e mode,
+ int doPad, const char *description)
+{
+
+ apr_crypto_key_t *key = NULL;
+ const apu_err_t *result = NULL;
+ const char *pass = "secret";
+ const char *salt = "salt";
+ apr_status_t rv;
+
+ if (!f) {
+ return NULL;
+ }
+
+ /* init the passphrase */
+ rv = apr_crypto_passphrase(&key, NULL, pass, strlen(pass),
+ (unsigned char *) salt, strlen(salt), type, mode, doPad, 4096, f,
+ pool);
+ if (APR_ENOCIPHER == rv) {
+ apr_crypto_error(&result, f);
+ ABTS_NOT_IMPL(tc, apr_psprintf(pool,
+ "skipped: %s %s passphrase return APR_ENOCIPHER: error %d: %s (%s)\n",
+ description, apr_crypto_driver_name(driver), result->rc,
+ result->reason ? result->reason : "", result->msg ? result->msg : ""));
+ return NULL;
+ }
+ else {
+ if (APR_SUCCESS != rv) {
+ apr_crypto_error(&result, f);
+ fprintf(stderr, "passphrase: %s %s apr error %d / native error %d: %s (%s)\n",
+ description, apr_crypto_driver_name(driver), rv, result->rc,
+ result->reason ? result->reason : "",
+ result->msg ? result->msg : "");
+ }
+ ABTS_ASSERT(tc, "apr_crypto_passphrase returned APR_ENOKEY", rv != APR_ENOKEY);
+ ABTS_ASSERT(tc, "apr_crypto_passphrase returned APR_EPADDING", rv != APR_EPADDING);
+ ABTS_ASSERT(tc, "apr_crypto_passphrase returned APR_EKEYTYPE", rv != APR_EKEYTYPE);
+ ABTS_ASSERT(tc, "failed to apr_crypto_passphrase", rv == APR_SUCCESS);
+ ABTS_ASSERT(tc, "apr_crypto_passphrase returned NULL context", key != NULL);
+ }
+ if (rv) {
+ return NULL;
+ }
+ return key;
+
+}
+
+static const apr_crypto_key_t *keypassphrase(abts_case *tc, apr_pool_t *pool,
+ const apr_crypto_driver_t *driver, const apr_crypto_t *f,
+ apr_crypto_block_key_type_e type, apr_crypto_block_key_mode_e mode,
+ int doPad, const char *description)
+{
+
+ apr_crypto_key_t *key = NULL;
+ const apu_err_t *result = NULL;
+ const char *pass = "secret";
+ const char *salt = "salt";
+ apr_crypto_key_rec_t *rec = apr_pcalloc(pool, sizeof(apr_crypto_key_rec_t));
+ apr_status_t rv;
+
+ if (!f) {
+ return NULL;
+ }
+
+ rec->ktype = APR_CRYPTO_KTYPE_PASSPHRASE;
+ rec->type = type;
+ rec->mode = mode;
+ rec->pad = doPad;
+ rec->k.passphrase.pass = pass;
+ rec->k.passphrase.passLen = strlen(pass);
+ rec->k.passphrase.salt = (unsigned char *)salt;
+ rec->k.passphrase.saltLen = strlen(salt);
+ rec->k.passphrase.iterations = 4096;
+
+ /* init the passphrase */
+ rv = apr_crypto_key(&key, rec, f, pool);
+ if (APR_ENOCIPHER == rv) {
+ apr_crypto_error(&result, f);
+ ABTS_NOT_IMPL(tc, apr_psprintf(pool,
+ "skipped: %s %s key passphrase return APR_ENOCIPHER: error %d: %s (%s)\n",
+ description, apr_crypto_driver_name(driver), result->rc,
+ result->reason ? result->reason : "", result->msg ? result->msg : ""));
+ return NULL;
+ }
+ else {
+ if (APR_SUCCESS != rv) {
+ apr_crypto_error(&result, f);
+ fprintf(stderr, "key passphrase: %s %s apr error %d / native error %d: %s (%s)\n",
+ description, apr_crypto_driver_name(driver), rv, result->rc,
+ result->reason ? result->reason : "",
+ result->msg ? result->msg : "");
+ }
+ ABTS_ASSERT(tc, "apr_crypto_key returned APR_ENOKEY", rv != APR_ENOKEY);
+ ABTS_ASSERT(tc, "apr_crypto_key returned APR_EPADDING", rv != APR_EPADDING);
+ ABTS_ASSERT(tc, "apr_crypto_key returned APR_EKEYTYPE", rv != APR_EKEYTYPE);
+ ABTS_ASSERT(tc, "failed to apr_crypto_key", rv == APR_SUCCESS);
+ ABTS_ASSERT(tc, "apr_crypto_key returned NULL context", key != NULL);
+ }
+ if (rv) {
+ return NULL;
+ }
+ return key;
+
+}
+
+static unsigned char *encrypt_block(abts_case *tc, apr_pool_t *pool,
+ const apr_crypto_driver_t *driver, const apr_crypto_t *f,
+ const apr_crypto_key_t *key, const unsigned char *in,
+ const apr_size_t inlen, unsigned char **cipherText,
+ apr_size_t *cipherTextLen, const unsigned char **iv,
+ apr_size_t *blockSize, const char *description)
+{
+
+ apr_crypto_block_t *block = NULL;
+ const apu_err_t *result = NULL;
+ apr_size_t len = 0;
+ apr_status_t rv;
+
+ if (!driver || !f || !key || !in) {
+ return NULL;
+ }
+
+ /* init the encryption */
+ rv = apr_crypto_block_encrypt_init(&block, iv, key, blockSize, pool);
+ if (APR_ENOTIMPL == rv) {
+ ABTS_NOT_IMPL(tc, "apr_crypto_block_encrypt_init returned APR_ENOTIMPL");
+ }
+ else {
+ if (APR_SUCCESS != rv) {
+ apr_crypto_error(&result, f);
+ fprintf(stderr,
+ "encrypt_init: %s %s (APR %d) native error %d: %s (%s)\n",
+ description, apr_crypto_driver_name(driver), rv, result->rc,
+ result->reason ? result->reason : "",
+ result->msg ? result->msg : "");
+ }
+ ABTS_ASSERT(tc, "apr_crypto_block_encrypt_init returned APR_ENOKEY",
+ rv != APR_ENOKEY);
+ ABTS_ASSERT(tc, "apr_crypto_block_encrypt_init returned APR_ENOIV",
+ rv != APR_ENOIV);
+ ABTS_ASSERT(tc, "apr_crypto_block_encrypt_init returned APR_EKEYTYPE",
+ rv != APR_EKEYTYPE);
+ ABTS_ASSERT(tc, "apr_crypto_block_encrypt_init returned APR_EKEYLENGTH",
+ rv != APR_EKEYLENGTH);
+ ABTS_ASSERT(tc,
+ "apr_crypto_block_encrypt_init returned APR_ENOTENOUGHENTROPY",
+ rv != APR_ENOTENOUGHENTROPY);
+ ABTS_ASSERT(tc, "failed to apr_crypto_block_encrypt_init",
+ rv == APR_SUCCESS);
+ ABTS_ASSERT(tc, "apr_crypto_block_encrypt_init returned NULL context",
+ block != NULL);
+ }
+ if (!block || rv) {
+ return NULL;
+ }
+
+ /* encrypt the block */
+ rv = apr_crypto_block_encrypt(cipherText, cipherTextLen, in, inlen, block);
+ if (APR_SUCCESS != rv) {
+ apr_crypto_error(&result, f);
+ fprintf(stderr, "encrypt: %s %s (APR %d) native error %d: %s (%s)\n",
+ description, apr_crypto_driver_name(driver), rv, result->rc,
+ result->reason ? result->reason : "",
+ result->msg ? result->msg : "");
+ }
+ ABTS_ASSERT(tc, "apr_crypto_block_encrypt returned APR_ECRYPT", rv != APR_ECRYPT);
+ ABTS_ASSERT(tc, "failed to apr_crypto_block_encrypt", rv == APR_SUCCESS);
+ ABTS_ASSERT(tc, "apr_crypto_block_encrypt failed to allocate buffer", *cipherText != NULL);
+ if (rv) {
+ return NULL;
+ }
+
+ /* finalise the encryption */
+ rv = apr_crypto_block_encrypt_finish(*cipherText + *cipherTextLen, &len,
+ block);
+ if (APR_SUCCESS != rv) {
+ apr_crypto_error(&result, f);
+ fprintf(stderr,
+ "encrypt_finish: %s %s (APR %d) native error %d: %s (%s)\n",
+ description, apr_crypto_driver_name(driver), rv, result->rc,
+ result->reason ? result->reason : "",
+ result->msg ? result->msg : "");
+ }
+ ABTS_ASSERT(tc, "apr_crypto_block_encrypt_finish returned APR_ECRYPT", rv != APR_ECRYPT);
+ ABTS_ASSERT(tc, "apr_crypto_block_encrypt_finish returned APR_EPADDING", rv != APR_EPADDING);
+ ABTS_ASSERT(tc, "apr_crypto_block_encrypt_finish returned APR_ENOSPACE", rv != APR_ENOSPACE);
+ ABTS_ASSERT(tc, "failed to apr_crypto_block_encrypt_finish", rv == APR_SUCCESS);
+ *cipherTextLen += len;
+ apr_crypto_block_cleanup(block);
+ if (rv) {
+ return NULL;
+ }
+
+ return *cipherText;
+
+}
+
+static unsigned char *decrypt_block(abts_case *tc, apr_pool_t *pool,
+ const apr_crypto_driver_t *driver, const apr_crypto_t *f,
+ const apr_crypto_key_t *key, unsigned char *cipherText,
+ apr_size_t cipherTextLen, unsigned char **plainText,
+ apr_size_t *plainTextLen, const unsigned char *iv,
+ apr_size_t *blockSize, const char *description)
+{
+
+ apr_crypto_block_t *block = NULL;
+ const apu_err_t *result = NULL;
+ apr_size_t len = 0;
+ apr_status_t rv;
+
+ if (!driver || !f || !key || !cipherText) {
+ return NULL;
+ }
+
+ /* init the decryption */
+ rv = apr_crypto_block_decrypt_init(&block, blockSize, iv, key, pool);
+ if (APR_ENOTIMPL == rv) {
+ ABTS_NOT_IMPL(tc, "apr_crypto_block_decrypt_init returned APR_ENOTIMPL");
+ }
+ else {
+ if (APR_SUCCESS != rv) {
+ apr_crypto_error(&result, f);
+ fprintf(stderr,
+ "decrypt_init: %s %s (APR %d) native error %d: %s (%s)\n",
+ description, apr_crypto_driver_name(driver), rv, result->rc,
+ result->reason ? result->reason : "",
+ result->msg ? result->msg : "");
+ }
+ ABTS_ASSERT(tc, "apr_crypto_block_decrypt_init returned APR_ENOKEY", rv != APR_ENOKEY);
+ ABTS_ASSERT(tc, "apr_crypto_block_decrypt_init returned APR_ENOIV", rv != APR_ENOIV);
+ ABTS_ASSERT(tc, "apr_crypto_block_decrypt_init returned APR_EKEYTYPE", rv != APR_EKEYTYPE);
+ ABTS_ASSERT(tc, "apr_crypto_block_decrypt_init returned APR_EKEYLENGTH", rv != APR_EKEYLENGTH);
+ ABTS_ASSERT(tc, "failed to apr_crypto_block_decrypt_init", rv == APR_SUCCESS);
+ ABTS_ASSERT(tc, "apr_crypto_block_decrypt_init returned NULL context", block != NULL);
+ }
+ if (!block || rv) {
+ return NULL;
+ }
+
+ /* decrypt the block */
+ rv = apr_crypto_block_decrypt(plainText, plainTextLen, cipherText,
+ cipherTextLen, block);
+ if (APR_SUCCESS != rv) {
+ apr_crypto_error(&result, f);
+ fprintf(stderr, "decrypt: %s %s (APR %d) native error %d: %s (%s)\n",
+ description, apr_crypto_driver_name(driver), rv, result->rc,
+ result->reason ? result->reason : "",
+ result->msg ? result->msg : "");
+ }
+ ABTS_ASSERT(tc, "apr_crypto_block_decrypt returned APR_ECRYPT", rv != APR_ECRYPT);
+ ABTS_ASSERT(tc, "failed to apr_crypto_block_decrypt", rv == APR_SUCCESS);
+ ABTS_ASSERT(tc, "apr_crypto_block_decrypt failed to allocate buffer", *plainText != NULL);
+ if (rv) {
+ return NULL;
+ }
+
+ /* finalise the decryption */
+ rv = apr_crypto_block_decrypt_finish(*plainText + *plainTextLen, &len,
+ block);
+ if (APR_SUCCESS != rv) {
+ apr_crypto_error(&result, f);
+ fprintf(stderr,
+ "decrypt_finish: %s %s (APR %d) native error %d: %s (%s)\n",
+ description, apr_crypto_driver_name(driver), rv, result->rc,
+ result->reason ? result->reason : "",
+ result->msg ? result->msg : "");
+ }
+ ABTS_ASSERT(tc, "apr_crypto_block_decrypt_finish returned APR_ECRYPT", rv != APR_ECRYPT);
+ ABTS_ASSERT(tc, "apr_crypto_block_decrypt_finish returned APR_EPADDING", rv != APR_EPADDING);
+ ABTS_ASSERT(tc, "apr_crypto_block_decrypt_finish returned APR_ENOSPACE", rv != APR_ENOSPACE);
+ ABTS_ASSERT(tc, "failed to apr_crypto_block_decrypt_finish", rv == APR_SUCCESS);
+ if (rv) {
+ return NULL;
+ }
+
+ *plainTextLen += len;
+ apr_crypto_block_cleanup(block);
+
+ return *plainText;
+
+}
+
+/**
+ * Interoperability test.
+ *
+ * data must point at an array of two driver structures. Data will be encrypted
+ * with the first driver, and decrypted with the second.
+ *
+ * If the two drivers interoperate, the test passes.
+ */
+static void crypto_block_cross(abts_case *tc, apr_pool_t *pool,
+ const apr_crypto_driver_t **drivers,
+ const apr_crypto_block_key_type_e type,
+ const apr_crypto_block_key_mode_e mode, int doPad,
+ const unsigned char *in, apr_size_t inlen, apr_size_t secretLen,
+ const char *description)
+{
+ const apr_crypto_driver_t *driver1 = drivers[0];
+ const apr_crypto_driver_t *driver2 = drivers[1];
+ apr_crypto_t *f1 = NULL;
+ apr_crypto_t *f2 = NULL;
+ const apr_crypto_key_t *key1 = NULL;
+ const apr_crypto_key_t *key2 = NULL;
+ const apr_crypto_key_t *key3 = NULL;
+ const apr_crypto_key_t *key4 = NULL;
+ const apr_crypto_key_t *key5 = NULL;
+ const apr_crypto_key_t *key6 = NULL;
+
+ unsigned char *cipherText = NULL;
+ apr_size_t cipherTextLen = 0;
+ unsigned char *plainText = NULL;
+ apr_size_t plainTextLen = 0;
+ const unsigned char *iv = NULL;
+ apr_size_t blockSize = 0;
+
+ f1 = make(tc, pool, driver1);
+ f2 = make(tc, pool, driver2);
+ key1 = passphrase(tc, pool, driver1, f1, type, mode, doPad, description);
+ key2 = passphrase(tc, pool, driver2, f2, type, mode, doPad, description);
+
+ cipherText = encrypt_block(tc, pool, driver1, f1, key1, in, inlen,
+ &cipherText, &cipherTextLen, &iv, &blockSize, description);
+ plainText = decrypt_block(tc, pool, driver2, f2, key2, cipherText,
+ cipherTextLen, &plainText, &plainTextLen, iv, &blockSize,
+ description);
+
+ if (cipherText && plainText) {
+ if (memcmp(in, plainText, inlen)) {
+ fprintf(stderr, "passphrase cross mismatch: %s %s/%s\n", description,
+ apr_crypto_driver_name(driver1), apr_crypto_driver_name(
+ driver2));
+ }
+ ABTS_STR_EQUAL(tc, (char *)in, (char *)plainText);
+ }
+
+ key3 = keysecret(tc, pool, driver1, f1, type, mode, doPad, secretLen, description);
+ key4 = keysecret(tc, pool, driver2, f2, type, mode, doPad, secretLen, description);
+
+ iv = NULL;
+ blockSize = 0;
+ cipherText = NULL;
+ plainText = NULL;
+ cipherText = encrypt_block(tc, pool, driver1, f1, key3, in, inlen,
+ &cipherText, &cipherTextLen, &iv, &blockSize, description);
+ plainText = decrypt_block(tc, pool, driver2, f2, key4, cipherText,
+ cipherTextLen, &plainText, &plainTextLen, iv, &blockSize,
+ description);
+
+ if (cipherText && plainText) {
+ if (memcmp(in, plainText, inlen)) {
+ fprintf(stderr, "key secret cross mismatch: %s %s/%s\n", description,
+ apr_crypto_driver_name(driver1), apr_crypto_driver_name(
+ driver2));
+ }
+ ABTS_STR_EQUAL(tc, (char *)in, (char *)plainText);
+ }
+
+ key5 = keypassphrase(tc, pool, driver1, f1, type, mode, doPad, description);
+ key6 = keypassphrase(tc, pool, driver2, f2, type, mode, doPad, description);
+
+ iv = NULL;
+ blockSize = 0;
+ cipherText = NULL;
+ plainText = NULL;
+ cipherText = encrypt_block(tc, pool, driver1, f1, key5, in, inlen,
+ &cipherText, &cipherTextLen, &iv, &blockSize, description);
+ plainText = decrypt_block(tc, pool, driver2, f2, key6, cipherText,
+ cipherTextLen, &plainText, &plainTextLen, iv, &blockSize,
+ description);
+
+ if (cipherText && plainText) {
+ if (memcmp(in, plainText, inlen)) {
+ fprintf(stderr, "key passphrase cross mismatch: %s %s/%s\n", description,
+ apr_crypto_driver_name(driver1), apr_crypto_driver_name(
+ driver2));
+ }
+ ABTS_STR_EQUAL(tc, (char *)in, (char *)plainText);
+ }
+
+}
+
+/**
+ * Test initialisation.
+ */
+static void test_crypto_init(abts_case *tc, void *data)
+{
+ apr_pool_t *pool = NULL;
+ apr_status_t rv;
+
+ apr_pool_create(&pool, NULL);
+
+ rv = apr_crypto_init(pool);
+ ABTS_ASSERT(tc, "failed to init apr_crypto", rv == APR_SUCCESS);
+
+ apr_pool_destroy(pool);
+
+}
+
+/**
+ * Simple test of OpenSSL key.
+ */
+static void test_crypto_key_openssl(abts_case *tc, void *data)
+{
+ apr_pool_t *pool = NULL;
+ const apr_crypto_driver_t *driver;
+ apr_crypto_t *f = NULL;
+
+ apr_pool_create(&pool, NULL);
+ driver = get_openssl_driver(tc, pool);
+
+ f = make(tc, pool, driver);
+ keysecret(tc, pool, driver, f, APR_KEY_AES_256, APR_MODE_CBC, 1, 32,
+ "KEY_AES_256/MODE_CBC");
+ apr_pool_destroy(pool);
+
+}
+
+/**
+ * Simple test of NSS key.
+ */
+static void test_crypto_key_nss(abts_case *tc, void *data)
+{
+ apr_pool_t *pool = NULL;
+ const apr_crypto_driver_t *driver;
+ apr_crypto_t *f = NULL;
+
+ apr_pool_create(&pool, NULL);
+ driver = get_nss_driver(tc, pool);
+
+ f = make(tc, pool, driver);
+ keysecret(tc, pool, driver, f, APR_KEY_AES_256, APR_MODE_CBC, 1, 32,
+ "KEY_AES_256/MODE_CBC");
+ apr_pool_destroy(pool);
+
+}
+
+/**
+ * Simple test of CommonCrypto key.
+ */
+static void test_crypto_key_commoncrypto(abts_case *tc, void *data)
+{
+ apr_pool_t *pool = NULL;
+ const apr_crypto_driver_t *driver;
+ apr_crypto_t *f = NULL;
+
+ apr_pool_create(&pool, NULL);
+ driver = get_commoncrypto_driver(tc, pool);
+
+ f = make(tc, pool, driver);
+ keysecret(tc, pool, driver, f, APR_KEY_AES_256, APR_MODE_CBC, 1, 32,
+ "KEY_AES_256/MODE_CBC");
+ apr_pool_destroy(pool);
+
+}
+
+/**
+ * Simple test of OpenSSL block crypt.
+ */
+static void test_crypto_block_openssl(abts_case *tc, void *data)
+{
+ apr_pool_t *pool = NULL;
+ const apr_crypto_driver_t *drivers[] = { NULL, NULL };
+
+ const unsigned char *in = (const unsigned char *) ALIGNED_STRING;
+ apr_size_t inlen = sizeof(ALIGNED_STRING);
+
+ apr_pool_create(&pool, NULL);
+ drivers[0] = get_openssl_driver(tc, pool);
+ drivers[1] = get_openssl_driver(tc, pool);
+ crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_CBC, 0,
+ in, inlen, 24, "KEY_3DES_192/MODE_CBC");
+ crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_ECB, 0,
+ in, inlen, 24, "KEY_3DES_192/MODE_ECB");
+ crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_CBC, 0, in,
+ inlen, 32, "KEY_AES_256/MODE_CBC");
+ crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_ECB, 0, in,
+ inlen, 32, "KEY_AES_256/MODE_ECB");
+ crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_CBC, 0, in,
+ inlen, 24, "KEY_AES_192/MODE_CBC");
+ crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_ECB, 0, in,
+ inlen, 24, "KEY_AES_192/MODE_ECB");
+ crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_CBC, 0, in,
+ inlen, 16, "KEY_AES_128/MODE_CBC");
+ crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_ECB, 0, in,
+ inlen, 16, "KEY_AES_128/MODE_ECB");
+ apr_pool_destroy(pool);
+
+}
+
+/**
+ * Simple test of NSS block crypt.
+ */
+static void test_crypto_block_nss(abts_case *tc, void *data)
+{
+ apr_pool_t *pool = NULL;
+ const apr_crypto_driver_t *drivers[] = { NULL, NULL };
+
+ const unsigned char *in = (const unsigned char *) ALIGNED_STRING;
+ apr_size_t inlen = sizeof(ALIGNED_STRING);
+
+ apr_pool_create(&pool, NULL);
+ drivers[0] = get_nss_driver(tc, pool);
+ drivers[1] = get_nss_driver(tc, pool);
+ crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_CBC, 0,
+ in, inlen, 24, "KEY_3DES_192/MODE_CBC");
+ /* KEY_3DES_192 / MODE_ECB doesn't work on NSS */
+ /* crypto_block_cross(tc, pool, drivers, KEY_3DES_192, MODE_ECB, 0, in, inlen, "KEY_3DES_192/MODE_ECB"); */
+ crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_CBC, 0, in,
+ inlen, 32, "KEY_AES_256/MODE_CBC");
+ crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_ECB, 0, in,
+ inlen, 32, "KEY_AES_256/MODE_ECB");
+ crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_CBC, 0, in,
+ inlen, 24, "KEY_AES_192/MODE_CBC");
+ crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_ECB, 0, in,
+ inlen, 24, "KEY_AES_192/MODE_ECB");
+ crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_CBC, 0, in,
+ inlen, 16, "KEY_AES_128/MODE_CBC");
+ crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_ECB, 0, in,
+ inlen, 16, "KEY_AES_128/MODE_ECB");
+ apr_pool_destroy(pool);
+
+}
+
+/**
+ * Simple test of Common Crypto block crypt.
+ */
+static void test_crypto_block_commoncrypto(abts_case *tc, void *data)
+{
+ apr_pool_t *pool = NULL;
+ const apr_crypto_driver_t *drivers[] = { NULL, NULL };
+
+ const unsigned char *in = (const unsigned char *) ALIGNED_STRING;
+ apr_size_t inlen = sizeof(ALIGNED_STRING);
+
+ apr_pool_create(&pool, NULL);
+ drivers[0] = get_commoncrypto_driver(tc, pool);
+ drivers[1] = get_commoncrypto_driver(tc, pool);
+ crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_CBC, 0,
+ in, inlen, 24, "KEY_3DES_192/MODE_CBC");
+ crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_ECB, 0,
+ in, inlen, 24, "KEY_3DES_192/MODE_ECB");
+ crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_CBC, 0, in,
+ inlen, 32, "KEY_AES_256/MODE_CBC");
+ crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_ECB, 0, in,
+ inlen, 32, "KEY_AES_256/MODE_ECB");
+ crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_CBC, 0, in,
+ inlen, 24, "KEY_AES_192/MODE_CBC");
+ crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_ECB, 0, in,
+ inlen, 24, "KEY_AES_192/MODE_ECB");
+ crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_CBC, 0, in,
+ inlen, 16, "KEY_AES_128/MODE_CBC");
+ crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_ECB, 0, in,
+ inlen, 16, "KEY_AES_128/MODE_ECB");
+ apr_pool_destroy(pool);
+
+}
+
+/**
+ * Encrypt NSS, decrypt OpenSSL.
+ */
+static void test_crypto_block_nss_openssl(abts_case *tc, void *data)
+{
+ apr_pool_t *pool = NULL;
+ const apr_crypto_driver_t *drivers[] = { NULL, NULL };
+
+ const unsigned char *in = (const unsigned char *) ALIGNED_STRING;
+ apr_size_t inlen = sizeof(ALIGNED_STRING);
+
+ apr_pool_create(&pool, NULL);
+ drivers[0] = get_nss_driver(tc, pool);
+ drivers[1] = get_openssl_driver(tc, pool);
+
+ crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_CBC, 0,
+ in, inlen, 24, "KEY_3DES_192/MODE_CBC");
+
+ /* KEY_3DES_192 / MODE_ECB doesn't work on NSS */
+ /* crypto_block_cross(tc, pool, drivers, KEY_3DES_192, MODE_ECB, 0, in, inlen, 24, "KEY_3DES_192/MODE_ECB"); */
+ crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_CBC, 0, in,
+ inlen, 32, "KEY_AES_256/MODE_CBC");
+ crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_ECB, 0, in,
+ inlen, 32, "KEY_AES_256/MODE_ECB");
+ crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_CBC, 0, in,
+ inlen, 24, "KEY_AES_192/MODE_CBC");
+ crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_ECB, 0, in,
+ inlen, 24, "KEY_AES_192/MODE_ECB");
+ crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_CBC, 0, in,
+ inlen, 16, "KEY_AES_128/MODE_CBC");
+ crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_ECB, 0, in,
+ inlen, 16, "KEY_AES_128/MODE_ECB");
+ apr_pool_destroy(pool);
+
+}
+
+/**
+ * Encrypt OpenSSL, decrypt NSS.
+ */
+static void test_crypto_block_openssl_nss(abts_case *tc, void *data)
+{
+ apr_pool_t *pool = NULL;
+ const apr_crypto_driver_t *drivers[] = { NULL, NULL };
+
+ const unsigned char *in = (const unsigned char *) ALIGNED_STRING;
+ apr_size_t inlen = sizeof(ALIGNED_STRING);
+
+ apr_pool_create(&pool, NULL);
+ drivers[0] = get_openssl_driver(tc, pool);
+ drivers[1] = get_nss_driver(tc, pool);
+ crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_CBC, 0,
+ in, inlen, 24, "KEY_3DES_192/MODE_CBC");
+
+ /* KEY_3DES_192 / MODE_ECB doesn't work on NSS */
+ /* crypto_block_cross(tc, pool, drivers, KEY_3DES_192, MODE_ECB, 0, in, inlen, 24, "KEY_3DES_192/MODE_ECB"); */
+
+ crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_CBC, 0, in,
+ inlen, 32, "KEY_AES_256/MODE_CBC");
+ crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_ECB, 0, in,
+ inlen, 32, "KEY_AES_256/MODE_ECB");
+ crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_CBC, 0, in,
+ inlen, 24, "KEY_AES_192/MODE_CBC");
+ crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_ECB, 0, in,
+ inlen, 24, "KEY_AES_192/MODE_ECB");
+ crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_CBC, 0, in,
+ inlen, 16, "KEY_AES_128/MODE_CBC");
+ crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_ECB, 0, in,
+ inlen, 16, "KEY_AES_128/MODE_ECB");
+ apr_pool_destroy(pool);
+
+}
+
+/**
+ * Encrypt OpenSSL, decrypt CommonCrypto.
+ */
+static void test_crypto_block_openssl_commoncrypto(abts_case *tc, void *data)
+{
+ apr_pool_t *pool = NULL;
+ const apr_crypto_driver_t *drivers[] =
+ { NULL, NULL };
+
+ const unsigned char *in = (const unsigned char *) ALIGNED_STRING;
+ apr_size_t inlen = sizeof(ALIGNED_STRING);
+
+ apr_pool_create(&pool, NULL);
+ drivers[0] = get_openssl_driver(tc, pool);
+ drivers[1] = get_commoncrypto_driver(tc, pool);
+
+ crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_CBC, 0, in,
+ inlen, 24, "KEY_3DES_192/MODE_CBC");
+ crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_ECB, 0, in,
+ inlen, 24, "KEY_3DES_192/MODE_ECB");
+ crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_CBC, 0, in,
+ inlen, 32, "KEY_AES_256/MODE_CBC");
+ crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_ECB, 0, in,
+ inlen, 32, "KEY_AES_256/MODE_ECB");
+ crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_CBC, 0, in,
+ inlen, 24, "KEY_AES_192/MODE_CBC");
+ crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_ECB, 0, in,
+ inlen, 24, "KEY_AES_192/MODE_ECB");
+ crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_CBC, 0, in,
+ inlen, 16, "KEY_AES_128/MODE_CBC");
+ crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_ECB, 0, in,
+ inlen, 16, "KEY_AES_128/MODE_ECB");
+ apr_pool_destroy(pool);
+
+}
+
+/**
+ * Encrypt OpenSSL, decrypt CommonCrypto.
+ */
+static void test_crypto_block_commoncrypto_openssl(abts_case *tc, void *data)
+{
+ apr_pool_t *pool = NULL;
+ const apr_crypto_driver_t *drivers[] =
+ { NULL, NULL };
+
+ const unsigned char *in = (const unsigned char *) ALIGNED_STRING;
+ apr_size_t inlen = sizeof(ALIGNED_STRING);
+
+ apr_pool_create(&pool, NULL);
+ drivers[0] = get_commoncrypto_driver(tc, pool);
+ drivers[1] = get_openssl_driver(tc, pool);
+
+ crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_CBC, 0, in,
+ inlen, 24, "KEY_3DES_192/MODE_CBC");
+ crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_ECB, 0, in,
+ inlen, 24, "KEY_3DES_192/MODE_ECB");
+ crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_CBC, 0, in,
+ inlen, 32, "KEY_AES_256/MODE_CBC");
+ crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_ECB, 0, in,
+ inlen, 32, "KEY_AES_256/MODE_ECB");
+ crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_CBC, 0, in,
+ inlen, 24, "KEY_AES_192/MODE_CBC");
+ crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_ECB, 0, in,
+ inlen, 24, "KEY_AES_192/MODE_ECB");
+ crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_CBC, 0, in,
+ inlen, 16, "KEY_AES_128/MODE_CBC");
+ crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_ECB, 0, in,
+ inlen, 16, "KEY_AES_128/MODE_ECB");
+ apr_pool_destroy(pool);
+
+}
+
+/**
+ * Simple test of OpenSSL block crypt.
+ */
+static void test_crypto_block_openssl_pad(abts_case *tc, void *data)
+{
+ apr_pool_t *pool = NULL;
+ const apr_crypto_driver_t *drivers[] = { NULL, NULL };
+
+ const unsigned char *in = (const unsigned char *) TEST_STRING;
+ apr_size_t inlen = sizeof(TEST_STRING);
+
+ apr_pool_create(&pool, NULL);
+ drivers[0] = get_openssl_driver(tc, pool);
+ drivers[1] = get_openssl_driver(tc, pool);
+
+ crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_CBC, 1,
+ in, inlen, 24, "KEY_3DES_192/MODE_CBC");
+ crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_ECB, 1,
+ in, inlen, 24, "KEY_3DES_192/MODE_ECB");
+ crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_CBC, 1, in,
+ inlen, 32, "KEY_AES_256/MODE_CBC");
+ crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_ECB, 1, in,
+ inlen, 32, "KEY_AES_256/MODE_ECB");
+ crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_CBC, 1, in,
+ inlen, 24, "KEY_AES_192/MODE_CBC");
+ crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_ECB, 1, in,
+ inlen, 24, "KEY_AES_192/MODE_ECB");
+ crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_CBC, 1, in,
+ inlen, 16, "KEY_AES_128/MODE_CBC");
+ crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_ECB, 1, in,
+ inlen, 16, "KEY_AES_128/MODE_ECB");
+
+ apr_pool_destroy(pool);
+
+}
+
+/**
+ * Simple test of NSS block crypt.
+ */
+static void test_crypto_block_nss_pad(abts_case *tc, void *data)
+{
+ apr_pool_t *pool = NULL;
+ const apr_crypto_driver_t *drivers[] =
+ { NULL, NULL };
+
+ const unsigned char *in = (const unsigned char *) TEST_STRING;
+ apr_size_t inlen = sizeof(TEST_STRING);
+
+ apr_pool_create(&pool, NULL);
+ drivers[0] = get_nss_driver(tc, pool);
+ drivers[1] = get_nss_driver(tc, pool);
+
+ crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_CBC, 1,
+ in, inlen, 24, "KEY_3DES_192/MODE_CBC");
+ /* KEY_3DES_192 / MODE_ECB doesn't work on NSS */
+ /* crypto_block_cross(tc, pool, drivers, KEY_3DES_192, MODE_ECB, 1, in, inlen, 24, "KEY_3DES_192/MODE_ECB"); */
+
+ crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_CBC, 1, in,
+ inlen, 32, "KEY_AES_256/MODE_CBC");
+
+ /* KEY_AES_256 / MODE_ECB doesn't support padding on NSS */
+ /*crypto_block_cross(tc, pool, drivers, KEY_AES_256, MODE_ECB, 1, in, inlen, 32, "KEY_AES_256/MODE_ECB");*/
+
+ crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_CBC, 1, in,
+ inlen, 24, "KEY_AES_192/MODE_CBC");
+
+ /* KEY_AES_256 / MODE_ECB doesn't support padding on NSS */
+ /*crypto_block_cross(tc, pool, drivers, KEY_AES_192, MODE_ECB, 1, in, inlen, 24, "KEY_AES_192/MODE_ECB");*/
+
+ crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_CBC, 1, in,
+ inlen, 16, "KEY_AES_128/MODE_CBC");
+
+ /* KEY_AES_256 / MODE_ECB doesn't support padding on NSS */
+ /*crypto_block_cross(tc, pool, drivers, KEY_AES_128, MODE_ECB, 1, in, inlen, 16, "KEY_AES_128/MODE_ECB");*/
+
+ apr_pool_destroy(pool);
+
+}
+
+/**
+ * Simple test of Common Crypto block crypt.
+ */
+static void test_crypto_block_commoncrypto_pad(abts_case *tc, void *data)
+{
+ apr_pool_t *pool = NULL;
+ const apr_crypto_driver_t *drivers[] = { NULL, NULL };
+
+ const unsigned char *in = (const unsigned char *) TEST_STRING;
+ apr_size_t inlen = sizeof(TEST_STRING);
+
+ apr_pool_create(&pool, NULL);
+ drivers[0] = get_commoncrypto_driver(tc, pool);
+ drivers[1] = get_commoncrypto_driver(tc, pool);
+
+ crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_CBC, 1,
+ in, inlen, 24, "KEY_3DES_192/MODE_CBC");
+ crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_ECB, 1,
+ in, inlen, 24, "KEY_3DES_192/MODE_ECB");
+ crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_CBC, 1, in,
+ inlen, 32, "KEY_AES_256/MODE_CBC");
+ crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_ECB, 1, in,
+ inlen, 32, "KEY_AES_256/MODE_ECB");
+ crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_CBC, 1, in,
+ inlen, 24, "KEY_AES_192/MODE_CBC");
+ crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_ECB, 1, in,
+ inlen, 24, "KEY_AES_192/MODE_ECB");
+ crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_CBC, 1, in,
+ inlen, 16, "KEY_AES_128/MODE_CBC");
+ crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_ECB, 1, in,
+ inlen, 16, "KEY_AES_128/MODE_ECB");
+
+ apr_pool_destroy(pool);
+
+}
+
+/**
+ * Encrypt NSS, decrypt OpenSSL.
+ */
+static void test_crypto_block_nss_openssl_pad(abts_case *tc, void *data)
+{
+ apr_pool_t *pool = NULL;
+ const apr_crypto_driver_t *drivers[] = { NULL, NULL };
+
+ const unsigned char *in = (const unsigned char *) TEST_STRING;
+ apr_size_t inlen = sizeof(TEST_STRING);
+
+ apr_pool_create(&pool, NULL);
+ drivers[0] = get_nss_driver(tc, pool);
+ drivers[1] = get_openssl_driver(tc, pool);
+
+ crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_CBC, 1,
+ in, inlen, 24, "KEY_3DES_192/MODE_CBC");
+
+ /* KEY_3DES_192 / MODE_ECB doesn't work on NSS */
+ /* crypto_block_cross(tc, pool, drivers, KEY_3DES_192, MODE_ECB, 1, in, inlen, 24, "KEY_3DES_192/MODE_ECB"); */
+
+ crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_CBC, 1, in,
+ inlen, 32, "KEY_AES_256/MODE_CBC");
+
+ /* KEY_AES_256 / MODE_ECB doesn't support padding on NSS */
+ /*crypto_block_cross(tc, pool, drivers, KEY_AES_256, MODE_ECB, 1, in, inlen, 32, "KEY_AES_256/MODE_ECB");*/
+
+ crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_CBC, 1, in,
+ inlen, 24, "KEY_AES_192/MODE_CBC");
+
+ /* KEY_AES_192 / MODE_ECB doesn't support padding on NSS */
+ /*crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_ECB, 1, in,
+ inlen, 24, "KEY_AES_192/MODE_ECB");*/
+
+ crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_CBC, 1, in,
+ inlen, 16, "KEY_AES_128/MODE_CBC");
+
+ /* KEY_AES_192 / MODE_ECB doesn't support padding on NSS */
+ /*crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_ECB, 1, in,
+ inlen, 16, "KEY_AES_128/MODE_ECB");*/
+
+ apr_pool_destroy(pool);
+
+}
+
+/**
+ * Encrypt OpenSSL, decrypt NSS.
+ */
+static void test_crypto_block_openssl_nss_pad(abts_case *tc, void *data)
+{
+ apr_pool_t *pool = NULL;
+ const apr_crypto_driver_t *drivers[] = { NULL, NULL };
+
+ const unsigned char *in = (const unsigned char *) TEST_STRING;
+ apr_size_t inlen = sizeof(TEST_STRING);
+
+ apr_pool_create(&pool, NULL);
+ drivers[0] = get_openssl_driver(tc, pool);
+ drivers[1] = get_nss_driver(tc, pool);
+ crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_CBC, 1,
+ in, inlen, 24, "KEY_3DES_192/MODE_CBC");
+
+ /* KEY_3DES_192 / MODE_ECB doesn't work on NSS */
+ /* crypto_block_cross(tc, pool, drivers, KEY_3DES_192, MODE_ECB, 1, in, inlen, 24, "KEY_3DES_192/MODE_ECB"); */
+
+ crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_CBC, 1, in,
+ inlen, 32, "KEY_AES_256/MODE_CBC");
+
+ /* KEY_AES_256 / MODE_ECB doesn't support padding on NSS */
+ /*crypto_block_cross(tc, pool, drivers, KEY_AES_256, MODE_ECB, 1, in, inlen, 32, "KEY_AES_256/MODE_ECB");*/
+
+ crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_CBC, 1, in, inlen,
+ 24, "KEY_AES_192/MODE_CBC");
+
+ /* KEY_AES_192 / MODE_ECB doesn't support padding on NSS */
+ /*crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_ECB, 1, in, inlen,
+ 24, "KEY_AES_192/MODE_ECB");*/
+
+ crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_CBC, 1, in, inlen,
+ 16, "KEY_AES_128/MODE_CBC");
+
+ /* KEY_AES_128 / MODE_ECB doesn't support padding on NSS */
+ /*crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_ECB, 1, in, inlen,
+ 16, "KEY_AES_128/MODE_ECB");*/
+
+ apr_pool_destroy(pool);
+
+}
+
+/**
+ * Encrypt CommonCrypto, decrypt OpenSSL.
+ */
+static void test_crypto_block_commoncrypto_openssl_pad(abts_case *tc,
+ void *data)
+{
+ apr_pool_t *pool = NULL;
+ const apr_crypto_driver_t *drivers[] =
+ { NULL, NULL };
+
+ const unsigned char *in = (const unsigned char *) TEST_STRING;
+ apr_size_t inlen = sizeof(TEST_STRING);
+
+ apr_pool_create(&pool, NULL);
+ drivers[0] = get_commoncrypto_driver(tc, pool);
+ drivers[1] = get_openssl_driver(tc, pool);
+
+ crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_CBC, 1, in,
+ inlen, 24, "KEY_3DES_192/MODE_CBC");
+ crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_ECB, 1, in,
+ inlen, 24, "KEY_3DES_192/MODE_ECB");
+ crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_CBC, 1, in,
+ inlen, 32, "KEY_AES_256/MODE_CBC");
+ crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_ECB, 1, in,
+ inlen, 32, "KEY_AES_256/MODE_ECB");
+ crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_CBC, 1, in,
+ inlen, 24, "KEY_AES_192/MODE_CBC");
+ crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_ECB, 1, in,
+ inlen, 24, "KEY_AES_192/MODE_ECB");
+ crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_CBC, 1, in,
+ inlen, 16, "KEY_AES_128/MODE_CBC");
+ crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_ECB, 1, in,
+ inlen, 16, "KEY_AES_128/MODE_ECB");
+
+ apr_pool_destroy(pool);
+
+}
+
+/**
+ * Encrypt OpenSSL, decrypt CommonCrypto.
+ */
+static void test_crypto_block_openssl_commoncrypto_pad(abts_case *tc,
+ void *data)
+{
+ apr_pool_t *pool = NULL;
+ const apr_crypto_driver_t *drivers[] =
+ { NULL, NULL };
+
+ const unsigned char *in = (const unsigned char *) TEST_STRING;
+ apr_size_t inlen = sizeof(TEST_STRING);
+
+ apr_pool_create(&pool, NULL);
+ drivers[0] = get_openssl_driver(tc, pool);
+ drivers[1] = get_commoncrypto_driver(tc, pool);
+
+ crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_CBC, 1, in,
+ inlen, 24, "KEY_3DES_192/MODE_CBC");
+ crypto_block_cross(tc, pool, drivers, APR_KEY_3DES_192, APR_MODE_ECB, 1, in,
+ inlen, 24, "KEY_3DES_192/MODE_ECB");
+ crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_CBC, 1, in,
+ inlen, 32, "KEY_AES_256/MODE_CBC");
+ crypto_block_cross(tc, pool, drivers, APR_KEY_AES_256, APR_MODE_ECB, 1, in,
+ inlen, 32, "KEY_AES_256/MODE_ECB");
+ crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_CBC, 1, in,
+ inlen, 24, "KEY_AES_192/MODE_CBC");
+ crypto_block_cross(tc, pool, drivers, APR_KEY_AES_192, APR_MODE_ECB, 1, in,
+ inlen, 24, "KEY_AES_192/MODE_ECB");
+ crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_CBC, 1, in,
+ inlen, 16, "KEY_AES_128/MODE_CBC");
+ crypto_block_cross(tc, pool, drivers, APR_KEY_AES_128, APR_MODE_ECB, 1, in,
+ inlen, 16, "KEY_AES_128/MODE_ECB");
+
+ apr_pool_destroy(pool);
+
+}
+
+/**
+ * Get Types, OpenSSL.
+ */
+static void test_crypto_get_block_key_types_openssl(abts_case *tc, void *data)
+{
+ apr_pool_t *pool = NULL;
+ const apr_crypto_driver_t *driver;
+ apr_crypto_t *f;
+ apr_hash_t *types;
+ int *key_3des_192;
+ int *key_aes_128;
+ int *key_aes_192;
+ int *key_aes_256;
+
+ apr_pool_create(&pool, NULL);
+ driver = get_openssl_driver(tc, pool);
+ if (driver) {
+
+ f = make(tc, pool, driver);
+ apr_crypto_get_block_key_types(&types, f);
+
+ key_3des_192 = apr_hash_get(types, "3des192", APR_HASH_KEY_STRING);
+ ABTS_PTR_NOTNULL(tc, key_3des_192);
+ ABTS_INT_EQUAL(tc, *key_3des_192, APR_KEY_3DES_192);
+
+ key_aes_128 = apr_hash_get(types, "aes128", APR_HASH_KEY_STRING);
+ ABTS_PTR_NOTNULL(tc, key_aes_128);
+ ABTS_INT_EQUAL(tc, *key_aes_128, APR_KEY_AES_128);
+
+ key_aes_192 = apr_hash_get(types, "aes192", APR_HASH_KEY_STRING);
+ ABTS_PTR_NOTNULL(tc, key_aes_192);
+ ABTS_INT_EQUAL(tc, *key_aes_192, APR_KEY_AES_192);
+
+ key_aes_256 = apr_hash_get(types, "aes256", APR_HASH_KEY_STRING);
+ ABTS_PTR_NOTNULL(tc, key_aes_256);
+ ABTS_INT_EQUAL(tc, *key_aes_256, APR_KEY_AES_256);
+
+ }
+
+ apr_pool_destroy(pool);
+
+}
+
+/**
+ * Get Types, NSS.
+ */
+static void test_crypto_get_block_key_types_nss(abts_case *tc, void *data)
+{
+ apr_pool_t *pool = NULL;
+ const apr_crypto_driver_t *driver;
+ apr_crypto_t *f;
+ apr_hash_t *types;
+ int *key_3des_192;
+ int *key_aes_128;
+ int *key_aes_192;
+ int *key_aes_256;
+
+ apr_pool_create(&pool, NULL);
+ driver = get_nss_driver(tc, pool);
+ if (driver) {
+
+ f = make(tc, pool, driver);
+ apr_crypto_get_block_key_types(&types, f);
+
+ key_3des_192 = apr_hash_get(types, "3des192", APR_HASH_KEY_STRING);
+ ABTS_PTR_NOTNULL(tc, key_3des_192);
+ ABTS_INT_EQUAL(tc, *key_3des_192, APR_KEY_3DES_192);
+
+ key_aes_128 = apr_hash_get(types, "aes128", APR_HASH_KEY_STRING);
+ ABTS_PTR_NOTNULL(tc, key_aes_128);
+ ABTS_INT_EQUAL(tc, *key_aes_128, APR_KEY_AES_128);
+
+ key_aes_192 = apr_hash_get(types, "aes192", APR_HASH_KEY_STRING);
+ ABTS_PTR_NOTNULL(tc, key_aes_192);
+ ABTS_INT_EQUAL(tc, *key_aes_192, APR_KEY_AES_192);
+
+ key_aes_256 = apr_hash_get(types, "aes256", APR_HASH_KEY_STRING);
+ ABTS_PTR_NOTNULL(tc, key_aes_256);
+ ABTS_INT_EQUAL(tc, *key_aes_256, APR_KEY_AES_256);
+
+ }
+
+ apr_pool_destroy(pool);
+
+}
+
+/**
+ * Get Types, Common Crypto.
+ */
+static void test_crypto_get_block_key_types_commoncrypto(abts_case *tc, void *data)
+{
+ apr_pool_t *pool = NULL;
+ const apr_crypto_driver_t *driver;
+ apr_crypto_t *f;
+ apr_hash_t *types;
+ int *key_3des_192;
+ int *key_aes_128;
+ int *key_aes_192;
+ int *key_aes_256;
+
+ apr_pool_create(&pool, NULL);
+ driver = get_commoncrypto_driver(tc, pool);
+ if (driver) {
+
+ f = make(tc, pool, driver);
+ apr_crypto_get_block_key_types(&types, f);
+
+ key_3des_192 = apr_hash_get(types, "3des192", APR_HASH_KEY_STRING);
+ ABTS_PTR_NOTNULL(tc, key_3des_192);
+ ABTS_INT_EQUAL(tc, *key_3des_192, APR_KEY_3DES_192);
+
+ key_aes_128 = apr_hash_get(types, "aes128", APR_HASH_KEY_STRING);
+ ABTS_PTR_NOTNULL(tc, key_aes_128);
+ ABTS_INT_EQUAL(tc, *key_aes_128, APR_KEY_AES_128);
+
+ key_aes_192 = apr_hash_get(types, "aes192", APR_HASH_KEY_STRING);
+ ABTS_PTR_NOTNULL(tc, key_aes_192);
+ ABTS_INT_EQUAL(tc, *key_aes_192, APR_KEY_AES_192);
+
+ key_aes_256 = apr_hash_get(types, "aes256", APR_HASH_KEY_STRING);
+ ABTS_PTR_NOTNULL(tc, key_aes_256);
+ ABTS_INT_EQUAL(tc, *key_aes_256, APR_KEY_AES_256);
+
+ }
+
+ apr_pool_destroy(pool);
+
+}
+
+/**
+ * Get Modes, OpenSSL.
+ */
+static void test_crypto_get_block_key_modes_openssl(abts_case *tc, void *data)
+{
+ apr_pool_t *pool = NULL;
+ const apr_crypto_driver_t *driver;
+ apr_crypto_t *f;
+ apr_hash_t *modes;
+ int *mode_ecb;
+ int *mode_cbc;
+
+ apr_pool_create(&pool, NULL);
+ driver = get_openssl_driver(tc, pool);
+ if (driver) {
+
+ f = make(tc, pool, driver);
+ apr_crypto_get_block_key_modes(&modes, f);
+
+ mode_ecb = apr_hash_get(modes, "ecb", APR_HASH_KEY_STRING);
+ ABTS_PTR_NOTNULL(tc, mode_ecb);
+ ABTS_INT_EQUAL(tc, *mode_ecb, APR_MODE_ECB);
+
+ mode_cbc = apr_hash_get(modes, "cbc", APR_HASH_KEY_STRING);
+ ABTS_PTR_NOTNULL(tc, mode_cbc);
+ ABTS_INT_EQUAL(tc, *mode_cbc, APR_MODE_CBC);
+
+ }
+
+ apr_pool_destroy(pool);
+
+}
+
+/**
+ * Get Modes, NSS.
+ */
+static void test_crypto_get_block_key_modes_nss(abts_case *tc, void *data)
+{
+ apr_pool_t *pool = NULL;
+ const apr_crypto_driver_t *driver;
+ apr_crypto_t *f;
+ apr_hash_t *modes;
+ int *mode_ecb;
+ int *mode_cbc;
+
+ apr_pool_create(&pool, NULL);
+ driver = get_nss_driver(tc, pool);
+ if (driver) {
+
+ f = make(tc, pool, driver);
+ apr_crypto_get_block_key_modes(&modes, f);
+
+ mode_ecb = apr_hash_get(modes, "ecb", APR_HASH_KEY_STRING);
+ ABTS_PTR_NOTNULL(tc, mode_ecb);
+ ABTS_INT_EQUAL(tc, *mode_ecb, APR_MODE_ECB);
+
+ mode_cbc = apr_hash_get(modes, "cbc", APR_HASH_KEY_STRING);
+ ABTS_PTR_NOTNULL(tc, mode_cbc);
+ ABTS_INT_EQUAL(tc, *mode_cbc, APR_MODE_CBC);
+
+ }
+
+ apr_pool_destroy(pool);
+
+}
+
+/**
+ * Get Modes, Common Crypto.
+ */
+static void test_crypto_get_block_key_modes_commoncrypto(abts_case *tc, void *data)
+{
+ apr_pool_t *pool = NULL;
+ const apr_crypto_driver_t *driver;
+ apr_crypto_t *f;
+ apr_hash_t *modes;
+ int *mode_ecb;
+ int *mode_cbc;
+
+ apr_pool_create(&pool, NULL);
+ driver = get_commoncrypto_driver(tc, pool);
+ if (driver) {
+
+ f = make(tc, pool, driver);
+ apr_crypto_get_block_key_modes(&modes, f);
+
+ mode_ecb = apr_hash_get(modes, "ecb", APR_HASH_KEY_STRING);
+ ABTS_PTR_NOTNULL(tc, mode_ecb);
+ ABTS_INT_EQUAL(tc, *mode_ecb, APR_MODE_ECB);
+
+ mode_cbc = apr_hash_get(modes, "cbc", APR_HASH_KEY_STRING);
+ ABTS_PTR_NOTNULL(tc, mode_cbc);
+ ABTS_INT_EQUAL(tc, *mode_cbc, APR_MODE_CBC);
+
+ }
+
+ apr_pool_destroy(pool);
+
+}
+
+static void test_crypto_memzero(abts_case *tc, void *data)
+{
+ /* Aligned message */
+ struct {
+ char buf[7 * sizeof(int)];
+ int untouched;
+ } msg;
+ /* A bit of type punning such that 'msg' might look unused
+ * after the call to apr_crypto_memzero().
+ */
+ int *ptr = (int *)&msg;
+ int i;
+
+ /* Fill buf with non-zeros (odds) */
+ for (i = 1; i < 2 * sizeof(msg.buf); i += 2) {
+ msg.buf[i / 2] = (char)i;
+ ABTS_ASSERT(tc, "test_crypto_memzero() barrier", msg.buf[i / 2] != 0);
+ }
+
+ /* Zero out the whole, and check it */
+ apr_crypto_memzero(&msg, sizeof msg);
+ for (i = 0; i < sizeof(msg) / sizeof(*ptr); ++i) {
+ ABTS_ASSERT(tc, "test_crypto_memzero() optimized out", ptr[i] == 0);
+ }
+}
+
+static void test_crypto_equals(abts_case *tc, void *data)
+{
+ /* Buffers of each type of scalar */
+ union {
+ char c;
+ short s;
+ int i;
+ long l;
+ float f;
+ double d;
+ void *p;
+ } buf0[7], buf1[7], buf[7];
+ char *ptr = (char *)buf;
+ int i;
+
+#define TEST_SCALAR_MATCH(i, x, r) \
+ ABTS_ASSERT(tc, "test_crypto_equals(" APR_STRINGIFY(x) ")" \
+ " != " APR_STRINGIFY(r), \
+ apr_crypto_equals(&buf##r[i].x, &buf[i].x, \
+ sizeof(buf[i].x)) == r)
+
+ /* Fill buf with non-zeros (odds) */
+ for (i = 1; i < 2 * sizeof(buf); i += 2) {
+ ptr[i / 2] = (char)i;
+ }
+ /* Set buf1 = buf */
+ memcpy(buf1, buf, sizeof buf);
+ /* Set buf0 = {0} */
+ memset(buf0, 0, sizeof buf0);
+
+ /* Check that buf1 == buf for each scalar */
+ TEST_SCALAR_MATCH(0, c, 1);
+ TEST_SCALAR_MATCH(1, s, 1);
+ TEST_SCALAR_MATCH(2, i, 1);
+ TEST_SCALAR_MATCH(3, l, 1);
+ TEST_SCALAR_MATCH(4, f, 1);
+ TEST_SCALAR_MATCH(5, d, 1);
+ TEST_SCALAR_MATCH(6, p, 1);
+
+ /* Check that buf0 != buf for each scalar */
+ TEST_SCALAR_MATCH(0, c, 0);
+ TEST_SCALAR_MATCH(1, s, 0);
+ TEST_SCALAR_MATCH(2, i, 0);
+ TEST_SCALAR_MATCH(3, l, 0);
+ TEST_SCALAR_MATCH(4, f, 0);
+ TEST_SCALAR_MATCH(5, d, 0);
+ TEST_SCALAR_MATCH(6, p, 0);
+}
+
+abts_suite *testcrypto(abts_suite *suite)
+{
+ suite = ADD_SUITE(suite);
+
+ /* test simple init and shutdown */
+ abts_run_test(suite, test_crypto_init, NULL);
+
+ /* test key parsing - openssl */
+ abts_run_test(suite, test_crypto_key_openssl, NULL);
+
+ /* test key parsing - nss */
+ abts_run_test(suite, test_crypto_key_nss, NULL);
+
+ /* test key parsing - commoncrypto */
+ abts_run_test(suite, test_crypto_key_commoncrypto, NULL);
+
+ /* test a simple encrypt / decrypt operation - openssl */
+ abts_run_test(suite, test_crypto_block_openssl, NULL);
+
+ /* test a padded encrypt / decrypt operation - openssl */
+ abts_run_test(suite, test_crypto_block_openssl_pad, NULL);
+
+ /* test a simple encrypt / decrypt operation - nss */
+ abts_run_test(suite, test_crypto_block_nss, NULL);
+
+ /* test a padded encrypt / decrypt operation - nss */
+ abts_run_test(suite, test_crypto_block_nss_pad, NULL);
+
+ /* test a simple encrypt / decrypt operation - commoncrypto */
+ abts_run_test(suite, test_crypto_block_commoncrypto, NULL);
+
+ /* test a padded encrypt / decrypt operation - commoncrypto */
+ abts_run_test(suite, test_crypto_block_commoncrypto_pad, NULL);
+
+ /* test encrypt nss / decrypt openssl */
+ abts_run_test(suite, test_crypto_block_nss_openssl, NULL);
+
+ /* test padded encrypt nss / decrypt openssl */
+ abts_run_test(suite, test_crypto_block_nss_openssl_pad, NULL);
+
+ /* test encrypt openssl / decrypt nss */
+ abts_run_test(suite, test_crypto_block_openssl_nss, NULL);
+
+ /* test padded encrypt openssl / decrypt nss */
+ abts_run_test(suite, test_crypto_block_openssl_nss_pad, NULL);
+
+ /* test encrypt openssl / decrypt commoncrypto */
+ abts_run_test(suite, test_crypto_block_openssl_commoncrypto, NULL);
+
+ /* test padded encrypt openssl / decrypt commoncrypto */
+ abts_run_test(suite, test_crypto_block_openssl_commoncrypto_pad, NULL);
+
+ /* test encrypt commoncrypto / decrypt openssl */
+ abts_run_test(suite, test_crypto_block_commoncrypto_openssl, NULL);
+
+ /* test padded encrypt commoncrypto / decrypt openssl */
+ abts_run_test(suite, test_crypto_block_commoncrypto_openssl_pad, NULL);
+
+ /* test block key types openssl */
+ abts_run_test(suite, test_crypto_get_block_key_types_openssl, NULL);
+
+ /* test block key types nss */
+ abts_run_test(suite, test_crypto_get_block_key_types_nss, NULL);
+
+ /* test block key types commoncrypto */
+ abts_run_test(suite, test_crypto_get_block_key_types_commoncrypto, NULL);
+
+ /* test block key modes openssl */
+ abts_run_test(suite, test_crypto_get_block_key_modes_openssl, NULL);
+
+ /* test block key modes nss */
+ abts_run_test(suite, test_crypto_get_block_key_modes_nss, NULL);
+
+ /* test block key modes commoncrypto */
+ abts_run_test(suite, test_crypto_get_block_key_modes_commoncrypto, NULL);
+
+ abts_run_test(suite, test_crypto_memzero, NULL);
+ abts_run_test(suite, test_crypto_equals, NULL);
+
+ return suite;
+}
+
+#else
+
+/**
+ * Dummy test suite when crypto is turned off.
+ */
+abts_suite *testcrypto(abts_suite *suite)
+{
+ return ADD_SUITE(suite);
+}
+
+#endif /* APU_HAVE_CRYPTO */
diff --git a/test/testdate.c b/test/testdate.c
new file mode 100644
index 0000000..b4e2edf
--- /dev/null
+++ b/test/testdate.c
@@ -0,0 +1,202 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "abts.h"
+#include "testutil.h"
+#include "apr_date.h"
+#include "apr_general.h"
+
+#if APR_HAVE_TIME_H
+#include <time.h>
+#endif /* APR_HAVE_TIME_H */
+
+static struct datetest {
+ const char *input;
+ const char *output;
+} tests[] = {
+ { "Mon, 27 Feb 1995 20:49:44 -0800", "Tue, 28 Feb 1995 04:49:44 GMT" },
+ { "Fri, 1 Jul 2005 11:34:25 -0400", "Fri, 01 Jul 2005 15:34:25 GMT" },
+ { "Monday, 27-Feb-95 20:49:44 -0800", "Tue, 28 Feb 1995 04:49:44 GMT" },
+ { "Tue, 4 Mar 1997 12:43:52 +0200", "Tue, 04 Mar 1997 10:43:52 GMT" },
+ { "Mon, 27 Feb 95 20:49:44 -0800", "Tue, 28 Feb 1995 04:49:44 GMT" },
+ { "Tue, 4 Mar 97 12:43:52 +0200", "Tue, 04 Mar 1997 10:43:52 GMT" },
+ { "Tue, 4 Mar 97 12:43:52 +0200", "Tue, 04 Mar 1997 10:43:52 GMT" },
+ { "Mon, 27 Feb 95 20:49 GMT", "Mon, 27 Feb 1995 20:49:00 GMT" },
+ { "Tue, 4 Mar 97 12:43 GMT", "Tue, 04 Mar 1997 12:43:00 GMT" },
+ { NULL, NULL }
+};
+
+static const apr_time_t year2secs[] = {
+ APR_INT64_C(0), /* 1970 */
+ APR_INT64_C(31536000), /* 1971 */
+ APR_INT64_C(63072000), /* 1972 */
+ APR_INT64_C(94694400), /* 1973 */
+ APR_INT64_C(126230400), /* 1974 */
+ APR_INT64_C(157766400), /* 1975 */
+ APR_INT64_C(189302400), /* 1976 */
+ APR_INT64_C(220924800), /* 1977 */
+ APR_INT64_C(252460800), /* 1978 */
+ APR_INT64_C(283996800), /* 1979 */
+ APR_INT64_C(315532800), /* 1980 */
+ APR_INT64_C(347155200), /* 1981 */
+ APR_INT64_C(378691200), /* 1982 */
+ APR_INT64_C(410227200), /* 1983 */
+ APR_INT64_C(441763200), /* 1984 */
+ APR_INT64_C(473385600), /* 1985 */
+ APR_INT64_C(504921600), /* 1986 */
+ APR_INT64_C(536457600), /* 1987 */
+ APR_INT64_C(567993600), /* 1988 */
+ APR_INT64_C(599616000), /* 1989 */
+ APR_INT64_C(631152000), /* 1990 */
+ APR_INT64_C(662688000), /* 1991 */
+ APR_INT64_C(694224000), /* 1992 */
+ APR_INT64_C(725846400), /* 1993 */
+ APR_INT64_C(757382400), /* 1994 */
+ APR_INT64_C(788918400), /* 1995 */
+ APR_INT64_C(820454400), /* 1996 */
+ APR_INT64_C(852076800), /* 1997 */
+ APR_INT64_C(883612800), /* 1998 */
+ APR_INT64_C(915148800), /* 1999 */
+ APR_INT64_C(946684800), /* 2000 */
+ APR_INT64_C(978307200), /* 2001 */
+ APR_INT64_C(1009843200), /* 2002 */
+ APR_INT64_C(1041379200), /* 2003 */
+ APR_INT64_C(1072915200), /* 2004 */
+ APR_INT64_C(1104537600), /* 2005 */
+ APR_INT64_C(1136073600), /* 2006 */
+ APR_INT64_C(1167609600), /* 2007 */
+ APR_INT64_C(1199145600), /* 2008 */
+ APR_INT64_C(1230768000), /* 2009 */
+ APR_INT64_C(1262304000), /* 2010 */
+ APR_INT64_C(1293840000), /* 2011 */
+ APR_INT64_C(1325376000), /* 2012 */
+ APR_INT64_C(1356998400), /* 2013 */
+ APR_INT64_C(1388534400), /* 2014 */
+ APR_INT64_C(1420070400), /* 2015 */
+ APR_INT64_C(1451606400), /* 2016 */
+ APR_INT64_C(1483228800), /* 2017 */
+ APR_INT64_C(1514764800), /* 2018 */
+ APR_INT64_C(1546300800), /* 2019 */
+ APR_INT64_C(1577836800), /* 2020 */
+ APR_INT64_C(1609459200), /* 2021 */
+ APR_INT64_C(1640995200), /* 2022 */
+ APR_INT64_C(1672531200), /* 2023 */
+ APR_INT64_C(1704067200), /* 2024 */
+ APR_INT64_C(1735689600), /* 2025 */
+ APR_INT64_C(1767225600), /* 2026 */
+ APR_INT64_C(1798761600), /* 2027 */
+ APR_INT64_C(1830297600), /* 2028 */
+ APR_INT64_C(1861920000), /* 2029 */
+ APR_INT64_C(1893456000), /* 2030 */
+ APR_INT64_C(1924992000), /* 2031 */
+ APR_INT64_C(1956528000), /* 2032 */
+ APR_INT64_C(1988150400), /* 2033 */
+ APR_INT64_C(2019686400), /* 2034 */
+ APR_INT64_C(2051222400), /* 2035 */
+ APR_INT64_C(2082758400), /* 2036 */
+ APR_INT64_C(2114380800), /* 2037 */
+ APR_INT64_C(2145916800) /* 2038 */
+};
+
+const char month_snames[12][4] = {
+ "Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"
+};
+
+/* XXX: non-portable */
+static void gm_timestr_822(char *ts, apr_time_t sec)
+{
+ static const char *const days[7]=
+ {"Sun","Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
+ struct tm *tms;
+ time_t ls = (time_t)sec;
+
+ tms = gmtime(&ls);
+
+ sprintf(ts, "%s, %.2d %s %d %.2d:%.2d:%.2d GMT", days[tms->tm_wday],
+ tms->tm_mday, month_snames[tms->tm_mon], tms->tm_year + 1900,
+ tms->tm_hour, tms->tm_min, tms->tm_sec);
+}
+
+/* Linear congruential generator */
+static apr_uint32_t lgc(apr_uint32_t a)
+{
+ apr_uint64_t z = a;
+ z *= 279470273;
+ z %= APR_UINT64_C(4294967291);
+ return (apr_uint32_t)z;
+}
+
+static void test_date_parse_http(abts_case *tc, void *data)
+{
+ int year, i;
+ apr_time_t guess;
+ apr_time_t offset = 0;
+ apr_time_t secstodate, newsecs;
+ char datestr[50];
+
+ for (year = 1970; year < 2038; ++year) {
+ secstodate = year2secs[year - 1970] + offset;
+ gm_timestr_822(datestr, secstodate);
+ secstodate *= APR_USEC_PER_SEC;
+ newsecs = apr_date_parse_http(datestr);
+ ABTS_TRUE(tc, secstodate == newsecs);
+ }
+
+#if APR_HAS_RANDOM
+ apr_generate_random_bytes((unsigned char *)&guess, sizeof(guess));
+#else
+ guess = apr_time_now() % APR_TIME_C(4294967291);
+#endif
+
+ for (i = 0; i < 10000; ++i) {
+ guess = (time_t)lgc((apr_uint32_t)guess);
+ if (guess < 0)
+ guess *= -1;
+ secstodate = guess + offset;
+ gm_timestr_822(datestr, secstodate);
+ secstodate *= APR_USEC_PER_SEC;
+ newsecs = apr_date_parse_http(datestr);
+ ABTS_TRUE(tc, secstodate == newsecs);
+ }
+}
+
+static void test_date_rfc(abts_case *tc, void *data)
+{
+ apr_time_t date;
+ int i = 0;
+
+ while (tests[i].input) {
+ char str_date[APR_RFC822_DATE_LEN] = { 0 };
+
+ date = apr_date_parse_rfc(tests[i].input);
+
+ apr_rfc822_date(str_date, date);
+
+ ABTS_STR_EQUAL(tc, str_date, tests[i].output);
+
+ i++;
+ }
+}
+
+abts_suite *testdate(abts_suite *suite)
+{
+ suite = ADD_SUITE(suite);
+
+ abts_run_test(suite, test_date_parse_http, NULL);
+ abts_run_test(suite, test_date_rfc, NULL);
+
+ return suite;
+}
diff --git a/test/testdbd.c b/test/testdbd.c
new file mode 100644
index 0000000..6f0698a
--- /dev/null
+++ b/test/testdbd.c
@@ -0,0 +1,245 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "testutil.h"
+#include "apr.h"
+#include "apu.h"
+#include "apr_pools.h"
+#include "apr_dbd.h"
+#include "apr_strings.h"
+
+static void test_dbd_init(abts_case *tc, void *data)
+{
+ apr_pool_t *pool = p;
+ apr_status_t rv;
+
+ rv = apr_dbd_init(pool);
+ ABTS_ASSERT(tc, "failed to init apr_dbd", rv == APR_SUCCESS);
+}
+
+#if APU_HAVE_SQLITE2 || APU_HAVE_SQLITE3
+static void test_statement(abts_case *tc, apr_dbd_t* handle,
+ const apr_dbd_driver_t* driver, const char* sql)
+{
+ int nrows;
+ apr_status_t rv;
+
+ rv = apr_dbd_query(driver, handle, &nrows, sql);
+
+ ABTS_ASSERT(tc, sql, rv == APR_SUCCESS);
+}
+
+static void create_table(abts_case *tc, apr_dbd_t* handle,
+ const apr_dbd_driver_t* driver)
+{
+ const char *sql = "CREATE TABLE apr_dbd_test ("
+ "col1 varchar(40) not null,"
+ "col2 varchar(40),"
+ "col3 integer)";
+
+ test_statement(tc, handle, driver, sql);
+}
+
+static void drop_table(abts_case *tc, apr_dbd_t* handle,
+ const apr_dbd_driver_t* driver)
+{
+ const char *sql = "DROP TABLE apr_dbd_test";
+ test_statement(tc, handle, driver, sql);
+}
+
+static void delete_rows(abts_case *tc, apr_dbd_t* handle,
+ const apr_dbd_driver_t* driver)
+{
+ const char *sql = "DELETE FROM apr_dbd_test";
+ test_statement(tc, handle, driver, sql);
+}
+
+
+static void insert_data(abts_case *tc, apr_dbd_t* handle,
+ const apr_dbd_driver_t* driver, int count)
+{
+ apr_pool_t* pool = p;
+ const char* sql = "INSERT INTO apr_dbd_test VALUES('%d', '%d', %d)";
+ char* sqf = NULL;
+ int i;
+ int nrows;
+ apr_status_t rv;
+
+ for (i=0; i<count; i++) {
+ sqf = apr_psprintf(pool, sql, i, i, i);
+ rv = apr_dbd_query(driver, handle, &nrows, sqf);
+ ABTS_ASSERT(tc, sqf, rv == APR_SUCCESS);
+ ABTS_ASSERT(tc, sqf, 1 == nrows);
+ }
+}
+
+static void select_rows(abts_case *tc, apr_dbd_t* handle,
+ const apr_dbd_driver_t* driver, int count)
+{
+ apr_status_t rv;
+ apr_pool_t* pool = p;
+ apr_pool_t* tpool;
+ const char* sql = "SELECT * FROM apr_dbd_test ORDER BY col1";
+ apr_dbd_results_t *res = NULL;
+ apr_dbd_row_t *row = NULL;
+ int i;
+
+ rv = apr_dbd_select(driver, pool, handle, &res, sql, 0);
+ ABTS_ASSERT(tc, sql, rv == APR_SUCCESS);
+ ABTS_PTR_NOTNULL(tc, res);
+
+ apr_pool_create(&tpool, pool);
+ i = count;
+ while (i > 0) {
+ row = NULL;
+ rv = apr_dbd_get_row(driver, pool, res, &row, -1);
+ ABTS_ASSERT(tc, sql, rv == APR_SUCCESS);
+ ABTS_PTR_NOTNULL(tc, row);
+ apr_pool_clear(tpool);
+ i--;
+ }
+ ABTS_ASSERT(tc, "Missing Rows!", i == 0);
+
+ res = NULL;
+ i = count;
+
+ rv = apr_dbd_select(driver, pool, handle, &res, sql, 1);
+ ABTS_ASSERT(tc, sql, rv == APR_SUCCESS);
+ ABTS_PTR_NOTNULL(tc, res);
+
+ rv = apr_dbd_num_tuples(driver, res);
+ ABTS_ASSERT(tc, "invalid row count", rv == count);
+
+ while (i > 0) {
+ row = NULL;
+ rv = apr_dbd_get_row(driver, pool, res, &row, i);
+ ABTS_ASSERT(tc, sql, rv == APR_SUCCESS);
+ ABTS_PTR_NOTNULL(tc, row);
+ apr_pool_clear(tpool);
+ i--;
+ }
+ ABTS_ASSERT(tc, "Missing Rows!", i == 0);
+ rv = apr_dbd_get_row(driver, pool, res, &row, count+100);
+ ABTS_ASSERT(tc, "If we overseek, get_row should return -1", rv == -1);
+}
+
+static void test_escape(abts_case *tc, apr_dbd_t *handle,
+ const apr_dbd_driver_t *driver)
+{
+ const char *escaped = apr_dbd_escape(driver, p, "foo'bar", handle);
+
+ ABTS_STR_EQUAL(tc, "foo''bar", escaped);
+}
+
+static void test_dbd_generic(abts_case *tc, apr_dbd_t* handle,
+ const apr_dbd_driver_t* driver)
+{
+ void* native;
+ apr_pool_t *pool = p;
+ apr_status_t rv;
+
+ native = apr_dbd_native_handle(driver, handle);
+ ABTS_PTR_NOTNULL(tc, native);
+
+ apr_dbd_check_conn(driver, pool, handle);
+
+ create_table(tc, handle, driver);
+ select_rows(tc, handle, driver, 0);
+ insert_data(tc, handle, driver, 5);
+ select_rows(tc, handle, driver, 5);
+ delete_rows(tc, handle, driver);
+ select_rows(tc, handle, driver, 0);
+ drop_table(tc, handle, driver);
+
+ test_escape(tc, handle, driver);
+
+ rv = apr_dbd_close(driver, handle);
+ ABTS_ASSERT(tc, "failed to close database", rv == APR_SUCCESS);
+}
+#endif
+
+#if APU_HAVE_SQLITE2
+static void test_dbd_sqlite2(abts_case *tc, void *data)
+{
+ apr_pool_t *pool = p;
+ apr_status_t rv;
+ const apr_dbd_driver_t* driver = NULL;
+ apr_dbd_t* handle = NULL;
+
+ rv = apr_dbd_get_driver(pool, "sqlite2", &driver);
+ ABTS_ASSERT(tc, "failed to fetch sqlite2 driver", rv == APR_SUCCESS);
+ ABTS_PTR_NOTNULL(tc, driver);
+ if (!driver) {
+ return;
+ }
+
+ ABTS_STR_EQUAL(tc, "sqlite2", apr_dbd_name(driver));
+
+ rv = apr_dbd_open(driver, pool, "data/sqlite2.db:600", &handle);
+ ABTS_ASSERT(tc, "failed to open sqlite2 atabase", rv == APR_SUCCESS);
+ ABTS_PTR_NOTNULL(tc, handle);
+ if (!handle) {
+ return;
+ }
+
+ test_dbd_generic(tc, handle, driver);
+}
+#endif
+
+#if APU_HAVE_SQLITE3
+static void test_dbd_sqlite3(abts_case *tc, void *data)
+{
+ apr_pool_t *pool = p;
+ apr_status_t rv;
+ const apr_dbd_driver_t* driver = NULL;
+ apr_dbd_t* handle = NULL;
+
+ rv = apr_dbd_get_driver(pool, "sqlite3", &driver);
+ ABTS_ASSERT(tc, "failed to fetch sqlite3 driver", rv == APR_SUCCESS);
+ ABTS_PTR_NOTNULL(tc, driver);
+ if (!driver) {
+ return;
+ }
+
+ ABTS_STR_EQUAL(tc, "sqlite3", apr_dbd_name(driver));
+
+ rv = apr_dbd_open(driver, pool, "data/sqlite3.db", &handle);
+ ABTS_ASSERT(tc, "failed to open sqlite3 database", rv == APR_SUCCESS);
+ ABTS_PTR_NOTNULL(tc, handle);
+ if (!handle) {
+ return;
+ }
+
+ test_dbd_generic(tc, handle, driver);
+}
+#endif
+
+abts_suite *testdbd(abts_suite *suite)
+{
+ suite = ADD_SUITE(suite);
+
+
+ abts_run_test(suite, test_dbd_init, NULL);
+
+#if APU_HAVE_SQLITE2
+ abts_run_test(suite, test_dbd_sqlite2, NULL);
+#endif
+
+#if APU_HAVE_SQLITE3
+ abts_run_test(suite, test_dbd_sqlite3, NULL);
+#endif
+ return suite;
+}
diff --git a/test/testdbm.c b/test/testdbm.c
new file mode 100644
index 0000000..4f6becb
--- /dev/null
+++ b/test/testdbm.c
@@ -0,0 +1,221 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "apr.h"
+#include "apr_general.h"
+#include "apr_pools.h"
+#include "apr_errno.h"
+#include "apr_dbm.h"
+#include "apr_uuid.h"
+#include "apr_strings.h"
+#include "abts.h"
+#include "testutil.h"
+
+#define NUM_TABLE_ROWS 1024
+
+typedef struct {
+ apr_datum_t key;
+ apr_datum_t val;
+ int deleted;
+ int visited;
+} dbm_table_t;
+
+static dbm_table_t *generate_table(void)
+{
+ unsigned int i;
+ apr_uuid_t uuid;
+ dbm_table_t *table = apr_pcalloc(p, sizeof(*table) * NUM_TABLE_ROWS);
+
+ for (i = 0; i < NUM_TABLE_ROWS/2; i++) {
+ apr_uuid_get(&uuid);
+ table[i].key.dptr = apr_pmemdup(p, uuid.data, sizeof(uuid.data));
+ table[i].key.dsize = sizeof(uuid.data);
+ table[i].val.dptr = apr_palloc(p, APR_UUID_FORMATTED_LENGTH + 1);
+ table[i].val.dsize = APR_UUID_FORMATTED_LENGTH + 1;
+ apr_uuid_format(table[i].val.dptr, &uuid);
+ }
+
+ for (; i < NUM_TABLE_ROWS; i++) {
+ apr_uuid_get(&uuid);
+ table[i].val.dptr = apr_pmemdup(p, uuid.data, sizeof(uuid.data));
+ table[i].val.dsize = sizeof(uuid.data);
+ table[i].key.dptr = apr_palloc(p, APR_UUID_FORMATTED_LENGTH + 1);
+ table[i].key.dsize = APR_UUID_FORMATTED_LENGTH + 1;
+ apr_uuid_format(table[i].key.dptr, &uuid);
+ }
+
+ return table;
+}
+
+static void test_dbm_store(abts_case *tc, apr_dbm_t *db, dbm_table_t *table)
+{
+ apr_status_t rv;
+ unsigned int i = NUM_TABLE_ROWS - 1;
+
+ for (; i >= NUM_TABLE_ROWS/2; i--) {
+ rv = apr_dbm_store(db, table[i].key, table[i].val);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+ table[i].deleted = FALSE;
+ }
+
+ for (i = 0; i < NUM_TABLE_ROWS/2; i++) {
+ rv = apr_dbm_store(db, table[i].key, table[i].val);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+ table[i].deleted = FALSE;
+ }
+}
+
+static void test_dbm_fetch(abts_case *tc, apr_dbm_t *db, dbm_table_t *table)
+{
+ apr_status_t rv;
+ unsigned int i;
+ apr_datum_t val;
+
+ for (i = 0; i < NUM_TABLE_ROWS; i++) {
+ memset(&val, 0, sizeof(val));
+ rv = apr_dbm_fetch(db, table[i].key, &val);
+ if (!table[i].deleted) {
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+ ABTS_INT_EQUAL(tc, table[i].val.dsize, val.dsize);
+ ABTS_INT_EQUAL(tc, 0, memcmp(table[i].val.dptr, val.dptr, val.dsize));
+ apr_dbm_freedatum(db, val);
+ } else {
+ ABTS_INT_EQUAL(tc, 0, val.dsize);
+ }
+ }
+}
+
+static void test_dbm_delete(abts_case *tc, apr_dbm_t *db, dbm_table_t *table)
+{
+ apr_status_t rv;
+ unsigned int i;
+
+ for (i = 0; i < NUM_TABLE_ROWS; i++) {
+ /* XXX: random */
+ if (i & 1)
+ continue;
+ rv = apr_dbm_delete(db, table[i].key);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+ table[i].deleted = TRUE;
+ }
+}
+
+static void test_dbm_exists(abts_case *tc, apr_dbm_t *db, dbm_table_t *table)
+{
+ unsigned int i;
+ int cond;
+
+ for (i = 0; i < NUM_TABLE_ROWS; i++) {
+ cond = apr_dbm_exists(db, table[i].key);
+ if (table[i].deleted) {
+ ABTS_TRUE(tc, cond == 0);
+ } else {
+ ABTS_TRUE(tc, cond != 0);
+ }
+ }
+}
+
+static void test_dbm_traversal(abts_case *tc, apr_dbm_t *db, dbm_table_t *table)
+{
+ apr_status_t rv;
+ unsigned int i;
+ apr_datum_t key;
+
+ rv = apr_dbm_firstkey(db, &key);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+
+ do {
+ if (key.dptr == NULL || key.dsize == 0)
+ break;
+
+ for (i = 0; i < NUM_TABLE_ROWS; i++) {
+ if (table[i].key.dsize != key.dsize)
+ continue;
+ if (memcmp(table[i].key.dptr, key.dptr, key.dsize))
+ continue;
+ ABTS_INT_EQUAL(tc, 0, table[i].deleted);
+ ABTS_INT_EQUAL(tc, 0, table[i].visited);
+ table[i].visited++;
+ }
+
+ rv = apr_dbm_nextkey(db, &key);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+ } while (1);
+
+ for (i = 0; i < NUM_TABLE_ROWS; i++) {
+ if (table[i].deleted)
+ continue;
+ ABTS_INT_EQUAL(tc, 1, table[i].visited);
+ table[i].visited = 0;
+ }
+}
+
+static void test_dbm(abts_case *tc, void *data)
+{
+ apr_dbm_t *db;
+ apr_status_t rv;
+ dbm_table_t *table;
+ const char *type = data;
+ const char *file = apr_pstrcat(p, "data/test-", type, NULL);
+
+ rv = apr_dbm_open_ex(&db, type, file, APR_DBM_RWCREATE, APR_OS_DEFAULT, p);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+
+ if (rv != APR_SUCCESS)
+ return;
+
+ table = generate_table();
+
+ test_dbm_store(tc, db, table);
+ test_dbm_fetch(tc, db, table);
+ test_dbm_delete(tc, db, table);
+ test_dbm_exists(tc, db, table);
+ test_dbm_traversal(tc, db, table);
+
+ apr_dbm_close(db);
+
+ rv = apr_dbm_open_ex(&db, type, file, APR_DBM_READONLY, APR_OS_DEFAULT, p);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+
+ if (rv != APR_SUCCESS)
+ return;
+
+ test_dbm_exists(tc, db, table);
+ test_dbm_traversal(tc, db, table);
+ test_dbm_fetch(tc, db, table);
+
+ apr_dbm_close(db);
+}
+
+abts_suite *testdbm(abts_suite *suite)
+{
+ suite = ADD_SUITE(suite);
+
+#if APU_HAVE_GDBM
+ abts_run_test(suite, test_dbm, "gdbm");
+#endif
+#if APU_HAVE_NDBM
+ abts_run_test(suite, test_dbm, "ndbm");
+#endif
+#if APU_HAVE_SDBM
+ abts_run_test(suite, test_dbm, "sdbm");
+#endif
+#if APU_HAVE_DB
+ abts_run_test(suite, test_dbm, "db");
+#endif
+
+ return suite;
+}
diff --git a/test/testldap.c b/test/testldap.c
new file mode 100644
index 0000000..4f4fef9
--- /dev/null
+++ b/test/testldap.c
@@ -0,0 +1,250 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+ /* Setup:
+ * - Create or edit the file data/host.data and add an
+ * ldap server DN. Multiple DNs may be listed on
+ * a single line.
+ * - Copy the server certificates to the data/ directory.
+ * All DER type certificates must have the .der extention.
+ * All BASE64 or PEM certificates must have the .b64
+ * extension. All certificate files copied to the /data
+ * directory will be added to the ldap certificate store.
+ */
+
+ /* This test covers the following three types of connections:
+ * - Unsecure ldap://
+ * - Secure ldaps://
+ * - Secure ldap://+Start_TLS
+ *
+ * - (TBD) Mutual authentication
+ *
+ * There are other variations that should be tested:
+ * - All of the above with multiple redundant LDAP servers
+ * This can be done by listing more than one server DN
+ * in the host.data file. The DNs should all be listed
+ * on one line separated by a space.
+ * - All of the above with multiple certificates
+ * If more than one certificate is found in the data/
+ * directory, each certificate found will be added
+ * to the certificate store.
+ * - All of the above on alternate ports
+ * An alternate port can be specified as part of the
+ * host in the host.data file. The ":port" should
+ * follow each DN listed. Default is 389 and 636.
+ * - Secure connections with mutual authentication
+ */
+
+#include "testutil.h"
+
+#include "apr.h"
+#include "apr_general.h"
+#include "apr_ldap.h"
+#include "apr_file_io.h"
+#include "apr_file_info.h"
+#include "apr_strings.h"
+#if APR_HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#define APR_WANT_STDIO
+#define APR_WANT_STRFUNC
+#include "apr_want.h"
+
+#define DIRNAME "data"
+#define FILENAME DIRNAME "/host.data"
+#define CERTFILEDER DIRNAME "/*.der"
+#define CERTFILEB64 DIRNAME "/*.b64"
+
+#if APR_HAS_LDAP
+
+static char ldap_host[256];
+
+static int get_ldap_host(void)
+{
+ apr_status_t rv;
+ apr_file_t *thefile = NULL;
+ char *ptr;
+
+ ldap_host[0] = '\0';
+ rv = apr_file_open(&thefile, FILENAME,
+ APR_FOPEN_READ,
+ APR_UREAD | APR_UWRITE | APR_GREAD, p);
+ if (rv != APR_SUCCESS) {
+ return 0;
+ }
+
+ rv = apr_file_gets(ldap_host, sizeof(ldap_host), thefile);
+ if (rv != APR_SUCCESS) {
+ return 0;
+ }
+
+ ptr = strstr (ldap_host, "\r\n");
+ if (ptr) {
+ *ptr = '\0';
+ }
+ apr_file_close(thefile);
+
+ return 1;
+
+}
+
+static int add_ldap_certs(abts_case *tc)
+{
+ apr_status_t status;
+ apr_dir_t *thedir;
+ apr_finfo_t dirent;
+ apr_ldap_err_t *result = NULL;
+
+ if ((status = apr_dir_open(&thedir, DIRNAME, p)) == APR_SUCCESS) {
+ apr_ldap_opt_tls_cert_t *cert = (apr_ldap_opt_tls_cert_t *)apr_pcalloc(p, sizeof(apr_ldap_opt_tls_cert_t));
+
+ do {
+ status = apr_dir_read(&dirent, APR_FINFO_MIN | APR_FINFO_NAME, thedir);
+ if (APR_STATUS_IS_INCOMPLETE(status)) {
+ continue; /* ignore un-stat()able files */
+ }
+ else if (status != APR_SUCCESS) {
+ break;
+ }
+
+ if (strstr(dirent.name, ".der")) {
+ cert->type = APR_LDAP_CA_TYPE_DER;
+ cert->path = apr_pstrcat (p, DIRNAME, "/", dirent.name, NULL);
+ apr_ldap_set_option(p, NULL, APR_LDAP_OPT_TLS_CERT, (void *)cert, &result);
+ ABTS_TRUE(tc, result->rc == LDAP_SUCCESS);
+ }
+ if (strstr(dirent.name, ".b64")) {
+ cert->type = APR_LDAP_CA_TYPE_BASE64;
+ cert->path = apr_pstrcat (p, DIRNAME, "/", dirent.name, NULL);
+ apr_ldap_set_option(p, NULL, APR_LDAP_OPT_TLS_CERT, (void *)cert, &result);
+ ABTS_TRUE(tc, result->rc == LDAP_SUCCESS);
+ }
+
+ } while (1);
+
+ apr_dir_close(thedir);
+ }
+ return 0;
+}
+
+static void test_ldap_connection(abts_case *tc, LDAP *ldap)
+{
+ int version = LDAP_VERSION3;
+ int failures, result;
+
+ /* always default to LDAP V3 */
+ ldap_set_option(ldap, LDAP_OPT_PROTOCOL_VERSION, &version);
+
+ for (failures=0; failures<10; failures++)
+ {
+ result = ldap_simple_bind_s(ldap,
+ (char *)NULL,
+ (char *)NULL);
+ if (LDAP_SERVER_DOWN != result)
+ break;
+ }
+
+ ABTS_TRUE(tc, result == LDAP_SUCCESS);
+ if (result != LDAP_SUCCESS) {
+ abts_log_message("%s\n", ldap_err2string(result));
+ }
+
+ ldap_unbind_s(ldap);
+
+ return;
+}
+
+static void test_ldap(abts_case *tc, void *data)
+{
+ apr_pool_t *pool = p;
+ LDAP *ldap;
+ apr_ldap_err_t *result = NULL;
+
+
+ ABTS_ASSERT(tc, "failed to get host", ldap_host[0] != '\0');
+
+ apr_ldap_init(pool, &ldap,
+ ldap_host, LDAP_PORT,
+ APR_LDAP_NONE, &(result));
+
+ ABTS_TRUE(tc, ldap != NULL);
+ ABTS_PTR_NOTNULL(tc, result);
+
+ if (result->rc == LDAP_SUCCESS) {
+ test_ldap_connection(tc, ldap);
+ }
+}
+
+static void test_ldaps(abts_case *tc, void *data)
+{
+ apr_pool_t *pool = p;
+ LDAP *ldap;
+ apr_ldap_err_t *result = NULL;
+
+ apr_ldap_init(pool, &ldap,
+ ldap_host, LDAPS_PORT,
+ APR_LDAP_SSL, &(result));
+
+ ABTS_TRUE(tc, ldap != NULL);
+ ABTS_PTR_NOTNULL(tc, result);
+
+ if (result->rc == LDAP_SUCCESS) {
+ add_ldap_certs(tc);
+
+ test_ldap_connection(tc, ldap);
+ }
+}
+
+static void test_ldap_tls(abts_case *tc, void *data)
+{
+ apr_pool_t *pool = p;
+ LDAP *ldap;
+ apr_ldap_err_t *result = NULL;
+
+ apr_ldap_init(pool, &ldap,
+ ldap_host, LDAP_PORT,
+ APR_LDAP_STARTTLS, &(result));
+
+ ABTS_TRUE(tc, ldap != NULL);
+ ABTS_PTR_NOTNULL(tc, result);
+
+ if (result->rc == LDAP_SUCCESS) {
+ add_ldap_certs(tc);
+
+ test_ldap_connection(tc, ldap);
+ }
+}
+
+#endif /* APR_HAS_LDAP */
+
+abts_suite *testldap(abts_suite *suite)
+{
+#if APR_HAS_LDAP
+ apr_ldap_err_t *result = NULL;
+ suite = ADD_SUITE(suite);
+
+ apr_ldap_ssl_init(p, NULL, 0, &result);
+
+ if (get_ldap_host()) {
+ abts_run_test(suite, test_ldap, NULL);
+ abts_run_test(suite, test_ldaps, NULL);
+ abts_run_test(suite, test_ldap_tls, NULL);
+ }
+#endif /* APR_HAS_LDAP */
+
+ return suite;
+}
+
diff --git a/test/testmd4.c b/test/testmd4.c
new file mode 100644
index 0000000..53a3361
--- /dev/null
+++ b/test/testmd4.c
@@ -0,0 +1,119 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/* This is derived from material copyright RSA Data Security, Inc.
+ * Their notice is reproduced below in its entirety.
+ *
+ * Copyright (C) 1990-2, RSA Data Security, Inc. Created 1990. All
+ * rights reserved.
+ *
+ * RSA Data Security, Inc. makes no representations concerning either
+ * the merchantability of this software or the suitability of this
+ * software for any particular purpose. It is provided "as is"
+ * without express or implied warranty of any kind.
+ *
+ * These notices must be retained in any copies of any part of this
+ * documentation and/or software.
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "apr_errno.h"
+#include "apr_md4.h"
+#include "apr_file_io.h"
+
+#include "abts.h"
+#include "testutil.h"
+
+static struct {
+ const char *string;
+ const char *md4sum;
+} md4sums[] =
+{
+/*
+* Taken from the old md4 test suite.
+* MD4 ("") = 31d6cfe0d16ae931b73c59d7e0c089c0
+* MD4 ("a") = bde52cb31de33e46245e05fbdbd6fb24
+* MD4 ("abc") = a448017aaf21d8525fc10ae87aa6729d
+* MD4 ("message digest") = d9130a8164549fe818874806e1c7014b
+* MD4 ("abcdefghijklmnopqrstuvwxyz") = d79e1c308aa5bbcdeea8ed63df412da9
+* MD4 ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789")
+* MD4 ("12345678901234567890123456789012345678901234567890123456789012345678901234567890") = e33b4ddc9c38f2199c3e7b164fcc0536
+*
+*/
+ {"",
+ "\x31\xd6\xcf\xe0\xd1\x6a\xe9\x31\xb7\x3c\x59\xd7\xe0\xc0\x89\xc0"},
+ {"a",
+ "\xbd\xe5\x2c\xb3\x1d\xe3\x3e\x46\x24\x5e\x05\xfb\xdb\xd6\xfb\x24"},
+ {"abc",
+ "\xa4\x48\x01\x7a\xaf\x21\xd8\x52\x5f\xc1\x0a\xe8\x7a\xa6\x72\x9d"},
+ {"message digest",
+ "\xd9\x13\x0a\x81\x64\x54\x9f\xe8\x18\x87\x48\x06\xe1\xc7\x01\x4b"},
+ {"abcdefghijklmnopqrstuvwxyz",
+ "\xd7\x9e\x1c\x30\x8a\xa5\xbb\xcd\xee\xa8\xed\x63\xdf\x41\x2d\xa9"},
+ {"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
+ "\x04\x3f\x85\x82\xf2\x41\xdb\x35\x1c\xe6\x27\xe1\x53\xe7\xf0\xe4"},
+ {"12345678901234567890123456789012345678901234567890123456789012345678901234567890",
+ "\xe3\x3b\x4d\xdc\x9c\x38\xf2\x19\x9c\x3e\x7b\x16\x4f\xcc\x05\x36"}
+};
+
+static int num_sums = sizeof(md4sums) / sizeof(md4sums[0]);
+static int count;
+
+#if 0
+static int MDStringComp(const void *string, const void *sum)
+{
+ apr_md4_ctx_t context;
+ unsigned char digest[APR_MD4_DIGESTSIZE];
+ unsigned int len = strlen(string);
+
+ apr_md4_init(&context);
+ apr_md4_update(&context, (unsigned char *)string, len);
+ apr_md4_final(digest, &context);
+ return (memcmp(digest, sum, APR_MD4_DIGESTSIZE));
+
+}
+#endif
+
+static void test_md4sum(abts_case *tc, void *data)
+{
+ apr_md4_ctx_t context;
+ unsigned char digest[APR_MD4_DIGESTSIZE];
+ const void *string = md4sums[count].string;
+ const void *sum = md4sums[count].md4sum;
+ unsigned int len = strlen(string);
+
+ ABTS_ASSERT(tc, "apr_md4_init", (apr_md4_init(&context) == 0));
+ ABTS_ASSERT(tc, "apr_md4_update",
+ (apr_md4_update(&context,
+ (unsigned char *)string, len) == 0));
+
+ ABTS_ASSERT(tc, "apr_md4_final", (apr_md4_final(digest, &context) ==0));
+ ABTS_ASSERT(tc, "check for correct md4 digest",
+ (memcmp(digest, sum, APR_MD4_DIGESTSIZE) == 0));
+}
+
+abts_suite *testmd4(abts_suite *suite)
+{
+ suite = ADD_SUITE(suite);
+
+ for (count=0; count < num_sums; count++) {
+ abts_run_test(suite, test_md4sum, NULL);
+ }
+
+ return suite;
+}
diff --git a/test/testmd5.c b/test/testmd5.c
new file mode 100644
index 0000000..4e13da2
--- /dev/null
+++ b/test/testmd5.c
@@ -0,0 +1,103 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "apr_md5.h"
+#include "apr_xlate.h"
+#include "apr_general.h"
+
+#include "abts.h"
+#include "testutil.h"
+
+static struct {
+ const char *string;
+ const char *digest;
+} md5sums[] =
+{
+ {"Jeff was here!",
+ "\xa5\x25\x8a\x89\x11\xb2\x9d\x1f\x81\x75\x96\x3b\x60\x94\x49\xc0"},
+ {"01234567890aBcDeFASDFGHJKLPOIUYTR"
+ "POIUYTREWQZXCVBN LLLLLLLLLLLLLLL",
+ "\xd4\x1a\x06\x2c\xc5\xfd\x6f\x24\x67\x68\x56\x7c\x40\x8a\xd5\x69"},
+ {"111111118888888888888888*******%%%%%%%%%%#####"
+ "142134u8097289720432098409289nkjlfkjlmn,m.. ",
+ "\xb6\xea\x5b\xe8\xca\x45\x8a\x33\xf0\xf1\x84\x6f\xf9\x65\xa8\xe1"},
+ {"01234567890aBcDeFASDFGHJKLPOIUYTR"
+ "POIUYTREWQZXCVBN LLLLLLLLLLLLLLL"
+ "01234567890aBcDeFASDFGHJKLPOIUYTR"
+ "POIUYTREWQZXCVBN LLLLLLLLLLLLLLL"
+ "1",
+ "\xd1\xa1\xc0\x97\x8a\x60\xbb\xfb\x2a\x25\x46\x9d\xa5\xae\xd0\xb0"}
+};
+
+static int num_sums = sizeof(md5sums) / sizeof(md5sums[0]);
+static int count;
+
+static void test_md5sum(abts_case *tc, void *data)
+{
+ apr_md5_ctx_t context;
+ unsigned char digest[APR_MD5_DIGESTSIZE];
+ const void *string = md5sums[count].string;
+ const void *sum = md5sums[count].digest;
+ unsigned int len = strlen(string);
+
+ ABTS_ASSERT(tc, "apr_md5_init", (apr_md5_init(&context) == 0));
+ ABTS_ASSERT(tc, "apr_md5_update",
+ (apr_md5_update(&context, string, len) == 0));
+ ABTS_ASSERT(tc, "apr_md5_final", (apr_md5_final(digest, &context)
+ == 0));
+ ABTS_ASSERT(tc, "check for correct md5 digest",
+ (memcmp(digest, sum, APR_MD5_DIGESTSIZE) == 0));
+}
+
+static void test_md5sum_unaligned(abts_case *tc, void *data)
+{
+ apr_md5_ctx_t context;
+ const char *string = "abcdefghijklmnopqrstuvwxyz01234"
+ "abcdefghijklmnopqrstuvwxyz01234"
+ "abcdefghijklmnopqrstuvwxyz01234"
+ "abcdefghijklmnopqrstuvwxyz01234_";
+ const char *sum =
+ "\x93\x17\x22\x78\xee\x30\x82\xb3\xeb\x95\x33\xec\xea\x78\xb7\x89";
+ unsigned char digest[APR_MD5_DIGESTSIZE];
+ unsigned int i;
+
+ ABTS_ASSERT(tc, "apr_md5_init", (apr_md5_init(&context) == 0));
+ for (i = 0; i < 10; i++) {
+ ABTS_ASSERT(tc, "apr_md5_update",
+ (apr_md5_update(&context, string, strlen(string)) == 0));
+ string++;
+ }
+ ABTS_ASSERT(tc, "apr_md5_final", (apr_md5_final(digest, &context)
+ == 0));
+ ABTS_ASSERT(tc, "check for correct md5 digest of unaligned data",
+ (memcmp(digest, sum, APR_MD5_DIGESTSIZE) == 0));
+}
+
+abts_suite *testmd5(abts_suite *suite)
+{
+ suite = ADD_SUITE(suite);
+
+ for (count=0; count < num_sums; count++) {
+ abts_run_test(suite, test_md5sum, NULL);
+ }
+ abts_run_test(suite, test_md5sum_unaligned, NULL);
+
+ return suite;
+}
diff --git a/test/testmemcache.c b/test/testmemcache.c
new file mode 100644
index 0000000..c65381e
--- /dev/null
+++ b/test/testmemcache.c
@@ -0,0 +1,626 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "testutil.h"
+#include "apr.h"
+#include "apu.h"
+#include "apr_general.h"
+#include "apr_strings.h"
+#include "apr_hash.h"
+#include "apr_memcache.h"
+#include "apr_network_io.h"
+
+#if APR_HAVE_STDLIB_H
+#include <stdlib.h> /* for exit() */
+#endif
+
+#define HOST "localhost"
+#define PORT 11211
+
+/* the total number of items to use for set/get testing */
+#define TDATA_SIZE 3000
+
+/* some smaller subset of TDATA_SIZE used for multiget testing */
+#define TDATA_SET 100
+
+/* our custom hash function just returns this all the time */
+#define HASH_FUNC_RESULT 510
+
+/* all keys will be prefixed with this */
+const char prefix[] = "testmemcache";
+
+/* text for values we store */
+const char txt[] =
+"Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Duis at"
+"lacus in ligula hendrerit consectetuer. Vestibulum tristique odio"
+"iaculis leo. In massa arcu, ultricies a, laoreet nec, hendrerit non,"
+"neque. Nulla sagittis sapien ac risus. Morbi ligula dolor, vestibulum"
+"nec, viverra id, placerat dapibus, arcu. Curabitur egestas feugiat"
+"tellus. Donec dignissim. Nunc ante. Curabitur id lorem. In mollis"
+"tortor sit amet eros auctor dapibus. Proin nulla sem, tristique in,"
+"convallis id, iaculis feugiat cras amet.";
+
+/*
+ * this datatype is for our custom server determination function. this might
+ * be useful if you don't want to rely on simply hashing keys to determine
+ * where a key belongs, but instead want to write something fancy, or use some
+ * other kind of configuration data, i.e. a hash plus some data about a
+ * namespace, or whatever. see my_server_func, and test_memcache_user_funcs
+ * for the examples.
+ */
+typedef struct {
+ const char *someval;
+ apr_uint32_t which_server;
+} my_hash_server_baton;
+
+
+/* this could do something fancy and return some hash result.
+ * for simplicity, just return the same value, so we can test it later on.
+ * if you wanted to use some external hashing library or functions for
+ * consistent hashing, for example, this would be a good place to do it.
+ */
+static apr_uint32_t my_hash_func(void *baton, const char *data,
+ apr_size_t data_len)
+{
+
+ return HASH_FUNC_RESULT;
+}
+
+/*
+ * a fancy function to determine which server to use given some kind of data
+ * and a hash value. this example actually ignores the hash value itself
+ * and pulls some number from the *baton, which is a struct that has some
+ * kind of meaningful stuff in it.
+ */
+static apr_memcache_server_t *my_server_func(void *baton,
+ apr_memcache_t *mc,
+ const apr_uint32_t hash)
+{
+ apr_memcache_server_t *ms = NULL;
+ my_hash_server_baton *mhsb = (my_hash_server_baton *)baton;
+
+ if(mc->ntotal == 0) {
+ return NULL;
+ }
+
+ if(mc->ntotal < mhsb->which_server) {
+ return NULL;
+ }
+
+ ms = mc->live_servers[mhsb->which_server - 1];
+
+ return ms;
+}
+
+apr_uint16_t firsttime = 0;
+static int randval(apr_uint32_t high)
+{
+ apr_uint32_t i = 0;
+ double d = 0;
+
+ if (firsttime == 0) {
+ srand((unsigned) (getpid()));
+ firsttime = 1;
+ }
+
+ d = (double) rand() / ((double) RAND_MAX + 1);
+ i = (int) (d * (high - 0 + 1));
+
+ return i > 0 ? i : 1;
+}
+
+/*
+ * general test to make sure we can create the memcache struct and add
+ * some servers, but not more than we tell it we can add
+ */
+
+static void test_memcache_create(abts_case * tc, void *data)
+{
+ apr_pool_t *pool = p;
+ apr_status_t rv;
+ apr_memcache_t *memcache;
+ apr_memcache_server_t *server, *s;
+ apr_uint32_t max_servers = 10;
+ apr_uint32_t i;
+ apr_uint32_t hash;
+
+ rv = apr_memcache_create(pool, max_servers, 0, &memcache);
+ ABTS_ASSERT(tc, "memcache create failed", rv == APR_SUCCESS);
+
+ for (i = 1; i <= max_servers; i++) {
+ apr_port_t port;
+
+ port = PORT + i;
+ rv =
+ apr_memcache_server_create(pool, HOST, PORT + i, 0, 1, 1, 60, &server);
+ ABTS_ASSERT(tc, "server create failed", rv == APR_SUCCESS);
+
+ rv = apr_memcache_add_server(memcache, server);
+ ABTS_ASSERT(tc, "server add failed", rv == APR_SUCCESS);
+
+ s = apr_memcache_find_server(memcache, HOST, port);
+ ABTS_PTR_EQUAL(tc, server, s);
+
+ rv = apr_memcache_disable_server(memcache, s);
+ ABTS_ASSERT(tc, "server disable failed", rv == APR_SUCCESS);
+
+ rv = apr_memcache_enable_server(memcache, s);
+ ABTS_ASSERT(tc, "server enable failed", rv == APR_SUCCESS);
+
+ hash = apr_memcache_hash(memcache, prefix, strlen(prefix));
+ ABTS_ASSERT(tc, "hash failed", hash > 0);
+
+ s = apr_memcache_find_server_hash(memcache, hash);
+ ABTS_PTR_NOTNULL(tc, s);
+ }
+
+ rv = apr_memcache_server_create(pool, HOST, PORT, 0, 1, 1, 60, &server);
+ ABTS_ASSERT(tc, "server create failed", rv == APR_SUCCESS);
+
+ rv = apr_memcache_add_server(memcache, server);
+ ABTS_ASSERT(tc, "server add should have failed", rv != APR_SUCCESS);
+
+}
+
+/* install our own custom hashing and server selection routines. */
+
+static int create_test_hash(apr_pool_t *p, apr_hash_t *h)
+{
+ int i;
+
+ for (i = 0; i < TDATA_SIZE; i++) {
+ char *k, *v;
+
+ k = apr_pstrcat(p, prefix, apr_itoa(p, i), NULL);
+ v = apr_pstrndup(p, txt, randval((apr_uint32_t)strlen(txt)));
+
+ apr_hash_set(h, k, APR_HASH_KEY_STRING, v);
+ }
+
+ return i;
+}
+
+static void test_memcache_user_funcs(abts_case * tc, void *data)
+{
+ apr_pool_t *pool = p;
+ apr_status_t rv;
+ apr_memcache_t *memcache;
+ apr_memcache_server_t *found;
+ apr_uint32_t max_servers = 10;
+ apr_uint32_t hres;
+ apr_uint32_t i;
+ my_hash_server_baton *baton =
+ apr_pcalloc(pool, sizeof(my_hash_server_baton));
+
+ rv = apr_memcache_create(pool, max_servers, 0, &memcache);
+ ABTS_ASSERT(tc, "memcache create failed", rv == APR_SUCCESS);
+
+ /* as noted above, install our custom hash function, and call
+ * apr_memcache_hash. the return value should be our predefined number,
+ * and our function just ignores the other args, for simplicity.
+ */
+ memcache->hash_func = my_hash_func;
+
+ hres = apr_memcache_hash(memcache, "whatever", sizeof("whatever") - 1);
+ ABTS_INT_EQUAL(tc, HASH_FUNC_RESULT, hres);
+
+ /* add some servers */
+ for(i = 1; i <= 10; i++) {
+ apr_memcache_server_t *ms;
+
+ rv = apr_memcache_server_create(pool, HOST, i, 0, 1, 1, 60, &ms);
+ ABTS_ASSERT(tc, "server create failed", rv == APR_SUCCESS);
+
+ rv = apr_memcache_add_server(memcache, ms);
+ ABTS_ASSERT(tc, "server add failed", rv == APR_SUCCESS);
+ }
+
+ /*
+ * set 'which_server' in our server_baton to find the third server
+ * which should have the same port.
+ */
+ baton->which_server = 3;
+ memcache->server_func = my_server_func;
+ memcache->server_baton = baton;
+ found = apr_memcache_find_server_hash(memcache, 0);
+ ABTS_ASSERT(tc, "wrong server found", found->port == baton->which_server);
+}
+
+/* test non data related commands like stats and version */
+static void test_memcache_meta(abts_case * tc, void *data)
+{
+ apr_pool_t *pool = p;
+ apr_memcache_t *memcache;
+ apr_memcache_server_t *server;
+ apr_memcache_stats_t *stats;
+ char *result;
+ apr_status_t rv;
+
+ rv = apr_memcache_create(pool, 1, 0, &memcache);
+ ABTS_ASSERT(tc, "memcache create failed", rv == APR_SUCCESS);
+
+ rv = apr_memcache_server_create(pool, HOST, PORT, 0, 1, 1, 60, &server);
+ ABTS_ASSERT(tc, "server create failed", rv == APR_SUCCESS);
+
+ rv = apr_memcache_add_server(memcache, server);
+ ABTS_ASSERT(tc, "server add failed", rv == APR_SUCCESS);
+
+ apr_memcache_version(server, pool, &result);
+ ABTS_PTR_NOTNULL(tc, result);
+
+ apr_memcache_stats(server, p, &stats);
+ ABTS_PTR_NOTNULL(tc, stats);
+
+ ABTS_STR_NEQUAL(tc, stats->version, result, 5);
+
+ /*
+ * no way to know exactly what will be in most of these, so
+ * just make sure there is something.
+ */
+
+ ABTS_ASSERT(tc, "pid", stats->pid >= 0);
+ ABTS_ASSERT(tc, "time", stats->time >= 0);
+ /* ABTS_ASSERT(tc, "pointer_size", stats->pointer_size >= 0); */
+ ABTS_ASSERT(tc, "rusage_user", stats->rusage_user >= 0);
+ ABTS_ASSERT(tc, "rusage_system", stats->rusage_system >= 0);
+
+ ABTS_ASSERT(tc, "curr_items", stats->curr_items >= 0);
+ ABTS_ASSERT(tc, "total_items", stats->total_items >= 0);
+ ABTS_ASSERT(tc, "bytes", stats->bytes >= 0);
+
+ ABTS_ASSERT(tc, "curr_connections", stats->curr_connections >= 0);
+ ABTS_ASSERT(tc, "total_connections", stats->total_connections >= 0);
+ ABTS_ASSERT(tc, "connection_structures",
+ stats->connection_structures >= 0);
+
+ ABTS_ASSERT(tc, "cmd_get", stats->cmd_get >= 0);
+ ABTS_ASSERT(tc, "cmd_set", stats->cmd_set >= 0);
+ ABTS_ASSERT(tc, "get_hits", stats->get_hits >= 0);
+ ABTS_ASSERT(tc, "get_misses", stats->get_misses >= 0);
+
+ /* ABTS_ASSERT(tc, "evictions", stats->evictions >= 0); */
+
+ ABTS_ASSERT(tc, "bytes_read", stats->bytes_read >= 0);
+ ABTS_ASSERT(tc, "bytes_written", stats->bytes_written >= 0);
+ ABTS_ASSERT(tc, "limit_maxbytes", stats->limit_maxbytes >= 0);
+
+ /* ABTS_ASSERT(tc, "threads", stats->threads >= 0); */
+}
+
+/* test add and replace calls */
+
+static void test_memcache_addreplace(abts_case * tc, void *data)
+{
+ apr_pool_t *pool = p;
+ apr_status_t rv;
+ apr_memcache_t *memcache;
+ apr_memcache_server_t *server;
+ apr_hash_t *tdata;
+ apr_hash_index_t *hi;
+ char *result;
+ apr_size_t len;
+
+ rv = apr_memcache_create(pool, 1, 0, &memcache);
+ ABTS_ASSERT(tc, "memcache create failed", rv == APR_SUCCESS);
+
+ rv = apr_memcache_server_create(pool, HOST, PORT, 0, 1, 1, 60, &server);
+ ABTS_ASSERT(tc, "server create failed", rv == APR_SUCCESS);
+
+ rv = apr_memcache_add_server(memcache, server);
+ ABTS_ASSERT(tc, "server add failed", rv == APR_SUCCESS);
+
+ tdata = apr_hash_make(p);
+ create_test_hash(pool, tdata);
+
+ for (hi = apr_hash_first(p, tdata); hi; hi = apr_hash_next(hi)) {
+ const void *k;
+ void *v;
+ const char *key;
+
+ apr_hash_this(hi, &k, NULL, &v);
+ key = k;
+
+ /* doesn't exist yet, fail */
+ rv = apr_memcache_replace(memcache, key, v, strlen(v) - 1, 0, 27);
+ ABTS_ASSERT(tc, "replace should have failed", rv != APR_SUCCESS);
+
+ /* doesn't exist yet, succeed */
+ rv = apr_memcache_add(memcache, key, v, strlen(v), 0, 27);
+ ABTS_ASSERT(tc, "add failed", rv == APR_SUCCESS);
+
+ /* exists now, succeed */
+ rv = apr_memcache_replace(memcache, key, "new", sizeof("new") - 1, 0, 27);
+ ABTS_ASSERT(tc, "replace failed", rv == APR_SUCCESS);
+
+ /* make sure its different */
+ rv = apr_memcache_getp(memcache, pool, key, &result, &len, NULL);
+ ABTS_ASSERT(tc, "get failed", rv == APR_SUCCESS);
+ ABTS_STR_NEQUAL(tc, result, "new", 3);
+
+ /* exists now, fail */
+ rv = apr_memcache_add(memcache, key, v, strlen(v), 0, 27);
+ ABTS_ASSERT(tc, "add should have failed", rv != APR_SUCCESS);
+
+ /* clean up */
+ rv = apr_memcache_delete(memcache, key, 0);
+ ABTS_ASSERT(tc, "delete failed", rv == APR_SUCCESS);
+ }
+}
+
+/* basic tests of the increment and decrement commands */
+static void test_memcache_incrdecr(abts_case * tc, void *data)
+{
+ apr_pool_t *pool = p;
+ apr_status_t rv;
+ apr_memcache_t *memcache;
+ apr_memcache_server_t *server;
+ apr_uint32_t new;
+ char *result;
+ apr_size_t len;
+ apr_uint32_t i;
+
+ rv = apr_memcache_create(pool, 1, 0, &memcache);
+ ABTS_ASSERT(tc, "memcache create failed", rv == APR_SUCCESS);
+
+ rv = apr_memcache_server_create(pool, HOST, PORT, 0, 1, 1, 60, &server);
+ ABTS_ASSERT(tc, "server create failed", rv == APR_SUCCESS);
+
+ rv = apr_memcache_add_server(memcache, server);
+ ABTS_ASSERT(tc, "server add failed", rv == APR_SUCCESS);
+
+ rv = apr_memcache_set(memcache, prefix, "271", sizeof("271") - 1, 0, 27);
+ ABTS_ASSERT(tc, "set failed", rv == APR_SUCCESS);
+
+ for( i = 1; i <= TDATA_SIZE; i++) {
+ apr_uint32_t expect;
+
+ rv = apr_memcache_getp(memcache, pool, prefix, &result, &len, NULL);
+ ABTS_ASSERT(tc, "get failed", rv == APR_SUCCESS);
+
+ expect = i + atoi(result);
+
+ rv = apr_memcache_incr(memcache, prefix, i, &new);
+ ABTS_ASSERT(tc, "incr failed", rv == APR_SUCCESS);
+
+ ABTS_INT_EQUAL(tc, expect, new);
+
+ rv = apr_memcache_decr(memcache, prefix, i, &new);
+ ABTS_ASSERT(tc, "decr failed", rv == APR_SUCCESS);
+ ABTS_INT_EQUAL(tc, atoi(result), new);
+
+ }
+
+ rv = apr_memcache_getp(memcache, pool, prefix, &result, &len, NULL);
+ ABTS_ASSERT(tc, "get failed", rv == APR_SUCCESS);
+
+ ABTS_INT_EQUAL(tc, 271, atoi(result));
+
+ rv = apr_memcache_delete(memcache, prefix, 0);
+ ABTS_ASSERT(tc, "delete failed", rv == APR_SUCCESS);
+}
+
+/* test the multiget functionality */
+static void test_memcache_multiget(abts_case * tc, void *data)
+{
+ apr_pool_t *pool = p;
+ apr_pool_t *tmppool;
+ apr_status_t rv;
+ apr_memcache_t *memcache;
+ apr_memcache_server_t *server;
+ apr_hash_t *tdata, *values;
+ apr_hash_index_t *hi;
+ apr_uint32_t i;
+
+ rv = apr_memcache_create(pool, 1, 0, &memcache);
+ ABTS_ASSERT(tc, "memcache create failed", rv == APR_SUCCESS);
+
+ rv = apr_memcache_server_create(pool, HOST, PORT, 0, 1, 1, 60, &server);
+ ABTS_ASSERT(tc, "server create failed", rv == APR_SUCCESS);
+
+ rv = apr_memcache_add_server(memcache, server);
+ ABTS_ASSERT(tc, "server add failed", rv == APR_SUCCESS);
+
+ values = apr_hash_make(p);
+ tdata = apr_hash_make(p);
+
+ create_test_hash(pool, tdata);
+
+ for (hi = apr_hash_first(p, tdata); hi; hi = apr_hash_next(hi)) {
+ const void *k;
+ void *v;
+ const char *key;
+
+ apr_hash_this(hi, &k, NULL, &v);
+ key = k;
+
+ rv = apr_memcache_set(memcache, key, v, strlen(v), 0, 27);
+ ABTS_ASSERT(tc, "set failed", rv == APR_SUCCESS);
+ }
+
+ apr_pool_create(&tmppool, pool);
+ for (i = 0; i < TDATA_SET; i++)
+ apr_memcache_add_multget_key(pool,
+ apr_pstrcat(pool, prefix,
+ apr_itoa(pool, i), NULL),
+ &values);
+
+ rv = apr_memcache_multgetp(memcache,
+ tmppool,
+ pool,
+ values);
+
+ ABTS_ASSERT(tc, "multgetp failed", rv == APR_SUCCESS);
+ ABTS_ASSERT(tc, "multgetp returned too few results",
+ apr_hash_count(values) == TDATA_SET);
+
+ for (hi = apr_hash_first(p, tdata); hi; hi = apr_hash_next(hi)) {
+ const void *k;
+ const char *key;
+
+ apr_hash_this(hi, &k, NULL, NULL);
+ key = k;
+
+ rv = apr_memcache_delete(memcache, key, 0);
+ ABTS_ASSERT(tc, "delete failed", rv == APR_SUCCESS);
+ }
+
+}
+
+/* test setting and getting */
+
+static void test_memcache_setget(abts_case * tc, void *data)
+{
+ apr_pool_t *pool = p;
+ apr_status_t rv;
+ apr_memcache_t *memcache;
+ apr_memcache_server_t *server;
+ apr_hash_t *tdata;
+ apr_hash_index_t *hi;
+ char *result;
+ apr_size_t len;
+
+ rv = apr_memcache_create(pool, 1, 0, &memcache);
+ ABTS_ASSERT(tc, "memcache create failed", rv == APR_SUCCESS);
+
+ rv = apr_memcache_server_create(pool, HOST, PORT, 0, 1, 1, 60, &server);
+ ABTS_ASSERT(tc, "server create failed", rv == APR_SUCCESS);
+
+ rv = apr_memcache_add_server(memcache, server);
+ ABTS_ASSERT(tc, "server add failed", rv == APR_SUCCESS);
+
+ tdata = apr_hash_make(pool);
+
+ create_test_hash(pool, tdata);
+
+ for (hi = apr_hash_first(p, tdata); hi; hi = apr_hash_next(hi)) {
+ const void *k;
+ void *v;
+ const char *key;
+
+ apr_hash_this(hi, &k, NULL, &v);
+ key = k;
+
+ rv = apr_memcache_set(memcache, key, v, strlen(v), 0, 27);
+ ABTS_ASSERT(tc, "set failed", rv == APR_SUCCESS);
+ rv = apr_memcache_getp(memcache, pool, key, &result, &len, NULL);
+ ABTS_ASSERT(tc, "get failed", rv == APR_SUCCESS);
+ }
+
+ rv = apr_memcache_getp(memcache, pool, "nothere3423", &result, &len, NULL);
+
+ ABTS_ASSERT(tc, "get should have failed", rv != APR_SUCCESS);
+
+ for (hi = apr_hash_first(p, tdata); hi; hi = apr_hash_next(hi)) {
+ const void *k;
+ const char *key;
+
+ apr_hash_this(hi, &k, NULL, NULL);
+ key = k;
+
+ rv = apr_memcache_delete(memcache, key, 0);
+ ABTS_ASSERT(tc, "delete failed", rv == APR_SUCCESS);
+ }
+}
+
+/* use apr_socket stuff to see if there is in fact a memcached server
+ * running on PORT.
+ */
+static apr_status_t check_mc(void)
+{
+ apr_pool_t *pool = p;
+ apr_status_t rv;
+ apr_socket_t *sock = NULL;
+ apr_sockaddr_t *sa;
+ struct iovec vec[2];
+ apr_size_t written;
+ char buf[128];
+ apr_size_t len;
+
+ rv = apr_socket_create(&sock, APR_INET, SOCK_STREAM, 0, pool);
+ if(rv != APR_SUCCESS) {
+ return rv;
+ }
+
+ rv = apr_sockaddr_info_get(&sa, HOST, APR_INET, PORT, 0, pool);
+ if(rv != APR_SUCCESS) {
+ return rv;
+ }
+
+ rv = apr_socket_timeout_set(sock, 1 * APR_USEC_PER_SEC);
+ if (rv != APR_SUCCESS) {
+ return rv;
+ }
+
+ rv = apr_socket_connect(sock, sa);
+ if (rv != APR_SUCCESS) {
+ return rv;
+ }
+
+ rv = apr_socket_timeout_set(sock, -1);
+ if (rv != APR_SUCCESS) {
+ return rv;
+ }
+
+ vec[0].iov_base = "version";
+ vec[0].iov_len = sizeof("version") - 1;
+
+ vec[1].iov_base = "\r\n";
+ vec[1].iov_len = sizeof("\r\n") -1;
+
+ rv = apr_socket_sendv(sock, vec, 2, &written);
+ if (rv != APR_SUCCESS) {
+ return rv;
+ }
+
+ len = sizeof(buf);
+ rv = apr_socket_recv(sock, buf, &len);
+ if(rv != APR_SUCCESS) {
+ return rv;
+ }
+
+ if(strncmp(buf, "VERSION", sizeof("VERSION")-1) != 0) {
+ rv = APR_EGENERAL;
+ }
+
+ apr_socket_close(sock);
+ return rv;
+}
+
+abts_suite *testmemcache(abts_suite * suite)
+{
+ apr_status_t rv;
+ suite = ADD_SUITE(suite);
+ /* check for a running memcached on the typical port before
+ * trying to run the tests. succeed if we don't find one.
+ */
+ rv = check_mc();
+ if (rv == APR_SUCCESS) {
+ abts_run_test(suite, test_memcache_create, NULL);
+ abts_run_test(suite, test_memcache_user_funcs, NULL);
+ abts_run_test(suite, test_memcache_meta, NULL);
+ abts_run_test(suite, test_memcache_setget, NULL);
+ abts_run_test(suite, test_memcache_multiget, NULL);
+ abts_run_test(suite, test_memcache_addreplace, NULL);
+ abts_run_test(suite, test_memcache_incrdecr, NULL);
+ }
+ else {
+ abts_log_message("Error %d occurred attempting to reach memcached "
+ "on %s:%d. Skipping apr_memcache tests...",
+ rv, HOST, PORT);
+ }
+
+ return suite;
+}
diff --git a/test/testpass.c b/test/testpass.c
new file mode 100644
index 0000000..2a27a8f
--- /dev/null
+++ b/test/testpass.c
@@ -0,0 +1,217 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "apr_errno.h"
+#include "apr_strings.h"
+#include "apr_file_io.h"
+#include "apr_thread_pool.h"
+#include "apr_md5.h"
+#include "apr_sha1.h"
+
+#include "abts.h"
+#include "testutil.h"
+
+#if defined(WIN32) || defined(BEOS) || defined(NETWARE)
+#define CRYPT_ALGO_SUPPORTED 0
+#else
+#define CRYPT_ALGO_SUPPORTED 1
+#endif
+
+#if defined __GLIBC_PREREQ
+#if __GLIBC_PREREQ(2,7)
+#define GLIBCSHA_ALGO_SUPPORTED
+#endif
+#endif
+
+#if CRYPT_ALGO_SUPPORTED
+
+static struct {
+ const char *password;
+ const char *hash;
+} passwords[] =
+{
+/*
+ passwords and hashes created with Apache's htpasswd utility like this:
+
+ htpasswd -c -b passwords pass1 pass1
+ htpasswd -b passwords pass2 pass2
+ htpasswd -b passwords pass3 pass3
+ htpasswd -b passwords pass4 pass4
+ htpasswd -b passwords pass5 pass5
+ htpasswd -b passwords pass6 pass6
+ htpasswd -b passwords pass7 pass7
+ htpasswd -b passwords pass8 pass8
+ (insert Perl one-liner to convert to initializer :) )
+ */
+ {"pass1", "1fWDc9QWYCWrQ"},
+ {"pass2", "1fiGx3u7QoXaM"},
+ {"pass3", "1fzijMylTiwCs"},
+ {"pass4", "nHUYc8U2UOP7s"},
+ {"pass5", "nHpETGLGPwAmA"},
+ {"pass6", "nHbsbWmJ3uyhc"},
+ {"pass7", "nHQ3BbF0Y9vpI"},
+ {"pass8", "nHZA1rViSldQk"}
+};
+static int num_passwords = sizeof(passwords) / sizeof(passwords[0]);
+
+static void test_crypt(abts_case *tc, void *data)
+{
+ int i;
+
+ for (i = 0; i < num_passwords; i++) {
+ apr_assert_success(tc, "check for valid password",
+ apr_password_validate(passwords[i].password,
+ passwords[i].hash));
+ }
+}
+
+#if APR_HAS_THREADS
+
+static void * APR_THREAD_FUNC testing_thread(apr_thread_t *thd,
+ void *data)
+{
+ abts_case *tc = data;
+ int i;
+
+ for (i = 0; i < 100; i++) {
+ test_crypt(tc, NULL);
+ }
+
+ return APR_SUCCESS;
+}
+
+#define NUM_THR 20
+
+/* test for threadsafe crypt() */
+static void test_threadsafe(abts_case *tc, void *data)
+{
+ int i;
+ apr_status_t rv;
+ apr_thread_pool_t *thrp;
+
+ rv = apr_thread_pool_create(&thrp, NUM_THR/2, NUM_THR, p);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+
+ for (i = 0; i < NUM_THR; i++) {
+ rv = apr_thread_pool_push(thrp, testing_thread, tc, 0, NULL);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+ }
+
+ apr_thread_pool_destroy(thrp);
+}
+#endif
+
+#endif /* CRYPT_ALGO_SUPPORTED */
+
+static void test_shapass(abts_case *tc, void *data)
+{
+ const char *pass = "hellojed";
+ const char *pass2 = "hellojed2";
+ char hash[100];
+
+ apr_sha1_base64(pass, strlen(pass), hash);
+
+ apr_assert_success(tc, "SHA1 password validated",
+ apr_password_validate(pass, hash));
+ APR_ASSERT_FAILURE(tc, "wrong SHA1 password should not validate",
+ apr_password_validate(pass2, hash));
+}
+
+static void test_md5pass(abts_case *tc, void *data)
+{
+ const char *pass = "hellojed", *salt = "sardine";
+ const char *pass2 = "hellojed2";
+ char hash[100];
+
+ apr_md5_encode(pass, salt, hash, sizeof hash);
+
+ apr_assert_success(tc, "MD5 password validated",
+ apr_password_validate(pass, hash));
+ APR_ASSERT_FAILURE(tc, "wrong MD5 password should not validate",
+ apr_password_validate(pass2, hash));
+}
+
+#ifdef GLIBCSHA_ALGO_SUPPORTED
+
+static struct {
+ const char *password;
+ const char *hash;
+} glibc_sha_pws[] = {
+ /* SHA256 */
+ { "secret1", "$5$0123456789abcdef$SFX.CooXBS8oXsbAPgU/UyiCodhrLQ19sBgvcA3Zh1D" },
+ { "secret2", "$5$rounds=100000$0123456789abcdef$dLXfO5m4d.xv8G66kpz2LyL0.Mi5wjLlH0m7rtgyhyB" },
+ /* SHA512 */
+ { "secret3", "$6$0123456789abcdef$idOsOfoWwnCQkJm9hd2hxS4NnEs9nBA9poOFXsvtrYSoSHaOToCfyUoZwKe.ZCZnq7D95tGVoi2jxZZMyVwTL1" },
+ { "secret4", "$6$rounds=100000$0123456789abcdef$ZiAMjbeA.iIGTWxq2oks9Bvz9sfxaoGPgAtpwimPEwFwkSNMTK7lLwABzzldds/n4UgCQ16HqawPrCrePr4YX1" },
+ { NULL, NULL }
+};
+
+static void test_glibc_shapass(abts_case *tc, void *data)
+{
+ int i = 0;
+ while (glibc_sha_pws[i].password) {
+ apr_assert_success(tc, "check for valid glibc crypt-sha password",
+ apr_password_validate(glibc_sha_pws[i].password,
+ glibc_sha_pws[i].hash));
+ i++;
+ }
+}
+#endif
+
+static void test_bcryptpass(abts_case *tc, void *data)
+{
+ const char *pass = "hellojed";
+ const char *pass2 = "hellojed2";
+ unsigned char salt[] = "sardine_sardine";
+ char hash[100];
+ const char *hash2 = "$2a$08$qipUJiI9fySUN38hcbz.lucXvAmtgowKOWYtB9y3CXyl6lTknruou";
+ const char *pass3 = "foobar";
+
+ apr_assert_success(tc, "bcrypt encode password",
+ apr_bcrypt_encode(pass, 5, salt, sizeof(salt), hash,
+ sizeof(hash)));
+
+ apr_assert_success(tc, "bcrypt password validated",
+ apr_password_validate(pass, hash));
+ APR_ASSERT_FAILURE(tc, "wrong bcrypt password should not validate",
+ apr_password_validate(pass2, hash));
+ apr_assert_success(tc, "bcrypt password validated",
+ apr_password_validate(pass3, hash2));
+}
+
+
+abts_suite *testpass(abts_suite *suite)
+{
+ suite = ADD_SUITE(suite);
+
+#if CRYPT_ALGO_SUPPORTED
+ abts_run_test(suite, test_crypt, NULL);
+#if APR_HAS_THREADS
+ abts_run_test(suite, test_threadsafe, NULL);
+#endif
+#endif /* CRYPT_ALGO_SUPPORTED */
+ abts_run_test(suite, test_shapass, NULL);
+ abts_run_test(suite, test_md5pass, NULL);
+ abts_run_test(suite, test_bcryptpass, NULL);
+#ifdef GLIBCSHA_ALGO_SUPPORTED
+ abts_run_test(suite, test_glibc_shapass, NULL);
+#endif
+
+ return suite;
+}
diff --git a/test/testqueue.c b/test/testqueue.c
new file mode 100644
index 0000000..8f71775
--- /dev/null
+++ b/test/testqueue.c
@@ -0,0 +1,135 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "apu.h"
+#include "apr_queue.h"
+#include "apr_thread_pool.h"
+#include "apr_time.h"
+#include "abts.h"
+#include "testutil.h"
+
+#if APR_HAS_THREADS
+
+#define NUMBER_CONSUMERS 3
+#define CONSUMER_ACTIVITY 4
+#define NUMBER_PRODUCERS 4
+#define PRODUCER_ACTIVITY 5
+#define QUEUE_SIZE 100
+
+static apr_queue_t *queue;
+
+static void * APR_THREAD_FUNC consumer(apr_thread_t *thd, void *data)
+{
+ long sleeprate;
+ abts_case *tc = data;
+ apr_status_t rv;
+ void *v;
+
+ sleeprate = 1000000/CONSUMER_ACTIVITY;
+ apr_sleep((rand() % 4) * 1000000); /* sleep random seconds */
+
+ while (1)
+ {
+ rv = apr_queue_pop(queue, &v);
+
+ if (rv == APR_EINTR)
+ continue;
+
+ if (rv == APR_EOF)
+ break;
+
+ ABTS_TRUE(tc, v == NULL);
+ ABTS_TRUE(tc, rv == APR_SUCCESS);
+
+ apr_sleep(sleeprate); /* sleep this long to acheive our rate */
+ }
+
+ return NULL;
+}
+
+static void * APR_THREAD_FUNC producer(apr_thread_t *thd, void *data)
+{
+ long sleeprate;
+ abts_case *tc = data;
+ apr_status_t rv;
+
+ sleeprate = 1000000/PRODUCER_ACTIVITY;
+ apr_sleep((rand() % 4) * 1000000); /* sleep random seconds */
+
+ while (1)
+ {
+ rv = apr_queue_push(queue, NULL);
+
+ if (rv == APR_EINTR)
+ continue;
+
+ if (rv == APR_EOF)
+ break;
+
+ ABTS_TRUE(tc, rv == APR_SUCCESS);
+
+ apr_sleep(sleeprate); /* sleep this long to acheive our rate */
+ }
+
+ return NULL;
+}
+
+static void test_queue_producer_consumer(abts_case *tc, void *data)
+{
+ unsigned int i;
+ apr_status_t rv;
+ apr_thread_pool_t *thrp;
+
+ /* XXX: non-portable */
+ srand((unsigned int)apr_time_now());
+
+ rv = apr_queue_create(&queue, QUEUE_SIZE, p);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+
+ rv = apr_thread_pool_create(&thrp, 0, NUMBER_CONSUMERS + NUMBER_PRODUCERS, p);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+
+ for (i = 0; i < NUMBER_CONSUMERS; i++) {
+ rv = apr_thread_pool_push(thrp, consumer, tc, 0, NULL);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+ }
+
+ for (i = 0; i < NUMBER_PRODUCERS; i++) {
+ rv = apr_thread_pool_push(thrp, producer, tc, 0, NULL);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+ }
+
+ apr_sleep(5000000); /* sleep 5 seconds */
+
+ rv = apr_queue_term(queue);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+
+ rv = apr_thread_pool_destroy(thrp);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+}
+
+#endif /* APR_HAS_THREADS */
+
+abts_suite *testqueue(abts_suite *suite)
+{
+ suite = ADD_SUITE(suite);
+
+#if APR_HAS_THREADS
+ abts_run_test(suite, test_queue_producer_consumer, NULL);
+#endif /* APR_HAS_THREADS */
+
+ return suite;
+}
diff --git a/test/testredis.c b/test/testredis.c
new file mode 100644
index 0000000..830c09a
--- /dev/null
+++ b/test/testredis.c
@@ -0,0 +1,552 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "testutil.h"
+#include "apr.h"
+#include "apu.h"
+#include "apr_general.h"
+#include "apr_strings.h"
+#include "apr_hash.h"
+#include "apr_redis.h"
+#include "apr_network_io.h"
+
+#include <stdio.h>
+#if APR_HAVE_STDLIB_H
+#include <stdlib.h> /* for exit() */
+#endif
+
+#define HOST "localhost"
+#define PORT 6379
+
+/* the total number of items to use for set/get testing */
+#define TDATA_SIZE 3000
+
+/* some smaller subset of TDATA_SIZE used for multiget testing */
+#define TDATA_SET 100
+
+/* our custom hash function just returns this all the time */
+#define HASH_FUNC_RESULT 510
+
+/* all keys will be prefixed with this */
+static const char prefix[] = "testredis";
+
+/* text for values we store */
+static const char txt[] =
+"Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Duis at"
+"lacus in ligula hendrerit consectetuer. Vestibulum tristique odio"
+"iaculis leo. In massa arcu, ultricies a, laoreet nec, hendrerit non,"
+"neque. Nulla sagittis sapien ac risus. Morbi ligula dolor, vestibulum"
+"nec, viverra id, placerat dapibus, arcu. Curabitur egestas feugiat"
+"tellus. Donec dignissim. Nunc ante. Curabitur id lorem. In mollis"
+"tortor sit amet eros auctor dapibus. Proin nulla sem, tristique in,"
+"convallis id, iaculis feugiat cras amet.";
+
+/*
+ * this datatype is for our custom server determination function. this might
+ * be useful if you don't want to rely on simply hashing keys to determine
+ * where a key belongs, but instead want to write something fancy, or use some
+ * other kind of configuration data, i.e. a hash plus some data about a
+ * namespace, or whatever. see my_server_func, and test_redis_user_funcs
+ * for the examples.
+ */
+typedef struct {
+ const char *someval;
+ apr_uint32_t which_server;
+} my_hash_server_baton;
+
+
+/* this could do something fancy and return some hash result.
+ * for simplicity, just return the same value, so we can test it later on.
+ * if you wanted to use some external hashing library or functions for
+ * consistent hashing, for example, this would be a good place to do it.
+ */
+static apr_uint32_t my_hash_func(void *baton, const char *data,
+ apr_size_t data_len)
+{
+
+ return HASH_FUNC_RESULT;
+}
+
+/*
+ * a fancy function to determine which server to use given some kind of data
+ * and a hash value. this example actually ignores the hash value itself
+ * and pulls some number from the *baton, which is a struct that has some
+ * kind of meaningful stuff in it.
+ */
+static apr_redis_server_t *my_server_func(void *baton,
+ apr_redis_t *mc,
+ const apr_uint32_t hash)
+{
+ apr_redis_server_t *ms = NULL;
+ my_hash_server_baton *mhsb = (my_hash_server_baton *)baton;
+
+ if(mc->ntotal == 0) {
+ return NULL;
+ }
+
+ if(mc->ntotal < mhsb->which_server) {
+ return NULL;
+ }
+
+ ms = mc->live_servers[mhsb->which_server - 1];
+
+ return ms;
+}
+
+static apr_uint16_t firsttime = 0;
+static int randval(apr_uint32_t high)
+{
+ apr_uint32_t i = 0;
+ double d = 0;
+
+ if (firsttime == 0) {
+ srand((unsigned) (getpid()));
+ firsttime = 1;
+ }
+
+ d = (double) rand() / ((double) RAND_MAX + 1);
+ i = (int) (d * (high - 0 + 1));
+
+ return i > 0 ? i : 1;
+}
+
+/*
+ * general test to make sure we can create the redis struct and add
+ * some servers, but not more than we tell it we can add
+ */
+
+static void test_redis_create(abts_case * tc, void *data)
+{
+ apr_pool_t *pool = p;
+ apr_status_t rv;
+ apr_redis_t *redis;
+ apr_redis_server_t *server, *s;
+ apr_uint32_t max_servers = 10;
+ apr_uint32_t i;
+ apr_uint32_t hash;
+
+ rv = apr_redis_create(pool, max_servers, 0, &redis);
+ ABTS_ASSERT(tc, "redis create failed", rv == APR_SUCCESS);
+
+ for (i = 1; i <= max_servers; i++) {
+ apr_port_t port;
+
+ port = PORT + i;
+ rv =
+ apr_redis_server_create(pool, HOST, PORT + i, 0, 1, 1, 60, 60, &server);
+ ABTS_ASSERT(tc, "server create failed", rv == APR_SUCCESS);
+
+ rv = apr_redis_add_server(redis, server);
+ ABTS_ASSERT(tc, "server add failed", rv == APR_SUCCESS);
+
+ s = apr_redis_find_server(redis, HOST, port);
+ ABTS_PTR_EQUAL(tc, server, s);
+
+ rv = apr_redis_disable_server(redis, s);
+ ABTS_ASSERT(tc, "server disable failed", rv == APR_SUCCESS);
+
+ rv = apr_redis_enable_server(redis, s);
+ ABTS_ASSERT(tc, "server enable failed", rv == APR_SUCCESS);
+
+ hash = apr_redis_hash(redis, prefix, strlen(prefix));
+ ABTS_ASSERT(tc, "hash failed", hash > 0);
+
+ s = apr_redis_find_server_hash(redis, hash);
+ ABTS_PTR_NOTNULL(tc, s);
+ }
+
+ rv = apr_redis_server_create(pool, HOST, PORT, 0, 1, 1, 60, 60, &server);
+ ABTS_ASSERT(tc, "server create failed", rv == APR_SUCCESS);
+
+ rv = apr_redis_add_server(redis, server);
+ ABTS_ASSERT(tc, "server add should have failed", rv != APR_SUCCESS);
+
+}
+
+/* install our own custom hashing and server selection routines. */
+
+static int create_test_hash(apr_pool_t *p, apr_hash_t *h)
+{
+ int i;
+
+ for (i = 0; i < TDATA_SIZE; i++) {
+ char *k, *v;
+
+ k = apr_pstrcat(p, prefix, apr_itoa(p, i), NULL);
+ v = apr_pstrndup(p, txt, randval((apr_uint32_t)strlen(txt)));
+
+ apr_hash_set(h, k, APR_HASH_KEY_STRING, v);
+ }
+
+ return i;
+}
+
+static void test_redis_user_funcs(abts_case * tc, void *data)
+{
+ apr_pool_t *pool = p;
+ apr_status_t rv;
+ apr_redis_t *redis;
+ apr_redis_server_t *found;
+ apr_uint32_t max_servers = 10;
+ apr_uint32_t hres;
+ apr_uint32_t i;
+ my_hash_server_baton *baton =
+ apr_pcalloc(pool, sizeof(my_hash_server_baton));
+
+ rv = apr_redis_create(pool, max_servers, 0, &redis);
+ ABTS_ASSERT(tc, "redis create failed", rv == APR_SUCCESS);
+
+ /* as noted above, install our custom hash function, and call
+ * apr_redis_hash. the return value should be our predefined number,
+ * and our function just ignores the other args, for simplicity.
+ */
+ redis->hash_func = my_hash_func;
+
+ hres = apr_redis_hash(redis, "whatever", sizeof("whatever") - 1);
+ ABTS_INT_EQUAL(tc, HASH_FUNC_RESULT, hres);
+
+ /* add some servers */
+ for(i = 1; i <= 10; i++) {
+ apr_redis_server_t *ms;
+
+ rv = apr_redis_server_create(pool, HOST, i, 0, 1, 1, 60, 60, &ms);
+ ABTS_ASSERT(tc, "server create failed", rv == APR_SUCCESS);
+
+ rv = apr_redis_add_server(redis, ms);
+ ABTS_ASSERT(tc, "server add failed", rv == APR_SUCCESS);
+ }
+
+ /*
+ * set 'which_server' in our server_baton to find the third server
+ * which should have the same port.
+ */
+ baton->which_server = 3;
+ redis->server_func = my_server_func;
+ redis->server_baton = baton;
+ found = apr_redis_find_server_hash(redis, 0);
+ ABTS_ASSERT(tc, "wrong server found", found->port == baton->which_server);
+}
+
+/* test non data related commands like stats and version */
+static void test_redis_meta(abts_case * tc, void *data)
+{
+ apr_pool_t *pool = p;
+ apr_redis_t *redis;
+ apr_redis_server_t *server;
+ apr_redis_stats_t *stats;
+ char *result;
+ apr_status_t rv;
+
+ rv = apr_redis_create(pool, 1, 0, &redis);
+ ABTS_ASSERT(tc, "redis create failed", rv == APR_SUCCESS);
+
+ rv = apr_redis_server_create(pool, HOST, PORT, 0, 1, 1, 60, 60, &server);
+ ABTS_ASSERT(tc, "server create failed", rv == APR_SUCCESS);
+
+ rv = apr_redis_add_server(redis, server);
+ ABTS_ASSERT(tc, "server add failed", rv == APR_SUCCESS);
+
+ apr_redis_version(server, pool, &result);
+ ABTS_PTR_NOTNULL(tc, result);
+
+ apr_redis_stats(server, p, &stats);
+ ABTS_PTR_NOTNULL(tc, stats);
+
+ /*
+ * no way to know exactly what will be in most of these, so
+ * just make sure there is something.
+ */
+ ABTS_ASSERT(tc, "major", stats->major >= 1);
+ ABTS_ASSERT(tc, "minor", stats->minor >= 0);
+ ABTS_ASSERT(tc, "patch", stats->patch >= 0);
+ ABTS_ASSERT(tc, "process_id", stats->process_id >= 0);
+ ABTS_ASSERT(tc, "uptime_in_seconds", stats->uptime_in_seconds >= 0);
+ ABTS_ASSERT(tc, "arch_bits", stats->arch_bits >= 0);
+ ABTS_ASSERT(tc, "connected_clients", stats->connected_clients >= 0);
+ ABTS_ASSERT(tc, "blocked_clients", stats->blocked_clients >= 0);
+ ABTS_ASSERT(tc, "maxmemory", stats->maxmemory >= 0);
+ ABTS_ASSERT(tc, "used_memory", stats->used_memory >= 0);
+ ABTS_ASSERT(tc, "total_system_memory", stats->total_system_memory >= 0);
+ ABTS_ASSERT(tc, "total_connections_received", stats->total_connections_received >= 0);
+ ABTS_ASSERT(tc, "total_commands_processed", stats->total_commands_processed >= 0);
+ ABTS_ASSERT(tc, "total_net_input_bytes", stats->total_net_input_bytes >= 0);
+ ABTS_ASSERT(tc, "total_net_output_bytes", stats->total_net_output_bytes >= 0);
+ ABTS_ASSERT(tc, "keyspace_hits", stats->keyspace_hits >= 0);
+ ABTS_ASSERT(tc, "keyspace_misses", stats->keyspace_misses >= 0);
+ ABTS_ASSERT(tc, "role", stats->role >= 0);
+ ABTS_ASSERT(tc, "connected_slaves", stats->connected_slaves >= 0);
+ ABTS_ASSERT(tc, "used_cpu_sys", stats->used_cpu_sys >= 0);
+ ABTS_ASSERT(tc, "used_cpu_user", stats->used_cpu_user >= 0);
+ ABTS_ASSERT(tc, "cluster_enabled", stats->cluster_enabled >= 0);
+}
+
+
+/* basic tests of the increment and decrement commands */
+static void test_redis_incrdecr(abts_case * tc, void *data)
+{
+ apr_pool_t *pool = p;
+ apr_status_t rv;
+ apr_redis_t *redis;
+ apr_redis_server_t *server;
+ apr_uint32_t new;
+ char *result;
+ apr_size_t len;
+ apr_uint32_t i;
+
+ rv = apr_redis_create(pool, 1, 0, &redis);
+ ABTS_ASSERT(tc, "redis create failed", rv == APR_SUCCESS);
+
+ rv = apr_redis_server_create(pool, HOST, PORT, 0, 1, 1, 60, 60, &server);
+ ABTS_ASSERT(tc, "server create failed", rv == APR_SUCCESS);
+
+ rv = apr_redis_add_server(redis, server);
+ ABTS_ASSERT(tc, "server add failed", rv == APR_SUCCESS);
+
+ rv = apr_redis_set(redis, prefix, "271", sizeof("271") - 1, 27);
+ ABTS_ASSERT(tc, "set failed", rv == APR_SUCCESS);
+
+ for( i = 1; i <= TDATA_SIZE; i++) {
+ apr_uint32_t expect;
+
+ rv = apr_redis_getp(redis, pool, prefix, &result, &len, NULL);
+ ABTS_ASSERT(tc, "get failed", rv == APR_SUCCESS);
+
+ expect = i + atoi(result);
+
+ rv = apr_redis_incr(redis, prefix, i, &new);
+ ABTS_ASSERT(tc, "incr failed", rv == APR_SUCCESS);
+
+ ABTS_INT_EQUAL(tc, expect, new);
+
+ rv = apr_redis_decr(redis, prefix, i, &new);
+ ABTS_ASSERT(tc, "decr failed", rv == APR_SUCCESS);
+
+ ABTS_INT_EQUAL(tc, atoi(result), new);
+
+ }
+
+ rv = apr_redis_getp(redis, pool, prefix, &result, &len, NULL);
+ ABTS_ASSERT(tc, "get failed", rv == APR_SUCCESS);
+
+ ABTS_INT_EQUAL(tc, 271, atoi(result));
+
+ rv = apr_redis_delete(redis, prefix, 0);
+ ABTS_ASSERT(tc, "delete failed", rv == APR_SUCCESS);
+}
+
+
+/* test setting and getting */
+
+static void test_redis_setget(abts_case * tc, void *data)
+{
+ apr_pool_t *pool = p;
+ apr_status_t rv;
+ apr_redis_t *redis;
+ apr_redis_server_t *server;
+ apr_hash_t *tdata;
+ apr_hash_index_t *hi;
+ char *result;
+ apr_size_t len;
+
+ rv = apr_redis_create(pool, 1, 0, &redis);
+ ABTS_ASSERT(tc, "redis create failed", rv == APR_SUCCESS);
+
+ rv = apr_redis_server_create(pool, HOST, PORT, 0, 1, 1, 60, 60, &server);
+ ABTS_ASSERT(tc, "server create failed", rv == APR_SUCCESS);
+
+ rv = apr_redis_add_server(redis, server);
+ ABTS_ASSERT(tc, "server add failed", rv == APR_SUCCESS);
+
+ tdata = apr_hash_make(pool);
+
+ create_test_hash(pool, tdata);
+
+ for (hi = apr_hash_first(p, tdata); hi; hi = apr_hash_next(hi)) {
+ const void *k;
+ void *v;
+ const char *key;
+
+ apr_hash_this(hi, &k, NULL, &v);
+ key = k;
+
+ rv = apr_redis_set(redis, key, v, strlen(v), 27);
+ ABTS_ASSERT(tc, "set failed", rv == APR_SUCCESS);
+ rv = apr_redis_getp(redis, pool, key, &result, &len, NULL);
+ ABTS_ASSERT(tc, "get failed", rv == APR_SUCCESS);
+ }
+
+ rv = apr_redis_getp(redis, pool, "nothere3423", &result, &len, NULL);
+
+ ABTS_ASSERT(tc, "get should have failed", rv != APR_SUCCESS);
+
+ for (hi = apr_hash_first(p, tdata); hi; hi = apr_hash_next(hi)) {
+ const void *k;
+ const char *key;
+
+ apr_hash_this(hi, &k, NULL, NULL);
+ key = k;
+
+ rv = apr_redis_delete(redis, key, 0);
+ ABTS_ASSERT(tc, "delete failed", rv == APR_SUCCESS);
+ }
+}
+
+/* test setting and getting */
+
+static void test_redis_setexget(abts_case * tc, void *data)
+{
+ apr_pool_t *pool = p;
+ apr_status_t rv;
+ apr_redis_t *redis;
+ apr_redis_server_t *server;
+ apr_hash_t *tdata;
+ apr_hash_index_t *hi;
+ char *result;
+ apr_size_t len;
+
+ rv = apr_redis_create(pool, 1, 0, &redis);
+ ABTS_ASSERT(tc, "redis create failed", rv == APR_SUCCESS);
+
+ rv = apr_redis_server_create(pool, HOST, PORT, 0, 1, 1, 60, 60, &server);
+ ABTS_ASSERT(tc, "server create failed", rv == APR_SUCCESS);
+
+ rv = apr_redis_add_server(redis, server);
+ ABTS_ASSERT(tc, "server add failed", rv == APR_SUCCESS);
+
+ tdata = apr_hash_make(pool);
+
+ create_test_hash(pool, tdata);
+
+ for (hi = apr_hash_first(p, tdata); hi; hi = apr_hash_next(hi)) {
+ const void *k;
+ void *v;
+ const char *key;
+
+ apr_hash_this(hi, &k, NULL, &v);
+ key = k;
+
+ rv = apr_redis_ping(server);
+ ABTS_ASSERT(tc, "ping failed", rv == APR_SUCCESS);
+ rv = apr_redis_setex(redis, key, v, strlen(v), 10, 27);
+ ABTS_ASSERT(tc, "set failed", rv == APR_SUCCESS);
+ rv = apr_redis_getp(redis, pool, key, &result, &len, NULL);
+ ABTS_ASSERT(tc, "get failed", rv == APR_SUCCESS);
+ }
+
+ rv = apr_redis_getp(redis, pool, "nothere3423", &result, &len, NULL);
+
+ ABTS_ASSERT(tc, "get should have failed", rv != APR_SUCCESS);
+
+ for (hi = apr_hash_first(p, tdata); hi; hi = apr_hash_next(hi)) {
+ const void *k;
+ const char *key;
+
+ apr_hash_this(hi, &k, NULL, NULL);
+ key = k;
+
+ rv = apr_redis_delete(redis, key, 0);
+ ABTS_ASSERT(tc, "delete failed", rv == APR_SUCCESS);
+ }
+}
+
+/* use apr_socket stuff to see if there is in fact a Redis server
+ * running on PORT.
+ */
+static apr_status_t check_redis(void)
+{
+ apr_pool_t *pool = p;
+ apr_status_t rv;
+ apr_socket_t *sock = NULL;
+ apr_sockaddr_t *sa;
+ struct iovec vec[2];
+ apr_size_t written;
+ char buf[128];
+ apr_size_t len;
+
+ rv = apr_socket_create(&sock, APR_INET, SOCK_STREAM, 0, pool);
+ if(rv != APR_SUCCESS) {
+ return rv;
+ }
+
+ rv = apr_sockaddr_info_get(&sa, HOST, APR_INET, PORT, 0, pool);
+ if(rv != APR_SUCCESS) {
+ return rv;
+ }
+
+ rv = apr_socket_timeout_set(sock, 1 * APR_USEC_PER_SEC);
+ if (rv != APR_SUCCESS) {
+ return rv;
+ }
+
+ rv = apr_socket_connect(sock, sa);
+ if (rv != APR_SUCCESS) {
+ return rv;
+ }
+
+ rv = apr_socket_timeout_set(sock, -1);
+ if (rv != APR_SUCCESS) {
+ return rv;
+ }
+
+ vec[0].iov_base = "PING";
+ vec[0].iov_len = sizeof("PING") - 1;
+
+ vec[1].iov_base = "\r\n";
+ vec[1].iov_len = sizeof("\r\n") -1;
+
+ rv = apr_socket_sendv(sock, vec, 2, &written);
+ if (rv != APR_SUCCESS) {
+ return rv;
+ }
+
+ len = sizeof(buf);
+ rv = apr_socket_recv(sock, buf, &len);
+ if(rv != APR_SUCCESS) {
+ return rv;
+ }
+ if(strncmp(buf, "+PONG", sizeof("+PONG")-1) != 0) {
+ rv = APR_EGENERAL;
+ }
+
+ apr_socket_close(sock);
+ return rv;
+}
+
+abts_suite *testredis(abts_suite * suite)
+{
+ apr_status_t rv;
+ suite = ADD_SUITE(suite);
+ /* check for a running redis on the typical port before
+ * trying to run the tests. succeed if we don't find one.
+ */
+ rv = check_redis();
+ if (rv == APR_SUCCESS) {
+ abts_run_test(suite, test_redis_create, NULL);
+ abts_run_test(suite, test_redis_user_funcs, NULL);
+ abts_run_test(suite, test_redis_meta, NULL);
+ abts_run_test(suite, test_redis_setget, NULL);
+ abts_run_test(suite, test_redis_setexget, NULL);
+ /* abts_run_test(suite, test_redis_multiget, NULL); */
+ abts_run_test(suite, test_redis_incrdecr, NULL);
+ }
+ else {
+ abts_log_message("Error %d occurred attempting to reach Redis "
+ "on %s:%d. Skipping apr_redis tests...",
+ rv, HOST, PORT);
+ }
+
+ return suite;
+}
diff --git a/test/testreslist.c b/test/testreslist.c
new file mode 100644
index 0000000..eef848f
--- /dev/null
+++ b/test/testreslist.c
@@ -0,0 +1,311 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "apr_general.h"
+#include "apu.h"
+#include "apr_reslist.h"
+#include "apr_thread_pool.h"
+
+#if APR_HAVE_TIME_H
+#include <time.h>
+#endif /* APR_HAVE_TIME_H */
+
+#include "abts.h"
+#include "testutil.h"
+
+#if APR_HAS_THREADS
+
+#define RESLIST_MIN 3
+#define RESLIST_SMAX 10
+#define RESLIST_HMAX 20
+#define RESLIST_TTL APR_TIME_C(35000) /* 35 ms */
+#define CONSUMER_THREADS 25
+#define CONSUMER_ITERATIONS 100
+#define CONSTRUCT_SLEEP_TIME APR_TIME_C(25000) /* 25 ms */
+#define DESTRUCT_SLEEP_TIME APR_TIME_C(10000) /* 10 ms */
+#define WORK_DELAY_SLEEP_TIME APR_TIME_C(15000) /* 15 ms */
+
+typedef struct {
+ apr_interval_time_t sleep_upon_construct;
+ apr_interval_time_t sleep_upon_destruct;
+ int c_count;
+ int d_count;
+} my_parameters_t;
+
+typedef struct {
+ int id;
+} my_resource_t;
+
+/* Linear congruential generator */
+static apr_uint32_t lgc(apr_uint32_t a)
+{
+ apr_uint64_t z = a;
+ z *= 279470273;
+ z %= APR_UINT64_C(4294967291);
+ return (apr_uint32_t)z;
+}
+
+static apr_status_t my_constructor(void **resource, void *params,
+ apr_pool_t *pool)
+{
+ my_resource_t *res;
+ my_parameters_t *my_params = params;
+
+ /* Create some resource */
+ res = apr_palloc(pool, sizeof(*res));
+ res->id = my_params->c_count++;
+
+ /* Sleep for awhile, to simulate construction overhead. */
+ apr_sleep(my_params->sleep_upon_construct);
+
+ /* Set the resource so it can be managed by the reslist */
+ *resource = res;
+ return APR_SUCCESS;
+}
+
+static apr_status_t my_destructor(void *resource, void *params,
+ apr_pool_t *pool)
+{
+ my_resource_t *res = resource;
+ my_parameters_t *my_params = params;
+ res->id = my_params->d_count++;
+
+ apr_sleep(my_params->sleep_upon_destruct);
+
+ return APR_SUCCESS;
+}
+
+typedef struct {
+ int tid;
+ abts_case *tc;
+ apr_reslist_t *reslist;
+ apr_interval_time_t work_delay_sleep;
+} my_thread_info_t;
+
+/* MAX_UINT * .95 = 2**32 * .95 = 4080218931u */
+#define PERCENT95th 4080218931u
+
+static void * APR_THREAD_FUNC resource_consuming_thread(apr_thread_t *thd,
+ void *data)
+{
+ int i;
+ apr_uint32_t chance;
+ void *vp;
+ apr_status_t rv;
+ my_resource_t *res;
+ my_thread_info_t *thread_info = data;
+ apr_reslist_t *rl = thread_info->reslist;
+
+#if APR_HAS_RANDOM
+ apr_generate_random_bytes((void*)&chance, sizeof(chance));
+#else
+ chance = (apr_uint32_t)(apr_time_now() % APR_TIME_C(4294967291));
+#endif
+
+ for (i = 0; i < CONSUMER_ITERATIONS; i++) {
+ rv = apr_reslist_acquire(rl, &vp);
+ ABTS_INT_EQUAL(thread_info->tc, APR_SUCCESS, rv);
+ res = vp;
+ apr_sleep(thread_info->work_delay_sleep);
+
+ /* simulate a 5% chance of the resource being bad */
+ chance = lgc(chance);
+ if ( chance < PERCENT95th ) {
+ rv = apr_reslist_release(rl, res);
+ ABTS_INT_EQUAL(thread_info->tc, APR_SUCCESS, rv);
+ } else {
+ rv = apr_reslist_invalidate(rl, res);
+ ABTS_INT_EQUAL(thread_info->tc, APR_SUCCESS, rv);
+ }
+ }
+
+ return APR_SUCCESS;
+}
+
+static void test_timeout(abts_case *tc, apr_reslist_t *rl)
+{
+ apr_status_t rv;
+ my_resource_t *resources[RESLIST_HMAX];
+ void *vp;
+ int i;
+
+ apr_reslist_timeout_set(rl, 1000);
+
+ /* deplete all possible resources from the resource list
+ * so that the next call will block until timeout is reached
+ * (since there are no other threads to make a resource
+ * available)
+ */
+
+ for (i = 0; i < RESLIST_HMAX; i++) {
+ rv = apr_reslist_acquire(rl, (void**)&resources[i]);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+ }
+
+ /* next call will block until timeout is reached */
+ rv = apr_reslist_acquire(rl, &vp);
+ ABTS_TRUE(tc, APR_STATUS_IS_TIMEUP(rv));
+
+ /* release the resources; otherwise the destroy operation
+ * will blow
+ */
+ for (i = 0; i < RESLIST_HMAX; i++) {
+ rv = apr_reslist_release(rl, resources[i]);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+ }
+}
+
+static void test_shrinking(abts_case *tc, apr_reslist_t *rl)
+{
+ apr_status_t rv;
+ my_resource_t *resources[RESLIST_HMAX];
+ my_resource_t *res;
+ void *vp;
+ int i;
+ int sleep_time = RESLIST_TTL / RESLIST_HMAX;
+
+ /* deplete all possible resources from the resource list */
+ for (i = 0; i < RESLIST_HMAX; i++) {
+ rv = apr_reslist_acquire(rl, (void**)&resources[i]);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+ }
+
+ /* Free all resources above RESLIST_SMAX - 1 */
+ for (i = RESLIST_SMAX - 1; i < RESLIST_HMAX; i++) {
+ rv = apr_reslist_release(rl, resources[i]);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+ }
+
+ for (i = 0; i < RESLIST_HMAX; i++) {
+ rv = apr_reslist_acquire(rl, &vp);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+ res = vp;
+ apr_sleep(sleep_time);
+ rv = apr_reslist_release(rl, res);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+ }
+ apr_sleep(sleep_time);
+
+ /*
+ * Now free the remaining elements. This should trigger the shrinking of
+ * the list
+ */
+ for (i = 0; i < RESLIST_SMAX - 1; i++) {
+ rv = apr_reslist_release(rl, resources[i]);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+ }
+}
+
+static void test_reslist(abts_case *tc, void *data)
+{
+ int i;
+ apr_status_t rv;
+ apr_reslist_t *rl;
+ my_parameters_t *params;
+ apr_thread_pool_t *thrp;
+ my_thread_info_t thread_info[CONSUMER_THREADS];
+
+ rv = apr_thread_pool_create(&thrp, CONSUMER_THREADS/2, CONSUMER_THREADS, p);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+
+ /* Create some parameters that will be passed into each
+ * constructor and destructor call. */
+ params = apr_pcalloc(p, sizeof(*params));
+ params->sleep_upon_construct = CONSTRUCT_SLEEP_TIME;
+ params->sleep_upon_destruct = DESTRUCT_SLEEP_TIME;
+
+ /* We're going to want 10 blocks of data from our target rmm. */
+ rv = apr_reslist_create(&rl, RESLIST_MIN, RESLIST_SMAX, RESLIST_HMAX,
+ RESLIST_TTL, my_constructor, my_destructor,
+ params, p);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+
+ for (i = 0; i < CONSUMER_THREADS; i++) {
+ thread_info[i].tid = i;
+ thread_info[i].tc = tc;
+ thread_info[i].reslist = rl;
+ thread_info[i].work_delay_sleep = WORK_DELAY_SLEEP_TIME;
+ rv = apr_thread_pool_push(thrp, resource_consuming_thread,
+ &thread_info[i], 0, NULL);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+ }
+
+ rv = apr_thread_pool_destroy(thrp);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+
+ test_timeout(tc, rl);
+
+ test_shrinking(tc, rl);
+ ABTS_INT_EQUAL(tc, RESLIST_SMAX, params->c_count - params->d_count);
+
+ rv = apr_reslist_destroy(rl);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+}
+
+static void test_reslist_no_ttl(abts_case *tc, void *data)
+{
+ apr_status_t rv;
+ apr_reslist_t *rl;
+ my_parameters_t *params;
+ my_resource_t *res;
+
+ /* Parameters (sleep not used) */
+ params = apr_pcalloc(p, sizeof(*params));
+
+ rv = apr_reslist_create(&rl,
+ /*no min*/0, /*no smax*/0, /*max*/1, /*no ttl*/0,
+ my_constructor, my_destructor, params, p);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+
+ /* Acquire/contruct one resource */
+ rv = apr_reslist_acquire(rl, (void **)&res);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+ ABTS_INT_EQUAL(tc, 0, res->id);
+
+ /* Release it before next check */
+ rv = apr_reslist_release(rl, res);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+
+ /* Re-acquire/release: the resource should be the same */
+ rv = apr_reslist_acquire(rl, (void **)&res);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+ ABTS_INT_EQUAL(tc, 0, res->id);
+
+ /* Release it before cleanup */
+ rv = apr_reslist_release(rl, res);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+
+ rv = apr_reslist_destroy(rl);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+ ABTS_INT_EQUAL(tc, params->d_count, 1);
+}
+
+#endif /* APR_HAS_THREADS */
+
+abts_suite *testreslist(abts_suite *suite)
+{
+ suite = ADD_SUITE(suite);
+
+#if APR_HAS_THREADS
+ abts_run_test(suite, test_reslist, NULL);
+ abts_run_test(suite, test_reslist_no_ttl, NULL);
+#endif
+
+ return suite;
+}
diff --git a/test/testrmm.c b/test/testrmm.c
new file mode 100644
index 0000000..4f8fb5e
--- /dev/null
+++ b/test/testrmm.c
@@ -0,0 +1,191 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "apr_shm.h"
+#include "apr_rmm.h"
+#include "apr_errno.h"
+#include "apr_general.h"
+#include "apr_lib.h"
+#include "apr_strings.h"
+#include "apr_time.h"
+#include "abts.h"
+#include "testutil.h"
+
+#if APR_HAS_SHARED_MEMORY
+
+#define FRAG_SIZE 80
+#define FRAG_COUNT 10
+#define SHARED_SIZE (apr_size_t)(FRAG_SIZE * FRAG_COUNT * sizeof(char*))
+
+static void test_rmm(abts_case *tc, void *data)
+{
+ apr_status_t rv;
+ apr_pool_t *pool;
+ apr_shm_t *shm;
+ apr_rmm_t *rmm;
+ apr_size_t size, fragsize;
+ apr_rmm_off_t *off, off2;
+ int i;
+ void *entity;
+
+ rv = apr_pool_create(&pool, p);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+
+ /* We're going to want 10 blocks of data from our target rmm. */
+ size = SHARED_SIZE + apr_rmm_overhead_get(FRAG_COUNT + 1);
+ rv = apr_shm_create(&shm, size, NULL, pool);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+
+ if (rv != APR_SUCCESS)
+ return;
+
+ rv = apr_rmm_init(&rmm, NULL, apr_shm_baseaddr_get(shm), size, pool);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+
+ if (rv != APR_SUCCESS)
+ return;
+
+ /* Creating each fragment of size fragsize */
+ fragsize = SHARED_SIZE / FRAG_COUNT;
+ off = apr_palloc(pool, FRAG_COUNT * sizeof(apr_rmm_off_t));
+ for (i = 0; i < FRAG_COUNT; i++) {
+ off[i] = apr_rmm_malloc(rmm, fragsize);
+ }
+
+ /* Checking for out of memory allocation */
+ off2 = apr_rmm_malloc(rmm, FRAG_SIZE * FRAG_COUNT);
+ ABTS_TRUE(tc, !off2);
+
+ /* Checking each fragment for address alignment */
+ for (i = 0; i < FRAG_COUNT; i++) {
+ char *c = apr_rmm_addr_get(rmm, off[i]);
+ apr_size_t sc = (apr_size_t)c;
+
+ ABTS_TRUE(tc, !!off[i]);
+ ABTS_TRUE(tc, !(sc & 7));
+ }
+
+ /* Setting each fragment to a unique value */
+ for (i = 0; i < FRAG_COUNT; i++) {
+ int j;
+ char **c = apr_rmm_addr_get(rmm, off[i]);
+ for (j = 0; j < FRAG_SIZE; j++, c++) {
+ *c = apr_itoa(pool, i + j);
+ }
+ }
+
+ /* Checking each fragment for its unique value */
+ for (i = 0; i < FRAG_COUNT; i++) {
+ int j;
+ char **c = apr_rmm_addr_get(rmm, off[i]);
+ for (j = 0; j < FRAG_SIZE; j++, c++) {
+ char *d = apr_itoa(pool, i + j);
+ ABTS_STR_EQUAL(tc, d, *c);
+ }
+ }
+
+ /* Freeing each fragment */
+ for (i = 0; i < FRAG_COUNT; i++) {
+ rv = apr_rmm_free(rmm, off[i]);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+ }
+
+ /* Creating one large segment */
+ off[0] = apr_rmm_calloc(rmm, SHARED_SIZE);
+
+ /* Setting large segment */
+ for (i = 0; i < FRAG_COUNT * FRAG_SIZE; i++) {
+ char **c = apr_rmm_addr_get(rmm, off[0]);
+ c[i] = apr_itoa(pool, i);
+ }
+
+ /* Freeing large segment */
+ rv = apr_rmm_free(rmm, off[0]);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+
+ /* Creating each fragment of size fragsize */
+ for (i = 0; i < FRAG_COUNT; i++) {
+ off[i] = apr_rmm_malloc(rmm, fragsize);
+ }
+
+ /* Freeing each fragment backwards */
+ for (i = FRAG_COUNT - 1; i >= 0; i--) {
+ rv = apr_rmm_free(rmm, off[i]);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+ }
+
+ /* Creating one large segment (again) */
+ off[0] = apr_rmm_calloc(rmm, SHARED_SIZE);
+
+ /* Freeing large segment */
+ rv = apr_rmm_free(rmm, off[0]);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+
+ /* Checking realloc */
+ off[0] = apr_rmm_calloc(rmm, SHARED_SIZE - 100);
+ off[1] = apr_rmm_calloc(rmm, 100);
+ ABTS_TRUE(tc, !!off[0]);
+ ABTS_TRUE(tc, !!off[1]);
+
+ entity = apr_rmm_addr_get(rmm, off[1]);
+ rv = apr_rmm_free(rmm, off[0]);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+
+ {
+ unsigned char *c = entity;
+
+ /* Fill in the region; the first half with zereos, which will
+ * likely catch the apr_rmm_realloc offset calculation bug by
+ * making it think the old region was zero length. */
+ for (i = 0; i < 100; i++) {
+ c[i] = (i < 50) ? 0 : i;
+ }
+ }
+
+ /* now we can realloc off[1] and get many more bytes */
+ off[0] = apr_rmm_realloc(rmm, entity, SHARED_SIZE - 100);
+ ABTS_TRUE(tc, !!off[0]);
+
+ {
+ unsigned char *c = apr_rmm_addr_get(rmm, off[0]);
+
+ /* fill in the region */
+ for (i = 0; i < 100; i++) {
+ ABTS_TRUE(tc, c[i] == (i < 50 ? 0 : i));
+ }
+ }
+
+ rv = apr_rmm_destroy(rmm);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+
+ rv = apr_shm_destroy(shm);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+
+ apr_pool_destroy(pool);
+}
+
+#endif /* APR_HAS_SHARED_MEMORY */
+
+abts_suite *testrmm(abts_suite *suite)
+{
+ suite = ADD_SUITE(suite);
+
+#if APR_HAS_SHARED_MEMORY
+ abts_run_test(suite, test_rmm, NULL);
+#endif
+
+ return suite;
+}
diff --git a/test/testsiphash.c b/test/testsiphash.c
new file mode 100644
index 0000000..58321ad
--- /dev/null
+++ b/test/testsiphash.c
@@ -0,0 +1,148 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "apr_siphash.h"
+
+#include "abts.h"
+#include "testutil.h"
+
+/*
+ * Wrapped test vectors from the authors, see
+ * https://131002.net/siphash/siphash24.c
+ */
+typedef unsigned char u8;
+#define crypto_auth apr_siphash24_auth
+
+#define MAXLEN 64
+
+/*
+ SipHash-2-4 output with
+ k = 00 01 02 ...
+ and
+ in = (empty string)
+ in = 00 (1 byte)
+ in = 00 01 (2 bytes)
+ in = 00 01 02 (3 bytes)
+ ...
+ in = 00 01 02 ... 3e (63 bytes)
+*/
+static const u8 vectors[MAXLEN][8] =
+{
+ { 0x31, 0x0e, 0x0e, 0xdd, 0x47, 0xdb, 0x6f, 0x72, },
+ { 0xfd, 0x67, 0xdc, 0x93, 0xc5, 0x39, 0xf8, 0x74, },
+ { 0x5a, 0x4f, 0xa9, 0xd9, 0x09, 0x80, 0x6c, 0x0d, },
+ { 0x2d, 0x7e, 0xfb, 0xd7, 0x96, 0x66, 0x67, 0x85, },
+ { 0xb7, 0x87, 0x71, 0x27, 0xe0, 0x94, 0x27, 0xcf, },
+ { 0x8d, 0xa6, 0x99, 0xcd, 0x64, 0x55, 0x76, 0x18, },
+ { 0xce, 0xe3, 0xfe, 0x58, 0x6e, 0x46, 0xc9, 0xcb, },
+ { 0x37, 0xd1, 0x01, 0x8b, 0xf5, 0x00, 0x02, 0xab, },
+ { 0x62, 0x24, 0x93, 0x9a, 0x79, 0xf5, 0xf5, 0x93, },
+ { 0xb0, 0xe4, 0xa9, 0x0b, 0xdf, 0x82, 0x00, 0x9e, },
+ { 0xf3, 0xb9, 0xdd, 0x94, 0xc5, 0xbb, 0x5d, 0x7a, },
+ { 0xa7, 0xad, 0x6b, 0x22, 0x46, 0x2f, 0xb3, 0xf4, },
+ { 0xfb, 0xe5, 0x0e, 0x86, 0xbc, 0x8f, 0x1e, 0x75, },
+ { 0x90, 0x3d, 0x84, 0xc0, 0x27, 0x56, 0xea, 0x14, },
+ { 0xee, 0xf2, 0x7a, 0x8e, 0x90, 0xca, 0x23, 0xf7, },
+ { 0xe5, 0x45, 0xbe, 0x49, 0x61, 0xca, 0x29, 0xa1, },
+ { 0xdb, 0x9b, 0xc2, 0x57, 0x7f, 0xcc, 0x2a, 0x3f, },
+ { 0x94, 0x47, 0xbe, 0x2c, 0xf5, 0xe9, 0x9a, 0x69, },
+ { 0x9c, 0xd3, 0x8d, 0x96, 0xf0, 0xb3, 0xc1, 0x4b, },
+ { 0xbd, 0x61, 0x79, 0xa7, 0x1d, 0xc9, 0x6d, 0xbb, },
+ { 0x98, 0xee, 0xa2, 0x1a, 0xf2, 0x5c, 0xd6, 0xbe, },
+ { 0xc7, 0x67, 0x3b, 0x2e, 0xb0, 0xcb, 0xf2, 0xd0, },
+ { 0x88, 0x3e, 0xa3, 0xe3, 0x95, 0x67, 0x53, 0x93, },
+ { 0xc8, 0xce, 0x5c, 0xcd, 0x8c, 0x03, 0x0c, 0xa8, },
+ { 0x94, 0xaf, 0x49, 0xf6, 0xc6, 0x50, 0xad, 0xb8, },
+ { 0xea, 0xb8, 0x85, 0x8a, 0xde, 0x92, 0xe1, 0xbc, },
+ { 0xf3, 0x15, 0xbb, 0x5b, 0xb8, 0x35, 0xd8, 0x17, },
+ { 0xad, 0xcf, 0x6b, 0x07, 0x63, 0x61, 0x2e, 0x2f, },
+ { 0xa5, 0xc9, 0x1d, 0xa7, 0xac, 0xaa, 0x4d, 0xde, },
+ { 0x71, 0x65, 0x95, 0x87, 0x66, 0x50, 0xa2, 0xa6, },
+ { 0x28, 0xef, 0x49, 0x5c, 0x53, 0xa3, 0x87, 0xad, },
+ { 0x42, 0xc3, 0x41, 0xd8, 0xfa, 0x92, 0xd8, 0x32, },
+ { 0xce, 0x7c, 0xf2, 0x72, 0x2f, 0x51, 0x27, 0x71, },
+ { 0xe3, 0x78, 0x59, 0xf9, 0x46, 0x23, 0xf3, 0xa7, },
+ { 0x38, 0x12, 0x05, 0xbb, 0x1a, 0xb0, 0xe0, 0x12, },
+ { 0xae, 0x97, 0xa1, 0x0f, 0xd4, 0x34, 0xe0, 0x15, },
+ { 0xb4, 0xa3, 0x15, 0x08, 0xbe, 0xff, 0x4d, 0x31, },
+ { 0x81, 0x39, 0x62, 0x29, 0xf0, 0x90, 0x79, 0x02, },
+ { 0x4d, 0x0c, 0xf4, 0x9e, 0xe5, 0xd4, 0xdc, 0xca, },
+ { 0x5c, 0x73, 0x33, 0x6a, 0x76, 0xd8, 0xbf, 0x9a, },
+ { 0xd0, 0xa7, 0x04, 0x53, 0x6b, 0xa9, 0x3e, 0x0e, },
+ { 0x92, 0x59, 0x58, 0xfc, 0xd6, 0x42, 0x0c, 0xad, },
+ { 0xa9, 0x15, 0xc2, 0x9b, 0xc8, 0x06, 0x73, 0x18, },
+ { 0x95, 0x2b, 0x79, 0xf3, 0xbc, 0x0a, 0xa6, 0xd4, },
+ { 0xf2, 0x1d, 0xf2, 0xe4, 0x1d, 0x45, 0x35, 0xf9, },
+ { 0x87, 0x57, 0x75, 0x19, 0x04, 0x8f, 0x53, 0xa9, },
+ { 0x10, 0xa5, 0x6c, 0xf5, 0xdf, 0xcd, 0x9a, 0xdb, },
+ { 0xeb, 0x75, 0x09, 0x5c, 0xcd, 0x98, 0x6c, 0xd0, },
+ { 0x51, 0xa9, 0xcb, 0x9e, 0xcb, 0xa3, 0x12, 0xe6, },
+ { 0x96, 0xaf, 0xad, 0xfc, 0x2c, 0xe6, 0x66, 0xc7, },
+ { 0x72, 0xfe, 0x52, 0x97, 0x5a, 0x43, 0x64, 0xee, },
+ { 0x5a, 0x16, 0x45, 0xb2, 0x76, 0xd5, 0x92, 0xa1, },
+ { 0xb2, 0x74, 0xcb, 0x8e, 0xbf, 0x87, 0x87, 0x0a, },
+ { 0x6f, 0x9b, 0xb4, 0x20, 0x3d, 0xe7, 0xb3, 0x81, },
+ { 0xea, 0xec, 0xb2, 0xa3, 0x0b, 0x22, 0xa8, 0x7f, },
+ { 0x99, 0x24, 0xa4, 0x3c, 0xc1, 0x31, 0x57, 0x24, },
+ { 0xbd, 0x83, 0x8d, 0x3a, 0xaf, 0xbf, 0x8d, 0xb7, },
+ { 0x0b, 0x1a, 0x2a, 0x32, 0x65, 0xd5, 0x1a, 0xea, },
+ { 0x13, 0x50, 0x79, 0xa3, 0x23, 0x1c, 0xe6, 0x60, },
+ { 0x93, 0x2b, 0x28, 0x46, 0xe4, 0xd7, 0x06, 0x66, },
+ { 0xe1, 0x91, 0x5f, 0x5c, 0xb1, 0xec, 0xa4, 0x6c, },
+ { 0xf3, 0x25, 0x96, 0x5c, 0xa1, 0x6d, 0x62, 0x9f, },
+ { 0x57, 0x5f, 0xf2, 0x8e, 0x60, 0x38, 0x1b, 0xe5, },
+ { 0x72, 0x45, 0x06, 0xeb, 0x4c, 0x32, 0x8a, 0x95, }
+};
+
+static int test_vectors(void)
+{
+ u8 in[MAXLEN], out[8], k[16];
+ int i;
+ int ok = 1;
+
+ for( i = 0; i < 16; ++i ) k[i] = i;
+
+ for( i = 0; i < MAXLEN; ++i )
+ {
+ in[i] = i;
+ crypto_auth( out, in, i, k );
+
+ if ( memcmp( out, vectors[i], 8 ) )
+ {
+ printf( "test vector failed for %d bytes\n", i );
+ ok = 0;
+ }
+ }
+
+ return ok;
+}
+
+static void test_siphash_vectors(abts_case *tc, void *data)
+{
+ ABTS_ASSERT(tc, "SipHash-2-4 test vectors", test_vectors());
+}
+
+abts_suite *testsiphash(abts_suite *suite)
+{
+ suite = ADD_SUITE(suite);
+
+ abts_run_test(suite, test_siphash_vectors, NULL);
+
+ return suite;
+}
diff --git a/test/teststrmatch.c b/test/teststrmatch.c
new file mode 100644
index 0000000..b6a4a12
--- /dev/null
+++ b/test/teststrmatch.c
@@ -0,0 +1,92 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "testutil.h"
+
+#include "apr.h"
+#include "apr_general.h"
+#include "apr_strmatch.h"
+#if APR_HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#define APR_WANT_STDIO
+#define APR_WANT_STRFUNC
+#include "apr_want.h"
+
+static void test_str(abts_case *tc, void *data)
+{
+ apr_pool_t *pool = p;
+ const apr_strmatch_pattern *pattern;
+ const apr_strmatch_pattern *pattern_nocase;
+ const apr_strmatch_pattern *pattern_onechar;
+ const apr_strmatch_pattern *pattern_zero;
+ const char *match = NULL;
+ const char *input1 = "string that contains a patterN...";
+ const char *input2 = "string that contains a pattern...";
+ const char *input3 = "pattern at the start of a string";
+ const char *input4 = "string that ends with a pattern";
+ const char *input5 = "patter\200n not found, negative chars in input";
+ const char *input6 = "patter\200n, negative chars, contains pattern...";
+
+ pattern = apr_strmatch_precompile(pool, "pattern", 1);
+ ABTS_PTR_NOTNULL(tc, pattern);
+
+ pattern_nocase = apr_strmatch_precompile(pool, "pattern", 0);
+ ABTS_PTR_NOTNULL(tc, pattern_nocase);
+
+ pattern_onechar = apr_strmatch_precompile(pool, "g", 0);
+ ABTS_PTR_NOTNULL(tc, pattern_onechar);
+
+ pattern_zero = apr_strmatch_precompile(pool, "", 0);
+ ABTS_PTR_NOTNULL(tc, pattern_zero);
+
+ match = apr_strmatch(pattern, input1, strlen(input1));
+ ABTS_PTR_EQUAL(tc, NULL, match);
+
+ match = apr_strmatch(pattern, input2, strlen(input2));
+ ABTS_PTR_EQUAL(tc, input2 + 23, match);
+
+ match = apr_strmatch(pattern_onechar, input1, strlen(input1));
+ ABTS_PTR_EQUAL(tc, input1 + 5, match);
+
+ match = apr_strmatch(pattern_zero, input1, strlen(input1));
+ ABTS_PTR_EQUAL(tc, input1, match);
+
+ match = apr_strmatch(pattern_nocase, input1, strlen(input1));
+ ABTS_PTR_EQUAL(tc, input1 + 23, match);
+
+ match = apr_strmatch(pattern, input3, strlen(input3));
+ ABTS_PTR_EQUAL(tc, input3, match);
+
+ match = apr_strmatch(pattern, input4, strlen(input4));
+ ABTS_PTR_EQUAL(tc, input4 + 24, match);
+
+ match = apr_strmatch(pattern, input5, strlen(input5));
+ ABTS_PTR_EQUAL(tc, NULL, match);
+
+ match = apr_strmatch(pattern, input6, strlen(input6));
+ ABTS_PTR_EQUAL(tc, input6 + 35, match);
+}
+
+abts_suite *teststrmatch(abts_suite *suite)
+{
+ suite = ADD_SUITE(suite);
+
+ abts_run_test(suite, test_str, NULL);
+
+ return suite;
+}
+
diff --git a/test/testuri.c b/test/testuri.c
new file mode 100644
index 0000000..4c5405a
--- /dev/null
+++ b/test/testuri.c
@@ -0,0 +1,331 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "testutil.h"
+#include "apr_general.h"
+#include "apr_strings.h"
+#include "apr_uri.h"
+
+struct aup_test {
+ const char *uri;
+ apr_status_t rv;
+ const char *scheme;
+ const char *hostinfo;
+ const char *user;
+ const char *password;
+ const char *hostname;
+ const char *port_str;
+ const char *path;
+ const char *query;
+ const char *fragment;
+ apr_port_t port;
+};
+
+struct aup_test aup_tests[] =
+{
+ { "http://[/::1]/index.html", APR_EGENERAL },
+ { "http://[", APR_EGENERAL },
+ { "http://[?::1]/index.html", APR_EGENERAL },
+
+ {
+ "http://127.0.0.1:9999/asdf.html",
+ 0, "http", "127.0.0.1:9999", NULL, NULL, "127.0.0.1", "9999", "/asdf.html", NULL, NULL, 9999
+ },
+ {
+ "http://127.0.0.1:9999a/asdf.html",
+ APR_EGENERAL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0
+ },
+ {
+ "http://[::127.0.0.1]:9999/asdf.html",
+ 0, "http", "[::127.0.0.1]:9999", NULL, NULL, "::127.0.0.1", "9999", "/asdf.html", NULL, NULL, 9999
+ },
+ {
+ "http://[::127.0.0.1]:9999a/asdf.html",
+ APR_EGENERAL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0
+ },
+ {
+ "/error/include/top.html",
+ 0, NULL, NULL, NULL, NULL, NULL, NULL, "/error/include/top.html", NULL, NULL, 0
+ },
+ {
+ "/error/include/../contact.html.var",
+ 0, NULL, NULL, NULL, NULL, NULL, NULL, "/error/include/../contact.html.var", NULL, NULL, 0
+ },
+ {
+ "/",
+ 0, NULL, NULL, NULL, NULL, NULL, NULL, "/", NULL, NULL, 0
+ },
+ {
+ "/manual/",
+ 0, NULL, NULL, NULL, NULL, NULL, NULL, "/manual/", NULL, NULL, 0
+ },
+ {
+ "/cocoon/developing/graphics/Using%20Databases-label_over.jpg",
+ 0, NULL, NULL, NULL, NULL, NULL, NULL, "/cocoon/developing/graphics/Using%20Databases-label_over.jpg", NULL, NULL, 0
+ },
+ {
+ "http://sonyamt:garbage@127.0.0.1/filespace/",
+ 0, "http", "sonyamt:garbage@127.0.0.1", "sonyamt", "garbage", "127.0.0.1", NULL, "/filespace/", NULL, NULL, 0
+ },
+ {
+ "http://sonyamt:garbage@[fe80::1]/filespace/",
+ 0, "http", "sonyamt:garbage@[fe80::1]", "sonyamt", "garbage", "fe80::1", NULL, "/filespace/", NULL, NULL, 0
+ },
+ {
+ "http://sonyamt@[fe80::1]/filespace/?arg1=store",
+ 0, "http", "sonyamt@[fe80::1]", "sonyamt", NULL, "fe80::1", NULL, "/filespace/", "arg1=store", NULL, 0
+ },
+ {
+ "http://localhost",
+ 0, "http", "localhost", NULL, NULL, "localhost", NULL, NULL, NULL, NULL, 0
+ },
+ {
+ "//www.apache.org/",
+ 0, NULL, "www.apache.org", NULL, NULL, "www.apache.org", NULL, "/", NULL, NULL, 0
+ },
+ {
+ "file:image.jpg",
+ 0, "file", NULL, NULL, NULL, NULL, NULL, "image.jpg", NULL, NULL, 0
+ },
+ {
+ "file:/image.jpg",
+ 0, "file", NULL, NULL, NULL, NULL, NULL, "/image.jpg", NULL, NULL, 0
+ },
+ {
+ "file:///image.jpg",
+ 0, "file", "", NULL, NULL, "", NULL, "/image.jpg", NULL, NULL, 0
+ },
+ {
+ "file:///tmp/photos/image.jpg",
+ 0, "file", "", NULL, NULL, "", NULL, "/tmp/photos/image.jpg", NULL, NULL, 0
+ },
+ {
+ "file:./image.jpg",
+ 0, "file", NULL, NULL, NULL, NULL, NULL, "./image.jpg", NULL, NULL, 0
+ },
+ {
+ "file:../photos/image.jpg",
+ 0, "file", NULL, NULL, NULL, NULL, NULL, "../photos/image.jpg", NULL, NULL, 0
+ },
+ {
+ "file+ssh-2:../photos/image.jpg",
+ 0, "file+ssh-2", NULL, NULL, NULL, NULL, NULL, "../photos/image.jpg", NULL, NULL, 0
+ },
+ {
+ "script/foo.js",
+ 0, NULL, NULL, NULL, NULL, NULL, NULL, "script/foo.js", NULL, NULL, 0
+ },
+ {
+ "../foo2.js",
+ 0, NULL, NULL, NULL, NULL, NULL, NULL, "../foo2.js", NULL, NULL, 0
+ },
+ {
+ "foo3.js",
+ 0, NULL, NULL, NULL, NULL, NULL, NULL, "foo3.js", NULL, NULL, 0
+ },
+ {
+ "_foo/bar",
+ 0, NULL, NULL, NULL, NULL, NULL, NULL, "_foo/bar", NULL, NULL, 0
+ },
+ {
+ "_foo:/bar",
+ APR_EGENERAL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0
+ },
+ {
+ "2foo:/bar",
+ APR_EGENERAL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0
+ },
+ {
+ ".foo:/bar",
+ APR_EGENERAL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0
+ },
+ {
+ "-foo:/bar",
+ APR_EGENERAL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0
+ },
+ {
+ "+foo:/bar",
+ APR_EGENERAL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0
+ },
+ {
+ "::/bar",
+ APR_EGENERAL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0
+ },
+ {
+ ":/bar",
+ APR_EGENERAL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0
+ },
+ {
+ ":foo",
+ APR_EGENERAL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0
+ },
+ {
+ ":",
+ APR_EGENERAL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0
+ },
+ {
+ "@localhost::8080",
+ APR_EGENERAL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0
+ },
+};
+
+struct uph_test {
+ const char *hostinfo;
+ apr_status_t rv;
+ const char *hostname;
+ const char *port_str;
+ apr_port_t port;
+};
+
+struct uph_test uph_tests[] =
+{
+ {
+ "www.ibm.com:443",
+ 0, "www.ibm.com", "443", 443
+ },
+ {
+ "[fe80::1]:443",
+ 0, "fe80::1", "443", 443
+ },
+ {
+ "127.0.0.1:443",
+ 0, "127.0.0.1", "443", 443
+ },
+ {
+ "127.0.0.1",
+ APR_EGENERAL, NULL, NULL, 0
+ },
+ {
+ "[fe80:80",
+ APR_EGENERAL, NULL, NULL, 0
+ },
+ {
+ "fe80::80]:443",
+ APR_EGENERAL, NULL, NULL, 0
+ }
+};
+
+#if 0
+static void show_info(apr_status_t rv, apr_status_t expected, const apr_uri_t *info)
+{
+ if (rv != expected) {
+ fprintf(stderr, " actual rv: %d expected rv: %d\n", rv, expected);
+ }
+ else {
+ fprintf(stderr,
+ " scheme: %s\n"
+ " hostinfo: %s\n"
+ " user: %s\n"
+ " password: %s\n"
+ " hostname: %s\n"
+ " port_str: %s\n"
+ " path: %s\n"
+ " query: %s\n"
+ " fragment: %s\n"
+ " hostent: %p\n"
+ " port: %u\n"
+ " is_initialized: %u\n"
+ " dns_looked_up: %u\n"
+ " dns_resolved: %u\n",
+ info->scheme, info->hostinfo, info->user, info->password,
+ info->hostname, info->port_str, info->path, info->query,
+ info->fragment, info->hostent, info->port, info->is_initialized,
+ info->dns_looked_up, info->dns_resolved);
+ }
+}
+#endif
+
+static void test_aup(abts_case *tc, void *data)
+{
+ int i;
+ apr_status_t rv;
+ apr_uri_t info;
+ struct aup_test *t;
+ const char *s = NULL;
+
+ for (i = 0; i < sizeof(aup_tests) / sizeof(aup_tests[0]); i++) {
+ char msg[256];
+
+ memset(&info, 0, sizeof(info));
+ t = &aup_tests[i];
+ rv = apr_uri_parse(p, t->uri, &info);
+ apr_snprintf(msg, sizeof msg, "uri '%s': rv=%d not %d", t->uri,
+ rv, t->rv);
+ ABTS_ASSERT(tc, msg, rv == t->rv);
+ if (t->rv == APR_SUCCESS) {
+ ABTS_STR_EQUAL(tc, t->scheme, info.scheme);
+ ABTS_STR_EQUAL(tc, t->hostinfo, info.hostinfo);
+ ABTS_STR_EQUAL(tc, t->user, info.user);
+ ABTS_STR_EQUAL(tc, t->password, info.password);
+ ABTS_STR_EQUAL(tc, t->hostname, info.hostname);
+ ABTS_STR_EQUAL(tc, t->port_str, info.port_str);
+ ABTS_STR_EQUAL(tc, t->path, info.path);
+ ABTS_STR_EQUAL(tc, t->query, info.query);
+ ABTS_STR_EQUAL(tc, t->user, info.user);
+ ABTS_INT_EQUAL(tc, t->port, info.port);
+
+ s = apr_uri_unparse(p, &info, APR_URI_UNP_REVEALPASSWORD);
+ ABTS_STR_EQUAL(tc, t->uri, s);
+
+ s = apr_uri_unparse(p, &info, APR_URI_UNP_OMITSITEPART);
+ apr_uri_parse(p, s, &info);
+ ABTS_STR_EQUAL(tc, info.scheme, NULL);
+ ABTS_STR_EQUAL(tc, info.hostinfo, NULL);
+ ABTS_STR_EQUAL(tc, info.user, NULL);
+ ABTS_STR_EQUAL(tc, info.password, NULL);
+ ABTS_STR_EQUAL(tc, info.hostname, NULL);
+ ABTS_STR_EQUAL(tc, info.port_str, NULL);
+ ABTS_STR_EQUAL(tc, info.path, t->path);
+ ABTS_STR_EQUAL(tc, info.query, t->query);
+ ABTS_STR_EQUAL(tc, info.user, NULL);
+ ABTS_INT_EQUAL(tc, info.port, 0);
+ }
+ }
+}
+
+static void test_uph(abts_case *tc, void *data)
+{
+ int i;
+ apr_status_t rv;
+ apr_uri_t info;
+ struct uph_test *t;
+
+ for (i = 0; i < sizeof(uph_tests) / sizeof(uph_tests[0]); i++) {
+ memset(&info, 0, sizeof(info));
+ t = &uph_tests[i];
+ rv = apr_uri_parse_hostinfo(p, t->hostinfo, &info);
+ ABTS_INT_EQUAL(tc, t->rv, rv);
+ if (t->rv == APR_SUCCESS) {
+ ABTS_STR_EQUAL(tc, t->hostname, info.hostname);
+ ABTS_STR_EQUAL(tc, t->port_str, info.port_str);
+ ABTS_INT_EQUAL(tc, t->port, info.port);
+ }
+ }
+}
+
+abts_suite *testuri(abts_suite *suite)
+{
+ suite = ADD_SUITE(suite);
+
+ abts_run_test(suite, test_aup, NULL);
+ abts_run_test(suite, test_uph, NULL);
+
+ return suite;
+}
+
diff --git a/test/testutil.c b/test/testutil.c
new file mode 100644
index 0000000..e5f8460
--- /dev/null
+++ b/test/testutil.c
@@ -0,0 +1,60 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "abts.h"
+#include "testutil.h"
+#include "apr_pools.h"
+
+apr_pool_t *p;
+
+void apr_assert_success(abts_case* tc, const char* context, apr_status_t rv)
+{
+ if (rv == APR_ENOTIMPL) {
+ ABTS_NOT_IMPL(tc, context);
+ }
+
+ if (rv != APR_SUCCESS) {
+ char buf[STRING_MAX], ebuf[128];
+ sprintf(buf, "%s (%d): %s\n", context, rv,
+ apr_strerror(rv, ebuf, sizeof ebuf));
+ ABTS_FAIL(tc, buf);
+ }
+}
+
+void apr_assert_failure(abts_case* tc, const char* context, apr_status_t rv,
+ int lineno)
+{
+ if (rv == APR_ENOTIMPL) {
+ abts_not_impl(tc, context, lineno);
+ } else if (rv == APR_SUCCESS) {
+ char buf[STRING_MAX];
+ sprintf(buf, "%s (%d): expected failure, got success\n", context, rv);
+ abts_fail(tc, buf, lineno);
+ }
+}
+
+void initialize(void) {
+ if (apr_initialize() != APR_SUCCESS) {
+ abort();
+ }
+ atexit(apr_terminate);
+
+ apr_pool_create(&p, NULL);
+ apr_pool_tag(p, "apr-util global test pool");
+}
diff --git a/test/testutil.h b/test/testutil.h
new file mode 100644
index 0000000..eaa7e75
--- /dev/null
+++ b/test/testutil.h
@@ -0,0 +1,73 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "apr_pools.h"
+#include "abts.h"
+
+#ifndef APR_TEST_UTIL
+#define APR_TEST_UTIL
+
+/* XXX FIXME */
+#ifdef WIN32
+#define EXTENSION ".exe"
+#elif NETWARE
+#define EXTENSION ".nlm"
+#else
+#define EXTENSION
+#endif
+
+#define STRING_MAX 8096
+
+/* Some simple functions to make the test apps easier to write and
+ * a bit more consistent...
+ */
+
+extern apr_pool_t *p;
+
+/* Assert that RV is an APR_SUCCESS value; else fail giving strerror
+ * for RV and CONTEXT message. */
+void apr_assert_success(abts_case* tc, const char *context, apr_status_t rv);
+
+void apr_assert_failure(abts_case* tc, const char *context,
+ apr_status_t rv, int lineno);
+#define APR_ASSERT_FAILURE(tc, ctxt, rv) \
+ apr_assert_failure(tc, ctxt, rv, __LINE__)
+
+
+void initialize(void);
+
+abts_suite *teststrmatch(abts_suite *suite);
+abts_suite *testuri(abts_suite *suite);
+abts_suite *testuuid(abts_suite *suite);
+abts_suite *testbuckets(abts_suite *suite);
+abts_suite *testpass(abts_suite *suite);
+abts_suite *testmd4(abts_suite *suite);
+abts_suite *testmd5(abts_suite *suite);
+abts_suite *testcrypto(abts_suite *suite);
+abts_suite *testldap(abts_suite *suite);
+abts_suite *testdbd(abts_suite *suite);
+abts_suite *testdate(abts_suite *suite);
+abts_suite *testmemcache(abts_suite *suite);
+abts_suite *testredis(abts_suite *suite);
+abts_suite *testreslist(abts_suite *suite);
+abts_suite *testqueue(abts_suite *suite);
+abts_suite *testxml(abts_suite *suite);
+abts_suite *testxlate(abts_suite *suite);
+abts_suite *testrmm(abts_suite *suite);
+abts_suite *testdbm(abts_suite *suite);
+abts_suite *testsiphash(abts_suite *suite);
+
+#endif /* APR_TEST_INCLUDES */
diff --git a/test/testutildll.dsp b/test/testutildll.dsp
new file mode 100644
index 0000000..9c90a16
--- /dev/null
+++ b/test/testutildll.dsp
@@ -0,0 +1,270 @@
+# Microsoft Developer Studio Project File - Name="testutildll" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) External Target" 0x0106
+
+CFG=testutildll - Win32 Release
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "testutildll.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "testutildll.mak" CFG="testutildll - Win32 Release"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "testutildll - Win32 Release" (based on "Win32 (x86) External Target")
+!MESSAGE "testutildll - Win32 Debug" (based on "Win32 (x86) External Target")
+!MESSAGE "testutildll - Win32 Release9x" (based on "Win32 (x86) External Target")
+!MESSAGE "testutildll - Win32 Debug9x" (based on "Win32 (x86) External Target")
+!MESSAGE "testutildll - x64 Release" (based on "Win32 (x86) External Target")
+!MESSAGE "testutildll - x64 Debug" (based on "Win32 (x86) External Target")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+
+!IF "$(CFG)" == "testutildll - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir ""
+# PROP BASE Intermediate_Dir ""
+# PROP BASE Cmd_Line "NMAKE /f Makefile.win INTDIR=Release OUTDIR=Release MODEL=dynamic all check"
+# PROP BASE Rebuild_Opt "/a"
+# PROP BASE Target_File "Release\testall.exe"
+# PROP BASE Bsc_Name ""
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir ""
+# PROP Intermediate_Dir ""
+# PROP Cmd_Line "NMAKE /f Makefile.win INTDIR=Release OUTDIR=Release MODEL=dynamic all check"
+# PROP Rebuild_Opt "/a"
+# PROP Target_File "Release\testall.exe"
+# PROP Bsc_Name ""
+# PROP Target_Dir ""
+
+!ELSEIF "$(CFG)" == "testutildll - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir ""
+# PROP BASE Intermediate_Dir ""
+# PROP BASE Cmd_Line "NMAKE /f Makefile.win INTDIR=Debug OUTDIR=Debug MODEL=dynamic _DEBUG=1 all check"
+# PROP BASE Rebuild_Opt "/a"
+# PROP BASE Target_File "Debug\testall.exe"
+# PROP BASE Bsc_Name ""
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir ""
+# PROP Intermediate_Dir ""
+# PROP Cmd_Line "NMAKE /f Makefile.win INTDIR=Debug OUTDIR=Debug MODEL=dynamic _DEBUG=1 all check"
+# PROP Rebuild_Opt "/a"
+# PROP Target_File "Debug\testall.exe"
+# PROP Bsc_Name ""
+# PROP Target_Dir ""
+
+!ELSEIF "$(CFG)" == "testutildll - Win32 Release9x"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir ""
+# PROP BASE Intermediate_Dir ""
+# PROP BASE Cmd_Line "NMAKE /f Makefile.win INTDIR=9x\Release OUTDIR=9x\Release MODEL=dynamic all check"
+# PROP BASE Rebuild_Opt "/a"
+# PROP BASE Target_File "9x\Release\testall.exe"
+# PROP BASE Bsc_Name ""
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir ""
+# PROP Intermediate_Dir ""
+# PROP Cmd_Line "NMAKE /f Makefile.win INTDIR=9x\Release OUTDIR=9x\Release MODEL=dynamic all check"
+# PROP Rebuild_Opt "/a"
+# PROP Target_File "9x\Release\testall.exe"
+# PROP Bsc_Name ""
+# PROP Target_Dir ""
+
+!ELSEIF "$(CFG)" == "testutildll - Win32 Debug9x"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir ""
+# PROP BASE Intermediate_Dir ""
+# PROP BASE Cmd_Line "NMAKE /f Makefile.win INTDIR=9x\Debug OUTDIR=9x\Debug MODEL=dynamic _DEBUG=1 all check"
+# PROP BASE Rebuild_Opt "/a"
+# PROP BASE Target_File "9x\Debug\testall.exe"
+# PROP BASE Bsc_Name ""
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir ""
+# PROP Intermediate_Dir ""
+# PROP Cmd_Line "NMAKE /f Makefile.win INTDIR=9x\Debug OUTDIR=9x\Debug MODEL=dynamic _DEBUG=1 all check"
+# PROP Rebuild_Opt "/a"
+# PROP Target_File "9x\Debug\testall.exe"
+# PROP Bsc_Name ""
+# PROP Target_Dir ""
+
+!ELSEIF "$(CFG)" == "testutildll - x64 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir ""
+# PROP BASE Intermediate_Dir ""
+# PROP BASE Cmd_Line "NMAKE /f Makefile.win INTDIR=x64\Release OUTDIR=x64\Release MODEL=dynamic all check"
+# PROP BASE Rebuild_Opt "/a"
+# PROP BASE Target_File "x64\Release\testall.exe"
+# PROP BASE Bsc_Name ""
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir ""
+# PROP Intermediate_Dir ""
+# PROP Cmd_Line "NMAKE /f Makefile.win INTDIR=x64\Release OUTDIR=x64\Release MODEL=dynamic all check"
+# PROP Rebuild_Opt "/a"
+# PROP Target_File "x64\Release\testall.exe"
+# PROP Bsc_Name ""
+# PROP Target_Dir ""
+
+!ELSEIF "$(CFG)" == "testutildll - x64 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir ""
+# PROP BASE Intermediate_Dir ""
+# PROP BASE Cmd_Line "NMAKE /f Makefile.win INTDIR=x64\Debug OUTDIR=x64\Debug MODEL=dynamic _DEBUG=1 all check"
+# PROP BASE Rebuild_Opt "/a"
+# PROP BASE Target_File "x64\Debug\testall.exe"
+# PROP BASE Bsc_Name ""
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir ""
+# PROP Intermediate_Dir ""
+# PROP Cmd_Line "NMAKE /f Makefile.win INTDIR=x64\Debug OUTDIR=x64\Debug MODEL=dynamic _DEBUG=1 all check"
+# PROP Rebuild_Opt "/a"
+# PROP Target_File "x64\Debug\testall.exe"
+# PROP Bsc_Name ""
+# PROP Target_Dir ""
+
+!ENDIF
+
+# Begin Target
+
+# Name "testutildll - Win32 Release"
+# Name "testutildll - Win32 Debug"
+# Name "testutildll - Win32 Release9x"
+# Name "testutildll - Win32 Debug9x"
+# Name "testutildll - x64 Release"
+# Name "testutildll - x64 Debug"
+# Begin Group "testall Source Files"
+
+# PROP Default_Filter ".c"
+# Begin Source File
+
+SOURCE=.\abts.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\abts.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\abts_tests.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\testbuckets.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\testdate.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\testdbd.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\testdbm.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\testldap.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\testmd4.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\testmd5.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\testmemcache.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\testpass.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\testqueue.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\testreslist.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\testrmm.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\teststrmatch.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\testuri.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\testutil.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\testuuid.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\testxlate.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\testxml.c
+# End Source File
+# End Group
+# Begin Group "Other Source Files"
+
+# PROP Default_Filter ".c"
+# Begin Source File
+
+SOURCE=.\dbd.c
+# End Source File
+# End Group
+# Begin Source File
+
+SOURCE=.\Makefile.win
+# End Source File
+# End Target
+# End Project
diff --git a/test/testutillib.dsp b/test/testutillib.dsp
new file mode 100644
index 0000000..6df114c
--- /dev/null
+++ b/test/testutillib.dsp
@@ -0,0 +1,270 @@
+# Microsoft Developer Studio Project File - Name="testutillib" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) External Target" 0x0106
+
+CFG=testutillib - Win32 Release
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "testutillib.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "testutillib.mak" CFG="testutillib - Win32 Release"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "testutillib - Win32 Release" (based on "Win32 (x86) External Target")
+!MESSAGE "testutillib - Win32 Debug" (based on "Win32 (x86) External Target")
+!MESSAGE "testutillib - Win32 Release9x" (based on "Win32 (x86) External Target")
+!MESSAGE "testutillib - Win32 Debug9x" (based on "Win32 (x86) External Target")
+!MESSAGE "testutillib - x64 Release" (based on "Win32 (x86) External Target")
+!MESSAGE "testutillib - x64 Debug" (based on "Win32 (x86) External Target")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+
+!IF "$(CFG)" == "testutillib - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir ""
+# PROP BASE Intermediate_Dir ""
+# PROP BASE Cmd_Line "NMAKE /f Makefile.win INTDIR=LibR OUTDIR=LibR MODEL=static all check"
+# PROP BASE Rebuild_Opt "/a"
+# PROP BASE Target_File "LibR\testall.exe"
+# PROP BASE Bsc_Name ""
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir ""
+# PROP Intermediate_Dir ""
+# PROP Cmd_Line "NMAKE /f Makefile.win INTDIR=LibR OUTDIR=LibR MODEL=static all check"
+# PROP Rebuild_Opt "/a"
+# PROP Target_File "LibR\testall.exe"
+# PROP Bsc_Name ""
+# PROP Target_Dir ""
+
+!ELSEIF "$(CFG)" == "testutillib - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir ""
+# PROP BASE Intermediate_Dir ""
+# PROP BASE Cmd_Line "NMAKE /f Makefile.win INTDIR=LibD OUTDIR=LibD MODEL=static _DEBUG=1 all check"
+# PROP BASE Rebuild_Opt "/a"
+# PROP BASE Target_File "LibD\testall.exe"
+# PROP BASE Bsc_Name ""
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir ""
+# PROP Intermediate_Dir ""
+# PROP Cmd_Line "NMAKE /f Makefile.win INTDIR=LibD OUTDIR=LibD MODEL=static _DEBUG=1 all check"
+# PROP Rebuild_Opt "/a"
+# PROP Target_File "LibD\testall.exe"
+# PROP Bsc_Name ""
+# PROP Target_Dir ""
+
+!ELSEIF "$(CFG)" == "testutillib - Win32 Release9x"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir ""
+# PROP BASE Intermediate_Dir ""
+# PROP BASE Cmd_Line "NMAKE /f Makefile.win INTDIR=9x\LibR OUTDIR=9x\LibR MODEL=static all check"
+# PROP BASE Rebuild_Opt "/a"
+# PROP BASE Target_File "9x\LibR\testall.exe"
+# PROP BASE Bsc_Name ""
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir ""
+# PROP Intermediate_Dir ""
+# PROP Cmd_Line "NMAKE /f Makefile.win INTDIR=9x\LibR OUTDIR=9x\LibR MODEL=static all check"
+# PROP Rebuild_Opt "/a"
+# PROP Target_File "9x\LibR\testall.exe"
+# PROP Bsc_Name ""
+# PROP Target_Dir ""
+
+!ELSEIF "$(CFG)" == "testutillib - Win32 Debug9x"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir ""
+# PROP BASE Intermediate_Dir ""
+# PROP BASE Cmd_Line "NMAKE /f Makefile.win INTDIR=9x\LibD OUTDIR=9x\LibD MODEL=static _DEBUG=1 all check"
+# PROP BASE Rebuild_Opt "/a"
+# PROP BASE Target_File "9x\LibD\testall.exe"
+# PROP BASE Bsc_Name ""
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir ""
+# PROP Intermediate_Dir ""
+# PROP Cmd_Line "NMAKE /f Makefile.win INTDIR=9x\LibD OUTDIR=9x\LibD MODEL=static _DEBUG=1 all check"
+# PROP Rebuild_Opt "/a"
+# PROP Target_File "9x\LibD\testall.exe"
+# PROP Bsc_Name ""
+# PROP Target_Dir ""
+
+!ELSEIF "$(CFG)" == "testutillib - x64 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir ""
+# PROP BASE Intermediate_Dir ""
+# PROP BASE Cmd_Line "NMAKE /f Makefile.win INTDIR=x64\LibR OUTDIR=x64\LibR MODEL=static all check"
+# PROP BASE Rebuild_Opt "/a"
+# PROP BASE Target_File "x64\LibR\testall.exe"
+# PROP BASE Bsc_Name ""
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir ""
+# PROP Intermediate_Dir ""
+# PROP Cmd_Line "NMAKE /f Makefile.win INTDIR=x64\LibR OUTDIR=x64\LibR MODEL=static all check"
+# PROP Rebuild_Opt "/a"
+# PROP Target_File "x64\LibR\testall.exe"
+# PROP Bsc_Name ""
+# PROP Target_Dir ""
+
+!ELSEIF "$(CFG)" == "testutillib - x64 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir ""
+# PROP BASE Intermediate_Dir ""
+# PROP BASE Cmd_Line "NMAKE /f Makefile.win INTDIR=x64\LibD OUTDIR=x64\LibD MODEL=static _DEBUG=1 all check"
+# PROP BASE Rebuild_Opt "/a"
+# PROP BASE Target_File "x64\LibD\testall.exe"
+# PROP BASE Bsc_Name ""
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir ""
+# PROP Intermediate_Dir ""
+# PROP Cmd_Line "NMAKE /f Makefile.win INTDIR=x64\LibD OUTDIR=x64\LibD MODEL=static _DEBUG=1 all check"
+# PROP Rebuild_Opt "/a"
+# PROP Target_File "x64\LibD\testall.exe"
+# PROP Bsc_Name ""
+# PROP Target_Dir ""
+
+!ENDIF
+
+# Begin Target
+
+# Name "testutillib - Win32 Release"
+# Name "testutillib - Win32 Debug"
+# Name "testutillib - Win32 Release9x"
+# Name "testutillib - Win32 Debug9x"
+# Name "testutillib - x64 Release"
+# Name "testutillib - x64 Debug"
+# Begin Group "testall Source Files"
+
+# PROP Default_Filter ".c"
+# Begin Source File
+
+SOURCE=.\abts.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\abts.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\abts_tests.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\testbuckets.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\testdate.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\testdbd.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\testdbm.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\testldap.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\testmd4.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\testmd5.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\testmemcache.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\testpass.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\testqueue.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\testreslist.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\testrmm.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\teststrmatch.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\testuri.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\testutil.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\testuuid.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\testxlate.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\testxml.c
+# End Source File
+# End Group
+# Begin Group "Other Source Files"
+
+# PROP Default_Filter ".c"
+# Begin Source File
+
+SOURCE=.\dbd.c
+# End Source File
+# End Group
+# Begin Source File
+
+SOURCE=.\Makefile.win
+# End Source File
+# End Target
+# End Project
diff --git a/test/testuuid.c b/test/testuuid.c
new file mode 100644
index 0000000..f33adde
--- /dev/null
+++ b/test/testuuid.c
@@ -0,0 +1,56 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "testutil.h"
+#include "apr_general.h"
+#include "apr_uuid.h"
+
+static void test_uuid_parse(abts_case *tc, void *data)
+{
+ apr_uuid_t uuid;
+ apr_uuid_t uuid2;
+ char buf[APR_UUID_FORMATTED_LENGTH + 1];
+
+ apr_uuid_get(&uuid);
+ apr_uuid_format(buf, &uuid);
+
+ apr_uuid_parse(&uuid2, buf);
+ ABTS_ASSERT(tc, "parse produced a different UUID",
+ memcmp(&uuid, &uuid2, sizeof(uuid)) == 0);
+}
+
+static void test_gen2(abts_case *tc, void *data)
+{
+ apr_uuid_t uuid;
+ apr_uuid_t uuid2;
+
+ /* generate two of them quickly */
+ apr_uuid_get(&uuid);
+ apr_uuid_get(&uuid2);
+
+ ABTS_ASSERT(tc, "generated the same UUID twice",
+ memcmp(&uuid, &uuid2, sizeof(uuid)) != 0);
+}
+
+abts_suite *testuuid(abts_suite *suite)
+{
+ suite = ADD_SUITE(suite);
+
+ abts_run_test(suite, test_uuid_parse, NULL);
+ abts_run_test(suite, test_gen2, NULL);
+
+ return suite;
+}
diff --git a/test/testxlate.c b/test/testxlate.c
new file mode 100644
index 0000000..6981eff
--- /dev/null
+++ b/test/testxlate.c
@@ -0,0 +1,134 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "apr.h"
+#include "apr_errno.h"
+#include "apr_general.h"
+#include "apr_strings.h"
+#include "apr_xlate.h"
+#include "abts.h"
+#include "testutil.h"
+
+#if APR_HAS_XLATE
+
+static const char test_utf8[] = "Edelwei\xc3\x9f";
+static const char test_utf7[] = "Edelwei+AN8-";
+static const char test_latin1[] = "Edelwei\xdf";
+static const char test_latin2[] = "Edelwei\xdf";
+
+static void test_conversion(abts_case *tc, apr_xlate_t *convset,
+ const char *inbuf, const char *expected)
+{
+ static char buf[1024];
+ apr_size_t inbytes_left = strlen(inbuf);
+ apr_size_t outbytes_left = sizeof(buf) - 1;
+ apr_status_t rv;
+
+ rv = apr_xlate_conv_buffer(convset, inbuf, &inbytes_left, buf, &outbytes_left);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+
+ if (rv != APR_SUCCESS)
+ return;
+
+ rv = apr_xlate_conv_buffer(convset, NULL, NULL, buf + sizeof(buf) -
+ outbytes_left - 1, &outbytes_left);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+
+ buf[sizeof(buf) - outbytes_left - 1] = '\0';
+
+ ABTS_STR_EQUAL(tc, expected, buf);
+}
+
+static void one_test(abts_case *tc, const char *cs1, const char *cs2,
+ const char *str1, const char *str2,
+ apr_pool_t *pool)
+{
+ apr_status_t rv;
+ apr_xlate_t *convset;
+
+ rv = apr_xlate_open(&convset, cs2, cs1, pool);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+
+ if (rv != APR_SUCCESS)
+ return;
+
+ test_conversion(tc, convset, str1, str2);
+
+ rv = apr_xlate_close(convset);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+}
+
+#if APU_HAVE_APR_ICONV
+/* it is a bug if iconv_open() fails */
+static int is_transform_supported(abts_case *tc, const char *cs1,
+ const char *cs2, apr_pool_t *pool) {
+ return 1;
+}
+#else
+/* some iconv implementations don't support all tested transforms;
+ * example: 8859-1 <-> 8859-2 using native Solaris iconv
+ */
+static int is_transform_supported(abts_case *tc, const char *cs1,
+ const char *cs2, apr_pool_t *pool) {
+ apr_status_t rv;
+ apr_xlate_t *convset;
+
+ rv = apr_xlate_open(&convset, cs2, cs1, pool);
+ if (rv != APR_SUCCESS) {
+ return 0;
+ }
+
+ rv = apr_xlate_close(convset);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+
+ return 1;
+}
+#endif
+
+static void test_transformation(abts_case *tc, void *data)
+{
+ /* 1. Identity transformation: UTF-8 -> UTF-8 */
+ one_test(tc, "UTF-8", "UTF-8", test_utf8, test_utf8, p);
+
+ /* 2. UTF-8 <-> ISO-8859-1 */
+ one_test(tc, "UTF-8", "ISO-8859-1", test_utf8, test_latin1, p);
+ one_test(tc, "ISO-8859-1", "UTF-8", test_latin1, test_utf8, p);
+
+ /* 3. ISO-8859-1 <-> ISO-8859-2, identity */
+ if (is_transform_supported(tc, "ISO-8859-1", "ISO-8859-2", p)) {
+ one_test(tc, "ISO-8859-1", "ISO-8859-2", test_latin1, test_latin2, p);
+ }
+ if (is_transform_supported(tc, "ISO-8859-2", "ISO-8859-1", p)) {
+ one_test(tc, "ISO-8859-2", "ISO-8859-1", test_latin2, test_latin1, p);
+ }
+
+ /* 4. Transformation using charset aliases */
+ one_test(tc, "UTF-8", "UTF-7", test_utf8, test_utf7, p);
+ one_test(tc, "UTF-7", "UTF-8", test_utf7, test_utf8, p);
+}
+
+#endif /* APR_HAS_XLATE */
+
+abts_suite *testxlate(abts_suite *suite)
+{
+ suite = ADD_SUITE(suite);
+
+#if APR_HAS_XLATE
+ abts_run_test(suite, test_transformation, NULL);
+#endif
+
+ return suite;
+}
diff --git a/test/testxml.c b/test/testxml.c
new file mode 100644
index 0000000..eed1067
--- /dev/null
+++ b/test/testxml.c
@@ -0,0 +1,205 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "apr.h"
+#include "apr_general.h"
+#include "apr_xml.h"
+#include "abts.h"
+#include "testutil.h"
+
+static apr_status_t create_dummy_file_error(abts_case *tc, apr_pool_t *p,
+ apr_file_t **fd)
+{
+ int i;
+ apr_status_t rv;
+ apr_off_t off = 0L;
+ char template[] = "data/testxmldummyerrorXXXXXX";
+
+ rv = apr_file_mktemp(fd, template, APR_FOPEN_CREATE | APR_FOPEN_TRUNCATE | APR_FOPEN_DELONCLOSE |
+ APR_FOPEN_READ | APR_FOPEN_WRITE | APR_FOPEN_EXCL, p);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+
+ if (rv != APR_SUCCESS)
+ return rv;
+
+ rv = apr_file_puts("<?xml version=\"1.0\" ?>\n<maryx>"
+ "<had a=\"little\"/><lamb/>\n", *fd);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+
+ for (i = 0; i < 5000; i++) {
+ rv = apr_file_puts("<hmm roast=\"lamb\" "
+ "for=\"dinner\">yummy</hmm>\n", *fd);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+ }
+
+ rv = apr_file_puts("</mary>\n", *fd);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+
+ rv = apr_file_seek(*fd, APR_SET, &off);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+
+ return rv;
+}
+
+static apr_status_t create_dummy_file(abts_case *tc, apr_pool_t *p,
+ apr_file_t **fd)
+{
+ int i;
+ apr_status_t rv;
+ apr_off_t off = 0L;
+ char template[] = "data/testxmldummyXXXXXX";
+
+ rv = apr_file_mktemp(fd, template, APR_FOPEN_CREATE | APR_FOPEN_TRUNCATE | APR_FOPEN_DELONCLOSE |
+ APR_FOPEN_READ | APR_FOPEN_WRITE | APR_FOPEN_EXCL, p);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+
+ if (rv != APR_SUCCESS)
+ return rv;
+
+ rv = apr_file_puts("<?xml version=\"1.0\" ?>\n<mary>\n", *fd);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+
+ for (i = 0; i < 5000; i++) {
+ rv = apr_file_puts("<hmm roast=\"lamb\" "
+ "for=\"dinner &lt;&gt;&#x3D;\">yummy</hmm>\n", *fd);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+ }
+
+ rv = apr_file_puts("</mary>\n", *fd);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+
+ rv = apr_file_seek(*fd, APR_SET, &off);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+
+ return rv;
+}
+
+static void dump_xml(abts_case *tc, apr_xml_elem *e, int level)
+{
+ apr_xml_attr *a;
+ apr_xml_elem *ec;
+
+ if (level == 0) {
+ ABTS_STR_EQUAL(tc, "mary", e->name);
+ } else {
+ ABTS_STR_EQUAL(tc, "hmm", e->name);
+ }
+
+ if (e->attr) {
+ a = e->attr;
+ ABTS_PTR_NOTNULL(tc, a);
+ ABTS_STR_EQUAL(tc, "for", a->name);
+ ABTS_STR_EQUAL(tc, "dinner <>=", a->value);
+ a = a->next;
+ ABTS_PTR_NOTNULL(tc, a);
+ ABTS_STR_EQUAL(tc, "roast", a->name);
+ ABTS_STR_EQUAL(tc, "lamb", a->value);
+ }
+ if (e->first_child) {
+ ec = e->first_child;
+ while (ec) {
+ dump_xml(tc, ec, level + 1);
+ ec = ec->next;
+ }
+ }
+}
+
+static void test_xml_parser(abts_case *tc, void *data)
+{
+ apr_file_t *fd;
+ apr_xml_parser *parser;
+ apr_xml_doc *doc;
+ apr_status_t rv;
+
+ rv = create_dummy_file(tc, p, &fd);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+
+ if (rv != APR_SUCCESS)
+ return;
+
+ rv = apr_xml_parse_file(p, &parser, &doc, fd, 2000);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+
+ dump_xml(tc, doc->root, 0);
+
+ rv = apr_file_close(fd);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+
+ rv = create_dummy_file_error(tc, p, &fd);
+ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
+
+ if (rv != APR_SUCCESS)
+ return;
+
+ rv = apr_xml_parse_file(p, &parser, &doc, fd, 2000);
+ ABTS_TRUE(tc, rv != APR_SUCCESS);
+}
+
+static void test_billion_laughs(abts_case *tc, void *data)
+{
+ apr_file_t *fd;
+ apr_xml_parser *parser;
+ apr_xml_doc *doc;
+ apr_status_t rv;
+
+ rv = apr_file_open(&fd, "data/billion-laughs.xml",
+ APR_FOPEN_READ, 0, p);
+ apr_assert_success(tc, "open billion-laughs.xml", rv);
+
+ /* Don't test for return value; if it returns, chances are the bug
+ * is fixed or the machine has insane amounts of RAM. */
+ apr_xml_parse_file(p, &parser, &doc, fd, 2000);
+
+ apr_file_close(fd);
+}
+
+static void test_CVE_2009_3720_alpha(abts_case *tc, void *data)
+{
+ apr_xml_parser *xp;
+ apr_xml_doc *doc;
+ apr_status_t rv;
+
+ xp = apr_xml_parser_create(p);
+
+ rv = apr_xml_parser_feed(xp, "\0\r\n", 3);
+ if (rv == APR_SUCCESS)
+ apr_xml_parser_done(xp, &doc);
+}
+
+static void test_CVE_2009_3720_beta(abts_case *tc, void *data)
+{
+ apr_xml_parser *xp;
+ apr_xml_doc *doc;
+ apr_status_t rv;
+
+ xp = apr_xml_parser_create(p);
+
+ rv = apr_xml_parser_feed(xp, "<?xml version\xc2\x85='1.0'?>\r\n", 25);
+ if (rv == APR_SUCCESS)
+ apr_xml_parser_done(xp, &doc);
+}
+
+abts_suite *testxml(abts_suite *suite)
+{
+ suite = ADD_SUITE(suite);
+
+ abts_run_test(suite, test_xml_parser, NULL);
+ abts_run_test(suite, test_billion_laughs, NULL);
+ abts_run_test(suite, test_CVE_2009_3720_alpha, NULL);
+ abts_run_test(suite, test_CVE_2009_3720_beta, NULL);
+
+ return suite;
+}