You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by jc...@apache.org on 2009/02/16 00:59:39 UTC

svn commit: r744782 [3/4] - in /couchdb/trunk: share/www/ share/www/script/ share/www/script/test/ test/

Added: couchdb/trunk/share/www/script/test/all_docs.js
URL: http://svn.apache.org/viewvc/couchdb/trunk/share/www/script/test/all_docs.js?rev=744782&view=auto
==============================================================================
--- couchdb/trunk/share/www/script/test/all_docs.js (added)
+++ couchdb/trunk/share/www/script/test/all_docs.js Sun Feb 15 23:59:38 2009
@@ -0,0 +1,100 @@
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+couchTests.all_docs = function(debug) {
+  var db = new CouchDB("test_suite_db");
+  db.deleteDb();
+  db.createDb();
+  if (debug) debugger;
+  
+  // Create some more documents.
+  // Notice the use of the ok member on the return result.
+  T(db.save({_id:"0",a:1,b:1}).ok);
+  T(db.save({_id:"3",a:4,b:16}).ok);
+  T(db.save({_id:"1",a:2,b:4}).ok);
+  T(db.save({_id:"2",a:3,b:9}).ok);
+
+  // Check the all docs
+  var results = db.allDocs();
+  var rows = results.rows;
+
+  T(results.total_rows == results.rows.length);
+
+  for(var i=0; i < rows.length; i++) {
+    T(rows[i].id >= "0" && rows[i].id <= "4");
+  }
+  
+  // Check _all_docs with descending=true
+  var desc = db.allDocs({descending:true});
+  T(desc.total_rows == desc.rows.length);
+
+  // Check _all_docs offset
+  var all = db.allDocs({startkey:"2"});
+  T(all.offset == 2);
+  
+  // check that the docs show up in the seq view in the order they were created
+  var all_seq = db.allDocsBySeq();
+  var ids = ["0","3","1","2"];
+  for (var i=0; i < all_seq.rows.length; i++) {
+    var row = all_seq.rows[i];
+    T(row.id == ids[i]);
+  };
+  
+  // it should work in reverse as well
+  all_seq = db.allDocsBySeq({descending:true});
+  ids = ["2","1","3","0"];
+  for (var i=0; i < all_seq.rows.length; i++) {
+    var row = all_seq.rows[i];
+    T(row.id == ids[i]);
+  };
+  
+  // check that deletions also show up right
+  var doc1 = db.open("1");
+  var deleted = db.deleteDoc(doc1);
+  T(deleted.ok);
+  all_seq = db.allDocsBySeq();
+  
+  // the deletion should make doc id 1 have the last seq num
+  T(all_seq.rows.length == 4);
+  T(all_seq.rows[3].id == "1");
+  T(all_seq.rows[3].value.deleted);
+
+  // is this a bug?
+  // T(all_seq.rows.length == all_seq.total_rows);
+  
+  // do an update
+  var doc2 = db.open("3");
+  doc2.updated = "totally";
+  db.save(doc2);
+  all_seq = db.allDocsBySeq();
+  
+  // the update should make doc id 3 have the last seq num
+  T(all_seq.rows.length == 4);
+  T(all_seq.rows[3].id == "3");
+
+  // ok now lets see what happens with include docs
+  all_seq = db.allDocsBySeq({include_docs: true});
+  T(all_seq.rows.length == 4);
+  T(all_seq.rows[3].id == "3");
+  T(all_seq.rows[3].doc.updated == "totally");
+
+  // and on the deleted one, no doc
+  T(all_seq.rows[2].value.deleted);
+  T(!all_seq.rows[2].doc);
+  
+  // test the all docs collates sanely
+  db.save({_id: "Z", foo: "Z"});
+  db.save({_id: "a", foo: "a"});
+
+  var rows = db.allDocs({startkey: "Z", endkey: "Z"}).rows;
+  T(rows.length == 1);
+};

Propchange: couchdb/trunk/share/www/script/test/all_docs.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: couchdb/trunk/share/www/script/test/attachment_paths.js
URL: http://svn.apache.org/viewvc/couchdb/trunk/share/www/script/test/attachment_paths.js?rev=744782&view=auto
==============================================================================
--- couchdb/trunk/share/www/script/test/attachment_paths.js (added)
+++ couchdb/trunk/share/www/script/test/attachment_paths.js Sun Feb 15 23:59:38 2009
@@ -0,0 +1,147 @@
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+couchTests.attachment_paths = function(debug) {
+  if (debug) debugger;
+  var dbNames = ["test_suite_db", "test_suite_db/with_slashes"];
+  for (var i=0; i < dbNames.length; i++) {
+    var db = new CouchDB(dbNames[i]);
+    var dbName = encodeURIComponent(dbNames[i]);
+    db.deleteDb();
+    db.createDb();
+
+    // first just save a regular doc with an attachment that has a slash in the url.
+    // (also gonna run an encoding check case)
+    var binAttDoc = {
+      _id: "bin_doc",
+      _attachments:{
+        "foo/bar.txt": {
+          content_type:"text/plain",
+          data: "VGhpcyBpcyBhIGJhc2U2NCBlbmNvZGVkIHRleHQ="
+        },
+        "foo%2Fbaz.txt": {
+          content_type:"text/plain",
+          data: "V2UgbGlrZSBwZXJjZW50IHR3byBGLg=="
+        }
+      }
+    }
+
+    T(db.save(binAttDoc).ok);
+
+    var xhr = CouchDB.request("GET", "/"+dbName+"/bin_doc/foo/bar.txt");
+    T(xhr.responseText == "This is a base64 encoded text");
+    T(xhr.getResponseHeader("Content-Type") == "text/plain");
+
+    // lets try it with an escaped attachment id...
+    // weird that it's at two urls
+    var xhr = CouchDB.request("GET", "/"+dbName+"/bin_doc/foo%2Fbar.txt");
+    T(xhr.status == 200); 
+    // xhr.responseText == "This is a base64 encoded text"
+
+    var xhr = CouchDB.request("GET", "/"+dbName+"/bin_doc/foo/baz.txt");
+    T(xhr.status == 404);
+
+    var xhr = CouchDB.request("GET", "/"+dbName+"/bin_doc/foo%252Fbaz.txt");
+    T(xhr.status == 200); 
+    T(xhr.responseText == "We like percent two F.");
+
+    // require a _rev to PUT
+    var xhr = CouchDB.request("PUT", "/"+dbName+"/bin_doc/foo/attachment.txt", {
+      headers:{"Content-Type":"text/plain;charset=utf-8"},
+      body:"Just some text"
+    });
+    T(xhr.status == 409);    
+
+    var xhr = CouchDB.request("PUT", "/"+dbName+"/bin_doc/foo/bar2.txt?rev=" + binAttDoc._rev, {
+      body:"This is no base64 encoded text",
+      headers:{"Content-Type": "text/plain;charset=utf-8"}
+    });
+    T(xhr.status == 201);
+    var rev = JSON.parse(xhr.responseText).rev;
+
+    binAttDoc = db.open("bin_doc");
+
+    T(binAttDoc._attachments["foo/bar.txt"] !== undefined);
+    T(binAttDoc._attachments["foo%2Fbaz.txt"] !== undefined);
+    T(binAttDoc._attachments["foo/bar2.txt"] !== undefined);
+    T(binAttDoc._attachments["foo/bar2.txt"].content_type == "text/plain;charset=utf-8");
+    T(binAttDoc._attachments["foo/bar2.txt"].length == 30);
+
+    //// now repeat the while thing with a design doc
+  
+    // first just save a regular doc with an attachment that has a slash in the url.
+    // (also gonna run an encoding check case)
+    var binAttDoc = {
+      _id: "_design/bin_doc",
+      _attachments:{
+        "foo/bar.txt": {
+          content_type:"text/plain",
+          data: "VGhpcyBpcyBhIGJhc2U2NCBlbmNvZGVkIHRleHQ="
+        },
+        "foo%2Fbaz.txt": {
+          content_type:"text/plain",
+          data: "V2UgbGlrZSBwZXJjZW50IHR3byBGLg=="
+        }
+      }
+    }
+
+    T(db.save(binAttDoc).ok);
+
+    var xhr = CouchDB.request("GET", "/"+dbName+"/_design%2Fbin_doc/foo/bar.txt");
+    T(xhr.responseText == "This is a base64 encoded text");
+    T(xhr.getResponseHeader("Content-Type") == "text/plain");
+
+    // lets try it with an escaped attachment id...
+    // weird that it's at two urls
+    var xhr = CouchDB.request("GET", "/"+dbName+"/_design%2Fbin_doc/foo%2Fbar.txt");
+    T(xhr.responseText == "This is a base64 encoded text");
+    T(xhr.status == 200);
+
+    // err, 3 urls
+    var xhr = CouchDB.request("GET", "/"+dbName+"/_design/bin_doc/foo%2Fbar.txt");
+    T(xhr.responseText == "This is a base64 encoded text");
+    T(xhr.status == 200);
+
+    // I mean um, 4 urls
+    var xhr = CouchDB.request("GET", "/"+dbName+"/_design/bin_doc/foo/bar.txt");
+    T(xhr.responseText == "This is a base64 encoded text");
+    T(xhr.status == 200);
+
+    var xhr = CouchDB.request("GET", "/"+dbName+"/_design%2Fbin_doc/foo/baz.txt");
+    T(xhr.status == 404);
+
+    var xhr = CouchDB.request("GET", "/"+dbName+"/_design%2Fbin_doc/foo%252Fbaz.txt");
+    T(xhr.status == 200); 
+    T(xhr.responseText == "We like percent two F.");
+
+    // require a _rev to PUT
+    var xhr = CouchDB.request("PUT", "/"+dbName+"/_design%2Fbin_doc/foo/attachment.txt", {
+      headers:{"Content-Type":"text/plain;charset=utf-8"},
+      body:"Just some text"
+    });
+    T(xhr.status == 409);    
+
+    var xhr = CouchDB.request("PUT", "/"+dbName+"/_design%2Fbin_doc/foo/bar2.txt?rev=" + binAttDoc._rev, {
+      body:"This is no base64 encoded text",
+      headers:{"Content-Type": "text/plain;charset=utf-8"}
+    });
+    T(xhr.status == 201);
+    var rev = JSON.parse(xhr.responseText).rev;
+
+    binAttDoc = db.open("_design/bin_doc");
+
+    T(binAttDoc._attachments["foo/bar.txt"] !== undefined);
+    T(binAttDoc._attachments["foo/bar2.txt"] !== undefined);
+    T(binAttDoc._attachments["foo/bar2.txt"].content_type == "text/plain;charset=utf-8");
+    T(binAttDoc._attachments["foo/bar2.txt"].length == 30);
+  }
+};

