ObjFW  Check-in [61a6ac873a]

Overview
Comment:Big diff, see details.

* Add OFComparable protocol.
* Add OFInvalidArgument exception - needs that sel_getName vs.
sel_get_name stuff again, therefore reintroduce it.
* Implement proper copy method for OFString and OFArray.
* Add isEqual: and compare: for OFString and OFArray.

Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 61a6ac873a38a44874fb58ae7c891b076a3a1605ae1465c3abe6cda2605fffd5
User & Date: js on 2009-02-14 17:08:21
Other Links: manifest | tags
Context
2009-02-14
17:16
Fix missing include and install OFComparable.h. check-in: 5642f16519 user: js tags: trunk
17:08
Big diff, see details. check-in: 61a6ac873a user: js tags: trunk
2009-01-24
20:28
[self alloc] isn't a good idea with the new API.
The reason is that a derived class, for example derived from OFArray,
would not return an OFArray when + arrayWithItemSize is called.
check-in: 7feac9e596 user: js tags: trunk
Changes

Modified configure.ac from [4c39ba909e] to [b86ef585ee].

38
39
40
41
42
43
44







45
46
47
48
49
50
51
		#endif], [
		AC_MSG_RESULT(yes)
		size_max="SIZE_T_MAX"], [
		AC_MSG_RESULT(no)
		size_max="((size_t)-1)"])
	AC_DEFINE_UNQUOTED(SIZE_MAX, $size_max, [Maximum value for size_t])])








AC_CHECK_FUNC(asprintf, [
	have_asprintf="yes"
	AC_DEFINE(HAVE_ASPRINTF, 1, "Whether we have asprintf")], [
	have_asprintf="no"
	AC_SUBST(ASPRINTF, "asprintf.c")])

AC_MSG_CHECKING(whether snprintf returns something useful)







>
>
>
>
>
>
>







38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
		#endif], [
		AC_MSG_RESULT(yes)
		size_max="SIZE_T_MAX"], [
		AC_MSG_RESULT(no)
		size_max="((size_t)-1)"])
	AC_DEFINE_UNQUOTED(SIZE_MAX, $size_max, [Maximum value for size_t])])

AC_CHECK_HEADER(objc/runtime.h,
	[AC_DEFINE(HAVE_OBJC_RUNTIME_H, 1, [Whether we have objc/runtime.h])])
AC_CHECK_LIB(objc, sel_get_name,
	[AC_DEFINE(HAVE_SEL_GET_NAME, 1, [Whether we have sel_get_name])])
AC_CHECK_LIB(objc, sel_getName,
	[AC_DEFINE(HAVE_SEL_GETNAME, 1, [Whether we have sel_getName])])

AC_CHECK_FUNC(asprintf, [
	have_asprintf="yes"
	AC_DEFINE(HAVE_ASPRINTF, 1, "Whether we have asprintf")], [
	have_asprintf="no"
	AC_SUBST(ASPRINTF, "asprintf.c")])

AC_MSG_CHECKING(whether snprintf returns something useful)

Modified src/OFArray.h from [0b607ebca5] to [0a9cee9129].

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 - 2009
 *   Jonathan Schleifer <js@webkeks.org>
 *
 * All rights reserved.
 *
 * This file is part of libobjfw. It may be distributed under the terms of the
 * Q Public License 1.0, which can be found in the file LICENSE included in
 * the packaging of this file.
 */

#import "OFObject.h"


/**
 * The OFArray class provides a class for storing dynamically sized arrays.
 * If you plan to store large hunks of data, you should consider using
 * OFBigArray, which allocates the memory in pages and not in bytes.
 */
@interface OFArray: OFObject
{
	char   *data;
	size_t itemsize;
	size_t items;
}

/**












>






|







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
/*
 * Copyright (c) 2008 - 2009
 *   Jonathan Schleifer <js@webkeks.org>
 *
 * All rights reserved.
 *
 * This file is part of libobjfw. It may be distributed under the terms of the
 * Q Public License 1.0, which can be found in the file LICENSE included in
 * the packaging of this file.
 */

#import "OFObject.h"
#import "OFComparable.h"

/**
 * The OFArray class provides a class for storing dynamically sized arrays.
 * If you plan to store large hunks of data, you should consider using
 * OFBigArray, which allocates the memory in pages and not in bytes.
 */
@interface OFArray: OFObject <OFComparable>
{
	char   *data;
	size_t itemsize;
	size_t items;
}

