ObjFW  Check-in [a29d403286]

Overview
Comment:A few renames in OFArray, OFDataArray and OFDictionary.

OFArray:
* Rename - object: to - objectAtIndex:.

OFDataArray:
* Rename - item: to - itemAtIndex:.

OFDictionary:
* Rename - get: to - objectForKey:.
* Rename - set:to: to - setObject:forKey:.
* Rename - remove: to - removeObjectForKey:.

Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: a29d403286face48d05696809940f5b24d6cafe0ea62c6a8474b7f7e7522a503
User & Date: js on 2009-05-23 16:50:44
Other Links: manifest | tags
Context
2009-05-23
20:32
Fix splitWithDelimiter:. check-in: cabf6ee9e7 user: js tags: trunk
16:50
A few renames in OFArray, OFDataArray and OFDictionary. check-in: a29d403286 user: js tags: trunk
01:59
Prevent + initialize from being called twice. check-in: e0163c30a9 user: js tags: trunk
Changes

Modified src/OFArray.h from [c8ae639320] to [74b613ec1f].

91
92
93
94
95
96
97
98
99
100
101
102
103
104
105

/**
 * Returns a specific object of the OFDataArray.
 *
 * \param index The number of the object to return
 * \return The specified object of the OFArray
 */
- (id)object: (size_t)index;

/**
 * \return The last object of the OFDataArray
 */
- (id)last;

/**







|







91
92
93
94
95
96
97
98
99
100
101
102
103
104
105

/**
 * Returns a specific object of the OFDataArray.
 *
 * \param index The number of the object to return
 * \return The specified object of the OFArray
 */
- (id)objectAtIndex: (size_t)index;

/**
 * \return The last object of the OFDataArray
 */
- (id)last;

/**

Modified src/OFArray.m from [47830eac24] to [dbe234c97f].

162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178

	for (i = 0; i < len; i++)
		[objs[i] retain];

	return new;
}

- (id)object: (size_t)index
{
	return *((OFObject**)[array item: index]);
}

- (id)last
{
	return *((OFObject**)[array last]);
}








|

|







162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178

	for (i = 0; i < len; i++)
		[objs[i] retain];

	return new;
}

- (id)objectAtIndex: (size_t)index
{
	return *((OFObject**)[array itemAtIndex: index]);
}

- (id)last
{
	return *((OFObject**)[array last]);
}

Modified src/OFDataArray.h from [1afd404279] to [2aac6c3e48].

68
69
70
71
72
73
74
75
76
77
78
79
80
81
82

/**
 * Returns a specific item of the OFDataArray.
 *
 * \param index The number of the item to return
 * \return The specified item of the OFDataArray
 */
- (void*)item: (size_t)index;

/**
 * \return The last item of the OFDataArray
 */
- (void*)last;

/**







|







68
69
70
71
72
73
74
75
76
77
78
79
80
81
82

/**
 * Returns a specific item of the OFDataArray.
 *
 * \param index The number of the item to return
 * \return The specified item of the OFDataArray
 */
- (void*)itemAtIndex: (size_t)index;

/**
 * \return The last item of the OFDataArray
 */
- (void*)last;

/**

Modified src/OFDataArray.m from [589715e608] to [2e56b1156a].

59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
}

- (void*)data
{
	return data;
}

- (void*)item: (size_t)index
{
	if (index >= count)
		@throw [OFOutOfRangeException newWithClass: isa];

	return data + index * itemsize;
}








|







59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
}

- (void*)data
{
	return data;
}

- (void*)itemAtIndex: (size_t)index
{
	if (index >= count)
		@throw [OFOutOfRangeException newWithClass: isa];

	return data + index * itemsize;
}

155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
	if ([obj count] == count)
		return memcmp(data, [obj data], count * itemsize);

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

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

		return *(char*)[obj item: count] * -1;
	}
}

- (uint32_t)hash
{
	uint32_t hash;
	size_t i;







|




|







155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
	if ([obj count] == count)
		return memcmp(data, [obj data], count * itemsize);

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

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

		return *(char*)[obj itemAtIndex: count] * -1;
	}
}

- (uint32_t)hash
{
	uint32_t hash;
	size_t i;

Modified src/OFDictionary.h from [315f04accc] to [12bb9cf14f].

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
 */
- (float)averageItemsPerBucket;

/**
 * \param key The key whose object should be returned
 * \return The object for the given key or nil if the key was not found
 */
- (id)get: (OFObject*)key;