Propchange: couchdb/trunk/share/www/script/test/attachment_paths.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: couchdb/trunk/share/www/script/test/attachment_views.js
URL: http://svn.apache.org/viewvc/couchdb/trunk/share/www/script/test/attachment_views.js?rev=744782&view=auto
==============================================================================
--- couchdb/trunk/share/www/script/test/attachment_views.js (added)
+++ couchdb/trunk/share/www/script/test/attachment_views.js Sun Feb 15 23:59:38 2009
@@ -0,0 +1,98 @@
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+couchTests.attachment_views= function(debug) {
+
+  var db = new CouchDB("test_suite_db");
+  db.deleteDb();
+  db.createDb();
+  if (debug) debugger;
+
+  // count attachments in a view
+
+  db.bulkSave(makeDocs(0, 10));
+
+  db.bulkSave(makeDocs(10, 20, {
+    _attachments:{
+      "foo.txt": {
+        content_type:"text/plain",
+        data: "VGhpcyBpcyBhIGJhc2U2NCBlbmNvZGVkIHRleHQ="
+      }
+    }
+  }));
+
+  db.bulkSave(makeDocs(20, 30, {
+    _attachments:{
+      "foo.txt": {
+        content_type:"text/plain",
+        data: "VGhpcyBpcyBhIGJhc2U2NCBlbmNvZGVkIHRleHQ="
+      },
+      "bar.txt": {
+        content_type:"text/plain",
+        data: "VGhpcyBpcyBhIGJhc2U2NCBlbmNvZGVkIHRleHQ="
+      }
+    }
+  }));
+
+  db.bulkSave(makeDocs(30, 40, {
+    _attachments:{
+      "foo.txt": {
+        content_type:"text/plain",
+        data: "VGhpcyBpcyBhIGJhc2U2NCBlbmNvZGVkIHRleHQ="
+      },
+      "bar.txt": {
+        content_type:"text/plain",
+        data: "VGhpcyBpcyBhIGJhc2U2NCBlbmNvZGVkIHRleHQ="
+      },
+      "baz.txt": {
+        content_type:"text/plain",
+        data: "VGhpcyBpcyBhIGJhc2U2NCBlbmNvZGVkIHRleHQ="
+      }
+    }
+  }));
+
+  var mapFunction = function(doc) {
+    var count = 0;
+
+    for(var idx in doc._attachments) {
+      count = count + 1;
+    }
+
+    emit(parseInt(doc._id), count);
+  }
+
+  var reduceFunction = function(key, values) {
+    return sum(values);
+  }
+  
+  var result = db.query(mapFunction, reduceFunction);
+
+  T(result.rows.length == 1);
+  T(result.rows[0].value == 60);
+
+  var result = db.query(mapFunction, reduceFunction, {
+    startkey:10,
+    endkey:19
+  });
+
+  T(result.rows.length == 1);
+  T(result.rows[0].value == 10);
+
+  var result = db.query(mapFunction, reduceFunction, {
+    startkey:20,
+    endkey:29
+  });
+
+  T(result.rows.length == 1);
+  T(result.rows[0].value == 20);
+
+};

Propchange: couchdb/trunk/share/www/script/test/attachment_views.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: couchdb/trunk/share/www/script/test/attachments.js
URL: http://svn.apache.org/viewvc/couchdb/trunk/share/www/script/test/attachments.js?rev=744782&view=auto
==============================================================================
--- couchdb/trunk/share/www/script/test/attachments.js (added)
+++ couchdb/trunk/share/www/script/test/attachments.js Sun Feb 15 23:59:38 2009
@@ -0,0 +1,146 @@
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+couchTests.attachments= function(debug) {
+  var db = new CouchDB("test_suite_db");
+  db.deleteDb();
+  db.createDb();
+  if (debug) debugger;
+
+  var binAttDoc = {
+    _id: "bin_doc",
+    _attachments:{
+      "foo.txt": {
+        content_type:"text/plain",
+        data: "VGhpcyBpcyBhIGJhc2U2NCBlbmNvZGVkIHRleHQ="
+      }
+    }
+  }
+
+  var save_response = db.save(binAttDoc);
+  T(save_response.ok);
+
+  var xhr = CouchDB.request("GET", "/test_suite_db/bin_doc/foo.txt");
+  T(xhr.responseText == "This is a base64 encoded text");
+  T(xhr.getResponseHeader("Content-Type") == "text/plain");
+  T(xhr.getResponseHeader("Etag") == save_response.rev);
+
+  // empty attachment
+  var binAttDoc2 = {
+    _id: "bin_doc2",
+    _attachments:{
+      "foo.txt": {
+        content_type:"text/plain",
+        data: ""
+      }
+    }
+  }
+
+  T(db.save(binAttDoc2).ok);
+
+  var xhr = CouchDB.request("GET", "/test_suite_db/bin_doc2/foo.txt");
+  T(xhr.responseText.length == 0);
+  T(xhr.getResponseHeader("Content-Type") == "text/plain");
+
+  // test RESTful doc API
+
+  var xhr = CouchDB.request("PUT", "/test_suite_db/bin_doc2/foo2.txt?rev=" + binAttDoc2._rev, {
+    body:"This is no base64 encoded text",
+    headers:{"Content-Type": "text/plain;charset=utf-8"}
+  });
+  T(xhr.status == 201);
+  var rev = JSON.parse(xhr.responseText).rev;
+
+  binAttDoc2 = db.open("bin_doc2");
+
+  T(binAttDoc2._attachments["foo.txt"] !== undefined);
+  T(binAttDoc2._attachments["foo2.txt"] !== undefined);
+  T(binAttDoc2._attachments["foo2.txt"].content_type == "text/plain;charset=utf-8");
+  T(binAttDoc2._attachments["foo2.txt"].length == 30);
+
+  var xhr = CouchDB.request("GET", "/test_suite_db/bin_doc2/foo2.txt");
+  T(xhr.responseText == "This is no base64 encoded text");
+  T(xhr.getResponseHeader("Content-Type") == "text/plain;charset=utf-8");
+  
+  // test without rev, should fail
+  var xhr = CouchDB.request("DELETE", "/test_suite_db/bin_doc2/foo2.txt");
+  T(xhr.status == 409);
+
+  // test with rev, should not fail
+  var xhr = CouchDB.request("DELETE", "/test_suite_db/bin_doc2/foo2.txt?rev=" + rev);
+  T(xhr.status == 200);
+  
+  
+  // test binary data
+  var bin_data = "JHAPDO*AU£PN ){(3u[d 93DQ9¡€])}    ææøo'∂ƒæ≤çæππ•¥∫¶®#†π¶®¥π€ª®˙π8np";
+  var xhr = CouchDB.request("PUT", "/test_suite_db/bin_doc3/attachment.txt", {
+    headers:{"Content-Type":"text/plain;charset=utf-8"},
+    body:bin_data
+  });
+  T(xhr.status == 201);
+  var rev = JSON.parse(xhr.responseText).rev;
+  
+  var xhr = CouchDB.request("GET", "/test_suite_db/bin_doc3/attachment.txt");
+  T(xhr.responseText == bin_data);
+  T(xhr.getResponseHeader("Content-Type") == "text/plain;charset=utf-8");
+  
+  var xhr = CouchDB.request("PUT", "/test_suite_db/bin_doc3/attachment.txt", {
+    headers:{"Content-Type":"text/plain;charset=utf-8"},
+    body:bin_data
+  });
+  T(xhr.status == 409);
+
+  var xhr = CouchDB.request("PUT", "/test_suite_db/bin_doc3/attachment.txt?rev=" + rev, {
+    headers:{"Content-Type":"text/plain;charset=utf-8"},
+    body:bin_data
+  });
+  T(xhr.status == 201);
+  var rev = JSON.parse(xhr.responseText).rev;
+
+  var xhr = CouchDB.request("GET", "/test_suite_db/bin_doc3/attachment.txt");
+  T(xhr.responseText == bin_data);
+  T(xhr.getResponseHeader("Content-Type") == "text/plain;charset=utf-8");
+
+  var xhr = CouchDB.request("GET", "/test_suite_db/bin_doc3/attachment.txt?rev=" + rev);
+  T(xhr.responseText == bin_data);
+  T(xhr.getResponseHeader("Content-Type") == "text/plain;charset=utf-8");
+
+  var xhr = CouchDB.request("DELETE", "/test_suite_db/bin_doc3/attachment.txt?rev=" + rev);
+  T(xhr.status == 200);
+  
+  var xhr = CouchDB.request("GET", "/test_suite_db/bin_doc3/attachment.txt?rev=" + rev);
+  T(xhr.status == 404);
+
+  // empty attachments
+  var xhr = CouchDB.request("PUT", "/test_suite_db/bin_doc4/attachment.txt", {
+    headers:{"Content-Type":"text/plain;charset=utf-8"},
+    body:""
+  });
+  T(xhr.status == 201);
+  var rev = JSON.parse(xhr.responseText).rev;
+
+  var xhr = CouchDB.request("GET", "/test_suite_db/bin_doc4/attachment.txt");
+  T(xhr.status == 200);
+  T(xhr.responseText.length == 0);
+  
+  // overwrite previsously empty attachment
+  var xhr = CouchDB.request("PUT", "/test_suite_db/bin_doc4/attachment.txt?rev=" + rev, {
+    headers:{"Content-Type":"text/plain;charset=utf-8"},
+    body:"This is a string"
+  });
+  T(xhr.status == 201);
+
+  var xhr = CouchDB.request("GET", "/test_suite_db/bin_doc4/attachment.txt");
+  T(xhr.status == 200);
+  T(xhr.responseText == "This is a string");
+
+};