/**
94
95
96
97
98
99
100







101
102
103
104
105
106
107
108
109
110
111
112
113

/**
 * Removes a specified amount of the last items from the OFArray.
 *
 * \param nitems The number of items to remove
 */
- removeNItems: (size_t)nitems;







@end

@interface OFBigArray: OFArray
{
	size_t size;
}

- initWithItemSize: (size_t)is;
- add: (void*)item;
- addNItems: (size_t)nitems
 fromCArray: (void*)carray;
- removeNItems: (size_t)nitems;
@end







>
>
>
>
>
>
>













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

/**
 * Removes a specified amount of the last items from the OFArray.
 *
 * \param nitems The number of items to remove
 */
- removeNItems: (size_t)nitems;

/**
 * Clones the OFArray, creating a new one.
 *
 * \return A new autoreleased copy of the OFArray
 */
- (id)copy;
@end

@interface OFBigArray: OFArray
{
	size_t size;
}

- initWithItemSize: (size_t)is;
- add: (void*)item;
- addNItems: (size_t)nitems
 fromCArray: (void*)carray;
- removeNItems: (size_t)nitems;
@end

Modified src/OFArray.m from [0b15af59f1] to [99432f285e].

112
113
114
115
116
117
118

















































119
120
121
122
123
124
125
		      toNItems: items - nitems
			ofSize: itemsize];

	items -= nitems;

	return self;
}

















































@end

@implementation OFBigArray
- initWithItemSize: (size_t)is
{
	if (lastpagebyte == 0)
		lastpagebyte = getpagesize() - 1;







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







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
		      toNItems: items - nitems
			ofSize: itemsize];

	items -= nitems;

	return self;
}

- (id)copy
{
	OFArray *new = [OFArray arrayWithItemSize: itemsize];

	[new addNItems: items
	    fromCArray: data];

	return new;
}

- (BOOL)isEqual: (id)obj
{
	if (![obj isKindOf: [OFArray class]])
		return NO;
	if ([obj items] != items || [obj itemsize] != itemsize)
		return NO;
	if (memcmp([obj data], data, items * itemsize))
		return NO;

	return YES;
}

- (int)compare: (id)obj
{
	int ret;

	if (![obj isKindOf: [OFArray class]])
		@throw [OFInvalidArgumentException newWithClass: [self class]
						    andSelector: _cmd];
	if ([obj itemsize] != itemsize)
		@throw [OFInvalidArgumentException newWithClass: [self class]
						    andSelector: _cmd];

	if ([obj items] == items)
		return memcmp(data, [obj data], items * itemsize);

	if (items > [obj items]) {
		if ((ret = memcmp(data, [obj data], [obj items] * itemsize)))
			return ret;

		return *(char*)[self item: [obj items]];
	} else {
		if ((ret = memcmp(data, [obj data], items * itemsize)))
			return ret;

		return *(char*)[obj item: [self items]] * -1;
	}
}
@end

@implementation OFBigArray
- initWithItemSize: (size_t)is
{
	if (lastpagebyte == 0)
		lastpagebyte = getpagesize() - 1;
184
185
186
187
188
189
190










191
				toSize: nsize];

	items -= nitems;
	size = nsize;

	return self;
}










@end







>
>
>
>
>
>
>
>
>
>

233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
				toSize: nsize];

	items -= nitems;
	size = nsize;

	return self;
}

- (id)copy
{
	OFArray *new = [OFArray bigArrayWithItemSize: itemsize];

	[new addNItems: items
	    fromCArray: data];

	return new;
}
@end

Added src/OFComparable.h version [3f1a71329b].

































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
/*
 * Copyright (c) 2008 - 2009
 *   Jonathan Schleifer <js@webkeks.org>
 *
 * All rights reserved.
 *
 * This file is part of libobjfw. It may be distributed under the terms of the
 * Q Public License 1.0, which can be found in the file LICENSE included in
 * the packaging of this file.
 */

#import "OFObject.h"

/**
 * The OFComparable protocol provides functions to compare two objects.
 */
@protocol OFComparable
/**
 * \param obj The object which is tested for equality
 * \return A boolean whether the object is equal to the other object
 */
- (BOOL)isEqual: (id)obj;

/**
 * Compares the object to another object.
 *
 * \param obj An object to compare with
 * \return An integer which is the result of the comparison, see for example
 *	   strcmp
 */
- (int)compare: (id)obj;
@end

Modified src/OFExceptions.h from [fb7bdc037c] to [3a58ffe4f3].

115
116
117
118
119
120
121



























122
123
124
125
126
127
128

