diff --git a/include/testing/license.txt b/include/testing/license.txt new file mode 100644 index 000000000..d66fba53e --- /dev/null +++ b/include/testing/license.txt @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2007-14 Mike Karlesky, Mark VanderVoord, Greg Williams + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/include/testing/unity.h b/include/testing/unity.h new file mode 100644 index 000000000..d1decd042 --- /dev/null +++ b/include/testing/unity.h @@ -0,0 +1,272 @@ +/* ========================================== + Unity Project - A Test Framework for C + Copyright (c) 2007-14 Mike Karlesky, Mark VanderVoord, Greg Williams + [Released under MIT License. Please refer to license.txt for details] +========================================== */ + +#ifndef UNITY_FRAMEWORK_H +#define UNITY_FRAMEWORK_H +#define UNITY + +#include "unity_internals.h" + +//------------------------------------------------------- +// Configuration Options +//------------------------------------------------------- +// All options described below should be passed as a compiler flag to all files using Unity. If you must add #defines, place them BEFORE the #include above. + +// Integers/longs/pointers +// - Unity attempts to automatically discover your integer sizes +// - define UNITY_EXCLUDE_STDINT_H to stop attempting to look in +// - define UNITY_EXCLUDE_LIMITS_H to stop attempting to look in +// - define UNITY_EXCLUDE_SIZEOF to stop attempting to use sizeof in macros +// - If you cannot use the automatic methods above, you can force Unity by using these options: +// - define UNITY_SUPPORT_64 +// - define UNITY_INT_WIDTH +// - UNITY_LONG_WIDTH +// - UNITY_POINTER_WIDTH + +// Floats +// - define UNITY_EXCLUDE_FLOAT to disallow floating point comparisons +// - define UNITY_FLOAT_PRECISION to specify the precision to use when doing TEST_ASSERT_EQUAL_FLOAT +// - define UNITY_FLOAT_TYPE to specify doubles instead of single precision floats +// - define UNITY_FLOAT_VERBOSE to print floating point values in errors (uses sprintf) +// - define UNITY_INCLUDE_DOUBLE to allow double floating point comparisons +// - define UNITY_EXCLUDE_DOUBLE to disallow double floating point comparisons (default) +// - define UNITY_DOUBLE_PRECISION to specify the precision to use when doing TEST_ASSERT_EQUAL_DOUBLE +// - define UNITY_DOUBLE_TYPE to specify something other than double +// - define UNITY_DOUBLE_VERBOSE to print floating point values in errors (uses sprintf) + +// Output +// - by default, Unity prints to standard out with putchar. define UNITY_OUTPUT_CHAR(a) with a different function if desired + +// Optimization +// - by default, line numbers are stored in unsigned shorts. Define UNITY_LINE_TYPE with a different type if your files are huge +// - by default, test and failure counters are unsigned shorts. Define UNITY_COUNTER_TYPE with a different type if you want to save space or have more than 65535 Tests. + +// Test Cases +// - define UNITY_SUPPORT_TEST_CASES to include the TEST_CASE macro, though really it's mostly about the runner generator script + +// Parameterized Tests +// - you'll want to create a define of TEST_CASE(...) which basically evaluates to nothing + +//------------------------------------------------------- +// Basic Fail and Ignore +//------------------------------------------------------- + +#define TEST_FAIL_MESSAGE(message) UNITY_TEST_FAIL(__LINE__, message) +#define TEST_FAIL() UNITY_TEST_FAIL(__LINE__, NULL) +#define TEST_IGNORE_MESSAGE(message) UNITY_TEST_IGNORE(__LINE__, message) +#define TEST_IGNORE() UNITY_TEST_IGNORE(__LINE__, NULL) +#define TEST_ONLY() + +//------------------------------------------------------- +// Test Asserts (simple) +//------------------------------------------------------- + +//Boolean +#define TEST_ASSERT(condition) UNITY_TEST_ASSERT( (condition), __LINE__, " Expression Evaluated To FALSE") +#define TEST_ASSERT_TRUE(condition) UNITY_TEST_ASSERT( (condition), __LINE__, " Expected TRUE Was FALSE") +#define TEST_ASSERT_UNLESS(condition) UNITY_TEST_ASSERT( !(condition), __LINE__, " Expression Evaluated To TRUE") +#define TEST_ASSERT_FALSE(condition) UNITY_TEST_ASSERT( !(condition), __LINE__, " Expected FALSE Was TRUE") +#define TEST_ASSERT_NULL(pointer) UNITY_TEST_ASSERT_NULL( (pointer), __LINE__, " Expected NULL") +#define TEST_ASSERT_NOT_NULL(pointer) UNITY_TEST_ASSERT_NOT_NULL((pointer), __LINE__, " Expected Non-NULL") + +//Integers (of all sizes) +#define TEST_ASSERT_EQUAL_INT(expected, actual) UNITY_TEST_ASSERT_EQUAL_INT((expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_INT8(expected, actual) UNITY_TEST_ASSERT_EQUAL_INT8((expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_INT16(expected, actual) UNITY_TEST_ASSERT_EQUAL_INT16((expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_INT32(expected, actual) UNITY_TEST_ASSERT_EQUAL_INT32((expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_INT64(expected, actual) UNITY_TEST_ASSERT_EQUAL_INT64((expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_EQUAL(expected, actual) UNITY_TEST_ASSERT_EQUAL_INT((expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_NOT_EQUAL(expected, actual) UNITY_TEST_ASSERT(((expected) != (actual)), __LINE__, " Expected Not-Equal") +#define TEST_ASSERT_EQUAL_UINT(expected, actual) UNITY_TEST_ASSERT_EQUAL_UINT( (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_UINT8(expected, actual) UNITY_TEST_ASSERT_EQUAL_UINT8( (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_UINT16(expected, actual) UNITY_TEST_ASSERT_EQUAL_UINT16( (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_UINT32(expected, actual) UNITY_TEST_ASSERT_EQUAL_UINT32( (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_UINT64(expected, actual) UNITY_TEST_ASSERT_EQUAL_UINT64( (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_HEX(expected, actual) UNITY_TEST_ASSERT_EQUAL_HEX32((expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_HEX8(expected, actual) UNITY_TEST_ASSERT_EQUAL_HEX8( (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_HEX16(expected, actual) UNITY_TEST_ASSERT_EQUAL_HEX16((expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_HEX32(expected, actual) UNITY_TEST_ASSERT_EQUAL_HEX32((expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_HEX64(expected, actual) UNITY_TEST_ASSERT_EQUAL_HEX64((expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_BITS(mask, expected, actual) UNITY_TEST_ASSERT_BITS((mask), (expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_BITS_HIGH(mask, actual) UNITY_TEST_ASSERT_BITS((mask), (_UU32)(-1), (actual), __LINE__, NULL) +#define TEST_ASSERT_BITS_LOW(mask, actual) UNITY_TEST_ASSERT_BITS((mask), (_UU32)(0), (actual), __LINE__, NULL) +#define TEST_ASSERT_BIT_HIGH(bit, actual) UNITY_TEST_ASSERT_BITS(((_UU32)1 << bit), (_UU32)(-1), (actual), __LINE__, NULL) +#define TEST_ASSERT_BIT_LOW(bit, actual) UNITY_TEST_ASSERT_BITS(((_UU32)1 << bit), (_UU32)(0), (actual), __LINE__, NULL) + +//Integer Ranges (of all sizes) +#define TEST_ASSERT_INT_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_INT_WITHIN(delta, expected, actual, __LINE__, NULL) +#define TEST_ASSERT_INT8_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_INT8_WITHIN(delta, expected, actual, __LINE__, NULL) +#define TEST_ASSERT_INT16_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_INT16_WITHIN(delta, expected, actual, __LINE__, NULL) +#define TEST_ASSERT_INT32_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_INT32_WITHIN(delta, expected, actual, __LINE__, NULL) +#define TEST_ASSERT_INT64_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_INT64_WITHIN(delta, expected, actual, __LINE__, NULL) +#define TEST_ASSERT_UINT_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_UINT_WITHIN(delta, expected, actual, __LINE__, NULL) +#define TEST_ASSERT_UINT8_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_UINT8_WITHIN(delta, expected, actual, __LINE__, NULL) +#define TEST_ASSERT_UINT16_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_UINT16_WITHIN(delta, expected, actual, __LINE__, NULL) +#define TEST_ASSERT_UINT32_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_UINT32_WITHIN(delta, expected, actual, __LINE__, NULL) +#define TEST_ASSERT_UINT64_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_UINT64_WITHIN(delta, expected, actual, __LINE__, NULL) +#define TEST_ASSERT_HEX_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_HEX32_WITHIN(delta, expected, actual, __LINE__, NULL) +#define TEST_ASSERT_HEX8_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_HEX8_WITHIN(delta, expected, actual, __LINE__, NULL) +#define TEST_ASSERT_HEX16_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_HEX16_WITHIN(delta, expected, actual, __LINE__, NULL) +#define TEST_ASSERT_HEX32_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_HEX32_WITHIN(delta, expected, actual, __LINE__, NULL) +#define TEST_ASSERT_HEX64_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_HEX64_WITHIN(delta, expected, actual, __LINE__, NULL) + +//Structs and Strings +#define TEST_ASSERT_EQUAL_PTR(expected, actual) UNITY_TEST_ASSERT_EQUAL_PTR((expected), (actual), __LINE__, NULL) +#define TEST_ASSERT_EQUAL_STRING(expected, actual) UNITY_TEST_ASSERT_EQUAL_STRING(expected, actual, __LINE__, NULL) +#define TEST_ASSERT_EQUAL_MEMORY(expected, actual, len) UNITY_TEST_ASSERT_EQUAL_MEMORY(expected, actual, len, __LINE__, NULL) + +//Arrays +#define TEST_ASSERT_EQUAL_INT_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_INT_ARRAY(expected, actual, num_elements, __LINE__, NULL) +#define TEST_ASSERT_EQUAL_INT8_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_INT8_ARRAY(expected, actual, num_elements, __LINE__, NULL) +#define TEST_ASSERT_EQUAL_INT16_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_INT16_ARRAY(expected, actual, num_elements, __LINE__, NULL) +#define TEST_ASSERT_EQUAL_INT32_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_INT32_ARRAY(expected, actual, num_elements, __LINE__, NULL) +#define TEST_ASSERT_EQUAL_INT64_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_INT64_ARRAY(expected, actual, num_elements, __LINE__, NULL) +#define TEST_ASSERT_EQUAL_UINT_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_UINT_ARRAY(expected, actual, num_elements, __LINE__, NULL) +#define TEST_ASSERT_EQUAL_UINT8_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_UINT8_ARRAY(expected, actual, num_elements, __LINE__, NULL) +#define TEST_ASSERT_EQUAL_UINT16_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_UINT16_ARRAY(expected, actual, num_elements, __LINE__, NULL) +#define TEST_ASSERT_EQUAL_UINT32_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_UINT32_ARRAY(expected, actual, num_elements, __LINE__, NULL) +#define TEST_ASSERT_EQUAL_UINT64_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_UINT64_ARRAY(expected, actual, num_elements, __LINE__, NULL) +#define TEST_ASSERT_EQUAL_HEX_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_HEX32_ARRAY(expected, actual, num_elements, __LINE__, NULL) +#define TEST_ASSERT_EQUAL_HEX8_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_HEX8_ARRAY(expected, actual, num_elements, __LINE__, NULL) +#define TEST_ASSERT_EQUAL_HEX16_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_HEX16_ARRAY(expected, actual, num_elements, __LINE__, NULL) +#define TEST_ASSERT_EQUAL_HEX32_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_HEX32_ARRAY(expected, actual, num_elements, __LINE__, NULL) +#define TEST_ASSERT_EQUAL_HEX64_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_HEX64_ARRAY(expected, actual, num_elements, __LINE__, NULL) +#define TEST_ASSERT_EQUAL_PTR_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_PTR_ARRAY(expected, actual, num_elements, __LINE__, NULL) +#define TEST_ASSERT_EQUAL_STRING_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_STRING_ARRAY(expected, actual, num_elements, __LINE__, NULL) +#define TEST_ASSERT_EQUAL_MEMORY_ARRAY(expected, actual, len, num_elements) UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY(expected, actual, len, num_elements, __LINE__, NULL) + +//Floating Point (If Enabled) +#define TEST_ASSERT_FLOAT_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_FLOAT_WITHIN(delta, expected, actual, __LINE__, NULL) +#define TEST_ASSERT_EQUAL_FLOAT(expected, actual) UNITY_TEST_ASSERT_EQUAL_FLOAT(expected, actual, __LINE__, NULL) +#define TEST_ASSERT_EQUAL_FLOAT_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_FLOAT_ARRAY(expected, actual, num_elements, __LINE__, NULL) +#define TEST_ASSERT_FLOAT_IS_INF(actual) UNITY_TEST_ASSERT_FLOAT_IS_INF(actual, __LINE__, NULL) +#define TEST_ASSERT_FLOAT_IS_NEG_INF(actual) UNITY_TEST_ASSERT_FLOAT_IS_NEG_INF(actual, __LINE__, NULL) +#define TEST_ASSERT_FLOAT_IS_NAN(actual) UNITY_TEST_ASSERT_FLOAT_IS_NAN(actual, __LINE__, NULL) +#define TEST_ASSERT_FLOAT_IS_DETERMINATE(actual) UNITY_TEST_ASSERT_FLOAT_IS_DETERMINATE(actual, __LINE__, NULL) +#define TEST_ASSERT_FLOAT_IS_NOT_INF(actual) UNITY_TEST_ASSERT_FLOAT_IS_NOT_INF(actual, __LINE__, NULL) +#define TEST_ASSERT_FLOAT_IS_NOT_NEG_INF(actual) UNITY_TEST_ASSERT_FLOAT_IS_NOT_NEG_INF(actual, __LINE__, NULL) +#define TEST_ASSERT_FLOAT_IS_NOT_NAN(actual) UNITY_TEST_ASSERT_FLOAT_IS_NOT_NAN(actual, __LINE__, NULL) +#define TEST_ASSERT_FLOAT_IS_NOT_DETERMINATE(actual) UNITY_TEST_ASSERT_FLOAT_IS_NOT_DETERMINATE(actual, __LINE__, NULL) + +//Double (If Enabled) +#define TEST_ASSERT_DOUBLE_WITHIN(delta, expected, actual) UNITY_TEST_ASSERT_DOUBLE_WITHIN(delta, expected, actual, __LINE__, NULL) +#define TEST_ASSERT_EQUAL_DOUBLE(expected, actual) UNITY_TEST_ASSERT_EQUAL_DOUBLE(expected, actual, __LINE__, NULL) +#define TEST_ASSERT_EQUAL_DOUBLE_ARRAY(expected, actual, num_elements) UNITY_TEST_ASSERT_EQUAL_DOUBLE_ARRAY(expected, actual, num_elements, __LINE__, NULL) +#define TEST_ASSERT_DOUBLE_IS_INF(actual) UNITY_TEST_ASSERT_DOUBLE_IS_INF(actual, __LINE__, NULL) +#define TEST_ASSERT_DOUBLE_IS_NEG_INF(actual) UNITY_TEST_ASSERT_DOUBLE_IS_NEG_INF(actual, __LINE__, NULL) +#define TEST_ASSERT_DOUBLE_IS_NAN(actual) UNITY_TEST_ASSERT_DOUBLE_IS_NAN(actual, __LINE__, NULL) +#define TEST_ASSERT_DOUBLE_IS_DETERMINATE(actual) UNITY_TEST_ASSERT_DOUBLE_IS_DETERMINATE(actual, __LINE__, NULL) +#define TEST_ASSERT_DOUBLE_IS_NOT_INF(actual) UNITY_TEST_ASSERT_DOUBLE_IS_NOT_INF(actual, __LINE__, NULL) +#define TEST_ASSERT_DOUBLE_IS_NOT_NEG_INF(actual) UNITY_TEST_ASSERT_DOUBLE_IS_NOT_NEG_INF(actual, __LINE__, NULL) +#define TEST_ASSERT_DOUBLE_IS_NOT_NAN(actual) UNITY_TEST_ASSERT_DOUBLE_IS_NOT_NAN(actual, __LINE__, NULL) +#define TEST_ASSERT_DOUBLE_IS_NOT_DETERMINATE(actual) UNITY_TEST_ASSERT_DOUBLE_IS_NOT_DETERMINATE(actual, __LINE__, NULL) + +//------------------------------------------------------- +// Test Asserts (with additional messages) +//------------------------------------------------------- + +//Boolean +#define TEST_ASSERT_MESSAGE(condition, message) UNITY_TEST_ASSERT( (condition), __LINE__, message) +#define TEST_ASSERT_TRUE_MESSAGE(condition, message) UNITY_TEST_ASSERT( (condition), __LINE__, message) +#define TEST_ASSERT_UNLESS_MESSAGE(condition, message) UNITY_TEST_ASSERT( !(condition), __LINE__, message) +#define TEST_ASSERT_FALSE_MESSAGE(condition, message) UNITY_TEST_ASSERT( !(condition), __LINE__, message) +#define TEST_ASSERT_NULL_MESSAGE(pointer, message) UNITY_TEST_ASSERT_NULL( (pointer), __LINE__, message) +#define TEST_ASSERT_NOT_NULL_MESSAGE(pointer, message) UNITY_TEST_ASSERT_NOT_NULL((pointer), __LINE__, message) + +//Integers (of all sizes) +#define TEST_ASSERT_EQUAL_INT_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_INT((expected), (actual), __LINE__, message) +#define TEST_ASSERT_EQUAL_INT8_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_INT8((expected), (actual), __LINE__, message) +#define TEST_ASSERT_EQUAL_INT16_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_INT16((expected), (actual), __LINE__, message) +#define TEST_ASSERT_EQUAL_INT32_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_INT32((expected), (actual), __LINE__, message) +#define TEST_ASSERT_EQUAL_INT64_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_INT64((expected), (actual), __LINE__, message) +#define TEST_ASSERT_EQUAL_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_INT((expected), (actual), __LINE__, message) +#define TEST_ASSERT_NOT_EQUAL_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT(((expected) != (actual)), __LINE__, message) +#define TEST_ASSERT_EQUAL_UINT_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_UINT( (expected), (actual), __LINE__, message) +#define TEST_ASSERT_EQUAL_UINT8_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_UINT8( (expected), (actual), __LINE__, message) +#define TEST_ASSERT_EQUAL_UINT16_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_UINT16( (expected), (actual), __LINE__, message) +#define TEST_ASSERT_EQUAL_UINT32_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_UINT32( (expected), (actual), __LINE__, message) +#define TEST_ASSERT_EQUAL_UINT64_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_UINT64( (expected), (actual), __LINE__, message) +#define TEST_ASSERT_EQUAL_HEX_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_HEX32((expected), (actual), __LINE__, message) +#define TEST_ASSERT_EQUAL_HEX8_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_HEX8( (expected), (actual), __LINE__, message) +#define TEST_ASSERT_EQUAL_HEX16_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_HEX16((expected), (actual), __LINE__, message) +#define TEST_ASSERT_EQUAL_HEX32_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_HEX32((expected), (actual), __LINE__, message) +#define TEST_ASSERT_EQUAL_HEX64_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_HEX64((expected), (actual), __LINE__, message) +#define TEST_ASSERT_BITS_MESSAGE(mask, expected, actual, message) UNITY_TEST_ASSERT_BITS((mask), (expected), (actual), __LINE__, message) +#define TEST_ASSERT_BITS_HIGH_MESSAGE(mask, actual, message) UNITY_TEST_ASSERT_BITS((mask), (_UU32)(-1), (actual), __LINE__, message) +#define TEST_ASSERT_BITS_LOW_MESSAGE(mask, actual, message) UNITY_TEST_ASSERT_BITS((mask), (_UU32)(0), (actual), __LINE__, message) +#define TEST_ASSERT_BIT_HIGH_MESSAGE(bit, actual, message) UNITY_TEST_ASSERT_BITS(((_UU32)1 << bit), (_UU32)(-1), (actual), __LINE__, message) +#define TEST_ASSERT_BIT_LOW_MESSAGE(bit, actual, message) UNITY_TEST_ASSERT_BITS(((_UU32)1 << bit), (_UU32)(0), (actual), __LINE__, message) + +//Integer Ranges (of all sizes) +#define TEST_ASSERT_INT_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_INT_WITHIN(delta, expected, actual, __LINE__, message) +#define TEST_ASSERT_INT8_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_INT8_WITHIN(delta, expected, actual, __LINE__, message) +#define TEST_ASSERT_INT16_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_INT16_WITHIN(delta, expected, actual, __LINE__, message) +#define TEST_ASSERT_INT32_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_INT32_WITHIN(delta, expected, actual, __LINE__, message) +#define TEST_ASSERT_INT64_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_INT64_WITHIN(delta, expected, actual, __LINE__, message) +#define TEST_ASSERT_UINT_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_UINT_WITHIN(delta, expected, actual, __LINE__, message) +#define TEST_ASSERT_UINT8_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_UINT8_WITHIN(delta, expected, actual, __LINE__, message) +#define TEST_ASSERT_UINT16_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_UINT16_WITHIN(delta, expected, actual, __LINE__, message) +#define TEST_ASSERT_UINT32_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_UINT32_WITHIN(delta, expected, actual, __LINE__, message) +#define TEST_ASSERT_UINT64_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_UINT64_WITHIN(delta, expected, actual, __LINE__, message) +#define TEST_ASSERT_HEX_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_HEX32_WITHIN(delta, expected, actual, __LINE__, message) +#define TEST_ASSERT_HEX8_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_HEX8_WITHIN(delta, expected, actual, __LINE__, message) +#define TEST_ASSERT_HEX16_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_HEX16_WITHIN(delta, expected, actual, __LINE__, message) +#define TEST_ASSERT_HEX32_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_HEX32_WITHIN(delta, expected, actual, __LINE__, message) +#define TEST_ASSERT_HEX64_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_HEX64_WITHIN(delta, expected, actual, __LINE__, message) + +//Structs and Strings +#define TEST_ASSERT_EQUAL_PTR_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_PTR(expected, actual, __LINE__, message) +#define TEST_ASSERT_EQUAL_STRING_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_STRING(expected, actual, __LINE__, message) +#define TEST_ASSERT_EQUAL_MEMORY_MESSAGE(expected, actual, len, message) UNITY_TEST_ASSERT_EQUAL_MEMORY(expected, actual, len, __LINE__, message) + +//Arrays +#define TEST_ASSERT_EQUAL_INT_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_INT_ARRAY(expected, actual, num_elements, __LINE__, message) +#define TEST_ASSERT_EQUAL_INT8_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_INT8_ARRAY(expected, actual, num_elements, __LINE__, message) +#define TEST_ASSERT_EQUAL_INT16_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_INT16_ARRAY(expected, actual, num_elements, __LINE__, message) +#define TEST_ASSERT_EQUAL_INT32_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_INT32_ARRAY(expected, actual, num_elements, __LINE__, message) +#define TEST_ASSERT_EQUAL_INT64_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_INT64_ARRAY(expected, actual, num_elements, __LINE__, message) +#define TEST_ASSERT_EQUAL_UINT_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_UINT_ARRAY(expected, actual, num_elements, __LINE__, message) +#define TEST_ASSERT_EQUAL_UINT8_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_UINT8_ARRAY(expected, actual, num_elements, __LINE__, message) +#define TEST_ASSERT_EQUAL_UINT16_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_UINT16_ARRAY(expected, actual, num_elements, __LINE__, message) +#define TEST_ASSERT_EQUAL_UINT32_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_UINT32_ARRAY(expected, actual, num_elements, __LINE__, message) +#define TEST_ASSERT_EQUAL_UINT64_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_UINT64_ARRAY(expected, actual, num_elements, __LINE__, message) +#define TEST_ASSERT_EQUAL_HEX_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_HEX32_ARRAY(expected, actual, num_elements, __LINE__, message) +#define TEST_ASSERT_EQUAL_HEX8_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_HEX8_ARRAY(expected, actual, num_elements, __LINE__, message) +#define TEST_ASSERT_EQUAL_HEX16_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_HEX16_ARRAY(expected, actual, num_elements, __LINE__, message) +#define TEST_ASSERT_EQUAL_HEX32_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_HEX32_ARRAY(expected, actual, num_elements, __LINE__, message) +#define TEST_ASSERT_EQUAL_HEX64_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_HEX64_ARRAY(expected, actual, num_elements, __LINE__, message) +#define TEST_ASSERT_EQUAL_PTR_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_PTR_ARRAY(expected, actual, num_elements, __LINE__, message) +#define TEST_ASSERT_EQUAL_STRING_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_STRING_ARRAY(expected, actual, num_elements, __LINE__, message) +#define TEST_ASSERT_EQUAL_MEMORY_ARRAY_MESSAGE(expected, actual, len, num_elements, message) UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY(expected, actual, len, num_elements, __LINE__, message) + +//Floating Point (If Enabled) +#define TEST_ASSERT_FLOAT_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_FLOAT_WITHIN(delta, expected, actual, __LINE__, message) +#define TEST_ASSERT_EQUAL_FLOAT_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_FLOAT(expected, actual, __LINE__, message) +#define TEST_ASSERT_EQUAL_FLOAT_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_FLOAT_ARRAY(expected, actual, num_elements, __LINE__, message) +#define TEST_ASSERT_FLOAT_IS_INF_MESSAGE(actual, message) UNITY_TEST_ASSERT_FLOAT_IS_INF(actual, __LINE__, message) +#define TEST_ASSERT_FLOAT_IS_NEG_INF_MESSAGE(actual, message) UNITY_TEST_ASSERT_FLOAT_IS_NEG_INF(actual, __LINE__, message) +#define TEST_ASSERT_FLOAT_IS_NAN_MESSAGE(actual, message) UNITY_TEST_ASSERT_FLOAT_IS_NAN(actual, __LINE__, message) +#define TEST_ASSERT_FLOAT_IS_DETERMINATE_MESSAGE(actual, message) UNITY_TEST_ASSERT_FLOAT_IS_DETERMINATE(actual, __LINE__, message) +#define TEST_ASSERT_FLOAT_IS_NOT_INF_MESSAGE(actual, message) UNITY_TEST_ASSERT_FLOAT_IS_NOT_INF(actual, __LINE__, message) +#define TEST_ASSERT_FLOAT_IS_NOT_NEG_INF_MESSAGE(actual, message) UNITY_TEST_ASSERT_FLOAT_IS_NOT_NEG_INF(actual, __LINE__, message) +#define TEST_ASSERT_FLOAT_IS_NOT_NAN_MESSAGE(actual, message) UNITY_TEST_ASSERT_FLOAT_IS_NOT_NAN(actual, __LINE__, message) +#define TEST_ASSERT_FLOAT_IS_NOT_DETERMINATE_MESSAGE(actual, message) UNITY_TEST_ASSERT_FLOAT_IS_NOT_DETERMINATE(actual, __LINE__, message) + +//Double (If Enabled) +#define TEST_ASSERT_DOUBLE_WITHIN_MESSAGE(delta, expected, actual, message) UNITY_TEST_ASSERT_DOUBLE_WITHIN(delta, expected, actual, __LINE__, message) +#define TEST_ASSERT_EQUAL_DOUBLE_MESSAGE(expected, actual, message) UNITY_TEST_ASSERT_EQUAL_DOUBLE(expected, actual, __LINE__, message) +#define TEST_ASSERT_EQUAL_DOUBLE_ARRAY_MESSAGE(expected, actual, num_elements, message) UNITY_TEST_ASSERT_EQUAL_DOUBLE_ARRAY(expected, actual, num_elements, __LINE__, message) +#define TEST_ASSERT_DOUBLE_IS_INF_MESSAGE(actual, message) UNITY_TEST_ASSERT_DOUBLE_IS_INF(actual, __LINE__, message) +#define TEST_ASSERT_DOUBLE_IS_NEG_INF_MESSAGE(actual, message) UNITY_TEST_ASSERT_DOUBLE_IS_NEG_INF(actual, __LINE__, message) +#define TEST_ASSERT_DOUBLE_IS_NAN_MESSAGE(actual, message) UNITY_TEST_ASSERT_DOUBLE_IS_NAN(actual, __LINE__, message) +#define TEST_ASSERT_DOUBLE_IS_DETERMINATE_MESSAGE(actual, message) UNITY_TEST_ASSERT_DOUBLE_IS_DETERMINATE(actual, __LINE__, message) +#define TEST_ASSERT_DOUBLE_IS_NOT_INF_MESSAGE(actual, message) UNITY_TEST_ASSERT_DOUBLE_IS_NOT_INF(actual, __LINE__, message) +#define TEST_ASSERT_DOUBLE_IS_NOT_NEG_INF_MESSAGE(actual, message) UNITY_TEST_ASSERT_DOUBLE_IS_NOT_NEG_INF(actual, __LINE__, message) +#define TEST_ASSERT_DOUBLE_IS_NOT_NAN_MESSAGE(actual, message) UNITY_TEST_ASSERT_DOUBLE_IS_NOT_NAN(actual, __LINE__, message) +#define TEST_ASSERT_DOUBLE_IS_NOT_DETERMINATE_MESSAGE(actual, message) UNITY_TEST_ASSERT_DOUBLE_IS_NOT_DETERMINATE(actual, __LINE__, message) + +//end of UNITY_FRAMEWORK_H +#endif diff --git a/include/testing/unity_fixture.h b/include/testing/unity_fixture.h new file mode 100644 index 000000000..304c2f7b7 --- /dev/null +++ b/include/testing/unity_fixture.h @@ -0,0 +1,98 @@ +//- Copyright (c) 2010 James Grenning and Contributed to Unity Project +/* ========================================== + Unity Project - A Test Framework for C + Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams + [Released under MIT License. Please refer to license.txt for details] +========================================== */ + +#ifndef UNITY_FIXTURE_H_ +#define UNITY_FIXTURE_H_ + +#include "unity.h" +#include "unity_internals.h" +#include "unity_fixture_malloc_overrides.h" +#include "unity_fixture_internals.h" + +int UnityMain(int argc, const char* argv[], void (*runAllTests)(void)); + + +#define TEST_GROUP(group)\ + static const char* TEST_GROUP_##group = #group + +#define TEST_SETUP(group) TEST_SETUP_WITH_TIMEOUT(group, UNITY_DEFAULT_TIMEOUT_MSEC) + +#define TEST_SETUP_WITH_TIMEOUT(group, timeout)\ + static const _U_UINT TEST_##group##_SETUP_TIMEOUT = (timeout);\ + void TEST_##group##_SETUP(void);\ + void TEST_##group##_SETUP(void) + +#define TEST_TEAR_DOWN(group) TEST_TEAR_DOWN_WITH_TIMEOUT(group, UNITY_DEFAULT_TIMEOUT_MSEC) + +#define TEST_TEAR_DOWN_WITH_TIMEOUT(group, timeout)\ + static const _U_UINT TEST_##group##_TEAR_DOWN_TIMEOUT = (timeout);\ + void TEST_##group##_TEAR_DOWN(void);\ + void TEST_##group##_TEAR_DOWN(void) + + +#define TEST(group, name) TEST_WITH_TIMEOUT(group, name, UNITY_DEFAULT_TIMEOUT_MSEC) + +#define TEST_WITH_TIMEOUT(group, name, timeout)\ + void TEST_##group##_##name##_(void);\ + void TEST_##group##_##name##_run(void);\ + void TEST_##group##_##name##_run(void)\ + {\ + UnityTestRunner(TEST_##group##_SETUP, TEST_##group##_SETUP_TIMEOUT,\ + TEST_##group##_##name##_, (timeout),\ + TEST_##group##_TEAR_DOWN, TEST_##group##_TEAR_DOWN_TIMEOUT,\ + #group "/" #name,\ + TEST_GROUP_##group, #name,\ + __FILE__, __LINE__);\ + }\ + void TEST_##group##_##name##_(void) + +#define IGNORE_TEST(group, name) IGNORE_TEST_WITH_TIMEOUT(group, name, UNITY_DEFAULT_TIMEOUT_MSEC) + +#define IGNORE_TEST_WITH_TIMEOUT(group, name, timeout) \ + void TEST_##group##_##name##_(void);\ + void TEST_##group##_##name##_run(void);\ + void TEST_##group##_##name##_run(void)\ + {\ + UnityIgnoreTest("IGNORE_TEST(" #group ", " #name ")");\ + }\ + void TEST_##group##_##name##_(void) + +#define DECLARE_TEST_CASE(group, name) \ + void TEST_##group##_##name##_run(void) + +#define RUN_TEST_CASE(group, name) \ + { DECLARE_TEST_CASE(group, name);\ + TEST_##group##_##name##_run(); } + +//This goes at the bottom of each test file or in a separate c file +#define TEST_GROUP_RUNNER(group)\ + void TEST_##group##_GROUP_RUNNER_runAll(void);\ + void TEST_##group##_GROUP_RUNNER(void);\ + void TEST_##group##_GROUP_RUNNER(void)\ + {\ + TEST_##group##_GROUP_RUNNER_runAll();\ + }\ + void TEST_##group##_GROUP_RUNNER_runAll(void) + +//Call this from main +#define RUN_TEST_GROUP(group)\ + { void TEST_##group##_GROUP_RUNNER(void);\ + TEST_##group##_GROUP_RUNNER(); } + +//CppUTest Compatibility Macros +#define UT_PTR_SET(ptr, newPointerValue) UnityPointer_Set((void**)&ptr, (void*)newPointerValue) +#define TEST_ASSERT_POINTERS_EQUAL(expected, actual) TEST_ASSERT_EQUAL_PTR(expected, actual) +#define TEST_ASSERT_BYTES_EQUAL(expected, actual) TEST_ASSERT_EQUAL_HEX8(0xff & (expected), 0xff & (actual)) +#define FAIL(message) TEST_FAIL((message)) +#define CHECK(condition) TEST_ASSERT_TRUE((condition)) +#define LONGS_EQUAL(expected, actual) TEST_ASSERT_EQUAL_INT((expected), (actual)) +#define STRCMP_EQUAL(expected, actual) TEST_ASSERT_EQUAL_STRING((expected), (actual)) +#define DOUBLES_EQUAL(expected, actual, delta) TEST_ASSERT_FLOAT_WITHIN(((expected), (actual), (delta)) + +void UnityMalloc_MakeMallocFailAfterCount(int count); + +#endif /* UNITY_FIXTURE_H_ */ diff --git a/include/testing/unity_fixture_internals.h b/include/testing/unity_fixture_internals.h new file mode 100644 index 000000000..dd5ceee8b --- /dev/null +++ b/include/testing/unity_fixture_internals.h @@ -0,0 +1,46 @@ +//- Copyright (c) 2010 James Grenning and Contributed to Unity Project +/* ========================================== + Unity Project - A Test Framework for C + Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams + [Released under MIT License. Please refer to license.txt for details] +========================================== */ + +#ifndef UNITY_FIXTURE_INTERNALS_H_ +#define UNITY_FIXTURE_INTERNALS_H_ + +typedef struct _UNITY_FIXTURE_T +{ + int Verbose; + int ListOnly; + unsigned int RepeatCount; + const char* NameFilter; + const char* GroupFilter; + const char** PlainListOfTests; +} UNITY_FIXTURE_T; + +typedef void unityfunction(void); +void UnityTestRunner(unityfunction * setup, _U_UINT setupTimeoutMsec, + unityfunction * body, _U_UINT bodyTimeoutMsec, + unityfunction * teardown, _U_UINT teardownTimeoutMsec, + const char * printableName, + const char * group, + const char * name, + const char * file, int line); + +void UnityIgnoreTest(const char * printableName); +void UnityMalloc_StartTest(void); +void UnityMalloc_EndTest(void); +int UnityFailureCount(void); +int UnityGetCommandLineOptions(int argc, const char* argv[]); +void UnityConcludeFixtureTest(void); + +void UnityPointer_Set(void ** ptr, void * newValue); +void UnityPointer_UndoAllSets(void); +void UnityPointer_Init(void); + +void UnityAssertEqualPointer(const void * expected, + const void * actual, + const char* msg, + const UNITY_LINE_TYPE lineNumber); + +#endif /* UNITY_FIXTURE_INTERNALS_H_ */ diff --git a/include/testing/unity_fixture_malloc_overrides.h b/include/testing/unity_fixture_malloc_overrides.h new file mode 100644 index 000000000..25385f4d7 --- /dev/null +++ b/include/testing/unity_fixture_malloc_overrides.h @@ -0,0 +1,27 @@ +//- Copyright (c) 2010 James Grenning and Contributed to Unity Project +/* ========================================== + Unity Project - A Test Framework for C + Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams + [Released under MIT License. Please refer to license.txt for details] +========================================== */ + +#ifndef UNITY_FIXTURE_MALLOC_OVERRIDES_H_ +#define UNITY_FIXTURE_MALLOC_OVERRIDES_H_ + +#ifndef UNITY_DISABLE_MEMORY_LEAK_TRACKING + +#include + +#define malloc unity_malloc +#define calloc unity_calloc +#define realloc unity_realloc +#define free unity_free + +void* unity_malloc(size_t size); +void* unity_calloc(size_t num, size_t size); +void* unity_realloc(void * oldMem, size_t size); +void unity_free(void * mem); + +#endif /* UNITY_DISABLE_MEMORY_LEAK_TRACKING */ + +#endif /* UNITY_FIXTURE_MALLOC_OVERRIDES_H_ */ diff --git a/include/testing/unity_internals.h b/include/testing/unity_internals.h new file mode 100644 index 000000000..b73729f13 --- /dev/null +++ b/include/testing/unity_internals.h @@ -0,0 +1,693 @@ +/* ========================================== + Unity Project - A Test Framework for C + Copyright (c) 2007-14 Mike Karlesky, Mark VanderVoord, Greg Williams + [Released under MIT License. Please refer to license.txt for details] +========================================== */ + +#ifndef UNITY_INTERNALS_H +#define UNITY_INTERNALS_H + +#ifdef UNITY_INCLUDE_CONFIG_H +#include "unity_config.h" +#endif + +// Unity Attempts to Auto-Detect Integer Types +// Attempt 1: UINT_MAX, ULONG_MAX, etc in +// Attempt 2: UINT_MAX, ULONG_MAX, etc in +// Attempt 3: Deduced from sizeof() macros +#ifndef UNITY_EXCLUDE_STDINT_H +#include +#endif + +#ifndef UNITY_EXCLUDE_LIMITS_H +#include +#endif + +#ifndef UNITY_EXCLUDE_SIZEOF +#ifndef UINT_MAX +#define UINT_MAX (sizeof(unsigned int) * 256 - 1) +#endif +#ifndef ULONG_MAX +#define ULONG_MAX (sizeof(unsigned long) * 256 - 1) +#endif +#ifndef UINTPTR_MAX +//apparently this is not a constant expression: (sizeof(unsigned int *) * 256 - 1) so we have to just let this fall through +#endif +#endif +//------------------------------------------------------- +// Guess Widths If Not Specified +//------------------------------------------------------- + +// Determine the size of an int, if not already specificied. +// We cannot use sizeof(int), because it is not yet defined +// at this stage in the trnslation of the C program. +// Therefore, infer it from UINT_MAX if possible. +#ifndef UNITY_INT_WIDTH + #ifdef UINT_MAX + #if (UINT_MAX == 0xFFFF) + #define UNITY_INT_WIDTH (16) + #elif (UINT_MAX == 0xFFFFFFFF) + #define UNITY_INT_WIDTH (32) + #elif (UINT_MAX == 0xFFFFFFFFFFFFFFFF) + #define UNITY_INT_WIDTH (64) + #endif + #endif +#endif +#ifndef UNITY_INT_WIDTH + #define UNITY_INT_WIDTH (32) +#endif + +// Determine the size of a long, if not already specified, +// by following the process used above to define +// UNITY_INT_WIDTH. +#ifndef UNITY_LONG_WIDTH + #ifdef ULONG_MAX + #if (ULONG_MAX == 0xFFFF) + #define UNITY_LONG_WIDTH (16) + #elif (ULONG_MAX == 0xFFFFFFFF) + #define UNITY_LONG_WIDTH (32) + #elif (ULONG_MAX == 0xFFFFFFFFFFFFFFFF) + #define UNITY_LONG_WIDTH (64) + #endif + #endif +#endif +#ifndef UNITY_LONG_WIDTH + #define UNITY_LONG_WIDTH (32) +#endif + +// Determine the size of a pointer, if not already specified, +// by following the process used above to define +// UNITY_INT_WIDTH. +#ifndef UNITY_POINTER_WIDTH + #ifdef UINTPTR_MAX + #if (UINTPTR_MAX <= 0xFFFF) + #define UNITY_POINTER_WIDTH (16) + #elif (UINTPTR_MAX <= 0xFFFFFFFF) + #define UNITY_POINTER_WIDTH (32) + #elif (UINTPTR_MAX <= 0xFFFFFFFFFFFFFFFF) + #define UNITY_POINTER_WIDTH (64) + #endif + #endif +#endif +#ifndef UNITY_POINTER_WIDTH + #ifdef INTPTR_MAX + #if (INTPTR_MAX <= 0x7FFF) + #define UNITY_POINTER_WIDTH (16) + #elif (INTPTR_MAX <= 0x7FFFFFFF) + #define UNITY_POINTER_WIDTH (32) + #elif (INTPTR_MAX <= 0x7FFFFFFFFFFFFFFF) + #define UNITY_POINTER_WIDTH (64) + #endif + #endif +#endif +#ifndef UNITY_POINTER_WIDTH + #define UNITY_POINTER_WIDTH UNITY_LONG_WIDTH +#endif + +//------------------------------------------------------- +// Int Support (Define types based on detected sizes) +//------------------------------------------------------- + +#if (UNITY_INT_WIDTH == 32) + typedef unsigned char _UU8; + typedef unsigned short _UU16; + typedef unsigned int _UU32; + typedef signed char _US8; + typedef signed short _US16; + typedef signed int _US32; +#elif (UNITY_INT_WIDTH == 16) + typedef unsigned char _UU8; + typedef unsigned int _UU16; + typedef unsigned long _UU32; + typedef signed char _US8; + typedef signed int _US16; + typedef signed long _US32; +#else + #error Invalid UNITY_INT_WIDTH specified! (16 or 32 are supported) +#endif + +//------------------------------------------------------- +// 64-bit Support +//------------------------------------------------------- + +#ifndef UNITY_SUPPORT_64 +#if UNITY_LONG_WIDTH > 32 +#define UNITY_SUPPORT_64 +#endif +#endif +#ifndef UNITY_SUPPORT_64 +#if UNITY_POINTER_WIDTH > 32 +#define UNITY_SUPPORT_64 +#endif +#endif + +#ifndef UNITY_SUPPORT_64 + +//No 64-bit Support +typedef _UU32 _U_UINT; +typedef _US32 _U_SINT; + +#else + +//64-bit Support +#if (UNITY_LONG_WIDTH == 32) + typedef unsigned long long _UU64; + typedef signed long long _US64; +#elif (UNITY_LONG_WIDTH == 64) + typedef unsigned long _UU64; + typedef signed long _US64; +#else + #error Invalid UNITY_LONG_WIDTH specified! (32 or 64 are supported) +#endif +typedef _UU64 _U_UINT; +typedef _US64 _U_SINT; + +#endif + +//------------------------------------------------------- +// Pointer Support +//------------------------------------------------------- + +#if (UNITY_POINTER_WIDTH == 32) + typedef _UU32 _UP; +#define UNITY_DISPLAY_STYLE_POINTER UNITY_DISPLAY_STYLE_HEX32 +#elif (UNITY_POINTER_WIDTH == 64) + typedef _UU64 _UP; +#define UNITY_DISPLAY_STYLE_POINTER UNITY_DISPLAY_STYLE_HEX64 +#elif (UNITY_POINTER_WIDTH == 16) + typedef _UU16 _UP; +#define UNITY_DISPLAY_STYLE_POINTER UNITY_DISPLAY_STYLE_HEX16 +#else + #error Invalid UNITY_POINTER_WIDTH specified! (16, 32 or 64 are supported) +#endif + +#ifndef UNITY_PTR_ATTRIBUTE + #define UNITY_PTR_ATTRIBUTE +#endif + +//------------------------------------------------------- +// Float Support +//------------------------------------------------------- + +#ifdef UNITY_EXCLUDE_FLOAT + +//No Floating Point Support +#undef UNITY_INCLUDE_FLOAT +#undef UNITY_FLOAT_PRECISION +#undef UNITY_FLOAT_TYPE +#undef UNITY_FLOAT_VERBOSE + +#else + +#ifndef UNITY_INCLUDE_FLOAT +#define UNITY_INCLUDE_FLOAT +#endif + +//Floating Point Support +#ifndef UNITY_FLOAT_PRECISION +#define UNITY_FLOAT_PRECISION (0.00001f) +#endif +#ifndef UNITY_FLOAT_TYPE +#define UNITY_FLOAT_TYPE float +#endif +typedef UNITY_FLOAT_TYPE _UF; + +#endif + +//------------------------------------------------------- +// Double Float Support +//------------------------------------------------------- + +//unlike FLOAT, we DON'T include by default +#ifndef UNITY_EXCLUDE_DOUBLE +#ifndef UNITY_INCLUDE_DOUBLE +#define UNITY_EXCLUDE_DOUBLE +#endif +#endif + +#ifdef UNITY_EXCLUDE_DOUBLE + +//No Floating Point Support +#undef UNITY_DOUBLE_PRECISION +#undef UNITY_DOUBLE_TYPE +#undef UNITY_DOUBLE_VERBOSE + +#ifdef UNITY_INCLUDE_DOUBLE +#undef UNITY_INCLUDE_DOUBLE +#endif + +#else + +//Double Floating Point Support +#ifndef UNITY_DOUBLE_PRECISION +#define UNITY_DOUBLE_PRECISION (1e-12f) +#endif +#ifndef UNITY_DOUBLE_TYPE +#define UNITY_DOUBLE_TYPE double +#endif +typedef UNITY_DOUBLE_TYPE _UD; + +#endif + +#ifdef UNITY_DOUBLE_VERBOSE +#ifndef UNITY_FLOAT_VERBOSE +#define UNITY_FLOAT_VERBOSE +#endif +#endif + +//------------------------------------------------------- +// Output Method: stdout (DEFAULT) +//------------------------------------------------------- +#ifndef UNITY_OUTPUT_CHAR +//Default to using putchar, which is defined in stdio.h +#include +#define UNITY_OUTPUT_CHAR(a) putchar(a) +#else +//If defined as something else, make sure we declare it here so it's ready for use +extern int UNITY_OUTPUT_CHAR(int); +#endif + +#ifndef UNITY_OUTPUT_START +#define UNITY_OUTPUT_START() +#endif + +#ifndef UNITY_OUTPUT_COMPLETE +#define UNITY_OUTPUT_COMPLETE() +#endif + +//------------------------------------------------------- +// Footprint +//------------------------------------------------------- + +#ifndef UNITY_LINE_TYPE +#define UNITY_LINE_TYPE _U_UINT +#endif + +#ifndef UNITY_COUNTER_TYPE +#define UNITY_COUNTER_TYPE _U_UINT +#endif + +//------------------------------------------------------- +// Language Features Available +//------------------------------------------------------- +#if !defined(UNITY_WEAK_ATTRIBUTE) && !defined(UNITY_WEAK_PRAGMA) +# ifdef __GNUC__ // includes clang +# if !(defined(__WIN32__) && defined(__clang__)) +# define UNITY_WEAK_ATTRIBUTE __attribute__((weak)) +# endif +# endif +#endif + +#ifdef UNITY_NO_WEAK +# undef UNITY_WEAK_ATTRIBUTE +# undef UNITY_WEAK_PRAGMA +#endif + + +//------------------------------------------------------- +// Internal Structs Needed +//------------------------------------------------------- + +typedef void (*UnityTestFunction)(void); + +#define UNITY_DISPLAY_RANGE_INT (0x10) +#define UNITY_DISPLAY_RANGE_UINT (0x20) +#define UNITY_DISPLAY_RANGE_HEX (0x40) +#define UNITY_DISPLAY_RANGE_AUTO (0x80) + +typedef enum +{ +#if (UNITY_INT_WIDTH == 16) + UNITY_DISPLAY_STYLE_INT = 2 + UNITY_DISPLAY_RANGE_INT + UNITY_DISPLAY_RANGE_AUTO, +#elif (UNITY_INT_WIDTH == 32) + UNITY_DISPLAY_STYLE_INT = 4 + UNITY_DISPLAY_RANGE_INT + UNITY_DISPLAY_RANGE_AUTO, +#elif (UNITY_INT_WIDTH == 64) + UNITY_DISPLAY_STYLE_INT = 8 + UNITY_DISPLAY_RANGE_INT + UNITY_DISPLAY_RANGE_AUTO, +#endif + UNITY_DISPLAY_STYLE_INT8 = 1 + UNITY_DISPLAY_RANGE_INT, + UNITY_DISPLAY_STYLE_INT16 = 2 + UNITY_DISPLAY_RANGE_INT, + UNITY_DISPLAY_STYLE_INT32 = 4 + UNITY_DISPLAY_RANGE_INT, +#ifdef UNITY_SUPPORT_64 + UNITY_DISPLAY_STYLE_INT64 = 8 + UNITY_DISPLAY_RANGE_INT, +#endif + +#if (UNITY_INT_WIDTH == 16) + UNITY_DISPLAY_STYLE_UINT = 2 + UNITY_DISPLAY_RANGE_UINT + UNITY_DISPLAY_RANGE_AUTO, +#elif (UNITY_INT_WIDTH == 32) + UNITY_DISPLAY_STYLE_UINT = 4 + UNITY_DISPLAY_RANGE_UINT + UNITY_DISPLAY_RANGE_AUTO, +#elif (UNITY_INT_WIDTH == 64) + UNITY_DISPLAY_STYLE_UINT = 8 + UNITY_DISPLAY_RANGE_UINT + UNITY_DISPLAY_RANGE_AUTO, +#endif + UNITY_DISPLAY_STYLE_UINT8 = 1 + UNITY_DISPLAY_RANGE_UINT, + UNITY_DISPLAY_STYLE_UINT16 = 2 + UNITY_DISPLAY_RANGE_UINT, + UNITY_DISPLAY_STYLE_UINT32 = 4 + UNITY_DISPLAY_RANGE_UINT, +#ifdef UNITY_SUPPORT_64 + UNITY_DISPLAY_STYLE_UINT64 = 8 + UNITY_DISPLAY_RANGE_UINT, +#endif + UNITY_DISPLAY_STYLE_HEX8 = 1 + UNITY_DISPLAY_RANGE_HEX, + UNITY_DISPLAY_STYLE_HEX16 = 2 + UNITY_DISPLAY_RANGE_HEX, + UNITY_DISPLAY_STYLE_HEX32 = 4 + UNITY_DISPLAY_RANGE_HEX, +#ifdef UNITY_SUPPORT_64 + UNITY_DISPLAY_STYLE_HEX64 = 8 + UNITY_DISPLAY_RANGE_HEX, +#endif + UNITY_DISPLAY_STYLE_UNKNOWN +} UNITY_DISPLAY_STYLE_T; + +#ifndef UNITY_EXCLUDE_FLOAT +typedef enum _UNITY_FLOAT_TRAIT_T +{ + UNITY_FLOAT_IS_NOT_INF = 0, + UNITY_FLOAT_IS_INF, + UNITY_FLOAT_IS_NOT_NEG_INF, + UNITY_FLOAT_IS_NEG_INF, + UNITY_FLOAT_IS_NOT_NAN, + UNITY_FLOAT_IS_NAN, + UNITY_FLOAT_IS_NOT_DET, + UNITY_FLOAT_IS_DET, +} UNITY_FLOAT_TRAIT_T; +#endif + +struct _Unity +{ + const char* TestFile; + const char* CurrentTestName; + UNITY_LINE_TYPE CurrentTestLineNumber; + UNITY_COUNTER_TYPE NumberOfTests; + UNITY_COUNTER_TYPE TestFailures; + UNITY_COUNTER_TYPE TestIgnores; + UNITY_COUNTER_TYPE CurrentTestFailed; + UNITY_COUNTER_TYPE CurrentTestIgnored; + UNITY_COUNTER_TYPE CurrentTestTimeout; +}; + +extern struct _Unity Unity; + +//------------------------------------------------------- +// Test Suite Management +//------------------------------------------------------- + +void UnityBegin(const char* filename); +int UnityEnd(void); +void UnityConcludeTest(void); +void UnityDefaultTestRun(UnityTestFunction Func, const char* FuncName, const int FuncLineNum); + +//------------------------------------------------------- +// Test Output +//------------------------------------------------------- + +void UnityPrint(const char* string); +void UnityPrintMask(const _U_UINT mask, const _U_UINT number); +void UnityPrintNumberByStyle(const _U_SINT number, const UNITY_DISPLAY_STYLE_T style); +void UnityPrintNumber(const _U_SINT number); +void UnityPrintNumberUnsigned(const _U_UINT number); +void UnityPrintNumberHex(const _U_UINT number, const char nibbles); + +#ifdef UNITY_FLOAT_VERBOSE +void UnityPrintFloat(const _UF number); +#endif + +//------------------------------------------------------- +// Test Assertion Fuctions +//------------------------------------------------------- +// Use the macros below this section instead of calling +// these directly. The macros have a consistent naming +// convention and will pull in file and line information +// for you. + +void UnityAssertEqualNumber(const _U_SINT expected, + const _U_SINT actual, + const char* msg, + const UNITY_LINE_TYPE lineNumber, + const UNITY_DISPLAY_STYLE_T style); + +void UnityAssertEqualIntArray(UNITY_PTR_ATTRIBUTE const void* expected, + UNITY_PTR_ATTRIBUTE const void* actual, + const _UU32 num_elements, + const char* msg, + const UNITY_LINE_TYPE lineNumber, + const UNITY_DISPLAY_STYLE_T style); + +void UnityAssertBits(const _U_SINT mask, + const _U_SINT expected, + const _U_SINT actual, + const char* msg, + const UNITY_LINE_TYPE lineNumber); + +void UnityAssertEqualString(const char* expected, + const char* actual, + const char* msg, + const UNITY_LINE_TYPE lineNumber); + +void UnityAssertEqualStringArray( const char** expected, + const char** actual, + const _UU32 num_elements, + const char* msg, + const UNITY_LINE_TYPE lineNumber); + +void UnityAssertEqualMemory( UNITY_PTR_ATTRIBUTE const void* expected, + UNITY_PTR_ATTRIBUTE const void* actual, + const _UU32 length, + const _UU32 num_elements, + const char* msg, + const UNITY_LINE_TYPE lineNumber); + +void UnityAssertNumbersWithin(const _U_SINT delta, + const _U_SINT expected, + const _U_SINT actual, + const char* msg, + const UNITY_LINE_TYPE lineNumber, + const UNITY_DISPLAY_STYLE_T style); + +void UnityFail(const char* message, const UNITY_LINE_TYPE line); + +void UnityIgnore(const char* message, const UNITY_LINE_TYPE line); + +#ifndef UNITY_EXCLUDE_FLOAT +void UnityAssertFloatsWithin(const _UF delta, + const _UF expected, + const _UF actual, + const char* msg, + const UNITY_LINE_TYPE lineNumber); + +void UnityAssertEqualFloatArray(UNITY_PTR_ATTRIBUTE const _UF* expected, + UNITY_PTR_ATTRIBUTE const _UF* actual, + const _UU32 num_elements, + const char* msg, + const UNITY_LINE_TYPE lineNumber); + +void UnityAssertFloatSpecial(const _UF actual, + const char* msg, + const UNITY_LINE_TYPE lineNumber, + const UNITY_FLOAT_TRAIT_T style); +#endif + +#ifndef UNITY_EXCLUDE_DOUBLE +void UnityAssertDoublesWithin(const _UD delta, + const _UD expected, + const _UD actual, + const char* msg, + const UNITY_LINE_TYPE lineNumber); + +void UnityAssertEqualDoubleArray(UNITY_PTR_ATTRIBUTE const _UD* expected, + UNITY_PTR_ATTRIBUTE const _UD* actual, + const _UU32 num_elements, + const char* msg, + const UNITY_LINE_TYPE lineNumber); + +void UnityAssertDoubleSpecial(const _UD actual, + const char* msg, + const UNITY_LINE_TYPE lineNumber, + const UNITY_FLOAT_TRAIT_T style); +#endif + +int UnityProtect(UnityTestFunction function, _U_UINT timeout_msec); + +//------------------------------------------------------- +// Error Strings We Might Need +//------------------------------------------------------- + +extern const char UnityStrErrFloat[]; +extern const char UnityStrErrDouble[]; +extern const char UnityStrErr64[]; + +//------------------------------------------------------- +// Test Running Macros +//------------------------------------------------------- + +#define UNITY_DEFAULT_TIMEOUT_MSEC 120000 + +#define TEST_PROTECTED_WITH_TIMEOUT(function, timeout) UnityProtect(function, timeout) +#define TEST_PROTECTED(function) TEST_PROTECTED_WITH_TIMEOUT(function, UNITY_DEFAULT_TIMEOUT_MSEC) + +//This tricky series of macros gives us an optional line argument to treat it as RUN_TEST(func, num=__LINE__) +#ifndef RUN_TEST +#ifdef __STDC_VERSION__ +#if __STDC_VERSION__ >= 199901L +#define RUN_TEST(...) UnityDefaultTestRun(RUN_TEST_FIRST(__VA_ARGS__), RUN_TEST_SECOND(__VA_ARGS__)) +#define RUN_TEST_FIRST(...) RUN_TEST_FIRST_HELPER(__VA_ARGS__, throwaway) +#define RUN_TEST_FIRST_HELPER(first,...) first, #first +#define RUN_TEST_SECOND(...) RUN_TEST_SECOND_HELPER(__VA_ARGS__, __LINE__, throwaway) +#define RUN_TEST_SECOND_HELPER(first,second,...) second +#endif +#endif +#endif + +//If we can't do the tricky version, we'll just have to require them to always include the line number +#ifndef RUN_TEST +#ifdef CMOCK +#define RUN_TEST(func, num) UnityDefaultTestRun(func, #func, num) +#else +#define RUN_TEST(func) UnityDefaultTestRun(func, #func, __LINE__) +#endif +#endif + +#define TEST_LINE_NUM (Unity.CurrentTestLineNumber) +#define TEST_IS_IGNORED (Unity.CurrentTestIgnored) +#define UNITY_NEW_TEST(a) \ + Unity.CurrentTestName = a; \ + Unity.CurrentTestLineNumber = (UNITY_LINE_TYPE)(__LINE__); \ + Unity.NumberOfTests++; + +#ifndef UNITY_BEGIN +#define UNITY_BEGIN() UnityBegin(__FILE__) +#endif + +#ifndef UNITY_END +#define UNITY_END() UnityEnd() +#endif + +//------------------------------------------------------- +// Basic Fail and Ignore +//------------------------------------------------------- + +#define UNITY_TEST_FAIL(line, message) UnityFail( (message), (UNITY_LINE_TYPE)line); +#define UNITY_TEST_IGNORE(line, message) UnityIgnore( (message), (UNITY_LINE_TYPE)line); + +//------------------------------------------------------- +// Test Asserts +//------------------------------------------------------- + +#define UNITY_TEST_ASSERT(condition, line, message) if (condition) {} else {UNITY_TEST_FAIL((UNITY_LINE_TYPE)line, message);} +#define UNITY_TEST_ASSERT_NULL(pointer, line, message) UNITY_TEST_ASSERT(((pointer) == NULL), (UNITY_LINE_TYPE)line, message) +#define UNITY_TEST_ASSERT_NOT_NULL(pointer, line, message) UNITY_TEST_ASSERT(((pointer) != NULL), (UNITY_LINE_TYPE)line, message) + +#define UNITY_TEST_ASSERT_EQUAL_INT(expected, actual, line, message) UnityAssertEqualNumber((_U_SINT)(expected), (_U_SINT)(actual), (message), (UNITY_LINE_TYPE)line, UNITY_DISPLAY_STYLE_INT) +#define UNITY_TEST_ASSERT_EQUAL_INT8(expected, actual, line, message) UnityAssertEqualNumber((_U_SINT)(_US8 )(expected), (_U_SINT)(_US8 )(actual), (message), (UNITY_LINE_TYPE)line, UNITY_DISPLAY_STYLE_INT8) +#define UNITY_TEST_ASSERT_EQUAL_INT16(expected, actual, line, message) UnityAssertEqualNumber((_U_SINT)(_US16)(expected), (_U_SINT)(_US16)(actual), (message), (UNITY_LINE_TYPE)line, UNITY_DISPLAY_STYLE_INT16) +#define UNITY_TEST_ASSERT_EQUAL_INT32(expected, actual, line, message) UnityAssertEqualNumber((_U_SINT)(_US32)(expected), (_U_SINT)(_US32)(actual), (message), (UNITY_LINE_TYPE)line, UNITY_DISPLAY_STYLE_INT32) +#define UNITY_TEST_ASSERT_EQUAL_UINT(expected, actual, line, message) UnityAssertEqualNumber((_U_SINT)(expected), (_U_SINT)(actual), (message), (UNITY_LINE_TYPE)line, UNITY_DISPLAY_STYLE_UINT) +#define UNITY_TEST_ASSERT_EQUAL_UINT8(expected, actual, line, message) UnityAssertEqualNumber((_U_SINT)(_UU8 )(expected), (_U_SINT)(_UU8 )(actual), (message), (UNITY_LINE_TYPE)line, UNITY_DISPLAY_STYLE_UINT8) +#define UNITY_TEST_ASSERT_EQUAL_UINT16(expected, actual, line, message) UnityAssertEqualNumber((_U_SINT)(_UU16)(expected), (_U_SINT)(_UU16)(actual), (message), (UNITY_LINE_TYPE)line, UNITY_DISPLAY_STYLE_UINT16) +#define UNITY_TEST_ASSERT_EQUAL_UINT32(expected, actual, line, message) UnityAssertEqualNumber((_U_SINT)(_UU32)(expected), (_U_SINT)(_UU32)(actual), (message), (UNITY_LINE_TYPE)line, UNITY_DISPLAY_STYLE_UINT32) +#define UNITY_TEST_ASSERT_EQUAL_HEX8(expected, actual, line, message) UnityAssertEqualNumber((_U_SINT)(_US8 )(expected), (_U_SINT)(_US8 )(actual), (message), (UNITY_LINE_TYPE)line, UNITY_DISPLAY_STYLE_HEX8) +#define UNITY_TEST_ASSERT_EQUAL_HEX16(expected, actual, line, message) UnityAssertEqualNumber((_U_SINT)(_US16)(expected), (_U_SINT)(_US16)(actual), (message), (UNITY_LINE_TYPE)line, UNITY_DISPLAY_STYLE_HEX16) +#define UNITY_TEST_ASSERT_EQUAL_HEX32(expected, actual, line, message) UnityAssertEqualNumber((_U_SINT)(_US32)(expected), (_U_SINT)(_US32)(actual), (message), (UNITY_LINE_TYPE)line, UNITY_DISPLAY_STYLE_HEX32) +#define UNITY_TEST_ASSERT_BITS(mask, expected, actual, line, message) UnityAssertBits((_U_SINT)(mask), (_U_SINT)(expected), (_U_SINT)(actual), (message), (UNITY_LINE_TYPE)line) + +#define UNITY_TEST_ASSERT_INT_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((_U_SINT)(delta), (_U_SINT)(expected), (_U_SINT)(actual), (message), (UNITY_LINE_TYPE)line, UNITY_DISPLAY_STYLE_INT) +#define UNITY_TEST_ASSERT_INT8_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((_U_SINT)(_US8 )(delta), (_U_SINT)(_US8 )(expected), (_U_SINT)(_US8 )(actual), (message), (UNITY_LINE_TYPE)line, UNITY_DISPLAY_STYLE_INT8) +#define UNITY_TEST_ASSERT_INT16_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((_U_SINT)(_US16)(delta), (_U_SINT)(_US16)(expected), (_U_SINT)(_US16)(actual), (message), (UNITY_LINE_TYPE)line, UNITY_DISPLAY_STYLE_INT16) +#define UNITY_TEST_ASSERT_INT32_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((_U_SINT)(_US32)(delta), (_U_SINT)(_US32)(expected), (_U_SINT)(_US32)(actual), (message), (UNITY_LINE_TYPE)line, UNITY_DISPLAY_STYLE_INT32) +#define UNITY_TEST_ASSERT_UINT_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((_U_SINT)(delta), (_U_SINT)(expected), (_U_SINT)(actual), (message), (UNITY_LINE_TYPE)line, UNITY_DISPLAY_STYLE_UINT) +#define UNITY_TEST_ASSERT_UINT8_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((_U_SINT)(_U_UINT)(_UU8 )(delta), (_U_SINT)(_U_UINT)(_UU8 )(expected), (_U_SINT)(_U_UINT)(_UU8 )(actual), (message), (UNITY_LINE_TYPE)line, UNITY_DISPLAY_STYLE_UINT8) +#define UNITY_TEST_ASSERT_UINT16_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((_U_SINT)(_U_UINT)(_UU16)(delta), (_U_SINT)(_U_UINT)(_UU16)(expected), (_U_SINT)(_U_UINT)(_UU16)(actual), (message), (UNITY_LINE_TYPE)line, UNITY_DISPLAY_STYLE_UINT16) +#define UNITY_TEST_ASSERT_UINT32_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((_U_SINT)(_U_UINT)(_UU32)(delta), (_U_SINT)(_U_UINT)(_UU32)(expected), (_U_SINT)(_U_UINT)(_UU32)(actual), (message), (UNITY_LINE_TYPE)line, UNITY_DISPLAY_STYLE_UINT32) +#define UNITY_TEST_ASSERT_HEX8_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((_U_SINT)(_U_UINT)(_UU8 )(delta), (_U_SINT)(_U_UINT)(_UU8 )(expected), (_U_SINT)(_U_UINT)(_UU8 )(actual), (message), (UNITY_LINE_TYPE)line, UNITY_DISPLAY_STYLE_HEX8) +#define UNITY_TEST_ASSERT_HEX16_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((_U_SINT)(_U_UINT)(_UU16)(delta), (_U_SINT)(_U_UINT)(_UU16)(expected), (_U_SINT)(_U_UINT)(_UU16)(actual), (message), (UNITY_LINE_TYPE)line, UNITY_DISPLAY_STYLE_HEX16) +#define UNITY_TEST_ASSERT_HEX32_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((_U_SINT)(_U_UINT)(_UU32)(delta), (_U_SINT)(_U_UINT)(_UU32)(expected), (_U_SINT)(_U_UINT)(_UU32)(actual), (message), (UNITY_LINE_TYPE)line, UNITY_DISPLAY_STYLE_HEX32) + +#define UNITY_TEST_ASSERT_EQUAL_PTR(expected, actual, line, message) UnityAssertEqualNumber((_U_SINT)(_UP)(expected), (_U_SINT)(_UP)(actual), (message), (UNITY_LINE_TYPE)line, UNITY_DISPLAY_STYLE_POINTER) +#define UNITY_TEST_ASSERT_EQUAL_STRING(expected, actual, line, message) UnityAssertEqualString((const char*)(expected), (const char*)(actual), (message), (UNITY_LINE_TYPE)line) +#define UNITY_TEST_ASSERT_EQUAL_MEMORY(expected, actual, len, line, message) UnityAssertEqualMemory((UNITY_PTR_ATTRIBUTE void*)(expected), (UNITY_PTR_ATTRIBUTE void*)(actual), (_UU32)(len), 1, (message), (UNITY_LINE_TYPE)line) + +#define UNITY_TEST_ASSERT_EQUAL_INT_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualIntArray((UNITY_PTR_ATTRIBUTE const void*)(expected), (UNITY_PTR_ATTRIBUTE const void*)(actual), (_UU32)(num_elements), (message), (UNITY_LINE_TYPE)line, UNITY_DISPLAY_STYLE_INT) +#define UNITY_TEST_ASSERT_EQUAL_INT8_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualIntArray((UNITY_PTR_ATTRIBUTE const void*)(expected), (UNITY_PTR_ATTRIBUTE const void*)(actual), (_UU32)(num_elements), (message), (UNITY_LINE_TYPE)line, UNITY_DISPLAY_STYLE_INT8) +#define UNITY_TEST_ASSERT_EQUAL_INT16_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualIntArray((UNITY_PTR_ATTRIBUTE const void*)(expected), (UNITY_PTR_ATTRIBUTE const void*)(actual), (_UU32)(num_elements), (message), (UNITY_LINE_TYPE)line, UNITY_DISPLAY_STYLE_INT16) +#define UNITY_TEST_ASSERT_EQUAL_INT32_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualIntArray((UNITY_PTR_ATTRIBUTE const void*)(expected), (UNITY_PTR_ATTRIBUTE const void*)(actual), (_UU32)(num_elements), (message), (UNITY_LINE_TYPE)line, UNITY_DISPLAY_STYLE_INT32) +#define UNITY_TEST_ASSERT_EQUAL_UINT_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualIntArray((UNITY_PTR_ATTRIBUTE const void*)(expected), (UNITY_PTR_ATTRIBUTE const void*)(actual), (_UU32)(num_elements), (message), (UNITY_LINE_TYPE)line, UNITY_DISPLAY_STYLE_UINT) +#define UNITY_TEST_ASSERT_EQUAL_UINT8_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualIntArray((UNITY_PTR_ATTRIBUTE const void*)(expected), (UNITY_PTR_ATTRIBUTE const void*)(actual), (_UU32)(num_elements), (message), (UNITY_LINE_TYPE)line, UNITY_DISPLAY_STYLE_UINT8) +#define UNITY_TEST_ASSERT_EQUAL_UINT16_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualIntArray((UNITY_PTR_ATTRIBUTE const void*)(expected), (UNITY_PTR_ATTRIBUTE const void*)(actual), (_UU32)(num_elements), (message), (UNITY_LINE_TYPE)line, UNITY_DISPLAY_STYLE_UINT16) +#define UNITY_TEST_ASSERT_EQUAL_UINT32_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualIntArray((UNITY_PTR_ATTRIBUTE const void*)(expected), (UNITY_PTR_ATTRIBUTE const void*)(actual), (_UU32)(num_elements), (message), (UNITY_LINE_TYPE)line, UNITY_DISPLAY_STYLE_UINT32) +#define UNITY_TEST_ASSERT_EQUAL_HEX8_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualIntArray((UNITY_PTR_ATTRIBUTE const void*)(expected), (UNITY_PTR_ATTRIBUTE const void*)(actual), (_UU32)(num_elements), (message), (UNITY_LINE_TYPE)line, UNITY_DISPLAY_STYLE_HEX8) +#define UNITY_TEST_ASSERT_EQUAL_HEX16_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualIntArray((UNITY_PTR_ATTRIBUTE const void*)(expected), (UNITY_PTR_ATTRIBUTE const void*)(actual), (_UU32)(num_elements), (message), (UNITY_LINE_TYPE)line, UNITY_DISPLAY_STYLE_HEX16) +#define UNITY_TEST_ASSERT_EQUAL_HEX32_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualIntArray((UNITY_PTR_ATTRIBUTE const void*)(expected), (UNITY_PTR_ATTRIBUTE const void*)(actual), (_UU32)(num_elements), (message), (UNITY_LINE_TYPE)line, UNITY_DISPLAY_STYLE_HEX32) +#define UNITY_TEST_ASSERT_EQUAL_PTR_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualIntArray((UNITY_PTR_ATTRIBUTE const void*)(_UP*)(expected), (const void*)(_UP*)(actual), (_UU32)(num_elements), (message), (UNITY_LINE_TYPE)line, UNITY_DISPLAY_STYLE_POINTER) +#define UNITY_TEST_ASSERT_EQUAL_STRING_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualStringArray((const char**)(expected), (const char**)(actual), (_UU32)(num_elements), (message), (UNITY_LINE_TYPE)line) +#define UNITY_TEST_ASSERT_EQUAL_MEMORY_ARRAY(expected, actual, len, num_elements, line, message) UnityAssertEqualMemory((UNITY_PTR_ATTRIBUTE void*)(expected), (UNITY_PTR_ATTRIBUTE void*)(actual), (_UU32)(len), (_UU32)(num_elements), (message), (UNITY_LINE_TYPE)line) + +#ifdef UNITY_SUPPORT_64 +#define UNITY_TEST_ASSERT_EQUAL_INT64(expected, actual, line, message) UnityAssertEqualNumber((_U_SINT)(expected), (_U_SINT)(actual), (message), (UNITY_LINE_TYPE)line, UNITY_DISPLAY_STYLE_INT64) +#define UNITY_TEST_ASSERT_EQUAL_UINT64(expected, actual, line, message) UnityAssertEqualNumber((_U_SINT)(expected), (_U_SINT)(actual), (message), (UNITY_LINE_TYPE)line, UNITY_DISPLAY_STYLE_UINT64) +#define UNITY_TEST_ASSERT_EQUAL_HEX64(expected, actual, line, message) UnityAssertEqualNumber((_U_SINT)(expected), (_U_SINT)(actual), (message), (UNITY_LINE_TYPE)line, UNITY_DISPLAY_STYLE_HEX64) +#define UNITY_TEST_ASSERT_EQUAL_INT64_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualIntArray((UNITY_PTR_ATTRIBUTE const _U_SINT*)(expected), (UNITY_PTR_ATTRIBUTE const _U_SINT*)(actual), (_UU32)(num_elements), (message), (UNITY_LINE_TYPE)line, UNITY_DISPLAY_STYLE_INT64) +#define UNITY_TEST_ASSERT_EQUAL_UINT64_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualIntArray((UNITY_PTR_ATTRIBUTE const _U_SINT*)(expected), (UNITY_PTR_ATTRIBUTE const _U_SINT*)(actual), (_UU32)(num_elements), (message), (UNITY_LINE_TYPE)line, UNITY_DISPLAY_STYLE_UINT64) +#define UNITY_TEST_ASSERT_EQUAL_HEX64_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualIntArray((UNITY_PTR_ATTRIBUTE const _U_SINT*)(expected), (UNITY_PTR_ATTRIBUTE const _U_SINT*)(actual), (_UU32)(num_elements), (message), (UNITY_LINE_TYPE)line, UNITY_DISPLAY_STYLE_HEX64) +#define UNITY_TEST_ASSERT_INT64_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((_U_SINT)(delta), (_U_SINT)(expected), (_U_SINT)(actual), NULL, (UNITY_LINE_TYPE)line, UNITY_DISPLAY_STYLE_INT64) +#define UNITY_TEST_ASSERT_UINT64_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((_U_SINT)(delta), (_U_SINT)(expected), (_U_SINT)(actual), NULL, (UNITY_LINE_TYPE)line, UNITY_DISPLAY_STYLE_UINT64) +#define UNITY_TEST_ASSERT_HEX64_WITHIN(delta, expected, actual, line, message) UnityAssertNumbersWithin((_U_SINT)(delta), (_U_SINT)(expected), (_U_SINT)(actual), NULL, (UNITY_LINE_TYPE)line, UNITY_DISPLAY_STYLE_HEX64) +#else +#define UNITY_TEST_ASSERT_EQUAL_INT64(expected, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)line, UnityStrErr64) +#define UNITY_TEST_ASSERT_EQUAL_UINT64(expected, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)line, UnityStrErr64) +#define UNITY_TEST_ASSERT_EQUAL_HEX64(expected, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)line, UnityStrErr64) +#define UNITY_TEST_ASSERT_EQUAL_INT64_ARRAY(expected, actual, num_elements, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)line, UnityStrErr64) +#define UNITY_TEST_ASSERT_EQUAL_UINT64_ARRAY(expected, actual, num_elements, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)line, UnityStrErr64) +#define UNITY_TEST_ASSERT_EQUAL_HEX64_ARRAY(expected, actual, num_elements, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)line, UnityStrErr64) +#define UNITY_TEST_ASSERT_INT64_WITHIN(delta, expected, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)line, UnityStrErr64) +#define UNITY_TEST_ASSERT_UINT64_WITHIN(delta, expected, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)line, UnityStrErr64) +#define UNITY_TEST_ASSERT_HEX64_WITHIN(delta, expected, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)line, UnityStrErr64) +#endif + +#ifdef UNITY_EXCLUDE_FLOAT +#define UNITY_TEST_ASSERT_FLOAT_WITHIN(delta, expected, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)line, UnityStrErrFloat) +#define UNITY_TEST_ASSERT_EQUAL_FLOAT(expected, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)line, UnityStrErrFloat) +#define UNITY_TEST_ASSERT_EQUAL_FLOAT_ARRAY(expected, actual, num_elements, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)line, UnityStrErrFloat) +#define UNITY_TEST_ASSERT_FLOAT_IS_INF(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)line, UnityStrErrFloat) +#define UNITY_TEST_ASSERT_FLOAT_IS_NEG_INF(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)line, UnityStrErrFloat) +#define UNITY_TEST_ASSERT_FLOAT_IS_NAN(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)line, UnityStrErrFloat) +#define UNITY_TEST_ASSERT_FLOAT_IS_DETERMINATE(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)line, UnityStrErrFloat) +#define UNITY_TEST_ASSERT_FLOAT_IS_NOT_INF(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)line, UnityStrErrFloat) +#define UNITY_TEST_ASSERT_FLOAT_IS_NOT_NEG_INF(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)line, UnityStrErrFloat) +#define UNITY_TEST_ASSERT_FLOAT_IS_NOT_NAN(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)line, UnityStrErrFloat) +#define UNITY_TEST_ASSERT_FLOAT_IS_NOT_DETERMINATE(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)line, UnityStrErrFloat) +#else +#define UNITY_TEST_ASSERT_FLOAT_WITHIN(delta, expected, actual, line, message) UnityAssertFloatsWithin((_UF)(delta), (_UF)(expected), (_UF)(actual), (message), (UNITY_LINE_TYPE)line) +#define UNITY_TEST_ASSERT_EQUAL_FLOAT(expected, actual, line, message) UNITY_TEST_ASSERT_FLOAT_WITHIN((_UF)(expected) * (_UF)UNITY_FLOAT_PRECISION, (_UF)expected, (_UF)actual, (UNITY_LINE_TYPE)line, message) +#define UNITY_TEST_ASSERT_EQUAL_FLOAT_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualFloatArray((_UF*)(expected), (_UF*)(actual), (_UU32)(num_elements), (message), (UNITY_LINE_TYPE)line) +#define UNITY_TEST_ASSERT_FLOAT_IS_INF(actual, line, message) UnityAssertFloatSpecial((_UF)(actual), (message), (UNITY_LINE_TYPE)line, UNITY_FLOAT_IS_INF) +#define UNITY_TEST_ASSERT_FLOAT_IS_NEG_INF(actual, line, message) UnityAssertFloatSpecial((_UF)(actual), (message), (UNITY_LINE_TYPE)line, UNITY_FLOAT_IS_NEG_INF) +#define UNITY_TEST_ASSERT_FLOAT_IS_NAN(actual, line, message) UnityAssertFloatSpecial((_UF)(actual), (message), (UNITY_LINE_TYPE)line, UNITY_FLOAT_IS_NAN) +#define UNITY_TEST_ASSERT_FLOAT_IS_DETERMINATE(actual, line, message) UnityAssertFloatSpecial((_UF)(actual), (message), (UNITY_LINE_TYPE)line, UNITY_FLOAT_IS_DET) +#define UNITY_TEST_ASSERT_FLOAT_IS_NOT_INF(actual, line, message) UnityAssertFloatSpecial((_UF)(actual), (message), (UNITY_LINE_TYPE)line, UNITY_FLOAT_IS_NOT_INF) +#define UNITY_TEST_ASSERT_FLOAT_IS_NOT_NEG_INF(actual, line, message) UnityAssertFloatSpecial((_UF)(actual), (message), (UNITY_LINE_TYPE)line, UNITY_FLOAT_IS_NOT_NEG_INF) +#define UNITY_TEST_ASSERT_FLOAT_IS_NOT_NAN(actual, line, message) UnityAssertFloatSpecial((_UF)(actual), (message), (UNITY_LINE_TYPE)line, UNITY_FLOAT_IS_NOT_NAN) +#define UNITY_TEST_ASSERT_FLOAT_IS_NOT_DETERMINATE(actual, line, message) UnityAssertFloatSpecial((_UF)(actual), (message), (UNITY_LINE_TYPE)line, UNITY_FLOAT_IS_NOT_DET) +#endif + +#ifdef UNITY_EXCLUDE_DOUBLE +#define UNITY_TEST_ASSERT_DOUBLE_WITHIN(delta, expected, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)line, UnityStrErrDouble) +#define UNITY_TEST_ASSERT_EQUAL_DOUBLE(expected, actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)line, UnityStrErrDouble) +#define UNITY_TEST_ASSERT_EQUAL_DOUBLE_ARRAY(expected, actual, num_elements, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)line, UnityStrErrDouble) +#define UNITY_TEST_ASSERT_DOUBLE_IS_INF(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)line, UnityStrErrDouble) +#define UNITY_TEST_ASSERT_DOUBLE_IS_NEG_INF(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)line, UnityStrErrDouble) +#define UNITY_TEST_ASSERT_DOUBLE_IS_NAN(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)line, UnityStrErrDouble) +#define UNITY_TEST_ASSERT_DOUBLE_IS_DETERMINATE(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)line, UnityStrErrDouble) +#define UNITY_TEST_ASSERT_DOUBLE_IS_NOT_INF(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)line, UnityStrErrDouble) +#define UNITY_TEST_ASSERT_DOUBLE_IS_NOT_NEG_INF(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)line, UnityStrErrDouble) +#define UNITY_TEST_ASSERT_DOUBLE_IS_NOT_NAN(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)line, UnityStrErrDouble) +#define UNITY_TEST_ASSERT_DOUBLE_IS_NOT_DETERMINATE(actual, line, message) UNITY_TEST_FAIL((UNITY_LINE_TYPE)line, UnityStrErrDouble) +#else +#define UNITY_TEST_ASSERT_DOUBLE_WITHIN(delta, expected, actual, line, message) UnityAssertDoublesWithin((_UD)(delta), (_UD)(expected), (_UD)(actual), (message), (UNITY_LINE_TYPE)line) +#define UNITY_TEST_ASSERT_EQUAL_DOUBLE(expected, actual, line, message) UNITY_TEST_ASSERT_DOUBLE_WITHIN((_UD)(expected) * (_UD)UNITY_DOUBLE_PRECISION, (_UD)expected, (_UD)actual, (UNITY_LINE_TYPE)line, message) +#define UNITY_TEST_ASSERT_EQUAL_DOUBLE_ARRAY(expected, actual, num_elements, line, message) UnityAssertEqualDoubleArray((_UD*)(expected), (_UD*)(actual), (_UU32)(num_elements), (message), (UNITY_LINE_TYPE)line) +#define UNITY_TEST_ASSERT_DOUBLE_IS_INF(actual, line, message) UnityAssertDoubleSpecial((_UD)(actual), (message), (UNITY_LINE_TYPE)line, UNITY_FLOAT_IS_INF) +#define UNITY_TEST_ASSERT_DOUBLE_IS_NEG_INF(actual, line, message) UnityAssertDoubleSpecial((_UD)(actual), (message), (UNITY_LINE_TYPE)line, UNITY_FLOAT_IS_NEG_INF) +#define UNITY_TEST_ASSERT_DOUBLE_IS_NAN(actual, line, message) UnityAssertDoubleSpecial((_UD)(actual), (message), (UNITY_LINE_TYPE)line, UNITY_FLOAT_IS_NAN) +#define UNITY_TEST_ASSERT_DOUBLE_IS_DETERMINATE(actual, line, message) UnityAssertDoubleSpecial((_UD)(actual), (message), (UNITY_LINE_TYPE)line, UNITY_FLOAT_IS_DET) +#define UNITY_TEST_ASSERT_DOUBLE_IS_NOT_INF(actual, line, message) UnityAssertDoubleSpecial((_UD)(actual), (message), (UNITY_LINE_TYPE)line, UNITY_FLOAT_IS_NOT_INF) +#define UNITY_TEST_ASSERT_DOUBLE_IS_NOT_NEG_INF(actual, line, message) UnityAssertDoubleSpecial((_UD)(actual), (message), (UNITY_LINE_TYPE)line, UNITY_FLOAT_IS_NOT_NEG_INF) +#define UNITY_TEST_ASSERT_DOUBLE_IS_NOT_NAN(actual, line, message) UnityAssertDoubleSpecial((_UD)(actual), (message), (UNITY_LINE_TYPE)line, UNITY_FLOAT_IS_NOT_NAN) +#define UNITY_TEST_ASSERT_DOUBLE_IS_NOT_DETERMINATE(actual, line, message) UnityAssertDoubleSpecial((_UD)(actual), (message), (UNITY_LINE_TYPE)line, UNITY_FLOAT_IS_NOT_DET) +#endif + +//End of UNITY_INTERNALS_H +#endif diff --git a/tests/Kconfig b/tests/Kconfig new file mode 100644 index 000000000..89fbb3ec3 --- /dev/null +++ b/tests/Kconfig @@ -0,0 +1,11 @@ +# +# For a description of the syntax of this configuration file, +# see misc/tools/kconfig-language.txt. +# + +menu "Unity test framework" +source "$APPSDIR/tests/testing/Kconfig" +source "$APPSDIR/tests/unity/Kconfig" +source "$APPSDIR/tests/unity_usrsock/Kconfig" +source "$APPSDIR/tests/unity_ramtest/Kconfig" +endmenu diff --git a/tests/Make.defs b/tests/Make.defs new file mode 100644 index 000000000..336f8959f --- /dev/null +++ b/tests/Make.defs @@ -0,0 +1,37 @@ +############################################################################ +# apps/tests/Make.defs +# Adds selected testing applications to apps/ build +# +# Copyright (C) 2015 Haltian Ltd. All rights reserved. +# Author: Roman Saveljev +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +include $(wildcard tests/*/Make.defs) diff --git a/tests/Makefile b/tests/Makefile new file mode 100644 index 000000000..3e31d5073 --- /dev/null +++ b/tests/Makefile @@ -0,0 +1,114 @@ +############################################################################ +# apps/tests/Makefile +# +# Copyright (C) 2015-2017 Haltian Ltd. All rights reserved. +# Author: Roman Saveljev +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +-include $(TOPDIR)/.config # Current configuration +-include $(TOPDIR)/Make.defs +include $(APPDIR)/Make.defs + +ASRCS = +AOBJS = $(ASRCS:.S=$(OBJEXT)) + +CSRCS = unity.c unity_fixture.c + +DEPPATH = --dep-path . +VPATH = . + +COBJS = $(CSRCS:.c=$(OBJEXT)) + +SRCS = $(ASRCS) $(CSRCS) +OBJS = $(AOBJS) $(COBJS) + +# Sub-directories + +# Wherever is a Makefile should be included +SUBDIRS = $(dir $(wildcard */Makefile)) + +# Sub-directories that might need context setup. Directories may need +# context setup for a variety of reasons, but the most common is because +# the example may be built as an NSH built-in function. + +# Projects that do not need the 'context' rule define it empty and/or +# variate the behavior according to the product configuration +CNTXTDIRS = $(SUBDIRS) + +all: .built + +.PHONY: context .depend depend clean distclean + +$(AOBJS): %$(OBJEXT): %.S + $(call ASSEMBLE, $<, $@) + +$(COBJS): %$(OBJEXT): %.c + $(call COMPILE, $<, $@) + +$(BIN): $(OBJS) + $(call ARCHIVE, $@, $(OBJS)) + +.built: $(OBJS) + $(call ARCHIVE, $(BIN), $(OBJS)) + @touch .built + +define SDIR_template +$(1)_$(2): + $(Q) $(MAKE) -C $(1) $(2) TOPDIR="$(TOPDIR)" APPDIR="$(APPDIR)" +endef + +$(foreach SDIR, $(CNTXTDIRS), $(eval $(call SDIR_template,$(SDIR),context))) +$(foreach SDIR, $(SUBDIRS), $(eval $(call SDIR_template,$(SDIR),depend))) +$(foreach SDIR, $(SUBDIRS), $(eval $(call SDIR_template,$(SDIR),clean))) +$(foreach SDIR, $(SUBDIRS), $(eval $(call SDIR_template,$(SDIR),distclean))) + +install: + +context: $(foreach SDIR, $(CNTXTDIRS), $(SDIR)_context) + +.depend: Makefile $(SRCS) + $(Q) $(MKDEP) $(DEPPATH) "$(CC)" -- $(CFLAGS) -- $(SRCS) >Make.dep + $(Q) touch $@ + +depend: $(foreach SDIR, $(SUBDIRS), $(SDIR)_depend) .depend + +clean: $(foreach SDIR, $(SUBDIRS), $(SDIR)_clean) + $(call DELFILE, $(BIN)) + $(call CLEAN) + +distclean: $(foreach SDIR, $(SUBDIRS), $(SDIR)_distclean) + $(call DELFILE, Make.dep) + $(call DELFILE, .depend) + +-include Make.dep + +.PHONY: preconfig +preconfig: diff --git a/tests/README.txt b/tests/README.txt new file mode 100644 index 000000000..7bf92a91f --- /dev/null +++ b/tests/README.txt @@ -0,0 +1,34 @@ +README +^^^^^^ + +This folder hosts NuttX unit test framework source files. + +INTRODUCTION +^^^^^^^^^^^^ + +NuttX unit test framework is based on Unity (https://github.com/ThrowTheSwitch/Unity). +The source code bears minimal changes and most of the additional functionality is brought +through the extension. + +NUTTX-SPECIFIC ISSUES +^^^^^^^^^^^^^^^^^^^^^ + +Unity relies on setjmp/longjmp to be available, so a testcase can be aborted. While the +functionality exists in simulator builds, the hardware environment does not have it. To +provide the same baseline we run test bodies and other abortable parts in their own threads. +The main thread blocks until a spawn exits. Thus we create the same context as offered by +setjmp/longjmp. + +RUNNING TESTS +^^^^^^^^^^^^^ + +Tests can be executed both in simulator and in the target. The test application can be built-in +into NSH or provide application entry point. + +Test application supports command line interface: + + application [--list] [test [test...]] + + --list - Lists all available testcases from all included modules + +Test is identified by its module name and function name. diff --git a/tests/docs/Unity_Summary.txt b/tests/docs/Unity_Summary.txt new file mode 100644 index 000000000..a157aaced --- /dev/null +++ b/tests/docs/Unity_Summary.txt @@ -0,0 +1,216 @@ +============== +Unity Test API +============== + +[Copyright (c) 2007 - 2012 Unity Project by Mike Karlesky, Mark VanderVoord, and Greg Williams] + +------------- +Running Tests +------------- + +RUN_TEST(func, linenum) + +Each Test is run within the macro RUN_TEST. This macro performs necessary setup before the test is called and handles cleanup and result tabulation afterwards. + +-------------- +Ignoring Tests +-------------- + +There are times when a test is incomplete or not valid for some reason. At these times, TEST_IGNORE can be called. Control will immediately be returned to the caller of the test, and no failures will be returned. + +TEST_IGNORE() + +Ignore this test and return immediately + +TEST_IGNORE_MESSAGE (message) + +Ignore this test and return immediately. Output a message stating why the test was ignored. + +-------------- +Aborting Tests +-------------- + +There are times when a test will contain an infinite loop on error conditions, or there may be reason to escape from the test early without executing the rest of the test. A pair of macros support this functionality in Unity. The first (TEST_PROTECT) sets up the feature, and handles emergency abort cases. TEST_ABORT can then be used at any time within the tests to return to the last TEST_PROTECT call. + +TEST_PROTECT() + +Setup and Catch macro + +TEST_ABORT() + +Abort Test macro + +Example: + +main() +{ + if (TEST_PROTECT() == 0) + { + MyTest(); + } +} + +If MyTest calls TEST_ABORT, program control will immediately return to TEST_PROTECT with a non-zero return value. + + +======================= +Unity Assertion Summary +======================= + +-------------------- +Basic Validity Tests +-------------------- + +TEST_ASSERT_TRUE(condition) + +Evaluates whatever code is in condition and fails if it evaluates to false + +TEST_ASSERT_FALSE(condition) + +Evaluates whatever code is in condition and fails if it evaluates to true + +TEST_ASSERT(condition) + +Another way of calling TEST_ASSERT_TRUE + +TEST_ASSERT_UNLESS(condition) + +Another way of calling TEST_ASSERT_FALSE + +TEST_FAIL() +TEST_FAIL_MESSAGE(message) + +This test is automatically marked as a failure. The message is output stating why. + +------------------------------ +Numerical Assertions: Integers +------------------------------ + +TEST_ASSERT_EQUAL_INT(expected, actual) +TEST_ASSERT_EQUAL_INT8(expected, actual) +TEST_ASSERT_EQUAL_INT16(expected, actual) +TEST_ASSERT_EQUAL_INT32(expected, actual) +TEST_ASSERT_EQUAL_INT64(expected, actual) + +Compare two integers for equality and display errors as signed integers. A cast will be performed +to your natural integer size so often this can just be used. When you need to specify the exact size, +like when comparing arrays, you can use a specific version: + +TEST_ASSERT_EQUAL_UINT(expected, actual) +TEST_ASSERT_EQUAL_UINT8(expected, actual) +TEST_ASSERT_EQUAL_UINT16(expected, actual) +TEST_ASSERT_EQUAL_UINT32(expected, actual) +TEST_ASSERT_EQUAL_UINT64(expected, actual) + +Compare two integers for equality and display errors as unsigned integers. Like INT, there are +variants for different sizes also. + +TEST_ASSERT_EQUAL_HEX(expected, actual) +TEST_ASSERT_EQUAL_HEX8(expected, actual) +TEST_ASSERT_EQUAL_HEX16(expected, actual) +TEST_ASSERT_EQUAL_HEX32(expected, actual) +TEST_ASSERT_EQUAL_HEX64(expected, actual) + +Compares two integers for equality and display errors as hexadecimal. Like the other integer comparisons, +you can specify the size... here the size will also effect how many nibbles are shown (for example, HEX16 +will show 4 nibbles). + +_ARRAY + +You can append _ARRAY to any of these macros to make an array comparison of that type. Here you will +need to care a bit more about the actual size of the value being checked. You will also specify an +additional argument which is the number of elements to compare. For example: + +TEST_ASSERT_EQUAL_HEX8_ARRAY(expected, actual, elements) + +TEST_ASSERT_EQUAL(expected, actual) + +Another way of calling TEST_ASSERT_EQUAL_INT + +TEST_ASSERT_INT_WITHIN(delta, expected, actual) + +Asserts that the actual value is within plus or minus delta of the expected value. This also comes in +size specific variants. + + +----------------------------- +Numerical Assertions: Bitwise +----------------------------- + +TEST_ASSERT_BITS(mask, expected, actual) + +Use an integer mask to specify which bits should be compared between two other integers. High bits in the mask are compared, low bits ignored. + +TEST_ASSERT_BITS_HIGH(mask, actual) + +Use an integer mask to specify which bits should be inspected to determine if they are all set high. High bits in the mask are compared, low bits ignored. + +TEST_ASSERT_BITS_LOW(mask, actual) + +Use an integer mask to specify which bits should be inspected to determine if they are all set low. High bits in the mask are compared, low bits ignored. + +TEST_ASSERT_BIT_HIGH(bit, actual) + +Test a single bit and verify that it is high. The bit is specified 0-31 for a 32-bit integer. + +TEST_ASSERT_BIT_LOW(bit, actual) + +Test a single bit and verify that it is low. The bit is specified 0-31 for a 32-bit integer. + +---------------------------- +Numerical Assertions: Floats +---------------------------- + +TEST_ASSERT_FLOAT_WITHIN(delta, expected, actual) + +Asserts that the actual value is within plus or minus delta of the expected value. + +TEST_ASSERT_EQUAL_FLOAT(expected, actual) +TEST_ASSERT_EQUAL_DOUBLE(expected, actual) + +Asserts that two floating point values are "equal" within a small % delta of the expected value. + +----------------- +String Assertions +----------------- + +TEST_ASSERT_EQUAL_STRING(expected, actual) + +Compare two null-terminate strings. Fail if any character is different or if the lengths are different. + +TEST_ASSERT_EQUAL_STRING_MESSAGE(expected, actual, message) + +Compare two null-terminate strings. Fail if any character is different or if the lengths are different. Output a custom message on failure. + +------------------ +Pointer Assertions +------------------ + +Most pointer operations can be performed by simply using the integer comparisons above. However, a couple of special cases are added for clarity. + +TEST_ASSERT_NULL(pointer) + +Fails if the pointer is not equal to NULL + +TEST_ASSERT_NOT_NULL(pointer) + +Fails if the pointer is equal to NULL + + +----------------- +Memory Assertions +----------------- + +TEST_ASSERT_EQUAL_MEMORY(expected, actual, len) + +Compare two blocks of memory. This is a good generic assertion for types that can't be coerced into acting like +standard types... but since it's a memory compare, you have to be careful that your data types are packed. + +-------- +_MESSAGE +-------- + +you can append _MESSAGE to any of the macros to make them take an additional argument. This argument +is a string that will be printed at the end of the failure strings. This is useful for specifying more +information about the problem. + diff --git a/tests/docs/license.txt b/tests/docs/license.txt new file mode 100644 index 000000000..d0f635fa3 --- /dev/null +++ b/tests/docs/license.txt @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2007-14 Mike Karlesky, Mark VanderVoord, Greg Williams + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/tests/testing/.built b/tests/testing/.built new file mode 100644 index 000000000..e69de29bb diff --git a/tests/testing/Kconfig b/tests/testing/Kconfig new file mode 100644 index 000000000..ae2bf3130 --- /dev/null +++ b/tests/testing/Kconfig @@ -0,0 +1,4 @@ +# +# For a description of the syntax of this configuration file, +# see misc/tools/kconfig-language.txt. +# diff --git a/tests/testing/Make.defs b/tests/testing/Make.defs new file mode 100644 index 000000000..fc761474f --- /dev/null +++ b/tests/testing/Make.defs @@ -0,0 +1,37 @@ +############################################################################ +# apps/tests/unity/Make.defs +# Adds selected testing applications to apps/ build +# +# Copyright (C) 2015 Haltian Ltd. All rights reserved. +# Author: Roman Saveljev +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +CONFIGURED_APPS += tests/testing diff --git a/tests/testing/Makefile b/tests/testing/Makefile new file mode 100644 index 000000000..2ae3d138e --- /dev/null +++ b/tests/testing/Makefile @@ -0,0 +1,95 @@ +############################################################################ +# testing/Makefile +# +# Copyright (C) 2015 Haltian Ltd. All rights reserved. +# Author: Roman Saveljev +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +-include $(TOPDIR)/.config +-include $(TOPDIR)/Make.defs +include $(APPDIR)/Make.defs + +ASRCS = +CSRCS = unity.c unity_fixture.c + +AOBJS = $(ASRCS:.S=$(OBJEXT)) +COBJS = $(CSRCS:.c=$(OBJEXT)) + +SRCS = $(ASRCS) $(CSRCS) +OBJS = $(AOBJS) $(COBJS) + +ifeq ($(CONFIG_WINDOWS_NATIVE),y) + BIN = ..\..\libapps$(LIBEXT) +else +ifeq ($(WINTOOL),y) + BIN = ..\\..\\libapps$(LIBEXT) +else + BIN = ../../libapps$(LIBEXT) +endif +endif + +ROOTDEPPATH = --dep-path . +VPATH = + +# Build targets + +all: .built +.PHONY: context .depend depend clean distclean + +$(AOBJS): %$(OBJEXT): %.S + $(call ASSEMBLE, $<, $@) + +$(COBJS): %$(OBJEXT): %.c + $(call COMPILE, $<, $@) + +.built: $(OBJS) + $(call ARCHIVE, $(BIN), $(OBJS)) + @touch .built + +install: + +context: + +.depend: Makefile $(SRCS) + @$(MKDEP) $(ROOTDEPPATH) "$(CC)" -- $(CFLAGS) -- $(SRCS) >Make.dep + @touch $@ + +depend: .depend + +clean: + $(call DELFILE, .built) + $(call CLEAN) + +distclean: clean + $(call DELFILE, Make.dep) + $(call DELFILE, .depend) + +-include Make.dep diff --git a/tests/testing/unity.c b/tests/testing/unity.c new file mode 100644 index 000000000..689103b6d --- /dev/null +++ b/tests/testing/unity.c @@ -0,0 +1,1268 @@ +/* ========================================================================= + Unity Project - A Test Framework for C + Copyright (c) 2007-14 Mike Karlesky, Mark VanderVoord, Greg Williams + [Released under MIT License. Please refer to license.txt for details] +============================================================================ */ + +#include +#include + +#define UNITY_FAIL_AND_BAIL { Unity.CurrentTestFailed = 1; UnityAbort(); } +#define UNITY_IGNORE_AND_BAIL { Unity.CurrentTestIgnored = 1; UnityAbort(); } +/// return prematurely if we are already in failure or ignore state +#define UNITY_SKIP_EXECUTION { if ((Unity.CurrentTestFailed != 0) || (Unity.CurrentTestIgnored != 0)) {return;} } +#define UNITY_PRINT_EOL { UNITY_OUTPUT_CHAR('\n'); } + +#define UNITY_MSEC_IN_USEC 1000 +#define UNITY_MIN_TIMEOUT_MSEC 200 + +#define SIG_UNITYSTOP 15 + +struct _Unity Unity; + +const char UnityStrOk[] = "OK"; +const char UnityStrPass[] = "PASS"; +const char UnityStrFail[] = "FAIL"; +const char UnityStrIgnore[] = "IGNORE"; +const char UnityStrNull[] = "NULL"; +const char UnityStrSpacer[] = ". "; +const char UnityStrExpected[] = " Expected "; +const char UnityStrWas[] = " Was "; +const char UnityStrTo[] = " To "; +const char UnityStrElement[] = " Element "; +const char UnityStrByte[] = " Byte "; +const char UnityStrMemory[] = " Memory Mismatch."; +const char UnityStrDelta[] = " Values Not Within Delta "; +const char UnityStrPointless[] = " You Asked Me To Compare Nothing, Which Was Pointless."; +const char UnityStrNullPointerForExpected[] = " Expected pointer to be NULL"; +const char UnityStrNullPointerForActual[] = " Actual pointer was NULL"; +const char UnityStrNot[] = "Not "; +const char UnityStrInf[] = "Infinity"; +const char UnityStrNegInf[] = "Negative Infinity"; +const char UnityStrNaN[] = "NaN"; +const char UnityStrDet[] = "Determinate"; +const char UnityStrErrFloat[] = "Unity Floating Point Disabled"; +const char UnityStrErrDouble[] = "Unity Double Precision Disabled"; +const char UnityStrErr64[] = "Unity 64-bit Support Disabled"; +const char UnityStrBreaker[] = "-----------------------"; +const char UnityStrResultsTests[] = " Tests "; +const char UnityStrResultsFailures[] = " Failures "; +const char UnityStrResultsIgnored[] = " Ignored "; + +#ifndef UNITY_EXCLUDE_FLOAT +// Dividing by these constants produces +/- infinity. +// The rationale is given in UnityAssertFloatIsInf's body. +static const _UF f_zero = 0.0f; +#ifndef UNITY_EXCLUDE_DOUBLE +static const _UD d_zero = 0.0; +#endif +#endif + +// compiler-generic print formatting masks +const _U_UINT UnitySizeMask[] = +{ + 255u, // 0xFF + 65535u, // 0xFFFF + 65535u, + 4294967295u, // 0xFFFFFFFF + 4294967295u, + 4294967295u, + 4294967295u +#ifdef UNITY_SUPPORT_64 + ,0xFFFFFFFFFFFFFFFF +#endif +}; + +struct UnityTimeoutAction +{ + _U_UINT timeout_msec; + pthread_t thread; + bool cancel_protected; +}; + +void UnityPrintFail(void); +void UnityPrintOk(void); + +static void UnityAbort(void) noreturn_function; + +static void UnityAbort(void) +{ + pthread_exit((void*)1); +} + +//----------------------------------------------- +// Pretty Printers & Test Result Output Handlers +//----------------------------------------------- + +void UnityPrint(const char* string) +{ + const char* pch = string; + + if (pch != NULL) + { + while (*pch) + { + // printable characters plus CR & LF are printed + if ((*pch <= 126) && (*pch >= 32)) + { + UNITY_OUTPUT_CHAR(*pch); + } + //write escaped carriage returns + else if (*pch == 13) + { + UNITY_OUTPUT_CHAR('\\'); + UNITY_OUTPUT_CHAR('r'); + } + //write escaped line feeds + else if (*pch == 10) + { + UNITY_OUTPUT_CHAR('\\'); + UNITY_OUTPUT_CHAR('n'); + } + // unprintable characters are shown as codes + else + { + UNITY_OUTPUT_CHAR('\\'); + UnityPrintNumberHex((_U_UINT)*pch, 2); + } + pch++; + } + } +} + +//----------------------------------------------- +void UnityPrintNumberByStyle(const _U_SINT number, const UNITY_DISPLAY_STYLE_T style) +{ + if ((style & UNITY_DISPLAY_RANGE_INT) == UNITY_DISPLAY_RANGE_INT) + { + UnityPrintNumber(number); + } + else if ((style & UNITY_DISPLAY_RANGE_UINT) == UNITY_DISPLAY_RANGE_UINT) + { + UnityPrintNumberUnsigned( (_U_UINT)number & UnitySizeMask[((_U_UINT)style & (_U_UINT)0x0F) - 1] ); + } + else + { + UnityPrintNumberHex((_U_UINT)number, (char)((style & 0x000F) << 1)); + } +} + +//----------------------------------------------- +/// basically do an itoa using as little ram as possible +void UnityPrintNumber(const _U_SINT number_to_print) +{ + _U_SINT divisor = 1; + _U_SINT next_divisor; + _U_UINT number; + + if (number_to_print == (1l << (UNITY_LONG_WIDTH-1))) + { + //The largest representable negative number + UNITY_OUTPUT_CHAR('-'); + number = (1ul << (UNITY_LONG_WIDTH-1)); + } + else if (number_to_print < 0) + { + //Some other negative number + UNITY_OUTPUT_CHAR('-'); + number = (_U_UINT)(-number_to_print); + } + else + { + //Positive number + number = (_U_UINT)number_to_print; + } + + // figure out initial divisor + while (number / divisor > 9) + { + next_divisor = divisor * 10; + if (next_divisor > divisor) + divisor = next_divisor; + else + break; + } + + // now mod and print, then divide divisor + do + { + UNITY_OUTPUT_CHAR((char)('0' + (number / divisor % 10))); + divisor /= 10; + } + while (divisor > 0); +} + +//----------------------------------------------- +/// basically do an itoa using as little ram as possible +void UnityPrintNumberUnsigned(const _U_UINT number) +{ + _U_UINT divisor = 1; + _U_UINT next_divisor; + + // figure out initial divisor + while (number / divisor > 9) + { + next_divisor = divisor * 10; + if (next_divisor > divisor) + divisor = next_divisor; + else + break; + } + + // now mod and print, then divide divisor + do + { + UNITY_OUTPUT_CHAR((char)('0' + (number / divisor % 10))); + divisor /= 10; + } + while (divisor > 0); +} + +//----------------------------------------------- +void UnityPrintNumberHex(const _U_UINT number, const char nibbles_to_print) +{ + _U_UINT nibble; + char nibbles = nibbles_to_print; + UNITY_OUTPUT_CHAR('0'); + UNITY_OUTPUT_CHAR('x'); + + while (nibbles > 0) + { + nibble = (number >> (--nibbles << 2)) & 0x0000000F; + if (nibble <= 9) + { + UNITY_OUTPUT_CHAR((char)('0' + nibble)); + } + else + { + UNITY_OUTPUT_CHAR((char)('A' - 10 + nibble)); + } + } +} + +//----------------------------------------------- +void UnityPrintMask(const _U_UINT mask, const _U_UINT number) +{ + _U_UINT current_bit = (_U_UINT)1 << (UNITY_INT_WIDTH - 1); + _US32 i; + + for (i = 0; i < UNITY_INT_WIDTH; i++) + { + if (current_bit & mask) + { + if (current_bit & number) + { + UNITY_OUTPUT_CHAR('1'); + } + else + { + UNITY_OUTPUT_CHAR('0'); + } + } + else + { + UNITY_OUTPUT_CHAR('X'); + } + current_bit = current_bit >> 1; + } +} + +//----------------------------------------------- +#ifdef UNITY_FLOAT_VERBOSE +#include +void UnityPrintFloat(_UF number) +{ + char TempBuffer[32]; + sprintf(TempBuffer, "%.6f", number); + UnityPrint(TempBuffer); +} +#endif + +//----------------------------------------------- + +void UnityPrintFail(void) +{ + UnityPrint(UnityStrFail); +} + +void UnityPrintOk(void) +{ + UnityPrint(UnityStrOk); +} + +//----------------------------------------------- +static void UnityTestResultsBegin(const char* file, const UNITY_LINE_TYPE line) +{ + UnityPrint(file); + UNITY_OUTPUT_CHAR(':'); + UnityPrintNumber((_U_SINT)line); + UNITY_OUTPUT_CHAR(':'); + UnityPrint(Unity.CurrentTestName); + UNITY_OUTPUT_CHAR(':'); +} + +//----------------------------------------------- +static void UnityTestResultsFailBegin(const UNITY_LINE_TYPE line) +{ + UnityTestResultsBegin(Unity.TestFile, line); + UnityPrint(UnityStrFail); + UNITY_OUTPUT_CHAR(':'); +} + +//----------------------------------------------- +void UnityConcludeTest(void) +{ + if (Unity.CurrentTestIgnored) + { + Unity.TestIgnores++; + } + else if (!Unity.CurrentTestFailed) + { + UnityTestResultsBegin(Unity.TestFile, Unity.CurrentTestLineNumber); + UnityPrint(UnityStrPass); + } + else + { + Unity.TestFailures++; + } + + Unity.CurrentTestFailed = 0; + Unity.CurrentTestIgnored = 0; + UNITY_PRINT_EOL; +} + +//----------------------------------------------- +static void UnityAddMsgIfSpecified(const char* msg) +{ + if (msg) + { + UnityPrint(UnityStrSpacer); + UnityPrint(msg); + } +} + +//----------------------------------------------- +static void UnityPrintExpectedAndActualStrings(const char* expected, const char* actual) +{ + UnityPrint(UnityStrExpected); + if (expected != NULL) + { + UNITY_OUTPUT_CHAR('\''); + UnityPrint(expected); + UNITY_OUTPUT_CHAR('\''); + } + else + { + UnityPrint(UnityStrNull); + } + UnityPrint(UnityStrWas); + if (actual != NULL) + { + UNITY_OUTPUT_CHAR('\''); + UnityPrint(actual); + UNITY_OUTPUT_CHAR('\''); + } + else + { + UnityPrint(UnityStrNull); + } +} + +//----------------------------------------------- +// Assertion & Control Helpers +//----------------------------------------------- + +static int UnityCheckArraysForNull(UNITY_PTR_ATTRIBUTE const void* expected, UNITY_PTR_ATTRIBUTE const void* actual, const UNITY_LINE_TYPE lineNumber, const char* msg) +{ + //return true if they are both NULL + if ((expected == NULL) && (actual == NULL)) + return 1; + + //throw error if just expected is NULL + if (expected == NULL) + { + UnityTestResultsFailBegin(lineNumber); + UnityPrint(UnityStrNullPointerForExpected); + UnityAddMsgIfSpecified(msg); + UNITY_FAIL_AND_BAIL; + } + + //throw error if just actual is NULL + if (actual == NULL) + { + UnityTestResultsFailBegin(lineNumber); + UnityPrint(UnityStrNullPointerForActual); + UnityAddMsgIfSpecified(msg); + UNITY_FAIL_AND_BAIL; + } + + //return false if neither is NULL + return 0; +} + +//----------------------------------------------- +// Assertion Functions +//----------------------------------------------- + +void UnityAssertBits(const _U_SINT mask, + const _U_SINT expected, + const _U_SINT actual, + const char* msg, + const UNITY_LINE_TYPE lineNumber) +{ + UNITY_SKIP_EXECUTION; + + if ((mask & expected) != (mask & actual)) + { + UnityTestResultsFailBegin(lineNumber); + UnityPrint(UnityStrExpected); + UnityPrintMask((_U_UINT)mask, (_U_UINT)expected); + UnityPrint(UnityStrWas); + UnityPrintMask((_U_UINT)mask, (_U_UINT)actual); + UnityAddMsgIfSpecified(msg); + UNITY_FAIL_AND_BAIL; + } +} + +//----------------------------------------------- +void UnityAssertEqualNumber(const _U_SINT expected, + const _U_SINT actual, + const char* msg, + const UNITY_LINE_TYPE lineNumber, + const UNITY_DISPLAY_STYLE_T style) +{ + UNITY_SKIP_EXECUTION; + + if (expected != actual) + { + UnityTestResultsFailBegin(lineNumber); + UnityPrint(UnityStrExpected); + UnityPrintNumberByStyle(expected, style); + UnityPrint(UnityStrWas); + UnityPrintNumberByStyle(actual, style); + UnityAddMsgIfSpecified(msg); + UNITY_FAIL_AND_BAIL; + } +} + +//----------------------------------------------- +void UnityAssertEqualIntArray(UNITY_PTR_ATTRIBUTE const void* expected, + UNITY_PTR_ATTRIBUTE const void* actual, + const _UU32 num_elements, + const char* msg, + const UNITY_LINE_TYPE lineNumber, + const UNITY_DISPLAY_STYLE_T style) +{ + _UU32 elements = num_elements; + UNITY_PTR_ATTRIBUTE const _US8* ptr_exp = (UNITY_PTR_ATTRIBUTE const _US8*)expected; + UNITY_PTR_ATTRIBUTE const _US8* ptr_act = (UNITY_PTR_ATTRIBUTE const _US8*)actual; + + UNITY_SKIP_EXECUTION; + + if (elements == 0) + { + UnityTestResultsFailBegin(lineNumber); + UnityPrint(UnityStrPointless); + UnityAddMsgIfSpecified(msg); + UNITY_FAIL_AND_BAIL; + } + + if (UnityCheckArraysForNull((UNITY_PTR_ATTRIBUTE const void*)expected, (UNITY_PTR_ATTRIBUTE const void*)actual, lineNumber, msg) == 1) + return; + + // If style is UNITY_DISPLAY_STYLE_INT, we'll fall into the default case rather than the INT16 or INT32 (etc) case + // as UNITY_DISPLAY_STYLE_INT includes a flag for UNITY_DISPLAY_RANGE_AUTO, which the width-specific + // variants do not. Therefore remove this flag. + switch(style & (UNITY_DISPLAY_STYLE_T)(~UNITY_DISPLAY_RANGE_AUTO)) + { + case UNITY_DISPLAY_STYLE_HEX8: + case UNITY_DISPLAY_STYLE_INT8: + case UNITY_DISPLAY_STYLE_UINT8: + while (elements--) + { + if (*ptr_exp != *ptr_act) + { + UnityTestResultsFailBegin(lineNumber); + UnityPrint(UnityStrElement); + UnityPrintNumberByStyle((num_elements - elements - 1), UNITY_DISPLAY_STYLE_UINT); + UnityPrint(UnityStrExpected); + UnityPrintNumberByStyle(*ptr_exp, style); + UnityPrint(UnityStrWas); + UnityPrintNumberByStyle(*ptr_act, style); + UnityAddMsgIfSpecified(msg); + UNITY_FAIL_AND_BAIL; + } + ptr_exp += 1; + ptr_act += 1; + } + break; + case UNITY_DISPLAY_STYLE_HEX16: + case UNITY_DISPLAY_STYLE_INT16: + case UNITY_DISPLAY_STYLE_UINT16: + while (elements--) + { + if (*(UNITY_PTR_ATTRIBUTE _US16*)ptr_exp != *(UNITY_PTR_ATTRIBUTE _US16*)ptr_act) + { + if (*(UNITY_PTR_ATTRIBUTE const _US16*)ptr_exp != *(UNITY_PTR_ATTRIBUTE const _US16*)ptr_act) + { + UnityTestResultsFailBegin(lineNumber); + UnityPrint(UnityStrElement); + UnityPrintNumberByStyle((num_elements - elements - 1), UNITY_DISPLAY_STYLE_UINT); + UnityPrint(UnityStrExpected); + UnityPrintNumberByStyle(*(UNITY_PTR_ATTRIBUTE const _US16*)ptr_exp, style); + UnityPrint(UnityStrWas); + UnityPrintNumberByStyle(*(UNITY_PTR_ATTRIBUTE const _US16*)ptr_act, style); + UnityAddMsgIfSpecified(msg); + UNITY_FAIL_AND_BAIL; + } + ptr_exp += 2; + ptr_act += 2; + } + ptr_exp += 2; + ptr_act += 2; + } + break; +#ifdef UNITY_SUPPORT_64 + case UNITY_DISPLAY_STYLE_HEX64: + case UNITY_DISPLAY_STYLE_INT64: + case UNITY_DISPLAY_STYLE_UINT64: + while (elements--) + { + if (*(UNITY_PTR_ATTRIBUTE _US64*)ptr_exp != *(UNITY_PTR_ATTRIBUTE _US64*)ptr_act) + { + if (*(UNITY_PTR_ATTRIBUTE const _US64*)ptr_exp != *(UNITY_PTR_ATTRIBUTE const _US64*)ptr_act) + { + UnityTestResultsFailBegin(lineNumber); + UnityPrint(UnityStrElement); + UnityPrintNumberByStyle((num_elements - elements - 1), UNITY_DISPLAY_STYLE_UINT); + UnityPrint(UnityStrExpected); + UnityPrintNumberByStyle(*(UNITY_PTR_ATTRIBUTE const _US64*)ptr_exp, style); + UnityPrint(UnityStrWas); + UnityPrintNumberByStyle(*(UNITY_PTR_ATTRIBUTE const _US64*)ptr_act, style); + UnityAddMsgIfSpecified(msg); + UNITY_FAIL_AND_BAIL; + } + ptr_exp += 8; + ptr_act += 8; + } + ptr_exp += 8; + ptr_act += 8; + } + break; +#endif + default: + while (elements--) + { + if (*(UNITY_PTR_ATTRIBUTE _US32*)ptr_exp != *(UNITY_PTR_ATTRIBUTE _US32*)ptr_act) + { + if (*(UNITY_PTR_ATTRIBUTE const _US32*)ptr_exp != *(UNITY_PTR_ATTRIBUTE const _US32*)ptr_act) + { + UnityTestResultsFailBegin(lineNumber); + UnityPrint(UnityStrElement); + UnityPrintNumberByStyle((num_elements - elements - 1), UNITY_DISPLAY_STYLE_UINT); + UnityPrint(UnityStrExpected); + UnityPrintNumberByStyle(*(UNITY_PTR_ATTRIBUTE const _US32*)ptr_exp, style); + UnityPrint(UnityStrWas); + UnityPrintNumberByStyle(*(UNITY_PTR_ATTRIBUTE const _US32*)ptr_act, style); + UnityAddMsgIfSpecified(msg); + UNITY_FAIL_AND_BAIL; + } + ptr_exp += 4; + ptr_act += 4; + } + ptr_exp += 4; + ptr_act += 4; + } + break; + } +} + +//----------------------------------------------- +#ifndef UNITY_EXCLUDE_FLOAT +void UnityAssertEqualFloatArray(UNITY_PTR_ATTRIBUTE const _UF* expected, + UNITY_PTR_ATTRIBUTE const _UF* actual, + const _UU32 num_elements, + const char* msg, + const UNITY_LINE_TYPE lineNumber) +{ + _UU32 elements = num_elements; + UNITY_PTR_ATTRIBUTE const _UF* ptr_expected = expected; + UNITY_PTR_ATTRIBUTE const _UF* ptr_actual = actual; + _UF diff, tol; + + UNITY_SKIP_EXECUTION; + + if (elements == 0) + { + UnityTestResultsFailBegin(lineNumber); + UnityPrint(UnityStrPointless); + UnityAddMsgIfSpecified(msg); + UNITY_FAIL_AND_BAIL; + } + + if (UnityCheckArraysForNull((UNITY_PTR_ATTRIBUTE const void*)expected, (UNITY_PTR_ATTRIBUTE const void*)actual, lineNumber, msg) == 1) + return; + + while (elements--) + { + diff = *ptr_expected - *ptr_actual; + if (diff < 0.0f) + diff = 0.0f - diff; + tol = UNITY_FLOAT_PRECISION **ptr_expected; + if (tol < 0.0f) + tol = 0.0f - tol; + + //This first part of this condition will catch any NaN or Infinite values + if ((diff * 0.0f != 0.0f) || (diff > tol)) + { + UnityTestResultsFailBegin(lineNumber); + UnityPrint(UnityStrElement); + UnityPrintNumberByStyle((num_elements - elements - 1), UNITY_DISPLAY_STYLE_UINT); +#ifdef UNITY_FLOAT_VERBOSE + UnityPrint(UnityStrExpected); + UnityPrintFloat(*ptr_expected); + UnityPrint(UnityStrWas); + UnityPrintFloat(*ptr_actual); +#else + UnityPrint(UnityStrDelta); +#endif + UnityAddMsgIfSpecified(msg); + UNITY_FAIL_AND_BAIL; + } + ptr_expected++; + ptr_actual++; + } +} + +//----------------------------------------------- +void UnityAssertFloatsWithin(const _UF delta, + const _UF expected, + const _UF actual, + const char* msg, + const UNITY_LINE_TYPE lineNumber) +{ + _UF diff = actual - expected; + _UF pos_delta = delta; + + UNITY_SKIP_EXECUTION; + + if (diff < 0.0f) + { + diff = 0.0f - diff; + } + if (pos_delta < 0.0f) + { + pos_delta = 0.0f - pos_delta; + } + + //This first part of this condition will catch any NaN or Infinite values + if ((diff * 0.0f != 0.0f) || (pos_delta < diff)) + { + UnityTestResultsFailBegin(lineNumber); +#ifdef UNITY_FLOAT_VERBOSE + UnityPrint(UnityStrExpected); + UnityPrintFloat(expected); + UnityPrint(UnityStrWas); + UnityPrintFloat(actual); +#else + UnityPrint(UnityStrDelta); +#endif + UnityAddMsgIfSpecified(msg); + UNITY_FAIL_AND_BAIL; + } +} + +//----------------------------------------------- +void UnityAssertFloatSpecial(const _UF actual, + const char* msg, + const UNITY_LINE_TYPE lineNumber, + const UNITY_FLOAT_TRAIT_T style) +{ + const char* trait_names[] = { UnityStrInf, UnityStrNegInf, UnityStrNaN, UnityStrDet }; + _U_SINT should_be_trait = ((_U_SINT)style & 1); + _U_SINT is_trait = !should_be_trait; + _U_SINT trait_index = style >> 1; + + UNITY_SKIP_EXECUTION; + + switch(style) + { + //To determine Inf / Neg Inf, we compare to an Inf / Neg Inf value we create on the fly + //We are using a variable to hold the zero value because some compilers complain about dividing by zero otherwise + case UNITY_FLOAT_IS_INF: + case UNITY_FLOAT_IS_NOT_INF: + is_trait = ((1.0f / f_zero) == actual) ? 1 : 0; + break; + case UNITY_FLOAT_IS_NEG_INF: + case UNITY_FLOAT_IS_NOT_NEG_INF: + is_trait = ((-1.0f / f_zero) == actual) ? 1 : 0; + break; + + //NaN is the only floating point value that does NOT equal itself. Therefore if Actual == Actual, then it is NOT NaN. + case UNITY_FLOAT_IS_NAN: + case UNITY_FLOAT_IS_NOT_NAN: + is_trait = (actual == actual) ? 0 : 1; + break; + + //A determinate number is non infinite and not NaN. (therefore the opposite of the two above) + case UNITY_FLOAT_IS_DET: + case UNITY_FLOAT_IS_NOT_DET: + if ( (actual != actual) || ((1.0f / f_zero) == actual) || ((-1.0f / f_zero) == actual) ) + is_trait = 0; + else + is_trait = 1; + break; + default: + ; + } + + if (is_trait != should_be_trait) + { + UnityTestResultsFailBegin(lineNumber); + UnityPrint(UnityStrExpected); + if (!should_be_trait) + UnityPrint(UnityStrNot); + UnityPrint(trait_names[trait_index]); + UnityPrint(UnityStrWas); +#ifdef UNITY_FLOAT_VERBOSE + UnityPrintFloat(actual); +#else + if (should_be_trait) + UnityPrint(UnityStrNot); + UnityPrint(trait_names[trait_index]); +#endif + UnityAddMsgIfSpecified(msg); + UNITY_FAIL_AND_BAIL; + } +} + +#endif //not UNITY_EXCLUDE_FLOAT + +//----------------------------------------------- +#ifndef UNITY_EXCLUDE_DOUBLE +void UnityAssertEqualDoubleArray(UNITY_PTR_ATTRIBUTE const _UD* expected, + UNITY_PTR_ATTRIBUTE const _UD* actual, + const _UU32 num_elements, + const char* msg, + const UNITY_LINE_TYPE lineNumber) +{ + _UU32 elements = num_elements; + UNITY_PTR_ATTRIBUTE const _UD* ptr_expected = expected; + UNITY_PTR_ATTRIBUTE const _UD* ptr_actual = actual; + _UD diff, tol; + + UNITY_SKIP_EXECUTION; + + if (elements == 0) + { + UnityTestResultsFailBegin(lineNumber); + UnityPrint(UnityStrPointless); + UnityAddMsgIfSpecified(msg); + UNITY_FAIL_AND_BAIL; + } + + if (UnityCheckArraysForNull((UNITY_PTR_ATTRIBUTE void*)expected, (UNITY_PTR_ATTRIBUTE void*)actual, lineNumber, msg) == 1) + return; + + while (elements--) + { + diff = *ptr_expected - *ptr_actual; + if (diff < 0.0) + diff = 0.0 - diff; + tol = UNITY_DOUBLE_PRECISION **ptr_expected; + if (tol < 0.0) + tol = 0.0 - tol; + + //This first part of this condition will catch any NaN or Infinite values + if ((diff * 0.0 != 0.0) || (diff > tol)) + { + UnityTestResultsFailBegin(lineNumber); + UnityPrint(UnityStrElement); + UnityPrintNumberByStyle((num_elements - elements - 1), UNITY_DISPLAY_STYLE_UINT); +#ifdef UNITY_DOUBLE_VERBOSE + UnityPrint(UnityStrExpected); + UnityPrintFloat((float)(*ptr_expected)); + UnityPrint(UnityStrWas); + UnityPrintFloat((float)(*ptr_actual)); +#else + UnityPrint(UnityStrDelta); +#endif + UnityAddMsgIfSpecified(msg); + UNITY_FAIL_AND_BAIL; + } + ptr_expected++; + ptr_actual++; + } +} + +//----------------------------------------------- +void UnityAssertDoublesWithin(const _UD delta, + const _UD expected, + const _UD actual, + const char* msg, + const UNITY_LINE_TYPE lineNumber) +{ + _UD diff = actual - expected; + _UD pos_delta = delta; + + UNITY_SKIP_EXECUTION; + + if (diff < 0.0) + { + diff = 0.0 - diff; + } + if (pos_delta < 0.0) + { + pos_delta = 0.0 - pos_delta; + } + + //This first part of this condition will catch any NaN or Infinite values + if ((diff * 0.0 != 0.0) || (pos_delta < diff)) + { + UnityTestResultsFailBegin(lineNumber); +#ifdef UNITY_DOUBLE_VERBOSE + UnityPrint(UnityStrExpected); + UnityPrintFloat((float)expected); + UnityPrint(UnityStrWas); + UnityPrintFloat((float)actual); +#else + UnityPrint(UnityStrDelta); +#endif + UnityAddMsgIfSpecified(msg); + UNITY_FAIL_AND_BAIL; + } +} + +//----------------------------------------------- + +void UnityAssertDoubleSpecial(const _UD actual, + const char* msg, + const UNITY_LINE_TYPE lineNumber, + const UNITY_FLOAT_TRAIT_T style) +{ + const char* trait_names[] = { UnityStrInf, UnityStrNegInf, UnityStrNaN, UnityStrDet }; + _U_SINT should_be_trait = ((_U_SINT)style & 1); + _U_SINT is_trait = !should_be_trait; + _U_SINT trait_index = style >> 1; + + UNITY_SKIP_EXECUTION; + + switch(style) + { + //To determine Inf / Neg Inf, we compare to an Inf / Neg Inf value we create on the fly + //We are using a variable to hold the zero value because some compilers complain about dividing by zero otherwise + case UNITY_FLOAT_IS_INF: + case UNITY_FLOAT_IS_NOT_INF: + is_trait = ((1.0 / d_zero) == actual) ? 1 : 0; + break; + case UNITY_FLOAT_IS_NEG_INF: + case UNITY_FLOAT_IS_NOT_NEG_INF: + is_trait = ((-1.0 / d_zero) == actual) ? 1 : 0; + break; + + //NaN is the only floating point value that does NOT equal itself. Therefore if Actual == Actual, then it is NOT NaN. + case UNITY_FLOAT_IS_NAN: + case UNITY_FLOAT_IS_NOT_NAN: + is_trait = (actual == actual) ? 0 : 1; + break; + + //A determinate number is non infinite and not NaN. (therefore the opposite of the two above) + case UNITY_FLOAT_IS_DET: + case UNITY_FLOAT_IS_NOT_DET: + if ( (actual != actual) || ((1.0 / d_zero) == actual) || ((-1.0 / d_zero) == actual) ) + is_trait = 0; + else + is_trait = 1; + break; + default: + ; + } + + if (is_trait != should_be_trait) + { + UnityTestResultsFailBegin(lineNumber); + UnityPrint(UnityStrExpected); + if (!should_be_trait) + UnityPrint(UnityStrNot); + UnityPrint(trait_names[trait_index]); + UnityPrint(UnityStrWas); +#ifdef UNITY_DOUBLE_VERBOSE + UnityPrintFloat(actual); +#else + if (should_be_trait) + UnityPrint(UnityStrNot); + UnityPrint(trait_names[trait_index]); +#endif + UnityAddMsgIfSpecified(msg); + UNITY_FAIL_AND_BAIL; + } +} + + +#endif // not UNITY_EXCLUDE_DOUBLE + +//----------------------------------------------- +void UnityAssertNumbersWithin( const _U_SINT delta, + const _U_SINT expected, + const _U_SINT actual, + const char* msg, + const UNITY_LINE_TYPE lineNumber, + const UNITY_DISPLAY_STYLE_T style) +{ + UNITY_SKIP_EXECUTION; + + if ((style & UNITY_DISPLAY_RANGE_INT) == UNITY_DISPLAY_RANGE_INT) + { + if (actual > expected) + Unity.CurrentTestFailed = ((actual - expected) > delta); + else + Unity.CurrentTestFailed = ((expected - actual) > delta); + } + else + { + if ((_U_UINT)actual > (_U_UINT)expected) + Unity.CurrentTestFailed = ((_U_UINT)(actual - expected) > (_U_UINT)delta); + else + Unity.CurrentTestFailed = ((_U_UINT)(expected - actual) > (_U_UINT)delta); + } + + if (Unity.CurrentTestFailed) + { + UnityTestResultsFailBegin(lineNumber); + UnityPrint(UnityStrDelta); + UnityPrintNumberByStyle(delta, style); + UnityPrint(UnityStrExpected); + UnityPrintNumberByStyle(expected, style); + UnityPrint(UnityStrWas); + UnityPrintNumberByStyle(actual, style); + UnityAddMsgIfSpecified(msg); + UNITY_FAIL_AND_BAIL; + } +} + +//----------------------------------------------- +void UnityAssertEqualString(const char* expected, + const char* actual, + const char* msg, + const UNITY_LINE_TYPE lineNumber) +{ + _UU32 i; + + UNITY_SKIP_EXECUTION; + + // if both pointers not null compare the strings + if (expected && actual) + { + for (i = 0; expected[i] || actual[i]; i++) + { + if (expected[i] != actual[i]) + { + Unity.CurrentTestFailed = 1; + break; + } + } + } + else + { + // handle case of one pointers being null (if both null, test should pass) + if (expected != actual) + { + Unity.CurrentTestFailed = 1; + } + } + + if (Unity.CurrentTestFailed) + { + UnityTestResultsFailBegin(lineNumber); + UnityPrintExpectedAndActualStrings(expected, actual); + UnityAddMsgIfSpecified(msg); + UNITY_FAIL_AND_BAIL; + } +} + +//----------------------------------------------- +void UnityAssertEqualStringArray( const char** expected, + const char** actual, + const _UU32 num_elements, + const char* msg, + const UNITY_LINE_TYPE lineNumber) +{ + _UU32 i, j = 0; + + UNITY_SKIP_EXECUTION; + + // if no elements, it's an error + if (num_elements == 0) + { + UnityTestResultsFailBegin(lineNumber); + UnityPrint(UnityStrPointless); + UnityAddMsgIfSpecified(msg); + UNITY_FAIL_AND_BAIL; + } + + if (UnityCheckArraysForNull((UNITY_PTR_ATTRIBUTE void*)expected, (UNITY_PTR_ATTRIBUTE void*)actual, lineNumber, msg) == 1) + return; + + do + { + // if both pointers not null compare the strings + if (expected[j] && actual[j]) + { + for (i = 0; expected[j][i] || actual[j][i]; i++) + { + if (expected[j][i] != actual[j][i]) + { + Unity.CurrentTestFailed = 1; + break; + } + } + } + else + { + // handle case of one pointers being null (if both null, test should pass) + if (expected[j] != actual[j]) + { + Unity.CurrentTestFailed = 1; + } + } + + if (Unity.CurrentTestFailed) + { + UnityTestResultsFailBegin(lineNumber); + if (num_elements > 1) + { + UnityPrint(UnityStrElement); + UnityPrintNumberByStyle((j), UNITY_DISPLAY_STYLE_UINT); + } + UnityPrintExpectedAndActualStrings((const char*)(expected[j]), (const char*)(actual[j])); + UnityAddMsgIfSpecified(msg); + UNITY_FAIL_AND_BAIL; + } + } + while (++j < num_elements); +} + +//----------------------------------------------- +void UnityAssertEqualMemory( UNITY_PTR_ATTRIBUTE const void* expected, + UNITY_PTR_ATTRIBUTE const void* actual, + const _UU32 length, + const _UU32 num_elements, + const char* msg, + const UNITY_LINE_TYPE lineNumber) +{ + UNITY_PTR_ATTRIBUTE const unsigned char* ptr_exp = (UNITY_PTR_ATTRIBUTE const unsigned char*)expected; + UNITY_PTR_ATTRIBUTE const unsigned char* ptr_act = (UNITY_PTR_ATTRIBUTE const unsigned char*)actual; + _UU32 elements = num_elements; + _UU32 bytes; + + UNITY_SKIP_EXECUTION; + + if ((elements == 0) || (length == 0)) + { + UnityTestResultsFailBegin(lineNumber); + UnityPrint(UnityStrPointless); + UnityAddMsgIfSpecified(msg); + UNITY_FAIL_AND_BAIL; + } + + if (UnityCheckArraysForNull((UNITY_PTR_ATTRIBUTE const void*)expected, (UNITY_PTR_ATTRIBUTE const void*)actual, lineNumber, msg) == 1) + return; + + while (elements--) + { + ///////////////////////////////////// + bytes = length; + while (bytes--) + { + if (*ptr_exp != *ptr_act) + { + UnityTestResultsFailBegin(lineNumber); + UnityPrint(UnityStrMemory); + if (num_elements > 1) + { + UnityPrint(UnityStrElement); + UnityPrintNumberByStyle((num_elements - elements - 1), UNITY_DISPLAY_STYLE_UINT); + } + UnityPrint(UnityStrByte); + UnityPrintNumberByStyle((length - bytes - 1), UNITY_DISPLAY_STYLE_UINT); + UnityPrint(UnityStrExpected); + UnityPrintNumberByStyle(*ptr_exp, UNITY_DISPLAY_STYLE_HEX8); + UnityPrint(UnityStrWas); + UnityPrintNumberByStyle(*ptr_act, UNITY_DISPLAY_STYLE_HEX8); + UnityAddMsgIfSpecified(msg); + UNITY_FAIL_AND_BAIL; + } + ptr_exp += 1; + ptr_act += 1; + } + ///////////////////////////////////// + + } +} + +//----------------------------------------------- +// Control Functions +//----------------------------------------------- + +void UnityFail(const char* msg, const UNITY_LINE_TYPE line) +{ + UNITY_SKIP_EXECUTION; + + UnityTestResultsBegin(Unity.TestFile, line); + UnityPrintFail(); + if (msg != NULL) + { + UNITY_OUTPUT_CHAR(':'); + if (msg[0] != ' ') + { + UNITY_OUTPUT_CHAR(' '); + } + UnityPrint(msg); + } + UNITY_FAIL_AND_BAIL; +} + +//----------------------------------------------- +void UnityIgnore(const char* msg, const UNITY_LINE_TYPE line) +{ + UNITY_SKIP_EXECUTION; + + UnityTestResultsBegin(Unity.TestFile, line); + UnityPrint(UnityStrIgnore); + if (msg != NULL) + { + UNITY_OUTPUT_CHAR(':'); + UNITY_OUTPUT_CHAR(' '); + UnityPrint(msg); + } + UNITY_IGNORE_AND_BAIL; +} + +//----------------------------------------------- +#if defined(UNITY_WEAK_ATTRIBUTE) + void setUp(void); + void tearDown(void); + UNITY_WEAK_ATTRIBUTE void setUp(void) { } + UNITY_WEAK_ATTRIBUTE void tearDown(void) { } +#elif defined(UNITY_WEAK_PRAGMA) +# pragma weak setUp + void setUp(void); +# pragma weak tearDown + void tearDown(void); +#else + void setUp(void); + void tearDown(void); +#endif +//----------------------------------------------- +void UnityDefaultTestRun(UnityTestFunction Func, const char* FuncName, const int FuncLineNum) +{ + Unity.CurrentTestName = FuncName; + Unity.CurrentTestLineNumber = (UNITY_LINE_TYPE)FuncLineNum; + Unity.NumberOfTests++; + if (TEST_PROTECTED(setUp) == 0) + { + TEST_PROTECTED(Func); + } + if (!(Unity.CurrentTestIgnored)) + { + TEST_PROTECTED(tearDown); + } + UnityConcludeTest(); +} + +//----------------------------------------------- +void UnityBegin(const char* filename) +{ + Unity.TestFile = filename; + Unity.CurrentTestName = NULL; + Unity.CurrentTestLineNumber = 0; + Unity.NumberOfTests = 0; + Unity.TestFailures = 0; + Unity.TestIgnores = 0; + Unity.CurrentTestFailed = 0; + Unity.CurrentTestIgnored = 0; + Unity.CurrentTestTimeout = 0; + + UNITY_OUTPUT_START(); +} + +//----------------------------------------------- +int UnityEnd(void) +{ + UNITY_PRINT_EOL; + UnityPrint(UnityStrBreaker); + UNITY_PRINT_EOL; + UnityPrintNumber((_U_SINT)(Unity.NumberOfTests)); + UnityPrint(UnityStrResultsTests); + UnityPrintNumber((_U_SINT)(Unity.TestFailures)); + UnityPrint(UnityStrResultsFailures); + UnityPrintNumber((_U_SINT)(Unity.TestIgnores)); + UnityPrint(UnityStrResultsIgnored); + UNITY_PRINT_EOL; + if (Unity.TestFailures == 0U) + { + UnityPrintOk(); + } + else + { + UnityPrintFail(); + } + UNITY_PRINT_EOL; + UNITY_OUTPUT_COMPLETE(); + return (int)(Unity.TestFailures); +} + +static void* UnityTimeoutThread(pthread_addr_t value) +{ + struct UnityTimeoutAction *timeout = (struct UnityTimeoutAction *)value; + + usleep(timeout->timeout_msec * UNITY_MSEC_IN_USEC); + + if (!timeout->cancel_protected) + return NULL; + + (void)pthread_kill(timeout->thread, SIG_UNITYSTOP); + Unity.CurrentTestTimeout = 1; + return NULL; +} + +static void* UnityProtectedThread(pthread_addr_t value) +{ + UnityTestFunction function = (UnityTestFunction)value; + function(); + return NULL; +} + +int UnityProtect(UnityTestFunction function, _U_UINT timeout_msec) +{ + struct UnityTimeoutAction action; + pthread_t thread, timeout_thread; + + if (timeout_msec < UNITY_MIN_TIMEOUT_MSEC) + timeout_msec = UNITY_MIN_TIMEOUT_MSEC; + + action.timeout_msec = timeout_msec; + action.cancel_protected = true; + + int result = pthread_create(&thread, NULL, UnityProtectedThread, (pthread_addr_t)function); + if (result == OK) + { + action.thread = thread; + result = pthread_create(&timeout_thread, NULL, UnityTimeoutThread, (pthread_addr_t)&action); + if (result == OK) + { + pthread_addr_t value; + result = pthread_join(thread, &value); + action.cancel_protected = false; + (void)pthread_kill(timeout_thread, SIG_UNITYSTOP); + (void)pthread_join(timeout_thread, &value); + if (result == 0) + { + result = Unity.CurrentTestFailed || Unity.CurrentTestTimeout ? 1 : 0; + } + } + } + return result; +} + +//----------------------------------------------- diff --git a/tests/testing/unity_fixture.c b/tests/testing/unity_fixture.c new file mode 100644 index 000000000..aedbe4e5e --- /dev/null +++ b/tests/testing/unity_fixture.c @@ -0,0 +1,466 @@ +//- Copyright (c) 2010 James Grenning and Contributed to Unity Project +/* ========================================== + Unity Project - A Test Framework for C + Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams + [Released under MIT License. Please refer to license.txt for details] +========================================== */ + +#include +#include +#include +#include +#include + +UNITY_FIXTURE_T UnityFixture; + +static char const* emptyList[] = {NULL}; + +int verbose = 0; + +void setUp(void); +void tearDown(void); +void setUp(void) { /*does nothing*/ } +void tearDown(void) { /*does nothing*/ } + +static void announceTestRun(unsigned int runNumber) +{ + UnityPrint("Unity test run "); + UnityPrintNumber(runNumber+1); + UnityPrint(" of "); + UnityPrintNumber(UnityFixture.RepeatCount); + UNITY_OUTPUT_CHAR('\n'); +} + +int UnityMain(int argc, const char* argv[], void (*runAllTests)(void)) +{ + int result = UnityGetCommandLineOptions(argc, argv); + unsigned int r; + if (result != 0) + return result; + + for (r = 0; r < UnityFixture.RepeatCount; r++) + { + UnityBegin(argv[0]); + announceTestRun(r); + runAllTests(); + UNITY_OUTPUT_CHAR('\n'); + UnityEnd(); + } + + return UnityFailureCount(); +} + +static int selected(const char * filter, const char * name) +{ + if (filter == 0) + return 1; + return strstr(name, filter) ? 1 : 0; +} + +static int testSelected(const char* test) +{ + return selected(UnityFixture.NameFilter, test); +} + +static int groupSelected(const char* group) +{ + return selected(UnityFixture.GroupFilter, group); +} + +static int plainSelected(const char* group, const char* test) +{ + if (UnityFixture.PlainListOfTests[0] == NULL) + { + return 1; + } + else + { + const char** plain = UnityFixture.PlainListOfTests; + while (plain[0] != NULL) + { + const char* selector = plain[0]; + int groupLen = strlen(group); + int testLen = strlen(test); + if (groupLen + testLen + 1 == strlen(selector) && + selector[groupLen] == '/' && + strstr(selector, group) == selector && + strstr(selector + groupLen + 1, test) == selector + groupLen + 1) + { + return 1; + } + plain++; + } + return 0; + } +} + +static void runTestCase(void) +{ + +} + +void UnityTestRunner(unityfunction* setup, _U_UINT setupTimeoutMsec, + unityfunction* testBody, _U_UINT bodyTimeoutMsec, + unityfunction* teardown, _U_UINT teardownTimeoutMsec, + const char * printableName, + const char * group, + const char * name, + const char * file, int line) +{ + if (testSelected(name) && groupSelected(group) && plainSelected(group, name)) + { + Unity.CurrentTestFailed = 0; + Unity.TestFile = file; + Unity.CurrentTestName = printableName; + Unity.CurrentTestLineNumber = line; + if (UnityFixture.ListOnly) + { + UnityPrint(group); + UNITY_OUTPUT_CHAR('/'); + UnityPrint(name); + UNITY_OUTPUT_CHAR('\n'); + Unity.NumberOfTests++; + } + else + { + if (!UnityFixture.Verbose) + UNITY_OUTPUT_CHAR('.'); + else + { + UnityPrint(printableName); + UNITY_OUTPUT_CHAR(' '); + } + + Unity.NumberOfTests++; + UnityMalloc_StartTest(); + UnityPointer_Init(); + + runTestCase(); + if (TEST_PROTECTED_WITH_TIMEOUT(setup, setupTimeoutMsec) == 0) + { + TEST_PROTECTED_WITH_TIMEOUT(testBody, bodyTimeoutMsec); + } + TEST_PROTECTED_WITH_TIMEOUT(teardown, teardownTimeoutMsec); + + UnityPointer_UndoAllSets(); + if (!Unity.CurrentTestFailed && !Unity.CurrentTestTimeout) + TEST_PROTECTED(UnityMalloc_EndTest); + + if (Unity.CurrentTestFailed && UnityFixture.Verbose) + { + UNITY_OUTPUT_CHAR('\n'); + } + } + UnityConcludeFixtureTest(); + } +} + +void UnityIgnoreTest(const char * printableName) +{ + Unity.NumberOfTests++; + Unity.CurrentTestIgnored = 1; + if (!UnityFixture.Verbose) + UNITY_OUTPUT_CHAR('!'); + else + UnityPrint(printableName); + UnityConcludeFixtureTest(); +} + + +//------------------------------------------------- +//Malloc and free stuff +// +#define MALLOC_DONT_FAIL -1 +static int malloc_count; +static int malloc_fail_countdown = MALLOC_DONT_FAIL; + +void UnityMalloc_StartTest(void) +{ + malloc_count = 0; + malloc_fail_countdown = MALLOC_DONT_FAIL; +} + +void UnityMalloc_EndTest(void) +{ + malloc_fail_countdown = MALLOC_DONT_FAIL; + if (malloc_count != 0) + { + TEST_FAIL_MESSAGE("This test leaks!"); + } +} + +void UnityMalloc_MakeMallocFailAfterCount(int countdown) +{ + malloc_fail_countdown = countdown; +} + +#ifdef malloc +#undef malloc +#endif + +#ifdef free +#undef free +#endif + +#ifdef calloc +#undef calloc +#endif + +#ifdef realloc +#undef realloc +#endif + +#include +#include + +typedef struct GuardBytes +{ + size_t size; + char guard[sizeof(size_t)]; +} Guard; + + +static const char * end = "END"; + +void * unity_malloc(size_t size) +{ + char* mem; + Guard* guard; + + if (malloc_fail_countdown != MALLOC_DONT_FAIL) + { + if (malloc_fail_countdown == 0) + return 0; + malloc_fail_countdown--; + } + + malloc_count++; + + guard = (Guard*)malloc(size + sizeof(Guard) + 4); + guard->size = size; + mem = (char*)&(guard[1]); + memcpy(&mem[size], end, strlen(end) + 1); + + return (void*)mem; +} + +static int isOverrun(void * mem) +{ + Guard* guard = (Guard*)mem; + char* memAsChar = (char*)mem; + guard--; + + return strcmp(&memAsChar[guard->size], end) != 0; +} + +static void release_memory(void * mem) +{ + Guard* guard = (Guard*)mem; + guard--; + + malloc_count--; + free(guard); +} + +void unity_free(void * mem) +{ + if (!mem) + { + /* Freeing NULL should be always OK */ + return; + } + int overrun = isOverrun(mem);//strcmp(&memAsChar[guard->size], end) != 0; + release_memory(mem); + if (overrun) + { + TEST_FAIL_MESSAGE("Buffer overrun detected during free()"); + } +} + +void* unity_calloc(size_t num, size_t size) +{ + void* mem = unity_malloc(num * size); + memset(mem, 0, num*size); + return mem; +} + +void* unity_realloc(void * oldMem, size_t size) +{ + Guard* guard = (Guard*)oldMem; +// char* memAsChar = (char*)oldMem; + void* newMem; + + if (oldMem == 0) + return unity_malloc(size); + + guard--; + if (isOverrun(oldMem)) + { + release_memory(oldMem); + TEST_FAIL_MESSAGE("Buffer overrun detected during realloc()"); + return 0; /* Above will not abort the test, if the execution is skipped */ + } + + if (size == 0) + { + release_memory(oldMem); + return 0; + } + + if (guard->size >= size) + return oldMem; + + newMem = unity_malloc(size); + memcpy(newMem, oldMem, guard->size); + unity_free(oldMem); + return newMem; +} + + +//-------------------------------------------------------- +//Automatic pointer restoration functions +typedef struct _PointerPair +{ + struct _PointerPair * next; + void ** pointer; + void * old_value; +} PointerPair; + +enum {MAX_POINTERS=50}; +static PointerPair pointer_store[MAX_POINTERS]; +static int pointer_index = 0; + +void UnityPointer_Init(void) +{ + pointer_index = 0; +} + +void UnityPointer_Set(void ** pointer, void * newValue) +{ + if (pointer_index >= MAX_POINTERS) + TEST_FAIL_MESSAGE("Too many pointers set"); + + pointer_store[pointer_index].pointer = pointer; + pointer_store[pointer_index].old_value = *pointer; + *pointer = newValue; + pointer_index++; +} + +void UnityPointer_UndoAllSets(void) +{ + while (pointer_index > 0) + { + pointer_index--; + *(pointer_store[pointer_index].pointer) = + pointer_store[pointer_index].old_value; + + } +} + +int UnityFailureCount(void) +{ + return Unity.TestFailures; +} + +int UnityGetCommandLineOptions(int argc, const char* argv[]) +{ + int i; + UnityFixture.Verbose = 0; + UnityFixture.ListOnly = 0; + UnityFixture.GroupFilter = 0; + UnityFixture.NameFilter = 0; + UnityFixture.RepeatCount = 1; + UnityFixture.PlainListOfTests = emptyList; + + if (argc == 1) + return 0; + + for (i = 1; i < argc; ) + { + if (strcmp(argv[i], "-l") == 0) + { + UnityFixture.ListOnly = 1; + i++; + } + else if (strcmp(argv[i], "-v") == 0) + { + UnityFixture.Verbose = 1; + i++; + } + else if (strcmp(argv[i], "-g") == 0) + { + i++; + if (i >= argc) + return 1; + UnityFixture.GroupFilter = argv[i]; + i++; + } + else if (strcmp(argv[i], "-n") == 0) + { + i++; + if (i >= argc) + return 1; + UnityFixture.NameFilter = argv[i]; + i++; + } + else if (strcmp(argv[i], "-r") == 0) + { + UnityFixture.RepeatCount = 2; + i++; + if (i < argc) + { + if (*(argv[i]) >= '0' && *(argv[i]) <= '9') + { + UnityFixture.RepeatCount = atoi(argv[i]); + i++; + } + } + } + else if (strcmp(argv[i], "--") == 0) + { + UnityFixture.PlainListOfTests = argv + i + 1; + break; + } + else { + // ignore unknown parameter + i++; + } + } + return 0; +} + +void UnityConcludeFixtureTest(void) +{ + if (Unity.CurrentTestIgnored) + { + if (UnityFixture.Verbose) + { + UNITY_OUTPUT_CHAR('\n'); + } + Unity.TestIgnores++; + } + else if (Unity.CurrentTestTimeout) + { + if (UnityFixture.Verbose) + { + UnityPrint(" TIMEOUT"); + UNITY_OUTPUT_CHAR('\n'); + } + Unity.TestFailures++; + } + else if (!Unity.CurrentTestFailed) + { + if (UnityFixture.Verbose) + { + UnityPrint(" PASS"); + UNITY_OUTPUT_CHAR('\n'); + } + } + else if (Unity.CurrentTestFailed) + { + Unity.TestFailures++; + } + + Unity.CurrentTestFailed = 0; + Unity.CurrentTestIgnored = 0; +} diff --git a/tests/tools/auto/colour_prompt.rb b/tests/tools/auto/colour_prompt.rb new file mode 100644 index 000000000..8adab6e61 --- /dev/null +++ b/tests/tools/auto/colour_prompt.rb @@ -0,0 +1,115 @@ +# ========================================== +# Unity Project - A Test Framework for C +# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams +# [Released under MIT License. Please refer to license.txt for details] +# ========================================== + +if RUBY_PLATFORM =~/(win|w)32$/ + begin + require 'Win32API' + rescue LoadError + puts "ERROR! \"Win32API\" library not found" + puts "\"Win32API\" is required for colour on a windows machine" + puts " try => \"gem install Win32API\" on the command line" + puts + end + # puts + # puts 'Windows Environment Detected...' + # puts 'Win32API Library Found.' + # puts +end + +class ColourCommandLine + def initialize + if RUBY_PLATFORM =~/(win|w)32$/ + get_std_handle = Win32API.new("kernel32", "GetStdHandle", ['L'], 'L') + @set_console_txt_attrb = + Win32API.new("kernel32","SetConsoleTextAttribute",['L','N'], 'I') + @hout = get_std_handle.call(-11) + end + end + + def change_to(new_colour) + if RUBY_PLATFORM =~/(win|w)32$/ + @set_console_txt_attrb.call(@hout,self.win32_colour(new_colour)) + else + "\033[30;#{posix_colour(new_colour)};22m" + end + end + + def win32_colour(colour) + case colour + when :black then 0 + when :dark_blue then 1 + when :dark_green then 2 + when :dark_cyan then 3 + when :dark_red then 4 + when :dark_purple then 5 + when :dark_yellow, :narrative then 6 + when :default_white, :default, :dark_white then 7 + when :silver then 8 + when :blue then 9 + when :green, :success then 10 + when :cyan, :output then 11 + when :red, :failure then 12 + when :purple then 13 + when :yellow then 14 + when :white then 15 + else + 0 + end + end + + def posix_colour(colour) + # ANSI Escape Codes - Foreground colors + # | Code | Color | + # | 39 | Default foreground color | + # | 30 | Black | + # | 31 | Red | + # | 32 | Green | + # | 33 | Yellow | + # | 34 | Blue | + # | 35 | Magenta | + # | 36 | Cyan | + # | 37 | Light gray | + # | 90 | Dark gray | + # | 91 | Light red | + # | 92 | Light green | + # | 93 | Light yellow | + # | 94 | Light blue | + # | 95 | Light magenta | + # | 96 | Light cyan | + # | 97 | White | + + case colour + when :black then 30 + when :red, :failure then 31 + when :green, :success then 32 + when :yellow then 33 + when :blue, :narrative then 34 + when :purple, :magenta then 35 + when :cyan, :output then 36 + when :white, :default_white then 37 + when :default then 39 + else + 39 + end + end + + def out_c(mode, colour, str) + case RUBY_PLATFORM + when /(win|w)32$/ + change_to(colour) + $stdout.puts str if mode == :puts + $stdout.print str if mode == :print + change_to(:default_white) + else + $stdout.puts("#{change_to(colour)}#{str}\033[0m") if mode == :puts + $stdout.print("#{change_to(colour)}#{str}\033[0m") if mode == :print + end + end +end # ColourCommandLine + +def colour_puts(role,str) ColourCommandLine.new.out_c(:puts, role, str) end +def colour_print(role,str) ColourCommandLine.new.out_c(:print, role, str) end + diff --git a/tests/tools/auto/colour_reporter.rb b/tests/tools/auto/colour_reporter.rb new file mode 100644 index 000000000..89e79519c --- /dev/null +++ b/tests/tools/auto/colour_reporter.rb @@ -0,0 +1,39 @@ +# ========================================== +# Unity Project - A Test Framework for C +# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams +# [Released under MIT License. Please refer to license.txt for details] +# ========================================== + +require "#{File.expand_path(File.dirname(__FILE__))}/colour_prompt" + +$colour_output = true + +def report(message) + if not $colour_output + $stdout.puts(message) + else + message = message.join('\n') if (message.class == Array) + message.each_line do |line| + line.chomp! + colour = case(line) + when /(?:total\s+)?tests:?\s+(\d+)\s+(?:total\s+)?failures:?\s+\d+\s+Ignored:?/i + ($1.to_i == 0) ? :green : :red + when /PASS/ + :green + when /^OK$/ + :green + when /(?:FAIL|ERROR)/ + :red + when /IGNORE/ + :yellow + when /^(?:Creating|Compiling|Linking)/ + :white + else + :silver + end + colour_puts(colour, line) + end + end + $stdout.flush + $stderr.flush +end \ No newline at end of file diff --git a/tests/tools/auto/generate_config.yml b/tests/tools/auto/generate_config.yml new file mode 100644 index 000000000..ce66cead5 --- /dev/null +++ b/tests/tools/auto/generate_config.yml @@ -0,0 +1,36 @@ +#this is a sample configuration file for generate_module +#you would use it by calling generate_module with the -ygenerate_config.yml option +#files like this are useful for customizing generate_module to your environment +:generate_module: + :defaults: + #these defaults are used in place of any missing options at the command line + :path_src: ../src/ + :path_inc: ../src/ + :path_tst: ../test/ + :update_svn: true + :includes: + #use [] for no additional includes, otherwise list the includes on separate lines + :src: + - Defs.h + - Board.h + :inc: [] + :tst: + - Defs.h + - Board.h + - Exception.h + :boilerplates: + #these are inserted at the top of generated files. + #just comment out or remove if not desired. + #use %1$s where you would like the file name to appear (path/extension not included) + :src: | + //------------------------------------------- + // %1$s.c + //------------------------------------------- + :inc: | + //------------------------------------------- + // %1$s.h + //------------------------------------------- + :tst: | + //------------------------------------------- + // Test%1$s.c : Units tests for %1$s.c + //------------------------------------------- diff --git a/tests/tools/auto/generate_module.rb b/tests/tools/auto/generate_module.rb new file mode 100644 index 000000000..4a020ebbf --- /dev/null +++ b/tests/tools/auto/generate_module.rb @@ -0,0 +1,202 @@ +# ========================================== +# Unity Project - A Test Framework for C +# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams +# [Released under MIT License. Please refer to license.txt for details] +# ========================================== + +# This script creates all the files with start code necessary for a new module. +# A simple module only requires a source file, header file, and test file. +# Triad modules require a source, header, and test file for each triad type (like model, conductor, and hardware). + +require 'rubygems' +require 'fileutils' + +HERE = File.expand_path(File.dirname(__FILE__)) + '/' + +#help text when requested +HELP_TEXT = [ "\nGENERATE MODULE\n-------- ------", + "\nUsage: ruby generate_module [options] module_name", + " -i\"include\" sets the path to output headers to 'include' (DEFAULT ../src)", + " -s\"../src\" sets the path to output source to '../src' (DEFAULT ../src)", + " -t\"C:/test\" sets the path to output source to 'C:/test' (DEFAULT ../test)", + " -p\"MCH\" sets the output pattern to MCH.", + " dh - driver hardware.", + " dih - driver interrupt hardware.", + " mch - model conductor hardware.", + " mvp - model view presenter.", + " src - just a single source module. (DEFAULT)", + " -d destroy module instead of creating it.", + " -u update subversion too (requires subversion command line)", + " -y\"my.yml\" selects a different yaml config file for module generation", + "" ].join("\n") + +#Built in patterns +PATTERNS = { 'src' => {'' => { :inc => [] } }, + 'dh' => {'Driver' => { :inc => ['%1$sHardware.h'] }, + 'Hardware' => { :inc => [] } + }, + 'dih' => {'Driver' => { :inc => ['%1$sHardware.h', '%1$sInterrupt.h'] }, + 'Interrupt'=> { :inc => ['%1$sHardware.h'] }, + 'Hardware' => { :inc => [] } + }, + 'mch' => {'Model' => { :inc => [] }, + 'Conductor'=> { :inc => ['%1$sModel.h', '%1$sHardware.h'] }, + 'Hardware' => { :inc => [] } + }, + 'mvp' => {'Model' => { :inc => [] }, + 'Presenter'=> { :inc => ['%1$sModel.h', '%1$sView.h'] }, + 'View' => { :inc => [] } + } + } + +#TEMPLATE_TST +TEMPLATE_TST = %q[#include "unity.h" +%2$s#include "%1$s.h" + +void setUp(void) +{ +} + +void tearDown(void) +{ +} + +void test_%1$s_NeedToImplement(void) +{ + TEST_IGNORE(); +} +] + +#TEMPLATE_SRC +TEMPLATE_SRC = %q[%2$s#include "%1$s.h" +] + +#TEMPLATE_INC +TEMPLATE_INC = %q[#ifndef _%3$s_H +#define _%3$s_H%2$s + +#endif // _%3$s_H +] + +# Parse the command line parameters. +ARGV.each do |arg| + case(arg) + when /^-d/ then @destroy = true + when /^-u/ then @update_svn = true + when /^-p(\w+)/ then @pattern = $1 + when /^-s(.+)/ then @path_src = $1 + when /^-i(.+)/ then @path_inc = $1 + when /^-t(.+)/ then @path_tst = $1 + when /^-y(.+)/ then @yaml_config = $1 + when /^(\w+)/ + raise "ERROR: You can't have more than one Module name specified!" unless @module_name.nil? + @module_name = arg + when /^-(h|-help)/ + puts HELP_TEXT + exit + else + raise "ERROR: Unknown option specified '#{arg}'" + end +end +raise "ERROR: You must have a Module name specified! (use option -h for help)" if @module_name.nil? + +#load yaml file if one was requested +if @yaml_config + require 'yaml' + cfg = YAML.load_file(HERE + @yaml_config)[:generate_module] + @path_src = cfg[:defaults][:path_src] if @path_src.nil? + @path_inc = cfg[:defaults][:path_inc] if @path_inc.nil? + @path_tst = cfg[:defaults][:path_tst] if @path_tst.nil? + @update_svn = cfg[:defaults][:update_svn] if @update_svn.nil? + @extra_inc = cfg[:includes] + @boilerplates = cfg[:boilerplates] +else + @boilerplates = {} +end + +# Create default file paths if none were provided +@path_src = HERE + "../src/" if @path_src.nil? +@path_inc = @path_src if @path_inc.nil? +@path_tst = HERE + "../test/" if @path_tst.nil? +@path_src += '/' unless (@path_src[-1] == 47) +@path_inc += '/' unless (@path_inc[-1] == 47) +@path_tst += '/' unless (@path_tst[-1] == 47) +@pattern = 'src' if @pattern.nil? +@includes = { :src => [], :inc => [], :tst => [] } +@includes.merge!(@extra_inc) unless @extra_inc.nil? + +#create triad definition +TRIAD = [ { :ext => '.c', :path => @path_src, :template => TEMPLATE_SRC, :inc => :src, :boilerplate => @boilerplates[:src] }, + { :ext => '.h', :path => @path_inc, :template => TEMPLATE_INC, :inc => :inc, :boilerplate => @boilerplates[:inc] }, + { :ext => '.c', :path => @path_tst+'Test', :template => TEMPLATE_TST, :inc => :tst, :boilerplate => @boilerplates[:tst] }, + ] + +#prepare the pattern for use +@patterns = PATTERNS[@pattern.downcase] +raise "ERROR: The design pattern specified isn't one that I recognize!" if @patterns.nil? + +# Assemble the path/names of the files we need to work with. +files = [] +TRIAD.each do |triad| + @patterns.each_pair do |pattern_file, pattern_traits| + files << { + :path => "#{triad[:path]}#{@module_name}#{pattern_file}#{triad[:ext]}", + :name => "#{@module_name}#{pattern_file}", + :template => triad[:template], + :boilerplate => triad[:boilerplate], + :includes => case(triad[:inc]) + when :src then @includes[:src] | pattern_traits[:inc].map{|f| f % [@module_name]} + when :inc then @includes[:inc] + when :tst then @includes[:tst] | pattern_traits[:inc].map{|f| "Mock#{f}"% [@module_name]} + end + } + end +end + +# destroy files if that was what was requested +if @destroy + files.each do |filespec| + file = filespec[:path] + if File.exist?(file) + if @update_svn + `svn delete \"#{file}\" --force` + puts "File #{file} deleted and removed from source control" + else + FileUtils.remove(file) + puts "File #{file} deleted" + end + else + puts "File #{file} does not exist so cannot be removed." + end + end + puts "Destroy Complete" + exit +end + +#Abort if any module already exists +files.each do |file| + raise "ERROR: File #{file[:name]} already exists. Exiting." if File.exist?(file[:path]) +end + +# Create Source Modules +files.each_with_index do |file, i| + File.open(file[:path], 'w') do |f| + f.write(file[:boilerplate] % [file[:name]]) unless file[:boilerplate].nil? + f.write(file[:template] % [ file[:name], + file[:includes].map{|f| "#include \"#{f}\"\n"}.join, + file[:name].upcase ] + ) + end + if (@update_svn) + `svn add \"#{file[:path]}\"` + if $?.exitstatus == 0 + puts "File #{file[:path]} created and added to source control" + else + puts "File #{file[:path]} created but FAILED adding to source control!" + end + else + puts "File #{file[:path]} created" + end +end + +puts 'Generate Complete' diff --git a/tests/tools/auto/generate_test_runner.rb b/tests/tools/auto/generate_test_runner.rb new file mode 100644 index 000000000..85e4e91db --- /dev/null +++ b/tests/tools/auto/generate_test_runner.rb @@ -0,0 +1,349 @@ +# ========================================== +# Unity Project - A Test Framework for C +# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams +# [Released under MIT License. Please refer to license.txt for details] +# ========================================== + +$QUICK_RUBY_VERSION = RUBY_VERSION.split('.').inject(0){|vv,v| vv * 100 + v.to_i } +File.expand_path(File.join(File.dirname(__FILE__),'colour_prompt')) + +class UnityTestRunnerGenerator + + def initialize(options = nil) + @options = UnityTestRunnerGenerator.default_options + case(options) + when NilClass then @options + when String then @options.merge!(UnityTestRunnerGenerator.grab_config(options)) + when Hash then @options.merge!(options) + else raise "If you specify arguments, it should be a filename or a hash of options" + end + require "#{File.expand_path(File.dirname(__FILE__))}/type_sanitizer" + end + + def self.default_options + { + :includes => [], + :plugins => [], + :framework => :unity, + :test_prefix => "test|spec|should", + :setup_name => "setUp", + :teardown_name => "tearDown", + } + end + + def self.grab_config(config_file) + options = self.default_options + unless (config_file.nil? or config_file.empty?) + require 'yaml' + yaml_guts = YAML.load_file(config_file) + options.merge!(yaml_guts[:unity] || yaml_guts[:cmock]) + raise "No :unity or :cmock section found in #{config_file}" unless options + end + return(options) + end + + def run(input_file, output_file, options=nil) + tests = [] + testfile_includes = [] + used_mocks = [] + + @options.merge!(options) unless options.nil? + module_name = File.basename(input_file) + + #pull required data from source file + source = File.read(input_file) + source = source.force_encoding("ISO-8859-1").encode("utf-8", :replace => nil) if ($QUICK_RUBY_VERSION > 10900) + tests = find_tests(source) + headers = find_includes(source) + testfile_includes = headers[:local] + headers[:system] + used_mocks = find_mocks(testfile_includes) + + #build runner file + generate(input_file, output_file, tests, used_mocks, testfile_includes) + + #determine which files were used to return them + all_files_used = [input_file, output_file] + all_files_used += testfile_includes.map {|filename| filename + '.c'} unless testfile_includes.empty? + all_files_used += @options[:includes] unless @options[:includes].empty? + return all_files_used.uniq + end + + def generate(input_file, output_file, tests, used_mocks, testfile_includes) + File.open(output_file, 'w') do |output| + create_header(output, used_mocks, testfile_includes) + create_externs(output, tests, used_mocks) + create_mock_management(output, used_mocks) + create_suite_setup_and_teardown(output) + create_reset(output, used_mocks) + create_main(output, input_file, tests, used_mocks) + end + end + + def find_tests(source) + tests_raw = [] + tests_args = [] + tests_and_line_numbers = [] + + source_scrubbed = source.gsub(/\/\/.*$/, '') # remove line comments + source_scrubbed = source_scrubbed.gsub(/\/\*.*?\*\//m, '') # remove block comments + lines = source_scrubbed.split(/(^\s*\#.*$) # Treat preprocessor directives as a logical line + | (;|\{|\}) /x) # Match ;, {, and } as end of lines + + lines.each_with_index do |line, index| + #find tests + if line =~ /^((?:\s*TEST_CASE\s*\(.*?\)\s*)*)\s*void\s+((?:#{@options[:test_prefix]}).*)\s*\(\s*(.*)\s*\)/ + arguments = $1 + name = $2 + call = $3 + args = nil + if (@options[:use_param_tests] and !arguments.empty?) + args = [] + arguments.scan(/\s*TEST_CASE\s*\((.*)\)\s*$/) {|a| args << a[0]} + end + tests_and_line_numbers << { :test => name, :args => args, :call => call, :line_number => 0 } + tests_args = [] + end + end + + #determine line numbers and create tests to run + source_lines = source.split("\n") + source_index = 0; + tests_and_line_numbers.size.times do |i| + source_lines[source_index..-1].each_with_index do |line, index| + if (line =~ /#{tests_and_line_numbers[i][:test]}/) + source_index += index + tests_and_line_numbers[i][:line_number] = source_index + 1 + break + end + end + end + + return tests_and_line_numbers + end + + def find_includes(source) + + #remove comments (block and line, in three steps to ensure correct precedence) + source.gsub!(/\/\/(?:.+\/\*|\*(?:$|[^\/])).*$/, '') # remove line comments that comment out the start of blocks + source.gsub!(/\/\*.*?\*\//m, '') # remove block comments + source.gsub!(/\/\/.*$/, '') # remove line comments (all that remain) + + #parse out includes + includes = { + local: source.scan(/^\s*#include\s+\"\s*(.+)\.[hH]\s*\"/).flatten, + system: source.scan(/^\s*#include\s+<\s*(.+)\s*>/).flatten.map { |inc| "<#{inc}>" } + } + return includes + end + + def find_mocks(includes) + mock_headers = [] + includes.each do |include_file| + mock_headers << File.basename(include_file) if (include_file =~ /^mock/i) + end + return mock_headers + end + + def create_header(output, mocks, testfile_includes=[]) + output.puts('/* AUTOGENERATED FILE. DO NOT EDIT. */') + create_runtest(output, mocks) + output.puts("\n//=======Automagically Detected Files To Include=====") + output.puts("#include \"#{@options[:framework].to_s}.h\"") + output.puts('#include "cmock.h"') unless (mocks.empty?) + @options[:includes].flatten.uniq.compact.each do |inc| + output.puts("#include #{inc.include?('<') ? inc : "\"#{inc.gsub('.h','')}.h\""}") + end + output.puts('#include ') + output.puts('#include ') + output.puts('#include "CException.h"') if @options[:plugins].include?(:cexception) + testfile_includes.delete_if{|inc| inc =~ /(unity|cmock)/} + testrunner_includes = testfile_includes - mocks + testrunner_includes.each do |inc| + output.puts("#include #{inc.include?('<') ? inc : "\"#{inc.gsub('.h','')}.h\""}") + end + mocks.each do |mock| + output.puts("#include \"#{mock.gsub('.h','')}.h\"") + end + if @options[:enforce_strict_ordering] + output.puts('') + output.puts('int GlobalExpectCount;') + output.puts('int GlobalVerifyOrder;') + output.puts('char* GlobalOrderError;') + end + end + + def create_externs(output, tests, mocks) + output.puts("\n//=======External Functions This Runner Calls=====") + output.puts("extern void #{@options[:setup_name]}(void);") + output.puts("extern void #{@options[:teardown_name]}(void);") + tests.each do |test| + output.puts("extern void #{test[:test]}(#{test[:call] || 'void'});") + end + output.puts('') + end + + def create_mock_management(output, mocks) + unless (mocks.empty?) + output.puts("\n//=======Mock Management=====") + output.puts("static void CMock_Init(void)") + output.puts("{") + if @options[:enforce_strict_ordering] + output.puts(" GlobalExpectCount = 0;") + output.puts(" GlobalVerifyOrder = 0;") + output.puts(" GlobalOrderError = NULL;") + end + mocks.each do |mock| + mock_clean = TypeSanitizer.sanitize_c_identifier(mock) + output.puts(" #{mock_clean}_Init();") + end + output.puts("}\n") + + output.puts("static void CMock_Verify(void)") + output.puts("{") + mocks.each do |mock| + mock_clean = TypeSanitizer.sanitize_c_identifier(mock) + output.puts(" #{mock_clean}_Verify();") + end + output.puts("}\n") + + output.puts("static void CMock_Destroy(void)") + output.puts("{") + mocks.each do |mock| + mock_clean = TypeSanitizer.sanitize_c_identifier(mock) + output.puts(" #{mock_clean}_Destroy();") + end + output.puts("}\n") + end + end + + def create_suite_setup_and_teardown(output) + unless (@options[:suite_setup].nil?) + output.puts("\n//=======Suite Setup=====") + output.puts("static int suite_setup(void)") + output.puts("{") + output.puts(@options[:suite_setup]) + output.puts("}") + end + unless (@options[:suite_teardown].nil?) + output.puts("\n//=======Suite Teardown=====") + output.puts("static int suite_teardown(int num_failures)") + output.puts("{") + output.puts(@options[:suite_teardown]) + output.puts("}") + end + end + + def create_runtest(output, used_mocks) + cexception = @options[:plugins].include? :cexception + va_args1 = @options[:use_param_tests] ? ', ...' : '' + va_args2 = @options[:use_param_tests] ? '__VA_ARGS__' : '' + output.puts("\n//=======Test Runner Used To Run Each Test Below=====") + output.puts("#define RUN_TEST_NO_ARGS") if @options[:use_param_tests] + output.puts("#define RUN_TEST(TestFunc, TestLineNum#{va_args1}) \\") + output.puts("{ \\") + output.puts(" Unity.CurrentTestName = #TestFunc#{va_args2.empty? ? '' : " \"(\" ##{va_args2} \")\""}; \\") + output.puts(" Unity.CurrentTestLineNumber = TestLineNum; \\") + output.puts(" Unity.NumberOfTests++; \\") + output.puts(" CMock_Init(); \\") unless (used_mocks.empty?) + output.puts(" if (TEST_PROTECT()) \\") + output.puts(" { \\") + output.puts(" CEXCEPTION_T e; \\") if cexception + output.puts(" Try { \\") if cexception + output.puts(" #{@options[:setup_name]}(); \\") + output.puts(" TestFunc(#{va_args2}); \\") + output.puts(" } Catch(e) { TEST_ASSERT_EQUAL_HEX32_MESSAGE(CEXCEPTION_NONE, e, \"Unhandled Exception!\"); } \\") if cexception + output.puts(" } \\") + output.puts(" if (TEST_PROTECT() && !TEST_IS_IGNORED) \\") + output.puts(" { \\") + output.puts(" #{@options[:teardown_name]}(); \\") + output.puts(" CMock_Verify(); \\") unless (used_mocks.empty?) + output.puts(" } \\") + output.puts(" CMock_Destroy(); \\") unless (used_mocks.empty?) + output.puts(" UnityConcludeTest(); \\") + output.puts("}\n") + end + + def create_reset(output, used_mocks) + output.puts("\n//=======Test Reset Option=====") + output.puts("void resetTest(void);") + output.puts("void resetTest(void)") + output.puts("{") + output.puts(" CMock_Verify();") unless (used_mocks.empty?) + output.puts(" CMock_Destroy();") unless (used_mocks.empty?) + output.puts(" #{@options[:teardown_name]}();") + output.puts(" CMock_Init();") unless (used_mocks.empty?) + output.puts(" #{@options[:setup_name]}();") + output.puts("}") + end + + def create_main(output, filename, tests, used_mocks) + output.puts("\n\n//=======MAIN=====") + output.puts("int main(void)") + output.puts("{") + output.puts(" suite_setup();") unless @options[:suite_setup].nil? + output.puts(" UnityBegin(\"#{filename}\");") + if (@options[:use_param_tests]) + tests.each do |test| + if ((test[:args].nil?) or (test[:args].empty?)) + output.puts(" RUN_TEST(#{test[:test]}, #{test[:line_number]}, RUN_TEST_NO_ARGS);") + else + test[:args].each {|args| output.puts(" RUN_TEST(#{test[:test]}, #{test[:line_number]}, #{args});")} + end + end + else + tests.each { |test| output.puts(" RUN_TEST(#{test[:test]}, #{test[:line_number]});") } + end + output.puts() + output.puts(" CMock_Guts_MemFreeFinal();") unless used_mocks.empty? + output.puts(" return #{@options[:suite_teardown].nil? ? "" : "suite_teardown"}(UnityEnd());") + output.puts("}") + end +end + + +if ($0 == __FILE__) + options = { :includes => [] } + yaml_file = nil + + #parse out all the options first (these will all be removed as we go) + ARGV.reject! do |arg| + case(arg) + when '-cexception' + options[:plugins] = [:cexception]; true + when /\.*\.ya?ml/ + options = UnityTestRunnerGenerator.grab_config(arg); true + when /\.*\.h/ + options[:includes] << arg; true + when /--(\w+)=\"?(.*)\"?/ + options[$1.to_sym] = $2; true + else false + end + end + + #make sure there is at least one parameter left (the input file) + if !ARGV[0] + puts ["\nusage: ruby #{__FILE__} (files) (options) input_test_file (output)", + "\n input_test_file - this is the C file you want to create a runner for", + " output - this is the name of the runner file to generate", + " defaults to (input_test_file)_Runner", + " files:", + " *.yml / *.yaml - loads configuration from here in :unity or :cmock", + " *.h - header files are added as #includes in runner", + " options:", + " -cexception - include cexception support", + " --setup_name=\"\" - redefine setUp func name to something else", + " --teardown_name=\"\" - redefine tearDown func name to something else", + " --test_prefix=\"\" - redefine test prefix from default test|spec|should", + " --suite_setup=\"\" - code to execute for setup of entire suite", + " --suite_teardown=\"\" - code to execute for teardown of entire suite", + " --use_param_tests=1 - enable parameterized tests (disabled by default)", + ].join("\n") + exit 1 + end + + #create the default test runner name if not specified + ARGV[1] = ARGV[0].gsub(".c","_Runner.c") if (!ARGV[1]) + + + UnityTestRunnerGenerator.new(options).run(ARGV[0], ARGV[1]) +end diff --git a/tests/tools/auto/parseOutput.rb b/tests/tools/auto/parseOutput.rb new file mode 100644 index 000000000..5165c7f0b --- /dev/null +++ b/tests/tools/auto/parseOutput.rb @@ -0,0 +1,189 @@ +#============================================================ +# Author: John Theofanopoulos +# A simple parser. Takes the output files generated during the build process and +# extracts information relating to the tests. +# +# Notes: +# To capture an output file under VS builds use the following: +# devenv [build instructions] > Output.txt & type Output.txt +# +# To capture an output file under GCC/Linux builds use the following: +# make | tee Output.txt +# +# To use this parser use the following command +# ruby parseOutput.rb [options] [file] +# options: -xml : produce a JUnit compatible XML file +# file : file to scan for results +#============================================================ + + +class ParseOutput +# The following flag is set to true when a test is found or false otherwise. + @testFlag + @xmlOut + @arrayList + @totalTests + @classIndex + +# Set the flag to indicate if there will be an XML output file or not + def setXmlOutput() + @xmlOut = true + end + +# if write our output to XML + def writeXmlOuput() + output = File.open("report.xml", "w") + output << "\n" + @arrayList.each do |item| + output << item << "\n" + end + output << "\n" + end + +# This function will try and determine when the suite is changed. This is +# is the name that gets added to the classname parameter. + def testSuiteVerify(testSuiteName) + if @testFlag == false + @testFlag = true; + # Split the path name + testName = testSuiteName.split("/") + # Remove the extension + baseName = testName[testName.size - 1].split(".") + @testSuite = "test." + baseName[0] + printf "New Test: %s\n", @testSuite + end + end + + +# Test was flagged as having passed so format the output + def testPassed(array) + lastItem = array.length - 1 + testName = array[lastItem - 1] + testSuiteVerify(array[@className]) + printf "%-40s PASS\n", testName + if @xmlOut == true + @arrayList.push " " + end + end + +# Test was flagged as being ingored so format the output + def testIgnored(array) + lastItem = array.length - 1 + testName = array[lastItem - 2] + reason = array[lastItem].chomp + testSuiteVerify(array[@className]) + printf "%-40s IGNORED\n", testName + if @xmlOut == true + @arrayList.push " " + @arrayList.push " " + reason + " " + @arrayList.push " " + end + end + +# Test was flagged as having failed so format the line + def testFailed(array) + lastItem = array.length - 1 + testName = array[lastItem - 2] + reason = array[lastItem].chomp + " at line: " + array[lastItem - 3] + testSuiteVerify(array[@className]) + printf "%-40s FAILED\n", testName + if @xmlOut == true + @arrayList.push " " + @arrayList.push " " + reason + " " + @arrayList.push " " + end + end + + +# Figure out what OS we are running on. For now we are assuming if it's not Windows it must +# be Unix based. + def detectOS() + myOS = RUBY_PLATFORM.split("-") + if myOS.size == 2 + if myOS[1] == "mingw32" + @className = 1 + else + @className = 0 + end + end + + end + +# Main function used to parse the file that was captured. + def process(name) + @testFlag = false + @arrayList = Array.new + + detectOS() + + puts "Parsing file: " + name + + + testPass = 0 + testFail = 0 + testIgnore = 0 + puts "" + puts "=================== RESULTS =====================" + puts "" + File.open(name).each do |line| + # Typical test lines look like this: + # /.c:36:test_tc1000_opsys:FAIL: Expected 1 Was 0 + # /.c:112:test_tc5004_initCanChannel:IGNORE: Not Yet Implemented + # /.c:115:test_tc5100_initCanVoidPtrs:PASS + # + # where path is different on Unix vs Windows devices (Windows leads with a drive letter) + lineArray = line.split(":") + lineSize = lineArray.size + # If we were able to split the line then we can look to see if any of our target words + # were found. Case is important. + if lineSize >= 4 + # Determine if this test passed + if line.include? ":PASS" + testPassed(lineArray) + testPass += 1 + elsif line.include? ":FAIL:" + testFailed(lineArray) + testFail += 1 + elsif line.include? ":IGNORE:" + testIgnored(lineArray) + testIgnore += 1 + # If none of the keywords are found there are no more tests for this suite so clear + # the test flag + else + @testFlag = false + end + else + @testFlag = false + end + end + puts "" + puts "=================== SUMMARY =====================" + puts "" + puts "Tests Passed : " + testPass.to_s + puts "Tests Failed : " + testFail.to_s + puts "Tests Ignored : " + testIgnore.to_s + @totalTests = testPass + testFail + testIgnore + if @xmlOut == true + heading = "" + @arrayList.insert(0, heading) + writeXmlOuput() + end + + # return result + end + + end + +# If the command line has no values in, used a default value of Output.txt +parseMyFile = ParseOutput.new + +if ARGV.size >= 1 + ARGV.each do |a| + if a == "-xml" + parseMyFile.setXmlOutput(); + else + parseMyFile.process(a) + break + end + end +end diff --git a/tests/tools/auto/test_file_filter.rb b/tests/tools/auto/test_file_filter.rb new file mode 100644 index 000000000..3dbc26a28 --- /dev/null +++ b/tests/tools/auto/test_file_filter.rb @@ -0,0 +1,23 @@ +# ========================================== +# Unity Project - A Test Framework for C +# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams +# [Released under MIT License. Please refer to license.txt for details] +# ========================================== + +require'yaml' + +module RakefileHelpers + class TestFileFilter + def initialize(all_files = false) + @all_files = all_files + if not @all_files == true + if File.exist?('test_file_filter.yml') + filters = YAML.load_file( 'test_file_filter.yml' ) + @all_files, @only_files, @exclude_files = + filters[:all_files], filters[:only_files], filters[:exclude_files] + end + end + end + attr_accessor :all_files, :only_files, :exclude_files + end +end diff --git a/tests/tools/auto/type_sanitizer.rb b/tests/tools/auto/type_sanitizer.rb new file mode 100644 index 000000000..7c2c0ac2c --- /dev/null +++ b/tests/tools/auto/type_sanitizer.rb @@ -0,0 +1,8 @@ +module TypeSanitizer + + def self.sanitize_c_identifier(unsanitized) + # convert filename to valid C identifier by replacing invalid chars with '_' + return unsanitized.gsub(/[-\/\\\.\,\s]/, "_") + end + +end diff --git a/tests/tools/auto/unity_test_summary.py b/tests/tools/auto/unity_test_summary.py new file mode 100644 index 000000000..7426ec8c3 --- /dev/null +++ b/tests/tools/auto/unity_test_summary.py @@ -0,0 +1,135 @@ +#! python3 +# ========================================== +# Unity Project - A Test Framework for C +# Copyright (c) 2015 Alexander Mueller / XelaRellum@web.de +# [Released under MIT License. Please refer to license.txt for details] +# Based on the ruby script by Mike Karlesky, Mark VanderVoord, Greg Williams +# ========================================== +import sys +import os +import re +from glob import glob + +class UnityTestSummary: + def __init__(self): + self.report = '' + self.total_tests = 0 + self.failures = 0 + self.ignored = 0 + + def run(self): + # Clean up result file names + results = [] + for target in self.targets: + results.append(target.replace('\\', '/')) + + # Dig through each result file, looking for details on pass/fail: + failure_output = [] + ignore_output = [] + + for result_file in results: + lines = list(map(lambda line: line.rstrip(), open(result_file, "r").read().split('\n'))) + if len(lines) == 0: + raise Exception("Empty test result file: %s" % result_file) + + details = self.get_details(result_file, lines) + failures = details['failures'] + ignores = details['ignores'] + if len(failures) > 0: failure_output.append('\n'.join(failures)) + if len(ignores) > 0: ignore_output.append('n'.join(ignores)) + tests,failures,ignored = self.parse_test_summary('\n'.join(lines)) + self.total_tests += tests + self.failures += failures + self.ignored += ignored + + if self.ignored > 0: + self.report += "\n" + self.report += "--------------------------\n" + self.report += "UNITY IGNORED TEST SUMMARY\n" + self.report += "--------------------------\n" + self.report += "\n".join(ignore_output) + + if self.failures > 0: + self.report += "\n" + self.report += "--------------------------\n" + self.report += "UNITY FAILED TEST SUMMARY\n" + self.report += "--------------------------\n" + self.report += '\n'.join(failure_output) + + self.report += "\n" + self.report += "--------------------------\n" + self.report += "OVERALL UNITY TEST SUMMARY\n" + self.report += "--------------------------\n" + self.report += "{total_tests} TOTAL TESTS {failures} TOTAL FAILURES {ignored} IGNORED\n".format(total_tests = self.total_tests, failures=self.failures, ignored=self.ignored) + self.report += "\n" + + return self.report + + def set_targets(self, target_array): + self.targets = target_array + + def set_root_path(self, path): + self.root = path + + def usage(self, err_msg=None): + print("\nERROR: ") + if err_msg: + print(err_msg) + print("\nUsage: unity_test_summary.rb result_file_directory/ root_path/") + print(" result_file_directory - The location of your results files.") + print(" Defaults to current directory if not specified.") + print(" Should end in / if specified.") + print(" root_path - Helpful for producing more verbose output if using relative paths.") + sys.exit(1) + + def get_details(self, result_file, lines): + results = { 'failures': [], 'ignores': [], 'successes': [] } + for line in lines: + parts = line.split(':') + if len(parts) != 5: + continue + src_file,src_line,test_name,status,msg = parts + if len(self.root) > 0: + line_out = "%s%s" % (self.root, line) + else: + line_out = line + if status == 'IGNORE': + results['ignores'].append(line_out) + elif status == 'FAIL': + results['failures'].append(line_out) + elif status == 'PASS': + results['successes'].append(line_out) + return results + + def parse_test_summary(self, summary): + m = re.search(r"([0-9]+) Tests ([0-9]+) Failures ([0-9]+) Ignored", summary) + if not m: + raise Exception("Couldn't parse test results: %s" % summary) + + return int(m.group(1)), int(m.group(2)), int(m.group(3)) + + +if __name__ == '__main__': + uts = UnityTestSummary() + try: + #look in the specified or current directory for result files + if len(sys.argv) > 1: + targets_dir = sys.argv[1] + else: + targets_dir = './' + targets = list(map(lambda x: x.replace('\\', '/'), glob(targets_dir + '*.test*'))) + if len(targets) == 0: + raise Exception("No *.testpass or *.testfail files found in '%s'" % targets_dir) + uts.set_targets(targets) + + #set the root path + if len(sys.argv) > 2: + root_path = sys.argv[2] + else: + root_path = os.path.split(__file__)[0] + uts.set_root_path(root_path) + + #run the summarizer + print(uts.run()) + except Exception as e: + uts.usage(e) diff --git a/tests/tools/auto/unity_test_summary.rb b/tests/tools/auto/unity_test_summary.rb new file mode 100644 index 000000000..8cf360f4a --- /dev/null +++ b/tests/tools/auto/unity_test_summary.rb @@ -0,0 +1,139 @@ +# ========================================== +# Unity Project - A Test Framework for C +# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams +# [Released under MIT License. Please refer to license.txt for details] +# ========================================== + +#!/usr/bin/ruby +# +# unity_test_summary.rb +# +require 'fileutils' +require 'set' + +class UnityTestSummary + include FileUtils::Verbose + + attr_reader :report, :total_tests, :failures, :ignored + + def initialize + @report = '' + @total_tests = 0 + @failures = 0 + @ignored = 0 + end + + def run + # Clean up result file names + results = @targets.map {|target| target.gsub(/\\/,'/')} + + # Dig through each result file, looking for details on pass/fail: + failure_output = [] + ignore_output = [] + + results.each do |result_file| + lines = File.readlines(result_file).map { |line| line.chomp } + if lines.length == 0 + raise "Empty test result file: #{result_file}" + else + output = get_details(result_file, lines) + failure_output << output[:failures] unless output[:failures].empty? + ignore_output << output[:ignores] unless output[:ignores].empty? + tests,failures,ignored = parse_test_summary(lines) + @total_tests += tests + @failures += failures + @ignored += ignored + end + end + + if @ignored > 0 + @report += "\n" + @report += "--------------------------\n" + @report += "UNITY IGNORED TEST SUMMARY\n" + @report += "--------------------------\n" + @report += ignore_output.flatten.join("\n") + end + + if @failures > 0 + @report += "\n" + @report += "--------------------------\n" + @report += "UNITY FAILED TEST SUMMARY\n" + @report += "--------------------------\n" + @report += failure_output.flatten.join("\n") + end + + @report += "\n" + @report += "--------------------------\n" + @report += "OVERALL UNITY TEST SUMMARY\n" + @report += "--------------------------\n" + @report += "#{@total_tests} TOTAL TESTS #{@failures} TOTAL FAILURES #{@ignored} IGNORED\n" + @report += "\n" + end + + def set_targets(target_array) + @targets = target_array + end + + def set_root_path(path) + @root = path + end + + def usage(err_msg=nil) + puts "\nERROR: " + puts err_msg if err_msg + puts "\nUsage: unity_test_summary.rb result_file_directory/ root_path/" + puts " result_file_directory - The location of your results files." + puts " Defaults to current directory if not specified." + puts " Should end in / if specified." + puts " root_path - Helpful for producing more verbose output if using relative paths." + exit 1 + end + + protected + + def get_details(result_file, lines) + results = { :failures => [], :ignores => [], :successes => [] } + lines.each do |line| + src_file,src_line,test_name,status,msg = line.split(/:/) + line_out = ((@root and (@root != 0)) ? "#{@root}#{line}" : line ).gsub(/\//, "\\") + case(status) + when 'IGNORE' then results[:ignores] << line_out + when 'FAIL' then results[:failures] << line_out + when 'PASS' then results[:successes] << line_out + end + end + return results + end + + def parse_test_summary(summary) + if summary.find { |v| v =~ /(\d+) Tests (\d+) Failures (\d+) Ignored/ } + [$1.to_i,$2.to_i,$3.to_i] + else + raise "Couldn't parse test results: #{summary}" + end + end + + def here; File.expand_path(File.dirname(__FILE__)); end + +end + +if $0 == __FILE__ + uts = UnityTestSummary.new + begin + #look in the specified or current directory for result files + ARGV[0] ||= './' + targets = "#{ARGV[0].gsub(/\\/, '/')}*.test*" + results = Dir[targets] + raise "No *.testpass or *.testfail files found in '#{targets}'" if results.empty? + uts.set_targets(results) + + #set the root path + ARGV[1] ||= File.expand_path(File.dirname(__FILE__)) + '/' + uts.set_root_path(ARGV[1]) + + #run the summarizer + puts uts.run + rescue Exception => e + uts.usage e.message + end +end diff --git a/tests/tools/build_fixture_runner.pl b/tests/tools/build_fixture_runner.pl new file mode 100644 index 000000000..df7eb1817 --- /dev/null +++ b/tests/tools/build_fixture_runner.pl @@ -0,0 +1,45 @@ +#!/usr/bin/perl + +use strict; +use warnings; +use feature 'say'; + +say "/* THIS IS GENERATED FILE! DO NOT EDIT! DO NOT COMMIT! */"; +say '#include '; +say ''; + +my @run_test_group; +foreach my $file (@ARGV) +{ + my @output = qx(grep -vh '#include' $file | $ENV{CPP} -); + my $test_group_found = 0; + foreach (@output) + { + s/\r//g; + chomp; + if (m/^TEST_GROUP\(/) + { + s/^TEST_GROUP/TEST_GROUP_RUNNER/; + s/;$//; + say "}\n" if ($test_group_found); + say $_; + say '{'; + $test_group_found = 1; + s/TEST_GROUP_RUNNER/\tRUN_TEST_GROUP/; + push @run_test_group, $_; + } + elsif (m/^TEST\(/) + { + s/^TEST/\tRUN_TEST_CASE/; + say "$_;"; + } + elsif (m/^TEST_WITH_TIMEOUT\(/) + { + s/^TEST_WITH_TIMEOUT/\tRUN_TEST_CASE/; + s/,\s+[^,]+\)$/)/; + say "$_;"; + } + } + say "}\n" if ($test_group_found); +} + diff --git a/tests/tools/license.txt b/tests/tools/license.txt new file mode 100644 index 000000000..d66fba53e --- /dev/null +++ b/tests/tools/license.txt @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2007-14 Mike Karlesky, Mark VanderVoord, Greg Williams + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/tests/tools/rename_symbols b/tests/tools/rename_symbols new file mode 100644 index 000000000..2d0b40afb --- /dev/null +++ b/tests/tools/rename_symbols @@ -0,0 +1,21 @@ +#!/bin/bash + +if [ -z "$2" ] +then + echo Usage: $(basename $0) " " 1>&2 + echo " Renames symbols generated by Unity inside object by incorporating unique string into them." 1<&2 + echo " Renaming makes it possible to have testcases with the same name and testsuite under" 1>&2 + echo " different executables" 1>&2 + echo " unique - unique string" 1>&2 + echo " object - object file to modify" 1>&2 + echo " Object file is transformed in-place" 1>&2 + exit 1 +fi + +UNIQUE=$1 +OBJECT=$2 +: ${OBJCOPY:=objcopy} + +# Do not hate me.. love me.. + +$OBJCOPY --redefine-syms <(readelf -Ws $OBJECT | tail -n +4 | awk '{if ($5 != "LOCAL") {print $8, $8}}' | grep -vP '^\s+$' | sed 's/\sTEST_/ TEST_'$UNIQUE'_/') $OBJECT diff --git a/tests/tools/unity_test_summary.rb b/tests/tools/unity_test_summary.rb new file mode 100644 index 000000000..90bf487ec --- /dev/null +++ b/tests/tools/unity_test_summary.rb @@ -0,0 +1,139 @@ +# ========================================== +# Unity Project - A Test Framework for C +# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams +# [Released under MIT License. Please refer to license.txt for details] +# ========================================== + +#!/usr/bin/ruby +# +# unity_test_summary.rb +# +require 'fileutils' +require 'set' + +class UnityTestSummary + include FileUtils::Verbose + + attr_reader :report, :total_tests, :failures, :ignored + + def initialize + @report = '' + @total_tests = 0 + @failures = 0 + @ignored = 0 + end + + def run + # Clean up result file names + results = @targets.map {|target| target.gsub(/\\/,'/')} + + # Dig through each result file, looking for details on pass/fail: + failure_output = [] + ignore_output = [] + + results.each do |result_file| + lines = File.readlines(result_file).map { |line| line.chomp } + if lines.length == 0 + raise "Empty test result file: #{result_file}" + else + output = get_details(result_file, lines) + failure_output << output[:failures] unless output[:failures].empty? + ignore_output << output[:ignores] unless output[:ignores].empty? + tests,failures,ignored = parse_test_summary(lines) + @total_tests += tests + @failures += failures + @ignored += ignored + end + end + + if @ignored > 0 + @report += "\n" + @report += "--------------------------\n" + @report += "UNITY IGNORED TEST SUMMARY\n" + @report += "--------------------------\n" + @report += ignore_output.flatten.join("\n") + end + + if @failures > 0 + @report += "\n" + @report += "--------------------------\n" + @report += "UNITY FAILED TEST SUMMARY\n" + @report += "--------------------------\n" + @report += failure_output.flatten.join("\n") + end + + @report += "\n" + @report += "--------------------------\n" + @report += "OVERALL UNITY TEST SUMMARY\n" + @report += "--------------------------\n" + @report += "#{@total_tests} TOTAL TESTS #{@failures} TOTAL FAILURES #{@ignored} IGNORED\n" + @report += "\n" + end + + def set_targets(target_array) + @targets = target_array + end + + def set_root_path(path) + @root = path + end + + def usage(err_msg=nil) + puts "\nERROR: " + puts err_msg if err_msg + puts "\nUsage: unity_test_summary.rb result_file_directory/ root_path/" + puts " result_file_directory - The location of your results files." + puts " Defaults to current directory if not specified." + puts " Should end in / if specified." + puts " root_path - Helpful for producing more verbose output if using relative paths." + exit 1 + end + + protected + + def get_details(result_file, lines) + results = { :failures => [], :ignores => [], :successes => [] } + lines.each do |line| + src_file,src_line,test_name,status,msg = line.split(/:/) + line_out = ((@root and (@root != 0)) ? "#{@root}#{line}" : line ).gsub(/\//, "\\") + case(status) + when 'IGNORE' then results[:ignores] << line_out + when 'FAIL' then results[:failures] << line_out + when 'PASS' then results[:successes] << line_out + end + end + return results + end + + def parse_test_summary(summary) + if summary.find { |v| v =~ /(\d+) Tests (\d+) Failures (\d+) Ignored/ } + [$1.to_i,$2.to_i,$3.to_i] + else + raise "Couldn't parse test results: #{summary}" + end + end + + def here; File.expand_path(File.dirname(__FILE__)); end + +end + +if $0 == __FILE__ + uts = UnityTestSummary.new + begin + #look in the specified or current directory for result files + ARGV[0] ||= './' + targets = "#{ARGV[0].gsub(/\\/, '/')}*.test*" + results = Dir[targets] + raise "No *.testpass or *.testfail files found in '#{targets}'" if results.empty? + uts.set_targets(results) + + #set the root path + ARGV[1] ||= File.expand_path(File.dirname(__FILE__)) + '/' + uts.set_root_path(ARGV[1]) + + #run the summarizer + puts uts.run + rescue Exception => e + uts.usage e.message + end +end diff --git a/tests/unity/.gitignore b/tests/unity/.gitignore new file mode 100644 index 000000000..fa1ec7579 --- /dev/null +++ b/tests/unity/.gitignore @@ -0,0 +1,11 @@ +/Make.dep +/.depend +/.built +/*.asm +/*.obj +/*.rel +/*.lst +/*.sym +/*.adb +/*.lib +/*.src diff --git a/tests/unity/Kconfig b/tests/unity/Kconfig new file mode 100644 index 000000000..e4cba1b6d --- /dev/null +++ b/tests/unity/Kconfig @@ -0,0 +1,22 @@ +# +# For a description of the syntax of this configuration file, +# see misc/tools/kconfig-language.txt. +# + +config TESTS_UNITY + bool "Unity fixture example" + default n + ---help--- + Demonstrates Unity fixture and runs its unit test + +if TESTS_UNITY + +config TESTS_UNITY_PROGNAME + string "Program name" + default "unity" + depends on BUILD_KERNEL + ---help--- + This is the name of the program that will be use when the NSH ELF + program is installed. + +endif diff --git a/tests/unity/Make.defs b/tests/unity/Make.defs new file mode 100644 index 000000000..3709e9a6c --- /dev/null +++ b/tests/unity/Make.defs @@ -0,0 +1,39 @@ +############################################################################ +# apps/tests/unity/Make.defs +# Adds selected testing applications to apps/ build +# +# Copyright (C) 2015 Haltian Ltd. All rights reserved. +# Author: Roman Saveljev +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +ifeq ($(CONFIG_TESTS_UNITY),y) +CONFIGURED_APPS += tests/unity +endif diff --git a/tests/unity/Makefile b/tests/unity/Makefile new file mode 100644 index 000000000..8a93d01c1 --- /dev/null +++ b/tests/unity/Makefile @@ -0,0 +1,137 @@ +############################################################################ +# apps/examples/unity/Makefile +# +# Copyright (C) 2015 Haltian Ltd. All rights reserved. +# Author: Roman Saveljev +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +-include $(TOPDIR)/.config +-include $(TOPDIR)/Make.defs +include $(APPDIR)/Make.defs + +# Hello, World! built-in application info + +APPNAME = unity +PRIORITY = SCHED_PRIORITY_DEFAULT +STACKSIZE = 2048 + +ASRCS = +CSRCS = unity_fixture_Test.c unity_fixture_TestRunner.c unity_output_Spy.c +MAINSRC = main/AllTests.c + +AOBJS = $(ASRCS:.S=$(OBJEXT)) +COBJS = $(CSRCS:.c=$(OBJEXT)) +MAINOBJ = $(MAINSRC:.c=$(OBJEXT)) + +SRCS = $(ASRCS) $(CSRCS) $(MAINSRC) +OBJS = $(AOBJS) $(COBJS) + +ifneq ($(CONFIG_BUILD_KERNEL),y) + OBJS += $(MAINOBJ) +endif + +ifeq ($(CONFIG_WINDOWS_NATIVE),y) + BIN = ..\..\libapps$(LIBEXT) +else +ifeq ($(WINTOOL),y) + BIN = ..\\..\\libapps$(LIBEXT) +else + BIN = ../../libapps$(LIBEXT) +endif +endif + +ifeq ($(WINTOOL),y) + INSTALL_DIR = "${shell cygpath -w $(BIN_DIR)}" +else + INSTALL_DIR = $(BIN_DIR) +endif + +CONFIG_EXAMPLES_UNITY_PROGNAME ?= unity$(EXEEXT) +PROGNAME = $(CONFIG_EXAMPLES_UNITY_PROGNAME) + +ROOTDEPPATH = --dep-path . + +# Common build + +VPATH = + +all: .built +.PHONY: clean depend distclean + +$(AOBJS): %$(OBJEXT): %.S + $(call ASSEMBLE, $<, $@) + +$(COBJS) $(MAINOBJ): %$(OBJEXT): %.c + $(call COMPILE, $<, $@) + $(Q) OBJCOPY=$(OBJCOPY) $(APPDIR)/tests/tools/rename_symbols $(APPNAME) $@ + +.built: $(OBJS) + $(call ARCHIVE, $(BIN), $(OBJS)) + @touch .built + +ifeq ($(CONFIG_BUILD_KERNEL),y) +$(BIN_DIR)$(DELIM)$(PROGNAME): $(OBJS) $(MAINOBJ) + @echo "LD: $(PROGNAME)" + $(Q) $(LD) $(LDELFFLAGS) $(LDLIBPATH) -o $(INSTALL_DIR)$(DELIM)$(PROGNAME) $(ARCHCRT0OBJ) $(MAINOBJ) $(LDLIBS) + $(Q) $(NM) -u $(INSTALL_DIR)$(DELIM)$(PROGNAME) + +install: $(BIN_DIR)$(DELIM)$(PROGNAME) + +else +install: + +endif + +ifeq ($(CONFIG_NSH_BUILTIN_APPS),y) +$(BUILTIN_REGISTRY)$(DELIM)$(APPNAME)_main.bdat: $(DEPCONFIG) Makefile + $(call REGISTER,$(APPNAME),$(PRIORITY),$(STACKSIZE),$(APPNAME)_main) + +context: $(BUILTIN_REGISTRY)$(DELIM)$(APPNAME)_main.bdat +else +context: +endif + +.depend: Makefile $(SRCS) + @$(MKDEP) $(ROOTDEPPATH) "$(CC)" -- $(CFLAGS) -- $(SRCS) >Make.dep + @touch $@ + +depend: .depend + +clean: + $(call DELFILE, .built) + $(call CLEAN) + $(Q) rm -f $(OBJS) + +distclean: clean + $(call DELFILE, Make.dep) + $(call DELFILE, .depend) + +-include Make.dep diff --git a/tests/unity/main/AllTests.c b/tests/unity/main/AllTests.c new file mode 100644 index 000000000..18f5278d6 --- /dev/null +++ b/tests/unity/main/AllTests.c @@ -0,0 +1,30 @@ +//- Copyright (c) 2010 James Grenning and Contributed to Unity Project +/* ========================================== + Unity Project - A Test Framework for C + Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams + [Released under MIT License. Please refer to license.txt for details] +========================================== */ + +#include + +// Enable for manual examination - tests will fail +//#define MANUAL_CHECKING + +static void runAllTests(void) +{ + RUN_TEST_GROUP(UnityFixture); + RUN_TEST_GROUP(UnityCommandOptions); + RUN_TEST_GROUP(LeakDetection); + RUN_TEST_GROUP(Timeout); +#ifdef MANUAL_CHECKING + RUN_TEST_GROUP(TimeoutInSetup); + RUN_TEST_GROUP(TimeoutInBody); + RUN_TEST_GROUP(TimeoutInTearDown); +#endif +} + +int unity_main(int argc, const char* argv[]) +{ + return UnityMain(argc, argv, runAllTests); +} + diff --git a/tests/unity/testunity_fixture.c b/tests/unity/testunity_fixture.c new file mode 100644 index 000000000..8d4db9f93 --- /dev/null +++ b/tests/unity/testunity_fixture.c @@ -0,0 +1,39 @@ +//- Copyright (c) 2010 James Grenning and Contributed to Unity Project +/* ========================================== + Unity Project - A Test Framework for C + Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams + [Released under MIT License. Please refer to license.txt for details] +========================================== */ + +#include + +static int data = -1; + +TEST_GROUP(mygroup); + +TEST_SETUP(mygroup) +{ + data = 0; +} + +TEST_TEAR_DOWN(mygroup) +{ + data = -1; +} + +TEST(mygroup, test1) +{ + TEST_ASSERT_EQUAL_INT(0, data); +} + +TEST(mygroup, test2) +{ + TEST_ASSERT_EQUAL_INT(0, data); + data = 5; +} + +TEST(mygroup, test3) +{ + data = 7; + TEST_ASSERT_EQUAL_INT(7, data); +} diff --git a/tests/unity/unity_fixture_Test.c b/tests/unity/unity_fixture_Test.c new file mode 100644 index 000000000..cb55858a2 --- /dev/null +++ b/tests/unity/unity_fixture_Test.c @@ -0,0 +1,454 @@ +//- Copyright (c) 2010 James Grenning and Contributed to Unity Project +/* ========================================== + Unity Project - A Test Framework for C + Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams + [Released under MIT License. Please refer to license.txt for details] +========================================== */ + +#include +#include "unity_output_Spy.h" +#include +#include + +extern UNITY_FIXTURE_T UnityFixture; + +TEST_GROUP(UnityFixture); + +TEST_SETUP(UnityFixture) +{ +} + +TEST_TEAR_DOWN(UnityFixture) +{ +} + +int my_int; +int* pointer1 = 0; +int* pointer2 = (int*)2; +int* pointer3 = (int*)3; +int int1; +int int2; +int int3; +int int4; + +TEST(UnityFixture, PointerSetting) +{ + TEST_ASSERT_POINTERS_EQUAL(pointer1, 0); + UT_PTR_SET(pointer1, &int1); + UT_PTR_SET(pointer2, &int2); + UT_PTR_SET(pointer3, &int3); + TEST_ASSERT_POINTERS_EQUAL(pointer1, &int1); + TEST_ASSERT_POINTERS_EQUAL(pointer2, &int2); + TEST_ASSERT_POINTERS_EQUAL(pointer3, &int3); + UT_PTR_SET(pointer1, &int4); + UnityPointer_UndoAllSets(); + TEST_ASSERT_POINTERS_EQUAL(pointer1, 0); + TEST_ASSERT_POINTERS_EQUAL(pointer2, (int*)2); + TEST_ASSERT_POINTERS_EQUAL(pointer3, (int*)3); +} + +TEST(UnityFixture, ForceMallocFail) +{ + void* m; + void* mfails; + UnityMalloc_MakeMallocFailAfterCount(1); + m = malloc(10); + CHECK(m); + mfails = malloc(10); + TEST_ASSERT_POINTERS_EQUAL(0, mfails); + free(m); +} + +TEST(UnityFixture, ReallocSmallerIsUnchanged) +{ + void* m1 = malloc(10); + void* m2 = realloc(m1, 5); + TEST_ASSERT_POINTERS_EQUAL(m1, m2); + free(m2); +} + +TEST(UnityFixture, ReallocSameIsUnchanged) +{ + void* m1 = malloc(10); + void* m2 = realloc(m1, 10); + TEST_ASSERT_POINTERS_EQUAL(m1, m2); + free(m2); +} + +TEST(UnityFixture, ReallocLargerNeeded) +{ + void* m1 = malloc(10); + void* m2; + strcpy((char*)m1, "123456789"); + m2 = realloc(m1, 15); + CHECK(m1 != m2); + STRCMP_EQUAL("123456789", m2); + free(m2); +} + +TEST(UnityFixture, ReallocNullPointerIsLikeMalloc) +{ + void* m = realloc(0, 15); + CHECK(m != 0); + free(m); +} + +TEST(UnityFixture, ReallocSizeZeroFreesMemAndReturnsNullPointer) +{ + void* m1 = malloc(10); + void* m2 = realloc(m1, 0); + TEST_ASSERT_POINTERS_EQUAL(0, m2); +} + +TEST(UnityFixture, CallocFillsWithZero) +{ + void* m = calloc(3, sizeof(char)); + char* s = (char*)m; + TEST_ASSERT_BYTES_EQUAL(0, s[0]); + TEST_ASSERT_BYTES_EQUAL(0, s[1]); + TEST_ASSERT_BYTES_EQUAL(0, s[2]); + free(m); +} + +char *p1; +char *p2; + +TEST(UnityFixture, PointerSet) +{ + char c1; + char c2; + char newC1; + char newC2; + p1 = &c1; + p2 = &c2; + + UnityPointer_Init(); + UT_PTR_SET(p1, &newC1); + UT_PTR_SET(p2, &newC2); + TEST_ASSERT_POINTERS_EQUAL(&newC1, p1); + TEST_ASSERT_POINTERS_EQUAL(&newC2, p2); + UnityPointer_UndoAllSets(); + TEST_ASSERT_POINTERS_EQUAL(&c1, p1); + TEST_ASSERT_POINTERS_EQUAL(&c2, p2); +} + +//------------------------------------------------------------ + +TEST_GROUP(UnityCommandOptions); + +static int savedVerbose; +static int savedRepeat; +static int savedListOnly; +static const char* savedName; +static const char* savedGroup; +static const char** savedList; + +TEST_SETUP(UnityCommandOptions) +{ + savedVerbose = UnityFixture.Verbose; + savedRepeat = UnityFixture.RepeatCount; + savedListOnly = UnityFixture.ListOnly; + savedName = UnityFixture.NameFilter; + savedGroup = UnityFixture.GroupFilter; + savedList = UnityFixture.PlainListOfTests; +} + +TEST_TEAR_DOWN(UnityCommandOptions) +{ + UnityFixture.Verbose = savedVerbose; + UnityFixture.RepeatCount= savedRepeat; + UnityFixture.ListOnly = savedListOnly; + UnityFixture.NameFilter = savedName; + UnityFixture.GroupFilter = savedGroup; + UnityFixture.PlainListOfTests = savedList; +} + + +static const char* noOptions[] = { + "testrunner.exe" +}; + +TEST(UnityCommandOptions, DefaultOptions) +{ + UnityGetCommandLineOptions(1, noOptions); + TEST_ASSERT_EQUAL(0, UnityFixture.Verbose); + TEST_ASSERT_POINTERS_EQUAL(0, UnityFixture.GroupFilter); + TEST_ASSERT_POINTERS_EQUAL(0, UnityFixture.NameFilter); + TEST_ASSERT_EQUAL(1, UnityFixture.RepeatCount); +} + +static const char* verbose[] = { + "testrunner.exe", + "-v" +}; + +TEST(UnityCommandOptions, OptionVerbose) +{ + TEST_ASSERT_EQUAL(0, UnityGetCommandLineOptions(2, verbose)); + TEST_ASSERT_EQUAL(1, UnityFixture.Verbose); +} + +static const char* group[] = { + "testrunner.exe", + "-g", "groupname" +}; + +TEST(UnityCommandOptions, OptionSelectTestByGroup) +{ + TEST_ASSERT_EQUAL(0, UnityGetCommandLineOptions(3, group)); + STRCMP_EQUAL("groupname", UnityFixture.GroupFilter); +} + +static const char* name[] = { + "testrunner.exe", + "-n", "testname" +}; + +TEST(UnityCommandOptions, OptionSelectTestByName) +{ + TEST_ASSERT_EQUAL(0, UnityGetCommandLineOptions(3, name)); + STRCMP_EQUAL("testname", UnityFixture.NameFilter); +} + +static const char* repeat[] = { + "testrunner.exe", + "-r", "99" +}; + +TEST(UnityCommandOptions, OptionSelectRepeatTestsDefaultCount) +{ + TEST_ASSERT_EQUAL(0, UnityGetCommandLineOptions(2, repeat)); + TEST_ASSERT_EQUAL(2, UnityFixture.RepeatCount); +} + +TEST(UnityCommandOptions, OptionSelectRepeatTestsSpecificCount) +{ + TEST_ASSERT_EQUAL(0, UnityGetCommandLineOptions(3, repeat)); + TEST_ASSERT_EQUAL(99, UnityFixture.RepeatCount); +} + +static const char* multiple[] = { + "testrunner.exe", + "-v", + "-g", "groupname", + "-n", "testname", + "-r", "98" +}; + +TEST(UnityCommandOptions, MultipleOptions) +{ + TEST_ASSERT_EQUAL(0, UnityGetCommandLineOptions(8, multiple)); + TEST_ASSERT_EQUAL(1, UnityFixture.Verbose); + STRCMP_EQUAL("groupname", UnityFixture.GroupFilter); + STRCMP_EQUAL("testname", UnityFixture.NameFilter); + TEST_ASSERT_EQUAL(98, UnityFixture.RepeatCount); +} + +static const char* dashRNotLast[] = { + "testrunner.exe", + "-v", + "-g", "gggg", + "-r", + "-n", "tttt", +}; + +TEST(UnityCommandOptions, MultipleOptionsDashRNotLastAndNoValueSpecified) +{ + TEST_ASSERT_EQUAL(0, UnityGetCommandLineOptions(7, dashRNotLast)); + TEST_ASSERT_EQUAL(1, UnityFixture.Verbose); + STRCMP_EQUAL("gggg", UnityFixture.GroupFilter); + STRCMP_EQUAL("tttt", UnityFixture.NameFilter); + TEST_ASSERT_EQUAL(2, UnityFixture.RepeatCount); +} + +static const char* unknownCommand[] = { + "testrunner.exe", + "-v", + "-g", "groupname", + "-n", "testname", + "-r", "98", + "-z" +}; +TEST(UnityCommandOptions, UnknownCommandIsIgnored) +{ + TEST_ASSERT_EQUAL(0, UnityGetCommandLineOptions(9, unknownCommand)); + TEST_ASSERT_EQUAL(1, UnityFixture.Verbose); + STRCMP_EQUAL("groupname", UnityFixture.GroupFilter); + STRCMP_EQUAL("testname", UnityFixture.NameFilter); + TEST_ASSERT_EQUAL(98, UnityFixture.RepeatCount); +} + +static const char* listing[] = { + "testrunner.exe", + "-l", +}; +TEST(UnityCommandOptions, Listing) +{ + TEST_ASSERT_EQUAL(0, UnityGetCommandLineOptions(2, listing)); + TEST_ASSERT_EQUAL(1, UnityFixture.ListOnly); +} + +static const char* exactListVerbose[] = { + "testrunner.exe", + "-v", + "--", + "MyTest/TestOne", + "MyTest/TestTwo", + NULL +}; +TEST(UnityCommandOptions, ExactList) +{ + TEST_ASSERT_EQUAL(0, UnityGetCommandLineOptions(5, exactListVerbose)); + TEST_ASSERT_EQUAL(1, UnityFixture.Verbose); + TEST_ASSERT_EQUAL_STRING("MyTest/TestOne", UnityFixture.PlainListOfTests[0]); + TEST_ASSERT_EQUAL_STRING("MyTest/TestTwo", UnityFixture.PlainListOfTests[1]); + TEST_ASSERT_NULL(UnityFixture.PlainListOfTests[2]); +} + +//------------------------------------------------------------ + +TEST_GROUP(LeakDetection); + +TEST_SETUP(LeakDetection) +{ + UnityOutputCharSpy_Create(1000); +} + +TEST_TEAR_DOWN(LeakDetection) +{ + UnityOutputCharSpy_Destroy(); +} + +TEST(LeakDetection, DetectsLeak) +{ + void* m = malloc(10); + UnityOutputCharSpy_Enable(1); + TEST_PROTECTED(UnityMalloc_EndTest); + UnityOutputCharSpy_Enable(0); + CHECK(strstr(UnityOutputCharSpy_Get(), "This test leaks!")); + free(m); + Unity.CurrentTestFailed = 0; +} + +static void BufferOverrunFoundDuringFree_worker(void) +{ + void* m = malloc(10); + char* s = (char*)m; + s[10] = (char)0xFF; + free(m); +} + +TEST(LeakDetection, BufferOverrunFoundDuringFree) +{ + UnityOutputCharSpy_Enable(1); + TEST_PROTECTED(BufferOverrunFoundDuringFree_worker); + UnityOutputCharSpy_Enable(0); + CHECK(strstr(UnityOutputCharSpy_Get(), "Buffer overrun detected during free()")); + Unity.CurrentTestFailed = 0; +} + +static void BufferOverrunFoundDuringRealloc_worker(void) +{ + void* m = malloc(10); + char* s = (char*)m; + s[10] = (char)0xFF; + m = realloc(m, 100); +} + +TEST(LeakDetection, BufferOverrunFoundDuringRealloc) +{ + UnityOutputCharSpy_Enable(1); + TEST_PROTECTED(BufferOverrunFoundDuringRealloc_worker); + UnityOutputCharSpy_Enable(0); + CHECK(strstr(UnityOutputCharSpy_Get(), "Buffer overrun detected during realloc()")); + Unity.CurrentTestFailed = 0; +} + +//------------------------------------------------------------ + +TEST_GROUP(Timeout); + +TEST_SETUP(Timeout) +{ +} + +TEST_TEAR_DOWN(Timeout) +{ +} + +static void SleepSome(void) +{ + usleep(100000); +} + +TEST(Timeout, Triggers) +{ + int result = TEST_PROTECTED_WITH_TIMEOUT(SleepSome, 10); + TEST_ASSERT_TRUE(Unity.CurrentTestTimeout); + TEST_ASSERT_NOT_EQUAL(0, result); + Unity.CurrentTestTimeout = false; +} + +TEST(Timeout, DoesNotTrigger) +{ + int result = TEST_PROTECTED_WITH_TIMEOUT(SleepSome, 200); + UNITY_COUNTER_TYPE isTimeout = Unity.CurrentTestTimeout; + Unity.CurrentTestTimeout = 0; + TEST_ASSERT_EQUAL(0, result); + TEST_ASSERT_FALSE(isTimeout); +} + +//------------------------------------------------------------ +// Manual checking +//------------------------------------------------------------ + +TEST_GROUP(TimeoutInSetup); + +TEST_SETUP_WITH_TIMEOUT(TimeoutInSetup, 100) +{ + usleep(300000); +} + +TEST_TEAR_DOWN_WITH_TIMEOUT(TimeoutInSetup, 100) +{ + usleep(2); +} + +TEST_WITH_TIMEOUT(TimeoutInSetup, Test, 100) +{ + usleep(2); +} + +TEST_GROUP(TimeoutInBody); + +TEST_SETUP_WITH_TIMEOUT(TimeoutInBody, 100) +{ + usleep(2); +} + +TEST_TEAR_DOWN_WITH_TIMEOUT(TimeoutInBody, 100) +{ + usleep(2); +} + +TEST_WITH_TIMEOUT(TimeoutInBody, Test, 100) +{ + usleep(300000); +} + +TEST_GROUP(TimeoutInTearDown); + +TEST_SETUP_WITH_TIMEOUT(TimeoutInTearDown, 100) +{ + usleep(2); +} + +TEST_TEAR_DOWN_WITH_TIMEOUT(TimeoutInTearDown, 100) +{ + usleep(300000); +} + +TEST_WITH_TIMEOUT(TimeoutInTearDown, Test, 100) +{ + usleep(2); +} diff --git a/tests/unity/unity_fixture_TestRunner.c b/tests/unity/unity_fixture_TestRunner.c new file mode 100644 index 000000000..5661e275f --- /dev/null +++ b/tests/unity/unity_fixture_TestRunner.c @@ -0,0 +1,64 @@ +//- Copyright (c) 2010 James Grenning and Contributed to Unity Project +/* ========================================== + Unity Project - A Test Framework for C + Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams + [Released under MIT License. Please refer to license.txt for details] +========================================== */ + +#include + +TEST_GROUP_RUNNER(UnityFixture) +{ + RUN_TEST_CASE(UnityFixture, PointerSetting); + RUN_TEST_CASE(UnityFixture, ForceMallocFail); + RUN_TEST_CASE(UnityFixture, ReallocSmallerIsUnchanged); + RUN_TEST_CASE(UnityFixture, ReallocSameIsUnchanged); + RUN_TEST_CASE(UnityFixture, ReallocLargerNeeded); + RUN_TEST_CASE(UnityFixture, ReallocNullPointerIsLikeMalloc); + RUN_TEST_CASE(UnityFixture, ReallocSizeZeroFreesMemAndReturnsNullPointer); + RUN_TEST_CASE(UnityFixture, CallocFillsWithZero); + RUN_TEST_CASE(UnityFixture, PointerSet); +} + +TEST_GROUP_RUNNER(UnityCommandOptions) +{ + RUN_TEST_CASE(UnityCommandOptions, DefaultOptions); + RUN_TEST_CASE(UnityCommandOptions, OptionVerbose); + RUN_TEST_CASE(UnityCommandOptions, OptionSelectTestByGroup); + RUN_TEST_CASE(UnityCommandOptions, OptionSelectTestByName); + RUN_TEST_CASE(UnityCommandOptions, OptionSelectRepeatTestsDefaultCount); + RUN_TEST_CASE(UnityCommandOptions, OptionSelectRepeatTestsSpecificCount); + RUN_TEST_CASE(UnityCommandOptions, MultipleOptions); + RUN_TEST_CASE(UnityCommandOptions, MultipleOptionsDashRNotLastAndNoValueSpecified); + RUN_TEST_CASE(UnityCommandOptions, UnknownCommandIsIgnored); + RUN_TEST_CASE(UnityCommandOptions, Listing); + RUN_TEST_CASE(UnityCommandOptions, ExactList); +} + +TEST_GROUP_RUNNER(LeakDetection) +{ + RUN_TEST_CASE(LeakDetection, DetectsLeak); + RUN_TEST_CASE(LeakDetection, BufferOverrunFoundDuringFree); + RUN_TEST_CASE(LeakDetection, BufferOverrunFoundDuringRealloc); +} + +TEST_GROUP_RUNNER(Timeout) +{ + RUN_TEST_CASE(Timeout, Triggers); + RUN_TEST_CASE(Timeout, DoesNotTrigger); +} + +TEST_GROUP_RUNNER(TimeoutInSetup) +{ + RUN_TEST_CASE(TimeoutInSetup, Test); +} + +TEST_GROUP_RUNNER(TimeoutInBody) +{ + RUN_TEST_CASE(TimeoutInBody, Test); +} + +TEST_GROUP_RUNNER(TimeoutInTearDown) +{ + RUN_TEST_CASE(TimeoutInTearDown, Test); +} diff --git a/tests/unity/unity_output_Spy.c b/tests/unity/unity_output_Spy.c new file mode 100644 index 000000000..0a0ad0448 --- /dev/null +++ b/tests/unity/unity_output_Spy.c @@ -0,0 +1,56 @@ +//- Copyright (c) 2010 James Grenning and Contributed to Unity Project +/* ========================================== + Unity Project - A Test Framework for C + Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams + [Released under MIT License. Please refer to license.txt for details] +========================================== */ + + +#include "unity_output_Spy.h" +#include +#include +#include + +static int size; +static int count; +static char* buffer; +static int spy_enable; + +void UnityOutputCharSpy_Create(int s) +{ + size = s; + count = 0; + spy_enable = 0; + buffer = malloc(size); + memset(buffer, 0, size); +} + +void UnityOutputCharSpy_Destroy(void) +{ + size = 0; + free(buffer); +} + +int UnityOutputCharSpy_OutputChar(int c) +{ + if (spy_enable) + { + if (count < (size-1)) + buffer[count++] = c; + } + else + { + putchar(c); + } + return c; +} + +const char * UnityOutputCharSpy_Get(void) +{ + return buffer; +} + +void UnityOutputCharSpy_Enable(int enable) +{ + spy_enable = enable; +} diff --git a/tests/unity/unity_output_Spy.h b/tests/unity/unity_output_Spy.h new file mode 100644 index 000000000..791f6a58d --- /dev/null +++ b/tests/unity/unity_output_Spy.h @@ -0,0 +1,17 @@ +//- Copyright (c) 2010 James Grenning and Contributed to Unity Project +/* ========================================== + Unity Project - A Test Framework for C + Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams + [Released under MIT License. Please refer to license.txt for details] +========================================== */ + +#ifndef D_unity_output_Spy_H +#define D_unity_output_Spy_H + +void UnityOutputCharSpy_Create(int s); +void UnityOutputCharSpy_Destroy(void); +int UnityOutputCharSpy_OutputChar(int c); +const char * UnityOutputCharSpy_Get(void); +void UnityOutputCharSpy_Enable(int enable); + +#endif diff --git a/tests/unity_ramtest/.gitignore b/tests/unity_ramtest/.gitignore new file mode 100644 index 000000000..fa1ec7579 --- /dev/null +++ b/tests/unity_ramtest/.gitignore @@ -0,0 +1,11 @@ +/Make.dep +/.depend +/.built +/*.asm +/*.obj +/*.rel +/*.lst +/*.sym +/*.adb +/*.lib +/*.src diff --git a/tests/unity_ramtest/Kconfig b/tests/unity_ramtest/Kconfig new file mode 100644 index 000000000..554b24819 --- /dev/null +++ b/tests/unity_ramtest/Kconfig @@ -0,0 +1,11 @@ +# +# For a description of the syntax of this configuration file, +# see misc/tools/kconfig-language.txt. +# + +config TESTS_UNITY_RAMTEST + bool "Automated RAM test" + default n + ---help--- + Enable automated RAM test + diff --git a/tests/unity_ramtest/Make.defs b/tests/unity_ramtest/Make.defs new file mode 100644 index 000000000..88a6de118 --- /dev/null +++ b/tests/unity_ramtest/Make.defs @@ -0,0 +1,39 @@ +############################################################################ +# apps/tests/unity_ramtest/Make.defs +# Adds selected testing applications to apps/ build +# +# Copyright (C) 2015 Haltian Ltd. All rights reserved. +# Author: Roman Saveljev +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +ifeq ($(CONFIG_TESTS_UNITY_RAMTEST),y) +CONFIGURED_APPS += tests/unity_ramtest +endif diff --git a/tests/unity_ramtest/Makefile b/tests/unity_ramtest/Makefile new file mode 100644 index 000000000..2517a218d --- /dev/null +++ b/tests/unity_ramtest/Makefile @@ -0,0 +1,146 @@ +############################################################################ +# apps/tests/unity_ramtest/Makefile +# +# Copyright (C) 2015 Haltian Ltd. All rights reserved. +# Author: Roman Saveljev +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +-include $(TOPDIR)/.config +-include $(TOPDIR)/Make.defs +include $(APPDIR)/Make.defs + +APPNAME = unity_ramtest +PRIORITY = SCHED_PRIORITY_DEFAULT +STACKSIZE = 2048 + +CFLAGS += -x c + +ASRCS = +RUNNERSRC = unity_ramtest_runner.src +TESTSRCS = marching_zeroes.c marching_ones.c pattern.c addr_in_addr.c +CSRCS = $(TESTSRCS) +MAINSRC = unity_ramtest_main.c + +RUNNEROBJ = $(RUNNERSRC:.src=$(OBJEXT)) +AOBJS = $(ASRCS:.S=$(OBJEXT)) +COBJS = $(CSRCS:.c=$(OBJEXT)) +MAINOBJ = $(MAINSRC:.c=$(OBJEXT)) + +SRCS = $(ASRCS) $(CSRCS) $(MAINSRC) $(RUNNERSRC) +OBJS = $(AOBJS) $(COBJS) $(RUNNEROBJ) + +ifneq ($(CONFIG_BUILD_KERNEL),y) + OBJS += $(MAINOBJ) +endif + +ifeq ($(CONFIG_WINDOWS_NATIVE),y) + BIN = ..\..\libapps$(LIBEXT) +else +ifeq ($(WINTOOL),y) + BIN = ..\\..\\libapps$(LIBEXT) +else + BIN = ../../libapps$(LIBEXT) +endif +endif + +ifeq ($(WINTOOL),y) + INSTALL_DIR = "${shell cygpath -w $(BIN_DIR)}" +else + INSTALL_DIR = $(BIN_DIR) +endif + +PROGNAME = unity_ramtest$(EXEEXT) + +ROOTDEPPATH = --dep-path . + +# Common build + +VPATH = + +all: .built +.PHONY: clean depend distclean + +$(RUNNERSRC) : $(TESTSRCS) + $(Q) CPP="$(CPP)" $(APPDIR)/tests/tools/build_fixture_runner.pl $^ >$@ + +$(AOBJS): %$(OBJEXT): %.S + $(call ASSEMBLE, $<, $@) + +$(RUNNEROBJ): $(RUNNERSRC) + $(call COMPILE, $<, $@) + $(Q) OBJCOPY=$(OBJCOPY) $(APPDIR)/tests/tools/rename_symbols $(APPNAME) $@ + +$(COBJS) $(MAINOBJ): %$(OBJEXT): %.c + $(call COMPILE, $<, $@) + $(Q) OBJCOPY=$(OBJCOPY) $(APPDIR)/tests/tools/rename_symbols $(APPNAME) $@ + +.built: $(OBJS) + $(call ARCHIVE, $(BIN), $(OBJS)) + @touch .built + +ifeq ($(CONFIG_BUILD_KERNEL),y) +$(BIN_DIR)$(DELIM)$(PROGNAME): $(OBJS) $(MAINOBJ) + @echo "LD: $(PROGNAME)" + $(Q) $(LD) $(LDELFFLAGS) $(LDLIBPATH) -o $(INSTALL_DIR)$(DELIM)$(PROGNAME) $(ARCHCRT0OBJ) $(MAINOBJ) $(LDLIBS) + $(Q) $(NM) -u $(INSTALL_DIR)$(DELIM)$(PROGNAME) + +install: $(BIN_DIR)$(DELIM)$(PROGNAME) + +else +install: + +endif + +ifeq ($(CONFIG_NSH_BUILTIN_APPS),y) +$(BUILTIN_REGISTRY)$(DELIM)$(APPNAME)_main.bdat: $(DEPCONFIG) Makefile + $(call REGISTER,$(APPNAME),$(PRIORITY),$(STACKSIZE),$(APPNAME)_main) + +context: $(BUILTIN_REGISTRY)$(DELIM)$(APPNAME)_main.bdat +else +context: +endif + +.depend: Makefile $(SRCS) + @$(MKDEP) $(ROOTDEPPATH) "$(CC)" -- $(CFLAGS) -- $(SRCS) >Make.dep + @touch $@ + +depend: .depend + +clean: + $(call DELFILE, .built) + $(call DELFILE, unity_dev_err_runner.src) + $(call CLEAN) + +distclean: clean + $(call DELFILE, Make.dep) + $(call DELFILE, .depend) + +-include Make.dep diff --git a/tests/unity_ramtest/addr_in_addr.c b/tests/unity_ramtest/addr_in_addr.c new file mode 100644 index 000000000..edbb9067e --- /dev/null +++ b/tests/unity_ramtest/addr_in_addr.c @@ -0,0 +1,185 @@ +/**************************************************************************** + * apps/tests/unity_ramtest/addr_in_addr.c + * Automated RAM test copied from apps/system/ramtest + * + * Copyright (C) 2015 Haltian Ltd. All rights reserved. + * Author: Roman Saveljev + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ +#include +#include "library.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ +static void* g_memory; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static void addr_in_addr(enum memory_access_width width) +{ + unity_ramtest_write_addrinaddr(width, g_memory, MEMORY_ALLOCATION_SIZE); + unity_ramtest_verify_addrinaddr(width, g_memory, MEMORY_ALLOCATION_SIZE); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +TEST_GROUP(AddrInAddr); + +/**************************************************************************** + * Name: AddrInAddr test group setup + * + * Description: + * Setup function executed before each testcase in this test group + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +TEST_SETUP(AddrInAddr) +{ + g_memory = malloc(MEMORY_ALLOCATION_SIZE); + TEST_ASSERT_NOT_NULL(g_memory); +} + +/**************************************************************************** + * Name: AddrInAddr test group tear down + * + * Description: + * Tear down function executed after each testcase in this test group + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +TEST_TEAR_DOWN(AddrInAddr) +{ + free(g_memory); + g_memory = NULL; +} + +/**************************************************************************** + * Name: ByteAccess + * + * Description: + * Daisy-chain writing the memory one byte at a time + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +TEST(AddrInAddr, ByteAccess) +{ + addr_in_addr(MEMORY_ACCESS_BYTE); +} + +/**************************************************************************** + * Name: HalfAccess + * + * Description: + * Daisy-chain writing the memory a half-word at a time + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +TEST(AddrInAddr, HalfAccess) +{ + addr_in_addr(MEMORY_ACCESS_HALFWORD); +} + +/**************************************************************************** + * Name: WordAccess + * + * Description: + * Daisy-chain writing the memory a word at a time + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +TEST(AddrInAddr, WordAccess) +{ + addr_in_addr(MEMORY_ACCESS_WORD); +} diff --git a/tests/unity_ramtest/library.h b/tests/unity_ramtest/library.h new file mode 100644 index 000000000..fd1de1056 --- /dev/null +++ b/tests/unity_ramtest/library.h @@ -0,0 +1,196 @@ +/**************************************************************************** + * apps/examples/unity_ramtest/library.h + * Common functions + * + * Copyright (C) 2015 Haltian Ltd. All rights reserved. + * Author: Roman Saveljev + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ +#ifndef __TESTS_UNITY_RAMTEST_LIBRARY_H +#define __TESTS_UNITY_RAMTEST_LIBRARY_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ +#define MEMORY_ALLOCATION_SIZE 0x2000 + +/**************************************************************************** + * Public Types + ****************************************************************************/ +enum memory_access_width +{ + MEMORY_ACCESS_BYTE = 8, + MEMORY_ACCESS_HALFWORD = 16, + MEMORY_ACCESS_WORD = 32 +}; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Inline Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: unity_ramtest_write_memory + * + * Description: + * Write memory with specific pattern and access width + * + * Input Parameters: + * value - pattern to write + * width - access width + * start - memory region starting address + * size - number of bytes allocated for the region + * + * Returned Value: + * none, fails the testcase + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +void unity_ramtest_write_memory(uint32_t value, enum memory_access_width width, void *start, size_t size); + +/**************************************************************************** + * Name: unity_ramtest_verify_memory + * + * Description: + * Verifies memory has specific pattern and reading it with access width + * + * Input Parameters: + * value - pattern to expect + * width - access width + * start - memory region starting address + * size - number of bytes allocated for the region + * + * Returned Value: + * none, fails the testcase + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +void unity_ramtest_verify_memory(uint32_t value, enum memory_access_width width, void *start, size_t size); + +/**************************************************************************** + * Name: unity_ramtest_write_memory2 + * + * Description: + * Writes memory with two alternating patterns + * + * Input Parameters: + * value_one - first pattern to write + * value_two - second pattern to write + * width - access width + * start - memory region starting address + * size - number of bytes allocated for the region + * + * Returned Value: + * none, fails the testcase + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +void unity_ramtest_write_memory2(uint32_t value_one, uint32_t value_two, enum memory_access_width width, void *start, size_t size); + +/**************************************************************************** + * Name: unity_ramtest_verify_memory2 + * + * Description: + * Verifies memory is filled with two alternating patterns + * + * Input Parameters: + * value_one - first pattern to expect + * value_two - second pattern to expect + * width - access width + * start - memory region starting address + * size - number of bytes allocated for the region + * + * Returned Value: + * none, fails the testcase + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +void unity_ramtest_verify_memory2(uint32_t value_one, uint32_t value_two, enum memory_access_width width, void *start, size_t size); + +/**************************************************************************** + * Name: unity_ramtest_write_addrinaddr + * + * Description: + * Writes every next memory location with the value from the previous location + * + * Input Parameters: + * width - access width + * start - memory region starting address + * size - number of bytes allocated for the region + * + * Returned Value: + * none, fails the testcase + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +void unity_ramtest_write_addrinaddr(enum memory_access_width width, void *start, size_t size); + +/**************************************************************************** + * Name: unity_ramtest_verify_addrinaddr + * + * Description: + * Verifies every memory location is filled with the value from the previous location + * + * Input Parameters: + * width - access width + * start - memory region starting address + * size - number of bytes allocated for the region + * + * Returned Value: + * none, fails the testcase + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +void unity_ramtest_verify_addrinaddr(enum memory_access_width width, void *start, size_t size); + +#endif /* __TESTS_UNITY_RAMTEST_LIBRARY_H */ diff --git a/tests/unity_ramtest/marching_ones.c b/tests/unity_ramtest/marching_ones.c new file mode 100644 index 000000000..5a77ed3f8 --- /dev/null +++ b/tests/unity_ramtest/marching_ones.c @@ -0,0 +1,191 @@ +/**************************************************************************** + * apps/tests/unity_ramtest/marching_ones.c + * Automated RAM test copied from apps/system/ramtest + * + * Copyright (C) 2015 Haltian Ltd. All rights reserved. + * Author: Roman Saveljev + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ +#include +#include "library.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ +static void* g_memory; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ +static void marching_ones(enum memory_access_width width, uint32_t mask) +{ + uint32_t pattern = 0x00000001; + + while (pattern != 0) + { + unity_ramtest_write_memory(pattern, width, g_memory, MEMORY_ALLOCATION_SIZE); + unity_ramtest_verify_memory(pattern, width, g_memory, MEMORY_ALLOCATION_SIZE); + pattern <<= 1; + pattern &= mask; + } +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +TEST_GROUP(MarchingOnes); + +/**************************************************************************** + * Name: MarchingOnes test group setup + * + * Description: + * Setup function executed before each testcase in this test group + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +TEST_SETUP(MarchingOnes) +{ + g_memory = malloc(MEMORY_ALLOCATION_SIZE); + TEST_ASSERT_NOT_NULL(g_memory); +} + +/**************************************************************************** + * Name: MarchingOnes test group tear down + * + * Description: + * Tear down function executed after each testcase in this test group + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +TEST_TEAR_DOWN(MarchingOnes) +{ + free(g_memory); + g_memory = NULL; +} + +/**************************************************************************** + * Name: ByteAccess + * + * Description: + * Running one on every memory location with byte access width + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +TEST(MarchingOnes, ByteAccess) +{ + marching_ones(MEMORY_ACCESS_BYTE, 0xff); +} + +/**************************************************************************** + * Name: HalfAccess + * + * Description: + * Running one on every memory location with half-word access width + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +TEST(MarchingOnes, HalfAccess) +{ + marching_ones(MEMORY_ACCESS_HALFWORD, 0xffff); +} + +/**************************************************************************** + * Name: WordAccess + * + * Description: + * Running one on every memory location with word access width + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +TEST(MarchingOnes, WordAccess) +{ + marching_ones(MEMORY_ACCESS_WORD, 0xffffffff); +} diff --git a/tests/unity_ramtest/marching_zeroes.c b/tests/unity_ramtest/marching_zeroes.c new file mode 100644 index 000000000..bc54be0a2 --- /dev/null +++ b/tests/unity_ramtest/marching_zeroes.c @@ -0,0 +1,193 @@ +/**************************************************************************** + * apps/tests/unity_ramtest/marching_zeroes.c + * Automated RAM test copied from apps/system/ramtest + * + * Copyright (C) 2015 Haltian Ltd. All rights reserved. + * Author: Roman Saveljev + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ +#include +#include "library.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ +static void* g_memory; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static void marching_zeroes(enum memory_access_width width, uint32_t mask) +{ + uint32_t pattern = 0xfffffffe; + + while (pattern != 0xffffffff) + { + unity_ramtest_write_memory(pattern, width, g_memory, MEMORY_ALLOCATION_SIZE); + unity_ramtest_verify_memory(pattern, width, g_memory, MEMORY_ALLOCATION_SIZE); + pattern <<= 1; + pattern |= 1; + pattern |= ~mask; + } +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +TEST_GROUP(MarchingZeroes); + +/**************************************************************************** + * Name: MarchingZeroes test group setup + * + * Description: + * Setup function executed before each testcase in this test group + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +TEST_SETUP(MarchingZeroes) +{ + g_memory = malloc(MEMORY_ALLOCATION_SIZE); + TEST_ASSERT_NOT_NULL(g_memory); +} + +/**************************************************************************** + * Name: MarchingZeroes test group tear down + * + * Description: + * Tear down function executed after each testcase in this test group + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +TEST_TEAR_DOWN(MarchingZeroes) +{ + free(g_memory); + g_memory = NULL; +} + +/**************************************************************************** + * Name: ByteAccess + * + * Description: + * Running zero on every memory location with byte access width + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +TEST(MarchingZeroes, ByteAccess) +{ + marching_zeroes(MEMORY_ACCESS_BYTE, 0xff); +} + +/**************************************************************************** + * Name: HalfAccess + * + * Description: + * Running zero on every memory location with half-word access width + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +TEST(MarchingZeroes, HalfAccess) +{ + marching_zeroes(MEMORY_ACCESS_HALFWORD, 0xffff); +} + +/**************************************************************************** + * Name: WordAccess + * + * Description: + * Running zero on every memory location with word access width + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +TEST(MarchingZeroes, WordAccess) +{ + marching_zeroes(MEMORY_ACCESS_WORD, 0xffffffff); +} diff --git a/tests/unity_ramtest/pattern.c b/tests/unity_ramtest/pattern.c new file mode 100644 index 000000000..89d2b705e --- /dev/null +++ b/tests/unity_ramtest/pattern.c @@ -0,0 +1,311 @@ +/**************************************************************************** + * apps/tests/unity_ramtest/pattern.c + * Automated RAM test copied from apps/system/ramtest + * + * Copyright (C) 2015 Haltian Ltd. All rights reserved. + * Author: Roman Saveljev + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ +#include +#include "library.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ +static void* g_memory; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static void pattern(enum memory_access_width width, uint32_t value_one, uint32_t value_two) +{ + unity_ramtest_write_memory2(value_one, value_two, width, g_memory, MEMORY_ALLOCATION_SIZE); + unity_ramtest_verify_memory2(value_one, value_two, width, g_memory, MEMORY_ALLOCATION_SIZE); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +TEST_GROUP(Pattern); + +/**************************************************************************** + * Name: Pattern test group setup + * + * Description: + * Setup function executed before each testcase in this test group + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +TEST_SETUP(Pattern) +{ + g_memory = malloc(MEMORY_ALLOCATION_SIZE); + TEST_ASSERT_NOT_NULL(g_memory); +} + +/**************************************************************************** + * Name: Pattern test group tear down + * + * Description: + * Tear down function executed after each testcase in this test group + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +TEST_TEAR_DOWN(Pattern) +{ + free(g_memory); + g_memory = NULL; +} + +/**************************************************************************** + * Name: ByteAccess_5_a + * + * Description: + * Writing pattern 0x55 and 0xaa with byte access + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +TEST(Pattern, ByteAccess_5_a) +{ + pattern(MEMORY_ACCESS_BYTE, 0x55, 0xaa); +} + +/**************************************************************************** + * Name: ByteAccess_6_9 + * + * Description: + * Writing pattern 0x66 and 0x99 with byte access + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +TEST(Pattern, ByteAccess_6_9) +{ + pattern(MEMORY_ACCESS_BYTE, 0x66, 0x99); +} + +/**************************************************************************** + * Name: ByteAccess_3_c + * + * Description: + * Writing pattern 0x33 and 0xcc with byte access + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +TEST(Pattern, ByteAccess_3_c) +{ + pattern(MEMORY_ACCESS_BYTE, 0x33, 0xcc); +} + +/**************************************************************************** + * Name: HalfAccess_5_a + * + * Description: + * Writing pattern 0x5555 and 0xaaaa with byte access + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +TEST(Pattern, HalfAccess_5_a) +{ + pattern(MEMORY_ACCESS_BYTE, 0x5555, 0xaaaa); +} + +/**************************************************************************** + * Name: HalfAccess_6_9 + * + * Description: + * Writing pattern 0x6666 and 0x9999 with byte access + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +TEST(Pattern, HalfAccess_6_9) +{ + pattern(MEMORY_ACCESS_BYTE, 0x6666, 0x9999); +} + +/**************************************************************************** + * Name: HalfAccess_3_c + * + * Description: + * Writing pattern 0x3333 and 0xcccc with byte access + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +TEST(Pattern, HalfAccess_3_c) +{ + pattern(MEMORY_ACCESS_BYTE, 0x3333, 0xcccc); +} + +/**************************************************************************** + * Name: WordAccess_5_a + * + * Description: + * Writing pattern 0x55555555 and 0xaaaaaaaa with byte access + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +TEST(Pattern, WordAccess_5_a) +{ + pattern(MEMORY_ACCESS_BYTE, 0x55555555, 0xaaaaaaaa); +} + +/**************************************************************************** + * Name: WordAccess_6_9 + * + * Description: + * Writing pattern 0x66666666 and 0x99999999 with byte access + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +TEST(Pattern, WordAccess_6_9) +{ + pattern(MEMORY_ACCESS_BYTE, 0x66666666, 0x99999999); +} + +/**************************************************************************** + * Name: WordAccess_3_c + * + * Description: + * Writing pattern 0x33333333 and 0xcccccccc with byte access + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +TEST(Pattern, WordAccess_3_c) +{ + pattern(MEMORY_ACCESS_BYTE, 0x33333333, 0xcccccccc); +} diff --git a/tests/unity_ramtest/unity_ramtest_main.c b/tests/unity_ramtest/unity_ramtest_main.c new file mode 100644 index 000000000..c86b9fba6 --- /dev/null +++ b/tests/unity_ramtest/unity_ramtest_main.c @@ -0,0 +1,503 @@ +/**************************************************************************** + * apps/tests/unity_ramtest/unity_ramtest_main.c + * Main function for Unity test application + * + * Copyright (C) 2015 Haltian Ltd. All rights reserved. + * Author: Roman Saveljev + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ +#include +#include + +#include "library.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ +static void runAllTests(void); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: runAllTests + * + * Description: + * Sequentially runs all included test groups + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +static void runAllTests(void) +{ + RUN_TEST_GROUP(MarchingZeroes); + RUN_TEST_GROUP(MarchingOnes); + RUN_TEST_GROUP(Pattern); + RUN_TEST_GROUP(AddrInAddr); +} + +/**************************************************************************** + * Name: number_of_transfers + * + * Description: + * Calculate number of transfers to cover the chunk of memory + * + * Input Parameters: + * width - access width + * size - memory size + * + * Returned Value: + * Number of transfers + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +static size_t number_of_transfers(enum memory_access_width width, size_t size) +{ + if (width == MEMORY_ACCESS_BYTE) + { + return size; + } + else if (width == MEMORY_ACCESS_WORD) + { + return size >> 2; + } + else if (width == MEMORY_ACCESS_HALFWORD) + { + return size >> 1; + } + else + { + DEBUGASSERT(0); + return 0; + } +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: unity_ramtest_write_memory + * + * Description: + * Write memory with specific pattern and access width + * + * Input Parameters: + * value - pattern to write + * width - access width + * start - memory region starting address + * size - number of bytes allocated for the region + * + * Returned Value: + * none, fails the testcase + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +void unity_ramtest_write_memory(uint32_t value, enum memory_access_width width, void *start, size_t size) +{ + size_t i, nxfrs = number_of_transfers(width, size); + + if (width == MEMORY_ACCESS_WORD) + { + uint32_t *ptr = (uint32_t*)start; + for (i = 0; i < nxfrs; i++) + { + *ptr++ = value; + } + } + else if (width == MEMORY_ACCESS_HALFWORD) + { + uint16_t *ptr = (uint16_t*)start; + for (i = 0; i < nxfrs; i++) + { + *ptr++ = (uint16_t)value; + } + } + else if (width == MEMORY_ACCESS_BYTE) + { + uint8_t *ptr = (uint8_t*)start; + for (i = 0; i < nxfrs; i++) + { + *ptr++ = (uint8_t)value; + } + } + else + { + TEST_FAIL_MESSAGE("Invalid width value"); + } +} + +/**************************************************************************** + * Name: unity_ramtest_verify_memory + * + * Description: + * Verifies memory has specific pattern and reading it with access width + * + * Input Parameters: + * value - pattern to expect + * width - access width + * start - memory region starting address + * size - number of bytes allocated for the region + * + * Returned Value: + * none, fails the testcase + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +void unity_ramtest_verify_memory(uint32_t value, enum memory_access_width width, void *start, size_t size) +{ + size_t i, nxfrs = number_of_transfers(width, size); + + if (width == MEMORY_ACCESS_WORD) + { + uint32_t *ptr = (uint32_t*)start; + for (i = 0; i < nxfrs; i++) + { + TEST_ASSERT_EQUAL_HEX32(value, *ptr); + ptr++; + } + } + else if (width == MEMORY_ACCESS_HALFWORD) + { + uint16_t value16 = (uint16_t)(value & 0x0000ffff); + uint16_t *ptr = (uint16_t*)start; + for (i = 0; i < nxfrs; i++) + { + TEST_ASSERT_EQUAL_HEX16(value16, *ptr); + ptr++; + } + } + else if (width == MEMORY_ACCESS_BYTE) + { + uint8_t value8 = (uint8_t)(value & 0x000000ff); + uint8_t *ptr = (uint8_t*)start; + for (i = 0; i < nxfrs; i++) + { + TEST_ASSERT_EQUAL_HEX(value8, *ptr); + ptr++; + } + } + else + { + TEST_FAIL_MESSAGE("Invalid width value"); + } +} + +/**************************************************************************** + * Name: unity_ramtest_write_memory2 + * + * Description: + * Writes memory with two alternating patterns + * + * Input Parameters: + * value_one - first pattern to write + * value_two - second pattern to write + * width - access width + * start - memory region starting address + * size - number of bytes allocated for the region + * + * Returned Value: + * none, fails the testcase + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +void unity_ramtest_write_memory2(uint32_t value_one, uint32_t value_two, enum memory_access_width width, void *start, size_t size) +{ + size_t even_nxfrs = number_of_transfers(width, size) & ~1; + size_t i; + + if (width == MEMORY_ACCESS_WORD) + { + uint32_t *ptr = (uint32_t*)start; + for (i = 0; i < even_nxfrs; i += 2) + { + *ptr++ = value_one; + *ptr++ = value_two; + } + } + else if (width == MEMORY_ACCESS_HALFWORD) + { + uint16_t *ptr = (uint16_t*)start; + for (i = 0; i < even_nxfrs; i += 2) + { + *ptr++ = (uint16_t)value_one; + *ptr++ = (uint16_t)value_two; + } + } + else if (width == MEMORY_ACCESS_BYTE) + { + uint8_t *ptr = (uint8_t*)start; + for (i = 0; i < even_nxfrs; i += 2) + { + *ptr++ = (uint8_t)value_one; + *ptr++ = (uint8_t)value_two; + } + } + else + { + TEST_FAIL_MESSAGE("Invalid width value"); + } +} + +/**************************************************************************** + * Name: unity_ramtest_verify_memory2 + * + * Description: + * Verifies memory is filled with two alternating patterns + * + * Input Parameters: + * value_one - first pattern to expect + * value_two - second pattern to expect + * width - access width + * start - memory region starting address + * size - number of bytes allocated for the region + * + * Returned Value: + * none, fails the testcase + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +void unity_ramtest_verify_memory2(uint32_t value_one, uint32_t value_two, enum memory_access_width width, void *start, size_t size) +{ + size_t even_nxfrs = number_of_transfers(width, size) & ~1; + size_t i; + + if (width == MEMORY_ACCESS_WORD) + { + uint32_t *ptr = (uint32_t*)start; + for (i = 0; i < even_nxfrs; i += 2) + { + TEST_ASSERT_EQUAL_HEX32(value_one, ptr[0]); + TEST_ASSERT_EQUAL_HEX32(value_two, ptr[1]); + ptr += 2; + } + } + else if (width == MEMORY_ACCESS_HALFWORD) + { + uint16_t value16_one = (uint16_t)(value_one & 0x0000ffff); + uint16_t value16_two = (uint16_t)(value_two & 0x0000ffff); + uint16_t *ptr = (uint16_t*)start; + for (i = 0; i < even_nxfrs; i += 2) + { + TEST_ASSERT_EQUAL_HEX16(value16_one, ptr[0]); + TEST_ASSERT_EQUAL_HEX16(value16_two, ptr[1]); + ptr += 2; + } + } + else if (width == MEMORY_ACCESS_BYTE) + { + uint8_t value8_one = (uint8_t)(value_one & 0x000000ff); + uint8_t value8_two = (uint8_t)(value_two & 0x000000ff); + uint8_t *ptr = (uint8_t*)start; + for (i = 0; i < even_nxfrs; i += 2) + { + TEST_ASSERT_EQUAL_HEX(value8_one, ptr[0]); + TEST_ASSERT_EQUAL_HEX(value8_two, ptr[1]); + ptr += 2; + } + } + else + { + TEST_FAIL_MESSAGE("Invalid width value"); + } +} + +/**************************************************************************** + * Name: unity_ramtest_write_addrinaddr + * + * Description: + * Writes every next memory location with the value from the previous location + * + * Input Parameters: + * width - access width + * start - memory region starting address + * size - number of bytes allocated for the region + * + * Returned Value: + * none, fails the testcase + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +void unity_ramtest_write_addrinaddr(enum memory_access_width width, void *start, size_t size) +{ + size_t i, nxfrs = number_of_transfers(width, size); + + if (width == MEMORY_ACCESS_WORD) + { + uint32_t *ptr = (uint32_t*)start; + for (i = 0; i < nxfrs; i++) + { + uint32_t value32 = (uint32_t)((uintptr_t)ptr); + *ptr++ = value32; + } + } + else if (width == MEMORY_ACCESS_HALFWORD) + { + uint16_t *ptr = (uint16_t*)start; + for (i = 0; i < nxfrs; i++) + { + uint16_t value16 = (uint16_t)((uintptr_t)ptr & 0x0000ffff); + *ptr++ = value16; + } + } + else if (width == MEMORY_ACCESS_BYTE) + { + uint8_t *ptr = (uint8_t*)start; + for (i = 0; i < nxfrs; i++) + { + uint8_t value8 = (uint8_t)((uintptr_t)ptr & 0x000000ff); + *ptr++ = value8; + } + } + else + { + TEST_FAIL_MESSAGE("Invalid width value"); + } +} + +/**************************************************************************** + * Name: unity_ramtest_verify_addrinaddr + * + * Description: + * Verifies every memory location is filled with the value from the previous location + * + * Input Parameters: + * width - access width + * start - memory region starting address + * size - number of bytes allocated for the region + * + * Returned Value: + * none, fails the testcase + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +void unity_ramtest_verify_addrinaddr(enum memory_access_width width, void *start, size_t size) +{ + size_t i, nxfrs = number_of_transfers(width, size); + + if (width == MEMORY_ACCESS_WORD) + { + uint32_t *ptr = (uint32_t*)start; + for (i = 0; i < nxfrs; i++) + { + uint32_t value32 = (uint32_t)((uintptr_t)ptr); + TEST_ASSERT_EQUAL_HEX32(*ptr, value32); + ptr++; + } + } + else if (width == MEMORY_ACCESS_HALFWORD) + { + uint16_t *ptr = (uint16_t*)start; + for (i = 0; i < nxfrs; i++) + { + uint16_t value16 = (uint16_t)((uintptr_t)ptr & 0x0000ffff); + TEST_ASSERT_EQUAL_HEX16(*ptr, value16); + ptr++; + } + } + else if (width == MEMORY_ACCESS_BYTE) + { + uint8_t *ptr = (uint8_t*)start; + for (i = 0; i < nxfrs; i++) + { + uint16_t value8 = (uint8_t)((uintptr_t)ptr & 0x000000ff); + TEST_ASSERT_EQUAL_HEX(*ptr, value8); + ptr++; + } + } + else + { + TEST_FAIL_MESSAGE("Invalid width value"); + } +} + +/**************************************************************************** + * Name: unity_ramtest_main + * + * Description: + * Application entry point + * + * Input Parameters: + * argc - number of arguments + * argv - arguments themselves + * + * Returned Value: + * exit status + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +int unity_ramtest_main(int argc, const char* argv[]) +{ + return UnityMain(argc, argv, runAllTests); +} diff --git a/tests/unity_usrsock/.gitignore b/tests/unity_usrsock/.gitignore new file mode 100644 index 000000000..fa1ec7579 --- /dev/null +++ b/tests/unity_usrsock/.gitignore @@ -0,0 +1,11 @@ +/Make.dep +/.depend +/.built +/*.asm +/*.obj +/*.rel +/*.lst +/*.sym +/*.adb +/*.lib +/*.src diff --git a/tests/unity_usrsock/Kconfig b/tests/unity_usrsock/Kconfig new file mode 100644 index 000000000..870afe96a --- /dev/null +++ b/tests/unity_usrsock/Kconfig @@ -0,0 +1,15 @@ +# +# For a description of the syntax of this configuration file, +# see misc/tools/kconfig-language.txt. +# + +config TESTS_UNITY_USRSOCK + bool "User-space networking stack API Unity tests" + default n + depends on NET + depends on NET_USRSOCK + depends on !DISABLE_POLL + select PIPES + ---help--- + Enable user-space networking stack API Unity tests + diff --git a/tests/unity_usrsock/Make.defs b/tests/unity_usrsock/Make.defs new file mode 100644 index 000000000..2f6460562 --- /dev/null +++ b/tests/unity_usrsock/Make.defs @@ -0,0 +1,39 @@ +############################################################################ +# apps/tests/unity_usrsock/Make.defs +# Adds selected testing applications to apps/ build +# +# Copyright (C) 2015 Haltian Ltd. All rights reserved. +# Author: Roman Saveljev +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +ifeq ($(CONFIG_TESTS_UNITY_USRSOCK),y) +CONFIGURED_APPS += tests/unity_usrsock +endif diff --git a/tests/unity_usrsock/Makefile b/tests/unity_usrsock/Makefile new file mode 100644 index 000000000..b856fbfd2 --- /dev/null +++ b/tests/unity_usrsock/Makefile @@ -0,0 +1,152 @@ +############################################################################ +# apps/examples/unity_usrsock/Makefile +# +# Copyright (C) 2015 Haltian Ltd. All rights reserved. +# Author: Roman Saveljev +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name NuttX nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +-include $(TOPDIR)/.config +-include $(TOPDIR)/Make.defs +include $(APPDIR)/Make.defs + +APPNAME = unity_usrsock +PRIORITY = SCHED_PRIORITY_DEFAULT +STACKSIZE = 2048 + +ARCH_SRCDIR = $(TOPDIR)/arch/$(CONFIG_ARCH)/src +CFLAGS += -x c + +ASRCS = +RUNNERSRC = unity_usrsock_runner.src +TESTSRCS = chardev.c nodaemon.c basic_daemon.c basic_connect.c \ + noblock_connect.c basic_send.c noblock_send.c block_send.c \ + noblock_recv.c block_recv.c poll.c remote_disconnect.c \ + basic_setsockopt.c basic_getsockopt.c basic_getsockname.c \ + multi_thread.c wake_with_signal.c + +CSRCS = $(TESTSRCS) usrsocktest_daemon.c +MAINSRC = unity_usrsock_main.c + +RUNNEROBJ = $(RUNNERSRC:.src=$(OBJEXT)) +AOBJS = $(ASRCS:.S=$(OBJEXT)) +COBJS = $(CSRCS:.c=$(OBJEXT)) +MAINOBJ = $(MAINSRC:.c=$(OBJEXT)) + +SRCS = $(ASRCS) $(CSRCS) $(MAINSRC) $(RUNNERSRC) +OBJS = $(AOBJS) $(COBJS) $(RUNNEROBJ) + +PROGNAME = unity_usrsock$(EXEEXT) + +ifneq ($(CONFIG_BUILD_KERNEL),y) + OBJS += $(MAINOBJ) +endif + +ifeq ($(CONFIG_WINDOWS_NATIVE),y) + BIN = ..\..\libapps$(LIBEXT) +else +ifeq ($(WINTOOL),y) + BIN = ..\\..\\libapps$(LIBEXT) +else + BIN = ../../libapps$(LIBEXT) +endif +endif + +ifeq ($(WINTOOL),y) + INSTALL_DIR = "${shell cygpath -w $(BIN_DIR)}" +else + INSTALL_DIR = $(BIN_DIR) +endif + +ROOTDEPPATH = --dep-path . + +# Common build + +VPATH = + +all: .built +.PHONY: clean depend distclean + +$(RUNNERSRC) : $(TESTSRCS) + $(Q) CPP="$(CPP)" $(APPDIR)/tests/tools/build_fixture_runner.pl $^ >$@ + +$(AOBJS): %$(OBJEXT): %.S + $(call ASSEMBLE, $<, $@) + +$(RUNNEROBJ): $(RUNNERSRC) + $(call COMPILE, $<, $@) + $(Q) OBJCOPY=$(OBJCOPY) $(APPDIR)/tests/tools/rename_symbols $(APPNAME) $@ + +$(COBJS) $(MAINOBJ): %$(OBJEXT): %.c + $(call COMPILE, $<, $@) + $(Q) OBJCOPY=$(OBJCOPY) $(APPDIR)/tests/tools/rename_symbols $(APPNAME) $@ + +.built: $(OBJS) + $(call ARCHIVE, $(BIN), $(OBJS)) + @touch .built + +ifeq ($(CONFIG_BUILD_KERNEL),y) +$(BIN_DIR)$(DELIM)$(PROGNAME): $(OBJS) $(MAINOBJ) + @echo "LD: $(PROGNAME)" + $(Q) $(LD) $(LDELFFLAGS) $(LDLIBPATH) -o $(INSTALL_DIR)$(DELIM)$(PROGNAME) $(ARCHCRT0OBJ) $(MAINOBJ) $(LDLIBS) + $(Q) $(NM) -u $(INSTALL_DIR)$(DELIM)$(PROGNAME) + +install: $(BIN_DIR)$(DELIM)$(PROGNAME) + +else +install: + +endif + +ifeq ($(CONFIG_NSH_BUILTIN_APPS),y) +$(BUILTIN_REGISTRY)$(DELIM)$(APPNAME)_main.bdat: $(DEPCONFIG) Makefile + $(call REGISTER,$(APPNAME),$(PRIORITY),$(STACKSIZE),$(APPNAME)_main) + +context: $(BUILTIN_REGISTRY)$(DELIM)$(APPNAME)_main.bdat +else +context: +endif + +.depend: Makefile $(SRCS) + @$(MKDEP) $(ROOTDEPPATH) "$(CC)" -- $(CFLAGS) -- $(SRCS) >Make.dep + @touch $@ + +depend: .depend + +clean: + $(call DELFILE, .built) + $(call DELFILE, test_runner.src) + $(call CLEAN) + +distclean: clean + $(call DELFILE, Make.dep) + $(call DELFILE, .depend) + +-include Make.dep diff --git a/tests/unity_usrsock/basic_connect.c b/tests/unity_usrsock/basic_connect.c new file mode 100644 index 000000000..5269b3337 --- /dev/null +++ b/tests/unity_usrsock/basic_connect.c @@ -0,0 +1,465 @@ +/**************************************************************************** + * apps/examples/unity_usrsock/basic_connect.c + * Basic connect tests with socket daemon + * + * Copyright (C) 2015 Haltian Ltd. All rights reserved. + * Authors: Roman Saveljev + * Jussi Kivilinna + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "defines.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ +static bool started; +static int sd; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: Setup + * + * Description: + * Run before every testcase + * + * Input Parameters: + * dconf - test daemon configuration + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +static void Setup(struct usrsocktest_daemon_conf_s *dconf) +{ + dconf->endpoint_addr = "127.0.0.1"; + dconf->endpoint_port = 255; + TEST_ASSERT_EQUAL(OK, usrsocktest_daemon_start(dconf)); + started = true; + + sd = socket(AF_INET, SOCK_STREAM, 0); + TEST_ASSERT_TRUE(sd >= 0); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); +} + +/**************************************************************************** + * Name: Teardown + * + * Description: + * Run after every testcase + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +static void Teardown(void) +{ + int ret; + + if (sd >= 0) + { + ret = close(sd); + assert(ret >= 0); + } + + if (started) + { + ret = usrsocktest_daemon_stop(); + assert(ret == OK); + } +} + +/**************************************************************************** + * Name: NotConnected + * + * Description: + * Opened socket is not connected + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +static void NotConnected(void) +{ + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); +} + +/**************************************************************************** + * Name: Connect + * + * Description: + * Open and connect the socket + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +static void Connect(void) +{ + int ret; + struct sockaddr_in addr; + + inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr.s_addr); + addr.sin_family = AF_INET; + addr.sin_port = htons(255); + ret = connect(sd, (FAR const struct sockaddr *)&addr, sizeof(addr)); + TEST_ASSERT_EQUAL(0, ret); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_connected_sockets()); + + /* Attempt reconnect to same address */ + + inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr.s_addr); + addr.sin_family = AF_INET; + addr.sin_port = htons(255); + ret = connect(sd, (FAR const struct sockaddr *)&addr, sizeof(addr)); + TEST_ASSERT_EQUAL(-1, ret); + TEST_ASSERT_EQUAL(EISCONN, errno); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + + /* Attempt reconnect to different address */ + + inet_pton(AF_INET, "1.1.1.1", &addr.sin_addr.s_addr); + addr.sin_family = AF_INET; + addr.sin_port = htons(1); + ret = connect(sd, (FAR const struct sockaddr *)&addr, sizeof(addr)); + TEST_ASSERT_EQUAL(-1, ret); + TEST_ASSERT_EQUAL(EISCONN, errno); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + + /* Close socket */ + + TEST_ASSERT_TRUE(close(sd) >= 0); + sd = -1; + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + + /* Stopping daemon should succeed. */ + + TEST_ASSERT_EQUAL(OK, usrsocktest_daemon_stop()); + started = false; + TEST_ASSERT_EQUAL(-ENODEV, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(-ENODEV, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_endp_malloc_cnt); + TEST_ASSERT_EQUAL(0, usrsocktest_dcmd_malloc_cnt); +} + +/**************************************************************************** + * Name: WrongAF + * + * Description: + * Open and connect the socket with wrong AF + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +static void WrongAF(void) +{ + int ret; + struct sockaddr_in addr; + + /* Try connect socket with wrong AF */ + + inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr.s_addr); + addr.sin_family = AF_UNIX; + addr.sin_port = htons(255); + ret = connect(sd, (FAR const struct sockaddr *)&addr, sizeof(addr)); + TEST_ASSERT_EQUAL(-1, ret); + TEST_ASSERT_EQUAL(EAFNOSUPPORT, errno); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + + /* Close socket */ + + TEST_ASSERT_TRUE(close(sd) >= 0); + sd = -1; + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + + /* Stopping daemon should succeed. */ + + TEST_ASSERT_EQUAL(OK, usrsocktest_daemon_stop()); + started = false; + TEST_ASSERT_EQUAL(-ENODEV, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(-ENODEV, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_endp_malloc_cnt); + TEST_ASSERT_EQUAL(0, usrsocktest_dcmd_malloc_cnt); +} + +/**************************************************************************** + * Name: WrongPort + * + * Description: + * Open and connect the socket with wrong port + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +static void WrongPort(void) +{ + int ret; + struct sockaddr_in addr; + + /* Try connect socket to wrong port */ + + inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr.s_addr); + addr.sin_family = AF_INET; + addr.sin_port = htons(127); + ret = connect(sd, (FAR const struct sockaddr *)&addr, sizeof(addr)); + TEST_ASSERT_EQUAL(-1, ret); + TEST_ASSERT_EQUAL(ECONNREFUSED, errno); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + + /* Close socket */ + + TEST_ASSERT_TRUE(close(sd) >= 0); + sd = -1; + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + + /* Stopping daemon should succeed. */ + + TEST_ASSERT_EQUAL(OK, usrsocktest_daemon_stop()); + started = false; + TEST_ASSERT_EQUAL(-ENODEV, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(-ENODEV, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_endp_malloc_cnt); + TEST_ASSERT_EQUAL(0, usrsocktest_dcmd_malloc_cnt); +} + +/**************************************************************************** + * Name: WrongEndpoint + * + * Description: + * Open and connect the socket with wrong endpoint + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +static void WrongEndpoint(void) +{ + int ret; + struct sockaddr_in addr; + + /* Try connect socket to unreachable endpoint */ + + inet_pton(AF_INET, "1.1.1.1", &addr.sin_addr.s_addr); + addr.sin_family = AF_INET; + addr.sin_port = htons(1); + ret = connect(sd, (FAR const struct sockaddr *)&addr, sizeof(addr)); + TEST_ASSERT_EQUAL(-1, ret); + TEST_ASSERT_EQUAL(ENETUNREACH, errno); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + + /* Connect */ + + inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr.s_addr); + addr.sin_family = AF_INET; + addr.sin_port = htons(255); + ret = connect(sd, (FAR const struct sockaddr *)&addr, sizeof(addr)); + TEST_ASSERT_EQUAL(0, ret); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + + /* Close socket */ + + TEST_ASSERT_TRUE(close(sd) >= 0); + sd = -1; + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + + /* Stopping daemon should succeed. */ + + TEST_ASSERT_EQUAL(OK, usrsocktest_daemon_stop()); + started = false; + TEST_ASSERT_EQUAL(-ENODEV, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(-ENODEV, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_endp_malloc_cnt); + TEST_ASSERT_EQUAL(0, usrsocktest_dcmd_malloc_cnt); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +TEST_GROUP(BasicConnect); + +TEST_SETUP(BasicConnect) +{ + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + Setup(&usrsocktest_daemon_config); +} + +TEST_TEAR_DOWN(BasicConnect) +{ + Teardown(); +} + +TEST(BasicConnect, NotConnected) +{ + NotConnected(); +} + +TEST(BasicConnect, Connect) +{ + Connect(); +} + +TEST(BasicConnect, WrongAF) +{ + WrongAF(); +} + +TEST(BasicConnect, WrongPort) +{ + WrongPort(); +} + +TEST(BasicConnect, WrongEndpoint) +{ + WrongEndpoint(); +} + +TEST_GROUP(BasicConnectDelay); + +TEST_SETUP(BasicConnectDelay) +{ + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + usrsocktest_daemon_config.delay_all_responses = true; + Setup(&usrsocktest_daemon_config); +} + +TEST_TEAR_DOWN(BasicConnectDelay) +{ + Teardown(); +} + +TEST(BasicConnectDelay, NotConnected) +{ + NotConnected(); +} + +TEST(BasicConnectDelay, Connect) +{ + Connect(); +} + +TEST(BasicConnectDelay, WrongAF) +{ + WrongAF(); +} + +TEST(BasicConnectDelay, WrongPort) +{ + WrongPort(); +} + +TEST(BasicConnectDelay, WrongEndpoint) +{ + WrongEndpoint(); +} diff --git a/tests/unity_usrsock/basic_daemon.c b/tests/unity_usrsock/basic_daemon.c new file mode 100644 index 000000000..929f88aec --- /dev/null +++ b/tests/unity_usrsock/basic_daemon.c @@ -0,0 +1,653 @@ +/**************************************************************************** + * apps/examples/unity_usrsock/basic_daemon.c + * Basic tests with socket daemon + * + * Copyright (C) 2015 Haltian Ltd. All rights reserved. + * Authors: Roman Saveljev + * Jussi Kivilinna + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "defines.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ +static bool started; +static int sd, sd2, sd3; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: NoActiveSockets + * + * Description: + * Checks there is no active sockets on daemon startup + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +static void NoActiveSockets(struct usrsocktest_daemon_conf_s *dconf) +{ + TEST_ASSERT_EQUAL(OK, usrsocktest_daemon_start(dconf)); + started = true; + + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_active_sockets()); +} + +/**************************************************************************** + * Name: OpenClose + * + * Description: + * Open and close AF_INET socket, check active socket counter updates + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +static void OpenClose(struct usrsocktest_daemon_conf_s *dconf) +{ + TEST_ASSERT_EQUAL(OK, usrsocktest_daemon_start(dconf)); + started = true; + + sd = socket(AF_INET, SOCK_STREAM, 0); + TEST_ASSERT_TRUE(sd >= 0); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + + TEST_ASSERT_TRUE(close(sd) >= 0); + sd = -1; + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_active_sockets()); + + TEST_ASSERT_EQUAL(OK, usrsocktest_daemon_stop()); + started = false; + TEST_ASSERT_EQUAL(0, usrsocktest_endp_malloc_cnt); + TEST_ASSERT_EQUAL(0, usrsocktest_dcmd_malloc_cnt); +} + +/**************************************************************************** + * Name: UnsupportedType + * + * Description: + * Try open socket for unsupported type + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +static void UnsupportedType(struct usrsocktest_daemon_conf_s *dconf) +{ + TEST_ASSERT_EQUAL(OK, usrsocktest_daemon_start(dconf)); + started = true; + + sd = socket(AF_INET, SOCK_RDM, 0); + TEST_ASSERT_TRUE(sd < 0); + TEST_ASSERT_EQUAL(EPROTONOSUPPORT, errno); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_active_sockets()); + + TEST_ASSERT_EQUAL(OK, usrsocktest_daemon_stop()); + started = false; + TEST_ASSERT_EQUAL(0, usrsocktest_endp_malloc_cnt); + TEST_ASSERT_EQUAL(0, usrsocktest_dcmd_malloc_cnt); +} + +/**************************************************************************** + * Name: UnsupportedProto + * + * Description: + * Try open socket for unsupported protocol + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +static void UnsupportedProto(struct usrsocktest_daemon_conf_s *dconf) +{ + TEST_ASSERT_EQUAL(OK, usrsocktest_daemon_start(dconf)); + started = true; + + sd = socket(AF_INET, SOCK_STREAM, 1); + TEST_ASSERT_TRUE(sd < 0); + TEST_ASSERT_EQUAL(EPROTONOSUPPORT, errno); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_active_sockets()); + + TEST_ASSERT_EQUAL(OK, usrsocktest_daemon_stop()); + started = false; + TEST_ASSERT_EQUAL(0, usrsocktest_endp_malloc_cnt); + TEST_ASSERT_EQUAL(0, usrsocktest_dcmd_malloc_cnt); +} + +/**************************************************************************** + * Name: OpenThree + * + * Description: + * Open multiple sockets + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +static void OpenThree(struct usrsocktest_daemon_conf_s *dconf) +{ + int ret; + + dconf->max_sockets = 3; + TEST_ASSERT_EQUAL(OK, usrsocktest_daemon_start(dconf)); + started = true; + + sd = socket(AF_INET, SOCK_STREAM, 0); + TEST_ASSERT_TRUE(sd >= 0); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + sd2 = socket(AF_INET, SOCK_STREAM, 0); + TEST_ASSERT_TRUE(sd2 >= 0); + TEST_ASSERT_EQUAL(2, usrsocktest_daemon_get_num_active_sockets()); + sd3 = socket(AF_INET, SOCK_STREAM, 0); + TEST_ASSERT_TRUE(sd3 >= 0); + TEST_ASSERT_EQUAL(3, usrsocktest_daemon_get_num_active_sockets()); + ret = socket(AF_INET, SOCK_STREAM, 0); + TEST_ASSERT_FALSE(ret >= 0); + TEST_ASSERT_EQUAL(3, usrsocktest_daemon_get_num_active_sockets()); + + ret = close(sd2); + TEST_ASSERT_EQUAL(0, ret); + sd2 = -1; + TEST_ASSERT_EQUAL(2, usrsocktest_daemon_get_num_active_sockets()); + ret = close(sd); + TEST_ASSERT_EQUAL(0, ret); + sd = -1; + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + ret = close(sd3); + TEST_ASSERT_EQUAL(0, ret); + sd3 = -1; + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_active_sockets()); + + TEST_ASSERT_EQUAL(OK, usrsocktest_daemon_stop()); + started = false; + TEST_ASSERT_EQUAL(0, usrsocktest_endp_malloc_cnt); + TEST_ASSERT_EQUAL(0, usrsocktest_dcmd_malloc_cnt); +} + +/**************************************************************************** + * Name: Dup + * + * Description: + * Dup opened socket + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +static void Dup(struct usrsocktest_daemon_conf_s *dconf) +{ + int ret; + + TEST_ASSERT_EQUAL(OK, usrsocktest_daemon_start(dconf)); + started = true; + + sd = socket(AF_INET, SOCK_STREAM, 0); + TEST_ASSERT_TRUE(sd >= 0); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + + sd2 = dup(sd); + TEST_ASSERT_TRUE(sd2 >= 0); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + + sd3 = dup(sd); + TEST_ASSERT_TRUE(sd3 >= 0); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + + ret = close(sd2); + TEST_ASSERT_EQUAL(0, ret); + sd2 = -1; + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + ret = close(sd); + TEST_ASSERT_EQUAL(0, ret); + sd = -1; + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + ret = close(sd3); + TEST_ASSERT_EQUAL(0, ret); + sd3 = -1; + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_active_sockets()); + + TEST_ASSERT_EQUAL(OK, usrsocktest_daemon_stop()); + started = false; + TEST_ASSERT_EQUAL(0, usrsocktest_endp_malloc_cnt); + TEST_ASSERT_EQUAL(0, usrsocktest_dcmd_malloc_cnt); +} + +/**************************************************************************** + * Name: Dup2 + * + * Description: + * Clone opened socket with dup2 + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +static void Dup2(struct usrsocktest_daemon_conf_s *dconf) +{ + int ret; + + TEST_ASSERT_EQUAL(OK, usrsocktest_daemon_start(dconf)); + started = true; + + sd = socket(AF_INET, SOCK_STREAM, 0); + TEST_ASSERT_TRUE(sd >= 0); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + sd2 = socket(AF_INET, SOCK_STREAM, 0); + TEST_ASSERT_TRUE(sd >= 0); + TEST_ASSERT_EQUAL(2, usrsocktest_daemon_get_num_active_sockets()); + + ret = dup2(sd2, sd); + TEST_ASSERT_EQUAL(0, ret); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + + ret = close(sd2); + TEST_ASSERT_EQUAL(0, ret); + sd2 = -1; + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + ret = close(sd); + TEST_ASSERT_EQUAL(0, ret); + sd = -1; + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_active_sockets()); + + TEST_ASSERT_EQUAL(OK, usrsocktest_daemon_stop()); + started = false; + TEST_ASSERT_EQUAL(0, usrsocktest_endp_malloc_cnt); + TEST_ASSERT_EQUAL(0, usrsocktest_dcmd_malloc_cnt); +} + +/**************************************************************************** + * Name: Stops + * + * Description: + * Daemon stops unexpectedly + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +static void Stops(struct usrsocktest_daemon_conf_s *dconf) +{ + int ret; + + TEST_ASSERT_EQUAL(OK, usrsocktest_daemon_start(dconf)); + started = true; + + sd = socket(AF_INET, SOCK_STREAM, 0); + TEST_ASSERT_TRUE(sd >= 0); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + sd2 = socket(AF_INET, SOCK_STREAM, 0); + TEST_ASSERT_TRUE(sd2 >= 0); + TEST_ASSERT_EQUAL(2, usrsocktest_daemon_get_num_active_sockets()); + + ret = usrsocktest_daemon_stop(); + TEST_ASSERT_EQUAL(OK, ret); + started = false; + TEST_ASSERT_EQUAL(-ENODEV, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_endp_malloc_cnt); + TEST_ASSERT_EQUAL(0, usrsocktest_dcmd_malloc_cnt); + + + TEST_ASSERT_EQUAL(0, close(sd)); + sd = -1; + TEST_ASSERT_EQUAL(0, close(sd2)); + sd2 = -1; +} + +/**************************************************************************** + * Name: StopsStarts + * + * Description: + * Daemon stops and restarts unexpectedly + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +static void StopsStarts(struct usrsocktest_daemon_conf_s *dconf) +{ + int ret; + struct sockaddr_in addr; + + TEST_ASSERT_EQUAL(OK, usrsocktest_daemon_start(dconf)); + started = true; + + sd = socket(AF_INET, SOCK_STREAM, 0); + TEST_ASSERT_TRUE(sd >= 0); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + sd2 = socket(AF_INET, SOCK_STREAM, 0); + TEST_ASSERT_TRUE(sd2 >= 0); + TEST_ASSERT_EQUAL(2, usrsocktest_daemon_get_num_active_sockets()); + + TEST_ASSERT_EQUAL(OK, usrsocktest_daemon_stop()); + started = false; + TEST_ASSERT_EQUAL(-ENODEV, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_endp_malloc_cnt); + TEST_ASSERT_EQUAL(0, usrsocktest_dcmd_malloc_cnt); + + TEST_ASSERT_EQUAL(OK, usrsocktest_daemon_start(dconf)); + started = true; + + inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr.s_addr); + addr.sin_family = AF_INET; + addr.sin_port = 255; + ret = connect(sd, (FAR const struct sockaddr *)&addr, sizeof(addr)); + TEST_ASSERT_EQUAL(-1, ret); + TEST_ASSERT_EQUAL(EPIPE, errno); + + ret = connect(sd2, (FAR const struct sockaddr *)&addr, sizeof(addr)); + TEST_ASSERT_EQUAL(-1, ret); + TEST_ASSERT_EQUAL(EPIPE, errno); + + TEST_ASSERT_EQUAL(0, close(sd)); + sd = -1; + TEST_ASSERT_EQUAL(0, close(sd2)); + sd2 = -1; + + TEST_ASSERT_EQUAL(OK, usrsocktest_daemon_stop()); + started = false; + TEST_ASSERT_EQUAL(0, usrsocktest_endp_malloc_cnt); + TEST_ASSERT_EQUAL(0, usrsocktest_dcmd_malloc_cnt); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +TEST_GROUP(BasicDaemon); + +/**************************************************************************** + * Name: BasicDaemon test group setup + * + * Description: + * Setup function executed before each testcase in this test group + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +TEST_SETUP(BasicDaemon) +{ + sd = -1; + sd2 = -1; + sd3 = -1; + started = false; +} + +/**************************************************************************** + * Name: BasicDaemon test group teardown + * + * Description: + * Setup function executed after each testcase in this test group + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +TEST_TEAR_DOWN(BasicDaemon) +{ + int ret; + if (sd >= 0) + { + ret = close(sd); + assert(ret >= 0); + } + if (sd2 >= 0) + { + ret = close(sd2); + assert(ret >= 0); + } + if (sd3 >= 0) + { + ret = close(sd3); + assert(ret >= 0); + } + if (started) + { + ret = usrsocktest_daemon_stop(); + assert(ret == OK); + } +} + +TEST(BasicDaemon, NoActiveSockets) +{ + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + NoActiveSockets(&usrsocktest_daemon_config); +} + +TEST(BasicDaemon, NoActiveSocketsDelay) +{ + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + usrsocktest_daemon_config.delay_all_responses = true; + NoActiveSockets(&usrsocktest_daemon_config); +} + +TEST(BasicDaemon, OpenClose) +{ + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + OpenClose(&usrsocktest_daemon_config); +} + +TEST(BasicDaemon, OpenCloseDelay) +{ + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + usrsocktest_daemon_config.delay_all_responses = true; + OpenClose(&usrsocktest_daemon_config); +} + +TEST(BasicDaemon, UnsupportedType) +{ + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + UnsupportedType(&usrsocktest_daemon_config); +} + +TEST(BasicDaemon, UnsupportedTypeDelay) +{ + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + usrsocktest_daemon_config.delay_all_responses = true; + UnsupportedType(&usrsocktest_daemon_config); +} + +TEST(BasicDaemon, UnsupportedProto) +{ + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + UnsupportedProto(&usrsocktest_daemon_config); +} + +TEST(BasicDaemon, UnsupportedProtoDelay) +{ + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + usrsocktest_daemon_config.delay_all_responses = true; + UnsupportedProto(&usrsocktest_daemon_config); +} + +TEST(BasicDaemon, OpenThree) +{ + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + OpenThree(&usrsocktest_daemon_config); +} + +TEST(BasicDaemon, OpenThreeDelay) +{ + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + usrsocktest_daemon_config.delay_all_responses = true; + OpenThree(&usrsocktest_daemon_config); +} + +TEST(BasicDaemon, Dup) +{ + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + Dup(&usrsocktest_daemon_config); +} + +TEST(BasicDaemon, DupDelay) +{ + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + usrsocktest_daemon_config.delay_all_responses = true; + Dup(&usrsocktest_daemon_config); +} + +TEST(BasicDaemon, Dup2) +{ + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + Dup2(&usrsocktest_daemon_config); +} + +TEST(BasicDaemon, Dup2Delay) +{ + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + usrsocktest_daemon_config.delay_all_responses = true; + Dup2(&usrsocktest_daemon_config); +} + +TEST(BasicDaemon, Stops) +{ + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + Stops(&usrsocktest_daemon_config); +} + +TEST(BasicDaemon, StopsDelay) +{ + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + usrsocktest_daemon_config.delay_all_responses = true; + Stops(&usrsocktest_daemon_config); +} + +TEST(BasicDaemon, StopsStarts) +{ + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + StopsStarts(&usrsocktest_daemon_config); +} + +TEST(BasicDaemon, StopsStartsDelay) +{ + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + usrsocktest_daemon_config.delay_all_responses = true; + StopsStarts(&usrsocktest_daemon_config); +} diff --git a/tests/unity_usrsock/basic_getsockname.c b/tests/unity_usrsock/basic_getsockname.c new file mode 100644 index 000000000..72f7e07ca --- /dev/null +++ b/tests/unity_usrsock/basic_getsockname.c @@ -0,0 +1,279 @@ +/**************************************************************************** + * apps/examples/unity_usrsock/basic_getsockname.c + * Basic getsockname tests + * + * Copyright (C) 2015 Haltian Ltd. All rights reserved. + * Authors: Roman Saveljev + * Jussi Kivilinna + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "defines.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ +static bool started; +static int sd; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: Open + * + * Description: + * Open and get socket options + * + * Input Parameters: + * dconf - socket daemon configuration + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +static void Open(struct usrsocktest_daemon_conf_s *dconf) +{ + int ret; + socklen_t addrlen; + union { + struct sockaddr_storage storage; + struct sockaddr_in in; + } addr; + + /* Start test daemon. */ + + dconf->endpoint_addr = "127.0.0.1"; + dconf->endpoint_port = 255; + TEST_ASSERT_EQUAL(OK, usrsocktest_daemon_start(dconf)); + started = true; + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_active_sockets()); + + /* Open socket */ + + sd = socket(AF_INET, SOCK_STREAM, 0); + TEST_ASSERT_TRUE(sd >= 0); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + + /* Get socket name */ + + memset(&addr, 0xff, sizeof(addr)); + addrlen = sizeof(addr.in); + ret = getsockname(sd, (FAR void *)&addr.in, &addrlen); + TEST_ASSERT_EQUAL(0, ret); + TEST_ASSERT_EQUAL(sizeof(addr.in), addrlen); + TEST_ASSERT_EQUAL(AF_INET, addr.in.sin_family); + TEST_ASSERT_EQUAL(htons(12345), addr.in.sin_port); + TEST_ASSERT_EQUAL(htonl(0x7f000001), addr.in.sin_addr.s_addr); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + + /* Get socket name, short buffer */ + + memset(&addr, 0xff, sizeof(addr)); + addrlen = 1; + ret = getsockname(sd, (FAR void *)&addr.in, &addrlen); + TEST_ASSERT_EQUAL(0, ret); + TEST_ASSERT_EQUAL(sizeof(addr.in), addrlen); + TEST_ASSERT_EQUAL(AF_INET, ((FAR uint8_t *)&addr.in.sin_family)[0]); + TEST_ASSERT_EQUAL(0xff, ((FAR uint8_t *)&addr.in.sin_family)[1]); + TEST_ASSERT_EQUAL(htons(0xffff), addr.in.sin_port); + TEST_ASSERT_EQUAL(htonl(0xffffffff), addr.in.sin_addr.s_addr); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + + /* Get socket name, larger buffer */ + + memset(&addr, 0xff, sizeof(addr)); + addrlen = sizeof(addr.storage); + ret = getsockname(sd, (FAR void *)&addr.in, &addrlen); + TEST_ASSERT_EQUAL(0, ret); + TEST_ASSERT_EQUAL(sizeof(addr.in), addrlen); + TEST_ASSERT_EQUAL(AF_INET, addr.in.sin_family); + TEST_ASSERT_EQUAL(htons(12345), addr.in.sin_port); + TEST_ASSERT_EQUAL(htonl(0x7f000001), addr.in.sin_addr.s_addr); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + + /* Get socket name, NULL addr */ + + memset(&addr, 0xff, sizeof(addr)); + addrlen = sizeof(addr.in); + ret = getsockname(sd, NULL, &addrlen); + TEST_ASSERT_EQUAL(-1, ret); + TEST_ASSERT_EQUAL(EINVAL, errno); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + + /* Get socket name, NULL addrlen */ + + memset(&addr, 0xff, sizeof(addr)); + addrlen = sizeof(addr.in); + ret = getsockname(sd, (FAR void *)&addr.in, NULL); + TEST_ASSERT_EQUAL(-1, ret); + TEST_ASSERT_EQUAL(EINVAL, errno); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + + /* Get socket name, zero length buffer */ + + memset(&addr, 0xff, sizeof(addr)); + addrlen = 0; + ret = getsockname(sd, (FAR void *)&addr.in, &addrlen); + TEST_ASSERT_EQUAL(0, ret); + TEST_ASSERT_EQUAL(sizeof(addr.in), addrlen); + TEST_ASSERT_EQUAL(0xffff, addr.in.sin_family); + TEST_ASSERT_EQUAL(htons(0xffff), addr.in.sin_port); + TEST_ASSERT_EQUAL(htonl(0xffffffff), addr.in.sin_addr.s_addr); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + + /* Close socket */ + + TEST_ASSERT_TRUE(close(sd) >= 0); + sd = -1; + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + + /* Stopping daemon should succeed. */ + + TEST_ASSERT_EQUAL(OK, usrsocktest_daemon_stop()); + started = false; + TEST_ASSERT_EQUAL(-ENODEV, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(-ENODEV, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_endp_malloc_cnt); + TEST_ASSERT_EQUAL(0, usrsocktest_dcmd_malloc_cnt); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +TEST_GROUP(BasicGetSockName); + +/**************************************************************************** + * Name: BasicGetSockName test group setup + * + * Description: + * Setup function executed before each testcase in this test group + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +TEST_SETUP(BasicGetSockName) +{ + sd = -1; + started = false; +} + +/**************************************************************************** + * Name: BasicGetSockName test group teardown + * + * Description: + * Setup function executed after each testcase in this test group + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +TEST_TEAR_DOWN(BasicGetSockName) +{ + int ret; + if (sd >= 0) + { + ret = close(sd); + assert(ret >= 0); + } + if (started) + { + ret = usrsocktest_daemon_stop(); + assert(ret == OK); + } +} + +TEST(BasicGetSockName, Open) +{ + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + Open(&usrsocktest_daemon_config); +} + +TEST(BasicGetSockName, OpenDelay) +{ + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + usrsocktest_daemon_config.delay_all_responses = true; + Open(&usrsocktest_daemon_config); +} diff --git a/tests/unity_usrsock/basic_getsockopt.c b/tests/unity_usrsock/basic_getsockopt.c new file mode 100644 index 000000000..719380afa --- /dev/null +++ b/tests/unity_usrsock/basic_getsockopt.c @@ -0,0 +1,258 @@ +/**************************************************************************** + * apps/examples/unity_usrsock/basic_getsockopt.c + * Basic getsockopt tests + * + * Copyright (C) 2015 Haltian Ltd. All rights reserved. + * Authors: Roman Saveljev + * Jussi Kivilinna + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ +#include +#include +#include +#include +#include +#include + +#include "defines.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ +static bool started; +static int sd; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: Open + * + * Description: + * Open and get socket options + * + * Input Parameters: + * dconf - socket daemon configuration + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +static void Open(struct usrsocktest_daemon_conf_s *dconf) +{ + int ret; + int value; + int valuelarge[2]; + socklen_t valuelen; + + /* Start test daemon. */ + + dconf->endpoint_addr = "127.0.0.1"; + dconf->endpoint_port = 255; + TEST_ASSERT_EQUAL(OK, usrsocktest_daemon_start(dconf)); + started = true; + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_active_sockets()); + + /* Open socket */ + + sd = socket(AF_INET, SOCK_STREAM, 0); + TEST_ASSERT_TRUE(sd >= 0); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + + /* Get supported option (SO_TYPE handled by nuttx) */ + + value = -2; + valuelen = sizeof(value); + ret = getsockopt(sd, SOL_SOCKET, SO_TYPE, &value, &valuelen); + TEST_ASSERT_EQUAL(0, ret); + TEST_ASSERT_EQUAL(sizeof(value), valuelen); + TEST_ASSERT_EQUAL(SOCK_STREAM, value); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + + /* Get supported option */ + + value = -1; + valuelen = sizeof(value); + ret = getsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &value, &valuelen); + TEST_ASSERT_EQUAL(0, ret); + TEST_ASSERT_EQUAL(sizeof(value), valuelen); + TEST_ASSERT_EQUAL(0, value); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + + /* Get supported option, too short buffer */ + + value = -1; + valuelen = 1; + ret = getsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &value, &valuelen); + TEST_ASSERT_EQUAL(-1, ret); + TEST_ASSERT_EQUAL(EINVAL, errno); + TEST_ASSERT_EQUAL(-1, value); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + + /* Get supported option, larger buffer */ + + valuelarge[0] = -1; + valuelarge[1] = -1; + valuelen = sizeof(valuelarge); + ret = getsockopt(sd, SOL_SOCKET, SO_REUSEADDR, valuelarge, &valuelen); + TEST_ASSERT_EQUAL(0, ret); + TEST_ASSERT_EQUAL(sizeof(value), valuelen); + TEST_ASSERT_EQUAL(0, valuelarge[0]); + TEST_ASSERT_EQUAL(-1, valuelarge[1]); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + + /* Get unsupported option */ + + value = -1; + valuelen = sizeof(value); + ret = getsockopt(sd, SOL_SOCKET, SO_BROADCAST, &value, &valuelen); + TEST_ASSERT_EQUAL(-1, ret); + TEST_ASSERT_EQUAL(ENOPROTOOPT, errno); + TEST_ASSERT_EQUAL(-1, value); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + + /* Close socket */ + + TEST_ASSERT_TRUE(close(sd) >= 0); + sd = -1; + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + + /* Stopping daemon should succeed. */ + + TEST_ASSERT_EQUAL(OK, usrsocktest_daemon_stop()); + started = false; + TEST_ASSERT_EQUAL(-ENODEV, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(-ENODEV, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_endp_malloc_cnt); + TEST_ASSERT_EQUAL(0, usrsocktest_dcmd_malloc_cnt); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +TEST_GROUP(BasicGetSockOpt); + +/**************************************************************************** + * Name: BasicGetSockOpt test group setup + * + * Description: + * Setup function executed before each testcase in this test group + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +TEST_SETUP(BasicGetSockOpt) +{ + sd = -1; + started = false; +} + +/**************************************************************************** + * Name: BasicGetSockOpt test group teardown + * + * Description: + * Setup function executed after each testcase in this test group + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +TEST_TEAR_DOWN(BasicGetSockOpt) +{ + int ret; + if (sd >= 0) + { + ret = close(sd); + assert(ret >= 0); + } + if (started) + { + ret = usrsocktest_daemon_stop(); + assert(ret == OK); + } +} + +TEST(BasicGetSockOpt, Open) +{ + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + Open(&usrsocktest_daemon_config); +} + +TEST(BasicGetSockOpt, OpenDelay) +{ + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + usrsocktest_daemon_config.delay_all_responses = true; + Open(&usrsocktest_daemon_config); +} diff --git a/tests/unity_usrsock/basic_send.c b/tests/unity_usrsock/basic_send.c new file mode 100644 index 000000000..4ed8e498f --- /dev/null +++ b/tests/unity_usrsock/basic_send.c @@ -0,0 +1,345 @@ +/**************************************************************************** + * apps/examples/unity_usrsock/basic_send.c + * Basic sending tests + * + * Copyright (C) 2015 Haltian Ltd. All rights reserved. + * Authors: Roman Saveljev + * Jussi Kivilinna + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "defines.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ +static bool started; +static int sd; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: Send + * + * Description: + * Open socket and send + * + * Input Parameters: + * dconf - socket daemon configuration + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +static void Send(struct usrsocktest_daemon_conf_s *dconf) +{ + struct sockaddr_in addr; + ssize_t ret; + size_t datalen; + const void *data; + + /* Start test daemon. */ + + dconf->endpoint_addr = "127.0.0.1"; + dconf->endpoint_port = 255; + TEST_ASSERT_EQUAL(OK, usrsocktest_daemon_start(dconf)); + started = true; + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_waiting_connect_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_send_bytes()); + + /* Open socket */ + + sd = socket(AF_INET, SOCK_STREAM, 0); + TEST_ASSERT_TRUE(sd >= 0); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + + /* Send on non-connected socket */ + + data = "data"; + datalen = strlen("data"); + ret = send(sd, data, datalen, 0); + TEST_ASSERT_EQUAL(-1, ret); + TEST_ASSERT_EQUAL(ENOTCONN, errno); + TEST_ASSERT_TRUE(sd >= 0); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + + /* Sendto with address */ + + data = "data"; + datalen = strlen("data"); + ret = sendto(sd, data, datalen, 0, (FAR const struct sockaddr *)&addr, sizeof(addr)); + TEST_ASSERT_EQUAL(-1, ret); + TEST_ASSERT_EQUAL(ENOTCONN, errno); + TEST_ASSERT_TRUE(sd >= 0); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + + /* Connect socket to available endpoint */ + + inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr.s_addr); + addr.sin_family = AF_INET; + addr.sin_port = htons(255); + ret = connect(sd, (FAR const struct sockaddr *)&addr, sizeof(addr)); + TEST_ASSERT_EQUAL(0, ret); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_connected_sockets()); + + /* Sendto with address */ + + data = "data"; + datalen = strlen("data"); + ret = sendto(sd, data, datalen, 0, (FAR const struct sockaddr *)&addr, sizeof(addr)); + TEST_ASSERT_EQUAL(-1, ret); + TEST_ASSERT_EQUAL(EISCONN, errno); + TEST_ASSERT_TRUE(sd >= 0); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_connected_sockets()); + + /* Close socket */ + + TEST_ASSERT_TRUE(close(sd) >= 0); + sd = -1; + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_send_bytes()); + + /* Stopping daemon should succeed. */ + + TEST_ASSERT_EQUAL(OK, usrsocktest_daemon_stop()); + started = false; + TEST_ASSERT_EQUAL(-ENODEV, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(-ENODEV, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(-ENODEV, usrsocktest_daemon_get_num_waiting_connect_sockets()); + TEST_ASSERT_EQUAL(-ENODEV, usrsocktest_daemon_get_send_bytes()); + TEST_ASSERT_EQUAL(0, usrsocktest_endp_malloc_cnt); + TEST_ASSERT_EQUAL(0, usrsocktest_dcmd_malloc_cnt); + +} + +/**************************************************************************** + * Name: ConnectSend + * + * Description: + * Send over connected socket + * + * Input Parameters: + * dconf - socket daemon configuration + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +static void ConnectSend(struct usrsocktest_daemon_conf_s *dconf) +{ + struct sockaddr_in addr; + ssize_t ret; + size_t datalen; + const void *data; + + /* Start test daemon. */ + + dconf->endpoint_addr = "127.0.0.1"; + dconf->endpoint_port = 255; + TEST_ASSERT_EQUAL(OK, usrsocktest_daemon_start(dconf)); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_waiting_connect_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_send_bytes()); + + /* Open socket */ + + sd = socket(AF_INET, SOCK_STREAM, 0); + TEST_ASSERT_TRUE(sd >= 0); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + + /* Connect socket to available endpoint */ + + inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr.s_addr); + addr.sin_family = AF_INET; + addr.sin_port = htons(255); + ret = connect(sd, (FAR const struct sockaddr *)&addr, sizeof(addr)); + TEST_ASSERT_EQUAL(0, ret); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + + /* Send data to remote */ + + data = "data"; + datalen = strlen("data"); + ret = send(sd, data, datalen, 0); + TEST_ASSERT_EQUAL(datalen, ret); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(datalen, usrsocktest_daemon_get_send_bytes()); + + /* Close socket */ + + TEST_ASSERT_TRUE(close(sd) >= 0); + sd = -1; + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(datalen, usrsocktest_daemon_get_send_bytes()); + + /* Stopping daemon should succeed. */ + + TEST_ASSERT_EQUAL(OK, usrsocktest_daemon_stop()); + TEST_ASSERT_EQUAL(-ENODEV, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(-ENODEV, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(-ENODEV, usrsocktest_daemon_get_num_waiting_connect_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_endp_malloc_cnt); + TEST_ASSERT_EQUAL(0, usrsocktest_dcmd_malloc_cnt); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +TEST_GROUP(BasicSend); + +/**************************************************************************** + * Name: BasicSend test group setup + * + * Description: + * Setup function executed before each testcase in this test group + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +TEST_SETUP(BasicSend) +{ + sd = -1; + started = false; +} + +/**************************************************************************** + * Name: BasicSend test group teardown + * + * Description: + * Setup function executed after each testcase in this test group + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +TEST_TEAR_DOWN(BasicSend) +{ + int ret; + if (sd >= 0) + { + ret = close(sd); + assert(ret >= 0); + } + if (started) + { + ret = usrsocktest_daemon_stop(); + assert(ret == OK); + } +} + +TEST(BasicSend, Send) +{ + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + Send(&usrsocktest_daemon_config); +} + +TEST(BasicSend, SendDelay) +{ + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + usrsocktest_daemon_config.delay_all_responses = true; + Send(&usrsocktest_daemon_config); +} + +TEST(BasicSend, ConnectSend) +{ + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + ConnectSend(&usrsocktest_daemon_config); +} + +TEST(BasicSend, ConnectSendDelay) +{ + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + usrsocktest_daemon_config.delay_all_responses = true; + ConnectSend(&usrsocktest_daemon_config); +} diff --git a/tests/unity_usrsock/basic_setsockopt.c b/tests/unity_usrsock/basic_setsockopt.c new file mode 100644 index 000000000..48c0918ac --- /dev/null +++ b/tests/unity_usrsock/basic_setsockopt.c @@ -0,0 +1,226 @@ +/**************************************************************************** + * apps/examples/unity_usrsock/basic_setsockopt.c + * Basic setsockopt tests + * + * Copyright (C) 2015 Haltian Ltd. All rights reserved. + * Authors: Roman Saveljev + * Jussi Kivilinna + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "defines.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ +static bool started; +static int sd; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: Open + * + * Description: + * Open and set socket options + * + * Input Parameters: + * dconf - socket daemon configuration + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +static void Open(struct usrsocktest_daemon_conf_s *dconf) +{ + int ret; + int value; + + /* Start test daemon. */ + + dconf->endpoint_addr = "127.0.0.1"; + dconf->endpoint_port = 255; + TEST_ASSERT_EQUAL(OK, usrsocktest_daemon_start(dconf)); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_active_sockets()); + + /* Open socket */ + + sd = socket(AF_INET, SOCK_STREAM, 0); + TEST_ASSERT_TRUE(sd >= 0); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + + /* Set supported option */ + + value = 1; + ret = setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &value, sizeof(value)); + TEST_ASSERT_EQUAL(0, ret); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + + /* Set supported option, too small buffer */ + + value = 1; + ret = setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &value, 1); + TEST_ASSERT_EQUAL(-1, ret); + TEST_ASSERT_EQUAL(EINVAL, errno); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + + /* Set unsupported option */ + + value = 1; + ret = setsockopt(sd, SOL_SOCKET, SO_BROADCAST, &value, sizeof(value)); + TEST_ASSERT_EQUAL(-1, ret); + TEST_ASSERT_EQUAL(ENOPROTOOPT, errno); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + + /* Close socket */ + + TEST_ASSERT_TRUE(close(sd) >= 0); + sd = -1; + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + + /* Stopping daemon should succeed. */ + + TEST_ASSERT_EQUAL(OK, usrsocktest_daemon_stop()); + started = false; + TEST_ASSERT_EQUAL(-ENODEV, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(-ENODEV, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_endp_malloc_cnt); + TEST_ASSERT_EQUAL(0, usrsocktest_dcmd_malloc_cnt); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +TEST_GROUP(BasicSetSockOpt); + +/**************************************************************************** + * Name: BasicSetSockOpt test group setup + * + * Description: + * Setup function executed before each testcase in this test group + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +TEST_SETUP(BasicSetSockOpt) +{ + sd = -1; + started = false; +} + +/**************************************************************************** + * Name: BasicSetSockOpt test group teardown + * + * Description: + * Setup function executed after each testcase in this test group + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +TEST_TEAR_DOWN(BasicSetSockOpt) +{ + int ret; + if (sd >= 0) + { + ret = close(sd); + assert(ret >= 0); + } + if (started) + { + ret = usrsocktest_daemon_stop(); + assert(ret == OK); + } +} + +TEST(BasicSetSockOpt, Open) +{ + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + Open(&usrsocktest_daemon_config); +} + +TEST(BasicSetSockOpt, OpenDelay) +{ + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + usrsocktest_daemon_config.delay_all_responses = true; + Open(&usrsocktest_daemon_config); +} diff --git a/tests/unity_usrsock/block_recv.c b/tests/unity_usrsock/block_recv.c new file mode 100644 index 000000000..8b5329af5 --- /dev/null +++ b/tests/unity_usrsock/block_recv.c @@ -0,0 +1,497 @@ +/**************************************************************************** + * apps/examples/unity_usrsock/block_recv.c + * Receive from the socket in blocking mode + * + * Copyright (C) 2015 Haltian Ltd. All rights reserved. + * Authors: Roman Saveljev + * Jussi Kivilinna + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "defines.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ +static bool started; +static int sd; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ConnectReceive + * + * Description: + * Blocking connect and receive + * + * Input Parameters: + * dconf - socket daemon configuration + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +static void ConnectReceive(struct usrsocktest_daemon_conf_s *dconf) +{ + ssize_t ret; + size_t datalen; + void *data; + struct sockaddr_in addr; + char databuf[5]; + + /* Start test daemon. */ + + dconf->endpoint_addr = "127.0.0.1"; + dconf->endpoint_port = 255; + dconf->endpoint_block_connect = true; + dconf->endpoint_block_send = true; + dconf->endpoint_recv_avail_from_start = false; + dconf->endpoint_recv_avail = 7; + TEST_ASSERT_EQUAL(OK, usrsocktest_daemon_start(dconf)); + started = true; + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_active_sockets()); + + /* Open socket */ + + sd = socket(AF_INET, SOCK_STREAM, 0); + TEST_ASSERT_TRUE(sd >= 0); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_waiting_connect_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_recv_empty_sockets()); + + /* Do connect, should succeed (after connect block released). */ + + inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr.s_addr); + addr.sin_family = AF_INET; + addr.sin_port = htons(255); + TEST_ASSERT_TRUE(usrsocktest_send_delayed_command('E', 100)); + ret = connect(sd, (FAR const struct sockaddr *)&addr, sizeof(addr)); + TEST_ASSERT_EQUAL(0, ret); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_waiting_connect_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_recv_empty_sockets()); + + /* Receive data from remote */ + + data = databuf; + datalen = sizeof(databuf); + TEST_ASSERT_TRUE(usrsocktest_send_delayed_command('r', 100)); + ret = recvfrom(sd, data, datalen, 0, NULL, 0); + TEST_ASSERT_EQUAL(datalen, ret); + TEST_ASSERT_EQUAL(5, ret); + TEST_ASSERT_EQUAL_UINT8_ARRAY("abcde", data, 5); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(5, usrsocktest_daemon_get_recv_bytes()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_recv_empty_sockets()); + + /* Receive data from remote */ + + data = databuf; + datalen = sizeof(databuf); + ret = recvfrom(sd, data, datalen, 0, NULL, 0); + TEST_ASSERT_EQUAL(2, ret); + TEST_ASSERT_EQUAL_UINT8_ARRAY("ab", data, 2); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(7, usrsocktest_daemon_get_recv_bytes()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_recv_empty_sockets()); + + /* Close socket */ + + TEST_ASSERT_TRUE(close(sd) >= 0); + sd = -1; + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + + /* Stopping daemon should succeed. */ + + TEST_ASSERT_EQUAL(OK, usrsocktest_daemon_stop()); + started = false; + TEST_ASSERT_EQUAL(-ENODEV, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(-ENODEV, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_endp_malloc_cnt); + TEST_ASSERT_EQUAL(0, usrsocktest_dcmd_malloc_cnt); +} + +/**************************************************************************** + * Name: NoBlockConnect + * + * Description: + * Non-blocking connect and blocking receive + * + * Input Parameters: + * dconf - socket daemon configuration + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +static void NoBlockConnect(struct usrsocktest_daemon_conf_s *dconf) +{ + ssize_t ret; + size_t datalen; + void *data; + struct sockaddr_in addr; + char databuf[5]; + struct sockaddr_in remoteaddr; + socklen_t addrlen; + + /* Start test daemon. */ + + dconf->endpoint_addr = "127.0.0.1"; + dconf->endpoint_port = 255; + dconf->endpoint_block_connect = true; + dconf->endpoint_block_send = true; + dconf->endpoint_recv_avail_from_start = true; + dconf->endpoint_recv_avail = 6; + TEST_ASSERT_EQUAL(OK, usrsocktest_daemon_start(dconf)); + started = true; + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_active_sockets()); + + /* Open socket */ + + sd = socket(AF_INET, SOCK_STREAM, 0); + TEST_ASSERT_TRUE(sd >= 0); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_waiting_connect_sockets()); + + /* Do connect, should succeed (after connect block released). */ + + inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr.s_addr); + addr.sin_family = AF_INET; + addr.sin_port = htons(255); + TEST_ASSERT_TRUE(usrsocktest_send_delayed_command('W', 100)); + TEST_ASSERT_TRUE(usrsocktest_send_delayed_command('E', 100)); + ret = connect(sd, (FAR const struct sockaddr *)&addr, sizeof(addr)); + TEST_ASSERT_EQUAL(0, ret); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_waiting_connect_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_recv_empty_sockets()); + + /* Receive data from remote */ + + data = databuf; + datalen = sizeof(databuf); + ret = read(sd, data, datalen); + TEST_ASSERT_EQUAL(datalen, ret); + TEST_ASSERT_EQUAL(5, ret); + TEST_ASSERT_EQUAL_UINT8_ARRAY("abcde", data, 5); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(5, usrsocktest_daemon_get_recv_bytes()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_waiting_connect_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_recv_empty_sockets()); + + /* Receive data from remote */ + + data = databuf; + datalen = sizeof(databuf); + addrlen = sizeof(remoteaddr); + ret = recvfrom(sd, data, datalen, 0, (FAR struct sockaddr *)&remoteaddr, &addrlen); + TEST_ASSERT_EQUAL(1, ret); + TEST_ASSERT_EQUAL_UINT8_ARRAY("a", data, 1); + TEST_ASSERT_EQUAL(sizeof(remoteaddr), addrlen); + TEST_ASSERT_EQUAL_UINT8_ARRAY(&remoteaddr, &addr, addrlen); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(6, usrsocktest_daemon_get_recv_bytes()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_recv_empty_sockets()); + + /* Receive data from remote */ + + data = databuf; + datalen = sizeof(databuf); + addrlen = sizeof(remoteaddr); + TEST_ASSERT_TRUE(usrsocktest_send_delayed_command('r', 100)); + ret = recvfrom(sd, data, datalen, 0, (FAR struct sockaddr *)&remoteaddr, &addrlen); + TEST_ASSERT_EQUAL(5, ret); + TEST_ASSERT_EQUAL_UINT8_ARRAY("abcde", data, 5); + TEST_ASSERT_EQUAL(sizeof(remoteaddr), addrlen); + TEST_ASSERT_EQUAL_UINT8_ARRAY(&remoteaddr, &addr, addrlen); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(11, usrsocktest_daemon_get_recv_bytes()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_recv_empty_sockets()); + + /* Close socket */ + + TEST_ASSERT_TRUE(close(sd) >= 0); + sd = -1; + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(11, usrsocktest_daemon_get_recv_bytes()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_recv_empty_sockets()); + + /* Stopping daemon should succeed. */ + + TEST_ASSERT_EQUAL(OK, usrsocktest_daemon_stop()); + started = false; + TEST_ASSERT_EQUAL(-ENODEV, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(-ENODEV, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_endp_malloc_cnt); + TEST_ASSERT_EQUAL(0, usrsocktest_dcmd_malloc_cnt); +} + +/**************************************************************************** + * Name: ReceiveTimeout + * + * Description: + * Blocking connect and receive with SO_RCVTIMEO + * + * Input Parameters: + * dconf - socket daemon configuration + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +static void ReceiveTimeout(struct usrsocktest_daemon_conf_s *dconf) +{ + ssize_t ret; + size_t datalen; + void *data; + struct sockaddr_in addr; + char databuf[5]; + struct timeval tv; + + /* Start test daemon. */ + + dconf->endpoint_addr = "127.0.0.1"; + dconf->endpoint_port = 255; + dconf->endpoint_block_connect = true; + dconf->endpoint_block_send = true; + dconf->endpoint_recv_avail_from_start = false; + dconf->endpoint_recv_avail = 7; + TEST_ASSERT_EQUAL(OK, usrsocktest_daemon_start(dconf)); + started = true; + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_active_sockets()); + + /* Open socket */ + + sd = socket(AF_INET, SOCK_STREAM, 0); + TEST_ASSERT_TRUE(sd >= 0); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_waiting_connect_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_recv_empty_sockets()); + + /* Do connect, should succeed (after connect block released). */ + + inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr.s_addr); + addr.sin_family = AF_INET; + addr.sin_port = htons(255); + TEST_ASSERT_TRUE(usrsocktest_send_delayed_command('E', 100)); + ret = connect(sd, (FAR const struct sockaddr *)&addr, sizeof(addr)); + TEST_ASSERT_EQUAL(0, ret); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_waiting_connect_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_recv_empty_sockets()); + + /* Setup recv timeout. */ + + tv.tv_sec = 0; + tv.tv_usec = 100 * 1000; + ret = setsockopt(sd, SOL_SOCKET, SO_RCVTIMEO, (FAR const void *)&tv, + sizeof(tv)); + TEST_ASSERT_EQUAL(0, ret); + + /* Receive data from remote */ + + data = databuf; + datalen = sizeof(databuf); + ret = recvfrom(sd, data, datalen, 0, NULL, 0); + TEST_ASSERT_EQUAL(-1, ret); + TEST_ASSERT_EQUAL(EAGAIN, errno); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_recv_bytes()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_recv_empty_sockets()); + + /* Close socket */ + + TEST_ASSERT_TRUE(close(sd) >= 0); + sd = -1; + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + + /* Stopping daemon should succeed. */ + + TEST_ASSERT_EQUAL(OK, usrsocktest_daemon_stop()); + started = false; + TEST_ASSERT_EQUAL(-ENODEV, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(-ENODEV, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_endp_malloc_cnt); + TEST_ASSERT_EQUAL(0, usrsocktest_dcmd_malloc_cnt); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +TEST_GROUP(BlockRecv); + +/**************************************************************************** + * Name: BlockRecv test group setup + * + * Description: + * Setup function executed before each testcase in this test group + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +TEST_SETUP(BlockRecv) +{ + sd = -1; + started = false; +} + +/**************************************************************************** + * Name: BlockRecv test group teardown + * + * Description: + * Setup function executed after each testcase in this test group + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +TEST_TEAR_DOWN(BlockRecv) +{ + int ret; + if (sd >= 0) + { + ret = close(sd); + assert(ret >= 0); + } + if (started) + { + ret = usrsocktest_daemon_stop(); + assert(ret == OK); + } +} + +TEST(BlockRecv, ConnectReceive) +{ + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + ConnectReceive(&usrsocktest_daemon_config); +} + +TEST(BlockRecv, ConnectReceiveDelay) +{ + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + usrsocktest_daemon_config.delay_all_responses = true; + ConnectReceive(&usrsocktest_daemon_config); +} + +TEST(BlockRecv, NoBlockConnect) +{ + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + NoBlockConnect(&usrsocktest_daemon_config); +} + +TEST(BlockRecv, NoBlockConnectDelay) +{ + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + usrsocktest_daemon_config.delay_all_responses = true; + NoBlockConnect(&usrsocktest_daemon_config); +} + +TEST(BlockRecv, ReceiveTimeout) +{ + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + ReceiveTimeout(&usrsocktest_daemon_config); +} + +TEST(BlockRecv, ReceiveTimeoutDelay) +{ + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + usrsocktest_daemon_config.delay_all_responses = true; + ReceiveTimeout(&usrsocktest_daemon_config); +} diff --git a/tests/unity_usrsock/block_send.c b/tests/unity_usrsock/block_send.c new file mode 100644 index 000000000..0aa15fb74 --- /dev/null +++ b/tests/unity_usrsock/block_send.c @@ -0,0 +1,428 @@ +/**************************************************************************** + * apps/examples/unity_usrsock/block_send.c + * Send through the socket in blocking mode + * + * Copyright (C) 2015 Haltian Ltd. All rights reserved. + * Authors: Roman Saveljev + * Jussi Kivilinna + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "defines.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ +static bool started; +static int sd; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ConnectSend + * + * Description: + * Open socket, connect in blocking mode and send + * + * Input Parameters: + * dconf - socket daemon configuration + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +static void ConnectSend(struct usrsocktest_daemon_conf_s *dconf) +{ + ssize_t ret; + size_t datalen; + const void *data; + struct sockaddr_in addr; + + /* Start test daemon. */ + + dconf->endpoint_addr = "127.0.0.1"; + dconf->endpoint_port = 255; + dconf->endpoint_block_connect = true; + dconf->endpoint_block_send = true; + TEST_ASSERT_EQUAL(OK, usrsocktest_daemon_start(dconf)); + started = true; + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_active_sockets()); + + /* Open socket */ + + sd = socket(AF_INET, SOCK_STREAM, 0); + TEST_ASSERT_TRUE(sd >= 0); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_waiting_connect_sockets()); + + /* Do connect, should succeed (after connect block released). */ + + inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr.s_addr); + addr.sin_family = AF_INET; + addr.sin_port = htons(255); + TEST_ASSERT_TRUE(usrsocktest_send_delayed_command('E', 100)); + ret = connect(sd, (FAR const struct sockaddr *)&addr, sizeof(addr)); + TEST_ASSERT_EQUAL(0, ret); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_waiting_connect_sockets()); + + /* Send data to remote, */ + + data = "abcde"; + datalen = strlen("abcde"); + TEST_ASSERT_TRUE(usrsocktest_send_delayed_command('W', 100)); + ret = sendto(sd, data, datalen, 0, NULL, 0); + TEST_ASSERT_EQUAL(datalen, ret); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(datalen, usrsocktest_daemon_get_send_bytes()); + + /* Close socket */ + + TEST_ASSERT_TRUE(close(sd) >= 0); + sd = -1; + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + + /* Stopping daemon should succeed. */ + + TEST_ASSERT_EQUAL(OK, usrsocktest_daemon_stop()); + started = false; + TEST_ASSERT_EQUAL(-ENODEV, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(-ENODEV, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_endp_malloc_cnt); + TEST_ASSERT_EQUAL(0, usrsocktest_dcmd_malloc_cnt); + +} + +/**************************************************************************** + * Name: NonBlockConnectSend + * + * Description: + * Open socket, connect in non-blocking mode and send + * + * Input Parameters: + * dconf - socket daemon configuration + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +static void NonBlockConnectSend(struct usrsocktest_daemon_conf_s *dconf) +{ + ssize_t ret; + size_t datalen; + const void *data; + struct sockaddr_in addr; + + /* Start test daemon. */ + + dconf->endpoint_addr = "127.0.0.1"; + dconf->endpoint_port = 255; + dconf->endpoint_block_connect = true; + dconf->endpoint_block_send = false; + TEST_ASSERT_EQUAL(OK, usrsocktest_daemon_start(dconf)); + started = true; + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_active_sockets()); + + /* Open socket */ + + sd = socket(AF_INET, SOCK_STREAM, 0); + TEST_ASSERT_TRUE(sd >= 0); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_waiting_connect_sockets()); + + /* Do connect, should succeed (after connect block released). */ + + inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr.s_addr); + addr.sin_family = AF_INET; + addr.sin_port = htons(255); + TEST_ASSERT_TRUE(usrsocktest_send_delayed_command('W', 100)); + TEST_ASSERT_TRUE(usrsocktest_send_delayed_command('E', 100)); + ret = connect(sd, (FAR const struct sockaddr *)&addr, sizeof(addr)); + TEST_ASSERT_EQUAL(0, ret); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_waiting_connect_sockets()); + + /* Send data to remote. */ + + data = "abcde"; + datalen = strlen("abcde"); + ret = write(sd, data, datalen); + TEST_ASSERT_EQUAL(datalen, ret); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(datalen, usrsocktest_daemon_get_send_bytes()); + + /* Close socket */ + + TEST_ASSERT_TRUE(close(sd) >= 0); + sd = -1; + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + + /* Stopping daemon should succeed. */ + + TEST_ASSERT_EQUAL(OK, usrsocktest_daemon_stop()); + started = false; + TEST_ASSERT_EQUAL(-ENODEV, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(-ENODEV, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_endp_malloc_cnt); + TEST_ASSERT_EQUAL(0, usrsocktest_dcmd_malloc_cnt); +} + +/**************************************************************************** + * Name: SendTimeout + * + * Description: + * Open socket, connect in blocking mode and send with SO_SNDTIMEO + * + * Input Parameters: + * dconf - socket daemon configuration + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +static void SendTimeout(struct usrsocktest_daemon_conf_s *dconf) +{ + ssize_t ret; + size_t datalen; + const void *data; + struct sockaddr_in addr; + struct timeval tv; + + dconf->endpoint_addr = "127.0.0.1"; + dconf->endpoint_port = 255; + dconf->endpoint_block_connect = true; + dconf->endpoint_block_send = true; + TEST_ASSERT_EQUAL(OK, usrsocktest_daemon_start(dconf)); + started = true; + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_active_sockets()); + + /* Open socket */ + + sd = socket(AF_INET, SOCK_STREAM, 0); + TEST_ASSERT_TRUE(sd >= 0); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_waiting_connect_sockets()); + + /* Do connect, should succeed (after connect block released). */ + + inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr.s_addr); + addr.sin_family = AF_INET; + addr.sin_port = htons(255); + TEST_ASSERT_TRUE(usrsocktest_send_delayed_command('E', 100)); + ret = connect(sd, (FAR const struct sockaddr *)&addr, sizeof(addr)); + TEST_ASSERT_EQUAL(0, ret); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_waiting_connect_sockets()); + + /* Setup send timeout. */ + + tv.tv_sec = 0; + tv.tv_usec = 100 * 1000; + ret = setsockopt(sd, SOL_SOCKET, SO_SNDTIMEO, (FAR const void *)&tv, + sizeof(tv)); + TEST_ASSERT_EQUAL(0, ret); + + /* Try send data to remote. */ + + data = "abcde"; + datalen = strlen("abcde"); + ret = sendto(sd, data, datalen, 0, NULL, 0); + TEST_ASSERT_EQUAL(-1, ret); + TEST_ASSERT_EQUAL(EAGAIN, errno); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_send_bytes()); + + /* Close socket */ + + TEST_ASSERT_TRUE(close(sd) >= 0); + sd = -1; + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + + /* Stopping daemon should succeed. */ + + TEST_ASSERT_EQUAL(OK, usrsocktest_daemon_stop()); + started = false; + TEST_ASSERT_EQUAL(-ENODEV, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(-ENODEV, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_endp_malloc_cnt); + TEST_ASSERT_EQUAL(0, usrsocktest_dcmd_malloc_cnt); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +TEST_GROUP(BlockSend); + +/**************************************************************************** + * Name: BlockSend test group setup + * + * Description: + * Setup function executed before each testcase in this test group + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +TEST_SETUP(BlockSend) +{ + sd = -1; + started = false; +} + +/**************************************************************************** + * Name: BlockSend test group teardown + * + * Description: + * Setup function executed after each testcase in this test group + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +TEST_TEAR_DOWN(BlockSend) +{ + int ret; + if (sd >= 0) + { + ret = close(sd); + assert(ret >= 0); + } + if (started) + { + ret = usrsocktest_daemon_stop(); + assert(ret == OK); + } +} + +TEST(BlockSend, ConnectSend) +{ + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + ConnectSend(&usrsocktest_daemon_config); +} + +TEST(BlockSend, ConnectSendDelay) +{ + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + usrsocktest_daemon_config.delay_all_responses = true; + ConnectSend(&usrsocktest_daemon_config); +} + +TEST(BlockSend, NonBlockConnectSend) +{ + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + NonBlockConnectSend(&usrsocktest_daemon_config); +} + +TEST(BlockSend, NonBlockConnectSendDelay) +{ + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + usrsocktest_daemon_config.delay_all_responses = true; + NonBlockConnectSend(&usrsocktest_daemon_config); +} + +TEST(BlockSend, SendTimeout) +{ + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + SendTimeout(&usrsocktest_daemon_config); +} + +TEST(BlockSend, SendTimeoutDelay) +{ + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + usrsocktest_daemon_config.delay_all_responses = true; + SendTimeout(&usrsocktest_daemon_config); +} diff --git a/tests/unity_usrsock/chardev.c b/tests/unity_usrsock/chardev.c new file mode 100644 index 000000000..bf9366032 --- /dev/null +++ b/tests/unity_usrsock/chardev.c @@ -0,0 +1,222 @@ +/**************************************************************************** + * apps/examples/unity_usrsock/chardev.c + * Character device node tests + * + * Copyright (C) 2015 Haltian Ltd. All rights reserved. + * Authors: Roman Saveljev + * Jussi Kivilinna + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ +#include +#include +#include + +#include "defines.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ +static int us_fd; +static int us_fd_two; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +TEST_GROUP(CharDev); + +/**************************************************************************** + * Name: CharDev test group setup + * + * Description: + * Setup function executed before each testcase in this test group + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +TEST_SETUP(CharDev) +{ + us_fd = -1; + us_fd_two = -1; +} + +/**************************************************************************** + * Name: CharDev test group teardown + * + * Description: + * Setup function executed after each testcase in this test group + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +TEST_TEAR_DOWN(CharDev) +{ + int ret; + + if (us_fd >= 0) + { + ret = close(us_fd); + assert(ret >= 0); + } + if (us_fd_two >= 0) + { + ret = close(us_fd_two); + assert(ret >= 0); + } +} + +/**************************************************************************** + * Name: OpenRw + * + * Description: + * Simple test for opening and closing usrsock node + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +TEST(CharDev, OpenRw) +{ + int ret; + + us_fd = open(USRSOCK_NODE, O_RDWR); + TEST_ASSERT_TRUE(us_fd >= 0); + + ret = close(us_fd); + TEST_ASSERT_TRUE(ret >= 0); + us_fd = -1; +} + +/**************************************************************************** + * Name: ReopenRw + * + * Description: + * Repeated simple test for opening and closing usrsock node, reopen should + * work + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +TEST(CharDev, ReopenRw) +{ + int ret; + + us_fd = open(USRSOCK_NODE, O_RDWR); + TEST_ASSERT_TRUE(us_fd >= 0); + + ret = close(us_fd); + TEST_ASSERT_TRUE(ret >= 0); + us_fd = -1; + + us_fd = open(USRSOCK_NODE, O_RDWR); + TEST_ASSERT_TRUE(us_fd >= 0); + + ret = close(us_fd); + TEST_ASSERT_TRUE(ret >= 0); + us_fd = -1; +} + +/**************************************************************************** + * Name: NoMultipleOpen + * + * Description: + * No permission for multiple access, + * first user should be only user. + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +TEST(CharDev, NoMultipleOpen) +{ + us_fd = open(USRSOCK_NODE, O_RDWR); + TEST_ASSERT_TRUE(us_fd >= 0); + + us_fd_two = open(USRSOCK_NODE, O_RDWR); + TEST_ASSERT_FALSE(us_fd_two >= 0); + TEST_ASSERT_EQUAL(EPERM, errno); +} diff --git a/tests/unity_usrsock/defines.h b/tests/unity_usrsock/defines.h new file mode 100644 index 000000000..153efc4f9 --- /dev/null +++ b/tests/unity_usrsock/defines.h @@ -0,0 +1,124 @@ +/**************************************************************************** + * apps/examples/unity_usrsock/defines.h + * Common defines for all testcases + * + * Copyright (C) 2015 Haltian Ltd. All rights reserved. + * Author: Roman Saveljev + * Jussi Kivilinna + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ +#ifndef __EXAMPLES_UNITY_USRSOCK_DEFINES_H +#define __EXAMPLES_UNITY_USRSOCK_DEFINES_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ +#define USRSOCK_NODE "/dev/usrsock" + +#define USRSOCKTEST_DAEMON_CONF_DEFAULTS \ + { \ + .max_sockets = UINT_MAX, \ + .supported_domain = AF_INET, \ + .supported_type = SOCK_STREAM, \ + .supported_protocol = 0, \ + .delay_all_responses = false, \ + .endpoint_addr = "127.0.0.1", \ + .endpoint_port = 255, \ + .endpoint_block_connect = false, \ + .endpoint_block_send = false, \ + .endpoint_recv_avail_from_start = true, \ + .endpoint_recv_avail = 4, \ + } + +/**************************************************************************** + * Public Types + ****************************************************************************/ +struct usrsocktest_daemon_conf_s +{ + unsigned int max_sockets; + int8_t supported_domain:8; + int8_t supported_type:8; + int8_t supported_protocol:8; + bool delay_all_responses:1; + bool endpoint_block_connect:1; + bool endpoint_block_send:1; + bool endpoint_recv_avail_from_start:1; + uint8_t endpoint_recv_avail:8; + const char *endpoint_addr; + uint16_t endpoint_port; +}; + +/**************************************************************************** + * Public Data + ****************************************************************************/ +extern int usrsocktest_endp_malloc_cnt; +extern int usrsocktest_dcmd_malloc_cnt; +extern const struct usrsocktest_daemon_conf_s usrsocktest_daemon_defconf; +extern struct usrsocktest_daemon_conf_s usrsocktest_daemon_config; + +/**************************************************************************** + * Inline Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ +int usrsocktest_daemon_start(const struct usrsocktest_daemon_conf_s *conf); + +int usrsocktest_daemon_stop(void); + +int usrsocktest_daemon_get_num_active_sockets(void); + +int usrsocktest_daemon_get_num_connected_sockets(void); + +int usrsocktest_daemon_get_num_waiting_connect_sockets(void); + +int usrsocktest_daemon_get_num_recv_empty_sockets(void); + +ssize_t usrsocktest_daemon_get_send_bytes(void); + +ssize_t usrsocktest_daemon_get_recv_bytes(void); + +int usrsocktest_daemon_get_num_unreachable_sockets(void); + +int usrsocktest_daemon_get_num_remote_disconnected_sockets(void); + +bool usrsocktest_daemon_establish_waiting_connections(void); + +bool usrsocktest_send_delayed_command(char cmd, unsigned int delay_msec); + +int usrsocktest_daemon_pause_usrsock_handling(bool pause); + +#endif /* __EXAMPLES_UNITY_USRSOCK_DEFINES_H */ diff --git a/tests/unity_usrsock/multi_thread.c b/tests/unity_usrsock/multi_thread.c new file mode 100644 index 000000000..17206d2ef --- /dev/null +++ b/tests/unity_usrsock/multi_thread.c @@ -0,0 +1,256 @@ +/**************************************************************************** + * apps/examples/unity_usrsock/multi_thread.c + * Multi-threaded access to sockets + * + * Copyright (C) 2015 Haltian Ltd. All rights reserved. + * Authors: Roman Saveljev + * Jussi Kivilinna + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ +#include +#include +#include +#include +#include + +#include "defines.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ +#ifndef ARRAY_SIZE +# define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ +static pthread_t tids[4]; +static int sds[4]; +static bool started; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ +static void usrsock_socket_multitask_do_work(int *sd) +{ + struct sockaddr_in addr; + int ret; + int i; + + for (i = 0; i < 10; i++) + { + /* Simple test for opening socket with usrsock daemon running. */ + + *sd = socket(AF_INET, SOCK_STREAM, 0); + TEST_ASSERT_TRUE(*sd >= 0); + + inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr.s_addr); + addr.sin_family = AF_INET; + addr.sin_port = htons(255); + ret = connect(*sd, (FAR const struct sockaddr *)&addr, sizeof(addr)); + TEST_ASSERT_EQUAL(0, ret); + + /* Close socket */ + + TEST_ASSERT_TRUE(close(*sd) >= 0); + *sd = -1; + } +} + +static FAR void *usrsock_socket_multitask_thread(FAR void *param) +{ + usrsock_socket_multitask_do_work((int*)param); + return NULL; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +TEST_GROUP(MultiThread); + +/**************************************************************************** + * Name: MultiThread test group setup + * + * Description: + * Setup function executed before each testcase in this test group + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +TEST_SETUP(MultiThread) +{ + int i; + for (i = 0; i < ARRAY_SIZE(sds); i++) + { + sds[i] = -1; + } + for (i = 0; i < ARRAY_SIZE(tids); i++) + { + tids[i] = -1; + } + started = false; +} + +/**************************************************************************** + * Name: MultiThread test group teardown + * + * Description: + * Setup function executed after each testcase in this test group + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +TEST_TEAR_DOWN(MultiThread) +{ + int ret; + int i; + + for (i = 0; i < ARRAY_SIZE(tids); i++) + { + if (tids[i] != -1) + { + ret = pthread_cancel(tids[i]); + assert(ret == OK); + ret = pthread_join(tids[i], NULL); + assert(ret == OK); + } + } + for (i = 0; i < ARRAY_SIZE(sds); i++) + { + if (sds[i] != -1) + { + ret = close(sds[i]); + assert(ret >= 0); + } + } + if (started) + { + ret = usrsocktest_daemon_stop(); + assert(ret == OK); + } +} + +/**************************************************************************** + * Name: OpenClose + * + * Description: + * Open and close socket with multiple threads + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +TEST(MultiThread, OpenClose) +{ + int ret; + int i; + + /* Start test daemon. */ + + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + usrsocktest_daemon_config.delay_all_responses = true; + usrsocktest_daemon_config.endpoint_block_send = false; + usrsocktest_daemon_config.endpoint_block_connect = false; + usrsocktest_daemon_config.endpoint_addr = "127.0.0.1"; + usrsocktest_daemon_config.endpoint_port = 255; + TEST_ASSERT_EQUAL(OK, usrsocktest_daemon_start(&usrsocktest_daemon_config)); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_active_sockets()); + + /* Launch worker threads. */ + + for (i = 0; i < ARRAY_SIZE(tids); i++) + { + ret = pthread_create(&tids[i], NULL, usrsock_socket_multitask_thread, + sds + i); + TEST_ASSERT_EQUAL(OK, ret); + } + + /* Wait threads to complete work. */ + + while (--i > -1) + { + pthread_addr_t tparam; + + ret = pthread_join(tids[i], &tparam); + TEST_ASSERT_EQUAL(OK, ret); + tids[i] = -1; + /* This flag is set whenever a test fails, otherwise it is not touched + * No need for synchronization. Here we bail from main test thread on + * first failure in any thread. + */ + TEST_ASSERT_FALSE(Unity.CurrentTestFailed); + } + + /* Stopping daemon should succeed. */ + + TEST_ASSERT_EQUAL(OK, usrsocktest_daemon_stop()); + started = false; + TEST_ASSERT_EQUAL(0, usrsocktest_endp_malloc_cnt); + TEST_ASSERT_EQUAL(0, usrsocktest_dcmd_malloc_cnt); +} + diff --git a/tests/unity_usrsock/noblock_connect.c b/tests/unity_usrsock/noblock_connect.c new file mode 100644 index 000000000..51cf35115 --- /dev/null +++ b/tests/unity_usrsock/noblock_connect.c @@ -0,0 +1,806 @@ +/**************************************************************************** + * apps/examples/unity_usrsock/noblock_connect.c + * Socket connect tests in non-blocking mode + * + * Copyright (C) 2015 Haltian Ltd. All rights reserved. + * Authors: Roman Saveljev + * Jussi Kivilinna + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include "defines.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ +static bool started; +static int sd, sd2; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +TEST_GROUP(NoBlockConnect); + +TEST_SETUP(NoBlockConnect) +{ + sd = -1; + sd2 = -1; + started = false; +} + +TEST_TEAR_DOWN(NoBlockConnect) +{ + int ret; + + if (sd >= 0) + { + ret = close(sd); + assert(ret == 0); + } + if (sd2 >= 0) + { + ret = close(sd2); + assert(ret == 0); + } + if (started) + { + ret = usrsocktest_daemon_stop(); + assert(ret == OK); + } +} + +TEST(NoBlockConnect, InstantConnect) +{ + int flags; + int ret; + struct sockaddr_in addr; + + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + usrsocktest_daemon_config.endpoint_addr = "127.0.0.1"; + usrsocktest_daemon_config.endpoint_port = 255; + TEST_ASSERT_EQUAL(OK, usrsocktest_daemon_start(&usrsocktest_daemon_config)); + started = true; + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_active_sockets()); + + /* Open socket */ + + sd = socket(AF_INET, SOCK_STREAM, 0); + TEST_ASSERT_TRUE(sd >= 0); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_waiting_connect_sockets()); + + /* Make socket non-blocking */ + + flags = fcntl(sd, F_GETFL, 0); + TEST_ASSERT_TRUE(flags >= 0); + TEST_ASSERT_EQUAL(O_RDWR, flags & O_RDWR); + TEST_ASSERT_EQUAL(0, flags & O_NONBLOCK); + ret = fcntl(sd, F_SETFL, flags | O_NONBLOCK); + TEST_ASSERT_EQUAL(0, ret); + flags = fcntl(sd, F_GETFL, 0); + TEST_ASSERT_TRUE(flags >= 0); + TEST_ASSERT_EQUAL(O_RDWR, flags & O_RDWR); + TEST_ASSERT_EQUAL(O_NONBLOCK, flags & O_NONBLOCK); + + /* Do connect, should succeed instantly. */ + + inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr.s_addr); + addr.sin_family = AF_INET; + addr.sin_port = htons(255); + ret = connect(sd, (FAR const struct sockaddr *)&addr, sizeof(addr)); + TEST_ASSERT_EQUAL(0, ret); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_waiting_connect_sockets()); + + /* Close socket */ + + TEST_ASSERT_TRUE(close(sd) >= 0); + sd = -1; + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + + /* Stopping daemon should succeed. */ + + TEST_ASSERT_EQUAL(OK, usrsocktest_daemon_stop()); + started = false; + TEST_ASSERT_EQUAL(-ENODEV, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(-ENODEV, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_endp_malloc_cnt); + TEST_ASSERT_EQUAL(0, usrsocktest_dcmd_malloc_cnt); +} + +TEST(NoBlockConnect, DelayedConnect) +{ + int flags, ret, count; + struct sockaddr_in addr; + + /* Start test daemon. */ + + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + usrsocktest_daemon_config.endpoint_block_connect = true; + usrsocktest_daemon_config.endpoint_addr = "127.0.0.1"; + usrsocktest_daemon_config.endpoint_port = 255; + usrsocktest_daemon_config.delay_all_responses = true; + TEST_ASSERT_EQUAL(OK, usrsocktest_daemon_start(&usrsocktest_daemon_config)); + started = true; + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_active_sockets()); + + /* Open socket */ + + sd = socket(AF_INET, SOCK_STREAM, 0); + TEST_ASSERT_TRUE(sd >= 0); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_waiting_connect_sockets()); + + /* Make socket non-blocking */ + + flags = fcntl(sd, F_GETFL, 0); + TEST_ASSERT_TRUE(flags >= 0); + TEST_ASSERT_EQUAL(O_RDWR, flags & O_RDWR); + TEST_ASSERT_EQUAL(0, flags & O_NONBLOCK); + ret = fcntl(sd, F_SETFL, flags | O_NONBLOCK); + TEST_ASSERT_EQUAL(0, ret); + flags = fcntl(sd, F_GETFL, 0); + TEST_ASSERT_TRUE(flags >= 0); + TEST_ASSERT_EQUAL(O_RDWR, flags & O_RDWR); + TEST_ASSERT_EQUAL(O_NONBLOCK, flags & O_NONBLOCK); + + /* Launch connect attempt, daemon delays actual connection until triggered. */ + + inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr.s_addr); + addr.sin_family = AF_INET; + addr.sin_port = htons(255); + ret = connect(sd, (FAR const struct sockaddr *)&addr, sizeof(addr)); + TEST_ASSERT_EQUAL(-1, ret); + TEST_ASSERT_EQUAL(EINPROGRESS, errno); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_waiting_connect_sockets()); + + /* Another connect attempt results EALREADY. */ + + ret = connect(sd, (FAR const struct sockaddr *)&addr, sizeof(addr)); + TEST_ASSERT_EQUAL(-1, ret); + TEST_ASSERT_EQUAL(EALREADY, errno); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_waiting_connect_sockets()); + + /* Release delayed connect. */ + + TEST_ASSERT_TRUE(usrsocktest_daemon_establish_waiting_connections()); + for (count = 0; usrsocktest_daemon_get_num_waiting_connect_sockets() > 0; count++) + { + TEST_ASSERT_TRUE(count <= 5); + usleep(10 * 1000); + } + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_waiting_connect_sockets()); + + /* Another connect attempt results EISCONN. */ + + ret = connect(sd, (FAR const struct sockaddr *)&addr, sizeof(addr)); + TEST_ASSERT_EQUAL(-1, ret); + TEST_ASSERT_EQUAL(EISCONN, errno); + + /* Close socket. */ + + TEST_ASSERT_TRUE(close(sd) >= 0); + sd = -1; + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_waiting_connect_sockets()); + + /* Stopping daemon should succeed. */ + + TEST_ASSERT_EQUAL(OK, usrsocktest_daemon_stop()); + started = false; + TEST_ASSERT_EQUAL(-ENODEV, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(-ENODEV, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(-ENODEV, usrsocktest_daemon_get_num_waiting_connect_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_endp_malloc_cnt); + TEST_ASSERT_EQUAL(0, usrsocktest_dcmd_malloc_cnt); +} + +TEST(NoBlockConnect, CloseNotConnected) +{ + int flags, ret; + struct sockaddr_in addr; + + /* Start test daemon. */ + + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + usrsocktest_daemon_config.endpoint_block_connect = true; + usrsocktest_daemon_config.endpoint_addr = "127.0.0.1"; + usrsocktest_daemon_config.endpoint_port = 255; + usrsocktest_daemon_config.delay_all_responses = true; + TEST_ASSERT_EQUAL(OK, usrsocktest_daemon_start(&usrsocktest_daemon_config)); + started = true; + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_active_sockets()); + + /* Open socket */ + + sd = socket(AF_INET, SOCK_STREAM, 0); + TEST_ASSERT_TRUE(sd >= 0); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_waiting_connect_sockets()); + + /* Make socket non-blocking */ + + flags = fcntl(sd, F_GETFL, 0); + TEST_ASSERT_TRUE(flags >= 0); + TEST_ASSERT_EQUAL(O_RDWR, flags & O_RDWR); + TEST_ASSERT_EQUAL(0, flags & O_NONBLOCK); + ret = fcntl(sd, F_SETFL, flags | O_NONBLOCK); + TEST_ASSERT_EQUAL(0, ret); + flags = fcntl(sd, F_GETFL, 0); + TEST_ASSERT_TRUE(flags >= 0); + TEST_ASSERT_EQUAL(O_RDWR, flags & O_RDWR); + TEST_ASSERT_EQUAL(O_NONBLOCK, flags & O_NONBLOCK); + + /* Launch connect attempt, daemon delays actual connection until triggered. */ + + inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr.s_addr); + addr.sin_family = AF_INET; + addr.sin_port = htons(255); + ret = connect(sd, (FAR const struct sockaddr *)&addr, sizeof(addr)); + TEST_ASSERT_EQUAL(-1, ret); + TEST_ASSERT_EQUAL(EINPROGRESS, errno); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_waiting_connect_sockets()); + + /* Close socket. */ + + TEST_ASSERT_TRUE(close(sd) >= 0); + sd = -1; + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_waiting_connect_sockets()); + + /* Stopping daemon should succeed. */ + + TEST_ASSERT_EQUAL(OK, usrsocktest_daemon_stop()); + started = false; + TEST_ASSERT_EQUAL(-ENODEV, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(-ENODEV, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(-ENODEV, usrsocktest_daemon_get_num_waiting_connect_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_endp_malloc_cnt); + TEST_ASSERT_EQUAL(0, usrsocktest_dcmd_malloc_cnt); +} + +TEST(NoBlockConnect, EarlyDrop) +{ + int flags, ret; + struct sockaddr_in addr; + + /* Start test daemon. */ + + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + usrsocktest_daemon_config.endpoint_block_connect = true; + usrsocktest_daemon_config.endpoint_addr = "127.0.0.1"; + usrsocktest_daemon_config.endpoint_port = 255; + usrsocktest_daemon_config.delay_all_responses = false; + TEST_ASSERT_EQUAL(OK, usrsocktest_daemon_start(&usrsocktest_daemon_config)); + started = true; + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_active_sockets()); + + /* Open socket */ + + sd = socket(AF_INET, SOCK_STREAM, 0); + TEST_ASSERT_TRUE(sd >= 0) + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_waiting_connect_sockets()); + + /* Make socket non-blocking */ + + flags = fcntl(sd, F_GETFL, 0); + TEST_ASSERT_TRUE(flags >= 0); + TEST_ASSERT_EQUAL(O_RDWR, flags & O_RDWR); + TEST_ASSERT_EQUAL(0, flags & O_NONBLOCK); + ret = fcntl(sd, F_SETFL, flags | O_NONBLOCK); + TEST_ASSERT_EQUAL(0, ret); + flags = fcntl(sd, F_GETFL, 0); + TEST_ASSERT_TRUE(flags >= 0); + TEST_ASSERT_EQUAL(O_RDWR, flags & O_RDWR); + TEST_ASSERT_EQUAL(O_NONBLOCK, flags & O_NONBLOCK); + + /* Launch connect attempt, daemon delays actual connection until triggered. */ + + inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr.s_addr); + addr.sin_family = AF_INET; + addr.sin_port = htons(255); + ret = connect(sd, (FAR const struct sockaddr *)&addr, sizeof(addr)); + TEST_ASSERT_EQUAL(-1, ret); + TEST_ASSERT_EQUAL(EINPROGRESS, errno); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_waiting_connect_sockets()); + + /* Stopping daemon should succeed. */ + + TEST_ASSERT_EQUAL(OK, usrsocktest_daemon_stop()); + started = false; + TEST_ASSERT_EQUAL(-ENODEV, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(-ENODEV, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(-ENODEV, usrsocktest_daemon_get_num_waiting_connect_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_endp_malloc_cnt); + TEST_ASSERT_EQUAL(0, usrsocktest_dcmd_malloc_cnt); + + /* Close socket. */ + + TEST_ASSERT_TRUE(close(sd) >= 0); + sd = -1; + TEST_ASSERT_EQUAL(-ENODEV, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(-ENODEV, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(-ENODEV, usrsocktest_daemon_get_num_waiting_connect_sockets()); +} + +TEST(NoBlockConnect, Multiple) +{ + int flags, ret, count; + struct sockaddr_in addr; + + /* Start test daemon. */ + + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + usrsocktest_daemon_config.endpoint_block_connect = true; + usrsocktest_daemon_config.endpoint_addr = "127.0.0.1"; + usrsocktest_daemon_config.endpoint_port = 255; + usrsocktest_daemon_config.delay_all_responses = false; + TEST_ASSERT_EQUAL(OK, usrsocktest_daemon_start(&usrsocktest_daemon_config)); + started = true; + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_active_sockets()); + + /* Open sockets */ + + sd = socket(AF_INET, SOCK_STREAM, 0); + TEST_ASSERT_TRUE(sd >= 0); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_waiting_connect_sockets()); + sd2 = socket(AF_INET, SOCK_STREAM, 0); + TEST_ASSERT_TRUE(sd2 >= 0); + TEST_ASSERT_EQUAL(2, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_waiting_connect_sockets()); + + /* Make socket non-blocking */ + + flags = fcntl(sd, F_GETFL, 0); + TEST_ASSERT_TRUE(flags >= 0); + TEST_ASSERT_EQUAL(O_RDWR, flags & O_RDWR); + TEST_ASSERT_EQUAL(0, flags & O_NONBLOCK); + ret = fcntl(sd, F_SETFL, flags | O_NONBLOCK); + TEST_ASSERT_EQUAL(0, ret); + flags = fcntl(sd, F_GETFL, 0); + TEST_ASSERT_TRUE(flags >= 0); + TEST_ASSERT_EQUAL(O_RDWR, flags & O_RDWR); + TEST_ASSERT_EQUAL(O_NONBLOCK, flags & O_NONBLOCK); + + flags = fcntl(sd2, F_GETFL, 0); + TEST_ASSERT_TRUE(flags >= 0); + TEST_ASSERT_EQUAL(O_RDWR, flags & O_RDWR); + TEST_ASSERT_EQUAL(0, flags & O_NONBLOCK); + ret = fcntl(sd2, F_SETFL, flags | O_NONBLOCK); + TEST_ASSERT_EQUAL(0, ret); + flags = fcntl(sd2, F_GETFL, 0); + TEST_ASSERT_TRUE(flags >= 0); + TEST_ASSERT_EQUAL(O_RDWR, flags & O_RDWR); + TEST_ASSERT_EQUAL(O_NONBLOCK, flags & O_NONBLOCK); + + /* Launch connect attempts, daemon delays actual connection until triggered. */ + + inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr.s_addr); + addr.sin_family = AF_INET; + addr.sin_port = htons(255); + ret = connect(sd2, (FAR const struct sockaddr *)&addr, sizeof(addr)); + TEST_ASSERT_EQUAL(-1, ret); + TEST_ASSERT_EQUAL(EINPROGRESS, errno); + TEST_ASSERT_EQUAL(2, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_waiting_connect_sockets()); + + /* Release delayed connections. */ + + TEST_ASSERT_TRUE(usrsocktest_daemon_establish_waiting_connections()); + for (count = 0; usrsocktest_daemon_get_num_waiting_connect_sockets() > 0; count++) + { + TEST_ASSERT_TRUE(count <= 5); + usleep(10 * 1000); + } + TEST_ASSERT_EQUAL(2, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_waiting_connect_sockets()); + + inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr.s_addr); + addr.sin_family = AF_INET; + addr.sin_port = htons(255); + ret = connect(sd2, (FAR const struct sockaddr *)&addr, sizeof(addr)); + TEST_ASSERT_EQUAL(-1, ret); + TEST_ASSERT_EQUAL(EISCONN, errno); + + inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr.s_addr); + addr.sin_family = AF_INET; + addr.sin_port = htons(255); + ret = connect(sd, (FAR const struct sockaddr *)&addr, sizeof(addr)); + TEST_ASSERT_EQUAL(-1, ret); + TEST_ASSERT_EQUAL(EINPROGRESS, errno); + TEST_ASSERT_EQUAL(2, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_waiting_connect_sockets()); + + /* Release delayed connections. */ + + TEST_ASSERT_TRUE(usrsocktest_daemon_establish_waiting_connections()); + for (count = 0; usrsocktest_daemon_get_num_waiting_connect_sockets() > 0; count++) + { + TEST_ASSERT_TRUE(count <= 5); + usleep(10 * 1000); + } + TEST_ASSERT_EQUAL(2, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(2, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_waiting_connect_sockets()); + + /* Close sockets. */ + + TEST_ASSERT_TRUE(close(sd2) >= 0); + sd2 = -1; + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_waiting_connect_sockets()); + TEST_ASSERT_TRUE(close(sd) >= 0); + sd = -1; + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_waiting_connect_sockets()); + + /* Open sockets */ + + sd = socket(AF_INET, SOCK_STREAM, 0); + TEST_ASSERT_TRUE(sd >= 0); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_waiting_connect_sockets()); + sd2 = socket(AF_INET, SOCK_STREAM, 0); + TEST_ASSERT_TRUE(sd2 >= 0); + TEST_ASSERT_EQUAL(2, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_waiting_connect_sockets()); + + /* Make socket non-blocking */ + + flags = fcntl(sd, F_GETFL, 0); + TEST_ASSERT_TRUE(flags >= 0); + TEST_ASSERT_EQUAL(O_RDWR, flags & O_RDWR); + TEST_ASSERT_EQUAL(0, flags & O_NONBLOCK); + ret = fcntl(sd, F_SETFL, flags | O_NONBLOCK); + TEST_ASSERT_EQUAL(0, ret); + flags = fcntl(sd, F_GETFL, 0); + TEST_ASSERT_TRUE(flags >= 0); + TEST_ASSERT_EQUAL(O_RDWR, flags & O_RDWR); + TEST_ASSERT_EQUAL(O_NONBLOCK, flags & O_NONBLOCK); + + flags = fcntl(sd2, F_GETFL, 0); + TEST_ASSERT_TRUE(flags >= 0); + TEST_ASSERT_EQUAL(O_RDWR, flags & O_RDWR); + TEST_ASSERT_EQUAL(0, flags & O_NONBLOCK); + ret = fcntl(sd2, F_SETFL, flags | O_NONBLOCK); + TEST_ASSERT_EQUAL(0, ret); + flags = fcntl(sd2, F_GETFL, 0); + TEST_ASSERT_TRUE(flags >= 0); + TEST_ASSERT_EQUAL(O_RDWR, flags & O_RDWR); + TEST_ASSERT_EQUAL(O_NONBLOCK, flags & O_NONBLOCK); + + /* Launch connect attempts, daemon delays actual connection until triggered. */ + + inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr.s_addr); + addr.sin_family = AF_INET; + addr.sin_port = htons(255); + ret = connect(sd, (FAR const struct sockaddr *)&addr, sizeof(addr)); + TEST_ASSERT_EQUAL(-1, ret); + TEST_ASSERT_EQUAL(EINPROGRESS, errno); + TEST_ASSERT_EQUAL(2, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_waiting_connect_sockets()); + + ret = connect(sd2, (FAR const struct sockaddr *)&addr, sizeof(addr)); + TEST_ASSERT_EQUAL(-1, ret); + TEST_ASSERT_EQUAL(EINPROGRESS, errno); + TEST_ASSERT_EQUAL(2, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(2, usrsocktest_daemon_get_num_waiting_connect_sockets()); + + /* Release delayed connections. */ + + TEST_ASSERT_TRUE(usrsocktest_daemon_establish_waiting_connections()); + for (count = 0; usrsocktest_daemon_get_num_waiting_connect_sockets() > 0; count++) + { + TEST_ASSERT_TRUE(count <= 5); + usleep(10 * 1000); + } + TEST_ASSERT_EQUAL(2, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(2, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_waiting_connect_sockets()); + + /* Close sockets. */ + + TEST_ASSERT_TRUE(close(sd2) >= 0); + sd2 = -1; + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_waiting_connect_sockets()); + TEST_ASSERT_TRUE(close(sd) >= 0); + sd = -1; + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_waiting_connect_sockets()); + + /* Open sockets */ + + sd = socket(AF_INET, SOCK_STREAM, 0); + TEST_ASSERT_TRUE(sd >= 0); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_waiting_connect_sockets()); + sd2 = socket(AF_INET, SOCK_STREAM, 0); + TEST_ASSERT_TRUE(sd2 >= 0); + TEST_ASSERT_EQUAL(2, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_waiting_connect_sockets()); + + /* Make socket non-blocking */ + + flags = fcntl(sd, F_GETFL, 0); + TEST_ASSERT_TRUE(flags >= 0); + TEST_ASSERT_EQUAL(O_RDWR, flags & O_RDWR); + TEST_ASSERT_EQUAL(0, flags & O_NONBLOCK); + ret = fcntl(sd, F_SETFL, flags | O_NONBLOCK); + TEST_ASSERT_EQUAL(0, ret); + flags = fcntl(sd, F_GETFL, 0); + TEST_ASSERT_TRUE(flags >= 0); + TEST_ASSERT_EQUAL(O_RDWR, flags & O_RDWR); + TEST_ASSERT_EQUAL(O_NONBLOCK, flags & O_NONBLOCK); + + flags = fcntl(sd2, F_GETFL, 0); + TEST_ASSERT_TRUE(flags >= 0); + TEST_ASSERT_EQUAL(O_RDWR, flags & O_RDWR); + TEST_ASSERT_EQUAL(0, flags & O_NONBLOCK); + ret = fcntl(sd2, F_SETFL, flags | O_NONBLOCK); + TEST_ASSERT_EQUAL(0, ret); + flags = fcntl(sd2, F_GETFL, 0); + TEST_ASSERT_TRUE(flags >= 0); + TEST_ASSERT_EQUAL(O_RDWR, flags & O_RDWR); + TEST_ASSERT_EQUAL(O_NONBLOCK, flags & O_NONBLOCK); + + /* Launch connect attempt, daemon delays actual connection until triggered. */ + + inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr.s_addr); + addr.sin_family = AF_INET; + addr.sin_port = htons(255); + ret = connect(sd, (FAR const struct sockaddr *)&addr, sizeof(addr)); + TEST_ASSERT_EQUAL(-1, ret); + TEST_ASSERT_EQUAL(EINPROGRESS, errno); + TEST_ASSERT_EQUAL(2, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_waiting_connect_sockets()); + + /* Release delayed connections. */ + + TEST_ASSERT_TRUE(usrsocktest_daemon_establish_waiting_connections()); + for (count = 0; usrsocktest_daemon_get_num_waiting_connect_sockets() > 0; count++) + { + TEST_ASSERT_TRUE(count <= 5); + usleep(10 * 1000); + } + TEST_ASSERT_EQUAL(2, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_waiting_connect_sockets()); + + /* Launch another connect attempt, daemon delays actual connection until triggered. */ + + ret = connect(sd2, (FAR const struct sockaddr *)&addr, sizeof(addr)); + TEST_ASSERT_EQUAL(-1, ret); + TEST_ASSERT_EQUAL(EINPROGRESS, errno); + TEST_ASSERT_EQUAL(2, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_waiting_connect_sockets()); + + /* Close sockets. */ + + TEST_ASSERT_TRUE(close(sd) >= 0); + sd = -1; + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_waiting_connect_sockets()); + TEST_ASSERT_TRUE(close(sd2) >= 0); + sd2 = -1; + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_waiting_connect_sockets()); + + /* Stopping daemon should succeed. */ + + TEST_ASSERT_EQUAL(OK, usrsocktest_daemon_stop()); + started = false; + TEST_ASSERT_EQUAL(-ENODEV, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(-ENODEV, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(-ENODEV, usrsocktest_daemon_get_num_waiting_connect_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_endp_malloc_cnt); + TEST_ASSERT_EQUAL(0, usrsocktest_dcmd_malloc_cnt); +} + +TEST(NoBlockConnect, Dup2) +{ + int flags, ret, count; + struct sockaddr_in addr; + + /* Start test daemon. */ + + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + usrsocktest_daemon_config.endpoint_block_connect = true; + usrsocktest_daemon_config.endpoint_addr = "127.0.0.1"; + usrsocktest_daemon_config.endpoint_port = 255; + usrsocktest_daemon_config.delay_all_responses = true; + TEST_ASSERT_EQUAL(OK, usrsocktest_daemon_start(&usrsocktest_daemon_config)); + started = true; + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_active_sockets()); + + /* Open socket */ + + sd = socket(AF_INET, SOCK_STREAM, 0); + TEST_ASSERT_TRUE(sd >= 0); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_waiting_connect_sockets()); + + /* Duplicate socket */ + + sd2 = dup(sd); + TEST_ASSERT_TRUE(sd2 >= 0); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + + /* Make socket non-blocking */ + + flags = fcntl(sd, F_GETFL, 0); + TEST_ASSERT_TRUE(flags >= 0); + TEST_ASSERT_EQUAL(O_RDWR, flags & O_RDWR); + TEST_ASSERT_EQUAL(0, flags & O_NONBLOCK); + ret = fcntl(sd, F_SETFL, flags | O_NONBLOCK); + TEST_ASSERT_EQUAL(0, ret); + flags = fcntl(sd, F_GETFL, 0); + TEST_ASSERT_TRUE(flags >= 0); + TEST_ASSERT_EQUAL(O_RDWR, flags & O_RDWR); + TEST_ASSERT_EQUAL(O_NONBLOCK, flags & O_NONBLOCK); + + /* Launch connect attempt, daemon delays actual connection until triggered. */ + + inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr.s_addr); + addr.sin_family = AF_INET; + addr.sin_port = htons(255); + ret = connect(sd, (FAR const struct sockaddr *)&addr, sizeof(addr)); + TEST_ASSERT_EQUAL(-1, ret); + TEST_ASSERT_EQUAL(EINPROGRESS, errno); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_waiting_connect_sockets()); + + /* Another connect attempt results EALREADY. */ + + ret = connect(sd2, (FAR const struct sockaddr *)&addr, sizeof(addr)); + TEST_ASSERT_EQUAL(-1, ret); + TEST_ASSERT_EQUAL(EALREADY, errno); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_waiting_connect_sockets()); + + /* Release delayed connect. */ + + TEST_ASSERT_TRUE(usrsocktest_daemon_establish_waiting_connections()); + for (count = 0; usrsocktest_daemon_get_num_waiting_connect_sockets() > 0; count++) + { + TEST_ASSERT_TRUE(count <= 5); + usleep(10 * 1000); + } + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_waiting_connect_sockets()); + + /* Another connect attempt results EISCONN. */ + + ret = connect(sd, (FAR const struct sockaddr *)&addr, sizeof(addr)); + TEST_ASSERT_EQUAL(-1, ret); + TEST_ASSERT_EQUAL(EISCONN, errno); + + /* Close sockets. */ + + TEST_ASSERT_TRUE(close(sd) >= 0); + sd = -1; + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_waiting_connect_sockets()); + + TEST_ASSERT_TRUE(close(sd2) >= 0); + sd2 = -1; + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_waiting_connect_sockets()); + + /* Stopping daemon should succeed. */ + + TEST_ASSERT_EQUAL(OK, usrsocktest_daemon_stop()); + started = false; + TEST_ASSERT_EQUAL(-ENODEV, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(-ENODEV, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(-ENODEV, usrsocktest_daemon_get_num_waiting_connect_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_endp_malloc_cnt); + TEST_ASSERT_EQUAL(0, usrsocktest_dcmd_malloc_cnt); +} diff --git a/tests/unity_usrsock/noblock_recv.c b/tests/unity_usrsock/noblock_recv.c new file mode 100644 index 000000000..4f191ac49 --- /dev/null +++ b/tests/unity_usrsock/noblock_recv.c @@ -0,0 +1,503 @@ +/**************************************************************************** + * apps/examples/unity_usrsock/noblock_recv.c + * Receive from the socket in non-blocking mode + * + * Copyright (C) 2015 Haltian Ltd. All rights reserved. + * Authors: Roman Saveljev + * Jussi Kivilinna + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "defines.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ +static bool started; +static int sd; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: Receive + * + * Description: + * Non-blocking & instant connect+recv + * + * Input Parameters: + * dconf - socket daemon configuration + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +static void Receive(struct usrsocktest_daemon_conf_s *dconf) +{ + int flags; + int count; + ssize_t ret; + size_t datalen; + void *data; + struct sockaddr_in addr; + char databuf[4]; + struct sockaddr_in remoteaddr; + socklen_t addrlen; + + /* Start test daemon. */ + + dconf->endpoint_addr = "127.0.0.1"; + dconf->endpoint_port = 255; + dconf->endpoint_recv_avail_from_start = true; + dconf->endpoint_recv_avail = 7; + TEST_ASSERT_EQUAL(OK, usrsocktest_daemon_start(dconf)); + started = true; + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_active_sockets()); + + /* Open socket */ + + sd = socket(AF_INET, SOCK_STREAM, 0); + TEST_ASSERT_TRUE(sd >= 0); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_waiting_connect_sockets()); + + /* Make socket non-blocking */ + + flags = fcntl(sd, F_GETFL, 0); + TEST_ASSERT_TRUE(flags >= 0); + TEST_ASSERT_EQUAL(O_RDWR, flags & O_RDWR); + TEST_ASSERT_EQUAL(0, flags & O_NONBLOCK); + ret = fcntl(sd, F_SETFL, flags | O_NONBLOCK); + TEST_ASSERT_EQUAL(0, ret); + flags = fcntl(sd, F_GETFL, 0); + TEST_ASSERT_TRUE(flags >= 0); + TEST_ASSERT_EQUAL(O_RDWR, flags & O_RDWR); + TEST_ASSERT_EQUAL(O_NONBLOCK, flags & O_NONBLOCK); + + /* Do connect, should succeed instantly. */ + + inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr.s_addr); + addr.sin_family = AF_INET; + addr.sin_port = htons(255); + ret = connect(sd, (FAR const struct sockaddr *)&addr, sizeof(addr)); + if (!dconf->delay_all_responses) + { + TEST_ASSERT_EQUAL(0, ret); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_waiting_connect_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_recv_empty_sockets()); + } + else + { + TEST_ASSERT_EQUAL(-1, ret); + TEST_ASSERT_EQUAL(EINPROGRESS, errno); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_waiting_connect_sockets()); + + for (count = 0; usrsocktest_daemon_get_num_connected_sockets() != 1; count++) + { + TEST_ASSERT_TRUE(count <= 3); + usleep(25 * 1000); + } + + ret = connect(sd, (FAR const struct sockaddr *)&addr, sizeof(addr)); + TEST_ASSERT_EQUAL(-1, ret); + TEST_ASSERT_EQUAL(EISCONN, errno); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_recv_empty_sockets()); + } + + /* Receive data from remote, daemon returns 4 bytes. */ + + data = databuf; + datalen = sizeof(databuf); + ret = recvfrom(sd, data, datalen, 0, NULL, NULL); + TEST_ASSERT_EQUAL(datalen, ret); + TEST_ASSERT_EQUAL(4, datalen); + TEST_ASSERT_EQUAL_UINT8_ARRAY("abcd", data, 4); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(4, usrsocktest_daemon_get_recv_bytes()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_recv_empty_sockets()); + + /* Receive data from remote with address, daemon returns 3 bytes. */ + + addrlen = sizeof(remoteaddr); + ret = recvfrom(sd, data, datalen, 0, (FAR struct sockaddr *)&remoteaddr, &addrlen); + TEST_ASSERT_EQUAL(3, ret); + TEST_ASSERT_EQUAL_UINT8_ARRAY("abc", data, 3); + TEST_ASSERT_EQUAL(addrlen, sizeof(remoteaddr)); + TEST_ASSERT_EQUAL_UINT8_ARRAY(&remoteaddr, &addr, addrlen); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(datalen + ret, usrsocktest_daemon_get_recv_bytes()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_recv_empty_sockets()); + + /* Receive data from remote, daemon has 0 bytes buffered => -EAGAIN */ + + data = databuf; + datalen = sizeof(databuf); + ret = recvfrom(sd, data, datalen, 0, NULL, NULL); + TEST_ASSERT_EQUAL(-1, ret); + TEST_ASSERT_EQUAL(EAGAIN, errno); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(7, usrsocktest_daemon_get_recv_bytes()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_recv_empty_sockets()); + + /* Receive data from remote, daemon has 0 bytes buffered => -EAGAIN */ + + data = databuf; + datalen = sizeof(databuf); + ret = read(sd, data, datalen); + TEST_ASSERT_EQUAL(-1, ret); + TEST_ASSERT_EQUAL(EAGAIN, errno); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(7, usrsocktest_daemon_get_recv_bytes()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_recv_empty_sockets()); + + /* Reset recv buffer for open sockets */ + + TEST_ASSERT_TRUE(usrsocktest_send_delayed_command('r', 0)); + for (count = 0; usrsocktest_daemon_get_num_recv_empty_sockets() > 0; count++) + { + TEST_ASSERT_TRUE(count <= 5); + usleep(5 * 1000); + } + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_recv_empty_sockets()); + + /* Receive data from remote, daemon returns 4 bytes. */ + + data = databuf; + datalen = sizeof(databuf); + ret = recvfrom(sd, data, datalen, 0, NULL, NULL); + TEST_ASSERT_EQUAL(datalen, ret); + TEST_ASSERT_EQUAL(4, datalen); + TEST_ASSERT_EQUAL_UINT8_ARRAY("abcd", data, 4); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(7 + 4, usrsocktest_daemon_get_recv_bytes()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_recv_empty_sockets()); + + /* Close socket */ + + TEST_ASSERT_TRUE(close(sd) >= 0); + sd = -1; + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(7 + 4, usrsocktest_daemon_get_recv_bytes()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_recv_empty_sockets()); + + /* Stopping daemon should succeed. */ + + TEST_ASSERT_EQUAL(OK, usrsocktest_daemon_stop()); + started = false; + TEST_ASSERT_EQUAL(-ENODEV, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(-ENODEV, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_endp_malloc_cnt); + TEST_ASSERT_EQUAL(0, usrsocktest_dcmd_malloc_cnt); +} + +/**************************************************************************** + * Name: DelayedConnect + * + * Description: + * Non-blocking & delayed connect + * + * Input Parameters: + * dconf - socket daemon configuration + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +static void DelayedConnect(struct usrsocktest_daemon_conf_s *dconf) +{ + int flags; + int count; + ssize_t ret; + size_t datalen; + void *data; + struct sockaddr_in addr; + char databuf[4]; + struct sockaddr_in remoteaddr; + socklen_t addrlen; + + /* Start test daemon. */ + + dconf->endpoint_block_connect = true; + dconf->endpoint_recv_avail_from_start = false; + dconf->endpoint_recv_avail = 4; + dconf->endpoint_addr = "127.0.0.1"; + dconf->endpoint_port = 255; + TEST_ASSERT_EQUAL(OK, usrsocktest_daemon_start(dconf)); + started = true; + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_active_sockets()); + + /* Open socket */ + + sd = socket(AF_INET, SOCK_STREAM, 0); + TEST_ASSERT_TRUE(sd >= 0); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_waiting_connect_sockets()); + + /* Make socket non-blocking */ + + flags = fcntl(sd, F_GETFL, 0); + TEST_ASSERT_TRUE(flags >= 0); + TEST_ASSERT_EQUAL(O_RDWR, flags & O_RDWR); + TEST_ASSERT_EQUAL(0, flags & O_NONBLOCK); + ret = fcntl(sd, F_SETFL, flags | O_NONBLOCK); + TEST_ASSERT_EQUAL(0, ret); + flags = fcntl(sd, F_GETFL, 0); + TEST_ASSERT_TRUE(flags >= 0); + TEST_ASSERT_EQUAL(O_RDWR, flags & O_RDWR); + TEST_ASSERT_EQUAL(O_NONBLOCK, flags & O_NONBLOCK); + + /* Launch connect attempt, daemon delays actual connection until triggered. */ + + inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr.s_addr); + addr.sin_family = AF_INET; + addr.sin_port = htons(255); + ret = connect(sd, (FAR const struct sockaddr *)&addr, sizeof(addr)); + TEST_ASSERT_EQUAL(-1, ret); + TEST_ASSERT_EQUAL(EINPROGRESS, errno); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_waiting_connect_sockets()); + + /* Try receive data, not connected yet. */ + + data = databuf; + datalen = sizeof(databuf); + ret = read(sd, data, datalen); + TEST_ASSERT_EQUAL(-1, ret); + TEST_ASSERT_EQUAL(EAGAIN, errno); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_waiting_connect_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_send_bytes()); + + /* Release delayed connect. */ + + TEST_ASSERT_TRUE(usrsocktest_daemon_establish_waiting_connections()); + for (count = 0; usrsocktest_daemon_get_num_waiting_connect_sockets() > 0; count++) + { + TEST_ASSERT_TRUE(count <= 5); + usleep(10 * 1000); + } + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_waiting_connect_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_recv_empty_sockets()); + + /* Try receive data, not received data yet. */ + + data = databuf; + datalen = sizeof(databuf); + addrlen = sizeof(remoteaddr); + ret = recvfrom(sd, data, datalen, 0, (FAR struct sockaddr *)&remoteaddr, &addrlen); + TEST_ASSERT_EQUAL(-1, ret); + TEST_ASSERT_EQUAL(EAGAIN, errno); + TEST_ASSERT_EQUAL(0, addrlen); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_send_bytes()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_recv_empty_sockets()); + + /* Reset recv buffer for open sockets */ + + TEST_ASSERT_TRUE(usrsocktest_send_delayed_command('r', 0)); + for (count = 0; usrsocktest_daemon_get_num_recv_empty_sockets() > 0; count++) + { + TEST_ASSERT_TRUE(count <= 5); + usleep(5 * 1000); + } + + /* Receive data from remote, daemon returns 4 bytes. */ + + data = databuf; + datalen = sizeof(databuf); + ret = recvfrom(sd, data, datalen, 0, NULL, NULL); + TEST_ASSERT_EQUAL(datalen, ret); + TEST_ASSERT_EQUAL(4, datalen); + TEST_ASSERT_EQUAL_UINT8_ARRAY("abcd", data, 4); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(4, usrsocktest_daemon_get_recv_bytes()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_recv_empty_sockets()); + + /* Close socket. */ + + TEST_ASSERT_TRUE(close(sd) >= 0); + sd = -1; + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_waiting_connect_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_recv_empty_sockets()); + + /* Stopping daemon should succeed. */ + + TEST_ASSERT_EQUAL(OK, usrsocktest_daemon_stop()); + started = false; + TEST_ASSERT_EQUAL(-ENODEV, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(-ENODEV, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(-ENODEV, usrsocktest_daemon_get_num_waiting_connect_sockets()); + TEST_ASSERT_EQUAL(-ENODEV, usrsocktest_daemon_get_num_recv_empty_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_endp_malloc_cnt); + TEST_ASSERT_EQUAL(0, usrsocktest_dcmd_malloc_cnt); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +TEST_GROUP(NoBlockRecv); + +/**************************************************************************** + * Name: NoBlockRecv test group setup + * + * Description: + * Setup function executed before each testcase in this test group + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +TEST_SETUP(NoBlockRecv) +{ + sd = -1; + started = false; +} + +/**************************************************************************** + * Name: NoBlockRecv test group teardown + * + * Description: + * Setup function executed after each testcase in this test group + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +TEST_TEAR_DOWN(NoBlockRecv) +{ + int ret; + if (sd >= 0) + { + ret = close(sd); + assert(ret >= 0); + } + if (started) + { + ret = usrsocktest_daemon_stop(); + assert(ret == OK); + } +} + +TEST(NoBlockRecv, Receive) +{ + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + Receive(&usrsocktest_daemon_config); +} + +TEST(NoBlockRecv, ReceiveDelay) +{ + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + usrsocktest_daemon_config.delay_all_responses = true; + Receive(&usrsocktest_daemon_config); +} + +TEST(NoBlockRecv, DelayedConnect) +{ + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + DelayedConnect(&usrsocktest_daemon_config); +} + +TEST(NoBlockRecv, DelayedConnectDelay) +{ + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + usrsocktest_daemon_config.delay_all_responses = true; + DelayedConnect(&usrsocktest_daemon_config); +} diff --git a/tests/unity_usrsock/noblock_send.c b/tests/unity_usrsock/noblock_send.c new file mode 100644 index 000000000..47055f76c --- /dev/null +++ b/tests/unity_usrsock/noblock_send.c @@ -0,0 +1,400 @@ +/**************************************************************************** + * apps/examples/unity_usrsock/noblock_send.c + * Send through the socket in non-blocking mode + * + * Copyright (C) 2015 Haltian Ltd. All rights reserved. + * Authors: Roman Saveljev + * Jussi Kivilinna + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "defines.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ +static bool started; +static int sd; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: Send + * + * Description: + * Open socket, connect instantly and send + * + * Input Parameters: + * dconf - socket daemon configuration + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +static void Send(struct usrsocktest_daemon_conf_s *dconf) +{ + int flags; + int count; + ssize_t ret; + size_t datalen; + const void *data; + struct sockaddr_in addr; + + /* Start test daemon. */ + + dconf->endpoint_addr = "127.0.0.1"; + dconf->endpoint_port = 255; + TEST_ASSERT_EQUAL(OK, usrsocktest_daemon_start(dconf)); + started = true; + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_active_sockets()); + + /* Open socket */ + + sd = socket(AF_INET, SOCK_STREAM, 0); + TEST_ASSERT_TRUE(sd >= 0); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_waiting_connect_sockets()); + + /* Make socket non-blocking */ + + flags = fcntl(sd, F_GETFL, 0); + TEST_ASSERT_TRUE(flags >= 0); + TEST_ASSERT_EQUAL(O_RDWR, flags & O_RDWR); + TEST_ASSERT_EQUAL(0, flags & O_NONBLOCK); + ret = fcntl(sd, F_SETFL, flags | O_NONBLOCK); + TEST_ASSERT_EQUAL(0, ret); + flags = fcntl(sd, F_GETFL, 0); + TEST_ASSERT_TRUE(flags >= 0); + TEST_ASSERT_EQUAL(O_RDWR, flags & O_RDWR); + TEST_ASSERT_EQUAL(O_NONBLOCK, flags & O_NONBLOCK); + + /* Do connect, should succeed instantly. */ + + inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr.s_addr); + addr.sin_family = AF_INET; + addr.sin_port = htons(255); + ret = connect(sd, (FAR const struct sockaddr *)&addr, sizeof(addr)); + if (!dconf->delay_all_responses) + { + TEST_ASSERT_EQUAL(0, ret); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_waiting_connect_sockets()); + } + else + { + TEST_ASSERT_EQUAL(-1, ret); + TEST_ASSERT_EQUAL(EINPROGRESS, errno); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_waiting_connect_sockets()); + + for (count = 0; usrsocktest_daemon_get_num_connected_sockets() != 1; count++) + { + TEST_ASSERT_TRUE(count <= 3); + usleep(25 * 1000); + } + + ret = connect(sd, (FAR const struct sockaddr *)&addr, sizeof(addr)); + TEST_ASSERT_EQUAL(-1, ret); + TEST_ASSERT_EQUAL(EISCONN, errno); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_connected_sockets()); + } + + /* Send data to remote */ + + data = "abcde"; + datalen = strlen("abcde"); + ret = sendto(sd, data, datalen, 0, NULL, 0); + TEST_ASSERT_EQUAL(datalen, ret); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(datalen, usrsocktest_daemon_get_send_bytes()); + + /* Close socket */ + + TEST_ASSERT_TRUE(close(sd) >= 0); + sd = -1; + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + + /* Stopping daemon should succeed. */ + + TEST_ASSERT_EQUAL(OK, usrsocktest_daemon_stop()); + started = false; + TEST_ASSERT_EQUAL(-ENODEV, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_endp_malloc_cnt); + TEST_ASSERT_EQUAL(0, usrsocktest_dcmd_malloc_cnt); + TEST_ASSERT_EQUAL(-ENODEV, usrsocktest_daemon_get_num_connected_sockets()); +} + +/**************************************************************************** + * Name: ConnectSend + * + * Description: + * Open socket, connect is delayed and send + * + * Input Parameters: + * dconf - socket daemon configuration + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +static void ConnectSend(struct usrsocktest_daemon_conf_s *dconf) +{ + int flags; + int count; + ssize_t ret; + size_t datalen; + const void *data; + struct sockaddr_in addr; + + /* Start test daemon. */ + + dconf->endpoint_block_connect = true; + dconf->endpoint_block_send = true; + dconf->endpoint_addr = "127.0.0.1"; + dconf->endpoint_port = 255; + TEST_ASSERT_EQUAL(OK, usrsocktest_daemon_start(dconf)); + started = true; + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_active_sockets()); + + /* Open socket */ + + sd = socket(AF_INET, SOCK_STREAM, 0); + TEST_ASSERT_TRUE(sd >= 0); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_waiting_connect_sockets()); + + /* Make socket non-blocking */ + + flags = fcntl(sd, F_GETFL, 0); + TEST_ASSERT_TRUE(flags >= 0); + TEST_ASSERT_EQUAL(O_RDWR, flags & O_RDWR); + TEST_ASSERT_EQUAL(0, flags & O_NONBLOCK); + ret = fcntl(sd, F_SETFL, flags | O_NONBLOCK); + TEST_ASSERT_EQUAL(0, ret); + flags = fcntl(sd, F_GETFL, 0); + TEST_ASSERT_TRUE(flags >= 0); + TEST_ASSERT_EQUAL(O_RDWR, flags & O_RDWR); + TEST_ASSERT_EQUAL(O_NONBLOCK, flags & O_NONBLOCK); + + /* Launch connect attempt, daemon delays actual connection until triggered. */ + + inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr.s_addr); + addr.sin_family = AF_INET; + addr.sin_port = htons(255); + ret = connect(sd, (FAR const struct sockaddr *)&addr, sizeof(addr)); + TEST_ASSERT_EQUAL(-1, ret); + TEST_ASSERT_EQUAL(EINPROGRESS, errno); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_waiting_connect_sockets()); + + /* Send data to remote, not connected yet. */ + + data = "abcde"; + datalen = strlen("abcde"); + ret = write(sd, data, datalen); + TEST_ASSERT_EQUAL(-1, ret); + TEST_ASSERT_EQUAL(EAGAIN, errno); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_waiting_connect_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_send_bytes()); + + /* Release delayed connect. */ + + TEST_ASSERT_TRUE(usrsocktest_daemon_establish_waiting_connections()); + for (count = 0; usrsocktest_daemon_get_num_waiting_connect_sockets() > 0; count++) + { + TEST_ASSERT_TRUE(count <= 5); + usleep(10 * 1000); + } + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_waiting_connect_sockets()); + + /* Send data to remote */ + + data = "abcde"; + datalen = strlen("abcde"); + ret = write(sd, data, datalen); + TEST_ASSERT_EQUAL(-1, ret); + TEST_ASSERT_EQUAL(EAGAIN, errno); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_send_bytes()); + + /* Close socket. */ + + TEST_ASSERT_TRUE(close(sd) >= 0); + sd = -1; + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_waiting_connect_sockets()); + + /* Stopping daemon should succeed. */ + + TEST_ASSERT_EQUAL(OK, usrsocktest_daemon_stop()); + started = false; + TEST_ASSERT_EQUAL(-ENODEV, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(-ENODEV, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(-ENODEV, usrsocktest_daemon_get_num_waiting_connect_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_endp_malloc_cnt); + TEST_ASSERT_EQUAL(0, usrsocktest_dcmd_malloc_cnt); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +TEST_GROUP(NoBlockSend); + +/**************************************************************************** + * Name: NoBlockSend test group setup + * + * Description: + * Setup function executed before each testcase in this test group + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +TEST_SETUP(NoBlockSend) +{ + sd = -1; + started = false; +} + +/**************************************************************************** + * Name: NoBlockSend test group teardown + * + * Description: + * Setup function executed after each testcase in this test group + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +TEST_TEAR_DOWN(NoBlockSend) +{ + int ret; + if (sd >= 0) + { + ret = close(sd); + assert(ret >= 0); + } + if (started) + { + ret = usrsocktest_daemon_stop(); + assert(ret == OK); + } +} + +TEST(NoBlockSend, Send) +{ + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + Send(&usrsocktest_daemon_config); +} + +TEST(NoBlockSend, SendDelay) +{ + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + usrsocktest_daemon_config.delay_all_responses = true; + Send(&usrsocktest_daemon_config); +} + +TEST(NoBlockSend, ConnectSend) +{ + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + ConnectSend(&usrsocktest_daemon_config); +} + +TEST(NoBlockSend, ConnectSendDelay) +{ + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + usrsocktest_daemon_config.delay_all_responses = true; + ConnectSend(&usrsocktest_daemon_config); +} diff --git a/tests/unity_usrsock/nodaemon.c b/tests/unity_usrsock/nodaemon.c new file mode 100644 index 000000000..eff1cb744 --- /dev/null +++ b/tests/unity_usrsock/nodaemon.c @@ -0,0 +1,148 @@ +/**************************************************************************** + * apps/examples/unity_usrsock/nodaemon.c + * Tests without user socket daemon + * + * Copyright (C) 2015 Haltian Ltd. All rights reserved. + * Authors: Roman Saveljev + * Jussi Kivilinna + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ +#include +#include +#include + +#include "defines.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ +static int sd; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +TEST_GROUP(NoDaemon); + +/**************************************************************************** + * Name: NoDaemon test group setup + * + * Description: + * Setup function executed before each testcase in this test group + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +TEST_SETUP(NoDaemon) +{ + sd = -1; +} + +/**************************************************************************** + * Name: NoDaemon test group teardown + * + * Description: + * Setup function executed after each testcase in this test group + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +TEST_TEAR_DOWN(NoDaemon) +{ + int ret; + + if (sd >= 0) + { + ret = close(sd); + assert(ret >= 0); + } +} + +/**************************************************************************** + * Name: NoSocket + * + * Description: + * Simple test for opening socket without usrsock daemon running + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +TEST(NoDaemon, NoSocket) +{ + sd = socket(AF_INET, SOCK_STREAM, 0); + TEST_ASSERT_EQUAL(-1, sd); + TEST_ASSERT_TRUE(errno == EAFNOSUPPORT || errno == EPROTONOSUPPORT || errno == ENETDOWN); +} + diff --git a/tests/unity_usrsock/poll.c b/tests/unity_usrsock/poll.c new file mode 100644 index 000000000..0a1c46bf9 --- /dev/null +++ b/tests/unity_usrsock/poll.c @@ -0,0 +1,632 @@ +/**************************************************************************** + * apps/examples/unity_usrsock/poll.c + * User socket polling tests + * + * Copyright (C) 2015 Haltian Ltd. All rights reserved. + * Authors: Roman Saveljev + * Jussi Kivilinna + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "defines.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ +static bool started; +static int sd; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ConnectReceive + * + * Description: + * Non-blocking connect and receive + * + * Input Parameters: + * dconf - socket daemon configuration + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +static void ConnectReceive(struct usrsocktest_daemon_conf_s *dconf) +{ + int flags; + int count; + ssize_t ret; + size_t datalen; + void *data; + struct sockaddr_in addr; + char databuf[4]; + struct pollfd pfd; + + /* Start test daemon. */ + + dconf->endpoint_addr = "127.0.0.1"; + dconf->endpoint_port = 255; + dconf->endpoint_recv_avail_from_start = false; + dconf->endpoint_recv_avail = 3; + TEST_ASSERT_EQUAL(OK, usrsocktest_daemon_start(dconf)); + started = true; + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_active_sockets()); + + /* Open socket */ + + sd = socket(AF_INET, SOCK_STREAM, 0); + TEST_ASSERT_TRUE(sd >= 0); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_waiting_connect_sockets()); + + /* Make socket non-blocking */ + + flags = fcntl(sd, F_GETFL, 0); + TEST_ASSERT_TRUE(flags >= 0); + TEST_ASSERT_EQUAL(O_RDWR, flags & O_RDWR); + TEST_ASSERT_EQUAL(0, flags & O_NONBLOCK); + ret = fcntl(sd, F_SETFL, flags | O_NONBLOCK); + TEST_ASSERT_EQUAL(0, ret); + flags = fcntl(sd, F_GETFL, 0); + TEST_ASSERT_TRUE(flags >= 0); + TEST_ASSERT_EQUAL(O_RDWR, flags & O_RDWR); + TEST_ASSERT_EQUAL(O_NONBLOCK, flags & O_NONBLOCK); + + /* Poll for input (instant timeout). */ + + memset(&pfd, 0, sizeof(pfd)); + pfd.fd = sd; + pfd.events = POLLIN; + ret = poll(&pfd, 1, 0); + TEST_ASSERT_EQUAL(1, ret); + TEST_ASSERT_EQUAL(0, pfd.revents & POLLERR); + TEST_ASSERT_EQUAL(POLLHUP, pfd.revents & POLLHUP); + TEST_ASSERT_EQUAL(POLLIN, pfd.revents & POLLIN); + TEST_ASSERT_EQUAL(0, pfd.revents & POLLOUT); + + /* Do connect, should succeed instantly. */ + + inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr.s_addr); + addr.sin_family = AF_INET; + addr.sin_port = htons(255); + ret = connect(sd, (FAR const struct sockaddr *)&addr, sizeof(addr)); + if (!dconf->delay_all_responses) + { + TEST_ASSERT_EQUAL(0, ret); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_waiting_connect_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_recv_empty_sockets()); + } + else + { + TEST_ASSERT_EQUAL(-1, ret); + TEST_ASSERT_EQUAL(EINPROGRESS, errno); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + + for (count = 0; usrsocktest_daemon_get_num_connected_sockets() != 1; count++) + { + TEST_ASSERT_TRUE(count <= 3); + usleep(25 * 1000); + } + + ret = connect(sd, (FAR const struct sockaddr *)&addr, sizeof(addr)); + TEST_ASSERT_EQUAL(-1, ret); + TEST_ASSERT_EQUAL(EISCONN, errno); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_recv_empty_sockets()); + } + + /* Poll for input (instant timeout). */ + + memset(&pfd, 0, sizeof(pfd)); + pfd.fd = sd; + pfd.events = POLLIN; + ret = poll(&pfd, 1, 0); + TEST_ASSERT_EQUAL(0, ret); + + /* Poll for input (with timeout). */ + + memset(&pfd, 0, sizeof(pfd)); + pfd.fd = sd; + pfd.events = POLLIN; + ret = poll(&pfd, 1, 10); + TEST_ASSERT_EQUAL(0, ret); + + /* Poll for input (no timeout). */ + + memset(&pfd, 0, sizeof(pfd)); + pfd.fd = sd; + pfd.events = POLLIN; + TEST_ASSERT_TRUE(usrsocktest_send_delayed_command('r', 100)); + ret = poll(&pfd, 1, -1); + TEST_ASSERT_EQUAL(1, ret); + TEST_ASSERT_EQUAL(POLLIN, pfd.revents); + + /* Receive data from remote, daemon returns 3 bytes. */ + + data = databuf; + datalen = sizeof(databuf); + ret = recvfrom(sd, data, datalen, 0, NULL, NULL); + TEST_ASSERT_EQUAL(3, ret); + TEST_ASSERT_EQUAL_UINT8_ARRAY("abc", data, 3); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(3, usrsocktest_daemon_get_recv_bytes()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_recv_empty_sockets()); + + /* Poll for input (instant timeout). */ + + memset(&pfd, 0, sizeof(pfd)); + pfd.fd = sd; + pfd.events = POLLIN; + ret = poll(&pfd, 1, 0); + TEST_ASSERT_EQUAL(0, ret); + + /* Make more data avail */ + + TEST_ASSERT_TRUE(usrsocktest_send_delayed_command('r', 0)); + for (count = 0; usrsocktest_daemon_get_num_recv_empty_sockets() > 0; count++) + { + TEST_ASSERT_TRUE(count <= 3); + usleep(5 * 1000); + } + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_recv_empty_sockets()); + + /* Poll for input (no timeout). */ + + memset(&pfd, 0, sizeof(pfd)); + pfd.fd = sd; + pfd.events = POLLIN; + ret = poll(&pfd, 1, -1); + TEST_ASSERT_EQUAL(1, ret); + TEST_ASSERT_EQUAL(POLLIN, pfd.revents); + + /* Receive data from remote, daemon returns 3 bytes. */ + + data = databuf; + datalen = sizeof(databuf); + ret = recvfrom(sd, data, datalen, 0, NULL, NULL); + TEST_ASSERT_EQUAL(3, ret); + TEST_ASSERT_EQUAL_UINT8_ARRAY("abc", data, 3); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(6, usrsocktest_daemon_get_recv_bytes()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_recv_empty_sockets()); + + /* Close socket */ + + TEST_ASSERT_TRUE(close(sd) >= 0); + sd = -1; + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(6, usrsocktest_daemon_get_recv_bytes()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_recv_empty_sockets()); + + /* Stopping daemon should succeed. */ + + TEST_ASSERT_EQUAL(OK, usrsocktest_daemon_stop()); + started = false; + TEST_ASSERT_EQUAL(-ENODEV, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(-ENODEV, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_endp_malloc_cnt); + TEST_ASSERT_EQUAL(0, usrsocktest_dcmd_malloc_cnt); +} + +/**************************************************************************** + * Name: ConnectSend + * + * Description: + * Non-blocking connect and receive + * + * Input Parameters: + * dconf - socket daemon configuration + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +static void ConnectSend(struct usrsocktest_daemon_conf_s *dconf) +{ + int flags; + ssize_t ret; + size_t datalen; + void *data; + struct sockaddr_in addr; + struct pollfd pfd; + + /* Start test daemon. */ + + dconf->endpoint_addr = "127.0.0.1"; + dconf->endpoint_port = 255; + dconf->endpoint_recv_avail_from_start = true; + dconf->endpoint_recv_avail = 3; + dconf->endpoint_block_send = false; + dconf->endpoint_block_connect = true; + TEST_ASSERT_EQUAL(OK, usrsocktest_daemon_start(dconf)); + started = true; + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_active_sockets()); + + /* Open socket */ + + sd = socket(AF_INET, SOCK_STREAM, 0); + TEST_ASSERT_TRUE(sd >= 0); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_waiting_connect_sockets()); + + /* Make socket non-blocking */ + + flags = fcntl(sd, F_GETFL, 0); + TEST_ASSERT_TRUE(flags >= 0); + TEST_ASSERT_EQUAL(O_RDWR, flags & O_RDWR); + TEST_ASSERT_EQUAL(0, flags & O_NONBLOCK); + ret = fcntl(sd, F_SETFL, flags | O_NONBLOCK); + TEST_ASSERT_EQUAL(0, ret); + flags = fcntl(sd, F_GETFL, 0); + TEST_ASSERT_TRUE(flags >= 0); + TEST_ASSERT_EQUAL(O_RDWR, flags & O_RDWR); + TEST_ASSERT_EQUAL(O_NONBLOCK, flags & O_NONBLOCK); + + /* Poll for input (instant timeout). */ + + memset(&pfd, 0, sizeof(pfd)); + pfd.fd = sd; + pfd.events = POLLIN; + ret = poll(&pfd, 1, 0); + TEST_ASSERT_EQUAL(1, ret); + TEST_ASSERT_EQUAL(0, pfd.revents & POLLERR); + TEST_ASSERT_EQUAL(POLLHUP, pfd.revents & POLLHUP); + TEST_ASSERT_EQUAL(POLLIN, pfd.revents & POLLIN); + TEST_ASSERT_EQUAL(0, pfd.revents & POLLOUT); + + /* Start non-blocking connect. */ + + inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr.s_addr); + addr.sin_family = AF_INET; + addr.sin_port = htons(255); + ret = connect(sd, (FAR const struct sockaddr *)&addr, sizeof(addr)); + TEST_ASSERT_EQUAL(-1, ret); + TEST_ASSERT_EQUAL(EINPROGRESS, errno); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_waiting_connect_sockets()); + + /* Poll for input (no timeout). As send is ready after established connection, + * poll will exit with POLLOUT. */ + + memset(&pfd, 0, sizeof(pfd)); + TEST_ASSERT_TRUE(usrsocktest_send_delayed_command('E', 100)); + pfd.fd = sd; + pfd.events = POLLOUT; + ret = poll(&pfd, 1, -1); + TEST_ASSERT_EQUAL(1, ret); + TEST_ASSERT_EQUAL(POLLOUT, pfd.revents); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_recv_empty_sockets()); + + ret = connect(sd, (FAR const struct sockaddr *)&addr, sizeof(addr)); + TEST_ASSERT_EQUAL(-1, ret); + TEST_ASSERT_EQUAL(EISCONN, errno); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_recv_empty_sockets()); + + /* Send data to remote. */ + + data = "abcdeFG"; + datalen = strlen(data); + ret = write(sd, data, datalen); + TEST_ASSERT_EQUAL(datalen, ret); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(datalen, usrsocktest_daemon_get_send_bytes()); + + /* Close socket */ + + TEST_ASSERT_TRUE(close(sd) >= 0); + sd = -1; + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(datalen, usrsocktest_daemon_get_send_bytes()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_recv_empty_sockets()); + + /* Stopping daemon should succeed. */ + + TEST_ASSERT_EQUAL(OK, usrsocktest_daemon_stop()); + started = false; + TEST_ASSERT_EQUAL(-ENODEV, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(-ENODEV, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_endp_malloc_cnt); + TEST_ASSERT_EQUAL(0, usrsocktest_dcmd_malloc_cnt); +} + +/**************************************************************************** + * Name: DaemonAbort + * + * Description: + * Poll with daemon abort + * + * Input Parameters: + * dconf - socket daemon configuration + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +static void DaemonAbort(struct usrsocktest_daemon_conf_s *dconf) +{ + int flags; + ssize_t ret; + struct sockaddr_in addr; + struct pollfd pfd; + + /* Start test daemon. */ + + dconf->endpoint_addr = "127.0.0.1"; + dconf->endpoint_port = 255; + dconf->endpoint_recv_avail_from_start = false; + dconf->endpoint_recv_avail = 3; + dconf->endpoint_block_send = false; + dconf->endpoint_block_connect = true; + TEST_ASSERT_EQUAL(OK, usrsocktest_daemon_start(dconf)); + started = true; + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_active_sockets()); + + /* Open socket */ + + sd = socket(AF_INET, SOCK_STREAM, 0); + TEST_ASSERT_TRUE(sd >= 0); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_waiting_connect_sockets()); + + /* Make socket non-blocking */ + + flags = fcntl(sd, F_GETFL, 0); + TEST_ASSERT_TRUE(flags >= 0); + TEST_ASSERT_EQUAL(O_RDWR, flags & O_RDWR); + TEST_ASSERT_EQUAL(0, flags & O_NONBLOCK); + ret = fcntl(sd, F_SETFL, flags | O_NONBLOCK); + TEST_ASSERT_EQUAL(0, ret); + flags = fcntl(sd, F_GETFL, 0); + TEST_ASSERT_TRUE(flags >= 0); + TEST_ASSERT_EQUAL(O_RDWR, flags & O_RDWR); + TEST_ASSERT_EQUAL(O_NONBLOCK, flags & O_NONBLOCK); + + /* Poll for input (instant timeout). */ + + memset(&pfd, 0, sizeof(pfd)); + pfd.fd = sd; + pfd.events = POLLIN; + ret = poll(&pfd, 1, 0); + TEST_ASSERT_EQUAL(1, ret); + TEST_ASSERT_EQUAL(0, pfd.revents & POLLERR); + TEST_ASSERT_EQUAL(POLLHUP, pfd.revents & POLLHUP); + TEST_ASSERT_EQUAL(POLLIN, pfd.revents & POLLIN); + TEST_ASSERT_EQUAL(0, pfd.revents & POLLOUT); + + /* Start non-blocking connect. */ + + inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr.s_addr); + addr.sin_family = AF_INET; + addr.sin_port = htons(255); + ret = connect(sd, (FAR const struct sockaddr *)&addr, sizeof(addr)); + TEST_ASSERT_EQUAL(-1, ret); + TEST_ASSERT_EQUAL(EINPROGRESS, errno); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_waiting_connect_sockets()); + + /* Poll for input (no timeout). Stop daemon forcefully. */ + + memset(&pfd, 0, sizeof(pfd)); + TEST_ASSERT_TRUE(usrsocktest_send_delayed_command('S', 100)); + pfd.fd = sd; + pfd.events = POLLOUT; + ret = poll(&pfd, 1, -1); + TEST_ASSERT_EQUAL(1, ret); + TEST_ASSERT_EQUAL(POLLERR, pfd.revents & POLLERR); + TEST_ASSERT_EQUAL(POLLHUP, pfd.revents & POLLHUP); + + /* Stopping daemon should succeed. */ + + TEST_ASSERT_EQUAL(OK, usrsocktest_daemon_stop()); + started = false; + TEST_ASSERT_EQUAL(-ENODEV, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(-ENODEV, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_endp_malloc_cnt); + TEST_ASSERT_EQUAL(0, usrsocktest_dcmd_malloc_cnt); + + /* Poll for input (no timeout). */ + + memset(&pfd, 0, sizeof(pfd)); + pfd.fd = sd; + pfd.events = POLLOUT; + ret = poll(&pfd, 1, -1); + TEST_ASSERT_EQUAL(1, ret); + TEST_ASSERT_EQUAL(POLLERR, pfd.revents & POLLERR); + TEST_ASSERT_EQUAL(POLLHUP, pfd.revents & POLLHUP); + TEST_ASSERT_EQUAL(0, pfd.revents & POLLIN); + TEST_ASSERT_EQUAL(0, pfd.revents & POLLOUT); + + /* Close socket */ + + TEST_ASSERT_TRUE(close(sd) >= 0); + sd = -1; + TEST_ASSERT_EQUAL(-ENODEV, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(-ENODEV, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(-ENODEV, usrsocktest_daemon_get_send_bytes()); + TEST_ASSERT_EQUAL(-ENODEV, usrsocktest_daemon_get_num_recv_empty_sockets()); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +TEST_GROUP(Poll); + +/**************************************************************************** + * Name: Poll test group setup + * + * Description: + * Setup function executed before each testcase in this test group + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +TEST_SETUP(Poll) +{ + sd = -1; + started = false; +} + +/**************************************************************************** + * Name: Poll test group teardown + * + * Description: + * Setup function executed after each testcase in this test group + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +TEST_TEAR_DOWN(Poll) +{ + int ret; + if (sd >= 0) + { + ret = close(sd); + assert(ret >= 0); + } + if (started) + { + ret = usrsocktest_daemon_stop(); + assert(ret == OK); + } +} + +TEST(Poll, ConnectReceive) +{ + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + ConnectReceive(&usrsocktest_daemon_config); +} + +TEST(Poll, ConnectReceiveDelay) +{ + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + usrsocktest_daemon_config.delay_all_responses = true; + ConnectReceive(&usrsocktest_daemon_config); +} + +TEST(Poll, ConnectSend) +{ + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + ConnectSend(&usrsocktest_daemon_config); +} + +TEST(Poll, ConnectSendDelay) +{ + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + usrsocktest_daemon_config.delay_all_responses = true; + ConnectSend(&usrsocktest_daemon_config); +} + +TEST(Poll, DaemonAbort) +{ + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + DaemonAbort(&usrsocktest_daemon_config); +} + +TEST(Poll, DaemonAbortDelay) +{ + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + usrsocktest_daemon_config.delay_all_responses = true; + DaemonAbort(&usrsocktest_daemon_config); +} diff --git a/tests/unity_usrsock/remote_disconnect.c b/tests/unity_usrsock/remote_disconnect.c new file mode 100644 index 000000000..1baec7ab8 --- /dev/null +++ b/tests/unity_usrsock/remote_disconnect.c @@ -0,0 +1,1055 @@ +/**************************************************************************** + * apps/examples/unity_usrsock/remote_disconnect.c + * Remote end disconnects + * + * Copyright (C) 2015 Haltian Ltd. All rights reserved. + * Authors: Roman Saveljev + * Jussi Kivilinna + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "defines.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ +static const uint8_t tevents[] = { POLLIN, POLLOUT, POLLOUT|POLLIN, 0}; +static bool started; +static int sd; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: ConnectReceive + * + * Description: + * Remote end is unreachable + * + * Input Parameters: + * dconf - socket daemon configuration + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +static void Unreachable(struct usrsocktest_daemon_conf_s *dconf) +{ + ssize_t ret; + struct sockaddr_in addr; + int flags; + struct pollfd pfd; + + /* Start test daemon. */ + + dconf->endpoint_addr = "127.0.0.1"; + dconf->endpoint_port = 255; + dconf->endpoint_block_connect = true; + dconf->endpoint_block_send = true; + dconf->endpoint_recv_avail_from_start = false; + dconf->endpoint_recv_avail = 7; + TEST_ASSERT_EQUAL(OK, usrsocktest_daemon_start(dconf)); + started = true; + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_active_sockets()); + + /* Open socket */ + + sd = socket(AF_INET, SOCK_STREAM, 0); + TEST_ASSERT_TRUE(sd >= 0); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_waiting_connect_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_recv_empty_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_unreachable_sockets()); + + /* Try connect, connection not accepted. */ + + inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr.s_addr); + addr.sin_family = AF_INET; + addr.sin_port = htons(255); + TEST_ASSERT_TRUE(usrsocktest_send_delayed_command('F', 100)); + ret = connect(sd, (FAR const struct sockaddr *)&addr, sizeof(addr)); + TEST_ASSERT_EQUAL(-1, ret); + TEST_ASSERT_EQUAL(ECONNREFUSED, errno); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_waiting_connect_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_unreachable_sockets()); + + /* Close socket */ + + TEST_ASSERT_TRUE(close(sd) >= 0); + sd = -1; + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_unreachable_sockets()); + + /* Open socket */ + + sd = socket(AF_INET, SOCK_STREAM, 0); + TEST_ASSERT_TRUE(sd >= 0); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_waiting_connect_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_recv_empty_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_unreachable_sockets()); + + /* Make socket non-blocking */ + + flags = fcntl(sd, F_GETFL, 0); + TEST_ASSERT_TRUE(flags >= 0); + TEST_ASSERT_EQUAL(O_RDWR, flags & O_RDWR); + TEST_ASSERT_EQUAL(0, flags & O_NONBLOCK); + ret = fcntl(sd, F_SETFL, flags | O_NONBLOCK); + TEST_ASSERT_EQUAL(0, ret); + flags = fcntl(sd, F_GETFL, 0); + TEST_ASSERT_TRUE(flags >= 0); + TEST_ASSERT_EQUAL(O_RDWR, flags & O_RDWR); + TEST_ASSERT_EQUAL(O_NONBLOCK, flags & O_NONBLOCK); + + /* Try connect, connection in progress. */ + + inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr.s_addr); + addr.sin_family = AF_INET; + addr.sin_port = htons(255); + ret = connect(sd, (FAR const struct sockaddr *)&addr, sizeof(addr)); + TEST_ASSERT_EQUAL(-1, ret); + TEST_ASSERT_EQUAL(EINPROGRESS, errno); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_waiting_connect_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_unreachable_sockets()); + + /* Disconnect pending connections. */ + + TEST_ASSERT_TRUE(usrsocktest_send_delayed_command('F', 100)); + + /* Poll for input (no timeout). */ + + memset(&pfd, 0, sizeof(pfd)); + pfd.fd = sd; + pfd.events = POLLIN; + ret = poll(&pfd, 1, -1); + TEST_ASSERT_EQUAL(1, ret); + TEST_ASSERT_EQUAL(POLLERR, pfd.revents & POLLERR); + TEST_ASSERT_EQUAL(POLLHUP, pfd.revents & POLLHUP); + TEST_ASSERT_EQUAL(0, pfd.revents & POLLIN); + TEST_ASSERT_EQUAL(0, pfd.revents & POLLOUT); + + /* Close socket */ + + TEST_ASSERT_TRUE(close(sd) >= 0); + sd = -1; + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + + /* Stopping daemon should succeed. */ + + TEST_ASSERT_EQUAL(OK, usrsocktest_daemon_stop()); + started = false; + TEST_ASSERT_EQUAL(-ENODEV, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(-ENODEV, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_endp_malloc_cnt); + TEST_ASSERT_EQUAL(0, usrsocktest_dcmd_malloc_cnt); + +} + +/**************************************************************************** + * Name: Send + * + * Description: + * Send and disconnect + * + * Input Parameters: + * dconf - socket daemon configuration + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +static void Send(struct usrsocktest_daemon_conf_s *dconf) +{ + ssize_t ret; + size_t datalen; + void *data; + struct sockaddr_in addr; + int count; + + /* Start test daemon. */ + + dconf->endpoint_addr = "127.0.0.1"; + dconf->endpoint_port = 255; + dconf->endpoint_block_connect = false; + dconf->endpoint_block_send = false; + dconf->endpoint_recv_avail_from_start = false; + dconf->endpoint_recv_avail = 7; + TEST_ASSERT_EQUAL(OK, usrsocktest_daemon_start(dconf)); + started = true; + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_active_sockets()); + + /* Open socket */ + + sd = socket(AF_INET, SOCK_STREAM, 0); + TEST_ASSERT_TRUE(sd >= 0); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_waiting_connect_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_recv_empty_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_unreachable_sockets()); + + /* Try connect, connection in progress. */ + + inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr.s_addr); + addr.sin_family = AF_INET; + addr.sin_port = htons(255); + ret = connect(sd, (FAR const struct sockaddr *)&addr, sizeof(addr)); + TEST_ASSERT_EQUAL(0, ret); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_waiting_connect_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_unreachable_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_remote_disconnected_sockets()); + + /* Disconnect connections. */ + + TEST_ASSERT_TRUE(usrsocktest_send_delayed_command('D', 0)); + for (count = 0; usrsocktest_daemon_get_num_connected_sockets() > 0; count++) + { + TEST_ASSERT_TRUE(count <= 3); + usleep(5 * 1000); + } + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_remote_disconnected_sockets()); + + for (count = 0; count < 2; count++) + { + /* Send data to remote */ + + data = "abcde"; + datalen = strlen("abcde"); + ret = write(sd, data, datalen); + TEST_ASSERT_EQUAL(-1, ret); + TEST_ASSERT_EQUAL(EPIPE, errno); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_remote_disconnected_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_send_bytes()); + } + + /* Close socket */ + + TEST_ASSERT_TRUE(close(sd) >= 0); + sd = -1; + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + + /* Stopping daemon should succeed. */ + + TEST_ASSERT_EQUAL(OK, usrsocktest_daemon_stop()); + started = false; + TEST_ASSERT_EQUAL(-ENODEV, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(-ENODEV, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_endp_malloc_cnt); + TEST_ASSERT_EQUAL(0, usrsocktest_dcmd_malloc_cnt); +} + +/**************************************************************************** + * Name: Send2 + * + * Description: + * Send and disconnect + * + * Input Parameters: + * dconf - socket daemon configuration + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +static void Send2(struct usrsocktest_daemon_conf_s *dconf) +{ + ssize_t ret; + size_t datalen; + void *data; + struct sockaddr_in addr; + int count; + + /* Start test daemon. */ + + dconf->endpoint_addr = "127.0.0.1"; + dconf->endpoint_port = 255; + dconf->endpoint_block_connect = false; + dconf->endpoint_block_send = true; + dconf->endpoint_recv_avail_from_start = false; + dconf->endpoint_recv_avail = 7; + TEST_ASSERT_EQUAL(OK, usrsocktest_daemon_start(dconf)); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_active_sockets()); + + /* Open socket */ + + sd = socket(AF_INET, SOCK_STREAM, 0); + TEST_ASSERT_TRUE(sd >= 0); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_waiting_connect_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_recv_empty_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_unreachable_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_remote_disconnected_sockets()); + + /* Try connect. */ + + inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr.s_addr); + addr.sin_family = AF_INET; + addr.sin_port = htons(255); + ret = connect(sd, (FAR const struct sockaddr *)&addr, sizeof(addr)); + TEST_ASSERT_EQUAL(0, ret); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_waiting_connect_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_unreachable_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_remote_disconnected_sockets()); + + /* Disconnect connections with delay. */ + + TEST_ASSERT_TRUE(usrsocktest_send_delayed_command('D', 100)); + + for (count = 0; count < 2; count++) + { + /* Send data to remote */ + + data = "abcde"; + datalen = strlen("abcde"); + ret = write(sd, data, datalen); + TEST_ASSERT_EQUAL(-1, ret); + TEST_ASSERT_EQUAL(EPIPE, errno); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_remote_disconnected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_send_bytes()); + } + + /* Close socket */ + + TEST_ASSERT_TRUE(close(sd) >= 0); + sd = -1; + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + + /* Stopping daemon should succeed. */ + + TEST_ASSERT_EQUAL(OK, usrsocktest_daemon_stop()); + started = false; + TEST_ASSERT_EQUAL(-ENODEV, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(-ENODEV, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_endp_malloc_cnt); + TEST_ASSERT_EQUAL(0, usrsocktest_dcmd_malloc_cnt); +} + +/**************************************************************************** + * Name: Receive + * + * Description: + * Receive and disconnect + * + * Input Parameters: + * dconf - socket daemon configuration + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +static void Receive(struct usrsocktest_daemon_conf_s *dconf) +{ + ssize_t ret; + size_t datalen; + void *data; + struct sockaddr_in addr; + char databuf[5]; + int count; + + /* Start test daemon. */ + + dconf->endpoint_addr = "127.0.0.1"; + dconf->endpoint_port = 255; + dconf->endpoint_block_connect = false; + dconf->endpoint_block_send = false; + dconf->endpoint_recv_avail_from_start = true; + dconf->endpoint_recv_avail = 1; + TEST_ASSERT_EQUAL(OK, usrsocktest_daemon_start(dconf)); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_active_sockets()); + + /* Open socket */ + + sd = socket(AF_INET, SOCK_STREAM, 0); + TEST_ASSERT_TRUE(sd >= 0); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_waiting_connect_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_recv_empty_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_unreachable_sockets()); + + /* Try connect. */ + + inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr.s_addr); + addr.sin_family = AF_INET; + addr.sin_port = htons(255); + ret = connect(sd, (FAR const struct sockaddr *)&addr, sizeof(addr)); + TEST_ASSERT_EQUAL(0, ret); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_waiting_connect_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_unreachable_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_remote_disconnected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_recv_empty_sockets()); + + /* Disconnect connections. */ + + TEST_ASSERT_TRUE(usrsocktest_send_delayed_command('D', 0)); + for (count = 0; usrsocktest_daemon_get_num_connected_sockets() > 0; count++) + { + TEST_ASSERT_TRUE(count <= 3); + usleep(5 * 1000); + } + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_remote_disconnected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_recv_empty_sockets()); + + for (count = 0; count < 2; count++) + { + /* Read from closed remote (EOF) */ + + data = databuf; + datalen = sizeof(databuf); + ret = read(sd, data, datalen); + TEST_ASSERT_EQUAL(0, ret); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_remote_disconnected_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_recv_bytes()); + } + + /* Close socket */ + + TEST_ASSERT_TRUE(close(sd) >= 0); + sd = -1; + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + + /* Stopping daemon should succeed. */ + + TEST_ASSERT_EQUAL(OK, usrsocktest_daemon_stop()); + started = false; + TEST_ASSERT_EQUAL(-ENODEV, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(-ENODEV, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_endp_malloc_cnt); + TEST_ASSERT_EQUAL(0, usrsocktest_dcmd_malloc_cnt); +} + +/**************************************************************************** + * Name: Receive2 + * + * Description: + * Receive and disconnect + * + * Input Parameters: + * dconf - socket daemon configuration + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +static void Receive2(struct usrsocktest_daemon_conf_s *dconf) +{ + ssize_t ret; + size_t datalen; + void *data; + struct sockaddr_in addr; + char databuf[5]; + int count; + + /* Start test daemon. */ + + dconf->endpoint_addr = "127.0.0.1"; + dconf->endpoint_port = 255; + dconf->endpoint_block_connect = false; + dconf->endpoint_block_send = true; + dconf->endpoint_recv_avail_from_start = false; + dconf->endpoint_recv_avail = 7; + TEST_ASSERT_EQUAL(OK, usrsocktest_daemon_start(dconf)); + started = true; + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_active_sockets()); + + /* Open socket */ + + sd = socket(AF_INET, SOCK_STREAM, 0); + TEST_ASSERT_TRUE(sd >= 0); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_waiting_connect_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_recv_empty_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_unreachable_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_remote_disconnected_sockets()); + + /* Try connect. */ + + inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr.s_addr); + addr.sin_family = AF_INET; + addr.sin_port = htons(255); + ret = connect(sd, (FAR const struct sockaddr *)&addr, sizeof(addr)); + TEST_ASSERT_EQUAL(0, ret); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_waiting_connect_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_unreachable_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_remote_disconnected_sockets()); + + /* Disconnect connections with delay. */ + + TEST_ASSERT_TRUE(usrsocktest_send_delayed_command('D', 100)); + + for (count = 0; count < 2; count++) + { + /* Read from closed remote (EOF) */ + + data = databuf; + datalen = sizeof(databuf); + ret = read(sd, data, datalen); + TEST_ASSERT_EQUAL(0, ret); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_remote_disconnected_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_recv_bytes()); + } + + /* Close socket */ + + TEST_ASSERT_TRUE(close(sd) >= 0); + sd = -1; + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + + /* Stopping daemon should succeed. */ + + TEST_ASSERT_EQUAL(OK, usrsocktest_daemon_stop()); + started = false; + TEST_ASSERT_EQUAL(-ENODEV, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(-ENODEV, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_endp_malloc_cnt); + TEST_ASSERT_EQUAL(0, usrsocktest_dcmd_malloc_cnt); +} + +/**************************************************************************** + * Name: Poll + * + * Description: + * Poll and disconnect + * + * Input Parameters: + * dconf - socket daemon configuration + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +static void Poll(struct usrsocktest_daemon_conf_s *dconf) +{ + ssize_t ret; + struct sockaddr_in addr; + int flags; + struct pollfd pfd; + + /* Start test daemon. */ + + dconf->endpoint_addr = "127.0.0.1"; + dconf->endpoint_port = 255; + dconf->endpoint_recv_avail_from_start = false; + dconf->endpoint_recv_avail = 3; + dconf->endpoint_block_send = false; + dconf->endpoint_block_connect = true; + TEST_ASSERT_EQUAL(OK, usrsocktest_daemon_start(dconf)); + started = true; + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_active_sockets()); + + /* Open socket */ + + sd = socket(AF_INET, SOCK_STREAM, 0); + TEST_ASSERT_TRUE(sd >= 0); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_waiting_connect_sockets()); + + /* Make socket non-blocking */ + + flags = fcntl(sd, F_GETFL, 0); + TEST_ASSERT_TRUE(flags >= 0); + TEST_ASSERT_EQUAL(O_RDWR, flags & O_RDWR); + TEST_ASSERT_EQUAL(0, flags & O_NONBLOCK); + ret = fcntl(sd, F_SETFL, flags | O_NONBLOCK); + TEST_ASSERT_EQUAL(0, ret); + flags = fcntl(sd, F_GETFL, 0); + TEST_ASSERT_TRUE(flags >= 0); + TEST_ASSERT_EQUAL(O_RDWR, flags & O_RDWR); + TEST_ASSERT_EQUAL(O_NONBLOCK, flags & O_NONBLOCK); + + /* Poll for input (instant timeout). */ + + memset(&pfd, 0, sizeof(pfd)); + pfd.fd = sd; + pfd.events = POLLIN; + ret = poll(&pfd, 1, 0); + TEST_ASSERT_EQUAL(1, ret); + TEST_ASSERT_EQUAL(0, pfd.revents & POLLERR); + TEST_ASSERT_EQUAL(POLLHUP, pfd.revents & POLLHUP); + TEST_ASSERT_EQUAL(POLLIN, pfd.revents & POLLIN); + TEST_ASSERT_EQUAL(0, pfd.revents & POLLOUT); + + /* Start non-blocking connect. */ + + inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr.s_addr); + addr.sin_family = AF_INET; + addr.sin_port = htons(255); + ret = connect(sd, (FAR const struct sockaddr *)&addr, sizeof(addr)); + TEST_ASSERT_EQUAL(-1, ret); + TEST_ASSERT_EQUAL(EINPROGRESS, errno); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_waiting_connect_sockets()); + + /* Poll for input/output (no timeout). Fail connection. */ + + memset(&pfd, 0, sizeof(pfd)); + TEST_ASSERT_TRUE(usrsocktest_send_delayed_command('F', 100)); + pfd.fd = sd; + pfd.events = POLLOUT | POLLIN; + ret = poll(&pfd, 1, -1); + TEST_ASSERT_EQUAL(1, ret); + TEST_ASSERT_EQUAL(POLLERR, pfd.revents & POLLERR); + TEST_ASSERT_EQUAL(POLLHUP, pfd.revents & POLLHUP); + TEST_ASSERT_EQUAL(0, pfd.revents & POLLIN); + TEST_ASSERT_EQUAL(0, pfd.revents & POLLOUT); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_remote_disconnected_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_unreachable_sockets()); + + /* Close socket */ + + TEST_ASSERT_TRUE(close(sd) >= 0); + sd = -1; + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + + /* Stopping daemon should succeed. */ + + TEST_ASSERT_EQUAL(OK, usrsocktest_daemon_stop()); + started = false; + TEST_ASSERT_EQUAL(-ENODEV, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(-ENODEV, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_endp_malloc_cnt); + TEST_ASSERT_EQUAL(0, usrsocktest_dcmd_malloc_cnt); +} + +/**************************************************************************** + * Name: Poll2 + * + * Description: + * Poll and disconnect + * + * Input Parameters: + * dconf - socket daemon configuration + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +static void Poll2(struct usrsocktest_daemon_conf_s *dconf) +{ + ssize_t ret; + size_t datalen; + void *data; + struct sockaddr_in addr; + char databuf[5]; + int flags; + struct pollfd pfd; + int count; + const uint8_t *events = tevents; + + /* Start test daemon. */ + + dconf->endpoint_addr = "127.0.0.1"; + dconf->endpoint_port = 255; + dconf->endpoint_recv_avail_from_start = false; + dconf->endpoint_recv_avail = 3; + dconf->endpoint_block_send = true; + dconf->endpoint_block_connect = false; + TEST_ASSERT_EQUAL(OK, usrsocktest_daemon_start(dconf)); + started = true; + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_active_sockets()); + + do + { + TEST_ASSERT_TRUE(*events == POLLIN || *events == POLLOUT || *events == (POLLOUT|POLLIN)); + + /* Open socket */ + + sd = socket(AF_INET, SOCK_STREAM, 0); + TEST_ASSERT_TRUE(sd >= 0); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_waiting_connect_sockets()); + + /* Make socket non-blocking */ + + flags = fcntl(sd, F_GETFL, 0); + TEST_ASSERT_TRUE(flags >= 0); + TEST_ASSERT_EQUAL(O_RDWR, flags & O_RDWR); + TEST_ASSERT_EQUAL(0, flags & O_NONBLOCK); + ret = fcntl(sd, F_SETFL, flags | O_NONBLOCK); + TEST_ASSERT_EQUAL(0, ret); + flags = fcntl(sd, F_GETFL, 0); + TEST_ASSERT_TRUE(flags >= 0); + TEST_ASSERT_EQUAL(O_RDWR, flags & O_RDWR); + TEST_ASSERT_EQUAL(O_NONBLOCK, flags & O_NONBLOCK); + + /* Poll for input (instant timeout). */ + + memset(&pfd, 0, sizeof(pfd)); + pfd.fd = sd; + pfd.events = *events; + ret = poll(&pfd, 1, 0); + TEST_ASSERT_EQUAL(1, ret); + TEST_ASSERT_EQUAL(0, pfd.revents & POLLERR); + TEST_ASSERT_EQUAL(POLLHUP, pfd.revents & POLLHUP); + TEST_ASSERT_EQUAL(*events & POLLIN, pfd.revents & POLLIN); + TEST_ASSERT_EQUAL(0, pfd.revents & POLLOUT); + + /* Start non-blocking connect. */ + + inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr.s_addr); + addr.sin_family = AF_INET; + addr.sin_port = htons(255); + ret = connect(sd, (FAR const struct sockaddr *)&addr, sizeof(addr)); + if (!dconf->delay_all_responses) + { + TEST_ASSERT_EQUAL(0, ret); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_waiting_connect_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_recv_empty_sockets()); + } + else + { + TEST_ASSERT_EQUAL(-1, ret); + TEST_ASSERT_EQUAL(EINPROGRESS, errno); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + + for (count = 0; usrsocktest_daemon_get_num_connected_sockets() != 1; count++) + { + TEST_ASSERT_TRUE(count <= 3); + usleep(25 * 1000); + } + + ret = connect(sd, (FAR const struct sockaddr *)&addr, sizeof(addr)); + TEST_ASSERT_EQUAL(-1, ret); + TEST_ASSERT_EQUAL(EISCONN, errno); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_recv_empty_sockets()); + } + + /* Poll for output (no timeout). Close connection. */ + + memset(&pfd, 0, sizeof(pfd)); + TEST_ASSERT_TRUE(usrsocktest_send_delayed_command('D', 100)); + pfd.fd = sd; + pfd.events = *events; + ret = poll(&pfd, 1, -1); + TEST_ASSERT_EQUAL(1, ret); + TEST_ASSERT_EQUAL(0, pfd.revents & POLLERR); + TEST_ASSERT_EQUAL(POLLHUP, pfd.revents & POLLHUP); + TEST_ASSERT_EQUAL(*events & POLLIN, pfd.revents & POLLIN); + TEST_ASSERT_EQUAL(0, pfd.revents & POLLOUT); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_remote_disconnected_sockets()); + + for (count = 0; count < 2; count++) + { + /* Read from closed remote (EOF) */ + + data = databuf; + datalen = sizeof(databuf); + ret = read(sd, data, datalen); + TEST_ASSERT_EQUAL(0, ret); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_remote_disconnected_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_recv_bytes()); + } + + for (count = 0; count < 2; count++) + { + /* Send data to remote */ + + data = "abcde"; + datalen = strlen("abcde"); + ret = write(sd, data, datalen); + TEST_ASSERT_EQUAL(-1, ret); + TEST_ASSERT_EQUAL(EPIPE, errno); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(1, usrsocktest_daemon_get_num_remote_disconnected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_send_bytes()); + } + + /* Close socket */ + + TEST_ASSERT_TRUE(close(sd) >= 0); + sd = -1; + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_connected_sockets()); + + events++; + } + while (*events); + + /* Stopping daemon should succeed. */ + + TEST_ASSERT_EQUAL(OK, usrsocktest_daemon_stop()); + started = false; + TEST_ASSERT_EQUAL(-ENODEV, usrsocktest_daemon_get_num_active_sockets()); + TEST_ASSERT_EQUAL(-ENODEV, usrsocktest_daemon_get_num_connected_sockets()); + TEST_ASSERT_EQUAL(0, usrsocktest_endp_malloc_cnt); + TEST_ASSERT_EQUAL(0, usrsocktest_dcmd_malloc_cnt); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +TEST_GROUP(RemoteDisconnect); + +/**************************************************************************** + * Name: RemoteDisconnect test group setup + * + * Description: + * Setup function executed before each testcase in this test group + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +TEST_SETUP(RemoteDisconnect) +{ + sd = -1; + started = false; +} + +/**************************************************************************** + * Name: RemoteDisconnect test group teardown + * + * Description: + * Setup function executed after each testcase in this test group + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +TEST_TEAR_DOWN(RemoteDisconnect) +{ + int ret; + if (sd >= 0) + { + ret = close(sd); + assert(ret >= 0); + } + if (started) + { + ret = usrsocktest_daemon_stop(); + assert(ret == OK); + } +} + +TEST(RemoteDisconnect, Unreachable) +{ + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + Unreachable(&usrsocktest_daemon_config); +} + +TEST(RemoteDisconnect, UnreachableDelay) +{ + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + usrsocktest_daemon_config.delay_all_responses = true; + Unreachable(&usrsocktest_daemon_config); +} + +TEST(RemoteDisconnect, Send) +{ + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + Send(&usrsocktest_daemon_config); +} + +TEST(RemoteDisconnect, SendDelay) +{ + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + usrsocktest_daemon_config.delay_all_responses = true; + Send(&usrsocktest_daemon_config); +} + +TEST(RemoteDisconnect, Send2) +{ + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + Send2(&usrsocktest_daemon_config); +} + +TEST(RemoteDisconnect, Send2Delay) +{ + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + usrsocktest_daemon_config.delay_all_responses = true; + Send2(&usrsocktest_daemon_config); +} + +TEST(RemoteDisconnect, Receive) +{ + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + Receive(&usrsocktest_daemon_config); +} + +TEST(RemoteDisconnect, ReceiveDelay) +{ + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + usrsocktest_daemon_config.delay_all_responses = true; + Receive(&usrsocktest_daemon_config); +} + +TEST(RemoteDisconnect, Receive2) +{ + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + Receive2(&usrsocktest_daemon_config); +} + +TEST(RemoteDisconnect, Receive2Delay) +{ + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + usrsocktest_daemon_config.delay_all_responses = true; + Receive2(&usrsocktest_daemon_config); +} + +TEST(RemoteDisconnect, Poll) +{ + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + Poll(&usrsocktest_daemon_config); +} + +TEST(RemoteDisconnect, PollDelay) +{ + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + usrsocktest_daemon_config.delay_all_responses = true; + Poll(&usrsocktest_daemon_config); +} + +TEST(RemoteDisconnect, Poll2) +{ + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + Poll2(&usrsocktest_daemon_config); +} + +TEST(RemoteDisconnect, Poll2Delay) +{ + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + usrsocktest_daemon_config.delay_all_responses = true; + Poll2(&usrsocktest_daemon_config); +} diff --git a/tests/unity_usrsock/unity_usrsock_main.c b/tests/unity_usrsock/unity_usrsock_main.c new file mode 100644 index 000000000..6025ee804 --- /dev/null +++ b/tests/unity_usrsock/unity_usrsock_main.c @@ -0,0 +1,161 @@ +/**************************************************************************** + * apps/examples/unity_usrsock/unity_usrsock_main.c + * Main function for Unity test application + * + * Copyright (C) 2015 Haltian Ltd. All rights reserved. + * Author: Roman Saveljev + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ +#include +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ +static void runAllTests(void); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ +int usrsocktest_endp_malloc_cnt = 0; +int usrsocktest_dcmd_malloc_cnt = 0; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static void get_mallinfo(struct mallinfo *mem) +{ +#ifdef CONFIG_CAN_PASS_STRUCTS + *mem = mallinfo(); +#else + (void)mallinfo(mem); +#endif +} + +static void print_mallinfo(const struct mallinfo *mem, const char *title) +{ + if (title) + printf("%s:\n", title); + printf(" %11s%11s%11s%11s\n", "total", "used", "free", "largest"); + printf("Mem: %11d%11d%11d%11d\n", + mem->arena, mem->uordblks, mem->fordblks, mem->mxordblk); +} + +/**************************************************************************** + * Name: runAllTests + * + * Description: + * Sequentially runs all included test groups + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +static void runAllTests(void) +{ + RUN_TEST_GROUP(CharDev); + RUN_TEST_GROUP(NoDaemon); + RUN_TEST_GROUP(BasicDaemon); + RUN_TEST_GROUP(BasicConnect); + RUN_TEST_GROUP(BasicConnectDelay); + RUN_TEST_GROUP(NoBlockConnect); + RUN_TEST_GROUP(BasicSend); + RUN_TEST_GROUP(NoBlockSend); + RUN_TEST_GROUP(BlockSend); + RUN_TEST_GROUP(NoBlockRecv); + RUN_TEST_GROUP(BlockRecv); + RUN_TEST_GROUP(RemoteDisconnect); + RUN_TEST_GROUP(BasicSetSockOpt); + RUN_TEST_GROUP(BasicGetSockOpt); + RUN_TEST_GROUP(BasicGetSockName); + RUN_TEST_GROUP(WakeWithSignal); + RUN_TEST_GROUP(MultiThread); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: unity_pwrbtn_main + * + * Description: + * Application entry point + * + * Input Parameters: + * argc - number of arguments + * argv - arguments themselves + * + * Returned Value: + * exit status + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +int unity_usrsock_main(int argc, const char* argv[]) +{ + int ret; + struct mallinfo mem_before, mem_after; + + get_mallinfo(&mem_before); + + ret = UnityMain(argc, argv, runAllTests); + + get_mallinfo(&mem_after); + + print_mallinfo(&mem_before, "HEAP BEFORE TESTS"); + print_mallinfo(&mem_after, "HEAP AFTER TESTS"); + + return ret; +} diff --git a/tests/unity_usrsock/usrsocktest_daemon.c b/tests/unity_usrsock/usrsocktest_daemon.c new file mode 100644 index 000000000..ba47bef06 --- /dev/null +++ b/tests/unity_usrsock/usrsocktest_daemon.c @@ -0,0 +1,1930 @@ +/**************************************************************************** + * examples/nettest/usrsocktest_daemon.c + * + * Copyright (C) 2015 Haltian Ltd. All rights reserved. + * Author: Jussi Kivilinna + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "defines.h" + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +#ifndef dbg + #define dbg _warn +#endif + +#define TEST_SOCKET_SOCKID_BASE 10000U +#define TEST_SOCKET_COUNT 8 + +#ifndef ARRAY_SIZE +# define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) +#endif + +#define noinline __attribute__((noinline)) + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct test_socket_s { + bool opened:1; + bool connected:1; + bool blocked_connect:1; + bool block_send:1; + bool connect_refused:1; + bool disconnected:1; + int recv_avail_bytes; + FAR void *endp; + struct usrsock_message_req_ack_s pending_resp; +}; + +struct delayed_cmd_s { + sq_entry_t node; + pthread_t tid; + sem_t startsem; + int pipefd; + uint16_t delay_msec; + char cmd; +}; + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static struct daemon_priv_s { + const struct usrsocktest_daemon_conf_s *conf; + pthread_t tid; + bool joined; + + int pipefd[2]; + sem_t wakewaitsem; + unsigned int sockets_active; + unsigned int sockets_connected; + unsigned int sockets_waiting_connect; + unsigned int sockets_recv_empty; + unsigned int sockets_not_connected_refused; + unsigned int sockets_remote_disconnected; + size_t total_send_bytes; + size_t total_recv_bytes; + bool do_not_poll_usrsock; + + struct test_socket_s test_sockets[TEST_SOCKET_COUNT]; + sq_queue_t delayed_cmd_threads; +} daemon = { + .joined = true, + .conf = NULL, +}; + +static pthread_mutex_t daemon_mutex = PTHREAD_MUTEX_INITIALIZER; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +const struct usrsocktest_daemon_conf_s usrsocktest_daemon_defconf = + USRSOCKTEST_DAEMON_CONF_DEFAULTS; +struct usrsocktest_daemon_conf_s usrsocktest_daemon_config; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static int test_socket_alloc(FAR struct daemon_priv_s *priv) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(priv->test_sockets); i++) + { + FAR struct test_socket_s *tsock = &priv->test_sockets[i]; + + if (!tsock->opened) + { + memset(tsock, 0, sizeof(*tsock)); + tsock->opened = true; + tsock->block_send = priv->conf->endpoint_block_send; + tsock->recv_avail_bytes = + priv->conf->endpoint_recv_avail_from_start ? + priv->conf->endpoint_recv_avail : 0; + priv->sockets_active++; + if (tsock->recv_avail_bytes == 0) + priv->sockets_recv_empty++; + return i + TEST_SOCKET_SOCKID_BASE; + } + } + + return -1; +} + +static FAR struct test_socket_s *test_socket_get(FAR struct daemon_priv_s *priv, + int sockid) +{ + if (sockid < TEST_SOCKET_SOCKID_BASE) + return NULL; + + sockid -= TEST_SOCKET_SOCKID_BASE; + if (sockid >= ARRAY_SIZE(priv->test_sockets)) + return NULL; + + return &priv->test_sockets[sockid]; +} + +static int test_socket_free(FAR struct daemon_priv_s *priv, int sockid) +{ + FAR struct test_socket_s *tsock = test_socket_get(priv, sockid); + + if (!tsock) + return -EBADFD; + + if (!tsock->opened) + return -EFAULT; + + if (tsock->connected) + { + priv->sockets_connected--; + tsock->connected = false; + } + if (tsock->blocked_connect) + { + priv->sockets_waiting_connect--; + tsock->blocked_connect = false; + } + if (tsock->endp) + { + free(tsock->endp); + usrsocktest_endp_malloc_cnt--; + tsock->endp = NULL; + } + if (tsock->recv_avail_bytes == 0) + { + priv->sockets_recv_empty--; + } + if (tsock->connect_refused) + { + priv->sockets_not_connected_refused--; + } + if (tsock->disconnected) + { + priv->sockets_remote_disconnected--; + } + + tsock->opened = false; + priv->sockets_active--; + + return 0; +} + +static int tsock_send_event(int fd, FAR struct daemon_priv_s *priv, + FAR struct test_socket_s *tsock, int events) +{ + FAR struct usrsock_message_socket_event_s event = {}; + ssize_t wlen; + int i; + + event.head.flags = USRSOCK_MESSAGE_FLAG_EVENT; + event.head.msgid = USRSOCK_MESSAGE_SOCKET_EVENT; + + for (i = 0; i < ARRAY_SIZE(priv->test_sockets); i++) + { + if (tsock == &priv->test_sockets[i]) + break; + } + + if (i == ARRAY_SIZE(priv->test_sockets)) + return -EINVAL; + + event.usockid = i + TEST_SOCKET_SOCKID_BASE; + event.events = events; + + wlen = write(fd, &event, sizeof(event)); + if (wlen < 0) + return -errno; + if (wlen != sizeof(event)) + return -ENOSPC; + + return OK; +} + + +static FAR void *find_endpoint(FAR struct daemon_priv_s *priv, in_addr_t ipaddr) +{ + FAR struct sockaddr_in *endpaddr; + int ok; + + endpaddr = malloc(sizeof(*endpaddr)); + usrsocktest_endp_malloc_cnt++; + assert(endpaddr); + + ok = inet_pton(AF_INET, priv->conf->endpoint_addr, &endpaddr->sin_addr.s_addr); + endpaddr->sin_family = AF_INET; + endpaddr->sin_port = htons(priv->conf->endpoint_port); + assert(ok); + + if (endpaddr->sin_addr.s_addr == ipaddr) + return endpaddr; + + free(endpaddr); + usrsocktest_endp_malloc_cnt--; + return NULL; +} + +static bool endpoint_connect(FAR struct daemon_priv_s *priv, FAR void *endp, + uint16_t port) +{ + FAR struct sockaddr_in *endpaddr = endp; + + if (endpaddr->sin_port == port) + return true; + else + return false; +} + +static void get_endpoint_sockaddr(FAR void *endp, FAR struct sockaddr_in *endpaddr) +{ + *endpaddr = *(FAR struct sockaddr_in *)endp; +} + +static ssize_t +read_req(int fd, FAR const struct usrsock_request_common_s *common_hdr, + void *req, size_t reqsize) +{ + ssize_t rlen; + int err; + + rlen = read(fd, (uint8_t *)req + sizeof(*common_hdr), + reqsize - sizeof(*common_hdr)); + if (rlen < 0) + { + err = errno; + dbg("Error reading %d bytes of request: ret=%d, errno=%d\n", + reqsize - sizeof(*common_hdr), (int)rlen, errno); + return -err; + } + if (rlen + sizeof(*common_hdr) != reqsize) + { + return -EMSGSIZE; + } + + return rlen; +} + +static int socket_request(int fd, FAR struct daemon_priv_s *priv, + FAR void *hdrbuf) +{ + FAR struct usrsock_request_socket_s *req = hdrbuf; + struct usrsock_message_req_ack_s resp = {}; + int socketid; + ssize_t wlen; + + /* Validate input. */ + + if (req->domain != priv->conf->supported_domain) + { + socketid = -EAFNOSUPPORT; + } + else if (req->type != priv->conf->supported_type || + req->protocol != priv->conf->supported_protocol) + { + socketid = -EPROTONOSUPPORT; + } + else if (priv->sockets_active >= priv->conf->max_sockets) + { + socketid = -EMFILE; + } + else + { + /* Allocate socket. */ + + socketid = test_socket_alloc(priv); + if (socketid < 0) + socketid = -ENFILE; + } + + /* Prepare response. */ + + resp.head.msgid = USRSOCK_MESSAGE_RESPONSE_ACK; + resp.head.flags = 0; + resp.xid = req->head.xid; + resp.result = socketid; + + /* Send response. */ + + wlen = write(fd, &resp, sizeof(resp)); + if (wlen < 0) + return -errno; + if (wlen != sizeof(resp)) + return -ENOSPC; + + return OK; +} + +static int close_request(int fd, FAR struct daemon_priv_s *priv, + FAR void *hdrbuf) +{ + FAR struct usrsock_request_close_s *req = hdrbuf; + struct usrsock_message_req_ack_s resp = {}; + ssize_t wlen; + int ret; + + /* Check if this socket exists. */ + + ret = test_socket_free(priv, req->usockid); + + /* Prepare response. */ + + resp.head.msgid = USRSOCK_MESSAGE_RESPONSE_ACK; + resp.xid = req->head.xid; + if (priv->conf->delay_all_responses) + { + resp.head.flags = USRSOCK_MESSAGE_FLAG_REQ_IN_PROGRESS; + resp.result = -EAGAIN; + } + else + { + resp.head.flags = 0; + resp.result = ret; + } + + /* Send response. */ + + wlen = write(fd, &resp, sizeof(resp)); + if (wlen < 0) + return -errno; + if (wlen != sizeof(resp)) + return -ENOSPC; + + if (priv->conf->delay_all_responses) + { + pthread_mutex_unlock(&daemon_mutex); + usleep(50 * 1000); + pthread_mutex_lock(&daemon_mutex); + + /* Previous write was acknowledgment to request, informing that request + * is still in progress. Now write actual completion response. */ + + resp.result = ret; + resp.head.flags &= ~USRSOCK_MESSAGE_FLAG_REQ_IN_PROGRESS; + + wlen = write(fd, &resp, sizeof(resp)); + if (wlen < 0) + return -errno; + if (wlen != sizeof(resp)) + return -ENOSPC; + } + + return OK; +} + +static int connect_request(int fd, FAR struct daemon_priv_s *priv, + FAR void *hdrbuf) +{ + DEBUGASSERT(priv); + DEBUGASSERT(hdrbuf); + FAR struct usrsock_request_connect_s *req = hdrbuf; + struct sockaddr_in addr; + FAR struct test_socket_s *tsock; + struct usrsock_message_req_ack_s resp = {}; + ssize_t wlen, rlen; + int ret = 0; + + /* Check if this socket exists. */ + + tsock = test_socket_get(priv, req->usockid); + if (!tsock) + { + ret = -EBADFD; + goto prepare; + } + + /* Check if this socket is already connected. */ + + if (tsock->connected) + { + ret = -EISCONN; + goto prepare; + } + + /* Check if address size ok. */ + + if (req->addrlen > sizeof(addr)) + { + ret = -EFAULT; + goto prepare; + } + + /* Read address. */ + + rlen = read(fd, &addr, sizeof(addr)); + if (rlen < 0 || rlen < req->addrlen) + { + ret = -EFAULT; + goto prepare; + } + + /* Check address family. */ + + if (addr.sin_family != priv->conf->supported_domain) + { + ret = -EAFNOSUPPORT; + goto prepare; + } + + /* Check if there is endpoint with target address */ + + tsock->endp = find_endpoint(priv, addr.sin_addr.s_addr); + if (!tsock->endp) + { + ret = -ENETUNREACH; + goto prepare; + } + + /* Check if there is port open at endpoint */ + + if (!endpoint_connect(priv, tsock->endp, addr.sin_port)) + { + free(tsock->endp); + usrsocktest_endp_malloc_cnt--; + tsock->endp = NULL; + ret = -ECONNREFUSED; + goto prepare; + } + + ret = OK; + +prepare: + /* Prepare response. */ + + resp.xid = req->head.xid; + resp.head.msgid = USRSOCK_MESSAGE_RESPONSE_ACK; + resp.head.flags = 0; + + if (priv->conf->endpoint_block_connect) + { + resp.head.flags = USRSOCK_MESSAGE_FLAG_REQ_IN_PROGRESS; + resp.result = ret; + + /* Mark connection as blocked */ + + priv->sockets_waiting_connect++; + tsock->blocked_connect = true; + tsock->pending_resp = resp; + } + else if (priv->conf->delay_all_responses) + { + resp.head.flags = USRSOCK_MESSAGE_FLAG_REQ_IN_PROGRESS; + resp.result = -EINPROGRESS; + tsock->blocked_connect = false; + } + else + { + if (ret == OK) + { + priv->sockets_connected++; + tsock->connected = true; + } + + resp.head.flags = 0; + resp.result = ret; + tsock->blocked_connect = false; + } + + /* Send response. */ + + wlen = write(fd, &resp, sizeof(resp)); + if (wlen < 0) + return -errno; + if (wlen != sizeof(resp)) + return -ENOSPC; + + if (priv->conf->endpoint_block_connect) + { + tsock->pending_resp.head.flags &= ~USRSOCK_MESSAGE_FLAG_REQ_IN_PROGRESS; + } + else + { + int events; + + if (priv->conf->delay_all_responses) + { + pthread_mutex_unlock(&daemon_mutex); + usleep(50 * 1000); + pthread_mutex_lock(&daemon_mutex); + + /* Previous write was acknowledgment to request, informing that request + * is still in progress. Now write actual completion response. */ + + resp.result = ret; + + if (ret == OK) + { + priv->sockets_connected++; + tsock->connected = true; + } + + resp.head.flags &= ~USRSOCK_MESSAGE_FLAG_REQ_IN_PROGRESS; + + wlen = write(fd, &resp, sizeof(resp)); + if (wlen < 0) + return -errno; + if (wlen != sizeof(resp)) + return -ENOSPC; + } + + events = 0; + if (!tsock->block_send) + events |= USRSOCK_EVENT_SENDTO_READY; + if (tsock->recv_avail_bytes > 0) + events |= USRSOCK_EVENT_RECVFROM_AVAIL; + + if (events) + { + wlen = tsock_send_event(fd, priv, tsock, events); + if (wlen < 0) + return wlen; + } + } + + return OK; +} + +static int sendto_request(int fd, FAR struct daemon_priv_s *priv, + FAR void *hdrbuf) +{ + DEBUGASSERT(priv); + DEBUGASSERT(hdrbuf); + FAR struct usrsock_request_sendto_s *req = hdrbuf; + FAR struct test_socket_s *tsock; + struct usrsock_message_req_ack_s resp = {}; + ssize_t wlen, rlen; + int ret = 0; + uint8_t sendbuf[16]; + int sendbuflen = 0; + + /* Check if this socket exists. */ + + tsock = test_socket_get(priv, req->usockid); + if (!tsock) + { + ret = -EBADFD; + goto prepare; + } + + /* Check if this socket is connected. */ + + if (!tsock->connected) + { + ret = -ENOTCONN; + goto prepare; + } + + /* Check if address size non-zero. */ + + if (req->addrlen > 0) + { + ret = -EISCONN; /* connection-mode socket do not accept address */ + goto prepare; + } + + /* Can send? */ + + if (!tsock->block_send) + { + /* Check if request has data. */ + + if (req->buflen > 0) + { + sendbuflen = req->buflen; + if (sendbuflen > sizeof(sendbuf)) + sendbuflen = sizeof(sendbuf); + + /* Read data. */ + + rlen = read(fd, sendbuf, sendbuflen); + if (rlen < 0 || rlen < sendbuflen) + { + ret = -EFAULT; + goto prepare; + } + + /* Debug print */ + + dbg("got %d bytes of data: '%.*s'\n", sendbuflen, sendbuflen, sendbuf); + } + } + else + { + ret = -EAGAIN; /* blocked. */ + goto prepare; + } + + ret = sendbuflen; + +prepare: + /* Prepare response. */ + + resp.xid = req->head.xid; + resp.head.msgid = USRSOCK_MESSAGE_RESPONSE_ACK; + resp.head.flags = 0; + + if (priv->conf->delay_all_responses) + { + resp.head.flags = USRSOCK_MESSAGE_FLAG_REQ_IN_PROGRESS; + resp.result = -EINPROGRESS; + } + else + { + if (ret > 0) + { + priv->total_send_bytes += ret; + } + + resp.head.flags = 0; + resp.result = ret; + } + + /* Send response. */ + + wlen = write(fd, &resp, sizeof(resp)); + if (wlen < 0) + return -errno; + if (wlen != sizeof(resp)) + return -ENOSPC; + + if (priv->conf->delay_all_responses) + { + pthread_mutex_unlock(&daemon_mutex); + usleep(50 * 1000); + pthread_mutex_lock(&daemon_mutex); + + /* Previous write was acknowledgment to request, informing that request + * is still in progress. Now write actual completion response. */ + + resp.result = ret; + + if (ret > 0) + { + priv->total_send_bytes += ret; + } + + resp.head.flags &= ~USRSOCK_MESSAGE_FLAG_REQ_IN_PROGRESS; + + wlen = write(fd, &resp, sizeof(resp)); + if (wlen < 0) + return -errno; + if (wlen != sizeof(resp)) + return -ENOSPC; + } + + if (!tsock->block_send) + { + /* Let kernel-side know that there is space for more send data. */ + + wlen = tsock_send_event(fd, priv, tsock, USRSOCK_EVENT_SENDTO_READY); + if (wlen < 0) + return wlen; + } + + return OK; +} + +static int recvfrom_request(int fd, FAR struct daemon_priv_s *priv, + FAR void *hdrbuf) +{ + DEBUGASSERT(priv); + DEBUGASSERT(hdrbuf); + FAR struct usrsock_request_recvfrom_s *req = hdrbuf; + FAR struct test_socket_s *tsock; + struct usrsock_message_datareq_ack_s resp = {}; + ssize_t wlen; + size_t i; + int ret = 0; + size_t outbuflen; + struct sockaddr_in endpointaddr; + + /* Check if this socket exists. */ + + tsock = test_socket_get(priv, req->usockid); + if (!tsock) + { + ret = -EBADFD; + goto prepare; + } + + /* Check if this socket is connected. */ + + if (!tsock->connected) + { + ret = -ENOTCONN; + goto prepare; + } + + get_endpoint_sockaddr(tsock->endp, &endpointaddr); + + /* Do we have recv data available? */ + + if (tsock->recv_avail_bytes > 0) + { + outbuflen = req->max_buflen; + + if (outbuflen > tsock->recv_avail_bytes) + { + outbuflen = tsock->recv_avail_bytes; + } + } + else + { + ret = -EAGAIN; /* blocked. */ + goto prepare; + } + + ret = outbuflen; + +prepare: + /* Prepare response. */ + + resp.reqack.xid = req->head.xid; + resp.reqack.head.msgid = USRSOCK_MESSAGE_RESPONSE_DATA_ACK; + resp.reqack.head.flags = 0; + + if (priv->conf->delay_all_responses) + { + resp.reqack.head.flags = USRSOCK_MESSAGE_FLAG_REQ_IN_PROGRESS; + resp.reqack.result = -EINPROGRESS; + resp.valuelen = 0; + resp.valuelen_nontrunc = 0; + + /* Send ack response. */ + + wlen = write(fd, &resp, sizeof(resp)); + if (wlen < 0) + return -errno; + if (wlen != sizeof(resp)) + return -ENOSPC; + + pthread_mutex_unlock(&daemon_mutex); + usleep(50 * 1000); + pthread_mutex_lock(&daemon_mutex); + + /* Previous write was acknowledgment to request, informing that request + * is still in progress. Now write actual completion response. */ + + resp.reqack.head.msgid = USRSOCK_MESSAGE_RESPONSE_DATA_ACK; + resp.reqack.head.flags &= ~USRSOCK_MESSAGE_FLAG_REQ_IN_PROGRESS; + } + + resp.reqack.head.flags = 0; + resp.reqack.result = ret; + if (ret >= 0) + { + priv->total_recv_bytes += ret; + resp.valuelen_nontrunc = sizeof(endpointaddr); + resp.valuelen = resp.valuelen_nontrunc; + if (resp.valuelen > req->max_addrlen) + resp.valuelen = req->max_addrlen; + } + else + { + resp.valuelen = 0; + resp.valuelen_nontrunc = 0; + } + + /* Send response. */ + + wlen = write(fd, &resp, sizeof(resp)); + if (wlen < 0) + return -errno; + if (wlen != sizeof(resp)) + return -ENOSPC; + + if (resp.valuelen > 0) + { + /* Send address (value) */ + + wlen = write(fd, &endpointaddr, resp.valuelen); + if (wlen < 0) + return -errno; + if (wlen != resp.valuelen) + return -ENOSPC; + } + + if (resp.reqack.result > 0) + { + /* Send buffer */ + + for (i = 0; i < resp.reqack.result; i++) + { + char tmp = 'a' + i; + + tsock->recv_avail_bytes--; + + wlen = write(fd, &tmp, 1); + if (wlen < 0) + return -errno; + if (wlen != 1) + return -ENOSPC; + } + + if (tsock->recv_avail_bytes == 0) + priv->sockets_recv_empty++; + } + + + if (tsock->recv_avail_bytes > 0) + { + /* Let kernel-side know that there is more recv data. */ + + wlen = tsock_send_event(fd, priv, tsock, USRSOCK_EVENT_RECVFROM_AVAIL); + if (wlen < 0) + return wlen; + } + + return OK; +} + +static int setsockopt_request(int fd, FAR struct daemon_priv_s *priv, + FAR void *hdrbuf) +{ + DEBUGASSERT(priv); + DEBUGASSERT(hdrbuf); + FAR struct usrsock_request_setsockopt_s *req = hdrbuf; + FAR struct test_socket_s *tsock; + struct usrsock_message_req_ack_s resp = {}; + ssize_t wlen, rlen; + int ret = 0; + int value; + + /* Check if this socket exists. */ + + tsock = test_socket_get(priv, req->usockid); + if (!tsock) + { + ret = -EBADFD; + goto prepare; + } + + if (req->level != SOL_SOCKET) + { + dbg("setsockopt: level=%d not supported\n", req->level); + ret = -ENOPROTOOPT; + goto prepare; + } + + if (req->option != SO_REUSEADDR) + { + dbg("setsockopt: option=%d not supported\n", req->option); + ret = -ENOPROTOOPT; + goto prepare; + } + + if (req->valuelen < sizeof(value)) + { + ret = -EINVAL; + goto prepare; + } + + /* Read value. */ + + rlen = read(fd, &value, sizeof(value)); + if (rlen < 0 || rlen < sizeof(value)) + { + ret = -EFAULT; + goto prepare; + } + + /* Debug print */ + + dbg("setsockopt: option=%d value=%d\n", req->option, value); + + ret = OK; + +prepare: + /* Prepare response. */ + + resp.xid = req->head.xid; + resp.head.msgid = USRSOCK_MESSAGE_RESPONSE_ACK; + resp.head.flags = 0; + + if (priv->conf->delay_all_responses) + { + resp.head.flags = USRSOCK_MESSAGE_FLAG_REQ_IN_PROGRESS; + resp.result = -EINPROGRESS; + } + else + { + resp.head.flags = 0; + resp.result = ret; + } + + /* Send response. */ + + wlen = write(fd, &resp, sizeof(resp)); + if (wlen < 0) + return -errno; + if (wlen != sizeof(resp)) + return -ENOSPC; + + if (priv->conf->delay_all_responses) + { + pthread_mutex_unlock(&daemon_mutex); + usleep(50 * 1000); + pthread_mutex_lock(&daemon_mutex); + + /* Previous write was acknowledgment to request, informing that request + * is still in progress. Now write actual completion response. */ + + resp.result = ret; + resp.head.flags &= ~USRSOCK_MESSAGE_FLAG_REQ_IN_PROGRESS; + + wlen = write(fd, &resp, sizeof(resp)); + if (wlen < 0) + return -errno; + if (wlen != sizeof(resp)) + return -ENOSPC; + } + + return OK; +} + +static int getsockopt_request(int fd, FAR struct daemon_priv_s *priv, + FAR void *hdrbuf) +{ + DEBUGASSERT(priv); + DEBUGASSERT(hdrbuf); + FAR struct usrsock_request_getsockopt_s *req = hdrbuf; + FAR struct test_socket_s *tsock; + struct usrsock_message_datareq_ack_s resp = {}; + ssize_t wlen; + int ret = 0; + int value; + + /* Check if this socket exists. */ + + tsock = test_socket_get(priv, req->usockid); + if (!tsock) + { + ret = -EBADFD; + goto prepare; + } + + if (req->level != SOL_SOCKET) + { + dbg("getsockopt: level=%d not supported\n", req->level); + ret = -ENOPROTOOPT; + goto prepare; + } + + if (req->option != SO_REUSEADDR) + { + dbg("getsockopt: option=%d not supported\n", req->option); + ret = -ENOPROTOOPT; + goto prepare; + } + + if (req->max_valuelen < sizeof(value)) + { + ret = -EINVAL; + goto prepare; + } + + value = 0; + ret = OK; + +prepare: + /* Prepare response. */ + + resp.reqack.xid = req->head.xid; + resp.reqack.head.msgid = USRSOCK_MESSAGE_RESPONSE_DATA_ACK; + resp.reqack.head.flags = 0; + + if (priv->conf->delay_all_responses) + { + resp.reqack.head.flags = USRSOCK_MESSAGE_FLAG_REQ_IN_PROGRESS; + resp.reqack.result = -EINPROGRESS; + resp.valuelen = 0; + resp.valuelen_nontrunc = 0; + + /* Send ack response. */ + + wlen = write(fd, &resp, sizeof(resp)); + if (wlen < 0) + return -errno; + if (wlen != sizeof(resp)) + return -ENOSPC; + + pthread_mutex_unlock(&daemon_mutex); + usleep(50 * 1000); + pthread_mutex_lock(&daemon_mutex); + + /* Previous write was acknowledgment to request, informing that request + * is still in progress. Now write actual completion response. */ + + resp.reqack.head.msgid = USRSOCK_MESSAGE_RESPONSE_DATA_ACK; + resp.reqack.head.flags &= ~USRSOCK_MESSAGE_FLAG_REQ_IN_PROGRESS; + } + + resp.reqack.head.flags = 0; + resp.reqack.result = ret; + if (ret >= 0) + { + resp.valuelen = sizeof(value); + } + else + { + resp.valuelen = 0; + } + + /* Send response. */ + + wlen = write(fd, &resp, sizeof(resp)); + if (wlen < 0) + return -errno; + if (wlen != sizeof(resp)) + return -ENOSPC; + + if (resp.valuelen > 0) + { + /* Send address (value) */ + + wlen = write(fd, &value, resp.valuelen); + if (wlen < 0) + return -errno; + if (wlen != resp.valuelen) + return -ENOSPC; + } + + return OK; +} + +static int getsockname_request(int fd, FAR struct daemon_priv_s *priv, + FAR void *hdrbuf) +{ + DEBUGASSERT(priv); + DEBUGASSERT(hdrbuf); + FAR struct usrsock_request_getsockname_s *req = hdrbuf; + FAR struct test_socket_s *tsock; + struct usrsock_message_datareq_ack_s resp = {}; + ssize_t wlen; + int ret = 0; + struct sockaddr_in addr; + + /* Check if this socket exists. */ + + tsock = test_socket_get(priv, req->usockid); + if (!tsock) + { + ret = -EBADFD; + goto prepare; + } + + ret = inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr.s_addr); + addr.sin_family = AF_INET; + addr.sin_port = htons(12345); + ret = ret == 1 ? 0 : -EINVAL; + +prepare: + /* Prepare response. */ + + resp.reqack.xid = req->head.xid; + resp.reqack.head.msgid = USRSOCK_MESSAGE_RESPONSE_DATA_ACK; + resp.reqack.head.flags = 0; + + if (priv->conf->delay_all_responses) + { + resp.reqack.head.flags = USRSOCK_MESSAGE_FLAG_REQ_IN_PROGRESS; + resp.reqack.result = -EINPROGRESS; + resp.valuelen = 0; + resp.valuelen_nontrunc = 0; + + /* Send ack response. */ + + wlen = write(fd, &resp, sizeof(resp)); + if (wlen < 0) + return -errno; + if (wlen != sizeof(resp)) + return -ENOSPC; + + pthread_mutex_unlock(&daemon_mutex); + usleep(50 * 1000); + pthread_mutex_lock(&daemon_mutex); + + /* Previous write was acknowledgment to request, informing that request + * is still in progress. Now write actual completion response. */ + + resp.reqack.head.msgid = USRSOCK_MESSAGE_RESPONSE_DATA_ACK; + resp.reqack.head.flags &= ~USRSOCK_MESSAGE_FLAG_REQ_IN_PROGRESS; + } + + resp.reqack.head.flags = 0; + resp.reqack.result = ret; + if (ret >= 0) + { + resp.valuelen = sizeof(addr); + resp.valuelen_nontrunc = sizeof(addr); + if (resp.valuelen > req->max_addrlen) + resp.valuelen = req->max_addrlen; + } + else + { + resp.valuelen = 0; + resp.valuelen_nontrunc = 0; + } + + /* Send response. */ + + wlen = write(fd, &resp, sizeof(resp)); + if (wlen < 0) + return -errno; + if (wlen != sizeof(resp)) + return -ENOSPC; + + if (resp.valuelen > 0) + { + /* Send address (value) */ + + wlen = write(fd, &addr, resp.valuelen); + if (wlen < 0) + return -errno; + if (wlen != resp.valuelen) + return -ENOSPC; + } + + return OK; +} + +static int handle_usrsock_request(int fd, FAR struct daemon_priv_s *priv) +{ + static const struct { + unsigned int hdrlen; + int (*fn)(int fd, FAR struct daemon_priv_s *priv, FAR void *req); + } handlers[USRSOCK_REQUEST__MAX] = + { + [USRSOCK_REQUEST_SOCKET] = + { + sizeof(struct usrsock_request_socket_s), + socket_request, + }, + [USRSOCK_REQUEST_CLOSE] = + { + sizeof(struct usrsock_request_close_s), + close_request, + }, + [USRSOCK_REQUEST_CONNECT] = + { + sizeof(struct usrsock_request_connect_s), + connect_request, + }, + [USRSOCK_REQUEST_SENDTO] = + { + sizeof(struct usrsock_request_sendto_s), + sendto_request, + }, + [USRSOCK_REQUEST_RECVFROM] = + { + sizeof(struct usrsock_request_recvfrom_s), + recvfrom_request, + }, + [USRSOCK_REQUEST_SETSOCKOPT] = + { + sizeof(struct usrsock_request_setsockopt_s), + setsockopt_request, + }, + [USRSOCK_REQUEST_GETSOCKOPT] = + { + sizeof(struct usrsock_request_getsockopt_s), + getsockopt_request, + }, + [USRSOCK_REQUEST_GETSOCKNAME] = + { + sizeof(struct usrsock_request_getsockname_s), + getsockname_request, + }, + }; + uint8_t hdrbuf[16]; + struct usrsock_request_common_s *common_hdr = (void *)hdrbuf; + ssize_t rlen; + + rlen = read(fd, common_hdr, sizeof(*common_hdr)); + if (rlen < 0) + return -errno; + if (rlen != sizeof(*common_hdr)) + return -EMSGSIZE; + + if (common_hdr->reqid >= USRSOCK_REQUEST__MAX || + !handlers[common_hdr->reqid].fn) + { + dbg("Unknown request type: %d\n", common_hdr->reqid); + return -EIO; + } + + assert(handlers[common_hdr->reqid].hdrlen < sizeof(hdrbuf)); + + rlen = read_req(fd, common_hdr, hdrbuf, handlers[common_hdr->reqid].hdrlen); + if (rlen < 0) + return rlen; + + return handlers[common_hdr->reqid].fn(fd, priv, hdrbuf); +} + +static int unblock_sendto(int fd, FAR struct daemon_priv_s *priv, + FAR struct test_socket_s *tsock) +{ + if (tsock->block_send) + { + int ret; + + tsock->block_send = false; + + ret = tsock_send_event(fd, priv, tsock, USRSOCK_EVENT_SENDTO_READY); + if (ret < 0) + return ret; + } + + return OK; +} + +static int reset_recv_avail(int fd, FAR struct daemon_priv_s *priv, + FAR struct test_socket_s *tsock) +{ + if (tsock->recv_avail_bytes == 0) + { + int ret; + + priv->sockets_recv_empty--; + + tsock->recv_avail_bytes = priv->conf->endpoint_recv_avail; + + ret = tsock_send_event(fd, priv, tsock, + USRSOCK_EVENT_RECVFROM_AVAIL); + if (ret < 0) + return ret; + } + + return OK; +} + +static int disconnect_connection(int fd, FAR struct daemon_priv_s *priv, + FAR struct test_socket_s *tsock) +{ + if (tsock->connected) + { + int ret; + + tsock->disconnected = true; + tsock->connected = false; + + priv->sockets_connected--; + priv->sockets_remote_disconnected++; + + ret = tsock_send_event(fd, priv, tsock, USRSOCK_EVENT_REMOTE_CLOSED); + if (ret < 0) + return ret; + } + + return OK; +} + +static int establish_blocked_connection(int fd, FAR struct daemon_priv_s *priv, + FAR struct test_socket_s *tsock) +{ + if (tsock->blocked_connect) + { + FAR struct usrsock_message_req_ack_s *resp = &tsock->pending_resp; + ssize_t wlen; + int events; + + if (resp->result == OK) + { + priv->sockets_connected++; + tsock->connected = true; + } + + tsock->blocked_connect = false; + + priv->sockets_waiting_connect--; + resp->head.flags &= ~USRSOCK_MESSAGE_FLAG_REQ_IN_PROGRESS; + + wlen = write(fd, resp, sizeof(*resp)); + if (wlen < 0) + return -errno; + if (wlen != sizeof(*resp)) + return -ENOSPC; + + events = 0; + if (!tsock->block_send) + events |= USRSOCK_EVENT_SENDTO_READY; + if (tsock->recv_avail_bytes > 0) + events |= USRSOCK_EVENT_RECVFROM_AVAIL; + + if (events) + { + wlen = tsock_send_event(fd, priv, tsock, events); + if (wlen < 0) + return wlen; + } + } + + return OK; +} + +static int fail_blocked_connection(int fd, FAR struct daemon_priv_s *priv, + FAR struct test_socket_s *tsock) +{ + if (tsock->blocked_connect) + { + FAR struct usrsock_message_req_ack_s *resp = &tsock->pending_resp; + ssize_t wlen; + + resp->result = -ECONNREFUSED; + priv->sockets_not_connected_refused++; + tsock->connect_refused = true; + tsock->blocked_connect = false; + + priv->sockets_waiting_connect--; + resp->head.flags &= ~USRSOCK_MESSAGE_FLAG_REQ_IN_PROGRESS; + + wlen = write(fd, resp, sizeof(*resp)); + if (wlen < 0) + return -errno; + if (wlen != sizeof(*resp)) + return -ENOSPC; + } + + return OK; +} + +static int for_each_connection(int fd, FAR struct daemon_priv_s *priv, + int (*iter_fn)( + int fd, + FAR struct daemon_priv_s *priv, + FAR struct test_socket_s *tsock)) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(priv->test_sockets); i++) + { + FAR struct test_socket_s *tsock = &priv->test_sockets[i]; + + if (tsock->opened) + { + int ret = iter_fn(fd, priv, tsock); + if (ret < 0) + return ret; + } + } + + return OK; +} + +static FAR void *usrsocktest_daemon(FAR void *param) +{ + FAR struct daemon_priv_s *priv = param; + bool stopped; + int ret; + int fd; + + dbg("\n"); + + priv->sockets_active = 0; + + fd = open("/dev/usrsock", O_RDWR); + if (fd < 0) + { + ret = -errno; + goto errout; + } + + do + { + struct pollfd pfd[2] = {}; + int npfds = 0; + int usrsock_pfdpos = -1; + int pipe_pdfpos = -1; + + stopped = false; + + /* Wait for request from kernel side. */ + + pthread_mutex_lock(&daemon_mutex); + if (!priv->do_not_poll_usrsock && fd >= 0) + { + pfd[npfds].fd = fd; + pfd[npfds].events = POLLIN; + usrsock_pfdpos = npfds++; + } + pfd[npfds].fd = priv->pipefd[0]; + pfd[npfds].events = POLLIN; + pipe_pdfpos = npfds++; + pthread_mutex_unlock(&daemon_mutex); + + ret = poll(pfd, npfds, -1); + if (ret < 0) + { + /* Error? */ + ret = -errno; + goto errout; + } + + if (usrsock_pfdpos >= 0 && (pfd[usrsock_pfdpos].revents & POLLIN)) + { + pthread_mutex_lock(&daemon_mutex); + ret = handle_usrsock_request(fd, priv); + pthread_mutex_unlock(&daemon_mutex); + if (ret < 0) + goto errout; + } + + if (pipe_pdfpos >= 0 && (pfd[pipe_pdfpos].revents & POLLIN)) + { + char in; + + if (read(pfd[pipe_pdfpos].fd, &in, 1) == 1) + { + pthread_mutex_lock(&daemon_mutex); + + switch (in) + { + case 'S': + stopped = true; + ret = 0; + break; + case 's': + stopped = false; + ret = 0; + break; + case 'E': + ret = for_each_connection(fd, priv, + &establish_blocked_connection); + break; + case 'F': + ret = for_each_connection(fd, priv, + &fail_blocked_connection); + break; + case 'D': + ret = for_each_connection(fd, priv, + &disconnect_connection); + break; + case 'W': + ret = for_each_connection(fd, priv, + &unblock_sendto); + break; + case 'r': + ret = for_each_connection(fd, priv, + &reset_recv_avail); + break; + case 'K': + /* Kill usrsockdev */ + if (fd >= 0) + { + close(fd); + fd = -1; + } + break; + case '*': + sem_post(&priv->wakewaitsem); + break; /* woke thread. */ + } + + pthread_mutex_unlock(&daemon_mutex); + + if (ret < 0) + goto errout; + } + } + + usleep(1); + } + while (!stopped); + + ret = OK; +errout: + if (fd >= 0) + { + close(fd); + } + + dbg("ret: %d\n", ret); + + return (FAR void *)(intptr_t)ret; +} + +static int get_daemon_value(FAR struct daemon_priv_s *priv, + FAR void *dst, FAR const void *src, size_t len) +{ + int ret = 0; + + if ((uintptr_t)src < (uintptr_t)priv || + (uintptr_t)src >= (uintptr_t)priv + sizeof(*priv) || len <= 0) + { + /* Not daemon value */ + + return -EINVAL; + } + + pthread_mutex_lock(&daemon_mutex); + + if (priv->conf == NULL) + { + /* Not running? */ + + ret = -ENODEV; + goto out; + } + + memmove(dst, src, len); + +out: + pthread_mutex_unlock(&daemon_mutex); + + return ret; +} + +static void *delayed_cmd_thread(void *priv) +{ + FAR struct delayed_cmd_s *cmd = priv; + + if (cmd->delay_msec) + sem_post(&cmd->startsem); + + usleep(cmd->delay_msec * 1000); + + (void)write(cmd->pipefd, &cmd->cmd, 1); + + if (!cmd->delay_msec) + sem_post(&cmd->startsem); + + return NULL; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +int usrsocktest_daemon_start(const struct usrsocktest_daemon_conf_s *conf) +{ + FAR struct daemon_priv_s *priv = &daemon; + pthread_attr_t attr; + int ret; + + dbg("\n"); + + pthread_mutex_lock(&daemon_mutex); + + if (priv->conf != NULL || !priv->joined) + { + /* Already running? */ + + ret = -EALREADY; + goto out; + } + + /* Clear daemon private data. */ + + memset(priv, 0, sizeof(*priv)); + + /* Allocate pipe for daemon commands. */ + + ret = pipe(priv->pipefd); + if (ret != OK) + { + ret = -errno; + goto out; + } + + ret = pthread_attr_init(&attr); + if (ret != OK) + { + ret = -ret; + goto errout_closepipe; + } + + sem_init(&priv->wakewaitsem, 0, 0); + + priv->joined = false; + priv->conf = conf; + + ret = pthread_create(&priv->tid, &attr, usrsocktest_daemon, priv); + if (ret != OK) + { + sem_destroy(&priv->wakewaitsem); + priv->joined = true; + priv->conf = NULL; + ret = -ret; + goto errout_closepipe; + } + +errout_closepipe: + if (ret != OK) + { + close(priv->pipefd[0]); + close(priv->pipefd[1]); + } +out: + pthread_mutex_unlock(&daemon_mutex); + dbg("ret: %d\n", ret); + return ret; +} + +int usrsocktest_daemon_stop(void) +{ + FAR struct daemon_priv_s *priv = &daemon; + FAR struct delayed_cmd_s *item, *next; + FAR pthread_addr_t retval; + char stopped; + int ret; + int i; + + dbg("\n"); + + pthread_mutex_lock(&daemon_mutex); + + if (priv->conf == NULL) + { + /* Not running? */ + + ret = -ENODEV; + goto out; + } + + item = (void *)sq_peek(&priv->delayed_cmd_threads); + while (item) + { + next = (void *)sq_next(&item->node); + + pthread_mutex_unlock(&daemon_mutex); + (void)pthread_join(item->tid, &retval); + pthread_mutex_lock(&daemon_mutex); + sq_rem(&item->node, &priv->delayed_cmd_threads); + free(item); + usrsocktest_dcmd_malloc_cnt--; + + item = next; + } + + pthread_mutex_unlock(&daemon_mutex); + stopped = 'S'; + write(priv->pipefd[1], &stopped, 1); + + ret = pthread_join(priv->tid, &retval); + pthread_mutex_lock(&daemon_mutex); + if (ret != OK) + { + ret = -ret; + goto out; + } + + for (i = 0; i < ARRAY_SIZE(priv->test_sockets); i++) + { + if (priv->test_sockets[i].opened && priv->test_sockets[i].endp != NULL) + { + free(priv->test_sockets[i].endp); + priv->test_sockets[i].endp = NULL; + usrsocktest_endp_malloc_cnt--; + } + } + + priv->conf = NULL; + close(priv->pipefd[0]); + close(priv->pipefd[1]); + sem_destroy(&priv->wakewaitsem); + + priv->joined = true; + ret = (intptr_t)retval; + +out: + pthread_mutex_unlock(&daemon_mutex); + dbg("ret: %d\n", ret); + return ret; +} + +int usrsocktest_daemon_get_num_active_sockets(void) +{ + FAR struct daemon_priv_s *priv = &daemon; + int ret, err; + + err = get_daemon_value(priv, &ret, &priv->sockets_active, sizeof(ret)); + if (err < 0) + return err; + + return ret; +} + +int usrsocktest_daemon_get_num_connected_sockets(void) +{ + FAR struct daemon_priv_s *priv = &daemon; + int ret, err; + + err = get_daemon_value(priv, &ret, &priv->sockets_connected, sizeof(ret)); + if (err < 0) + return err; + + return ret; +} + +int usrsocktest_daemon_get_num_waiting_connect_sockets(void) +{ + FAR struct daemon_priv_s *priv = &daemon; + int ret, err; + + err = get_daemon_value(priv, &ret, &priv->sockets_waiting_connect, sizeof(ret)); + if (err < 0) + return err; + + return ret; +} + +int usrsocktest_daemon_get_num_recv_empty_sockets(void) +{ + FAR struct daemon_priv_s *priv = &daemon; + int ret, err; + + err = get_daemon_value(priv, &ret, &priv->sockets_recv_empty, sizeof(ret)); + if (err < 0) + return err; + + return ret; +} + +ssize_t usrsocktest_daemon_get_send_bytes(void) +{ + FAR struct daemon_priv_s *priv = &daemon; + size_t ret; + int err; + + err = get_daemon_value(priv, &ret, &priv->total_send_bytes, sizeof(ret)); + if (err < 0) + return err; + + return ret; +} + +ssize_t usrsocktest_daemon_get_recv_bytes(void) +{ + FAR struct daemon_priv_s *priv = &daemon; + size_t ret; + int err; + + err = get_daemon_value(priv, &ret, &priv->total_recv_bytes, sizeof(ret)); + if (err < 0) + return err; + + return ret; +} + +int usrsocktest_daemon_get_num_unreachable_sockets(void) +{ + FAR struct daemon_priv_s *priv = &daemon; + int ret, err; + + err = get_daemon_value(priv, &ret, &priv->sockets_not_connected_refused, sizeof(ret)); + if (err < 0) + return err; + + return ret; +} + +int usrsocktest_daemon_get_num_remote_disconnected_sockets(void) +{ + FAR struct daemon_priv_s *priv = &daemon; + int ret, err; + + err = get_daemon_value(priv, &ret, &priv->sockets_remote_disconnected, sizeof(ret)); + if (err < 0) + return err; + + return ret; +} + +int usrsocktest_daemon_pause_usrsock_handling(bool pause) +{ + FAR struct daemon_priv_s *priv = &daemon; + int ret; + char cmd = '*'; + + pthread_mutex_lock(&daemon_mutex); + + if (priv->conf == NULL) + { + /* Not running? */ + + pthread_mutex_unlock(&daemon_mutex); + return -ENODEV; + } + + priv->do_not_poll_usrsock = pause; + + (void)write(priv->pipefd[1], &cmd, 1); + ret = OK; + + pthread_mutex_unlock(&daemon_mutex); + + sem_wait(&priv->wakewaitsem); + + return ret; +} + +bool usrsocktest_send_delayed_command(const char cmd, unsigned int delay_msec) +{ + FAR struct daemon_priv_s *priv = &daemon; + pthread_attr_t attr; + FAR struct delayed_cmd_s *delayed_cmd; + int ret; + + if (priv->conf == NULL) + { + /* Not running? */ + + return false; + } + + delayed_cmd = calloc(1, sizeof(*delayed_cmd)); + if (!delayed_cmd) + { + return false; + } + + usrsocktest_dcmd_malloc_cnt++; + + delayed_cmd->delay_msec = delay_msec; + delayed_cmd->cmd = cmd; + delayed_cmd->pipefd = priv->pipefd[1]; + (void)sem_init(&delayed_cmd->startsem, 0, 0); + + ret = pthread_attr_init(&attr); + if (ret != OK) + { + free(delayed_cmd); + usrsocktest_dcmd_malloc_cnt--; + return false; + } + + ret = pthread_create(&delayed_cmd->tid, &attr, delayed_cmd_thread, + delayed_cmd); + if (ret != OK) + { + free(delayed_cmd); + usrsocktest_dcmd_malloc_cnt--; + return false; + } + + while (sem_wait(&delayed_cmd->startsem) != OK); + + sq_addlast(&delayed_cmd->node, &priv->delayed_cmd_threads); + + return true; +} + +bool usrsocktest_daemon_establish_waiting_connections(void) +{ + return usrsocktest_send_delayed_command('E', 0); +} diff --git a/tests/unity_usrsock/wake_with_signal.c b/tests/unity_usrsock/wake_with_signal.c new file mode 100644 index 000000000..2904dc0c7 --- /dev/null +++ b/tests/unity_usrsock/wake_with_signal.c @@ -0,0 +1,1563 @@ +/**************************************************************************** + * apps/examples/unity_usrsock/wake_with_signal.c + * Wake blocked IO with signal or daemon abort + * + * Copyright (C) 2015-2016 Haltian Ltd. All rights reserved. + * Authors: Jussi Kivilinna + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ +#include +#include +#include +#include +#include +#include +#include + +#include "defines.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ +#ifndef ARRAY_SIZE +# define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) +#endif + +#define TEST_FLAG_PAUSE_USRSOCK_HANDLING (1 << 0) +#define TEST_FLAG_DAEMON_ABORT (1 << 1) +#define TEST_FLAG_MULTI_THREAD (1 << 2) + +#define MAX_THREADS 4 + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +enum e_test_type +{ + TEST_TYPE_SOCKET = 0, + TEST_TYPE_CLOSE, + TEST_TYPE_CONNECT, + TEST_TYPE_SETSOCKOPT, + TEST_TYPE_GETSOCKOPT, + TEST_TYPE_SEND, + TEST_TYPE_RECV, + TEST_TYPE_POLL, + __TEST_TYPE_MAX, +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ +static pthread_t tid[MAX_THREADS]; +static sem_t tid_startsem; +static sem_t tid_releasesem; +static int test_sd[MAX_THREADS]; +static enum e_test_type test_type; +static int test_flags; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static FAR void * usrsock_blocking_socket_thread(FAR void *param) +{ + intptr_t tidx = (intptr_t)param; + bool test_abort = !!(test_flags & TEST_FLAG_DAEMON_ABORT); + bool test_hang = !!(test_flags & TEST_FLAG_PAUSE_USRSOCK_HANDLING); + + TEST_ASSERT_TRUE(test_hang); + TEST_ASSERT_TRUE(test_abort); + + /* Allow main thread to hang usrsock daemon at this point. */ + + sem_post(&tid_startsem); + sem_wait(&tid_releasesem); + + /* Attempt hanging open socket. */ + + sem_post(&tid_startsem); + test_sd[tidx] = socket(AF_INET, SOCK_STREAM, 0); + TEST_ASSERT_EQUAL(-1, test_sd[tidx]); + TEST_ASSERT_EQUAL(ENETDOWN, errno); + + return NULL; +} + +static FAR void * usrsock_blocking_close_thread(FAR void *param) +{ + intptr_t tidx = (intptr_t)param; + struct sockaddr_in addr; + int ret; + bool test_abort = !!(test_flags & TEST_FLAG_DAEMON_ABORT); + bool test_hang = !!(test_flags & TEST_FLAG_PAUSE_USRSOCK_HANDLING); + + TEST_ASSERT_TRUE(test_hang); + TEST_ASSERT_TRUE(test_abort); + + /* Open socket. */ + + test_sd[tidx] = socket(AF_INET, SOCK_STREAM, 0); + TEST_ASSERT_TRUE(test_sd[tidx] >= 0); + + inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr.s_addr); + addr.sin_family = AF_INET; + addr.sin_port = htons(255); + + /* Allow main thread to hang usrsock daemon at this point. */ + + sem_post(&tid_startsem); + sem_wait(&tid_releasesem); + + /* Attempt hanging close socket. */ + + sem_post(&tid_startsem); + ret = close(test_sd[tidx]); + TEST_ASSERT_EQUAL(0, ret); + test_sd[tidx] = -1; + + return NULL; +} + +static FAR void * usrsock_blocking_connect_thread(FAR void *param) +{ + intptr_t tidx = (intptr_t)param; + struct sockaddr_in addr; + int ret; + bool test_abort = !!(test_flags & TEST_FLAG_DAEMON_ABORT); + bool test_hang = !!(test_flags & TEST_FLAG_PAUSE_USRSOCK_HANDLING); + + TEST_ASSERT_TRUE(test_hang || !test_hang); + + /* Open socket. */ + + test_sd[tidx] = socket(AF_INET, SOCK_STREAM, 0); + TEST_ASSERT_TRUE(test_sd[tidx] >= 0); + + inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr.s_addr); + addr.sin_family = AF_INET; + addr.sin_port = htons(255); + + /* Allow main thread to hang usrsock daemon at this point. */ + + sem_post(&tid_startsem); + sem_wait(&tid_releasesem); + + /* Attempt blocking connect. */ + + sem_post(&tid_startsem); + ret = connect(test_sd[tidx], (FAR const struct sockaddr *)&addr, sizeof(addr)); + TEST_ASSERT_EQUAL(-1, ret); + TEST_ASSERT_EQUAL(test_abort ? ECONNABORTED : EINTR, errno); + + /* Close socket */ + + TEST_ASSERT_TRUE(close(test_sd[tidx]) >= 0); + test_sd[tidx] = -1; + + return NULL; +} + +static FAR void * usrsock_blocking_setsockopt_thread(FAR void *param) +{ + intptr_t tidx = (intptr_t)param; + struct sockaddr_in addr; + int ret; + int value; + bool test_abort = !!(test_flags & TEST_FLAG_DAEMON_ABORT); + bool test_hang = !!(test_flags & TEST_FLAG_PAUSE_USRSOCK_HANDLING); + + /* Open socket. */ + + test_sd[tidx] = socket(AF_INET, SOCK_STREAM, 0); + TEST_ASSERT_TRUE(test_sd[tidx] >= 0); + + inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr.s_addr); + addr.sin_family = AF_INET; + addr.sin_port = htons(255); + + TEST_ASSERT_TRUE(test_hang); + TEST_ASSERT_TRUE(test_abort); + + /* Allow main thread to hang usrsock daemon at this point. */ + + sem_post(&tid_startsem); + sem_wait(&tid_releasesem); + + /* Attempt hanging setsockopt. */ + + sem_post(&tid_startsem); + value = 1; + ret = setsockopt(test_sd[tidx], SOL_SOCKET, SO_REUSEADDR, &value, sizeof(value)); + TEST_ASSERT_EQUAL(-1, ret); + + /* Close socket */ + + TEST_ASSERT_TRUE(close(test_sd[tidx]) >= 0); + test_sd[tidx] = -1; + + return NULL; +} + +static FAR void * usrsock_blocking_getsockopt_thread(FAR void *param) +{ + intptr_t tidx = (intptr_t)param; + struct sockaddr_in addr; + int ret; + int value; + socklen_t valuelen; + bool test_abort = !!(test_flags & TEST_FLAG_DAEMON_ABORT); + bool test_hang = !!(test_flags & TEST_FLAG_PAUSE_USRSOCK_HANDLING); + + /* Open socket. */ + + test_sd[tidx] = socket(AF_INET, SOCK_STREAM, 0); + TEST_ASSERT_TRUE(test_sd[tidx] >= 0); + + inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr.s_addr); + addr.sin_family = AF_INET; + addr.sin_port = htons(255); + + TEST_ASSERT_TRUE(test_hang); + TEST_ASSERT_TRUE(test_abort); + + /* Allow main thread to hang usrsock daemon at this point. */ + + sem_post(&tid_startsem); + sem_wait(&tid_releasesem); + + /* Attempt hanging getsockopt. */ + + sem_post(&tid_startsem); + value = -1; + valuelen = sizeof(value); + ret = getsockopt(test_sd[tidx], SOL_SOCKET, SO_REUSEADDR, &value, &valuelen); + TEST_ASSERT_EQUAL(-1, ret); + + /* Close socket */ + + TEST_ASSERT_TRUE(close(test_sd[tidx]) >= 0); + test_sd[tidx] = -1; + + return NULL; +} + +static FAR void * usrsock_blocking_send_thread(FAR void *param) +{ + intptr_t tidx = (intptr_t)param; + struct sockaddr_in addr; + int ret; + bool test_abort = !!(test_flags & TEST_FLAG_DAEMON_ABORT); + bool test_hang = !!(test_flags & TEST_FLAG_PAUSE_USRSOCK_HANDLING); + + TEST_ASSERT_TRUE(test_hang || !test_hang); + + /* Open socket. */ + + test_sd[tidx] = socket(AF_INET, SOCK_STREAM, 0); + TEST_ASSERT_TRUE(test_sd[tidx] >= 0); + + inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr.s_addr); + addr.sin_family = AF_INET; + addr.sin_port = htons(255); + + /* Connect socket. */ + + ret = connect(test_sd[tidx], (FAR const struct sockaddr *)&addr, sizeof(addr)); + TEST_ASSERT_EQUAL(0, ret); + + /* Allow main thread to hang usrsock daemon at this point. */ + + sem_post(&tid_startsem); + sem_wait(&tid_releasesem); + + /* Attempt blocking send. */ + + sem_post(&tid_startsem); + ret = send(test_sd[tidx], &addr, sizeof(addr), 0); + TEST_ASSERT_EQUAL(-1, ret); + TEST_ASSERT_EQUAL(test_abort ? EPIPE : EINTR, errno); + + /* Close socket */ + + TEST_ASSERT_TRUE(close(test_sd[tidx]) >= 0); + test_sd[tidx] = -1; + + return NULL; +} + +static FAR void * usrsock_blocking_recv_thread(FAR void *param) +{ + intptr_t tidx = (intptr_t)param; + struct sockaddr_in addr; + int ret; + bool test_abort = !!(test_flags & TEST_FLAG_DAEMON_ABORT); + bool test_hang = !!(test_flags & TEST_FLAG_PAUSE_USRSOCK_HANDLING); + + TEST_ASSERT_TRUE(test_hang || !test_hang); + + /* Open socket. */ + + test_sd[tidx] = socket(AF_INET, SOCK_STREAM, 0); + TEST_ASSERT_TRUE(test_sd[tidx] >= 0); + + inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr.s_addr); + addr.sin_family = AF_INET; + addr.sin_port = htons(255); + + /* Connect socket. */ + + ret = connect(test_sd[tidx], (FAR const struct sockaddr *)&addr, sizeof(addr)); + TEST_ASSERT_EQUAL(0, ret); + + /* Allow main thread to hang usrsock daemon at this point. */ + + sem_post(&tid_startsem); + sem_wait(&tid_releasesem); + + /* Attempt blocking recv. */ + + sem_post(&tid_startsem); + ret = recv(test_sd[tidx], &addr, sizeof(addr), 0); + TEST_ASSERT_EQUAL(-1, ret); + TEST_ASSERT_EQUAL(test_abort ? EPIPE : EINTR, errno); + + /* Close socket */ + + TEST_ASSERT_TRUE(close(test_sd[tidx]) >= 0); + test_sd[tidx] = -1; + + return NULL; +} + +static FAR void * usrsock_blocking_poll_thread(FAR void *param) +{ + intptr_t tidx = (intptr_t)param; + struct sockaddr_in addr; + int ret; + struct pollfd pfd = {}; + bool test_abort = !!(test_flags & TEST_FLAG_DAEMON_ABORT); + bool test_hang = !!(test_flags & TEST_FLAG_PAUSE_USRSOCK_HANDLING); + + TEST_ASSERT_TRUE(test_abort); + TEST_ASSERT_TRUE(test_hang || !test_hang); + + /* Open socket. */ + + test_sd[tidx] = socket(AF_INET, SOCK_STREAM, 0); + TEST_ASSERT_TRUE(test_sd[tidx] >= 0); + + inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr.s_addr); + addr.sin_family = AF_INET; + addr.sin_port = htons(255); + + /* Connect socket. */ + + ret = connect(test_sd[tidx], (FAR const struct sockaddr *)&addr, sizeof(addr)); + TEST_ASSERT_EQUAL(0, ret); + + /* Allow main thread to hang usrsock daemon at this point. */ + + sem_post(&tid_startsem); + sem_wait(&tid_releasesem); + + /* Attempt poll. */ + + pfd.fd = test_sd[tidx]; + pfd.events = POLLIN; + + sem_post(&tid_startsem); + ret = poll(&pfd, 1, -1); + TEST_ASSERT_EQUAL(1, ret); + TEST_ASSERT_EQUAL(POLLERR | POLLHUP, pfd.revents); + + /* Attempt read from aborted socket */ + + ret = recv(test_sd[tidx], &addr, sizeof(addr), 0); + TEST_ASSERT_EQUAL(-1, ret); + TEST_ASSERT_EQUAL(EPIPE, errno); + + /* Close socket */ + + TEST_ASSERT_TRUE(close(test_sd[tidx]) >= 0); + test_sd[tidx] = -1; + + return NULL; +} + +static void do_wake_test(enum e_test_type type, int flags) +{ + static const struct + { + pthread_startroutine_t fn; + bool stop_only_on_hang; + } thread_funcs[__TEST_TYPE_MAX] = + { + [TEST_TYPE_SOCKET] = { usrsock_blocking_socket_thread, false }, + [TEST_TYPE_CLOSE] = { usrsock_blocking_close_thread, false }, + [TEST_TYPE_CONNECT] = { usrsock_blocking_connect_thread, true }, + [TEST_TYPE_SETSOCKOPT] = { usrsock_blocking_setsockopt_thread, false }, + [TEST_TYPE_GETSOCKOPT] = { usrsock_blocking_getsockopt_thread, false }, + [TEST_TYPE_RECV] = { usrsock_blocking_recv_thread, true }, + [TEST_TYPE_SEND] = { usrsock_blocking_send_thread, true }, + [TEST_TYPE_POLL] = { usrsock_blocking_poll_thread, true }, + }; + int ret; + int nthreads = (flags & TEST_FLAG_MULTI_THREAD) ? MAX_THREADS : 1; + int tidx; + bool test_abort = !!(flags & TEST_FLAG_DAEMON_ABORT); + bool test_hang = !!(flags & TEST_FLAG_PAUSE_USRSOCK_HANDLING); + + /* Start test daemon. */ + + TEST_ASSERT_EQUAL(OK, usrsocktest_daemon_start(&usrsocktest_daemon_config)); + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_get_num_active_sockets()); + + /* Launch worker threads. */ + + test_type = type; + test_flags = flags; + for (tidx = 0; tidx < nthreads; tidx++) + { + ret = pthread_create(&tid[tidx], NULL, thread_funcs[type].fn, + (pthread_addr_t)(intptr_t)tidx); + TEST_ASSERT_EQUAL(OK, ret); + } + +/* Let workers to start. */ + + for (tidx = 0; tidx < nthreads; tidx++) + { + sem_wait(&tid_startsem); + } + + if (test_hang || !thread_funcs[type].stop_only_on_hang) + { + TEST_ASSERT_EQUAL(0, usrsocktest_daemon_pause_usrsock_handling(true)); + } + + for (tidx = 0; tidx < nthreads; tidx++) + { + sem_post(&tid_releasesem); + } + for (tidx = 0; tidx < nthreads; tidx++) + { + sem_wait(&tid_startsem); + } + + usleep(100 * USEC_PER_MSEC); /* Let worker thread proceed to blocking + * function. */ + + if (!test_abort) + { + /* Wake waiting thread with signal. */ + + /* Send signal to task to break out from blocking send. */ + + for (tidx = 0; tidx < nthreads; tidx++) + { + pthread_kill(tid[tidx], 1); + + /* Wait threads to complete work. */ + + ret = pthread_join(tid[tidx], NULL); + TEST_ASSERT_EQUAL(OK, ret); + tid[tidx] = -1; + } + TEST_ASSERT_FALSE(Unity.CurrentTestFailed); + + /* Stopping daemon should succeed. */ + + TEST_ASSERT_EQUAL(OK, usrsocktest_daemon_stop()); + TEST_ASSERT_EQUAL(0, usrsocktest_endp_malloc_cnt); + TEST_ASSERT_EQUAL(0, usrsocktest_dcmd_malloc_cnt); + } + else + { + /* Wake waiting thread with daemon abort. */ + + /* Stopping daemon should succeed. */ + + TEST_ASSERT_EQUAL(OK, usrsocktest_daemon_stop()); + TEST_ASSERT_EQUAL(0, usrsocktest_endp_malloc_cnt); + TEST_ASSERT_EQUAL(0, usrsocktest_dcmd_malloc_cnt); + + /* Wait threads to complete work. */ + + for (tidx = 0; tidx < nthreads; tidx++) + { + ret = pthread_join(tid[tidx], NULL); + TEST_ASSERT_EQUAL(OK, ret); + tid[tidx] = -1; + } + TEST_ASSERT_FALSE(Unity.CurrentTestFailed); + } +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +TEST_GROUP(WakeWithSignal); + +/**************************************************************************** + * Name: WakeWithSignal test group setup + * + * Description: + * Setup function executed before each testcase in this test group + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +TEST_SETUP(WakeWithSignal) +{ + int i; + + for (i = 0; i < MAX_THREADS; i++) + { + tid[i] = -1; + test_sd[i] = -1; + } + sem_init(&tid_startsem, 0, 0); + sem_init(&tid_releasesem, 0, 0); +} + +/**************************************************************************** + * Name: WakeWithSignal test group teardown + * + * Description: + * Setup function executed after each testcase in this test group + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +TEST_TEAR_DOWN(WakeWithSignal) +{ + int ret; + int i; + + for (i = 0; i < MAX_THREADS; i++) + { + if (tid[i] != -1) + { + ret = pthread_cancel(tid[i]); + assert(ret == OK); + ret = pthread_join(tid[i], NULL); + assert(ret == OK); + } + if (test_sd[i] != -1) + { + close(test_sd[i]); + test_sd[i] = -1; + } + } + sem_destroy(&tid_startsem); + sem_destroy(&tid_releasesem); +} + +/**************************************************************************** + * Name: WakeBlockingConnect + * + * Description: + * Wake blocking connect with signal + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +TEST(WakeWithSignal, WakeBlockingConnect) +{ + /* Configure test daemon. */ + + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + usrsocktest_daemon_config.delay_all_responses = false; + usrsocktest_daemon_config.endpoint_block_send = true; + usrsocktest_daemon_config.endpoint_block_connect = true; + usrsocktest_daemon_config.endpoint_addr = "127.0.0.1"; + usrsocktest_daemon_config.endpoint_port = 255; + + /* Run test. */ + + do_wake_test(TEST_TYPE_CONNECT, 0); +} + +/**************************************************************************** + * Name: WakeBlockingConnectMultiThread + * + * Description: + * Wake multiple blocking connect with signal + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +TEST(WakeWithSignal, WakeBlockingConnectMultiThread) +{ + /* Configure test daemon. */ + + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + usrsocktest_daemon_config.delay_all_responses = false; + usrsocktest_daemon_config.endpoint_block_send = true; + usrsocktest_daemon_config.endpoint_block_connect = true; + usrsocktest_daemon_config.endpoint_addr = "127.0.0.1"; + usrsocktest_daemon_config.endpoint_port = 255; + + /* Run test. */ + + do_wake_test(TEST_TYPE_CONNECT, TEST_FLAG_MULTI_THREAD); +} + +/**************************************************************************** + * Name: WakeBlockingSend + * + * Description: + * Wake blocking send with signal + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +TEST(WakeWithSignal, WakeBlockingSend) +{ + /* Configure test daemon. */ + + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + usrsocktest_daemon_config.delay_all_responses = false; + usrsocktest_daemon_config.endpoint_block_send = true; + usrsocktest_daemon_config.endpoint_block_connect = false; + usrsocktest_daemon_config.endpoint_addr = "127.0.0.1"; + usrsocktest_daemon_config.endpoint_port = 255; + + /* Run test. */ + + do_wake_test(TEST_TYPE_SEND, 0); +} + +/**************************************************************************** + * Name: WakeBlockingSendMultiThread + * + * Description: + * Wake multiple blocking send with signal + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +TEST(WakeWithSignal, WakeBlockingSendMultiThread) +{ + /* Configure test daemon. */ + + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + usrsocktest_daemon_config.delay_all_responses = false; + usrsocktest_daemon_config.endpoint_block_send = true; + usrsocktest_daemon_config.endpoint_block_connect = false; + usrsocktest_daemon_config.endpoint_addr = "127.0.0.1"; + usrsocktest_daemon_config.endpoint_port = 255; + + /* Run test. */ + + do_wake_test(TEST_TYPE_SEND, TEST_FLAG_MULTI_THREAD); +} +/**************************************************************************** + * Name: WakeBlockingRecv + * + * Description: + * Wake blocking recv with signal + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +TEST(WakeWithSignal, WakeBlockingRecv) +{ + /* Configure test daemon. */ + + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + usrsocktest_daemon_config.delay_all_responses = false; + usrsocktest_daemon_config.endpoint_block_send = false; + usrsocktest_daemon_config.endpoint_block_connect = false; + usrsocktest_daemon_config.endpoint_recv_avail = 0; + usrsocktest_daemon_config.endpoint_addr = "127.0.0.1"; + usrsocktest_daemon_config.endpoint_port = 255; + + /* Run test. */ + + do_wake_test(TEST_TYPE_RECV, 0); +} + +/**************************************************************************** + * Name: WakeBlockingRecvMultiThread + * + * Description: + * Wake multiple blocking recv with signal + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +TEST(WakeWithSignal, WakeBlockingRecvMultiThread) +{ + /* Configure test daemon. */ + + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + usrsocktest_daemon_config.delay_all_responses = false; + usrsocktest_daemon_config.endpoint_block_send = false; + usrsocktest_daemon_config.endpoint_block_connect = false; + usrsocktest_daemon_config.endpoint_recv_avail = 0; + usrsocktest_daemon_config.endpoint_addr = "127.0.0.1"; + usrsocktest_daemon_config.endpoint_port = 255; + + /* Run test. */ + + do_wake_test(TEST_TYPE_RECV, TEST_FLAG_MULTI_THREAD); +} + +/**************************************************************************** + * Name: AbortBlockingConnect + * + * Description: + * Wake blocking connect with daemon abort + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +TEST(WakeWithSignal, AbortBlockingConnect) +{ + /* Configure test daemon. */ + + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + usrsocktest_daemon_config.delay_all_responses = false; + usrsocktest_daemon_config.endpoint_block_send = true; + usrsocktest_daemon_config.endpoint_block_connect = true; + usrsocktest_daemon_config.endpoint_addr = "127.0.0.1"; + usrsocktest_daemon_config.endpoint_port = 255; + + /* Run test. */ + + do_wake_test(TEST_TYPE_CONNECT, TEST_FLAG_DAEMON_ABORT); +} + +/**************************************************************************** + * Name: AbortBlockingConnectMultiThread + * + * Description: + * Wake multiple blocking connect with daemon abort + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +TEST(WakeWithSignal, AbortBlockingConnectMultiThread) +{ + /* Configure test daemon. */ + + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + usrsocktest_daemon_config.delay_all_responses = false; + usrsocktest_daemon_config.endpoint_block_send = true; + usrsocktest_daemon_config.endpoint_block_connect = true; + usrsocktest_daemon_config.endpoint_addr = "127.0.0.1"; + usrsocktest_daemon_config.endpoint_port = 255; + + /* Run test. */ + + do_wake_test(TEST_TYPE_CONNECT, + TEST_FLAG_DAEMON_ABORT | TEST_FLAG_MULTI_THREAD); +} + +/**************************************************************************** + * Name: AbortBlockingSend + * + * Description: + * Wake blocking send with daemon abort + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +TEST(WakeWithSignal, AbortBlockingSend) +{ + /* Configure test daemon. */ + + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + usrsocktest_daemon_config.delay_all_responses = false; + usrsocktest_daemon_config.endpoint_block_send = true; + usrsocktest_daemon_config.endpoint_block_connect = false; + usrsocktest_daemon_config.endpoint_addr = "127.0.0.1"; + usrsocktest_daemon_config.endpoint_port = 255; + + /* Run test. */ + + do_wake_test(TEST_TYPE_SEND, TEST_FLAG_DAEMON_ABORT); +} + +/**************************************************************************** + * Name: AbortBlockingSendMultiThread + * + * Description: + * Wake multiple blocking send with daemon abort + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +TEST(WakeWithSignal, AbortBlockingSendMultiThread) +{ + /* Configure test daemon. */ + + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + usrsocktest_daemon_config.delay_all_responses = false; + usrsocktest_daemon_config.endpoint_block_send = true; + usrsocktest_daemon_config.endpoint_block_connect = false; + usrsocktest_daemon_config.endpoint_addr = "127.0.0.1"; + usrsocktest_daemon_config.endpoint_port = 255; + + /* Run test. */ + + do_wake_test(TEST_TYPE_SEND, + TEST_FLAG_DAEMON_ABORT | TEST_FLAG_MULTI_THREAD); +} + +/**************************************************************************** + * Name: AbortBlockingRecv + * + * Description: + * Wake blocking recv with daemon abort + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +TEST(WakeWithSignal, AbortBlockingRecv) +{ + /* Configure test daemon. */ + + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + usrsocktest_daemon_config.delay_all_responses = false; + usrsocktest_daemon_config.endpoint_block_send = false; + usrsocktest_daemon_config.endpoint_block_connect = false; + usrsocktest_daemon_config.endpoint_recv_avail = 0; + usrsocktest_daemon_config.endpoint_addr = "127.0.0.1"; + usrsocktest_daemon_config.endpoint_port = 255; + + /* Run test. */ + + do_wake_test(TEST_TYPE_RECV, TEST_FLAG_DAEMON_ABORT); +} + +/**************************************************************************** + * Name: AbortBlockingRecvMultiThread + * + * Description: + * Wake multiple blocking recv with daemon abort + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +TEST(WakeWithSignal, AbortBlockingRecvMultiThread) +{ + /* Configure test daemon. */ + + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + usrsocktest_daemon_config.delay_all_responses = false; + usrsocktest_daemon_config.endpoint_block_send = false; + usrsocktest_daemon_config.endpoint_block_connect = false; + usrsocktest_daemon_config.endpoint_recv_avail = 0; + usrsocktest_daemon_config.endpoint_addr = "127.0.0.1"; + usrsocktest_daemon_config.endpoint_port = 255; + + /* Run test. */ + + do_wake_test(TEST_TYPE_RECV, + TEST_FLAG_DAEMON_ABORT | TEST_FLAG_MULTI_THREAD); +} + +/**************************************************************************** + * Name: PendingRequestBlockingConnect + * + * Description: + * Wake blocking connect with daemon abort (and daemon not handling pending + * request before abort) + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +TEST(WakeWithSignal, PendingRequestBlockingConnect) +{ + /* Configure test daemon. */ + + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + usrsocktest_daemon_config.delay_all_responses = false; + usrsocktest_daemon_config.endpoint_block_send = true; + usrsocktest_daemon_config.endpoint_block_connect = true; + usrsocktest_daemon_config.endpoint_addr = "127.0.0.1"; + usrsocktest_daemon_config.endpoint_port = 255; + + /* Run test. */ + + do_wake_test(TEST_TYPE_CONNECT, + TEST_FLAG_DAEMON_ABORT | TEST_FLAG_PAUSE_USRSOCK_HANDLING); +} + +/**************************************************************************** + * Name: PendingRequestBlockingConnectMultiThread + * + * Description: + * Wake multiple blocking connect with daemon abort (and daemon not handling + * pending requests before abort) + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +TEST(WakeWithSignal, PendingRequestBlockingConnectMultiThread) +{ + /* Configure test daemon. */ + + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + usrsocktest_daemon_config.delay_all_responses = false; + usrsocktest_daemon_config.endpoint_block_send = true; + usrsocktest_daemon_config.endpoint_block_connect = true; + usrsocktest_daemon_config.endpoint_addr = "127.0.0.1"; + usrsocktest_daemon_config.endpoint_port = 255; + + /* Run test. */ + + do_wake_test(TEST_TYPE_CONNECT, + TEST_FLAG_DAEMON_ABORT | TEST_FLAG_PAUSE_USRSOCK_HANDLING | + TEST_FLAG_MULTI_THREAD); +} + +/**************************************************************************** + * Name: PendingRequestBlockingSend + * + * Description: + * Wake blocking send with daemon abort (and daemon not handling pending + * request before abort) + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +TEST(WakeWithSignal, PendingRequestBlockingSend) +{ + /* Configure test daemon. */ + + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + usrsocktest_daemon_config.delay_all_responses = false; + usrsocktest_daemon_config.endpoint_block_send = true; + usrsocktest_daemon_config.endpoint_block_connect = false; + usrsocktest_daemon_config.endpoint_addr = "127.0.0.1"; + usrsocktest_daemon_config.endpoint_port = 255; + + /* Run test. */ + + do_wake_test(TEST_TYPE_SEND, + TEST_FLAG_DAEMON_ABORT | TEST_FLAG_PAUSE_USRSOCK_HANDLING); +} + +/**************************************************************************** + * Name: PendingRequestBlockingSendMultiThread + * + * Description: + * Wake multiple blocking send with daemon abort (and daemon not handling + * pending requests before abort) + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +TEST(WakeWithSignal, PendingRequestBlockingSendMultiThread) +{ + /* Configure test daemon. */ + + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + usrsocktest_daemon_config.delay_all_responses = false; + usrsocktest_daemon_config.endpoint_block_send = true; + usrsocktest_daemon_config.endpoint_block_connect = false; + usrsocktest_daemon_config.endpoint_addr = "127.0.0.1"; + usrsocktest_daemon_config.endpoint_port = 255; + + /* Run test. */ + + do_wake_test(TEST_TYPE_SEND, + TEST_FLAG_DAEMON_ABORT | TEST_FLAG_PAUSE_USRSOCK_HANDLING | + TEST_FLAG_MULTI_THREAD); +} + +/**************************************************************************** + * Name: PendingRequestBlockingRecv + * + * Description: + * Wake blocking recv with daemon abort (and daemon not handling pending + * request before abort) + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +TEST(WakeWithSignal, PendingRequestBlockingRecv) +{ + /* Configure test daemon. */ + + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + usrsocktest_daemon_config.delay_all_responses = false; + usrsocktest_daemon_config.endpoint_block_send = false; + usrsocktest_daemon_config.endpoint_block_connect = false; + usrsocktest_daemon_config.endpoint_recv_avail = 0; + usrsocktest_daemon_config.endpoint_addr = "127.0.0.1"; + usrsocktest_daemon_config.endpoint_port = 255; + + /* Run test. */ + + do_wake_test(TEST_TYPE_RECV, + TEST_FLAG_DAEMON_ABORT | TEST_FLAG_PAUSE_USRSOCK_HANDLING); +} + +/**************************************************************************** + * Name: PendingRequestBlockingRecvMultiThread + * + * Description: + * Wake multiple blocking recv with daemon abort (and daemon not handling + * pending requests before abort) + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +TEST(WakeWithSignal, PendingRequestBlockingRecvMultiThread) +{ + /* Configure test daemon. */ + + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + usrsocktest_daemon_config.delay_all_responses = false; + usrsocktest_daemon_config.endpoint_block_send = false; + usrsocktest_daemon_config.endpoint_block_connect = false; + usrsocktest_daemon_config.endpoint_recv_avail = 0; + usrsocktest_daemon_config.endpoint_addr = "127.0.0.1"; + usrsocktest_daemon_config.endpoint_port = 255; + + /* Run test. */ + + do_wake_test(TEST_TYPE_RECV, + TEST_FLAG_DAEMON_ABORT | TEST_FLAG_PAUSE_USRSOCK_HANDLING | + TEST_FLAG_MULTI_THREAD); +} + +/**************************************************************************** + * Name: PendingRequestBlockingOpen + * + * Description: + * Wake blocking open with daemon abort (and daemon not handling pending + * request before abort) + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +TEST(WakeWithSignal, PendingRequestBlockingOpen) +{ + /* Configure test daemon. */ + + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + usrsocktest_daemon_config.delay_all_responses = false; + usrsocktest_daemon_config.endpoint_block_send = true; + usrsocktest_daemon_config.endpoint_block_connect = true; + usrsocktest_daemon_config.endpoint_recv_avail = 0; + usrsocktest_daemon_config.endpoint_addr = "127.0.0.1"; + usrsocktest_daemon_config.endpoint_port = 255; + + /* Run test. */ + + do_wake_test(TEST_TYPE_SOCKET, + TEST_FLAG_DAEMON_ABORT | TEST_FLAG_PAUSE_USRSOCK_HANDLING); +} + +/**************************************************************************** + * Name: PendingRequestBlockingOpenMultiThread + * + * Description: + * Wake multiple blocking open with daemon abort (and daemon not handling + * pending requests before abort) + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +TEST(WakeWithSignal, PendingRequestBlockingOpenMultiThread) +{ + /* Configure test daemon. */ + + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + usrsocktest_daemon_config.delay_all_responses = false; + usrsocktest_daemon_config.endpoint_block_send = true; + usrsocktest_daemon_config.endpoint_block_connect = true; + usrsocktest_daemon_config.endpoint_recv_avail = 0; + usrsocktest_daemon_config.endpoint_addr = "127.0.0.1"; + usrsocktest_daemon_config.endpoint_port = 255; + + /* Run test. */ + + do_wake_test(TEST_TYPE_SOCKET, + TEST_FLAG_DAEMON_ABORT | TEST_FLAG_PAUSE_USRSOCK_HANDLING | + TEST_FLAG_MULTI_THREAD); +} + +/**************************************************************************** + * Name: PendingRequestBlockingClose + * + * Description: + * Wake blocking close with daemon abort (and daemon not handling pending + * request before abort) + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +TEST(WakeWithSignal, PendingRequestBlockingClose) +{ + /* Configure test daemon. */ + + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + usrsocktest_daemon_config.delay_all_responses = false; + usrsocktest_daemon_config.endpoint_block_send = true; + usrsocktest_daemon_config.endpoint_block_connect = true; + usrsocktest_daemon_config.endpoint_recv_avail = 0; + usrsocktest_daemon_config.endpoint_addr = "127.0.0.1"; + usrsocktest_daemon_config.endpoint_port = 255; + + /* Run test. */ + + do_wake_test(TEST_TYPE_CLOSE, + TEST_FLAG_DAEMON_ABORT | TEST_FLAG_PAUSE_USRSOCK_HANDLING); +} + +/**************************************************************************** + * Name: PendingRequestBlockingCloseMultiThread + * + * Description: + * Wake multiple blocking close with daemon abort (and daemon not handling + * pending requests before abort) + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +TEST(WakeWithSignal, PendingRequestBlockingCloseMultiThread) +{ + /* Configure test daemon. */ + + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + usrsocktest_daemon_config.delay_all_responses = false; + usrsocktest_daemon_config.endpoint_block_send = true; + usrsocktest_daemon_config.endpoint_block_connect = true; + usrsocktest_daemon_config.endpoint_recv_avail = 0; + usrsocktest_daemon_config.endpoint_addr = "127.0.0.1"; + usrsocktest_daemon_config.endpoint_port = 255; + + /* Run test. */ + + do_wake_test(TEST_TYPE_CLOSE, + TEST_FLAG_DAEMON_ABORT | TEST_FLAG_PAUSE_USRSOCK_HANDLING | + TEST_FLAG_MULTI_THREAD); +} + +/**************************************************************************** + * Name: PendingRequestBlockingPoll + * + * Description: + * Wake blocking poll with daemon abort (and daemon not handling pending + * request before abort) + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +TEST(WakeWithSignal, PendingRequestBlockingPoll) +{ + /* Configure test daemon. */ + + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + usrsocktest_daemon_config.delay_all_responses = false; + usrsocktest_daemon_config.endpoint_block_send = true; + usrsocktest_daemon_config.endpoint_block_connect = false; + usrsocktest_daemon_config.endpoint_recv_avail = 0; + usrsocktest_daemon_config.endpoint_addr = "127.0.0.1"; + usrsocktest_daemon_config.endpoint_port = 255; + + /* Run test. */ + + do_wake_test(TEST_TYPE_POLL, + TEST_FLAG_DAEMON_ABORT | TEST_FLAG_PAUSE_USRSOCK_HANDLING); +} + +/**************************************************************************** + * Name: PendingRequestBlockingPollMultiThread + * + * Description: + * Wake multiple blocking poll with daemon abort (and daemon not handling + * pending requests before abort) + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +TEST(WakeWithSignal, PendingRequestBlockingPollMultiThread) +{ + /* Configure test daemon. */ + + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + usrsocktest_daemon_config.delay_all_responses = false; + usrsocktest_daemon_config.endpoint_block_send = true; + usrsocktest_daemon_config.endpoint_block_connect = false; + usrsocktest_daemon_config.endpoint_recv_avail = 0; + usrsocktest_daemon_config.endpoint_addr = "127.0.0.1"; + usrsocktest_daemon_config.endpoint_port = 255; + + /* Run test. */ + + do_wake_test(TEST_TYPE_POLL, + TEST_FLAG_DAEMON_ABORT | TEST_FLAG_PAUSE_USRSOCK_HANDLING | + TEST_FLAG_MULTI_THREAD); +} + +/**************************************************************************** + * Name: PendingRequestBlockingSetSockOpt + * + * Description: + * Wake blocking setsockopt with daemon abort (and daemon not handling pending + * request before abort) + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +TEST(WakeWithSignal, PendingRequestBlockingSetSockOpt) +{ + /* Configure test daemon. */ + + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + usrsocktest_daemon_config.delay_all_responses = false; + usrsocktest_daemon_config.endpoint_block_send = true; + usrsocktest_daemon_config.endpoint_block_connect = true; + usrsocktest_daemon_config.endpoint_recv_avail = 0; + usrsocktest_daemon_config.endpoint_addr = "127.0.0.1"; + usrsocktest_daemon_config.endpoint_port = 255; + + /* Run test. */ + + do_wake_test(TEST_TYPE_SETSOCKOPT, + TEST_FLAG_DAEMON_ABORT | TEST_FLAG_PAUSE_USRSOCK_HANDLING); +} + +/**************************************************************************** + * Name: PendingRequestBlockingSetSockOptMultiThread + * + * Description: + * Wake multiple blocking setsockopt with daemon abort (and daemon not + * handling pending requests before abort) + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +TEST(WakeWithSignal, PendingRequestBlockingSetSockOptMultiThread) +{ + /* Configure test daemon. */ + + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + usrsocktest_daemon_config.delay_all_responses = false; + usrsocktest_daemon_config.endpoint_block_send = true; + usrsocktest_daemon_config.endpoint_block_connect = true; + usrsocktest_daemon_config.endpoint_recv_avail = 0; + usrsocktest_daemon_config.endpoint_addr = "127.0.0.1"; + usrsocktest_daemon_config.endpoint_port = 255; + + /* Run test. */ + + do_wake_test(TEST_TYPE_SETSOCKOPT, + TEST_FLAG_DAEMON_ABORT | TEST_FLAG_PAUSE_USRSOCK_HANDLING | + TEST_FLAG_MULTI_THREAD); +} + +/**************************************************************************** + * Name: PendingRequestBlockingGetSockOpt + * + * Description: + * Wake blocking getsockopt with daemon abort (and daemon not handling pending + * request before abort) + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +TEST(WakeWithSignal, PendingRequestBlockingGetSockOpt) +{ + /* Configure test daemon. */ + + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + usrsocktest_daemon_config.delay_all_responses = false; + usrsocktest_daemon_config.endpoint_block_send = true; + usrsocktest_daemon_config.endpoint_block_connect = true; + usrsocktest_daemon_config.endpoint_recv_avail = 0; + usrsocktest_daemon_config.endpoint_addr = "127.0.0.1"; + usrsocktest_daemon_config.endpoint_port = 255; + + /* Run test. */ + + do_wake_test(TEST_TYPE_GETSOCKOPT, + TEST_FLAG_DAEMON_ABORT | TEST_FLAG_PAUSE_USRSOCK_HANDLING); +} + +/**************************************************************************** + * Name: PendingRequestBlockingGetSockOptMultiThread + * + * Description: + * Wake multiple blocking getsockopt with daemon abort (and daemon not + * handling pending requests before abort) + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions/Limitations: + * None + * + ****************************************************************************/ +TEST(WakeWithSignal, PendingRequestBlockingGetSockOptMultiThread) +{ + /* Configure test daemon. */ + + usrsocktest_daemon_config = usrsocktest_daemon_defconf; + usrsocktest_daemon_config.delay_all_responses = false; + usrsocktest_daemon_config.endpoint_block_send = true; + usrsocktest_daemon_config.endpoint_block_connect = true; + usrsocktest_daemon_config.endpoint_recv_avail = 0; + usrsocktest_daemon_config.endpoint_addr = "127.0.0.1"; + usrsocktest_daemon_config.endpoint_port = 255; + + /* Run test. */ + + do_wake_test(TEST_TYPE_GETSOCKOPT, + TEST_FLAG_DAEMON_ABORT | TEST_FLAG_PAUSE_USRSOCK_HANDLING | + TEST_FLAG_MULTI_THREAD); +}