--- /dev/null
+// SPDX-License-Identifier: Apache-2.0
+/**
+ * Copyright (C) 2021 Jihoon Lee <jhoon.it.lee@samsung.com>
+ *
+ * @file data_producer_common_tests.cpp
+ * @date 12 July 2021
+ * @brief Common test for nntrainer data producers (Param Tests)
+ * @see https://github.com/nnstreamer/nntrainer
+ * @author Jihoon Lee <jhoon.it.lee@samsung.com>
+ * @bug No known bugs except for NYI items
+ */
+#include <gtest/gtest.h>
+
+#include <data_producer_common_tests.h>
+
+void DataProducerSemantics::SetUp() {
+ auto [producerFactory, properties, input_dims_, label_dims_, validator_,
+ result_] = GetParam();
+
+ producer = producerFactory(properties);
+ input_dims = std::move(input_dims_);
+ label_dims = std::move(label_dims_);
+ result = result_;
+ validator = std::move(validator_);
+
+ if (result != DataProducerSemanticsExpectedResult::SUCCESS) {
+ ASSERT_EQ(validator, nullptr)
+ << "Given expected result of not success, validator must be empty!";
+ }
+}
+
+void DataProducerSemantics::TearDown() {}
+
+TEST_P(DataProducerSemantics, finalize_pn) {
+ if (result == DataProducerSemanticsExpectedResult::FAIL_AT_FINALIZE) {
+ EXPECT_ANY_THROW(producer->finalize(input_dims, label_dims));
+ } else {
+ EXPECT_NO_THROW(producer->finalize(input_dims, label_dims));
+ }
+}
+
+TEST_P(DataProducerSemantics, fetch_one_epoch_or_10_iteration_pn) {
+ if (result != DataProducerSemanticsExpectedResult::SUCCESS) {
+ return; // skip this test
+ }
+
+ auto generator = producer->finalize(input_dims, label_dims);
+ auto sz = producer->size(input_dims, label_dims);
+ bool has_fixed_size = sz != nntrainer::DataProducer::SIZE_UNDEFINED;
+
+ if (!has_fixed_size) {
+ sz = 5;
+ }
+
+ for (unsigned i = 0; i < sz; ++i) {
+ auto [last, ins, labels] = generator();
+
+ ASSERT_FALSE(last) << " reached last at iteration: " << i << '\n';
+ if (validator) {
+ ASSERT_TRUE(validator(ins, labels))
+ << " failed validation for iteration: " << i << '\n';
+ }
+ }
+
+ if (has_fixed_size) {
+ {
+ auto [last, ins, labels] = generator();
+ EXPECT_TRUE(last);
+ }
+
+ {
+ auto [last, ins, labels] = generator();
+ EXPECT_TRUE(validator(ins, labels))
+ << "failed last validation after one epoch\n";
+ EXPECT_FALSE(last);
+ }
+ }
+}
--- /dev/null
+// SPDX-License-Identifier: Apache-2.0
+/**
+ * Copyright (C) 2021 Jihoon Lee <jhoon.it.lee@samsung.com>
+ *
+ * @file data_producer_common_tests.h
+ * @date 12 July 2021
+ * @brief Common test for nntrainer data producers (Param Tests)
+ * @see https://github.com/nnstreamer/nntrainer
+ * @author Jihoon Lee <jhoon.it.lee@samsung.com>
+ * @bug No known bugs except for NYI items
+ */
+#ifndef __DATA_PRODUCER_COMMON_TESTS_H__
+#define __DATA_PRODUCER_COMMON_TESTS_H__
+
+#include <gtest/gtest.h>
+
+#include <vector>
+
+#include <data_producers.h>
+#include <tensor.h>
+#include <tensor_dim.h>
+
+using DataProducerFactoryType =
+ std::function<std::unique_ptr<nntrainer::DataProducer>(
+ const std::vector<std::string> &)>;
+
+using DataProducerValidatorType =
+ std::function<bool(const std::vector<nntrainer::Tensor> &,
+ const std::vector<nntrainer::Tensor> &)>;
+
+/**
+ * @brief Data Producer Semantics expected result
+ *
+ */
+enum class DataProducerSemanticsExpectedResult {
+ SUCCESS = 0, /**< SUCCESS */
+ FAIL_AT_FINALIZE = 1, /**< FAIL AT FINALIZE */
+};
+
+using DataProducerSemanticsParamType =
+ std::tuple<DataProducerFactoryType /**< layer factory */,
+ std::vector<std::string> /**< properties */,
+ std::vector<nntrainer::TensorDim> /**< input dimensions */,
+ std::vector<nntrainer::TensorDim> /**< label dimensions */,
+ DataProducerValidatorType /**< validator if any */,
+ DataProducerSemanticsExpectedResult /**< expected result */>;
+
+/**
+ * @brief Dataset Producer Semantics Tests
+ *
+ */
+class DataProducerSemantics
+ : public ::testing::TestWithParam<DataProducerSemanticsParamType> {
+public:
+ /**
+ * @brief SetUp test cases here
+ *
+ */
+ virtual void SetUp();
+
+ /**
+ * @brief do here if any memory needs to be released
+ *
+ */
+ virtual void TearDown();
+
+protected:
+ std::unique_ptr<nntrainer::DataProducer>
+ producer; /**< producer to be tested */
+ std::vector<nntrainer::TensorDim> input_dims; /**< input dims */
+ std::vector<nntrainer::TensorDim> label_dims; /**< output dims */
+ DataProducerValidatorType validator; /**< result validator */
+ DataProducerSemanticsExpectedResult result; /**< expected result */
+};
+
+/**
+ * @brief Create a Data Producer object
+ *
+ * @tparam T inherited class of data producer
+ * @param props properties
+ * @return std::unique_ptr<nntrainer::DataProducer> created producer object
+ */
+template <typename T,
+ std::enable_if_t<std::is_base_of<nntrainer::DataProducer, T>::value,
+ T> * = nullptr>
+std::unique_ptr<nntrainer::DataProducer>
+createDataProducer(const std::vector<std::string> &props = {}) {
+ std::unique_ptr<nntrainer::DataProducer> ptr = std::make_unique<T>();
+ ptr->setProperty(props);
+ return ptr;
+}
+
+#endif // __DATA_PRODUCER_COMMON_TESTS_H__
--- /dev/null
+test_name = 'unittest_datasets'
+
+test_target = []
+
+producer_targets = [
+ 'data_producer_common_tests.cpp',
+ 'unittest_random_data_producers.cpp'
+]
+
+test_target += producer_targets
+exe = executable(
+ test_name,
+ test_target,
+ dependencies: [
+ nntrainer_test_main_deps,
+ ],
+ install: get_option('enable-test'),
+ install_dir: application_install_dir
+)
+
+test(test_name, exe,
+ args: '--gtest_output=xml:@0@/@1@.xml'.format(meson.build_root(), test_name)
+)
--- /dev/null
+// SPDX-License-Identifier: Apache-2.0
+/**
+ * Copyright (C) 2021 Jihoon Lee <jhoon.it.lee@samsung.com>
+ *
+ * @file data_producer_common_tests.cpp
+ * @date 12 July 2021
+ * @brief Common test for nntrainer dataset producers (Param Tests)
+ * @see https://github.com/nnstreamer/nntrainer
+ * @author Jihoon Lee <jhoon.it.lee@samsung.com>
+ * @bug No known bugs except for NYI items
+ */
+#include <gtest/gtest.h>
+
+#include <algorithm>
+
+#include <data_producer_common_tests.h>
+#include <random_data_producers.h>
+
+DataProducerValidatorType random_onehot_validator(float min, float max) {
+ /// input validator: every value is in range of min, max
+ auto input_valid = [min, max](const nntrainer::Tensor &t) {
+ auto data = t.getData();
+ for (unsigned int i = 0; i < t.length(); ++i) {
+ if (*data < min || max < *data) {
+ return false;
+ }
+ data++;
+ }
+ return true;
+ };
+
+ /// label validator: sum of all is equal to batch
+ auto label_valid = [](const nntrainer::Tensor &t) {
+ /// @todo better to check batch by batch
+ return fabs(t.batch() - t.sum({0, 1, 2, 3}).getValue(0, 0, 0, 0) < 1e-7);
+ };
+
+ auto f = [input_valid,
+ label_valid](const std::vector<nntrainer::Tensor> &inputs,
+ const std::vector<nntrainer::Tensor> &labels) -> bool {
+ bool is_inputs_valid =
+ std::all_of(inputs.begin(), inputs.end(), input_valid);
+ bool is_labels_valid =
+ std::all_of(labels.begin(), labels.end(), label_valid);
+ return is_inputs_valid && is_labels_valid;
+ };
+
+ return f;
+}
+auto random_onehot_success = DataProducerSemanticsParamType(
+ createDataProducer<nntrainer::RandomDataOneHotProducer>,
+ {"min=0", "max=1", "size=10"}, {{3, 2, 4, 5}}, {{3, 1, 1, 10}},
+ random_onehot_validator(0, 1), DataProducerSemanticsExpectedResult::SUCCESS);
+
+auto random_onehot_min_over_max = DataProducerSemanticsParamType(
+ createDataProducer<nntrainer::RandomDataOneHotProducer>,
+ {"min=2", "max=1", "size=10"}, {{3, 2, 4, 5}}, {{3, 1, 1, 10}}, nullptr,
+ DataProducerSemanticsExpectedResult::FAIL_AT_FINALIZE);
+
+auto random_onehot_invalid_label_shape = DataProducerSemanticsParamType(
+ createDataProducer<nntrainer::RandomDataOneHotProducer>, {}, {{3, 2, 4, 5}},
+ {{3, 1, 2, 10}}, nullptr,
+ DataProducerSemanticsExpectedResult::FAIL_AT_FINALIZE);
+
+INSTANTIATE_TEST_CASE_P(RandomOneHot, DataProducerSemantics,
+ ::testing::Values(random_onehot_success,
+ random_onehot_min_over_max));
subdir('compiler')
subdir('layers')
+subdir('datasets')