Propchange: couchdb/trunk/share/www/script/test/attachments.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: couchdb/trunk/share/www/script/test/basics.js
URL: http://svn.apache.org/viewvc/couchdb/trunk/share/www/script/test/basics.js?rev=744782&view=auto
==============================================================================
--- couchdb/trunk/share/www/script/test/basics.js (added)
+++ couchdb/trunk/share/www/script/test/basics.js Sun Feb 15 23:59:38 2009
@@ -0,0 +1,144 @@
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+// Do some basic tests.
+couchTests.basics = function(debug) {
+    var result = JSON.parse(CouchDB.request("GET", "/").responseText);
+    T(result.couchdb == "Welcome"); 
+    
+    var db = new CouchDB("test_suite_db");
+    db.deleteDb();
+
+    // bug COUCHDB-100: DELETE on non-existent DB returns 500 instead of 404
+    db.deleteDb();
+    
+db.createDb();
+
+    // PUT on existing DB should return 412 instead of 500
+    xhr = CouchDB.request("PUT", "/test_suite_db/");
+    T(xhr.status == 412);
+    if (debug) debugger;
+
+    // Get the database info, check the db_name
+    T(db.info().db_name == "test_suite_db");
+
+    // Get the database info, check the doc_count
+    T(db.info().doc_count == 0);
+
+    // create a document and save it to the database
+    var doc = {_id:"0",a:1,b:1};
+    var result = db.save(doc);
+
+    T(result.ok==true); // return object has an ok member with a value true
+    T(result.id); // the _id of the document is set.
+    T(result.rev); // the revision id of the document is set.
+
+    // Verify the input doc is now set with the doc id and rev
+    // (for caller convenience).
+    T(doc._id == result.id && doc._rev == result.rev);
+
+    var id = result.id; // save off the id for later
+
+    // make sure the revs_info status is good
+    var doc = db.open(id, {revs_info:true});
+    T(doc._revs_info[0].status == "available");
+
+    // Create some more documents.
+    // Notice the use of the ok member on the return result.
+    T(db.save({_id:"1",a:2,b:4}).ok);
+    T(db.save({_id:"2",a:3,b:9}).ok);
+    T(db.save({_id:"3",a:4,b:16}).ok);
+
+    // Check the database doc count
+    T(db.info().doc_count == 4);
+
+    // Test a simple map functions
+
+    // create a map function that selects all documents whose "a" member
+    // has a value of 4, and then returns the document's b value.
+    var mapFunction = function(doc){
+      if (doc.a==4)
+        emit(null, doc.b);
+    };
+
+    results = db.query(mapFunction);
+
+    // verify only one document found and the result value (doc.b).
+    T(results.total_rows == 1 && results.rows[0].value == 16);
+
+    // reopen document we saved earlier
+    existingDoc = db.open(id);
+
+    T(existingDoc.a==1);
+
+    //modify and save
+    existingDoc.a=4;
+    db.save(existingDoc);
+
+    // redo the map query
+    results = db.query(mapFunction);
+
+    // the modified document should now be in the results.
+    T(results.total_rows == 2);
+
+    // write 2 more documents
+    T(db.save({a:3,b:9}).ok);
+    T(db.save({a:4,b:16}).ok);
+
+    results = db.query(mapFunction);
+
+    // 1 more document should now be in the result.
+    T(results.total_rows == 3);
+    T(db.info().doc_count == 6);
+
+    var reduceFunction = function(keys, values){
+      return sum(values);
+    };
+
+    results = db.query(mapFunction, reduceFunction);
+
+    T(results.rows[0].value == 33);
+
+    // delete a document
+    T(db.deleteDoc(existingDoc).ok);
+
+    // make sure we can't open the doc
+    T(db.open(existingDoc._id) == null);
+
+    results = db.query(mapFunction);
+
+    // 1 less document should now be in the results.
+    T(results.total_rows == 2);
+    T(db.info().doc_count == 5);
+
+    // make sure we can still open the old rev of the deleted doc
+    T(db.open(existingDoc._id, {rev: existingDoc._rev}) != null);
+    
+    // make sure restart works
+    T(db.ensureFullCommit().ok);
+    restartServer();
+    
+    // make sure we can still open
+    T(db.open(existingDoc._id, {rev: existingDoc._rev}) != null);
+    
+    // test that the POST response has a Location header
+    var xhr = CouchDB.request("POST", "/test_suite_db", {
+      body: JSON.stringify({"foo":"bar"})
+    });
+    var resp = JSON.parse(xhr.responseText);
+    T(resp.ok);
+    var loc = xhr.getResponseHeader("Location");
+    T(loc, "should have a Location header");
+    var locs = loc.split('/');
+    T(locs[4] == resp.id);
+    T(locs[3] == "test_suite_db");    
+  };

Propchange: couchdb/trunk/share/www/script/test/basics.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: couchdb/trunk/share/www/script/test/bulk_docs.js
URL: http://svn.apache.org/viewvc/couchdb/trunk/share/www/script/test/bulk_docs.js?rev=744782&view=auto
==============================================================================
--- couchdb/trunk/share/www/script/test/bulk_docs.js (added)
+++ couchdb/trunk/share/www/script/test/bulk_docs.js Sun Feb 15 23:59:38 2009
@@ -0,0 +1,56 @@
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+couchTests.bulk_docs = function(debug) {
+  var db = new CouchDB("test_suite_db");
+  db.deleteDb();
+  db.createDb();
+  if (debug) debugger;
+
+  var docs = makeDocs(5);
+
+  // Create the docs
+  var result = db.bulkSave(docs);
+  T(result.ok);
+  T(result.new_revs.length == 5);
+  for (var i = 0; i < 5; i++) {
+    T(result.new_revs[i].id == docs[i]._id);
+    T(result.new_revs[i].rev);
+    docs[i].string = docs[i].string + ".00";
+  }
+
+  // Update the docs
+  result = db.bulkSave(docs);
+  T(result.ok);
+  T(result.new_revs.length == 5);
+  for (i = 0; i < 5; i++) {
+    T(result.new_revs[i].id == i.toString());
+    docs[i]._deleted = true;
+  }
+
+  // Delete the docs
+  result = db.bulkSave(docs);
+  T(result.ok);
+  T(result.new_revs.length == 5);
+  for (i = 0; i < 5; i++) {
+    T(db.open(docs[i]._id) == null);
+  }
+  
+  // verify creating a document with no id returns a new id
+  var req = CouchDB.request("POST", "/test_suite_db/_bulk_docs", {
+    body: JSON.stringify({"docs": [{"foo":"bar"}]})
+  });
+  result = JSON.parse(req.responseText);
+  
+  T(result.new_revs[0].id != "");
+  T(result.new_revs[0].rev != "");
+};

Propchange: couchdb/trunk/share/www/script/test/bulk_docs.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: couchdb/trunk/share/www/script/test/compact.js
URL: http://svn.apache.org/viewvc/couchdb/trunk/share/www/script/test/compact.js?rev=744782&view=auto
==============================================================================
--- couchdb/trunk/share/www/script/test/compact.js (added)
+++ couchdb/trunk/share/www/script/test/compact.js Sun Feb 15 23:59:38 2009
@@ -0,0 +1,56 @@
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+couchTests.compact = function(debug) {
+  var db = new CouchDB("test_suite_db");
+  db.deleteDb();
+  db.createDb();
+  if (debug) debugger;
+  var docs = makeDocs(0, 10);
+  var saveResult = db.bulkSave(docs);
+  T(saveResult.ok);
+
+  var binAttDoc = {
+    _id: "bin_doc",
+    _attachments:{
+      "foo.txt": {
+        content_type:"text/plain",
+        data: "VGhpcyBpcyBhIGJhc2U2NCBlbmNvZGVkIHRleHQ="
+      }
+    }
+  }
+
+  T(db.save(binAttDoc).ok);
+
+  var originalsize = db.info().disk_size;
+
+  for(var i in docs) {
+      db.deleteDoc(docs[i]);
+  }
+  db.setAdmins(["Foo bar"]);
+  var deletesize = db.info().disk_size;
+  T(deletesize > originalsize);
+
+  var xhr = CouchDB.request("POST", "/test_suite_db/_compact");
+  T(xhr.status == 202);
+  // compaction isn't instantaneous, loop until done
+  while (db.info().compact_running) {};
+  
+  T(db.ensureFullCommit().ok);
+  restartServer();
+  var xhr = CouchDB.request("GET", "/test_suite_db/bin_doc/foo.txt");
+  T(xhr.responseText == "This is a base64 encoded text")
+  T(xhr.getResponseHeader("Content-Type") == "text/plain")
+  T(db.info().doc_count == 1);
+  T(db.info().disk_size < deletesize);
+  
+};

Propchange: couchdb/trunk/share/www/script/test/compact.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: couchdb/trunk/share/www/script/test/config.js
URL: http://svn.apache.org/viewvc/couchdb/trunk/share/www/script/test/config.js?rev=744782&view=auto
==============================================================================
--- couchdb/trunk/share/www/script/test/config.js (added)
+++ couchdb/trunk/share/www/script/test/config.js Sun Feb 15 23:59:38 2009
@@ -0,0 +1,66 @@
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+couchTests.config = function(debug) {
+  var db = new CouchDB("test_suite_db");
+  db.deleteDb();
+  db.createDb();
+  if (debug) debugger;
+  
+  // test that /_config returns all the settings
+  var xhr = CouchDB.request("GET", "/_config");
+  var config = JSON.parse(xhr.responseText);
+
+  /*
+    if we run on standard ports, we can't extract
+    the number from the URL. Instead we try to guess
+    from the protocol what port we are running on.
+    If we can't guess, we don't test for the port.
+    Overengineering FTW.
+  */
+  var server_port = CouchDB.host.split(':');
+  if(server_port.length == 1 && CouchDB.inBrowser) {
+    var proto = window.location.protocol;
+    if(proto == "http:") {
+      port = 80;
+    }
+    if(proto == "https:") {
+      port = 443;
+    }
+  } else {
+    port = server_port.pop();
+  }
+
+  if(port) {
+    T(config.httpd.port == port);
+  }
+
+  T(config.couchdb.database_dir);
+  T(config.daemons.httpd);
+  T(config.httpd_global_handlers._config);
+  T(config.log.level);
+  T(config.query_servers.javascript);
+  
+  // test that settings can be altered
+  xhr = CouchDB.request("PUT", "/_config/test/foo",{
+    body : JSON.stringify("bar"),
+    headers: {"X-Couch-Persist": "false"}
+  });
+  T(xhr.status == 200);
+  xhr = CouchDB.request("GET", "/_config/test");
+  config = JSON.parse(xhr.responseText);
+  T(config.foo == "bar");
+
+  // you can get a single key
+  xhr = CouchDB.request("GET", "/_config/test/foo");
+  T(xhr.responseText == '"bar"');
+};

