Index: .fossil-settings/clean-glob ================================================================== --- .fossil-settings/clean-glob +++ .fossil-settings/clean-glob @@ -24,26 +24,37 @@ configure docs extra.mk generators/library/gen_libraries generators/unicode/gen_tables +new_tests/EBOOT.PBP +new_tests/PARAM.SFO +new_tests/plugin/Info.plist +new_tests/subprocess/subprocess +new_tests/testfile_bin.m +new_tests/testfile_ini.m +new_tests/tests +new_tests/tests.3dsx +new_tests/tests.arm9 +new_tests/tests.nds +new_tests/tests.nro +new_tests/tests.rpx src/Info.plist src/bridge/Info.plist src/libobjfw.* src/objfw-defs.h src/runtime/Info.plist src/runtime/libobjfwrt.* +src/test/libobjfwtest.a src/tls/Info.plist +src/tls/libobjfwtls.* tests/DerivedData tests/EBOOT.PBP tests/Info.plist tests/PARAM.SFO tests/objc_sync/objc_sync -tests/plugin/Info.plist tests/terminal/terminal_tests -tests/testfile_bin.m -tests/testfile_ini.m tests/tests tests/tests.3dsx tests/tests.arm9 tests/tests.nds tests/tests.nro Index: .fossil-settings/ignore-glob ================================================================== --- .fossil-settings/ignore-glob +++ .fossil-settings/ignore-glob @@ -26,29 +26,40 @@ configure docs extra.mk generators/library/gen_libraries generators/unicode/gen_tables +new_tests/EBOOT.PBP +new_tests/PARAM.SFO +new_tests/plugin/Info.plist +new_tests/subprocess/subprocess +new_tests/testfile_bin.m +new_tests/testfile_ini.m +new_tests/tests +new_tests/tests.3dsx +new_tests/tests.arm9 +new_tests/tests.nds +new_tests/tests.nro +new_tests/tests.rpx src/Info.plist src/bridge/Info.plist src/libobjfw.* src/objfw-defs.h src/runtime/Info.plist src/runtime/libobjfwrt.* +src/test/libobjfwtest.a src/tls/Info.plist +src/tls/libobjfwtls.* tests/DerivedData tests/EBOOT.PBP tests/Info.plist tests/PARAM.SFO tests/iOS.xcodeproj/*.pbxuser tests/iOS.xcodeproj/project.xcworkspace tests/iOS.xcodeproj/xcuserdata tests/objc_sync/objc_sync -tests/plugin/Info.plist tests/terminal/terminal_tests -tests/testfile_bin.m -tests/testfile_ini.m tests/tests tests/tests.3dsx tests/tests.arm9 tests/tests.nds tests/tests.nro ADDED .github/workflows/dragonflybsd.yml Index: .github/workflows/dragonflybsd.yml ================================================================== --- .github/workflows/dragonflybsd.yml +++ .github/workflows/dragonflybsd.yml @@ -0,0 +1,25 @@ +name: dragonflybsd +on: [push, pull_request] +jobs: + tests: + runs-on: ubuntu-latest + strategy: + matrix: + configure_flags: + - + - --disable-shared + - --with-tls=gnutls + steps: + - uses: actions/checkout@v4 + - uses: vmactions/dragonflybsd-vm@v1 + with: + usesh: true + copyback: false + prepare: | + pkg install -y autoconf automake gnutls llvm pkgconf + run: | + ./autogen.sh + ./configure OBJC=clang ${{ matrix.configure_flags }} + make -j4 + make check + make install ADDED .github/workflows/freebsd.yml Index: .github/workflows/freebsd.yml ================================================================== --- .github/workflows/freebsd.yml +++ .github/workflows/freebsd.yml @@ -0,0 +1,25 @@ +name: freebsd +on: [push, pull_request] +jobs: + tests: + runs-on: ubuntu-latest + strategy: + matrix: + configure_flags: + - + - --disable-shared + - --with-tls=gnutls + steps: + - uses: actions/checkout@v4 + - uses: vmactions/freebsd-vm@v1 + with: + usesh: true + copyback: false + prepare: | + pkg install -y autoconf automake gnutls pkgconf + run: | + ./autogen.sh + ./configure OBJC=clang ${{ matrix.configure_flags }} + make -j4 + make check + make install ADDED .github/workflows/netbsd-gcc.yml Index: .github/workflows/netbsd-gcc.yml ================================================================== --- .github/workflows/netbsd-gcc.yml +++ .github/workflows/netbsd-gcc.yml @@ -0,0 +1,25 @@ +name: netbsd-gcc +on: [push, pull_request] +jobs: + tests: + runs-on: ubuntu-latest + strategy: + matrix: + configure_flags: + - + - --disable-shared + - --with-tls=gnutls + steps: + - uses: actions/checkout@v4 + - uses: vmactions/netbsd-vm@v1 + with: + usesh: true + copyback: false + prepare: | + /usr/sbin/pkg_add autoconf automake gnutls pkgconf + run: | + ./autogen.sh + ./configure OBJC=gcc ${{ matrix.configure_flags }} + make -j4 + make check + make install ADDED .github/workflows/netbsd.yml Index: .github/workflows/netbsd.yml ================================================================== --- .github/workflows/netbsd.yml +++ .github/workflows/netbsd.yml @@ -0,0 +1,25 @@ +name: netbsd +on: [push, pull_request] +jobs: + tests: + runs-on: ubuntu-latest + strategy: + matrix: + configure_flags: + - + - --disable-shared + - --with-tls=gnutls + steps: + - uses: actions/checkout@v4 + - uses: vmactions/netbsd-vm@v1 + with: + usesh: true + copyback: false + prepare: | + /usr/sbin/pkg_add autoconf automake clang gnutls pkgconf + run: | + ./autogen.sh + ./configure OBJC=clang ${{ matrix.configure_flags }} + make -j4 + make check + make install ADDED .github/workflows/openbsd.yml Index: .github/workflows/openbsd.yml ================================================================== --- .github/workflows/openbsd.yml +++ .github/workflows/openbsd.yml @@ -0,0 +1,25 @@ +name: openbsd +on: [push, pull_request] +jobs: + tests: + runs-on: ubuntu-latest + strategy: + matrix: + configure_flags: + - + - --disable-shared + - --with-tls=gnutls + steps: + - uses: actions/checkout@v4 + - uses: vmactions/openbsd-vm@v1 + with: + usesh: true + copyback: false + prepare: | + pkg_add autoconf-2.71 automake-1.16.5 gnutls pkgconf + run: | + ./autogen.sh + ./configure OBJC=clang ${{ matrix.configure_flags }} + make -j4 + make check + make install Index: .github/workflows/ubuntu-latest-gcc.yml ================================================================== --- .github/workflows/ubuntu-latest-gcc.yml +++ .github/workflows/ubuntu-latest-gcc.yml @@ -19,15 +19,17 @@ - --disable-shared - --disable-shared --enable-seluid24 - --disable-compiler-tls --disable-threads - --with-tls=gnutls - --with-tls=gnutls --disable-shared + - --with-tls=mbedtls + - --with-tls=mbedtls --disable-shared steps: - name: Install dependencies run: | sudo apt-get update - sudo apt-get install gobjc libssl-dev gnutls-dev + sudo apt-get install gobjc libssl-dev gnutls-dev libmbedtls-dev - uses: actions/checkout@v4 - name: autogen.sh run: ./autogen.sh - name: configure run: ./configure OBJC="gcc" ${{ matrix.configure_flags }} Index: .github/workflows/ubuntu-latest.yml ================================================================== --- .github/workflows/ubuntu-latest.yml +++ .github/workflows/ubuntu-latest.yml @@ -19,15 +19,17 @@ - --disable-shared - --disable-shared --enable-seluid24 - --disable-compiler-tls --disable-threads - --with-tls=gnutls - --with-tls=gnutls --disable-shared + - --with-tls=mbedtls + - --with-tls=mbedtls --disable-shared steps: - name: Install dependencies run: | sudo apt-get update - sudo apt-get install libssl-dev gnutls-dev + sudo apt-get install libssl-dev gnutls-dev libmbedtls-dev - uses: actions/checkout@v4 - name: autogen.sh run: ./autogen.sh - name: configure run: ./configure ${{ matrix.configure_flags }} Index: .gitignore ================================================================== --- .gitignore +++ .gitignore @@ -26,29 +26,40 @@ configure docs extra.mk generators/library/gen_libraries generators/unicode/gen_tables +new_tests/EBOOT.PBP +new_tests/PARAM.SFO +new_tests/plugin/Info.plist +new_tests/subprocess/subprocess +new_tests/testfile_bin.m +new_tests/testfile_ini.m +new_tests/tests +new_tests/tests.3dsx +new_tests/tests.arm9 +new_tests/tests.nds +new_tests/tests.nro +new_tests/tests.rpx src/Info.plist src/bridge/Info.plist src/libobjfw.* src/objfw-defs.h src/runtime/Info.plist src/runtime/libobjfwrt.* +src/test/libobjfwtest.a src/tls/Info.plist +src/tls/libobjfwtls.* tests/DerivedData tests/EBOOT.PBP tests/Info.plist tests/PARAM.SFO tests/iOS.xcodeproj/*.pbxuser tests/iOS.xcodeproj/project.xcworkspace tests/iOS.xcodeproj/xcuserdata tests/objc_sync/objc_sync -tests/plugin/Info.plist tests/terminal/terminal_tests -tests/testfile_bin.m -tests/testfile_ini.m tests/tests tests/tests.3dsx tests/tests.arm9 tests/tests.nds tests/tests.nro Index: ChangeLog ================================================================== --- ChangeLog +++ ChangeLog @@ -2,10 +2,27 @@ * Changes of existing features or bugfixes + New features This file only contains the most significant changes. +ObjFW 1.0.7 -> ObjFW 1.0.8, 2024-01-21 + * Fixes compilation on NetBSD, OpenBSD, OpenIndiana etc. which was broken by + 1.0.7. + +ObjFW 1.0.6 -> ObjFW 1.0.7, 2024-01-21 + * Fixes inheriting the environment in OFSubprocess. + * Fixes dealloc in OFSubprocess when -[closeForWriting] was called. + + Adds tests for OFSubprocess. + * Changes the key for +[OFSystemInfo networkInterfaces] to the adapter name + on Windows XP and newer to avoid a possible collission on the adapter index. + * Fixes compilation with old MinGW versions. + * Fixes the documentation for OFSRVDNSResourceRecord. + +ObjFW 1.0.5 -> ObjFW 1.0.6, 2024-01-15 + * Fixes compatibility with autoconf 2.72. + * Fixes OFDNSResolver's handling of types, classes and lengths > 255. + ObjFW 1.0.4 -> ObjFW 1.0.5, 2023-11-05 * Fixes the calculation of the extra alignment in OFAllocObject() * Fixes +[OFSystemInfo networkInterfaces] on OpenBSD and Windows 98 * Fixes OFSocketAddressString() for AppleTalk addresses * Uses GetModuleHandle() instead of LoadLibrary() where possible on Windows Index: Makefile ================================================================== --- Makefile +++ Makefile @@ -1,8 +1,8 @@ include extra.mk -SUBDIRS = src utils tests +SUBDIRS = src utils tests new_tests DISTCLEAN = Info.plist \ aclocal.m4 \ autom4te.cache \ buildsys.mk \ config.h \ @@ -12,14 +12,15 @@ include buildsys.mk .PHONY: check docs release -utils tests: src +utils tests new_tests: src -check: tests +check: tests new_tests cd tests && ${MAKE} -s run + cd new_tests && ${MAKE} -s run docs: rm -fr docs doxygen >/dev/null Index: configure.ac ================================================================== --- configure.ac +++ configure.ac @@ -439,11 +439,11 @@ AC_DEFINE_UNQUOTED(PLUGIN_SUFFIX, "$PLUGIN_SUFFIX", [Suffix for plugins]) AS_IF([test x"$enable_files" != x"no" -a x"$PLUGIN_SUFFIX" != x""], [ AC_SUBST(USE_SRCS_PLUGINS, '${SRCS_PLUGINS}') AC_SUBST(TESTPLUGIN, "plugin") AC_DEFINE(OF_HAVE_PLUGINS, 1, [Whether we have plugin support]) - AC_CONFIG_FILES(tests/plugin/Info.plist) + AC_CONFIG_FILES(new_tests/plugin/Info.plist) AS_IF([test x"$build_framework" = x"yes"], [ TESTPLUGIN_LIBS="-F../../src -F../../src/runtime" TESTPLUGIN_LIBS="$TESTPLUGIN_LIBS -framework ObjFW" TESTPLUGIN_LIBS="$TESTPLUGIN_LIBS \${RUNTIME_FRAMEWORK_LIBS}" @@ -1853,19 +1853,10 @@ : ]) ]) AS_IF([test x"$with_tls" = x"mbedtls"], [ - AC_ARG_WITH(mbedtls-ca-path, - AS_HELP_STRING([path to CA file for Mbed TLS])) - - AS_IF([test x"$with_mbedtls_ca_path" = x""], [ - AC_MSG_ERROR([--mbedtls-ca-path needs to be specified!]) - ]) - AC_DEFINE_UNQUOTED(OF_MBEDTLS_CA_PATH, "$with_mbedtls_ca_path", - [Path to CA file for Mbed TLS]) - AC_CHECK_LIB(mbedtls, mbedtls_net_init, [ AC_CHECK_HEADER(mbedtls/ssl.h, [ tls_support="Mbed TLS" TLS_LIBS="-lmbedx509 -lmbedcrypto $TLS_LIBS" TLS_LIBS="-lmbedtls $TLS_LIBS" @@ -1900,11 +1891,11 @@ ]) AS_IF([test x"$with_tls" != x"no" -a x"$tls_support" = x"no"], [ AC_MSG_ERROR(m4_normalize([ No TLS implementation was found. Please install OpenSSL, - GnuTLS or use --without-tls. + GnuTLS, Mbed TLS or use --without-tls. ])) ]) AS_IF([test x"$enable_threads" != x"no"], [ AC_SUBST(OF_HTTP_CLIENT_TESTS_M, "OFHTTPClientTests.m") @@ -1988,11 +1979,12 @@ break ]) ]) ]) AS_IF([test x"$have_subprocesses" = x"yes"], [ - AC_SUBST(OF_SUBPROCESS_M, "OFSubprocess.m") + AC_SUBST(USE_SRCS_SUBPROCESSES, '${SRCS_SUBPROCESSES}') + AC_SUBST(SUBPROCESS, "subprocess") AC_DEFINE(OF_HAVE_SUBPROCESSES, 1, [Whether we have subprocesses]) ]) AC_CHECK_HEADERS_ONCE([complex.h sys/ioctl.h sys/ttycom.h]) AC_CHECK_FUNCS(ioctl isatty) Index: extra.mk.in ================================================================== --- extra.mk.in +++ extra.mk.in @@ -8,11 +8,11 @@ OBJFWRT_SHARED_LIB = @OBJFWRT_SHARED_LIB@ OBJFWRT_STATIC_LIB = @OBJFWRT_STATIC_LIB@ OBJFWRT_FRAMEWORK = @OBJFWRT_FRAMEWORK@ OBJFWRT_LIB_MAJOR = 1 -OBJFWRT_LIB_MINOR = 0 +OBJFWRT_LIB_MINOR = 1 OBJFWRT_LIB_PATCH = 0 OBJFWRT_LIB_MAJOR_MINOR = ${OBJFWRT_LIB_MAJOR}.${OBJFWRT_LIB_MINOR} OBJFWBRIDGE_SHARED_LIB = @OBJFWBRIDGE_SHARED_LIB@ OBJFWBRIDGE_STATIC_LIB = @OBJFWBRIDGE_STATIC_LIB@ @@ -61,22 +61,19 @@ OF_MBEDTLS_TLS_STREAM_M = @OF_MBEDTLS_TLS_STREAM_M@ OF_OPENSSL_TLS_STREAM_M = @OF_OPENSSL_TLS_STREAM_M@ OF_POLL_KERNEL_EVENT_OBSERVER_M = @OF_POLL_KERNEL_EVENT_OBSERVER_M@ OF_SECURE_TRANSPORT_TLS_STREAM_M = @OF_SECURE_TRANSPORT_TLS_STREAM_M@ OF_SELECT_KERNEL_EVENT_OBSERVER_M = @OF_SELECT_KERNEL_EVENT_OBSERVER_M@ -OF_SUBPROCESS_M = @OF_SUBPROCESS_M@ REEXPORT_RUNTIME = @REEXPORT_RUNTIME@ REEXPORT_RUNTIME_FRAMEWORK = @REEXPORT_RUNTIME_FRAMEWORK@ RUNTIME = @RUNTIME@ RUNTIME_ARC_TESTS_M = @RUNTIME_ARC_TESTS_M@ RUNTIME_AUTORELEASE_M = @RUNTIME_AUTORELEASE_M@ RUNTIME_FRAMEWORK_LIBS = @RUNTIME_FRAMEWORK_LIBS@ RUNTIME_INSTANCE_M = @RUNTIME_INSTANCE_M@ RUNTIME_LIBS = @RUNTIME_LIBS@ -SFDC_INLINE_H = @SFDC_INLINE_H@ -SFDC_TARGET = @SFDC_TARGET@ -SFD_FILE = @SFD_FILE@ +SUBPROCESS = @SUBPROCESS@ TESTPLUGIN = @TESTPLUGIN@ TESTPLUGIN_LIBS = @TESTPLUGIN_LIBS@ TESTS_LIBS = @TESTS_LIBS@ TESTS_STATIC_LIB = @TESTS_STATIC_LIB@ TLS = @TLS@ @@ -87,10 +84,11 @@ USE_SRCS_APPLETALK = @USE_SRCS_APPLETALK@ USE_SRCS_FILES = @USE_SRCS_FILES@ USE_SRCS_IPX = @USE_SRCS_IPX@ USE_SRCS_PLUGINS = @USE_SRCS_PLUGINS@ USE_SRCS_SOCKETS = @USE_SRCS_SOCKETS@ +USE_SRCS_SUBPROCESSES = @USE_SRCS_SUBPROCESSES@ USE_SRCS_TAGGED_POINTERS = @USE_SRCS_TAGGED_POINTERS@ USE_SRCS_THREADS = @USE_SRCS_THREADS@ USE_SRCS_UNIX_SOCKETS = @USE_SRCS_UNIX_SOCKETS@ USE_SRCS_WINDOWS = @USE_SRCS_WINDOWS@ WRAPPER = @WRAPPER@ ADDED new_tests/Makefile Index: new_tests/Makefile ================================================================== --- new_tests/Makefile +++ new_tests/Makefile @@ -0,0 +1,182 @@ +include ../extra.mk + +SUBDIRS = ${TESTPLUGIN} ${SUBPROCESS} + +CLEAN = EBOOT.PBP \ + boot.dol \ + ${PROG_NOINST}.arm9 \ + ${PROG_NOINST}.nds \ + ${PROG_NOINST}.nro \ + ${PROG_NOINST}.rpx \ + testfile_bin.m \ + testfile_ini.m + +PROG_NOINST = tests${PROG_SUFFIX} +SRCS = OFArrayTests.m \ + OFCharacterSetTests.m \ + OFColorTests.m \ + OFConcreteArrayTests.m \ + OFConcreteMutableArrayTests.m \ + OFCryptographicHashTests.m \ + OFDateTests.m \ + OFHMACTests.m \ + OFINIFileTests.m \ + OFIRITests.m \ + OFInvocationTests.m \ + OFJSONTests.m \ + OFMatrix4x4Tests.m \ + OFMethodSignatureTests.m \ + OFMutableArrayTests.m \ + OFNumberTests.m \ + OFPBKDF2Tests.m \ + OFPropertyListTests.m \ + OFScryptTests.m \ + ${USE_SRCS_PLUGINS} \ + ${USE_SRCS_SOCKETS} \ + ${USE_SRCS_SUBPROCESSES} \ + ${USE_SRCS_THREADS} \ + testfile_bin.m \ + testfile_ini.m +SRCS_PLUGINS = OFPluginTests.m +SRCS_SOCKETS = OFSocketTests.m +SRCS_SUBPROCESSES = OFSubprocessTests.m +SRCS_THREADS = OFThreadTests.m + +include ../buildsys.mk + +testfile_bin.m: testfile.bin + ${SHELL} ../utils/objfw-embed testfile.bin testfile.bin $@ +testfile_ini.m: testfile.ini + ${SHELL} ../utils/objfw-embed testfile.ini testfile.ini $@ + +.PHONY: run run-on-ios run-on-android +run: + rm -f libobjfw.so.${OBJFW_LIB_MAJOR} + rm -f libobjfw.so.${OBJFW_LIB_MAJOR_MINOR} + rm -f objfw${OBJFW_LIB_MAJOR}.dll libobjfw.${OBJFW_LIB_MAJOR}.dylib + rm -f libobjfwrt.so.${OBJFWRT_LIB_MAJOR} + rm -f libobjfwrt.so.${OBJFWRT_LIB_MAJOR_MINOR} + rm -f objfwrt${OBJFWRT_LIB_MAJOR}.dll + rm -f libobjfwrt.${OBJFWRT_LIB_MAJOR}.dylib + if test -f ../src/libobjfw.so; then \ + ${LN_S} ../src/libobjfw.so libobjfw.so.${OBJFW_LIB_MAJOR}; \ + ${LN_S} ../src/libobjfw.so \ + libobjfw.so.${OBJFW_LIB_MAJOR_MINOR}; \ + elif test -f ../src/libobjfw.so.${OBJFW_LIB_MAJOR_MINOR}; then \ + ${LN_S} ../src/libobjfw.so.${OBJFW_LIB_MAJOR_MINOR} \ + libobjfw.so.${OBJFW_LIB_MAJOR_MINOR}; \ + fi + if test -f ../src/objfw${OBJFW_LIB_MAJOR}.dll; then \ + ${LN_S} ../src/objfw${OBJFW_LIB_MAJOR}.dll \ + objfw${OBJFW_LIB_MAJOR}.dll; \ + fi + if test -f ../src/libobjfw.dylib; then \ + ${LN_S} ../src/libobjfw.dylib \ + libobjfw.${OBJFW_LIB_MAJOR}.dylib; \ + fi + if test -f ../src/runtime/libobjfwrt.so; then \ + ${LN_S} ../src/runtime/libobjfwrt.so \ + libobjfwrt.so.${OBJFWRT_LIB_MAJOR}; \ + ${LN_S} ../src/runtime/libobjfwrt.so \ + libobjfwrt.so.${OBJFWRT_LIB_MAJOR_MINOR}; \ + elif test -f ../src/runtime/libobjfwrt.so.${OBJFWRT_LIB_MAJOR_MINOR}; then \ + ${LN_S} ../src/runtime/libobjfwrt.so.${OBJFWRT_LIB_MAJOR_MINOR} libobjfwrt.so.${OBJFWRT_LIB_MAJOR_MINOR}; \ + fi + if test -f ../src/runtime/objfwrt${OBJFWRT_LIB_MAJOR}.dll; then \ + ${LN_S} ../src/runtime/objfwrt${OBJFWRT_LIB_MAJOR}.dll \ + objfwrt${OBJFWRT_LIB_MAJOR}.dll; \ + fi + if test -f ../src/runtime/libobjfwrt.dylib; then \ + ${LN_S} ../src/runtime/libobjfwrt.dylib \ + libobjfwrt.${OBJFWRT_LIB_MAJOR}.dylib; \ + fi + LD_LIBRARY_PATH=.$${LD_LIBRARY_PATH+:}$$LD_LIBRARY_PATH \ + DYLD_FRAMEWORK_PATH=../src:../src/runtime$${DYLD_FRAMEWORK_PATH+:}$$DYLD_FRAMEWORK_PATH \ + DYLD_LIBRARY_PATH=.$${DYLD_LIBRARY_PATH+:}$$DYLD_LIBRARY_PATH \ + LIBRARY_PATH=.$${LIBRARY_PATH+:}$$LIBRARY_PATH \ + ASAN_OPTIONS=allocator_may_return_null=1 \ + ${WRAPPER} ./${PROG_NOINST}; EXIT=$$?; \ + rm -f libobjfw.so.${OBJFW_LIB_MAJOR}; \ + rm -f libobjfw.so.${OBJFW_LIB_MAJOR_MINOR}; \ + rm -f objfw${OBJFW_LIB_MAJOR}.dll; \ + rm -f libobjfw.${OBJFW_LIB_MAJOR}.dylib; \ + rm -f libobjfwrt.so.${OBJFWRT_LIB_MAJOR}; \ + rm -f libobjfwrt.so.${OBJFWRT_LIB_MAJOR_MINOR}; \ + rm -f objfwrt${OBJFWRT_LIB_MAJOR}.dll; \ + rm -f libobjfwrt.${OBJFWRT_LIB_MAJOR}.dylib; \ + exit $$EXIT + +run-on-android: all + echo "Uploading files to Android device..." + if test -f ../src/libobjfw.so; then \ + adb push ../src/libobjfw.so \ + /data/local/tmp/objfw/libobjfw.so.${OBJFW_LIB_MAJOR}; \ + fi + if test -f ../src/runtime/libobjfwrt.so; then \ + adb push ../src/runtime/libobjfwrt.so \ + /data/local/tmp/objfw/libobjfwrt.so.${OBJFWRT_LIB_MAJOR}; \ + fi + adb push tests /data/local/tmp/objfw/tests + adb push testfile.txt /data/local/tmp/objfw/testfile.txt + if test -f plugin/TestPlugin.so; then \ + adb push plugin/TestPlugin.so \ + /data/local/tmp/objfw/plugin/TestPlugin.so; \ + fi + echo "Running tests binary on Android device..." + adb shell 'cd /data/local/tmp/objfw && LD_LIBRARY_PATH=. exec ${WRAPPER} ./tests' + +EBOOT.PBP: ${PROG_NOINST} + psp-fixup-imports ${PROG_NOINST} + mksfo "ObjFW Tests" PARAM.SFO + psp-strip ${PROG_NOINST} + pack-pbp $@ PARAM.SFO NULL NULL NULL NULL NULL ${PROG_NOINST} NULL + +boot.dol: ${PROG_NOINST} + elf2dol ${PROG_NOINST} $@ + +${PROG_NOINST}: ${LIBOBJFW_DEP} ${LIBOBJFWRT_DEP} ../src/test/libobjfwtest.a + +${PROG_NOINST}.3dsx: ${PROG_NOINST} + 3dsxtool $< $@ + +${PROG_NOINST}.arm9: ${PROG_NOINST} + arm-none-eabi-objcopy -O binary $< $@ + +${PROG_NOINST}.nds: ${PROG_NOINST}.arm9 testfile.txt + rm -fr nds-data + mkdir -p nds-data + cp testfile.txt nds-data + ndstool -c $@ -9 ${PROG_NOINST} -d nds-data + rm -fr nds-data + +${PROG_NOINST}.nro: ${PROG_NOINST} testfile.txt + rm -fr romfs + mkdir -p romfs + cp testfile.txt romfs + nacptool --create "ObjFW tests" "Jonathan Schleifer" \ + "${PACKAGE_VERSION}" tests.nacp + elf2nro ${PROG_NOINST} $@ --nacp=tests.nacp --romfsdir=romfs + rm -fr romfs tests.nacp + +${PROG_NOINST}.rpx: ${PROG_NOINST} + elf2rpl $< $@ + +CPPFLAGS += -I../src \ + -I../src/exceptions \ + -I../src/runtime \ + -I../src/test \ + -I.. \ + -DOBJFWTEST_LOCAL_INCLUDES \ + -DPROG_SUFFIX=\"${PROG_SUFFIX}\" +# Repetition is required for Wii U, as otherwise it cannot find main. Just +# moving -lobjfwtest later doesn't work either, as then the linker cannot find +# ObjFW symbols. So the only solution is to list everything twice. +LIBS := -L../src/test \ + -lobjfwtest \ + ${TESTS_LIBS} \ + ${LIBS} \ + -lobjfwtest \ + ${TESTS_LIBS} \ + ${LIBS} +LDFLAGS += ${MAP_LDFLAGS} +LD = ${OBJC} ADDED new_tests/OFArrayTests.h Index: new_tests/OFArrayTests.h ================================================================== --- new_tests/OFArrayTests.h +++ new_tests/OFArrayTests.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2008-2024 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#import "ObjFW.h" +#import "ObjFWTest.h" + +@interface OFArrayTests: OTTestCase +{ + OFArray *_array; +} + +- (Class)arrayClass; +@end ADDED new_tests/OFArrayTests.m Index: new_tests/OFArrayTests.m ================================================================== --- new_tests/OFArrayTests.m +++ new_tests/OFArrayTests.m @@ -0,0 +1,342 @@ +/* + * Copyright (c) 2008-2024 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#include "config.h" + +#import "OFArrayTests.h" + +@interface CustomArray: OFArray +{ + OFMutableArray *_array; +} +@end + +static OFString *const cArray[] = { + @"Foo", + @"Bar", + @"Baz" +}; + +@implementation OFArrayTests +- (Class)arrayClass +{ + return [CustomArray class]; +} + +- (void)setUp +{ + [super setUp]; + + _array = [[self.arrayClass alloc] + initWithObjects: cArray + count: sizeof(cArray) / sizeof(*cArray)]; +} + +- (void)dealloc +{ + [_array release]; + + [super dealloc]; +} + +- (void)testArray +{ + OFArray *array = [self.arrayClass array]; + + OTAssertNotNil(array); + OTAssertEqual(array.count, 0); +} + +- (void)testArrayWithObjects +{ + OFArray *array = [self.arrayClass arrayWithObjects: + @"Foo", @"Bar", @"Baz", nil]; + + OTAssertNotNil(array); + OTAssertEqual(array.count, 3); + OTAssertEqualObjects([array objectAtIndex: 0], @"Foo"); + OTAssertEqualObjects([array objectAtIndex: 1], @"Bar"); + OTAssertEqualObjects([array objectAtIndex: 2], @"Baz"); +} + +- (void)testArrayWithObjectsCount +{ + OFArray *array1 = [self.arrayClass arrayWithObjects: + @"Foo", @"Bar", @"Baz", nil]; + OFArray *array2 = [self.arrayClass arrayWithObjects: cArray count: 3]; + + OTAssertEqualObjects(array1, array2); +} + +- (void)testDescription +{ + OTAssertEqualObjects(_array.description, + @"(\n\tFoo,\n\tBar,\n\tBaz\n)"); +} + +- (void)testCount +{ + OTAssertEqual(_array.count, 3); +} + +- (void)testIsEqual +{ + OFArray *array = [self.arrayClass arrayWithObjects: cArray count: 3]; + + OTAssertEqualObjects(array, _array); + OTAssertNotEqual(array, _array); +} + +- (void)testObjectAtIndex +{ + OTAssertEqualObjects([_array objectAtIndex: 0], cArray[0]); + OTAssertEqualObjects([_array objectAtIndex: 1], cArray[1]); + OTAssertEqualObjects([_array objectAtIndex: 2], cArray[2]); +} + +- (void)testObjectAtIndexFailsWhenOutOfRange +{ + OTAssertThrowsSpecific([_array objectAtIndex: _array.count], + OFOutOfRangeException); +} + +- (void)testContainsObject +{ + OTAssertTrue([_array containsObject: cArray[1]]); + OTAssertFalse([_array containsObject: @"nonexistent"]); +} + +- (void)testContainsObjectIdenticalTo +{ + OTAssertTrue([_array containsObjectIdenticalTo: cArray[1]]); + OTAssertFalse([_array containsObjectIdenticalTo: + [OFString stringWithString: cArray[1]]]); +} + +- (void)testIndexOfObject +{ + OTAssertEqual([_array indexOfObject: cArray[1]], 1); + OTAssertEqual([_array indexOfObject: @"nonexistent"], OFNotFound); +} + +- (void)testIndexOfObjectIdenticalTo +{ + OTAssertEqual([_array indexOfObjectIdenticalTo: cArray[1]], 1); + OTAssertEqual([_array indexOfObjectIdenticalTo: + [OFString stringWithString: cArray[1]]], + OFNotFound); +} + +- (void)objectsInRange +{ + OTAssertEqualObjects([_array objectsInRange: OFMakeRange(1, 2)], + ([self.arrayClass arrayWithObjects: cArray[1], cArray[2], nil])); +} + +- (void)testEnumerator +{ + OFEnumerator *enumerator = [_array objectEnumerator]; + + OTAssertEqualObjects([enumerator nextObject], cArray[0]); + OTAssertEqualObjects([enumerator nextObject], cArray[1]); + OTAssertEqualObjects([enumerator nextObject], cArray[2]); + OTAssertNil([enumerator nextObject]); +} + +- (void)testFastEnumeration +{ + size_t i = 0; + + for (OFString *object in _array) { + OTAssert(i < 3); + OTAssertEqualObjects(object, cArray[i++]); + } +} + +- (void)testComponentsJoinedByString +{ + OFArray *array; + + array = [self.arrayClass arrayWithObjects: @"", @"a", @"b", @"c", nil]; + OTAssertEqualObjects([array componentsJoinedByString: @" "], + @" a b c"); + + array = [self.arrayClass arrayWithObject: @"foo"]; + OTAssertEqualObjects([array componentsJoinedByString: @" "], @"foo"); +} + +- (void)testComponentsJoinedByStringOptions +{ + OFArray *array; + + array = [self.arrayClass + arrayWithObjects: @"", @"foo", @"", @"", @"bar", @"", nil]; + OTAssertEqualObjects( + [array componentsJoinedByString: @" " + options: OFArraySkipEmptyComponents], + @"foo bar"); +} + +- (void)testSortedArray +{ + OFArray *array = [_array arrayByAddingObjectsFromArray: + [OFArray arrayWithObjects: @"0", @"z", nil]]; + + OTAssertEqualObjects([array sortedArray], + ([OFArray arrayWithObjects: @"0", @"Bar", @"Baz", @"Foo", @"z", + nil])); + + OTAssertEqualObjects( + [array sortedArrayUsingSelector: @selector(compare:) + options: OFArraySortDescending], + ([OFArray arrayWithObjects: @"z", @"Foo", @"Baz", @"Bar", @"0", + nil])); +} + +- (void)testReversedArray +{ + OTAssertEqualObjects(_array.reversedArray, + ([OFArray arrayWithObjects: cArray[2], cArray[1], cArray[0], nil])); +} + +#ifdef OF_HAVE_BLOCKS +- (void)testEnumerateObjectsUsingBlock +{ + __block size_t i = 0; + + [_array enumerateObjectsUsingBlock: + ^ (id object, size_t idx, bool *stop) { + OTAssertEqualObjects(object, [_array objectAtIndex: i++]); + }]; + + OTAssertEqual(i, _array.count); +} + +- (void)testMappedArrayUsingBlock +{ + OTAssertEqualObjects( + [_array mappedArrayUsingBlock: ^ id (id object, size_t idx) { + switch (idx) { + case 0: + return @"foobar"; + case 1: + return @"qux"; + } + + return @""; + }].description, + @"(\n\tfoobar,\n\tqux,\n\t\n)"); +} + +- (void)testFilteredArrayUsingBlock +{ + OTAssertEqualObjects( + [_array filteredArrayUsingBlock: ^ bool (id object, size_t idx) { + return [object isEqual: @"Foo"]; + }].description, + @"(\n\tFoo\n)"); + +} + +- (void)testFoldUsingBlock +{ + OTAssertEqualObjects( + [([self.arrayClass arrayWithObjects: [OFMutableString string], + @"foo", @"bar", @"baz", nil]) + foldUsingBlock: ^ id (id left, id right) { + [left appendString: right]; + return left; + }], + @"foobarbaz"); +} +#endif + +- (void)testValueForKey +{ + OTAssertEqualObjects( + [([self.arrayClass arrayWithObjects: @"foo", @"bar", @"quxqux", + nil]) valueForKey: @"length"], + ([self.arrayClass arrayWithObjects: [OFNumber numberWithInt: 3], + [OFNumber numberWithInt: 3], [OFNumber numberWithInt: 6], nil])); + + OTAssertEqualObjects( + [([self.arrayClass arrayWithObjects: @"1", @"2", nil]) + valueForKey: @"@count"], + [OFNumber numberWithInt: 2]); +} +@end + +@implementation CustomArray +- (instancetype)init +{ + self = [super init]; + + @try { + _array = [[OFMutableArray alloc] init]; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (instancetype)initWithObject: (id)object arguments: (va_list)arguments +{ + self = [super init]; + + @try { + _array = [[OFMutableArray alloc] initWithObject: object + arguments: arguments]; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (instancetype)initWithObjects: (id const *)objects count: (size_t)count +{ + self = [super init]; + + @try { + _array = [[OFMutableArray alloc] initWithObjects: objects + count: count]; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (void)dealloc +{ + [_array release]; + + [super dealloc]; +} + +- (id)objectAtIndex: (size_t)idx +{ + return [_array objectAtIndex: idx]; +} + +- (size_t)count +{ + return [_array count]; +} +@end ADDED new_tests/OFCharacterSetTests.m Index: new_tests/OFCharacterSetTests.m ================================================================== --- new_tests/OFCharacterSetTests.m +++ new_tests/OFCharacterSetTests.m @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2008-2024 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#include "config.h" + +#import "ObjFW.h" +#import "ObjFWTest.h" + +#import "OFCharacterSet.h" +#import "OFBitSetCharacterSet.h" +#import "OFRangeCharacterSet.h" + +@interface OFCharacterSetTests: OTTestCase +@end + +@interface CustomCharacterSet: OFCharacterSet +@end + +@implementation CustomCharacterSet +- (bool)characterIsMember: (OFUnichar)character +{ + return (character % 2 == 0); +} +@end + +@implementation OFCharacterSetTests +- (void)testCustomCharacterSet +{ + OFCharacterSet *characterSet = + [[[CustomCharacterSet alloc] init] autorelease]; + + for (OFUnichar c = 0; c < 65536; c++) + if (c % 2 == 0) + OTAssertTrue([characterSet characterIsMember: c]); + else + OTAssertFalse([characterSet characterIsMember: c]); +} + +- (void)testBitSetCharacterSet +{ + OFCharacterSet *characterSet = + [OFCharacterSet characterSetWithCharactersInString: @"0123456789"]; + + OTAssertTrue( + [characterSet isKindOfClass: [OFBitSetCharacterSet class]]); + + for (OFUnichar c = 0; c < 65536; c++) + if (c >= '0' && c <= '9') + OTAssertTrue([characterSet characterIsMember: c]); + else if ([characterSet characterIsMember: c]) + OTAssertFalse([characterSet characterIsMember: c]); +} + +- (void)testRangeCharacterSet +{ + OFCharacterSet *characterSet = + [OFCharacterSet characterSetWithRange: OFMakeRange('0', 10)]; + + OTAssertTrue( + [characterSet isKindOfClass: [OFRangeCharacterSet class]]); + + for (OFUnichar c = 0; c < 65536; c++) + if (c >= '0' && c <= '9') + OTAssertTrue([characterSet characterIsMember: c]); + else + OTAssertFalse([characterSet characterIsMember: c]); +} + +- (void)testInvertedCharacterSet +{ + OFCharacterSet *characterSet = [[OFCharacterSet + characterSetWithRange: OFMakeRange('0', 10)] invertedSet]; + + for (OFUnichar c = 0; c < 65536; c++) + if (c >= '0' && c <= '9') + OTAssertFalse([characterSet characterIsMember: c]); + else + OTAssertTrue([characterSet characterIsMember: c]); +} + +- (void)testInvertingInvertedSetReturnsOriginal +{ + OFCharacterSet *characterSet = + [OFCharacterSet characterSetWithRange: OFMakeRange('0', 10)]; + + OTAssertEqual(characterSet, characterSet.invertedSet.invertedSet); +} +@end ADDED new_tests/OFColorTests.m Index: new_tests/OFColorTests.m ================================================================== --- new_tests/OFColorTests.m +++ new_tests/OFColorTests.m @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2008-2024 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#include "config.h" + +#import "ObjFW.h" +#import "ObjFWTest.h" + +@interface OFColorTests: OTTestCase +{ + OFColor *_color; +} +@end + +@implementation OFColorTests +- (void)setUp +{ + [super setUp]; + + _color = [[OFColor alloc] initWithRed: 63.f / 255 + green: 127.f / 255 + blue: 1 + alpha: 1]; +} + +- (void)dealloc +{ + [_color release]; + + [super dealloc]; +} + +#ifdef OF_OBJFW_RUNTIME +- (void)testReturnsTaggedPointer +{ + OTAssertTrue(object_isTaggedPointer(_color)); +} +#endif + +- (void)testGetRedGreenBlueAlpha +{ + float red, green, blue, alpha; + + [_color getRed: &red green: &green blue: &blue alpha: &alpha]; + OTAssertEqual(red, 63.f / 255); + OTAssertEqual(green, 127.f / 255); + OTAssertEqual(blue, 1); + OTAssertEqual(alpha, 1); +} +@end ADDED new_tests/OFConcreteArrayTests.m Index: new_tests/OFConcreteArrayTests.m ================================================================== --- new_tests/OFConcreteArrayTests.m +++ new_tests/OFConcreteArrayTests.m @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2008-2024 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#include "config.h" + +#import "OFArrayTests.h" + +#import "OFConcreteArray.h" + +@interface OFConcreteArrayTests: OFArrayTests +@end + +@implementation OFConcreteArrayTests +- (Class)arrayClass +{ + return [OFConcreteArray class]; +} +@end ADDED new_tests/OFConcreteMutableArrayTests.m Index: new_tests/OFConcreteMutableArrayTests.m ================================================================== --- new_tests/OFConcreteMutableArrayTests.m +++ new_tests/OFConcreteMutableArrayTests.m @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2008-2024 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#include "config.h" + +#import "OFMutableArrayTests.h" + +#import "OFConcreteMutableArray.h" + +@interface OFConcreteMutableArrayTests: OFMutableArrayTests +@end + +static OFString *const cArray[] = { + @"Foo", + @"Bar", + @"Baz" +}; + +@implementation OFConcreteMutableArrayTests +- (Class)arrayClass +{ + return [OFConcreteMutableArray class]; +} + +- (void)testDetectMutationDuringEnumeration +{ + OFEnumerator *enumerator = [_mutableArray objectEnumerator]; + OFString *object; + size_t i; + + i = 0; + while ((object = [enumerator nextObject]) != nil) { + OTAssertEqualObjects(object, cArray[i]); + + [_mutableArray replaceObjectAtIndex: i withObject: @""]; + i++; + } + OTAssertEqual(i, _mutableArray.count); + + [_mutableArray removeObjectAtIndex: 0]; + OTAssertThrowsSpecific([enumerator nextObject], + OFEnumerationMutationException); +} + +- (void)testDetectMutationDuringFastEnumeration +{ + bool detected = false; + size_t i; + + i = 0; + for (OFString *object in _mutableArray) { + OTAssertEqualObjects(object, cArray[i]); + + [_mutableArray replaceObjectAtIndex: i withObject: @""]; + i++; + } + OTAssertEqual(i, _mutableArray.count); + + @try { + for (OFString *object in _mutableArray) { + (void)object; + [_mutableArray removeObjectAtIndex: 0]; + } + } @catch (OFEnumerationMutationException *e) { + detected = true; + } + OTAssertTrue(detected); +} + +#ifdef OF_HAVE_BLOCKS +- (void)testDetectMutationDuringEnumerateObjectsUsingBlock +{ + __block size_t i; + + i = 0; + [_mutableArray enumerateObjectsUsingBlock: + ^ (id object, size_t idx, bool *stop) { + OTAssertEqualObjects(object, cArray[idx]); + + [_mutableArray replaceObjectAtIndex: idx withObject: @""]; + i++; + }]; + OTAssertEqual(i, _mutableArray.count); + + OTAssertThrowsSpecific( + [_mutableArray enumerateObjectsUsingBlock: + ^ (id object, size_t idx, bool *stop) { + [_mutableArray removeObjectAtIndex: 0]; + }], + OFEnumerationMutationException); +} +#endif +@end ADDED new_tests/OFCryptographicHashTests.m Index: new_tests/OFCryptographicHashTests.m ================================================================== --- new_tests/OFCryptographicHashTests.m +++ new_tests/OFCryptographicHashTests.m @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2008-2024 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#include "config.h" + +#include + +#import "ObjFW.h" +#import "ObjFWTest.h" + +@interface OFCryptographicHashTests: OTTestCase +{ + OFStream *_stream; +} +@end + +const unsigned char testFileMD5[16] = + "\x00\x8B\x9D\x1B\x58\xDF\xF8\xFE\xEE\xF3\xAE\x8D\xBB\x68\x2D\x38"; +const unsigned char testFileRIPEMD160[20] = + "\x46\x02\x97\xF5\x85\xDF\xB9\x21\x00\xC8\xF9\x87\xC6\xEC\x84\x0D" + "\xCE\xE6\x08\x8B"; +const unsigned char testFileSHA1[20] = + "\xC9\x9A\xB8\x7E\x1E\xC8\xEC\x65\xD5\xEB\xE4\x2E\x0D\xA6\x80\x96" + "\xF5\x94\xE7\x17"; +const unsigned char testFileSHA224[28] = + "\x27\x69\xD8\x04\x2D\x0F\xCA\x84\x6C\xF1\x62\x44\xBA\x0C\xBD\x46" + "\x64\x5F\x4F\x20\x02\x4D\x15\xED\x1C\x61\x1F\xF7"; +const unsigned char testFileSHA256[32] = + "\x1A\x02\xD6\x46\xF5\xA6\xBA\xAA\xFF\x7F\xD5\x87\xBA\xC3\xF6\xC6" + "\xB5\x67\x93\x8F\x0F\x44\x90\xB8\xF5\x35\x89\xF0\x5A\x23\x7F\x69"; +const unsigned char testFileSHA384[48] = + "\x7E\xDE\x62\xE2\x10\xA5\x1E\x18\x8A\x11\x7F\x78\xD7\xC7\x55\xB6" + "\x43\x94\x1B\xD2\x78\x5C\xCF\xF3\x8A\xB8\x98\x22\xC7\x0E\xFE\xF1" + "\xEC\x53\xE9\x1A\xB3\x51\x70\x8C\x1F\x3F\x56\x12\x44\x01\x91\x54"; +const unsigned char testFileSHA512[64] = + "\x8F\x36\x6E\x3C\x19\x4B\xBB\xC7\x82\xAA\xCD\x7D\x55\xA2\xD3\x29" + "\x29\x97\x6A\x3F\xEB\x9B\xB2\xCB\x75\xC9\xEC\xC8\x10\x07\xD6\x07" + "\x31\x4A\xB1\x30\x97\x82\x58\xA5\x1F\x71\x42\xE6\x56\x07\x99\x57" + "\xB2\xB8\x3B\xA1\x8A\x41\x64\x33\x69\x21\x8C\x2A\x44\x6D\xF2\xA0"; + +@implementation OFCryptographicHashTests +- (void)setUp +{ + OFIRI *IRI; + + [super setUp]; + + IRI = [OFIRI IRIWithString: @"embedded:testfile.bin"]; + _stream = [[OFIRIHandler openItemAtIRI: IRI mode: @"r"] retain]; +} + +- (void)tearDown +{ + [_stream close]; + + [super tearDown]; +} + +- (void)dealloc +{ + [_stream release]; + + [super dealloc]; +} + +- (void)testHash: (Class)hashClass + expectedDigest: (const unsigned char *)expectedDigest +{ + id hash = + [hashClass hashWithAllowsSwappableMemory: true]; + id copy; + + OTAssertNotNil(hash); + + while (!_stream.atEndOfStream) { + char buffer[64]; + size_t length = [_stream readIntoBuffer: buffer length: 64]; + [hash updateWithBuffer: buffer length: length]; + } + + copy = [[hash copy] autorelease]; + + [hash calculate]; + [copy calculate]; + + OTAssertEqual(memcmp(hash.digest, expectedDigest, hash.digestSize), 0); + OTAssertEqual(memcmp(hash.digest, expectedDigest, hash.digestSize), 0); + + OTAssertThrowsSpecific([hash updateWithBuffer: "" length: 1], + OFHashAlreadyCalculatedException); +} + +- (void)testMD5 +{ + [self testHash: [OFMD5Hash class] expectedDigest: testFileMD5]; +} + +- (void)testRIPEMD160 +{ + [self testHash: [OFRIPEMD160Hash class] + expectedDigest: testFileRIPEMD160]; +} + +- (void)testSHA1 +{ + [self testHash: [OFSHA1Hash class] expectedDigest: testFileSHA1]; +} + +- (void)testSHA224 +{ + [self testHash: [OFSHA224Hash class] expectedDigest: testFileSHA224]; +} + +- (void)testSHA256 +{ + [self testHash: [OFSHA256Hash class] expectedDigest: testFileSHA256]; +} + +- (void)testSHA384 +{ + [self testHash: [OFSHA384Hash class] expectedDigest: testFileSHA384]; +} + +- (void)testSHA512 +{ + [self testHash: [OFSHA512Hash class] expectedDigest: testFileSHA512]; +} +@end ADDED new_tests/OFDateTests.m Index: new_tests/OFDateTests.m ================================================================== --- new_tests/OFDateTests.m +++ new_tests/OFDateTests.m @@ -0,0 +1,198 @@ +/* + * Copyright (c) 2008-2024 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#include "config.h" + +#include + +#import "ObjFW.h" +#import "ObjFWTest.h" + +#import "OFStrPTime.h" + +@interface OFDateTests: OTTestCase +{ + OFDate *_date[2]; +} +@end + +@implementation OFDateTests +- (void)setUp +{ + [super setUp]; + + _date[0] = [[OFDate alloc] initWithTimeIntervalSince1970: 0]; + _date[1] = [[OFDate alloc] + initWithTimeIntervalSince1970: 3600 * 25 + 5.000002]; +} + +- (void)dealloc +{ + [_date[0] release]; + [_date[1] release]; + + [super dealloc]; +} + +- (void)testStrPTime +{ + struct tm tm; + int16_t timeZone; + const char *dateString = "Wed, 09 Jun 2021 +0200x"; + + OTAssertEqual(OFStrPTime(dateString, "%a, %d %b %Y %z", &tm, &timeZone), + dateString + 22); + OTAssertEqual(tm.tm_wday, 3); + OTAssertEqual(tm.tm_mday, 9); + OTAssertEqual(tm.tm_mon, 5); + OTAssertEqual(tm.tm_year, 2021 - 1900); + OTAssertEqual(timeZone, 2 * 60); +} + +- (void)testDateByAddingTimeInterval +{ + OTAssertEqualObjects( + [_date[0] dateByAddingTimeInterval: 3600 * 25 + 5.000002], + _date[1]); +} + +- (void)testDescription +{ + OTAssertEqualObjects(_date[0].description, @"1970-01-01T00:00:00Z"); + OTAssertEqualObjects(_date[1].description, @"1970-01-02T01:00:05Z"); +} + +- (void)testDateWithDateStringFormat +{ + OTAssertEqualObjects( + [[OFDate dateWithDateString: @"2000-06-20T12:34:56+0200" + format: @"%Y-%m-%dT%H:%M:%S%z"] description], + @"2000-06-20T10:34:56Z"); +} + +- (void)testDateWithDateStringFormatFailsWithTrailingCharacters +{ + OTAssertThrowsSpecific( + [OFDate dateWithDateString: @"2000-06-20T12:34:56+0200x" + format: @"%Y-%m-%dT%H:%M:%S%z"], + OFInvalidFormatException); +} + +- (void)testDateWithLocalDateStringFormatFormat +{ + OTAssertEqualObjects( + [[OFDate dateWithLocalDateString: @"2000-06-20T12:34:56" + format: @"%Y-%m-%dT%H:%M:%S"] + localDateStringWithFormat: @"%Y-%m-%dT%H:%M:%S"], + @"2000-06-20T12:34:56"); + + OTAssertEqualObjects( + [[OFDate dateWithLocalDateString: @"2000-06-20T12:34:56-0200" + format: @"%Y-%m-%dT%H:%M:%S%z"] + description], + @"2000-06-20T14:34:56Z"); +} + +- (void)testDateWithLocalDateStringFormatFailsWithTrailingCharacters +{ + OTAssertThrowsSpecific( + [OFDate dateWithLocalDateString: @"2000-06-20T12:34:56x" + format: @"%Y-%m-%dT%H:%M:%S"], + OFInvalidFormatException); + + OTAssertThrowsSpecific( + [OFDate dateWithLocalDateString: @"2000-06-20T12:34:56+0200x" + format: @"%Y-%m-%dT%H:%M:%S%z"], + OFInvalidFormatException); +} + +- (void)testIsEqual +{ + OTAssertEqualObjects(_date[0], + [OFDate dateWithTimeIntervalSince1970: 0]); + + OTAssertNotEqualObjects(_date[0], + [OFDate dateWithTimeIntervalSince1970: 0.0000001]); +} + +- (void)testCompare +{ + OTAssertEqual([_date[0] compare: _date[1]], OFOrderedAscending); +} + +- (void)testSecond +{ + OTAssertEqual(_date[0].second, 0); + OTAssertEqual(_date[1].second, 5); +} + +- (void)testMicrosecond +{ + OTAssertEqual(_date[0].microsecond, 0); + OTAssertEqual(_date[1].microsecond, 2); +} + +- (void)testMinute +{ + OTAssertEqual(_date[0].minute, 0); + OTAssertEqual(_date[1].minute, 0); +} + +- (void)testHour +{ + OTAssertEqual(_date[0].hour, 0); + OTAssertEqual(_date[1].hour, 1); +} + +- (void)testDayOfMonth +{ + OTAssertEqual(_date[0].dayOfMonth, 1); + OTAssertEqual(_date[1].dayOfMonth, 2); +} + +- (void)testMonthOfYear +{ + OTAssertEqual(_date[0].monthOfYear, 1); + OTAssertEqual(_date[1].monthOfYear, 1); +} + +- (void)testYear +{ + OTAssertEqual(_date[0].year, 1970); + OTAssertEqual(_date[1].year, 1970); +} + +- (void)testDayOfWeek +{ + OTAssertEqual(_date[0].dayOfWeek, 4); + OTAssertEqual(_date[1].dayOfWeek, 5); +} + +- (void)testDayOfYear +{ + OTAssertEqual(_date[0].dayOfYear, 1); + OTAssertEqual(_date[1].dayOfYear, 2); +} + +- (void)testEarlierDate +{ + OTAssertEqualObjects([_date[0] earlierDate: _date[1]], _date[0]); +} + +- (void)testLaterDate +{ + OTAssertEqualObjects([_date[0] laterDate: _date[1]], _date[1]); +} +@end ADDED new_tests/OFHMACTests.m Index: new_tests/OFHMACTests.m ================================================================== --- new_tests/OFHMACTests.m +++ new_tests/OFHMACTests.m @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2008-2024 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#include "config.h" + +#include + +#import "ObjFW.h" +#import "ObjFWTest.h" + +@interface OFHMACTests: OTTestCase +{ + OFStream *_stream; +} +@end + +static const uint8_t key[] = + "yM9h8K6IWnJRvxC/0F8XRWG7RnACDBz8wqK2tbXrYVLoKC3vPLeJikyJSM47tVHc" + "DlXHww9zULAC2sJUlm2Kg1z4oz2aXY3Y1PQSB4VkC/m0DQ7hCI6cAg4TWnKdzWTy" + "cvYGX+Y6HWeDY79/PGSd8fNItme6I8w4HDBqU7BP2sum3jbePJqoiSnhcyJZQTeZ" + "jw0ZXoyrfHgOYD2M+NsTDaGpLblFtQ7n5CczjKtafG40PkEwx1dcrd46U9i3GyTK"; +static const size_t keyLength = sizeof(key); +static const uint8_t MD5Digest[] = + "\xCC\x1F\xEF\x09\x29\xA3\x25\x1A\x06\xA9\x83\x99\xF9\xBC\x8F\x42"; +static const uint8_t SHA1Digest[] = + "\x94\xB9\x0A\x6F\xFB\xA7\x13\x6A\x75\x55" + "\xD5\x7F\x5D\xB7\xF4\xCA\xEB\x4A\xDE\xBF"; +static const uint8_t RIPEMD160Digest[] = + "\x2C\xE1\xED\x41\xC6\xF3\x51\xA8\x04\xD2" + "\xC3\x9B\x08\x33\x3B\xD5\xC9\x00\x39\x50"; +static const uint8_t SHA256Digest[] = + "\xFB\x8C\xDA\x88\xB3\x81\x32\x16\xD7\xD8\x62\xD4\xA6\x26\x9D\x77" + "\x01\x99\x62\x65\x29\x02\x41\xE6\xEF\xA1\x02\x31\xA8\x9D\x77\x5D"; +static const uint8_t SHA384Digest[] = + "\x2F\x4A\x47\xAE\x13\x8E\x96\x52\xF1\x8F\x05\xFD\x65\xCD\x9A\x97" + "\x93\x2F\xC9\x02\xD6\xC6\xAB\x2E\x15\x76\xC0\xA7\xA0\x05\xF4\xEF" + "\x14\x52\x33\x4B\x9C\x5F\xD8\x07\x4E\x98\xAE\x97\x46\x29\x24\xB4"; +static const uint8_t SHA512Digest[] = + "\xF5\x8C\x3F\x9C\xA2\x2F\x0A\xF3\x26\xD8\xC0\x7E\x20\x63\x88\x61" + "\xC9\xE1\x1F\xD7\xC7\xE5\x59\x33\xD5\x2F\xAF\x56\x1C\x94\xC8\xA4" + "\x61\xB3\xF9\x1A\xE3\x09\x43\xA6\x5B\x85\xB1\x50\x5B\xCB\x1A\x2E" + "\xB7\xE8\x87\xC1\x73\x19\x63\xF6\xA2\x91\x8D\x7E\x2E\xCC\xEC\x99"; + +@implementation OFHMACTests +- (void)setUp +{ + OFIRI *IRI; + + [super setUp]; + + IRI = [OFIRI IRIWithString: @"embedded:testfile.bin"]; + _stream = [[OFIRIHandler openItemAtIRI: IRI mode: @"r"] retain]; +} + +- (void)tearDown +{ + [_stream close]; + + [super tearDown]; +} + +- (void)dealloc +{ + [_stream release]; + + [super dealloc]; +} + +- (void)testWithHashClass: (Class)hashClass + expectedDigest: (const unsigned char *)expectedDigest +{ + OFHMAC *HMAC = [OFHMAC HMACWithHashClass: hashClass + allowsSwappableMemory: true]; + + OTAssertNotNil(HMAC); + + OTAssertThrowsSpecific([HMAC updateWithBuffer: "" length: 0], + OFInvalidArgumentException); + + [HMAC setKey: key length: keyLength]; + + while (!_stream.atEndOfStream) { + char buffer[64]; + size_t length = [_stream readIntoBuffer: buffer length: 64]; + [HMAC updateWithBuffer: buffer length: length]; + } + + [HMAC calculate]; + + OTAssertEqual(memcmp(HMAC.digest, expectedDigest, HMAC.digestSize), 0); +} + +- (void)testHMACWithMD5 +{ + [self testWithHashClass: [OFMD5Hash class] expectedDigest: MD5Digest]; +} + +- (void)testHMACWithRIPEMD160 +{ + [self testWithHashClass: [OFRIPEMD160Hash class] + expectedDigest: RIPEMD160Digest]; +} + +- (void)testHMACWithSHA1 +{ + [self testWithHashClass: [OFSHA1Hash class] expectedDigest: SHA1Digest]; +} + +- (void)testHMACWithSHA256 +{ + [self testWithHashClass: [OFSHA256Hash class] + expectedDigest: SHA256Digest]; +} + +- (void)testHMACWithSHA384 +{ + [self testWithHashClass: [OFSHA384Hash class] + expectedDigest: SHA384Digest]; +} + +- (void)testHMACWithSHA512 +{ + [self testWithHashClass: [OFSHA512Hash class] + expectedDigest: SHA512Digest]; +} +@end ADDED new_tests/OFINIFileTests.m Index: new_tests/OFINIFileTests.m ================================================================== --- new_tests/OFINIFileTests.m +++ new_tests/OFINIFileTests.m @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2008-2024 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#include "config.h" + +#import "ObjFW.h" +#import "ObjFWTest.h" + +@interface OFINIFileTests: OTTestCase +{ + OFINIFile *_file; +} +@end + +@implementation OFINIFileTests +- (void)setUp +{ + OFIRI *IRI; + + [super setUp]; + + IRI = [OFIRI IRIWithString: @"embedded:testfile.ini"]; + _file = [[OFINIFile alloc] initWithIRI: IRI + encoding: OFStringEncodingISO8859_1]; +} + +- (void)dealloc +{ + [_file release]; + + [super dealloc]; +} + +- (void)testCategoryForName +{ + OTAssertNotNil([_file categoryForName: @"tests"]); + OTAssertNotNil([_file categoryForName: @"foobar"]); + OTAssertNotNil([_file categoryForName: @"types"]); +} + +- (void)testStringValueForKey +{ + OTAssertEqualObjects( + [[_file categoryForName: @"tests"] stringValueForKey: @"foo"], + @"bar"); + + OTAssertEqualObjects([[_file categoryForName: @"foobar"] + stringValueForKey: @"quxquxqux"], + @"hello\"wörld"); +} + +- (void)testLongLongValueForKeyDefaultValue +{ + OTAssertEqual([[_file categoryForName: @"types"] + longLongValueForKey: @"integer" + defaultValue: 2], + 0x20); +} + +- (void)testBoolValueForKeyDefaultValue +{ + OTAssertTrue([[_file categoryForName: @"types"] + boolValueForKey: @"bool" + defaultValue: false]); +} + +- (void)testFloatValueForKeyDefaultValue +{ + OTAssertEqual([[_file categoryForName: @"types"] + floatValueForKey: @"float" + defaultValue: 1], + 0.5f); +} + +- (void)testDoubleValueForKeyDefaultValue +{ + OTAssertEqual([[_file categoryForName: @"types"] + doubleValueForKey: @"double" + defaultValue: 3], + 0.25); +} + +- (void)testArrayValueForKey +{ + OFINICategory *types = [_file categoryForName: @"types"]; + OFArray *array = [OFArray arrayWithObjects: @"1", @"2", nil]; + + OTAssertEqualObjects([types arrayValueForKey: @"array1"], array); + OTAssertEqualObjects([types arrayValueForKey: @"array2"], array); + OTAssertEqualObjects([types arrayValueForKey: @"array3"], + [OFArray array]); +} + +- (void)testWriteToIRIEncoding +{ + OFString *expectedOutput = @"[tests]\r\n" + @"foo=baz\r\n" + @"foobar=baz\r\n" + @";comment\r\n" + @"new=new\r\n" + @"\r\n" + @"[foobar]\r\n" + @";foobarcomment\r\n" + @"qux=\" asd\"\r\n" + @"quxquxqux=\"hello\\\"wörld\"\r\n" + @"qux2=\"a\\f\"\r\n" + @"qux3=a\fb\r\n" + @"\r\n" + @"[types]\r\n" + @"integer=16\r\n" + @"bool=false\r\n" + @"float=0.25\r\n" + @"array1=foo\r\n" + @"array1=bar\r\n" + @"double=0.75\r\n"; + OFINICategory *tests = [_file categoryForName: @"tests"]; + OFINICategory *foobar = [_file categoryForName: @"foobar"]; + OFINICategory *types = [_file categoryForName: @"types"]; + OFArray *array = [OFArray arrayWithObjects: @"foo", @"bar", nil]; +#if defined(OF_HAVE_FILES) && !defined(OF_NINTENDO_DS) + OFIRI *writeIRI; +#endif + + [tests setStringValue: @"baz" forKey: @"foo"]; + [tests setStringValue: @"new" forKey: @"new"]; + [foobar setStringValue: @"a\fb" forKey: @"qux3"]; + [types setLongLongValue: 0x10 forKey: @"integer"]; + [types setBoolValue: false forKey: @"bool"]; + [types setFloatValue: 0.25f forKey: @"float"]; + [types setDoubleValue: 0.75 forKey: @"double"]; + [types setArrayValue: array forKey: @"array1"]; + + [foobar removeValueForKey: @"quxqux "]; + [types removeValueForKey: @"array2"]; + + /* FIXME: Find a way to write files on Nintendo DS */ +#if defined(OF_HAVE_FILES) && !defined(OF_NINTENDO_DS) + writeIRI = [OFSystemInfo temporaryDirectoryIRI]; + if (writeIRI == nil) + writeIRI = [[OFFileManager defaultManager] currentDirectoryIRI]; + writeIRI = [writeIRI IRIByAppendingPathComponent: @"objfw-tests.ini" + isDirectory: false]; + + [_file writeToIRI: writeIRI + encoding: OFStringEncodingISO8859_1]; + + @try { + OTAssertEqualObjects([OFString + stringWithContentsOfIRI: writeIRI + encoding: OFStringEncodingISO8859_1], + expectedOutput); + } @finally { + [[OFFileManager defaultManager] removeItemAtIRI: writeIRI]; + } +#else + (void)expectedOutput; +#endif +} +@end ADDED new_tests/OFIRITests.m Index: new_tests/OFIRITests.m ================================================================== --- new_tests/OFIRITests.m +++ new_tests/OFIRITests.m @@ -0,0 +1,539 @@ +/* + * Copyright (c) 2008-2024 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#include "config.h" + +#import "ObjFW.h" +#import "ObjFWTest.h" + +@interface OFIRITests: OTTestCase +{ + OFIRI *_IRI[11]; + OFMutableIRI *_mutableIRI; +} +@end + +static OFString *IRI0String = @"ht+tp://us%3Aer:p%40w@ho%3Ast:1234/" + @"pa%3Fth?que%23ry=1&f%26oo=b%3dar#frag%23ment"; + +@implementation OFIRITests +- (void)setUp +{ + [super setUp]; + + _IRI[0] = [[OFIRI alloc] initWithString: IRI0String]; + _IRI[1] = [[OFIRI alloc] initWithString: @"http://foo:80"]; + _IRI[2] = [[OFIRI alloc] initWithString: @"http://bar/"]; + _IRI[3] = [[OFIRI alloc] initWithString: @"file:///etc/passwd"]; + _IRI[4] = [[OFIRI alloc] + initWithString: @"http://foo/bar/qux/foo%2fbar"]; + _IRI[5] = [[OFIRI alloc] initWithString: @"https://[12:34::56:abcd]/"]; + _IRI[6] = [[OFIRI alloc] + initWithString: @"https://[12:34::56:abcd]:234/"]; + _IRI[7] = [[OFIRI alloc] initWithString: @"urn:qux:foo"]; + _IRI[8] = [[OFIRI alloc] initWithString: @"file:/foo?query#frag"]; + _IRI[9] = [[OFIRI alloc] + initWithString: @"file:foo@bar/qux?query#frag"]; + _IRI[10] = [[OFIRI alloc] initWithString: @"http://ä/ö?ü"]; + + _mutableIRI = [[OFMutableIRI alloc] initWithScheme: @"dummy"]; +} + +- (void)dealloc +{ + for (uint_fast8_t i = 0; i < 11; i++) + [_IRI[i] release]; + + [_mutableIRI release]; + + [super dealloc]; +} + +- (void)testIRIWithStringFailsWithInvalidCharacters +{ + OTAssertThrowsSpecific([OFIRI IRIWithString: @"ht,tp://foo"], + OFInvalidFormatException); + + OTAssertThrowsSpecific([OFIRI IRIWithString: @"http://f`oo"], + OFInvalidFormatException); + + OTAssertThrowsSpecific([OFIRI IRIWithString: @"http://foo/`"], + OFInvalidFormatException); + + OTAssertThrowsSpecific([OFIRI IRIWithString: @"http://foo/foo?`"], + OFInvalidFormatException); + + OTAssertThrowsSpecific([OFIRI IRIWithString: @"http://foo/foo?foo#`"], + OFInvalidFormatException); + + OTAssertThrowsSpecific([OFIRI IRIWithString: @"https://[g]/"], + OFInvalidFormatException); + + OTAssertThrowsSpecific([OFIRI IRIWithString: @"https://[f]:/"], + OFInvalidFormatException); + + OTAssertThrowsSpecific([OFIRI IRIWithString: @"https://[f]:f/"], + OFInvalidFormatException); + + OTAssertThrowsSpecific([OFIRI IRIWithString: @"foo:"], + OFInvalidFormatException); +} + +- (void)testIRIWithStringRelativeToIRI +{ + OTAssertEqualObjects([[OFIRI IRIWithString: @"/foo" + relativeToIRI: _IRI[0]] string], + @"ht+tp://us%3Aer:p%40w@ho%3Ast:1234/foo"); + + OTAssertEqualObjects( + [[OFIRI IRIWithString: @"foo/bar?q" + relativeToIRI: [OFIRI IRIWithString: @"http://h/qux/quux"]] + string], + @"http://h/qux/foo/bar?q"); + + OTAssertEqualObjects( + [[OFIRI IRIWithString: @"foo/bar" + relativeToIRI: [OFIRI IRIWithString: @"http://h/qux/?x"]] + string], + @"http://h/qux/foo/bar"); + + OTAssertEqualObjects([[OFIRI IRIWithString: @"http://foo/?q" + relativeToIRI: _IRI[0]] string], + @"http://foo/?q"); + + OTAssertEqualObjects( + [[OFIRI IRIWithString: @"foo" + relativeToIRI: [OFIRI IRIWithString: @"http://foo/bar"]] + string], + @"http://foo/foo"); + + OTAssertEqualObjects( + [[OFIRI IRIWithString: @"foo" + relativeToIRI: [OFIRI IRIWithString: @"http://foo"]] + string], + @"http://foo/foo"); +} + +- (void)testIRIWithStringRelativeToIRIFailsWithInvalidCharacters +{ + OTAssertThrowsSpecific( + [OFIRI IRIWithString: @"`" relativeToIRI: _IRI[0]], + OFInvalidFormatException); + + OTAssertThrowsSpecific( + [OFIRI IRIWithString: @"/`" relativeToIRI: _IRI[0]], + OFInvalidFormatException); + + OTAssertThrowsSpecific( + [OFIRI IRIWithString: @"?`" relativeToIRI: _IRI[0]], + OFInvalidFormatException); + + OTAssertThrowsSpecific( + [OFIRI IRIWithString: @"#`" relativeToIRI: _IRI[0]], + OFInvalidFormatException); +} + +#ifdef OF_HAVE_FILES +- (void)testFileIRIWithPath +{ + OTAssertEqualObjects( + [[OFIRI fileIRIWithPath: @"testfile.txt"] fileSystemRepresentation], + [[OFFileManager defaultManager].currentDirectoryPath + stringByAppendingPathComponent: @"testfile.txt"]); +} + +# if defined(OF_WINDOWS) || defined(OF_MSDOS) +- (void)testFileIRWithPathC +{ + OFIRI *IRI = [OFIRI fileIRIWithPath: @"c:\\"]; + OTAssertEqualObjects(IRI.string, @"file:/c:/"); + OTAssertEqualObjects(IRI.fileSystemRepresentation, @"c:\\"); +} +# endif + +# ifdef OF_WINDOWS +- (void)testFileIRIWithPathUNC +{ + OFIRI *IRI; + + IRI = [OFIRI fileIRIWithPath: @"\\\\foo\\bar" isDirectory: false]; + OTAssertEqualObjects(IRI.host, @"foo"); + OTAssertEqualObjects(IRI.path, @"/bar"); + OTAssertEqualObjects(IRI.string, @"file://foo/bar"); + OTAssertEqualObjects(IRI.fileSystemRepresentation, @"\\\\foo\\bar"); + + IRI = [OFIRI fileIRIWithPath: @"\\\\test" isDirectory: true]; + OTAssertEqualObjects(IRI.host, @"test"); + OTAssertEqualObjects(IRI.path, @"/"); + OTAssertEqualObjects(IRI.string, @"file://test/"); + OTAssertEqualObjects(IRI.fileSystemRepresentation, @"\\\\test"); +} +# endif +#endif + +- (void)testString +{ + OTAssertEqualObjects(_IRI[0].string, IRI0String); + OTAssertEqualObjects(_IRI[1].string, @"http://foo:80"); + OTAssertEqualObjects(_IRI[2].string, @"http://bar/"); + OTAssertEqualObjects(_IRI[3].string, @"file:///etc/passwd"); + OTAssertEqualObjects(_IRI[4].string, @"http://foo/bar/qux/foo%2fbar"); + OTAssertEqualObjects(_IRI[5].string, @"https://[12:34::56:abcd]/"); + OTAssertEqualObjects(_IRI[6].string, @"https://[12:34::56:abcd]:234/"); + OTAssertEqualObjects(_IRI[7].string, @"urn:qux:foo"); + OTAssertEqualObjects(_IRI[8].string, @"file:/foo?query#frag"); + OTAssertEqualObjects(_IRI[9].string, @"file:foo@bar/qux?query#frag"); + OTAssertEqualObjects(_IRI[10].string, @"http://ä/ö?ü"); +} + +- (void)testScheme +{ + OTAssertEqualObjects(_IRI[0].scheme, @"ht+tp"); + OTAssertEqualObjects(_IRI[3].scheme, @"file"); + OTAssertEqualObjects(_IRI[8].scheme, @"file"); + OTAssertEqualObjects(_IRI[9].scheme, @"file"); + OTAssertEqualObjects(_IRI[10].scheme, @"http"); +} + +- (void)testUser +{ + OTAssertEqualObjects(_IRI[0].user, @"us:er"); + OTAssertNil(_IRI[3].user); + OTAssertNil(_IRI[9].user); + OTAssertNil(_IRI[10].user); +} + +- (void)testPassword +{ + OTAssertEqualObjects(_IRI[0].password, @"p@w"); + OTAssertNil(_IRI[3].password); + OTAssertNil(_IRI[9].password); + OTAssertNil(_IRI[10].password); +} + +- (void)testHost +{ + OTAssertEqualObjects(_IRI[0].host, @"ho:st"); + OTAssertEqualObjects(_IRI[5].host, @"12:34::56:abcd"); + OTAssertEqualObjects(_IRI[6].host, @"12:34::56:abcd"); + OTAssertNil(_IRI[7].host); + OTAssertNil(_IRI[8].host); + OTAssertNil(_IRI[9].host); + OTAssertEqualObjects(_IRI[10].host, @"ä"); +} + +- (void)testPort +{ + OTAssertEqual(_IRI[0].port.unsignedShortValue, 1234); + OTAssertNil(_IRI[3].port); + OTAssertEqual(_IRI[6].port.unsignedShortValue, 234); + OTAssertNil(_IRI[7].port); + OTAssertNil(_IRI[8].port); + OTAssertNil(_IRI[9].port); + OTAssertNil(_IRI[10].port); +} + +- (void)testPath +{ + OTAssertEqualObjects(_IRI[0].path, @"/pa?th"); + OTAssertEqualObjects(_IRI[3].path, @"/etc/passwd"); + OTAssertEqualObjects(_IRI[7].path, @"qux:foo"); + OTAssertEqualObjects(_IRI[8].path, @"/foo"); + OTAssertEqualObjects(_IRI[9].path, @"foo@bar/qux"); + OTAssertEqualObjects(_IRI[10].path, @"/ö"); +} + +- (void)testPathComponents +{ + OTAssertEqualObjects(_IRI[0].pathComponents, + ([OFArray arrayWithObjects: @"/", @"pa?th", nil])); + + OTAssertEqualObjects(_IRI[3].pathComponents, + ([OFArray arrayWithObjects: @"/", @"etc", @"passwd", nil])); + + OTAssertEqualObjects(_IRI[4].pathComponents, + ([OFArray arrayWithObjects: @"/", @"bar", @"qux", @"foo/bar", + nil])); +} + +- (void)testLastPathComponent +{ + OTAssertEqualObjects([[OFIRI IRIWithString: @"http://host/foo//bar/baz"] + lastPathComponent], + @"baz"); + + OTAssertEqualObjects( + [[OFIRI IRIWithString: @"http://host/foo//bar/baz/"] + lastPathComponent], + @"baz"); + + OTAssertEqualObjects([[OFIRI IRIWithString: @"http://host/foo/"] + lastPathComponent], + @"foo"); + + OTAssertEqualObjects([[OFIRI IRIWithString: @"http://host/"] + lastPathComponent], + @"/"); + + OTAssertEqualObjects(_IRI[4].lastPathComponent, @"foo/bar"); +} + +- (void)testQuery +{ + OTAssertEqualObjects(_IRI[0].query, @"que#ry=1&f&oo=b=ar"); + OTAssertNil(_IRI[3].query); + OTAssertEqualObjects(_IRI[8].query, @"query"); + OTAssertEqualObjects(_IRI[9].query, @"query"); + OTAssertEqualObjects(_IRI[10].query, @"ü"); +} + +- (void)testQueryItems +{ + OTAssertEqualObjects(_IRI[0].queryItems, + ([OFArray arrayWithObjects: + [OFPair pairWithFirstObject: @"que#ry" secondObject: @"1"], + [OFPair pairWithFirstObject: @"f&oo" secondObject: @"b=ar"], nil])); +} + +- (void)testFragment +{ + OTAssertEqualObjects(_IRI[0].fragment, @"frag#ment"); + OTAssertNil(_IRI[3].fragment); + OTAssertEqualObjects(_IRI[8].fragment, @"frag"); + OTAssertEqualObjects(_IRI[9].fragment, @"frag"); +} + +- (void)testCopy +{ + OTAssertEqualObjects(_IRI[0], [[_IRI[0] copy] autorelease]); +} + +- (void)testIsEqual +{ + OTAssertEqualObjects(_IRI[0], [OFIRI IRIWithString: IRI0String]); + OTAssertNotEqualObjects(_IRI[1], _IRI[2]); + OTAssertEqualObjects([OFIRI IRIWithString: @"HTTP://bar/"], _IRI[2]); +} + +- (void)testHash +{ + OTAssertEqual(_IRI[0].hash, [[OFIRI IRIWithString: IRI0String] hash]); + OTAssertNotEqual(_IRI[1].hash, _IRI[2].hash); +} + +- (void)testIRIWithStringFailsWithInvalidFormat +{ + OTAssertThrowsSpecific([OFIRI IRIWithString: @"http"], + OFInvalidFormatException); +} + +- (void)testIRIByAddingPercentEncodingForUnicodeCharacters +{ + OTAssertEqualObjects( + _IRI[10].IRIByAddingPercentEncodingForUnicodeCharacters, + [OFIRI IRIWithString: @"http://%C3%A4/%C3%B6?%C3%BC"]); +} + +- (void)testSetPercentEncodedSchemeFailsWithInvalidCharacters +{ + OTAssertThrowsSpecific(_mutableIRI.scheme = @"%20", + OFInvalidFormatException); +} + +- (void)testSetHost +{ + _mutableIRI.host = @"ho:st"; + OTAssertEqualObjects(_mutableIRI.percentEncodedHost, @"ho%3Ast"); + + _mutableIRI.host = @"12:34:ab"; + OTAssertEqualObjects(_mutableIRI.percentEncodedHost, @"[12:34:ab]"); + + _mutableIRI.host = @"12:34:aB"; + OTAssertEqualObjects(_mutableIRI.percentEncodedHost, @"[12:34:aB]"); + + _mutableIRI.host = @"12:34:g"; + OTAssertEqualObjects(_mutableIRI.percentEncodedHost, @"12%3A34%3Ag"); +} + +- (void)testSetPercentEncodedHost +{ + _mutableIRI.percentEncodedHost = @"ho%3Ast"; + OTAssertEqualObjects(_mutableIRI.host, @"ho:st"); + + _mutableIRI.percentEncodedHost = @"[12:34]"; + OTAssertEqualObjects(_mutableIRI.host, @"12:34"); + + _mutableIRI.percentEncodedHost = @"[12::ab]"; + OTAssertEqualObjects(_mutableIRI.host, @"12::ab"); +} + +- (void)testSetPercentEncodedHostFailsWithInvalidCharacters +{ + OTAssertThrowsSpecific(_mutableIRI.percentEncodedHost = @"/", + OFInvalidFormatException); + + OTAssertThrowsSpecific(_mutableIRI.percentEncodedHost = @"[12:34", + OFInvalidFormatException); + + OTAssertThrowsSpecific(_mutableIRI.percentEncodedHost = @"[a::g]", + OFInvalidFormatException); +} + +- (void)testSetUser +{ + _mutableIRI.user = @"us:er"; + OTAssertEqualObjects(_mutableIRI.percentEncodedUser, @"us%3Aer"); +} + +- (void)testSetPercentEncodedUser +{ + _mutableIRI.percentEncodedUser = @"us%3Aer"; + OTAssertEqualObjects(_mutableIRI.user, @"us:er"); +} + +- (void)testSetPercentEncodedUserFailsWithInvalidCharacters +{ + OTAssertThrowsSpecific(_mutableIRI.percentEncodedHost = @"/", + OFInvalidFormatException); +} + +- (void)testSetPassword +{ + _mutableIRI.password = @"pass:word"; + OTAssertEqualObjects(_mutableIRI.percentEncodedPassword, + @"pass%3Aword"); +} + +- (void)testSetPercentEncodedPassword +{ + _mutableIRI.percentEncodedPassword = @"pass%3Aword"; + OTAssertEqualObjects(_mutableIRI.password, @"pass:word"); +} + +- (void)testSetPercentEncodedPasswordFailsWithInvalidCharacters +{ + OTAssertThrowsSpecific(_mutableIRI.percentEncodedPassword = @"/", + OFInvalidFormatException); +} + +- (void)testSetPath +{ + _mutableIRI.path = @"pa/th@?"; + OTAssertEqualObjects(_mutableIRI.percentEncodedPath, @"pa/th@%3F"); +} + +- (void)testSetPercentEncodedPath +{ + _mutableIRI.percentEncodedPath = @"pa/th@%3F"; + OTAssertEqualObjects(_mutableIRI.path, @"pa/th@?"); +} + +- (void)testSetPercentEncodedPathFailsWithInvalidCharacters +{ + OTAssertThrowsSpecific(_mutableIRI.percentEncodedPath = @"?", + OFInvalidFormatException); +} + +- (void)testSetQuery +{ + _mutableIRI.query = @"que/ry?#"; + OTAssertEqualObjects(_mutableIRI.percentEncodedQuery, @"que/ry?%23"); +} + +- (void)testSetPercentEncodedQuery +{ + _mutableIRI.percentEncodedQuery = @"que/ry?%23"; + OTAssertEqualObjects(_mutableIRI.query, @"que/ry?#"); +} + +- (void)testSetPercentEncodedQueryFailsWithInvalidCharacters +{ + OTAssertThrowsSpecific(_mutableIRI.percentEncodedQuery = @"`", + OFInvalidFormatException); +} + +- (void)testSetQueryItems +{ + _mutableIRI.queryItems = [OFArray arrayWithObjects: + [OFPair pairWithFirstObject: @"foo&bar" secondObject: @"baz=qux"], + [OFPair pairWithFirstObject: @"f=oobar" secondObject: @"b&azqux"], + nil]; + OTAssertEqualObjects(_mutableIRI.percentEncodedQuery, + @"foo%26bar=baz%3Dqux&f%3Doobar=b%26azqux"); +} + +- (void)testSetFragment +{ + _mutableIRI.fragment = @"frag/ment?#"; + OTAssertEqualObjects(_mutableIRI.percentEncodedFragment, + @"frag/ment?%23"); +} + +- (void)testSetPercentEncodedFragment +{ + _mutableIRI.percentEncodedFragment = @"frag/ment?%23"; + OTAssertEqualObjects(_mutableIRI.fragment, @"frag/ment?#"); +} + +- (void)testSetPercentEncodedFragmentFailsWithInvalidCharacters +{ + OTAssertThrowsSpecific(_mutableIRI.percentEncodedFragment = @"`", + OFInvalidFormatException); +} + +-(void)testIRIByAppendingPathComponentIsDirectory +{ + OTAssertEqualObjects([[OFIRI IRIWithString: @"file:///foo/bar"] + IRIByAppendingPathComponent: @"qux" + isDirectory: false], + [OFIRI IRIWithString: @"file:///foo/bar/qux"]); + + OTAssertEqualObjects([[OFIRI IRIWithString: @"file:///foo/bar/"] + IRIByAppendingPathComponent: @"qux" + isDirectory: false], + [OFIRI IRIWithString: @"file:///foo/bar/qux"]); + + OTAssertEqualObjects([[OFIRI IRIWithString: @"file:///foo/bar/"] + IRIByAppendingPathComponent: @"qu?x" + isDirectory: false], + [OFIRI IRIWithString: @"file:///foo/bar/qu%3Fx"]); + + OTAssertEqualObjects([[OFIRI IRIWithString: @"file:///foo/bar/"] + IRIByAppendingPathComponent: @"qu?x" + isDirectory: true], + [OFIRI IRIWithString: @"file:///foo/bar/qu%3Fx/"]); +} + +- (void)testIRIByStandardizingPath +{ + OTAssertEqualObjects([[OFIRI IRIWithString: @"http://foo/bar/.."] + IRIByStandardizingPath], + [OFIRI IRIWithString: @"http://foo/"]); + + OTAssertEqualObjects( + [[OFIRI IRIWithString: @"http://foo/bar/%2E%2E/../qux/"] + IRIByStandardizingPath], + [OFIRI IRIWithString: @"http://foo/bar/qux/"]); + + OTAssertEqualObjects( + [[OFIRI IRIWithString: @"http://foo/bar/./././qux/./"] + IRIByStandardizingPath], + [OFIRI IRIWithString: @"http://foo/bar/qux/"]); + + OTAssertEqualObjects([[OFIRI IRIWithString: @"http://foo/bar/../../qux"] + IRIByStandardizingPath], + [OFIRI IRIWithString: @"http://foo/../qux"]); +} +@end ADDED new_tests/OFInvocationTests.m Index: new_tests/OFInvocationTests.m ================================================================== --- new_tests/OFInvocationTests.m +++ new_tests/OFInvocationTests.m @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2008-2024 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#include "config.h" + +#include + +#if defined(HAVE_COMPLEX_H) && !defined(__STDC_NO_COMPLEX__) +# include +#endif + +#import "ObjFW.h" +#import "ObjFWTest.h" + +@interface OFInvocationTests: OTTestCase +{ + OFInvocation *_invocation; +} +@end + +struct TestStruct { + unsigned char c; + unsigned int i; +}; + +@implementation OFInvocationTests +- (struct TestStruct)invocationTestMethod1: (unsigned char)c + : (unsigned int)i + : (struct TestStruct *)testStructPtr + : (struct TestStruct)testStruct +{ + return testStruct; +} + +- (void)setUp +{ + [super setUp]; + + SEL selector = @selector(invocationTestMethod1::::); + OFMethodSignature *signature = + [self methodSignatureForSelector: selector]; + + _invocation = [[OFInvocation alloc] initWithMethodSignature: signature]; +} + +- (void)dealloc +{ + [_invocation release]; + + [super dealloc]; +} + +- (void)testSetAndGetReturnValue +{ + struct TestStruct testStruct, testStruct2; + + memset(&testStruct, 0xFF, sizeof(testStruct)); + testStruct.c = 0x55; + testStruct.i = 0xAAAAAAAA; + + [_invocation setReturnValue: &testStruct]; + [_invocation getReturnValue: &testStruct2]; + OTAssertEqual(memcmp(&testStruct, &testStruct2, sizeof(testStruct)), 0); +} + +- (void)testSetAndGetArgumentAtIndex +{ + struct TestStruct testStruct, testStruct2; + struct TestStruct *testStructPtr = &testStruct, *testStructPtr2; + unsigned const char c = 0xAA; + unsigned char c2; + const unsigned int i = 0x55555555; + unsigned int i2; + + memset(&testStruct, 0xFF, sizeof(testStruct)); + testStruct.c = 0x55; + testStruct.i = 0xAAAAAAAA; + + memset(&testStruct2, 0, sizeof(testStruct2)); + + [_invocation setArgument: &c atIndex: 2]; + [_invocation setArgument: &i atIndex: 3]; + [_invocation setArgument: &testStructPtr atIndex: 4]; + [_invocation setArgument: &testStruct atIndex: 5]; + + [_invocation getArgument: &c2 atIndex: 2]; + OTAssertEqual(c, c2); + + [_invocation getArgument: &i2 atIndex: 3]; + OTAssertEqual(i, i2); + + [_invocation getArgument: &testStructPtr2 atIndex: 4]; + OTAssertEqual(testStructPtr, testStructPtr2); + + [_invocation getArgument: &testStruct2 atIndex: 5]; + OTAssertEqual(memcmp(&testStruct, &testStruct2, sizeof(testStruct)), 0); +} +@end ADDED new_tests/OFJSONTests.m Index: new_tests/OFJSONTests.m ================================================================== --- new_tests/OFJSONTests.m +++ new_tests/OFJSONTests.m @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2008-2024 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#include "config.h" + +#import "ObjFW.h" +#import "ObjFWTest.h" + +@interface OFJSONTests: OTTestCase +{ + unsigned long long _hashSeed; + OFDictionary *_dictionary; +} +@end + +extern unsigned long long OFHashSeed; + +static OFString *string = @"{\"foo\"\t:'b\\na\\r', \"x\":/*foo*/ [.5\r,0xF," + @"null//bar\n,\"foo\",false]}"; + +@implementation OFJSONTests +- (void)setUp +{ + [super setUp]; + + _hashSeed = OFHashSeed; + OFHashSeed = 0; + + _dictionary = [[OFDictionary alloc] initWithKeysAndObjects: + @"foo", @"b\na\r", + @"x", [OFArray arrayWithObjects: + [OFNumber numberWithFloat: .5f], + [OFNumber numberWithInt: 0xF], + [OFNull null], + @"foo", + [OFNumber numberWithBool: false], + nil], + nil]; +} + +- (void)tearDown +{ + OFHashSeed = _hashSeed; + + [super tearDown]; +} + +- (void)dealloc +{ + [_dictionary release]; + + [super dealloc]; +} + +- (void)testObjectByParsingJSON +{ + OTAssertEqualObjects(string.objectByParsingJSON, _dictionary); +} + +- (void)testJSONRepresentation +{ + OTAssertEqualObjects(_dictionary.JSONRepresentation, + @"{\"x\":[0.5,15,null,\"foo\",false],\"foo\":\"b\\na\\r\"}"); +} + +- (void)testPrettyJSONRepresentation +{ + OTAssertEqualObjects([_dictionary JSONRepresentationWithOptions: + OFJSONRepresentationOptionPretty], + @"{\n\t\"x\": [\n\t\t0.5,\n\t\t15,\n\t\tnull,\n\t\t" + @"\"foo\",\n\t\tfalse\n\t],\n\t\"foo\": \"b\\na\\r\"\n}"); +} + +- (void)testJSON5Representation +{ + OTAssertEqualObjects([_dictionary JSONRepresentationWithOptions: + OFJSONRepresentationOptionJSON5], + @"{x:[0.5,15,null,\"foo\",false],foo:\"b\\\na\\r\"}"); +} + +- (void)testObjectByParsingJSONFailsWithInvalidJSON +{ + OTAssertThrowsSpecific([@"{" objectByParsingJSON], + OFInvalidJSONException); + + OTAssertThrowsSpecific([@"]" objectByParsingJSON], + OFInvalidJSONException); + + OTAssertThrowsSpecific([@"bar" objectByParsingJSON], + OFInvalidJSONException); + + OTAssertThrowsSpecific([@"[\"a\" \"b\"]" objectByParsingJSON], + OFInvalidJSONException); +} + +- (void)testObjectByParsingJSONWithDeepNesting +{ + OTAssertEqualObjects( + @"[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[{}]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]" + .objectByParsingJSON, + [OFArray arrayWithObject: + [OFArray arrayWithObject: [OFArray arrayWithObject: + [OFArray arrayWithObject: [OFArray arrayWithObject: + [OFArray arrayWithObject: [OFArray arrayWithObject: + [OFArray arrayWithObject: [OFArray arrayWithObject: + [OFArray arrayWithObject: [OFArray arrayWithObject: + [OFArray arrayWithObject: [OFArray arrayWithObject: + [OFArray arrayWithObject: [OFArray arrayWithObject: + [OFArray arrayWithObject: [OFArray arrayWithObject: + [OFArray arrayWithObject: [OFArray arrayWithObject: + [OFArray arrayWithObject: [OFArray arrayWithObject: + [OFArray arrayWithObject: [OFArray arrayWithObject: + [OFArray arrayWithObject: [OFArray arrayWithObject: + [OFArray arrayWithObject: [OFArray arrayWithObject: + [OFArray arrayWithObject: [OFArray arrayWithObject: + [OFArray arrayWithObject: + [OFDictionary dictionary]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]); +} + +- (void)testObjectByParsingJSONFailsWithTooDeepNesting +{ + OTAssertThrowsSpecific( + [@"[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[{}]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]" + objectByParsingJSON], + OFInvalidJSONException); +} +@end ADDED new_tests/OFMatrix4x4Tests.m Index: new_tests/OFMatrix4x4Tests.m ================================================================== --- new_tests/OFMatrix4x4Tests.m +++ new_tests/OFMatrix4x4Tests.m @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2008-2024 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#include "config.h" + +#import "ObjFW.h" +#import "ObjFWTest.h" + +@interface OFMatrix4x4Tests: OTTestCase +{ + OFMatrix4x4 *_matrix; +} +@end + +@implementation OFMatrix4x4Tests +- (void)setUp +{ + [super setUp]; + + _matrix = [[OFMatrix4x4 alloc] initWithValues: (const float [4][4]){ + { 1, 2, 3, 4 }, + { 5, 6, 7, 8 }, + { 9, 10, 11, 12 }, + { 13, 14, 15, 16 } + }]; +} + +- (void)dealloc +{ + [_matrix release]; + + [super dealloc]; +} + +- (void)testIdentityMatrix +{ + OTAssertEqual(memcmp([[OFMatrix4x4 identityMatrix] values], + (const float [4][4]){ + { 1, 0, 0, 0 }, + { 0, 1, 0, 0 }, + { 0, 0, 1, 0 }, + { 0, 0, 0, 1 } + }, 16 * sizeof(float)), + 0); +} + +- (void)testDescription +{ + OTAssertEqualObjects(_matrix.description, + @""); +} + +- (void)testIsEqual +{ + OTAssertEqualObjects([OFMatrix4x4 identityMatrix], + ([OFMatrix4x4 matrixWithValues: (const float [4][4]){ + { 1, 0, 0, 0 }, + { 0, 1, 0, 0 }, + { 0, 0, 1, 0 }, + { 0, 0, 0, 1 } + }])); +} + +/* TODO: testHash */ + +- (void)testCopy +{ + OTAssertEqualObjects(_matrix, [[_matrix copy] autorelease]); +} + +- (void)testMultiplyWithMatrix +{ + OFMatrix4x4 *matrix; + + matrix = [[_matrix copy] autorelease]; + [matrix multiplyWithMatrix: [OFMatrix4x4 identityMatrix]]; + OTAssertEqualObjects(matrix, _matrix); + + matrix = [OFMatrix4x4 matrixWithValues: (const float [4][4]){ + { 100, 200, 300, 400 }, + { 500, 600, 700, 800 }, + { 900, 1000, 1100, 1200 }, + { 1300, 1400, 1500, 1600 } + }]; + [matrix multiplyWithMatrix: _matrix]; + OTAssertEqualObjects(matrix, + ([OFMatrix4x4 matrixWithValues: (const float [4][4]){ + { 9000, 10000, 11000, 12000 }, + { 20200, 22800, 25400, 28000 }, + { 31400, 35600, 39800, 44000 }, + { 42600, 48400, 54200, 60000 } + }])); +} + +- (void)testTranslateWithVector +{ + OFMatrix4x4 *matrix = [OFMatrix4x4 identityMatrix]; + OFVector4D point; + + [matrix translateWithVector: OFMakeVector3D(1, 2, 3)]; + + point = [matrix transformedVector: OFMakeVector4D(2, 3, 4, 1)]; + OTAssertEqual(point.x, 3); + OTAssertEqual(point.y, 5); + OTAssertEqual(point.z, 7); + OTAssertEqual(point.w, 1); +} + +- (void)testScaleWithVector +{ + OFMatrix4x4 *matrix = [OFMatrix4x4 identityMatrix]; + OFVector4D point; + + [matrix translateWithVector: OFMakeVector3D(1, 2, 3)]; + [matrix scaleWithVector: OFMakeVector3D(-1, 0.5f, 2)]; + + point = [matrix transformedVector: OFMakeVector4D(2, 3, 4, 1)]; + OTAssertEqual(point.x, -3); + OTAssertEqual(point.y, 2.5); + OTAssertEqual(point.z, 14); + OTAssertEqual(point.w, 1); +} + +- (void)testTransformVectorsCount +{ + OFVector4D points[2] = {{ 1, 2, 3, 1 }, { 7, 8, 9, 2 }}; + + [_matrix transformVectors: points count: 2]; + + OTAssertEqual(points[0].x, 18); + OTAssertEqual(points[0].y, 46); + OTAssertEqual(points[0].z, 74); + OTAssertEqual(points[0].w, 102); + OTAssertEqual(points[1].x, 58); + OTAssertEqual(points[1].y, 162); + OTAssertEqual(points[1].z, 266); + OTAssertEqual(points[1].w, 370); +} +@end ADDED new_tests/OFMethodSignatureTests.m Index: new_tests/OFMethodSignatureTests.m ================================================================== --- new_tests/OFMethodSignatureTests.m +++ new_tests/OFMethodSignatureTests.m @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2008-2024 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#include "config.h" + +#include + +#if !defined(__STDC_NO_COMPLEX__) && defined(HAVE_COMPLEX_H) +# include +#endif + +#import "ObjFW.h" +#import "ObjFWTest.h" + +@interface OFMethodSignatureTests: OTTestCase +@end + +struct Test1Struct { + char c; + int i; + char d; +}; + +struct Test2Struct { + char c; + struct { + short s; + int i; + } st; + union { + char c; + int i; + } u; + double d; +}; + +#if !defined(__STDC_NO_COMPLEX__) && defined(HAVE_COMPLEX_H) +struct Test3Struct { + char c; + complex double cd; +}; +#endif + +union Test3Union { + char c; + int i; + double d; +}; + +union Test4Union { + char c; + struct { + short x, y; + } st; + int i; + union { + float f; + double d; + } u; +}; + +@implementation OFMethodSignatureTests +- (void)testSignatureWithObjCTypes +{ + OFMethodSignature *methodSignature; + + methodSignature = + [OFMethodSignature signatureWithObjCTypes: "i28@0:8S16*20"]; + OTAssertEqual(methodSignature.numberOfArguments, 4); + OTAssertEqual(strcmp(methodSignature.methodReturnType, "i"), 0); + OTAssertEqual(strcmp([methodSignature argumentTypeAtIndex: 0], "@"), 0); + OTAssertEqual(strcmp([methodSignature argumentTypeAtIndex: 1], ":"), 0); + OTAssertEqual(strcmp([methodSignature argumentTypeAtIndex: 2], "S"), 0); + OTAssertEqual(strcmp([methodSignature argumentTypeAtIndex: 3], "*"), 0); + OTAssertEqual(methodSignature.frameLength, 28); + OTAssertEqual([methodSignature argumentOffsetAtIndex: 0], 0); + OTAssertEqual([methodSignature argumentOffsetAtIndex: 1], 8); + OTAssertEqual([methodSignature argumentOffsetAtIndex: 2], 16); + OTAssertEqual([methodSignature argumentOffsetAtIndex: 3], 20); + + methodSignature = [OFMethodSignature signatureWithObjCTypes: + "{s0=csi(u1={s2=iii{s3=(u4=ic^v*)}})}24@0:8" + "^{s0=csi(u1={s2=iii{s3=(u4=ic^v*)}})}16"]; + OTAssertEqual(methodSignature.numberOfArguments, 3); + OTAssertEqual(strcmp(methodSignature.methodReturnType, + "{s0=csi(u1={s2=iii{s3=(u4=ic^v*)}})}"), 0); + OTAssertEqual(strcmp([methodSignature argumentTypeAtIndex: 0], "@"), 0); + OTAssertEqual(strcmp([methodSignature argumentTypeAtIndex: 1], ":"), 0); + OTAssertEqual(strcmp([methodSignature argumentTypeAtIndex: 2], + "^{s0=csi(u1={s2=iii{s3=(u4=ic^v*)}})}"), 0); + OTAssertEqual(methodSignature.frameLength, 24); + OTAssertEqual([methodSignature argumentOffsetAtIndex: 0], 0); + OTAssertEqual([methodSignature argumentOffsetAtIndex: 1], 8); + OTAssertEqual([methodSignature argumentOffsetAtIndex: 2], 16); +} + +- (void)testSignatureWithObjCTypesFailsWithInvalidFormat +{ + OTAssertThrowsSpecific( + [OFMethodSignature signatureWithObjCTypes: "{ii"], + OFInvalidFormatException); + + OTAssertThrowsSpecific([OFMethodSignature signatureWithObjCTypes: ""], + OFInvalidFormatException); + + OTAssertThrowsSpecific([OFMethodSignature signatureWithObjCTypes: "0"], + OFInvalidFormatException); + + OTAssertThrowsSpecific( + [OFMethodSignature signatureWithObjCTypes: "{{}0"], + OFInvalidFormatException); +} + +- (void)testSizeOfTypeEncoding +{ + OTAssertEqual(OFSizeOfTypeEncoding(@encode(struct Test1Struct)), + sizeof(struct Test1Struct)); + + OTAssertEqual(OFSizeOfTypeEncoding(@encode(struct Test2Struct)), + sizeof(struct Test2Struct)); + +#if !defined(__STDC_NO_COMPLEX__) && defined(HAVE_COMPLEX_H) && \ + OF_GCC_VERSION >= 402 + OTAssertEqual(OFSizeOfTypeEncoding(@encode(struct Test3Struct)), + sizeof(struct Test3Struct)); +#endif + + OTAssertEqual(OFSizeOfTypeEncoding(@encode(union Test3Union)), + sizeof(union Test3Union)); + + OTAssertEqual(OFSizeOfTypeEncoding(@encode(union Test4Union)), + sizeof(union Test4Union)); + + OTAssertEqual(OFSizeOfTypeEncoding(@encode(struct Test1Struct [5])), + sizeof(struct Test1Struct [5])); +} + +- (void)testAlignmentOfTypeEncoding +{ + OTAssertEqual(OFAlignmentOfTypeEncoding(@encode(struct Test1Struct)), + OF_ALIGNOF(struct Test1Struct)); + + OTAssertEqual(OFAlignmentOfTypeEncoding(@encode(struct Test2Struct)), + OF_ALIGNOF(struct Test2Struct)); + +#if !defined(__STDC_NO_COMPLEX__) && defined(HAVE_COMPLEX_H) && \ + OF_GCC_VERSION >= 402 + OTAssertEqual(OFAlignmentOfTypeEncoding(@encode(struct Test3Struct)), + OF_ALIGNOF(struct Test3Struct)); +#endif + + OTAssertEqual(OFAlignmentOfTypeEncoding(@encode(union Test3Union)), + OF_ALIGNOF(union Test3Union)); + + OTAssertEqual(OFAlignmentOfTypeEncoding(@encode(union Test4Union)), + OF_ALIGNOF(union Test4Union)); + + OTAssertEqual( + OFAlignmentOfTypeEncoding(@encode(struct Test1Struct [5])), + OF_ALIGNOF(struct Test1Struct [5])); +} +@end ADDED new_tests/OFMutableArrayTests.h Index: new_tests/OFMutableArrayTests.h ================================================================== --- new_tests/OFMutableArrayTests.h +++ new_tests/OFMutableArrayTests.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2008-2024 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#import "OFArrayTests.h" + +@interface OFMutableArrayTests: OFArrayTests +{ + OFMutableArray *_mutableArray; +} +@end ADDED new_tests/OFMutableArrayTests.m Index: new_tests/OFMutableArrayTests.m ================================================================== --- new_tests/OFMutableArrayTests.m +++ new_tests/OFMutableArrayTests.m @@ -0,0 +1,252 @@ +/* + * Copyright (c) 2008-2024 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#include "config.h" + +#import "OFMutableArrayTests.h" + +#import "OFArray+Private.h" + +@interface CustomMutableArray: OFMutableArray +{ + OFMutableArray *_array; +} +@end + +static OFString *const cArray[] = { + @"Foo", + @"Bar", + @"Baz" +}; + +@implementation OFMutableArrayTests +- (Class)arrayClass +{ + return [CustomMutableArray class]; +} + +- (void)setUp +{ + [super setUp]; + + _mutableArray = [[self.arrayClass alloc] + initWithObjects: cArray + count: sizeof(cArray) / sizeof(*cArray)]; +} + +- (void)dealloc +{ + [_mutableArray release]; + + [super dealloc]; +} + +- (void)testAddObject +{ + [_mutableArray addObject: cArray[0]]; + [_mutableArray addObject: cArray[2]]; + + OTAssertEqualObjects(_mutableArray, + ([OFArray arrayWithObjects: @"Foo", @"Bar", @"Baz", @"Foo", @"Baz", + nil])); +} + +- (void)testInsertObjectAtIndex +{ + [_mutableArray insertObject: cArray[1] atIndex: 1]; + + OTAssertEqualObjects(_mutableArray, + ([OFArray arrayWithObjects: @"Foo", @"Bar", @"Bar", @"Baz", nil])); +} + +- (void)testReplaceObjectWithObject +{ + [_mutableArray insertObject: cArray[1] atIndex: 1]; + [_mutableArray replaceObject: cArray[1] withObject: cArray[0]]; + + OTAssertEqualObjects(_mutableArray, + ([OFArray arrayWithObjects: @"Foo", @"Foo", @"Foo", @"Baz", nil])); +} + +- (void)testReplaceObjectIdenticalToWithObject +{ + [_mutableArray insertObject: [[cArray[1] mutableCopy] autorelease] + atIndex: 1]; + [_mutableArray replaceObjectIdenticalTo: cArray[1] + withObject: cArray[0]]; + + OTAssertEqualObjects(_mutableArray, + ([OFArray arrayWithObjects: @"Foo", @"Bar", @"Foo", @"Baz", nil])); +} + +- (void)testReplaceObjectAtIndexWithObject +{ + [_mutableArray replaceObjectAtIndex: 1 + withObject: cArray[0]]; + + OTAssertEqualObjects(_mutableArray, + ([OFArray arrayWithObjects: @"Foo", @"Foo", @"Baz", nil])); +} + +- (void)testRemoveObject +{ + [_mutableArray removeObject: cArray[1]]; + + OTAssertEqualObjects(_mutableArray, + ([OFArray arrayWithObjects: @"Foo", @"Baz", nil])); +} + +- (void)testRemoveObjectIdenticalTo +{ + [_mutableArray removeObjectIdenticalTo: cArray[1]]; + + OTAssertEqualObjects(_mutableArray, + ([OFArray arrayWithObjects: @"Foo", @"Baz", nil])); +} + +- (void)testRemoveObjectAtIndex +{ + [_mutableArray removeObjectAtIndex: 1]; + + OTAssertEqualObjects(_mutableArray, + ([OFArray arrayWithObjects: @"Foo", @"Baz", nil])); +} + +- (void)testRemoveObjectsInRange +{ + [_mutableArray removeObjectsInRange: OFMakeRange(1, 2)]; + + OTAssertEqualObjects(_mutableArray, [OFArray arrayWithObject: @"Foo"]); +} + +- (void)testRemoveObjectsInRangeFailsWhenOutOfRange +{ + OTAssertThrowsSpecific([_mutableArray removeObjectsInRange: + OFMakeRange(0, _mutableArray.count + 1)], OFOutOfRangeException); +} + +- (void)testReverse +{ + [_mutableArray reverse]; + + OTAssertEqualObjects(_mutableArray, + ([OFArray arrayWithObjects: @"Baz", @"Bar", @"Foo", nil])); +} + +#ifdef OF_HAVE_BLOCKS +- (void)testReplaceObjectsUsingBlock +{ + [_mutableArray replaceObjectsUsingBlock: ^ id (id object, size_t idx) { + return [object lowercaseString]; + }]; + + OTAssertEqualObjects(_mutableArray, + ([OFArray arrayWithObjects: @"foo", @"bar", @"baz", nil])); +} +#endif + +- (void)testSetValueForKey +{ + OFMutableArray *array = [self.arrayClass arrayWithObjects: + [OFMutableIRI IRIWithString: @"http://foo.bar/"], + [OFMutableIRI IRIWithString: @"http://bar.qux/"], + [OFMutableIRI IRIWithString: @"http://qux.quxqux/"], nil]; + + [array setValue: [OFNumber numberWithShort: 1234] + forKey: @"port"]; + OTAssertEqualObjects(array, ([OFArray arrayWithObjects: + [OFIRI IRIWithString: @"http://foo.bar:1234/"], + [OFIRI IRIWithString: @"http://bar.qux:1234/"], + [OFIRI IRIWithString: @"http://qux.quxqux:1234/"], nil])); +} +@end + +@implementation CustomMutableArray +- (instancetype)init +{ + self = [super init]; + + @try { + _array = [[OFMutableArray alloc] init]; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (instancetype)initWithObject: (id)object arguments: (va_list)arguments +{ + self = [super init]; + + @try { + _array = [[OFMutableArray alloc] initWithObject: object + arguments: arguments]; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (instancetype)initWithObjects: (id const *)objects count: (size_t)count +{ + self = [super init]; + + @try { + _array = [[OFMutableArray alloc] initWithObjects: objects + count: count]; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (void)dealloc +{ + [_array release]; + + [super dealloc]; +} + +- (id)objectAtIndex: (size_t)idx +{ + return [_array objectAtIndex: idx]; +} + +- (size_t)count +{ + return [_array count]; +} + +- (void)insertObject: (id)object atIndex: (size_t)idx +{ + [_array insertObject: object atIndex: idx]; +} + +- (void)replaceObjectAtIndex: (size_t)idx withObject: (id)object +{ + [_array replaceObjectAtIndex: idx withObject: object]; +} + +- (void)removeObjectAtIndex: (size_t)idx +{ + [_array removeObjectAtIndex: idx]; +} +@end ADDED new_tests/OFNumberTests.m Index: new_tests/OFNumberTests.m ================================================================== --- new_tests/OFNumberTests.m +++ new_tests/OFNumberTests.m @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2008-2024 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#include "config.h" + +#import "ObjFW.h" +#import "ObjFWTest.h" + +@interface OFNumberTests: OTTestCase +@end + +extern unsigned long long OFHashSeed; + +@implementation OFNumberTests +- (void)testIsEqual +{ + OFNumber *number = [OFNumber numberWithLongLong: 123456789]; + OTAssertEqualObjects(number, [OFNumber numberWithLong: 123456789]); +} + +- (void)testHash +{ + unsigned long long hashSeed = OFHashSeed; + OFHashSeed = 0; + @try { + OFNumber *number = [OFNumber numberWithLongLong: 123456789]; + OTAssertEqual(number.hash, 0x82D8BC42); + } @finally { + OFHashSeed = hashSeed; + }; +} + +- (void)testCharValue +{ + OFNumber *number = [OFNumber numberWithLongLong: 123456789]; + OTAssertEqual(number.charValue, 21); +} + +- (void)testDoubleValue +{ + OFNumber *number = [OFNumber numberWithLongLong: 123456789]; + OTAssertEqual(number.doubleValue, 123456789.L); +} + +- (void)testSignedCharMinAndMaxUnmodified +{ + OTAssertEqual([[OFNumber numberWithChar: SCHAR_MIN] charValue], + SCHAR_MIN); + OTAssertEqual([[OFNumber numberWithChar: SCHAR_MAX] charValue], + SCHAR_MAX); +} + +- (void)testShortMinAndMaxUnmodified +{ + OTAssertEqual([[OFNumber numberWithShort: SHRT_MIN] shortValue], + SHRT_MIN); + OTAssertEqual([[OFNumber numberWithShort: SHRT_MAX] shortValue], + SHRT_MAX); +} + +- (void)testIntMinAndMaxUnmodified +{ + OTAssertEqual([[OFNumber numberWithInt: INT_MIN] intValue], INT_MIN); + OTAssertEqual([[OFNumber numberWithInt: INT_MAX] intValue], INT_MAX); +} + +- (void)testLongMinAndMaxUnmodified +{ + OTAssertEqual([[OFNumber numberWithLong: LONG_MIN] longValue], + LONG_MIN); + OTAssertEqual([[OFNumber numberWithLong: LONG_MAX] longValue], + LONG_MAX);; +} + +- (void)testLongLongMinAndMaxUnmodified +{ + OTAssertEqual([[OFNumber numberWithLongLong: LLONG_MIN] longLongValue], + LLONG_MIN); + OTAssertEqual([[OFNumber numberWithLongLong: LLONG_MAX] longLongValue], + LLONG_MAX); +} + +- (void)testUnsignedCharMaxUnmodified +{ + OTAssertEqual([[OFNumber numberWithUnsignedChar: UCHAR_MAX] + unsignedCharValue], UCHAR_MAX); +} + +- (void)testUnsignedShortMaxUnmodified +{ + OTAssertEqual([[OFNumber numberWithUnsignedShort: USHRT_MAX] + unsignedShortValue], USHRT_MAX); +} + +- (void)testUnsignedIntMaxUnmodified +{ + OTAssertEqual([[OFNumber numberWithUnsignedInt: UINT_MAX] + unsignedIntValue], UINT_MAX); +} + +- (void)testUnsignedLongMaxUnmodified +{ + OTAssertEqual([[OFNumber numberWithUnsignedLong: ULONG_MAX] + unsignedLongValue], ULONG_MAX); +} + +- (void)testUnsignedLongLongMaxUnmodified +{ + OTAssertEqual([[OFNumber numberWithUnsignedLongLong: ULLONG_MAX] + unsignedLongLongValue], ULLONG_MAX); +} +@end ADDED new_tests/OFPBKDF2Tests.m Index: new_tests/OFPBKDF2Tests.m ================================================================== --- new_tests/OFPBKDF2Tests.m +++ new_tests/OFPBKDF2Tests.m @@ -0,0 +1,170 @@ +/* + * Copyright (c) 2008-2024 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#include "config.h" + +#include + +#import "ObjFW.h" +#import "ObjFWTest.h" + +@interface OFPBKDF2Tests: OTTestCase +{ + OFHMAC *_HMAC; +} +@end + +@implementation OFPBKDF2Tests +- (void)setUp +{ + [super setUp]; + + _HMAC = [[OFHMAC alloc] initWithHashClass: [OFSHA1Hash class] + allowsSwappableMemory: true]; +} + +- (void)dealloc +{ + [_HMAC release]; + + [super dealloc]; +} + +/* Test vectors from RFC 6070 */ + +- (void)testRFC6070TestVector1 +{ + unsigned char key[25]; + + OFPBKDF2((OFPBKDF2Parameters){ + .HMAC = _HMAC, + .iterations = 1, + .salt = (unsigned char *)"salt", + .saltLength = 4, + .password = "password", + .passwordLength = 8, + .key = key, + .keyLength = 20, + .allowsSwappableMemory = true + }); + + OTAssertEqual(memcmp(key, "\x0C\x60\xC8\x0F\x96\x1F\x0E\x71\xF3\xA9\xB5" + "\x24\xAF\x60\x12\x06\x2F\xE0\x37\xA6", 20), 0); +} + +- (void)testRFC6070TestVector2 +{ + unsigned char key[25]; + + OFPBKDF2((OFPBKDF2Parameters){ + .HMAC = _HMAC, + .iterations = 2, + .salt = (unsigned char *)"salt", + .saltLength = 4, + .password = "password", + .passwordLength = 8, + .key = key, + .keyLength = 20, + .allowsSwappableMemory = true + }); + + OTAssertEqual(memcmp(key, "\xEA\x6C\x01\x4D\xC7\x2D\x6F\x8C\xCD\x1E\xD9" + "\x2A\xCE\x1D\x41\xF0\xD8\xDE\x89\x57", 20), 0); +} + +- (void)testRFC6070TestVector3 +{ + unsigned char key[25]; + + OFPBKDF2((OFPBKDF2Parameters){ + .HMAC = _HMAC, + .iterations = 4096, + .salt = (unsigned char *)"salt", + .saltLength = 4, + .password = "password", + .passwordLength = 8, + .key = key, + .keyLength = 20, + .allowsSwappableMemory = true + }); + + OTAssertEqual(memcmp(key, "\x4B\x00\x79\x01\xB7\x65\x48\x9A\xBE\xAD\x49" + "\xD9\x26\xF7\x21\xD0\x65\xA4\x29\xC1", 20), 0); +} + +#if 0 +/* This test takes too long, even on a fast machine. */ +- (void)testRFC6070TestVector4 +{ + unsigned char key[25]; + + OFPBKDF2((OFPBKDF2Parameters){ + .HMAC = _HMAC, + .iterations = 16777216, + .salt = (unsigned char *)"salt", + .saltLength = 4, + .password = "password", + .passwordLength = 8, + .key = key, + .keyLength = 20, + .allowsSwappableMemory = true + }); + + OTAssertEqual(memcmp(key, "\xEE\xFE\x3D\x61\xCD\x4D\xA4\xE4\xE9\x94\x5B" + "\x3D\x6B\xA2\x15\x8C\x26\x34\xE9\x84", 20), 0); +} +#endif + +- (void)testRFC6070TestVector5 +{ + unsigned char key[25]; + + OFPBKDF2((OFPBKDF2Parameters){ + .HMAC = _HMAC, + .iterations = 4096, + .salt = (unsigned char *)"saltSALTsaltSALTsalt" + "SALTsaltSALTsalt", + .saltLength = 36, + .password = "passwordPASSWORDpassword", + .passwordLength = 24, + .key = key, + .keyLength = 25, + .allowsSwappableMemory = true + }); + + OTAssertEqual(memcmp(key, "\x3D\x2E\xEC\x4F\xE4\x1C\x84\x9B\x80\xC8\xD8" + "\x36\x62\xC0\xE4\x4A\x8B\x29\x1A\x96\x4C\xF2\xF0\x70\x38", 25), 0); +} + +- (void)testRFC6070TestVector6 +{ + unsigned char key[25]; + + OFPBKDF2((OFPBKDF2Parameters){ + .HMAC = _HMAC, + .iterations = 4096, + .salt = (unsigned char *)"sa\0lt", + .saltLength = 5, + .password = "pass\0word", + .passwordLength = 9, + .key = key, + .keyLength = 16, + .allowsSwappableMemory = true + }); + + OTAssertEqual(memcmp(key, "\x56\xFA\x6A\xA7\x55\x48\x09\x9D\xCC\x37\xD7" + "\xF0\x34\x25\xE0\xC3", 16), 0); +} +@end ADDED new_tests/OFPluginTests.m Index: new_tests/OFPluginTests.m ================================================================== --- new_tests/OFPluginTests.m +++ new_tests/OFPluginTests.m @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2008-2024 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#include "config.h" + +#import "ObjFW.h" +#import "ObjFWTest.h" + +#import "plugin/TestPlugin.h" + +@interface OFPluginTests: OTTestCase +@end + +@implementation OFPluginTests +- (void)testPlugin +{ + TestPlugin *test = nil; + OFString *path; + OFPlugin *plugin; + Class (*class)(void); + +#ifndef OF_IOS + path = [OFPlugin pathForName: @"plugin/TestPlugin"]; +#else + path = [OFPlugin pathForName: @"PlugIns/TestPlugin"]; +#endif + OTAssertNotNil(path); + + plugin = [OFPlugin pluginWithPath: path]; + OTAssertNotNil(plugin); + + class = (Class (*)(void))(uintptr_t)[plugin addressForSymbol: @"class"]; + OTAssert(class != NULL); + + @try { + test = [[class() alloc] init]; + OTAssertEqual([test test: 1234], 2468); + } @finally { + [test release]; + } +} +@end ADDED new_tests/OFPropertyListTests.m Index: new_tests/OFPropertyListTests.m ================================================================== --- new_tests/OFPropertyListTests.m +++ new_tests/OFPropertyListTests.m @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2008-2024 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#include "config.h" + +#import "ObjFW.h" +#import "ObjFWTest.h" + +@interface OFPropertyListTests: OTTestCase +@end + +#define PLIST(x) \ + @"" \ + @"" \ + @"\n" \ + x @"\n" \ + @"" + +@implementation OFPropertyListTests +- (void)testObjectByParsingPropertyList +{ + OFArray *array = [OFArray arrayWithObjects: + @"Hello", + [OFData dataWithItems: "World!" count: 6], + [OFDate dateWithTimeIntervalSince1970: 1521030896], + [OFNumber numberWithBool: true], + [OFNumber numberWithBool: false], + [OFNumber numberWithFloat: 12.25f], + [OFNumber numberWithInt: -10], + nil]; + + OTAssertEqualObjects([PLIST( + @"Hello") objectByParsingPropertyList], + @"Hello"); + OTAssertEqualObjects([PLIST( + @"" + @" Hello" + @" V29ybGQh" + @" 2018-03-14T12:34:56Z" + @" " + @" " + @" 12.25" + @" -10" + @"") objectByParsingPropertyList], + array); + OTAssertEqualObjects([PLIST( + @"" + @" array" + @" " + @" Hello" + @" V29ybGQh" + @" 2018-03-14T12:34:56Z" + @" " + @" " + @" 12.25" + @" -10" + @" " + @" foo" + @" bar" + @"") objectByParsingPropertyList], + ([OFDictionary dictionaryWithKeysAndObjects: + @"array", array, + @"foo", @"bar", + nil])); +} + +- (void)testDetectUnsupportedVersion +{ + OTAssertThrowsSpecific( + [[PLIST(@"") + stringByReplacingOccurrencesOfString: @"1.0" + withString: @"1.1"] + objectByParsingPropertyList], + OFUnsupportedVersionException); +} + +- (void)testDetectInvalidFormat +{ + OTAssertThrowsSpecific( + [PLIST(@"") objectByParsingPropertyList], + OFInvalidFormatException); + + OTAssertThrowsSpecific( + [PLIST(@"") objectByParsingPropertyList], + OFInvalidFormatException); + + OTAssertThrowsSpecific( + [PLIST(@"") objectByParsingPropertyList], + OFInvalidFormatException); + + OTAssertThrowsSpecific( + [PLIST(@"") + objectByParsingPropertyList], + OFInvalidFormatException); + + OTAssertThrowsSpecific( + [PLIST(@"") + objectByParsingPropertyList], + OFInvalidFormatException); +} +@end ADDED new_tests/OFScryptTests.m Index: new_tests/OFScryptTests.m ================================================================== --- new_tests/OFScryptTests.m +++ new_tests/OFScryptTests.m @@ -0,0 +1,251 @@ +/* + * Copyright (c) 2008-2024 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#include "config.h" + +#include + +#import "ObjFW.h" +#import "ObjFWTest.h" + +@interface OFScryptTests: OTTestCase +@end + +/* Test vectors form RFC 7914 */ +static const unsigned char salsa20Input[64] = { + 0x7E, 0x87, 0x9A, 0x21, 0x4F, 0x3E, 0xC9, 0x86, 0x7C, 0xA9, 0x40, 0xE6, + 0x41, 0x71, 0x8F, 0x26, 0xBA, 0xEE, 0x55, 0x5B, 0x8C, 0x61, 0xC1, 0xB5, + 0x0D, 0xF8, 0x46, 0x11, 0x6D, 0xCD, 0x3B, 0x1D, 0xEE, 0x24, 0xF3, 0x19, + 0xDF, 0x9B, 0x3D, 0x85, 0x14, 0x12, 0x1E, 0x4B, 0x5A, 0xC5, 0xAA, 0x32, + 0x76, 0x02, 0x1D, 0x29, 0x09, 0xC7, 0x48, 0x29, 0xED, 0xEB, 0xC6, 0x8D, + 0xB8, 0xB8, 0xC2, 0x5E +}; +static const unsigned char salsa20Output[64] = { + 0xA4, 0x1F, 0x85, 0x9C, 0x66, 0x08, 0xCC, 0x99, 0x3B, 0x81, 0xCA, 0xCB, + 0x02, 0x0C, 0xEF, 0x05, 0x04, 0x4B, 0x21, 0x81, 0xA2, 0xFD, 0x33, 0x7D, + 0xFD, 0x7B, 0x1C, 0x63, 0x96, 0x68, 0x2F, 0x29, 0xB4, 0x39, 0x31, 0x68, + 0xE3, 0xC9, 0xE6, 0xBC, 0xFE, 0x6B, 0xC5, 0xB7, 0xA0, 0x6D, 0x96, 0xBA, + 0xE4, 0x24, 0xCC, 0x10, 0x2C, 0x91, 0x74, 0x5C, 0x24, 0xAD, 0x67, 0x3D, + 0xC7, 0x61, 0x8F, 0x81 +}; +static const union { + unsigned char uc[128]; + uint32_t u32[32]; +} blockMixInput = { .uc = { + 0xF7, 0xCE, 0x0B, 0x65, 0x3D, 0x2D, 0x72, 0xA4, 0x10, 0x8C, 0xF5, 0xAB, + 0xE9, 0x12, 0xFF, 0xDD, 0x77, 0x76, 0x16, 0xDB, 0xBB, 0x27, 0xA7, 0x0E, + 0x82, 0x04, 0xF3, 0xAE, 0x2D, 0x0F, 0x6F, 0xAD, 0x89, 0xF6, 0x8F, 0x48, + 0x11, 0xD1, 0xE8, 0x7B, 0xCC, 0x3B, 0xD7, 0x40, 0x0A, 0x9F, 0xFD, 0x29, + 0x09, 0x4F, 0x01, 0x84, 0x63, 0x95, 0x74, 0xF3, 0x9A, 0xE5, 0xA1, 0x31, + 0x52, 0x17, 0xBC, 0xD7, + 0x89, 0x49, 0x91, 0x44, 0x72, 0x13, 0xBB, 0x22, 0x6C, 0x25, 0xB5, 0x4D, + 0xA8, 0x63, 0x70, 0xFB, 0xCD, 0x98, 0x43, 0x80, 0x37, 0x46, 0x66, 0xBB, + 0x8F, 0xFC, 0xB5, 0xBF, 0x40, 0xC2, 0x54, 0xB0, 0x67, 0xD2, 0x7C, 0x51, + 0xCE, 0x4A, 0xD5, 0xFE, 0xD8, 0x29, 0xC9, 0x0B, 0x50, 0x5A, 0x57, 0x1B, + 0x7F, 0x4D, 0x1C, 0xAD, 0x6A, 0x52, 0x3C, 0xDA, 0x77, 0x0E, 0x67, 0xBC, + 0xEA, 0xAF, 0x7E, 0x89 +}}; +static const unsigned char blockMixOutput[128] = { + 0xA4, 0x1F, 0x85, 0x9C, 0x66, 0x08, 0xCC, 0x99, 0x3B, 0x81, 0xCA, 0xCB, + 0x02, 0x0C, 0xEF, 0x05, 0x04, 0x4B, 0x21, 0x81, 0xA2, 0xFD, 0x33, 0x7D, + 0xFD, 0x7B, 0x1C, 0x63, 0x96, 0x68, 0x2F, 0x29, 0xB4, 0x39, 0x31, 0x68, + 0xE3, 0xC9, 0xE6, 0xBC, 0xFE, 0x6B, 0xC5, 0xB7, 0xA0, 0x6D, 0x96, 0xBA, + 0xE4, 0x24, 0xCC, 0x10, 0x2C, 0x91, 0x74, 0x5C, 0x24, 0xAD, 0x67, 0x3D, + 0xC7, 0x61, 0x8F, 0x81, + 0x20, 0xED, 0xC9, 0x75, 0x32, 0x38, 0x81, 0xA8, 0x05, 0x40, 0xF6, 0x4C, + 0x16, 0x2D, 0xCD, 0x3C, 0x21, 0x07, 0x7C, 0xFE, 0x5F, 0x8D, 0x5F, 0xE2, + 0xB1, 0xA4, 0x16, 0x8F, 0x95, 0x36, 0x78, 0xB7, 0x7D, 0x3B, 0x3D, 0x80, + 0x3B, 0x60, 0xE4, 0xAB, 0x92, 0x09, 0x96, 0xE5, 0x9B, 0x4D, 0x53, 0xB6, + 0x5D, 0x2A, 0x22, 0x58, 0x77, 0xD5, 0xED, 0xF5, 0x84, 0x2C, 0xB9, 0xF1, + 0x4E, 0xEF, 0xE4, 0x25 +}; +static const unsigned char ROMixInput[128] = { + 0xF7, 0xCE, 0x0B, 0x65, 0x3D, 0x2D, 0x72, 0xA4, 0x10, 0x8C, 0xF5, 0xAB, + 0xE9, 0x12, 0xFF, 0xDD, 0x77, 0x76, 0x16, 0xDB, 0xBB, 0x27, 0xA7, 0x0E, + 0x82, 0x04, 0xF3, 0xAE, 0x2D, 0x0F, 0x6F, 0xAD, 0x89, 0xF6, 0x8F, 0x48, + 0x11, 0xD1, 0xE8, 0x7B, 0xCC, 0x3B, 0xD7, 0x40, 0x0A, 0x9F, 0xFD, 0x29, + 0x09, 0x4F, 0x01, 0x84, 0x63, 0x95, 0x74, 0xF3, 0x9A, 0xE5, 0xA1, 0x31, + 0x52, 0x17, 0xBC, 0xD7, 0x89, 0x49, 0x91, 0x44, 0x72, 0x13, 0xBB, 0x22, + 0x6C, 0x25, 0xB5, 0x4D, 0xA8, 0x63, 0x70, 0xFB, 0xCD, 0x98, 0x43, 0x80, + 0x37, 0x46, 0x66, 0xBB, 0x8F, 0xFC, 0xB5, 0xBF, 0x40, 0xC2, 0x54, 0xB0, + 0x67, 0xD2, 0x7C, 0x51, 0xCE, 0x4A, 0xD5, 0xFE, 0xD8, 0x29, 0xC9, 0x0B, + 0x50, 0x5A, 0x57, 0x1B, 0x7F, 0x4D, 0x1C, 0xAD, 0x6A, 0x52, 0x3C, 0xDA, + 0x77, 0x0E, 0x67, 0xBC, 0xEA, 0xAF, 0x7E, 0x89 +}; +static const unsigned char ROMixOutput[128] = { + 0x79, 0xCC, 0xC1, 0x93, 0x62, 0x9D, 0xEB, 0xCA, 0x04, 0x7F, 0x0B, 0x70, + 0x60, 0x4B, 0xF6, 0xB6, 0x2C, 0xE3, 0xDD, 0x4A, 0x96, 0x26, 0xE3, 0x55, + 0xFA, 0xFC, 0x61, 0x98, 0xE6, 0xEA, 0x2B, 0x46, 0xD5, 0x84, 0x13, 0x67, + 0x3B, 0x99, 0xB0, 0x29, 0xD6, 0x65, 0xC3, 0x57, 0x60, 0x1F, 0xB4, 0x26, + 0xA0, 0xB2, 0xF4, 0xBB, 0xA2, 0x00, 0xEE, 0x9F, 0x0A, 0x43, 0xD1, 0x9B, + 0x57, 0x1A, 0x9C, 0x71, 0xEF, 0x11, 0x42, 0xE6, 0x5D, 0x5A, 0x26, 0x6F, + 0xDD, 0xCA, 0x83, 0x2C, 0xE5, 0x9F, 0xAA, 0x7C, 0xAC, 0x0B, 0x9C, 0xF1, + 0xBE, 0x2B, 0xFF, 0xCA, 0x30, 0x0D, 0x01, 0xEE, 0x38, 0x76, 0x19, 0xC4, + 0xAE, 0x12, 0xFD, 0x44, 0x38, 0xF2, 0x03, 0xA0, 0xE4, 0xE1, 0xC4, 0x7E, + 0xC3, 0x14, 0x86, 0x1F, 0x4E, 0x90, 0x87, 0xCB, 0x33, 0x39, 0x6A, 0x68, + 0x73, 0xE8, 0xF9, 0xD2, 0x53, 0x9A, 0x4B, 0x8E +}; +static const unsigned char testVector1[64] = { + 0x77, 0xD6, 0x57, 0x62, 0x38, 0x65, 0x7B, 0x20, 0x3B, 0x19, 0xCA, 0x42, + 0xC1, 0x8A, 0x04, 0x97, 0xF1, 0x6B, 0x48, 0x44, 0xE3, 0x07, 0x4A, 0xE8, + 0xDF, 0xDF, 0xFA, 0x3F, 0xED, 0xE2, 0x14, 0x42, 0xFC, 0xD0, 0x06, 0x9D, + 0xED, 0x09, 0x48, 0xF8, 0x32, 0x6A, 0x75, 0x3A, 0x0F, 0xC8, 0x1F, 0x17, + 0xE8, 0xD3, 0xE0, 0xFB, 0x2E, 0x0D, 0x36, 0x28, 0xCF, 0x35, 0xE2, 0x0C, + 0x38, 0xD1, 0x89, 0x06 +}; +static const unsigned char testVector2[64] = { + 0xFD, 0xBA, 0xBE, 0x1C, 0x9D, 0x34, 0x72, 0x00, 0x78, 0x56, 0xE7, 0x19, + 0x0D, 0x01, 0xE9, 0xFE, 0x7C, 0x6A, 0xD7, 0xCB, 0xC8, 0x23, 0x78, 0x30, + 0xE7, 0x73, 0x76, 0x63, 0x4B, 0x37, 0x31, 0x62, 0x2E, 0xAF, 0x30, 0xD9, + 0x2E, 0x22, 0xA3, 0x88, 0x6F, 0xF1, 0x09, 0x27, 0x9D, 0x98, 0x30, 0xDA, + 0xC7, 0x27, 0xAF, 0xB9, 0x4A, 0x83, 0xEE, 0x6D, 0x83, 0x60, 0xCB, 0xDF, + 0xA2, 0xCC, 0x06, 0x40 +}; +/* The third test vector is too expensive for m68k. */ +#ifndef OF_M68K +static const unsigned char testVector3[64] = { + 0x70, 0x23, 0xBD, 0xCB, 0x3A, 0xFD, 0x73, 0x48, 0x46, 0x1C, 0x06, 0xCD, + 0x81, 0xFD, 0x38, 0xEB, 0xFD, 0xA8, 0xFB, 0xBA, 0x90, 0x4F, 0x8E, 0x3E, + 0xA9, 0xB5, 0x43, 0xF6, 0x54, 0x5D, 0xA1, 0xF2, 0xD5, 0x43, 0x29, 0x55, + 0x61, 0x3F, 0x0F, 0xCF, 0x62, 0xD4, 0x97, 0x05, 0x24, 0x2A, 0x9A, 0xF9, + 0xE6, 0x1E, 0x85, 0xDC, 0x0D, 0x65, 0x1E, 0x40, 0xDF, 0xCF, 0x01, 0x7B, + 0x45, 0x57, 0x58, 0x87 +}; +#endif +/* The forth test vector is too expensive to include it in the tests. */ +#if 0 +static const unsigned char testVector4[64] = { + 0x21, 0x01, 0xCB, 0x9B, 0x6A, 0x51, 0x1A, 0xAE, 0xAD, 0xDB, 0xBE, 0x09, + 0xCF, 0x70, 0xF8, 0x81, 0xEC, 0x56, 0x8D, 0x57, 0x4A, 0x2F, 0xFD, 0x4D, + 0xAB, 0xE5, 0xEE, 0x98, 0x20, 0xAD, 0xAA, 0x47, 0x8E, 0x56, 0xFD, 0x8F, + 0x4B, 0xA5, 0xD0, 0x9F, 0xFA, 0x1C, 0x6D, 0x92, 0x7C, 0x40, 0xF4, 0xC3, + 0x37, 0x30, 0x40, 0x49, 0xE8, 0xA9, 0x52, 0xFB, 0xCB, 0xF4, 0x5C, 0x6F, + 0xA7, 0x7A, 0x41, 0xA4 +}; +#endif + +@implementation OFScryptTests +- (void)testSalsa20_8Core +{ + uint32_t salsa20Buffer[16]; + + memcpy(salsa20Buffer, salsa20Input, 64); + OFSalsa20_8Core(salsa20Buffer); + OTAssertEqual(memcmp(salsa20Buffer, salsa20Output, 64), 0); +} + +- (void)testBlockMix +{ + uint32_t blockMixBuffer[32]; + + OFScryptBlockMix(blockMixBuffer, blockMixInput.u32, 1); + OTAssertEqual(memcmp(blockMixBuffer, blockMixOutput, 128), 0); +} + +- (void)testROMix +{ + uint32_t ROMixBuffer[32], ROMixTmp[17 * 32]; + + memcpy(ROMixBuffer, ROMixInput, 128); + OFScryptROMix(ROMixBuffer, 1, 16, ROMixTmp); + OTAssertEqual(memcmp(ROMixBuffer, ROMixOutput, 128), 0); +} + +- (void)testRFC7941TestVector1 +{ + unsigned char output[64]; + + OFScrypt((OFScryptParameters){ + .blockSize = 1, + .costFactor = 16, + .parallelization = 1, + .salt = (unsigned char *)"", + .saltLength = 0, + .password = "", + .passwordLength = 0, + .key = output, + .keyLength = 64, + .allowsSwappableMemory = true + }); + + OTAssertEqual(memcmp(output, testVector1, 64), 0); +} + +- (void)testRFC7941TestVector2 +{ + unsigned char output[64]; + + OFScrypt((OFScryptParameters){ + .blockSize = 8, + .costFactor = 1024, + .parallelization = 16, + .salt = (unsigned char *)"NaCl", + .saltLength = 4, + .password = "password", + .passwordLength = 8, + .key = output, + .keyLength = 64, + .allowsSwappableMemory = true + }); + + OTAssertEqual(memcmp(output, testVector2, 64), 0); +} + +/* The third test vector is too expensive for m68k. */ +#ifndef OF_M68K +- (void)testRFC7941TestVector3 +{ + unsigned char output[64]; + + OFScrypt((OFScryptParameters){ + .blockSize = 8, + .costFactor = 16384, + .parallelization = 1, + .salt = (unsigned char *)"SodiumChloride", + .saltLength = 14, + .password = "pleaseletmein", + .passwordLength = 13, + .key = output, + .keyLength = 64, + .allowsSwappableMemory = true + }); + + OTAssertEqual(memcmp(output, testVector3, 64), 0); +} +#endif + +/* The forth test vector is too expensive to include it in the tests. */ +#if 0 +- (void)testRFC7941TestVector4 +{ + unsigned char output[64]; + + OFScrypt((OFScryptParameters){ + .blockSize = 8, + .costFactor = 1048576, + .parallelization = 1, + .salt = (unsigned char *)"SodiumChloride", + .saltLength = 14, + .password = "pleaseletmein", + .passwordLength = 13, + .key = output, + .keyLength = 64, + .allowsSwappableMemory = true + }); + + OTAssertEqual(memcmp(output, testVector4, 64), 0); +} +#endif +@end ADDED new_tests/OFSocketTests.m Index: new_tests/OFSocketTests.m ================================================================== --- new_tests/OFSocketTests.m +++ new_tests/OFSocketTests.m @@ -0,0 +1,231 @@ +/* + * Copyright (c) 2008-2024 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#include "config.h" + +#import "ObjFW.h" +#import "ObjFWTest.h" + +@interface OFSocketTests: OTTestCase +@end + +#define COMPARE_V6(a, a0, a1, a2, a3, a4, a5, a6, a7) \ + (a.sockaddr.in6.sin6_addr.s6_addr[0] == (a0 >> 8) && \ + a.sockaddr.in6.sin6_addr.s6_addr[1] == (a0 & 0xFF) && \ + a.sockaddr.in6.sin6_addr.s6_addr[2] == (a1 >> 8) && \ + a.sockaddr.in6.sin6_addr.s6_addr[3] == (a1 & 0xFF) && \ + a.sockaddr.in6.sin6_addr.s6_addr[4] == (a2 >> 8) && \ + a.sockaddr.in6.sin6_addr.s6_addr[5] == (a2 & 0xFF) && \ + a.sockaddr.in6.sin6_addr.s6_addr[6] == (a3 >> 8) && \ + a.sockaddr.in6.sin6_addr.s6_addr[7] == (a3 & 0xFF) && \ + a.sockaddr.in6.sin6_addr.s6_addr[8] == (a4 >> 8) && \ + a.sockaddr.in6.sin6_addr.s6_addr[9] == (a4 & 0xFF) && \ + a.sockaddr.in6.sin6_addr.s6_addr[10] == (a5 >> 8) && \ + a.sockaddr.in6.sin6_addr.s6_addr[11] == (a5 & 0xFF) && \ + a.sockaddr.in6.sin6_addr.s6_addr[12] == (a6 >> 8) && \ + a.sockaddr.in6.sin6_addr.s6_addr[13] == (a6 & 0xFF) && \ + a.sockaddr.in6.sin6_addr.s6_addr[14] == (a7 >> 8) && \ + a.sockaddr.in6.sin6_addr.s6_addr[15] == (a7 & 0xFF)) +#define SET_V6(a, a0, a1, a2, a3, a4, a5, a6, a7) \ + a.sockaddr.in6.sin6_addr.s6_addr[0] = a0 >> 8; \ + a.sockaddr.in6.sin6_addr.s6_addr[1] = a0 & 0xFF; \ + a.sockaddr.in6.sin6_addr.s6_addr[2] = a1 >> 8; \ + a.sockaddr.in6.sin6_addr.s6_addr[3] = a1 & 0xFF; \ + a.sockaddr.in6.sin6_addr.s6_addr[4] = a2 >> 8; \ + a.sockaddr.in6.sin6_addr.s6_addr[5] = a2 & 0xFF; \ + a.sockaddr.in6.sin6_addr.s6_addr[6] = a3 >> 8; \ + a.sockaddr.in6.sin6_addr.s6_addr[7] = a3 & 0xFF; \ + a.sockaddr.in6.sin6_addr.s6_addr[8] = a4 >> 8; \ + a.sockaddr.in6.sin6_addr.s6_addr[9] = a4 & 0xFF; \ + a.sockaddr.in6.sin6_addr.s6_addr[10] = a5 >> 8; \ + a.sockaddr.in6.sin6_addr.s6_addr[11] = a5 & 0xFF; \ + a.sockaddr.in6.sin6_addr.s6_addr[12] = a6 >> 8; \ + a.sockaddr.in6.sin6_addr.s6_addr[13] = a6 & 0xFF; \ + a.sockaddr.in6.sin6_addr.s6_addr[14] = a7 >> 8; \ + a.sockaddr.in6.sin6_addr.s6_addr[15] = a7 & 0xFF; + +@implementation OFSocketTests +- (void)testParseIPv4 +{ + OFSocketAddress address = OFSocketAddressParseIP(@"127.0.0.1", 1234); + + OTAssertEqual(OFFromBigEndian32(address.sockaddr.in.sin_addr.s_addr), + 0x7F000001); + OTAssertEqual(OFFromBigEndian16(address.sockaddr.in.sin_port), 1234); +} + +- (void)testParseRejectsInvalidIPv4 +{ + OTAssertThrowsSpecific(OFSocketAddressParseIP(@"127.0.0.0.1", 1234), + OFInvalidFormatException); + + OTAssertThrowsSpecific(OFSocketAddressParseIP(@"127.0.0.256", 1234), + OFInvalidFormatException); + + OTAssertThrowsSpecific(OFSocketAddressParseIP(@"127.0.0. 1", 1234), + OFInvalidFormatException); + + OTAssertThrowsSpecific(OFSocketAddressParseIP(@" 127.0.0.1", 1234), + OFInvalidFormatException); + + OTAssertThrowsSpecific(OFSocketAddressParseIP(@"127.0.a.1", 1234), + OFInvalidFormatException); + + OTAssertThrowsSpecific(OFSocketAddressParseIP(@"127.0..1", 1234), + OFInvalidFormatException); +} + +- (void)testPortForIPv4 +{ + OFSocketAddress address = OFSocketAddressParseIP(@"127.0.0.1", 1234); + + OTAssertEqual(OFSocketAddressIPPort(&address), 1234); +} + +- (void)testStringForIPv4 +{ + OFSocketAddress address = OFSocketAddressParseIP(@"127.0.0.1", 1234); + + OTAssertEqualObjects(OFSocketAddressString(&address), @"127.0.0.1"); +} + +- (void)testParseIPv6 +{ + OFSocketAddress address; + + address = OFSocketAddressParseIP( + @"1122:3344:5566:7788:99aa:bbCc:ddee:ff00", 1234); + OTAssert(COMPARE_V6(address, + 0x1122, 0x3344, 0x5566, 0x7788, 0x99AA, 0xBBCC, 0xDDEE, 0xFF00)); + OTAssertEqual(OFFromBigEndian16(address.sockaddr.in6.sin6_port), 1234); + + address = OFSocketAddressParseIP(@"::", 1234); + OTAssert(COMPARE_V6(address, 0, 0, 0, 0, 0, 0, 0, 0)); + OTAssertEqual(OFFromBigEndian16(address.sockaddr.in6.sin6_port), 1234); + + address = OFSocketAddressParseIP(@"aaAa::bBbb", 1234); + OTAssert(COMPARE_V6(address, 0xAAAA, 0, 0, 0, 0, 0, 0, 0xBBBB)); + OTAssertEqual(OFFromBigEndian16(address.sockaddr.in6.sin6_port), 1234); + + address = OFSocketAddressParseIP(@"aaAa::", 1234); + OTAssert(COMPARE_V6(address, 0xAAAA, 0, 0, 0, 0, 0, 0, 0)); + OTAssertEqual(OFFromBigEndian16(address.sockaddr.in6.sin6_port), 1234); + + address = OFSocketAddressParseIP(@"::aaAa", 1234); + OTAssert(COMPARE_V6(address, 0, 0, 0, 0, 0, 0, 0, 0xAAAA)); + OTAssertEqual(OFFromBigEndian16(address.sockaddr.in6.sin6_port), 1234); + + address = OFSocketAddressParseIP(@"fd00::1%123", 1234); + OTAssert(COMPARE_V6(address, 0xFD00, 0, 0, 0, 0, 0, 0, 1)); + OTAssertEqual(OFFromBigEndian16(address.sockaddr.in6.sin6_port), 1234); + OTAssertEqual(address.sockaddr.in6.sin6_scope_id, 123); + + address = OFSocketAddressParseIP(@"::ffff:127.0.0.1", 1234); + OTAssert(COMPARE_V6(address, 0, 0, 0, 0, 0, 0xFFFF, 0x7F00, 1)); + OTAssertEqual(OFFromBigEndian16(address.sockaddr.in6.sin6_port), 1234); + + address = OFSocketAddressParseIP(@"64:ff9b::127.0.0.1", 1234); + OTAssert(COMPARE_V6(address, 0x64, 0xFF9B, 0, 0, 0, 0, 0x7F00, 1)); + OTAssertEqual(OFFromBigEndian16(address.sockaddr.in6.sin6_port), 1234); +} + +- (void)testParseRejectsInvalidIPv6 +{ + OTAssertThrowsSpecific(OFSocketAddressParseIP(@"1:::2", 1234), + OFInvalidFormatException); + + OTAssertThrowsSpecific(OFSocketAddressParseIP(@"1: ::2", 1234), + OFInvalidFormatException); + + OTAssertThrowsSpecific(OFSocketAddressParseIP(@"1:: :2", 1234), + OFInvalidFormatException); + + OTAssertThrowsSpecific(OFSocketAddressParseIP(@"1::2::3", 1234), + OFInvalidFormatException); + + OTAssertThrowsSpecific(OFSocketAddressParseIP(@"10000::1", 1234), + OFInvalidFormatException); + + OTAssertThrowsSpecific(OFSocketAddressParseIP(@"::10000", 1234), + OFInvalidFormatException); + + OTAssertThrowsSpecific(OFSocketAddressParseIP(@"::1::", 1234), + OFInvalidFormatException); + + OTAssertThrowsSpecific(OFSocketAddressParseIP(@"1:2:3:4:5:6:7:", 1234), + OFInvalidFormatException); + + OTAssertThrowsSpecific(OFSocketAddressParseIP(@"1:2:3:4:5:6:7::", 1234), + OFInvalidFormatException); + + OTAssertThrowsSpecific(OFSocketAddressParseIP(@"1:2", 1234), + OFInvalidFormatException); +} + +- (void)testPortForIPv6 +{ + OFSocketAddress address = OFSocketAddressParseIP(@"::", 1234); + + OTAssertEqual(OFSocketAddressIPPort(&address), 1234); +} + +- (void)testStringForIPv6 +{ + OFSocketAddress address = OFSocketAddressParseIP(@"::", 1234); + + OTAssertEqualObjects(OFSocketAddressString(&address), @"::"); + + SET_V6(address, 0, 0, 0, 0, 0, 0, 0, 1) + OTAssertEqualObjects(OFSocketAddressString(&address), @"::1"); + + SET_V6(address, 1, 0, 0, 0, 0, 0, 0, 0) + OTAssertEqualObjects(OFSocketAddressString(&address), @"1::"); + + SET_V6(address, + 0x1122, 0x3344, 0x5566, 0x7788, 0x99AA, 0xBBCC, 0xDDEE, 0xFF00) + OTAssertEqualObjects(OFSocketAddressString(&address), + @"1122:3344:5566:7788:99aa:bbcc:ddee:ff00"); + + SET_V6(address, + 0x1122, 0x3344, 0x5566, 0x7788, 0x99AA, 0xBBCC, 0xDDEE, 0) + OTAssertEqualObjects(OFSocketAddressString(&address), + @"1122:3344:5566:7788:99aa:bbcc:ddee:0"); + + SET_V6(address, 0x1122, 0x3344, 0x5566, 0x7788, 0x99AA, 0xBBCC, 0, 0) + OTAssertEqualObjects(OFSocketAddressString(&address), + @"1122:3344:5566:7788:99aa:bbcc::"); + + SET_V6(address, + 0, 0x3344, 0x5566, 0x7788, 0x99AA, 0xBBCC, 0xDDEE, 0xFF00) + OTAssertEqualObjects(OFSocketAddressString(&address), + @"0:3344:5566:7788:99aa:bbcc:ddee:ff00"); + + SET_V6(address, 0, 0, 0x5566, 0x7788, 0x99AA, 0xBBCC, 0xDDEE, 0xFF00) + OTAssertEqualObjects(OFSocketAddressString(&address), + @"::5566:7788:99aa:bbcc:ddee:ff00"); + + SET_V6(address, 0, 0, 0x5566, 0, 0, 0, 0xDDEE, 0xFF00) + OTAssertEqualObjects(OFSocketAddressString(&address), + @"0:0:5566::ddee:ff00"); + + SET_V6(address, 0, 0, 0x5566, 0x7788, 0x99AA, 0xBBCC, 0, 0) + OTAssertEqualObjects(OFSocketAddressString(&address), + @"::5566:7788:99aa:bbcc:0:0"); + + address.sockaddr.in6.sin6_scope_id = 123; + OTAssertEqualObjects(OFSocketAddressString(&address), + @"::5566:7788:99aa:bbcc:0:0%123"); +} +@end ADDED new_tests/OFSubprocessTests.m Index: new_tests/OFSubprocessTests.m ================================================================== --- new_tests/OFSubprocessTests.m +++ new_tests/OFSubprocessTests.m @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2008-2024 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#include "config.h" + +#import "ObjFW.h" +#import "ObjFWTest.h" + +@interface OFSubprocessTests: OTTestCase +@end + +@implementation OFSubprocessTests +- (void)testSubprocess +{ +#ifdef OF_HAVE_FILES + OFString *program = [@"subprocess" stringByAppendingPathComponent: + @"subprocess" @PROG_SUFFIX]; +#else + OFString *program = @"subprocess/subprocess" @PROG_SUFFIX; +#endif + OFArray *arguments = [OFArray arrayWithObjects: @"tést", @"123", nil]; + OFMutableDictionary *environment = + [[[OFApplication environment] mutableCopy] autorelease]; + OFSubprocess *subprocess; + + [environment setObject: @"yés" forKey: @"tëst"]; + + subprocess = [OFSubprocess subprocessWithProgram: program + programName: program + arguments: arguments + environment: environment]; + + [subprocess writeLine: @"Hellö world!"]; + OTAssertEqualObjects([subprocess readLine], @"HELLÖ WORLD!"); + + [subprocess closeForWriting]; + + OTAssertEqual([subprocess waitForTermination], 0); +} +@end ADDED new_tests/OFThreadTests.m Index: new_tests/OFThreadTests.m ================================================================== --- new_tests/OFThreadTests.m +++ new_tests/OFThreadTests.m @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2008-2024 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#include "config.h" + +#import "ObjFW.h" +#import "ObjFWTest.h" + +@interface OFThreadTests: OTTestCase +@end + +@interface TestThread: OFThread +@end + +@implementation TestThread +- (id)main +{ + [[OFThread threadDictionary] setObject: @"bar" forKey: @"foo"]; + OFEnsure([[[OFThread threadDictionary] + objectForKey: @"foo"] isEqual: @"bar"]); + + return @"success"; +} +@end + +@implementation OFThreadTests +- (void)testThread +{ + TestThread *thread = [TestThread thread]; + + [thread start]; + + OTAssertEqualObjects([thread join], @"success"); + OTAssertNil([[OFThread threadDictionary] objectForKey: @"foo"]); +} +@end ADDED new_tests/plugin/Info.plist.in Index: new_tests/plugin/Info.plist.in ================================================================== --- new_tests/plugin/Info.plist.in +++ new_tests/plugin/Info.plist.in @@ -0,0 +1,22 @@ + + + + + CFBundleExecutable + TestPlugin + CFBundleName + TestPlugin + CFBundleIdentifier + im.nil.objfw.tests.plugin + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + BNDL + CFBundleVersion + @BUNDLE_VERSION@ + CFBundleShortVersionString + @BUNDLE_SHORT_VERSION@ + MinimumOSVersion + 9.0 + + ADDED new_tests/plugin/Makefile Index: new_tests/plugin/Makefile ================================================================== --- new_tests/plugin/Makefile +++ new_tests/plugin/Makefile @@ -0,0 +1,11 @@ +DISTCLEAN = Info.plist + +PLUGIN_NOINST = TestPlugin${PLUGIN_SUFFIX} +SRCS = TestPlugin.m + +include ../../buildsys.mk +include ../../extra.mk + +CPPFLAGS += -I../.. -I../../src -I../../src/runtime +LIBS := ${TESTPLUGIN_LIBS} ${LIBS} +LD = ${OBJC} ADDED new_tests/plugin/TestPlugin.h Index: new_tests/plugin/TestPlugin.h ================================================================== --- new_tests/plugin/TestPlugin.h +++ new_tests/plugin/TestPlugin.h @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2008-2024 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#import "OFObject.h" + +@interface TestPlugin: OFObject +- (int)test: (int)num; +@end ADDED new_tests/plugin/TestPlugin.m Index: new_tests/plugin/TestPlugin.m ================================================================== --- new_tests/plugin/TestPlugin.m +++ new_tests/plugin/TestPlugin.m @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2008-2024 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#include "config.h" + +#import "TestPlugin.h" + +#ifdef OF_OBJFW_RUNTIME +# import "runtime/private.h" + +OF_DESTRUCTOR() +{ + Class class = objc_getClass("TestPlugin"); + + if (class == Nil) + /* + * musl has broken dlclose(): Instead of calling the destructor + * on dlclose(), they call it on exit(). This of course means + * that our tests might have already called objc_deinit() and + * the class is already gone. + */ + return; + + objc_unregisterClass(class); +} +#endif + +@implementation TestPlugin +- (int)test: (int)num +{ + return num * 2; +} +@end + +Class +class(void) +{ + return [TestPlugin class]; +} ADDED new_tests/subprocess/Makefile Index: new_tests/subprocess/Makefile ================================================================== --- new_tests/subprocess/Makefile +++ new_tests/subprocess/Makefile @@ -0,0 +1,9 @@ +PROG_NOINST = subprocess${PROG_SUFFIX} +SRCS = Subprocess.m + +include ../../buildsys.mk +include ../../extra.mk + +CPPFLAGS += -I../../src -I../../src/exceptions -I../../src/runtime -I../.. +LIBS := -L../../src -lobjfw -L../../src/runtime ${RUNTIME_LIBS} ${LIBS} +LD = ${OBJC} ADDED new_tests/subprocess/Subprocess.m Index: new_tests/subprocess/Subprocess.m ================================================================== --- new_tests/subprocess/Subprocess.m +++ new_tests/subprocess/Subprocess.m @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2008-2024 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#include "config.h" + +#import "ObjFW.h" + +@interface Subprocess: OFObject +@end + +OF_APPLICATION_DELEGATE(Subprocess) + +@implementation Subprocess +- (void)applicationDidFinishLaunching: (OFNotification *)notification +{ + OFString *line; + + if (![[OFApplication arguments] isEqual: + [OFArray arrayWithObjects: @"tést", @"123", nil]]) + [OFApplication terminateWithStatus: 1]; + + if (![[[OFApplication environment] objectForKey: @"tëst"] + isEqual: @"yés"]) + [OFApplication terminateWithStatus: 2]; + + while ((line = [OFStdIn readLine]) != nil) + [OFStdOut writeLine: line.uppercaseString]; + + [OFApplication terminate]; +} +@end ADDED new_tests/testfile.bin Index: new_tests/testfile.bin ================================================================== --- new_tests/testfile.bin +++ new_tests/testfile.bin cannot compute difference between binary files ADDED new_tests/testfile.ini Index: new_tests/testfile.ini ================================================================== --- new_tests/testfile.ini +++ new_tests/testfile.ini @@ -0,0 +1,21 @@ +[tests] +foo = bar +foobar=baz +;comment + +[foobar] +;foobarcomment +qux=" asd" +"quxqux " = asd +quxquxqux="hello\"wörld" +qux2="a\f" + +[types] +integer = 0x20 +bool = true +float = 0.5 +array1 = 1 +array2 = 1 +double = 0.25 +array1 = 2 +array2 = 2 Index: src/Makefile ================================================================== --- src/Makefile +++ src/Makefile @@ -1,9 +1,9 @@ include ../extra.mk SUBDIRS = ${RUNTIME} exceptions encodings forwarding -SUBDIRS_AFTER = ${BRIDGE} ${TLS} +SUBDIRS_AFTER = ${BRIDGE} ${TLS} test DISTCLEAN = Info.plist objfw-defs.h SHARED_LIB = ${OBJFW_SHARED_LIB} STATIC_LIB = ${OBJFW_STATIC_LIB} FRAMEWORK = ${OBJFW_FRAMEWORK} @@ -96,11 +96,10 @@ OFString+JSONParsing.m \ OFString+PercentEncoding.m \ OFString+PropertyListParsing.m \ OFString+XMLEscaping.m \ OFString+XMLUnescaping.m \ - ${OF_SUBPROCESS_M} \ OFSystemInfo.m \ OFTarArchive.m \ OFTarArchiveEntry.m \ OFThread.m \ OFTimer.m \ @@ -119,42 +118,57 @@ OFZIPArchive.m \ OFZIPArchiveEntry.m \ ${USE_SRCS_FILES} \ ${USE_SRCS_PLUGINS} \ ${USE_SRCS_SOCKETS} \ + ${USE_SRCS_SUBPROCESSES} \ ${USE_SRCS_THREADS} \ ${USE_SRCS_WINDOWS} SRCS_FILES = OFFile.m \ OFString+PathAdditions.m SRCS_PLUGINS = OFPlugin.m -SRCS_SOCKETS = OFDNSQuery.m \ +SRCS_SOCKETS = OFAAAADNSResourceRecord.m \ + OFADNSResourceRecord.m \ + OFCNAMEDNSResourceRecord.m \ + OFDNSQuery.m \ OFDNSResolver.m \ OFDNSResourceRecord.m \ OFDNSResponse.m \ OFDatagramSocket.m \ + OFHINFODNSResourceRecord.m \ OFHTTPClient.m \ OFHTTPCookie.m \ OFHTTPCookieManager.m \ OFHTTPRequest.m \ OFHTTPResponse.m \ OFHTTPServer.m \ + OFLOCDNSResourceRecord.m \ + OFMXDNSResourceRecord.m \ + OFNSDNSResourceRecord.m \ + OFPTRDNSResourceRecord.m \ + OFRPDNSResourceRecord.m \ + OFSOADNSResourceRecord.m \ + OFSRVDNSResourceRecord.m \ OFSequencedPacketSocket.m \ OFSocket.m \ OFStreamSocket.m \ OFSystemInfo+NetworkInterfaces.m \ OFTCPSocket.m \ OFTLSStream.m \ + OFTXTDNSResourceRecord.m \ OFUDPSocket.m \ + OFURIDNSResourceRecord.m \ ${USE_SRCS_APPLETALK} \ ${USE_SRCS_IPX} \ ${USE_SRCS_UNIX_SOCKETS} SRCS_APPLETALK = OFDDPSocket.m SRCS_IPX = OFIPXSocket.m \ OFSPXSocket.m \ OFSPXStreamSocket.m SRCS_UNIX_SOCKETS = OFUNIXDatagramSocket.m \ OFUNIXStreamSocket.m +SRCS_SUBPROCESSES = OFSubprocess.m SRCS_THREADS = OFCondition.m \ OFMutex.m \ OFPlainCondition.m \ OFPlainMutex.m \ OFPlainThread.m \ ADDED src/OFAAAADNSResourceRecord.h Index: src/OFAAAADNSResourceRecord.h ================================================================== --- src/OFAAAADNSResourceRecord.h +++ src/OFAAAADNSResourceRecord.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2008-2024 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#import "OFDNSResourceRecord.h" + +OF_ASSUME_NONNULL_BEGIN + +/** + * @class OFAAAADNSResourceRecord \ + * OFDNSResourceRecord.h ObjFW/OFDNSResourceRecord.h + * + * @brief A class representing a DNS resource record. + */ +OF_SUBCLASSING_RESTRICTED +@interface OFAAAADNSResourceRecord: OFDNSResourceRecord +{ + OFSocketAddress _address; +} + +/** + * @brief The IPv6 address of the resource record. + */ +@property (readonly, nonatomic) const OFSocketAddress *address; + +- (instancetype)initWithName: (OFString *)name + DNSClass: (OFDNSClass)DNSClass + recordType: (OFDNSRecordType)recordType + TTL: (uint32_t)TTL OF_UNAVAILABLE; + +/** + * @brief Initializes an already allocated OFAAAADNSResourceRecord with the + * specified name, class, address and time to live. + * + * @param name The name for the resource record + * @param address The address for the resource record + * @param TTL The time to live for the resource record + * @return An initialized OFAAAADNSResourceRecord + */ +- (instancetype)initWithName: (OFString *)name + address: (const OFSocketAddress *)address + TTL: (uint32_t)TTL OF_DESIGNATED_INITIALIZER; +@end + +OF_ASSUME_NONNULL_END ADDED src/OFAAAADNSResourceRecord.m Index: src/OFAAAADNSResourceRecord.m ================================================================== --- src/OFAAAADNSResourceRecord.m +++ src/OFAAAADNSResourceRecord.m @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2008-2024 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#include "config.h" + +#import "OFAAAADNSResourceRecord.h" + +@implementation OFAAAADNSResourceRecord +- (instancetype)initWithName: (OFString *)name + DNSClass: (OFDNSClass)DNSClass + recordType: (OFDNSRecordType)recordType + TTL: (uint32_t)TTL +{ + OF_INVALID_INIT_METHOD +} + +- (instancetype)initWithName: (OFString *)name + address: (const OFSocketAddress *)address + TTL: (uint32_t)TTL +{ + self = [super initWithName: name + DNSClass: OFDNSClassIN + recordType: OFDNSRecordTypeAAAA + TTL: TTL]; + + _address = *address; + + return self; +} + +- (const OFSocketAddress *)address +{ + return &_address; +} + +- (bool)isEqual: (id)object +{ + OFAAAADNSResourceRecord *record; + + if (object == self) + return true; + + if (![object isKindOfClass: [OFAAAADNSResourceRecord class]]) + return false; + + record = object; + + if (record->_name != _name && ![record->_name isEqual: _name]) + return false; + + if (record->_DNSClass != _DNSClass) + return false; + + if (record->_recordType != _recordType) + return false; + + if (!OFSocketAddressEqual(&record->_address, &_address)) + return false; + + return true; +} + +- (unsigned long)hash +{ + unsigned long hash; + + OFHashInit(&hash); + + OFHashAddHash(&hash, _name.hash); + OFHashAddByte(&hash, _DNSClass >> 8); + OFHashAddByte(&hash, _DNSClass); + OFHashAddByte(&hash, _recordType >> 8); + OFHashAddByte(&hash, _recordType); + OFHashAddHash(&hash, OFSocketAddressHash(&_address)); + + OFHashFinalize(&hash); + + return hash; +} + +- (OFString *)description +{ + return [OFString stringWithFormat: + @"<%@:\n" + @"\tName = %@\n" + @"\tAddress = %@\n" + @"\tTTL = %" PRIu32 "\n" + @">", + self.className, _name, OFSocketAddressString(&_address), _TTL]; +} +@end ADDED src/OFADNSResourceRecord.h Index: src/OFADNSResourceRecord.h ================================================================== --- src/OFADNSResourceRecord.h +++ src/OFADNSResourceRecord.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2008-2024 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#import "OFDNSResourceRecord.h" + +OF_ASSUME_NONNULL_BEGIN + +/** + * @class OFADNSResourceRecord OFDNSResourceRecord.h ObjFW/OFDNSResourceRecord.h + * + * @brief A class representing an A DNS resource record. + */ +OF_SUBCLASSING_RESTRICTED +@interface OFADNSResourceRecord: OFDNSResourceRecord +{ + OFSocketAddress _address; +} + +/** + * @brief The IPv4 address of the resource record. + */ +@property (readonly, nonatomic) const OFSocketAddress *address; + +- (instancetype)initWithName: (OFString *)name + DNSClass: (OFDNSClass)DNSClass + recordType: (OFDNSRecordType)recordType + TTL: (uint32_t)TTL OF_UNAVAILABLE; + +/** + * @brief Initializes an already allocated OFADNSResourceRecord with the + * specified name, class, address and time to live. + * + * @param name The name for the resource record + * @param address The address for the resource record + * @param TTL The time to live for the resource record + * @return An initialized OFADNSResourceRecord + */ +- (instancetype)initWithName: (OFString *)name + address: (const OFSocketAddress *)address + TTL: (uint32_t)TTL OF_DESIGNATED_INITIALIZER; +@end + +OF_ASSUME_NONNULL_END ADDED src/OFADNSResourceRecord.m Index: src/OFADNSResourceRecord.m ================================================================== --- src/OFADNSResourceRecord.m +++ src/OFADNSResourceRecord.m @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2008-2024 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#include "config.h" + +#import "OFADNSResourceRecord.h" + +@implementation OFADNSResourceRecord +- (instancetype)initWithName: (OFString *)name + DNSClass: (OFDNSClass)DNSClass + recordType: (OFDNSRecordType)recordType + TTL: (uint32_t)TTL +{ + OF_INVALID_INIT_METHOD +} + +- (instancetype)initWithName: (OFString *)name + address: (const OFSocketAddress *)address + TTL: (uint32_t)TTL +{ + self = [super initWithName: name + DNSClass: OFDNSClassIN + recordType: OFDNSRecordTypeA + TTL: TTL]; + + _address = *address; + + return self; +} + +- (const OFSocketAddress *)address +{ + return &_address; +} + +- (bool)isEqual: (id)object +{ + OFADNSResourceRecord *record; + + if (object == self) + return true; + + if (![object isKindOfClass: [OFADNSResourceRecord class]]) + return false; + + record = object; + + if (record->_name != _name && ![record->_name isEqual: _name]) + return false; + + if (record->_DNSClass != _DNSClass) + return false; + + if (record->_recordType != _recordType) + return false; + + if (!OFSocketAddressEqual(&record->_address, &_address)) + return false; + + return true; +} + +- (unsigned long)hash +{ + unsigned long hash; + + OFHashInit(&hash); + + OFHashAddHash(&hash, _name.hash); + OFHashAddByte(&hash, _DNSClass >> 8); + OFHashAddByte(&hash, _DNSClass); + OFHashAddByte(&hash, _recordType >> 8); + OFHashAddByte(&hash, _recordType); + OFHashAddHash(&hash, OFSocketAddressHash(&_address)); + + OFHashFinalize(&hash); + + return hash; +} + +- (OFString *)description +{ + return [OFString stringWithFormat: + @"<%@:\n" + @"\tName = %@\n" + @"\tAddress = %@\n" + @"\tTTL = %" PRIu32 "\n" + @">", + self.className, _name, OFSocketAddressString(&_address), _TTL]; +} +@end ADDED src/OFCNAMEDNSResourceRecord.h Index: src/OFCNAMEDNSResourceRecord.h ================================================================== --- src/OFCNAMEDNSResourceRecord.h +++ src/OFCNAMEDNSResourceRecord.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2008-2024 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#import "OFDNSResourceRecord.h" + +OF_ASSUME_NONNULL_BEGIN + +/** + * @class OFCNAMEDNSResourceRecord \ + * OFDNSResourceRecord.h ObjFW/OFDNSResourceRecord.h + * + * @brief A class representing a CNAME DNS resource record. + */ +OF_SUBCLASSING_RESTRICTED +@interface OFCNAMEDNSResourceRecord: OFDNSResourceRecord +{ + OFString *_alias; +} + +/** + * @brief The alias of the resource record. + */ +@property (readonly, nonatomic) OFString *alias; + +- (instancetype)initWithName: (OFString *)name + DNSClass: (OFDNSClass)DNSClass + recordType: (OFDNSRecordType)recordType + TTL: (uint32_t)TTL OF_UNAVAILABLE; + +/** + * @brief Initializes an already allocated OFCNAMEDNSResourceRecord with the + * specified name, class, alias and time to live. + * + * @param name The name for the resource record + * @param DNSClass The class code for the resource record + * @param alias The alias for the resource record + * @param TTL The time to live for the resource record + * @return An initialized OFCNAMEDNSResourceRecord + */ +- (instancetype)initWithName: (OFString *)name + DNSClass: (OFDNSClass)DNSClass + alias: (OFString *)alias + TTL: (uint32_t)TTL OF_DESIGNATED_INITIALIZER; +@end + +OF_ASSUME_NONNULL_END ADDED src/OFCNAMEDNSResourceRecord.m Index: src/OFCNAMEDNSResourceRecord.m ================================================================== --- src/OFCNAMEDNSResourceRecord.m +++ src/OFCNAMEDNSResourceRecord.m @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2008-2024 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#include "config.h" + +#import "OFCNAMEDNSResourceRecord.h" + +@implementation OFCNAMEDNSResourceRecord +@synthesize alias = _alias; + +- (instancetype)initWithName: (OFString *)name + DNSClass: (OFDNSClass)DNSClass + recordType: (OFDNSRecordType)recordType + TTL: (uint32_t)TTL +{ + OF_INVALID_INIT_METHOD +} + +- (instancetype)initWithName: (OFString *)name + DNSClass: (OFDNSClass)DNSClass + alias: (OFString *)alias + TTL: (uint32_t)TTL +{ + self = [super initWithName: name + DNSClass: DNSClass + recordType: OFDNSRecordTypeCNAME + TTL: TTL]; + + @try { + _alias = [alias copy]; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (void)dealloc +{ + [_alias release]; + + [super dealloc]; +} + +- (bool)isEqual: (id)object +{ + OFCNAMEDNSResourceRecord *record; + + if (object == self) + return true; + + if (![object isKindOfClass: [OFCNAMEDNSResourceRecord class]]) + return false; + + record = object; + + if (record->_name != _name && ![record->_name isEqual: _name]) + return false; + + if (record->_DNSClass != _DNSClass) + return false; + + if (record->_recordType != _recordType) + return false; + + if (record->_alias != _alias && ![record->_alias isEqual: _alias]) + return false; + + return true; +} + +- (unsigned long)hash +{ + unsigned long hash; + + OFHashInit(&hash); + + OFHashAddHash(&hash, _name.hash); + OFHashAddByte(&hash, _DNSClass >> 8); + OFHashAddByte(&hash, _DNSClass); + OFHashAddByte(&hash, _recordType >> 8); + OFHashAddByte(&hash, _recordType); + OFHashAddHash(&hash, _alias.hash); + + OFHashFinalize(&hash); + + return hash; +} + +- (OFString *)description +{ + return [OFString stringWithFormat: + @"<%@:\n" + @"\tName = %@\n" + @"\tClass = %@\n" + @"\tAlias = %@\n" + @"\tTTL = %" PRIu32 "\n" + @">", + self.className, _name, OFDNSClassName(_DNSClass), _alias, _TTL]; +} +@end Index: src/OFColor.h ================================================================== --- src/OFColor.h +++ src/OFColor.h @@ -24,11 +24,13 @@ */ @interface OFColor: OFObject #ifdef OF_HAVE_CLASS_PROPERTIES @property (class, readonly, nonatomic) OFColor *black; @property (class, readonly, nonatomic) OFColor *silver; -@property (class, readonly, nonatomic) OFColor *grey; +@property (class, readonly, nonatomic) OFColor *gray; +@property (class, readonly, nonatomic) OFColor *grey + OF_DEPRECATED(ObjFW, 1, 1, "Use gray instead"); @property (class, readonly, nonatomic) OFColor *white; @property (class, readonly, nonatomic) OFColor *maroon; @property (class, readonly, nonatomic) OFColor *red; @property (class, readonly, nonatomic) OFColor *purple; @property (class, readonly, nonatomic) OFColor *fuchsia; @@ -74,17 +76,28 @@ * @return The HTML color `silver` */ + (OFColor *)silver; /** - * @brief Returns the HTML color `grey`. + * @brief Returns the HTML color `gray`. + * + * The RGBA value is (0.5, 0.5, 0.5, 1). + * + * @return The HTML color `gray` + */ ++ (OFColor *)gray; + +/** + * @brief Returns the HTML color `gray`. + * + * @deprecated Use @ref gray instead. * * The RGBA value is (0.5, 0.5, 0.5, 1). * - * @return The HTML color `grey` + * @return The HTML color `gray` */ -+ (OFColor *)grey; ++ (OFColor *)grey OF_DEPRECATED(ObjFW, 1, 1, "Use gray instead"); /** * @brief Returns the HTML color `white`. * * The RGBA value is (1, 1, 1, 1). Index: src/OFColor.m ================================================================== --- src/OFColor.m +++ src/OFColor.m @@ -109,11 +109,11 @@ return name##Color; \ } PREDEFINED_COLOR(black, 0.00f, 0.00f, 0.00f) PREDEFINED_COLOR(silver, 0.75f, 0.75f, 0.75f) -PREDEFINED_COLOR(grey, 0.50f, 0.50f, 0.50f) +PREDEFINED_COLOR(gray, 0.50f, 0.50f, 0.50f) PREDEFINED_COLOR(white, 1.00f, 1.00f, 1.00f) PREDEFINED_COLOR(maroon, 0.50f, 0.00f, 0.00f) PREDEFINED_COLOR(red, 1.00f, 0.00f, 0.00f) PREDEFINED_COLOR(purple, 0.50f, 0.00f, 0.50f) PREDEFINED_COLOR(fuchsia, 1.00f, 0.00f, 1.00f) @@ -123,10 +123,15 @@ PREDEFINED_COLOR(yellow, 1.00f, 1.00f, 0.00f) PREDEFINED_COLOR(navy, 0.00f, 0.00f, 0.50f) PREDEFINED_COLOR(blue, 0.00f, 0.00f, 1.00f) PREDEFINED_COLOR(teal, 0.00f, 0.50f, 0.50f) PREDEFINED_COLOR(aqua, 0.00f, 1.00f, 1.00f) + ++ (OFColor *)grey +{ + return [self gray]; +} + (instancetype)colorWithRed: (float)red green: (float)green blue: (float)blue alpha: (float)alpha Index: src/OFDNSResolver.m ================================================================== --- src/OFDNSResolver.m +++ src/OFDNSResolver.m @@ -377,10 +377,37 @@ return [[[OFAAAADNSResourceRecord alloc] initWithName: name address: &address TTL: TTL] autorelease]; + } else if (recordType == OFDNSRecordTypeLOC) { + uint8_t size, horizontalPrecision, verticalPrecision; + uint32_t latitude, longitude, altitude; + + if (dataLength < 16 || buffer[i] != 0) + @throw [OFInvalidServerResponseException exception]; + + size = buffer[i + 1]; + horizontalPrecision = buffer[i + 2]; + verticalPrecision = buffer[i + 3]; + latitude = (buffer[i + 4] << 24) | (buffer[i + 5] << 16) | + (buffer[i + 6] << 8) | buffer[i + 7]; + longitude = (buffer[i + 8] << 24) | (buffer[i + 9] << 16) | + (buffer[i + 10] << 8) | buffer[i + 11]; + altitude = (buffer[i + 12] << 24) | (buffer[i + 13] << 16) | + (buffer[i + 14] << 8) | buffer[i + 15]; + + return [[[OFLOCDNSResourceRecord alloc] + initWithName: name + DNSClass: DNSClass + size: size + horizontalPrecision: horizontalPrecision + verticalPrecision: verticalPrecision + latitude: latitude + longitude: longitude + altitude: altitude + TTL: TTL] autorelease]; } else if (recordType == OFDNSRecordTypeSRV && DNSClass == OFDNSClassIN) { uint16_t priority, weight, port; size_t j; OFString *target; @@ -402,10 +429,30 @@ initWithName: name priority: priority weight: weight target: target port: port + TTL: TTL] autorelease]; + } else if (recordType == OFDNSRecordTypeURI) { + uint16_t priority, weight; + OFString *target; + + if (dataLength < 4) + @throw [OFInvalidServerResponseException exception]; + + priority = (buffer[i] << 8) | buffer[i + 1]; + weight = (buffer[i + 2] << 8) | buffer[i + 3]; + + target = [OFString stringWithUTF8String: (char *)buffer + i + 4 + length: dataLength - 4]; + + return [[[OFURIDNSResourceRecord alloc] + initWithName: name + DNSClass: DNSClass + priority: priority + weight: weight + target: target TTL: TTL] autorelease]; } else return [[[OFDNSResourceRecord alloc] initWithName: name DNSClass: DNSClass @@ -431,15 +478,15 @@ OFDNSResourceRecord *record; if (*i + 10 > length) @throw [OFTruncatedDataException exception]; - recordType = (buffer[*i] << 16) | buffer[*i + 1]; - DNSClass = (buffer[*i + 2] << 16) | buffer[*i + 3]; + recordType = (buffer[*i] << 8) | buffer[*i + 1]; + DNSClass = (buffer[*i + 2] << 8) | buffer[*i + 3]; TTL = (buffer[*i + 4] << 24) | (buffer[*i + 5] << 16) | (buffer[*i + 6] << 8) | buffer[*i + 7]; - dataLength = (buffer[*i + 8] << 16) | buffer[*i + 9]; + dataLength = (buffer[*i + 8] << 8) | buffer[*i + 9]; *i += 10; if (*i + dataLength > length) @throw [OFTruncatedDataException exception]; Index: src/OFDNSResourceRecord.h ================================================================== --- src/OFDNSResourceRecord.h +++ src/OFDNSResourceRecord.h @@ -56,14 +56,18 @@ OFDNSRecordTypeTXT = 16, /** RP */ OFDNSRecordTypeRP = 17, /** AAAA */ OFDNSRecordTypeAAAA = 28, + /** LOC */ + OFDNSRecordTypeLOC = 29, /** SRV */ OFDNSRecordTypeSRV = 33, /** All types. Only for queries. */ OFDNSRecordTypeAll = 255, + /** URI */ + OFDNSRecordTypeURI = 256, } OFDNSRecordType; /** * @class OFDNSResourceRecord OFDNSResourceRecord.h ObjFW/OFDNSResourceRecord.h * @@ -113,512 +117,10 @@ DNSClass: (OFDNSClass)DNSClass recordType: (OFDNSRecordType)recordType TTL: (uint32_t)TTL OF_DESIGNATED_INITIALIZER; @end -/** - * @class OFADNSResourceRecord OFDNSResourceRecord.h ObjFW/OFDNSResourceRecord.h - * - * @brief A class representing an A DNS resource record. - */ -OF_SUBCLASSING_RESTRICTED -@interface OFADNSResourceRecord: OFDNSResourceRecord -{ - OFSocketAddress _address; -} - -/** - * @brief The IPv4 address of the resource record. - */ -@property (readonly, nonatomic) const OFSocketAddress *address; - -- (instancetype)initWithName: (OFString *)name - DNSClass: (OFDNSClass)DNSClass - recordType: (OFDNSRecordType)recordType - TTL: (uint32_t)TTL OF_UNAVAILABLE; - -/** - * @brief Initializes an already allocated OFADNSResourceRecord with the - * specified name, class, address and time to live. - * - * @param name The name for the resource record - * @param address The address for the resource record - * @param TTL The time to live for the resource record - * @return An initialized OFADNSResourceRecord - */ -- (instancetype)initWithName: (OFString *)name - address: (const OFSocketAddress *)address - TTL: (uint32_t)TTL OF_DESIGNATED_INITIALIZER; -@end - -/** - * @class OFAAAADNSResourceRecord \ - * OFDNSResourceRecord.h ObjFW/OFDNSResourceRecord.h - * - * @brief A class represenging a DNS resource record. - */ -OF_SUBCLASSING_RESTRICTED -@interface OFAAAADNSResourceRecord: OFDNSResourceRecord -{ - OFSocketAddress _address; -} - -/** - * @brief The IPv6 address of the resource record. - */ -@property (readonly, nonatomic) const OFSocketAddress *address; - -- (instancetype)initWithName: (OFString *)name - DNSClass: (OFDNSClass)DNSClass - recordType: (OFDNSRecordType)recordType - TTL: (uint32_t)TTL OF_UNAVAILABLE; - -/** - * @brief Initializes an already allocated OFAAAADNSResourceRecord with the - * specified name, class, address and time to live. - * - * @param name The name for the resource record - * @param address The address for the resource record - * @param TTL The time to live for the resource record - * @return An initialized OFAAAADNSResourceRecord - */ -- (instancetype)initWithName: (OFString *)name - address: (const OFSocketAddress *)address - TTL: (uint32_t)TTL OF_DESIGNATED_INITIALIZER; -@end - -/** - * @class OFCNAMEDNSResourceRecord \ - * OFDNSResourceRecord.h ObjFW/OFDNSResourceRecord.h - * - * @brief A class representing a CNAME DNS resource record. - */ -OF_SUBCLASSING_RESTRICTED -@interface OFCNAMEDNSResourceRecord: OFDNSResourceRecord -{ - OFString *_alias; -} - -/** - * @brief The alias of the resource record. - */ -@property (readonly, nonatomic) OFString *alias; - -- (instancetype)initWithName: (OFString *)name - DNSClass: (OFDNSClass)DNSClass - recordType: (OFDNSRecordType)recordType - TTL: (uint32_t)TTL OF_UNAVAILABLE; - -/** - * @brief Initializes an already allocated OFCNAMEDNSResourceRecord with the - * specified name, class, alias and time to live. - * - * @param name The name for the resource record - * @param DNSClass The class code for the resource record - * @param alias The alias for the resource record - * @param TTL The time to live for the resource record - * @return An initialized OFCNAMEDNSResourceRecord - */ -- (instancetype)initWithName: (OFString *)name - DNSClass: (OFDNSClass)DNSClass - alias: (OFString *)alias - TTL: (uint32_t)TTL OF_DESIGNATED_INITIALIZER; -@end - -/** - * @class OFHINFODNSResourceRecord \ - * OFDNSResourceRecord.h ObjFW/OFDNSResourceRecord.h - * - * @brief A class representing an HINFO DNS resource record. - */ -OF_SUBCLASSING_RESTRICTED -@interface OFHINFODNSResourceRecord: OFDNSResourceRecord -{ - OFString *_CPU, *_OS; -} - -/** - * @brief The CPU of the host info of the resource record. - */ -@property (readonly, nonatomic) OFString *CPU; - -/** - * @brief The OS of the host info of the resource record. - */ -@property (readonly, nonatomic) OFString *OS; - -- (instancetype)initWithName: (OFString *)name - DNSClass: (OFDNSClass)DNSClass - recordType: (OFDNSRecordType)recordType - TTL: (uint32_t)TTL OF_UNAVAILABLE; - -/** - * @brief Initializes an already allocated OFHINFODNSResourceRecord with the - * specified name, class, domain name and time to live. - * - * @param name The name for the resource record - * @param DNSClass The class code for the resource record - * @param CPU The CPU of the host info for the resource record - * @param OS The OS of the host info for the resource record - * @param TTL The time to live for the resource record - * @return An initialized OFHINFODNSResourceRecord - */ -- (instancetype)initWithName: (OFString *)name - DNSClass: (OFDNSClass)DNSClass - CPU: (OFString *)CPU - OS: (OFString *)OS - TTL: (uint32_t)TTL OF_DESIGNATED_INITIALIZER; -@end - -/** - * @class OFMXDNSResourceRecord \ - * OFDNSResourceRecord.h ObjFW/OFDNSResourceRecord.h - * - * @brief A class representing an MX DNS resource record. - */ -OF_SUBCLASSING_RESTRICTED -@interface OFMXDNSResourceRecord: OFDNSResourceRecord -{ - uint16_t _preference; - OFString *_mailExchange; -} - -/** - * @brief The preference of the resource record. - */ -@property (readonly, nonatomic) uint16_t preference; - -/** - * @brief The mail exchange of the resource record. - */ -@property (readonly, nonatomic) OFString *mailExchange; - -- (instancetype)initWithName: (OFString *)name - DNSClass: (OFDNSClass)DNSClass - recordType: (OFDNSRecordType)recordType - TTL: (uint32_t)TTL OF_UNAVAILABLE; - -/** - * @brief Initializes an already allocated OFMXDNSResourceRecord with the - * specified name, class, preference, mail exchange and time to live. - * - * @param name The name for the resource record - * @param DNSClass The class code for the resource record - * @param preference The preference for the resource record - * @param mailExchange The mail exchange for the resource record - * @param TTL The time to live for the resource record - * @return An initialized OFMXDNSResourceRecord - */ -- (instancetype)initWithName: (OFString *)name - DNSClass: (OFDNSClass)DNSClass - preference: (uint16_t)preference - mailExchange: (OFString *)mailExchange - TTL: (uint32_t)TTL OF_DESIGNATED_INITIALIZER; -@end - -/** - * @class OFNSDNSResourceRecord \ - * OFDNSResourceRecord.h ObjFW/OFDNSResourceRecord.h - * - * @brief A class representing an NS DNS resource record. - */ -OF_SUBCLASSING_RESTRICTED -@interface OFNSDNSResourceRecord: OFDNSResourceRecord -{ - OFString *_authoritativeHost; -} - -/** - * @brief The authoritative host of the resource record. - */ -@property (readonly, nonatomic) OFString *authoritativeHost; - -- (instancetype)initWithName: (OFString *)name - DNSClass: (OFDNSClass)DNSClass - recordType: (OFDNSRecordType)recordType - TTL: (uint32_t)TTL OF_UNAVAILABLE; - -/** - * @brief Initializes an already allocated OFNSDNSResourceRecord with the - * specified name, class, authoritative host and time to live. - * - * @param name The name for the resource record - * @param DNSClass The class code for the resource record - * @param authoritativeHost The authoritative host for the resource record - * @param TTL The time to live for the resource record - * @return An initialized OFNSDNSResourceRecord - */ -- (instancetype)initWithName: (OFString *)name - DNSClass: (OFDNSClass)DNSClass - authoritativeHost: (OFString *)authoritativeHost - TTL: (uint32_t)TTL OF_DESIGNATED_INITIALIZER; -@end - -/** - * @class OFPTRDNSResourceRecord \ - * OFDNSResourceRecord.h ObjFW/OFDNSResourceRecord.h - * - * @brief A class representing a PTR DNS resource record. - */ -OF_SUBCLASSING_RESTRICTED -@interface OFPTRDNSResourceRecord: OFDNSResourceRecord -{ - OFString *_domainName; -} - -/** - * @brief The domain name of the resource record. - */ -@property (readonly, nonatomic) OFString *domainName; - -- (instancetype)initWithName: (OFString *)name - DNSClass: (OFDNSClass)DNSClass - recordType: (OFDNSRecordType)recordType - TTL: (uint32_t)TTL OF_UNAVAILABLE; - -/** - * @brief Initializes an already allocated OFPTRDNSResourceRecord with the - * specified name, class, domain name and time to live. - * - * @param name The name for the resource record - * @param DNSClass The class code for the resource record - * @param domainName The domain name for the resource record - * @param TTL The time to live for the resource record - * @return An initialized OFPTRDNSResourceRecord - */ -- (instancetype)initWithName: (OFString *)name - DNSClass: (OFDNSClass)DNSClass - domainName: (OFString *)domainName - TTL: (uint32_t)TTL OF_DESIGNATED_INITIALIZER; -@end - -/** - * @class OFRPNSResourceRecord \ - * OFDNSResourceRecord.h ObjFW/OFDNSResourceRecord.h - * - * @brief A class representing an RP DNS resource record. - */ -OF_SUBCLASSING_RESTRICTED -@interface OFRPDNSResourceRecord: OFDNSResourceRecord -{ - OFString *_mailbox, *_TXTDomainName; -} - -/** - * @brief The mailbox of the responsible person of the resource record. - */ -@property (readonly, nonatomic) OFString *mailbox; - -/** - * @brief A domain name that contains a TXT resource record for the responsible - * person of the resource record. - */ -@property (readonly, nonatomic) OFString *TXTDomainName; - -- (instancetype)initWithName: (OFString *)name - DNSClass: (OFDNSClass)DNSClass - recordType: (OFDNSRecordType)recordType - TTL: (uint32_t)TTL OF_UNAVAILABLE; - -/** - * @brief Initializes an already allocated OFRPDNSResourceRecord with the - * specified name, class, alias and time to live. - * - * @param name The name for the resource record - * @param DNSClass The class code for the resource record - * @param mailbox The mailbox of the responsible person of the resource record - * @param TXTDomainName A domain name that contains a TXT resource record for - * the responsible person of the resource record - * @param TTL The time to live for the resource record - * @return An initialized OFRPDNSResourceRecord - */ -- (instancetype)initWithName: (OFString *)name - DNSClass: (OFDNSClass)DNSClass - mailbox: (OFString *)mailbox - TXTDomainName: (OFString *)TXTDomainName - TTL: (uint32_t)TTL OF_DESIGNATED_INITIALIZER; -@end - -/** - * @class OFSOADNSResourceRecord \ - * OFDNSResourceRecord.h ObjFW/OFDNSResourceRecord.h - * - * @brief A class representing an SOA DNS resource record. - */ -OF_SUBCLASSING_RESTRICTED -@interface OFSOADNSResourceRecord: OFDNSResourceRecord -{ - OFString *_primaryNameServer, *_responsiblePerson; - uint32_t _serialNumber, _refreshInterval, _retryInterval; - uint32_t _expirationInterval, _minTTL; -} - -/** - * @brief The the primary name server for the zone. - */ -@property (readonly, nonatomic) OFString *primaryNameServer; - -/** - * @brief The mailbox of the person responsible for the zone. - */ -@property (readonly, nonatomic) OFString *responsiblePerson; - -/** - * @brief The serial number of the original copy of the zone. - */ -@property (readonly, nonatomic) uint32_t serialNumber; - -/** - * @brief The refresh interval of the zone. - */ -@property (readonly, nonatomic) uint32_t refreshInterval; - -/** - * @brief The retry interval of the zone. - */ -@property (readonly, nonatomic) uint32_t retryInterval; - -/** - * @brief The expiration interval of the zone. - */ -@property (readonly, nonatomic) uint32_t expirationInterval; - -/** - * @brief The minimum TTL of the zone. - */ -@property (readonly, nonatomic) uint32_t minTTL; - -- (instancetype)initWithName: (OFString *)name - DNSClass: (OFDNSClass)DNSClass - recordType: (OFDNSRecordType)recordType - TTL: (uint32_t)TTL OF_UNAVAILABLE; - -/** - * @brief Initializes an already allocated OFSOADNSResourceRecord with the - * specified name, class, text data and time to live. - * - * @param name The name for the resource record - * @param DNSClass The class code for the resource record - * @param primaryNameServer The the primary name server for the zone - * @param responsiblePerson The mailbox of the person responsible for the zone - * @param serialNumber The serial number of the original copy of the zone - * @param refreshInterval The refresh interval of the zone - * @param retryInterval The retry interval of the zone - * @param expirationInterval The expiration interval of the zone - * @param minTTL The minimum TTL of the zone - * @param TTL The time to live for the resource record - * @return An initialized OFSOADNSResourceRecord - */ -- (instancetype)initWithName: (OFString *)name - DNSClass: (OFDNSClass)DNSClass - primaryNameServer: (OFString *)primaryNameServer - responsiblePerson: (OFString *)responsiblePerson - serialNumber: (uint32_t)serialNumber - refreshInterval: (uint32_t)refreshInterval - retryInterval: (uint32_t)retryInterval - expirationInterval: (uint32_t)expirationInterval - minTTL: (uint32_t)minTTL - TTL: (uint32_t)TTL OF_DESIGNATED_INITIALIZER; -@end - -/** - * @class OFSRVDNSResourceRecord \ - * OFDNSResourceRecord.h ObjFW/OFDNSResourceRecord.h - * - * @brief A class representing an SRV DNS resource record. - */ -OF_SUBCLASSING_RESTRICTED -@interface OFSRVDNSResourceRecord: OFDNSResourceRecord -{ - uint16_t _priority, _weight; - OFString *_target; - uint16_t _port; -} - -/** - * @brief The priority of the resource record. - */ -@property (readonly, nonatomic) uint16_t priority; - -/** - * @brief The weight of the resource record. - */ -@property (readonly, nonatomic) uint16_t weight; - -/** - * @brief The target of the resource record. - */ -@property (readonly, nonatomic) OFString *target; - -/** - * @brief The port on the target of the resource record. - */ -@property (readonly, nonatomic) uint16_t port; - -- (instancetype)initWithName: (OFString *)name - DNSClass: (OFDNSClass)DNSClass - recordType: (OFDNSRecordType)recordType - TTL: (uint32_t)TTL OF_UNAVAILABLE; - -/** - * @brief Initializes an already allocated OFSRVDNSResourceRecord with the - * specified name, class, preference, mail exchange and time to live. - * - * @param name The name for the resource record - * @param priority The priority for the resource record - * @param weight The weight for the resource record - * @param target The target for the resource record - * @param port The port on the target for the resource record - * @param TTL The time to live for the resource record - * @return An initialized OFSRVDNSResourceRecord - */ -- (instancetype)initWithName: (OFString *)name - priority: (uint16_t)priority - weight: (uint16_t)weight - target: (OFString *)target - port: (uint16_t)port - TTL: (uint32_t)TTL OF_DESIGNATED_INITIALIZER; -@end - -/** - * @class OFTXTDNSResourceRecord \ - * OFDNSResourceRecord.h ObjFW/OFDNSResourceRecord.h - * - * @brief A class representing a TXT DNS resource record. - */ -OF_SUBCLASSING_RESTRICTED -@interface OFTXTDNSResourceRecord: OFDNSResourceRecord -{ - OFArray OF_GENERIC(OFData *) *_textStrings; -} - -/** - * @brief The text of the resource record. - */ -@property (readonly, nonatomic) OFArray OF_GENERIC(OFData *) *textStrings; - -- (instancetype)initWithName: (OFString *)name - DNSClass: (OFDNSClass)DNSClass - recordType: (OFDNSRecordType)recordType - TTL: (uint32_t)TTL OF_UNAVAILABLE; - -/** - * @brief Initializes an already allocated OFTXTDNSResourceRecord with the - * specified name, class, text data and time to live. - * - * @param name The name for the resource record - * @param DNSClass The class code for the resource record - * @param textStrings An array of text strings for the resource record - * @param TTL The time to live for the resource record - * @return An initialized OFTXTDNSResourceRecord - */ -- (instancetype)initWithName: (OFString *)name - DNSClass: (OFDNSClass)DNSClass - textStrings: (OFArray OF_GENERIC(OFData *) *)textStrings - TTL: (uint32_t)TTL OF_DESIGNATED_INITIALIZER; -@end - #ifdef __cplusplus extern "C" { #endif /** * @brief Returns the name for the specified OFDNSClass. @@ -656,5 +158,19 @@ #ifdef __cplusplus } #endif OF_ASSUME_NONNULL_END + +#import "OFAAAADNSResourceRecord.h" +#import "OFADNSResourceRecord.h" +#import "OFCNAMEDNSResourceRecord.h" +#import "OFHINFODNSResourceRecord.h" +#import "OFLOCDNSResourceRecord.h" +#import "OFMXDNSResourceRecord.h" +#import "OFNSDNSResourceRecord.h" +#import "OFPTRDNSResourceRecord.h" +#import "OFRPDNSResourceRecord.h" +#import "OFSOADNSResourceRecord.h" +#import "OFSRVDNSResourceRecord.h" +#import "OFTXTDNSResourceRecord.h" +#import "OFURIDNSResourceRecord.h" Index: src/OFDNSResourceRecord.m ================================================================== --- src/OFDNSResourceRecord.m +++ src/OFDNSResourceRecord.m @@ -56,14 +56,18 @@ return @"TXT"; case OFDNSRecordTypeRP: return @"RP"; case OFDNSRecordTypeAAAA: return @"AAAA"; + case OFDNSRecordTypeLOC: + return @"LOC"; case OFDNSRecordTypeSRV: return @"SRV"; case OFDNSRecordTypeAll: return @"all"; + case OFDNSRecordTypeURI: + return @"URI"; default: return [OFString stringWithFormat: @"%u", recordType]; } } @@ -113,14 +117,18 @@ recordType = OFDNSRecordTypeTXT; else if ([string isEqual: @"RP"]) recordType = OFDNSRecordTypeRP; else if ([string isEqual: @"AAAA"]) recordType = OFDNSRecordTypeAAAA; + else if ([string isEqual: @"LOC"]) + recordType = OFDNSRecordTypeLOC; else if ([string isEqual: @"SRV"]) recordType = OFDNSRecordTypeSRV; else if ([string isEqual: @"ALL"]) recordType = OFDNSRecordTypeAll; + else if ([string isEqual: @"URI"]) + recordType = OFDNSRecordTypeURI; else { recordType = (OFDNSRecordType)[string unsignedLongLongValueWithBase: 0]; } @@ -175,1201 +183,6 @@ @"\tTTL = %" PRIu32 "\n" @">", self.className, _name, OFDNSClassName(_DNSClass), OFDNSRecordTypeName(_recordType), _TTL]; } -@end - -@implementation OFADNSResourceRecord -- (instancetype)initWithName: (OFString *)name - DNSClass: (OFDNSClass)DNSClass - recordType: (OFDNSRecordType)recordType - TTL: (uint32_t)TTL -{ - OF_INVALID_INIT_METHOD -} - -- (instancetype)initWithName: (OFString *)name - address: (const OFSocketAddress *)address - TTL: (uint32_t)TTL -{ - self = [super initWithName: name - DNSClass: OFDNSClassIN - recordType: OFDNSRecordTypeA - TTL: TTL]; - - _address = *address; - - return self; -} - -- (const OFSocketAddress *)address -{ - return &_address; -} - -- (bool)isEqual: (id)object -{ - OFADNSResourceRecord *record; - - if (object == self) - return true; - - if (![object isKindOfClass: [OFADNSResourceRecord class]]) - return false; - - record = object; - - if (record->_name != _name && ![record->_name isEqual: _name]) - return false; - - if (record->_DNSClass != _DNSClass) - return false; - - if (record->_recordType != _recordType) - return false; - - if (!OFSocketAddressEqual(&record->_address, &_address)) - return false; - - return true; -} - -- (unsigned long)hash -{ - unsigned long hash; - - OFHashInit(&hash); - - OFHashAddHash(&hash, _name.hash); - OFHashAddByte(&hash, _DNSClass >> 8); - OFHashAddByte(&hash, _DNSClass); - OFHashAddByte(&hash, _recordType >> 8); - OFHashAddByte(&hash, _recordType); - OFHashAddHash(&hash, OFSocketAddressHash(&_address)); - - OFHashFinalize(&hash); - - return hash; -} - -- (OFString *)description -{ - return [OFString stringWithFormat: - @"<%@:\n" - @"\tName = %@\n" - @"\tAddress = %@\n" - @"\tTTL = %" PRIu32 "\n" - @">", - self.className, _name, OFSocketAddressString(&_address), _TTL]; -} -@end - -@implementation OFAAAADNSResourceRecord -- (instancetype)initWithName: (OFString *)name - DNSClass: (OFDNSClass)DNSClass - recordType: (OFDNSRecordType)recordType - TTL: (uint32_t)TTL -{ - OF_INVALID_INIT_METHOD -} - -- (instancetype)initWithName: (OFString *)name - address: (const OFSocketAddress *)address - TTL: (uint32_t)TTL -{ - self = [super initWithName: name - DNSClass: OFDNSClassIN - recordType: OFDNSRecordTypeAAAA - TTL: TTL]; - - _address = *address; - - return self; -} - -- (const OFSocketAddress *)address -{ - return &_address; -} - -- (bool)isEqual: (id)object -{ - OFAAAADNSResourceRecord *record; - - if (object == self) - return true; - - if (![object isKindOfClass: [OFAAAADNSResourceRecord class]]) - return false; - - record = object; - - if (record->_name != _name && ![record->_name isEqual: _name]) - return false; - - if (record->_DNSClass != _DNSClass) - return false; - - if (record->_recordType != _recordType) - return false; - - if (!OFSocketAddressEqual(&record->_address, &_address)) - return false; - - return true; -} - -- (unsigned long)hash -{ - unsigned long hash; - - OFHashInit(&hash); - - OFHashAddHash(&hash, _name.hash); - OFHashAddByte(&hash, _DNSClass >> 8); - OFHashAddByte(&hash, _DNSClass); - OFHashAddByte(&hash, _recordType >> 8); - OFHashAddByte(&hash, _recordType); - OFHashAddHash(&hash, OFSocketAddressHash(&_address)); - - OFHashFinalize(&hash); - - return hash; -} - -- (OFString *)description -{ - return [OFString stringWithFormat: - @"<%@:\n" - @"\tName = %@\n" - @"\tAddress = %@\n" - @"\tTTL = %" PRIu32 "\n" - @">", - self.className, _name, OFSocketAddressString(&_address), _TTL]; -} -@end - -@implementation OFCNAMEDNSResourceRecord -@synthesize alias = _alias; - -- (instancetype)initWithName: (OFString *)name - DNSClass: (OFDNSClass)DNSClass - recordType: (OFDNSRecordType)recordType - TTL: (uint32_t)TTL -{ - OF_INVALID_INIT_METHOD -} - -- (instancetype)initWithName: (OFString *)name - DNSClass: (OFDNSClass)DNSClass - alias: (OFString *)alias - TTL: (uint32_t)TTL -{ - self = [super initWithName: name - DNSClass: DNSClass - recordType: OFDNSRecordTypeCNAME - TTL: TTL]; - - @try { - _alias = [alias copy]; - } @catch (id e) { - [self release]; - @throw e; - } - - return self; -} - -- (void)dealloc -{ - [_alias release]; - - [super dealloc]; -} - -- (bool)isEqual: (id)object -{ - OFCNAMEDNSResourceRecord *record; - - if (object == self) - return true; - - if (![object isKindOfClass: [OFCNAMEDNSResourceRecord class]]) - return false; - - record = object; - - if (record->_name != _name && ![record->_name isEqual: _name]) - return false; - - if (record->_DNSClass != _DNSClass) - return false; - - if (record->_recordType != _recordType) - return false; - - if (record->_alias != _alias && ![record->_alias isEqual: _alias]) - return false; - - return true; -} - -- (unsigned long)hash -{ - unsigned long hash; - - OFHashInit(&hash); - - OFHashAddHash(&hash, _name.hash); - OFHashAddByte(&hash, _DNSClass >> 8); - OFHashAddByte(&hash, _DNSClass); - OFHashAddByte(&hash, _recordType >> 8); - OFHashAddByte(&hash, _recordType); - OFHashAddHash(&hash, _alias.hash); - - OFHashFinalize(&hash); - - return hash; -} - -- (OFString *)description -{ - return [OFString stringWithFormat: - @"<%@:\n" - @"\tName = %@\n" - @"\tClass = %@\n" - @"\tAlias = %@\n" - @"\tTTL = %" PRIu32 "\n" - @">", - self.className, _name, OFDNSClassName(_DNSClass), _alias, _TTL]; -} -@end - -@implementation OFHINFODNSResourceRecord -@synthesize CPU = _CPU, OS = _OS; - -- (instancetype)initWithName: (OFString *)name - DNSClass: (OFDNSClass)DNSClass - recordType: (OFDNSRecordType)recordType - TTL: (uint32_t)TTL -{ - OF_INVALID_INIT_METHOD -} - -- (instancetype)initWithName: (OFString *)name - DNSClass: (OFDNSClass)DNSClass - CPU: (OFString *)CPU - OS: (OFString *)OS - TTL: (uint32_t)TTL -{ - self = [super initWithName: name - DNSClass: DNSClass - recordType: OFDNSRecordTypeHINFO - TTL: TTL]; - - @try { - _CPU = [CPU copy]; - _OS = [OS copy]; - } @catch (id e) { - [self release]; - @throw e; - } - - return self; -} - -- (void)dealloc -{ - [_CPU release]; - [_OS release]; - - [super dealloc]; -} - -- (bool)isEqual: (id)object -{ - OFHINFODNSResourceRecord *record; - - if (object == self) - return true; - - if (![object isKindOfClass: [OFHINFODNSResourceRecord class]]) - return false; - - record = object; - - if (record->_name != _name && ![record->_name isEqual: _name]) - return false; - - if (record->_DNSClass != _DNSClass) - return false; - - if (record->_recordType != _recordType) - return false; - - if (record->_CPU != _CPU && ![record->_CPU isEqual: _CPU]) - return false; - - if (record->_OS != _OS && ![record->_OS isEqual: _OS]) - return false; - - return true; -} - -- (unsigned long)hash -{ - unsigned long hash; - - OFHashInit(&hash); - - OFHashAddHash(&hash, _name.hash); - OFHashAddByte(&hash, _DNSClass >> 8); - OFHashAddByte(&hash, _DNSClass); - OFHashAddByte(&hash, _recordType >> 8); - OFHashAddByte(&hash, _recordType); - OFHashAddHash(&hash, _CPU.hash); - OFHashAddHash(&hash, _OS.hash); - - OFHashFinalize(&hash); - - return hash; -} - -- (OFString *)description -{ - return [OFString stringWithFormat: - @"<%@:\n" - @"\tName = %@\n" - @"\tClass = %@\n" - @"\tCPU = %@\n" - @"\tOS = %@\n" - @"\tTTL = %" PRIu32 "\n" - @">", - self.className, _name, OFDNSClassName(_DNSClass), _CPU, _OS, _TTL]; -} -@end - -@implementation OFMXDNSResourceRecord -@synthesize preference = _preference, mailExchange = _mailExchange; - -- (instancetype)initWithName: (OFString *)name - DNSClass: (OFDNSClass)DNSClass - recordType: (OFDNSRecordType)recordType - TTL: (uint32_t)TTL -{ - OF_INVALID_INIT_METHOD -} - -- (instancetype)initWithName: (OFString *)name - DNSClass: (OFDNSClass)DNSClass - preference: (uint16_t)preference - mailExchange: (OFString *)mailExchange - TTL: (uint32_t)TTL -{ - self = [super initWithName: name - DNSClass: DNSClass - recordType: OFDNSRecordTypeMX - TTL: TTL]; - - @try { - _preference = preference; - _mailExchange = [mailExchange copy]; - } @catch (id e) { - [self release]; - @throw e; - } - - return self; -} - -- (void)dealloc -{ - [_mailExchange release]; - - [super dealloc]; -} - -- (bool)isEqual: (id)object -{ - OFMXDNSResourceRecord *record; - - if (object == self) - return true; - - if (![object isKindOfClass: [OFMXDNSResourceRecord class]]) - return false; - - record = object; - - if (record->_name != _name && ![record->_name isEqual: _name]) - return false; - - if (record->_DNSClass != _DNSClass) - return false; - - if (record->_recordType != _recordType) - return false; - - if (record->_preference != _preference) - return false; - - if (record->_mailExchange != _mailExchange && - ![record->_mailExchange isEqual: _mailExchange]) - return false; - - return true; -} - -- (unsigned long)hash -{ - unsigned long hash; - - OFHashInit(&hash); - - OFHashAddHash(&hash, _name.hash); - OFHashAddByte(&hash, _DNSClass >> 8); - OFHashAddByte(&hash, _DNSClass); - OFHashAddByte(&hash, _recordType >> 8); - OFHashAddByte(&hash, _recordType); - OFHashAddByte(&hash, _preference >> 8); - OFHashAddByte(&hash, _preference); - OFHashAddHash(&hash, _mailExchange.hash); - - OFHashFinalize(&hash); - - return hash; -} - -- (OFString *)description -{ - return [OFString stringWithFormat: - @"<%@:\n" - @"\tName = %@\n" - @"\tClass = %@\n" - @"\tPreference = %" PRIu16 "\n" - @"\tMail Exchange = %@\n" - @"\tTTL = %" PRIu32 "\n" - @">", - self.className, _name, OFDNSClassName(_DNSClass), _preference, - _mailExchange, _TTL]; -} -@end - -@implementation OFNSDNSResourceRecord -@synthesize authoritativeHost = _authoritativeHost; - -- (instancetype)initWithName: (OFString *)name - DNSClass: (OFDNSClass)DNSClass - recordType: (OFDNSRecordType)recordType - TTL: (uint32_t)TTL -{ - OF_INVALID_INIT_METHOD -} - -- (instancetype)initWithName: (OFString *)name - DNSClass: (OFDNSClass)DNSClass - authoritativeHost: (OFString *)authoritativeHost - TTL: (uint32_t)TTL -{ - self = [super initWithName: name - DNSClass: DNSClass - recordType: OFDNSRecordTypeNS - TTL: TTL]; - - @try { - _authoritativeHost = [authoritativeHost copy]; - } @catch (id e) { - [self release]; - @throw e; - } - - return self; -} - -- (void)dealloc -{ - [_authoritativeHost release]; - - [super dealloc]; -} - -- (bool)isEqual: (id)object -{ - OFNSDNSResourceRecord *record; - - if (object == self) - return true; - - if (![object isKindOfClass: [OFNSDNSResourceRecord class]]) - return false; - - record = object; - - if (record->_name != _name && ![record->_name isEqual: _name]) - return false; - - if (record->_DNSClass != _DNSClass) - return false; - - if (record->_recordType != _recordType) - return false; - - if (record->_authoritativeHost != _authoritativeHost && - ![record->_authoritativeHost isEqual: _authoritativeHost]) - return false; - - return true; -} - -- (unsigned long)hash -{ - unsigned long hash; - - OFHashInit(&hash); - - OFHashAddHash(&hash, _name.hash); - OFHashAddByte(&hash, _DNSClass >> 8); - OFHashAddByte(&hash, _DNSClass); - OFHashAddByte(&hash, _recordType >> 8); - OFHashAddByte(&hash, _recordType); - OFHashAddHash(&hash, _authoritativeHost.hash); - - OFHashFinalize(&hash); - - return hash; -} - -- (OFString *)description -{ - return [OFString stringWithFormat: - @"<%@:\n" - @"\tName = %@\n" - @"\tClass = %@\n" - @"\tAuthoritative Host = %@\n" - @"\tTTL = %" PRIu32 "\n" - @">", - self.className, _name, OFDNSClassName(_DNSClass), - _authoritativeHost, _TTL]; -} -@end - -@implementation OFPTRDNSResourceRecord -@synthesize domainName = _domainName; - -- (instancetype)initWithName: (OFString *)name - DNSClass: (OFDNSClass)DNSClass - recordType: (OFDNSRecordType)recordType - TTL: (uint32_t)TTL -{ - OF_INVALID_INIT_METHOD -} - -- (instancetype)initWithName: (OFString *)name - DNSClass: (OFDNSClass)DNSClass - domainName: (OFString *)domainName - TTL: (uint32_t)TTL -{ - self = [super initWithName: name - DNSClass: DNSClass - recordType: OFDNSRecordTypePTR - TTL: TTL]; - - @try { - _domainName = [domainName copy]; - } @catch (id e) { - [self release]; - @throw e; - } - - return self; -} - -- (void)dealloc -{ - [_domainName release]; - - [super dealloc]; -} - -- (bool)isEqual: (id)object -{ - OFPTRDNSResourceRecord *record; - - if (object == self) - return true; - - if (![object isKindOfClass: [OFPTRDNSResourceRecord class]]) - return false; - - record = object; - - if (record->_name != _name && ![record->_name isEqual: _name]) - return false; - - if (record->_DNSClass != _DNSClass) - return false; - - if (record->_recordType != _recordType) - return false; - - if (record->_domainName != _domainName && - ![record->_domainName isEqual: _domainName]) - return false; - - return true; -} - -- (unsigned long)hash -{ - unsigned long hash; - - OFHashInit(&hash); - - OFHashAddHash(&hash, _name.hash); - OFHashAddByte(&hash, _DNSClass >> 8); - OFHashAddByte(&hash, _DNSClass); - OFHashAddByte(&hash, _recordType >> 8); - OFHashAddByte(&hash, _recordType); - OFHashAddHash(&hash, _domainName.hash); - - OFHashFinalize(&hash); - - return hash; -} - -- (OFString *)description -{ - return [OFString stringWithFormat: - @"<%@:\n" - @"\tName = %@\n" - @"\tClass = %@\n" - @"\tDomain Name = %@\n" - @"\tTTL = %" PRIu32 "\n" - @">", - self.className, _name, OFDNSClassName(_DNSClass), _domainName, - _TTL]; -} -@end - -@implementation OFRPDNSResourceRecord -@synthesize mailbox = _mailbox, TXTDomainName = _TXTDomainName; - -- (instancetype)initWithName: (OFString *)name - DNSClass: (OFDNSClass)DNSClass - recordType: (OFDNSRecordType)recordType - TTL: (uint32_t)TTL -{ - OF_INVALID_INIT_METHOD -} - -- (instancetype)initWithName: (OFString *)name - DNSClass: (OFDNSClass)DNSClass - mailbox: (OFString *)mailbox - TXTDomainName: (OFString *)TXTDomainName - TTL: (uint32_t)TTL -{ - self = [super initWithName: name - DNSClass: DNSClass - recordType: OFDNSRecordTypeRP - TTL: TTL]; - - @try { - _mailbox = [mailbox copy]; - _TXTDomainName = [TXTDomainName copy]; - } @catch (id e) { - [self release]; - @throw e; - } - - return self; -} - -- (void)dealloc -{ - [_mailbox release]; - [_TXTDomainName release]; - - [super dealloc]; -} - -- (bool)isEqual: (id)object -{ - OFRPDNSResourceRecord *record; - - if (object == self) - return true; - - if (![object isKindOfClass: [OFRPDNSResourceRecord class]]) - return false; - - record = object; - - if (record->_name != _name && ![record->_name isEqual: _name]) - return false; - - if (record->_DNSClass != _DNSClass) - return false; - - if (record->_recordType != _recordType) - return false; - - if (record->_mailbox != _mailbox && - ![record->_mailbox isEqual: _mailbox]) - return false; - - if (record->_TXTDomainName != _TXTDomainName && - ![record->_TXTDomainName isEqual: _TXTDomainName]) - return false; - - return true; -} - -- (unsigned long)hash -{ - unsigned long hash; - - OFHashInit(&hash); - - OFHashAddHash(&hash, _name.hash); - OFHashAddByte(&hash, _DNSClass >> 8); - OFHashAddByte(&hash, _DNSClass); - OFHashAddByte(&hash, _recordType >> 8); - OFHashAddByte(&hash, _recordType); - OFHashAddHash(&hash, _mailbox.hash); - OFHashAddHash(&hash, _TXTDomainName.hash); - - OFHashFinalize(&hash); - - return hash; -} - -- (OFString *)description -{ - return [OFString stringWithFormat: - @"<%@:\n" - @"\tName = %@\n" - @"\tClass = %@\n" - @"\tMailbox = %@\n" - @"\tTXT Domain Name = %@\n" - @"\tTTL = %" PRIu32 "\n" - @">", - self.className, _name, OFDNSClassName(_DNSClass), _mailbox, - _TXTDomainName, _TTL]; -} -@end - -@implementation OFSOADNSResourceRecord -@synthesize primaryNameServer = _primaryNameServer; -@synthesize responsiblePerson = _responsiblePerson; -@synthesize serialNumber = _serialNumber, refreshInterval = _refreshInterval; -@synthesize retryInterval = _retryInterval; -@synthesize expirationInterval = _expirationInterval, minTTL = _minTTL; - -- (instancetype)initWithName: (OFString *)name - DNSClass: (OFDNSClass)DNSClass - recordType: (OFDNSRecordType)recordType - TTL: (uint32_t)TTL -{ - OF_INVALID_INIT_METHOD -} - -- (instancetype)initWithName: (OFString *)name - DNSClass: (OFDNSClass)DNSClass - primaryNameServer: (OFString *)primaryNameServer - responsiblePerson: (OFString *)responsiblePerson - serialNumber: (uint32_t)serialNumber - refreshInterval: (uint32_t)refreshInterval - retryInterval: (uint32_t)retryInterval - expirationInterval: (uint32_t)expirationInterval - minTTL: (uint32_t)minTTL - TTL: (uint32_t)TTL -{ - self = [super initWithName: name - DNSClass: DNSClass - recordType: OFDNSRecordTypeSOA - TTL: TTL]; - - @try { - _primaryNameServer = [primaryNameServer copy]; - _responsiblePerson = [responsiblePerson copy]; - _serialNumber = serialNumber; - _refreshInterval = refreshInterval; - _retryInterval = retryInterval; - _expirationInterval = expirationInterval; - _minTTL = minTTL; - } @catch (id e) { - [self release]; - @throw e; - } - - return self; -} - -- (void)dealloc -{ - [_primaryNameServer release]; - [_responsiblePerson release]; - - [super dealloc]; -} - -- (bool)isEqual: (id)object -{ - OFSOADNSResourceRecord *record; - - if (object == self) - return true; - - if (![object isKindOfClass: [OFSOADNSResourceRecord class]]) - return false; - - record = object; - - if (record->_name != _name && ![record->_name isEqual: _name]) - return false; - - if (record->_DNSClass != _DNSClass) - return false; - - if (record->_recordType != _recordType) - return false; - - if (record->_primaryNameServer != _primaryNameServer && - ![record->_primaryNameServer isEqual: _primaryNameServer]) - return false; - - if (record->_responsiblePerson != _responsiblePerson && - ![record->_responsiblePerson isEqual: _responsiblePerson]) - return false; - - if (record->_serialNumber != _serialNumber) - return false; - - if (record->_refreshInterval != _refreshInterval) - return false; - - if (record->_retryInterval != _retryInterval) - return false; - - if (record->_expirationInterval != _expirationInterval) - return false; - - if (record->_minTTL != _minTTL) - return false; - - return true; -} - -- (unsigned long)hash -{ - unsigned long hash; - - OFHashInit(&hash); - - OFHashAddHash(&hash, _name.hash); - OFHashAddByte(&hash, _DNSClass >> 8); - OFHashAddByte(&hash, _DNSClass); - OFHashAddByte(&hash, _recordType >> 8); - OFHashAddByte(&hash, _recordType); - OFHashAddHash(&hash, _primaryNameServer.hash); - OFHashAddHash(&hash, _responsiblePerson.hash); - OFHashAddByte(&hash, _serialNumber >> 24); - OFHashAddByte(&hash, _serialNumber >> 16); - OFHashAddByte(&hash, _serialNumber >> 8); - OFHashAddByte(&hash, _serialNumber); - OFHashAddByte(&hash, _refreshInterval >> 24); - OFHashAddByte(&hash, _refreshInterval >> 16); - OFHashAddByte(&hash, _refreshInterval >> 8); - OFHashAddByte(&hash, _refreshInterval); - OFHashAddByte(&hash, _retryInterval >> 24); - OFHashAddByte(&hash, _retryInterval >> 16); - OFHashAddByte(&hash, _retryInterval >> 8); - OFHashAddByte(&hash, _retryInterval); - OFHashAddByte(&hash, _expirationInterval >> 24); - OFHashAddByte(&hash, _expirationInterval >> 16); - OFHashAddByte(&hash, _expirationInterval >> 8); - OFHashAddByte(&hash, _expirationInterval); - OFHashAddByte(&hash, _minTTL >> 24); - OFHashAddByte(&hash, _minTTL >> 16); - OFHashAddByte(&hash, _minTTL >> 8); - OFHashAddByte(&hash, _minTTL); - - OFHashFinalize(&hash); - - return hash; -} - -- (OFString *)description -{ - return [OFString stringWithFormat: - @"<%@:\n" - @"\tName = %@\n" - @"\tClass = %@\n" - @"\tPrimary Name Server = %@\n" - @"\tResponsible Person = %@\n" - @"\tSerial Number = %" PRIu32 "\n" - @"\tRefresh Interval = %" PRIu32 "\n" - @"\tRetry Interval = %" PRIu32 "\n" - @"\tExpiration Interval = %" PRIu32 "\n" - @"\tMinimum TTL = %" PRIu32 "\n" - @"\tTTL = %" PRIu32 "\n" - @">", - self.className, _name, OFDNSClassName(_DNSClass), - _primaryNameServer, _responsiblePerson, _serialNumber, - _refreshInterval, _retryInterval, _expirationInterval, _minTTL, - _TTL]; -} -@end - -@implementation OFSRVDNSResourceRecord -@synthesize priority = _priority, weight = _weight, target = _target; -@synthesize port = _port; - -- (instancetype)initWithName: (OFString *)name - DNSClass: (OFDNSClass)DNSClass - recordType: (OFDNSRecordType)recordType - TTL: (uint32_t)TTL -{ - OF_INVALID_INIT_METHOD -} - -- (instancetype)initWithName: (OFString *)name - priority: (uint16_t)priority - weight: (uint16_t)weight - target: (OFString *)target - port: (uint16_t)port - TTL: (uint32_t)TTL -{ - self = [super initWithName: name - DNSClass: OFDNSClassIN - recordType: OFDNSRecordTypeSRV - TTL: TTL]; - - @try { - _priority = priority; - _weight = weight; - _target = [target copy]; - _port = port; - } @catch (id e) { - [self release]; - @throw e; - } - - return self; -} - -- (void)dealloc -{ - [_target release]; - - [super dealloc]; -} - -- (bool)isEqual: (id)object -{ - OFSRVDNSResourceRecord *record; - - if (object == self) - return true; - - if (![object isKindOfClass: [OFSRVDNSResourceRecord class]]) - return false; - - record = object; - - if (record->_name != _name && ![record->_name isEqual: _name]) - return false; - - if (record->_DNSClass != _DNSClass) - return false; - - if (record->_recordType != _recordType) - return false; - - if (record->_priority != _priority) - return false; - - if (record->_weight != _weight) - return false; - - if (record->_target != _target && ![record->_target isEqual: _target]) - return false; - - if (record->_port != _port) - return false; - - return true; -} - -- (unsigned long)hash -{ - unsigned long hash; - - OFHashInit(&hash); - - OFHashAddHash(&hash, _name.hash); - OFHashAddByte(&hash, _DNSClass >> 8); - OFHashAddByte(&hash, _DNSClass); - OFHashAddByte(&hash, _recordType >> 8); - OFHashAddByte(&hash, _recordType); - OFHashAddByte(&hash, _priority >> 8); - OFHashAddByte(&hash, _priority); - OFHashAddByte(&hash, _weight >> 8); - OFHashAddByte(&hash, _weight); - OFHashAddHash(&hash, _target.hash); - OFHashAddByte(&hash, _port >> 8); - OFHashAddByte(&hash, _port); - - OFHashFinalize(&hash); - - return hash; -} - -- (OFString *)description -{ - return [OFString stringWithFormat: - @"<%@:\n" - @"\tName = %@\n" - @"\tPriority = %" PRIu16 "\n" - @"\tWeight = %" PRIu16 "\n" - @"\tTarget = %@\n" - @"\tPort = %" PRIu16 "\n" - @"\tTTL = %" PRIu32 "\n" - @">", - self.className, _name, _priority, _weight, _target, _port, _TTL]; -} -@end - -@implementation OFTXTDNSResourceRecord -@synthesize textStrings = _textStrings; - -- (instancetype)initWithName: (OFString *)name - DNSClass: (OFDNSClass)DNSClass - recordType: (OFDNSRecordType)recordType - TTL: (uint32_t)TTL -{ - OF_INVALID_INIT_METHOD -} - -- (instancetype)initWithName: (OFString *)name - DNSClass: (OFDNSClass)DNSClass - textStrings: (OFArray OF_GENERIC(OFData *) *)textStrings - TTL: (uint32_t)TTL -{ - self = [super initWithName: name - DNSClass: DNSClass - recordType: OFDNSRecordTypeTXT - TTL: TTL]; - - @try { - _textStrings = [textStrings copy]; - } @catch (id e) { - [self release]; - @throw e; - } - - return self; -} - -- (void)dealloc -{ - [_textStrings release]; - - [super dealloc]; -} - -- (bool)isEqual: (id)object -{ - OFTXTDNSResourceRecord *record; - - if (object == self) - return true; - - if (![object isKindOfClass: [OFTXTDNSResourceRecord class]]) - return false; - - record = object; - - if (record->_name != _name && ![record->_name isEqual: _name]) - return false; - - if (record->_DNSClass != _DNSClass) - return false; - - if (record->_recordType != _recordType) - return false; - - if (record->_textStrings != _textStrings && - ![record->_textStrings isEqual: _textStrings]) - return false; - - return true; -} - -- (unsigned long)hash -{ - unsigned long hash; - - OFHashInit(&hash); - - OFHashAddHash(&hash, _name.hash); - OFHashAddByte(&hash, _DNSClass >> 8); - OFHashAddByte(&hash, _DNSClass); - OFHashAddByte(&hash, _recordType >> 8); - OFHashAddByte(&hash, _recordType); - OFHashAddHash(&hash, _textStrings.hash); - - OFHashFinalize(&hash); - - return hash; -} - -- (OFString *)description -{ - void *pool = objc_autoreleasePoolPush(); - OFMutableString *text = [OFMutableString string]; - bool first = true; - OFString *ret; - - for (OFData *string in _textStrings) { - const unsigned char *stringItems = string.items; - size_t stringCount = string.count; - - if (first) { - first = false; - [text appendString: @"\""]; - } else - [text appendString: @" \""]; - - for (size_t i = 0; i < stringCount; i++) { - if (stringItems[i] == '\\') - [text appendString: @"\\\\"]; - else if (stringItems[i] == '"') - [text appendString: @"\\\""]; - else if (stringItems[i] < 0x20) - [text appendFormat: @"\\x%02X", stringItems[i]]; - else if (stringItems[i] < 0x7F) - [text appendFormat: @"%c", stringItems[i]]; - else - [text appendFormat: @"\\x%02X", stringItems[i]]; - } - - [text appendString: @"\""]; - } - - ret = [OFString stringWithFormat: - @"<%@:\n" - @"\tName = %@\n" - @"\tClass = %@\n" - @"\tText strings = %@\n" - @"\tTTL = %" PRIu32 "\n" - @">", - self.className, _name, OFDNSClassName(_DNSClass), text, _TTL]; - - [ret retain]; - - objc_autoreleasePoolPop(pool); - - return [ret autorelease]; -} @end Index: src/OFData.h ================================================================== --- src/OFData.h +++ src/OFData.h @@ -123,11 +123,11 @@ /** * @brief Creates a new OFData with the specified `count` items of size 1 by * taking over ownership of the specified items pointer. * * If initialization fails for whatever reason, the passed memory is *not* - * free'd if `freeWhenDone` is true. + * freed if `freeWhenDone` is true. * * @param items The items to store in the OFData * @param count The number of items * @param freeWhenDone Whether to free the pointer when it is no longer needed * by the OFData @@ -140,11 +140,11 @@ /** * @brief Creates a new OFData with the specified `count` items of the * specified size by taking ownership of the specified items pointer. * * If initialization fails for whatever reason, the passed memory is *not* - * free'd if `freeWhenDone` is true. + * freed if `freeWhenDone` is true. * * @param items The items to store in the OFData * @param count The number of items * @param itemSize The item size of a single item in bytes * @param freeWhenDone Whether to free the pointer when it is no longer needed @@ -242,11 +242,11 @@ * @brief Initializes an already allocated OFData with the specified `count` * items of size 1 by taking over ownership of the specified items * pointer. * * If initialization fails for whatever reason, the passed memory is *not* - * free'd if `freeWhenDone` is true. + * freed if `freeWhenDone` is true. * * @param items The items to store in the OFData * @param count The number of items * @param freeWhenDone Whether to free the pointer when it is no longer needed * by the OFData @@ -260,11 +260,11 @@ * @brief Initializes an already allocated OFData with the specified `count` * items of the specified size by taking ownership of the specified * items pointer. * * If initialization fails for whatever reason, the passed memory is *not* - * free'd if `freeWhenDone` is true. + * freed if `freeWhenDone` is true. * * @param items The items to store in the OFData * @param count The number of items * @param itemSize The item size of a single item in bytes * @param freeWhenDone Whether to free the pointer when it is no longer needed Index: src/OFDatagramSocket.h ================================================================== --- src/OFDatagramSocket.h +++ src/OFDatagramSocket.h @@ -185,11 +185,12 @@ * * If the buffer is too small, the datagram is truncated. * * @param buffer The buffer to write the datagram to * @param length The length of the buffer - * @param runLoopMode The run loop mode in which to perform the async receive + * @param runLoopMode The run loop mode in which to perform the asynchronous + * receive */ - (void)asyncReceiveIntoBuffer: (void *)buffer length: (size_t)length runLoopMode: (OFRunLoopMode)runLoopMode; @@ -219,11 +220,12 @@ * * If the buffer is too small, the datagram is truncated. * * @param buffer The buffer to write the datagram to * @param length The length of the buffer - * @param runLoopMode The run loop mode in which to perform the async receive + * @param runLoopMode The run loop mode in which to perform the asynchronous + * receive * @param block The block to call when the datagram has been received. If the * block returns true, it will be called again with the same * buffer and maximum length when more datagrams have been * received. If you want the next method in the queue to handle * the datagram received next, you need to return false from the @@ -261,13 +263,14 @@ /** * @brief Asynchronously sends the specified datagram to the specified address. * * @param data The data to send as a datagram - * @param receiver A pointer to an @ref OFSocketAddress to which the datgram + * @param receiver A pointer to an @ref OFSocketAddress to which the datagram * should be sent. The receiver is copied. - * @param runLoopMode The run loop mode in which to perform the async send + * @param runLoopMode The run loop mode in which to perform the asynchronous + * send */ - (void)asyncSendData: (OFData *)data receiver: (const OFSocketAddress *)receiver runLoopMode: (OFRunLoopMode)runLoopMode; @@ -290,11 +293,12 @@ * @brief Asynchronously sends the specified datagram to the specified address. * * @param data The data to send as a datagram * @param receiver A pointer to an @ref OFSocketAddress to which the datagram * should be sent. The receiver is copied. - * @param runLoopMode The run loop mode in which to perform the async send + * @param runLoopMode The run loop mode in which to perform the asynchronous + * send * @param block The block to call when the packet has been sent. It should * return the data for the next send with the same callback or nil * if it should not repeat. */ - (void)asyncSendData: (OFData *)data Index: src/OFDate.h ================================================================== --- src/OFDate.h +++ src/OFDate.h @@ -187,20 +187,20 @@ format: (OFString *)format; /** * @brief Returns a date in the distant future. * - * The date is system-dependant. + * The date is system-dependent. * * @return A date in the distant future */ + (instancetype)distantFuture; /** * @brief Returns a date in the distant past. * - * The date is system-dependant. + * The date is system-dependent. * * @return A date in the distant past */ + (instancetype)distantPast; Index: src/OFFileManager.h ================================================================== --- src/OFFileManager.h +++ src/OFFileManager.h @@ -762,11 +762,11 @@ forName: (OFString *)name ofItemAtIRI: (OFIRI *)IRI; #ifdef OF_FILE_MANAGER_SUPPORTS_EXTENDED_ATTRIBUTES /** - * @brief Removes the extended attribute for the specified name wof the item at + * @brief Removes the extended attribute for the specified name of the item at * the specified path. * * This method is not available on some systems. * * @param name The name of the extended attribute to remove @@ -779,11 +779,11 @@ - (void)removeExtendedAttributeForName: (OFString *)name ofItemAtPath: (OFString *)path; #endif /** - * @brief Removes the extended attribute for the specified name wof the item at + * @brief Removes the extended attribute for the specified name of the item at * the specified IRI. * * This method is not available for all IRIs. * * @param name The name of the extended attribute to remove Index: src/OFGZIPStream.m ================================================================== --- src/OFGZIPStream.m +++ src/OFGZIPStream.m @@ -248,12 +248,13 @@ _inflateStream = nil; _state++; break; case OFGZIPStreamStateCRC32: - _bytesRead += [_stream readIntoBuffer: _buffer - length: 4 - _bytesRead]; + _bytesRead += [_stream + readIntoBuffer: _buffer + _bytesRead + length: 4 - _bytesRead]; if (_bytesRead < 4) return 0; CRC32 = ((uint32_t)_buffer[3] << 24) | @@ -272,14 +273,18 @@ _bytesRead = 0; _CRC32 = ~0; _state++; break; case OFGZIPStreamStateUncompressedSize: - _bytesRead += [_stream readIntoBuffer: _buffer - length: 4 - _bytesRead]; + _bytesRead += [_stream + readIntoBuffer: _buffer + _bytesRead + length: 4 - _bytesRead]; + + if (_bytesRead < 4) + return 0; - uncompressedSize = ((uint32_t)_buffer[3] << 24) | + uncompressedSize = (_buffer[3] << 24) | (_buffer[2] << 16) | (_buffer[1] << 8) | _buffer[0]; if (_uncompressedSize != uncompressedSize) { OFString *actual = [OFString stringWithFormat: @"%" PRIu32, _uncompressedSize]; OFString *expected = [OFString stringWithFormat: ADDED src/OFHINFODNSResourceRecord.h Index: src/OFHINFODNSResourceRecord.h ================================================================== --- src/OFHINFODNSResourceRecord.h +++ src/OFHINFODNSResourceRecord.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2008-2024 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#import "OFDNSResourceRecord.h" + +OF_ASSUME_NONNULL_BEGIN + +/** + * @class OFHINFODNSResourceRecord \ + * OFDNSResourceRecord.h ObjFW/OFDNSResourceRecord.h + * + * @brief A class representing an HINFO DNS resource record. + */ +OF_SUBCLASSING_RESTRICTED +@interface OFHINFODNSResourceRecord: OFDNSResourceRecord +{ + OFString *_CPU, *_OS; +} + +/** + * @brief The CPU of the host info of the resource record. + */ +@property (readonly, nonatomic) OFString *CPU; + +/** + * @brief The OS of the host info of the resource record. + */ +@property (readonly, nonatomic) OFString *OS; + +- (instancetype)initWithName: (OFString *)name + DNSClass: (OFDNSClass)DNSClass + recordType: (OFDNSRecordType)recordType + TTL: (uint32_t)TTL OF_UNAVAILABLE; + +/** + * @brief Initializes an already allocated OFHINFODNSResourceRecord with the + * specified name, class, domain name and time to live. + * + * @param name The name for the resource record + * @param DNSClass The class code for the resource record + * @param CPU The CPU of the host info for the resource record + * @param OS The OS of the host info for the resource record + * @param TTL The time to live for the resource record + * @return An initialized OFHINFODNSResourceRecord + */ +- (instancetype)initWithName: (OFString *)name + DNSClass: (OFDNSClass)DNSClass + CPU: (OFString *)CPU + OS: (OFString *)OS + TTL: (uint32_t)TTL OF_DESIGNATED_INITIALIZER; +@end + +OF_ASSUME_NONNULL_END ADDED src/OFHINFODNSResourceRecord.m Index: src/OFHINFODNSResourceRecord.m ================================================================== --- src/OFHINFODNSResourceRecord.m +++ src/OFHINFODNSResourceRecord.m @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2008-2024 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#include "config.h" + +#import "OFHINFODNSResourceRecord.h" + +@implementation OFHINFODNSResourceRecord +@synthesize CPU = _CPU, OS = _OS; + +- (instancetype)initWithName: (OFString *)name + DNSClass: (OFDNSClass)DNSClass + recordType: (OFDNSRecordType)recordType + TTL: (uint32_t)TTL +{ + OF_INVALID_INIT_METHOD +} + +- (instancetype)initWithName: (OFString *)name + DNSClass: (OFDNSClass)DNSClass + CPU: (OFString *)CPU + OS: (OFString *)OS + TTL: (uint32_t)TTL +{ + self = [super initWithName: name + DNSClass: DNSClass + recordType: OFDNSRecordTypeHINFO + TTL: TTL]; + + @try { + _CPU = [CPU copy]; + _OS = [OS copy]; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (void)dealloc +{ + [_CPU release]; + [_OS release]; + + [super dealloc]; +} + +- (bool)isEqual: (id)object +{ + OFHINFODNSResourceRecord *record; + + if (object == self) + return true; + + if (![object isKindOfClass: [OFHINFODNSResourceRecord class]]) + return false; + + record = object; + + if (record->_name != _name && ![record->_name isEqual: _name]) + return false; + + if (record->_DNSClass != _DNSClass) + return false; + + if (record->_recordType != _recordType) + return false; + + if (record->_CPU != _CPU && ![record->_CPU isEqual: _CPU]) + return false; + + if (record->_OS != _OS && ![record->_OS isEqual: _OS]) + return false; + + return true; +} + +- (unsigned long)hash +{ + unsigned long hash; + + OFHashInit(&hash); + + OFHashAddHash(&hash, _name.hash); + OFHashAddByte(&hash, _DNSClass >> 8); + OFHashAddByte(&hash, _DNSClass); + OFHashAddByte(&hash, _recordType >> 8); + OFHashAddByte(&hash, _recordType); + OFHashAddHash(&hash, _CPU.hash); + OFHashAddHash(&hash, _OS.hash); + + OFHashFinalize(&hash); + + return hash; +} + +- (OFString *)description +{ + return [OFString stringWithFormat: + @"<%@:\n" + @"\tName = %@\n" + @"\tClass = %@\n" + @"\tCPU = %@\n" + @"\tOS = %@\n" + @"\tTTL = %" PRIu32 "\n" + @">", + self.className, _name, OFDNSClassName(_DNSClass), _CPU, _OS, _TTL]; +} +@end Index: src/OFHTTPResponse.h ================================================================== --- src/OFHTTPResponse.h +++ src/OFHTTPResponse.h @@ -72,11 +72,11 @@ * @return The response as a string */ - (OFString *)readString; /** - * @brief Rread the response as a string, trying to detect the encoding and + * @brief Read the response as a string, trying to detect the encoding and * falling back to the specified encoding if not detectable. * * @return The response as a string */ - (OFString *)readStringWithEncoding: (OFStringEncoding)encoding; Index: src/OFHTTPServer.h ================================================================== --- src/OFHTTPServer.h +++ src/OFHTTPServer.h @@ -56,11 +56,11 @@ * @param server The HTTP server which encountered an exception * @param exception The exception which occurred on the HTTP server's listening * socket * @return Whether to continue listening. If you return false, existing * connections will still be handled and you can start accepting new - * connections again by calling @ref OFHTTPServer::start again. + * connections again by calling @ref OFHTTPServer#start again. */ - (bool)server: (OFHTTPServer *)server didReceiveExceptionOnListeningSocket: (id)exception; /** Index: src/OFIRI.h ================================================================== --- src/OFIRI.h +++ src/OFIRI.h @@ -216,11 +216,11 @@ /** * @brief Creates a new IRI with the specified local file path. * * @param path The local file path * @param isDirectory Whether the path is a directory, in which case a slash is - * appened if there is no slash yet + * appended if there is no slash yet * @return An initialized OFIRI */ + (instancetype)fileIRIWithPath: (OFString *)path isDirectory: (bool)isDirectory; #endif @@ -265,11 +265,11 @@ * @brief Initializes an already allocated OFIRI with the specified local file * path. * * @param path The local file path * @param isDirectory Whether the path is a directory, in which case a slash is - * appened if there is no slash yet + * appended if there is no slash yet * @return An initialized OFIRI */ - (instancetype)initFileIRIWithPath: (OFString *)path isDirectory: (bool)isDirectory; #endif Index: src/OFIRIHandler.h ================================================================== --- src/OFIRIHandler.h +++ src/OFIRIHandler.h @@ -330,11 +330,11 @@ - (void)setExtendedAttributeData: (OFData *)data forName: (OFString *)name ofItemAtIRI: (OFIRI *)IRI; /** - * @brief Removes the extended attribute for the specified name wof the item at + * @brief Removes the extended attribute for the specified name of the item at * the specified IRI. * * This method is not available for all IRIs. * * @param name The name of the extended attribute to remove Index: src/OFKernelEventObserver.h ================================================================== --- src/OFKernelEventObserver.h +++ src/OFKernelEventObserver.h @@ -43,11 +43,11 @@ @optional /** * @brief This callback is called when an object did get ready for reading. * * @note If the object is a subclass of @ref OFStream and - * @ref OFStream::tryReadLine or @ref OFStream::tryReadUntilDelimiter: + * @ref OFStream#tryReadLine or @ref OFStream#tryReadUntilDelimiter: * has been called on the stream, this callback will not be called again * until new data has been received, even though there is still data in * the cache. The reason for this is to prevent spinning in a loop when * there is an incomplete string in the cache. Once the string has been * completed, the callback will be called again as long there is data in ADDED src/OFLOCDNSResourceRecord.h Index: src/OFLOCDNSResourceRecord.h ================================================================== --- src/OFLOCDNSResourceRecord.h +++ src/OFLOCDNSResourceRecord.h @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2008-2024 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#import "OFDNSResourceRecord.h" + +OF_ASSUME_NONNULL_BEGIN + +/** + * @class OFLOCDNSResourceRecord \ + * OFDNSResourceRecord.h ObjFW/OFDNSResourceRecord.h + * + * @brief A class representing an LOC DNS resource record. + */ +OF_SUBCLASSING_RESTRICTED +@interface OFLOCDNSResourceRecord: OFDNSResourceRecord +{ + uint8_t _size, _horizontalPrecision, _verticalPrecision; + uint32_t _latitude, _longitude, _altitude; +} + +/** + * @brief The diameter in centimeters of a sphere enclosing the position, + * encoded as per RFC 1876. + */ +@property (readonly, nonatomic) uint8_t size; + +/** + * @brief The horizontal precision in centimeters, encoded as per RFC 1876. + */ +@property (readonly, nonatomic) uint8_t horizontalPrecision; + +/** + * @brief The vertical precision in centimeters, encoded as per RFC 1876. + */ +@property (readonly, nonatomic) uint8_t verticalPrecision; + +/** + * @brief The latitude in thousands of a second of an arc. + */ +@property (readonly, nonatomic) uint32_t latitude; + +/** + * @brief The longitude in thousands of a second of an arc. + */ +@property (readonly, nonatomic) uint32_t longitude; + +/** + * @brief The altitude in centimeters from a base of 100000 meters below the + * GPS reference. + */ +@property (readonly, nonatomic) uint32_t altitude; + +- (instancetype)initWithName: (OFString *)name + DNSClass: (OFDNSClass)DNSClass + recordType: (OFDNSRecordType)recordType + TTL: (uint32_t)TTL OF_UNAVAILABLE; + +/** + * @brief Initializes an already allocated OFLOCDNSResourceRecord with the + * specified name, class, domain name and time to live. + * + * @param name The name for the resource record + * @param DNSClass The class code for the resource record + * @param size The diameter in centimeters of a sphere enclosing the position, + * encoded as per RFC 1876 + * @param horizontalPrecision The horizontal precision in centimeters, encoded + * as per RFC 1876 + * @param verticalPrecision The vertical precision in centimeters, encoded as + * per RFC 1876 + * @param latitude The latitude in thousands of a second of an arc + * @param longitude The longitude in thousands of a second of an arc + * @param altitude The altitude in centimeters from a base of 100000 meters + * below the GPS reference + * @param TTL The time to live for the resource record + * @return An initialized OFLOCDNSResourceRecord + */ +- (instancetype)initWithName: (OFString *)name + DNSClass: (OFDNSClass)DNSClass + size: (uint8_t)size + horizontalPrecision: (uint8_t)horizontalPrecision + verticalPrecision: (uint8_t)verticalPrecision + latitude: (uint32_t)latitude + longitude: (uint32_t)longitude + altitude: (uint32_t)altitude + TTL: (uint32_t)TTL OF_DESIGNATED_INITIALIZER; +@end + +OF_ASSUME_NONNULL_END ADDED src/OFLOCDNSResourceRecord.m Index: src/OFLOCDNSResourceRecord.m ================================================================== --- src/OFLOCDNSResourceRecord.m +++ src/OFLOCDNSResourceRecord.m @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2008-2024 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#include "config.h" + +#import "OFLOCDNSResourceRecord.h" + +@implementation OFLOCDNSResourceRecord +@synthesize size = _size, horizontalPrecision = _horizontalPrecision; +@synthesize verticalPrecision = _verticalPrecision, latitude = _latitude; +@synthesize longitude = _longitude, altitude = _altitude; + +- (instancetype)initWithName: (OFString *)name + DNSClass: (OFDNSClass)DNSClass + recordType: (OFDNSRecordType)recordType + TTL: (uint32_t)TTL +{ + OF_INVALID_INIT_METHOD +} + +- (instancetype)initWithName: (OFString *)name + DNSClass: (OFDNSClass)DNSClass + size: (uint8_t)size + horizontalPrecision: (uint8_t)horizontalPrecision + verticalPrecision: (uint8_t)verticalPrecision + latitude: (uint32_t)latitude + longitude: (uint32_t)longitude + altitude: (uint32_t)altitude + TTL: (uint32_t)TTL +{ + self = [super initWithName: name + DNSClass: DNSClass + recordType: OFDNSRecordTypeLOC + TTL: TTL]; + + @try { + _size = size; + _horizontalPrecision = horizontalPrecision; + _verticalPrecision = verticalPrecision; + _latitude = latitude; + _longitude = longitude; + _altitude = altitude; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (bool)isEqual: (id)object +{ + OFLOCDNSResourceRecord *record; + + if (object == self) + return true; + + if (![object isKindOfClass: [OFLOCDNSResourceRecord class]]) + return false; + + record = object; + + if (record->_name != _name && ![record->_name isEqual: _name]) + return false; + + if (record->_DNSClass != _DNSClass) + return false; + + if (record->_recordType != _recordType) + return false; + + if (record->_size != _size) + return false; + + if (record->_horizontalPrecision != _horizontalPrecision) + return false; + + if (record->_verticalPrecision != _verticalPrecision) + return false; + + if (record->_latitude != _latitude) + return false; + + if (record->_longitude != _longitude) + return false; + + if (record->_altitude != _altitude) + return false; + + return true; +} + +- (unsigned long)hash +{ + unsigned long hash; + + OFHashInit(&hash); + + OFHashAddHash(&hash, _name.hash); + OFHashAddByte(&hash, _DNSClass >> 8); + OFHashAddByte(&hash, _DNSClass); + OFHashAddByte(&hash, _recordType >> 8); + OFHashAddByte(&hash, _recordType); + OFHashAddByte(&hash, _size); + OFHashAddByte(&hash, _horizontalPrecision); + OFHashAddByte(&hash, _verticalPrecision); + OFHashAddByte(&hash, _latitude >> 24); + OFHashAddByte(&hash, _latitude >> 16); + OFHashAddByte(&hash, _latitude >> 8); + OFHashAddByte(&hash, _latitude); + OFHashAddByte(&hash, _longitude >> 24); + OFHashAddByte(&hash, _longitude >> 16); + OFHashAddByte(&hash, _longitude >> 8); + OFHashAddByte(&hash, _longitude); + OFHashAddByte(&hash, _altitude >> 24); + OFHashAddByte(&hash, _altitude >> 16); + OFHashAddByte(&hash, _altitude >> 8); + OFHashAddByte(&hash, _altitude); + + OFHashFinalize(&hash); + + return hash; +} + +- (OFString *)description +{ + return [OFString stringWithFormat: + @"<%@:\n" + @"\tName = %@\n" + @"\tClass = %@\n" + @"\tSize = %ue%u\n" + @"\tHorizontal precision = %ue%u\n" + @"\tVertical precision = %ue%u\n" + @"\tLatitude = %f\n" + @"\tLongitude = %f\n" + @"\tAltitude = %f\n" + @"\tTTL = %" PRIu32 "\n" + @">", + self.className, _name, OFDNSClassName(_DNSClass), + _size >> 4, _size & 0xF, + _horizontalPrecision >> 4, _horizontalPrecision & 0xF, + _verticalPrecision >> 4, _verticalPrecision & 0xF, + ((double)_latitude - 2147483648) / 3600000, + ((double)_longitude - 2147483648) / 3600000, + ((double)_altitude - 10000000) / 100, _TTL]; +} +@end Index: src/OFList.h ================================================================== --- src/OFList.h +++ src/OFList.h @@ -20,12 +20,12 @@ OF_ASSUME_NONNULL_BEGIN /** @file */ /* - * Make clang's -Wdocumentation shut about about using @struct on someting it - * thinks is not a struct. Doxygen requires it this way. + * Make clang's -Wdocumentation shut up about about using @struct on something + * it thinks is not a struct. Doxygen requires it this way. */ #ifdef __clang__ # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wdocumentation" #endif ADDED src/OFMXDNSResourceRecord.h Index: src/OFMXDNSResourceRecord.h ================================================================== --- src/OFMXDNSResourceRecord.h +++ src/OFMXDNSResourceRecord.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2008-2024 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#import "OFDNSResourceRecord.h" + +OF_ASSUME_NONNULL_BEGIN + +/** + * @class OFMXDNSResourceRecord \ + * OFDNSResourceRecord.h ObjFW/OFDNSResourceRecord.h + * + * @brief A class representing an MX DNS resource record. + */ +OF_SUBCLASSING_RESTRICTED +@interface OFMXDNSResourceRecord: OFDNSResourceRecord +{ + uint16_t _preference; + OFString *_mailExchange; +} + +/** + * @brief The preference of the resource record. + */ +@property (readonly, nonatomic) uint16_t preference; + +/** + * @brief The mail exchange of the resource record. + */ +@property (readonly, nonatomic) OFString *mailExchange; + +- (instancetype)initWithName: (OFString *)name + DNSClass: (OFDNSClass)DNSClass + recordType: (OFDNSRecordType)recordType + TTL: (uint32_t)TTL OF_UNAVAILABLE; + +/** + * @brief Initializes an already allocated OFMXDNSResourceRecord with the + * specified name, class, preference, mail exchange and time to live. + * + * @param name The name for the resource record + * @param DNSClass The class code for the resource record + * @param preference The preference for the resource record + * @param mailExchange The mail exchange for the resource record + * @param TTL The time to live for the resource record + * @return An initialized OFMXDNSResourceRecord + */ +- (instancetype)initWithName: (OFString *)name + DNSClass: (OFDNSClass)DNSClass + preference: (uint16_t)preference + mailExchange: (OFString *)mailExchange + TTL: (uint32_t)TTL OF_DESIGNATED_INITIALIZER; +@end + +OF_ASSUME_NONNULL_END ADDED src/OFMXDNSResourceRecord.m Index: src/OFMXDNSResourceRecord.m ================================================================== --- src/OFMXDNSResourceRecord.m +++ src/OFMXDNSResourceRecord.m @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2008-2024 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#include "config.h" + +#import "OFMXDNSResourceRecord.h" + +@implementation OFMXDNSResourceRecord +@synthesize preference = _preference, mailExchange = _mailExchange; + +- (instancetype)initWithName: (OFString *)name + DNSClass: (OFDNSClass)DNSClass + recordType: (OFDNSRecordType)recordType + TTL: (uint32_t)TTL +{ + OF_INVALID_INIT_METHOD +} + +- (instancetype)initWithName: (OFString *)name + DNSClass: (OFDNSClass)DNSClass + preference: (uint16_t)preference + mailExchange: (OFString *)mailExchange + TTL: (uint32_t)TTL +{ + self = [super initWithName: name + DNSClass: DNSClass + recordType: OFDNSRecordTypeMX + TTL: TTL]; + + @try { + _preference = preference; + _mailExchange = [mailExchange copy]; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (void)dealloc +{ + [_mailExchange release]; + + [super dealloc]; +} + +- (bool)isEqual: (id)object +{ + OFMXDNSResourceRecord *record; + + if (object == self) + return true; + + if (![object isKindOfClass: [OFMXDNSResourceRecord class]]) + return false; + + record = object; + + if (record->_name != _name && ![record->_name isEqual: _name]) + return false; + + if (record->_DNSClass != _DNSClass) + return false; + + if (record->_recordType != _recordType) + return false; + + if (record->_preference != _preference) + return false; + + if (record->_mailExchange != _mailExchange && + ![record->_mailExchange isEqual: _mailExchange]) + return false; + + return true; +} + +- (unsigned long)hash +{ + unsigned long hash; + + OFHashInit(&hash); + + OFHashAddHash(&hash, _name.hash); + OFHashAddByte(&hash, _DNSClass >> 8); + OFHashAddByte(&hash, _DNSClass); + OFHashAddByte(&hash, _recordType >> 8); + OFHashAddByte(&hash, _recordType); + OFHashAddByte(&hash, _preference >> 8); + OFHashAddByte(&hash, _preference); + OFHashAddHash(&hash, _mailExchange.hash); + + OFHashFinalize(&hash); + + return hash; +} + +- (OFString *)description +{ + return [OFString stringWithFormat: + @"<%@:\n" + @"\tName = %@\n" + @"\tClass = %@\n" + @"\tPreference = %" PRIu16 "\n" + @"\tMail Exchange = %@\n" + @"\tTTL = %" PRIu32 "\n" + @">", + self.className, _name, OFDNSClassName(_DNSClass), _preference, + _mailExchange, _TTL]; +} +@end Index: src/OFMatrix4x4.h ================================================================== --- src/OFMatrix4x4.h +++ src/OFMatrix4x4.h @@ -60,11 +60,11 @@ */ - (instancetype)initWithValues: (const float [_Nonnull 4][4])values OF_DESIGNATED_INITIALIZER; /** - * @brief Mulitplies the receiver with the specified matrix on the left side + * @brief Multiplies the receiver with the specified matrix on the left side * and the receiver on the right side. * * @param matrix The matrix to multiply the receiver with */ - (void)multiplyWithMatrix: (OFMatrix4x4 *)matrix; @@ -93,10 +93,11 @@ /** * @brief Transforms the specified vectors in-place according to the matrix. * * @param vectors The vectors to transform + * @param count The count of the specified vectors */ - (void)transformVectors: (OFVector4D *)vectors count: (size_t)count; @end OF_ASSUME_NONNULL_END Index: src/OFMutableIRI.h ================================================================== --- src/OFMutableIRI.h +++ src/OFMutableIRI.h @@ -201,11 +201,11 @@ /** * @brief Appends the specified path component. * * @param component The component to append * @param isDirectory Whether the path is a directory, in which case a slash is - * appened if there is no slash yet + * appended if there is no slash yet */ - (void)appendPathComponent: (OFString *)component isDirectory: (bool)isDirectory; /** Index: src/OFMutableString.h ================================================================== --- src/OFMutableString.h +++ src/OFMutableString.h @@ -175,11 +175,11 @@ * @brief Replaces all occurrences of a string in the specified range with * another string. * * @param string The string to replace * @param replacement The string with which it should be replaced - * @param options Options modifying search behaviour + * @param options Options modifying search behavior * Possible values: None yet * @param range The range in which the string should be replaced */ - (void)replaceOccurrencesOfString: (OFString *)string withString: (OFString *)replacement ADDED src/OFNSDNSResourceRecord.h Index: src/OFNSDNSResourceRecord.h ================================================================== --- src/OFNSDNSResourceRecord.h +++ src/OFNSDNSResourceRecord.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2008-2024 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#import "OFDNSResourceRecord.h" + +OF_ASSUME_NONNULL_BEGIN + +/** + * @class OFNSDNSResourceRecord \ + * OFDNSResourceRecord.h ObjFW/OFDNSResourceRecord.h + * + * @brief A class representing an NS DNS resource record. + */ +OF_SUBCLASSING_RESTRICTED +@interface OFNSDNSResourceRecord: OFDNSResourceRecord +{ + OFString *_authoritativeHost; +} + +/** + * @brief The authoritative host of the resource record. + */ +@property (readonly, nonatomic) OFString *authoritativeHost; + +- (instancetype)initWithName: (OFString *)name + DNSClass: (OFDNSClass)DNSClass + recordType: (OFDNSRecordType)recordType + TTL: (uint32_t)TTL OF_UNAVAILABLE; + +/** + * @brief Initializes an already allocated OFNSDNSResourceRecord with the + * specified name, class, authoritative host and time to live. + * + * @param name The name for the resource record + * @param DNSClass The class code for the resource record + * @param authoritativeHost The authoritative host for the resource record + * @param TTL The time to live for the resource record + * @return An initialized OFNSDNSResourceRecord + */ +- (instancetype)initWithName: (OFString *)name + DNSClass: (OFDNSClass)DNSClass + authoritativeHost: (OFString *)authoritativeHost + TTL: (uint32_t)TTL OF_DESIGNATED_INITIALIZER; +@end + +OF_ASSUME_NONNULL_END ADDED src/OFNSDNSResourceRecord.m Index: src/OFNSDNSResourceRecord.m ================================================================== --- src/OFNSDNSResourceRecord.m +++ src/OFNSDNSResourceRecord.m @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2008-2024 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#include "config.h" + +#import "OFMXDNSResourceRecord.h" + +@implementation OFNSDNSResourceRecord +@synthesize authoritativeHost = _authoritativeHost; + +- (instancetype)initWithName: (OFString *)name + DNSClass: (OFDNSClass)DNSClass + recordType: (OFDNSRecordType)recordType + TTL: (uint32_t)TTL +{ + OF_INVALID_INIT_METHOD +} + +- (instancetype)initWithName: (OFString *)name + DNSClass: (OFDNSClass)DNSClass + authoritativeHost: (OFString *)authoritativeHost + TTL: (uint32_t)TTL +{ + self = [super initWithName: name + DNSClass: DNSClass + recordType: OFDNSRecordTypeNS + TTL: TTL]; + + @try { + _authoritativeHost = [authoritativeHost copy]; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (void)dealloc +{ + [_authoritativeHost release]; + + [super dealloc]; +} + +- (bool)isEqual: (id)object +{ + OFNSDNSResourceRecord *record; + + if (object == self) + return true; + + if (![object isKindOfClass: [OFNSDNSResourceRecord class]]) + return false; + + record = object; + + if (record->_name != _name && ![record->_name isEqual: _name]) + return false; + + if (record->_DNSClass != _DNSClass) + return false; + + if (record->_recordType != _recordType) + return false; + + if (record->_authoritativeHost != _authoritativeHost && + ![record->_authoritativeHost isEqual: _authoritativeHost]) + return false; + + return true; +} + +- (unsigned long)hash +{ + unsigned long hash; + + OFHashInit(&hash); + + OFHashAddHash(&hash, _name.hash); + OFHashAddByte(&hash, _DNSClass >> 8); + OFHashAddByte(&hash, _DNSClass); + OFHashAddByte(&hash, _recordType >> 8); + OFHashAddByte(&hash, _recordType); + OFHashAddHash(&hash, _authoritativeHost.hash); + + OFHashFinalize(&hash); + + return hash; +} + +- (OFString *)description +{ + return [OFString stringWithFormat: + @"<%@:\n" + @"\tName = %@\n" + @"\tClass = %@\n" + @"\tAuthoritative Host = %@\n" + @"\tTTL = %" PRIu32 "\n" + @">", + self.className, _name, OFDNSClassName(_DNSClass), + _authoritativeHost, _TTL]; +} +@end Index: src/OFObject.h ================================================================== --- src/OFObject.h +++ src/OFObject.h @@ -81,11 +81,11 @@ */ typedef OFComparisonResult (^OFComparator)(id _Nonnull left, id _Nonnull right); #endif /** - * @brief An enum for representing endianess. + * @brief An enum for representing endianness. */ typedef enum { /** Most significant byte first (big endian) */ OFByteOrderBigEndian, /** Least significant byte first (little endian) */ @@ -113,11 +113,11 @@ /** * @brief Creates a new OFRange. * * @param start The starting index of the range * @param length The length of the range - * @return An OFRangeith the specified start and length + * @return An OFRange with the specified start and length */ static OF_INLINE OFRange OF_CONST_FUNC OFMakeRange(size_t start, size_t length) { OFRange range = { start, length }; @@ -1375,11 +1375,12 @@ /** * @protocol OFComparing OFObject.h ObjFW/OFObject.h * * @brief A protocol for comparing objects. * - * This protocol is implemented by objects that can be compared. Its only method, @ref compare:, should be overridden with a stronger type. + * This protocol is implemented by objects that can be compared. Its only + * method, @ref compare:, should be overridden with a stronger type. */ @protocol OFComparing /** * @brief Compares the object to another object. * @@ -1448,11 +1449,11 @@ /** * @brief Frees memory allocated by @ref OFAllocMemory, @ref OFAllocZeroedMemory * or @ref OFResizeMemory. * - * @param pointer A pointer to the memory to free or nil (passing nil ooes + * @param pointer A pointer to the memory to free or nil (passing nil does * nothing) */ extern void OFFreeMemory(void *_Nullable pointer); #ifdef OF_APPLE_RUNTIME Index: src/OFPBKDF2.h ================================================================== --- src/OFPBKDF2.h +++ src/OFPBKDF2.h @@ -60,11 +60,11 @@ extern "C" { #endif /** * @brief Derives a key from a password and a salt using PBKDF2. * - * @note This will call @ref OFHMAC::reset on the `HMAC` first, making it + * @note This will call @ref OFHMAC#reset on the `HMAC` first, making it * possible to reuse the `HMAC`, but also meaning all previous results * from the `HMAC` get invalidated if they have not been copied. * * @param parameters The parameters to use */ ADDED src/OFPTRDNSResourceRecord.h Index: src/OFPTRDNSResourceRecord.h ================================================================== --- src/OFPTRDNSResourceRecord.h +++ src/OFPTRDNSResourceRecord.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2008-2024 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#import "OFDNSResourceRecord.h" + +OF_ASSUME_NONNULL_BEGIN + +/** + * @class OFPTRDNSResourceRecord \ + * OFDNSResourceRecord.h ObjFW/OFDNSResourceRecord.h + * + * @brief A class representing a PTR DNS resource record. + */ +OF_SUBCLASSING_RESTRICTED +@interface OFPTRDNSResourceRecord: OFDNSResourceRecord +{ + OFString *_domainName; +} + +/** + * @brief The domain name of the resource record. + */ +@property (readonly, nonatomic) OFString *domainName; + +- (instancetype)initWithName: (OFString *)name + DNSClass: (OFDNSClass)DNSClass + recordType: (OFDNSRecordType)recordType + TTL: (uint32_t)TTL OF_UNAVAILABLE; + +/** + * @brief Initializes an already allocated OFPTRDNSResourceRecord with the + * specified name, class, domain name and time to live. + * + * @param name The name for the resource record + * @param DNSClass The class code for the resource record + * @param domainName The domain name for the resource record + * @param TTL The time to live for the resource record + * @return An initialized OFPTRDNSResourceRecord + */ +- (instancetype)initWithName: (OFString *)name + DNSClass: (OFDNSClass)DNSClass + domainName: (OFString *)domainName + TTL: (uint32_t)TTL OF_DESIGNATED_INITIALIZER; +@end + +OF_ASSUME_NONNULL_END ADDED src/OFPTRDNSResourceRecord.m Index: src/OFPTRDNSResourceRecord.m ================================================================== --- src/OFPTRDNSResourceRecord.m +++ src/OFPTRDNSResourceRecord.m @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2008-2024 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#include "config.h" + +#import "OFPTRDNSResourceRecord.h" + +@implementation OFPTRDNSResourceRecord +@synthesize domainName = _domainName; + +- (instancetype)initWithName: (OFString *)name + DNSClass: (OFDNSClass)DNSClass + recordType: (OFDNSRecordType)recordType + TTL: (uint32_t)TTL +{ + OF_INVALID_INIT_METHOD +} + +- (instancetype)initWithName: (OFString *)name + DNSClass: (OFDNSClass)DNSClass + domainName: (OFString *)domainName + TTL: (uint32_t)TTL +{ + self = [super initWithName: name + DNSClass: DNSClass + recordType: OFDNSRecordTypePTR + TTL: TTL]; + + @try { + _domainName = [domainName copy]; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (void)dealloc +{ + [_domainName release]; + + [super dealloc]; +} + +- (bool)isEqual: (id)object +{ + OFPTRDNSResourceRecord *record; + + if (object == self) + return true; + + if (![object isKindOfClass: [OFPTRDNSResourceRecord class]]) + return false; + + record = object; + + if (record->_name != _name && ![record->_name isEqual: _name]) + return false; + + if (record->_DNSClass != _DNSClass) + return false; + + if (record->_recordType != _recordType) + return false; + + if (record->_domainName != _domainName && + ![record->_domainName isEqual: _domainName]) + return false; + + return true; +} + +- (unsigned long)hash +{ + unsigned long hash; + + OFHashInit(&hash); + + OFHashAddHash(&hash, _name.hash); + OFHashAddByte(&hash, _DNSClass >> 8); + OFHashAddByte(&hash, _DNSClass); + OFHashAddByte(&hash, _recordType >> 8); + OFHashAddByte(&hash, _recordType); + OFHashAddHash(&hash, _domainName.hash); + + OFHashFinalize(&hash); + + return hash; +} + +- (OFString *)description +{ + return [OFString stringWithFormat: + @"<%@:\n" + @"\tName = %@\n" + @"\tClass = %@\n" + @"\tDomain Name = %@\n" + @"\tTTL = %" PRIu32 "\n" + @">", + self.className, _name, OFDNSClassName(_DNSClass), _domainName, + _TTL]; +} +@end Index: src/OFPlugin.h ================================================================== --- src/OFPlugin.h +++ src/OFPlugin.h @@ -73,11 +73,11 @@ /** * @brief Returns the address for the specified symbol, or `nil` if not found. * * @param symbol The symbol to return the address for - * @return The address for the speccified symbol, or `nil` if not found + * @return The address for the specified symbol, or `nil` if not found */ - (nullable void *)addressForSymbol: (OFString *)symbol; @end OF_ASSUME_NONNULL_END ADDED src/OFRPDNSResourceRecord.h Index: src/OFRPDNSResourceRecord.h ================================================================== --- src/OFRPDNSResourceRecord.h +++ src/OFRPDNSResourceRecord.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2008-2024 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#import "OFDNSResourceRecord.h" + +OF_ASSUME_NONNULL_BEGIN + +/** + * @class OFRPDNSResourceRecord \ + * OFDNSResourceRecord.h ObjFW/OFDNSResourceRecord.h + * + * @brief A class representing an RP DNS resource record. + */ +OF_SUBCLASSING_RESTRICTED +@interface OFRPDNSResourceRecord: OFDNSResourceRecord +{ + OFString *_mailbox, *_TXTDomainName; +} + +/** + * @brief The mailbox of the responsible person of the resource record. + */ +@property (readonly, nonatomic) OFString *mailbox; + +/** + * @brief A domain name that contains a TXT resource record for the responsible + * person of the resource record. + */ +@property (readonly, nonatomic) OFString *TXTDomainName; + +- (instancetype)initWithName: (OFString *)name + DNSClass: (OFDNSClass)DNSClass + recordType: (OFDNSRecordType)recordType + TTL: (uint32_t)TTL OF_UNAVAILABLE; + +/** + * @brief Initializes an already allocated OFRPDNSResourceRecord with the + * specified name, class, alias and time to live. + * + * @param name The name for the resource record + * @param DNSClass The class code for the resource record + * @param mailbox The mailbox of the responsible person of the resource record + * @param TXTDomainName A domain name that contains a TXT resource record for + * the responsible person of the resource record + * @param TTL The time to live for the resource record + * @return An initialized OFRPDNSResourceRecord + */ +- (instancetype)initWithName: (OFString *)name + DNSClass: (OFDNSClass)DNSClass + mailbox: (OFString *)mailbox + TXTDomainName: (OFString *)TXTDomainName + TTL: (uint32_t)TTL OF_DESIGNATED_INITIALIZER; +@end + +OF_ASSUME_NONNULL_END ADDED src/OFRPDNSResourceRecord.m Index: src/OFRPDNSResourceRecord.m ================================================================== --- src/OFRPDNSResourceRecord.m +++ src/OFRPDNSResourceRecord.m @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2008-2024 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#include "config.h" + +#import "OFRPDNSResourceRecord.h" + +@implementation OFRPDNSResourceRecord +@synthesize mailbox = _mailbox, TXTDomainName = _TXTDomainName; + +- (instancetype)initWithName: (OFString *)name + DNSClass: (OFDNSClass)DNSClass + recordType: (OFDNSRecordType)recordType + TTL: (uint32_t)TTL +{ + OF_INVALID_INIT_METHOD +} + +- (instancetype)initWithName: (OFString *)name + DNSClass: (OFDNSClass)DNSClass + mailbox: (OFString *)mailbox + TXTDomainName: (OFString *)TXTDomainName + TTL: (uint32_t)TTL +{ + self = [super initWithName: name + DNSClass: DNSClass + recordType: OFDNSRecordTypeRP + TTL: TTL]; + + @try { + _mailbox = [mailbox copy]; + _TXTDomainName = [TXTDomainName copy]; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (void)dealloc +{ + [_mailbox release]; + [_TXTDomainName release]; + + [super dealloc]; +} + +- (bool)isEqual: (id)object +{ + OFRPDNSResourceRecord *record; + + if (object == self) + return true; + + if (![object isKindOfClass: [OFRPDNSResourceRecord class]]) + return false; + + record = object; + + if (record->_name != _name && ![record->_name isEqual: _name]) + return false; + + if (record->_DNSClass != _DNSClass) + return false; + + if (record->_recordType != _recordType) + return false; + + if (record->_mailbox != _mailbox && + ![record->_mailbox isEqual: _mailbox]) + return false; + + if (record->_TXTDomainName != _TXTDomainName && + ![record->_TXTDomainName isEqual: _TXTDomainName]) + return false; + + return true; +} + +- (unsigned long)hash +{ + unsigned long hash; + + OFHashInit(&hash); + + OFHashAddHash(&hash, _name.hash); + OFHashAddByte(&hash, _DNSClass >> 8); + OFHashAddByte(&hash, _DNSClass); + OFHashAddByte(&hash, _recordType >> 8); + OFHashAddByte(&hash, _recordType); + OFHashAddHash(&hash, _mailbox.hash); + OFHashAddHash(&hash, _TXTDomainName.hash); + + OFHashFinalize(&hash); + + return hash; +} + +- (OFString *)description +{ + return [OFString stringWithFormat: + @"<%@:\n" + @"\tName = %@\n" + @"\tClass = %@\n" + @"\tMailbox = %@\n" + @"\tTXT Domain Name = %@\n" + @"\tTTL = %" PRIu32 "\n" + @">", + self.className, _name, OFDNSClassName(_DNSClass), _mailbox, + _TXTDomainName, _TTL]; +} +@end ADDED src/OFSOADNSResourceRecord.h Index: src/OFSOADNSResourceRecord.h ================================================================== --- src/OFSOADNSResourceRecord.h +++ src/OFSOADNSResourceRecord.h @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2008-2024 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#import "OFDNSResourceRecord.h" + +OF_ASSUME_NONNULL_BEGIN + +/** + * @class OFSOADNSResourceRecord \ + * OFDNSResourceRecord.h ObjFW/OFDNSResourceRecord.h + * + * @brief A class representing an SOA DNS resource record. + */ +OF_SUBCLASSING_RESTRICTED +@interface OFSOADNSResourceRecord: OFDNSResourceRecord +{ + OFString *_primaryNameServer, *_responsiblePerson; + uint32_t _serialNumber, _refreshInterval, _retryInterval; + uint32_t _expirationInterval, _minTTL; +} + +/** + * @brief The the primary name server for the zone. + */ +@property (readonly, nonatomic) OFString *primaryNameServer; + +/** + * @brief The mailbox of the person responsible for the zone. + */ +@property (readonly, nonatomic) OFString *responsiblePerson; + +/** + * @brief The serial number of the original copy of the zone. + */ +@property (readonly, nonatomic) uint32_t serialNumber; + +/** + * @brief The refresh interval of the zone. + */ +@property (readonly, nonatomic) uint32_t refreshInterval; + +/** + * @brief The retry interval of the zone. + */ +@property (readonly, nonatomic) uint32_t retryInterval; + +/** + * @brief The expiration interval of the zone. + */ +@property (readonly, nonatomic) uint32_t expirationInterval; + +/** + * @brief The minimum TTL of the zone. + */ +@property (readonly, nonatomic) uint32_t minTTL; + +- (instancetype)initWithName: (OFString *)name + DNSClass: (OFDNSClass)DNSClass + recordType: (OFDNSRecordType)recordType + TTL: (uint32_t)TTL OF_UNAVAILABLE; + +/** + * @brief Initializes an already allocated OFSOADNSResourceRecord with the + * specified name, class, text data and time to live. + * + * @param name The name for the resource record + * @param DNSClass The class code for the resource record + * @param primaryNameServer The the primary name server for the zone + * @param responsiblePerson The mailbox of the person responsible for the zone + * @param serialNumber The serial number of the original copy of the zone + * @param refreshInterval The refresh interval of the zone + * @param retryInterval The retry interval of the zone + * @param expirationInterval The expiration interval of the zone + * @param minTTL The minimum TTL of the zone + * @param TTL The time to live for the resource record + * @return An initialized OFSOADNSResourceRecord + */ +- (instancetype)initWithName: (OFString *)name + DNSClass: (OFDNSClass)DNSClass + primaryNameServer: (OFString *)primaryNameServer + responsiblePerson: (OFString *)responsiblePerson + serialNumber: (uint32_t)serialNumber + refreshInterval: (uint32_t)refreshInterval + retryInterval: (uint32_t)retryInterval + expirationInterval: (uint32_t)expirationInterval + minTTL: (uint32_t)minTTL + TTL: (uint32_t)TTL OF_DESIGNATED_INITIALIZER; +@end + +OF_ASSUME_NONNULL_END ADDED src/OFSOADNSResourceRecord.m Index: src/OFSOADNSResourceRecord.m ================================================================== --- src/OFSOADNSResourceRecord.m +++ src/OFSOADNSResourceRecord.m @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2008-2024 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#include "config.h" + +#import "OFSOADNSResourceRecord.h" + +@implementation OFSOADNSResourceRecord +@synthesize primaryNameServer = _primaryNameServer; +@synthesize responsiblePerson = _responsiblePerson; +@synthesize serialNumber = _serialNumber, refreshInterval = _refreshInterval; +@synthesize retryInterval = _retryInterval; +@synthesize expirationInterval = _expirationInterval, minTTL = _minTTL; + +- (instancetype)initWithName: (OFString *)name + DNSClass: (OFDNSClass)DNSClass + recordType: (OFDNSRecordType)recordType + TTL: (uint32_t)TTL +{ + OF_INVALID_INIT_METHOD +} + +- (instancetype)initWithName: (OFString *)name + DNSClass: (OFDNSClass)DNSClass + primaryNameServer: (OFString *)primaryNameServer + responsiblePerson: (OFString *)responsiblePerson + serialNumber: (uint32_t)serialNumber + refreshInterval: (uint32_t)refreshInterval + retryInterval: (uint32_t)retryInterval + expirationInterval: (uint32_t)expirationInterval + minTTL: (uint32_t)minTTL + TTL: (uint32_t)TTL +{ + self = [super initWithName: name + DNSClass: DNSClass + recordType: OFDNSRecordTypeSOA + TTL: TTL]; + + @try { + _primaryNameServer = [primaryNameServer copy]; + _responsiblePerson = [responsiblePerson copy]; + _serialNumber = serialNumber; + _refreshInterval = refreshInterval; + _retryInterval = retryInterval; + _expirationInterval = expirationInterval; + _minTTL = minTTL; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (void)dealloc +{ + [_primaryNameServer release]; + [_responsiblePerson release]; + + [super dealloc]; +} + +- (bool)isEqual: (id)object +{ + OFSOADNSResourceRecord *record; + + if (object == self) + return true; + + if (![object isKindOfClass: [OFSOADNSResourceRecord class]]) + return false; + + record = object; + + if (record->_name != _name && ![record->_name isEqual: _name]) + return false; + + if (record->_DNSClass != _DNSClass) + return false; + + if (record->_recordType != _recordType) + return false; + + if (record->_primaryNameServer != _primaryNameServer && + ![record->_primaryNameServer isEqual: _primaryNameServer]) + return false; + + if (record->_responsiblePerson != _responsiblePerson && + ![record->_responsiblePerson isEqual: _responsiblePerson]) + return false; + + if (record->_serialNumber != _serialNumber) + return false; + + if (record->_refreshInterval != _refreshInterval) + return false; + + if (record->_retryInterval != _retryInterval) + return false; + + if (record->_expirationInterval != _expirationInterval) + return false; + + if (record->_minTTL != _minTTL) + return false; + + return true; +} + +- (unsigned long)hash +{ + unsigned long hash; + + OFHashInit(&hash); + + OFHashAddHash(&hash, _name.hash); + OFHashAddByte(&hash, _DNSClass >> 8); + OFHashAddByte(&hash, _DNSClass); + OFHashAddByte(&hash, _recordType >> 8); + OFHashAddByte(&hash, _recordType); + OFHashAddHash(&hash, _primaryNameServer.hash); + OFHashAddHash(&hash, _responsiblePerson.hash); + OFHashAddByte(&hash, _serialNumber >> 24); + OFHashAddByte(&hash, _serialNumber >> 16); + OFHashAddByte(&hash, _serialNumber >> 8); + OFHashAddByte(&hash, _serialNumber); + OFHashAddByte(&hash, _refreshInterval >> 24); + OFHashAddByte(&hash, _refreshInterval >> 16); + OFHashAddByte(&hash, _refreshInterval >> 8); + OFHashAddByte(&hash, _refreshInterval); + OFHashAddByte(&hash, _retryInterval >> 24); + OFHashAddByte(&hash, _retryInterval >> 16); + OFHashAddByte(&hash, _retryInterval >> 8); + OFHashAddByte(&hash, _retryInterval); + OFHashAddByte(&hash, _expirationInterval >> 24); + OFHashAddByte(&hash, _expirationInterval >> 16); + OFHashAddByte(&hash, _expirationInterval >> 8); + OFHashAddByte(&hash, _expirationInterval); + OFHashAddByte(&hash, _minTTL >> 24); + OFHashAddByte(&hash, _minTTL >> 16); + OFHashAddByte(&hash, _minTTL >> 8); + OFHashAddByte(&hash, _minTTL); + + OFHashFinalize(&hash); + + return hash; +} + +- (OFString *)description +{ + return [OFString stringWithFormat: + @"<%@:\n" + @"\tName = %@\n" + @"\tClass = %@\n" + @"\tPrimary Name Server = %@\n" + @"\tResponsible Person = %@\n" + @"\tSerial Number = %" PRIu32 "\n" + @"\tRefresh Interval = %" PRIu32 "\n" + @"\tRetry Interval = %" PRIu32 "\n" + @"\tExpiration Interval = %" PRIu32 "\n" + @"\tMinimum TTL = %" PRIu32 "\n" + @"\tTTL = %" PRIu32 "\n" + @">", + self.className, _name, OFDNSClassName(_DNSClass), + _primaryNameServer, _responsiblePerson, _serialNumber, + _refreshInterval, _retryInterval, _expirationInterval, _minTTL, + _TTL]; +} +@end Index: src/OFSPXSocket.h ================================================================== --- src/OFSPXSocket.h +++ src/OFSPXSocket.h @@ -113,11 +113,12 @@ * * @param network The network on which the node to connect to is * @param node The node to connect to * @param port The port (sometimes also called socket number) on the node to * connect to - * @param runLoopMode The run loop mode in which to perform the async connect + * @param runLoopMode The run loop mode in which to perform the asynchronous + * connect */ - (void)asyncConnectToNetwork: (uint32_t)network node: (const unsigned char [_Nonnull IPX_NODE_LEN])node port: (uint16_t)port runLoopMode: (OFRunLoopMode)runLoopMode; @@ -142,11 +143,12 @@ * * @param node The node to connect to * @param network The network on which the node to connect to is * @param port The port (sometimes also called socket number) on the node to * connect to - * @param runLoopMode The run loop mode in which to perform the async connect + * @param runLoopMode The run loop mode in which to perform the asynchronous + * connect * @param block The block to execute once the connection has been established */ - (void)asyncConnectToNetwork: (uint32_t)network node: (const unsigned char [_Nonnull IPX_NODE_LEN])node port: (uint16_t)port Index: src/OFSPXStreamSocket.h ================================================================== --- src/OFSPXStreamSocket.h +++ src/OFSPXStreamSocket.h @@ -116,11 +116,12 @@ * * @param network The network on which the node to connect to is * @param node The node to connect to * @param port The port (sometimes also called socket number) on the node to * connect to - * @param runLoopMode The run loop mode in which to perform the async connect + * @param runLoopMode The run loop mode in which to perform the asynchronous + * connect */ - (void)asyncConnectToNetwork: (uint32_t)network node: (const unsigned char [_Nonnull IPX_NODE_LEN])node port: (uint16_t)port runLoopMode: (OFRunLoopMode)runLoopMode; @@ -147,11 +148,12 @@ * * @param network The network on which the node to connect to is * @param node The node to connect to * @param port The port (sometimes also called socket number) on the node to * connect to - * @param runLoopMode The run loop mode in which to perform the async connect + * @param runLoopMode The run loop mode in which to perform the asynchronous + * connect * @param block The block to execute once the connection has been established */ - (void)asyncConnectToNetwork: (uint32_t)network node: (const unsigned char [_Nonnull IPX_NODE_LEN])node port: (uint16_t)port ADDED src/OFSRVDNSResourceRecord.h Index: src/OFSRVDNSResourceRecord.h ================================================================== --- src/OFSRVDNSResourceRecord.h +++ src/OFSRVDNSResourceRecord.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2008-2024 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#import "OFDNSResourceRecord.h" + +OF_ASSUME_NONNULL_BEGIN + +/** + * @class OFSRVDNSResourceRecord \ + * OFDNSResourceRecord.h ObjFW/OFDNSResourceRecord.h + * + * @brief A class representing an SRV DNS resource record. + */ +OF_SUBCLASSING_RESTRICTED +@interface OFSRVDNSResourceRecord: OFDNSResourceRecord +{ + uint16_t _priority, _weight; + OFString *_target; + uint16_t _port; +} + +/** + * @brief The priority of the resource record. + */ +@property (readonly, nonatomic) uint16_t priority; + +/** + * @brief The weight of the resource record. + */ +@property (readonly, nonatomic) uint16_t weight; + +/** + * @brief The target of the resource record. + */ +@property (readonly, nonatomic) OFString *target; + +/** + * @brief The port on the target of the resource record. + */ +@property (readonly, nonatomic) uint16_t port; + +- (instancetype)initWithName: (OFString *)name + DNSClass: (OFDNSClass)DNSClass + recordType: (OFDNSRecordType)recordType + TTL: (uint32_t)TTL OF_UNAVAILABLE; + +/** + * @brief Initializes an already allocated OFSRVDNSResourceRecord with the + * specified name, priority, weight, target, port and time to live. + * + * @param name The name for the resource record + * @param priority The priority for the resource record + * @param weight The weight for the resource record + * @param target The target for the resource record + * @param port The port on the target for the resource record + * @param TTL The time to live for the resource record + * @return An initialized OFSRVDNSResourceRecord + */ +- (instancetype)initWithName: (OFString *)name + priority: (uint16_t)priority + weight: (uint16_t)weight + target: (OFString *)target + port: (uint16_t)port + TTL: (uint32_t)TTL OF_DESIGNATED_INITIALIZER; +@end + +OF_ASSUME_NONNULL_END ADDED src/OFSRVDNSResourceRecord.m Index: src/OFSRVDNSResourceRecord.m ================================================================== --- src/OFSRVDNSResourceRecord.m +++ src/OFSRVDNSResourceRecord.m @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2008-2024 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#include "config.h" + +#import "OFSRVDNSResourceRecord.h" + +@implementation OFSRVDNSResourceRecord +@synthesize priority = _priority, weight = _weight, target = _target; +@synthesize port = _port; + +- (instancetype)initWithName: (OFString *)name + DNSClass: (OFDNSClass)DNSClass + recordType: (OFDNSRecordType)recordType + TTL: (uint32_t)TTL +{ + OF_INVALID_INIT_METHOD +} + +- (instancetype)initWithName: (OFString *)name + priority: (uint16_t)priority + weight: (uint16_t)weight + target: (OFString *)target + port: (uint16_t)port + TTL: (uint32_t)TTL +{ + self = [super initWithName: name + DNSClass: OFDNSClassIN + recordType: OFDNSRecordTypeSRV + TTL: TTL]; + + @try { + _priority = priority; + _weight = weight; + _target = [target copy]; + _port = port; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (void)dealloc +{ + [_target release]; + + [super dealloc]; +} + +- (bool)isEqual: (id)object +{ + OFSRVDNSResourceRecord *record; + + if (object == self) + return true; + + if (![object isKindOfClass: [OFSRVDNSResourceRecord class]]) + return false; + + record = object; + + if (record->_name != _name && ![record->_name isEqual: _name]) + return false; + + if (record->_DNSClass != _DNSClass) + return false; + + if (record->_recordType != _recordType) + return false; + + if (record->_priority != _priority) + return false; + + if (record->_weight != _weight) + return false; + + if (record->_target != _target && ![record->_target isEqual: _target]) + return false; + + if (record->_port != _port) + return false; + + return true; +} + +- (unsigned long)hash +{ + unsigned long hash; + + OFHashInit(&hash); + + OFHashAddHash(&hash, _name.hash); + OFHashAddByte(&hash, _DNSClass >> 8); + OFHashAddByte(&hash, _DNSClass); + OFHashAddByte(&hash, _recordType >> 8); + OFHashAddByte(&hash, _recordType); + OFHashAddByte(&hash, _priority >> 8); + OFHashAddByte(&hash, _priority); + OFHashAddByte(&hash, _weight >> 8); + OFHashAddByte(&hash, _weight); + OFHashAddHash(&hash, _target.hash); + OFHashAddByte(&hash, _port >> 8); + OFHashAddByte(&hash, _port); + + OFHashFinalize(&hash); + + return hash; +} + +- (OFString *)description +{ + return [OFString stringWithFormat: + @"<%@:\n" + @"\tName = %@\n" + @"\tPriority = %" PRIu16 "\n" + @"\tWeight = %" PRIu16 "\n" + @"\tTarget = %@\n" + @"\tPort = %" PRIu16 "\n" + @"\tTTL = %" PRIu32 "\n" + @">", + self.className, _name, _priority, _weight, _target, _port, _TTL]; +} +@end Index: src/OFSequencedPacketSocket.h ================================================================== --- src/OFSequencedPacketSocket.h +++ src/OFSequencedPacketSocket.h @@ -207,11 +207,12 @@ * * If the buffer is too small, the receive operation fails. * * @param buffer The buffer to write the packet to * @param length The length of the buffer - * @param runLoopMode The run loop mode in which to perform the async receive + * @param runLoopMode The run loop mode in which to perform the asynchronous + * receive */ - (void)asyncReceiveIntoBuffer: (void *)buffer length: (size_t)length runLoopMode: (OFRunLoopMode)runLoopMode; @@ -240,11 +241,12 @@ * * If the buffer is too small, the receive operation fails. * * @param buffer The buffer to write the packet to * @param length The length of the buffer - * @param runLoopMode The run loop mode in which to perform the async receive + * @param runLoopMode The run loop mode in which to perform the asynchronous + * receive * @param block The block to call when the packet has been received. If the * block returns true, it will be called again with the same * buffer and maximum length when more packets have been received. * If you want the next method in the queue to handle the packet * received next, you need to return false from the method. @@ -274,11 +276,12 @@ /** * @brief Asynchronously sends the specified packet. * * @param data The data to send as a packet - * @param runLoopMode The run loop mode in which to perform the async send + * @param runLoopMode The run loop mode in which to perform the asynchronous + * send */ - (void)asyncSendData: (OFData *)data runLoopMode: (OFRunLoopMode)runLoopMode; #ifdef OF_HAVE_BLOCKS /** @@ -294,11 +297,12 @@ /** * @brief Asynchronously sends the specified packet. * * @param data The data to send as a packet - * @param runLoopMode The run loop mode in which to perform the async send + * @param runLoopMode The run loop mode in which to perform the asynchronous + * send * @param block The block to call when the packet has been sent. It should * return the data for the next send with the same callback or nil * if it should not repeat. */ - (void)asyncSendData: (OFData *)data @@ -338,11 +342,12 @@ - (void)asyncAccept; /** * @brief Asynchronously accept an incoming connection. * - * @param runLoopMode The run loop mode in which to perform the async accept + * @param runLoopMode The run loop mode in which to perform the asynchronous + * accept */ - (void)asyncAcceptWithRunLoopMode: (OFRunLoopMode)runLoopMode; #ifdef OF_HAVE_BLOCKS /** @@ -355,11 +360,12 @@ - (void)asyncAcceptWithBlock: (OFSequencedPacketSocketAsyncAcceptBlock)block; /** * @brief Asynchronously accept an incoming connection. * - * @param runLoopMode The run loop mode in which to perform the async accept + * @param runLoopMode The run loop mode in which to perform the asynchronous + * accept * @param block The block to execute when a new connection has been accepted. * Returns whether the next incoming connection should be accepted * by the specified block as well. */ - (void) Index: src/OFSettings.h ================================================================== --- src/OFSettings.h +++ src/OFSettings.h @@ -23,11 +23,11 @@ /** * @class OFSettings OFSettings.h ObjFW/OFSettings.h * * Paths are delimited by dots, for example `category.subcategory.key`. * - * @note The behaviour when accessing a path with a different type than it has + * @note The behavior when accessing a path with a different type than it has * been accessed with before is undefined! If you want to change the type * for a path, remove it and then set it with the new type. * * @brief A class for storing and retrieving settings */ Index: src/OFStdIOStream.m ================================================================== --- src/OFStdIOStream.m +++ src/OFStdIOStream.m @@ -137,11 +137,11 @@ return 35; if ([color isEqual: [OFColor teal]]) return 36; if ([color isEqual: [OFColor silver]]) return 37; - if ([color isEqual: [OFColor grey]]) + if ([color isEqual: [OFColor gray]]) return 90; if ([color isEqual: [OFColor red]]) return 91; if ([color isEqual: [OFColor lime]]) return 92; Index: src/OFStream.h ================================================================== --- src/OFStream.h +++ src/OFStream.h @@ -493,11 +493,11 @@ * @brief Reads a uint16_t from the stream which is encoded in big endian. * * @warning Only call this when you know that enough data is available! * Otherwise you will get an exception! * - * @return A uint16_t from the stream in native endianess + * @return A uint16_t from the stream in big endian * @throw OFReadFailedException Reading failed * @throw OFTruncatedDataException The end of the stream was reached before * reading enough bytes * @throw OFNotOpenException The stream is not open */ @@ -507,11 +507,11 @@ * @brief Reads a uint32_t from the stream which is encoded in big endian. * * @warning Only call this when you know that enough data is available! * Otherwise you will get an exception! * - * @return A uint32_t from the stream in the native endianess + * @return A uint32_t from the stream in big endian * @throw OFReadFailedException Reading failed * @throw OFTruncatedDataException The end of the stream was reached before * reading enough bytes * @throw OFNotOpenException The stream is not open */ @@ -521,11 +521,11 @@ * @brief Reads a uint64_t from the stream which is encoded in big endian. * * @warning Only call this when you know that enough data is available! * Otherwise you will get an exception! * - * @return A uint64_t from the stream in the native endianess + * @return A uint64_t from the stream in big endian * @throw OFReadFailedException Reading failed * @throw OFTruncatedDataException The end of the stream was reached before * reading enough bytes * @throw OFNotOpenException The stream is not open */ @@ -535,11 +535,11 @@ * @brief Reads a float from the stream which is encoded in big endian. * * @warning Only call this when you know that enough data is available! * Otherwise you will get an exception! * - * @return A float from the stream in the native endianess + * @return A float from the stream in big endian * @throw OFReadFailedException Reading failed * @throw OFTruncatedDataException The end of the stream was reached before * reading enough bytes * @throw OFNotOpenException The stream is not open */ @@ -549,11 +549,11 @@ * @brief Reads a double from the stream which is encoded in big endian. * * @warning Only call this when you know that enough data is available! * Otherwise you will get an exception! * - * @return A double from the stream in the native endianess + * @return A double from the stream in big endian * @throw OFReadFailedException Reading failed * @throw OFTruncatedDataException The end of the stream was reached before * reading enough bytes * @throw OFNotOpenException The stream is not open */ @@ -563,11 +563,11 @@ * @brief Reads a uint16_t from the stream which is encoded in little endian. * * @warning Only call this when you know that enough data is available! * Otherwise you will get an exception! * - * @return A uint16_t from the stream in native endianess + * @return A uint16_t from the stream in little endian * @throw OFReadFailedException Reading failed * @throw OFTruncatedDataException The end of the stream was reached before * reading enough bytes * @throw OFNotOpenException The stream is not open */ @@ -577,11 +577,11 @@ * @brief Reads a uint32_t from the stream which is encoded in little endian. * * @warning Only call this when you know that enough data is available! * Otherwise you will get an exception! * - * @return A uint32_t from the stream in the native endianess + * @return A uint32_t from the stream in little endian * @throw OFReadFailedException Reading failed * @throw OFTruncatedDataException The end of the stream was reached before * reading enough bytes * @throw OFNotOpenException The stream is not open */ @@ -591,11 +591,11 @@ * @brief Reads a uint64_t from the stream which is encoded in little endian. * * @warning Only call this when you know that enough data is available! * Otherwise you will get an exception! * - * @return A uint64_t from the stream in the native endianess + * @return A uint64_t from the stream in little endian * @throw OFReadFailedException Reading failed * @throw OFTruncatedDataException The end of the stream was reached before * reading enough bytes * @throw OFNotOpenException The stream is not open */ @@ -605,11 +605,11 @@ * @brief Reads a float from the stream which is encoded in little endian. * * @warning Only call this when you know that enough data is available! * Otherwise you will get an exception! * - * @return A float from the stream in the native endianess + * @return A float from the stream in little endian * @throw OFReadFailedException Reading failed * @throw OFTruncatedDataException The end of the stream was reached before * reading enough bytes * @throw OFNotOpenException The stream is not open */ @@ -619,11 +619,11 @@ * @brief Reads a double from the stream which is encoded in little endian. * * @warning Only call this when you know that enough data is available! * Otherwise you will get an exception! * - * @return A double from the stream in the native endianess + * @return A double from the stream in little endian * @throw OFReadFailedException Reading failed * @throw OFTruncatedDataException The end of the stream was reached before * reading enough bytes * @throw OFNotOpenException The stream is not open */ Index: src/OFString.h ================================================================== --- src/OFString.h +++ src/OFString.h @@ -77,15 +77,15 @@ OFStringEncodingISO8859_15, /** Windows-1251 */ OFStringEncodingWindows1251, /** Windows-1252 */ OFStringEncodingWindows1252, - /** Codepage 437 */ + /** Code page 437 */ OFStringEncodingCodepage437, - /** Codepage 850 */ + /** Code page 850 */ OFStringEncodingCodepage850, - /** Codepage 858 */ + /** Code page 858 */ OFStringEncodingCodepage858, /** Mac OS Roman */ OFStringEncodingMacRoman, /** KOI8-R */ OFStringEncodingKOI8R, @@ -132,11 +132,11 @@ * @brief A class for handling strings. */ @interface OFString: OFObject /** - * @brief The length of the string in Unicode codepoints. + * @brief The length of the string in Unicode code points. */ @property (readonly, nonatomic) size_t length; /** * @brief The OFString as a UTF-8 encoded C string. @@ -305,11 +305,11 @@ /** * @brief Creates a new OFString from a UTF-8 encoded C string without copying * the string, if possible. * * If initialization fails for whatever reason, the passed C string is *not* - * free'd if `freeWhenDone` is true. + * freed if `freeWhenDone` is true. * * @note OFMutableString always creates a copy! * * @param UTF8String A UTF-8 encoded C string to initialize the OFString with * @param freeWhenDone Whether to free the C string when the OFString gets @@ -323,11 +323,11 @@ /** * @brief Creates a new OFString from a UTF-8 encoded C string with the * specified length without copying the string, if possible. * * If initialization fails for whatever reason, the passed C string is *not* - * free'd if `freeWhenDone` is true. + * freed if `freeWhenDone` is true. * * @note OFMutableString always creates a copy! * * @param UTF8String A UTF-8 encoded C string to initialize the OFString with * @param UTF8StringLength The length of the UTF-8 encoded C string @@ -529,13 +529,13 @@ /** * @brief Creates a new OFString with the contents of the specified IRI. * * If the IRI's scheme is file, it tries UTF-8 encoding. * - * If the IRI's scheme is http(s), it tries to detect the encoding from the HTTP - * headers. If it could not detect the encoding using the HTTP headers, it tries - * UTF-8. + * If the IRI's scheme is `http` or `https`, it tries to detect the encoding + * from the HTTP headers. If it could not detect the encoding using the HTTP + * headers, it tries UTF-8. * * @param IRI The IRI to the contents for the string * @return A new autoreleased OFString * @throw OFInvalidEncodingException The string is not in the expected encoding */ @@ -585,11 +585,11 @@ /** * @brief Initializes an already allocated OFString from an UTF-8 encoded C * string without copying the string, if possible. * * If initialization fails for whatever reason, the passed C string is *not* - * free'd if `freeWhenDone` is true. + * freed if `freeWhenDone` is true. * * @note OFMutableString always creates a copy! * * @param UTF8String A UTF-8 encoded C string to initialize the OFString with * @param freeWhenDone Whether to free the C string when it is not needed @@ -604,11 +604,11 @@ * @brief Initializes an already allocated OFString from an UTF-8 encoded C * string with the specified length without copying the string, if * possible. * * If initialization fails for whatever reason, the passed C string is *not* - * free'd if `freeWhenDone` is true. + * freed if `freeWhenDone` is true. * * @note OFMutableString always creates a copy! * * @param UTF8String A UTF-8 encoded C string to initialize the OFString with * @param UTF8StringLength The length of the UTF-8 encoded C string @@ -830,13 +830,13 @@ * @brief Initializes an already allocated OFString with the contents of the * specified IRI. * * If the IRI's scheme is file, it tries UTF-8 encoding. * - * If the IRI's scheme is http(s), it tries to detect the encoding from the HTTP - * headers. If it could not detect the encoding using the HTTP headers, it tries - * UTF-8. + * If the IRI's scheme is `http` or `https`, it tries to detect the encoding + * from the HTTP headers. If it could not detect the encoding using the HTTP + * headers, it tries UTF-8. * * @param IRI The IRI to the contents for the string * @return An initialized OFString * @throw OFInvalidEncodingException The string is not in the expected encoding */ @@ -1003,11 +1003,11 @@ /** * @brief Returns the index of the first character from the set. * * @param characterSet The set of characters to search for - * @param options Options modifying search behaviour + * @param options Options modifying search behavior * @return The index of the first occurrence of a character from the set or * `OFNotFound` if it was not found */ - (size_t)indexOfCharacterFromSet: (OFCharacterSet *)characterSet options: (OFStringSearchOptions)options; @@ -1014,11 +1014,11 @@ /** * @brief Returns the index of the first character from the set. * * @param characterSet The set of characters to search for - * @param options Options modifying search behaviour + * @param options Options modifying search behavior * @param range The range in which to search * @return The index of the first occurrence of a character from the set or * `OFNotFound` if it was not found */ - (size_t)indexOfCharacterFromSet: (OFCharacterSet *)characterSet @@ -1043,11 +1043,11 @@ /** * @brief Creates a substring from the beginning to the specified index. * * @param idx The index at which the substring should end, exclusive - * @return The subtring from the beginning to the specified index + * @return The substring from the beginning to the specified index */ - (OFString *)substringToIndex: (size_t)idx; /** * @brief Creates a substring with the specified range. @@ -1149,11 +1149,11 @@ * @brief Creates a new string by replacing the occurrences of the specified * string in the specified range with the specified replacement. * * @param string The string to replace * @param replacement The string with which it should be replaced - * @param options Options modifying search behaviour. + * @param options Options modifying search behavior. * Possible values are: * * None yet, pass 0 * @param range The range in which to replace the string * @return A new string with the occurrences of the specified string replaced */ Index: src/OFTCPSocket.h ================================================================== --- src/OFTCPSocket.h +++ src/OFTCPSocket.h @@ -78,11 +78,11 @@ @property (class, nonatomic) uint16_t SOCKS5Port; #endif #if !defined(OF_WII) && !defined(OF_NINTENDO_3DS) /** - * @brief Whether the socket sends keep alives for the connection. + * @brief Whether the socket sends keep-alives for the connection. * * @warning This is not available on the Wii or Nintendo 3DS! * * @throw OFGetOptionFailedException The option could not be retrieved * @throw OFSetOptionFailedException The option could not be set @@ -172,11 +172,12 @@ /** * @brief Asynchronously connects the OFTCPSocket to the specified destination. * * @param host The host to connect to * @param port The port on the host to connect to - * @param runLoopMode The run loop mode in which to perform the async connect + * @param runLoopMode The run loop mode in which to perform the asynchronous + * connect */ - (void)asyncConnectToHost: (OFString *)host port: (uint16_t)port runLoopMode: (OFRunLoopMode)runLoopMode; @@ -195,11 +196,12 @@ /** * @brief Asynchronously connects the OFTCPSocket to the specified destination. * * @param host The host to connect to * @param port The port on the host to connect to - * @param runLoopMode The run loop mode in which to perform the async connect + * @param runLoopMode The run loop mode in which to perform the asynchronous + * connect * @param block The block to execute once the connection has been established */ - (void)asyncConnectToHost: (OFString *)host port: (uint16_t)port runLoopMode: (OFRunLoopMode)runLoopMode ADDED src/OFTXTDNSResourceRecord.h Index: src/OFTXTDNSResourceRecord.h ================================================================== --- src/OFTXTDNSResourceRecord.h +++ src/OFTXTDNSResourceRecord.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2008-2024 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#import "OFDNSResourceRecord.h" + +OF_ASSUME_NONNULL_BEGIN + +/** + * @class OFTXTDNSResourceRecord \ + * OFDNSResourceRecord.h ObjFW/OFDNSResourceRecord.h + * + * @brief A class representing a TXT DNS resource record. + */ +OF_SUBCLASSING_RESTRICTED +@interface OFTXTDNSResourceRecord: OFDNSResourceRecord +{ + OFArray OF_GENERIC(OFData *) *_textStrings; +} + +/** + * @brief The text of the resource record. + */ +@property (readonly, nonatomic) OFArray OF_GENERIC(OFData *) *textStrings; + +- (instancetype)initWithName: (OFString *)name + DNSClass: (OFDNSClass)DNSClass + recordType: (OFDNSRecordType)recordType + TTL: (uint32_t)TTL OF_UNAVAILABLE; + +/** + * @brief Initializes an already allocated OFTXTDNSResourceRecord with the + * specified name, class, text data and time to live. + * + * @param name The name for the resource record + * @param DNSClass The class code for the resource record + * @param textStrings An array of text strings for the resource record + * @param TTL The time to live for the resource record + * @return An initialized OFTXTDNSResourceRecord + */ +- (instancetype)initWithName: (OFString *)name + DNSClass: (OFDNSClass)DNSClass + textStrings: (OFArray OF_GENERIC(OFData *) *)textStrings + TTL: (uint32_t)TTL OF_DESIGNATED_INITIALIZER; +@end + +OF_ASSUME_NONNULL_END ADDED src/OFTXTDNSResourceRecord.m Index: src/OFTXTDNSResourceRecord.m ================================================================== --- src/OFTXTDNSResourceRecord.m +++ src/OFTXTDNSResourceRecord.m @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2008-2024 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#include "config.h" + +#import "OFTXTDNSResourceRecord.h" +#import "OFArray.h" +#import "OFData.h" + +@implementation OFTXTDNSResourceRecord +@synthesize textStrings = _textStrings; + +- (instancetype)initWithName: (OFString *)name + DNSClass: (OFDNSClass)DNSClass + recordType: (OFDNSRecordType)recordType + TTL: (uint32_t)TTL +{ + OF_INVALID_INIT_METHOD +} + +- (instancetype)initWithName: (OFString *)name + DNSClass: (OFDNSClass)DNSClass + textStrings: (OFArray OF_GENERIC(OFData *) *)textStrings + TTL: (uint32_t)TTL +{ + self = [super initWithName: name + DNSClass: DNSClass + recordType: OFDNSRecordTypeTXT + TTL: TTL]; + + @try { + _textStrings = [textStrings copy]; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (void)dealloc +{ + [_textStrings release]; + + [super dealloc]; +} + +- (bool)isEqual: (id)object +{ + OFTXTDNSResourceRecord *record; + + if (object == self) + return true; + + if (![object isKindOfClass: [OFTXTDNSResourceRecord class]]) + return false; + + record = object; + + if (record->_name != _name && ![record->_name isEqual: _name]) + return false; + + if (record->_DNSClass != _DNSClass) + return false; + + if (record->_recordType != _recordType) + return false; + + if (record->_textStrings != _textStrings && + ![record->_textStrings isEqual: _textStrings]) + return false; + + return true; +} + +- (unsigned long)hash +{ + unsigned long hash; + + OFHashInit(&hash); + + OFHashAddHash(&hash, _name.hash); + OFHashAddByte(&hash, _DNSClass >> 8); + OFHashAddByte(&hash, _DNSClass); + OFHashAddByte(&hash, _recordType >> 8); + OFHashAddByte(&hash, _recordType); + OFHashAddHash(&hash, _textStrings.hash); + + OFHashFinalize(&hash); + + return hash; +} + +- (OFString *)description +{ + void *pool = objc_autoreleasePoolPush(); + OFMutableString *text = [OFMutableString string]; + bool first = true; + OFString *ret; + + for (OFData *string in _textStrings) { + const unsigned char *stringItems = string.items; + size_t stringCount = string.count; + + if (first) { + first = false; + [text appendString: @"\""]; + } else + [text appendString: @" \""]; + + for (size_t i = 0; i < stringCount; i++) { + if (stringItems[i] == '\\') + [text appendString: @"\\\\"]; + else if (stringItems[i] == '"') + [text appendString: @"\\\""]; + else if (stringItems[i] < 0x20) + [text appendFormat: @"\\x%02X", stringItems[i]]; + else if (stringItems[i] < 0x7F) + [text appendFormat: @"%c", stringItems[i]]; + else + [text appendFormat: @"\\x%02X", stringItems[i]]; + } + + [text appendString: @"\""]; + } + + ret = [OFString stringWithFormat: + @"<%@:\n" + @"\tName = %@\n" + @"\tClass = %@\n" + @"\tText strings = %@\n" + @"\tTTL = %" PRIu32 "\n" + @">", + self.className, _name, OFDNSClassName(_DNSClass), text, _TTL]; + + [ret retain]; + + objc_autoreleasePoolPop(pool); + + return [ret autorelease]; +} +@end Index: src/OFThread.h ================================================================== --- src/OFThread.h +++ src/OFThread.h @@ -293,11 +293,11 @@ /** * @brief This routine is executed when the thread's main method has finished * executing or terminate has been called. * - * @note Be sure to call [super handleTermination]! + * @note Be sure to call `[super handleTermination]`! */ - (void)handleTermination OF_REQUIRES_SUPER; /** * @brief Starts the thread. ADDED src/OFURIDNSResourceRecord.h Index: src/OFURIDNSResourceRecord.h ================================================================== --- src/OFURIDNSResourceRecord.h +++ src/OFURIDNSResourceRecord.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2008-2024 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#import "OFDNSResourceRecord.h" + +OF_ASSUME_NONNULL_BEGIN + +/** + * @class OFURIDNSResourceRecord \ + * OFDNSResourceRecord.h ObjFW/OFDNSResourceRecord.h + * + * @brief A class representing an URI DNS resource record. + */ +OF_SUBCLASSING_RESTRICTED +@interface OFURIDNSResourceRecord: OFDNSResourceRecord +{ + uint16_t _priority, _weight; + OFString *_target; +} + +/** + * @brief The priority of the resource record. + */ +@property (readonly, nonatomic) uint16_t priority; + +/** + * @brief The weight of the resource record. + */ +@property (readonly, nonatomic) uint16_t weight; + +/** + * @brief The target of the resource record. + */ +@property (readonly, nonatomic) OFString *target; + +- (instancetype)initWithName: (OFString *)name + DNSClass: (OFDNSClass)DNSClass + recordType: (OFDNSRecordType)recordType + TTL: (uint32_t)TTL OF_UNAVAILABLE; + +/** + * @brief Initializes an already allocated OFURIDNSResourceRecord with the + * specified name, class, priority, weight, target and time to live. + * + * @param name The name for the resource record + * @param DNSClass The class code for the resource record + * @param priority The priority for the resource record + * @param weight The weight for the resource record + * @param target The target for the resource record + * @param TTL The time to live for the resource record + * @return An initialized OFURIDNSResourceRecord + */ +- (instancetype)initWithName: (OFString *)name + DNSClass: (OFDNSClass)DNSClass + priority: (uint16_t)priority + weight: (uint16_t)weight + target: (OFString *)target + TTL: (uint32_t)TTL OF_DESIGNATED_INITIALIZER; +@end + +OF_ASSUME_NONNULL_END ADDED src/OFURIDNSResourceRecord.m Index: src/OFURIDNSResourceRecord.m ================================================================== --- src/OFURIDNSResourceRecord.m +++ src/OFURIDNSResourceRecord.m @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2008-2024 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#include "config.h" + +#import "OFURIDNSResourceRecord.h" + +@implementation OFURIDNSResourceRecord +@synthesize priority = _priority, weight = _weight, target = _target; + +- (instancetype)initWithName: (OFString *)name + DNSClass: (OFDNSClass)DNSClass + recordType: (OFDNSRecordType)recordType + TTL: (uint32_t)TTL +{ + OF_INVALID_INIT_METHOD +} + +- (instancetype)initWithName: (OFString *)name + DNSClass: (OFDNSClass)DNSClass + priority: (uint16_t)priority + weight: (uint16_t)weight + target: (OFString *)target + TTL: (uint32_t)TTL +{ + self = [super initWithName: name + DNSClass: DNSClass + recordType: OFDNSRecordTypeURI + TTL: TTL]; + + @try { + _priority = priority; + _weight = weight; + _target = [target copy]; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (void)dealloc +{ + [_target release]; + + [super dealloc]; +} + +- (bool)isEqual: (id)object +{ + OFURIDNSResourceRecord *record; + + if (object == self) + return true; + + if (![object isKindOfClass: [OFURIDNSResourceRecord class]]) + return false; + + record = object; + + if (record->_name != _name && ![record->_name isEqual: _name]) + return false; + + if (record->_DNSClass != _DNSClass) + return false; + + if (record->_recordType != _recordType) + return false; + + if (record->_priority != _priority) + return false; + + if (record->_weight != _weight) + return false; + + if (record->_target != _target && ![record->_target isEqual: _target]) + return false; + + return true; +} + +- (unsigned long)hash +{ + unsigned long hash; + + OFHashInit(&hash); + + OFHashAddHash(&hash, _name.hash); + OFHashAddByte(&hash, _DNSClass >> 8); + OFHashAddByte(&hash, _DNSClass); + OFHashAddByte(&hash, _recordType >> 8); + OFHashAddByte(&hash, _recordType); + OFHashAddByte(&hash, _priority >> 8); + OFHashAddByte(&hash, _priority); + OFHashAddByte(&hash, _weight >> 8); + OFHashAddByte(&hash, _weight); + OFHashAddHash(&hash, _target.hash); + + OFHashFinalize(&hash); + + return hash; +} + +- (OFString *)description +{ + return [OFString stringWithFormat: + @"<%@:\n" + @"\tName = %@\n" + @"\tClass = %@\n" + @"\tPriority = %" PRIu16 "\n" + @"\tWeight = %" PRIu16 "\n" + @"\tTarget = %@\n" + @"\tTTL = %" PRIu32 "\n" + @">", + self.className, _name, OFDNSClassName(_DNSClass), _priority, + _weight, _target, _TTL]; +} +@end Index: src/OFXMLElement.h ================================================================== --- src/OFXMLElement.h +++ src/OFXMLElement.h @@ -60,11 +60,11 @@ */ @property OF_NULLABLE_PROPERTY (readonly, nonatomic) OFArray OF_GENERIC(OFXMLAttribute *) *attributes; /** - * @brief An array of OFXMLNodes with all children of the element. + * @brief An array of @ref OFXMLNode with all children of the element. */ @property OF_NULLABLE_PROPERTY (nonatomic, copy) OFArray OF_GENERIC(OFXMLNode *) *children; /** @@ -319,11 +319,11 @@ - (void)insertChild: (OFXMLNode *)child atIndex: (size_t)index; /** * @brief Inserts the specified children at the specified index. * - * @param children An array of OFXMLNodes which are added as children + * @param children An array of @ref OFXMLNode which are added as children * @param index The index where the child is added */ - (void)insertChildren: (OFArray OF_GENERIC(OFXMLNode *) *)children atIndex: (size_t)index; Index: src/OFZIPArchiveEntry.h ================================================================== --- src/OFZIPArchiveEntry.h +++ src/OFZIPArchiveEntry.h @@ -196,11 +196,11 @@ * @return The ZIP entry version as a string */ extern OFString *OFZIPArchiveEntryVersionToString(uint16_t version); /** - * @brief Convers the ZIP entry compression method to a string. + * @brief Converts the ZIP entry compression method to a string. * * @param compressionMethod The ZIP entry compression method to convert to a * string * @return The ZIP entry compression method as a string */ Index: src/bridge/Makefile ================================================================== --- src/bridge/Makefile +++ src/bridge/Makefile @@ -39,9 +39,9 @@ includesubdir = ObjFWBridge include ../../buildsys.mk -CPPFLAGS += -I. -I.. -I../.. -I../exceptions -DOF_BRIDGE_LOCAL_INCLUDES +CPPFLAGS += -I. -I.. -I../.. -I../exceptions -DOBJFWBRIDGE_LOCAL_INCLUDES LD = ${OBJC} FRAMEWORK_LIBS := -framework Foundation -F.. -framework ObjFW ${LIBS} LIBS := -framework Foundation -L.. -lobjfw ${LIBS} Index: src/bridge/NSBridging.h ================================================================== --- src/bridge/NSBridging.h +++ src/bridge/NSBridging.h @@ -11,11 +11,11 @@ * Public License, either version 2 or 3, which can be found in the file * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ -#ifdef OF_BRIDGE_LOCAL_INCLUDES +#ifdef OBJFWBRIDGE_LOCAL_INCLUDES # import "macros.h" #else # if defined(__has_feature) && __has_feature(modules) @import ObjFW; # else Index: src/bridge/OFArray+NSObject.h ================================================================== --- src/bridge/OFArray+NSObject.h +++ src/bridge/OFArray+NSObject.h @@ -11,11 +11,11 @@ * Public License, either version 2 or 3, which can be found in the file * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ -#ifdef OF_BRIDGE_LOCAL_INCLUDES +#ifdef OBJFWBRIDGE_LOCAL_INCLUDES # import "OFArray.h" #else # if defined(__has_feature) && __has_feature(modules) @import ObjFW; # else Index: src/bridge/OFBridging.h ================================================================== --- src/bridge/OFBridging.h +++ src/bridge/OFBridging.h @@ -11,11 +11,11 @@ * Public License, either version 2 or 3, which can be found in the file * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ -#ifdef OF_BRIDGE_LOCAL_INCLUDES +#ifdef OBJFWBRIDGE_LOCAL_INCLUDES # import "macros.h" #else # if defined(__has_feature) && __has_feature(modules) @import ObjFW; # else Index: src/bridge/OFDictionary+NSObject.h ================================================================== --- src/bridge/OFDictionary+NSObject.h +++ src/bridge/OFDictionary+NSObject.h @@ -11,11 +11,11 @@ * Public License, either version 2 or 3, which can be found in the file * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ -#ifdef OF_BRIDGE_LOCAL_INCLUDES +#ifdef OBJFWBRIDGE_LOCAL_INCLUDES # import "OFDictionary.h" #else # if defined(__has_feature) && __has_feature(modules) @import ObjFW; # else Index: src/bridge/OFEnumerator+NSObject.h ================================================================== --- src/bridge/OFEnumerator+NSObject.h +++ src/bridge/OFEnumerator+NSObject.h @@ -11,11 +11,11 @@ * Public License, either version 2 or 3, which can be found in the file * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ -#ifdef OF_BRIDGE_LOCAL_INCLUDES +#ifdef OBJFWBRIDGE_LOCAL_INCLUDES # import "OFEnumerator.h" #else # if defined(__has_feature) && __has_feature(modules) @import ObjFW; # else Index: src/bridge/OFException+Swift.h ================================================================== --- src/bridge/OFException+Swift.h +++ src/bridge/OFException+Swift.h @@ -11,11 +11,11 @@ * Public License, either version 2 or 3, which can be found in the file * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ -#ifdef OF_BRIDGE_LOCAL_INCLUDES +#ifdef OBJFWBRIDGE_LOCAL_INCLUDES # import "OFException.h" #else # if defined(__has_feature) && __has_feature(modules) @import ObjFW; # else Index: src/bridge/OFNSArray.h ================================================================== --- src/bridge/OFNSArray.h +++ src/bridge/OFNSArray.h @@ -11,11 +11,11 @@ * Public License, either version 2 or 3, which can be found in the file * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ -#ifdef OF_BRIDGE_LOCAL_INCLUDES +#ifdef OBJFWBRIDGE_LOCAL_INCLUDES # import "OFArray.h" #else # if defined(__has_feature) && __has_feature(modules) @import ObjFW; # else Index: src/bridge/OFNSDictionary.h ================================================================== --- src/bridge/OFNSDictionary.h +++ src/bridge/OFNSDictionary.h @@ -11,11 +11,11 @@ * Public License, either version 2 or 3, which can be found in the file * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ -#ifdef OF_BRIDGE_LOCAL_INCLUDES +#ifdef OBJFWBRIDGE_LOCAL_INCLUDES # import "OFDictionary.h" #else # if defined(__has_feature) && __has_feature(modules) @import ObjFW; # else Index: src/bridge/OFNSEnumerator.h ================================================================== --- src/bridge/OFNSEnumerator.h +++ src/bridge/OFNSEnumerator.h @@ -11,11 +11,11 @@ * Public License, either version 2 or 3, which can be found in the file * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ -#ifdef OF_BRIDGE_LOCAL_INCLUDES +#ifdef OBJFWBRIDGE_LOCAL_INCLUDES # import "OFEnumerator.h" #else # if defined(__has_feature) && __has_feature(modules) @import ObjFW; # else Index: src/bridge/OFNSSet.h ================================================================== --- src/bridge/OFNSSet.h +++ src/bridge/OFNSSet.h @@ -11,11 +11,11 @@ * Public License, either version 2 or 3, which can be found in the file * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ -#ifdef OF_BRIDGE_LOCAL_INCLUDES +#ifdef OBJFWBRIDGE_LOCAL_INCLUDES # import "OFSet.h" #else # if defined(__has_feature) && __has_feature(modules) @import ObjFW; # else Index: src/bridge/OFNumber+NSObject.h ================================================================== --- src/bridge/OFNumber+NSObject.h +++ src/bridge/OFNumber+NSObject.h @@ -11,11 +11,11 @@ * Public License, either version 2 or 3, which can be found in the file * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ -#ifdef OF_BRIDGE_LOCAL_INCLUDES +#ifdef OBJFWBRIDGE_LOCAL_INCLUDES # import "OFNumber.h" #else # if defined(__has_feature) && __has_feature(modules) @import ObjFW; # else Index: src/bridge/OFSet+NSObject.h ================================================================== --- src/bridge/OFSet+NSObject.h +++ src/bridge/OFSet+NSObject.h @@ -11,11 +11,11 @@ * Public License, either version 2 or 3, which can be found in the file * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ -#ifdef OF_BRIDGE_LOCAL_INCLUDES +#ifdef OBJFWBRIDGE_LOCAL_INCLUDES # import "OFSet.h" #else # if defined(__has_feature) && __has_feature(modules) @import ObjFW; # else Index: src/bridge/OFString+NSObject.h ================================================================== --- src/bridge/OFString+NSObject.h +++ src/bridge/OFString+NSObject.h @@ -11,11 +11,11 @@ * Public License, either version 2 or 3, which can be found in the file * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ -#ifdef OF_BRIDGE_LOCAL_INCLUDES +#ifdef OBJFWBRIDGE_LOCAL_INCLUDES # import "OFString.h" #else # if defined(__has_feature) && __has_feature(modules) @import ObjFW; # else Index: src/exceptions/OFCreateSymbolicLinkFailedException.h ================================================================== --- src/exceptions/OFCreateSymbolicLinkFailedException.h +++ src/exceptions/OFCreateSymbolicLinkFailedException.h @@ -33,16 +33,16 @@ int _errNo; OF_RESERVE_IVARS(OFCreateSymbolicLinkFailedException, 4) } /** - * @brief The IRI at which the symlink should have been created. + * @brief The IRI at which the symbolic link should have been created. */ @property (readonly, nonatomic) OFIRI *IRI; /** - * @brief The target for the symlink. + * @brief The target for the symbolic link. */ @property (readonly, nonatomic) OFString *target; /** * @brief The errno of the error that occurred. @@ -50,11 +50,11 @@ @property (readonly, nonatomic) int errNo; /** * @brief Creates a new, autoreleased create symbolic link failed exception. * - * @param IRI The IRI where the symlink should have been created + * @param IRI The IRI where the symbolic link should have been created * @param target The target for the symbolic link * @param errNo The errno of the error that occurred * @return A new, autoreleased create symbolic link failed exception */ + (instancetype)exceptionWithIRI: (OFIRI *)IRI @@ -65,11 +65,11 @@ /** * @brief Initializes an already allocated create symbolic link failed * exception. * - * @param IRI The IRI where the symlink should have been created + * @param IRI The IRI where the symbolic link should have been created * @param target The target for the symbolic link * @param errNo The errno of the error that occurred * @return An initialized create symbolic link failed exception */ - (instancetype)initWithIRI: (OFIRI *)IRI Index: src/platform/POSIX/OFSubprocess.m ================================================================== --- src/platform/POSIX/OFSubprocess.m +++ src/platform/POSIX/OFSubprocess.m @@ -39,12 +39,15 @@ #import "OFNotOpenException.h" #import "OFOutOfRangeException.h" #import "OFReadFailedException.h" #import "OFWriteFailedException.h" -#if !defined(HAVE_POSIX_SPAWNP) || !defined(HAVE_SPAWN_H) +#ifndef OF_MACOS extern char **environ; +#else +# include +# define environ (*_NSGetEnviron()) #endif @interface OFSubprocess () - (void)of_getArgv: (char ***)argv forProgramName: (OFString *)programName @@ -176,20 +179,21 @@ @throw [OFInitializationFailedException exceptionWithClass: self.class]; # endif if (posix_spawnp(&_pid, path, &actions, &attr, - argv, env) != 0) + argv, (env != NULL ? env : environ)) != 0) @throw [OFInitializationFailedException exceptionWithClass: self.class]; } @finally { posix_spawn_file_actions_destroy(&actions); posix_spawnattr_destroy(&attr); } #else if ((_pid = vfork()) == 0) { - environ = env; + if (env != NULL) + environ = env; close(_readPipe[0]); close(_writePipe[1]); dup2(_writePipe[0], 0); dup2(_readPipe[1], 1); @@ -374,11 +378,13 @@ - (void)close { if (_readPipe[0] == -1) @throw [OFNotOpenException exceptionWithObject: self]; - [self closeForWriting]; + if (_writePipe[1] != -1) + [self closeForWriting]; + close(_readPipe[0]); if (_pid != -1) { kill(_pid, SIGTERM); waitpid(_pid, &_status, WNOHANG); Index: src/platform/Windows/OFSubprocess.m ================================================================== --- src/platform/Windows/OFSubprocess.m +++ src/platform/Windows/OFSubprocess.m @@ -381,11 +381,13 @@ - (void)close { if (_readPipe[0] == NULL) @throw [OFNotOpenException exceptionWithObject: self]; - [self closeForWriting]; + if (_writePipe[1] != NULL) + [self closeForWriting]; + CloseHandle(_readPipe[0]); if (_handle != INVALID_HANDLE_VALUE) { TerminateProcess(_handle, 0); CloseHandle(_handle); Index: src/platform/Windows/OFSystemInfo+NetworkInterfaces.m ================================================================== --- src/platform/Windows/OFSystemInfo+NetworkInterfaces.m +++ src/platform/Windows/OFSystemInfo+NetworkInterfaces.m @@ -40,11 +40,10 @@ if ((module = GetModuleHandle("iphlpapi.dll")) != NULL) GetAdaptersAddressesFuncPtr = (WINAPI ULONG (*)(ULONG, ULONG, PVOID, PIP_ADAPTER_ADDRESSES, PULONG)) GetProcAddress(module, "GetAdaptersAddresses"); - } static OFMutableDictionary OF_GENERIC(OFString *, OFNetworkInterface) * networkInterfacesFromGetAdaptersAddresses(void) { @@ -54,10 +53,11 @@ if ((adapterAddresses = malloc(adapterAddressesSize)) == NULL) return nil; @try { + OFStringEncoding encoding = [OFLocale encoding]; ULONG error = GetAdaptersAddressesFuncPtr(AF_UNSPEC, 0, NULL, adapterAddresses, &adapterAddressesSize); if (error == ERROR_BUFFER_OVERFLOW) { PIP_ADAPTER_ADDRESSES newAdapterAddresses = @@ -78,12 +78,12 @@ iter != NULL; iter = iter->Next) { OFString *name; OFMutableDictionary *interface; OFNumber *index; - name = [OFString stringWithFormat: @"%lu", - iter->IfIndex]; + name = [OFString stringWithCString: iter->AdapterName + encoding: encoding]; if ((interface = [ret objectForKey: name]) == nil) { interface = [OFMutableDictionary dictionary]; [ret setObject: interface forKey: name]; } @@ -99,11 +99,11 @@ dataWithItems: iter->PhysicalAddress count: iter->PhysicalAddressLength]; [interface setObject: address forKey: key]; } - for (PIP_ADAPTER_UNICAST_ADDRESS_LH addrIter = + for (__typeof__(iter->FirstUnicastAddress) addrIter = iter->FirstUnicastAddress; addrIter != NULL; addrIter = addrIter->Next) { OFSocketAddress address; int length; OFNetworkInterfaceKey key; Index: src/runtime/Makefile ================================================================== --- src/runtime/Makefile +++ src/runtime/Makefile @@ -9,10 +9,11 @@ LIB_MAJOR = ${OBJFWRT_LIB_MAJOR} LIB_MINOR = ${OBJFWRT_LIB_MINOR} LIB_PATCH = ${OBJFWRT_LIB_PATCH} SRCS = arc.m \ + association.m \ autorelease.m \ category.m \ class.m \ dtable.m \ exception.m \ Index: src/runtime/ObjFWRT.h ================================================================== --- src/runtime/ObjFWRT.h +++ src/runtime/ObjFWRT.h @@ -132,11 +132,11 @@ */ typedef bool BOOL; #endif /** - * @brief A method implemenation. + * @brief A method implementation. * * @param object The messaged object * @param selector The selector sent */ typedef id _Nullable (*IMP)(id _Nonnull object, SEL _Nonnull selector, ...); @@ -171,10 +171,26 @@ #else Class _Nonnull class; #endif }; +/** + * @brief A policy for object association, see @ref objc_setAssociatedObject. + */ +typedef enum objc_associationPolicy { + /** @brief Associate the object like an assigned property. */ + OBJC_ASSOCIATION_ASSIGN = 0, + /** @brief Associate the object like a retained, nonatomic property. */ + OBJC_ASSOCIATION_RETAIN_NONATOMIC = 1, + /** @brief Associate the object like a retained property. */ + OBJC_ASSOCIATION_RETAIN = OBJC_ASSOCIATION_RETAIN_NONATOMIC | 0x300, + /** @brief Associate the object like a copied, nonatomic property. */ + OBJC_ASSOCIATION_COPY_NONATOMIC = 3, + /** @brief Associate the object like a copied property. */ + OBJC_ASSOCIATION_COPY = OBJC_ASSOCIATION_COPY_NONATOMIC | 0x300 +} objc_associationPolicy; + #ifdef __cplusplus extern "C" { #endif /** @@ -310,11 +326,11 @@ * ABI, small structs might not use the struct return ABI. * * @param class_ The class whose method implementation should be returned * @param selector The selector for the method whose implementation should be * returned - * @return The class's metod implementation for the specified selector + * @return The class's method implementation for the specified selector */ extern IMP _Nullable class_getMethodImplementation(Class _Nullable class_, SEL _Nonnull selector); /** @@ -325,11 +341,11 @@ * ABI, small structs might not use the struct return ABI. * * @param class_ The class whose method implementation should be returned * @param selector The selector for the method whose implementation should be * returned - * @return The class's metod implementation for the specified selector + * @return The class's method implementation for the specified selector */ extern IMP _Nullable class_getMethodImplementation_stret(Class _Nullable class_, SEL _Nonnull selector); /** @@ -644,10 +660,41 @@ * @param value The value the tagged pointer should have * @return A tagged pointer, or `nil` if it could not be created */ extern id _Nullable objc_createTaggedPointer(int class_, uintptr_t value); +/** + * @brief Sets an associated object on the specified object for the specified + * key. + * + * @param object The object on which to set an associated object + * @param key A unique pointer to use as the key for the association + * @param value The object to associate with the specified object + * @param policy The association policy, see @ref objc_associationPolicy + */ +extern void objc_setAssociatedObject(id _Nonnull object, + const void *_Nonnull key, id _Nullable value, + objc_associationPolicy policy); + +/** + * @brief Returns the associated object on the specified object for the + * specified key. + * + * @param object The object on which to get the associated object + * @param key The key of the association + * @return The associated object on the specified object for the specified key + */ +extern id _Nullable objc_getAssociatedObject(id _Nonnull object, + const void *_Nonnull key); + +/** + * @brief Removes all associated objects for the specified object. + * + * @param object The object on which to remove all associated objects + */ +extern void objc_removeAssociatedObjects(id _Nonnull object); + /* * Used by the compiler, but can also be called manually. * * These declarations are also required to prevent Clang's implicit * declarations which include __declspec(dllimport) on Windows. ADDED src/runtime/association.m Index: src/runtime/association.m ================================================================== --- src/runtime/association.m +++ src/runtime/association.m @@ -0,0 +1,219 @@ +/* + * Copyright (c) 2008-2024 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#include "config.h" + +#import "ObjFWRT.h" +#import "private.h" + +#ifdef OF_HAVE_THREADS +# import "OFPlainMutex.h" +# define numSpinlocks 8 /* needs to be a power of 2 */ +static OFSpinlock spinlocks[numSpinlocks]; + +static OF_INLINE size_t +spinlockSlot(id object) +{ + return ((size_t)((uintptr_t)object >> 4) & (numSpinlocks - 1)); +} +#endif + +struct Association { + id object; + objc_associationPolicy policy; +}; + +static struct objc_hashtable *hashtable; + +static uint32_t +hash(const void *object) +{ + return (uint32_t)(uintptr_t)object; +} + +static bool +equal(const void *object1, const void *object2) +{ + return (object1 == object2); +} + +OF_CONSTRUCTOR() +{ + hashtable = objc_hashtable_new(hash, equal, 2); + +#ifdef OF_HAVE_THREADS + for (size_t i = 0; i < numSpinlocks; i++) + if (OFSpinlockNew(&spinlocks[i]) != 0) + OBJC_ERROR("Failed to create spinlocks!"); +#endif +} + +void +objc_setAssociatedObject(id object, const void *key, id value, + objc_associationPolicy policy) +{ +#ifdef OF_HAVE_THREADS + size_t slot; +#endif + + switch (policy) { + case OBJC_ASSOCIATION_ASSIGN: + break; + case OBJC_ASSOCIATION_RETAIN: + case OBJC_ASSOCIATION_RETAIN_NONATOMIC: + value = [value retain]; + break; + case OBJC_ASSOCIATION_COPY: + case OBJC_ASSOCIATION_COPY_NONATOMIC: + value = [value copy]; + break; + default: + /* Don't know what to do, so do nothing. */ + return; + } + +#ifdef OF_HAVE_THREADS + slot = spinlockSlot(object); + + if (OFSpinlockLock(&spinlocks[slot]) != 0) + OBJC_ERROR("Failed to lock spinlock!"); + + @try { +#endif + struct objc_hashtable *objectHashtable; + struct Association *association; + + objectHashtable = objc_hashtable_get(hashtable, object); + if (objectHashtable == NULL) { + objectHashtable = objc_hashtable_new(hash, equal, 2); + objc_hashtable_set(hashtable, object, objectHashtable); + } + + association = objc_hashtable_get(objectHashtable, key); + if (association != NULL) { + switch (association->policy) { + case OBJC_ASSOCIATION_RETAIN: + case OBJC_ASSOCIATION_RETAIN_NONATOMIC: + case OBJC_ASSOCIATION_COPY: + case OBJC_ASSOCIATION_COPY_NONATOMIC: + [association->object release]; + break; + default: + break; + } + } else { + association = malloc(sizeof(*association)); + if (association == NULL) + OBJC_ERROR("Failed to allocate association!"); + + objc_hashtable_set(objectHashtable, key, association); + } + + association->policy = policy; + association->object = value; +#ifdef OF_HAVE_THREADS + } @finally { + if (OFSpinlockUnlock(&spinlocks[slot]) != 0) + OBJC_ERROR("Failed to unlock spinlock!"); + } +#endif +} + +id +objc_getAssociatedObject(id object, const void *key) +{ +#ifdef OF_HAVE_THREADS + size_t slot = spinlockSlot(object); + + if (OFSpinlockLock(&spinlocks[slot]) != 0) + OBJC_ERROR("Failed to lock spinlock!"); + + @try { +#endif + struct objc_hashtable *objectHashtable; + struct Association *association; + + objectHashtable = objc_hashtable_get(hashtable, object); + if (objectHashtable == NULL) + return nil; + + association = objc_hashtable_get(objectHashtable, key); + if (association == NULL) + return nil; + + switch (association->policy) { + case OBJC_ASSOCIATION_RETAIN: + case OBJC_ASSOCIATION_COPY: + return [[association->object retain] autorelease]; + default: + return association->object; + } +#ifdef OF_HAVE_THREADS + } @finally { + if (OFSpinlockUnlock(&spinlocks[slot]) != 0) + OBJC_ERROR("Failed to unlock spinlock!"); + } +#endif +} + +void +objc_removeAssociatedObjects(id object) +{ +#ifdef OF_HAVE_THREADS + size_t slot = spinlockSlot(object); + + if (OFSpinlockLock(&spinlocks[slot]) != 0) + OBJC_ERROR("Failed to lock spinlock!"); + + @try { +#endif + struct objc_hashtable *objectHashtable; + + objectHashtable = objc_hashtable_get(hashtable, object); + if (objectHashtable == NULL) + return; + + for (uint32_t i = 0; i < objectHashtable->size; i++) { + struct Association *association; + + if (objectHashtable->data[i] == NULL || + objectHashtable->data[i] == &objc_deletedBucket) + continue; + + association = (struct Association *) + objectHashtable->data[i]->object; + + switch (association->policy) { + case OBJC_ASSOCIATION_RETAIN: + case OBJC_ASSOCIATION_RETAIN_NONATOMIC: + case OBJC_ASSOCIATION_COPY: + case OBJC_ASSOCIATION_COPY_NONATOMIC: + [association->object release]; + break; + default: + break; + } + + free(association); + } + + objc_hashtable_delete(hashtable, object); +#ifdef OF_HAVE_THREADS + } @finally { + if (OFSpinlockUnlock(&spinlocks[slot]) != 0) + OBJC_ERROR("Failed to unlock spinlock!"); + } +#endif +} Index: src/runtime/class.m ================================================================== --- src/runtime/class.m +++ src/runtime/class.m @@ -601,11 +601,12 @@ if (j >= count) { objc_globalMutex_unlock(); return j; } - if (classes->data[i] == NULL) + if (classes->data[i] == NULL || + classes->data[i] == &objc_deletedBucket) continue; if (strcmp(classes->data[i]->key, "Protocol") == 0) continue; Index: src/runtime/instance.m ================================================================== --- src/runtime/instance.m +++ src/runtime/instance.m @@ -99,8 +99,10 @@ last = destruct; } else break; } + + objc_removeAssociatedObjects(object); return object; } Index: src/runtime/property.m ================================================================== --- src/runtime/property.m +++ src/runtime/property.m @@ -28,13 +28,11 @@ static OF_INLINE size_t spinlockSlot(const void *ptr) { return ((size_t)((uintptr_t)ptr >> 4) & (numSpinlocks - 1)); } -#endif -#ifdef OF_HAVE_THREADS OF_CONSTRUCTOR() { for (size_t i = 0; i < numSpinlocks; i++) if (OFSpinlockNew(&spinlocks[i]) != 0) OBJC_ERROR("Failed to create spinlocks!"); ADDED src/test/Makefile Index: src/test/Makefile ================================================================== --- src/test/Makefile +++ src/test/Makefile @@ -0,0 +1,50 @@ +include ../../extra.mk + +DISTCLEAN = Info.plist + +STATIC_LIB = libobjfwtest.a + +SRCS = OTAssert.m \ + OTTestCase.m +INCLUDES := ${SRCS:.m=.h} \ + ObjFWTest.h +SRCS += OTAppDelegate.m \ + OTAssertionFailedException.m + +includesubdir = ObjFWTest + +include ../../buildsys.mk + +CPPFLAGS += -I. \ + -I.. \ + -I../.. \ + -I../exceptions \ + -I../runtime \ + -DOBJFWTEST_LOCAL_INCLUDES +LD = ${OBJC} +FRAMEWORK_LIBS := -F.. \ + -framework ObjFW \ + -F../runtime \ + ${RUNTIME_FRAMEWORK_LIBS} \ + ${LIBS} +LIBS := -L.. -lobjfw -L../runtime ${RUNTIME_LIBS} ${LIBS} + +install-extra: + i=ObjFWTest.oc; \ + ${INSTALL_STATUS}; \ + if ${MKDIR_P} ${libdir}/objfw-config && ${INSTALL} -m 644 $$i ${libdir}/objfw-config/$$i; then \ + ${INSTALL_OK}; \ + else \ + ${INSTALL_FAILED}; \ + fi + +uninstall-extra: + i=ObjFWTest.oc; \ + if test -f ${libdir}/objfw-config/$$i; then \ + if rm -f ${libdir}/objfw-config/$$i; then \ + ${DELETE_OK}; \ + else \ + ${DELETE_FAILED}; \ + fi \ + fi; \ + rmdir ${libdir}/objfw-config >/dev/null 2>&1 || true ADDED src/test/OTAppDelegate.h Index: src/test/OTAppDelegate.h ================================================================== --- src/test/OTAppDelegate.h +++ src/test/OTAppDelegate.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2008-2024 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#import "OFApplication.h" + +OF_ASSUME_NONNULL_BEGIN + +@interface OTAppDelegate: OFObject +@end + +OF_ASSUME_NONNULL_END ADDED src/test/OTAppDelegate.m Index: src/test/OTAppDelegate.m ================================================================== --- src/test/OTAppDelegate.m +++ src/test/OTAppDelegate.m @@ -0,0 +1,250 @@ +/* + * Copyright (c) 2008-2024 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#include "config.h" + +#import "OTAppDelegate.h" + +#import "OFColor.h" +#import "OFMethodSignature.h" +#import "OFSet.h" +#import "OFStdIOStream.h" +#import "OFValue.h" + +#import "OTTestCase.h" + +#import "OTAssertionFailedException.h" + +OF_APPLICATION_DELEGATE(OTAppDelegate) + +static bool +isSubclassOfClass(Class class, Class superclass) +{ + for (Class iter = class; iter != Nil; iter = class_getSuperclass(iter)) + if (iter == superclass) + return true; + + return false; +} + +@implementation OTAppDelegate +- (OFSet OF_GENERIC(Class) *)testClasses +{ + Class *classes = objc_copyClassList(NULL); + OFMutableSet *testClasses; + + if (classes == NULL) + return nil; + + @try { + testClasses = [OFMutableSet set]; + + for (Class *iter = classes; *iter != Nil; iter++) { + /* + * Make sure the class is initialized. + * Required for the ObjFW runtime, as otherwise + * class_getSuperclass() crashes. + */ + [*iter class]; + + /* + * Don't use +[isSubclassOfClass:], as the Apple runtime + * can return (presumably internal?) classes that don't + * implement it, resulting in a crash. + */ + if (isSubclassOfClass(*iter, [OTTestCase class])) + [testClasses addObject: *iter]; + } + } @finally { + OFFreeMemory(classes); + } + + [testClasses removeObject: [OTTestCase class]]; + + [testClasses makeImmutable]; + return testClasses; +} + +- (OFSet OF_GENERIC(OFValue *) *)testsInClass: (Class)class +{ + Method *methods = class_copyMethodList(class, NULL); + OFMutableSet *tests; + + if (methods == NULL) + return nil; + + @try { + tests = [OFMutableSet set]; + + for (Method *iter = methods; *iter != NULL; iter++) { + SEL selector = method_getName(*iter); + void *pool; + OFMethodSignature *sig; + + if (selector == NULL) + continue; + + if (strncmp(sel_getName(selector), "test", 4) != 0) + continue; + + pool = objc_autoreleasePoolPush(); + sig = [OFMethodSignature signatureWithObjCTypes: + method_getTypeEncoding(*iter)]; + + if (strcmp(sig.methodReturnType, "v") == 0 && + sig.numberOfArguments == 2 && + strcmp([sig argumentTypeAtIndex: 0], "@") == 0 && + strcmp([sig argumentTypeAtIndex: 1], ":") == 0) + [tests addObject: + [OFValue valueWithPointer: selector]]; + + objc_autoreleasePoolPop(pool); + } + } @finally { + OFFreeMemory(methods); + } + + if (class_getSuperclass(class) != Nil) + [tests unionSet: + [self testsInClass: class_getSuperclass(class)]]; + + [tests makeImmutable]; + return tests; +} + +- (void)printStatusForTest: (SEL)test + inClass: (Class)class + status: (int)status + description: (OFString *)description +{ + switch (status) { + case 0: + [OFStdOut setForegroundColor: [OFColor olive]]; + [OFStdOut writeFormat: @"-[%@ ", class]; + [OFStdOut setForegroundColor: [OFColor yellow]]; + [OFStdOut writeFormat: @"%s", sel_getName(test)]; + [OFStdOut setForegroundColor: [OFColor olive]]; + [OFStdOut writeString: @"]: "]; + break; + case 1: + [OFStdOut setForegroundColor: [OFColor green]]; + [OFStdOut writeFormat: @"\r-[%@ ", class]; + [OFStdOut setForegroundColor: [OFColor lime]]; + [OFStdOut writeFormat: @"%s", sel_getName(test)]; + [OFStdOut setForegroundColor: [OFColor green]]; + [OFStdOut writeLine: @"]: ok"]; + break; + case 2: + [OFStdOut setForegroundColor: [OFColor maroon]]; + [OFStdOut writeFormat: @"\r-[%@ ", class]; + [OFStdOut setForegroundColor: [OFColor red]]; + [OFStdOut writeFormat: @"%s", sel_getName(test)]; + [OFStdOut setForegroundColor: [OFColor maroon]]; + [OFStdOut writeLine: @"]: failed"]; + [OFStdOut writeLine: description]; + break; + } + + [OFStdOut reset]; +} + +- (void)applicationDidFinishLaunching: (OFNotification *)notification +{ + OFSet OF_GENERIC(Class) *testClasses = [self testClasses]; + size_t numSucceeded = 0, numFailed = 0; + + [OFStdOut writeFormat: @"Running %zu test case(s)\n", + testClasses.count]; + + for (Class class in testClasses) { + [OFStdOut setForegroundColor: [OFColor teal]]; + [OFStdOut writeFormat: @"Running ", class]; + [OFStdOut setForegroundColor: [OFColor aqua]]; + [OFStdOut writeFormat: @"%@\n", class]; + [OFStdOut reset]; + + for (OFValue *test in [self testsInClass: class]) { + void *pool = objc_autoreleasePoolPush(); + bool failed = false; + OTTestCase *instance; + + [self printStatusForTest: test.pointerValue + inClass: class + status: 0 + description: nil]; + + instance = [[[class alloc] init] autorelease]; + + @try { + [instance setUp]; + [instance performSelector: test.pointerValue]; + } @catch (OTAssertionFailedException *e) { + /* + * If an assertion fails during -[setUp], don't + * run the test. + * If an assertion fails during a test, abort + * the test. + */ + [self printStatusForTest: test.pointerValue + inClass: class + status: 2 + description: e.description]; + failed = true; + } + @try { + [instance tearDown]; + } @catch (OTAssertionFailedException *e) { + /* + * If an assertion fails during -[tearDown], + * abort the tear down. + */ + if (!failed) { + SEL selector = test.pointerValue; + OFString *description = e.description; + + [self printStatusForTest: selector + inClass: class + status: 2 + description: description]; + failed = true; + } + } + + if (!failed) { + [self printStatusForTest: test.pointerValue + inClass: class + status: 1 + description: nil]; + numSucceeded++; + } else + numFailed++; + + objc_autoreleasePoolPop(pool); + } + } + + [OFStdOut setForegroundColor: [OFColor fuchsia]]; + [OFStdOut writeFormat: @"%zu", numSucceeded]; + [OFStdOut setForegroundColor: [OFColor purple]]; + [OFStdOut writeString: @" test(s) succeeded, "]; + [OFStdOut setForegroundColor: [OFColor fuchsia]]; + [OFStdOut writeFormat: @"%zu", numFailed]; + [OFStdOut setForegroundColor: [OFColor purple]]; + [OFStdOut writeLine: @" test(s) failed."]; + [OFStdOut reset]; + + [OFApplication terminateWithStatus: (int)numFailed]; +} +@end ADDED src/test/OTAssert.h Index: src/test/OTAssert.h ================================================================== --- src/test/OTAssert.h +++ src/test/OTAssert.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2008-2024 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +/* + * Unfortunately, that's the only way to make all compilers happy with the GNU + * extensions for variadic macros that are being used here. + */ +#pragma GCC system_header + +#define OTAssert(cond, ...) \ + OTAssertImpl(self, _cmd, cond, @#cond, @__FILE__, __LINE__, \ + ## __VA_ARGS__, nil) +#define OTAssertTrue(cond, ...) OTAssert(cond == true, ## __VA_ARGS__) +#define OTAssertFalse(cond, ...) OTAssert(cond == false, ## __VA_ARGS__) +#define OTAssertEqual(a, b, ...) OTAssert(a == b, ## __VA_ARGS__) +#define OTAssertNotEqual(a, b, ...) OTAssert(a != b, ## __VA_ARGS__) +#define OTAssertEqualObjects(a, b, ...) OTAssert([a isEqual: b], ## __VA_ARGS__) +#define OTAssertNotEqualObjects(a, b, ...) \ + OTAssert(![a isEqual: b], ## __VA_ARGS__) +#define OTAssertNil(object, ...) OTAssert(object == nil, ## __VA_ARGS__) +#define OTAssertNotNil(object, ...) OTAssert(object != nil, ## __VA_ARGS__) +#define OTAssertThrows(expression, ...) \ + { \ + bool OTThrown = false; \ + @try { \ + expression; \ + } @catch (id e) { \ + OTThrown = true; \ + } \ + OTAssert(OTThrown, ## __VA_ARGS__); \ + } +#define OTAssertThrowsSpecific(expression, exception, ...) \ + { \ + bool OTThrown = false; \ + @try { \ + expression; \ + } @catch (exception *e) { \ + OTThrown = true; \ + } \ + OTAssert(OTThrown, ## __VA_ARGS__); \ + } + +#ifdef __cplusplus +extern "C" { +#endif +extern void OTAssertImpl(id testCase, SEL test, bool condition, OFString *check, + OFString *file, size_t line, ...); +#ifdef __cplusplus +} +#endif ADDED src/test/OTAssert.m Index: src/test/OTAssert.m ================================================================== --- src/test/OTAssert.m +++ src/test/OTAssert.m @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2008-2024 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#include "config.h" + +#import "OFString.h" + +#import "OTAssertionFailedException.h" + +void +OTAssertImpl(id testCase, SEL test, bool condition, OFString *check, + OFString *file, size_t line, ...) +{ + va_list arguments; + OFConstantString *format; + OFString *message = nil; + + if (condition) + return; + + va_start(arguments, line); + format = va_arg(arguments, OFConstantString *); + + if (format != nil) + message = [[[OFString alloc] + initWithFormat: format + arguments: arguments] autorelease]; + + va_end(arguments); + + @throw [OTAssertionFailedException exceptionWithCondition: check + message: message]; +} ADDED src/test/OTAssertionFailedException.h Index: src/test/OTAssertionFailedException.h ================================================================== --- src/test/OTAssertionFailedException.h +++ src/test/OTAssertionFailedException.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2008-2024 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#import "OFException.h" +#import "OFString.h" + +OF_ASSUME_NONNULL_BEGIN + +@interface OTAssertionFailedException: OFException +{ + OFString *_condition; + OFString *_Nullable _message; +} + +@property (readonly, nonatomic) OFString *condition; +@property OF_NULLABLE_PROPERTY (readonly, nonatomic) OFString *message; + ++ (instancetype)exceptionWithCondition: (OFString *)condition + message: (nullable OFString *)message; ++ (instancetype)exception OF_UNAVAILABLE; +- (instancetype)initWithCondition: (OFString *)condition + message: (nullable OFString *)message; +- (instancetype)init OF_UNAVAILABLE; +@end + +OF_ASSUME_NONNULL_END ADDED src/test/OTAssertionFailedException.m Index: src/test/OTAssertionFailedException.m ================================================================== --- src/test/OTAssertionFailedException.m +++ src/test/OTAssertionFailedException.m @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2008-2024 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#include "config.h" + +#import "OTAssertionFailedException.h" + +@implementation OTAssertionFailedException +@synthesize condition = _condition, message = _message; + ++ (instancetype)exceptionWithCondition: (OFString *)condition + message: (OFString *)message +{ + return [[[self alloc] initWithCondition: condition + message: message] autorelease]; +} + ++ (instancetype)exception +{ + OF_UNRECOGNIZED_SELECTOR +} + +- (instancetype)initWithCondition: (OFString *)condition + message: (OFString *)message +{ + self = [super init]; + + @try { + _condition = [condition copy]; + _message = [message copy]; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (instancetype)init +{ + OF_INVALID_INIT_METHOD +} + +- (void)dealloc +{ + [_condition release]; + [_message release]; + + [super dealloc]; +} + +- (OFString *)description +{ + if (_message != nil) + return [OFString stringWithFormat: @"Assertion failed: %@: %@", + _condition, _message]; + else + return [OFString stringWithFormat: @"Assertion failed: %@", + _condition]; +} +@end ADDED src/test/OTTestCase.h Index: src/test/OTTestCase.h ================================================================== --- src/test/OTTestCase.h +++ src/test/OTTestCase.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2008-2024 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#ifdef OBJFWTEST_LOCAL_INCLUDES +# import "OFObject.h" +#else +# import +#endif + +OF_ASSUME_NONNULL_BEGIN + +@interface OTTestCase: OFObject +- (void)setUp; +- (void)tearDown; +@end + +OF_ASSUME_NONNULL_END ADDED src/test/OTTestCase.m Index: src/test/OTTestCase.m ================================================================== --- src/test/OTTestCase.m +++ src/test/OTTestCase.m @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2008-2024 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#include "config.h" + +#import "OTTestCase.h" + +@implementation OTTestCase: OFObject +- (void)setUp +{ +} + +- (void)tearDown +{ +} +@end ADDED src/test/ObjFWTest.h Index: src/test/ObjFWTest.h ================================================================== --- src/test/ObjFWTest.h +++ src/test/ObjFWTest.h @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2008-2024 Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#import "OTTestCase.h" +#import "OTAssert.h" ADDED src/test/ObjFWTest.oc Index: src/test/ObjFWTest.oc ================================================================== --- src/test/ObjFWTest.oc +++ src/test/ObjFWTest.oc @@ -0,0 +1,3 @@ +package_format 1 +LIBS="-lobjfwtest $LIBS" +FRAMEWORK_LIBS="-lobjfwtest $FRAMEWORK_LIBS" Index: src/tls/OFGnuTLSTLSStream.m ================================================================== --- src/tls/OFGnuTLSTLSStream.m +++ src/tls/OFGnuTLSTLSStream.m @@ -194,10 +194,11 @@ - (void)asyncPerformClientHandshakeWithHost: (OFString *)host runLoopMode: (OFRunLoopMode)runLoopMode { static const OFTLSStreamErrorCode initFailedErrorCode = OFTLSStreamErrorCodeInitializationFailed; + void *pool = objc_autoreleasePoolPush(); id exception = nil; int status; if (_initialized) @throw [OFAlreadyOpenException exceptionWithObject: self]; @@ -245,10 +246,11 @@ [_underlyingStream asyncReadIntoBuffer: (void *)"" length: 0 runLoopMode: runLoopMode]; [_delegate retain]; + objc_autoreleasePoolPop(pool); return; } if (status == GNUTLS_E_SUCCESS) _handshakeDone = true; @@ -262,10 +264,12 @@ if ([_delegate respondsToSelector: @selector(stream:didPerformClientHandshakeWithHost:exception:)]) [_delegate stream: self didPerformClientHandshakeWithHost: host exception: exception]; + + objc_autoreleasePoolPop(pool); } - (bool)stream: (OFStream *)stream didReadIntoBuffer: (void *)buffer length: (size_t)length Index: src/tls/OFMbedTLSTLSStream.h ================================================================== --- src/tls/OFMbedTLSTLSStream.h +++ src/tls/OFMbedTLSTLSStream.h @@ -22,10 +22,11 @@ @interface OFMbedTLSTLSStream: OFTLSStream { bool _initialized, _handshakeDone; mbedtls_ssl_config _config; mbedtls_ssl_context _SSL; + mbedtls_x509_crt _CAChain; OFString *_host; } @end OF_ASSUME_NONNULL_END Index: src/tls/OFMbedTLSTLSStream.m ================================================================== --- src/tls/OFMbedTLSTLSStream.m +++ src/tls/OFMbedTLSTLSStream.m @@ -16,11 +16,14 @@ #include "config.h" #include #import "OFMbedTLSTLSStream.h" +#import "OFApplication.h" #import "OFData.h" +#import "OFDictionary.h" +#import "OFLocale.h" #import "OFAlreadyOpenException.h" #import "OFInitializationFailedException.h" #import "OFNotOpenException.h" #import "OFOutOfRangeException.h" @@ -32,11 +35,10 @@ #include int _ObjFWTLS_reference; static mbedtls_entropy_context entropy; static mbedtls_ctr_drbg_context CTRDRBG; -static mbedtls_x509_crt CAChain; @implementation OFMbedTLSTLSStream static int readFunc(void *ctx, unsigned char *buffer, size_t length) { @@ -99,24 +101,21 @@ mbedtls_entropy_init(&entropy); if (mbedtls_ctr_drbg_seed(&CTRDRBG, mbedtls_entropy_func, &entropy, NULL, 0) != 0) @throw [OFInitializationFailedException exceptionWithClass: self]; - - mbedtls_x509_crt_init(&CAChain); - if (mbedtls_x509_crt_parse_file(&CAChain, OF_MBEDTLS_CA_PATH) != 0) - @throw [OFInitializationFailedException - exceptionWithClass: self]; } - (instancetype)initWithStream: (OFStream *)stream { self = [super initWithStream: stream]; @try { _underlyingStream.delegate = self; + + mbedtls_x509_crt_init(&_CAChain); } @catch (id e) { [self release]; @throw e; } @@ -127,10 +126,12 @@ { if (_initialized) [self close]; [_host release]; + + mbedtls_x509_crt_free(&_CAChain); [super dealloc]; } - (void)close @@ -212,10 +213,12 @@ - (void)asyncPerformClientHandshakeWithHost: (OFString *)host runLoopMode: (OFRunLoopMode)runLoopMode { static const OFTLSStreamErrorCode initFailedErrorCode = OFTLSStreamErrorCodeInitializationFailed; + void *pool = objc_autoreleasePoolPush(); + OFString *CAFilePath; id exception = nil; int status; if (_initialized) @throw [OFAlreadyOpenException exceptionWithObject: self]; @@ -228,11 +231,24 @@ errorCode: initFailedErrorCode]; mbedtls_ssl_conf_rng(&_config, mbedtls_ctr_drbg_random, &CTRDRBG); mbedtls_ssl_conf_authmode(&_config, (_verifiesCertificates ? MBEDTLS_SSL_VERIFY_REQUIRED : MBEDTLS_SSL_VERIFY_NONE)); - mbedtls_ssl_conf_ca_chain(&_config, &CAChain, NULL); + + /* TODO: Add other ways to add a CA chain */ + CAFilePath = [[OFApplication environment] + objectForKey: @"OBJFW_MBEDTLS_CA_PATH"]; + if (CAFilePath != nil) { + if (mbedtls_x509_crt_parse_file(&_CAChain, + [CAFilePath cStringWithEncoding: [OFLocale encoding]]) != 0) + @throw [OFTLSHandshakeFailedException + exceptionWithStream: self + host: host + errorCode: initFailedErrorCode]; + } + + mbedtls_ssl_conf_ca_chain(&_config, &_CAChain, NULL); mbedtls_ssl_init(&_SSL); if (mbedtls_ssl_setup(&_SSL, &_config) != 0) @throw [OFTLSHandshakeFailedException exceptionWithStream: self @@ -254,15 +270,17 @@ if (status == MBEDTLS_ERR_SSL_WANT_READ) { [_underlyingStream asyncReadIntoBuffer: (void *)"" length: 0 runLoopMode: runLoopMode]; [_delegate retain]; + objc_autoreleasePoolPop(pool); return; } else if (status == MBEDTLS_ERR_SSL_WANT_WRITE) { [_underlyingStream asyncWriteData: [OFData data] runLoopMode: runLoopMode]; [_delegate retain]; + objc_autoreleasePoolPop(pool); return; } if (status == 0) _handshakeDone = true; @@ -276,10 +294,12 @@ if ([_delegate respondsToSelector: @selector(stream:didPerformClientHandshakeWithHost:exception:)]) [_delegate stream: self didPerformClientHandshakeWithHost: host exception: exception]; + + objc_autoreleasePoolPop(pool); } - (bool)stream: (OFStream *)stream didReadIntoBuffer: (void *)buffer length: (size_t)length Index: src/tls/OFOpenSSLTLSStream.m ================================================================== --- src/tls/OFOpenSSLTLSStream.m +++ src/tls/OFOpenSSLTLSStream.m @@ -212,10 +212,11 @@ - (void)asyncPerformClientHandshakeWithHost: (OFString *)host runLoopMode: (OFRunLoopMode)runLoopMode { static const OFTLSStreamErrorCode initFailedErrorCode = OFTLSStreamErrorCodeInitializationFailed; + void *pool = objc_autoreleasePoolPush(); id exception = nil; int status; if (_SSL != NULL) @throw [OFAlreadyOpenException exceptionWithObject: self]; @@ -285,15 +286,17 @@ case SSL_ERROR_WANT_READ: [_underlyingStream asyncReadIntoBuffer: _buffer length: bufferSize runLoopMode: runLoopMode]; [_delegate retain]; + objc_autoreleasePoolPop(pool); return; case SSL_ERROR_WANT_WRITE: [_underlyingStream asyncWriteData: [OFData data] runLoopMode: runLoopMode]; [_delegate retain]; + objc_autoreleasePoolPop(pool); return; default: /* FIXME: Map to better errors */ exception = [OFTLSHandshakeFailedException exceptionWithStream: self @@ -306,10 +309,12 @@ if ([_delegate respondsToSelector: @selector(stream:didPerformClientHandshakeWithHost:exception:)]) [_delegate stream: self didPerformClientHandshakeWithHost: host exception: exception]; + + objc_autoreleasePoolPop(pool); } - (bool)stream: (OFStream *)stream didReadIntoBuffer: (void *)buffer length: (size_t)length Index: src/tls/OFSecureTransportTLSStream.m ================================================================== --- src/tls/OFSecureTransportTLSStream.m +++ src/tls/OFSecureTransportTLSStream.m @@ -180,10 +180,11 @@ - (void)asyncPerformClientHandshakeWithHost: (OFString *)host runLoopMode: (OFRunLoopMode)runLoopMode { static const OFTLSStreamErrorCode initFailedErrorCode = OFTLSStreamErrorCodeInitializationFailed; + void *pool = objc_autoreleasePoolPush(); id exception = nil; OSStatus status; if (_context != NULL) @throw [OFAlreadyOpenException exceptionWithObject: self]; @@ -229,10 +230,11 @@ */ [_underlyingStream asyncReadIntoBuffer: (void *)"" length: 0 runLoopMode: runLoopMode]; [_delegate retain]; + objc_autoreleasePoolPop(pool); return; } if (status != noErr) /* FIXME: Map to better errors */ @@ -244,10 +246,12 @@ if ([_delegate respondsToSelector: @selector(stream:didPerformClientHandshakeWithHost:exception:)]) [_delegate stream: self didPerformClientHandshakeWithHost: _host exception: exception]; + + objc_autoreleasePoolPop(pool); } - (bool)stream: (OFStream *)stream didReadIntoBuffer: (void *)buffer length: (size_t)length Index: tests/Makefile ================================================================== --- tests/Makefile +++ tests/Makefile @@ -1,56 +1,31 @@ include ../extra.mk -SUBDIRS = ${TESTPLUGIN} \ - ${OBJC_SYNC} \ +SUBDIRS = ${OBJC_SYNC} \ terminal CLEAN = EBOOT.PBP \ boot.dol \ ${PROG_NOINST}.arm9 \ ${PROG_NOINST}.nds \ ${PROG_NOINST}.nro \ - ${PROG_NOINST}.rpx \ - testfile_bin.m \ - testfile_ini.m + ${PROG_NOINST}.rpx DISTCLEAN = Info.plist PROG_NOINST = tests${PROG_SUFFIX} STATIC_LIB_NOINST = ${TESTS_STATIC_LIB} SRCS = ForwardingTests.m \ OFASN1DERParsingTests.m \ OFASN1DERRepresentationTests.m \ - OFArrayTests.m \ ${OF_BLOCK_TESTS_M} \ - OFCharacterSetTests.m \ - OFColorTests.m \ OFDataTests.m \ - OFDateTests.m \ OFDictionaryTests.m \ - OFHMACTests.m \ - OFINIFileTests.m \ - OFIRITests.m \ - OFInvocationTests.m \ - OFJSONTests.m \ OFListTests.m \ OFLocaleTests.m \ - OFMD5HashTests.m \ - OFMatrix4x4Tests.m \ OFMemoryStreamTests.m \ - OFMethodSignatureTests.m \ OFNotificationCenterTests.m \ - OFNumberTests.m \ OFObjectTests.m \ - OFPBKDF2Tests.m \ - OFPropertyListTests.m \ - OFRIPEMD160HashTests.m \ - OFSHA1HashTests.m \ - OFSHA224HashTests.m \ - OFSHA256HashTests.m \ - OFSHA384HashTests.m \ - OFSHA512HashTests.m \ - OFScryptTests.m \ OFSetTests.m \ OFStreamTests.m \ OFStringTests.m \ OFSystemInfoTests.m \ OFValueTests.m \ @@ -59,23 +34,17 @@ OFXMLParserTests.m \ RuntimeTests.m \ ${RUNTIME_ARC_TESTS_M} \ TestsAppDelegate.m \ ${USE_SRCS_FILES} \ - ${USE_SRCS_PLUGINS} \ ${USE_SRCS_SOCKETS} \ - ${USE_SRCS_THREADS} \ - ${USE_SRCS_WINDOWS} \ - testfile_bin.m \ - testfile_ini.m -SRCS_PLUGINS = OFPluginTests.m + ${USE_SRCS_WINDOWS} SRCS_SOCKETS = OFDNSResolverTests.m \ ${OF_HTTP_CLIENT_TESTS_M} \ OFHTTPCookieTests.m \ OFHTTPCookieManagerTests.m \ OFKernelEventObserverTests.m \ - OFSocketTests.m \ OFTCPSocketTests.m \ OFUDPSocketTests.m \ ${USE_SRCS_APPLETALK} \ ${USE_SRCS_IPX} \ ${USE_SRCS_UNIX_SOCKETS} @@ -83,23 +52,17 @@ SRCS_IPX = OFIPXSocketTests.m \ OFSPXSocketTests.m \ OFSPXStreamSocketTests.m SRCS_UNIX_SOCKETS = OFUNIXDatagramSocketTests.m \ OFUNIXStreamSocketTests.m -SRCS_THREADS = OFThreadTests.m SRCS_WINDOWS = OFWindowsRegistryKeyTests.m IOS_USER ?= mobile IOS_TMP ?= /tmp/objfw-test include ../buildsys.mk -testfile_bin.m: testfile.bin - ${SHELL} ../utils/objfw-embed testfile.bin testfile.bin $@ -testfile_ini.m: testfile.ini - ${SHELL} ../utils/objfw-embed testfile.ini testfile.ini $@ - .PHONY: run run-on-ios run-on-android run: rm -f libobjfw.so.${OBJFW_LIB_MAJOR} rm -f libobjfw.so.${OBJFW_LIB_MAJOR_MINOR} rm -f objfw${OBJFW_LIB_MAJOR}.dll libobjfw.${OBJFW_LIB_MAJOR}.dylib @@ -153,28 +116,10 @@ rm -f libobjfwrt.so.${OBJFWRT_LIB_MAJOR_MINOR}; \ rm -f objfwrt${OBJFWRT_LIB_MAJOR}.dll; \ rm -f libobjfwrt.${OBJFWRT_LIB_MAJOR}.dylib; \ exit $$EXIT -run-on-ios: all - if [ -z "${IOS_HOST}" ]; then \ - echo "Please set IOS_HOST to the hostname of your iOS host!"; \ - exit 1; \ - fi - echo "Uploading files to iOS device ${IOS_HOST} at ${IOS_TMP}..." - ssh ${IOS_USER}@${IOS_HOST} \ - 'rm -fr ${IOS_TMP} && mkdir -p ${IOS_TMP}/plugin' - destname=libobjfw.${OBJFW_LIB_MAJOR}.dylib; \ - scp -q ../src/libobjfw.dylib \ - ${IOS_USER}@${IOS_HOST}:${IOS_TMP}/$$destname - scp -q tests testfile.txt ${IOS_USER}@${IOS_HOST}:${IOS_TMP}/ - scp -q plugin/TestPlugin.bundle \ - ${IOS_USER}@${IOS_HOST}:${IOS_TMP}/plugin/ - echo "Running tests binary on iOS device ${IOS_HOST}..." - ssh ${IOS_USER}@${IOS_HOST} \ - 'cd ${IOS_TMP} && DYLD_LIBRARY_PATH=. ${WRAPPER} ./tests' - run-on-android: all echo "Uploading files to Android device..." if test -f ../src/libobjfw.so; then \ adb push ../src/libobjfw.so \ /data/local/tmp/objfw/libobjfw.so.${OBJFW_LIB_MAJOR}; \ @@ -183,14 +128,10 @@ adb push ../src/runtime/libobjfwrt.so \ /data/local/tmp/objfw/libobjfwrt.so.${OBJFWRT_LIB_MAJOR}; \ fi adb push tests /data/local/tmp/objfw/tests adb push testfile.txt /data/local/tmp/objfw/testfile.txt - if test -f plugin/TestPlugin.so; then \ - adb push plugin/TestPlugin.so \ - /data/local/tmp/objfw/plugin/TestPlugin.so; \ - fi echo "Running tests binary on Android device..." adb shell 'cd /data/local/tmp/objfw && LD_LIBRARY_PATH=. exec ${WRAPPER} ./tests' EBOOT.PBP: ${PROG_NOINST} psp-fixup-imports ${PROG_NOINST} @@ -226,10 +167,14 @@ rm -fr romfs tests.nacp ${PROG_NOINST}.rpx: ${PROG_NOINST} elf2rpl $< $@ -CPPFLAGS += -I../src -I../src/exceptions -I../src/runtime -I.. -DSTDOUT +CPPFLAGS += -I../src \ + -I../src/exceptions \ + -I../src/runtime \ + -I.. \ + -DSTDOUT OBJCFLAGS_RuntimeARCTests.m = -fobjc-arc -fobjc-arc-exceptions LIBS := ${TESTS_LIBS} ${LIBS} LDFLAGS += ${MAP_LDFLAGS} LD = ${OBJC} DELETED tests/OFArrayTests.m Index: tests/OFArrayTests.m ================================================================== --- tests/OFArrayTests.m +++ tests/OFArrayTests.m @@ -1,458 +0,0 @@ -/* - * Copyright (c) 2008-2024 Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It may be distributed under the terms of the - * Q Public License 1.0, which can be found in the file LICENSE.QPL included in - * the packaging of this file. - * - * Alternatively, it may be distributed under the terms of the GNU General - * Public License, either version 2 or 3, which can be found in the file - * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this - * file. - */ - -#include "config.h" - -#import "TestsAppDelegate.h" - -static OFString *module; -static OFString *const cArray[] = { - @"Foo", - @"Bar", - @"Baz" -}; - -@interface SimpleArray: OFArray -{ - OFMutableArray *_array; -} -@end - -@interface SimpleMutableArray: OFMutableArray -{ - OFMutableArray *_array; -} -@end - -@implementation SimpleArray -- (instancetype)init -{ - self = [super init]; - - @try { - _array = [[OFMutableArray alloc] init]; - } @catch (id e) { - [self release]; - @throw e; - } - - return self; -} - -- (instancetype)initWithObject: (id)object arguments: (va_list)arguments -{ - self = [super init]; - - @try { - _array = [[OFMutableArray alloc] initWithObject: object - arguments: arguments]; - } @catch (id e) { - [self release]; - @throw e; - } - - return self; -} - -- (instancetype)initWithObjects: (id const *)objects count: (size_t)count -{ - self = [super init]; - - @try { - _array = [[OFMutableArray alloc] initWithObjects: objects - count: count]; - } @catch (id e) { - [self release]; - @throw e; - } - - return self; -} - -- (void)dealloc -{ - [_array release]; - - [super dealloc]; -} - -- (id)objectAtIndex: (size_t)idx -{ - return [_array objectAtIndex: idx]; -} - -- (size_t)count -{ - return [_array count]; -} -@end - -@implementation SimpleMutableArray -+ (void)initialize -{ - if (self == [SimpleMutableArray class]) - [self inheritMethodsFromClass: [SimpleArray class]]; -} - -- (void)insertObject: (id)object atIndex: (size_t)idx -{ - [_array insertObject: object atIndex: idx]; -} - -- (void)replaceObjectAtIndex: (size_t)idx withObject: (id)object -{ - [_array replaceObjectAtIndex: idx withObject: object]; -} - -- (void)removeObjectAtIndex: (size_t)idx -{ - [_array removeObjectAtIndex: idx]; -} -@end - -@implementation TestsAppDelegate (OFArrayTests) -- (void)arrayTestsWithClass: (Class)arrayClass - mutableClass: (Class)mutableArrayClass -{ - void *pool = objc_autoreleasePoolPush(); - OFArray *array1, *array2; - OFMutableArray *mutableArray1, *mutableArray2; - OFEnumerator *enumerator; - id object; - bool ok; - size_t i; - - TEST(@"+[array]", (mutableArray1 = [mutableArrayClass array])) - - TEST(@"+[arrayWithObjects:]", - (array1 = - [arrayClass arrayWithObjects: @"Foo", @"Bar", @"Baz", nil])) - - TEST(@"+[arrayWithObjects:count:]", - (array2 = [arrayClass arrayWithObjects: cArray count: 3]) && - [array2 isEqual: array1]) - - TEST(@"-[description]", - [array1.description isEqual: @"(\n\tFoo,\n\tBar,\n\tBaz\n)"]) - - TEST(@"-[addObject:]", - R([mutableArray1 addObject: cArray[0]]) && - R([mutableArray1 addObject: cArray[2]])) - - TEST(@"-[insertObject:atIndex:]", - R([mutableArray1 insertObject: cArray[1] atIndex: 1])) - - TEST(@"-[count]", - mutableArray1.count == 3 && array1.count == 3 && array2.count == 3) - - TEST(@"-[isEqual:]", - [mutableArray1 isEqual: array1] && [array1 isEqual: array2]) - - TEST(@"-[objectAtIndex:]", - [[mutableArray1 objectAtIndex: 0] isEqual: cArray[0]] && - [[mutableArray1 objectAtIndex: 1] isEqual: cArray[1]] && - [[mutableArray1 objectAtIndex: 2] isEqual: cArray[2]] && - [[array1 objectAtIndex: 0] isEqual: cArray[0]] && - [[array1 objectAtIndex: 1] isEqual: cArray[1]] && - [[array1 objectAtIndex: 2] isEqual: cArray[2]] && - [[array2 objectAtIndex: 0] isEqual: cArray[0]] && - [[array2 objectAtIndex: 1] isEqual: cArray[1]] && - [[array2 objectAtIndex: 2] isEqual: cArray[2]]) - - TEST(@"-[containsObject:]", - [array1 containsObject: cArray[1]] && - ![array1 containsObject: @"nonexistent"]) - - TEST(@"-[containsObjectIdenticalTo:]", - [array1 containsObjectIdenticalTo: cArray[1]] && - ![array1 containsObjectIdenticalTo: - [OFString stringWithString: cArray[1]]]) - - TEST(@"-[indexOfObject:]", [array1 indexOfObject: cArray[1]] == 1) - - TEST(@"-[indexOfObjectIdenticalTo:]", - [array2 indexOfObjectIdenticalTo: cArray[1]] == 1) - - TEST(@"-[objectsInRange:]", - [[array1 objectsInRange: OFMakeRange(1, 2)] isEqual: - [arrayClass arrayWithObjects: cArray[1], cArray[2], nil]]) - - TEST(@"-[replaceObject:withObject:]", - R([mutableArray1 replaceObject: cArray[1] withObject: cArray[0]]) && - [[mutableArray1 objectAtIndex: 0] isEqual: cArray[0]] && - [[mutableArray1 objectAtIndex: 1] isEqual: cArray[0]] && - [[mutableArray1 objectAtIndex: 2] isEqual: cArray[2]]) - - TEST(@"-[replaceObject:identicalTo:]", - R([mutableArray1 replaceObjectIdenticalTo: cArray[0] - withObject: cArray[1]]) && - [[mutableArray1 objectAtIndex: 0] isEqual: cArray[1]] && - [[mutableArray1 objectAtIndex: 1] isEqual: cArray[0]] && - [[mutableArray1 objectAtIndex: 2] isEqual: cArray[2]]) - - TEST(@"-[replaceObjectAtIndex:withObject:]", - R([mutableArray1 replaceObjectAtIndex: 0 withObject: cArray[0]]) && - [[mutableArray1 objectAtIndex: 0] isEqual: cArray[0]] && - [[mutableArray1 objectAtIndex: 1] isEqual: cArray[0]] && - [[mutableArray1 objectAtIndex: 2] isEqual: cArray[2]]) - - TEST(@"-[removeObject:]", - R([mutableArray1 removeObject: cArray[0]]) && - mutableArray1.count == 1) - - [mutableArray1 addObject: cArray[0]]; - - TEST(@"-[removeObjectIdenticalTo:]", - R([mutableArray1 removeObjectIdenticalTo: cArray[2]]) && - mutableArray1.count == 1) - - mutableArray2 = [[array1 mutableCopy] autorelease]; - TEST(@"-[removeObjectAtIndex:]", - R([mutableArray2 removeObjectAtIndex: 1]) && - mutableArray2.count == 2 && - [[mutableArray2 objectAtIndex: 1] isEqual: cArray[2]]) - - mutableArray2 = [[array1 mutableCopy] autorelease]; - TEST(@"-[removeObjectsInRange:]", - R([mutableArray2 removeObjectsInRange: OFMakeRange(0, 2)]) && - mutableArray2.count == 1 && - [[mutableArray2 objectAtIndex: 0] isEqual: cArray[2]]) - - mutableArray2 = [[array1 mutableCopy] autorelease]; - [mutableArray2 addObject: @"qux"]; - [mutableArray2 addObject: @"last"]; - TEST(@"-[reverse]", - R([mutableArray2 reverse]) && - [mutableArray2 isEqual: [arrayClass arrayWithObjects: - @"last", @"qux", @"Baz", @"Bar", @"Foo", nil]]) - - mutableArray2 = [[array1 mutableCopy] autorelease]; - [mutableArray2 addObject: @"qux"]; - [mutableArray2 addObject: @"last"]; - TEST(@"-[reversedArray]", - [[mutableArray2 reversedArray] isEqual: - [arrayClass arrayWithObjects: - @"last", @"qux", @"Baz", @"Bar", @"Foo", nil]]) - - mutableArray2 = [[array1 mutableCopy] autorelease]; - [mutableArray2 addObject: @"0"]; - [mutableArray2 addObject: @"z"]; - TEST(@"-[sortedArray]", - [[mutableArray2 sortedArray] isEqual: [arrayClass arrayWithObjects: - @"0", @"Bar", @"Baz", @"Foo", @"z", nil]] && - [[mutableArray2 sortedArrayUsingSelector: @selector(compare:) - options: OFArraySortDescending] - isEqual: [arrayClass arrayWithObjects: - @"z", @"Foo", @"Baz", @"Bar", @"0", nil]]) - - EXPECT_EXCEPTION(@"Detect out of range in -[objectAtIndex:]", - OFOutOfRangeException, [array1 objectAtIndex: array1.count]) - - EXPECT_EXCEPTION(@"Detect out of range in -[removeObjectsInRange:]", - OFOutOfRangeException, [mutableArray1 removeObjectsInRange: - OFMakeRange(0, mutableArray1.count + 1)]) - - TEST(@"-[componentsJoinedByString:]", - (array2 = [arrayClass arrayWithObjects: @"", @"a", @"b", @"c", - nil]) && - [[array2 componentsJoinedByString: @" "] isEqual: @" a b c"] && - (array2 = [arrayClass arrayWithObject: @"foo"]) && - [[array2 componentsJoinedByString: @" "] isEqual: @"foo"]) - - TEST(@"-[componentsJoinedByString:options]", - (array2 = [arrayClass arrayWithObjects: @"", @"foo", @"", @"", - @"bar", @"", nil]) && - [[array2 componentsJoinedByString: @" " - options: OFArraySkipEmptyComponents] - isEqual: @"foo bar"]) - - mutableArray1 = [[array1 mutableCopy] autorelease]; - ok = true; - i = 0; - - TEST(@"-[objectEnumerator]", - (enumerator = [mutableArray1 objectEnumerator])) - - while ((object = [enumerator nextObject]) != nil) { - if (![object isEqual: cArray[i]]) - ok = false; - [mutableArray1 replaceObjectAtIndex: i withObject: @""]; - i++; - } - - if (mutableArray1.count != i) - ok = false; - - TEST(@"OFEnumerator's -[nextObject]", ok) - - [mutableArray1 removeObjectAtIndex: 0]; - - EXPECT_EXCEPTION(@"Detection of mutation during enumeration", - OFEnumerationMutationException, [enumerator nextObject]) - - mutableArray1 = [[array1 mutableCopy] autorelease]; - ok = true; - i = 0; - - for (OFString *string in mutableArray1) { - if (![string isEqual: cArray[i]]) - ok = false; - [mutableArray1 replaceObjectAtIndex: i withObject: @""]; - i++; - } - - if (mutableArray1.count != i) - ok = false; - - TEST(@"Fast Enumeration", ok) - - [mutableArray1 replaceObjectAtIndex: 0 withObject: cArray[0]]; - [mutableArray1 replaceObjectAtIndex: 1 withObject: cArray[1]]; - [mutableArray1 replaceObjectAtIndex: 2 withObject: cArray[2]]; - - ok = false; - i = 0; - @try { - for (OFString *string in mutableArray1) { - (void)string; - - if (i == 0) - [mutableArray1 addObject: @""]; - - i++; - } - } @catch (OFEnumerationMutationException *e) { - ok = true; - } - - TEST(@"Detection of mutation during Fast Enumeration", ok) - - [mutableArray1 removeLastObject]; - -#ifdef OF_HAVE_BLOCKS - { - __block bool blockOK = true; - __block size_t count = 0; - OFArray *compareArray = array1; - OFMutableArray *mutableArray3; - - mutableArray1 = [[array1 mutableCopy] autorelease]; - [mutableArray1 enumerateObjectsUsingBlock: - ^ (id object_, size_t idx, bool *stop) { - count++; - if (![object_ isEqual: - [compareArray objectAtIndex: idx]]) - blockOK = false; - }]; - - if (count != compareArray.count) - blockOK = false; - - TEST(@"Enumeration using blocks", blockOK) - - blockOK = false; - mutableArray3 = mutableArray1; - @try { - [mutableArray3 enumerateObjectsUsingBlock: - ^ (id object_, size_t idx, bool *stop) { - [mutableArray3 removeObjectAtIndex: idx]; - }]; - } @catch (OFEnumerationMutationException *e) { - blockOK = true; - } @catch (OFOutOfRangeException *e) { - /* - * Out of bounds access due to enumeration not being - * detected. - */ - } - - TEST(@"Detection of mutation during enumeration using blocks", - blockOK) - } - - TEST(@"-[replaceObjectsUsingBlock:]", - R([mutableArray1 replaceObjectsUsingBlock: - ^ id (id object_, size_t idx) { - switch (idx) { - case 0: - return @"foo"; - case 1: - return @"bar"; - } - - return nil; - }]) && [mutableArray1.description isEqual: @"(\n\tfoo,\n\tbar\n)"]) - - TEST(@"-[mappedArrayUsingBlock:]", - [[mutableArray1 mappedArrayUsingBlock: - ^ id (id object_, size_t idx) { - switch (idx) { - case 0: - return @"foobar"; - case 1: - return @"qux"; - } - - return nil; - }].description isEqual: @"(\n\tfoobar,\n\tqux\n)"]) - - TEST(@"-[filteredArrayUsingBlock:]", - [[mutableArray1 filteredArrayUsingBlock: - ^ bool (id object_, size_t idx) { - return [object_ isEqual: @"foo"]; - }].description isEqual: @"(\n\tfoo\n)"]) - - TEST(@"-[foldUsingBlock:]", - [[arrayClass arrayWithObjects: [OFMutableString string], @"foo", - @"bar", @"baz", nil] foldUsingBlock: ^ id (id left, id right) { - [left appendString: right]; - return left; - }]) -#endif - - TEST(@"-[valueForKey:]", - [[[arrayClass arrayWithObjects: @"foo", @"bar", @"quxqux", nil] - valueForKey: @"length"] isEqual: - [arrayClass arrayWithObjects: [OFNumber numberWithInt: 3], - [OFNumber numberWithInt: 3], [OFNumber numberWithInt: 6], nil]] && - [[[arrayClass arrayWithObjects: @"1", @"2", nil] - valueForKey: @"@count"] isEqual: [OFNumber numberWithInt: 2]]) - - mutableArray1 = [mutableArrayClass arrayWithObjects: - [OFMutableIRI IRIWithString: @"http://foo.bar/"], - [OFMutableIRI IRIWithString: @"http://bar.qux/"], - [OFMutableIRI IRIWithString: @"http://qux.quxqux/"], nil]; - TEST(@"-[setValue:forKey:]", - R([mutableArray1 setValue: [OFNumber numberWithShort: 1234] - forKey: @"port"]) && - [mutableArray1 isEqual: [arrayClass arrayWithObjects: - [OFIRI IRIWithString: @"http://foo.bar:1234/"], - [OFIRI IRIWithString: @"http://bar.qux:1234/"], - [OFIRI IRIWithString: @"http://qux.quxqux:1234/"], nil]]) - - objc_autoreleasePoolPop(pool); -} - -- (void)arrayTests -{ - module = @"OFArray"; - [self arrayTestsWithClass: [SimpleArray class] - mutableClass: [SimpleMutableArray class]]; - - module = @"OFArray_adjacent"; - [self arrayTestsWithClass: [OFArray class] - mutableClass: [OFMutableArray class]]; -} -@end DELETED tests/OFCharacterSetTests.m Index: tests/OFCharacterSetTests.m ================================================================== --- tests/OFCharacterSetTests.m +++ tests/OFCharacterSetTests.m @@ -1,107 +0,0 @@ -/* - * Copyright (c) 2008-2024 Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It may be distributed under the terms of the - * Q Public License 1.0, which can be found in the file LICENSE.QPL included in - * the packaging of this file. - * - * Alternatively, it may be distributed under the terms of the GNU General - * Public License, either version 2 or 3, which can be found in the file - * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this - * file. - */ - -#include "config.h" - -#import "TestsAppDelegate.h" - -#import "OFCharacterSet.h" -#import "OFBitSetCharacterSet.h" -#import "OFRangeCharacterSet.h" - -static OFString *module; - -@interface SimpleCharacterSet: OFCharacterSet -@end - -@implementation SimpleCharacterSet -- (bool)characterIsMember: (OFUnichar)character -{ - return (character % 2 == 0); -} -@end - -@implementation TestsAppDelegate (OFCharacterSetTests) -- (void)characterSetTests -{ - void *pool = objc_autoreleasePoolPush(); - OFCharacterSet *characterSet, *invertedCharacterSet; - bool ok; - - module = @"OFCharacterSet"; - - characterSet = [[[SimpleCharacterSet alloc] init] autorelease]; - - ok = true; - for (OFUnichar c = 0; c < 65536; c++) { - if (c % 2 == 0) { - if (![characterSet characterIsMember: c]) - ok = false; - } else if ([characterSet characterIsMember: c]) - ok = false; - } - TEST(@"-[characterIsMember:]", ok); - - module = @"OFBitSetCharacterSet"; - - TEST(@"+[characterSetWithCharactersInString:]", - (characterSet = [OFCharacterSet characterSetWithCharactersInString: - @"0123456789"]) && - [characterSet isKindOfClass: [OFBitSetCharacterSet class]]) - - ok = true; - for (OFUnichar c = 0; c < 65536; c++) { - if (c >= '0' && c <= '9') { - if (![characterSet characterIsMember: c]) - ok = false; - } else if ([characterSet characterIsMember: c]) - ok = false; - } - TEST(@"-[characterIsMember:]", ok); - - module = @"OFRangeCharacterSet"; - - TEST(@"+[characterSetWithRange:]", - (characterSet = [OFCharacterSet - characterSetWithRange: OFMakeRange('0', 10)]) && - [characterSet isKindOfClass: [OFRangeCharacterSet class]]) - - ok = true; - for (OFUnichar c = 0; c < 65536; c++) { - if (c >= '0' && c <= '9') { - if (![characterSet characterIsMember: c]) - ok = false; - } else if ([characterSet characterIsMember: c]) - ok = false; - } - TEST(@"-[characterIsMember:]", ok); - - ok = true; - invertedCharacterSet = characterSet.invertedSet; - for (OFUnichar c = 0; c < 65536; c++) { - if (c >= '0' && c <= '9') { - if ([invertedCharacterSet characterIsMember: c]) - ok = false; - } else if (![invertedCharacterSet characterIsMember: c]) - ok = false; - } - TEST(@"-[invertedSet]", ok); - - TEST(@"Inverting -[invertedSet] returns original set", - invertedCharacterSet.invertedSet == characterSet) - - objc_autoreleasePoolPop(pool); -} -@end DELETED tests/OFColorTests.m Index: tests/OFColorTests.m ================================================================== --- tests/OFColorTests.m +++ tests/OFColorTests.m @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2008-2024 Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It may be distributed under the terms of the - * Q Public License 1.0, which can be found in the file LICENSE.QPL included in - * the packaging of this file. - * - * Alternatively, it may be distributed under the terms of the GNU General - * Public License, either version 2 or 3, which can be found in the file - * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this - * file. - */ - -#include "config.h" - -#import "TestsAppDelegate.h" - -static OFString *const module = @"OFColor"; - -@implementation TestsAppDelegate (OFColorTests) -- (void)colorTests -{ - void *pool = objc_autoreleasePoolPush(); - OFColor *color; - float red, green, blue, alpha; - - TEST(@"+[colorWithRed:green:blue:alpha:]", - (color = [OFColor colorWithRed: 63.f / 255 - green: 127.f / 255 - blue: 1 - alpha: 1])) - -#ifdef OF_OBJFW_RUNTIME - TEST(@"+[colorWithRed:green:blue:alpha:] returns tagged pointer", - object_isTaggedPointer(color)) -#endif - - TEST(@"-[getRed:green:blue:alpha:]", - R([color getRed: &red green: &green blue: &blue alpha: &alpha]) && - red == 63.f / 255 && green == 127.f / 255 && blue == 1 && - alpha == 1) - - objc_autoreleasePoolPop(pool); -} -@end DELETED tests/OFDateTests.m Index: tests/OFDateTests.m ================================================================== --- tests/OFDateTests.m +++ tests/OFDateTests.m @@ -1,112 +0,0 @@ -/* - * Copyright (c) 2008-2024 Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It may be distributed under the terms of the - * Q Public License 1.0, which can be found in the file LICENSE.QPL included in - * the packaging of this file. - * - * Alternatively, it may be distributed under the terms of the GNU General - * Public License, either version 2 or 3, which can be found in the file - * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this - * file. - */ - -#include "config.h" - -#include - -#import "TestsAppDelegate.h" -#import "OFStrPTime.h" - -static OFString *const module = @"OFDate"; - -@implementation TestsAppDelegate (OFDateTests) -- (void)dateTests -{ - void *pool = objc_autoreleasePoolPush(); - OFDate *date1, *date2; - - struct tm tm; - int16_t tz; - const char *dstr = "Wed, 09 Jun 2021 +0200x"; - TEST(@"OFStrPTime()", - OFStrPTime(dstr, "%a, %d %b %Y %z", &tm, &tz) == dstr + 22 && - tm.tm_wday == 3 && tm.tm_mday == 9 && tm.tm_mon == 5 && - tm.tm_year == 2021 - 1900 && tz == 2 * 60) - - TEST(@"+[dateWithTimeIntervalSince1970:]", - (date1 = [OFDate dateWithTimeIntervalSince1970: 0])) - - TEST(@"-[dateByAddingTimeInterval:]", - (date2 = [date1 dateByAddingTimeInterval: 3600 * 25 + 5.000002])) - - TEST(@"-[description]", - [date1.description isEqual: @"1970-01-01T00:00:00Z"] && - [date2.description isEqual: @"1970-01-02T01:00:05Z"]) - - TEST(@"+[dateWithDateString:format:]", - [[[OFDate dateWithDateString: @"2000-06-20T12:34:56+0200" - format: @"%Y-%m-%dT%H:%M:%S%z"] description] - isEqual: @"2000-06-20T10:34:56Z"]); - - EXPECT_EXCEPTION(@"Detection of unparsed in " - @"+[dateWithDateString:format:]", OFInvalidFormatException, - [OFDate dateWithDateString: @"2000-06-20T12:34:56+0200x" - format: @"%Y-%m-%dT%H:%M:%S%z"]) - - TEST(@"+[dateWithLocalDateString:format:]", - [[[OFDate dateWithLocalDateString: @"2000-06-20T12:34:56" - format: @"%Y-%m-%dT%H:%M:%S"] - localDateStringWithFormat: @"%Y-%m-%dT%H:%M:%S"] - isEqual: @"2000-06-20T12:34:56"]); - - TEST(@"+[dateWithLocalDateString:format:]", - [[[OFDate dateWithLocalDateString: @"2000-06-20T12:34:56-0200" - format: @"%Y-%m-%dT%H:%M:%S%z"] - description] isEqual: @"2000-06-20T14:34:56Z"]); - - EXPECT_EXCEPTION(@"Detection of unparsed in " - @"+[dateWithLocalDateString:format:] #1", OFInvalidFormatException, - [OFDate dateWithLocalDateString: @"2000-06-20T12:34:56x" - format: @"%Y-%m-%dT%H:%M:%S"]) - - EXPECT_EXCEPTION(@"Detection of unparsed in " - @"+[dateWithLocalDateString:format:] #2", OFInvalidFormatException, - [OFDate dateWithLocalDateString: @"2000-06-20T12:34:56+0200x" - format: @"%Y-%m-%dT%H:%M:%S%z"]) - - TEST(@"-[isEqual:]", - [date1 isEqual: [OFDate dateWithTimeIntervalSince1970: 0]] && - ![date1 isEqual: [OFDate dateWithTimeIntervalSince1970: 0.0000001]]) - - TEST(@"-[compare:]", [date1 compare: date2] == OFOrderedAscending) - - TEST(@"-[second]", date1.second == 0 && date2.second == 5) - - TEST(@"-[microsecond]", - date1.microsecond == 0 && date2.microsecond == 2) - - TEST(@"-[minute]", date1.minute == 0 && date2.minute == 0) - - TEST(@"-[hour]", date1.hour == 0 && date2.hour == 1) - - TEST(@"-[dayOfMonth]", date1.dayOfMonth == 1 && date2.dayOfMonth == 2) - - TEST(@"-[monthOfYear]", - date1.monthOfYear == 1 && date2.monthOfYear == 1) - - TEST(@"-[year]", date1.year == 1970 && date2.year == 1970) - - TEST(@"-[dayOfWeek]", date1.dayOfWeek == 4 && date2.dayOfWeek == 5) - - TEST(@"-[dayOfYear]", date1.dayOfYear == 1 && date2.dayOfYear == 2) - - TEST(@"-[earlierDate:]", [[date1 earlierDate: date2] isEqual: date1]) - - TEST(@"-[laterDate:]", [[date1 laterDate: date2] isEqual: date2]) - - objc_autoreleasePoolPop(pool); -} -@end DELETED tests/OFHMACTests.m Index: tests/OFHMACTests.m ================================================================== --- tests/OFHMACTests.m +++ tests/OFHMACTests.m @@ -1,130 +0,0 @@ -/* - * Copyright (c) 2008-2024 Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It may be distributed under the terms of the - * Q Public License 1.0, which can be found in the file LICENSE.QPL included in - * the packaging of this file. - * - * Alternatively, it may be distributed under the terms of the GNU General - * Public License, either version 2 or 3, which can be found in the file - * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this - * file. - */ - -#include "config.h" - -#include - -#import "TestsAppDelegate.h" - -static OFString *const module = @"OFHMAC"; -static const uint8_t key[] = - "yM9h8K6IWnJRvxC/0F8XRWG7RnACDBz8wqK2tbXrYVLoKC3vPLeJikyJSM47tVHc" - "DlXHww9zULAC2sJUlm2Kg1z4oz2aXY3Y1PQSB4VkC/m0DQ7hCI6cAg4TWnKdzWTy" - "cvYGX+Y6HWeDY79/PGSd8fNItme6I8w4HDBqU7BP2sum3jbePJqoiSnhcyJZQTeZ" - "jw0ZXoyrfHgOYD2M+NsTDaGpLblFtQ7n5CczjKtafG40PkEwx1dcrd46U9i3GyTK"; -static const size_t keyLength = sizeof(key); -static const uint8_t MD5Digest[] = - "\xCC\x1F\xEF\x09\x29\xA3\x25\x1A\x06\xA9\x83\x99\xF9\xBC\x8F\x42"; -static const uint8_t SHA1Digest[] = - "\x94\xB9\x0A\x6F\xFB\xA7\x13\x6A\x75\x55" - "\xD5\x7F\x5D\xB7\xF4\xCA\xEB\x4A\xDE\xBF"; -static const uint8_t RIPEMD160Digest[] = - "\x2C\xE1\xED\x41\xC6\xF3\x51\xA8\x04\xD2" - "\xC3\x9B\x08\x33\x3B\xD5\xC9\x00\x39\x50"; -static const uint8_t SHA256Digest[] = - "\xFB\x8C\xDA\x88\xB3\x81\x32\x16\xD7\xD8\x62\xD4\xA6\x26\x9D\x77" - "\x01\x99\x62\x65\x29\x02\x41\xE6\xEF\xA1\x02\x31\xA8\x9D\x77\x5D"; -static const uint8_t SHA384Digest[] = - "\x2F\x4A\x47\xAE\x13\x8E\x96\x52\xF1\x8F\x05\xFD\x65\xCD\x9A\x97" - "\x93\x2F\xC9\x02\xD6\xC6\xAB\x2E\x15\x76\xC0\xA7\xA0\x05\xF4\xEF" - "\x14\x52\x33\x4B\x9C\x5F\xD8\x07\x4E\x98\xAE\x97\x46\x29\x24\xB4"; -static const uint8_t SHA512Digest[] = - "\xF5\x8C\x3F\x9C\xA2\x2F\x0A\xF3\x26\xD8\xC0\x7E\x20\x63\x88\x61" - "\xC9\xE1\x1F\xD7\xC7\xE5\x59\x33\xD5\x2F\xAF\x56\x1C\x94\xC8\xA4" - "\x61\xB3\xF9\x1A\xE3\x09\x43\xA6\x5B\x85\xB1\x50\x5B\xCB\x1A\x2E" - "\xB7\xE8\x87\xC1\x73\x19\x63\xF6\xA2\x91\x8D\x7E\x2E\xCC\xEC\x99"; - -@implementation TestsAppDelegate (OFHMACTests) -- (void)HMACTests -{ - void *pool = objc_autoreleasePoolPush(); - OFIRI *IRI = [OFIRI IRIWithString: @"embedded:testfile.bin"]; - OFStream *file = [OFIRIHandler openItemAtIRI: IRI mode: @"r"]; - OFHMAC *HMACMD5, *HMACSHA1, *HMACRMD160; - OFHMAC *HMACSHA256, *HMACSHA384, *HMACSHA512; - - TEST(@"+[HMACWithHashClass:] with MD5", - (HMACMD5 = [OFHMAC HMACWithHashClass: [OFMD5Hash class] - allowsSwappableMemory: true])) - TEST(@"+[HMACWithHashClass:] with SHA-1", - (HMACSHA1 = [OFHMAC HMACWithHashClass: [OFSHA1Hash class] - allowsSwappableMemory: true])) - TEST(@"+[HMACWithHashClass:] with RIPEMD-160", - (HMACRMD160 = [OFHMAC HMACWithHashClass: [OFRIPEMD160Hash class] - allowsSwappableMemory: true])) - TEST(@"+[HMACWithHashClass:] with SHA-256", - (HMACSHA256 = [OFHMAC HMACWithHashClass: [OFSHA256Hash class] - allowsSwappableMemory: true])) - TEST(@"+[HMACWithHashClass:] with SHA-384", - (HMACSHA384 = [OFHMAC HMACWithHashClass: [OFSHA384Hash class] - allowsSwappableMemory: true])) - TEST(@"+[HMACWithHashClass:] with SHA-512", - (HMACSHA512 = [OFHMAC HMACWithHashClass: [OFSHA512Hash class] - allowsSwappableMemory: true])) - - EXPECT_EXCEPTION(@"Detection of missing key", - OFInvalidArgumentException, - [HMACMD5 updateWithBuffer: "" length: 0]) - - TEST(@"-[setKey:length:] with MD5", - R([HMACMD5 setKey: key length: keyLength])) - TEST(@"-[setKey:length:] with SHA-1", - R([HMACSHA1 setKey: key length: keyLength])) - TEST(@"-[setKey:length:] with RIPEMD-160", - R([HMACRMD160 setKey: key length: keyLength])) - TEST(@"-[setKey:length:] with SHA-256", - R([HMACSHA256 setKey: key length: keyLength])) - TEST(@"-[setKey:length:] with SHA-384", - R([HMACSHA384 setKey: key length: keyLength])) - TEST(@"-[setKey:length:] with SHA-512", - R([HMACSHA512 setKey: key length: keyLength])) - - while (!file.atEndOfStream) { - char buffer[64]; - size_t length = [file readIntoBuffer: buffer length: 64]; - [HMACMD5 updateWithBuffer: buffer length: length]; - [HMACSHA1 updateWithBuffer: buffer length: length]; - [HMACRMD160 updateWithBuffer: buffer length: length]; - [HMACSHA256 updateWithBuffer: buffer length: length]; - [HMACSHA384 updateWithBuffer: buffer length: length]; - [HMACSHA512 updateWithBuffer: buffer length: length]; - } - [file close]; - - TEST(@"-[calculate] with MD5", R([HMACMD5 calculate])) - TEST(@"-[calculate] with SHA-1", R([HMACSHA1 calculate])) - TEST(@"-[calculate] with RIPEMD-160", R([HMACRMD160 calculate])) - TEST(@"-[calculate] with SHA-256", R([HMACSHA256 calculate])) - TEST(@"-[calculate] with SHA-384", R([HMACSHA384 calculate])) - TEST(@"-[calculate] with SHA-512", R([HMACSHA512 calculate])) - - TEST(@"-[digest] with MD5", - memcmp(HMACMD5.digest, MD5Digest, HMACMD5.digestSize) == 0) - TEST(@"-[digest] with SHA-1", - memcmp(HMACSHA1.digest, SHA1Digest, HMACSHA1.digestSize) == 0) - TEST(@"-[digest] with RIPEMD-160", - memcmp(HMACRMD160.digest, RIPEMD160Digest, - HMACRMD160.digestSize) == 0) - TEST(@"-[digest] with SHA-256", - memcmp(HMACSHA256.digest, SHA256Digest, HMACSHA256.digestSize) == 0) - TEST(@"-[digest] with SHA-384", - memcmp(HMACSHA384.digest, SHA384Digest, HMACSHA384.digestSize) == 0) - TEST(@"-[digest] with SHA-512", - memcmp(HMACSHA512.digest, SHA512Digest, HMACSHA512.digestSize) == 0) - - objc_autoreleasePoolPop(pool); -} -@end DELETED tests/OFINIFileTests.m Index: tests/OFINIFileTests.m ================================================================== --- tests/OFINIFileTests.m +++ tests/OFINIFileTests.m @@ -1,138 +0,0 @@ -/* - * Copyright (c) 2008-2024 Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It may be distributed under the terms of the - * Q Public License 1.0, which can be found in the file LICENSE.QPL included in - * the packaging of this file. - * - * Alternatively, it may be distributed under the terms of the GNU General - * Public License, either version 2 or 3, which can be found in the file - * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this - * file. - */ - -#include "config.h" - -#import "TestsAppDelegate.h" - -static OFString *module; - -@implementation TestsAppDelegate (OFINIFileTests) -- (void)INIFileTests -{ - void *pool = objc_autoreleasePoolPush(); - OFString *output = @"[tests]\r\n" - @"foo=baz\r\n" - @"foobar=baz\r\n" - @";comment\r\n" - @"new=new\r\n" - @"\r\n" - @"[foobar]\r\n" - @";foobarcomment\r\n" - @"qux=\" asd\"\r\n" - @"quxquxqux=\"hello\\\"wörld\"\r\n" - @"qux2=\"a\\f\"\r\n" - @"qux3=a\fb\r\n" - @"\r\n" - @"[types]\r\n" - @"integer=16\r\n" - @"bool=false\r\n" - @"float=0.25\r\n" - @"array1=foo\r\n" - @"array1=bar\r\n" - @"double=0.75\r\n"; - OFIRI *IRI; - OFINIFile *file; - OFINICategory *tests, *foobar, *types; - OFArray *array; -#if defined(OF_HAVE_FILES) && !defined(OF_NINTENDO_DS) - OFIRI *writeIRI; -#endif - - module = @"OFINIFile"; - - IRI = [OFIRI IRIWithString: @"embedded:testfile.ini"]; - TEST(@"+[fileWithIRI:encoding:]", - (file = [OFINIFile fileWithIRI: IRI - encoding: OFStringEncodingCodepage437])) - - tests = [file categoryForName: @"tests"]; - foobar = [file categoryForName: @"foobar"]; - types = [file categoryForName: @"types"]; - TEST(@"-[categoryForName:]", - tests != nil && foobar != nil && types != nil) - - module = @"OFINICategory"; - - TEST(@"-[stringValueForKey:]", - [[tests stringValueForKey: @"foo"] isEqual: @"bar"] && - [[foobar stringValueForKey: @"quxquxqux"] isEqual: @"hello\"wörld"]) - - TEST(@"-[setStringValue:forKey:]", - R([tests setStringValue: @"baz" forKey: @"foo"]) && - R([tests setStringValue: @"new" forKey: @"new"]) && - R([foobar setStringValue: @"a\fb" forKey: @"qux3"])) - - TEST(@"-[longLongValueForKey:defaultValue:]", - [types longLongValueForKey: @"integer" defaultValue: 2] == 0x20) - - TEST(@"-[setLongLongValue:forKey:]", - R([types setLongLongValue: 0x10 forKey: @"integer"])) - - TEST(@"-[boolValueForKey:defaultValue:]", - [types boolValueForKey: @"bool" defaultValue: false] == true) - - TEST(@"-[setBoolValue:forKey:]", - R([types setBoolValue: false forKey: @"bool"])) - - TEST(@"-[floatValueForKey:defaultValue:]", - [types floatValueForKey: @"float" defaultValue: 1] == 0.5f) - - TEST(@"-[setFloatValue:forKey:]", - R([types setFloatValue: 0.25f forKey: @"float"])) - - TEST(@"-[doubleValueForKey:defaultValue:]", - [types doubleValueForKey: @"double" defaultValue: 3] == 0.25) - - TEST(@"-[setDoubleValue:forKey:]", - R([types setDoubleValue: 0.75 forKey: @"double"])) - - array = [OFArray arrayWithObjects: @"1", @"2", nil]; - TEST(@"-[arrayValueForKey:]", - [[types arrayValueForKey: @"array1"] isEqual: array] && - [[types arrayValueForKey: @"array2"] isEqual: array] && - [[types arrayValueForKey: @"array3"] isEqual: [OFArray array]]) - - array = [OFArray arrayWithObjects: @"foo", @"bar", nil]; - TEST(@"-[setArrayValue:forKey:]", - R([types setArrayValue: array forKey: @"array1"])) - - TEST(@"-[removeValueForKey:]", - R([foobar removeValueForKey: @"quxqux "]) && - R([types removeValueForKey: @"array2"])) - - module = @"OFINIFile"; - - /* FIXME: Find a way to write files on Nintendo DS */ -#if defined(OF_HAVE_FILES) && !defined(OF_NINTENDO_DS) - writeIRI = [OFSystemInfo temporaryDirectoryIRI]; - if (writeIRI == nil) - writeIRI = [[OFFileManager defaultManager] currentDirectoryIRI]; - writeIRI = [writeIRI IRIByAppendingPathComponent: @"objfw-tests.ini" - isDirectory: false]; - TEST(@"-[writeToFile:encoding:]", - R([file writeToIRI: writeIRI - encoding: OFStringEncodingCodepage437]) && - [[OFString stringWithContentsOfIRI: writeIRI - encoding: OFStringEncodingCodepage437] - isEqual: output]) - [[OFFileManager defaultManager] removeItemAtIRI: writeIRI]; -#else - (void)output; -#endif - - objc_autoreleasePoolPop(pool); -} -@end DELETED tests/OFIRITests.m Index: tests/OFIRITests.m ================================================================== --- tests/OFIRITests.m +++ tests/OFIRITests.m @@ -1,371 +0,0 @@ -/* - * Copyright (c) 2008-2024 Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It may be distributed under the terms of the - * Q Public License 1.0, which can be found in the file LICENSE.QPL included in - * the packaging of this file. - * - * Alternatively, it may be distributed under the terms of the GNU General - * Public License, either version 2 or 3, which can be found in the file - * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this - * file. - */ - -#include "config.h" - -#import "TestsAppDelegate.h" - -static OFString *const module = @"OFIRI"; -static OFString *IRIString = @"ht+tp://us%3Aer:p%40w@ho%3Ast:1234/" - @"pa%3Fth?que%23ry=1&f%26oo=b%3dar#frag%23ment"; - -@implementation TestsAppDelegate (OFIRITests) -- (void)IRITests -{ - void *pool = objc_autoreleasePoolPush(); - OFIRI *IRI1, *IRI2, *IRI3, *IRI4, *IRI5, *IRI6, *IRI7, *IRI8, *IRI9; - OFIRI *IRI10, *IRI11; - OFMutableIRI *mutableIRI; - - TEST(@"+[IRIWithString:]", - R(IRI1 = [OFIRI IRIWithString: IRIString]) && - R(IRI2 = [OFIRI IRIWithString: @"http://foo:80"]) && - R(IRI3 = [OFIRI IRIWithString: @"http://bar/"]) && - R(IRI4 = [OFIRI IRIWithString: @"file:///etc/passwd"]) && - R(IRI5 = [OFIRI IRIWithString: @"http://foo/bar/qux/foo%2fbar"]) && - R(IRI6 = [OFIRI IRIWithString: @"https://[12:34::56:abcd]/"]) && - R(IRI7 = [OFIRI IRIWithString: @"https://[12:34::56:abcd]:234/"]) && - R(IRI8 = [OFIRI IRIWithString: @"urn:qux:foo"]) && - R(IRI9 = [OFIRI IRIWithString: @"file:/foo?query#frag"]) && - R(IRI10 = [OFIRI IRIWithString: @"file:foo@bar/qux?query#frag"]) && - R(IRI11 = [OFIRI IRIWithString: @"http://ä/ö?ü"])) - - EXPECT_EXCEPTION(@"+[IRIWithString:] fails with invalid characters #1", - OFInvalidFormatException, - [OFIRI IRIWithString: @"ht,tp://foo"]) - - EXPECT_EXCEPTION(@"+[IRIWithString:] fails with invalid characters #2", - OFInvalidFormatException, - [OFIRI IRIWithString: @"http://f`oo"]) - - EXPECT_EXCEPTION(@"+[IRIWithString:] fails with invalid characters #3", - OFInvalidFormatException, - [OFIRI IRIWithString: @"http://foo/`"]) - - EXPECT_EXCEPTION(@"+[IRIWithString:] fails with invalid characters #4", - OFInvalidFormatException, - [OFIRI IRIWithString: @"http://foo/foo?`"]) - - EXPECT_EXCEPTION(@"+[IRIWithString:] fails with invalid characters #5", - OFInvalidFormatException, - [OFIRI IRIWithString: @"http://foo/foo?foo#`"]) - - EXPECT_EXCEPTION(@"+[IRIWithString:] fails with invalid characters #6", - OFInvalidFormatException, - [OFIRI IRIWithString: @"https://[g]/"]) - - EXPECT_EXCEPTION(@"+[IRIWithString:] fails with invalid characters #7", - OFInvalidFormatException, - [OFIRI IRIWithString: @"https://[f]:/"]) - - EXPECT_EXCEPTION(@"+[IRIWithString:] fails with invalid characters #8", - OFInvalidFormatException, - [OFIRI IRIWithString: @"https://[f]:f/"]) - - EXPECT_EXCEPTION(@"+[IRIWithString:] fails with invalid characters #9", - OFInvalidFormatException, - [OFIRI IRIWithString: @"foo:"]) - - TEST(@"+[IRIWithString:relativeToIRI:]", - [[[OFIRI IRIWithString: @"/foo" relativeToIRI: IRI1] string] - isEqual: @"ht+tp://us%3Aer:p%40w@ho%3Ast:1234/foo"] && - [[[OFIRI IRIWithString: @"foo/bar?q" - relativeToIRI: [OFIRI IRIWithString: @"http://h/qux/quux"]] - string] isEqual: @"http://h/qux/foo/bar?q"] && - [[[OFIRI IRIWithString: @"foo/bar" - relativeToIRI: [OFIRI IRIWithString: @"http://h/qux/?x"]] - string] isEqual: @"http://h/qux/foo/bar"] && - [[[OFIRI IRIWithString: @"http://foo/?q" - relativeToIRI: IRI1] string] isEqual: @"http://foo/?q"] && - [[[OFIRI IRIWithString: @"foo" - relativeToIRI: [OFIRI IRIWithString: @"http://foo/bar"]] - string] isEqual: @"http://foo/foo"] && - [[[OFIRI IRIWithString: @"foo" - relativeToIRI: [OFIRI IRIWithString: @"http://foo"]] - string] isEqual: @"http://foo/foo"]) - - EXPECT_EXCEPTION( - @"+[IRIWithString:relativeToIRI:] fails with invalid characters #1", - OFInvalidFormatException, - [OFIRI IRIWithString: @"`" relativeToIRI: IRI1]) - - EXPECT_EXCEPTION( - @"+[IRIWithString:relativeToIRI:] fails with invalid characters #2", - OFInvalidFormatException, - [OFIRI IRIWithString: @"/`" relativeToIRI: IRI1]) - - EXPECT_EXCEPTION( - @"+[IRIWithString:relativeToIRI:] fails with invalid characters #3", - OFInvalidFormatException, - [OFIRI IRIWithString: @"?`" relativeToIRI: IRI1]) - - EXPECT_EXCEPTION( - @"+[IRIWithString:relativeToIRI:] fails with invalid characters #4", - OFInvalidFormatException, - [OFIRI IRIWithString: @"#`" relativeToIRI: IRI1]) - -#ifdef OF_HAVE_FILES - TEST(@"+[fileIRIWithPath:]", - [[[OFIRI fileIRIWithPath: @"testfile.txt"] fileSystemRepresentation] - isEqual: [[OFFileManager defaultManager].currentDirectoryPath - stringByAppendingPathComponent: @"testfile.txt"]]) - -# if defined(OF_WINDOWS) || defined(OF_MSDOS) - OFIRI *tmp; - TEST(@"+[fileIRIWithPath:] for c:\\", - (tmp = [OFIRI fileIRIWithPath: @"c:\\"]) && - [tmp.string isEqual: @"file:/c:/"] && - [tmp.fileSystemRepresentation isEqual: @"c:\\"]) -# endif - -# ifdef OF_WINDOWS - TEST(@"+[fileIRIWithPath:] with UNC", - (tmp = [OFIRI fileIRIWithPath: @"\\\\foo\\bar" - isDirectory: false]) && - [tmp.host isEqual: @"foo"] && [tmp.path isEqual: @"/bar"] && - [tmp.string isEqual: @"file://foo/bar"] && - [tmp.fileSystemRepresentation isEqual: @"\\\\foo\\bar"] && - (tmp = [OFIRI fileIRIWithPath: @"\\\\test" isDirectory: true]) && - [tmp.host isEqual: @"test"] && [tmp.path isEqual: @"/"] && - [tmp.string isEqual: @"file://test/"] && - [tmp.fileSystemRepresentation isEqual: @"\\\\test"]) -# endif -#endif - - TEST(@"-[string]", - [IRI1.string isEqual: IRIString] && - [IRI2.string isEqual: @"http://foo:80"] && - [IRI3.string isEqual: @"http://bar/"] && - [IRI4.string isEqual: @"file:///etc/passwd"] && - [IRI5.string isEqual: @"http://foo/bar/qux/foo%2fbar"] && - [IRI6.string isEqual: @"https://[12:34::56:abcd]/"] && - [IRI7.string isEqual: @"https://[12:34::56:abcd]:234/"] && - [IRI8.string isEqual: @"urn:qux:foo"] && - [IRI9.string isEqual: @"file:/foo?query#frag"] && - [IRI10.string isEqual: @"file:foo@bar/qux?query#frag"] && - [IRI11.string isEqual: @"http://ä/ö?ü"]) - - TEST(@"-[scheme]", - [IRI1.scheme isEqual: @"ht+tp"] && [IRI4.scheme isEqual: @"file"] && - [IRI9.scheme isEqual: @"file"] && [IRI10.scheme isEqual: @"file"] && - [IRI11.scheme isEqual: @"http"]) - - TEST(@"-[user]", [IRI1.user isEqual: @"us:er"] && IRI4.user == nil && - IRI10.user == nil && IRI11.user == nil) - TEST(@"-[password]", - [IRI1.password isEqual: @"p@w"] && IRI4.password == nil && - IRI10.password == nil && IRI11.password == nil) - TEST(@"-[host]", [IRI1.host isEqual: @"ho:st"] && - [IRI6.host isEqual: @"12:34::56:abcd"] && - [IRI7.host isEqual: @"12:34::56:abcd"] && - IRI8.host == nil && IRI9.host == nil && IRI10.host == nil && - [IRI11.host isEqual: @"ä"]) - TEST(@"-[port]", IRI1.port.unsignedShortValue == 1234 && - [IRI4 port] == nil && IRI7.port.unsignedShortValue == 234 && - IRI8.port == nil && IRI9.port == nil && IRI10.port == nil && - IRI11.port == nil) - TEST(@"-[path]", - [IRI1.path isEqual: @"/pa?th"] && - [IRI4.path isEqual: @"/etc/passwd"] && - [IRI8.path isEqual: @"qux:foo"] && - [IRI9.path isEqual: @"/foo"] && - [IRI10.path isEqual: @"foo@bar/qux"] && - [IRI11.path isEqual: @"/ö"]) - TEST(@"-[pathComponents]", - [IRI1.pathComponents isEqual: - [OFArray arrayWithObjects: @"/", @"pa?th", nil]] && - [IRI4.pathComponents isEqual: - [OFArray arrayWithObjects: @"/", @"etc", @"passwd", nil]] && - [IRI5.pathComponents isEqual: - [OFArray arrayWithObjects: @"/", @"bar", @"qux", @"foo/bar", nil]]) - TEST(@"-[lastPathComponent]", - [[[OFIRI IRIWithString: @"http://host/foo//bar/baz"] - lastPathComponent] isEqual: @"baz"] && - [[[OFIRI IRIWithString: @"http://host/foo//bar/baz/"] - lastPathComponent] isEqual: @"baz"] && - [[[OFIRI IRIWithString: @"http://host/foo/"] - lastPathComponent] isEqual: @"foo"] && - [[[OFIRI IRIWithString: @"http://host/"] - lastPathComponent] isEqual: @"/"] && - [IRI5.lastPathComponent isEqual: @"foo/bar"]) - TEST(@"-[query]", - [IRI1.query isEqual: @"que#ry=1&f&oo=b=ar"] && IRI4.query == nil && - [IRI9.query isEqual: @"query"] && [IRI10.query isEqual: @"query"] && - [IRI11.query isEqual: @"ü"]) - TEST(@"-[queryItems]", - [IRI1.queryItems isEqual: [OFArray arrayWithObjects: - [OFPair pairWithFirstObject: @"que#ry" secondObject: @"1"], - [OFPair pairWithFirstObject: @"f&oo" secondObject: @"b=ar"], nil]]); - TEST(@"-[fragment]", - [IRI1.fragment isEqual: @"frag#ment"] && IRI4.fragment == nil && - [IRI9.fragment isEqual: @"frag"] && - [IRI10.fragment isEqual: @"frag"]) - - TEST(@"-[copy]", R(IRI4 = [[IRI1 copy] autorelease])) - - TEST(@"-[isEqual:]", [IRI1 isEqual: IRI4] && ![IRI2 isEqual: IRI3] && - [[OFIRI IRIWithString: @"HTTP://bar/"] isEqual: IRI3]) - - TEST(@"-[hash:]", IRI1.hash == IRI4.hash && IRI2.hash != IRI3.hash) - - EXPECT_EXCEPTION(@"Detection of invalid format", - OFInvalidFormatException, [OFIRI IRIWithString: @"http"]) - - TEST(@"-[IRIByAddingPercentEncodingForUnicodeCharacters]", - [IRI11.IRIByAddingPercentEncodingForUnicodeCharacters - isEqual: [OFIRI IRIWithString: @"http://%C3%A4/%C3%B6?%C3%BC"]]) - - mutableIRI = [OFMutableIRI IRIWithScheme: @"dummy"]; - - EXPECT_EXCEPTION( - @"-[setPercentEncodedScheme:] with invalid characters fails", - OFInvalidFormatException, mutableIRI.scheme = @"%20") - - TEST(@"-[setHost:]", - (mutableIRI.host = @"ho:st") && - [mutableIRI.percentEncodedHost isEqual: @"ho%3Ast"] && - (mutableIRI.host = @"12:34:ab") && - [mutableIRI.percentEncodedHost isEqual: @"[12:34:ab]"] && - (mutableIRI.host = @"12:34:aB") && - [mutableIRI.percentEncodedHost isEqual: @"[12:34:aB]"] && - (mutableIRI.host = @"12:34:g") && - [mutableIRI.percentEncodedHost isEqual: @"12%3A34%3Ag"]) - - TEST(@"-[setPercentEncodedHost:]", - (mutableIRI.percentEncodedHost = @"ho%3Ast") && - [mutableIRI.host isEqual: @"ho:st"] && - (mutableIRI.percentEncodedHost = @"[12:34]") && - [mutableIRI.host isEqual: @"12:34"] && - (mutableIRI.percentEncodedHost = @"[12::ab]") && - [mutableIRI.host isEqual: @"12::ab"]) - - EXPECT_EXCEPTION( - @"-[setPercentEncodedHost:] with invalid characters fails #1", - OFInvalidFormatException, - mutableIRI.percentEncodedHost = @"/") - - EXPECT_EXCEPTION( - @"-[setPercentEncodedHost:] with invalid characters fails #2", - OFInvalidFormatException, - mutableIRI.percentEncodedHost = @"[12:34") - - EXPECT_EXCEPTION( - @"-[setPercentEncodedHost:] with invalid characters fails #3", - OFInvalidFormatException, - mutableIRI.percentEncodedHost = @"[a::g]") - - TEST(@"-[setUser:]", - (mutableIRI.user = @"us:er") && - [mutableIRI.percentEncodedUser isEqual: @"us%3Aer"]) - - TEST(@"-[setPercentEncodedUser:]", - (mutableIRI.percentEncodedUser = @"us%3Aer") && - [mutableIRI.user isEqual: @"us:er"]) - - EXPECT_EXCEPTION( - @"-[setPercentEncodedUser:] with invalid characters fails", - OFInvalidFormatException, - mutableIRI.percentEncodedHost = @"/") - - TEST(@"-[setPassword:]", - (mutableIRI.password = @"pass:word") && - [mutableIRI.percentEncodedPassword isEqual: @"pass%3Aword"]) - - TEST(@"-[setPercentEncodedPassword:]", - (mutableIRI.percentEncodedPassword = @"pass%3Aword") && - [mutableIRI.password isEqual: @"pass:word"]) - - EXPECT_EXCEPTION( - @"-[setPercentEncodedPassword:] with invalid characters fails", - OFInvalidFormatException, - mutableIRI.percentEncodedPassword = @"/") - - TEST(@"-[setPath:]", - (mutableIRI.path = @"pa/th@?") && - [mutableIRI.percentEncodedPath isEqual: @"pa/th@%3F"]) - - TEST(@"-[setPercentEncodedPath:]", - (mutableIRI.percentEncodedPath = @"pa/th@%3F") && - [mutableIRI.path isEqual: @"pa/th@?"]) - - EXPECT_EXCEPTION( - @"-[setPercentEncodedPath:] with invalid characters fails", - OFInvalidFormatException, - mutableIRI.percentEncodedPath = @"?") - - TEST(@"-[setQuery:]", - (mutableIRI.query = @"que/ry?#") && - [mutableIRI.percentEncodedQuery isEqual: @"que/ry?%23"]) - - TEST(@"-[setPercentEncodedQuery:]", - (mutableIRI.percentEncodedQuery = @"que/ry?%23") && - [mutableIRI.query isEqual: @"que/ry?#"]) - - EXPECT_EXCEPTION( - @"-[setPercentEncodedQuery:] with invalid characters fails", - OFInvalidFormatException, - mutableIRI.percentEncodedQuery = @"`") - - TEST(@"-[setQueryItems:]", - (mutableIRI.queryItems = [OFArray arrayWithObjects: - [OFPair pairWithFirstObject: @"foo&bar" secondObject: @"baz=qux"], - [OFPair pairWithFirstObject: @"f=oobar" secondObject: @"b&azqux"], - nil]) && [mutableIRI.percentEncodedQuery isEqual: - @"foo%26bar=baz%3Dqux&f%3Doobar=b%26azqux"]) - - TEST(@"-[setFragment:]", - (mutableIRI.fragment = @"frag/ment?#") && - [mutableIRI.percentEncodedFragment isEqual: @"frag/ment?%23"]) - - TEST(@"-[setPercentEncodedFragment:]", - (mutableIRI.percentEncodedFragment = @"frag/ment?%23") && - [mutableIRI.fragment isEqual: @"frag/ment?#"]) - - EXPECT_EXCEPTION( - @"-[setPercentEncodedFragment:] with invalid characters fails", - OFInvalidFormatException, - mutableIRI.percentEncodedFragment = @"`") - - TEST(@"-[IRIByAppendingPathComponent:isDirectory:]", - [[[OFIRI IRIWithString: @"file:///foo/bar"] - IRIByAppendingPathComponent: @"qux" isDirectory: false] isEqual: - [OFIRI IRIWithString: @"file:///foo/bar/qux"]] && - [[[OFIRI IRIWithString: @"file:///foo/bar/"] - IRIByAppendingPathComponent: @"qux" isDirectory: false] isEqual: - [OFIRI IRIWithString: @"file:///foo/bar/qux"]] && - [[[OFIRI IRIWithString: @"file:///foo/bar/"] - IRIByAppendingPathComponent: @"qu?x" isDirectory: false] isEqual: - [OFIRI IRIWithString: @"file:///foo/bar/qu%3Fx"]] && - [[[OFIRI IRIWithString: @"file:///foo/bar/"] - IRIByAppendingPathComponent: @"qu?x" isDirectory: true] isEqual: - [OFIRI IRIWithString: @"file:///foo/bar/qu%3Fx/"]]) - - TEST(@"-[IRIByStandardizingPath]", - [[[OFIRI IRIWithString: @"http://foo/bar/.."] - IRIByStandardizingPath] isEqual: - [OFIRI IRIWithString: @"http://foo/"]] && - [[[OFIRI IRIWithString: @"http://foo/bar/%2E%2E/../qux/"] - IRIByStandardizingPath] isEqual: - [OFIRI IRIWithString: @"http://foo/bar/qux/"]] && - [[[OFIRI IRIWithString: @"http://foo/bar/./././qux/./"] - IRIByStandardizingPath] isEqual: - [OFIRI IRIWithString: @"http://foo/bar/qux/"]] && - [[[OFIRI IRIWithString: @"http://foo/bar/../../qux"] - IRIByStandardizingPath] isEqual: - [OFIRI IRIWithString: @"http://foo/../qux"]]) - - objc_autoreleasePoolPop(pool); -} -@end DELETED tests/OFInvocationTests.m Index: tests/OFInvocationTests.m ================================================================== --- tests/OFInvocationTests.m +++ tests/OFInvocationTests.m @@ -1,95 +0,0 @@ -/* - * Copyright (c) 2008-2024 Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It may be distributed under the terms of the - * Q Public License 1.0, which can be found in the file LICENSE.QPL included in - * the packaging of this file. - * - * Alternatively, it may be distributed under the terms of the GNU General - * Public License, either version 2 or 3, which can be found in the file - * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this - * file. - */ - -#include "config.h" - -#include - -#if defined(HAVE_COMPLEX_H) && !defined(__STDC_NO_COMPLEX__) -# include -#endif - -#import "TestsAppDelegate.h" - -static OFString *const module = @"OFInvocation"; - -struct TestStruct { - unsigned char c; - unsigned int i; -}; - -@implementation TestsAppDelegate (OFInvocationTests) -- (struct TestStruct)invocationTestMethod1: (unsigned char)c - : (unsigned int)i - : (struct TestStruct *)ptr - : (struct TestStruct)st -{ - return st; -} - -- (void)invocationTests -{ - void *pool = objc_autoreleasePoolPush(); - SEL selector = @selector(invocationTestMethod1::::); - OFMethodSignature *sig = [self methodSignatureForSelector: selector]; - OFInvocation *invocation; - struct TestStruct st, st2, *stp = &st, *stp2; - unsigned const char c = 0xAA; - unsigned char c2; - const unsigned int i = 0x55555555; - unsigned int i2; - - memset(&st, '\xFF', sizeof(st)); - st.c = 0x55; - st.i = 0xAAAAAAAA; - - TEST(@"+[invocationWithMethodSignature:]", - (invocation = [OFInvocation invocationWithMethodSignature: sig])) - - TEST(@"-[setReturnValue]", R([invocation setReturnValue: &st])) - - TEST(@"-[getReturnValue]", R([invocation getReturnValue: &st2]) && - memcmp(&st, &st2, sizeof(st)) == 0) - - memset(&st2, '\0', sizeof(st2)); - - TEST(@"-[setArgument:atIndex:] #1", - R([invocation setArgument: &c atIndex: 2])) - - TEST(@"-[setArgument:atIndex:] #2", - R([invocation setArgument: &i atIndex: 3])) - - TEST(@"-[setArgument:atIndex:] #3", - R([invocation setArgument: &stp atIndex: 4])) - - TEST(@"-[setArgument:atIndex:] #4", - R([invocation setArgument: &st atIndex: 5])) - - TEST(@"-[getArgument:atIndex:] #1", - R([invocation getArgument: &c2 atIndex: 2]) && c == c2) - - TEST(@"-[getArgument:atIndex:] #2", - R([invocation getArgument: &i2 atIndex: 3]) && i == i2) - - TEST(@"-[getArgument:atIndex:] #3", - R([invocation getArgument: &stp2 atIndex: 4]) && stp == stp2) - - TEST(@"-[getArgument:atIndex:] #4", - R([invocation getArgument: &st2 atIndex: 5]) && - memcmp(&st, &st2, sizeof(st)) == 0) - - objc_autoreleasePoolPop(pool); -} -@end DELETED tests/OFJSONTests.m Index: tests/OFJSONTests.m ================================================================== --- tests/OFJSONTests.m +++ tests/OFJSONTests.m @@ -1,92 +0,0 @@ -/* - * Copyright (c) 2008-2024 Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It may be distributed under the terms of the - * Q Public License 1.0, which can be found in the file LICENSE.QPL included in - * the packaging of this file. - * - * Alternatively, it may be distributed under the terms of the GNU General - * Public License, either version 2 or 3, which can be found in the file - * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this - * file. - */ - -#include "config.h" - -#import "TestsAppDelegate.h" - -static OFString *const module = @"OFJSON"; - -@implementation TestsAppDelegate (JSONTests) -- (void)JSONTests -{ - void *pool = objc_autoreleasePoolPush(); - OFString *string = @"{\"foo\"\t:'b\\na\\r', \"x\":/*foo*/ [.5\r,0xF," - @"null//bar\n,\"foo\",false]}"; - OFDictionary *dict = [OFDictionary dictionaryWithKeysAndObjects: - @"foo", @"b\na\r", - @"x", [OFArray arrayWithObjects: - [OFNumber numberWithFloat: .5f], - [OFNumber numberWithInt: 0xF], - [OFNull null], - @"foo", - [OFNumber numberWithBool: false], - nil], - nil]; - - TEST(@"-[objectByParsingJSON] #1", - [string.objectByParsingJSON isEqual: dict]) - - TEST(@"-[JSONRepresentation]", - [[dict JSONRepresentation] isEqual: - @"{\"x\":[0.5,15,null,\"foo\",false],\"foo\":\"b\\na\\r\"}"]) - - TEST(@"OFJSONRepresentationOptionPretty", - [[dict JSONRepresentationWithOptions: - OFJSONRepresentationOptionPretty] isEqual: - @"{\n\t\"x\": [\n\t\t0.5,\n\t\t15,\n\t\tnull,\n\t\t" - @"\"foo\",\n\t\tfalse\n\t],\n\t\"foo\": \"b\\na\\r\"\n}"]) - - TEST(@"OFJSONRepresentationOptionJSON5", - [[dict JSONRepresentationWithOptions: - OFJSONRepresentationOptionJSON5] isEqual: - @"{x:[0.5,15,null,\"foo\",false],foo:\"b\\\na\\r\"}"]) - - EXPECT_EXCEPTION(@"-[objectByParsingJSON] #2", OFInvalidJSONException, - [@"{" objectByParsingJSON]) - EXPECT_EXCEPTION(@"-[objectByParsingJSON] #3", OFInvalidJSONException, - [@"]" objectByParsingJSON]) - EXPECT_EXCEPTION(@"-[objectByParsingJSON] #4", OFInvalidJSONException, - [@"bar" objectByParsingJSON]) - EXPECT_EXCEPTION(@"-[objectByParsingJSON] #5", OFInvalidJSONException, - [@"[\"a\" \"b\"]" objectByParsingJSON]) - - TEST(@"-[objectByParsingJSON] #6", - [@"[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[{}]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]" - .objectByParsingJSON isEqual: [OFArray arrayWithObject: - [OFArray arrayWithObject: [OFArray arrayWithObject: - [OFArray arrayWithObject: [OFArray arrayWithObject: - [OFArray arrayWithObject: [OFArray arrayWithObject: - [OFArray arrayWithObject: [OFArray arrayWithObject: - [OFArray arrayWithObject: [OFArray arrayWithObject: - [OFArray arrayWithObject: [OFArray arrayWithObject: - [OFArray arrayWithObject: [OFArray arrayWithObject: - [OFArray arrayWithObject: [OFArray arrayWithObject: - [OFArray arrayWithObject: [OFArray arrayWithObject: - [OFArray arrayWithObject: [OFArray arrayWithObject: - [OFArray arrayWithObject: [OFArray arrayWithObject: - [OFArray arrayWithObject: [OFArray arrayWithObject: - [OFArray arrayWithObject: [OFArray arrayWithObject: - [OFArray arrayWithObject: [OFArray arrayWithObject: - [OFArray arrayWithObject: - [OFDictionary dictionary]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]) - - EXPECT_EXCEPTION(@"-[objectByParsingJSON] #7", OFInvalidJSONException, - [@"[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[{}]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]" - objectByParsingJSON]) - - objc_autoreleasePoolPop(pool); -} -@end DELETED tests/OFMD5HashTests.m Index: tests/OFMD5HashTests.m ================================================================== --- tests/OFMD5HashTests.m +++ tests/OFMD5HashTests.m @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2008-2024 Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It may be distributed under the terms of the - * Q Public License 1.0, which can be found in the file LICENSE.QPL included in - * the packaging of this file. - * - * Alternatively, it may be distributed under the terms of the GNU General - * Public License, either version 2 or 3, which can be found in the file - * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this - * file. - */ - -#include "config.h" - -#include - -#import "TestsAppDelegate.h" - -static OFString *const module = @"OFMD5Hash"; - -const uint8_t testFileMD5[16] = - "\x00\x8B\x9D\x1B\x58\xDF\xF8\xFE\xEE\xF3\xAE\x8D\xBB\x68\x2D\x38"; - -@implementation TestsAppDelegate (OFMD5HashTests) -- (void)MD5HashTests -{ - void *pool = objc_autoreleasePoolPush(); - OFMD5Hash *MD5, *MD5Copy; - OFIRI *IRI = [OFIRI IRIWithString: @"embedded:testfile.bin"]; - OFStream *file = [OFIRIHandler openItemAtIRI: IRI mode: @"r"]; - - TEST(@"+[hashWithAllowsSwappableMemory:]", - (MD5 = [OFMD5Hash hashWithAllowsSwappableMemory: true])) - - while (!file.atEndOfStream) { - char buffer[64]; - size_t length = [file readIntoBuffer: buffer length: 64]; - [MD5 updateWithBuffer: buffer length: length]; - } - [file close]; - - TEST(@"-[copy]", (MD5Copy = [[MD5 copy] autorelease])) - - TEST(@"-[calculate]", R([MD5 calculate]) && R([MD5Copy calculate])) - - TEST(@"-[digest]", - memcmp(MD5.digest, testFileMD5, 16) == 0 && - memcmp(MD5Copy.digest, testFileMD5, 16) == 0) - - EXPECT_EXCEPTION(@"Detect invalid call of " - @"-[updateWithBuffer:length]", OFHashAlreadyCalculatedException, - [MD5 updateWithBuffer: "" length: 1]) - - objc_autoreleasePoolPop(pool); -} -@end DELETED tests/OFMatrix4x4Tests.m Index: tests/OFMatrix4x4Tests.m ================================================================== --- tests/OFMatrix4x4Tests.m +++ tests/OFMatrix4x4Tests.m @@ -1,106 +0,0 @@ -/* - * Copyright (c) 2008-2024 Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It may be distributed under the terms of the - * Q Public License 1.0, which can be found in the file LICENSE.QPL included in - * the packaging of this file. - * - * Alternatively, it may be distributed under the terms of the GNU General - * Public License, either version 2 or 3, which can be found in the file - * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this - * file. - */ - -#include "config.h" - -#import "TestsAppDelegate.h" - -static OFString *const module = @"OFMatrix4x4Tests"; - -@implementation TestsAppDelegate (OFMatrix4x4Tests) -- (void)matrix4x4Tests -{ - void *pool = objc_autoreleasePoolPush(); - OFMatrix4x4 *matrix, *matrix2; - OFVector4D point; - OFVector4D points[2] = {{ 1, 2, 3, 1 }, { 7, 8, 9, 2 }}; - - TEST(@"+[identityMatrix]", - memcmp([[OFMatrix4x4 identityMatrix] values], (const float [4][4]){ - { 1, 0, 0, 0 }, - { 0, 1, 0, 0 }, - { 0, 0, 1, 0 }, - { 0, 0, 0, 1 } - }, 16 * sizeof(float)) == 0) - - TEST(@"+[matrixWithValues:]", - (matrix = [OFMatrix4x4 matrixWithValues: (const float [4][4]){ - { 1, 2, 3, 4 }, - { 5, 6, 7, 8 }, - { 9, 10, 11, 12 }, - { 13, 14, 15, 16 } - }])) - - TEST(@"-[description]", - [matrix.description isEqual: @""]) - - TEST(@"-[isEqual:]", [[OFMatrix4x4 identityMatrix] isEqual: - [OFMatrix4x4 matrixWithValues: (const float [4][4]){ - { 1, 0, 0, 0 }, - { 0, 1, 0, 0 }, - { 0, 0, 1, 0 }, - { 0, 0, 0, 1 } - }]]) - - TEST(@"-[copy]", (matrix2 = [[matrix copy] autorelease]) && - [matrix2 isEqual: matrix]) - - TEST(@"-[multiplyWithMatrix:] #1", - R([matrix2 multiplyWithMatrix: [OFMatrix4x4 identityMatrix]]) && - [matrix2 isEqual: matrix]) - - matrix2 = [OFMatrix4x4 matrixWithValues: (const float [4][4]){ - { 100, 200, 300, 400 }, - { 500, 600, 700, 800 }, - { 900, 1000, 1100, 1200 }, - { 1300, 1400, 1500, 1600 } - }]; - TEST(@"-[multiplyWithMatrix:] #2", - R([matrix2 multiplyWithMatrix: matrix]) && - [matrix2 isEqual: - [OFMatrix4x4 matrixWithValues: (const float [4][4]){ - { 9000, 10000, 11000, 12000 }, - { 20200, 22800, 25400, 28000 }, - { 31400, 35600, 39800, 44000 }, - { 42600, 48400, 54200, 60000 } - }]]) - - TEST(@"-[translateWithVector:]", - (matrix2 = [OFMatrix4x4 identityMatrix]) && - R([matrix2 translateWithVector: OFMakeVector3D(1, 2, 3)]) && - R(point = - [matrix2 transformedVector: OFMakeVector4D(2, 3, 4, 1)]) && - point.x == 3 && point.y == 5 && point.z == 7 && point.w == 1) - - TEST(@"-[scaleWithVector:]", - R([matrix2 scaleWithVector: OFMakeVector3D(-1, 0.5f, 2)]) && - R(point = - [matrix2 transformedVector: OFMakeVector4D(2, 3, 4, 1)]) && - point.x == -3 && point.y == 2.5 && point.z == 14 && point.w == 1) - - TEST(@"-[transformVectors:count:]", - R([matrix transformVectors: points count: 2]) && - points[0].x == 18 && points[0].y == 46 && points[0].z == 74 && - points[0].w == 102 && points[1].x == 58 && points[1].y == 162 && - points[1].z == 266 && points[1].w == 370) - - objc_autoreleasePoolPop(pool); -} -@end DELETED tests/OFMethodSignatureTests.m Index: tests/OFMethodSignatureTests.m ================================================================== --- tests/OFMethodSignatureTests.m +++ tests/OFMethodSignatureTests.m @@ -1,181 +0,0 @@ -/* - * Copyright (c) 2008-2024 Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It may be distributed under the terms of the - * Q Public License 1.0, which can be found in the file LICENSE.QPL included in - * the packaging of this file. - * - * Alternatively, it may be distributed under the terms of the GNU General - * Public License, either version 2 or 3, which can be found in the file - * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this - * file. - */ - -#include "config.h" - -#include - -#if !defined(__STDC_NO_COMPLEX__) && defined(HAVE_COMPLEX_H) -# include -#endif - -#import "TestsAppDelegate.h" - -static OFString *const module = @"OFMethodSignature"; - -struct Test1Struct { - char c; - int i; - char d; -}; - -struct Test2Struct { - char c; - struct { - short s; - int i; - } st; - union { - char c; - int i; - } u; - double d; -}; - -#if !defined(__STDC_NO_COMPLEX__) && defined(HAVE_COMPLEX_H) -struct Test3Struct { - char c; - complex double cd; -}; -#endif - -union Test3Union { - char c; - int i; - double d; -}; - -union Test4Union { - char c; - struct { - short x, y; - } st; - int i; - union { - float f; - double d; - } u; -}; - -@implementation TestsAppDelegate (OFMethodSignatureTests) -- (void)methodSignatureTests -{ - void *pool = objc_autoreleasePoolPush(); - OFMethodSignature *methodSignature; - - TEST(@"-[signatureWithObjCTypes:] #1", - (methodSignature = [OFMethodSignature signatureWithObjCTypes: - "i28@0:8S16*20"]) && - methodSignature.numberOfArguments == 4 && - strcmp(methodSignature.methodReturnType, "i") == 0 && - strcmp([methodSignature argumentTypeAtIndex: 0], "@") == 0 && - strcmp([methodSignature argumentTypeAtIndex: 1], ":") == 0 && - strcmp([methodSignature argumentTypeAtIndex: 2], "S") == 0 && - strcmp([methodSignature argumentTypeAtIndex: 3], "*") == 0 && - methodSignature.frameLength == 28 && - [methodSignature argumentOffsetAtIndex: 0] == 0 && - [methodSignature argumentOffsetAtIndex: 1] == 8 && - [methodSignature argumentOffsetAtIndex: 2] == 16 && - [methodSignature argumentOffsetAtIndex: 3] == 20) - - TEST(@"-[signatureWithObjCTypes:] #2", - (methodSignature = [OFMethodSignature signatureWithObjCTypes: - "{s0=csi(u1={s2=iii{s3=(u4=ic^v*)}})}24@0:8" - "^{s0=csi(u1={s2=iii{s3=(u4=ic^v*)}})}16"]) && - methodSignature.numberOfArguments == 3 && - strcmp(methodSignature.methodReturnType, - "{s0=csi(u1={s2=iii{s3=(u4=ic^v*)}})}") == 0 && - strcmp([methodSignature argumentTypeAtIndex: 0], "@") == 0 && - strcmp([methodSignature argumentTypeAtIndex: 1], ":") == 0 && - strcmp([methodSignature argumentTypeAtIndex: 2], - "^{s0=csi(u1={s2=iii{s3=(u4=ic^v*)}})}") == 0 && - methodSignature.frameLength == 24 && - [methodSignature argumentOffsetAtIndex: 0] == 0 && - [methodSignature argumentOffsetAtIndex: 1] == 8 && - [methodSignature argumentOffsetAtIndex: 2] == 16) - - EXPECT_EXCEPTION(@"-[signatureWithObjCTypes:] #3", - OFInvalidFormatException, - [OFMethodSignature signatureWithObjCTypes: "{ii"]) - - EXPECT_EXCEPTION(@"-[signatureWithObjCTypes:] #4", - OFInvalidFormatException, - [OFMethodSignature signatureWithObjCTypes: ""]) - - EXPECT_EXCEPTION(@"-[signatureWithObjCTypes:] #5", - OFInvalidFormatException, - [OFMethodSignature signatureWithObjCTypes: "0"]) - - EXPECT_EXCEPTION(@"-[signatureWithObjCTypes:] #6", - OFInvalidFormatException, - [OFMethodSignature signatureWithObjCTypes: "{{}0"]) - - TEST(@"OFSizeOfTypeEncoding() #1", - OFSizeOfTypeEncoding(@encode(struct Test1Struct)) == - sizeof(struct Test1Struct)) - - TEST(@"OFSizeOfTypeEncoding() #2", - OFSizeOfTypeEncoding(@encode(struct Test2Struct)) == - sizeof(struct Test2Struct)) - -#if !defined(__STDC_NO_COMPLEX__) && defined(HAVE_COMPLEX_H) && \ - OF_GCC_VERSION >= 402 - TEST(@"OFSizeOfTypeEncoding() #3", - OFSizeOfTypeEncoding(@encode(struct Test3Struct)) == - sizeof(struct Test3Struct)) -#endif - - TEST(@"OFSizeOfTypeEncoding() #4", - OFSizeOfTypeEncoding(@encode(union Test3Union)) == - sizeof(union Test3Union)) - - TEST(@"OFSizeOfTypeEncoding() #5", - OFSizeOfTypeEncoding(@encode(union Test4Union)) == - sizeof(union Test4Union)) - - TEST(@"OFSizeOfTypeEncoding() #6", - OFSizeOfTypeEncoding(@encode(struct Test1Struct [5])) == - sizeof(struct Test1Struct [5])) - - TEST(@"OFAlignmentOfTypeEncoding() #1", - OFAlignmentOfTypeEncoding(@encode(struct Test1Struct)) == - OF_ALIGNOF(struct Test1Struct)) - - TEST(@"OFAlignmentOfTypeEncoding() #2", - OFAlignmentOfTypeEncoding(@encode(struct Test2Struct)) == - OF_ALIGNOF(struct Test2Struct)) - -#if !defined(__STDC_NO_COMPLEX__) && defined(HAVE_COMPLEX_H) && \ - OF_GCC_VERSION >= 402 - TEST(@"OFAlignmentOfTypeEncoding() #3", - OFAlignmentOfTypeEncoding(@encode(struct Test3Struct)) == - OF_ALIGNOF(struct Test3Struct)) -#endif - - TEST(@"OFAlignmentOfTypeEncoding() #4", - OFAlignmentOfTypeEncoding(@encode(union Test3Union)) == - OF_ALIGNOF(union Test3Union)) - - TEST(@"OFAlignmentOfTypeEncoding() #5", - OFAlignmentOfTypeEncoding(@encode(union Test4Union)) == - OF_ALIGNOF(union Test4Union)) - - TEST(@"OFAlignmentOfTypeEncoding() #6", - OFAlignmentOfTypeEncoding(@encode(struct Test1Struct [5])) == - OF_ALIGNOF(struct Test1Struct [5])) - - objc_autoreleasePoolPop(pool); -} -@end DELETED tests/OFNumberTests.m Index: tests/OFNumberTests.m ================================================================== --- tests/OFNumberTests.m +++ tests/OFNumberTests.m @@ -1,92 +0,0 @@ -/* - * Copyright (c) 2008-2024 Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It may be distributed under the terms of the - * Q Public License 1.0, which can be found in the file LICENSE.QPL included in - * the packaging of this file. - * - * Alternatively, it may be distributed under the terms of the GNU General - * Public License, either version 2 or 3, which can be found in the file - * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this - * file. - */ - -#include "config.h" - -#import "TestsAppDelegate.h" - -static OFString *const module = @"OFNumber"; - -@implementation TestsAppDelegate (OFNumberTests) -- (void)numberTests -{ - void *pool = objc_autoreleasePoolPush(); - OFNumber *number; - - TEST(@"+[numberWithLongLong:]", - (number = [OFNumber numberWithLongLong: 123456789])) - - TEST(@"-[isEqual:]", - [number isEqual: [OFNumber numberWithLong: 123456789]]) - - TEST(@"-[hash]", number.hash == 0x82D8BC42) - - TEST(@"-[charValue]", number.charValue == 21) - - TEST(@"-[doubleValue]", number.doubleValue == 123456789.L) - - TEST(@"signed char minimum & maximum unmodified", - (number = [OFNumber numberWithChar: SCHAR_MIN]) && - number.charValue == SCHAR_MIN && - (number = [OFNumber numberWithChar: SCHAR_MAX]) && - number.charValue == SCHAR_MAX) - - TEST(@"short minimum & maximum unmodified", - (number = [OFNumber numberWithShort: SHRT_MIN]) && - number.shortValue == SHRT_MIN && - (number = [OFNumber numberWithShort: SHRT_MAX]) && - number.shortValue == SHRT_MAX) - - TEST(@"int minimum & maximum unmodified", - (number = [OFNumber numberWithInt: INT_MIN]) && - number.intValue == INT_MIN && - (number = [OFNumber numberWithInt: INT_MAX]) && - number.intValue == INT_MAX) - - TEST(@"long minimum & maximum unmodified", - (number = [OFNumber numberWithLong: LONG_MIN]) && - number.longValue == LONG_MIN && - (number = [OFNumber numberWithLong: LONG_MAX]) && - number.longValue == LONG_MAX) - - TEST(@"long long minimum & maximum unmodified", - (number = [OFNumber numberWithLongLong: LLONG_MIN]) && - number.longLongValue == LLONG_MIN && - (number = [OFNumber numberWithLongLong: LLONG_MAX]) && - number.longLongValue == LLONG_MAX) - - TEST(@"unsigned char maximum unmodified", - (number = [OFNumber numberWithUnsignedChar: UCHAR_MAX]) && - number.unsignedCharValue == UCHAR_MAX) - - TEST(@"unsigned short maximum unmodified", - (number = [OFNumber numberWithUnsignedShort: USHRT_MAX]) && - number.unsignedShortValue == USHRT_MAX) - - TEST(@"unsigned int maximum unmodified", - (number = [OFNumber numberWithUnsignedInt: UINT_MAX]) && - number.unsignedIntValue == UINT_MAX) - - TEST(@"unsigned long maximum unmodified", - (number = [OFNumber numberWithUnsignedLong: ULONG_MAX]) && - number.unsignedLongValue == ULONG_MAX) - - TEST(@"unsigned long long maximum unmodified", - (number = [OFNumber numberWithUnsignedLongLong: ULLONG_MAX]) && - number.unsignedLongLongValue == ULLONG_MAX) - - objc_autoreleasePoolPop(pool); -} -@end DELETED tests/OFPBKDF2Tests.m Index: tests/OFPBKDF2Tests.m ================================================================== --- tests/OFPBKDF2Tests.m +++ tests/OFPBKDF2Tests.m @@ -1,125 +0,0 @@ -/* - * Copyright (c) 2008-2024 Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It may be distributed under the terms of the - * Q Public License 1.0, which can be found in the file LICENSE.QPL included in - * the packaging of this file. - * - * Alternatively, it may be distributed under the terms of the GNU General - * Public License, either version 2 or 3, which can be found in the file - * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this - * file. - */ - -#include "config.h" - -#include - -#import "TestsAppDelegate.h" - -static OFString *const module = @"OFPBKDF2"; - -@implementation TestsAppDelegate (OFPBKDF2Tests) -- (void)PBKDF2Tests -{ - void *pool = objc_autoreleasePoolPush(); - OFHMAC *HMAC = [OFHMAC HMACWithHashClass: [OFSHA1Hash class] - allowsSwappableMemory: true]; - unsigned char key[25]; - - /* Test vectors from RFC 6070 */ - - TEST(@"PBKDF2-SHA1, 1 iteration", - R(OFPBKDF2((OFPBKDF2Parameters){ - .HMAC = HMAC, - .iterations = 1, - .salt = (unsigned char *)"salt", - .saltLength = 4, - .password = "password", - .passwordLength = 8, - .key = key, - .keyLength = 20, - .allowsSwappableMemory = true - })) && memcmp(key, "\x0C\x60\xC8\x0F\x96\x1F\x0E\x71\xF3\xA9\xB5" - "\x24\xAF\x60\x12\x06\x2F\xE0\x37\xA6", 20) == 0) - - TEST(@"PBKDF2-SHA1, 2 iterations", - R(OFPBKDF2((OFPBKDF2Parameters){ - .HMAC = HMAC, - .iterations = 2, - .salt = (unsigned char *)"salt", - .saltLength = 4, - .password = "password", - .passwordLength = 8, - .key = key, - .keyLength = 20, - .allowsSwappableMemory = true - })) && memcmp(key, "\xEA\x6C\x01\x4D\xC7\x2D\x6F\x8C\xCD\x1E\xD9" - "\x2A\xCE\x1D\x41\xF0\xD8\xDE\x89\x57", 20) == 0) - - TEST(@"PBKDF2-SHA1, 4096 iterations", - R(OFPBKDF2((OFPBKDF2Parameters){ - .HMAC = HMAC, - .iterations = 4096, - .salt = (unsigned char *)"salt", - .saltLength = 4, - .password = "password", - .passwordLength = 8, - .key = key, - .keyLength = 20, - .allowsSwappableMemory = true - })) && memcmp(key, "\x4B\x00\x79\x01\xB7\x65\x48\x9A\xBE\xAD\x49" - "\xD9\x26\xF7\x21\xD0\x65\xA4\x29\xC1", 20) == 0) - - /* This test takes too long, even on a fast machine. */ -#if 0 - TEST(@"PBKDF2-SHA1, 16777216 iterations", - R(OFPBKDF2((OFPBKDF2Parameters){ - .HMAC = HMAC, - .iterations = 16777216, - .salt = (unsigned char *)"salt", - .saltLength = 4, - .password = "password", - .passwordLength = 8, - .key = key, - .keyLength = 20, - .allowsSwappableMemory = true - })) && memcmp(key, "\xEE\xFE\x3D\x61\xCD\x4D\xA4\xE4\xE9\x94\x5B" - "\x3D\x6B\xA2\x15\x8C\x26\x34\xE9\x84", 20) == 0) -#endif - - TEST(@"PBKDF2-SHA1, 4096 iterations, key > 1 block", - R(OFPBKDF2((OFPBKDF2Parameters){ - .HMAC = HMAC, - .iterations = 4096, - .salt = (unsigned char *)"saltSALTsaltSALTsalt" - "SALTsaltSALTsalt", - .saltLength = 36, - .password = "passwordPASSWORDpassword", - .passwordLength = 24, - .key = key, - .keyLength = 25, - .allowsSwappableMemory = true - })) && - memcmp(key, "\x3D\x2E\xEC\x4F\xE4\x1C\x84\x9B\x80\xC8\xD8\x36\x62" - "\xC0\xE4\x4A\x8B\x29\x1A\x96\x4C\xF2\xF0\x70\x38", 25) == 0) - - TEST(@"PBKDF2-SHA1, 4096 iterations, key < 1 block", - R(OFPBKDF2((OFPBKDF2Parameters){ - .HMAC = HMAC, - .iterations = 4096, - .salt = (unsigned char *)"sa\0lt", - .saltLength = 5, - .password = "pass\0word", - .passwordLength = 9, - .key = key, - .keyLength = 16, - .allowsSwappableMemory = true - })) && memcmp(key, "\x56\xFA\x6A\xA7\x55\x48\x09\x9D\xCC\x37\xD7" - "\xF0\x34\x25\xE0\xC3", 16) == 0) - - objc_autoreleasePoolPop(pool); -} -@end DELETED tests/OFPluginTests.m Index: tests/OFPluginTests.m ================================================================== --- tests/OFPluginTests.m +++ tests/OFPluginTests.m @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2008-2024 Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It may be distributed under the terms of the - * Q Public License 1.0, which can be found in the file LICENSE.QPL included in - * the packaging of this file. - * - * Alternatively, it may be distributed under the terms of the GNU General - * Public License, either version 2 or 3, which can be found in the file - * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this - * file. - */ - -#include "config.h" - -#import "TestsAppDelegate.h" - -#import "plugin/TestPlugin.h" - -#ifndef OF_IOS -static OFString *const pluginName = @"plugin/TestPlugin"; -#else -static OFString *const pluginName = @"PlugIns/TestPlugin"; -#endif - -static OFString *const module = @"OFPlugin"; - -@implementation TestsAppDelegate (OFPluginTests) -- (void)pluginTests -{ - void *pool = objc_autoreleasePoolPush(); - OFString *path; - OFPlugin *plugin; - Class (*class)(void); - TestPlugin *test; - - TEST(@"+[pathForName:]", (path = [OFPlugin pathForName: pluginName])) - - TEST(@"+[pluginWithPath:]", (plugin = [OFPlugin pluginWithPath: path])) - - TEST(@"-[addressForSymbol:]", - (class = (Class (*)(void))(uintptr_t) - [plugin addressForSymbol: @"class"])) - - test = [[class() alloc] init]; - @try { - TEST(@"TestPlugin's -[test:]", [test test: 1234] == 2468) - } @finally { - [test release]; - } - - objc_autoreleasePoolPop(pool); -} -@end DELETED tests/OFPropertyListTests.m Index: tests/OFPropertyListTests.m ================================================================== --- tests/OFPropertyListTests.m +++ tests/OFPropertyListTests.m @@ -1,118 +0,0 @@ -/* - * Copyright (c) 2008-2024 Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It may be distributed under the terms of the - * Q Public License 1.0, which can be found in the file LICENSE.QPL included in - * the packaging of this file. - * - * Alternatively, it may be distributed under the terms of the GNU General - * Public License, either version 2 or 3, which can be found in the file - * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this - * file. - */ - -#include "config.h" - -#import "TestsAppDelegate.h" - -#define PLIST(x) \ - @"" \ - @"" \ - @"\n" \ - x @"\n" \ - @"" - -static OFString *const module = @"OFPropertyList"; -static OFString *const PLIST1 = PLIST(@"Hello"); -static OFString *const PLIST2 = PLIST( - @"" - @" Hello" - @" V29ybGQh" - @" 2018-03-14T12:34:56Z" - @" " - @" " - @" 12.25" - @" -10" - @""); -static OFString *const PLIST3 = PLIST( - @"" - @" array" - @" " - @" Hello" - @" V29ybGQh" - @" 2018-03-14T12:34:56Z" - @" " - @" " - @" 12.25" - @" -10" - @" " - @" foo" - @" bar" - @""); - -@implementation TestsAppDelegate (OFPLISTParser) -- (void)propertyListTests -{ - void *pool = objc_autoreleasePoolPush(); - OFArray *array = [OFArray arrayWithObjects: - @"Hello", - [OFData dataWithItems: "World!" count: 6], - [OFDate dateWithTimeIntervalSince1970: 1521030896], - [OFNumber numberWithBool: true], - [OFNumber numberWithBool: false], - [OFNumber numberWithFloat: 12.25f], - [OFNumber numberWithInt: -10], - nil]; - - TEST(@"-[objectByParsingPropertyList:] #1", - [PLIST1.objectByParsingPropertyList isEqual: @"Hello"]) - - TEST(@"-[objectByParsingPropertyList:] #2", - [PLIST2.objectByParsingPropertyList isEqual: array]) - - TEST(@"-[objectByParsingPropertyList:] #3", - [PLIST3.objectByParsingPropertyList isEqual: - [OFDictionary dictionaryWithKeysAndObjects: - @"array", array, - @"foo", @"bar", - nil]]) - - EXPECT_EXCEPTION(@"Detecting unsupported version", - OFUnsupportedVersionException, - [[PLIST(@"") stringByReplacingOccurrencesOfString: @"1.0" - withString: @"1.1"] - objectByParsingPropertyList]) - - EXPECT_EXCEPTION( - @"-[objectByParsingPropertyList] detecting invalid format #1", - OFInvalidFormatException, - [PLIST(@"") objectByParsingPropertyList]) - - EXPECT_EXCEPTION( - @"-[objectByParsingPropertyList] detecting invalid format #2", - OFInvalidFormatException, - [PLIST(@"") objectByParsingPropertyList]) - - EXPECT_EXCEPTION( - @"-[objectByParsingPropertyList] detecting invalid format #3", - OFInvalidFormatException, - [PLIST(@"") objectByParsingPropertyList]) - - EXPECT_EXCEPTION( - @"-[objectByParsingPropertyList] detecting invalid format #4", - OFInvalidFormatException, - [PLIST(@"") - objectByParsingPropertyList]) - - EXPECT_EXCEPTION( - @"-[objectByParsingPropertyList] detecting invalid format #5", - OFInvalidFormatException, - [PLIST(@"") - objectByParsingPropertyList]) - - objc_autoreleasePoolPop(pool); -} -@end DELETED tests/OFRIPEMD160HashTests.m Index: tests/OFRIPEMD160HashTests.m ================================================================== --- tests/OFRIPEMD160HashTests.m +++ tests/OFRIPEMD160HashTests.m @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2008-2024 Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It may be distributed under the terms of the - * Q Public License 1.0, which can be found in the file LICENSE.QPL included in - * the packaging of this file. - * - * Alternatively, it may be distributed under the terms of the GNU General - * Public License, either version 2 or 3, which can be found in the file - * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this - * file. - */ - -#include "config.h" - -#include - -#import "TestsAppDelegate.h" - -static OFString *const module = @"OFRIPEMD160Hash"; - -const uint8_t testFileRIPEMD160[20] = - "\x46\x02\x97\xF5\x85\xDF\xB9\x21\x00\xC8\xF9\x87\xC6\xEC\x84\x0D\xCE" - "\xE6\x08\x8B"; - -@implementation TestsAppDelegate (OFRIPEMD160HashTests) -- (void)RIPEMD160HashTests -{ - void *pool = objc_autoreleasePoolPush(); - OFRIPEMD160Hash *RIPEMD160, *RIPEMD160Copy; - OFIRI *IRI = [OFIRI IRIWithString: @"embedded:testfile.bin"]; - OFStream *file = [OFIRIHandler openItemAtIRI: IRI mode: @"r"]; - - TEST(@"+[hashWithAllowsSwappableMemory:]", - (RIPEMD160 = [OFRIPEMD160Hash hashWithAllowsSwappableMemory: true])) - - while (!file.atEndOfStream) { - char buffer[64]; - size_t length = [file readIntoBuffer: buffer length: 64]; - [RIPEMD160 updateWithBuffer: buffer length: length]; - } - [file close]; - - TEST(@"-[copy]", (RIPEMD160Copy = [[RIPEMD160 copy] autorelease])) - - TEST(@"-[calculate]", - R([RIPEMD160 calculate]) && R([RIPEMD160Copy calculate])) - - TEST(@"-[digest]", - memcmp(RIPEMD160.digest, testFileRIPEMD160, 20) == 0 && - memcmp(RIPEMD160Copy.digest, testFileRIPEMD160, 20) == 0) - - EXPECT_EXCEPTION(@"Detect invalid call of " - @"-[updateWithBuffer:length]", OFHashAlreadyCalculatedException, - [RIPEMD160 updateWithBuffer: "" length: 1]) - - objc_autoreleasePoolPop(pool); -} -@end DELETED tests/OFSHA1HashTests.m Index: tests/OFSHA1HashTests.m ================================================================== --- tests/OFSHA1HashTests.m +++ tests/OFSHA1HashTests.m @@ -1,60 +0,0 @@ -/* - * Copyright (c) 2008-2024 Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It may be distributed under the terms of the - * Q Public License 1.0, which can be found in the file LICENSE.QPL included in - * the packaging of this file. - * - * Alternatively, it may be distributed under the terms of the GNU General - * Public License, either version 2 or 3, which can be found in the file - * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this - * file. - */ - -#include "config.h" - -#include - -#import "TestsAppDelegate.h" - -static OFString *const module = @"OFSHA1Hash"; - -const uint8_t testFileSHA1[20] = - "\xC9\x9A\xB8\x7E\x1E\xC8\xEC\x65\xD5\xEB\xE4\x2E\x0D\xA6\x80\x96\xF5" - "\x94\xE7\x17"; - -@implementation TestsAppDelegate (SHA1HashTests) -- (void)SHA1HashTests -{ - void *pool = objc_autoreleasePoolPush(); - OFSHA1Hash *SHA1, *SHA1Copy; - OFIRI *IRI = [OFIRI IRIWithString: @"embedded:testfile.bin"]; - OFStream *file = [OFIRIHandler openItemAtIRI: IRI mode: @"r"]; - - TEST(@"+[hashWithAllowsSwappableMemory:]", - (SHA1 = [OFSHA1Hash hashWithAllowsSwappableMemory: true])) - - while (!file.atEndOfStream) { - char buffer[64]; - size_t length = [file readIntoBuffer: buffer length: 64]; - [SHA1 updateWithBuffer: buffer length: length]; - } - [file close]; - - TEST(@"-[copy]", (SHA1Copy = [[SHA1 copy] autorelease])) - - TEST(@"-[calculate]", R([SHA1 calculate]) && R([SHA1Copy calculate])) - - TEST(@"-[digest]", - memcmp(SHA1.digest, testFileSHA1, 20) == 0 && - memcmp(SHA1Copy.digest, testFileSHA1, 20) == 0) - - EXPECT_EXCEPTION(@"Detect invalid call of " - @"-[updateWithBuffer:length:]", OFHashAlreadyCalculatedException, - [SHA1 updateWithBuffer: "" length: 1]) - - objc_autoreleasePoolPop(pool); -} -@end DELETED tests/OFSHA224HashTests.m Index: tests/OFSHA224HashTests.m ================================================================== --- tests/OFSHA224HashTests.m +++ tests/OFSHA224HashTests.m @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2008-2024 Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It may be distributed under the terms of the - * Q Public License 1.0, which can be found in the file LICENSE.QPL included in - * the packaging of this file. - * - * Alternatively, it may be distributed under the terms of the GNU General - * Public License, either version 2 or 3, which can be found in the file - * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this - * file. - */ - -#include "config.h" - -#include - -#import "TestsAppDelegate.h" - -static OFString *const module = @"OFSHA224Hash"; - -const uint8_t testFileSHA224[28] = - "\x27\x69\xD8\x04\x2D\x0F\xCA\x84\x6C\xF1\x62\x44\xBA\x0C\xBD\x46\x64" - "\x5F\x4F\x20\x02\x4D\x15\xED\x1C\x61\x1F\xF7"; - -@implementation TestsAppDelegate (SHA224HashTests) -- (void)SHA224HashTests -{ - void *pool = objc_autoreleasePoolPush(); - OFSHA224Hash *SHA224, *SHA224Copy; - OFIRI *IRI = [OFIRI IRIWithString: @"embedded:testfile.bin"]; - OFStream *file = [OFIRIHandler openItemAtIRI: IRI mode: @"r"]; - - TEST(@"+[hashWithAllowsSwappableMemory:]", - (SHA224 = [OFSHA224Hash hashWithAllowsSwappableMemory: true])) - - while (!file.atEndOfStream) { - char buffer[64]; - size_t length = [file readIntoBuffer: buffer length: 64]; - [SHA224 updateWithBuffer: buffer length: length]; - } - [file close]; - - TEST(@"-[copy]", (SHA224Copy = [[SHA224 copy] autorelease])) - - TEST(@"-[calculate]", - R([SHA224 calculate]) && R([SHA224Copy calculate])) - - TEST(@"-[digest]", - memcmp(SHA224.digest, testFileSHA224, 28) == 0 && - memcmp(SHA224Copy.digest, testFileSHA224, 28) == 0) - - EXPECT_EXCEPTION(@"Detect invalid call of " - @"-[updateWithBuffer:length:]", OFHashAlreadyCalculatedException, - [SHA224 updateWithBuffer: "" length: 1]) - - objc_autoreleasePoolPop(pool); -} -@end DELETED tests/OFSHA256HashTests.m Index: tests/OFSHA256HashTests.m ================================================================== --- tests/OFSHA256HashTests.m +++ tests/OFSHA256HashTests.m @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2008-2024 Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It may be distributed under the terms of the - * Q Public License 1.0, which can be found in the file LICENSE.QPL included in - * the packaging of this file. - * - * Alternatively, it may be distributed under the terms of the GNU General - * Public License, either version 2 or 3, which can be found in the file - * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this - * file. - */ - -#include "config.h" - -#include - -#import "TestsAppDelegate.h" - -static OFString *const module = @"OFSHA256Hash"; - -const uint8_t testFileSHA256[32] = - "\x1A\x02\xD6\x46\xF5\xA6\xBA\xAA\xFF\x7F\xD5\x87\xBA\xC3\xF6\xC6\xB5" - "\x67\x93\x8F\x0F\x44\x90\xB8\xF5\x35\x89\xF0\x5A\x23\x7F\x69"; - -@implementation TestsAppDelegate (SHA256HashTests) -- (void)SHA256HashTests -{ - void *pool = objc_autoreleasePoolPush(); - OFSHA256Hash *SHA256, *SHA256Copy; - OFIRI *IRI = [OFIRI IRIWithString: @"embedded:testfile.bin"]; - OFStream *file = [OFIRIHandler openItemAtIRI: IRI mode: @"r"]; - - TEST(@"+[hashWithAllowsSwappableMemory:]", - (SHA256 = [OFSHA256Hash hashWithAllowsSwappableMemory: true])) - - while (!file.atEndOfStream) { - char buffer[64]; - size_t length = [file readIntoBuffer: buffer length: 64]; - [SHA256 updateWithBuffer: buffer length: length]; - } - [file close]; - - TEST(@"-[copy]", (SHA256Copy = [[SHA256 copy] autorelease])) - - TEST(@"-[calculate]", - R([SHA256 calculate]) && R([SHA256Copy calculate])) - - TEST(@"-[digest]", - memcmp(SHA256.digest, testFileSHA256, 32) == 0 && - memcmp(SHA256Copy.digest, testFileSHA256, 32) == 0) - - EXPECT_EXCEPTION(@"Detect invalid call of " - @"-[updateWithBuffer:length:]", OFHashAlreadyCalculatedException, - [SHA256 updateWithBuffer: "" length: 1]) - - objc_autoreleasePoolPop(pool); -} -@end DELETED tests/OFSHA384HashTests.m Index: tests/OFSHA384HashTests.m ================================================================== --- tests/OFSHA384HashTests.m +++ tests/OFSHA384HashTests.m @@ -1,62 +0,0 @@ -/* - * Copyright (c) 2008-2024 Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It may be distributed under the terms of the - * Q Public License 1.0, which can be found in the file LICENSE.QPL included in - * the packaging of this file. - * - * Alternatively, it may be distributed under the terms of the GNU General - * Public License, either version 2 or 3, which can be found in the file - * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this - * file. - */ - -#include "config.h" - -#include - -#import "TestsAppDelegate.h" - -static OFString *const module = @"OFSHA384Hash"; - -const uint8_t testFileSHA384[48] = - "\x7E\xDE\x62\xE2\x10\xA5\x1E\x18\x8A\x11\x7F\x78\xD7\xC7\x55\xB6\x43" - "\x94\x1B\xD2\x78\x5C\xCF\xF3\x8A\xB8\x98\x22\xC7\x0E\xFE\xF1\xEC\x53" - "\xE9\x1A\xB3\x51\x70\x8C\x1F\x3F\x56\x12\x44\x01\x91\x54"; - -@implementation TestsAppDelegate (SHA384HashTests) -- (void)SHA384HashTests -{ - void *pool = objc_autoreleasePoolPush(); - OFSHA384Hash *SHA384, *SHA384Copy; - OFIRI *IRI = [OFIRI IRIWithString: @"embedded:testfile.bin"]; - OFStream *file = [OFIRIHandler openItemAtIRI: IRI mode: @"r"]; - - TEST(@"+[hashWithAllowsSwappableMemory:]", - (SHA384 = [OFSHA384Hash hashWithAllowsSwappableMemory: true])) - - while (!file.atEndOfStream) { - char buffer[128]; - size_t length = [file readIntoBuffer: buffer length: 128]; - [SHA384 updateWithBuffer: buffer length: length]; - } - [file close]; - - TEST(@"-[copy]", (SHA384Copy = [[SHA384 copy] autorelease])) - - TEST(@"-[calculate]", - R([SHA384 calculate]) && R([SHA384Copy calculate])) - - TEST(@"-[digest]", - memcmp(SHA384.digest, testFileSHA384, 48) == 0 && - memcmp(SHA384Copy.digest, testFileSHA384, 48) == 0) - - EXPECT_EXCEPTION(@"Detect invalid call of " - @"-[updateWithBuffer:length:]", OFHashAlreadyCalculatedException, - [SHA384 updateWithBuffer: "" length: 1]) - - objc_autoreleasePoolPop(pool); -} -@end DELETED tests/OFSHA512HashTests.m Index: tests/OFSHA512HashTests.m ================================================================== --- tests/OFSHA512HashTests.m +++ tests/OFSHA512HashTests.m @@ -1,63 +0,0 @@ -/* - * Copyright (c) 2008-2024 Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It may be distributed under the terms of the - * Q Public License 1.0, which can be found in the file LICENSE.QPL included in - * the packaging of this file. - * - * Alternatively, it may be distributed under the terms of the GNU General - * Public License, either version 2 or 3, which can be found in the file - * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this - * file. - */ - -#include "config.h" - -#include - -#import "TestsAppDelegate.h" - -static OFString *const module = @"OFSHA512Hash"; - -const uint8_t testFileSHA512[64] = - "\x8F\x36\x6E\x3C\x19\x4B\xBB\xC7\x82\xAA\xCD\x7D\x55\xA2\xD3\x29\x29" - "\x97\x6A\x3F\xEB\x9B\xB2\xCB\x75\xC9\xEC\xC8\x10\x07\xD6\x07\x31\x4A" - "\xB1\x30\x97\x82\x58\xA5\x1F\x71\x42\xE6\x56\x07\x99\x57\xB2\xB8\x3B" - "\xA1\x8A\x41\x64\x33\x69\x21\x8C\x2A\x44\x6D\xF2\xA0"; - -@implementation TestsAppDelegate (SHA512HashTests) -- (void)SHA512HashTests -{ - void *pool = objc_autoreleasePoolPush(); - OFSHA512Hash *SHA512, *SHA512Copy; - OFIRI *IRI = [OFIRI IRIWithString: @"embedded:testfile.bin"]; - OFStream *file = [OFIRIHandler openItemAtIRI: IRI mode: @"r"]; - - TEST(@"+[hashWithAllowsSwappableMemory:]", - (SHA512 = [OFSHA512Hash hashWithAllowsSwappableMemory: true])) - - while (!file.atEndOfStream) { - char buffer[128]; - size_t length = [file readIntoBuffer: buffer length: 128]; - [SHA512 updateWithBuffer: buffer length: length]; - } - [file close]; - - TEST(@"-[copy]", (SHA512Copy = [[SHA512 copy] autorelease])) - - TEST(@"-[calculate]", - R([SHA512 calculate]) && R([SHA512Copy calculate])) - - TEST(@"-[digest]", - memcmp(SHA512.digest, testFileSHA512, 64) == 0 && - memcmp(SHA512Copy.digest, testFileSHA512, 64) == 0) - - EXPECT_EXCEPTION(@"Detect invalid call of " - @"-[updateWithBuffer:length:]", OFHashAlreadyCalculatedException, - [SHA512 updateWithBuffer: "" length: 1]) - - objc_autoreleasePoolPop(pool); -} -@end DELETED tests/OFScryptTests.m Index: tests/OFScryptTests.m ================================================================== --- tests/OFScryptTests.m +++ tests/OFScryptTests.m @@ -1,223 +0,0 @@ -/* - * Copyright (c) 2008-2024 Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It may be distributed under the terms of the - * Q Public License 1.0, which can be found in the file LICENSE.QPL included in - * the packaging of this file. - * - * Alternatively, it may be distributed under the terms of the GNU General - * Public License, either version 2 or 3, which can be found in the file - * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this - * file. - */ - -#include "config.h" - -#include - -#import "TestsAppDelegate.h" - -static OFString *const module = @"OFScrypt"; -/* Test vectors form RFC 7914 */ -static const unsigned char salsa20Input[64] = { - 0x7E, 0x87, 0x9A, 0x21, 0x4F, 0x3E, 0xC9, 0x86, 0x7C, 0xA9, 0x40, 0xE6, - 0x41, 0x71, 0x8F, 0x26, 0xBA, 0xEE, 0x55, 0x5B, 0x8C, 0x61, 0xC1, 0xB5, - 0x0D, 0xF8, 0x46, 0x11, 0x6D, 0xCD, 0x3B, 0x1D, 0xEE, 0x24, 0xF3, 0x19, - 0xDF, 0x9B, 0x3D, 0x85, 0x14, 0x12, 0x1E, 0x4B, 0x5A, 0xC5, 0xAA, 0x32, - 0x76, 0x02, 0x1D, 0x29, 0x09, 0xC7, 0x48, 0x29, 0xED, 0xEB, 0xC6, 0x8D, - 0xB8, 0xB8, 0xC2, 0x5E -}; -static const unsigned char salsa20Output[64] = { - 0xA4, 0x1F, 0x85, 0x9C, 0x66, 0x08, 0xCC, 0x99, 0x3B, 0x81, 0xCA, 0xCB, - 0x02, 0x0C, 0xEF, 0x05, 0x04, 0x4B, 0x21, 0x81, 0xA2, 0xFD, 0x33, 0x7D, - 0xFD, 0x7B, 0x1C, 0x63, 0x96, 0x68, 0x2F, 0x29, 0xB4, 0x39, 0x31, 0x68, - 0xE3, 0xC9, 0xE6, 0xBC, 0xFE, 0x6B, 0xC5, 0xB7, 0xA0, 0x6D, 0x96, 0xBA, - 0xE4, 0x24, 0xCC, 0x10, 0x2C, 0x91, 0x74, 0x5C, 0x24, 0xAD, 0x67, 0x3D, - 0xC7, 0x61, 0x8F, 0x81 -}; -static const union { - unsigned char uc[128]; - uint32_t u32[32]; -} blockMixInput = { .uc = { - 0xF7, 0xCE, 0x0B, 0x65, 0x3D, 0x2D, 0x72, 0xA4, 0x10, 0x8C, 0xF5, 0xAB, - 0xE9, 0x12, 0xFF, 0xDD, 0x77, 0x76, 0x16, 0xDB, 0xBB, 0x27, 0xA7, 0x0E, - 0x82, 0x04, 0xF3, 0xAE, 0x2D, 0x0F, 0x6F, 0xAD, 0x89, 0xF6, 0x8F, 0x48, - 0x11, 0xD1, 0xE8, 0x7B, 0xCC, 0x3B, 0xD7, 0x40, 0x0A, 0x9F, 0xFD, 0x29, - 0x09, 0x4F, 0x01, 0x84, 0x63, 0x95, 0x74, 0xF3, 0x9A, 0xE5, 0xA1, 0x31, - 0x52, 0x17, 0xBC, 0xD7, - 0x89, 0x49, 0x91, 0x44, 0x72, 0x13, 0xBB, 0x22, 0x6C, 0x25, 0xB5, 0x4D, - 0xA8, 0x63, 0x70, 0xFB, 0xCD, 0x98, 0x43, 0x80, 0x37, 0x46, 0x66, 0xBB, - 0x8F, 0xFC, 0xB5, 0xBF, 0x40, 0xC2, 0x54, 0xB0, 0x67, 0xD2, 0x7C, 0x51, - 0xCE, 0x4A, 0xD5, 0xFE, 0xD8, 0x29, 0xC9, 0x0B, 0x50, 0x5A, 0x57, 0x1B, - 0x7F, 0x4D, 0x1C, 0xAD, 0x6A, 0x52, 0x3C, 0xDA, 0x77, 0x0E, 0x67, 0xBC, - 0xEA, 0xAF, 0x7E, 0x89 -}}; -static const unsigned char blockMixOutput[128] = { - 0xA4, 0x1F, 0x85, 0x9C, 0x66, 0x08, 0xCC, 0x99, 0x3B, 0x81, 0xCA, 0xCB, - 0x02, 0x0C, 0xEF, 0x05, 0x04, 0x4B, 0x21, 0x81, 0xA2, 0xFD, 0x33, 0x7D, - 0xFD, 0x7B, 0x1C, 0x63, 0x96, 0x68, 0x2F, 0x29, 0xB4, 0x39, 0x31, 0x68, - 0xE3, 0xC9, 0xE6, 0xBC, 0xFE, 0x6B, 0xC5, 0xB7, 0xA0, 0x6D, 0x96, 0xBA, - 0xE4, 0x24, 0xCC, 0x10, 0x2C, 0x91, 0x74, 0x5C, 0x24, 0xAD, 0x67, 0x3D, - 0xC7, 0x61, 0x8F, 0x81, - 0x20, 0xED, 0xC9, 0x75, 0x32, 0x38, 0x81, 0xA8, 0x05, 0x40, 0xF6, 0x4C, - 0x16, 0x2D, 0xCD, 0x3C, 0x21, 0x07, 0x7C, 0xFE, 0x5F, 0x8D, 0x5F, 0xE2, - 0xB1, 0xA4, 0x16, 0x8F, 0x95, 0x36, 0x78, 0xB7, 0x7D, 0x3B, 0x3D, 0x80, - 0x3B, 0x60, 0xE4, 0xAB, 0x92, 0x09, 0x96, 0xE5, 0x9B, 0x4D, 0x53, 0xB6, - 0x5D, 0x2A, 0x22, 0x58, 0x77, 0xD5, 0xED, 0xF5, 0x84, 0x2C, 0xB9, 0xF1, - 0x4E, 0xEF, 0xE4, 0x25 -}; -static const unsigned char ROMixInput[128] = { - 0xF7, 0xCE, 0x0B, 0x65, 0x3D, 0x2D, 0x72, 0xA4, 0x10, 0x8C, 0xF5, 0xAB, - 0xE9, 0x12, 0xFF, 0xDD, 0x77, 0x76, 0x16, 0xDB, 0xBB, 0x27, 0xA7, 0x0E, - 0x82, 0x04, 0xF3, 0xAE, 0x2D, 0x0F, 0x6F, 0xAD, 0x89, 0xF6, 0x8F, 0x48, - 0x11, 0xD1, 0xE8, 0x7B, 0xCC, 0x3B, 0xD7, 0x40, 0x0A, 0x9F, 0xFD, 0x29, - 0x09, 0x4F, 0x01, 0x84, 0x63, 0x95, 0x74, 0xF3, 0x9A, 0xE5, 0xA1, 0x31, - 0x52, 0x17, 0xBC, 0xD7, 0x89, 0x49, 0x91, 0x44, 0x72, 0x13, 0xBB, 0x22, - 0x6C, 0x25, 0xB5, 0x4D, 0xA8, 0x63, 0x70, 0xFB, 0xCD, 0x98, 0x43, 0x80, - 0x37, 0x46, 0x66, 0xBB, 0x8F, 0xFC, 0xB5, 0xBF, 0x40, 0xC2, 0x54, 0xB0, - 0x67, 0xD2, 0x7C, 0x51, 0xCE, 0x4A, 0xD5, 0xFE, 0xD8, 0x29, 0xC9, 0x0B, - 0x50, 0x5A, 0x57, 0x1B, 0x7F, 0x4D, 0x1C, 0xAD, 0x6A, 0x52, 0x3C, 0xDA, - 0x77, 0x0E, 0x67, 0xBC, 0xEA, 0xAF, 0x7E, 0x89 -}; -static const unsigned char ROMixOutput[128] = { - 0x79, 0xCC, 0xC1, 0x93, 0x62, 0x9D, 0xEB, 0xCA, 0x04, 0x7F, 0x0B, 0x70, - 0x60, 0x4B, 0xF6, 0xB6, 0x2C, 0xE3, 0xDD, 0x4A, 0x96, 0x26, 0xE3, 0x55, - 0xFA, 0xFC, 0x61, 0x98, 0xE6, 0xEA, 0x2B, 0x46, 0xD5, 0x84, 0x13, 0x67, - 0x3B, 0x99, 0xB0, 0x29, 0xD6, 0x65, 0xC3, 0x57, 0x60, 0x1F, 0xB4, 0x26, - 0xA0, 0xB2, 0xF4, 0xBB, 0xA2, 0x00, 0xEE, 0x9F, 0x0A, 0x43, 0xD1, 0x9B, - 0x57, 0x1A, 0x9C, 0x71, 0xEF, 0x11, 0x42, 0xE6, 0x5D, 0x5A, 0x26, 0x6F, - 0xDD, 0xCA, 0x83, 0x2C, 0xE5, 0x9F, 0xAA, 0x7C, 0xAC, 0x0B, 0x9C, 0xF1, - 0xBE, 0x2B, 0xFF, 0xCA, 0x30, 0x0D, 0x01, 0xEE, 0x38, 0x76, 0x19, 0xC4, - 0xAE, 0x12, 0xFD, 0x44, 0x38, 0xF2, 0x03, 0xA0, 0xE4, 0xE1, 0xC4, 0x7E, - 0xC3, 0x14, 0x86, 0x1F, 0x4E, 0x90, 0x87, 0xCB, 0x33, 0x39, 0x6A, 0x68, - 0x73, 0xE8, 0xF9, 0xD2, 0x53, 0x9A, 0x4B, 0x8E -}; -static const unsigned char testVector1[64] = { - 0x77, 0xD6, 0x57, 0x62, 0x38, 0x65, 0x7B, 0x20, 0x3B, 0x19, 0xCA, 0x42, - 0xC1, 0x8A, 0x04, 0x97, 0xF1, 0x6B, 0x48, 0x44, 0xE3, 0x07, 0x4A, 0xE8, - 0xDF, 0xDF, 0xFA, 0x3F, 0xED, 0xE2, 0x14, 0x42, 0xFC, 0xD0, 0x06, 0x9D, - 0xED, 0x09, 0x48, 0xF8, 0x32, 0x6A, 0x75, 0x3A, 0x0F, 0xC8, 0x1F, 0x17, - 0xE8, 0xD3, 0xE0, 0xFB, 0x2E, 0x0D, 0x36, 0x28, 0xCF, 0x35, 0xE2, 0x0C, - 0x38, 0xD1, 0x89, 0x06 -}; -static const unsigned char testVector2[64] = { - 0xFD, 0xBA, 0xBE, 0x1C, 0x9D, 0x34, 0x72, 0x00, 0x78, 0x56, 0xE7, 0x19, - 0x0D, 0x01, 0xE9, 0xFE, 0x7C, 0x6A, 0xD7, 0xCB, 0xC8, 0x23, 0x78, 0x30, - 0xE7, 0x73, 0x76, 0x63, 0x4B, 0x37, 0x31, 0x62, 0x2E, 0xAF, 0x30, 0xD9, - 0x2E, 0x22, 0xA3, 0x88, 0x6F, 0xF1, 0x09, 0x27, 0x9D, 0x98, 0x30, 0xDA, - 0xC7, 0x27, 0xAF, 0xB9, 0x4A, 0x83, 0xEE, 0x6D, 0x83, 0x60, 0xCB, 0xDF, - 0xA2, 0xCC, 0x06, 0x40 -}; -/* The third test vector is too expensive for m68k. */ -#ifndef OF_M68K -static const unsigned char testVector3[64] = { - 0x70, 0x23, 0xBD, 0xCB, 0x3A, 0xFD, 0x73, 0x48, 0x46, 0x1C, 0x06, 0xCD, - 0x81, 0xFD, 0x38, 0xEB, 0xFD, 0xA8, 0xFB, 0xBA, 0x90, 0x4F, 0x8E, 0x3E, - 0xA9, 0xB5, 0x43, 0xF6, 0x54, 0x5D, 0xA1, 0xF2, 0xD5, 0x43, 0x29, 0x55, - 0x61, 0x3F, 0x0F, 0xCF, 0x62, 0xD4, 0x97, 0x05, 0x24, 0x2A, 0x9A, 0xF9, - 0xE6, 0x1E, 0x85, 0xDC, 0x0D, 0x65, 0x1E, 0x40, 0xDF, 0xCF, 0x01, 0x7B, - 0x45, 0x57, 0x58, 0x87 -}; -#endif -/* The forth test vector is too expensive to include it in the tests. */ -#if 0 -static const unsigned char testVector4[64] = { - 0x21, 0x01, 0xCB, 0x9B, 0x6A, 0x51, 0x1A, 0xAE, 0xAD, 0xDB, 0xBE, 0x09, - 0xCF, 0x70, 0xF8, 0x81, 0xEC, 0x56, 0x8D, 0x57, 0x4A, 0x2F, 0xFD, 0x4D, - 0xAB, 0xE5, 0xEE, 0x98, 0x20, 0xAD, 0xAA, 0x47, 0x8E, 0x56, 0xFD, 0x8F, - 0x4B, 0xA5, 0xD0, 0x9F, 0xFA, 0x1C, 0x6D, 0x92, 0x7C, 0x40, 0xF4, 0xC3, - 0x37, 0x30, 0x40, 0x49, 0xE8, 0xA9, 0x52, 0xFB, 0xCB, 0xF4, 0x5C, 0x6F, - 0xA7, 0x7A, 0x41, 0xA4 -}; -#endif - -@implementation TestsAppDelegate (OFScryptTests) -- (void)scryptTests -{ - void *pool = objc_autoreleasePoolPush(); - uint32_t salsa20Buffer[16]; - uint32_t blockMixBuffer[32]; - uint32_t ROMixBuffer[32], ROMixTmp[17 * 32]; - unsigned char output[64]; - - TEST(@"Salsa20/8 Core", - R(memcpy(salsa20Buffer, salsa20Input, 64)) && - R(OFSalsa20_8Core(salsa20Buffer)) && - memcmp(salsa20Buffer, salsa20Output, 64) == 0) - - TEST(@"Block mix", - R(OFScryptBlockMix(blockMixBuffer, blockMixInput.u32, 1)) && - memcmp(blockMixBuffer, blockMixOutput, 128) == 0) - - TEST(@"ROMix", - R(memcpy(ROMixBuffer, ROMixInput, 128)) && - R(OFScryptROMix(ROMixBuffer, 1, 16, ROMixTmp)) && - memcmp(ROMixBuffer, ROMixOutput, 128) == 0) - - TEST(@"scrypt test vector #1", - R(OFScrypt((OFScryptParameters){ - .blockSize = 1, - .costFactor = 16, - .parallelization = 1, - .salt = (unsigned char *)"", - .saltLength = 0, - .password = "", - .passwordLength = 0, - .key = output, - .keyLength = 64, - .allowsSwappableMemory = true - })) && memcmp(output, testVector1, 64) == 0) - - TEST(@"scrypt test vector #2", - R(OFScrypt((OFScryptParameters){ - .blockSize = 8, - .costFactor = 1024, - .parallelization = 16, - .salt = (unsigned char *)"NaCl", - .saltLength = 4, - .password = "password", - .passwordLength = 8, - .key = output, - .keyLength = 64, - .allowsSwappableMemory = true - })) && memcmp(output, testVector2, 64) == 0) - - /* The third test vector is too expensive for m68k. */ -#ifndef OF_M68K - TEST(@"scrypt test vector #3", - R(OFScrypt((OFScryptParameters){ - .blockSize = 8, - .costFactor = 16384, - .parallelization = 1, - .salt = (unsigned char *)"SodiumChloride", - .saltLength = 14, - .password = "pleaseletmein", - .passwordLength = 13, - .key = output, - .keyLength = 64, - .allowsSwappableMemory = true - })) && memcmp(output, testVector3, 64) == 0) -#endif - - /* The forth test vector is too expensive to include it in the tests. */ -#if 0 - TEST(@"scrypt test vector #4", - R(OFScrypt((OFScryptParameters){ - .blockSize = 8, - .costFactor = 1048576, - .parallelization = 1, - .salt = (unsigned char *)"SodiumChloride", - .saltLength = 14, - .password = "pleaseletmein", - .passwordLength = 13, - .key = output, - .keyLength = 64, - .allowsSwappableMemory = true - })) && memcmp(output, testVector4, 64) == 0) -#endif - - objc_autoreleasePoolPop(pool); -} -@end DELETED tests/OFSocketTests.m Index: tests/OFSocketTests.m ================================================================== --- tests/OFSocketTests.m +++ tests/OFSocketTests.m @@ -1,217 +0,0 @@ -/* - * Copyright (c) 2008-2024 Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It may be distributed under the terms of the - * Q Public License 1.0, which can be found in the file LICENSE.QPL included in - * the packaging of this file. - * - * Alternatively, it may be distributed under the terms of the GNU General - * Public License, either version 2 or 3, which can be found in the file - * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this - * file. - */ - -#include "config.h" - -#import "TestsAppDelegate.h" - -#define COMPARE_V6(a, a0, a1, a2, a3, a4, a5, a6, a7) \ - (a.sockaddr.in6.sin6_addr.s6_addr[0] == (a0 >> 8) && \ - a.sockaddr.in6.sin6_addr.s6_addr[1] == (a0 & 0xFF) && \ - a.sockaddr.in6.sin6_addr.s6_addr[2] == (a1 >> 8) && \ - a.sockaddr.in6.sin6_addr.s6_addr[3] == (a1 & 0xFF) && \ - a.sockaddr.in6.sin6_addr.s6_addr[4] == (a2 >> 8) && \ - a.sockaddr.in6.sin6_addr.s6_addr[5] == (a2 & 0xFF) && \ - a.sockaddr.in6.sin6_addr.s6_addr[6] == (a3 >> 8) && \ - a.sockaddr.in6.sin6_addr.s6_addr[7] == (a3 & 0xFF) && \ - a.sockaddr.in6.sin6_addr.s6_addr[8] == (a4 >> 8) && \ - a.sockaddr.in6.sin6_addr.s6_addr[9] == (a4 & 0xFF) && \ - a.sockaddr.in6.sin6_addr.s6_addr[10] == (a5 >> 8) && \ - a.sockaddr.in6.sin6_addr.s6_addr[11] == (a5 & 0xFF) && \ - a.sockaddr.in6.sin6_addr.s6_addr[12] == (a6 >> 8) && \ - a.sockaddr.in6.sin6_addr.s6_addr[13] == (a6 & 0xFF) && \ - a.sockaddr.in6.sin6_addr.s6_addr[14] == (a7 >> 8) && \ - a.sockaddr.in6.sin6_addr.s6_addr[15] == (a7 & 0xFF)) -#define SET_V6(a, a0, a1, a2, a3, a4, a5, a6, a7) \ - a.sockaddr.in6.sin6_addr.s6_addr[0] = a0 >> 8; \ - a.sockaddr.in6.sin6_addr.s6_addr[1] = a0 & 0xFF; \ - a.sockaddr.in6.sin6_addr.s6_addr[2] = a1 >> 8; \ - a.sockaddr.in6.sin6_addr.s6_addr[3] = a1 & 0xFF; \ - a.sockaddr.in6.sin6_addr.s6_addr[4] = a2 >> 8; \ - a.sockaddr.in6.sin6_addr.s6_addr[5] = a2 & 0xFF; \ - a.sockaddr.in6.sin6_addr.s6_addr[6] = a3 >> 8; \ - a.sockaddr.in6.sin6_addr.s6_addr[7] = a3 & 0xFF; \ - a.sockaddr.in6.sin6_addr.s6_addr[8] = a4 >> 8; \ - a.sockaddr.in6.sin6_addr.s6_addr[9] = a4 & 0xFF; \ - a.sockaddr.in6.sin6_addr.s6_addr[10] = a5 >> 8; \ - a.sockaddr.in6.sin6_addr.s6_addr[11] = a5 & 0xFF; \ - a.sockaddr.in6.sin6_addr.s6_addr[12] = a6 >> 8; \ - a.sockaddr.in6.sin6_addr.s6_addr[13] = a6 & 0xFF; \ - a.sockaddr.in6.sin6_addr.s6_addr[14] = a7 >> 8; \ - a.sockaddr.in6.sin6_addr.s6_addr[15] = a7 & 0xFF; - -static OFString *const module = @"OFSocket"; - -@implementation TestsAppDelegate (OFSocketTests) -- (void)socketTests -{ - void *pool = objc_autoreleasePoolPush(); - OFSocketAddress addr; - - TEST(@"Parsing an IPv4", - R(addr = OFSocketAddressParseIP(@"127.0.0.1", 1234)) && - OFFromBigEndian32(addr.sockaddr.in.sin_addr.s_addr) == 0x7F000001 && - OFFromBigEndian16(addr.sockaddr.in.sin_port) == 1234) - - EXPECT_EXCEPTION(@"Refusing invalid IPv4 #1", OFInvalidFormatException, - OFSocketAddressParseIP(@"127.0.0.0.1", 1234)) - - EXPECT_EXCEPTION(@"Refusing invalid IPv4 #2", OFInvalidFormatException, - OFSocketAddressParseIP(@"127.0.0.256", 1234)) - - EXPECT_EXCEPTION(@"Refusing invalid IPv4 #3", OFInvalidFormatException, - OFSocketAddressParseIP(@"127.0.0. 1", 1234)) - - EXPECT_EXCEPTION(@"Refusing invalid IPv4 #4", OFInvalidFormatException, - OFSocketAddressParseIP(@" 127.0.0.1", 1234)) - - EXPECT_EXCEPTION(@"Refusing invalid IPv4 #5", OFInvalidFormatException, - OFSocketAddressParseIP(@"127.0.a.1", 1234)) - - EXPECT_EXCEPTION(@"Refusing invalid IPv4 #6", OFInvalidFormatException, - OFSocketAddressParseIP(@"127.0..1", 1234)) - - TEST(@"Port of an IPv4 address", OFSocketAddressIPPort(&addr) == 1234) - - TEST(@"Converting an IPv4 to a string", - [OFSocketAddressString(&addr) isEqual: @"127.0.0.1"]) - - TEST(@"Parsing an IPv6 #1", - R(addr = OFSocketAddressParseIP( - @"1122:3344:5566:7788:99aa:bbCc:ddee:ff00", 1234)) && - COMPARE_V6(addr, - 0x1122, 0x3344, 0x5566, 0x7788, 0x99AA, 0xBBCC, 0xDDEE, 0xFF00) && - OFFromBigEndian16(addr.sockaddr.in6.sin6_port) == 1234) - - TEST(@"Parsing an IPv6 #2", - R(addr = OFSocketAddressParseIP(@"::", 1234)) && - COMPARE_V6(addr, 0, 0, 0, 0, 0, 0, 0, 0) && - OFFromBigEndian16(addr.sockaddr.in6.sin6_port) == 1234) - - TEST(@"Parsing an IPv6 #3", - R(addr = OFSocketAddressParseIP(@"aaAa::bBbb", 1234)) && - COMPARE_V6(addr, 0xAAAA, 0, 0, 0, 0, 0, 0, 0xBBBB) && - OFFromBigEndian16(addr.sockaddr.in6.sin6_port) == 1234) - - TEST(@"Parsing an IPv6 #4", - R(addr = OFSocketAddressParseIP(@"aaAa::", 1234)) && - COMPARE_V6(addr, 0xAAAA, 0, 0, 0, 0, 0, 0, 0) && - OFFromBigEndian16(addr.sockaddr.in6.sin6_port) == 1234) - - TEST(@"Parsing an IPv6 #5", - R(addr = OFSocketAddressParseIP(@"::aaAa", 1234)) && - COMPARE_V6(addr, 0, 0, 0, 0, 0, 0, 0, 0xAAAA) && - OFFromBigEndian16(addr.sockaddr.in6.sin6_port) == 1234) - - TEST(@"Parsing an IPv6 #6", - R(addr = OFSocketAddressParseIP(@"fd00::1%123", 1234)) && - COMPARE_V6(addr, 0xFD00, 0, 0, 0, 0, 0, 0, 1) && - OFFromBigEndian16(addr.sockaddr.in6.sin6_port) == 1234 && - addr.sockaddr.in6.sin6_scope_id == 123) - - TEST(@"Parsing an IPv6 #7", - R(addr = OFSocketAddressParseIP(@"::ffff:127.0.0.1", 1234)) && - COMPARE_V6(addr, 0, 0, 0, 0, 0, 0xFFFF, 0x7F00, 1) && - OFFromBigEndian16(addr.sockaddr.in6.sin6_port) == 1234) - - TEST(@"Parsing an IPv6 #8", - R(addr = OFSocketAddressParseIP(@"64:ff9b::127.0.0.1", 1234)) && - COMPARE_V6(addr, 0x64, 0xFF9B, 0, 0, 0, 0, 0x7F00, 1) && - OFFromBigEndian16(addr.sockaddr.in6.sin6_port) == 1234) - - EXPECT_EXCEPTION(@"Refusing invalid IPv6 #1", OFInvalidFormatException, - OFSocketAddressParseIP(@"1:::2", 1234)) - - EXPECT_EXCEPTION(@"Refusing invalid IPv6 #2", OFInvalidFormatException, - OFSocketAddressParseIP(@"1: ::2", 1234)) - - EXPECT_EXCEPTION(@"Refusing invalid IPv6 #3", OFInvalidFormatException, - OFSocketAddressParseIP(@"1:: :2", 1234)) - - EXPECT_EXCEPTION(@"Refusing invalid IPv6 #4", OFInvalidFormatException, - OFSocketAddressParseIP(@"1::2::3", 1234)) - - EXPECT_EXCEPTION(@"Refusing invalid IPv6 #5", OFInvalidFormatException, - OFSocketAddressParseIP(@"10000::1", 1234)) - - EXPECT_EXCEPTION(@"Refusing invalid IPv6 #6", OFInvalidFormatException, - OFSocketAddressParseIP(@"::10000", 1234)) - - EXPECT_EXCEPTION(@"Refusing invalid IPv6 #7", OFInvalidFormatException, - OFSocketAddressParseIP(@"::1::", 1234)) - - EXPECT_EXCEPTION(@"Refusing invalid IPv6 #8", OFInvalidFormatException, - OFSocketAddressParseIP(@"1:2:3:4:5:6:7:", 1234)) - - EXPECT_EXCEPTION(@"Refusing invalid IPv6 #9", OFInvalidFormatException, - OFSocketAddressParseIP(@"1:2:3:4:5:6:7::", 1234)) - - EXPECT_EXCEPTION(@"Refusing invalid IPv6 #10", OFInvalidFormatException, - OFSocketAddressParseIP(@"1:2", 1234)) - - TEST(@"Port of an IPv6 address", OFSocketAddressIPPort(&addr) == 1234) - - addr.sockaddr.in6.sin6_scope_id = 0; - - SET_V6(addr, 0, 0, 0, 0, 0, 0, 0, 0) - TEST(@"Converting an IPv6 to a string #1", - [OFSocketAddressString(&addr) isEqual: @"::"]) - - SET_V6(addr, 0, 0, 0, 0, 0, 0, 0, 1) - TEST(@"Converting an IPv6 to a string #2", - [OFSocketAddressString(&addr) isEqual: @"::1"]) - - SET_V6(addr, 1, 0, 0, 0, 0, 0, 0, 0) - TEST(@"Converting an IPv6 to a string #3", - [OFSocketAddressString(&addr) isEqual: @"1::"]) - - SET_V6(addr, - 0x1122, 0x3344, 0x5566, 0x7788, 0x99AA, 0xBBCC, 0xDDEE, 0xFF00) - TEST(@"Converting an IPv6 to a string #4", - [OFSocketAddressString(&addr) - isEqual: @"1122:3344:5566:7788:99aa:bbcc:ddee:ff00"]) - - SET_V6(addr, 0x1122, 0x3344, 0x5566, 0x7788, 0x99AA, 0xBBCC, 0xDDEE, 0) - TEST(@"Converting an IPv6 to a string #5", - [OFSocketAddressString(&addr) - isEqual: @"1122:3344:5566:7788:99aa:bbcc:ddee:0"]) - - SET_V6(addr, 0x1122, 0x3344, 0x5566, 0x7788, 0x99AA, 0xBBCC, 0, 0) - TEST(@"Converting an IPv6 to a string #6", - [OFSocketAddressString(&addr) - isEqual: @"1122:3344:5566:7788:99aa:bbcc::"]) - - SET_V6(addr, 0, 0x3344, 0x5566, 0x7788, 0x99AA, 0xBBCC, 0xDDEE, 0xFF00) - TEST(@"Converting an IPv6 to a string #7", - [OFSocketAddressString(&addr) - isEqual: @"0:3344:5566:7788:99aa:bbcc:ddee:ff00"]) - - SET_V6(addr, 0, 0, 0x5566, 0x7788, 0x99AA, 0xBBCC, 0xDDEE, 0xFF00) - TEST(@"Converting an IPv6 to a string #8", - [OFSocketAddressString(&addr) - isEqual: @"::5566:7788:99aa:bbcc:ddee:ff00"]) - - SET_V6(addr, 0, 0, 0x5566, 0, 0, 0, 0xDDEE, 0xFF00) - TEST(@"Converting an IPv6 to a string #9", - [OFSocketAddressString(&addr) isEqual: @"0:0:5566::ddee:ff00"]) - - SET_V6(addr, 0, 0, 0x5566, 0x7788, 0x99AA, 0xBBCC, 0, 0) - TEST(@"Converting an IPv6 to a string #10", - [OFSocketAddressString(&addr) - isEqual: @"::5566:7788:99aa:bbcc:0:0"]) - - objc_autoreleasePoolPop(pool); -} -@end DELETED tests/OFThreadTests.m Index: tests/OFThreadTests.m ================================================================== --- tests/OFThreadTests.m +++ tests/OFThreadTests.m @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2008-2024 Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It may be distributed under the terms of the - * Q Public License 1.0, which can be found in the file LICENSE.QPL included in - * the packaging of this file. - * - * Alternatively, it may be distributed under the terms of the GNU General - * Public License, either version 2 or 3, which can be found in the file - * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this - * file. - */ - -#include "config.h" - -#import "TestsAppDelegate.h" - -static OFString *const module = @"OFThread"; - -@interface TestThread: OFThread -@end - -@implementation TestThread -- (id)main -{ - [[OFThread threadDictionary] setObject: @"bar" forKey: @"foo"]; - OFEnsure([[[OFThread threadDictionary] - objectForKey: @"foo"] isEqual: @"bar"]); - - return @"success"; -} -@end - -@implementation TestsAppDelegate (OFThreadTests) -- (void)threadTests -{ - void *pool = objc_autoreleasePoolPush(); - TestThread *thread; - - TEST(@"+[thread]", (thread = [TestThread thread])) - - TEST(@"-[start]", R([thread start])) - - TEST(@"-[join]", [[thread join] isEqual: @"success"]) - - TEST(@"-[threadDictionary]", - [[OFThread threadDictionary] objectForKey: @"foo"] == nil) - - objc_autoreleasePoolPop(pool); -} -@end Index: tests/RuntimeTests.m ================================================================== --- tests/RuntimeTests.m +++ tests/RuntimeTests.m @@ -16,10 +16,11 @@ #include "config.h" #import "TestsAppDelegate.h" static OFString *const module = @"Runtime"; +static void *testKey = &testKey; @interface OFObject (SuperTest) - (id)superTest; @end @@ -86,10 +87,25 @@ test.bar = string; TEST(@"retain, atomic properties", test.bar == string && string.retainCount == 3) + TEST(@"Associated objects", + R(objc_setAssociatedObject(self, testKey, test, + OBJC_ASSOCIATION_ASSIGN)) && test.retainCount == 2 && + R(objc_setAssociatedObject(self, testKey, test, + OBJC_ASSOCIATION_RETAIN)) && test.retainCount == 3 && + objc_getAssociatedObject(self, testKey) == test && + test.retainCount == 4 && + R(objc_setAssociatedObject(self, testKey, test, + OBJC_ASSOCIATION_ASSIGN)) && test.retainCount == 3 && + R(objc_setAssociatedObject(self, testKey, test, + OBJC_ASSOCIATION_RETAIN_NONATOMIC)) && test.retainCount == 4 && + objc_getAssociatedObject(self, testKey) == test && + test.retainCount == 4 && + R(objc_removeAssociatedObjects(self)) && test.retainCount == 3) + #ifdef OF_OBJFW_RUNTIME if (sizeof(uintptr_t) == 8) value = 0xDEADBEEFDEADBEF; else if (sizeof(uintptr_t) == 4) value = 0xDEADBEF; Index: tests/TestsAppDelegate.h ================================================================== --- tests/TestsAppDelegate.h +++ tests/TestsAppDelegate.h @@ -65,26 +65,14 @@ @interface TestsAppDelegate (OFASN1DERRepresentationTests) - (void)ASN1DERRepresentationTests; @end -@interface TestsAppDelegate (OFArrayTests) -- (void)arrayTests; -@end - @interface TestsAppDelegate (OFBlockTests) - (void)blockTests; @end -@interface TestsAppDelegate (OFCharacterSetTests) -- (void)characterSetTests; -@end - -@interface TestsAppDelegate (OFColorTests) -- (void)colorTests; -@end - @interface TestsAppDelegate (OFDDPSocketTests) - (void)DDPSocketTests; @end @interface TestsAppDelegate (OFDNSResolverTests) @@ -93,14 +81,10 @@ @interface TestsAppDelegate (OFDataTests) - (void)dataTests; @end -@interface TestsAppDelegate (OFDateTests) -- (void)dateTests; -@end - @interface TestsAppDelegate (OFDictionaryTests) - (void)dictionaryTests; @end @interface TestsAppDelegate (ForwardingTests) @@ -117,34 +101,14 @@ @interface TestsAppDelegate (OFHTTPCookieManagerTests) - (void)HTTPCookieManagerTests; @end -@interface TestsAppDelegate (OFINIFileTests) -- (void)INIFileTests; -@end - -@interface TestsAppDelegate (OFIRITests) -- (void)IRITests; -@end - @interface TestsAppDelegate (OFIPXSocketTests) - (void)IPXSocketTests; @end -@interface TestsAppDelegate (OFInvocationTests) -- (void)invocationTests; -@end - -@interface TestsAppDelegate (OFJSONTests) -- (void)JSONTests; -@end - -@interface TestsAppDelegate (OFHMACTests) -- (void)HMACTests; -@end - @interface TestsAppDelegate (OFKernelEventObserverTests) - (void)kernelEventObserverTests; @end @interface TestsAppDelegate (OFListTests) @@ -153,86 +117,30 @@ @interface TestsAppDelegate (OFLocaleTests) - (void)localeTests; @end -@interface TestsAppDelegate (OFMD5HashTests) -- (void)MD5HashTests; -@end - -@interface TestsAppDelegate (OFMatrix4x4Tests) -- (void)matrix4x4Tests; -@end - @interface TestsAppDelegate (OFMemoryStreamTests) - (void)memoryStreamTests; @end -@interface TestsAppDelegate (OFMethodSignatureTests) -- (void)methodSignatureTests; -@end - @interface TestsAppDelegate (OFNotificationCenterTests) - (void)notificationCenterTests; @end -@interface TestsAppDelegate (OFNumberTests) -- (void)numberTests; -@end - @interface TestsAppDelegate (OFObjectTests) - (void)objectTests; @end -@interface TestsAppDelegate (OFPBKDF2Tests) -- (void)PBKDF2Tests; -@end - -@interface TestsAppDelegate (OFPropertyListTests) -- (void)propertyListTests; -@end - -@interface TestsAppDelegate (OFPluginTests) -- (void)pluginTests; -@end - @interface TestsAppDelegate (RuntimeTests) - (void)runtimeTests; @end @interface TestsAppDelegate (RuntimeARCTests) - (void)runtimeARCTests; @end -@interface TestsAppDelegate (OFRIPEMD160HashTests) -- (void)RIPEMD160HashTests; -@end - -@interface TestsAppDelegate (OFScryptTests) -- (void)scryptTests; -@end - -@interface TestsAppDelegate (OFSHA1HashTests) -- (void)SHA1HashTests; -@end - -@interface TestsAppDelegate (OFSHA224HashTests) -- (void)SHA224HashTests; -@end - -@interface TestsAppDelegate (OFSHA256HashTests) -- (void)SHA256HashTests; -@end - -@interface TestsAppDelegate (OFSHA384HashTests) -- (void)SHA384HashTests; -@end - -@interface TestsAppDelegate (OFSHA512HashTests) -- (void)SHA512HashTests; -@end - @interface TestsAppDelegate (OFSPXSocketTests) - (void)SPXSocketTests; @end @interface TestsAppDelegate (OFSPXStreamSocketTests) @@ -245,14 +153,10 @@ @interface TestsAppDelegate (OFSystemInfoTests) - (void)systemInfoTests; @end -@interface TestsAppDelegate (OFSocketTests) -- (void)socketTests; -@end - @interface TestsAppDelegate (OFStreamTests) - (void)streamTests; @end @interface TestsAppDelegate (OFStringTests) @@ -261,14 +165,10 @@ @interface TestsAppDelegate (OFTCPSocketTests) - (void)TCPSocketTests; @end -@interface TestsAppDelegate (OFThreadTests) -- (void)threadTests; -@end - @interface TestsAppDelegate (OFUDPSocketTests) - (void)UDPSocketTests; @end @interface TestsAppDelegate (OFUNIXDatagramSocketTests) Index: tests/TestsAppDelegate.m ================================================================== --- tests/TestsAppDelegate.m +++ tests/TestsAppDelegate.m @@ -373,45 +373,24 @@ [self runtimeTests]; #ifdef COMPILER_SUPPORTS_ARC [self runtimeARCTests]; #endif [self objectTests]; - [self methodSignatureTests]; - [self invocationTests]; [self forwardingTests]; #ifdef OF_HAVE_BLOCKS [self blockTests]; #endif [self stringTests]; - [self characterSetTests]; [self dataTests]; - [self arrayTests]; [self dictionaryTests]; [self listTests]; [self setTests]; - [self dateTests]; [self valueTests]; - [self numberTests]; - [self colorTests]; [self streamTests]; [self memoryStreamTests]; [self notificationCenterTests]; - [self MD5HashTests]; - [self RIPEMD160HashTests]; - [self SHA1HashTests]; - [self SHA224HashTests]; - [self SHA256HashTests]; - [self SHA384HashTests]; - [self SHA512HashTests]; - [self HMACTests]; - [self PBKDF2Tests]; - [self scryptTests]; -#ifdef HAVE_CODEPAGE_437 - [self INIFileTests]; -#endif #ifdef OF_HAVE_SOCKETS - [self socketTests]; [self TCPSocketTests]; [self UDPSocketTests]; # ifdef OF_HAVE_UNIX_SOCKETS [self UNIXDatagramSocketTests]; [self UNIXStreamSocketTests]; @@ -424,14 +403,10 @@ # ifdef OF_HAVE_APPLETALK [self DDPSocketTests]; # endif [self kernelEventObserverTests]; #endif -#ifdef OF_HAVE_THREADS - [self threadTests]; -#endif - [self IRITests]; #if defined(OF_HAVE_SOCKETS) && defined(OF_HAVE_THREADS) [self HTTPClientTests]; #endif #ifdef OF_HAVE_SOCKETS [self HTTPCookieTests]; @@ -438,21 +413,13 @@ [self HTTPCookieManagerTests]; #endif [self XMLParserTests]; [self XMLNodeTests]; [self XMLElementBuilderTests]; - [self JSONTests]; - [self propertyListTests]; [self ASN1DERParsingTests]; [self ASN1DERRepresentationTests]; - [self matrix4x4Tests]; - -#if defined(OF_HAVE_PLUGINS) - [self pluginTests]; -#endif - #ifdef OF_WINDOWS [self windowsRegistryKeyTests]; #endif #ifdef OF_HAVE_SOCKETS DELETED tests/plugin/Info.plist.in Index: tests/plugin/Info.plist.in ================================================================== --- tests/plugin/Info.plist.in +++ tests/plugin/Info.plist.in @@ -1,22 +0,0 @@ - - - - - CFBundleExecutable - TestPlugin - CFBundleName - TestPlugin - CFBundleIdentifier - im.nil.objfw.tests.plugin - CFBundleInfoDictionaryVersion - 6.0 - CFBundlePackageType - BNDL - CFBundleVersion - @BUNDLE_VERSION@ - CFBundleShortVersionString - @BUNDLE_SHORT_VERSION@ - MinimumOSVersion - 9.0 - - DELETED tests/plugin/Makefile Index: tests/plugin/Makefile ================================================================== --- tests/plugin/Makefile +++ tests/plugin/Makefile @@ -1,11 +0,0 @@ -DISTCLEAN = Info.plist - -PLUGIN_NOINST = TestPlugin${PLUGIN_SUFFIX} -SRCS = TestPlugin.m - -include ../../buildsys.mk -include ../../extra.mk - -CPPFLAGS += -I../.. -I../../src -I../../src/runtime -LIBS := ${TESTPLUGIN_LIBS} ${LIBS} -LD = ${OBJC} DELETED tests/plugin/TestPlugin.h Index: tests/plugin/TestPlugin.h ================================================================== --- tests/plugin/TestPlugin.h +++ tests/plugin/TestPlugin.h @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2008-2024 Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It may be distributed under the terms of the - * Q Public License 1.0, which can be found in the file LICENSE.QPL included in - * the packaging of this file. - * - * Alternatively, it may be distributed under the terms of the GNU General - * Public License, either version 2 or 3, which can be found in the file - * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this - * file. - */ - -#import "OFObject.h" - -@interface TestPlugin: OFObject -- (int)test: (int)num; -@end DELETED tests/plugin/TestPlugin.m Index: tests/plugin/TestPlugin.m ================================================================== --- tests/plugin/TestPlugin.m +++ tests/plugin/TestPlugin.m @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2008-2024 Jonathan Schleifer - * - * All rights reserved. - * - * This file is part of ObjFW. It may be distributed under the terms of the - * Q Public License 1.0, which can be found in the file LICENSE.QPL included in - * the packaging of this file. - * - * Alternatively, it may be distributed under the terms of the GNU General - * Public License, either version 2 or 3, which can be found in the file - * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this - * file. - */ - -#include "config.h" - -#import "TestPlugin.h" - -#ifdef OF_OBJFW_RUNTIME -# import "runtime/private.h" - -OF_DESTRUCTOR() -{ - Class class = objc_getClass("TestPlugin"); - - if (class == Nil) - /* - * musl has broken dlclose(): Instead of calling the destructor - * on dlclose(), they call it on exit(). This of course means - * that our tests might have already called objc_deinit() and - * the class is already gone. - */ - return; - - objc_unregisterClass(class); -} -#endif - -@implementation TestPlugin -- (int)test: (int)num -{ - return num * 2; -} -@end - -Class -class(void) -{ - return [TestPlugin class]; -} Index: tests/terminal/TerminalTests.m ================================================================== --- tests/terminal/TerminalTests.m +++ tests/terminal/TerminalTests.m @@ -28,11 +28,11 @@ @implementation TerminalTests - (void)applicationDidFinishLaunching: (OFNotification *)notification { OFArray *colors = [OFArray arrayWithObjects: - [OFColor black], [OFColor silver], [OFColor grey], [OFColor white], + [OFColor black], [OFColor silver], [OFColor gray], [OFColor white], [OFColor maroon], [OFColor red], [OFColor purple], [OFColor fuchsia], [OFColor green], [OFColor lime], [OFColor olive], [OFColor yellow], [OFColor navy], [OFColor blue], [OFColor teal], [OFColor aqua], nil]; size_t i; DELETED tests/testfile.bin Index: tests/testfile.bin ================================================================== --- tests/testfile.bin +++ tests/testfile.bin cannot compute difference between binary files DELETED tests/testfile.ini Index: tests/testfile.ini ================================================================== --- tests/testfile.ini +++ tests/testfile.ini @@ -1,21 +0,0 @@ -[tests] -foo = bar -foobar=baz -;comment - -[foobar] -;foobarcomment -qux=" asd" -"quxqux " = asd -quxquxqux="hello\"w”rld" -qux2="a\f" - -[types] -integer = 0x20 -bool = true -float = 0.5 -array1 = 1 -array2 = 1 -double = 0.25 -array1 = 2 -array2 = 2