/**
 * An OFException indicating the given value is out of range.
 */
@interface OFOutOfRangeException: OFException {}
@end




























/**
 * An OFException indicating that the encoding is invalid for this object.
 */
@interface OFInvalidEncodingException: OFException {}
@end

/**







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







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

/**
 * An OFException indicating the given value is out of range.
 */
@interface OFOutOfRangeException: OFException {}
@end

/**
 * An OFException indicating that the argument is invalid for this method.
 */
@interface OFInvalidArgumentException: OFException
{
	SEL selector;
}

/**
 * \param class The class of the object which caused the exception
 * \param selector The selector which doesn't accept the argument
 * \return A new invalid argument exception
 */
+ newWithClass: (Class)class
   andSelector: (SEL)selector;

/**
 * Initializes an already allocated invalid argument exception
 *
 * \param class The class of the object which caused the exception
 * \param selector The selector which doesn't accept the argument
 * \return An initialized invalid argument exception
 */
- initWithClass: (Class)class
    andSelector: (SEL)selector;
@end

/**
 * An OFException indicating that the encoding is invalid for this object.
 */
@interface OFInvalidEncodingException: OFException {}
@end

/**

Modified src/OFExceptions.m from [1b0dd75e24] to [24b883adc0].

25
26
27
28
29
30
31
32




33








34
35
36
37
38
39
40
#else
#import <windows.h>
#define GET_ERR	     GetLastError()
#define GET_SOCK_ERR WSAGetLastError()
#define ERRFMT	     "Error code was: %d"
#define ERRPARAM     err
#endif





#import "OFExceptions.h"









#ifndef HAVE_ASPRINTF
#import "asprintf.h"
#endif

@implementation OFException
+ newWithClass: (Class)class_








>
>
>
>

>
>
>
>
>
>
>
>







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
#else
#import <windows.h>
#define GET_ERR	     GetLastError()
#define GET_SOCK_ERR WSAGetLastError()
#define ERRFMT	     "Error code was: %d"
#define ERRPARAM     err
#endif

#ifdef HAVE_OBJC_RUNTIME_H
#import <objc/runtime.h>
#endif

#import "OFExceptions.h"

#if defined(HAVE_SEL_GET_NAME)
#define SEL_NAME(x) sel_get_name(x)
#elif defined(HAVE_SEL_GETNAME)
#define SEL_NAME(x) sel_getName(x)
#else
#error "You need either sel_get_name() or sel_getName()!"
#endif

#ifndef HAVE_ASPRINTF
#import "asprintf.h"
#endif

@implementation OFException
+ newWithClass: (Class)class_
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
		return string;

	asprintf(&string, "Value out of range in class %s!", [class name]);

	return string;
}
@end






























@implementation OFInvalidEncodingException
- (const char*)cString
{
	if (string != NULL)
		return string;

	asprintf(&string, "The encoding is invalid for classs %s!",
	    [class name]);

	return string;
}
@end

@implementation OFInvalidFormatException
- (const char*)cString
{
	if (string != NULL)
		return string;

	asprintf(&string, "The format is invalid for classs %s!", [class name]);

	return string;
}
@end

@implementation OFInitializationFailedException
- (const char*)cString







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







|












|







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
		return string;

	asprintf(&string, "Value out of range in class %s!", [class name]);

	return string;
}
@end

@implementation OFInvalidArgumentException
+ newWithClass: (Class)class_
   andSelector: (SEL)selector_
{
	return [[self alloc] initWithClass: class_
			       andSelector: selector_];
}

- initWithClass: (Class)class_
    andSelector: (SEL)selector_
{
	if ((self = [super initWithClass: class_]))
		selector = selector_;

	return self;
}

- (const char*)cString
{
	if (string != NULL)
		return string;

	asprintf(&string, "The argument for method %s of class %s is invalid!",
	    SEL_NAME(selector), [class name]);

	return string;
}
@end

@implementation OFInvalidEncodingException
- (const char*)cString
{
	if (string != NULL)
		return string;

	asprintf(&string, "The encoding is invalid for class %s!",
	    [class name]);

	return string;
}
@end

@implementation OFInvalidFormatException
- (const char*)cString
{
	if (string != NULL)
		return string;

	asprintf(&string, "The format is invalid for class %s!", [class name]);

	return string;
}
@end

@implementation OFInitializationFailedException
- (const char*)cString

Modified src/OFString.h from [3f383f6fa1] to [d0143637ff].

9
10
11
12
13
14
15

16
17
18
19
20
21
22
23
24
25
26
27
 * the packaging of this file.
 */

