binarystore: Initial implementation

Dummy BinaryStore class implementation where most functions just return.
Implement getBaseBlobId/getBlobIds/canHandleBlobId and add unit tests
using real objects.

Signed-off-by: Kun Yi <kunyi@google.com>
Change-Id: Iaf8c59f3c4b1bab9de186333074a9cd0160a5764
diff --git a/test/handler_unittest.cpp b/test/handler_unittest.cpp
index d51818e..ef42ea6 100644
--- a/test/handler_unittest.cpp
+++ b/test/handler_unittest.cpp
@@ -1,9 +1,19 @@
 #include "handler_unittest.hpp"
 
+#include <algorithm>
+#include <memory>
+#include <string>
+#include <vector>
+
 using ::testing::_;
+using ::testing::AtLeast;
+using ::testing::ElementsAreArray;
+using ::testing::IsEmpty;
 using ::testing::Return;
 using ::testing::StrEq;
 using ::testing::StrNe;
+using ::testing::UnorderedElementsAreArray;
+
 using namespace std::string_literals;
 using namespace binstore;
 
@@ -15,112 +25,116 @@
   protected:
     static inline std::string basicTestBaseId = "/test/"s;
     static inline std::string basicTestBlobId = "/test/blob0"s;
+
+    static const std::vector<std::string> basicTestBaseIdList;
     static inline std::string basicTestInvalidBlobId = "/invalid/blob0"s;
+
+    void addAllBaseIds()
+    {
+        for (size_t i = 0; i < basicTestBaseIdList.size(); ++i)
+        {
+            auto store = defaultMockStore(basicTestBaseIdList[i]);
+
+            EXPECT_CALL(*store, getBaseBlobId()).Times(AtLeast(1));
+
+            handler.addNewBinaryStore(std::move(store));
+        }
+    }
 };
 
+const std::vector<std::string>
+    BinaryStoreBlobHandlerBasicTest::basicTestBaseIdList = {
+        BinaryStoreBlobHandlerBasicTest::basicTestBaseId, "/another/"s,
+        "/null\0/"s};
+
 TEST_F(BinaryStoreBlobHandlerBasicTest, CanHandleBlobZeroStoreFail)
 {
     // Cannot handle since there is no store. Shouldn't crash.
     EXPECT_FALSE(handler.canHandleBlob(basicTestInvalidBlobId));
 }
 
-TEST_F(BinaryStoreBlobHandlerBasicTest, CanHandleBlobChecksNameInvalid)
+TEST_F(BinaryStoreBlobHandlerBasicTest, CanHandleBlobChecksName)
 {
-    auto bstore = std::make_unique<MockBinaryStore>();
+    auto store = defaultMockStore(basicTestBaseId);
 
-    handler.addNewBinaryStore(std::move(bstore));
+    EXPECT_CALL(*store, getBaseBlobId()).Times(AtLeast(1));
+
+    handler.addNewBinaryStore(std::move(store));
 
     // Verify canHandleBlob checks and returns false on an invalid name.
     EXPECT_FALSE(handler.canHandleBlob(basicTestInvalidBlobId));
-}
-
-TEST_F(BinaryStoreBlobHandlerBasicTest, CanHandleBlobCanOpenValidBlob)
-{
-    auto bstore = std::make_unique<MockBinaryStore>();
-
-    EXPECT_CALL(*bstore, getBaseBlobId())
-        .WillRepeatedly(Return(basicTestBaseId));
-    EXPECT_CALL(*bstore, canHandleBlob(StrNe(basicTestBlobId)))
-        .WillRepeatedly(Return(false));
-    EXPECT_CALL(*bstore, canHandleBlob(StrEq(basicTestBlobId)))
-        .WillRepeatedly(Return(true));
-    handler.addNewBinaryStore(std::move(bstore));
-
     // Verify canHandleBlob return true for a blob id that it can handle
-    EXPECT_FALSE(handler.canHandleBlob(basicTestInvalidBlobId));
     EXPECT_TRUE(handler.canHandleBlob(basicTestBlobId));
 }
 
-TEST_F(BinaryStoreBlobHandlerBasicTest, CanHandleBlobCanOpenValidBlobMultiple)
+TEST_F(BinaryStoreBlobHandlerBasicTest, GetBlobIdEqualsConcatenationsOfBaseIds)
 {
-    auto bstore = std::make_unique<MockBinaryStore>();
-    auto bstore1 = std::make_unique<MockBinaryStore>();
-    const std::string anotherBaseId = "/another/"s;
-    const std::string anotherBlobId = "/another/blob/id"s;
+    addAllBaseIds();
 
-    EXPECT_CALL(*bstore, getBaseBlobId())
-        .WillRepeatedly(Return(basicTestBaseId));
-    EXPECT_CALL(*bstore, canHandleBlob(StrNe(basicTestBlobId)))
-        .WillRepeatedly(Return(false));
-    EXPECT_CALL(*bstore, canHandleBlob(StrEq(basicTestBlobId)))
-        .WillRepeatedly(Return(true));
-    handler.addNewBinaryStore(std::move(bstore));
-
-    EXPECT_CALL(*bstore1, getBaseBlobId())
-        .WillRepeatedly(Return(anotherBaseId));
-    EXPECT_CALL(*bstore1, canHandleBlob(StrNe(anotherBlobId)))
-        .WillRepeatedly(Return(false));
-    EXPECT_CALL(*bstore1, canHandleBlob(StrEq(anotherBlobId)))
-        .WillRepeatedly(Return(true));
-    handler.addNewBinaryStore(std::move(bstore1));
-
-    // Verify canHandleBlob return true for a blob id that it can handle
-    EXPECT_FALSE(handler.canHandleBlob(basicTestInvalidBlobId));
-    EXPECT_TRUE(handler.canHandleBlob(basicTestBlobId));
-    EXPECT_TRUE(handler.canHandleBlob(anotherBlobId));
+    // When there is no other blob id, ids are just base ids (might be
+    // re-ordered).
+    EXPECT_THAT(handler.getBlobIds(),
+                UnorderedElementsAreArray(basicTestBaseIdList));
 }
 
