summaryrefslogtreecommitdiff
path: root/indra/llcorehttp/tests/test_httpheaders.hpp
blob: c05f1d9429ceddb82c2d2870e4129d21dc2c2cc8 (plain)
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
/** 
 * @file test_httpheaders.hpp
 * @brief unit tests for the LLCore::HttpHeaders class
 *
 * $LicenseInfo:firstyear=2012&license=viewerlgpl$
 * Second Life Viewer Source Code
 * Copyright (C) 2012-2013, Linden Research, Inc.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation;
 * version 2.1 of the License only.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 * $/LicenseInfo$
 */
#ifndef TEST_LLCORE_HTTP_HEADERS_H_
#define TEST_LLCORE_HTTP_HEADERS_H_

#include "httpheaders.h"

#include <iostream>

#include "test_allocator.h"


using namespace LLCoreInt;


namespace tut
{

struct HttpHeadersTestData
{
	// the test objects inherit from this so the member functions and variables
	// can be referenced directly inside of the test functions.
	size_t mMemTotal;
};

typedef test_group<HttpHeadersTestData> HttpHeadersTestGroupType;
typedef HttpHeadersTestGroupType::object HttpHeadersTestObjectType;
HttpHeadersTestGroupType HttpHeadersTestGroup("HttpHeaders Tests");

template <> template <>
void HttpHeadersTestObjectType::test<1>()
{
	set_test_name("HttpHeaders construction");

	// record the total amount of dynamically allocated memory
	mMemTotal = GetMemTotal();

	// create a new ref counted object with an implicit reference
	HttpHeaders::ptr_t headers = HttpHeaders::ptr_t(new HttpHeaders());
	ensure("Memory being used", mMemTotal < GetMemTotal());
	ensure("Nothing in headers", 0 == headers->size());

	// release the implicit reference, causing the object to be released
    headers.reset();

	// make sure we didn't leak any memory
	ensure(mMemTotal == GetMemTotal());
}

template <> template <>
void HttpHeadersTestObjectType::test<2>()
{
	set_test_name("HttpHeaders construction");

	// record the total amount of dynamically allocated memory
	mMemTotal = GetMemTotal();

	// create a new ref counted object with an implicit reference
	HttpHeaders::ptr_t headers = HttpHeaders::ptr_t(new HttpHeaders());
	
	{
		// Append a few strings
		std::string str1n("Pragma");
		std::string str1v("");
		headers->append(str1n, str1v);
		std::string str2n("Accept");
		std::string str2v("application/json");
		headers->append(str2n, str2v);
	
		ensure("Headers retained", 2 == headers->size());
		HttpHeaders::container_t & c(headers->getContainerTESTONLY());
		
		ensure("First name is first name", c[0].first == str1n);
		ensure("First value is first value", c[0].second == str1v);
		ensure("Second name is second name", c[1].first == str2n);
		ensure("Second value is second value", c[1].second == str2v);
	}
	
	// release the implicit reference, causing the object to be released
    headers.reset();

	// make sure we didn't leak any memory
	ensure(mMemTotal == GetMemTotal());
}

template <> template <>
void HttpHeadersTestObjectType::test<3>()
{
	set_test_name("HttpHeaders basic find");

	// record the total amount of dynamically allocated memory
	mMemTotal = GetMemTotal();

	// create a new ref counted object with an implicit reference
	HttpHeaders::ptr_t headers = HttpHeaders::ptr_t(new HttpHeaders());
	
	{
		// Append a few strings
		std::string str1n("Uno");
		std::string str1v("1");
		headers->append(str1n, str1v);
		std::string str2n("doS");
		std::string str2v("2-2-2-2");
		headers->append(str2n, str2v);
		std::string str3n("TRES");
		std::string str3v("trois gymnopedie");
		headers->append(str3n, str3v);
	
		ensure("Headers retained", 3 == headers->size());

		const std::string * result(NULL);

		// Find a header
		result = headers->find("TRES");
		ensure("Found the last item", result != NULL);
		ensure("Last item is a nice", result != NULL && str3v == *result);

		// appends above are raw and find is case sensitive
		result = headers->find("TReS");
		ensure("Last item not found due to case", result == NULL);

		result = headers->find("TRE");
		ensure("Last item not found due to prefixing (1)", result == NULL);

		result = headers->find("TRESS");
		ensure("Last item not found due to prefixing (2)", result == NULL);
	}
	
	// release the implicit reference, causing the object to be released
    headers.reset();

	// make sure we didn't leak any memory
	ensure(mMemTotal == GetMemTotal());
}

template <> template <>
void HttpHeadersTestObjectType::test<4>()
{
	set_test_name("HttpHeaders normalized header entry");

	// record the total amount of dynamically allocated memory
	mMemTotal = GetMemTotal();

	// create a new ref counted object with an implicit reference
    HttpHeaders::ptr_t headers = HttpHeaders::ptr_t(new HttpHeaders());

	{
		static char line1[] = " AcCePT : image/yourfacehere";
		static char line1v[] = "image/yourfacehere";
		headers->appendNormal(line1, sizeof(line1) - 1);
		
		ensure("First append worked in some fashion", 1 == headers->size());

		const std::string * result(NULL);

		// Find a header
		result = headers->find("accept");
		ensure("Found 'accept'", result != NULL);
		ensure("accept value has face", result != NULL && *result == line1v);

		// Left-clean on value
		static char line2[] = " next : \t\tlinejunk \t";
		headers->appendNormal(line2, sizeof(line2) - 1);
		ensure("Second append worked", 2 == headers->size());
		result = headers->find("next");
		ensure("Found 'next'", result != NULL);
		ensure("next value is left-clean", result != NULL &&
			   *result == "linejunk \t");

		// First value unmolested
		result = headers->find("accept");
		ensure("Found 'accept' again", result != NULL);
		ensure("accept value has face", result != NULL && *result == line1v);

		// Colons in value are okay
		static char line3[] = "FancY-PANTs::plop:-neuf-=vleem=";
		static char line3v[] = ":plop:-neuf-=vleem=";
		headers->appendNormal(line3, sizeof(line3) - 1);
		ensure("Third append worked", 3 == headers->size());
		result = headers->find("fancy-pants");
		ensure("Found 'fancy-pants'", result != NULL);
		ensure("fancy-pants value has colons", result != NULL && *result == line3v);

		// Zero-length value
		static char line4[] = "all-talk-no-walk:";
		headers->appendNormal(line4, sizeof(line4) - 1);
		ensure("Fourth append worked", 4 == headers->size());
		result = headers->find("all-talk-no-walk");
		ensure("Found 'all-talk'", result != NULL);
		ensure("al-talk value is zero-length", result != NULL && result->size() == 0);

		// Zero-length name
		static char line5[] = ":all-talk-no-walk";
		static char line5v[] = "all-talk-no-walk";
		headers->appendNormal(line5, sizeof(line5) - 1);
		ensure("Fifth append worked", 5 == headers->size());
		result = headers->find("");
		ensure("Found no-name", result != NULL);
		ensure("no-name value is something", result != NULL && *result == line5v);

		// Lone colon is still something
		headers->clear();
		static char line6[] = "  :";
		headers->appendNormal(line6, sizeof(line6) - 1);
		ensure("Sixth append worked", 1 == headers->size());
		result = headers->find("");
		ensure("Found 2nd no-name", result != NULL);
		ensure("2nd no-name value is nothing", result != NULL && result->size() == 0);

		// Line without colons is taken as-is and unstripped in name
		static char line7[] = " \toskdgioasdghaosdghoowg28342908tg8902hg0hwedfhqew890v7qh0wdebv78q0wdevbhq>?M>BNM<ZV>?NZ? \t";
		headers->appendNormal(line7, sizeof(line7) - 1);
		ensure("Seventh append worked", 2 == headers->size());
		result = headers->find(line7);
		ensure("Found whatsit line", result != NULL);
		ensure("Whatsit line has no value", result != NULL && result->size() == 0);

		// Normaling interface heeds the byte count, doesn't look for NUL-terminator
		static char line8[] = "binary:ignorestuffontheendofthis";
		headers->appendNormal(line8, 13);
		ensure("Eighth append worked", 3 == headers->size());
		result = headers->find("binary");
		ensure("Found 'binary'", result != NULL);
		ensure("binary value was limited to 'ignore'", result != NULL &&
			   *result == "ignore");

	}
	
	// release the implicit reference, causing the object to be released
    headers.reset();

	// make sure we didn't leak any memory
	ensure(mMemTotal == GetMemTotal());
}

// Verify forward iterator finds everything as expected
template <> template <>
void HttpHeadersTestObjectType::test<5>()
{
	set_test_name("HttpHeaders iterator tests");

	// record the total amount of dynamically allocated memory
	mMemTotal = GetMemTotal();

	// create a new ref counted object with an implicit reference
    HttpHeaders::ptr_t headers = HttpHeaders::ptr_t(new HttpHeaders());

	HttpHeaders::iterator end(headers->end()), begin(headers->begin());
	ensure("Empty container has equal begin/end const iterators", end == begin);
	HttpHeaders::const_iterator cend(headers->end()), cbegin(headers->begin());
	ensure("Empty container has equal rbegin/rend const iterators", cend == cbegin);

	ensure("Empty container has equal begin/end iterators", headers->end() == headers->begin());
	
	{
		static char line1[] = " AcCePT : image/yourfacehere";
		static char line1v[] = "image/yourfacehere";
		headers->appendNormal(line1, sizeof(line1) - 1);

		static char line2[] = " next : \t\tlinejunk \t";
		static char line2v[] = "linejunk \t";
		headers->appendNormal(line2, sizeof(line2) - 1);

		static char line3[] = "FancY-PANTs::plop:-neuf-=vleem=";
		static char line3v[] = ":plop:-neuf-=vleem=";
		headers->appendNormal(line3, sizeof(line3) - 1);

		static char line4[] = "all-talk-no-walk:";
		static char line4v[] = "";
		headers->appendNormal(line4, sizeof(line4) - 1);

		static char line5[] = ":all-talk-no-walk";
		static char line5v[] = "all-talk-no-walk";
		headers->appendNormal(line5, sizeof(line5) - 1);

		static char line6[] = "  :";
		static char line6v[] = "";
		headers->appendNormal(line6, sizeof(line6) - 1);

		ensure("All entries accounted for", 6 == headers->size());

		static char * values[] = {
			line1v,
			line2v,
			line3v,
			line4v,
			line5v,
			line6v
		};
			
		int i(0);
		HttpHeaders::const_iterator cend(headers->end());
		for (HttpHeaders::const_iterator it(headers->begin());
			 cend != it;
			 ++it, ++i)
		{
			std::ostringstream str;
			str << "Const Iterator value # " << i << " was " << values[i];
			ensure(str.str(), (*it).second == values[i]);
		}

		// Rewind, do non-consts
		i = 0;
		HttpHeaders::iterator end(headers->end());
		for (HttpHeaders::iterator it(headers->begin());
			 end != it;
			 ++it, ++i)
		{
			std::ostringstream str;
			str << "Const Iterator value # " << i << " was " << values[i];
			ensure(str.str(), (*it).second == values[i]);
		}
	}
	
	// release the implicit reference, causing the object to be released
    headers.reset();

	// make sure we didn't leak any memory
	ensure(mMemTotal == GetMemTotal());
}

// Reverse iterators find everything as expected
template <> template <>
void HttpHeadersTestObjectType::test<6>()
{
	set_test_name("HttpHeaders reverse iterator tests");

	// record the total amount of dynamically allocated memory
	mMemTotal = GetMemTotal();

	// create a new ref counted object with an implicit reference
    HttpHeaders::ptr_t headers = HttpHeaders::ptr_t(new HttpHeaders());

	HttpHeaders::reverse_iterator rend(headers->rend()), rbegin(headers->rbegin());
	ensure("Empty container has equal rbegin/rend const iterators", rend == rbegin);
	HttpHeaders::const_reverse_iterator crend(headers->rend()), crbegin(headers->rbegin());
	ensure("Empty container has equal rbegin/rend const iterators", crend == crbegin);
	
	{
		static char line1[] = " AcCePT : image/yourfacehere";
		static char line1v[] = "image/yourfacehere";
		headers->appendNormal(line1, sizeof(line1) - 1);

		static char line2[] = " next : \t\tlinejunk \t";
		static char line2v[] = "linejunk \t";
		headers->appendNormal(line2, sizeof(line2) - 1);

		static char line3[] = "FancY-PANTs::plop:-neuf-=vleem=";
		static char line3v[] = ":plop:-neuf-=vleem=";
		headers->appendNormal(line3, sizeof(line3) - 1);

		static char line4[] = "all-talk-no-walk:";
		static char line4v[] = "";
		headers->appendNormal(line4, sizeof(line4) - 1);

		static char line5[] = ":all-talk-no-walk";
		static char line5v[] = "all-talk-no-walk";
		headers->appendNormal(line5, sizeof(line5) - 1);

		static char line6[] = "  :";
		static char line6v[] = "";
		headers->appendNormal(line6, sizeof(line6) - 1);

		ensure("All entries accounted for", 6 == headers->size());

		static char * values[] = {
			line6v,
			line5v,
			line4v,
			line3v,
			line2v,
			line1v
		};
			
		int i(0);
		HttpHeaders::const_reverse_iterator cend(headers->rend());
		for (HttpHeaders::const_reverse_iterator it(headers->rbegin());
			 cend != it;
			 ++it, ++i)
		{
			std::ostringstream str;
			str << "Const Iterator value # " << i << " was " << values[i];
			ensure(str.str(), (*it).second == values[i]);
		}

		// Rewind, do non-consts
		i = 0;
		HttpHeaders::reverse_iterator end(headers->rend());
		for (HttpHeaders::reverse_iterator it(headers->rbegin());
			 end != it;
			 ++it, ++i)
		{
			std::ostringstream str;
			str << "Iterator value # " << i << " was " << values[i];
			ensure(str.str(), (*it).second == values[i]);
		}
	}
	
	// release the implicit reference, causing the object to be released
    headers.reset();

	// make sure we didn't leak any memory
	ensure(mMemTotal == GetMemTotal());
}

}  // end namespace tut


#endif  // TEST_LLCORE_HTTP_HEADERS_H_