diff --git a/Makefile b/Makefile index 29f9bd7c39f4b7541c0056b6cc3a8636891daa04..9c8fb41f709defcd56d8f7730f801de9a873c640 100644 --- a/Makefile +++ b/Makefile @@ -80,6 +80,7 @@ conan: conan-install-deps conan-create .PHONY: conan doc: + @doxygen --version || ( echo "Doxygen not found. Please install Doxygen first." ; exit 1 ) mkdir -p build && cd build && conan install .. --build=missing -s $(CONAN_SETTINGS) \ && cmake .. && cmake --build . --target doc-sphinx \ && echo "The documentation starts at build/doc/sphinx_out/index.html ." diff --git a/doc/CHANGELOG.md b/doc/CHANGELOG.md index 66d8b3660215477bf3e0ba83b7f115d7637352fe..7d0a100c879a2a87b6738c766e2882da96d5af14 100644 --- a/doc/CHANGELOG.md +++ b/doc/CHANGELOG.md @@ -22,6 +22,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed +- Values can now hold empty vectors and do not silently convert them into a scalar. + ### Security ### Documentation diff --git a/doc/Install_develop.rst b/doc/Install_develop.rst index 9704ada8e982dd7881a220433cce101c4f4def97..5aa5c8a6c9af7d33a2b11f54af60f7c9c5bd8fa2 100644 --- a/doc/Install_develop.rst +++ b/doc/Install_develop.rst @@ -189,11 +189,14 @@ test``. If you want to build manually, follow these steps: - Depending on the clang version it may be necessary to also add ``-DCMAKE_CXX_FLAGS="-Wno-unused-parameter"`` 4. ``cmake --build .`` + - If this fails with ``Error running '': No such file or directory``, you may want to try + CMake's ``-D SKIP_LINTING=ON``. (See previous step.) Run ^^^ -In the build directory, run ``ctest`` +In the build directory, run ``ctest``. For more verbose output of a single test: +``ctest -R test_value.test_list -V`` Framework ^^^^^^^^^ diff --git a/include/caosdb/value.h b/include/caosdb/value.h index cffb11162b9ed8b83508316c155f1fca46be2714..1da6f1c2178b1b9091b990a016e1959b5e7f2a4c 100644 --- a/include/caosdb/value.h +++ b/include/caosdb/value.h @@ -36,6 +36,10 @@ for (const auto &value : values) { \ this->wrapped->mutable_list_values()->add_values()->SETTER(value); \ } \ + if (values.empty()) { \ + this->wrapped->mutable_list_values()->add_values()->set_special_value( \ + ProtoSpecialValue::SPECIAL_VALUE_UNSPECIFIED); \ + } \ } namespace caosdb::entity { @@ -385,7 +389,9 @@ public: return !IsNull() && this->wrapped->value_case() == ValueCase::kListValues; } [[nodiscard]] inline auto GetAsVector() const noexcept -> const std::vector<ScalarValue> & { - if (!IsVector()) { + if (!IsVector() || (this->wrapped->list_values().values(0).has_special_value() && + this->wrapped->list_values().values(0).special_value() == + ProtoSpecialValue::SPECIAL_VALUE_UNSPECIFIED)) { // create empty list static std::vector<ScalarValue> empty_values; return empty_values; diff --git a/test/test_value.cpp b/test/test_value.cpp index 1d959acf40c766c2123b7fdc541b642126983fcc..767965df68e648a04ba64a4148dc58839ebcc08c 100644 --- a/test/test_value.cpp +++ b/test/test_value.cpp @@ -137,6 +137,14 @@ TEST(test_value, test_list) { EXPECT_EQ(item.IsString(), true); EXPECT_EQ(item.GetAsString(), "id" + std::to_string(counter++)); } + + // Test empty lists + auto empty_content = std::vector<int>(); + Value value_0(empty_content); + EXPECT_TRUE(value_0.IsVector()); + auto const &list_value_0 = value_0.GetAsVector(); + EXPECT_EQ(list_value_0.size(), 0); + EXPECT_TRUE(list_value_0.empty()); } TEST(test_value, test_scalar_value_to_value) {