This is an automated email from the ASF dual-hosted git repository.

xyji pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-opendal.git


The following commit(s) were added to refs/heads/main by this push:
     new 42a0e994d feat(bindings/C): implement capability (#3479)
42a0e994d is described below

commit 42a0e994d35ddcdb4b3b47936939f08e3a194436
Author: Xinyou Ji <[email protected]>
AuthorDate: Tue Nov 7 00:40:51 2023 -0500

    feat(bindings/C): implement capability (#3479)
    
    * add capability support
    
    * polish
---
 bindings/c/Makefile             |   4 +-
 bindings/c/include/opendal.h    | 257 +++++++++++++++++++++++++++++++++++-
 bindings/c/src/lib.rs           |   2 +
 bindings/c/src/metadata.rs      |   2 +-
 bindings/c/src/operator_info.rs | 279 ++++++++++++++++++++++++++++++++++++++++
 bindings/c/tests/opinfo.cpp     | 111 ++++++++++++++++
 6 files changed, 652 insertions(+), 3 deletions(-)

diff --git a/bindings/c/Makefile b/bindings/c/Makefile
index 245d4facb..d7a1bd244 100644
--- a/bindings/c/Makefile
+++ b/bindings/c/Makefile
@@ -25,7 +25,7 @@ LDFLAGS=-L$(RPATH) -Wl,-rpath,$(RPATH)
 
 LIBS=-lopendal_c -lgtest -lpthread
 
-VALGRIND=valgrind --error-exitcode=1 --leak-check=full -- 
+VALGRIND=valgrind --error-exitcode=1 --leak-check=full --
 
 .PHONY: all
 all: build test examples
@@ -46,9 +46,11 @@ test:
        $(CXX) tests/bdd.cpp -o $(OBJ_DIR)/bdd $(CXXFLAGS) $(LDFLAGS) $(LIBS)
        $(CXX) tests/list.cpp -o $(OBJ_DIR)/list $(CXXFLAGS) $(LDFLAGS) $(LIBS)
        $(CXX) tests/error_msg.cpp -o $(OBJ_DIR)/error_msg $(CXXFLAGS) 
$(LDFLAGS) $(LIBS)
+       $(CXX) tests/opinfo.cpp -o $(OBJ_DIR)/opinfo $(CXXFLAGS) $(LDFLAGS) 
$(LIBS)
        $(OBJ_DIR)/bdd
        $(OBJ_DIR)/list
        $(OBJ_DIR)/error_msg
+       $(OBJ_DIR)/opinfo
 
 .PHONY: test_memory_leak
 memory_leak:
diff --git a/bindings/c/include/opendal.h b/bindings/c/include/opendal.h
index cc4339151..55586cd83 100644
--- a/bindings/c/include/opendal.h
+++ b/bindings/c/include/opendal.h
@@ -207,6 +207,11 @@ typedef struct HashMap_String__String 
HashMap_String__String;
  */
 typedef struct Metadata Metadata;
 
+/**
+ * Metadata for operator, users can use this metadata to get information of 
operator.
+ */
+typedef struct OperatorInfo OperatorInfo;
+
 /**
  * \brief opendal_bytes carries raw-bytes with its length
  *
@@ -295,7 +300,7 @@ typedef struct opendal_lister {
 } opendal_lister;
 
 /**
- * \brief Carries all metadata associated with a path.
+ * \brief Carries all metadata associated with a **path**.
  *
  * The metadata of the "thing" under a path. Please **only** use the 
opendal_metadata
  * with our provided API, e.g. opendal_metadata_content_length().
@@ -478,6 +483,199 @@ typedef struct opendal_result_list {
   struct opendal_error *error;
 } opendal_result_list;
 
+/**
+ * \brief Metadata for **operator**, users can use this metadata to get 
information
+ * of operator.
+ */
+typedef struct opendal_operator_info {
+  struct OperatorInfo *inner;
+} opendal_operator_info;
+
+/**
+ * \brief Capability is used to describe what operations are supported
+ * by current Operator.
+ */
+typedef struct opendal_capability {
+  /**
+   * If operator supports stat.
+   */
+  bool stat;
+  /**
+   * If operator supports stat with if match.
+   */
+  bool stat_with_if_match;
+  /**
+   * If operator supports stat with if none match.
+   */
+  bool stat_with_if_none_match;
+  /**
+   * If operator supports read.
+   */
+  bool read;
+  /**
+   * If operator supports seek on returning reader.
+   */
+  bool read_can_seek;
+  /**
+   * If operator supports next on returning reader.
+   */
+  bool read_can_next;
+  /**
+   * If operator supports read with range.
+   */
+  bool read_with_range;
+  /**
+   * If operator supports read with if match.
+   */
+  bool read_with_if_match;
+  /**
+   * If operator supports read with if none match.
+   */
+  bool read_with_if_none_match;
+  /**
+   * if operator supports read with override cache control.
+   */
+  bool read_with_override_cache_control;
+  /**
+   * if operator supports read with override content disposition.
+   */
+  bool read_with_override_content_disposition;
+  /**
+   * if operator supports read with override content type.
+   */
+  bool read_with_override_content_type;
+  /**
+   * If operator supports write.
+   */
+  bool write;
+  /**
+   * If operator supports write can be called in multi times.
+   */
+  bool write_can_multi;
+  /**
+   * If operator supports write with empty content.
+   */
+  bool write_can_empty;
+  /**
+   * If operator supports write by append.
+   */
+  bool write_can_append;
+  /**
+   * If operator supports write with content type.
+   */
+  bool write_with_content_type;
+  /**
+   * If operator supports write with content disposition.
+   */
+  bool write_with_content_disposition;
+  /**
+   * If operator supports write with cache control.
+   */
+  bool write_with_cache_control;
+  /**
+   * write_multi_max_size is the max size that services support in write_multi.
+   *
+   * For example, AWS S3 supports 5GiB as max in write_multi.
+   *
+   * If it is not set, this will be zero
+   */
+  uintptr_t write_multi_max_size;
+  /**
+   * write_multi_min_size is the min size that services support in write_multi.
+   *
+   * For example, AWS S3 requires at least 5MiB in write_multi expect the last 
one.
+   *
+   * If it is not set, this will be zero
+   */
+  uintptr_t write_multi_min_size;
+  /**
+   * write_multi_align_size is the align size that services required in 
write_multi.
+   *
+   * For example, Google GCS requires align size to 256KiB in write_multi.
+   *
+   * If it is not set, this will be zero
+   */
+  uintptr_t write_multi_align_size;
+  /**
+   * write_total_max_size is the max size that services support in write_total.
+   *
+   * For example, Cloudflare D1 supports 1MB as max in write_total.
+   *
+   * If it is not set, this will be zero
+   */
+  uintptr_t write_total_max_size;
+  /**
+   * If operator supports create dir.
+   */
+  bool create_dir;
+  /**
+   * If operator supports delete.
+   */
+  bool delete_;
+  /**
+   * If operator supports copy.
+   */
+  bool copy;
+  /**
+   * If operator supports rename.
+   */
+  bool rename;
+  /**
+   * If operator supports list.
+   */
+  bool list;
+  /**
+   * If backend supports list with limit.
+   */
+  bool list_with_limit;
+  /**
+   * If backend supports list with start after.
+   */
+  bool list_with_start_after;
+  /**
+   * If backend support list with using slash as delimiter.
+   */
+  bool list_with_delimiter_slash;
+  /**
+   * If backend supports list without delimiter.
+   */
+  bool list_without_delimiter;
+  /**
+   * If operator supports presign.
+   */
+  bool presign;
+  /**
+   * If operator supports presign read.
+   */
+  bool presign_read;
+  /**
+   * If operator supports presign stat.
+   */
+  bool presign_stat;
+  /**
+   * If operator supports presign write.
+   */
+  bool presign_write;
+  /**
+   * If operator supports batch.
+   */
+  bool batch;
+  /**
+   * If operator supports batch delete.
+   */
+  bool batch_delete;
+  /**
+   * The max operations that operator supports in batch.
+   *
+   * If it is not set, this will be zero
+   */
+  uintptr_t batch_max_operations;
+  /**
+   * If operator supports blocking.
+   */
+  bool blocking;
+} opendal_capability;
+
 /**
  * \brief The is the result type returned by opendal_reader_read().
  * The result type contains a size field, which is the size of the data read,
@@ -951,6 +1149,63 @@ struct opendal_result_stat opendal_operator_stat(const 
struct opendal_operator *
 struct opendal_result_list opendal_operator_list(const struct opendal_operator 
*op,
                                                  const char *path);
 
+/**
+ * \brief Get information of underlying accessor.
+ *
+ * # Example
+ *
+ * ```C
+ * /// suppose you have a memory-backed opendal_operator* named op
+ * char *scheme;
+ * opendal_operator_info *info = opendal_operator_info_new(op);
+ *
+ * scheme = opendal_operator_info_get_scheme(info);
+ * assert(!strcmp(scheme, "memory"));
+ *
+ * /// free the heap memory
+ * free(scheme);
+ * opendal_operator_info_free(info);
+ * ```
+ */
+struct opendal_operator_info *opendal_operator_info_new(const struct 
opendal_operator *op);
+
+/**
+ * \brief Free the heap-allocated opendal_operator_info
+ */
+void opendal_operator_info_free(struct opendal_operator_info *ptr);
+
+/**
+ * \brief Return the nul-terminated operator's scheme, i.e. service
+ *
+ * \note: The string is on heap, remember to free it
+ */
+char *opendal_operator_info_get_scheme(const struct opendal_operator_info 
*self);
+
+/**
+ * \brief Return the nul-terminated operator's working root path
+ *
+ * \note: The string is on heap, remember to free it
+ */
+char *opendal_operator_info_get_root(const struct opendal_operator_info *self);
+
+/**
+ * \brief Return the nul-terminated operator backend's name, could be empty if 
underlying backend has no
+ * namespace concept.
+ *
+ * \note: The string is on heap, remember to free it
+ */
+char *opendal_operator_info_get_name(const struct opendal_operator_info *self);
+
+/**
+ * \brief Return the operator's full capability
+ */
+struct opendal_capability opendal_operator_info_get_full_capability(const 
struct opendal_operator_info *self);
+
+/**
+ * \brief Return the operator's native capability
+ */
+struct opendal_capability opendal_operator_info_get_native_capability(const 
struct opendal_operator_info *self);
+
 /**
  * \brief Frees the heap memory used by the opendal_bytes
  */
diff --git a/bindings/c/src/lib.rs b/bindings/c/src/lib.rs
index 76f26381a..a4429813b 100644
--- a/bindings/c/src/lib.rs
+++ b/bindings/c/src/lib.rs
@@ -43,6 +43,8 @@ pub use metadata::opendal_metadata;
 mod operator;
 pub use operator::opendal_operator;
 
+mod operator_info;
+
 mod result;
 pub use result::opendal_result_is_exist;
 pub use result::opendal_result_list;
diff --git a/bindings/c/src/metadata.rs b/bindings/c/src/metadata.rs
index 15c38bbd2..a28d72d7b 100644
--- a/bindings/c/src/metadata.rs
+++ b/bindings/c/src/metadata.rs
@@ -17,7 +17,7 @@
 
 use ::opendal as core;
 
-/// \brief Carries all metadata associated with a path.
+/// \brief Carries all metadata associated with a **path**.
 ///
 /// The metadata of the "thing" under a path. Please **only** use the 
opendal_metadata
 /// with our provided API, e.g. opendal_metadata_content_length().
diff --git a/bindings/c/src/operator_info.rs b/bindings/c/src/operator_info.rs
new file mode 100644
index 000000000..2a700a6e7
--- /dev/null
+++ b/bindings/c/src/operator_info.rs
@@ -0,0 +1,279 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you 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.
+
+use std::ffi::{c_char, CString};
+
+use ::opendal as core;
+
+use crate::opendal_operator;
+
+/// \brief Metadata for **operator**, users can use this metadata to get 
information
+/// of operator.
+#[repr(C)]
+pub struct opendal_operator_info {
+    pub inner: *mut core::OperatorInfo,
+}
+
+/// \brief Capability is used to describe what operations are supported
+/// by current Operator.
+#[repr(C)]
+pub struct opendal_capability {
+    /// If operator supports stat.
+    pub stat: bool,
+    /// If operator supports stat with if match.
+    pub stat_with_if_match: bool,
+    /// If operator supports stat with if none match.
+    pub stat_with_if_none_match: bool,
+
+    /// If operator supports read.
+    pub read: bool,
+    /// If operator supports seek on returning reader.
+    pub read_can_seek: bool,
+    /// If operator supports next on returning reader.
+    pub read_can_next: bool,
+    /// If operator supports read with range.
+    pub read_with_range: bool,
+    /// If operator supports read with if match.
+    pub read_with_if_match: bool,
+    /// If operator supports read with if none match.
+    pub read_with_if_none_match: bool,
+    /// if operator supports read with override cache control.
+    pub read_with_override_cache_control: bool,
+    /// if operator supports read with override content disposition.
+    pub read_with_override_content_disposition: bool,
+    /// if operator supports read with override content type.
+    pub read_with_override_content_type: bool,
+
+    /// If operator supports write.
+    pub write: bool,
+    /// If operator supports write can be called in multi times.
+    pub write_can_multi: bool,
+    /// If operator supports write with empty content.
+    pub write_can_empty: bool,
+    /// If operator supports write by append.
+    pub write_can_append: bool,
+    /// If operator supports write with content type.
+    pub write_with_content_type: bool,
+    /// If operator supports write with content disposition.
+    pub write_with_content_disposition: bool,
+    /// If operator supports write with cache control.
+    pub write_with_cache_control: bool,
+    /// write_multi_max_size is the max size that services support in 
write_multi.
+    ///
+    /// For example, AWS S3 supports 5GiB as max in write_multi.
+    ///
+    /// If it is not set, this will be zero
+    pub write_multi_max_size: usize,
+    /// write_multi_min_size is the min size that services support in 
write_multi.
+    ///
+    /// For example, AWS S3 requires at least 5MiB in write_multi expect the 
last one.
+    ///
+    /// If it is not set, this will be zero
+    pub write_multi_min_size: usize,
+    /// write_multi_align_size is the align size that services required in 
write_multi.
+    ///
+    /// For example, Google GCS requires align size to 256KiB in write_multi.
+    ///
+    /// If it is not set, this will be zero
+    pub write_multi_align_size: usize,
+    /// write_total_max_size is the max size that services support in 
write_total.
+    ///
+    /// For example, Cloudflare D1 supports 1MB as max in write_total.
+    ///
+    /// If it is not set, this will be zero
+    pub write_total_max_size: usize,
+
+    /// If operator supports create dir.
+    pub create_dir: bool,
+
+    /// If operator supports delete.
+    pub delete: bool,
+
+    /// If operator supports copy.
+    pub copy: bool,
+
+    /// If operator supports rename.
+    pub rename: bool,
+
+    /// If operator supports list.
+    pub list: bool,
+    /// If backend supports list with limit.
+    pub list_with_limit: bool,
+    /// If backend supports list with start after.
+    pub list_with_start_after: bool,
+    /// If backend support list with using slash as delimiter.
+    pub list_with_delimiter_slash: bool,
+    /// If backend supports list without delimiter.
+    pub list_without_delimiter: bool,
+
+    /// If operator supports presign.
+    pub presign: bool,
+    /// If operator supports presign read.
+    pub presign_read: bool,
+    /// If operator supports presign stat.
+    pub presign_stat: bool,
+    /// If operator supports presign write.
+    pub presign_write: bool,
+
+    /// If operator supports batch.
+    pub batch: bool,
+    /// If operator supports batch delete.
+    pub batch_delete: bool,
+    /// The max operations that operator supports in batch.
+    ///
+    /// If it is not set, this will be zero
+    pub batch_max_operations: usize,
+
+    /// If operator supports blocking.
+    pub blocking: bool,
+}
+
+impl opendal_operator_info {
+    /// \brief Get information of underlying accessor.
+    ///
+    /// # Example
+    ///
+    /// ```C
+    /// /// suppose you have a memory-backed opendal_operator* named op
+    /// char *scheme;
+    /// opendal_operator_info *info = opendal_operator_info_new(op);
+    ///
+    /// scheme = opendal_operator_info_get_scheme(info);
+    /// assert(!strcmp(scheme, "memory"));
+    ///
+    /// /// free the heap memory
+    /// free(scheme);
+    /// opendal_operator_info_free(info);
+    /// ```
+    #[no_mangle]
+    pub unsafe extern "C" fn opendal_operator_info_new(op: *const 
opendal_operator) -> *mut Self {
+        let op = (*op).as_ref();
+        let info = op.info();
+
+        Box::into_raw(Box::new(Self {
+            inner: Box::into_raw(Box::new(info)),
+        }))
+    }
+
+    /// \brief Free the heap-allocated opendal_operator_info
+    #[no_mangle]
+    pub unsafe extern "C" fn opendal_operator_info_free(ptr: *mut Self) {
+        unsafe {
+            let _ = Box::from_raw((*ptr).inner);
+            let _ = Box::from_raw(ptr);
+        }
+    }
+
+    /// \brief Return the nul-terminated operator's scheme, i.e. service
+    ///
+    /// \note: The string is on heap, remember to free it
+    #[no_mangle]
+    pub unsafe extern "C" fn opendal_operator_info_get_scheme(&self) -> *mut 
c_char {
+        let scheme = (*self.inner).scheme().to_string();
+        CString::new(scheme)
+            .expect("CString::new failed in opendal_operator_info_get_root")
+            .into_raw()
+    }
+
+    /// \brief Return the nul-terminated operator's working root path
+    ///
+    /// \note: The string is on heap, remember to free it
+    #[no_mangle]
+    pub unsafe extern "C" fn opendal_operator_info_get_root(&self) -> *mut 
c_char {
+        let root = (*self.inner).root();
+        CString::new(root)
+            .expect("CString::new failed in opendal_operator_info_get_root")
+            .into_raw()
+    }
+
+    /// \brief Return the nul-terminated operator backend's name, could be 
empty if underlying backend has no
+    /// namespace concept.
+    ///
+    /// \note: The string is on heap, remember to free it
+    #[no_mangle]
+    pub unsafe extern "C" fn opendal_operator_info_get_name(&self) -> *mut 
c_char {
+        let name = (*self.inner).name();
+        CString::new(name)
+            .expect("CString::new failed in opendal_operator_info_get_name")
+            .into_raw()
+    }
+
+    /// \brief Return the operator's full capability
+    #[no_mangle]
+    pub unsafe extern "C" fn opendal_operator_info_get_full_capability(
+        &self,
+    ) -> opendal_capability {
+        let cap = (*self.inner).full_capability();
+        cap.into()
+    }
+
+    /// \brief Return the operator's native capability
+    #[no_mangle]
+    pub unsafe extern "C" fn opendal_operator_info_get_native_capability(
+        &self,
+    ) -> opendal_capability {
+        let cap = (*self.inner).native_capability();
+        cap.into()
+    }
+}
+
+impl From<core::Capability> for opendal_capability {
+    fn from(value: core::Capability) -> Self {
+        Self {
+            stat: value.stat,
+            stat_with_if_match: value.stat_with_if_match,
+            stat_with_if_none_match: value.stat_with_if_none_match,
+            read: value.read,
+            read_can_seek: value.read_can_seek,
+            read_can_next: value.read_can_next,
+            read_with_range: value.read_with_range,
+            read_with_if_match: value.read_with_if_match,
+            read_with_if_none_match: value.read_with_if_none_match,
+            read_with_override_content_type: 
value.read_with_override_content_type,
+            read_with_override_cache_control: 
value.read_with_override_cache_control,
+            read_with_override_content_disposition: 
value.read_with_override_content_disposition,
+            write: value.write,
+            write_can_multi: value.write_can_multi,
+            write_can_empty: value.write_can_empty,
+            write_can_append: value.write_can_append,
+            write_with_content_type: value.write_with_content_type,
+            write_with_content_disposition: 
value.write_with_content_disposition,
+            write_with_cache_control: value.write_with_cache_control,
+            write_multi_max_size: value.write_multi_max_size.unwrap_or(0),
+            write_multi_min_size: value.write_multi_min_size.unwrap_or(0),
+            write_multi_align_size: value.write_multi_align_size.unwrap_or(0),
+            write_total_max_size: value.write_total_max_size.unwrap_or(0),
+            create_dir: value.create_dir,
+            delete: value.delete,
+            copy: value.copy,
+            rename: value.rename,
+            list: value.list,
+            list_with_limit: value.list_with_limit,
+            list_with_start_after: value.list_with_start_after,
+            list_without_delimiter: value.list_without_delimiter,
+            list_with_delimiter_slash: value.list_with_delimiter_slash,
+            presign: value.presign,
+            presign_read: value.presign_read,
+            presign_stat: value.presign_stat,
+            presign_write: value.presign_write,
+            batch: value.batch,
+            batch_delete: value.batch_delete,
+            batch_max_operations: value.batch_max_operations.unwrap_or(0),
+            blocking: value.blocking,
+        }
+    }
+}
diff --git a/bindings/c/tests/opinfo.cpp b/bindings/c/tests/opinfo.cpp
new file mode 100644
index 000000000..7239b7543
--- /dev/null
+++ b/bindings/c/tests/opinfo.cpp
@@ -0,0 +1,111 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+#include "gtest/gtest.h"
+extern "C" {
+#include "opendal.h"
+}
+
+class OpendalOperatorInfoTest : public ::testing::Test {
+protected:
+    opendal_operator* p;
+    opendal_operator_info* info;
+    std::string root;
+    std::string scheme;
+
+    // set up a brand new operator
+    void SetUp() override
+    {
+        this->root = std::string("/myroot/");
+        this->scheme = std::string("memory");
+
+        opendal_operator_options* options = opendal_operator_options_new();
+        opendal_operator_options_set(options, "root", this->root.c_str());
+
+        opendal_result_operator_new result = 
opendal_operator_new(this->scheme.c_str(), options);
+        EXPECT_TRUE(result.error == nullptr);
+
+        this->p = result.op;
+        EXPECT_TRUE(this->p);
+
+        this->info = opendal_operator_info_new(this->p);
+        EXPECT_TRUE(this->info);
+
+        opendal_operator_options_free(options);
+    }
+
+    void TearDown() override
+    {
+        opendal_operator_free(this->p);
+        opendal_operator_info_free(this->info);
+    }
+};
+
+// We test the capability set by **memory** service.
+TEST_F(OpendalOperatorInfoTest, CapabilityTest)
+{
+    opendal_capability full_cap = 
opendal_operator_info_get_full_capability(this->info);
+    opendal_capability native_cap = 
opendal_operator_info_get_native_capability(this->info);
+    opendal_capability caps[2] = { full_cap, native_cap };
+
+    for (int i = 0; i < 2; ++i) {
+        opendal_capability cap = caps[i];
+
+        EXPECT_TRUE(cap.blocking);
+
+        EXPECT_TRUE(cap.read);
+        EXPECT_TRUE(cap.read_can_seek);
+        EXPECT_TRUE(cap.read_can_next);
+        EXPECT_TRUE(cap.read_with_range);
+        EXPECT_TRUE(cap.stat);
+
+        EXPECT_TRUE(cap.write);
+        EXPECT_TRUE(cap.write_can_empty);
+        EXPECT_TRUE(cap.create_dir);
+
+        EXPECT_TRUE(cap.delete_);
+
+        EXPECT_TRUE(cap.list);
+        EXPECT_TRUE(cap.list_without_delimiter);
+
+        EXPECT_TRUE(cap.copy);
+
+        EXPECT_TRUE(cap.rename);
+    }
+}
+
+TEST_F(OpendalOperatorInfoTest, InfoTest)
+{
+    char *scheme, *root;
+    scheme = opendal_operator_info_get_scheme(this->info);
+    root = opendal_operator_info_get_root(this->info);
+
+    EXPECT_TRUE(!strcmp(scheme, this->scheme.c_str()));
+    EXPECT_TRUE(!strcmp(root, this->root.c_str()));
+
+    // remember to free the strings
+    free(scheme);
+    free(root);
+}
+
+int main(int argc, char** argv)
+{
+    ::testing::InitGoogleTest(&argc, argv);
+    return RUN_ALL_TESTS();
+}

Reply via email to