public void TestMultipartWriterGzipped()
        {
            var mp = new MultipartWriter("foo/bar", "BOUNDARY");
            var data1 = Enumerable.Repeat((byte)'*', 100);
            mp.SetNextPartHeaders(new Dictionary<string, string> { 
                { "Content-Type", "star-bellies" }
            });
            mp.AddGZippedData(data1);
            var output = mp.AllOutput();

            // Compression flags & OS type will differ depending on which platform this test is run on
            // So we need to compare for "almost" equality.  In this particular output the compression
            // flags are on byte 97 and the os type is in byte 98
            var expectedOutput = GetType().Assembly.GetManifestResourceStream("MultipartStars.mime").ReadAllBytes();
            Assert.AreEqual(expectedOutput.Take(96), output.Take(96));
            Assert.AreEqual(expectedOutput.Skip(98), output.Skip(98));
        }
        private MultipartWriter GetMultipartWriter(RevisionInternal rev, string boundary)
        {
            // Find all the attachments with "follows" instead of a body, and put 'em in a multipart stream.
            // It's important to scan the _attachments entries in the same order in which they will appear
            // in the JSON, because CouchDB expects the MIME bodies to appear in that same order
            var bodyStream = default(MultipartWriter);
            var attachments = rev.GetAttachments();
            foreach (var a in attachments) {
                var attachment = a.Value.AsDictionary<string, object>();
                if (attachment != null && attachment.GetCast<bool>("follows")) {
                    if (bodyStream == null) {
                        // Create the HTTP multipart stream:
                        bodyStream = new MultipartWriter("multipart/related", boundary);
                        bodyStream.SetNextPartHeaders(new Dictionary<string, string> { 
                            { "Content-Type", "application/json" } 
                        });

                        // Use canonical JSON encoder so that _attachments keys will be written in the
                        // same order that this for loop is processing the attachments.
                        var json = Manager.GetObjectMapper().WriteValueAsBytes(rev.GetProperties(), true);
                        if (CanSendCompressedRequests) {
                            bodyStream.AddGZippedData(json);
                        } else {
                            bodyStream.AddData(json);
                        }
                    }

                    // Add attachment as another MIME part:
                    var disposition = String.Format("attachment; filename={0}", Misc.QuoteString(a.Key));
                    var contentType = attachment.GetCast<string>("type");
                    var contentEncoding = attachment.GetCast<string>("encoding");
                    bodyStream.SetNextPartHeaders(new NonNullDictionary<string, string> {
                        { "Content-Disposition", disposition },
                        { "Content-Type", contentType },
                        { "Content-Encoding", contentEncoding }
                    });

                    var attachmentObj = default(AttachmentInternal);
                    try {
                        attachmentObj = LocalDatabase.AttachmentForDict(attachment, a.Key);
                    } catch(CouchbaseLiteException) {
                        return null;
                    }

                    bodyStream.AddStream(attachmentObj.ContentStream, attachmentObj.Length);
                }
            }

            return bodyStream;
        }