Publish curated LumaOps source from c85ee9ef8f1454f5c305398902afbb9e6738de40
Managed validation / full (push) Failing after 8s

This commit is contained in:
Public Source Publisher committed 2026-09-30 00:26:45 +00:00
1 parent 91f8b3e3c1
commit def7920856
2271 files changed
+501225 -501178

No files matched your search

+132 -132
View File
@@ -1,132 +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()
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()
+15 -15
View File
@@ -1,15 +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 ""
)
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 ""
)
+234 -234
View File
@@ -1,234 +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
# 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
+62 -62
View File
@@ -1,63 +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()));
}
};
/**
\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
@@ -1,44 +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
/**
\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
+79 -79
View File
@@ -1,79 +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
/**
\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
+130 -130
View File
@@ -1,130 +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
/**
\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
+323 -323
View File
@@ -1,323 +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());
}
}
/**
\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());
}
}
+70 -70
View File
@@ -1,70 +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));
}
/**
\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));
}
+125 -125
View File
@@ -1,125 +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));
}
/**
\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));
}
+239 -239
View File
@@ -1,239 +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));
}
/**
\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));
}
File diff suppressed because it is too large. Load diff
+195 -195
View File
@@ -1,195 +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());
}
/**
\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());
}
+237 -237
View File
@@ -1,238 +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
/**
\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
}
@@ -1,200 +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());
}
}
/**
\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());
}
}
@@ -1,122 +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());
}
}
/**
\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 -301
View File
@@ -1,301 +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());
}
/**
\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());
}
+242 -242
View File
@@ -1,242 +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());
}
}
/**
\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());
}
}
File diff suppressed because it is too large. Load diff
+174 -174
View File
@@ -1,174 +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);
}
/**
\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);
}
+55 -55
View File
@@ -1,55 +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();
}
/**
\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();
}
+74 -74
View File
@@ -1,75 +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());
}
/**
\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());
}
}
+299 -299
View File
@@ -1,300 +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));
/**
\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 -270
View File
@@ -1,270 +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());
}
/**
\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());
}
File diff suppressed because it is too large. Load diff
+330 -330
View File
@@ -1,330 +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());
}
}
/**
\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 -257
View File
@@ -1,257 +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());
}
/**
\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());
}
+392 -392
View File
@@ -1,392 +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);
}
/**
\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);
}
+100 -100
View File
@@ -1,100 +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; })));
}
}
/**
\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; })));
}
}
@@ -1,93 +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)));
}
/**
\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)));
}
@@ -1,486 +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)));
}
/**
\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)));
}
@@ -1,154 +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)));
}
/**
\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)));
}
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+54 -54
View File
@@ -1,54 +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);
}
/**
\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 -283
View File
@@ -1,283 +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
/**
\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