--- /dev/null
+// Copyright (C) 2018 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <config.h>
+
+#include <yang/translator.h>
+
+#include <boost/scoped_ptr.hpp>
+#include <gtest/gtest.h>
+
+using namespace std;
+using namespace isc;
+using namespace isc::data;
+using namespace isc::yang;
+
+namespace {
+
+// Test constructor.
+TEST(TranslatorBasicTest, constructor) {
+ // Get a connection.
+ S_Connection conn(new Connection("translator unittests"));
+ // Get a session.
+ S_Session sess(new Session(conn, SR_DS_CANDIDATE));
+ // Get a translator object.
+ boost::scoped_ptr<TranslatorBasic> t_obj;
+ EXPECT_NO_THROW(t_obj.reset(new TranslatorBasic(sess)));
+}
+
+// Test basic yang value to JSON using the static method.
+TEST(TranslatorBasicTest, valueFrom) {
+ S_Val s_val;
+ ConstElementPtr elem;
+
+ // Null.
+ EXPECT_THROW(TranslatorBasic::value(s_val), BadValue);
+
+ // No easy and direct way to build a container or a list...
+
+ // String.
+ string str("foo");
+ s_val.reset(new Val(str.c_str(), SR_STRING_T));
+ EXPECT_NO_THROW(elem = TranslatorBasic::value(s_val));
+ ASSERT_TRUE(elem);
+ ASSERT_EQ(Element::string, elem->getType());
+ EXPECT_EQ(str, elem->stringValue());
+ elem.reset();
+
+ // Bool.
+ s_val.reset(new Val(false, SR_BOOL_T));
+ EXPECT_NO_THROW(elem = TranslatorBasic::value(s_val));
+ ASSERT_TRUE(elem);
+ ASSERT_EQ(Element::boolean, elem->getType());
+ EXPECT_FALSE(elem->boolValue());
+ elem.reset();
+
+ // Unsigned 8 bit integer.
+ uint8_t u8(123);
+ s_val.reset(new Val(u8, SR_UINT8_T));
+ EXPECT_NO_THROW(elem = TranslatorBasic::value(s_val));
+ ASSERT_TRUE(elem);
+ ASSERT_EQ(Element::integer, elem->getType());
+ EXPECT_EQ(u8, elem->intValue());
+ elem.reset();
+
+ // Unsigned 16 bit integer.
+ uint16_t u16(12345);
+ s_val.reset(new Val(u16, SR_UINT16_T));
+ EXPECT_NO_THROW(elem = TranslatorBasic::value(s_val));
+ ASSERT_TRUE(elem);
+ ASSERT_EQ(Element::integer, elem->getType());
+ EXPECT_EQ(u16, elem->intValue());
+ elem.reset();
+
+ // Unsigned 32 bit integer.
+ uint32_t u32(123456789);
+ s_val.reset(new Val(u32, SR_UINT32_T));
+ EXPECT_NO_THROW(elem = TranslatorBasic::value(s_val));
+ ASSERT_TRUE(elem);
+ ASSERT_EQ(Element::integer, elem->getType());
+ EXPECT_EQ(u32, elem->intValue());
+ elem.reset();
+
+ // Signed 8 bit integer.
+ int8_t s8(-123);
+ s_val.reset(new Val(s8, SR_INT8_T));
+ EXPECT_NO_THROW(elem = TranslatorBasic::value(s_val));
+ ASSERT_TRUE(elem);
+ ASSERT_EQ(Element::integer, elem->getType());
+ EXPECT_EQ(s8, elem->intValue());
+ elem.reset();
+
+ // Signed 16 bit integer.
+ int16_t s16(-12345);
+ s_val.reset(new Val(s16, SR_INT16_T));
+ EXPECT_NO_THROW(elem = TranslatorBasic::value(s_val));
+ ASSERT_TRUE(elem);
+ ASSERT_EQ(Element::integer, elem->getType());
+ EXPECT_EQ(s16, elem->intValue());
+ elem.reset();
+
+ // Signed 32 bit integer.
+ int32_t s32(-123456789);
+ s_val.reset(new Val(s32, SR_INT32_T));
+ EXPECT_NO_THROW(elem = TranslatorBasic::value(s_val));
+ ASSERT_TRUE(elem);
+ ASSERT_EQ(Element::integer, elem->getType());
+ EXPECT_EQ(s32, elem->intValue());
+ elem.reset();
+
+ // Identity reference.
+ s_val.reset(new Val(str.c_str(), SR_IDENTITYREF_T));
+ EXPECT_NO_THROW(elem = TranslatorBasic::value(s_val));
+ ASSERT_TRUE(elem);
+ ASSERT_EQ(Element::string, elem->getType());
+ EXPECT_EQ(str, elem->stringValue());
+ elem.reset();
+
+ // Enumeration item.
+ s_val.reset(new Val(str.c_str(), SR_ENUM_T));
+ EXPECT_NO_THROW(elem = TranslatorBasic::value(s_val));
+ ASSERT_TRUE(elem);
+ ASSERT_EQ(Element::string, elem->getType());
+ EXPECT_EQ(str, elem->stringValue());
+ elem.reset();
+
+ // Binary.
+ string binary("Zm9vYmFy");
+ s_val.reset(new Val(binary.c_str(), SR_BINARY_T));
+ EXPECT_NO_THROW(elem = TranslatorBasic::value(s_val));
+ ASSERT_TRUE(elem);
+ ASSERT_EQ(Element::string, elem->getType());
+ EXPECT_EQ("foobar", elem->stringValue());
+ elem.reset();
+
+ // Unknown / unsupported.
+ double d64(.1234);
+ s_val.reset(new Val(d64));
+ EXPECT_THROW(TranslatorBasic::value(s_val), NotImplemented);
+}
+
+// Test basic yang value to JSON using sysrepo test models.
+TEST(TranslatorBasicTest, getItem) {
+ // Get a translator object to play with.
+ S_Connection conn(new Connection("translator unittests"));
+ S_Session sess(new Session(conn, SR_DS_CANDIDATE));
+ boost::scoped_ptr<TranslatorBasic> t_obj;
+ ASSERT_NO_THROW(t_obj.reset(new TranslatorBasic(sess)));
+
+ // Container.
+ string xpath = "/example-module:container/list";
+ S_Val s_val;
+ EXPECT_NO_THROW(sess->set_item(xpath.c_str(), s_val));
+ ConstElementPtr elem;
+ EXPECT_NO_THROW(elem = t_obj->getItem("/example-module:container"));
+ EXPECT_FALSE(elem);
+ elem.reset();
+
+ // List.
+ EXPECT_NO_THROW(elem = t_obj->getItem(xpath));
+ ASSERT_TRUE(elem);
+ ASSERT_EQ(Element::list, elem->getType());
+ EXPECT_EQ(0, elem->size());
+ elem.reset();
+
+ // String.
+ xpath = "/test-module:main/string";
+ s_val.reset(new Val("str", SR_STRING_T));
+ EXPECT_NO_THROW(sess->set_item(xpath.c_str(), s_val));
+ EXPECT_NO_THROW(elem = t_obj->getItem(xpath));
+ ASSERT_TRUE(elem);
+ ASSERT_EQ(Element::string, elem->getType());
+ EXPECT_EQ("str", elem->stringValue());
+ elem.reset();
+
+ // Bool.
+ xpath = "/test-module:main/boolean";
+ s_val.reset(new Val(true, SR_BOOL_T));
+ EXPECT_NO_THROW(sess->set_item(xpath.c_str(), s_val));
+ EXPECT_NO_THROW(elem = t_obj->getItem(xpath));
+ ASSERT_TRUE(elem);
+ ASSERT_EQ(Element::boolean, elem->getType());
+ EXPECT_TRUE(elem->boolValue());
+ elem.reset();
+
+ // Unsigned 8 bit integer.
+ xpath = "/test-module:main/ui8";
+ uint8_t u8(8);
+ s_val.reset(new Val(u8, SR_UINT8_T));
+ EXPECT_NO_THROW(sess->set_item(xpath.c_str(), s_val));
+ EXPECT_NO_THROW(elem = t_obj->getItem(xpath));
+ ASSERT_TRUE(elem);
+ ASSERT_EQ(Element::integer, elem->getType());
+ EXPECT_EQ(8, elem->intValue());
+ elem.reset();
+
+ // Unsigned 16 bit integer.
+ xpath = "/test-module:main/ui16";
+ uint16_t u16(16);
+ s_val.reset(new Val(u16, SR_UINT16_T));
+ EXPECT_NO_THROW(sess->set_item(xpath.c_str(), s_val));
+ EXPECT_NO_THROW(elem = t_obj->getItem(xpath));
+ ASSERT_TRUE(elem);
+ ASSERT_EQ(Element::integer, elem->getType());
+ EXPECT_EQ(16, elem->intValue());
+ elem.reset();
+
+ // Unsigned 32 bit integer.
+ xpath = "/test-module:main/ui32";
+ uint32_t u32(32);
+ s_val.reset(new Val(u32, SR_UINT32_T));
+ EXPECT_NO_THROW(sess->set_item(xpath.c_str(), s_val));
+ EXPECT_NO_THROW(elem = t_obj->getItem(xpath));
+ ASSERT_TRUE(elem);
+ ASSERT_EQ(Element::integer, elem->getType());
+ EXPECT_EQ(32, elem->intValue());
+ elem.reset();
+
+ // Signed 8 bit integer.
+ xpath = "/test-module:main/i8";
+ int8_t s8(8);
+ s_val.reset(new Val(s8, SR_INT8_T));
+ EXPECT_NO_THROW(sess->set_item(xpath.c_str(), s_val));
+ EXPECT_NO_THROW(elem = t_obj->getItem(xpath));
+ ASSERT_TRUE(elem);
+ ASSERT_EQ(Element::integer, elem->getType());
+ EXPECT_EQ(8, elem->intValue());
+ elem.reset();
+
+ // Signed 16 bit integer.
+ xpath = "/test-module:main/i16";
+ int16_t s16(16);
+ s_val.reset(new Val(s16, SR_INT16_T));
+ EXPECT_NO_THROW(sess->set_item(xpath.c_str(), s_val));
+ EXPECT_NO_THROW(elem = t_obj->getItem(xpath));
+ ASSERT_TRUE(elem);
+ ASSERT_EQ(Element::integer, elem->getType());
+ EXPECT_EQ(16, elem->intValue());
+ elem.reset();
+
+ // Signed 32 bit integer.
+ xpath = "/test-module:main/i32";
+ int32_t s32(32);
+ s_val.reset(new Val(s32, SR_INT32_T));
+ EXPECT_NO_THROW(sess->set_item(xpath.c_str(), s_val));
+ EXPECT_NO_THROW(elem = t_obj->getItem(xpath));
+ ASSERT_TRUE(elem);
+ ASSERT_EQ(Element::integer, elem->getType());
+ EXPECT_EQ(32, elem->intValue());
+ elem.reset();
+
+ // Identity reference.
+ xpath = "/test-module:main/id_ref";
+ s_val.reset(new Val("id_1", SR_IDENTITYREF_T));
+ EXPECT_NO_THROW(sess->set_item(xpath.c_str(), s_val));
+ EXPECT_NO_THROW(elem = t_obj->getItem(xpath));
+ ASSERT_TRUE(elem);
+ ASSERT_EQ(Element::string, elem->getType());
+ EXPECT_EQ("id_1", elem->stringValue());
+ elem.reset();
+
+ // Enumeration item.
+ xpath = "/test-module:main/enum";
+ s_val.reset(new Val("maybe", SR_ENUM_T));
+ EXPECT_NO_THROW(sess->set_item(xpath.c_str(), s_val));
+ EXPECT_NO_THROW(elem = t_obj->getItem(xpath));
+ ASSERT_TRUE(elem);
+ ASSERT_EQ(Element::string, elem->getType());
+ EXPECT_EQ("maybe", elem->stringValue());
+ elem.reset();
+
+ // Binary.
+ xpath = "/test-module:main/raw";
+ s_val.reset(new Val("Zm9vYmFy", SR_BINARY_T));
+ EXPECT_NO_THROW(sess->set_item(xpath.c_str(), s_val));
+ EXPECT_NO_THROW(elem = t_obj->getItem(xpath));
+ ASSERT_TRUE(elem);
+ ASSERT_EQ(Element::string, elem->getType());
+ EXPECT_EQ("foobar", elem->stringValue());
+ elem.reset();
+
+ // Leaf-list: not yet exist.
+ xpath = "/test-module:main/numbers";
+ EXPECT_NO_THROW(elem = t_obj->getItem(xpath));
+ EXPECT_FALSE(elem);
+ elem.reset();
+
+ // No easy way to create it empty.
+
+ // Leaf-list: 1, 2 and 3.
+ u8 = 1;
+ s_val.reset(new Val(u8, SR_UINT8_T));
+ EXPECT_NO_THROW(sess->set_item(xpath.c_str(), s_val));
+ u8 = 2;
+ s_val.reset(new Val(u8, SR_UINT8_T));
+ EXPECT_NO_THROW(sess->set_item(xpath.c_str(), s_val));
+ u8 = 3;
+ s_val.reset(new Val(u8, SR_UINT8_T));
+ EXPECT_NO_THROW(sess->set_item(xpath.c_str(), s_val));
+ EXPECT_NO_THROW(elem = t_obj->getItems(xpath));
+ ASSERT_TRUE(elem);
+ ASSERT_EQ(Element::list, elem->getType());
+ EXPECT_EQ(3, elem->size());
+ EXPECT_EQ("[ 1, 2, 3 ]", elem->str());
+ elem.reset();
+
+ // Unknown / unsupported.
+ xpath = "/test-module:main/dec64";
+ s_val.reset(new Val(9.85));
+ EXPECT_NO_THROW(sess->set_item(xpath.c_str(), s_val));
+ EXPECT_THROW(elem = t_obj->getItem(xpath), NotImplemented);
+ elem.reset();
+
+ // Not found.
+ xpath = "/test-module:main/no_such_string";
+ EXPECT_NO_THROW(sess->delete_item(xpath.c_str()));
+ EXPECT_NO_THROW(elem = t_obj->getItem(xpath));
+ EXPECT_FALSE(elem);
+ elem.reset();
+
+ // Check error.
+ xpath = "null";
+ try {
+ elem = t_obj->getItem(xpath);
+ ADD_FAILURE() << "expected exception";
+ } catch (const SysrepoError& ex) {
+ EXPECT_EQ("sysrepo error getting item at 'null': Invalid argument",
+ string(ex.what()));
+ } catch (const std::exception& ex) {
+ ADD_FAILURE() << "unexpected exception with: " << ex.what();
+ }
+}
+
+// Test JSON to basic yang value using the static method.
+TEST(TranslatorBasicTest, valueTo) {
+
+ // Null.
+ ConstElementPtr elem;
+ EXPECT_THROW(TranslatorBasic::value(elem, SR_STRING_T), BadValue);
+
+ // Container.
+ elem = Element::createMap();
+ EXPECT_THROW(TranslatorBasic::value(elem, SR_CONTAINER_T), NotImplemented);
+ EXPECT_THROW(TranslatorBasic::value(elem, SR_CONTAINER_PRESENCE_T), NotImplemented);
+
+ // List.
+ elem = Element::createList();
+ S_Val s_val;
+ EXPECT_NO_THROW(s_val = TranslatorBasic::value(elem, SR_LIST_T));
+ EXPECT_FALSE(s_val);
+ s_val.reset();
+
+ // String.
+ string str("foo");
+ elem = Element::create(str);
+ EXPECT_NO_THROW(s_val = TranslatorBasic::value(elem, SR_STRING_T));
+ ASSERT_TRUE(s_val);
+ ASSERT_EQ(SR_STRING_T, s_val->type());
+ EXPECT_EQ(str, string(s_val->data()->get_string()));
+ s_val.reset();
+
+ // Bool.
+ elem = Element::create(false);
+ EXPECT_NO_THROW(s_val = TranslatorBasic::value(elem, SR_BOOL_T));
+ ASSERT_TRUE(s_val);
+ ASSERT_EQ(SR_BOOL_T, s_val->type());
+ EXPECT_FALSE(s_val->data()->get_bool());
+ s_val.reset();
+
+ // Unsigned 8 bit integer.
+ elem = Element::create(123);
+ EXPECT_NO_THROW(s_val = TranslatorBasic::value(elem, SR_UINT8_T));
+ ASSERT_TRUE(s_val);
+ ASSERT_EQ(SR_UINT8_T, s_val->type());
+ EXPECT_EQ(123, s_val->data()->get_uint8());
+ elem.reset();
+
+ // Unsigned 16 bit integer.
+ elem = Element::create(12345);
+ EXPECT_NO_THROW(s_val = TranslatorBasic::value(elem, SR_UINT16_T));
+ ASSERT_TRUE(s_val);
+ ASSERT_EQ(SR_UINT16_T, s_val->type());
+ EXPECT_EQ(12345, s_val->data()->get_uint16());
+ elem.reset();
+
+ // Unsigned 32 bit integer.
+ elem = Element::create(123456789);
+ EXPECT_NO_THROW(s_val = TranslatorBasic::value(elem, SR_UINT32_T));
+ ASSERT_TRUE(s_val);
+ ASSERT_EQ(SR_UINT32_T, s_val->type());
+ EXPECT_EQ(123456789, s_val->data()->get_uint32());
+ elem.reset();
+
+ // Signed 8 bit integer.
+ elem = Element::create(-123);
+ EXPECT_NO_THROW(s_val = TranslatorBasic::value(elem, SR_INT8_T));
+ ASSERT_TRUE(s_val);
+ ASSERT_EQ(SR_INT8_T, s_val->type());
+ EXPECT_EQ(-123, s_val->data()->get_int8());
+ elem.reset();
+
+ // Signed 16 bit integer.
+ elem = Element::create(-12345);
+ EXPECT_NO_THROW(s_val = TranslatorBasic::value(elem, SR_INT16_T));
+ ASSERT_TRUE(s_val);
+ ASSERT_EQ(SR_INT16_T, s_val->type());
+ EXPECT_EQ(-12345, s_val->data()->get_int16());
+ elem.reset();
+
+ // Signed 32 bit integer.
+ elem = Element::create(-123456789);
+ EXPECT_NO_THROW(s_val = TranslatorBasic::value(elem, SR_INT32_T));
+ ASSERT_TRUE(s_val);
+ ASSERT_EQ(SR_INT32_T, s_val->type());
+ EXPECT_EQ(-123456789, s_val->data()->get_int32());
+ elem.reset();
+
+ // Identity reference.
+ elem = Element::create(str);
+ EXPECT_NO_THROW(s_val = TranslatorBasic::value(elem, SR_IDENTITYREF_T));
+ ASSERT_TRUE(s_val);
+ ASSERT_EQ(SR_IDENTITYREF_T, s_val->type());
+ EXPECT_EQ(str, string(s_val->data()->get_identityref()));
+ s_val.reset();
+
+ // Enumeration item.
+ EXPECT_NO_THROW(s_val = TranslatorBasic::value(elem, SR_ENUM_T));
+ ASSERT_TRUE(s_val);
+ EXPECT_EQ(str, string(s_val->data()->get_enum()));
+ s_val.reset();
+
+ // Binary.
+ elem = Element::create(string("foobar"));
+ EXPECT_NO_THROW(s_val = TranslatorBasic::value(elem, SR_BINARY_T));
+ ASSERT_TRUE(s_val);
+ EXPECT_EQ("Zm9vYmFy", string(s_val->data()->get_binary()));
+ s_val.reset();
+
+ // Unknown / unsupported.
+ elem = Element::create(.1234);
+ EXPECT_THROW(TranslatorBasic::value(elem, SR_DECIMAL64_T), NotImplemented);
+}
+
+// Test JSON to basic yang value using sysrepo test models.
+TEST(TranslatorBasicTest, setItem) {
+ // Get a translator object to play with.
+ S_Connection conn(new Connection("translator unittests"));
+ S_Session sess(new Session(conn, SR_DS_CANDIDATE));
+ boost::scoped_ptr<TranslatorBasic> t_obj;
+ ASSERT_NO_THROW(t_obj.reset(new TranslatorBasic(sess)));
+
+ // Container.
+ string xpath = "/example-module:container";
+ ConstElementPtr elem = Element::createMap();
+ EXPECT_THROW(t_obj->setItem(xpath, elem, SR_CONTAINER_T), NotImplemented);
+ EXPECT_THROW(t_obj->setItem(xpath, elem, SR_CONTAINER_PRESENCE_T),
+ NotImplemented);
+
+ // List.
+ xpath = "/example-module:container/list";
+ elem = Element::createList();
+ EXPECT_NO_THROW(t_obj->setItem(xpath, elem, SR_LIST_T));
+ S_Val s_val;
+ EXPECT_NO_THROW(s_val = sess->get_item(xpath.c_str()));
+ ASSERT_TRUE(s_val);
+ ASSERT_EQ(SR_LIST_T, s_val->type());
+ s_val.reset();
+
+ // String.
+ xpath = "/test-module:main/string";
+ elem = Element::create(string("str"));
+ EXPECT_NO_THROW(t_obj->setItem(xpath, elem, SR_STRING_T));
+ EXPECT_NO_THROW(s_val = sess->get_item(xpath.c_str()));
+ ASSERT_TRUE(s_val);
+ ASSERT_EQ(SR_STRING_T, s_val->type());
+ EXPECT_EQ("str", string(s_val->data()->get_string()));
+ s_val.reset();
+
+ // Bool.
+ xpath = "/test-module:main/boolean";
+ elem = Element::create(true);
+ EXPECT_NO_THROW(t_obj->setItem(xpath, elem, SR_BOOL_T));
+ EXPECT_NO_THROW(s_val = sess->get_item(xpath.c_str()));
+ ASSERT_TRUE(s_val);
+ ASSERT_EQ(SR_BOOL_T, s_val->type());
+ EXPECT_TRUE(s_val->data()->get_bool());
+ s_val.reset();
+
+ // Unsigned 8 bit integer.
+ xpath = "/test-module:main/ui8";
+ elem = Element::create(8);
+ EXPECT_NO_THROW(t_obj->setItem(xpath, elem, SR_UINT8_T));
+ EXPECT_NO_THROW(s_val = sess->get_item(xpath.c_str()));
+ ASSERT_TRUE(s_val);
+ ASSERT_EQ(SR_UINT8_T, s_val->type());
+ EXPECT_EQ(8, s_val->data()->get_uint8());
+ s_val.reset();
+
+ // Unsigned 16 bit integer.
+ xpath = "/test-module:main/ui16";
+ elem = Element::create(16);
+ EXPECT_NO_THROW(t_obj->setItem(xpath, elem, SR_UINT16_T));
+ EXPECT_NO_THROW(s_val = sess->get_item(xpath.c_str()));
+ ASSERT_TRUE(s_val);
+ ASSERT_EQ(SR_UINT16_T, s_val->type());
+ EXPECT_EQ(16, s_val->data()->get_uint16());
+ s_val.reset();
+
+ // Unsigned 32 bit integer.
+ xpath = "/test-module:main/ui32";
+ elem = Element::create(32);
+ EXPECT_NO_THROW(t_obj->setItem(xpath, elem, SR_UINT32_T));
+ EXPECT_NO_THROW(s_val = sess->get_item(xpath.c_str()));
+ ASSERT_TRUE(s_val);
+ ASSERT_EQ(SR_UINT32_T, s_val->type());
+ EXPECT_EQ(32, s_val->data()->get_uint32());
+ s_val.reset();
+
+ // Signed 8 bit integer.
+ xpath = "/test-module:main/i8";
+ elem = Element::create(8);
+ EXPECT_NO_THROW(t_obj->setItem(xpath, elem, SR_INT8_T));
+ EXPECT_NO_THROW(s_val = sess->get_item(xpath.c_str()));
+ ASSERT_TRUE(s_val);
+ ASSERT_EQ(SR_INT8_T, s_val->type());
+ EXPECT_EQ(8, s_val->data()->get_int8());
+ s_val.reset();
+
+ // Signed 16 bit integer.
+ xpath = "/test-module:main/i16";
+ elem = Element::create(16);
+ EXPECT_NO_THROW(t_obj->setItem(xpath, elem, SR_INT16_T));
+ EXPECT_NO_THROW(s_val = sess->get_item(xpath.c_str()));
+ ASSERT_TRUE(s_val);
+ ASSERT_EQ(SR_INT16_T, s_val->type());
+ EXPECT_EQ(16, s_val->data()->get_int16());
+ s_val.reset();
+
+ // Signed 32 bit integer.
+ xpath = "/test-module:main/i32";
+ elem = Element::create(32);
+ EXPECT_NO_THROW(t_obj->setItem(xpath, elem, SR_INT32_T));
+ EXPECT_NO_THROW(s_val = sess->get_item(xpath.c_str()));
+ ASSERT_TRUE(s_val);
+ ASSERT_EQ(SR_INT32_T, s_val->type());
+ EXPECT_EQ(32, s_val->data()->get_int32());
+ s_val.reset();
+
+ // Identity reference.
+ xpath = "/test-module:main/id_ref";
+ elem = Element::create(string("id_1"));
+ EXPECT_NO_THROW(t_obj->setItem(xpath, elem, SR_IDENTITYREF_T));
+ EXPECT_NO_THROW(s_val = sess->get_item(xpath.c_str()));
+ ASSERT_TRUE(s_val);
+ ASSERT_EQ(SR_IDENTITYREF_T, s_val->type());
+ EXPECT_EQ("id_1", string(s_val->data()->get_identityref()));
+ s_val.reset();
+
+ // Enumeration item.
+ xpath = "/test-module:main/enum";
+ elem = Element::create(string("maybe"));
+ EXPECT_NO_THROW(t_obj->setItem(xpath, elem, SR_ENUM_T));
+ EXPECT_NO_THROW(s_val = sess->get_item(xpath.c_str()));
+ ASSERT_TRUE(s_val);
+ ASSERT_EQ(SR_ENUM_T, s_val->type());
+ EXPECT_EQ("maybe", string(s_val->data()->get_enum()));
+ s_val.reset();
+
+ // Binary.
+ xpath = "/test-module:main/raw";
+ elem = Element::create(string("foobar"));
+ EXPECT_NO_THROW(t_obj->setItem(xpath, elem, SR_BINARY_T));
+ EXPECT_NO_THROW(s_val = sess->get_item(xpath.c_str()));
+ ASSERT_TRUE(s_val);
+ ASSERT_EQ(SR_BINARY_T, s_val->type());
+ EXPECT_EQ("Zm9vYmFy", string(s_val->data()->get_binary()));
+ s_val.reset();
+
+ // Leaf-list.
+ xpath = "/test-module:main/numbers";
+ S_Vals s_vals;
+ EXPECT_NO_THROW(s_vals = sess->get_items(xpath.c_str()));
+ EXPECT_FALSE(s_vals);
+ s_vals.reset();
+
+ // Fill it.
+ elem = Element::create(1);
+ EXPECT_NO_THROW(t_obj->setItem(xpath, elem, SR_UINT8_T));
+ elem = Element::create(2);
+ EXPECT_NO_THROW(t_obj->setItem(xpath, elem, SR_UINT8_T));
+ elem = Element::create(3);
+ EXPECT_NO_THROW(t_obj->setItem(xpath, elem, SR_UINT8_T));
+ EXPECT_NO_THROW(s_vals = sess->get_items(xpath.c_str()));
+ ASSERT_TRUE(s_vals);
+ EXPECT_EQ(3, s_vals->val_cnt());
+ s_vals.reset();
+
+ // Clean it.
+ EXPECT_NO_THROW(t_obj->delItem(xpath));
+ EXPECT_NO_THROW(s_vals = sess->get_items(xpath.c_str()));
+ EXPECT_FALSE(s_vals);
+ s_vals.reset();
+
+ // Unknown / unsupported.
+ xpath = "/test-module:main/dec64";
+ elem = Element::create(9.85);
+ EXPECT_THROW(t_obj->setItem(xpath, elem, SR_DECIMAL64_T), NotImplemented);
+
+ // Bad xpath.
+ xpath = "/test-module:main/no_such_string";
+ elem = Element::create(string("str"));
+ try {
+ t_obj->setItem(xpath, elem, SR_STRING_T);
+ ADD_FAILURE() << "expected exception";
+ } catch (const SysrepoError& ex) {
+ string expected = "sysrepo error setting item '\"str\"' at '" +
+ xpath + "': Request contains unknown element";
+ EXPECT_EQ(expected, string(ex.what()));
+ } catch (const std::exception& ex) {
+ ADD_FAILURE() << "unexpected exception with: " << ex.what();
+ }
+
+ // Bad type.
+ xpath = "/test-module:main/string";
+ elem = Element::create(true);
+ try {
+ t_obj->setItem(xpath, elem, SR_BOOL_T);
+ ADD_FAILURE() << "expected exception";
+ } catch (const SysrepoError& ex) {
+ string expected = "sysrepo error setting item 'true' at '" +
+ xpath + "': Invalid argument";
+ EXPECT_EQ(expected, string(ex.what()));
+ } catch (const std::exception& ex) {
+ ADD_FAILURE() << "unexpected exception with: " << ex.what();
+ }
+
+ // Delete (twice).
+ xpath = "/test-module:main/string";
+ EXPECT_NO_THROW(s_val = sess->get_item(xpath.c_str()));
+ EXPECT_TRUE(s_val);
+ s_val.reset();
+ EXPECT_NO_THROW(t_obj->delItem(xpath));
+ EXPECT_NO_THROW(s_val = sess->get_item(xpath.c_str()));
+ EXPECT_FALSE(s_val);
+ EXPECT_NO_THROW(t_obj->delItem(xpath));
+}
+
+// Test yang list iteration.
+TEST(TranslatorBasicTest, list) {
+ // Get a translator object to play with.
+ S_Connection conn(new Connection("translator unittests"));
+ S_Session sess(new Session(conn, SR_DS_CANDIDATE));
+ boost::scoped_ptr<TranslatorBasic> t_obj;
+ ASSERT_NO_THROW(t_obj.reset(new TranslatorBasic(sess)));
+
+ // Empty list.
+ S_Iter_Value iter;
+ EXPECT_NO_THROW(iter = t_obj->getIter("/example-module:container/list"));
+ ASSERT_TRUE(iter);
+ string xpath;
+ EXPECT_NO_THROW(xpath = t_obj->getNext(iter));
+ EXPECT_TRUE(xpath.empty());
+
+ // Retried with a filled list.
+ xpath = "/example-module:container/list[key1='key1'][key2='key2']/leaf";
+ S_Val s_val(new Val("Leaf value"));
+ EXPECT_NO_THROW(sess->set_item(xpath.c_str(), s_val));
+ EXPECT_NO_THROW(iter = t_obj->getIter("/example-module:container/list"));
+ ASSERT_TRUE(iter);
+ EXPECT_NO_THROW(xpath = t_obj->getNext(iter));
+ EXPECT_EQ("/example-module:container/list[key1='key1'][key2='key2']", xpath);
+ EXPECT_NO_THROW(xpath = t_obj->getNext(iter));
+ EXPECT_TRUE(xpath.empty());
+
+ // Not found: same than empty because sr_get_items_iter() translates
+ // SR_ERR_NOT_FOUND by SR_ERR_OK...
+}
+
+}; // end of anonymous namespace
--- /dev/null
+// Copyright (C) 2018 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <yang/translator.h>
+#include <util/encode/base64.h>
+#include <cstring>
+
+using namespace std;
+using namespace isc::data;
+using namespace isc::util::encode;
+
+namespace {
+
+string encode64(const string& input) {
+ vector<uint8_t> binary;
+ binary.resize(input.size());
+ memmove(&binary[0], input.c_str(), binary.size());
+ return (encodeBase64(binary));
+}
+
+string decode64(const string& input) {
+ vector<uint8_t> binary;
+ decodeBase64(input, binary);
+ string result;
+ result.resize(binary.size());
+ memmove(&result[0], &binary[0], result.size());
+ return (result);
+}
+
+} // end of anonymous namespace
+
+namespace isc {
+namespace yang {
+
+TranslatorBasic::TranslatorBasic(S_Session session) : session_(session) {
+}
+
+TranslatorBasic::~TranslatorBasic() {
+}
+
+ElementPtr
+TranslatorBasic::value(S_Val s_val) {
+ if (!s_val) {
+ isc_throw(BadValue, "value called with null");
+ }
+ switch (s_val->type()) {
+ case SR_CONTAINER_T:
+ case SR_CONTAINER_PRESENCE_T:
+ // Internal node.
+ return (ElementPtr());
+
+ case SR_LIST_T:
+ return (Element::createList());
+
+ case SR_STRING_T:
+ return (Element::create(string(s_val->data()->get_string())));
+
+ case SR_BOOL_T:
+ return (Element::create(s_val->data()->get_bool() ? true : false));
+
+ case SR_UINT8_T:
+ return (Element::create(static_cast<long long>(s_val->data()->get_uint8())));
+ case SR_UINT16_T:
+ return (Element::create(static_cast<long long>(s_val->data()->get_uint16())));
+
+ case SR_UINT32_T:
+ return (Element::create(static_cast<long long>(s_val->data()->get_uint32())));
+
+ case SR_INT8_T:
+ return (Element::create(static_cast<long long>(s_val->data()->get_int8())));
+
+ case SR_INT16_T:
+ return (Element::create(static_cast<long long>(s_val->data()->get_int16())));
+
+ case SR_INT32_T:
+ return (Element::create(static_cast<long long>(s_val->data()->get_int32())));
+
+ case SR_IDENTITYREF_T:
+ return (Element::create(string(s_val->data()->get_identityref())));
+
+ case SR_ENUM_T:
+ return (Element::create(string(s_val->data()->get_enum())));
+
+ case SR_BINARY_T:
+ return (Element::create(decode64(s_val->data()->get_binary())));
+
+ default:
+ isc_throw(NotImplemented,
+ "value called with unupported type: " << s_val->type());
+ }
+}
+
+ElementPtr
+TranslatorBasic::getItem(const string& xpath) {
+ S_Val s_val;
+ try {
+ s_val = session_->get_item(xpath.c_str());
+ } catch (const sysrepo_exception& ex) {
+ isc_throw(SysrepoError,
+ "sysrepo error getting item at '" << xpath
+ << "': " << ex.what());
+ }
+ if (!s_val) {
+ return (ElementPtr());
+ }
+ return (value(s_val));
+}
+
+ElementPtr
+TranslatorBasic::getItems(const string& xpath) {
+ S_Vals s_vals;
+ try {
+ s_vals = session_->get_items(xpath.c_str());
+ if (!s_vals) {
+ return (ElementPtr());
+ }
+ ElementPtr result = Element::createList();
+ for (size_t i = 0; i < s_vals->val_cnt(); ++i) {
+ S_Val s_val = s_vals->val(i);
+ result->add(value(s_val));
+ }
+ return (result);
+ } catch (const sysrepo_exception& ex) {
+ isc_throw(SysrepoError,
+ "sysrepo error getting item at '" << xpath
+ << "': " << ex.what());
+ }
+}
+
+S_Val
+TranslatorBasic::value(ConstElementPtr elem, sr_type_t type) {
+ if (!elem) {
+ isc_throw(BadValue, "value called with null");
+ }
+ S_Val s_val;
+ switch (type) {
+ case SR_CONTAINER_T:
+ case SR_CONTAINER_PRESENCE_T:
+ isc_throw(NotImplemented, "value called for a container");
+
+ case SR_LIST_T:
+ if (elem->getType() != Element::list) {
+ isc_throw(BadValue, "value for a list called with not a list");
+ }
+ // Return null.
+ break;
+
+ case SR_STRING_T:
+ case SR_IDENTITYREF_T:
+ case SR_ENUM_T:
+ if (elem->getType() != Element::string) {
+ isc_throw(BadValue, "value for a string called with not a string");
+ }
+ s_val.reset(new Val(elem->stringValue().c_str(), type));
+ break;
+
+ case SR_BOOL_T:
+ if (elem->getType() != Element::boolean) {
+ isc_throw(BadValue, "value for a boolean called with not a boolean");
+ }
+ s_val.reset(new Val(elem->boolValue(), type));
+ break;
+
+ case SR_UINT8_T:
+ if (elem->getType() != Element::integer) {
+ isc_throw(BadValue, "value for an integer called with not an integer");
+ }
+ s_val.reset(new Val(static_cast<uint8_t>(elem->intValue()), type));
+ break;
+
+ case SR_UINT16_T:
+ if (elem->getType() != Element::integer) {
+ isc_throw(BadValue, "value for an integer called with not an integer");
+ }
+ s_val.reset(new Val(static_cast<uint16_t>(elem->intValue()), type));
+ break;
+
+ case SR_UINT32_T:
+ if (elem->getType() != Element::integer) {
+ isc_throw(BadValue, "value for an integer called with not an integer");
+ }
+ s_val.reset(new Val(static_cast<uint32_t>(elem->intValue()), type));
+ break;
+
+ case SR_INT8_T:
+ if (elem->getType() != Element::integer) {
+ isc_throw(BadValue, "value for an integer called with not an integer");
+ }
+ s_val.reset(new Val(static_cast<int8_t>(elem->intValue()), type));
+ break;
+
+ case SR_INT16_T:
+ if (elem->getType() != Element::integer) {
+ isc_throw(BadValue, "value for an integer called with not an integer");
+ }
+ s_val.reset(new Val(static_cast<int16_t>(elem->intValue()), type));
+ break;
+
+ case SR_INT32_T:
+ if (elem->getType() != Element::integer) {
+ isc_throw(BadValue, "value for an integer called with not an integer");
+ }
+ s_val.reset(new Val(static_cast<int32_t>(elem->intValue()), type));
+ break;
+
+ case SR_BINARY_T:
+ if (elem->getType() != Element::string) {
+ isc_throw(BadValue, "value for a base64 called with not a string");
+ }
+ s_val.reset(new Val(encode64(elem->stringValue()).c_str(), type));
+ break;
+
+ default:
+ isc_throw(NotImplemented,
+ "value called with unupported type: " << type);
+ }
+
+ return (s_val);
+}
+
+void
+TranslatorBasic::setItem(const string& xpath, ConstElementPtr elem,
+ sr_type_t type) {
+ S_Val s_val = value(elem, type);
+ if (!s_val && (type != SR_LIST_T)) {
+ return;
+ }
+ try {
+ session_->set_item(xpath.c_str(), s_val);
+ } catch (const sysrepo_exception& ex) {
+ isc_throw(SysrepoError,
+ "sysrepo error setting item '" << elem->str()
+ << "' at '" << xpath << "': " << ex.what());
+ }
+}
+
+void
+TranslatorBasic::delItem(const std::string& xpath) {
+ try {
+ session_->delete_item(xpath.c_str());
+ } catch (const sysrepo_exception& ex) {
+ isc_throw(SysrepoError,
+ "sysrepo error deleting item at '"
+ << xpath << "': " << ex.what());
+ }
+}
+
+
+S_Iter_Value
+TranslatorBasic::getIter(const std::string& xpath) {
+ return (session_->get_items_iter(xpath.c_str()));
+}
+
+string
+TranslatorBasic::getNext(S_Iter_Value iter) {
+ if (!iter) {
+ isc_throw(BadValue, "getNext called with null");
+ }
+ S_Val s_val;
+ try {
+ s_val = session_->get_item_next(iter);
+ } catch (const sysrepo_exception&) {
+ // Should not happen according to the doc but still happen?
+ return ("");
+ }
+ if (!s_val) {
+ return ("");
+ }
+ return (s_val->xpath());
+}
+
+}; // end of namespace isc::yang
+}; // end of namespace isc