Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add GetValueEndPoint() to Manager #2013

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions cpp/src/Driver.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,10 @@ namespace OpenZWave
class Msg;
class TimerThread;
}
namespace Testing
{
class TestHelper;
}

/** \brief The Driver class handles communication between OpenZWave
* and a device attached via a serial port (typically a controller).
Expand All @@ -103,6 +107,7 @@ namespace OpenZWave
friend class Internal::Msg;
friend class Internal::ManufacturerSpecificDB;
friend class TimerThread;
friend class Testing::TestHelper;

//-----------------------------------------------------------------------------
// Controller Interfaces
Expand Down
43 changes: 43 additions & 0 deletions cpp/src/Manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2518,6 +2518,49 @@ bool Manager::GetValueListValues(ValueID const& _id, vector<int32>* o_value)
return res;
}

uint8 Manager::GetValueEndPoint(ValueID const &_id)
{
if (Driver *driver = GetDriver(_id.GetHomeId()))
{
// Need to lock and unlock nodes before calling driver->GetValue
Internal::LockGuard LG(driver->m_nodeMutex);

// We don't actually need the Value, everything we need is in _id
// But we call GetValue to check if it is valid.
if (auto v = driver->GetValue(_id))
{
// Because GetValue worked, the Node ID and CC have to be valid
// So theoretically GetNode and GetCommandClass cannot fail.
// Unless... there is some multithread issue somewhere else.
if (auto node = driver->GetNode(_id.GetNodeId()))
{
auto cc = node->GetCommandClass(_id.GetCommandClassId());
if (cc)
{
return cc->GetEndPoint(_id.GetInstance());
}
else
{
OZW_ERROR(OZWException::OZWEXCEPTION_INVALID_VALUEID, "Invalid ValueID passed to GetValueEndPoint: node does not have CommandClass");
}
}
else
{
OZW_ERROR(OZWException::OZWEXCEPTION_INVALID_VALUEID, "Invalid ValueID passed to GetValueEndPoint: node does exist");
}
}
else
{
OZW_ERROR(OZWException::OZWEXCEPTION_INVALID_VALUEID, "Invalid ValueID passed to GetValueEndPoint");
}
}
else
{
// There is no real "else" part because either we get a driver or GetDriver throws an exception
return 0;
}
}

//-----------------------------------------------------------------------------
// <Manager::GetValueFloatPrecision>
// Gets a value's scale as a uint8
Expand Down
15 changes: 15 additions & 0 deletions cpp/src/Manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,11 @@ namespace OpenZWave
class Node;
class Notification;

namespace Testing
{
class TestHelper;
}

/** \brief
* The main public interface to OpenZWave.
*
Expand Down Expand Up @@ -114,6 +119,7 @@ namespace OpenZWave
friend class Internal::VC::Value;
friend class Internal::VC::ValueStore;
friend class Internal::Msg;
friend class Testing::TestHelper;

public:
typedef void (*pfnOnNotification_t)(Notification const* _pNotification, void* _context);
Expand Down Expand Up @@ -1260,6 +1266,15 @@ namespace OpenZWave
*/
bool GetValueListValues(ValueID const& _id, vector<int32>* o_value);

/**
* \brief Gets the End Point of a ValueID
* \param _id The unique identifier of the value.
* \return The End Point of _id
* \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_VALUEID if the ValueID is invalid
* \throws OZWException with Type OZWException::OZWEXCEPTION_INVALID_HOMEID if the Driver cannot be found
*/
uint8 GetValueEndPoint(ValueID const& _id);

