test_v3: write multiple ops

test case for reading and writing multiple operations of different types

Test: cow_api_test
Change-Id: I8d59a460a50c7054df0b17dc44dd6605048682aa
diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/test_v3.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/test_v3.cpp
index 8a67c08..d39c4a7 100644
--- a/fs_mgr/libsnapshot/libsnapshot_cow/test_v3.cpp
+++ b/fs_mgr/libsnapshot/libsnapshot_cow/test_v3.cpp
@@ -339,5 +339,87 @@
     ASSERT_EQ(i, 5);
 }
 
+TEST_F(CowTestV3, AllOps) {
+    CowOptions options;
+    options.op_count_max = 100;
+    auto writer = CreateCowWriter(3, options, GetCowFd());
+
+    std::string data;
+    data.resize(options.block_size * 5);
+    for (int i = 0; i < data.size(); i++) {
+        data[i] = char(rand() % 256);
+    }
+
+    ASSERT_TRUE(writer->AddZeroBlocks(10, 5));
+    ASSERT_TRUE(writer->AddCopy(15, 3, 5));
+    ASSERT_TRUE(writer->AddRawBlocks(18, data.data(), data.size()));
+    ASSERT_TRUE(writer->AddXorBlocks(50, data.data(), data.size(), 24, 10));
+    ASSERT_TRUE(writer->Finalize());
+
+    CowReader reader;
+
+    ASSERT_TRUE(reader.Parse(cow_->fd));
+
+    const auto& header = reader.header_v3();
+    ASSERT_EQ(header.prefix.magic, kCowMagicNumber);
+    ASSERT_EQ(header.prefix.major_version, 3);
+    ASSERT_EQ(header.prefix.minor_version, kCowVersionMinor);
+    ASSERT_EQ(header.block_size, options.block_size);
+    ASSERT_EQ(header.buffer_size, BUFFER_REGION_DEFAULT_SIZE);
+    ASSERT_EQ(header.op_count, 20);
+    ASSERT_EQ(header.op_count_max, 100);
+
+    auto iter = reader.GetOpIter();
+    ASSERT_NE(iter, nullptr);
+    ASSERT_FALSE(iter->AtEnd());
+
+    size_t i = 0;
+
+    while (i < 5) {
+        auto op = iter->Get();
+        ASSERT_EQ(op->type, kCowZeroOp);
+        ASSERT_EQ(op->new_block, 10 + i);
+        iter->Next();
+        i++;
+    }
+    i = 0;
+    while (i < 5) {
+        auto op = iter->Get();
+        ASSERT_EQ(op->type, kCowCopyOp);
+        ASSERT_EQ(op->new_block, 15 + i);
+        ASSERT_EQ(GetCowOpSourceInfoData(*op), 3 + i);
+        iter->Next();
+        i++;
+    }
+    i = 0;
+    std::string sink(data.size(), '\0');
+
+    while (i < 5) {
+        auto op = iter->Get();
+        ASSERT_EQ(op->type, kCowReplaceOp);
+        ASSERT_EQ(op->data_length, options.block_size);
+        ASSERT_EQ(op->new_block, 18 + i);
+        ASSERT_TRUE(
+                ReadData(reader, op, sink.data() + (i * options.block_size), options.block_size));
+        iter->Next();
+        i++;
+    }
+    ASSERT_EQ(sink, data);
+
+    i = 0;
+    std::fill(sink.begin(), sink.end(), '\0');
+    while (i < 5) {
+        auto op = iter->Get();
+        ASSERT_EQ(op->type, kCowXorOp);
+        ASSERT_EQ(op->data_length, 4096);
+        ASSERT_EQ(op->new_block, 50 + i);
+        ASSERT_EQ(GetCowOpSourceInfoData(*op), 98314 + (i * options.block_size));  // 4096 * 24 + 10
+        ASSERT_TRUE(
+                ReadData(reader, op, sink.data() + (i * options.block_size), options.block_size));
+        iter->Next();
+        i++;
+    }
+    ASSERT_EQ(sink, data);
+}
 }  // namespace snapshot
 }  // namespace android