Propchange: couchdb/trunk/share/www/script/test/config.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: couchdb/trunk/share/www/script/test/conflicts.js
URL: http://svn.apache.org/viewvc/couchdb/trunk/share/www/script/test/conflicts.js?rev=744782&view=auto
==============================================================================
--- couchdb/trunk/share/www/script/test/conflicts.js (added)
+++ couchdb/trunk/share/www/script/test/conflicts.js Sun Feb 15 23:59:38 2009
@@ -0,0 +1,60 @@
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+// Do some edit conflict detection tests
+couchTests.conflicts = function(debug) {
+  var db = new CouchDB("test_suite_db");
+  db.deleteDb();
+  db.createDb();
+  if (debug) debugger;
+
+  // create a doc and save
+  var doc = {_id:"foo",a:1,b:1};
+  T(db.save(doc).ok);
+
+  // reopen
+  var doc2 = db.open(doc._id);
+
+  // ensure the revisions are the same
+  T(doc._id == doc2._id && doc._rev == doc2._rev);
+
+  // edit the documents.
+  doc.a = 2;
+  doc2.a = 3;
+
+  // save one document
+  T(db.save(doc).ok);
+
+  // save the other document
+  try {
+    db.save(doc2);  // this should generate a conflict exception
+    T("no save conflict 1" && false); // we shouldn't hit here
+  } catch (e) {
+    T(e.error == "conflict");
+  }
+
+  // Now clear out the _rev member and save. This indicates this document is
+  // new, not based on an existing revision.
+  doc2._rev = undefined;
+  try {
+    db.save(doc2); // this should generate a conflict exception
+    T("no save conflict 2" && false); // we shouldn't hit here
+  } catch (e) {
+    T(e.error == "conflict");
+  }
+
+  // Now delete the document from the database
+  T(db.deleteDoc(doc).ok);
+
+  T(db.save(doc2).ok);  // we can save a new document over a deletion without
+                        // knowing the deletion rev.
+};

Propchange: couchdb/trunk/share/www/script/test/conflicts.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: couchdb/trunk/share/www/script/test/content_negotiation.js
URL: http://svn.apache.org/viewvc/couchdb/trunk/share/www/script/test/content_negotiation.js?rev=744782&view=auto
==============================================================================
--- couchdb/trunk/share/www/script/test/content_negotiation.js (added)
+++ couchdb/trunk/share/www/script/test/content_negotiation.js Sun Feb 15 23:59:38 2009
@@ -0,0 +1,32 @@
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+couchTests.content_negotiation = function(debug) {
+  var db = new CouchDB("test_suite_db");
+  db.deleteDb();
+  db.createDb();
+  if (debug) debugger;
+  var xhr;
+
+  xhr = CouchDB.request("GET", "/test_suite_db/");
+  T(xhr.getResponseHeader("Content-Type") == "text/plain;charset=utf-8");
+
+  xhr = CouchDB.request("GET", "/test_suite_db/", {
+    headers: {"Accept": "text/html;text/plain;*/*"}
+  });
+  T(xhr.getResponseHeader("Content-Type") == "text/plain;charset=utf-8");
+
+  xhr = CouchDB.request("GET", "/test_suite_db/", {
+    headers: {"Accept": "application/json"}
+  });
+  T(xhr.getResponseHeader("Content-Type") == "application/json");
+};

Propchange: couchdb/trunk/share/www/script/test/content_negotiation.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: couchdb/trunk/share/www/script/test/copy_move_doc.js
URL: http://svn.apache.org/viewvc/couchdb/trunk/share/www/script/test/copy_move_doc.js?rev=744782&view=auto
==============================================================================
--- couchdb/trunk/share/www/script/test/copy_move_doc.js (added)
+++ couchdb/trunk/share/www/script/test/copy_move_doc.js Sun Feb 15 23:59:38 2009
@@ -0,0 +1,65 @@
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+couchTests.copy_move_doc = function(debug) {
+  var db = new CouchDB("test_suite_db");
+  db.deleteDb();
+  db.createDb();
+  if (debug) debugger;
+
+  // copy a doc
+  T(db.save({_id:"doc_to_be_copied",v:1}).ok);
+  var xhr = CouchDB.request("COPY", "/test_suite_db/doc_to_be_copied", {
+    headers: {"Destination":"doc_that_was_copied"}
+  });
+
+  T(xhr.status == 201);
+  T(db.open("doc_that_was_copied").v == 1);
+
+  // move a doc
+
+  // test error condition
+  var xhr = CouchDB.request("MOVE", "/test_suite_db/doc_to_be_copied", {
+    headers: {"Destination":"doc_that_was_moved"}
+  });
+  T(xhr.status == 400); // bad request, MOVE requires source rev.
+
+  var rev = db.open("doc_to_be_copied")._rev;
+  var xhr = CouchDB.request("MOVE", "/test_suite_db/doc_to_be_copied?rev=" + rev, {
+    headers: {"Destination":"doc_that_was_moved"}
+  });
+
+  T(xhr.status == 201);
+  T(db.open("doc_that_was_moved").v == 1);
+  T(db.open("doc_to_be_copied") == null);
+
+  // COPY with existing target
+  T(db.save({_id:"doc_to_be_copied",v:1}).ok);
+  var doc = db.save({_id:"doc_to_be_overwritten",v:2});
+  T(doc.ok);
+
+  // error condition
+  var xhr = CouchDB.request("COPY", "/test_suite_db/doc_to_be_copied", {
+      headers: {"Destination":"doc_to_be_overwritten"}
+  });
+  T(xhr.status == 409); // conflict
+
+  var rev = db.open("doc_to_be_overwritten")._rev;
+  var xhr = CouchDB.request("COPY", "/test_suite_db/doc_to_be_copied", {
+    headers: {"Destination":"doc_to_be_overwritten?rev=" + rev}
+  });
+  T(xhr.status == 201);
+
+  var over = db.open("doc_to_be_overwritten");
+  T(rev != over._rev);
+  T(over.v == 1);
+};

Propchange: couchdb/trunk/share/www/script/test/copy_move_doc.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: couchdb/trunk/share/www/script/test/delayed_commits.js
URL: http://svn.apache.org/viewvc/couchdb/trunk/share/www/script/test/delayed_commits.js?rev=744782&view=auto
==============================================================================
--- couchdb/trunk/share/www/script/test/delayed_commits.js (added)
+++ couchdb/trunk/share/www/script/test/delayed_commits.js Sun Feb 15 23:59:38 2009
@@ -0,0 +1,93 @@
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+couchTests.delayed_commits = function(debug) {
+  var db = new CouchDB("test_suite_db");
+  db.deleteDb();
+  db.createDb();
+  if (debug) debugger;
+  
+  // By default, couchdb doesn't fully commit documents to disk right away,
+  // it waits about a second to batch the full commit flush along with any 
+  // other updates. If it crashes or is restarted you may lose the most
+  // recent commits.
+  
+  T(db.save({_id:"1",a:2,b:4}).ok);
+  T(db.open("1") != null);
+  
+  restartServer();
+  
+  T(db.open("1") == null); // lost the update.
+  // note if we waited > 1 sec before the restart, the doc would likely
+  // commit.
+  
+  
+  // Retry the same thing but with full commits on.
+  
+  var db2 = new CouchDB("test_suite_db", {"X-Couch-Full-Commit":"true"});
+  
+  T(db2.save({_id:"1",a:2,b:4}).ok);
+  T(db2.open("1") != null);
+  
+  restartServer();
+  
+  T(db2.open("1") != null);
+  
+  // You can update but without committing immediately, and then ensure
+  // everything is commited in the last step.
+  
+  T(db.save({_id:"2",a:2,b:4}).ok);
+  T(db.open("2") != null);
+  T(db.ensureFullCommit().ok);
+  restartServer();
+  
+  T(db.open("2") != null);
+  
+  // However, it's possible even when flushed, that the server crashed between
+  // the update and the commit, and you don't want to check to make sure
+  // every doc you updated actually made it to disk. So record the instance
+  // start time of the database before the updates and then check it again
+  // after the flush (the instance start time is returned by the flush
+  // operation). if they are the same, we know everything was updated
+  // safely.
+  
+  // First try it with a crash.
+  
+  var instanceStartTime = db.info().instance_start_time;
+  
+  T(db.save({_id:"3",a:2,b:4}).ok);
+  T(db.open("3") != null);
+  
+  restartServer();
+  
+  var commitResult = db.ensureFullCommit();
+  T(commitResult.ok && commitResult.instance_start_time != instanceStartTime);
+  // start times don't match, meaning the server lost our change
+  
+  T(db.open("3") == null); // yup lost it
+  
+  // retry with no server restart
+  
+  var instanceStartTime = db.info().instance_start_time;
+  
+  T(db.save({_id:"4",a:2,b:4}).ok);
+  T(db.open("4") != null);
+  
+  var commitResult = db.ensureFullCommit();
+  T(commitResult.ok && commitResult.instance_start_time == instanceStartTime);
+  // Successful commit, start times match!
+  
+  restartServer();
+  
+  T(db.open("4") != null);
+  
+};