/**
* \brief Gets a float value's precision.
* \param _id The unique identifier of the value.
Expand Down
7 changes: 7 additions & 0 deletions cpp/src/Node.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,12 @@ namespace OpenZWave
class ProductDescriptor;
class ManufacturerSpecificDB;
}

namespace Testing
{
class TestHelper;
}

class Driver;
class Group;

Expand All @@ -97,6 +103,7 @@ namespace OpenZWave
friend class Internal::CC::Version;
friend class Internal::CC::ZWavePlusInfo;
friend class Internal::ManufacturerSpecificDB;
friend class Testing::TestHelper;

//-----------------------------------------------------------------------------
// Construction
Expand Down
7 changes: 7 additions & 0 deletions cpp/src/Options.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@

namespace OpenZWave
{
namespace Testing
{
class TestHelper;
}

/** \brief Manages library options read from XML files or the command line.
*
* A class that manages program options read from XML files or the command line.
Expand Down Expand Up @@ -65,6 +70,8 @@ namespace OpenZWave
*/
class OPENZWAVE_EXPORT Options
{
friend class Testing::TestHelper;

public:
enum OptionType
{
Expand Down
100 changes: 100 additions & 0 deletions cpp/test/Manager_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
//-----------------------------------------------------------------------------
//
// Manager_test.cpp
//
// Test Framework for Manager Stuff
//
// Copyright (c) 2019 Peter Gebruers <[email protected]>
//
// Based on work Copyrighted (c) 2017 Justin Hammond <[email protected]>
//
// SOFTWARE NOTICE AND LICENSE
//
// This file is part of OpenZWave.
//
// OpenZWave is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation, either version 3 of the License,
// or (at your option) any later version.
//
// OpenZWave is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with OpenZWave. If not, see <http://www.gnu.org/licenses/>.
//
//-----------------------------------------------------------------------------

#include "Manager.h"
#include "TestHelper.h"
#include "gtest/gtest.h"

namespace OpenZWave
{
namespace Testing
{

TEST_F(TestHelper, GetValueEndPoint)
{
// Test valid data
EXPECT_EQ(
Manager::Get()->GetValueEndPoint(ValueID(FakeHomeId, FakeNode2Id, ValueID::ValueGenre_Basic, FakeCommandClass, Instance1, FakeValueIndex, ValueID::ValueType_BitSet)),
0);

EXPECT_EQ(
Manager::Get()->GetValueEndPoint(ValueID(FakeHomeId, FakeNode2Id, ValueID::ValueGenre_Basic, FakeCommandClass, Instance2, FakeValueIndex, ValueID::ValueType_BitSet)),
1);

EXPECT_EQ(
Manager::Get()->GetValueEndPoint(ValueID(FakeHomeId, FakeNode2Id, ValueID::ValueGenre_Basic, FakeCommandClass, Instance3, FakeValueIndex, ValueID::ValueType_BitSet)),
127);

// Test *unset* Instance i.e. device does not have Instance

EXPECT_EQ(
Manager::Get()->GetValueEndPoint(ValueID(FakeHomeId, FakeNode2Id, ValueID::ValueGenre_Basic, FakeCommandClass, Instance4, FakeValueIndex, ValueID::ValueType_BitSet)),
0);

// Test exceptions

// Could compare "full" message but might prove "unstable" because it contains source code and line number
// EXPECT_STREQ(e.what(), "Manager.cpp:403 - InvalidHomeIDError (100) Msg: Invalid HomeId passed to GetDriver");

// Cannot use EXPECT_THROW of googletest here because we need to test properties of the exception.
// https://github.com/google/googletest/issues/952

try
{
Manager::Get()->GetValueEndPoint(ValueID(0, static_cast<uint64>(0x01)));
ADD_FAILURE() << "GetValueEndPoint should throw an error, but it did not...";
}
catch (OZWException &e)
{
EXPECT_EQ(e.GetMsg(), "Invalid HomeId passed to GetDriver");
EXPECT_EQ(e.GetType(), OZWException::ExceptionType::OZWEXCEPTION_INVALID_HOMEID);
}
catch (...)
{
ADD_FAILURE() << "GetValueEndPoint should throw OZWException but got a different type.\n ";
}

try
{
Manager::Get()->GetValueEndPoint(ValueID(FakeHomeId, static_cast<uint64>(0x01)));
ADD_FAILURE() << "GetValueEndPoint should throw an error, but it did not...";
}
catch (OZWException &e)
{
EXPECT_EQ(e.GetMsg(), "Invalid ValueID passed to GetValueEndPoint");
EXPECT_EQ(e.GetType(), OZWException::ExceptionType::OZWEXCEPTION_INVALID_VALUEID);
}
catch (...)
{
ADD_FAILURE() << "GetValueEndPoint should throw OZWException but got a different type.\n ";
}
}

} // namespace Testing
} // namespace OpenZWave
114 changes: 114 additions & 0 deletions cpp/test/TestHelper.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
//-----------------------------------------------------------------------------
// Copyright (c) 2019 Peter Gebruers <[email protected]>
//
// Based on work Copyrighted (c) 2017 Justin Hammond <[email protected]>
//
// SOFTWARE NOTICE AND LICENSE
//
// This file is part of OpenZWave.
//
// OpenZWave is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation, either version 3 of the License,
// or (at your option) any later version.
//
// OpenZWave is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with OpenZWave. If not, see <http://www.gnu.org/licenses/>.
//
//-----------------------------------------------------------------------------

/*
To get access to private members of Options, Manager and Driver,
this has to be in their header files

namespace Testing
{
class TestHelper;
}

friend class Testing::TestHelper;
*/

#include "TestHelper.h"
#include "Manager.h"
#include "Options.h"
#include "command_classes/CommandClass.h"

namespace OpenZWave
{
namespace Testing
{

void TestHelper::SetUp()
{
// Doing options = new Options then "fix up" the internal
// state of the object creates a "fake object". It is
// much faster, and lighter than calling Options::Create
// because the latter does a lot more. For testing purposes
// we don't need need everything done by Create.

// The constructor of Options does not seem to set "the singleton"
// while the constructor of Manager does set it... Do this here...
Options::s_instance = new Options("", "", "");

// Doing "new Manager" creates a "fake Manager object".
// It is much faster, and lighter than calling Manager::Create
// because the latter does a lot more... Like logging, doing http, load
// config files... Last time I checked, Create took > 1000 ms.
// doing "new Manager" takes a fraction of that.
// A call to Manager::Destroy(); is needed to free the memory
// Manager is a singleton.
new Manager();

// You would expect to call Manager::AddDriver("") here but that will start up many
// things we do not need and will ultimately fail to open the port because we do
// not have a port... Instead create an instance with fake controllerPath.

Driver *driver = new Driver("dummy", Driver::ControllerInterface::ControllerInterface_Serial);

// Pretend the Manager knows about a certain HomeID by setting m_readyDrivers to this fake driver
Manager::Get()->m_readyDrivers[FakeHomeId] = driver;

// Pretend node 2 exists
Node *node = new Node(FakeHomeId, FakeNode2Id);
driver->m_nodes[node->GetNodeId()] = node;

auto cc = node->AddCommandClass(FakeCommandClass);

if (cc == nullptr)
{
throw std::runtime_error("auto cc = node->AddCommandClass(test_cc) returned a nullptr");
}

// Real devices will usually have either Instance 1 -> End Point 1 or 0
// But for sake of testing we can set anything we like.
cc->SetEndPoint(Instance1, 0);
node->CreateValueString(ValueID::ValueGenre_User, FakeCommandClass, Instance1, FakeValueIndex, "label", "units", false, false, "default", 0);
cc->SetEndPoint(Instance2, 1);
node->CreateValueString(ValueID::ValueGenre_User, FakeCommandClass, Instance2, FakeValueIndex, "label", "units", false, false, "default", 0);
cc->SetEndPoint(Instance3, 127);
node->CreateValueString(ValueID::ValueGenre_User, FakeCommandClass, Instance3, FakeValueIndex, "label", "units", false, false, "default", 0);

// Set a value, but do not set an endpoint, to test if the map properly initializes to zero
node->CreateValueString(ValueID::ValueGenre_User, FakeCommandClass, Instance4, FakeValueIndex, "label", "units", false, false, "default", 0);
}

// virtual void TearDown() will be called after each test is run.

void TestHelper::TearDown()
{
// Do a reasonable job of cleaning up
// Manager::Get()->RemoveDriver calls the driver's destructor
// That destructor is pretty long and destroys a truckload of objects
Manager::Get()->RemoveDriver("dummy");
Manager::Destroy();
Options::Destroy();
};

} // namespace Testing
} // namespace OpenZWave
Loading