[Coverage] Increase the overall code coverage
authorDongju Chae <dongju.chae@samsung.com>
Fri, 8 May 2020 07:14:06 +0000 (16:14 +0900)
committer송욱/On-Device Lab(SR)/Staff Engineer/삼성전자 <wook16.song@samsung.com>
Fri, 8 May 2020 08:07:13 +0000 (17:07 +0900)
This patch increase the overall code coverage to cover newly added
or changed source codes.

Signed-off-by: Dongju Chae <dongju.chae@samsung.com>
src/core/ne-handler.cc
src/core/ne-model.cc
src/core/ne-model.h
tests/unittests/ne_core_inf_test.cc
tests/unittests/ne_core_inputservice_test.cc
tests/unittests/ne_core_model_test.cc

index 5310fd2..2e0596b 100644 (file)
@@ -1612,7 +1612,7 @@ TrinityVision::manipulateData (const Model *model, uint32_t idx, bool is_input,
     assert (data_size >= get_data_size (DATA_TYPE_SRNPU));
 
     if (data_size > get_data_size (DATA_TYPE_SRNPU) ||
-        !(zero_point == default_zero_point && scale == default_scale))
+        !(zero_point == default_quant_zero && scale == default_quant_scale))
       need_quantization = true;
   }
 
index ee521f8..257d07d 100644 (file)
@@ -46,19 +46,18 @@ Metadata::extractMetadata (void *data)
     return nullptr;
   }
 
-  std::unique_ptr<Metadata> meta_ptr;
-  Metadata * meta_ins = nullptr;
+  std::unique_ptr<Metadata> meta (nullptr);
 
   switch (NPUBIN_VERSION (meta_data->magiccode)) {
   case 0:
   case 1:
-    meta_ins = new Metadata_v1 (meta_data);
+    meta.reset (Metadata_v1::createInstance (meta_data));
     break;
   case 2:
-    meta_ins = new Metadata_v2 (meta_data);
+    meta.reset (Metadata_v2::createInstance (meta_data));
     break;
   case 3:
-    meta_ins = new Metadata_v3 (meta_data);
+    meta.reset (Metadata_v3::createInstance (meta_data));
     break;
   default:
     logerr (TAG, "Invalid NPU binary format version: %d\n",
@@ -66,14 +65,10 @@ Metadata::extractMetadata (void *data)
     break;
   }
 
-  if (meta_ins != nullptr && !meta_ins->checkSanity ()) {
+  if (meta.get () == nullptr)
     logerr (TAG, "Failed to pass the metadata sanity check\n");
-    delete meta_ins;
-    meta_ins = nullptr;
-  }
 
-  meta_ptr.reset (meta_ins);
-  return meta_ptr;
+  return meta;
 }
 
 /** @brief constructor of npubinfmt v1 */
@@ -91,14 +86,21 @@ Metadata_v1::Metadata_v1 (npubin_meta *meta)
   }
 }
 
-/** @brief sanity check for npubinfmt v1 */
-bool
-Metadata_v1::checkSanity () const
+/** @brief create npubinfmt v1 instance with sanity check */
+Metadata_v1 *
+Metadata_v1::createInstance (npubin_meta *meta)
 {
-  if (getVersion () != 1)
-    return false;
+  Metadata_v1 *metadata = new Metadata_v1 (meta);
+
+  if (metadata->getSize () != metadata->getMetaSize () +
+      metadata->getProgramSize () + metadata->getWeightSize ())
+    goto sanity_violation;
 
-  return getSize () == getMetaSize () + getProgramSize () + getWeightSize ();
+  return metadata;
+
+sanity_violation:
+  delete metadata;
+  return nullptr;
 }
 
 /** @brief constructor of npubinfmt v2 */
@@ -107,18 +109,25 @@ Metadata_v2::Metadata_v2 (npubin_meta *meta)
 {
 }
 
-/** @brief sanity check for npubinfmt v2 */
-bool
-Metadata_v2::checkSanity () const
+/** @brief create npubinfmt v1 instance with sanity check */
+Metadata_v2 *
+Metadata_v2::createInstance (npubin_meta *meta)
 {
-  if (getVersion () != 2)
-    return false;
-  if (getInputNum () > MAX_TENSORS)
-    return false;
-  if (getOutputNum () > MAX_TENSORS)
-    return false;
-
-  return getSize () == getMetaSize () + getProgramSize () + getWeightSize ();
+  Metadata_v2 *metadata = new Metadata_v2 (meta);
+
+  if (metadata->getInputNum () > MAX_TENSORS)
+    goto sanity_violation;
+  if (metadata->getOutputNum () > MAX_TENSORS)
+    goto sanity_violation;
+  if (metadata->getSize () != metadata->getMetaSize () +
+      metadata->getProgramSize () + metadata->getWeightSize ())
+    goto sanity_violation;
+
+  return metadata;
+
+sanity_violation:
+  delete metadata;
+  return nullptr;
 }
 
 /** @brief calculate tensor size depending on specified layout */