Propchange: couchdb/trunk/share/www/script/test/delayed_commits.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: couchdb/trunk/share/www/script/test/design_docs.js
URL: http://svn.apache.org/viewvc/couchdb/trunk/share/www/script/test/design_docs.js?rev=744782&view=auto
==============================================================================
--- couchdb/trunk/share/www/script/test/design_docs.js (added)
+++ couchdb/trunk/share/www/script/test/design_docs.js Sun Feb 15 23:59:38 2009
@@ -0,0 +1,107 @@
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+couchTests.design_docs = function(debug) {
+  var db = new CouchDB("test_suite_db");
+  db.deleteDb();
+  db.createDb();
+  if (debug) debugger;
+
+  var numDocs = 500;
+
+  function makebigstring(power) {
+    var str = "a";
+    while(power-- > 0) {
+      str = str + str;
+    }
+    return str;
+  }
+
+  var designDoc = {
+    _id:"_design/test", // turn off couch.js id escaping?
+    language: "javascript",
+    views: {
+      all_docs_twice: {map: "function(doc) { emit(doc.integer, null); emit(doc.integer, null) }"},
+      no_docs: {map: "function(doc) {}"},
+      single_doc: {map: "function(doc) { if (doc._id == \"1\") { emit(1, null) }}"},
+      summate: {map:"function (doc) {emit(doc.integer, doc.integer)};",
+                reduce:"function (keys, values) { return sum(values); };"},
+      summate2: {map:"function (doc) {emit(doc.integer, doc.integer)};",
+                reduce:"function (keys, values) { return sum(values); };"},
+      huge_src_and_results: {map: "function(doc) { if (doc._id == \"1\") { emit(\"" + makebigstring(16) + "\", null) }}",
+                reduce:"function (keys, values) { return \"" + makebigstring(16) + "\"; };"}
+    }
+  }
+  T(db.save(designDoc).ok);
+
+  T(db.bulkSave(makeDocs(1, numDocs + 1)).ok);
+
+  // test that the _all_docs view returns correctly with keys
+  var results = db.allDocs({startkey:"_design", endkey:"_design0"});
+  T(results.rows.length == 1);
+
+  for (var loop = 0; loop < 2; loop++) {
+    var rows = db.view("test/all_docs_twice").rows;
+    for (var i = 0; i < numDocs; i++) {
+      T(rows[2*i].key == i+1);
+      T(rows[(2*i)+1].key == i+1);
+    }
+    T(db.view("test/no_docs").total_rows == 0)
+    T(db.view("test/single_doc").total_rows == 1)
+    T(db.ensureFullCommit().ok);
+    restartServer();
+  };
+  
+  // test when language not specified, Javascript is implied
+  var designDoc2 = {
+    _id:"_design/test2",
+    // language: "javascript", 
+    views: {
+      single_doc: {map: "function(doc) { if (doc._id == \"1\") { emit(1, null) }}"}
+    }
+  };
+  
+  T(db.save(designDoc2).ok);
+  T(db.view("test2/single_doc").total_rows == 1);
+
+  var summate = function(N) {return (N+1)*N/2;};
+  var result = db.view("test/summate");
+  T(result.rows[0].value == summate(numDocs));
+
+  result = db.view("test/summate", {startkey:4,endkey:4});
+  T(result.rows[0].value == 4);
+
+  result = db.view("test/summate", {startkey:4,endkey:5});
+  T(result.rows[0].value == 9);
+
+  result = db.view("test/summate", {startkey:4,endkey:6});
+  T(result.rows[0].value == 15);
+
+  // Verify that a shared index (view def is an exact copy of "summate")
+  // does not confuse the reduce stage
+  result = db.view("test/summate2", {startkey:4,endkey:6});
+  T(result.rows[0].value == 15);
+
+  for(var i=1; i<numDocs/2; i+=30) {
+    result = db.view("test/summate", {startkey:i,endkey:numDocs-i});
+    T(result.rows[0].value == summate(numDocs-i) - summate(i-1));
+  }
+
+  T(db.deleteDoc(designDoc).ok);
+  T(db.open(designDoc._id) == null);
+  T(db.view("test/no_docs") == null);
+  
+  T(db.ensureFullCommit().ok);
+  restartServer();
+  T(db.open(designDoc._id) == null);
+  T(db.view("test/no_docs") == null);
+};

Propchange: couchdb/trunk/share/www/script/test/design_docs.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: couchdb/trunk/share/www/script/test/design_options.js
URL: http://svn.apache.org/viewvc/couchdb/trunk/share/www/script/test/design_options.js?rev=744782&view=auto
==============================================================================
--- couchdb/trunk/share/www/script/test/design_options.js (added)
+++ couchdb/trunk/share/www/script/test/design_options.js Sun Feb 15 23:59:38 2009
@@ -0,0 +1,63 @@
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+couchTests.design_options = function(debug) {
+  var db = new CouchDB("test_suite_db");
+  db.deleteDb();
+  db.createDb();
+  if (debug) debugger;
+
+  //// test the includes_design option
+  var map = "function (doc) {emit(null, doc._id);}";
+
+  // we need a design doc even to test temp views with it
+  var designDoc = {
+    _id:"_design/fu",
+    language: "javascript",
+    options: {
+      include_design: true        
+    },
+    views: {
+      data: {"map": map}
+    }
+  };
+  T(db.save(designDoc).ok);
+
+  // should work for temp views
+  var rows = db.query(map, null, {options:{include_design: true}}).rows;
+  T(rows.length == 1);
+  T(rows[0].value == "_design/fu");
+
+  rows = db.query(map).rows;
+  T(rows.length == 0);
+
+  // when true, should include design docs in views
+  rows = db.view("fu/data").rows;
+  T(rows.length == 1);
+  T(rows[0].value == "_design/fu");
+
+  // when false, should not
+  designDoc.options.include_design = false;
+  delete designDoc._rev;
+  designDoc._id = "_design/bingo";
+  T(db.save(designDoc).ok);
+  rows = db.view("bingo/data").rows;
+  T(rows.length == 0);
+
+  // should default to false
+  delete designDoc.options;
+  delete designDoc._rev;
+  designDoc._id = "_design/bango";
+  T(db.save(designDoc).ok);
+  rows = db.view("bango/data").rows;
+  T(rows.length == 0);
+};

Propchange: couchdb/trunk/share/www/script/test/design_options.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: couchdb/trunk/share/www/script/test/design_paths.js
URL: http://svn.apache.org/viewvc/couchdb/trunk/share/www/script/test/design_paths.js?rev=744782&view=auto
==============================================================================
--- couchdb/trunk/share/www/script/test/design_paths.js (added)
+++ couchdb/trunk/share/www/script/test/design_paths.js Sun Feb 15 23:59:38 2009
@@ -0,0 +1,72 @@
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+couchTests.design_paths = function(debug) {
+  if (debug) debugger;
+  var dbNames = ["test_suite_db", "test_suite_db/with_slashes"];
+  for (var i=0; i < dbNames.length; i++) {
+    var db = new CouchDB(dbNames[i]);
+    var dbName = encodeURIComponent(dbNames[i]);
+    db.deleteDb();
+    db.createDb();
+    
+    // create a ddoc w bulk_docs
+    db.bulkSave([{
+      _id : "_design/test",
+      views : {
+        "testing" : {
+          "map" : "function(){emit(1,1)}"
+        }
+      }
+    }]);
+
+    // ddoc is getable
+    var xhr = CouchDB.request("GET", "/"+dbName+"/_design/test");
+    var resp = JSON.parse(xhr.responseText);
+    T(resp._id == "_design/test");
+
+    // it's at 2 urls...
+    var xhr = CouchDB.request("GET", "/"+dbName+"/_design%2Ftest");
+    var resp = JSON.parse(xhr.responseText);
+    T(resp._id == "_design/test");
+
+    // ensure that views are addressable
+    resp = db.view("test/testing")
+    T(resp.total_rows == 0)
+
+    // create a ddoc by putting to url with raw slash
+    var xhr = CouchDB.request("PUT", "/"+dbName+"/_design/test2",{
+      body : JSON.stringify({
+        _id : "_design/test2",
+        views : {
+          "testing" : {
+            "map" : "function(){emit(1,1)}"
+          }
+        }
+      })
+    });
+
+    // ddoc is getable
+    var xhr = CouchDB.request("GET", "/"+dbName+"/_design/test2");
+    var resp = JSON.parse(xhr.responseText);
+    T(resp._id == "_design/test2");
+
+    // it's at 2 urls...
+    var xhr = CouchDB.request("GET", "/"+dbName+"/_design%2Ftest2");
+    var resp = JSON.parse(xhr.responseText);
+    T(resp._id == "_design/test2");
+
+    // ensure that views are addressable
+    resp = db.view("test2/testing");
+    T(resp.total_rows == 0);
+  };
+};

Propchange: couchdb/trunk/share/www/script/test/design_paths.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: couchdb/trunk/share/www/script/test/etags_head.js
URL: http://svn.apache.org/viewvc/couchdb/trunk/share/www/script/test/etags_head.js?rev=744782&view=auto
==============================================================================
--- couchdb/trunk/share/www/script/test/etags_head.js (added)
+++ couchdb/trunk/share/www/script/test/etags_head.js Sun Feb 15 23:59:38 2009
@@ -0,0 +1,78 @@
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+couchTests.etags_head = function(debug) {
+  var db = new CouchDB("test_suite_db");
+  db.deleteDb();
+  db.createDb();
+  if (debug) debugger;
+
+  var xhr;
+
+  // create a new doc
+  xhr = CouchDB.request("PUT", "/test_suite_db/1", {
+    body: "{}"
+  });
+  T(xhr.status == 201);
+
+  // extract the ETag header values
+  var etag = xhr.getResponseHeader("etag");
+
+  // get the doc and verify the headers match
+  xhr = CouchDB.request("GET", "/test_suite_db/1");
+  T(etag == xhr.getResponseHeader("etag"));
+
+  // 'head' the doc and verify the headers match
+  xhr = CouchDB.request("HEAD", "/test_suite_db/1", {
+    headers: {"if-none-match": "s"}
+  });
+  T(etag == xhr.getResponseHeader("etag"));
+
+  // replace a doc
+  xhr = CouchDB.request("PUT", "/test_suite_db/1", {
+    body: "{}",
+    headers: {"if-match": etag}
+  });
+  T(xhr.status == 201);
+
+  // extract the new ETag value
+  var etagOld= etag;
+  etag = xhr.getResponseHeader("etag");
+
+  // fail to replace a doc
+  xhr = CouchDB.request("PUT", "/test_suite_db/1", {
+    body: "{}"
+  });
+  T(xhr.status == 409);
+
+  // verify get w/Etag
+  xhr = CouchDB.request("GET", "/test_suite_db/1", {
+    headers: {"if-none-match": etagOld}
+  });
+  T(xhr.status == 200);
+  xhr = CouchDB.request("GET", "/test_suite_db/1", {
+    headers: {"if-none-match": etag}
+  });
+  T(xhr.status == 304);
+
+  // fail to delete a doc
+  xhr = CouchDB.request("DELETE", "/test_suite_db/1", {
+    headers: {"if-match": etagOld}
+  });
+  T(xhr.status == 409);
+
+  //now do it for real
+  xhr = CouchDB.request("DELETE", "/test_suite_db/1", {
+    headers: {"if-match": etag}
+  });
+  T(xhr.status == 200);
+};