/**
 * Sets a key to an object. A key can be any object.
 *
 * \param key The key to set
 * \param obj The object to set the key to
 */

- set: (OFObject <OFCopying>*)key
   to: (OFObject*)obj;

/**
 * Remove the object with the given key from the dictionary.
 *
 * \param key The key whose object should be removed
 */
- remove: (OFObject*)key;

/**
 * Changes the hash size of the dictionary.
 *
 * \param hashsize The new hash size for the dictionary
 */
- changeHashSize: (int)hashsize;
@end

#import "OFIterator.h"
#import "OFMutableDictionary.h"







|







>
|
<






|











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
 */
- (float)averageItemsPerBucket;

/**
 * \param key The key whose object should be returned
 * \return The object for the given key or nil if the key was not found
 */
- (id)objectForKey: (OFObject*)key;

/**
 * Sets a key to an object. A key can be any object.
 *
 * \param key The key to set
 * \param obj The object to set the key to
 */
- setObject: (OFObject*)obj
     forKey: (OFObject <OFCopying>*)key;


/**
 * Remove the object with the given key from the dictionary.
 *
 * \param key The key whose object should be removed
 */
- removeObjectForKey: (OFObject*)key;

/**
 * Changes the hash size of the dictionary.
 *
 * \param hashsize The new hash size for the dictionary
 */
- changeHashSize: (int)hashsize;
@end

#import "OFIterator.h"
#import "OFMutableDictionary.h"

Modified src/OFDictionary.m from [921468f6aa] to [232cbc945d].

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
			buckets++;
		}
	}

	return (float)items / buckets;
}

- (id)get: (OFObject*)key
{
	uint32_t hash;
	of_list_object_t *iter;

	if (key == nil)
		@throw [OFInvalidArgumentException newWithClass: isa
						    andSelector: _cmd];

	hash = [key hash] & (size - 1);

	if (data[hash] == nil)
		return nil;

	for (iter = [data[hash] first]; iter != NULL; iter = iter->next->next)
		if ([iter->object isEqual: key])
			return iter->next->object;

	return nil;
}


- set: (OFObject <OFCopying>*)key
   to: (OFObject*)obj
{
	@throw [OFNotImplementedException newWithClass: isa
					   andSelector: _cmd];
}

- remove: (OFObject*)key
{
	@throw [OFNotImplementedException newWithClass: isa
					   andSelector: _cmd];
}

- changeHashSize: (int)hashsize
{







|




















>
|
<





|







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
			buckets++;
		}
	}

	return (float)items / buckets;
}

- (id)objectForKey: (OFObject*)key
{
	uint32_t hash;
	of_list_object_t *iter;

	if (key == nil)
		@throw [OFInvalidArgumentException newWithClass: isa
						    andSelector: _cmd];

	hash = [key hash] & (size - 1);

	if (data[hash] == nil)
		return nil;

	for (iter = [data[hash] first]; iter != NULL; iter = iter->next->next)
		if ([iter->object isEqual: key])
			return iter->next->object;

	return nil;
}

- setObject: (OFObject*)obj
     forKey: (OFObject <OFCopying>*)key

{
	@throw [OFNotImplementedException newWithClass: isa
					   andSelector: _cmd];
}

- removeObjectForKey: (OFObject*)key
{
	@throw [OFNotImplementedException newWithClass: isa
					   andSelector: _cmd];
}

- changeHashSize: (int)hashsize
{

Modified src/OFMutableDictionary.m from [8ea4251805] to [da30bcc8d4].

14
15
16
17
18
19
20

21
22
23
24
25
26
27
28
29
#include <string.h>

#import "OFMutableDictionary.h"
#import "OFExceptions.h"
#import "OFMacros.h"

@implementation OFMutableDictionary

- set: (OFObject <OFCopying>*)key
   to: (OFObject*)obj
{
	uint32_t hash;
	of_list_object_t *iter, *key_obj;

	if (key == nil || obj == nil)
		@throw [OFInvalidArgumentException newWithClass: isa
						    andSelector: _cmd];







>
|
<







14
15
16
17
18
19
20
21
22

23
24
25
26
27
28
29
#include <string.h>

#import "OFMutableDictionary.h"
#import "OFExceptions.h"
#import "OFMacros.h"

@implementation OFMutableDictionary
- setObject: (OFObject*)obj
     forKey: (OFObject <OFCopying>*)key

{
	uint32_t hash;
	of_list_object_t *iter, *key_obj;

	if (key == nil || obj == nil)
		@throw [OFInvalidArgumentException newWithClass: isa
						    andSelector: _cmd];
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
		[data[hash] remove: key_obj];
		@throw e;
	}

	return self;
}

- remove: (OFObject*)key
{
	uint32_t hash;
	of_list_object_t *iter;

	if (key == nil)
		@throw [OFInvalidArgumentException newWithClass: isa
						    andSelector: _cmd];







|







56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
		[data[hash] remove: key_obj];
		@throw e;
	}

	return self;
}