#import <stdarg.h>
#import <stdio.h>

#import "OFObject.h"


/**
 * A class for storing and modifying strings.
 */
@interface OFString: OFObject
{
	char   *string;
	size_t length;
	BOOL   is_utf8;
}

/**







>




|







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
 * the packaging of this file.
 */

#import <stdarg.h>
#import <stdio.h>

#import "OFObject.h"
#import "OFComparable.h"

/**
 * A class for storing and modifying strings.
 */
@interface OFString: OFObject <OFComparable>
{
	char   *string;
	size_t length;
	BOOL   is_utf8;
}

/**
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
- (size_t)length;

/**
 * Clones the OFString, creating a new one.
 *
 * \return A new autoreleased copy of the OFString
 */
- (OFString*)clone;

/**
 * Sets the OFString to the specified OFString.
 *
 * \param str An OFString to set the OFString to.
 */
- setTo: (OFString*)str;

/**
 * Compares the OFString to another OFString.
 *
 * \param str An OFString to compare with
 * \return An integer which is the result of the comparison, see wcscmp
 */
- (int)compareTo: (OFString*)str;

/**
 * Append another OFString to the OFString.
 *
 * \param str An OFString to append
 */
- append: (OFString*)str;








|








<
<
<
<
<
<
<
<







104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119








120
121
122
123
124
125
126
- (size_t)length;

/**
 * Clones the OFString, creating a new one.
 *
 * \return A new autoreleased copy of the OFString
 */
- (id)copy;

/**
 * Sets the OFString to the specified OFString.
 *
 * \param str An OFString to set the OFString to.
 */
- setTo: (OFString*)str;









/**
 * Append another OFString to the OFString.
 *
 * \param str An OFString to append
 */
- append: (OFString*)str;

Modified src/OFString.m from [69097c8dd7] to [d870a955f7].

233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
}

- (size_t)length
{
	return length;
}

- (OFString*)clone
{
	return [OFString stringWithCString: string];
}

- setTo: (OFString*)str
{
	size_t len;







|







233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
}

- (size_t)length
{
	return length;
}

- (id)copy
{
	return [OFString stringWithCString: string];
}

- setTo: (OFString*)str
{
	size_t len;
266
267
268
269
270
271
272










273
274



275
276
277
278
279
280
281
282
	length = len;
	string = [self getMemWithSize: length + 1];
	memcpy(string, [str cString], length + 1);

	return self;
}











- (int)compareTo: (OFString*)str
{



	return strcmp(string, [str cString]);
}

- append: (OFString*)str
{
	return [self appendCString: [str cString]];
}








>
>
>
>
>
>
>
>
>
>
|

>
>
>
|







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
	length = len;
	string = [self getMemWithSize: length + 1];
	memcpy(string, [str cString], length + 1);

	return self;
}

- (BOOL)isEqual: (id)obj
{
	if (![obj isKindOf: [OFString class]])
		return NO;
	if (strcmp(string, [obj cString]))
		return NO;

	return YES;
}

- (int)compare: (id)obj
{
	if (![obj isKindOf: [OFString class]])
		@throw [OFInvalidArgumentException newWithClass: [self class]];

	return strcmp(string, [obj cString]);
}

- append: (OFString*)str
{
	return [self appendCString: [str cString]];
}

Modified tests/OFArray/OFArray.m from [0b1404de72] to [95c48806f0].

14
15
16
17
18
19
20

21
22
23
24
25
26
27
#import <stdio.h>
#import <stdlib.h>
#import <string.h>
#import <limits.h>

#import "OFArray.h"
#import "OFExceptions.h"