Propchange: couchdb/trunk/share/www/script/test/etags_head.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: couchdb/trunk/share/www/script/test/etags_views.js
URL: http://svn.apache.org/viewvc/couchdb/trunk/share/www/script/test/etags_views.js?rev=744782&view=auto
==============================================================================
--- couchdb/trunk/share/www/script/test/etags_views.js (added)
+++ couchdb/trunk/share/www/script/test/etags_views.js Sun Feb 15 23:59:38 2009
@@ -0,0 +1,87 @@
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+couchTests.etags_views = function(debug) {
+  var db = new CouchDB("test_suite_db");
+  db.deleteDb();
+  db.createDb();
+  if (debug) debugger;
+  
+  var designDoc = {
+    _id:"_design/etags",
+    language: "javascript",
+    views : {
+      basicView : {
+        map : stringFun(function(doc) {
+          emit(doc.integer, doc.string);
+        })
+      },
+      withReduce : {
+        map : stringFun(function(doc) {
+          emit(doc.integer, doc.string);
+        }),
+        reduce : stringFun(function(keys, values, rereduce) {
+          if (rereduce) {
+            return sum(values);
+          } else {
+            return values.length;
+          }
+        })
+      }
+    }
+  }
+  T(db.save(designDoc).ok);
+  var xhr;
+  var docs = makeDocs(0, 10);
+  var saveResult = db.bulkSave(docs);
+  T(saveResult.ok);
+  
+  // verify get w/Etag on map view
+  xhr = CouchDB.request("GET", "/test_suite_db/_view/etags/basicView");
+  T(xhr.status == 200);
+  var etag = xhr.getResponseHeader("etag");
+  xhr = CouchDB.request("GET", "/test_suite_db/_view/etags/basicView", {
+    headers: {"if-none-match": etag}
+  });
+  T(xhr.status == 304);
+  // TODO GET with keys (when that is available)
+  
+  // reduce view
+  xhr = CouchDB.request("GET", "/test_suite_db/_view/etags/withReduce");
+  T(xhr.status == 200);
+  var etag = xhr.getResponseHeader("etag");
+  xhr = CouchDB.request("GET", "/test_suite_db/_view/etags/withReduce", {
+    headers: {"if-none-match": etag}
+  });
+  T(xhr.status == 304);
+  
+  // all docs
+  xhr = CouchDB.request("GET", "/test_suite_db/_all_docs");
+  T(xhr.status == 200);
+  var etag = xhr.getResponseHeader("etag");
+  xhr = CouchDB.request("GET", "/test_suite_db/_all_docs", {
+    headers: {"if-none-match": etag}
+  });
+  T(xhr.status == 304);
+
+  // by seq
+  xhr = CouchDB.request("GET", "/test_suite_db/_all_docs_by_seq");
+  T(xhr.status == 200);
+  var etag = xhr.getResponseHeader("etag");
+  xhr = CouchDB.request("GET", "/test_suite_db/_all_docs_by_seq", {
+    headers: {"if-none-match": etag}
+  });
+  T(xhr.status == 304);    
+
+  // list etag
+  // in the list test for now
+};

Propchange: couchdb/trunk/share/www/script/test/etags_views.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: couchdb/trunk/share/www/script/test/invalid_docids.js
URL: http://svn.apache.org/viewvc/couchdb/trunk/share/www/script/test/invalid_docids.js?rev=744782&view=auto
==============================================================================
--- couchdb/trunk/share/www/script/test/invalid_docids.js (added)
+++ couchdb/trunk/share/www/script/test/invalid_docids.js Sun Feb 15 23:59:38 2009
@@ -0,0 +1,54 @@
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+couchTests.invalid_docids = function(debug) {
+  var db = new CouchDB("test_suite_db");
+  db.deleteDb();
+  db.createDb();
+  if (debug) debugger;
+
+  // Test _local explicitly first.
+  T(db.save({"_id": "_local/foo"}).ok);
+  T(db.open("_local/foo")._id == "_local/foo");
+  
+  //Test non-string
+  try {
+    db.save({"_id": 1});
+    T(1 == 0);
+  } catch(e) {
+      T(db.last_req.status == 400);
+      T(e.error == "invalid_doc");
+  }
+
+  // Test invalid _prefix
+  try {
+    db.save({"_id": "_invalid"});
+    T(1 == 0);
+  } catch(e) {
+      T(db.last_req.status == 400);
+      T(e.error == "invalid_doc");
+  }
+
+  // Test _bulk_docs explicitly.
+  var docs = [{"_id": "_design/foo"}, {"_id": "_local/bar"}];
+  T(db.bulkSave(docs).ok);
+  docs.forEach(function(d) {T(db.open(d._id)._id == d._id);});
+
+  docs = [{"_id": "_invalid"}];
+  try {
+    db.bulkSave(docs);
+    T(1 == 0);
+  } catch(e) {
+      T(db.last_req.status == 400);
+      T(e.error == "invalid_doc");
+  }
+};

Propchange: couchdb/trunk/share/www/script/test/invalid_docids.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: couchdb/trunk/share/www/script/test/large_docs.js
URL: http://svn.apache.org/viewvc/couchdb/trunk/share/www/script/test/large_docs.js?rev=744782&view=auto
==============================================================================
--- couchdb/trunk/share/www/script/test/large_docs.js (added)
+++ couchdb/trunk/share/www/script/test/large_docs.js Sun Feb 15 23:59:38 2009
@@ -0,0 +1,33 @@
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+couchTests.large_docs = function(debug) {
+  var db = new CouchDB("test_suite_db");
+  db.deleteDb();
+  db.createDb();
+  if (debug) debugger;
+
+  var longtext = "0123456789\n";
+
+  for (var i=0; i<10; i++) {
+    longtext = longtext + longtext
+  }
+  T(db.save({"longtest":longtext}).ok);
+  T(db.save({"longtest":longtext}).ok);
+  T(db.save({"longtest":longtext}).ok);
+  T(db.save({"longtest":longtext}).ok);
+
+  // query all documents, and return the doc.foo member as a key.
+  results = db.query(function(doc){
+      emit(null, doc.longtest);
+  });
+};

Propchange: couchdb/trunk/share/www/script/test/large_docs.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: couchdb/trunk/share/www/script/test/list_views.js
URL: http://svn.apache.org/viewvc/couchdb/trunk/share/www/script/test/list_views.js?rev=744782&view=auto
==============================================================================
--- couchdb/trunk/share/www/script/test/list_views.js (added)
+++ couchdb/trunk/share/www/script/test/list_views.js Sun Feb 15 23:59:38 2009
@@ -0,0 +1,216 @@
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+couchTests.list_views = function(debug) {
+  var db = new CouchDB("test_suite_db");
+  db.deleteDb();
+  db.createDb();
+  if (debug) debugger;
+      
+  var designDoc = {
+    _id:"_design/lists",
+    language: "javascript",
+    views : {
+      basicView : {
+        map : stringFun(function(doc) {
+          emit(doc.integer, doc.string);
+        })
+      },
+      withReduce : {
+        map : stringFun(function(doc) {
+          emit(doc.integer, doc.string);
+        }),
+        reduce : stringFun(function(keys, values, rereduce) {
+          if (rereduce) {
+            return sum(values);
+          } else {
+            return values.length;
+          }
+        })
+      }
+    },
+    lists: {
+      simpleForm: stringFun(function(head, row, req, row_info) {
+        if (row) {
+          // we ignore headers on rows and tail
+          return {
+                  body : '\n<li>Key: '+row.key
+                  +' Value: '+row.value
+                  +' LineNo: '+row_info.row_number+'</li>'
+          };
+        } else if (head) {
+          // we return an object (like those used by external and show)
+          // so that we can specify headers
+          return {
+            body : '<h1>Total Rows: '
+              + head.total_rows
+              + ' Offset: ' + head.offset
+              + '</h1><ul>'
+          };
+        } else {
+          // tail
+          return {body : '</ul>'+
+              '<p>FirstKey: '+row_info.first_key+ 
+              ' LastKey: '+row_info.prev_key+'</p>'};
+        }
+      }),
+      acceptSwitch: stringFun(function(head, row, req, row_info) {
+        return respondWith(req, {
+          html : function() {
+            // If you're outputting text and you're not setting
+            // any headers, you can just return a string.
+            if (head) {
+              return "HTML <ul>";
+            } else if (row) {
+              return '\n<li>Key: '
+                +row.key+' Value: '+row.value
+                +' LineNo: '+row_info.row_number+'</li>';
+            } else { // tail
+              return '</ul>';
+
+            }
+          },
+          xml : function() {
+            if (head) {
+              return '<feed xmlns="http://www.w3.org/2005/Atom">'
+                +'<title>Test XML Feed</title>';
+            } else if (row) {
+              // Becase Safari can't stand to see that dastardly
+              // E4X outside of a string. Outside of tests you
+              // can just use E4X literals.
+              var entry = new XML('<entry/>');
+              entry.id = row.id;
+              entry.title = row.key;
+              entry.content = row.value;
+              // We'll also let you return just an E4X object
+              // if you aren't setting headers.
+              return entry;
+            } else {
+              return "</feed>";
+            }
+          }
+        })
+      }),
+      qsParams: stringFun(function(head, row, req, row_info) {
+        if(head) return {body: req.query.foo};
+        else return {body: "\n"};
+      }),
+      stopIter: stringFun(function(head, row, req, row_info) {
+        if(head) {
+          return {body: "head"};
+        } else if(row) {
+          if(row_info.row_number > 2) return {stop: true};
+          return {body: " " + row_info.row_number};
+        } else {
+          return {body: " tail"};
+        }
+      }),
+      stopIter2: stringFun(function(head, row, req, row_info) {
+        return respondWith(req, {
+          html: function() {
+            if(head) {
+              return "head";
+            } else if(row) {
+              if(row_info.row_number > 2) return {stop: true};
+              return " " + row_info.row_number;
+            } else {
+              return " tail";
+            }
+          }
+        });
+      })
+    }
+  };
+
+  T(db.save(designDoc).ok);
+  
+  var docs = makeDocs(0, 10);
+  var saveResult = db.bulkSave(docs);
+  T(saveResult.ok);
+  
+  var view = db.view('lists/basicView');
+  T(view.total_rows == 10);
+  
+  // standard get
+  var xhr = CouchDB.request("GET", "/test_suite_db/_list/lists/simpleForm/basicView");
+  T(xhr.status == 200);
+  T(/Total Rows/.test(xhr.responseText));
+  T(/Key: 1/.test(xhr.responseText));
+  T(/LineNo: 0/.test(xhr.responseText));
+  T(/LineNo: 5/.test(xhr.responseText));
+  T(/FirstKey: 0/.test(xhr.responseText));
+  T(/LastKey: 9/.test(xhr.responseText));
+
+
+  var lines = xhr.responseText.split('\n');
+  T(/LineNo: 5/.test(lines[6]));
+
+  // test that etags are available
+  var etag = xhr.getResponseHeader("etag");
+  xhr = CouchDB.request("GET", "/test_suite_db/_list/lists/simpleForm/basicView", {
+    headers: {"if-none-match": etag}
+  });
+  T(xhr.status == 304);
+
+  // get with query params
+  var xhr = CouchDB.request("GET", "/test_suite_db/_list/lists/simpleForm/basicView?startkey=3");
+  T(xhr.status == 200);
+  T(/Total Rows/.test(xhr.responseText));
+  T(!(/Key: 1/.test(xhr.responseText)));
+  T(/FirstKey: 3/.test(xhr.responseText));
+  T(/LastKey: 9/.test(xhr.responseText));
+
+  
+  // with 0 rows
+  var xhr = CouchDB.request("GET", "/test_suite_db/_list/lists/simpleForm/basicView?startkey=30");
+  T(xhr.status == 200);
+  T(/Total Rows/.test(xhr.responseText));
+  T(/Offset: null/.test(xhr.responseText));
+  
+  // when there is a reduce present, but not used
+  var xhr = CouchDB.request("GET", "/test_suite_db/_list/lists/simpleForm/withReduce?reduce=false");
+  T(xhr.status == 200);
+  T(/Total Rows/.test(xhr.responseText));
+  T(/Key: 1/.test(xhr.responseText));
+  
+  // with accept headers for HTML
+  xhr = CouchDB.request("GET", "/test_suite_db/_list/lists/acceptSwitch/basicView", {
+    headers: {
+      "Accept": 'text/html'
+    }
+  });
+  T(xhr.getResponseHeader("Content-Type") == "text/html");
+  T(xhr.responseText.match(/HTML/));
+  T(xhr.responseText.match(/Value/));
+
+  // now with xml
+  xhr = CouchDB.request("GET", "/test_suite_db/_list/lists/acceptSwitch/basicView", {
+    headers: {
+      "Accept": 'application/xml'
+    }
+  });
+  T(xhr.getResponseHeader("Content-Type") == "application/xml");
+  T(xhr.responseText.match(/XML/));
+  T(xhr.responseText.match(/entry/));
+
+  // now with extra qs params
+  xhr = CouchDB.request("GET", "/test_suite_db/_list/lists/qsParams/basicView?foo=blam");
+  T(xhr.responseText.match(/blam/));
+  
+
+  // aborting iteration
+  xhr = CouchDB.request("GET", "/test_suite_db/_list/lists/stopIter/basicView");
+  T(xhr.responseText.match(/^head 0 1 2 tail$/));
+  xhr = CouchDB.request("GET", "/test_suite_db/_list/lists/stopIter2/basicView");
+  T(xhr.responseText.match(/^head 0 1 2 tail$/));
+
+};

