The stock:
Code: Select all
/**
* Given a number on a certain base until 10, calculates and return the equivalent number on another
* base until 10.
*
* @param origin_number the number to be converted.
* @param origin_base the base where `origin_number` is on.
* @param destiny_base the base where `origin_number` is to be converted to.
*/
stock convert_numeric_base( origin_number, origin_base, destiny_base )
{
new integer;
new Array:digits;
digits = toDigitsRepresentation( origin_number, 10 );
integer = fromDigitsRepresentation( digits, origin_base );
ArrayDestroy( digits );
digits = toDigitsRepresentation( integer, destiny_base );
integer = fromDigitsRepresentation( digits, 10 );
ArrayDestroy( digits );
return integer;
}
/**
* Read an digits Dynamic Array at its given base and return an integer representation.
*
* @param digits a Dynamic Array within the digits of inputed number on the specified base.
* @param origin_base the base where `digits` are represented.
*
* return an integer representation inputed number on the specified base.
*/
stock fromDigitsRepresentation( Array:digits, origin_base )
{
new integer;
new arraySize = ArraySize( digits );
for( new index = 0; index < arraySize; index ++ )
{
integer = integer * origin_base + ArrayGetCell( digits, index );
}
return integer;
}
/**
* Create an Dynamic Array within of the decimal number at its given base.
*
* @param origin_number a decimal number to be converted.
* @param origin_base the base where `origin_number` is to be converted to.
*
* return a Dynamic Array within the digits of inputed number on the specified base.
*/
stock Array:toDigitsRepresentation( origin_number, origin_base )
{
new Array:digits = ArrayCreate();
ArrayPushCell( digits, origin_number % origin_base );
origin_number = origin_number / origin_base;
while( origin_number > 0 )
{
ArrayInsertCellBefore( digits, 0, origin_number % origin_base );
origin_number = origin_number / origin_base;
}
return digits;
}Code: Select all
L 12/29/2016 - 16:59:05: {1.000 16292 -1944939 -1944939} I AM ENTERING ON configureTheUnitTests(0)
L 12/29/2016 - 16:59:05: {1.000 16296 -1944936 3}
L 12/29/2016 - 16:59:05: {1.000 16296 -1944919 17}
L 12/29/2016 - 16:59:05: {1.000 16296 -1944914 5}
L 12/29/2016 - 16:59:05: {1.000 16296 -1944910 4}
L 12/29/2016 - 16:59:05: {1.000 16296 -1944904 6}
L 12/29/2016 - 16:59:05: {1.000 14928 -1944899 5} EXECUTING TEST 1 AFTER 1 SECONDS - test_convertNumericBase.aa_case1
L 12/29/2016 - 16:59:05: {1.000 15196 -1944889 10} I AM ENTERING ON convert_numeric_base(3) | number: 10 (7->10)
L 12/29/2016 - 16:59:05: {1.000 14692 -1944886 3} Array Cells: (0) 1, (1) 0,
L 12/29/2016 - 16:59:05: {1.000 14692 -1944882 4} Array Cells: (0) 7,
L 12/29/2016 - 16:59:05: {1.000 15196 -1944878 4} ( convert_numeric_base ) Returning integer: 7
L 12/29/2016 - 16:59:05: {1.000 14904 -1944872 6} ( displaysLastTestOk ) numberOfFailures: 0, lastFailure: 0, lastTestId: 1
L 12/29/2016 - 16:59:05: {1.000 14920 -1944868 4} OK!
L 12/29/2016 - 16:59:05: {1.000 14920 -1944863 5}
L 12/29/2016 - 16:59:05: {1.000 14920 -1944859 4}
L 12/29/2016 - 16:59:05: {1.000 14928 -1944853 6} EXECUTING TEST 2 AFTER 1 SECONDS - test_convertNumericBase.aa_case2
L 12/29/2016 - 16:59:05: {1.000 15196 -1944849 4} I AM ENTERING ON convert_numeric_base(3) | number: 10 (6->10)
L 12/29/2016 - 16:59:05: {1.000 14692 -1944845 4} Array Cells: (0) 1, (1) 0,
L 12/29/2016 - 16:59:05: {1.000 14692 -1944841 4} Array Cells: (0) 6,
L 12/29/2016 - 16:59:05: {1.000 15196 -1944836 5} ( convert_numeric_base ) Returning integer: 6
L 12/29/2016 - 16:59:05: {1.000 14904 -1944832 4} ( displaysLastTestOk ) numberOfFailures: 0, lastFailure: 0, lastTestId: 2
L 12/29/2016 - 16:59:05: {1.000 14920 -1944828 4} OK!
L 12/29/2016 - 16:59:05: {1.000 14920 -1944822 6}
L 12/29/2016 - 16:59:05: {1.000 14920 -1944816 6}
L 12/29/2016 - 16:59:05: {1.000 14928 -1944812 4} EXECUTING TEST 3 AFTER 1 SECONDS - test_convertNumericBase.aa_case3
L 12/29/2016 - 16:59:05: {1.000 15196 -1944808 4} I AM ENTERING ON convert_numeric_base(3) | number: 10 (5->10)
L 12/29/2016 - 16:59:05: {1.000 14692 -1944803 5} Array Cells: (0) 1, (1) 0,
L 12/29/2016 - 16:59:06: {1.000 14692 -1944798 5} Array Cells: (0) 5,
L 12/29/2016 - 16:59:06: {1.000 15196 -1944794 4} ( convert_numeric_base ) Returning integer: 5
L 12/29/2016 - 16:59:06: {1.000 14904 -1944790 4} ( displaysLastTestOk ) numberOfFailures: 0, lastFailure: 0, lastTestId: 3
L 12/29/2016 - 16:59:06: {1.000 14920 -1944784 6} OK!
L 12/29/2016 - 16:59:06: {1.000 14920 -1944779 5}
L 12/29/2016 - 16:59:06: {1.000 14920 -1944776 3}
L 12/29/2016 - 16:59:06: {1.000 14928 -1944769 7} EXECUTING TEST 4 AFTER 2 SECONDS - test_convertNumericBase.aa_case4
L 12/29/2016 - 16:59:06: {1.000 15196 -1944765 4} I AM ENTERING ON convert_numeric_base(3) | number: 10 (8->10)
L 12/29/2016 - 16:59:06: {1.000 14692 -1944761 4} Array Cells: (0) 1, (1) 0,
L 12/29/2016 - 16:59:06: {1.000 14692 -1944758 3} Array Cells: (0) 8,
L 12/29/2016 - 16:59:06: {1.000 15196 -1944751 7} ( convert_numeric_base ) Returning integer: 8
L 12/29/2016 - 16:59:06: {1.000 14904 -1944748 3} ( displaysLastTestOk ) numberOfFailures: 0, lastFailure: 0, lastTestId: 4
L 12/29/2016 - 16:59:06: {1.000 14920 -1944744 4} OK!
L 12/29/2016 - 16:59:06: {1.000 14920 -1944736 8}
L 12/29/2016 - 16:59:06: {1.000 14920 -1944732 4}
L 12/29/2016 - 16:59:06: {1.000 14928 -1944730 2} EXECUTING TEST 5 AFTER 2 SECONDS - test_convertNumericBase.aa_case5
L 12/29/2016 - 16:59:06: {1.000 15196 -1944726 4} I AM ENTERING ON convert_numeric_base(3) | number: 10 (9->10)
L 12/29/2016 - 16:59:06: {1.000 14692 -1944719 7} Array Cells: (0) 1, (1) 0,
L 12/29/2016 - 16:59:06: {1.000 14692 -1944716 3} Array Cells: (0) 9,
L 12/29/2016 - 16:59:06: {1.000 15196 -1944712 4} ( convert_numeric_base ) Returning integer: 9
L 12/29/2016 - 16:59:06: {1.000 14904 -1944708 4} ( displaysLastTestOk ) numberOfFailures: 0, lastFailure: 0, lastTestId: 5
L 12/29/2016 - 16:59:06: {1.000 14920 -1944702 6} OK!
L 12/29/2016 - 16:59:06: {1.000 14920 -1944698 4}
L 12/29/2016 - 16:59:06: {1.000 14920 -1944694 4}
L 12/29/2016 - 16:59:06: {1.000 14928 -1944689 5} EXECUTING TEST 6 AFTER 2 SECONDS - test_convertNumericBase.aa_case6
L 12/29/2016 - 16:59:06: {1.000 15196 -1944684 5} I AM ENTERING ON convert_numeric_base(3) | number: 10 (10->10)
L 12/29/2016 - 16:59:06: {1.000 14692 -1944681 3} Array Cells: (0) 1, (1) 0,
L 12/29/2016 - 16:59:06: {1.000 14692 -1944677 4} Array Cells: (0) 1, (1) 0,
L 12/29/2016 - 16:59:06: {1.000 15196 -1944671 6} ( convert_numeric_base ) Returning integer: 10
L 12/29/2016 - 16:59:06: {1.000 14904 -1944667 4} ( displaysLastTestOk ) numberOfFailures: 0, lastFailure: 0, lastTestId: 6
L 12/29/2016 - 16:59:06: {1.000 14920 -1944663 4} OK!
L 12/29/2016 - 16:59:06: {1.000 14920 -1944659 4}
L 12/29/2016 - 16:59:06: {1.000 14920 -1944653 6}
L 12/29/2016 - 16:59:06: {1.000 14928 -1944649 4} EXECUTING TEST 7 AFTER 2 SECONDS - test_convertNumericBase.aa_case7
L 12/29/2016 - 16:59:06: {1.000 15196 -1944645 4} I AM ENTERING ON convert_numeric_base(3) | number: 11 (7->9)
L 12/29/2016 - 16:59:06: {1.000 14692 -1944641 4} Array Cells: (0) 1, (1) 1,
L 12/29/2016 - 16:59:06: {1.000 14692 -1944636 5} Array Cells: (0) 8,
L 12/29/2016 - 16:59:06: {1.000 15196 -1944632 4} ( convert_numeric_base ) Returning integer: 8
L 12/29/2016 - 16:59:06: {1.000 14904 -1944628 4} ( displaysLastTestOk ) numberOfFailures: 0, lastFailure: 0, lastTestId: 7
L 12/29/2016 - 16:59:06: {1.000 14920 -1944622 6} OK!
L 12/29/2016 - 16:59:06: {1.000 14920 -1944618 4}
L 12/29/2016 - 16:59:06: {1.000 14920 -1944614 4}
L 12/29/2016 - 16:59:06: {1.000 14928 -1944610 4} EXECUTING TEST 8 AFTER 2 SECONDS - test_convertNumericBase.aa_case8
L 12/29/2016 - 16:59:06: {1.000 15196 -1944608 2} I AM ENTERING ON convert_numeric_base(3) | number: 2462 (7->9)
L 12/29/2016 - 16:59:06: {1.000 14668 -1944601 7} Array Cells: (0) 2, (1) 4, (2) 6, (3) 2,
L 12/29/2016 - 16:59:06: {1.000 14668 -1944597 4} Array Cells: (0) 1, (1) 2, (2) 3, (3) 8,
L 12/29/2016 - 16:59:06: {1.000 15196 -1944593 4} ( convert_numeric_base ) Returning integer: 1238
L 12/29/2016 - 16:59:06: {1.000 14904 -1944586 7} ( displaysLastTestOk ) numberOfFailures: 0, lastFailure: 0, lastTestId: 8
L 12/29/2016 - 16:59:06: {1.000 14920 -1944583 3} OK!
L 12/29/2016 - 16:59:06: {1.000 14920 -1944579 4}
L 12/29/2016 - 16:59:06: {1.000 14920 -1944575 4}
L 12/29/2016 - 16:59:06: {1.000 14928 -1944569 6} EXECUTING TEST 9 AFTER 2 SECONDS - test_convertNumericBase.aa_case9
L 12/29/2016 - 16:59:06: {1.000 15196 -1944565 4} I AM ENTERING ON convert_numeric_base(3) | number: 1238 (9->7)
L 12/29/2016 - 16:59:06: {1.000 14668 -1944561 4} Array Cells: (0) 1, (1) 2, (2) 3, (3) 8,
L 12/29/2016 - 16:59:06: {1.000 14668 -1944556 5} Array Cells: (0) 2, (1) 4, (2) 6, (3) 2,
L 12/29/2016 - 16:59:06: {1.000 15196 -1944551 5} ( convert_numeric_base ) Returning integer: 2462
L 12/29/2016 - 16:59:06: {1.000 16256 -1944548 3} ( displaysLastTestOk ) numberOfFailures: 0, lastFailure: 0, lastTestId: 9
L 12/29/2016 - 16:59:06: {1.000 16272 -1944544 4} OK!
L 12/29/2016 - 16:59:06: {1.000 16272 -1944538 6}
L 12/29/2016 - 16:59:06: {1.000 16272 -1944534 4}
L 12/29/2016 - 16:59:06: {1.000 16296 -1944530 4}
L 12/29/2016 - 16:59:06: {1.000 16280 -1944526 4} I AM ENTERING ON print_all_tests_executed(0)
L 12/29/2016 - 16:59:06: {1.000 16024 -1944520 6}
L 12/29/2016 - 16:59:06: {1.000 16024 -1944517 3}
L 12/29/2016 - 16:59:06: {1.000 16024 -1944512 5}
L 12/29/2016 - 16:59:06: {1.000 16024 -1944509 3} The following tests were executed:
L 12/29/2016 - 16:59:06: {1.000 16024 -1944503 6}
L 12/29/2016 - 16:59:06: {1.000 16008 -1944498 5} 1. test_convertNumericBase.aa_case1
L 12/29/2016 - 16:59:06: {1.000 16008 -1944494 4} 2. test_convertNumericBase.aa_case2
L 12/29/2016 - 16:59:06: {1.000 16008 -1944489 5} 3. test_convertNumericBase.aa_case3
L 12/29/2016 - 16:59:06: {1.000 16008 -1944485 4} 4. test_convertNumericBase.aa_case4
L 12/29/2016 - 16:59:06: {1.000 16008 -1944484 1} 5. test_convertNumericBase.aa_case5
L 12/29/2016 - 16:59:06: {1.000 16008 -1944476 8} 6. test_convertNumericBase.aa_case6
L 12/29/2016 - 16:59:06: {1.000 16008 -1944470 6} 7. test_convertNumericBase.aa_case7
L 12/29/2016 - 16:59:06: {1.000 16008 -1944466 4} 8. test_convertNumericBase.aa_case8
L 12/29/2016 - 16:59:06: {1.000 16008 -1944462 4} 9. test_convertNumericBase.aa_case9
L 12/29/2016 - 16:59:06: {1.000 14996 -1944458 4}
L 12/29/2016 - 16:59:06: {1.000 14988 -1944453 5} 9 tests succeed.
L 12/29/2016 - 16:59:06: {1.000 14992 -1944449 4} 0 tests failed.
L 12/29/2016 - 16:59:06: {1.000 16284 -1944445 4}
L 12/29/2016 - 16:59:06: {1.000 16272 -1944439 6} Finished the General Numeric Base Conversion's Unit Tests execution after '2' seconds.
L 12/29/2016 - 16:59:06: {1.000 16284 -1944435 4}
L 12/29/2016 - 16:59:06: {1.000 16284 -1944431 4}Code: Select all
/** AMX Mod X Script
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or ( at
* your option ) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* ***********************************************************
*/
#include <amxmodx>
// ################################# Unit Tests Header Start ##################################
#define MAX_SHORT_STRING 64
#define MAX_LONG_STRING 256
#define MAX_BIG_BOSS_STRING 512
#define LOGGER(%1) debugMesssageLogger( %1 );
/**
* Call the internal function to perform its task and stop the current test execution to avoid
* double failure at the test control system.
*
* @see the stock 'setTestFailure(3)'.
*/
#define SET_TEST_FAILURE(%1) \
{ \
if( setTestFailure( %1 ) ) \
{ \
LOGGER( 1, " ( SET_TEST_FAILURE ) Just returning/bloking." ) \
return; \
} \
}
/**
* General handler to assist object property applying and keep the code clear. This only need
* to be used with destructors/cleaners which does not support uninitialized handlers, requiring
* an if pre-checking.
*
* @param objectHandler the object handler to be called.
* @param objectIndentifation the object identification number to be destroyed.
*/
#define TRY_TO_APPLY(%1,%2) \
{ \
LOGGER( 128, "I AM ENTERING ON TRY_TO_APPLY(2) | objectIndentifation: %d", %2 ) \
if( %2 ) \
{ \
%1( %2 ); \
} \
}
new g_test_testsNumber;
new g_debug_level = 255;
new g_test_lastTimeStamp;
new g_test_startDayInteger;
/**
* Used to know when the Unit Tests are running.
*/
new bool:g_test_isTheUnitTestsRunning;
/**
* General data.
*/
new const PLUGIN_NAME[] = "General Numeric Base Conversion";
new const DEBUGGER_OUTPUT_LOG_FILE_NAME[] = "text.log";
/**
* Test unit variables related to the DEBUG_LEVEL_UNIT_TESTs'.
*/
new g_test_failureNumber;
new Trie: g_test_failureIdsTrie;
new Array:g_test_failureIdsArray;
new Array:g_test_idsAndNamesArray;
new Array:g_test_failureReasonsArray;
// ################################# Unit Tests Header End ####################################
public plugin_init()
{
register_plugin( PLUGIN_NAME, "1.0", "Addons zz" );
server_print( "^n^n^n^n^n^n^n^n^n^n^n^n" )
configureTheUnitTests()
test_convertNumericBase_load()
printTheUnitTestsResults()
}
/**
* To test the stock convert_numeric_base(3).
*/
stock test_convertNumericBase_load()
{
test_convertNumericBase( .origin_number = 10 , .origin_base = 7 , .destiny_base = 10, .expected = 7 ); // Case 1
test_convertNumericBase( .origin_number = 10 , .origin_base = 6 , .destiny_base = 10, .expected = 6 ); // Case 2
test_convertNumericBase( .origin_number = 10 , .origin_base = 5 , .destiny_base = 10, .expected = 5 ); // Case 3
test_convertNumericBase( .origin_number = 10 , .origin_base = 8 , .destiny_base = 10, .expected = 8 ); // Case 4
test_convertNumericBase( .origin_number = 10 , .origin_base = 9 , .destiny_base = 10, .expected = 9 ); // Case 5
test_convertNumericBase( .origin_number = 10 , .origin_base = 10, .destiny_base = 10, .expected = 10 ); // Case 6
test_convertNumericBase( .origin_number = 11 , .origin_base = 7 , .destiny_base = 9 , .expected = 8 ); // Case 7
test_convertNumericBase( .origin_number = 2462, .origin_base = 7 , .destiny_base = 9 , .expected = 1238 ); // Case 8
test_convertNumericBase( .origin_number = 1238, .origin_base = 9 , .destiny_base = 7 , .expected = 2462 ); // Case 9
}
/**
* Create one case test for the stock convert_numeric_base(0) based on its parameters passed
* by the test_convertNumericBase_load(0) loader function.
*/
stock test_convertNumericBase( origin_number, origin_base, destiny_base, expected )
{
new errorMessage[ MAX_LONG_STRING ];
new test_id = test_registerSeriesNaming( "test_convertNumericBase", 'a' );
new result = convert_numeric_base( origin_number, origin_base, destiny_base );
formatex( errorMessage, charsmax( errorMessage ),
"Converting the number %d on base %d to base %d must to be %d, instead of %d.",
origin_number, origin_base, destiny_base, expected, result );
SET_TEST_FAILURE( test_id, result != expected, errorMessage )
}
/**
* Given a number on a certain base until 10, calculates and return the equivalent number on another
* base until 10.
*
* @param origin_number the number to be converted.
* @param origin_base the base where `origin_number` is on.
* @param destiny_base the base where `origin_number` is to be converted to.
*/
stock convert_numeric_base( origin_number, origin_base, destiny_base )
{
LOGGER( 128, "I AM ENTERING ON convert_numeric_base(3) | number: %d (%d->%d)", \
origin_number, origin_base, destiny_base )
new integer;
new Array:digits;
digits = toDigitsRepresentation( origin_number, 10 );
printDynamicArrayCells( digits );
integer = fromDigitsRepresentation( digits, origin_base );
ArrayDestroy( digits );
digits = toDigitsRepresentation( integer, destiny_base );
printDynamicArrayCells( digits );
integer = fromDigitsRepresentation( digits, 10 );
ArrayDestroy( digits );
LOGGER( 1, " ( convert_numeric_base ) Returning integer: %d", integer )
return integer;
}
/**
* Read an digits Dynamic Array at its given base and return an integer representation.
*
* @param digits a Dynamic Array within the digits of inputed number on the specified base.
* @param origin_base the base where `digits` are represented.
*
* return an integer representation inputed number on the specified base.
*/
stock fromDigitsRepresentation( Array:digits, origin_base )
{
new integer;
new arraySize = ArraySize( digits );
for( new index = 0; index < arraySize; index ++ )
{
integer = integer * origin_base + ArrayGetCell( digits, index );
}
return integer;
}
/**
* Create an Dynamic Array within of the decimal number at its given base.
*
* @param origin_number a decimal number to be converted.
* @param origin_base the base where `origin_number` is to be converted to.
*
* return a Dynamic Array within the digits of inputed number on the specified base.
*/
stock Array:toDigitsRepresentation( origin_number, origin_base )
{
new Array:digits = ArrayCreate();
ArrayPushCell( digits, origin_number % origin_base );
origin_number = origin_number / origin_base;
while( origin_number > 0 )
{
ArrayInsertCellBefore( digits, 0, origin_number % origin_base );
origin_number = origin_number / origin_base;
}
return digits;
}
// ################################# Unit Tests Body Start ####################################
#define MAX_CELL_LENGHT 20
#define MAX_MESSAGE_LENGHT 80
stock printDynamicArrayCells( Array:array )
{
// server_print( "" );
new indexString [ 8 ];
new elementString [ 8 ];
new cellString [ MAX_CELL_LENGHT ];
new cellStringsBuffer[ MAX_MESSAGE_LENGHT ];
new arraySize = ArraySize( array );
for( new index = 0; index < arraySize; index++ )
{
// Create a cellString within a trailing comma
formatex( indexString , charsmax( indexString ) , "(%d) " , index );
formatex( elementString, charsmax( elementString ), "%d, " , ArrayGetCell( array, index ) );
formatex( cellString , charsmax( cellString ) , "%7s %-9s" , indexString, elementString );
// Add a new cellString to the output buffer and flushes it when it full
announceCellString( cellString, cellStringsBuffer );
}
// Flush the last cells
flushCellStrings( cellStringsBuffer );
// server_print( "" );
}
/**
* Announce cells to the server console.
*
* @param cellStringAnnounce a cell as string.
* @param cellStringsBuffer the output string to be printed.
*
* @note It does not immediately print the cell, the output occurs when the buffer is full.
*/
stock announceCellString( cellStringAnnounce[], cellStringsBuffer[] )
{
static copiedChars;
// Reset the characters counter for the output flush
if( !cellStringsBuffer[ 0 ] )
{
copiedChars = 0;
}
// Add the cellString to the buffer
copiedChars += copy( cellStringsBuffer[ copiedChars ], MAX_MESSAGE_LENGHT - 1 - copiedChars, cellStringAnnounce );
// Calculate whether to flush now or not
if( copiedChars > MAX_MESSAGE_LENGHT - MAX_CELL_LENGHT )
{
flushCellStrings( cellStringsBuffer );
}
}
/**
* Print the current buffer, if there are any cellStrings on it.
*
* @param cellStringsBuffer the formatted cellStrings list to be printed.
*/
stock flushCellStrings( cellStringsBuffer[] )
{
if( cellStringsBuffer[ 0 ] )
{
// Print the message
LOGGER( 1, "%-13s%s", "Array Cells: ", cellStringsBuffer[ 0 ] )
// Clear the buffer
cellStringsBuffer[ 0 ] = '^0';
}
}
/**
* Write debug messages accordantly with the 'g_debug_level' variable.
*
* @param mode the debug mode level, see the variable 'g_debug_level' for the levels.
* @param text the debug message, if omitted its default value is ""
* @param any the variable number of formatting parameters
*
* @see the stock writeToTheDebugFile( log_file[], formated_message[] ) for the output log
* 'DEBUGGER_OUTPUT_LOG_FILE_NAME'.
*/
stock debugMesssageLogger( const mode, const message[] = "", any:... )
{
if( mode & g_debug_level )
{
static formated_message[ MAX_BIG_BOSS_STRING ];
vformat( formated_message, charsmax( formated_message ), message, 3 );
writeToTheDebugFile( DEBUGGER_OUTPUT_LOG_FILE_NAME, formated_message );
}
}
/**
* Write debug messages to server's console and log file.
*
* @param message the debug message, if omitted its default value is ""
* @param any the variable number of formatting parameters
*
* @see the stock writeToTheDebugFile( log_file[], formated_message[] ) for the output log
* 'DEBUGGER_OUTPUT_LOG_FILE_NAME'.
*/
stock print_logger( const message[] = "", any:... )
{
static formated_message[ MAX_BIG_BOSS_STRING ];
vformat( formated_message, charsmax( formated_message ), message, 2 );
writeToTheDebugFile( DEBUGGER_OUTPUT_LOG_FILE_NAME, formated_message );
}
/**
* Write messages to the debug log file on 'addons/amxmodx/logs'.
*
* @param log_file the log file name.
* @param formated_message the formatted message to write down to the debug log file.
*/
stock writeToTheDebugFile( const log_file[], const formated_message[] )
{
new currentTime;
static lastRun;
currentTime = tickcount();
log_to_file( log_file, "{%.3f %d %5d %4d} %s", get_gametime(), heapspace(), currentTime, currentTime - lastRun, formated_message );
lastRun = currentTime;
// Removes the compiler warning `warning 203: symbol is never used` when only the debug
// level `DEBUG_LEVEL_NORMAL` is enabled.
if( g_test_isTheUnitTestsRunning ) { }
}
stock displaysLastTestOk()
{
if( g_test_testsNumber > 0 )
{
new lastTestId = ( g_test_testsNumber );
new numberOfFailures = ArraySize( g_test_failureIdsArray );
new lastFailure = ( numberOfFailures? ArrayGetCell( g_test_failureIdsArray, numberOfFailures - 1 ) : 0 );
LOGGER( 1, "( displaysLastTestOk ) numberOfFailures: %d, lastFailure: %d, lastTestId: %d", \
numberOfFailures, lastFailure, lastTestId )
if( !numberOfFailures
|| lastFailure != lastTestId )
{
print_logger( "OK!" );
print_logger( "" );
print_logger( "" );
}
else if( lastFailure == lastTestId )
{
print_logger( "FAILED!" );
print_logger( "" );
print_logger( "" );
print_logger( "" );
// Blocks the delayed Unit Tests to run, because the chain is broke.
return false;
}
}
return true;
}
stock print_all_tests_executed()
{
LOGGER( 128, "I AM ENTERING ON print_all_tests_executed(0)" )
new test_name[ MAX_SHORT_STRING ];
new testsNumber = ArraySize( g_test_idsAndNamesArray );
print_logger( "" );
print_logger( "" );
print_logger( "" );
print_logger( " The following tests were executed: " );
print_logger( "" );
for( new test_index = 0; test_index < testsNumber; test_index++ )
{
ArrayGetString( g_test_idsAndNamesArray, test_index, test_name, charsmax( test_name ) );
print_logger( " %3d. %s", test_index + 1, test_name );
}
}
stock print_tests_failure()
{
LOGGER( 0, "I AM ENTERING ON print_tests_failure(0)" )
new test_id;
new test_name[ MAX_SHORT_STRING ];
new failure_reason[ MAX_LONG_STRING ];
new failureTestsNumber = ArraySize( g_test_failureIdsArray );
if( failureTestsNumber )
{
print_logger( "" );
print_logger( "" );
print_logger( " The following %s's Unit Tests failed: ", PLUGIN_NAME );
print_logger( "" );
for( new failure_index = 0; failure_index < failureTestsNumber; failure_index++ )
{
test_id = ArrayGetCell( g_test_failureIdsArray, failure_index );
ArrayGetString( g_test_idsAndNamesArray, test_id - 1, test_name, charsmax( test_name ) );
ArrayGetString( g_test_failureReasonsArray, failure_index, failure_reason, charsmax( failure_reason ) );
print_logger( " %3d. %s: %s", test_id, test_name, failure_reason );
}
}
print_logger( "" );
print_logger( " %d tests succeed.", g_test_testsNumber - g_test_failureNumber );
print_logger( " %d tests failed.", g_test_failureNumber );
}
/**
* Informs the Test System that the test failed and why.
*
* @param test_id the test_id at the Test System
* @param isFailure a boolean value setting whether the failure status is true.
* @param failure_reason the reason why the test failed
*/
stock setTestFailure( test_id, bool:isFailure, failure_reason[] )
{
LOGGER( 0, "I AM ENTERING ON setTestFailure(...) | test_id: %d, isFailure: %d, \
failure_reason: %s", test_id, isFailure, failure_reason )
new trieKey[ 10 ];
num_to_str( test_id, trieKey, charsmax( trieKey ) );
if( isFailure
&& !TrieKeyExists( g_test_failureIdsTrie, trieKey ) )
{
g_test_failureNumber++;
ArrayPushCell( g_test_failureIdsArray, test_id );
TrieSetCell( g_test_failureIdsTrie, trieKey, 0 );
ArrayPushString( g_test_failureReasonsArray, failure_reason );
print_logger( " TEST FAILURE! %s", failure_reason );
return true;
}
return false;
}
/**
* This is the first thing called when a test begin running. It function is to let the Test System
* know that the test exists and then know how to handle it using the test_id.
*
* @param test_name the test name to register
*
* @return test_id an integer that refers it at the Test System.
*/
stock register_test( test_name[] )
{
LOGGER( 0, "I AM ENTERING ON register_test(2) | test_name: %s", test_name )
ArrayPushString( g_test_idsAndNamesArray, test_name );
displaysLastTestOk();
g_test_testsNumber++;
print_logger( " EXECUTING TEST %d AFTER %d SECONDS - %s ", g_test_testsNumber, computeTheTestElapsedTime(),test_name );
return g_test_testsNumber;
}
/**
* Register a test series naming, used to easily allow to distinguish between tests names.
* Example, this:
* 1. test_loadVoteChoices.aa_case1
* 2. test_loadVoteChoices.aa_case2
* 3. test_loadVoteChoices.bb.bb_case1
* 4. test_loadVoteChoices.bb.bb_case2
*
* Instead of this:
* 1. test_loadVoteChoices.a_case1
* 2. test_loadVoteChoices.a_case2
* 3. test_loadVoteChoices.b_case1
* 4. test_loadVoteChoices.b_case2
*
* @param seriesName the current test name.
* @param newSeries a char as the new test series start. The default is to use the last serie.
*/
stock test_registerSeriesNaming( seriesName[], newSeries = 0 )
{
new currentIndex;
new testName[ MAX_SHORT_STRING ];
static indentation;
static currentSerie;
static currentCaseNumber;
static intentationLevel[ MAX_SHORT_STRING ];
currentCaseNumber++;
if( newSeries
&& newSeries != currentSerie )
{
currentSerie = newSeries;
indentation = ( ( currentSerie - 'a' + 1 ) * 3 ) % 15;
currentCaseNumber = 1;
for( currentIndex = 0; currentIndex < indentation; ++currentIndex )
{
if( currentIndex % 3 == 0 )
{
intentationLevel[ currentIndex ] = '.';
}
else
{
intentationLevel[ currentIndex ] = currentSerie;
}
}
intentationLevel[ currentIndex ] = '^0';
}
formatex( testName, charsmax( testName ), "%s%s_case%d", seriesName, intentationLevel, currentCaseNumber );
return register_test( testName );
}
stock configureTheUnitTests()
{
LOGGER( 128, "I AM ENTERING ON configureTheUnitTests(0)" )
print_logger( "" );
print_logger( "" );
print_logger( "" );
print_logger( "" );
print_logger( "" );
saveCurrentTestsTimeStamp()
g_test_failureIdsTrie = TrieCreate();
g_test_failureIdsArray = ArrayCreate( 1 );
g_test_failureReasonsArray = ArrayCreate( MAX_LONG_STRING );
g_test_idsAndNamesArray = ArrayCreate( MAX_SHORT_STRING );
}
stock printTheUnitTestsResults()
{
displaysLastTestOk();
print_logger( "" );
print_all_tests_executed();
print_tests_failure();
print_tests_results_count();
}
stock print_tests_results_count()
{
print_logger( "" );
print_logger( " Finished the %s's Unit Tests execution after '%d' seconds.", PLUGIN_NAME, computeTheTestElapsedTime() );
print_logger( "" );
print_logger( "" );
// Clear the time-stamp.
g_test_lastTimeStamp = 0;
}
/**
* Compute how many days are elapsed since 1st January of 2000.
*
* @param currentDayInteger the current day from this year (1-366).
* @param currentYearInteger the current year (2016).
*/
#define GET_CURRENT_BASED_DAY(%1,%2) ( ( %2 - 2000 ) * 366 + %1 )
/**
* Save a time-stamp when the Unit Tests started to run.
*/
stock saveCurrentTestsTimeStamp()
{
if( !g_test_lastTimeStamp )
{
new hour;
new minute;
new second;
time( hour, minute, second );
new currentDayInteger;
new currentYearInteger;
new rawTimeData[ 10 ];
get_time("%j", rawTimeData, charsmax( rawTimeData ) );
currentDayInteger = str_to_num( rawTimeData );
get_time("%Y", rawTimeData, charsmax( rawTimeData ) );
currentYearInteger = str_to_num( rawTimeData );
g_test_lastTimeStamp = hour * 3600 + minute * 60 + second;
g_test_startDayInteger = GET_CURRENT_BASED_DAY( currentDayInteger, currentYearInteger );
}
}
/**
* Calculates how much time took to run the Unit Tests. For this to work, the stock
* 'saveCurrentTestsTimeStamp(0)' must to be called on the beginning of the tests.
*
* @return seconds how much seconds are elapsed, or -1 on when the time-stamp is null.
*/
stock computeTheTestElapsedTime()
{
if( g_test_lastTimeStamp )
{
new hour;
new minute;
new second;
new delayResulted;
time( hour, minute, second );
new currentDayInteger;
new currentYearInteger;
new rawTimeData[ 10 ];
get_time("%j", rawTimeData, charsmax( rawTimeData ) );
currentDayInteger = str_to_num( rawTimeData );
get_time("%Y", rawTimeData, charsmax( rawTimeData ) );
currentYearInteger = str_to_num( rawTimeData );
delayResulted = hour * 3600 + minute * 60 + second - g_test_lastTimeStamp + 1;
currentDayInteger = GET_CURRENT_BASED_DAY( currentDayInteger, currentYearInteger );
if( g_test_startDayInteger != currentDayInteger )
{
// end - start = delay
// 1:59 - 1:55 = 4
// 2:05 - 1:59 = -54 plus + 1 * 60 = 6 seconds (correct)
// 3:05 - 1:59 = -54 plus + 2 * 60 = 66 seconds (correct)
return delayResulted + ( currentDayInteger - g_test_startDayInteger ) * 86400;
}
return delayResulted;
}
return -1;
}
public plugin_end()
{
TRY_TO_APPLY( ArrayDestroy, g_test_idsAndNamesArray )
TRY_TO_APPLY( ArrayDestroy, g_test_failureIdsArray )
TRY_TO_APPLY( ArrayDestroy, g_test_failureReasonsArray )
TRY_TO_APPLY( TrieDestroy, g_test_failureIdsTrie )
}
// ################################# Unit Tests Body End ###################################### 