@@ -171,31 +180,41 @@ Metadata_v3::Metadata_v3 (npubin_meta *meta)
 {
 }
 
-/** @brief sanity check for npubinfmt v3 */
-bool
-Metadata_v3::checkSanity () const
+/** @brief create npubinfmt v1 instance with sanity check */
+Metadata_v3 *
+Metadata_v3::createInstance (npubin_meta *meta)
 {
-  if (getVersion () != 3)
-    return false;
-  if (getSegmentsNum () > MAX_SEGMENTS)
-    return false;
-  if (getInputNum () > getSegmentsNum () || getInputNum () > MAX_TENSORS)
-    return false;
-  if (getOutputNum () > getSegmentsNum () || getOutputNum () > MAX_TENSORS)
-    return false;
-
-  if (getWeightSegmentIndex () >= getSegmentsNum ())
-      return false;
-  for (uint32_t i = 0; i < getInputNum (); i++) {
-    if (getInputSegmentIndex (i) >= getSegmentsNum ())
-      return false;
+  Metadata_v3 *metadata = new Metadata_v3 (meta);
+
+  if (metadata->getSegmentsNum () > MAX_SEGMENTS)
+    goto sanity_violation;
+  if (metadata->getInputNum () > metadata->getSegmentsNum () ||
+      metadata->getInputNum () > MAX_TENSORS)
+    goto sanity_violation;
+  if (metadata->getOutputNum () > metadata->getSegmentsNum () ||
+      metadata->getOutputNum () > MAX_TENSORS)
+    goto sanity_violation;
+
+  if (metadata->getWeightSegmentIndex () >= metadata->getSegmentsNum ())
+      goto sanity_violation;
+  for (uint32_t i = 0; i < metadata->getInputNum (); i++) {
+    if (metadata->getInputSegmentIndex (i) >= metadata->getSegmentsNum ())
+      goto sanity_violation;
   }
-  for (uint32_t i = 0; i < getOutputNum (); i++) {
-    if (getOutputSegmentIndex (i) >= getSegmentsNum ())
-      return false;
+  for (uint32_t i = 0; i < metadata->getOutputNum (); i++) {
+    if (metadata->getOutputSegmentIndex (i) >= metadata->getSegmentsNum ())
+      goto sanity_violation;
   }
 
-  return getSize () == getMetaSize () + getProgramSize () + getWeightSize ();
+  if (metadata->getSize () != metadata->getMetaSize () +
+      metadata->getProgramSize () + metadata->getWeightSize ())
+    goto sanity_violation;
+
+  return metadata;
+
+sanity_violation:
+  delete metadata;
+  return nullptr;
 }
 
 /**
@@ -208,7 +227,7 @@ Metadata_v3::getInputTensorSize (uint32_t idx, data_layout layout) const
   assert (idx < getInputNum ());
 
   const uint32_t *dims = getInputDims (idx);
-  uint32_t tensor_size = 1;
+  uint32_t tensor_size = getInputElemSize (idx);
 
   for (uint32_t rank_idx = 0; rank_idx < MAX_RANK; rank_idx++)
     tensor_size *= dims[rank_idx];
@@ -226,7 +245,7 @@ Metadata_v3::getOutputTensorSize (uint32_t idx, data_layout layout) const
   assert (idx < getOutputNum ());
 
   const uint32_t *dims = getOutputDims (idx);
-  uint32_t tensor_size = 1;
+  uint32_t tensor_size = getOutputElemSize (idx);
 
   for (uint32_t rank_idx = 0; rank_idx < MAX_RANK; rank_idx++)
     tensor_size *= dims[rank_idx];
@@ -246,11 +265,11 @@ Model::Model (const HWmemImpl* impl)
   constraint_.notimode = default_notimode;
 
   in_.num_info = 1;
-  in_.info[0].layout = DATA_LAYOUT_SRNPU;
-  in_.info[0].type = DATA_TYPE_SRNPU;
+  in_.info[0].layout = default_data_layout;
+  in_.info[0].type = default_data_type;
   out_.num_info = 1;
-  out_.info[0].layout = DATA_LAYOUT_SRNPU;
-  out_.info[0].type = DATA_TYPE_SRNPU;
+  out_.info[0].layout = default_data_layout;
+  out_.info[0].type = default_data_type;
 }
 
 /**
index 57f8176..d5786d5 100644 (file)
 
 #include <assert.h>
 
+/** default data layout and type */
+static const data_type default_data_type = DATA_TYPE_SRNPU;
+static const data_layout default_data_layout = DATA_LAYOUT_SRNPU;
 /** this assumes uint8 zero quantization */
-static const uint32_t default_zero_point = 127;
-static const float default_scale = 1.0;
+static const uint32_t default_quant_zero = 127;
+static const float default_quant_scale = 1.0;
 
 /**
  * Here, the following is dependent to npubinfmt.h. So, this also follows
  * standard types rather than size_t.
  */
 
+uint32_t get_data_size (data_type type);
+
 /** @brief model metadata class */
 class Metadata {
   public:
+    /** @brief extract metadata info from the data and create metadata instance */
     static std::unique_ptr<Metadata> extractMetadata (void *data);
 
-    Metadata (npubin_meta *meta);
     virtual ~Metadata () {};
 
-    virtual bool checkSanity () const = 0;
-
     virtual uint32_t getInputNum () const = 0;
     virtual uint32_t getOutputNum () const = 0;
 
@@ -61,14 +64,14 @@ class Metadata {
     virtual const uint32_t* getInputDims (uint32_t idx) const = 0;
     virtual const uint32_t* getOutputDims (uint32_t idx) const = 0;
 
-    virtual uint32_t getInputQuantZero (uint32_t idx) const = 0;
-    virtual float getInputQuantScale (uint32_t idx) const = 0;
+    virtual uint32_t getInputQuantZero (uint32_t idx) const { return default_quant_zero; }
+    virtual float getInputQuantScale (uint32_t idx) const { return default_quant_scale; }
 
-    virtual uint32_t getOutputQuantZero (uint32_t idx) const = 0;
-    virtual float getOutputQuantScale (uint32_t idx) const = 0;
+    virtual uint32_t getOutputQuantZero (uint32_t idx) const { return default_quant_zero; }
+    virtual float getOutputQuantScale (uint32_t idx) const { return default_quant_scale; }
 
-    virtual data_type getInputQuantType (uint32_t idx) const { return DATA_TYPE_SRNPU; }
-    virtual data_type getOutputQuantType (uint32_t idx) const { return DATA_TYPE_SRNPU; }
+    virtual data_type getInputQuantType (uint32_t idx) const { return default_data_type; }
+    virtual data_type getOutputQuantType (uint32_t idx) const { return default_data_type; }
 
     virtual uint32_t getSegmentsNum () const { return 0; }
     virtual uint32_t getSegmentSize (uint32_t idx) const { return 0; }
@@ -85,6 +88,8 @@ class Metadata {
     int getVersion () const { return version_; }
 
   protected:
+    Metadata (npubin_meta *meta);
+
     npubin_meta *meta_;   /**< user-exposed metadata structure */
     int version_;         /**< metadata version */
 };
@@ -92,9 +97,8 @@ class Metadata {
 /** @brief metadata version 1: support only a single pair of input/ouput tensors */
 class Metadata_v1 : public Metadata {
   public:
-    Metadata_v1 (npubin_meta *meta);
-
-    bool checkSanity () const;
+    /** @brief create metadata with npubinfmt v1. if sanity check is failed, return nullptr */
+    static Metadata_v1 * createInstance (npubin_meta *meta);
 
     uint32_t getInputNum () const override { return 1; }
     uint32_t getOutputNum () const override { return 1; }
@@ -124,20 +128,9 @@ class Metadata_v1 : public Metadata {
       return output_dims[idx];
     }
 
-    uint32_t getInputQuantZero (uint32_t idx) const override {
-      return default_zero_point;
-    }
-    float getInputQuantScale (uint32_t idx) const override {
-      return default_scale;
-    }
-    uint32_t getOutputQuantZero (uint32_t idx) const override {
-      return default_zero_point;
-    }
-    float getOutputQuantScale (uint32_t idx) const override {
-      return default_scale;
-    }
-
   private:
+    Metadata_v1 (npubin_meta *meta);
+
     uint32_t input_dims[MAX_TENSORS][MAX_RANK];   /**< dummy input dimensions */
     uint32_t output_dims[MAX_TENSORS][MAX_RANK];  /**< dummy output dimensions */
 };
@@ -145,9 +138,8 @@ class Metadata_v1 : public Metadata {
 /** @brief metadata version 2: support multiple input/output tensors */
 class Metadata_v2 : public Metadata {
   public:
-    Metadata_v2 (npubin_meta *meta);
-
-    bool checkSanity () const;
+    /** @brief create metadata with npubinfmt v2. if sanity check is failed, return nullptr */
+    static Metadata_v2 * createInstance (npubin_meta *meta);
 
     uint32_t getInputNum () const override { return meta_->input_num; }
     uint32_t getOutputNum () const override { return meta_->output_num; }
@@ -197,14 +189,16 @@ class Metadata_v2 : public Metadata {
       assert (idx < getOutputNum ());
       return meta_->output_quant_s[idx];
     }
+
+  private:
+    Metadata_v2 (npubin_meta *meta);
 };
 
 /** @brief metadata version 3: support a segment table */
 class Metadata_v3 : public Metadata {
   public:
-    Metadata_v3 (npubin_meta *meta);
-
-    bool checkSanity () const;
+    /** @brief create metadata with npubinfmt v3. if sanity check is failed, return nullptr */
+    static Metadata_v3 * createInstance (npubin_meta *meta);
 
     uint32_t getInputNum () const override { return meta_->input_seg_num; }
     uint32_t getOutputNum () const override { return meta_->output_seg_num; }
@@ -215,8 +209,12 @@ class Metadata_v3 : public Metadata {
     uint32_t getInputTensorSize (uint32_t idx, data_layout layout) const override;
     uint32_t getOutputTensorSize (uint32_t idx, data_layout layout) const override;
 
-    uint32_t getInputElemSize (uint32_t idx) const override { return 1; }
-    uint32_t getOutputElemSize (uint32_t idx) const override { return 1; }
+    uint32_t getInputElemSize (uint32_t idx) const override {
+      return get_data_size (getInputQuantType (idx));
+    }
+    uint32_t getOutputElemSize (uint32_t idx) const override {
+      return get_data_size (getOutputQuantType (idx));
+    }
 
     const uint32_t* getInputDims (uint32_t idx) const override {
       assert (idx < getInputNum ());
@@ -269,6 +267,9 @@ class Metadata_v3 : public Metadata {
       assert (idx < getOutputNum ());
       return meta_->output_seg_idx[idx];
     }
+
+  private:
+    Metadata_v3 (npubin_meta *meta);
 };
 
 /** @brief model class derived from hwmem */
@@ -309,6 +310,4 @@ class Model : public HWmem {
     tensors_data_info out_;     /**< output tensor info. */
 };
 
-uint32_t get_data_size (data_type type);
-
 #endif /* __NE_MODEL_HH__ */
index d19a353..d07c8c8 100644 (file)
@@ -33,8 +33,40 @@ TEST (ne_core_inf_test, invoke)
   buffer->setDriverAPI (api.get());
   EXPECT_EQ (buffer->alloc (4096), 0);
 
+  /** dummy segt */
+  std::unique_ptr<SegmentTable> segt (new SegmentTable (new HWmemDevice));
+  segt->setDriverAPI (api.get());
+  EXPECT_EQ (segt->alloc (), 0);
+
   EXPECT_EQ (InferenceEngine::invokeInputService (
         api.get(), NPUINPUT_HOST, 0, model.get(), buffer.get()), 0);
+  EXPECT_EQ (InferenceEngine::invokeInputService (
+        api.get(), NPUINPUT_HOST, 1, model.get(), segt.get()), 0);
+
+  sleep (1);
+}
+
+/**
+ * @brief test invokeInputService () with TRIV2
+ */
+TEST (ne_core_inf_test, invoke_triv2)
+{
+  std::unique_ptr<DriverAPI> api;
+  api = DriverAPI::createDriverAPI (NPUCOND_TRIV2_CONN_SOCIP, 0);
+
+  /** create dummy model & segt */
+  std::unique_ptr<Model> model (new Model (new HWmemDevice));
+  model->setDriverAPI (api.get());
+  EXPECT_EQ (model->alloc (4096), 0);
+
+  std::unique_ptr<SegmentTable> segt (new SegmentTable (new HWmemDevice));
+  segt->setDriverAPI (api.get());
+  EXPECT_EQ (segt->alloc (), 0);
+
+  EXPECT_EQ (InferenceEngine::invokeInputService (
+        api.get(), NPUINPUT_HOST, 1, model.get(), segt.get()), 0);
+  EXPECT_EQ (InferenceEngine::invokeInputService (
+        api.get(), NPUINPUT_HW_RECURRING, 1, model.get(), segt.get()), 0);
 
   sleep (1);
 }
@@ -56,6 +88,10 @@ TEST (ne_core_inf_test, invoke_opmode_n)
   buffer->setDriverAPI (api.get());
   EXPECT_EQ (buffer->alloc (4096), 0);
 
+  std::unique_ptr<SegmentTable> segt (new SegmentTable (new HWmemDevice));
+  segt->setDriverAPI (api.get());
+  EXPECT_EQ (segt->alloc (), 0);
+
   /** unsupported opmode */
   EXPECT_NE (InferenceEngine::invokeInputService (
         api.get(), NPUINPUT_STOP, 0, model.get(), buffer.get()), 0);
@@ -64,6 +100,17 @@ TEST (ne_core_inf_test, invoke_opmode_n)
   EXPECT_NE (InferenceEngine::invokeInputService (
         api.get(), NPUINPUT_I2S_MIC, 0, model.get(), buffer.get()), 0);
 
+  EXPECT_NE (InferenceEngine::invokeInputService (
+        api.get(), NPUINPUT_STOP, 0, model.get(), segt.get()), 0);
+  EXPECT_NE (InferenceEngine::invokeInputService (
+        api.get(), NPUINPUT_INTERNAL_CAM, 0, model.get(), segt.get()), 0);
+  EXPECT_NE (InferenceEngine::invokeInputService (
+        api.get(), NPUINPUT_I2S_MIC, 0, model.get(), segt.get()), 0);
+
+  /** HW_RECURRING works only with segment table */
+  EXPECT_NE (InferenceEngine::invokeInputService (
+        api.get(), NPUINPUT_HW_RECURRING, 0, model.get(), buffer.get()), 0);
+
   sleep (1);
 }
 
@@ -84,6 +131,10 @@ TEST (ne_core_inf_test, invoke_args_n)
   buffer->setDriverAPI (api.get());
   EXPECT_EQ (buffer->alloc (4096), 0);
 
+  std::unique_ptr<SegmentTable> segt (new SegmentTable (new HWmemDevice));
+  segt->setDriverAPI (api.get());
+  EXPECT_EQ (segt->alloc (), 0);
+
   /** invalid args (api should be valid) */
   EXPECT_NE (InferenceEngine::invokeInputService (
         nullptr, NPUINPUT_HOST, 0, nullptr, (Buffer *) nullptr), 0);
@@ -93,6 +144,15 @@ TEST (ne_core_inf_test, invoke_args_n)
         nullptr, NPUINPUT_HOST, 0, nullptr, buffer.get()), 0);
   EXPECT_NE (InferenceEngine::invokeInputService (
         nullptr, NPUINPUT_HOST, 0, model.get(), buffer.get()), 0);
+
+  EXPECT_NE (InferenceEngine::invokeInputService (
+        nullptr, NPUINPUT_HOST, 0, nullptr, (SegmentTable *) nullptr), 0);
+  EXPECT_NE (InferenceEngine::invokeInputService (
+        nullptr, NPUINPUT_HOST, 0, model.get(), (SegmentTable *) nullptr), 0);
+  EXPECT_NE (InferenceEngine::invokeInputService (
+        nullptr, NPUINPUT_HOST, 0, nullptr, segt.get()), 0);
+  EXPECT_NE (InferenceEngine::invokeInputService (
+        nullptr, NPUINPUT_HOST, 0, model.get(), segt.get()), 0);
 }
 
 /**
index 6b1631b..371fb10 100644 (file)
@@ -98,11 +98,36 @@ TEST (ne_core_inputservice_test, host_submit_args_n)
   EXPECT_NE (service.submit (nullptr, 0, model, buffer), 0);
   EXPECT_EQ (service.submit (api.get(), 0, model, buffer), 0);
 
+  SegmentTable * segt = nullptr;
+  EXPECT_NE (service.submit (nullptr, 1, nullptr, segt), 0);
+  EXPECT_NE (service.submit (api.get(), 1, nullptr, segt), 0);
+  EXPECT_NE (service.submit (nullptr, 1, model, segt), 0);
+  EXPECT_EQ (service.submit (api.get(), 1, model, segt), 0);
+
   sleep (1);
 
   delete model;
 }
 
+class TestInputService : public InputService
+{
+  public:
+    TestInputService () {};
+};
+
+/**
+ * @brief test features of submit() with unsupported input service
+ */
+TEST (ne_core_inputservice_test, host_submit_unsupported_n)
+{
+  InputService * service = new TestInputService;
+
+  EXPECT_NE (service->submit (nullptr, 0, nullptr, (Buffer *) nullptr), 0);
+  EXPECT_NE (service->submit (nullptr, 0, nullptr, (SegmentTable *) nullptr), 0);
+
+  delete service;
+}
+
 /**
  * @brief test features of submit() with error handling
  */
index 4f43bd4..7856070 100644 (file)
@@ -55,13 +55,13 @@ TEST (ne_core_model_test, model_primitives)
 
   const tensor_data_info * in = model->getInputDataInfo (0);
   EXPECT_NE (in, nullptr);
-  EXPECT_EQ (in->layout, DATA_LAYOUT_SRNPU);
-  EXPECT_EQ (in->type, DATA_TYPE_SRNPU);
+  EXPECT_EQ (in->layout, default_data_layout);
+  EXPECT_EQ (in->type, default_data_type);
 
   const tensor_data_info * out = model->getOutputDataInfo (0);
   EXPECT_NE (out, nullptr);
-  EXPECT_EQ (out->layout, DATA_LAYOUT_SRNPU);
-  EXPECT_EQ (out->type, DATA_TYPE_SRNPU);
+  EXPECT_EQ (out->layout, default_data_layout);
+  EXPECT_EQ (out->type, default_data_type);
 
   /** user can specify constraint & info */
   constraint.timeout_ms = 100;
@@ -99,10 +99,26 @@ TEST (ne_core_model_test, model_primitives)
 TEST (ne_core_model_test, model_primitives_invalid_args_n)
 {
   std::unique_ptr <Model> model (new Model (new HWmemDevice));
+  const uint64_t exp_size_input = 2048;
+  const uint64_t exp_size_output = 2048;
 
   /** invalid arguments */
   EXPECT_NE (model->setMetadata (nullptr), 0);
 
+  /** make dummy metadata */
+  npubin_meta data;
+  data.magiccode = NPUBIN_MAGICCODE | 0x1;  /* v1 */
+  data.size = 4096;
+  data.buffer_size = 4096;
+  data.input_size = exp_size_input;
+  data.input_offset = 0;
+  data.output_size = exp_size_output;
+  data.output_offset = 2048;
+  data.program_size = 0;
+  data.weight_size = 0;
+  ASSERT_EQ (model->setMetadata (&data), 0);
+
+  /** data info */
   tensors_data_info info;
   EXPECT_NE (model->setDataInfo (nullptr, nullptr), 0);
   EXPECT_NE (model->setDataInfo (&info, nullptr), 0);
@@ -126,6 +142,8 @@ TEST (ne_core_model_test, model_primitives_no_metadata_n)
 
   /** access info without setting metadata */
   EXPECT_EQ (model->getMetadata (), nullptr);
+  EXPECT_EQ (model->getInputTensorNum (), (uint32_t) 0);
+  EXPECT_EQ (model->getOutputTensorNum (), (uint32_t) 0);
   EXPECT_EQ (model->getInputTensorSize (0), (uint32_t) 0);
   EXPECT_EQ (model->getOutputTensorSize (0), (uint32_t) 0);
   EXPECT_EQ (model->getInputDataInfo (0), nullptr);
@@ -159,6 +177,7 @@ TEST (ne_core_model_test, model_set_metadata_n)
   data.magiccode = NPUBIN_MAGICCODE | 0x2;  /* v2 */
   data.input_num = MAX_TENSORS + 1;
   EXPECT_NE (model->setMetadata (&data), 0);
+  data.input_num = 1;
   data.output_num = MAX_TENSORS + 1;
   EXPECT_NE (model->setMetadata (&data), 0);
 
@@ -172,10 +191,57 @@ TEST (ne_core_model_test, model_set_metadata_n)
   data.weight_size = NPUBIN_META_SIZE;
   EXPECT_NE (model->setMetadata (&data), 0); /* size overflow */
 
+  /** invalid segment num or index */
+  data.magiccode = NPUBIN_MAGICCODE | 0x3;  /* v3 */
+  data.segment_num = MAX_SEGMENTS + 1;
+  EXPECT_NE (model->setMetadata (&data), 0);
+  data.segment_num = MAX_SEGMENTS / 2;
+
+  data.input_seg_num = data.segment_num + 1;
+  EXPECT_NE (model->setMetadata (&data), 0);
+  data.input_seg_num = data.segment_num - 1;
+  data.output_seg_num = data.segment_num + 1;
+  EXPECT_NE (model->setMetadata (&data), 0);
+  data.output_seg_num = data.segment_num - 1;
+
+  data.input_seg_num = MAX_TENSORS + 1;
+  EXPECT_NE (model->setMetadata (&data), 0);
+  data.input_seg_num = MAX_TENSORS;
+  data.output_seg_num = MAX_TENSORS + 1;
+  EXPECT_NE (model->setMetadata (&data), 0);
+  data.output_seg_num = MAX_TENSORS;
+
+  data.weight_seg_idx = data.segment_num;
+  EXPECT_NE (model->setMetadata (&data), 0);
+  data.weight_seg_idx = data.segment_num - 1;
+  data.input_seg_idx[0] = data.segment_num;
+  EXPECT_NE (model->setMetadata (&data), 0);
+  data.input_seg_idx[0] = data.segment_num - 1;
+  data.output_seg_idx[0] = data.segment_num;
+  EXPECT_NE (model->setMetadata (&data), 0);
+
   /** TODO add more */
 }
 
 /**
+ * @brief check get_data_size
+ */
+TEST (ne_core_model_test, get_data_size)
+{
+  EXPECT_EQ (get_data_size (DATA_TYPE_SRNPU), (uint32_t) 1);
+  EXPECT_EQ (get_data_size (DATA_TYPE_INT8), (uint32_t) 1);
+  EXPECT_EQ (get_data_size (DATA_TYPE_UINT8), (uint32_t) 1);
+  EXPECT_EQ (get_data_size (DATA_TYPE_INT16), (uint32_t) 2);
+  EXPECT_EQ (get_data_size (DATA_TYPE_UINT16), (uint32_t) 2);
+  EXPECT_EQ (get_data_size (DATA_TYPE_INT32), (uint32_t) 4);
+  EXPECT_EQ (get_data_size (DATA_TYPE_UINT32), (uint32_t) 4);
+  EXPECT_EQ (get_data_size (DATA_TYPE_FLOAT32), (uint32_t) 4);
+  EXPECT_EQ (get_data_size (DATA_TYPE_INT64), (uint32_t) 8);
+  EXPECT_EQ (get_data_size (DATA_TYPE_UINT64), (uint32_t) 8);
+  EXPECT_EQ (get_data_size (DATA_TYPE_FLOAT64), (uint32_t) 8);
+}
+
+/**
  * @brief check set/get primitives of metadata v1
  */
 TEST (ne_core_model_test, metadata_primitives_v1)
@@ -219,12 +285,26 @@ TEST (ne_core_model_test, metadata_primitives_v1)
   /** return default values for unsupported info */
   EXPECT_EQ (meta->getInputElemSize (0), (uint32_t) 1);
   EXPECT_EQ (meta->getOutputElemSize (0), (uint32_t) 1);
-  EXPECT_EQ (meta->getInputDims (0)[0], meta->getInputTensorSize (0, DATA_LAYOUT_SRNPU));
-  EXPECT_EQ (meta->getOutputDims (0)[0], meta->getOutputTensorSize (0, DATA_LAYOUT_SRNPU));
-  EXPECT_EQ (meta->getInputQuantZero (0), default_zero_point);
-  EXPECT_EQ (meta->getOutputQuantZero (0), default_zero_point);
-  EXPECT_FLOAT_EQ (meta->getInputQuantScale (0), default_scale);
-  EXPECT_FLOAT_EQ (meta->getOutputQuantScale (0), default_scale);
+  EXPECT_EQ (meta->getInputDims (0)[0], meta->getInputTensorSize (0, default_data_layout));
+  EXPECT_EQ (meta->getOutputDims (0)[0], meta->getOutputTensorSize (0, default_data_layout));
+  EXPECT_EQ (meta->getInputQuantZero (0), default_quant_zero);
+  EXPECT_EQ (meta->getOutputQuantZero (0), default_quant_zero);
+  EXPECT_FLOAT_EQ (meta->getInputQuantScale (0), default_quant_scale);
+  EXPECT_FLOAT_EQ (meta->getOutputQuantScale (0), default_quant_scale);
+  EXPECT_EQ (meta->getInputQuantType (0), default_data_type);
+  EXPECT_EQ (meta->getOutputQuantType (0), default_data_type);
+
+  EXPECT_EQ (meta->getSegmentsNum (), (uint32_t) 0);
+  EXPECT_EQ (meta->getSegmentSize (0), (uint32_t) 0);
+  EXPECT_EQ (meta->getWeightSegmentIndex (), (uint32_t) 0);
+  EXPECT_EQ (meta->getInputSegmentIndex (0), (uint32_t) 0);
+  EXPECT_EQ (meta->getOutputSegmentIndex (0), (uint32_t) 0);
+
+  /** v0 also works */
+  data.magiccode = NPUBIN_MAGICCODE;  /* v0 --> v1 */
+  EXPECT_EQ (model->setMetadata (&data), 0);
+  EXPECT_NE (model->getMetadata (), nullptr);
+  EXPECT_EQ (model->getMetadata ()->getVersion (), 1);
 }
 
 /**
@@ -298,6 +378,94 @@ TEST (ne_core_model_test, metadata_primitives_v2)
 }
 
 /**
+ * @brief check set/get primitives of metadata v3
+ */
+TEST (ne_core_model_test, metadata_primitives_v3)
+{
+  std::unique_ptr <Model> model (new Model (new HWmemDevice));
+
+  /** make dummy metadata v3 */
+  npubin_meta data;
+
+  data.magiccode = NPUBIN_MAGICCODE | 0x3;  /* v3 */
+  data.size = 8192;
+  data.buffer_size = 4096;
+  data.program_size = 2048;
+  data.weight_size = 2048;
+
+  uint32_t input_num = 3;
+  uint32_t output_num = 4;
+
+  data.segment_num = input_num + output_num + 1;
+  for (uint32_t i = 0; i < data.segment_num; i++)
+    data.segment_size[i] = 0x1000;
+
+  data.input_seg_num = input_num;
+  for (uint32_t i = 0; i < data.input_seg_num; i++) {
+    data.input_seg_idx[i] = i;
+    for (uint32_t j = 0; j < MAX_RANK; j++)
+      data.input_seg_dims[i][j] = 2 * (i + 1);
+    data.input_seg_quant_z[i] = 3 * (i + 1);
+    data.input_seg_quant_s[i] = 4 * (i + 1);
+    data.input_seg_quant_type[i] = DATA_TYPE_QASYMM8;
+  }
+
+  data.output_seg_num = output_num;
+  for (uint32_t i = 0; i < data.output_seg_num; i++) {
+    data.output_seg_idx[i] = data.input_seg_num + i;
+    for (uint32_t j = 0; j < MAX_RANK; j++)
+      data.output_seg_dims[i][j] = 2 * (i + 1);
+    data.output_seg_quant_z[i] = 3 * (i + 1);
+    data.output_seg_quant_s[i] = 4 * (i + 1);
+    data.output_seg_quant_type[i] = DATA_TYPE_QSYMM16;
+  }
+
+  data.weight_seg_idx = data.segment_num - 1;
+
+  EXPECT_EQ (model->setMetadata (&data), 0);
+
+  const Metadata * meta = model->getMetadata ();
+  EXPECT_NE (meta, nullptr);
+
+  EXPECT_EQ (meta->getVersion (), 3);
+  EXPECT_EQ (meta->getBufferSize(), data.buffer_size);
+  EXPECT_EQ (meta->getProgramSize(), data.program_size);
+  EXPECT_EQ (meta->getWeightSize(), data.weight_size);
+
+  EXPECT_EQ (meta->getInputNum (), input_num);
+  for (uint32_t i = 0; i < meta->getInputNum (); i++) {
+    uint32_t size = meta->getInputElemSize (i);
+    EXPECT_EQ (meta->getInputOffset (i), 0);
+    EXPECT_EQ (meta->getInputElemSize (i), get_data_size (DATA_TYPE_QASYMM8));
+    for (uint32_t j = 0; j < MAX_RANK; j++) {
+      EXPECT_EQ (meta->getInputDims(i)[j], 2 * (i + 1));
+      size *= meta->getInputDims(i)[j];
+    }
+    EXPECT_EQ (meta->getInputQuantZero (i), 3 * (i + 1));
+    EXPECT_EQ (meta->getInputQuantScale (i), 4 * (i + 1));
+    EXPECT_EQ (meta->getInputQuantType (i), DATA_TYPE_QASYMM8);
+
+    EXPECT_EQ (meta->getInputTensorSize (i, DATA_LAYOUT_NHWC), size);
+  }
+
+  EXPECT_EQ (meta->getOutputNum (), output_num);
+  for (uint32_t i = 0; i < meta->getOutputNum (); i++) {
+    uint32_t size = meta->getOutputElemSize (i);
+    EXPECT_EQ (meta->getOutputOffset (i), 0);
+    EXPECT_EQ (meta->getOutputElemSize (i), get_data_size (DATA_TYPE_QSYMM16));
+    for (uint32_t j = 0; j < MAX_RANK; j++) {
+      EXPECT_EQ (meta->getOutputDims(i)[j], 2 * (i + 1));
+      size *= meta->getOutputDims(i)[j];
+    }
+    EXPECT_EQ (meta->getOutputQuantZero (i), 3 * (i + 1));
+    EXPECT_EQ (meta->getOutputQuantScale (i), 4 * (i + 1));
+    EXPECT_EQ (meta->getOutputQuantType (i), DATA_TYPE_QSYMM16);
+
+    EXPECT_EQ (meta->getOutputTensorSize (i, DATA_LAYOUT_NHWC), size);
+  }
+}
+
+/**
  * @brief model alloc without driver api
  */
 TEST (ne_core_model_test, model_alloc_no_drv_api_n)