public void TestForceInsertEmptyHistory()
        {
            var rev = new RevisionInternal("FakeDocId", "1-abcd".AsRevID(), false);
            var revProperties = new Dictionary<string, object>();
            revProperties.SetDocRevID(rev.DocID, rev.RevID);
            revProperties["message"] = "hi";
            rev.SetProperties(revProperties);

            IList<RevisionID> revHistory = null;
            database.ForceInsert(rev, revHistory, null);
        }
        public void TestRevTree()
        {
            var change = default(DocumentChange);
            database.Changed += (sender, args) =>
            {
                Assert.AreEqual(1, args.Changes.Count());
                Assert.IsNull(change, "Multiple notifications posted");
                change = args.Changes.First();
            };

            var rev = new RevisionInternal("MyDocId", "4-4444".AsRevID(), false);
            var revProperties = new Dictionary<string, object>();
            revProperties.SetDocRevID(rev.DocID, rev.RevID);
            revProperties["message"] = "hi";
            rev.SetProperties(revProperties);

            var revHistory = new List<RevisionID>();
            revHistory.Add(rev.RevID);
            revHistory.Add("3-3333".AsRevID());
            revHistory.Add("2-2222".AsRevID());
            revHistory.Add("1-1111".AsRevID());
            database.ForceInsert(rev, revHistory, null);
            Assert.AreEqual(1, database.GetDocumentCount());
            VerifyRev(rev, revHistory);
            Assert.AreEqual(Announcement(database, rev, rev), change);
            Assert.IsFalse(change.IsConflict);

            // No-op ForceInsert of already-existing revision
            var lastSeq = database.GetLastSequenceNumber();
            database.ForceInsert(rev, revHistory, null);
            Assert.AreEqual(lastSeq, database.GetLastSequenceNumber());
            
            var conflict = new RevisionInternal("MyDocId", "5-5555".AsRevID(), false);
            var conflictProperties = new Dictionary<string, object>();
            conflictProperties.SetDocRevID(conflict.DocID, conflict.RevID);
            conflictProperties["message"] = "yo";
            conflict.SetProperties(conflictProperties);
            
            var conflictHistory = new List<RevisionID>();
            conflictHistory.Add(conflict.RevID);
            conflictHistory.Add("4-4545".AsRevID());
            conflictHistory.Add("3-3030".AsRevID());
            conflictHistory.Add("2-2222".AsRevID());
            conflictHistory.Add("1-1111".AsRevID());
            change = null;
            database.ForceInsert(conflict, conflictHistory, null);
            Assert.AreEqual(1, database.GetDocumentCount());
            VerifyRev(conflict, conflictHistory);
            Assert.AreEqual(Announcement(database, conflict, conflict), change);
            Assert.IsTrue(change.IsConflict);

            // Add an unrelated document:
            var other = new RevisionInternal("AnotherDocID", "1-1010".AsRevID(), false);
            var otherProperties = new Dictionary<string, object>();
            otherProperties["language"] = "jp";
            other.SetProperties(otherProperties);
            var otherHistory = new List<RevisionID>();
            otherHistory.Add(other.RevID);
            change = null;
            database.ForceInsert(other, otherHistory, null);
            Assert.AreEqual(Announcement(database, other, other), change);
            Assert.IsFalse(change.IsConflict);

            // Fetch one of those phantom revisions with no body:
            var rev2 = database.GetDocument(rev.DocID, "2-2222".AsRevID(), 
                true);
            Assert.IsTrue(rev2.Missing);
            Assert.IsNull(rev2.GetBody());

            Assert.IsNull(database.GetDocument(rev.DocID, "666-6666".AsRevID(), true));

            // Make sure no duplicate rows were inserted for the common revisions:
            if(_storageType == StorageEngineTypes.SQLite) {
                Assert.AreEqual(8, database.GetLastSequenceNumber());
            } else {
                Assert.AreEqual(3, database.GetLastSequenceNumber());
            }
            // Make sure the revision with the higher revID wins the conflict:
            var current = database.GetDocument(rev.DocID, null, 
                true);
            Assert.AreEqual(conflict, current);

            // Check that the list of conflicts is accurate
            var conflictingRevs = database.Storage.GetAllDocumentRevisions(rev.DocID, true, false);
            CollectionAssert.AreEqual(new[] { conflict, rev }, conflictingRevs);
            
            // Get the _changes feed and verify only the winner is in it:
            var options = new ChangesOptions();
            var changes = database.ChangesSince(0, options, null, null);
            CollectionAssert.AreEqual(new[] { conflict, other }, changes);
            options.IncludeConflicts = true;
            changes = database.ChangesSince(0, options, null, null);
            var expectedChanges = new RevisionList();
            expectedChanges.Add(rev);
            expectedChanges.Add(conflict);
            expectedChanges.Add(other);
            var expectedChangesAlt = new RevisionList();
            expectedChangesAlt.Add(conflict);
            expectedChangesAlt.Add(rev);
            expectedChangesAlt.Add(other);
            Assert.IsTrue(expectedChanges.SequenceEqual(changes) || expectedChangesAlt.SequenceEqual(changes));
        }
        public void TestRevTreeChangeNotification()
        {
            const string DOCUMENT_ID = "MyDocId";

            var rev = new RevisionInternal(DOCUMENT_ID, "1-abcd".AsRevID(), false);
            var revProperties = new Dictionary<string, object>();
            revProperties.SetDocRevID(rev.DocID, rev.RevID);
            revProperties["message"] = "hi";
            rev.SetProperties(revProperties);

            var revHistory = new List<RevisionID>();
            revHistory.Add(rev.RevID);

            EventHandler<DatabaseChangeEventArgs> handler = (sender, e) =>
            {
                var changes = e.Changes.ToList();
                Assert.AreEqual(1, changes.Count);
                var change = changes[0];
                Assert.AreEqual(DOCUMENT_ID, change.DocumentId);
                Assert.AreEqual(rev.RevID, change.RevisionId);
                Assert.IsTrue(change.IsCurrentRevision);
                Assert.IsFalse(change.IsConflict);

                var current = database.GetDocument(change.DocumentId).CurrentRevision;
                Assert.AreEqual(rev.RevID, current.Id);
            };

            database.Changed += handler;
            database.ForceInsert(rev, revHistory, null);
            database.Changed -= handler;

            // add two more revisions to the document
            var rev3 = new RevisionInternal(DOCUMENT_ID, "3-abcd".AsRevID(), false);
            var rev3Properties = new Dictionary<string, object>();
            rev3Properties.SetDocRevID(rev3.DocID, rev3.RevID);
            rev3Properties["message"] = "hi again";
            rev3.SetProperties(rev3Properties);

            var rev3History = new List<RevisionID>();
            rev3History.Add(rev3.RevID);
            rev3History.Add("2-abcd".AsRevID());
            rev3History.Add(rev.RevID);

            handler = (sender, e) =>
            {
                var changes = e.Changes.ToList();
                Assert.AreEqual(1, changes.Count);
                var change = changes[0];
                Assert.AreEqual(DOCUMENT_ID, change.DocumentId);
                Assert.AreEqual(rev3.RevID, change.RevisionId);
                Assert.IsTrue(change.IsCurrentRevision);
                Assert.IsFalse(change.IsConflict);

                var doc = database.GetDocument(change.DocumentId);
                Assert.AreEqual(rev3.RevID, doc.CurrentRevisionId);
                try
                {
                    Assert.AreEqual(3, doc.RevisionHistory.ToList().Count);
                }
                catch (CouchbaseLiteException)
                {
                    Assert.Fail();
                }
            };

            database.Changed += handler;
            database.ForceInsert(rev3, rev3History, null);
            database.Changed -= handler;

            // add a conflicting revision, with the same history length as the last revision we
            // inserted. Since this new revision's revID has a higher ASCII sort, it should become the
            // new winning revision.
            var conflictRev = new RevisionInternal(DOCUMENT_ID, "3-bcde".AsRevID(), false);
            var conflictProperties = new Dictionary<string, object>();
            conflictProperties.SetDocRevID(conflictRev.DocID, conflictRev.RevID);
            conflictProperties["message"] = "winner";
            conflictRev.SetProperties(conflictProperties);

            var conflictRevHistory = new List<RevisionID>();
            conflictRevHistory.Add(conflictRev.RevID);
            conflictRevHistory.Add("2-abcd".AsRevID());
            conflictRevHistory.Add(rev.RevID);

            handler = (sender, e) =>
            {
                var changes = e.Changes.ToList();
                Assert.AreEqual(1, changes.Count);
                var change = changes[0];
                Assert.AreEqual(DOCUMENT_ID, change.DocumentId);
                Assert.AreEqual(conflictRev.RevID, change.RevisionId);
                Assert.IsTrue(change.IsCurrentRevision);
                Assert.IsFalse(change.IsConflict);

                var doc = database.GetDocument(change.DocumentId);
                Assert.AreEqual(rev3.RevID, doc.CurrentRevisionId);
                try
                {
                    Assert.AreEqual(2, doc.ConflictingRevisions.ToList().Count);
                    Assert.AreEqual(3, doc.RevisionHistory.ToList().Count);
                }
                catch (CouchbaseLiteException)
                {
                    Assert.Fail();
                }
            };

            database.Changed += handler;
            database.ForceInsert(conflictRev, conflictRevHistory, null);
            database.Changed -= handler;
        }
        public static HttpResponseMessage FakeBulkDocs(HttpRequestMessage request)
        {
            var jsonMap = GetJsonMapFromRequest(request);
            var responseList = new List<IDictionary<string, object>>();

            var docs = ((JArray)jsonMap["docs"]).ToList();

            foreach (JObject doc in docs)
            {
                IDictionary<string, object> responseListItem = new Dictionary<string, object>();
                responseListItem.SetDocRevID(doc["_id"].Value<string>(), doc["_rev"].Value<string>());
                responseList.Add(responseListItem);
            }

            var response = GenerateHttpResponseMessage(responseList);
            return response;
        }
        public void TestPulledChangesAreExternal()
        {
            var countDown = new CountdownEvent(1);

            EventHandler<DatabaseChangeEventArgs> handler = (sender, e) =>
            {
                countDown.Signal();
                Assert.IsFalse(e.IsExternal);
            };

            database.Changed += handler;

            // Insert a dcoument as if it came from a remote source.
            var rev = new RevisionInternal("docId", "1-abcd".AsRevID(), false);
            var properties = new Dictionary<string, object>();
            properties.SetDocRevID(rev.DocID, rev.RevID);
            rev.SetProperties(properties);

            var history = new List<RevisionID>();
            history.Add(rev.RevID);
            database.ForceInsert(rev, history, GetReplicationURL());

            Assert.IsTrue(countDown.Wait(TimeSpan.FromSeconds(1)));

            // Analysis disable once DelegateSubtraction
            database.Changed -= handler;
        }
        public void TestAllDocsLiveQuery()
        {
            var query = database.CreateAllDocumentsQuery().ToLiveQuery();
            query.Start();
            var docs = PutDocs(database);
            var expectedRowBase = new List<IDictionary<string, object>>(docs.Count);
            foreach (RevisionInternal rev in docs)
            {
                expectedRowBase.Add(new Dictionary<string, object> {
                    { "id", rev.DocID },
                    { "key", rev.DocID },
                    { "value", new Dictionary<string, object> {
                            { "rev", rev.RevID }
                        }
                    }
                });
            }

            var mre = new AutoResetEvent(false);

            query.Changed += (sender, e) => {
                if(e.Rows.Count < expectedRowBase.Count) {
                    return;
                }

                AssertEnumerablesAreEqual(expectedRowBase, e.Rows);
                mre.Set();
            };

            Assert.IsTrue(mre.WaitOne(TimeSpan.FromSeconds(30)), "Live query timed out");

            expectedRowBase.Add(new Dictionary<string, object> {
                { "id", "66666" },
                { "key", "66666" },
                { "value", new Dictionary<string, object> {
                        { "rev", "1-abcdef" }
                    }
                }
            });

            var dict6 = new Dictionary<string, object>();
            dict6.SetDocRevID("66666", "1-adcdef");
            dict6["key"] = "six";
            PutDoc(database, dict6);

            Assert.IsTrue(mre.WaitOne(TimeSpan.FromSeconds(30)), "Live query timed out");
        }
        public void TestCreateRevisions()
        {
            var properties = new Dictionary<String, Object>();
            properties["testName"] = "testCreateRevisions";
            properties["tag"] = 1337;
            var db = database;

            var doc = CreateDocumentWithProperties(db, properties);
            Assert.IsFalse(doc.Deleted);
            var rev1 = doc.CurrentRevision;
            Assert.IsTrue(rev1.Id.StartsWith("1-"));
            Assert.AreEqual(1, rev1.Sequence);
            Assert.AreEqual(0, rev1.Attachments.Count());

            // Test -createRevisionWithProperties:
            var properties2 = new Dictionary<String, Object>(properties);
            properties2["tag"] = 4567;
            SavedRevision rev2 = null;
            try
            {
                rev2 = rev1.CreateRevision(properties2);
            }
            catch
            {
                Assert.Fail("Couldn't create revision");
            }
            Assert.IsNotNull(rev2, "Put failed");
            Assert.IsTrue(doc.CurrentRevisionId.StartsWith("2-"), "Document revision ID is still " + doc.CurrentRevisionId);
            Assert.AreEqual(rev2.Id, doc.CurrentRevisionId);
            Assert.IsNotNull(rev2.PropertiesAvailable);
            Assert.AreEqual(properties2, rev2.UserProperties);
            Assert.AreEqual(doc, rev2.Document);
            Assert.AreEqual(doc.Id, rev2.GetProperty("_id"));
            Assert.AreEqual(rev2.Id, rev2.GetProperty("_rev"));
            
            // Test -createRevision:
            var newRev = rev2.CreateRevision();
            Assert.IsNull(newRev.Id);
            Assert.AreEqual(newRev.Parent, rev2);
            Assert.AreEqual(newRev.ParentId, rev2.Id);
            Assert.AreEqual(doc.CurrentRevision, rev2);
            Assert.IsFalse(doc.Deleted);

            var listRevs = new List<SavedRevision>();
            listRevs.Add(rev1);
            listRevs.Add(rev2);
            Assert.AreEqual(listRevs, newRev.RevisionHistory);
            Assert.AreEqual(rev2.Properties, newRev.Properties);
            Assert.AreEqual(rev2.UserProperties, newRev.UserProperties);

            var userProperties = new Dictionary<String, Object>();
            userProperties["because"] = "NoSQL";
            newRev.SetUserProperties(userProperties);
            Assert.AreEqual(newRev.UserProperties, userProperties);

            var expectProperties = new Dictionary<String, Object>();
            expectProperties["because"] = "NoSQL";
            expectProperties.SetDocRevID(doc.Id, rev2.Id);
            Assert.AreEqual(newRev.Properties, expectProperties);

            var rev3 = newRev.Save();
            Assert.IsNotNull(rev3);
            Assert.AreEqual(rev3.UserProperties, newRev.UserProperties);
        }
        public RevisionInternal Copy(string docId, RevisionID revId)
        {
            System.Diagnostics.Debug.Assert((docId != null));
            System.Diagnostics.Debug.Assert(((_docId == null) || (_docId.Equals(docId))));

            var result = new RevisionInternal(docId, revId, Deleted);
            var unmodifiableProperties = GetProperties();
            var properties = new Dictionary<string, object>();
            if(unmodifiableProperties != null) {
                properties.PutAll(unmodifiableProperties);
            }

            properties.SetDocRevID(docId, revId);
            result.SetProperties(properties);
            return result;
        }