-TEST_F(BinaryStoreBlobHandlerBasicTest, GetBlobIdEqualsConcatenationsOfIds)
+TEST_F(BinaryStoreBlobHandlerBasicTest, CanHandleBlobInvalidNames)
 {
-    std::string baseId0 = "/test/"s;
-    std::string baseId1 = "/test1/"s;
-    std::vector<std::string> idList0 = {"/test/"s, "/test/0"s};
-    std::vector<std::string> idList1 = {"/test1/"s, "/test1/2"s};
-    auto expectedIdList = idList0;
-    expectedIdList.insert(expectedIdList.end(), idList1.begin(), idList1.end());
+    addAllBaseIds();
 
-    auto bstore0 = std::make_unique<MockBinaryStore>();
-    EXPECT_CALL(*bstore0, getBaseBlobId()).WillOnce(Return(baseId0));
-    EXPECT_CALL(*bstore0, getBlobIds()).WillOnce(Return(idList0));
-    handler.addNewBinaryStore(std::move(bstore0));
+    const std::vector<std::string> invalidNames = {
+        basicTestInvalidBlobId,
+        "/"s,
+        "//"s,
+        "/test"s, // Cannot handle the base path
+        "/test/"s,
+        "/test/this/blob"s, // Cannot handle nested path
+    };
 
-    auto bstore1 = std::make_unique<MockBinaryStore>();
-    EXPECT_CALL(*bstore1, getBaseBlobId()).WillOnce(Return(baseId1));
-    EXPECT_CALL(*bstore1, getBlobIds()).WillOnce(Return(idList1));
-    handler.addNewBinaryStore(std::move(bstore1));
+    // Unary helper for algorithm
+    auto canHandle = [this](const std::string& blobId) {
+        return handler.canHandleBlob(blobId);
+    };
 
-    // Verify canHandleBlob return true for a blob id that it can handle
-    EXPECT_EQ(expectedIdList, handler.getBlobIds());
+    EXPECT_TRUE(
+        std::none_of(invalidNames.cbegin(), invalidNames.cend(), canHandle));
+}
+
+TEST_F(BinaryStoreBlobHandlerBasicTest, CanHandleBlobValidNames)
+{
+    addAllBaseIds();
+
+    const std::vector<std::string> validNames = {
+        basicTestBlobId,  "/test/test"s,          "/test/xyz.abc"s,
+        "/another/blob"s, "/null\0/\0\0zer\0\0"s,
+    };
+
+    // Unary helper for algorithm
+    auto canHandle = [this](const std::string& blobId) {
+        return handler.canHandleBlob(blobId);
+    };
+
+    // Verify canHandleBlob can handle a valid blob under the path.
+    EXPECT_TRUE(std::all_of(validNames.cbegin(), validNames.cend(), canHandle));
 }
 
 TEST_F(BinaryStoreBlobHandlerBasicTest, DeleteReturnsWhatStoreReturns)
 {
-    auto bstore = std::make_unique<MockBinaryStore>();
+    auto store = defaultMockStore(basicTestBaseId);
 
-    EXPECT_CALL(*bstore, getBaseBlobId())
-        .WillRepeatedly(Return(basicTestBaseId));
-    EXPECT_CALL(*bstore, canHandleBlob(StrNe(basicTestBlobId)))
-        .WillRepeatedly(Return(false));
-    EXPECT_CALL(*bstore, canHandleBlob(StrEq(basicTestBlobId)))
-        .WillRepeatedly(Return(true));
-    EXPECT_CALL(*bstore, deleteBlob(StrEq(basicTestBlobId)))
+    EXPECT_CALL(*store, getBaseBlobId()).Times(AtLeast(1));
+    EXPECT_CALL(*store, deleteBlob(StrEq(basicTestBlobId)))
         .WillOnce(Return(false))
         .WillOnce(Return(true));
-    handler.addNewBinaryStore(std::move(bstore));
+    handler.addNewBinaryStore(std::move(store));
+
+    // Unary helper for algorithm
+    auto canHandle = [this](const std::string& blobId) {
+        return handler.canHandleBlob(blobId);
+    };
 
     // Verify canHandleBlob return true for a blob id that it can handle
-    EXPECT_FALSE(handler.canHandleBlob(basicTestInvalidBlobId));
-    EXPECT_TRUE(handler.canHandleBlob(basicTestBlobId));
+    EXPECT_FALSE(canHandle(basicTestInvalidBlobId));
+    EXPECT_TRUE(canHandle(basicTestBlobId));
     EXPECT_FALSE(handler.deleteBlob(basicTestInvalidBlobId));
     EXPECT_FALSE(handler.deleteBlob(basicTestBlobId));
     EXPECT_TRUE(handler.deleteBlob(basicTestBlobId));