Publish LumaOps source
This commit is contained in:
+132
@@ -0,0 +1,132 @@
|
||||
if(NOT hueplusplus_NO_EXTERNAL_LIBRARIES)
|
||||
find_package(GTest)
|
||||
find_package(GMock)
|
||||
endif()
|
||||
|
||||
if(NOT GTest_FOUND OR NOT GMock_FOUND)
|
||||
# Download and unpack googletest at configure time
|
||||
configure_file(CMakeLists.txt.in googletest-download/CMakeLists.txt)
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} -G ${CMAKE_GENERATOR} .
|
||||
RESULT_VARIABLE result
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/googletest-download"
|
||||
)
|
||||
if(result)
|
||||
message(FATAL_ERROR "CMake step for googletest failed: ${result}")
|
||||
endif()
|
||||
execute_process(COMMAND "${CMAKE_COMMAND}" --build .
|
||||
RESULT_VARIABLE result
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/googletest-download"
|
||||
)
|
||||
if(result)
|
||||
message(FATAL_ERROR "Build step for googletest failed: ${result}")
|
||||
endif()
|
||||
|
||||
# Prevent overriding the parent project's compiler/linker
|
||||
# settings on Windows
|
||||
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
|
||||
|
||||
# Add googletest directly to our build. This defines
|
||||
# the gtest and gtest_main targets.
|
||||
add_subdirectory(${CMAKE_CURRENT_BINARY_DIR}/googletest-src EXCLUDE_FROM_ALL
|
||||
${CMAKE_CURRENT_BINARY_DIR}/googletest-build EXCLUDE_FROM_ALL
|
||||
)
|
||||
target_compile_features(gmock PUBLIC cxx_std_14)
|
||||
target_compile_features(gtest PUBLIC cxx_std_14)
|
||||
endif()
|
||||
|
||||
|
||||
# define all test sources
|
||||
set(TEST_SOURCES
|
||||
test_Action.cpp
|
||||
test_APICache.cpp
|
||||
test_BaseDevice.cpp
|
||||
test_BaseHttpHandler.cpp
|
||||
test_Bridge.cpp
|
||||
test_BridgeConfig.cpp
|
||||
test_SensorImpls.cpp
|
||||
test_ColorUnits.cpp
|
||||
test_ExtendedColorHueStrategy.cpp
|
||||
test_ExtendedColorTemperatureStrategy.cpp
|
||||
test_Group.cpp
|
||||
test_HueCommandAPI.cpp
|
||||
test_Light.cpp
|
||||
test_LightFactory.cpp
|
||||
test_Main.cpp
|
||||
test_NewDeviceList.cpp
|
||||
test_UPnP.cpp
|
||||
test_ResourceList.cpp
|
||||
test_Rule.cpp
|
||||
test_Scene.cpp
|
||||
test_Schedule.cpp
|
||||
test_Sensor.cpp
|
||||
test_SensorList.cpp
|
||||
test_SimpleBrightnessStrategy.cpp
|
||||
test_SimpleColorHueStrategy.cpp
|
||||
test_SimpleColorTemperatureStrategy.cpp
|
||||
test_StateTransaction.cpp
|
||||
test_TimePattern.cpp)
|
||||
|
||||
set(HuePlusPlus_INCLUDE_DIR "${PROJECT_SOURCE_DIR}/include")
|
||||
|
||||
# test executable
|
||||
add_executable(test_HuePlusPlus ${TEST_SOURCES})
|
||||
#if(DO_CLANG_TIDY)
|
||||
# set_target_properties(test_HuePlusPlus PROPERTIES CXX_CLANG_TIDY ${DO_CLANG_TIDY})
|
||||
#endif()
|
||||
target_compile_features(test_HuePlusPlus PUBLIC cxx_std_14)
|
||||
set_property(TARGET test_HuePlusPlus PROPERTY CXX_EXTENSIONS OFF)
|
||||
|
||||
target_link_libraries(test_HuePlusPlus PUBLIC hueplusplusstatic)
|
||||
target_link_libraries(test_HuePlusPlus PUBLIC gtest gmock)
|
||||
target_include_directories(test_HuePlusPlus PUBLIC ${GTest_INCLUDE_DIRS})
|
||||
# add custom target to make it simple to run the tests
|
||||
add_custom_target("unittest"
|
||||
# Run the executable
|
||||
COMMAND test_HuePlusPlus
|
||||
# Depends on test_HuePlusPlus
|
||||
DEPENDS test_HuePlusPlus
|
||||
)
|
||||
|
||||
# Check for coverage test prerequisites
|
||||
find_program( GCOV_PATH gcov )
|
||||
find_program( LCOV_PATH lcov )
|
||||
|
||||
mark_as_advanced(GCOV_PATH)
|
||||
mark_as_advanced(LCOV_PATH)
|
||||
|
||||
if(LCOV_PATH AND GCOV_PATH)
|
||||
# GCov
|
||||
include(CodeCoverage.cmake)
|
||||
add_executable(testcov_HuePlusPlus ${TEST_SOURCES} ${hueplusplus_SOURCES})
|
||||
target_include_directories(testcov_HuePlusPlus PUBLIC "${PROJECT_SOURCE_DIR}/include")
|
||||
target_compile_features(testcov_HuePlusPlus PUBLIC cxx_std_14)
|
||||
set_property(TARGET testcov_HuePlusPlus PROPERTY CXX_EXTENSIONS OFF)
|
||||
|
||||
target_link_libraries(testcov_HuePlusPlus PRIVATE mbedtls)
|
||||
target_link_libraries(testcov_HuePlusPlus PUBLIC nlohmann_json::nlohmann_json gtest gmock)
|
||||
target_include_directories(testcov_HuePlusPlus PUBLIC ${GTest_INCLUDE_DIRS})
|
||||
# this will be already done by APPEND_COVERAGE_COMPILER_FLAGS()
|
||||
#set_target_properties(
|
||||
# testcov_HuePlusPlus PROPERTIES
|
||||
# COMPILE_FLAGS "-O0 -g -fprofile-arcs -ftest-coverage"
|
||||
#)
|
||||
# Normally this would be -lgcov, but on mac only -Lgcov works
|
||||
#set_target_properties(
|
||||
# testcov_HuePlusPlus PROPERTIES
|
||||
# LINK_FLAGS "-O0 -g -Lgcov -fprofile-arcs -ftest-coverage"
|
||||
#)
|
||||
# exclude some special files we do not want to profile
|
||||
set(COVERAGE_EXCLUDES
|
||||
'/usr/*' # unix
|
||||
'*/hueplusplus/build/*'
|
||||
'*/json*'
|
||||
'*/test/*'
|
||||
'*/v1/*' # iOS
|
||||
)
|
||||
APPEND_COVERAGE_COMPILER_FLAGS()
|
||||
SETUP_TARGET_FOR_COVERAGE(
|
||||
NAME "coveragetest"
|
||||
EXECUTABLE testcov_HuePlusPlus
|
||||
DEPENDENCIES testcov_HuePlusPlus
|
||||
)
|
||||
endif()
|
||||
@@ -0,0 +1,15 @@
|
||||
cmake_minimum_required(VERSION 2.8.2)
|
||||
|
||||
project(googletest-download NONE)
|
||||
|
||||
include(ExternalProject)
|
||||
ExternalProject_Add(googletest
|
||||
GIT_REPOSITORY https://github.com/google/googletest.git
|
||||
GIT_TAG main
|
||||
SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-src"
|
||||
BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-build"
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ""
|
||||
INSTALL_COMMAND ""
|
||||
TEST_COMMAND ""
|
||||
)
|
||||
@@ -0,0 +1,234 @@
|
||||
# Copyright (c) 2012 - 2017, Lars Bilke
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright notice, this
|
||||
# list of conditions and the following disclaimer.
|
||||
#
|
||||
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# 3. Neither the name of the copyright holder nor the names of its contributors
|
||||
# may be used to endorse or promote products derived from this software without
|
||||
# specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
# CHANGES:
|
||||
#
|
||||
# 2012-01-31, Lars Bilke
|
||||
# - Enable Code Coverage
|
||||
#
|
||||
# 2013-09-17, Joakim Söderberg
|
||||
# - Added support for Clang.
|
||||
# - Some additional usage instructions.
|
||||
#
|
||||
# 2016-02-03, Lars Bilke
|
||||
# - Refactored functions to use named parameters
|
||||
#
|
||||
# 2017-06-02, Lars Bilke
|
||||
# - Merged with modified version from github.com/ufz/ogs
|
||||
#
|
||||
#
|
||||
# USAGE:
|
||||
#
|
||||
# 1. Copy this file into your cmake modules path.
|
||||
#
|
||||
# 2. Add the following line to your CMakeLists.txt:
|
||||
# include(CodeCoverage)
|
||||
#
|
||||
# 3. Append necessary compiler flags:
|
||||
# APPEND_COVERAGE_COMPILER_FLAGS()
|
||||
#
|
||||
# 4. If you need to exclude additional directories from the report, specify them
|
||||
# using the COVERAGE_EXCLUDES variable before calling SETUP_TARGET_FOR_COVERAGE.
|
||||
# Example:
|
||||
# set(COVERAGE_EXCLUDES 'dir1/*' 'dir2/*')
|
||||
#
|
||||
# 5. Use the functions described below to create a custom make target which
|
||||
# runs your test executable and produces a code coverage report.
|
||||
#
|
||||
# 6. Build a Debug build:
|
||||
# cmake -DCMAKE_BUILD_TYPE=Debug ..
|
||||
# make
|
||||
# make my_coverage_target
|
||||
#
|
||||
|
||||
include(CMakeParseArguments)
|
||||
|
||||
# Check prereqs
|
||||
find_program( GCOV_PATH gcov )
|
||||
find_program( LCOV_PATH lcov )
|
||||
find_program( GENHTML_PATH genhtml )
|
||||
find_program( GCOVR_PATH gcovr PATHS ${CMAKE_SOURCE_DIR}/scripts/test)
|
||||
find_program( SIMPLE_PYTHON_EXECUTABLE python )
|
||||
|
||||
if(NOT GCOV_PATH)
|
||||
message(FATAL_ERROR "gcov not found! Aborting...")
|
||||
endif() # NOT GCOV_PATH
|
||||
|
||||
if("${CMAKE_CXX_COMPILER_ID}" MATCHES "(Apple)?[Cc]lang")
|
||||
if("${CMAKE_CXX_COMPILER_VERSION}" VERSION_LESS 3)
|
||||
message(FATAL_ERROR "Clang version must be 3.0.0 or greater! Aborting...")
|
||||
endif()
|
||||
elseif(NOT CMAKE_COMPILER_IS_GNUCXX)
|
||||
message(FATAL_ERROR "Compiler is not GNU gcc! Aborting...")
|
||||
endif()
|
||||
|
||||
set(COVERAGE_COMPILER_FLAGS "-g -O0 --coverage -fprofile-arcs -ftest-coverage"
|
||||
CACHE INTERNAL "")
|
||||
|
||||
set(CMAKE_CXX_FLAGS_COVERAGE
|
||||
${COVERAGE_COMPILER_FLAGS}
|
||||
CACHE STRING "Flags used by the C++ compiler during coverage builds."
|
||||
FORCE )
|
||||
set(CMAKE_C_FLAGS_COVERAGE
|
||||
${COVERAGE_COMPILER_FLAGS}
|
||||
CACHE STRING "Flags used by the C compiler during coverage builds."
|
||||
FORCE )
|
||||
set(CMAKE_EXE_LINKER_FLAGS_COVERAGE
|
||||
""
|
||||
CACHE STRING "Flags used for linking binaries during coverage builds."
|
||||
FORCE )
|
||||
set(CMAKE_SHARED_LINKER_FLAGS_COVERAGE
|
||||
""
|
||||
CACHE STRING "Flags used by the shared libraries linker during coverage builds."
|
||||
FORCE )
|
||||
mark_as_advanced(
|
||||
CMAKE_CXX_FLAGS_COVERAGE
|
||||
CMAKE_C_FLAGS_COVERAGE
|
||||
CMAKE_EXE_LINKER_FLAGS_COVERAGE
|
||||
CMAKE_SHARED_LINKER_FLAGS_COVERAGE )
|
||||
|
||||
if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
message(WARNING "Code coverage results with an optimised (non-Debug) build may be misleading")
|
||||
endif() # NOT CMAKE_BUILD_TYPE STREQUAL "Debug"
|
||||
|
||||
if(CMAKE_C_COMPILER_ID STREQUAL "GNU")
|
||||
link_libraries(gcov)
|
||||
else()
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --coverage")
|
||||
endif()
|
||||
|
||||
# Defines a target for running and collection code coverage information
|
||||
# Builds dependencies, runs the given executable and outputs reports.
|
||||
# NOTE! The executable should always have a ZERO as exit code otherwise
|
||||
# the coverage generation will not complete.
|
||||
#
|
||||
# SETUP_TARGET_FOR_COVERAGE(
|
||||
# NAME testrunner_coverage # New target name
|
||||
# EXECUTABLE testrunner -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR
|
||||
# DEPENDENCIES testrunner # Dependencies to build first
|
||||
# )
|
||||
function(SETUP_TARGET_FOR_COVERAGE)
|
||||
|
||||
set(options NONE)
|
||||
set(oneValueArgs NAME)
|
||||
set(multiValueArgs EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES)
|
||||
cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
||||
|
||||
if(NOT LCOV_PATH)
|
||||
message(FATAL_ERROR "lcov not found! Aborting...")
|
||||
endif() # NOT LCOV_PATH
|
||||
|
||||
if(NOT GENHTML_PATH)
|
||||
message(FATAL_ERROR "genhtml not found! Aborting...")
|
||||
endif() # NOT GENHTML_PATH
|
||||
|
||||
# Setup target
|
||||
add_custom_target(${Coverage_NAME}
|
||||
|
||||
# Cleanup lcov
|
||||
COMMAND ${LCOV_PATH} --directory . --zerocounters
|
||||
|
||||
# Run tests
|
||||
COMMAND ${Coverage_EXECUTABLE}
|
||||
|
||||
# Capturing lcov counters and generating report
|
||||
COMMAND ${LCOV_PATH} --directory . --capture --output-file ${Coverage_NAME}.info --ignore-errors mismatch
|
||||
COMMAND ${LCOV_PATH} --remove ${Coverage_NAME}.info ${COVERAGE_EXCLUDES} --output-file ${Coverage_NAME}.info.cleaned --ignore-errors unused
|
||||
COMMAND ${GENHTML_PATH} -o ${Coverage_NAME} ${Coverage_NAME}.info.cleaned
|
||||
COMMAND ${CMAKE_COMMAND} -E remove ${Coverage_NAME}.info ${Coverage_NAME}.info.cleaned
|
||||
|
||||
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
|
||||
DEPENDS ${Coverage_DEPENDENCIES}
|
||||
COMMENT "Resetting code coverage counters to zero.\nProcessing code coverage counters and generating report."
|
||||
)
|
||||
|
||||
# Show info where to find the report
|
||||
add_custom_command(TARGET ${Coverage_NAME} POST_BUILD
|
||||
COMMAND ;
|
||||
COMMENT "Open ./${Coverage_NAME}/index.html in your browser to view the coverage report."
|
||||
)
|
||||
|
||||
endfunction() # SETUP_TARGET_FOR_COVERAGE
|
||||
|
||||
# Defines a target for running and collection code coverage information
|
||||
# Builds dependencies, runs the given executable and outputs reports.
|
||||
# NOTE! The executable should always have a ZERO as exit code otherwise
|
||||
# the coverage generation will not complete.
|
||||
#
|
||||
# SETUP_TARGET_FOR_COVERAGE_COBERTURA(
|
||||
# NAME ctest_coverage # New target name
|
||||
# EXECUTABLE ctest -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR
|
||||
# DEPENDENCIES executable_target # Dependencies to build first
|
||||
# )
|
||||
function(SETUP_TARGET_FOR_COVERAGE_COBERTURA)
|
||||
|
||||
set(options NONE)
|
||||
set(oneValueArgs NAME)
|
||||
set(multiValueArgs EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES)
|
||||
cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
||||
|
||||
if(NOT SIMPLE_PYTHON_EXECUTABLE)
|
||||
message(FATAL_ERROR "python not found! Aborting...")
|
||||
endif() # NOT SIMPLE_PYTHON_EXECUTABLE
|
||||
|
||||
if(NOT GCOVR_PATH)
|
||||
message(FATAL_ERROR "gcovr not found! Aborting...")
|
||||
endif() # NOT GCOVR_PATH
|
||||
|
||||
# Combine excludes to several -e arguments
|
||||
set(COBERTURA_EXCLUDES "")
|
||||
foreach(EXCLUDE ${COVERAGE_EXCLUDES})
|
||||
set(COBERTURA_EXCLUDES "-e ${EXCLUDE} ${COBERTURA_EXCLUDES}")
|
||||
endforeach()
|
||||
|
||||
add_custom_target(${Coverage_NAME}
|
||||
|
||||
# Run tests
|
||||
${Coverage_EXECUTABLE}
|
||||
|
||||
# Running gcovr
|
||||
COMMAND ${GCOVR_PATH} -x -r ${CMAKE_SOURCE_DIR} ${COBERTURA_EXCLUDES}
|
||||
-o ${Coverage_NAME}.xml
|
||||
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
|
||||
DEPENDS ${Coverage_DEPENDENCIES}
|
||||
COMMENT "Running gcovr to produce Cobertura code coverage report."
|
||||
)
|
||||
|
||||
# Show info where to find the report
|
||||
add_custom_command(TARGET ${Coverage_NAME} POST_BUILD
|
||||
COMMAND ;
|
||||
COMMENT "Cobertura code coverage report saved in ${Coverage_NAME}.xml."
|
||||
)
|
||||
|
||||
endfunction() # SETUP_TARGET_FOR_COVERAGE_COBERTURA
|
||||
|
||||
function(APPEND_COVERAGE_COMPILER_FLAGS)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${COVERAGE_COMPILER_FLAGS}" PARENT_SCOPE)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${COVERAGE_COMPILER_FLAGS}" PARENT_SCOPE)
|
||||
message(STATUS "Appending code coverage compiler flags: ${COVERAGE_COMPILER_FLAGS}")
|
||||
endfunction() # APPEND_COVERAGE_COMPILER_FLAGS
|
||||
@@ -0,0 +1,63 @@
|
||||
/**
|
||||
\file TestTransaction.h
|
||||
Copyright Notice\n
|
||||
Copyright (C) 2020 Jan Rogall - developer\n
|
||||
|
||||
This file is part of hueplusplus.
|
||||
|
||||
hueplusplus 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.
|
||||
|
||||
hueplusplus 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 hueplusplus. If not, see <http://www.gnu.org/licenses/>.
|
||||
**/
|
||||
|
||||
#ifndef INCLUDE_HUEPLUSPLUS_TEST_TRANSACTION_H
|
||||
#define INCLUDE_HUEPLUSPLUS_TEST_TRANSACTION_H
|
||||
|
||||
#include <hueplusplus/StateTransaction.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "testhelper.h"
|
||||
|
||||
#include "mocks/mock_HttpHandler.h"
|
||||
|
||||
class TestTransaction : public hueplusplus::StateTransaction
|
||||
{
|
||||
public:
|
||||
TestTransaction(hueplusplus::StateTransaction& t) : hueplusplus::StateTransaction(std::move(t)) {}
|
||||
|
||||
nlohmann::json getRequest() const { return request; }
|
||||
nlohmann::json getResponse() const
|
||||
{
|
||||
nlohmann::json response;
|
||||
const std::string pathPrefix = path + '/';
|
||||
for (auto it = request.begin(); it != request.end(); ++it)
|
||||
{
|
||||
response.push_back({{"success", {{pathPrefix + it.key(), it.value()}}}});
|
||||
}
|
||||
return response;
|
||||
}
|
||||
std::string getPath() const { return path; }
|
||||
|
||||
decltype(auto) expectPut(const std::shared_ptr<MockHttpHandler>& handler) const
|
||||
{
|
||||
return EXPECT_CALL(
|
||||
*handler, PUTJson("/api/" + getBridgeUsername() + path, request, getBridgeIp(), getBridgePort()));
|
||||
}
|
||||
decltype(auto) expectSuccessfulPut(const std::shared_ptr<MockHttpHandler>& handler,
|
||||
const testing::Cardinality& cardinality = testing::AtLeast(1)) const
|
||||
{
|
||||
return expectPut(handler).Times(cardinality).WillRepeatedly(testing::Return(getResponse()));
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
\file mock_BaseHttpHandler.h
|
||||
Copyright Notice\n
|
||||
Copyright (C) 2017 Jan Rogall - developer\n
|
||||
Copyright (C) 2017 Moritz Wirger - developer\n
|
||||
|
||||
This file is part of hueplusplus.
|
||||
|
||||
hueplusplus 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.
|
||||
|
||||
hueplusplus 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 hueplusplus. If not, see <http://www.gnu.org/licenses/>.
|
||||
**/
|
||||
|
||||
#ifndef _MOCK_BASE_HTTPHANDLER_H
|
||||
#define _MOCK_BASE_HTTPHANDLER_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <gmock/gmock.h>
|
||||
|
||||
#include "hueplusplus/BaseHttpHandler.h"
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
//! Mock Class
|
||||
class MockBaseHttpHandler : public hueplusplus::BaseHttpHandler
|
||||
{
|
||||
public:
|
||||
MOCK_CONST_METHOD3(send, std::string(const std::string& msg, const std::string& adr, int port));
|
||||
|
||||
MOCK_CONST_METHOD4(
|
||||
sendMulticast, std::vector<std::string>(const std::string& msg, const std::string& adr, int port, std::chrono::steady_clock::duration timeout));
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,79 @@
|
||||
/**
|
||||
\file mock_HttpHandler.h
|
||||
Copyright Notice\n
|
||||
Copyright (C) 2017 Jan Rogall - developer\n
|
||||
Copyright (C) 2017 Moritz Wirger - developer\n
|
||||
|
||||
This file is part of hueplusplus.
|
||||
|
||||
hueplusplus 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.
|
||||
|
||||
hueplusplus 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 hueplusplus. If not, see <http://www.gnu.org/licenses/>.
|
||||
**/
|
||||
|
||||
#ifndef _MOCK_HTTPHANDLER_H
|
||||
#define _MOCK_HTTPHANDLER_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <gmock/gmock.h>
|
||||
|
||||
#include "hueplusplus/IHttpHandler.h"
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
//! Mock Class
|
||||
class MockHttpHandler : public hueplusplus::IHttpHandler
|
||||
{
|
||||
public:
|
||||
MOCK_CONST_METHOD3(send, std::string(const std::string& msg, const std::string& adr, int port));
|
||||
|
||||
MOCK_CONST_METHOD3(sendGetHTTPBody, std::string(const std::string& msg, const std::string& adr, int port));
|
||||
|
||||
MOCK_CONST_METHOD4(sendMulticast,
|
||||
std::vector<std::string>(
|
||||
const std::string& msg, const std::string& adr, int port, std::chrono::steady_clock::duration timeout));
|
||||
|
||||
MOCK_CONST_METHOD6(sendHTTPRequest,
|
||||
std::string(const std::string& method, const std::string& uri, const std::string& content_type,
|
||||
const std::string& body, const std::string& adr, int port));
|
||||
|
||||
MOCK_CONST_METHOD5(GETString,
|
||||
std::string(const std::string& uri, const std::string& content_type, const std::string& body,
|
||||
const std::string& adr, int port));
|
||||
|
||||
MOCK_CONST_METHOD5(POSTString,
|
||||
std::string(const std::string& uri, const std::string& content_type, const std::string& body,
|
||||
const std::string& adr, int port));
|
||||
|
||||
MOCK_CONST_METHOD5(PUTString,
|
||||
std::string(const std::string& uri, const std::string& content_type, const std::string& body,
|
||||
const std::string& adr, int port));
|
||||
|
||||
MOCK_CONST_METHOD5(DELETEString,
|
||||
std::string(const std::string& uri, const std::string& content_type, const std::string& body,
|
||||
const std::string& adr, int port));
|
||||
|
||||
MOCK_CONST_METHOD4(
|
||||
GETJson, nlohmann::json(const std::string& uri, const nlohmann::json& body, const std::string& adr, int port));
|
||||
|
||||
MOCK_CONST_METHOD4(
|
||||
POSTJson, nlohmann::json(const std::string& uri, const nlohmann::json& body, const std::string& adr, int port));
|
||||
|
||||
MOCK_CONST_METHOD4(
|
||||
PUTJson, nlohmann::json(const std::string& uri, const nlohmann::json& body, const std::string& adr, int port));
|
||||
|
||||
MOCK_CONST_METHOD4(DELETEJson,
|
||||
nlohmann::json(const std::string& uri, const nlohmann::json& body, const std::string& adr, int port));
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,130 @@
|
||||
/**
|
||||
\file mock_Light.h
|
||||
Copyright Notice\n
|
||||
Copyright (C) 2017 Jan Rogall - developer\n
|
||||
Copyright (C) 2017 Moritz Wirger - developer\n
|
||||
|
||||
This file is part of hueplusplus.
|
||||
|
||||
hueplusplus 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.
|
||||
|
||||
hueplusplus 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 hueplusplus. If not, see <http://www.gnu.org/licenses/>.
|
||||
**/
|
||||
|
||||
#ifndef _MOCK_HUE_LIGHT_H
|
||||
#define _MOCK_HUE_LIGHT_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <gmock/gmock.h>
|
||||
|
||||
#include "../testhelper.h"
|
||||
#include "hueplusplus/Light.h"
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
//! Mock Class
|
||||
class MockLight : public hueplusplus::Light
|
||||
{
|
||||
public:
|
||||
MockLight(std::shared_ptr<const hueplusplus::IHttpHandler> handler)
|
||||
: Light(1, hueplusplus::HueCommandAPI(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler), nullptr,
|
||||
nullptr, nullptr, std::chrono::steady_clock::duration::max(), nullptr)
|
||||
{
|
||||
// Set refresh duration to max, so random refreshes do not hinder the test setups
|
||||
}
|
||||
|
||||
nlohmann::json& getState() { return state.getValue(); }
|
||||
|
||||
MOCK_METHOD1(on, bool(uint8_t transition));
|
||||
|
||||
MOCK_METHOD1(off, bool(uint8_t transition));
|
||||
|
||||
MOCK_METHOD0(isOn, bool());
|
||||
|
||||
MOCK_CONST_METHOD0(isOn, bool());
|
||||
|
||||
MOCK_CONST_METHOD0(getId, int());
|
||||
|
||||
MOCK_CONST_METHOD0(getType, std::string());
|
||||
|
||||
MOCK_METHOD0(getName, std::string());
|
||||
|
||||
MOCK_CONST_METHOD0(getName, std::string());
|
||||
|
||||
MOCK_CONST_METHOD0(getModelId, std::string());
|
||||
|
||||
MOCK_CONST_METHOD0(getUId, std::string());
|
||||
|
||||
MOCK_CONST_METHOD0(getManufacturername, std::string());
|
||||
|
||||
MOCK_CONST_METHOD0(getLuminaireUId, std::string());
|
||||
|
||||
MOCK_METHOD0(getSwVersion, std::string());
|
||||
|
||||
MOCK_CONST_METHOD0(getSwVersion, std::string());
|
||||
|
||||
MOCK_METHOD1(setName, bool(const std::string& name));
|
||||
|
||||
MOCK_CONST_METHOD0(getColorType, hueplusplus::ColorType());
|
||||
|
||||
MOCK_CONST_METHOD0(hasBrightnessControl, bool());
|
||||
|
||||
MOCK_CONST_METHOD0(hasTemperatureControl, bool());
|
||||
|
||||
MOCK_CONST_METHOD0(hasColorControl, bool());
|
||||
|
||||
MOCK_METHOD2(setBrightness, bool(unsigned int bri, uint8_t transition));
|
||||
|
||||
MOCK_CONST_METHOD0(getBrightness, unsigned int());
|
||||
|
||||
MOCK_METHOD0(getBrightness, unsigned int());
|
||||
|
||||
MOCK_METHOD2(setColorTemperature, bool(unsigned int mired, uint8_t transition));
|
||||
|
||||
MOCK_CONST_METHOD0(getColorTemperature, unsigned int());
|
||||
|
||||
MOCK_METHOD0(getColorTemperature, unsigned int());
|
||||
|
||||
MOCK_METHOD2(setColorHue, bool(uint16_t hue, uint8_t transition));
|
||||
|
||||
MOCK_METHOD2(setColorSaturation, bool(uint8_t sat, uint8_t transition));
|
||||
|
||||
MOCK_METHOD2(setColorHueSaturation, bool(const hueplusplus::HueSaturation& hueSat, uint8_t transition));
|
||||
|
||||
MOCK_CONST_METHOD0(getColorHueSaturation, hueplusplus::HueSaturation());
|
||||
|
||||
MOCK_METHOD0(getColorHueSaturation, hueplusplus::HueSaturation());
|
||||
|
||||
MOCK_METHOD2(setColorXY, bool(const hueplusplus::XYBrightness& xy, uint8_t transition));
|
||||
|
||||
MOCK_CONST_METHOD0(getColorXY, hueplusplus::XYBrightness());
|
||||
|
||||
MOCK_METHOD0(getColorXY, hueplusplus::XYBrightness());
|
||||
|
||||
MOCK_METHOD2(setColorRGB, bool(const hueplusplus::RGB& rgb, uint8_t transition));
|
||||
|
||||
MOCK_METHOD0(alert, bool());
|
||||
|
||||
MOCK_METHOD1(alertTemperature, bool(unsigned int mired));
|
||||
|
||||
MOCK_METHOD1(alertHueSaturation, bool(const hueplusplus::HueSaturation& hueSat));
|
||||
|
||||
MOCK_METHOD1(alertXY, bool(const hueplusplus::XYBrightness& xy));
|
||||
|
||||
MOCK_METHOD1(setColorLoop, bool(bool on));
|
||||
|
||||
MOCK_METHOD3(sendPutRequest,
|
||||
nlohmann::json(const std::string& subPath, const nlohmann::json& request, hueplusplus::FileInfo fileInfo));
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,323 @@
|
||||
/**
|
||||
\file test_Hue.cpp
|
||||
Copyright Notice\n
|
||||
Copyright (C) 2017 Jan Rogall - developer\n
|
||||
Copyright (C) 2017 Moritz Wirger - developer\n
|
||||
|
||||
This file is part of hueplusplus.
|
||||
|
||||
hueplusplus 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.
|
||||
|
||||
hueplusplus 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 hueplusplus. If not, see <http://www.gnu.org/licenses/>.
|
||||
**/
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "testhelper.h"
|
||||
|
||||
#include "hueplusplus/APICache.h"
|
||||
#include "mocks/mock_HttpHandler.h"
|
||||
|
||||
using namespace hueplusplus;
|
||||
|
||||
TEST(APICache, getRefreshDuration)
|
||||
{
|
||||
auto handler = std::make_shared<MockHttpHandler>();
|
||||
HueCommandAPI commands(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler);
|
||||
{
|
||||
std::chrono::steady_clock::duration refresh = std::chrono::seconds(20);
|
||||
APICache cache("", commands, refresh, nullptr);
|
||||
EXPECT_EQ(refresh, cache.getRefreshDuration());
|
||||
}
|
||||
{
|
||||
std::chrono::steady_clock::duration refresh = std::chrono::seconds(0);
|
||||
APICache cache("", commands, refresh, nullptr);
|
||||
EXPECT_EQ(refresh, cache.getRefreshDuration());
|
||||
}
|
||||
{
|
||||
std::chrono::steady_clock::duration refresh = c_refreshNever;
|
||||
APICache cache("", commands, refresh, nullptr);
|
||||
EXPECT_EQ(refresh, cache.getRefreshDuration());
|
||||
}
|
||||
// With base cache, still independent duration
|
||||
{
|
||||
auto duration = std::chrono::seconds(5);
|
||||
auto baseCache = std::make_shared<APICache>("/test", commands, std::chrono::seconds(0), nullptr);
|
||||
APICache c(baseCache, "api", duration);
|
||||
EXPECT_EQ(duration, c.getRefreshDuration());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(APICache, refresh)
|
||||
{
|
||||
using namespace ::testing;
|
||||
auto handler = std::make_shared<MockHttpHandler>();
|
||||
HueCommandAPI commands(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler);
|
||||
|
||||
{
|
||||
std::string path = "/test/abc";
|
||||
APICache cache(path, commands, std::chrono::seconds(10), nullptr);
|
||||
EXPECT_CALL(*handler,
|
||||
GETJson("/api/" + getBridgeUsername() + path, nlohmann::json::object(), getBridgeIp(), getBridgePort()))
|
||||
.WillOnce(Return(nlohmann::json::object()));
|
||||
cache.refresh();
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
}
|
||||
{
|
||||
std::string path = "";
|
||||
APICache cache(path, commands, std::chrono::seconds(10), nullptr);
|
||||
EXPECT_CALL(*handler,
|
||||
GETJson("/api/" + getBridgeUsername() + path, nlohmann::json::object(), getBridgeIp(), getBridgePort()))
|
||||
.Times(2)
|
||||
.WillRepeatedly(Return(nlohmann::json::object()));
|
||||
cache.refresh();
|
||||
cache.refresh();
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(APICache, refreshBase)
|
||||
{
|
||||
using namespace ::testing;
|
||||
auto handler = std::make_shared<MockHttpHandler>();
|
||||
HueCommandAPI commands(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler);
|
||||
const std::string basePath = "/test";
|
||||
const std::string childPath = "/test/abc";
|
||||
// Base cache with max duration
|
||||
{
|
||||
auto baseCache
|
||||
= std::make_shared<APICache>(basePath, commands, c_refreshNever, nullptr);
|
||||
APICache cache(baseCache, "abc", std::chrono::seconds(0));
|
||||
|
||||
// First call refreshes base, second call only child
|
||||
InSequence s;
|
||||
EXPECT_CALL(*handler,
|
||||
GETJson("/api/" + getBridgeUsername() + basePath, nlohmann::json::object(), getBridgeIp(), getBridgePort()))
|
||||
.WillOnce(Return(nlohmann::json::object()));
|
||||
EXPECT_CALL(*handler,
|
||||
GETJson(
|
||||
"/api/" + getBridgeUsername() + childPath, nlohmann::json::object(), getBridgeIp(), getBridgePort()))
|
||||
.WillOnce(Return(nlohmann::json::object()));
|
||||
cache.refresh();
|
||||
cache.refresh();
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
}
|
||||
// Base cache with min duration
|
||||
{
|
||||
auto baseCache = std::make_shared<APICache>(basePath, commands, std::chrono::seconds(0), nullptr);
|
||||
APICache cache(baseCache, "abc", std::chrono::seconds(0));
|
||||
|
||||
// Both calls refresh base
|
||||
EXPECT_CALL(*handler,
|
||||
GETJson("/api/" + getBridgeUsername() + basePath, nlohmann::json::object(), getBridgeIp(), getBridgePort()))
|
||||
.Times(2)
|
||||
.WillRepeatedly(Return(nlohmann::json::object()));
|
||||
cache.refresh();
|
||||
cache.refresh();
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(APICache, getValue)
|
||||
{
|
||||
using namespace ::testing;
|
||||
auto handler = std::make_shared<MockHttpHandler>();
|
||||
HueCommandAPI commands(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler);
|
||||
|
||||
// Always refresh
|
||||
{
|
||||
std::string path = "/test/abc";
|
||||
APICache cache(path, commands, std::chrono::seconds(0), nullptr);
|
||||
nlohmann::json value = {{"a", "b"}};
|
||||
EXPECT_CALL(*handler,
|
||||
GETJson("/api/" + getBridgeUsername() + path, nlohmann::json::object(), getBridgeIp(), getBridgePort()))
|
||||
.Times(2)
|
||||
.WillRepeatedly(Return(value));
|
||||
EXPECT_EQ(value, cache.getValue());
|
||||
EXPECT_EQ(value, cache.getValue());
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
}
|
||||
// Only refresh once
|
||||
{
|
||||
std::string path = "/test/abc";
|
||||
APICache cache(path, commands, c_refreshNever, nullptr);
|
||||
nlohmann::json value = {{"a", "b"}};
|
||||
EXPECT_CALL(*handler,
|
||||
GETJson("/api/" + getBridgeUsername() + path, nlohmann::json::object(), getBridgeIp(), getBridgePort()))
|
||||
.WillOnce(Return(value));
|
||||
EXPECT_EQ(value, cache.getValue());
|
||||
EXPECT_EQ(value, cache.getValue());
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
}
|
||||
// Only refresh once
|
||||
{
|
||||
std::string path = "/test/abc";
|
||||
APICache cache(path, commands, std::chrono::seconds(0), nullptr);
|
||||
nlohmann::json value = {{"a", "b"}};
|
||||
EXPECT_CALL(*handler,
|
||||
GETJson("/api/" + getBridgeUsername() + path, nlohmann::json::object(), getBridgeIp(), getBridgePort()))
|
||||
.WillOnce(Return(value));
|
||||
EXPECT_EQ(value, cache.getValue());
|
||||
EXPECT_EQ(value, Const(cache).getValue());
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
}
|
||||
// No refresh with const throws exception
|
||||
{
|
||||
std::string path = "/test/abc";
|
||||
const APICache cache(path, commands, c_refreshNever, nullptr);
|
||||
nlohmann::json value = {{"a", "b"}};
|
||||
EXPECT_CALL(*handler,
|
||||
GETJson("/api/" + getBridgeUsername() + path, nlohmann::json::object(), getBridgeIp(), getBridgePort()))
|
||||
.Times(0);
|
||||
EXPECT_THROW(cache.getValue(), HueException);
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
}
|
||||
// No refresh with initial value
|
||||
{
|
||||
std::string path = "/test/abc";
|
||||
nlohmann::json value = {{"a", "b"}};
|
||||
APICache cache(path, commands, c_refreshNever, value);
|
||||
EXPECT_CALL(*handler,
|
||||
GETJson("/api/" + getBridgeUsername() + path, nlohmann::json::object(), getBridgeIp(), getBridgePort()))
|
||||
.Times(0);
|
||||
EXPECT_EQ(value, cache.getValue());
|
||||
EXPECT_EQ(value, cache.getValue());
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
}
|
||||
// No refresh with const but initial value
|
||||
{
|
||||
std::string path = "/test/abc";
|
||||
nlohmann::json value = {{"a", "b"}};
|
||||
const APICache cache(path, commands, c_refreshNever, value);
|
||||
EXPECT_CALL(*handler,
|
||||
GETJson("/api/" + getBridgeUsername() + path, nlohmann::json::object(), getBridgeIp(), getBridgePort()))
|
||||
.Times(0);
|
||||
EXPECT_EQ(value, cache.getValue());
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(APICache, getValueBase)
|
||||
{
|
||||
using namespace ::testing;
|
||||
auto handler = std::make_shared<MockHttpHandler>();
|
||||
HueCommandAPI commands(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler);
|
||||
|
||||
const std::string basePath = "/test";
|
||||
const std::string childPath = "/test/abc";
|
||||
const nlohmann::json childValue = {{"test", "value"}};
|
||||
const nlohmann::json baseValue = {{"abc", childValue}};
|
||||
// Always refresh base
|
||||
{
|
||||
auto baseCache = std::make_shared<APICache>(basePath, commands, std::chrono::seconds(0), nullptr);
|
||||
APICache cache(baseCache, "abc", std::chrono::seconds(0));
|
||||
EXPECT_CALL(*handler,
|
||||
GETJson("/api/" + getBridgeUsername() + basePath, nlohmann::json::object(), getBridgeIp(), getBridgePort()))
|
||||
.Times(2)
|
||||
.WillRepeatedly(Return(baseValue));
|
||||
EXPECT_EQ(childValue, cache.getValue());
|
||||
EXPECT_EQ(childValue, cache.getValue());
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
}
|
||||
// Child duration > base duration
|
||||
{
|
||||
auto baseCache = std::make_shared<APICache>(basePath, commands, std::chrono::seconds(0), nullptr);
|
||||
APICache cache(baseCache, "abc", c_refreshNever);
|
||||
EXPECT_CALL(*handler,
|
||||
GETJson("/api/" + getBridgeUsername() + basePath, nlohmann::json::object(), getBridgeIp(), getBridgePort()))
|
||||
.Times(1)
|
||||
.WillRepeatedly(Return(baseValue));
|
||||
EXPECT_EQ(childValue, cache.getValue());
|
||||
EXPECT_EQ(childValue, cache.getValue());
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
}
|
||||
// Child duration < base duration
|
||||
{
|
||||
auto baseCache
|
||||
= std::make_shared<APICache>(basePath, commands, c_refreshNever, nullptr);
|
||||
APICache cache(baseCache, "abc", std::chrono::seconds(0));
|
||||
const nlohmann::json updateChildValue = {{"test", "updated"}};
|
||||
InSequence s;
|
||||
EXPECT_CALL(*handler,
|
||||
GETJson("/api/" + getBridgeUsername() + basePath, nlohmann::json::object(), getBridgeIp(), getBridgePort()))
|
||||
.Times(1)
|
||||
.WillRepeatedly(Return(baseValue));
|
||||
EXPECT_CALL(*handler,
|
||||
GETJson(
|
||||
"/api/" + getBridgeUsername() + childPath, nlohmann::json::object(), getBridgeIp(), getBridgePort()))
|
||||
.Times(1)
|
||||
.WillRepeatedly(Return(updateChildValue));
|
||||
EXPECT_EQ(childValue, cache.getValue());
|
||||
EXPECT_EQ(updateChildValue, cache.getValue());
|
||||
// Base cache is updated
|
||||
EXPECT_EQ(updateChildValue, baseCache->getValue()["abc"]);
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
}
|
||||
// Only refresh once
|
||||
{
|
||||
auto baseCache
|
||||
= std::make_shared<APICache>(basePath, commands, c_refreshNever, nullptr);
|
||||
APICache cache(baseCache, "abc", c_refreshNever);
|
||||
EXPECT_CALL(*handler,
|
||||
GETJson("/api/" + getBridgeUsername() + basePath, nlohmann::json::object(), getBridgeIp(), getBridgePort()))
|
||||
.Times(1)
|
||||
.WillRepeatedly(Return(baseValue));
|
||||
EXPECT_EQ(childValue, cache.getValue());
|
||||
EXPECT_EQ(childValue, cache.getValue());
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(APICache, setRefreshDuration)
|
||||
{
|
||||
using namespace ::testing;
|
||||
auto handler = std::make_shared<MockHttpHandler>();
|
||||
HueCommandAPI commands(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler);
|
||||
|
||||
{
|
||||
std::string path = "/test/abc";
|
||||
APICache cache(path, commands, std::chrono::seconds(0), nullptr);
|
||||
nlohmann::json value = { {"a", "b"} };
|
||||
EXPECT_CALL(*handler,
|
||||
GETJson("/api/" + getBridgeUsername() + path, nlohmann::json::object(), getBridgeIp(), getBridgePort()))
|
||||
.Times(1)
|
||||
.WillOnce(Return(value));
|
||||
EXPECT_EQ(value, cache.getValue());
|
||||
cache.setRefreshDuration(c_refreshNever);
|
||||
EXPECT_EQ(c_refreshNever, cache.getRefreshDuration());
|
||||
// Next getValue does not refresh
|
||||
EXPECT_EQ(value, cache.getValue());
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(APICache, getRequestPath)
|
||||
{
|
||||
using namespace ::testing;
|
||||
auto handler = std::make_shared<MockHttpHandler>();
|
||||
HueCommandAPI commands(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler);
|
||||
|
||||
// No base cache
|
||||
{
|
||||
std::string path = "/test/api";
|
||||
APICache c(path, commands, std::chrono::seconds(0), nullptr);
|
||||
EXPECT_EQ(path, c.getRequestPath());
|
||||
}
|
||||
// With base cache
|
||||
{
|
||||
auto baseCache = std::make_shared<APICache>("/test", commands, std::chrono::seconds(0), nullptr);
|
||||
APICache c(baseCache, "api", std::chrono::seconds(0));
|
||||
EXPECT_EQ("/test/api", c.getRequestPath());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/**
|
||||
\file test_Action.cpp
|
||||
Copyright Notice\n
|
||||
Copyright (C) 2020 Jan Rogall - developer\n
|
||||
|
||||
This file is part of hueplusplus.
|
||||
|
||||
hueplusplus 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.
|
||||
|
||||
hueplusplus 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 hueplusplus. If not, see <http://www.gnu.org/licenses/>.
|
||||
**/
|
||||
|
||||
#include <hueplusplus/Action.h>
|
||||
#include <hueplusplus/HueException.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
using namespace testing;
|
||||
using hueplusplus::Action;
|
||||
|
||||
TEST(Action, Constructor)
|
||||
{
|
||||
const std::string address = "/api/abcd/test";
|
||||
const nlohmann::json body = {{"test", "value"}};
|
||||
const nlohmann::json json = {{"address", address}, {"method", "PUT"}, {"body", body}};
|
||||
Action command(json);
|
||||
|
||||
EXPECT_EQ(address, command.getAddress());
|
||||
EXPECT_EQ(Action::Method::put, command.getMethod());
|
||||
EXPECT_EQ(body, command.getBody());
|
||||
EXPECT_EQ(json, command.toJson());
|
||||
}
|
||||
|
||||
TEST(Action, getMethod)
|
||||
{
|
||||
nlohmann::json json = {{"address", "/test"}, {"method", "PUT"}, {"body", {}}};
|
||||
EXPECT_EQ(Action::Method::put, Action(json).getMethod());
|
||||
json["method"] = "POST";
|
||||
EXPECT_EQ(Action::Method::post, Action(json).getMethod());
|
||||
json["method"] = "DELETE";
|
||||
EXPECT_EQ(Action::Method::deleteMethod, Action(json).getMethod());
|
||||
json["method"] = "unknown";
|
||||
EXPECT_THROW(Action(json).getMethod(), hueplusplus::HueException);
|
||||
}
|
||||
|
||||
TEST(Action, parseMethod)
|
||||
{
|
||||
using M = Action::Method;
|
||||
EXPECT_EQ(M::put, Action::parseMethod("PUT"));
|
||||
EXPECT_EQ(M::post, Action::parseMethod("POST"));
|
||||
EXPECT_EQ(M::deleteMethod, Action::parseMethod("DELETE"));
|
||||
EXPECT_THROW(Action::parseMethod("unknown"), hueplusplus::HueException);
|
||||
}
|
||||
|
||||
TEST(Action, methodToString)
|
||||
{
|
||||
using M = Action::Method;
|
||||
EXPECT_EQ("POST", Action::methodToString(M::post));
|
||||
EXPECT_EQ("PUT", Action::methodToString(M::put));
|
||||
EXPECT_EQ("DELETE", Action::methodToString(M::deleteMethod));
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
/**
|
||||
\file test_BaseDevice.cpp
|
||||
Copyright Notice\n
|
||||
Copyright (C) 2020 Jan Rogall - developer\n
|
||||
|
||||
This file is part of hueplusplus.
|
||||
|
||||
hueplusplus 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.
|
||||
|
||||
hueplusplus 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 hueplusplus. If not, see <http://www.gnu.org/licenses/>.
|
||||
**/
|
||||
|
||||
#include <gmock/gmock.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "testhelper.h"
|
||||
|
||||
#include "hueplusplus/BaseDevice.h"
|
||||
#include "mocks/mock_HttpHandler.h"
|
||||
|
||||
using namespace hueplusplus;
|
||||
using namespace testing;
|
||||
|
||||
class TestDevice : public BaseDevice
|
||||
{
|
||||
public:
|
||||
TestDevice(int id, const HueCommandAPI& commands, const std::string& path,
|
||||
std::chrono::steady_clock::duration refreshDuration, const nlohmann::json& currentState)
|
||||
: BaseDevice(id, commands, path, refreshDuration, currentState)
|
||||
{ }
|
||||
};
|
||||
|
||||
class BaseDeviceTest : public Test
|
||||
{
|
||||
protected:
|
||||
std::shared_ptr<MockHttpHandler> handler;
|
||||
HueCommandAPI commands;
|
||||
nlohmann::json state;
|
||||
std::string path = "/test/";
|
||||
|
||||
protected:
|
||||
BaseDeviceTest()
|
||||
: handler(std::make_shared<MockHttpHandler>()),
|
||||
commands(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler),
|
||||
state({{"type", "testType"}, {"name", "Test name"}, {"swversion", "1.2.3.4"}, {"modelid", "TEST"},
|
||||
{"manufacturername", "testManuf"}, {"uniqueid", "00:00:00:00:00:00:00:00-00"},
|
||||
{"productname", "Test type"}})
|
||||
{ }
|
||||
|
||||
TestDevice getDevice(int id)
|
||||
{
|
||||
EXPECT_CALL(*handler,
|
||||
GETJson("/api/" + getBridgeUsername() + path + std::to_string(id), _, getBridgeIp(), getBridgePort()))
|
||||
.WillOnce(Return(state));
|
||||
return TestDevice(id, commands, path, std::chrono::steady_clock::duration::max(), nullptr);
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(BaseDeviceTest, getId)
|
||||
{
|
||||
const int id = 1;
|
||||
EXPECT_EQ(id, getDevice(id).getId());
|
||||
}
|
||||
|
||||
TEST_F(BaseDeviceTest, getName)
|
||||
{
|
||||
EXPECT_EQ("Test name", getDevice(1).getName());
|
||||
}
|
||||
|
||||
TEST_F(BaseDeviceTest, getType)
|
||||
{
|
||||
EXPECT_EQ("testType", getDevice(1).getType());
|
||||
}
|
||||
|
||||
TEST_F(BaseDeviceTest, getModelId)
|
||||
{
|
||||
EXPECT_EQ("TEST", getDevice(1).getModelId());
|
||||
}
|
||||
|
||||
TEST_F(BaseDeviceTest, getUId)
|
||||
{
|
||||
EXPECT_EQ("00:00:00:00:00:00:00:00-00", getDevice(1).getUId());
|
||||
state.erase("uniqueid");
|
||||
EXPECT_EQ("", getDevice(1).getUId());
|
||||
}
|
||||
|
||||
TEST_F(BaseDeviceTest, getManufacturername)
|
||||
{
|
||||
EXPECT_EQ("testManuf", getDevice(1).getManufacturername());
|
||||
state.erase("manufacturername");
|
||||
EXPECT_EQ("", getDevice(1).getManufacturername());
|
||||
}
|
||||
|
||||
TEST_F(BaseDeviceTest, getProductname)
|
||||
{
|
||||
EXPECT_EQ("Test type", getDevice(1).getProductname());
|
||||
state.erase("productname");
|
||||
EXPECT_EQ("", getDevice(1).getProductname());
|
||||
}
|
||||
|
||||
TEST_F(BaseDeviceTest, getSwVersion)
|
||||
{
|
||||
EXPECT_EQ("1.2.3.4", getDevice(1).getSwVersion());
|
||||
}
|
||||
|
||||
TEST_F(BaseDeviceTest, setName)
|
||||
{
|
||||
const std::string name = "asdbsdakfl";
|
||||
const nlohmann::json request = {{"name", name}};
|
||||
const nlohmann::json response = { {{"success", {{"/lights/1/name", name}}}} };
|
||||
|
||||
TestDevice device = getDevice(1);
|
||||
EXPECT_CALL(*handler, PUTJson("/api/" + getBridgeUsername() + path + "1/name", request, getBridgeIp(), getBridgePort()))
|
||||
.WillOnce(Return(response));
|
||||
EXPECT_TRUE(device.setName(name));
|
||||
}
|
||||
@@ -0,0 +1,239 @@
|
||||
/**
|
||||
\file test_BaseHttpHandler.cpp
|
||||
Copyright Notice\n
|
||||
Copyright (C) 2017 Jan Rogall - developer\n
|
||||
Copyright (C) 2017 Moritz Wirger - developer\n
|
||||
|
||||
This file is part of hueplusplus.
|
||||
|
||||
hueplusplus 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.
|
||||
|
||||
hueplusplus 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 hueplusplus. If not, see <http://www.gnu.org/licenses/>.
|
||||
**/
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include <gmock/gmock.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "testhelper.h"
|
||||
|
||||
#include "hueplusplus/HueException.h"
|
||||
#include <nlohmann/json.hpp>
|
||||
#include "mocks/mock_BaseHttpHandler.h"
|
||||
|
||||
using namespace hueplusplus;
|
||||
|
||||
TEST(BaseHttpHandler, sendGetHTTPBody)
|
||||
{
|
||||
using namespace ::testing;
|
||||
MockBaseHttpHandler handler;
|
||||
|
||||
EXPECT_CALL(handler, send("testmsg", "192.168.2.1", 90))
|
||||
.Times(AtLeast(2))
|
||||
.WillOnce(Return(""))
|
||||
.WillRepeatedly(Return("\r\n\r\ntestreply"));
|
||||
|
||||
EXPECT_THROW(handler.sendGetHTTPBody("testmsg", "192.168.2.1", 90), HueException);
|
||||
EXPECT_EQ("testreply", handler.sendGetHTTPBody("testmsg", "192.168.2.1", 90));
|
||||
}
|
||||
|
||||
TEST(BaseHttpHandler, sendHTTPRequest)
|
||||
{
|
||||
using namespace ::testing;
|
||||
MockBaseHttpHandler handler;
|
||||
|
||||
EXPECT_CALL(handler,
|
||||
send("GET UrI HTTP/1.0\r\nContent-Type: "
|
||||
"text/html\r\nContent-Length: 4\r\n\r\nbody\r\n\r\n",
|
||||
"192.168.2.1", 90))
|
||||
.Times(AtLeast(2))
|
||||
.WillOnce(Return(""))
|
||||
.WillRepeatedly(Return("\r\n\r\ntestreply"));
|
||||
|
||||
EXPECT_THROW(handler.sendHTTPRequest("GET", "UrI", "text/html", "body", "192.168.2.1", 90), HueException);
|
||||
EXPECT_EQ("testreply", handler.sendHTTPRequest("GET", "UrI", "text/html", "body", "192.168.2.1", 90));
|
||||
}
|
||||
|
||||
TEST(BaseHttpHandler, GETString)
|
||||
{
|
||||
using namespace ::testing;
|
||||
MockBaseHttpHandler handler;
|
||||
|
||||
EXPECT_CALL(handler,
|
||||
send("GET UrI HTTP/1.0\r\nContent-Type: "
|
||||
"text/html\r\nContent-Length: 4\r\n\r\nbody\r\n\r\n",
|
||||
"192.168.2.1", 90))
|
||||
.Times(AtLeast(2))
|
||||
.WillOnce(Return(""))
|
||||
.WillRepeatedly(Return("\r\n\r\ntestreply"));
|
||||
|
||||
EXPECT_THROW(handler.GETString("UrI", "text/html", "body", "192.168.2.1", 90), HueException);
|
||||
EXPECT_EQ("testreply", handler.GETString("UrI", "text/html", "body", "192.168.2.1", 90));
|
||||
}
|
||||
|
||||
TEST(BaseHttpHandler, POSTString)
|
||||
{
|
||||
using namespace ::testing;
|
||||
MockBaseHttpHandler handler;
|
||||
|
||||
EXPECT_CALL(handler,
|
||||
send("POST UrI HTTP/1.0\r\nContent-Type: "
|
||||
"text/html\r\nContent-Length: 4\r\n\r\nbody\r\n\r\n",
|
||||
"192.168.2.1", 90))
|
||||
.Times(AtLeast(2))
|
||||
.WillOnce(Return(""))
|
||||
.WillRepeatedly(Return("\r\n\r\ntestreply"));
|
||||
|
||||
EXPECT_THROW(handler.POSTString("UrI", "text/html", "body", "192.168.2.1", 90), HueException);
|
||||
EXPECT_EQ("testreply", handler.POSTString("UrI", "text/html", "body", "192.168.2.1", 90));
|
||||
}
|
||||
|
||||
TEST(BaseHttpHandler, PUTString)
|
||||
{
|
||||
using namespace ::testing;
|
||||
MockBaseHttpHandler handler;
|
||||
|
||||
EXPECT_CALL(handler,
|
||||
send("PUT UrI HTTP/1.0\r\nContent-Type: "
|
||||
"text/html\r\nContent-Length: 4\r\n\r\nbody\r\n\r\n",
|
||||
"192.168.2.1", 90))
|
||||
.Times(AtLeast(2))
|
||||
.WillOnce(Return(""))
|
||||
.WillRepeatedly(Return("\r\n\r\ntestreply"));
|
||||
|
||||
EXPECT_THROW(handler.PUTString("UrI", "text/html", "body", "192.168.2.1", 90), HueException);
|
||||
EXPECT_EQ("testreply", handler.PUTString("UrI", "text/html", "body", "192.168.2.1", 90));
|
||||
}
|
||||
|
||||
TEST(BaseHttpHandler, DELETEString)
|
||||
{
|
||||
using namespace ::testing;
|
||||
MockBaseHttpHandler handler;
|
||||
|
||||
EXPECT_CALL(handler,
|
||||
send("DELETE UrI HTTP/1.0\r\nContent-Type: "
|
||||
"text/html\r\nContent-Length: 4\r\n\r\nbody\r\n\r\n",
|
||||
"192.168.2.1", 90))
|
||||
.Times(AtLeast(2))
|
||||
.WillOnce(Return(""))
|
||||
.WillRepeatedly(Return("\r\n\r\ntestreply"));
|
||||
|
||||
EXPECT_THROW(handler.DELETEString("UrI", "text/html", "body", "192.168.2.1", 90), HueException);
|
||||
EXPECT_EQ("testreply", handler.DELETEString("UrI", "text/html", "body", "192.168.2.1", 90));
|
||||
}
|
||||
|
||||
TEST(BaseHttpHandler, GETJson)
|
||||
{
|
||||
using namespace ::testing;
|
||||
MockBaseHttpHandler handler;
|
||||
|
||||
nlohmann::json testval;
|
||||
testval["test"] = 100;
|
||||
std::string expected_call = "GET UrI HTTP/1.0\r\nContent-Type: application/json\r\nContent-Length: ";
|
||||
expected_call.append(std::to_string(testval.dump().size()));
|
||||
expected_call.append("\r\n\r\n");
|
||||
expected_call.append(testval.dump());
|
||||
expected_call.append("\r\n\r\n");
|
||||
|
||||
EXPECT_CALL(handler, send(expected_call, "192.168.2.1", 90))
|
||||
.Times(AtLeast(2))
|
||||
.WillOnce(Return(""))
|
||||
.WillOnce(Return("\r\n\r\n"))
|
||||
.WillRepeatedly(Return("\r\n\r\n{\"test\" : \"whatever\"}"));
|
||||
nlohmann::json expected;
|
||||
expected["test"] = "whatever";
|
||||
|
||||
EXPECT_THROW(handler.GETJson("UrI", testval, "192.168.2.1", 90), HueException);
|
||||
EXPECT_THROW(handler.GETJson("UrI", testval, "192.168.2.1", 90), nlohmann::json::parse_error);
|
||||
EXPECT_EQ(expected, handler.GETJson("UrI", testval, "192.168.2.1", 90));
|
||||
}
|
||||
|
||||
TEST(BaseHttpHandler, POSTJson)
|
||||
{
|
||||
using namespace ::testing;
|
||||
MockBaseHttpHandler handler;
|
||||
|
||||
nlohmann::json testval;
|
||||
testval["test"] = 100;
|
||||
std::string expected_call = "POST UrI HTTP/1.0\r\nContent-Type: application/json\r\nContent-Length: ";
|
||||
expected_call.append(std::to_string(testval.dump().size()));
|
||||
expected_call.append("\r\n\r\n");
|
||||
expected_call.append(testval.dump());
|
||||
expected_call.append("\r\n\r\n");
|
||||
|
||||
EXPECT_CALL(handler, send(expected_call, "192.168.2.1", 90))
|
||||
.Times(AtLeast(2))
|
||||
.WillOnce(Return(""))
|
||||
.WillOnce(Return("\r\n\r\n"))
|
||||
.WillRepeatedly(Return("\r\n\r\n{\"test\" : \"whatever\"}"));
|
||||
nlohmann::json expected;
|
||||
expected["test"] = "whatever";
|
||||
|
||||
EXPECT_THROW(handler.POSTJson("UrI", testval, "192.168.2.1", 90), HueException);
|
||||
EXPECT_THROW(handler.POSTJson("UrI", testval, "192.168.2.1", 90), nlohmann::json::parse_error);
|
||||
EXPECT_EQ(expected, handler.POSTJson("UrI", testval, "192.168.2.1", 90));
|
||||
}
|
||||
|
||||
TEST(BaseHttpHandler, PUTJson)
|
||||
{
|
||||
using namespace ::testing;
|
||||
MockBaseHttpHandler handler;
|
||||
|
||||
nlohmann::json testval;
|
||||
testval["test"] = 100;
|
||||
std::string expected_call = "PUT UrI HTTP/1.0\r\nContent-Type: application/json\r\nContent-Length: ";
|
||||
expected_call.append(std::to_string(testval.dump().size()));
|
||||
expected_call.append("\r\n\r\n");
|
||||
expected_call.append(testval.dump());
|
||||
expected_call.append("\r\n\r\n");
|
||||
|
||||
EXPECT_CALL(handler, send(expected_call, "192.168.2.1", 90))
|
||||
.Times(AtLeast(2))
|
||||
.WillOnce(Return(""))
|
||||
.WillOnce(Return("\r\n\r\n"))
|
||||
.WillRepeatedly(Return("\r\n\r\n{\"test\" : \"whatever\"}"));
|
||||
nlohmann::json expected;
|
||||
expected["test"] = "whatever";
|
||||
|
||||
EXPECT_THROW(handler.PUTJson("UrI", testval, "192.168.2.1", 90), HueException);
|
||||
EXPECT_THROW(handler.PUTJson("UrI", testval, "192.168.2.1", 90), nlohmann::json::parse_error);
|
||||
EXPECT_EQ(expected, handler.PUTJson("UrI", testval, "192.168.2.1", 90));
|
||||
}
|
||||
|
||||
TEST(BaseHttpHandler, DELETEJson)
|
||||
{
|
||||
using namespace ::testing;
|
||||
MockBaseHttpHandler handler;
|
||||
|
||||
nlohmann::json testval;
|
||||
testval["test"] = 100;
|
||||
std::string expected_call = "DELETE UrI HTTP/1.0\r\nContent-Type: "
|
||||
"application/json\r\nContent-Length: ";
|
||||
expected_call.append(std::to_string(testval.dump().size()));
|
||||
expected_call.append("\r\n\r\n");
|
||||
expected_call.append(testval.dump());
|
||||
expected_call.append("\r\n\r\n");
|
||||
|
||||
EXPECT_CALL(handler, send(expected_call, "192.168.2.1", 90))
|
||||
.Times(AtLeast(2))
|
||||
.WillOnce(Return(""))
|
||||
.WillOnce(Return("\r\n\r\n"))
|
||||
.WillRepeatedly(Return("\r\n\r\n{\"test\" : \"whatever\"}"));
|
||||
nlohmann::json expected;
|
||||
expected["test"] = "whatever";
|
||||
|
||||
EXPECT_THROW(handler.DELETEJson("UrI", testval, "192.168.2.1", 90), HueException);
|
||||
EXPECT_THROW(handler.DELETEJson("UrI", testval, "192.168.2.1", 90), nlohmann::json::parse_error);
|
||||
EXPECT_EQ(expected, handler.DELETEJson("UrI", testval, "192.168.2.1", 90));
|
||||
}
|
||||
+625
@@ -0,0 +1,625 @@
|
||||
/**
|
||||
\file test_Bridge.cpp
|
||||
Copyright Notice\n
|
||||
Copyright (C) 2017 Jan Rogall - developer\n
|
||||
Copyright (C) 2017 Moritz Wirger - developer\n
|
||||
|
||||
This file is part of hueplusplus.
|
||||
|
||||
hueplusplus 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.
|
||||
|
||||
hueplusplus 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 hueplusplus. If not, see <http://www.gnu.org/licenses/>.
|
||||
**/
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include <gmock/gmock.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "testhelper.h"
|
||||
|
||||
#include "hueplusplus/Bridge.h"
|
||||
#include "hueplusplus/LibConfig.h"
|
||||
#include <nlohmann/json.hpp>
|
||||
#include "mocks/mock_HttpHandler.h"
|
||||
|
||||
using namespace hueplusplus;
|
||||
|
||||
class BridgeFinderTest : public ::testing::Test
|
||||
{
|
||||
protected:
|
||||
std::shared_ptr<MockHttpHandler> handler;
|
||||
|
||||
protected:
|
||||
BridgeFinderTest() : handler(std::make_shared<MockHttpHandler>())
|
||||
{
|
||||
using namespace ::testing;
|
||||
|
||||
EXPECT_CALL(*handler,
|
||||
sendMulticast("M-SEARCH * HTTP/1.1\r\nHOST: 239.255.255.250:1900\r\nMAN: "
|
||||
"\"ssdp:discover\"\r\nMX: 5\r\nST: ssdp:all\r\n\r\n",
|
||||
"239.255.255.250", 1900, Config::instance().getUPnPTimeout()))
|
||||
.Times(AtLeast(1))
|
||||
.WillRepeatedly(Return(getMulticastReply()));
|
||||
|
||||
EXPECT_CALL(*handler, GETString("/description.xml", "application/xml", "", "192.168.2.1", getBridgePort()))
|
||||
.Times(0);
|
||||
|
||||
EXPECT_CALL(*handler, GETString("/description.xml", "application/xml", "", getBridgeIp(), getBridgePort()))
|
||||
.Times(AtLeast(1))
|
||||
.WillRepeatedly(Return(getBridgeXml()));
|
||||
}
|
||||
~BridgeFinderTest() {};
|
||||
};
|
||||
|
||||
TEST_F(BridgeFinderTest, findBridges)
|
||||
{
|
||||
BridgeFinder finder(handler);
|
||||
std::vector<BridgeFinder::BridgeIdentification> bridges = finder.findBridges();
|
||||
|
||||
BridgeFinder::BridgeIdentification bridge_to_comp;
|
||||
bridge_to_comp.ip = getBridgeIp();
|
||||
bridge_to_comp.port = getBridgePort();
|
||||
bridge_to_comp.mac = getBridgeMac();
|
||||
|
||||
EXPECT_EQ(bridges.size(), 1) << "BridgeFinder found more than one Bridge";
|
||||
EXPECT_EQ(bridges[0].ip, bridge_to_comp.ip) << "BridgeIdentification ip does not match";
|
||||
EXPECT_EQ(bridges[0].port, bridge_to_comp.port) << "BridgeIdentification port does not match";
|
||||
EXPECT_EQ(bridges[0].mac, bridge_to_comp.mac) << "BridgeIdentification mac does not match";
|
||||
|
||||
// Test invalid description
|
||||
EXPECT_CALL(*handler, GETString("/description.xml", "application/xml", "", getBridgeIp(), getBridgePort()))
|
||||
.Times(1)
|
||||
.WillOnce(::testing::Return("invalid stuff"));
|
||||
bridges = finder.findBridges();
|
||||
EXPECT_TRUE(bridges.empty());
|
||||
}
|
||||
|
||||
TEST_F(BridgeFinderTest, getBridge)
|
||||
{
|
||||
using namespace ::testing;
|
||||
nlohmann::json request {{"devicetype", "HuePlusPlus#User"}, {"generateclientkey", true}};
|
||||
|
||||
nlohmann::json errorResponse
|
||||
= {{{"error", {{"type", 101}, {"address", ""}, {"description", "link button not pressed"}}}}};
|
||||
|
||||
EXPECT_CALL(*handler, POSTJson("/api", request, getBridgeIp(), getBridgePort()))
|
||||
.Times(AtLeast(1))
|
||||
.WillRepeatedly(Return(errorResponse));
|
||||
|
||||
BridgeFinder finder(handler);
|
||||
std::vector<BridgeFinder::BridgeIdentification> bridges = finder.findBridges();
|
||||
|
||||
ASSERT_THROW(finder.getBridge(bridges[0]), HueException);
|
||||
|
||||
nlohmann::json successResponse = {{{"success", {{"username", getBridgeUsername()}}}}};
|
||||
|
||||
EXPECT_CALL(*handler, POSTJson("/api", request, getBridgeIp(), getBridgePort()))
|
||||
.Times(1)
|
||||
.WillOnce(Return(successResponse));
|
||||
|
||||
finder = BridgeFinder(handler);
|
||||
bridges = finder.findBridges();
|
||||
|
||||
Bridge test_bridge = finder.getBridge(bridges[0]);
|
||||
|
||||
EXPECT_EQ(test_bridge.getBridgeIP(), getBridgeIp()) << "Bridge IP not matching";
|
||||
EXPECT_EQ(test_bridge.getBridgePort(), getBridgePort()) << "Bridge Port not matching";
|
||||
EXPECT_EQ(test_bridge.getUsername(), getBridgeUsername()) << "Bridge username not matching";
|
||||
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
}
|
||||
|
||||
TEST_F(BridgeFinderTest, addUsername)
|
||||
{
|
||||
BridgeFinder finder(handler);
|
||||
std::vector<BridgeFinder::BridgeIdentification> bridges = finder.findBridges();
|
||||
|
||||
finder.addUsername(bridges[0].mac, getBridgeUsername());
|
||||
Bridge test_bridge = finder.getBridge(bridges[0]);
|
||||
|
||||
EXPECT_EQ(test_bridge.getBridgeIP(), getBridgeIp()) << "Bridge IP not matching";
|
||||
EXPECT_EQ(test_bridge.getBridgePort(), getBridgePort()) << "Bridge Port not matching";
|
||||
EXPECT_EQ(test_bridge.getUsername(), getBridgeUsername()) << "Bridge username not matching";
|
||||
}
|
||||
|
||||
TEST_F(BridgeFinderTest, getAllUsernames)
|
||||
{
|
||||
BridgeFinder finder(handler);
|
||||
std::vector<BridgeFinder::BridgeIdentification> bridges = finder.findBridges();
|
||||
|
||||
finder.addUsername(bridges[0].mac, getBridgeUsername());
|
||||
|
||||
std::map<std::string, std::string> users = finder.getAllUsernames();
|
||||
EXPECT_EQ(users[getBridgeMac()], getBridgeUsername()) << "Username of MAC:" << getBridgeMac() << "not matching";
|
||||
}
|
||||
|
||||
TEST(Bridge, Constructor)
|
||||
{
|
||||
std::shared_ptr<MockHttpHandler> handler = std::make_shared<MockHttpHandler>();
|
||||
Bridge test_bridge(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler);
|
||||
|
||||
EXPECT_EQ(test_bridge.getBridgeIP(), getBridgeIp()) << "Bridge IP not matching";
|
||||
EXPECT_EQ(test_bridge.getBridgePort(), getBridgePort()) << "Bridge Port not matching";
|
||||
EXPECT_EQ(test_bridge.getUsername(), getBridgeUsername()) << "Bridge username not matching";
|
||||
}
|
||||
|
||||
TEST(Bridge, requestUsername)
|
||||
{
|
||||
using namespace ::testing;
|
||||
std::shared_ptr<MockHttpHandler> handler = std::make_shared<MockHttpHandler>();
|
||||
nlohmann::json request {{"devicetype", "HuePlusPlus#User"}, {"generateclientkey", true}};
|
||||
|
||||
{
|
||||
nlohmann::json errorResponse
|
||||
= {{{"error", {{"type", 101}, {"address", ""}, {"description", "link button not pressed"}}}}};
|
||||
|
||||
EXPECT_CALL(*handler, POSTJson("/api", request, getBridgeIp(), getBridgePort()))
|
||||
.Times(AtLeast(1))
|
||||
.WillRepeatedly(Return(errorResponse));
|
||||
|
||||
Bridge test_bridge(getBridgeIp(), getBridgePort(), "", handler);
|
||||
|
||||
std::string username = test_bridge.requestUsername();
|
||||
EXPECT_EQ(username, "") << "Returned username not matching";
|
||||
EXPECT_EQ(test_bridge.getUsername(), "") << "Bridge username not matching";
|
||||
}
|
||||
|
||||
{
|
||||
// Other error code causes exception
|
||||
int otherError = 1;
|
||||
nlohmann::json exceptionResponse
|
||||
= {{{"error", {{"type", otherError}, {"address", ""}, {"description", "some error"}}}}};
|
||||
Bridge testBridge(getBridgeIp(), getBridgePort(), "", handler);
|
||||
|
||||
EXPECT_CALL(*handler, POSTJson("/api", request, getBridgeIp(), getBridgePort()))
|
||||
.WillOnce(Return(exceptionResponse));
|
||||
|
||||
try
|
||||
{
|
||||
testBridge.requestUsername();
|
||||
FAIL() << "requestUsername did not throw";
|
||||
}
|
||||
catch (const HueAPIResponseException& e)
|
||||
{
|
||||
EXPECT_EQ(e.GetErrorNumber(), otherError);
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
FAIL() << "wrong exception: " << e.what();
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
nlohmann::json successResponse = {{{"success", {{"username", getBridgeUsername()}}}}};
|
||||
EXPECT_CALL(*handler, POSTJson("/api", request, getBridgeIp(), getBridgePort()))
|
||||
.Times(1)
|
||||
.WillRepeatedly(Return(successResponse));
|
||||
|
||||
Bridge test_bridge(getBridgeIp(), getBridgePort(), "", handler);
|
||||
|
||||
nlohmann::json hue_bridge_state {{"lights", {}}};
|
||||
EXPECT_CALL(
|
||||
*handler, GETJson("/api/" + getBridgeUsername(), nlohmann::json::object(), getBridgeIp(), getBridgePort()))
|
||||
.Times(1)
|
||||
.WillOnce(Return(hue_bridge_state));
|
||||
std::string username = test_bridge.requestUsername();
|
||||
|
||||
EXPECT_EQ(username, test_bridge.getUsername()) << "Returned username not matching";
|
||||
EXPECT_EQ(test_bridge.getBridgeIP(), getBridgeIp()) << "Bridge IP not matching";
|
||||
EXPECT_EQ(test_bridge.getUsername(), getBridgeUsername()) << "Bridge username not matching";
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Bridge, setIP)
|
||||
{
|
||||
std::shared_ptr<MockHttpHandler> handler = std::make_shared<MockHttpHandler>();
|
||||
Bridge test_bridge(getBridgeIp(), getBridgePort(), "", handler);
|
||||
EXPECT_EQ(test_bridge.getBridgeIP(), getBridgeIp()) << "Bridge IP not matching after initialization";
|
||||
test_bridge.setIP("192.168.2.112");
|
||||
EXPECT_EQ(test_bridge.getBridgeIP(), "192.168.2.112") << "Bridge IP not matching after setting it";
|
||||
}
|
||||
|
||||
TEST(Bridge, setPort)
|
||||
{
|
||||
std::shared_ptr<MockHttpHandler> handler = std::make_shared<MockHttpHandler>();
|
||||
Bridge test_bridge = Bridge(getBridgeIp(), getBridgePort(), "", handler);
|
||||
EXPECT_EQ(test_bridge.getBridgePort(), getBridgePort()) << "Bridge Port not matching after initialization";
|
||||
test_bridge.setPort(81);
|
||||
EXPECT_EQ(test_bridge.getBridgePort(), 81) << "Bridge Port not matching after setting it";
|
||||
}
|
||||
|
||||
TEST(Bridge, getLight)
|
||||
{
|
||||
using namespace ::testing;
|
||||
std::shared_ptr<MockHttpHandler> handler = std::make_shared<MockHttpHandler>();
|
||||
EXPECT_CALL(
|
||||
*handler, GETJson("/api/" + getBridgeUsername(), nlohmann::json::object(), getBridgeIp(), getBridgePort()))
|
||||
.Times(1);
|
||||
|
||||
Bridge test_bridge(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler);
|
||||
|
||||
// Test exception
|
||||
ASSERT_THROW(test_bridge.lights().get(1), HueException);
|
||||
|
||||
nlohmann::json hue_bridge_state {{"lights",
|
||||
{{"1",
|
||||
{{"state",
|
||||
{{"on", true}, {"bri", 254}, {"ct", 366}, {"alert", "none"}, {"colormode", "ct"},
|
||||
{"reachable", true}}},
|
||||
{"swupdate", {{"state", "noupdates"}, {"lastinstall", nullptr}}}, {"type", "Color temperature light"},
|
||||
{"name", "Hue ambiance lamp 1"}, {"modelid", "LTW001"}, {"manufacturername", "Philips"},
|
||||
{"uniqueid", "00:00:00:00:00:00:00:00-00"}, {"swversion", "5.50.1.19085"}}}}}};
|
||||
|
||||
EXPECT_CALL(
|
||||
*handler, GETJson("/api/" + getBridgeUsername(), nlohmann::json::object(), getBridgeIp(), getBridgePort()))
|
||||
.Times(1)
|
||||
.WillOnce(Return(hue_bridge_state));
|
||||
|
||||
// Refresh cache
|
||||
test_bridge = Bridge(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler);
|
||||
|
||||
// Test when correct data is sent
|
||||
Light test_light_1 = test_bridge.lights().get(1);
|
||||
EXPECT_EQ(test_light_1.getName(), "Hue ambiance lamp 1");
|
||||
EXPECT_EQ(test_light_1.getColorType(), ColorType::TEMPERATURE);
|
||||
|
||||
// Test again to check whether light is returned directly -> interesting for
|
||||
// code coverage test
|
||||
test_light_1 = test_bridge.lights().get(1);
|
||||
EXPECT_EQ(test_light_1.getName(), "Hue ambiance lamp 1");
|
||||
EXPECT_EQ(test_light_1.getColorType(), ColorType::TEMPERATURE);
|
||||
}
|
||||
|
||||
TEST(Bridge, SharedState)
|
||||
{
|
||||
using namespace ::testing;
|
||||
std::shared_ptr<MockHttpHandler> handler = std::make_shared<MockHttpHandler>();
|
||||
|
||||
nlohmann::json hue_bridge_state {{"lights",
|
||||
{{"1",
|
||||
{{"state",
|
||||
{{"on", true}, {"bri", 254}, {"ct", 366}, {"alert", "none"}, {"colormode", "ct"},
|
||||
{"reachable", true}}},
|
||||
{"swupdate", {{"state", "noupdates"}, {"lastinstall", nullptr}}}, {"type", "Color temperature light"},
|
||||
{"name", "Hue ambiance lamp 1"}, {"modelid", "LTW001"}, {"manufacturername", "Philips"},
|
||||
{"uniqueid", "00:00:00:00:00:00:00:00-00"}, {"swversion", "5.50.1.19085"}}}}}};
|
||||
|
||||
EXPECT_CALL(
|
||||
*handler, GETJson("/api/" + getBridgeUsername(), nlohmann::json::object(), getBridgeIp(), getBridgePort()))
|
||||
.Times(1)
|
||||
.WillOnce(Return(hue_bridge_state));
|
||||
Bridge test_bridge(
|
||||
getBridgeIp(), getBridgePort(), getBridgeUsername(), handler, "", std::chrono::seconds(10), true);
|
||||
|
||||
// Test when correct data is sent
|
||||
Light test_light_1 = test_bridge.lights().get(1);
|
||||
|
||||
Light test_light_copy = test_bridge.lights().get(1);
|
||||
const std::string newName = "New light name";
|
||||
EXPECT_CALL(*handler, PUTJson("/api/" + getBridgeUsername() + "/lights/1/name", _, getBridgeIp(), getBridgePort()))
|
||||
.WillOnce(Return(nlohmann::json({{"success", {{{"/lights/1/name", newName}}}}})));
|
||||
test_light_1.setName(newName);
|
||||
hue_bridge_state["lights"]["1"]["name"] = newName;
|
||||
|
||||
EXPECT_CALL(*handler,
|
||||
GETJson("/api/" + getBridgeUsername() + "/lights/1", nlohmann::json::object(), getBridgeIp(), getBridgePort()))
|
||||
.Times(1)
|
||||
.WillOnce(Return(hue_bridge_state["lights"]["1"]));
|
||||
test_light_1.refresh(true);
|
||||
|
||||
EXPECT_EQ(newName, test_light_copy.getName());
|
||||
}
|
||||
|
||||
TEST(Bridge, removeLight)
|
||||
{
|
||||
using namespace ::testing;
|
||||
std::shared_ptr<MockHttpHandler> handler = std::make_shared<MockHttpHandler>();
|
||||
nlohmann::json hue_bridge_state {{"lights",
|
||||
{{"1",
|
||||
{{"state",
|
||||
{{"on", true}, {"bri", 254}, {"ct", 366}, {"alert", "none"}, {"colormode", "ct"},
|
||||
{"reachable", true}}},
|
||||
{"swupdate", {{"state", "noupdates"}, {"lastinstall", nullptr}}}, {"type", "Color temperature light"},
|
||||
{"name", "Hue ambiance lamp 1"}, {"modelid", "LTW001"}, {"manufacturername", "Philips"},
|
||||
{"uniqueid", "00:00:00:00:00:00:00:00-00"}, {"swversion", "5.50.1.19085"}}}}}};
|
||||
EXPECT_CALL(
|
||||
*handler, GETJson("/api/" + getBridgeUsername(), nlohmann::json::object(), getBridgeIp(), getBridgePort()))
|
||||
.Times(1)
|
||||
.WillOnce(Return(hue_bridge_state));
|
||||
|
||||
Bridge test_bridge(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler);
|
||||
|
||||
nlohmann::json return_answer;
|
||||
return_answer = nlohmann::json::array();
|
||||
return_answer[0] = nlohmann::json::object();
|
||||
return_answer[0]["success"] = "/lights/1 deleted";
|
||||
EXPECT_CALL(*handler,
|
||||
DELETEJson(
|
||||
"/api/" + getBridgeUsername() + "/lights/1", nlohmann::json::object(), getBridgeIp(), getBridgePort()))
|
||||
.Times(2)
|
||||
.WillOnce(Return(return_answer))
|
||||
.WillOnce(Return(nlohmann::json()));
|
||||
|
||||
// Test when correct data is sent
|
||||
Light test_light_1 = test_bridge.lights().get(1);
|
||||
|
||||
EXPECT_EQ(test_bridge.lights().remove(1), true);
|
||||
|
||||
EXPECT_EQ(test_bridge.lights().remove(1), false);
|
||||
}
|
||||
|
||||
TEST(Bridge, getAllLights)
|
||||
{
|
||||
using namespace ::testing;
|
||||
std::shared_ptr<MockHttpHandler> handler = std::make_shared<MockHttpHandler>();
|
||||
nlohmann::json hue_bridge_state {{"lights",
|
||||
{{"1",
|
||||
{{"state",
|
||||
{{"on", true}, {"bri", 254}, {"ct", 366}, {"alert", "none"}, {"colormode", "ct"},
|
||||
{"reachable", true}}},
|
||||
{"swupdate", {{"state", "noupdates"}, {"lastinstall", nullptr}}}, {"type", "Color temperature light"},
|
||||
{"name", "Hue ambiance lamp 1"}, {"modelid", "LTW001"}, {"manufacturername", "Philips"},
|
||||
{"uniqueid", "00:00:00:00:00:00:00:00-00"}, {"swversion", "5.50.1.19085"}}}}}};
|
||||
|
||||
EXPECT_CALL(
|
||||
*handler, GETJson("/api/" + getBridgeUsername(), nlohmann::json::object(), getBridgeIp(), getBridgePort()))
|
||||
.Times(AtLeast(1))
|
||||
.WillRepeatedly(Return(hue_bridge_state));
|
||||
|
||||
Bridge test_bridge(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler);
|
||||
|
||||
std::vector<Light> test_lights = test_bridge.lights().getAll();
|
||||
ASSERT_EQ(1, test_lights.size());
|
||||
EXPECT_EQ(test_lights[0].getName(), "Hue ambiance lamp 1");
|
||||
EXPECT_EQ(test_lights[0].getColorType(), ColorType::TEMPERATURE);
|
||||
}
|
||||
|
||||
TEST(Bridge, lightExists)
|
||||
{
|
||||
using namespace ::testing;
|
||||
std::shared_ptr<MockHttpHandler> handler = std::make_shared<MockHttpHandler>();
|
||||
nlohmann::json hue_bridge_state {{"lights",
|
||||
{{"1",
|
||||
{{"state",
|
||||
{{"on", true}, {"bri", 254}, {"ct", 366}, {"alert", "none"}, {"colormode", "ct"},
|
||||
{"reachable", true}}},
|
||||
{"swupdate", {{"state", "noupdates"}, {"lastinstall", nullptr}}}, {"type", "Color temperature light"},
|
||||
{"name", "Hue ambiance lamp 1"}, {"modelid", "LTW001"}, {"manufacturername", "Philips"},
|
||||
{"uniqueid", "00:00:00:00:00:00:00:00-00"}, {"swversion", "5.50.1.19085"}}}}}};
|
||||
EXPECT_CALL(
|
||||
*handler, GETJson("/api/" + getBridgeUsername(), nlohmann::json::object(), getBridgeIp(), getBridgePort()))
|
||||
.Times(AtLeast(1))
|
||||
.WillRepeatedly(Return(hue_bridge_state));
|
||||
|
||||
Bridge test_bridge(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler);
|
||||
|
||||
test_bridge.refresh();
|
||||
|
||||
EXPECT_TRUE(Const(test_bridge).lights().exists(1));
|
||||
EXPECT_FALSE(Const(test_bridge).lights().exists(2));
|
||||
}
|
||||
|
||||
TEST(Bridge, getGroup)
|
||||
{
|
||||
using namespace ::testing;
|
||||
std::shared_ptr<MockHttpHandler> handler = std::make_shared<MockHttpHandler>();
|
||||
EXPECT_CALL(
|
||||
*handler, GETJson("/api/" + getBridgeUsername(), nlohmann::json::object(), getBridgeIp(), getBridgePort()))
|
||||
.Times(1);
|
||||
|
||||
Bridge test_bridge(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler);
|
||||
|
||||
// Test exception
|
||||
ASSERT_THROW(test_bridge.groups().get(1), HueException);
|
||||
|
||||
nlohmann::json hue_bridge_state {{"groups",
|
||||
{{"1",
|
||||
{{"name", "Group 1"}, {"type", "LightGroup"}, {"lights", {"1", "2", "3"}},
|
||||
{"action",
|
||||
{{"on", true}, {"bri", 254}, {"ct", 366}, {"alert", "none"}, {"colormode", "ct"}, {"hue", 200},
|
||||
{"sat", 254}, {"effect", "none"}, {"xy", {0.f, 0.f}}}},
|
||||
{"state", {{"any_on", true}, {"all_on", true}}}}}}}};
|
||||
|
||||
EXPECT_CALL(
|
||||
*handler, GETJson("/api/" + getBridgeUsername(), nlohmann::json::object(), getBridgeIp(), getBridgePort()))
|
||||
.Times(1)
|
||||
.WillOnce(Return(hue_bridge_state));
|
||||
|
||||
// Refresh cache
|
||||
test_bridge = Bridge(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler);
|
||||
|
||||
// Test when correct data is sent
|
||||
Group test_group_1 = test_bridge.groups().get(1);
|
||||
EXPECT_EQ(test_group_1.getName(), "Group 1");
|
||||
EXPECT_EQ(test_group_1.getType(), "LightGroup");
|
||||
|
||||
// Test again to check whether group is returned directly
|
||||
test_group_1 = test_bridge.groups().get(1);
|
||||
EXPECT_EQ(test_group_1.getName(), "Group 1");
|
||||
EXPECT_EQ(test_group_1.getType(), "LightGroup");
|
||||
}
|
||||
|
||||
TEST(Bridge, removeGroup)
|
||||
{
|
||||
using namespace ::testing;
|
||||
std::shared_ptr<MockHttpHandler> handler = std::make_shared<MockHttpHandler>();
|
||||
nlohmann::json hue_bridge_state {{"groups",
|
||||
{{"1",
|
||||
{{"name", "Group 1"}, {"type", "LightGroup"}, {"lights", {"1", "2", "3"}},
|
||||
{"action",
|
||||
{{"on", true}, {"bri", 254}, {"ct", 366}, {"alert", "none"}, {"colormode", "ct"}, {"hue", 200},
|
||||
{"sat", 254}, {"effect", "none"}, {"xy", {0.f, 0.f}}}},
|
||||
{"state", {{"any_on", true}, {"all_on", true}}}}}}}};
|
||||
EXPECT_CALL(
|
||||
*handler, GETJson("/api/" + getBridgeUsername(), nlohmann::json::object(), getBridgeIp(), getBridgePort()))
|
||||
.Times(1)
|
||||
.WillOnce(Return(hue_bridge_state));
|
||||
|
||||
Bridge test_bridge(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler);
|
||||
|
||||
nlohmann::json return_answer;
|
||||
return_answer = nlohmann::json::array();
|
||||
return_answer[0] = nlohmann::json::object();
|
||||
return_answer[0]["success"] = "/groups/1 deleted";
|
||||
EXPECT_CALL(*handler,
|
||||
DELETEJson(
|
||||
"/api/" + getBridgeUsername() + "/groups/1", nlohmann::json::object(), getBridgeIp(), getBridgePort()))
|
||||
.Times(2)
|
||||
.WillOnce(Return(return_answer))
|
||||
.WillOnce(Return(nlohmann::json()));
|
||||
|
||||
// Test when correct data is sent
|
||||
Group test_group_1 = test_bridge.groups().get(1);
|
||||
|
||||
EXPECT_EQ(test_bridge.groups().remove(1), true);
|
||||
|
||||
EXPECT_EQ(test_bridge.groups().remove(1), false);
|
||||
}
|
||||
|
||||
TEST(Bridge, groupExists)
|
||||
{
|
||||
using namespace ::testing;
|
||||
std::shared_ptr<MockHttpHandler> handler = std::make_shared<MockHttpHandler>();
|
||||
nlohmann::json hue_bridge_state {{"groups",
|
||||
{{"1",
|
||||
{{"name", "Group 1"}, {"type", "LightGroup"}, {"lights", {"1", "2", "3"}},
|
||||
{"action",
|
||||
{{"on", true}, {"bri", 254}, {"ct", 366}, {"alert", "none"}, {"colormode", "ct"}, {"hue", 200},
|
||||
{"sat", 254}, {"effect", "none"}, {"xy", {0.f, 0.f}}}},
|
||||
{"state", {{"any_on", true}, {"all_on", true}}}}}}}};
|
||||
EXPECT_CALL(
|
||||
*handler, GETJson("/api/" + getBridgeUsername(), nlohmann::json::object(), getBridgeIp(), getBridgePort()))
|
||||
.Times(AtLeast(1))
|
||||
.WillRepeatedly(Return(hue_bridge_state));
|
||||
|
||||
Bridge test_bridge(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler);
|
||||
|
||||
test_bridge.refresh();
|
||||
|
||||
EXPECT_EQ(true, Const(test_bridge).groups().exists(1));
|
||||
EXPECT_EQ(false, Const(test_bridge).groups().exists(2));
|
||||
}
|
||||
|
||||
TEST(Bridge, getAllGroups)
|
||||
{
|
||||
using namespace ::testing;
|
||||
std::shared_ptr<MockHttpHandler> handler = std::make_shared<MockHttpHandler>();
|
||||
nlohmann::json hue_bridge_state {{"groups",
|
||||
{{"1",
|
||||
{{"name", "Group 1"}, {"type", "LightGroup"}, {"lights", {"1", "2", "3"}},
|
||||
{"action",
|
||||
{{"on", true}, {"bri", 254}, {"ct", 366}, {"alert", "none"}, {"colormode", "ct"}, {"hue", 200},
|
||||
{"sat", 254}, {"effect", "none"}, {"xy", {0.f, 0.f}}}},
|
||||
{"state", {{"any_on", true}, {"all_on", true}}}}}}}};
|
||||
|
||||
EXPECT_CALL(
|
||||
*handler, GETJson("/api/" + getBridgeUsername(), nlohmann::json::object(), getBridgeIp(), getBridgePort()))
|
||||
.Times(AtLeast(1))
|
||||
.WillRepeatedly(Return(hue_bridge_state));
|
||||
|
||||
Bridge test_bridge(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler);
|
||||
|
||||
std::vector<Group> test_groups = test_bridge.groups().getAll();
|
||||
ASSERT_EQ(1, test_groups.size());
|
||||
EXPECT_EQ(test_groups[0].getName(), "Group 1");
|
||||
EXPECT_EQ(test_groups[0].getType(), "LightGroup");
|
||||
}
|
||||
|
||||
TEST(Bridge, createGroup)
|
||||
{
|
||||
using namespace ::testing;
|
||||
std::shared_ptr<MockHttpHandler> handler = std::make_shared<MockHttpHandler>();
|
||||
EXPECT_CALL(
|
||||
*handler, GETJson("/api/" + getBridgeUsername(), nlohmann::json::object(), getBridgeIp(), getBridgePort()))
|
||||
.Times(AtLeast(1));
|
||||
Bridge test_bridge(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler);
|
||||
CreateGroup create = CreateGroup::Room({2, 3}, "Nice room", "LivingRoom");
|
||||
nlohmann::json request = create.getRequest();
|
||||
const int id = 4;
|
||||
nlohmann::json response = {{{"success", {{"id", std::to_string(id)}}}}};
|
||||
EXPECT_CALL(*handler, POSTJson("/api/" + getBridgeUsername() + "/groups", request, getBridgeIp(), getBridgePort()))
|
||||
.WillOnce(Return(response));
|
||||
EXPECT_EQ(id, test_bridge.groups().create(create));
|
||||
|
||||
response = {};
|
||||
EXPECT_CALL(*handler, POSTJson("/api/" + getBridgeUsername() + "/groups", request, getBridgeIp(), getBridgePort()))
|
||||
.WillOnce(Return(response));
|
||||
EXPECT_EQ(0, test_bridge.groups().create(create));
|
||||
}
|
||||
|
||||
#define IGNORE_EXCEPTIONS(statement) \
|
||||
try \
|
||||
{ \
|
||||
statement; \
|
||||
} \
|
||||
catch (...) \
|
||||
{ }
|
||||
|
||||
TEST(Bridge, instantiateResourceLists)
|
||||
{
|
||||
// Instantiate all methods on the resource lists, so that compile errors become visible
|
||||
using namespace ::testing;
|
||||
nlohmann::json bridgeState {{"lights", nlohmann::json::object()}, {"groups", nlohmann::json::object()},
|
||||
{"schedules", nlohmann::json::object()}, {"scenes", nlohmann::json::object()},
|
||||
{"sensors", nlohmann::json::object()}, {"rules", nlohmann::json::object()}};
|
||||
std::shared_ptr<MockHttpHandler> handler = std::make_shared<MockHttpHandler>();
|
||||
EXPECT_CALL(*handler, GETJson(_, _, getBridgeIp(), getBridgePort())).Times(AnyNumber());
|
||||
EXPECT_CALL(*handler, POSTJson(_, _, getBridgeIp(), getBridgePort())).Times(AnyNumber());
|
||||
EXPECT_CALL(*handler, DELETEJson(_, _, getBridgeIp(), getBridgePort())).Times(AnyNumber());
|
||||
EXPECT_CALL(
|
||||
*handler, GETJson("/api/" + getBridgeUsername(), nlohmann::json::object(), getBridgeIp(), getBridgePort()))
|
||||
.Times(AtLeast(1))
|
||||
.WillRepeatedly(Return(bridgeState));
|
||||
|
||||
Bridge bridge(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler);
|
||||
|
||||
IGNORE_EXCEPTIONS(bridge.lights().getAll());
|
||||
IGNORE_EXCEPTIONS(bridge.lights().get(1));
|
||||
IGNORE_EXCEPTIONS(bridge.lights().exists(1));
|
||||
IGNORE_EXCEPTIONS(bridge.lights().search());
|
||||
IGNORE_EXCEPTIONS(bridge.lights().getNewDevices());
|
||||
IGNORE_EXCEPTIONS(bridge.lights().remove(1));
|
||||
|
||||
IGNORE_EXCEPTIONS(bridge.groups().getAll());
|
||||
IGNORE_EXCEPTIONS(bridge.groups().get(1));
|
||||
IGNORE_EXCEPTIONS(bridge.groups().exists(1));
|
||||
IGNORE_EXCEPTIONS(bridge.groups().create(CreateGroup::Entertainment({}, "")));
|
||||
IGNORE_EXCEPTIONS(bridge.groups().remove(1));
|
||||
|
||||
IGNORE_EXCEPTIONS(bridge.schedules().getAll());
|
||||
IGNORE_EXCEPTIONS(bridge.schedules().get(1));
|
||||
IGNORE_EXCEPTIONS(bridge.schedules().exists(1));
|
||||
IGNORE_EXCEPTIONS(bridge.schedules().create(CreateSchedule()));
|
||||
IGNORE_EXCEPTIONS(bridge.schedules().remove(1));
|
||||
|
||||
IGNORE_EXCEPTIONS(bridge.scenes().getAll());
|
||||
IGNORE_EXCEPTIONS(bridge.scenes().get("1"));
|
||||
IGNORE_EXCEPTIONS(bridge.scenes().exists("1"));
|
||||
IGNORE_EXCEPTIONS(bridge.scenes().create(CreateScene()));
|
||||
IGNORE_EXCEPTIONS(bridge.scenes().remove("1"));
|
||||
|
||||
IGNORE_EXCEPTIONS(bridge.sensors().getAll());
|
||||
IGNORE_EXCEPTIONS(bridge.sensors().get(1));
|
||||
IGNORE_EXCEPTIONS(bridge.sensors().exists(1));
|
||||
IGNORE_EXCEPTIONS(bridge.sensors().create(CreateSensor("", "", "", "", "", "")));
|
||||
IGNORE_EXCEPTIONS(bridge.sensors().search());
|
||||
IGNORE_EXCEPTIONS(bridge.sensors().getNewDevices());
|
||||
IGNORE_EXCEPTIONS(bridge.sensors().remove(1));
|
||||
|
||||
IGNORE_EXCEPTIONS(bridge.rules().getAll());
|
||||
IGNORE_EXCEPTIONS(bridge.rules().get(1));
|
||||
IGNORE_EXCEPTIONS(bridge.rules().exists(1));
|
||||
IGNORE_EXCEPTIONS(bridge.rules().create(CreateRule({}, {})));
|
||||
IGNORE_EXCEPTIONS(bridge.rules().remove(1));
|
||||
}
|
||||
@@ -0,0 +1,195 @@
|
||||
/**
|
||||
\file test_BridgeConfig.cpp
|
||||
Copyright Notice\n
|
||||
Copyright (C) 2020 Jan Rogall - developer\n
|
||||
|
||||
This file is part of hueplusplus.
|
||||
|
||||
hueplusplus 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.
|
||||
|
||||
hueplusplus 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 hueplusplus. If not, see <http://www.gnu.org/licenses/>.
|
||||
**/
|
||||
|
||||
#include <hueplusplus/BridgeConfig.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "testhelper.h"
|
||||
|
||||
#include "mocks/mock_HttpHandler.h"
|
||||
|
||||
using namespace hueplusplus;
|
||||
using namespace testing;
|
||||
|
||||
TEST(BridgeConfig, refresh)
|
||||
{
|
||||
auto handler = std::make_shared<MockHttpHandler>();
|
||||
HueCommandAPI commands(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler);
|
||||
auto baseCache = std::make_shared<APICache>("", commands, std::chrono::steady_clock::duration::max(), nullptr);
|
||||
EXPECT_CALL(
|
||||
*handler, GETJson("/api/" + getBridgeUsername(), nlohmann::json::object(), getBridgeIp(), getBridgePort()))
|
||||
.WillOnce(Return(nlohmann::json::object()));
|
||||
baseCache->refresh();
|
||||
BridgeConfig config(baseCache, std::chrono::steady_clock::duration::max());
|
||||
|
||||
EXPECT_CALL(*handler,
|
||||
GETJson("/api/" + getBridgeUsername() + "/config", nlohmann::json::object(), getBridgeIp(), getBridgePort()))
|
||||
.WillOnce(Return(nlohmann::json::object()));
|
||||
config.refresh(true);
|
||||
}
|
||||
|
||||
TEST(BridgeConfig, getWhitelistedUsers)
|
||||
{
|
||||
const nlohmann::json state {{"config",
|
||||
{{"whitelist",
|
||||
{{"abcd",
|
||||
{{"name", "User A"}, {"last use date", "2020-04-01T10:00:04"},
|
||||
{"create date", "2020-01-01T12:00:00"}}},
|
||||
{"cdef",
|
||||
{{"name", "User B"}, {"last use date", "2020-03-05T14:00:00"},
|
||||
{"create date", "2020-02-01T02:03:40"}}}}}}}};
|
||||
auto handler = std::make_shared<MockHttpHandler>();
|
||||
HueCommandAPI commands(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler);
|
||||
auto baseCache = std::make_shared<APICache>("", commands, std::chrono::steady_clock::duration::max(), nullptr);
|
||||
EXPECT_CALL(
|
||||
*handler, GETJson("/api/" + getBridgeUsername(), nlohmann::json::object(), getBridgeIp(), getBridgePort()))
|
||||
.WillOnce(Return(state));
|
||||
baseCache->refresh();
|
||||
BridgeConfig config(baseCache, std::chrono::steady_clock::duration::max());
|
||||
|
||||
std::vector<WhitelistedUser> users = config.getWhitelistedUsers();
|
||||
EXPECT_THAT(users,
|
||||
UnorderedElementsAre(Truly([](const WhitelistedUser& u) { return u.key == "abcd" && u.name == "User A"; }),
|
||||
Truly([](const WhitelistedUser& u) { return u.key == "cdef" && u.name == "User B"; })));
|
||||
}
|
||||
|
||||
TEST(BridgeConfig, removeUser)
|
||||
{
|
||||
auto handler = std::make_shared<MockHttpHandler>();
|
||||
HueCommandAPI commands(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler);
|
||||
auto baseCache = std::make_shared<APICache>("", commands, std::chrono::steady_clock::duration::max(), nullptr);
|
||||
EXPECT_CALL(
|
||||
*handler, GETJson("/api/" + getBridgeUsername(), nlohmann::json::object(), getBridgeIp(), getBridgePort()))
|
||||
.WillOnce(Return(nlohmann::json::object()));
|
||||
baseCache->refresh();
|
||||
BridgeConfig config(baseCache, std::chrono::steady_clock::duration::max());
|
||||
|
||||
const std::string userKey = "abcd";
|
||||
EXPECT_CALL(*handler,
|
||||
DELETEJson("/api/" + getBridgeUsername() + "/config/whitelist/" + userKey, nlohmann::json::object(),
|
||||
getBridgeIp(), getBridgePort()))
|
||||
.WillOnce(Return(nlohmann::json {"/config/whitelist/" + userKey + " deleted"}));
|
||||
config.removeUser(userKey);
|
||||
}
|
||||
|
||||
TEST(BridgeConfig, getLinkButton)
|
||||
{
|
||||
const nlohmann::json state {{"config", {{"linkbutton", true}}}};
|
||||
auto handler = std::make_shared<MockHttpHandler>();
|
||||
HueCommandAPI commands(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler);
|
||||
auto baseCache = std::make_shared<APICache>("", commands, std::chrono::steady_clock::duration::max(), nullptr);
|
||||
EXPECT_CALL(
|
||||
*handler, GETJson("/api/" + getBridgeUsername(), nlohmann::json::object(), getBridgeIp(), getBridgePort()))
|
||||
.WillOnce(Return(state));
|
||||
baseCache->refresh();
|
||||
BridgeConfig config(baseCache, std::chrono::steady_clock::duration::max());
|
||||
|
||||
EXPECT_TRUE(config.getLinkButton());
|
||||
EXPECT_CALL(*handler,
|
||||
GETJson("/api/" + getBridgeUsername() + "/config", nlohmann::json::object(), getBridgeIp(), getBridgePort()))
|
||||
.WillOnce(Return(nlohmann::json {{"linkbutton", false}}));
|
||||
config.refresh(true);
|
||||
EXPECT_FALSE(config.getLinkButton());
|
||||
}
|
||||
|
||||
TEST(BridgeConfig, pressLinkButton)
|
||||
{
|
||||
auto handler = std::make_shared<MockHttpHandler>();
|
||||
HueCommandAPI commands(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler);
|
||||
auto baseCache = std::make_shared<APICache>("", commands, std::chrono::steady_clock::duration::max(), nullptr);
|
||||
EXPECT_CALL(
|
||||
*handler, GETJson("/api/" + getBridgeUsername(), nlohmann::json::object(), getBridgeIp(), getBridgePort()))
|
||||
.WillOnce(Return(nlohmann::json::object()));
|
||||
baseCache->refresh();
|
||||
BridgeConfig config(baseCache, std::chrono::steady_clock::duration::max());
|
||||
|
||||
EXPECT_CALL(*handler,
|
||||
PUTJson("/api/" + getBridgeUsername() + "/config", nlohmann::json {{"linkbutton", true}}, getBridgeIp(),
|
||||
getBridgePort()))
|
||||
.WillOnce(Return(nlohmann::json {{{"success", {{"/config/linkbutton", true}}}}}));
|
||||
config.pressLinkButton();
|
||||
}
|
||||
|
||||
TEST(BridgeConfig, touchLink)
|
||||
{
|
||||
auto handler = std::make_shared<MockHttpHandler>();
|
||||
HueCommandAPI commands(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler);
|
||||
auto baseCache = std::make_shared<APICache>("", commands, std::chrono::steady_clock::duration::max(), nullptr);
|
||||
EXPECT_CALL(
|
||||
*handler, GETJson("/api/" + getBridgeUsername(), nlohmann::json::object(), getBridgeIp(), getBridgePort()))
|
||||
.WillOnce(Return(nlohmann::json::object()));
|
||||
baseCache->refresh();
|
||||
BridgeConfig config(baseCache, std::chrono::steady_clock::duration::max());
|
||||
|
||||
EXPECT_CALL(*handler,
|
||||
PUTJson("/api/" + getBridgeUsername() + "/config", nlohmann::json {{"touchlink", true}}, getBridgeIp(),
|
||||
getBridgePort()))
|
||||
.WillOnce(Return(nlohmann::json {{{"success", {{"/config/touchlink", true}}}}}));
|
||||
config.touchLink();
|
||||
}
|
||||
|
||||
TEST(BridgeConfig, getMACAddress)
|
||||
{
|
||||
const nlohmann::json state {{"config", {{"mac", getBridgeMac()}}}};
|
||||
auto handler = std::make_shared<MockHttpHandler>();
|
||||
HueCommandAPI commands(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler);
|
||||
auto baseCache = std::make_shared<APICache>("", commands, std::chrono::steady_clock::duration::max(), nullptr);
|
||||
EXPECT_CALL(
|
||||
*handler, GETJson("/api/" + getBridgeUsername(), nlohmann::json::object(), getBridgeIp(), getBridgePort()))
|
||||
.WillOnce(Return(state));
|
||||
baseCache->refresh();
|
||||
BridgeConfig config(baseCache, std::chrono::steady_clock::duration::max());
|
||||
|
||||
EXPECT_EQ(getBridgeMac(), config.getMACAddress());
|
||||
}
|
||||
|
||||
TEST(BridgeConfig, getUTCTime)
|
||||
{
|
||||
const std::string utc = "2020-06-01T10:00:00";
|
||||
const nlohmann::json state {{"config", {{"UTC", utc}}}};
|
||||
auto handler = std::make_shared<MockHttpHandler>();
|
||||
HueCommandAPI commands(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler);
|
||||
auto baseCache = std::make_shared<APICache>("", commands, std::chrono::steady_clock::duration::max(), nullptr);
|
||||
EXPECT_CALL(
|
||||
*handler, GETJson("/api/" + getBridgeUsername(), nlohmann::json::object(), getBridgeIp(), getBridgePort()))
|
||||
.WillOnce(Return(state));
|
||||
baseCache->refresh();
|
||||
BridgeConfig config(baseCache, std::chrono::steady_clock::duration::max());
|
||||
|
||||
EXPECT_EQ(time::AbsoluteTime::parseUTC(utc).getBaseTime(), config.getUTCTime().getBaseTime());
|
||||
}
|
||||
|
||||
TEST(BridgeConfig, getTimezone)
|
||||
{
|
||||
const std::string timezone = "ab";
|
||||
const nlohmann::json state {{"config", {{"timezone", timezone}}}};
|
||||
auto handler = std::make_shared<MockHttpHandler>();
|
||||
HueCommandAPI commands(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler);
|
||||
auto baseCache = std::make_shared<APICache>("", commands, std::chrono::steady_clock::duration::max(), nullptr);
|
||||
EXPECT_CALL(
|
||||
*handler, GETJson("/api/" + getBridgeUsername(), nlohmann::json::object(), getBridgeIp(), getBridgePort()))
|
||||
.WillOnce(Return(state));
|
||||
baseCache->refresh();
|
||||
BridgeConfig config(baseCache, std::chrono::steady_clock::duration::max());
|
||||
|
||||
EXPECT_EQ(timezone, config.getTimezone());
|
||||
}
|
||||
@@ -0,0 +1,238 @@
|
||||
/**
|
||||
\file test_ColorUnits.cpp
|
||||
Copyright Notice\n
|
||||
Copyright (C) 2020 Jan Rogall - developer\n
|
||||
|
||||
This file is part of hueplusplus.
|
||||
|
||||
hueplusplus 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.
|
||||
|
||||
hueplusplus 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 hueplusplus. If not, see <http://www.gnu.org/licenses/>.
|
||||
**/
|
||||
|
||||
#include <random>
|
||||
|
||||
#include <hueplusplus/ColorUnits.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
using namespace hueplusplus;
|
||||
|
||||
TEST(ColorGamut, contains)
|
||||
{
|
||||
ColorGamut gamut = gamut::maxGamut;
|
||||
|
||||
EXPECT_TRUE(gamut.contains({0.f, 0.5f}));
|
||||
EXPECT_TRUE(gamut.contains({1.f, 0.f}));
|
||||
EXPECT_TRUE(gamut.contains({0.5f, 0.5f}));
|
||||
EXPECT_TRUE(gamut.contains({0.f, 1.f}));
|
||||
EXPECT_TRUE(gamut.contains({0.f, 0.f}));
|
||||
EXPECT_FALSE(gamut.contains({1.f, 1.f}));
|
||||
EXPECT_FALSE(gamut.contains({-1.f, 1.f}));
|
||||
}
|
||||
|
||||
TEST(ColorGamut, corrected)
|
||||
{
|
||||
ColorGamut gamut = gamut::maxGamut;
|
||||
|
||||
{
|
||||
const XY xy {0.f, 0.5f};
|
||||
const XY result = gamut.corrected(xy);
|
||||
EXPECT_FLOAT_EQ(xy.x, result.x);
|
||||
EXPECT_FLOAT_EQ(xy.y, result.y);
|
||||
}
|
||||
{
|
||||
const XY xy {0.f, 1.f};
|
||||
const XY result = gamut.corrected(xy);
|
||||
EXPECT_FLOAT_EQ(xy.x, result.x);
|
||||
EXPECT_FLOAT_EQ(xy.y, result.y);
|
||||
}
|
||||
{
|
||||
const XY xy {1.f, 1.f};
|
||||
const XY result = gamut.corrected(xy);
|
||||
EXPECT_FLOAT_EQ(0.5f, result.x);
|
||||
EXPECT_FLOAT_EQ(0.5f, result.y);
|
||||
}
|
||||
{
|
||||
const XY xy {1.f, -1.f};
|
||||
const XY result = gamut.corrected(xy);
|
||||
EXPECT_FLOAT_EQ(1.f, result.x);
|
||||
EXPECT_FLOAT_EQ(0.f, result.y);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(RGB, toXY)
|
||||
{
|
||||
{
|
||||
const RGB red {255, 0, 0};
|
||||
XYBrightness xy = red.toXY();
|
||||
EXPECT_FLOAT_EQ(xy.xy.x, 0.70060623f);
|
||||
EXPECT_FLOAT_EQ(xy.xy.y, 0.299301f);
|
||||
EXPECT_FLOAT_EQ(xy.brightness, 1.f);
|
||||
}
|
||||
{
|
||||
const RGB red {255, 0, 0};
|
||||
XYBrightness xy = red.toXY(gamut::gamutC);
|
||||
EXPECT_FLOAT_EQ(xy.xy.x, 0.69557756f);
|
||||
EXPECT_FLOAT_EQ(xy.xy.y, 0.30972576f);
|
||||
EXPECT_FLOAT_EQ(xy.brightness, 1.f);
|
||||
}
|
||||
{
|
||||
const RGB white {255, 255, 255};
|
||||
XYBrightness xy = white.toXY();
|
||||
EXPECT_FLOAT_EQ(xy.xy.x, 0.32272673f);
|
||||
EXPECT_FLOAT_EQ(xy.xy.y, 0.32902291f);
|
||||
EXPECT_FLOAT_EQ(xy.brightness, 1.f);
|
||||
}
|
||||
{
|
||||
const RGB white {255, 255, 255};
|
||||
XYBrightness xy = white.toXY(gamut::gamutA);
|
||||
EXPECT_FLOAT_EQ(xy.xy.x, 0.32272673f);
|
||||
EXPECT_FLOAT_EQ(xy.xy.y, 0.32902291f);
|
||||
EXPECT_FLOAT_EQ(xy.brightness, 1.f);
|
||||
}
|
||||
{
|
||||
const RGB white {255, 255, 255};
|
||||
XYBrightness xy = white.toXY(gamut::gamutB);
|
||||
EXPECT_FLOAT_EQ(xy.xy.x, 0.32272673f);
|
||||
EXPECT_FLOAT_EQ(xy.xy.y, 0.32902291f);
|
||||
EXPECT_FLOAT_EQ(xy.brightness, 1.f);
|
||||
}
|
||||
{
|
||||
const RGB black {0, 0, 0};
|
||||
XYBrightness xy = black.toXY(gamut::maxGamut);
|
||||
EXPECT_FLOAT_EQ(xy.xy.x, 0.32272673f);
|
||||
EXPECT_FLOAT_EQ(xy.xy.y, 0.32902291f);
|
||||
EXPECT_FLOAT_EQ(xy.brightness, 0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(RGB, toHueSaturation)
|
||||
{
|
||||
{
|
||||
const RGB red {255, 0, 0};
|
||||
HueSaturation hs = red.toHueSaturation();
|
||||
EXPECT_EQ(0, hs.hue);
|
||||
EXPECT_EQ(254, hs.saturation);
|
||||
}
|
||||
{
|
||||
const RGB darkGreen {64, 128, 128};
|
||||
HueSaturation hs = darkGreen.toHueSaturation();
|
||||
EXPECT_EQ(38250, hs.hue);
|
||||
EXPECT_EQ(127, hs.saturation);
|
||||
}
|
||||
{
|
||||
const RGB white {255, 255, 255};
|
||||
HueSaturation hs = white.toHueSaturation();
|
||||
EXPECT_EQ(0, hs.hue);
|
||||
EXPECT_EQ(0, hs.saturation);
|
||||
}
|
||||
{
|
||||
const RGB black {0, 0, 0};
|
||||
HueSaturation hs = black.toHueSaturation();
|
||||
EXPECT_EQ(0, hs.hue);
|
||||
EXPECT_EQ(0, hs.saturation);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(RGB, fromXY)
|
||||
{
|
||||
{
|
||||
const XYBrightness xyRed {{0.70060623f, 0.299301f}, 1.f};
|
||||
const RGB red = RGB::fromXY(xyRed);
|
||||
EXPECT_EQ(255, red.r);
|
||||
EXPECT_EQ(0, red.g);
|
||||
EXPECT_EQ(0, red.b);
|
||||
const XYBrightness reversed = red.toXY();
|
||||
EXPECT_FLOAT_EQ(xyRed.xy.x, reversed.xy.x);
|
||||
EXPECT_FLOAT_EQ(xyRed.xy.y, reversed.xy.y);
|
||||
EXPECT_FLOAT_EQ(xyRed.brightness, reversed.brightness);
|
||||
}
|
||||
{
|
||||
const XYBrightness xyWhite {{0.32272673f, 0.32902291f}, 1.f};
|
||||
const RGB white = RGB::fromXY(xyWhite);
|
||||
EXPECT_EQ(255, white.r);
|
||||
EXPECT_EQ(255, white.g);
|
||||
EXPECT_EQ(255, white.b);
|
||||
const XYBrightness reversed = white.toXY();
|
||||
EXPECT_FLOAT_EQ(xyWhite.xy.x, reversed.xy.x);
|
||||
EXPECT_FLOAT_EQ(xyWhite.xy.y, reversed.xy.y);
|
||||
EXPECT_FLOAT_EQ(xyWhite.brightness, reversed.brightness);
|
||||
}
|
||||
{
|
||||
const XYBrightness xyRed {{0.70060623f, 0.299301f}, 1.f};
|
||||
const RGB red = RGB::fromXY(xyRed, gamut::gamutB);
|
||||
const RGB red2 = RGB::fromXY({gamut::gamutB.corrected(xyRed.xy), xyRed.brightness});
|
||||
EXPECT_EQ(red2.r, red.r);
|
||||
EXPECT_EQ(red2.g, red.g);
|
||||
EXPECT_EQ(red2.b, red.b);
|
||||
}
|
||||
|
||||
// Statistical tests of conversion accuracy
|
||||
// Fixed seed so the tests dont fail randomly
|
||||
std::mt19937 rng {12374682};
|
||||
std::uniform_int_distribution<int> dist(0, 255);
|
||||
|
||||
uint64_t N = 1000;
|
||||
|
||||
uint64_t totalDiffR = 0;
|
||||
uint64_t totalDiffG = 0;
|
||||
uint64_t totalDiffB = 0;
|
||||
int maxDiffR = 0;
|
||||
int maxDiffG = 0;
|
||||
int maxDiffB = 0;
|
||||
for (int i = 0; i < N; ++i)
|
||||
{
|
||||
const RGB rgb {
|
||||
static_cast<uint8_t>(dist(rng)), static_cast<uint8_t>(dist(rng)), static_cast<uint8_t>(dist(rng))};
|
||||
const XYBrightness xy = rgb.toXY();
|
||||
const RGB back = RGB::fromXY(xy);
|
||||
int diffR = (rgb.r - back.r) * (rgb.r - back.r);
|
||||
int diffG = (rgb.g - back.g) * (rgb.g - back.g);
|
||||
int diffB = (rgb.b - back.b) * (rgb.b - back.b);
|
||||
totalDiffR += diffR;
|
||||
totalDiffG += diffG;
|
||||
totalDiffB += diffB;
|
||||
maxDiffR = std::max(diffR, maxDiffR);
|
||||
maxDiffG = std::max(diffG, maxDiffG);
|
||||
maxDiffB = std::max(diffB, maxDiffB);
|
||||
}
|
||||
float varR = (float)totalDiffR / N;
|
||||
float varG = (float)totalDiffG / N;
|
||||
float varB = (float)totalDiffB / N;
|
||||
EXPECT_LT(varR, 5.f);
|
||||
EXPECT_LT(varG, 5.f);
|
||||
EXPECT_LT(varB, 4.f);
|
||||
EXPECT_LE(maxDiffR, 81);
|
||||
EXPECT_LE(maxDiffG, 81);
|
||||
EXPECT_LE(maxDiffB, 64);
|
||||
}
|
||||
|
||||
TEST(ColorUnits, kelvinToMired)
|
||||
{
|
||||
EXPECT_EQ(10000, kelvinToMired(100));
|
||||
EXPECT_EQ(500, kelvinToMired(2000));
|
||||
EXPECT_EQ(303, kelvinToMired(3300));
|
||||
EXPECT_EQ(250, kelvinToMired(4000));
|
||||
EXPECT_EQ(200, kelvinToMired(5000));
|
||||
EXPECT_EQ(167, kelvinToMired(6000));
|
||||
}
|
||||
|
||||
TEST(ColorUnits, miredToKelvin)
|
||||
{
|
||||
EXPECT_EQ(100, miredToKelvin(10000));
|
||||
EXPECT_EQ(2000, miredToKelvin(500));
|
||||
EXPECT_EQ(3300, miredToKelvin(303));
|
||||
EXPECT_EQ(4000, miredToKelvin(250));
|
||||
EXPECT_EQ(5000, miredToKelvin(200));
|
||||
EXPECT_EQ(6024, miredToKelvin(166)); // 6000 kelvin should be 166 mired, but is rounded
|
||||
}
|
||||
@@ -0,0 +1,200 @@
|
||||
/**
|
||||
\file test_ExtendedColorHueStrategy.cpp
|
||||
Copyright Notice\n
|
||||
Copyright (C) 2017 Jan Rogall - developer\n
|
||||
Copyright (C) 2017 Moritz Wirger - developer\n
|
||||
|
||||
This file is part of hueplusplus.
|
||||
|
||||
hueplusplus 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.
|
||||
|
||||
hueplusplus 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 hueplusplus. If not, see <http://www.gnu.org/licenses/>.
|
||||
**/
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include <gmock/gmock.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "TestTransaction.h"
|
||||
#include "testhelper.h"
|
||||
|
||||
#include "hueplusplus/ExtendedColorHueStrategy.h"
|
||||
#include <nlohmann/json.hpp>
|
||||
#include "mocks/mock_HttpHandler.h"
|
||||
#include "mocks/mock_Light.h"
|
||||
|
||||
using namespace hueplusplus;
|
||||
|
||||
TEST(ExtendedColorHueStrategy, alertHueSaturation)
|
||||
{
|
||||
using namespace ::testing;
|
||||
std::shared_ptr<MockHttpHandler> handler(std::make_shared<MockHttpHandler>());
|
||||
EXPECT_CALL(
|
||||
*handler, GETJson("/api/" + getBridgeUsername() + "/lights/1", nlohmann::json::object(), getBridgeIp(), 80))
|
||||
.Times(AtLeast(1))
|
||||
.WillRepeatedly(Return(nlohmann::json::object()));
|
||||
MockLight light(handler);
|
||||
|
||||
const HueSaturation hueSat {200, 100};
|
||||
// Needs to update the state so transactions are correctly trimmed
|
||||
const auto setColorLambda = [&](const HueSaturation& hueSat, int transition) {
|
||||
light.getState()["state"]["colormode"] = "hs";
|
||||
light.getState()["state"]["on"] = true;
|
||||
light.getState()["state"]["hue"] = hueSat.hue;
|
||||
light.getState()["state"]["sat"] = hueSat.saturation;
|
||||
return true;
|
||||
};
|
||||
// Invalid state
|
||||
{
|
||||
light.getState()["state"]["colormode"] = "invalid";
|
||||
light.getState()["state"]["on"] = false;
|
||||
EXPECT_FALSE(ExtendedColorHueStrategy().alertHueSaturation(hueSat, light));
|
||||
}
|
||||
// Colormode not ct is forwarded to SimpleColorHueStrategy
|
||||
{
|
||||
const nlohmann::json state = {{"colormode", "hs"}, {"on", true}, {"xy", {0.1, 0.1}}, {"hue", 300}, {"sat", 100},
|
||||
{"bri", 254}, {"ct", 300}};
|
||||
light.getState()["state"] = state;
|
||||
EXPECT_CALL(Const(light), getColorHueSaturation())
|
||||
.Times(AnyNumber())
|
||||
.WillRepeatedly(Return(HueSaturation {300, 100}));
|
||||
TestTransaction reverseTransaction = light.transaction().setColorHue(300).setTransition(1);
|
||||
InSequence s;
|
||||
EXPECT_CALL(light, setColorHueSaturation(hueSat, 1)).WillOnce(Invoke(setColorLambda));
|
||||
EXPECT_CALL(light, alert()).WillOnce(Return(true));
|
||||
reverseTransaction.expectSuccessfulPut(handler, Exactly(1));
|
||||
EXPECT_TRUE(ExtendedColorHueStrategy().alertHueSaturation(hueSat, light));
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
}
|
||||
|
||||
// Colormode ct
|
||||
{
|
||||
const nlohmann::json state
|
||||
= {{"colormode", "ct"}, {"on", true}, {"xy", {0.1, 0.1}}, {"sat", 100}, {"bri", 254}, {"ct", 300}};
|
||||
light.getState()["state"] = state;
|
||||
TestTransaction reverseTransaction = light.transaction().setColorTemperature(300).setTransition(1);
|
||||
|
||||
InSequence s;
|
||||
EXPECT_CALL(light, setColorHueSaturation(hueSat, 1)).WillOnce(Invoke(setColorLambda));
|
||||
EXPECT_CALL(light, alert()).WillOnce(Return(false));
|
||||
EXPECT_FALSE(ExtendedColorHueStrategy().alertHueSaturation(hueSat, light));
|
||||
light.getState()["state"] = state;
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
|
||||
EXPECT_CALL(light, setColorHueSaturation(hueSat, 1)).WillOnce(Invoke(setColorLambda));
|
||||
EXPECT_CALL(light, alert()).WillOnce(Return(true));
|
||||
reverseTransaction.expectSuccessfulPut(handler, Exactly(1));
|
||||
EXPECT_TRUE(ExtendedColorHueStrategy().alertHueSaturation(hueSat, light));
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
}
|
||||
|
||||
// Colormode ct, off
|
||||
{
|
||||
const nlohmann::json state
|
||||
= {{"colormode", "ct"}, {"on", false}, {"xy", {0., 1.}}, {"sat", 100}, {"bri", 254}, {"ct", 300}};
|
||||
light.getState()["state"] = state;
|
||||
|
||||
TestTransaction reverseTransaction = light.transaction().setColorTemperature(300).setOn(false).setTransition(1);
|
||||
InSequence s;
|
||||
EXPECT_CALL(light, setColorHueSaturation(hueSat, 1)).WillOnce(Invoke(setColorLambda));
|
||||
EXPECT_CALL(light, alert()).WillOnce(Return(true));
|
||||
reverseTransaction.expectSuccessfulPut(handler, Exactly(1));
|
||||
EXPECT_TRUE(ExtendedColorHueStrategy().alertHueSaturation(hueSat, light));
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(ExtendedColorHueStrategy, alertXY)
|
||||
{
|
||||
using namespace ::testing;
|
||||
std::shared_ptr<MockHttpHandler> handler(std::make_shared<MockHttpHandler>());
|
||||
EXPECT_CALL(
|
||||
*handler, GETJson("/api/" + getBridgeUsername() + "/lights/1", nlohmann::json::object(), getBridgeIp(), 80))
|
||||
.Times(AtLeast(1))
|
||||
.WillRepeatedly(Return(nlohmann::json::object()));
|
||||
MockLight light(handler);
|
||||
|
||||
const XYBrightness xy {{0.1f, 0.1f}, 1.f};
|
||||
// Needs to update the state so transactions are correctly trimmed
|
||||
const auto setColorLambda = [&](const XYBrightness& xy, int transition) {
|
||||
light.getState()["state"]["colormode"] = "xy";
|
||||
light.getState()["state"]["on"] = true;
|
||||
light.getState()["state"]["xy"] = {xy.xy.x, xy.xy.y};
|
||||
light.getState()["state"]["bri"] = static_cast<int>(std::round(xy.brightness * 254.f));
|
||||
return true;
|
||||
};
|
||||
// Invalid colormode
|
||||
{
|
||||
light.getState()["state"]["colormode"] = "invalid";
|
||||
light.getState()["state"]["on"] = false;
|
||||
EXPECT_FALSE(ExtendedColorHueStrategy().alertXY({{0.1f, 0.1f}, 1.f}, light));
|
||||
}
|
||||
// Colormode not ct is forwarded to SimpleColorHueStrategy
|
||||
{
|
||||
const nlohmann::json state = {{"colormode", "hs"}, {"on", true}, {"xy", {0.1, 0.1}}, {"hue", 200}, {"sat", 100},
|
||||
{"bri", 254}, {"ct", 300}};
|
||||
light.getState()["state"] = state;
|
||||
EXPECT_CALL(Const(light), getBrightness()).Times(AnyNumber()).WillRepeatedly(Return(254));
|
||||
HueSaturation hueSat {200, 100};
|
||||
EXPECT_CALL(Const(light), getColorHueSaturation()).Times(AnyNumber()).WillRepeatedly(Return(hueSat));
|
||||
|
||||
TestTransaction reverseTransaction = light.transaction().setColor(hueSat).setTransition(1);
|
||||
|
||||
InSequence s;
|
||||
EXPECT_CALL(light, setColorXY(xy, 1)).WillOnce(Invoke(setColorLambda));
|
||||
EXPECT_CALL(light, alert()).WillOnce(Return(true));
|
||||
reverseTransaction.expectSuccessfulPut(handler, Exactly(1));
|
||||
EXPECT_TRUE(SimpleColorHueStrategy().alertXY(xy, light));
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
}
|
||||
|
||||
// Colormode ct
|
||||
{
|
||||
const nlohmann::json state
|
||||
= { {"colormode", "ct"}, {"on", true}, {"xy", {0.1, 0.1}}, {"sat", 100}, {"bri", 128}, {"ct", 300} };
|
||||
light.getState()["state"] = state;
|
||||
EXPECT_CALL(Const(light), getBrightness()).Times(AnyNumber()).WillRepeatedly(Return(128));
|
||||
|
||||
TestTransaction reverseTransaction = light.transaction().setColorTemperature(300).setBrightness(128).setTransition(1);
|
||||
|
||||
InSequence s;
|
||||
EXPECT_CALL(light, setColorXY(xy, 1)).WillOnce(Invoke(setColorLambda));
|
||||
EXPECT_CALL(light, alert()).WillOnce(Return(false));
|
||||
EXPECT_FALSE(ExtendedColorHueStrategy().alertXY(xy, light));
|
||||
light.getState()["state"] = state;
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
|
||||
EXPECT_CALL(light, setColorXY(xy, 1)).WillOnce(Invoke(setColorLambda));
|
||||
EXPECT_CALL(light, alert()).WillOnce(Return(true));
|
||||
reverseTransaction.expectSuccessfulPut(handler, Exactly(1));
|
||||
EXPECT_TRUE(ExtendedColorHueStrategy().alertXY(xy, light));
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
}
|
||||
|
||||
// Colormode ct, off
|
||||
{
|
||||
const nlohmann::json state
|
||||
= { {"colormode", "ct"}, {"on", false}, {"xy", {0., 1.}}, {"sat", 100}, {"bri", 254}, {"ct", 300} };
|
||||
light.getState()["state"] = state;
|
||||
EXPECT_CALL(Const(light), getBrightness()).Times(AnyNumber()).WillRepeatedly(Return(254));
|
||||
|
||||
TestTransaction reverseTransaction = light.transaction().setColorTemperature(300).setOn(false).setTransition(1);
|
||||
InSequence s;
|
||||
EXPECT_CALL(light, setColorXY(xy, 1)).WillOnce(Invoke(setColorLambda));
|
||||
EXPECT_CALL(light, alert()).WillOnce(Return(true));
|
||||
reverseTransaction.expectSuccessfulPut(handler, Exactly(1));
|
||||
EXPECT_TRUE(ExtendedColorHueStrategy().alertXY(xy, light));
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
}
|
||||
}
|
||||
+122
@@ -0,0 +1,122 @@
|
||||
/**
|
||||
\file test_ExtendedColorTemperatureStrategy.cpp
|
||||
Copyright Notice\n
|
||||
Copyright (C) 2017 Jan Rogall - developer\n
|
||||
Copyright (C) 2017 Moritz Wirger - developer\n
|
||||
|
||||
This file is part of hueplusplus.
|
||||
|
||||
hueplusplus 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.
|
||||
|
||||
hueplusplus 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 hueplusplus. If not, see <http://www.gnu.org/licenses/>.
|
||||
**/
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include <gmock/gmock.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "TestTransaction.h"
|
||||
#include "testhelper.h"
|
||||
|
||||
#include "hueplusplus/ExtendedColorTemperatureStrategy.h"
|
||||
#include <nlohmann/json.hpp>
|
||||
#include "mocks/mock_HttpHandler.h"
|
||||
#include "mocks/mock_Light.h"
|
||||
|
||||
using namespace hueplusplus;
|
||||
|
||||
TEST(ExtendedColorTemperatureStrategy, alertTemperature)
|
||||
{
|
||||
using namespace ::testing;
|
||||
std::shared_ptr<MockHttpHandler> handler(std::make_shared<MockHttpHandler>());
|
||||
EXPECT_CALL(
|
||||
*handler, GETJson("/api/" + getBridgeUsername() + "/lights/1", nlohmann::json::object(), getBridgeIp(), 80))
|
||||
.Times(AtLeast(1))
|
||||
.WillRepeatedly(Return(nlohmann::json::object()));
|
||||
MockLight light(handler);
|
||||
|
||||
const auto setCTLambda = [&](unsigned int ct, int transition) {
|
||||
light.getState()["state"]["colormode"] = "ct";
|
||||
light.getState()["state"]["on"] = true;
|
||||
light.getState()["state"]["ct"] = ct;
|
||||
return true;
|
||||
};
|
||||
|
||||
// Invalid colormode
|
||||
{
|
||||
light.getState()["state"]["colormode"] = "invalid";
|
||||
light.getState()["state"]["on"] = false;
|
||||
EXPECT_EQ(false, ExtendedColorTemperatureStrategy().alertTemperature(400, light));
|
||||
}
|
||||
// Colormode ct forwarded to SimpleColorTemperatureStrategy
|
||||
{
|
||||
const nlohmann::json state = {{"colormode", "ct"}, {"on", true}, {"ct", 200}, {"xy", {0.1, 0.1}}, {"hue", 300},
|
||||
{"sat", 100}, {"bri", 254}};
|
||||
light.getState()["state"] = state;
|
||||
TestTransaction reverseTransaction = light.transaction().setColorTemperature(200).setTransition(1);
|
||||
|
||||
light.getState()["state"] = state;
|
||||
EXPECT_CALL(light, setColorTemperature(400, 1)).WillOnce(Invoke(setCTLambda));
|
||||
EXPECT_CALL(light, alert()).WillOnce(Return(true));
|
||||
reverseTransaction.expectSuccessfulPut(handler, Exactly(1));
|
||||
EXPECT_TRUE(ExtendedColorTemperatureStrategy().alertTemperature(400, light));
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
}
|
||||
// Colormode xy
|
||||
{
|
||||
const nlohmann::json state = {{"colormode", "xy"}, {"on", true}, {"ct", 200}, {"xy", {0.1, 0.1}}, {"hue", 300},
|
||||
{"sat", 100}, {"bri", 254}};
|
||||
light.getState()["state"] = state;
|
||||
EXPECT_CALL(Const(light), getColorXY()).Times(AnyNumber()).WillRepeatedly(Return(XYBrightness{ {0.1f,0.1f},1.f }));
|
||||
TestTransaction reverseTransaction = light.transaction().setColor(XY{ 0.1f,0.1f }).setTransition(1);
|
||||
|
||||
EXPECT_CALL(light, setColorTemperature(400, 1)).WillOnce(Return(false));
|
||||
EXPECT_FALSE(ExtendedColorTemperatureStrategy().alertTemperature(400, light));
|
||||
|
||||
InSequence s;
|
||||
EXPECT_CALL(light, setColorTemperature(400, 1)).WillOnce(Invoke(setCTLambda));
|
||||
EXPECT_CALL(light, alert()).WillOnce(Return(false));
|
||||
EXPECT_FALSE(ExtendedColorTemperatureStrategy().alertTemperature(400, light));
|
||||
|
||||
light.getState()["state"] = state;
|
||||
EXPECT_CALL(light, setColorTemperature(400, 1)).WillOnce(Invoke(setCTLambda));
|
||||
EXPECT_CALL(light, alert()).WillOnce(Return(true));
|
||||
reverseTransaction.expectSuccessfulPut(handler, Exactly(1));
|
||||
EXPECT_TRUE(ExtendedColorTemperatureStrategy().alertTemperature(400, light));
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
}
|
||||
// Colormode hs
|
||||
{
|
||||
const nlohmann::json state = { {"colormode", "hs"}, {"on", true}, {"ct", 200}, {"xy", {0.1, 0.1}}, {"hue", 300},
|
||||
{"sat", 100}, {"bri", 254} };
|
||||
light.getState()["state"] = state;
|
||||
EXPECT_CALL(Const(light), getColorHueSaturation()).Times(AnyNumber()).WillRepeatedly(Return(HueSaturation{ 300,200 }));
|
||||
TestTransaction reverseTransaction = light.transaction().setColor(HueSaturation{ 300,200 }).setTransition(1);
|
||||
|
||||
EXPECT_CALL(light, setColorTemperature(400, 1)).WillOnce(Return(false));
|
||||
EXPECT_FALSE(ExtendedColorTemperatureStrategy().alertTemperature(400, light));
|
||||
|
||||
InSequence s;
|
||||
EXPECT_CALL(light, setColorTemperature(400, 1)).WillOnce(Invoke(setCTLambda));
|
||||
EXPECT_CALL(light, alert()).WillOnce(Return(false));
|
||||
EXPECT_FALSE(ExtendedColorTemperatureStrategy().alertTemperature(400, light));
|
||||
|
||||
light.getState()["state"] = state;
|
||||
EXPECT_CALL(light, setColorTemperature(400, 1)).WillOnce(Invoke(setCTLambda));
|
||||
EXPECT_CALL(light, alert()).WillOnce(Return(true));
|
||||
reverseTransaction.expectSuccessfulPut(handler, Exactly(1));
|
||||
EXPECT_TRUE(ExtendedColorTemperatureStrategy().alertTemperature(400, light));
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
}
|
||||
}
|
||||
+301
@@ -0,0 +1,301 @@
|
||||
/**
|
||||
\file test_Group.cpp
|
||||
Copyright Notice\n
|
||||
Copyright (C) 2020 Jan Rogall - developer\n
|
||||
Copyright (C) 2020 Moritz Wirger - developer\n
|
||||
|
||||
This file is part of hueplusplus.
|
||||
|
||||
hueplusplus 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.
|
||||
|
||||
hueplusplus 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 hueplusplus. If not, see <http://www.gnu.org/licenses/>.
|
||||
**/
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "testhelper.h"
|
||||
|
||||
#include "hueplusplus/Group.h"
|
||||
#include "mocks/mock_HttpHandler.h"
|
||||
|
||||
using namespace hueplusplus;
|
||||
using namespace testing;
|
||||
|
||||
class GroupTest : public Test
|
||||
{
|
||||
protected:
|
||||
const std::string groupName = "Group 1";
|
||||
const std::string type = "Room";
|
||||
const std::string roomType = "Bedroom";
|
||||
const bool on = true;
|
||||
const int bri = 254;
|
||||
const int hue = 10000;
|
||||
const int sat = 254;
|
||||
const std::string effect = "none";
|
||||
const float x = 0.5f;
|
||||
const float y = 0.6f;
|
||||
const int ct = 250;
|
||||
const std::string alert = "none";
|
||||
const std::string colormode = "ct";
|
||||
const bool any_on = true;
|
||||
const bool all_on = false;
|
||||
|
||||
std::shared_ptr<MockHttpHandler> handler;
|
||||
HueCommandAPI commands;
|
||||
nlohmann::json groupState;
|
||||
|
||||
protected:
|
||||
GroupTest()
|
||||
: handler(std::make_shared<MockHttpHandler>()),
|
||||
commands(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler),
|
||||
groupState({{"name", groupName}, {"type", type}, {"class", roomType}, {"lights", {"1", "2", "4"}},
|
||||
{"action",
|
||||
{{"on", on}, {"bri", bri}, {"hue", hue}, {"sat", sat}, {"effect", effect},
|
||||
{"xy", nlohmann::json::array({x, y})}, {"ct", ct}, {"alert", alert}, {"colormode", colormode}}},
|
||||
{"state", {{"any_on", any_on}, {"all_on", all_on}}}})
|
||||
{}
|
||||
|
||||
void expectGetState(int id)
|
||||
{
|
||||
EXPECT_CALL(*handler,
|
||||
GETJson("/api/" + getBridgeUsername() + "/groups/" + std::to_string(id), nlohmann::json::object(),
|
||||
getBridgeIp(), getBridgePort()))
|
||||
.WillOnce(Return(groupState));
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(GroupTest, Construtor)
|
||||
{
|
||||
{
|
||||
const int id = 12;
|
||||
expectGetState(id);
|
||||
Group group(id, commands, std::chrono::seconds(0), nullptr);
|
||||
EXPECT_EQ(id, group.getId());
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
}
|
||||
{
|
||||
const int id = 0;
|
||||
expectGetState(id);
|
||||
Group group(id, commands, std::chrono::seconds(0), nullptr);
|
||||
EXPECT_EQ(id, group.getId());
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(GroupTest, getName)
|
||||
{
|
||||
const int id = 1;
|
||||
expectGetState(id);
|
||||
Group group(id, commands, std::chrono::seconds(0), nullptr);
|
||||
EXPECT_EQ(groupName, Const(group).getName());
|
||||
}
|
||||
|
||||
TEST_F(GroupTest, getType)
|
||||
{
|
||||
const int id = 1;
|
||||
expectGetState(id);
|
||||
Group group(id, commands, std::chrono::seconds(0), nullptr);
|
||||
EXPECT_EQ(type, Const(group).getType());
|
||||
}
|
||||
|
||||
TEST_F(GroupTest, getLightIds)
|
||||
{
|
||||
const int id = 1;
|
||||
expectGetState(id);
|
||||
Group group(id, commands, std::chrono::seconds(0), nullptr);
|
||||
EXPECT_EQ(std::vector<int>({1, 2, 4}), Const(group).getLightIds());
|
||||
}
|
||||
|
||||
TEST_F(GroupTest, getRoomType)
|
||||
{
|
||||
const int id = 1;
|
||||
expectGetState(id);
|
||||
Group group(id, commands, std::chrono::seconds(0), nullptr);
|
||||
EXPECT_EQ(roomType, Const(group).getRoomType());
|
||||
}
|
||||
|
||||
TEST_F(GroupTest, getAllOn)
|
||||
{
|
||||
const int id = 1;
|
||||
expectGetState(id);
|
||||
Group group(id, commands, std::chrono::steady_clock::duration::max(), nullptr);
|
||||
EXPECT_EQ(all_on, group.getAllOn());
|
||||
EXPECT_EQ(all_on, Const(group).getAllOn());
|
||||
}
|
||||
|
||||
TEST_F(GroupTest, getAnyOn)
|
||||
{
|
||||
const int id = 1;
|
||||
expectGetState(id);
|
||||
Group group(id, commands, std::chrono::steady_clock::duration::max(), nullptr);
|
||||
EXPECT_EQ(any_on, group.getAnyOn());
|
||||
EXPECT_EQ(any_on, Const(group).getAnyOn());
|
||||
}
|
||||
|
||||
TEST_F(GroupTest, getActionOn)
|
||||
{
|
||||
const int id = 1;
|
||||
expectGetState(id);
|
||||
Group group(id, commands, std::chrono::steady_clock::duration::max(), nullptr);
|
||||
EXPECT_EQ(on, group.getActionOn());
|
||||
EXPECT_EQ(on, Const(group).getActionOn());
|
||||
}
|
||||
|
||||
TEST_F(GroupTest, getActionHueSaturation)
|
||||
{
|
||||
const int id = 1;
|
||||
expectGetState(id);
|
||||
Group group(id, commands, std::chrono::steady_clock::duration::max(), nullptr);
|
||||
std::pair<uint16_t, uint8_t> hueSat {hue, sat};
|
||||
EXPECT_EQ(hueSat, group.getActionHueSaturation());
|
||||
EXPECT_EQ(hueSat, Const(group).getActionHueSaturation());
|
||||
}
|
||||
|
||||
TEST_F(GroupTest, getActionBrightness)
|
||||
{
|
||||
const int id = 1;
|
||||
expectGetState(id);
|
||||
Group group(id, commands, std::chrono::steady_clock::duration::max(), nullptr);
|
||||
EXPECT_EQ(bri, group.getActionBrightness());
|
||||
EXPECT_EQ(bri, Const(group).getActionBrightness());
|
||||
}
|
||||
|
||||
TEST_F(GroupTest, getActionColorTemperature)
|
||||
{
|
||||
const int id = 1;
|
||||
expectGetState(id);
|
||||
Group group(id, commands, std::chrono::steady_clock::duration::max(), nullptr);
|
||||
EXPECT_EQ(ct, group.getActionColorTemperature());
|
||||
EXPECT_EQ(ct, Const(group).getActionColorTemperature());
|
||||
}
|
||||
|
||||
TEST_F(GroupTest, getActionColorXY)
|
||||
{
|
||||
const int id = 1;
|
||||
expectGetState(id);
|
||||
Group group(id, commands, std::chrono::steady_clock::duration::max(), nullptr);
|
||||
std::pair<float, float> xy {x, y};
|
||||
EXPECT_EQ(xy, group.getActionColorXY());
|
||||
EXPECT_EQ(xy, Const(group).getActionColorXY());
|
||||
}
|
||||
|
||||
TEST_F(GroupTest, getActionColorMode)
|
||||
{
|
||||
const int id = 1;
|
||||
expectGetState(id);
|
||||
Group group(id, commands, std::chrono::steady_clock::duration::max(), nullptr);
|
||||
EXPECT_EQ(colormode, group.getActionColorMode());
|
||||
EXPECT_EQ(colormode, Const(group).getActionColorMode());
|
||||
}
|
||||
|
||||
TEST_F(GroupTest, setName)
|
||||
{
|
||||
const int id = 1;
|
||||
expectGetState(id);
|
||||
Group group(id, commands, std::chrono::steady_clock::duration::max(), nullptr);
|
||||
const std::string name = "Test group";
|
||||
nlohmann::json request = {{"name", name}};
|
||||
nlohmann::json response = {{"success", {"/groups/1/name", name}}};
|
||||
EXPECT_CALL(*handler, PUTJson("/api/" + getBridgeUsername() + "/groups/1", request, getBridgeIp(), getBridgePort()))
|
||||
.WillOnce(Return(response));
|
||||
expectGetState(id);
|
||||
group.setName(name);
|
||||
}
|
||||
|
||||
TEST_F(GroupTest, setLights)
|
||||
{
|
||||
const int id = 1;
|
||||
expectGetState(id);
|
||||
Group group(id, commands, std::chrono::steady_clock::duration::max(), nullptr);
|
||||
const nlohmann::json lights = {"2", "4", "5"};
|
||||
nlohmann::json request = {{"lights", lights}};
|
||||
nlohmann::json response = {{"success", {"/groups/1/lights", lights}}};
|
||||
EXPECT_CALL(*handler, PUTJson("/api/" + getBridgeUsername() + "/groups/1", request, getBridgeIp(), getBridgePort()))
|
||||
.WillOnce(Return(response));
|
||||
expectGetState(id);
|
||||
group.setLights(std::vector<int> {2, 4, 5});
|
||||
}
|
||||
|
||||
TEST_F(GroupTest, setRoomType)
|
||||
{
|
||||
const int id = 1;
|
||||
expectGetState(id);
|
||||
Group group(id, commands, std::chrono::steady_clock::duration::max(), nullptr);
|
||||
const std::string type = "LivingRoom";
|
||||
nlohmann::json request = {{"class", type}};
|
||||
nlohmann::json response = {{"success", {"/groups/1/class", type}}};
|
||||
EXPECT_CALL(*handler, PUTJson("/api/" + getBridgeUsername() + "/groups/1", request, getBridgeIp(), getBridgePort()))
|
||||
.WillOnce(Return(response));
|
||||
expectGetState(id);
|
||||
group.setRoomType(type);
|
||||
}
|
||||
|
||||
TEST_F(GroupTest, setScene)
|
||||
{
|
||||
const int id = 1;
|
||||
expectGetState(id);
|
||||
Group group(id, commands, std::chrono::steady_clock::duration::max(), nullptr);
|
||||
const std::string scene = "testScene";
|
||||
nlohmann::json request = {{"scene", scene}};
|
||||
nlohmann::json response = {{"success", {"/groups/1/action/scene", scene}}};
|
||||
EXPECT_CALL(
|
||||
*handler, PUTJson("/api/" + getBridgeUsername() + "/groups/1/action", request, getBridgeIp(), getBridgePort()))
|
||||
.WillOnce(Return(response));
|
||||
group.setScene(scene);
|
||||
}
|
||||
|
||||
TEST_F(GroupTest, createSceneAction)
|
||||
{
|
||||
const int id = 1;
|
||||
expectGetState(id);
|
||||
const Group group(id, commands, std::chrono::steady_clock::duration::max(), nullptr);
|
||||
const std::string scene = "testScene";
|
||||
nlohmann::json request = { {"scene", scene} };
|
||||
hueplusplus::Action command = group.createSceneAction(scene);
|
||||
EXPECT_EQ(hueplusplus::Action::Method::put, command.getMethod());
|
||||
EXPECT_EQ("/api/" + getBridgeUsername() + "/groups/1/action", command.getAddress());
|
||||
EXPECT_EQ(request, command.getBody());
|
||||
}
|
||||
|
||||
TEST(CreateGroup, LightGroup)
|
||||
{
|
||||
EXPECT_EQ(nlohmann::json({{"lights", {"1"}}, {"type", "LightGroup"}, {"name", "Name"}, {"class", "Other"}}),
|
||||
CreateGroup::LightGroup({1}, "Name").getRequest());
|
||||
EXPECT_EQ(nlohmann::json({{"lights", {"2", "4"}}, {"type", "LightGroup"}, {"class", "Other"}}),
|
||||
CreateGroup::LightGroup({2, 4}).getRequest());
|
||||
}
|
||||
|
||||
TEST(CreateGroup, Entertainment)
|
||||
{
|
||||
EXPECT_EQ(nlohmann::json({{"lights", {"1"}}, {"type", "Entertainment"}, {"name", "Name"}, {"class", "Other"}}),
|
||||
CreateGroup::Entertainment({1}, "Name").getRequest());
|
||||
EXPECT_EQ(nlohmann::json({{"lights", {"2", "4"}}, {"type", "Entertainment"}, {"class", "Other"}}),
|
||||
CreateGroup::Entertainment({2, 4}).getRequest());
|
||||
}
|
||||
|
||||
TEST(CreateGroup, Zone)
|
||||
{
|
||||
EXPECT_EQ(nlohmann::json({{"lights", {"1"}}, {"type", "Zone"}, {"name", "Name"}, {"class", "Other"}}),
|
||||
CreateGroup::Zone({1}, "Name").getRequest());
|
||||
EXPECT_EQ(nlohmann::json({{"lights", {"2", "4"}}, {"type", "Zone"}, {"class", "Other"}}),
|
||||
CreateGroup::Zone({2, 4}).getRequest());
|
||||
}
|
||||
|
||||
TEST(CreateGroup, Room)
|
||||
{
|
||||
EXPECT_EQ(nlohmann::json({{"lights", {"1"}}, {"type", "Room"}, {"name", "Name"}, {"class", "Bedroom"}}),
|
||||
CreateGroup::Room({1}, "Name", "Bedroom").getRequest());
|
||||
EXPECT_EQ(nlohmann::json({{"lights", {"1"}}, {"type", "Room"}, {"name", "Name"}, {"class", "Other"}}),
|
||||
CreateGroup::Room({1}, "Name").getRequest());
|
||||
EXPECT_EQ(nlohmann::json({{"lights", {"2", "4"}}, {"type", "Room"}, {"class", "Other"}}),
|
||||
CreateGroup::Room({2, 4}).getRequest());
|
||||
}
|
||||
@@ -0,0 +1,242 @@
|
||||
/**
|
||||
\file test_HueCommandAPI.cpp
|
||||
Copyright Notice\n
|
||||
Copyright (C) 2018 Jan Rogall - developer\n
|
||||
Copyright (C) 2018 Moritz Wirger - developer\n
|
||||
|
||||
This file is part of hueplusplus.
|
||||
|
||||
hueplusplus 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.
|
||||
|
||||
hueplusplus 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 hueplusplus. If not, see <http://www.gnu.org/licenses/>.
|
||||
**/
|
||||
|
||||
#include <gmock/gmock.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "testhelper.h"
|
||||
|
||||
#include "hueplusplus/Bridge.h"
|
||||
#include <nlohmann/json.hpp>
|
||||
#include "mocks/mock_HttpHandler.h"
|
||||
|
||||
using namespace hueplusplus;
|
||||
|
||||
TEST(HueCommandAPI, PUTRequest)
|
||||
{
|
||||
using namespace ::testing;
|
||||
std::shared_ptr<MockHttpHandler> httpHandler = std::make_shared<MockHttpHandler>();
|
||||
|
||||
HueCommandAPI api(getBridgeIp(), getBridgePort(), getBridgeUsername(), httpHandler);
|
||||
nlohmann::json request;
|
||||
nlohmann::json result = nlohmann::json::object();
|
||||
result["ok"] = true;
|
||||
|
||||
// empty path
|
||||
{
|
||||
EXPECT_CALL(*httpHandler, PUTJson("/api/" + getBridgeUsername(), request, getBridgeIp(), 80))
|
||||
.WillOnce(Return(result));
|
||||
EXPECT_EQ(result, api.PUTRequest("", request));
|
||||
Mock::VerifyAndClearExpectations(httpHandler.get());
|
||||
}
|
||||
// not empty path, starting with slash
|
||||
{
|
||||
const std::string path = "/test";
|
||||
EXPECT_CALL(*httpHandler, PUTJson("/api/" + getBridgeUsername() + path, request, getBridgeIp(), 80))
|
||||
.WillOnce(Return(result));
|
||||
EXPECT_EQ(result, api.PUTRequest(path, request));
|
||||
Mock::VerifyAndClearExpectations(httpHandler.get());
|
||||
}
|
||||
// not empty path, not starting with slash
|
||||
{
|
||||
const std::string path = "test";
|
||||
EXPECT_CALL(*httpHandler, PUTJson("/api/" + getBridgeUsername() + '/' + path, request, getBridgeIp(), 80))
|
||||
.WillOnce(Return(result));
|
||||
EXPECT_EQ(result, api.PUTRequest(path, request));
|
||||
Mock::VerifyAndClearExpectations(httpHandler.get());
|
||||
}
|
||||
// recoverable error
|
||||
{
|
||||
const std::string path = "/test";
|
||||
EXPECT_CALL(*httpHandler, PUTJson("/api/" + getBridgeUsername() + path, request, getBridgeIp(), 80))
|
||||
.WillOnce(Throw(std::system_error(std::make_error_code(std::errc::connection_reset))))
|
||||
.WillOnce(Return(result));
|
||||
EXPECT_EQ(result, api.PUTRequest(path, request));
|
||||
Mock::VerifyAndClearExpectations(httpHandler.get());
|
||||
}
|
||||
// recoverable error x2
|
||||
{
|
||||
const std::string path = "/test";
|
||||
EXPECT_CALL(*httpHandler, PUTJson("/api/" + getBridgeUsername() + path, request, getBridgeIp(), 80))
|
||||
.WillOnce(Throw(std::system_error(std::make_error_code(std::errc::connection_reset))))
|
||||
.WillOnce(Throw(std::system_error(std::make_error_code(std::errc::connection_reset))));
|
||||
EXPECT_THROW(api.PUTRequest(path, request), std::system_error);
|
||||
Mock::VerifyAndClearExpectations(httpHandler.get());
|
||||
}
|
||||
// unrecoverable error
|
||||
{
|
||||
const std::string path = "/test";
|
||||
EXPECT_CALL(*httpHandler, PUTJson("/api/" + getBridgeUsername() + path, request, getBridgeIp(), 80))
|
||||
.WillOnce(Throw(std::system_error(std::make_error_code(std::errc::not_enough_memory))));
|
||||
EXPECT_THROW(api.PUTRequest(path, request), std::system_error);
|
||||
Mock::VerifyAndClearExpectations(httpHandler.get());
|
||||
}
|
||||
// api returns error
|
||||
{
|
||||
const std::string path = "/test";
|
||||
const nlohmann::json errorResponse{{"error", {{"type", 10}, {"address", path}, {"description", "Stuff"}}}};
|
||||
EXPECT_CALL(*httpHandler, PUTJson("/api/" + getBridgeUsername() + path, request, getBridgeIp(), 80))
|
||||
.WillOnce(Return(errorResponse));
|
||||
EXPECT_THROW(api.PUTRequest(path, request), HueAPIResponseException);
|
||||
Mock::VerifyAndClearExpectations(httpHandler.get());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(HueCommandAPI, GETRequest)
|
||||
{
|
||||
using namespace ::testing;
|
||||
std::shared_ptr<MockHttpHandler> httpHandler = std::make_shared<MockHttpHandler>();
|
||||
|
||||
HueCommandAPI api(getBridgeIp(), getBridgePort(), getBridgeUsername(), httpHandler);
|
||||
nlohmann::json request;
|
||||
nlohmann::json result = nlohmann::json::object();
|
||||
result["ok"] = true;
|
||||
|
||||
// empty path
|
||||
{
|
||||
EXPECT_CALL(*httpHandler, GETJson("/api/" + getBridgeUsername(), request, getBridgeIp(), 80))
|
||||
.WillOnce(Return(result));
|
||||
EXPECT_EQ(result, api.GETRequest("", request));
|
||||
Mock::VerifyAndClearExpectations(httpHandler.get());
|
||||
}
|
||||
// not empty path, starting with slash
|
||||
{
|
||||
const std::string path = "/test";
|
||||
EXPECT_CALL(*httpHandler, GETJson("/api/" + getBridgeUsername() + path, request, getBridgeIp(), 80))
|
||||
.WillOnce(Return(result));
|
||||
EXPECT_EQ(result, api.GETRequest(path, request));
|
||||
Mock::VerifyAndClearExpectations(httpHandler.get());
|
||||
}
|
||||
// not empty path, not starting with slash
|
||||
{
|
||||
const std::string path = "test";
|
||||
EXPECT_CALL(*httpHandler, GETJson("/api/" + getBridgeUsername() + '/' + path, request, getBridgeIp(), 80))
|
||||
.WillOnce(Return(result));
|
||||
EXPECT_EQ(result, api.GETRequest(path, request));
|
||||
Mock::VerifyAndClearExpectations(httpHandler.get());
|
||||
}
|
||||
// recoverable error
|
||||
{
|
||||
const std::string path = "/test";
|
||||
EXPECT_CALL(*httpHandler, GETJson("/api/" + getBridgeUsername() + path, request, getBridgeIp(), 80))
|
||||
.WillOnce(Throw(std::system_error(std::make_error_code(std::errc::connection_reset))))
|
||||
.WillOnce(Return(result));
|
||||
EXPECT_EQ(result, api.GETRequest(path, request));
|
||||
Mock::VerifyAndClearExpectations(httpHandler.get());
|
||||
}
|
||||
// recoverable error x2
|
||||
{
|
||||
const std::string path = "/test";
|
||||
EXPECT_CALL(*httpHandler, GETJson("/api/" + getBridgeUsername() + path, request, getBridgeIp(), 80))
|
||||
.WillOnce(Throw(std::system_error(std::make_error_code(std::errc::connection_reset))))
|
||||
.WillOnce(Throw(std::system_error(std::make_error_code(std::errc::connection_reset))));
|
||||
EXPECT_THROW(api.GETRequest(path, request), std::system_error);
|
||||
Mock::VerifyAndClearExpectations(httpHandler.get());
|
||||
}
|
||||
// unrecoverable error
|
||||
{
|
||||
const std::string path = "/test";
|
||||
EXPECT_CALL(*httpHandler, GETJson("/api/" + getBridgeUsername() + path, request, getBridgeIp(), 80))
|
||||
.WillOnce(Throw(std::system_error(std::make_error_code(std::errc::not_enough_memory))));
|
||||
EXPECT_THROW(api.GETRequest(path, request), std::system_error);
|
||||
Mock::VerifyAndClearExpectations(httpHandler.get());
|
||||
}
|
||||
// api returns error
|
||||
{
|
||||
const std::string path = "/test";
|
||||
const nlohmann::json errorResponse{{"error", {{"type", 10}, {"address", path}, {"description", "Stuff"}}}};
|
||||
EXPECT_CALL(*httpHandler, GETJson("/api/" + getBridgeUsername() + path, request, getBridgeIp(), 80))
|
||||
.WillOnce(Return(errorResponse));
|
||||
EXPECT_THROW(api.GETRequest(path, request), HueAPIResponseException);
|
||||
Mock::VerifyAndClearExpectations(httpHandler.get());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(HueCommandAPI, DELETERequest)
|
||||
{
|
||||
using namespace ::testing;
|
||||
std::shared_ptr<MockHttpHandler> httpHandler = std::make_shared<MockHttpHandler>();
|
||||
|
||||
HueCommandAPI api(getBridgeIp(), getBridgePort(), getBridgeUsername(), httpHandler);
|
||||
nlohmann::json request;
|
||||
nlohmann::json result = nlohmann::json::object();
|
||||
result["ok"] = true;
|
||||
|
||||
// empty path
|
||||
{
|
||||
EXPECT_CALL(*httpHandler, DELETEJson("/api/" + getBridgeUsername(), request, getBridgeIp(), 80))
|
||||
.WillOnce(Return(result));
|
||||
EXPECT_EQ(result, api.DELETERequest("", request));
|
||||
Mock::VerifyAndClearExpectations(httpHandler.get());
|
||||
}
|
||||
// not empty path, starting with slash
|
||||
{
|
||||
const std::string path = "/test";
|
||||
EXPECT_CALL(*httpHandler, DELETEJson("/api/" + getBridgeUsername() + path, request, getBridgeIp(), 80))
|
||||
.WillOnce(Return(result));
|
||||
EXPECT_EQ(result, api.DELETERequest(path, request));
|
||||
Mock::VerifyAndClearExpectations(httpHandler.get());
|
||||
}
|
||||
// not empty path, not starting with slash
|
||||
{
|
||||
const std::string path = "test";
|
||||
EXPECT_CALL(*httpHandler, DELETEJson("/api/" + getBridgeUsername() + '/' + path, request, getBridgeIp(), 80))
|
||||
.WillOnce(Return(result));
|
||||
EXPECT_EQ(result, api.DELETERequest(path, request));
|
||||
Mock::VerifyAndClearExpectations(httpHandler.get());
|
||||
}
|
||||
// recoverable error
|
||||
{
|
||||
const std::string path = "/test";
|
||||
EXPECT_CALL(*httpHandler, DELETEJson("/api/" + getBridgeUsername() + path, request, getBridgeIp(), 80))
|
||||
.WillOnce(Throw(std::system_error(std::make_error_code(std::errc::connection_reset))))
|
||||
.WillOnce(Return(result));
|
||||
EXPECT_EQ(result, api.DELETERequest(path, request));
|
||||
Mock::VerifyAndClearExpectations(httpHandler.get());
|
||||
}
|
||||
// recoverable error x2
|
||||
{
|
||||
const std::string path = "/test";
|
||||
EXPECT_CALL(*httpHandler, DELETEJson("/api/" + getBridgeUsername() + path, request, getBridgeIp(), 80))
|
||||
.WillOnce(Throw(std::system_error(std::make_error_code(std::errc::connection_reset))))
|
||||
.WillOnce(Throw(std::system_error(std::make_error_code(std::errc::connection_reset))));
|
||||
EXPECT_THROW(api.DELETERequest(path, request), std::system_error);
|
||||
Mock::VerifyAndClearExpectations(httpHandler.get());
|
||||
}
|
||||
// unrecoverable error
|
||||
{
|
||||
const std::string path = "/test";
|
||||
EXPECT_CALL(*httpHandler, DELETEJson("/api/" + getBridgeUsername() + path, request, getBridgeIp(), 80))
|
||||
.WillOnce(Throw(std::system_error(std::make_error_code(std::errc::not_enough_memory))));
|
||||
EXPECT_THROW(api.DELETERequest(path, request), std::system_error);
|
||||
Mock::VerifyAndClearExpectations(httpHandler.get());
|
||||
}
|
||||
// api returns error
|
||||
{
|
||||
const std::string path = "/test";
|
||||
const nlohmann::json errorResponse{{"error", {{"type", 10}, {"address", path}, {"description", "Stuff"}}}};
|
||||
EXPECT_CALL(*httpHandler, DELETEJson("/api/" + getBridgeUsername() + path, request, getBridgeIp(), 80))
|
||||
.WillOnce(Return(errorResponse));
|
||||
EXPECT_THROW(api.DELETERequest(path, request), HueAPIResponseException);
|
||||
Mock::VerifyAndClearExpectations(httpHandler.get());
|
||||
}
|
||||
}
|
||||
+787
@@ -0,0 +1,787 @@
|
||||
/**
|
||||
\file test_HueLight.cpp
|
||||
Copyright Notice\n
|
||||
Copyright (C) 2017 Jan Rogall - developer\n
|
||||
Copyright (C) 2017 Moritz Wirger - developer\n
|
||||
|
||||
This file is part of hueplusplus.
|
||||
|
||||
hueplusplus 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.
|
||||
|
||||
hueplusplus 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 hueplusplus. If not, see <http://www.gnu.org/licenses/>.
|
||||
**/
|
||||
|
||||
#include <gmock/gmock.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "testhelper.h"
|
||||
|
||||
#include "hueplusplus/Bridge.h"
|
||||
#include "hueplusplus/Light.h"
|
||||
#include <nlohmann/json.hpp>
|
||||
#include "mocks/mock_HttpHandler.h"
|
||||
|
||||
using namespace hueplusplus;
|
||||
|
||||
class HueLightTest : public ::testing::Test
|
||||
{
|
||||
protected:
|
||||
std::shared_ptr<MockHttpHandler> handler;
|
||||
nlohmann::json hue_bridge_state;
|
||||
Bridge test_bridge;
|
||||
|
||||
protected:
|
||||
HueLightTest()
|
||||
: handler(std::make_shared<MockHttpHandler>()),
|
||||
hue_bridge_state({{"lights",
|
||||
{{"1",
|
||||
{{"state",
|
||||
{{"on", true}, {"bri", 254}, {"ct", 366}, {"alert", "none"}, {"colormode", "ct"},
|
||||
{"reachable", true}, {"effect", "none"}}},
|
||||
{"swupdate", {{"state", "noupdates"}, {"lastinstall", nullptr}}}, {"type", "Dimmable light"},
|
||||
{"name", "Hue lamp 1"}, {"modelid", "LWB004"}, {"manufacturername", "Philips"},
|
||||
{"productname", "Hue bloom"}, {"uniqueid", "00:00:00:00:00:00:00:00-00"},
|
||||
{"swversion", "5.50.1.19085"}, {"luminaireuniqueid", "0000000"}}},
|
||||
{"2",
|
||||
{{"state",
|
||||
{{"on", false}, {"bri", 0}, {"ct", 366}, {"hue", 12345}, {"sat", 123},
|
||||
{"xy", {0.102, 0.102}}, {"alert", "none"}, {"colormode", "ct"}, {"reachable", true},
|
||||
{"effect", "none"}}},
|
||||
{"swupdate", {{"state", "noupdates"}, {"lastinstall", nullptr}}}, {"type", "Color light"},
|
||||
{"name", "Hue lamp 2"}, {"modelid", "LST001"}, {"uniqueid", "11:11:11:11:11:11:11:11-11"},
|
||||
{"swversion", "5.50.1.19085"}}},
|
||||
{"3",
|
||||
{{"state",
|
||||
{{"on", false}, {"bri", 254}, {"ct", 366}, {"hue", 12345}, {"sat", 123},
|
||||
{"xy", {0.102, 0.102}}, {"alert", "none"}, {"colormode", "ct"}, {"reachable", true},
|
||||
{"effect", "none"}}},
|
||||
{"swupdate", {{"state", "noupdates"}, {"lastinstall", nullptr}}},
|
||||
{"type", "Extended color light"}, {"name", "Hue lamp 3"}, {"modelid", "LCT010"},
|
||||
{"manufacturername", "Philips"}, {"productname", "Hue bloom"},
|
||||
{"swversion", "5.50.1.19085"}}}}}}),
|
||||
test_bridge(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler)
|
||||
{
|
||||
using namespace ::testing;
|
||||
|
||||
EXPECT_CALL(*handler, GETJson("/api/" + getBridgeUsername(), nlohmann::json::object(), getBridgeIp(), 80))
|
||||
.Times(AtLeast(1))
|
||||
.WillRepeatedly(Return(hue_bridge_state));
|
||||
}
|
||||
~HueLightTest() {};
|
||||
};
|
||||
|
||||
TEST_F(HueLightTest, Constructor)
|
||||
{
|
||||
const Light ctest_light_1 = test_bridge.lights().get(1);
|
||||
Light test_light_1 = test_bridge.lights().get(1);
|
||||
const Light ctest_light_2 = test_bridge.lights().get(2);
|
||||
Light test_light_2 = test_bridge.lights().get(2);
|
||||
const Light ctest_light_3 = test_bridge.lights().get(3);
|
||||
Light test_light_3 = test_bridge.lights().get(3);
|
||||
}
|
||||
|
||||
TEST_F(HueLightTest, on)
|
||||
{
|
||||
using namespace ::testing;
|
||||
EXPECT_CALL(*handler, PUTJson("/api/" + getBridgeUsername() + "/lights/2/state", _, getBridgeIp(), 80))
|
||||
.Times(1)
|
||||
.WillOnce(Return(nlohmann::json::array()));
|
||||
|
||||
nlohmann::json prep_ret;
|
||||
prep_ret = nlohmann::json::array();
|
||||
prep_ret[0] = nlohmann::json::object();
|
||||
prep_ret[0]["success"] = nlohmann::json::object();
|
||||
prep_ret[0]["success"]["/lights/3/state/transitiontime"] = 255;
|
||||
prep_ret[1] = nlohmann::json::object();
|
||||
prep_ret[1]["success"] = nlohmann::json::object();
|
||||
prep_ret[1]["success"]["/lights/3/state/on"] = true;
|
||||
EXPECT_CALL(*handler, PUTJson("/api/" + getBridgeUsername() + "/lights/3/state", _, getBridgeIp(), 80))
|
||||
.Times(1)
|
||||
.WillOnce(Return(prep_ret));
|
||||
|
||||
Light test_light_1 = test_bridge.lights().get(1);
|
||||
Light test_light_2 = test_bridge.lights().get(2);
|
||||
Light test_light_3 = test_bridge.lights().get(3);
|
||||
|
||||
EXPECT_EQ(true, test_light_1.on(33));
|
||||
EXPECT_EQ(false, test_light_2.on());
|
||||
EXPECT_EQ(true, test_light_3.on(255));
|
||||
}
|
||||
|
||||
TEST_F(HueLightTest, off)
|
||||
{
|
||||
using namespace ::testing;
|
||||
nlohmann::json prep_ret;
|
||||
prep_ret = nlohmann::json::array();
|
||||
prep_ret[0] = nlohmann::json::object();
|
||||
prep_ret[0]["success"] = nlohmann::json::object();
|
||||
prep_ret[0]["success"]["/lights/1/state/transitiontime"] = 33;
|
||||
prep_ret[1] = nlohmann::json::object();
|
||||
prep_ret[1]["success"] = nlohmann::json::object();
|
||||
prep_ret[1]["success"]["/lights/1/state/on"] = false;
|
||||
EXPECT_CALL(*handler, PUTJson("/api/" + getBridgeUsername() + "/lights/1/state", _, getBridgeIp(), 80))
|
||||
.Times(1)
|
||||
.WillOnce(Return(prep_ret));
|
||||
|
||||
Light test_light_1 = test_bridge.lights().get(1);
|
||||
Light test_light_2 = test_bridge.lights().get(2);
|
||||
Light test_light_3 = test_bridge.lights().get(3);
|
||||
|
||||
EXPECT_EQ(true, test_light_1.off(33));
|
||||
EXPECT_EQ(true, test_light_2.off());
|
||||
EXPECT_EQ(true, test_light_3.off(255));
|
||||
}
|
||||
|
||||
TEST_F(HueLightTest, isOn)
|
||||
{
|
||||
const Light ctest_light_1 = test_bridge.lights().get(1);
|
||||
const Light ctest_light_2 = test_bridge.lights().get(2);
|
||||
const Light ctest_light_3 = test_bridge.lights().get(3);
|
||||
Light test_light_1 = test_bridge.lights().get(1);
|
||||
Light test_light_2 = test_bridge.lights().get(2);
|
||||
Light test_light_3 = test_bridge.lights().get(3);
|
||||
|
||||
EXPECT_EQ(true, ctest_light_1.isOn());
|
||||
EXPECT_EQ(false, ctest_light_2.isOn());
|
||||
EXPECT_EQ(false, ctest_light_3.isOn());
|
||||
EXPECT_EQ(true, test_light_1.isOn());
|
||||
EXPECT_EQ(false, test_light_2.isOn());
|
||||
EXPECT_EQ(false, test_light_3.isOn());
|
||||
}
|
||||
|
||||
TEST_F(HueLightTest, getId)
|
||||
{
|
||||
const Light ctest_light_1 = test_bridge.lights().get(1);
|
||||
const Light ctest_light_2 = test_bridge.lights().get(2);
|
||||
const Light ctest_light_3 = test_bridge.lights().get(3);
|
||||
Light test_light_1 = test_bridge.lights().get(1);
|
||||
Light test_light_2 = test_bridge.lights().get(2);
|
||||
Light test_light_3 = test_bridge.lights().get(3);
|
||||
|
||||
EXPECT_EQ(1, ctest_light_1.getId());
|
||||
EXPECT_EQ(2, ctest_light_2.getId());
|
||||
EXPECT_EQ(3, ctest_light_3.getId());
|
||||
EXPECT_EQ(1, test_light_1.getId());
|
||||
EXPECT_EQ(2, test_light_2.getId());
|
||||
EXPECT_EQ(3, test_light_3.getId());
|
||||
}
|
||||
|
||||
TEST_F(HueLightTest, getType)
|
||||
{
|
||||
const Light ctest_light_1 = test_bridge.lights().get(1);
|
||||
const Light ctest_light_2 = test_bridge.lights().get(2);
|
||||
const Light ctest_light_3 = test_bridge.lights().get(3);
|
||||
Light test_light_1 = test_bridge.lights().get(1);
|
||||
Light test_light_2 = test_bridge.lights().get(2);
|
||||
Light test_light_3 = test_bridge.lights().get(3);
|
||||
|
||||
EXPECT_EQ("Dimmable light", ctest_light_1.getType());
|
||||
EXPECT_EQ("Color light", ctest_light_2.getType());
|
||||
EXPECT_EQ("Extended color light", ctest_light_3.getType());
|
||||
EXPECT_EQ("Dimmable light", test_light_1.getType());
|
||||
EXPECT_EQ("Color light", test_light_2.getType());
|
||||
EXPECT_EQ("Extended color light", test_light_3.getType());
|
||||
}
|
||||
|
||||
TEST_F(HueLightTest, getName)
|
||||
{
|
||||
const Light ctest_light_1 = test_bridge.lights().get(1);
|
||||
const Light ctest_light_2 = test_bridge.lights().get(2);
|
||||
const Light ctest_light_3 = test_bridge.lights().get(3);
|
||||
Light test_light_1 = test_bridge.lights().get(1);
|
||||
Light test_light_2 = test_bridge.lights().get(2);
|
||||
Light test_light_3 = test_bridge.lights().get(3);
|
||||
|
||||
EXPECT_EQ("Hue lamp 1", ctest_light_1.getName());
|
||||
EXPECT_EQ("Hue lamp 2", ctest_light_2.getName());
|
||||
EXPECT_EQ("Hue lamp 3", ctest_light_3.getName());
|
||||
EXPECT_EQ("Hue lamp 1", test_light_1.getName());
|
||||
EXPECT_EQ("Hue lamp 2", test_light_2.getName());
|
||||
EXPECT_EQ("Hue lamp 3", test_light_3.getName());
|
||||
}
|
||||
|
||||
TEST_F(HueLightTest, getModelId)
|
||||
{
|
||||
const Light ctest_light_1 = test_bridge.lights().get(1);
|
||||
const Light ctest_light_2 = test_bridge.lights().get(2);
|
||||
const Light ctest_light_3 = test_bridge.lights().get(3);
|
||||
Light test_light_1 = test_bridge.lights().get(1);
|
||||
Light test_light_2 = test_bridge.lights().get(2);
|
||||
Light test_light_3 = test_bridge.lights().get(3);
|
||||
|
||||
EXPECT_EQ("LWB004", ctest_light_1.getModelId());
|
||||
EXPECT_EQ("LST001", ctest_light_2.getModelId());
|
||||
EXPECT_EQ("LCT010", ctest_light_3.getModelId());
|
||||
EXPECT_EQ("LWB004", test_light_1.getModelId());
|
||||
EXPECT_EQ("LST001", test_light_2.getModelId());
|
||||
EXPECT_EQ("LCT010", test_light_3.getModelId());
|
||||
}
|
||||
|
||||
TEST_F(HueLightTest, getUId)
|
||||
{
|
||||
const Light ctest_light_1 = test_bridge.lights().get(1);
|
||||
const Light ctest_light_2 = test_bridge.lights().get(2);
|
||||
const Light ctest_light_3 = test_bridge.lights().get(3);
|
||||
Light test_light_1 = test_bridge.lights().get(1);
|
||||
Light test_light_2 = test_bridge.lights().get(2);
|
||||
Light test_light_3 = test_bridge.lights().get(3);
|
||||
|
||||
EXPECT_EQ("00:00:00:00:00:00:00:00-00", ctest_light_1.getUId());
|
||||
EXPECT_EQ("11:11:11:11:11:11:11:11-11", ctest_light_2.getUId());
|
||||
EXPECT_EQ("", ctest_light_3.getUId());
|
||||
EXPECT_EQ("00:00:00:00:00:00:00:00-00", test_light_1.getUId());
|
||||
EXPECT_EQ("11:11:11:11:11:11:11:11-11", test_light_2.getUId());
|
||||
EXPECT_EQ("", test_light_3.getUId());
|
||||
}
|
||||
|
||||
TEST_F(HueLightTest, getManufacturername)
|
||||
{
|
||||
const Light ctest_light_1 = test_bridge.lights().get(1);
|
||||
const Light ctest_light_2 = test_bridge.lights().get(2);
|
||||
const Light ctest_light_3 = test_bridge.lights().get(3);
|
||||
Light test_light_1 = test_bridge.lights().get(1);
|
||||
Light test_light_2 = test_bridge.lights().get(2);
|
||||
Light test_light_3 = test_bridge.lights().get(3);
|
||||
|
||||
EXPECT_EQ("Philips", ctest_light_1.getManufacturername());
|
||||
EXPECT_EQ("", ctest_light_2.getManufacturername());
|
||||
EXPECT_EQ("Philips", ctest_light_3.getManufacturername());
|
||||
EXPECT_EQ("Philips", test_light_1.getManufacturername());
|
||||
EXPECT_EQ("", test_light_2.getManufacturername());
|
||||
EXPECT_EQ("Philips", test_light_3.getManufacturername());
|
||||
}
|
||||
|
||||
TEST_F(HueLightTest, getProductname)
|
||||
{
|
||||
const Light ctest_light_1 = test_bridge.lights().get(1);
|
||||
const Light ctest_light_2 = test_bridge.lights().get(2);
|
||||
const Light ctest_light_3 = test_bridge.lights().get(3);
|
||||
Light test_light_1 = test_bridge.lights().get(1);
|
||||
Light test_light_2 = test_bridge.lights().get(2);
|
||||
Light test_light_3 = test_bridge.lights().get(3);
|
||||
|
||||
EXPECT_EQ("Hue bloom", ctest_light_1.getProductname());
|
||||
EXPECT_EQ("", ctest_light_2.getProductname());
|
||||
EXPECT_EQ("Hue bloom", ctest_light_3.getProductname());
|
||||
EXPECT_EQ("Hue bloom", test_light_1.getProductname());
|
||||
EXPECT_EQ("", test_light_2.getProductname());
|
||||
EXPECT_EQ("Hue bloom", test_light_3.getProductname());
|
||||
}
|
||||
|
||||
TEST_F(HueLightTest, getLuminaireUId)
|
||||
{
|
||||
const Light ctest_light_1 = test_bridge.lights().get(1);
|
||||
const Light ctest_light_2 = test_bridge.lights().get(2);
|
||||
const Light ctest_light_3 = test_bridge.lights().get(3);
|
||||
Light test_light_1 = test_bridge.lights().get(1);
|
||||
Light test_light_2 = test_bridge.lights().get(2);
|
||||
Light test_light_3 = test_bridge.lights().get(3);
|
||||
|
||||
EXPECT_EQ("0000000", ctest_light_1.getLuminaireUId());
|
||||
EXPECT_EQ("", ctest_light_2.getLuminaireUId());
|
||||
EXPECT_EQ("", ctest_light_3.getLuminaireUId());
|
||||
EXPECT_EQ("0000000", test_light_1.getLuminaireUId());
|
||||
EXPECT_EQ("", test_light_2.getLuminaireUId());
|
||||
EXPECT_EQ("", test_light_3.getLuminaireUId());
|
||||
}
|
||||
|
||||
TEST_F(HueLightTest, getSwVersion)
|
||||
{
|
||||
const Light ctest_light_1 = test_bridge.lights().get(1);
|
||||
const Light ctest_light_2 = test_bridge.lights().get(2);
|
||||
const Light ctest_light_3 = test_bridge.lights().get(3);
|
||||
Light test_light_1 = test_bridge.lights().get(1);
|
||||
Light test_light_2 = test_bridge.lights().get(2);
|
||||
Light test_light_3 = test_bridge.lights().get(3);
|
||||
|
||||
EXPECT_EQ("5.50.1.19085", ctest_light_1.getSwVersion());
|
||||
EXPECT_EQ("5.50.1.19085", ctest_light_2.getSwVersion());
|
||||
EXPECT_EQ("5.50.1.19085", ctest_light_3.getSwVersion());
|
||||
EXPECT_EQ("5.50.1.19085", test_light_1.getSwVersion());
|
||||
EXPECT_EQ("5.50.1.19085", test_light_2.getSwVersion());
|
||||
EXPECT_EQ("5.50.1.19085", test_light_3.getSwVersion());
|
||||
}
|
||||
|
||||
TEST_F(HueLightTest, setName)
|
||||
{
|
||||
using namespace ::testing;
|
||||
nlohmann::json expected_request({});
|
||||
expected_request["name"] = "Baskj189";
|
||||
nlohmann::json prep_ret;
|
||||
prep_ret = nlohmann::json::array();
|
||||
prep_ret[0] = nlohmann::json::object();
|
||||
prep_ret[0]["success"] = nlohmann::json::object();
|
||||
prep_ret[0]["success"]["/lights/1/name"] = expected_request["name"];
|
||||
EXPECT_CALL(
|
||||
*handler, PUTJson("/api/" + getBridgeUsername() + "/lights/1/name", expected_request, getBridgeIp(), 80))
|
||||
.Times(1)
|
||||
.WillOnce(Return(prep_ret));
|
||||
EXPECT_CALL(
|
||||
*handler, PUTJson("/api/" + getBridgeUsername() + "/lights/2/name", expected_request, getBridgeIp(), 80))
|
||||
.Times(1)
|
||||
.WillOnce(Return(nlohmann::json::array()));
|
||||
prep_ret[0]["success"] = nlohmann::json::object();
|
||||
prep_ret[0]["success"]["/lights/3/name"] = expected_request["name"];
|
||||
EXPECT_CALL(
|
||||
*handler, PUTJson("/api/" + getBridgeUsername() + "/lights/3/name", expected_request, getBridgeIp(), 80))
|
||||
.Times(1)
|
||||
.WillOnce(Return(prep_ret));
|
||||
|
||||
Light test_light_1 = test_bridge.lights().get(1);
|
||||
Light test_light_2 = test_bridge.lights().get(2);
|
||||
Light test_light_3 = test_bridge.lights().get(3);
|
||||
|
||||
EXPECT_EQ(true, test_light_1.setName(expected_request["name"].get<std::string>()));
|
||||
EXPECT_EQ(false, test_light_2.setName(expected_request["name"].get<std::string>()));
|
||||
EXPECT_EQ(true, test_light_3.setName(expected_request["name"].get<std::string>()));
|
||||
}
|
||||
|
||||
TEST_F(HueLightTest, getColorType)
|
||||
{
|
||||
const Light ctest_light_1 = test_bridge.lights().get(1);
|
||||
const Light ctest_light_2 = test_bridge.lights().get(2);
|
||||
const Light ctest_light_3 = test_bridge.lights().get(3);
|
||||
Light test_light_1 = test_bridge.lights().get(1);
|
||||
Light test_light_2 = test_bridge.lights().get(2);
|
||||
Light test_light_3 = test_bridge.lights().get(3);
|
||||
|
||||
EXPECT_EQ(ColorType::NONE, ctest_light_1.getColorType());
|
||||
EXPECT_EQ(ColorType::GAMUT_A, ctest_light_2.getColorType());
|
||||
EXPECT_EQ(ColorType::GAMUT_C_TEMPERATURE, ctest_light_3.getColorType());
|
||||
EXPECT_EQ(ColorType::NONE, test_light_1.getColorType());
|
||||
EXPECT_EQ(ColorType::GAMUT_A, test_light_2.getColorType());
|
||||
EXPECT_EQ(ColorType::GAMUT_C_TEMPERATURE, test_light_3.getColorType());
|
||||
}
|
||||
|
||||
TEST_F(HueLightTest, hasBrightnessControl)
|
||||
{
|
||||
const Light ctest_light_1 = test_bridge.lights().get(1);
|
||||
const Light ctest_light_2 = test_bridge.lights().get(2);
|
||||
const Light ctest_light_3 = test_bridge.lights().get(3);
|
||||
Light test_light_1 = test_bridge.lights().get(1);
|
||||
Light test_light_2 = test_bridge.lights().get(2);
|
||||
Light test_light_3 = test_bridge.lights().get(3);
|
||||
|
||||
EXPECT_EQ(true, ctest_light_1.hasBrightnessControl());
|
||||
EXPECT_EQ(true, ctest_light_2.hasBrightnessControl());
|
||||
EXPECT_EQ(true, ctest_light_3.hasBrightnessControl());
|
||||
EXPECT_EQ(true, test_light_1.hasBrightnessControl());
|
||||
EXPECT_EQ(true, test_light_2.hasBrightnessControl());
|
||||
EXPECT_EQ(true, test_light_3.hasBrightnessControl());
|
||||
}
|
||||
|
||||
TEST_F(HueLightTest, hasTemperatureControl)
|
||||
{
|
||||
const Light ctest_light_1 = test_bridge.lights().get(1);
|
||||
const Light ctest_light_2 = test_bridge.lights().get(2);
|
||||
const Light ctest_light_3 = test_bridge.lights().get(3);
|
||||
Light test_light_1 = test_bridge.lights().get(1);
|
||||
Light test_light_2 = test_bridge.lights().get(2);
|
||||
Light test_light_3 = test_bridge.lights().get(3);
|
||||
|
||||
EXPECT_EQ(false, ctest_light_1.hasTemperatureControl());
|
||||
EXPECT_EQ(false, ctest_light_2.hasTemperatureControl());
|
||||
EXPECT_EQ(true, ctest_light_3.hasTemperatureControl());
|
||||
EXPECT_EQ(false, test_light_1.hasTemperatureControl());
|
||||
EXPECT_EQ(false, test_light_2.hasTemperatureControl());
|
||||
EXPECT_EQ(true, test_light_3.hasTemperatureControl());
|
||||
}
|
||||
|
||||
TEST_F(HueLightTest, hasColorControl)
|
||||
{
|
||||
const Light ctest_light_1 = test_bridge.lights().get(1);
|
||||
const Light ctest_light_2 = test_bridge.lights().get(2);
|
||||
const Light ctest_light_3 = test_bridge.lights().get(3);
|
||||
Light test_light_1 = test_bridge.lights().get(1);
|
||||
Light test_light_2 = test_bridge.lights().get(2);
|
||||
Light test_light_3 = test_bridge.lights().get(3);
|
||||
|
||||
EXPECT_EQ(false, ctest_light_1.hasColorControl());
|
||||
EXPECT_EQ(true, ctest_light_2.hasColorControl());
|
||||
EXPECT_EQ(true, ctest_light_3.hasColorControl());
|
||||
EXPECT_EQ(false, test_light_1.hasColorControl());
|
||||
EXPECT_EQ(true, test_light_2.hasColorControl());
|
||||
EXPECT_EQ(true, test_light_3.hasColorControl());
|
||||
}
|
||||
|
||||
TEST_F(HueLightTest, setBrightness)
|
||||
{
|
||||
using namespace ::testing;
|
||||
EXPECT_CALL(*handler, PUTJson("/api/" + getBridgeUsername() + "/lights/1/state", _, getBridgeIp(), 80))
|
||||
.Times(1)
|
||||
.WillOnce(Return(nlohmann::json::array()));
|
||||
nlohmann::json prep_ret;
|
||||
prep_ret = nlohmann::json::array();
|
||||
prep_ret[0] = nlohmann::json::object();
|
||||
prep_ret[0]["success"] = nlohmann::json::object();
|
||||
prep_ret[0]["success"]["/lights/3/state/transitiontime"] = 0;
|
||||
prep_ret[1] = nlohmann::json::object();
|
||||
prep_ret[1]["success"] = nlohmann::json::object();
|
||||
prep_ret[1]["success"]["/lights/3/state/on"] = true;
|
||||
prep_ret[2] = nlohmann::json::object();
|
||||
prep_ret[2]["success"] = nlohmann::json::object();
|
||||
prep_ret[2]["success"]["/lights/3/state/bri"] = 253;
|
||||
EXPECT_CALL(*handler, PUTJson("/api/" + getBridgeUsername() + "/lights/3/state", _, getBridgeIp(), 80))
|
||||
.Times(1)
|
||||
.WillOnce(Return(prep_ret));
|
||||
|
||||
Light test_light_1 = test_bridge.lights().get(1);
|
||||
Light test_light_2 = test_bridge.lights().get(2);
|
||||
Light test_light_3 = test_bridge.lights().get(3);
|
||||
|
||||
EXPECT_EQ(false, test_light_1.setBrightness(200));
|
||||
EXPECT_EQ(true, test_light_2.setBrightness(0, 2));
|
||||
EXPECT_EQ(true, test_light_3.setBrightness(253, 0));
|
||||
}
|
||||
|
||||
TEST_F(HueLightTest, getBrightness)
|
||||
{
|
||||
const Light ctest_light_1 = test_bridge.lights().get(1);
|
||||
const Light ctest_light_2 = test_bridge.lights().get(2);
|
||||
const Light ctest_light_3 = test_bridge.lights().get(3);
|
||||
Light test_light_1 = test_bridge.lights().get(1);
|
||||
Light test_light_2 = test_bridge.lights().get(2);
|
||||
Light test_light_3 = test_bridge.lights().get(3);
|
||||
|
||||
EXPECT_EQ(254, ctest_light_1.getBrightness());
|
||||
EXPECT_EQ(0, ctest_light_2.getBrightness());
|
||||
EXPECT_EQ(254, ctest_light_3.getBrightness());
|
||||
EXPECT_EQ(254, test_light_1.getBrightness());
|
||||
EXPECT_EQ(0, test_light_2.getBrightness());
|
||||
EXPECT_EQ(254, test_light_3.getBrightness());
|
||||
}
|
||||
|
||||
TEST_F(HueLightTest, setColorTemperature)
|
||||
{
|
||||
using namespace ::testing;
|
||||
nlohmann::json prep_ret;
|
||||
prep_ret = nlohmann::json::array();
|
||||
prep_ret[2] = nlohmann::json::object();
|
||||
prep_ret[2]["success"] = nlohmann::json::object();
|
||||
prep_ret[2]["success"]["/lights/3/state/ct"] = 153;
|
||||
prep_ret[1] = nlohmann::json::object();
|
||||
prep_ret[1]["success"] = nlohmann::json::object();
|
||||
prep_ret[1]["success"]["/lights/3/state/on"] = true;
|
||||
prep_ret[0] = nlohmann::json::object();
|
||||
prep_ret[0]["success"] = nlohmann::json::object();
|
||||
prep_ret[0]["success"]["/lights/3/state/transitiontime"] = 0;
|
||||
EXPECT_CALL(*handler, PUTJson("/api/" + getBridgeUsername() + "/lights/3/state", _, getBridgeIp(), 80))
|
||||
.Times(1)
|
||||
.WillOnce(Return(prep_ret));
|
||||
|
||||
Light test_light_1 = test_bridge.lights().get(1);
|
||||
Light test_light_2 = test_bridge.lights().get(2);
|
||||
Light test_light_3 = test_bridge.lights().get(3);
|
||||
|
||||
EXPECT_EQ(false, test_light_1.setColorTemperature(153));
|
||||
EXPECT_EQ(false, test_light_2.setColorTemperature(400, 2));
|
||||
EXPECT_EQ(true, test_light_3.setColorTemperature(100, 0));
|
||||
}
|
||||
|
||||
TEST_F(HueLightTest, getColorTemperature)
|
||||
{
|
||||
const Light ctest_light_1 = test_bridge.lights().get(1);
|
||||
const Light ctest_light_2 = test_bridge.lights().get(2);
|
||||
const Light ctest_light_3 = test_bridge.lights().get(3);
|
||||
Light test_light_1 = test_bridge.lights().get(1);
|
||||
Light test_light_2 = test_bridge.lights().get(2);
|
||||
Light test_light_3 = test_bridge.lights().get(3);
|
||||
|
||||
EXPECT_EQ(0, ctest_light_1.getColorTemperature());
|
||||
EXPECT_EQ(0, ctest_light_2.getColorTemperature());
|
||||
EXPECT_EQ(366, ctest_light_3.getColorTemperature());
|
||||
EXPECT_EQ(0, test_light_1.getColorTemperature());
|
||||
EXPECT_EQ(0, test_light_2.getColorTemperature());
|
||||
EXPECT_EQ(366, test_light_3.getColorTemperature());
|
||||
}
|
||||
|
||||
TEST_F(HueLightTest, setColorHue)
|
||||
{
|
||||
using namespace ::testing;
|
||||
EXPECT_CALL(*handler, PUTJson("/api/" + getBridgeUsername() + "/lights/2/state", _, getBridgeIp(), 80))
|
||||
.Times(1)
|
||||
.WillOnce(Return(nlohmann::json::array()));
|
||||
nlohmann::json prep_ret;
|
||||
prep_ret = nlohmann::json::array();
|
||||
prep_ret[2] = nlohmann::json::object();
|
||||
prep_ret[2]["success"] = nlohmann::json::object();
|
||||
prep_ret[2]["success"]["/lights/3/state/hue"] = 65500;
|
||||
prep_ret[1] = nlohmann::json::object();
|
||||
prep_ret[1]["success"] = nlohmann::json::object();
|
||||
prep_ret[1]["success"]["/lights/3/state/on"] = true;
|
||||
prep_ret[0] = nlohmann::json::object();
|
||||
prep_ret[0]["success"] = nlohmann::json::object();
|
||||
prep_ret[0]["success"]["/lights/3/state/transitiontime"] = 0;
|
||||
EXPECT_CALL(*handler, PUTJson("/api/" + getBridgeUsername() + "/lights/3/state", _, getBridgeIp(), 80))
|
||||
.Times(1)
|
||||
.WillOnce(Return(prep_ret));
|
||||
|
||||
Light test_light_1 = test_bridge.lights().get(1);
|
||||
Light test_light_2 = test_bridge.lights().get(2);
|
||||
Light test_light_3 = test_bridge.lights().get(3);
|
||||
|
||||
EXPECT_EQ(false, test_light_1.setColorHue(153));
|
||||
EXPECT_EQ(false, test_light_2.setColorHue(30000, 2));
|
||||
EXPECT_EQ(true, test_light_3.setColorHue(65500, 0));
|
||||
}
|
||||
|
||||
TEST_F(HueLightTest, setColorSaturation)
|
||||
{
|
||||
using namespace ::testing;
|
||||
EXPECT_CALL(*handler, PUTJson("/api/" + getBridgeUsername() + "/lights/2/state", _, getBridgeIp(), 80))
|
||||
.Times(1)
|
||||
.WillOnce(Return(nlohmann::json::array()));
|
||||
nlohmann::json prep_ret;
|
||||
prep_ret = nlohmann::json::array();
|
||||
prep_ret[2] = nlohmann::json::object();
|
||||
prep_ret[2]["success"] = nlohmann::json::object();
|
||||
prep_ret[2]["success"]["/lights/3/state/sat"] = 250;
|
||||
prep_ret[1] = nlohmann::json::object();
|
||||
prep_ret[1]["success"] = nlohmann::json::object();
|
||||
prep_ret[1]["success"]["/lights/3/state/on"] = true;
|
||||
prep_ret[0] = nlohmann::json::object();
|
||||
prep_ret[0]["success"] = nlohmann::json::object();
|
||||
prep_ret[0]["success"]["/lights/3/state/transitiontime"] = 0;
|
||||
EXPECT_CALL(*handler, PUTJson("/api/" + getBridgeUsername() + "/lights/3/state", _, getBridgeIp(), 80))
|
||||
.Times(1)
|
||||
.WillOnce(Return(prep_ret));
|
||||
|
||||
Light test_light_1 = test_bridge.lights().get(1);
|
||||
Light test_light_2 = test_bridge.lights().get(2);
|
||||
Light test_light_3 = test_bridge.lights().get(3);
|
||||
|
||||
EXPECT_EQ(false, test_light_1.setColorSaturation(0));
|
||||
EXPECT_EQ(false, test_light_2.setColorSaturation(140, 2));
|
||||
EXPECT_EQ(true, test_light_3.setColorSaturation(250, 0));
|
||||
}
|
||||
|
||||
TEST_F(HueLightTest, setColorHueSaturation)
|
||||
{
|
||||
using namespace ::testing;
|
||||
EXPECT_CALL(*handler, PUTJson("/api/" + getBridgeUsername() + "/lights/2/state", _, getBridgeIp(), 80))
|
||||
.Times(1)
|
||||
.WillOnce(Return(nlohmann::json::array()));
|
||||
nlohmann::json prep_ret;
|
||||
prep_ret = nlohmann::json::array();
|
||||
prep_ret[0] = nlohmann::json::object();
|
||||
prep_ret[0]["success"] = nlohmann::json::object();
|
||||
prep_ret[0]["success"]["/lights/3/state/transitiontime"] = 0;
|
||||
prep_ret[1] = nlohmann::json::object();
|
||||
prep_ret[1]["success"] = nlohmann::json::object();
|
||||
prep_ret[1]["success"]["/lights/3/state/on"] = true;
|
||||
prep_ret[2] = nlohmann::json::object();
|
||||
prep_ret[2]["success"] = nlohmann::json::object();
|
||||
prep_ret[2]["success"]["/lights/3/state/hue"] = 65500;
|
||||
prep_ret[3] = nlohmann::json::object();
|
||||
prep_ret[3]["success"] = nlohmann::json::object();
|
||||
prep_ret[3]["success"]["/lights/3/state/sat"] = 250;
|
||||
EXPECT_CALL(*handler, PUTJson("/api/" + getBridgeUsername() + "/lights/3/state", _, getBridgeIp(), 80))
|
||||
.Times(1)
|
||||
.WillOnce(Return(prep_ret));
|
||||
|
||||
Light test_light_1 = test_bridge.lights().get(1);
|
||||
Light test_light_2 = test_bridge.lights().get(2);
|
||||
Light test_light_3 = test_bridge.lights().get(3);
|
||||
|
||||
EXPECT_EQ(false, test_light_1.setColorHueSaturation({153, 0}));
|
||||
EXPECT_EQ(false, test_light_2.setColorHueSaturation({30000, 140}, 2));
|
||||
EXPECT_EQ(true, test_light_3.setColorHueSaturation({65500, 250}, 0));
|
||||
}
|
||||
|
||||
TEST_F(HueLightTest, getColorHueSaturation)
|
||||
{
|
||||
const Light ctest_light_1 = test_bridge.lights().get(1);
|
||||
const Light ctest_light_2 = test_bridge.lights().get(2);
|
||||
const Light ctest_light_3 = test_bridge.lights().get(3);
|
||||
Light test_light_1 = test_bridge.lights().get(1);
|
||||
Light test_light_2 = test_bridge.lights().get(2);
|
||||
Light test_light_3 = test_bridge.lights().get(3);
|
||||
|
||||
EXPECT_EQ((HueSaturation {0, 0}), ctest_light_1.getColorHueSaturation());
|
||||
EXPECT_EQ((HueSaturation {12345, 123}), ctest_light_2.getColorHueSaturation());
|
||||
EXPECT_EQ((HueSaturation {12345, 123}), ctest_light_3.getColorHueSaturation());
|
||||
EXPECT_EQ((HueSaturation {0, 0}), test_light_1.getColorHueSaturation());
|
||||
EXPECT_EQ((HueSaturation {12345, 123}), test_light_2.getColorHueSaturation());
|
||||
EXPECT_EQ((HueSaturation {12345, 123}), test_light_3.getColorHueSaturation());
|
||||
}
|
||||
|
||||
TEST_F(HueLightTest, setColorXY)
|
||||
{
|
||||
using namespace ::testing;
|
||||
EXPECT_CALL(*handler, PUTJson("/api/" + getBridgeUsername() + "/lights/2/state", _, getBridgeIp(), 80))
|
||||
.Times(1)
|
||||
.WillOnce(Return(nlohmann::json::array()));
|
||||
nlohmann::json prep_ret;
|
||||
prep_ret = nlohmann::json::array();
|
||||
prep_ret[2] = nlohmann::json::object();
|
||||
prep_ret[2]["success"] = nlohmann::json::object();
|
||||
prep_ret[2]["success"]["/lights/3/state/xy"][0] = 0.4232;
|
||||
prep_ret[2]["success"]["/lights/3/state/xy"][1] = 0.1231;
|
||||
prep_ret[1] = nlohmann::json::object();
|
||||
prep_ret[1]["success"] = nlohmann::json::object();
|
||||
prep_ret[1]["success"]["/lights/3/state/on"] = true;
|
||||
prep_ret[0] = nlohmann::json::object();
|
||||
prep_ret[0]["success"] = nlohmann::json::object();
|
||||
prep_ret[0]["success"]["/lights/3/state/transitiontime"] = 0;
|
||||
EXPECT_CALL(*handler, PUTJson("/api/" + getBridgeUsername() + "/lights/3/state", _, getBridgeIp(), 80))
|
||||
.Times(1)
|
||||
.WillOnce(Return(prep_ret));
|
||||
|
||||
Light test_light_1 = test_bridge.lights().get(1);
|
||||
Light test_light_2 = test_bridge.lights().get(2);
|
||||
Light test_light_3 = test_bridge.lights().get(3);
|
||||
|
||||
EXPECT_EQ(false, test_light_1.setColorXY({{0.01f, 0.f}, 1.f}));
|
||||
EXPECT_EQ(false, test_light_2.setColorXY({{0.123f, 1.f}, 1.f}, 2));
|
||||
EXPECT_EQ(true, test_light_3.setColorXY({{0.4232f, 0.1231f}, 1.f}, 0));
|
||||
}
|
||||
|
||||
TEST_F(HueLightTest, getColorXY)
|
||||
{
|
||||
const Light ctest_light_1 = test_bridge.lights().get(1);
|
||||
const Light ctest_light_2 = test_bridge.lights().get(2);
|
||||
const Light ctest_light_3 = test_bridge.lights().get(3);
|
||||
Light test_light_1 = test_bridge.lights().get(1);
|
||||
Light test_light_2 = test_bridge.lights().get(2);
|
||||
Light test_light_3 = test_bridge.lights().get(3);
|
||||
EXPECT_EQ((XYBrightness {{0.f, 0.f}, 0.f}), ctest_light_1.getColorXY());
|
||||
EXPECT_EQ((XYBrightness {{0.102f, 0.102f}, 0.f}), ctest_light_2.getColorXY());
|
||||
EXPECT_EQ((XYBrightness {{0.102f, 0.102f}, 1.f}), ctest_light_3.getColorXY());
|
||||
EXPECT_EQ((XYBrightness {{0.f, 0.f}, 0.f}), test_light_1.getColorXY());
|
||||
EXPECT_EQ((XYBrightness {{0.102f, 0.102f}, 0.f}), test_light_2.getColorXY());
|
||||
EXPECT_EQ((XYBrightness {{0.102f, 0.102f}, 1.f}), test_light_3.getColorXY());
|
||||
}
|
||||
|
||||
TEST_F(HueLightTest, setColorRGB)
|
||||
{
|
||||
using namespace ::testing;
|
||||
EXPECT_CALL(*handler, PUTJson("/api/" + getBridgeUsername() + "/lights/2/state", _, getBridgeIp(), 80))
|
||||
.Times(1)
|
||||
.WillOnce(Return(nlohmann::json::array()));
|
||||
nlohmann::json prep_ret;
|
||||
prep_ret = nlohmann::json::array();
|
||||
prep_ret[2] = nlohmann::json::object();
|
||||
prep_ret[2]["success"] = nlohmann::json::object();
|
||||
prep_ret[2]["success"]["/lights/3/state/xy"][0] = 0.1596;
|
||||
prep_ret[2]["success"]["/lights/3/state/xy"][1] = 0.1437;
|
||||
prep_ret[1] = nlohmann::json::object();
|
||||
prep_ret[1]["success"] = nlohmann::json::object();
|
||||
prep_ret[1]["success"]["/lights/3/state/on"] = true;
|
||||
prep_ret[0] = nlohmann::json::object();
|
||||
prep_ret[0]["success"] = nlohmann::json::object();
|
||||
prep_ret[0]["success"]["/lights/3/state/transitiontime"] = 0;
|
||||
EXPECT_CALL(*handler, PUTJson("/api/" + getBridgeUsername() + "/lights/3/state", _, getBridgeIp(), 80))
|
||||
.Times(1)
|
||||
.WillOnce(Return(prep_ret));
|
||||
|
||||
Light test_light_1 = test_bridge.lights().get(1);
|
||||
Light test_light_2 = test_bridge.lights().get(2);
|
||||
Light test_light_3 = test_bridge.lights().get(3);
|
||||
|
||||
EXPECT_EQ(false, test_light_1.setColorRGB({0, 0, 0}, 0));
|
||||
EXPECT_EQ(false, test_light_2.setColorRGB({32, 64, 128}, 2));
|
||||
EXPECT_EQ(true, test_light_3.setColorRGB({64, 128, 255}, 0));
|
||||
}
|
||||
|
||||
TEST_F(HueLightTest, alert)
|
||||
{
|
||||
using namespace ::testing;
|
||||
EXPECT_CALL(*handler, PUTJson("/api/" + getBridgeUsername() + "/lights/1/state", _, getBridgeIp(), 80))
|
||||
.Times(1)
|
||||
.WillOnce(Return(nlohmann::json::array()));
|
||||
EXPECT_CALL(*handler, PUTJson("/api/" + getBridgeUsername() + "/lights/2/state", _, getBridgeIp(), 80))
|
||||
.Times(1)
|
||||
.WillOnce(Return(nlohmann::json::array()));
|
||||
nlohmann::json prep_ret;
|
||||
prep_ret = nlohmann::json::array();
|
||||
prep_ret[0] = nlohmann::json::object();
|
||||
prep_ret[0]["success"] = nlohmann::json::object();
|
||||
prep_ret[0]["success"]["/lights/3/state/alert"] = "select";
|
||||
EXPECT_CALL(*handler, PUTJson("/api/" + getBridgeUsername() + "/lights/3/state", _, getBridgeIp(), 80))
|
||||
.Times(1)
|
||||
.WillOnce(Return(prep_ret));
|
||||
|
||||
Light test_light_1 = test_bridge.lights().get(1);
|
||||
Light test_light_2 = test_bridge.lights().get(2);
|
||||
Light test_light_3 = test_bridge.lights().get(3);
|
||||
|
||||
EXPECT_EQ(false, test_light_1.alert());
|
||||
EXPECT_EQ(false, test_light_2.alert());
|
||||
EXPECT_EQ(true, test_light_3.alert());
|
||||
}
|
||||
|
||||
TEST_F(HueLightTest, alertTemperature)
|
||||
{
|
||||
using namespace ::testing;
|
||||
EXPECT_CALL(*handler, PUTJson("/api/" + getBridgeUsername() + "/lights/3/state", _, getBridgeIp(), 80))
|
||||
.Times(1)
|
||||
.WillOnce(Return(nlohmann::json::array()));
|
||||
|
||||
Light test_light_1 = test_bridge.lights().get(1);
|
||||
Light test_light_2 = test_bridge.lights().get(2);
|
||||
Light test_light_3 = test_bridge.lights().get(3);
|
||||
|
||||
EXPECT_EQ(false, test_light_1.alertTemperature(400));
|
||||
EXPECT_EQ(false, test_light_2.alertTemperature(100));
|
||||
EXPECT_EQ(false, test_light_3.alertTemperature(0));
|
||||
}
|
||||
|
||||
TEST_F(HueLightTest, alertHueSaturation)
|
||||
{
|
||||
using namespace ::testing;
|
||||
EXPECT_CALL(*handler, PUTJson("/api/" + getBridgeUsername() + "/lights/3/state", _, getBridgeIp(), 80))
|
||||
.Times(1)
|
||||
.WillOnce(Return(nlohmann::json::array()));
|
||||
|
||||
Light test_light_1 = test_bridge.lights().get(1);
|
||||
Light test_light_2 = test_bridge.lights().get(2);
|
||||
Light test_light_3 = test_bridge.lights().get(3);
|
||||
|
||||
EXPECT_EQ(false, test_light_1.alertHueSaturation({0, 255}));
|
||||
EXPECT_EQ(false, test_light_2.alertHueSaturation({3000, 100}));
|
||||
EXPECT_EQ(false, test_light_3.alertHueSaturation({50000, 0}));
|
||||
}
|
||||
|
||||
TEST_F(HueLightTest, alertXY)
|
||||
{
|
||||
using namespace ::testing;
|
||||
EXPECT_CALL(*handler, PUTJson("/api/" + getBridgeUsername() + "/lights/3/state", _, getBridgeIp(), 80))
|
||||
.Times(1)
|
||||
.WillOnce(Return(nlohmann::json::array()));
|
||||
|
||||
Light test_light_1 = test_bridge.lights().get(1);
|
||||
Light test_light_2 = test_bridge.lights().get(2);
|
||||
Light test_light_3 = test_bridge.lights().get(3);
|
||||
|
||||
EXPECT_EQ(false, test_light_1.alertXY({{0.1f, 0.1f}, 1.f}));
|
||||
EXPECT_EQ(false, test_light_2.alertXY({{0.2434f, 0.2344f}, 1.f}));
|
||||
EXPECT_EQ(false, test_light_3.alertXY({{0.1234f, 0.1234f}, 1.f}));
|
||||
}
|
||||
|
||||
TEST_F(HueLightTest, setColorLoop)
|
||||
{
|
||||
using namespace ::testing;
|
||||
EXPECT_CALL(*handler, PUTJson("/api/" + getBridgeUsername() + "/lights/2/state", _, getBridgeIp(), 80))
|
||||
.Times(1)
|
||||
.WillOnce(Return(nlohmann::json::array()));
|
||||
EXPECT_CALL(*handler, PUTJson("/api/" + getBridgeUsername() + "/lights/3/state", _, getBridgeIp(), 80))
|
||||
.Times(1)
|
||||
.WillOnce(Return(nlohmann::json::array()));
|
||||
|
||||
Light test_light_1 = test_bridge.lights().get(1);
|
||||
Light test_light_2 = test_bridge.lights().get(2);
|
||||
Light test_light_3 = test_bridge.lights().get(3);
|
||||
|
||||
EXPECT_EQ(false, test_light_1.setColorLoop(true));
|
||||
EXPECT_EQ(false, test_light_2.setColorLoop(false));
|
||||
EXPECT_EQ(false, test_light_3.setColorLoop(true));
|
||||
}
|
||||
@@ -0,0 +1,174 @@
|
||||
/**
|
||||
\file test_HueLightFactory.cpp
|
||||
Copyright Notice\n
|
||||
Copyright (C) 2020 Jan Rogall - developer\n
|
||||
Copyright (C) 2020 Moritz Wirger - developer\n
|
||||
|
||||
This file is part of hueplusplus.
|
||||
|
||||
hueplusplus 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.
|
||||
|
||||
hueplusplus 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 hueplusplus. If not, see <http://www.gnu.org/licenses/>.
|
||||
**/
|
||||
|
||||
#include <hueplusplus/HueDeviceTypes.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "testhelper.h"
|
||||
|
||||
#include "mocks/mock_HttpHandler.h"
|
||||
|
||||
using namespace hueplusplus;
|
||||
|
||||
TEST(LightFactory, createLight_noGamut)
|
||||
{
|
||||
using namespace ::testing;
|
||||
std::shared_ptr<MockHttpHandler> handler = std::make_shared<MockHttpHandler>();
|
||||
|
||||
LightFactory factory(HueCommandAPI(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler),
|
||||
std::chrono::steady_clock::duration::max());
|
||||
|
||||
nlohmann::json lightState
|
||||
= {{"state",
|
||||
{{"on", true}, {"bri", 254}, {"ct", 366}, {"alert", "none"}, {"colormode", "ct"}, {"reachable", true}}},
|
||||
{"swupdate", {{"state", "noupdates"}, {"lastinstall", nullptr}}}, {"type", "Color temperature light"},
|
||||
{"name", "Hue ambiance lamp 1"}, {"modelid", "LTW001"}, {"manufacturername", "Philips"},
|
||||
{"uniqueid", "00:00:00:00:00:00:00:00-00"}, {"swversion", "5.50.1.19085"}};
|
||||
|
||||
Light test_light_1 = factory.createLight(lightState, 1);
|
||||
EXPECT_EQ(test_light_1.getColorType(), ColorType::TEMPERATURE);
|
||||
|
||||
lightState["type"] = "Dimmable light";
|
||||
|
||||
test_light_1 = factory.createLight(lightState, 1);
|
||||
EXPECT_EQ(test_light_1.getColorType(), ColorType::NONE);
|
||||
|
||||
lightState["type"] = "On/Off light";
|
||||
|
||||
test_light_1 = factory.createLight(lightState, 1);
|
||||
EXPECT_EQ(test_light_1.getColorType(), ColorType::NONE);
|
||||
|
||||
lightState["type"] = "unknown light type";
|
||||
ASSERT_THROW(factory.createLight(lightState, 1), HueException);
|
||||
}
|
||||
|
||||
TEST(LightFactory, createLight_gamutCapabilities)
|
||||
{
|
||||
using namespace ::testing;
|
||||
std::shared_ptr<MockHttpHandler> handler = std::make_shared<MockHttpHandler>();
|
||||
|
||||
LightFactory factory(HueCommandAPI(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler),
|
||||
std::chrono::steady_clock::duration::max());
|
||||
|
||||
nlohmann::json lightState
|
||||
= {{"state",
|
||||
{{"on", true}, {"bri", 254}, {"ct", 366}, {"alert", "none"}, {"colormode", "ct"}, {"reachable", true}}},
|
||||
{"swupdate", {{"state", "noupdates"}, {"lastinstall", nullptr}}}, {"type", "Color light"},
|
||||
{"name", "Hue ambiance lamp 1"}, {"modelid", "LTW001"}, {"manufacturername", "Philips"},
|
||||
{"uniqueid", "00:00:00:00:00:00:00:00-00"}, {"swversion", "5.50.1.19085"},
|
||||
{"capabilities", {{"control", {{"colorgamuttype", "A"}}}}}};
|
||||
|
||||
Light test_light_1 = factory.createLight(lightState, 1);
|
||||
EXPECT_EQ(test_light_1.getColorType(), ColorType::GAMUT_A);
|
||||
|
||||
lightState["capabilities"]["control"]["colorgamuttype"] = "B";
|
||||
|
||||
test_light_1 = factory.createLight(lightState, 1);
|
||||
EXPECT_EQ(test_light_1.getColorType(), ColorType::GAMUT_B);
|
||||
|
||||
lightState["capabilities"]["control"]["colorgamuttype"] = "C";
|
||||
|
||||
test_light_1 = factory.createLight(lightState, 1);
|
||||
EXPECT_EQ(test_light_1.getColorType(), ColorType::GAMUT_C);
|
||||
|
||||
lightState["capabilities"]["control"]["colorgamuttype"] = "Other";
|
||||
|
||||
test_light_1 = factory.createLight(lightState, 1);
|
||||
EXPECT_EQ(test_light_1.getColorType(), ColorType::GAMUT_OTHER);
|
||||
|
||||
// With color temperature
|
||||
lightState["type"] = "Extended color light";
|
||||
lightState["capabilities"]["control"]["colorgamuttype"] = "A";
|
||||
|
||||
test_light_1 = factory.createLight(lightState, 1);
|
||||
EXPECT_EQ(test_light_1.getColorType(), ColorType::GAMUT_A_TEMPERATURE);
|
||||
|
||||
lightState["capabilities"]["control"]["colorgamuttype"] = "B";
|
||||
|
||||
test_light_1 = factory.createLight(lightState, 1);
|
||||
EXPECT_EQ(test_light_1.getColorType(), ColorType::GAMUT_B_TEMPERATURE);
|
||||
|
||||
lightState["capabilities"]["control"]["colorgamuttype"] = "C";
|
||||
|
||||
test_light_1 = factory.createLight(lightState, 1);
|
||||
EXPECT_EQ(test_light_1.getColorType(), ColorType::GAMUT_C_TEMPERATURE);
|
||||
|
||||
lightState["capabilities"]["control"]["colorgamuttype"] = "Other";
|
||||
|
||||
test_light_1 = factory.createLight(lightState, 1);
|
||||
EXPECT_EQ(test_light_1.getColorType(), ColorType::GAMUT_OTHER_TEMPERATURE);
|
||||
}
|
||||
|
||||
TEST(LightFactory, createLight_gamutModelid)
|
||||
{
|
||||
using namespace ::testing;
|
||||
std::shared_ptr<MockHttpHandler> handler = std::make_shared<MockHttpHandler>();
|
||||
|
||||
LightFactory factory(HueCommandAPI(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler),
|
||||
std::chrono::steady_clock::duration::max());
|
||||
|
||||
const std::string gamutAModel = "LST001";
|
||||
const std::string gamutBModel = "LCT001";
|
||||
const std::string gamutCModel = "LCT010";
|
||||
|
||||
nlohmann::json lightState
|
||||
= {{"state",
|
||||
{{"on", true}, {"bri", 254}, {"ct", 366}, {"alert", "none"}, {"colormode", "ct"}, {"reachable", true}}},
|
||||
{"swupdate", {{"state", "noupdates"}, {"lastinstall", nullptr}}}, {"type", "Color light"},
|
||||
{"name", "Hue ambiance lamp 1"}, {"modelid", gamutAModel}, {"manufacturername", "Philips"},
|
||||
{"uniqueid", "00:00:00:00:00:00:00:00-00"}, {"swversion", "5.50.1.19085"}};
|
||||
|
||||
Light test_light_1 = factory.createLight(lightState, 1);
|
||||
EXPECT_EQ(test_light_1.getColorType(), ColorType::GAMUT_A);
|
||||
|
||||
lightState["modelid"] = gamutBModel;
|
||||
test_light_1 = factory.createLight(lightState, 1);
|
||||
EXPECT_EQ(test_light_1.getColorType(), ColorType::GAMUT_B);
|
||||
|
||||
lightState["modelid"] = gamutCModel;
|
||||
|
||||
test_light_1 = factory.createLight(lightState, 1);
|
||||
EXPECT_EQ(test_light_1.getColorType(), ColorType::GAMUT_C);
|
||||
|
||||
// With color temperature
|
||||
lightState["type"] = "Extended color light";
|
||||
lightState["modelid"] = gamutAModel;
|
||||
|
||||
test_light_1 = factory.createLight(lightState, 1);
|
||||
EXPECT_EQ(test_light_1.getColorType(), ColorType::GAMUT_A_TEMPERATURE);
|
||||
|
||||
lightState["modelid"] = gamutBModel;
|
||||
|
||||
test_light_1 = factory.createLight(lightState, 1);
|
||||
EXPECT_EQ(test_light_1.getColorType(), ColorType::GAMUT_B_TEMPERATURE);
|
||||
|
||||
lightState["modelid"] = gamutCModel;
|
||||
|
||||
test_light_1 = factory.createLight(lightState, 1);
|
||||
EXPECT_EQ(test_light_1.getColorType(), ColorType::GAMUT_C_TEMPERATURE);
|
||||
|
||||
// Unknown model
|
||||
lightState["modelid"] = "Unknown model";
|
||||
test_light_1 = factory.createLight(lightState, 1);
|
||||
EXPECT_EQ(test_light_1.getColorType(), ColorType::UNDEFINED);
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/**
|
||||
\file test_Main.cpp
|
||||
Copyright Notice\n
|
||||
Copyright (C) 2017 Jan Rogall - developer\n
|
||||
Copyright (C) 2017 Moritz Wirger - developer\n
|
||||
|
||||
This file is part of hueplusplus.
|
||||
|
||||
hueplusplus 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.
|
||||
|
||||
hueplusplus 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 hueplusplus. If not, see <http://www.gnu.org/licenses/>.
|
||||
**/
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <hueplusplus/LibConfig.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
class TestConfig : public hueplusplus::Config
|
||||
{
|
||||
public:
|
||||
TestConfig()
|
||||
{
|
||||
preAlertDelay = postAlertDelay = upnpTimeout = bridgeRequestDelay = requestUsernameDelay
|
||||
= requestUsernameAttemptInterval = std::chrono::seconds(0);
|
||||
}
|
||||
};
|
||||
|
||||
// Environment sets config to disable all delays and speed up tests
|
||||
class Environment : public ::testing::Environment
|
||||
{
|
||||
public:
|
||||
~Environment() override {}
|
||||
|
||||
void SetUp() override { hueplusplus::Config::instance() = TestConfig(); }
|
||||
|
||||
void TearDown() override {}
|
||||
};
|
||||
} // namespace
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
::testing::AddGlobalTestEnvironment(new Environment());
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/**
|
||||
\file test_NewDeviceList.cpp
|
||||
Copyright Notice\n
|
||||
Copyright (C) 2020 Jan Rogall - developer\n
|
||||
|
||||
This file is part of hueplusplus.
|
||||
|
||||
hueplusplus 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.
|
||||
|
||||
hueplusplus 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 hueplusplus. If not, see <http://www.gnu.org/licenses/>.
|
||||
**/
|
||||
|
||||
#include <hueplusplus/HueException.h>
|
||||
#include <hueplusplus/NewDeviceList.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
using namespace hueplusplus;
|
||||
using namespace testing;
|
||||
|
||||
TEST(NewDeviceList, Constructor)
|
||||
{
|
||||
{
|
||||
NewDeviceList list("none", {});
|
||||
EXPECT_TRUE(list.getNewDevices().empty());
|
||||
EXPECT_FALSE(list.hasLastScanTime());
|
||||
EXPECT_FALSE(list.isScanActive());
|
||||
EXPECT_THROW(list.getLastScanTime(), HueException);
|
||||
}
|
||||
{
|
||||
const std::map<int, std::string> devices = {{1, "a"}, {2, "b"}, {3, "c"}};
|
||||
NewDeviceList list("active", devices);
|
||||
EXPECT_FALSE(list.hasLastScanTime());
|
||||
EXPECT_TRUE(list.isScanActive());
|
||||
EXPECT_EQ(devices, list.getNewDevices());
|
||||
EXPECT_THROW(list.getLastScanTime(), HueException);
|
||||
}
|
||||
{
|
||||
const std::string timestamp = "2020-03-01T00:10:00";
|
||||
NewDeviceList list(timestamp, {});
|
||||
EXPECT_TRUE(list.hasLastScanTime());
|
||||
EXPECT_FALSE(list.isScanActive());
|
||||
EXPECT_EQ(time::AbsoluteTime::parseUTC(timestamp).getBaseTime(), list.getLastScanTime().getBaseTime());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(NewDeviceList, parse)
|
||||
{
|
||||
{
|
||||
NewDeviceList list = NewDeviceList::parse({});
|
||||
EXPECT_FALSE(list.hasLastScanTime());
|
||||
EXPECT_FALSE(list.isScanActive());
|
||||
EXPECT_TRUE(list.getNewDevices().empty());
|
||||
EXPECT_THROW(list.getLastScanTime(), HueException);
|
||||
}
|
||||
{
|
||||
const std::map<int, std::string> devices = {{1, "a"}, {2, "b"}, {3, "c"}};
|
||||
const std::string timestamp = "2020-03-01T00:10:00";
|
||||
NewDeviceList list = NewDeviceList::parse(
|
||||
{{"1", {{"name", "a"}}}, {"2", {{"name", "b"}}}, {"3", {{"name", "c"}}}, {"lastscan", timestamp}});
|
||||
EXPECT_TRUE(list.hasLastScanTime());
|
||||
EXPECT_FALSE(list.isScanActive());
|
||||
EXPECT_EQ(time::AbsoluteTime::parseUTC(timestamp).getBaseTime(), list.getLastScanTime().getBaseTime());
|
||||
EXPECT_EQ(devices, list.getNewDevices());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,300 @@
|
||||
/**
|
||||
\file test_ResourceList.cpp
|
||||
Copyright Notice\n
|
||||
Copyright (C) 2020 Jan Rogall - developer\n
|
||||
|
||||
This file is part of hueplusplus.
|
||||
|
||||
hueplusplus 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.
|
||||
|
||||
hueplusplus 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 hueplusplus. If not, see <http://www.gnu.org/licenses/>.
|
||||
**/
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "testhelper.h"
|
||||
|
||||
#include "hueplusplus/ResourceList.h"
|
||||
#include "mocks/mock_HttpHandler.h"
|
||||
|
||||
using namespace hueplusplus;
|
||||
using namespace testing;
|
||||
|
||||
class TestResource
|
||||
{
|
||||
public:
|
||||
TestResource(int id, std::shared_ptr<APICache> baseCache) {}
|
||||
TestResource(int id, HueCommandAPI api, std::chrono::steady_clock::duration refreshDuration, const nlohmann::json& currentState) : id(id) { }
|
||||
|
||||
void refresh(bool force = false) { }
|
||||
|
||||
public:
|
||||
int id;
|
||||
};
|
||||
class TestResourceFactory
|
||||
{
|
||||
public:
|
||||
void refresh(bool force = false) { }
|
||||
};
|
||||
class TestStringResource
|
||||
{
|
||||
public:
|
||||
TestStringResource(const std::string& id, std::shared_ptr<APICache> baseCache) {}
|
||||
TestStringResource(const std::string& id, HueCommandAPI api, std::chrono::steady_clock::duration refreshDuration, const nlohmann::json& currentState)
|
||||
: id(id)
|
||||
{ }
|
||||
void refresh(bool force = false) { }
|
||||
|
||||
public:
|
||||
std::string id;
|
||||
};
|
||||
|
||||
class TestCreateType
|
||||
{
|
||||
public:
|
||||
MOCK_CONST_METHOD0(getRequest, nlohmann::json());
|
||||
};
|
||||
|
||||
TEST(ResourceList, refresh)
|
||||
{
|
||||
auto handler = std::make_shared<MockHttpHandler>();
|
||||
HueCommandAPI commands(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler);
|
||||
|
||||
const std::string path = "/resources";
|
||||
{
|
||||
ResourceList<TestResource, int> list(commands, path, std::chrono::steady_clock::duration::max());
|
||||
EXPECT_CALL(*handler,
|
||||
GETJson("/api/" + getBridgeUsername() + path, nlohmann::json::object(), getBridgeIp(), getBridgePort()))
|
||||
.Times(2)
|
||||
.WillRepeatedly(Return(nlohmann::json::object()));
|
||||
list.refresh();
|
||||
list.refresh();
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
}
|
||||
{
|
||||
auto baseCache = std::make_shared<APICache>("", commands, std::chrono::steady_clock::duration::max(), nullptr);
|
||||
ResourceList<TestResource, int> list(baseCache, "resources", std::chrono::steady_clock::duration::max());
|
||||
InSequence s;
|
||||
EXPECT_CALL(
|
||||
*handler, GETJson("/api/" + getBridgeUsername(), nlohmann::json::object(), getBridgeIp(), getBridgePort()))
|
||||
.WillOnce(Return(nlohmann::json {{"resources", nlohmann::json::object()}}));
|
||||
EXPECT_CALL(*handler,
|
||||
GETJson("/api/" + getBridgeUsername() + path, nlohmann::json::object(), getBridgeIp(), getBridgePort()))
|
||||
.Times(2)
|
||||
.WillRepeatedly(Return(nlohmann::json::object()));
|
||||
list.refresh();
|
||||
list.refresh();
|
||||
list.refresh();
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(ResourceList, get)
|
||||
{
|
||||
auto handler = std::make_shared<MockHttpHandler>();
|
||||
HueCommandAPI commands(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler);
|
||||
|
||||
const std::string path = "/resources";
|
||||
// No factory
|
||||
{
|
||||
const int id = 2;
|
||||
const nlohmann::json response = {{std::to_string(id), {{"resource", "state"}}}};
|
||||
ResourceList<TestResource, int> list(commands, path, std::chrono::steady_clock::duration::max());
|
||||
EXPECT_CALL(*handler,
|
||||
GETJson("/api/" + getBridgeUsername() + path, nlohmann::json::object(), getBridgeIp(), getBridgePort()))
|
||||
.WillOnce(Return(response));
|
||||
|
||||
TestResource r = list.get(id);
|
||||
EXPECT_EQ(id, r.id);
|
||||
TestResource r2 = list.get(id);
|
||||
EXPECT_EQ(id, r2.id);
|
||||
}
|
||||
// With factory
|
||||
{
|
||||
const int id = 2;
|
||||
const nlohmann::json state = {{"resource", "state"}};
|
||||
const nlohmann::json response = {{std::to_string(id), state}};
|
||||
|
||||
MockFunction<TestResource(int, const nlohmann::json&, const std::shared_ptr<APICache>&)> factory;
|
||||
EXPECT_CALL(factory, Call(id, state, std::shared_ptr<APICache>()))
|
||||
.WillOnce(Return(TestResource(id, commands, std::chrono::steady_clock::duration::max(), nullptr)));
|
||||
|
||||
ResourceList<TestResource, int> list(
|
||||
commands, path, std::chrono::steady_clock::duration::max(), factory.AsStdFunction());
|
||||
EXPECT_CALL(*handler,
|
||||
GETJson("/api/" + getBridgeUsername() + path, nlohmann::json::object(), getBridgeIp(), getBridgePort()))
|
||||
.WillOnce(Return(response));
|
||||
|
||||
TestResource r = list.get(id);
|
||||
EXPECT_EQ(id, r.id);
|
||||
}
|
||||
// String id without factory
|
||||
{
|
||||
const std::string id = "id-2";
|
||||
const nlohmann::json response = {{id, {{"resource", "state"}}}};
|
||||
ResourceList<TestStringResource, std::string> list(commands, path, std::chrono::steady_clock::duration::max());
|
||||
EXPECT_CALL(*handler,
|
||||
GETJson("/api/" + getBridgeUsername() + path, nlohmann::json::object(), getBridgeIp(), getBridgePort()))
|
||||
.WillOnce(Return(response));
|
||||
|
||||
TestStringResource r = list.get(id);
|
||||
EXPECT_EQ(id, r.id);
|
||||
TestStringResource r2 = list.get(id);
|
||||
EXPECT_EQ(id, r2.id);
|
||||
}
|
||||
|
||||
{
|
||||
ResourceList<TestResourceFactory, int> list(commands, path, std::chrono::steady_clock::duration::max());
|
||||
|
||||
const int id = 2;
|
||||
const nlohmann::json response = {{std::to_string(id), {{"resource", "state"}}}};
|
||||
EXPECT_CALL(*handler,
|
||||
GETJson("/api/" + getBridgeUsername() + path, nlohmann::json::object(), getBridgeIp(), getBridgePort()))
|
||||
.WillOnce(Return(response));
|
||||
EXPECT_THROW(list.get(id), HueException);
|
||||
}
|
||||
{
|
||||
ResourceList<TestResourceFactory, int> list(commands, path, std::chrono::steady_clock::duration::max(),
|
||||
[](int, const nlohmann::json&, const std::shared_ptr<APICache>&) { return TestResourceFactory(); });
|
||||
|
||||
const int id = 2;
|
||||
const nlohmann::json response = {{std::to_string(id), {{"resource", "state"}}}};
|
||||
EXPECT_CALL(*handler,
|
||||
GETJson("/api/" + getBridgeUsername() + path, nlohmann::json::object(), getBridgeIp(), getBridgePort()))
|
||||
.WillOnce(Return(response));
|
||||
EXPECT_NO_THROW(list.get(id));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(ResourceList, exists)
|
||||
{
|
||||
auto handler = std::make_shared<MockHttpHandler>();
|
||||
HueCommandAPI commands(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler);
|
||||
|
||||
const std::string path = "/resources";
|
||||
const int id = 2;
|
||||
const nlohmann::json response = {{std::to_string(id), {{"resource", "state"}}}};
|
||||
ResourceList<TestResource, int> list(commands, path, std::chrono::steady_clock::duration::max());
|
||||
EXPECT_CALL(*handler,
|
||||
GETJson("/api/" + getBridgeUsername() + path, nlohmann::json::object(), getBridgeIp(), getBridgePort()))
|
||||
.WillOnce(Return(response));
|
||||
list.refresh();
|
||||
EXPECT_TRUE(list.exists(id));
|
||||
EXPECT_FALSE(list.exists(4));
|
||||
}
|
||||
|
||||
TEST(ResourceList, getAll)
|
||||
{
|
||||
auto handler = std::make_shared<MockHttpHandler>();
|
||||
HueCommandAPI commands(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler);
|
||||
|
||||
const std::string path = "/resources";
|
||||
|
||||
const int id = 2;
|
||||
const nlohmann::json response = {{std::to_string(id), {{"resource", "state"}}}};
|
||||
ResourceList<TestResource, int> list(commands, path, std::chrono::steady_clock::duration::max());
|
||||
EXPECT_CALL(*handler,
|
||||
GETJson("/api/" + getBridgeUsername() + path, nlohmann::json::object(), getBridgeIp(), getBridgePort()))
|
||||
.WillOnce(Return(response));
|
||||
|
||||
auto resources = list.getAll();
|
||||
EXPECT_THAT(resources, ElementsAre(testing::Field("id", &TestResource::id, Eq(id))));
|
||||
|
||||
const int id2 = 3;
|
||||
const nlohmann::json response2 = {{std::to_string(id), {{"r", "s"}}}, {std::to_string(id2), {{"b", "c"}}}};
|
||||
|
||||
EXPECT_CALL(*handler,
|
||||
GETJson("/api/" + getBridgeUsername() + path, nlohmann::json::object(), getBridgeIp(), getBridgePort()))
|
||||
.WillOnce(Return(response2));
|
||||
list.refresh();
|
||||
auto resources2 = list.getAll();
|
||||
EXPECT_THAT(resources2,
|
||||
ElementsAre(testing::Field("id", &TestResource::id, Eq(id)), testing::Field("id", &TestResource::id, Eq(id2))));
|
||||
}
|
||||
|
||||
TEST(ResourceList, remove)
|
||||
{
|
||||
auto handler = std::make_shared<MockHttpHandler>();
|
||||
HueCommandAPI commands(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler);
|
||||
|
||||
const std::string path = "/resources";
|
||||
const int id = 2;
|
||||
const std::string requestPath = path + "/" + std::to_string(id);
|
||||
const nlohmann::json response = {{{"success", requestPath + " deleted"}}};
|
||||
ResourceList<TestResource, int> list(commands, path, std::chrono::steady_clock::duration::max());
|
||||
EXPECT_CALL(*handler,
|
||||
DELETEJson(
|
||||
"/api/" + getBridgeUsername() + requestPath, nlohmann::json::object(), getBridgeIp(), getBridgePort()))
|
||||
.WillOnce(Return(response))
|
||||
.WillOnce(Return(nlohmann::json()));
|
||||
EXPECT_TRUE(list.remove(id));
|
||||
EXPECT_FALSE(list.remove(id));
|
||||
}
|
||||
|
||||
TEST(SearchableResourceList, search)
|
||||
{
|
||||
auto handler = std::make_shared<MockHttpHandler>();
|
||||
HueCommandAPI commands(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler);
|
||||
|
||||
const std::string path = "/resources";
|
||||
SearchableResourceList<TestResource> list(commands, path, std::chrono::steady_clock::duration::max());
|
||||
const nlohmann::json response = {{{"success", {{path, "Searching for new devices"}}}}};
|
||||
EXPECT_CALL(*handler,
|
||||
POSTJson("/api/" + getBridgeUsername() + path, nlohmann::json::object(), getBridgeIp(), getBridgePort()))
|
||||
.WillOnce(Return(response));
|
||||
list.search();
|
||||
|
||||
EXPECT_CALL(*handler,
|
||||
POSTJson("/api/" + getBridgeUsername() + path, nlohmann::json({{"deviceid", {"abcd", "def", "fgh"}}}),
|
||||
getBridgeIp(), getBridgePort()))
|
||||
.WillOnce(Return(response));
|
||||
list.search({"abcd", "def", "fgh"});
|
||||
}
|
||||
|
||||
TEST(SearchableResourceList, getNewDevices)
|
||||
{
|
||||
auto handler = std::make_shared<MockHttpHandler>();
|
||||
HueCommandAPI commands(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler);
|
||||
|
||||
const std::string path = "/resources";
|
||||
SearchableResourceList<TestResource> list(commands, path, std::chrono::steady_clock::duration::max());
|
||||
const nlohmann::json response = {{"lastscan", "active"}, {"1", {{"name", "A"}}}};
|
||||
EXPECT_CALL(*handler,
|
||||
GETJson(
|
||||
"/api/" + getBridgeUsername() + path + "/new", nlohmann::json::object(), getBridgeIp(), getBridgePort()))
|
||||
.WillOnce(Return(response));
|
||||
NewDeviceList newDevices = list.getNewDevices();
|
||||
EXPECT_TRUE(newDevices.isScanActive());
|
||||
EXPECT_THAT(newDevices.getNewDevices(), ElementsAre(std::make_pair(1, "A")));
|
||||
}
|
||||
|
||||
TEST(CreateableResourceList, create)
|
||||
{
|
||||
auto handler = std::make_shared<MockHttpHandler>();
|
||||
HueCommandAPI commands(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler);
|
||||
|
||||
const std::string path = "/resources";
|
||||
const nlohmann::json response = {{{"success", {{"id", path + "/2"}}}}};
|
||||
const nlohmann::json request = {{"name", "bla"}};
|
||||
CreateableResourceList<ResourceList<TestResource, int>, TestCreateType> list(
|
||||
commands, path, std::chrono::steady_clock::duration::max());
|
||||
EXPECT_CALL(*handler, POSTJson("/api/" + getBridgeUsername() + path, request, getBridgeIp(), getBridgePort()))
|
||||
.WillOnce(Return(response))
|
||||
.WillOnce(Return(nlohmann::json()));
|
||||
EXPECT_CALL(*handler, GETJson("/api/" + getBridgeUsername() + path, _, getBridgeIp(), getBridgePort()))
|
||||
.Times(AnyNumber())
|
||||
.WillRepeatedly(Return(nlohmann::json::object()));
|
||||
TestCreateType params;
|
||||
EXPECT_CALL(params, getRequest()).Times(2).WillRepeatedly(Return(request));
|
||||
EXPECT_EQ(2, list.create(params));
|
||||
EXPECT_EQ(0, list.create(params));
|
||||
}
|
||||
+270
@@ -0,0 +1,270 @@
|
||||
/**
|
||||
\file test_Rule.cpp
|
||||
Copyright Notice\n
|
||||
Copyright (C) 2020 Jan Rogall - developer\n
|
||||
|
||||
This file is part of hueplusplus.
|
||||
|
||||
hueplusplus 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.
|
||||
|
||||
hueplusplus 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 hueplusplus. If not, see <http://www.gnu.org/licenses/>.
|
||||
**/
|
||||
|
||||
#include <hueplusplus/Rule.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "testhelper.h"
|
||||
|
||||
#include "mocks/mock_HttpHandler.h"
|
||||
|
||||
using namespace hueplusplus;
|
||||
using namespace testing;
|
||||
|
||||
TEST(Condition, Constructor)
|
||||
{
|
||||
const std::string address = "/api/abcd/test";
|
||||
const std::string value = "test value";
|
||||
Condition condition(address, Condition::Operator::eq, value);
|
||||
EXPECT_EQ(address, condition.getAddress());
|
||||
EXPECT_EQ(Condition::Operator::eq, condition.getOperator());
|
||||
EXPECT_EQ(value, condition.getValue());
|
||||
}
|
||||
|
||||
TEST(Condition, toJson)
|
||||
{
|
||||
Condition condition("/abcd", Condition::Operator::lt, "3");
|
||||
EXPECT_EQ(nlohmann::json({{"address", "/abcd"}, {"operator", "lt"}, {"value", "3"}}), condition.toJson());
|
||||
}
|
||||
|
||||
TEST(Condition, parse)
|
||||
{
|
||||
Condition condition = Condition::parse(nlohmann::json({{"address", "/abcd"}, {"operator", "lt"}, {"value", "3"}}));
|
||||
EXPECT_EQ("/abcd", condition.getAddress());
|
||||
EXPECT_EQ(Condition::Operator::lt, condition.getOperator());
|
||||
EXPECT_EQ("3", condition.getValue());
|
||||
EXPECT_THROW(Condition::parse(nlohmann::json({{"address", "/abcd"}, {"operator", "something"}, {"value", "3"}})),
|
||||
HueException);
|
||||
}
|
||||
|
||||
TEST(Condition, operatorString)
|
||||
{
|
||||
using Op = Condition::Operator;
|
||||
std::map<Op, std::string> values = {{Op::eq, "eq"}, {Op::gt, "gt"}, {Op::lt, "lt"}, {Op::dx, "dx"},
|
||||
{Op::ddx, "ddx"}, {Op::stable, "stable"}, {Op::notStable, "not stable"}, {Op::in, "in"}, {Op::notIn, "not in"}};
|
||||
|
||||
for (const auto& pair : values)
|
||||
{
|
||||
Condition c("", pair.first, "");
|
||||
// Check that correct string is
|
||||
EXPECT_EQ(pair.second, c.toJson().at("operator"));
|
||||
EXPECT_EQ(pair.first,
|
||||
Condition::parse(nlohmann::json {{"address", "/abcd"}, {"operator", pair.second}, {"value", "3"}})
|
||||
.getOperator());
|
||||
}
|
||||
}
|
||||
|
||||
class RuleTest : public Test
|
||||
{
|
||||
protected:
|
||||
std::shared_ptr<MockHttpHandler> handler;
|
||||
HueCommandAPI commands;
|
||||
nlohmann::json ruleState;
|
||||
|
||||
RuleTest()
|
||||
: handler(std::make_shared<MockHttpHandler>()),
|
||||
commands(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler),
|
||||
ruleState({{"name", "Rule 1"}, {"owner", "testOwner"}, {"created", "2020-06-01T10:00:00"},
|
||||
{"lasttriggered", "none"}, {"timestriggered", 0}, {"status", "enabled"},
|
||||
{"conditions", {{{"address", "testAddress"}, {"operator", "eq"}, {"value", "10"}}}},
|
||||
{"actions", {{{"address", "testAction"}, {"method", "PUT"}, {"body", {}}}}}})
|
||||
{ }
|
||||
|
||||
void expectGetState(int id)
|
||||
{
|
||||
EXPECT_CALL(*handler,
|
||||
GETJson("/api/" + getBridgeUsername() + "/rules/" + std::to_string(id), _, getBridgeIp(), getBridgePort()))
|
||||
.WillOnce(Return(ruleState));
|
||||
}
|
||||
|
||||
Rule getRule(int id = 1)
|
||||
{
|
||||
expectGetState(id);
|
||||
return Rule(id, commands, std::chrono::steady_clock::duration::max(), nullptr);
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(RuleTest, getName)
|
||||
{
|
||||
const std::string name = "Rule name";
|
||||
ruleState["name"] = name;
|
||||
const Rule rule = getRule();
|
||||
EXPECT_EQ(name, rule.getName());
|
||||
}
|
||||
|
||||
TEST_F(RuleTest, setName)
|
||||
{
|
||||
Rule rule = getRule();
|
||||
const std::string name = "Test rule";
|
||||
nlohmann::json request = {{"name", name}};
|
||||
nlohmann::json response = {{"success", {"/rules/1/name", name}}};
|
||||
EXPECT_CALL(*handler, PUTJson("/api/" + getBridgeUsername() + "/rules/1", request, getBridgeIp(), getBridgePort()))
|
||||
.WillOnce(Return(response));
|
||||
expectGetState(1);
|
||||
rule.setName(name);
|
||||
}
|
||||
|
||||
TEST_F(RuleTest, getCreated)
|
||||
{
|
||||
const std::string timestamp = "2020-06-01T10:00:00";
|
||||
ruleState["created"] = timestamp;
|
||||
const Rule rule = getRule();
|
||||
EXPECT_EQ(time::AbsoluteTime::parseUTC(timestamp).getBaseTime(), rule.getCreated().getBaseTime());
|
||||
}
|
||||
|
||||
TEST_F(RuleTest, getLastTriggered)
|
||||
{
|
||||
const std::string timestamp = "2020-06-01T10:00:00";
|
||||
ruleState["lasttriggered"] = timestamp;
|
||||
const Rule rule = getRule();
|
||||
EXPECT_EQ(time::AbsoluteTime::parseUTC(timestamp).getBaseTime(), rule.getLastTriggered().getBaseTime());
|
||||
ruleState["lasttriggered"] = "none";
|
||||
const Rule rule2 = getRule();
|
||||
EXPECT_EQ(std::chrono::system_clock::time_point(std::chrono::seconds(0)), rule2.getLastTriggered().getBaseTime());
|
||||
}
|
||||
|
||||
TEST_F(RuleTest, getTimesTriggered)
|
||||
{
|
||||
const int times = 20;
|
||||
ruleState["timestriggered"] = times;
|
||||
EXPECT_EQ(times, getRule().getTimesTriggered());
|
||||
}
|
||||
|
||||
TEST_F(RuleTest, isEnabled)
|
||||
{
|
||||
ruleState["status"] = "enabled";
|
||||
EXPECT_TRUE(getRule().isEnabled());
|
||||
ruleState["status"] = "disabled";
|
||||
EXPECT_FALSE(getRule().isEnabled());
|
||||
}
|
||||
|
||||
TEST_F(RuleTest, setEnabled)
|
||||
{
|
||||
Rule rule = getRule();
|
||||
{
|
||||
nlohmann::json request = {{"status", "enabled"}};
|
||||
nlohmann::json response = {{"success", {"/rules/1/status", "enabled"}}};
|
||||
EXPECT_CALL(
|
||||
*handler, PUTJson("/api/" + getBridgeUsername() + "/rules/1", request, getBridgeIp(), getBridgePort()))
|
||||
.WillOnce(Return(response));
|
||||
expectGetState(1);
|
||||
rule.setEnabled(true);
|
||||
}
|
||||
{
|
||||
nlohmann::json request = {{"status", "disabled"}};
|
||||
nlohmann::json response = {{"success", {"/rules/1/status", "disabled"}}};
|
||||
EXPECT_CALL(
|
||||
*handler, PUTJson("/api/" + getBridgeUsername() + "/rules/1", request, getBridgeIp(), getBridgePort()))
|
||||
.WillOnce(Return(response));
|
||||
expectGetState(1);
|
||||
rule.setEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(RuleTest, getOwner)
|
||||
{
|
||||
const std::string owner = "testowner";
|
||||
ruleState["owner"] = owner;
|
||||
EXPECT_EQ(owner, getRule().getOwner());
|
||||
}
|
||||
|
||||
TEST_F(RuleTest, getConditions)
|
||||
{
|
||||
std::vector<Condition> conditions
|
||||
= {Condition("/a/b/c", Condition::Operator::eq, "12"), Condition("/d/c", Condition::Operator::dx, "")};
|
||||
ruleState["conditions"] = {conditions[0].toJson(), conditions[1].toJson()};
|
||||
const std::vector<Condition> result = getRule().getConditions();
|
||||
ASSERT_EQ(2, result.size());
|
||||
EXPECT_EQ(conditions[0].toJson(), result[0].toJson());
|
||||
EXPECT_EQ(conditions[1].toJson(), result[1].toJson());
|
||||
}
|
||||
|
||||
TEST_F(RuleTest, getActions)
|
||||
{
|
||||
nlohmann::json action0 {{"address", "/a/b"}, {"method", "PUT"}, {"body", {{"value", "test"}}}};
|
||||
nlohmann::json action1 {{"address", "/c/d"}, {"method", "POST"}, {"body", {{"32", 1}}}};
|
||||
|
||||
ruleState["actions"] = {action0, action1};
|
||||
const std::vector<hueplusplus::Action> result = getRule().getActions();
|
||||
ASSERT_EQ(2, result.size());
|
||||
EXPECT_EQ(action0, result[0].toJson());
|
||||
EXPECT_EQ(action1, result[1].toJson());
|
||||
}
|
||||
|
||||
TEST_F(RuleTest, setConditions)
|
||||
{
|
||||
std::vector<Condition> conditions
|
||||
= {Condition("/a/b/c", Condition::Operator::eq, "12"), Condition("/d/c", Condition::Operator::dx, "")};
|
||||
const nlohmann::json request = {{"conditions", {conditions[0].toJson(), conditions[1].toJson()}}};
|
||||
|
||||
Rule rule = getRule();
|
||||
EXPECT_CALL(*handler, PUTJson("/api/" + getBridgeUsername() + "/rules/1", request, getBridgeIp(), getBridgePort()));
|
||||
expectGetState(1);
|
||||
rule.setConditions(conditions);
|
||||
}
|
||||
|
||||
TEST_F(RuleTest, setActions)
|
||||
{
|
||||
using hueplusplus::Action;
|
||||
nlohmann::json action0 {{"address", "/a/b"}, {"method", "PUT"}, {"body", {{"value", "test"}}}};
|
||||
nlohmann::json action1 {{"address", "/c/d"}, {"method", "POST"}, {"body", {{"32", 1}}}};
|
||||
const nlohmann::json request = {{"actions", {action0, action1}}};
|
||||
|
||||
const std::vector<Action> actions = {Action(action0), Action(action1)};
|
||||
|
||||
Rule rule = getRule();
|
||||
EXPECT_CALL(*handler, PUTJson("/api/" + getBridgeUsername() + "/rules/1", request, getBridgeIp(), getBridgePort()));
|
||||
expectGetState(1);
|
||||
rule.setActions(actions);
|
||||
}
|
||||
|
||||
TEST(CreateRule, setName)
|
||||
{
|
||||
const std::string name = "New rule";
|
||||
const nlohmann::json request = {{"conditions", nullptr}, {"actions", nullptr}, {"name", name}};
|
||||
EXPECT_EQ(request, CreateRule({}, {}).setName(name).getRequest());
|
||||
}
|
||||
|
||||
TEST(CreateRule, setStatus)
|
||||
{
|
||||
{
|
||||
const nlohmann::json request = {{"conditions", nullptr}, {"actions", nullptr}, {"status", "enabled"}};
|
||||
EXPECT_EQ(request, CreateRule({}, {}).setStatus(true).getRequest());
|
||||
}
|
||||
{
|
||||
const nlohmann::json request = {{"conditions", nullptr}, {"actions", nullptr}, {"status", "disabled"}};
|
||||
EXPECT_EQ(request, CreateRule({}, {}).setStatus(false).getRequest());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(CreateRule, Constructor)
|
||||
{
|
||||
using hueplusplus::Action;
|
||||
std::vector<Condition> conditions
|
||||
= {Condition("/a/b/c", Condition::Operator::eq, "12"), Condition("/d/c", Condition::Operator::dx, "")};
|
||||
nlohmann::json action0 {{"address", "/a/b"}, {"method", "PUT"}, {"body", {{"value", "test"}}}};
|
||||
nlohmann::json action1 {{"address", "/c/d"}, {"method", "POST"}, {"body", {{"32", 1}}}};
|
||||
const std::vector<Action> actions = {Action(action0), Action(action1)};
|
||||
const nlohmann::json request
|
||||
= {{"conditions", {conditions[0].toJson(), conditions[1].toJson()}}, {"actions", {action0, action1}}};
|
||||
EXPECT_EQ(request, CreateRule(conditions, actions).getRequest());
|
||||
}
|
||||
+501
@@ -0,0 +1,501 @@
|
||||
/**
|
||||
\file test_Scene.cpp
|
||||
Copyright Notice\n
|
||||
Copyright (C) 2020 Jan Rogall - developer\n
|
||||
|
||||
This file is part of hueplusplus.
|
||||
|
||||
hueplusplus 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.
|
||||
|
||||
hueplusplus 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 hueplusplus. If not, see <http://www.gnu.org/licenses/>.
|
||||
**/
|
||||
|
||||
#include <hueplusplus/Scene.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "testhelper.h"
|
||||
|
||||
#include "mocks/mock_HttpHandler.h"
|
||||
|
||||
using namespace hueplusplus;
|
||||
using namespace testing;
|
||||
|
||||
TEST(LightState, on)
|
||||
{
|
||||
EXPECT_FALSE(LightState(nlohmann::json::object()).isOn());
|
||||
EXPECT_TRUE(LightState(nlohmann::json {{"on", true}}).isOn());
|
||||
EXPECT_FALSE(LightState(nlohmann::json {{"on", false}}).isOn());
|
||||
}
|
||||
|
||||
TEST(LightState, Brightness)
|
||||
{
|
||||
EXPECT_FALSE(LightState(nlohmann::json::object()).hasBrightness());
|
||||
const int bri = 125;
|
||||
nlohmann::json json {{"bri", bri}};
|
||||
const LightState state {json};
|
||||
EXPECT_TRUE(state.hasBrightness());
|
||||
EXPECT_EQ(bri, state.getBrightness());
|
||||
}
|
||||
|
||||
TEST(LightState, HueSat)
|
||||
{
|
||||
EXPECT_FALSE(LightState(nlohmann::json::object()).hasHueSat());
|
||||
EXPECT_FALSE(LightState(nlohmann::json {{"hue", 0}}).hasHueSat());
|
||||
EXPECT_FALSE(LightState(nlohmann::json {{"sat", 0}}).hasHueSat());
|
||||
const int hue = 12553;
|
||||
const int sat = 240;
|
||||
nlohmann::json json {{"hue", hue}, {"sat", sat}};
|
||||
const LightState state {json};
|
||||
EXPECT_TRUE(state.hasHueSat());
|
||||
EXPECT_EQ(hue, state.getHueSat().hue);
|
||||
EXPECT_EQ(sat, state.getHueSat().saturation);
|
||||
}
|
||||
|
||||
TEST(LightState, XY)
|
||||
{
|
||||
EXPECT_FALSE(LightState(nlohmann::json::object()).hasXY());
|
||||
const float x = 0.6f;
|
||||
const float y = 0.3f;
|
||||
nlohmann::json json {{"xy", {x, y}}, {"bri", 255}};
|
||||
const LightState state {json};
|
||||
EXPECT_TRUE(state.hasXY());
|
||||
EXPECT_FLOAT_EQ(x, state.getXY().xy.x);
|
||||
EXPECT_FLOAT_EQ(y, state.getXY().xy.y);
|
||||
EXPECT_FLOAT_EQ(1.f, state.getXY().brightness);
|
||||
}
|
||||
|
||||
TEST(LightState, Ct)
|
||||
{
|
||||
EXPECT_FALSE(LightState(nlohmann::json::object()).hasCt());
|
||||
const int ct = 260;
|
||||
nlohmann::json json {{"ct", ct}};
|
||||
const LightState state {json};
|
||||
EXPECT_TRUE(state.hasCt());
|
||||
EXPECT_EQ(ct, state.getCt());
|
||||
}
|
||||
|
||||
TEST(LightState, Effect)
|
||||
{
|
||||
EXPECT_FALSE(LightState(nlohmann::json::object()).hasEffect());
|
||||
nlohmann::json json {{"effect", "colorloop"}};
|
||||
const LightState state {json};
|
||||
EXPECT_TRUE(state.hasEffect());
|
||||
EXPECT_TRUE(state.getColorloop());
|
||||
EXPECT_FALSE(LightState(nlohmann::json {{"effect", "none"}}).getColorloop());
|
||||
}
|
||||
|
||||
TEST(LightState, TransitionTime)
|
||||
{
|
||||
EXPECT_EQ(4, LightState(nlohmann::json::object()).getTransitionTime());
|
||||
EXPECT_EQ(0, LightState(nlohmann::json {{"transitiontime", 0}}).getTransitionTime());
|
||||
}
|
||||
|
||||
TEST(LightState, toJson)
|
||||
{
|
||||
const nlohmann::json json {{"on", false}, {"bri", 254}, {"ct", 400}};
|
||||
EXPECT_EQ(json, LightState(json).toJson());
|
||||
}
|
||||
|
||||
TEST(LightStateBuilder, create)
|
||||
{
|
||||
{
|
||||
const nlohmann::json json {{"on", false}, {"bri", 254}, {"ct", 400}, {"effect", "colorloop"}};
|
||||
EXPECT_EQ(
|
||||
json, LightStateBuilder().setOn(false).setBrightness(254).setCt(400).setColorloop(true).create().toJson());
|
||||
}
|
||||
{
|
||||
const nlohmann::json json {{"xy", {0.5f, 0.5f}}, {"effect", "none"}};
|
||||
EXPECT_EQ(json, LightStateBuilder().setXY({0.5f, 0.5f}).setColorloop(false).create().toJson());
|
||||
}
|
||||
{
|
||||
const nlohmann::json json {{"hue", 360}, {"sat", 230}, {"transitiontime", 4}};
|
||||
EXPECT_EQ(json, LightStateBuilder().setHueSat({360, 230}).setTransitionTime(4).create().toJson());
|
||||
}
|
||||
}
|
||||
|
||||
class SceneTest : public Test
|
||||
{
|
||||
public:
|
||||
std::shared_ptr<MockHttpHandler> handler;
|
||||
HueCommandAPI commands;
|
||||
nlohmann::json sceneState;
|
||||
|
||||
SceneTest()
|
||||
: handler(std::make_shared<MockHttpHandler>()),
|
||||
commands(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler),
|
||||
sceneState({{"name", "Test scene"}, {"type", "GroupScene"}, {"group", "4"}, {"lights", {"3", "4", "5"}},
|
||||
{"owner", "testowner"}, {"recycle", false}, {"locked", false},
|
||||
{"appdata", {{"data", "test-data"}, {"version", 2}}}, {"picture", ""},
|
||||
{"lastupdated", "2020-04-23T12:00:04"}, {"version", 2},
|
||||
{"lightstates",
|
||||
{{"3", {{"on", false}, {"bri", 100}, {"xy", {0.3, 0.2}}}},
|
||||
{"4", {{"on", true}, {"bri", 200}, {"xy", {0.3, 0.2}}, {"effect", "colorloop"}}},
|
||||
{"5", {{"on", true}, {"bri", 100}, {"xy", {0.3, 0.2}}}}}}})
|
||||
{ }
|
||||
|
||||
void expectGetState(const std::string& id)
|
||||
{
|
||||
EXPECT_CALL(*handler,
|
||||
GETJson("/api/" + getBridgeUsername() + "/scenes/" + id, nlohmann::json::object(), getBridgeIp(),
|
||||
getBridgePort()))
|
||||
.WillOnce(Return(sceneState));
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(SceneTest, Constructor)
|
||||
{
|
||||
const std::string id = "asd89263";
|
||||
expectGetState(id);
|
||||
const Scene scene(id, commands, std::chrono::seconds(0), nullptr);
|
||||
EXPECT_EQ(id, scene.getId());
|
||||
}
|
||||
|
||||
TEST_F(SceneTest, getName)
|
||||
{
|
||||
const std::string id = "125abets8912";
|
||||
const std::string name = "Scene name";
|
||||
sceneState["name"] = name;
|
||||
expectGetState(id);
|
||||
const Scene scene(id, commands, std::chrono::seconds(0), nullptr);
|
||||
EXPECT_EQ(name, scene.getName());
|
||||
}
|
||||
|
||||
TEST_F(SceneTest, getType)
|
||||
{
|
||||
const std::string id = "125abets8912";
|
||||
{
|
||||
sceneState["type"] = "GroupScene";
|
||||
expectGetState(id);
|
||||
const Scene scene(id, commands, std::chrono::seconds(0), nullptr);
|
||||
EXPECT_EQ(Scene::Type::groupScene, scene.getType());
|
||||
}
|
||||
{
|
||||
sceneState["type"] = "LightScene";
|
||||
expectGetState(id);
|
||||
const Scene scene(id, commands, std::chrono::seconds(0), nullptr);
|
||||
EXPECT_EQ(Scene::Type::lightScene, scene.getType());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(SceneTest, getGroupId)
|
||||
{
|
||||
const std::string id = "125abets8912";
|
||||
{
|
||||
sceneState["group"] = "3";
|
||||
expectGetState(id);
|
||||
const Scene scene(id, commands, std::chrono::seconds(0), nullptr);
|
||||
EXPECT_EQ(3, scene.getGroupId());
|
||||
}
|
||||
{
|
||||
sceneState["type"] = "LightScene";
|
||||
sceneState.erase("group");
|
||||
expectGetState(id);
|
||||
const Scene scene(id, commands, std::chrono::seconds(0), nullptr);
|
||||
EXPECT_EQ(0, scene.getGroupId());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(SceneTest, getLightIds)
|
||||
{
|
||||
const std::string id = "125asav3";
|
||||
sceneState["lights"] = {"3", "4", "5"};
|
||||
expectGetState(id);
|
||||
const Scene scene(id, commands, std::chrono::seconds(0), nullptr);
|
||||
EXPECT_THAT(scene.getLightIds(), UnorderedElementsAre(3, 4, 5));
|
||||
}
|
||||
|
||||
TEST_F(SceneTest, getOwner)
|
||||
{
|
||||
const std::string id = "125asav3";
|
||||
const std::string owner = "testowner";
|
||||
sceneState["owner"] = owner;
|
||||
expectGetState(id);
|
||||
const Scene scene(id, commands, std::chrono::seconds(0), nullptr);
|
||||
EXPECT_EQ(owner, scene.getOwner());
|
||||
}
|
||||
|
||||
TEST_F(SceneTest, getRecycle)
|
||||
{
|
||||
const std::string id = "125asav3";
|
||||
const bool recycle = true;
|
||||
sceneState["recycle"] = recycle;
|
||||
expectGetState(id);
|
||||
const Scene scene(id, commands, std::chrono::seconds(0), nullptr);
|
||||
EXPECT_EQ(recycle, scene.getRecycle());
|
||||
}
|
||||
|
||||
TEST_F(SceneTest, isLocked)
|
||||
{
|
||||
const std::string id = "125asav3";
|
||||
const bool locked = true;
|
||||
sceneState["locked"] = locked;
|
||||
expectGetState(id);
|
||||
const Scene scene(id, commands, std::chrono::seconds(0), nullptr);
|
||||
EXPECT_EQ(locked, scene.isLocked());
|
||||
}
|
||||
|
||||
TEST_F(SceneTest, getAppdata)
|
||||
{
|
||||
const std::string id = "125asav3";
|
||||
const std::string appdata = "some data";
|
||||
const int version = 10;
|
||||
sceneState["appdata"] = {{"version", version}, {"data", appdata}};
|
||||
expectGetState(id);
|
||||
const Scene scene(id, commands, std::chrono::seconds(0), nullptr);
|
||||
EXPECT_EQ(version, scene.getAppdataVersion());
|
||||
EXPECT_EQ(appdata, scene.getAppdata());
|
||||
}
|
||||
|
||||
TEST_F(SceneTest, getPicture)
|
||||
{
|
||||
const std::string id = "125asav3";
|
||||
const std::string picture = "abcpicture";
|
||||
sceneState["picture"] = picture;
|
||||
expectGetState(id);
|
||||
const Scene scene(id, commands, std::chrono::seconds(0), nullptr);
|
||||
EXPECT_EQ(picture, scene.getPicture());
|
||||
}
|
||||
|
||||
TEST_F(SceneTest, getLastUpdated)
|
||||
{
|
||||
const std::string id = "125asav3";
|
||||
expectGetState(id);
|
||||
const Scene scene(id, commands, std::chrono::seconds(0), nullptr);
|
||||
const time::AbsoluteTime lastUpdated = scene.getLastUpdated();
|
||||
EXPECT_EQ(time::parseUTCTimestamp("2020-04-23T12:00:04"), lastUpdated.getBaseTime());
|
||||
}
|
||||
|
||||
TEST_F(SceneTest, getVersion)
|
||||
{
|
||||
const std::string id = "125asav3";
|
||||
const int version = 2;
|
||||
sceneState["version"] = version;
|
||||
expectGetState(id);
|
||||
const Scene scene(id, commands, std::chrono::seconds(0), nullptr);
|
||||
EXPECT_EQ(version, scene.getVersion());
|
||||
}
|
||||
|
||||
TEST_F(SceneTest, getLightstates)
|
||||
{
|
||||
const std::string id = "125asav3";
|
||||
{
|
||||
const std::map<int, LightState> lightstates {
|
||||
{3, LightStateBuilder().setOn(false).setBrightness(100).setXY({0.3, 0.2}).create()},
|
||||
{4, LightStateBuilder().setOn(false).setBrightness(200).setXY({0.3, 0.2}).setColorloop(true).create()},
|
||||
{5, LightStateBuilder().setOn(true).setBrightness(100).setXY({0.3, 0.2}).create()}};
|
||||
nlohmann::json lightstatesJson;
|
||||
for (const auto& entry : lightstates)
|
||||
{
|
||||
lightstatesJson[std::to_string(entry.first)] = entry.second.toJson();
|
||||
}
|
||||
sceneState["lightstates"] = lightstatesJson;
|
||||
expectGetState(id);
|
||||
const Scene scene(id, commands, std::chrono::seconds(0), nullptr);
|
||||
const std::map<int, LightState> result = scene.getLightStates();
|
||||
EXPECT_EQ(lightstates, result);
|
||||
}
|
||||
// No lightstates (old scene)
|
||||
{
|
||||
sceneState.erase("lightstates");
|
||||
expectGetState(id);
|
||||
const Scene scene(id, commands, std::chrono::seconds(0), nullptr);
|
||||
EXPECT_TRUE(scene.getLightStates().empty());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(SceneTest, refresh)
|
||||
{
|
||||
const std::string id = "125asav3";
|
||||
expectGetState(id);
|
||||
Scene scene(id, commands, std::chrono::seconds(0), nullptr);
|
||||
expectGetState(id);
|
||||
scene.refresh(true);
|
||||
}
|
||||
|
||||
TEST_F(SceneTest, setName)
|
||||
{
|
||||
const std::string id = "125asav3";
|
||||
expectGetState(id);
|
||||
Scene scene(id, commands, std::chrono::seconds(0), nullptr);
|
||||
const std::string name = "Scene name";
|
||||
nlohmann::json request = {{"name", name}};
|
||||
nlohmann::json response = {{"success", {"/scenes/" + id + "/name", name}}};
|
||||
EXPECT_CALL(
|
||||
*handler, PUTJson("/api/" + getBridgeUsername() + "/scenes/" + id, request, getBridgeIp(), getBridgePort()))
|
||||
.WillOnce(Return(response));
|
||||
expectGetState(id);
|
||||
scene.setName(name);
|
||||
}
|
||||
|
||||
TEST_F(SceneTest, setLightIds)
|
||||
{
|
||||
const std::string id = "125asav3";
|
||||
expectGetState(id);
|
||||
Scene scene(id, commands, std::chrono::seconds(0), nullptr);
|
||||
const std::vector<int> lightIds = {3, 4, 6, 8};
|
||||
nlohmann::json request = {{"lights", {"3", "4", "6", "8"}}};
|
||||
nlohmann::json response = {{"success", {"/scenes/" + id + "/lights", {"3", "4", "6", "8"}}}};
|
||||
EXPECT_CALL(
|
||||
*handler, PUTJson("/api/" + getBridgeUsername() + "/scenes/" + id, request, getBridgeIp(), getBridgePort()))
|
||||
.WillOnce(Return(response));
|
||||
expectGetState(id);
|
||||
scene.setLightIds(lightIds);
|
||||
}
|
||||
|
||||
TEST_F(SceneTest, setAppdata)
|
||||
{
|
||||
const std::string id = "125asav3";
|
||||
expectGetState(id);
|
||||
Scene scene(id, commands, std::chrono::seconds(0), nullptr);
|
||||
const std::string appdata = "New appdata";
|
||||
const int version = 3;
|
||||
nlohmann::json request = {{"appdata", {{"version", version}, {"data", appdata}}}};
|
||||
nlohmann::json response = {{"success", {"/scenes/" + id + "/appdata/version", version}},
|
||||
{"success", {"/scenes/" + id + "/appdata/data", appdata}}};
|
||||
EXPECT_CALL(
|
||||
*handler, PUTJson("/api/" + getBridgeUsername() + "/scenes/" + id, request, getBridgeIp(), getBridgePort()))
|
||||
.WillOnce(Return(response));
|
||||
expectGetState(id);
|
||||
scene.setAppdata(appdata, version);
|
||||
}
|
||||
|
||||
TEST_F(SceneTest, setLightStates)
|
||||
{
|
||||
const std::string id = "125asav3";
|
||||
const std::map<int, LightState> lightstates {
|
||||
{3, LightStateBuilder().setOn(false).setBrightness(100).setCt(200).create()},
|
||||
{5, LightStateBuilder().setOn(true).setBrightness(200).setXY({0.3, 0.2}).create()}};
|
||||
nlohmann::json lightstatesJson;
|
||||
for (const auto& entry : lightstates)
|
||||
{
|
||||
lightstatesJson[std::to_string(entry.first)] = entry.second.toJson();
|
||||
}
|
||||
expectGetState(id);
|
||||
Scene scene(id, commands, std::chrono::seconds(0), nullptr);
|
||||
nlohmann::json request = {{"lightstates", lightstatesJson}};
|
||||
nlohmann::json response = {{"success", {"/scenes/" + id + "/lights/3/state/on", false}},
|
||||
{"success", {"/scenes/" + id + "/lights/3/state/bri", 100}},
|
||||
{"success", {"/scenes/" + id + "/lights/3/state/ct", 200}},
|
||||
{"success", {"/scenes/" + id + "/lights/5/state/on", true}},
|
||||
{"success", {"/scenes/" + id + "/lights/5/state/bri", 200}},
|
||||
{"success", {"/scenes/" + id + "/lights/5/state/xy", {0.3, 0.2}}}};
|
||||
EXPECT_CALL(
|
||||
*handler, PUTJson("/api/" + getBridgeUsername() + "/scenes/" + id, request, getBridgeIp(), getBridgePort()))
|
||||
.WillOnce(Return(response));
|
||||
expectGetState(id);
|
||||
scene.setLightStates(lightstates);
|
||||
}
|
||||
|
||||
TEST_F(SceneTest, storeCurrentLightState)
|
||||
{
|
||||
const std::string id = "125asav3";
|
||||
expectGetState(id);
|
||||
Scene scene(id, commands, std::chrono::seconds(0), nullptr);
|
||||
{
|
||||
nlohmann::json request = {{"storelightstate", true}};
|
||||
nlohmann::json response = {{"success", {"/scenes/" + id + "/storelightstate", true}}};
|
||||
EXPECT_CALL(
|
||||
*handler, PUTJson("/api/" + getBridgeUsername() + "/scenes/" + id, request, getBridgeIp(), getBridgePort()))
|
||||
.WillOnce(Return(response));
|
||||
expectGetState(id);
|
||||
scene.storeCurrentLightState();
|
||||
}
|
||||
{
|
||||
const int transitiontime = 3;
|
||||
nlohmann::json request = {{"storelightstate", true}, {"transitiontime", 3}};
|
||||
nlohmann::json response = {{"success", {"/scenes/" + id + "/storelightstate", true}}};
|
||||
EXPECT_CALL(
|
||||
*handler, PUTJson("/api/" + getBridgeUsername() + "/scenes/" + id, request, getBridgeIp(), getBridgePort()))
|
||||
.WillOnce(Return(response));
|
||||
expectGetState(id);
|
||||
scene.storeCurrentLightState(transitiontime);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(SceneTest, recall)
|
||||
{
|
||||
const std::string id = "125asav3";
|
||||
// LightScene
|
||||
{
|
||||
sceneState["type"] = "LightScene";
|
||||
expectGetState(id);
|
||||
nlohmann::json request = {{"scene", id}};
|
||||
nlohmann::json response = {{"success", {"/groups/0/action/scene", id}}};
|
||||
Scene scene(id, commands, std::chrono::seconds(0), nullptr);
|
||||
EXPECT_CALL(*handler,
|
||||
PUTJson("/api/" + getBridgeUsername() + "/groups/0/action", request, getBridgeIp(), getBridgePort()))
|
||||
.WillOnce(Return(response));
|
||||
scene.recall();
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
}
|
||||
// GroupScene
|
||||
{
|
||||
sceneState["type"] = "GroupScene";
|
||||
std::string groupId = "3";
|
||||
sceneState["group"] = groupId;
|
||||
expectGetState(id);
|
||||
nlohmann::json request = {{"scene", id}};
|
||||
nlohmann::json response = {{"success", {"/groups/" + groupId + "/action/scene", id}}};
|
||||
Scene scene(id, commands, std::chrono::seconds(0), nullptr);
|
||||
EXPECT_CALL(*handler,
|
||||
PUTJson("/api/" + getBridgeUsername() + "/groups/" + groupId + "/action", request, getBridgeIp(),
|
||||
getBridgePort()))
|
||||
.WillOnce(Return(response));
|
||||
scene.recall();
|
||||
}
|
||||
}
|
||||
|
||||
TEST(CreateScene, setName)
|
||||
{
|
||||
const std::string name = "New scene";
|
||||
const nlohmann::json request = {{"name", name}};
|
||||
EXPECT_EQ(request, CreateScene().setName(name).getRequest());
|
||||
}
|
||||
|
||||
TEST(CreateScene, setGroupId)
|
||||
{
|
||||
const int groupId = 23;
|
||||
const nlohmann::json request = {{"group", "23"}, {"type", "GroupScene"}};
|
||||
EXPECT_EQ(request, CreateScene().setGroupId(groupId).getRequest());
|
||||
EXPECT_THROW(CreateScene().setGroupId(2).setLightIds({1}), HueException);
|
||||
}
|
||||
|
||||
TEST(CreateScene, setLightIds)
|
||||
{
|
||||
const std::vector<int> lightIds = {3, 4, 5, 9};
|
||||
const nlohmann::json request = {{"lights", {"3", "4", "5", "9"}}, {"type", "LightScene"}};
|
||||
EXPECT_EQ(request, CreateScene().setLightIds(lightIds).getRequest());
|
||||
EXPECT_THROW(CreateScene().setLightIds(lightIds).setGroupId(1), HueException);
|
||||
}
|
||||
|
||||
TEST(CreateScene, setRecycle)
|
||||
{
|
||||
const nlohmann::json request = {{"recycle", true}};
|
||||
EXPECT_EQ(request, CreateScene().setRecycle(true).getRequest());
|
||||
}
|
||||
|
||||
TEST(CreateScene, setAppdata)
|
||||
{
|
||||
const std::string data = "testdata";
|
||||
const int version = 3;
|
||||
const nlohmann::json request = {{"appdata", {{"data", data}, {"version", version}}}};
|
||||
EXPECT_EQ(request, CreateScene().setAppdata(data, version).getRequest());
|
||||
}
|
||||
|
||||
TEST(CreateScene, setLightStates)
|
||||
{
|
||||
const std::map<int, LightState> lightStates
|
||||
= {{1, LightStateBuilder().setOn(true).create()}, {5, LightStateBuilder().setCt(300).create()}};
|
||||
const nlohmann::json request = {{"lightstates", {{"1", {{"on", true}}}, {"5", {{"ct", 300}}}}}};
|
||||
EXPECT_EQ(request, CreateScene().setLightStates(lightStates).getRequest());
|
||||
}
|
||||
@@ -0,0 +1,330 @@
|
||||
/**
|
||||
\file test_Schedule.cpp
|
||||
Copyright Notice\n
|
||||
Copyright (C) 2020 Jan Rogall - developer\n
|
||||
|
||||
This file is part of hueplusplus.
|
||||
|
||||
hueplusplus 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.
|
||||
|
||||
hueplusplus 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 hueplusplus. If not, see <http://www.gnu.org/licenses/>.
|
||||
**/
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <hueplusplus/Schedule.h>
|
||||
|
||||
#include "testhelper.h"
|
||||
|
||||
#include "mocks/mock_HttpHandler.h"
|
||||
|
||||
using namespace hueplusplus;
|
||||
using namespace testing;
|
||||
|
||||
class ScheduleTest : public Test
|
||||
{
|
||||
protected:
|
||||
std::shared_ptr<MockHttpHandler> handler;
|
||||
HueCommandAPI commands;
|
||||
nlohmann::json scheduleState;
|
||||
|
||||
ScheduleTest()
|
||||
: handler(std::make_shared<MockHttpHandler>()),
|
||||
commands(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler),
|
||||
scheduleState({{"name", "Schedule 1"}, {"description", "nice schedule"},
|
||||
{"command", {{"address", "/test"}, {"body", {}}, {"method", "PUT"}}}, {"created", "2020-03-03T23:00:03"},
|
||||
{"localtime", "T13:00:00/T14:00:00"}, {"status", "enabled"}, {"autodelete", false},
|
||||
{"starttime", "2020-04-01T00:00:00"}})
|
||||
{}
|
||||
|
||||
void expectGetState(int id)
|
||||
{
|
||||
EXPECT_CALL(*handler,
|
||||
GETJson("/api/" + getBridgeUsername() + "/schedules/" + std::to_string(id), nlohmann::json::object(),
|
||||
getBridgeIp(), getBridgePort()))
|
||||
.WillOnce(Return(scheduleState));
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(ScheduleTest, Constructor)
|
||||
{
|
||||
{
|
||||
const int id = 13;
|
||||
expectGetState(id);
|
||||
const Schedule schedule(id, commands, std::chrono::seconds(0), nullptr);
|
||||
EXPECT_EQ(id, schedule.getId());
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
}
|
||||
{
|
||||
const int id = 0;
|
||||
expectGetState(id);
|
||||
const Schedule schedule(id, commands, std::chrono::seconds(0), nullptr);
|
||||
EXPECT_EQ(id, schedule.getId());
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(ScheduleTest, getName)
|
||||
{
|
||||
const int id = 1;
|
||||
const std::string name = "Schedule name";
|
||||
scheduleState["name"] = name;
|
||||
expectGetState(id);
|
||||
const Schedule schedule(id, commands, std::chrono::seconds(0), nullptr);
|
||||
EXPECT_EQ(name, schedule.getName());
|
||||
}
|
||||
|
||||
TEST_F(ScheduleTest, getDescription)
|
||||
{
|
||||
const int id = 1;
|
||||
const std::string description = "Schedule description";
|
||||
scheduleState["description"] = description;
|
||||
expectGetState(id);
|
||||
const Schedule schedule(id, commands, std::chrono::seconds(0), nullptr);
|
||||
EXPECT_EQ(description, schedule.getDescription());
|
||||
}
|
||||
|
||||
TEST_F(ScheduleTest, getCommand)
|
||||
{
|
||||
const int id = 1;
|
||||
const std::string addr = "/api/blabla";
|
||||
const nlohmann::json body = {{"test", "value"}};
|
||||
scheduleState["command"] = {{"address", addr}, {"body", body}, {"method", "PUT"}};
|
||||
expectGetState(id);
|
||||
const Schedule schedule(id, commands, std::chrono::seconds(0), nullptr);
|
||||
hueplusplus::Action command = schedule.getCommand();
|
||||
EXPECT_EQ(addr, command.getAddress());
|
||||
EXPECT_EQ(body, command.getBody());
|
||||
EXPECT_EQ(hueplusplus::Action::Method::put, command.getMethod());
|
||||
}
|
||||
|
||||
TEST_F(ScheduleTest, getTime)
|
||||
{
|
||||
const int id = 1;
|
||||
const std::string time = "T13:00:00/T14:00:00";
|
||||
scheduleState["localtime"] = time;
|
||||
expectGetState(id);
|
||||
const Schedule schedule(id, commands, std::chrono::seconds(0), nullptr);
|
||||
time::TimePattern pattern = schedule.getTime();
|
||||
EXPECT_EQ(time, pattern.toString());
|
||||
}
|
||||
|
||||
TEST_F(ScheduleTest, getStatus)
|
||||
{
|
||||
const int id = 1;
|
||||
{
|
||||
scheduleState["status"] = "enabled";
|
||||
expectGetState(id);
|
||||
const Schedule schedule(id, commands, std::chrono::seconds(0), nullptr);
|
||||
EXPECT_EQ(true, schedule.isEnabled());
|
||||
}
|
||||
{
|
||||
scheduleState["status"] = "disabled";
|
||||
expectGetState(id);
|
||||
const Schedule schedule(id, commands, std::chrono::seconds(0), nullptr);
|
||||
EXPECT_EQ(false, schedule.isEnabled());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(ScheduleTest, getAutodelete)
|
||||
{
|
||||
const int id = 1;
|
||||
const bool autodelete = true;
|
||||
scheduleState["autodelete"] = autodelete;
|
||||
expectGetState(id);
|
||||
const Schedule schedule(id, commands, std::chrono::seconds(0), nullptr);
|
||||
EXPECT_EQ(autodelete, schedule.getAutodelete());
|
||||
}
|
||||
|
||||
TEST_F(ScheduleTest, getCreated)
|
||||
{
|
||||
const int id = 1;
|
||||
const std::string created = "2020-03-03T08:20:53";
|
||||
scheduleState["created"] = created;
|
||||
expectGetState(id);
|
||||
const Schedule schedule(id, commands, std::chrono::seconds(0), nullptr);
|
||||
EXPECT_EQ(created, schedule.getCreated().toString());
|
||||
}
|
||||
|
||||
TEST_F(ScheduleTest, getStartTime)
|
||||
{
|
||||
const int id = 1;
|
||||
const std::string starttime = "2020-03-03T08:20:53";
|
||||
scheduleState["starttime"] = starttime;
|
||||
expectGetState(id);
|
||||
const Schedule schedule(id, commands, std::chrono::seconds(0), nullptr);
|
||||
EXPECT_EQ(starttime, schedule.getStartTime().toString());
|
||||
}
|
||||
|
||||
TEST_F(ScheduleTest, setName)
|
||||
{
|
||||
const int id = 1;
|
||||
expectGetState(id);
|
||||
Schedule schedule(id, commands, std::chrono::steady_clock::duration::max(), nullptr);
|
||||
const std::string name = "Test schedule";
|
||||
nlohmann::json request = {{"name", name}};
|
||||
nlohmann::json response = {{"success", {"/schedules/1/name", name}}};
|
||||
EXPECT_CALL(
|
||||
*handler, PUTJson("/api/" + getBridgeUsername() + "/schedules/1", request, getBridgeIp(), getBridgePort()))
|
||||
.WillOnce(Return(response));
|
||||
expectGetState(id);
|
||||
schedule.setName(name);
|
||||
}
|
||||
|
||||
TEST_F(ScheduleTest, setDescription)
|
||||
{
|
||||
const int id = 1;
|
||||
expectGetState(id);
|
||||
Schedule schedule(id, commands, std::chrono::steady_clock::duration::max(), nullptr);
|
||||
const std::string description = "Test schedule description";
|
||||
nlohmann::json request = {{"description", description}};
|
||||
nlohmann::json response = {{"success", {"/schedules/1/description", description}}};
|
||||
EXPECT_CALL(
|
||||
*handler, PUTJson("/api/" + getBridgeUsername() + "/schedules/1", request, getBridgeIp(), getBridgePort()))
|
||||
.WillOnce(Return(response));
|
||||
expectGetState(id);
|
||||
schedule.setDescription(description);
|
||||
}
|
||||
|
||||
TEST_F(ScheduleTest, setCommand)
|
||||
{
|
||||
const int id = 1;
|
||||
expectGetState(id);
|
||||
Schedule schedule(id, commands, std::chrono::steady_clock::duration::max(), nullptr);
|
||||
const hueplusplus::Action command({{"address", "abcd"}, {"body", {}}, {"method", "PUT"}});
|
||||
nlohmann::json request = {{"command", command.toJson()}};
|
||||
nlohmann::json response = {{"success", {"/schedules/1/command", command.toJson()}}};
|
||||
EXPECT_CALL(
|
||||
*handler, PUTJson("/api/" + getBridgeUsername() + "/schedules/1", request, getBridgeIp(), getBridgePort()))
|
||||
.WillOnce(Return(response));
|
||||
expectGetState(id);
|
||||
schedule.setCommand(command);
|
||||
}
|
||||
|
||||
TEST_F(ScheduleTest, setTime)
|
||||
{
|
||||
const int id = 1;
|
||||
expectGetState(id);
|
||||
Schedule schedule(id, commands, std::chrono::steady_clock::duration::max(), nullptr);
|
||||
time::TimePattern time {time::AbsoluteVariedTime(std::chrono::system_clock::now())};
|
||||
nlohmann::json request = {{"localtime", time.toString()}};
|
||||
nlohmann::json response = {{"success", {"/schedules/1/localtime", time.toString()}}};
|
||||
EXPECT_CALL(
|
||||
*handler, PUTJson("/api/" + getBridgeUsername() + "/schedules/1", request, getBridgeIp(), getBridgePort()))
|
||||
.WillOnce(Return(response));
|
||||
expectGetState(id);
|
||||
schedule.setTime(time);
|
||||
}
|
||||
|
||||
TEST_F(ScheduleTest, setStatus)
|
||||
{
|
||||
const int id = 1;
|
||||
expectGetState(id);
|
||||
Schedule schedule(id, commands, std::chrono::steady_clock::duration::max(), nullptr);
|
||||
{
|
||||
nlohmann::json request = {{"status", "enabled"}};
|
||||
nlohmann::json response = {{"success", {"/schedules/1/status", "enabled"}}};
|
||||
EXPECT_CALL(
|
||||
*handler, PUTJson("/api/" + getBridgeUsername() + "/schedules/1", request, getBridgeIp(), getBridgePort()))
|
||||
.WillOnce(Return(response));
|
||||
expectGetState(id);
|
||||
schedule.setEnabled(true);
|
||||
}
|
||||
{
|
||||
nlohmann::json request = {{"status", "disabled"}};
|
||||
nlohmann::json response = {{"success", {"/schedules/1/status", "disabled"}}};
|
||||
EXPECT_CALL(
|
||||
*handler, PUTJson("/api/" + getBridgeUsername() + "/schedules/1", request, getBridgeIp(), getBridgePort()))
|
||||
.WillOnce(Return(response));
|
||||
expectGetState(id);
|
||||
schedule.setEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(ScheduleTest, setAutodelete)
|
||||
{
|
||||
const int id = 1;
|
||||
expectGetState(id);
|
||||
Schedule schedule(id, commands, std::chrono::steady_clock::duration::max(), nullptr);
|
||||
const bool autodelete = false;
|
||||
nlohmann::json request = {{"autodelete", autodelete}};
|
||||
nlohmann::json response = {{"success", {"/schedules/1/autodelete", autodelete}}};
|
||||
EXPECT_CALL(
|
||||
*handler, PUTJson("/api/" + getBridgeUsername() + "/schedules/1", request, getBridgeIp(), getBridgePort()))
|
||||
.WillOnce(Return(response));
|
||||
expectGetState(id);
|
||||
schedule.setAutodelete(autodelete);
|
||||
}
|
||||
|
||||
TEST(CreateSchedule, setName)
|
||||
{
|
||||
const std::string name = "New schedule";
|
||||
const nlohmann::json request = {{"name", name}};
|
||||
EXPECT_EQ(request, CreateSchedule().setName(name).getRequest());
|
||||
}
|
||||
|
||||
TEST(CreateSchedule, setDescription)
|
||||
{
|
||||
const std::string description = "New schedule description";
|
||||
{
|
||||
const nlohmann::json request = {{"description", description}};
|
||||
EXPECT_EQ(request, CreateSchedule().setDescription(description).getRequest());
|
||||
}
|
||||
{
|
||||
const std::string name = "New schedule name";
|
||||
const nlohmann::json request = {{"name", name}, {"description", description}};
|
||||
EXPECT_EQ(request, CreateSchedule().setName(name).setDescription(description).getRequest());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(CreateSchedule, setCommand)
|
||||
{
|
||||
const nlohmann::json commandJson = {{"address", "/api/asdf"}, {"method", "PUT"}, {"body", {}}};
|
||||
hueplusplus::Action command {commandJson};
|
||||
const nlohmann::json request = {{"command", commandJson}};
|
||||
EXPECT_EQ(request, CreateSchedule().setCommand(command).getRequest());
|
||||
}
|
||||
|
||||
TEST(CreateSchedule, setTime)
|
||||
{
|
||||
const time::AbsoluteVariedTime time(std::chrono::system_clock::now());
|
||||
const nlohmann::json request = {{"localtime", time.toString()}};
|
||||
EXPECT_EQ(request, CreateSchedule().setTime(time::TimePattern(time)).getRequest());
|
||||
}
|
||||
|
||||
TEST(CreateSchedule, setStatus)
|
||||
{
|
||||
{
|
||||
const nlohmann::json request = {{"status", "enabled"}};
|
||||
EXPECT_EQ(request, CreateSchedule().setStatus(true).getRequest());
|
||||
}
|
||||
{
|
||||
const nlohmann::json request = {{"status", "disabled"}};
|
||||
EXPECT_EQ(request, CreateSchedule().setStatus(false).getRequest());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(CreateSchedule, setAutodelete)
|
||||
{
|
||||
{
|
||||
const nlohmann::json request = { {"autodelete", true} };
|
||||
EXPECT_EQ(request, CreateSchedule().setAutodelete(true).getRequest());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(CreateSchedule, setRecycle)
|
||||
{
|
||||
{
|
||||
const nlohmann::json request = {{"recycle", true}};
|
||||
EXPECT_EQ(request, CreateSchedule().setRecycle(true).getRequest());
|
||||
}
|
||||
}
|
||||
+257
@@ -0,0 +1,257 @@
|
||||
/**
|
||||
\file test_Sensor.cpp
|
||||
Copyright Notice\n
|
||||
Copyright (C) 2020 Jan Rogall - developer\n
|
||||
|
||||
This file is part of hueplusplus.
|
||||
|
||||
hueplusplus 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.
|
||||
|
||||
hueplusplus 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 hueplusplus. If not, see <http://www.gnu.org/licenses/>.
|
||||
**/
|
||||
|
||||
#include <hueplusplus/Sensor.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "testhelper.h"
|
||||
|
||||
#include "mocks/mock_HttpHandler.h"
|
||||
|
||||
using namespace hueplusplus;
|
||||
using namespace testing;
|
||||
|
||||
class SensorTest : public Test
|
||||
{
|
||||
protected:
|
||||
std::shared_ptr<MockHttpHandler> handler;
|
||||
HueCommandAPI commands;
|
||||
nlohmann::json state;
|
||||
|
||||
protected:
|
||||
SensorTest()
|
||||
: handler(std::make_shared<MockHttpHandler>()),
|
||||
commands(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler),
|
||||
state({{"type", "testSensor"}, {"name", "Test sensor"}, {"swversion", "1.2.3.4"}, {"modelid", "test"},
|
||||
{"manufacturername", "testManuf"}, {"uniqueid", "00:00:00:00:00:00:00:00-00"},
|
||||
{"productname", "Test sensor"}, {"config", nlohmann::json::object()},
|
||||
{"state", nlohmann::json::object()}})
|
||||
{ }
|
||||
|
||||
Sensor getSensor(int id = 1)
|
||||
{
|
||||
EXPECT_CALL(*handler,
|
||||
GETJson(
|
||||
"/api/" + getBridgeUsername() + "/sensors/" + std::to_string(id), _, getBridgeIp(), getBridgePort()))
|
||||
.WillOnce(Return(state));
|
||||
return Sensor(id, commands, std::chrono::steady_clock::duration::max(), nullptr);
|
||||
}
|
||||
};
|
||||
|
||||
TEST(Alert, alertFromString)
|
||||
{
|
||||
EXPECT_EQ(Alert::none, alertFromString("none"));
|
||||
EXPECT_EQ(Alert::select, alertFromString("select"));
|
||||
EXPECT_EQ(Alert::lselect, alertFromString("lselect"));
|
||||
EXPECT_EQ(Alert::none, alertFromString("anything"));
|
||||
}
|
||||
|
||||
TEST(Alert, alertToString)
|
||||
{
|
||||
EXPECT_EQ("none", alertToString(Alert::none));
|
||||
EXPECT_EQ("select", alertToString(Alert::select));
|
||||
EXPECT_EQ("lselect", alertToString(Alert::lselect));
|
||||
}
|
||||
|
||||
TEST_F(SensorTest, on)
|
||||
{
|
||||
EXPECT_FALSE(getSensor().hasOn());
|
||||
state["config"]["on"] = true;
|
||||
EXPECT_TRUE(getSensor().hasOn());
|
||||
EXPECT_TRUE(getSensor().isOn());
|
||||
|
||||
EXPECT_CALL(*handler,
|
||||
PUTJson("/api/" + getBridgeUsername() + "/sensors/1/config", nlohmann::json({{"on", false}}), getBridgeIp(),
|
||||
getBridgePort()))
|
||||
.WillOnce(Return(nlohmann::json {{{"success", {{"/sensors/1/config/on", false}}}}}));
|
||||
getSensor().setOn(false);
|
||||
}
|
||||
|
||||
TEST_F(SensorTest, BatteryState)
|
||||
{
|
||||
EXPECT_FALSE(getSensor().hasBatteryState());
|
||||
state["config"]["battery"] = 90;
|
||||
EXPECT_TRUE(getSensor().hasBatteryState());
|
||||
EXPECT_EQ(90, getSensor().getBatteryState());
|
||||
|
||||
int percent = 10;
|
||||
EXPECT_CALL(*handler,
|
||||
PUTJson("/api/" + getBridgeUsername() + "/sensors/1/config", nlohmann::json({{"battery", percent}}),
|
||||
getBridgeIp(), getBridgePort()))
|
||||
.WillOnce(Return(nlohmann::json {{{"success", {{"/sensors/1/config/battery", percent}}}}}));
|
||||
getSensor().setBatteryState(percent);
|
||||
}
|
||||
|
||||
TEST_F(SensorTest, Alert)
|
||||
{
|
||||
EXPECT_FALSE(getSensor().hasAlert());
|
||||
state["config"]["alert"] = "none";
|
||||
EXPECT_TRUE(getSensor().hasAlert());
|
||||
EXPECT_EQ(Alert::none, getSensor().getLastAlert());
|
||||
|
||||
std::string alert = "lselect";
|
||||
EXPECT_CALL(*handler,
|
||||
PUTJson("/api/" + getBridgeUsername() + "/sensors/1/config", nlohmann::json({{"alert", alert}}), getBridgeIp(),
|
||||
getBridgePort()))
|
||||
.WillOnce(Return(nlohmann::json {{{"success", {{"/sensors/1/config/alert", alert}}}}}));
|
||||
getSensor().sendAlert(Alert::lselect);
|
||||
}
|
||||
|
||||
TEST_F(SensorTest, Reachable)
|
||||
{
|
||||
EXPECT_FALSE(getSensor().hasReachable());
|
||||
state["config"]["reachable"] = false;
|
||||
EXPECT_TRUE(getSensor().hasReachable());
|
||||
EXPECT_FALSE(getSensor().isReachable());
|
||||
}
|
||||
|
||||
TEST_F(SensorTest, UserTest)
|
||||
{
|
||||
EXPECT_FALSE(getSensor().hasUserTest());
|
||||
state["config"]["usertest"] = false;
|
||||
EXPECT_TRUE(getSensor().hasUserTest());
|
||||
|
||||
EXPECT_CALL(*handler,
|
||||
PUTJson("/api/" + getBridgeUsername() + "/sensors/1/config", nlohmann::json({{"usertest", true}}),
|
||||
getBridgeIp(), getBridgePort()))
|
||||
.WillOnce(Return(nlohmann::json {{{"success", {{"/sensors/1/config/usertest", true}}}}}));
|
||||
getSensor().setUserTest(true);
|
||||
}
|
||||
|
||||
TEST_F(SensorTest, URL)
|
||||
{
|
||||
EXPECT_FALSE(getSensor().hasURL());
|
||||
const std::string url = "https://abc";
|
||||
state["config"]["url"] = url;
|
||||
EXPECT_TRUE(getSensor().hasURL());
|
||||
EXPECT_EQ(url, getSensor().getURL());
|
||||
|
||||
std::string newUrl = "https://cde";
|
||||
EXPECT_CALL(*handler,
|
||||
PUTJson("/api/" + getBridgeUsername() + "/sensors/1/config", nlohmann::json({{"url", newUrl}}), getBridgeIp(),
|
||||
getBridgePort()))
|
||||
.WillOnce(Return(nlohmann::json {{{"success", {{"/sensors/1/config/url", newUrl}}}}}));
|
||||
getSensor().setURL(newUrl);
|
||||
}
|
||||
|
||||
TEST_F(SensorTest, getPendingConfig)
|
||||
{
|
||||
EXPECT_TRUE(getSensor().getPendingConfig().empty());
|
||||
state["config"]["pending"] = nullptr;
|
||||
EXPECT_TRUE(getSensor().getPendingConfig().empty());
|
||||
|
||||
state["config"]["pending"] = {"abc", "cde", "def"};
|
||||
|
||||
EXPECT_THAT(getSensor().getPendingConfig(), UnorderedElementsAre("abc", "cde", "def"));
|
||||
}
|
||||
|
||||
TEST_F(SensorTest, LEDIndication)
|
||||
{
|
||||
EXPECT_FALSE(getSensor().hasLEDIndication());
|
||||
state["config"]["ledindication"] = true;
|
||||
EXPECT_TRUE(getSensor().hasLEDIndication());
|
||||
EXPECT_TRUE(getSensor().getLEDIndication());
|
||||
|
||||
EXPECT_CALL(*handler,
|
||||
PUTJson("/api/" + getBridgeUsername() + "/sensors/1/config", nlohmann::json({{"ledindication", false}}),
|
||||
getBridgeIp(), getBridgePort()))
|
||||
.WillOnce(Return(nlohmann::json {{{"success", {{"/sensors/1/config/ledindication", false}}}}}));
|
||||
getSensor().setLEDIndication(false);
|
||||
}
|
||||
|
||||
TEST_F(SensorTest, getConfig)
|
||||
{
|
||||
EXPECT_EQ(state["config"], getSensor().getConfig());
|
||||
state["config"]["attribute"] = false;
|
||||
EXPECT_EQ(state["config"], getSensor().getConfig());
|
||||
}
|
||||
|
||||
TEST_F(SensorTest, setConfigAttribute)
|
||||
{
|
||||
const std::string key = "attribute";
|
||||
const nlohmann::json value = "some value";
|
||||
EXPECT_CALL(*handler,
|
||||
PUTJson("/api/" + getBridgeUsername() + "/sensors/1/config", nlohmann::json({{key, value}}), getBridgeIp(),
|
||||
getBridgePort()))
|
||||
.WillOnce(Return(nlohmann::json {{{"success", {{"/sensors/1/config/" + key, value}}}}}));
|
||||
getSensor().setConfigAttribute(key, value);
|
||||
}
|
||||
|
||||
TEST_F(SensorTest, getLastUpdated)
|
||||
{
|
||||
time::AbsoluteTime none = getSensor().getLastUpdated();
|
||||
EXPECT_EQ(std::chrono::seconds(0), none.getBaseTime().time_since_epoch());
|
||||
|
||||
const std::string timestamp = "2020-05-02T12:00:01";
|
||||
state["state"]["lastupdated"] = timestamp;
|
||||
time::AbsoluteTime time = time::AbsoluteTime::parseUTC(timestamp);
|
||||
EXPECT_EQ(time.getBaseTime(), getSensor().getLastUpdated().getBaseTime());
|
||||
}
|
||||
|
||||
TEST_F(SensorTest, getState)
|
||||
{
|
||||
nlohmann::json stateContent = {{"bla", "bla"}};
|
||||
state["state"] = stateContent;
|
||||
EXPECT_EQ(stateContent, getSensor().getState());
|
||||
}
|
||||
|
||||
TEST_F(SensorTest, setStateAttribute)
|
||||
{
|
||||
const std::string key = "attribute";
|
||||
const nlohmann::json value = "some value";
|
||||
EXPECT_CALL(*handler,
|
||||
PUTJson("/api/" + getBridgeUsername() + "/sensors/1/state", nlohmann::json({{key, value}}), getBridgeIp(),
|
||||
getBridgePort()))
|
||||
.WillOnce(Return(nlohmann::json {{{"success", {{"/sensors/1/state/" + key, value}}}}}));
|
||||
getSensor().setStateAttribute(key, value);
|
||||
}
|
||||
|
||||
TEST_F(SensorTest, isCertified)
|
||||
{
|
||||
EXPECT_FALSE(getSensor().isCertified());
|
||||
state["capabilities"]["certified"] = true;
|
||||
EXPECT_TRUE(getSensor().isCertified());
|
||||
}
|
||||
|
||||
TEST_F(SensorTest, isPrimary)
|
||||
{
|
||||
EXPECT_FALSE(getSensor().isPrimary());
|
||||
state["capabilities"]["primary"] = true;
|
||||
EXPECT_TRUE(getSensor().isPrimary());
|
||||
}
|
||||
|
||||
TEST_F(SensorTest, asSensorType)
|
||||
{
|
||||
// Test both rvalue and const access
|
||||
{
|
||||
const Sensor s = getSensor();
|
||||
EXPECT_THROW(s.asSensorType<sensors::DaylightSensor>(), HueException);
|
||||
}
|
||||
EXPECT_THROW(getSensor().asSensorType<sensors::DaylightSensor>(), HueException);
|
||||
|
||||
state["type"] = sensors::DaylightSensor::typeStr;
|
||||
sensors::DaylightSensor ds = getSensor().asSensorType<sensors::DaylightSensor>();
|
||||
EXPECT_EQ(1, ds.getId());
|
||||
const Sensor s = getSensor();
|
||||
ds = s.asSensorType<sensors::DaylightSensor>();
|
||||
EXPECT_EQ(s.getId(), ds.getId());
|
||||
}
|
||||
@@ -0,0 +1,392 @@
|
||||
/**
|
||||
\file test_SensorImpls.cpp
|
||||
Copyright Notice\n
|
||||
Copyright (C) 2020 Jan Rogall - developer\n
|
||||
|
||||
This file is part of hueplusplus.
|
||||
|
||||
hueplusplus 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.
|
||||
|
||||
hueplusplus 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 hueplusplus. If not, see <http://www.gnu.org/licenses/>.
|
||||
**/
|
||||
|
||||
#include <hueplusplus/CLIPSensors.h>
|
||||
#include <hueplusplus/ZLLSensors.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "testhelper.h"
|
||||
|
||||
#include "mocks/mock_HttpHandler.h"
|
||||
|
||||
using namespace testing;
|
||||
using namespace hueplusplus;
|
||||
using namespace hueplusplus::sensors;
|
||||
|
||||
// Many sensor classes contain duplicate methods, with the type parameterized tests at least the test cases
|
||||
// do not have to be duplicated
|
||||
template <typename T>
|
||||
class SensorImplTest : public Test
|
||||
{
|
||||
protected:
|
||||
std::shared_ptr<MockHttpHandler> handler;
|
||||
HueCommandAPI commands;
|
||||
nlohmann::json state;
|
||||
|
||||
protected:
|
||||
SensorImplTest()
|
||||
: handler(std::make_shared<MockHttpHandler>()),
|
||||
commands(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler),
|
||||
state({{"type", T::typeStr}, {"config", nlohmann::json::object()}, {"state", nlohmann::json::object()}})
|
||||
{ }
|
||||
|
||||
void expectConfigSet(const std::string& key, const nlohmann::json& value)
|
||||
{
|
||||
EXPECT_CALL(*handler,
|
||||
PUTJson("/api/" + getBridgeUsername() + "/sensors/1/config", nlohmann::json({{key, value}}), getBridgeIp(),
|
||||
getBridgePort()))
|
||||
.WillOnce(Return(nlohmann::json {{{"success", {{"/sensors/1/config/" + key, value}}}}}));
|
||||
}
|
||||
void expectStateSet(const std::string& key, const nlohmann::json& value)
|
||||
{
|
||||
EXPECT_CALL(*handler,
|
||||
PUTJson("/api/" + getBridgeUsername() + "/sensors/1/state", nlohmann::json({{key, value}}), getBridgeIp(),
|
||||
getBridgePort()))
|
||||
.WillOnce(Return(nlohmann::json {{{"success", {{"/sensors/1/state/" + key, value}}}}}));
|
||||
}
|
||||
|
||||
T getSensor()
|
||||
{
|
||||
EXPECT_CALL(*handler, GETJson("/api/" + getBridgeUsername() + "/sensors/1", _, getBridgeIp(), getBridgePort()))
|
||||
.WillOnce(Return(state));
|
||||
return T(Sensor(1, commands, std::chrono::steady_clock::duration::max(), nullptr));
|
||||
}
|
||||
};
|
||||
|
||||
// Sensors with shared methods
|
||||
|
||||
template <typename T>
|
||||
class SensorOnTest : public SensorImplTest<T>
|
||||
{ };
|
||||
// Only need to test one CLIP type, because they share the basic methods
|
||||
using SensorOnTypes
|
||||
= Types<CLIPSwitch, ZGPSwitch, ZLLSwitch, ZLLPresence, ZLLTemperature, ZLLLightLevel, DaylightSensor>;
|
||||
TYPED_TEST_SUITE(SensorOnTest, SensorOnTypes);
|
||||
|
||||
template <typename T>
|
||||
class SensorBatteryTest : public SensorImplTest<T>
|
||||
{ };
|
||||
using SensorBatteryTypes = Types<CLIPSwitch, ZLLSwitch, ZLLPresence, ZLLTemperature, ZLLLightLevel, DaylightSensor>;
|
||||
TYPED_TEST_SUITE(SensorBatteryTest, SensorBatteryTypes);
|
||||
|
||||
template <typename T>
|
||||
class SensorReachableTest : public SensorImplTest<T>
|
||||
{ };
|
||||
using SensorReachableTypes = Types<CLIPSwitch, ZLLSwitch, ZLLPresence, ZLLTemperature, ZLLLightLevel>;
|
||||
TYPED_TEST_SUITE(SensorReachableTest, SensorReachableTypes);
|
||||
|
||||
template <typename T>
|
||||
class SensorUpdateTest : public SensorImplTest<T>
|
||||
{ };
|
||||
using SensorUpdateTypes = Types<CLIPSwitch, ZLLSwitch, ZLLPresence, ZLLLightLevel, ZLLTemperature, DaylightSensor>;
|
||||
TYPED_TEST_SUITE(SensorUpdateTest, SensorUpdateTypes);
|
||||
|
||||
template <typename T>
|
||||
class SensorAlertTest : public SensorImplTest<T>
|
||||
{ };
|
||||
using SensorAlertTypes = Types<ZLLSwitch, ZLLPresence, ZLLTemperature>;
|
||||
TYPED_TEST_SUITE(SensorAlertTest, SensorAlertTypes);
|
||||
|
||||
template <typename T>
|
||||
class SensorButtonTest : public SensorImplTest<T>
|
||||
{ };
|
||||
using SensorButtonTypes = Types<CLIPSwitch, ZLLSwitch, ZGPSwitch>;
|
||||
TYPED_TEST_SUITE(SensorButtonTest, SensorButtonTypes);
|
||||
|
||||
template <typename T>
|
||||
class SensorTemperatureTest : public SensorImplTest<T>
|
||||
{ };
|
||||
using SensorTemperatureTypes = Types<CLIPTemperature, ZLLTemperature>;
|
||||
TYPED_TEST_SUITE(SensorTemperatureTest, SensorTemperatureTypes);
|
||||
|
||||
template <typename T>
|
||||
class SensorLightLevelTest : public SensorImplTest<T>
|
||||
{ };
|
||||
using SensorLightLevelTypes = Types<CLIPLightLevel, ZLLLightLevel>;
|
||||
TYPED_TEST_SUITE(SensorLightLevelTest, SensorLightLevelTypes);
|
||||
|
||||
template <typename T>
|
||||
class SensorPresenceTest : public SensorImplTest<T>
|
||||
{ };
|
||||
using SensorPresenceTypes = Types<CLIPPresence, ZLLPresence>;
|
||||
TYPED_TEST_SUITE(SensorPresenceTest, SensorPresenceTypes);
|
||||
|
||||
// Sensors with unique methods
|
||||
|
||||
class DaylightSensorTest : public SensorImplTest<DaylightSensor>
|
||||
{ };
|
||||
|
||||
class ZLLPresenceTest : public SensorImplTest<ZLLPresence>
|
||||
{ };
|
||||
|
||||
class CLIPSwitchTest : public SensorImplTest<CLIPSwitch>
|
||||
{ };
|
||||
|
||||
class CLIPOpenCloseTest : public SensorImplTest<CLIPOpenClose>
|
||||
{ };
|
||||
|
||||
class CLIPPresenceTest : public SensorImplTest<CLIPPresence>
|
||||
{ };
|
||||
|
||||
class CLIPTemperatureTest : public SensorImplTest<CLIPTemperature>
|
||||
{ };
|
||||
|
||||
class CLIPHumidityTest : public SensorImplTest<CLIPHumidity>
|
||||
{ };
|
||||
|
||||
class CLIPGenericFlagTest : public SensorImplTest<CLIPGenericFlag>
|
||||
{ };
|
||||
|
||||
class CLIPGenericStatusTest : public SensorImplTest<CLIPGenericStatus>
|
||||
{ };
|
||||
|
||||
TYPED_TEST(SensorOnTest, on)
|
||||
{
|
||||
this->state["config"]["on"] = false;
|
||||
EXPECT_FALSE(this->getSensor().isOn());
|
||||
this->state["config"]["on"] = true;
|
||||
EXPECT_TRUE(this->getSensor().isOn());
|
||||
|
||||
this->expectConfigSet("on", false);
|
||||
this->getSensor().setOn(false);
|
||||
}
|
||||
|
||||
TYPED_TEST(SensorBatteryTest, BatteryState)
|
||||
{
|
||||
EXPECT_FALSE(this->getSensor().hasBatteryState());
|
||||
this->state["config"]["battery"] = 90;
|
||||
EXPECT_TRUE(this->getSensor().hasBatteryState());
|
||||
EXPECT_EQ(90, this->getSensor().getBatteryState());
|
||||
}
|
||||
|
||||
TYPED_TEST(SensorReachableTest, Reachable)
|
||||
{
|
||||
this->state["config"]["reachable"] = true;
|
||||
EXPECT_TRUE(this->getSensor().isReachable());
|
||||
}
|
||||
|
||||
TYPED_TEST(SensorUpdateTest, getLastUpdated)
|
||||
{
|
||||
time::AbsoluteTime none = this->getSensor().getLastUpdated();
|
||||
EXPECT_EQ(std::chrono::seconds(0), none.getBaseTime().time_since_epoch());
|
||||
|
||||
const std::string timestamp = "2020-05-02T12:00:01";
|
||||
this->state["state"]["lastupdated"] = timestamp;
|
||||
time::AbsoluteTime time = time::AbsoluteTime::parseUTC(timestamp);
|
||||
EXPECT_EQ(time.getBaseTime(), this->getSensor().getLastUpdated().getBaseTime());
|
||||
}
|
||||
|
||||
TYPED_TEST(SensorAlertTest, Alert)
|
||||
{
|
||||
this->state["config"]["alert"] = "none";
|
||||
EXPECT_EQ(Alert::none, this->getSensor().getLastAlert());
|
||||
|
||||
this->expectConfigSet("alert", "lselect");
|
||||
this->getSensor().sendAlert(Alert::lselect);
|
||||
}
|
||||
|
||||
TYPED_TEST(SensorButtonTest, ButtonEvent)
|
||||
{
|
||||
int code = 12;
|
||||
this->state["state"]["buttonevent"] = code;
|
||||
EXPECT_EQ(code, this->getSensor().getButtonEvent());
|
||||
}
|
||||
|
||||
TYPED_TEST(SensorTemperatureTest, Temperature)
|
||||
{
|
||||
int temperature = 1200;
|
||||
this->state["state"]["temperature"] = temperature;
|
||||
EXPECT_EQ(temperature, this->getSensor().getTemperature());
|
||||
}
|
||||
|
||||
TYPED_TEST(SensorLightLevelTest, LightLevel)
|
||||
{
|
||||
int lightLevel = 1200;
|
||||
this->state["state"] = {{"lightlevel", lightLevel}, {"dark", true}, {"daylight", false}};
|
||||
EXPECT_EQ(lightLevel, this->getSensor().getLightLevel());
|
||||
EXPECT_TRUE(this->getSensor().isDark());
|
||||
EXPECT_FALSE(this->getSensor().isDaylight());
|
||||
}
|
||||
|
||||
TYPED_TEST(SensorLightLevelTest, DarkThreshold)
|
||||
{
|
||||
int darkThreshold = 12000;
|
||||
this->state["config"]["tholddark"] = darkThreshold;
|
||||
EXPECT_EQ(darkThreshold, this->getSensor().getDarkThreshold());
|
||||
|
||||
int newThreshold = 10;
|
||||
this->expectConfigSet("tholddark", newThreshold);
|
||||
this->getSensor().setDarkThreshold(newThreshold);
|
||||
}
|
||||
|
||||
TYPED_TEST(SensorLightLevelTest, ThresholdOffset)
|
||||
{
|
||||
int offset = 12000;
|
||||
this->state["config"]["tholdoffset"] = offset;
|
||||
EXPECT_EQ(offset, this->getSensor().getThresholdOffset());
|
||||
|
||||
int newOffset = 10;
|
||||
this->expectConfigSet("tholdoffset", newOffset);
|
||||
this->getSensor().setThresholdOffset(newOffset);
|
||||
}
|
||||
|
||||
TYPED_TEST(SensorPresenceTest, Presence)
|
||||
{
|
||||
this->state["state"]["presence"] = true;
|
||||
EXPECT_TRUE(this->getSensor().getPresence());
|
||||
}
|
||||
|
||||
TEST_F(DaylightSensorTest, Coordinates)
|
||||
{
|
||||
const std::string lat = "000.0000N";
|
||||
const std::string lon = "000.0000E";
|
||||
EXPECT_CALL(*handler,
|
||||
PUTJson("/api/" + getBridgeUsername() + "/sensors/1/config", nlohmann::json({{"lat", lat}, {"long", lon}}),
|
||||
getBridgeIp(), getBridgePort()))
|
||||
.WillOnce(Return(nlohmann::json {
|
||||
{{"success", {{"/sensors/1/config/lat", lat}}}}, {{"success", {{"/sensors/1/config/long", lon}}}}}));
|
||||
getSensor().setCoordinates(lat, lon);
|
||||
state["config"]["configured"] = true;
|
||||
EXPECT_TRUE(getSensor().isConfigured());
|
||||
}
|
||||
|
||||
TEST_F(DaylightSensorTest, SunriseOffset)
|
||||
{
|
||||
int offset = 10;
|
||||
state["config"]["sunriseoffset"] = offset;
|
||||
EXPECT_EQ(offset, getSensor().getSunriseOffset());
|
||||
|
||||
int newOffset = 20;
|
||||
expectConfigSet("sunriseoffset", newOffset);
|
||||
getSensor().setSunriseOffset(newOffset);
|
||||
}
|
||||
|
||||
TEST_F(DaylightSensorTest, SunsetOffset)
|
||||
{
|
||||
int offset = 10;
|
||||
state["config"]["sunsetoffset"] = offset;
|
||||
EXPECT_EQ(offset, getSensor().getSunsetOffset());
|
||||
|
||||
int newOffset = 20;
|
||||
expectConfigSet("sunsetoffset", newOffset);
|
||||
getSensor().setSunsetOffset(newOffset);
|
||||
}
|
||||
|
||||
TEST_F(DaylightSensorTest, isDaylight)
|
||||
{
|
||||
state["state"]["daylight"] = true;
|
||||
EXPECT_TRUE(getSensor().isDaylight());
|
||||
}
|
||||
|
||||
TEST_F(ZLLPresenceTest, Sensitivity)
|
||||
{
|
||||
int sensitivity = 1000;
|
||||
state["config"]["sensitivity"] = sensitivity;
|
||||
int maxSensitivity = 10000;
|
||||
state["config"]["sensitivitymax"] = maxSensitivity;
|
||||
EXPECT_EQ(sensitivity, getSensor().getSensitivity());
|
||||
EXPECT_EQ(maxSensitivity, getSensor().getMaxSensitivity());
|
||||
|
||||
int newSensitivity = 10;
|
||||
expectConfigSet("sensitivity", newSensitivity);
|
||||
this->getSensor().setSensitivity(newSensitivity);
|
||||
}
|
||||
|
||||
TEST_F(CLIPSwitchTest, setBatteryState)
|
||||
{
|
||||
int percent = 10;
|
||||
expectConfigSet("battery", percent);
|
||||
this->getSensor().setBatteryState(percent);
|
||||
}
|
||||
|
||||
TEST_F(CLIPSwitchTest, URL)
|
||||
{
|
||||
EXPECT_FALSE(getSensor().hasURL());
|
||||
const std::string url = "https://abc";
|
||||
state["config"]["url"] = url;
|
||||
EXPECT_TRUE(getSensor().hasURL());
|
||||
EXPECT_EQ(url, getSensor().getURL());
|
||||
|
||||
std::string newUrl = "https://cde";
|
||||
expectConfigSet("url", newUrl);
|
||||
getSensor().setURL(newUrl);
|
||||
}
|
||||
|
||||
TEST_F(CLIPSwitchTest, setButtonEvent)
|
||||
{
|
||||
int code = 10;
|
||||
expectStateSet("buttonevent", code);
|
||||
this->getSensor().setButtonEvent(code);
|
||||
}
|
||||
|
||||
TEST_F(CLIPOpenCloseTest, Open)
|
||||
{
|
||||
state["state"]["open"] = true;
|
||||
EXPECT_TRUE(getSensor().isOpen());
|
||||
|
||||
bool open = false;
|
||||
expectStateSet("open", open);
|
||||
getSensor().setOpen(open);
|
||||
}
|
||||
|
||||
TEST_F(CLIPPresenceTest, setPresence)
|
||||
{
|
||||
bool presence = false;
|
||||
expectStateSet("presence", presence);
|
||||
getSensor().setPresence(presence);
|
||||
}
|
||||
|
||||
TEST_F(CLIPTemperatureTest, setPresence)
|
||||
{
|
||||
int temperature = 1100;
|
||||
expectStateSet("temperature", temperature);
|
||||
getSensor().setTemperature(temperature);
|
||||
}
|
||||
|
||||
TEST_F(CLIPHumidityTest, Humidity)
|
||||
{
|
||||
int humidity = 100;
|
||||
state["state"]["humidity"] = humidity;
|
||||
EXPECT_EQ(humidity, getSensor().getHumidity());
|
||||
|
||||
int newHumidity = 1100;
|
||||
expectStateSet("humidity", newHumidity);
|
||||
getSensor().setHumidity(newHumidity);
|
||||
}
|
||||
|
||||
TEST_F(CLIPGenericFlagTest, Flag)
|
||||
{
|
||||
state["state"]["flag"] = true;
|
||||
EXPECT_TRUE(getSensor().getFlag());
|
||||
expectStateSet("flag", false);
|
||||
getSensor().setFlag(false);
|
||||
}
|
||||
|
||||
TEST_F(CLIPGenericStatusTest, Status)
|
||||
{
|
||||
int status = 32;
|
||||
state["state"]["status"] = status;
|
||||
EXPECT_EQ(status, getSensor().getStatus());
|
||||
int newStatus = 52;
|
||||
expectStateSet("status", newStatus);
|
||||
getSensor().setStatus(newStatus);
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
/**
|
||||
\file test_SensorList.cpp
|
||||
Copyright Notice\n
|
||||
Copyright (C) 2020 Jan Rogall - developer\n
|
||||
|
||||
This file is part of hueplusplus.
|
||||
|
||||
hueplusplus 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.
|
||||
|
||||
hueplusplus 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 hueplusplus. If not, see <http://www.gnu.org/licenses/>.
|
||||
**/
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "testhelper.h"
|
||||
|
||||
#include "hueplusplus/SensorList.h"
|
||||
#include "mocks/mock_HttpHandler.h"
|
||||
|
||||
using namespace hueplusplus;
|
||||
using namespace testing;
|
||||
|
||||
class BlaSensor
|
||||
{
|
||||
public:
|
||||
BlaSensor(Sensor s) { }
|
||||
|
||||
static constexpr const char* typeStr = "bla";
|
||||
};
|
||||
|
||||
TEST(SensorList, getAsType)
|
||||
{
|
||||
auto handler = std::make_shared<MockHttpHandler>();
|
||||
HueCommandAPI commands(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler);
|
||||
|
||||
SensorList sensors {commands, "/sensors", std::chrono::steady_clock::duration::max()};
|
||||
|
||||
const int id = 2;
|
||||
const nlohmann::json response = {{std::to_string(id), {{"type", "Daylight"}}}};
|
||||
|
||||
EXPECT_CALL(*handler,
|
||||
GETJson("/api/" + getBridgeUsername() + "/sensors", nlohmann::json::object(), getBridgeIp(), getBridgePort()))
|
||||
.WillOnce(Return(response));
|
||||
|
||||
sensors::DaylightSensor daylightSensor = sensors.getAsType<sensors::DaylightSensor>(id);
|
||||
EXPECT_THROW(sensors.getAsType<BlaSensor>(2), HueException);
|
||||
}
|
||||
|
||||
TEST(SensorList, getAllByType)
|
||||
{
|
||||
|
||||
auto handler = std::make_shared<MockHttpHandler>();
|
||||
HueCommandAPI commands(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler);
|
||||
|
||||
SensorList sensors {commands, "/sensors", std::chrono::steady_clock::duration::max()};
|
||||
|
||||
// Empty
|
||||
{
|
||||
const nlohmann::json response = nlohmann::json::object();
|
||||
|
||||
EXPECT_CALL(*handler,
|
||||
GETJson(
|
||||
"/api/" + getBridgeUsername() + "/sensors", nlohmann::json::object(), getBridgeIp(), getBridgePort()))
|
||||
.WillOnce(Return(response));
|
||||
EXPECT_TRUE(sensors.getAllByType<sensors::DaylightSensor>().empty());
|
||||
}
|
||||
// Not matching
|
||||
{
|
||||
const nlohmann::json response = {{"1", {{"type", "stuff"}}}};
|
||||
EXPECT_CALL(*handler,
|
||||
GETJson(
|
||||
"/api/" + getBridgeUsername() + "/sensors", nlohmann::json::object(), getBridgeIp(), getBridgePort()))
|
||||
.WillOnce(Return(response));
|
||||
sensors.refresh();
|
||||
EXPECT_TRUE(sensors.getAllByType<sensors::DaylightSensor>().empty());
|
||||
}
|
||||
// Some matching (daylight maybe not the best example, because there is always exactly one)
|
||||
{
|
||||
const nlohmann::json response = {{"1", {{"type", "stuff"}}}, {"2", {{"type", "Daylight"}}},
|
||||
{"3", {{"type", "stuff"}}}, {"4", {{"type", "Daylight"}}}};
|
||||
EXPECT_CALL(*handler,
|
||||
GETJson(
|
||||
"/api/" + getBridgeUsername() + "/sensors", nlohmann::json::object(), getBridgeIp(), getBridgePort()))
|
||||
.WillOnce(Return(response));
|
||||
sensors.refresh();
|
||||
std::vector<sensors::DaylightSensor> result = sensors.getAllByType<sensors::DaylightSensor>();
|
||||
EXPECT_THAT(result,
|
||||
UnorderedElementsAre(Truly([](const auto& s) { return s.getId() == 2; }),
|
||||
Truly([](const auto& s) { return s.getId() == 4; })));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
/**
|
||||
\file test_SimpleBrightnessStrategy.cpp
|
||||
Copyright Notice\n
|
||||
Copyright (C) 2017 Jan Rogall - developer\n
|
||||
Copyright (C) 2017 Moritz Wirger - developer\n
|
||||
|
||||
This file is part of hueplusplus.
|
||||
|
||||
hueplusplus 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.
|
||||
|
||||
hueplusplus 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 hueplusplus. If not, see <http://www.gnu.org/licenses/>.
|
||||
**/
|
||||
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include <gmock/gmock.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "testhelper.h"
|
||||
|
||||
#include "hueplusplus/SimpleBrightnessStrategy.h"
|
||||
#include <nlohmann/json.hpp>
|
||||
#include "mocks/mock_HttpHandler.h"
|
||||
#include "mocks/mock_Light.h"
|
||||
|
||||
using namespace hueplusplus;
|
||||
|
||||
TEST(SimpleBrightnessStrategy, setBrightness)
|
||||
{
|
||||
using namespace ::testing;
|
||||
std::shared_ptr<MockHttpHandler> handler(std::make_shared<MockHttpHandler>());
|
||||
EXPECT_CALL(
|
||||
*handler, GETJson("/api/" + getBridgeUsername() + "/lights/1", nlohmann::json::object(), getBridgeIp(), 80))
|
||||
.Times(AtLeast(1))
|
||||
.WillRepeatedly(Return(nlohmann::json::object()));
|
||||
MockLight test_light(handler);
|
||||
|
||||
const std::string statePath = "/api/" + getBridgeUsername() + "/lights/1/state";
|
||||
|
||||
nlohmann::json prep_ret
|
||||
= {{{"success", {{"/lights/1/state/on", false}}}}, {{"success", {{"/lights/1/state/bri", 0}}}}};
|
||||
EXPECT_CALL(*handler, PUTJson(statePath, _, getBridgeIp(), getBridgePort())).Times(1).WillOnce(Return(prep_ret));
|
||||
test_light.getState()["state"]["on"] = true;
|
||||
EXPECT_EQ(true, SimpleBrightnessStrategy().setBrightness(0, 4, test_light));
|
||||
// Only set brightness, already off
|
||||
test_light.getState()["state"]["on"] = false;
|
||||
test_light.getState()["state"].erase("bri");
|
||||
prep_ret = {{{"success", {{"/lights/1/state/bri", 0}}}}};
|
||||
EXPECT_CALL(*handler, PUTJson(statePath, _, getBridgeIp(), getBridgePort())).Times(1).WillOnce(Return(prep_ret));
|
||||
EXPECT_EQ(true, SimpleBrightnessStrategy().setBrightness(0, 4, test_light));
|
||||
|
||||
prep_ret = {{{"success", {{"/lights/1/state/on", true}}}}, {{"success", {{"/lights/1/state/bri", 50}}}}};
|
||||
EXPECT_CALL(*handler, PUTJson(statePath, _, getBridgeIp(), getBridgePort())).Times(1).WillOnce(Return(prep_ret));
|
||||
test_light.getState()["state"]["bri"] = 0;
|
||||
EXPECT_EQ(true, SimpleBrightnessStrategy().setBrightness(50, 6, test_light));
|
||||
test_light.getState()["state"]["on"] = true;
|
||||
test_light.getState()["state"]["bri"] = 50;
|
||||
// No request because state matches
|
||||
EXPECT_EQ(true, SimpleBrightnessStrategy().setBrightness(50, 6, test_light));
|
||||
|
||||
prep_ret[1]["success"]["/lights/1/state/bri"] = 254;
|
||||
EXPECT_CALL(*handler, PUTJson(statePath, _, getBridgeIp(), getBridgePort())).Times(1).WillOnce(Return(prep_ret));
|
||||
test_light.getState()["state"]["on"] = false;
|
||||
test_light.getState()["state"]["bri"] = 50;
|
||||
EXPECT_EQ(true, SimpleBrightnessStrategy().setBrightness(255, 6, test_light));
|
||||
}
|
||||
|
||||
TEST(SimpleBrightnessStrategy, getBrightness)
|
||||
{
|
||||
using namespace ::testing;
|
||||
std::shared_ptr<MockHttpHandler> handler(std::make_shared<MockHttpHandler>());
|
||||
EXPECT_CALL(
|
||||
*handler, GETJson("/api/" + getBridgeUsername() + "/lights/1", nlohmann::json::object(), getBridgeIp(), 80))
|
||||
.Times(AtLeast(1))
|
||||
.WillRepeatedly(Return(nlohmann::json::object()));
|
||||
MockLight test_light(handler);
|
||||
|
||||
test_light.getState()["state"]["bri"] = 200;
|
||||
EXPECT_EQ(200, SimpleBrightnessStrategy().getBrightness(test_light));
|
||||
test_light.getState()["state"]["bri"] = 0;
|
||||
EXPECT_EQ(0, SimpleBrightnessStrategy().getBrightness(static_cast<const Light>(test_light)));
|
||||
}
|
||||
@@ -0,0 +1,486 @@
|
||||
/**
|
||||
\file test_SimpleColorHuewStrategy.cpp
|
||||
Copyright Notice\n
|
||||
Copyright (C) 2017 Jan Rogall - developer\n
|
||||
Copyright (C) 2017 Moritz Wirger - developer\n
|
||||
|
||||
This file is part of hueplusplus.
|
||||
|
||||
hueplusplus 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.
|
||||
|
||||
hueplusplus 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 hueplusplus. If not, see <http://www.gnu.org/licenses/>.
|
||||
**/
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include <gmock/gmock.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "TestTransaction.h"
|
||||
#include "testhelper.h"
|
||||
|
||||
#include "hueplusplus/SimpleColorHueStrategy.h"
|
||||
#include <nlohmann/json.hpp>
|
||||
#include "mocks/mock_HttpHandler.h"
|
||||
#include "mocks/mock_Light.h"
|
||||
|
||||
using namespace hueplusplus;
|
||||
|
||||
TEST(SimpleColorHueStrategy, setColorHue)
|
||||
{
|
||||
using namespace ::testing;
|
||||
std::shared_ptr<MockHttpHandler> handler(std::make_shared<MockHttpHandler>());
|
||||
EXPECT_CALL(
|
||||
*handler, GETJson("/api/" + getBridgeUsername() + "/lights/1", nlohmann::json::object(), getBridgeIp(), 80))
|
||||
.Times(AtLeast(1))
|
||||
.WillRepeatedly(Return(nlohmann::json::object()));
|
||||
MockLight test_light(handler);
|
||||
|
||||
const std::string statePath = "/api/" + getBridgeUsername() + "/lights/1/state";
|
||||
|
||||
nlohmann::json prep_ret;
|
||||
prep_ret = nlohmann::json::array();
|
||||
prep_ret[0] = nlohmann::json::object();
|
||||
prep_ret[0]["success"] = nlohmann::json::object();
|
||||
prep_ret[0]["success"]["/lights/1/state/transitiontime"] = 6;
|
||||
prep_ret[1] = nlohmann::json::object();
|
||||
prep_ret[1]["success"] = nlohmann::json::object();
|
||||
prep_ret[1]["success"]["/lights/1/state/on"] = true;
|
||||
prep_ret[2] = nlohmann::json::object();
|
||||
prep_ret[2]["success"] = nlohmann::json::object();
|
||||
prep_ret[2]["success"]["/lights/1/state/hue"] = 30500;
|
||||
EXPECT_CALL(*handler, PUTJson(statePath, _, getBridgeIp(), getBridgePort())).Times(1).WillOnce(Return(prep_ret));
|
||||
|
||||
test_light.getState()["state"]["on"] = true;
|
||||
test_light.getState()["state"]["hue"] = 200;
|
||||
test_light.getState()["state"]["colormode"] = "hs";
|
||||
EXPECT_EQ(true, SimpleColorHueStrategy().setColorHue(200, 4, test_light));
|
||||
|
||||
test_light.getState()["state"]["on"] = false;
|
||||
EXPECT_EQ(true, SimpleColorHueStrategy().setColorHue(30500, 6, test_light));
|
||||
}
|
||||
|
||||
TEST(SimpleColorHueStrategy, setColorSaturation)
|
||||
{
|
||||
using namespace ::testing;
|
||||
std::shared_ptr<MockHttpHandler> handler(std::make_shared<MockHttpHandler>());
|
||||
EXPECT_CALL(
|
||||
*handler, GETJson("/api/" + getBridgeUsername() + "/lights/1", nlohmann::json::object(), getBridgeIp(), 80))
|
||||
.Times(AtLeast(1))
|
||||
.WillRepeatedly(Return(nlohmann::json::object()));
|
||||
MockLight test_light(handler);
|
||||
|
||||
const std::string statePath = "/api/" + getBridgeUsername() + "/lights/1/state";
|
||||
|
||||
nlohmann::json prep_ret;
|
||||
prep_ret = nlohmann::json::array();
|
||||
prep_ret[0] = nlohmann::json::object();
|
||||
prep_ret[0]["success"] = nlohmann::json::object();
|
||||
prep_ret[0]["success"]["/lights/1/state/transitiontime"] = 6;
|
||||
prep_ret[1] = nlohmann::json::object();
|
||||
prep_ret[1]["success"] = nlohmann::json::object();
|
||||
prep_ret[1]["success"]["/lights/1/state/on"] = true;
|
||||
prep_ret[2] = nlohmann::json::object();
|
||||
prep_ret[2]["success"] = nlohmann::json::object();
|
||||
prep_ret[2]["success"]["/lights/1/state/sat"] = 254;
|
||||
EXPECT_CALL(*handler, PUTJson(statePath, _, getBridgeIp(), getBridgePort())).Times(1).WillOnce(Return(prep_ret));
|
||||
|
||||
test_light.getState()["state"]["on"] = true;
|
||||
test_light.getState()["state"]["sat"] = 100;
|
||||
test_light.getState()["state"]["colormode"] = "hs";
|
||||
EXPECT_EQ(true, SimpleColorHueStrategy().setColorSaturation(100, 4, test_light));
|
||||
|
||||
test_light.getState()["state"]["on"] = false;
|
||||
EXPECT_EQ(true, SimpleColorHueStrategy().setColorSaturation(255, 6, test_light));
|
||||
}
|
||||
|
||||
TEST(SimpleColorHueStrategy, setColorHueSaturation)
|
||||
{
|
||||
using namespace ::testing;
|
||||
std::shared_ptr<MockHttpHandler> handler(std::make_shared<MockHttpHandler>());
|
||||
EXPECT_CALL(
|
||||
*handler, GETJson("/api/" + getBridgeUsername() + "/lights/1", nlohmann::json::object(), getBridgeIp(), 80))
|
||||
.Times(AtLeast(1))
|
||||
.WillRepeatedly(Return(nlohmann::json::object()));
|
||||
MockLight test_light(handler);
|
||||
|
||||
const std::string statePath = "/api/" + getBridgeUsername() + "/lights/1/state";
|
||||
|
||||
nlohmann::json prep_ret;
|
||||
prep_ret = nlohmann::json::array();
|
||||
prep_ret[0] = nlohmann::json::object();
|
||||
prep_ret[0]["success"] = nlohmann::json::object();
|
||||
prep_ret[0]["success"]["/lights/1/state/transitiontime"] = 6;
|
||||
prep_ret[1] = nlohmann::json::object();
|
||||
prep_ret[1]["success"] = nlohmann::json::object();
|
||||
prep_ret[1]["success"]["/lights/1/state/on"] = true;
|
||||
prep_ret[2] = nlohmann::json::object();
|
||||
prep_ret[2]["success"] = nlohmann::json::object();
|
||||
prep_ret[2]["success"]["/lights/1/state/hue"] = 30500;
|
||||
prep_ret[3] = nlohmann::json::object();
|
||||
prep_ret[3]["success"] = nlohmann::json::object();
|
||||
prep_ret[3]["success"]["/lights/1/state/sat"] = 254;
|
||||
EXPECT_CALL(*handler, PUTJson(statePath, _, getBridgeIp(), getBridgePort())).Times(1).WillOnce(Return(prep_ret));
|
||||
|
||||
test_light.getState()["state"]["on"] = true;
|
||||
test_light.getState()["state"]["sat"] = 100;
|
||||
test_light.getState()["state"]["hue"] = 200;
|
||||
test_light.getState()["state"]["colormode"] = "hs";
|
||||
EXPECT_EQ(true, SimpleColorHueStrategy().setColorHueSaturation({200, 100}, 4, test_light));
|
||||
|
||||
test_light.getState()["state"]["on"] = false;
|
||||
EXPECT_EQ(true, SimpleColorHueStrategy().setColorHueSaturation({30500, 255}, 6, test_light));
|
||||
}
|
||||
|
||||
TEST(SimpleColorHueStrategy, setColorXY)
|
||||
{
|
||||
using namespace ::testing;
|
||||
std::shared_ptr<MockHttpHandler> handler(std::make_shared<MockHttpHandler>());
|
||||
EXPECT_CALL(
|
||||
*handler, GETJson("/api/" + getBridgeUsername() + "/lights/1", nlohmann::json::object(), getBridgeIp(), 80))
|
||||
.Times(AtLeast(1))
|
||||
.WillRepeatedly(Return(nlohmann::json::object()));
|
||||
MockLight test_light(handler);
|
||||
|
||||
const std::string statePath = "/api/" + getBridgeUsername() + "/lights/1/state";
|
||||
|
||||
nlohmann::json prep_ret
|
||||
= {{{"success", {{"/lights/1/state/transitiontime", 6}}}}, {{"success", {{"/lights/1/state/on", true}}}},
|
||||
{{"success", {{"/lights/1/state/xy", {0.2355, 0.1234}}}}}, {{"success", {{"/lights/1/state/bri", 254}}}}};
|
||||
EXPECT_CALL(*handler, PUTJson(statePath, _, getBridgeIp(), getBridgePort())).Times(1).WillOnce(Return(prep_ret));
|
||||
|
||||
test_light.getState()["state"]["on"] = true;
|
||||
test_light.getState()["state"]["xy"][0] = 0.1f;
|
||||
test_light.getState()["state"]["xy"][1] = 0.1f;
|
||||
test_light.getState()["state"]["bri"] = 254;
|
||||
test_light.getState()["state"]["colormode"] = "xy";
|
||||
EXPECT_EQ(true, SimpleColorHueStrategy().setColorXY({{0.1f, 0.1f}, 1.f}, 4, test_light));
|
||||
|
||||
test_light.getState()["state"]["on"] = false;
|
||||
test_light.getState()["state"]["bri"] = 0;
|
||||
EXPECT_EQ(true, SimpleColorHueStrategy().setColorXY({{0.2355f, 0.1234f}, 1.f}, 6, test_light));
|
||||
}
|
||||
|
||||
TEST(SimpleColorHueStrategy, setColorLoop)
|
||||
{
|
||||
using namespace ::testing;
|
||||
std::shared_ptr<MockHttpHandler> handler(std::make_shared<MockHttpHandler>());
|
||||
EXPECT_CALL(
|
||||
*handler, GETJson("/api/" + getBridgeUsername() + "/lights/1", nlohmann::json::object(), getBridgeIp(), 80))
|
||||
.Times(AtLeast(1))
|
||||
.WillRepeatedly(Return(nlohmann::json::object()));
|
||||
MockLight test_light(handler);
|
||||
|
||||
const std::string statePath = "/api/" + getBridgeUsername() + "/lights/1/state";
|
||||
|
||||
nlohmann::json prep_ret;
|
||||
prep_ret = nlohmann::json::array();
|
||||
prep_ret[0] = nlohmann::json::object();
|
||||
prep_ret[0]["success"] = nlohmann::json::object();
|
||||
prep_ret[0]["success"]["/lights/1/state/on"] = true;
|
||||
prep_ret[1] = nlohmann::json::object();
|
||||
prep_ret[1]["success"] = nlohmann::json::object();
|
||||
prep_ret[1]["success"]["/lights/1/state/effect"] = "colorloop";
|
||||
EXPECT_CALL(*handler, PUTJson(statePath, _, getBridgeIp(), getBridgePort())).Times(1).WillOnce(Return(prep_ret));
|
||||
|
||||
test_light.getState()["state"]["on"] = true;
|
||||
test_light.getState()["state"]["effect"] = "colorloop";
|
||||
EXPECT_EQ(true, SimpleColorHueStrategy().setColorLoop(true, test_light));
|
||||
|
||||
test_light.getState()["state"]["on"] = false;
|
||||
test_light.getState()["state"]["effect"] = "none";
|
||||
EXPECT_EQ(true, SimpleColorHueStrategy().setColorLoop(true, test_light));
|
||||
}
|
||||
|
||||
TEST(SimpleColorHueStrategy, alertHueSaturation)
|
||||
{
|
||||
using namespace ::testing;
|
||||
std::shared_ptr<MockHttpHandler> handler(std::make_shared<MockHttpHandler>());
|
||||
EXPECT_CALL(
|
||||
*handler, GETJson("/api/" + getBridgeUsername() + "/lights/1", nlohmann::json::object(), getBridgeIp(), 80))
|
||||
.Times(AtLeast(1))
|
||||
.WillRepeatedly(Return(nlohmann::json::object()));
|
||||
MockLight light(handler);
|
||||
|
||||
// Invalid colormode
|
||||
{
|
||||
light.getState()["state"]["colormode"] = "invalid";
|
||||
light.getState()["state"]["on"] = false;
|
||||
EXPECT_EQ(false, SimpleColorHueStrategy().alertHueSaturation({30000, 128}, light));
|
||||
}
|
||||
const HueSaturation hueSat {200, 100};
|
||||
// Needs to update the state so transactions are correctly trimmed
|
||||
const auto setColorLambda = [&](const HueSaturation& hueSat, int transition) {
|
||||
light.getState()["state"]["colormode"] = "hs";
|
||||
light.getState()["state"]["on"] = true;
|
||||
light.getState()["state"]["hue"] = hueSat.hue;
|
||||
light.getState()["state"]["sat"] = hueSat.saturation;
|
||||
return true;
|
||||
};
|
||||
// Colormode hs
|
||||
{
|
||||
const nlohmann::json state
|
||||
= {{"colormode", "hs"}, {"on", true}, {"xy", {0.1, 0.1}}, {"hue", 300}, {"sat", 100}, {"bri", 254}};
|
||||
light.getState()["state"] = state;
|
||||
EXPECT_CALL(Const(light), getBrightness()).Times(AnyNumber()).WillRepeatedly(Return(254));
|
||||
EXPECT_CALL(Const(light), getColorHueSaturation())
|
||||
.Times(AnyNumber())
|
||||
.WillRepeatedly(Return(HueSaturation {300, 100}));
|
||||
|
||||
TestTransaction reverseTransaction = light.transaction().setColorHue(300).setTransition(1);
|
||||
// Set color fails
|
||||
{
|
||||
EXPECT_CALL(light, setColorHueSaturation(hueSat, 1)).WillOnce(Return(false));
|
||||
EXPECT_FALSE(SimpleColorHueStrategy().alertHueSaturation(hueSat, light));
|
||||
}
|
||||
// Alert call fails
|
||||
{
|
||||
InSequence s;
|
||||
EXPECT_CALL(light, setColorHueSaturation(hueSat, 1)).WillOnce(Invoke(setColorLambda));
|
||||
EXPECT_CALL(light, alert()).WillOnce(Return(false));
|
||||
EXPECT_FALSE(SimpleColorHueStrategy().alertHueSaturation(hueSat, light));
|
||||
}
|
||||
light.getState()["state"] = state;
|
||||
// Reverse transaction fails
|
||||
{
|
||||
InSequence s;
|
||||
EXPECT_CALL(light, setColorHueSaturation(hueSat, 1)).WillOnce(Invoke(setColorLambda));
|
||||
EXPECT_CALL(light, alert()).WillOnce(Return(true));
|
||||
reverseTransaction.expectPut(handler).WillOnce(Return(nlohmann::json::object()));
|
||||
EXPECT_FALSE(SimpleColorHueStrategy().alertHueSaturation(hueSat, light));
|
||||
}
|
||||
light.getState()["state"] = state;
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
// Successful
|
||||
{
|
||||
InSequence s;
|
||||
EXPECT_CALL(light, setColorHueSaturation(hueSat, 1)).WillOnce(Invoke(setColorLambda));
|
||||
EXPECT_CALL(light, alert()).WillOnce(Return(true));
|
||||
reverseTransaction.expectSuccessfulPut(handler, Exactly(1));
|
||||
EXPECT_TRUE(SimpleColorHueStrategy().alertHueSaturation(hueSat, light));
|
||||
}
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
}
|
||||
|
||||
// Colormode hs, off
|
||||
{
|
||||
const nlohmann::json state
|
||||
= {{"colormode", "hs"}, {"on", false}, {"xy", {0.1, 0.1}}, {"hue", 300}, {"sat", 100}, {"bri", 254}};
|
||||
light.getState()["state"] = state;
|
||||
TestTransaction reverseTransaction = light.transaction().setColorHue(300).setOn(false).setTransition(1);
|
||||
InSequence s;
|
||||
EXPECT_CALL(light, setColorHueSaturation(hueSat, 1)).WillOnce(Invoke(setColorLambda));
|
||||
EXPECT_CALL(light, alert()).WillOnce(Return(true));
|
||||
reverseTransaction.expectSuccessfulPut(handler, Exactly(1));
|
||||
EXPECT_TRUE(SimpleColorHueStrategy().alertHueSaturation(hueSat, light));
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
}
|
||||
// Colormode xy
|
||||
{
|
||||
const nlohmann::json state
|
||||
= {{"colormode", "xy"}, {"on", true}, {"xy", {0.1, 0.1}}, {"sat", 100}, {"bri", 254}};
|
||||
light.getState()["state"] = state;
|
||||
EXPECT_CALL(Const(light), getColorXY())
|
||||
.Times(AnyNumber())
|
||||
.WillRepeatedly(Return(XYBrightness {{0.1f, 0.1f}, 1.f}));
|
||||
TestTransaction reverseTransaction = light.transaction().setColor(XY {0.1f, 0.1f}).setTransition(1);
|
||||
|
||||
InSequence s;
|
||||
EXPECT_CALL(light, setColorHueSaturation(hueSat, 1)).WillOnce(Invoke(setColorLambda));
|
||||
EXPECT_CALL(light, alert()).WillOnce(Return(false));
|
||||
EXPECT_FALSE(SimpleColorHueStrategy().alertHueSaturation(hueSat, light));
|
||||
light.getState()["state"] = state;
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
|
||||
EXPECT_CALL(light, setColorHueSaturation(hueSat, 1)).WillOnce(Invoke(setColorLambda));
|
||||
EXPECT_CALL(light, alert()).WillOnce(Return(true));
|
||||
reverseTransaction.expectSuccessfulPut(handler, Exactly(1));
|
||||
EXPECT_TRUE(SimpleColorHueStrategy().alertHueSaturation(hueSat, light));
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
}
|
||||
|
||||
// Colormode xy, off
|
||||
{
|
||||
const nlohmann::json state = {{"colormode", "xy"}, {"on", false}, {"xy", {0., 1.}}, {"sat", 100}, {"bri", 254}};
|
||||
EXPECT_CALL(Const(light), getColorXY())
|
||||
.Times(AnyNumber())
|
||||
.WillRepeatedly(Return(XYBrightness {{0.f, 1.f}, 1.f}));
|
||||
light.getState()["state"] = state;
|
||||
|
||||
TestTransaction reverseTransaction = light.transaction().setColor(XY {0.f, 1.f}).setOn(false).setTransition(1);
|
||||
InSequence s;
|
||||
EXPECT_CALL(light, setColorHueSaturation(hueSat, 1)).WillOnce(Invoke(setColorLambda));
|
||||
EXPECT_CALL(light, alert()).WillOnce(Return(true));
|
||||
reverseTransaction.expectSuccessfulPut(handler, Exactly(1));
|
||||
EXPECT_TRUE(SimpleColorHueStrategy().alertHueSaturation(hueSat, light));
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(SimpleColorHueStrategy, alertXY)
|
||||
{
|
||||
using namespace ::testing;
|
||||
std::shared_ptr<MockHttpHandler> handler(std::make_shared<MockHttpHandler>());
|
||||
EXPECT_CALL(
|
||||
*handler, GETJson("/api/" + getBridgeUsername() + "/lights/1", nlohmann::json::object(), getBridgeIp(), 80))
|
||||
.Times(AtLeast(1))
|
||||
.WillRepeatedly(Return(nlohmann::json::object()));
|
||||
MockLight light(handler);
|
||||
|
||||
// Invalid colormode
|
||||
{
|
||||
light.getState()["state"]["colormode"] = "invalid";
|
||||
light.getState()["state"]["on"] = false;
|
||||
EXPECT_EQ(false, SimpleColorHueStrategy().alertXY({{0.1f, 0.1f}, 1.f}, light));
|
||||
}
|
||||
const XYBrightness xy {{0.1f, 0.1f}, 1.f};
|
||||
// Needs to update the state so transactions are correctly trimmed
|
||||
const auto setColorLambda = [&](const XYBrightness& xy, int transition) {
|
||||
light.getState()["state"]["colormode"] = "xy";
|
||||
light.getState()["state"]["on"] = true;
|
||||
light.getState()["state"]["xy"] = {xy.xy.x, xy.xy.y};
|
||||
light.getState()["state"]["bri"] = static_cast<int>(std::round(xy.brightness * 254.f));
|
||||
return true;
|
||||
};
|
||||
// Colormode hs
|
||||
{
|
||||
const nlohmann::json state
|
||||
= {{"colormode", "hs"}, {"on", true}, {"xy", {0.1, 0.1}}, {"hue", 200}, {"sat", 100}, {"bri", 254}};
|
||||
light.getState()["state"] = state;
|
||||
EXPECT_CALL(Const(light), getBrightness()).Times(AnyNumber()).WillRepeatedly(Return(254));
|
||||
HueSaturation hueSat {200, 100};
|
||||
EXPECT_CALL(Const(light), getColorHueSaturation()).Times(AnyNumber()).WillRepeatedly(Return(hueSat));
|
||||
|
||||
TestTransaction reverseTransaction = light.transaction().setColor(hueSat).setTransition(1);
|
||||
// Set color fails
|
||||
{
|
||||
EXPECT_CALL(light, setColorXY(xy, 1)).WillOnce(Return(false));
|
||||
EXPECT_FALSE(SimpleColorHueStrategy().alertXY(xy, light));
|
||||
}
|
||||
// Alert call fails
|
||||
{
|
||||
InSequence s;
|
||||
EXPECT_CALL(light, setColorXY(xy, 1)).WillOnce(Invoke(setColorLambda));
|
||||
EXPECT_CALL(light, alert()).WillOnce(Return(false));
|
||||
EXPECT_FALSE(SimpleColorHueStrategy().alertXY(xy, light));
|
||||
}
|
||||
light.getState()["state"] = state;
|
||||
// Reverse transaction fails
|
||||
{
|
||||
InSequence s;
|
||||
EXPECT_CALL(light, setColorXY(xy, 1)).WillOnce(Invoke(setColorLambda));
|
||||
EXPECT_CALL(light, alert()).WillOnce(Return(true));
|
||||
reverseTransaction.expectPut(handler).WillOnce(Return(nlohmann::json::object()));
|
||||
EXPECT_FALSE(SimpleColorHueStrategy().alertXY(xy, light));
|
||||
}
|
||||
light.getState()["state"] = state;
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
// Successful
|
||||
{
|
||||
InSequence s;
|
||||
EXPECT_CALL(light, setColorXY(xy, 1)).WillOnce(Invoke(setColorLambda));
|
||||
EXPECT_CALL(light, alert()).WillOnce(Return(true));
|
||||
reverseTransaction.expectSuccessfulPut(handler, Exactly(1));
|
||||
EXPECT_TRUE(SimpleColorHueStrategy().alertXY(xy, light));
|
||||
}
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
}
|
||||
// Colormode hs, off
|
||||
{
|
||||
const nlohmann::json state
|
||||
= {{"colormode", "hs"}, {"on", false}, {"xy", {0.1, 0.1}}, {"hue", 200}, {"sat", 100}, {"bri", 254}};
|
||||
light.getState()["state"] = state;
|
||||
TestTransaction reverseTransaction
|
||||
= light.transaction().setColor(HueSaturation {200, 100}).setOn(false).setTransition(1);
|
||||
InSequence s;
|
||||
EXPECT_CALL(light, setColorXY(xy, 1)).WillOnce(Invoke(setColorLambda));
|
||||
EXPECT_CALL(light, alert()).WillOnce(Return(true));
|
||||
reverseTransaction.expectSuccessfulPut(handler, Exactly(1));
|
||||
EXPECT_TRUE(SimpleColorHueStrategy().alertXY(xy, light));
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
}
|
||||
// Colormode xy
|
||||
{
|
||||
const nlohmann::json state
|
||||
= {{"colormode", "xy"}, {"on", true}, {"xy", {0.1, 0.1}}, {"sat", 100}, {"bri", 254}};
|
||||
light.getState()["state"] = state;
|
||||
EXPECT_CALL(Const(light), getColorXY()).Times(AnyNumber()).WillRepeatedly(Return(xy));
|
||||
// No reverse transaction sent, because color already matches
|
||||
EXPECT_CALL(light, setColorXY(xy, 1)).WillOnce(Invoke(setColorLambda));
|
||||
EXPECT_CALL(light, alert()).WillOnce(Return(false));
|
||||
EXPECT_FALSE(SimpleColorHueStrategy().alertXY(xy, light));
|
||||
light.getState()["state"] = state;
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
|
||||
EXPECT_CALL(light, setColorXY(xy, 1)).WillOnce(Invoke(setColorLambda));
|
||||
EXPECT_CALL(light, alert()).WillOnce(Return(true));
|
||||
EXPECT_TRUE(SimpleColorHueStrategy().alertXY(xy, light));
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
}
|
||||
|
||||
// Colormode xy, off
|
||||
{
|
||||
const nlohmann::json state = {{"colormode", "xy"}, {"on", false}, {"xy", {0., 1.}}, {"sat", 100}, {"bri", 254}};
|
||||
EXPECT_CALL(Const(light), getColorXY())
|
||||
.Times(AnyNumber())
|
||||
.WillRepeatedly(Return(XYBrightness {{0.f, 1.f}, 1.f}));
|
||||
light.getState()["state"] = state;
|
||||
|
||||
// Brightness unchanged, so not requested
|
||||
TestTransaction reverseTransaction = light.transaction().setColor(XY {0.f, 1.f}).setOn(false).setTransition(1);
|
||||
InSequence s;
|
||||
EXPECT_CALL(light, setColorXY(xy, 1)).WillOnce(Invoke(setColorLambda));
|
||||
EXPECT_CALL(light, alert()).WillOnce(Return(true));
|
||||
reverseTransaction.expectSuccessfulPut(handler, Exactly(1));
|
||||
EXPECT_TRUE(SimpleColorHueStrategy().alertXY(xy, light));
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(SimpleColorHueStrategy, getColorHueSaturation)
|
||||
{
|
||||
using namespace ::testing;
|
||||
std::shared_ptr<MockHttpHandler> handler(std::make_shared<MockHttpHandler>());
|
||||
EXPECT_CALL(
|
||||
*handler, GETJson("/api/" + getBridgeUsername() + "/lights/1", nlohmann::json::object(), getBridgeIp(), 80))
|
||||
.Times(AtLeast(1))
|
||||
.WillRepeatedly(Return(nlohmann::json::object()));
|
||||
MockLight test_light(handler);
|
||||
|
||||
test_light.getState()["state"]["hue"] = 5000;
|
||||
test_light.getState()["state"]["sat"] = 128;
|
||||
EXPECT_EQ((HueSaturation {5000, 128}), SimpleColorHueStrategy().getColorHueSaturation(test_light));
|
||||
test_light.getState()["state"]["hue"] = 50000;
|
||||
test_light.getState()["state"]["sat"] = 158;
|
||||
EXPECT_EQ((HueSaturation {50000, 158}),
|
||||
SimpleColorHueStrategy().getColorHueSaturation(static_cast<const Light>(test_light)));
|
||||
}
|
||||
|
||||
TEST(SimpleColorHueStrategy, getColorXY)
|
||||
{
|
||||
using namespace ::testing;
|
||||
std::shared_ptr<MockHttpHandler> handler(std::make_shared<MockHttpHandler>());
|
||||
EXPECT_CALL(
|
||||
*handler, GETJson("/api/" + getBridgeUsername() + "/lights/1", nlohmann::json::object(), getBridgeIp(), 80))
|
||||
.Times(AtLeast(1))
|
||||
.WillRepeatedly(Return(nlohmann::json::object()));
|
||||
MockLight test_light(handler);
|
||||
|
||||
test_light.getState()["state"]["xy"][0] = 0.1234;
|
||||
test_light.getState()["state"]["xy"][1] = 0.1234;
|
||||
test_light.getState()["state"]["bri"] = 254;
|
||||
EXPECT_EQ((XYBrightness {{0.1234f, 0.1234f}, 1.f}), SimpleColorHueStrategy().getColorXY(test_light));
|
||||
test_light.getState()["state"]["xy"][0] = 0.12;
|
||||
test_light.getState()["state"]["xy"][1] = 0.6458;
|
||||
EXPECT_EQ((XYBrightness {{0.12f, 0.6458f}, 1.f}), SimpleColorHueStrategy().getColorXY(Const(test_light)));
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
/**
|
||||
\file test_SimpleColorTemperatureStrategy.cpp
|
||||
Copyright Notice\n
|
||||
Copyright (C) 2017 Jan Rogall - developer\n
|
||||
Copyright (C) 2017 Moritz Wirger - developer\n
|
||||
|
||||
This file is part of hueplusplus.
|
||||
|
||||
hueplusplus 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.
|
||||
|
||||
hueplusplus 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 hueplusplus. If not, see <http://www.gnu.org/licenses/>.
|
||||
**/
|
||||
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include <gmock/gmock.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "TestTransaction.h"
|
||||
#include "testhelper.h"
|
||||
|
||||
#include "hueplusplus/SimpleColorTemperatureStrategy.h"
|
||||
#include <nlohmann/json.hpp>
|
||||
#include "mocks/mock_HttpHandler.h"
|
||||
#include "mocks/mock_Light.h"
|
||||
|
||||
using namespace hueplusplus;
|
||||
|
||||
TEST(SimpleColorTemperatureStrategy, setColorTemperature)
|
||||
{
|
||||
using namespace ::testing;
|
||||
std::shared_ptr<MockHttpHandler> handler(std::make_shared<MockHttpHandler>());
|
||||
EXPECT_CALL(
|
||||
*handler, GETJson("/api/" + getBridgeUsername() + "/lights/1", nlohmann::json::object(), getBridgeIp(), 80))
|
||||
.Times(AtLeast(1))
|
||||
.WillRepeatedly(Return(nlohmann::json::object()));
|
||||
MockLight test_light(handler);
|
||||
|
||||
const std::string statePath = "/api/" + getBridgeUsername() + "/lights/1/state";
|
||||
|
||||
nlohmann::json prep_ret;
|
||||
prep_ret = nlohmann::json::array();
|
||||
prep_ret[0] = nlohmann::json::object();
|
||||
prep_ret[0]["success"] = nlohmann::json::object();
|
||||
prep_ret[0]["success"]["/lights/1/state/transitiontime"] = 6;
|
||||
prep_ret[1] = nlohmann::json::object();
|
||||
prep_ret[1]["success"] = nlohmann::json::object();
|
||||
prep_ret[1]["success"]["/lights/1/state/on"] = true;
|
||||
prep_ret[2] = nlohmann::json::object();
|
||||
prep_ret[2]["success"] = nlohmann::json::object();
|
||||
prep_ret[2]["success"]["/lights/1/state/ct"] = 155;
|
||||
EXPECT_CALL(*handler, PUTJson(statePath, _, getBridgeIp(), getBridgePort())).Times(1).WillOnce(Return(prep_ret));
|
||||
|
||||
test_light.getState()["state"]["on"] = true;
|
||||
test_light.getState()["state"]["ct"] = 200;
|
||||
test_light.getState()["state"]["colormode"] = "ct";
|
||||
EXPECT_EQ(true, SimpleColorTemperatureStrategy().setColorTemperature(200, 4, test_light));
|
||||
|
||||
test_light.getState()["state"]["on"] = false;
|
||||
EXPECT_EQ(true, SimpleColorTemperatureStrategy().setColorTemperature(155, 6, test_light));
|
||||
|
||||
prep_ret = {{{"success", {{"/lights/1/state/transitiontime", 6}}}}, {{"success", {{"/lights/1/state/ct", 153}}}}};
|
||||
EXPECT_CALL(*handler, PUTJson(statePath, _, getBridgeIp(), getBridgePort())).Times(1).WillOnce(Return(prep_ret));
|
||||
EXPECT_EQ(true, SimpleColorTemperatureStrategy().setColorTemperature(0, 6, test_light));
|
||||
|
||||
prep_ret[1]["success"]["/lights/1/state/ct"] = 500;
|
||||
EXPECT_CALL(*handler, PUTJson(statePath, _, getBridgeIp(), getBridgePort())).Times(1).WillOnce(Return(prep_ret));
|
||||
EXPECT_EQ(true, SimpleColorTemperatureStrategy().setColorTemperature(600, 6, test_light));
|
||||
}
|
||||
|
||||
TEST(SimpleColorTemperatureStrategy, alertTemperature)
|
||||
{
|
||||
using namespace ::testing;
|
||||
std::shared_ptr<MockHttpHandler> handler(std::make_shared<MockHttpHandler>());
|
||||
EXPECT_CALL(
|
||||
*handler, GETJson("/api/" + getBridgeUsername() + "/lights/1", nlohmann::json::object(), getBridgeIp(), 80))
|
||||
.Times(AtLeast(1))
|
||||
.WillRepeatedly(Return(nlohmann::json::object()));
|
||||
MockLight light(handler);
|
||||
|
||||
const auto setCTLambda = [&](unsigned int ct, int transition) {
|
||||
light.getState()["state"]["colormode"] = "ct";
|
||||
light.getState()["state"]["on"] = true;
|
||||
light.getState()["state"]["ct"] = ct;
|
||||
return true;
|
||||
};
|
||||
|
||||
// Invalid colormode
|
||||
{
|
||||
light.getState()["state"]["colormode"] = "invalid";
|
||||
light.getState()["state"]["on"] = false;
|
||||
EXPECT_EQ(false, SimpleColorTemperatureStrategy().alertTemperature(400, light));
|
||||
}
|
||||
// on
|
||||
{
|
||||
const nlohmann::json state = {{"colormode", "ct"}, {"on", true}, {"ct", 200}};
|
||||
light.getState()["state"] = state;
|
||||
TestTransaction reverseTransaction = light.transaction().setColorTemperature(200).setTransition(1);
|
||||
|
||||
EXPECT_CALL(light, setColorTemperature(400, 1)).WillOnce(Return(false));
|
||||
EXPECT_FALSE(SimpleColorTemperatureStrategy().alertTemperature(400, light));
|
||||
|
||||
InSequence s;
|
||||
EXPECT_CALL(light, setColorTemperature(400, 1)).WillOnce(Invoke(setCTLambda));
|
||||
EXPECT_CALL(light, alert()).WillOnce(Return(false));
|
||||
EXPECT_FALSE(SimpleColorTemperatureStrategy().alertTemperature(400, light));
|
||||
|
||||
light.getState()["state"] = state;
|
||||
EXPECT_CALL(light, setColorTemperature(400, 1)).WillOnce(Invoke(setCTLambda));
|
||||
EXPECT_CALL(light, alert()).WillOnce(Return(true));
|
||||
reverseTransaction.expectSuccessfulPut(handler, Exactly(1));
|
||||
EXPECT_TRUE(SimpleColorTemperatureStrategy().alertTemperature(400, light));
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
}
|
||||
// off
|
||||
{
|
||||
const nlohmann::json state = {{"colormode", "ct"}, {"on", false}, {"ct", 200}};
|
||||
light.getState()["state"] = state;
|
||||
TestTransaction reverseTransaction = light.transaction().setColorTemperature(200).setOn(false).setTransition(1);
|
||||
|
||||
EXPECT_CALL(light, setColorTemperature(400, 1)).WillOnce(Invoke(setCTLambda));
|
||||
EXPECT_CALL(light, alert()).WillOnce(Return(true));
|
||||
reverseTransaction.expectSuccessfulPut(handler, Exactly(1));
|
||||
EXPECT_TRUE(SimpleColorTemperatureStrategy().alertTemperature(400, light));
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(SimpleColorTemperatureStrategy, getColorTemperature)
|
||||
{
|
||||
using namespace ::testing;
|
||||
std::shared_ptr<MockHttpHandler> handler(std::make_shared<MockHttpHandler>());
|
||||
EXPECT_CALL(
|
||||
*handler, GETJson("/api/" + getBridgeUsername() + "/lights/1", nlohmann::json::object(), getBridgeIp(), 80))
|
||||
.Times(AtLeast(1))
|
||||
.WillRepeatedly(Return(nlohmann::json::object()));
|
||||
MockLight test_light(handler);
|
||||
|
||||
test_light.getState()["state"]["ct"] = 200;
|
||||
EXPECT_EQ(200, SimpleColorTemperatureStrategy().getColorTemperature(test_light));
|
||||
test_light.getState()["state"]["ct"] = 500;
|
||||
EXPECT_EQ(500, SimpleColorTemperatureStrategy().getColorTemperature(static_cast<const Light>(test_light)));
|
||||
}
|
||||
@@ -0,0 +1,637 @@
|
||||
/**
|
||||
\file test_StateTransaction.cpp
|
||||
Copyright Notice\n
|
||||
Copyright (C) 2020 Jan Rogall - developer\n
|
||||
Copyright (C) 2020 Moritz Wirger - developer\n
|
||||
|
||||
This file is part of hueplusplus.
|
||||
|
||||
hueplusplus 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.
|
||||
|
||||
hueplusplus 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 hueplusplus. If not, see <http://www.gnu.org/licenses/>.
|
||||
**/
|
||||
|
||||
#include <hueplusplus/StateTransaction.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "testhelper.h"
|
||||
|
||||
#include "mocks/mock_HttpHandler.h"
|
||||
|
||||
using namespace hueplusplus;
|
||||
using namespace testing;
|
||||
|
||||
TEST(StateTransaction, commit)
|
||||
{
|
||||
auto handler = std::make_shared<MockHttpHandler>();
|
||||
HueCommandAPI commands(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler);
|
||||
const std::string requestPath = "/api/" + getBridgeUsername() + "/path";
|
||||
{
|
||||
EXPECT_CALL(*handler, PUTJson(_, _, getBridgeIp(), getBridgePort())).Times(0);
|
||||
EXPECT_TRUE(StateTransaction(commands, "/path", nullptr).commit());
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
}
|
||||
// Explicit off overrides brightness
|
||||
{
|
||||
nlohmann::json request = {{"on", false}, {"bri", 100}};
|
||||
nlohmann::json response = {{{"success", {{"/path/on", false}}}}, {{"success", {{"/path/bri", 100}}}}};
|
||||
EXPECT_CALL(*handler, PUTJson(requestPath, request, getBridgeIp(), getBridgePort())).WillOnce(Return(response));
|
||||
EXPECT_TRUE(StateTransaction(commands, "/path", nullptr).setOn(false).setBrightness(100).commit());
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
}
|
||||
// Do not trim
|
||||
{
|
||||
const nlohmann::json request = {{"on", false}, {"bri", 100}};
|
||||
nlohmann::json state = {{"on", false}, {"bri", 100}};
|
||||
nlohmann::json response = {{{"success", {{"/path/on", false}}}}, {{"success", {{"/path/bri", 100}}}}};
|
||||
EXPECT_CALL(*handler, PUTJson(requestPath, request, getBridgeIp(), getBridgePort())).WillOnce(Return(response));
|
||||
EXPECT_TRUE(StateTransaction(commands, "/path", &state).setOn(false).setBrightness(100).commit(false));
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(StateTransaction, toAction)
|
||||
{
|
||||
auto handler = std::make_shared<MockHttpHandler>();
|
||||
HueCommandAPI commands(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler);
|
||||
const std::string requestPath = "/api/" + getBridgeUsername() + "/path";
|
||||
nlohmann::json request = {{"on", false}, {"bri", 100}};
|
||||
|
||||
hueplusplus::Action command
|
||||
= StateTransaction(commands, "/path", nullptr).setOn(false).setBrightness(100).toAction();
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
EXPECT_EQ(hueplusplus::Action::Method::put, command.getMethod());
|
||||
EXPECT_EQ(request, command.getBody());
|
||||
EXPECT_EQ(requestPath, command.getAddress());
|
||||
}
|
||||
|
||||
TEST(StateTransaction, setOn)
|
||||
{
|
||||
auto handler = std::make_shared<MockHttpHandler>();
|
||||
HueCommandAPI commands(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler);
|
||||
const std::string requestPath = "/api/" + getBridgeUsername() + "/path";
|
||||
// Set on
|
||||
{
|
||||
nlohmann::json request = {{"on", true}};
|
||||
nlohmann::json response = {{{"success", {{"/path/on", true}}}}};
|
||||
EXPECT_CALL(*handler, PUTJson(requestPath, request, getBridgeIp(), getBridgePort())).WillOnce(Return(response));
|
||||
EXPECT_TRUE(StateTransaction(commands, "/path", nullptr).setOn(true).commit());
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
}
|
||||
// Set off
|
||||
{
|
||||
nlohmann::json request = {{"on", false}};
|
||||
nlohmann::json response = {{{"success", {{"/path/on", false}}}}};
|
||||
EXPECT_CALL(*handler, PUTJson(requestPath, request, getBridgeIp(), getBridgePort())).WillOnce(Return(response));
|
||||
EXPECT_TRUE(StateTransaction(commands, "/path", nullptr).setOn(false).commit());
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
}
|
||||
// Fail
|
||||
{
|
||||
nlohmann::json request = {{"on", false}};
|
||||
nlohmann::json response = {{{"success", {{"/path/on", true}}}}};
|
||||
EXPECT_CALL(*handler, PUTJson(requestPath, request, getBridgeIp(), getBridgePort())).WillOnce(Return(response));
|
||||
EXPECT_FALSE(StateTransaction(commands, "/path", nullptr).setOn(false).commit());
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
}
|
||||
// No change requested
|
||||
{
|
||||
nlohmann::json state = {{"on", false}};
|
||||
EXPECT_CALL(*handler, PUTJson(_, _, getBridgeIp(), getBridgePort())).Times(0);
|
||||
EXPECT_TRUE(StateTransaction(commands, "/path", &state).setOn(false).commit());
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(StateTransaction, setBrightness)
|
||||
{
|
||||
auto handler = std::make_shared<MockHttpHandler>();
|
||||
HueCommandAPI commands(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler);
|
||||
const std::string requestPath = "/api/" + getBridgeUsername() + "/path";
|
||||
// No state
|
||||
{
|
||||
const int bri = 128;
|
||||
nlohmann::json request = {{"on", true}, {"bri", bri}};
|
||||
nlohmann::json response = {{{"success", {{"/path/on", true}}}}, {{"success", {{"/path/bri", bri}}}}};
|
||||
EXPECT_CALL(*handler, PUTJson(requestPath, request, getBridgeIp(), getBridgePort())).WillOnce(Return(response));
|
||||
EXPECT_TRUE(StateTransaction(commands, "/path", nullptr).setBrightness(bri).commit());
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
}
|
||||
// Clamp to 254
|
||||
{
|
||||
const int bri = 254;
|
||||
nlohmann::json request = {{"on", true}, {"bri", bri}};
|
||||
nlohmann::json response = {{{"success", {{"/path/on", true}}}}, {{"success", {{"/path/bri", bri}}}}};
|
||||
EXPECT_CALL(*handler, PUTJson(requestPath, request, getBridgeIp(), getBridgePort())).WillOnce(Return(response));
|
||||
EXPECT_TRUE(StateTransaction(commands, "/path", nullptr).setBrightness(255).commit());
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
}
|
||||
// Already off
|
||||
{
|
||||
const int bri = 0;
|
||||
nlohmann::json request = {{"bri", bri}};
|
||||
nlohmann::json response = {{{"success", {{"/path/bri", bri}}}}};
|
||||
nlohmann::json state = {{"on", false}};
|
||||
EXPECT_CALL(*handler, PUTJson(requestPath, request, getBridgeIp(), getBridgePort())).WillOnce(Return(response));
|
||||
EXPECT_TRUE(StateTransaction(commands, "/path", &state).setBrightness(bri).commit());
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
}
|
||||
// No change requested
|
||||
{
|
||||
const int bri = 120;
|
||||
nlohmann::json state = {{"on", true}, {"bri", bri}};
|
||||
EXPECT_CALL(*handler, PUTJson(_, _, getBridgeIp(), getBridgePort())).Times(0);
|
||||
EXPECT_TRUE(StateTransaction(commands, "/path", &state).setBrightness(bri).commit());
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
}
|
||||
// Fixed unexpected on/off flickering
|
||||
{
|
||||
const int hue = 32;
|
||||
nlohmann::json state = {{"on", false}, {"bri", 20}};
|
||||
nlohmann::json request = { {"hue", hue}, {"bri", 0} };
|
||||
nlohmann::json response = {{{"success", {{"/path/hue", hue}}}}};
|
||||
EXPECT_CALL(*handler, PUTJson(requestPath, request, getBridgeIp(), getBridgePort())).WillOnce(Return(response));
|
||||
EXPECT_TRUE(StateTransaction(commands, "/path", &state).setBrightness(0).setColorHue(hue).commit());
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(StateTransaction, setColorHue)
|
||||
{
|
||||
auto handler = std::make_shared<MockHttpHandler>();
|
||||
HueCommandAPI commands(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler);
|
||||
const std::string requestPath = "/api/" + getBridgeUsername() + "/path";
|
||||
// No state
|
||||
{
|
||||
const int hue = 2159;
|
||||
nlohmann::json request = {{"on", true}, {"hue", hue}};
|
||||
nlohmann::json response = {{{"success", {{"/path/on", true}}}}, {{"success", {{"/path/hue", hue}}}}};
|
||||
EXPECT_CALL(*handler, PUTJson(requestPath, request, getBridgeIp(), getBridgePort())).WillOnce(Return(response));
|
||||
EXPECT_TRUE(StateTransaction(commands, "/path", nullptr).setColorHue(hue).commit());
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
}
|
||||
// Already on
|
||||
{
|
||||
const int hue = 2159;
|
||||
nlohmann::json request = {{"hue", hue}};
|
||||
nlohmann::json response = {{{"success", {{"/path/hue", hue}}}}};
|
||||
nlohmann::json state = {{"on", true}};
|
||||
EXPECT_CALL(*handler, PUTJson(requestPath, request, getBridgeIp(), getBridgePort())).WillOnce(Return(response));
|
||||
EXPECT_TRUE(StateTransaction(commands, "/path", &state).setColorHue(hue).commit());
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
}
|
||||
// Wrong colormode
|
||||
{
|
||||
const int hue = 2159;
|
||||
nlohmann::json request = {{"hue", hue}};
|
||||
nlohmann::json response = {{{"success", {{"/path/hue", hue}}}}};
|
||||
nlohmann::json state = {{"on", true}, {"hue", hue}, {"colormode", "ct"}};
|
||||
EXPECT_CALL(*handler, PUTJson(requestPath, request, getBridgeIp(), getBridgePort())).WillOnce(Return(response));
|
||||
EXPECT_TRUE(StateTransaction(commands, "/path", &state).setColorHue(hue).commit());
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
}
|
||||
// No request
|
||||
{
|
||||
const int hue = 2159;
|
||||
nlohmann::json state = {{"on", true}, {"hue", hue}, {"colormode", "hs"}};
|
||||
EXPECT_CALL(*handler, PUTJson(_, _, getBridgeIp(), getBridgePort())).Times(0);
|
||||
EXPECT_TRUE(StateTransaction(commands, "/path", &state).setColorHue(hue).commit());
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(StateTransaction, setColorSaturation)
|
||||
{
|
||||
auto handler = std::make_shared<MockHttpHandler>();
|
||||
HueCommandAPI commands(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler);
|
||||
const std::string requestPath = "/api/" + getBridgeUsername() + "/path";
|
||||
// No state
|
||||
{
|
||||
const int sat = 125;
|
||||
nlohmann::json request = {{"on", true}, {"sat", sat}};
|
||||
nlohmann::json response = {{{"success", {{"/path/on", true}}}}, {{"success", {{"/path/sat", sat}}}}};
|
||||
EXPECT_CALL(*handler, PUTJson(requestPath, request, getBridgeIp(), getBridgePort())).WillOnce(Return(response));
|
||||
EXPECT_TRUE(StateTransaction(commands, "/path", nullptr).setColorSaturation(sat).commit());
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
}
|
||||
// Clamp to 254
|
||||
{
|
||||
const int sat = 254;
|
||||
nlohmann::json request = {{"on", true}, {"sat", sat}};
|
||||
nlohmann::json response = {{{"success", {{"/path/on", true}}}}, {{"success", {{"/path/sat", sat}}}}};
|
||||
EXPECT_CALL(*handler, PUTJson(requestPath, request, getBridgeIp(), getBridgePort())).WillOnce(Return(response));
|
||||
EXPECT_TRUE(StateTransaction(commands, "/path", nullptr).setColorSaturation(255).commit());
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
}
|
||||
// Already on
|
||||
{
|
||||
const int sat = 125;
|
||||
nlohmann::json request = {{"sat", sat}};
|
||||
nlohmann::json response = {{{"success", {{"/path/sat", sat}}}}};
|
||||
nlohmann::json state = {{"on", true}};
|
||||
EXPECT_CALL(*handler, PUTJson(requestPath, request, getBridgeIp(), getBridgePort())).WillOnce(Return(response));
|
||||
EXPECT_TRUE(StateTransaction(commands, "/path", &state).setColorSaturation(sat).commit());
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
}
|
||||
// Wrong colormode
|
||||
{
|
||||
const int sat = 125;
|
||||
nlohmann::json request = {{"sat", sat}};
|
||||
nlohmann::json response = {{{"success", {{"/path/sat", sat}}}}};
|
||||
nlohmann::json state = {{"on", true}, {"sat", sat}, {"colormode", "ct"}};
|
||||
EXPECT_CALL(*handler, PUTJson(requestPath, request, getBridgeIp(), getBridgePort())).WillOnce(Return(response));
|
||||
EXPECT_TRUE(StateTransaction(commands, "/path", &state).setColorSaturation(sat).commit());
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
}
|
||||
// No request
|
||||
{
|
||||
const int sat = 125;
|
||||
nlohmann::json state = {{"on", true}, {"sat", sat}, {"colormode", "hs"}};
|
||||
EXPECT_CALL(*handler, PUTJson(_, _, getBridgeIp(), getBridgePort())).Times(0);
|
||||
EXPECT_TRUE(StateTransaction(commands, "/path", &state).setColorSaturation(sat).commit());
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(StateTransaction, setColorXY)
|
||||
{
|
||||
auto handler = std::make_shared<MockHttpHandler>();
|
||||
HueCommandAPI commands(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler);
|
||||
const std::string requestPath = "/api/" + getBridgeUsername() + "/path";
|
||||
// No state
|
||||
{
|
||||
const float x = 0.5f;
|
||||
const float y = 0.8f;
|
||||
nlohmann::json request = {{"on", true}, {"xy", {x, y}}};
|
||||
nlohmann::json response = {{{"success", {{"/path/on", true}}}}, {{"success", {{"/path/xy", {x, y}}}}}};
|
||||
EXPECT_CALL(*handler, PUTJson(requestPath, request, getBridgeIp(), getBridgePort())).WillOnce(Return(response));
|
||||
EXPECT_TRUE(StateTransaction(commands, "/path", nullptr).setColor(XY {x, y}).commit());
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
}
|
||||
// Clamp
|
||||
{
|
||||
const float x = 1.f;
|
||||
const float y = 0.f;
|
||||
nlohmann::json request = {{"on", true}, {"xy", {x, y}}};
|
||||
nlohmann::json response = {{{"success", {{"/path/on", true}}}}, {{"success", {{"/path/xy", {x, y}}}}}};
|
||||
EXPECT_CALL(*handler, PUTJson(requestPath, request, getBridgeIp(), getBridgePort())).WillOnce(Return(response));
|
||||
EXPECT_TRUE(StateTransaction(commands, "/path", nullptr).setColor(XY {2.f, -1.f}).commit());
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
}
|
||||
// Already on
|
||||
{
|
||||
const float x = 0.5f;
|
||||
const float y = 0.8f;
|
||||
nlohmann::json request = {{"xy", {x, y}}};
|
||||
nlohmann::json response = {{{"success", {{"/path/xy", {x, y}}}}}};
|
||||
nlohmann::json state = {{"on", true}};
|
||||
EXPECT_CALL(*handler, PUTJson(requestPath, request, getBridgeIp(), getBridgePort())).WillOnce(Return(response));
|
||||
EXPECT_TRUE(StateTransaction(commands, "/path", &state).setColor(XY {x, y}).commit());
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
}
|
||||
// Wrong colormode
|
||||
{
|
||||
const float x = 0.5f;
|
||||
const float y = 0.8f;
|
||||
nlohmann::json request = {{"xy", {x, y}}};
|
||||
nlohmann::json response = {{{"success", {{"/path/xy", {x, y}}}}}};
|
||||
nlohmann::json state = {{"on", true},
|
||||
{"xy",
|
||||
{
|
||||
x,
|
||||
y,
|
||||
}},
|
||||
{"colormode", "hs"}};
|
||||
EXPECT_CALL(*handler, PUTJson(requestPath, request, getBridgeIp(), getBridgePort())).WillOnce(Return(response));
|
||||
EXPECT_TRUE(StateTransaction(commands, "/path", &state).setColor(XY {x, y}).commit());
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
}
|
||||
// No request
|
||||
{
|
||||
const float x = 0.5f;
|
||||
const float y = 0.8f;
|
||||
nlohmann::json state = {{"on", true},
|
||||
{"xy",
|
||||
{
|
||||
x,
|
||||
y,
|
||||
}},
|
||||
{"colormode", "xy"}};
|
||||
EXPECT_CALL(*handler, PUTJson(_, _, getBridgeIp(), getBridgePort())).Times(0);
|
||||
EXPECT_TRUE(StateTransaction(commands, "/path", &state).setColor(XY {x, y}).commit());
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(StateTransaction, setColorTemperature)
|
||||
{
|
||||
auto handler = std::make_shared<MockHttpHandler>();
|
||||
HueCommandAPI commands(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler);
|
||||
const std::string requestPath = "/api/" + getBridgeUsername() + "/path";
|
||||
// No state
|
||||
{
|
||||
const int ct = 240;
|
||||
nlohmann::json request = {{"on", true}, {"ct", ct}};
|
||||
nlohmann::json response = {{{"success", {{"/path/on", true}}}}, {{"success", {{"/path/ct", ct}}}}};
|
||||
EXPECT_CALL(*handler, PUTJson(requestPath, request, getBridgeIp(), getBridgePort())).WillOnce(Return(response));
|
||||
EXPECT_TRUE(StateTransaction(commands, "/path", nullptr).setColorTemperature(ct).commit());
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
}
|
||||
// Clamp
|
||||
{
|
||||
const int ct = 500;
|
||||
nlohmann::json request = {{"ct", ct}};
|
||||
nlohmann::json response = {{{"success", {{"/path/ct", ct}}}}};
|
||||
nlohmann::json state = {{"on", true}};
|
||||
EXPECT_CALL(*handler, PUTJson(requestPath, request, getBridgeIp(), getBridgePort())).WillOnce(Return(response));
|
||||
EXPECT_TRUE(StateTransaction(commands, "/path", &state).setColorTemperature(520).commit());
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
}
|
||||
// Already on
|
||||
{
|
||||
const int ct = 240;
|
||||
nlohmann::json request = {{"ct", ct}};
|
||||
nlohmann::json response = {{{"success", {{"/path/ct", ct}}}}};
|
||||
nlohmann::json state = {{"on", true}};
|
||||
EXPECT_CALL(*handler, PUTJson(requestPath, request, getBridgeIp(), getBridgePort())).WillOnce(Return(response));
|
||||
EXPECT_TRUE(StateTransaction(commands, "/path", &state).setColorTemperature(ct).commit());
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
}
|
||||
// Wrong colormode
|
||||
{
|
||||
const int ct = 240;
|
||||
nlohmann::json request = {{"ct", ct}};
|
||||
nlohmann::json response = {{{"success", {{"/path/ct", ct}}}}};
|
||||
nlohmann::json state = {{"on", true}, {"ct", ct}, {"colormode", "hs"}};
|
||||
EXPECT_CALL(*handler, PUTJson(requestPath, request, getBridgeIp(), getBridgePort())).WillOnce(Return(response));
|
||||
EXPECT_TRUE(StateTransaction(commands, "/path", &state).setColorTemperature(ct).commit());
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
}
|
||||
// No request
|
||||
{
|
||||
const int ct = 240;
|
||||
nlohmann::json state = {{"on", true}, {"ct", ct}, {"colormode", "ct"}};
|
||||
EXPECT_CALL(*handler, PUTJson(_, _, getBridgeIp(), getBridgePort())).Times(0);
|
||||
EXPECT_TRUE(StateTransaction(commands, "/path", &state).setColorTemperature(ct).commit());
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(StateTransaction, setColorLoop)
|
||||
{
|
||||
auto handler = std::make_shared<MockHttpHandler>();
|
||||
HueCommandAPI commands(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler);
|
||||
const std::string requestPath = "/api/" + getBridgeUsername() + "/path";
|
||||
// Set on
|
||||
{
|
||||
nlohmann::json request = {{"on", true}, {"effect", "colorloop"}};
|
||||
nlohmann::json response = {{{"success", {{"/path/on", true}}}}, {{"success", {{"/path/effect", "colorloop"}}}}};
|
||||
EXPECT_CALL(*handler, PUTJson(requestPath, request, getBridgeIp(), getBridgePort())).WillOnce(Return(response));
|
||||
EXPECT_TRUE(StateTransaction(commands, "/path", nullptr).setColorLoop(true).commit());
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
}
|
||||
// Set off
|
||||
{
|
||||
nlohmann::json request = {{"on", true}, {"effect", "none"}};
|
||||
nlohmann::json response = {{{"success", {{"/path/on", true}}}}, {{"success", {{"/path/effect", "none"}}}}};
|
||||
EXPECT_CALL(*handler, PUTJson(requestPath, request, getBridgeIp(), getBridgePort())).WillOnce(Return(response));
|
||||
EXPECT_TRUE(StateTransaction(commands, "/path", nullptr).setColorLoop(false).commit());
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
}
|
||||
// No request
|
||||
{
|
||||
nlohmann::json state = {{"on", true}, {"effect", "colorloop"}};
|
||||
EXPECT_CALL(*handler, PUTJson(_, _, getBridgeIp(), getBridgePort())).Times(0);
|
||||
EXPECT_TRUE(StateTransaction(commands, "/path", &state).setColorLoop(true).commit());
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(StateTransaction, incrementBrightness)
|
||||
{
|
||||
auto handler = std::make_shared<MockHttpHandler>();
|
||||
HueCommandAPI commands(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler);
|
||||
const std::string requestPath = "/api/" + getBridgeUsername() + "/path";
|
||||
{
|
||||
const int inc = 20;
|
||||
nlohmann::json request = {{"bri_inc", inc}};
|
||||
nlohmann::json response = {{{"success", {{"/path/bri_inc", inc}}}}};
|
||||
EXPECT_CALL(*handler, PUTJson(requestPath, request, getBridgeIp(), getBridgePort())).WillOnce(Return(response));
|
||||
EXPECT_TRUE(StateTransaction(commands, "/path", nullptr).incrementBrightness(inc).commit());
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
}
|
||||
// Clamp
|
||||
{
|
||||
const int inc = -254;
|
||||
nlohmann::json request = {{"bri_inc", inc}};
|
||||
nlohmann::json response = {{{"success", {{"/path/bri_inc", inc}}}}};
|
||||
EXPECT_CALL(*handler, PUTJson(requestPath, request, getBridgeIp(), getBridgePort())).WillOnce(Return(response));
|
||||
EXPECT_TRUE(StateTransaction(commands, "/path", nullptr).incrementBrightness(-300).commit());
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(StateTransaction, incrementSaturation)
|
||||
{
|
||||
auto handler = std::make_shared<MockHttpHandler>();
|
||||
HueCommandAPI commands(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler);
|
||||
const std::string requestPath = "/api/" + getBridgeUsername() + "/path";
|
||||
{
|
||||
const int inc = 20;
|
||||
nlohmann::json request = {{"sat_inc", inc}};
|
||||
nlohmann::json response = {{{"success", {{"/path/sat_inc", inc}}}}};
|
||||
EXPECT_CALL(*handler, PUTJson(requestPath, request, getBridgeIp(), getBridgePort())).WillOnce(Return(response));
|
||||
EXPECT_TRUE(StateTransaction(commands, "/path", nullptr).incrementSaturation(inc).commit());
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
}
|
||||
// Clamp
|
||||
{
|
||||
const int inc = -254;
|
||||
nlohmann::json request = {{"sat_inc", inc}};
|
||||
nlohmann::json response = {{{"success", {{"/path/sat_inc", inc}}}}};
|
||||
EXPECT_CALL(*handler, PUTJson(requestPath, request, getBridgeIp(), getBridgePort())).WillOnce(Return(response));
|
||||
EXPECT_TRUE(StateTransaction(commands, "/path", nullptr).incrementSaturation(-300).commit());
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(StateTransaction, incrementHue)
|
||||
{
|
||||
auto handler = std::make_shared<MockHttpHandler>();
|
||||
HueCommandAPI commands(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler);
|
||||
const std::string requestPath = "/api/" + getBridgeUsername() + "/path";
|
||||
{
|
||||
const int inc = 20;
|
||||
nlohmann::json request = {{"hue_inc", inc}};
|
||||
nlohmann::json response = {{{"success", {{"/path/hue_inc", inc}}}}};
|
||||
EXPECT_CALL(*handler, PUTJson(requestPath, request, getBridgeIp(), getBridgePort())).WillOnce(Return(response));
|
||||
EXPECT_TRUE(StateTransaction(commands, "/path", nullptr).incrementHue(inc).commit());
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
}
|
||||
// Clamp
|
||||
{
|
||||
const int inc = -65534;
|
||||
nlohmann::json request = {{"hue_inc", inc}};
|
||||
nlohmann::json response = {{{"success", {{"/path/hue_inc", inc}}}}};
|
||||
EXPECT_CALL(*handler, PUTJson(requestPath, request, getBridgeIp(), getBridgePort())).WillOnce(Return(response));
|
||||
EXPECT_TRUE(StateTransaction(commands, "/path", nullptr).incrementHue(-300000).commit());
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(StateTransaction, incrementColorTemperature)
|
||||
{
|
||||
auto handler = std::make_shared<MockHttpHandler>();
|
||||
HueCommandAPI commands(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler);
|
||||
const std::string requestPath = "/api/" + getBridgeUsername() + "/path";
|
||||
{
|
||||
const int inc = 20;
|
||||
nlohmann::json request = {{"ct_inc", inc}};
|
||||
nlohmann::json response = {{{"success", {{"/path/ct_inc", inc}}}}};
|
||||
EXPECT_CALL(*handler, PUTJson(requestPath, request, getBridgeIp(), getBridgePort())).WillOnce(Return(response));
|
||||
EXPECT_TRUE(StateTransaction(commands, "/path", nullptr).incrementColorTemperature(inc).commit());
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
}
|
||||
// Clamp
|
||||
{
|
||||
const int inc = -65534;
|
||||
nlohmann::json request = {{"ct_inc", inc}};
|
||||
nlohmann::json response = {{{"success", {{"/path/ct_inc", inc}}}}};
|
||||
EXPECT_CALL(*handler, PUTJson(requestPath, request, getBridgeIp(), getBridgePort())).WillOnce(Return(response));
|
||||
EXPECT_TRUE(StateTransaction(commands, "/path", nullptr).incrementColorTemperature(-300000).commit());
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(StateTransaction, incrementColorXY)
|
||||
{
|
||||
auto handler = std::make_shared<MockHttpHandler>();
|
||||
HueCommandAPI commands(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler);
|
||||
const std::string requestPath = "/api/" + getBridgeUsername() + "/path";
|
||||
{
|
||||
const float incX = 0.2f;
|
||||
const float incY = -0.4f;
|
||||
nlohmann::json request = {{"xy_inc", {incX, incY}}};
|
||||
nlohmann::json response = {{{"success", {{"/path/xy_inc", {incX, incY}}}}}};
|
||||
EXPECT_CALL(*handler, PUTJson(requestPath, request, getBridgeIp(), getBridgePort())).WillOnce(Return(response));
|
||||
EXPECT_TRUE(StateTransaction(commands, "/path", nullptr).incrementColorXY(incX, incY).commit());
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
}
|
||||
// Clamp
|
||||
{
|
||||
const float incX = 0.5f;
|
||||
const float incY = -0.5f;
|
||||
nlohmann::json request = {{"xy_inc", {incX, incY}}};
|
||||
nlohmann::json response = {{{"success", {{"/path/xy_inc", {incX, incY}}}}}};
|
||||
EXPECT_CALL(*handler, PUTJson(requestPath, request, getBridgeIp(), getBridgePort())).WillOnce(Return(response));
|
||||
EXPECT_TRUE(StateTransaction(commands, "/path", nullptr).incrementColorXY(1.f, -1.f).commit());
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(StateTransaction, setTransition)
|
||||
{
|
||||
auto handler = std::make_shared<MockHttpHandler>();
|
||||
HueCommandAPI commands(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler);
|
||||
const std::string requestPath = "/api/" + getBridgeUsername() + "/path";
|
||||
{
|
||||
nlohmann::json request = {{"on", true}, {"transitiontime", 2}};
|
||||
nlohmann::json response = {{{"success", {{"/path/on", true}}}}, {{"success", {{"/path/transitiontime", 2}}}}};
|
||||
EXPECT_CALL(*handler, PUTJson(requestPath, request, getBridgeIp(), getBridgePort())).WillOnce(Return(response));
|
||||
EXPECT_TRUE(StateTransaction(commands, "/path", nullptr).setOn(true).setTransition(2).commit());
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
}
|
||||
// No transition time 4
|
||||
{
|
||||
nlohmann::json request = {{"on", true}};
|
||||
nlohmann::json response = {{{"success", {{"/path/on", true}}}}};
|
||||
EXPECT_CALL(*handler, PUTJson(requestPath, request, getBridgeIp(), getBridgePort())).WillOnce(Return(response));
|
||||
EXPECT_TRUE(StateTransaction(commands, "/path", nullptr).setOn(true).setTransition(4).commit());
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
}
|
||||
// No request with only transition
|
||||
{
|
||||
EXPECT_CALL(*handler, PUTJson(_, _, getBridgeIp(), getBridgePort())).Times(0);
|
||||
EXPECT_TRUE(StateTransaction(commands, "/path", nullptr).setTransition(2).commit());
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(StateTransaction, alert)
|
||||
{
|
||||
auto handler = std::make_shared<MockHttpHandler>();
|
||||
HueCommandAPI commands(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler);
|
||||
const std::string requestPath = "/api/" + getBridgeUsername() + "/path";
|
||||
{
|
||||
nlohmann::json request = {{"alert", "select"}};
|
||||
nlohmann::json response = {{{"success", {{"/path/alert", "select"}}}}};
|
||||
EXPECT_CALL(*handler, PUTJson(requestPath, request, getBridgeIp(), getBridgePort())).WillOnce(Return(response));
|
||||
EXPECT_TRUE(StateTransaction(commands, "/path", nullptr).alert().commit());
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
}
|
||||
// Also alert when in state
|
||||
{
|
||||
nlohmann::json request = {{"alert", "select"}};
|
||||
nlohmann::json response = {{{"success", {{"/path/alert", "select"}}}}};
|
||||
nlohmann::json state = {{"alert", "select"}};
|
||||
EXPECT_CALL(*handler, PUTJson(requestPath, request, getBridgeIp(), getBridgePort())).WillOnce(Return(response));
|
||||
EXPECT_TRUE(StateTransaction(commands, "/path", &state).alert().commit());
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(StateTransaction, longAlert)
|
||||
{
|
||||
auto handler = std::make_shared<MockHttpHandler>();
|
||||
HueCommandAPI commands(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler);
|
||||
const std::string requestPath = "/api/" + getBridgeUsername() + "/path";
|
||||
{
|
||||
nlohmann::json request = {{"alert", "lselect"}};
|
||||
nlohmann::json response = {{{"success", {{"/path/alert", "lselect"}}}}};
|
||||
EXPECT_CALL(*handler, PUTJson(requestPath, request, getBridgeIp(), getBridgePort())).WillOnce(Return(response));
|
||||
EXPECT_TRUE(StateTransaction(commands, "/path", nullptr).longAlert().commit());
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
}
|
||||
// Also alert when in state
|
||||
{
|
||||
nlohmann::json request = {{"alert", "lselect"}};
|
||||
nlohmann::json response = {{{"success", {{"/path/alert", "lselect"}}}}};
|
||||
nlohmann::json state = {{"alert", "lselect"}};
|
||||
EXPECT_CALL(*handler, PUTJson(requestPath, request, getBridgeIp(), getBridgePort())).WillOnce(Return(response));
|
||||
EXPECT_TRUE(StateTransaction(commands, "/path", &state).longAlert().commit());
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(StateTransaction, stopAlert)
|
||||
{
|
||||
auto handler = std::make_shared<MockHttpHandler>();
|
||||
HueCommandAPI commands(getBridgeIp(), getBridgePort(), getBridgeUsername(), handler);
|
||||
const std::string requestPath = "/api/" + getBridgeUsername() + "/path";
|
||||
{
|
||||
nlohmann::json request = {{"alert", "none"}};
|
||||
nlohmann::json response = {{{"success", {{"/path/alert", "none"}}}}};
|
||||
EXPECT_CALL(*handler, PUTJson(requestPath, request, getBridgeIp(), getBridgePort())).WillOnce(Return(response));
|
||||
EXPECT_TRUE(StateTransaction(commands, "/path", nullptr).stopAlert().commit());
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
}
|
||||
// Also alert when in state
|
||||
{
|
||||
nlohmann::json request = {{"alert", "none"}};
|
||||
nlohmann::json response = {{{"success", {{"/path/alert", "none"}}}}};
|
||||
nlohmann::json state = {{"alert", "none"}};
|
||||
EXPECT_CALL(*handler, PUTJson(requestPath, request, getBridgeIp(), getBridgePort())).WillOnce(Return(response));
|
||||
EXPECT_TRUE(StateTransaction(commands, "/path", &state).stopAlert().commit());
|
||||
Mock::VerifyAndClearExpectations(handler.get());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,543 @@
|
||||
/**
|
||||
\file test_TimePattern.cpp
|
||||
Copyright Notice\n
|
||||
Copyright (C) 2020 Jan Rogall - developer\n
|
||||
|
||||
This file is part of hueplusplus.
|
||||
|
||||
hueplusplus 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.
|
||||
|
||||
hueplusplus 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 hueplusplus. If not, see <http://www.gnu.org/licenses/>.
|
||||
**/
|
||||
|
||||
#include <hueplusplus/HueException.h>
|
||||
#include <hueplusplus/TimePattern.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
using namespace hueplusplus::time;
|
||||
using std::chrono::system_clock;
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
TEST(Time, parseTimestamp)
|
||||
{
|
||||
std::tm tm {};
|
||||
tm.tm_year = 2020 - 1900;
|
||||
tm.tm_mon = 3 - 1;
|
||||
tm.tm_mday = 24;
|
||||
tm.tm_hour = 12;
|
||||
tm.tm_min = 45;
|
||||
tm.tm_sec = 0;
|
||||
// Auto detect daylight savings time
|
||||
tm.tm_isdst = -1;
|
||||
const std::time_t ctime = std::mktime(&tm);
|
||||
const auto timePoint = system_clock::from_time_t(ctime);
|
||||
EXPECT_EQ(timePoint, parseTimestamp("2020-03-24T12:45:00"));
|
||||
}
|
||||
|
||||
TEST(Time, timepointToTimestamp)
|
||||
{
|
||||
std::tm tm {};
|
||||
tm.tm_year = 2020 - 1900;
|
||||
tm.tm_mon = 3 - 1;
|
||||
tm.tm_mday = 24;
|
||||
tm.tm_hour = 12;
|
||||
tm.tm_min = 45;
|
||||
tm.tm_sec = 0;
|
||||
// Auto detect daylight savings time
|
||||
tm.tm_isdst = -1;
|
||||
const std::time_t ctime = std::mktime(&tm);
|
||||
const auto timePoint = system_clock::from_time_t(ctime);
|
||||
EXPECT_EQ("2020-03-24T12:45:00", timepointToTimestamp(timePoint));
|
||||
|
||||
EXPECT_EQ(timePoint, parseTimestamp(timepointToTimestamp(timePoint)));
|
||||
}
|
||||
|
||||
TEST(Time, parseDuration)
|
||||
{
|
||||
EXPECT_EQ(1h + 24min + 1s, parseDuration("01:24:01"));
|
||||
EXPECT_EQ(22h + 59min + 49s, parseDuration("22:59:49"));
|
||||
EXPECT_EQ(0s, parseDuration("00:00:00"));
|
||||
}
|
||||
|
||||
TEST(Time, durationTo_hh_mm_ss)
|
||||
{
|
||||
EXPECT_EQ("00:00:00", durationTo_hh_mm_ss(0s));
|
||||
EXPECT_EQ("01:32:05", durationTo_hh_mm_ss(1h + 32min + 5s));
|
||||
EXPECT_EQ("20:45:13", durationTo_hh_mm_ss(20h + 45min + 13s));
|
||||
const auto duration = 20h + 45min + 13s;
|
||||
EXPECT_EQ(duration, parseDuration(durationTo_hh_mm_ss(duration)));
|
||||
}
|
||||
|
||||
TEST(AbsoluteVariedTime, Constructor)
|
||||
{
|
||||
system_clock::time_point now = system_clock::now();
|
||||
{
|
||||
AbsoluteVariedTime time(now);
|
||||
EXPECT_EQ(now, time.getBaseTime());
|
||||
EXPECT_EQ(0s, time.getRandomVariation());
|
||||
}
|
||||
system_clock::duration variation = 4h + 2min;
|
||||
{
|
||||
AbsoluteVariedTime time(now, variation);
|
||||
EXPECT_EQ(now, time.getBaseTime());
|
||||
EXPECT_EQ(variation, time.getRandomVariation());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(AbsoluteVariedTime, toString)
|
||||
{
|
||||
const system_clock::time_point timePoint = parseTimestamp("2020-03-03T20:53:03");
|
||||
|
||||
EXPECT_EQ("2020-03-03T20:53:03", AbsoluteVariedTime(timePoint).toString());
|
||||
|
||||
const system_clock::duration noVariation = 0s;
|
||||
EXPECT_EQ("2020-03-03T20:53:03", AbsoluteVariedTime(timePoint, noVariation).toString());
|
||||
|
||||
const system_clock::duration variation = 1h + 2min + 1s;
|
||||
EXPECT_EQ("2020-03-03T20:53:03A01:02:01", AbsoluteVariedTime(timePoint, variation).toString());
|
||||
}
|
||||
|
||||
TEST(AbsoluteTime, parseUTC)
|
||||
{
|
||||
AbsoluteTime absolute = AbsoluteTime::parseUTC("2020-03-03T20:53:03");
|
||||
std::time_t ctime = system_clock::to_time_t(absolute.getBaseTime());
|
||||
std::tm* pTm = std::gmtime(&ctime);
|
||||
ASSERT_NE(nullptr, pTm);
|
||||
std::tm tm = *pTm;
|
||||
EXPECT_EQ(2020 - 1900, tm.tm_year);
|
||||
EXPECT_EQ(3 - 1, tm.tm_mon);
|
||||
EXPECT_EQ(20, tm.tm_hour);
|
||||
EXPECT_EQ(53, tm.tm_min);
|
||||
EXPECT_EQ(3, tm.tm_sec);
|
||||
}
|
||||
|
||||
TEST(Weekdays, Constructor)
|
||||
{
|
||||
EXPECT_TRUE(Weekdays().isNone());
|
||||
EXPECT_TRUE(Weekdays(0).isMonday());
|
||||
EXPECT_TRUE(Weekdays(6).isSunday());
|
||||
}
|
||||
|
||||
TEST(Weekdays, isXXX)
|
||||
{
|
||||
Weekdays none = Weekdays::none();
|
||||
EXPECT_TRUE(none.isNone());
|
||||
EXPECT_FALSE(none.isAll());
|
||||
EXPECT_FALSE(none.isMonday());
|
||||
EXPECT_FALSE(none.isTuesday());
|
||||
EXPECT_FALSE(none.isWednesday());
|
||||
EXPECT_FALSE(none.isThursday());
|
||||
EXPECT_FALSE(none.isFriday());
|
||||
EXPECT_FALSE(none.isSaturday());
|
||||
EXPECT_FALSE(none.isSunday());
|
||||
|
||||
Weekdays all = Weekdays::all();
|
||||
EXPECT_FALSE(all.isNone());
|
||||
EXPECT_TRUE(all.isAll());
|
||||
EXPECT_TRUE(all.isMonday());
|
||||
EXPECT_TRUE(all.isTuesday());
|
||||
EXPECT_TRUE(all.isWednesday());
|
||||
EXPECT_TRUE(all.isThursday());
|
||||
EXPECT_TRUE(all.isFriday());
|
||||
EXPECT_TRUE(all.isSaturday());
|
||||
EXPECT_TRUE(all.isSunday());
|
||||
|
||||
// Test that for all days, only their own isXXX function is true
|
||||
std::vector<Weekdays> days {Weekdays::monday(), Weekdays::tuesday(), Weekdays::wednesday(), Weekdays::thursday(),
|
||||
Weekdays::friday(), Weekdays::saturday(), Weekdays::sunday()};
|
||||
using BoolGetter = bool (Weekdays::*)() const;
|
||||
std::vector<BoolGetter> getters {&Weekdays::isMonday, &Weekdays::isTuesday, &Weekdays::isWednesday,
|
||||
&Weekdays::isThursday, &Weekdays::isFriday, &Weekdays::isSaturday, &Weekdays::isSunday};
|
||||
for (int i = 0; i < days.size(); ++i)
|
||||
{
|
||||
Weekdays day = days[i];
|
||||
EXPECT_FALSE(day.isNone());
|
||||
EXPECT_FALSE(day.isAll());
|
||||
for (int j = 0; j < getters.size(); ++j)
|
||||
{
|
||||
EXPECT_EQ(j == i, (day.*getters[j])()) << "on Day " << i << ": getter for day " << j << " has wrong result";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Weekdays, unionWith)
|
||||
{
|
||||
Weekdays day = Weekdays::monday().unionWith(Weekdays::saturday());
|
||||
EXPECT_TRUE(day.isMonday());
|
||||
EXPECT_TRUE(day.isSaturday());
|
||||
|
||||
day = Weekdays::monday() | Weekdays::tuesday() | Weekdays::all();
|
||||
EXPECT_TRUE(day.isAll());
|
||||
}
|
||||
|
||||
TEST(Weekdays, equals)
|
||||
{
|
||||
EXPECT_EQ(Weekdays::monday(), Weekdays(0));
|
||||
EXPECT_EQ(Weekdays::none(), Weekdays());
|
||||
EXPECT_EQ(Weekdays::monday() | Weekdays::tuesday(), Weekdays::monday().unionWith(Weekdays::tuesday()));
|
||||
|
||||
EXPECT_NE(Weekdays::none(), Weekdays(0));
|
||||
EXPECT_NE(Weekdays::all(), Weekdays::monday());
|
||||
}
|
||||
|
||||
TEST(Weekdays, toString)
|
||||
{
|
||||
EXPECT_EQ("001", Weekdays(0).toString());
|
||||
EXPECT_EQ("064", Weekdays(6).toString());
|
||||
EXPECT_EQ("112", (Weekdays(6) | Weekdays(5) | Weekdays(4)).toString());
|
||||
}
|
||||
|
||||
TEST(RecurringTime, Constructor)
|
||||
{
|
||||
{
|
||||
const auto time = 6h + 4min;
|
||||
const Weekdays days = Weekdays::all();
|
||||
const RecurringTime recurring(time, days);
|
||||
|
||||
EXPECT_EQ(time, recurring.getDaytime());
|
||||
EXPECT_EQ(0s, recurring.getRandomVariation());
|
||||
EXPECT_EQ(days, recurring.getWeekdays());
|
||||
}
|
||||
{
|
||||
const auto time = 2h + 3min + 2s;
|
||||
const Weekdays days = Weekdays::monday() | Weekdays::friday();
|
||||
const auto variation = 40min;
|
||||
const RecurringTime recurring(time, days, variation);
|
||||
|
||||
EXPECT_EQ(time, recurring.getDaytime());
|
||||
EXPECT_EQ(variation, recurring.getRandomVariation());
|
||||
EXPECT_EQ(days, recurring.getWeekdays());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(RecurringTime, toString)
|
||||
{
|
||||
const auto time = 0h + 4min;
|
||||
const RecurringTime recurring(time, Weekdays::monday());
|
||||
EXPECT_EQ("W001/T00:04:00", recurring.toString());
|
||||
|
||||
const RecurringTime variation(time, Weekdays::monday(), 1s);
|
||||
EXPECT_EQ("W001/T00:04:00A00:00:01", variation.toString());
|
||||
}
|
||||
|
||||
TEST(TimeInterval, Constructor)
|
||||
{
|
||||
{
|
||||
const auto start = 1h + 40min;
|
||||
const auto end = 11h + 25s;
|
||||
const TimeInterval interval(start, end);
|
||||
|
||||
EXPECT_EQ(start, interval.getStartTime());
|
||||
EXPECT_EQ(end, interval.getEndTime());
|
||||
EXPECT_EQ(Weekdays::all(), interval.getWeekdays());
|
||||
}
|
||||
{
|
||||
const auto start = 0s;
|
||||
const auto end = 20h;
|
||||
const Weekdays days = Weekdays::friday() | Weekdays::saturday();
|
||||
const TimeInterval interval(start, end, days);
|
||||
EXPECT_EQ(start, interval.getStartTime());
|
||||
EXPECT_EQ(end, interval.getEndTime());
|
||||
EXPECT_EQ(days, interval.getWeekdays());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(TimeInterval, toString)
|
||||
{
|
||||
{
|
||||
const TimeInterval interval(1h + 40min, 11h + 25s);
|
||||
EXPECT_EQ("T01:40:00/T11:00:25", interval.toString());
|
||||
}
|
||||
{
|
||||
const TimeInterval interval(0h, 20h + 1s, Weekdays::monday());
|
||||
EXPECT_EQ("W001/T00:00:00/T20:00:01", interval.toString());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Timer, Constructor)
|
||||
{
|
||||
{
|
||||
const auto duration = 1min + 20s;
|
||||
const Timer timer(duration);
|
||||
EXPECT_FALSE(timer.isRecurring());
|
||||
EXPECT_EQ(1, timer.getNumberOfExecutions());
|
||||
EXPECT_EQ(duration, timer.getExpiryTime());
|
||||
EXPECT_EQ(0s, timer.getRandomVariation());
|
||||
}
|
||||
{
|
||||
const auto duration = 1min + 20s;
|
||||
const auto variation = 1h;
|
||||
const Timer timer(duration, variation);
|
||||
EXPECT_FALSE(timer.isRecurring());
|
||||
EXPECT_EQ(1, timer.getNumberOfExecutions());
|
||||
EXPECT_EQ(duration, timer.getExpiryTime());
|
||||
EXPECT_EQ(variation, timer.getRandomVariation());
|
||||
}
|
||||
{
|
||||
const auto duration = 1min + 20s;
|
||||
const int num = 0;
|
||||
const Timer timer(duration, num);
|
||||
EXPECT_TRUE(timer.isRecurring());
|
||||
EXPECT_EQ(num, timer.getNumberOfExecutions());
|
||||
EXPECT_EQ(duration, timer.getExpiryTime());
|
||||
EXPECT_EQ(0s, timer.getRandomVariation());
|
||||
}
|
||||
{
|
||||
const auto duration = 1min + 20s;
|
||||
const int num = 10;
|
||||
const auto variation = 20min;
|
||||
const Timer timer(duration, num, variation);
|
||||
EXPECT_TRUE(timer.isRecurring());
|
||||
EXPECT_EQ(num, timer.getNumberOfExecutions());
|
||||
EXPECT_EQ(duration, timer.getExpiryTime());
|
||||
EXPECT_EQ(variation, timer.getRandomVariation());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Timer, toString)
|
||||
{
|
||||
{
|
||||
const Timer timer(1min + 20s);
|
||||
EXPECT_EQ("PT00:01:20", timer.toString());
|
||||
}
|
||||
{
|
||||
const Timer timer(1min + 20s, 1h);
|
||||
EXPECT_EQ("PT00:01:20A01:00:00", timer.toString());
|
||||
}
|
||||
{
|
||||
const Timer timer(1min + 20s, Timer::infiniteExecutions);
|
||||
EXPECT_EQ("R/PT00:01:20", timer.toString());
|
||||
}
|
||||
{
|
||||
const Timer timer(1min + 20s, 1);
|
||||
EXPECT_EQ("PT00:01:20", timer.toString());
|
||||
}
|
||||
{
|
||||
const Timer timer(1min + 20s, 15);
|
||||
EXPECT_EQ("R15/PT00:01:20", timer.toString());
|
||||
}
|
||||
{
|
||||
const Timer timer(1min + 20s, 5, 1h);
|
||||
EXPECT_EQ("R05/PT00:01:20A01:00:00", timer.toString());
|
||||
}
|
||||
{
|
||||
const Timer timer(1min + 20s, Timer::infiniteExecutions, 1h);
|
||||
EXPECT_EQ("R/PT00:01:20A01:00:00", timer.toString());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(TimePattern, Undefined)
|
||||
{
|
||||
{
|
||||
TimePattern pattern;
|
||||
EXPECT_EQ(TimePattern::Type::undefined, pattern.getType());
|
||||
}
|
||||
{
|
||||
TimePattern pattern = TimePattern::parse("");
|
||||
EXPECT_EQ(TimePattern::Type::undefined, pattern.getType());
|
||||
}
|
||||
{
|
||||
TimePattern pattern = TimePattern::parse("none");
|
||||
EXPECT_EQ(TimePattern::Type::undefined, pattern.getType());
|
||||
}
|
||||
EXPECT_THROW(TimePattern::parse("bla"), hueplusplus::HueException);
|
||||
}
|
||||
|
||||
TEST(TimePattern, CopyConstructor)
|
||||
{
|
||||
{
|
||||
TimePattern pattern;
|
||||
TimePattern copy = pattern;
|
||||
EXPECT_EQ(TimePattern::Type::undefined, copy.getType());
|
||||
}
|
||||
{
|
||||
const AbsoluteVariedTime abs(system_clock::now());
|
||||
const TimePattern pattern(abs);
|
||||
const TimePattern copy(pattern);
|
||||
ASSERT_EQ(TimePattern::Type::absolute, copy.getType());
|
||||
EXPECT_EQ(abs.getBaseTime(), copy.asAbsolute().getBaseTime());
|
||||
}
|
||||
{
|
||||
const RecurringTime rec(12h + 30min, Weekdays::monday(), 1h);
|
||||
const TimePattern pattern(rec);
|
||||
const TimePattern copy(pattern);
|
||||
ASSERT_EQ(TimePattern::Type::recurring, copy.getType());
|
||||
EXPECT_EQ(rec.getDaytime(), copy.asRecurring().getDaytime());
|
||||
EXPECT_EQ(rec.getWeekdays(), copy.asRecurring().getWeekdays());
|
||||
EXPECT_EQ(rec.getRandomVariation(), copy.asRecurring().getRandomVariation());
|
||||
}
|
||||
{
|
||||
const TimeInterval interval(12h + 30min, 13h + 20min, Weekdays::friday());
|
||||
const TimePattern pattern(interval);
|
||||
const TimePattern copy(pattern);
|
||||
ASSERT_EQ(TimePattern::Type::interval, copy.getType());
|
||||
EXPECT_EQ(interval.getStartTime(), copy.asInterval().getStartTime());
|
||||
EXPECT_EQ(interval.getEndTime(), copy.asInterval().getEndTime());
|
||||
EXPECT_EQ(interval.getWeekdays(), copy.asInterval().getWeekdays());
|
||||
}
|
||||
{
|
||||
const Timer timer(1h + 30min, 5, 20s);
|
||||
const TimePattern pattern(timer);
|
||||
const TimePattern copy(pattern);
|
||||
ASSERT_EQ(TimePattern::Type::timer, copy.getType());
|
||||
EXPECT_EQ(timer.getExpiryTime(), copy.asTimer().getExpiryTime());
|
||||
EXPECT_EQ(timer.getRandomVariation(), copy.asTimer().getRandomVariation());
|
||||
EXPECT_EQ(timer.getNumberOfExecutions(), copy.asTimer().getNumberOfExecutions());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(TimePattern, Absolute)
|
||||
{
|
||||
{
|
||||
const AbsoluteVariedTime abs(system_clock::now(), 20s);
|
||||
const TimePattern pattern(abs);
|
||||
ASSERT_EQ(TimePattern::Type::absolute, pattern.getType());
|
||||
EXPECT_EQ(abs.getBaseTime(), pattern.asAbsolute().getBaseTime());
|
||||
EXPECT_EQ(abs.getRandomVariation(), pattern.asAbsolute().getRandomVariation());
|
||||
}
|
||||
|
||||
const system_clock::time_point timePoint = parseTimestamp("2020-03-03T20:53:03");
|
||||
{
|
||||
const TimePattern pattern = TimePattern::parse("2020-03-03T20:53:03");
|
||||
const AbsoluteVariedTime expected(timePoint);
|
||||
ASSERT_EQ(TimePattern::Type::absolute, pattern.getType());
|
||||
EXPECT_EQ(expected.getBaseTime(), pattern.asAbsolute().getBaseTime());
|
||||
EXPECT_EQ(expected.getRandomVariation(), pattern.asAbsolute().getRandomVariation());
|
||||
}
|
||||
{
|
||||
const system_clock::duration variation = 1h + 2min + 1s;
|
||||
const TimePattern pattern = TimePattern::parse("2020-03-03T20:53:03A01:02:01");
|
||||
const AbsoluteVariedTime expected(timePoint, variation);
|
||||
ASSERT_EQ(TimePattern::Type::absolute, pattern.getType());
|
||||
EXPECT_EQ(expected.getBaseTime(), pattern.asAbsolute().getBaseTime());
|
||||
EXPECT_EQ(expected.getRandomVariation(), pattern.asAbsolute().getRandomVariation());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(TimePattern, Recurring)
|
||||
{
|
||||
{
|
||||
const RecurringTime rec(12h + 30min, Weekdays::monday(), 1h);
|
||||
const TimePattern pattern(rec);
|
||||
ASSERT_EQ(TimePattern::Type::recurring, pattern.getType());
|
||||
EXPECT_EQ(rec.getDaytime(), pattern.asRecurring().getDaytime());
|
||||
EXPECT_EQ(rec.getWeekdays(), pattern.asRecurring().getWeekdays());
|
||||
EXPECT_EQ(rec.getRandomVariation(), pattern.asRecurring().getRandomVariation());
|
||||
}
|
||||
{
|
||||
const TimePattern pattern = TimePattern::parse("W001/T12:30:00");
|
||||
const RecurringTime expected(12h + 30min, Weekdays::monday());
|
||||
|
||||
ASSERT_EQ(TimePattern::Type::recurring, pattern.getType());
|
||||
EXPECT_EQ(expected.getDaytime(), pattern.asRecurring().getDaytime());
|
||||
EXPECT_EQ(expected.getWeekdays(), pattern.asRecurring().getWeekdays());
|
||||
EXPECT_EQ(expected.getRandomVariation(), pattern.asRecurring().getRandomVariation());
|
||||
}
|
||||
{
|
||||
const TimePattern pattern = TimePattern::parse("W001/T12:30:00A01:00:00");
|
||||
const RecurringTime expected(12h + 30min, Weekdays::monday(), 1h);
|
||||
|
||||
ASSERT_EQ(TimePattern::Type::recurring, pattern.getType());
|
||||
EXPECT_EQ(expected.getDaytime(), pattern.asRecurring().getDaytime());
|
||||
EXPECT_EQ(expected.getWeekdays(), pattern.asRecurring().getWeekdays());
|
||||
EXPECT_EQ(expected.getRandomVariation(), pattern.asRecurring().getRandomVariation());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(TimePattern, Interval)
|
||||
{
|
||||
{
|
||||
const TimeInterval interval(12h + 30min, 13h + 20min, Weekdays::friday());
|
||||
const TimePattern pattern(interval);
|
||||
ASSERT_EQ(TimePattern::Type::interval, pattern.getType());
|
||||
EXPECT_EQ(interval.getStartTime(), pattern.asInterval().getStartTime());
|
||||
EXPECT_EQ(interval.getEndTime(), pattern.asInterval().getEndTime());
|
||||
EXPECT_EQ(interval.getWeekdays(), pattern.asInterval().getWeekdays());
|
||||
}
|
||||
{
|
||||
const TimeInterval expected(12h + 30min, 13h + 20min + 12s);
|
||||
const TimePattern pattern = TimePattern::parse("T12:30:00/T13:20:12");
|
||||
ASSERT_EQ(TimePattern::Type::interval, pattern.getType());
|
||||
EXPECT_EQ(expected.getStartTime(), pattern.asInterval().getStartTime());
|
||||
EXPECT_EQ(expected.getEndTime(), pattern.asInterval().getEndTime());
|
||||
EXPECT_EQ(expected.getWeekdays(), pattern.asInterval().getWeekdays());
|
||||
}
|
||||
{
|
||||
const TimeInterval expected(12h + 30min, 13h + 20min + 12s, Weekdays::monday());
|
||||
const TimePattern pattern = TimePattern::parse("W001/T12:30:00/T13:20:12");
|
||||
ASSERT_EQ(TimePattern::Type::interval, pattern.getType());
|
||||
EXPECT_EQ(expected.getStartTime(), pattern.asInterval().getStartTime());
|
||||
EXPECT_EQ(expected.getEndTime(), pattern.asInterval().getEndTime());
|
||||
EXPECT_EQ(expected.getWeekdays(), pattern.asInterval().getWeekdays());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(TimePattern, Timer)
|
||||
{
|
||||
{
|
||||
const Timer timer(1h + 30min, 5, 20s);
|
||||
const TimePattern pattern(timer);
|
||||
ASSERT_EQ(TimePattern::Type::timer, pattern.getType());
|
||||
EXPECT_EQ(timer.getExpiryTime(), pattern.asTimer().getExpiryTime());
|
||||
EXPECT_EQ(timer.getRandomVariation(), pattern.asTimer().getRandomVariation());
|
||||
EXPECT_EQ(timer.getNumberOfExecutions(), pattern.asTimer().getNumberOfExecutions());
|
||||
}
|
||||
{
|
||||
const Timer expected(1h + 30min + 20s);
|
||||
const TimePattern pattern = TimePattern::parse("PT01:30:20");
|
||||
ASSERT_EQ(TimePattern::Type::timer, pattern.getType());
|
||||
EXPECT_EQ(expected.getExpiryTime(), pattern.asTimer().getExpiryTime());
|
||||
EXPECT_EQ(expected.getRandomVariation(), pattern.asTimer().getRandomVariation());
|
||||
EXPECT_EQ(expected.getNumberOfExecutions(), pattern.asTimer().getNumberOfExecutions());
|
||||
}
|
||||
{
|
||||
const Timer expected(1h + 30min + 20s, 20s);
|
||||
const TimePattern pattern = TimePattern::parse("PT01:30:20A00:00:20");
|
||||
ASSERT_EQ(TimePattern::Type::timer, pattern.getType());
|
||||
EXPECT_EQ(expected.getExpiryTime(), pattern.asTimer().getExpiryTime());
|
||||
EXPECT_EQ(expected.getRandomVariation(), pattern.asTimer().getRandomVariation());
|
||||
EXPECT_EQ(expected.getNumberOfExecutions(), pattern.asTimer().getNumberOfExecutions());
|
||||
}
|
||||
{
|
||||
const Timer expected(1h + 30min + 20s, Timer::infiniteExecutions);
|
||||
const TimePattern pattern = TimePattern::parse("R/PT01:30:20");
|
||||
ASSERT_EQ(TimePattern::Type::timer, pattern.getType());
|
||||
EXPECT_EQ(expected.getExpiryTime(), pattern.asTimer().getExpiryTime());
|
||||
EXPECT_EQ(expected.getRandomVariation(), pattern.asTimer().getRandomVariation());
|
||||
EXPECT_EQ(expected.getNumberOfExecutions(), pattern.asTimer().getNumberOfExecutions());
|
||||
}
|
||||
{
|
||||
const Timer expected(1h + 30min + 20s, Timer::infiniteExecutions, 20s);
|
||||
const TimePattern pattern = TimePattern::parse("R/PT01:30:20A00:00:20");
|
||||
ASSERT_EQ(TimePattern::Type::timer, pattern.getType());
|
||||
EXPECT_EQ(expected.getExpiryTime(), pattern.asTimer().getExpiryTime());
|
||||
EXPECT_EQ(expected.getRandomVariation(), pattern.asTimer().getRandomVariation());
|
||||
EXPECT_EQ(expected.getNumberOfExecutions(), pattern.asTimer().getNumberOfExecutions());
|
||||
}
|
||||
{
|
||||
const Timer expected(1h + 30min + 20s, 5);
|
||||
const TimePattern pattern = TimePattern::parse("R05/PT01:30:20");
|
||||
ASSERT_EQ(TimePattern::Type::timer, pattern.getType());
|
||||
EXPECT_EQ(expected.getExpiryTime(), pattern.asTimer().getExpiryTime());
|
||||
EXPECT_EQ(expected.getRandomVariation(), pattern.asTimer().getRandomVariation());
|
||||
EXPECT_EQ(expected.getNumberOfExecutions(), pattern.asTimer().getNumberOfExecutions());
|
||||
}
|
||||
{
|
||||
const Timer expected(1h + 30min + 20s, 5, 20s);
|
||||
const TimePattern pattern = TimePattern::parse("R05/PT01:30:20A00:00:20");
|
||||
ASSERT_EQ(TimePattern::Type::timer, pattern.getType());
|
||||
EXPECT_EQ(expected.getExpiryTime(), pattern.asTimer().getExpiryTime());
|
||||
EXPECT_EQ(expected.getRandomVariation(), pattern.asTimer().getRandomVariation());
|
||||
EXPECT_EQ(expected.getNumberOfExecutions(), pattern.asTimer().getNumberOfExecutions());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/**
|
||||
\file test_UPnP.cpp
|
||||
Copyright Notice\n
|
||||
Copyright (C) 2017 Jan Rogall - developer\n
|
||||
Copyright (C) 2017 Moritz Wirger - developer\n
|
||||
|
||||
This file is part of hueplusplus.
|
||||
|
||||
hueplusplus 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.
|
||||
|
||||
hueplusplus 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 hueplusplus. If not, see <http://www.gnu.org/licenses/>.
|
||||
**/
|
||||
|
||||
#include <gmock/gmock.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "iostream"
|
||||
#include "testhelper.h"
|
||||
|
||||
#include "hueplusplus/LibConfig.h"
|
||||
#include "hueplusplus/UPnP.h"
|
||||
#include <nlohmann/json.hpp>
|
||||
#include "mocks/mock_HttpHandler.h"
|
||||
|
||||
using namespace hueplusplus;
|
||||
|
||||
const std::vector<std::pair<std::string, std::string>> expected_uplug_dev
|
||||
= {{"http://192.168.2.1:1900/gatedesc.xml", "Linux/2.6.36, UPnP/1.0, Portable SDK for UPnP devices/1.6.19"},
|
||||
{"http://192.168.2.116:80/description.xml", "Linux/3.14.0 UPnP/1.0 IpBridge/1.21.0"}};
|
||||
|
||||
TEST(UPnP, getDevices)
|
||||
{
|
||||
std::shared_ptr<MockHttpHandler> handler = std::make_shared<MockHttpHandler>();
|
||||
EXPECT_CALL(*handler,
|
||||
sendMulticast("M-SEARCH * HTTP/1.1\r\nHOST: 239.255.255.250:1900\r\nMAN: "
|
||||
"\"ssdp:discover\"\r\nMX: 5\r\nST: ssdp:all\r\n\r\n",
|
||||
"239.255.255.250", 1900, Config::instance().getUPnPTimeout()))
|
||||
.Times(1)
|
||||
.WillRepeatedly(::testing::Return(getMulticastReply()));
|
||||
|
||||
UPnP uplug;
|
||||
std::vector<std::pair<std::string, std::string>> foundDevices = uplug.getDevices(handler);
|
||||
|
||||
EXPECT_EQ(foundDevices, expected_uplug_dev);
|
||||
}
|
||||
+283
@@ -0,0 +1,283 @@
|
||||
/**
|
||||
\file testhelper.h
|
||||
Copyright Notice\n
|
||||
Copyright (C) 2017 Jan Rogall - developer\n
|
||||
Copyright (C) 2017 Moritz Wirger - developer\n
|
||||
|
||||
This file is part of hueplusplus.
|
||||
|
||||
hueplusplus 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.
|
||||
|
||||
hueplusplus 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 hueplusplus. If not, see <http://www.gnu.org/licenses/>.
|
||||
**/
|
||||
|
||||
#ifndef _TEST_HELPER_H
|
||||
#define _TEST_HELPER_H
|
||||
|
||||
inline std::string getBridgeIp()
|
||||
{
|
||||
return "192.168.2.116"; //!< IP-Address of the fake hue bridge in dotted
|
||||
//!< decimal notation like "192.168.2.1"
|
||||
}
|
||||
|
||||
inline int getBridgePort()
|
||||
{
|
||||
return 80;
|
||||
}
|
||||
|
||||
inline std::string getBridgeUsername()
|
||||
{
|
||||
return "83b7780291a6ceffbe0bd049104df"; //!< Username that is used to access
|
||||
//!< the fake hue bridge
|
||||
}
|
||||
inline std::string getBridgeId()
|
||||
{
|
||||
return "111111FFFE11E111";
|
||||
}
|
||||
inline std::string getBridgeUuid()
|
||||
{
|
||||
return "1f111f11-da11-11e1-1b11-11111111e111";
|
||||
}
|
||||
inline std::string getBridgeMac()
|
||||
{
|
||||
return "11111111e111";
|
||||
}
|
||||
|
||||
inline std::string getBridgeXml()
|
||||
{
|
||||
return R"xml(<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<root xmlns="urn:schemas-upnp-org:device-1-0">
|
||||
<specVersion>
|
||||
<major>1</major>
|
||||
<minor>0</minor>
|
||||
</specVersion>
|
||||
<URLBase>http://192.168.2.116:80/</URLBase>
|
||||
<device>
|
||||
<deviceType>urn:schemas-upnp-org:device:Basic:1</deviceType>
|
||||
<friendlyName>Philips hue (192.168.2.116)</friendlyName>
|
||||
<manufacturer>Royal Philips Electronics</manufacturer>
|
||||
<manufacturerURL>http://www.philips.com</manufacturerURL>
|
||||
<modelDescription>Philips hue Personal Wireless Lighting</modelDescription>
|
||||
<modelName>Philips hue bridge 2015</modelName>
|
||||
<modelNumber>BSB002</modelNumber>
|
||||
<modelURL>http://www.meethue.com</modelURL>
|
||||
<serialNumber>11111111e111</serialNumber>
|
||||
<UDN>uuid:1f111f11-da11-11e1-1b11-11111111e111</UDN>
|
||||
<presentationURL>index.html</presentationURL>
|
||||
<iconList>
|
||||
<icon>
|
||||
<mimetype>image/png</mimetype>
|
||||
<height>48</height>
|
||||
<width>48</width>
|
||||
<depth>24</depth>
|
||||
<url>hue_logo_0.png</url>
|
||||
</icon>
|
||||
</iconList>
|
||||
</device>
|
||||
</root>)xml";
|
||||
}
|
||||
|
||||
inline std::vector<std::string> getMulticastReply()
|
||||
{
|
||||
return {"HTTP/1.1 200 OK\r\n"
|
||||
"CACHE-CONTROL: max-age=300\r\n"
|
||||
"DATE: Wed, 21 Jan 1970 05:42:21 GMT\r\n"
|
||||
"EXT:\r\n"
|
||||
"LOCATION: http://192.168.2.1:1900/gatedesc.xml\r\n"
|
||||
"OPT: \"http://schemas.upnp.org/upnp/1/0/\"; ns=01\r\n"
|
||||
"01-NLS: 000c0000-0dd0-00b0-0da0-00a000e000c0\r\n"
|
||||
"SERVER: Linux/2.6.36, UPnP/1.0, Portable SDK for UPnP devices/1.6.19\r\n"
|
||||
"X-User-Agent: redsonic\r\n"
|
||||
"ST: upnp:rootdevice\r\n"
|
||||
"USN: uuid:0f0000b0-f0da-0ad0-00b0-0000000fdf00::upnp:rootdevice",
|
||||
|
||||
"HTTP/1.1 200 OK\r\n"
|
||||
"CACHE-CONTROL: max-age=300\r\n"
|
||||
"DATE: Wed, 21 Jan 1970 05:42:21 GMT\r\n"
|
||||
"EXT:\r\n"
|
||||
"LOCATION: http://192.168.2.1:1900/gatedesc.xml\r\n"
|
||||
"OPT: \"http://schemas.upnp.org/upnp/1/0/\"; ns=01\r\n"
|
||||
"01-NLS: 000c0000-0dd0-00b0-0da0-00a000e000c0\r\n"
|
||||
"SERVER: Linux/2.6.36, UPnP/1.0, Portable SDK for UPnP devices/1.6.19\r\n"
|
||||
"X-User-Agent: redsonic\r\n"
|
||||
"ST: uuid:0f0000b0-f0da-0ad0-00b0-0000000fdf00\r\n"
|
||||
"USN: uuid:0f0000b0-f0da-0ad0-00b0-0000000fdf00",
|
||||
|
||||
"HTTP/1.1 200 OK\r\n"
|
||||
"CACHE-CONTROL: max-age=300\r\n"
|
||||
"DATE: Wed, 21 Jan 1970 05:42:21 GMT\r\n"
|
||||
"EXT:\r\n"
|
||||
"LOCATION: http://192.168.2.1:1900/gatedesc.xml\r\n"
|
||||
"OPT: \"http://schemas.upnp.org/upnp/1/0/\"; ns=01\r\n"
|
||||
"01-NLS: 000c0000-0dd0-00b0-0da0-00a000e000c0\r\n"
|
||||
"SERVER: Linux/2.6.36, UPnP/1.0, Portable SDK for UPnP devices/1.6.19\r\n"
|
||||
"X-User-Agent: redsonic\r\n"
|
||||
"ST: urn:schemas-upnp-org:device:InternetGatewayDevice:1\r\n"
|
||||
"USN: "
|
||||
"uuid:0f0000b0-f0da-0ad0-00b0-0000000fdf00::urn:schemas-upnp-org:device:"
|
||||
"InternetGatewayDevice:1",
|
||||
|
||||
"HTTP/1.1 200 OK\r\n"
|
||||
"CACHE-CONTROL: max-age=300\r\n"
|
||||
"DATE: Wed, 21 Jan 1970 05:42:21 GMT\r\n"
|
||||
"EXT:\r\n"
|
||||
"LOCATION: http://192.168.2.1:1900/gatedesc.xml\r\n"
|
||||
"OPT: \"http://schemas.upnp.org/upnp/1/0/\"; ns=01\r\n"
|
||||
"01-NLS: 000c0000-0dd0-00b0-0da0-00a000e000c0\r\n"
|
||||
"SERVER: Linux/2.6.36, UPnP/1.0, Portable SDK for UPnP devices/1.6.19\r\n"
|
||||
"X-User-Agent: redsonic\r\n"
|
||||
"ST: urn:schemas-upnp-org:service:Layer3Forwarding:1\r\n"
|
||||
"USN: "
|
||||
"uuid:0f0000b0-f0da-0ad0-00b0-0000000fdf00::urn:schemas-upnp-org:service:"
|
||||
"Layer3Forwarding:1",
|
||||
|
||||
"HTTP/1.1 200 OK\r\n"
|
||||
"CACHE-CONTROL: max-age=300\r\n"
|
||||
"DATE: Wed, 21 Jan 1970 05:42:21 GMT\r\n"
|
||||
"EXT:\r\n"
|
||||
"LOCATION: http://192.168.2.1:1900/gatedesc.xml\r\n"
|
||||
"OPT: \"http://schemas.upnp.org/upnp/1/0/\"; ns=01\r\n"
|
||||
"01-NLS: 000c0000-0dd0-00b0-0da0-00a000e000c0\r\n"
|
||||
"SERVER: Linux/2.6.36, UPnP/1.0, Portable SDK for UPnP devices/1.6.19\r\n"
|
||||
"X-User-Agent: redsonic\r\n"
|
||||
"ST: uuid:0f0000b0-f0da-0ad0-00b0-0000000fdf00\r\n"
|
||||
"USN: uuid:0f0000b0-f0da-0ad0-00b0-0000000fdf00",
|
||||
|
||||
"HTTP/1.1 200 OK\r\n"
|
||||
"CACHE-CONTROL: max-age=300\r\n"
|
||||
"DATE: Wed, 21 Jan 1970 05:42:21 GMT\r\n"
|
||||
"EXT:\r\n"
|
||||
"LOCATION: http://192.168.2.1:1900/gatedesc.xml\r\n"
|
||||
"OPT: \"http://schemas.upnp.org/upnp/1/0/\"; ns=01\r\n"
|
||||
"01-NLS: 000c0000-0dd0-00b0-0da0-00a000e000c0\r\n"
|
||||
"SERVER: Linux/2.6.36, UPnP/1.0, Portable SDK for UPnP devices/1.6.19\r\n"
|
||||
"X-User-Agent: redsonic\r\n"
|
||||
"ST: urn:schemas-upnp-org:device:WANDevice:1\r\n"
|
||||
"USN: "
|
||||
"uuid:0f0000b0-f0da-0ad0-00b0-0000000fdf00::urn:schemas-upnp-org:device:"
|
||||
"WANDevice:1",
|
||||
|
||||
"HTTP/1.1 200 OK\r\n"
|
||||
"CACHE-CONTROL: max-age=300\r\n"
|
||||
"DATE: Wed, 21 Jan 1970 05:42:21 GMT\r\n"
|
||||
"EXT:\r\n"
|
||||
"LOCATION: http://192.168.2.1:1900/gatedesc.xml\r\n"
|
||||
"OPT: \"http://schemas.upnp.org/upnp/1/0/\"; ns=01\r\n"
|
||||
"01-NLS: 000c0000-0dd0-00b0-0da0-00a000e000c0\r\n"
|
||||
"SERVER: Linux/2.6.36, UPnP/1.0, Portable SDK for UPnP devices/1.6.19\r\n"
|
||||
"X-User-Agent: redsonic\r\n"
|
||||
"ST: urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1\r\n"
|
||||
"USN: "
|
||||
"uuid:0f0000b0-f0da-0ad0-00b0-0000000fdf00::urn:schemas-upnp-org:service:"
|
||||
"WANCommonInterfaceConfig:1",
|
||||
|
||||
"HTTP/1.1 200 OK\r\n"
|
||||
"CACHE-CONTROL: max-age=300\r\n"
|
||||
"DATE: Wed, 21 Jan 1970 05:42:21 GMT\r\n"
|
||||
"EXT:\r\n"
|
||||
"LOCATION: http://192.168.2.1:1900/gatedesc.xml\r\n"
|
||||
"OPT: \"http://schemas.upnp.org/upnp/1/0/\"; ns=01\r\n"
|
||||
"01-NLS: 000c0000-0dd0-00b0-0da0-00a000e000c0\r\n"
|
||||
"SERVER: Linux/2.6.36, UPnP/1.0, Portable SDK for UPnP devices/1.6.19\r\n"
|
||||
"X-User-Agent: redsonic\r\n"
|
||||
"ST: uuid:0f0000b0-f0da-0ad0-00b0-0000000fdf00\r\n"
|
||||
"USN: uuid:0f0000b0-f0da-0ad0-00b0-0000000fdf00",
|
||||
|
||||
"HTTP/1.1 200 OK\r\n"
|
||||
"CACHE-CONTROL: max-age=300\r\n"
|
||||
"DATE: Wed, 21 Jan 1970 05:42:21 GMT\r\n"
|
||||
"EXT:\r\n"
|
||||
"LOCATION: http://192.168.2.1:1900/gatedesc.xml\r\n"
|
||||
"OPT: \"http://schemas.upnp.org/upnp/1/0/\"; ns=01\r\n"
|
||||
"01-NLS: 000c0000-0dd0-00b0-0da0-00a000e000c0\r\n"
|
||||
"SERVER: Linux/2.6.36, UPnP/1.0, Portable SDK for UPnP devices/1.6.19\r\n"
|
||||
"X-User-Agent: redsonic\r\n"
|
||||
"ST: urn:schemas-upnp-org:device:WANConnectionDevice:1\r\n"
|
||||
"USN: "
|
||||
"uuid:0f0000b0-f0da-0ad0-00b0-0000000fdf00::urn:schemas-upnp-org:device:"
|
||||
"WANConnectionDevice:1",
|
||||
|
||||
"HTTP/1.1 200 OK\r\n"
|
||||
"CACHE-CONTROL: max-age=300\r\n"
|
||||
"DATE: Wed, 21 Jan 1970 05:42:21 GMT\r\n"
|
||||
"EXT:\r\n"
|
||||
"LOCATION: http://192.168.2.1:1900/gatedesc.xml\r\n"
|
||||
"OPT: \"http://schemas.upnp.org/upnp/1/0/\"; ns=01\r\n"
|
||||
"01-NLS: 000c0000-0dd0-00b0-0da0-00a000e000c0\r\n"
|
||||
"SERVER: Linux/2.6.36, UPnP/1.0, Portable SDK for UPnP devices/1.6.19\r\n"
|
||||
"X-User-Agent: redsonic\r\n"
|
||||
"ST: urn:schemas-upnp-org:service:WANIPConnection:1\r\n"
|
||||
"USN: "
|
||||
"uuid:0f0000b0-f0da-0ad0-00b0-0000000fdf00::urn:schemas-upnp-org:service:"
|
||||
"WANIPConnection:1",
|
||||
|
||||
"HTTP/1.1 200 OK\r\n"
|
||||
"HOST: 239.255.255.250:1900\r\n"
|
||||
"EXT:\r\n"
|
||||
"CACHE-CONTROL: max-age=100\r\n"
|
||||
"LOCATION: http://192.168.2.116:80/description.xml\r\n"
|
||||
"SERVER: Linux/3.14.0 UPnP/1.0 IpBridge/1.21.0\r\n"
|
||||
"hue-bridgeid: 111111FFFE11E111\r\n"
|
||||
"ST: upnp:rootdevice\r\n"
|
||||
"USN: uuid:1f111f11-da11-11e1-1b11-11111111e111::upnp:rootdevice",
|
||||
|
||||
"HTTP/1.1 200 OK\r\n"
|
||||
"HOST: 239.255.255.250:1900\r\n"
|
||||
"EXT:\r\n"
|
||||
"CACHE-CONTROL: max-age=100\r\n"
|
||||
"LOCATION: http://192.168.2.116:80/description.xml\r\n"
|
||||
"SERVER: Linux/3.14.0 UPnP/1.0 IpBridge/1.21.0\r\n"
|
||||
"hue-bridgeid: 111111FFFE11E111\r\n"
|
||||
"ST: uuid:1f111f11-da11-11e1-1b11-11111111e111\r\n"
|
||||
"USN: uuid:1f111f11-da11-11e1-1b11-11111111e111",
|
||||
|
||||
"HTTP/1.1 200 OK\r\n"
|
||||
"HOST: 239.255.255.250:1900\r\n"
|
||||
"EXT:\r\n"
|
||||
"CACHE-CONTROL: max-age=100\r\n"
|
||||
"LOCATION: http://192.168.2.116:80/description.xml\r\n"
|
||||
"SERVER: Linux/3.14.0 UPnP/1.0 IpBridge/1.21.0\r\n"
|
||||
"hue-bridgeid: 111111FFFE11E111\r\n"
|
||||
"ST: urn:schemas-upnp-org:device:basic:1\r\n"
|
||||
"USN: uuid:1f111f11-da11-11e1-1b11-11111111e111",
|
||||
|
||||
"HTTP/1.1 200 OK\r\n"
|
||||
"HOST: 239.255.255.250:1900\r\n"
|
||||
"EXT:\r\n"
|
||||
"CACHE-CONTROL: max-age=100\r\n"
|
||||
"LOCATION: http://192.168.2.116:80/description.xml\r\n"
|
||||
"SERVER: Linux/3.14.0 UPnP/1.0 IpBridge/1.21.0\r\n"
|
||||
"hue-bridgeid: 111111FFFE11E111\r\n"
|
||||
"ST: upnp:rootdevice\r\n"
|
||||
"USN: uuid:1f111f11-da11-11e1-1b11-11111111e111::upnp:rootdevice",
|
||||
|
||||
"HTTP/1.1 200 OK\r\n"
|
||||
"HOST: 239.255.255.250:1900\r\n"
|
||||
"EXT:\r\n"
|
||||
"CACHE-CONTROL: max-age=100\r\n"
|
||||
"LOCATION: http://192.168.2.116:80/description.xml\r\n"
|
||||
"SERVER: Linux/3.14.0 UPnP/1.0 IpBridge/1.21.0\r\n"
|
||||
"hue-bridgeid: 111111FFFE11E111\r\n"
|
||||
"ST: uuid:1f111f11-da11-11e1-1b11-11111111e111\r\n"
|
||||
"USN: uuid:1f111f11-da11-11e1-1b11-11111111e111",
|
||||
|
||||
"HTTP/1.1 200 OK\r\n"
|
||||
"HOST: 239.255.255.250:1900\r\n"
|
||||
"EXT:\r\n"
|
||||
"CACHE-CONTROL: max-age=100\r\n"
|
||||
"LOCATION: http://192.168.2.116:80/description.xml\r\n"
|
||||
"SERVER: Linux/3.14.0 UPnP/1.0 IpBridge/1.21.0\r\n"
|
||||
"hue-bridgeid: 111111FFFE11E111\r\n"
|
||||
"ST: urn:schemas-upnp-org:device:basic:1\r\n"
|
||||
"USN: uuid:1f111f11-da11-11e1-1b11-11111111e111"};
|
||||
}
|
||||
#endif
|
||||
Reference in New Issue
Block a user