#define CATCH_EXCEPTION(code, exception)		\
	@try {						\
		code;					\
							\
		puts("NOT CAUGHT!");			\
		return 1;				\







>







14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#import <stdio.h>
#import <stdlib.h>
#import <string.h>
#import <limits.h>

#import "OFArray.h"
#import "OFExceptions.h"
#import "OFAutoreleasePool.h"

#define CATCH_EXCEPTION(code, exception)		\
	@try {						\
		code;					\
							\
		puts("NOT CAUGHT!");			\
		return 1;				\
113
114
115
116
117
118
119


120
121
122
123
124
125
126









































127
128

int
main()
{
	id a;
	void *p, *q;
	size_t i;



	puts("== TESTING OFArray ==");
	TEST(OFArray)

	puts("== TESTING OFBigArray ==");
	TEST(OFBigArray)










































	return 0;
}







>
>







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


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

int
main()
{
	id a;
	void *p, *q;
	size_t i;
	OFArray *x, *y;
	OFAutoreleasePool *pool;

	puts("== TESTING OFArray ==");
	TEST(OFArray)

	puts("== TESTING OFBigArray ==");
	TEST(OFBigArray)

	pool = [OFAutoreleasePool new];
	x = [OFArray arrayWithItemSize: 1];
	y = [OFArray bigArrayWithItemSize: 1];

	if (![x isEqual: y]) {
		puts("FAIL 1!");
		return 1;
	}

	[x add: "x"];
	if ([x isEqual: y]) {
		puts("FAIL 2!");
		return 2;
	}
	[pool releaseObjects];

	x = [OFArray arrayWithItemSize: 2];
	y = [OFArray bigArrayWithItemSize: 4];

	if ([x isEqual: y]) {
		puts("FAIL 3!");
		return 1;
	}
	[pool releaseObjects];

	x = [OFArray arrayWithItemSize: 1];
	[x addNItems: 3
	  fromCArray: "abc"];
	y = [x copy];
	if ([x compare: y]) {
		puts("FAIL 4!");
		return 1;
	}

	[y add: "de"];
	if ([x compare: y] != -100) {
		puts("FAIL 5!");
		return 1;
	}
	[pool release];

	return 0;
}

Modified tests/OFString/OFString.m from [ffc025b2b3] to [d1e8e561ed].

21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

#ifndef _WIN32
#define ZD "%zd"
#else
#define ZD "%u"
#endif

#define NUM_TESTS 12
#define SUCCESS								\
	printf("\r\033[1;%dmTests successful: " ZD "/%d\033[0m",	\
	    (i == NUM_TESTS - 1 ? 32 : 33), i + 1, NUM_TESTS);		\
	fflush(stdout);
#define FAIL								\
	printf("\r\033[K\033[1;31mTest " ZD "/%d failed!\033[m\n",	\
	    i + 1, NUM_TESTS);						\







|







21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

#ifndef _WIN32
#define ZD "%zd"
#else
#define ZD "%u"
#endif

#define NUM_TESTS 13
#define SUCCESS								\
	printf("\r\033[1;%dmTests successful: " ZD "/%d\033[0m",	\
	    (i == NUM_TESTS - 1 ? 32 : 33), i + 1, NUM_TESTS);		\
	fflush(stdout);
#define FAIL								\
	printf("\r\033[K\033[1;31mTest " ZD "/%d failed!\033[m\n",	\
	    i + 1, NUM_TESTS);						\
57
58
59
60
61
62
63
64
65

66
67
68
69
70
71
72
73
74
75
76
77
78

	OFAutoreleasePool *pool = [OFAutoreleasePool new];
	OFString *s1 = [OFString stringWithCString: "test"];
	OFString *s2 = [OFString stringWithCString: ""];
	OFString *s3;
	OFString *s4 = [OFString string];

	s3 = [s1 clone];


	CHECK(![s1 compareTo: s3])

	[s2 appendCString: "123"];
	[s4 setTo: s2];

	CHECK(![s2 compareTo: s4])
	CHECK(!strcmp([[s1 append: s2] cString], "test123"))
	CHECK(strlen([s1 cString]) == [s1 length] && [s1 length] == 7)
	CHECK(!strcmp([[s1 reverse] cString], "321tset"))
	CHECK(!strcmp([[s1 upper] cString], "321TSET"))
	CHECK(!strcmp([[s1 lower] cString], "321tset"))

	/* Also clears all the memory of the returned C strings */







|

>
|




|







57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79

	OFAutoreleasePool *pool = [OFAutoreleasePool new];
	OFString *s1 = [OFString stringWithCString: "test"];
	OFString *s2 = [OFString stringWithCString: ""];
	OFString *s3;
	OFString *s4 = [OFString string];

	s3 = [s1 copy];

	CHECK([s1 isEqual: s3])
	CHECK(![s1 isEqual: [OFObject new]]);

	[s2 appendCString: "123"];
	[s4 setTo: s2];

	CHECK(![s2 compare: s4])
	CHECK(!strcmp([[s1 append: s2] cString], "test123"))
	CHECK(strlen([s1 cString]) == [s1 length] && [s1 length] == 7)
	CHECK(!strcmp([[s1 reverse] cString], "321tset"))
	CHECK(!strcmp([[s1 upper] cString], "321TSET"))
	CHECK(!strcmp([[s1 lower] cString], "321tset"))

	/* Also clears all the memory of the returned C strings */