- removeObjectForKey: (OFObject*)key
{
	uint32_t hash;
	of_list_object_t *iter;

	if (key == nil)
		@throw [OFInvalidArgumentException newWithClass: isa
						    andSelector: _cmd];

Modified tests/OFArray/OFArray.m from [693a970af9] to [3882b8f32d].

59
60
61
62
63
64
65
66
67
68
69
70
	[b add: @"Baz"];
	assert([a isEqual: b]);

	[b removeNObjects: 1];
	[b add: @"Qux"];
	assert(![a isEqual: b]);

	CATCH_EXCEPTION([a object: 3], OFOutOfRangeException)
	CATCH_EXCEPTION([a add: @"foo"], OFNotImplementedException)

	return 0;
}







|




59
60
61
62
63
64
65
66
67
68
69
70
	[b add: @"Baz"];
	assert([a isEqual: b]);

	[b removeNObjects: 1];
	[b add: @"Qux"];
	assert(![a isEqual: b]);

	CATCH_EXCEPTION([a objectAtIndex: 3], OFOutOfRangeException)
	CATCH_EXCEPTION([a add: @"foo"], OFNotImplementedException)

	return 0;
}

Modified tests/OFDataArray/OFDataArray.m from [a5da935c08] to [6aad159bdb].

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
	[a freeMem: q];							\
									\
	puts("Adding multiple items at once...");			\
	p = [a allocWithSize: 8192];					\
	memset(p, 64, 8192);						\
	[a addNItems: 2							\
	  fromCArray: p];						\
	if (!memcmp([a last], [a item: [a count] - 2], 4096) &&		\
	    !memcmp([a item: [a count] - 2], p, 4096))			\
		puts("[a last], [a item: [a count] - 2] and p match!");	\

	else {								\
		puts("[a last], [a item: [a count] - 2] and p did not match!");\

		abort();						\
	}								\
	[a freeMem: p];							\
									\
	i = [a count];							\
	puts("Removing 2 items...");					\
	[a removeNItems: 2];						\
	if ([a count] + 2 != i) {					\
		puts("[a count] + 2 != i!");				\
		abort();						\
	}								\
									\
	puts("Trying to remove more data than we added...");		\
	CATCH_EXCEPTION([a removeNItems: [a count] + 1],		\
	    OFOutOfRangeException);					\
									\
	puts("Trying to access an index that does not exist...");	\

	CATCH_EXCEPTION([a item: [a count]], OFOutOfRangeException);	\
									\
	[a release];							\
									\
	puts("Creating new array and using it to build a string...");	\
	a = [[type alloc] initWithItemSize: 1];				\
									\
	for (i = 0; i < strlen(str); i++)				\







|
|
|
>

|
>

















>
|







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
	[a freeMem: q];							\
									\
	puts("Adding multiple items at once...");			\
	p = [a allocWithSize: 8192];					\
	memset(p, 64, 8192);						\
	[a addNItems: 2							\
	  fromCArray: p];						\
	if (!memcmp([a last], [a itemAtIndex: [a count] - 2], 4096) &&	\
	    !memcmp([a itemAtIndex: [a count] - 2], p, 4096))		\
		puts("[a last], [a itemAtIndex: [a count] - 2] and p "	\
		    "match!");						\
	else {								\
		puts("[a last], [a itemAtIndex: [a count] - 2] and p "	\
		    "do not match!");					\
		abort();						\
	}								\
	[a freeMem: p];							\
									\
	i = [a count];							\
	puts("Removing 2 items...");					\
	[a removeNItems: 2];						\
	if ([a count] + 2 != i) {					\
		puts("[a count] + 2 != i!");				\
		abort();						\
	}								\
									\
	puts("Trying to remove more data than we added...");		\
	CATCH_EXCEPTION([a removeNItems: [a count] + 1],		\
	    OFOutOfRangeException);					\
									\
	puts("Trying to access an index that does not exist...");	\
	CATCH_EXCEPTION([a itemAtIndex: [a count]],			\
	    OFOutOfRangeException);					\
									\
	[a release];							\
									\
	puts("Creating new array and using it to build a string...");	\
	a = [[type alloc] initWithItemSize: 1];				\
									\
	for (i = 0; i < strlen(str); i++)				\