Propchange: couchdb/trunk/share/www/script/test/list_views.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: couchdb/trunk/share/www/script/test/lots_of_docs.js
URL: http://svn.apache.org/viewvc/couchdb/trunk/share/www/script/test/lots_of_docs.js?rev=744782&view=auto
==============================================================================
--- couchdb/trunk/share/www/script/test/lots_of_docs.js (added)
+++ couchdb/trunk/share/www/script/test/lots_of_docs.js Sun Feb 15 23:59:38 2009
@@ -0,0 +1,56 @@
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+
+// test saving a semi-large quanitity of documents and do some view queries.
+couchTests.lots_of_docs = function(debug) {
+  var db = new CouchDB("test_suite_db");
+  db.deleteDb();
+  db.createDb();
+  if (debug) debugger;
+
+  // keep number lowish for now to keep tests fasts. Crank up manually to
+  // to really test.
+  var numDocsToCreate = 500;
+
+  for(var i=0; i < numDocsToCreate; i += 100) {
+      var createNow = Math.min(numDocsToCreate - i, 100);
+      var docs = makeDocs(i, i + createNow);
+      T(db.bulkSave(docs).ok);
+  }
+
+  // query all documents, and return the doc.integer member as a key.
+  results = db.query(function(doc){ emit(doc.integer, null) });
+
+  T(results.total_rows == numDocsToCreate);
+
+  // validate the keys are ordered ascending
+  for(var i=0; i<numDocsToCreate; i++) {
+    T(results.rows[i].key==i);
+  }
+
+  // do the query again, but with descending output
+  results = db.query(function(doc){ emit(doc.integer, null) }, null, {
+    descending: true
+  });
+
+  T(results.total_rows == numDocsToCreate);
+
+  // validate the keys are ordered descending
+  for(var i=0; i<numDocsToCreate; i++) {
+    T(results.rows[numDocsToCreate-1-i].key==i);
+  }
+
+  // Check _all_docs with descending=true again (now that there are many docs)
+  var desc = db.allDocs({descending:true});
+  T(desc.total_rows == desc.rows.length);
+};

Propchange: couchdb/trunk/share/www/script/test/lots_of_docs.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: couchdb/trunk/share/www/script/test/max_dbs_open.js
URL: http://svn.apache.org/viewvc/couchdb/trunk/share/www/script/test/max_dbs_open.js?rev=744782&view=auto
==============================================================================
--- couchdb/trunk/share/www/script/test/max_dbs_open.js (added)
+++ couchdb/trunk/share/www/script/test/max_dbs_open.js Sun Feb 15 23:59:38 2009
@@ -0,0 +1,41 @@
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+couchTests.max_dbs_open = function(debug) {
+  if (debug) debugger;
+  restartServer();
+  var max = 5;
+  run_on_modified_server(
+    [{section: "couchdb",
+      key: "max_dbs_open",
+      value: max.toString()}],
+      
+    function () {
+      for(var i=0; i<max*2; i++) {
+        var db = new CouchDB("test_suite_db"+ i);
+        db.deleteDb();
+        db.createDb();
+      }
+      
+      var stats = JSON.parse(CouchDB.request("GET", "/_stats").responseText);
+      T(stats.dbs_open == max);
+      
+      
+      for(var i=0; i<max*2; i++) {
+        var db = new CouchDB("test_suite_db"+ i);
+        db.deleteDb();
+      }
+      
+      var stats = JSON.parse(CouchDB.request("GET", "/_stats").responseText);
+      T(stats.dbs_open == 0);
+    })
+};

Propchange: couchdb/trunk/share/www/script/test/max_dbs_open.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: couchdb/trunk/share/www/script/test/multiple_rows.js
URL: http://svn.apache.org/viewvc/couchdb/trunk/share/www/script/test/multiple_rows.js?rev=744782&view=auto
==============================================================================
--- couchdb/trunk/share/www/script/test/multiple_rows.js (added)
+++ couchdb/trunk/share/www/script/test/multiple_rows.js Sun Feb 15 23:59:38 2009
@@ -0,0 +1,80 @@
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+couchTests.multiple_rows = function(debug) {
+  var db = new CouchDB("test_suite_db");
+  db.deleteDb();
+  db.createDb();
+  if (debug) debugger;
+
+  var nc = {_id:"NC", cities:["Charlotte", "Raleigh"]};
+  var ma = {_id:"MA", cities:["Boston", "Lowell", "Worcester", "Cambridge", "Springfield"]};
+  var fl = {_id:"FL", cities:["Miami", "Tampa", "Orlando", "Springfield"]};
+
+  T(db.save(nc).ok);
+  T(db.save(ma).ok);
+  T(db.save(fl).ok);
+
+  var generateListOfCitiesAndState = "function(doc) {" +
+  " for (var i = 0; i < doc.cities.length; i++)" +
+  "  emit(doc.cities[i] + \", \" + doc._id, null);" +
+  "}";
+
+  var results = db.query(generateListOfCitiesAndState);
+  var rows = results.rows;
+
+  T(rows[0].key == "Boston, MA");
+  T(rows[1].key == "Cambridge, MA");
+  T(rows[2].key == "Charlotte, NC");
+  T(rows[3].key == "Lowell, MA");
+  T(rows[4].key == "Miami, FL");
+  T(rows[5].key == "Orlando, FL");
+  T(rows[6].key == "Raleigh, NC");
+  T(rows[7].key == "Springfield, FL");
+  T(rows[8].key == "Springfield, MA");
+  T(rows[9].key == "Tampa, FL");
+  T(rows[10].key == "Worcester, MA");
+
+  // add another city to NC
+  nc.cities.push("Wilmington");
+  T(db.save(nc).ok);
+
+  var results = db.query(generateListOfCitiesAndState);
+  var rows = results.rows;
+
+  T(rows[0].key == "Boston, MA");
+  T(rows[1].key == "Cambridge, MA");
+  T(rows[2].key == "Charlotte, NC");
+  T(rows[3].key == "Lowell, MA");
+  T(rows[4].key == "Miami, FL");
+  T(rows[5].key == "Orlando, FL");
+  T(rows[6].key == "Raleigh, NC");
+  T(rows[7].key == "Springfield, FL");
+  T(rows[8].key == "Springfield, MA");
+  T(rows[9].key == "Tampa, FL");
+  T(rows[10].key == "Wilmington, NC");
+  T(rows[11].key == "Worcester, MA");
+
+  // now delete MA
+  T(db.deleteDoc(ma).ok);
+
+  var results = db.query(generateListOfCitiesAndState);
+  var rows = results.rows;
+
+  T(rows[0].key == "Charlotte, NC");
+  T(rows[1].key == "Miami, FL");
+  T(rows[2].key == "Orlando, FL");
+  T(rows[3].key == "Raleigh, NC");
+  T(rows[4].key == "Springfield, FL");
+  T(rows[5].key == "Tampa, FL");
+  T(rows[6].key == "Wilmington, NC");
+};

