ObjFW  Check-in [1779d5b5a7]

Overview
Comment:Merge trunk into branch "asn1"
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | asn1
Files: files | file ages | folders
SHA3-256: 1779d5b5a74a0cf7cfb0b185bad5e3ad6df5e2c48c06364eb8b11fa4265d3d3a
User & Date: js on 2024-02-18 21:07:27
Other Links: branch diff | manifest | tags
Context
2024-02-18
21:07
Merge trunk into branch "asn1" Leaf check-in: 1779d5b5a7 user: js tags: asn1
20:34
A few minor improvements check-in: 4eea22291b user: js tags: trunk
2024-02-11
23:56
Migrate OFASN1DERRepresentationTests to ObjFWTest check-in: 5bc1402377 user: js tags: asn1
Changes

Modified .fossil-settings/clean-glob from [e643e584dc] to [2a90f48586].

22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54


55


56
57
58
59
60
61
62
63
64
65
66
67
config.log
config.status
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/terminal/terminal_tests


tests/tests
tests/tests.3dsx
tests/tests.arm9
tests/tests.nds
tests/tests.nro
tests/tests.rpx
utils/objfw-config
utils/objfw-new/objfw-new
utils/ofarc/ofarc
utils/ofdns/ofdns
utils/ofhash/ofhash
utils/ofhttp/ofhttp







<
<
<
<
<
<
<
<
<
<
<
<














>
>

>
>












22
23
24
25
26
27
28












29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
config.log
config.status
configure
docs
extra.mk
generators/library/gen_libraries
generators/unicode/gen_tables












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/subprocess/subprocess
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
tests/tests.rpx
utils/objfw-config
utils/objfw-new/objfw-new
utils/ofarc/ofarc
utils/ofdns/ofdns
utils/ofhash/ofhash
utils/ofhttp/ofhttp

Modified .fossil-settings/ignore-glob from [c6f3c5d302] to [1998337625].

24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59


60


61
62
63
64
65
66
67
68
69
70
71
72
config.log
config.status
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/terminal/terminal_tests


tests/tests
tests/tests.3dsx
tests/tests.arm9
tests/tests.nds
tests/tests.nro
tests/tests.rpx
utils/objfw-config
utils/objfw-new/objfw-new
utils/ofarc/ofarc
utils/ofdns/ofdns
utils/ofhash/ofhash
utils/ofhttp/ofhttp







<
<
<
<
<
<
<
<
<
<
<
<

















>
>

>
>












24
25
26
27
28
29
30












31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
config.log
config.status
configure
docs
extra.mk
generators/library/gen_libraries
generators/unicode/gen_tables












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/subprocess/subprocess
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
tests/tests.rpx
utils/objfw-config
utils/objfw-new/objfw-new
utils/ofarc/ofarc
utils/ofdns/ofdns
utils/ofhash/ofhash
utils/ofhttp/ofhttp

Modified .gitignore from [fdf5c85348] to [f4069ec503].

24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59


60


61
62
63
64
65
66
67
68
69
70
71
72
config.log
config.status
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/terminal/terminal_tests


tests/tests
tests/tests.3dsx
tests/tests.arm9
tests/tests.nds
tests/tests.nro
tests/tests.rpx
utils/objfw-config
utils/objfw-new/objfw-new
utils/ofarc/ofarc
utils/ofdns/ofdns
utils/ofhash/ofhash
utils/ofhttp/ofhttp







<
<
<
<
<
<
<
<
<
<
<
<

















>
>

>
>












24
25
26
27
28
29
30












31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
config.log
config.status
configure
docs
extra.mk
generators/library/gen_libraries
generators/unicode/gen_tables












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/subprocess/subprocess
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
tests/tests.rpx
utils/objfw-config
utils/objfw-new/objfw-new
utils/ofarc/ofarc
utils/ofdns/ofdns
utils/ofhash/ofhash
utils/ofhttp/ofhttp

Modified ChangeLog from [400b1b6d53] to [fcedf24573].

1
2
3
4
5











6
7
8
9
10
11
12
Legend:
 * 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.





>
>
>
>
>
>
>
>
>
>
>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Legend:
 * Changes of existing features or bugfixes
 + New features

This file only contains the most significant changes.

ObjFW 1.0.8 -> ObjFW 1.0.9, 2024-02-18
 * Fixes OFGZIPStream reading the size and CRC32 incorrectly when either spans
   multiple reads.
 * Fixes a type mismatch in OFMapTable that could cause problems on big endian
   systems when uint32_t and unsigned long have a different size.
 * Fixes the default implementation of -[initWithKeys:arguments:] for custom
   dictionaries.
 * Improves detection of mutation during enumeration in
   -[enumerateKeysAndObjectsUsingBlock:].
 * Minor documentation fixes.

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.

Modified Makefile from [3b78119a83] to [cf98c87f50].

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
include extra.mk

SUBDIRS = src utils tests new_tests
DISTCLEAN = Info.plist		\
	    aclocal.m4		\
	    autom4te.cache	\
	    buildsys.mk		\
	    config.h		\
	    config.log		\
	    config.status	\
	    extra.mk

include buildsys.mk

.PHONY: check docs release

utils tests new_tests: src

check: tests new_tests
	cd tests && ${MAKE} -s run
	cd new_tests && ${MAKE} -s run

docs:
	rm -fr docs
	doxygen >/dev/null

release: docs
	echo "Generating tarball for version ${PACKAGE_VERSION}..."


|













|

|
|
<







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

21
22
23
24
25
26
27
include extra.mk

SUBDIRS = src utils tests
DISTCLEAN = Info.plist		\
	    aclocal.m4		\
	    autom4te.cache	\
	    buildsys.mk		\
	    config.h		\
	    config.log		\
	    config.status	\
	    extra.mk

include buildsys.mk

.PHONY: check docs release

utils tests: src

check: tests
	${MAKE} -C tests -s run


docs:
	rm -fr docs
	doxygen >/dev/null

release: docs
	echo "Generating tarball for version ${PACKAGE_VERSION}..."

Modified configure.ac from [724633f612] to [914db26e91].

437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
])

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(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}"
	], [
		TESTPLUGIN_LIBS="-L../../src -L../../src/runtime"







|







437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
])

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)

	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}"
	], [
		TESTPLUGIN_LIBS="-L../../src -L../../src/runtime"
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
		@end
	], [[
		__weak id foo = [Foo alloc];
		(void)foo;
	]])
], [
	AC_MSG_RESULT(yes)
	AC_DEFINE(COMPILER_SUPPORTS_ARC, 1, [Whether the compiler supports ARC])
	AC_SUBST(RUNTIME_ARC_TESTS_M, RuntimeARCTests.m)
], [
	AC_MSG_RESULT(no)
])
OBJCFLAGS="$old_OBJCFLAGS"

AC_C_BIGENDIAN([







<







735
736
737
738
739
740
741

742
743
744
745
746
747
748
		@end
	], [[
		__weak id foo = [Foo alloc];
		(void)foo;
	]])
], [
	AC_MSG_RESULT(yes)

	AC_SUBST(RUNTIME_ARC_TESTS_M, RuntimeARCTests.m)
], [
	AC_MSG_RESULT(no)
])
OBJCFLAGS="$old_OBJCFLAGS"

AC_C_BIGENDIAN([
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802

AC_CHECK_HEADER(inttypes.h,
	[AC_DEFINE(OF_HAVE_INTTYPES_H, 1, [Whether we have inttypes.h])])

AC_CHECK_HEADER(sys/types.h,
	[AC_DEFINE(OF_HAVE_SYS_TYPES_H, 1, [Whether we have sys/types.h])])

AC_CHECK_TYPE(max_align_t,
	[AC_DEFINE(OF_HAVE_MAX_ALIGN_T, 1, [Whether we have max_align_t])])

AC_CHECK_HEADER(stdnoreturn.h,
	[AC_DEFINE(OF_HAVE_STDNORETURN_H, 1, [Whether we have stdnoreturn.h])])

AC_CHECK_TYPE(wchar_t)
AC_CHECK_HEADER(wchar.h)

AC_CHECK_SIZEOF(float)







<
<
<







785
786
787
788
789
790
791



792
793
794
795
796
797
798

AC_CHECK_HEADER(inttypes.h,
	[AC_DEFINE(OF_HAVE_INTTYPES_H, 1, [Whether we have inttypes.h])])

AC_CHECK_HEADER(sys/types.h,
	[AC_DEFINE(OF_HAVE_SYS_TYPES_H, 1, [Whether we have sys/types.h])])




AC_CHECK_HEADER(stdnoreturn.h,
	[AC_DEFINE(OF_HAVE_STDNORETURN_H, 1, [Whether we have stdnoreturn.h])])

AC_CHECK_TYPE(wchar_t)
AC_CHECK_HEADER(wchar.h)

AC_CHECK_SIZEOF(float)

Deleted new_tests/Makefile version [8d253bc11b].

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
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 = OFASN1DERParsingTests.m		\
       OFASN1DERRepresentationTests.m	\
       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}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
















































































































































































































































































































































































Deleted new_tests/OFArrayTests.h version [418a1a5a2c].

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/*
 * Copyright (c) 2008-2024 Jonathan Schleifer <js@nil.im>
 *
 * 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
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<


















































Deleted new_tests/OFArrayTests.m version [82ed4031a9].

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
/*
 * Copyright (c) 2008-2024 Jonathan Schleifer <js@nil.im>
 *
 * 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
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<












































































































































































































































































































































































































































































































































































































































































































Deleted new_tests/OFCharacterSetTests.m version [2ac90291b5].

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
/*
 * Copyright (c) 2008-2024 Jonathan Schleifer <js@nil.im>
 *
 * 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
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<








































































































































































































Deleted new_tests/OFColorTests.m version [f2116a7a9c].

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
/*
 * Copyright (c) 2008-2024 Jonathan Schleifer <js@nil.im>
 *
 * 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
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<




























































































































Deleted new_tests/OFConcreteArrayTests.m version [70542429e0].

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
/*
 * Copyright (c) 2008-2024 Jonathan Schleifer <js@nil.im>
 *
 * 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
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<




























































Deleted new_tests/OFConcreteMutableArrayTests.m version [b38f014238].

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
/*
 * Copyright (c) 2008-2024 Jonathan Schleifer <js@nil.im>
 *
 * 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
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<


















































































































































































































Deleted new_tests/OFCryptographicHashTests.m version [9a95ece37d].

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
/*
 * Copyright (c) 2008-2024 Jonathan Schleifer <js@nil.im>
 *
 * 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 <string.h>

#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 <OFCryptographicHash> hash =
	    [hashClass hashWithAllowsSwappableMemory: true];
	id <OFCryptographicHash> 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
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
























































































































































































































































































Deleted new_tests/OFDateTests.m version [f4f700dfaa].

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
/*
 * Copyright (c) 2008-2024 Jonathan Schleifer <js@nil.im>
 *
 * 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 <time.h>

#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
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<












































































































































































































































































































































































































Deleted new_tests/OFHMACTests.m version [726dca6e51].

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
/*
 * Copyright (c) 2008-2024 Jonathan Schleifer <js@nil.im>
 *
 * 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 <string.h>

#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
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<




















































































































































































































































































Deleted new_tests/OFINIFileTests.m version [878892df10].

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
/*
 * Copyright (c) 2008-2024 Jonathan Schleifer <js@nil.im>
 *
 * 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
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<






















































































































































































































































































































































Deleted new_tests/OFInvocationTests.m version [11b71f5c4f].

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
/*
 * Copyright (c) 2008-2024 Jonathan Schleifer <js@nil.im>
 *
 * 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 <string.h>

#if defined(HAVE_COMPLEX_H) && !defined(__STDC_NO_COMPLEX__)
# include <complex.h>
#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
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<




























































































































































































































Deleted new_tests/OFJSONTests.m version [125230cf82].

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
/*
 * Copyright (c) 2008-2024 Jonathan Schleifer <js@nil.im>
 *
 * 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
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<






















































































































































































































































































Deleted new_tests/OFMethodSignatureTests.m version [27f044c8f7].

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
/*
 * Copyright (c) 2008-2024 Jonathan Schleifer <js@nil.im>
 *
 * 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 <string.h>

#if !defined(__STDC_NO_COMPLEX__) && defined(HAVE_COMPLEX_H)
# include <complex.h>
#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
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<




























































































































































































































































































































































Deleted new_tests/OFMutableArrayTests.h version [5ae96e61d9].

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/*
 * Copyright (c) 2008-2024 Jonathan Schleifer <js@nil.im>
 *
 * 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
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<












































Deleted new_tests/OFMutableArrayTests.m version [55585061e4].

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
/*
 * Copyright (c) 2008-2024 Jonathan Schleifer <js@nil.im>
 *
 * 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
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
























































































































































































































































































































































































































































































































Deleted new_tests/OFNumberTests.m version [03fbf0fe79].

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
/*
 * Copyright (c) 2008-2024 Jonathan Schleifer <js@nil.im>
 *
 * 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
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
























































































































































































































































Deleted new_tests/OFPluginTests.m version [b4655165af].

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
/*
 * Copyright (c) 2008-2024 Jonathan Schleifer <js@nil.im>
 *
 * 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
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<












































































































Deleted new_tests/OFPropertyListTests.m version [2c2f0ce2a0].

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
/*
 * Copyright (c) 2008-2024 Jonathan Schleifer <js@nil.im>
 *
 * 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)							\
	@"<?xml version=\"1.0\" encoding=\"UTF-8\"?>"			\
	@"<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" "	\
	@"\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">"		\
	@"<plist version=\"1.0\">\n"					\
	x @"\n"								\
	@"</plist>"

@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(
	    @"<string>Hello</string>") objectByParsingPropertyList],
	    @"Hello");
	OTAssertEqualObjects([PLIST(
	    @"<array>"
	    @" <string>Hello</string>"
	    @" <data>V29ybGQh</data>"
	    @" <date>2018-03-14T12:34:56Z</date>"
	    @" <true/>"
	    @" <false/>"
	    @" <real>12.25</real>"
	    @" <integer>-10</integer>"
	    @"</array>") objectByParsingPropertyList],
	    array);
	OTAssertEqualObjects([PLIST(
	    @"<dict>"
	    @" <key>array</key>"
	    @" <array>"
	    @"  <string>Hello</string>"
	    @"  <data>V29ybGQh</data>"
	    @"  <date>2018-03-14T12:34:56Z</date>"
	    @"  <true/>"
	    @"  <false/>"
	    @"  <real>12.25</real>"
	    @"  <integer>-10</integer>"
	    @" </array>"
	    @" <key>foo</key>"
	    @" <string>bar</string>"
	    @"</dict>") objectByParsingPropertyList],
	    ([OFDictionary dictionaryWithKeysAndObjects:
	    @"array", array,
	    @"foo", @"bar",
	    nil]));
}

- (void)testDetectUnsupportedVersion
{
	OTAssertThrowsSpecific(
	    [[PLIST(@"<string/>")
	    stringByReplacingOccurrencesOfString: @"1.0"
				      withString: @"1.1"]
	    objectByParsingPropertyList],
	    OFUnsupportedVersionException);
}

- (void)testDetectInvalidFormat
{
	OTAssertThrowsSpecific(
	    [PLIST(@"<string x='b'/>") objectByParsingPropertyList],
	    OFInvalidFormatException);

	OTAssertThrowsSpecific(
	    [PLIST(@"<string xmlns='foo'/>") objectByParsingPropertyList],
	    OFInvalidFormatException);

	OTAssertThrowsSpecific(
	    [PLIST(@"<dict count='0'/>") objectByParsingPropertyList],
	    OFInvalidFormatException);

	OTAssertThrowsSpecific(
	    [PLIST(@"<dict><key/><string/><key/></dict>")
	    objectByParsingPropertyList],
	    OFInvalidFormatException);

	OTAssertThrowsSpecific(
	    [PLIST(@"<dict><key x='x'/><string/></dict>")
	    objectByParsingPropertyList],
	    OFInvalidFormatException);
}
@end
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<




































































































































































































































Deleted new_tests/OFSubprocessTests.m version [bf448d2b80].

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
/*
 * Copyright (c) 2008-2024 Jonathan Schleifer <js@nil.im>
 *
 * 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
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<








































































































Deleted new_tests/OFThreadTests.m version [b2b1434e44].

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
/*
 * Copyright (c) 2008-2024 Jonathan Schleifer <js@nil.im>
 *
 * 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
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
































































































Deleted new_tests/plugin/Info.plist.in version [bbe65d4bbd].

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>CFBundleExecutable</key>
	<string>TestPlugin</string>
	<key>CFBundleName</key>
	<string>TestPlugin</string>
	<key>CFBundleIdentifier</key>
	<string>im.nil.objfw.tests.plugin</string>
	<key>CFBundleInfoDictionaryVersion</key>
	<string>6.0</string>
	<key>CFBundlePackageType</key>
	<string>BNDL</string>
	<key>CFBundleVersion</key>
	<string>@BUNDLE_VERSION@</string>
	<key>CFBundleShortVersionString</key>
	<string>@BUNDLE_SHORT_VERSION@</string>
	<key>MinimumOSVersion</key>
	<string>9.0</string>
</dict>
</plist>
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<












































Deleted new_tests/plugin/Makefile version [a32249aa5e].

1
2
3
4
5
6
7
8
9
10
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}
<
<
<
<
<
<
<
<
<
<
<






















Deleted new_tests/plugin/TestPlugin.h version [0bf4ece135].

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/*
 * Copyright (c) 2008-2024 Jonathan Schleifer <js@nil.im>
 *
 * 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 new_tests/plugin/TestPlugin.m version [f9d32844b0].

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
/*
 * Copyright (c) 2008-2024 Jonathan Schleifer <js@nil.im>
 *
 * 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];
}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<






































































































Deleted new_tests/subprocess/Makefile version [0c326652cc].

1
2
3
4
5
6
7
8
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}
<
<
<
<
<
<
<
<
<


















Deleted new_tests/subprocess/Subprocess.m version [31a1046120].

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
/*
 * Copyright (c) 2008-2024 Jonathan Schleifer <js@nil.im>
 *
 * 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 <OFApplicationDelegate>
@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
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<






















































































Deleted new_tests/testfile.bin version [ac78121630].

cannot compute difference between binary files

Deleted new_tests/testfile.ini version [9e2ef2dc1a].

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<










































Modified src/OFDictionary.m from [b6db2734d8] to [4417aedc0d].

315
316
317
318
319
320
321








322
323
324
325
326
327
328
		if (count % 2 != 0)
			@throw [OFInvalidArgumentException exception];

		count /= 2;

		objects = OFAllocMemory(count, sizeof(id));
		keys = OFAllocMemory(count, sizeof(id));









		while ((key = va_arg(arguments, id)) != nil &&
		    (object = va_arg(arguments, id)) != nil) {
			OFEnsure(i < count);

			objects[i] = object;
			keys[i] = key;







>
>
>
>
>
>
>
>







315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
		if (count % 2 != 0)
			@throw [OFInvalidArgumentException exception];

		count /= 2;

		objects = OFAllocMemory(count, sizeof(id));
		keys = OFAllocMemory(count, sizeof(id));

		keys[i] = firstKey;
		objects[i] = va_arg(arguments, id);

		if (objects[i] == nil)
			@throw [OFInvalidArgumentException exception];

		i++;

		while ((key = va_arg(arguments, id)) != nil &&
		    (object = va_arg(arguments, id)) != nil) {
			OFEnsure(i < count);

			objects[i] = object;
			keys[i] = key;

Modified src/OFMapTable.m from [810b88a011] to [77fd4c4f10].

24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#import "OFMapTable+Private.h"
#import "OFEnumerator.h"

#import "OFEnumerationMutationException.h"
#import "OFInvalidArgumentException.h"
#import "OFOutOfRangeException.h"

extern uint32_t OFHashSeed;

static const uint32_t minCapacity = 16;

struct OFMapTableBucket {
	void *key, *object;
	uint32_t hash;
};







|







24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#import "OFMapTable+Private.h"
#import "OFEnumerator.h"

#import "OFEnumerationMutationException.h"
#import "OFInvalidArgumentException.h"
#import "OFOutOfRangeException.h"

extern unsigned long OFHashSeed;

static const uint32_t minCapacity = 16;

struct OFMapTableBucket {
	void *key, *object;
	uint32_t hash;
};
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483

484
485
486
487
488
489
490

	for (i = rotatedHash & (_capacity - 1);
	    i < last && _buckets[i] != NULL; i++) {
		if (_buckets[i] == &deletedBucket)
			continue;

		if (_keyFunctions.equal(_buckets[i]->key, key)) {
			_mutations++;

			_keyFunctions.release(_buckets[i]->key);
			_objectFunctions.release(_buckets[i]->object);

			OFFreeMemory(_buckets[i]);
			_buckets[i] = &deletedBucket;

			_count--;

			resizeForCount(self, _count);

			return;
		}
	}

	if (i < last)







<
<







>







468
469
470
471
472
473
474


475
476
477
478
479
480
481
482
483
484
485
486
487
488
489

	for (i = rotatedHash & (_capacity - 1);
	    i < last && _buckets[i] != NULL; i++) {
		if (_buckets[i] == &deletedBucket)
			continue;

		if (_keyFunctions.equal(_buckets[i]->key, key)) {


			_keyFunctions.release(_buckets[i]->key);
			_objectFunctions.release(_buckets[i]->object);

			OFFreeMemory(_buckets[i]);
			_buckets[i] = &deletedBucket;

			_count--;
			_mutations++;
			resizeForCount(self, _count);

			return;
		}
	}

	if (i < last)
614
615
616
617
618
619
620



621
622
623
624
625
626
627
628
629
630
631
632
633
#ifdef OF_HAVE_BLOCKS
- (void)enumerateKeysAndObjectsUsingBlock: (OFMapTableEnumerationBlock)block
{
	bool stop = false;
	unsigned long mutations = _mutations;

	for (size_t i = 0; i < _capacity && !stop; i++) {



		if (_mutations != mutations)
			@throw [OFEnumerationMutationException
			    exceptionWithObject: self];

		if (_buckets[i] != NULL && _buckets[i] != &deletedBucket)
			block(_buckets[i]->key, _buckets[i]->object, &stop);
	}
}

- (void)replaceObjectsUsingBlock: (OFMapTableReplaceBlock)block
{
	unsigned long mutations = _mutations;








>
>
>



<
<
<







613
614
615
616
617
618
619
620
621
622
623
624
625



626
627
628
629
630
631
632
#ifdef OF_HAVE_BLOCKS
- (void)enumerateKeysAndObjectsUsingBlock: (OFMapTableEnumerationBlock)block
{
	bool stop = false;
	unsigned long mutations = _mutations;

	for (size_t i = 0; i < _capacity && !stop; i++) {
		if (_buckets[i] != NULL && _buckets[i] != &deletedBucket)
			block(_buckets[i]->key, _buckets[i]->object, &stop);

		if (_mutations != mutations)
			@throw [OFEnumerationMutationException
			    exceptionWithObject: self];



	}
}

- (void)replaceObjectsUsingBlock: (OFMapTableReplaceBlock)block
{
	unsigned long mutations = _mutations;

Modified src/OFObject.m from [70b0e206af] to [8335b4d9d4].

83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
struct PreIvars {
	int retainCount;
#if !defined(OF_HAVE_ATOMIC_OPS) && !defined(OF_AMIGAOS)
	OFSpinlock retainCountSpinlock;
#endif
};

#define PRE_IVARS_ALIGN ((sizeof(struct PreIvars) + \
    (OF_BIGGEST_ALIGNMENT - 1)) & ~(OF_BIGGEST_ALIGNMENT - 1))
#define PRE_IVARS ((struct PreIvars *)(void *)((char *)self - PRE_IVARS_ALIGN))

static struct {
	Class isa;
} allocFailedException;

unsigned long OFHashSeed;







|
|







83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
struct PreIvars {
	int retainCount;
#if !defined(OF_HAVE_ATOMIC_OPS) && !defined(OF_AMIGAOS)
	OFSpinlock retainCountSpinlock;
#endif
};

#define PRE_IVARS_ALIGN \
	OFRoundUpToPowerOf2(sizeof(struct PreIvars), OF_BIGGEST_ALIGNMENT)
#define PRE_IVARS ((struct PreIvars *)(void *)((char *)self - PRE_IVARS_ALIGN))

static struct {
	Class isa;
} allocFailedException;

unsigned long OFHashSeed;
336
337
338
339
340
341
342

343
344






345
346
347
348
349
350
351
352
353
354
355
356

357



358
359
360
361
362
363
364
365
366
367
368
369

370



371
372
373
374
375
376
377
	instanceSize = class_getInstanceSize(class);

	if OF_UNLIKELY (extraAlignment > 1)
		extraAlignment = OFRoundUpToPowerOf2(extraAlignment,
		    PRE_IVARS_ALIGN + instanceSize) -
		    PRE_IVARS_ALIGN - instanceSize;


	instance = calloc(1, PRE_IVARS_ALIGN + instanceSize +
	    extraAlignment + extraSize);







	if OF_UNLIKELY (instance == nil) {
		object_setClass((id)&allocFailedException,
		    [OFAllocFailedException class]);
		@throw (id)&allocFailedException;
	}

	((struct PreIvars *)instance)->retainCount = 1;

#if !defined(OF_HAVE_ATOMIC_OPS) && !defined(OF_AMIGAOS)
	if OF_UNLIKELY (OFSpinlockNew(
	    &((struct PreIvars *)instance)->retainCountSpinlock) != 0) {

		free(instance);



		@throw [OFInitializationFailedException
		    exceptionWithClass: class];
	}
#endif

	instance = (OFObject *)(void *)((char *)instance + PRE_IVARS_ALIGN);

	if (!objc_constructInstance(class, instance)) {
#if !defined(OF_HAVE_ATOMIC_OPS) && !defined(OF_AMIGAOS)
		OFSpinlockFree(&((struct PreIvars *)(void *)
		    ((char *)instance - PRE_IVARS_ALIGN))->retainCountSpinlock);
#endif

		free((char *)instance - PRE_IVARS_ALIGN);



		@throw [OFInitializationFailedException
		    exceptionWithClass: class];
	}

	if OF_UNLIKELY (extra != NULL)
		*extra = (char *)instance + instanceSize + extraAlignment;








>


>
>
>
>
>
>












>

>
>
>












>

>
>
>







336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
	instanceSize = class_getInstanceSize(class);

	if OF_UNLIKELY (extraAlignment > 1)
		extraAlignment = OFRoundUpToPowerOf2(extraAlignment,
		    PRE_IVARS_ALIGN + instanceSize) -
		    PRE_IVARS_ALIGN - instanceSize;

#ifndef OF_WINDOWS
	instance = calloc(1, PRE_IVARS_ALIGN + instanceSize +
	    extraAlignment + extraSize);
#else
	instance = _aligned_malloc(PRE_IVARS_ALIGN + instanceSize +
	    extraAlignment + extraSize, OF_BIGGEST_ALIGNMENT);
	memset(instance, 0, PRE_IVARS_ALIGN + instanceSize + extraAlignment +
	    extraSize);
#endif

	if OF_UNLIKELY (instance == nil) {
		object_setClass((id)&allocFailedException,
		    [OFAllocFailedException class]);
		@throw (id)&allocFailedException;
	}

	((struct PreIvars *)instance)->retainCount = 1;

#if !defined(OF_HAVE_ATOMIC_OPS) && !defined(OF_AMIGAOS)
	if OF_UNLIKELY (OFSpinlockNew(
	    &((struct PreIvars *)instance)->retainCountSpinlock) != 0) {
# ifndef OF_WINDOWS
		free(instance);
# else
		_aligned_free(instance);
# endif
		@throw [OFInitializationFailedException
		    exceptionWithClass: class];
	}
#endif

	instance = (OFObject *)(void *)((char *)instance + PRE_IVARS_ALIGN);

	if (!objc_constructInstance(class, instance)) {
#if !defined(OF_HAVE_ATOMIC_OPS) && !defined(OF_AMIGAOS)
		OFSpinlockFree(&((struct PreIvars *)(void *)
		    ((char *)instance - PRE_IVARS_ALIGN))->retainCountSpinlock);
#endif
#ifndef OF_WINDOWS
		free((char *)instance - PRE_IVARS_ALIGN);
#else
		_aligned_free((char *)instance - PRE_IVARS_ALIGN);
#endif
		@throw [OFInitializationFailedException
		    exceptionWithClass: class];
	}

	if OF_UNLIKELY (extra != NULL)
		*extra = (char *)instance + instanceSize + extraAlignment;

1230
1231
1232
1233
1234
1235
1236

1237



1238
1239
1240
1241
1242
1243
1244
{
	objc_destructInstance(self);

#if !defined(OF_HAVE_ATOMIC_OPS) && !defined(OF_AMIGAOS)
	OFSpinlockFree(&PRE_IVARS->retainCountSpinlock);
#endif


	free((char *)self - PRE_IVARS_ALIGN);



}

/* Required to use properties with the Apple runtime */
- (id)copyWithZone: (void *)zone
{
	if OF_UNLIKELY (zone != NULL) {
		[self doesNotRecognizeSelector: _cmd];







>

>
>
>







1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
{
	objc_destructInstance(self);

#if !defined(OF_HAVE_ATOMIC_OPS) && !defined(OF_AMIGAOS)
	OFSpinlockFree(&PRE_IVARS->retainCountSpinlock);
#endif

#ifndef OF_WINDOWS
	free((char *)self - PRE_IVARS_ALIGN);
#else
	_aligned_free((char *)self - PRE_IVARS_ALIGN);
#endif
}

/* Required to use properties with the Apple runtime */
- (id)copyWithZone: (void *)zone
{
	if OF_UNLIKELY (zone != NULL) {
		[self doesNotRecognizeSelector: _cmd];

Modified src/OFStdIOStream.m from [4bd5de9454] to [4e9d096bab].

115
116
117
118
119
120
121
122
123
124
125
126
127
128
129

	[OFStdErr writeFormat: @"[%@.%03d %@(%d)] %@\n", dateString,
			       date.microsecond / 1000, me, getpid(), msg];

	objc_autoreleasePoolPop(pool);
}

#if defined(HAVE_ISATTY) && !defined(OF_WII_U)
static int
colorToANSI(OFColor *color)
{
	if ([color isEqual: [OFColor black]])
		return 30;
	if ([color isEqual: [OFColor maroon]])
		return 31;







<







115
116
117
118
119
120
121

122
123
124
125
126
127
128

	[OFStdErr writeFormat: @"[%@.%03d %@(%d)] %@\n", dateString,
			       date.microsecond / 1000, me, getpid(), msg];

	objc_autoreleasePoolPop(pool);
}


static int
colorToANSI(OFColor *color)
{
	if ([color isEqual: [OFColor black]])
		return 30;
	if ([color isEqual: [OFColor maroon]])
		return 31;
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
	if ([color isEqual: [OFColor aqua]])
		return 96;
	if ([color isEqual: [OFColor white]])
		return 97;

	return -1;
}
#endif

@implementation OFStdIOStream
#ifndef OF_WINDOWS
+ (void)load
{
	if (self != [OFStdIOStream class])
		return;







<







153
154
155
156
157
158
159

160
161
162
163
164
165
166
	if ([color isEqual: [OFColor aqua]])
		return 96;
	if ([color isEqual: [OFColor white]])
		return 97;

	return -1;
}


@implementation OFStdIOStream
#ifndef OF_WINDOWS
+ (void)load
{
	if (self != [OFStdIOStream class])
		return;
428
429
430
431
432
433
434



435
436
437
438
439
440
441
442
- (unsigned int)retainCount
{
	return OFMaxRetainCount;
}

- (bool)hasTerminal
{



#if defined(HAVE_ISATTY) && !defined(OF_WII_U)
	return isatty(_fd);
#else
	return false;
#endif
}

- (int)columns







>
>
>
|







426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
- (unsigned int)retainCount
{
	return OFMaxRetainCount;
}

- (bool)hasTerminal
{
#if defined(OF_WII) || defined(OF_NINTENDO_DS) || defined(OF_NINTENDO_3DS) || \
    defined(OF_NINTENDO_SWITCH)
	return true;
#elif defined(HAVE_ISATTY) && !defined(OF_WII_U)
	return isatty(_fd);
#else
	return false;
#endif
}

- (int)columns
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
#else
	return -1;
#endif
}

- (void)setForegroundColor: (OFColor *)color
{
#if defined(HAVE_ISATTY) && !defined(OF_WII_U)
	int code;

	if (!isatty(_fd))
		return;

	if ((code = colorToANSI(color)) == -1)
		return;

	[self writeFormat: @"\033[%um", code];
#endif
}

- (void)setBackgroundColor: (OFColor *)color
{
#if defined(HAVE_ISATTY) && !defined(OF_WII_U)
	int code;

	if (!isatty(_fd))
		return;

	if ((code = colorToANSI(color)) == -1)
		return;

	[self writeFormat: @"\033[%um", code + 10];
#endif
}

- (void)reset
{
#if defined(HAVE_ISATTY) && !defined(OF_WII_U)
	if (!isatty(_fd))
		return;

	[self writeString: @"\033[0m"];
#endif
}

- (void)clear
{
#if defined(HAVE_ISATTY) && !defined(OF_WII_U)
	if (!isatty(_fd))
		return;

	[self writeString: @"\033[2J"];
#endif
}

- (void)eraseLine
{
#if defined(HAVE_ISATTY) && !defined(OF_WII_U)
	if (!isatty(_fd))
		return;

	[self writeString: @"\033[2K"];
#endif
}

- (void)setCursorColumn: (unsigned int)column
{
#if defined(HAVE_ISATTY) && !defined(OF_WII_U)
	if (!isatty(_fd))
		return;

	[self writeFormat: @"\033[%uG", column + 1];
#endif
}

- (void)setCursorPosition: (OFPoint)position
{
	if (position.x < 0 || position.y < 0)
		@throw [OFInvalidArgumentException exception];

#if defined(HAVE_ISATTY) && !defined(OF_WII_U)
	if (!isatty(_fd))
		return;

	[self writeFormat: @"\033[%u;%uH",
			   (unsigned)position.y + 1, (unsigned)position.x + 1];
#endif
}

- (void)setRelativeCursorPosition: (OFPoint)position
{
#if defined(HAVE_ISATTY) && !defined(OF_WII_U)
	if (!isatty(_fd))
		return;

	if (position.x > 0)
		[self writeFormat: @"\033[%uC", (unsigned)position.x];
	else if (position.x < 0)
		[self writeFormat: @"\033[%uD", (unsigned)-position.x];

	if (position.y > 0)
		[self writeFormat: @"\033[%uB", (unsigned)position.y];
	else if (position.y < 0)
		[self writeFormat: @"\033[%uA", (unsigned)-position.y];
#endif
}
@end







<


|






<




<


|






<




<
|



<




<
|



<




<
|



<




<
|



<







<
|




<




<
|











<


468
469
470
471
472
473
474

475
476
477
478
479
480
481
482
483

484
485
486
487

488
489
490
491
492
493
494
495
496

497
498
499
500

501
502
503
504

505
506
507
508

509
510
511
512

513
514
515
516

517
518
519
520

521
522
523
524

525
526
527
528

529
530
531
532
533
534
535

536
537
538
539
540

541
542
543
544

545
546
547
548
549
550
551
552
553
554
555
556

557
558
#else
	return -1;
#endif
}

- (void)setForegroundColor: (OFColor *)color
{

	int code;

	if (!self.hasTerminal)
		return;

	if ((code = colorToANSI(color)) == -1)
		return;

	[self writeFormat: @"\033[%um", code];

}

- (void)setBackgroundColor: (OFColor *)color
{

	int code;

	if (!self.hasTerminal)
		return;

	if ((code = colorToANSI(color)) == -1)
		return;

	[self writeFormat: @"\033[%um", code + 10];

}

- (void)reset
{

	if (!self.hasTerminal)
		return;

	[self writeString: @"\033[0m"];

}

- (void)clear
{

	if (!self.hasTerminal)
		return;

	[self writeString: @"\033[2J"];

}

- (void)eraseLine
{

	if (!self.hasTerminal)
		return;

	[self writeString: @"\033[2K"];

}

- (void)setCursorColumn: (unsigned int)column
{

	if (!self.hasTerminal)
		return;

	[self writeFormat: @"\033[%uG", column + 1];

}

- (void)setCursorPosition: (OFPoint)position
{
	if (position.x < 0 || position.y < 0)
		@throw [OFInvalidArgumentException exception];


	if (!self.hasTerminal)
		return;

	[self writeFormat: @"\033[%u;%uH",
			   (unsigned)position.y + 1, (unsigned)position.x + 1];

}

- (void)setRelativeCursorPosition: (OFPoint)position
{

	if (!self.hasTerminal)
		return;

	if (position.x > 0)
		[self writeFormat: @"\033[%uC", (unsigned)position.x];
	else if (position.x < 0)
		[self writeFormat: @"\033[%uD", (unsigned)-position.x];

	if (position.y > 0)
		[self writeFormat: @"\033[%uB", (unsigned)position.y];
	else if (position.y < 0)
		[self writeFormat: @"\033[%uA", (unsigned)-position.y];

}
@end

Modified src/OFString+PathAdditions.m from [d839db3f93] to [1756dbb6cf].

17
18
19
20
21
22
23
24
25
26
27
28
29

#include "platform.h"

#if defined(OF_WINDOWS) || defined(OF_MSDOS) || defined(OF_MINT)
# import "platform/Windows/OFString+PathAdditions.m"
#elif defined(OF_AMIGAOS)
# import "platform/AmigaOS/OFString+PathAdditions.m"
#elif defined(OF_NINTENDO_3DS) || defined(OF_WII) || \
    defined(OF_NINTENDO_SWITCH)
# import "platform/libfat/OFString+PathAdditions.m"
#else
# import "platform/POSIX/OFString+PathAdditions.m"
#endif







|
|




17
18
19
20
21
22
23
24
25
26
27
28
29

#include "platform.h"

#if defined(OF_WINDOWS) || defined(OF_MSDOS) || defined(OF_MINT)
# import "platform/Windows/OFString+PathAdditions.m"
#elif defined(OF_AMIGAOS)
# import "platform/AmigaOS/OFString+PathAdditions.m"
#elif defined(OF_WII) || defined(OF_NINTENDO_DS) || \
    defined(OF_NINTENDO_3DS) || defined(OF_NINTENDO_SWITCH)
# import "platform/libfat/OFString+PathAdditions.m"
#else
# import "platform/POSIX/OFString+PathAdditions.m"
#endif

Modified src/OFString.m from [855db5cb26] to [fd5aa1a3b0].

2337
2338
2339
2340
2341
2342
2343
2344

2345
2346
2347
2348


2349
2350
2351
2352
2353
2354
2355
	if ([stripped caseInsensitiveCompare: @"-NAN"] == OFOrderedSame)
		return -NAN;

#if defined(HAVE_STRTOF_L) || defined(HAVE_USELOCALE)
	const char *UTF8String = self.UTF8String;
#else
	/*
	 * If we have no strtof_l, we have no other choice but to replace "."

	 * with the locale's decimal point.
	 */
	OFString *decimalSeparator = [OFLocale decimalSeparator];
	const char *UTF8String = [self


	    stringByReplacingOccurrencesOfString: @"."
				      withString: decimalSeparator].UTF8String;
#endif
	char *endPtr = NULL;
	float value;

	errno = 0;







|
>
|


|
>
>







2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
	if ([stripped caseInsensitiveCompare: @"-NAN"] == OFOrderedSame)
		return -NAN;

#if defined(HAVE_STRTOF_L) || defined(HAVE_USELOCALE)
	const char *UTF8String = self.UTF8String;
#else
	/*
	 * If we have no strtof_l, we have no other choice than to replace the
	 * locale's decimal point with something that will be rejected and
	 * replacing "." with the locale's decimal point.
	 */
	OFString *decimalSeparator = [OFLocale decimalSeparator];
	const char *UTF8String = [[self
	    stringByReplacingOccurrencesOfString: decimalSeparator
				      withString: @"!"]
	    stringByReplacingOccurrencesOfString: @"."
				      withString: decimalSeparator].UTF8String;
#endif
	char *endPtr = NULL;
	float value;

	errno = 0;
2394
2395
2396
2397
2398
2399
2400
2401

2402
2403
2404
2405


2406
2407
2408
2409
2410
2411
2412
	if ([stripped caseInsensitiveCompare: @"-NAN"] == OFOrderedSame)
		return -NAN;

#if defined(HAVE_STRTOD_L) || defined(HAVE_USELOCALE)
	const char *UTF8String = self.UTF8String;
#else
	/*
	 * If we have no strtod_l, we have no other choice but to replace "."

	 * with the locale's decimal point.
	 */
	OFString *decimalSeparator = [OFLocale decimalSeparator];
	const char *UTF8String = [self


	    stringByReplacingOccurrencesOfString: @"."
				      withString: decimalSeparator].UTF8String;
#endif
	char *endPtr = NULL;
	double value;

	errno = 0;







|
>
|


|
>
>







2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
	if ([stripped caseInsensitiveCompare: @"-NAN"] == OFOrderedSame)
		return -NAN;

#if defined(HAVE_STRTOD_L) || defined(HAVE_USELOCALE)
	const char *UTF8String = self.UTF8String;
#else
	/*
	 * If we have no strtod_l, we have no other choice than to replace the
	 * locale's decimal point with something that will be rejected and
	 * replacing "." with the locale's decimal point.
	 */
	OFString *decimalSeparator = [OFLocale decimalSeparator];
	const char *UTF8String = [[self
	    stringByReplacingOccurrencesOfString: decimalSeparator
				      withString: @"!"]
	    stringByReplacingOccurrencesOfString: @"."
				      withString: decimalSeparator].UTF8String;
#endif
	char *endPtr = NULL;
	double value;

	errno = 0;

Modified src/macros.h from [f9c11c2712] to [1147a05908].

110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125







126
127
128
129
130
131
132
# define OF_ALIGNOF(type) _Alignof(type)
# define OF_ALIGNAS(type) _Alignas(type)
#else
# define OF_ALIGNOF(type) __alignof__(type)
# define OF_ALIGNAS(type) OF_ALIGN(OF_ALIGNOF(type))
#endif

#if __STDC_VERSION__ >= 201112L && defined(OF_HAVE_MAX_ALIGN_T)
# define OF_BIGGEST_ALIGNMENT _Alignof(max_align_t)
#else
# ifdef __BIGGEST_ALIGNMENT__
#  define OF_BIGGEST_ALIGNMENT __BIGGEST_ALIGNMENT__
# else
#  /* Hopefully no arch needs more than 16 byte alignment */
#  define OF_BIGGEST_ALIGNMENT 16
# endif







#endif

#define OF_PREPROCESSOR_CONCAT2(a, b) a##b
#define OF_PREPROCESSOR_CONCAT(a, b) OF_PREPROCESSOR_CONCAT2(a, b)

#if __OBJFW_RUNTIME_ABI__ || (defined(OF_APPLE_RUNTIME) && defined(__OBJC2__))
# define OF_HAVE_NONFRAGILE_IVARS







<
<
<
|
|
|
|
|
|
>
>
>
>
>
>
>







110
111
112
113
114
115
116



117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# define OF_ALIGNOF(type) _Alignof(type)
# define OF_ALIGNAS(type) _Alignas(type)
#else
# define OF_ALIGNOF(type) __alignof__(type)
# define OF_ALIGNAS(type) OF_ALIGN(OF_ALIGNOF(type))
#endif




#ifdef __BIGGEST_ALIGNMENT__
# define OF_BIGGEST_ALIGNMENT __BIGGEST_ALIGNMENT__
#else
/* Hopefully no arch needs more than 16 byte alignment */
# define OF_BIGGEST_ALIGNMENT 16
#endif
/*
 * We use SSE inline assembly on AMD64 and x86, so it must never be smaller
 * than 16.
 */
#if (defined(OF_AMD64) || defined(OF_X86)) && OF_BIGGEST_ALIGNMENT < 16
# undef OF_BIGGEST_ALIGNMENT
# define OF_BIGGEST_ALIGNMENT 16
#endif

#define OF_PREPROCESSOR_CONCAT2(a, b) a##b
#define OF_PREPROCESSOR_CONCAT(a, b) OF_PREPROCESSOR_CONCAT2(a, b)

#if __OBJFW_RUNTIME_ABI__ || (defined(OF_APPLE_RUNTIME) && defined(__OBJC2__))
# define OF_HAVE_NONFRAGILE_IVARS

Modified src/objfw-defs.h.in from [5a8629e6a6] to [ab0ba34911].

13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#undef OF_HAVE_CHOWN
#undef OF_HAVE_FILES
#undef OF_HAVE_FORWARDING_TARGET_FOR_SELECTOR
#undef OF_HAVE_IPV6
#undef OF_HAVE_IPX
#undef OF_HAVE_LIMITS_H
#undef OF_HAVE_LINK
#undef OF_HAVE_MAX_ALIGN_T
#undef OF_HAVE_NETATALK_AT_H
#undef OF_HAVE_NETAT_APPLETALK_H
#undef OF_HAVE_NETINET_IN_H
#undef OF_HAVE_NETINET_TCP_H
#undef OF_HAVE_NETIPX_IPX_H
#undef OF_HAVE_OSATOMIC
#undef OF_HAVE_OSATOMIC_64







<







13
14
15
16
17
18
19

20
21
22
23
24
25
26
#undef OF_HAVE_CHOWN
#undef OF_HAVE_FILES
#undef OF_HAVE_FORWARDING_TARGET_FOR_SELECTOR
#undef OF_HAVE_IPV6
#undef OF_HAVE_IPX
#undef OF_HAVE_LIMITS_H
#undef OF_HAVE_LINK

#undef OF_HAVE_NETATALK_AT_H
#undef OF_HAVE_NETAT_APPLETALK_H
#undef OF_HAVE_NETINET_IN_H
#undef OF_HAVE_NETINET_TCP_H
#undef OF_HAVE_NETIPX_IPX_H
#undef OF_HAVE_OSATOMIC
#undef OF_HAVE_OSATOMIC_64

Modified src/test/Makefile from [b269c69e19] to [c3118bd230].

1
2
3
4
5
6
7

8
9
10
11
12

13
14
15
16
17
18
19
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..			\






|
>




|
>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
include ../../extra.mk

DISTCLEAN = Info.plist

STATIC_LIB = libobjfwtest.a

SRCS = OTAssert.m		\
       OTOrderedDictionary.m	\
       OTTestCase.m
INCLUDES := ${SRCS:.m=.h}	\
	    ObjFWTest.h
SRCS += OTAppDelegate.m			\
	OTAssertionFailedException.m	\
	OTTestSkippedException.m

includesubdir = ObjFWTest

include ../../buildsys.mk

CPPFLAGS += -I. 			\
	    -I..			\

Deleted src/test/OTAppDelegate.h version [64bf862003].

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/*
 * Copyright (c) 2008-2024 Jonathan Schleifer <js@nil.im>
 *
 * 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 <OFApplicationDelegate>
@end

OF_ASSUME_NONNULL_END
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<














































Modified src/test/OTAppDelegate.m from [c000033e03] to [e5ebae8f3e].

11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28





















































29
30
31
32
33
34
35
36
37
38
39
40
41
42






















































43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59

60

61
62
63
64
65
66
67
 * 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]))







|
|
|








>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>














>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

















>

>







11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
 * 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 "OFApplication.h"
#import "OFColor.h"
#import "OFDictionary.h"
#import "OFMethodSignature.h"
#import "OFSet.h"
#import "OFStdIOStream.h"
#import "OFValue.h"

#import "OTTestCase.h"

#import "OTAssertionFailedException.h"
#import "OTTestSkippedException.h"

#ifdef OF_IOS
# include <CoreFoundation/CoreFoundation.h>
#endif

#ifdef OF_WII
# define asm __asm__
# include <gccore.h>
# include <wiiuse/wpad.h>
# undef asm
#endif

#ifdef OF_NINTENDO_DS
# define asm __asm__
# include <nds.h>
# undef asm
#endif

#ifdef OF_NINTENDO_3DS
/* Newer versions of libctru started using id as a parameter name. */
# define id id_3ds
# include <3ds.h>
# undef id
#endif

#ifdef OF_NINTENDO_SWITCH
# define id nx_id
# include <switch.h>
# undef id

static OFDate *lastConsoleUpdate;

static void
updateConsole(bool force)
{
	if (force || lastConsoleUpdate.timeIntervalSinceNow <= -1.0 / 60) {
		consoleUpdate(NULL);
		[lastConsoleUpdate release];
		lastConsoleUpdate = [[OFDate alloc] init];
	}
}
#endif

@interface OTAppDelegate: OFObject <OFApplicationDelegate>
@end

enum Status {
	StatusRunning,
	StatusOk,
	StatusFailed,
	StatusSkipped
};

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
+ (void)initialize
{
	if (self != [OTAppDelegate class])
		return;

#if defined(OF_IOS)
	CFBundleRef mainBundle = CFBundleGetMainBundle();
	CFURLRef resourcesURL = CFBundleCopyResourcesDirectoryURL(mainBundle);
	UInt8 resourcesPath[PATH_MAX];

	if (!CFURLGetFileSystemRepresentation(resourcesURL, true, resourcesPath,
	    PATH_MAX)) {
		[OFStdErr writeLine: @"Failed to locate resources!"];
		[OFApplication terminateWithStatus: 1];
	}

	[[OFFileManager defaultManager] changeCurrentDirectoryPath:
	    [OFString stringWithUTF8String: (const char *)resourcesPath]];

	CFRelease(resourcesURL);
#elif defined(OF_WII)
	GXRModeObj *mode;
	void *nextFB;

	VIDEO_Init();
	WPAD_Init();

	mode = VIDEO_GetPreferredMode(NULL);
	nextFB = MEM_K0_TO_K1(SYS_AllocateFramebuffer(mode));
	VIDEO_Configure(mode);
	VIDEO_SetNextFramebuffer(nextFB);
	VIDEO_SetBlack(FALSE);
	VIDEO_Flush();

	VIDEO_WaitVSync();
	if (mode->viTVMode & VI_NON_INTERLACE)
		VIDEO_WaitVSync();

	CON_InitEx(mode, 2, 2, mode->fbWidth - 4, mode->xfbHeight - 4);
	VIDEO_ClearFrameBuffer(mode, nextFB, COLOR_BLACK);
#elif defined(OF_NINTENDO_DS)
	consoleDemoInit();
#elif defined(OF_NINTENDO_3DS)
	gfxInitDefault();
	atexit(gfxExit);

	consoleInit(GFX_TOP, NULL);
#elif defined(OF_NINTENDO_SWITCH)
	consoleInit(NULL);
	padConfigureInput(1, HidNpadStyleSet_NpadStandard);
	updateConsole(true);
#endif
}

- (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.
			 */
#ifdef OF_OBJFW_RUNTIME
			[*iter class];
#endif

			/*
			 * 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]))
122
123
124
125
126
127
128
129
130
131
132
133

134
135
136
137
138
139



140
141

142
143
144
145
146
147


148
149

150
151
152
153
154
155
156


157










158


159






160

































































































161
162
163
164
165
166

167








168
169
170
171


172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203


















204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220

221
222



223




224



225




226
227
228
229

230
231
232

233
234
235
236



237



















238



239
240
241



242

243
244
245









246










































247
248
249
250

	[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







|



|
>
|
|
|
|
|
|
>
>
>

|
>
|
|
|
|
|
|
>
>

|
>
|
|
|
|
|
|
|
>
>

>
>
>
>
>
>
>
>
>
>
|
>
>

>
>
>
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>





|
>

>
>
>
>
>
>
>
>
|
|


>
>




<



|




|
















|

>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>















|

>


>
>
>
|
>
>
>
>

>
>
>
|
>
>
>
>


|

>

<
<
>



|
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

>
>
>


|
>
>
>

>


|
>
>
>
>
>
>
>
>
>

>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>




231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420

421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508


509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607

	[tests makeImmutable];
	return tests;
}

- (void)printStatusForTest: (SEL)test
		   inClass: (Class)class
		    status: (enum Status)status
	       description: (OFString *)description
{
	switch (status) {
	case StatusRunning:
		if (OFStdOut.hasTerminal) {
			[OFStdOut setForegroundColor: [OFColor olive]];
			[OFStdOut writeFormat: @"-[%@ ", class];
			[OFStdOut setForegroundColor: [OFColor yellow]];
			[OFStdOut writeFormat: @"%s", sel_getName(test)];
			[OFStdOut setForegroundColor: [OFColor olive]];
			[OFStdOut writeString: @"]: "];
		} else
			[OFStdOut writeFormat: @"-[%@ %s]: ",
					       class, sel_getName(test)];
		break;
	case StatusOk:
		if (OFStdOut.hasTerminal) {
			[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"];
		} else
			[OFStdOut writeLine: @"ok"];
		break;
	case StatusFailed:
		if (OFStdOut.hasTerminal) {
			[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];
		} else
			[OFStdOut writeLine: @"failed"];
		break;
	case StatusSkipped:
		if (OFStdOut.hasTerminal) {
			[OFStdOut setForegroundColor: [OFColor gray]];
			[OFStdOut writeFormat: @"\r-[%@ ", class];
			[OFStdOut setForegroundColor: [OFColor silver]];
			[OFStdOut writeFormat: @"%s", sel_getName(test)];
			[OFStdOut setForegroundColor: [OFColor gray]];
			[OFStdOut writeLine: @"]: skipped"];
		} else
			[OFStdOut writeLine: @"skipped"];

		if (description != nil)
			[OFStdOut writeLine: description];

		break;
	}

	if (status == StatusFailed) {
#if defined(OF_WII)
		[OFStdOut setForegroundColor: [OFColor silver]];
		[OFStdOut writeLine: @"Press A to continue"];

		for (;;) {
			WPAD_ScanPads();

			if (WPAD_ButtonsDown(0) & WPAD_BUTTON_A)
				break;

			VIDEO_WaitVSync();
		}
#elif defined(OF_NINTENDO_DS)
		[OFStdOut setForegroundColor: [OFColor silver]];
		[OFStdOut writeLine: @"Press A to continue"];

		for (;;) {
			swiWaitForVBlank();
			scanKeys();

			if (keysDown() & KEY_A)
				break;
		}
#elif defined(OF_NINTENDO_3DS)
		[OFStdOut setForegroundColor: [OFColor silver]];
		[OFStdOut writeLine: @"Press A to continue"];

		for (;;) {
			hidScanInput();

			if (hidKeysDown() & KEY_A)
				break;

			gspWaitForVBlank();
		}
#elif defined(OF_NINTENDO_SWITCH)
		[OFStdOut setForegroundColor: [OFColor silver]];
		[OFStdOut writeLine: @"Press A to continue"];

		while (appletMainLoop()) {
			PadState pad;

			padUpdate(&pad);
			updateConsole(true);

			if (padGetButtonsDown(&pad) & HidNpadButton_A)
				break;
		}
#endif
	}
}

- (OFString *)descriptionForException: (id)exception
{
	OFMutableString *description = [OFMutableString
	    stringWithFormat: @"Unhandled exception: %@",
			      exception];
	OFArray OF_GENERIC(OFValue *) *stackTraceAddresses = nil;
	OFArray OF_GENERIC(OFString *) *stackTraceSymbols = nil;
	OFStringEncoding encoding = [OFLocale encoding];

	if ([exception respondsToSelector: @selector(stackTraceAddresses)])
		stackTraceAddresses = [exception stackTraceAddresses];

	if (stackTraceAddresses != nil) {
		size_t count = stackTraceAddresses.count;

		if ([exception respondsToSelector:
		    @selector(stackTraceSymbols)])
			stackTraceSymbols = [exception stackTraceSymbols];

		if (stackTraceSymbols.count != count)
			stackTraceSymbols = nil;

		[description appendString: @"\n\nStack trace:"];

		if (stackTraceSymbols != nil) {
			for (size_t i = 0; i < count; i++) {
				void *address = [[stackTraceAddresses
				    objectAtIndex: i] pointerValue];
				const char *symbol = [[stackTraceSymbols
				    objectAtIndex: i]
				    cStringWithEncoding: encoding];

				[description appendFormat: @"\n  %p  %s",
							   address, symbol];
			}
		} else {
			for (size_t i = 0; i < count; i++) {
				void *address = [[stackTraceAddresses
				    objectAtIndex: i] pointerValue];

				[description appendFormat: @"\n  %p", address];
			}
		}
	}

	[description makeImmutable];

	return description;
}

- (void)applicationDidFinishLaunching: (OFNotification *)notification
{
	OFSet OF_GENERIC(Class) *testClasses = [self testClasses];
	size_t numSucceeded = 0, numFailed = 0, numSkipped = 0;
	OFMutableDictionary *summaries = [OFMutableDictionary dictionary];

	[OFStdOut setForegroundColor: [OFColor purple]];
	[OFStdOut writeString: @"Found "];
#if !defined(OF_WII) && !defined(OF_NINTENDO_DS) && \
    !defined(OF_NINTENDO_3DS) && !defined(OF_NINTENDO_SWITCH)
	[OFStdOut setForegroundColor: [OFColor fuchsia]];
#endif
	[OFStdOut writeFormat: @"%zu", testClasses.count];
	[OFStdOut setForegroundColor: [OFColor purple]];
	[OFStdOut writeFormat: @" test case%s\n",
			       (testClasses.count != 1 ? "s" : "")];

	for (Class class in testClasses) {
		OFArray *summary;

		[OFStdOut setForegroundColor: [OFColor teal]];
		[OFStdOut writeFormat: @"Running ", class];
		[OFStdOut setForegroundColor: [OFColor aqua]];
		[OFStdOut writeFormat: @"%@\n", class];


		for (OFValue *test in [self testsInClass: class]) {
			void *pool = objc_autoreleasePoolPush();
			bool failed = false, skipped = false;
			OTTestCase *instance;

			[self printStatusForTest: test.pointerValue
					 inClass: class
					  status: StatusRunning
				     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: StatusFailed
					     description: e.description];

				failed = true;
			} @catch (OTTestSkippedException *e) {
				[self printStatusForTest: test.pointerValue
						 inClass: class
						  status: StatusSkipped
					     description: e.description];

				skipped = true;
			} @catch (id e) {
				OFString *description =
				    [self descriptionForException: e];

				[self printStatusForTest: test.pointerValue
						 inClass: class
						  status: StatusFailed
					     description: 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: StatusFailed
						     description: description];

					failed = true;
				}
			} @catch (id e) {
				OFString *description =
				    [self descriptionForException: e];

				[self printStatusForTest: test.pointerValue
						 inClass: class
						  status: StatusFailed
					     description: description];

				failed = true;
			}

			if (failed)
				numFailed++;
			else if (skipped)
				numSkipped++;
			else {
				[self printStatusForTest: test.pointerValue
						 inClass: class
						  status: StatusOk
					     description: nil];

				numSucceeded++;


			}

			objc_autoreleasePoolPop(pool);
		}

		summary = [class summary];
		if (summary != nil)
			[summaries setObject: summary forKey: class];
	}

	for (Class class in summaries) {
		OFArray *summary = [summaries objectForKey: class];

		[OFStdOut setForegroundColor: [OFColor teal]];
		[OFStdOut writeString: @"Summary for "];
		[OFStdOut setForegroundColor: [OFColor aqua]];
		[OFStdOut writeFormat: @"%@\n", class];

		for (OFPair *line in summary) {
			[OFStdOut setForegroundColor: [OFColor navy]];
			[OFStdOut writeFormat: @"%@: ", line.firstObject];
			[OFStdOut setForegroundColor: [OFColor blue]];
			[OFStdOut writeFormat: @"%@\n", line.secondObject];
		}
	}

#if !defined(OF_WII) && !defined(OF_NINTENDO_DS) && \
    !defined(OF_NINTENDO_3DS) && !defined(OF_NINTENDO_SWITCH)
	[OFStdOut setForegroundColor: [OFColor fuchsia]];
#else
	[OFStdOut setForegroundColor: [OFColor purple]];
#endif
	[OFStdOut writeFormat: @"%zu", numSucceeded];
	[OFStdOut setForegroundColor: [OFColor purple]];
	[OFStdOut writeFormat: @" test%s succeeded, ",
			       (numSucceeded != 1 ? "s" : "")];
#if !defined(OF_WII) && !defined(OF_NINTENDO_DS) && \
    !defined(OF_NINTENDO_3DS) && !defined(OF_NINTENDO_SWITCH)
	[OFStdOut setForegroundColor: [OFColor fuchsia]];
#endif
	[OFStdOut writeFormat: @"%zu", numFailed];
	[OFStdOut setForegroundColor: [OFColor purple]];
	[OFStdOut writeFormat: @" test%s failed, ",
			       (numFailed != 1 ? "s" : "")];
#if !defined(OF_WII) && !defined(OF_NINTENDO_DS) && \
    !defined(OF_NINTENDO_3DS) && !defined(OF_NINTENDO_SWITCH)
	[OFStdOut setForegroundColor: [OFColor fuchsia]];
#endif
	[OFStdOut writeFormat: @"%zu", numSkipped];
	[OFStdOut setForegroundColor: [OFColor purple]];
	[OFStdOut writeFormat: @" test%s skipped\n",
			       (numSkipped != 1 ? "s" : "")];
	[OFStdOut reset];

#if defined(OF_WII)
	[OFStdOut setForegroundColor: [OFColor silver]];
	[OFStdOut writeLine: @"Press home button to exit"];

	for (;;) {
		WPAD_ScanPads();

		if (WPAD_ButtonsDown(0) & WPAD_BUTTON_HOME)
			break;

		VIDEO_WaitVSync();
	}
#elif defined(OF_NINTENDO_DS)
	[OFStdOut setForegroundColor: [OFColor silver]];
	[OFStdOut writeLine: @"Press start button to exit"];

	for (;;) {
		swiWaitForVBlank();
		scanKeys();

		if (keysDown() & KEY_START)
			break;
	}
#elif defined(OF_NINTENDO_3DS)
	[OFStdOut setForegroundColor: [OFColor silver]];
	[OFStdOut writeLine: @"Press start button to exit"];

	for (;;) {
		hidScanInput();

		if (hidKeysDown() & KEY_START)
			break;

		gspWaitForVBlank();
	}
#elif defined(OF_NINTENDO_SWITCH)
	while (appletMainLoop())
		updateConsole(true);

	consoleExit(NULL);
#endif

	[OFApplication terminateWithStatus: (int)numFailed];
}
@end

Modified src/test/OTAssert.h from [4079f8ef1f] to [5c08862032].

22
23
24
25
26
27
28




29
30
31
32
33
34
35
#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, ...)				\
	{							\







>
>
>
>







22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#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 OTAssertLessThan(a, b, ...) OTAssert(a < b, ## __VA_ARGS__)
#define OTAssertLessThanOrEqual(a, b, ...) OTAssert(a <= b, ## __VA_ARGS__)
#define OTAssertGreaterThan(a, b, ...) OTAssert(a > b, ## __VA_ARGS__)
#define OTAssertGreaterThanOrEqual(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, ...)				\
	{							\
47
48
49
50
51
52
53


54
55
56
57
58
59

60
61
62
		@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







>
>






>



51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
		@try {						\
			expression;				\
		} @catch (exception *e) {			\
			OTThrown = true;			\
		}						\
		OTAssert(OTThrown, ## __VA_ARGS__);		\
	}
#define OTSkip(...) \
	OTSkipImpl(self, _cmd, @__FILE__, __LINE__, ## __VA_ARGS__, nil)

#ifdef __cplusplus
extern "C" {
#endif
extern void OTAssertImpl(id testCase, SEL test, bool condition, OFString *check,
    OFString *file, size_t line, ...);
extern void OTSkipImpl(id testCase, SEL test, OFString *file, size_t line, ...);
#ifdef __cplusplus
}
#endif

Modified src/test/OTAssert.m from [dfc3f7ba82] to [27e2adc076].

14
15
16
17
18
19
20

21
22
23
24
25
26
27
 */

#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;







>







14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
 */

#include "config.h"

#import "OFString.h"

#import "OTAssertionFailedException.h"
#import "OTTestSkippedException.h"

void
OTAssertImpl(id testCase, SEL test, bool condition, OFString *check,
    OFString *file, size_t line, ...)
{
	va_list arguments;
	OFConstantString *format;
39
40
41
42
43
44
45




















			 arguments: arguments] autorelease];

	va_end(arguments);

	@throw [OTAssertionFailedException exceptionWithCondition: check
							  message: message];
}



























>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
			 arguments: arguments] autorelease];

	va_end(arguments);

	@throw [OTAssertionFailedException exceptionWithCondition: check
							  message: message];
}

void
OTSkipImpl(id testCase, SEL test, OFString *file, size_t line, ...)
{
	va_list arguments;
	OFConstantString *format;
	OFString *message = nil;

	va_start(arguments, line);
	format = va_arg(arguments, OFConstantString *);

	if (format != nil)
		message = [[[OFString alloc]
		    initWithFormat: format
			 arguments: arguments] autorelease];

	va_end(arguments);

	@throw [OTTestSkippedException exceptionWithMessage: message];
}

Added src/test/OTOrderedDictionary.h version [b6c6515436].































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
/*
 * Copyright (c) 2008-2024 Jonathan Schleifer <js@nil.im>
 *
 * 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 "ObjFW.h"
#else
# import <ObjFW/ObjFW.h>
#endif

OF_ASSUME_NONNULL_BEGIN

@interface OTOrderedDictionary: OFDictionary
{
	OFArray *_keys;
	OFArray *_objects;
}
@end

OF_ASSUME_NONNULL_END

Added src/test/OTOrderedDictionary.m version [fea7c7d9b6].

















































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
/*
 * Copyright (c) 2008-2024 Jonathan Schleifer <js@nil.im>
 *
 * 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 "OTOrderedDictionary.h"

@implementation OTOrderedDictionary
- (instancetype)initWithObjects: (id const *)objects
			forKeys: (id const *)keys
			  count: (size_t)count
{
	self = [super init];

	@try {
		OFMutableArray *mutableKeys, *mutableObjects;

		mutableKeys = [[OFMutableArray alloc] initWithCapacity: count];
		_keys = mutableKeys;

		mutableObjects = [[OFMutableArray alloc]
		    initWithCapacity: count];
		_objects = mutableObjects;

		for (size_t i = 0; i < count; i++) {
			[mutableKeys addObject: keys[i]];
			[mutableObjects addObject: objects[i]];
		}

		[mutableKeys makeImmutable];
		[mutableObjects makeImmutable];
	} @catch (id e) {
		[self release];
		@throw e;
	}

	return self;
}

- (void)dealloc
{
	[_keys release];
	[_objects release];

	[super dealloc];
}

- (id)objectForKey: (id)key
{
	size_t i = 0;

	for (id iter in _keys) {
		if ([iter isEqual: key])
			return [_objects objectAtIndex: i];

		i++;
	}

	return nil;
}

- (size_t)count
{
	return _keys.count;
}

- (OFEnumerator *)keyEnumerator
{
	return [_keys objectEnumerator];
}

- (OFEnumerator *)objectEnumerator
{
	return [_objects objectEnumerator];
}
@end

Modified src/test/OTTestCase.h from [2add704de5] to [a61157e757].

10
11
12
13
14
15
16
17
18
19
20
21
22
23
24






25
26
27
28
29
 * 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 <ObjFW/OFObject.h>
#endif

OF_ASSUME_NONNULL_BEGIN

@interface OTTestCase: OFObject






- (void)setUp;
- (void)tearDown;
@end

OF_ASSUME_NONNULL_END







|

|





>
>
>
>
>
>





10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
 * 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 "ObjFW.h"
#else
# import <ObjFW/ObjFW.h>
#endif

OF_ASSUME_NONNULL_BEGIN

@interface OTTestCase: OFObject
#ifdef OF_HAVE_CLASS_PROPERTIES
@property (class, readonly, nullable, nonatomic)
    OFArray OF_GENERIC(OFPair OF_GENERIC(OFString *, id) *) *summary;
#endif

+ (nullable OFArray OF_GENERIC(OFPair OF_GENERIC(OFString *, id) *) *)summary;
- (void)setUp;
- (void)tearDown;
@end

OF_ASSUME_NONNULL_END

Modified src/test/OTTestCase.m from [3c3d45f200] to [fdb0a500c1].

14
15
16
17
18
19
20





21
22
23
24
25
26
27
 */

#include "config.h"

#import "OTTestCase.h"

@implementation OTTestCase: OFObject





- (void)setUp
{
}

- (void)tearDown
{
}







>
>
>
>
>







14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
 */

#include "config.h"

#import "OTTestCase.h"

@implementation OTTestCase: OFObject
+ (OFArray OF_GENERIC(OFPair OF_GENERIC(OFString *, id) *) *)summary
{
	return nil;
}

- (void)setUp
{
}

- (void)tearDown
{
}

Added src/test/OTTestSkippedException.h version [499842bf2f].





































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
/*
 * Copyright (c) 2008-2024 Jonathan Schleifer <js@nil.im>
 *
 * 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 OTTestSkippedException: OFException
{
	OFString *_Nullable _message;
}

@property OF_NULLABLE_PROPERTY (readonly, nonatomic) OFString *message;

+ (instancetype)exceptionWithMessage: (nullable OFString *)message;
+ (instancetype)exception OF_UNAVAILABLE;
- (instancetype)initWithMessage: (nullable OFString *)message;
- (instancetype)init OF_UNAVAILABLE;
@end

OF_ASSUME_NONNULL_END

Added src/test/OTTestSkippedException.m version [b2f5e97a93].







































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
/*
 * Copyright (c) 2008-2024 Jonathan Schleifer <js@nil.im>
 *
 * 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 "OTTestSkippedException.h"

@implementation OTTestSkippedException
@synthesize message = _message;

+ (instancetype)exceptionWithMessage: (OFString *)message
{
	return [[[self alloc] initWithMessage: message] autorelease];
}

+ (instancetype)exception
{
	OF_UNRECOGNIZED_SELECTOR
}

- (instancetype)initWithMessage: (OFString *)message
{
	self = [super init];

	@try {
		_message = [message copy];
	} @catch (id e) {
		[self release];
		@throw e;
	}

	return self;
}

- (instancetype)init
{
	OF_INVALID_INIT_METHOD
}

- (void)dealloc
{
	[_message release];

	[super dealloc];
}

- (OFString *)description
{
	if (_message != nil)
		return [OFString stringWithFormat: @"Test skipped: %@",
						   _message];
	else
		return nil;
}
@end

Modified src/test/ObjFWTest.h from [c6fa64803a] to [e2709fe53c].

11
12
13
14
15
16
17

 * 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"








>
11
12
13
14
15
16
17
18
 * 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"
#import "OTOrderedDictionary.h"

Modified tests/ForwardingTests.m from [1d203d1fb8] to [f769714063].

13
14
15
16
17
18
19
20

21
22
23
24
25
26


27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
 * file.
 */

#include "config.h"

#include <string.h>

#import "TestsAppDelegate.h"


#define FORMAT @"%@ %@ %@ %@ %@ %@ %@ %@ %@ %g %g %g %g %g %g %g %g %g"
#define ARGS @"a", @"b", @"c", @"d", @"e", @"f", @"g", @"h", @"i", \
	    1.5, 2.25, 3.125, 4.0625, 5.03125, 6.5, 7.25, 8.0, 9.0
#define RESULT @"a b c d e f g h i 1.5 2.25 3.125 4.0625 5.03125 6.5 7.25 8 9"



static OFString *const module = @"Forwarding";
static size_t forwardingsCount = 0;
static bool success = false;
static id target = nil;

struct StretTest {
	char buffer[1024];
};

@interface ForwardingTest: OFObject
@end

@interface ForwardingTest (Test)
+ (void)test;
- (void)test;
- (uint32_t)forwardingTargetTest: (intptr_t)a0
				: (intptr_t)a1
				: (double)a2
				: (double)a3;
- (OFString *)forwardingTargetVarArgTest: (OFConstantString *)format, ...;







|
>






>
>
|








|


|







13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
 * file.
 */

#include "config.h"

#include <string.h>

#import "ObjFW.h"
#import "ObjFWTest.h"

#define FORMAT @"%@ %@ %@ %@ %@ %@ %@ %@ %@ %g %g %g %g %g %g %g %g %g"
#define ARGS @"a", @"b", @"c", @"d", @"e", @"f", @"g", @"h", @"i", \
	    1.5, 2.25, 3.125, 4.0625, 5.03125, 6.5, 7.25, 8.0, 9.0
#define RESULT @"a b c d e f g h i 1.5 2.25 3.125 4.0625 5.03125 6.5 7.25 8 9"

@interface ForwardingTests: OTTestCase
@end

static size_t forwardingsCount = 0;
static bool success = false;
static id target = nil;

struct StretTest {
	char buffer[1024];
};

@interface ForwardingTestObject: OFObject
@end

@interface ForwardingTestObject (NonExistentMethods)
+ (void)test;
- (void)test;
- (uint32_t)forwardingTargetTest: (intptr_t)a0
				: (intptr_t)a1
				: (double)a2
				: (double)a3;
- (OFString *)forwardingTargetVarArgTest: (OFConstantString *)format, ...;
57
58
59
60
61
62
63
64










































































































































65
66
67
68
69
70
71

static void
test(id self, SEL _cmd)
{
	success = true;
}

@implementation ForwardingTest










































































































































+ (bool)resolveClassMethod: (SEL)selector
{
	forwardingsCount++;

	if (sel_isEqual(selector, @selector(test))) {
		class_replaceMethod(object_getClass(self), @selector(test),
		    (IMP)test, "v#:");







|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212

static void
test(id self, SEL _cmd)
{
	success = true;
}

@implementation ForwardingTests
- (void)setUp
{
	[super setUp];

	forwardingsCount = 0;
	success = false;
	target = nil;
}

- (void)testForwardingMessageAndAddingClassMethod
{
	[ForwardingTestObject test];
	OTAssertTrue(success);
	OTAssertEqual(forwardingsCount, 1);

	[ForwardingTestObject test];
	OTAssertEqual(forwardingsCount, 1);
}

- (void)forwardingMessageAndAddingInstanceMethod
{
	ForwardingTestObject *testObject =
	    [[[ForwardingTestObject alloc] init] autorelease];

	[testObject test];
	OTAssertTrue(success);
	OTAssertEqual(forwardingsCount, 1);

	[testObject test];
	OTAssertEqual(forwardingsCount, 1);
}

#ifdef OF_HAVE_FORWARDING_TARGET_FOR_SELECTOR
- (void)testForwardingTargetForSelector
{
	ForwardingTestObject *testObject =
	    [[[ForwardingTestObject alloc] init] autorelease];

	target = [[[ForwardingTarget alloc] init] autorelease];

	OTAssertEqual(
	    [testObject forwardingTargetTest: 0xDEADBEEF
					    : -1
					    : 1.25
					    : 2.75], 0x12345678);
}

- (void)testForwardingTargetForSelectorWithVariableArguments
{
	ForwardingTestObject *testObject =
	    [[[ForwardingTestObject alloc] init] autorelease];

	target = [[[ForwardingTarget alloc] init] autorelease];

	OTAssertEqualObjects(
	    ([testObject forwardingTargetVarArgTest: FORMAT, ARGS]), RESULT);
}

/*
 * Don't try fpret on Win64 if we don't have stret forwarding, as long double
 * is handled as a struct there.
 */
# if !defined(OF_WINDOWS) || !defined(OF_AMD64) || \
    defined(OF_HAVE_FORWARDING_TARGET_FOR_SELECTOR_STRET)
- (void)testForwardingTargetForSelectorFPRet
{
	ForwardingTestObject *testObject =
	    [[[ForwardingTestObject alloc] init] autorelease];

	target = [[[ForwardingTarget alloc] init] autorelease];

	OTAssertEqual([testObject forwardingTargetFPRetTest],
	    12345678.00006103515625);
}
# endif

# ifdef OF_HAVE_FORWARDING_TARGET_FOR_SELECTOR_STRET
- (void)testForwardingTargetForSelectorStRet
{
	ForwardingTestObject *testObject =
	    [[[ForwardingTestObject alloc] init] autorelease];

	target = [[[ForwardingTarget alloc] init] autorelease];

	OTAssertEqual(memcmp([testObject forwardingTargetStRetTest].buffer,
	    "abcdefghijklmnopqrstuvwxyz", 27), 0);
}
# endif

- (void)testForwardingTargetForSelectorReturningNilThrows
{
	ForwardingTestObject *testObject =
	    [[[ForwardingTestObject alloc] init] autorelease];

	target = [[[ForwardingTarget alloc] init] autorelease];

	OTAssertThrowsSpecific([testObject forwardingTargetNilTest],
	    OFNotImplementedException);
}

- (void)testForwardingTargetForSelectorReturningSelfThrows
{
	ForwardingTestObject *testObject =
	    [[[ForwardingTestObject alloc] init] autorelease];

	target = [[[ForwardingTarget alloc] init] autorelease];

	OTAssertThrowsSpecific([testObject forwardingTargetSelfTest],
	    OFNotImplementedException);
}

# ifdef OF_HAVE_FORWARDING_TARGET_FOR_SELECTOR_STRET
- (void)testForwardingTargetForSelectorStRetReturningNilThrows
{
	ForwardingTestObject *testObject =
	    [[[ForwardingTestObject alloc] init] autorelease];

	target = [[[ForwardingTarget alloc] init] autorelease];

	OTAssertThrowsSpecific([testObject forwardingTargetNilStRetTest],
	    OFNotImplementedException);
}

- (void)testForwardingTargetForSelectorStRetReturningSelfThrows
{
	ForwardingTestObject *testObject =
	    [[[ForwardingTestObject alloc] init] autorelease];

	target = [[[ForwardingTarget alloc] init] autorelease];

	OTAssertThrowsSpecific([testObject forwardingTargetSelfStRetTest],
	    OFNotImplementedException);
}
# endif
#endif
@end

@implementation ForwardingTestObject
+ (bool)resolveClassMethod: (SEL)selector
{
	forwardingsCount++;

	if (sel_isEqual(selector, @selector(test))) {
		class_replaceMethod(object_getClass(self), @selector(test),
		    (IMP)test, "v#:");
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237

	OFEnsure(self == target);

	memcpy(ret.buffer, "abcdefghijklmnopqrstuvwxyz", 27);

	return ret;
}
@end

@implementation TestsAppDelegate (ForwardingTests)
- (void)forwardingTests
{
	void *pool = objc_autoreleasePoolPush();

	TEST(@"Forwarding a message and adding a class method",
	    R([ForwardingTest test]) && success &&
	    R([ForwardingTest test]) && forwardingsCount == 1);

	ForwardingTest *testObject =
	    [[[ForwardingTest alloc] init] autorelease];

	success = false;
	forwardingsCount = 0;

	TEST(@"Forwarding a message and adding an instance method",
	    R([testObject test]) && success && R([testObject test]) &&
	    forwardingsCount == 1);

#ifdef OF_HAVE_FORWARDING_TARGET_FOR_SELECTOR
	target = [[[ForwardingTarget alloc] init] autorelease];
	TEST(@"-[forwardingTargetForSelector:]",
	    [testObject forwardingTargetTest: 0xDEADBEEF
					    : -1
					    : 1.25
					    : 2.75] == 0x12345678)
	TEST(@"-[forwardingTargetForSelector:] variable arguments",
	    [[testObject forwardingTargetVarArgTest: FORMAT, ARGS]
	    isEqual: RESULT])
	/*
	 * Don't try fpret on Win64 if we don't have stret forwarding, as
	 * long double is handled as a struct there.
	 */
# if !defined(OF_WINDOWS) || !defined(OF_AMD64) || \
    defined(OF_HAVE_FORWARDING_TARGET_FOR_SELECTOR_STRET)
	TEST(@"-[forwardingTargetForSelector:] fp return",
	    [testObject forwardingTargetFPRetTest] == 12345678.00006103515625)
# endif
# ifdef OF_HAVE_FORWARDING_TARGET_FOR_SELECTOR_STRET
	TEST(@"-[forwardingTargetForSelector:] struct return",
	    !memcmp([testObject forwardingTargetStRetTest].buffer,
	    "abcdefghijklmnopqrstuvwxyz", 27))
# endif
	EXPECT_EXCEPTION(@"-[forwardingTargetForSelector:] nil target",
	    OFNotImplementedException, [testObject forwardingTargetNilTest])
	EXPECT_EXCEPTION(@"-[forwardingTargetForSelector:] self target",
	    OFNotImplementedException, [testObject forwardingTargetSelfTest])
# ifdef OF_HAVE_FORWARDING_TARGET_FOR_SELECTOR_STRET
	EXPECT_EXCEPTION(@"-[forwardingTargetForSelector:] nil target + "
	    @"stret", OFNotImplementedException,
	    [testObject forwardingTargetNilStRetTest])
	EXPECT_EXCEPTION(@"-[forwardingTargetForSelector:] self target + "
	    @"stret", OFNotImplementedException,
	    [testObject forwardingTargetSelfStRetTest])
# endif
#endif

	objc_autoreleasePoolPop(pool);
}
@end








<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
310
311
312
313
314
315
316
317






























































	OFEnsure(self == target);

	memcpy(ret.buffer, "abcdefghijklmnopqrstuvwxyz", 27);

	return ret;
}
@end





























































Modified tests/Makefile from [f359c6f71f] to [cfd6eda8c6].

1
2


3
4
5
6
7
8
9
10
11


12
13
14
15
16



17









18














19
20
21
22
23

24



25
26
27
28

29
30
31
32
33
34
35
36
37


38



39
40
41
42
43

44
45
46
47
48
49
50
51
52
53
54


55
56
57
58
59

60


61
62
63
64
65
66
67
68
include ../extra.mk



SUBDIRS = ${OBJC_SYNC}	\
	  terminal

CLEAN = EBOOT.PBP		\
	boot.dol		\
	${PROG_NOINST}.arm9	\
	${PROG_NOINST}.nds	\
	${PROG_NOINST}.nro	\
	${PROG_NOINST}.rpx


DISTCLEAN = Info.plist

PROG_NOINST = tests${PROG_SUFFIX}
STATIC_LIB_NOINST = ${TESTS_STATIC_LIB}
SRCS = ForwardingTests.m		\



       ${OF_BLOCK_TESTS_M}		\









       OFDataTests.m			\














       OFDictionaryTests.m		\
       OFListTests.m			\
       OFLocaleTests.m			\
       OFMemoryStreamTests.m		\
       OFNotificationCenterTests.m	\

       OFObjectTests.m			\



       OFSetTests.m			\
       OFStreamTests.m			\
       OFStringTests.m			\
       OFSystemInfoTests.m		\

       OFValueTests.m			\
       OFXMLElementBuilderTests.m	\
       OFXMLNodeTests.m			\
       OFXMLParserTests.m		\
       RuntimeTests.m			\
       ${RUNTIME_ARC_TESTS_M}		\
       TestsAppDelegate.m		\
       ${USE_SRCS_FILES}		\
       ${USE_SRCS_SOCKETS}		\


       ${USE_SRCS_WINDOWS}



SRCS_SOCKETS = OFDNSResolverTests.m		\
	       ${OF_HTTP_CLIENT_TESTS_M}	\
	       OFHTTPCookieTests.m		\
	       OFHTTPCookieManagerTests.m	\
	       OFKernelEventObserverTests.m	\

	       OFTCPSocketTests.m		\
	       OFUDPSocketTests.m		\
	       ${USE_SRCS_APPLETALK}		\
	       ${USE_SRCS_IPX}			\
	       ${USE_SRCS_UNIX_SOCKETS}
SRCS_APPLETALK = OFDDPSocketTests.m
SRCS_IPX = OFIPXSocketTests.m		\
	   OFSPXSocketTests.m		\
	   OFSPXStreamSocketTests.m
SRCS_UNIX_SOCKETS = OFUNIXDatagramSocketTests.m	\
		    OFUNIXStreamSocketTests.m


SRCS_WINDOWS = OFWindowsRegistryKeyTests.m

IOS_USER ?= mobile
IOS_TMP ?= /tmp/objfw-test


include ../buildsys.mk



.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}


>
>
|







|
>
>




|
>
>
>
|
>
>
>
>
>
>
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
|
|
|
|
>
|
>
>
>
|
|
|
|
>
|
|
|
|
<
|
|
|
|
>
>
|
>
>
>


|
|

>











>
>


|
<

>
|
>
>








1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67

68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99

100
101
102
103
104
105
106
107
108
109
110
111
112
include ../extra.mk

SUBDIRS = ${TESTPLUGIN}	\
	  ${SUBPROCESS}	\
	  ${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
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				\
       OFConcreteArrayTests.m			\
       OFConcreteDictionaryTests.m		\
       OFConcreteMutableArrayTests.m		\
       OFConcreteMutableDictionaryTests.m	\
       OFConcreteMutableSetTests.m		\
       OFConcreteSetTests.m			\
       OFCryptographicHashTests.m		\
       OFDataTests.m				\
       OFDateTests.m				\
       OFDictionaryTests.m			\
       OFHMACTests.m				\
       OFINIFileTests.m				\
       OFIRITests.m				\
       OFInvocationTests.m			\
       OFJSONTests.m				\
       OFListTests.m				\
       OFLocaleTests.m				\
       OFMatrix4x4Tests.m			\
       OFMemoryStreamTests.m			\
       OFMethodSignatureTests.m			\
       OFMutableArrayTests.m			\
       OFMutableDataTests.m			\
       OFMutableDictionaryTests.m		\
       OFMutableSetTests.m			\
       OFMutableStringTests.m			\
       OFMutableUTF8StringTests.m		\
       OFNotificationCenterTests.m		\
       OFNumberTests.m				\
       OFObjectTests.m				\
       OFPBKDF2Tests.m				\
       OFPropertyListTests.m			\
       OFScryptTests.m				\
       OFSetTests.m				\
       OFStreamTests.m				\
       OFStringTests.m				\
       OFSystemInfoTests.m			\
       OFUTF8StringTests.m			\
       OFValueTests.m				\
       OFXMLElementBuilderTests.m		\
       OFXMLNodeTests.m				\
       OFXMLParserTests.m			\

       ${RUNTIME_ARC_TESTS_M}			\
       RuntimeTests.m				\
       ${USE_SRCS_PLUGINS}			\
       ${USE_SRCS_SOCKETS}			\
       ${USE_SRCS_SUBPROCESSES}			\
       ${USE_SRCS_THREADS}			\
       ${USE_SRCS_WINDOWS}			\
       testfile_bin.m				\
       testfile_ini.m
SRCS_PLUGINS = OFPluginTests.m
SRCS_SOCKETS = OFDNSResolverTests.m		\
	       ${OF_HTTP_CLIENT_TESTS_M}	\
	       OFHTTPCookieManagerTests.m	\
	       OFHTTPCookieTests.m		\
	       OFKernelEventObserverTests.m	\
	       OFSocketTests.m			\
	       OFTCPSocketTests.m		\
	       OFUDPSocketTests.m		\
	       ${USE_SRCS_APPLETALK}		\
	       ${USE_SRCS_IPX}			\
	       ${USE_SRCS_UNIX_SOCKETS}
SRCS_APPLETALK = OFDDPSocketTests.m
SRCS_IPX = OFIPXSocketTests.m		\
	   OFSPXSocketTests.m		\
	   OFSPXStreamSocketTests.m
SRCS_UNIX_SOCKETS = OFUNIXDatagramSocketTests.m	\
		    OFUNIXStreamSocketTests.m
SRCS_SUBPROCESSES = OFSubprocessTests.m
SRCS_THREADS = OFThreadTests.m
SRCS_WINDOWS = OFWindowsRegistryKeyTests.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}
124
125
126
127
128
129
130




131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
	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




	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}

${PROG_NOINST}.3dsx: ${PROG_NOINST}
	3dsxtool $< $@

${PROG_NOINST}.arm9: ${PROG_NOINST}
	arm-none-eabi-objcopy -O binary $< $@








>
>
>
>












|







168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
	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 $< $@

166
167
168
169
170
171
172

173
174

175





176




177
178

${PROG_NOINST}.rpx: ${PROG_NOINST}
	elf2rpl $< $@

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}







>

|
>

>
>
>
>
>
|
>
>
>
>


214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237

${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}\"
OBJCFLAGS_RuntimeARCTests.m = -fobjc-arc -fobjc-arc-exceptions
# 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}

Name change from new_tests/OFASN1DERParsingTests.m to tests/OFASN1DERParsingTests.m.

Name change from new_tests/OFASN1DERRepresentationTests.m to tests/OFASN1DERRepresentationTests.m.

Added tests/OFArrayTests.h version [8f8b5c5038].



















































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/*
 * Copyright (c) 2008-2024 Jonathan Schleifer <js@nil.im>
 *
 * 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;
}

@property (readonly, nonatomic) Class arrayClass;
@end

Added tests/OFArrayTests.m version [805893a2b1].



















































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
/*
 * Copyright (c) 2008-2024 Jonathan Schleifer <js@nil.im>
 *
 * 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
{
	OFArray *_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) {
		OTAssertLessThan(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)initWithObjects: (id const *)objects count: (size_t)count
{
	self = [super init];

	@try {
		_array = [[OFArray 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

Modified tests/OFBlockTests.m from [41100ed0e1] to [b2a3854f7c].

11
12
13
14
15
16
17
18

19
20

21
22
23
24
25
26
27
 * 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 = @"OFBlock";


#if defined(OF_OBJFW_RUNTIME)
extern struct objc_class _NSConcreteStackBlock;
extern struct objc_class _NSConcreteGlobalBlock;
extern struct objc_class _NSConcreteMallocBlock;
#elif defined(OF_APPLE_RUNTIME)
extern void *_NSConcreteStackBlock;







|
>

|
>







11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
 * 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 OFBlockTests: OTTestCase
@end

#if defined(OF_OBJFW_RUNTIME)
extern struct objc_class _NSConcreteStackBlock;
extern struct objc_class _NSConcreteGlobalBlock;
extern struct objc_class _NSConcreteMallocBlock;
#elif defined(OF_APPLE_RUNTIME)
extern void *_NSConcreteStackBlock;
52
53
54
55
56
57
58
59





60

61




62




















































63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119

	block();
	Block_release(block);

	return d;
}

@implementation TestsAppDelegate (OFBlockTests)





- (void)blockTests

{




	void *pool = objc_autoreleasePoolPush();




















































	__block int x;
	void (^stackBlock)(void) = ^ {
		x = 0;
		(void)x;
	};
	void (^mallocBlock)(void);
	int (^voidBlock)(void);

	TEST(@"Class of stack block",
	    (Class)&_NSConcreteStackBlock == objc_getClass("OFStackBlock") &&
	    [stackBlock isKindOfClass: [OFBlock class]])

#if !defined(OF_WINDOWS) || !defined(__clang__)
	TEST(@"Class of global block",
	    (Class)&_NSConcreteGlobalBlock == objc_getClass("OFGlobalBlock") &&
	    [globalBlock isKindOfClass: [OFBlock class]])
#endif

	TEST(@"Class of a malloc block",
	    (Class)&_NSConcreteMallocBlock == objc_getClass("OFMallocBlock"))

	TEST(@"Copying a stack block",
	    (mallocBlock = [[stackBlock copy] autorelease]) &&
	    [mallocBlock class] == objc_getClass("OFMallocBlock") &&
	    [mallocBlock isKindOfClass: [OFBlock class]])

	TEST(@"Copying a stack block and referencing its variable",
	    forwardTest() == 5)

	TEST(@"Copying a stack block and using its copied variable",
	    (voidBlock = returnStackBlock()) && voidBlock() == 43 &&
	    voidBlock() == 44 && voidBlock() == 45)

#if !defined(OF_WINDOWS) || !defined(__clang__)
	TEST(@"Copying a global block",
	    (id)globalBlock == [[globalBlock copy] autorelease])
#endif

#ifndef __clang_analyzer__
	TEST(@"Copying a malloc block",
	    (id)mallocBlock == [mallocBlock copy] &&
	    [mallocBlock retainCount] == 2)
#endif

	TEST(@"Autorelease a stack block", R([stackBlock autorelease]))

#if !defined(OF_WINDOWS) || !defined(__clang__)
	TEST(@"Autorelease a global block", R([globalBlock autorelease]))
#endif

#ifndef __clang_analyzer__
	TEST(@"Autorelease a malloc block", R([mallocBlock autorelease]))
#endif

	objc_autoreleasePoolPop(pool);
}
@end







|
>
>
>
>
>
|
>
|
>
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>






<

<
<
<
<
<
<
<
<
<
<
<
<
<
<
|
<
<
<
<
<
<
<
<
<
<
<
<
|
<
<
<
<
<
|
<
|
<
<
<
<
<
<
<
<
<
<
<
<

54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132

133














134












135





136

137












138

	block();
	Block_release(block);

	return d;
}

@implementation OFBlockTests
- (void)testClassOfStackBlock
{
	__block int x;
	void (^stackBlock)(void) = ^ {
		x = 0;
		(void)x;
	};

	OTAssertEqual((Class)&_NSConcreteStackBlock,
	    objc_getClass("OFStackBlock"));
	OTAssertTrue([stackBlock isKindOfClass: [OFBlock class]]);
}

#if !defined(OF_WINDOWS) || !defined(__clang__)
- (void)testClassOfGlobalBlock
{
	OTAssertEqual((Class)&_NSConcreteGlobalBlock,
	    objc_getClass("OFGlobalBlock"));
	OTAssertTrue([globalBlock isKindOfClass: [OFBlock class]]);
}
#endif

- (void)testClassOfMallocBlock
{
	OTAssertEqual((Class)&_NSConcreteMallocBlock,
	    objc_getClass("OFMallocBlock"));
}

- (void)testCopyStackBlock
{
	__block int x;
	void (^stackBlock)(void) = ^ {
		x = 0;
		(void)x;
	};
	void (^mallocBlock)(void);

	mallocBlock = [[stackBlock copy] autorelease];
	OTAssertEqual([mallocBlock class], objc_getClass("OFMallocBlock"));
	OTAssertTrue([mallocBlock isKindOfClass: [OFBlock class]]);
}

- (void)testCopyStackBlockAndReferenceVariable
{
	OTAssertEqual(forwardTest(), 5);
}

- (void)testCopyStackBlockAndReferenceCopiedVariable
{
	int (^voidBlock)(void) = returnStackBlock();

	OTAssertEqual(voidBlock(), 43);
	OTAssertEqual(voidBlock(), 44);
	OTAssertEqual(voidBlock(), 45);
}

#if !defined(OF_WINDOWS) || !defined(__clang__)
- (void)testCopyGlobalBlock
{
	OTAssertEqual([[globalBlock copy] autorelease], (id)globalBlock);
}
#endif

- (void)testCopyMallocBlock
{
	__block int x;
	void (^stackBlock)(void) = ^ {
		x = 0;
		(void)x;
	};
	void (^mallocBlock)(void);
















	mallocBlock = [[stackBlock copy] autorelease];












	OTAssertEqual([[mallocBlock copy] autorelease], (id)mallocBlock);





	OTAssertEqual([mallocBlock retainCount], 2);

}












@end

Added tests/OFCharacterSetTests.m version [2ac90291b5].









































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
/*
 * Copyright (c) 2008-2024 Jonathan Schleifer <js@nil.im>
 *
 * 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 tests/OFColorTests.m version [f2116a7a9c].





























































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
/*
 * Copyright (c) 2008-2024 Jonathan Schleifer <js@nil.im>
 *
 * 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 tests/OFConcreteArrayTests.m version [70542429e0].





























































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
/*
 * Copyright (c) 2008-2024 Jonathan Schleifer <js@nil.im>
 *
 * 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 tests/OFConcreteDictionaryTests.m version [59f7bc08f5].





























































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
/*
 * Copyright (c) 2008-2024 Jonathan Schleifer <js@nil.im>
 *
 * 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 "OFDictionaryTests.h"

#import "OFConcreteDictionary.h"

@interface OFConcreteDictionaryTests: OFDictionaryTests
@end

@implementation OFConcreteDictionaryTests
- (Class)dictionaryClass
{
	return [OFConcreteDictionary class];
}
@end

Added tests/OFConcreteMutableArrayTests.m version [b38f014238].



















































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
/*
 * Copyright (c) 2008-2024 Jonathan Schleifer <js@nil.im>
 *
 * 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 tests/OFConcreteMutableDictionaryTests.m version [5d0492a10a].









































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
/*
 * Copyright (c) 2008-2024 Jonathan Schleifer <js@nil.im>
 *
 * 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 "OFMutableDictionaryTests.h"

#import "OFConcreteMutableDictionary.h"

@interface OFConcreteMutableDictionaryTests: OFMutableDictionaryTests
@end

@implementation OFConcreteMutableDictionaryTests
- (Class)dictionaryClass
{
	return [OFConcreteMutableDictionary class];
}

- (void)testDetectMutationDuringEnumeration
{
	OFMutableDictionary *mutableDictionary =
	    [[_dictionary mutableCopy] autorelease];
	OFEnumerator *keyEnumerator = [mutableDictionary keyEnumerator];
	OFEnumerator *objectEnumerator = [mutableDictionary objectEnumerator];
	OFString *key;
	size_t i;

	i = 0;
	while ((key = [keyEnumerator nextObject]) != nil) {
		[mutableDictionary setObject: @"test" forKey: key];
		i++;
	}
	OTAssertEqual(i, mutableDictionary.count);

	[mutableDictionary removeObjectForKey: @"key2"];
	OTAssertThrowsSpecific([keyEnumerator nextObject],
	    OFEnumerationMutationException);
	OTAssertThrowsSpecific([objectEnumerator nextObject],
	    OFEnumerationMutationException);
}

- (void)testDetectMutationDuringFastEnumeration
{
	OFMutableDictionary *mutableDictionary =
	    [[_dictionary mutableCopy] autorelease];
	bool detected = false;
	size_t i;

	i = 0;
	for (OFString *key in mutableDictionary) {
		[mutableDictionary setObject: @"test" forKey: key];
		i++;
	}
	OTAssertEqual(i, mutableDictionary.count);

	@try {
		for (OFString *key in mutableDictionary)
			[mutableDictionary removeObjectForKey: key];
	} @catch (OFEnumerationMutationException *e) {
		detected = true;
	}
	OTAssertTrue(detected);
}

#ifdef OF_HAVE_BLOCKS
- (void)testDetectMutationDuringEnumerateObjectsUsingBlock
{
	OFMutableDictionary *mutableDictionary =
	    [[_dictionary mutableCopy] autorelease];
	__block size_t i;

	i = 0;
	[mutableDictionary enumerateKeysAndObjectsUsingBlock:
	    ^ (id key, id object, bool *stop) {
		[mutableDictionary setObject: @"test" forKey: key];
		i++;
	}];
	OTAssertEqual(i, mutableDictionary.count);

	OTAssertThrowsSpecific(
	[mutableDictionary enumerateKeysAndObjectsUsingBlock:
	    ^ (id key, id object, bool *stop) {
		[mutableDictionary removeObjectForKey: key];
	    }],
	    OFEnumerationMutationException);
}
#endif
@end

Added tests/OFConcreteMutableSetTests.m version [b0e6f39f4d].



































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
/*
 * Copyright (c) 2008-2024 Jonathan Schleifer <js@nil.im>
 *
 * 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 "OFMutableSetTests.h"

#import "OFConcreteMutableSet.h"

@interface OFConcreteMutableSetTests: OFMutableSetTests
@end

@implementation OFConcreteMutableSetTests
- (Class)setClass
{
	return [OFConcreteMutableSet class];
}

- (void)testDetectMutationDuringEnumeration
{
	OFEnumerator *enumerator = [_mutableSet objectEnumerator];

	[_mutableSet removeObject: @"foo"];

	OTAssertThrowsSpecific([enumerator nextObject],
	    OFEnumerationMutationException);
}

- (void)testDetectMutationDuringFastEnumeration
{
	bool detected = false;

	@try {
		for (OFString *object in _mutableSet)
			[_mutableSet removeObject: object];
	} @catch (OFEnumerationMutationException *e) {
		detected = true;
	}

	OTAssertTrue(detected);
}

#ifdef OF_HAVE_BLOCKS
- (void)testDetectMutationDuringEnumerateObjectsUsingBlock
{
	OTAssertThrowsSpecific(
	    [_mutableSet enumerateObjectsUsingBlock: ^ (id object, bool *stop) {
		[_mutableSet removeObject: object];
	    }],
	    OFEnumerationMutationException);
}
#endif
@end

Added tests/OFConcreteSetTests.m version [8b35e67bcd].





























































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
/*
 * Copyright (c) 2008-2024 Jonathan Schleifer <js@nil.im>
 *
 * 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 "OFSetTests.h"

#import "OFConcreteSet.h"

@interface OFConcreteSetTests: OFSetTests
@end

@implementation OFConcreteSetTests
- (Class)setClass
{
	return [OFConcreteSet class];
}
@end

Added tests/OFCryptographicHashTests.m version [9a95ece37d].

























































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
/*
 * Copyright (c) 2008-2024 Jonathan Schleifer <js@nil.im>
 *
 * 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 <string.h>

#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 <OFCryptographicHash> hash =
	    [hashClass hashWithAllowsSwappableMemory: true];
	id <OFCryptographicHash> 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

Modified tests/OFDDPSocketTests.m from [5433dc7a16] to [d03a653eed].

12
13
14
15
16
17
18

19
20

21
22

23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68

69
70
71

72
73
74
75
76
 * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
 * file.
 */

#include "config.h"

#include <errno.h>


#import "TestsAppDelegate.h"


static OFString *const module = @"OFDDPSocket";


@implementation TestsAppDelegate (OFDDPSocketTests)
- (void)DDPSocketTests
{
	void *pool = objc_autoreleasePoolPush();
	OFDDPSocket *sock;
	OFSocketAddress address1, address2;
	char buffer[5];

	TEST(@"+[socket]", (sock = [OFDDPSocket socket]))

	@try {
		TEST(@"-[bindToNetwork:node:port:]",
		    R(address1 = [sock bindToNetwork: 0
						node: 0
						port: 0
					protocolType: 11]))
	} @catch (OFBindSocketFailedException *e) {
		switch (e.errNo) {
		case EAFNOSUPPORT:
		case EPROTONOSUPPORT:
			[OFStdOut setForegroundColor: [OFColor lime]];
			[OFStdOut writeLine:
			    @"\r[OFDDPSocket] -[bindToNetwork:node:port:"
			    @"protocolType:] AppleTalk unsupported, skipping "
			    @"tests"];
			break;
		case EADDRNOTAVAIL:
			[OFStdOut setForegroundColor: [OFColor lime]];
			[OFStdOut writeLine:
			    @"\r[OFDDPSocket] -[bindToNetwork:node:port:"
			    @"protocolType:] AppleTalk not configured, "
			    @"skipping tests"];
			break;
		default:
			@throw e;
		}

		objc_autoreleasePoolPop(pool);
		return;
	}

	TEST(@"-[sendBuffer:length:receiver:]",
	    R([sock sendBuffer: "Hello" length: 5 receiver: &address1]))

	TEST(@"-[receiveIntoBuffer:length:sender:]",

	    [sock receiveIntoBuffer: buffer length: 5 sender: &address2] == 5 &&
	    memcmp(buffer, "Hello", 5) == 0 &&
	    OFSocketAddressEqual(&address1, &address2) &&

	    OFSocketAddressHash(&address1) == OFSocketAddressHash(&address2))

	objc_autoreleasePoolPop(pool);
}
@end







>

|
>

|
>

|
|

<




|


<
|
|
|
|




<
<
<
|
<
<

<
<
<
|
<
<



|
<
<
|
<
<
|

|
>
|
|
|
>
|
<
<


12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

30
31
32
33
34
35
36

37
38
39
40
41
42
43
44



45


46



47


48
49
50
51


52


53
54
55
56
57
58
59
60
61


62
63
 * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
 * file.
 */

#include "config.h"

#include <errno.h>
#include <string.h>

#import "ObjFW.h"
#import "ObjFWTest.h"

@interface OFDDPSocketTests: OTTestCase
@end

@implementation OFDDPSocketTests
- (void)testDDPSocket
{

	OFDDPSocket *sock;
	OFSocketAddress address1, address2;
	char buffer[5];

	sock = [OFDDPSocket socket];

	@try {

		address1 = [sock bindToNetwork: 0
					  node: 0
					  port: 0
				  protocolType: 11];
	} @catch (OFBindSocketFailedException *e) {
		switch (e.errNo) {
		case EAFNOSUPPORT:
		case EPROTONOSUPPORT:



			OTSkip(@"AppleTalk unsupported");


		case EADDRNOTAVAIL:



			OTSkip(@"AppleTalk not configured");


		default:
			@throw e;
		}
	}





	[sock sendBuffer: "Hello" length: 5 receiver: &address1];

	OTAssertEqual([sock receiveIntoBuffer: buffer
				       length: 5
				       sender: &address2], 5);
	OTAssertEqual(memcmp(buffer, "Hello", 5), 0);
	OTAssertTrue(OFSocketAddressEqual(&address1, &address2));
	OTAssertEqual(OFSocketAddressHash(&address1),
	    OFSocketAddressHash(&address2));


}
@end

Modified tests/OFDNSResolverTests.m from [979544c90c] to [09e6956470].

11
12
13
14
15
16
17
18

19
20


21

22
23

24
25
26

27







28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63

64
65
66
67




68
69

70
71
 * 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"


@implementation TestsAppDelegate (OFDNSResolverTests)


- (void)DNSResolverTests

{
	void *pool = objc_autoreleasePoolPush();

	OFDNSResolver *resolver = [OFDNSResolver resolver];
	OFMutableString *staticHosts = [OFMutableString string];


	[OFStdOut setForegroundColor: [OFColor lime]];








	for (OFString *host in resolver.staticHosts) {
		OFString *IPs;

		if (staticHosts.length > 0)
			[staticHosts appendString: @"; "];

		IPs = [[resolver.staticHosts objectForKey: host]
		    componentsJoinedByString: @", "];

		[staticHosts appendFormat: @"%@=(%@)", host, IPs];
	}
	[OFStdOut writeFormat: @"[OFDNSResolver] Static hosts: %@\n",
	    staticHosts];

	[OFStdOut writeFormat: @"[OFDNSResolver] Name servers: %@\n",
	    [resolver.nameServers componentsJoinedByString: @", "]];

	[OFStdOut writeFormat: @"[OFDNSResolver] Local domain: %@\n",
	    resolver.localDomain];

	[OFStdOut writeFormat: @"[OFDNSResolver] Search domains: %@\n",
	    [resolver.searchDomains componentsJoinedByString: @", "]];

	[OFStdOut writeFormat: @"[OFDNSResolver] Timeout: %lf\n",
	    resolver.timeout];

	[OFStdOut writeFormat: @"[OFDNSResolver] Max attempts: %u\n",
	    resolver.maxAttempts];

	[OFStdOut writeFormat:
	    @"[OFDNSResolver] Min number of dots in absolute name: %u\n",
	    resolver.minNumberOfDotsInAbsoluteName];

	[OFStdOut writeFormat: @"[OFDNSResolver] Forces TCP: %u\n",
	    resolver.forcesTCP];


	[OFStdOut writeFormat:
	    @"[OFDNSResolver] Config reload interval: %lf\n",
	    resolver.configReloadInterval];





	objc_autoreleasePoolPop(pool);

}
@end







|
>

|
>
>
|
>

<
>



>
|
>
>
>
>
>
>
>












|
<

|
|
<
<
|
|
<
|

<
|
<
<
|
<
<
|
|
<
<
|
>

<
<
<
>
>
>
>

<
>


11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52

53
54
55


56
57

58
59

60


61


62
63


64
65
66



67
68
69
70
71

72
73
74
 * 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 OFDNSResolverTests: OTTestCase
@end

@implementation OFDNSResolverTests
+ (OFArray OF_GENERIC(OFPair OF_GENERIC(OFString *, id) *) *)summary
{

	OFMutableArray *summary = [OFMutableArray array];
	OFDNSResolver *resolver = [OFDNSResolver resolver];
	OFMutableString *staticHosts = [OFMutableString string];

#define ADD(name, value)						\
	[summary addObject: [OFPair pairWithFirstObject: name		\
					   secondObject: value]];
#define ADD_DOUBLE(name, value)						\
	ADD(name, [OFNumber numberWithDouble: value])
#define ADD_UINT(name, value)						\
	ADD(name, [OFNumber numberWithUnsignedInt: value]);
#define ADD_BOOL(name, value)						\
	ADD(name, [OFNumber numberWithBool: value]);

	for (OFString *host in resolver.staticHosts) {
		OFString *IPs;

		if (staticHosts.length > 0)
			[staticHosts appendString: @"; "];

		IPs = [[resolver.staticHosts objectForKey: host]
		    componentsJoinedByString: @", "];

		[staticHosts appendFormat: @"%@=(%@)", host, IPs];
	}
	ADD(@"Static hosts", staticHosts)


	ADD(@"Name servers",
	    [resolver.nameServers componentsJoinedByString: @", "]);


	ADD(@"Local domain", resolver.localDomain);
	ADD(@"Search domains",

	    [resolver.searchDomains componentsJoinedByString: @", "]);


	ADD_DOUBLE(@"Timeout", resolver.timeout);


	ADD_UINT(@"Max attempts", resolver.maxAttempts);


	ADD_UINT(@"Min number of dots in absolute name",
	    resolver.minNumberOfDotsInAbsoluteName);


	ADD_BOOL(@"Forces TCP", resolver.forcesTCP);
	ADD_DOUBLE(@"Config reload interval", resolver.configReloadInterval);




#undef ADD
#undef ADD_DOUBLE
#undef ADD_UINT
#undef ADD_BOOL


	return summary;
}
@end

Added tests/OFDataTests.h version [b0edcdb3e6].





















































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/*
 * Copyright (c) 2008-2024 Jonathan Schleifer <js@nil.im>
 *
 * 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 OFDataTests: OTTestCase
{
	OFData *_data;
	unsigned char _items[2][4096];
}

@property (readonly, nonatomic) Class dataClass;
@end

Modified tests/OFDataTests.m from [a8658a6bbf] to [e445376d45].

13
14
15
16
17
18
19
20
21



22
23
24
25
26
27
28
29
30
31


32
33

34
35
36
37


38


39

40


41
42
43
44
45

46

47
48
49
50

51
52
53
54
55

56
57
58



59
60


61
62
63
64



65
66



67

68
69
70

71

72


73
74
75
76

77
78


79
80





81
82
83
84
85

86


87

88
89





90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119

120
121
122
123
124
125
126
127

128
129
130
131
132
133
134
135
136
137




138

139





140
141
142
143
144

145
146
147
148
149
150
151

152

153







154
155


156
157
158
159
160

161



162
163
164




165

166

167

168
169

170

171

172
173

174

175

176
177

178
179
180
181
182
183
184
185
186
187

188
189
190
191
192
193
194
195
196
197
198
199
200
201
202


203
204
205
206
207
208
209
210

211



212
213
214
215
216
217
218

219
220
221
222
223
224

225


226
227
228
 * file.
 */

#include "config.h"

#include <string.h>

#import "TestsAppDelegate.h"




static OFString *const module = @"OFData";

@implementation TestsAppDelegate (OFDataTests)
- (void)dataTests
{
	void *pool = objc_autoreleasePoolPush();
	OFMutableData *mutableData;
	OFData *data;
	void *raw[2];
	OFRange range;



	TEST(@"+[dataWithItemSize:]",

	    (mutableData = [OFMutableData dataWithItemSize: 4096]))

	raw[0] = OFAllocMemory(1, 4096);
	raw[1] = OFAllocMemory(1, 4096);


	memset(raw[0], 0xFF, 4096);


	memset(raw[1], 0x42, 4096);




	TEST(@"-[addItem:]", R([mutableData addItem: raw[0]]) &&
	    R([mutableData addItem: raw[1]]))

	TEST(@"-[itemAtIndex:]",
	    memcmp([mutableData itemAtIndex: 0], raw[0], 4096) == 0 &&

	    memcmp([mutableData itemAtIndex: 1], raw[1], 4096) == 0)


	TEST(@"-[lastItem]", memcmp(mutableData.lastItem, raw[1], 4096) == 0)

	TEST(@"-[count]", mutableData.count == 2)


	TEST(@"-[isEqual:]",
	    (data = [OFData dataWithItems: mutableData.items
				    count: mutableData.count
				 itemSize: mutableData.itemSize]) &&

	    [data isEqual: mutableData] &&
	    R([mutableData removeLastItem]) && ![mutableData isEqual: data])




	TEST(@"-[mutableCopy]",
	    (mutableData = [[data mutableCopy] autorelease]) &&


	    [mutableData isEqual: data])

	TEST(@"-[compare]", [mutableData compare: data] == 0 &&
	    R([mutableData removeLastItem]) &&



	    [data compare: mutableData] == OFOrderedDescending &&
	    [mutableData compare: data] == OFOrderedAscending &&



	    [[OFData dataWithItems: "aa" count: 2] compare:

	    [OFData dataWithItems: "z" count: 1]] == OFOrderedAscending)

	TEST(@"-[hash]", data.hash == 0x634A529F)



	mutableData = [OFMutableData dataWithItems: "abcdef" count: 6];



	TEST(@"-[removeLastItem]",
	    R([mutableData removeLastItem]) && mutableData.count == 5 &&
	    memcmp(mutableData.items, "abcde", 5) == 0)


	TEST(@"-[removeItemsInRange:]",


	    R([mutableData removeItemsInRange: OFMakeRange(1, 2)]) &&
	    mutableData.count == 3 && memcmp(mutableData.items, "ade", 3) == 0)






	TEST(@"-[insertItems:atIndex:count:]",
	    R([mutableData insertItems: "bc" atIndex: 1 count: 2]) &&
	    mutableData.count == 5 &&
	    memcmp(mutableData.items, "abcde", 5) == 0)




	data = [OFData dataWithItems: "aaabaccdacaabb" count: 7 itemSize: 2];


	range = [data rangeOfData: [OFData dataWithItems: "aa"





						   count: 1
						itemSize: 2]
			  options: 0
			    range: OFMakeRange(0, 7)];
	TEST(@"-[rangeOfData:options:range:] #1",
	    range.location == 0 && range.length == 1)

	range = [data rangeOfData: [OFData dataWithItems: "aa"
						   count: 1
						itemSize: 2]
			  options: OFDataSearchBackwards
			    range: OFMakeRange(0, 7)];
	TEST(@"-[rangeOfData:options:range:] #2",
	    range.location == 5 && range.length == 1)

	range = [data rangeOfData: [OFData dataWithItems: "ac"
						   count: 1
						itemSize: 2]
			  options: 0
			    range: OFMakeRange(0, 7)];
	TEST(@"-[rangeOfData:options:range:] #3",
	    range.location == 2 && range.length == 1)

	range = [data rangeOfData: [OFData dataWithItems: "aabb"
						   count: 2
						itemSize: 2]
			  options: 0
			    range: OFMakeRange(0, 7)];
	TEST(@"-[rangeOfData:options:range:] #4",
	    range.location == 5 && range.length == 2)


	TEST(@"-[rangeOfData:options:range:] #5",
	    R(range = [data rangeOfData: [OFData dataWithItems: "aa"
							 count: 1
						      itemSize: 2]
				options: 0
				  range: OFMakeRange(1, 6)]) &&
	    range.location == 5 && range.length == 1)


	range = [data rangeOfData: [OFData dataWithItems: "aa"
						   count: 1
						itemSize: 2]
			  options: OFDataSearchBackwards
			    range: OFMakeRange(0, 5)];
	TEST(@"-[rangeOfData:options:range:] #6",
	    range.location == 0 && range.length == 1)

	EXPECT_EXCEPTION(




	    @"-[rangeOfData:options:range:] failing on different itemSize",

	    OFInvalidArgumentException,





	    [data rangeOfData: [OFData dataWithItems: "aaa"
					       count: 1
					    itemSize: 3]
		      options: 0
			range: OFMakeRange(0, 1)])


	EXPECT_EXCEPTION(
	    @"-[rangeOfData:options:range:] failing on out of range",
	    OFOutOfRangeException,
	    [data rangeOfData: [OFData dataWithItems: "" count: 0 itemSize: 2]
		      options: 0
			range: OFMakeRange(8, 1)])



	TEST(@"-[subdataWithRange:]",







	    [[data subdataWithRange: OFMakeRange(2, 4)]
	    isEqual: [OFData dataWithItems: "accdacaa" count: 4 itemSize: 2]] &&


	    [[mutableData subdataWithRange: OFMakeRange(2, 3)]
	    isEqual: [OFData dataWithItems: "cde" count: 3]])

	EXPECT_EXCEPTION(@"-[subdataWithRange:] failing on out of range #1",
	    OFOutOfRangeException,

	    [data subdataWithRange: OFMakeRange(7, 1)])




	EXPECT_EXCEPTION(@"-[subdataWithRange:] failing on out of range #2",
	    OFOutOfRangeException,




	    [mutableData subdataWithRange: OFMakeRange(6, 1)])



	TEST(@"-[stringByMD5Hashing]",

	    [mutableData.stringByMD5Hashing
	    isEqual: @"ab56b4d92b40713acc5af89985d4b786"])



	TEST(@"-[stringByRIPEMD160Hashing]",

	    [mutableData.stringByRIPEMD160Hashing
	    isEqual: @"973398b6e6c6cfa6b5e6a5173f195ce3274bf828"])



	TEST(@"-[stringBySHA1Hashing]",

	    [mutableData.stringBySHA1Hashing
	    isEqual: @"03de6c570bfe24bfc328ccd7ca46b76eadaf4334"])


	TEST(@"-[stringBySHA224Hashing]",
	    [mutableData.stringBySHA224Hashing
	    isEqual: @"bdd03d560993e675516ba5a50638b6531ac2ac3d5847c61916cfced6"
	    ])

	TEST(@"-[stringBySHA256Hashing]",
	    [mutableData.stringBySHA256Hashing
	    isEqual: @"36bbe50ed96841d10443bcb670d6554f0a34b761be67ec9c4a8ad2c0"
		     @"c44ca42c"])


	TEST(@"-[stringBySHA384Hashing]",
	    [mutableData.stringBySHA384Hashing
	    isEqual: @"4c525cbeac729eaf4b4665815bc5db0c84fe6300068a727cf74e2813"
		     @"521565abc0ec57a37ee4d8be89d097c0d2ad52f0"])

	TEST(@"-[stringBySHA512Hashing]",
	    [mutableData.stringBySHA512Hashing
	    isEqual: @"878ae65a92e86cac011a570d4c30a7eaec442b85ce8eca0c2952b5e3"
		     @"cc0628c2e79d889ad4d5c7c626986d452dd86374b6ffaa7cd8b67665"
		     @"bef2289a5c70b0a1"])

	TEST(@"-[stringByBase64Encoding]",
	    [mutableData.stringByBase64Encoding isEqual: @"YWJjZGU="])



	TEST(@"+[dataWithBase64EncodedString:]",
	    memcmp([[OFData dataWithBase64EncodedString: @"YWJjZGU="] items],
	    "abcde", 5) == 0)

	TEST(@"Building strings",
	    (mutableData = [OFMutableData dataWithItems: "Hello!" count: 6]) &&
	    R([mutableData addItem: ""]) &&
	    strcmp(mutableData.items, "Hello!") == 0)





	EXPECT_EXCEPTION(@"Detect out of range in -[itemAtIndex:]",
	    OFOutOfRangeException, [mutableData itemAtIndex: mutableData.count])

	EXPECT_EXCEPTION(@"Detect out of range in -[addItems:count:]",
	    OFOutOfRangeException,
	    [mutableData addItems: raw[0] count: SIZE_MAX])


	EXPECT_EXCEPTION(@"Detect out of range in -[removeItemsInRange:]",
	    OFOutOfRangeException,
	    [mutableData removeItemsInRange: OFMakeRange(mutableData.count, 1)])

	OFFreeMemory(raw[0]);
	OFFreeMemory(raw[1]);




	objc_autoreleasePoolPop(pool);
}
@end







|

>
>
>
|
|
|
|

<
<
<
|
|
>
>

|
>
|
|
|
|
>
>
|
>
>
|
>
|
>
>
|
|
|
<
|
>
|
>
|
|
|
|
>
|
|
<
<
|
>
|
|
|
>
>
>
|
<
>
>
|
|
|
|
>
>
>
|
<
>
>
>
|
>
|
|
|
>
|
>
|
>
>
|
|
<
<
>
|
|
>
>
|
<
>
>
>
>
>
|
|
<
<
<
>
|
>
>
|
>
|
|
>
>
>
>
>
|
|


|
|

|
|
|


|
|

|
|
|


|
|

|
|
|


<
|
>

<
|
|
|
|
|
|
>

|
|
|


|
|
|
|
>
>
>
>
|
>
|
>
>
>
>
>
|
<
<
|
|
>

<
|
<
|
|
|
>
|
>
|
>
>
>
>
>
>
>
|
|
>
>
|
|
|
|
|
>
|
>
>
>

|
|
>
>
>
>
|
>
|
>
|
>
|
<
>
|
>
|
>
|
<
>
|
>
|
>
|
<
>
|
|
|
<
<
|
<
|
<
<
>
|
|
|
<
<
|
|
|
|
<
<
|
|
|
|
>
>
|
|
<
|
|
<
<
<
>
|
>
>
>
|
|
|
|
|
<
|
>
|
<
<
|
|
<
>
|
>
>
|


13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29



30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53

54
55
56
57
58
59
60
61
62
63
64


65
66
67
68
69
70
71
72
73

74
75
76
77
78
79
80
81
82
83

84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99


100
101
102
103
104
105

106
107
108
109
110
111
112



113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153

154
155
156

157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186


187
188
189
190

191

192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233

234
235
236
237
238
239

240
241
242
243
244
245

246
247
248
249


250

251


252
253
254
255


256
257
258
259


260
261
262
263
264
265
266
267

268
269



270
271
272
273
274
275
276
277
278
279

280
281
282


283
284

285
286
287
288
289
290
291
 * file.
 */

#include "config.h"

#include <string.h>

#import "OFDataTests.h"

@implementation OFDataTests
- (Class)dataClass
{
	return [OFData class];
}

- (void)setUp
{



	[super setUp];

	memset(&_items[0], 0xFF, 4096);
	memset(&_items[1], 0x42, 4096);

	_data = [[self.dataClass alloc] initWithItems: _items
						count: 2
					     itemSize: 4096];
}

- (void)dealloc
{
	[_data release];

	[super dealloc];
}

- (void)testCount
{
	OTAssertEqual(_data.count, 2);
}

- (void)testItemSize
{

	OTAssertEqual(_data.itemSize, 4096);
}

- (void)testItems
{
	OTAssertEqual(memcmp(_data.items, _items, 2 * _data.itemSize), 0);
}

- (void)testItemAtIndex
{
	OTAssertEqual(


	    memcmp([_data itemAtIndex: 1], &_items[1], _data.itemSize), 0);
}

- (void)testItemAtIndexThrowsOnOutOfRangeIndex
{
	OTAssertThrowsSpecific([_data itemAtIndex: _data.count],
	    OFOutOfRangeException);
}


- (void)testFirstItem
{
	OTAssertEqual(memcmp(_data.firstItem, &_items[0], _data.itemSize), 0);
}

- (void)testLastItem
{
	OTAssertEqual(memcmp(_data.lastItem, &_items[1], _data.itemSize), 0);
}


- (void)testIsEqual
{
	OTAssertEqualObjects(
	    _data, [OFData dataWithItems: _items count: 2 itemSize: 4096]);
	OTAssertNotEqualObjects(
	    _data, [OFData dataWithItems: _items count: 1 itemSize: 4096]);
}

- (void)testHash
{
	OTAssertEqual(_data.hash,
	    [[OFData dataWithItems: _items count: 2 itemSize: 4096] hash]);
	OTAssertNotEqual(_data.hash,
	    [[OFData dataWithItems: _items count: 1 itemSize: 4096] hash]);
}



- (void)testCompare
{
	OFData *data1 = [self.dataClass dataWithItems: "aa" count: 2];
	OFData *data2 = [self.dataClass dataWithItems: "ab" count: 2];
	OFData *data3 = [self.dataClass dataWithItems: "aaa" count: 3];


	OTAssertEqual([data1 compare: data2], OFOrderedAscending);
	OTAssertEqual([data2 compare: data1], OFOrderedDescending);
	OTAssertEqual([data1 compare: data1], OFOrderedSame);
	OTAssertEqual([data1 compare: data3], OFOrderedAscending);
	OTAssertEqual([data2 compare: data3], OFOrderedDescending);
}




- (void)testCopy
{
	OTAssertEqualObjects([[_data copy] autorelease], _data);
}

- (void)testRangeOfDataOptionsRange
{
	OFData *data = [self.dataClass dataWithItems: "aaabaccdacaabb"
					       count: 7
					    itemSize: 2];
	OFRange range;

	range = [data rangeOfData: [self.dataClass dataWithItems: "aa"
							   count: 1
							itemSize: 2]
			  options: 0
			    range: OFMakeRange(0, 7)];
	OTAssertEqual(range.location, 0);
	OTAssertEqual(range.length, 1);

	range = [data rangeOfData: [self.dataClass dataWithItems: "aa"
							   count: 1
							itemSize: 2]
			  options: OFDataSearchBackwards
			    range: OFMakeRange(0, 7)];
	OTAssertEqual(range.location, 5);
	OTAssertEqual(range.length, 1);

	range = [data rangeOfData: [self.dataClass dataWithItems: "ac"
							   count: 1
							itemSize: 2]
			  options: 0
			    range: OFMakeRange(0, 7)];
	OTAssertEqual(range.location, 2);
	OTAssertEqual(range.length, 1);

	range = [data rangeOfData: [self.dataClass dataWithItems: "aabb"
							   count: 2
							itemSize: 2]
			  options: 0
			    range: OFMakeRange(0, 7)];

	OTAssertEqual(range.location, 5);
	OTAssertEqual(range.length, 2);


	range = [data rangeOfData: [self.dataClass dataWithItems: "aa"
							   count: 1
							itemSize: 2]
			  options: 0
			    range: OFMakeRange(1, 6)];
	OTAssertEqual(range.location, 5);
	OTAssertEqual(range.length, 1);

	range = [data rangeOfData: [self.dataClass dataWithItems: "aa"
							   count: 1
							itemSize: 2]
			  options: OFDataSearchBackwards
			    range: OFMakeRange(0, 5)];
	OTAssertEqual(range.location, 0);
	OTAssertEqual(range.length, 1);
}

- (void)testRangeOfDataOptionsRangeThrowsOnDifferentItemSize
{
	OTAssertThrowsSpecific(
	    [_data rangeOfData: [OFData dataWithItems: "a" count: 1]
		       options: 0
			 range: OFMakeRange(0, 1)],
	    OFInvalidArgumentException);
}

- (void)testRangeOfDataOptionsRangeThrowsOnOutOfRangeRange
{
	OTAssertThrowsSpecific(
	    [_data rangeOfData: [OFData dataWithItemSize: 4096]


		       options: 0
			 range: OFMakeRange(1, 2)],
	    OFOutOfRangeException);


	OTAssertThrowsSpecific(

	    [_data rangeOfData: [OFData dataWithItemSize: 4096]
		       options: 0
			 range: OFMakeRange(2, 1)],
	    OFOutOfRangeException);
}

- (void)testSubdataWithRange
{
	OFData *data1 = [self.dataClass dataWithItems: "aaabaccdacaabb"
						count: 7
					     itemSize: 2];
	OFData *data2 = [self.dataClass dataWithItems: "abcde" count: 5];

	OTAssertEqualObjects(
	    [data1 subdataWithRange: OFMakeRange(2, 4)],
	    [OFData dataWithItems: "accdacaa" count: 4 itemSize: 2]);

	OTAssertEqualObjects(
	    [data2 subdataWithRange: OFMakeRange(2, 3)],
	    [OFData dataWithItems: "cde" count: 3]);
}

- (void)testSubdataWithRangeThrowsOnOutOfRangeRange
{
	OFData *data1 = [self.dataClass dataWithItems: "aaabaccdacaabb"
						count: 7
					     itemSize: 2];
	OFData *data2 = [self.dataClass dataWithItems: "abcde" count: 5];

	OTAssertThrowsSpecific([data1 subdataWithRange: OFMakeRange(7, 1)],
	    OFOutOfRangeException);

	OTAssertThrowsSpecific([data1 subdataWithRange: OFMakeRange(8, 0)],
	    OFOutOfRangeException);

	OTAssertThrowsSpecific([data2 subdataWithRange: OFMakeRange(6, 1)],
	    OFOutOfRangeException);
}

- (void)testStringByMD5Hashing
{
	OTAssertEqualObjects(_data.stringByMD5Hashing,

	    @"37d65c8816008d58175b1d71ee892de3");
}

- (void)testStringByRIPEMD160Hashing
{
	OTAssertEqualObjects(_data.stringByRIPEMD160Hashing,

	    @"ab33a6a725f9fcec6299054dc604c0eb650cd889");
}

- (void)testStringBySHA1Hashing
{
	OTAssertEqualObjects(_data.stringBySHA1Hashing,

	    @"eb50cfcc29d0bed96b3bafe03e99110bcf6663b3");
}

- (void)testStringBySHA224Hashing


{

	OTAssertEqualObjects(_data.stringBySHA224Hashing,


	    @"204f8418a914a6828f8eb27871e01f74366f6d8fac8936029ebf0041");
}

- (void)testStringBySHA256Hashing


{
	OTAssertEqualObjects(_data.stringBySHA256Hashing,
	    @"27c521859f6f5b10aeac4e210a6d005c"
	    @"85e382c594e2622af9c46c6da8906821");


}

- (void)testStringBySHA384Hashing
{
	OTAssertEqualObjects(_data.stringBySHA384Hashing,
	    @"af99a52c26c00f01fe649dcc53d7c7a0"
	    @"a9ee0150b971955be2af395708966120"
	    @"5f2634f70df083ef63b232d5b8549db4");

}




- (void)testStringBySHA512Hashing
{
	OTAssertEqualObjects(_data.stringBySHA512Hashing,
	    @"1cbd53bf8bed9b45a63edda645ee1217"
	    @"24d2f0323c865e1039ba13320bc6c66e"
	    @"c79b6cdf6d08395c612b7decb1e59ad1"
	    @"e72bfa007c2f76a823d10204d47d2e2d");
}

- (void)testStringByBase64Encoding

{
	OTAssertEqualObjects([[self.dataClass dataWithItems: "abcde" count: 5]
	    stringByBase64Encoding], @"YWJjZGU=");


}


- (void)testDataWithBase64EncodedString
{
	OTAssertEqualObjects(
	    [self.dataClass dataWithBase64EncodedString: @"YWJjZGU="],
	    [OFData dataWithItems: "abcde" count: 5]);
}
@end

Added tests/OFDateTests.m version [f4f700dfaa].













































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
/*
 * Copyright (c) 2008-2024 Jonathan Schleifer <js@nil.im>
 *
 * 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 <time.h>

#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 tests/OFDictionaryTests.h version [e83688b5f9].



















































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/*
 * Copyright (c) 2008-2024 Jonathan Schleifer <js@nil.im>
 *
 * 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 OFDictionaryTests: OTTestCase
{
	OFDictionary *_dictionary;
}

@property (readonly, nonatomic) Class dictionaryClass;
@end

Modified tests/OFDictionaryTests.m from [322f36dbf5] to [49b4f5c917].

11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35





36

37









38
39

40
41
































42
43




44

45





46

47



48


49


50






51








52







53








54
55




56



57




58

59


60































61
62





63

64

65
66
67







68




69
70









71



72
73













74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
 * 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 *keys[] = {
	@"key1",
	@"key2"
};
static OFString *values[] = {
	@"value1",
	@"value2"
};

@interface SimpleDictionary: OFDictionary
{
	OFMutableDictionary *_dictionary;
}
@end






@interface SimpleMutableDictionary: OFMutableDictionary

{









	OFMutableDictionary *_dictionary;
	unsigned long _mutations;

}
@end

































@implementation SimpleDictionary




- (instancetype)init

{





	self = [super init];





	@try {


		_dictionary = [[OFMutableDictionary alloc] init];


	} @catch (id e) {






		[self release];








		@throw e;







	}









	return self;




}








- (instancetype)initWithKey: (id)key arguments: (va_list)arguments

{


	self = [super init];
































	@try {





		_dictionary = [[OFMutableDictionary alloc]

		    initWithKey: key

		      arguments: arguments];
	} @catch (id e) {
		[self release];







		@throw e;




	}










	return self;



}














- (instancetype)initWithObjects: (const id *)objects
			forKeys: (const id *)keys_
			  count: (size_t)count
{
	self = [super init];

	@try {
		_dictionary = [[OFMutableDictionary alloc]
		    initWithObjects: objects
			    forKeys: keys_
			      count: count];
	} @catch (id e) {
		[self release];
		@throw e;
	}

	return self;
}







|

<




|




|

|



>
>
>
>
>
|
>

>
>
>
>
>
>
>
>
>
|
|
>

|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
|
>
>
>
>
|
>

>
>
>
>
>
|
>
|
>
>
>
|
>
>
|
>
>
|
>
>
>
>
>
>
|
>
>
>
>
>
>
>
>
|
>
>
>
>
>
>
>
|
>
>
>
>
>
>
>
>
|
|
>
>
>
>
|
>
>
>

>
>
>
>
|
>

>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
|
>
>
>
>
>
|
>
|
>
|
|
|
>
>
>
>
>
>
>
|
>
>
>
>
|

>
>
>
>
>
>
>
>
>
|
>
>
>


>
>
>
>
>
>
>
>
>
>
>
>
>
|






<
|
|
|







11
12
13
14
15
16
17
18
19

20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262

263
264
265
266
267
268
269
270
271
272
 * 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 "OFDictionaryTests.h"


static OFString *keys[] = {
	@"key1",
	@"key2"
};
static OFString *objects[] = {
	@"value1",
	@"value2"
};

@interface CustomDictionary: OFDictionary
{
	OFDictionary *_dictionary;
}
@end

@implementation OFDictionaryTests
- (Class)dictionaryClass
{
	return [CustomDictionary class];
}

- (void)setUp
{
	[super setUp];

	_dictionary = [[self.dictionaryClass alloc] initWithObjects: objects
							    forKeys: keys
							      count: 2];
}

- (void)dealloc
{
	[_dictionary release];

	[super dealloc];
}

- (void)testObjectForKey
{
	OTAssertEqualObjects([_dictionary objectForKey: keys[0]], objects[0]);
	OTAssertEqualObjects([_dictionary objectForKey: keys[1]], objects[1]);
}

- (void)testCount
{
	OTAssertEqual(_dictionary.count, 2);
}

- (void)testIsEqual
{
	OTAssertEqualObjects(_dictionary,
	    [OFDictionary dictionaryWithObjects: objects
					forKeys: keys
					  count: 2]);
	OTAssertNotEqualObjects(_dictionary,
	    [OFDictionary dictionaryWithObjects: keys
					forKeys: objects
					  count: 2]);
}

- (void)testHash
{
	OTAssertEqual(_dictionary.hash,
	    [[OFDictionary dictionaryWithObjects: objects
					 forKeys: keys
					   count: 2] hash]);
	OTAssertNotEqual(_dictionary.hash,
	    [[OFDictionary dictionaryWithObject: objects[0]
					 forKey: keys[0]] hash]);
}

- (void)testCopy
{
	OTAssertEqualObjects([[_dictionary copy] autorelease], _dictionary);
}

- (void)testValueForKey
{
	OTAssertEqualObjects([_dictionary valueForKey: keys[0]], objects[0]);
	OTAssertEqualObjects([_dictionary valueForKey: keys[1]], objects[1]);
	OTAssertEqualObjects(
	    [_dictionary valueForKey: @"@count"], [OFNumber numberWithInt: 2]);
}

- (void)testSetValueForKey
{
	OTAssertThrowsSpecific([_dictionary setValue: @"x" forKey: @"x"],
	    OFUndefinedKeyException);
}

- (void)testContainsObject
{
	OTAssertTrue([_dictionary containsObject: objects[0]]);
	OTAssertFalse([_dictionary containsObject: @"nonexistent"]);
}

- (void)testContainsObjectIdenticalTo
{
	OTAssertTrue([_dictionary containsObjectIdenticalTo: objects[0]]);
	OTAssertFalse([_dictionary containsObjectIdenticalTo:
	    [[objects[0] mutableCopy] autorelease]]);
}

- (void)testDescription
{
	OTAssert(
	    [_dictionary.description isEqual:
	    @"{\n\tkey1 = value1;\n\tkey2 = value2;\n}"] ||
	    [_dictionary.description isEqual:
	    @"{\n\tkey2 = value2;\n\tkey1 = value1;\n}"]);
}

- (void)testAllKeys
{
	OTAssert(
	    [_dictionary.allKeys isEqual:
	    ([OFArray arrayWithObjects: keys[0], keys[1], nil])] ||
	    [_dictionary.allKeys isEqual:
	    ([OFArray arrayWithObjects: keys[1], keys[0], nil])]);
}

- (void)testAllObjects
{
	OTAssert(
	    [_dictionary.allObjects isEqual:
	    ([OFArray arrayWithObjects: objects[0], objects[1], nil])] ||
	    [_dictionary.allObjects isEqual:
	    ([OFArray arrayWithObjects: objects[1], objects[0], nil])]);
}

- (void)testKeyEnumerator
{
	OFEnumerator *enumerator = [_dictionary keyEnumerator];
	OFString *first, *second;

	first = [enumerator nextObject];
	second = [enumerator nextObject];
	OTAssertNil([enumerator nextObject]);

	OTAssert(
	    ([first isEqual: keys[0]] && [second isEqual: keys[1]]) ||
	    ([first isEqual: keys[1]] && [second isEqual: keys[0]]));
}

- (void)testObjectEnumerator
{
	OFEnumerator *enumerator = [_dictionary objectEnumerator];
	OFString *first, *second;

	first = [enumerator nextObject];
	second = [enumerator nextObject];
	OTAssertNil([enumerator nextObject]);

	OTAssert(
	    ([first isEqual: objects[0]] && [second isEqual: objects[1]]) ||
	    ([first isEqual: objects[1]] && [second isEqual: objects[0]]));
}

- (void)testFastEnumeration
{
	size_t i = 0;
	OFString *first = nil, *second = nil;

	for (OFString *key in _dictionary) {
		OTAssertLessThan(i, 2);

		switch (i++) {
		case 0:
			first = key;
			break;
		case 1:
			second = key;
			break;
		}
	}

	OTAssertEqual(i, 2);
	OTAssert(
	    ([first isEqual: keys[0]] && [second isEqual: keys[1]]) ||
	    ([first isEqual: keys[1]] && [second isEqual: keys[0]]));
}

#ifdef OF_HAVE_BLOCKS
- (void)testEnumerateKeysAndObjectsUsingBlock
{
	__block size_t i = 0;
	__block OFString *first = nil, *second = nil;

	[_dictionary enumerateKeysAndObjectsUsingBlock:
	    ^ (id key, id object, bool *stop) {
		OTAssertLessThan(i, 2);

		switch (i++) {
		case 0:
			first = key;
			break;
		case 1:
			second = key;
			break;
		}
	}];

	OTAssertEqual(i, 2);
	OTAssert(
	    ([first isEqual: keys[0]] && [second isEqual: keys[1]]) ||
	    ([first isEqual: keys[1]] && [second isEqual: keys[0]]));
}

- (void)testMappedDictionaryUsingBlock
{
	OTAssertEqualObjects([_dictionary mappedDictionaryUsingBlock:
	    ^ id (id key, id object) {
		if ([key isEqual: keys[0]])
			return @"val1";
		if ([key isEqual: keys[1]])
			return @"val2";

		return nil;
	    }],
	    ([OFDictionary dictionaryWithKeysAndObjects:
	    @"key1", @"val1", @"key2", @"val2", nil]));
}

- (void)testFilteredDictionaryUsingBlock
{
	OTAssertEqualObjects([_dictionary filteredDictionaryUsingBlock:
	    ^ bool (id key, id object) {
		return [key isEqual: keys[0]];
	    }],
	    [OFDictionary dictionaryWithObject: objects[0]
					forKey: keys[0]]);
}
#endif
@end

@implementation CustomDictionary
- (instancetype)initWithObjects: (const id *)objects_
			forKeys: (const id *)keys_
			  count: (size_t)count
{
	self = [super init];

	@try {

		_dictionary = [[OFDictionary alloc] initWithObjects: objects_
							    forKeys: keys_
							      count: count];
	} @catch (id e) {
		[self release];
		@throw e;
	}

	return self;
}
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
	return _dictionary.count;
}

- (OFEnumerator *)keyEnumerator
{
	return [_dictionary keyEnumerator];
}
@end

@implementation SimpleMutableDictionary
+ (void)initialize
{
	if (self == [SimpleMutableDictionary class])
		[self inheritMethodsFromClass: [SimpleDictionary class]];
}

- (void)setObject: (id)object forKey: (id)key
{
	bool existed = ([_dictionary objectForKey: key] == nil);

	[_dictionary setObject: object forKey: key];

	if (existed)
		_mutations++;
}

- (void)removeObjectForKey: (id)key
{
	bool existed = ([_dictionary objectForKey: key] == nil);

	[_dictionary removeObjectForKey: key];

	if (existed)
		_mutations++;
}

- (int)countByEnumeratingWithState: (OFFastEnumerationState *)state
			   objects: (id *)objects
			     count: (int)count
{
	int ret = [super countByEnumeratingWithState: state
					     objects: objects
					       count: count];

	state->mutationsPtr = &_mutations;

	return ret;
}
@end

@implementation TestsAppDelegate (OFDictionaryTests)
- (void)dictionaryTestsWithClass: (Class)dictionaryClass
		    mutableClass: (Class)mutableDictionaryClass
{
	void *pool = objc_autoreleasePoolPush();
	OFMutableDictionary *mutableDict = [mutableDictionaryClass dictionary];
	OFDictionary *dict;
	OFEnumerator *keyEnumerator, *objectEnumerator;
	OFArray *keysArray, *valuesArray;

	[mutableDict setObject: values[0] forKey: keys[0]];
	[mutableDict setValue: values[1] forKey: keys[1]];

	TEST(@"-[objectForKey:]",
	    [[mutableDict objectForKey: keys[0]] isEqual: values[0]] &&
	    [[mutableDict objectForKey: keys[1]] isEqual: values[1]] &&
	    [mutableDict objectForKey: @"key3"] == nil)

	TEST(@"-[valueForKey:]",
	    [[mutableDict valueForKey: keys[0]] isEqual: values[0]] &&
	    [[mutableDict valueForKey: @"@count"] isEqual:
	    [OFNumber numberWithInt: 2]])

	EXPECT_EXCEPTION(@"Catching -[setValue:forKey:] on immutable "
	    @"dictionary", OFUndefinedKeyException,
	    [[dictionaryClass dictionary] setValue: @"x" forKey: @"x"])

	TEST(@"-[containsObject:]",
	    [mutableDict containsObject: values[0]] &&
	    ![mutableDict containsObject: @"nonexistent"])

	TEST(@"-[containsObjectIdenticalTo:]",
	    [mutableDict containsObjectIdenticalTo: values[0]] &&
	    ![mutableDict containsObjectIdenticalTo:
	    [OFString stringWithString: values[0]]])

	TEST(@"-[description]",
	    [[mutableDict description] isEqual:
	    @"{\n\tkey1 = value1;\n\tkey2 = value2;\n}"])

	TEST(@"-[allKeys]",
	    [[mutableDict allKeys] isEqual:
	    [OFArray arrayWithObjects: keys[0], keys[1], nil]])

	TEST(@"-[allObjects]",
	    [[mutableDict allObjects] isEqual:
	    [OFArray arrayWithObjects: values[0], values[1], nil]])

	TEST(@"-[keyEnumerator]", (keyEnumerator = [mutableDict keyEnumerator]))
	TEST(@"-[objectEnumerator]",
	    (objectEnumerator = [mutableDict objectEnumerator]))

	TEST(@"OFEnumerator's -[nextObject]",
	    [[keyEnumerator nextObject] isEqual: keys[0]] &&
	    [[objectEnumerator nextObject] isEqual: values[0]] &&
	    [[keyEnumerator nextObject] isEqual: keys[1]] &&
	    [[objectEnumerator nextObject] isEqual: values[1]] &&
	    [keyEnumerator nextObject] == nil &&
	    [objectEnumerator nextObject] == nil)

	[mutableDict removeObjectForKey: keys[0]];

	EXPECT_EXCEPTION(@"Detection of mutation during enumeration",
	    OFEnumerationMutationException, [keyEnumerator nextObject]);

	[mutableDict setObject: values[0] forKey: keys[0]];

	size_t i = 0;
	bool ok = true;

	for (OFString *key in mutableDict) {
		if (i > 1 || ![key isEqual: keys[i]]) {
			ok = false;
			break;
		}

		[mutableDict setObject: [mutableDict objectForKey: key]
				forKey: key];
		i++;
	}

	TEST(@"Fast Enumeration", ok)

	ok = false;
	@try {
		for (OFString *key in mutableDict) {
			(void)key;
			[mutableDict setObject: @"" forKey: @""];
		}
	} @catch (OFEnumerationMutationException *e) {
		ok = true;
	}

	TEST(@"Detection of mutation during Fast Enumeration", ok)

	[mutableDict removeObjectForKey: @""];

#ifdef OF_HAVE_BLOCKS
	{
		__block size_t j = 0;
		__block bool blockOk = true;

		[mutableDict enumerateKeysAndObjectsUsingBlock:
		    ^ (id key, id object, bool *stop) {
			if (j > 1 || ![key isEqual: keys[j]]) {
				blockOk = false;
				*stop = true;
				return;
			}

			[mutableDict setObject: [mutableDict objectForKey: key]
					forKey: key];
			j++;
		}];

		TEST(@"Enumeration using blocks", blockOk)

		blockOk = false;
		@try {
			[mutableDict enumerateKeysAndObjectsUsingBlock:
			    ^ (id key, id object, bool *stop) {
				[mutableDict setObject: @"" forKey: @""];
			}];
		} @catch (OFEnumerationMutationException *e) {
			blockOk = true;
		}

		TEST(@"Detection of mutation during enumeration using blocks",
		    blockOk)

		[mutableDict removeObjectForKey: @""];
	}

	TEST(@"-[replaceObjectsUsingBlock:]",
	    R([mutableDict replaceObjectsUsingBlock: ^ id (id key, id object) {
		    if ([key isEqual: keys[0]])
			    return @"value_1";
		    if ([key isEqual: keys[1]])
			    return @"value_2";

		    return nil;
	    }]) && [[mutableDict objectForKey: keys[0]] isEqual: @"value_1"] &&
	    [[mutableDict objectForKey: keys[1]] isEqual: @"value_2"])

	TEST(@"-[mappedDictionaryUsingBlock:]",
	    [[[mutableDict mappedDictionaryUsingBlock:
		^ id (id key, id object) {
		    if ([key isEqual: keys[0]])
			    return @"val1";
		    if ([key isEqual: keys[1]])
			    return @"val2";

		return nil;
	    }] description] isEqual: @"{\n\tkey1 = val1;\n\tkey2 = val2;\n}"])

	TEST(@"-[filteredDictionaryUsingBlock:]",
	    [[[mutableDict filteredDictionaryUsingBlock:
		^ bool (id key, id object) {
		    return [key isEqual: keys[0]];
	    }] description] isEqual: @"{\n\tkey1 = value_1;\n}"])
#endif

	TEST(@"-[count]", mutableDict.count == 2)

	TEST(@"+[dictionaryWithKeysAndObjects:]",
	    (dict = [dictionaryClass dictionaryWithKeysAndObjects:
	    @"foo", @"bar", @"baz", @"qux", nil]) &&
	    [[dict objectForKey: @"foo"] isEqual: @"bar"] &&
	    [[dict objectForKey: @"baz"] isEqual: @"qux"])

	TEST(@"+[dictionaryWithObject:forKey:]",
	    (dict = [dictionaryClass dictionaryWithObject: @"bar"
						   forKey: @"foo"]) &&
	    [[dict objectForKey: @"foo"] isEqual: @"bar"])

	keysArray = [OFArray arrayWithObjects: keys[0], keys[1], nil];
	valuesArray = [OFArray arrayWithObjects: values[0], values[1], nil];
	TEST(@"+[dictionaryWithObjects:forKeys:]",
	    (dict = [dictionaryClass dictionaryWithObjects: valuesArray
						   forKeys: keysArray]) &&
	    [[dict objectForKey: keys[0]] isEqual: values[0]] &&
	    [[dict objectForKey: keys[1]] isEqual: values[1]])

	TEST(@"-[copy]",
	    (dict = [[dict copy] autorelease]) &&
	    [[dict objectForKey: keys[0]] isEqual: values[0]] &&
	    [[dict objectForKey: keys[1]] isEqual: values[1]])

	TEST(@"-[mutableCopy]",
	    (mutableDict = [[dict mutableCopy] autorelease]) &&
	    mutableDict.count == dict.count &&
	    [[mutableDict objectForKey: keys[0]] isEqual: values[0]] &&
	    [[mutableDict objectForKey: keys[1]] isEqual: values[1]] &&
	    R([mutableDict setObject: @"value3" forKey: @"key3"]) &&
	    [[mutableDict objectForKey: @"key3"] isEqual: @"value3"] &&
	    [[mutableDict objectForKey: keys[0]] isEqual: values[0]] &&
	    R([mutableDict setObject: @"foo" forKey: keys[0]]) &&
	    [[mutableDict objectForKey: keys[0]] isEqual: @"foo"])

	TEST(@"-[removeObjectForKey:]",
	    R([mutableDict removeObjectForKey: keys[0]]) &&
	    [mutableDict objectForKey: keys[0]] == nil)

	[mutableDict setObject: @"foo" forKey: keys[0]];
	TEST(@"-[isEqual:]", ![mutableDict isEqual: dict] &&
	    R([mutableDict removeObjectForKey: @"key3"]) &&
	    ![mutableDict isEqual: dict] &&
	    R([mutableDict setObject: values[0] forKey: keys[0]]) &&
	    [mutableDict isEqual: dict])

	objc_autoreleasePoolPop(pool);
}

- (void)dictionaryTests
{
	module = @"OFDictionary";
	[self dictionaryTestsWithClass: [SimpleDictionary class]
			  mutableClass: [SimpleMutableDictionary class]];

	module = @"OFDictionary_hashtable";
	[self dictionaryTestsWithClass: [OFDictionary class]
			  mutableClass: [OFMutableDictionary class]];
}
@end








<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
288
289
290
291
292
293
294
295










































































































































































































































































	return _dictionary.count;
}

- (OFEnumerator *)keyEnumerator
{
	return [_dictionary keyEnumerator];
}
@end










































































































































































































































































Added tests/OFHMACTests.m version [726dca6e51].





















































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
/*
 * Copyright (c) 2008-2024 Jonathan Schleifer <js@nil.im>
 *
 * 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 <string.h>

#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

Modified tests/OFHTTPClientTests.m from [8ae0f89264] to [d3dab1d884].

14
15
16
17
18
19
20
21

22
23
24

25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96

97
98
99
100
101
102
103
104
105
106
107
108

109
110


111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130



131
132
133
134























135

136
137

138
139



140

















141



142


143


144










145
146








147


148












149
150
 */

#include "config.h"

#include <inttypes.h>
#include <string.h>

#import "TestsAppDelegate.h"


static OFString *const module = @"OFHTTPClient";
static OFCondition *condition;

static OFHTTPResponse *response = nil;

@interface TestsAppDelegate (HTTPClientTests) <OFHTTPClientDelegate>
@end

@interface HTTPClientTestsServer: OFThread
{
@public
	uint16_t _port;
}
@end

@implementation HTTPClientTestsServer
- (id)main
{
	OFTCPSocket *listener, *client;
	OFSocketAddress address;
	char buffer[5];

	[condition lock];

	listener = [OFTCPSocket socket];
	address = [listener bindToHost: @"127.0.0.1" port: 0];
	_port = OFSocketAddressIPPort(&address);
	[listener listen];

	[condition signal];
	[condition unlock];

	client = [listener accept];

	OFEnsure([[client readLine] isEqual: @"GET /foo HTTP/1.1"]);
	OFEnsure([[client readLine] hasPrefix: @"User-Agent:"]);
	OFEnsure([[client readLine] isEqual: @"Content-Length: 5"]);
	OFEnsure([[client readLine] isEqual:
	    @"Content-Type: application/x-www-form-urlencoded; charset=UTF-8"]);

	if (![[client readLine] isEqual:
	    [OFString stringWithFormat: @"Host: 127.0.0.1:%" @PRIu16, _port]])
		OFEnsure(0);

	OFEnsure([[client readLine] isEqual: @""]);

	[client readIntoBuffer: buffer exactLength: 5];
	OFEnsure(memcmp(buffer, "Hello", 5) == 0);

	[client writeString: @"HTTP/1.0 200 OK\r\n"
			     @"cONTeNT-lENgTH: 7\r\n"
			     @"\r\n"
			     @"foo\n"
			     @"bar"];
	[client close];

	return nil;
}
@end

@implementation TestsAppDelegate (OFHTTPClientTests)
-     (void)client: (OFHTTPClient *)client
  wantsRequestBody: (OFStream *)body
	   request: (OFHTTPRequest *)request
{
	[body writeString: @"Hello"];
}

-      (void)client: (OFHTTPClient *)client
  didPerformRequest: (OFHTTPRequest *)request
	   response: (OFHTTPResponse *)response_
	  exception: (id)exception
{
	OFEnsure(exception == nil);


	response = [response_ retain];

	[[OFRunLoop mainRunLoop] stop];
}

- (void)HTTPClientTests
{
	void *pool = objc_autoreleasePoolPush();
	HTTPClientTestsServer *server;
	OFIRI *IRI;
	OFHTTPClient *client;
	OFHTTPRequest *request;

	OFData *data;



	condition = [OFCondition condition];
	[condition lock];

	server = [[[HTTPClientTestsServer alloc] init] autorelease];
	server.supportsSockets = true;
	[server start];

	[condition wait];
	[condition unlock];

	IRI = [OFIRI IRIWithString:
	    [OFString stringWithFormat: @"http://127.0.0.1:%" @PRIu16 "/foo",
					server->_port]];

	TEST(@"-[asyncPerformRequest:]",
	    (client = [OFHTTPClient client]) && (client.delegate = self) &&
	    (request = [OFHTTPRequest requestWithIRI: IRI]) &&
	    (request.headers =
	    [OFDictionary dictionaryWithObject: @"5"
					forKey: @"Content-Length"]) &&



	    R([client asyncPerformRequest: request]))

	[[OFRunLoop mainRunLoop] runUntilDate:
	    [OFDate dateWithTimeIntervalSinceNow: 2]];























	[response autorelease];


	TEST(@"Asynchronous handling of requests", response != nil)


	TEST(@"Normalization of server header keys",



	    [response.headers objectForKey: @"Content-Length"] != nil)





















	TEST(@"Correct parsing of data",


	    (data = [response readDataUntilEndOfStream]) &&


	    data.count == 7 && memcmp(data.items, "foo\nbar", 7) == 0)











	[server join];











	objc_autoreleasePoolPop(pool);












}
@end







|
>

|
<
>
|
|
<




|


<

<
<
<
<
<
<
|
<
|
<
<
<
<
|
<
<

<
|
<
<
<
<
<
|
<
<
<
|
<
|
<
<

<
<
<
<
<
<
|
<

<

<












|

>
|




|

<


<

>


>
>
|
|

<
<


|
|



|

<
<
|
|
|
|
>
>
>
|



>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>
|
|
>
|
|
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

>
>
>
|
>
>
|
>
>
|
>
>
>
>
>
>
>
>
>
>
|
|
>
>
>
>
>
>
>
>

>
>
|
>
>
>
>
>
>
>
>
>
>
>
>


14
15
16
17
18
19
20
21
22
23
24

25
26
27

28
29
30
31
32
33
34

35






36

37




38


39

40





41



42

43


44






45

46

47

48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69

70
71

72
73
74
75
76
77
78
79
80


81
82
83
84
85
86
87
88
89


90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
 */

#include "config.h"

#include <inttypes.h>
#include <string.h>

#import "ObjFW.h"
#import "ObjFWTest.h"

@interface OFHTTPClientTests: OTTestCase <OFHTTPClientDelegate>

{
	OFHTTPResponse *_response;
}

@end

@interface HTTPClientTestsServer: OFThread
{
	OFCondition *_condition;
	uint16_t _port;
}








@property (readonly, nonatomic) OFCondition *condition;

@property (readonly) uint16_t port;




@end




@implementation OFHTTPClientTests





- (void)dealloc



{

	[_response release];









	[super dealloc];

}



-     (void)client: (OFHTTPClient *)client
  wantsRequestBody: (OFStream *)body
	   request: (OFHTTPRequest *)request
{
	[body writeString: @"Hello"];
}

-      (void)client: (OFHTTPClient *)client
  didPerformRequest: (OFHTTPRequest *)request
	   response: (OFHTTPResponse *)response_
	  exception: (id)exception
{
	OTAssertNil(exception);

	[_response release];
	_response = [response_ retain];

	[[OFRunLoop mainRunLoop] stop];
}

- (void)testClient
{

	HTTPClientTestsServer *server;
	OFIRI *IRI;

	OFHTTPRequest *request;
	OFHTTPClient *client;
	OFData *data;

	server = [[[HTTPClientTestsServer alloc] init] autorelease];
	server.supportsSockets = true;

	[server.condition lock];



	[server start];

	[server.condition wait];
	[server.condition unlock];

	IRI = [OFIRI IRIWithString:
	    [OFString stringWithFormat: @"http://127.0.0.1:%" @PRIu16 "/foo",
					server.port]];



	request = [OFHTTPRequest requestWithIRI: IRI];
	request.headers = [OFDictionary
	    dictionaryWithObject: @"5"
			  forKey: @"Content-Length"];

	client = [OFHTTPClient client];
	client.delegate = self;
	[client asyncPerformRequest: request];

	[[OFRunLoop mainRunLoop] runUntilDate:
	    [OFDate dateWithTimeIntervalSinceNow: 2]];

	OTAssertNotNil(_response);
	OTAssertNotNil([_response.headers objectForKey: @"Content-Length"]);

	data = [_response readDataUntilEndOfStream];
	OTAssertEqual(data.count, 7);
	OTAssertEqual(data.itemSize, 1);
	OTAssertEqual(memcmp(data.items, "foo\nbar", 7), 0);

	OTAssertNil([server join]);
}
@end

@implementation HTTPClientTestsServer
@synthesize condition = _condition, port = _port;

- (instancetype)init
{
	self = [super init];

	@try {
		_condition = [[OFCondition alloc] init];
	} @catch (id e) {
		[self release];
		@throw e;
	}

	return self;
}

- (void)dealloc
{
	[_condition release];

	[super dealloc];
}

- (id)main
{
	OFTCPSocket *listener, *client;
	OFSocketAddress address;
	bool sawHost = false, sawContentLength = false, sawContentType = false;
	bool sawUserAgent = false;
	char buffer[5];

	[_condition lock];

	listener = [OFTCPSocket socket];
	address = [listener bindToHost: @"127.0.0.1" port: 0];
	_port = OFSocketAddressIPPort(&address);
	[listener listen];

	[_condition signal];
	[_condition unlock];
	client = [listener accept];

	if (![[client readLine] isEqual: @"GET /foo HTTP/1.1"])
		return @"Wrong request";

	for (size_t i = 0; i < 4; i++) {
		OFString *line = [client readLine];

		if ([line isEqual: [OFString stringWithFormat:
		    @"Host: 127.0.0.1:%" @PRIu16, _port]])
			sawHost = true;
		else if ([line isEqual: @"Content-Length: 5"])
			sawContentLength = true;
		if ([line isEqual: @"Content-Type: application/"
		    @"x-www-form-urlencoded; charset=UTF-8"])
			sawContentType = true;
		else if ([line hasPrefix: @"User-Agent:"])
			sawUserAgent = true;
	}

	if (!sawHost)
		return @"Missing host";
	if (!sawContentLength)
		return @"Missing content length";
	if (!sawContentType)
		return @"Missing content type";
	if (!sawUserAgent)
		return @"Missing user agent";

	if (![[client readLine] isEqual: @""])
		return @"Missing empty line";

	[client readIntoBuffer: buffer exactLength: 5];
	if (memcmp(buffer, "Hello", 5) != 0)
		return @"Missing body";

	[client writeString: @"HTTP/1.0 200 OK\r\n"
			     @"cONTeNT-lENgTH: 7\r\n"
			     @"\r\n"
			     @"foo\n"
			     @"bar"];
	[client close];

	return nil;
}
@end

Modified tests/OFHTTPCookieManagerTests.m from [fdaaae41cf] to [03be30a247].

11
12
13
14
15
16
17
18

19
20

21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
 * 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 = @"OFHTTPCookieManager";


@implementation TestsAppDelegate (OFHTTPCookieManagerTests)
- (void)HTTPCookieManagerTests
{
	void *pool = objc_autoreleasePoolPush();
	OFHTTPCookieManager *manager = [OFHTTPCookieManager manager];
	OFIRI *IRI1, *IRI2, *IRI3, *IRI4;
	OFHTTPCookie *cookie1, *cookie2, *cookie3, *cookie4, *cookie5;

	IRI1 = [OFIRI IRIWithString: @"http://nil.im/foo"];
	IRI2 = [OFIRI IRIWithString: @"https://nil.im/foo/bar"];
	IRI3 = [OFIRI IRIWithString: @"https://test.nil.im/foo/bar"];
	IRI4 = [OFIRI IRIWithString: @"http://webkeks.org/foo/bar"];

	cookie1 = [OFHTTPCookie cookieWithName: @"test"
					 value: @"1"
					domain: @"nil.im"];
	TEST(@"-[addCookie:forIRI:] #1",
	    R([manager addCookie: cookie1 forIRI: IRI1]))

	TEST(@"-[cookiesForIRI:] #1",
	    [[manager cookiesForIRI: IRI1] isEqual:
	    [OFArray arrayWithObject: cookie1]])

	cookie2 = [OFHTTPCookie cookieWithName: @"test"
					 value: @"2"
					domain: @"webkeks.org"];
	TEST(@"-[addCookie:forIRI:] #2",
	    R([manager addCookie: cookie2 forIRI: IRI1]))

	TEST(@"-[cookiesForIRI:] #2",
	    [[manager cookiesForIRI: IRI1] isEqual:
	    [OFArray arrayWithObject: cookie1]] &&
	    [[manager cookiesForIRI: IRI4] isEqual: [OFArray array]])

	cookie3 = [OFHTTPCookie cookieWithName: @"test"
					 value: @"3"
					domain: @"nil.im"];
	cookie3.secure = true;
	TEST(@"-[addCookie:forIRI:] #3",
	    R([manager addCookie: cookie3 forIRI: IRI2]))

	TEST(@"-[cookiesForIRI:] #3",
	    [[manager cookiesForIRI: IRI2] isEqual:
	    [OFArray arrayWithObject: cookie3]] &&
	    [[manager cookiesForIRI: IRI1] isEqual: [OFArray array]])

	cookie3.expires = [OFDate dateWithTimeIntervalSinceNow: -1];
	cookie4 = [OFHTTPCookie cookieWithName: @"test"
					 value: @"4"
					domain: @"nil.im"];
	cookie4.domain = @".nil.im";
	TEST(@"-[addCookie:forIRI:] #4",
	    R([manager addCookie: cookie4 forIRI: IRI2]))

	TEST(@"-[cookiesForIRI:] #4",
	    [[manager cookiesForIRI: IRI2] isEqual:
	    [OFArray arrayWithObject: cookie4]] &&
	    [[manager cookiesForIRI: IRI3] isEqual:
	    [OFArray arrayWithObject: cookie4]])

	cookie5 = [OFHTTPCookie cookieWithName: @"bar"
					 value: @"5"
					domain: @"test.nil.im"];
	TEST(@"-[addCookie:forIRI:] #5",
	    R([manager addCookie: cookie5 forIRI: IRI1]))

	TEST(@"-[cookiesForIRI:] #5",
	    [[manager cookiesForIRI: IRI1] isEqual:
	    [OFArray arrayWithObject: cookie4]] &&
	    [[manager cookiesForIRI: IRI3] isEqual:
	    [OFArray arrayWithObjects: cookie4, cookie5, nil]])

	TEST(@"-[purgeExpiredCookies]",
	    [manager.cookies isEqual:
	    [OFArray arrayWithObjects: cookie3, cookie4, cookie5, nil]] &&
	    R([manager purgeExpiredCookies]) &&
	    [manager.cookies isEqual:
	    [OFArray arrayWithObjects: cookie4, cookie5, nil]])

	objc_autoreleasePoolPop(pool);
}
@end







|
>

|
>

|
|

<












<
|
<
<
|
|




<
|
<
<
|
|
|





<
|
<
<
|
|
|






<
|
<
<
|
|
|
|




<
|
<
<
|
|
|
|

<
|
|
|
|
|
<
<


11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

27
28
29
30
31
32
33
34
35
36
37
38

39


40
41
42
43
44
45

46


47
48
49
50
51
52
53
54

55


56
57
58
59
60
61
62
63
64

65


66
67
68
69
70
71
72
73

74


75
76
77
78
79

80
81
82
83
84


85
86
 * 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 OFHTTPCookieManagerTests: OTTestCase
@end

@implementation OFHTTPCookieManagerTests
- (void)testCookieManager
{

	OFHTTPCookieManager *manager = [OFHTTPCookieManager manager];
	OFIRI *IRI1, *IRI2, *IRI3, *IRI4;
	OFHTTPCookie *cookie1, *cookie2, *cookie3, *cookie4, *cookie5;

	IRI1 = [OFIRI IRIWithString: @"http://nil.im/foo"];
	IRI2 = [OFIRI IRIWithString: @"https://nil.im/foo/bar"];
	IRI3 = [OFIRI IRIWithString: @"https://test.nil.im/foo/bar"];
	IRI4 = [OFIRI IRIWithString: @"http://webkeks.org/foo/bar"];

	cookie1 = [OFHTTPCookie cookieWithName: @"test"
					 value: @"1"
					domain: @"nil.im"];

	[manager addCookie: cookie1 forIRI: IRI1];


	OTAssertEqualObjects([manager cookiesForIRI: IRI1],
	    [OFArray arrayWithObject: cookie1]);

	cookie2 = [OFHTTPCookie cookieWithName: @"test"
					 value: @"2"
					domain: @"webkeks.org"];

	[manager addCookie: cookie2 forIRI: IRI1];


	OTAssertEqualObjects([manager cookiesForIRI: IRI1],
	    [OFArray arrayWithObject: cookie1]);
	OTAssertEqualObjects([manager cookiesForIRI: IRI4], [OFArray array]);

	cookie3 = [OFHTTPCookie cookieWithName: @"test"
					 value: @"3"
					domain: @"nil.im"];
	cookie3.secure = true;

	[manager addCookie: cookie3 forIRI: IRI2];


	OTAssertEqualObjects([manager cookiesForIRI: IRI2],
	    [OFArray arrayWithObject: cookie3]);
	OTAssertEqualObjects([manager cookiesForIRI: IRI1], [OFArray array]);

	cookie3.expires = [OFDate dateWithTimeIntervalSinceNow: -1];
	cookie4 = [OFHTTPCookie cookieWithName: @"test"
					 value: @"4"
					domain: @"nil.im"];
	cookie4.domain = @".nil.im";

	[manager addCookie: cookie4 forIRI: IRI2];


	OTAssertEqualObjects([manager cookiesForIRI: IRI2],
	    [OFArray arrayWithObject: cookie4]);
	OTAssertEqualObjects([manager cookiesForIRI: IRI3],
	    [OFArray arrayWithObject: cookie4]);

	cookie5 = [OFHTTPCookie cookieWithName: @"bar"
					 value: @"5"
					domain: @"test.nil.im"];

	[manager addCookie: cookie5 forIRI: IRI1];


	OTAssertEqualObjects([manager cookiesForIRI: IRI1],
	    [OFArray arrayWithObject: cookie4]);
	OTAssertEqualObjects([manager cookiesForIRI: IRI3],
	    ([OFArray arrayWithObjects: cookie4, cookie5, nil]));


	OTAssertEqualObjects(manager.cookies,
	    ([OFArray arrayWithObjects: cookie3, cookie4, cookie5, nil]));
	[manager purgeExpiredCookies];
	OTAssertEqualObjects(manager.cookies,
	    ([OFArray arrayWithObjects: cookie4, cookie5, nil]));


}
@end

Modified tests/OFHTTPCookieTests.m from [eb0c618283] to [ef1c0d2e2f].

11
12
13
14
15
16
17
18

19
20

21
22
23
24
25
26
27
28
29

30
31
32
33
34
35
36


37
38
39
40
41
42
43
44
45


46
47
48
49
50
51
52
53
54
55
56
57
58
59
60


61
62





63


64
65

66








67

68
69
70
71
72
73
 * 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 = @"OFHTTPCookie";


@implementation TestsAppDelegate (OFHTTPCookieTests)
- (void)HTTPCookieTests
{
	void *pool = objc_autoreleasePoolPush();
	OFIRI *IRI = [OFIRI IRIWithString: @"http://nil.im"];
	OFHTTPCookie *cookie1, *cookie2;
	OFArray OF_GENERIC(OFHTTPCookie *) *cookies;


	cookie1 = [OFHTTPCookie cookieWithName: @"foo"
					 value: @"bar"
					domain: @"nil.im"];
	TEST(@"+[cookiesWithResponseHeaderFields:forIRI:] #1",
	    [[OFHTTPCookie cookiesWithResponseHeaderFields: [OFDictionary
	    dictionaryWithObject: @"foo=bar"
	    forKey: @"Set-Cookie"] forIRI: IRI]


	    isEqual: [OFArray arrayWithObject: cookie1]])

	cookie2 = [OFHTTPCookie cookieWithName: @"qux"
					 value: @"cookie"
					domain: @"nil.im"];
	TEST(@"+[cookiesWithResponseHeaderFields:forIRI:] #2",
	    [[OFHTTPCookie cookiesWithResponseHeaderFields: [OFDictionary
	    dictionaryWithObject: @"foo=bar,qux=cookie"
	    forKey: @"Set-Cookie"] forIRI: IRI]


	    isEqual: [OFArray arrayWithObjects: cookie1, cookie2, nil]])

	cookie1.expires = [OFDate dateWithTimeIntervalSince1970: 1234567890];
	cookie2.expires = [OFDate dateWithTimeIntervalSince1970: 1234567890];
	cookie1.path = @"/x";
	cookie2.domain = @"webkeks.org";
	cookie2.path = @"/objfw";
	cookie2.secure = true;
	cookie2.HTTPOnly = true;
	[cookie2.extensions addObject: @"foo"];
	[cookie2.extensions addObject: @"bar"];
	TEST(@"+[cookiesWithResponseHeaderFields:forIRI:] #3",
	    [(cookies = [OFHTTPCookie cookiesWithResponseHeaderFields:
	    [OFDictionary dictionaryWithObject:
	    @"foo=bar; Expires=Fri, 13 Feb 2009 23:31:30 GMT; Path=/x,"


	    @"qux=cookie; Expires=Fri, 13 Feb 2009 23:31:30 GMT; "
	    @"Domain=webkeks.org; Path=/objfw; Secure; HTTPOnly; foo; bar"





	    forKey: @"Set-Cookie"] forIRI: IRI]) isEqual:


	    [OFArray arrayWithObjects: cookie1, cookie2, nil]])


	TEST(@"+[requestHeaderFieldsWithCookies:]",








	    [[OFHTTPCookie requestHeaderFieldsWithCookies: cookies] isEqual:

	    [OFDictionary dictionaryWithObject: @"foo=bar; qux=cookie"
					forKey: @"Cookie"]])

	objc_autoreleasePoolPop(pool);
}
@end







|
>

|
>

|
|

<

|
<
|
>
|
|
|
|
|
|
|
>
>
|

<
<
<
<
<
|
|
>
>
|










|
|
|
|
>
>
|
|
>
>
>
>
>
|
>
>
|
|
>
|
>
>
>
>
>
>
>
>
|
>

|
<
<


11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

27
28

29
30
31
32
33
34
35
36
37
38
39
40
41





42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88


89
90
 * 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 OFHTTPCookieTests: OTTestCase
@end

@implementation OFHTTPCookieTests
- (void)testCookiesWithResponseHeaderFieldsForIRI
{

	OFIRI *IRI = [OFIRI IRIWithString: @"http://nil.im"];
	OFHTTPCookie *cookie1 = [OFHTTPCookie cookieWithName: @"foo"

						       value: @"bar"
						      domain: @"nil.im"];
	OFHTTPCookie *cookie2 = [OFHTTPCookie cookieWithName: @"qux"
						       value: @"cookie"
						      domain: @"nil.im"];
	OFDictionary *headers;

	headers = [OFDictionary dictionaryWithObject: @"foo=bar"
					      forKey: @"Set-Cookie"];
	OTAssertEqualObjects(
	    [OFHTTPCookie cookiesWithResponseHeaderFields: headers forIRI: IRI],
	    [OFArray arrayWithObject: cookie1]);






	headers = [OFDictionary dictionaryWithObject: @"foo=bar,qux=cookie"
					      forKey: @"Set-Cookie"];
	OTAssertEqualObjects(
	    [OFHTTPCookie cookiesWithResponseHeaderFields: headers forIRI: IRI],
	    ([OFArray arrayWithObjects: cookie1, cookie2, nil]));

	cookie1.expires = [OFDate dateWithTimeIntervalSince1970: 1234567890];
	cookie2.expires = [OFDate dateWithTimeIntervalSince1970: 1234567890];
	cookie1.path = @"/x";
	cookie2.domain = @"webkeks.org";
	cookie2.path = @"/objfw";
	cookie2.secure = true;
	cookie2.HTTPOnly = true;
	[cookie2.extensions addObject: @"foo"];
	[cookie2.extensions addObject: @"bar"];

	headers = [OFDictionary
	    dictionaryWithObject: @"foo=bar; "
				  @"Expires=Fri, 13 Feb 2009 23:31:30 GMT; "
				  @"Path=/x,"
				  @"qux=cookie; "
				  @"Expires=Fri, 13 Feb 2009 23:31:30 GMT; "
				  @"Domain=webkeks.org; "
				  @"Path=/objfw; "
				  @"Secure; "
				  @"HTTPOnly; "
				  @"foo; "
				  @"bar"
			  forKey: @"Set-Cookie"];
	OTAssertEqualObjects(
	    [OFHTTPCookie cookiesWithResponseHeaderFields: headers forIRI: IRI],
	    ([OFArray arrayWithObjects: cookie1, cookie2, nil]));
}

- (void)testRequestHeaderFieldsWithCookies
{
	OFHTTPCookie *cookie1 = [OFHTTPCookie cookieWithName: @"foo"
						       value: @"bar"
						      domain: @"nil.im"];
	OFHTTPCookie *cookie2 = [OFHTTPCookie cookieWithName: @"qux"
						       value: @"cookie"
						      domain: @"nil.im"];

	OTAssertEqualObjects([OFHTTPCookie requestHeaderFieldsWithCookies:
	    ([OFArray arrayWithObjects: cookie1, cookie2, nil])],
	    [OFDictionary dictionaryWithObject: @"foo=bar; qux=cookie"
					forKey: @"Cookie"]);


}
@end

Added tests/OFINIFileTests.m version [878892df10].























































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
/*
 * Copyright (c) 2008-2024 Jonathan Schleifer <js@nil.im>
 *
 * 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

Modified tests/OFIPXSocketTests.m from [0ae4e44d89] to [1646dd280e].

12
13
14
15
16
17
18

19
20

21
22

23
24
25
26

27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
 * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
 * file.
 */

#include "config.h"

#include <errno.h>


#import "TestsAppDelegate.h"


static OFString *const module = @"OFIPXSocket";


@implementation TestsAppDelegate (OFIPXSocketTests)
- (void)IPXSocketTests
{

	const unsigned char zeroNode[IPX_NODE_LEN] = { 0 };
	void *pool = objc_autoreleasePoolPush();
	OFIPXSocket *sock;
	OFSocketAddress address1, address2;
	OFDictionary *networkInterfaces;
	char buffer[5];
	unsigned char node1[IPX_NODE_LEN], node2[IPX_NODE_LEN];
	unsigned char node[IPX_NODE_LEN];

	TEST(@"+[socket]", (sock = [OFIPXSocket socket]))

	@try {
		TEST(@"-[bindToNetwork:node:port:packetType:]",
		R(address1 = [sock bindToNetwork: 0
					    node: zeroNode
					    port: 0
				      packetType: 0]))
	} @catch (OFBindSocketFailedException *e) {
		switch (e.errNo) {
		case EAFNOSUPPORT:
			[OFStdOut setForegroundColor: [OFColor lime]];
			[OFStdOut writeLine:
			    @"\r[OFIPXSocket] -[bindToNetwork:node:port:"
			    @"packetType:]: IPX unsupported, skipping tests"];
			break;
		case EADDRNOTAVAIL:
			[OFStdOut setForegroundColor: [OFColor lime]];
			[OFStdOut writeLine:
			    @"\r[OFIPXSocket] -[bindToNetwork:node:port:"
			    @"packetType:]: IPX not configured, skipping "
			    @"tests"];
			break;
		default:
			@throw e;
		}

		objc_autoreleasePoolPop(pool);
		return;
	}

	/*
	 * Find any network interface with IPX and send to it. Any should be
	 * fine since we bound to 0.0.
	 */
	networkInterfaces = [OFSystemInfo networkInterfaces];







>

|
>

|
>

|
|

>

<
<






<
<

<
|
|
|
|



<
<
<
|
<

<
<
<
|
<
<



<
<
<







12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31


32
33
34
35
36
37


38

39
40
41
42
43
44
45



46

47



48


49
50
51



52
53
54
55
56
57
58
 * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
 * file.
 */

#include "config.h"

#include <errno.h>
#include <string.h>

#import "ObjFW.h"
#import "ObjFWTest.h"

@interface OFIPXSocketTests: OTTestCase
@end

@implementation OFIPXSocketTests
- (void)testIPXSocket
{
	OFIPXSocket *sock = [OFIPXSocket socket];
	const unsigned char zeroNode[IPX_NODE_LEN] = { 0 };


	OFSocketAddress address1, address2;
	OFDictionary *networkInterfaces;
	char buffer[5];
	unsigned char node1[IPX_NODE_LEN], node2[IPX_NODE_LEN];
	unsigned char node[IPX_NODE_LEN];



	@try {

		address1 = [sock bindToNetwork: 0
					  node: zeroNode
					  port: 0
				    packetType: 0];
	} @catch (OFBindSocketFailedException *e) {
		switch (e.errNo) {
		case EAFNOSUPPORT:



			OTSkip(@"IPX unsupported");

		case EADDRNOTAVAIL:



			OTSkip(@"IPX not configured");


		default:
			@throw e;
		}



	}

	/*
	 * Find any network interface with IPX and send to it. Any should be
	 * fine since we bound to 0.0.
	 */
	networkInterfaces = [OFSystemInfo networkInterfaces];
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101

102
103
104
105
106
107
108
109
110
111
112
		    OFSocketAddressIPXNetwork([addresses itemAtIndex: 0]));
		OFSocketAddressGetIPXNode([addresses itemAtIndex: 0], node);
		OFSocketAddressSetIPXNode(&address1, node);
	}

	OFSocketAddressGetIPXNode(&address1, node);
	if (OFSocketAddressIPXNetwork(&address1) == 0 &&
	    memcmp(node, zeroNode, 6) == 0) {
		[OFStdOut setForegroundColor: [OFColor lime]];
		[OFStdOut writeLine:
		    @"[OFIPXSocket] -[sendBuffer:length:receiver:]: "
		    @"Could not determine own address, skipping tests"];
		objc_autoreleasePoolPop(pool);
		return;
	}

	TEST(@"-[sendBuffer:length:receiver:]",
	    R([sock sendBuffer: "Hello" length: 5 receiver: &address1]))

	TEST(@"-[receiveIntoBuffer:length:sender:]",

	    [sock receiveIntoBuffer: buffer length: 5 sender: &address2] == 5 &&
	    memcmp(buffer, "Hello", 5) == 0 &&
	    R(OFSocketAddressGetIPXNode(&address1, node1)) &&
	    R(OFSocketAddressGetIPXNode(&address2, node2)) &&
	    memcmp(node1, node2, IPX_NODE_LEN) == 0 &&
	    OFSocketAddressIPXPort(&address1) ==
	    OFSocketAddressIPXPort(&address2))

	objc_autoreleasePoolPop(pool);
}
@end







|
<
<
<
|
<
<
|
<
<
|

|
>
|
|
|
|
|
|
|
|
<
<

69
70
71
72
73
74
75
76



77


78


79
80
81
82
83
84
85
86
87
88
89
90


91
		    OFSocketAddressIPXNetwork([addresses itemAtIndex: 0]));
		OFSocketAddressGetIPXNode([addresses itemAtIndex: 0], node);
		OFSocketAddressSetIPXNode(&address1, node);
	}

	OFSocketAddressGetIPXNode(&address1, node);
	if (OFSocketAddressIPXNetwork(&address1) == 0 &&
	    memcmp(node, zeroNode, 6) == 0)



		OTSkip(@"Could not determine own IPX address");





	[sock sendBuffer: "Hello" length: 5 receiver: &address1];

	OTAssertEqual([sock receiveIntoBuffer: buffer
				       length: 5
				       sender: &address2], 5);
	OTAssertEqual(memcmp(buffer, "Hello", 5), 0);
	OFSocketAddressGetIPXNode(&address1, node1);
	OFSocketAddressGetIPXNode(&address2, node2);
	OTAssertEqual(memcmp(node1, node2, IPX_NODE_LEN), 0);
	OTAssertEqual(OFSocketAddressIPXPort(&address1),
	    OFSocketAddressIPXPort(&address2));
}


@end

Renamed and modified new_tests/OFIRITests.m [f4eb7c532e] to tests/OFIRITests.m [55f0cf3dc6].

313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
	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]);







|







313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
	OTAssertNil(_IRI[3].fragment);
	OTAssertEqualObjects(_IRI[8].fragment, @"frag");
	OTAssertEqualObjects(_IRI[9].fragment, @"frag");
}

- (void)testCopy
{
	OTAssertEqualObjects([[_IRI[0] copy] autorelease], _IRI[0]);
}

- (void)testIsEqual
{
	OTAssertEqualObjects(_IRI[0], [OFIRI IRIWithString: IRI0String]);
	OTAssertNotEqualObjects(_IRI[1], _IRI[2]);
	OTAssertEqualObjects([OFIRI IRIWithString: @"HTTP://bar/"], _IRI[2]);

Added tests/OFInvocationTests.m version [11b71f5c4f].





























































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
/*
 * Copyright (c) 2008-2024 Jonathan Schleifer <js@nil.im>
 *
 * 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 <string.h>

#if defined(HAVE_COMPLEX_H) && !defined(__STDC_NO_COMPLEX__)
# include <complex.h>
#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 tests/OFJSONTests.m version [2e899d37b6].





























































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
/*
 * Copyright (c) 2008-2024 Jonathan Schleifer <js@nil.im>
 *
 * 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
{
	OFDictionary *_dictionary;
}
@end

static OFString *string = @"{\"foo\"\t:'b\\na\\r', \"x\":/*foo*/ [.5\r,0xF,"
    @"null//bar\n,\"foo\",false]}";

@implementation OFJSONTests
- (void)setUp
{
	[super setUp];

	_dictionary = [[OTOrderedDictionary alloc] initWithKeysAndObjects:
	    @"foo", @"b\na\r",
	    @"x", [OFArray arrayWithObjects:
		[OFNumber numberWithFloat: .5f],
		[OFNumber numberWithInt: 0xF],
		[OFNull null],
		@"foo",
		[OFNumber numberWithBool: false],
		nil],
	    nil];
}

- (void)dealloc
{
	[_dictionary release];

	[super dealloc];
}

- (void)testObjectByParsingJSON
{
	OTAssertEqualObjects(string.objectByParsingJSON, _dictionary);
}

- (void)testJSONRepresentation
{
	OTAssert(_dictionary.JSONRepresentation,
	    @"{\"foo\":\"b\\na\\r\",\"x\":[0.5,15,null,\"foo\",false]}");
}

- (void)testPrettyJSONRepresentation
{
	OTAssertEqualObjects([_dictionary JSONRepresentationWithOptions:
	    OFJSONRepresentationOptionPretty],
	    @"{\n\t\"foo\": \"b\\na\\r\",\n\t\"x\": [\n\t\t0.5,\n\t\t15,"
	    @"\n\t\tnull,\n\t\t\"foo\",\n\t\tfalse\n\t]\n}");
}

- (void)testJSON5Representation
{
	OTAssertEqualObjects([_dictionary JSONRepresentationWithOptions:
	    OFJSONRepresentationOptionJSON5],
	    @"{foo:\"b\\\na\\r\",x:[0.5,15,null,\"foo\",false]}");
}

- (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

Modified tests/OFKernelEventObserverTests.m from [fd27260531] to [2177e01800].

11
12
13
14
15
16
17



18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42

43
44
45
46
47
48
49
50
51
52

53
54
55
56
57
58

59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88

89
90
91

92
93

94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152

153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187

188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223

224
225
226
227


228

229
230
231
232


233
234
235

236
 * 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"




#ifdef HAVE_KQUEUE
# import "OFKqueueKernelEventObserver.h"
#endif
#ifdef HAVE_EPOLL
# import "OFEpollKernelEventObserver.h"
#endif
#ifdef HAVE_POLL
# import "OFPollKernelEventObserver.h"
#endif
#ifdef HAVE_SELECT
# import "OFSelectKernelEventObserver.h"
#endif

#import "TestsAppDelegate.h"

static const size_t numExpectedEvents = 3;

static OFString *module;

@interface ObserverTest: OFObject <OFKernelEventObserverDelegate>
{
@public
	TestsAppDelegate *_testsAppDelegate;
	OFKernelEventObserver *_observer;
	OFTCPSocket *_server, *_client, *_accepted;

	size_t _events;
	int _fails;
}

- (void)run;
@end

@implementation ObserverTest
- (instancetype)initWithTestsAppDelegate: (TestsAppDelegate *)testsAppDelegate
{

	self = [super init];

	@try {
		OFSocketAddress address;

		_testsAppDelegate = testsAppDelegate;


		_server = [[OFTCPSocket alloc] init];
		address = [_server bindToHost: @"127.0.0.1" port: 0];
		[_server listen];

		_client = [[OFTCPSocket alloc] init];
		[_client connectToHost: @"127.0.0.1"
				  port: OFSocketAddressIPPort(&address)];
		[_client writeBuffer: "0" length: 1];
	} @catch (id e) {
		[self release];
		@throw e;
	}

	return self;
}

- (void)dealloc
{
	[_server release];
	[_client release];
	[_accepted release];

	[super dealloc];
}

- (void)run
{
	OFDate *deadline;
	bool deadlineExceeded = false;


	[_testsAppDelegate outputTesting: @"-[observe] with listening socket"
				inModule: module];


	deadline = [OFDate dateWithTimeIntervalSinceNow: 1];

	while (_events < numExpectedEvents) {
		if (deadline.timeIntervalSinceNow < 0) {
			deadlineExceeded = true;
			break;
		}

		[_observer observeForTimeInterval: 0.01];
	}

	if (!deadlineExceeded)
		[_testsAppDelegate
		    outputSuccess: @"-[observe] not exceeding deadline"
			 inModule: module];
	else {
		[_testsAppDelegate
		    outputFailure: @"-[observe] not exceeding deadline"
			 inModule: module];
		_fails++;
	}

	if (_events == numExpectedEvents)
		[_testsAppDelegate
		    outputSuccess: @"-[observe] handling all events"
			 inModule: module];
	else {
		[_testsAppDelegate
		    outputFailure: @"-[observe] handling all events"
			 inModule: module];
		_fails++;
	}
}

- (void)objectIsReadyForReading: (id)object
{
	char buffer;

	switch (_events++) {
	case 0:
		if (object == _server)
			[_testsAppDelegate
			    outputSuccess: @"-[observe] with listening socket"
				 inModule: module];
		else {
			[_testsAppDelegate
			    outputFailure: @"-[observe] with listening socket"
				 inModule: module];
			_fails++;
		}

		_accepted = [[object accept] retain];
		[_observer addObjectForReading: _accepted];

		[_testsAppDelegate
		    outputTesting: @"-[observe] with data ready to read"
			 inModule: module];

		break;
	case 1:
		if (object == _accepted &&

		    [object readIntoBuffer: &buffer length: 1] == 1 &&
		    buffer == '0')
			[_testsAppDelegate
			    outputSuccess: @"-[observe] with data ready to read"
				 inModule: module];
		else {
			[_testsAppDelegate
			    outputFailure: @"-[observe] with data ready to read"
				 inModule: module];
			_fails++;
		}

		[_client close];

		[_testsAppDelegate
		    outputTesting: @"-[observe] with closed connection"
			 inModule: module];

		break;
	case 2:
		if (object == _accepted &&
		    [object readIntoBuffer: &buffer length: 1] == 0)
			[_testsAppDelegate
			    outputSuccess: @"-[observe] with closed connection"
				 inModule: module];
		else {
			[_testsAppDelegate
			    outputFailure: @"-[observe] with closed connection"
				 inModule: module];
			_fails++;
		}

		break;
	default:
		OFEnsure(0);

	}
}
@end

@implementation TestsAppDelegate (OFKernelEventObserverTests)
- (void)kernelEventObserverTestsWithClass: (Class)class
{
	void *pool = objc_autoreleasePoolPush();
	ObserverTest *test;

	module = [class className];
	test = [[[ObserverTest alloc]
	    initWithTestsAppDelegate: self] autorelease];

	TEST(@"+[observer]", (test->_observer = [class observer]))
	test->_observer.delegate = test;

	TEST(@"-[addObjectForReading:]",
	    R([test->_observer addObjectForReading: test->_server]))

	[test run];
	_fails += test->_fails;

	objc_autoreleasePoolPop(pool);
}

- (void)kernelEventObserverTests
{
#ifdef HAVE_SELECT
	[self kernelEventObserverTestsWithClass:
	    [OFSelectKernelEventObserver class]];
#endif

#ifdef HAVE_POLL
	[self kernelEventObserverTestsWithClass:
	    [OFPollKernelEventObserver class]];

#endif

#ifdef HAVE_EPOLL
	[self kernelEventObserverTestsWithClass:


	    [OFEpollKernelEventObserver class]];

#endif

#ifdef HAVE_KQUEUE
	[self kernelEventObserverTestsWithClass:


	    [OFKqueueKernelEventObserver class]];
#endif
}

@end







>
>
>













<
|
<
<
<
<
|

<
<
<

>

<

<
<


|
<
|
>
|
|
<
|

<
>

|
|
|

|
|
|
|
<
<
<
<
<
<




|
|





|

<

>

|
|
>


>









|
<
<
<
<
<
<
<
<
<
<
|
<
<
<
<
<
<
<
<
<








|
<
<
<
<
<
<
<
<
<



<
<
<
<
<


|
>
|
|
<
<
<
<
<
<
<
<
|
<

<
<
<
<
<


|
<
<
<
<
<
<
<
<
<
|
|


<
>


<

<
<
<
<
<
|
<
<
<
|
<
<
|
<
<
|
<
<
|
<

|
<
|
|
<
|
<
|
<
|

>



|
>
>

>



|
>
>

<

>

11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

34




35
36



37
38
39

40


41
42
43

44
45
46
47

48
49

50
51
52
53
54
55
56
57
58
59






60
61
62
63
64
65
66
67
68
69
70
71
72

73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91










92









93
94
95
96
97
98
99
100
101









102
103
104





105
106
107
108
109
110








111

112





113
114
115









116
117
118
119

120
121
122

123





124



125


126


127


128

129
130

131
132

133

134

135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152

153
154
155
 * 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"

#ifdef HAVE_KQUEUE
# import "OFKqueueKernelEventObserver.h"
#endif
#ifdef HAVE_EPOLL
# import "OFEpollKernelEventObserver.h"
#endif
#ifdef HAVE_POLL
# import "OFPollKernelEventObserver.h"
#endif
#ifdef HAVE_SELECT
# import "OFSelectKernelEventObserver.h"
#endif


@interface OFKernelEventObserverTests: OTTestCase




    <OFKernelEventObserverDelegate>
{



	OFTCPSocket *_server, *_client, *_accepted;
	OFKernelEventObserver *_observer;
	size_t _events;

}


@end

static const size_t numExpectedEvents = 3;


@implementation OFKernelEventObserverTests
- (void)setUp
{

	OFSocketAddress address;


	[super setUp];

	_server = [[OFTCPSocket alloc] init];
	address = [_server bindToHost: @"127.0.0.1" port: 0];
	[_server listen];

	_client = [[OFTCPSocket alloc] init];
	[_client connectToHost: @"127.0.0.1"
			  port: OFSocketAddressIPPort(&address)];
	[_client writeBuffer: "0" length: 1];






}

- (void)dealloc
{
	[_client release];
	[_server release];
	[_accepted release];

	[super dealloc];
}

- (void)testKernelEventObserverWithClass: (Class)class
{

	bool deadlineExceeded = false;
	OFDate *deadline;

	_observer = [[class alloc] init];
	_observer.delegate = self;
	[_observer addObjectForReading: _server];

	deadline = [OFDate dateWithTimeIntervalSinceNow: 1];

	while (_events < numExpectedEvents) {
		if (deadline.timeIntervalSinceNow < 0) {
			deadlineExceeded = true;
			break;
		}

		[_observer observeForTimeInterval: 0.01];
	}

	OTAssertFalse(deadlineExceeded);










	OTAssertEqual(_events, numExpectedEvents);









}

- (void)objectIsReadyForReading: (id)object
{
	char buffer;

	switch (_events++) {
	case 0:
		OTAssertEqual(object, _server);










		_accepted = [[object accept] retain];
		[_observer addObjectForReading: _accepted];





		break;
	case 1:
		OTAssert(object, _accepted);

		OTAssertEqual([object readIntoBuffer: &buffer length: 1], 1);
		OTAssertEqual(buffer, '0');










		[_client close];





		break;
	case 2:
		OTAssertEqual(object,  _accepted);










		OTAssertEqual([object readIntoBuffer: &buffer length: 1], 0);
		break;
	default:

		OTAssert(false);
	}
}







#ifdef HAVE_SELECT



- (void)testSelectKernelEventObserver


{


	[self testKernelEventObserverWithClass:


	    [OFSelectKernelEventObserver class]];

}
#endif


#ifdef HAVE_POLL

- (void)testPollKernelEventObserver

{

	[self testKernelEventObserverWithClass:
	    [OFPollKernelEventObserver class]];
}
#endif

#ifdef HAVE_EPOLL
- (void)testEpollKernelEventObserver
{
	[self testKernelEventObserverWithClass:
	    [OFEpollKernelEventObserver class]];
}
#endif

#ifdef HAVE_KQUEUE
- (void)testKqueueKernelEventObserver
{
	[self testKernelEventObserverWithClass:
	    [OFKqueueKernelEventObserver class]];

}
#endif
@end

Modified tests/OFListTests.m from [39ffbcd436] to [48a2f18d5f].

11
12
13
14
15
16
17
18

19





20




21

22
23
24

25

26

27



28



29
30
31
32

33
34
35
36


37
38

39


40


41


42

43

44
45
46
47

48

49
50



51

52









53


54

55

56
57

58
59
60
61
62
63

64
65
66
67
68
69

70
71

72


73


74


75


76



77



78
79
80
81

82


83


84


85
86
87

88

89
90

91
92



93



94
95

96
97
98



99

100

101


102

103
104
105



106

107
108
109

110
111

112
113
114
115


116
117
118

119
120
121





122

123

124
125
126



127



128


129










130
131
132
133
134
135

136
137

138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
 * 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 = @"OFList";




static OFString *strings[] = {

	@"Foo",
	@"Bar",
	@"Baz"

};



@implementation TestsAppDelegate (OFListTests)



- (void)listTests



{
	void *pool = objc_autoreleasePoolPush();
	OFList *list;
	OFEnumerator *enumerator;

	OFListItem iter;
	OFString *object;
	size_t i;
	bool ok;



	TEST(@"+[list]", (list = [OFList list]))




	TEST(@"-[appendObject:]", [list appendObject: strings[0]] &&


	    [list appendObject: strings[1]] && [list appendObject: strings[2]])




	TEST(@"-[firstListItem]",

	    [OFListItemObject(list.firstListItem) isEqual: strings[0]])

	TEST(@"OFListItemNext()",
	    [OFListItemObject(OFListItemNext(list.firstListItem))

	    isEqual: strings[1]])


	TEST(@"-[lastListItem]",



	    [OFListItemObject(list.lastListItem) isEqual: strings[2]])











	TEST(@"OFListItemPrevious()",


	    [OFListItemObject(OFListItemPrevious(list.lastListItem))

	    isEqual: strings[1]])


	TEST(@"-[removeListItem:]",

	    R([list removeListItem: list.lastListItem]) &&
	    [list.lastObject isEqual: strings[1]] &&
	    R([list removeListItem: list.firstListItem]) &&
	    [list.firstObject isEqual: list.lastObject])

	TEST(@"-[insertObject:beforeListItem:]",

	    [list insertObject: strings[0] beforeListItem: list.lastListItem] &&
	    [OFListItemObject(OFListItemPrevious(list.lastListItem))
	    isEqual: strings[0]])

	TEST(@"-[insertObject:afterListItem:]",
	    [list insertObject: strings[2]

		 afterListItem: OFListItemNext(list.firstListItem)] &&
	    [list.lastObject isEqual: strings[2]])




	TEST(@"-[count]", list.count == 3)





	TEST(@"-[containsObject:]",


	    [list containsObject: strings[1]] &&



	    ![list containsObject: @"nonexistent"])




	TEST(@"-[containsObjectIdenticalTo:]",
	    [list containsObjectIdenticalTo: strings[1]] &&
	    ![list containsObjectIdenticalTo:

	    [OFString stringWithString: strings[1]]])





	TEST(@"-[copy]", (list = [[list copy] autorelease]) &&


	    [list.firstObject isEqual: strings[0]] &&
	    [OFListItemObject(OFListItemNext(list.firstListItem))
	    isEqual: strings[1]] &&

	    [list.lastObject isEqual: strings[2]])


	TEST(@"-[isEqual:]", [list isEqual: [[list copy] autorelease]])


	TEST(@"-[description]",



	    [list.description isEqual: @"[\n\tFoo,\n\tBar,\n\tBaz\n]"])




	TEST(@"-[objectEnumerator]", (enumerator = [list objectEnumerator]))


	iter = list.firstListItem;
	i = 0;



	ok = true;

	while ((object = [enumerator nextObject]) != nil) {

		if (![object isEqual: OFListItemObject(iter)])


			ok = false;


		iter = OFListItemNext(iter);
		i++;



	}


	if (list.count != i)
		ok = false;


	TEST(@"OFEnumerator's -[nextObject]", ok);


	[list removeListItem: list.firstListItem];

	EXPECT_EXCEPTION(@"Detection of mutation during enumeration",


	    OFEnumerationMutationException, [enumerator nextObject])

	[list prependObject: strings[0]];


	iter = list.firstListItem;
	i = 0;





	ok = true;



	for (OFString *object_ in list) {
		if (![object_ isEqual: OFListItemObject(iter)])
			ok = false;







		iter = OFListItemNext(iter);


		i++;










	}

	if (list.count != i)
		ok = false;

	TEST(@"Fast Enumeration", ok)


	ok = false;

	@try {
		for (OFString *object_ in list) {
			(void)object_;

			[list removeListItem: list.lastListItem];
		}
	} @catch (OFEnumerationMutationException *e) {
		ok = true;
	}

	TEST(@"Detection of mutation during Fast Enumeration", ok)

	objc_autoreleasePoolPop(pool);
}
@end







|
>

>
>
>
>
>
|
>
>
>
>
|
>
|
|
|
>
|
>
|
>
|
>
>
>
|
>
>
>
|
|
<
<
>
|
|
|
|
>
>

|
>

>
>
|
>
>
|
>
>
|
>
|
>
|
|
|
|
>
|
>

|
>
>
>
|
>
|
>
>
>
>
>
>
>
>
>
|
>
>
|
>
|
>
|
|
>
|
|
|
|

|
>
|
|
|
|
|
|
>
|
|
>

>
>
|
>
>

>
>
|
>
>
|
>
>
>
|
>
>
>

|
|
|
>
|
>
>

>
>
|
>
>
|
|
|
>
|
>
|
|
>
|
|
>
>
>
|
>
>
>
|
|
>
|
|
|
>
>
>
|
>
|
>
|
>
>
|
>
|
|
|
>
>
>
|
>

|
|
>
|
|
>
|
|
|
|
>
>
|
|
|
>
|
|
|
>
>
>
>
>
|
>
|
>
|
|
|
>
>
>

>
>
>
|
>
>
|
>
>
>
>
>
>
>
>
>
>
|
|
|
|
|
|
>
|
|
>

|
|
<
|


|


<
|
<


11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50


51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268

269
270
271
272
273
274

275

276
277
 * 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 OFListTests: OTTestCase
{
	OFList *_list;
}
@end

@implementation OFListTests
- (void)setUp
{
	[super setUp];

	_list = [[OFList alloc] init];
	[_list appendObject: @"Foo"];
	[_list appendObject: @"Bar"];
	[_list appendObject: @"Baz"];
}

- (void)dealloc
{
	[_list release];

	[super dealloc];
}

- (void)testCount
{
	OTAssertEqual(_list.count, 3);
}

- (void)testAppendObject


{
	OFListItem item;

	[_list appendObject: @"Qux"];

	item = _list.firstListItem;
	OTAssertEqualObjects(OFListItemObject(item), @"Foo");

	item = OFListItemNext(item);
	OTAssertEqualObjects(OFListItemObject(item), @"Bar");

	item = OFListItemNext(item);
	OTAssertEqualObjects(OFListItemObject(item), @"Baz");

	item = OFListItemNext(item);
	OTAssertEqualObjects(OFListItemObject(item), @"Qux");

	item = OFListItemNext(item);
	OTAssertEqual(item, NULL);
}

- (void)testFirstListItem
{
	OTAssertEqualObjects(OFListItemObject(_list.firstListItem), @"Foo");
}

- (void)testFirstObject
{
	OTAssertEqualObjects(_list.firstObject, @"Foo");
}

- (void)testLastListItem
{
	OTAssertEqualObjects(OFListItemObject(_list.lastListItem), @"Baz");
}

- (void)testLastObject
{
	OTAssertEqualObjects(_list.lastObject, @"Baz");
}

- (void)testListItemNext
{
	OTAssertEqualObjects(
	    OFListItemObject(OFListItemNext(_list.firstListItem)), @"Bar");
}

- (void)testListItemPrevious
{
	OTAssertEqualObjects(
	    OFListItemObject(OFListItemPrevious(_list.lastListItem)), @"Bar");
}

- (void)testRemoveListItem
{
	OFListItem item;

	[_list removeListItem: OFListItemNext(_list.firstListItem)];

	item = _list.firstListItem;
	OTAssertEqualObjects(OFListItemObject(item), @"Foo");

	item = OFListItemNext(item);
	OTAssertEqualObjects(OFListItemObject(item), @"Baz");

	item = OFListItemNext(item);
	OTAssertEqual(item, NULL);
}

- (void)testInsertObjectBeforeListItem
{
	OFListItem item;

	[_list insertObject: @"Qux" beforeListItem: _list.lastListItem];

	item = _list.firstListItem;
	OTAssertEqualObjects(OFListItemObject(item), @"Foo");

	item = OFListItemNext(item);
	OTAssertEqualObjects(OFListItemObject(item), @"Bar");

	item = OFListItemNext(item);
	OTAssertEqualObjects(OFListItemObject(item), @"Qux");

	item = OFListItemNext(item);
	OTAssertEqualObjects(OFListItemObject(item), @"Baz");

	item = OFListItemNext(item);
	OTAssertEqual(item, NULL);
}

- (void)testInsertObjectAfterListItem
{
	OFListItem item;

	[_list insertObject: @"Qux" afterListItem: _list.firstListItem];

	item = _list.firstListItem;
	OTAssertEqualObjects(OFListItemObject(item), @"Foo");

	item = OFListItemNext(item);
	OTAssertEqualObjects(OFListItemObject(item), @"Qux");

	item = OFListItemNext(item);
	OTAssertEqualObjects(OFListItemObject(item), @"Bar");

	item = OFListItemNext(item);
	OTAssertEqualObjects(OFListItemObject(item), @"Baz");

	item = OFListItemNext(item);
	OTAssertEqual(item, NULL);
}

- (void)testContainsObject
{
	OTAssertTrue([_list containsObject: @"Foo"]);
	OTAssertFalse([_list containsObject: @"Qux"]);
}

- (void)testContainsObjectIdenticalTo
{
	OFString *foo = _list.firstObject;

	OTAssertTrue([_list containsObjectIdenticalTo: foo]);
	OTAssertFalse(
	    [_list containsObjectIdenticalTo: [[foo mutableCopy] autorelease]]);
}

- (void)testIsEqual
{
	OFList *list = [OFList list];

	[list appendObject: @"Foo"];
	[list appendObject: @"Bar"];
	[list appendObject: @"Baz"];

	OTAssertEqualObjects(list, _list);

	[list appendObject: @"Qux"];

	OTAssertNotEqualObjects(list, _list);
}

- (void)testHash
{
	OFList *list = [OFList list];

	[list appendObject: @"Foo"];
	[list appendObject: @"Bar"];
	[list appendObject: @"Baz"];

	OTAssertEqual(list.hash, _list.hash);

	[list appendObject: @"Qux"];

	OTAssertNotEqual(list.hash, _list.hash);
}

- (void)testCopy
{
	OTAssertEqualObjects([[_list copy] autorelease], _list);
}

- (void)testDescription
{
	OTAssertEqualObjects(_list.description, @"[\n\tFoo,\n\tBar,\n\tBaz\n]");
}

- (void)testEnumerator
{
	OFEnumerator *enumerator = [_list objectEnumerator];

	OTAssertEqualObjects([enumerator nextObject], @"Foo");
	OTAssertEqualObjects([enumerator nextObject], @"Bar");
	OTAssertEqualObjects([enumerator nextObject], @"Baz");
	OTAssertNil([enumerator nextObject]);
}

- (void)testDetectMutationDuringEnumeration
{
	OFEnumerator *enumerator = [_list objectEnumerator];

	[_list removeListItem: _list.firstListItem];

	OTAssertThrowsSpecific([enumerator nextObject],
	    OFEnumerationMutationException);
}

- (void)testFastEnumeration
{
	size_t i = 0;

	for (OFString *object in _list) {
		OTAssertLessThan(i, 3);

		switch (i++) {
		case 0:
			OTAssertEqualObjects(object, @"Foo");
			break;
		case 1:
			OTAssertEqualObjects(object, @"Bar");
			break;
		case 2:
			OTAssertEqualObjects(object, @"Baz");
			break;
		}
	}

	OTAssertEqual(i, 3);
}

- (void)testDetectMutationDuringFastEnumeration
{
	bool detected = false;

	@try {
		for (OFString *object in _list) {
			(void)object;

			[_list removeListItem: _list.firstListItem];
		}
	} @catch (OFEnumerationMutationException *e) {
		detected = true;
	}


	OTAssertTrue(detected);

}
@end

Modified tests/OFLocaleTests.m from [bb15c236d6] to [c000e04b91].

11
12
13
14
15
16
17
18

19
20
21

22
23


24
25

26
27
28



29
30
31
32
33
34

35
36
37
38
39

40
41
 * 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"


@implementation TestsAppDelegate (OFLocaleTests)
- (void)localeTests

{
	void *pool = objc_autoreleasePoolPush();



	[OFStdOut setForegroundColor: [OFColor lime]];


	[OFStdOut writeFormat: @"[OFLocale] Language code: %@\n",
	    [OFLocale languageCode]];




	[OFStdOut writeFormat: @"[OFLocale] Country code: %@\n",
	    [OFLocale countryCode]];

	[OFStdOut writeFormat: @"[OFLocale] Encoding: %@\n",
	    OFStringEncodingName([OFLocale encoding])];


	[OFStdOut writeFormat: @"[OFLocale] Decimal separator: %@\n",
	    [OFLocale decimalSeparator]];

	objc_autoreleasePoolPop(pool);

}
@end







|
>

<
|
>
|
<
>
>
|
<
>

<
<
>
>
>

|
|
<
<
|
>

<
|

<
>


11
12
13
14
15
16
17
18
19
20

21
22
23

24
25
26

27
28


29
30
31
32
33
34


35
36
37

38
39

40
41
42
 * 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 OFLocaleTests: OTTestCase
@end


@implementation OFLocaleTests
+ (OFArray OF_GENERIC(OFPair OF_GENERIC(OFString *, id) *) *)summary
{

	OFMutableArray *summary = [OFMutableArray array];



#define ADD(name, value)						\
	[summary addObject: [OFPair pairWithFirstObject: name		\
					   secondObject: value]];

	ADD(@"Language code", [OFLocale languageCode])
	ADD(@"Country code", [OFLocale countryCode])


	ADD(@"Encoding", OFStringEncodingName([OFLocale encoding]))
	ADD(@"Decimal separator", [OFLocale decimalSeparator])


#undef ADD


	return summary;
}
@end

Renamed and modified new_tests/OFMatrix4x4Tests.m [53d6e8ba9c] to tests/OFMatrix4x4Tests.m [25395304c9].

74
75
76
77
78
79
80
81









82
83
84
85
86
87
88
89
90
91
92
		{ 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];







|
>
>
>
>
>
>
>
>
>



|







74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
		{ 1, 0, 0, 0 },
		{ 0, 1, 0, 0 },
		{ 0, 0, 1, 0 },
		{ 0, 0, 0, 1 }
	    }]));
}

- (void)testHash
{
	OTAssertEqual([[OFMatrix4x4 identityMatrix] hash],
	    [([OFMatrix4x4 matrixWithValues: (const float [4][4]){
		{ 1, 0, 0, 0 },
		{ 0, 1, 0, 0 },
		{ 0, 0, 1, 0 },
		{ 0, 0, 0, 1 }
	    }]) hash]);
}

- (void)testCopy
{
	OTAssertEqualObjects([[_matrix copy] autorelease], _matrix);
}

- (void)testMultiplyWithMatrix
{
	OFMatrix4x4 *matrix;

	matrix = [[_matrix copy] autorelease];

Modified tests/OFMemoryStreamTests.m from [8479ce3790] to [be569a5484].

11
12
13
14
15
16
17
18

19


20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52

53

54
55
56
57

58
59
60
61
62
63
64
65



66


67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
 * 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 = @"OFMemoryStream";
static const char string[] = "abcdefghijkl";

@implementation TestsAppDelegate (OFMemoryStreamTests)
- (void)memoryStreamTests
{
	void *pool = objc_autoreleasePoolPush();
	OFMemoryStream *stream;
	char buffer[10];
	OFMutableData *data;

	TEST(@"+[streamWithMemoryAddress:size:writable:]",
	    (stream = [OFMemoryStream streamWithMemoryAddress: (char *)string
							 size: sizeof(string)
						     writable: false]));


	/*
	 * Test the lowlevel methods, as otherwise OFStream will do one big
	 * read and we will not test OFMemoryStream.
	 */

	TEST(@"-[lowlevelReadIntoBuffer:length:]",
	    [stream lowlevelReadIntoBuffer: buffer length: 5] == 5 &&
	    memcmp(buffer, "abcde", 5) == 0 &&
	    [stream lowlevelReadIntoBuffer: buffer length: 3] == 3 &&
	    memcmp(buffer, "fgh", 3) == 0 &&
	    [stream lowlevelReadIntoBuffer: buffer length: 10] == 5 &&
	    memcmp(buffer, "ijkl", 5) == 0)

	TEST(@"-[lowlevelIsAtEndOfStream]", [stream lowlevelIsAtEndOfStream])

	TEST(@"-[lowlevelSeekToOffset:whence:]",
	    [stream lowlevelSeekToOffset: 0 whence: OFSeekCurrent] ==

	    sizeof(string) && [stream lowlevelIsAtEndOfStream] &&

	    [stream lowlevelSeekToOffset: 4 whence: OFSeekSet] == 4 &&
	    ![stream lowlevelIsAtEndOfStream] &&
	    [stream lowlevelReadIntoBuffer: buffer length: 10] == 9 &&
	    memcmp(buffer, "efghijkl", 9) == 0 &&

	    [stream lowlevelSeekToOffset: -2 whence: OFSeekEnd] == 11 &&
	    [stream lowlevelReadIntoBuffer: buffer length: 10] == 2 &&
	    memcmp(buffer, "l", 2) == 0 &&
	    [stream lowlevelReadIntoBuffer: buffer length: 10] == 0)

	EXPECT_EXCEPTION(@"Writes rejected on read-only stream",
	    OFWriteFailedException, [stream lowlevelWriteBuffer: "" length: 1])




	data = [OFMutableData dataWithCapacity: 13];


	[data increaseCountBy: 13];
	stream = [OFMemoryStream streamWithMemoryAddress: data.mutableItems
						    size: data.count
						writable: true];
	TEST(@"-[lowlevelWriteBuffer:length:]",
	    [stream lowlevelWriteBuffer: "abcde" length: 5] == 5 &&
	    [stream lowlevelWriteBuffer: "fgh" length: 3] == 3 &&
	    [stream lowlevelWriteBuffer: "ijkl" length: 5] == 5 &&
	    memcmp(data.items, string, data.count) == 0 &&
	    [stream lowlevelSeekToOffset: -3 whence: OFSeekEnd] == 10)

	EXPECT_EXCEPTION(@"Out of bound writes rejected",
	    OFWriteFailedException,
	    [stream lowlevelWriteBuffer: "xyz" length: 4])

	TEST(@"Partial write for too long write",
	    memcmp(data.items, "abcdefghijxyz", 13) == 0)

	objc_autoreleasePoolPop(pool);
}
@end







|
>

>
>
|


|
|

<
|
<
<
<
<
|
|
|
>






<
|
|
|
|
|
|
<
|

<
|
>
|
>
|
|
|
|
>
|
|
|
|

|
|
|
>
>
>
|
>
>




|
|
|
|
|
|

<
<
|
|
<
<
<
<


11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

29




30
31
32
33
34
35
36
37
38
39

40
41
42
43
44
45

46
47

48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81


82
83




84
85
 * 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 OFMemoryStreamTests: OTTestCase
@end

static const char string[] = "abcdefghijkl";

@implementation OFMemoryStreamTests
- (void)testReadOnlyMemoryStream
{

	OFMemoryStream *stream = [OFMemoryStream




	    streamWithMemoryAddress: (char *)string
			       size: sizeof(string)
			   writable: false];
	char buffer[10];

	/*
	 * Test the lowlevel methods, as otherwise OFStream will do one big
	 * read and we will not test OFMemoryStream.
	 */


	OTAssertEqual([stream lowlevelReadIntoBuffer: buffer length: 5], 5);
	OTAssertEqual(memcmp(buffer, "abcde", 5), 0);
	OTAssertEqual([stream lowlevelReadIntoBuffer: buffer length: 3], 3);
	OTAssertEqual(memcmp(buffer, "fgh", 3), 0);
	OTAssertEqual([stream lowlevelReadIntoBuffer: buffer length: 10], 5);
	OTAssertEqual(memcmp(buffer, "ijkl", 5), 0);

	OTAssertTrue([stream lowlevelIsAtEndOfStream]);


	OTAssertEqual([stream lowlevelSeekToOffset: 0 whence: OFSeekCurrent],
	    sizeof(string));
	OTAssertTrue([stream lowlevelIsAtEndOfStream]);

	OTAssertEqual([stream lowlevelSeekToOffset: 4 whence: OFSeekSet], 4);
	OTAssertFalse([stream lowlevelIsAtEndOfStream]);
	OTAssertEqual([stream lowlevelReadIntoBuffer: buffer length: 10], 9);
	OTAssertEqual(memcmp(buffer, "efghijkl", 9), 0);

	OTAssertEqual([stream lowlevelSeekToOffset: -2 whence: OFSeekEnd], 11);
	OTAssertEqual([stream lowlevelReadIntoBuffer: buffer length: 10], 2);
	OTAssertEqual(memcmp(buffer, "l", 2), 0);
	OTAssertEqual([stream lowlevelReadIntoBuffer: buffer length: 10], 0);

	OTAssertThrowsSpecific([stream lowlevelWriteBuffer: "" length: 1],
	    OFWriteFailedException);
}

- (void)testReadWriteMemoryStream
{
	OFMutableData *data = [OFMutableData dataWithCapacity: 13];
	OFMemoryStream *stream;

	[data increaseCountBy: 13];
	stream = [OFMemoryStream streamWithMemoryAddress: data.mutableItems
						    size: data.count
						writable: true];

	OTAssertEqual([stream lowlevelWriteBuffer: "abcde" length: 5], 5);
	OTAssertEqual([stream lowlevelWriteBuffer: "fgh" length: 3], 3);
	OTAssertEqual([stream lowlevelWriteBuffer: "ijkl" length: 5], 5);
	OTAssertEqual(memcmp(data.items, string, data.count), 0);
	OTAssertEqual([stream lowlevelSeekToOffset: -3 whence: OFSeekEnd], 10);



	OTAssertThrowsSpecific([stream lowlevelWriteBuffer: "xyz" length: 4],
	    OFWriteFailedException);




}
@end

Added tests/OFMethodSignatureTests.m version [27f044c8f7].





























































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
/*
 * Copyright (c) 2008-2024 Jonathan Schleifer <js@nil.im>
 *
 * 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 <string.h>

#if !defined(__STDC_NO_COMPLEX__) && defined(HAVE_COMPLEX_H)
# include <complex.h>
#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 tests/OFMutableArrayTests.h version [5ae96e61d9].













































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/*
 * Copyright (c) 2008-2024 Jonathan Schleifer <js@nil.im>
 *
 * 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 tests/OFMutableArrayTests.m version [29c5b449b7].































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
/*
 * Copyright (c) 2008-2024 Jonathan Schleifer <js@nil.im>
 *
 * 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)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 tests/OFMutableDataTests.m version [6267c8f315].











































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
/*
 * Copyright (c) 2008-2024 Jonathan Schleifer <js@nil.im>
 *
 * 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 <string.h>

#import "OFDataTests.h"

@interface OFMutableDataTests: OFDataTests
{
	OFMutableData *_mutableData;
}
@end

@implementation OFMutableDataTests
- (Class)dataClass
{
	return [OFMutableData class];
}

- (void)setUp
{
	[super setUp];

	_mutableData = [[OFMutableData alloc] initWithItems: "abcdef" count: 6];
}

- (void)dealloc
{
	[_mutableData release];

	[super dealloc];
}

- (void)testMutableCopy
{
	OTAssertEqualObjects([[_data mutableCopy] autorelease], _data);
	OTAssertNotEqual([[_data mutableCopy] autorelease], _data);
}

- (void)testAddItem
{
	[_mutableData addItem: "g"];

	OTAssertEqualObjects(_mutableData,
	    [OFData dataWithItems: "abcdefg" count: 7]);
}

- (void)testAddItemsCount
{
	[_mutableData addItems: "gh" count: 2];

	OTAssertEqualObjects(_mutableData,
	    [OFData dataWithItems: "abcdefgh" count: 8]);
}

- (void)testAddItemsCountThrowsOnOutOfRange
{
	OTAssertThrowsSpecific([_mutableData addItems: "" count: SIZE_MAX],
	    OFOutOfRangeException);
}

- (void)testRemoveLastItem
{
	[_mutableData removeLastItem];

	OTAssertEqualObjects(_mutableData,
	    [OFData dataWithItems: "abcde" count: 5]);
}

- (void)testRemoveItemsInRange
{
	[_mutableData removeItemsInRange: OFMakeRange(1, 2)];

	OTAssertEqualObjects(_mutableData,
	    [OFData dataWithItems: "adef" count: 4]);
}

- (void)testRemoveItemsInRangeThrowsOnOutOfRangeRange
{
	OTAssertThrowsSpecific(
	    [_mutableData removeItemsInRange: OFMakeRange(6, 1)],
	    OFOutOfRangeException);

	OTAssertThrowsSpecific(
	    [_mutableData removeItemsInRange: OFMakeRange(7, 0)],
	    OFOutOfRangeException);
}

- (void)testInsertItemsAtIndexCount
{
	[_mutableData insertItems: "BC" atIndex: 1 count: 2];

	OTAssertEqualObjects(_mutableData,
	    [OFData dataWithItems: "aBCbcdef" count: 8]);
}

- (void)testInsertItemsAtIndexCountThrowsOnOutOfRangeIndex
{
	OTAssertThrowsSpecific(
	    [_mutableData insertItems: "a" atIndex: 7 count: 1],
	    OFOutOfRangeException);
}
@end

Added tests/OFMutableDictionaryTests.h version [426f7697f8].



















































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/*
 * Copyright (c) 2008-2024 Jonathan Schleifer <js@nil.im>
 *
 * 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"

#import "OFDictionaryTests.h"

@interface OFMutableDictionaryTests: OFDictionaryTests
{
	OFMutableDictionary *_mutableDictionary;
}
@end

Added tests/OFMutableDictionaryTests.m version [4f6485a158].





























































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
/*
 * Copyright (c) 2008-2024 Jonathan Schleifer <js@nil.im>
 *
 * 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 "OFMutableDictionaryTests.h"

@interface CustomMutableDictionary: OFMutableDictionary
{
	OFMutableDictionary *_dictionary;
}
@end

@implementation OFMutableDictionaryTests
- (Class)dictionaryClass
{
	return [CustomMutableDictionary class];
}

- (void)setUp
{
	[super setUp];

	_mutableDictionary = [[self.dictionaryClass alloc] init];
}

- (void)dealloc
{
	[_mutableDictionary release];

	[super dealloc];
}

- (void)testSetObjectForKey
{
	[_mutableDictionary setObject: @"bar" forKey: @"foo"];
	OTAssertEqualObjects([_mutableDictionary objectForKey: @"foo"], @"bar");

	[_mutableDictionary setObject: @"qux" forKey: @"baz"];
	OTAssertEqualObjects(_mutableDictionary,
	    ([OFDictionary dictionaryWithKeysAndObjects:
	    @"foo", @"bar", @"baz", @"qux", nil]));
}

- (void)testSetValueForKey
{
	[_mutableDictionary setValue: @"bar" forKey: @"foo"];
	OTAssertEqualObjects([_mutableDictionary objectForKey: @"foo"], @"bar");

	[_mutableDictionary setValue: @"qux" forKey: @"baz"];
	OTAssertEqualObjects(_mutableDictionary,
	    ([OFDictionary dictionaryWithKeysAndObjects:
	    @"foo", @"bar", @"baz", @"qux", nil]));
}

- (void)testRemoveObjectForKey
{
	[_mutableDictionary addEntriesFromDictionary: _dictionary];
	OTAssertEqual(_mutableDictionary.count, 2);

	[_mutableDictionary removeObjectForKey: @"key2"];
	OTAssertEqual(_mutableDictionary.count, 1);
	OTAssertEqualObjects(_mutableDictionary,
	    [OFDictionary dictionaryWithObject: @"value1" forKey: @"key1"]);
}

- (void)testMutableCopy
{
	OFMutableDictionary *copy = [[_dictionary mutableCopy] autorelease];

	OTAssertEqualObjects(copy, _dictionary);
	OTAssertNotEqual(copy, _dictionary);
}

#ifdef OF_HAVE_BLOCKS
- (void)testReplaceObjectsUsingBlock
{
	OFMutableDictionary *mutableDictionary =
	    [[_dictionary mutableCopy] autorelease];

	[mutableDictionary replaceObjectsUsingBlock: ^ id (id key, id object) {
		if ([key isEqual: @"key1"])
			return @"value_1";
		if ([key isEqual: @"key2"])
			return @"value_2";

		return nil;
	}];

	OTAssertEqualObjects(mutableDictionary,
	    ([OFDictionary dictionaryWithKeysAndObjects:
	    @"key1", @"value_1", @"key2", @"value_2", nil]));
}
#endif
@end

@implementation CustomMutableDictionary
- (instancetype)init
{
	self = [super init];

	@try {
		_dictionary = [[OFMutableDictionary alloc] init];
	} @catch (id e) {
		[self release];
		@throw e;
	}

	return self;
}

- (instancetype)initWithObjects: (const id *)objects_
			forKeys: (const id *)keys_
			  count: (size_t)count
{
	self = [super init];

	@try {
		_dictionary = [[OFMutableDictionary alloc]
		    initWithObjects: objects_
			    forKeys: keys_
			      count: count];
	} @catch (id e) {
		[self release];
		@throw e;
	}

	return self;
}

- (void)dealloc
{
	[_dictionary release];

	[super dealloc];
}

- (id)objectForKey: (id)key
{
	return [_dictionary objectForKey: key];
}

- (size_t)count
{
	return _dictionary.count;
}

- (OFEnumerator *)keyEnumerator
{
	return [_dictionary keyEnumerator];
}

- (void)setObject: (id)object forKey: (id)key
{
	[_dictionary setObject: object forKey: key];
}

- (void)removeObjectForKey: (id)key
{
	[_dictionary removeObjectForKey: key];
}
@end

Added tests/OFMutableSetTests.h version [a531cff94b].













































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/*
 * Copyright (c) 2008-2024 Jonathan Schleifer <js@nil.im>
 *
 * 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 "OFSetTests.h"

@interface OFMutableSetTests: OFSetTests
{
	OFMutableSet *_mutableSet;
}
@end

Added tests/OFMutableSetTests.m version [8420adbe6c].





























































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
/*
 * Copyright (c) 2008-2024 Jonathan Schleifer <js@nil.im>
 *
 * 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 "OFMutableSetTests.h"

@interface CustomMutableSet: OFMutableSet
{
	OFMutableSet *_set;
}
@end

@implementation OFMutableSetTests
- (Class)setClass
{
	return [CustomMutableSet class];
}

- (void)setUp
{
	[super setUp];

	_mutableSet = [[OFMutableSet alloc]
	    initWithObjects: @"foo", @"bar", @"baz", nil];
}

- (void)dealloc
{
	[_mutableSet release];

	[super dealloc];
}

- (void)testAddObject
{
	[_mutableSet addObject: @"x"];

	OTAssertEqualObjects(_mutableSet,
	    ([OFSet setWithObjects: @"foo", @"bar", @"baz", @"x", nil]));
}

- (void)testRemoveObject
{
	[_mutableSet removeObject: @"foo"];

	OTAssertEqualObjects(_mutableSet,
	    ([OFSet setWithObjects: @"bar", @"baz", nil]));
}

- (void)testMinusSet
{
	[_mutableSet minusSet: [OFSet setWithObjects: @"foo", @"bar", nil]];

	OTAssertEqualObjects(_mutableSet,
	    ([OFSet setWithObjects: @"baz", nil]));
}

- (void)testIntersectSet
{
	[_mutableSet intersectSet: [OFSet setWithObjects: @"foo", @"qux", nil]];

	OTAssertEqualObjects(_mutableSet,
	    ([OFSet setWithObjects: @"foo", nil]));
}

- (void)testUnionSet
{
	[_mutableSet unionSet: [OFSet setWithObjects: @"x", @"y", nil]];

	OTAssertEqualObjects(_mutableSet,
	    ([OFSet setWithObjects: @"foo", @"bar", @"baz", @"x", @"y", nil]));
}

- (void)testRemoveAllObjects
{
	[_mutableSet removeAllObjects];

	OTAssertEqual(_mutableSet.count, 0);
}
@end

@implementation CustomMutableSet
- (instancetype)initWithObjects: (id const *)objects count: (size_t)count
{
	self = [super init];

	@try {
		_set = [[OFMutableSet alloc] initWithObjects: objects
						       count: count];
	} @catch (id e) {
		[self release];
		@throw e;
	}

	return self;
}

- (void)dealloc
{
	[_set release];

	[super dealloc];
}

- (size_t)count
{
	return _set.count;
}

- (bool)containsObject: (id)object
{
	return [_set containsObject: object];
}

- (OFEnumerator *)objectEnumerator
{
	return [_set objectEnumerator];
}

- (void)addObject: (id)object
{
	[_set addObject: object];
}

- (void)removeObject: (id)object
{
	[_set removeObject: object];
}
@end

Added tests/OFMutableStringTests.h version [206d9c71b6].



















































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/*
 * Copyright (c) 2008-2024 Jonathan Schleifer <js@nil.im>
 *
 * 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"

#import "OFStringTests.h"

@interface OFMutableStringTests: OFStringTests
{
	OFMutableString *_mutableString;
}
@end

Added tests/OFMutableStringTests.m version [9349febbaa].

















































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
/*
 * Copyright (c) 2008-2024 Jonathan Schleifer <js@nil.im>
 *
 * 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 <string.h>

#import "OFMutableStringTests.h"

@interface CustomMutableString: OFMutableString
{
	OFMutableString *_string;
}
@end

static OFString *const whitespace[] = {
	@" \r \t\n\t \tasd  \t \t\t\r\n",
	@" \t\t  \t\t  \t \t"
};

@implementation OFMutableStringTests
- (Class)stringClass
{
	return [CustomMutableString class];
}

- (void)setUp
{
	[super setUp];

	_mutableString = [[self.stringClass alloc] initWithString: @"täṠ€🤔"];
}

- (void)dealloc
{
	[_mutableString release];

	[super dealloc];
}

- (void)testAppendString
{
	[_mutableString appendString: @"ö"];

	OTAssertEqualObjects(_mutableString, @"täṠ€🤔ö");
}

- (void)testAppendUTF8String
{
	[_mutableString appendUTF8String: "ö"];

	OTAssertEqualObjects(_mutableString, @"täṠ€🤔ö");
}

- (void)testAppendUTF8StringLength
{
	[_mutableString appendUTF8String: "\xEF\xBB\xBF" "öÖ" length: 7];

	OTAssertEqualObjects(_mutableString, @"täṠ€🤔öÖ");
}

- (void)testAppendFormat
{
	[_mutableString appendFormat: @"%02X", 15];

	OTAssertEqualObjects(_mutableString, @"täṠ€🤔0F");
}

- (void)testAppendCharactersLength
{
	[_mutableString appendCharacters: (OFUnichar []){ 0xF6, 0xD6 }
				  length: 2];

	OTAssertEqualObjects(_mutableString, @"täṠ€🤔öÖ");
}

- (void)testUppercase
{
	[_mutableString uppercase];

#ifdef OF_HAVE_UNICODE_TABLES
	OTAssertEqualObjects(_mutableString, @"TÄṠ€🤔");
#else
	OTAssertEqualObjects(_mutableString, @"TäṠ€🤔");
#endif
}

- (void)testLowercase
{
	[_mutableString lowercase];

#ifdef OF_HAVE_UNICODE_TABLES
	OTAssertEqualObjects(_mutableString, @"täṡ€🤔");
#else
	OTAssertEqualObjects(_mutableString, @"täṠ€🤔");
#endif
}

- (void)testCapitalize
{
	OFMutableString *string =
	    [self.stringClass stringWithString: @"täṠ€🤔täṠ€🤔 täṠ€🤔"];

	[string capitalize];

#ifdef OF_HAVE_UNICODE_TABLES
	OTAssertEqualObjects(string, @"Täṡ€🤔täṡ€🤔 Täṡ€🤔");
#else
	OTAssertEqualObjects(string, @"TäṠ€🤔täṠ€🤔 TäṠ€🤔");
#endif
}

- (void)testInsertStringAtIndex
{
	[_mutableString insertString: @"fööbär" atIndex: 2];

	OTAssertEqualObjects(_mutableString, @"täfööbärṠ€🤔");
}

- (void)testSetCharacterAtIndex
{
	[_mutableString setCharacter: 0x1F600 atIndex: 2];

	OTAssertEqualObjects(_mutableString, @"tä😀€🤔");
}

- (void)testDeleteCharactersInRange
{
	[_mutableString deleteCharactersInRange: OFMakeRange(2, 2)];

	OTAssertEqualObjects(_mutableString, @"tä🤔");
}

- (void)testDeleteCharactersInRangeThrowsWithOutOfRangeRange
{
	OTAssertThrowsSpecific(
	    [_mutableString deleteCharactersInRange: OFMakeRange(4, 2)],
	    OFOutOfRangeException);

	OTAssertThrowsSpecific(
	    [_mutableString deleteCharactersInRange: OFMakeRange(5, 1)],
	    OFOutOfRangeException);

	OTAssertThrowsSpecific(
	    [_mutableString deleteCharactersInRange: OFMakeRange(6, 0)],
	    OFOutOfRangeException);
}

- (void)testReplaceCharactersInRangeWithString
{
	OFMutableString *string =
	    [self.stringClass stringWithString: @"ð„žÃ¶Ã¶Ã¶bä€"];

	[string replaceCharactersInRange: OFMakeRange(1, 3)
			      withString: @"äöüß"];
	OTAssertEqualObjects(string, @"ð„žÃ¤Ã¶Ã¼ÃŸbä€");

	[string replaceCharactersInRange: OFMakeRange(4, 2) withString: @"b"];
	OTAssertEqualObjects(string, @"ð„žÃ¤Ã¶Ã¼bä€");

	[string replaceCharactersInRange: OFMakeRange(0, 7) withString: @""];
	OTAssertEqualObjects(string, @"");
}

- (void)testReplaceCharactersInRangeWithStringFailsWithOutOfRangeRange
{
	OTAssertThrowsSpecific(
	    [_mutableString replaceCharactersInRange: OFMakeRange(4, 2)
					  withString: @"abc"],
	    OFOutOfRangeException);

	OTAssertThrowsSpecific(
	    [_mutableString replaceCharactersInRange: OFMakeRange(5, 1)
					  withString: @"abc"],
	    OFOutOfRangeException);

	OTAssertThrowsSpecific(
	    [_mutableString replaceCharactersInRange: OFMakeRange(6, 0)
					  withString: @""],
	    OFOutOfRangeException);
}

- (void)testReplaceOccurrencesOfStringWithString
{
	OFMutableString *string;

	string = [self.stringClass stringWithString: @"asd fo asd fofo asd"];
	[string replaceOccurrencesOfString: @"fo" withString: @"foo"];
	OTAssertEqualObjects(string, @"asd foo asd foofoo asd");

	string = [self.stringClass stringWithString: @"XX"];
	[string replaceOccurrencesOfString: @"X" withString: @"XX"];
	OTAssertEqualObjects(string, @"XXXX");
}

- (void)testReplaceOccurrencesOfStringWithStringOptionsRange
{
	OFMutableString *string =
	    [self.stringClass stringWithString: @"foofoobarfoobarfoo"];

	[string replaceOccurrencesOfString: @"oo"
				withString: @"óò"
				   options: 0
				     range: OFMakeRange(2, 15)];
	OTAssertEqualObjects(string, @"foofóòbarfóòbarfoo");
}

- (void)
  testReplaceOccurrencesOfStringWithStringOptionsRangeThrowsWithOutOfRangeRange
{
	OTAssertThrowsSpecific(
	    [_mutableString replaceOccurrencesOfString: @"t"
					    withString: @"abc"
					       options: 0
						 range: OFMakeRange(4, 2)],
	    OFOutOfRangeException);

	OTAssertThrowsSpecific(
	    [_mutableString replaceOccurrencesOfString: @"t"
					    withString: @"abc"
					       options: 0
						 range: OFMakeRange(5, 1)],
	    OFOutOfRangeException);

	OTAssertThrowsSpecific(
	    [_mutableString replaceOccurrencesOfString: @"t"
					    withString: @""
					       options: 0
						 range: OFMakeRange(6, 0)],
	    OFOutOfRangeException);
}

- (void)deleteLeadingWhitespaces
{
	OFMutableString *string;

	string = [self.stringClass stringWithString: whitespace[0]];
	[string deleteLeadingWhitespaces];
	OTAssertEqualObjects(string, @"asd  \t \t\t\r\n");

	string = [self.stringClass stringWithString: whitespace[1]];
	[string deleteLeadingWhitespaces];
	OTAssertEqualObjects(string, @"");
}

- (void)deleteTrailingWhitespaces
{
	OFMutableString *string;

	string = [self.stringClass stringWithString: whitespace[0]];
	[string deleteTrailingWhitespaces];
	OTAssertEqualObjects(string,  @" \r \t\n\t \tasd");

	string = [self.stringClass stringWithString: whitespace[1]];
	[string deleteTrailingWhitespaces];
	OTAssertEqualObjects(string, @"");
}

- (void)deleteEnclosingWhitespaces
{
	OFMutableString *string;

	string = [self.stringClass stringWithString: whitespace[0]];
	[string deleteEnclosingWhitespaces];
	OTAssertEqualObjects(string, @"asd");

	string = [self.stringClass stringWithString: whitespace[1]];
	[string deleteEnclosingWhitespaces];
	OTAssertEqualObjects(string, @"");
}
@end

@implementation CustomMutableString
- (instancetype)init
{
	self = [super init];

	@try {
		_string = [[OFMutableString alloc] init];
	} @catch (id e) {
		[self release];
		@throw e;
	}

	return self;
}

- (instancetype)initWithString: (OFString *)string
{
	self = [super init];

	@try {
		_string = [string mutableCopy];
	} @catch (id e) {
		[self release];
		@throw e;
	}

	return self;
}

- (instancetype)initWithCString: (const char *)cString
		       encoding: (OFStringEncoding)encoding
			 length: (size_t)length
{
	self = [super init];

	@try {
		_string = [[OFMutableString alloc] initWithCString: cString
							  encoding: encoding
							    length: length];
	} @catch (id e) {
		[self release];
		@throw e;
	}

	return self;
}

- (instancetype)initWithUTF16String: (const OFChar16 *)UTF16String
			     length: (size_t)length
			  byteOrder: (OFByteOrder)byteOrder
{
	self = [super init];

	@try {
		_string = [[OFMutableString alloc]
		    initWithUTF16String: UTF16String
				 length: length
			      byteOrder: byteOrder];
	} @catch (id e) {
		[self release];
		@throw e;
	}

	return self;
}

- (instancetype)initWithUTF32String: (const OFChar32 *)UTF32String
			     length: (size_t)length
			  byteOrder: (OFByteOrder)byteOrder
{
	self = [super init];

	@try {
		_string = [[OFMutableString alloc]
		    initWithUTF32String: UTF32String
				 length: length
			      byteOrder: byteOrder];
	} @catch (id e) {
		[self release];
		@throw e;
	}

	return self;
}

- (instancetype)initWithFormat: (OFConstantString *)format
		     arguments: (va_list)arguments
{
	self = [super init];

	@try {
		_string = [[OFMutableString alloc] initWithFormat: format
							arguments: arguments];
	} @catch (id e) {
		[self release];
		@throw e;
	}

	return self;
}

- (void)dealloc
{
	[_string release];

	[super dealloc];
}

- (OFUnichar)characterAtIndex: (size_t)idx
{
	return [_string characterAtIndex: idx];
}

- (size_t)length
{
	return _string.length;
}

- (void)replaceCharactersInRange: (OFRange)range
		      withString: (OFString *)string
{
	[_string replaceCharactersInRange: range withString: string];
}
@end

Added tests/OFMutableUTF8StringTests.m version [be500c9e1a].





























































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
/*
 * Copyright (c) 2008-2024 Jonathan Schleifer <js@nil.im>
 *
 * 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 "OFMutableStringTests.h"

#import "OFMutableUTF8String.h"

@interface OFMutableUTF8StringTests: OFMutableStringTests
@end

@implementation OFMutableUTF8StringTests
- (Class)arrayClass
{
	return [OFMutableUTF8String class];
}
@end

Modified tests/OFNotificationCenterTests.m from [088812ee19] to [0385b37634].

11
12
13
14
15
16
17
18

19
20
21
22
23
24
25
26



27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93

94

95
96
97
98
99
100

101

102
103
104
105
106
107

108

109
110
111
112
113
114
115
116
117
118
119
120

121

122

123

124

125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154

155
156
157
158
159
 * 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 = @"OFNotificationCenter";
static const OFNotificationName notificationName =
    @"OFNotificationCenterTestName";
static const OFNotificationName otherNotificationName =
    @"OFNotificationCenterTestOtherName";

@interface OFNotificationCenterTest: OFObject



{
@public
	id _expectedObject;
	int _received;
}

- (void)handleNotification: (OFNotification *)notification;
@end

@implementation OFNotificationCenterTest
- (void)handleNotification: (OFNotification *)notification
{
	OFEnsure([notification.name isEqual: notificationName]);
	OFEnsure(_expectedObject == nil ||
	    notification.object == _expectedObject);

	_received++;
}
@end

@implementation TestsAppDelegate (OFNotificationCenterTests)
- (void)notificationCenterTests
{
	void *pool = objc_autoreleasePoolPush();
	OFNotificationCenter *center = [OFNotificationCenter defaultCenter];
	OFNotificationCenterTest *test1, *test2, *test3, *test4;
	OFNotification *notification;

	test1 =
	    [[[OFNotificationCenterTest alloc] init] autorelease];
	test1->_expectedObject = self;
	test2 =
	    [[[OFNotificationCenterTest alloc] init] autorelease];
	test3 =
	    [[[OFNotificationCenterTest alloc] init] autorelease];
	test3->_expectedObject = self;
	test4 =
	    [[[OFNotificationCenterTest alloc] init] autorelease];

	/* First one intentionally added twice to test deduplication. */
	TEST(@"-[addObserver:selector:name:object:]",
	    R([center addObserver: test1
			 selector: @selector(handleNotification:)
			     name: notificationName
			   object: self]) &&
	    R([center addObserver: test1
			 selector: @selector(handleNotification:)
			     name: notificationName
			   object: self]) &&
	    R([center addObserver: test2
			 selector: @selector(handleNotification:)
			     name: notificationName
			   object: nil]) &&
	    R([center addObserver: test3
			 selector: @selector(handleNotification:)
			     name: otherNotificationName
			   object: self]) &&
	    R([center addObserver: test4
			 selector: @selector(handleNotification:)
			     name: otherNotificationName
			   object: nil]))

	notification = [OFNotification notificationWithName: notificationName
						     object: nil];
	TEST(@"-[postNotification:] #1",
	    R([center postNotification: notification]) &&
	    test1->_received == 0 && test2->_received == 1 &&

	    test3->_received == 0 && test4->_received == 0)


	notification = [OFNotification notificationWithName: notificationName
						     object: self];
	TEST(@"-[postNotification:] #2",
	    R([center postNotification: notification]) &&
	    test1->_received == 1 && test2->_received == 2 &&

	    test3->_received == 0 && test4->_received == 0)


	notification = [OFNotification notificationWithName: notificationName
						     object: @"foo"];
	TEST(@"-[postNotification:] #3",
	    R([center postNotification: notification]) &&
	    test1->_received == 1 && test2->_received == 3 &&

	    test3->_received == 0 && test4->_received == 0)


#ifdef OF_HAVE_BLOCKS
	__block bool received = false;
	id handle;

	notification = [OFNotification notificationWithName: notificationName
						     object: self];
	TEST(@"-[addObserverForName:object:usingBlock:]",
	    (handle = [center addObserverForName: notificationName
					  object: self
				      usingBlock: ^ (OFNotification *notif) {
		OFEnsure(notif == notification && !received);

		received = true;

	    }]) && R([center postNotification: notification]) && received &&

	    test1->_received == 2 && test2->_received == 4 &&

	    test3->_received == 0 && test4->_received == 0)


	/* Act like the block test didn't happen. */
	[center removeObserver: handle];
	test1->_received--;
	test2->_received--;
#endif

	TEST(@"-[removeObserver:selector:name:object:]",
	    R([center removeObserver: test1
			    selector: @selector(handleNotification:)
				name: notificationName
			      object: self]) &&
	    R([center removeObserver: test2
			    selector: @selector(handleNotification:)
				name: notificationName
			      object: nil]) &&
	    R([center removeObserver: test3
			    selector: @selector(handleNotification:)
				name: otherNotificationName
			      object: self]) &&
	    R([center removeObserver: test4
			    selector: @selector(handleNotification:)
				name: otherNotificationName
			      object: nil]))

	notification = [OFNotification notificationWithName: notificationName
						     object: self];
	TEST(@"-[postNotification:] with no observers",
	    R([center postNotification: notification]) &&
	    test1->_received == 1 && test2->_received == 3 &&

	    test3->_received == 0 && test4->_received == 0)

	objc_autoreleasePoolPop(pool);
}
@end







|
>

<





|
>
>
>









|










|
|

<

|


<
|

<
|
<
|

<
|


<
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|



<
|
|
>
|
>



<
|
|
>
|
>



<
|
|
>
|
>







<
|
|
|
|
>

>
|
>
|
>
|
>







<
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|



<
|
|
>
|
|
<


11
12
13
14
15
16
17
18
19
20

21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52

53
54
55
56

57
58

59

60
61

62
63
64

65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87

88
89
90
91
92
93
94
95

96
97
98
99
100
101
102
103

104
105
106
107
108
109
110
111
112
113
114
115

116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135

136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154

155
156
157
158
159

160
161
 * 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"


static const OFNotificationName notificationName =
    @"OFNotificationCenterTestName";
static const OFNotificationName otherNotificationName =
    @"OFNotificationCenterTestOtherName";

@interface OFNotificationCenterTests: OTTestCase
@end

@interface OFNotificationCenterTestClass: OFObject
{
@public
	id _expectedObject;
	int _received;
}

- (void)handleNotification: (OFNotification *)notification;
@end

@implementation OFNotificationCenterTestClass
- (void)handleNotification: (OFNotification *)notification
{
	OFEnsure([notification.name isEqual: notificationName]);
	OFEnsure(_expectedObject == nil ||
	    notification.object == _expectedObject);

	_received++;
}
@end

@implementation OFNotificationCenterTests
- (void)testNotificationCenter
{

	OFNotificationCenter *center = [OFNotificationCenter defaultCenter];
	OFNotificationCenterTestClass *test1, *test2, *test3, *test4;
	OFNotification *notification;


	test1 = [[[OFNotificationCenterTestClass alloc] init] autorelease];
	test1->_expectedObject = self;

	test2 = [[[OFNotificationCenterTestClass alloc] init] autorelease];

	test3 = [[[OFNotificationCenterTestClass alloc] init] autorelease];
	test3->_expectedObject = self;

	test4 = [[[OFNotificationCenterTestClass alloc] init] autorelease];

	/* First one intentionally added twice to test deduplication. */

	[center addObserver: test1
		   selector: @selector(handleNotification:)
		       name: notificationName
		     object: self];
	[center addObserver: test1
		   selector: @selector(handleNotification:)
		       name: notificationName
		     object: self];
	[center addObserver: test2
		   selector: @selector(handleNotification:)
		       name: notificationName
		     object: nil];
	[center addObserver: test3
		   selector: @selector(handleNotification:)
		       name: otherNotificationName
		     object: self];
	[center addObserver: test4
		   selector: @selector(handleNotification:)
		       name: otherNotificationName
		     object: nil];

	notification = [OFNotification notificationWithName: notificationName
						     object: nil];

	[center postNotification: notification];
	OTAssertEqual(test1->_received, 0);
	OTAssertEqual(test2->_received, 1);
	OTAssertEqual(test3->_received, 0);
	OTAssertEqual(test4->_received, 0);

	notification = [OFNotification notificationWithName: notificationName
						     object: self];

	[center postNotification: notification];
	OTAssertEqual(test1->_received, 1);
	OTAssertEqual(test2->_received, 2);
	OTAssertEqual(test3->_received, 0);
	OTAssertEqual(test4->_received, 0);

	notification = [OFNotification notificationWithName: notificationName
						     object: @"foo"];

	[center postNotification: notification];
	OTAssertEqual(test1->_received, 1);
	OTAssertEqual(test2->_received, 3);
	OTAssertEqual(test3->_received, 0);
	OTAssertEqual(test4->_received, 0);

#ifdef OF_HAVE_BLOCKS
	__block bool received = false;
	id handle;

	notification = [OFNotification notificationWithName: notificationName
						     object: self];

	handle = [center addObserverForName: notificationName
				     object: self
				 usingBlock: ^ (OFNotification *notification_) {
		OTAssertEqual(notification_, notification);
		OTAssertFalse(received);
		received = true;
	    }];
	[center postNotification: notification];
	OTAssertTrue(received);
	OTAssertEqual(test1->_received, 2);
	OTAssertEqual(test2->_received, 4);
	OTAssertEqual(test3->_received, 0);
	OTAssertEqual(test4->_received, 0);

	/* Act like the block test didn't happen. */
	[center removeObserver: handle];
	test1->_received--;
	test2->_received--;
#endif


	[center removeObserver: test1
		      selector: @selector(handleNotification:)
			  name: notificationName
			object: self];
	[center removeObserver: test2
		      selector: @selector(handleNotification:)
			  name: notificationName
			object: nil];
	[center removeObserver: test3
		      selector: @selector(handleNotification:)
			  name: otherNotificationName
			object: self];
	[center removeObserver: test4
		      selector: @selector(handleNotification:)
			  name: otherNotificationName
			object: nil];

	notification = [OFNotification notificationWithName: notificationName
						     object: self];

	[center postNotification: notification];
	OTAssertEqual(test1->_received, 1);
	OTAssertEqual(test2->_received, 3);
	OTAssertEqual(test3->_received, 0);
	OTAssertEqual(test4->_received, 0);

}
@end

Added tests/OFNumberTests.m version [79e5b7d8e7].





































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
/*
 * Copyright (c) 2008-2024 Jonathan Schleifer <js@nil.im>
 *
 * 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
{
	OFNumber *_number;
}
@end

@implementation OFNumberTests
- (void)setUp
{
	[super setUp];

	_number = [[OFNumber alloc] initWithLongLong: 123456789];
}

- (void)dealloc
{
	[_number release];

	[super dealloc];
}

- (void)testIsEqual
{
	OTAssertEqualObjects(_number, [OFNumber numberWithLong: 123456789]);
}

- (void)testHash
{
	OTAssertEqual(_number.hash,
	    [[OFNumber numberWithLong: 123456789] hash]);
}

- (void)testCharValue
{
	OTAssertEqual(_number.charValue, 21);
}

- (void)testDoubleValue
{
	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

Modified tests/OFObjectTests.m from [39c729edc8] to [289bb9d695].

11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
 * 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"

#if (defined(OF_DRAGONFLYBSD) && defined(__LP64__)) || defined(OF_NINTENDO_3DS)
# define TOO_BIG (SIZE_MAX / 3)
#else
# define TOO_BIG (SIZE_MAX - 128)
#endif

static OFString *const module = @"OFObject";

@interface MyObject: OFObject
{
	id _objectValue;
	Class _classValue;
	bool _boolValue;
	char _charValue;







|
|
<
<
<
<
<
<
<







11
12
13
14
15
16
17
18
19







20
21
22
23
24
25
26
 * 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 MyObject: OFObject
{
	id _objectValue;
	Class _classValue;
	bool _boolValue;
	char _charValue;
56
57
58
59
60
61
62


























































































































































































63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
@property (nonatomic) unsigned short unsignedShortValue;
@property (nonatomic) unsigned int unsignedIntValue;
@property (nonatomic) unsigned long unsignedLongValue;
@property (nonatomic) unsigned long long unsignedLongLongValue;
@property (nonatomic) float floatValue;
@property (nonatomic) double doubleValue;
@end



























































































































































































@implementation MyObject
@synthesize objectValue = _objectValue, classValue = _classValue;
@synthesize boolValue = _boolValue, charValue = _charValue;
@synthesize shortValue = _shortValue, intValue = _intValue;
@synthesize longValue = _longValue, longLongValue = _longLongValue;
@synthesize unsignedCharValue = _unsignedCharValue;
@synthesize unsignedShortValue = _unsignedShortValue;
@synthesize unsignedIntValue = _unsignedIntValue;
@synthesize unsignedLongValue = _unsignedLongValue;
@synthesize unsignedLongLongValue = _unsignedLongLongValue;
@synthesize floatValue = _floatValue, doubleValue = _doubleValue;

- (void)dealloc
{
	[_objectValue release];

	[super dealloc];
}
@end

@implementation TestsAppDelegate (OFObjectTests)
- (void)objectTests
{
	void *pool = objc_autoreleasePoolPush();
	OFObject *object;
	MyObject *myObject;

	TEST(@"+[description]",
	    [[OFObject description] isEqual: @"OFObject"] &&
	    [[MyObject description] isEqual: @"MyObject"])

	object = [[[OFObject alloc] init] autorelease];
	myObject = [[[MyObject alloc] init] autorelease];

	TEST(@"-[description]",
	    [object.description isEqual: @"<OFObject>"] &&
	    [myObject.description isEqual: @"<MyObject>"])

	myObject.objectValue = @"Hello";
	myObject.classValue = myObject.class;
	TEST(@"-[valueForKey:]",
	    [[myObject valueForKey: @"objectValue"] isEqual: @"Hello"] &&
	    [[myObject valueForKey: @"classValue"] isEqual: myObject.class] &&
	    [[myObject valueForKey: @"class"] isEqual: myObject.class])

	EXPECT_EXCEPTION(@"-[valueForKey:] with undefined key",
	    OFUndefinedKeyException, [myObject valueForKey: @"undefined"])

	TEST(@"-[setValue:forKey:]",
	    R([myObject setValue: @"World" forKey: @"objectValue"]) &&
	    R([myObject setValue: [OFObject class] forKey: @"classValue"]) &&
	    [myObject.objectValue isEqual: @"World"] &&
	    [myObject.classValue isEqual: [OFObject class]])

	EXPECT_EXCEPTION(@"-[setValue:forKey:] with undefined key",
	    OFUndefinedKeyException,
	    [myObject setValue: @"x" forKey: @"undefined"])

	myObject.boolValue = 1;
	myObject.charValue = 2;
	myObject.shortValue = 3;
	myObject.intValue = 4;
	myObject.longValue = 5;
	myObject.longLongValue = 6;
	myObject.unsignedCharValue = 7;
	myObject.unsignedShortValue = 8;
	myObject.unsignedIntValue = 9;
	myObject.unsignedLongValue = 10;
	myObject.unsignedLongLongValue = 11;
	myObject.floatValue = 12;
	myObject.doubleValue = 13;
	TEST(@"Auto-wrapping of -[valueForKey:]",
	    [[myObject valueForKey: @"boolValue"] isEqual:
	    [OFNumber numberWithBool: 1]] &&
	    [[myObject valueForKey: @"charValue"] isEqual:
	    [OFNumber numberWithChar: 2]] &&
	    [[myObject valueForKey: @"shortValue"] isEqual:
	    [OFNumber numberWithShort: 3]] &&
	    [[myObject valueForKey: @"intValue"] isEqual:
	    [OFNumber numberWithInt: 4]] &&
	    [[myObject valueForKey: @"longValue"] isEqual:
	    [OFNumber numberWithLong: 5]] &&
	    [[myObject valueForKey: @"longLongValue"] isEqual:
	    [OFNumber numberWithLongLong: 6]] &&
	    [[myObject valueForKey: @"unsignedCharValue"] isEqual:
	    [OFNumber numberWithUnsignedChar: 7]] &&
	    [[myObject valueForKey: @"unsignedShortValue"] isEqual:
	    [OFNumber numberWithUnsignedShort: 8]] &&
	    [[myObject valueForKey: @"unsignedIntValue"] isEqual:
	    [OFNumber numberWithUnsignedInt: 9]] &&
	    [[myObject valueForKey: @"unsignedLongValue"] isEqual:
	    [OFNumber numberWithUnsignedLong: 10]] &&
	    [[myObject valueForKey: @"unsignedLongLongValue"] isEqual:
	    [OFNumber numberWithUnsignedLongLong: 11]] &&
	    [[myObject valueForKey: @"floatValue"] isEqual:
	    [OFNumber numberWithFloat: 12]] &&
	    [[myObject valueForKey: @"doubleValue"] isEqual:
	    [OFNumber numberWithDouble: 13]])

	TEST(@"Auto-wrapping of -[setValue:forKey:]",
	    R([myObject setValue: [OFNumber numberWithBool: 0]
			  forKey: @"boolValue"]) &&
	    R([myObject setValue: [OFNumber numberWithChar: 10]
			  forKey: @"charValue"]) &&
	    R([myObject setValue: [OFNumber numberWithShort: 20]
			  forKey: @"shortValue"]) &&
	    R([myObject setValue: [OFNumber numberWithInt: 30]
			  forKey: @"intValue"]) &&
	    R([myObject setValue: [OFNumber numberWithLong: 40]
			  forKey: @"longValue"]) &&
	    R([myObject setValue: [OFNumber numberWithLongLong: 50]
			  forKey: @"longLongValue"]) &&
	    R([myObject setValue: [OFNumber numberWithUnsignedChar: 60]
			  forKey: @"unsignedCharValue"]) &&
	    R([myObject setValue: [OFNumber numberWithUnsignedShort: 70]
			  forKey: @"unsignedShortValue"]) &&
	    R([myObject setValue: [OFNumber numberWithUnsignedInt: 80]
			  forKey: @"unsignedIntValue"]) &&
	    R([myObject setValue: [OFNumber numberWithUnsignedLong: 90]
			  forKey: @"unsignedLongValue"]) &&
	    R([myObject setValue: [OFNumber numberWithUnsignedLongLong: 100]
			  forKey: @"unsignedLongLongValue"]) &&
	    R([myObject setValue: [OFNumber numberWithFloat: 110]
			  forKey: @"floatValue"]) &&
	    R([myObject setValue: [OFNumber numberWithDouble: 120]
			  forKey: @"doubleValue"]) &&
	    myObject.isBoolValue == 0 && myObject.charValue == 10 &&
	    myObject.shortValue == 20 && myObject.intValue == 30 &&
	    myObject.longValue == 40 && myObject.longLongValue == 50 &&
	    myObject.unsignedCharValue == 60 &&
	    myObject.unsignedShortValue == 70 &&
	    myObject.unsignedIntValue == 80 &&
	    myObject.unsignedLongValue == 90 &&
	    myObject.unsignedLongLongValue == 100 &&
	    myObject.floatValue == 110 &&
	    myObject.doubleValue == 120)

	EXPECT_EXCEPTION(@"Catch -[setValue:forKey:] with nil key for scalar",
	    OFInvalidArgumentException,
	    [myObject setValue: (id _Nonnull)nil forKey: @"intValue"])

	TEST(@"-[valueForKeyPath:]",
	    (myObject = [[[MyObject alloc] init] autorelease]) &&
	    (myObject.objectValue = [[[MyObject alloc] init] autorelease]) &&
	    R([myObject.objectValue
	    setObjectValue: [[[MyObject alloc] init] autorelease]]) &&
	    R([[myObject.objectValue objectValue] setDoubleValue: 0.5]) &&
	    [[myObject valueForKeyPath: @"objectValue.objectValue.doubleValue"]
	    doubleValue] == 0.5)

	TEST(@"[-setValue:forKeyPath:]",
	    R([myObject setValue: [OFNumber numberWithDouble: 0.75]
		      forKeyPath: @"objectValue.objectValue.doubleValue"]) &&
	    [[myObject.objectValue objectValue] doubleValue] == 0.75)

	objc_autoreleasePoolPop(pool);
}
@end







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>




















<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261











































































































































@property (nonatomic) unsigned short unsignedShortValue;
@property (nonatomic) unsigned int unsignedIntValue;
@property (nonatomic) unsigned long unsignedLongValue;
@property (nonatomic) unsigned long long unsignedLongLongValue;
@property (nonatomic) float floatValue;
@property (nonatomic) double doubleValue;
@end

@interface OFObjectTests: OTTestCase
{
	MyObject *_myObject;
}
@end

@implementation OFObjectTests
- (void)setUp
{
	[super setUp];

	_myObject = [[MyObject alloc] init];
}

- (void)dealloc
{
	[_myObject release];

	[super dealloc];
}

- (void)testClassDescription
{
	OTAssertEqualObjects([OFObject description], @"OFObject");
	OTAssertEqualObjects([MyObject description], @"MyObject");
}

- (void)testInstanceDescription
{
	OFObject *object = [[[OFObject alloc] init] autorelease];

	OTAssertEqualObjects(object.description, @"<OFObject>");
	OTAssertEqualObjects(_myObject.description, @"<MyObject>");
}

- (void)testValueForKey
{
	_myObject.objectValue = @"Hello";
	_myObject.classValue = _myObject.class;

	OTAssertEqualObjects([_myObject valueForKey: @"objectValue"], @"Hello");
	OTAssertEqualObjects([_myObject valueForKey: @"classValue"],
	    _myObject.class);
	OTAssertEqualObjects([_myObject valueForKey: @"class"],
	    _myObject.class);
}

- (void)testValueForKeyWithUndefinedKeyThrows
{
	OTAssertThrowsSpecific([_myObject valueForKey: @"undefined"],
	   OFUndefinedKeyException);
}

- (void)testSetValueForKey
{
	[_myObject setValue: @"World" forKey: @"objectValue"];
	[_myObject setValue: [OFObject class] forKey: @"classValue"];

	OTAssertEqualObjects(_myObject.objectValue, @"World");
	OTAssertEqualObjects(_myObject.classValue, [OFObject class]);
}

- (void)testSetValueWithUndefinedKeyThrows
{
	OTAssertThrowsSpecific([_myObject setValue: @"x" forKey: @"undefined"],
	    OFUndefinedKeyException);
}

- (void)testAutoWrappingOfValueForKey
{
	_myObject.boolValue = 1;
	_myObject.charValue = 2;
	_myObject.shortValue = 3;
	_myObject.intValue = 4;
	_myObject.longValue = 5;
	_myObject.longLongValue = 6;
	_myObject.unsignedCharValue = 7;
	_myObject.unsignedShortValue = 8;
	_myObject.unsignedIntValue = 9;
	_myObject.unsignedLongValue = 10;
	_myObject.unsignedLongLongValue = 11;
	_myObject.floatValue = 12;
	_myObject.doubleValue = 13;

	OTAssertEqualObjects([_myObject valueForKey: @"boolValue"],
	    [OFNumber numberWithBool: 1]);
	OTAssertEqualObjects([_myObject valueForKey: @"charValue"],
	    [OFNumber numberWithChar: 2]);
	OTAssertEqualObjects([_myObject valueForKey: @"shortValue"],
	    [OFNumber numberWithShort: 3]);
	OTAssertEqualObjects([_myObject valueForKey: @"intValue"],
	    [OFNumber numberWithInt: 4]);
	OTAssertEqualObjects([_myObject valueForKey: @"longValue"],
	    [OFNumber numberWithLong: 5]);
	OTAssertEqualObjects([_myObject valueForKey: @"longLongValue"],
	    [OFNumber numberWithLongLong: 6]);
	OTAssertEqualObjects([_myObject valueForKey: @"unsignedCharValue"],
	    [OFNumber numberWithUnsignedChar: 7]);
	OTAssertEqualObjects([_myObject valueForKey: @"unsignedShortValue"],
	    [OFNumber numberWithUnsignedShort: 8]);
	OTAssertEqualObjects([_myObject valueForKey: @"unsignedIntValue"],
	    [OFNumber numberWithUnsignedInt: 9]);
	OTAssertEqualObjects([_myObject valueForKey: @"unsignedLongValue"],
	    [OFNumber numberWithUnsignedLong: 10]);
	OTAssertEqualObjects([_myObject valueForKey: @"unsignedLongLongValue"],
	    [OFNumber numberWithUnsignedLongLong: 11]);
	OTAssertEqualObjects([_myObject valueForKey: @"floatValue"],
	    [OFNumber numberWithFloat: 12]);
	OTAssertEqualObjects([_myObject valueForKey: @"doubleValue"],
	    [OFNumber numberWithDouble: 13]);
}

- (void)testAutoWrappingOfSetValueForKey
{
	[_myObject setValue: [OFNumber numberWithBool: 0]
		     forKey: @"boolValue"];
	[_myObject setValue: [OFNumber numberWithChar: 10]
		     forKey: @"charValue"];
	[_myObject setValue: [OFNumber numberWithShort: 20]
		     forKey: @"shortValue"];
	[_myObject setValue: [OFNumber numberWithInt: 30]
		     forKey: @"intValue"];
	[_myObject setValue: [OFNumber numberWithLong: 40]
		     forKey: @"longValue"];
	[_myObject setValue: [OFNumber numberWithLongLong: 50]
		     forKey: @"longLongValue"];
	[_myObject setValue: [OFNumber numberWithUnsignedChar: 60]
		     forKey: @"unsignedCharValue"];
	[_myObject setValue: [OFNumber numberWithUnsignedShort: 70]
		     forKey: @"unsignedShortValue"];
	[_myObject setValue: [OFNumber numberWithUnsignedInt: 80]
		     forKey: @"unsignedIntValue"];
	[_myObject setValue: [OFNumber numberWithUnsignedLong: 90]
		     forKey: @"unsignedLongValue"];
	[_myObject setValue: [OFNumber numberWithUnsignedLongLong: 100]
		     forKey: @"unsignedLongLongValue"];
	[_myObject setValue: [OFNumber numberWithFloat: 110]
		     forKey: @"floatValue"];
	[_myObject setValue: [OFNumber numberWithDouble: 120]
		     forKey: @"doubleValue"];

	OTAssertEqual(_myObject.isBoolValue, 0);
	OTAssertEqual(_myObject.charValue, 10);
	OTAssertEqual(_myObject.shortValue, 20);
	OTAssertEqual(_myObject.intValue, 30);
	OTAssertEqual(_myObject.longValue, 40);
	OTAssertEqual(_myObject.longLongValue, 50);
	OTAssertEqual(_myObject.unsignedCharValue, 60);
	OTAssertEqual(_myObject.unsignedShortValue, 70);
	OTAssertEqual(_myObject.unsignedIntValue, 80);
	OTAssertEqual(_myObject.unsignedLongValue, 90);
	OTAssertEqual(_myObject.unsignedLongLongValue, 100);
	OTAssertEqual(_myObject.floatValue, 110);
	OTAssertEqual(_myObject.doubleValue, 120);
}

- (void)testSetValueForKeyWithNilThrows
{
	OTAssertThrowsSpecific(
	    [_myObject setValue: (id _Nonnull)nil forKey: @"intValue"],
	    OFInvalidArgumentException);
}

- (void)testValueForKeyPath
{
	_myObject.objectValue = [[[MyObject alloc] init] autorelease];
	[_myObject.objectValue setObjectValue:
	    [[[MyObject alloc] init] autorelease]];
	[[_myObject.objectValue objectValue] setDoubleValue: 0.5];

	OTAssertEqual([[_myObject valueForKeyPath:
	    @"objectValue.objectValue.doubleValue"] doubleValue], 0.5);
}

- (void)testSetValueForKeyPath
{
	_myObject.objectValue = [[[MyObject alloc] init] autorelease];
	[_myObject.objectValue setObjectValue:
	    [[[MyObject alloc] init] autorelease]];
	[_myObject setValue: [OFNumber numberWithDouble: 0.75]
		 forKeyPath: @"objectValue.objectValue.doubleValue"];

	OTAssertEqual([[_myObject.objectValue objectValue] doubleValue], 0.75);
}
@end

@implementation MyObject
@synthesize objectValue = _objectValue, classValue = _classValue;
@synthesize boolValue = _boolValue, charValue = _charValue;
@synthesize shortValue = _shortValue, intValue = _intValue;
@synthesize longValue = _longValue, longLongValue = _longLongValue;
@synthesize unsignedCharValue = _unsignedCharValue;
@synthesize unsignedShortValue = _unsignedShortValue;
@synthesize unsignedIntValue = _unsignedIntValue;
@synthesize unsignedLongValue = _unsignedLongValue;
@synthesize unsignedLongLongValue = _unsignedLongLongValue;
@synthesize floatValue = _floatValue, doubleValue = _doubleValue;

- (void)dealloc
{
	[_objectValue release];

	[super dealloc];
}
@end











































































































































Renamed and modified new_tests/OFPBKDF2Tests.m [cd8293bb12] to tests/OFPBKDF2Tests.m [b154b79fa0].

42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
	[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",







|



















|



















|







42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
	[super dealloc];
}

/* Test vectors from RFC 6070 */

- (void)testRFC6070TestVector1
{
	unsigned char key[20];

	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[20];

	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[20];

	OFPBKDF2((OFPBKDF2Parameters){
		.HMAC                  = _HMAC,
		.iterations            = 4096,
		.salt                  = (unsigned char *)"salt",
		.saltLength            = 4,
		.password              = "password",
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
	    "\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",







|







104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
	    "\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[20];

	OFPBKDF2((OFPBKDF2Parameters){
		.HMAC                  = _HMAC,
		.iterations            = 16777216,
		.salt                  = (unsigned char *)"salt",
		.saltLength            = 4,
		.password              = "password",
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160

	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",







|







146
147
148
149
150
151
152
153
154
155
156
157
158
159
160

	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[16];

	OFPBKDF2((OFPBKDF2Parameters){
		.HMAC                  = _HMAC,
		.iterations            = 4096,
		.salt                  = (unsigned char *)"sa\0lt",
		.saltLength            = 5,
		.password              = "pass\0word",

Added tests/OFPluginTests.m version [b4655165af].













































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
/*
 * Copyright (c) 2008-2024 Jonathan Schleifer <js@nil.im>
 *
 * 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 tests/OFPropertyListTests.m version [2c2f0ce2a0].





































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
/*
 * Copyright (c) 2008-2024 Jonathan Schleifer <js@nil.im>
 *
 * 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)							\
	@"<?xml version=\"1.0\" encoding=\"UTF-8\"?>"			\
	@"<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" "	\
	@"\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">"		\
	@"<plist version=\"1.0\">\n"					\
	x @"\n"								\
	@"</plist>"

@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(
	    @"<string>Hello</string>") objectByParsingPropertyList],
	    @"Hello");
	OTAssertEqualObjects([PLIST(
	    @"<array>"
	    @" <string>Hello</string>"
	    @" <data>V29ybGQh</data>"
	    @" <date>2018-03-14T12:34:56Z</date>"
	    @" <true/>"
	    @" <false/>"
	    @" <real>12.25</real>"
	    @" <integer>-10</integer>"
	    @"</array>") objectByParsingPropertyList],
	    array);
	OTAssertEqualObjects([PLIST(
	    @"<dict>"
	    @" <key>array</key>"
	    @" <array>"
	    @"  <string>Hello</string>"
	    @"  <data>V29ybGQh</data>"
	    @"  <date>2018-03-14T12:34:56Z</date>"
	    @"  <true/>"
	    @"  <false/>"
	    @"  <real>12.25</real>"
	    @"  <integer>-10</integer>"
	    @" </array>"
	    @" <key>foo</key>"
	    @" <string>bar</string>"
	    @"</dict>") objectByParsingPropertyList],
	    ([OFDictionary dictionaryWithKeysAndObjects:
	    @"array", array,
	    @"foo", @"bar",
	    nil]));
}

- (void)testDetectUnsupportedVersion
{
	OTAssertThrowsSpecific(
	    [[PLIST(@"<string/>")
	    stringByReplacingOccurrencesOfString: @"1.0"
				      withString: @"1.1"]
	    objectByParsingPropertyList],
	    OFUnsupportedVersionException);
}

- (void)testDetectInvalidFormat
{
	OTAssertThrowsSpecific(
	    [PLIST(@"<string x='b'/>") objectByParsingPropertyList],
	    OFInvalidFormatException);

	OTAssertThrowsSpecific(
	    [PLIST(@"<string xmlns='foo'/>") objectByParsingPropertyList],
	    OFInvalidFormatException);

	OTAssertThrowsSpecific(
	    [PLIST(@"<dict count='0'/>") objectByParsingPropertyList],
	    OFInvalidFormatException);

	OTAssertThrowsSpecific(
	    [PLIST(@"<dict><key/><string/><key/></dict>")
	    objectByParsingPropertyList],
	    OFInvalidFormatException);

	OTAssertThrowsSpecific(
	    [PLIST(@"<dict><key x='x'/><string/></dict>")
	    objectByParsingPropertyList],
	    OFInvalidFormatException);
}
@end

Modified tests/OFSPXSocketTests.m from [262f8617dc] to [7025b286e5].

12
13
14
15
16
17
18

19
20

21


22



23
24
25
26
27
28
29
30
31
32
33





























































































































































34
35
36
37
38
39
40
 * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
 * file.
 */

#include "config.h"

#include <errno.h>


#import "TestsAppDelegate.h"




static OFString *const module = @"OFSPXSocket";




@interface SPXSocketDelegate: OFObject <OFSPXSocketDelegate>
{
@public
	OFSequencedPacketSocket *_expectedServerSocket;
	OFSPXSocket *_expectedClientSocket;
	unsigned char _expectedNode[IPX_NODE_LEN];
	uint32_t _expectedNetwork;
	uint16_t _expectedPort;
	bool _accepted;
	bool _connected;





























































































































































}
@end

@implementation SPXSocketDelegate
-    (bool)socket: (OFSequencedPacketSocket *)sock
  didAcceptSocket: (OFSequencedPacketSocket *)accepted
	exception: (id)exception







>

|
>

>
>
|
>
>
>











>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
 * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
 * file.
 */

#include "config.h"

#include <errno.h>
#include <string.h>

#import "ObjFW.h"
#import "ObjFWTest.h"

@interface OFSPXSocketTests: OTTestCase
{
	OFSPXSocket *_sockServer;
	OFSocketAddress _addrServer;
}
@end

@interface SPXSocketDelegate: OFObject <OFSPXSocketDelegate>
{
@public
	OFSequencedPacketSocket *_expectedServerSocket;
	OFSPXSocket *_expectedClientSocket;
	unsigned char _expectedNode[IPX_NODE_LEN];
	uint32_t _expectedNetwork;
	uint16_t _expectedPort;
	bool _accepted;
	bool _connected;
}
@end

@implementation OFSPXSocketTests
- (void)setUp
{
	const unsigned char zeroNode[IPX_NODE_LEN] = { 0 };

	_sockServer = [[OFSPXSocket alloc] init];

	@try {
		_addrServer = [_sockServer bindToNetwork: 0
						    node: zeroNode
						    port: 0];
	} @catch (OFBindSocketFailedException *e) {
		switch (e.errNo) {
		case EAFNOSUPPORT:
			OTSkip(@"IPX unsupported");
		case ESOCKTNOSUPPORT:
			OTSkip(@"SPX unsupported");
		case EADDRNOTAVAIL:
			OTSkip(@"IPX not configured");
		default:
			@throw e;
		}
	}
}

- (void)dealloc
{
	[_sockServer release];

	[super dealloc];
}

- (void)testSPXSocket
{
	OFSPXSocket *sockClient, *sockAccepted;
	const OFSocketAddress *addrAccepted;
	uint32_t network;
	unsigned char node[IPX_NODE_LEN], node2[IPX_NODE_LEN];
	uint16_t port;
	OFDictionary *networkInterfaces;
	char buffer[5];

	sockClient = [OFSPXSocket socket];

	network = OFSocketAddressIPXNetwork(&_addrServer);
	OFSocketAddressGetIPXNode(&_addrServer, node);
	port = OFSocketAddressIPXPort(&_addrServer);

	[_sockServer listen];

	/*
	 * Find any network interface with IPX and send to it. Any should be
	 * fine since we bound to 0.0.
	 */
	networkInterfaces = [OFSystemInfo networkInterfaces];
	for (OFString *name in networkInterfaces) {
		OFNetworkInterface interface = [networkInterfaces
		    objectForKey: name];
		OFData *addresses = [interface
		    objectForKey: OFNetworkInterfaceIPXAddresses];

		if (addresses.count == 0)
			continue;

		network = OFSocketAddressIPXNetwork([addresses itemAtIndex: 0]);
		OFSocketAddressGetIPXNode([addresses itemAtIndex: 0], node);
	}

	[sockClient connectToNetwork: network node: node port: port];

	sockAccepted = [_sockServer accept];
	[sockAccepted sendBuffer: "Hello" length: 5];

	OTAssertEqual([sockClient receiveIntoBuffer: buffer length: 5], 5);
	OTAssertEqual(memcmp(buffer, "Hello", 5), 0);

	addrAccepted = sockAccepted.remoteAddress;
	OFSocketAddressGetIPXNode(addrAccepted, node2);
	OTAssertEqual(memcmp(node, node2, IPX_NODE_LEN), 0);
}

- (void)testAsyncSPXSocket
{
	SPXSocketDelegate *delegate =
	    [[[SPXSocketDelegate alloc] init] autorelease];
	uint32_t network;
	unsigned char node[IPX_NODE_LEN];
	uint16_t port;
	OFDictionary *networkInterfaces;
	OFSPXSocket *sockClient;

	delegate->_expectedServerSocket = _sockServer;
	_sockServer.delegate = delegate;

	sockClient = [OFSPXSocket socket];
	delegate->_expectedClientSocket = sockClient;
	sockClient.delegate = delegate;

	[_sockServer listen];
	[_sockServer asyncAccept];

	network = OFSocketAddressIPXNetwork(&_addrServer);
	OFSocketAddressGetIPXNode(&_addrServer, node);
	port = OFSocketAddressIPXPort(&_addrServer);

	/*
	 * Find any network interface with IPX and send to it. Any should be
	 * fine since we bound to 0.0.
	 */
	networkInterfaces = [OFSystemInfo networkInterfaces];
	for (OFString *name in networkInterfaces) {
		OFNetworkInterface interface = [networkInterfaces
		    objectForKey: name];
		OFData *addresses = [interface
		    objectForKey: OFNetworkInterfaceIPXAddresses];

		if (addresses.count == 0)
			continue;

		network = OFSocketAddressIPXNetwork([addresses itemAtIndex: 0]);
		OFSocketAddressGetIPXNode([addresses itemAtIndex: 0], node);
	}

	delegate->_expectedNetwork = network =
	    OFSocketAddressIPXNetwork(&_addrServer);
	OFSocketAddressGetIPXNode(&_addrServer, node);
	memcpy(delegate->_expectedNode, node, IPX_NODE_LEN);
	delegate->_expectedPort = port = OFSocketAddressIPXPort(&_addrServer);

	@try {
		[sockClient asyncConnectToNetwork: network
					     node: node
					     port: port];

		[[OFRunLoop mainRunLoop] runUntilDate:
		    [OFDate dateWithTimeIntervalSinceNow: 2]];

		OTAssertTrue(delegate->_accepted);
		OTAssertTrue(delegate->_connected);
	} @catch (OFObserveKernelEventsFailedException *e) {
		/*
		 * Make sure it doesn't stay in the run loop and throws again
		 * next time we run the run loop.
		 */
		[sockClient cancelAsyncRequests];
		[_sockServer cancelAsyncRequests];

		switch (e.errNo) {
		case ENOTSOCK:
			OTSkip(@"select() not supported for SPX");
		default:
			@throw e;
		}
	}
}
@end

@implementation SPXSocketDelegate
-    (bool)socket: (OFSequencedPacketSocket *)sock
  didAcceptSocket: (OFSequencedPacketSocket *)accepted
	exception: (id)exception
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
	    network == _expectedNetwork &&
	    memcmp(node, _expectedNode, IPX_NODE_LEN) == 0 &&
	    port == _expectedPort && exception == nil);

	if (_accepted && _connected)
		[[OFRunLoop mainRunLoop] stop];
}
@end

@implementation TestsAppDelegate (OFSPXSocketTests)
- (void)SPXSocketTests
{
	const unsigned char zeroNode[IPX_NODE_LEN] = { 0 };
	void *pool = objc_autoreleasePoolPush();
	OFSPXSocket *sockClient, *sockServer = nil, *sockAccepted;
	OFSocketAddress address1;
	const OFSocketAddress *address2;
	uint32_t network;
	unsigned char node[IPX_NODE_LEN], node2[IPX_NODE_LEN];
	uint16_t port;
	OFDictionary *networkInterfaces;
	char buffer[5];
	SPXSocketDelegate *delegate;

	TEST(@"+[socket]", (sockClient = [OFSPXSocket socket]) &&
	    (sockServer = [OFSPXSocket socket]))

	@try {
		TEST(@"-[bindToNetwork:node:port:]",
		    R(address1 = [sockServer bindToNetwork: 0
						      node: zeroNode
						      port: 0]))
	} @catch (OFBindSocketFailedException *e) {
		switch (e.errNo) {
		case EAFNOSUPPORT:
			[OFStdOut setForegroundColor: [OFColor lime]];
			[OFStdOut writeLine:
			    @"\r[OFSPXSocket] -[bindToNetwork:node:port:]: "
			    @"IPX unsupported, skipping tests"];
			break;
		case ESOCKTNOSUPPORT:
			[OFStdOut setForegroundColor: [OFColor lime]];
			[OFStdOut writeLine:
			    @"\r[OFSPXSocket] -[bindToNetwork:node:port:]: "
			    @"SPX unsupported, skipping tests"];
			break;
		case EADDRNOTAVAIL:
			[OFStdOut setForegroundColor: [OFColor lime]];
			[OFStdOut writeLine:
			    @"\r[OFSPXSocket] -[bindToNetwork:node:port:]: "
			    @"IPX not configured, skipping tests"];
			break;
		default:
			@throw e;
		}

		objc_autoreleasePoolPop(pool);
		return;
	}

	network = OFSocketAddressIPXNetwork(&address1);
	OFSocketAddressGetIPXNode(&address1, node);
	port = OFSocketAddressIPXPort(&address1);

	TEST(@"-[listen]", R([sockServer listen]))

	/*
	 * Find any network interface with IPX and send to it. Any should be
	 * fine since we bound to 0.0.
	 */
	networkInterfaces = [OFSystemInfo networkInterfaces];
	for (OFString *name in networkInterfaces) {
		OFNetworkInterface interface = [networkInterfaces
		    objectForKey: name];
		OFData *addresses = [interface
		    objectForKey: OFNetworkInterfaceIPXAddresses];

		if (addresses.count == 0)
			continue;

		network = OFSocketAddressIPXNetwork([addresses itemAtIndex: 0]);
		OFSocketAddressGetIPXNode([addresses itemAtIndex: 0], node);
	}

	TEST(@"-[connectToNetwork:node:port:]",
	    R([sockClient connectToNetwork: network node: node port: port]))

	TEST(@"-[accept]", (sockAccepted = [sockServer accept]))

	TEST(@"-[sendBuffer:length:]",
	    R([sockAccepted sendBuffer: "Hello" length: 5]))

	TEST(@"-[receiveIntoBuffer:length:]",
	    [sockClient receiveIntoBuffer: buffer length: 5] == 5 &&
	    memcmp(buffer, "Hello", 5) == 0)

	TEST(@"-[remoteAddress]",
	    (address2 = sockAccepted.remoteAddress) &&
	    R(OFSocketAddressGetIPXNode(address2, node2)) &&
	    memcmp(node, node2, IPX_NODE_LEN) == 0)

	delegate = [[[SPXSocketDelegate alloc] init] autorelease];

	sockServer = [OFSPXSocket socket];
	delegate->_expectedServerSocket = sockServer;
	sockServer.delegate = delegate;

	sockClient = [OFSPXSocket socket];
	delegate->_expectedClientSocket = sockClient;
	sockClient.delegate = delegate;

	address1 = [sockServer bindToNetwork: 0 node: zeroNode port: 0];
	[sockServer listen];
	[sockServer asyncAccept];

	delegate->_expectedNetwork = network =
	    OFSocketAddressIPXNetwork(&address1);
	OFSocketAddressGetIPXNode(&address1, node);
	memcpy(delegate->_expectedNode, node, IPX_NODE_LEN);
	delegate->_expectedPort = port = OFSocketAddressIPXPort(&address1);

	@try {
		[sockClient asyncConnectToNetwork: network
					     node: node
					     port: port];

		[[OFRunLoop mainRunLoop] runUntilDate:
		    [OFDate dateWithTimeIntervalSinceNow: 2]];

		TEST(@"-[asyncAccept] & -[asyncConnectToNetwork:node:port:]",
		    delegate->_accepted && delegate->_connected)
	} @catch (OFObserveKernelEventsFailedException *e) {
		/*
		 * Make sure it doesn't stay in the run loop and throws again
		 * next time we run the run loop.
		 */
		[sockClient cancelAsyncRequests];
		[sockServer cancelAsyncRequests];

		switch (e.errNo) {
		case ENOTSOCK:
			[OFStdOut setForegroundColor: [OFColor lime]];
			[OFStdOut writeLine:
			    @"\r[OFSPXSocket] -[asyncAccept] & "
			    @"-[asyncConnectToNetwork:node:port:]: select() "
			    @"not supported for SPX, skipping test"];
			break;
		default:
			@throw e;
		}
	}

	objc_autoreleasePoolPop(pool);
}
@end








<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
226
227
228
229
230
231
232
233



















































































































































	    network == _expectedNetwork &&
	    memcmp(node, _expectedNode, IPX_NODE_LEN) == 0 &&
	    port == _expectedPort && exception == nil);

	if (_accepted && _connected)
		[[OFRunLoop mainRunLoop] stop];
}
@end



















































































































































Modified tests/OFSPXStreamSocketTests.m from [37e7d0cfd1] to [096521a07d].

12
13
14
15
16
17
18

19
20

21


22



23
24
25
26
27
28
29
30
31
32
33
































































































































































34
35
36
37
38
39
40
 * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
 * file.
 */

#include "config.h"

#include <errno.h>


#import "TestsAppDelegate.h"




static OFString *const module = @"OFSPXStreamSocket";




@interface SPXStreamSocketDelegate: OFObject <OFSPXStreamSocketDelegate>
{
@public
	OFStreamSocket *_expectedServerSocket;
	OFSPXStreamSocket *_expectedClientSocket;
	uint32_t _expectedNetwork;
	unsigned char _expectedNode[IPX_NODE_LEN];
	uint16_t _expectedPort;
	bool _accepted;
	bool _connected;
































































































































































}
@end

@implementation SPXStreamSocketDelegate
-    (bool)socket: (OFStreamSocket *)sock
  didAcceptSocket: (OFStreamSocket *)accepted
	exception: (id)exception







>

|
>

>
>
|
>
>
>











>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
 * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
 * file.
 */

#include "config.h"

#include <errno.h>
#include <string.h>

#import "ObjFW.h"
#import "ObjFWTest.h"

@interface OFSPXStreamSocketTests: OTTestCase
{
	OFSPXStreamSocket *_sockServer;
	OFSocketAddress _addrServer;
}
@end

@interface SPXStreamSocketDelegate: OFObject <OFSPXStreamSocketDelegate>
{
@public
	OFStreamSocket *_expectedServerSocket;
	OFSPXStreamSocket *_expectedClientSocket;
	uint32_t _expectedNetwork;
	unsigned char _expectedNode[IPX_NODE_LEN];
	uint16_t _expectedPort;
	bool _accepted;
	bool _connected;
}
@end

@implementation OFSPXStreamSocketTests
- (void)setUp
{
	const unsigned char zeroNode[IPX_NODE_LEN] = { 0 };

	_sockServer = [[OFSPXStreamSocket alloc] init];

	@try {
		_addrServer = [_sockServer bindToNetwork: 0
						    node: zeroNode
						    port: 0];
	} @catch (OFBindSocketFailedException *e) {
		switch (e.errNo) {
		case EAFNOSUPPORT:
			OTSkip(@"IPX unsupported");
		case ESOCKTNOSUPPORT:
		case EPROTONOSUPPORT:
			OTSkip(@"SPX unsupported");
		case EADDRNOTAVAIL:
			OTSkip(@"IPX not configured");
		default:
			@throw e;
		}
	}
}

- (void)dealloc
{
	[_sockServer release];

	[super dealloc];
}

- (void)testSPXStreamSocket
{
	OFSPXStreamSocket *sockClient, *sockAccepted;
	const OFSocketAddress *addrAccepted;
	uint32_t network;
	unsigned char node[IPX_NODE_LEN], node2[IPX_NODE_LEN];
	uint16_t port;
	OFDictionary *networkInterfaces;
	char buffer[5];

	sockClient = [OFSPXStreamSocket socket];

	network = OFSocketAddressIPXNetwork(&_addrServer);
	OFSocketAddressGetIPXNode(&_addrServer, node);
	port = OFSocketAddressIPXPort(&_addrServer);

	[_sockServer listen];

	/*
	 * Find any network interface with IPX and send to it. Any should be
	 * fine since we bound to 0.0.
	 */
	networkInterfaces = [OFSystemInfo networkInterfaces];
	for (OFString *name in networkInterfaces) {
		OFNetworkInterface interface = [networkInterfaces
		    objectForKey: name];
		OFData *addresses = [interface
		    objectForKey: OFNetworkInterfaceIPXAddresses];

		if (addresses.count == 0)
			continue;

		network = OFSocketAddressIPXNetwork([addresses itemAtIndex: 0]);
		OFSocketAddressGetIPXNode([addresses itemAtIndex: 0], node);
	}

	[sockClient connectToNetwork: network node: node port: port];

	sockAccepted = [_sockServer accept];
	[sockAccepted writeBuffer: "Hello" length: 5];

	/* Test reassembly (this would not work with OFSPXSocket) */
	OTAssertEqual([sockClient readIntoBuffer: buffer length: 2], 2);
	OTAssertEqual([sockClient readIntoBuffer: buffer + 2 length: 3], 3);
	OTAssertEqual(memcmp(buffer, "Hello", 5), 0);

	addrAccepted = sockAccepted.remoteAddress;
	OFSocketAddressGetIPXNode(addrAccepted, node2);
	OTAssertEqual(memcmp(node, node2, IPX_NODE_LEN), 0);
}

- (void)testAsyncSPXStreamSocket
{
	SPXStreamSocketDelegate *delegate =
	    [[[SPXStreamSocketDelegate alloc] init] autorelease];
	uint32_t network;
	unsigned char node[IPX_NODE_LEN];
	uint16_t port;
	OFDictionary *networkInterfaces;
	OFSPXStreamSocket *sockClient;

	delegate->_expectedServerSocket = _sockServer;
	_sockServer.delegate = delegate;

	sockClient = [OFSPXStreamSocket socket];
	delegate->_expectedClientSocket = sockClient;
	sockClient.delegate = delegate;

	[_sockServer listen];
	[_sockServer asyncAccept];

	network = OFSocketAddressIPXNetwork(&_addrServer);
	OFSocketAddressGetIPXNode(&_addrServer, node);
	port = OFSocketAddressIPXPort(&_addrServer);

	/*
	 * Find any network interface with IPX and send to it. Any should be
	 * fine since we bound to 0.0.
	 */
	networkInterfaces = [OFSystemInfo networkInterfaces];
	for (OFString *name in networkInterfaces) {
		OFNetworkInterface interface = [networkInterfaces
		    objectForKey: name];
		OFData *addresses = [interface
		    objectForKey: OFNetworkInterfaceIPXAddresses];

		if (addresses.count == 0)
			continue;

		network = OFSocketAddressIPXNetwork([addresses itemAtIndex: 0]);
		OFSocketAddressGetIPXNode([addresses itemAtIndex: 0], node);
	}

	delegate->_expectedNetwork = network =
	    OFSocketAddressIPXNetwork(&_addrServer);
	OFSocketAddressGetIPXNode(&_addrServer, node);
	memcpy(delegate->_expectedNode, node, IPX_NODE_LEN);
	delegate->_expectedPort = port = OFSocketAddressIPXPort(&_addrServer);

	@try {
		[sockClient asyncConnectToNetwork: network
					     node: node
					     port: port];

		[[OFRunLoop mainRunLoop] runUntilDate:
		    [OFDate dateWithTimeIntervalSinceNow: 2]];

		OTAssertTrue(delegate->_accepted);
		OTAssertTrue(delegate->_connected);
	} @catch (OFObserveKernelEventsFailedException *e) {
		/*
		 * Make sure it doesn't stay in the run loop and throws again
		 * next time we run the run loop.
		 */
		[sockClient cancelAsyncRequests];
		[_sockServer cancelAsyncRequests];

		switch (e.errNo) {
		case ENOTSOCK:
			OTSkip(@"select() not supported for SPX");
		default:
			@throw e;
		}
	}
}
@end

@implementation SPXStreamSocketDelegate
-    (bool)socket: (OFStreamSocket *)sock
  didAcceptSocket: (OFStreamSocket *)accepted
	exception: (id)exception
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
	    network == _expectedNetwork &&
	    memcmp(node, _expectedNode, IPX_NODE_LEN) == 0 &&
	    port == _expectedPort && exception == nil);

	if (_accepted && _connected)
		[[OFRunLoop mainRunLoop] stop];
}
@end

@implementation TestsAppDelegate (OFSPXStreamSocketTests)
- (void)SPXStreamSocketTests
{
	const unsigned char zeroNode[IPX_NODE_LEN] = { 0 };
	void *pool = objc_autoreleasePoolPush();
	OFSPXStreamSocket *sockClient, *sockServer = nil, *sockAccepted;
	OFSocketAddress address1;
	const OFSocketAddress *address2;
	uint32_t network;
	unsigned char node[IPX_NODE_LEN], node2[IPX_NODE_LEN];
	uint16_t port;
	OFDictionary *networkInterfaces;
	char buffer[5];
	SPXStreamSocketDelegate *delegate;

	TEST(@"+[socket]", (sockClient = [OFSPXStreamSocket socket]) &&
	    (sockServer = [OFSPXStreamSocket socket]))

	@try {
		TEST(@"-[bindToNetwork:node:port:]",
		    R(address1 = [sockServer bindToNetwork: 0
						      node: zeroNode
						      port: 0]))
	} @catch (OFBindSocketFailedException *e) {
		switch (e.errNo) {
		case EAFNOSUPPORT:
			[OFStdOut setForegroundColor: [OFColor lime]];
			[OFStdOut writeLine:
			    @"\r[OFSPXStreamSocket] -[bindToNetwork:node:"
			    @"port:]: IPX unsupported, skipping tests"];
			break;
		case ESOCKTNOSUPPORT:
		case EPROTONOSUPPORT:
			[OFStdOut setForegroundColor: [OFColor lime]];
			[OFStdOut writeLine:
			    @"\r[OFSPXStreamSocket] -[bindToNetwork:node:"
			    @"port:]: SPX unsupported, skipping tests"];
			break;
		case EADDRNOTAVAIL:
			[OFStdOut setForegroundColor: [OFColor lime]];
			[OFStdOut writeLine:
			    @"\r[OFSPXStreamSocket] -[bindToNetwork:node:"
			    @"port:]: IPX not configured, skipping tests"];
			break;
		default:
			@throw e;
		}

		objc_autoreleasePoolPop(pool);
		return;
	}

	network = OFSocketAddressIPXNetwork(&address1);
	OFSocketAddressGetIPXNode(&address1, node);
	port = OFSocketAddressIPXPort(&address1);

	TEST(@"-[listen]", R([sockServer listen]))

	/*
	 * Find any network interface with IPX and send to it. Any should be
	 * fine since we bound to 0.0.
	 */
	networkInterfaces = [OFSystemInfo networkInterfaces];
	for (OFString *name in networkInterfaces) {
		OFNetworkInterface interface = [networkInterfaces
		    objectForKey: name];
		OFData *addresses = [interface
		    objectForKey: OFNetworkInterfaceIPXAddresses];

		if (addresses.count == 0)
			continue;

		network = OFSocketAddressIPXNetwork([addresses itemAtIndex: 0]);
		OFSocketAddressGetIPXNode([addresses itemAtIndex: 0], node);
	}

	TEST(@"-[connectToNetwork:node:port:]",
	    R([sockClient connectToNetwork: network node: node port: port]))

	TEST(@"-[accept]", (sockAccepted = [sockServer accept]))

	/* Test reassembly (this would not work with OFSPXSocket) */
	TEST(@"-[writeBuffer:length:]",
	    R([sockAccepted writeBuffer: "Hello" length: 5]))

	TEST(@"-[readIntoBuffer:length:]",
	    [sockClient readIntoBuffer: buffer length: 2] == 2 &&
	    memcmp(buffer, "He", 2) == 0 &&
	    [sockClient readIntoBuffer: buffer length: 3] == 3 &&
	    memcmp(buffer, "llo", 3) == 0)

	TEST(@"-[remoteAddress]",
	    (address2 = sockAccepted.remoteAddress) &&
	    R(OFSocketAddressGetIPXNode(address2, node2)) &&
	    memcmp(node, node2, IPX_NODE_LEN) == 0)

	delegate = [[[SPXStreamSocketDelegate alloc] init] autorelease];

	sockServer = [OFSPXStreamSocket socket];
	delegate->_expectedServerSocket = sockServer;
	sockServer.delegate = delegate;

	sockClient = [OFSPXStreamSocket socket];
	delegate->_expectedClientSocket = sockClient;
	sockClient.delegate = delegate;

	address1 = [sockServer bindToNetwork: 0 node: zeroNode port: 0];
	[sockServer listen];
	[sockServer asyncAccept];

	delegate->_expectedNetwork = network =
	    OFSocketAddressIPXNetwork(&address1);
	OFSocketAddressGetIPXNode(&address1, node);
	memcpy(delegate->_expectedNode, node, IPX_NODE_LEN);
	delegate->_expectedPort = port = OFSocketAddressIPXPort(&address1);

	@try {
		[sockClient asyncConnectToNetwork: network
					     node: node
					     port: port];

		[[OFRunLoop mainRunLoop] runUntilDate:
		    [OFDate dateWithTimeIntervalSinceNow: 2]];

		TEST(@"-[asyncAccept] & -[asyncConnectToNetwork:node:port:]",
		    delegate->_accepted && delegate->_connected)
	} @catch (OFObserveKernelEventsFailedException *e) {
		/*
		 * Make sure it doesn't stay in the run loop and throws again
		 * next time we run the run loop.
		 */
		[sockClient cancelAsyncRequests];
		[sockServer cancelAsyncRequests];

		switch (e.errNo) {
		case ENOTSOCK:
			[OFStdOut setForegroundColor: [OFColor lime]];
			[OFStdOut writeLine:
			    @"\r[OFSPXStreamSocket] -[asyncAccept] & "
			    @"-[asyncConnectToNetwork:node:port:]: select() "
			    @"not supported for SPX, skipping test"];
			break;
		default:
			@throw e;
		}
	}

	objc_autoreleasePoolPop(pool);
}
@end








<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
229
230
231
232
233
234
235
236























































































































































	    network == _expectedNetwork &&
	    memcmp(node, _expectedNode, IPX_NODE_LEN) == 0 &&
	    port == _expectedPort && exception == nil);

	if (_accepted && _connected)
		[[OFRunLoop mainRunLoop] stop];
}
@end























































































































































Renamed and modified new_tests/OFScryptTests.m [0924135d9a] to tests/OFScryptTests.m [88a05d2135].

101
102
103
104
105
106
107


108
109
110
111
112
113
114
115


116


117
118
119
120
121
122
123
124
	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







>
>








>
>
|
>
>
|







101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
	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
};
/* Nintendo DS does not have enough RAM for the second test vector. */
#ifndef OF_NINTENDO_DS
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
};
#endif
/*
 * The third test vector is too expensive for m68k.
 * Nintendo DS does not have enough RAM for the third test vector.
 */
#if !defined(OF_M68K) && !defined(OF_NINTENDO_DS)
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
179
180
181
182
183
184
185


186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204

205

206


207
208
209
210
211
212
213
214
		.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,







>
>



















>

>
|
>
>
|







185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
		.keyLength             = 64,
		.allowsSwappableMemory = true
	});

	OTAssertEqual(memcmp(output, testVector1, 64), 0);
}

/* Nintendo DS does not have enough RAM for the second test vector. */
#ifndef OF_NINTENDO_DS
- (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);
}
#endif

/*
 * The third test vector is too expensive for m68k.
 * Nintendo DS does not have enough RAM for the third test vector.
 */
#if !defined(OF_M68K) && !defined(OF_NINTENDO_DS)
- (void)testRFC7941TestVector3
{
	unsigned char output[64];

	OFScrypt((OFScryptParameters){
		.blockSize             = 8,
		.costFactor            = 16384,

Added tests/OFSetTests.h version [bf9db612f3].



















































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/*
 * Copyright (c) 2008-2024 Jonathan Schleifer <js@nil.im>
 *
 * 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 OFSetTests: OTTestCase
{
	OFSet *_set;
}

@property (readonly, nonatomic) Class setClass;
@end

Modified tests/OFSetTests.m from [4668cbb71a] to [7ee6122d59].

11
12
13
14
15
16
17
18
19


20


21





22

23

24

25
26

27
28
29
30
31
32

33


34

35




36
37




38
39
40
41

42







43
44


45

46



47



48






49
50
51





52












53
54


55
56

57

58
59
60


61






62

63
64
65
66
67
68


69

70













71


72
73


74

75
76


77

78




79



80


81



82
83
84
85
86
87
88
89
90
91
92
93
94
95
 * 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 "OFSet.h"


#import "OFConcreteSet.h"





#import "OFConcreteMutableSet.h"



static OFString *module;


@interface SimpleSet: OFSet

{
	OFMutableSet *_set;
}
@end

@interface SimpleMutableSet: OFMutableSet

{


	OFMutableSet *_set;

	unsigned long _mutations;




}
@end





@implementation SimpleSet
- (instancetype)init
{

	self = [super init];








	@try {


		_set = [[OFMutableSet alloc] init];

	} @catch (id e) {



		[self release];



		@throw e;






	}

	return self;





}













- (instancetype)initWithSet: (OFSet *)set


{
	self = [super init];



	@try {
		_set = [[OFMutableSet alloc] initWithSet: set];
	} @catch (id e) {


		[self release];






		@throw e;

	}

	return self;
}

- (instancetype)initWithArray: (OFArray *)array


{

	self = [super init];
















	@try {
		_set = [[OFMutableSet alloc] initWithArray: array];


	} @catch (id e) {

		[self release];
		@throw e;


	}






	return self;



}






- (instancetype)initWithObject: (id)firstObject arguments: (va_list)arguments
{
	self = [super init];

	@try {
		_set = [[OFMutableSet alloc] initWithObject: firstObject
						  arguments: arguments];
	} @catch (id e) {
		[self release];
		@throw e;
	}

	return self;
}







|

>
>
|
>
>
|
>
>
>
>
>
|
>
|
>
|
>
|
|
>

|
|
|
|
|
>

>
>
|
>
|
>
>
>
>

|
>
>
>
>
|
|
|

>
|
>
>
>
>
>
>
>
|
|
>
>
|
>
|
>
>
>
|
>
>
>
|
>
>
>
>
>
>
|

<
>
>
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
|
|
>
>
|
<
>
|
>
|
|
<
>
>
|
>
>
>
>
>
>
|
>


|


<
>
>

>
|
>
>
>
>
>
>
>
>
>
>
>
>
>

>
>
|
<
>
>
|
>
|
|
>
>
|
>

>
>
>
>
|
>
>
>
|
>
>
|
>
>
>
|




|
<







11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98

99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121

122
123
124
125
126

127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142

143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164

165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196

197
198
199
200
201
202
203
 * 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 "OFSetTests.h"

@interface CustomSet: OFSet
{
	OFSet *_set;
}
@end

@implementation OFSetTests
- (Class)setClass
{
	return [CustomSet class];
}

- (void)setUp
{
	[super setUp];

	_set = [[OFSet alloc] initWithObjects: @"foo", @"bar", @"baz", nil];
}

- (void)dealloc
{
	[_set release];

	[super dealloc];
}

- (void)testSetWithArray
{
	OTAssertEqualObjects([self.setClass setWithArray:
	    ([OFArray arrayWithObjects: @"foo", @"bar", @"baz", @"foo", nil])],
	    _set);
}

- (void)testIsEqual
{
	OTAssertEqualObjects(_set,
	    ([OFSet setWithObjects: @"foo", @"bar", @"baz", nil]));
}

- (void)testHash
{
	OTAssertEqual(_set.hash,
	    [([OFSet setWithObjects: @"foo", @"bar", @"baz", nil]) hash]);
}

- (void)testDescription
{
	OFString *description = _set.description;

	OTAssert(
	    [description isEqual: @"{(\n\tfoo,\n\tbar,\n\tbaz\n)}"] ||
	    [description isEqual: @"{(\n\tfoo,\n\tbaz,\n\tbar\n)}"] ||
	    [description isEqual: @"{(\n\tbar,\n\tfoo,\n\tbaz\n)}"] ||
	    [description isEqual: @"{(\n\tbar,\n\tbaz,\n\tfoo\n)}"] ||
	    [description isEqual: @"{(\n\tbaz,\n\tfoo,\n\tbar\n)}"] ||
	    [description isEqual: @"{(\n\tbaz,\n\tbar,\n\tfoo\n)}"]);
}

- (void)testCopy
{
	OTAssertEqualObjects([[_set copy] autorelease], _set);
}

- (void)testIsSubsetOfSet
{
	OTAssertTrue([([OFSet setWithObjects: @"foo", nil])
	    isSubsetOfSet: _set]);
	OTAssertFalse([([OFSet setWithObjects: @"foo", @"Foo", nil])
	    isSubsetOfSet: _set]);
}

- (void)testIntersectsSet
{
	OTAssertTrue([([OFSet setWithObjects: @"foo", @"Foo", nil])
	    intersectsSet: _set]);
	OTAssertFalse([([OFSet setWithObjects: @"Foo", nil])
	    intersectsSet: _set]);
}


- (void)testEnumerator
{
	OFEnumerator *enumerator = [_set objectEnumerator];
	bool seenFoo = false, seenBar = false, seenBaz = false;
	OFString *object;

	while ((object = [enumerator nextObject]) != nil) {
		if ([object isEqual: @"foo"]) {
			OTAssertFalse(seenFoo);
			seenFoo = true;
		} else if ([object isEqual: @"bar"]) {
			OTAssertFalse(seenBar);
			seenBar = true;
		} else if ([object isEqual: @"baz"]) {
			OTAssertFalse(seenBaz);
			seenBaz = true;
		} else
			OTAssert(false, @"Unexpected object seen: %@", object);
	}

	OTAssert(seenFoo && seenBar && seenBaz);
}


- (void)testFastEnumeration
{
	bool seenFoo = false, seenBar = false, seenBaz = false;

	for (OFString *object in _set) {

		if ([object isEqual: @"foo"]) {
			OTAssertFalse(seenFoo);
			seenFoo = true;
		} else if ([object isEqual: @"bar"]) {
			OTAssertFalse(seenBar);
			seenBar = true;
		} else if ([object isEqual: @"baz"]) {
			OTAssertFalse(seenBaz);
			seenBaz = true;
		} else
			OTAssert(false, @"Unexpected object seen: %@", object);
	}

	OTAssert(seenFoo && seenBar && seenBaz);
}


#ifdef OF_HAVE_BLOCKS
- (void)testEnumerateObjectsUsingBlock
{
	__block bool seenFoo = false, seenBar = false, seenBaz = false;

	[_set enumerateObjectsUsingBlock: ^ (id object, bool *stop) {
		if ([object isEqual: @"foo"]) {
			OTAssertFalse(seenFoo);
			seenFoo = true;
		} else if ([object isEqual: @"bar"]) {
			OTAssertFalse(seenBar);
			seenBar = true;
		} else if ([object isEqual: @"baz"]) {
			OTAssertFalse(seenBaz);
			seenBaz = true;
		} else
			OTAssert(false, @"Unexpected object seen: %@", object);
	}];

	OTAssert(seenFoo && seenBar && seenBaz);
}


- (void)testFilteredSetUsingBlock
{
	OFSet *filteredSet = [_set filteredSetUsingBlock: ^ (id object) {
		return [object hasPrefix: @"ba"];
	}];

	OTAssertEqualObjects(filteredSet,
	    ([OFSet setWithObjects: @"bar", @"baz", nil]));
}
#endif

- (void)testValueForKey
{
	OFSet *set = [[self.setClass setWithObjects:
	    @"a", @"ab", @"abc", @"b", nil] valueForKey: @"length"];

	OTAssertEqualObjects(set, ([OFSet  setWithObjects:
	    [OFNumber numberWithInt: 1], [OFNumber numberWithInt: 2],
	    [OFNumber numberWithInt: 3], nil]));

	OTAssertEqualObjects([set valueForKey: @"@count"],
	    [OFNumber numberWithInt: 3]);
}
@end

@implementation CustomSet
- (instancetype)initWithObjects: (id const *)objects count: (size_t)count
{
	self = [super init];

	@try {
		_set = [[OFSet alloc] initWithObjects: objects count: count];

	} @catch (id e) {
		[self release];
		@throw e;
	}

	return self;
}
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
	return [_set containsObject: object];
}

- (OFEnumerator *)objectEnumerator
{
	return [_set objectEnumerator];
}
@end

@implementation SimpleMutableSet
+ (void)initialize
{
	if (self == [SimpleMutableSet class])
		[self inheritMethodsFromClass: [SimpleSet class]];
}

- (void)addObject: (id)object
{
	bool existed = [self containsObject: object];

	[_set addObject: object];

	if (existed)
		_mutations++;
}

- (void)removeObject: (id)object
{
	bool existed = [self containsObject: object];

	[_set removeObject: object];

	if (existed)
		_mutations++;
}

- (int)countByEnumeratingWithState: (OFFastEnumerationState *)state
			   objects: (id *)objects
			     count: (int)count
{
	int ret = [_set countByEnumeratingWithState: state
					    objects: objects
					      count: count];

	state->mutationsPtr = &_mutations;

	return ret;
}
@end

@implementation TestsAppDelegate (OFSetTests)
- (void)setTestsWithClass: (Class)setClass mutableClass: (Class)mutableSetClass
{
	void *pool = objc_autoreleasePoolPush();
	OFSet *set1, *set2;
	OFMutableSet *mutableSet;
	bool ok;
	size_t i;

	TEST(@"+[setWithArray:]",
	    (set1 = [setClass setWithArray: [OFArray arrayWithObjects: @"foo",
	    @"bar", @"baz", @"foo", @"x", nil]]))

	TEST(@"+[setWithObjects:]",
	    (set2 = [setClass setWithObjects: @"foo", @"bar", @"baz", @"bar",
	    @"x", nil]))

	TEST(@"-[isEqual:]", [set1 isEqual: set2])

	TEST(@"-[hash]", set1.hash == set2.hash)

	TEST(@"-[description]",
	    [set1.description
	    isEqual: @"{(\n\tx,\n\tbar,\n\tfoo,\n\tbaz\n)}"] &&
	    [set1.description isEqual: set2.description])

	TEST(@"-[copy]", [set1 isEqual: [[set1 copy] autorelease]])

	TEST(@"-[mutableCopy]",
	    [set1 isEqual: [[set1 mutableCopy] autorelease]]);

	mutableSet = [mutableSetClass setWithSet: set1];

	TEST(@"-[addObject:]",
	    R([mutableSet addObject: @"baz"]) && [mutableSet isEqual: set2] &&
	    R([mutableSet addObject: @"y"]) && [mutableSet isEqual:
	    [setClass setWithObjects: @"foo", @"bar", @"baz", @"x", @"y", nil]])

	TEST(@"-[removeObject:]",
	    R([mutableSet removeObject: @"y"]) && [mutableSet isEqual: set1])

	TEST(@"-[isSubsetOfSet:]",
	    R([mutableSet removeObject: @"foo"]) &&
	    [mutableSet isSubsetOfSet: set1] &&
	    ![set1 isSubsetOfSet: mutableSet]);

	TEST(@"-[intersectsSet:]",
	    [(set2 = [setClass setWithObjects: @"x", nil])
	    intersectsSet: set1] && [set1 intersectsSet: set2] &&
	    ![[setClass setWithObjects: @"1", nil] intersectsSet: set1]);

	TEST(@"-[minusSet:]",
	    R([mutableSet minusSet: [setClass setWithObjects: @"x", nil]]) &&
	    [mutableSet isEqual: [setClass setWithObjects:
	    @"baz", @"bar", nil]])

	TEST(@"-[intersectSet:]",
	    R([mutableSet intersectSet: [setClass setWithObjects:
	    @"baz", nil]]) && [mutableSet isEqual: [setClass setWithObjects:
	    @"baz", nil]])

	TEST(@"-[unionSet:]",
	    R([mutableSet unionSet: [setClass setWithObjects:
	    @"x", @"bar", nil]]) && [mutableSet isEqual:
	    [setClass setWithObjects: @"baz", @"bar", @"x", nil]])

	TEST(@"-[removeAllObjects]",
	    R([mutableSet removeAllObjects]) &&
	    [mutableSet isEqual: [setClass set]])

	ok = true;
	i = 0;

	for (OFString *s in set1) {
		switch (i) {
		case 0:
			if (![s isEqual: @"x"])
				ok = false;
			break;
		case 1:
			if (![s isEqual: @"bar"])
				ok = false;
			break;
		case 2:
			if (![s isEqual: @"foo"])
				ok = false;
			break;
		case 3:
			if (![s isEqual: @"baz"])
				ok = false;
			break;
		}

		i++;
	}

	if (i != 4)
		ok = false;

	TEST(@"Fast enumeration", ok)

	ok = false;
	[mutableSet addObject: @"foo"];
	[mutableSet addObject: @"bar"];
	@try {
		for (OFString *s in mutableSet)
			[mutableSet removeObject: s];
	} @catch (OFEnumerationMutationException *e) {
		ok = true;
	}

	TEST(@"Detection of mutation during Fast Enumeration", ok);

	TEST(@"-[valueForKey:]",
	    [(set1 = [[setClass setWithObjects: @"a", @"ab", @"abc", @"b", nil]
	    valueForKey: @"length"]) isEqual: [setClass setWithObjects:
	    [OFNumber numberWithInt: 1], [OFNumber numberWithInt: 2],
	    [OFNumber numberWithInt: 3], nil]] &&
	    [[set1 valueForKey: @"@count"] isEqual:
	    [OFNumber numberWithInt: 3]])

	objc_autoreleasePoolPop(pool);
}

- (void)setTests
{
	module = @"OFSet";
	[self setTestsWithClass: [SimpleSet class]
		   mutableClass: [SimpleMutableSet class]];

	module = @"OFConcreteSet";
	[self setTestsWithClass: [OFConcreteSet class]
		   mutableClass: [OFConcreteMutableSet class]];
}
@end








<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
219
220
221
222
223
224
225
226

















































































































































































	return [_set containsObject: object];
}

- (OFEnumerator *)objectEnumerator
{
	return [_set objectEnumerator];
}
@end

















































































































































































Renamed and modified new_tests/OFSocketTests.m [b6fe3d8b77] to tests/OFSocketTests.m [a25ea91bad].

224
225
226
227
228
229
230





















231
	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







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
	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");
}

- (void)testAddressEqual
{
	OFSocketAddress addr1 = OFSocketAddressParseIP(@"127.0.0.1", 1234);
	OFSocketAddress addr2 = OFSocketAddressParseIP(@"127.0.0.1", 1234);
	OFSocketAddress addr3 = OFSocketAddressParseIP(@"127.0.0.1", 1235);

	OTAssertTrue(OFSocketAddressEqual(&addr1, &addr2));
	OTAssertFalse(OFSocketAddressEqual(&addr1, &addr3));
}

- (void)testAddressHash
{
	OFSocketAddress addr1 = OFSocketAddressParseIP(@"127.0.0.1", 1234);
	OFSocketAddress addr2 = OFSocketAddressParseIP(@"127.0.0.1", 1234);
	OFSocketAddress addr3 = OFSocketAddressParseIP(@"127.0.0.1", 1235);

	OTAssertEqual(OFSocketAddressHash(&addr1), OFSocketAddressHash(&addr2));
	OTAssertNotEqual(OFSocketAddressHash(&addr1),
	    OFSocketAddressHash(&addr3));
}
@end

Modified tests/OFStreamTests.m from [b1e1e0bf5b] to [cac1034b86].

11
12
13
14
15
16
17
18

19
20

21
22
23
24

























25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
 * 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 = @"OFStream";


@interface StreamTest: OFStream
{
	int state;

























}
@end

@implementation StreamTest
- (bool)lowlevelIsAtEndOfStream
{
	return (state > 1);
}

- (size_t)lowlevelReadIntoBuffer: (void *)buffer length: (size_t)size
{
	size_t pageSize = [OFSystemInfo pageSize];

	switch (state) {
	case 0:
		if (size < 1)
			return 0;

		memcpy(buffer, "f", 1);

		state++;
		return 1;
	case 1:
		if (size < pageSize)
			return 0;

		memcpy(buffer, "oo\n", 3);
		memset((char *)buffer + 3, 'X', pageSize - 3);

		state++;
		return pageSize;
	}

	return 0;
}
@end

@implementation TestsAppDelegate (OFStreamTests)
- (void)streamTests
{
	void *pool = objc_autoreleasePoolPush();
	size_t pageSize = [OFSystemInfo pageSize];
	StreamTest *test = [[[StreamTest alloc] init] autorelease];
	OFString *string;
	char *cString;

	cString = OFAllocMemory(pageSize - 2, 1);
	memset(cString, 'X', pageSize - 3);
	cString[pageSize - 3] = '\0';

	TEST(@"-[readLine] #1", [[test readLine] isEqual: @"foo"])

	string = [test readLine];
	TEST(@"-[readLine] #2", string != nil &&
	    string.length == pageSize - 3 &&
	    !strcmp(string.UTF8String, cString))

	OFFreeMemory(cString);

	objc_autoreleasePoolPop(pool);
}
@end







|
>

|
>

|

|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>



|


|






|






|








|





<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<

11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86


























87
 * 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 OFStreamTests: OTTestCase
@end

@interface OFTestStream: OFStream
{
	int _state;
}
@end

@implementation OFStreamTests
- (void)testStream
{
	size_t pageSize = [OFSystemInfo pageSize];
	OFTestStream *stream = [[[OFTestStream alloc] init] autorelease];
	char *cString = OFAllocMemory(pageSize - 2, 1);

	@try {
		OFString *string;

		memset(cString, 'X', pageSize - 3);
		cString[pageSize - 3] = '\0';

		OTAssertEqualObjects([stream readLine], @"foo");

		string = [stream readLine];
		OTAssertNotNil(string);
		OTAssertEqual(string.length, pageSize - 3);
		OTAssertEqual(strcmp(string.UTF8String, cString), 0);
	} @finally {
		OFFreeMemory(cString);
	}
}
@end

@implementation OFTestStream
- (bool)lowlevelIsAtEndOfStream
{
	return (_state > 1);
}

- (size_t)lowlevelReadIntoBuffer: (void *)buffer length: (size_t)size
{
	size_t pageSize = [OFSystemInfo pageSize];

	switch (_state) {
	case 0:
		if (size < 1)
			return 0;

		memcpy(buffer, "f", 1);

		_state++;
		return 1;
	case 1:
		if (size < pageSize)
			return 0;

		memcpy(buffer, "oo\n", 3);
		memset((char *)buffer + 3, 'X', pageSize - 3);

		_state++;
		return pageSize;
	}

	return 0;
}


























@end

Added tests/OFStringTests.h version [358687fcb0].



















































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/*
 * Copyright (c) 2008-2024 Jonathan Schleifer <js@nil.im>
 *
 * 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 OFStringTests: OTTestCase
{
	OFString *_string;
}

@property (readonly, nonatomic) Class stringClass;
@end

Modified tests/OFStringTests.m from [dc9aaa2341] to [0fac0482da].

15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63






































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































64
65
66
67
68
69
70
71

#include "config.h"

#include <stdlib.h>
#include <string.h>
#include <math.h>

#import "TestsAppDelegate.h"

#import "OFString.h"
#import "OFMutableUTF8String.h"
#import "OFUTF8String.h"

#ifndef INFINITY
# define INFINITY __builtin_inf()
#endif

static OFString *module;
static OFString *const whitespace[] = {
	@" \r \t\n\t \tasd  \t \t\t\r\n",
	@" \t\t  \t\t  \t \t"
};
static const OFUnichar unicharString[] = {
	0xFEFF, 'f', 0xF6, 0xF6, 'b', 0xE4, 'r', 0x1F03A, 0
};
static const OFUnichar swappedUnicharString[] = {
	0xFFFE0000, 0x66000000, 0xF6000000, 0xF6000000, 0x62000000, 0xE4000000,
	0x72000000, 0x3AF00100, 0
};
static const OFChar16 char16String[] = {
	0xFEFF, 'f', 0xF6, 0xF6, 'b', 0xE4, 'r', 0xD83C, 0xDC3A, 0
};
static const OFChar16 swappedChar16String[] = {
	0xFFFE, 0x6600, 0xF600, 0xF600, 0x6200, 0xE400, 0x7200, 0x3CD8, 0x3ADC,
	0
};

@interface SimpleString: OFString
{
	OFMutableString *_string;
}
@end

@interface SimpleMutableString: OFMutableString
{
	OFMutableString *_string;
}
@end







































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































@implementation SimpleString
- (instancetype)init
{
	self = [super init];

	@try {
		_string = [[OFMutableString alloc] init];
	} @catch (id e) {







<
<
|
<
<





<
<
<
<
<















|





|





>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|







15
16
17
18
19
20
21


22


23
24
25
26
27





28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540

#include "config.h"

#include <stdlib.h>
#include <string.h>
#include <math.h>



#import "OFStringTests.h"



#ifndef INFINITY
# define INFINITY __builtin_inf()
#endif






static const OFUnichar unicharString[] = {
	0xFEFF, 'f', 0xF6, 0xF6, 'b', 0xE4, 'r', 0x1F03A, 0
};
static const OFUnichar swappedUnicharString[] = {
	0xFFFE0000, 0x66000000, 0xF6000000, 0xF6000000, 0x62000000, 0xE4000000,
	0x72000000, 0x3AF00100, 0
};
static const OFChar16 char16String[] = {
	0xFEFF, 'f', 0xF6, 0xF6, 'b', 0xE4, 'r', 0xD83C, 0xDC3A, 0
};
static const OFChar16 swappedChar16String[] = {
	0xFFFE, 0x6600, 0xF600, 0xF600, 0x6200, 0xE400, 0x7200, 0x3CD8, 0x3ADC,
	0
};

@interface CustomString: OFString
{
	OFMutableString *_string;
}
@end

@interface CustomMutableString: OFMutableString
{
	OFMutableString *_string;
}
@end

@interface EntityHandler: OFObject <OFStringXMLUnescapingDelegate>
@end

@implementation OFStringTests
- (Class)stringClass
{
	return [CustomString class];
}

- (void)setUp
{
	[super setUp];

	_string = [[self.stringClass alloc] initWithString: @"täṠ€🤔"];
}

- (void)dealloc
{
	[_string release];

	[super dealloc];
}

- (void)testIsEqual
{
	OTAssertEqualObjects(_string, @"täṠ€🤔");
	OTAssertEqualObjects(@"täṠ€🤔", _string);
	OTAssertNotEqualObjects([self.stringClass stringWithString: @"test"],
	    @"täṠ€🤔");
	OTAssertNotEqualObjects(@"täṠ€🤔",
	    [self.stringClass stringWithString: @"test"]);
}

- (void)testHash
{
	OTAssertEqual(_string.hash, @"täṠ€🤔".hash);
	OTAssertNotEqual([[self.stringClass stringWithString: @"test"] hash],
	    @"täṠ€".hash);
}

- (void)testCompare
{
	OTAssertEqual([_string compare: @"täṠ€🤔"], OFOrderedSame);
	OTAssertEqual([[self.stringClass stringWithString: @""]
	    compare: @"a"], OFOrderedAscending);
	OTAssertEqual([[self.stringClass stringWithString: @"a"]
	    compare: @"b"], OFOrderedAscending);
	OTAssertEqual([[self.stringClass stringWithString: @"cd"]
	    compare: @"bc"], OFOrderedDescending);
	OTAssertEqual([[self.stringClass stringWithString: @"ä"]
	    compare: @"ö"], OFOrderedAscending);
	OTAssertEqual([[self.stringClass stringWithString: @"€"]
	    compare: @"ß"], OFOrderedDescending);
	OTAssertEqual([[self.stringClass stringWithString: @"aa"]
	    compare: @"z"], OFOrderedAscending);
	OTAssertEqual([@"aa" compare:
	    [self.stringClass stringWithString: @"z"]], OFOrderedAscending);
}

- (void)testCaseInsensitiveCompare
{
#ifdef OF_HAVE_UNICODE_TABLES
	OTAssertEqual([[self.stringClass stringWithString: @"a"]
	    caseInsensitiveCompare: @"A"], OFOrderedSame);
	OTAssertEqual([[self.stringClass stringWithString: @"Ä"]
	    caseInsensitiveCompare: @"ä"], OFOrderedSame);
	OTAssertEqual([[self.stringClass stringWithString: @"Ñ"]
	    caseInsensitiveCompare: @"Я"], OFOrderedSame);
	OTAssertEqual([[self.stringClass stringWithString: @"€"]
	    caseInsensitiveCompare: @"ß"], OFOrderedDescending);
	OTAssertEqual([[self.stringClass stringWithString: @"ß"]
	    caseInsensitiveCompare: @"→"], OFOrderedAscending);
	OTAssertEqual([[self.stringClass stringWithString: @"AA"]
	    caseInsensitiveCompare: @"z"], OFOrderedAscending);
	OTAssertEqual([[self.stringClass stringWithString: @"ABC"]
	    caseInsensitiveCompare: @"AbD"], OFOrderedAscending);
#else
	OTAssertEqual([[self.stringClass stringWithString: @"a"]
	    caseInsensitiveCompare: @"A"], OFOrderedSame);
	OTAssertEqual([[self.stringClass stringWithString: @"AA"]
	    caseInsensitiveCompare: @"z"], OFOrderedAscending);
	OTAssertEqual([[self.stringClass stringWithString: @"ABC"]
	    caseInsensitiveCompare: @"AbD"], OFOrderedAscending);
#endif
}

- (void)testDescription
{
	OTAssertEqualObjects(_string.description, @"täṠ€🤔");
}

- (void)testLength
{
	OTAssertEqual(_string.length, 5);
}

- (void)testUTF8StringLength
{
	OTAssertEqual(_string.UTF8StringLength, 13);
}

- (void)testCharacterAtIndex
{
	OTAssertEqual([_string characterAtIndex: 0], 't');
	OTAssertEqual([_string characterAtIndex: 1], 0xE4);
	OTAssertEqual([_string characterAtIndex: 2], 0x1E60);
	OTAssertEqual([_string characterAtIndex: 3], 0x20AC);
	OTAssertEqual([_string characterAtIndex: 4], 0x1F914);
}

- (void)testCharacterAtIndexFailsWithOutOfRangeIndex
{
	OTAssertThrowsSpecific([_string characterAtIndex: 5],
	    OFOutOfRangeException);
}

- (void)testUppercaseString
{
#ifdef OF_HAVE_UNICODE_TABLES
	OTAssertEqualObjects(_string.uppercaseString, @"TÄṠ€🤔");
#else
	OTAssertEqualObjects(_string.uppercaseString, @"TäṠ€🤔");
#endif
}

- (void)testLowercaseString
{
#ifdef OF_HAVE_UNICODE_TABLES
	OTAssertEqualObjects(_string.lowercaseString, @"täṡ€🤔");
#else
	OTAssertEqualObjects(_string.lowercaseString, @"täṠ€🤔");
#endif
}

- (void)testCapitalizedString
{
#ifdef OF_HAVE_UNICODE_TABLES
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"täṠ€🤔täṠ€🤔 täṠ€🤔"] capitalizedString], @"Täṡ€🤔täṡ€🤔 Täṡ€🤔");
#else
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"täṠ€🤔täṠ€🤔 täṠ€🤔"] capitalizedString], @"TäṠ€🤔täṠ€🤔 TäṠ€🤔");
#endif
}

- (void)testStringWithUTF8StringLength
{
	OTAssertEqualObjects([self.stringClass
	    stringWithUTF8String: "\xEF\xBB\xBF" "foobar"
			  length: 6], @"foo");
}

- (void)testStringWithUTF16String
{
	OTAssertEqualObjects([self.stringClass
	    stringWithUTF16String: char16String], @"fööbär🀺");
	OTAssertEqualObjects([self.stringClass
	    stringWithUTF16String: swappedChar16String], @"fööbär🀺");
}

- (void)testStringWithUTF32String
{
	OTAssertEqualObjects([self.stringClass
	    stringWithUTF32String: unicharString], @"fööbär🀺");
	OTAssertEqualObjects([self.stringClass
	    stringWithUTF32String: swappedUnicharString], @"fööbär🀺");
}

- (void)testStringWithUTF8StringFailsWithInvalidUTF8
{
	OTAssertThrowsSpecific(
	    [self.stringClass stringWithUTF8String: "\xE0\x80"],
	    OFInvalidEncodingException);

	OTAssertThrowsSpecific(
	    [self.stringClass stringWithUTF8String: "\xF0\x80\x80\xC0"],
	    OFInvalidEncodingException);
}

- (void)testStringWithCStringEncodingISO8859_1
{
	OTAssertEqualObjects([self.stringClass
	    stringWithCString: "\xE4\xF6\xFC"
		     encoding: OFStringEncodingISO8859_1], @"äöü");
}

#ifdef HAVE_ISO_8859_15
- (void)testStringWithCStringEncodingISO8859_15
{
	OTAssertEqualObjects([self.stringClass
	    stringWithCString: "\xA4\xA6\xA8\xB4\xB8\xBC\xBD\xBE"
		     encoding: OFStringEncodingISO8859_15], @"€ŠšŽžŒœŸ");
}
#endif

#ifdef HAVE_WINDOWS_1252
- (void)testStringWithCStringEncodingWindows1252
{
	OTAssertEqualObjects([self.stringClass
	    stringWithCString: "\x80\x82\x83\x84\x85\x86\x87\x88\x89\x8A\x8B"
			       "\x8C\x8E\x91\x92\x93\x94\x95\x96\x97\x98\x99"
			       "\x9A\x9B\x9C\x9E\x9F"
		     encoding: OFStringEncodingWindows1252],
	    @"€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“â€â€¢â€“—˜™š›œžŸ");
}
#endif

#ifdef HAVE_CODEPAGE_437
- (void)testStringWithCStringEncodingCodepage437
{
	OTAssertEqualObjects([self.stringClass
	    stringWithCString: "\xB0\xB1\xB2\xDB"
		     encoding: OFStringEncodingCodepage437], @"â–‘â–’â–“â–ˆ");
}
#endif

#ifdef OF_HAVE_FILES
- (void)testStringWithContentsOfFileEncoding
{
	OTAssertEqualObjects([self.stringClass
	    stringWithContentsOfFile: @"testfile.txt"
			    encoding: OFStringEncodingISO8859_1], @"testäöü");
}

- (void)testStringWithContentsOfIRIEncoding
{
	OTAssertEqualObjects([self.stringClass
	    stringWithContentsOfIRI: [OFIRI fileIRIWithPath: @"testfile.txt"]
			   encoding: OFStringEncodingISO8859_1], @"testäöü");
}
#endif

- (void)testCStringWithEncodingASCII
{
	OTAssertEqual(strcmp([[self.stringClass stringWithString:
	    @"This is a test"] cStringWithEncoding: OFStringEncodingASCII],
	    "This is a test"), 0);

	OTAssertThrowsSpecific([[self.stringClass stringWithString:
	    @"This is a tést"] cStringWithEncoding: OFStringEncodingASCII],
	    OFInvalidEncodingException);
}

- (void)testCStringWithEncodingISO8859_1
{
	OTAssertEqual(strcmp([[self.stringClass stringWithString:
	    @"This is ä test"] cStringWithEncoding: OFStringEncodingISO8859_1],
	    "This is \xE4 test"), 0);

	OTAssertThrowsSpecific([[self.stringClass stringWithString:
	    @"This is ä t€st"] cStringWithEncoding: OFStringEncodingISO8859_1],
	    OFInvalidEncodingException);
}

#ifdef HAVE_ISO_8859_15
- (void)testCStringWithEncodingISO8859_15
{
	OTAssertEqual(strcmp([[self.stringClass stringWithString:
	    @"This is ä t€st"] cStringWithEncoding: OFStringEncodingISO8859_15],
	    "This is \xE4 t\xA4st"), 0);

	OTAssertThrowsSpecific(
	    [[self.stringClass stringWithString: @"This is ä t€st…"]
	    cStringWithEncoding: OFStringEncodingISO8859_15],
	    OFInvalidEncodingException);
}
#endif

#ifdef HAVE_WINDOWS_1252
- (void)testCStringWithEncodingWindows1252
{
	OTAssertEqual(
	    strcmp([[self.stringClass stringWithString: @"This is ä t€st…"]
	    cStringWithEncoding: OFStringEncodingWindows1252],
	    "This is \xE4 t\x80st\x85"), 0);

	OTAssertThrowsSpecific(
	    [[self.stringClass stringWithString: @"This is ä t€st…‼"]
	    cStringWithEncoding: OFStringEncodingWindows1252],
	    OFInvalidEncodingException);
}
#endif

#ifdef HAVE_CODEPAGE_437
- (void)testCStringWithEncodingCodepage437
{
	OTAssertEqual(
	    strcmp([[self.stringClass stringWithString: @"Tést strîng ░▒▓"]
	    cStringWithEncoding: OFStringEncodingCodepage437],
	    "T\x82st str\x8Cng \xB0\xB1\xB2"), 0);

	OTAssertThrowsSpecific(
	    [[self.stringClass stringWithString: @"T€st strîng ░▒▓"]
	    cStringWithEncoding: OFStringEncodingCodepage437],
	    OFInvalidEncodingException);
}
#endif

- (void)testLossyCStringWithEncodingASCII
{
	OTAssertEqual(strcmp([[self.stringClass stringWithString:
	    @"This is a tést"] lossyCStringWithEncoding: OFStringEncodingASCII],
	    "This is a t?st"), 0);
}

- (void)testLossyCStringWithEncodingISO8859_1
{
	OTAssertEqual(
	    strcmp([[self.stringClass stringWithString: @"This is ä t€st"]
	    lossyCStringWithEncoding: OFStringEncodingISO8859_1],
	    "This is \xE4 t?st"), 0);
}

#ifdef HAVE_ISO_8859_15
- (void)testLossyCStringWithEncodingISO8859_15
{
	OTAssertEqual(
	    strcmp([[self.stringClass stringWithString: @"This is ä t€st…"]
	    lossyCStringWithEncoding: OFStringEncodingISO8859_15],
	    "This is \xE4 t\xA4st?"), 0);
}
#endif

#ifdef HAVE_WINDOWS_1252
- (void)testLossyCStringWithEncodingWindows1252
{
	OTAssertEqual(
	    strcmp([[self.stringClass stringWithString: @"This is ä t€st…‼"]
	    lossyCStringWithEncoding: OFStringEncodingWindows1252],
	    "This is \xE4 t\x80st\x85?"), 0);
}
#endif

#ifdef HAVE_CODEPAGE_437
- (void)testLossyCStringWithEncodingCodepage437
{
	OTAssertEqual(
	    strcmp([[self.stringClass stringWithString: @"T€st strîng ░▒▓"]
	    lossyCStringWithEncoding: OFStringEncodingCodepage437],
	    "T?st str\x8Cng \xB0\xB1\xB2"), 0);
}
#endif

- (void)testStringWithFormat
{
	OTAssertEqualObjects(
	    ([self.stringClass stringWithFormat: @"%@:%d", @"test", 123]),
	    @"test:123");
}

- (void)testRangeOfString
{
	OFString *string = [self.stringClass stringWithString: @"ð„žÃ¶Ã¶"];

	OTAssertEqual([string rangeOfString: @"öö"].location, 1);
	OTAssertEqual([string rangeOfString: @"ö"].location, 1);
	OTAssertEqual([string rangeOfString: @"ð„ž"].location, 0);
	OTAssertEqual([string rangeOfString: @"x"].location, OFNotFound);

	OTAssertEqual([string
	    rangeOfString: @"öö"
		  options: OFStringSearchBackwards].location, 1);

	OTAssertEqual([string
	    rangeOfString: @"ö"
		  options: OFStringSearchBackwards].location, 2);

	OTAssertEqual([string
	    rangeOfString: @"ð„ž"
		  options: OFStringSearchBackwards].location, 0);

	OTAssertEqual([string
	    rangeOfString: @"x"
		  options: OFStringSearchBackwards].location, OFNotFound);
}

- (void)testRangeOfStringFailsWithOutOfRangeRange
{
	OTAssertThrowsSpecific(
	    [_string rangeOfString: @"t" options: 0 range: OFMakeRange(6, 1)],
	    OFOutOfRangeException);
}

- (void)testIndexOfCharacterFromSet
{
	OFCharacterSet *characterSet =
	    [OFCharacterSet characterSetWithCharactersInString: @"cđ"];

	OTAssertEqual([[self.stringClass stringWithString: @"abcđabcđe"]
	    indexOfCharacterFromSet: characterSet], 2);

	OTAssertEqual([[self.stringClass stringWithString: @"abcđabcđë"]
	    indexOfCharacterFromSet: characterSet
			    options: OFStringSearchBackwards], 7);

	OTAssertEqual([[self.stringClass stringWithString: @"abcđabcđë"]
	    indexOfCharacterFromSet: characterSet
			    options: 0
			      range: OFMakeRange(4, 4)], 6);

	OTAssertEqual([[self.stringClass stringWithString: @"abcđabcđëf"]
	    indexOfCharacterFromSet: characterSet
			    options: 0
			      range: OFMakeRange(8, 2)], OFNotFound);
}

- (void)testIndexOfCharacterFromSetFailsWithOutOfRangeRange
{
	OFCharacterSet *characterSet =
	    [OFCharacterSet characterSetWithCharactersInString: @"cđ"];

	OTAssertThrowsSpecific([[self.stringClass stringWithString: @"ð„žÃ¶Ã¶"]
	    indexOfCharacterFromSet: characterSet
			    options: 0
			      range: OFMakeRange(3, 1)],
	    OFOutOfRangeException);
}

- (void)testSubstringWithRange
{
	OTAssertEqualObjects([_string substringWithRange: OFMakeRange(1, 2)],
	    @"äṠ");

	OTAssertEqualObjects([_string substringWithRange: OFMakeRange(3, 0)],
	    @"");
}

- (void)testSubstringWithRangeFailsWithOutOfRangeRange
{
	OTAssertThrowsSpecific([_string substringWithRange: OFMakeRange(4, 2)],
	    OFOutOfRangeException);

	OTAssertThrowsSpecific([_string substringWithRange: OFMakeRange(6, 0)],
	    OFOutOfRangeException);
}

- (void)testStringByAppendingString
{
	OTAssertEqualObjects([_string stringByAppendingString: @"äöü"],
	    @"täṠ€🤔äöü");
}

- (void)testHasPrefix
{
	OTAssertTrue([_string hasPrefix: @"täṠ"]);
	OTAssertFalse([_string hasPrefix: @"🤔"]);
}

- (void)testHasSuffix
{
	OTAssertTrue([_string hasSuffix: @"🤔"]);
	OTAssertFalse([_string hasSuffix: @"täṠ"]);
}

- (void)testComponentsSeparatedByString
{
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"fooXXbarXXXXbazXXXX"] componentsSeparatedByString: @"XX"],
	    ([OFArray arrayWithObjects: @"foo", @"bar", @"", @"baz", @"", @"",
	    nil]));

	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"foo"] componentsSeparatedByString: @""],
	    [OFArray arrayWithObject: @"foo"]);
}

- (void)testComponentsSeparatedByStringOptions
{
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"fooXXbarXXXXbazXXXX"]
	    componentsSeparatedByString: @"XX"
				options: OFStringSkipEmptyComponents],
	    ([OFArray arrayWithObjects: @"foo", @"bar", @"baz", nil]));
}

- (void)testComponentsSeparatedByCharactersInSet
{
	OFCharacterSet *characterSet =
	    [OFCharacterSet characterSetWithCharactersInString: @"XYZ"];

	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"fooXYbarXYZXbazXYXZx"]
	    componentsSeparatedByCharactersInSet: characterSet],
	    ([OFArray arrayWithObjects: @"foo", @"", @"bar", @"", @"", @"",
	    @"baz", @"", @"", @"", @"x", nil]));
}

- (void)testComponentsSeparatedByCharactersInSetOptions
{
	OFCharacterSet *characterSet =
	    [OFCharacterSet characterSetWithCharactersInString: @"XYZ"];

	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"fooXYbarXYZXbazXYXZ"]
	    componentsSeparatedByCharactersInSet: characterSet
					 options: OFStringSkipEmptyComponents],
	    ([OFArray arrayWithObjects: @"foo", @"bar", @"baz", nil]));
}

- (void)testLongLongValue
{
	OTAssertEqual([[self.stringClass stringWithString:
	    @"1234"] longLongValue], 1234);

	OTAssertEqual([[self.stringClass stringWithString:
	    @"\r\n+123  "] longLongValue], 123);

	OTAssertEqual([[self.stringClass stringWithString:
	    @"-500\t"] longLongValue], -500);

	OTAssertEqual([[self.stringClass stringWithString:
	    @"-0x10\t"] longLongValueWithBase: 0], -0x10);

	OTAssertEqual([[self.stringClass stringWithString:
	    @"\t\t\r\n"] longLongValue], 0);

	OTAssertEqual([[self.stringClass stringWithString:
	    @"123f"] longLongValueWithBase: 16], 0x123f);

	OTAssertEqual([[self.stringClass stringWithString:
	    @"-1234"] longLongValueWithBase: 0], -1234);

	OTAssertEqual([[self.stringClass stringWithString:
	    @"\t\n0xABcd\r"] longLongValueWithBase: 0], 0xABCD);

	OTAssertEqual([[self.stringClass stringWithString:
	    @"1234567"] longLongValueWithBase: 8], 01234567);

	OTAssertEqual([[self.stringClass stringWithString:
	    @"\r\n0123"] longLongValueWithBase: 0], 0123);

	OTAssertEqual([[self.stringClass stringWithString:
	    @"765\t"] longLongValueWithBase: 8], 0765);

	OTAssertEqual([[self.stringClass stringWithString:
	    @"\t\t\r\n"] longLongValueWithBase: 8], 0);
}

- (void)testLongLongValueThrowsOnInvalidFormat
{
	OTAssertThrowsSpecific(
	    [[self.stringClass stringWithString: @"abc"] longLongValue],
	    OFInvalidFormatException);

	OTAssertThrowsSpecific(
	    [[self.stringClass stringWithString: @"0a"] longLongValue],
	    OFInvalidFormatException);

	OTAssertThrowsSpecific(
	    [[self.stringClass stringWithString: @"0 1"] longLongValue],
	    OFInvalidFormatException);

	OTAssertThrowsSpecific(
	    [[self.stringClass stringWithString: @"0xABCDEFG"]
	    longLongValueWithBase: 0],
	    OFInvalidFormatException);

	OTAssertThrowsSpecific(
	    [[self.stringClass stringWithString: @"0x"]
	    longLongValueWithBase: 0],
	    OFInvalidFormatException);
}

- (void)testLongLongValueThrowsOnOutOfRange
{
	OTAssertThrowsSpecific([[self.stringClass stringWithString:
	    @"-12345678901234567890123456789012345678901234567890"
	    @"12345678901234567890123456789012345678901234567890"]
	    longLongValueWithBase: 16], OFOutOfRangeException)
}

- (void)testUnsignedLongLongValue
{
	OTAssertEqual([[self.stringClass stringWithString:
	    @"1234"] unsignedLongLongValue], 1234);

	OTAssertEqual([[self.stringClass stringWithString:
	    @"\r\n+123  "] unsignedLongLongValue], 123);

	OTAssertEqual([[self.stringClass stringWithString:
	    @"\t\t\r\n"] unsignedLongLongValue], 0);

	OTAssertEqual([[self.stringClass stringWithString:
	    @"123f"] unsignedLongLongValueWithBase: 16], 0x123f);

	OTAssertEqual([[self.stringClass stringWithString:
	    @"1234"] unsignedLongLongValueWithBase: 0], 1234);

	OTAssertEqual([[self.stringClass stringWithString:
	    @"\t\n0xABcd\r"] unsignedLongLongValueWithBase: 0], 0xABCD);

	OTAssertEqual([[self.stringClass stringWithString:
	    @"1234567"] unsignedLongLongValueWithBase: 8], 01234567);

	OTAssertEqual([[self.stringClass stringWithString:
	    @"\r\n0123"] unsignedLongLongValueWithBase: 0], 0123);

	OTAssertEqual([[self.stringClass stringWithString: @"765\t"]
	    unsignedLongLongValueWithBase: 8], 0765);

	OTAssertEqual([[self.stringClass stringWithString: @"\t\t\r\n"]
	    unsignedLongLongValueWithBase: 8], 0);
}

- (void)testUnsignedLongLongValueThrowsOnOutOfRange
{
	OTAssertThrowsSpecific([[self.stringClass stringWithString:
	    @"0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF"
	    @"0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF"]
	    unsignedLongLongValueWithBase: 16], OFOutOfRangeException);
}

- (void)testFloatValue
{
	/*
	 * These test numbers can be generated without rounding if we have IEEE
	 * floating point numbers, thus we can use OTAssertEqual on them.
	 */

	OTAssertEqual([[self.stringClass stringWithString:
	    @"\t-0.25 "] floatValue], -0.25);

	OTAssertEqual([[self.stringClass stringWithString:
	    @"\r\n\tINF\t\n"] floatValue], INFINITY);
	OTAssertEqual([[self.stringClass stringWithString:
	    @"\r -INFINITY\n"] floatValue], -INFINITY);

	OTAssertTrue(isnan([[self.stringClass stringWithString:
	    @"   NAN\t\t"] floatValue]));
	OTAssertTrue(isnan([[self.stringClass stringWithString:
	    @"   -NaN\t\t"] floatValue]));
}

- (void)testFloatValueThrowsOnInvalidFormat
{
	OTAssertThrowsSpecific([[self.stringClass stringWithString:
	    @"0.0a"] floatValue], OFInvalidFormatException);
	OTAssertThrowsSpecific([[self.stringClass stringWithString:
	    @"0 0"] floatValue], OFInvalidFormatException);
	OTAssertThrowsSpecific([[self.stringClass stringWithString:
	    @"0,0"] floatValue], OFInvalidFormatException);
}

- (void)testDoubleValue
{
#if (defined(OF_SOLARIS) && defined(OF_X86)) || defined(OF_AMIGAOS_M68K)
	/*
	 * Solaris' strtod() has weird rounding on x86, but not on AMD64.
	 * AmigaOS 3 with libnix has weird rounding as well.
	 */
	OTAssertEqual([[self.stringClass stringWithString:
	    @"\t-0.125 "] doubleValue], -0.125);
#elif defined(OF_ANDROID) || defined(OF_SOLARIS) || defined(OF_HPUX) || \
    defined(OF_DJGPP) || defined(OF_AMIGAOS_M68K)
	/*
	 * Android, Solaris, HP-UX, DJGPP and AmigaOS 3 do not accept 0x for
	 * strtod().
	 */
	OTAssertEqual([[self.stringClass stringWithString:
	    @"\t-0.123456789 "] doubleValue], -0.123456789);
#else
	OTAssertEqual([[self.stringClass stringWithString:
	    @"\t-0x1.FFFFFFFFFFFFFP-1020 "] doubleValue],
	    -0x1.FFFFFFFFFFFFFP-1020);
#endif

	OTAssertEqual([[self.stringClass stringWithString:
	    @"\r\n\tINF\t\n"] doubleValue], INFINITY);
	OTAssertEqual([[self.stringClass stringWithString:
	    @"\r -INFINITY\n"] doubleValue], -INFINITY);

	OTAssert(isnan([[self.stringClass stringWithString:
	    @"   NAN\t\t"] doubleValue]));
	OTAssert(isnan([[self.stringClass stringWithString:
	    @"   -NaN\t\t"] doubleValue]));
}

- (void)testDoubleValueThrowsOnInvalidFormat
{
	OTAssertThrowsSpecific([[self.stringClass stringWithString:
	    @"0.0a"] doubleValue], OFInvalidFormatException);
	OTAssertThrowsSpecific([[self.stringClass stringWithString:
	    @"0 0"] doubleValue], OFInvalidFormatException);
	OTAssertThrowsSpecific([[self.stringClass stringWithString:
	    @"0,0"] doubleValue], OFInvalidFormatException);
}

- (void)testCharacters
{
	OTAssertEqual(memcmp([[self.stringClass stringWithString: @"fööbär🀺"]
	    characters], unicharString + 1, sizeof(unicharString) - 8), 0);
}

- (void)testUTF16String
{
	OFString *string = [self.stringClass stringWithString: @"fööbär🀺"];

	OTAssertEqual(memcmp(string.UTF16String, char16String + 1,
	    OFUTF16StringLength(char16String) * 2), 0);

#ifdef OF_BIG_ENDIAN
	OTAssertEqual(memcmp([string UTF16StringWithByteOrder:
	    OFByteOrderLittleEndian], swappedChar16String + 1,
	    OFUTF16StringLength(swappedChar16String) * 2), 0);
#else
	OTAssertEqual(memcmp([string UTF16StringWithByteOrder:
	    OFByteOrderBigEndian], swappedChar16String + 1,
	    OFUTF16StringLength(swappedChar16String) * 2), 0);
#endif
}

- (void)testUTF16StringLength
{
	OTAssertEqual(_string.UTF16StringLength, 6);
}

- (void)testUTF32String
{
	OFString *string = [self.stringClass stringWithString: @"fööbär🀺"];

	OTAssertEqual(memcmp(string.UTF32String, unicharString + 1,
	    OFUTF32StringLength(unicharString) * 4), 0);

#ifdef OF_BIG_ENDIAN
	OTAssertEqual(memcmp([string UTF32StringWithByteOrder:
	    OFByteOrderLittleEndian], swappedUnicharString + 1,
	    OFUTF32StringLength(swappedUnicharString) * 4), 0);
#else
	OTAssertEqual(memcmp([string UTF32StringWithByteOrder:
	    OFByteOrderBigEndian], swappedUnicharString + 1,
	    OFUTF32StringLength(swappedUnicharString) * 4), 0);
#endif
}

- (void)testStringByMD5Hashing
{
	OTAssertEqualObjects(_string.stringByMD5Hashing,
	    @"7e6bef5fe100d93e808d15b1c6e6145a");
}

- (void)testStringByRIPEMD160Hashing
{
	OTAssertEqualObjects(_string.stringByRIPEMD160Hashing,
	    @"2fd0ec899c55cf2821a2f844b9d80887fc351103");
}

- (void)testStringBySHA1Hashing
{
	OTAssertEqualObjects(_string.stringBySHA1Hashing,
	    @"3f76f9358b372b7147344b7a3ba6d309e4466b3a");
}

- (void)testStringBySHA224Hashing
{
	OTAssertEqualObjects(_string.stringBySHA224Hashing,
	    @"6e57ec72e4da55c46d88a15ce7ce4d8db83d0493a263134a3734259d");
}

- (void)testStringBySHA256Hashing
{
	OTAssertEqualObjects(_string.stringBySHA256Hashing,
	    @"6eac4d3d0b4152c82ff88599482696ca"
	    @"d6dca0b533e8a2e6963d995b19b0a683");
}

- (void)testStringBySHA384Hashing
{
	OTAssertEqualObjects(_string.stringBySHA384Hashing,
	    @"d9bd6a671407d01cee4022888677040d"
	    @"108dd0270c38e0ce755d6dcadb4bf9c1"
	    @"89204dd2a51f954be55ea5d5fe00667b");
}

- (void)testStringBySHA512Hashing
{
	OTAssertEqualObjects(_string.stringBySHA512Hashing,
	    @"64bec66b3633c585da6d32760fa3617a"
	    @"47ca4c247472bdbbfb452b2dbf5a3612"
	    @"5629053394a16ecd08f8a21d461537c5"
	    @"f1224cbb379589e73dcd6763ec4f886c");
}

- (void)testStringByAddingPercentEncodingWithAllowedCharacters
{
	OFCharacterSet *characterSet =
	    [OFCharacterSet characterSetWithCharactersInString: @"abfo'_~$ðŸ"];

	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"foo\"ba'_~$]ðŸðŸŒ"]
	    stringByAddingPercentEncodingWithAllowedCharacters: characterSet],
	    @"foo%22ba'_~$%5DðŸ%F0%9F%8D%8C");
}

- (void)testStringByRemovingPercentEncoding
{
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"foo%20bar%22+%24%F0%9F%8D%8C"] stringByRemovingPercentEncoding],
	    @"foo bar\"+$ðŸŒ");
}

- (void)testStringByRemovingPercentEncodingThrowsOnInvalidFormat
{
	OTAssertThrowsSpecific([[self.stringClass stringWithString:
	    @"foo%xbar"] stringByRemovingPercentEncoding],
	    OFInvalidFormatException);
}

- (void)testStringByRemovingPercentEncodingThrowsOnInvalidEncoding
{
	OTAssertThrowsSpecific([[self.stringClass stringWithString:
	    @"foo%FFbar"] stringByRemovingPercentEncoding],
	    OFInvalidEncodingException);
}

- (void)testStringByXMLEscaping
{
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"<hello> &world'\"!&"] stringByXMLEscaping],
	    @"&lt;hello&gt; &amp;world&apos;&quot;!&amp;");
}

- (void)testStringByXMLUnescaping
{
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"&lt;hello&gt; &amp;world&apos;&quot;!&amp;"]
	    stringByXMLUnescaping],
	    @"<hello> &world'\"!&");

	OTAssertEqualObjects([[self.stringClass stringWithString: @"&#x79;"]
	    stringByXMLUnescaping], @"y");
	OTAssertEqualObjects([[self.stringClass stringWithString: @"&#xe4;"]
	    stringByXMLUnescaping], @"ä");
	OTAssertEqualObjects([[self.stringClass stringWithString: @"&#8364;"]
	    stringByXMLUnescaping], @"€");
	OTAssertEqualObjects([[self.stringClass stringWithString: @"&#x1D11E;"]
	    stringByXMLUnescaping], @"ð„ž");
}

- (void)testStringByXMLUnescapingThrowsOnUnknownEntities
{
	OTAssertThrowsSpecific([[self.stringClass stringWithString: @"&foo;"]
	    stringByXMLUnescaping], OFUnknownXMLEntityException);
}

- (void)testStringByXMLUnescapingThrowsOnInvalidFormat
{
	OTAssertThrowsSpecific([[self.stringClass stringWithString: @"x&amp"]
	    stringByXMLUnescaping], OFInvalidFormatException);
	OTAssertThrowsSpecific([[self.stringClass stringWithString: @"&#;"]
	    stringByXMLUnescaping], OFInvalidFormatException);
	OTAssertThrowsSpecific([[self.stringClass stringWithString: @"&#x;"]
	    stringByXMLUnescaping], OFInvalidFormatException);
	OTAssertThrowsSpecific([[self.stringClass stringWithString: @"&#g;"]
	    stringByXMLUnescaping], OFInvalidFormatException);
	OTAssertThrowsSpecific([[self.stringClass stringWithString: @"&#xg;"]
	    stringByXMLUnescaping], OFInvalidFormatException);
}

- (void)testStringByXMLUnescapingWithDelegate
{
	EntityHandler *entityHandler =
	    [[[EntityHandler alloc] init] autorelease];

	OTAssertEqualObjects([[self.stringClass stringWithString: @"x&foo;y"]
	    stringByXMLUnescapingWithDelegate: entityHandler],
	    @"xbary");
}

#ifdef OF_HAVE_BLOCKS
- (void)testStringByXMLUnescapingWithBlock
{
	OTAssertEqualObjects([[self.stringClass stringWithString: @"x&foo;y"]
	    stringByXMLUnescapingWithBlock: ^ OFString * (OFString *string,
							  OFString *entity) {
		if ([entity isEqual: @"foo"])
			return @"bar";

		return nil;
	    }], @"xbary");
}

- (void)testEnumerateLinesUsingBlock
{
	__block size_t count = 0;

	[[self.stringClass stringWithString: @"foo\nbar\nbaz"]
	    enumerateLinesUsingBlock: ^ (OFString *line, bool *stop) {
		switch (count++) {
		case 0:
			OTAssertEqualObjects(line, @"foo");
			break;
		case 1:
			OTAssertEqualObjects(line, @"bar");
			break;
		case 2:
			OTAssertEqualObjects(line, @"baz");
			break;
		default:
			OTAssert(false);
		}
	}];

	OTAssertEqual(count, 3);
}
#endif

#ifdef OF_HAVE_FILES
- (void)testIsAbsolutePath
{
# if defined(OF_WINDOWS) || defined(OF_MSDOS)
	OTAssertTrue(
	    [[self.stringClass stringWithString: @"C:\\foo"] isAbsolutePath]);
	OTAssertTrue(
	    [[self.stringClass stringWithString: @"a:/foo"] isAbsolutePath]);
	OTAssertFalse(
	    [[self.stringClass stringWithString: @"foo"] isAbsolutePath]);
	OTAssertFalse(
	    [[self.stringClass stringWithString: @"b:foo"] isAbsolutePath]);
#  ifdef OF_WINDOWS
	OTAssertTrue(
	    [[self.stringClass stringWithString: @"\\\\foo"] isAbsolutePath]);
#  endif
# elif defined(OF_AMIGAOS)
	OTAssertTrue(
	    [[self.stringClass stringWithString: @"dh0:foo"] isAbsolutePath]);
	OTAssertTrue(
	    [[self.stringClass stringWithString: @"dh0:a/b"] isAbsolutePath]);
	OTAssertFalse(
	    [[self.stringClass stringWithString: @"foo/bar"] isAbsolutePath]);
	OTAssertFalse(
	    [[self.stringClass stringWithString: @"foo"] isAbsolutePath]);
# elif defined(OF_NINTENDO_DS) || defined(OF_NINTENDO_3DS) || \
    defined(OF_WII) || defined(OF_NINTENDO_SWITCH)
	OTAssertTrue(
	    [[self.stringClass stringWithString: @"sdmc:/foo"] isAbsolutePath]);
	OTAssertFalse(
	    [[self.stringClass stringWithString: @"sdmc:foo"] isAbsolutePath]);
	OTAssertFalse(
	    [[self.stringClass stringWithString: @"foo/bar"] isAbsolutePath]);
	OTAssertFalse(
	    [[self.stringClass stringWithString: @"foo"] isAbsolutePath]);
# else
	OTAssertTrue(
	    [[self.stringClass stringWithString: @"/foo"] isAbsolutePath]);
	OTAssertTrue(
	    [[self.stringClass stringWithString: @"/foo/bar"] isAbsolutePath]);
	OTAssertFalse(
	    [[self.stringClass stringWithString: @"foo/bar"] isAbsolutePath]);
	OTAssertFalse(
	    [[self.stringClass stringWithString: @"foo"] isAbsolutePath]);
# endif
}

- (void)testStringByAppendingPathComponent
{
# if defined(OF_WINDOWS) || defined(OF_MSDOS)
	OTAssertEqualObjects([[self.stringClass stringWithString: @"foo\\bar"]
	    stringByAppendingPathComponent: @"baz"],
	    @"foo\\bar\\baz");

	OTAssertEqualObjects([[self.stringClass stringWithString: @"foo\\bar\\"]
	    stringByAppendingPathComponent: @"baz"],
	    @"foo\\bar\\baz");
# else
	OTAssertEqualObjects([[self.stringClass stringWithString: @"foo/bar"]
	    stringByAppendingPathComponent: @"baz"],
	    @"foo/bar/baz");

	OTAssertEqualObjects([[self.stringClass stringWithString: @"foo/bar/"]
	    stringByAppendingPathComponent: @"baz"],
	    @"foo/bar/baz");
# endif
}

- (void)testStringByAppendingPathExtension
{
# if defined(OF_WINDOWS) || defined(OF_MSDOS)
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"foo"] stringByAppendingPathExtension: @"bar"],
	    @"foo.bar");

	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"c:\\tmp\\foo"] stringByAppendingPathExtension: @"bar"],
	    @"c:\\tmp\\foo.bar");

	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"c:\\tmp\\/\\"] stringByAppendingPathExtension: @"bar"],
	    @"c:\\tmp.bar");
# elif defined(OF_AMIGAOS)
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"foo"] stringByAppendingPathExtension: @"bar"],
	    @"foo.bar");

	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"foo/bar"] stringByAppendingPathExtension: @"baz"],
	    @"foo/bar.baz");
# else
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"foo"] stringByAppendingPathExtension: @"bar"],
	    @"foo.bar");

	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"foo/bar"] stringByAppendingPathExtension: @"baz"],
	    @"foo/bar.baz");

	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"foo///"] stringByAppendingPathExtension: @"bar"],
	    @"foo.bar");
# endif
}

- (void)testPathWithComponents
{
# if defined(OF_WINDOWS) || defined(OF_MSDOS)
	OTAssertEqualObjects([self.stringClass pathWithComponents:
	    ([OFArray arrayWithObjects: @"foo", @"bar", @"baz", nil])],
	    @"foo\\bar\\baz");

	OTAssertEqualObjects([self.stringClass pathWithComponents:
	    ([OFArray arrayWithObjects: @"c:\\", @"foo", @"bar", @"baz", nil])],
	    @"c:\\foo\\bar\\baz");

	OTAssertEqualObjects([self.stringClass pathWithComponents:
	    ([OFArray arrayWithObjects: @"c:", @"foo", @"bar", @"baz", nil])],
	    @"c:foo\\bar\\baz");

	OTAssertEqualObjects([self.stringClass pathWithComponents:
	    ([OFArray arrayWithObjects: @"c:", @"\\", @"foo", @"bar", @"baz",
	    nil])], @"c:\\foo\\bar\\baz");

	OTAssertEqualObjects([self.stringClass pathWithComponents:
	    ([OFArray arrayWithObjects: @"c:", @"/", @"foo", @"bar", @"baz",
	    nil])], @"c:/foo\\bar\\baz");

	OTAssertEqualObjects([self.stringClass pathWithComponents:
	    ([OFArray arrayWithObjects: @"foo/", @"bar\\", @"", @"baz", @"\\",
	    nil])], @"foo/bar\\baz");

	OTAssertEqualObjects([self.stringClass pathWithComponents:
	    [OFArray arrayWithObject: @"foo"]], @"foo");

	OTAssertEqualObjects([self.stringClass pathWithComponents:
	    [OFArray arrayWithObject: @"c:"]], @"c:");

	OTAssertEqualObjects([self.stringClass pathWithComponents:
	    [OFArray arrayWithObject: @"c:\\"]], @"c:\\");

	OTAssertEqualObjects([self.stringClass pathWithComponents:
	    [OFArray arrayWithObject: @"\\"]], @"\\");

	OTAssertEqualObjects([self.stringClass pathWithComponents:
	    [OFArray arrayWithObject: @"/"]], @"/");

#  ifdef OF_WINDOWS
	OTAssertEqualObjects([self.stringClass pathWithComponents:
	    ([OFArray arrayWithObjects: @"\\\\", @"foo", @"bar", nil])],
	    @"\\\\foo\\bar");
#  endif
# elif defined(OF_AMIGAOS)
	OTAssertEqualObjects([self.stringClass pathWithComponents:
	    ([OFArray arrayWithObjects: @"dh0:", @"foo", @"bar", @"baz", nil])],
	    @"dh0:foo/bar/baz");

	OTAssertEqualObjects([self.stringClass pathWithComponents:
	    ([OFArray arrayWithObjects: @"foo", @"bar", @"baz", nil])],
	    @"foo/bar/baz");

	OTAssertEqualObjects([self.stringClass pathWithComponents:
	    ([OFArray arrayWithObjects: @"foo/", @"bar", @"", @"baz", @"/",
	    nil])], @"foo//bar/baz//");

	OTAssertEqualObjects([self.stringClass pathWithComponents:
	    [OFArray arrayWithObject: @"foo"]], @"foo");
# elif defined(OF_WII) || defined(OF_NINTENDO_DS) || \
    defined(OF_NINTENDO_3DS) || defined(OF_NINTENDO_SWITCH)
	OTAssertEqualObjects([self.stringClass pathWithComponents:
	    ([OFArray arrayWithObjects: @"foo", @"bar", @"baz", nil])],
	    @"foo/bar/baz");

	OTAssertEqualObjects([self.stringClass pathWithComponents:
	    ([OFArray arrayWithObjects: @"sdmc:", @"foo", @"bar", @"baz",
	    nil])], @"sdmc:/foo/bar/baz");

	OTAssertEqualObjects([self.stringClass pathWithComponents:
	    ([OFArray arrayWithObjects: @"foo/", @"bar/", @"", @"baz", @"/",
	    nil])], @"foo/bar/baz");

	OTAssertEqualObjects([self.stringClass pathWithComponents:
	    [OFArray arrayWithObject: @"foo"]], @"foo");

	OTAssertEqualObjects([self.stringClass pathWithComponents:
	    [OFArray arrayWithObject: @"sdmc:"]], @"sdmc:/");
# else
	OTAssertEqualObjects([self.stringClass pathWithComponents:
	    ([OFArray arrayWithObjects: @"/", @"foo", @"bar", @"baz", nil])],
	    @"/foo/bar/baz");

	OTAssertEqualObjects([self.stringClass pathWithComponents:
	    ([OFArray arrayWithObjects: @"foo", @"bar", @"baz", nil])],
	    @"foo/bar/baz");

	OTAssertEqualObjects([self.stringClass pathWithComponents:
	    ([OFArray arrayWithObjects: @"foo/", @"bar", @"", @"baz", @"/",
	    nil])], @"foo/bar/baz");

	OTAssertEqualObjects([self.stringClass pathWithComponents:
	    [OFArray arrayWithObject: @"foo"]], @"foo");
# endif
}

- (void)testPathComponents
{
# if defined(OF_WINDOWS) || defined(OF_MSDOS)
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"c:/tmp"] pathComponents],
	    ([OFArray arrayWithObjects: @"c:/", @"tmp", nil]));

	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"c:\\tmp\\"] pathComponents],
	    ([OFArray arrayWithObjects: @"c:\\", @"tmp", nil]));

	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"c:\\"] pathComponents], [OFArray arrayWithObject: @"c:\\"]);

	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"c:/"] pathComponents], [OFArray arrayWithObject: @"c:/"]);

	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"c:"] pathComponents], [OFArray arrayWithObject: @"c:"]);

	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"foo\\bar"] pathComponents],
	    ([OFArray arrayWithObjects: @"foo", @"bar", nil]));

	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"foo\\bar/baz/"] pathComponents],
	    ([OFArray arrayWithObjects: @"foo", @"bar", @"baz", nil]));

	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"foo\\/"] pathComponents], [OFArray arrayWithObject: @"foo"]);

#  ifdef OF_WINDOWS
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"\\\\foo\\bar"] pathComponents],
	    ([OFArray arrayWithObjects: @"\\\\", @"foo", @"bar", nil]));
#  endif

	OTAssertEqualObjects([[self.stringClass stringWithString: @""]
	    pathComponents], [OFArray array]);
# elif defined(OF_AMIGAOS)
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"dh0:tmp"] pathComponents],
	    ([OFArray arrayWithObjects: @"dh0:", @"tmp", nil]));

	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"dh0:tmp/"] pathComponents],
	    ([OFArray arrayWithObjects: @"dh0:", @"tmp", nil]));

	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"dh0:/"] pathComponents],
	    ([OFArray arrayWithObjects: @"dh0:", @"/", nil]));

	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"foo/bar"] pathComponents],
	    ([OFArray arrayWithObjects: @"foo", @"bar", nil]));

	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"foo/bar/baz/"] pathComponents],
	    ([OFArray arrayWithObjects: @"foo", @"bar", @"baz", nil]));

	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"foo//"] pathComponents],
	    ([OFArray arrayWithObjects: @"foo", @"/", nil]));

	OTAssertEqualObjects([[self.stringClass stringWithString: @""]
	    pathComponents], [OFArray array]);
# elif defined(OF_NINTENDO_3DS) || defined(OF_WII) || \
    defined(OF_NINTENDO_SWITCH)
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"sdmc:/tmp"] pathComponents],
	    ([OFArray arrayWithObjects: @"sdmc:", @"tmp", nil]));

	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"sdmc:/"] pathComponents], [OFArray arrayWithObject: @"sdmc:"]);

	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"foo/bar"] pathComponents],
	    ([OFArray arrayWithObjects: @"foo", @"bar", nil]));

	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"foo/bar/baz/"] pathComponents],
	    ([OFArray arrayWithObjects: @"foo", @"bar", @"baz", nil]));

	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"foo//"] pathComponents], [OFArray arrayWithObject: @"foo"]);

	OTAssertEqualObjects([[self.stringClass stringWithString: @""]
	    pathComponents], [OFArray array]);
# else
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"/tmp"] pathComponents],
	    ([OFArray arrayWithObjects: @"/", @"tmp", nil]));

	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"/tmp/"] pathComponents],
	    ([OFArray arrayWithObjects: @"/", @"tmp", nil]));

	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"/"] pathComponents], [OFArray arrayWithObject: @"/"]);

	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"foo/bar"] pathComponents],
	    ([OFArray arrayWithObjects: @"foo", @"bar", nil]));

	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"foo/bar/baz/"] pathComponents],
	    ([OFArray arrayWithObjects: @"foo", @"bar", @"baz", nil]));

	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"foo//"] pathComponents], [OFArray arrayWithObject: @"foo"]);

	OTAssertEqualObjects([[self.stringClass stringWithString: @""]
	    pathComponents], [OFArray array]);
# endif
}

- (void)testLastPathComponent
{
# if defined(OF_WINDOWS) || defined(OF_MSDOS)
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"c:/tmp"] lastPathComponent], @"tmp");
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"c:\\tmp\\"] lastPathComponent], @"tmp");
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"c:\\"] lastPathComponent], @"c:\\");
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"c:/"] lastPathComponent], @"c:/");
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"\\"] lastPathComponent], @"\\");
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"foo"] lastPathComponent], @"foo");
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"foo\\bar"] lastPathComponent], @"bar");
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"foo/bar/baz/"] lastPathComponent], @"baz");
#  ifdef OF_WINDOWS
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"\\\\foo\\bar"] lastPathComponent], @"bar");
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"\\\\"] lastPathComponent], @"\\\\");
#  endif
# elif defined(OF_AMIGAOS)
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"dh0:tmp"] lastPathComponent], @"tmp");
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"dh0:tmp/"] lastPathComponent], @"tmp");
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"dh0:/"] lastPathComponent], @"/");
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"dh0:"] lastPathComponent], @"dh0:");
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"foo"] lastPathComponent], @"foo");
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"foo/bar"] lastPathComponent], @"bar");
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"foo/bar/baz/"] lastPathComponent], @"baz");
# elif defined(OF_WII) || defined(OF_NINTENDO_DS) || \
    defined(OF_NINTENDO_3DS) || defined(OF_NINTENDO_SWITCH)
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"sdmc:/tmp"] lastPathComponent], @"tmp");
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"sdmc:/tmp/"] lastPathComponent], @"tmp");
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"sdmc:/"] lastPathComponent], @"sdmc:/");
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"sdmc:"] lastPathComponent], @"sdmc:");
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"foo"] lastPathComponent], @"foo");
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"foo/bar"] lastPathComponent], @"bar");
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"foo/bar/baz/"] lastPathComponent], @"baz");
# else
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"/tmp"] lastPathComponent], @"tmp");
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"/tmp/"] lastPathComponent], @"tmp");
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"/"] lastPathComponent], @"/");
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"foo"] lastPathComponent], @"foo");
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"foo/bar"] lastPathComponent], @"bar");
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"foo/bar/baz/"] lastPathComponent], @"baz");
# endif
}

- (void)testPathExtension
{
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"foo.bar"] pathExtension], @"bar");
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"foo/.bar"] pathExtension], @"");
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"foo/.bar.baz"] pathExtension], @"baz");
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"foo/bar.baz/"] pathExtension], @"baz");
}

- (void)testStringByDeletingLastPathComponent
{
# if defined(OF_WINDOWS) || defined(OF_MSDOS)
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"\\tmp"] stringByDeletingLastPathComponent], @"\\");
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"/tmp/"] stringByDeletingLastPathComponent], @"/");
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"c:\\"] stringByDeletingLastPathComponent], @"c:\\");
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"c:/"] stringByDeletingLastPathComponent], @"c:/");
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"c:\\tmp/foo/"] stringByDeletingLastPathComponent], @"c:\\tmp");
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"foo\\bar"] stringByDeletingLastPathComponent], @"foo");
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"\\"] stringByDeletingLastPathComponent], @"\\");
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"foo"] stringByDeletingLastPathComponent], @".");
#  ifdef OF_WINDOWS
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"\\\\foo\\bar"] stringByDeletingLastPathComponent], @"\\\\foo");
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"\\\\foo"] stringByDeletingLastPathComponent], @"\\\\");
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"\\\\"] stringByDeletingLastPathComponent], @"\\\\");
#  endif
# elif defined(OF_AMIGAOS)
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"dh0:"] stringByDeletingLastPathComponent], @"dh0:");
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"dh0:tmp"] stringByDeletingLastPathComponent], @"dh0:");
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"dh0:tmp/"] stringByDeletingLastPathComponent], @"dh0:");
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"dh0:/"] stringByDeletingLastPathComponent], @"dh0:");
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"dh0:tmp/foo/"] stringByDeletingLastPathComponent], @"dh0:tmp");
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"foo/bar"] stringByDeletingLastPathComponent], @"foo");
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"foo"] stringByDeletingLastPathComponent], @"");
# elif defined(OF_NINTENDO_3DS) || defined(OF_WII) || \
    defined(OF_NINTENDO_SWITCH)
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"/tmp/"] stringByDeletingLastPathComponent], @"");
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"sdmc:/tmp/foo/"] stringByDeletingLastPathComponent],
	    @"sdmc:/tmp");
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"sdmc:/"] stringByDeletingLastPathComponent], @"sdmc:/");
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"foo/bar"] stringByDeletingLastPathComponent], @"foo");
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"/"] stringByDeletingLastPathComponent], @"");
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"foo"] stringByDeletingLastPathComponent], @".");
# else
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"/tmp"] stringByDeletingLastPathComponent], @"/");
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"/tmp/"] stringByDeletingLastPathComponent], @"/");
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"/tmp/foo/"] stringByDeletingLastPathComponent], @"/tmp");
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"foo/bar"] stringByDeletingLastPathComponent], @"foo");
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"/"] stringByDeletingLastPathComponent], @"/");
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"foo"] stringByDeletingLastPathComponent], @".");
# endif
}

- (void)testStringByDeletingPathExtension
{
# if defined(OF_WINDOWS) || defined(OF_MSDOS)
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"foo.bar"] stringByDeletingPathExtension], @"foo");
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"foo..bar"] stringByDeletingPathExtension], @"foo.");
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"c:/foo.\\bar"] stringByDeletingPathExtension], @"c:/foo.\\bar");
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"c:\\foo./bar.baz"] stringByDeletingPathExtension],
	    @"c:\\foo.\\bar");
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"foo.bar/"] stringByDeletingPathExtension], @"foo");
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @".foo"] stringByDeletingPathExtension], @".foo");
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @".foo.bar"] stringByDeletingPathExtension], @".foo");
# elif defined(OF_AMIGAOS)
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"foo.bar"] stringByDeletingPathExtension], @"foo");
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"foo..bar"] stringByDeletingPathExtension], @"foo.");
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"dh0:foo.bar"] stringByDeletingPathExtension], @"dh0:foo");
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"dh0:foo./bar"] stringByDeletingPathExtension], @"dh0:foo./bar");
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"dh0:foo./bar.baz"] stringByDeletingPathExtension],
	    @"dh0:foo./bar");
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"foo.bar/"] stringByDeletingPathExtension], @"foo");
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @".foo"] stringByDeletingPathExtension], @".foo");
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @".foo\\bar"] stringByDeletingPathExtension], @".foo\\bar");
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @".foo.bar"] stringByDeletingPathExtension], @".foo");
# elif defined(OF_WII) || defined(OF_NINTENDO_DS) || \
    defined(OF_NINTENDO_3DS) || defined(OF_NINTENDO_SWITCH)
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"foo.bar"] stringByDeletingPathExtension], @"foo");
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"foo..bar"] stringByDeletingPathExtension], @"foo.");
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"sdmc:/foo./bar"] stringByDeletingPathExtension],
	    @"sdmc:/foo./bar");
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"sdmc:/foo./bar.baz"] stringByDeletingPathExtension],
	    @"sdmc:/foo./bar");
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"foo.bar/"] stringByDeletingPathExtension], @"foo");
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @".foo"] stringByDeletingPathExtension], @".foo");
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @".foo.bar"] stringByDeletingPathExtension], @".foo");
# else
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"foo.bar"] stringByDeletingPathExtension], @"foo");
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"foo..bar"] stringByDeletingPathExtension], @"foo.");
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"/foo./bar"] stringByDeletingPathExtension], @"/foo./bar");
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"/foo./bar.baz"] stringByDeletingPathExtension], @"/foo./bar");
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"foo.bar/"] stringByDeletingPathExtension], @"foo");
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @".foo"] stringByDeletingPathExtension], @".foo");
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @".foo\\bar"] stringByDeletingPathExtension], @".foo\\bar");
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @".foo.bar"] stringByDeletingPathExtension], @".foo");
# endif
}

# if defined(OF_WINDOWS) || defined(OF_MSDOS)
- (void)testStringByStandardizingPath
{
	/* TODO: Add more tests */

	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"c:\\..\\asd"] stringByStandardizingPath],
	    @"c:\\..\\asd");

#  ifndef OF_MSDOS
	OTAssertEqualObjects([[self.stringClass stringWithString:
	    @"\\\\foo\\..\\bar\\qux"] stringByStandardizingPath],
	    @"\\\\bar\\qux");
#  endif
}
# endif
#endif
@end

@implementation CustomString
- (instancetype)init
{
	self = [super init];

	@try {
		_string = [[OFMutableString alloc] init];
	} @catch (id e) {
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492

- (size_t)length
{
	return _string.length;
}
@end

@implementation SimpleMutableString
+ (void)initialize
{
	if (self == [SimpleMutableString class])
		[self inheritMethodsFromClass: [SimpleString class]];
}

- (void)replaceCharactersInRange: (OFRange)range
		      withString: (OFString *)string
{
	[_string replaceCharactersInRange: range withString: string];
}
@end

@interface EntityHandler: OFObject <OFStringXMLUnescapingDelegate>
@end

@implementation EntityHandler
-	  (OFString *)string: (OFString *)string
  containsUnknownEntityNamed: (OFString *)entity
{
	if ([entity isEqual: @"foo"])
		return @"bar";

	return nil;
}
@end

@implementation TestsAppDelegate (OFStringTests)
- (void)stringTestsWithClass: (Class)stringClass
		mutableClass: (Class)mutableStringClass
{
	void *pool = objc_autoreleasePoolPush();
	OFMutableString *mutableString1, *mutableString2, *mutableString3;
	OFString *string;
	OFArray *array;
	size_t i;
	const OFUnichar *characters;
	const uint16_t *UTF16Characters;
	OFCharacterSet *characterSet;
	EntityHandler *entityHandler;
#ifdef OF_HAVE_BLOCKS
	__block int j;
	__block bool ok;
#endif

#define C(s) ((OFString *)[stringClass stringWithString: s])

	mutableString1 = [mutableStringClass stringWithString: @"täs€"];
	mutableString2 = [mutableStringClass string];
	mutableString3 = [[mutableString1 copy] autorelease];

	TEST(@"-[isEqual:]", [mutableString1 isEqual: mutableString3] &&
	    ![mutableString1 isEqual: [[[OFObject alloc] init] autorelease]])

	TEST(@"-[compare:]",
	    [mutableString1 compare: mutableString3] == OFOrderedSame &&
	    [mutableString1 compare: @""] != OFOrderedSame &&
	    [C(@"") compare: @"a"] == OFOrderedAscending &&
	    [C(@"a") compare: @"b"] == OFOrderedAscending &&
	    [C(@"cd") compare: @"bc"] == OFOrderedDescending &&
	    [C(@"ä") compare: @"ö"] == OFOrderedAscending &&
	    [C(@"€") compare: @"ß"] == OFOrderedDescending &&
	    [C(@"aa") compare: @"z"] == OFOrderedAscending)

#ifdef OF_HAVE_UNICODE_TABLES
	TEST(@"-[caseInsensitiveCompare:]",
	    [C(@"a") caseInsensitiveCompare: @"A"] == OFOrderedSame &&
	    [C(@"Ä") caseInsensitiveCompare: @"ä"] == OFOrderedSame &&
	    [C(@"Ñ") caseInsensitiveCompare: @"Я"] == OFOrderedSame &&
	    [C(@"€") caseInsensitiveCompare: @"ß"] == OFOrderedDescending &&
	    [C(@"ß") caseInsensitiveCompare: @"→"] == OFOrderedAscending &&
	    [C(@"AA") caseInsensitiveCompare: @"z"] == OFOrderedAscending &&
	    [[stringClass stringWithUTF8String: "ABC"] caseInsensitiveCompare:
	    [stringClass stringWithUTF8String: "AbD"]] ==
	    [C(@"abc") compare: @"abd"])
#else
	TEST(@"-[caseInsensitiveCompare:]",
	    [C(@"a") caseInsensitiveCompare: @"A"] == OFOrderedSame &&
	    [C(@"AA") caseInsensitiveCompare: @"z"] == OFOrderedAscending &&
	    [[stringClass stringWithUTF8String: "ABC"] caseInsensitiveCompare:
	    [stringClass stringWithUTF8String: "AbD"]] ==
	    [C(@"abc") compare: @"abd"])
#endif

	TEST(@"-[hash] is the same if -[isEqual:] is true",
	    mutableString1.hash == mutableString3.hash)

	TEST(@"-[description]",
	    [mutableString1.description isEqual: mutableString1])

	TEST(@"-[appendString:] and -[appendUTF8String:]",
	    R([mutableString2 appendUTF8String: "1ð„ž"]) &&
	    R([mutableString2 appendString: @"3"]) &&
	    R([mutableString1 appendString: mutableString2]) &&
	    [mutableString1 isEqual: @"täs€1ð„ž3"])

	TEST(@"-[appendCharacters:length:]",
	    R([mutableString2 appendCharacters: unicharString + 6 length: 2]) &&
	    [mutableString2 isEqual: @"1ð„ž3r🀺"])

	TEST(@"-[length]", mutableString1.length == 7)
	TEST(@"-[UTF8StringLength]", mutableString1.UTF8StringLength == 13)
	TEST(@"-[hash]", mutableString1.hash == 0x705583C0)

	TEST(@"-[characterAtIndex:]",
	    [mutableString1 characterAtIndex: 0] == 't' &&
	    [mutableString1 characterAtIndex: 1] == 0xE4 &&
	    [mutableString1 characterAtIndex: 3] == 0x20AC &&
	    [mutableString1 characterAtIndex: 5] == 0x1D11E)

	EXPECT_EXCEPTION(@"Detect out of range in -[characterAtIndex:]",
	    OFOutOfRangeException, [mutableString1 characterAtIndex: 7])

	mutableString2 = [mutableStringClass stringWithString: @"abc"];

#ifdef OF_HAVE_UNICODE_TABLES
	TEST(@"-[uppercase]", R([mutableString1 uppercase]) &&
	    [mutableString1 isEqual: @"TÄS€1ð„ž3"] &&
	    R([mutableString2 uppercase]) && [mutableString2 isEqual: @"ABC"])

	TEST(@"-[lowercase]", R([mutableString1 lowercase]) &&
	    [mutableString1 isEqual: @"täs€1ð„ž3"] &&
	    R([mutableString2 lowercase]) && [mutableString2 isEqual: @"abc"])

	TEST(@"-[uppercaseString]",
	    [[mutableString1 uppercaseString] isEqual: @"TÄS€1ð„ž3"])

	TEST(@"-[lowercaseString]", R([mutableString1 uppercase]) &&
	    [[mutableString1 lowercaseString] isEqual: @"täs€1ð„ž3"])

	TEST(@"-[capitalizedString]", [C(@"džbla tdžst TDŽST").capitalizedString
	    isEqual: @"Džbla Tdžst Tdžst"])
#else
	TEST(@"-[uppercase]", R([mutableString1 uppercase]) &&
	    [mutableString1 isEqual: @"3ð„ž1€SäT"] &&
	    R([mutableString2 uppercase]) && [mutableString2 isEqual: @"ABC"])

	TEST(@"-[lowercase]", R([mutableString1 lowercase]) &&
	    [mutableString1 isEqual: @"3ð„ž1€sät"] &&
	    R([mutableString2 lowercase]) && [mutableString2 isEqual: @"abc"])

	TEST(@"-[uppercaseString]",
	    [mutableString1.uppercaseString isEqual: @"3ð„ž1€SäT"])

	TEST(@"-[lowercaseString]",
	    R([mutableString1 uppercase]) &&
	    [mutableString1.lowercaseString isEqual: @"3ð„ž1€sät"])

	TEST(@"-[capitalizedString]", [C(@"džbla tdžst TDŽST").capitalizedString
	    isEqual: @"džbla Tdžst TDŽst"])
#endif

	TEST(@"+[stringWithUTF8String:length:]",
	    (mutableString1 = [mutableStringClass
	    stringWithUTF8String: "\xEF\xBB\xBF" "foobar"
			  length: 6]) &&
	    [mutableString1 isEqual: @"foo"])

	TEST(@"+[stringWithUTF16String:]",
	    (string = [stringClass stringWithUTF16String: char16String]) &&
	    [string isEqual: @"fööbär🀺"] &&
	    (string = [stringClass stringWithUTF16String:
	    swappedChar16String]) && [string isEqual: @"fööbär🀺"])

	TEST(@"+[stringWithUTF32String:]",
	    (string = [stringClass stringWithUTF32String: unicharString]) &&
	    [string isEqual: @"fööbär🀺"] &&
	    (string = [stringClass stringWithUTF32String:
	    swappedUnicharString]) && [string isEqual: @"fööbär🀺"])

#ifdef OF_HAVE_FILES
	TEST(@"+[stringWithContentsOfFile:encoding]", (string = [stringClass
	    stringWithContentsOfFile: @"testfile.txt"
			    encoding: OFStringEncodingISO8859_1]) &&
	    [string isEqual: @"testäöü"])

	TEST(@"+[stringWithContentsOfIRI:encoding]", (string = [stringClass
	    stringWithContentsOfIRI: [OFIRI fileIRIWithPath: @"testfile.txt"]
			   encoding: OFStringEncodingISO8859_1]) &&
	    [string isEqual: @"testäöü"])
#endif

	TEST(@"-[appendUTFString:length:]",
	    R([mutableString1 appendUTF8String: "\xEF\xBB\xBF" "barqux"
					length: 6]) &&
	    [mutableString1 isEqual: @"foobar"])

	EXPECT_EXCEPTION(@"Detection of invalid UTF-8 encoding #1",
	    OFInvalidEncodingException,
	    [stringClass stringWithUTF8String: "\xE0\x80"])
	EXPECT_EXCEPTION(@"Detection of invalid UTF-8 encoding #2",
	    OFInvalidEncodingException,
	    [stringClass stringWithUTF8String: "\xF0\x80\x80\xC0"])

	TEST(@"Conversion of ISO 8859-1 to Unicode",
	    [[stringClass stringWithCString: "\xE4\xF6\xFC"
				   encoding: OFStringEncodingISO8859_1]
	    isEqual: @"äöü"])

#ifdef HAVE_ISO_8859_15
	TEST(@"Conversion of ISO 8859-15 to Unicode",
	    [[stringClass stringWithCString: "\xA4\xA6\xA8\xB4\xB8\xBC\xBD\xBE"
				   encoding: OFStringEncodingISO8859_15]
	    isEqual: @"€ŠšŽžŒœŸ"])
#endif

#ifdef HAVE_WINDOWS_1252
	TEST(@"Conversion of Windows 1252 to Unicode",
	    [[stringClass stringWithCString: "\x80\x82\x83\x84\x85\x86\x87\x88"
					     "\x89\x8A\x8B\x8C\x8E\x91\x92\x93"
					     "\x94\x95\x96\x97\x98\x99\x9A\x9B"
					     "\x9C\x9E\x9F"
				   encoding: OFStringEncodingWindows1252]
	    isEqual: @"€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“â€â€¢â€“—˜™š›œžŸ"])
#endif

#ifdef HAVE_CODEPAGE_437
	TEST(@"Conversion of Codepage 437 to Unicode",
	    [[stringClass stringWithCString: "\xB0\xB1\xB2\xDB"
				   encoding: OFStringEncodingCodepage437]
	    isEqual: @"â–‘â–’â–“â–ˆ"])
#endif

	TEST(@"Conversion of Unicode to ASCII #1",
	    !strcmp([C(@"This is a test") cStringWithEncoding:
	    OFStringEncodingASCII], "This is a test"))

	EXPECT_EXCEPTION(@"Conversion of Unicode to ASCII #2",
	    OFInvalidEncodingException,
	    [C(@"This is a tést")
	    cStringWithEncoding: OFStringEncodingASCII])

	TEST(@"Conversion of Unicode to ISO-8859-1 #1",
	    !strcmp([C(@"This is ä test") cStringWithEncoding:
	    OFStringEncodingISO8859_1], "This is \xE4 test"))

	EXPECT_EXCEPTION(@"Conversion of Unicode to ISO-8859-1 #2",
	    OFInvalidEncodingException,
	    [C(@"This is ä t€st") cStringWithEncoding:
	    OFStringEncodingISO8859_1])

#ifdef HAVE_ISO_8859_15
	TEST(@"Conversion of Unicode to ISO-8859-15 #1",
	    !strcmp([C(@"This is ä t€st") cStringWithEncoding:
	    OFStringEncodingISO8859_15], "This is \xE4 t\xA4st"))

	EXPECT_EXCEPTION(@"Conversion of Unicode to ISO-8859-15 #2",
	    OFInvalidEncodingException,
	    [C(@"This is ä t€st…") cStringWithEncoding:
	    OFStringEncodingISO8859_15])
#endif

#ifdef HAVE_WINDOWS_1252
	TEST(@"Conversion of Unicode to Windows-1252 #1",
	    !strcmp([C(@"This is ä t€st…") cStringWithEncoding:
	    OFStringEncodingWindows1252], "This is \xE4 t\x80st\x85"))

	EXPECT_EXCEPTION(@"Conversion of Unicode to Windows-1252 #2",
	    OFInvalidEncodingException, [C(@"This is ä t€st…‼")
	    cStringWithEncoding: OFStringEncodingWindows1252])
#endif

#ifdef HAVE_CODEPAGE_437
	TEST(@"Conversion of Unicode to Codepage 437 #1",
	    !strcmp([C(@"Tést strîng ░▒▓") cStringWithEncoding:
	    OFStringEncodingCodepage437], "T\x82st str\x8Cng \xB0\xB1\xB2"))

	EXPECT_EXCEPTION(@"Conversion of Unicode to Codepage 437 #2",
	    OFInvalidEncodingException, [C(@"T€st strîng ░▒▓")
	    cStringWithEncoding: OFStringEncodingCodepage437])
#endif

	TEST(@"Lossy conversion of Unicode to ASCII",
	    !strcmp([C(@"This is a tést") lossyCStringWithEncoding:
	    OFStringEncodingASCII], "This is a t?st"))

	TEST(@"Lossy conversion of Unicode to ISO-8859-1",
	    !strcmp([C(@"This is ä t€st") lossyCStringWithEncoding:
	    OFStringEncodingISO8859_1], "This is \xE4 t?st"))

#ifdef HAVE_ISO_8859_15
	TEST(@"Lossy conversion of Unicode to ISO-8859-15",
	    !strcmp([C(@"This is ä t€st…") lossyCStringWithEncoding:
	    OFStringEncodingISO8859_15], "This is \xE4 t\xA4st?"))
#endif

#ifdef HAVE_WINDOWS_1252
	TEST(@"Lossy conversion of Unicode to Windows-1252",
	    !strcmp([C(@"This is ä t€st…‼") lossyCStringWithEncoding:
	    OFStringEncodingWindows1252], "This is \xE4 t\x80st\x85?"))
#endif

#ifdef HAVE_CODEPAGE_437
	TEST(@"Lossy conversion of Unicode to Codepage 437",
	    !strcmp([C(@"T€st strîng ░▒▓") lossyCStringWithEncoding:
	    OFStringEncodingCodepage437], "T?st str\x8Cng \xB0\xB1\xB2"))
#endif

	TEST(@"+[stringWithFormat:]",
	    [(mutableString1 = [mutableStringClass stringWithFormat: @"%@:%d",
								     @"test",
								     123])
	    isEqual: @"test:123"])

	TEST(@"-[appendFormat:]",
	    R(([mutableString1 appendFormat: @"%02X", 15])) &&
	    [mutableString1 isEqual: @"test:1230F"])

	TEST(@"-[rangeOfString:]",
	    [C(@"ð„žÃ¶Ã¶") rangeOfString: @"öö"].location == 1 &&
	    [C(@"ð„žÃ¶Ã¶") rangeOfString: @"ö"].location == 1 &&
	    [C(@"ð„žÃ¶Ã¶") rangeOfString: @"ð„ž"].location == 0 &&
	    [C(@"ð„žÃ¶Ã¶") rangeOfString: @"x"].location == OFNotFound &&
	    [C(@"ð„žÃ¶Ã¶") rangeOfString: @"öö"
	    options: OFStringSearchBackwards].location == 1 &&
	    [C(@"ð„žÃ¶Ã¶") rangeOfString: @"ö"
	    options: OFStringSearchBackwards].location == 2 &&
	    [C(@"ð„žÃ¶Ã¶") rangeOfString: @"ð„ž"
	    options: OFStringSearchBackwards].location == 0 &&
	    [C(@"ð„žÃ¶Ã¶") rangeOfString: @"x"
	    options: OFStringSearchBackwards].location == OFNotFound)

	EXPECT_EXCEPTION(
	    @"Detect out of range in -[rangeOfString:options:range:]",
	    OFOutOfRangeException,
	    [C(@"ð„žÃ¶Ã¶") rangeOfString: @"ö" options: 0 range: OFMakeRange(3, 1)])

	characterSet =
	    [OFCharacterSet characterSetWithCharactersInString: @"cđ"];
	TEST(@"-[indexOfCharacterFromSet:]",
	    [C(@"abcđabcđe") indexOfCharacterFromSet: characterSet] == 2 &&
	    [C(@"abcđabcđë")
	    indexOfCharacterFromSet: characterSet
			    options: OFStringSearchBackwards] == 7 &&
	    [C(@"abcđabcđë") indexOfCharacterFromSet: characterSet
					     options: 0
					       range: OFMakeRange(4, 4)] == 6 &&
	    [C(@"abcđabcđëf")
	    indexOfCharacterFromSet: characterSet
			    options: 0
			      range: OFMakeRange(8, 2)] == OFNotFound)

	EXPECT_EXCEPTION(
	    @"Detect out of range in -[indexOfCharacterFromSet:options:range:]",
	    OFOutOfRangeException,
	    [C(@"ð„žÃ¶Ã¶") indexOfCharacterFromSet: characterSet
				       options: 0
					 range: OFMakeRange(3, 1)])

	TEST(@"-[substringWithRange:]",
	    [[C(@"ð„žÃ¶Ã¶") substringWithRange: OFMakeRange(1, 1)] isEqual: @"ö"] &&
	    [[C(@"ð„žÃ¶Ã¶") substringWithRange: OFMakeRange(3, 0)] isEqual: @""])

	EXPECT_EXCEPTION(@"Detect out of range in -[substringWithRange:] #1",
	    OFOutOfRangeException,
	    [C(@"ð„žÃ¶Ã¶") substringWithRange: OFMakeRange(2, 2)])
	EXPECT_EXCEPTION(@"Detect out of range in -[substringWithRange:] #2",
	    OFOutOfRangeException,
	    [C(@"ð„žÃ¶Ã¶") substringWithRange: OFMakeRange(4, 0)])

	TEST(@"-[stringByAppendingString:]",
	    [[C(@"foo") stringByAppendingString: @"bar"] isEqual: @"foobar"])

#ifdef OF_HAVE_FILES
# if defined(OF_WINDOWS)
	TEST(@"-[isAbsolutePath]",
	    C(@"C:\\foo").absolutePath && C(@"a:/foo").absolutePath &&
	    !C(@"foo").absolutePath && !C(@"b:foo").absolutePath &&
	    C(@"\\\\foo").absolutePath)
# elif  defined(OF_MSDOS)
	TEST(@"-[isAbsolutePath]",
	    C(@"C:\\foo").absolutePath && C(@"a:/foo").absolutePath &&
	    !C(@"foo").absolutePath && !C(@"b:foo").absolutePath)
# elif defined(OF_AMIGAOS)
	TEST(@"-[isAbsolutePath]",
	    C(@"dh0:foo").absolutePath && C(@"dh0:a/b").absolutePath &&
	    !C(@"foo/bar").absolutePath && !C(@"foo").absolutePath)
# elif defined(OF_NINTENDO_3DS) || defined(OF_WII) || \
    defined(OF_NINTENDO_SWITCH)
	TEST(@"-[isAbsolutePath]",
	    C(@"sdmc:/foo").absolutePath && !C(@"sdmc:foo").absolutePath &&
	    !C(@"foo/bar").absolutePath && !C(@"foo").absolutePath)
# else
	TEST(@"-[isAbsolutePath]",
	    C(@"/foo").absolutePath && C(@"/foo/bar").absolutePath &&
	    !C(@"foo/bar").absolutePath && !C(@"foo").absolutePath)
# endif

	mutableString1 = [mutableStringClass stringWithString: @"foo"];
# if defined(OF_WINDOWS) || defined(OF_MSDOS)
	[mutableString1 appendString: @"\\"];
# else
	[mutableString1 appendString: @"/"];
# endif
	[mutableString1 appendString: @"bar"];
	mutableString2 = [mutableStringClass stringWithString: mutableString1];
# if defined(OF_WINDOWS) || defined(OF_MSDOS)
	[mutableString2 appendString: @"\\"];
# else
	[mutableString2 appendString: @"/"];
# endif
	string = [stringClass stringWithString: mutableString2];
	[mutableString2 appendString: @"baz"];
	TEST(@"-[stringByAppendingPathComponent:]",
	    [[mutableString1 stringByAppendingPathComponent: @"baz"]
	    isEqual: mutableString2] &&
	    [[string stringByAppendingPathComponent: @"baz"]
	    isEqual: mutableString2])

# if defined(OF_WINDOWS) || defined(OF_MSDOS)
	TEST(@"-[stringByAppendingPathExtension:]",
	    [[C(@"foo") stringByAppendingPathExtension: @"bar"]
	    isEqual: @"foo.bar"] &&
	    [[C(@"c:\\tmp\\foo") stringByAppendingPathExtension: @"bar"]
	    isEqual: @"c:\\tmp\\foo.bar"] &&
	    [[C(@"c:\\tmp\\/\\") stringByAppendingPathExtension: @"bar"]
	    isEqual: @"c:\\tmp.bar"])
# elif defined(OF_AMIGAOS)
	TEST(@"-[stringByAppendingPathExtension:]",
	    [[C(@"foo") stringByAppendingPathExtension: @"bar"]
	    isEqual: @"foo.bar"] &&
	    [[C(@"foo/bar") stringByAppendingPathExtension: @"baz"]
	    isEqual: @"foo/bar.baz"])
# else
	TEST(@"-[stringByAppendingPathExtension:]",
	    [[C(@"foo") stringByAppendingPathExtension: @"bar"]
	    isEqual: @"foo.bar"] &&
	    [[C(@"foo/bar") stringByAppendingPathExtension: @"baz"]
	    isEqual: @"foo/bar.baz"] &&
	    [[C(@"foo///") stringByAppendingPathExtension: @"bar"]
	    isEqual: @"foo.bar"])
# endif
#endif

	TEST(@"-[hasPrefix:]", [C(@"foobar") hasPrefix: @"foo"] &&
	    ![C(@"foobar") hasPrefix: @"foobar0"])

	TEST(@"-[hasSuffix:]", [C(@"foobar") hasSuffix: @"bar"] &&
	    ![C(@"foobar") hasSuffix: @"foobar0"])

	i = 0;
	TEST(@"-[componentsSeparatedByString:]",
	    (array = [C(@"fooXXbarXXXXbazXXXX")
	    componentsSeparatedByString: @"XX"]) &&
	    [[array objectAtIndex: i++] isEqual: @"foo"] &&
	    [[array objectAtIndex: i++] isEqual: @"bar"] &&
	    [[array objectAtIndex: i++] isEqual: @""] &&
	    [[array objectAtIndex: i++] isEqual: @"baz"] &&
	    [[array objectAtIndex: i++] isEqual: @""] &&
	    [[array objectAtIndex: i++] isEqual: @""] &&
	    array.count == i &&
	    (array = [C(@"foo") componentsSeparatedByString: @""]) &&
	    [[array objectAtIndex: 0] isEqual: @"foo"] &&
	    array.count == 1)

	i = 0;
	TEST(@"-[componentsSeparatedByString:options:]",
	    (array = [C(@"fooXXbarXXXXbazXXXX")
	    componentsSeparatedByString: @"XX"
				options: OFStringSkipEmptyComponents]) &&
	    [[array objectAtIndex: i++] isEqual: @"foo"] &&
	    [[array objectAtIndex: i++] isEqual: @"bar"] &&
	    [[array objectAtIndex: i++] isEqual: @"baz"] &&
	    array.count == i)

	characterSet =
	    [OFCharacterSet characterSetWithCharactersInString: @"XYZ"];

	i = 0;
	TEST(@"-[componentsSeparatedByCharactersInSet:]",
	    (array = [C(@"fooXYbarXYZXbazXYXZx")
	    componentsSeparatedByCharactersInSet: characterSet]) &&
	    [[array objectAtIndex: i++] isEqual: @"foo"] &&
	    [[array objectAtIndex: i++] isEqual: @""] &&
	    [[array objectAtIndex: i++] isEqual: @"bar"] &&
	    [[array objectAtIndex: i++] isEqual: @""] &&
	    [[array objectAtIndex: i++] isEqual: @""] &&
	    [[array objectAtIndex: i++] isEqual: @""] &&
	    [[array objectAtIndex: i++] isEqual: @"baz"] &&
	    [[array objectAtIndex: i++] isEqual: @""] &&
	    [[array objectAtIndex: i++] isEqual: @""] &&
	    [[array objectAtIndex: i++] isEqual: @""] &&
	    [[array objectAtIndex: i++] isEqual: @"x"] &&
	    array.count == i)

	i = 0;
	TEST(@"-[componentsSeparatedByCharactersInSet:options:]",
	    (array = [C(@"fooXYbarXYZXbazXYXZ")
	    componentsSeparatedByCharactersInSet: characterSet
	    options: OFStringSkipEmptyComponents]) &&
	    [[array objectAtIndex: i++] isEqual: @"foo"] &&
	    [[array objectAtIndex: i++] isEqual: @"bar"] &&
	    [[array objectAtIndex: i++] isEqual: @"baz"] &&
	    array.count == i)

#ifdef OF_HAVE_FILES
# if defined(OF_WINDOWS)
	TEST(@"+[pathWithComponents:]",
	    [[stringClass pathWithComponents: [OFArray arrayWithObjects:
	    @"foo", @"bar", @"baz", nil]] isEqual: @"foo\\bar\\baz"] &&
	    [[stringClass pathWithComponents: [OFArray arrayWithObjects:
	    @"c:\\", @"foo", @"bar", @"baz", nil]]
	    isEqual: @"c:\\foo\\bar\\baz"] &&
	    [[stringClass pathWithComponents: [OFArray arrayWithObjects:
	    @"c:", @"foo", @"bar", @"baz", nil]]
	    isEqual: @"c:foo\\bar\\baz"] &&
	    [[stringClass pathWithComponents: [OFArray arrayWithObjects:
	    @"c:", @"\\", @"foo", @"bar", @"baz", nil]]
	    isEqual: @"c:\\foo\\bar\\baz"] &&
	    [[stringClass pathWithComponents: [OFArray arrayWithObjects:
	    @"c:", @"/", @"foo", @"bar", @"baz", nil]]
	    isEqual: @"c:/foo\\bar\\baz"] &&
	    [[stringClass pathWithComponents: [OFArray arrayWithObjects:
	    @"foo/", @"bar\\", @"", @"baz", @"\\", nil]]
	    isEqual: @"foo/bar\\baz"] &&
	    [[stringClass pathWithComponents: [OFArray arrayWithObjects:
	    @"foo", nil]] isEqual: @"foo"] &&
	    [[stringClass pathWithComponents: [OFArray arrayWithObject: @"c:"]]
	    isEqual: @"c:"] &&
	    [[stringClass pathWithComponents:
	    [OFArray arrayWithObject: @"c:\\"]] isEqual: @"c:\\"] &&
	    [[stringClass pathWithComponents:
	    [OFArray arrayWithObject: @"\\"]] isEqual: @"\\"] &&
	    [[stringClass pathWithComponents:
	    [OFArray arrayWithObject: @"/"]] isEqual: @"/"] &&
	    [[stringClass pathWithComponents: [OFArray arrayWithObjects:
	    @"\\\\", @"foo", @"bar", nil]] isEqual: @"\\\\foo\\bar"])
# elif defined(OF_MSDOS)
	TEST(@"+[pathWithComponents:]",
	    [[stringClass pathWithComponents: [OFArray arrayWithObjects:
	    @"foo", @"bar", @"baz", nil]] isEqual: @"foo\\bar\\baz"] &&
	    [[stringClass pathWithComponents: [OFArray arrayWithObjects:
	    @"c:\\", @"foo", @"bar", @"baz", nil]]
	    isEqual: @"c:\\foo\\bar\\baz"] &&
	    [[stringClass pathWithComponents: [OFArray arrayWithObjects:
	    @"c:", @"foo", @"bar", @"baz", nil]]
	    isEqual: @"c:foo\\bar\\baz"] &&
	    [[stringClass pathWithComponents: [OFArray arrayWithObjects:
	    @"c:", @"\\", @"foo", @"bar", @"baz", nil]]
	    isEqual: @"c:\\foo\\bar\\baz"] &&
	    [[stringClass pathWithComponents: [OFArray arrayWithObjects:
	    @"c:", @"/", @"foo", @"bar", @"baz", nil]]
	    isEqual: @"c:/foo\\bar\\baz"] &&
	    [[stringClass pathWithComponents: [OFArray arrayWithObjects:
	    @"foo/", @"bar\\", @"", @"baz", @"\\", nil]]
	    isEqual: @"foo/bar\\baz"] &&
	    [[stringClass pathWithComponents: [OFArray arrayWithObjects:
	    @"foo", nil]] isEqual: @"foo"] &&
	    [[stringClass pathWithComponents: [OFArray arrayWithObject: @"c:"]]
	    isEqual: @"c:"] &&
	    [[stringClass pathWithComponents:
	    [OFArray arrayWithObject: @"c:\\"]] isEqual: @"c:\\"] &&
	    [[stringClass pathWithComponents:
	    [OFArray arrayWithObject: @"\\"]] isEqual: @"\\"] &&
	    [[stringClass pathWithComponents:
	    [OFArray arrayWithObject: @"/"]] isEqual: @"/"])
# elif defined(OF_AMIGAOS)
	TEST(@"+[pathWithComponents:]",
	    [[stringClass pathWithComponents: [OFArray arrayWithObjects:
	    @"dh0:", @"foo", @"bar", @"baz", nil]]
	    isEqual: @"dh0:foo/bar/baz"] &&
	    [[stringClass pathWithComponents: [OFArray arrayWithObjects:
	    @"foo", @"bar", @"baz", nil]] isEqual: @"foo/bar/baz"] &&
	    [[stringClass pathWithComponents: [OFArray arrayWithObjects:
	    @"foo/", @"bar", @"", @"baz", @"/", nil]]
	    isEqual: @"foo//bar/baz//"] &&
	    [[stringClass pathWithComponents: [OFArray arrayWithObjects:
	    @"foo", nil]] isEqual: @"foo"])
# elif defined(OF_NINTENDO_3DS) || defined(OF_WII) || \
    defined(OF_NINTENDO_SWITCH)
	TEST(@"+[pathWithComponents:]",
	    [[stringClass pathWithComponents: [OFArray arrayWithObjects:
	    @"foo", @"bar", @"baz", nil]] isEqual: @"foo/bar/baz"] &&
	    [[stringClass pathWithComponents: [OFArray arrayWithObjects:
	    @"sdmc:", @"foo", @"bar", @"baz", nil]]
	    isEqual: @"sdmc:/foo/bar/baz"] &&
	    [[stringClass pathWithComponents: [OFArray arrayWithObjects:
	    @"foo/", @"bar/", @"", @"baz", @"/", nil]]
	    isEqual: @"foo/bar/baz"] &&
	    [[stringClass pathWithComponents: [OFArray arrayWithObjects:
	    @"foo", nil]] isEqual: @"foo"] &&
	    [[stringClass pathWithComponents: [OFArray arrayWithObject:
	    @"sdmc:"]] isEqual: @"sdmc:/"])
# else
	TEST(@"+[pathWithComponents:]",
	    [[stringClass pathWithComponents: [OFArray arrayWithObjects:
	    @"/", @"foo", @"bar", @"baz", nil]] isEqual: @"/foo/bar/baz"] &&
	    [[stringClass pathWithComponents: [OFArray arrayWithObjects:
	    @"foo", @"bar", @"baz", nil]] isEqual: @"foo/bar/baz"] &&
	    [[stringClass pathWithComponents: [OFArray arrayWithObjects:
	    @"foo/", @"bar", @"", @"baz", @"/", nil]]
	    isEqual: @"foo/bar/baz"] &&
	    [[stringClass pathWithComponents: [OFArray arrayWithObjects:
	    @"foo", nil]] isEqual: @"foo"])
# endif

# if defined(OF_WINDOWS)
	TEST(@"-[pathComponents]",
	    /* c:/tmp */
	    (array = C(@"c:/tmp").pathComponents) && array.count == 2 &&
	    [[array objectAtIndex: 0] isEqual: @"c:/"] &&
	    [[array objectAtIndex: 1] isEqual: @"tmp"] &&
	    /* c:\tmp\ */
	    (array = C(@"c:\\tmp\\").pathComponents) && array.count == 2 &&
	    [[array objectAtIndex: 0] isEqual: @"c:\\"] &&
	    [[array objectAtIndex: 1] isEqual: @"tmp"] &&
	    /* c:\ */
	    (array = C(@"c:\\").pathComponents) && array.count == 1 &&
	    [[array objectAtIndex: 0] isEqual: @"c:\\"] &&
	    /* c:/ */
	    (array = C(@"c:/").pathComponents) && array.count == 1 &&
	    [[array objectAtIndex: 0] isEqual: @"c:/"] &&
	    /* c: */
	    (array = C(@"c:").pathComponents) && array.count == 1 &&
	    [[array objectAtIndex: 0] isEqual: @"c:"] &&
	    /* foo\bar */
	    (array = C(@"foo\\bar").pathComponents) && array.count == 2 &&
	    [[array objectAtIndex: 0] isEqual: @"foo"] &&
	    [[array objectAtIndex: 1] isEqual: @"bar"] &&
	    /* foo\bar/baz/ */
	    (array = C(@"foo\\bar/baz/").pathComponents) && array.count == 3 &&
	    [[array objectAtIndex: 0] isEqual: @"foo"] &&
	    [[array objectAtIndex: 1] isEqual: @"bar"] &&
	    [[array objectAtIndex: 2] isEqual: @"baz"] &&
	    /* foo\/ */
	    (array = C(@"foo\\/").pathComponents) && array.count == 1 &&
	    [[array objectAtIndex: 0] isEqual: @"foo"] &&
	    /* \\foo\bar */
	    (array = C(@"\\\\foo\\bar").pathComponents) && array.count == 3 &&
	    [[array objectAtIndex: 0] isEqual: @"\\\\"] &&
	    [[array objectAtIndex: 1] isEqual: @"foo"] &&
	    [[array objectAtIndex: 2] isEqual: @"bar"] &&
	    C(@"").pathComponents.count == 0)
# elif defined(OF_MSDOS)
	TEST(@"-[pathComponents]",
	    /* c:/tmp */
	    (array = C(@"c:/tmp").pathComponents) && array.count == 2 &&
	    [[array objectAtIndex: 0] isEqual: @"c:/"] &&
	    [[array objectAtIndex: 1] isEqual: @"tmp"] &&
	    /* c:\tmp\ */
	    (array = C(@"c:\\tmp\\").pathComponents) && array.count == 2 &&
	    [[array objectAtIndex: 0] isEqual: @"c:\\"] &&
	    [[array objectAtIndex: 1] isEqual: @"tmp"] &&
	    /* c:\ */
	    (array = C(@"c:\\").pathComponents) && array.count == 1 &&
	    [[array objectAtIndex: 0] isEqual: @"c:\\"] &&
	    /* c:/ */
	    (array = C(@"c:/").pathComponents) && array.count == 1 &&
	    [[array objectAtIndex: 0] isEqual: @"c:/"] &&
	    /* c: */
	    (array = C(@"c:").pathComponents) && array.count == 1 &&
	    [[array objectAtIndex: 0] isEqual: @"c:"] &&
	    /* foo\bar */
	    (array = C(@"foo\\bar").pathComponents) && array.count == 2 &&
	    [[array objectAtIndex: 0] isEqual: @"foo"] &&
	    [[array objectAtIndex: 1] isEqual: @"bar"] &&
	    /* foo\bar/baz/ */
	    (array = C(@"foo\\bar/baz/").pathComponents) && array.count == 3 &&
	    [[array objectAtIndex: 0] isEqual: @"foo"] &&
	    [[array objectAtIndex: 1] isEqual: @"bar"] &&
	    [[array objectAtIndex: 2] isEqual: @"baz"] &&
	    /* foo\/ */
	    (array = C(@"foo\\/").pathComponents) && array.count == 1 &&
	    [[array objectAtIndex: 0] isEqual: @"foo"] &&
	    C(@"").pathComponents.count == 0)
# elif defined(OF_AMIGAOS)
	TEST(@"-[pathComponents]",
	    /* dh0:tmp */
	    (array = C(@"dh0:tmp").pathComponents) && array.count == 2 &&
	    [[array objectAtIndex: 0] isEqual: @"dh0:"] &&
	    [[array objectAtIndex: 1] isEqual: @"tmp"] &&
	    /* dh0:tmp/ */
	    (array = C(@"dh0:tmp/").pathComponents) && array.count == 2 &&
	    [[array objectAtIndex: 0] isEqual: @"dh0:"] &&
	    [[array objectAtIndex: 1] isEqual: @"tmp"] &&
	    /* dh0: */
	    (array = C(@"dh0:/").pathComponents) && array.count == 2 &&
	    [[array objectAtIndex: 0] isEqual: @"dh0:"] &&
	    [[array objectAtIndex: 1] isEqual: @"/"] &&
	    /* foo/bar */
	    (array = C(@"foo/bar").pathComponents) && array.count == 2 &&
	    [[array objectAtIndex: 0] isEqual: @"foo"] &&
	    [[array objectAtIndex: 1] isEqual: @"bar"] &&
	    /* foo/bar/baz/ */
	    (array = C(@"foo/bar/baz/").pathComponents) && array.count == 3 &&
	    [[array objectAtIndex: 0] isEqual: @"foo"] &&
	    [[array objectAtIndex: 1] isEqual: @"bar"] &&
	    [[array objectAtIndex: 2] isEqual: @"baz"] &&
	    /* foo// */
	    (array = C(@"foo//").pathComponents) && array.count == 2 &&
	    [[array objectAtIndex: 0] isEqual: @"foo"] &&
	    [[array objectAtIndex: 1] isEqual: @"/"] &&
	    C(@"").pathComponents.count == 0)
# elif defined(OF_NINTENDO_3DS) || defined(OF_WII) || \
    defined(OF_NINTENDO_SWITCH)
	TEST(@"-[pathComponents]",
	    /* sdmc:/tmp */
	    (array = C(@"sdmc:/tmp").pathComponents) && array.count == 2 &&
	    [[array objectAtIndex: 0] isEqual: @"sdmc:"] &&
	    [[array objectAtIndex: 1] isEqual: @"tmp"] &&
	    /* sdmc:/ */
	    (array = C(@"sdmc:/").pathComponents) && array.count == 1 &&
	    [[array objectAtIndex: 0] isEqual: @"sdmc:"] &&
	    /* foo/bar */
	    (array = C(@"foo/bar").pathComponents) && array.count == 2 &&
	    [[array objectAtIndex: 0] isEqual: @"foo"] &&
	    [[array objectAtIndex: 1] isEqual: @"bar"] &&
	    /* foo/bar/baz/ */
	    (array = C(@"foo/bar/baz/").pathComponents) && array.count == 3 &&
	    [[array objectAtIndex: 0] isEqual: @"foo"] &&
	    [[array objectAtIndex: 1] isEqual: @"bar"] &&
	    [[array objectAtIndex: 2] isEqual: @"baz"] &&
	    /* foo// */
	    (array = C(@"foo//").pathComponents) && array.count == 1 &&
	    [[array objectAtIndex: 0] isEqual: @"foo"] &&
	    C(@"").pathComponents.count == 0)
# else
	TEST(@"-[pathComponents]",
	    /* /tmp */
	    (array = C(@"/tmp").pathComponents) && array.count == 2 &&
	    [[array objectAtIndex: 0] isEqual: @"/"] &&
	    [[array objectAtIndex: 1] isEqual: @"tmp"] &&
	    /* /tmp/ */
	    (array = C(@"/tmp/").pathComponents) && array.count == 2 &&
	    [[array objectAtIndex: 0] isEqual: @"/"] &&
	    [[array objectAtIndex: 1] isEqual: @"tmp"] &&
	    /* / */
	    (array = C(@"/").pathComponents) && array.count == 1 &&
	    [[array objectAtIndex: 0] isEqual: @"/"] &&
	    /* foo/bar */
	    (array = C(@"foo/bar").pathComponents) && array.count == 2 &&
	    [[array objectAtIndex: 0] isEqual: @"foo"] &&
	    [[array objectAtIndex: 1] isEqual: @"bar"] &&
	    /* foo/bar/baz/ */
	    (array = C(@"foo/bar/baz/").pathComponents) && array.count == 3 &&
	    [[array objectAtIndex: 0] isEqual: @"foo"] &&
	    [[array objectAtIndex: 1] isEqual: @"bar"] &&
	    [[array objectAtIndex: 2] isEqual: @"baz"] &&
	    /* foo// */
	    (array = C(@"foo//").pathComponents) && array.count == 1 &&
	    [[array objectAtIndex: 0] isEqual: @"foo"] &&
	    C(@"").pathComponents.count == 0)
# endif

# if defined(OF_WINDOWS)
	TEST(@"-[lastPathComponent]",
	    [C(@"c:/tmp").lastPathComponent isEqual: @"tmp"] &&
	    [C(@"c:\\tmp\\").lastPathComponent isEqual: @"tmp"] &&
	    [C(@"c:\\").lastPathComponent isEqual: @"c:\\"] &&
	    [C(@"c:/").lastPathComponent isEqual: @"c:/"] &&
	    [C(@"\\").lastPathComponent isEqual: @"\\"] &&
	    [C(@"foo").lastPathComponent isEqual: @"foo"] &&
	    [C(@"foo\\bar").lastPathComponent isEqual: @"bar"] &&
	    [C(@"foo/bar/baz/").lastPathComponent isEqual: @"baz"] &&
	    [C(@"\\\\foo\\bar").lastPathComponent isEqual: @"bar"] &&
	    [C(@"\\\\").lastPathComponent isEqual: @"\\\\"])
# elif defined(OF_MSDOS)
	TEST(@"-[lastPathComponent]",
	    [C(@"c:/tmp").lastPathComponent isEqual: @"tmp"] &&
	    [C(@"c:\\tmp\\").lastPathComponent isEqual: @"tmp"] &&
	    [C(@"c:\\").lastPathComponent isEqual: @"c:\\"] &&
	    [C(@"c:/").lastPathComponent isEqual: @"c:/"] &&
	    [C(@"\\").lastPathComponent isEqual: @"\\"] &&
	    [C(@"foo").lastPathComponent isEqual: @"foo"] &&
	    [C(@"foo\\bar").lastPathComponent isEqual: @"bar"] &&
	    [C(@"foo/bar/baz/").lastPathComponent isEqual: @"baz"])
# elif defined(OF_AMIGAOS)
	TEST(@"-[lastPathComponent]",
	    [C(@"dh0:tmp").lastPathComponent isEqual: @"tmp"] &&
	    [C(@"dh0:tmp/").lastPathComponent isEqual: @"tmp"] &&
	    [C(@"dh0:/").lastPathComponent isEqual: @"/"] &&
	    [C(@"dh0:").lastPathComponent isEqual: @"dh0:"] &&
	    [C(@"foo").lastPathComponent isEqual: @"foo"] &&
	    [C(@"foo/bar").lastPathComponent isEqual: @"bar"] &&
	    [C(@"foo/bar/baz/").lastPathComponent isEqual: @"baz"])
# elif defined(OF_NINTENDO_3DS) || defined(OF_WII) || \
    defined(OF_NINTENDO_SWITCH)
	TEST(@"-[lastPathComponent]",
	    [C(@"sdmc:/tmp").lastPathComponent isEqual: @"tmp"] &&
	    [C(@"sdmc:/tmp/").lastPathComponent isEqual: @"tmp"] &&
	    [C(@"sdmc:/").lastPathComponent isEqual: @"sdmc:/"] &&
	    [C(@"sdmc:").lastPathComponent isEqual: @"sdmc:"] &&
	    [C(@"foo").lastPathComponent isEqual: @"foo"] &&
	    [C(@"foo/bar").lastPathComponent isEqual: @"bar"] &&
	    [C(@"foo/bar/baz/").lastPathComponent isEqual: @"baz"])
# else
	TEST(@"-[lastPathComponent]",
	    [C(@"/tmp").lastPathComponent isEqual: @"tmp"] &&
	    [C(@"/tmp/").lastPathComponent isEqual: @"tmp"] &&
	    [C(@"/").lastPathComponent isEqual: @"/"] &&
	    [C(@"foo").lastPathComponent isEqual: @"foo"] &&
	    [C(@"foo/bar").lastPathComponent isEqual: @"bar"] &&
	    [C(@"foo/bar/baz/").lastPathComponent isEqual: @"baz"])
# endif

	TEST(@"-[pathExtension]",
	    [C(@"foo.bar").pathExtension isEqual: @"bar"] &&
	    [C(@"foo/.bar").pathExtension isEqual: @""] &&
	    [C(@"foo/.bar.baz").pathExtension isEqual: @"baz"] &&
	    [C(@"foo/bar.baz/").pathExtension isEqual: @"baz"])

# if defined(OF_WINDOWS)
	TEST(@"-[stringByDeletingLastPathComponent]",
	    [C(@"\\tmp").stringByDeletingLastPathComponent isEqual: @"\\"] &&
	    [C(@"/tmp/").stringByDeletingLastPathComponent isEqual: @"/"] &&
	    [C(@"c:\\").stringByDeletingLastPathComponent isEqual: @"c:\\"] &&
	    [C(@"c:/").stringByDeletingLastPathComponent isEqual: @"c:/"] &&
	    [C(@"c:\\tmp/foo/").stringByDeletingLastPathComponent
	    isEqual: @"c:\\tmp"] &&
	    [C(@"foo\\bar").stringByDeletingLastPathComponent
	    isEqual: @"foo"] &&
	    [C(@"\\").stringByDeletingLastPathComponent isEqual: @"\\"] &&
	    [C(@"foo").stringByDeletingLastPathComponent isEqual: @"."] &&
	    [C(@"\\\\foo\\bar").stringByDeletingLastPathComponent
	    isEqual: @"\\\\foo"] &&
	    [C(@"\\\\foo").stringByDeletingLastPathComponent
	    isEqual: @"\\\\"] &&
	    [C(@"\\\\").stringByDeletingLastPathComponent isEqual: @"\\\\"])
# elif defined(OF_MSDOS)
	TEST(@"-[stringByDeletingLastPathComponent]",
	    [C(@"\\tmp").stringByDeletingLastPathComponent isEqual: @"\\"] &&
	    [C(@"/tmp/").stringByDeletingLastPathComponent isEqual: @"/"] &&
	    [C(@"c:\\").stringByDeletingLastPathComponent isEqual: @"c:\\"] &&
	    [C(@"c:/").stringByDeletingLastPathComponent isEqual: @"c:/"] &&
	    [C(@"c:\\tmp/foo/").stringByDeletingLastPathComponent
	    isEqual: @"c:\\tmp"] &&
	    [C(@"foo\\bar").stringByDeletingLastPathComponent
	    isEqual: @"foo"] &&
	    [C(@"\\").stringByDeletingLastPathComponent isEqual: @"\\"] &&
	    [C(@"foo").stringByDeletingLastPathComponent isEqual: @"."])
# elif defined(OF_AMIGAOS)
	TEST(@"-[stringByDeletingLastPathComponent]",
	    [C(@"dh0:").stringByDeletingLastPathComponent isEqual: @"dh0:"] &&
	    [C(@"dh0:tmp").stringByDeletingLastPathComponent
	    isEqual: @"dh0:"] &&
	    [C(@"dh0:tmp/").stringByDeletingLastPathComponent
	    isEqual: @"dh0:"] &&
	    [C(@"dh0:/").stringByDeletingLastPathComponent isEqual: @"dh0:"] &&
	    [C(@"dh0:tmp/foo/").stringByDeletingLastPathComponent
	    isEqual: @"dh0:tmp"] &&
	    [C(@"foo/bar").stringByDeletingLastPathComponent isEqual: @"foo"] &&
	    [C(@"foo").stringByDeletingLastPathComponent isEqual: @""])
# elif defined(OF_NINTENDO_3DS) || defined(OF_WII) || \
    defined(OF_NINTENDO_SWITCH)
	TEST(@"-[stringByDeletingLastPathComponent]",
	    [C(@"/tmp/").stringByDeletingLastPathComponent isEqual: @""] &&
	    [C(@"sdmc:/tmp/foo/").stringByDeletingLastPathComponent
	    isEqual: @"sdmc:/tmp"] &&
	    [C(@"sdmc:/").stringByDeletingLastPathComponent
	    isEqual: @"sdmc:/"] &&
	    [C(@"foo/bar").stringByDeletingLastPathComponent isEqual: @"foo"] &&
	    [C(@"/").stringByDeletingLastPathComponent isEqual: @""] &&
	    [C(@"foo").stringByDeletingLastPathComponent isEqual: @"."])
# else
	TEST(@"-[stringByDeletingLastPathComponent]",
	    [C(@"/tmp").stringByDeletingLastPathComponent isEqual: @"/"] &&
	    [C(@"/tmp/").stringByDeletingLastPathComponent isEqual: @"/"] &&
	    [C(@"/tmp/foo/").stringByDeletingLastPathComponent
	    isEqual: @"/tmp"] &&
	    [C(@"foo/bar").stringByDeletingLastPathComponent isEqual: @"foo"] &&
	    [C(@"/").stringByDeletingLastPathComponent isEqual: @"/"] &&
	    [C(@"foo").stringByDeletingLastPathComponent isEqual: @"."])
# endif

# if defined(OF_WINDOWS) || defined(OF_MSDOS)
	TEST(@"-[stringByDeletingPathExtension]",
	    [C(@"foo.bar").stringByDeletingPathExtension isEqual: @"foo"] &&
	    [C(@"foo..bar").stringByDeletingPathExtension isEqual: @"foo."] &&
	    [C(@"c:/foo.\\bar").stringByDeletingPathExtension
	    isEqual: @"c:/foo.\\bar"] &&
	    [C(@"c:\\foo./bar.baz").stringByDeletingPathExtension
	    isEqual: @"c:\\foo.\\bar"] &&
	    [C(@"foo.bar/").stringByDeletingPathExtension isEqual: @"foo"] &&
	    [C(@".foo").stringByDeletingPathExtension isEqual: @".foo"] &&
	    [C(@".foo.bar").stringByDeletingPathExtension isEqual: @".foo"])
# elif defined(OF_AMIGAOS)
	TEST(@"-[stringByDeletingPathExtension]",
	    [C(@"foo.bar").stringByDeletingPathExtension isEqual: @"foo"] &&
	    [C(@"foo..bar").stringByDeletingPathExtension isEqual: @"foo."] &&
	    [C(@"dh0:foo.bar").stringByDeletingPathExtension
	    isEqual: @"dh0:foo"] &&
	    [C(@"dh0:foo./bar").stringByDeletingPathExtension
	    isEqual: @"dh0:foo./bar"] &&
	    [C(@"dh0:foo./bar.baz").stringByDeletingPathExtension
	    isEqual: @"dh0:foo./bar"] &&
	    [C(@"foo.bar/").stringByDeletingPathExtension isEqual: @"foo"] &&
	    [C(@".foo").stringByDeletingPathExtension isEqual: @".foo"] &&
	    [C(@".foo\\bar").stringByDeletingPathExtension
	    isEqual: @".foo\\bar"] &&
	    [C(@".foo.bar").stringByDeletingPathExtension isEqual: @".foo"])
# elif defined(OF_NINTENDO_3DS) || defined(OF_WII) || \
    defined(OF_NINTENDO_SWITCH)
	TEST(@"-[stringByDeletingPathExtension]",
	    [C(@"foo.bar").stringByDeletingPathExtension isEqual: @"foo"] &&
	    [C(@"foo..bar").stringByDeletingPathExtension isEqual: @"foo."] &&
	    [C(@"sdmc:/foo./bar").stringByDeletingPathExtension
	    isEqual: @"sdmc:/foo./bar"] &&
	    [C(@"sdmc:/foo./bar.baz").stringByDeletingPathExtension
	    isEqual: @"sdmc:/foo./bar"] &&
	    [C(@"foo.bar/").stringByDeletingPathExtension isEqual: @"foo"] &&
	    [C(@".foo").stringByDeletingPathExtension isEqual: @".foo"] &&
	    [C(@".foo.bar").stringByDeletingPathExtension isEqual: @".foo"])
# else
	TEST(@"-[stringByDeletingPathExtension]",
	    [C(@"foo.bar").stringByDeletingPathExtension isEqual: @"foo"] &&
	    [C(@"foo..bar").stringByDeletingPathExtension isEqual: @"foo."] &&
	    [C(@"/foo./bar").stringByDeletingPathExtension
	    isEqual: @"/foo./bar"] &&
	    [C(@"/foo./bar.baz").stringByDeletingPathExtension
	    isEqual: @"/foo./bar"] &&
	    [C(@"foo.bar/").stringByDeletingPathExtension isEqual: @"foo"] &&
	    [C(@".foo").stringByDeletingPathExtension isEqual: @".foo"] &&
	    [C(@".foo\\bar").stringByDeletingPathExtension
	    isEqual: @".foo\\bar"] &&
	    [C(@".foo.bar").stringByDeletingPathExtension isEqual: @".foo"])
# endif

# ifdef OF_WINDOWS
	/* TODO: Add more tests */
	TEST(@"-[stringByStandardizingPath]",
	    [C(@"\\\\foo\\..\\bar\\qux").stringByStandardizingPath
	    isEqual: @"\\\\bar\\qux"] &&
	    [C(@"c:\\..\\asd").stringByStandardizingPath
	    isEqual: @"c:\\..\\asd"])
# endif
#endif

	TEST(@"-[longLongValue]",
	    C(@"1234").longLongValue == 1234 &&
	    C(@"\r\n+123  ").longLongValue == 123 &&
	    C(@"-500\t").longLongValue == -500 &&
	    [C(@"-0x10\t") longLongValueWithBase: 0] == -0x10 &&
	    C(@"\t\t\r\n").longLongValue == 0 &&
	    [C(@"123f") longLongValueWithBase: 16] == 0x123f &&
	    [C(@"-1234") longLongValueWithBase: 0] == -1234 &&
	    [C(@"\t\n0xABcd\r") longLongValueWithBase: 0] == 0xABCD &&
	    [C(@"1234567") longLongValueWithBase: 8] == 01234567 &&
	    [C(@"\r\n0123") longLongValueWithBase: 0] == 0123 &&
	    [C(@"765\t") longLongValueWithBase: 8] == 0765 &&
	    [C(@"\t\t\r\n") longLongValueWithBase: 8] == 0)

	TEST(@"-[unsignedLongLongValue]",
	    C(@"1234").unsignedLongLongValue == 1234 &&
	    C(@"\r\n+123  ").unsignedLongLongValue == 123 &&
	    C(@"\t\t\r\n").unsignedLongLongValue == 0 &&
	    [C(@"123f") unsignedLongLongValueWithBase: 16] == 0x123f &&
	    [C(@"1234") unsignedLongLongValueWithBase: 0] == 1234 &&
	    [C(@"\t\n0xABcd\r") unsignedLongLongValueWithBase: 0] == 0xABCD &&
	    [C(@"1234567") unsignedLongLongValueWithBase: 8] == 01234567 &&
	    [C(@"\r\n0123") unsignedLongLongValueWithBase: 0] == 0123 &&
	    [C(@"765\t") unsignedLongLongValueWithBase: 8] == 0765 &&
	    [C(@"\t\t\r\n") unsignedLongLongValueWithBase: 8] == 0)

	/*
	 * These test numbers can be generated without rounding if we have IEEE
	 * floating point numbers, thus we can use == on them.
	 */
	TEST(@"-[floatValue]",
	    C(@"\t-0.25 ").floatValue == -0.25 &&
	    C(@"\r\n\tINF\t\n").floatValue == INFINITY &&
	    C(@"\r -INFINITY\n").floatValue == -INFINITY &&
	    isnan(C(@"   NAN\t\t").floatValue) &&
	    isnan(C(@"   -NaN\t\t").floatValue))

#if !defined(OF_ANDROID) && !defined(OF_SOLARIS) && !defined(OF_HPUX) && \
    !defined(OF_DJGPP) && !defined(OF_AMIGAOS_M68K)
# define INPUT @"\t-0x1.FFFFFFFFFFFFFP-1020 "
# define EXPECTED -0x1.FFFFFFFFFFFFFP-1020
#else
/* Android, Solaris, HP-UX, DJGPP and AmigaOS 3 do not accept 0x for strtod() */
# if (!defined(OF_SOLARIS) || !defined(OF_X86)) && !defined(OF_AMIGAOS_M68K)
#  define INPUT @"\t-0.123456789 "
#  define EXPECTED -0.123456789
# else
/*
 * Solaris' strtod() has weird rounding on x86, but not on AMD64.
 * AmigaOS 3 with libnix has weird rounding as well.
 */
#  define INPUT @"\t-0.125 "
#  define EXPECTED -0.125
# endif
#endif
	TEST(@"-[doubleValue]",
	    INPUT.doubleValue == EXPECTED &&
	    C(@"\r\n\tINF\t\n").doubleValue == INFINITY &&
	    C(@"\r -INFINITY\n").doubleValue == -INFINITY &&
	    isnan(C(@"   NAN\t\t").doubleValue))
#undef INPUT
#undef EXPECTED

	EXPECT_EXCEPTION(@"Detect invalid chars in -[longLongValue] #1",
	    OFInvalidFormatException, [C(@"abc") longLongValue])
	EXPECT_EXCEPTION(@"Detect invalid chars in -[longLongValue] #2",
	    OFInvalidFormatException, [C(@"0a") longLongValue])
	EXPECT_EXCEPTION(@"Detect invalid chars in -[longLongValue] #3",
	    OFInvalidFormatException, [C(@"0 1") longLongValue])
	EXPECT_EXCEPTION(@"Detect invalid chars in -[longLongValue] #4",
	    OFInvalidFormatException,
	    [C(@"0xABCDEFG") longLongValueWithBase: 0])
	EXPECT_EXCEPTION(@"Detect invalid chars in -[longLongValue] #5",
	    OFInvalidFormatException, [C(@"0x") longLongValueWithBase: 0])

	EXPECT_EXCEPTION(@"Detect invalid chars in -[floatValue] #1",
	    OFInvalidFormatException, [C(@"0.0a") floatValue])
	EXPECT_EXCEPTION(@"Detect invalid chars in -[floatValue] #2",
	    OFInvalidFormatException, [C(@"0 0") floatValue])
#ifdef HAVE_STRTOF_L
	/*
	 * Only do this if we have strtof_l, as the locale might allow the
	 * comma.
	 */
	EXPECT_EXCEPTION(@"Detect invalid chars in -[floatValue] #3",
	    OFInvalidFormatException, [C(@"0,0") floatValue])
#endif

	EXPECT_EXCEPTION(@"Detect invalid chars in -[doubleValue] #1",
	    OFInvalidFormatException, [C(@"0.0a") doubleValue])
	EXPECT_EXCEPTION(@"Detect invalid chars in -[doubleValue] #2",
	    OFInvalidFormatException, [C(@"0 0") doubleValue])
#ifdef HAVE_STRTOD_L
	/*
	 * Only do this if we have strtod_l, as the locale might allow the
	 * comma.
	 */
	EXPECT_EXCEPTION(@"Detect invalid chars in -[doubleValue] #3",
	    OFInvalidFormatException, [C(@"0,0") doubleValue])
#endif

	EXPECT_EXCEPTION(@"Detect out of range in -[longLongValue]",
	    OFOutOfRangeException,
	    [C(@"-12345678901234567890123456789012345678901234567890"
	       @"12345678901234567890123456789012345678901234567890")
	    longLongValueWithBase: 16])

	EXPECT_EXCEPTION(@"Detect out of range in -[unsignedLongLongValue]",
	    OFOutOfRangeException,
	    [C(@"0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF"
	       @"0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF")
	    unsignedLongLongValueWithBase: 16])

	TEST(@"-[characters]", (characters = C(@"fööbär🀺").characters) &&
	    !memcmp(characters, unicharString + 1, sizeof(unicharString) - 8))

#ifdef OF_BIG_ENDIAN
# define swappedByteOrder OFByteOrderLittleEndian
#else
# define swappedByteOrder OFByteOrderBigEndian
#endif
	TEST(@"-[UTF16String]", (UTF16Characters = C(@"fööbär🀺").UTF16String) &&
	    !memcmp(UTF16Characters, char16String + 1,
	    OFUTF16StringLength(char16String) * 2) &&
	    (UTF16Characters = [C(@"fööbär🀺")
	    UTF16StringWithByteOrder: swappedByteOrder]) &&
	    !memcmp(UTF16Characters, swappedChar16String + 1,
	    OFUTF16StringLength(swappedChar16String) * 2))

	TEST(@"-[UTF16StringLength]", C(@"fööbär🀺").UTF16StringLength == 8)

	TEST(@"-[UTF32String]", (characters = C(@"fööbär🀺").UTF32String) &&
	    !memcmp(characters, unicharString + 1,
	    OFUTF32StringLength(unicharString) * 4) &&
	    (characters = [C(@"fööbär🀺") UTF32StringWithByteOrder:
	    swappedByteOrder]) &&
	    !memcmp(characters, swappedUnicharString + 1,
	    OFUTF32StringLength(swappedUnicharString) * 4))
#undef swappedByteOrder

	TEST(@"-[stringByMD5Hashing]", [C(@"asdfoobar").stringByMD5Hashing
	    isEqual: @"184dce2ec49b5422c7cfd8728864db4c"])

	TEST(@"-[stringByRIPEMD160Hashing]",
	    [C(@"asdfoobar").stringByRIPEMD160Hashing
	    isEqual: @"021d773b0fac06eb6755ca6aa58a580c980f7f13"])

	TEST(@"-[stringBySHA1Hashing]", [C(@"asdfoobar").stringBySHA1Hashing
	    isEqual: @"f5f81ac0a8b5cbfdc4585ec1ad32e7b3a12b9b49"])

	TEST(@"-[stringBySHA224Hashing]", [C(@"asdfoobar").stringBySHA224Hashing
	    isEqual: @"5a06822dcbd5a874f67d062b80b9d8a9cb9b5b303960b9da9290c192"
	    ])

	TEST(@"-[stringBySHA256Hashing]", [C(@"asdfoobar").stringBySHA256Hashing
	    isEqual: @"28e65b1dcd7f6ce2ea6277b15f87b913628b5500bf7913a2bbf4cedc"
		     @"fa1215f6"])

	TEST(@"-[stringBySHA384Hashing]", [C(@"asdfoobar").stringBySHA384Hashing
	    isEqual: @"73286da882ffddca2f45e005cfa6b44f3fc65bfb26db1d087ded2f9c"
		     @"279e5addf8be854044bca0cece073fce28eec7d9"])

	TEST(@"-[stringBySHA512Hashing]", [C(@"asdfoobar").stringBySHA512Hashing
	    isEqual: @"0464c427da158b02161bb44a3090bbfc594611ef6a53603640454b56"
		     @"412a9247c3579a329e53a5dc74676b106755e3394f9454a2d4227324"
		     @"2615d32f80437d61"])

	characterSet =
	    [OFCharacterSet characterSetWithCharactersInString: @"abfo'_~$ðŸ"];
	TEST(@"-[stringByAddingPercentEncodingWithAllowedCharacters:]",
	    [[C(@"foo\"ba'_~$]ðŸðŸŒ")
	    stringByAddingPercentEncodingWithAllowedCharacters: characterSet]
	    isEqual: @"foo%22ba'_~$%5DðŸ%F0%9F%8D%8C"])

	TEST(@"-[stringByRemovingPercentEncoding]",
	    [C(@"foo%20bar%22+%24%F0%9F%8D%8C").stringByRemovingPercentEncoding
	    isEqual: @"foo bar\"+$ðŸŒ"])

	TEST(@"-[insertString:atIndex:]",
	    (mutableString1 = [mutableStringClass
	    stringWithString: @"ð„žÃ¶Ã¶Ã¶bä€"]) &&
	    R([mutableString1 insertString: @"äöü" atIndex: 3]) &&
	    [mutableString1 isEqual: @"ð„žÃ¶Ã¶Ã¤Ã¶Ã¼Ã¶bä€"])

	EXPECT_EXCEPTION(@"Detect invalid format in "
	    @"-[stringByRemovingPercentEncoding] #1",
	    OFInvalidFormatException,
	    [C(@"foo%xbar") stringByRemovingPercentEncoding])
	EXPECT_EXCEPTION(@"Detect invalid encoding in "
	    @"-[stringByRemovingPercentEncoding] #2",
	    OFInvalidEncodingException,
	    [C(@"foo%FFbar") stringByRemovingPercentEncoding])

	TEST(@"-[setCharacter:atIndex:]",
	    (mutableString1 = [mutableStringClass
	    stringWithString: @"abäde"]) &&
	    R([mutableString1 setCharacter: 0xF6 atIndex: 2]) &&
	    [mutableString1 isEqual: @"aböde"] &&
	    R([mutableString1 setCharacter: 'c' atIndex: 2]) &&
	    [mutableString1 isEqual: @"abcde"] &&
	    R([mutableString1 setCharacter: 0x20AC atIndex: 3]) &&
	    [mutableString1 isEqual: @"abc€e"] &&
	    R([mutableString1 setCharacter: 'x' atIndex: 1]) &&
	    [mutableString1 isEqual: @"axc€e"])

	TEST(@"-[deleteCharactersInRange:]",
	    (mutableString1 = [mutableStringClass
	    stringWithString: @"ð„žÃ¶Ã¶Ã¶bä€"]) &&
	    R([mutableString1 deleteCharactersInRange: OFMakeRange(1, 3)]) &&
	    [mutableString1 isEqual: @"ð„žbä€"] &&
	    R([mutableString1 deleteCharactersInRange: OFMakeRange(0, 4)]) &&
	    [mutableString1 isEqual: @""])

	TEST(@"-[replaceCharactersInRange:withString:]",
	    (mutableString1 = [mutableStringClass
	    stringWithString: @"ð„žÃ¶Ã¶Ã¶bä€"]) &&
	    R([mutableString1 replaceCharactersInRange: OFMakeRange(1, 3)
					    withString: @"äöüß"]) &&
	    [mutableString1 isEqual: @"ð„žÃ¤Ã¶Ã¼ÃŸbä€"] &&
	    R([mutableString1 replaceCharactersInRange: OFMakeRange(4, 2)
					    withString: @"b"]) &&
	    [mutableString1 isEqual: @"ð„žÃ¤Ã¶Ã¼bä€"] &&
	    R([mutableString1 replaceCharactersInRange: OFMakeRange(0, 7)
					    withString: @""]) &&
	    [mutableString1 isEqual: @""])

	EXPECT_EXCEPTION(@"Detect OoR in -[deleteCharactersInRange:] #1",
	    OFOutOfRangeException,
	    {
		mutableString1 = [mutableStringClass stringWithString: @"ð„žÃ¶Ã¶"];
		[mutableString1 deleteCharactersInRange: OFMakeRange(2, 2)];
	    })

	EXPECT_EXCEPTION(@"Detect OoR in -[deleteCharactersInRange:] #2",
	    OFOutOfRangeException,
	    [mutableString1 deleteCharactersInRange: OFMakeRange(4, 0)])

	EXPECT_EXCEPTION(@"Detect OoR in "
	    @"-[replaceCharactersInRange:withString:] #1",
	    OFOutOfRangeException,
	    [mutableString1 replaceCharactersInRange: OFMakeRange(2, 2)
					  withString: @""])

	EXPECT_EXCEPTION(@"Detect OoR in "
	    @"-[replaceCharactersInRange:withString:] #2",
	    OFOutOfRangeException,
	    [mutableString1 replaceCharactersInRange: OFMakeRange(4, 0)
					  withString: @""])

	TEST(@"-[replaceOccurrencesOfString:withString:]",
	    (mutableString1 = [mutableStringClass stringWithString:
	    @"asd fo asd fofo asd"]) &&
	    R([mutableString1 replaceOccurrencesOfString: @"fo"
					      withString: @"foo"]) &&
	    [mutableString1 isEqual: @"asd foo asd foofoo asd"] &&
	    (mutableString1 = [mutableStringClass stringWithString: @"XX"]) &&
	    R([mutableString1 replaceOccurrencesOfString: @"X"
					      withString: @"XX"]) &&
	    [mutableString1 isEqual: @"XXXX"])

	TEST(@"-[replaceOccurrencesOfString:withString:options:range:]",
	    (mutableString1 = [mutableStringClass stringWithString:
	    @"foofoobarfoobarfoo"]) && R([mutableString1
	    replaceOccurrencesOfString: @"oo"
			    withString: @"óò"
			       options: 0
				 range: OFMakeRange(2, 15)]) &&
	    [mutableString1 isEqual: @"foofóòbarfóòbarfoo"])

	TEST(@"-[deleteLeadingWhitespaces]",
	    (mutableString1 = [mutableStringClass
	    stringWithString: whitespace[0]]) &&
	    R([mutableString1 deleteLeadingWhitespaces]) &&
	    [mutableString1 isEqual: @"asd  \t \t\t\r\n"] &&
	    (mutableString1 = [mutableStringClass
	    stringWithString: whitespace[1]]) &&
	    R([mutableString1 deleteLeadingWhitespaces]) &&
	    [mutableString1 isEqual: @""])

	TEST(@"-[deleteTrailingWhitespaces]",
	    (mutableString1 = [mutableStringClass
	    stringWithString: whitespace[0]]) &&
	    R([mutableString1 deleteTrailingWhitespaces]) &&
	    [mutableString1 isEqual: @" \r \t\n\t \tasd"] &&
	    (mutableString1 = [mutableStringClass
	    stringWithString: whitespace[1]]) &&
	    R([mutableString1 deleteTrailingWhitespaces]) &&
	    [mutableString1 isEqual: @""])

	TEST(@"-[deleteEnclosingWhitespaces]",
	    (mutableString1 = [mutableStringClass
	    stringWithString: whitespace[0]]) &&
	    R([mutableString1 deleteEnclosingWhitespaces]) &&
	    [mutableString1 isEqual: @"asd"] &&
	    (mutableString1 = [mutableStringClass
	    stringWithString: whitespace[1]]) &&
	    R([mutableString1 deleteEnclosingWhitespaces]) &&
	    [mutableString1 isEqual: @""])

	TEST(@"-[stringByXMLEscaping]",
	    (string = C(@"<hello> &world'\"!&").stringByXMLEscaping) &&
	    [string isEqual: @"&lt;hello&gt; &amp;world&apos;&quot;!&amp;"])

	TEST(@"-[stringByXMLUnescaping]",
	    [string.stringByXMLUnescaping isEqual: @"<hello> &world'\"!&"] &&
	    [C(@"&#x79;").stringByXMLUnescaping isEqual: @"y"] &&
	    [C(@"&#xe4;").stringByXMLUnescaping isEqual: @"ä"] &&
	    [C(@"&#8364;").stringByXMLUnescaping isEqual: @"€"] &&
	    [C(@"&#x1D11E;").stringByXMLUnescaping isEqual: @"ð„ž"])

	EXPECT_EXCEPTION(@"Detect unknown entities in -[stringByXMLUnescaping]",
	    OFUnknownXMLEntityException, [C(@"&foo;") stringByXMLUnescaping])
	EXPECT_EXCEPTION(@"Detect invalid entities in -[stringByXMLUnescaping] "
	    @"#1", OFInvalidFormatException,
	    [C(@"x&amp") stringByXMLUnescaping])
	EXPECT_EXCEPTION(@"Detect invalid entities in -[stringByXMLUnescaping] "
	    @"#2", OFInvalidFormatException, [C(@"&#;") stringByXMLUnescaping])
	EXPECT_EXCEPTION(@"Detect invalid entities in -[stringByXMLUnescaping] "
	    @"#3", OFInvalidFormatException, [C(@"&#x;") stringByXMLUnescaping])
	EXPECT_EXCEPTION(@"Detect invalid entities in -[stringByXMLUnescaping] "
	    @"#4", OFInvalidFormatException, [C(@"&#g;") stringByXMLUnescaping])
	EXPECT_EXCEPTION(@"Detect invalid entities in -[stringByXMLUnescaping] "
	    @"#5", OFInvalidFormatException,
	    [C(@"&#xg;") stringByXMLUnescaping])

	TEST(@"-[stringByXMLUnescapingWithDelegate:]",
	    (entityHandler = [[[EntityHandler alloc] init] autorelease]) &&
	    [[C(@"x&foo;y") stringByXMLUnescapingWithDelegate: entityHandler]
	    isEqual: @"xbary"])

#ifdef OF_HAVE_BLOCKS
	TEST(@"-[stringByXMLUnescapingWithBlock:]",
	    [[C(@"x&foo;y") stringByXMLUnescapingWithBlock:
		^ OFString *(OFString *str, OFString *entity) {
		    if ([entity isEqual: @"foo"])
			    return @"bar";

		    return nil;
	    }] isEqual: @"xbary"])

	j = 0;
	ok = true;
	[C(@"foo\nbar\nbaz") enumerateLinesUsingBlock:
	    ^ (OFString *line, bool *stop) {
		switch (j) {
		case 0:
			if (![line isEqual: @"foo"])
				ok = false;
			break;
		case 1:
			if (![line isEqual: @"bar"])
				ok = false;
			break;
		case 2:
			if (![line isEqual: @"baz"])
				ok = false;
			break;
		default:
			ok = false;
		}

		j++;
	}];
	TEST(@"-[enumerateLinesUsingBlock:]", ok)
#endif

#undef C

	objc_autoreleasePoolPop(pool);
}

- (void)stringTests
{
	module = @"OFString";
	[self stringTestsWithClass: [SimpleString class]
		      mutableClass: [SimpleMutableString class]];

	module = @"OFString_UTF8";
	[self stringTestsWithClass: [OFUTF8String class]
		      mutableClass: [OFMutableUTF8String class]];
}
@end







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<









<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<

1645
1646
1647
1648
1649
1650
1651

















1652
1653
1654
1655
1656
1657
1658
1659
1660



































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































1661

- (size_t)length
{
	return _string.length;
}
@end


















@implementation EntityHandler
-	  (OFString *)string: (OFString *)string
  containsUnknownEntityNamed: (OFString *)entity
{
	if ([entity isEqual: @"foo"])
		return @"bar";

	return nil;
}



































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































@end

Added tests/OFSubprocessTests.m version [c950e491df].

















































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
/*
 * Copyright (c) 2008-2024 Jonathan Schleifer <js@nil.im>
 *
 * 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!"];
#ifdef OF_HAVE_UNICODE_TABLES
	OTAssertEqualObjects([subprocess readLine], @"HELLÖ WORLD!");
#else
	OTAssertEqualObjects([subprocess readLine], @"HELLö WORLD!");
#endif

	[subprocess closeForWriting];

	OTAssertEqual([subprocess waitForTermination], 0);
}
@end

Modified tests/OFSystemInfoTests.m from [f3db5fbea9] to [0545403f54].

11
12
13
14
15
16
17
18




19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

41
42
43
44

45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101

102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145

146
147
148




149



150
151
152

153
154
155
156
157

158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206





207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223

224
225
226

227
228
229
230

231
232
233
234

235
236
237
238
239
240
241
242
243
244
245
246
247
248
249

250
251

252
253
254
255
256
257


258
259
260
261

262
263
 * 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"





#ifdef OF_HAVE_SOCKETS
static void
printAddresses(OFData *addresses, bool *firstAddress)
{
	size_t count = addresses.count;

	for (size_t i = 0; i < count; i++) {
		const OFSocketAddress *address = [addresses itemAtIndex: i];

		if (!*firstAddress)
			[OFStdOut writeString: @", "];

		*firstAddress = false;

		[OFStdOut writeString: OFSocketAddressString(address)];
	}
}
#endif

@implementation TestsAppDelegate (OFSystemInfoTests)
- (void)systemInfoTests

{
	void *pool = objc_autoreleasePoolPush();
#ifdef OF_HAVE_SOCKETS
	OFDictionary *networkInterfaces;

	bool firstInterface = true;
#endif

	[OFStdOut setForegroundColor: [OFColor lime]];

	[OFStdOut writeFormat: @"[OFSystemInfo] Page size: %zd\n",
	    [OFSystemInfo pageSize]];

	[OFStdOut writeFormat: @"[OFSystemInfo] Number of CPUs: %zd\n",
	    [OFSystemInfo numberOfCPUs]];

	[OFStdOut writeFormat: @"[OFSystemInfo] ObjFW version: %@\n",
	    [OFSystemInfo ObjFWVersion]];

	[OFStdOut writeFormat: @"[OFSystemInfo] ObjFW version major: %u\n",
	    [OFSystemInfo ObjFWVersionMajor]];

	[OFStdOut writeFormat: @"[OFSystemInfo] ObjFW version minor: %u\n",
	    [OFSystemInfo ObjFWVersionMinor]];

	[OFStdOut writeFormat: @"[OFSystemInfo] Operating system name: %@\n",
	    [OFSystemInfo operatingSystemName]];

	[OFStdOut writeFormat:
	    @"[OFSystemInfo] Operating system version: %@\n",
	    [OFSystemInfo operatingSystemVersion]];

	[OFStdOut writeFormat: @"[OFSystemInfo] User config IRI: %@\n",
	    [OFSystemInfo userConfigIRI].string];

	[OFStdOut writeFormat: @"[OFSystemInfo] User data IRI: %@\n",
	    [OFSystemInfo userDataIRI].string];

	[OFStdOut writeFormat: @"[OFSystemInfo] Temporary directory IRI: %@\n",
	    [OFSystemInfo temporaryDirectoryIRI].string];

	[OFStdOut writeFormat: @"[OFSystemInfo] CPU vendor: %@\n",
	    [OFSystemInfo CPUVendor]];

	[OFStdOut writeFormat: @"[OFSystemInfo] CPU model: %@\n",
	    [OFSystemInfo CPUModel]];

#if defined(OF_AMD64) || defined(OF_X86)
	[OFStdOut writeFormat: @"[OFSystemInfo] Supports MMX: %d\n",
	    [OFSystemInfo supportsMMX]];

	[OFStdOut writeFormat: @"[OFSystemInfo] Supports 3DNow!: %d\n",
	    [OFSystemInfo supports3DNow]];

	[OFStdOut writeFormat: @"[OFSystemInfo] Supports enhanced 3DNow!: %d\n",
	    [OFSystemInfo supportsEnhanced3DNow]];

	[OFStdOut writeFormat: @"[OFSystemInfo] Supports SSE: %d\n",
	    [OFSystemInfo supportsSSE]];

	[OFStdOut writeFormat: @"[OFSystemInfo] Supports SSE2: %d\n",
	    [OFSystemInfo supportsSSE2]];


	[OFStdOut writeFormat: @"[OFSystemInfo] Supports SSE3: %d\n",
	    [OFSystemInfo supportsSSE3]];

	[OFStdOut writeFormat: @"[OFSystemInfo] Supports SSSE3: %d\n",
	    [OFSystemInfo supportsSSSE3]];

	[OFStdOut writeFormat: @"[OFSystemInfo] Supports SSE4.1: %d\n",
	    [OFSystemInfo supportsSSE41]];

	[OFStdOut writeFormat: @"[OFSystemInfo] Supports SSE4.2: %d\n",
	    [OFSystemInfo supportsSSE42]];

	[OFStdOut writeFormat: @"[OFSystemInfo] Supports AVX: %d\n",
	    [OFSystemInfo supportsAVX]];

	[OFStdOut writeFormat: @"[OFSystemInfo] Supports AVX2: %d\n",
	    [OFSystemInfo supportsAVX2]];

	[OFStdOut writeFormat: @"[OFSystemInfo] Supports AES-NI: %d\n",
	    [OFSystemInfo supportsAESNI]];

	[OFStdOut writeFormat: @"[OFSystemInfo] Supports SHA extensions: %d\n",
	    [OFSystemInfo supportsSHAExtensions]];

	[OFStdOut writeFormat: @"[OFSystemInfo] Supports fused multiply-add: "
	    @"%d\n",
	    [OFSystemInfo supportsFusedMultiplyAdd]];

	[OFStdOut writeFormat: @"[OFSystemInfo] Supports F16C: %d\n",
	    [OFSystemInfo supportsF16C]];

	[OFStdOut writeFormat:
	    @"[OFSystemInfo] Supports AVX-512 Foundation: %d\n",
	    [OFSystemInfo supportsAVX512Foundation]];

	[OFStdOut writeFormat:
	    @"[OFSystemInfo] Supports AVX-512 Conflict Detection Instructions: "
	    @"%d\n",
	    [OFSystemInfo supportsAVX512ConflictDetectionInstructions]];

	[OFStdOut writeFormat:
	    @"[OFSystemInfo] Supports AVX-512 Exponential and Reciprocal "
	    @"Instructions: %d\n",

	    [OFSystemInfo supportsAVX512ExponentialAndReciprocalInstructions]];

	[OFStdOut writeFormat:




	    @"[OFSystemInfo] Supports AVX-512 Prefetch Instructions: %d\n",



	    [OFSystemInfo supportsAVX512PrefetchInstructions]];

	[OFStdOut writeFormat:

	    @"[OFSystemInfo] Supports AVX-512 Vector Length Extensions: %d\n",
	    [OFSystemInfo supportsAVX512VectorLengthExtensions]];

	[OFStdOut writeFormat:
	    @"[OFSystemInfo] Supports AVX-512 Doubleword and Quadword "

	    @"Instructions: %d\n",
	    [OFSystemInfo supportsAVX512DoublewordAndQuadwordInstructions]];

	[OFStdOut writeFormat:
	    @"[OFSystemInfo] Supports AVX-512 Byte and Word Instructions: %d\n",
	    [OFSystemInfo supportsAVX512ByteAndWordInstructions]];

	[OFStdOut writeFormat:
	    @"[OFSystemInfo] Supports AVX-512 Integer Fused Multiply Add: %d\n",
	    [OFSystemInfo supportsAVX512IntegerFusedMultiplyAdd]];

	[OFStdOut writeFormat:
	    @"[OFSystemInfo] Supports AVX-512 Vector Byte Manipulation "
	    @"Instructions: %d\n",
	    [OFSystemInfo supportsAVX512VectorByteManipulationInstructions]];

	[OFStdOut writeFormat:
	    @"[OFSystemInfo] Supports AVX-512 Vector Population Count "
	    @"Instruction: %d\n",
	    [OFSystemInfo supportsAVX512VectorPopulationCountInstruction]];

	[OFStdOut writeFormat:
	    @"[OFSystemInfo] Supports AVX-512 Vector Neutral Network "
	    @"Instructions: %d\n",
	    [OFSystemInfo supportsAVX512VectorNeuralNetworkInstructions]];

	[OFStdOut writeFormat:
	    @"[OFSystemInfo] Supports AVX-512 Vector Byte Manipulation "
	    @"Instructions 2: %d\n",
	    [OFSystemInfo supportsAVX512VectorByteManipulationInstructions2]];

	[OFStdOut writeFormat:
	    @"[OFSystemInfo] Supports AVX-512 Bit Algorithms: %d\n",
	    [OFSystemInfo supportsAVX512BitAlgorithms]];

	[OFStdOut writeFormat:
	    @"[OFSystemInfo] Supports AVX-512 Float16 Instructions: %d\n",
	    [OFSystemInfo supportsAVX512Float16Instructions]];

	[OFStdOut writeFormat:
	    @"[OFSystemInfo] Supports AVX-512 BFloat16 Instructions: %d\n",
	    [OFSystemInfo supportsAVX512BFloat16Instructions]];
#endif

#ifdef OF_POWERPC
	[OFStdOut writeFormat: @"[OFSystemInfo] Supports AltiVec: %d\n",
	    [OFSystemInfo supportsAltiVec]];
#endif






#ifdef OF_HAVE_SOCKETS
	networkInterfaces = [OFSystemInfo networkInterfaces];
	[OFStdOut writeString: @"[OFSystemInfo] Network interfaces: "];
	for (OFString *name in networkInterfaces) {
		bool firstAddress = true;
		OFNetworkInterface interface;
		OFData *hardwareAddress;

		if (!firstInterface)
			[OFStdOut writeString: @"; "];

		firstInterface = false;

		[OFStdOut writeFormat: @"%@(", name];

		interface = [networkInterfaces objectForKey: name];


		printAddresses([interface objectForKey:
		    OFNetworkInterfaceIPv4Addresses], &firstAddress);
# ifdef OF_HAVE_IPV6

		printAddresses([interface objectForKey:
		    OFNetworkInterfaceIPv6Addresses], &firstAddress);
# endif
# ifdef OF_HAVE_IPX

		printAddresses([interface objectForKey:
		    OFNetworkInterfaceIPXAddresses], &firstAddress);
# endif
# ifdef OF_HAVE_APPLETALK

		printAddresses([interface objectForKey:
		    OFNetworkInterfaceAppleTalkAddresses], &firstAddress);
# endif

		hardwareAddress = [interface
		    objectForKey: OFNetworkInterfaceHardwareAddress];
		if (hardwareAddress != nil) {
			const unsigned char *bytes = hardwareAddress.items;
			size_t length = hardwareAddress.count;

			if (!firstAddress)
				[OFStdOut writeString: @", "];

			for (size_t i = 0; i < length; i++) {
				if (i > 0)

					[OFStdOut writeString: @":"];


				[OFStdOut writeFormat: @"%02X", bytes[i]];
			}
		}

		[OFStdOut writeString: @")"];
	}


	[OFStdOut writeString: @"\n"];
#endif

	objc_autoreleasePoolPop(pool);

}
@end







|
>
>
>
>



|







|



|




<
|
>

|


>


<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<

<
<
|
<
<
|
<
<
|
|
<
<
|
<
<
|
<
<
|
<
<
|
<
<
>

<
|
|
|
|
|
<
|
|
|
|
|
<
|
|
<
|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<

|
|
|
>
|
|
|
>
>
>
>
|
>
>
>
|
|
|
>
|
|
|
|
|
>
|
|
|
|
|
|
|
|
|
|
<
<
|
<
|
<
<
|
<
|
<
<
|
<
|
<
<
|
<
|
<
<
|
|
<
<
|
|
<
<
|
|



<
|


>
>
>
>
>


|






|



|



>
|
|

>
|
|


>
|
|


>
|










|



>
|

>
|



|

>
>
|


<
>


11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42

43
44
45
46
47
48
49
50
51






























52


53


54


55
56


57


58


59


60


61
62

63
64
65
66
67

68
69
70
71
72

73
74

75






















76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111


112

113


114

115


116

117


118

119


120
121


122
123


124
125
126
127
128

129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198

199
200
201
 * 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 OFSystemInfoTests: OTTestCase
@end

#ifdef OF_HAVE_SOCKETS
static void
appendAddresses(OFMutableString *string, OFData *addresses, bool *firstAddress)
{
	size_t count = addresses.count;

	for (size_t i = 0; i < count; i++) {
		const OFSocketAddress *address = [addresses itemAtIndex: i];

		if (!*firstAddress)
			[string appendString: @", "];

		*firstAddress = false;

		[string appendString: OFSocketAddressString(address)];
	}
}
#endif


@implementation OFSystemInfoTests
+ (OFArray OF_GENERIC(OFPair OF_GENERIC(OFString *, id) *) *)summary
{
	OFMutableArray *summary = [OFMutableArray array];
#ifdef OF_HAVE_SOCKETS
	OFDictionary *networkInterfaces;
	OFMutableString *networkInterfacesString;
	bool firstInterface = true;
#endif

































#define ADD(name, value)						\


	[summary addObject: [OFPair pairWithFirstObject: name		\


					   secondObject: value]];
#define ADD_UINT(name, value)						\


	ADD(name, [OFNumber numberWithUnsignedInt: value]);


#define ADD_ULONGLONG(name, value)					\


	ADD(name, [OFNumber numberWithUnsignedLongLong: value]);


#define ADD_BOOL(name, value)						\


	ADD(name, [OFNumber numberWithBool: value]);


	ADD(@"ObjFW version", [OFSystemInfo ObjFWVersion])
	ADD_UINT(@"ObjFW version major", [OFSystemInfo ObjFWVersionMajor])
	ADD_UINT(@"ObjFW version minor", [OFSystemInfo ObjFWVersionMinor])
	ADD(@"Operating system name", [OFSystemInfo operatingSystemName]);
	ADD(@"Operating system version", [OFSystemInfo operatingSystemVersion]);

	ADD_ULONGLONG(@"Page size", [OFSystemInfo pageSize]);
	ADD_ULONGLONG(@"Number of CPUs", [OFSystemInfo numberOfCPUs]);
	ADD(@"User config IRI", [OFSystemInfo userConfigIRI].string);
	ADD(@"User data IRI", [OFSystemInfo userDataIRI].string);
	ADD(@"Temporary directory IRI",

	    [OFSystemInfo temporaryDirectoryIRI].string);
	ADD(@"CPU vendor", [OFSystemInfo CPUVendor]);

	ADD(@"CPU model", [OFSystemInfo CPUModel]);























#if defined(OF_AMD64) || defined(OF_X86)
	ADD_BOOL(@"Supports MMX", [OFSystemInfo supportsMMX]);
	ADD_BOOL(@"Supports 3DNow!", [OFSystemInfo supports3DNow]);
	ADD_BOOL(@"Supports enhanced 3DNow!",
	    [OFSystemInfo supportsEnhanced3DNow]);
	ADD_BOOL(@"Supports SSE", [OFSystemInfo supportsSSE]);
	ADD_BOOL(@"Supports SSE2", [OFSystemInfo supportsSSE2]);
	ADD_BOOL(@"Supports SSE3", [OFSystemInfo supportsSSE3]);
	ADD_BOOL(@"Supports SSSE3", [OFSystemInfo supportsSSSE3]);
	ADD_BOOL(@"Supports SSE4.1", [OFSystemInfo supportsSSE41]);
	ADD_BOOL(@"Supports SSE4.2", [OFSystemInfo supportsSSE42]);
	ADD_BOOL(@"Supports AVX", [OFSystemInfo supportsAVX]);
	ADD_BOOL(@"Supports AVX2", [OFSystemInfo supportsAVX2]);
	ADD_BOOL(@"Supports AES-NI", [OFSystemInfo supportsAESNI]);
	ADD_BOOL(@"Supports SHA extensions",
	    [OFSystemInfo supportsSHAExtensions]);
	ADD_BOOL(@"Supports fused multiply-add",
	    [OFSystemInfo supportsFusedMultiplyAdd]);
	ADD_BOOL(@"Supports F16C", [OFSystemInfo supportsF16C]);
	ADD_BOOL(@"Supports AVX-512 Foundation",
	    [OFSystemInfo supportsAVX512Foundation]);
	ADD_BOOL(@"Supports AVX-512 Conflict Detection Instructions",
	    [OFSystemInfo supportsAVX512ConflictDetectionInstructions]);
	ADD_BOOL(@"Supports AVX-512 Exponential and Reciprocal Instructions",
	    [OFSystemInfo supportsAVX512ExponentialAndReciprocalInstructions]);
	ADD_BOOL(@"Supports AVX-512 Prefetch Instructions",
	    [OFSystemInfo supportsAVX512PrefetchInstructions]);
	ADD_BOOL(@"Supports AVX-512 Vector Length Extensions",
	    [OFSystemInfo supportsAVX512VectorLengthExtensions]);
	ADD_BOOL(@"Supports AVX-512 Doubleword and Quadword Instructions",
	    [OFSystemInfo supportsAVX512DoublewordAndQuadwordInstructions]);
	ADD_BOOL(@"Supports AVX-512 Byte and Word Instructions",
	    [OFSystemInfo supportsAVX512ByteAndWordInstructions]);
	ADD_BOOL(@"Supports AVX-512 Integer Fused Multiply Add",
	    [OFSystemInfo supportsAVX512IntegerFusedMultiplyAdd]);


	ADD_BOOL(@"Supports AVX-512 Vector Byte Manipulation Instructions",

	    [OFSystemInfo supportsAVX512VectorByteManipulationInstructions]);


	ADD_BOOL(@"Supports AVX-512 Vector Population Count Instruction",

	    [OFSystemInfo supportsAVX512VectorPopulationCountInstruction]);


	ADD_BOOL(@"Supports AVX-512 Vector Neutral Network Instructions",

	    [OFSystemInfo supportsAVX512VectorNeuralNetworkInstructions]);


	ADD_BOOL(@"Supports AVX-512 Vector Byte Manipulation Instructions 2",

	    [OFSystemInfo supportsAVX512VectorByteManipulationInstructions2]);


	ADD_BOOL(@"Supports AVX-512 Bit Algorithms",
	    [OFSystemInfo supportsAVX512BitAlgorithms]);


	ADD_BOOL(@"Supports AVX-512 Float16 Instructions",
	    [OFSystemInfo supportsAVX512Float16Instructions]);


	ADD_BOOL(@"Supports AVX-512 BFloat16 Instructions",
	    [OFSystemInfo supportsAVX512BFloat16Instructions]);
#endif

#ifdef OF_POWERPC

	ADD_BOOL(@"Supports AltiVec", [OFSystemInfo supportsAltiVec]);
#endif

#undef ADD
#undef ADD_UINT
#undef ADD_ULONGLONG
#undef ADD_BOOL

#ifdef OF_HAVE_SOCKETS
	networkInterfaces = [OFSystemInfo networkInterfaces];
	networkInterfacesString = [OFMutableString string];
	for (OFString *name in networkInterfaces) {
		bool firstAddress = true;
		OFNetworkInterface interface;
		OFData *hardwareAddress;

		if (!firstInterface)
			[networkInterfacesString appendString: @"; "];

		firstInterface = false;

		[networkInterfacesString appendFormat: @"%@(", name];

		interface = [networkInterfaces objectForKey: name];

		appendAddresses(networkInterfacesString,
		    [interface objectForKey: OFNetworkInterfaceIPv4Addresses],
		    &firstAddress);
# ifdef OF_HAVE_IPV6
		appendAddresses(networkInterfacesString,
		    [interface objectForKey: OFNetworkInterfaceIPv6Addresses],
		    &firstAddress);
# endif
# ifdef OF_HAVE_IPX
		appendAddresses(networkInterfacesString,
		    [interface objectForKey: OFNetworkInterfaceIPXAddresses],
		    &firstAddress);
# endif
# ifdef OF_HAVE_APPLETALK
		appendAddresses(networkInterfacesString,
		    [interface objectForKey:
		    OFNetworkInterfaceAppleTalkAddresses], &firstAddress);
# endif

		hardwareAddress = [interface
		    objectForKey: OFNetworkInterfaceHardwareAddress];
		if (hardwareAddress != nil) {
			const unsigned char *bytes = hardwareAddress.items;
			size_t length = hardwareAddress.count;

			if (!firstAddress)
				[networkInterfacesString appendString: @", "];

			for (size_t i = 0; i < length; i++) {
				if (i > 0)
					[networkInterfacesString
					    appendString: @":"];

				[networkInterfacesString
				    appendFormat: @"%02X", bytes[i]];
			}
		}

		[networkInterfacesString appendString: @")"];
	}
	[summary addObject:
	    [OFPair pairWithFirstObject: @"Network interfaces"
			   secondObject: networkInterfacesString]];
#endif


	return summary;
}
@end

Modified tests/OFTCPSocketTests.m from [4cfbc85ac3] to [5aca96f5ad].

13
14
15
16
17
18
19
20

21
22

23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
 * file.
 */

#include "config.h"

#include <string.h>

#import "TestsAppDelegate.h"


static OFString *const module = @"OFTCPSocket";


@implementation TestsAppDelegate (OFTCPSocketTests)
- (void)TCPSocketTests
{
	void *pool = objc_autoreleasePoolPush();
	OFTCPSocket *server, *client = nil, *accepted;
	OFSocketAddress address;
	char buffer[6];

	TEST(@"+[socket]", (server = [OFTCPSocket socket]) &&
	    (client = [OFTCPSocket socket]))

	TEST(@"-[bindToHost:port:]",
	    R(address = [server bindToHost: @"127.0.0.1" port: 0]))

	TEST(@"-[listen]", R([server listen]))

	TEST(@"-[connectToHost:port:]",
	    R([client connectToHost: @"127.0.0.1"
			       port: OFSocketAddressIPPort(&address)]))

	TEST(@"-[accept]", (accepted = [server accept]))

	TEST(@"-[remoteAddress]",
	    [OFSocketAddressString(accepted.remoteAddress)
	    isEqual: @"127.0.0.1"])

	TEST(@"-[writeString:]", R([client writeString: @"Hello!"]))

	TEST(@"-[readIntoBuffer:length:]",
	    [accepted readIntoBuffer: buffer length: 6] &&
	    !memcmp(buffer, "Hello!", 6))

	objc_autoreleasePoolPop(pool);
}
@end







|
>

|
>

|
|

<
|



|
|

<
|
<
|

<
|
|

|
<
<
|
|

|

<
|
|
<
<


13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

29
30
31
32
33
34
35

36

37
38

39
40
41
42


43
44
45
46
47

48
49


50
51
 * file.
 */

#include "config.h"

#include <string.h>

#import "ObjFW.h"
#import "ObjFWTest.h"

@interface OFTCPSocketTests: OTTestCase
@end

@implementation OFTCPSocketTests
- (void)testTCPSocket
{

	OFTCPSocket *server, *client, *accepted;
	OFSocketAddress address;
	char buffer[6];

	server = [OFTCPSocket socket];
	client = [OFTCPSocket socket];


	address = [server bindToHost: @"127.0.0.1" port: 0];

	[server listen];


	[client connectToHost: @"127.0.0.1"
			 port: OFSocketAddressIPPort(&address)];

	accepted = [server accept];


	OTAssertEqualObjects(OFSocketAddressString(accepted.remoteAddress),
	    @"127.0.0.1");

	[client writeString: @"Hello!"];


	[accepted readIntoBuffer: buffer exactLength: 6];
	OTAssertEqual(memcmp(buffer, "Hello!", 6), 0);


}
@end

Added tests/OFThreadTests.m version [b2b1434e44].

































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
/*
 * Copyright (c) 2008-2024 Jonathan Schleifer <js@nil.im>
 *
 * 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

Modified tests/OFUDPSocketTests.m from [9c08c02308] to [b806dc5c9a].

13
14
15
16
17
18
19
20

21
22

23
24
25
26
27
28
29
30
31
32
33
34
35

36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
 * file.
 */

#include "config.h"

#include <string.h>

#import "TestsAppDelegate.h"


static OFString *const module = @"OFUDPSocket";


@implementation TestsAppDelegate (OFUDPSocketTests)
- (void)UDPSocketTests
{
	void *pool = objc_autoreleasePoolPush();
	OFUDPSocket *sock;
	OFSocketAddress addr1, addr2, addr3;
	char buf[6];

	TEST(@"+[socket]", (sock = [OFUDPSocket socket]))

	TEST(@"-[bindToHost:port:]",
	    R(addr1 = [sock bindToHost: @"127.0.0.1" port: 0]))


	TEST(@"-[sendBuffer:length:receiver:]",
	    R([sock sendBuffer: "Hello" length: 6 receiver: &addr1]))

	TEST(@"-[receiveIntoBuffer:length:sender:]",
	    [sock receiveIntoBuffer: buf length: 6 sender: &addr2] == 6 &&
	    !memcmp(buf, "Hello", 6) &&
	    [OFSocketAddressString(&addr2) isEqual: @"127.0.0.1"] &&
	    OFSocketAddressIPPort(&addr2) == OFSocketAddressIPPort(&addr1))

	addr3 = OFSocketAddressParseIP(@"127.0.0.1",
	    OFSocketAddressIPPort(&addr1) + 1);

	TEST(@"OFSocketAddressEqual()",
	    OFSocketAddressEqual(&addr1, &addr2) &&
	    !OFSocketAddressEqual(&addr1, &addr3))

	TEST(@"OFSocketAddressHash()",
	    OFSocketAddressHash(&addr1) == OFSocketAddressHash(&addr2) &&
	    OFSocketAddressHash(&addr1) != OFSocketAddressHash(&addr3))

	objc_autoreleasePoolPop(pool);
}
@end







|
>

|
>

|
|

<
|
|
|

|

<
|
>

<
|

<
|
|
|
|
<
<
|
<
<
<
<
<
<
<
<
<
<


13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

29
30
31
32
33
34

35
36
37

38
39

40
41
42
43


44










45
46
 * file.
 */

#include "config.h"

#include <string.h>

#import "ObjFW.h"
#import "ObjFWTest.h"

@interface OFUDPSocketTests: OTTestCase
@end

@implementation OFUDPSocketTests
- (void)testUDPSocket
{

	OFUDPSocket *sock = [OFUDPSocket socket];
	OFSocketAddress addr1, addr2;
	char buffer[6];

	sock = [OFUDPSocket socket];


	addr1 = [sock bindToHost: @"127.0.0.1" port: 0];
	OTAssertEqualObjects(OFSocketAddressString(&addr1), @"127.0.0.1");


	[sock sendBuffer: "Hello" length: 6 receiver: &addr1];


	[sock receiveIntoBuffer: buffer length: 6 sender: &addr2];
	OTAssertEqual(memcmp(buffer, "Hello", 6), 0);
	OTAssertEqualObjects(OFSocketAddressString(&addr2), @"127.0.0.1");
	OTAssertEqual(OFSocketAddressIPPort(&addr2),


	    OFSocketAddressIPPort(&addr1));










}
@end

Modified tests/OFUNIXDatagramSocketTests.m from [588aa866e4] to [cd285c23b4].

12
13
14
15
16
17
18

19
20

21
22

23
24
25
26
27

28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
 * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
 * file.
 */

#include "config.h"

#include <errno.h>


#import "TestsAppDelegate.h"


static OFString *const module = @"OFUNIXDatagramSocket";


@implementation TestsAppDelegate (OFUNIXDatagramSocketTests)
- (void)UNIXDatagramSocketTests
{
	void *pool = objc_autoreleasePoolPush();

	OFString *path;
	OFUNIXDatagramSocket *sock;
	OFSocketAddress address1, address2;
	char buffer[5];

#if defined(OF_HAVE_FILES) && !defined(OF_IOS)
	path = [[OFSystemInfo temporaryDirectoryIRI]
	    IRIByAppendingPathComponent: [[OFUUID UUID] UUIDString]]
	    .fileSystemRepresentation;
#else
	/*
	 * We can have sockets, including UNIX sockets, while file support is
	 * disabled.
	 *
	 * We also use this code path for iOS, as the temporaryDirectoryIRI is
	 * too long on the iOS simulator.
	 */
	path = [OFString stringWithFormat: @"/tmp/%@",
					   [[OFUUID UUID] UUIDString]];
#endif

	TEST(@"+[socket]", (sock = [OFUNIXDatagramSocket socket]))

	@try {
		TEST(@"-[bindToPath:]", R(address1 = [sock bindToPath: path]))
	} @catch (OFBindSocketFailedException *e) {
		switch (e.errNo) {
		case EAFNOSUPPORT:
		case EPERM:
			[OFStdOut setForegroundColor: [OFColor lime]];
			[OFStdOut writeLine:
			    @"\r[OFUNIXDatagramSocket] -[bindToPath:]: "
			    @"UNIX datagram sockets unsupported, skipping "
			    @"tests"];

			objc_autoreleasePoolPop(pool);
			return;
		default:
			@throw e;
		}
	}

	@try {
		TEST(@"-[sendBuffer:length:receiver:]",
		    R([sock sendBuffer: "Hello" length: 5 receiver: &address1]))

		TEST(@"-[receiveIntoBuffer:length:sender:]",
		    [sock receiveIntoBuffer: buffer
				     length: 5
				     sender: &address2] == 5 &&
		    memcmp(buffer, "Hello", 5) == 0 &&
		    OFSocketAddressEqual(&address1, &address2) &&
		    OFSocketAddressHash(&address1) ==
		    OFSocketAddressHash(&address2))
	} @finally {
#ifdef OF_HAVE_FILES
		[[OFFileManager defaultManager] removeItemAtPath: path];
#endif
	}

	objc_autoreleasePoolPop(pool);
}
@end







>

|
>

|
>

|
|

<
>

<



















<
<

|




<
<
<
|
<
<
<
<






<
|

<
|
|
|
|
|
|
|





|
<
<

12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

30
31

32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50


51
52
53
54
55
56



57




58
59
60
61
62
63

64
65

66
67
68
69
70
71
72
73
74
75
76
77
78


79
 * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
 * file.
 */

#include "config.h"

#include <errno.h>
#include <string.h>

#import "ObjFW.h"
#import "ObjFWTest.h"

@interface OFUNIXDatagramSocketTests: OTTestCase
@end

@implementation OFUNIXDatagramSocketTests
- (void)testUNIXDatagramSocket
{

	OFUNIXDatagramSocket *sock = [OFUNIXDatagramSocket socket];
	OFString *path;

	OFSocketAddress address1, address2;
	char buffer[5];

#if defined(OF_HAVE_FILES) && !defined(OF_IOS)
	path = [[OFSystemInfo temporaryDirectoryIRI]
	    IRIByAppendingPathComponent: [[OFUUID UUID] UUIDString]]
	    .fileSystemRepresentation;
#else
	/*
	 * We can have sockets, including UNIX sockets, while file support is
	 * disabled.
	 *
	 * We also use this code path for iOS, as the temporaryDirectoryIRI is
	 * too long on the iOS simulator.
	 */
	path = [OFString stringWithFormat: @"/tmp/%@",
					   [[OFUUID UUID] UUIDString]];
#endif



	@try {
		address1 = [sock bindToPath: path];
	} @catch (OFBindSocketFailedException *e) {
		switch (e.errNo) {
		case EAFNOSUPPORT:
		case EPERM:



			OTSkip(@"UNIX datagram sockets unsupported");




		default:
			@throw e;
		}
	}

	@try {

		[sock sendBuffer: "Hello" length: 5 receiver: &address1];


		OTAssertEqual([sock receiveIntoBuffer: buffer
					       length: 5
					       sender: &address2], 5);
		OTAssertEqual(memcmp(buffer, "Hello", 5), 0);
		OTAssertTrue(OFSocketAddressEqual(&address1, &address2));
		OTAssertEqual(OFSocketAddressHash(&address1),
		    OFSocketAddressHash(&address2));
	} @finally {
#ifdef OF_HAVE_FILES
		[[OFFileManager defaultManager] removeItemAtPath: path];
#endif
	}
}


@end

Modified tests/OFUNIXStreamSocketTests.m from [b3f4ed0fcd] to [404c597141].

12
13
14
15
16
17
18

19
20

21
22

23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
 * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
 * file.
 */

#include "config.h"

#include <errno.h>


#import "TestsAppDelegate.h"


static OFString *const module = @"OFUNIXStreamSocket";


@implementation TestsAppDelegate (OFUNIXStreamSocketTests)
- (void)UNIXStreamSocketTests
{
	void *pool = objc_autoreleasePoolPush();
	OFString *path;
	OFUNIXStreamSocket *sockClient, *sockServer, *sockAccepted;
	char buffer[5];

#if defined(OF_HAVE_FILES) && !defined(OF_IOS)
	path = [[OFSystemInfo temporaryDirectoryIRI]
	    IRIByAppendingPathComponent: [[OFUUID UUID] UUIDString]]
	    .fileSystemRepresentation;
#else
	/*
	 * We can have sockets, including UNIX sockets, while file support is
	 * disabled.
	 *
	 * We also use this code path for iOS, as the temporaryDirectory:RI is
	 * too long on the iOS simulator.
	 */
	path = [OFString stringWithFormat: @"/tmp/%@",
					   [[OFUUID UUID] UUIDString]];
#endif

	TEST(@"+[socket]", (sockClient = [OFUNIXStreamSocket socket]) &&
	    (sockServer = [OFUNIXStreamSocket socket]))

	@try {
		TEST(@"-[bindToPath:]", R([sockServer bindToPath: path]))
	} @catch (OFBindSocketFailedException *e) {
		switch (e.errNo) {
		case EAFNOSUPPORT:
		case EPERM:
			[OFStdOut setForegroundColor: [OFColor lime]];
			[OFStdOut writeLine:
			    @"\r[OFUNIXStreamSocket] -[bindToPath:]: "
			    @"UNIX stream sockets unsupported, skipping tests"];

			objc_autoreleasePoolPop(pool);
			return;
		default:
			@throw e;
		}
	}

	@try {
		TEST(@"-[listen]", R([sockServer listen]))

		TEST(@"-[connectToPath:]",
		    R([sockClient connectToPath: path]))

		TEST(@"-[accept]", (sockAccepted = [sockServer accept]))

		TEST(@"-[writeBuffer:length:]",
		    R([sockAccepted writeBuffer: "Hello" length: 5]))

		TEST(@"-[readIntoBuffer:length:]",
		    [sockClient readIntoBuffer: buffer length: 5] == 5 &&
		    memcmp(buffer, "Hello", 5) == 0)

		TEST(@"-[remoteAddress]", OFSocketAddressUNIXPath(
		    sockAccepted.remoteAddress).length == 0)
	} @finally {
#ifdef OF_HAVE_FILES
		[[OFFileManager defaultManager] removeItemAtPath: path];
#endif
	}

	objc_autoreleasePoolPop(pool);
}
@end







>

|
>

|
>

|
|

<




















|
|


|




<
<
<
|
<
<
<






|

<
|

|
<
<
|

<
|
|

|
|





|
<
<

12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58



59



60
61
62
63
64
65
66
67

68
69
70


71
72

73
74
75
76
77
78
79
80
81
82
83


84
 * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
 * file.
 */

#include "config.h"

#include <errno.h>
#include <string.h>

#import "ObjFW.h"
#import "ObjFWTest.h"

@interface OFUNIXStreamSocketTests: OTTestCase
@end

@implementation OFUNIXStreamSocketTests
- (void)testUNIXStreamSocket
{

	OFString *path;
	OFUNIXStreamSocket *sockClient, *sockServer, *sockAccepted;
	char buffer[5];

#if defined(OF_HAVE_FILES) && !defined(OF_IOS)
	path = [[OFSystemInfo temporaryDirectoryIRI]
	    IRIByAppendingPathComponent: [[OFUUID UUID] UUIDString]]
	    .fileSystemRepresentation;
#else
	/*
	 * We can have sockets, including UNIX sockets, while file support is
	 * disabled.
	 *
	 * We also use this code path for iOS, as the temporaryDirectory:RI is
	 * too long on the iOS simulator.
	 */
	path = [OFString stringWithFormat: @"/tmp/%@",
					   [[OFUUID UUID] UUIDString]];
#endif

	sockClient = [OFUNIXStreamSocket socket];
	sockServer = [OFUNIXStreamSocket socket];

	@try {
		[sockServer bindToPath: path];
	} @catch (OFBindSocketFailedException *e) {
		switch (e.errNo) {
		case EAFNOSUPPORT:
		case EPERM:



			OTSkip(@"UNIX stream sockets unsupported");



		default:
			@throw e;
		}
	}

	@try {
		[sockServer listen];


		[sockClient connectToPath: path];

		sockAccepted = [sockServer accept];


		[sockAccepted writeBuffer: "Hello" length: 5];


		OTAssertEqual([sockClient readIntoBuffer: buffer length: 5], 5);
		OTAssertEqual(memcmp(buffer, "Hello", 5), 0);

		OTAssertEqual(OFSocketAddressUNIXPath(
		    sockAccepted.remoteAddress).length, 0);
	} @finally {
#ifdef OF_HAVE_FILES
		[[OFFileManager defaultManager] removeItemAtPath: path];
#endif
	}
}


@end

Added tests/OFUTF8StringTests.m version [29756ee219].





























































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
/*
 * Copyright (c) 2008-2024 Jonathan Schleifer <js@nil.im>
 *
 * 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 "OFStringTests.h"

#import "OFUTF8String.h"

@interface OFUTF8StringTests: OFStringTests
@end

@implementation OFUTF8StringTests
- (Class)arrayClass
{
	return [OFUTF8String class];
}
@end

Modified tests/OFValueTests.m from [52b7d9b170] to [200d6d2788].

13
14
15
16
17
18
19
20

21
22

23
24
25
26



27





28


29



30


31
32









33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55

56
57
58
59
60

61

62


63
64
65
66
67
68
69
70
71
72
73

74
75



76
77
78
79

80
81
82
83
84
85
86
87
88
89

90

91
92

93
94



95
96
97
98

99
100
101
102
103
104
105
106
107
108

109

110
111

112
113



114
115
116
117

118
119
120
121
122
123
124
125
126
127
128
129
130

131
132



133
134
135
136

137
138
139
140
141
142
143
144
145
146

147

148

149

150
151
152
153

154
155
156

157
158
159
160
161
162
 * file.
 */

#include "config.h"

#include <string.h>

#import "TestsAppDelegate.h"


static OFString *const module = @"OFValue";


@implementation TestsAppDelegate (OFValueTests)
- (void)valueTests
{



	void *pool = objc_autoreleasePoolPush();





	OFRange range = OFMakeRange(1, 64), range2;


	OFPoint point = OFMakePoint(1.5f, 3.0f), point2;



	OFSize size = OFMakeSize(4.5f, 5.0f), size2;


	OFRect rect = OFMakeRect(1.5f, 3.0f, 4.5f, 6.0f), rect2;
	OFValue *value;









	void *pointer = &value;

	TEST(@"+[valueWithBytes:objCType:]",
	    (value = [OFValue valueWithBytes: &range
				    objCType: @encode(OFRange)]))

	TEST(@"-[objCType]", strcmp(value.objCType, @encode(OFRange)) == 0)

	TEST(@"-[getValue:size:]",
	    R([value getValue: &range2 size: sizeof(OFRange)]) &&
	    OFEqualRanges(range2, range))

	EXPECT_EXCEPTION(@"-[getValue:size:] with wrong size throws",
	    OFOutOfRangeException,
	    [value getValue: &range size: sizeof(OFRange) - 1])

	TEST(@"+[valueWithPointer:]",
	    (value = [OFValue valueWithPointer: pointer]))

	TEST(@"-[pointerValue]",
	    value.pointerValue == pointer &&
	    [[OFValue valueWithBytes: &pointer
			    objCType: @encode(void *)] pointerValue] == pointer)


	EXPECT_EXCEPTION(@"-[pointerValue] with wrong size throws",
	    OFOutOfRangeException,
	    [[OFValue valueWithBytes: "a"
			    objCType: @encode(char)] pointerValue])



	TEST(@"+[valueWithNonretainedObject:]",


	    (value = [OFValue valueWithNonretainedObject: pointer]))

	TEST(@"-[nonretainedObjectValue]",
	    value.nonretainedObjectValue == pointer &&
	    [[OFValue valueWithBytes: &pointer
			    objCType: @encode(id)] pointerValue] == pointer)

	EXPECT_EXCEPTION(@"-[nonretainedObjectValue] with wrong size throws",
	    OFOutOfRangeException,
	    [[OFValue valueWithBytes: "a"
			    objCType: @encode(char)] nonretainedObjectValue])


	TEST(@"+[valueWithRange:]",



	    (value = [OFValue valueWithRange: range]))

	TEST(@"-[rangeValue]",
	    OFEqualRanges(value.rangeValue, range) &&

	    (value = [OFValue valueWithBytes: &range
				    objCType: @encode(OFRange)]) &&
	    OFEqualRanges(value.rangeValue, range))

	TEST(@"-[getValue:size:] for OFRangeValue",
	    (value = [OFValue valueWithRange: range]) &&
	    R([value getValue: &range2 size: sizeof(range2)]) &&
	    OFEqualRanges(range2, range))

	EXPECT_EXCEPTION(@"-[rangeValue] with wrong size throws",

	    OFOutOfRangeException,

	    [[OFValue valueWithBytes: "a"
			    objCType: @encode(char)] rangeValue])


	TEST(@"+[valueWithPoint:]",



	    (value = [OFValue valueWithPoint: point]))

	TEST(@"-[pointValue]",
	    OFEqualPoints(value.pointValue, point) &&

	    (value = [OFValue valueWithBytes: &point
				    objCType: @encode(OFPoint)]) &&
	    OFEqualPoints(value.pointValue, point))

	TEST(@"-[getValue:size:] for OFPointValue",
	    (value = [OFValue valueWithPoint: point]) &&
	    R([value getValue: &point2 size: sizeof(point2)]) &&
	    OFEqualPoints(point2, point))

	EXPECT_EXCEPTION(@"-[pointValue] with wrong size throws",

	    OFOutOfRangeException,

	    [[OFValue valueWithBytes: "a"
			    objCType: @encode(char)] pointValue])


	TEST(@"+[valueWithSize:]",



	    (value = [OFValue valueWithSize: size]))

	TEST(@"-[sizeValue]",
	    OFEqualSizes(value.sizeValue, size) &&

	    (value = [OFValue valueWithBytes: &size
				    objCType: @encode(OFSize)]) &&
	    OFEqualSizes(value.sizeValue, size))

	TEST(@"-[getValue:size:] for OFSizeValue",
	    (value = [OFValue valueWithSize: size]) &&
	    R([value getValue: &size2 size: sizeof(size2)]) &&
	    OFEqualSizes(size2, size))

	EXPECT_EXCEPTION(@"-[sizeValue] with wrong size throws",
	    OFOutOfRangeException,
	    [[OFValue valueWithBytes: "a"
			    objCType: @encode(char)] sizeValue])


	TEST(@"+[valueWithRect:]",



	    (value = [OFValue valueWithRect: rect]))

	TEST(@"-[rectValue]",
	    OFEqualRects(value.rectValue, rect) &&

	    (value = [OFValue valueWithBytes: &rect
				    objCType: @encode(OFRect)]) &&
	    OFEqualRects(value.rectValue, rect))

	TEST(@"-[getValue:size:] for OFRectValue",
	    (value = [OFValue valueWithRect: rect]) &&
	    R([value getValue: &rect2 size: sizeof(rect2)]) &&
	    OFEqualRects(rect2, rect))

	EXPECT_EXCEPTION(@"-[rectValue] with wrong size throws",

	    OFOutOfRangeException,

	    [[OFValue valueWithBytes: "a" objCType: @encode(char)] rectValue])



	TEST(@"-[isEqual:]",
	    [[OFValue valueWithRect: rect]
	    isEqual: [OFValue valueWithBytes: &rect
				    objCType: @encode(OFRect)]] &&

	    ![[OFValue valueWithBytes: "a" objCType: @encode(signed char)]
	    isEqual: [OFValue valueWithBytes: "a"
				    objCType: @encode(unsigned char)]] &&

	    ![[OFValue valueWithBytes: "a" objCType: @encode(char)]
	    isEqual: [OFValue valueWithBytes: "b" objCType: @encode(char)]])

	objc_autoreleasePoolPop(pool);
}
@end







|
>

|
>

|
|

>
>
>
|
>
>
>
>
>

>
>
|
>
>
>
|
>
>
|
|
>
>
>
>
>
>
>
>
>
|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
|

<
|
|
|
>

|
<

|
>
|
>
|
>
>
|

|
|
|
|

|
<

|
>
|
|
>
>
>
|

<
|
>
|
|
<
<
<
<
<
<

|
>
|
>

|
>
|
|
>
>
>
|

<
|
>
|
|
<
<
<
<
<
<

|
>
|
>

|
>
|
|
>
>
>
|

<
|
>
|
|
<

<
<
|
|

|
<

|
>
|
|
>
>
>
|

<
|
>
|
|
<

<
<
|
|

|
>
|
>
|
>
|
>
|
|
|
|
>
|
<
|
>
|
|
<
<


13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
















60
61

62
63
64
65
66
67

68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83

84
85
86
87
88
89
90
91
92
93

94
95
96
97






98
99
100
101
102
103
104
105
106
107
108
109
110
111
112

113
114
115
116






117
118
119
120
121
122
123
124
125
126
127
128
129
130
131

132
133
134
135

136


137
138
139
140

141
142
143
144
145
146
147
148
149
150

151
152
153
154

155


156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172

173
174
175
176


177
178
 * file.
 */

#include "config.h"

#include <string.h>

#import "ObjFW.h"
#import "ObjFWTest.h"

@interface OFValueTests: OTTestCase
@end

@implementation OFValueTests
- (void)testObjCType
{
	OFRange range = OFMakeRange(1, 64);
	OFValue *value = [OFValue valueWithBytes: &range
					objCType: @encode(OFRange)];

	OTAssertEqual(strcmp(value.objCType, @encode(OFRange)), 0);
}

- (void)testGetValueSize
{
	OFRange range = OFMakeRange(1, 64), range2;
	OFValue *value = [OFValue valueWithBytes: &range
					objCType: @encode(OFRange)];

	[value getValue: &range2 size: sizeof(OFRange)];
	OTAssert(OFEqualRanges(range2, range));
}

- (void)testGetValueSizeThrowsOnWrongSize
{
	OFRange range = OFMakeRange(1, 64);
	OFValue *value = [OFValue valueWithBytes: &range
					objCType: @encode(OFRange)];

	OTAssertThrowsSpecific(
	    [value getValue: &range size: sizeof(OFRange) - 1],
	    OFOutOfRangeException);
}

- (void)testPointer
{
	void *pointer = &pointer;
















	OFValue *value = [OFValue valueWithPointer: pointer];


	OTAssertEqual(value.pointerValue, pointer);
	OTAssertEqual([[OFValue valueWithBytes: &pointer
				      objCType: @encode(void *)] pointerValue],
	    pointer);

	OTAssertThrowsSpecific(

	    [[OFValue valueWithBytes: "a"
			    objCType: @encode(char)] pointerValue],
	    OFOutOfRangeException);
}

- (void)testNonretainedObject
{
	id object = (id)&object;
	OFValue *value = [OFValue valueWithNonretainedObject: object];

	OTAssertEqual(value.nonretainedObjectValue, object);
	OTAssertEqual([[OFValue
	    valueWithBytes: &object
		  objCType: @encode(id)] nonretainedObjectValue], object);

	OTAssertThrowsSpecific(

	    [[OFValue valueWithBytes: "a"
			    objCType: @encode(char)] nonretainedObjectValue],
	    OFOutOfRangeException);
}

- (void)testRange
{
	OFRange range = OFMakeRange(1, 64), range2;
	OFValue *value = [OFValue valueWithRange: range];


	OTAssert(OFEqualRanges(value.rangeValue, range));
	OTAssert(OFEqualRanges(
	    [[OFValue valueWithBytes: &range
			    objCType: @encode(OFRange)] rangeValue], range));







	[value getValue: &range2 size: sizeof(range2)];
	OTAssert(OFEqualRanges(range2, range));

	OTAssertThrowsSpecific(
	    [[OFValue valueWithBytes: "a"
			    objCType: @encode(char)] rangeValue],
	    OFOutOfRangeException);
}

- (void)testPoint
{
	OFPoint point = OFMakePoint(1.5f, 3.0f), point2;
	OFValue *value = [OFValue valueWithPoint: point];


	OTAssert(OFEqualPoints(value.pointValue, point));
	OTAssert(OFEqualPoints(
	    [[OFValue valueWithBytes: &point
			    objCType: @encode(OFPoint)] pointValue], point));







	[value getValue: &point2 size: sizeof(point2)];
	OTAssert(OFEqualPoints(point2, point));

	OTAssertThrowsSpecific(
	    [[OFValue valueWithBytes: "a"
			    objCType: @encode(char)] pointValue],
	    OFOutOfRangeException);
}

- (void)testSize
{
	OFSize size = OFMakeSize(4.5f, 5.0f), size2;
	OFValue *value = [OFValue valueWithSize: size];


	OTAssert(OFEqualSizes(value.sizeValue, size));
	OTAssert(OFEqualSizes(
	    [[OFValue valueWithBytes: &size
			    objCType: @encode(OFSize)] sizeValue], size));




	[value getValue: &size2 size: sizeof(size2)];
	OTAssert(OFEqualSizes(size2, size));

	OTAssertThrowsSpecific(

	    [[OFValue valueWithBytes: "a"
			    objCType: @encode(char)] sizeValue],
	    OFOutOfRangeException);
}

- (void)testRect
{
	OFRect rect = OFMakeRect(1.5f, 3.0f, 4.5f, 6.0f), rect2;
	OFValue *value = [OFValue valueWithRect: rect];


	OTAssert(OFEqualRects(value.rectValue, rect));
	OTAssert(OFEqualRects(
	    [[OFValue valueWithBytes: &rect
			    objCType: @encode(OFRect)] rectValue], rect));




	[value getValue: &rect2 size: sizeof(rect2)];
	OTAssert(OFEqualRects(rect2, rect));

	OTAssertThrowsSpecific(
	    [[OFValue valueWithBytes: "a" objCType: @encode(char)] rectValue],
	    OFOutOfRangeException);
}

- (void)testIsEqual
{
	OFRect rect = OFMakeRect(1.5f, 3.0f, 4.5f, 6.0f);

	OTAssertEqualObjects([OFValue valueWithRect: rect],
	    [OFValue valueWithBytes: &rect
			   objCType: @encode(OFRect)]);
	OTAssertNotEqualObjects(
	    [OFValue valueWithBytes: "a" objCType: @encode(signed char)],

	    [OFValue valueWithBytes: "a" objCType: @encode(unsigned char)]);
	OTAssertNotEqualObjects(
	    [OFValue valueWithBytes: "a" objCType: @encode(char)],
	    [OFValue valueWithBytes: "b" objCType: @encode(char)]);


}
@end

Modified tests/OFWindowsRegistryKeyTests.m from [0f0fbee00b] to [295a442df9].

11
12
13
14
15
16
17
18

19








































20
21




22





23

24





25










26

27








28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56


57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
 * 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 = @"OFWindowsRegistryKey";





@implementation TestsAppDelegate (OFWindowsRegistryKeyTests)





- (void)windowsRegistryKeyTests

{





	void *pool = objc_autoreleasePoolPush();










	OFData *data = [OFData dataWithItems: "abcdef" count: 6];

	OFWindowsRegistryKey *softwareKey, *objFWKey;








	DWORD type;

	TEST(@"+[OFWindowsRegistryKey classesRootKey]",
	    [OFWindowsRegistryKey classesRootKey])

	TEST(@"+[OFWindowsRegistryKey currentConfigKey]",
	    [OFWindowsRegistryKey currentConfigKey])

	TEST(@"+[OFWindowsRegistryKey currentUserKey]",
	    [OFWindowsRegistryKey currentUserKey])

	TEST(@"+[OFWindowsRegistryKey localMachineKey]",
	    [OFWindowsRegistryKey localMachineKey])

	TEST(@"+[OFWindowsRegistryKey usersKey]",
	    [OFWindowsRegistryKey usersKey])

	    TEST(@"-[openSubkeyAtPath:accessRights:options:] #1",
	    (softwareKey = [[OFWindowsRegistryKey currentUserKey]
		openSubkeyAtPath: @"Software"
		    accessRights: KEY_ALL_ACCESS
			 options: 0]))

	EXPECT_EXCEPTION(@"-[openSubkeyAtPath:accessRights:options:] #2",
	    OFOpenWindowsRegistryKeyFailedException,
	    [[OFWindowsRegistryKey currentUserKey]
		openSubkeyAtPath: @"nonexistent"
		    accessRights: KEY_ALL_ACCESS
			 options: 0])



	TEST(@"-[createSubkeyAtPath:accessRights:securityAttributes:options:"
	    @"disposition:]",
	    (objFWKey = [softwareKey createSubkeyAtPath: @"ObjFW"
					   accessRights: KEY_ALL_ACCESS
				     securityAttributes: NULL
						options: 0
					    disposition: NULL]))

	TEST(@"-[setData:forValueNamed:type:]",
	    R([objFWKey setData: data forValueNamed: @"data" type: REG_BINARY]))

	TEST(@"-[dataForValueNamed:subkeyPath:flags:type:]",
	    [[objFWKey dataForValueNamed: @"data" type: &type] isEqual: data] &&
	    type == REG_BINARY)

	TEST(@"-[setString:forValueNamed:type:]",
	    R([objFWKey setString: @"foobar" forValueNamed: @"string"]) &&
	    R([objFWKey setString: @"%PATH%;foo"
		    forValueNamed: @"expand"
			     type: REG_EXPAND_SZ]))

	TEST(@"-[stringForValue:subkeyPath:]",
	    [[objFWKey stringForValueNamed: @"string"] isEqual: @"foobar"] &&
	    [[objFWKey stringForValueNamed: @"expand" type: &type]
	    isEqual: @"%PATH%;foo"] &&
	    type == REG_EXPAND_SZ)

	TEST(@"-[deleteValueNamed:]", R([objFWKey deleteValueNamed: @"data"]))

	TEST(@"-[deleteSubkeyAtPath:]",
	    R([softwareKey deleteSubkeyAtPath: @"ObjFW"]))

	objc_autoreleasePoolPop(pool);
}
@end







|
>

>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
|
>
>
>
>
|
>
>
>
>
>
|
>
|
>
>
>
>
>
|
>
>
>
>
>
>
>
>
>
>

>
|
>
>
>
>
>
>
>
>


<
<
|
<
<
|
<
<
|
<
<

<
<
|
<
<
|
<
|
|
<
<
<
<
<
|
>
>
|
<
<
<
<
<
<
<

<
<
|
<
<
<
|
<
|
<
<
<
<
<
<
|
|
<

|
|
<
<
<
<


11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104


105


106


107


108


109


110

111
112





113
114
115
116







117


118



119

120






121
122

123
124
125




126
127
 * 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 OFWindowsRegistryKeyTests: OTTestCase
{
	OFWindowsRegistryKey *_softwareKey, *_objFWKey;
}
@end

@implementation OFWindowsRegistryKeyTests
- (void)setUp
{
	[super setUp];

	_softwareKey = [[[OFWindowsRegistryKey currentUserKey]
	    openSubkeyAtPath: @"Software"
		accessRights: KEY_ALL_ACCESS
		     options: 0] retain];
	_objFWKey = [[_softwareKey createSubkeyAtPath: @"ObjFW"
					 accessRights: KEY_ALL_ACCESS
				   securityAttributes: NULL
					      options: 0
					  disposition: NULL] retain];
}

- (void)tearDown
{
	[_softwareKey deleteSubkeyAtPath: @"ObjFW"];

	[super tearDown];
}

- (void)dealloc
{
	[_softwareKey release];
	[_objFWKey release];

	[super dealloc];
}

- (void)testClassesRootKey
{
	OTAssertEqual([[OFWindowsRegistryKey classesRootKey] class],
	    [OFWindowsRegistryKey class]);
}

- (void)testCurrentConfigKey
{
	OTAssertEqual([[OFWindowsRegistryKey currentConfigKey] class],
	    [OFWindowsRegistryKey class]);
}

- (void)testCurrentUserKey
{
	OTAssertEqual([[OFWindowsRegistryKey currentUserKey] class],
	    [OFWindowsRegistryKey class]);
}

- (void)testLocalMachineKey
{
	OTAssertEqual([[OFWindowsRegistryKey localMachineKey] class],
	    [OFWindowsRegistryKey class]);
}

- (void)testOpenSubkeyAtPathAccessRightsOptionsThrowsForNonExistentKey
{
	OTAssertThrowsSpecific([[OFWindowsRegistryKey currentUserKey]
	    openSubkeyAtPath: @"nonexistent"
		accessRights: KEY_ALL_ACCESS
		     options: 0], OFOpenWindowsRegistryKeyFailedException);
}

- (void)testSetAndGetData
{
	OFData *data = [OFData dataWithItems: "abcdef" count: 6];
	DWORD type;

	[_objFWKey setData: data forValueNamed: @"data" type: REG_BINARY];
	OTAssertEqualObjects([_objFWKey dataForValueNamed: @"data" type: &type],
	    data);
	OTAssertEqual(type, REG_BINARY);
}

- (void)testSetAndGetString
{
	DWORD type;



	[_objFWKey setString: @"foobar" forValueNamed: @"string"];


	OTAssertEqualObjects([_objFWKey stringForValueNamed: @"string"],


	    @"foobar");





	[_objFWKey setString: @"%PATH%;foo"


	       forValueNamed: @"expand"

			type: REG_EXPAND_SZ];
	OTAssertEqualObjects([_objFWKey stringForValueNamed: @"expand"





						       type: &type],
	    @"%PATH%;foo");
	OTAssertEqual(type, REG_EXPAND_SZ);
}










- (void)testDeleteValue



{

	[_objFWKey setString: @"foobar" forValueNamed: @"deleteme"];






	OTAssertEqualObjects([_objFWKey stringForValueNamed: @"deleteme"],
	    @"foobar");


	[_objFWKey deleteValueNamed: @"deleteme"];
	OTAssertNil([_objFWKey stringForValueNamed: @"deleteme"]);




}
@end

Modified tests/OFXMLElementBuilderTests.m from [94889a4bd5] to [7e8aac9296].

11
12
13
14
15
16
17
18

19
20

21
22
23


24








25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53

54
55
56
57
58
59
60
61
62
 * 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 = @"OFXMLElementBuilder";

static OFXMLNode *nodes[2];
static size_t i = 0;



@implementation TestsAppDelegate (OFXMLElementBuilderTests)








- (void)elementBuilder: (OFXMLElementBuilder *)builder
       didBuildElement: (OFXMLElement *)element
{
	OFEnsure(i == 0);
	nodes[i++] = [element retain];
}

- (void)elementBuilder: (OFXMLElementBuilder *)builder
    didBuildOrphanNode: (OFXMLNode *)node
{
	OFEnsure(i == 1);
	nodes[i++] = [node retain];
}

- (void)XMLElementBuilderTests
{
	void *pool = objc_autoreleasePoolPush();
	OFXMLParser *parser = [OFXMLParser parser];
	OFXMLElementBuilder *builder = [OFXMLElementBuilder builder];
	OFString *string = @"<foo>bar<![CDATA[f<oo]]>baz<qux/>"
	    " <qux xmlns:qux='urn:qux'><?asd?><qux:bar/><x qux:y='z'/></qux>"
	    "</foo>";

	parser.delegate = builder;
	builder.delegate = self;

	TEST(@"Building elements from parsed XML",
	    R([parser parseString: string]) &&
	    nodes[0] != nil && [nodes[0].XMLString isEqual: string] &&

	    R([parser parseString: @"<!--foo-->"]) &&
	    nodes[1] != nil && [nodes[1].XMLString isEqual: @"<!--foo-->"] &&
	    i == 2)

	[nodes[0] release];
	[nodes[1] release];
	objc_autoreleasePoolPop(pool);
}
@end







|
>

|
>
|
|
|
>
>
|
>
>
>
>
>
>
>
>



|
|





|
|


|

<









<
|
|
>
|
|
<

|
<
<


11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52

53
54
55
56
57
58
59
60
61

62
63
64
65
66

67
68


69
70
 * 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 OFXMLElementBuilderTests: OTTestCase <OFXMLElementBuilderDelegate>
{
	OFXMLNode *_nodes[2];
	size_t _i;
}
@end

@implementation OFXMLElementBuilderTests
- (void)dealloc
{
	[_nodes[0] release];
	[_nodes[1] release];

	[super dealloc];
}

- (void)elementBuilder: (OFXMLElementBuilder *)builder
       didBuildElement: (OFXMLElement *)element
{
	OTAssertEqual(_i, 0);
	_nodes[_i++] = [element retain];
}

- (void)elementBuilder: (OFXMLElementBuilder *)builder
    didBuildOrphanNode: (OFXMLNode *)node
{
	OTAssertEqual(_i, 1);
	_nodes[_i++] = [node retain];
}

- (void)testElementBuilder
{

	OFXMLParser *parser = [OFXMLParser parser];
	OFXMLElementBuilder *builder = [OFXMLElementBuilder builder];
	OFString *string = @"<foo>bar<![CDATA[f<oo]]>baz<qux/>"
	    " <qux xmlns:qux='urn:qux'><?asd?><qux:bar/><x qux:y='z'/></qux>"
	    "</foo>";

	parser.delegate = builder;
	builder.delegate = self;


	[parser parseString: string];
	OTAssertEqualObjects(_nodes[0].XMLString, string);

	[parser parseString: @"<!--foo-->"];
	OTAssertEqualObjects(_nodes[1].XMLString, @"<!--foo-->");


	OTAssertEqual(_i, 2);


}
@end

Modified tests/OFXMLNodeTests.m from [806daf51ab] to [eb43bc25ed].

11
12
13
14
15
16
17
18

19
20

21
22
23
24
25
26
27


28
29
30
31
32
33
34
35

36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69


70
71

72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91

92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118






119


















































120

121

122

123



124
























125





126



127











128


129





130


131
132
133
134
135
136
137
 * 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 (OFXMLNodeTests)
- (void)XMLNodeTests
{
	void *pool = objc_autoreleasePoolPush();
	id node1, node2, node3, node4;
	OFArray *array;



	module = @"OFXMLNode";

	TEST(@"+[elementWithName:]",
	    (node1 = [OFXMLElement elementWithName: @"foo"]) &&
	    [[node1 XMLString] isEqual: @"<foo/>"])

	TEST(@"+[elementWithName:stringValue:]",

	    (node2 = [OFXMLElement elementWithName: @"foo"
				       stringValue: @"b&ar"]) &&
	    [[node2 XMLString] isEqual: @"<foo>b&amp;ar</foo>"])

	TEST(@"+[elementWithName:namespace:]",
	    (node3 = [OFXMLElement elementWithName: @"foo"
					 namespace: @"urn:objfw:test"]) &&
	    R([node3 addAttributeWithName: @"test" stringValue: @"test"]) &&
	    R([node3 setPrefix: @"objfw-test"
		  forNamespace: @"urn:objfw:test"]) &&
	    [[node3 XMLString] isEqual: @"<objfw-test:foo test='test'/>"] &&
	    (node4 = [OFXMLElement elementWithName: @"foo"
					 namespace: @"urn:objfw:test"]) &&
	    R([node4 addAttributeWithName: @"test" stringValue: @"test"]) &&
	    [[node4 XMLString] isEqual:
	    @"<foo xmlns='urn:objfw:test' test='test'/>"])

	TEST(@"+[elementWithName:namespace:stringValue:]",
	    (node4 = [OFXMLElement elementWithName: @"foo"
					 namespace: @"urn:objfw:test"
				       stringValue: @"x"]) &&
	    R([node4 setPrefix: @"objfw-test"
		  forNamespace: @"urn:objfw:test"]) &&
	    [[node4 XMLString] isEqual: @"<objfw-test:foo>x</objfw-test:foo>"])

	TEST(@"+[charactersWithString:]",
	    (node4 = [OFXMLCharacters charactersWithString: @"<foo>"]) &&
	    [[node4 XMLString] isEqual: @"&lt;foo&gt;"])

	TEST(@"+[CDATAWithString:]",
	    (node4 = [OFXMLCDATA CDATAWithString: @"<foo>"]) &&
	    [[node4 XMLString] isEqual: @"<![CDATA[<foo>]]>"]);

	TEST(@"+[commentWithText:]",


	    (node4 = [OFXMLComment commentWithText: @" comment "]) &&
	    [[node4 XMLString] isEqual: @"<!-- comment -->"])


	module = @"OFXMLElement";

	TEST(@"-[addAttributeWithName:stringValue:]",
	    R([node1 addAttributeWithName: @"foo" stringValue: @"b&ar"]) &&
	    [[node1 XMLString] isEqual: @"<foo foo='b&amp;ar'/>"] &&
	    R([node2 addAttributeWithName: @"foo" stringValue: @"b&ar"]) &&
	    [[node2 XMLString] isEqual: @"<foo foo='b&amp;ar'>b&amp;ar</foo>"])

	TEST(@"-[setPrefix:forNamespace:]",
	    R([node2 setPrefix: @"objfw-test"
		  forNamespace: @"urn:objfw:test"]))

	TEST(@"-[addAttributeWithName:namespace:stringValue:]",
	    R([node2 addAttributeWithName: @"foo"
				namespace: @"urn:objfw:test"
			      stringValue: @"bar"]) &&
	    R([node2 addAttributeWithName: @"foo"
				namespace: @"urn:objfw:test"
			      stringValue: @"ignored"]) &&

	    [[node2 XMLString] isEqual:
	    @"<foo foo='b&amp;ar' objfw-test:foo='bar'>b&amp;ar</foo>"])

	TEST(@"-[removeAttributeForName:namespace:]",
	    R([node2 removeAttributeForName: @"foo"]) &&
	    [[node2 XMLString] isEqual:
	    @"<foo objfw-test:foo='bar'>b&amp;ar</foo>"] &&
	    R([node2 removeAttributeForName: @"foo"
				  namespace: @"urn:objfw:test"]) &&
	    [[node2 XMLString] isEqual: @"<foo>b&amp;ar</foo>"])

	TEST(@"-[addChild:]",
	    R([node1 addChild: [OFXMLElement elementWithName: @"bar"]]) &&
	    [[node1 XMLString] isEqual:
	    @"<foo foo='b&amp;ar'><bar/></foo>"] &&
	    R([node3 addChild: [OFXMLElement elementWithName: @"bar"
		    namespace: @"urn:objfw:test"]]) &&
	    [[node3 XMLString] isEqual:
	    @"<objfw-test:foo test='test'><objfw-test:bar/></objfw-test:foo>"])

	TEST(@"+[elementWithXMLString:] and -[stringValue]",
	    [[[OFXMLElement elementWithXMLString:
	    @"<?xml version='1.0' encoding='UTF-8'?>\r\n<x>foo<![CDATA[bar]]>"
	    @"<y>b<!-- fooo -->az</y>qux</x>"] stringValue]
	    isEqual: @"foobarbazqux"])

	TEST(@"-[elementsForName:namespace:]",






	    (array = [node3 elementsForName: @"bar"


















































				  namespace: @"urn:objfw:test"]) &&

	    array.count == 1 && [[array.firstObject XMLString] isEqual:

	    @"<bar xmlns='urn:objfw:test'/>"])





	TEST(@"-[isEqual:]",
























	    [[OFXMLElement elementWithXMLString: @"<foo bar='asd'/>"] isEqual:





	    [OFXMLElement elementWithXMLString: @"<foo bar='asd'></foo>"]] &&



	    [[OFXMLElement elementWithXMLString: @"<x><y/></x>"] isEqual:











	    [OFXMLElement elementWithXMLString: @"<x><y></y></x>"]])








	TEST(@"-[XMLStringWithIndentation:]",


	    [[[OFXMLElement elementWithXMLString: @"<x><y><z>a\nb</z>"
	    @"<!-- foo --></y></x>"] XMLStringWithIndentation: 2] isEqual:
	    @"<x>\n  <y>\n    <z>a\nb</z>\n    <!-- foo -->\n  </y>\n</x>"])

	objc_autoreleasePoolPop(pool);
}
@end







|
>

|
>

|
|

<
<
|
>
>
|
<

|
<
<
|
<
>
|
|
|
|
<
<
<
<
<
<
<
<
<
<
<
<

<
|
<
<
<
<
<
|
<
<
<
|
<
<
<

|
>
>
|
|
>

|
|
<
|
|
<
|
|
|
<
|
|
<
|
<
<
<
|
|
>
|
|
|
<
<
<
<
<
<
<

<
<
|
<
<
<
<
<
|
<
|

|
|
|
|
>
>
>
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>
|
>
|
>

>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>
>
>
>
>
|
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
|
>
>

>
>
>
>
>
|
>
>
|
|
|
<
<


11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26


27
28
29
30

31
32


33

34
35
36
37
38












39

40





41



42



43
44
45
46
47
48
49
50
51
52

53
54

55
56
57

58
59

60



61
62
63
64
65
66







67


68





69

70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204


205
206
 * 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 OFXMLNodeTests: OTTestCase
@end

@implementation OFXMLNodeTests
- (void)testElementWithName
{


	OTAssertEqualObjects(
	    [[OFXMLElement elementWithName: @"foo"] XMLString],
	    @"<foo/>");
}


- (void)testElementWithNameStringValue


{

	OTAssertEqualObjects(
	    [[OFXMLElement elementWithName: @"foo"
			       stringValue: @"b&ar"] XMLString],
	    @"<foo>b&amp;ar</foo>");
}














- (void)testElementWithNameNamespace





{



	OFXMLElement *element;




	element = [OFXMLElement elementWithName: @"foo"
				      namespace: @"urn:objfw:test"];
	[element addAttributeWithName: @"test" stringValue: @"test"];
	[element setPrefix: @"objfw-test" forNamespace: @"urn:objfw:test"];
	OTAssertEqualObjects(element.XMLString,
	    @"<objfw-test:foo test='test'/>");

	element = [OFXMLElement elementWithName: @"foo"
				      namespace: @"urn:objfw:test"];

	[element addAttributeWithName: @"test" stringValue: @"test"];
	OTAssertEqualObjects(element.XMLString,

	    @"<foo xmlns='urn:objfw:test' test='test'/>");
}


- (void)testElementWithNameNamespaceStringValue
{

	OFXMLElement *element = [OFXMLElement elementWithName: @"foo"



						    namespace: @"urn:objfw:test"
						  stringValue: @"x"];
	[element setPrefix: @"objfw-test" forNamespace: @"urn:objfw:test"];
	OTAssertEqualObjects(element.XMLString,
	    @"<objfw-test:foo>x</objfw-test:foo>");
}










- (void)testElementWithXMLStringAndStringValue





{

	OTAssertEqualObjects([[OFXMLElement elementWithXMLString:
	    @"<?xml version='1.0' encoding='UTF-8'?>\r\n<x>foo<![CDATA[bar]]>"
	    @"<y>b<!-- fooo -->az</y>qux</x>"] stringValue],
	    @"foobarbazqux");
}

- (void)testCharactersWithString
{
	OTAssertEqualObjects(
	    [[OFXMLCharacters charactersWithString: @"<foo>"] XMLString],
	    @"&lt;foo&gt;");
}

- (void)testCDATAWithString
{
	OTAssertEqualObjects(
	    [[OFXMLCDATA CDATAWithString: @"<foo>"] XMLString],
	    @"<![CDATA[<foo>]]>");
}

- (void)testCommentWithText
{
	OTAssertEqualObjects(
	    [[OFXMLComment commentWithText: @" comment "] XMLString],
	    @"<!-- comment -->");
}

- (void)testIsEqual
{
	OTAssertEqualObjects(
	    [OFXMLElement elementWithXMLString: @"<foo bar='asd'/>"],
	    [OFXMLElement elementWithXMLString: @"<foo bar='asd'></foo>"]);

	OTAssertEqualObjects(
	    [OFXMLElement elementWithXMLString: @"<x><y/></x>"],
	    [OFXMLElement elementWithXMLString: @"<x><y></y></x>"]);

	OTAssertNotEqualObjects(
	    [OFXMLElement elementWithXMLString: @"<x><Y/></x>"],
	    [OFXMLElement elementWithXMLString: @"<x><y></y></x>"]);
}

- (void)testHash
{
	OTAssertEqual(
	    [[OFXMLElement elementWithXMLString: @"<foo bar='asd'/>"] hash],
	    [[OFXMLElement elementWithXMLString: @"<foo bar='asd'></foo>"]
	    hash]);

	OTAssertEqual(
	    [[OFXMLElement elementWithXMLString: @"<x><y/></x>"] hash],
	    [[OFXMLElement elementWithXMLString: @"<x><y></y></x>"] hash]);

	OTAssertNotEqual(
	    [[OFXMLElement elementWithXMLString: @"<x><Y/></x>"] hash],
	    [[OFXMLElement elementWithXMLString: @"<x><y></y></x>"] hash]);
}

- (void)testAddAttributeWithNameStringValue
{
	OFXMLElement *element = [OFXMLElement elementWithName: @"foo"
						  stringValue: @"b&ar"];

	[element setPrefix: @"objfw-test" forNamespace: @"urn:objfw:test"];
	[element addAttributeWithName: @"foo"
			  stringValue: @"b&ar"];
	[element addAttributeWithName: @"foo"
			    namespace: @"urn:objfw:test"
			  stringValue: @"bar"];

	OTAssertEqualObjects(element.XMLString,
	    @"<foo foo='b&amp;ar' objfw-test:foo='bar'>b&amp;ar</foo>");
}

- (void)testRemoveAttributeForNameNamespace
{
	OFXMLElement *element = [OFXMLElement elementWithName: @"foo"
						  stringValue: @"b&ar"];

	[element setPrefix: @"objfw-test" forNamespace: @"urn:objfw:test"];
	[element addAttributeWithName: @"foo"
			  stringValue: @"b&ar"];
	[element addAttributeWithName: @"foo"
			    namespace: @"urn:objfw:test"
			  stringValue: @"bar"];

	[element removeAttributeForName: @"foo"];
	OTAssertEqualObjects(element.XMLString,
	    @"<foo objfw-test:foo='bar'>b&amp;ar</foo>");

	[element removeAttributeForName: @"foo" namespace: @"urn:objfw:test"];
	OTAssertEqualObjects(element.XMLString, @"<foo>b&amp;ar</foo>");
}

- (void)testAddChild
{
	OFXMLElement *element;

	element = [OFXMLElement elementWithName: @"foo"];
	[element addAttributeWithName: @"foo" stringValue: @"b&ar"];
	[element addChild: [OFXMLElement elementWithName: @"bar"]];
	OTAssertEqualObjects(element.XMLString,
	    @"<foo foo='b&amp;ar'><bar/></foo>");

	element = [OFXMLElement elementWithName: @"foo"
				      namespace: @"urn:objfw:test"];
	[element setPrefix: @"objfw-test" forNamespace: @"urn:objfw:test"];
	[element addAttributeWithName: @"test" stringValue: @"test"];
	[element addChild: [OFXMLElement elementWithName: @"bar"
					       namespace: @"urn:objfw:test"]];
	OTAssertEqualObjects(element.XMLString,
	    @"<objfw-test:foo test='test'><objfw-test:bar/></objfw-test:foo>");
}

- (void)testElementsForNameNamespace
{
	OFXMLElement *element = [OFXMLElement elementWithName: @"foo"];
	OFXMLElement *bar;

	[element addChild: [OFXMLElement elementWithName: @"foo"]];
	bar = [OFXMLElement elementWithName: @"bar"
				  namespace: @"urn:objfw:test"];
	[element addChild: bar];

	OTAssertEqualObjects([element elementsForName: @"bar"
					    namespace: @"urn:objfw:test"],
	    [OFArray arrayWithObject: bar]);
}

- (void)testXMLStringWithIndentation
{
	OTAssertEqualObjects([[OFXMLElement
	    elementWithXMLString: @"<x><y><z>a\nb</z><!-- foo --></y></x>"]
	    XMLStringWithIndentation: 2],
	    @"<x>\n  <y>\n    <z>a\nb</z>\n    <!-- foo -->\n  </y>\n</x>");


}
@end

Modified tests/OFXMLParserTests.m from [e9e91152cf] to [7002f67f2b].

14
15
16
17
18
19
20
21

22
23

24


25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58

59
60
61
62
63



64
65
66
67
68

69
70
71
72

73







74
75
76
77


78

79
80
81
82
83

84
85


86



87

88
89
90
91
92
93
94
95
96
97
98
99
100
101






102

103
104
105


106

107

108
109
110
111
112
113
114
115
116



117
118
119
120

121
122
123
124

125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144

145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164






165



166



167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196


197





198



199
200
201
202

203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228



229
230
231
232
233
234
235
236
237
238

239
240
241
242

243
244
245
246
247
248
249
250

251
252
253
254
255
256

257
258
259
260

261
262
263
264
265
266

267
268
269
270


271
272
273
274
275
276
277
278
 */

#include "config.h"

#include <stdlib.h>
#include <string.h>

#import "TestsAppDelegate.h"


static OFString *const module = @"OFXMLParser";

static int i = 0;



enum EventType {
	eventTypeProcessingInstruction,
	eventTypeTagOpen,
	eventTypeTagClose,
	eventTypeString,
	eventTypeCDATA,
	eventTypeComment
};

@implementation TestsAppDelegate (OFXMLParser)
-   (void)parser: (OFXMLParser *)parser
  didCreateEvent: (enum EventType)type
	    name: (OFString *)name
	  prefix: (OFString *)prefix
       namespace: (OFString *)namespace
      attributes: (OFArray *)attrs
	  string: (OFString *)string
{
	OFString *message;

	i++;
	message = [OFString stringWithFormat: @"Parsing part #%d", i];

	switch (i) {
	case 1:
		TEST(message,
		    type == eventTypeProcessingInstruction &&
		    [name isEqual: @"xml"] &&
		    [string isEqual: @"version='1.0'"])
		break;
	case 2:
		TEST(message,
		    type == eventTypeProcessingInstruction &&

		    [name isEqual: @"p?i"] && string == nil)
		break;
	case 3:
		TEST(message,
		    type == eventTypeTagOpen && [name isEqual: @"root"] &&



		    prefix == nil && namespace == nil && attrs.count == 0)
		break;
	case 4:
		TEST(message,
		    type == eventTypeString && [string isEqual: @"\n\n "])

		break;
	case 5:
		TEST(message,
		    type == eventTypeCDATA && [string isEqual: @"f<]]]oo]"] &&

		    parser.lineNumber == 3)







		break;
	case 6:
		TEST(message,
		    type == eventTypeTagOpen && [name isEqual: @"bar"] &&


		    prefix == nil && namespace == nil && attrs == nil)

		break;
	case 7:
		TEST(message,
		    type == eventTypeTagClose && [name isEqual: @"bar"] &&
		    prefix == nil && namespace == nil && attrs == nil)

		break;
	case 8:


		TEST(message,



		    type == eventTypeString && [string isEqual: @"\n "])

		break;
	case 9:
		TEST(message,
		    type == eventTypeTagOpen && [name isEqual: @"foobar"] &&
		    prefix == nil &&
		    [namespace isEqual: @"urn:objfw:test:foobar"] &&
		    attrs.count == 1 &&
		    /* xmlns attr */
		    [[[attrs objectAtIndex: 0] name] isEqual: @"xmlns"] &&
		    [[attrs objectAtIndex: 0] namespace] == nil &&
		    [[[attrs objectAtIndex: 0] stringValue] isEqual:
		    @"urn:objfw:test:foobar"])
		break;
	case 10:






		TEST(message,

		    type == eventTypeString && [string isEqual: @"\n  "])
		break;
	case 11:


		TEST(message,

		    type == eventTypeTagOpen && [name isEqual: @"qux"] &&

		    prefix == nil &&
		    [namespace isEqual: @"urn:objfw:test:foobar"] &&
		    attrs.count == 1 &&
		    /* xmlns:foo attr */
		    [[[attrs objectAtIndex: 0] name] isEqual: @"foo"] &&
		    [[[attrs objectAtIndex: 0] namespace] isEqual:
		    @"http://www.w3.org/2000/xmlns/"] &&
		    [[[attrs objectAtIndex: 0] stringValue] isEqual:
		    @"urn:objfw:test:foo"])



		break;
	case 12:
		TEST(message,
		    type == eventTypeString && [string isEqual: @"\n   "])

		break;
	case 13:
		TEST(message,
		    type == eventTypeTagOpen && [name isEqual: @"bla"] &&

		    [prefix isEqual: @"foo"] &&
		    [namespace isEqual: @"urn:objfw:test:foo"] &&
		    attrs.count == 2 &&
		    /* foo:bla attr */
		    [[[attrs objectAtIndex: 0] name] isEqual: @"bla"] &&
		    [[[attrs objectAtIndex: 0] namespace] isEqual:
		    @"urn:objfw:test:foo"] &&
		    [[[attrs objectAtIndex: 0] stringValue] isEqual: @"bla"] &&
		    /* blafoo attr */
		    [[[attrs objectAtIndex: 1] name] isEqual: @"blafoo"] &&
		    [[attrs objectAtIndex: 1] namespace] == nil &&
		    [[[attrs objectAtIndex: 1] stringValue] isEqual: @"foo"])
		break;
	case 14:
		TEST(message,
		    type == eventTypeString && [string isEqual: @"\n    "])
		break;
	case 15:
		TEST(message,
		    type == eventTypeTagOpen && [name isEqual: @"blup"] &&

		    prefix == nil &&
		    [namespace isEqual: @"urn:objfw:test:foobar"] &&
		    attrs.count == 2 &&
		    /* foo:qux attr */
		    [[[attrs objectAtIndex: 0] name] isEqual: @"qux"] &&
		    [[[attrs objectAtIndex: 0] namespace] isEqual:
		    @"urn:objfw:test:foo"] &&
		    [[[attrs objectAtIndex: 0] stringValue] isEqual: @"asd"] &&
		    /* quxqux attr */
		    [[[attrs objectAtIndex: 1] name] isEqual: @"quxqux"] &&
		    [[attrs objectAtIndex: 1] namespace] == nil &&
		    [[[attrs objectAtIndex: 1] stringValue] isEqual: @"test"])
		break;
	case 16:
		TEST(message,
		    type == eventTypeTagClose && [name isEqual: @"blup"] &&
		    prefix == nil &&
		    [namespace isEqual: @"urn:objfw:test:foobar"])
		break;
	case 17:






		TEST(message,



		    type == eventTypeString && [string isEqual: @"\n    "])



		break;
	case 18:
		TEST(message,
		    type == eventTypeTagOpen && [name isEqual: @"bla"] &&
		    [prefix isEqual: @"bla"] &&
		    [namespace isEqual: @"urn:objfw:test:bla"] &&
		    attrs.count == 3 &&
		    /* xmlns:bla attr */
		    [[[attrs objectAtIndex: 0] name] isEqual: @"bla"] &&
		    [[[attrs objectAtIndex: 0] namespace] isEqual:
		    @"http://www.w3.org/2000/xmlns/"] &&
		    [[[attrs objectAtIndex: 0] stringValue] isEqual:
		    @"urn:objfw:test:bla"] &&
		    /* qux attr */
		    [[[attrs objectAtIndex: 1] name] isEqual: @"qux"] &&
		    [[attrs objectAtIndex: 1] namespace] == nil &&
		    [[[attrs objectAtIndex: 1] stringValue] isEqual: @"qux"] &&
		    /* bla:foo attr */
		    [[[attrs objectAtIndex: 2] name] isEqual: @"foo"] &&
		    [[[attrs objectAtIndex: 2] namespace] isEqual:
		    @"urn:objfw:test:bla"] &&
		    [[[attrs objectAtIndex: 2] stringValue] isEqual: @"blafoo"])
		break;
	case 19:
		TEST(message,
		    type == eventTypeTagClose && [name isEqual: @"bla"] &&
		    [prefix isEqual: @"bla"] &&
		    [namespace isEqual: @"urn:objfw:test:bla"])
		break;
	case 20:


		TEST(message,





		    type == eventTypeString && [string isEqual: @"\n    "])



		break;
	case 21:
		TEST(message,
		    type == eventTypeTagOpen && [name isEqual: @"abc"] &&

		    prefix == nil &&
		    [namespace isEqual: @"urn:objfw:test:abc"] &&
		    attrs.count == 3 &&
		    /* xmlns attr */
		    [[[attrs objectAtIndex: 0] name] isEqual: @"xmlns"] &&
		    [[attrs objectAtIndex: 0] namespace] == nil &&
		    [[[attrs objectAtIndex: 0] stringValue] isEqual:
		    @"urn:objfw:test:abc"] &&
		    /* abc attr */
		    [[[attrs objectAtIndex: 1] name] isEqual: @"abc"] &&
		    [[attrs objectAtIndex: 1] namespace] == nil &&
		    [[[attrs objectAtIndex: 1] stringValue] isEqual: @"abc"] &&
		    /* foo:abc attr */
		    [[[attrs objectAtIndex: 2] name] isEqual: @"abc"] &&
		    [[[attrs objectAtIndex: 2] namespace] isEqual:
		    @"urn:objfw:test:foo"] &&
		    [[[attrs objectAtIndex: 2] stringValue] isEqual: @"abc"])
		break;
	case 22:
		TEST(message,
		    type == eventTypeTagClose && [name isEqual: @"abc"] &&
		    prefix == nil && [namespace isEqual: @"urn:objfw:test:abc"])
		break;
	case 23:
		TEST(message,
		    type == eventTypeString && [string isEqual: @"\n   "])



		break;
	case 24:
		TEST(message,
		    type == eventTypeTagClose && [name isEqual: @"bla"] &&
		    [prefix isEqual: @"foo"] &&
		    [namespace isEqual: @"urn:objfw:test:foo"])
		break;
	case 25:
		TEST(message,
		    type == eventTypeString && [string isEqual: @"\n   "])

		break;
	case 26:
		TEST(message,
		    type == eventTypeComment && [string isEqual: @" commänt "])

		break;
	case 27:
		TEST(message,
		    type == eventTypeString && [string isEqual: @"\n  "])
		break;
	case 28:
		TEST(message,
		    type == eventTypeTagClose && [name isEqual: @"qux"] &&

		    prefix == nil &&
		    [namespace isEqual: @"urn:objfw:test:foobar"])
		break;
	case 29:
		TEST(message,
		    type == eventTypeString && [string isEqual: @"\n "])

		break;
	case 30:
		TEST(message,
		    type == eventTypeTagClose && [name isEqual: @"foobar"] &&

		    prefix == nil &&
		    [namespace isEqual: @"urn:objfw:test:foobar"])
		break;
	case 31:
		TEST(message,
		    type == eventTypeString && [string isEqual: @"\n"])

		break;
	case 32:
		TEST(message,
		    type == eventTypeTagClose && [name isEqual: @"root"] &&


		    prefix == nil && namespace == nil);
		break;
	}
}

-			  (void)parser: (OFXMLParser *)parser
  foundProcessingInstructionWithTarget: (OFString *)target
				  text: (OFString *)text







|
>

|
>
|
>
>










|








<
<
<
<
<
|
|
<
|
|
|

|
<
|
>
|

|
<
|
>
>
>
|

|
<
|
>

|
<
|
>
|
>
>
>
>
>
>
>


<
|
>
>
|
>


<
|
<
>


>
>
|
>
>
>
|
>


<
|
<
|
<
<
<
<
<
<


>
>
>
>
>
>
|
>
|


>
>
|
>
|
>
|
|
|
|
<
<
<
<
|
>
>
>

|
<
|
>

|
<
|
>
|
|
|
|
<
<
|
|
|
<
<
|
<
<
<
<


<
|
>
|
<
<
<
<
<
|
<
<
<
<
<


<
|
<
|


>
>
>
>
>
>
|
>
>
>
|
>
>
>


<
|
|
<
<
<
|
<
<
<
|
<
<
<
<
<
<
<
<
<


<
|
|
<


>
>
|
>
>
>
>
>
|
>
>
>


<
|
>
|
<
<
<
<
<
<
|
<
<
<
<
<
<
<
<
<


<
|
|


<
|
>
>
>


<
|
|
<


<
|
>


<
|
>


<
<
<
<
<
|
>
|
|

|
<
|
>

|
<
|
>
|
|

|
<
|
>

|
<
|
>
>
|







14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47





48
49

50
51
52
53
54

55
56
57
58
59

60
61
62
63
64
65
66

67
68
69
70

71
72
73
74
75
76
77
78
79
80
81
82

83
84
85
86
87
88
89

90

91
92
93
94
95
96
97
98
99
100
101
102
103

104

105






106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128




129
130
131
132
133
134

135
136
137
138

139
140
141
142
143
144


145
146
147


148




149
150

151
152
153





154





155
156

157

158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176

177
178



179



180









181
182

183
184

185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200

201
202
203






204









205
206

207
208
209
210

211
212
213
214
215
216

217
218

219
220

221
222
223
224

225
226
227
228





229
230
231
232
233
234

235
236
237
238

239
240
241
242
243
244

245
246
247
248

249
250
251
252
253
254
255
256
257
258
259
 */

#include "config.h"

#include <stdlib.h>
#include <string.h>

#import "ObjFW.h"
#import "ObjFWTest.h"

@interface OFXMLParserTests: OTTestCase <OFXMLParserDelegate>
{
	int _i;
}
@end

enum EventType {
	eventTypeProcessingInstruction,
	eventTypeTagOpen,
	eventTypeTagClose,
	eventTypeString,
	eventTypeCDATA,
	eventTypeComment
};

@implementation OFXMLParserTests
-   (void)parser: (OFXMLParser *)parser
  didCreateEvent: (enum EventType)type
	    name: (OFString *)name
	  prefix: (OFString *)prefix
       namespace: (OFString *)namespace
      attributes: (OFArray *)attrs
	  string: (OFString *)string
{





	switch (_i++) {
	case 0:

		OTAssertEqual(type, eventTypeProcessingInstruction);
		OTAssertEqualObjects(name, @"xml");
		OTAssertEqualObjects(string, @"version='1.0'");
		break;
	case 1:

		OTAssertEqual(type, eventTypeProcessingInstruction);
		OTAssertEqualObjects(name, @"p?i");
		OTAssertNil(string);
		break;
	case 2:

		OTAssertEqual(type, eventTypeTagOpen);
		OTAssertEqualObjects(name, @"root");
		OTAssertNil(prefix);
		OTAssertNil(namespace);
		OTAssertEqual(attrs.count, 0);
		break;
	case 3:

		OTAssertEqual(type, eventTypeString);
		OTAssertEqualObjects(string, @"\n\n ");
		break;
	case 4:

		OTAssertEqual(type, eventTypeCDATA);
		OTAssertEqualObjects(string, @"f<]]]oo]");
		OTAssertEqual(parser.lineNumber, 3);
		break;
	case 5:
		OTAssertEqual(type, eventTypeTagOpen);
		OTAssertEqualObjects(name, @"bar");
		OTAssertNil(prefix);
		OTAssertNil(namespace);
		OTAssertNil(attrs);
		break;
	case 6:

		OTAssertEqual(type, eventTypeTagClose);
		OTAssertEqualObjects(name, @"bar");
		OTAssertNil(prefix);
		OTAssertNil(namespace);
		OTAssertNil(attrs);
		break;
	case 7:

		OTAssertEqual(type, eventTypeString);

		OTAssertEqualObjects(string, @"\n ");
		break;
	case 8:
		OTAssertEqual(type, eventTypeTagOpen);
		OTAssertEqualObjects(name, @"foobar");
		OTAssertNil(prefix);
		OTAssertEqualObjects(namespace, @"urn:objfw:test:foobar");
		OTAssertEqualObjects(attrs, [OFArray arrayWithObject:
		    [OFXMLAttribute attributeWithName: @"xmlns"
					  stringValue: @"urn:objfw:test:"
						       @"foobar"]]);
		break;
	case 9:

		OTAssertEqual(type, eventTypeString);

		OTAssertEqualObjects(string, @"\n  ");






		break;
	case 10:
		OTAssertEqual(type, eventTypeTagOpen);
		OTAssertEqualObjects(name, @"qux");
		OTAssertNil(prefix);
		OTAssertEqualObjects(namespace, @"urn:objfw:test:foobar");
		OTAssertEqualObjects(attrs, [OFArray arrayWithObject:
		    [OFXMLAttribute attributeWithName: @"foo"
					    namespace: @"http://www.w3.org/"
						       @"2000/xmlns/"
					  stringValue: @"urn:objfw:test:foo"]]);
		break;
	case 11:
		OTAssertEqual(type, eventTypeString);
		OTAssertEqualObjects(string, @"\n   ");
		break;
	case 12:
		OTAssertEqual(type, eventTypeTagOpen);
		OTAssertEqualObjects(name, @"bla");
		OTAssertEqualObjects(prefix, @"foo");
		OTAssertEqualObjects(namespace, @"urn:objfw:test:foo");
		OTAssertEqualObjects(attrs, ([OFArray arrayWithObjects:
		    [OFXMLAttribute attributeWithName: @"bla"




					    namespace: @"urn:objfw:test:foo"
					  stringValue: @"bla"],
		    [OFXMLAttribute attributeWithName: @"blafoo"
					  stringValue: @"foo"], nil]));
		break;
	case 13:

		OTAssertEqual(type, eventTypeString);
		OTAssertEqualObjects(string, @"\n    ");
		break;
	case 14:

		OTAssertEqual(type, eventTypeTagOpen);
		OTAssertEqualObjects(name, @"blup");
		OTAssertNil(prefix);
		OTAssertEqualObjects(namespace, @"urn:objfw:test:foobar");
		OTAssertEqualObjects(attrs, ([OFArray arrayWithObjects:
		    [OFXMLAttribute attributeWithName: @"qux"


					    namespace: @"urn:objfw:test:foo"
					  stringValue: @"asd"],
		    [OFXMLAttribute attributeWithName: @"quxqux"


					  stringValue: @"test"], nil]));




		break;
	case 15:

		OTAssertEqual(type, eventTypeTagClose);
		OTAssertEqualObjects(name, @"blup");
		OTAssertNil(prefix);





		OTAssertEqualObjects(namespace, @"urn:objfw:test:foobar");





		break;
	case 16:

		OTAssertEqual(type, eventTypeString);

		OTAssertEqualObjects(string, @"\n    ");
		break;
	case 17:
		OTAssertEqual(type, eventTypeTagOpen);
		OTAssertEqualObjects(name, @"bla");
		OTAssertEqualObjects(prefix, @"bla");
		OTAssertEqualObjects(namespace, @"urn:objfw:test:bla");
		OTAssertEqualObjects(attrs, ([OFArray arrayWithObjects:
		    [OFXMLAttribute attributeWithName: @"bla"
					    namespace: @"http://www.w3.org/"
						       @"2000/xmlns/"
					  stringValue: @"urn:objfw:test:bla"],
		    [OFXMLAttribute attributeWithName: @"qux"
					  stringValue: @"qux"],
		    [OFXMLAttribute attributeWithName: @"foo"
					    namespace: @"urn:objfw:test:bla"
					  stringValue: @"blafoo"], nil]));
		break;
	case 18:

		OTAssertEqual(type, eventTypeTagClose);
		OTAssertEqualObjects(name, @"bla");



		OTAssertEqualObjects(prefix, @"bla");



		OTAssertEqualObjects(namespace, @"urn:objfw:test:bla");









		break;
	case 19:

		OTAssertEqual(type, eventTypeString);
		OTAssertEqualObjects(string, @"\n    ");

		break;
	case 20:
		OTAssertEqual(type, eventTypeTagOpen);
		OTAssertEqualObjects(name, @"abc");
		OTAssertNil(prefix);
		OTAssertEqualObjects(namespace, @"urn:objfw:test:abc");
		OTAssertEqualObjects(attrs, ([OFArray arrayWithObjects:
		    [OFXMLAttribute attributeWithName: @"xmlns"
					  stringValue: @"urn:objfw:test:abc"],
		    [OFXMLAttribute attributeWithName: @"abc"
					  stringValue: @"abc"],
		    [OFXMLAttribute attributeWithName: @"abc"
					    namespace: @"urn:objfw:test:foo"
					  stringValue: @"abc"], nil]));
		break;
	case 21:

		OTAssertEqual(type, eventTypeTagClose);
		OTAssertEqualObjects(name, @"abc");
		OTAssertNil(prefix);






		OTAssertEqualObjects(namespace, @"urn:objfw:test:abc");









		break;
	case 22:

		OTAssertEqual(type, eventTypeString);
		OTAssertEqualObjects(string, @"\n   ");
		break;
	case 23:

		OTAssertEqual(type, eventTypeTagClose);
		OTAssertEqualObjects(name, @"bla");
		OTAssertEqualObjects(prefix, @"foo");
		OTAssertEqualObjects(namespace, @"urn:objfw:test:foo");
		break;
	case 24:

		OTAssertEqual(type, eventTypeString);
		OTAssertEqualObjects(string, @"\n   ");

		break;
	case 25:

		OTAssertEqual(type, eventTypeComment);
		OTAssertEqualObjects(string, @" commänt ");
		break;
	case 26:

		OTAssertEqual(type, eventTypeString);
		OTAssertEqualObjects(string, @"\n  ");
		break;
	case 27:





		OTAssertEqual(type, eventTypeTagClose);
		OTAssertEqualObjects(name, @"qux");
		OTAssertNil(prefix);
		OTAssertEqualObjects(namespace, @"urn:objfw:test:foobar");
		break;
	case 28:

		OTAssertEqual(type, eventTypeString);
		OTAssertEqualObjects(string, @"\n ");
		break;
	case 29:

		OTAssertEqual(type, eventTypeTagClose);
		OTAssertEqualObjects(name, @"foobar");
		OTAssertNil(prefix);
		OTAssertEqualObjects(namespace, @"urn:objfw:test:foobar");
		break;
	case 30:

		OTAssertEqual(type, eventTypeString);
		OTAssertEqualObjects(string, @"\n");
		break;
	case 31:

		OTAssertEqual(type, eventTypeTagClose);
		OTAssertEqualObjects(name, @"root");
		OTAssertNil(prefix);
		OTAssertNil(namespace);
		break;
	}
}

-			  (void)parser: (OFXMLParser *)parser
  foundProcessingInstructionWithTarget: (OFString *)target
				  text: (OFString *)text
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409

410


411
412


413
414
415
416

417
418
419
420



421
422
423
424
425
426
427

428
429
430
431
432
{
	if ([entity isEqual: @"foo"])
		return @"foobar";

	return nil;
}

- (void)XMLParserTests
{
	void *pool = objc_autoreleasePoolPush();
	const char *string = "\xEF\xBB\xBF<?xml version='1.0'?><?p?i?>"
	    "<!DOCTYPE foo><root>\r\r"
	    " <![CDATA[f<]]]oo]]]><bar/>\n"
	    " <foobar xmlns='urn:objfw:test:foobar'>\r\n"
	    "  <qux xmlns:foo='urn:objfw:test:foo'>\n"
	    "   <foo:bla foo:bla = '&#x62;&#x6c;&#x61;' blafoo='foo'>\n"
	    "    <blup foo:qux='asd' quxqux='test'/>\n"
	    "    <bla:bla\r\rxmlns:bla\r=\t\"urn:objfw:test:bla\" qux='qux'\r\n"
	    "     bla:foo='blafoo'/>\n"
	    "    <abc xmlns='urn:objfw:test:abc' abc='abc' foo:abc='abc'/>\n"
	    "   </foo:bla>\n"
	    "   <!-- commänt -->\n"
	    "  </qux>\n"
	    " </foobar>\n"
	    "</root>";
	OFXMLParser *parser;
	size_t j, length;

	TEST(@"+[parser]", (parser = [OFXMLParser parser]))

	TEST(@"-[setDelegate:]", (parser.delegate = self))

	/* Simulate a stream where we only get chunks */
	length = strlen(string);

	for (j = 0; j < length; j+= 2) {
		if (parser.hasFinishedParsing)
			abort();

		if (j + 2 > length)
			[parser parseBuffer: string + j length: 1];
		else
			[parser parseBuffer: string + j length: 2];
	}

	TEST(@"Checking if everything was parsed",
	    i == 32 && parser.lineNumber == 18)

	TEST(@"-[hasFinishedParsing]", parser.hasFinishedParsing)

	TEST(@"Parsing whitespaces after the document",
	    R([parser parseString: @" \t\r\n "]))

	TEST(@"Parsing comments after the document",
	    R([parser parseString: @" \t<!-- foo -->\r<!--bar-->\n "]))

	EXPECT_EXCEPTION(@"Detection of junk after the document #1",

	    OFMalformedXMLException, [parser parseString: @"a"])



	EXPECT_EXCEPTION(@"Detection of junk after the document #2",


	    OFMalformedXMLException, [parser parseString: @"<!["])

	parser = [OFXMLParser parser];
	EXPECT_EXCEPTION(@"Detection of invalid XML processing instruction #1",

	    OFMalformedXMLException,
	    [parser parseString: @"<?xml version='2.0'?>"])

	parser = [OFXMLParser parser];



	EXPECT_EXCEPTION(@"Detection of invalid XML processing instruction #2",
	    OFInvalidEncodingException,
	    [parser parseString: @"<?xml encoding='UTF-7'?>"])

	parser = [OFXMLParser parser];
	EXPECT_EXCEPTION(@"Detection of invalid XML processing instruction #3",
	    OFMalformedXMLException,

	    [parser parseString: @"<x><?xml?></x>"])

	objc_autoreleasePoolPop(pool);
}
@end







|

<
|

















|
<
|














|
|
<
|

|
|

|
|

|
>
|
>
>
|
|
>
>
|


<
>
|
<


>
>
>
|
|
<
|
|
|
<
>
|
|
<


334
335
336
337
338
339
340
341
342

343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361

362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378

379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398

399
400

401
402
403
404
405
406
407

408
409
410

411
412
413

414
415
{
	if ([entity isEqual: @"foo"])
		return @"foobar";

	return nil;
}

- (void)testParser
{

	static const char *string = "\xEF\xBB\xBF<?xml version='1.0'?><?p?i?>"
	    "<!DOCTYPE foo><root>\r\r"
	    " <![CDATA[f<]]]oo]]]><bar/>\n"
	    " <foobar xmlns='urn:objfw:test:foobar'>\r\n"
	    "  <qux xmlns:foo='urn:objfw:test:foo'>\n"
	    "   <foo:bla foo:bla = '&#x62;&#x6c;&#x61;' blafoo='foo'>\n"
	    "    <blup foo:qux='asd' quxqux='test'/>\n"
	    "    <bla:bla\r\rxmlns:bla\r=\t\"urn:objfw:test:bla\" qux='qux'\r\n"
	    "     bla:foo='blafoo'/>\n"
	    "    <abc xmlns='urn:objfw:test:abc' abc='abc' foo:abc='abc'/>\n"
	    "   </foo:bla>\n"
	    "   <!-- commänt -->\n"
	    "  </qux>\n"
	    " </foobar>\n"
	    "</root>";
	OFXMLParser *parser;
	size_t j, length;

	parser = [OFXMLParser parser];

	parser.delegate = self;

	/* Simulate a stream where we only get chunks */
	length = strlen(string);

	for (j = 0; j < length; j+= 2) {
		if (parser.hasFinishedParsing)
			abort();

		if (j + 2 > length)
			[parser parseBuffer: string + j length: 1];
		else
			[parser parseBuffer: string + j length: 2];
	}

	OTAssertEqual(_i, 32);
	OTAssertEqual(parser.lineNumber, 18);

	OTAssertTrue(parser.hasFinishedParsing);

	/* Parsing whitespaces after the document */
	[parser parseString: @" \t\r\n "];

	/* Parsing comments after the document */
	[parser parseString: @" \t<!-- foo -->\r<!--bar-->\n "];

	/* Detection of junk after the document */
	OTAssertThrowsSpecific([parser parseString: @"a"],
	    OFMalformedXMLException);
	OTAssertThrowsSpecific([parser parseString: @"<!["],
	    OFMalformedXMLException);
}

- (void)testDetectionOfInvalidXMLProcessingInstructions
{
	OFXMLParser *parser;

	parser = [OFXMLParser parser];

	OTAssertThrowsSpecific([parser parseString: @"<?xml version='2.0'?>"],
	    OFMalformedXMLException);


	parser = [OFXMLParser parser];
	OTAssertThrowsSpecific([parser parseString: @"<x><?xml?></x>"],
	    OFMalformedXMLException);
}

- (void)testDetectionOfInvalidEncoding

{
	OFXMLParser *parser = [OFXMLParser parser];


	OTAssertThrowsSpecific(
	    [parser parseString: @"<?xml encoding='UTF-7'?>"],
	    OFInvalidEncodingException);

}
@end

Modified tests/RuntimeARCTests.m from [464cdbc085] to [685be12c90].

11
12
13
14
15
16
17
18

19
20

21
22
23
24
25


















26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
 * 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 = @"Runtime (ARC)";


@interface RuntimeARCTest: OFObject
@end

@implementation RuntimeARCTest


















- (instancetype)init
{
	self = [super init];

#if defined(OF_WINDOWS) && defined(OF_AMD64)
	/*
	 * Clang has a bug on Windows where it creates an invalid call into
	 * objc_retainAutoreleasedReturnValue(). Work around it by not using an
	 * autoreleased exception.
	 */
	@throw [[OFException alloc] init];
#else
	@throw [OFException exception];
#endif

	return self;
}
@end

@implementation TestsAppDelegate (RuntimeARCTests)
- (void)runtimeARCTests
{
	id object;
	__weak id weak;

	EXPECT_EXCEPTION(@"Exceptions in init", OFException,
	    object = [[RuntimeARCTest alloc] init])

	object = [[OFObject alloc] init];
	weak = object;
	TEST(@"weakly referencing an object", weak == object)

	object = nil;
	TEST(@"weak references becoming nil", weak == nil)
}
@end







|
>

|
>

|


|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>


















<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63


















 * 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 RuntimeARCTests: OTTestCase
@end

@interface RuntimeARCTestClass: OFObject
@end

@implementation RuntimeARCTests
- (void)testExceptionsDuringInit
{
	OTAssertThrows((void)[[RuntimeARCTestClass alloc] init]);
}

- (void)testWeakReferences
{
	id object = [[OFObject alloc] init];
	__weak id weak = object;

	OTAssertEqual(weak, object);

	object = nil;
	OTAssertNil(weak);
}
@end

@implementation RuntimeARCTestClass
- (instancetype)init
{
	self = [super init];

#if defined(OF_WINDOWS) && defined(OF_AMD64)
	/*
	 * Clang has a bug on Windows where it creates an invalid call into
	 * objc_retainAutoreleasedReturnValue(). Work around it by not using an
	 * autoreleased exception.
	 */
	@throw [[OFException alloc] init];
#else
	@throw [OFException exception];
#endif

	return self;
}
@end


















Modified tests/RuntimeTests.m from [99fca0e28e] to [6e0282335c].

11
12
13
14
15
16
17
18

19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37










38




































































































39
40
41
42
43
44
45
 * 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 = @"Runtime";
static void *testKey = &testKey;

@interface OFObject (SuperTest)
- (id)superTest;
@end

@interface RuntimeTest: OFObject
{
	OFString *_foo, *_bar;
}

@property (nonatomic, copy) OFString *foo;
@property (retain) OFString *bar;

- (id)nilSuperTest;
@end











@implementation RuntimeTest




































































































@synthesize foo = _foo;
@synthesize bar = _bar;

- (void)dealloc
{
	[_foo release];
	[_bar release];







|
>

<


<
<
<
<
|










>
>
>
>
>
>
>
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







11
12
13
14
15
16
17
18
19
20

21
22




23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
 * 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"


static void *testKey = &testKey;





@interface RuntimeTestClass: OFObject
{
	OFString *_foo, *_bar;
}

@property (nonatomic, copy) OFString *foo;
@property (retain) OFString *bar;

- (id)nilSuperTest;
@end

@interface RuntimeTests: OTTestCase
{
	RuntimeTestClass *_test;
}
@end

@interface OFObject (SuperTest)
- (id)superTest;
@end

@implementation RuntimeTests
- (void)setUp
{
	[super setUp];

	_test = [[RuntimeTestClass alloc] init];
}

- (void)dealloc
{
	[_test release];

	[super dealloc];
}

- (void)testCallNonExistentMethodViaSuper
{
	OTAssertThrowsSpecific([_test superTest], OFNotImplementedException);
}

- (void)testCallMethodViaSuperWithNilSelf
{
	OTAssertNil([_test nilSuperTest]);
}

- (void)testPropertyCopyNonatomic
{
	OFMutableString *string = [OFMutableString stringWithString: @"foo"];
	OFString *foo = @"foo";

	_test.foo = string;
	OTAssertEqualObjects(_test.foo, foo);
	OTAssertNotEqual(_test.foo, foo);
	OTAssertEqual(_test.foo.retainCount, 1);
}

- (void)testPropertyRetainAtomic
{
	OFMutableString *string = [OFMutableString stringWithString: @"foo"];

	_test.bar = string;
	OTAssertEqual(_test.bar, string);
	OTAssertEqual(string.retainCount, 3);
}

- (void)testAssociatedObjects
{
	objc_setAssociatedObject(self, testKey, _test, OBJC_ASSOCIATION_ASSIGN);
	OTAssertEqual(_test.retainCount, 1);

	objc_setAssociatedObject(self, testKey, _test, OBJC_ASSOCIATION_RETAIN);
	OTAssertEqual(_test.retainCount, 2);

	OTAssertEqual(objc_getAssociatedObject(self, testKey), _test);
	OTAssertEqual(_test.retainCount, 3);

	objc_setAssociatedObject(self, testKey, _test, OBJC_ASSOCIATION_ASSIGN);
	OTAssertEqual(_test.retainCount, 2);

	objc_setAssociatedObject(self, testKey, _test,
	    OBJC_ASSOCIATION_RETAIN_NONATOMIC);
	OTAssertEqual(_test.retainCount, 3);

	OTAssertEqual(objc_getAssociatedObject(self, testKey), _test);
	OTAssertEqual(_test.retainCount, 3);

	objc_removeAssociatedObjects(self);
	OTAssertEqual(_test.retainCount, 2);
}

#ifdef OF_OBJFW_RUNTIME
- (void)testTaggedPointers
{
	int classID;
	uintmax_t value;
	id object;

	if (sizeof(uintptr_t) == 8)
		value = 0xDEADBEEFDEADBEF;
	else if (sizeof(uintptr_t) == 4)
		value = 0xDEADBEF;
	else
		OTAssert(sizeof(uintptr_t) == 8 || sizeof(uintptr_t) == 4);

	OTAssertNotEqual(objc_registerTaggedPointerClass([OFString class]), -1);

	classID = objc_registerTaggedPointerClass([OFNumber class]);
	OTAssertNotEqual(classID, -1);

	object = objc_createTaggedPointer(classID, (uintptr_t)value);
	OTAssertNotNil(object);
	OTAssertEqual(object_getClass(object), [OFNumber class]);
	OTAssertEqual([object class], [OFNumber class]);
	OTAssertEqual(object_getTaggedPointerValue(object), value);
	OTAssertNotNil(objc_createTaggedPointer(classID, UINTPTR_MAX >> 4));
	OTAssertNil(objc_createTaggedPointer(classID, (UINTPTR_MAX >> 4) + 1));
}
#endif
@end

@implementation RuntimeTestClass
@synthesize foo = _foo;
@synthesize bar = _bar;

- (void)dealloc
{
	[_foo release];
	[_bar release];
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129

- (id)nilSuperTest
{
	self = nil;

	return [self superTest];
}
@end

@implementation TestsAppDelegate (RuntimeTests)
- (void)runtimeTests
{
	void *pool = objc_autoreleasePoolPush();
	RuntimeTest *test = [[[RuntimeTest alloc] init] autorelease];
	OFString *string, *foo;
#ifdef OF_OBJFW_RUNTIME
	int classID;
	uintmax_t value;
	id object;
#endif

	EXPECT_EXCEPTION(@"Calling a non-existent method via super",
	    OFNotImplementedException, [test superTest])

	TEST(@"Calling a method via a super with self == nil",
	    [test nilSuperTest] == nil)

	string = [OFMutableString stringWithString: @"foo"];
	foo = @"foo";

	test.foo = string;
	TEST(@"copy, nonatomic properties", [test.foo isEqual: foo] &&
	    test.foo != foo && test.foo.retainCount == 1)

	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;
	else
		abort();

	TEST(@"Tagged pointers",
	    objc_registerTaggedPointerClass([OFString class]) != -1 &&
	    (classID = objc_registerTaggedPointerClass([OFNumber class])) !=
	    -1 &&
	    (object = objc_createTaggedPointer(classID, (uintptr_t)value)) &&
	    object_getClass(object) == [OFNumber class] &&
	    [object class] == [OFNumber class] &&
	    object_getTaggedPointerValue(object) == value &&
	    objc_createTaggedPointer(classID, UINTPTR_MAX >> 4) != nil &&
	    objc_createTaggedPointer(classID, (UINTPTR_MAX >> 4) + 1) == nil)
#endif

	objc_autoreleasePoolPop(pool);
}
@end








<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
160
161
162
163
164
165
166
167





































































- (id)nilSuperTest
{
	self = nil;

	return [self superTest];
}
@end




































































Deleted tests/TestsAppDelegate.h version [6640fe2961].

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
/*
 * Copyright (c) 2008-2024 Jonathan Schleifer <js@nil.im>
 *
 * 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"

#define TEST(test, ...)							\
	{								\
		[self outputTesting: test inModule: module];		\
									\
		if (__VA_ARGS__)					\
			[self outputSuccess: test inModule: module];	\
		else {							\
			[self outputFailure: test inModule: module];	\
			_fails++;					\
		}							\
	}
#define EXPECT_EXCEPTION(test, exception, code)				\
	{								\
		bool caught = false;					\
									\
		[self outputTesting: test inModule: module];		\
									\
		@try {							\
			code;						\
		} @catch (exception *e) {				\
			caught = true;					\
		}							\
									\
		if (caught)						\
			[self outputSuccess: test inModule: module];	\
		else {							\
			[self outputFailure: test inModule: module];	\
			_fails++;					\
		}							\
	}
#define R(...) (__VA_ARGS__, 1)

@class OFString;

@interface TestsAppDelegate: OFObject <OFApplicationDelegate>
{
	int _fails;
}

- (void)outputTesting: (OFString *)test inModule: (OFString *)module;
- (void)outputSuccess: (OFString *)test inModule: (OFString *)module;
- (void)outputFailure: (OFString *)test inModule: (OFString *)module;
@end

@interface TestsAppDelegate (OFBlockTests)
- (void)blockTests;
@end

@interface TestsAppDelegate (OFDDPSocketTests)
- (void)DDPSocketTests;
@end

@interface TestsAppDelegate (OFDNSResolverTests)
- (void)DNSResolverTests;
@end

@interface TestsAppDelegate (OFDataTests)
- (void)dataTests;
@end

@interface TestsAppDelegate (OFDictionaryTests)
- (void)dictionaryTests;
@end

@interface TestsAppDelegate (ForwardingTests)
- (void)forwardingTests;
@end

@interface TestsAppDelegate (OFHTTPClientTests)
- (void)HTTPClientTests;
@end

@interface TestsAppDelegate (OFHTTPCookieTests)
- (void)HTTPCookieTests;
@end

@interface TestsAppDelegate (OFHTTPCookieManagerTests)
- (void)HTTPCookieManagerTests;
@end

@interface TestsAppDelegate (OFIPXSocketTests)
- (void)IPXSocketTests;
@end

@interface TestsAppDelegate (OFKernelEventObserverTests)
- (void)kernelEventObserverTests;
@end

@interface TestsAppDelegate (OFListTests)
- (void)listTests;
@end

@interface TestsAppDelegate (OFLocaleTests)
- (void)localeTests;
@end

@interface TestsAppDelegate  (OFMemoryStreamTests)
- (void)memoryStreamTests;
@end

@interface TestsAppDelegate (OFNotificationCenterTests)
- (void)notificationCenterTests;
@end

@interface TestsAppDelegate (OFObjectTests)
- (void)objectTests;
@end

@interface TestsAppDelegate (RuntimeTests)
- (void)runtimeTests;
@end

@interface TestsAppDelegate (RuntimeARCTests)
- (void)runtimeARCTests;
@end

@interface TestsAppDelegate (OFSPXSocketTests)
- (void)SPXSocketTests;
@end

@interface TestsAppDelegate (OFSPXStreamSocketTests)
- (void)SPXStreamSocketTests;
@end

@interface TestsAppDelegate (OFSetTests)
- (void)setTests;
@end

@interface TestsAppDelegate (OFSystemInfoTests)
- (void)systemInfoTests;
@end

@interface TestsAppDelegate (OFStreamTests)
- (void)streamTests;
@end

@interface TestsAppDelegate (OFStringTests)
- (void)stringTests;
@end

@interface TestsAppDelegate (OFTCPSocketTests)
- (void)TCPSocketTests;
@end

@interface TestsAppDelegate (OFUDPSocketTests)
- (void)UDPSocketTests;
@end

@interface TestsAppDelegate (OFUNIXDatagramSocketTests)
- (void)UNIXDatagramSocketTests;
@end

@interface TestsAppDelegate (OFUNIXStreamSocketTests)
- (void)UNIXStreamSocketTests;
@end

@interface TestsAppDelegate (OFValueTests)
- (void)valueTests;
@end

@interface TestsAppDelegate (OFWindowsRegistryKeyTests)
- (void)windowsRegistryKeyTests;
@end

@interface TestsAppDelegate (OFXMLElementBuilderTests)
- (void)XMLElementBuilderTests;
@end

@interface TestsAppDelegate (OFXMLNodeTests)
- (void)XMLNodeTests;
@end

@interface TestsAppDelegate (OFXMLParserTests)
    <OFXMLParserDelegate, OFXMLElementBuilderDelegate>
- (void)XMLParserTests;
@end
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<


































































































































































































































































































































































































Deleted tests/TestsAppDelegate.m version [283f0286c6].

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
/*
 * Copyright (c) 2008-2024 Jonathan Schleifer <js@nil.im>
 *
 * 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 <stdlib.h>

#import "TestsAppDelegate.h"

#ifdef OF_IOS
# include <CoreFoundation/CoreFoundation.h>
#endif

#ifdef OF_PSP
# include <pspmoduleinfo.h>
# include <pspkernel.h>
# include <pspdebug.h>
# include <pspctrl.h>
PSP_MODULE_INFO("ObjFW Tests", 0, 0, 0);
#endif

#ifdef OF_WII
# define asm __asm__
# include <gccore.h>
# include <wiiuse/wpad.h>
# undef asm
#endif

#ifdef OF_NINTENDO_DS
# define asm __asm__
# include <nds.h>
# undef asm
#endif

#ifdef OF_NINTENDO_3DS
/* Newer versions of libctru started using id as a parameter name. */
# define id id_3ds
# include <3ds.h>
# undef id
#endif

#ifdef OF_NINTENDO_SWITCH
# define id nx_id
# include <switch.h>
# undef id

static OFDate *lastConsoleUpdate;

static void
updateConsole(bool force)
{
	if (force || lastConsoleUpdate.timeIntervalSinceNow <= -1.0 / 60) {
		consoleUpdate(NULL);
		[lastConsoleUpdate release];
		lastConsoleUpdate = [[OFDate alloc] init];
	}
}
#endif

extern unsigned long OFHashSeed;

#ifdef OF_PSP
static int
exitCallback(int arg1, int arg2, void *arg)
{
	sceKernelExitGame();

	return 0;
}

static int
threadCallback(SceSize args, void *argp)
{
	sceKernelRegisterExitCallback(
	    sceKernelCreateCallback("Exit Callback", exitCallback, NULL));
	sceKernelSleepThreadCB();

	return 0;
}
#endif

int
main(int argc, char *argv[])
{
#ifdef OF_PSP
	int tid;
#endif

#if defined(OF_OBJFW_RUNTIME) && !defined(OF_WINDOWS) && !defined(OF_AMIGAOS)
	/*
	 * This does not work on Win32 if ObjFW is built as a DLL.
	 *
	 * On AmigaOS, some destructors need to be able to send messages.
	 * Calling objc_deinit() via atexit() would result in the runtime being
	 * destructed before for the destructors ran.
	 */
	atexit(objc_deinit);
#endif

	/* We need deterministic hashes for tests */
	OFHashSeed = 0;

#ifdef OF_WII
	GXRModeObj *rmode;
	void *xfb;

	VIDEO_Init();
	WPAD_Init();

	rmode = VIDEO_GetPreferredMode(NULL);
	xfb = MEM_K0_TO_K1(SYS_AllocateFramebuffer(rmode));
	VIDEO_Configure(rmode);
	VIDEO_SetNextFramebuffer(xfb);
	VIDEO_SetBlack(FALSE);
	VIDEO_Flush();

	VIDEO_WaitVSync();
	if (rmode->viTVMode & VI_NON_INTERLACE)
		VIDEO_WaitVSync();

	CON_InitEx(rmode, 10, 20, rmode->fbWidth - 10, rmode->xfbHeight - 20);
	VIDEO_ClearFrameBuffer(rmode, xfb, COLOR_BLACK);
#endif

#ifdef OF_PSP
	pspDebugScreenInit();

	sceCtrlSetSamplingCycle(0);
	sceCtrlSetSamplingMode(PSP_CTRL_MODE_DIGITAL);

	if ((tid = sceKernelCreateThread("update_thread", threadCallback,
	    0x11, 0xFA0, 0, 0)) >= 0)
		sceKernelStartThread(tid, 0, 0);
#endif

#ifdef OF_NINTENDO_DS
	consoleDemoInit();
#endif

#ifdef OF_NINTENDO_3DS
	gfxInitDefault();
	atexit(gfxExit);

	consoleInit(GFX_TOP, NULL);
#endif

#ifdef OF_NINTENDO_SWITCH
	consoleInit(NULL);
	padConfigureInput(1, HidNpadStyleSet_NpadStandard);
	updateConsole(true);

# ifdef OF_HAVE_FILES
	[[OFFileManager defaultManager] changeCurrentDirectoryPath: @"romfs:/"];
# endif
#endif

#if defined(OF_WII) || defined(OF_WII_U) || defined(OF_PSP) || \
    defined(OF_NINTENDO_DS) || defined(OF_NINTENDO_3DS) || \
    defined(OF_NINTENDO_SWITCH)
	@try {
		return OFApplicationMain(&argc, &argv,
		    [[TestsAppDelegate alloc] init]);
	} @catch (id e) {
		OFString *string = [OFString stringWithFormat:
		    @"\nRuntime error: Unhandled exception:\n%@\n", e];

		[OFStdOut setForegroundColor: [OFColor red]];
		[OFStdOut writeString: string];

		if ([e stackTraceAddresses] != nil)
			[OFStdOut writeString: @"\nStack trace:\n"];

		for (OFValue *address in [e stackTraceAddresses])
			[OFStdOut writeFormat: @"  %p\n", address.pointerValue];

# if defined(OF_WII)
		[OFStdOut reset];
		[OFStdOut writeString: @"Press home button to exit!"];

		for (;;) {
			WPAD_ScanPads();

			if (WPAD_ButtonsDown(0) & WPAD_BUTTON_HOME)
				[OFApplication terminateWithStatus: 1];

			VIDEO_WaitVSync();
		}
# elif defined(OF_PSP)
		sceKernelSleepThreadCB();
# elif defined(OF_NINTENDO_DS)
		[OFStdOut reset];
		[OFStdOut writeString: @"Press start button to exit!"];

		for (;;) {
			swiWaitForVBlank();
			scanKeys();
			if (keysDown() & KEY_START)
				[OFApplication terminateWithStatus: 1];
		}
# elif defined(OF_NINTENDO_3DS)
		[OFStdOut reset];
		[OFStdOut writeString: @"Press start button to exit!"];

		for (;;) {
			hidScanInput();

			if (hidKeysDown() & KEY_START)
				[OFApplication terminateWithStatus: 1];

			gspWaitForVBlank();
		}
# elif defined(OF_NINTENDO_SWITCH)
		while (appletMainLoop())
			updateConsole(true);

		consoleExit(NULL);
		abort();
# else
		abort();
# endif
	}
#else
	return OFApplicationMain(&argc, &argv, [[TestsAppDelegate alloc] init]);
#endif
}

@implementation TestsAppDelegate
- (void)outputTesting: (OFString *)test inModule: (OFString *)module
{
	if (OFStdOut.hasTerminal) {
		[OFStdOut setForegroundColor: [OFColor yellow]];
		[OFStdOut writeFormat: @"[%@] %@: testing...", module, test];
	} else
		[OFStdOut writeFormat: @"[%@] %@: ", module, test];

#ifdef OF_NINTENDO_SWITCH
	updateConsole(false);
#endif
}

- (void)outputSuccess: (OFString *)test inModule: (OFString *)module
{
	if (OFStdOut.hasTerminal) {
		[OFStdOut setForegroundColor: [OFColor lime]];
		[OFStdOut eraseLine];
		[OFStdOut writeFormat: @"\r[%@] %@: ok\n", module, test];
	} else
		[OFStdOut writeLine: @"ok"];

#ifdef OF_NINTENDO_SWITCH
	updateConsole(false);
#endif
}

- (void)outputFailure: (OFString *)test inModule: (OFString *)module
{
	if (OFStdOut.hasTerminal) {
		[OFStdOut setForegroundColor: [OFColor red]];
		[OFStdOut eraseLine];
		[OFStdOut writeFormat: @"\r[%@] %@: failed\n", module, test];
	} else
		[OFStdOut writeLine: @"failed"];

#ifdef OF_WII
	[OFStdOut reset];
	[OFStdOut writeLine: @"Press A to continue!"];

	for (;;) {
		WPAD_ScanPads();

		if (WPAD_ButtonsDown(0) & WPAD_BUTTON_A)
			return;

		VIDEO_WaitVSync();
	}
#endif
#ifdef OF_PSP
	[OFStdOut reset];
	[OFStdOut writeLine: @"Press X to continue!"];

	for (;;) {
		SceCtrlData pad;

		sceCtrlReadBufferPositive(&pad, 1);
		if (pad.Buttons & PSP_CTRL_CROSS) {
			for (;;) {
				sceCtrlReadBufferPositive(&pad, 1);
				if (!(pad.Buttons & PSP_CTRL_CROSS))
					return;
			}
		}
	}
#endif
#ifdef OF_NINTENDO_DS
	[OFStdOut reset];
	[OFStdOut writeString: @"Press A to continue!"];

	for (;;) {
		swiWaitForVBlank();
		scanKeys();
		if (keysDown() & KEY_A)
			break;
	}
#endif
#ifdef OF_NINTENDO_3DS
	[OFStdOut reset];
	[OFStdOut writeString: @"Press A to continue!"];

	for (;;) {
		hidScanInput();

		if (hidKeysDown() & KEY_A)
			break;

		gspWaitForVBlank();
	}
#endif
#ifdef OF_NINTENDO_SWITCH
	[OFStdOut reset];
	[OFStdOut writeString: @"Press A to continue!"];

	while (appletMainLoop()) {
		PadState pad;

		padUpdate(&pad);
		updateConsole(true);

		if (padGetButtonsDown(&pad) & HidNpadButton_A)
			break;
	}
#endif

	if (OFStdOut.hasTerminal) {
		[OFStdOut writeString: @"\r"];
		[OFStdOut reset];
		[OFStdOut eraseLine];
	}
}

- (void)applicationDidFinishLaunching: (OFNotification *)notification
{
#if defined(OF_IOS) && defined(OF_HAVE_FILES)
	CFBundleRef mainBundle = CFBundleGetMainBundle();
	CFURLRef resourcesURL = CFBundleCopyResourcesDirectoryURL(mainBundle);
	UInt8 resourcesPath[PATH_MAX];

	if (!CFURLGetFileSystemRepresentation(resourcesURL, true, resourcesPath,
	    PATH_MAX)) {
		[OFStdErr writeString: @"Failed to locate resources!\n"];
		[OFApplication terminateWithStatus: 1];
	}

	[[OFFileManager defaultManager] changeCurrentDirectoryPath:
	    [OFString stringWithUTF8String: (const char *)resourcesPath]];
#endif
#if defined(OF_WII) && defined(OF_HAVE_FILES)
	[[OFFileManager defaultManager]
	    changeCurrentDirectoryPath: @"/apps/objfw-tests"];
#endif

	[self runtimeTests];
#ifdef COMPILER_SUPPORTS_ARC
	[self runtimeARCTests];
#endif
	[self objectTests];
	[self forwardingTests];
#ifdef OF_HAVE_BLOCKS
	[self blockTests];
#endif
	[self stringTests];
	[self dataTests];
	[self dictionaryTests];
	[self listTests];
	[self setTests];
	[self valueTests];
	[self streamTests];
	[self memoryStreamTests];
	[self notificationCenterTests];
#ifdef OF_HAVE_SOCKETS
	[self TCPSocketTests];
	[self UDPSocketTests];
# ifdef OF_HAVE_UNIX_SOCKETS
	[self UNIXDatagramSocketTests];
	[self UNIXStreamSocketTests];
# endif
# ifdef OF_HAVE_IPX
	[self IPXSocketTests];
	[self SPXSocketTests];
	[self SPXStreamSocketTests];
# endif
# ifdef OF_HAVE_APPLETALK
	[self DDPSocketTests];
# endif
	[self kernelEventObserverTests];
#endif
#if defined(OF_HAVE_SOCKETS) && defined(OF_HAVE_THREADS)
	[self HTTPClientTests];
#endif
#ifdef OF_HAVE_SOCKETS
	[self HTTPCookieTests];
	[self HTTPCookieManagerTests];
#endif
	[self XMLParserTests];
	[self XMLNodeTests];
	[self XMLElementBuilderTests];

#ifdef OF_WINDOWS
	[self windowsRegistryKeyTests];
#endif

#ifdef OF_HAVE_SOCKETS
	[self DNSResolverTests];
#endif
	[self systemInfoTests];
	[self localeTests];

	[OFStdOut reset];

#if defined(OF_IOS)
	[OFStdOut writeFormat: @"%d tests failed!", _fails];
	[OFApplication terminateWithStatus: _fails];
#elif defined(OF_WII)
	[OFStdOut writeString: @"Press home button to exit!"];

	for (;;) {
		WPAD_ScanPads();

		if (WPAD_ButtonsDown(0) & WPAD_BUTTON_HOME)
			[OFApplication terminateWithStatus: _fails];

		VIDEO_WaitVSync();
	}
#elif defined(OF_PSP)
	[OFStdOut writeFormat: @"%d tests failed!", _fails];

	sceKernelSleepThreadCB();
#elif defined(OF_NINTENDO_DS)
	[OFStdOut writeString: @"Press start button to exit!"];

	for (;;) {
		swiWaitForVBlank();
		scanKeys();
		if (keysDown() & KEY_START)
			[OFApplication terminateWithStatus: _fails];
	}
#elif defined(OF_NINTENDO_3DS)
	[OFStdOut writeString: @"Press start button to exit!"];

	for (;;) {
		hidScanInput();

		if (hidKeysDown() & KEY_START)
			[OFApplication terminateWithStatus: _fails];

		gspWaitForVBlank();
	}
#elif defined(OF_NINTENDO_SWITCH)
	while (appletMainLoop())
		updateConsole(true);

	consoleExit(NULL);

	[OFApplication terminateWithStatus: _fails];
#else
	[OFApplication terminateWithStatus: _fails];
#endif
}
@end
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































Modified tests/iOS.xcodeproj/project.pbxproj from [ac2dd7d645] to [a002968e40].

1
2
3
4
5
6
7
8
9

10
11
12
13
14
15
16
// !$*UTF8*$!
{
	archiveVersion = 1;
	classes = {
	};
	objectVersion = 48;
	objects = {

/* Begin PBXBuildFile section */

		4B6AB9CD202BA431007BAC7D /* TestPlugin.bundle in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4B6AB9CA202BA408007BAC7D /* TestPlugin.bundle */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
		4BC7FD07201394F300280496 /* ObjFW.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4BC7FD06201394F300280496 /* ObjFW.framework */; };
		4BC7FD092013954B00280496 /* tests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4BC7FD082013954B00280496 /* tests.a */; };
		4BC7FD0B2013956D00280496 /* ObjFW.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4BC7FD06201394F300280496 /* ObjFW.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
		4BC7FD102013960600280496 /* testfile.txt in Resources */ = {isa = PBXBuildFile; fileRef = 4BC7FD0C2013960600280496 /* testfile.txt */; };
		4BC7FD112013960600280496 /* testfile.bin in Resources */ = {isa = PBXBuildFile; fileRef = 4BC7FD0D2013960600280496 /* testfile.bin */; };
		4BC7FD132013960600280496 /* testfile.ini in Resources */ = {isa = PBXBuildFile; fileRef = 4BC7FD0F2013960600280496 /* testfile.ini */; };









>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// !$*UTF8*$!
{
	archiveVersion = 1;
	classes = {
	};
	objectVersion = 48;
	objects = {

/* Begin PBXBuildFile section */
		4B1E2CEF2B8294F200BB28B6 /* libobjfwtest.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4B1E2CEE2B8294F200BB28B6 /* libobjfwtest.a */; };
		4B6AB9CD202BA431007BAC7D /* TestPlugin.bundle in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4B6AB9CA202BA408007BAC7D /* TestPlugin.bundle */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
		4BC7FD07201394F300280496 /* ObjFW.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4BC7FD06201394F300280496 /* ObjFW.framework */; };
		4BC7FD092013954B00280496 /* tests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4BC7FD082013954B00280496 /* tests.a */; };
		4BC7FD0B2013956D00280496 /* ObjFW.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4BC7FD06201394F300280496 /* ObjFW.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
		4BC7FD102013960600280496 /* testfile.txt in Resources */ = {isa = PBXBuildFile; fileRef = 4BC7FD0C2013960600280496 /* testfile.txt */; };
		4BC7FD112013960600280496 /* testfile.bin in Resources */ = {isa = PBXBuildFile; fileRef = 4BC7FD0D2013960600280496 /* testfile.bin */; };
		4BC7FD132013960600280496 /* testfile.ini in Resources */ = {isa = PBXBuildFile; fileRef = 4BC7FD0F2013960600280496 /* testfile.ini */; };
37
38
39
40
41
42
43

44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61


62
63
64
65
66
67
68
69
70
71
72

73
74
75
76
77
78
79
				4BC7FD0B2013956D00280496 /* ObjFW.framework in CopyFiles */,
			);
			runOnlyForDeploymentPostprocessing = 0;
		};
/* End PBXCopyFilesBuildPhase section */

/* Begin PBXFileReference section */

		4B6AB9CA202BA408007BAC7D /* TestPlugin.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; name = TestPlugin.bundle; path = plugin/TestPlugin.bundle; sourceTree = "<group>"; };
		4BC7FD06201394F300280496 /* ObjFW.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ObjFW.framework; path = ../src/ObjFW.framework; sourceTree = "<group>"; };
		4BC7FD082013954B00280496 /* tests.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = tests.a; sourceTree = "<group>"; };
		4BC7FD0C2013960600280496 /* testfile.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = testfile.txt; sourceTree = "<group>"; };
		4BC7FD0D2013960600280496 /* testfile.bin */ = {isa = PBXFileReference; lastKnownFileType = archive.macbinary; path = testfile.bin; sourceTree = "<group>"; };
		4BC7FD0F2013960600280496 /* testfile.ini */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = testfile.ini; sourceTree = "<group>"; };
		4BEBFB5B2013934E002E8710 /* tests.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = tests.app; sourceTree = BUILT_PRODUCTS_DIR; };
		4BEBFB6C2013934E002E8710 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = SOURCE_ROOT; };
		4BEBFB6D2013934E002E8710 /* ImportTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ImportTest.m; sourceTree = SOURCE_ROOT; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
		4BEBFB582013934E002E8710 /* Frameworks */ = {
			isa = PBXFrameworksBuildPhase;
			buildActionMask = 2147483647;
			files = (
				4BC7FD07201394F300280496 /* ObjFW.framework in Frameworks */,
				4BC7FD092013954B00280496 /* tests.a in Frameworks */,


			);
			runOnlyForDeploymentPostprocessing = 0;
		};
/* End PBXFrameworksBuildPhase section */

/* Begin PBXGroup section */
		4BC7FD05201394F300280496 /* Frameworks */ = {
			isa = PBXGroup;
			children = (
				4B6AB9CA202BA408007BAC7D /* TestPlugin.bundle */,
				4BC7FD082013954B00280496 /* tests.a */,

				4BC7FD06201394F300280496 /* ObjFW.framework */,
			);
			name = Frameworks;
			sourceTree = "<group>";
		};
		4BEBFB522013934E002E8710 = {
			isa = PBXGroup;







>
















<

>
>











>







38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61

62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
				4BC7FD0B2013956D00280496 /* ObjFW.framework in CopyFiles */,
			);
			runOnlyForDeploymentPostprocessing = 0;
		};
/* End PBXCopyFilesBuildPhase section */

/* Begin PBXFileReference section */
		4B1E2CEE2B8294F200BB28B6 /* libobjfwtest.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libobjfwtest.a; path = ../src/test/libobjfwtest.a; sourceTree = "<group>"; };
		4B6AB9CA202BA408007BAC7D /* TestPlugin.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; name = TestPlugin.bundle; path = plugin/TestPlugin.bundle; sourceTree = "<group>"; };
		4BC7FD06201394F300280496 /* ObjFW.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ObjFW.framework; path = ../src/ObjFW.framework; sourceTree = "<group>"; };
		4BC7FD082013954B00280496 /* tests.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = tests.a; sourceTree = "<group>"; };
		4BC7FD0C2013960600280496 /* testfile.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = testfile.txt; sourceTree = "<group>"; };
		4BC7FD0D2013960600280496 /* testfile.bin */ = {isa = PBXFileReference; lastKnownFileType = archive.macbinary; path = testfile.bin; sourceTree = "<group>"; };
		4BC7FD0F2013960600280496 /* testfile.ini */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = testfile.ini; sourceTree = "<group>"; };
		4BEBFB5B2013934E002E8710 /* tests.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = tests.app; sourceTree = BUILT_PRODUCTS_DIR; };
		4BEBFB6C2013934E002E8710 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = SOURCE_ROOT; };
		4BEBFB6D2013934E002E8710 /* ImportTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ImportTest.m; sourceTree = SOURCE_ROOT; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
		4BEBFB582013934E002E8710 /* Frameworks */ = {
			isa = PBXFrameworksBuildPhase;
			buildActionMask = 2147483647;
			files = (

				4BC7FD092013954B00280496 /* tests.a in Frameworks */,
				4B1E2CEF2B8294F200BB28B6 /* libobjfwtest.a in Frameworks */,
				4BC7FD07201394F300280496 /* ObjFW.framework in Frameworks */,
			);
			runOnlyForDeploymentPostprocessing = 0;
		};
/* End PBXFrameworksBuildPhase section */

/* Begin PBXGroup section */
		4BC7FD05201394F300280496 /* Frameworks */ = {
			isa = PBXGroup;
			children = (
				4B6AB9CA202BA408007BAC7D /* TestPlugin.bundle */,
				4BC7FD082013954B00280496 /* tests.a */,
				4B1E2CEE2B8294F200BB28B6 /* libobjfwtest.a */,
				4BC7FD06201394F300280496 /* ObjFW.framework */,
			);
			name = Frameworks;
			sourceTree = "<group>";
		};
		4BEBFB522013934E002E8710 = {
			isa = PBXGroup;
300
301
302
303
304
305
306

307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326

327
328
329
330
331
332
333
				DEVELOPMENT_TEAM = MXKNFCKFL6;
				FRAMEWORK_SEARCH_PATHS = "$(PROJECT_DIR)/../src";
				INFOPLIST_FILE = Info.plist;
				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
				LIBRARY_SEARCH_PATHS = (
					"$(inherited)",
					"$(PROJECT_DIR)",

				);
				OTHER_LDFLAGS = "-all_load";
				PRODUCT_BUNDLE_IDENTIFIER = im.nil.objfw.tests;
				PRODUCT_NAME = "$(TARGET_NAME)";
				TARGETED_DEVICE_FAMILY = "1,2";
			};
			name = Debug;
		};
		4BEBFB732013934E002E8710 /* Release */ = {
			isa = XCBuildConfiguration;
			buildSettings = {
				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
				CODE_SIGN_STYLE = Automatic;
				DEVELOPMENT_TEAM = MXKNFCKFL6;
				FRAMEWORK_SEARCH_PATHS = "$(PROJECT_DIR)/../src";
				INFOPLIST_FILE = Info.plist;
				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
				LIBRARY_SEARCH_PATHS = (
					"$(inherited)",
					"$(PROJECT_DIR)",

				);
				OTHER_LDFLAGS = "-all_load";
				PRODUCT_BUNDLE_IDENTIFIER = im.nil.objfw.tests;
				PRODUCT_NAME = "$(TARGET_NAME)";
				TARGETED_DEVICE_FAMILY = "1,2";
			};
			name = Release;







>




















>







304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
				DEVELOPMENT_TEAM = MXKNFCKFL6;
				FRAMEWORK_SEARCH_PATHS = "$(PROJECT_DIR)/../src";
				INFOPLIST_FILE = Info.plist;
				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
				LIBRARY_SEARCH_PATHS = (
					"$(inherited)",
					"$(PROJECT_DIR)",
					"$(PROJECT_DIR)/../src/test",
				);
				OTHER_LDFLAGS = "-all_load";
				PRODUCT_BUNDLE_IDENTIFIER = im.nil.objfw.tests;
				PRODUCT_NAME = "$(TARGET_NAME)";
				TARGETED_DEVICE_FAMILY = "1,2";
			};
			name = Debug;
		};
		4BEBFB732013934E002E8710 /* Release */ = {
			isa = XCBuildConfiguration;
			buildSettings = {
				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
				CODE_SIGN_STYLE = Automatic;
				DEVELOPMENT_TEAM = MXKNFCKFL6;
				FRAMEWORK_SEARCH_PATHS = "$(PROJECT_DIR)/../src";
				INFOPLIST_FILE = Info.plist;
				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
				LIBRARY_SEARCH_PATHS = (
					"$(inherited)",
					"$(PROJECT_DIR)",
					"$(PROJECT_DIR)/../src/test",
				);
				OTHER_LDFLAGS = "-all_load";
				PRODUCT_BUNDLE_IDENTIFIER = im.nil.objfw.tests;
				PRODUCT_NAME = "$(TARGET_NAME)";
				TARGETED_DEVICE_FAMILY = "1,2";
			};
			name = Release;

Added tests/plugin/Info.plist.in version [bbe65d4bbd].













































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>CFBundleExecutable</key>
	<string>TestPlugin</string>
	<key>CFBundleName</key>
	<string>TestPlugin</string>
	<key>CFBundleIdentifier</key>
	<string>im.nil.objfw.tests.plugin</string>
	<key>CFBundleInfoDictionaryVersion</key>
	<string>6.0</string>
	<key>CFBundlePackageType</key>
	<string>BNDL</string>
	<key>CFBundleVersion</key>
	<string>@BUNDLE_VERSION@</string>
	<key>CFBundleShortVersionString</key>
	<string>@BUNDLE_SHORT_VERSION@</string>
	<key>MinimumOSVersion</key>
	<string>9.0</string>
</dict>
</plist>

Added tests/plugin/Makefile version [a32249aa5e].























>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
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 tests/plugin/TestPlugin.h version [0bf4ece135].









































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/*
 * Copyright (c) 2008-2024 Jonathan Schleifer <js@nil.im>
 *
 * 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 tests/plugin/TestPlugin.m version [f9d32844b0].







































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
/*
 * Copyright (c) 2008-2024 Jonathan Schleifer <js@nil.im>
 *
 * 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 tests/subprocess/Makefile version [0c326652cc].



















>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
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 tests/subprocess/Subprocess.m version [31a1046120].























































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
/*
 * Copyright (c) 2008-2024 Jonathan Schleifer <js@nil.im>
 *
 * 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 <OFApplicationDelegate>
@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 tests/testfile.bin version [ac78121630].

cannot compute difference between binary files

Added tests/testfile.ini version [9e2ef2dc1a].











































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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

Modified utils/objfw-new/Makefile from [b67c1400ab] to [8cc4a388ef].

1
2
3
4
5

6
7
8
9
10
11
12
include ../../extra.mk

PROG = objfw-new${PROG_SUFFIX}
SRCS = NewApp.m		\
       NewClass.m	\

       ObjFWNew.m	\
       Property.m

include ../../buildsys.mk

${PROG}: ${LIBOBJFW_DEP_LVL2} ${LIBOBJFWRT_DEP_LVL2}






>







1
2
3
4
5
6
7
8
9
10
11
12
13
include ../../extra.mk

PROG = objfw-new${PROG_SUFFIX}
SRCS = NewApp.m		\
       NewClass.m	\
       NewTest.m	\
       ObjFWNew.m	\
       Property.m

include ../../buildsys.mk

${PROG}: ${LIBOBJFW_DEP_LVL2} ${LIBOBJFWRT_DEP_LVL2}

Added utils/objfw-new/NewTest.m version [0991f0679f].













































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
/*
 * Copyright (c) 2008-2024 Jonathan Schleifer <js@nil.im>
 *
 * 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 <errno.h>

#import "OFApplication.h"
#import "OFFile.h"
#import "OFStdIOStream.h"
#import "OFString.h"

#import "OFOpenItemFailedException.h"

void
newTest(OFString *name)
{
	OFString *path = [name stringByAppendingPathExtension: @"m"];
	OFFile *file = nil;
	@try {
		file = [OFFile fileWithPath: path mode: @"wx"];
	} @catch (OFOpenItemFailedException *e) {
		if (e.errNo != EEXIST)
			@throw e;

		[OFStdErr writeFormat: @"File %@ already exists! Aborting...\n",
				       e.path];
		[OFApplication terminateWithStatus: 1];
	}

	[file writeFormat: @"#import <ObjFW/ObjFW.h>\n"
			   @"#import <ObjFWTest/ObjFWTest.h>\n"
			   @"\n"
			   @"@interface %@: OTTestCase\n"
			   @"@end\n"
			   @"\n"
			   @"@implementation %@\n"
			   @"@end\n",
			   name, name];

	[file close];
}

Modified utils/objfw-new/ObjFWNew.m from [5f604351d2] to [0b89b26b9a].

23
24
25
26
27
28
29

30
31
32
33
34
35
36
37

38
39
40
41
42
43
44
45
46
47
48
49
50
51



52
53
54
55
56
57
58
59
60
61
62
63
64
65
66

67
68
69
70
71
72
73
74
75
#import "OFString.h"

@interface ObjFWNew: OFObject <OFApplicationDelegate>
@end

extern void newApp(OFString *);
extern void newClass(OFString *, OFString *, OFMutableArray *);


OF_APPLICATION_DELEGATE(ObjFWNew)

static void
help(OFStream *stream, bool full, int status)
{
	[stream writeFormat:
	    @"Usage: %@ --app|--class [--superclass=] [--property=] name\n",

	    [OFApplication programName]];

	if (full) {
		[stream writeString: @"\n"];
		[stream writeLine:
		    @"Options:\n"
		    @"    -a  --app          Create a new app\n"
		    @"    -c  --class        Create a new class\n"
		    @"    -h  --help         Show this help\n"
		    @"    -s  --superclass=  Specify the superclass for the "
		    @"class\n"
		    @"    -p  --property=    Add a property to the class.\n"
		    @"                       E.g.: --property='(readonly, "
		    @"nonatomic) id foo'"];



	}

	[OFApplication terminateWithStatus: status];
}

@implementation ObjFWNew
- (void)applicationDidFinishLaunching: (OFNotification *)notification
{
	bool app, class;
	OFString *superclass = nil, *name;
	OFMutableArray OF_GENERIC(OFString *) *properties = nil;
	const OFOptionsParserOption options[] = {
		{ 'a', @"app", 0, &app, NULL },
		{ 'c', @"class", 0, &class, NULL },
		{ 'h', @"help", 0, NULL, NULL },

		{ 's', @"superclass", 1, NULL, &superclass },
		{ 'p', @"property", 1, NULL, NULL },
		{ '\0', nil, 0, NULL, NULL }
	};
	OFOptionsParser *optionsParser;
	OFUnichar option;

	if ([OFApplication arguments].count == 0)
		help(OFStdErr, true, 1);







>







|
>









<
<


|
>
>
>








|






>

|







23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48


49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
#import "OFString.h"

@interface ObjFWNew: OFObject <OFApplicationDelegate>
@end

extern void newApp(OFString *);
extern void newClass(OFString *, OFString *, OFMutableArray *);
extern void newTest(OFString *);

OF_APPLICATION_DELEGATE(ObjFWNew)

static void
help(OFStream *stream, bool full, int status)
{
	[stream writeFormat:
	    @"Usage: %@ --app|--class|--test [--superclass=] [--property=] name"
	    @"\n",
	    [OFApplication programName]];

	if (full) {
		[stream writeString: @"\n"];
		[stream writeLine:
		    @"Options:\n"
		    @"    -a  --app          Create a new app\n"
		    @"    -c  --class        Create a new class\n"
		    @"    -h  --help         Show this help\n"


		    @"    -p  --property=    Add a property to the class.\n"
		    @"                       E.g.: --property='(readonly, "
		    @"nonatomic) id foo'\n"
		    @"    -s  --superclass=  Specify the superclass for the "
		    @"class\n"
		    @"    -t  --test         Create a new test\n"];
	}

	[OFApplication terminateWithStatus: status];
}

@implementation ObjFWNew
- (void)applicationDidFinishLaunching: (OFNotification *)notification
{
	bool app, class, test;
	OFString *superclass = nil, *name;
	OFMutableArray OF_GENERIC(OFString *) *properties = nil;
	const OFOptionsParserOption options[] = {
		{ 'a', @"app", 0, &app, NULL },
		{ 'c', @"class", 0, &class, NULL },
		{ 'h', @"help", 0, NULL, NULL },
		{ 'p', @"property", 1, NULL, NULL },
		{ 's', @"superclass", 1, NULL, &superclass },
		{ 't', @"test", 0, &test, NULL },
		{ '\0', nil, 0, NULL, NULL }
	};
	OFOptionsParser *optionsParser;
	OFUnichar option;

	if ([OFApplication arguments].count == 0)
		help(OFStdErr, true, 1);
90
91
92
93
94
95
96

97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112


113
114
115
116
117
118
		case ':':
		case '=':
			help(OFStdErr, false, 1);
			break;
		}
	}


	if ((app ^ class) != 1 || optionsParser.remainingArguments.count != 1)
		help(OFStdErr, false, 1);

	if ((superclass && !class)  || (properties != nil && !class))
		help(OFStdErr, false, 1);

	name = optionsParser.remainingArguments.firstObject;
	if ([name rangeOfString: @"."].location != OFNotFound) {
		[OFStdErr writeLine: @"Name must not contain dots!"];
		[OFApplication terminate];
	}

	if (app)
		newApp(name);
	else if (class)
		newClass(name, superclass, properties);


	else
		help(OFStdErr, false, 1);

	[OFApplication terminate];
}
@end







>
|















>
>






94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
		case ':':
		case '=':
			help(OFStdErr, false, 1);
			break;
		}
	}

	if (app + class + test != 1 ||
	    optionsParser.remainingArguments.count != 1)
		help(OFStdErr, false, 1);

	if ((superclass && !class)  || (properties != nil && !class))
		help(OFStdErr, false, 1);

	name = optionsParser.remainingArguments.firstObject;
	if ([name rangeOfString: @"."].location != OFNotFound) {
		[OFStdErr writeLine: @"Name must not contain dots!"];
		[OFApplication terminate];
	}

	if (app)
		newApp(name);
	else if (class)
		newClass(name, superclass, properties);
	else if (test)
		newTest(name);
	else
		help(OFStdErr, false, 1);

	[OFApplication terminate];
}
@end