Modified tests/OFDictionary/OFDictionary.m from [ba48f04406] to [1070e23922].

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

	OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init];
	OFString *key1 = [OFString stringWithCString: "key1"];
	OFString *key2 = [OFString stringWithCString: "key2"];
	OFString *value1 = [OFString stringWithCString: "value1"];
	OFString *value2 = [OFString stringWithCString: "value2"];

	[dict set: key1
	       to: value1];
	[dict set: key2
	       to: value2];
	[pool release];

	i++;
	if (strcmp([[dict get: @"key1"] cString], "value1")) {
		printf("\033[K\033[1;31mTest %d/%d failed!\033[m\n", i, TESTS);
		return 1;
	}

	i++;
	if (strcmp([[dict get: key2] cString], "value2")) {
		printf("\033[K\033[1;31mTest %d/%d failed!\033[m\n", i, TESTS);
		return 1;
	}

	i++;
	if (![[iter nextObject] isEqual: @"key2"] ||
	    ![[iter nextObject] isEqual: @"value2"] ||







|
|
|
|



|





|







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

	OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init];
	OFString *key1 = [OFString stringWithCString: "key1"];
	OFString *key2 = [OFString stringWithCString: "key2"];
	OFString *value1 = [OFString stringWithCString: "value1"];
	OFString *value2 = [OFString stringWithCString: "value2"];

	[dict setObject: value1
		 forKey: key1];
	[dict setObject: value2
		 forKey: key2];
	[pool release];

	i++;
	if (strcmp([[dict objectForKey: @"key1"] cString], "value1")) {
		printf("\033[K\033[1;31mTest %d/%d failed!\033[m\n", i, TESTS);
		return 1;
	}

	i++;
	if (strcmp([[dict objectForKey: key2] cString], "value2")) {
		printf("\033[K\033[1;31mTest %d/%d failed!\033[m\n", i, TESTS);
		return 1;
	}

	i++;
	if (![[iter nextObject] isEqual: @"key2"] ||
	    ![[iter nextObject] isEqual: @"value2"] ||
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
	i++;
	if ([iter nextObject] != nil) {
		printf("\033[K\033[1;31mTest %d/%d failed!\033[m\n", i, TESTS);
		return 1;
	}

	i++;
	if ([dict get: @"key3"] != nil) {
		printf("\033[K\033[1;31mTest %d/%d failed!\033[m\n", i, TESTS);
		return 1;
	}

	i++;
	[dict release];
	dict = [OFDictionary dictionaryWithKeysAndObjects: @"foo", @"bar",
							    @"baz", @"qux",
							    nil];

	if (![[dict get: @"foo"] isEqual: @"bar"]) {
		printf("\033[K\033[1;31mTest %d/%d failed!\033[m\n", i, TESTS);
		return 1;
	}

	i++;
	if (![[dict get: @"baz"] isEqual: @"qux"]) {
		printf("\033[K\033[1;31mTest %d/%d failed!\033[m\n", i, TESTS);
		return 1;
	}

	i++;
	[dict release];
	dict = [OFDictionary dictionaryWithKey: @"foo"
				     andObject: @"bar"];
	if (![[dict get: @"foo"] isEqual: @"bar"]) {
		printf("\033[K\033[1;31mTest %d/%d failed!\033[m\n", i, TESTS);
		return 1;
	}

	i++;
	[dict release];
	dict = [OFDictionary
	    dictionaryWithKeys: [OFArray arrayWithObjects: @"k1", @"k2", nil]
		    andObjects: [OFArray arrayWithObjects: @"o1", @"o2", nil]];
	if (![[dict get: @"k1"] isEqual: @"o1"]) {
		printf("\033[K\033[1;31mTest %d/%d failed!\033[m\n", i, TESTS);
		return 1;
	}

	i++;
	if (![[dict get: @"k2"] isEqual: @"o2"]) {
		printf("\033[K\033[1;31mTest %d/%d failed!\033[m\n", i, TESTS);
		return 1;
	}

	printf("\033[1;32mTests successful: %d/%d\033[0m\n", i, TESTS);

	return 0;
}







|










|





|








|









|





