npm: Upgrade to 1.3.17
[platform/upstream/nodejs.git] / deps / npm / node_modules / request / node_modules / tough-cookie / test.js
1 /*
2  * Copyright GoInstant, Inc. and other contributors. All rights reserved.
3  * Permission is hereby granted, free of charge, to any person obtaining a copy
4  * of this software and associated documentation files (the "Software"), to
5  * deal in the Software without restriction, including without limitation the
6  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
7  * sell copies of the Software, and to permit persons to whom the Software is
8  * furnished to do so, subject to the following conditions:
9  *
10  * The above copyright notice and this permission notice shall be included in
11  * all copies or substantial portions of the Software.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
19  * IN THE SOFTWARE.
20  */
21
22 var vows = require('vows');
23 var assert = require('assert');
24 var async = require('async');
25
26 // NOTE use require("tough-cookie") in your own code:
27 var tough = require('./lib/cookie');
28 var Cookie = tough.Cookie;
29 var CookieJar = tough.CookieJar;
30
31
32 function dateVows(table) {
33   var theVows = { };
34   var keys = Object.keys(table).forEach(function(date) {
35     var expect = table[date];
36     theVows[date] = function() {
37       var got = tough.parseDate(date) ? 'valid' : 'invalid';
38       assert.equal(got, expect ? 'valid' : 'invalid');
39     };
40   });
41   return { "date parsing": theVows };
42 }
43
44 function matchVows(func,table) {
45   var theVows = {};
46   table.forEach(function(item) {
47     var str = item[0];
48     var dom = item[1];
49     var expect = item[2];
50     var label = str+(expect?" matches ":" doesn't match ")+dom;
51     theVows[label] = function() {
52       assert.equal(func(str,dom),expect);
53     };
54   });
55   return theVows;
56 }
57
58 function defaultPathVows(table) {
59   var theVows = {};
60   table.forEach(function(item) {
61     var str = item[0];
62     var expect = item[1];
63     var label = str+" gives "+expect;
64     theVows[label] = function() {
65       assert.equal(tough.defaultPath(str),expect);
66     };
67   });
68   return theVows;
69 }
70
71 var atNow = Date.now();
72 function at(offset) { return {now: new Date(atNow+offset)} }
73
74 vows.describe('Cookie Jar')
75 .addBatch({
76   "all defined": function() {
77     assert.ok(Cookie);
78     assert.ok(CookieJar);
79   },
80 })
81 .addBatch(
82   dateVows({
83     "Wed, 09 Jun 2021 10:18:14 GMT": true,
84     "Wed, 09 Jun 2021 22:18:14 GMT": true,
85     "Tue, 18 Oct 2011 07:42:42.123 GMT": true,
86     "18 Oct 2011 07:42:42 GMT": true,
87     "8 Oct 2011 7:42:42 GMT": true,
88     "8 Oct 2011 7:2:42 GMT": false,
89     "Oct 18 2011 07:42:42 GMT": true,
90     "Tue Oct 18 2011 07:05:03 GMT+0000 (GMT)": true,
91     "09 Jun 2021 10:18:14 GMT": true,
92     "99 Jix 3038 48:86:72 ZMT": false,
93     '01 Jan 1970 00:00:00 GMT': true,
94     '01 Jan 1600 00:00:00 GMT': false, // before 1601
95     '01 Jan 1601 00:00:00 GMT': true,
96     '10 Feb 81 13:00:00 GMT': true, // implicit year
97     'Thu, 01 Jan 1970 00:00:010 GMT': true, // strange time, non-strict OK
98     'Thu, 17-Apr-2014 02:12:29 GMT': true, // dashes
99     'Thu, 17-Apr-2014 02:12:29 UTC': true, // dashes and UTC
100   })
101 )
102 .addBatch({
103   "strict date parse of Thu, 01 Jan 1970 00:00:010 GMT": {
104     topic: function() {
105       return tough.parseDate('Thu, 01 Jan 1970 00:00:010 GMT', true) ? true : false;
106     },
107     "invalid": function(date) {
108       assert.equal(date,false);
109     },
110   }
111 })
112 .addBatch({
113   "formatting": {
114     "a simple cookie": {
115       topic: function() {
116         var c = new Cookie();
117         c.key = 'a';
118         c.value = 'b';
119         return c;
120       },
121       "validates": function(c) {
122         assert.ok(c.validate());
123       },
124       "to string": function(c) {
125         assert.equal(c.toString(), 'a=b');
126       },
127     },
128     "a cookie with spaces in the value": {
129       topic: function() {
130         var c = new Cookie();
131         c.key = 'a';
132         c.value = 'beta gamma';
133         return c;
134       },
135       "doesn't validate": function(c) {
136         assert.ok(!c.validate());
137       },
138       "to string": function(c) {
139         assert.equal(c.toString(), 'a="beta gamma"');
140       },
141     },
142     "with an empty value and HttpOnly": {
143       topic: function() {
144         var c = new Cookie();
145         c.key = 'a';
146         c.httpOnly = true;
147         return c;
148       },
149       "to string": function(c) {
150         assert.equal(c.toString(), 'a=; HttpOnly');
151       }
152     },
153     "with an expiry": {
154       topic: function() {
155         var c = new Cookie();
156         c.key = 'a';
157         c.value = 'b';
158         c.setExpires("Oct 18 2011 07:05:03 GMT");
159         return c;
160       },
161       "validates": function(c) {
162         assert.ok(c.validate());
163       },
164       "to string": function(c) {
165         assert.equal(c.toString(), 'a=b; Expires=Tue, 18 Oct 2011 07:05:03 GMT');
166       },
167       "to short string": function(c) {
168         assert.equal(c.cookieString(), 'a=b');
169       },
170     },
171     "with a max-age": {
172       topic: function() {
173         var c = new Cookie();
174         c.key = 'a';
175         c.value = 'b';
176         c.setExpires("Oct 18 2011 07:05:03 GMT");
177         c.maxAge = 12345;
178         return c;
179       },
180       "validates": function(c) {
181         assert.ok(c.validate()); // mabe this one *shouldn't*?
182       },
183       "to string": function(c) {
184         assert.equal(c.toString(), 'a=b; Expires=Tue, 18 Oct 2011 07:05:03 GMT; Max-Age=12345');
185       },
186     },
187     "with a bunch of things": function() {
188       var c = new Cookie();
189       c.key = 'a';
190       c.value = 'b';
191       c.setExpires("Oct 18 2011 07:05:03 GMT");
192       c.maxAge = 12345;
193       c.domain = 'example.com';
194       c.path = '/foo';
195       c.secure = true;
196       c.httpOnly = true;
197       c.extensions = ['MyExtension'];
198       assert.equal(c.toString(), 'a=b; Expires=Tue, 18 Oct 2011 07:05:03 GMT; Max-Age=12345; Domain=example.com; Path=/foo; Secure; HttpOnly; MyExtension');
199     },
200     "a host-only cookie": {
201       topic: function() {
202         var c = new Cookie();
203         c.key = 'a';
204         c.value = 'b';
205         c.hostOnly = true;
206         c.domain = 'shouldnt-stringify.example.com';
207         c.path = '/should-stringify';
208         return c;
209       },
210       "validates": function(c) {
211         assert.ok(c.validate());
212       },
213       "to string": function(c) {
214         assert.equal(c.toString(), 'a=b; Path=/should-stringify');
215       },
216     },
217     "minutes are '10'": {
218       topic: function() {
219         var c = new Cookie();
220         c.key = 'a';
221         c.value = 'b';
222         c.expires = new Date(1284113410000);
223         return c;
224       },
225       "validates": function(c) {
226         assert.ok(c.validate());
227       },
228       "to string": function(c) {
229         var str = c.toString();
230         assert.notEqual(str, 'a=b; Expires=Fri, 010 Sep 2010 010:010:010 GMT');
231         assert.equal(str, 'a=b; Expires=Fri, 10 Sep 2010 10:10:10 GMT');
232       },
233     }
234   }
235 })
236 .addBatch({
237   "TTL with max-age": function() {
238     var c = new Cookie();
239     c.maxAge = 123;
240     assert.equal(c.TTL(), 123000);
241     assert.equal(c.expiryTime(new Date(9000000)), 9123000);
242   },
243   "TTL with zero max-age": function() {
244     var c = new Cookie();
245     c.key = 'a'; c.value = 'b';
246     c.maxAge = 0; // should be treated as "earliest representable"
247     assert.equal(c.TTL(), 0);
248     assert.equal(c.expiryTime(new Date(9000000)), -Infinity);
249     assert.ok(!c.validate()); // not valid, really: non-zero-digit *DIGIT
250   },
251   "TTL with negative max-age": function() {
252     var c = new Cookie();
253     c.key = 'a'; c.value = 'b';
254     c.maxAge = -1; // should be treated as "earliest representable"
255     assert.equal(c.TTL(), 0);
256     assert.equal(c.expiryTime(new Date(9000000)), -Infinity);
257     assert.ok(!c.validate()); // not valid, really: non-zero-digit *DIGIT
258   },
259   "TTL with max-age and expires": function() {
260     var c = new Cookie();
261     c.maxAge = 123;
262     c.expires = new Date(Date.now()+9000);
263     assert.equal(c.TTL(), 123000);
264     assert.ok(c.isPersistent());
265   },
266   "TTL with expires": function() {
267     var c = new Cookie();
268     var now = Date.now();
269     c.expires = new Date(now+9000);
270     assert.equal(c.TTL(now), 9000);
271     assert.equal(c.expiryTime(), c.expires.getTime());
272   },
273   "TTL with old expires": function() {
274     var c = new Cookie();
275     c.setExpires('17 Oct 2010 00:00:00 GMT');
276     assert.ok(c.TTL() < 0);
277     assert.ok(c.isPersistent());
278   },
279   "default TTL": {
280     topic: function() { return new Cookie() },
281     "is Infinite-future": function(c) { assert.equal(c.TTL(), Infinity) },
282     "is a 'session' cookie": function(c) { assert.ok(!c.isPersistent()) },
283   },
284 }).addBatch({
285   "Parsing": {
286     "simple": {
287       topic: function() {
288         return Cookie.parse('a=bcd',true) || null;
289       },
290       "parsed": function(c) { assert.ok(c) },
291       "key": function(c) { assert.equal(c.key, 'a') },
292       "value": function(c) { assert.equal(c.value, 'bcd') },
293       "no path": function(c) { assert.equal(c.path, null) },
294       "no domain": function(c) { assert.equal(c.domain, null) },
295       "no extensions": function(c) { assert.ok(!c.extensions) },
296     },
297     "with expiry": {
298       topic: function() {
299         return Cookie.parse('a=bcd; Expires=Tue, 18 Oct 2011 07:05:03 GMT',true) || null;
300       },
301       "parsed": function(c) { assert.ok(c) },
302       "key": function(c) { assert.equal(c.key, 'a') },
303       "value": function(c) { assert.equal(c.value, 'bcd') },
304       "has expires": function(c) {
305         assert.ok(c.expires !== Infinity, 'expiry is infinite when it shouldn\'t be');
306         assert.equal(c.expires.getTime(), 1318921503000);
307       },
308     },
309     "with expiry and path": {
310       topic: function() {
311         return Cookie.parse('abc="xyzzy!"; Expires=Tue, 18 Oct 2011 07:05:03 GMT; Path=/aBc',true) || null;
312       },
313       "parsed": function(c) { assert.ok(c) },
314       "key": function(c) { assert.equal(c.key, 'abc') },
315       "value": function(c) { assert.equal(c.value, 'xyzzy!') },
316       "has expires": function(c) {
317         assert.ok(c.expires !== Infinity, 'expiry is infinite when it shouldn\'t be');
318         assert.equal(c.expires.getTime(), 1318921503000);
319       },
320       "has path": function(c) { assert.equal(c.path, '/aBc'); },
321       "no httponly or secure": function(c) {
322         assert.ok(!c.httpOnly);
323         assert.ok(!c.secure);
324       },
325     },
326     "with everything": {
327       topic: function() {
328         return Cookie.parse('abc="xyzzy!"; Expires=Tue, 18 Oct 2011 07:05:03 GMT; Path=/aBc; Domain=example.com; Secure; HTTPOnly; Max-Age=1234; Foo=Bar; Baz', true) || null;
329       },
330       "parsed": function(c) { assert.ok(c) },
331       "key": function(c) { assert.equal(c.key, 'abc') },
332       "value": function(c) { assert.equal(c.value, 'xyzzy!') },
333       "has expires": function(c) {
334         assert.ok(c.expires !== Infinity, 'expiry is infinite when it shouldn\'t be');
335         assert.equal(c.expires.getTime(), 1318921503000);
336       },
337       "has path": function(c) { assert.equal(c.path, '/aBc'); },
338       "has domain": function(c) { assert.equal(c.domain, 'example.com'); },
339       "has httponly": function(c) { assert.equal(c.httpOnly, true); },
340       "has secure": function(c) { assert.equal(c.secure, true); },
341       "has max-age": function(c) { assert.equal(c.maxAge, 1234); },
342       "has extensions": function(c) {
343         assert.ok(c.extensions);
344         assert.equal(c.extensions[0], 'Foo=Bar');
345         assert.equal(c.extensions[1], 'Baz');
346       },
347     },
348     "invalid expires": {
349       "strict": function() { assert.ok(!Cookie.parse("a=b; Expires=xyzzy", true)) },
350       "non-strict": function() {
351         var c = Cookie.parse("a=b; Expires=xyzzy");
352         assert.ok(c);
353         assert.equal(c.expires, Infinity);
354       },
355     },
356     "zero max-age": {
357       "strict": function() { assert.ok(!Cookie.parse("a=b; Max-Age=0", true)) },
358       "non-strict": function() {
359         var c = Cookie.parse("a=b; Max-Age=0");
360         assert.ok(c);
361         assert.equal(c.maxAge, 0);
362       },
363     },
364     "negative max-age": {
365       "strict": function() { assert.ok(!Cookie.parse("a=b; Max-Age=-1", true)) },
366       "non-strict": function() {
367         var c = Cookie.parse("a=b; Max-Age=-1");
368         assert.ok(c);
369         assert.equal(c.maxAge, -1);
370       },
371     },
372     "empty domain": {
373       "strict": function() { assert.ok(!Cookie.parse("a=b; domain=", true)) },
374       "non-strict": function() {
375         var c = Cookie.parse("a=b; domain=");
376         assert.ok(c);
377         assert.equal(c.domain, null);
378       },
379     },
380     "dot domain": {
381       "strict": function() { assert.ok(!Cookie.parse("a=b; domain=.", true)) },
382       "non-strict": function() {
383         var c = Cookie.parse("a=b; domain=.");
384         assert.ok(c);
385         assert.equal(c.domain, null);
386       },
387     },
388     "uppercase domain": {
389       "strict lowercases": function() {
390         var c = Cookie.parse("a=b; domain=EXAMPLE.COM");
391         assert.ok(c);
392         assert.equal(c.domain, 'example.com');
393       },
394       "non-strict lowercases": function() {
395         var c = Cookie.parse("a=b; domain=EXAMPLE.COM");
396         assert.ok(c);
397         assert.equal(c.domain, 'example.com');
398       },
399     },
400     "trailing dot in domain": {
401       topic: function() {
402         return Cookie.parse("a=b; Domain=example.com.", true) || null;
403       },
404       "has the domain": function(c) { assert.equal(c.domain,"example.com.") },
405       "but doesn't validate": function(c) { assert.equal(c.validate(),false) },
406     },
407     "empty path": {
408       "strict": function() { assert.ok(!Cookie.parse("a=b; path=", true)) },
409       "non-strict": function() {
410         var c = Cookie.parse("a=b; path=");
411         assert.ok(c);
412         assert.equal(c.path, null);
413       },
414     },
415     "no-slash path": {
416       "strict": function() { assert.ok(!Cookie.parse("a=b; path=xyzzy", true)) },
417       "non-strict": function() {
418         var c = Cookie.parse("a=b; path=xyzzy");
419         assert.ok(c);
420         assert.equal(c.path, null);
421       },
422     },
423     "trailing semi-colons after path": {
424       topic: function () {
425         return [
426           "a=b; path=/;",
427           "c=d;;;;"
428         ];
429       },
430       "strict": function (t) {
431         assert.ok(!Cookie.parse(t[0], true));
432         assert.ok(!Cookie.parse(t[1], true));
433       },
434       "non-strict": function (t) {
435         var c1 = Cookie.parse(t[0]);
436         var c2 = Cookie.parse(t[1]);
437         assert.ok(c1);
438         assert.ok(c2);
439         assert.equal(c1.path, '/');
440       }
441     },
442     "secure-with-value": {
443       "strict": function() { assert.ok(!Cookie.parse("a=b; Secure=xyzzy", true)) },
444       "non-strict": function() {
445         var c = Cookie.parse("a=b; Secure=xyzzy");
446         assert.ok(c);
447         assert.equal(c.secure, true);
448       },
449     },
450     "httponly-with-value": {
451       "strict": function() { assert.ok(!Cookie.parse("a=b; HttpOnly=xyzzy", true)) },
452       "non-strict": function() {
453         var c = Cookie.parse("a=b; HttpOnly=xyzzy");
454         assert.ok(c);
455         assert.equal(c.httpOnly, true);
456       },
457     },
458     "garbage": {
459       topic: function() {
460         return Cookie.parse("\x08", true) || null;
461       },
462       "doesn't parse": function(c) { assert.equal(c,null) },
463     },
464     "public suffix domain": {
465       topic: function() {
466         return Cookie.parse("a=b; domain=kyoto.jp", true) || null;
467       },
468       "parses fine": function(c) {
469         assert.ok(c);
470         assert.equal(c.domain, 'kyoto.jp');
471       },
472       "but fails validation": function(c) {
473         assert.ok(c);
474         assert.ok(!c.validate());
475       },
476     },
477     "Ironically, Google 'GAPS' cookie has very little whitespace": {
478       topic: function() {
479         return Cookie.parse("GAPS=1:A1aaaaAaAAa1aaAaAaaAAAaaa1a11a:aaaAaAaAa-aaaA1-;Path=/;Expires=Thu, 17-Apr-2014 02:12:29 GMT;Secure;HttpOnly");
480       },
481       "parsed": function(c) { assert.ok(c) },
482       "key": function(c) { assert.equal(c.key, 'GAPS') },
483       "value": function(c) { assert.equal(c.value, '1:A1aaaaAaAAa1aaAaAaaAAAaaa1a11a:aaaAaAaAa-aaaA1-') },
484       "path": function(c) {
485         assert.notEqual(c.path, '/;Expires'); // BUG
486         assert.equal(c.path, '/');
487       },
488       "expires": function(c) {
489         assert.notEqual(c.expires, Infinity);
490         assert.equal(c.expires.getTime(), 1397700749000);
491       },
492       "secure": function(c) { assert.ok(c.secure) },
493       "httponly": function(c) { assert.ok(c.httpOnly) },
494     },
495     "lots of equal signs": {
496       topic: function() {
497         return Cookie.parse("queryPref=b=c&d=e; Path=/f=g; Expires=Thu, 17 Apr 2014 02:12:29 GMT; HttpOnly");
498       },
499       "parsed": function(c) { assert.ok(c) },
500       "key": function(c) { assert.equal(c.key, 'queryPref') },
501       "value": function(c) { assert.equal(c.value, 'b=c&d=e') },
502       "path": function(c) {
503         assert.equal(c.path, '/f=g');
504       },
505       "expires": function(c) {
506         assert.notEqual(c.expires, Infinity);
507         assert.equal(c.expires.getTime(), 1397700749000);
508       },
509       "httponly": function(c) { assert.ok(c.httpOnly) },
510     }
511   }
512 })
513 .addBatch({
514   "domain normalization": {
515     "simple": function() {
516       var c = new Cookie();
517       c.domain = "EXAMPLE.com";
518       assert.equal(c.canonicalizedDomain(), "example.com");
519     },
520     "extra dots": function() {
521       var c = new Cookie();
522       c.domain = ".EXAMPLE.com";
523       assert.equal(c.cdomain(), "example.com");
524     },
525     "weird trailing dot": function() {
526       var c = new Cookie();
527       c.domain = "EXAMPLE.ca.";
528       assert.equal(c.canonicalizedDomain(), "example.ca.");
529     },
530     "weird internal dots": function() {
531       var c = new Cookie();
532       c.domain = "EXAMPLE...ca.";
533       assert.equal(c.canonicalizedDomain(), "example...ca.");
534     },
535     "IDN": function() {
536       var c = new Cookie();
537       c.domain = "δοκιμή.δοκιμή"; // "test.test" in greek
538       assert.equal(c.canonicalizedDomain(), "xn--jxalpdlp.xn--jxalpdlp");
539     }
540   }
541 })
542 .addBatch({
543   "Domain Match":matchVows(tough.domainMatch, [
544     // str,          dom,          expect
545     ["example.com", "example.com", true],
546     ["eXaMpLe.cOm", "ExAmPlE.CoM", true],
547     ["no.ca", "yes.ca", false],
548     ["wwwexample.com", "example.com", false],
549     ["www.example.com", "example.com", true],
550     ["example.com", "www.example.com", false],
551     ["www.subdom.example.com", "example.com", true],
552     ["www.subdom.example.com", "subdom.example.com", true],
553     ["example.com", "example.com.", false], // RFC6265 S4.1.2.3
554     ["192.168.0.1", "168.0.1", false], // S5.1.3 "The string is a host name"
555     [null, "example.com", null],
556     ["example.com", null, null],
557     [null, null, null],
558     [undefined, undefined, null],
559   ])
560 })
561 .addBatch({
562   "default-path": defaultPathVows([
563     [null,"/"],
564     ["/","/"],
565     ["/file","/"],
566     ["/dir/file","/dir"],
567     ["noslash","/"],
568   ])
569 })
570 .addBatch({
571   "Path-Match": matchVows(tough.pathMatch, [
572     // request, cookie, match
573     ["/","/",true],
574     ["/dir","/",true],
575     ["/","/dir",false],
576     ["/dir/","/dir/", true],
577     ["/dir/file","/dir/",true],
578     ["/dir/file","/dir",true],
579     ["/directory","/dir",false],
580   ])
581 })
582 .addBatch({
583   "Cookie Sorting": {
584     topic: function() {
585       var cookies = [];
586       var now = Date.now();
587       cookies.push(Cookie.parse("a=0; Domain=example.com"));
588       cookies.push(Cookie.parse("b=1; Domain=www.example.com"));
589       cookies.push(Cookie.parse("c=2; Domain=example.com; Path=/pathA"));
590       cookies.push(Cookie.parse("d=3; Domain=www.example.com; Path=/pathA"));
591       cookies.push(Cookie.parse("e=4; Domain=example.com; Path=/pathA/pathB"));
592       cookies.push(Cookie.parse("f=5; Domain=www.example.com; Path=/pathA/pathB"));
593
594       // force a stable creation time consistent with the order above since
595       // some may have been created at now + 1ms.
596       var i = cookies.length;
597       cookies.forEach(function(cookie) {
598         cookie.creation = new Date(now - 100*(i--));
599       });
600
601       // weak shuffle:
602       cookies = cookies.sort(function(){return Math.random()-0.5});
603
604       cookies = cookies.sort(tough.cookieCompare);
605       return cookies;
606     },
607     "got": function(cookies) {
608       assert.lengthOf(cookies, 6);
609       var names = cookies.map(function(c) {return c.key});
610       assert.deepEqual(names, ['e','f','c','d','a','b']);
611     },
612   }
613 })
614 .addBatch({
615   "CookieJar": {
616     "Setting a basic cookie": {
617       topic: function() {
618         var cj = new CookieJar();
619         var c = Cookie.parse("a=b; Domain=example.com; Path=/");
620         assert.strictEqual(c.hostOnly, null);
621         assert.instanceOf(c.creation, Date);
622         assert.strictEqual(c.lastAccessed, null);
623         c.creation = new Date(Date.now()-10000);
624         cj.setCookie(c, 'http://example.com/index.html', this.callback);
625       },
626       "works": function(c) { assert.instanceOf(c,Cookie) }, // C is for Cookie, good enough for me
627       "gets timestamped": function(c) {
628         assert.ok(c.creation);
629         assert.ok(Date.now() - c.creation.getTime() < 5000); // recently stamped
630         assert.ok(c.lastAccessed);
631         assert.equal(c.creation, c.lastAccessed);
632         assert.equal(c.TTL(), Infinity);
633         assert.ok(!c.isPersistent());
634       },
635     },
636     "Setting a no-path cookie": {
637       topic: function() {
638         var cj = new CookieJar();
639         var c = Cookie.parse("a=b; Domain=example.com");
640         assert.strictEqual(c.hostOnly, null);
641         assert.instanceOf(c.creation, Date);
642         assert.strictEqual(c.lastAccessed, null);
643         c.creation = new Date(Date.now()-10000);
644         cj.setCookie(c, 'http://example.com/index.html', this.callback);
645       },
646       "domain": function(c) { assert.equal(c.domain, 'example.com') },
647       "path is /": function(c) { assert.equal(c.path, '/') },
648       "path was derived": function(c) { assert.strictEqual(c.pathIsDefault, true) },
649     },
650     "Setting a cookie already marked as host-only": {
651       topic: function() {
652         var cj = new CookieJar();
653         var c = Cookie.parse("a=b; Domain=example.com");
654         assert.strictEqual(c.hostOnly, null);
655         assert.instanceOf(c.creation, Date);
656         assert.strictEqual(c.lastAccessed, null);
657         c.creation = new Date(Date.now()-10000);
658         c.hostOnly = true;
659         cj.setCookie(c, 'http://example.com/index.html', this.callback);
660       },
661       "domain": function(c) { assert.equal(c.domain, 'example.com') },
662       "still hostOnly": function(c) { assert.strictEqual(c.hostOnly, true) },
663     },
664     "Setting a session cookie": {
665       topic: function() {
666         var cj = new CookieJar();
667         var c = Cookie.parse("a=b");
668         assert.strictEqual(c.path, null);
669         cj.setCookie(c, 'http://www.example.com/dir/index.html', this.callback);
670       },
671       "works": function(c) { assert.instanceOf(c,Cookie) },
672       "gets the domain": function(c) { assert.equal(c.domain, 'www.example.com') },
673       "gets the default path": function(c) { assert.equal(c.path, '/dir') },
674       "is 'hostOnly'": function(c) { assert.ok(c.hostOnly) },
675     },
676     "Setting wrong domain cookie": {
677       topic: function() {
678         var cj = new CookieJar();
679         var c = Cookie.parse("a=b; Domain=fooxample.com; Path=/");
680         cj.setCookie(c, 'http://example.com/index.html', this.callback);
681       },
682       "fails": function(err,c) {
683         assert.ok(err.message.match(/domain/i));
684         assert.ok(!c);
685       },
686     },
687     "Setting sub-domain cookie": {
688       topic: function() {
689         var cj = new CookieJar();
690         var c = Cookie.parse("a=b; Domain=www.example.com; Path=/");
691         cj.setCookie(c, 'http://example.com/index.html', this.callback);
692       },
693       "fails": function(err,c) {
694         assert.ok(err.message.match(/domain/i));
695         assert.ok(!c);
696       },
697     },
698     "Setting super-domain cookie": {
699       topic: function() {
700         var cj = new CookieJar();
701         var c = Cookie.parse("a=b; Domain=example.com; Path=/");
702         cj.setCookie(c, 'http://www.app.example.com/index.html', this.callback);
703       },
704       "success": function(err,c) {
705         assert.ok(!err);
706         assert.equal(c.domain, 'example.com');
707       },
708     },
709     "Setting HttpOnly cookie over non-HTTP API": {
710       topic: function() {
711         var cj = new CookieJar();
712         var c = Cookie.parse("a=b; Domain=example.com; Path=/; HttpOnly");
713         cj.setCookie(c, 'http://example.com/index.html', {http:false}, this.callback);
714       },
715       "fails": function(err,c) {
716         assert.match(err.message, /HttpOnly/i);
717         assert.ok(!c);
718       },
719     },
720   },
721   "Cookie Jar store eight cookies": {
722     topic: function() {
723       var cj = new CookieJar();
724       var ex = 'http://example.com/index.html';
725       var tasks = [];
726       tasks.push(function(next) {
727         cj.setCookie('a=1; Domain=example.com; Path=/',ex,at(0),next);
728       });
729       tasks.push(function(next) {
730         cj.setCookie('b=2; Domain=example.com; Path=/; HttpOnly',ex,at(1000),next);
731       });
732       tasks.push(function(next) {
733         cj.setCookie('c=3; Domain=example.com; Path=/; Secure',ex,at(2000),next);
734       });
735       tasks.push(function(next) { // path
736         cj.setCookie('d=4; Domain=example.com; Path=/foo',ex,at(3000),next);
737       });
738       tasks.push(function(next) { // host only
739         cj.setCookie('e=5',ex,at(4000),next);
740       });
741       tasks.push(function(next) { // other domain
742         cj.setCookie('f=6; Domain=nodejs.org; Path=/','http://nodejs.org',at(5000),next);
743       });
744       tasks.push(function(next) { // expired
745         cj.setCookie('g=7; Domain=example.com; Path=/; Expires=Tue, 18 Oct 2011 00:00:00 GMT',ex,at(6000),next);
746       });
747       tasks.push(function(next) { // expired via Max-Age
748         cj.setCookie('h=8; Domain=example.com; Path=/; Max-Age=1',ex,next);
749       });
750       var cb = this.callback;
751       async.parallel(tasks, function(err,results){
752         setTimeout(function() {
753           cb(err,cj,results);
754         }, 2000); // so that 'h=8' expires
755       });
756     },
757     "setup ok": function(err,cj,results) {
758       assert.ok(1);
759     },
760     "then retrieving for http://nodejs.org": {
761       topic: function(cj,results) {
762         cj.getCookies('http://nodejs.org',this.callback);
763       },
764       "get a nodejs cookie": function(cookies) {
765         assert.lengthOf(cookies, 1);
766         var cookie = cookies[0];
767         assert.equal(cookie.domain, 'nodejs.org');
768       },
769     },
770     "then retrieving for https://example.com": {
771       topic: function(cj,results) {
772         cj.getCookies('https://example.com',{secure:true},this.callback);
773       },
774       "get a secure example cookie with others": function(cookies) {
775         var names = cookies.map(function(c) {return c.key});
776         assert.deepEqual(names, ['a','b','c','e']);
777       },
778     },
779     "then retrieving for https://example.com (missing options)": {
780       topic: function(cj,results) {
781         cj.getCookies('https://example.com',this.callback);
782       },
783       "get a secure example cookie with others": function(cookies) {
784         var names = cookies.map(function(c) {return c.key});
785         assert.deepEqual(names, ['a','b','c','e']);
786       },
787     },
788     "then retrieving for http://example.com": {
789       topic: function(cj,results) {
790         cj.getCookies('http://example.com',this.callback);
791       },
792       "get a bunch of cookies": function(cookies) {
793         var names = cookies.map(function(c) {return c.key});
794         assert.deepEqual(names, ['a','b','e']);
795       },
796     },
797     "then retrieving for http://EXAMPlE.com": {
798       topic: function(cj,results) {
799         cj.getCookies('http://EXAMPlE.com',this.callback);
800       },
801       "get a bunch of cookies": function(cookies) {
802         var names = cookies.map(function(c) {return c.key});
803         assert.deepEqual(names, ['a','b','e']);
804       },
805     },
806     "then retrieving for http://example.com, non-HTTP": {
807       topic: function(cj,results) {
808         cj.getCookies('http://example.com',{http:false},this.callback);
809       },
810       "get a bunch of cookies": function(cookies) {
811         var names = cookies.map(function(c) {return c.key});
812         assert.deepEqual(names, ['a','e']);
813       },
814     },
815     "then retrieving for http://example.com/foo/bar": {
816       topic: function(cj,results) {
817         cj.getCookies('http://example.com/foo/bar',this.callback);
818       },
819       "get a bunch of cookies": function(cookies) {
820         var names = cookies.map(function(c) {return c.key});
821         assert.deepEqual(names, ['d','a','b','e']);
822       },
823     },
824     "then retrieving for http://example.com as a string": {
825       topic: function(cj,results) {
826         cj.getCookieString('http://example.com',this.callback);
827       },
828       "get a single string": function(cookieHeader) {
829         assert.equal(cookieHeader, "a=1; b=2; e=5");
830       },
831     },
832     "then retrieving for http://example.com as a set-cookie header": {
833       topic: function(cj,results) {
834         cj.getSetCookieStrings('http://example.com',this.callback);
835       },
836       "get a single string": function(cookieHeaders) {
837         assert.lengthOf(cookieHeaders, 3);
838         assert.equal(cookieHeaders[0], "a=1; Domain=example.com; Path=/");
839         assert.equal(cookieHeaders[1], "b=2; Domain=example.com; Path=/; HttpOnly");
840         assert.equal(cookieHeaders[2], "e=5; Path=/");
841       },
842     },
843     "then retrieving for http://www.example.com/": {
844       topic: function(cj,results) {
845         cj.getCookies('http://www.example.com/foo/bar',this.callback);
846       },
847       "get a bunch of cookies": function(cookies) {
848         var names = cookies.map(function(c) {return c.key});
849         assert.deepEqual(names, ['d','a','b']); // note lack of 'e'
850       },
851     },
852   },
853   "Repeated names": {
854     topic: function() {
855       var cb = this.callback;
856       var cj = new CookieJar();
857       var ex = 'http://www.example.com/';
858       var sc = cj.setCookie;
859       var tasks = [];
860       var now = Date.now();
861       tasks.push(sc.bind(cj,'aaaa=xxxx',ex,at(0)));
862       tasks.push(sc.bind(cj,'aaaa=1111; Domain=www.example.com',ex,at(1000)));
863       tasks.push(sc.bind(cj,'aaaa=2222; Domain=example.com',ex,at(2000)));
864       tasks.push(sc.bind(cj,'aaaa=3333; Domain=www.example.com; Path=/pathA',ex,at(3000)));
865       async.series(tasks,function(err,results) {
866         results = results.filter(function(e) {return e !== undefined});
867         cb(err,{cj:cj, cookies:results, now:now});
868       });
869     },
870     "all got set": function(err,t) {
871       assert.lengthOf(t.cookies,4);
872     },
873     "then getting 'em back": {
874       topic: function(t) {
875         var cj = t.cj;
876         cj.getCookies('http://www.example.com/pathA',this.callback);
877       },
878       "there's just three": function (err,cookies) {
879         var vals = cookies.map(function(c) {return c.value});
880         // may break with sorting; sorting should put 3333 first due to longest path:
881         assert.deepEqual(vals, ['3333','1111','2222']);
882       }
883     },
884   },
885   "CookieJar setCookie errors": {
886     "public-suffix domain": {
887       topic: function() {
888         var cj = new CookieJar();
889         cj.setCookie('i=9; Domain=kyoto.jp; Path=/','kyoto.jp',this.callback);
890       },
891       "errors": function(err,cookie) {
892         assert.ok(err);
893         assert.ok(!cookie);
894         assert.match(err.message, /public suffix/i);
895       },
896     },
897     "wrong domain": {
898       topic: function() {
899         var cj = new CookieJar();
900         cj.setCookie('j=10; Domain=google.com; Path=/','google.ca',this.callback);
901       },
902       "errors": function(err,cookie) {
903         assert.ok(err);
904         assert.ok(!cookie);
905         assert.match(err.message, /not in this host's domain/i);
906       },
907     },
908     "old cookie is HttpOnly": {
909       topic: function() {
910         var cb = this.callback;
911         var next = function (err,c) {
912           return cb(err,cj);
913         };
914         var cj = new CookieJar();
915         cj.setCookie('k=11; Domain=example.ca; Path=/; HttpOnly','http://example.ca',{http:true},next);
916       },
917       "initial cookie is set": function(err,cj) {
918         assert.ok(!err);
919       },
920       "but when trying to overwrite": {
921         topic: function(cj) {
922           var cb = this.callback;
923           cj.setCookie('k=12; Domain=example.ca; Path=/','http://example.ca',{http:false},function(err,c) {cb(null,err)});
924         },
925         "it's an error": function(err) {
926           assert.ok(err);
927         },
928         "then, checking the original": {
929           topic: function(ignored,cj) {
930             assert.ok(cj instanceof CookieJar);
931             cj.getCookies('http://example.ca',{http:true},this.callback);
932           },
933           "cookie has original value": function(err,cookies) {
934             assert.equal(err,null);
935             assert.lengthOf(cookies, 1);
936             assert.equal(cookies[0].value,11);
937           },
938         },
939       },
940     },
941   },
942 })
943 .addBatch({
944   "JSON": {
945     "serialization": {
946       topic: function() {
947         var c = Cookie.parse('alpha=beta; Domain=example.com; Path=/foo; Expires=Tue, 19 Jan 2038 03:14:07 GMT; HttpOnly');
948         return JSON.stringify(c);
949       },
950       "gives a string": function(str) {
951         assert.equal(typeof str, "string");
952       },
953       "date is in ISO format": function(str) {
954         assert.match(str, /"expires":"2038-01-19T03:14:07\.000Z"/, 'expires is in ISO format');
955       },
956     },
957     "deserialization": {
958       topic: function() {
959         var json = '{"key":"alpha","value":"beta","domain":"example.com","path":"/foo","expires":"2038-01-19T03:14:07.000Z","httpOnly":true,"lastAccessed":2000000000123}';
960         return Cookie.fromJSON(json);
961       },
962       "works": function(c) {
963         assert.ok(c);
964       },
965       "key": function(c) { assert.equal(c.key, "alpha") },
966       "value": function(c) { assert.equal(c.value, "beta") },
967       "domain": function(c) { assert.equal(c.domain, "example.com") },
968       "path": function(c) { assert.equal(c.path, "/foo") },
969       "httpOnly": function(c) { assert.strictEqual(c.httpOnly, true) },
970       "secure": function(c) { assert.strictEqual(c.secure, false) },
971       "hostOnly": function(c) { assert.strictEqual(c.hostOnly, null) },
972       "expires is a date object": function(c) {
973         assert.equal(c.expires.getTime(), 2147483647000);
974       },
975       "lastAccessed is a date object": function(c) {
976         assert.equal(c.lastAccessed.getTime(), 2000000000123);
977       },
978       "creation defaulted": function(c) {
979         assert.ok(c.creation.getTime());
980       }
981     },
982     "null deserialization": {
983       topic: function() {
984         return Cookie.fromJSON(null);
985       },
986       "is null": function(cookie) {
987         assert.equal(cookie,null);
988       },
989     },
990   },
991   "expiry deserialization": {
992     "Infinity": {
993       topic: Cookie.fromJSON.bind(null, '{"expires":"Infinity"}'),
994       "is infinite": function(c) {
995         assert.strictEqual(c.expires, "Infinity");
996         assert.equal(c.expires, Infinity);
997       },
998     },
999   },
1000   "maxAge serialization": {
1001     topic: function() {
1002       return function(toSet) {
1003         var c = new Cookie();
1004         c.key = 'foo'; c.value = 'bar';
1005         c.setMaxAge(toSet);
1006         return JSON.stringify(c);
1007       };
1008     },
1009     "zero": {
1010       topic: function(f) { return f(0) },
1011       "looks good": function(str) {
1012         assert.match(str, /"maxAge":0/);
1013       },
1014     },
1015     "Infinity": {
1016       topic: function(f) { return f(Infinity) },
1017       "looks good": function(str) {
1018         assert.match(str, /"maxAge":"Infinity"/);
1019       },
1020     },
1021     "-Infinity": {
1022       topic: function(f) { return f(-Infinity) },
1023       "looks good": function(str) {
1024         assert.match(str, /"maxAge":"-Infinity"/);
1025       },
1026     },
1027     "null": {
1028       topic: function(f) { return f(null) },
1029       "looks good": function(str) {
1030         assert.match(str, /"maxAge":null/);
1031       },
1032     },
1033   },
1034   "maxAge deserialization": {
1035     "number": {
1036       topic: Cookie.fromJSON.bind(null,'{"key":"foo","value":"bar","maxAge":123}'),
1037       "is the number": function(c) {
1038         assert.strictEqual(c.maxAge, 123);
1039       },
1040     },
1041     "null": {
1042       topic: Cookie.fromJSON.bind(null,'{"key":"foo","value":"bar","maxAge":null}'),
1043       "is null": function(c) {
1044         assert.strictEqual(c.maxAge, null);
1045       },
1046     },
1047     "less than zero": {
1048       topic: Cookie.fromJSON.bind(null,'{"key":"foo","value":"bar","maxAge":-123}'),
1049       "is -123": function(c) {
1050         assert.strictEqual(c.maxAge, -123);
1051       },
1052     },
1053     "Infinity": {
1054       topic: Cookie.fromJSON.bind(null,'{"key":"foo","value":"bar","maxAge":"Infinity"}'),
1055       "is inf-as-string": function(c) {
1056         assert.strictEqual(c.maxAge, "Infinity");
1057       },
1058     },
1059     "-Infinity": {
1060       topic: Cookie.fromJSON.bind(null,'{"key":"foo","value":"bar","maxAge":"-Infinity"}'),
1061       "is inf-as-string": function(c) {
1062         assert.strictEqual(c.maxAge, "-Infinity");
1063       },
1064     },
1065   }
1066 })
1067 .addBatch({
1068   "permuteDomain": {
1069     "base case": {
1070       topic: tough.permuteDomain.bind(null,'example.com'),
1071       "got the domain": function(list) {
1072         assert.deepEqual(list, ['example.com']);
1073       },
1074     },
1075     "two levels": {
1076       topic: tough.permuteDomain.bind(null,'foo.bar.example.com'),
1077       "got three things": function(list) {
1078         assert.deepEqual(list, ['example.com','bar.example.com','foo.bar.example.com']);
1079       },
1080     },
1081     "invalid domain": {
1082       topic: tough.permuteDomain.bind(null,'foo.bar.example.localduhmain'),
1083       "got three things": function(list) {
1084         assert.equal(list, null);
1085       },
1086     },
1087   },
1088   "permutePath": {
1089     "base case": {
1090       topic: tough.permutePath.bind(null,'/'),
1091       "just slash": function(list) {
1092         assert.deepEqual(list,['/']);
1093       },
1094     },
1095     "single case": {
1096       topic: tough.permutePath.bind(null,'/foo'),
1097       "two things": function(list) {
1098         assert.deepEqual(list,['/foo','/']);
1099       },
1100       "path matching": function(list) {
1101         list.forEach(function(e) {
1102           assert.ok(tough.pathMatch('/foo',e));
1103         });
1104       },
1105     },
1106     "double case": {
1107       topic: tough.permutePath.bind(null,'/foo/bar'),
1108       "four things": function(list) {
1109         assert.deepEqual(list,['/foo/bar','/foo','/']);
1110       },
1111       "path matching": function(list) {
1112         list.forEach(function(e) {
1113           assert.ok(tough.pathMatch('/foo/bar',e));
1114         });
1115       },
1116     },
1117     "trailing slash": {
1118       topic: tough.permutePath.bind(null,'/foo/bar/'),
1119       "three things": function(list) {
1120         assert.deepEqual(list,['/foo/bar','/foo','/']);
1121       },
1122       "path matching": function(list) {
1123         list.forEach(function(e) {
1124           assert.ok(tough.pathMatch('/foo/bar/',e));
1125         });
1126       },
1127     },
1128   }
1129 })
1130 .addBatch({
1131   "Issue 1": {
1132     topic: function() {
1133       var cj = new CookieJar();
1134       cj.setCookie('hello=world; path=/some/path/', 'http://domain/some/path/file', function(err,cookie) {
1135         this.callback(err,{cj:cj, cookie:cookie});
1136       }.bind(this));
1137     },
1138     "stored a cookie": function(t) {
1139       assert.ok(t.cookie);
1140     },
1141     "cookie's path was modified to remove unnecessary slash": function(t) {
1142       assert.equal(t.cookie.path, '/some/path');
1143     },
1144     "getting it back": {
1145       topic: function(t) {
1146         t.cj.getCookies('http://domain/some/path/file', function(err,cookies) {
1147           this.callback(err, {cj:t.cj, cookies:cookies||[]});
1148         }.bind(this));
1149       },
1150       "got one cookie": function(t) {
1151         assert.lengthOf(t.cookies, 1);
1152       },
1153       "it's the right one": function(t) {
1154         var c = t.cookies[0];
1155         assert.equal(c.key, 'hello');
1156         assert.equal(c.value, 'world');
1157       },
1158     }
1159   }
1160 })
1161 .addBatch({
1162   "expiry option": {
1163     topic: function() {
1164       var cb = this.callback;
1165       var cj = new CookieJar();
1166       cj.setCookie('near=expiry; Domain=example.com; Path=/; Max-Age=1','http://www.example.com',at(-1), function(err,cookie) {
1167
1168         cb(err, {cj:cj, cookie:cookie});
1169       });
1170     },
1171     "set the cookie": function(t) {
1172       assert.ok(t.cookie, "didn't set?!");
1173       assert.equal(t.cookie.key, 'near');
1174     },
1175     "then, retrieving": {
1176       topic: function(t) {
1177         var cb = this.callback;
1178         setTimeout(function() {
1179           t.cj.getCookies('http://www.example.com', {http:true, expire:false}, function(err,cookies) {
1180             t.cookies = cookies;
1181             cb(err,t);
1182           });
1183         },2000);
1184       },
1185       "got the cookie": function(t) {
1186         assert.lengthOf(t.cookies, 1);
1187         assert.equal(t.cookies[0].key, 'near');
1188       },
1189     }
1190   }
1191 })
1192 .addBatch({
1193   "trailing semi-colon set into cj": {
1194     topic: function () {
1195       var cb = this.callback;
1196       var cj = new CookieJar();
1197       var ex = 'http://www.example.com';
1198       var tasks = [];
1199       tasks.push(function(next) {
1200         cj.setCookie('broken_path=testme; path=/;',ex,at(-1),next);
1201       });
1202       tasks.push(function(next) {
1203         cj.setCookie('b=2; Path=/;;;;',ex,at(-1),next);
1204       });
1205       async.parallel(tasks, function (err, cookies) {
1206         cb(null, {
1207           cj: cj,
1208           cookies: cookies
1209         });
1210       });
1211     },
1212     "check number of cookies": function (t) {
1213       assert.lengthOf(t.cookies, 2, "didn't set");
1214     },
1215     "check *broken_path* was set properly": function (t) {
1216       assert.equal(t.cookies[0].key, "broken_path");
1217       assert.equal(t.cookies[0].value, "testme");
1218       assert.equal(t.cookies[0].path, "/");
1219     },
1220     "check *b* was set properly": function (t) {
1221       assert.equal(t.cookies[1].key, "b");
1222       assert.equal(t.cookies[1].value, "2");
1223       assert.equal(t.cookies[1].path, "/");
1224     },
1225     "retrieve the cookie": {
1226       topic: function (t) {
1227         var cb = this.callback;
1228         t.cj.getCookies('http://www.example.com', {}, function (err, cookies) {
1229           t.cookies = cookies;
1230           cb(err, t);
1231         });
1232       },
1233       "get the cookie": function(t) {
1234         assert.lengthOf(t.cookies, 2);
1235         assert.equal(t.cookies[0].key, 'broken_path');
1236         assert.equal(t.cookies[0].value, 'testme');
1237         assert.equal(t.cookies[1].key, "b");
1238         assert.equal(t.cookies[1].value, "2");
1239         assert.equal(t.cookies[1].path, "/");
1240       },
1241     },
1242   }
1243 })
1244 .addBatch({
1245   "Constructor":{
1246     topic: function () {
1247       return new Cookie({
1248         key: 'test',
1249         value: 'b',
1250         maxAge: 60
1251       });
1252     },
1253     'check for key property': function (c) {
1254       assert.ok(c);
1255       assert.equal(c.key, 'test');
1256     },
1257     'check for value property': function (c) {
1258       assert.equal(c.value, 'b');
1259     },
1260     'check for maxAge': function (c) {
1261       assert.equal(c.maxAge, 60);
1262     },
1263     'check for default values for unspecified properties': function (c) {
1264       assert.equal(c.expires, "Infinity");
1265       assert.equal(c.secure, false);
1266       assert.equal(c.httpOnly, false);
1267     }
1268   }
1269 })
1270 .addBatch({
1271   "allPaths option": {
1272     topic: function() {
1273       var cj = new CookieJar();
1274       var tasks = [];
1275       tasks.push(cj.setCookie.bind(cj, 'nopath_dom=qq; Path=/; Domain=example.com', 'http://example.com', {}));
1276       tasks.push(cj.setCookie.bind(cj, 'path_dom=qq; Path=/foo; Domain=example.com', 'http://example.com', {}));
1277       tasks.push(cj.setCookie.bind(cj, 'nopath_host=qq; Path=/', 'http://www.example.com', {}));
1278       tasks.push(cj.setCookie.bind(cj, 'path_host=qq; Path=/foo', 'http://www.example.com', {}));
1279       tasks.push(cj.setCookie.bind(cj, 'other=qq; Path=/', 'http://other.example.com/', {}));
1280       tasks.push(cj.setCookie.bind(cj, 'other2=qq; Path=/foo', 'http://other.example.com/foo', {}));
1281       var cb = this.callback;
1282       async.parallel(tasks, function(err,results) {
1283         cb(err, {cj:cj, cookies: results});
1284       });
1285     },
1286     "all set": function(t) {
1287       assert.equal(t.cookies.length, 6);
1288       assert.ok(t.cookies.every(function(c) { return !!c }));
1289     },
1290     "getting without allPaths": {
1291       topic: function(t) {
1292         var cb = this.callback;
1293         var cj = t.cj;
1294         cj.getCookies('http://www.example.com/', {}, function(err,cookies) {
1295           cb(err, {cj:cj, cookies:cookies});
1296         });
1297       },
1298       "found just two cookies": function(t) {
1299         assert.equal(t.cookies.length, 2);
1300       },
1301       "all are path=/": function(t) {
1302         assert.ok(t.cookies.every(function(c) { return c.path === '/' }));
1303       },
1304       "no 'other' cookies": function(t) {
1305         assert.ok(!t.cookies.some(function(c) { return (/^other/).test(c.name) }));
1306       },
1307     },
1308     "getting without allPaths for /foo": {
1309       topic: function(t) {
1310         var cb = this.callback;
1311         var cj = t.cj;
1312         cj.getCookies('http://www.example.com/foo', {}, function(err,cookies) {
1313           cb(err, {cj:cj, cookies:cookies});
1314         });
1315       },
1316       "found four cookies": function(t) {
1317         assert.equal(t.cookies.length, 4);
1318       },
1319       "no 'other' cookies": function(t) {
1320         assert.ok(!t.cookies.some(function(c) { return (/^other/).test(c.name) }));
1321       },
1322     },
1323     "getting with allPaths:true": {
1324       topic: function(t) {
1325         var cb = this.callback;
1326         var cj = t.cj;
1327         cj.getCookies('http://www.example.com/', {allPaths:true}, function(err,cookies) {
1328           cb(err, {cj:cj, cookies:cookies});
1329         });
1330       },
1331       "found four cookies": function(t) {
1332         assert.equal(t.cookies.length, 4);
1333       },
1334       "no 'other' cookies": function(t) {
1335         assert.ok(!t.cookies.some(function(c) { return (/^other/).test(c.name) }));
1336       },
1337     },
1338   }
1339 })
1340 .export(module);