From: Marcin Niesluchowski Date: Mon, 28 Jul 2014 08:49:13 +0000 (+0200) Subject: Move test framework from wrt-commons to security-tests X-Git-Tag: security-manager_5.5_testing~216 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=6fdfd15692b25830947841f6a90110a052b2a7f1;p=platform%2Fcore%2Ftest%2Fsecurity-tests.git Move test framework from wrt-commons to security-tests Change-Id: If185e7401ded389f40d1a07e610c5d999ff152c1 --- diff --git a/packaging/security-tests.spec b/packaging/security-tests.spec index b9b6d6d..6d41ea2 100644 --- a/packaging/security-tests.spec +++ b/packaging/security-tests.spec @@ -12,10 +12,12 @@ BuildRequires: pkgconfig(libsmack) BuildRequires: pkgconfig(libprivilege-control) BuildRequires: pkgconfig(security-server) BuildRequires: pkgconfig(security-manager) -BuildRequires: pkgconfig(dpl-test-efl) BuildRequires: pkgconfig(dlog) +BuildRequires: pkgconfig(glib-2.0) BuildRequires: pkgconfig(dbus-1) BuildRequires: pkgconfig(dbus-glib-1) +BuildRequires: pkgconfig(libpcrecpp) +BuildRequires: pkgconfig(libxml-2.0) BuildRequires: pkgconfig(libiri) BuildRequires: pkgconfig(sqlite3) BuildRequires: pkgconfig(cynara-admin) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index db4ee57..9606a41 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -13,6 +13,39 @@ # limitations under the License. # +INCLUDE(FindPkgConfig) + +PKG_CHECK_MODULES(SYS_FRAMEWORK_TEST + REQUIRED + libxml-2.0 + libpcrecpp + libiri + ) + +PKG_CHECK_MODULES(SYS_FRAMEWORK_TEST_OTHER + REQUIRED + glib-2.0 + dlog + ) + +ADD_DEFINITIONS(${SYS_FRAMEWORK_TEST_OTHER_CFLAGS}) + +include(framework/config.cmake) + +SET(DPL_FRAMEWORK_TEST_LIBRARY "dpl-test-framework") + +INCLUDE_DIRECTORIES(SYSTEM + ${SYS_FRAMEWORK_TEST_OTHER_INCLUDE_DIRS} + ${DPL_FRAMEWORK_TEST_INCLUDE_DIR} + ) + +ADD_LIBRARY(${DPL_FRAMEWORK_TEST_LIBRARY} ${DPL_FRAMEWORK_TEST_SOURCES}) + +TARGET_LINK_LIBRARIES(${DPL_FRAMEWORK_TEST_LIBRARY} + ${SYS_FRAMEWORK_TEST_OTHER_LIBRARIES} + ${SYS_FRAMEWORK_TEST_LIBRARIES} + ) + INSTALL(FILES ${PROJECT_SOURCE_DIR}/tests/security-tests.sh DESTINATION bin PERMISSIONS OWNER_READ @@ -59,6 +92,7 @@ INSTALL(FILES WORLD_EXECUTE ) + ADD_SUBDIRECTORY(common) ADD_SUBDIRECTORY(libprivilege-control-tests) ADD_SUBDIRECTORY(libsmack-tests) diff --git a/tests/common/CMakeLists.txt b/tests/common/CMakeLists.txt index bf079e0..85d4ac1 100644 --- a/tests/common/CMakeLists.txt +++ b/tests/common/CMakeLists.txt @@ -4,7 +4,6 @@ SET(COMMON_TARGET_TEST "tests-common") #dependencies PKG_CHECK_MODULES(COMMON_TARGET_DEP libsmack - dpl-test-efl dbus-1 dbus-glib-1 sqlite3 @@ -29,12 +28,16 @@ SET(COMMON_TARGET_TEST_SOURCES #system and local includes INCLUDE_DIRECTORIES(SYSTEM ${COMMON_TARGET_DEP_INCLUDE_DIRS}) -INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/tests/common) +INCLUDE_DIRECTORIES( + ${PROJECT_SOURCE_DIR}/tests/framework/include + ${PROJECT_SOURCE_DIR}/tests/common + ) #output OBJECT format ADD_LIBRARY(${COMMON_TARGET_TEST} ${COMMON_TARGET_TEST_SOURCES}) -TARGET_LINK_LIBRARIES(${COMMON_TARGET_TEST} ${COMMON_TARGET_DEP_LIBRARIES}) +TARGET_LINK_LIBRARIES(${COMMON_TARGET_TEST} ${COMMON_TARGET_DEP_LIBRARIES} + dpl-test-framework) INSTALL (FILES ${PROJECT_SOURCE_DIR}/tests/common/security-tests.conf DESTINATION /etc/dbus-1/system.d) diff --git a/tests/common/tests_common.cpp b/tests/common/tests_common.cpp index e55ec75..555b8b5 100644 --- a/tests/common/tests_common.cpp +++ b/tests/common/tests_common.cpp @@ -26,6 +26,7 @@ #include #include #include +#include int DB::Transaction::db_result = PC_OPERATION_SUCCESS; diff --git a/tests/cynara-tests/CMakeLists.txt b/tests/cynara-tests/CMakeLists.txt index 9093003..8f69835 100644 --- a/tests/cynara-tests/CMakeLists.txt +++ b/tests/cynara-tests/CMakeLists.txt @@ -5,7 +5,6 @@ SET(CYNARA_TARGET_TEST "cynara-test") PKG_CHECK_MODULES(CYNARA_TARGET_DEP REQUIRED - dpl-test-efl libprivilege-control cynara-admin cynara-client @@ -41,6 +40,7 @@ ADD_EXECUTABLE(${CYNARA_TARGET_TEST} ${CYNARA_TARGET_TEST_SOURCES}) #linker directories TARGET_LINK_LIBRARIES(${CYNARA_TARGET_TEST} ${CYNARA_TARGET_DEP_LIBRARIES} + dpl-test-framework tests-common ) diff --git a/tests/cynara-tests/test_cases.cpp b/tests/cynara-tests/test_cases.cpp index c61e632..aeeed20 100644 --- a/tests/cynara-tests/test_cases.cpp +++ b/tests/cynara-tests/test_cases.cpp @@ -22,6 +22,7 @@ * @brief Tests for libcynara-client and libcynara-admin */ +#include #include #include #include diff --git a/tests/framework/config.cmake b/tests/framework/config.cmake new file mode 100644 index 0000000..4ec039a --- /dev/null +++ b/tests/framework/config.cmake @@ -0,0 +1,42 @@ +# Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# +# @file config.cmake +# @author Lukasz Marek (l.marek@samsung.com) +# @version 1.0 +# @brief +# + +SET(DPL_FRAMEWORK_TEST_SOURCES + ${PROJECT_SOURCE_DIR}/tests/framework/src/assert.cpp + ${PROJECT_SOURCE_DIR}/tests/framework/src/atomic.cpp + ${PROJECT_SOURCE_DIR}/tests/framework/src/binary_queue.cpp + ${PROJECT_SOURCE_DIR}/tests/framework/src/colors.cpp + ${PROJECT_SOURCE_DIR}/tests/framework/src/exception.cpp + ${PROJECT_SOURCE_DIR}/tests/framework/src/noncopyable.cpp + ${PROJECT_SOURCE_DIR}/tests/framework/src/singleton.cpp + ${PROJECT_SOURCE_DIR}/tests/framework/src/abstract_log_provider.cpp + ${PROJECT_SOURCE_DIR}/tests/framework/src/dlog_log_provider.cpp + ${PROJECT_SOURCE_DIR}/tests/framework/src/log.cpp + ${PROJECT_SOURCE_DIR}/tests/framework/src/old_style_log_provider.cpp + ${PROJECT_SOURCE_DIR}/tests/framework/src/test_results_collector.cpp + ${PROJECT_SOURCE_DIR}/tests/framework/src/test_runner_child.cpp + ${PROJECT_SOURCE_DIR}/tests/framework/src/test_runner.cpp + ${PROJECT_SOURCE_DIR}/tests/framework/src/test_runner_multiprocess.cpp +) + +SET(DPL_FRAMEWORK_TEST_INCLUDE_DIR + ${PROJECT_SOURCE_DIR}/tests/framework/include +) diff --git a/tests/framework/include/dpl/abstract_input.h b/tests/framework/include/dpl/abstract_input.h new file mode 100644 index 0000000..8c0e16a --- /dev/null +++ b/tests/framework/include/dpl/abstract_input.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file abstract_input.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the header file of abstract input + */ +#ifndef DPL_ABSTRACT_INPUT_H +#define DPL_ABSTRACT_INPUT_H + +#include +#include + +namespace DPL { +class BinaryQueue; +typedef std::auto_ptr BinaryQueueAutoPtr; + +class AbstractInput +{ + public: + class Exception + { + public: + DECLARE_EXCEPTION_TYPE(DPL::Exception, Base) + DECLARE_EXCEPTION_TYPE(Base, ReadFailed) + }; + + public: + virtual ~AbstractInput() {} + + /** + * Read binary data from input + * If no data is available method returns NULL buffer. + * In case connection was successfuly close, method returns empty buffer + * + * @param[in] size Maximum number of bytes to read from input + * @return Buffer containing read bytes + * @throw ReadFailed + */ + virtual BinaryQueueAutoPtr Read(size_t size) = 0; +}; +} // namespace DPL + +#endif // DPL_ABSTRACT_INPUT_H diff --git a/tests/framework/include/dpl/abstract_input_output.h b/tests/framework/include/dpl/abstract_input_output.h new file mode 100644 index 0000000..153d5c4 --- /dev/null +++ b/tests/framework/include/dpl/abstract_input_output.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file abstract_output.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the header file of abstract output + */ +#ifndef DPL_ABSTRACT_INPUT_OUTPUT_H +#define DPL_ABSTRACT_INPUT_OUTPUT_H + +#include +#include + +namespace DPL { +class AbstractInputOutput : + public AbstractInput, + public AbstractOutput +{ + public: + virtual ~AbstractInputOutput() {} +}; +} // namespace DPL + +#endif // DPL_ABSTRACT_INPUT_OUTPUT_H diff --git a/tests/framework/include/dpl/abstract_output.h b/tests/framework/include/dpl/abstract_output.h new file mode 100644 index 0000000..56c86fb --- /dev/null +++ b/tests/framework/include/dpl/abstract_output.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file abstract_output.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the header file of abstract output + */ +#ifndef DPL_ABSTRACT_OUTPUT_H +#define DPL_ABSTRACT_OUTPUT_H + +#include +#include + +namespace DPL { +class BinaryQueue; +typedef std::auto_ptr BinaryQueueAutoPtr; + +class AbstractOutput +{ + public: + class Exception + { + public: + DECLARE_EXCEPTION_TYPE(DPL::Exception, Base) + DECLARE_EXCEPTION_TYPE(Base, WriteFailed) + }; + + public: + virtual ~AbstractOutput() {} + + /** + * Write binary data to output + * If output is blocked, Write returns zero, if instance is a type of + * WaitableAbstractOutput one can wait for writability then + * + * @param[in] buffer Input buffer with data to be written + * @param[in] bufferSize Maximum number of bytes to write from buffer + * @return Number of bytes success successfuly written or zero if output is + * blocked + * @throw WriteFailed + */ + virtual size_t Write(const BinaryQueue &buffer, size_t bufferSize) = 0; +}; +} // namespace DPL + +#endif // DPL_ABSTRACT_OUTPUT_H diff --git a/tests/framework/include/dpl/assert.h b/tests/framework/include/dpl/assert.h new file mode 100644 index 0000000..59331a0 --- /dev/null +++ b/tests/framework/include/dpl/assert.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file assert.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of assert + */ +#ifndef DPL_ASSERT_H +#define DPL_ASSERT_H + +#include + +namespace DPL { +// Assertion handler procedure +// Do not call directly +// Always use Assert macro +DPL_NORETURN void AssertProc(const char *condition, + const char *file, + int line, + const char *function); +} // namespace DPL + +#define Assert(Condition) do { if (!(Condition)) { DPL::AssertProc(#Condition, \ + __FILE__, \ + __LINE__, \ + __FUNCTION__); \ + } } while (0) + +#endif // DPL_ASSERT_H diff --git a/tests/framework/include/dpl/atomic.h b/tests/framework/include/dpl/atomic.h new file mode 100644 index 0000000..50c4a1a --- /dev/null +++ b/tests/framework/include/dpl/atomic.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file atomic.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the header file of atomic + */ +#ifndef DPL_ATOMIC_H +#define DPL_ATOMIC_H + +#pragma GCC system_header +#include + +namespace DPL { +class Atomic +{ + public: + typedef gint ValueType; + + private: + volatile ValueType m_value; + + public: + Atomic(ValueType value = static_cast(0)); + + ValueType ExchangeAndAdd(ValueType value); + bool CompareAndExchange(ValueType oldValue, ValueType newValue); + bool operator--(); + void operator++(); + + operator ValueType() const; +}; +} // namespace DPL + +#endif // DPL_ATOMIC_H diff --git a/tests/framework/include/dpl/availability.h b/tests/framework/include/dpl/availability.h new file mode 100644 index 0000000..0813892 --- /dev/null +++ b/tests/framework/include/dpl/availability.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file availability.h + * @author Jihoon Chung (jihoon.chung@samsung.com) + * @version 1.0 + */ +#ifndef DPL_AVAILABILITY_H +#define DPL_AVAILABILITY_H + +#define DPL_DEPRECATED __attribute__((deprecated)) +#define DPL_DEPRECATED_WITH_MESSAGE(msg) __attribute__((deprecated(msg))) + +#define DPL_UNUSED __attribute__((unused)) +#define DPL_UNUSED_PARAM(variable) (void)variable + +#endif // DPL_AVAILABILITY_H diff --git a/tests/framework/include/dpl/binary_queue.h b/tests/framework/include/dpl/binary_queue.h new file mode 100644 index 0000000..f4fa278 --- /dev/null +++ b/tests/framework/include/dpl/binary_queue.h @@ -0,0 +1,296 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file binary_queue.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the header file of binary queue + */ +#ifndef DPL_BINARY_QUEUE_H +#define DPL_BINARY_QUEUE_H + +#include +#include +#include +#include +#include + +namespace DPL { +/** + * Binary stream implemented as constant size bucket list + * + * @todo Add optimized implementation for FlattenConsume + */ +class BinaryQueue : + public AbstractInputOutput +{ + public: + class Exception + { + public: + DECLARE_EXCEPTION_TYPE(DPL::Exception, Base) + DECLARE_EXCEPTION_TYPE(Base, OutOfData) + }; + + typedef void (*BufferDeleter)(const void *buffer, size_t bufferSize, + void *userParam); + static void BufferDeleterFree(const void *buffer, + size_t bufferSize, + void *userParam); + + class BucketVisitor + { + public: + /** + * Destructor + */ + virtual ~BucketVisitor(); + + /** + * Visit bucket + * + * @return none + * @param[in] buffer Constant pointer to bucket data buffer + * @param[in] bufferSize Number of bytes in bucket + */ + virtual void OnVisitBucket(const void *buffer, size_t bufferSize) = 0; + }; + + private: + struct Bucket : + private Noncopyable + { + const void *buffer; + const void *ptr; + size_t size; + size_t left; + + BufferDeleter deleter; + void *param; + + Bucket(const void *buffer, + size_t bufferSize, + BufferDeleter deleter, + void *userParam); + virtual ~Bucket(); + }; + + typedef std::list BucketList; + BucketList m_buckets; + size_t m_size; + + static void DeleteBucket(Bucket *bucket); + + class BucketVisitorCall + { + private: + BucketVisitor *m_visitor; + + public: + BucketVisitorCall(BucketVisitor *visitor); + virtual ~BucketVisitorCall(); + + void operator()(Bucket *bucket) const; + }; + + public: + /** + * Construct empty binary queue + */ + BinaryQueue(); + + /** + * Construct binary queue via bare copy of other binary queue + * + * @param[in] other Other binary queue to copy from + * @warning One cannot assume that bucket structure is preserved during copy + */ + BinaryQueue(const BinaryQueue &other); + + /** + * Destructor + */ + virtual ~BinaryQueue(); + + /** + * Construct binary queue via bare copy of other binary queue + * + * @param[in] other Other binary queue to copy from + * @warning One cannot assume that bucket structure is preserved during copy + */ + const BinaryQueue &operator=(const BinaryQueue &other); + + /** + * Append copy of @a bufferSize bytes from memory pointed by @a buffer + * to the end of binary queue. Uses default deleter based on free. + * + * @return none + * @param[in] buffer Pointer to buffer to copy data from + * @param[in] bufferSize Number of bytes to copy + * @exception std::bad_alloc Cannot allocate memory to hold additional data + * @see BinaryQueue::BufferDeleterFree + */ + void AppendCopy(const void *buffer, size_t bufferSize); + + /** + * Append @a bufferSize bytes from memory pointed by @a buffer + * to the end of binary queue. Uses custom provided deleter. + * Responsibility for deleting provided buffer is transfered to BinaryQueue. + * + * @return none + * @param[in] buffer Pointer to data buffer + * @param[in] bufferSize Number of bytes available in buffer + * @param[in] deleter Pointer to deleter procedure used to free provided + * buffer + * @param[in] userParam User parameter passed to deleter routine + * @exception std::bad_alloc Cannot allocate memory to hold additional data + */ + void AppendUnmanaged( + const void *buffer, + size_t bufferSize, + BufferDeleter deleter = + &BinaryQueue::BufferDeleterFree, + void *userParam = NULL); + + /** + * Append copy of other binary queue to the end of this binary queue + * + * @return none + * @param[in] other Constant reference to other binary queue to copy data + * from + * @exception std::bad_alloc Cannot allocate memory to hold additional data + * @warning One cannot assume that bucket structure is preserved during copy + */ + void AppendCopyFrom(const BinaryQueue &other); + + /** + * Move bytes from other binary queue to the end of this binary queue. + * This also removes all bytes from other binary queue. + * This method is designed to be as fast as possible (only pointer swaps) + * and is suggested over making copies of binary queues. + * Bucket structure is preserved after operation. + * + * @return none + * @param[in] other Reference to other binary queue to move data from + * @exception std::bad_alloc Cannot allocate memory to hold additional data + */ + void AppendMoveFrom(BinaryQueue &other); + + /** + * Append copy of binary queue to the end of other binary queue + * + * @return none + * @param[in] other Constant reference to other binary queue to copy data to + * @exception std::bad_alloc Cannot allocate memory to hold additional data + * @warning One cannot assume that bucket structure is preserved during copy + */ + void AppendCopyTo(BinaryQueue &other) const; + + /** + * Move bytes from binary queue to the end of other binary queue. + * This also removes all bytes from binary queue. + * This method is designed to be as fast as possible (only pointer swaps) + * and is suggested over making copies of binary queues. + * Bucket structure is preserved after operation. + * + * @return none + * @param[in] other Reference to other binary queue to move data to + * @exception std::bad_alloc Cannot allocate memory to hold additional data + */ + void AppendMoveTo(BinaryQueue &other); + + /** + * Retrieve total size of all data contained in binary queue + * + * @return Number of bytes in binary queue + */ + size_t Size() const; + + /** + * Remove all data from binary queue + * + * @return none + */ + void Clear(); + + /** + * Check if binary queue is empty + * + * @return true if binary queue is empty, false otherwise + */ + bool Empty() const; + + /** + * Remove @a size bytes from beginning of binary queue + * + * @return none + * @param[in] size Number of bytes to remove + * @exception BinaryQueue::Exception::OutOfData Number of bytes is larger + * than available bytes in binary queue + */ + void Consume(size_t size); + + /** + * Retrieve @a bufferSize bytes from beginning of binary queue and copy them + * to user supplied buffer + * + * @return none + * @param[in] buffer Pointer to user buffer to receive bytes + * @param[in] bufferSize Size of user buffer pointed by @a buffer + * @exception BinaryQueue::Exception::OutOfData Number of bytes to flatten + * is larger than available bytes in binary queue + */ + void Flatten(void *buffer, size_t bufferSize) const; + + /** + * Retrieve @a bufferSize bytes from beginning of binary queue, copy them + * to user supplied buffer, and remove from binary queue + * + * @return none + * @param[in] buffer Pointer to user buffer to receive bytes + * @param[in] bufferSize Size of user buffer pointed by @a buffer + * @exception BinaryQueue::Exception::OutOfData Number of bytes to flatten + * is larger than available bytes in binary queue + */ + void FlattenConsume(void *buffer, size_t bufferSize); + + /** + * Visit each buffer with data using visitor object + * + * @return none + * @param[in] visitor Pointer to bucket visitor + * @see BinaryQueue::BucketVisitor + */ + void VisitBuckets(BucketVisitor *visitor) const; + + /** + * IAbstractInput interface + */ + virtual BinaryQueueAutoPtr Read(size_t size); + + /** + * IAbstractOutput interface + */ + virtual size_t Write(const BinaryQueue &buffer, size_t bufferSize); +}; + +/** + * Binary queue auto pointer + */ +typedef std::auto_ptr BinaryQueueAutoPtr; +} // namespace DPL + +#endif // DPL_BINARY_QUEUE_H diff --git a/tests/framework/include/dpl/colors.h b/tests/framework/include/dpl/colors.h new file mode 100644 index 0000000..c7cfd53 --- /dev/null +++ b/tests/framework/include/dpl/colors.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file colors.h + * @author Lukasz Wrzosek (l.wrzosek@samsung.com) + * @version 1.0 + * @brief Some constants with definition of colors for Console + * and html output + */ + +#ifndef DPL_COLORS_H +#define DPL_COLORS_H + +namespace DPL { +namespace Colors { +namespace Text { +extern const char* BOLD_GREEN_BEGIN; +extern const char* BOLD_GREEN_END; +extern const char* PURPLE_BEGIN; +extern const char* PURPLE_END; +extern const char* RED_BEGIN; +extern const char* RED_END; +extern const char* GREEN_BEGIN; +extern const char* GREEN_END; +extern const char* CYAN_BEGIN; +extern const char* CYAN_END; +extern const char* BOLD_RED_BEGIN; +extern const char* BOLD_RED_END; +extern const char* BOLD_YELLOW_BEGIN; +extern const char* BOLD_YELLOW_END; +extern const char* BOLD_GOLD_BEGIN; +extern const char* BOLD_GOLD_END; +extern const char* BOLD_WHITE_BEGIN; +extern const char* BOLD_WHITE_END; +} //namespace Text + +namespace Html { +extern const char* BOLD_GREEN_BEGIN; +extern const char* BOLD_GREEN_END; +extern const char* PURPLE_BEGIN; +extern const char* PURPLE_END; +extern const char* RED_BEGIN; +extern const char* RED_END; +extern const char* GREEN_BEGIN; +extern const char* GREEN_END; +extern const char* CYAN_BEGIN; +extern const char* CYAN_END; +extern const char* BOLD_RED_BEGIN; +extern const char* BOLD_RED_END; +extern const char* BOLD_YELLOW_BEGIN; +extern const char* BOLD_YELLOW_END; +extern const char* BOLD_GOLD_BEGIN; +extern const char* BOLD_GOLD_END; +extern const char* BOLD_WHITE_BEGIN; +extern const char* BOLD_WHITE_END; +} //namespace Html +} //namespace Colors +} //namespace DPL + +#endif /* DPL_COLORS_H */ diff --git a/tests/framework/include/dpl/exception.h b/tests/framework/include/dpl/exception.h new file mode 100644 index 0000000..cdbdc53 --- /dev/null +++ b/tests/framework/include/dpl/exception.h @@ -0,0 +1,385 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file exception.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief Header file for base exception + */ +#ifndef DPL_EXCEPTION_H +#define DPL_EXCEPTION_H + +#include +#include +#include +#include +#include +#include + +namespace DPL { +void LogUnhandledException(const std::string &str); +void LogUnhandledException(const std::string &str, + const char *filename, + int line, + const char *function); +} + +namespace DPL { +class Exception +{ + private: + static unsigned int m_exceptionCount; + static Exception* m_lastException; + static void (*m_terminateHandler)(); + + static void AddRef(Exception* exception) + { + if (!m_exceptionCount) { + m_terminateHandler = std::set_terminate(&TerminateHandler); + } + + ++m_exceptionCount; + m_lastException = exception; + } + + static void UnRef(Exception* e) + { + if (m_lastException == e) { + m_lastException = NULL; + } + + --m_exceptionCount; + + if (!m_exceptionCount) { + std::set_terminate(m_terminateHandler); + m_terminateHandler = NULL; + } + } + + static void TerminateHandler() + { + if (m_lastException != NULL) { + DisplayKnownException(*m_lastException); + abort(); + } else { + DisplayUnknownException(); + abort(); + } + } + + Exception *m_reason; + std::string m_path; + std::string m_function; + int m_line; + + protected: + std::string m_message; + std::string m_className; + + public: + static std::string KnownExceptionToString(const Exception &e) + { + std::ostringstream message; + message << + "\033[1;5;31m\n=== Unhandled DPL exception occurred ===\033[m\n\n"; + message << "\033[1;33mException trace:\033[m\n\n"; + message << e.DumpToString(); + message << "\033[1;31m\n=== Will now abort ===\033[m\n"; + + return message.str(); + } + + static std::string UnknownExceptionToString() + { + std::ostringstream message; + message << + "\033[1;5;31m\n=== Unhandled non-DPL exception occurred ===\033[m\n\n"; + message << "\033[1;31m\n=== Will now abort ===\033[m\n"; + + return message.str(); + } + + static void DisplayKnownException(const Exception& e) + { + LogUnhandledException(KnownExceptionToString(e).c_str()); + } + + static void DisplayUnknownException() + { + LogUnhandledException(UnknownExceptionToString().c_str()); + } + + Exception(const Exception &other) + { + // Deep copy + if (other.m_reason != NULL) { + m_reason = new Exception(*other.m_reason); + } else { + m_reason = NULL; + } + + m_message = other.m_message; + m_path = other.m_path; + m_function = other.m_function; + m_line = other.m_line; + + m_className = other.m_className; + + AddRef(this); + } + + const Exception &operator =(const Exception &other) + { + if (this == &other) { + return *this; + } + + // Deep copy + if (other.m_reason != NULL) { + m_reason = new Exception(*other.m_reason); + } else { + m_reason = NULL; + } + + m_message = other.m_message; + m_path = other.m_path; + m_function = other.m_function; + m_line = other.m_line; + + m_className = other.m_className; + + AddRef(this); + + return *this; + } + + Exception(const char *path, + const char *function, + int line, + const std::string &message) : + m_reason(NULL), + m_path(path), + m_function(function), + m_line(line), + m_message(message) + { + AddRef(this); + } + + Exception(const char *path, + const char *function, + int line, + const Exception &reason, + const std::string &message) : + m_reason(new Exception(reason)), + m_path(path), + m_function(function), + m_line(line), + m_message(message) + { + AddRef(this); + } + + virtual ~Exception() throw() + { + if (m_reason != NULL) { + delete m_reason; + m_reason = NULL; + } + + UnRef(this); + } + + void Dump() const + { + // Show reason first + if (m_reason != NULL) { + m_reason->Dump(); + } + + // Afterward, dump exception + const char *file = strchr(m_path.c_str(), '/'); + + if (file == NULL) { + file = m_path.c_str(); + } else { + ++file; + } + + printf("\033[0;36m[%s:%i]\033[m %s() \033[4;35m%s\033[m: %s\033[m\n", + file, m_line, + m_function.c_str(), + m_className.c_str(), + m_message.empty() ? "" : m_message.c_str()); + } + + std::string DumpToString() const + { + std::string ret; + if (m_reason != NULL) { + ret = m_reason->DumpToString(); + } + + const char *file = strchr(m_path.c_str(), '/'); + + if (file == NULL) { + file = m_path.c_str(); + } else { + ++file; + } + + char buf[1024]; + snprintf(buf, + sizeof(buf), + "\033[0;36m[%s:%i]\033[m %s() \033[4;35m%s\033[m: %s\033[m\n", + file, + m_line, + m_function.c_str(), + m_className.c_str(), + m_message.empty() ? "" : m_message.c_str()); + + buf[sizeof(buf) - 1] = '\n'; + ret += buf; + + return ret; + } + + Exception *GetReason() const + { + return m_reason; + } + + std::string GetPath() const + { + return m_path; + } + + std::string GetFunction() const + { + return m_function; + } + + int GetLine() const + { + return m_line; + } + + std::string GetMessage() const + { + return m_message; + } + + std::string GetClassName() const + { + return m_className; + } +}; +} // namespace DPL + +#define Try try + +#define Throw(ClassName) \ + throw ClassName(__FILE__, __FUNCTION__, __LINE__) + +#define ThrowMsg(ClassName, Message) \ + do \ + { \ + std::ostringstream dplLoggingStream; \ + dplLoggingStream << Message; \ + throw ClassName(__FILE__, __FUNCTION__, __LINE__, dplLoggingStream.str()); \ + } while (0) + +#define ReThrow(ClassName) \ + throw ClassName(__FILE__, __FUNCTION__, __LINE__, _rethrown_exception) + +#define ReThrowMsg(ClassName, Message) \ + throw ClassName(__FILE__, \ + __FUNCTION__, \ + __LINE__, \ + _rethrown_exception, \ + Message) + +#define Catch(ClassName) \ + catch (const ClassName &_rethrown_exception) + +#define DECLARE_EXCEPTION_TYPE(BaseClass, Class) \ + class Class : \ + public BaseClass \ + { \ + public: \ + Class(const char *path, \ + const char *function, \ + int line, \ + const std::string & message = std::string()) : \ + BaseClass(path, function, line, message) \ + { \ + BaseClass::m_className = #Class; \ + } \ + \ + Class(const char *path, \ + const char *function, \ + int line, \ + const DPL::Exception & reason, \ + const std::string & message = std::string()) : \ + BaseClass(path, function, line, reason, message) \ + { \ + BaseClass::m_className = #Class; \ + } \ + }; + +#define UNHANDLED_EXCEPTION_HANDLER_BEGIN try + +#define UNHANDLED_EXCEPTION_HANDLER_END \ + catch (const DPL::Exception &exception) \ + { \ + std::ostringstream msg; \ + msg << DPL::Exception::KnownExceptionToString(exception); \ + DPL::LogUnhandledException(msg.str(), __FILE__, __LINE__, __FUNCTION__); \ + abort(); \ + } \ + catch (std::exception& e) \ + { \ + std::ostringstream msg; \ + msg << e.what(); \ + msg << "\n"; \ + msg << DPL::Exception::UnknownExceptionToString(); \ + DPL::LogUnhandledException(msg.str(), __FILE__, __LINE__, __FUNCTION__); \ + abort(); \ + } \ + catch (...) \ + { \ + std::ostringstream msg; \ + msg << DPL::Exception::UnknownExceptionToString(); \ + DPL::LogUnhandledException(msg.str(), __FILE__, __LINE__, __FUNCTION__); \ + abort(); \ + } + +namespace DPL { +namespace CommonException { +/** + * Internal exception definitions + * + * These should normally not happen. + * Usually, exception trace with internal error includes + * important messages. + */ +DECLARE_EXCEPTION_TYPE(Exception, InternalError) ///< Unexpected error from + // underlying libraries or + // kernel +} +} + +#endif // DPL_EXCEPTION_H diff --git a/tests/framework/include/dpl/log/abstract_log_provider.h b/tests/framework/include/dpl/log/abstract_log_provider.h new file mode 100644 index 0000000..62fa050 --- /dev/null +++ b/tests/framework/include/dpl/log/abstract_log_provider.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file abstract_log_provider.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of abstract log provider + */ +#ifndef DPL_ABSTRACT_LOG_PROVIDER_H +#define DPL_ABSTRACT_LOG_PROVIDER_H + +namespace DPL { +namespace Log { +class AbstractLogProvider +{ + public: + virtual ~AbstractLogProvider() {} + + virtual void Debug(const char *message, + const char *fileName, + int line, + const char *function) = 0; + virtual void Info(const char *message, + const char *fileName, + int line, + const char *function) = 0; + virtual void Warning(const char *message, + const char *fileName, + int line, + const char *function) = 0; + virtual void Error(const char *message, + const char *fileName, + int line, + const char *function) = 0; + virtual void Pedantic(const char *message, + const char *fileName, + int line, + const char *function) = 0; + + protected: + static const char *LocateSourceFileName(const char *filename); +}; +} +} // namespace DPL + +#endif // DPL_ABSTRACT_LOG_PROVIDER_H diff --git a/tests/framework/include/dpl/log/dlog_log_provider.h b/tests/framework/include/dpl/log/dlog_log_provider.h new file mode 100644 index 0000000..1dd4c2d --- /dev/null +++ b/tests/framework/include/dpl/log/dlog_log_provider.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file dlog_log_provider.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of DLOG log provider + */ +#ifndef DPL_DLOG_LOG_PROVIDER_H +#define DPL_DLOG_LOG_PROVIDER_H + +#include +#include +#include + +namespace DPL { +namespace Log { +class DLOGLogProvider : + public AbstractLogProvider +{ + private: + DPL::ScopedFree m_tag; + + static std::string FormatMessage(const char *message, + const char *filename, + int line, + const char *function); + + public: + DLOGLogProvider(); + virtual ~DLOGLogProvider(); + + virtual void Debug(const char *message, + const char *fileName, + int line, + const char *function); + virtual void Info(const char *message, + const char *fileName, + int line, + const char *function); + virtual void Warning(const char *message, + const char *fileName, + int line, + const char *function); + virtual void Error(const char *message, + const char *fileName, + int line, + const char *function); + virtual void Pedantic(const char *message, + const char *fileName, + int line, + const char *function); + + // Set global Tag according to DLOG + void SetTag(const char *tag); +}; +} +} // namespace DPL + +#endif // DPL_DLOG_LOG_PROVIDER_H diff --git a/tests/framework/include/dpl/log/log.h b/tests/framework/include/dpl/log/log.h new file mode 100644 index 0000000..d4d95ed --- /dev/null +++ b/tests/framework/include/dpl/log/log.h @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file log.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of log system + */ +#ifndef DPL_LOG_H +#define DPL_LOG_H + +#include +#include +#include +#include +#include +#include +#include + +namespace DPL { +namespace Log { +/** + * DPL log system + * + * To switch logs into old style, export + * DPL_USE_OLD_STYLE_LOGS before application start + */ +class LogSystem : + private Noncopyable +{ + private: + typedef std::list AbstractLogProviderPtrList; + AbstractLogProviderPtrList m_providers; + + DLOGLogProvider *m_dlogProvider; + OldStyleLogProvider *m_oldStyleProvider; + + bool m_isLoggingEnabled; + + public: + bool IsLoggingEnabled() const; + LogSystem(); + virtual ~LogSystem(); + + /** + * Log debug message + */ + void Debug(const char *message, + const char *filename, + int line, + const char *function); + + /** + * Log info message + */ + void Info(const char *message, + const char *filename, + int line, + const char *function); + + /** + * Log warning message + */ + void Warning(const char *message, + const char *filename, + int line, + const char *function); + + /** + * Log error message + */ + void Error(const char *message, + const char *filename, + int line, + const char *function); + + /** + * Log pedantic message + */ + void Pedantic(const char *message, + const char *filename, + int line, + const char *function); + + /** + * Set default's DLOG provider Tag + */ + void SetTag(const char *tag); + + /** + * Add abstract provider to providers list + * + * @notice Ownership is transfered to LogSystem and deleted upon exit + */ + void AddProvider(AbstractLogProvider *provider); + + /** + * Remove abstract provider from providers list + */ + void RemoveProvider(AbstractLogProvider *provider); +}; + +/* + * Replacement low overhead null logging class + */ +class NullStream +{ + public: + NullStream() {} + + template + NullStream& operator<<(const T&) + { + return *this; + } +}; + +/** + * Log system singleton + */ +typedef Singleton LogSystemSingleton; +} +} // namespace DPL + +// +// Log support +// +// + +#ifdef DPL_LOGS_ENABLED + #define DPL_MACRO_FOR_LOGGING(message, function) \ + do \ + { \ + if (DPL::Log::LogSystemSingleton::Instance().IsLoggingEnabled()) \ + { \ + std::ostringstream platformLog; \ + platformLog << message; \ + DPL::Log::LogSystemSingleton::Instance().function( \ + platformLog.str().c_str(), \ + __FILE__, __LINE__, __FUNCTION__); \ + } \ + } while (0) +#else +/* avoid warnings about unused variables */ + #define DPL_MACRO_FOR_LOGGING(message, function) \ + do { \ + DPL::Log::NullStream ns; \ + ns << message; \ + } while (0) +#endif + +#define LogDebug(message) DPL_MACRO_FOR_LOGGING(message, Debug) +#define LogInfo(message) DPL_MACRO_FOR_LOGGING(message, Info) +#define LogWarning(message) DPL_MACRO_FOR_LOGGING(message, Warning) +#define LogError(message) DPL_MACRO_FOR_LOGGING(message, Error) +#define LogPedantic(message) DPL_MACRO_FOR_LOGGING(message, Pedantic) + +#endif // DPL_LOG_H diff --git a/tests/framework/include/dpl/log/old_style_log_provider.h b/tests/framework/include/dpl/log/old_style_log_provider.h new file mode 100644 index 0000000..70e308a --- /dev/null +++ b/tests/framework/include/dpl/log/old_style_log_provider.h @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file old_style_log_provider.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of old style log provider + */ +#ifndef DPL_OLD_STYLE_LOG_PROVIDER_H +#define DPL_OLD_STYLE_LOG_PROVIDER_H + +#include +#include + +namespace DPL { +namespace Log { +class OldStyleLogProvider : + public AbstractLogProvider +{ + private: + bool m_showDebug; + bool m_showInfo; + bool m_showWarning; + bool m_showError; + bool m_showPedantic; + bool m_printStdErr; + + static std::string FormatMessage(const char *message, + const char *filename, + int line, + const char *function); + + public: + OldStyleLogProvider(bool showDebug, + bool showInfo, + bool showWarning, + bool showError, + bool showPedantic); + OldStyleLogProvider(bool showDebug, + bool showInfo, + bool showWarning, + bool showError, + bool showPedantic, + bool printStdErr); + virtual ~OldStyleLogProvider() {} + + virtual void Debug(const char *message, + const char *fileName, + int line, + const char *function); + virtual void Info(const char *message, + const char *fileName, + int line, + const char *function); + virtual void Warning(const char *message, + const char *fileName, + int line, + const char *function); + virtual void Error(const char *message, + const char *fileName, + int line, + const char *function); + virtual void Pedantic(const char *message, + const char *fileName, + int line, + const char *function); +}; +} +} // namespace DPL + +#endif // DPL_OLD_STYLE_LOG_PROVIDER_H diff --git a/tests/framework/include/dpl/log/secure_log.h b/tests/framework/include/dpl/log/secure_log.h new file mode 100644 index 0000000..d8a0750 --- /dev/null +++ b/tests/framework/include/dpl/log/secure_log.h @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @file secure_log.h + * @author Jihoon Chung(jihoon.chung@samsung.com) + * @version 0.1 + * @brief + */ + +#ifndef DPL_SECURE_LOG_H +#define DPL_SECURE_LOG_H + +#include + +#define COLOR_ERROR "\e[1;31m" +#define COLOR_WARNING "\e[2;31m" +#define COLOR_END "\e[0m" +#define COLOR_TAG "\e[0m" + +// default TAG +#undef LOG_TAG +#define LOG_TAG "WRT_UNDEFINED" + +#ifdef WRT_LOG +#undef LOG_TAG +#define LOG_TAG "WRT" +#undef COLOR_TAG +#define COLOR_TAG "\e[1;32m" +#endif + +#ifdef WRT_BUNDLE_LOG +#undef LOG_TAG +#define LOG_TAG "WRT_BUNDLE" +#undef COLOR_TAG +#define COLOR_TAG "\e[1;34m" +#endif + +#ifdef WRT_PLUGINS_COMMON_LOG +#undef LOG_TAG +#define LOG_TAG "WRT_PLUGINS/COMMON" +#undef COLOR_TAG +#define COLOR_TAG "\e[1;36m" +#endif + +#ifdef WRT_PLUGINS_WIDGET_LOG +#undef LOG_TAG +#define LOG_TAG "WRT_PLUGINS/WIDGET" +#undef COLOR_TAG +#define COLOR_TAG "\e[1;35m" +#endif + +#ifdef WRT_INSTALLER_LOG +#undef LOG_TAG +#define LOG_TAG "WRT_INSTALLER" +#undef COLOR_TAG +#define COLOR_TAG "\e[1;32m" +#endif + +#ifndef SECURE_SLOGD +#define SECURE_SLOGD(fmt, arg...) SLOGD(fmt,##arg) +#endif + +#ifndef SECURE_SLOGW +#define SECURE_SLOGW(fmt, arg...) SLOGW(fmt,##arg) +#endif + +#ifndef SECURE_SLOGE +#define SECURE_SLOGE(fmt, arg...) SLOGE(fmt,##arg) +#endif + +#define _D(fmt, arg ...) SECURE_SLOGD(COLOR_TAG fmt COLOR_END,##arg) +#define _W(fmt, arg ...) SECURE_SLOGW(COLOR_WARNING fmt COLOR_END,##arg) +#define _E(fmt, arg ...) SECURE_SLOGE(COLOR_ERROR fmt COLOR_END,##arg) + +#endif // DPL_SECURE_LOG_H + diff --git a/tests/framework/include/dpl/noncopyable.h b/tests/framework/include/dpl/noncopyable.h new file mode 100644 index 0000000..98d57dd --- /dev/null +++ b/tests/framework/include/dpl/noncopyable.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file noncopyable + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of noncopyable + */ +#ifndef DPL_NONCOPYABLE_H +#define DPL_NONCOPYABLE_H + +namespace DPL { +class Noncopyable +{ + private: + Noncopyable(const Noncopyable &); + const Noncopyable &operator=(const Noncopyable &); + + public: + Noncopyable(); + virtual ~Noncopyable(); +}; +} // namespace DPL + +#endif // DPL_NONCOPYABLE_H diff --git a/tests/framework/include/dpl/noreturn.h b/tests/framework/include/dpl/noreturn.h new file mode 100644 index 0000000..93845b7 --- /dev/null +++ b/tests/framework/include/dpl/noreturn.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file noreturn.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of noreturn + */ +#ifndef DPL_NORETURN_H +#define DPL_NORETURN_H + +#define DPL_NORETURN __attribute__((__noreturn__)) + +#endif // DPL_NORETURN_H diff --git a/tests/framework/include/dpl/scoped_fclose.h b/tests/framework/include/dpl/scoped_fclose.h new file mode 100644 index 0000000..e8deb15 --- /dev/null +++ b/tests/framework/include/dpl/scoped_fclose.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*! + * @file scoped_fclose.h + * @author Piotr Marcinkiewicz (p.marcinkiew@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of scoped fclose RAII + */ +#ifndef DPL_SCOPED_FCLOSE_H +#define DPL_SCOPED_FCLOSE_H + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace DPL { +struct ScopedFClosePolicy +{ + typedef FILE* Type; + static Type NullValue() + { + return NULL; + } + static void Destroy(Type file) + { + if (file != NULL) { + // Try to flush first + if (TEMP_FAILURE_RETRY(fflush(file)) != 0) { + std::string errString = strerror(errno); + LogPedantic("Failed to fflush scoped fclose error: " + << errString); + } + + // fclose cannot be retried, try to close once + if (fclose(file) != 0) { + std::string errString = strerror(errno); + LogPedantic("Failed scoped fclose error: " << errString); + } + } + } +}; + +class ScopedFClose : public ScopedResource +{ + typedef ScopedFClosePolicy Policy; + typedef ScopedResource BaseType; + + public: + explicit ScopedFClose(FILE* argFileStream = Policy::NullValue()) : + BaseType(argFileStream) + {} +}; +} // namespace DPL + +#endif // DPL_SCOPED_FCLOSE_H diff --git a/tests/framework/include/dpl/scoped_free.h b/tests/framework/include/dpl/scoped_free.h new file mode 100644 index 0000000..7bebe39 --- /dev/null +++ b/tests/framework/include/dpl/scoped_free.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/*! + * @file scoped_free.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of scoped free RAII + */ + +#ifndef DPL_SCOPED_FREE_H +#define DPL_SCOPED_FREE_H + +#include +#include + +#include + +namespace DPL { +template +struct ScopedFreePolicy +{ + typedef Class* Type; + static Type NullValue() + { + return NULL; + } + static void Destroy(Type ptr) + { + free(ptr); + } +}; + +template +class ScopedFree : public ScopedResource > +{ + typedef ScopedFreePolicy Policy; + typedef ScopedResource BaseType; + + public: + explicit ScopedFree(Memory *ptr = Policy::NullValue()) : BaseType(ptr) { } +}; +} // namespace DPL + +#endif // DPL_SCOPED_FREE_H diff --git a/tests/framework/include/dpl/scoped_resource.h b/tests/framework/include/dpl/scoped_resource.h new file mode 100644 index 0000000..63287da --- /dev/null +++ b/tests/framework/include/dpl/scoped_resource.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file scoped_resource.h + * @author Piotr Marcinkiewicz (p.marcinkiew@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of scoped resource pattern + */ +#ifndef DPL_SCOPED_RESOURCE_H +#define DPL_SCOPED_RESOURCE_H + +#include + +namespace DPL { +template +class ScopedResource : + private Noncopyable +{ + public: + typedef typename ClassPolicy::Type ValueType; + typedef ScopedResource ThisType; + + protected: + ValueType m_value; + + public: + explicit ScopedResource(ValueType value) : m_value(value) { } + + ~ScopedResource() + { + ClassPolicy::Destroy(m_value); + } + + ValueType Get() const + { + return m_value; + } + + void Reset(ValueType value = ClassPolicy::NullValue()) + { + ClassPolicy::Destroy(m_value); + m_value = value; + } + + ValueType Release() + { + ValueType value = m_value; + m_value = ClassPolicy::NullValue(); + return value; + } + typedef ValueType ThisType::*UnknownBoolType; + + operator UnknownBoolType() const + { + return m_value == ClassPolicy::NullValue() ? + 0 : //0 is valid here because it converts to false + &ThisType::m_value; //it converts to true + } + + bool operator !() const + { + return m_value == ClassPolicy::NullValue(); + } +}; +} // namespace DPL + +#endif // DPL_SCOPED_RESOURCE_H diff --git a/tests/framework/include/dpl/singleton.h b/tests/framework/include/dpl/singleton.h new file mode 100644 index 0000000..fc118d5 --- /dev/null +++ b/tests/framework/include/dpl/singleton.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file singleton.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of singleton + */ +#ifndef DPL_SINGLETON_H +#define DPL_SINGLETON_H + +#include + +namespace DPL { +template +class Singleton : + private Class +{ + // + // Note: + // + // To remove posibility of instantiating directly Class, + // make Class' default constructor protected + // + + private: + Singleton() + {} + + static Singleton &InternalInstance(); + + public: + virtual ~Singleton() + {} + + static Class &Instance(); +}; +} // namespace DPL + +#endif // DPL_SINGLETON_H diff --git a/tests/framework/include/dpl/singleton_impl.h b/tests/framework/include/dpl/singleton_impl.h new file mode 100644 index 0000000..12dbf32 --- /dev/null +++ b/tests/framework/include/dpl/singleton_impl.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file singleton_impl.h + * @author Lukasz Wrzosek (l.wrzosek@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of singleton + */ +#ifndef DPL_SINGLETON_IMPL_H +#define DPL_SINGLETON_IMPL_H + +/* + * WARNING! + * + * If some singleton's implementation uses another singletons implementation, + * those templates make the second singleton a dubleton. Be warned. Try to use + * singleton_safe_impl.h if possible. + */ + +namespace DPL { +template +Singleton& Singleton::InternalInstance() +{ + static Singleton instance; + return instance; +} + +template +Class &Singleton::Instance() +{ + Singleton& instance = Singleton::InternalInstance(); + return instance; +} +} // namespace DPL + +#define IMPLEMENT_SINGLETON(Type) \ + template DPL::Singleton&DPL::Singleton::InternalInstance(); \ + template Type & DPL::Singleton::Instance(); \ + +#endif // DPL_SINGLETON_IMPL_H diff --git a/tests/framework/include/dpl/singleton_safe_impl.h b/tests/framework/include/dpl/singleton_safe_impl.h new file mode 100644 index 0000000..c8923b7 --- /dev/null +++ b/tests/framework/include/dpl/singleton_safe_impl.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file singleton_safe_impl.h + * @author Tomasz Swierczek (t.swierczek@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of singleton + */ +#ifndef DPL_SINGLETON_SAFE_IMPL_H +#define DPL_SINGLETON_SAFE_IMPL_H + +#define IMPLEMENT_SAFE_SINGLETON(Class) \ + namespace DPL { \ + template<> \ + Singleton&Singleton::InternalInstance() \ + { \ + static Singleton instance; \ + return instance; \ + } \ + \ + template<> \ + Class & Singleton::Instance() \ + { \ + Singleton& instance = Singleton::InternalInstance(); \ + return instance; \ + } \ + \ + template Singleton&Singleton::InternalInstance(); \ + template Class & Singleton::Instance(); \ + } // namespace DPL + +#endif // DPL_SINGLETON_SAFE_IMPL_H diff --git a/tests/framework/include/dpl/test/test_results_collector.h b/tests/framework/include/dpl/test/test_results_collector.h new file mode 100644 index 0000000..cb29921 --- /dev/null +++ b/tests/framework/include/dpl/test/test_results_collector.h @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file test_results_collector.h + * @author Lukasz Wrzosek (l.wrzosek@samsung.com) + * @version 1.0 + * @brief Header file with declaration of TestResultsCollectorBase + */ + +#ifndef DPL_TEST_RESULTS_COLLECTOR_H +#define DPL_TEST_RESULTS_COLLECTOR_H + +#include +#include +#include +#include +#include +#include +#include + +namespace DPL { +namespace Test { +class TestResultsCollectorBase; +typedef std::shared_ptr +TestResultsCollectorBasePtr; + +class TestResultsCollectorBase : + private DPL::Noncopyable +{ + public: + typedef TestResultsCollectorBase* (*CollectorConstructorFunc)(); + typedef std::list TestCaseIdList; + struct FailStatus + { + enum Type + { + NONE, + FAILED, + IGNORED, + INTERNAL + }; + }; + + virtual ~TestResultsCollectorBase() {} + + virtual bool Configure() + { + return true; + } + virtual void Start() { } + virtual void Finish() { } + virtual void CollectCurrentTestGroupName(const std::string& /*groupName*/) + {} + + virtual void CollectTestsCasesList(const TestCaseIdList& /*list*/) {} + virtual void CollectResult(const std::string& id, + const std::string& description, + const FailStatus::Type status = FailStatus::NONE, + const std::string& reason = "", + const bool& isPerformanceTest = false, + const std::chrono::system_clock::duration& performanceTime = std::chrono::microseconds::zero(), + const std::chrono::system_clock::duration& performanceMaxTime = std::chrono::microseconds::zero()) = 0; + virtual std::string CollectorSpecificHelp() const + { + return ""; + } + virtual bool ParseCollectorSpecificArg (const std::string& /*arg*/) + { + return false; + } + + static TestResultsCollectorBase* Create(const std::string& name); + static void RegisterCollectorConstructor( + const std::string& name, + CollectorConstructorFunc + constructor); + static std::vector GetCollectorsNames(); + + private: + typedef std::map ConstructorsMap; + static ConstructorsMap m_constructorsMap; +}; +} +} + +#endif /* DPL_TEST_RESULTS_COLLECTOR_H */ diff --git a/tests/framework/include/dpl/test/test_runner.h b/tests/framework/include/dpl/test/test_runner.h new file mode 100644 index 0000000..4893ee5 --- /dev/null +++ b/tests/framework/include/dpl/test/test_runner.h @@ -0,0 +1,282 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file test_runner.h + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @author Lukasz Wrzosek (l.wrzosek@samsung.com) + * @version 1.0 + * @brief This file is the header file of test runner + */ +#ifndef DPL_TEST_RUNNER_H +#define DPL_TEST_RUNNER_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace DPL { +namespace Test { +class TestRunner +{ + typedef std::map + TestResultsCollectors; + TestResultsCollectors m_collectors; + + std::string m_startTestId; + bool m_runIgnored; + + public: + TestRunner() : + m_currentTestCase(NULL) + , m_terminate(false) + , m_allowChildLogs(false) + {} + + void beginPerformanceTestTime(std::chrono::system_clock::duration maxTimeInMicroseconds); + void endPerformanceTestTime(); + void getCurrentTestCasePerformanceResult(bool& isPerformanceTest, + std::chrono::system_clock::duration& result, + std::chrono::system_clock::duration& resultMax); + void setCurrentTestCasePerformanceResult(bool isPerformanceTest, + std::chrono::system_clock::duration result, + std::chrono::system_clock::duration resultMax); + + typedef void (*TestCase)(); + + private: + struct TestCaseStruct + { + std::string name; + TestCase proc; + + bool m_isPerformanceTest; + std::chrono::system_clock::time_point m_performanceTestStartTime; + std::chrono::system_clock::duration m_performanceTestDurationTime; + std::chrono::system_clock::duration m_performanceMaxTime; + + bool operator <(const TestCaseStruct &other) const + { + return name < other.name; + } + + bool operator ==(const TestCaseStruct &other) const + { + return name == other.name; + } + + TestCaseStruct(const std::string &n, TestCase p) : + name(n), + proc(p), + m_isPerformanceTest(false) + {} + }; + + typedef std::list TestCaseStructList; + typedef std::map TestCaseGroupMap; + TestCaseGroupMap m_testGroups; + + TestCaseStruct * m_currentTestCase; + + typedef std::set SelectedTestNameSet; + SelectedTestNameSet m_selectedTestNamesSet; + typedef std::set SelectedTestGroupSet; + SelectedTestGroupSet m_selectedTestGroupSet; + std::string m_currentGroup; + + DPL::Atomic m_totalAssertions; + + // Terminate without any logs. + // Some test requires to call fork function. + // Child process must not produce any logs and should die quietly. + bool m_terminate; + bool m_allowChildLogs; + + void Banner(); + void InvalidArgs(const std::string& message = "Invalid arguments!"); + void Usage(); + + bool filterGroupsByXmls(const std::vector & files); + bool filterByXML(std::map & casesMap); + void normalizeXMLTag(std::string& str, const std::string& testcase); + + enum Status { FAILED, IGNORED, PASS }; + + Status RunTestCase(const TestCaseStruct& testCase); + + void setCurrentTestCase(TestCaseStruct* testCase); + TestCaseStruct *getCurrentTestCase(); + + void RunTests(); + + void CollectResult(const std::string& id, + const std::string& description, + const TestResultsCollectorBase::FailStatus::Type status + = TestResultsCollectorBase::FailStatus::NONE, + const std::string& reason = std::string(), + const bool& isPerformanceTest = false, + const std::chrono::system_clock::duration& performanceTime = std::chrono::microseconds::zero(), + const std::chrono::system_clock::duration& performanceMaxTime = std::chrono::microseconds::zero()); + + public: + class TestFailed + { + private: + std::string m_message; + + public: + TestFailed() + {} + + //! \brief Failed test message creator + //! + //! \param[in] aTest string for tested expression + //! \param[in] aFile source file name + //! \param[in] aLine source file line + //! \param[in] aMessage error message + TestFailed(const char* aTest, + const char* aFile, + int aLine, + const std::string &aMessage); + + TestFailed(const std::string &message); + + std::string GetMessage() const + { + return m_message; + } + }; + + class Ignored + { + private: + std::string m_message; + + public: + Ignored() + {} + + Ignored(const std::string &message) : + m_message(message) + {} + + std::string GetMessage() const + { + return m_message; + } + }; + + void MarkAssertion(); + + void RegisterTest(const char *testName, TestCase proc); + void InitGroup(const char* name); + + int ExecTestRunner(int argc, char *argv[]); + typedef std::vector ArgsList; + int ExecTestRunner(ArgsList args); + bool getRunIgnored() const; + // The runner will terminate as soon as possible (after current test). + void Terminate(); + bool GetAllowChildLogs(); +}; + +typedef DPL::Singleton TestRunnerSingleton; +} +} // namespace DPL + +#define RUNNER_TEST_GROUP_INIT(GroupName) \ + static int Static##GroupName##Init() \ + { \ + DPL::Test::TestRunnerSingleton::Instance().InitGroup(#GroupName); \ + return 0; \ + } \ + const int DPL_UNUSED Static##GroupName##InitVar = \ + Static##GroupName##Init(); + +#define RUNNER_TEST(Proc) \ + void Proc(); \ + static int Static##Proc##Init() \ + { \ + DPL::Test::TestRunnerSingleton::Instance().RegisterTest(#Proc, &Proc); \ + return 0; \ + } \ + const int DPL_UNUSED Static##Proc##InitVar = Static##Proc##Init(); \ + void Proc() + +//! \brief Returns base name for path + +#define RUNNER_ASSERT_MSG(test, message) \ + do \ + { \ + DPL::Test::TestRunnerSingleton::Instance().MarkAssertion(); \ + \ + if (!(test)) \ + { \ + std::ostringstream assertMsg; \ + assertMsg << message; \ + throw DPL::Test::TestRunner::TestFailed(#test, \ + __FILE__, \ + __LINE__, \ + assertMsg.str()); \ + } \ + } while (0) + +#define RUNNER_ASSERT(test) RUNNER_ASSERT_MSG(test, "") + +#define RUNNER_FAIL RUNNER_ASSERT(false) + +#define RUNNER_IGNORED_MSG(message) do { std::ostringstream assertMsg; \ + assertMsg << message; \ + throw DPL::Test::TestRunner::Ignored( \ + assertMsg.str()); \ +} while (0) + +/* + * Use these macros to do the time measurement. The first macro will start time measurement, + * the second will gather the result. These macros can be used only once per test-case. + * The result of time measurement will be displayed only if the test will pass. + * Notice that these macros will work only if will be used in parent process. If these + * macros will be used in child process then there will be no time measure results printed. + * This macro in multiprocess tests has effect only if used in parent process. This macro + * used in child process in multiprocess test has no effect. + * The precision of measurement is 1 microsecond - the smallest time value that can be + * measured is 0.000001s. + * The time measure results will be printed only specific output format: + * - text + * - html + * - xml + * - csv + * In TAP format performance result will not be displayed. + */ +#define RUNNER_PERF_TEST_BEGIN(maxTime) \ + do { \ + DPL::Test::TestRunnerSingleton::Instance().beginPerformanceTestTime( \ + std::chrono::microseconds{static_cast(maxTime*1000000.0)}); \ + } while (0) + +#define RUNNER_PERF_TEST_END() \ + do { \ + DPL::Test::TestRunnerSingleton::Instance().endPerformanceTestTime(); \ + } while (0) + +#endif // DPL_TEST_RUNNER_H diff --git a/tests/framework/include/dpl/test/test_runner_child.h b/tests/framework/include/dpl/test/test_runner_child.h new file mode 100644 index 0000000..d1e4b1c --- /dev/null +++ b/tests/framework/include/dpl/test/test_runner_child.h @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file test_runner_child.h + * @author Bartlomiej Grzelewski (b.grzelewski@samsung.com) + * @version 1.0 + * @brief This file is the header file of test runner + */ +#ifndef DPL_TEST_RUNNER_CHILD_H +#define DPL_TEST_RUNNER_CHILD_H + +#include + +namespace DPL { +namespace Test { + +class PipeWrapper : DPL::Noncopyable +{ + public: + enum Usage { + READONLY, + WRITEONLY + }; + + enum Status { + SUCCESS, + TIMEOUT, + ERROR + }; + + PipeWrapper(); + + bool isReady(); + + void setUsage(Usage usage); + + virtual ~PipeWrapper(); + + Status send(int code, std::string &message); + Status sendTime(int code, + std::chrono::system_clock::duration time, + std::chrono::system_clock::duration timeMax); + + Status receive(int &code, + int &msgType, + std::string &data, + std::chrono::system_clock::duration &time, + std::chrono::system_clock::duration &timeMax, + time_t deadline); + + void closeAll(); + + protected: + + std::string toBinaryString(int data); + std::string toBinaryString(std::chrono::system_clock::duration data); + + void closeHelp(int desc); + + Status writeHelp(const void *buffer, int size); + + Status readHelp(void *buf, int size, time_t deadline); + + static const int PIPE_CLOSED = -1; + + int m_pipefd[2]; +}; + +void RunChildProc(TestRunner::TestCase procChild); +} // namespace Test +} // namespace DPL + +#define RUNNER_CHILD_TEST(Proc) \ + void Proc(); \ + void Proc##Child(); \ + static int Static##Proc##Init() \ + { \ + DPL::Test::TestRunnerSingleton::Instance().RegisterTest(#Proc, &Proc); \ + return 0; \ + } \ + const int DPL_UNUSED Static##Proc##InitVar = Static##Proc##Init(); \ + void Proc(){ \ + DPL::Test::RunChildProc(&Proc##Child); \ + } \ + void Proc##Child() + +#endif // DPL_TEST_RUNNER_CHILD_H diff --git a/tests/framework/include/dpl/test/test_runner_multiprocess.h b/tests/framework/include/dpl/test/test_runner_multiprocess.h new file mode 100644 index 0000000..279b5ef --- /dev/null +++ b/tests/framework/include/dpl/test/test_runner_multiprocess.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file test_runner_multiprocess.h + * @author Marcin Niesluchowski (m.niesluchow@samsung.com) + * @version 1.0 + * @brief This file is the header file of multiprocess test runner + */ +#ifndef DPL_TEST_RUNNER_MULTIPROCESS_H +#define DPL_TEST_RUNNER_MULTIPROCESS_H + +#include + +namespace DPL { +namespace Test { + +class SimplePipeWrapper : + public PipeWrapper +{ + public: + SimplePipeWrapper(); + + virtual ~SimplePipeWrapper(); + + Status send(std::string &message); + Status receive(std::string &data, bool &empty, time_t deadline); +}; + +void RunMultiProc(TestRunner::TestCase procMulti); +} // namespace Test +} // namespace DPL + +#define RUNNER_MULTIPROCESS_TEST(Proc) \ + void Proc(); \ + void Proc##Multi(); \ + static int Static##Proc##Init() \ + { \ + DPL::Test::TestRunnerSingleton::Instance().RegisterTest(#Proc, &Proc); \ + return 0; \ + } \ + const int DPL_UNUSED Static##Proc##InitVar = Static##Proc##Init(); \ + void Proc(){ \ + DPL::Test::RunMultiProc(&Proc##Multi); \ + } \ + void Proc##Multi() + +#endif // DPL_TEST_RUNNER_MULTIPROCESS_H diff --git a/tests/framework/src/abstract_log_provider.cpp b/tests/framework/src/abstract_log_provider.cpp new file mode 100644 index 0000000..a03f8a0 --- /dev/null +++ b/tests/framework/src/abstract_log_provider.cpp @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file abstract_log_provider.cpp + * @author Pawel Sikorski (p.sikorski@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of abstract log provider + */ +#include +#include +#include + +namespace DPL { +namespace Log { +const char *AbstractLogProvider::LocateSourceFileName(const char *filename) +{ + const char *ptr = strrchr(filename, '/'); + return ptr != NULL ? ptr + 1 : filename; +} +} +} diff --git a/tests/framework/src/assert.cpp b/tests/framework/src/assert.cpp new file mode 100644 index 0000000..636a7cf --- /dev/null +++ b/tests/framework/src/assert.cpp @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file assert.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of assert + */ +#include +#include +#include +#include +#include +#include + +namespace DPL { +void AssertProc(const char *condition, + const char *file, + int line, + const char *function) +{ +#define INTERNAL_LOG(message) \ + do \ + { \ + std::ostringstream platformLog; \ + platformLog << message; \ + DPL::Log::LogSystemSingleton::Instance().Pedantic( \ + platformLog.str().c_str(), \ + __FILE__, __LINE__, __FUNCTION__); \ + } \ + while (0) + + // Try to log failed assertion to log system + Try + { + INTERNAL_LOG( + "################################################################################"); + INTERNAL_LOG( + "### DPL assertion failed! ###"); + INTERNAL_LOG( + "################################################################################"); + INTERNAL_LOG("### Condition: " << condition); + INTERNAL_LOG("### File: " << file); + INTERNAL_LOG("### Line: " << line); + INTERNAL_LOG("### Function: " << function); + INTERNAL_LOG( + "################################################################################"); + } catch (Exception) { + // Just ignore possible double errors + } + + // Fail with c-library abort + abort(); +} +} // namespace DPL diff --git a/tests/framework/src/atomic.cpp b/tests/framework/src/atomic.cpp new file mode 100644 index 0000000..2f50074 --- /dev/null +++ b/tests/framework/src/atomic.cpp @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file atomic.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of atomic + */ +#include +#include + +namespace DPL { +Atomic::Atomic(ValueType value) : + m_value(value) +{} + +Atomic::ValueType Atomic::ExchangeAndAdd(ValueType value) +{ + return g_atomic_int_add(const_cast(&m_value), value); +} + +bool Atomic::CompareAndExchange(ValueType oldValue, ValueType newValue) +{ + return g_atomic_int_compare_and_exchange(const_cast(&m_value), + oldValue, + newValue); +} + +bool Atomic::operator--() +{ + return g_atomic_int_dec_and_test(const_cast(&m_value)) != TRUE; +} + +void Atomic::operator++() +{ + g_atomic_int_inc(const_cast(&m_value)); +} + +Atomic::operator ValueType() const +{ + return g_atomic_int_get(const_cast(&m_value)); +} +} // namespace DPL diff --git a/tests/framework/src/binary_queue.cpp b/tests/framework/src/binary_queue.cpp new file mode 100644 index 0000000..2234c8f --- /dev/null +++ b/tests/framework/src/binary_queue.cpp @@ -0,0 +1,312 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file binary_queue.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of binary queue + */ +#include +#include +#include +#include +#include +#include +#include +#include + +namespace DPL { +BinaryQueue::BinaryQueue() : + m_size(0) +{} + +BinaryQueue::BinaryQueue(const BinaryQueue &other) : + m_size(0) +{ + AppendCopyFrom(other); +} + +BinaryQueue::~BinaryQueue() +{ + // Remove all remainig buckets + Clear(); +} + +const BinaryQueue &BinaryQueue::operator=(const BinaryQueue &other) +{ + if (this != &other) { + Clear(); + AppendCopyFrom(other); + } + + return *this; +} + +void BinaryQueue::AppendCopyFrom(const BinaryQueue &other) +{ + // To speed things up, always copy as one bucket + void *bufferCopy = malloc(other.m_size); + + if (bufferCopy == NULL) { + throw std::bad_alloc(); + } + + try { + other.Flatten(bufferCopy, other.m_size); + AppendUnmanaged(bufferCopy, other.m_size, &BufferDeleterFree, NULL); + } catch (const std::bad_alloc &) { + // Free allocated memory + free(bufferCopy); + throw; + } +} + +void BinaryQueue::AppendMoveFrom(BinaryQueue &other) +{ + // Copy all buckets + std::copy(other.m_buckets.begin(), + other.m_buckets.end(), std::back_inserter(m_buckets)); + m_size += other.m_size; + + // Clear other, but do not free memory + other.m_buckets.clear(); + other.m_size = 0; +} + +void BinaryQueue::AppendCopyTo(BinaryQueue &other) const +{ + other.AppendCopyFrom(*this); +} + +void BinaryQueue::AppendMoveTo(BinaryQueue &other) +{ + other.AppendMoveFrom(*this); +} + +void BinaryQueue::Clear() +{ + std::for_each(m_buckets.begin(), m_buckets.end(), &DeleteBucket); + m_buckets.clear(); + m_size = 0; +} + +void BinaryQueue::AppendCopy(const void* buffer, size_t bufferSize) +{ + // Create data copy with malloc/free + void *bufferCopy = malloc(bufferSize); + + // Check if allocation succeded + if (bufferCopy == NULL) { + throw std::bad_alloc(); + } + + // Copy user data + memcpy(bufferCopy, buffer, bufferSize); + + try { + // Try to append new bucket + AppendUnmanaged(bufferCopy, bufferSize, &BufferDeleterFree, NULL); + } catch (const std::bad_alloc &) { + // Free allocated memory + free(bufferCopy); + throw; + } +} + +void BinaryQueue::AppendUnmanaged(const void* buffer, + size_t bufferSize, + BufferDeleter deleter, + void* userParam) +{ + // Do not attach empty buckets + if (bufferSize == 0) { + deleter(buffer, bufferSize, userParam); + return; + } + + // Just add new bucket with selected deleter + m_buckets.push_back(new Bucket(buffer, bufferSize, deleter, userParam)); + + // Increase total queue size + m_size += bufferSize; +} + +size_t BinaryQueue::Size() const +{ + return m_size; +} + +bool BinaryQueue::Empty() const +{ + return m_size == 0; +} + +void BinaryQueue::Consume(size_t size) +{ + // Check parameters + if (size > m_size) { + Throw(Exception::OutOfData); + } + + size_t bytesLeft = size; + + // Consume data and/or remove buckets + while (bytesLeft > 0) { + // Get consume size + size_t count = std::min(bytesLeft, m_buckets.front()->left); + + m_buckets.front()->ptr = + static_cast(m_buckets.front()->ptr) + count; + m_buckets.front()->left -= count; + bytesLeft -= count; + m_size -= count; + + if (m_buckets.front()->left == 0) { + DeleteBucket(m_buckets.front()); + m_buckets.pop_front(); + } + } +} + +void BinaryQueue::Flatten(void *buffer, size_t bufferSize) const +{ + // Check parameters + if (bufferSize == 0) { + return; + } + + if (bufferSize > m_size) { + Throw(Exception::OutOfData); + } + + size_t bytesLeft = bufferSize; + void *ptr = buffer; + BucketList::const_iterator bucketIterator = m_buckets.begin(); + Assert(m_buckets.end() != bucketIterator); + + // Flatten data + while (bytesLeft > 0) { + // Get consume size + size_t count = std::min(bytesLeft, (*bucketIterator)->left); + + // Copy data to user pointer + memcpy(ptr, (*bucketIterator)->ptr, count); + + // Update flattened bytes count + bytesLeft -= count; + ptr = static_cast(ptr) + count; + + // Take next bucket + ++bucketIterator; + } +} + +void BinaryQueue::FlattenConsume(void *buffer, size_t bufferSize) +{ + // FIXME: Optimize + Flatten(buffer, bufferSize); + Consume(bufferSize); +} + +void BinaryQueue::DeleteBucket(BinaryQueue::Bucket *bucket) +{ + delete bucket; +} + +void BinaryQueue::BufferDeleterFree(const void* data, + size_t dataSize, + void* userParam) +{ + (void)dataSize; + (void)userParam; + + // Default free deleter + free(const_cast(data)); +} + +BinaryQueue::Bucket::Bucket(const void* data, + size_t dataSize, + BufferDeleter dataDeleter, + void* userParam) : + buffer(data), + ptr(data), + size(dataSize), + left(dataSize), + deleter(dataDeleter), + param(userParam) +{ + Assert(data != NULL); + Assert(deleter != NULL); +} + +BinaryQueue::Bucket::~Bucket() +{ + // Invoke deleter on bucket data + deleter(buffer, size, param); +} + +BinaryQueue::BucketVisitor::~BucketVisitor() +{} + +BinaryQueue::BucketVisitorCall::BucketVisitorCall(BucketVisitor *visitor) : + m_visitor(visitor) +{} + +BinaryQueue::BucketVisitorCall::~BucketVisitorCall() +{} + +void BinaryQueue::BucketVisitorCall::operator()(Bucket *bucket) const +{ + m_visitor->OnVisitBucket(bucket->ptr, bucket->left); +} + +void BinaryQueue::VisitBuckets(BucketVisitor *visitor) const +{ + Assert(visitor != NULL); + + // Visit all buckets + std::for_each(m_buckets.begin(), m_buckets.end(), BucketVisitorCall(visitor)); +} + +BinaryQueueAutoPtr BinaryQueue::Read(size_t size) +{ + // Simulate input stream + size_t available = std::min(size, m_size); + + ScopedFree bufferCopy(malloc(available)); + + if (!bufferCopy) { + throw std::bad_alloc(); + } + + BinaryQueueAutoPtr result(new BinaryQueue()); + + Flatten(bufferCopy.Get(), available); + result->AppendUnmanaged( + bufferCopy.Get(), available, &BufferDeleterFree, NULL); + bufferCopy.Release(); + Consume(available); + + return result; +} + +size_t BinaryQueue::Write(const BinaryQueue &buffer, size_t bufferSize) +{ + // Simulate output stream + AppendCopyFrom(buffer); + return bufferSize; +} +} // namespace DPL diff --git a/tests/framework/src/colors.cpp b/tests/framework/src/colors.cpp new file mode 100644 index 0000000..0b2fcd4 --- /dev/null +++ b/tests/framework/src/colors.cpp @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file colors.cpp + * @author Lukasz Wrzosek (l.wrzosek@samsung.com) + * @version 1.0 + * @brief Some constants with definition of colors for Console + * and html output + */ +#include +#include + +namespace DPL { +namespace Colors { +namespace Text { +const char* BOLD_GREEN_BEGIN = "\033[1;32m"; +const char* BOLD_GREEN_END = "\033[m"; +const char* RED_BEGIN = "\033[0;31m"; +const char* RED_END = "\033[m"; +const char* PURPLE_BEGIN = "\033[0;35m"; +const char* PURPLE_END = "\033[m"; +const char* GREEN_BEGIN = "\033[0;32m"; +const char* GREEN_END = "\033[m"; +const char* CYAN_BEGIN = "\033[0;36m"; +const char* CYAN_END = "\033[m"; +const char* BOLD_RED_BEGIN = "\033[1;31m"; +const char* BOLD_RED_END = "\033[m"; +const char* BOLD_YELLOW_BEGIN = "\033[1;33m"; +const char* BOLD_YELLOW_END = "\033[m"; +const char* BOLD_GOLD_BEGIN = "\033[0;33m"; +const char* BOLD_GOLD_END = "\033[m"; +const char* BOLD_WHITE_BEGIN = "\033[1;37m"; +const char* BOLD_WHITE_END = "\033[m"; +} //namespace Text + +namespace Html { +const char* BOLD_GREEN_BEGIN = ""; +const char* BOLD_GREEN_END = ""; +const char* PURPLE_BEGIN = ""; +const char* PURPLE_END = ""; +const char* RED_BEGIN = ""; +const char* RED_END = ""; +const char* GREEN_BEGIN = ""; +const char* GREEN_END = ""; +const char* CYAN_BEGIN = ""; +const char* CYAN_END = ""; +const char* BOLD_RED_BEGIN = ""; +const char* BOLD_RED_END = ""; +const char* BOLD_YELLOW_BEGIN = ""; +const char* BOLD_YELLOW_END = ""; +const char* BOLD_GOLD_BEGIN = ""; +const char* BOLD_GOLD_END = ""; +const char* BOLD_WHITE_BEGIN = ""; +const char* BOLD_WHITE_END = ""; +} //namespace Html +} //namespace Colors +} //namespace DPL diff --git a/tests/framework/src/dlog_log_provider.cpp b/tests/framework/src/dlog_log_provider.cpp new file mode 100644 index 0000000..573ee89 --- /dev/null +++ b/tests/framework/src/dlog_log_provider.cpp @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file dlog_log_provider.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of DLOG log provider + */ +#include +#include +#include +#include +#include + +namespace DPL { +namespace Log { +std::string DLOGLogProvider::FormatMessage(const char *message, + const char *filename, + int line, + const char *function) +{ + std::ostringstream val; + + val << std::string("[") << + LocateSourceFileName(filename) << std::string(":") << line << + std::string("] ") << function << std::string("(): ") << message; + + return val.str(); +} + +DLOGLogProvider::DLOGLogProvider() +{} + +DLOGLogProvider::~DLOGLogProvider() +{} + +void DLOGLogProvider::SetTag(const char *tag) +{ + m_tag.Reset(strdup(tag)); +} + +void DLOGLogProvider::Debug(const char *message, + const char *filename, + int line, + const char *function) +{ +#ifdef SECURE_LOG + SECURE_LOG(LOG_DEBUG, m_tag.Get(), "%s", + FormatMessage(message, filename, line, function).c_str()); +#else + LOG(LOG_DEBUG, m_tag.Get(), "%s", + FormatMessage(message, filename, line, function).c_str()); +#endif +} + +void DLOGLogProvider::Info(const char *message, + const char *filename, + int line, + const char *function) +{ +#ifdef SECURE_LOG + SECURE_LOG(LOG_INFO, m_tag.Get(), "%s", + FormatMessage(message, filename, line, function).c_str()); +#else + LOG(LOG_INFO, m_tag.Get(), "%s", + FormatMessage(message, filename, line, function).c_str()); +#endif +} + +void DLOGLogProvider::Warning(const char *message, + const char *filename, + int line, + const char *function) +{ +#ifdef SECURE_LOG + SECURE_LOG(LOG_WARN, m_tag.Get(), "%s", + FormatMessage(message, filename, line, function).c_str()); +#else + LOG(LOG_WARN, m_tag.Get(), "%s", + FormatMessage(message, filename, line, function).c_str()); +#endif +} + +void DLOGLogProvider::Error(const char *message, + const char *filename, + int line, + const char *function) +{ +#ifdef SECURE_LOG + SECURE_LOG(LOG_ERROR, m_tag.Get(), "%s", + FormatMessage(message, filename, line, function).c_str()); +#else + LOG(LOG_ERROR, m_tag.Get(), "%s", + FormatMessage(message, filename, line, function).c_str()); +#endif +} + +void DLOGLogProvider::Pedantic(const char *message, + const char *filename, + int line, + const char *function) +{ +#ifdef SECURE_LOG + SECURE_LOG(LOG_DEBUG, "DPL", "%s", FormatMessage(message, + filename, + line, + function).c_str()); +#else + LOG(LOG_DEBUG, "DPL", "%s", FormatMessage(message, + filename, + line, + function).c_str()); +#endif +} +} +} // namespace DPL diff --git a/tests/framework/src/exception.cpp b/tests/framework/src/exception.cpp new file mode 100644 index 0000000..d3673e6 --- /dev/null +++ b/tests/framework/src/exception.cpp @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file exception.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation of exception system + */ +#include +#include +#include +#include + +namespace DPL { +Exception* Exception::m_lastException = NULL; +unsigned int Exception::m_exceptionCount = 0; +void (*Exception::m_terminateHandler)() = NULL; + +void LogUnhandledException(const std::string &str) +{ + // Logging to console + printf("%s\n", str.c_str()); + + // Logging to dlog + LogPedantic(str); +} + +void LogUnhandledException(const std::string &str, + const char *filename, + int line, + const char *function) +{ + // Logging to console + std::ostringstream msg; + msg << "\033[1;5;31m\n=== [" << filename << ":" << line << "] " << + function << " ===\033[m"; + msg << str; + printf("%s\n", msg.str().c_str()); + + // Logging to dlog + DPL::Log::LogSystemSingleton::Instance().Error( + str.c_str(), filename, line, function); +} +} // namespace DPL diff --git a/tests/framework/src/log.cpp b/tests/framework/src/log.cpp new file mode 100644 index 0000000..5e155bf --- /dev/null +++ b/tests/framework/src/log.cpp @@ -0,0 +1,224 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file log.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of log system + */ +#include +#include + +#include +#include + +IMPLEMENT_SINGLETON(DPL::Log::LogSystem) + +namespace DPL { +namespace Log { +namespace // anonymous +{ +const char *OLD_STYLE_LOGS_ENV_NAME = "DPL_USE_OLD_STYLE_LOGS"; +const char *OLD_STYLE_PEDANTIC_LOGS_ENV_NAME = + "DPL_USE_OLD_STYLE_PEDANTIC_LOGS"; +const char *OLD_STYLE_LOGS_MASK_ENV_NAME = "DPL_USE_OLD_STYLE_LOGS_MASK"; +const char *DPL_LOG_OFF = "DPL_LOG_OFF"; +} // namespace anonymous + +bool LogSystem::IsLoggingEnabled() const +{ + return m_isLoggingEnabled; +} + +LogSystem::LogSystem() : + m_dlogProvider(NULL), + m_oldStyleProvider(NULL), + m_isLoggingEnabled(!getenv(DPL_LOG_OFF)) +{ + bool oldStyleLogs = false; + bool oldStyleDebugLogs = true; + bool oldStyleInfoLogs = true; + bool oldStyleWarningLogs = true; + bool oldStyleErrorLogs = true; + bool oldStylePedanticLogs = false; + + // Check environment settings about pedantic logs + const char *value = getenv(OLD_STYLE_LOGS_ENV_NAME); + + if (value != NULL && !strcmp(value, "1")) { + oldStyleLogs = true; + } + + value = getenv(OLD_STYLE_PEDANTIC_LOGS_ENV_NAME); + + if (value != NULL && !strcmp(value, "1")) { + oldStylePedanticLogs = true; + } + + value = getenv(OLD_STYLE_LOGS_MASK_ENV_NAME); + + if (value != NULL) { + size_t len = strlen(value); + + if (len >= 1) { + if (value[0] == '0') { + oldStyleDebugLogs = false; + } else if (value[0] == '1') { + oldStyleDebugLogs = true; + } + } + + if (len >= 2) { + if (value[1] == '0') { + oldStyleInfoLogs = false; + } else if (value[1] == '1') { + oldStyleInfoLogs = true; + } + } + + if (len >= 3) { + if (value[2] == '0') { + oldStyleWarningLogs = false; + } else if (value[2] == '1') { + oldStyleWarningLogs = true; + } + } + + if (len >= 4) { + if (value[3] == '0') { + oldStyleErrorLogs = false; + } else if (value[3] == '1') { + oldStyleErrorLogs = true; + } + } + } + + // Setup default DLOG and old style logging + if (oldStyleLogs) { + // Old style + m_oldStyleProvider = new OldStyleLogProvider(oldStyleDebugLogs, + oldStyleInfoLogs, + oldStyleWarningLogs, + oldStyleErrorLogs, + oldStylePedanticLogs); + AddProvider(m_oldStyleProvider); + } else { + // DLOG + m_dlogProvider = new DLOGLogProvider(); + AddProvider(m_dlogProvider); + } +} + +LogSystem::~LogSystem() +{ + // Delete all providers + for (AbstractLogProviderPtrList::iterator iterator = m_providers.begin(); + iterator != m_providers.end(); + ++iterator) + { + delete *iterator; + } + + m_providers.clear(); + + // And even default providers + m_dlogProvider = NULL; + m_oldStyleProvider = NULL; +} + +void LogSystem::SetTag(const char* tag) +{ + if (m_dlogProvider != NULL) { + m_dlogProvider->SetTag(tag); + } +} + +void LogSystem::AddProvider(AbstractLogProvider *provider) +{ + m_providers.push_back(provider); +} + +void LogSystem::RemoveProvider(AbstractLogProvider *provider) +{ + m_providers.remove(provider); +} + +void LogSystem::Debug(const char *message, + const char *filename, + int line, + const char *function) +{ + for (AbstractLogProviderPtrList::iterator iterator = m_providers.begin(); + iterator != m_providers.end(); + ++iterator) + { + (*iterator)->Debug(message, filename, line, function); + } +} + +void LogSystem::Info(const char *message, + const char *filename, + int line, + const char *function) +{ + for (AbstractLogProviderPtrList::iterator iterator = m_providers.begin(); + iterator != m_providers.end(); + ++iterator) + { + (*iterator)->Info(message, filename, line, function); + } +} + +void LogSystem::Warning(const char *message, + const char *filename, + int line, + const char *function) +{ + for (AbstractLogProviderPtrList::iterator iterator = m_providers.begin(); + iterator != m_providers.end(); + ++iterator) + { + (*iterator)->Warning(message, filename, line, function); + } +} + +void LogSystem::Error(const char *message, + const char *filename, + int line, + const char *function) +{ + for (AbstractLogProviderPtrList::iterator iterator = m_providers.begin(); + iterator != m_providers.end(); + ++iterator) + { + (*iterator)->Error(message, filename, line, function); + } +} + +void LogSystem::Pedantic(const char *message, + const char *filename, + int line, + const char *function) +{ + for (AbstractLogProviderPtrList::iterator iterator = m_providers.begin(); + iterator != m_providers.end(); + ++iterator) + { + (*iterator)->Pedantic(message, filename, line, function); + } +} +} +} // namespace DPL diff --git a/tests/framework/src/noncopyable.cpp b/tests/framework/src/noncopyable.cpp new file mode 100644 index 0000000..9453655 --- /dev/null +++ b/tests/framework/src/noncopyable.cpp @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file noncopyable.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of noncopyable + */ +#include +#include + +namespace DPL { +Noncopyable::Noncopyable() +{} + +Noncopyable::~Noncopyable() +{} +} // namespace DPL diff --git a/tests/framework/src/old_style_log_provider.cpp b/tests/framework/src/old_style_log_provider.cpp new file mode 100644 index 0000000..b8060dd --- /dev/null +++ b/tests/framework/src/old_style_log_provider.cpp @@ -0,0 +1,200 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file old_style_log_provider.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of old style log provider + */ +#include +#include +#include +#include +#include +#include +#include +#include + +namespace DPL { +namespace Log { +namespace // anonymous +{ +using namespace DPL::Colors::Text; +const char *DEBUG_BEGIN = GREEN_BEGIN; +const char *DEBUG_END = GREEN_END; +const char *INFO_BEGIN = CYAN_BEGIN; +const char *INFO_END = CYAN_END; +const char *ERROR_BEGIN = RED_BEGIN; +const char *ERROR_END = RED_END; +const char *WARNING_BEGIN = BOLD_GOLD_BEGIN; +const char *WARNING_END = BOLD_GOLD_END; +const char *PEDANTIC_BEGIN = PURPLE_BEGIN; +const char *PEDANTIC_END = PURPLE_END; + +std::string GetFormattedTime() +{ + timeval tv; + tm localNowTime; + + gettimeofday(&tv, NULL); + localtime_r(&tv.tv_sec, &localNowTime); + + char format[64]; + snprintf(format, + sizeof(format), + "%02i:%02i:%02i.%03i", + localNowTime.tm_hour, + localNowTime.tm_min, + localNowTime.tm_sec, + static_cast(tv.tv_usec / 1000)); + return format; +} +} // namespace anonymous + +std::string OldStyleLogProvider::FormatMessage(const char *message, + const char *filename, + int line, + const char *function) +{ + std::ostringstream val; + + val << std::string("[") << GetFormattedTime() << std::string("] [") << + static_cast(pthread_self()) << "/" << + static_cast(getpid()) << std::string("] [") << + LocateSourceFileName(filename) << std::string(":") << line << + std::string("] ") << function << std::string("(): ") << message; + + return val.str(); +} + +OldStyleLogProvider::OldStyleLogProvider(bool showDebug, + bool showInfo, + bool showWarning, + bool showError, + bool showPedantic) : + m_showDebug(showDebug), + m_showInfo(showInfo), + m_showWarning(showWarning), + m_showError(showError), + m_showPedantic(showPedantic), + m_printStdErr(false) +{} + +OldStyleLogProvider::OldStyleLogProvider(bool showDebug, + bool showInfo, + bool showWarning, + bool showError, + bool showPedantic, + bool printStdErr) : + m_showDebug(showDebug), + m_showInfo(showInfo), + m_showWarning(showWarning), + m_showError(showError), + m_showPedantic(showPedantic), + m_printStdErr(printStdErr) +{} + +void OldStyleLogProvider::Debug(const char *message, + const char *filename, + int line, + const char *function) +{ + if (m_showDebug) { + if (m_printStdErr) { + fprintf(stderr, "%s%s%s\n", DEBUG_BEGIN, + FormatMessage(message, filename, line, + function).c_str(), DEBUG_END); + } else { + fprintf(stdout, "%s%s%s\n", DEBUG_BEGIN, + FormatMessage(message, filename, line, + function).c_str(), DEBUG_END); + } + } +} + +void OldStyleLogProvider::Info(const char *message, + const char *filename, + int line, + const char *function) +{ + if (m_showInfo) { + if (m_printStdErr) { + fprintf(stderr, "%s%s%s\n", INFO_BEGIN, + FormatMessage(message, filename, line, + function).c_str(), INFO_END); + } else { + fprintf(stdout, "%s%s%s\n", INFO_BEGIN, + FormatMessage(message, filename, line, + function).c_str(), INFO_END); + } + } +} + +void OldStyleLogProvider::Warning(const char *message, + const char *filename, + int line, + const char *function) +{ + if (m_showWarning) { + if (m_printStdErr) { + fprintf(stderr, "%s%s%s\n", WARNING_BEGIN, + FormatMessage(message, filename, line, + function).c_str(), WARNING_END); + } else { + fprintf(stdout, "%s%s%s\n", WARNING_BEGIN, + FormatMessage(message, filename, line, + function).c_str(), WARNING_END); + } + } +} + +void OldStyleLogProvider::Error(const char *message, + const char *filename, + int line, + const char *function) +{ + if (m_showError) { + if (m_printStdErr) { + fprintf(stderr, "%s%s%s\n", ERROR_BEGIN, + FormatMessage(message, filename, line, + function).c_str(), ERROR_END); + } else { + fprintf(stdout, "%s%s%s\n", ERROR_BEGIN, + FormatMessage(message, filename, line, + function).c_str(), ERROR_END); + } + } +} + +void OldStyleLogProvider::Pedantic(const char *message, + const char *filename, + int line, + const char *function) +{ + if (m_showPedantic) { + if (m_printStdErr) { + fprintf(stderr, "%s%s%s\n", PEDANTIC_BEGIN, + FormatMessage(message, filename, line, + function).c_str(), PEDANTIC_END); + } else { + fprintf(stdout, "%s%s%s\n", PEDANTIC_BEGIN, + FormatMessage(message, filename, line, + function).c_str(), PEDANTIC_END); + } + } +} +} +} // namespace DPL diff --git a/tests/framework/src/singleton.cpp b/tests/framework/src/singleton.cpp new file mode 100644 index 0000000..54abd52 --- /dev/null +++ b/tests/framework/src/singleton.cpp @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file singleton.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of singleton + */ +#include +#include + +// +// Note: +// +// The file here is left blank to enable precompilation +// of templates in corresponding header file. +// Do not remove this file. +// diff --git a/tests/framework/src/test_results_collector.cpp b/tests/framework/src/test_results_collector.cpp new file mode 100644 index 0000000..e42f60e --- /dev/null +++ b/tests/framework/src/test_results_collector.cpp @@ -0,0 +1,1081 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file test_results_collector.h + * @author Lukasz Wrzosek (l.wrzosek@samsung.com) + * @version 1.0 + * @brief Implementation file some concrete TestResulstsCollector + */ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#define GREEN_RESULT_OK "[%s%s%s]\n", BOLD_GREEN_BEGIN, " OK ", \ + BOLD_GREEN_END +#define GREEN_RESULT_OK_TIME "[%s%s%s] [elapsed: %0.3fms]\n", BOLD_GREEN_BEGIN, \ + " OK ", BOLD_GREEN_END +#define GREEN_RESULT_OK_TIME_MAX(elapsed, max) \ + "[%s%s%s] %s[elapsed: %0.3fms, expected < %0.3fms]%s\n", BOLD_GREEN_BEGIN, \ + " OK ", BOLD_GREEN_END, BOLD_GREEN_BEGIN, elapsed, max, BOLD_GREEN_END +#define GREEN_RESULT_OK_TIME_TOO_LONG(elapsed, max) \ + "[%s%s%s] %s[elapsed: %0.3fms, expected < %0.3fms]%s\n", BOLD_GREEN_BEGIN, \ + " OK ", BOLD_GREEN_END, BOLD_RED_BEGIN, elapsed, max, BOLD_RED_END + +namespace { /* anonymous namespace */ +// Get duration as a fraction of millisecond (max precision is 1 microsecond) +double get_milliseconds (const std::chrono::system_clock::duration& performanceTime) +{ + return (static_cast(std::chrono::duration_cast + (performanceTime).count()))/1000.0; +} +} /* anonymous namespace */ + +namespace DPL { +namespace Test { +namespace { +const char *DEFAULT_HTML_FILE_NAME = "index.html"; +const char *DEFAULT_TAP_FILE_NAME = "results.tap"; +const char *DEFAULT_XML_FILE_NAME = "results.xml"; + +bool ParseCollectorFileArg(const std::string &arg, std::string &filename) +{ + const std::string argname = "--file="; + if (arg.find(argname) == 0 ) { + filename = arg.substr(argname.size()); + return true; + } + return false; +} + +class Statistic +{ + public: + Statistic() : + m_failed(0), + m_ignored(0), + m_passed(0), + m_count(0) + {} + + void AddTest(TestResultsCollectorBase::FailStatus::Type type) + { + ++m_count; + switch (type) { + case TestResultsCollectorBase::FailStatus::INTERNAL: + case TestResultsCollectorBase::FailStatus::FAILED: ++m_failed; + break; + case TestResultsCollectorBase::FailStatus::IGNORED: ++m_ignored; + break; + case TestResultsCollectorBase::FailStatus::NONE: ++m_passed; + break; + default: + Assert(false && "Bad FailStatus"); + } + } + + std::size_t GetTotal() const + { + return m_count; + } + std::size_t GetPassed() const + { + return m_passed; + } + std::size_t GetSuccesed() const + { + return m_passed; + } + std::size_t GetFailed() const + { + return m_failed; + } + std::size_t GetIgnored() const + { + return m_ignored; + } + float GetPassedOrIgnoredPercend() const + { + float passIgnoredPercent = + 100.0f * (static_cast(m_passed) + + static_cast(m_ignored)) + / static_cast(m_count); + return passIgnoredPercent; + } + + private: + std::size_t m_failed; + std::size_t m_ignored; + std::size_t m_passed; + std::size_t m_count; +}; + +class ConsoleCollector : + public TestResultsCollectorBase +{ + public: + static TestResultsCollectorBase* Constructor(); + + private: + ConsoleCollector() {} + + virtual void CollectCurrentTestGroupName(const std::string& name) + { + printf("Starting group %s\n", name.c_str()); + m_currentGroup = name; + } + + virtual void Finish() + { + using namespace DPL::Colors::Text; + + // Show result + for (auto &group : m_groupsStats) { + PrintStats(group.first, group.second); + } + PrintStats("All tests together", m_stats); + } + + virtual void CollectResult(const std::string& id, + const std::string& /*description*/, + const FailStatus::Type status = FailStatus::NONE, + const std::string& reason = "", + const bool& isPerformanceTest = true, + const std::chrono::system_clock::duration& performanceTime = std::chrono::microseconds::zero(), + const std::chrono::system_clock::duration& performanceMaxTime = std::chrono::microseconds::zero()) + { + using namespace DPL::Colors::Text; + std::string tmp = "'" + id + "' ..."; + + printf("Running test case %-60s", tmp.c_str()); + switch (status) { + case TestResultsCollectorBase::FailStatus::NONE: + if (isPerformanceTest) { + if (performanceMaxTime <= std::chrono::microseconds::zero()) { + printf(GREEN_RESULT_OK_TIME, + get_milliseconds(performanceTime)); + break; + } + else { + if (performanceTime > performanceMaxTime) + printf(GREEN_RESULT_OK_TIME_TOO_LONG( + get_milliseconds(performanceTime), + get_milliseconds(performanceMaxTime))); + else + printf(GREEN_RESULT_OK_TIME_MAX( + get_milliseconds(performanceTime), + get_milliseconds(performanceMaxTime))); + break; + } + } + printf(GREEN_RESULT_OK); + break; + case TestResultsCollectorBase::FailStatus::FAILED: + PrintfErrorMessage(" FAILED ", reason, true); + break; + case TestResultsCollectorBase::FailStatus::IGNORED: + PrintfIgnoredMessage("Ignored ", reason, true); + break; + case TestResultsCollectorBase::FailStatus::INTERNAL: + PrintfErrorMessage("INTERNAL", reason, true); + break; + default: + Assert(false && "Bad status"); + } + m_stats.AddTest(status); + m_groupsStats[m_currentGroup].AddTest(status); + } + + void PrintfErrorMessage(const char* type, + const std::string& message, + bool verbosity) + { + using namespace DPL::Colors::Text; + if (verbosity) { + printf("[%s%s%s] %s%s%s\n", + BOLD_RED_BEGIN, + type, + BOLD_RED_END, + BOLD_YELLOW_BEGIN, + message.c_str(), + BOLD_YELLOW_END); + } else { + printf("[%s%s%s]\n", + BOLD_RED_BEGIN, + type, + BOLD_RED_END); + } + } + + void PrintfIgnoredMessage(const char* type, + const std::string& message, + bool verbosity) + { + using namespace DPL::Colors::Text; + if (verbosity) { + printf("[%s%s%s] %s%s%s\n", + CYAN_BEGIN, + type, + CYAN_END, + BOLD_GOLD_BEGIN, + message.c_str(), + BOLD_GOLD_END); + } else { + printf("[%s%s%s]\n", + CYAN_BEGIN, + type, + CYAN_END); + } + } + + void PrintStats(const std::string& title, const Statistic& stats) + { + using namespace DPL::Colors::Text; + printf("\n%sResults [%s]: %s\n", BOLD_GREEN_BEGIN, + title.c_str(), BOLD_GREEN_END); + printf("%s%s%3zu%s\n", + CYAN_BEGIN, + "Total tests: ", + stats.GetTotal(), + CYAN_END); + printf(" %s%s%3zu%s\n", + CYAN_BEGIN, + "Succeeded: ", + stats.GetPassed(), + CYAN_END); + printf(" %s%s%3zu%s\n", + CYAN_BEGIN, + "Failed: ", + stats.GetFailed(), + CYAN_END); + printf(" %s%s%3zu%s\n", + CYAN_BEGIN, + "Ignored: ", + stats.GetIgnored(), + CYAN_END); + } + + Statistic m_stats; + std::map m_groupsStats; + std::string m_currentGroup; +}; + +TestResultsCollectorBase* ConsoleCollector::Constructor() +{ + return new ConsoleCollector(); +} + +class HtmlCollector : + public TestResultsCollectorBase +{ + public: + static TestResultsCollectorBase* Constructor(); + + private: + HtmlCollector() : m_filename(DEFAULT_HTML_FILE_NAME) {} + + virtual void CollectCurrentTestGroupName(const std::string& name) + { + fprintf(m_fp.Get(), "Starting group %s", name.c_str()); + m_currentGroup = name; + } + + virtual bool Configure() + { + m_fp.Reset(fopen(m_filename.c_str(), "w")); + if (!m_fp) { + LogPedantic("Could not open file " << m_filename << " for writing"); + return false; + } + return true; + } + virtual std::string CollectorSpecificHelp() const + { + return "--file= - name of file for output\n" + " default - index.html\n"; + } + + virtual void Start() + { + Assert(!!m_fp && "File handle must not be null"); + fprintf(m_fp.Get(), + "\n"); + fprintf(m_fp.Get(), + "\n"); + fprintf(m_fp.Get(), "\n"); + fprintf(m_fp.Get(), "
\n");
+        fprintf(m_fp.Get(), "\n");
+    }
+
+    virtual void Finish()
+    {
+        using namespace DPL::Colors::Html;
+        // Show result
+        for (auto &group : m_groupsStats) {
+            PrintStats(group.first, group.second);
+        }
+        PrintStats("All tests together", m_stats);
+        fprintf(m_fp.Get(), "\n");
+        fprintf(m_fp.Get(), "
\n"); + fprintf(m_fp.Get(), "\n"); + fprintf(m_fp.Get(), "\n"); + } + + virtual bool ParseCollectorSpecificArg(const std::string& arg) + { + return ParseCollectorFileArg(arg, m_filename); + } + + virtual void CollectResult(const std::string& id, + const std::string& /*description*/, + const FailStatus::Type status = FailStatus::NONE, + const std::string& reason = "", + const bool& isPerformanceTest = false, + const std::chrono::system_clock::duration& performanceTime = std::chrono::microseconds::zero(), + const std::chrono::system_clock::duration& performanceMaxTime = std::chrono::microseconds::zero()) + { + using namespace DPL::Colors::Html; + std::string tmp = "'" + id + "' ..."; + + fprintf(m_fp.Get(), "Running test case %-100s", tmp.c_str()); + switch (status) { + case TestResultsCollectorBase::FailStatus::NONE: + if (isPerformanceTest) { + if (performanceMaxTime <= std::chrono::microseconds::zero()) { + fprintf(m_fp.Get(), GREEN_RESULT_OK_TIME, + get_milliseconds(performanceTime)); + break; + } else { + if (performanceTime > performanceMaxTime) + fprintf(m_fp.Get(), GREEN_RESULT_OK_TIME_TOO_LONG( + get_milliseconds(performanceTime), + get_milliseconds(performanceMaxTime))); + else + fprintf(m_fp.Get(), GREEN_RESULT_OK_TIME_MAX( + get_milliseconds(performanceTime), + get_milliseconds(performanceMaxTime))); + break; + } + } + fprintf(m_fp.Get(), GREEN_RESULT_OK); + break; + case TestResultsCollectorBase::FailStatus::FAILED: + PrintfErrorMessage(" FAILED ", reason, true); + break; + case TestResultsCollectorBase::FailStatus::IGNORED: + PrintfIgnoredMessage("Ignored ", reason, true); + break; + case TestResultsCollectorBase::FailStatus::INTERNAL: + PrintfErrorMessage("INTERNAL", reason, true); + break; + default: + Assert(false && "Bad status"); + } + m_groupsStats[m_currentGroup].AddTest(status); + m_stats.AddTest(status); + } + + void PrintfErrorMessage(const char* type, + const std::string& message, + bool verbosity) + { + using namespace DPL::Colors::Html; + if (verbosity) { + fprintf(m_fp.Get(), + "[%s%s%s] %s%s%s\n", + BOLD_RED_BEGIN, + type, + BOLD_RED_END, + BOLD_YELLOW_BEGIN, + message.c_str(), + BOLD_YELLOW_END); + } else { + fprintf(m_fp.Get(), + "[%s%s%s]\n", + BOLD_RED_BEGIN, + type, + BOLD_RED_END); + } + } + + void PrintfIgnoredMessage(const char* type, + const std::string& message, + bool verbosity) + { + using namespace DPL::Colors::Html; + + if (verbosity) { + fprintf(m_fp.Get(), + "[%s%s%s] %s%s%s\n", + CYAN_BEGIN, + type, + CYAN_END, + BOLD_GOLD_BEGIN, + message.c_str(), + BOLD_GOLD_END); + } else { + fprintf(m_fp.Get(), + "[%s%s%s]\n", + CYAN_BEGIN, + type, + CYAN_END); + } + } + + void PrintStats(const std::string& name, const Statistic& stats) + { + using namespace DPL::Colors::Html; + fprintf( + m_fp.Get(), "\n%sResults [%s]:%s\n", BOLD_GREEN_BEGIN, + name.c_str(), BOLD_GREEN_END); + fprintf( + m_fp.Get(), "%s%s%3zu%s\n", CYAN_BEGIN, + "Total tests: ", stats.GetTotal(), CYAN_END); + fprintf( + m_fp.Get(), " %s%s%3zu%s\n", CYAN_BEGIN, + "Succeeded: ", stats.GetPassed(), CYAN_END); + fprintf( + m_fp.Get(), " %s%s%3zu%s\n", CYAN_BEGIN, + "Failed: ", stats.GetFailed(), CYAN_END); + fprintf( + m_fp.Get(), " %s%s%3zu%s\n", CYAN_BEGIN, + "Ignored: ", stats.GetIgnored(), CYAN_END); + } + + std::string m_filename; + ScopedFClose m_fp; + Statistic m_stats; + std::string m_currentGroup; + std::map m_groupsStats; +}; + +TestResultsCollectorBase* HtmlCollector::Constructor() +{ + return new HtmlCollector(); +} + +class XmlCollector : + public TestResultsCollectorBase +{ + public: + static TestResultsCollectorBase* Constructor(); + + private: + XmlCollector() : m_filename(DEFAULT_XML_FILE_NAME) {} + + virtual void CollectCurrentTestGroupName(const std::string& name) + { + std::size_t pos = GetCurrentGroupPosition(); + if (std::string::npos != pos) { + GroupFinish(pos); + FlushOutput(); + m_stats = Statistic(); + } + + pos = m_outputBuffer.find(""); + if (std::string::npos == pos) { + ThrowMsg(DPL::Exception, "Could not find test suites closing tag"); + } + GroupStart(pos, name); + } + + void GroupStart(const std::size_t pos, const std::string& name) + { + std::stringstream groupHeader; + groupHeader << "\n\t"; + + groupHeader << "\n\t\t"; + groupHeader << + "\n\t\t\t"; + groupHeader << "\n\t\t"; + + groupHeader << "\n\t"; + + m_outputBuffer.insert(pos - 1, groupHeader.str()); + } + + virtual bool Configure() + { + m_fp.Reset(fopen(m_filename.c_str(), "w")); + if (!m_fp) { + LogPedantic("Could not open file " << m_filename << " for writing"); + return false; + } + return true; + } + + virtual std::string CollectorSpecificHelp() const + { + return "--file= - name of file for output\n" + " default - results.xml\n"; + } + + virtual void Start() + { + Assert(!!m_fp && "File handle must not be null"); + m_outputBuffer.append("\n"); + m_outputBuffer.append("\n"); + FlushOutput(); + } + + virtual void Finish() + { + std::size_t pos = GetCurrentGroupPosition(); + if (std::string::npos != pos) { + GroupFinish(pos); + FlushOutput(); + } + } + + virtual bool ParseCollectorSpecificArg(const std::string& arg) + { + return ParseCollectorFileArg(arg, m_filename); + } + + virtual void CollectResult(const std::string& id, + const std::string& /*description*/, + const FailStatus::Type status = FailStatus::NONE, + const std::string& reason = "", + const bool& isPerformanceTest = false, + const std::chrono::system_clock::duration& performanceTime = std::chrono::microseconds::zero(), + const std::chrono::system_clock::duration& performanceMaxTime = std::chrono::microseconds::zero()) + { + m_resultBuffer.erase(); + m_resultBuffer.append("\t\t\n"); + break; + } else { + m_resultBuffer.append(" status=\"OK\" time=\""); + std::ostringstream ostr; + ostr << performanceTime.count(); + m_resultBuffer.append(ostr.str()); + m_resultBuffer.append("\" time_expected=\""); + ostr.str(""); + ostr << performanceMaxTime.count(); + m_resultBuffer.append(ostr.str()); + m_resultBuffer.append("\"/>\n"); + break; + } + } + m_resultBuffer.append(" status=\"OK\"/>\n"); + break; + case TestResultsCollectorBase::FailStatus::FAILED: + m_resultBuffer.append(" status=\"FAILED\">\n"); + PrintfErrorMessage("FAILED", EscapeSpecialCharacters(reason), true); + m_resultBuffer.append("\t\t\n"); + break; + case TestResultsCollectorBase::FailStatus::IGNORED: + m_resultBuffer.append(" status=\"Ignored\">\n"); + PrintfIgnoredMessage("Ignored", EscapeSpecialCharacters( + reason), true); + m_resultBuffer.append("\t\t\n"); + break; + case TestResultsCollectorBase::FailStatus::INTERNAL: + m_resultBuffer.append(" status=\"FAILED\">\n"); + PrintfErrorMessage("INTERNAL", EscapeSpecialCharacters( + reason), true); + m_resultBuffer.append("\t\t"); + break; + default: + Assert(false && "Bad status"); + } + std::size_t group_pos = GetCurrentGroupPosition(); + if (std::string::npos == group_pos) { + ThrowMsg(DPL::Exception, "No current group set"); + } + + std::size_t last_case_pos = m_outputBuffer.find( + "\n"); + } else { + m_resultBuffer.append("\t\t\t\n"); + } + } + + void PrintfIgnoredMessage(const char* type, + const std::string& message, + bool verbosity) + { + if (verbosity) { + m_resultBuffer.append("\t\t\t\n"); + } else { + m_resultBuffer.append("\t\t\t\n"); + } + } + + std::string EscapeSpecialCharacters(std::string s) + { + for (unsigned int i = 0; i < s.size();) { + switch (s[i]) { + case '"': + s.erase(i, 1); + s.insert(i, """); + i += 6; + break; + + case '&': + s.erase(i, 1); + s.insert(i, "&"); + i += 5; + break; + + case '<': + s.erase(i, 1); + s.insert(i, "<"); + i += 4; + break; + + case '>': + s.erase(i, 1); + s.insert(i, ">"); + i += 4; + break; + + case '\'': + s.erase(i, 1); + s.insert(i, "'"); + i += 5; + break; + default: + ++i; + break; + } + } + return s; + } + + std::string m_filename; + ScopedFClose m_fp; + Statistic m_stats; + std::string m_outputBuffer; + std::string m_resultBuffer; +}; + +TestResultsCollectorBase* XmlCollector::Constructor() +{ + return new XmlCollector(); +} + +class CSVCollector : + public TestResultsCollectorBase +{ + public: + static TestResultsCollectorBase* Constructor(); + + private: + CSVCollector() {} + + virtual void Start() + { + printf("GROUP;ID;RESULT;REASON;ELAPSED [s];EXPECTED [s]\n"); + } + + virtual void CollectCurrentTestGroupName(const std::string& name) + { + m_currentGroup = name; + } + + virtual void CollectResult(const std::string& id, + const std::string& /*description*/, + const FailStatus::Type status = FailStatus::NONE, + const std::string& reason = "", + const bool& isPerformanceTest = false, + const std::chrono::system_clock::duration& performanceTime = std::chrono::microseconds::zero(), + const std::chrono::system_clock::duration& performanceMaxTime = std::chrono::microseconds::zero()) + { + std::string statusMsg = ""; + switch (status) { + case TestResultsCollectorBase::FailStatus::NONE: + statusMsg = "OK"; + if (isPerformanceTest) { + statusMsg.append(";;"); + std::ostringstream ostr; + ostr << performanceTime.count(); + statusMsg.append(ostr.str()); + if (performanceMaxTime <= std::chrono::microseconds::zero()) { + statusMsg.append(";"); + ostr.str(""); + ostr << performanceMaxTime.count(); + statusMsg.append(ostr.str()); + } + } + break; + case TestResultsCollectorBase::FailStatus::FAILED: statusMsg = "FAILED"; + break; + case TestResultsCollectorBase::FailStatus::IGNORED: statusMsg = + "IGNORED"; + break; + case TestResultsCollectorBase::FailStatus::INTERNAL: statusMsg = + "FAILED"; + break; + default: + Assert(false && "Bad status"); + } + printf("%s;%s;%s;%s\n", + m_currentGroup.c_str(), + id.c_str(), + statusMsg.c_str(), + reason.c_str()); + } + + std::string m_currentGroup; +}; + +TestResultsCollectorBase* CSVCollector::Constructor() +{ + return new CSVCollector(); +} +} + +class TAPCollector : + public TestResultsCollectorBase +{ + public: + static TestResultsCollectorBase* Constructor(); + + private: + TAPCollector() : m_filename(DEFAULT_TAP_FILE_NAME) {} + + virtual bool Configure() + { + m_output.open(m_filename.c_str(), std::ios_base::trunc); + if (m_output.fail()) { + LogError("Can't open output file: " << m_filename); + return false; + } + return true; + } + virtual std::string CollectorSpecificHelp() const + { + std::string retVal = "--file= - name of file for output\n" + " default - "; + retVal += DEFAULT_TAP_FILE_NAME; + retVal += "\n"; + return retVal; + } + + virtual void Start() + { + Assert(m_output.good() && "Output file must be opened."); + m_output << "TAP version 13" << std::endl; + m_testIndex = 0; + } + + virtual void Finish() + { + m_output << "1.." << m_testIndex << std::endl; + m_output << m_collectedData.rdbuf(); + m_output.close(); + } + + virtual bool ParseCollectorSpecificArg(const std::string& arg) + { + return ParseCollectorFileArg(arg, m_filename); + } + + virtual void CollectResult(const std::string& id, + const std::string& description, + const FailStatus::Type status = FailStatus::NONE, + const std::string& reason = "", + const bool& isPerformanceTest = false, + const std::chrono::system_clock::duration& performanceTime = std::chrono::microseconds::zero(), + const std::chrono::system_clock::duration& performanceMaxTime = std::chrono::microseconds::zero()) + { + /* Remove unused variable warning */ + DPL_UNUSED_PARAM(isPerformanceTest); + DPL_UNUSED_PARAM(performanceTime); + DPL_UNUSED_PARAM(performanceMaxTime); + + m_testIndex++; + switch (status) { + case TestResultsCollectorBase::FailStatus::NONE: + LogBasicTAP(true, id, description); + endTAPLine(); + break; + case TestResultsCollectorBase::FailStatus::FAILED: + LogBasicTAP(false, id, description); + endTAPLine(); + break; + case TestResultsCollectorBase::FailStatus::IGNORED: + LogBasicTAP(true, id, description); + m_collectedData << " # skip " << reason; + endTAPLine(); + break; + case TestResultsCollectorBase::FailStatus::INTERNAL: + LogBasicTAP(true, id, description); + endTAPLine(); + m_collectedData << " ---" << std::endl; + m_collectedData << " message: " << reason << std::endl; + m_collectedData << " severity: Internal" << std::endl; + m_collectedData << " ..." << std::endl; + break; + default: + Assert(false && "Bad status"); + } + } + + void LogBasicTAP(bool isOK, const std::string& id, + const std::string& description) + { + if (!isOK) { + m_collectedData << "not "; + } + m_collectedData << "ok " << m_testIndex << " [" << + id << "] " << description; + } + + void endTAPLine() + { + m_collectedData << std::endl; + } + + std::string m_filename; + std::stringstream m_collectedData; + std::ofstream m_output; + int m_testIndex; +}; + +TestResultsCollectorBase* TAPCollector::Constructor() +{ + return new TAPCollector(); +} + +void TestResultsCollectorBase::RegisterCollectorConstructor( + const std::string& name, + TestResultsCollectorBase::CollectorConstructorFunc func) +{ + Assert(m_constructorsMap.find(name) == m_constructorsMap.end()); + m_constructorsMap[name] = func; +} + +TestResultsCollectorBase* TestResultsCollectorBase::Create( + const std::string& name) +{ + ConstructorsMap::iterator found = m_constructorsMap.find(name); + if (found != m_constructorsMap.end()) { + return found->second(); + } else { + return NULL; + } +} + +std::vector TestResultsCollectorBase::GetCollectorsNames() +{ + std::vector list; + for (auto &constructor : m_constructorsMap) + { + list.push_back(constructor.first); + } + return list; +} + +TestResultsCollectorBase::ConstructorsMap TestResultsCollectorBase:: + m_constructorsMap; + +namespace { +static int RegisterCollectorConstructors(); +static const int RegisterHelperVariable = RegisterCollectorConstructors(); +int RegisterCollectorConstructors() +{ + (void)RegisterHelperVariable; + + TestResultsCollectorBase::RegisterCollectorConstructor( + "text", + &ConsoleCollector::Constructor); + TestResultsCollectorBase::RegisterCollectorConstructor( + "html", + &HtmlCollector::Constructor); + TestResultsCollectorBase::RegisterCollectorConstructor( + "csv", + &CSVCollector::Constructor); + TestResultsCollectorBase::RegisterCollectorConstructor( + "tap", + &TAPCollector::Constructor); + TestResultsCollectorBase::RegisterCollectorConstructor( + "xml", + &XmlCollector::Constructor); + + return 0; +} +} +} +} +#undef GREEN_RESULT_OK diff --git a/tests/framework/src/test_runner.cpp b/tests/framework/src/test_runner.cpp new file mode 100644 index 0000000..ee316e2 --- /dev/null +++ b/tests/framework/src/test_runner.cpp @@ -0,0 +1,767 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file test_runner.cpp + * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com) + * @author Lukasz Wrzosek (l.wrzosek@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of test runner + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +IMPLEMENT_SINGLETON(DPL::Test::TestRunner) + +namespace { + +std::string getXMLNode(xmlNodePtr node) +{ + std::string ret; + xmlChar * value = xmlNodeGetContent(node); + ret = std::string(reinterpret_cast(value)); + xmlFree(value); + return ret; +} + +} + + +namespace DPL { +namespace Test { +namespace // anonymous +{ +std::string BaseName(std::string aPath) +{ + ScopedFree path(strdup(aPath.c_str())); + if (NULL == path.Get()) { + throw std::bad_alloc(); + } + char* baseName = basename(path.Get()); + std::string retValue = baseName; + return retValue; +} +} // namespace anonymous + +//! \brief Failed test message creator +//! +//! \param[in] aTest string for tested expression +//! \param[in] aFile source file name +//! \param[in] aLine source file line +//! \param[in] aMessage error message +TestRunner::TestFailed::TestFailed(const char* aTest, + const char* aFile, + int aLine, + const std::string &aMessage) +{ + std::ostringstream assertMsg; + assertMsg << "[" << BaseName(aFile) << ":" << aLine + << "] Assertion failed (" + << aTest << ") " << aMessage; + m_message = assertMsg.str(); +} + +TestRunner::TestFailed::TestFailed(const std::string &message) +{ + m_message = message; +} + +void TestRunner::RegisterTest(const char *testName, TestCase proc) +{ + m_testGroups[m_currentGroup].push_back(TestCaseStruct(testName, proc)); +} + +void TestRunner::InitGroup(const char* name) +{ + m_currentGroup = name; +} + +void TestRunner::normalizeXMLTag(std::string& str, const std::string& testcase) +{ + //Add testcase if missing + std::string::size_type pos = str.find(testcase); + if(pos != 0) + { + str = testcase + "_" + str; + } + + //dpl test runner cannot have '-' character in name so it have to be replaced + // for TCT case to make comparision works + std::replace(str.begin(), str.end(), '-', '_'); +} + +bool TestRunner::filterGroupsByXmls(const std::vector & files) +{ + DECLARE_EXCEPTION_TYPE(DPL::Exception, XMLError) + + const std::string idPath = "/test_definition/suite/set/testcase/@id"; + + bool success = true; + std::map casesMap; + + std::string testsuite; + if(!m_testGroups.empty()) + { + for(TestCaseGroupMap::const_iterator cit = m_testGroups.begin(); cit != m_testGroups.end(); ++cit) + { + if(!cit->second.empty()) + { + for(TestCaseStructList::const_iterator cj = cit->second.begin(); cj != cit->second.end(); ++cj) + { + std::string name = cj->name; + std::string::size_type st = name.find('_'); + if(st != std::string::npos) + { + name = name.substr(0, st); + testsuite = name; + break; + } + } + if(!testsuite.empty()) break; + } + } + } + + xmlInitParser(); + LIBXML_TEST_VERSION + xmlXPathInit(); + + Try + { + for (const std::string &file : files) + { + xmlDocPtr doc; + xmlXPathContextPtr xpathCtx; + + doc = xmlReadFile(file.c_str(), NULL, 0); + if (doc == NULL) { + ThrowMsg(XMLError, "File Problem"); + } else { + //context + xpathCtx = xmlXPathNewContext(doc); + if (xpathCtx == NULL) { + ThrowMsg(XMLError, + "Error: unable to create new XPath context\n"); + } + xpathCtx->node = xmlDocGetRootElement(doc); + } + + std::string result; + xmlXPathObjectPtr xpathObject; + //get requested node's values + xpathObject = xmlXPathEvalExpression(BAD_CAST idPath.c_str(), xpathCtx); + if (xpathObject == NULL) + { + ThrowMsg(XMLError, "XPath evaluation failure: " << idPath); + } + xmlNodeSetPtr nodes = xpathObject->nodesetval; + unsigned size = (nodes) ? nodes->nodeNr : 0; + LogDebug("Found " << size << " nodes matching xpath"); + for(unsigned i = 0; i < size; ++i) + { + LogPedantic("Type: " << nodes->nodeTab[i]->type); + if (nodes->nodeTab[i]->type == XML_ATTRIBUTE_NODE) { + xmlNodePtr curNode = nodes->nodeTab[i]; + result = getXMLNode(curNode); + LogPedantic("Result: " << result); + normalizeXMLTag(result, testsuite); + casesMap.insert(make_pair(result, false)); + } + } + //Cleanup of XPath data + xmlXPathFreeObject(xpathObject); + xmlXPathFreeContext(xpathCtx); + xmlFreeDoc(doc); + } + } + Catch(XMLError) + { + LogError("Libxml error: " << _rethrown_exception.DumpToString()); + success = false; + } + xmlCleanupParser(); + + if(!filterByXML(casesMap)) + { + success = false; + } + + return success; +} + +bool TestRunner::filterByXML(std::map & casesMap) +{ + for (auto &group : m_testGroups) { + TestCaseStructList newList; + for (auto &tc : group.second) + { + if (casesMap.find(tc.name) != casesMap.end()) { + casesMap[tc.name] = true; + newList.push_back(tc); + } + } + group.second = newList; + } + for (auto &cs : casesMap) + { + if(cs.second == false) + { + LogError("Cannot find testcase from XML file: " << cs.first); + return false; + } + } + return true; +} + +TestRunner::Status TestRunner::RunTestCase(const TestCaseStruct& testCase) +{ + setCurrentTestCase(&(const_cast(testCase))); + try { + testCase.proc(); + } catch (const TestFailed &e) { + // Simple test failure + CollectResult(testCase.name, + "", + TestResultsCollectorBase::FailStatus::FAILED, + e.GetMessage()); + + setCurrentTestCase(NULL); + return FAILED; + } catch (const Ignored &e) { + if (m_runIgnored) { + // Simple test have to be implemented + CollectResult(testCase.name, + "", + TestResultsCollectorBase::FailStatus::IGNORED, + e.GetMessage()); + } + + setCurrentTestCase(NULL); + return IGNORED; + } catch (const DPL::Exception &e) { + // DPL exception failure + CollectResult(testCase.name, + "", + TestResultsCollectorBase::FailStatus::INTERNAL, + "DPL exception:" + e.GetMessage()); + + setCurrentTestCase(NULL); + return FAILED; + } catch (const std::exception &) { + // std exception failure + CollectResult(testCase.name, + "", + TestResultsCollectorBase::FailStatus::INTERNAL, + "std exception"); + + setCurrentTestCase(NULL); + return FAILED; + } catch (...) { + // Unknown exception failure + CollectResult(testCase.name, + "", + TestResultsCollectorBase::FailStatus::INTERNAL, + "unknown exception"); + + setCurrentTestCase(NULL); + return FAILED; + } + + CollectResult(testCase.name, + "", + TestResultsCollectorBase::FailStatus::NONE, + "", + testCase.m_isPerformanceTest, + testCase.m_performanceTestDurationTime, + testCase.m_performanceMaxTime); + setCurrentTestCase(NULL); + + // Everything OK + return PASS; +} + +void TestRunner::RunTests() +{ + using namespace DPL::Colors::Text; + + Banner(); + for (auto &collector : m_collectors) { + collector.second->Start(); + } + + unsigned count = 0; + for (auto &group : m_testGroups) { + count += group.second.size(); + } + fprintf(stderr, "%sFound %d testcases...%s\n", GREEN_BEGIN, count, GREEN_END); + fprintf(stderr, "%s%s%s\n", GREEN_BEGIN, "Running tests...", GREEN_END); + for (auto &group : m_testGroups) { + TestCaseStructList list = group.second; + if (!list.empty()) { + for (auto &collector : m_collectors) { + collector.second->CollectCurrentTestGroupName(group.first); + } + list.sort(); + + for (TestCaseStructList::const_iterator iterator = list.begin(); + iterator != list.end(); + ++iterator) + { + TestCaseStruct test = *iterator; + if (m_startTestId == test.name) { + m_startTestId = ""; + } + + if (m_startTestId.empty()) { + RunTestCase(test); + } + if (m_terminate == true) { + // Terminate quietly without any logs + return; + } + } + } + } + + std::for_each(m_collectors.begin(), + m_collectors.end(), + [] (const TestResultsCollectors::value_type & collector) + { + collector.second->Finish(); + }); + + // Finished + fprintf(stderr, "%s%s%s\n\n", GREEN_BEGIN, "Finished", GREEN_END); +} + +TestRunner::TestCaseStruct *TestRunner::getCurrentTestCase() +{ + return m_currentTestCase; +} + +void TestRunner::setCurrentTestCase(TestCaseStruct* testCase) +{ + m_currentTestCase = testCase; +} + +void TestRunner::beginPerformanceTestTime(std::chrono::system_clock::duration maxTimeInMicroseconds) +{ + TestCaseStruct* testCase = getCurrentTestCase(); + if (!testCase) + return; + + testCase->m_isPerformanceTest = true; + testCase->m_performanceMaxTime = maxTimeInMicroseconds; + testCase->m_performanceTestStartTime = std::chrono::system_clock::now(); + + // Set result to 0 microseconds. Display 0ms result when end macro is missing. + testCase->m_performanceTestDurationTime = std::chrono::microseconds::zero(); +} + +void TestRunner::endPerformanceTestTime() +{ + TestCaseStruct* testCase = getCurrentTestCase(); + if (!testCase) + return; + + testCase->m_performanceTestDurationTime = std::chrono::system_clock::now() - + testCase->m_performanceTestStartTime; +} + +void TestRunner::getCurrentTestCasePerformanceResult(bool& isPerformanceTest, + std::chrono::system_clock::duration& result, + std::chrono::system_clock::duration& resultMax) +{ + TestCaseStruct* testCase = getCurrentTestCase(); + if (!testCase || !(testCase->m_isPerformanceTest)){ + isPerformanceTest = false; + return; + } + + isPerformanceTest = testCase->m_isPerformanceTest; + result = testCase->m_performanceTestDurationTime; + resultMax = testCase->m_performanceMaxTime; +} + +void TestRunner::setCurrentTestCasePerformanceResult(bool isPerformanceTest, + std::chrono::system_clock::duration result, + std::chrono::system_clock::duration resultMax) +{ + TestCaseStruct* testCase = getCurrentTestCase(); + if (!testCase) + return; + + testCase->m_isPerformanceTest = isPerformanceTest; + testCase->m_performanceTestDurationTime = result; + testCase->m_performanceMaxTime = resultMax; +} + + +void TestRunner::CollectResult( + const std::string& id, + const std::string& description, + const TestResultsCollectorBase::FailStatus::Type status, + const std::string& reason, + const bool& isPerformanceTest, + const std::chrono::system_clock::duration& performanceTestDurationTime, + const std::chrono::system_clock::duration& performanceMaxTime) +{ + std::for_each(m_collectors.begin(), + m_collectors.end(), + [&](const TestResultsCollectors::value_type & collector) + { + collector.second->CollectResult(id, + description, + status, + reason, + isPerformanceTest, + performanceTestDurationTime, + performanceMaxTime); + }); +} + +void TestRunner::Banner() +{ + using namespace DPL::Colors::Text; + fprintf(stderr, + "%s%s%s\n", + BOLD_GREEN_BEGIN, + "DPL tests runner", + BOLD_GREEN_END); + fprintf(stderr, + "%s%s%s%s\n\n", + GREEN_BEGIN, + "Build: ", + __TIMESTAMP__, + GREEN_END); +} + +void TestRunner::InvalidArgs(const std::string& message) +{ + using namespace DPL::Colors::Text; + fprintf(stderr, + "%s%s%s\n", + BOLD_RED_BEGIN, + message.c_str(), + BOLD_RED_END); +} + +void TestRunner::Usage() +{ + fprintf(stderr, "Usage: runner [options]\n\n"); + fprintf(stderr, "Output type:\n"); + fprintf(stderr, " --output= --output= ...\n"); + fprintf(stderr, "\n possible output types:\n"); + for (std::string &type : TestResultsCollectorBase::GetCollectorsNames()) { + fprintf(stderr, " --output=%s\n", type.c_str()); + } + fprintf(stderr, "\n example:\n"); + fprintf(stderr, + " test-binary --output=text --output=xml --file=output.xml\n\n"); + fprintf(stderr, "Other parameters:\n"); + fprintf(stderr, + " --regexp='regexp'\t Only selected tests" + " which names match regexp run\n\n"); + fprintf(stderr, " --start=\tStart from concrete test id"); + fprintf(stderr, " --group=\t Run tests only from one group\n"); + fprintf(stderr, " --runignored\t Run also ignored tests\n"); + fprintf(stderr, " --list\t Show a list of Test IDs\n"); + fprintf(stderr, " --listgroups\t Show a list of Test Group names \n"); + fprintf(stderr, " --only-from-xml=\t Run only testcases specified in XML file \n" + " XML name is taken from attribute id=\"part1_part2\" as whole.\n" + " If part1 is not found (no _) then it is implicitily " + "set according to suite part1 from binary tests\n"); + fprintf( + stderr, + " --listingroup=\t Show a list of Test IDS in one group\n"); + fprintf(stderr, " --allowchildlogs\t Allow to print logs from child process on screen.\n"); + fprintf(stderr, " When active child process will be able to print logs on stdout and stderr.\n"); + fprintf(stderr, " Both descriptors will be closed after test.\n"); + fprintf(stderr, " --help\t This help\n\n"); + std::for_each(m_collectors.begin(), + m_collectors.end(), + [] (const TestResultsCollectors::value_type & collector) + { + fprintf(stderr, + "Output %s has specific args:\n", + collector.first.c_str()); + fprintf(stderr, + "%s\n", + collector.second-> + CollectorSpecificHelp().c_str()); + }); + fprintf(stderr, "For bug reporting, please write to:\n"); + fprintf(stderr, "\n"); +} + +int TestRunner::ExecTestRunner(int argc, char *argv[]) +{ + std::vector args; + for (int i = 0; i < argc; ++i) { + args.push_back(argv[i]); + } + return ExecTestRunner(args); +} + +void TestRunner::MarkAssertion() +{ + ++m_totalAssertions; +} + +int TestRunner::ExecTestRunner(ArgsList args) +{ + m_runIgnored = false; + // Parse command line + if (args.size() == 1) { + InvalidArgs(); + Usage(); + return -1; + } + + args.erase(args.begin()); + + bool showHelp = false; + bool justList = false; + std::vector xmlFiles; + + TestResultsCollectorBasePtr currentCollector; + + // Parse each argument + for(std::string &arg : args) + { + const std::string regexp = "--regexp="; + const std::string output = "--output="; + const std::string groupId = "--group="; + const std::string runIgnored = "--runignored"; + const std::string listCmd = "--list"; + const std::string startCmd = "--start="; + const std::string listGroupsCmd = "--listgroups"; + const std::string listInGroup = "--listingroup="; + const std::string allowChildLogs = "--allowchildlogs"; + const std::string onlyFromXML = "--only-from-xml="; + + if (currentCollector) { + if (currentCollector->ParseCollectorSpecificArg(arg)) { + continue; + } + } + + if (arg.find(startCmd) == 0) { + arg.erase(0, startCmd.length()); + for (auto &group : m_testGroups) { + for (auto &tc : group.second) { + if (tc.name == arg) { + m_startTestId = arg; + break; + } + } + if (!m_startTestId.empty()) { + break; + } + } + if (!m_startTestId.empty()) { + continue; + } + InvalidArgs(); + fprintf(stderr, "Start test id has not been found\n"); + Usage(); + return 0; + } else if (arg.find(groupId) == 0) { + arg.erase(0, groupId.length()); + TestCaseGroupMap::iterator found = m_testGroups.find(arg); + if (found != m_testGroups.end()) { + std::string name = found->first; + TestCaseStructList newList = found->second; + m_testGroups.clear(); + m_testGroups[name] = newList; + } else { + fprintf(stderr, "Group %s not found\n", arg.c_str()); + InvalidArgs(); + Usage(); + return -1; + } + } else if (arg == runIgnored) { + m_runIgnored = true; + } else if (arg == listCmd) { + justList = true; + } else if (arg == listGroupsCmd) { + for (auto &group : m_testGroups) { + printf("GR:%s\n", group.first.c_str()); + } + return 0; + } else if (arg.find(listInGroup) == 0) { + arg.erase(0, listInGroup.length()); + for (auto &test : m_testGroups[arg]) { + printf("ID:%s\n", test.name.c_str()); + } + return 0; + } else if (arg.find(allowChildLogs) == 0) { + arg.erase(0, allowChildLogs.length()); + m_allowChildLogs = true; + } else if (arg == "--help") { + showHelp = true; + } else if (arg.find(output) == 0) { + arg.erase(0, output.length()); + if (m_collectors.find(arg) != m_collectors.end()) { + InvalidArgs( + "Multiple outputs of the same type are not supported!"); + Usage(); + return -1; + } + currentCollector.reset(TestResultsCollectorBase::Create(arg)); + if (!currentCollector) { + InvalidArgs("Unsupported output type!"); + Usage(); + return -1; + } + m_collectors[arg] = currentCollector; + } else if (arg.find(regexp) == 0) { + arg.erase(0, regexp.length()); + if (arg.length() == 0) { + InvalidArgs(); + Usage(); + return -1; + } + + if (arg[0] == '\'' && arg[arg.length() - 1] == '\'') { + arg.erase(0); + arg.erase(arg.length() - 1); + } + + if (arg.length() == 0) { + InvalidArgs(); + Usage(); + return -1; + } + + pcrecpp::RE re(arg.c_str()); + for (auto &group : m_testGroups) { + TestCaseStructList newList; + for (auto &tc : group.second) + { + if (re.PartialMatch(tc.name)) { + newList.push_back(tc); + } + } + group.second = newList; + } + } else if(arg.find(onlyFromXML) == 0) { + arg.erase(0, onlyFromXML.length()); + if (arg.length() == 0) { + InvalidArgs(); + Usage(); + return -1; + } + + if (arg[0] == '\'' && arg[arg.length() - 1] == '\'') { + arg.erase(0); + arg.erase(arg.length() - 1); + } + + if (arg.length() == 0) { + InvalidArgs(); + Usage(); + return -1; + } + + xmlFiles.push_back(arg); + } else { + InvalidArgs(); + Usage(); + return -1; + } + } + + if(!xmlFiles.empty()) + { + if(!filterGroupsByXmls(xmlFiles)) + { + fprintf(stderr, "XML file is not correct\n"); + return 0; + } + } + + if(justList) + { + for (auto &group : m_testGroups) { + for (auto &tc : group.second) { + printf("ID:%s:%s\n", group.first.c_str(), tc.name.c_str()); + } + } + return 0; + } + + currentCollector.reset(); + + // Show help + if (showHelp) { + Usage(); + return 0; + } + + if (m_collectors.empty()) { + TestResultsCollectorBasePtr collector( + TestResultsCollectorBase::Create("text")); + m_collectors["text"] = collector; + } + + for (auto &collector : m_collectors) { + if (!collector.second->Configure()) { + fprintf(stderr, "Could not configure selected output"); + return 0; + } + } + + // Run tests + RunTests(); + + return 0; +} + +bool TestRunner::getRunIgnored() const +{ + return m_runIgnored; +} + +void TestRunner::Terminate() +{ + m_terminate = true; +} + +bool TestRunner::GetAllowChildLogs() +{ + return m_allowChildLogs; +} + +} +} // namespace DPL diff --git a/tests/framework/src/test_runner_child.cpp b/tests/framework/src/test_runner_child.cpp new file mode 100644 index 0000000..19ed08c --- /dev/null +++ b/tests/framework/src/test_runner_child.cpp @@ -0,0 +1,400 @@ +/* + * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file test_runner_child.cpp + * @author Bartlomiej Grzelewski (b.grzelewski@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of test runner + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace { +const int CHILD_TEST_FAIL = 0; +const int CHILD_TEST_PASS = 1; +const int CHILD_TEST_IGNORED = 2; + +const int MSG_TYPE_MESSAGE = 0; // sizeof(Message) + Message +const int MSG_TYPE_PERF_TIME = 1; // perfTime + maxTime + +int closeOutput() { + int devnull; + int retcode = -1; + if (-1 == (devnull = TEMP_FAILURE_RETRY(open("/dev/null", O_WRONLY)))) + return -1; + + // replace stdout with /dev/null + if (-1 == TEMP_FAILURE_RETRY(dup2(devnull, STDOUT_FILENO))) + goto end; + + // replace stderr with /dev/null + if (-1 == TEMP_FAILURE_RETRY(dup2(devnull, STDERR_FILENO))) + goto end; + + retcode = 0; + +end: + close(devnull); + return retcode; +} + +} // namespace anonymous + +namespace DPL { +namespace Test { + +PipeWrapper::PipeWrapper() +{ + if (-1 == pipe(m_pipefd)) { + m_pipefd[0] = PIPE_CLOSED; + m_pipefd[1] = PIPE_CLOSED; + } +} + +PipeWrapper::~PipeWrapper() +{ + closeHelp(0); + closeHelp(1); +} + +bool PipeWrapper::isReady() +{ + return m_pipefd[0] != PIPE_CLOSED || m_pipefd[1] != PIPE_CLOSED; +} + +void PipeWrapper::setUsage(Usage usage) +{ + if (usage == READONLY) { + closeHelp(1); + } + if (usage == WRITEONLY) { + closeHelp(0); + } +} + +PipeWrapper::Status PipeWrapper::send(int code, std::string &message) +{ + if (m_pipefd[1] == PIPE_CLOSED) { + return ERROR; + } + + std::ostringstream output; + output << toBinaryString(code); + output << toBinaryString(MSG_TYPE_MESSAGE); + output << toBinaryString(static_cast(message.size())); + output << message; + + std::string binary = output.str(); + int size = binary.size(); + + if ((writeHelp(&size, + sizeof(int)) == ERROR) || + (writeHelp(binary.c_str(), size) == ERROR)) + { + return ERROR; + } + return SUCCESS; +} + +PipeWrapper::Status PipeWrapper::sendTime(int code, + std::chrono::system_clock::duration time, + std::chrono::system_clock::duration timeMax) +{ + if (m_pipefd[1] == PIPE_CLOSED) { + return ERROR; + } + + std::ostringstream output; + output << toBinaryString(code); + output << toBinaryString(MSG_TYPE_PERF_TIME); + output << toBinaryString(time); + output << toBinaryString(timeMax); + + std::string binary = output.str(); + int size = binary.size(); + + if ((writeHelp(&size, + sizeof(int)) == ERROR) || + (writeHelp(binary.c_str(), size) == ERROR)) + { + return ERROR; + } + return SUCCESS; +} + +PipeWrapper::Status PipeWrapper::receive(int &code, + int &msgType, + std::string &data, + std::chrono::system_clock::duration &time, + std::chrono::system_clock::duration &timeMax, + time_t deadline) +{ + if (m_pipefd[0] == PIPE_CLOSED) { + return ERROR; + } + + int size; + Status ret; + + if ((ret = readHelp(&size, sizeof(int), deadline)) != SUCCESS) { + return ret; + } + + std::vector buffer; + buffer.resize(size); + + if ((ret = readHelp(&buffer[0], size, deadline)) != SUCCESS) { + return ret; + } + + try { + DPL::BinaryQueue queue; + queue.AppendCopy(&buffer[0], size); + + queue.FlattenConsume(&code, sizeof(int)); + queue.FlattenConsume(&msgType, sizeof(int)); + + switch (msgType) { + case MSG_TYPE_MESSAGE: + queue.FlattenConsume(&size, sizeof(int)); + + buffer.resize(size); + + queue.FlattenConsume(&buffer[0], size); + data.assign(buffer.begin(), buffer.end()); + break; + case MSG_TYPE_PERF_TIME: + queue.FlattenConsume(&time, sizeof(std::chrono::system_clock::duration)); + queue.FlattenConsume(&timeMax, sizeof(std::chrono::system_clock::duration)); + break; + default: + return ERROR; + } + } catch (DPL::BinaryQueue::Exception::Base &e) { + return ERROR; + } + return SUCCESS; +} + +void PipeWrapper::closeAll() +{ + closeHelp(0); + closeHelp(1); +} + +std::string PipeWrapper::toBinaryString(int data) +{ + char buffer[sizeof(int)]; + memcpy(buffer, &data, sizeof(int)); + return std::string(buffer, buffer + sizeof(int)); +} + +std::string PipeWrapper::toBinaryString(std::chrono::system_clock::duration data) +{ + char buffer[sizeof(std::chrono::system_clock::duration)]; + memcpy(buffer, &data, sizeof(std::chrono::system_clock::duration)); + return std::string(buffer, buffer + sizeof(std::chrono::system_clock::duration)); +} + +void PipeWrapper::closeHelp(int desc) +{ + if (m_pipefd[desc] != PIPE_CLOSED) { + TEMP_FAILURE_RETRY(close(m_pipefd[desc])); + m_pipefd[desc] = PIPE_CLOSED; + } +} + +PipeWrapper::Status PipeWrapper::writeHelp(const void *buffer, int size) +{ + int ready = 0; + const char *p = static_cast(buffer); + while (ready != size) { + int ret = write(m_pipefd[1], &p[ready], size - ready); + + if (ret == -1 && (errno == EAGAIN || errno == EINTR)) { + continue; + } + + if (ret == -1) { + closeHelp(1); + return ERROR; + } + + ready += ret; + } + return SUCCESS; +} + +PipeWrapper::Status PipeWrapper::readHelp(void *buf, int size, time_t deadline) +{ + int ready = 0; + char *buffer = static_cast(buf); + while (ready != size) { + time_t wait = deadline - time(0); + wait = wait < 1 ? 1 : wait; + pollfd fds = { m_pipefd[0], POLLIN, 0 }; + + int pollReturn = poll(&fds, 1, wait * 1000); + + if (pollReturn == 0) { + return TIMEOUT; // Timeout + } + + if (pollReturn < -1) { + return ERROR; + } + + int ret = read(m_pipefd[0], &buffer[ready], size - ready); + + if (ret == -1 && (errno == EAGAIN || errno == EINTR)) { + continue; + } + + if (ret == -1 || ret == 0) { + closeHelp(0); + return ERROR; + } + + ready += ret; + } + return SUCCESS; +} + +void RunChildProc(TestRunner::TestCase procChild) +{ + PipeWrapper pipe; + if (!pipe.isReady()) { + throw TestRunner::TestFailed("Pipe creation failed"); + } + + pid_t pid = fork(); + + if (pid == -1) { + throw TestRunner::TestFailed("Child creation failed"); + } + + if (pid != 0) { + // parent code + pipe.setUsage(PipeWrapper::READONLY); + + int code; + int msgType; + std::chrono::system_clock::duration time_m; + std::chrono::system_clock::duration timeMax_m; + std::string message; + + int pipeReturn = pipe.receive(code, msgType, message, time_m, timeMax_m, time(0) + 10); + + if (pipeReturn != PipeWrapper::SUCCESS) { // Timeout or reading error + pipe.closeAll(); + kill(pid, SIGKILL); + } + + int status; + waitpid(pid, &status, 0); + + if (pipeReturn == PipeWrapper::TIMEOUT) { + throw TestRunner::TestFailed("Timeout"); + } + + if (pipeReturn == PipeWrapper::ERROR) { + throw TestRunner::TestFailed("Reading pipe error"); + } + + if (code == CHILD_TEST_PASS && msgType == MSG_TYPE_PERF_TIME) { + DPL::Test::TestRunnerSingleton::Instance().setCurrentTestCasePerformanceResult(true, + time_m, + timeMax_m); + } + + if (code == CHILD_TEST_FAIL) { + throw TestRunner::TestFailed(message); + } else if (code == CHILD_TEST_IGNORED) { + throw TestRunner::Ignored(message); + } + } else { + // child code + + // End Runner after current test + TestRunnerSingleton::Instance().Terminate(); + + int code = CHILD_TEST_PASS; + std::string msg; + bool isPerformanceTest; + std::chrono::system_clock::duration time_m; + std::chrono::system_clock::duration timeMax_m; + + bool allowLogs = TestRunnerSingleton::Instance().GetAllowChildLogs(); + + close(STDIN_FILENO); + if (!allowLogs) { + closeOutput(); // if fails nothing we can do + } + + pipe.setUsage(PipeWrapper::WRITEONLY); + + try { + procChild(); + } catch (const DPL::Test::TestRunner::TestFailed &e) { + msg = e.GetMessage(); + code = CHILD_TEST_FAIL; + } catch (const DPL::Test::TestRunner::Ignored &e) { + msg = e.GetMessage(); + code = CHILD_TEST_IGNORED; + } catch (...) { // catch all exception generated by "user" code + msg = "unhandled exeception"; + code = CHILD_TEST_FAIL; + } + + if (allowLogs) { + closeOutput(); + } + + DPL::Test::TestRunnerSingleton::Instance().getCurrentTestCasePerformanceResult(isPerformanceTest, + time_m, + timeMax_m); + + if (code == CHILD_TEST_PASS && isPerformanceTest){ + pipe.sendTime(code, + time_m, + timeMax_m); + } else { + pipe.send(code, msg); + } + } +} +} // namespace Test +} // namespace DPL diff --git a/tests/framework/src/test_runner_multiprocess.cpp b/tests/framework/src/test_runner_multiprocess.cpp new file mode 100644 index 0000000..881e1c1 --- /dev/null +++ b/tests/framework/src/test_runner_multiprocess.cpp @@ -0,0 +1,275 @@ +/* + * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @file test_runner_multiprocess.cpp + * @author Marcin Niesluchowski (m.niesluchow@samsung.com) + * @version 1.0 + * @brief This file is the implementation file of multiprocess test runner + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace { + +const int MULTI_TEST_ERROR = -1; +const int MULTI_TEST_PASS = 0; +const int MULTI_TEST_FAILED = 1; +const int MULTI_TEST_IGNORED = 2; +const int MULTI_TEST_INTERNAL = 3; + +} + +namespace DPL { +namespace Test { + +SimplePipeWrapper::SimplePipeWrapper() +: PipeWrapper() +{ + +} + +SimplePipeWrapper::~SimplePipeWrapper() +{ + +} + +PipeWrapper::Status SimplePipeWrapper::send(std::string &message) +{ + if (m_pipefd[1] == PIPE_CLOSED) { + return ERROR; + } + + if (message.size() > PIPE_BUF-1) { + return ERROR; + } + + char buffer[PIPE_BUF] = { 0 }; + + + for(unsigned int i = 0; i < message.size(); ++i) { + buffer[i] = message[i]; + } + + return writeHelp(buffer, PIPE_BUF); +} + +PipeWrapper::Status SimplePipeWrapper::receive(std::string &data, bool &empty, time_t deadline) +{ + if (m_pipefd[0] == PIPE_CLOSED) { + return ERROR; + } + + empty = false; + + data.resize(PIPE_BUF); + + char buffer[PIPE_BUF] = { 0 }; + + int ready = 0; + while (ready != PIPE_BUF) { + time_t wait = deadline - time(0); + wait = wait < 1 ? 1 : wait; + pollfd fds = { m_pipefd[0], POLLIN, 0 }; + + int pollReturn = poll(&fds, 1, wait * 1000); + + if (pollReturn == 0) { + return TIMEOUT; // Timeout + } + + if (pollReturn < -1) { + return ERROR; + } + int ret = read(m_pipefd[0], &buffer[ready], PIPE_BUF - ready); + if (ret == -1 && (errno == EAGAIN || errno == EINTR)) { + continue; + } + + if (ret == -1) { + closeHelp(0); + return ERROR; + } + if (ret == 0) { + empty = true; + break; + } + + ready += ret; + } + + + for(unsigned int i = 0; i < PIPE_BUF; ++i){ + if(buffer[i] == 0) { + data.resize(i); + return SUCCESS; + } + data[i] = buffer[i]; + } + + return ERROR; +} + +void RunMultiProc(TestRunner::TestCase procMulti) +{ + SimplePipeWrapper pipe; + int code = MULTI_TEST_PASS; + std::string msg = ""; + int pipeReturn; + + int waitStatus; + + pid_t top_pid = getpid(); + + if (!pipe.isReady()) { + throw TestRunner::TestFailed("Pipe creation failed"); + } + // pipe + + try { + procMulti(); + } catch (const TestRunner::TestFailed &e) { + code = MULTI_TEST_FAILED; + msg = e.GetMessage(); + } catch (const TestRunner::Ignored &e) { + code = MULTI_TEST_IGNORED; + msg = e.GetMessage(); + } catch (const DPL::Exception &e) { + code = MULTI_TEST_INTERNAL; + msg = "DPL exception:" + e.GetMessage(); + } catch (const std::exception &) { + code = MULTI_TEST_INTERNAL; + msg = "std exception"; + } catch (...) { + // Unknown exception failure + code = MULTI_TEST_INTERNAL; + msg = "unknown exception"; + } + + while (true) { + pid_t child_pid = wait(&waitStatus); + if (child_pid == -1) { + if (errno == ECHILD) { + if (top_pid == getpid()) { + std::string recMsg=""; + + pipe.setUsage(PipeWrapper::READONLY); + + bool empty=false; + while(true) { + pipeReturn = pipe.receive(recMsg, empty, time(0) + 10); + + if (empty) { + break; + } + if (pipeReturn == PipeWrapper::ERROR) { + pipe.closeAll(); + throw TestRunner::TestFailed("Reading pipe error"); + } else if (pipeReturn == PipeWrapper::TIMEOUT) { + pipe.closeAll(); + throw TestRunner::TestFailed("Timeout error"); + } + msg = msg + "\n" + recMsg; + } + pipe.closeAll(); + + switch(code) { + case MULTI_TEST_PASS: + return; + case MULTI_TEST_FAILED: + throw TestRunner::TestFailed(msg); + case MULTI_TEST_IGNORED: + throw TestRunner::Ignored(msg); + case MULTI_TEST_INTERNAL: + throw TestRunner::TestFailed(msg); + default: + throw TestRunner::TestFailed(msg); + } + } else { + pipe.setUsage(PipeWrapper::WRITEONLY); + + pipeReturn = pipe.send(msg); + + if (pipeReturn == PipeWrapper::ERROR) { + pipe.closeAll(); + code = MULTI_TEST_ERROR; + } + + exit(code); + } + } + } else if (WIFEXITED(waitStatus)) { + if ((signed char)WEXITSTATUS(waitStatus) == MULTI_TEST_FAILED) { + switch (code) { + case MULTI_TEST_PASS: + code = MULTI_TEST_FAILED; + break; + case MULTI_TEST_FAILED: + break; + case MULTI_TEST_IGNORED: + code = MULTI_TEST_FAILED; + break; + case MULTI_TEST_INTERNAL: + break; + default: + break; + } + } else if ((signed char)WEXITSTATUS(waitStatus) == MULTI_TEST_IGNORED) { + switch (code) { + case MULTI_TEST_PASS: + code = MULTI_TEST_IGNORED; + break; + case MULTI_TEST_FAILED: + break; + case MULTI_TEST_IGNORED: + break; + case MULTI_TEST_INTERNAL: + break; + default: + break; + } + } else if ((signed char)WEXITSTATUS(waitStatus) == MULTI_TEST_INTERNAL) { + switch (code) { + case MULTI_TEST_PASS: + code = MULTI_TEST_INTERNAL; + break; + case MULTI_TEST_FAILED: + code = MULTI_TEST_INTERNAL; + break; + case MULTI_TEST_IGNORED: + code = MULTI_TEST_INTERNAL; + break; + case MULTI_TEST_INTERNAL: + break; + default: + break; + } + } else if ((signed char)WEXITSTATUS(waitStatus) != MULTI_TEST_PASS) { + code = MULTI_TEST_ERROR; + msg = "PROCESS BAD CODE RETURN"; + } + } + } +} +} // namespace Test +} // namespace DPL diff --git a/tests/libprivilege-control-tests/CMakeLists.txt b/tests/libprivilege-control-tests/CMakeLists.txt index 9bd88ba..7a6e956 100644 --- a/tests/libprivilege-control-tests/CMakeLists.txt +++ b/tests/libprivilege-control-tests/CMakeLists.txt @@ -61,7 +61,6 @@ SET(LPC_TARGET_TEST "libprivilege-control-test") PKG_CHECK_MODULES(LPC_TARGET_DEP libsmack libprivilege-control - dpl-test-efl sqlite3 libtzplatform-config REQUIRED @@ -99,6 +98,7 @@ ADD_EXECUTABLE(${LPC_TARGET_TEST} ${LPC_TARGET_TEST_SOURCES}) #linker directories TARGET_LINK_LIBRARIES(${LPC_TARGET_TEST} ${LPC_TARGET_DEP_LIBRARIES} + dpl-test-framework tests-common -lcrypt ) diff --git a/tests/libsmack-tests/CMakeLists.txt b/tests/libsmack-tests/CMakeLists.txt index cf1da99..799d19b 100644 --- a/tests/libsmack-tests/CMakeLists.txt +++ b/tests/libsmack-tests/CMakeLists.txt @@ -23,7 +23,6 @@ SET(TARGET_TEST "libsmack-test") #dependencies PKG_CHECK_MODULES(TARGET_DEP libsmack - dpl-test-efl REQUIRED ) @@ -51,6 +50,7 @@ ADD_EXECUTABLE(${TARGET_TEST} ${TARGET_TEST_SOURCES}) #linker directories TARGET_LINK_LIBRARIES(${TARGET_TEST} ${TARGET_DEP_LIBRARIES} + dpl-test-framework tests-common ) diff --git a/tests/security-manager-tests/CMakeLists.txt b/tests/security-manager-tests/CMakeLists.txt index 066bfcb..ae894b5 100644 --- a/tests/security-manager-tests/CMakeLists.txt +++ b/tests/security-manager-tests/CMakeLists.txt @@ -27,8 +27,7 @@ PKG_CHECK_MODULES(SEC_MGR_TESTS_DEP libprivilege-control security-manager libtzplatform-config - sqlite3 - dpl-test-efl) + sqlite3) SET(TARGET_SEC_MGR_TESTS "security-manager-tests") @@ -53,7 +52,9 @@ ADD_EXECUTABLE(${TARGET_SEC_MGR_TESTS} ${SEC_MGR_SOURCES}) TARGET_LINK_LIBRARIES(${TARGET_SEC_MGR_TESTS} ${SEC_MGR_TESTS_DEP_LIBRARIES} - tests-common) + dpl-test-framework + tests-common + ) INSTALL(TARGETS ${TARGET_SEC_MGR_TESTS} DESTINATION /usr/bin) diff --git a/tests/security-server-tests/CMakeLists.txt b/tests/security-server-tests/CMakeLists.txt index b22e3ca..d0497a9 100644 --- a/tests/security-server-tests/CMakeLists.txt +++ b/tests/security-server-tests/CMakeLists.txt @@ -26,7 +26,6 @@ PKG_CHECK_MODULES(SEC_SRV_TESTS_DEP libsmack libprivilege-control security-server - dpl-test-efl dlog dbus-1 dbus-glib-1 @@ -117,38 +116,54 @@ ADD_EXECUTABLE(${TARGET_SEC_SRV_MEASURER} ${SEC_SRV_MEASURER_SOURCES}) TARGET_LINK_LIBRARIES(${TARGET_SEC_SRV_CLIENT_SMACK_TESTS} ${SEC_SRV_TESTS_DEP_LIBRARIES} - tests-common) + dpl-test-framework + tests-common + ) TARGET_LINK_LIBRARIES(${TARGET_SEC_SRV_TC_SERVER_TESTS} ${TARGET_SEC_SRV_COMMON} ${SEC_SRV_TESTS_DEP_LIBRARIES} - tests-common) + dpl-test-framework + tests-common + ) TARGET_LINK_LIBRARIES(${TARGET_SEC_SRV_PWD_TESTS} ${TARGET_SEC_SRV_COMMON} ${SEC_SRV_TESTS_DEP_LIBRARIES} - tests-common) + dpl-test-framework + tests-common + ) TARGET_LINK_LIBRARIES(${TARGET_SEC_SRV_PRIVILEGE_TESTS} ${SEC_SRV_TESTS_DEP_LIBRARIES} - tests-common) + dpl-test-framework + tests-common + ) TARGET_LINK_LIBRARIES(${TARGET_SEC_SRV_STRESS_TESTS} ${SEC_SRV_TESTS_DEP_LIBRARIES} - tests-common) + dpl-test-framework + tests-common + ) TARGET_LINK_LIBRARIES(${TARGET_SEC_SRV_MT_TESTS} ${SEC_SRV_TESTS_DEP_LIBRARIES} - tests-common) + dpl-test-framework + tests-common + ) TARGET_LINK_LIBRARIES(${TARGET_SEC_SRV_DBUS_TESTS} ${SEC_SRV_TESTS_DEP_LIBRARIES} - tests-common) + dpl-test-framework + tests-common + ) TARGET_LINK_LIBRARIES(${TARGET_SEC_SRV_MEASURER} ${TARGET_SEC_SRV_COMMON} ${SEC_SRV_TESTS_DEP_LIBRARIES} - tests-common) + dpl-test-framework + tests-common + ) # Installation diff --git a/tests/security-server-tests/security_server_measurer_API_speed.cpp b/tests/security-server-tests/security_server_measurer_API_speed.cpp index a74625c..db42e3a 100644 --- a/tests/security-server-tests/security_server_measurer_API_speed.cpp +++ b/tests/security-server-tests/security_server_measurer_API_speed.cpp @@ -29,7 +29,6 @@ */ #include -#include #include #include #include