|








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
	i++;
	if ([iter nextObject] != nil) {
		printf("\033[K\033[1;31mTest %d/%d failed!\033[m\n", i, TESTS);
		return 1;
	}

	i++;
	if ([dict objectForKey: @"key3"] != nil) {
		printf("\033[K\033[1;31mTest %d/%d failed!\033[m\n", i, TESTS);
		return 1;
	}

	i++;
	[dict release];
	dict = [OFDictionary dictionaryWithKeysAndObjects: @"foo", @"bar",
							    @"baz", @"qux",
							    nil];

	if (![[dict objectForKey: @"foo"] isEqual: @"bar"]) {
		printf("\033[K\033[1;31mTest %d/%d failed!\033[m\n", i, TESTS);
		return 1;
	}

	i++;
	if (![[dict objectForKey: @"baz"] isEqual: @"qux"]) {
		printf("\033[K\033[1;31mTest %d/%d failed!\033[m\n", i, TESTS);
		return 1;
	}

	i++;
	[dict release];
	dict = [OFDictionary dictionaryWithKey: @"foo"
				     andObject: @"bar"];
	if (![[dict objectForKey: @"foo"] isEqual: @"bar"]) {
		printf("\033[K\033[1;31mTest %d/%d failed!\033[m\n", i, TESTS);
		return 1;
	}

	i++;
	[dict release];
	dict = [OFDictionary
	    dictionaryWithKeys: [OFArray arrayWithObjects: @"k1", @"k2", nil]
		    andObjects: [OFArray arrayWithObjects: @"o1", @"o2", nil]];
	if (![[dict objectForKey: @"k1"] isEqual: @"o1"]) {
		printf("\033[K\033[1;31mTest %d/%d failed!\033[m\n", i, TESTS);
		return 1;
	}

	i++;
	if (![[dict objectForKey: @"k2"] isEqual: @"o2"]) {
		printf("\033[K\033[1;31mTest %d/%d failed!\033[m\n", i, TESTS);
		return 1;
	}

	printf("\033[1;32mTests successful: %d/%d\033[0m\n", i, TESTS);

	return 0;
}

Modified tests/OFString/OFString.m from [203f97552a] to [c6f6b5b983].

98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
	s1 = [OFMutableString stringWithFormat: @"%s: %d", "test", 123];
	CHECK(!strcmp([s1 cString], "test: 123"))

	[s1 appendWithFormat: @"%02X", 15];
	CHECK(!strcmp([s1 cString], "test: 1230F"))

	a = [@"fooXXbarXXXXbazXXXX" splitWithDelimiter: @"XX"];
	CHECK([[a object: j++] isEqual: @"foo"])
	CHECK([[a object: j++] isEqual: @"bar"])
	CHECK([[a object: j++] isEqual: @""])
	CHECK([[a object: j++] isEqual: @"baz"])
	CHECK([[a object: j++] isEqual: @""])
	CHECK([[a object: j++] isEqual: @""])

	CHECK([[@"foo\"ba'_$" urlencode] isEqual: @"foo%22ba%27_%24"])
	CHECK([[@"foo%20bar%22%24" urldecode] isEqual: @"foo bar\"$"])
	CHECK_EXCEPT([@"foo%bar" urldecode], OFInvalidEncodingException)
	CHECK_EXCEPT([@"foo%FFbar" urldecode], OFInvalidEncodingException)

	puts("");

	return 0;
}







|
|
|
|
|
|










98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
	s1 = [OFMutableString stringWithFormat: @"%s: %d", "test", 123];
	CHECK(!strcmp([s1 cString], "test: 123"))

	[s1 appendWithFormat: @"%02X", 15];
	CHECK(!strcmp([s1 cString], "test: 1230F"))

	a = [@"fooXXbarXXXXbazXXXX" splitWithDelimiter: @"XX"];
	CHECK([[a objectAtIndex: j++] isEqual: @"foo"])
	CHECK([[a objectAtIndex: j++] isEqual: @"bar"])
	CHECK([[a objectAtIndex: j++] isEqual: @""])
	CHECK([[a objectAtIndex: j++] isEqual: @"baz"])
	CHECK([[a objectAtIndex: j++] isEqual: @""])
	CHECK([[a objectAtIndex: j++] isEqual: @""])

	CHECK([[@"foo\"ba'_$" urlencode] isEqual: @"foo%22ba%27_%24"])
	CHECK([[@"foo%20bar%22%24" urldecode] isEqual: @"foo bar\"$"])
	CHECK_EXCEPT([@"foo%bar" urldecode], OFInvalidEncodingException)
	CHECK_EXCEPT([@"foo%FFbar" urldecode], OFInvalidEncodingException)

	puts("");

	return 0;
}