Propchange: couchdb/trunk/share/www/script/test/multiple_rows.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: couchdb/trunk/share/www/script/test/purge.js
URL: http://svn.apache.org/viewvc/couchdb/trunk/share/www/script/test/purge.js?rev=744782&view=auto
==============================================================================
--- couchdb/trunk/share/www/script/test/purge.js (added)
+++ couchdb/trunk/share/www/script/test/purge.js Sun Feb 15 23:59:38 2009
@@ -0,0 +1,101 @@
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+couchTests.purge = function(debug) {
+  var db = new CouchDB("test_suite_db");
+  db.deleteDb();
+  db.createDb();
+  if (debug) debugger;
+  
+  /*
+   purge is not to be confused with a document deletion.  It removes the
+   document and all edit history from the local instance of the database.
+  */
+
+  var numDocs = 10;
+
+  var designDoc = {
+    _id:"_design/test",
+    language: "javascript",
+    views: {
+      all_docs_twice: {map: "function(doc) { emit(doc.integer, null); emit(doc.integer, null) }"},
+      single_doc: {map: "function(doc) { if (doc._id == \"1\") { emit(1, null) }}"}
+    }
+  }
+  
+  T(db.save(designDoc).ok);
+
+  T(db.bulkSave(makeDocs(1, numDocs + 1)).ok);
+
+  // go ahead and validate the views before purging
+  var rows = db.view("test/all_docs_twice").rows;
+  for (var i = 0; i < numDocs; i++) {
+    T(rows[2*i].key == i+1);
+    T(rows[(2*i)+1].key == i+1);
+  }
+  T(db.view("test/single_doc").total_rows == 1);
+  
+  var info = db.info();
+  var doc1 = db.open("1");
+  var doc2 = db.open("2");
+  
+  // purge the documents
+  var xhr = CouchDB.request("POST", "/test_suite_db/_purge", {
+    body: JSON.stringify({"1":[doc1._rev], "2":[doc2._rev]}),
+  });
+  T(xhr.status == 200);
+
+  var newInfo = db.info();
+  // purging increments the update sequence
+  T(info.update_seq+1 == newInfo.update_seq);
+  // and it increments the purge_seq
+  T(info.purge_seq+1 == newInfo.purge_seq);
+
+  var result = JSON.parse(xhr.responseText);
+  T(result.purged["1"][0] == doc1._rev);
+  T(result.purged["2"][0] == doc2._rev);
+  
+  T(db.open("1") == null);
+  T(db.open("2") == null);
+  
+  var rows = db.view("test/all_docs_twice").rows;
+  for (var i = 2; i < numDocs; i++) {
+    T(rows[2*(i-2)].key == i+1);
+    T(rows[(2*(i-2))+1].key == i+1);
+  }
+  T(db.view("test/single_doc").total_rows == 0);
+  
+  // purge documents twice in a row without loading views
+  // (causes full view rebuilds)
+  
+  var doc3 = db.open("3");
+  var doc4 = db.open("4");
+  
+  xhr = CouchDB.request("POST", "/test_suite_db/_purge", {
+    body: JSON.stringify({"3":[doc3._rev]}),
+  });
+  
+  T(xhr.status == 200);
+  
+  xhr = CouchDB.request("POST", "/test_suite_db/_purge", {
+    body: JSON.stringify({"4":[doc4._rev]}),
+  });
+  
+  T(xhr.status == 200);
+  
+  var rows = db.view("test/all_docs_twice").rows;
+  for (var i = 4; i < numDocs; i++) {
+    T(rows[2*(i-4)].key == i+1);
+    T(rows[(2*(i-4))+1].key == i+1);
+  }
+  T(db.view("test/single_doc").total_rows == 0);
+};

Propchange: couchdb/trunk/share/www/script/test/purge.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: couchdb/trunk/share/www/script/test/recreate_doc.js
URL: http://svn.apache.org/viewvc/couchdb/trunk/share/www/script/test/recreate_doc.js?rev=744782&view=auto
==============================================================================
--- couchdb/trunk/share/www/script/test/recreate_doc.js (added)
+++ couchdb/trunk/share/www/script/test/recreate_doc.js Sun Feb 15 23:59:38 2009
@@ -0,0 +1,39 @@
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+couchTests.recreate_doc = function(debug) {
+  var db = new CouchDB("test_suite_db");
+  db.deleteDb();
+  db.createDb();
+  if (debug) debugger;
+
+  // First create a new document with the ID "foo", and delete it again
+  var doc = {_id: "foo", a: "bar", b: 42};
+  T(db.save(doc).ok);
+  T(db.deleteDoc(doc).ok);
+
+  // Now create a new document with the same ID, save it, and then modify it
+  // This should work fine, but currently results in a conflict error, at
+  // least "sometimes"
+  for (var i = 0; i < 10; i++) {
+    doc = {_id: "foo"};
+    T(db.save(doc).ok);
+    doc = db.open("foo");
+    doc.a = "baz";
+    try {
+      T(db.save(doc).ok);
+    } finally {
+      // And now, we can't even delete the document anymore :/
+      T(db.deleteDoc(doc).rev != undefined);
+    }
+  }
+};

Propchange: couchdb/trunk/share/www/script/test/recreate_doc.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: couchdb/trunk/share/www/script/test/reduce.js
URL: http://svn.apache.org/viewvc/couchdb/trunk/share/www/script/test/reduce.js?rev=744782&view=auto
==============================================================================
--- couchdb/trunk/share/www/script/test/reduce.js (added)
+++ couchdb/trunk/share/www/script/test/reduce.js Sun Feb 15 23:59:38 2009
@@ -0,0 +1,169 @@
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+couchTests.reduce = function(debug) {
+  var db = new CouchDB("test_suite_db");
+  db.deleteDb();
+  db.createDb();
+  if (debug) debugger;
+  var numDocs = 500
+  var docs = makeDocs(1,numDocs + 1);
+  T(db.bulkSave(docs).ok);
+  var summate = function(N) {return (N+1)*N/2;};
+
+  var map = function (doc) {
+      emit(doc.integer, doc.integer);
+      emit(doc.integer, doc.integer)};
+  var reduce = function (keys, values) { return sum(values); };
+  var result = db.query(map, reduce);
+  T(result.rows[0].value == 2*summate(numDocs));
+
+  result = db.query(map, reduce, {startkey: 4, endkey: 4});
+  T(result.rows[0].value == 8);
+
+  result = db.query(map, reduce, {startkey: 4, endkey: 5});
+  T(result.rows[0].value == 18);
+
+  result = db.query(map, reduce, {startkey: 4, endkey: 6});
+  T(result.rows[0].value == 30);
+
+  result = db.query(map, reduce, {group:true, limit:3});
+  T(result.rows[0].value == 2);
+  T(result.rows[1].value == 4);
+  T(result.rows[2].value == 6);
+
+  for(var i=1; i<numDocs/2; i+=30) {
+    result = db.query(map, reduce, {startkey: i, endkey: numDocs - i});
+    T(result.rows[0].value == 2*(summate(numDocs-i) - summate(i-1)));
+  }
+
+  db.deleteDb();
+  db.createDb();
+
+  for(var i=1; i <= 5; i++) {
+
+    for(var j=0; j < 10; j++) {
+      // these docs are in the order of the keys collation, for clarity
+      var docs = [];
+      docs.push({keys:["a"]});
+      docs.push({keys:["a"]});
+      docs.push({keys:["a", "b"]});
+      docs.push({keys:["a", "b"]});
+      docs.push({keys:["a", "b", "c"]});
+      docs.push({keys:["a", "b", "d"]});
+      docs.push({keys:["a", "c", "d"]});
+      docs.push({keys:["d"]});
+      docs.push({keys:["d", "a"]});
+      docs.push({keys:["d", "b"]});
+      docs.push({keys:["d", "c"]});
+      T(db.bulkSave(docs).ok);
+      T(db.info().doc_count == ((i - 1) * 10 * 11) + ((j + 1) * 11));
+    }
+
+    map = function (doc) {emit(doc.keys, 1)};
+    reduce = function (keys, values) { return sum(values); };
+
+    var results = db.query(map, reduce, {group:true});
+
+    //group by exact key match
+    T(equals(results.rows[0], {key:["a"],value:20*i}));
+    T(equals(results.rows[1], {key:["a","b"],value:20*i}));
+    T(equals(results.rows[2], {key:["a", "b", "c"],value:10*i}));
+    T(equals(results.rows[3], {key:["a", "b", "d"],value:10*i}));
+
+    // test to make sure group reduce and limit params provide valid json
+    var results = db.query(map, reduce, {group: true, limit: 2});
+    T(equals(results.rows[0], {key: ["a"], value: 20*i}));
+    T(equals(results.rows.length, 2));
+
+    //group by the first element in the key array
+    var results = db.query(map, reduce, {group_level:1});
+    T(equals(results.rows[0], {key:["a"],value:70*i}));
+    T(equals(results.rows[1], {key:["d"],value:40*i}));
+
+    //group by the first 2 elements in the key array
+    var results = db.query(map, reduce, {group_level:2});
+    T(equals(results.rows[0], {key:["a"],value:20*i}));
+    T(equals(results.rows[1], {key:["a","b"],value:40*i}));
+    T(equals(results.rows[2], {key:["a","c"],value:10*i}));
+    T(equals(results.rows[3], {key:["d"],value:10*i}));
+    T(equals(results.rows[4], {key:["d","a"],value:10*i}));
+    T(equals(results.rows[5], {key:["d","b"],value:10*i}));
+    T(equals(results.rows[6], {key:["d","c"],value:10*i}));
+  }
+
+  // now test out more complex reductions that need to use the combine option.
+
+  db.deleteDb();
+  db.createDb();
+
+
+  var map = function (doc) {emit(doc.val, doc.val)};
+  var reduceCombine = function (keys, values, rereduce) {
+      // This computes the standard deviation of the mapped results
+      var stdDeviation=0.0;
+      var count=0;
+      var total=0.0;
+      var sqrTotal=0.0;
+
+      if (!rereduce) {
+        // This is the reduce phase, we are reducing over emitted values from
+        // the map functions.
+        for(var i in values) {
+          total = total + values[i];
+          sqrTotal = sqrTotal + (values[i] * values[i]);
+        }
+        count = values.length;
+      }
+      else {
+        // This is the rereduce phase, we are re-reducing previosuly
+        // reduced values.
+        for(var i in values) {
+          count = count + values[i].count;
+          total = total + values[i].total;
+          sqrTotal = sqrTotal + values[i].sqrTotal;
+        }
+      }
+
+      var variance =  (sqrTotal - ((total * total)/count)) / count;
+      stdDeviation = Math.sqrt(variance);
+
+      // the reduce result. It contains enough information to be rereduced
+      // with other reduce results.
+      return {"stdDeviation":stdDeviation,"count":count,
+          "total":total,"sqrTotal":sqrTotal};
+    };
+
+    // Save a bunch a docs.
+
+  for(var i=0; i < 10; i++) {
+    var docs = [];
+    docs.push({val:10});
+    docs.push({val:20});
+    docs.push({val:30});
+    docs.push({val:40});
+    docs.push({val:50});
+    docs.push({val:60});
+    docs.push({val:70});
+    docs.push({val:80});
+    docs.push({val:90});
+    docs.push({val:100});
+    T(db.bulkSave(docs).ok);
+  }
+  
+  var results = db.query(map, reduceCombine);
+  
+  var difference = results.rows[0].value.stdDeviation - 28.722813232690143;
+  // account for floating point rounding error
+  T(Math.abs(difference) < 0.0000000001);
+  
+};

Propchange: couchdb/trunk/share/www/script/test/reduce.js
------------------------------------------------------------------------------
    svn:eol-style = native