agent/native/ext/unit_tests/unit_test_util.cpp (119 lines of code) (raw):

/* * Licensed to Elasticsearch B.V. under one or more contributor * license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright * ownership. Elasticsearch B.V. licenses this file to you under * the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #include "cmocka_wrapped_for_unit_tests.h" #include "unit_test_util.h" #include <string.h> #include "ResultCode.h" #include "elastic_apm_assert.h" #include "elastic_apm_alloc.h" #include "log.h" static void elasticApmCmockaFail( String filePath, int lineNumber ) ELASTIC_APM_NO_RETURN_ATTRIBUTE; static void elasticApmCmockaFail( String filePath, int lineNumber ) { _fail( extractLastPartOfFilePathString( filePath ), lineNumber ); elasticApmAbort(); } #define ELASTIC_APM_CMOCKA_PRINT_ERROR( printfFmt, /* printfFmtArgs: */ ... ) \ cm_print_error( printfFmt"\n", ##__VA_ARGS__ ) void elasticApmCmockaAssertStringEqual( String left, String right, String leftExprStringized, String rightExprStringized, String filePath, int lineNumber, String printfFmt, /* printfFmt args */ ... ) { if ( strcmp( left, right ) == 0) return; char txtOutStreamBuf[ ELASTIC_APM_TEXT_OUTPUT_STREAM_ON_STACK_BUFFER_SIZE * 10 ]; TextOutputStream txtOutStream = ELASTIC_APM_TEXT_OUTPUT_STREAM_FROM_STATIC_BUFFER( txtOutStreamBuf ); va_list msgArgs; va_start( msgArgs, printfFmt ); String additionalMessage = streamVPrintf( &txtOutStream, printfFmt, msgArgs ); va_end( msgArgs ); ELASTIC_APM_CMOCKA_PRINT_ERROR( "Assertion:" "\n\n" "\t" "%s == %s" "\n\n" "failed:" "\n\n" "\t" "%s:" "\n\n" "\t\t" "`%s'" "\n\n" "\t" "%s:" "\n\n" "\t\t" "`%s'" "\n\n" "%s\n", leftExprStringized, rightExprStringized, leftExprStringized, left, rightExprStringized, right, additionalMessage ); elasticApmCmockaFail( filePath, lineNumber ); } static ResultCode strdup_StringView_as_C_string( StringView src, String* dst ) { ELASTIC_APM_ASSERT_VALID_OUT_PTR_TO_PTR( dst ); ResultCode resultCode; char* dup_as_C_string = NULL; ELASTIC_APM_PEMALLOC_STRING_IF_FAILED_GOTO( src.length + 1, dup_as_C_string ); strncpy( dup_as_C_string, src.begin, src.length ); dup_as_C_string[ src.length ] = '\0'; *dst = dup_as_C_string; resultCode = resultSuccess; finally: return resultCode; failure: ELASTIC_APM_PEMALLOC_STRING_IF_FAILED_GOTO( src.length + 1, dup_as_C_string ); goto finally; } static ResultCode assert_StringView_equal_impl( StringView a, StringView b, String file, int line ) { ResultCode resultCode; String a_as_C_string = NULL; String b_as_C_string = NULL; ELASTIC_APM_CALL_IF_FAILED_GOTO( strdup_StringView_as_C_string( a, &a_as_C_string ) ); ELASTIC_APM_CALL_IF_FAILED_GOTO( strdup_StringView_as_C_string( b, &b_as_C_string ) ); _assert_string_equal( a_as_C_string, b_as_C_string, file, line ); resultCode = resultSuccess; finally: ELASTIC_APM_PEFREE_STRING_SIZE_AND_SET_TO_NULL( a.length + 1, a_as_C_string ); ELASTIC_APM_PEFREE_STRING_SIZE_AND_SET_TO_NULL( b.length + 1, b_as_C_string ); ELASTIC_APM_CMOCKA_CALL_ASSERT_RESULT_SUCCESS( resultCode ); return resultCode; failure: goto finally; } void elasticApmCmockaAssertStringViewEqual( StringView a, StringView b, String filePath, int lineNumber ) { ELASTIC_APM_CMOCKA_CALL_ASSERT_RESULT_SUCCESS( assert_StringView_equal_impl( a, b, filePath, lineNumber ) ); } static const char* find_substring_ignore_case( String haystack, String needle ) { ELASTIC_APM_ASSERT_VALID_STRING( haystack ); ELASTIC_APM_ASSERT_VALID_STRING( needle ); // Edge case: The empty string is a substring of everything if ( isEmtpyString( needle ) ) return haystack; // Loop over all possible start positions for ( const char* pHaystack = haystack ; *pHaystack != '\0' ; ++pHaystack ) { // See if needle matches starting from pHaystack for ( const char* pNeedle = needle, * pHaystack2 = pHaystack ; true ; ++pNeedle, ++pHaystack2 ) { // If we reached end of needle then we found a match that starts from pHaystack if ( *pNeedle == '\0' ) return pHaystack; // If we found mismatch then we need to go back to outer loop if ( ! areCharsEqualIgnoringCase( *pNeedle, *pHaystack2 ) ) break; // If we reached end of haystack then we won't be able to find a match // because the remainder of haystack is too short to contain needle if ( *pHaystack2 == '\0' ) return NULL; } } return NULL; } void elasticApmCmockaAssertStringContainsIgnoreCase( String haystack, String needle, String fileName, int lineNumber ) { if ( find_substring_ignore_case( haystack, needle ) != NULL ) return; ELASTIC_APM_CMOCKA_ASSERT_FAILED( fileName, lineNumber, "Assertion that a string contains another one (ignoring case) has failed." " haystack: `%s'. needle: `%s'.", haystack, needle ); }