Commit d79650d8 authored by tlh2000's avatar tlh2000

* applied patch #1702308 (Setup and Teardown functions) - but without changing...

* applied patch #1702308 (Setup and Teardown functions) - but without changing the interface (added CU_add_suite_with_setup_and_teardown)

git-svn-id: http://svn.code.sf.net/p/cunit/code/trunk@133 f00e6729-6848-4c17-8bfb-678c97c00071
parent 060a9c70
......@@ -41,6 +41,9 @@
* 15-Apr-2006 Removed constraint that suites/tests be uniquely named.
* Added ability to turn individual tests/suites on or off.
* Moved doxygen comments for public API here to header. (JDS)
*
* 16-Avr-2007 Added setup and teardown functions. (CJN)
*
*/
/** @file
......@@ -74,6 +77,8 @@ extern "C" {
typedef int (*CU_InitializeFunc)(void); /**< Signature for suite initialization function. */
typedef int (*CU_CleanupFunc)(void); /**< Signature for suite cleanup function. */
typedef void (*CU_TestFunc)(void); /**< Signature for a testing function in a test case. */
typedef void (*CU_SetUpFunc)(void); /**< Signature for a test SetUp function. */
typedef void (*CU_TearDownFunc)(void); /**< Signature for a test TearDown function. */
/*-----------------------------------------------------------------
* CU_Test, CU_pTest
......@@ -147,6 +152,8 @@ typedef struct CU_Suite
CU_pTest pTest; /**< Pointer to the 1st test in the suite. */
CU_InitializeFunc pInitializeFunc; /**< Pointer to the suite initialization function. */
CU_CleanupFunc pCleanupFunc; /**< Pointer to the suite cleanup function. */
CU_SetUpFunc pSetUpFunc; /**< Pointer to the test SetUp function. */
CU_TearDownFunc pTearDownFunc; /**< Pointer to the test TearDown function. */
unsigned int uiNumberOfTests; /**< Number of tests in the suite. */
struct CU_Suite* pNext; /**< Pointer to the next suite in linked list. */
......@@ -310,6 +317,20 @@ CU_pSuite CU_add_suite(const char *strName,
* @return A pointer to the newly-created suite (NULL if creation failed)
*/
CU_EXPORT
CU_pSuite CU_add_suite_with_setup_and_teardown(const char *strName,
CU_InitializeFunc pInit,
CU_CleanupFunc pClean,
CU_SetUpFunc pSetup,
CU_TearDownFunc pTear);
/**<
* The same as CU_add_suite but also adds setup and tear down callbacks for
* each test in this suite.
*
* @param pSetup SetUp function to call before running each test.
* @param pTear TearDown function to call after running each test.
*/
CU_EXPORT
CU_ErrorCode CU_set_suite_active(CU_pSuite pSuite, CU_BOOL fNewActive);
/**<
......@@ -673,16 +694,18 @@ typedef CU_TestInfo* CU_pTestInfo; /**< Pointer to CU_TestInfo type. */
* CU_register_suite() or CU_register_suites().
*/
typedef struct CU_SuiteInfo {
char *pName; /**< Suite name. */
CU_InitializeFunc pInitFunc; /**< Suite initialization function. */
CU_CleanupFunc pCleanupFunc; /**< Suite cleanup function */
CU_TestInfo *pTests; /**< Test case array - must be NULL terminated. */
const char *pName; /**< Suite name. */
CU_InitializeFunc pInitFunc; /**< Suite initialization function. */
CU_CleanupFunc pCleanupFunc; /**< Suite cleanup function */
CU_SetUpFunc pSetUpFunc; /**< Pointer to the test SetUp function. */
CU_TearDownFunc pTearDownFunc; /**< Pointer to the test TearDown function. */
CU_TestInfo *pTests; /**< Test case array - must be NULL terminated. */
} CU_SuiteInfo;
typedef CU_SuiteInfo* CU_pSuiteInfo; /**< Pointer to CU_SuiteInfo type. */
#define CU_TEST_INFO_NULL { NULL, NULL }
/**< NULL CU_test_info_t to terminate arrays of tests. */
#define CU_SUITE_INFO_NULL { NULL, NULL, NULL, NULL }
#define CU_SUITE_INFO_NULL { NULL, NULL, NULL, NULL, NULL, NULL }
/**< NULL CU_suite_info_t to terminate arrays of suites. */
......
......@@ -303,7 +303,7 @@ static void automated_test_complete_message_handler(const CU_pTest pTest,
size_t szTemp_len = 0;
size_t cur_len = 0;
CU_pFailureRecord pTempFailure = pFailure;
char *pPackageName = CU_automated_package_name_get();
const char *pPackageName = CU_automated_package_name_get();
CU_UNREFERENCED_PARAMETER(pSuite); /* pSuite is not used except in assertion */
......
......@@ -44,7 +44,10 @@
* Modified internal unit tests to include these changes. (JDS)
*
* 02-May-2006 Added internationalization hooks. (JDS)
*/
*
* 16-Avr-2007 Added setup and teardown functions. (CJN)
*
*/
/** @file
* Management functions for tests, suites, and the test registry (implementation).
......@@ -75,7 +78,7 @@ static CU_pTestRegistry f_pTestRegistry = NULL; /**< The active internal Test Re
* Private function forward declarations
*=================================================================*/
static void cleanup_test_registry(CU_pTestRegistry pRegistry);
static CU_pSuite create_suite(const char* strName, CU_InitializeFunc pInit, CU_CleanupFunc pClean);
static CU_pSuite create_suite(const char* strName, CU_InitializeFunc pInit, CU_CleanupFunc pClean, CU_SetUpFunc pSetup, CU_TearDownFunc pTear);
static void cleanup_suite(CU_pSuite pSuite);
static void insert_suite(CU_pTestRegistry pRegistry, CU_pSuite pSuite);
static CU_pTest create_test(const char* strName, CU_TestFunc pTestFunc);
......@@ -144,7 +147,7 @@ CU_pTestRegistry CU_set_registry(CU_pTestRegistry pRegistry)
}
/*------------------------------------------------------------------------*/
CU_pSuite CU_add_suite(const char* strName, CU_InitializeFunc pInit, CU_CleanupFunc pClean)
CU_pSuite CU_add_suite_with_setup_and_teardown(const char* strName, CU_InitializeFunc pInit, CU_CleanupFunc pClean, CU_SetUpFunc pSetup, CU_TearDownFunc pTear)
{
CU_pSuite pRetValue = NULL;
CU_ErrorCode error = CUE_SUCCESS;
......@@ -158,7 +161,7 @@ CU_pSuite CU_add_suite(const char* strName, CU_InitializeFunc pInit, CU_CleanupF
error = CUE_NO_SUITENAME;
}
else {
pRetValue = create_suite(strName, pInit, pClean);
pRetValue = create_suite(strName, pInit, pClean, pSetup, pTear);
if (NULL == pRetValue) {
error = CUE_NOMEMORY;
}
......@@ -174,6 +177,12 @@ CU_pSuite CU_add_suite(const char* strName, CU_InitializeFunc pInit, CU_CleanupF
return pRetValue;
}
/*------------------------------------------------------------------------*/
CU_pSuite CU_add_suite(const char* strName, CU_InitializeFunc pInit, CU_CleanupFunc pClean)
{
return CU_add_suite_with_setup_and_teardown(strName, pInit, pClean, NULL, NULL);
}
/*------------------------------------------------------------------------*/
CU_ErrorCode CU_set_suite_active(CU_pSuite pSuite, CU_BOOL fNewActive)
{
......@@ -574,7 +583,7 @@ CU_ErrorCode CU_register_nsuites(int suite_count, ...)
pSuiteItem = va_arg(argptr, CU_pSuiteInfo);
if (NULL != pSuiteItem) {
for ( ; NULL != pSuiteItem->pName; pSuiteItem++) {
if (NULL != (pSuite = CU_add_suite(pSuiteItem->pName, pSuiteItem->pInitFunc, pSuiteItem->pCleanupFunc))) {
if (NULL != (pSuite = CU_add_suite_with_setup_and_teardown(pSuiteItem->pName, pSuiteItem->pInitFunc, pSuiteItem->pCleanupFunc, pSuiteItem->pSetUpFunc, pSuiteItem->pTearDownFunc))) {
for (pTestItem = pSuiteItem->pTests; NULL != pTestItem->pName; pTestItem++) {
if (NULL == CU_add_test(pSuite, pTestItem->pName, pTestItem->pTestFunc)) {
return CU_get_error();
......@@ -651,7 +660,7 @@ static void cleanup_test_registry(CU_pTestRegistry pRegistry)
* @param pClean Cleanup function to call after running suite.
* @return A pointer to the newly-created suite (NULL if creation failed)
*/
static CU_pSuite create_suite(const char* strName, CU_InitializeFunc pInit, CU_CleanupFunc pClean)
static CU_pSuite create_suite(const char* strName, CU_InitializeFunc pInit, CU_CleanupFunc pClean, CU_SetUpFunc pSetup, CU_TearDownFunc pTear)
{
CU_pSuite pRetValue = (CU_pSuite)CU_MALLOC(sizeof(CU_Suite));
......@@ -664,6 +673,8 @@ static CU_pSuite create_suite(const char* strName, CU_InitializeFunc pInit, CU_C
pRetValue->fActive = CU_TRUE;
pRetValue->pInitializeFunc = pInit;
pRetValue->pCleanupFunc = pClean;
pRetValue->pSetUpFunc = pSetup;
pRetValue->pTearDownFunc = pTear;
pRetValue->pTest = NULL;
pRetValue->pNext = NULL;
pRetValue->pPrev = NULL;
......@@ -2197,8 +2208,8 @@ static void test_cleanup_test_registry(void)
pTest4 = create_test("", NULL);
/* create suites to hold tests */
pSuite1 = create_suite("suite1", NULL, NULL);
pSuite2 = create_suite("suite2", sfunc1, sfunc1);
pSuite1 = create_suite("suite1", NULL, NULL, NULL, NULL);
pSuite2 = create_suite("suite2", sfunc1, sfunc1, NULL, NULL);
insert_suite(pReg, pSuite1);
insert_suite(pReg, pSuite2);
......@@ -2263,12 +2274,12 @@ static void test_create_suite(void)
/* error condition - memory allocation failure */
test_cunit_deactivate_malloc();
pSuite1 = create_suite("suite1", NULL, NULL);
pSuite1 = create_suite("suite1", NULL, NULL, NULL, NULL);
TEST(NULL == pSuite1);
test_cunit_activate_malloc();
/* normal creation & cleanup */
pSuite1 = create_suite("suite1", NULL, NULL);
pSuite1 = create_suite("suite1", NULL, NULL, NULL, NULL);
TEST(NULL != pSuite1);
TEST(!strcmp("suite1", pSuite1->pName));
TEST(pSuite1->pTest == NULL); /* no tests added yet */
......@@ -2277,7 +2288,7 @@ static void test_create_suite(void)
TEST(pSuite1->pCleanupFunc == NULL); /* no cleanup function */
TEST(pSuite1->pNext == NULL); /* no more suites added yet */
pSuite2 = create_suite("suite2", sfunc1, NULL);
pSuite2 = create_suite("suite2", sfunc1, NULL, NULL, NULL);
TEST(NULL != pSuite2);
TEST(!strcmp("suite2", pSuite2->pName));
TEST(pSuite2->pTest == NULL); /* no tests added yet */
......@@ -2286,7 +2297,7 @@ static void test_create_suite(void)
TEST(pSuite2->pCleanupFunc == NULL); /* no cleanup function */
TEST(pSuite2->pNext == NULL); /* no more suites added yet */
pSuite3 = create_suite("suite3", NULL, sfunc1);
pSuite3 = create_suite("suite3", NULL, sfunc1, NULL, NULL);
TEST(NULL != pSuite3);
TEST(!strcmp("suite3", pSuite3->pName));
TEST(pSuite3->pTest == NULL); /* no tests added yet */
......@@ -2295,7 +2306,7 @@ static void test_create_suite(void)
TEST(pSuite3->pCleanupFunc == sfunc1); /* cleanup function */
TEST(pSuite3->pNext == NULL); /* no more suites added yet */
pSuite4 = create_suite("suite4", sfunc1, sfunc1);
pSuite4 = create_suite("suite4", sfunc1, sfunc1, NULL, NULL);
TEST(NULL != pSuite4);
TEST(!strcmp("suite4", pSuite4->pName));
TEST(pSuite4->pTest == NULL); /* no tests added yet */
......@@ -2353,7 +2364,7 @@ static void test_insert_suite(void)
TEST(CU_FALSE == suite_exists(pReg, ""));
/* normal creation & cleanup */
pSuite1 = create_suite("suite1", NULL, NULL);
pSuite1 = create_suite("suite1", NULL, NULL, NULL, NULL);
insert_suite(pReg, pSuite1);
TEST(1 == pReg->uiNumberOfSuites);
TEST(0 == pReg->uiNumberOfTests);
......@@ -2366,7 +2377,7 @@ static void test_insert_suite(void)
TEST(CU_FALSE == suite_exists(pReg, "suite5"));
TEST(CU_FALSE == suite_exists(pReg, ""));
pSuite2 = create_suite("suite2", sfunc1, NULL);
pSuite2 = create_suite("suite2", sfunc1, NULL, NULL, NULL);
insert_suite(pReg, pSuite2);
TEST(2 == pReg->uiNumberOfSuites);
TEST(0 == pReg->uiNumberOfTests);
......@@ -2380,7 +2391,7 @@ static void test_insert_suite(void)
TEST(CU_FALSE == suite_exists(pReg, "suite5"));
TEST(CU_FALSE == suite_exists(pReg, ""));
pSuite3 = create_suite("suite3", NULL, sfunc1);
pSuite3 = create_suite("suite3", NULL, sfunc1, NULL, NULL);
insert_suite(pReg, pSuite3);
TEST(3 == pReg->uiNumberOfSuites);
TEST(0 == pReg->uiNumberOfTests);
......@@ -2395,7 +2406,7 @@ static void test_insert_suite(void)
TEST(CU_FALSE == suite_exists(pReg, "suite5"));
TEST(CU_FALSE == suite_exists(pReg, ""));
pSuite4 = create_suite("suite4", sfunc1, sfunc1);
pSuite4 = create_suite("suite4", sfunc1, sfunc1, NULL, NULL);
insert_suite(pReg, pSuite4);
TEST(4 == pReg->uiNumberOfSuites);
TEST(0 == pReg->uiNumberOfTests);
......@@ -2503,8 +2514,8 @@ static void test_insert_test(void)
pTest4 = create_test("", NULL);
/* create suites to hold tests */
pSuite1 = create_suite("suite1", NULL, NULL);
pSuite2 = create_suite("suite2", sfunc1, sfunc1);
pSuite1 = create_suite("suite1", NULL, NULL, NULL, NULL);
pSuite2 = create_suite("suite2", sfunc1, sfunc1, NULL, NULL);
TEST(CU_FALSE == test_exists(pSuite1, "test1"));
TEST(CU_FALSE == test_exists(pSuite1, "test2"));
......@@ -2663,20 +2674,20 @@ static CU_SuiteInfo suites0[] = {
};
static CU_SuiteInfo suites1[] = {
{ "A1", NULL, NULL, group_A_test_cases },
{ "B1", NULL, NULL, group_B_test_cases },
{ "A1", NULL, NULL, NULL, NULL, group_A_test_cases },
{ "B1", NULL, NULL, NULL, NULL, group_B_test_cases },
CU_SUITE_INFO_NULL,
};
static CU_SuiteInfo suites2[] = {
{ "A2", NULL, NULL, group_A_test_cases },
{ "B2", NULL, NULL, group_B_test_cases },
{ "A2", NULL, NULL, NULL, NULL, group_A_test_cases },
{ "B2", NULL, NULL, NULL, NULL, group_B_test_cases },
CU_SUITE_INFO_NULL,
};
static CU_SuiteInfo suites3[] = {
{ "A3", NULL, NULL, group_A_test_cases },
{ "A3", NULL, NULL, group_C_test_cases }, /* duplicate suite name */
{ "A3", NULL, NULL, NULL, NULL, group_A_test_cases },
{ "A3", NULL, NULL, NULL, NULL, group_C_test_cases }, /* duplicate suite name */
CU_SUITE_INFO_NULL,
};
......
......@@ -59,6 +59,9 @@
* 02-Jun-2006 Added support for elapsed time. Added handlers for suite
* start and complete events. Reworked test run routines to
* better support these features, suite/test activation. (JDS)
*
* 16-Avr-2007 Added setup and teardown functions. (CJN)
*
*/
/** @file
......@@ -90,7 +93,7 @@ static CU_pSuite f_pCurSuite = NULL; /**< Pointer to the suite currentl
static CU_pTest f_pCurTest = NULL; /**< Pointer to the test currently being run. */
/** CU_RunSummary to hold results of each test run. */
static CU_RunSummary f_run_summary = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
static CU_RunSummary f_run_summary = {"", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
/** CU_pFailureRecord to hold head of failure record list of each test run. */
static CU_pFailureRecord f_failure_list = NULL;
......@@ -977,6 +980,10 @@ static CU_ErrorCode run_single_test(CU_pTest pTest, CU_pRunSummary pRunSummary)
/* run test if it is active */
if (CU_FALSE != pTest->fActive) {
if (NULL != f_pCurSuite->pSetUpFunc) {
(*f_pCurSuite->pSetUpFunc)();
}
/* set jmp_buf and run test */
pTest->pJumpBuf = &buf;
if (0 == setjmp(buf)) {
......@@ -985,6 +992,10 @@ static CU_ErrorCode run_single_test(CU_pTest pTest, CU_pRunSummary pRunSummary)
}
}
if (NULL != f_pCurSuite->pTearDownFunc) {
(*f_pCurSuite->pTearDownFunc)();
}
pRunSummary->nTestsRun++;
}
else {
......@@ -1353,6 +1364,15 @@ static void test_fail(void) { CU_TEST(CU_FALSE); }
static int suite_succeed(void) { return 0; }
static int suite_fail(void) { return 1; }
static CU_BOOL SetUp_Passed;
static void test_succeed_if_setup(void) { CU_TEST(SetUp_Passed); }
static void test_fail_if_not_setup(void) { CU_TEST(SetUp_Passed); }
static void suite_setup(void) { SetUp_Passed = CU_TRUE; }
static void suite_teardown(void) { SetUp_Passed = CU_FALSE; }
/*-------------------------------------------------*/
/* tests:
* CU_set_suite_start_handler()
......@@ -2079,6 +2099,7 @@ static void test_CU_run_all_tests(void)
CU_cleanup_registry();
}
/*-------------------------------------------------*/
static void test_CU_run_suite(void)
{
......@@ -2086,6 +2107,8 @@ static void test_CU_run_suite(void)
CU_pSuite pSuite2 = NULL;
CU_pSuite pSuite3 = NULL;
CU_pSuite pSuite4 = NULL;
CU_pSuite pSuite5 = NULL;
CU_pSuite pSuite6 = NULL;
CU_pTest pTest1 = NULL;
CU_pTest pTest2 = NULL;
CU_pTest pTest3 = NULL;
......@@ -2095,6 +2118,8 @@ static void test_CU_run_suite(void)
CU_pTest pTest7 = NULL;
CU_pTest pTest8 = NULL;
CU_pTest pTest9 = NULL;
CU_pTest pTest10 = NULL;
CU_pTest pTest11 = NULL;
/* error - NULL suite (CUEA_IGNORE) */
CU_set_error_action(CUEA_IGNORE);
......@@ -2131,9 +2156,13 @@ static void test_CU_run_suite(void)
pTest8 = CU_add_test(pSuite3, "test8", test_fail);
pTest9 = CU_add_test(pSuite3, "test8", test_succeed); /* duplicate test name OK */
pSuite4 = CU_add_suite("suite4", NULL, NULL);
pSuite5 = CU_add_suite_with_setup_and_teardown("suite5", NULL, NULL, suite_setup, suite_teardown);
pTest10 = CU_add_test(pSuite5, "test10", test_succeed_if_setup);
pSuite6 = CU_add_suite("suite6", NULL, NULL);
pTest11 = CU_add_test(pSuite6, "test11", test_fail_if_not_setup);
TEST_FATAL(4 == CU_get_registry()->uiNumberOfSuites);
TEST_FATAL(9 == CU_get_registry()->uiNumberOfTests);
TEST_FATAL(6 == CU_get_registry()->uiNumberOfSuites);
TEST_FATAL(11 == CU_get_registry()->uiNumberOfTests);
/* run each suite (CUEA_IGNORE) */
CU_set_error_action(CUEA_IGNORE);
......@@ -2150,6 +2179,12 @@ static void test_CU_run_suite(void)
TEST(CUE_SUCCESS == CU_run_suite(pSuite4));
test_results(1,0,0,0,0,0,0,0,0,0);
TEST(CUE_SUCCESS == CU_run_suite(pSuite5));
test_results(1,0,0,1,0,0,1,1,0,0);
TEST(CUE_SUCCESS == CU_run_suite(pSuite6));
test_results(1,0,0,1,1,0,1,0,1,1);
CU_set_suite_active(pSuite3, CU_FALSE);
CU_set_fail_on_inactive(CU_FALSE);
TEST(CUE_SUCCESS == CU_run_suite(pSuite3)); /* suite inactive */
......@@ -2807,7 +2842,7 @@ static void test_add_failure(void)
CU_pFailureRecord pFailure2 = NULL;
CU_pFailureRecord pFailure3 = NULL;
CU_pFailureRecord pFailure4 = NULL;
CU_RunSummary run_summary = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
CU_RunSummary run_summary = {"", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
/* test under memory exhaustion */
test_cunit_deactivate_malloc();
......
......@@ -319,22 +319,22 @@ static CU_TestInfo tests_fatal[] = {
};
static CU_SuiteInfo suites[] = {
{ "suite_success_both", suite_success_init, suite_success_clean, tests_success },
{ "suite_success_init", suite_success_init, NULL, tests_success },
{ "suite_success_clean", NULL, suite_success_clean, tests_success },
{ "test_failure", NULL, NULL, tests_failure },
{ "suite_failure_both", suite_failure_init, suite_failure_clean, tests_suitefailure }, /* tests should not run */
{ "suite_failure_init", suite_failure_init, NULL, tests_suitefailure }, /* tests should not run */
{ "suite_success_but_failure_clean", NULL, suite_failure_clean, tests_suitefailure }, /* tests will run, suite counted as running, but suite tagged as a failure */
{ "TestSimpleAssert", NULL, NULL, tests_simple },
{ "TestBooleanAssert", NULL, NULL, tests_bool },
{ "TestEqualityAssert", NULL, NULL, tests_equal },
{ "TestPointerAssert", NULL, NULL, tests_ptr },
{ "TestNullnessAssert", NULL, NULL, tests_null },
{ "TestStringAssert", NULL, NULL, tests_string },
{ "TestNStringAssert", NULL, NULL, tests_nstring },
{ "TestDoubleAssert", NULL, NULL, tests_double },
{ "TestFatal", NULL, NULL, tests_fatal },
{ "suite_success_both", suite_success_init, suite_success_clean, NULL, NULL, tests_success},
{ "suite_success_init", suite_success_init, NULL, NULL, NULL, tests_success},
{ "suite_success_clean", NULL, suite_success_clean, NULL, NULL, tests_success},
{ "test_failure", NULL, NULL, NULL, NULL, tests_failure},
{ "suite_failure_both", suite_failure_init, suite_failure_clean, NULL, NULL, tests_suitefailure}, /* tests should not run */
{ "suite_failure_init", suite_failure_init, NULL, NULL, NULL, tests_suitefailure}, /* tests should not run */
{ "suite_success_but_failure_clean", NULL, suite_failure_clean, NULL, NULL, tests_suitefailure}, /* tests will run, suite counted as running, but suite tagged as a failure */
{ "TestSimpleAssert", NULL, NULL, NULL, NULL, tests_simple},
{ "TestBooleanAssert", NULL, NULL, NULL, NULL, tests_bool},
{ "TestEqualityAssert", NULL, NULL, NULL, NULL, tests_equal},
{ "TestPointerAssert", NULL, NULL, NULL, NULL, tests_ptr},
{ "TestNullnessAssert", NULL, NULL, NULL, NULL, tests_null},
{ "TestStringAssert", NULL, NULL, NULL, NULL, tests_string},
{ "TestNStringAssert", NULL, NULL, NULL, NULL, tests_nstring},
{ "TestDoubleAssert", NULL, NULL, NULL, NULL, tests_double},
{ "TestFatal", NULL, NULL, NULL, NULL, tests_fatal},
CU_SUITE_INFO_NULL,
};
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment