2024-02-16 22:26:32 +00:00
< ? php
/* Copyright ( C ) 2018 Laurent Destailleur < eldy @ users . sourceforge . net >
* Copyright ( C ) 2023 Alexandre Janniaux < alexandre . janniaux @ gmail . com >
2025-01-30 16:53:56 +00:00
* Copyright ( C ) 2024 - 2025 MDW < mdeweerd @ users . noreply . github . com >
2025-11-09 00:19:31 +00:00
* Copyright ( C ) 2024 - 2025 Frédéric France < frederic . france @ free . fr >
2024-02-16 22:26:32 +00:00
*
* 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 3 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 < https :// www . gnu . org / licenses />.
* or see https :// www . gnu . org /
*/
/**
2024-02-17 03:12:42 +00:00
* \file test / phpunit / CommonClassTest . php
2024-02-16 22:26:32 +00:00
* \ingroup test
* \brief PHPUnit test
2024-03-19 23:35:01 +00:00
* \remarks Class that extends all PHPunit tests . To share similar code between each test .
2024-02-16 22:26:32 +00:00
*/
2024-03-11 11:49:15 +00:00
// Workaround for false security issue with main.inc.php on Windows in tests:
if ( strtoupper ( substr ( PHP_OS , 0 , 3 )) === 'WIN' ) {
$_SERVER [ 'PHP_SELF' ] = " phpunit " ;
}
2024-03-10 14:17:58 +00:00
2024-02-16 22:26:32 +00:00
global $conf , $user , $langs , $db ;
//define('TEST_DB_FORCE_TYPE','mysql'); // This is to force using mysql driver
//require_once 'PHPUnit/Autoload.php';
require_once dirname ( __FILE__ ) . '/../../htdocs/master.inc.php' ;
2024-03-10 14:17:58 +00:00
2025-02-06 11:04:41 +00:00
// Delete the log file to avoid problem of writing permission on it
@ unlink ( DOL_DATA_ROOT . '/dolibarr.log' );
2024-03-10 14:17:58 +00:00
2024-02-16 22:26:32 +00:00
if ( empty ( $user -> id )) {
print " Load permissions for admin user nb 1 \n " ;
$user -> fetch ( 1 );
2024-11-13 23:16:43 +00:00
$user -> loadRights ();
2024-02-16 22:26:32 +00:00
}
2024-02-19 14:28:21 +00:00
$conf -> global -> MAIN_DISABLE_ALL_MAILS = 1 ;
2024-02-16 22:26:32 +00:00
2024-02-23 16:43:18 +00:00
use PHPUnit\Framework\TestCase ;
2024-02-16 22:26:32 +00:00
/**
* Class for PHPUnit tests
*
* @ backupGlobals disabled
* @ backupStaticAttributes enabled
2026-03-14 18:55:08 +00:00
* @ remarks backupGlobals must be disabled to have db , conf , user and lang not erased .
* @ phan - file - suppress PhanUndeclaredClass
* @ phan - file - suppress PhanUndeclaredExtendedClass
* @ phan - file - suppress PhanUndeclaredMethod
2024-02-16 22:26:32 +00:00
*/
2026-03-14 18:55:08 +00:00
/** @phpstan-ignore class.notFound */
2024-02-23 16:43:18 +00:00
abstract class CommonClassTest extends TestCase
2024-02-16 22:26:32 +00:00
{
2026-03-14 18:55:08 +00:00
/** @var \Conf */
2024-02-16 22:26:32 +00:00
protected $savconf ;
2026-03-14 18:55:08 +00:00
/** @var \User */
2024-02-16 22:26:32 +00:00
protected $savuser ;
2026-03-14 18:55:08 +00:00
/** @var \Translate */
2024-02-16 22:26:32 +00:00
protected $savlangs ;
2026-03-14 18:55:08 +00:00
/** @var \DoliDB */
2024-02-16 22:26:32 +00:00
protected $savdb ;
2024-02-23 16:43:18 +00:00
/**
* Number of Dolibarr log lines to show in case of error
*
* @ var integer
*/
2026-06-20 06:07:21 +00:00
public $nbLinesToShow = 50 ;
2024-02-23 16:43:18 +00:00
2024-03-02 11:42:20 +00:00
/**
* Log file from which to extract lines in case of failing test
2026-03-14 18:55:08 +00:00
*
* @ var string
2024-03-02 11:42:20 +00:00
*/
public $logfile = DOL_DATA_ROOT . '/dolibarr.log' ;
/**
* Log file size before a test started ( = in setUp () call )
2026-03-14 18:55:08 +00:00
*
* @ var int
2024-03-02 11:42:20 +00:00
*/
public $logSizeAtSetup = 0 ;
2024-02-16 22:26:32 +00:00
/**
* Constructor
* We save global variables into local variables
*
2024-02-23 16:43:18 +00:00
* @ param string $name Name
2026-03-14 18:55:08 +00:00
* @ param array < mixed > $data Test data
2024-02-23 16:43:18 +00:00
* @ param string $dataName Test data name .
2024-02-16 22:26:32 +00:00
*/
2024-02-23 16:43:18 +00:00
public function __construct ( $name = null , array $data = array (), $dataName = '' )
2024-02-16 22:26:32 +00:00
{
2024-02-23 16:43:18 +00:00
parent :: __construct ( $name , $data , $dataName );
2024-02-16 22:26:32 +00:00
//$this->sharedFixture
global $conf , $user , $langs , $db ;
2024-02-19 14:28:21 +00:00
$this -> savconf = $conf ;
$this -> savuser = $user ;
$this -> savlangs = $langs ;
$this -> savdb = $db ;
2024-02-16 22:26:32 +00:00
2024-02-24 13:12:32 +00:00
if (( int ) getenv ( 'PHPUNIT_DEBUG' ) > 0 ) {
2024-02-24 17:05:42 +00:00
print get_called_class () . " db->type= " . $db -> type . " user->id= " . $user -> id . PHP_EOL ;
2024-02-24 13:12:32 +00:00
}
2024-02-16 22:26:32 +00:00
//print " - db ".$db->db;
}
/**
* setUpBeforeClass
*
* @ return void
*/
public static function setUpBeforeClass () : void
{
global $conf , $user , $langs , $db ;
$db -> begin (); // This is to have all actions inside a transaction even if test launched without suite.
2024-02-24 13:12:32 +00:00
if (( int ) getenv ( 'PHPUNIT_DEBUG' ) > 0 ) {
print get_called_class () . " :: " . __FUNCTION__ . PHP_EOL ;
2024-02-23 16:43:18 +00:00
}
2024-02-16 22:26:32 +00:00
}
/**
* This method is called when a test fails
*
* @ param Throwable $t Throwable object
* @ return void
*/
protected function onNotSuccessfulTest ( Throwable $t ) : void
{
2026-06-21 14:03:55 +00:00
global $db ;
2024-02-16 22:26:32 +00:00
2024-03-02 11:42:20 +00:00
// Get the lines that were added since the start of the test
2025-02-19 14:56:13 +00:00
if ( file_exists ( $this -> logfile )) {
$filecontent = ( string ) @ file_get_contents ( $this -> logfile );
} else {
$filecontent = '' ;
}
2024-03-02 11:42:20 +00:00
$currentSize = strlen ( $filecontent );
if ( $currentSize >= $this -> logSizeAtSetup ) {
$filecontent = substr ( $filecontent , $this -> logSizeAtSetup );
}
$lines = preg_split ( " / \r ? \n / " , $filecontent , - 1 , PREG_SPLIT_NO_EMPTY );
// Determine the number of lines to show
2024-02-16 22:26:32 +00:00
2024-02-23 16:43:18 +00:00
$nbLinesToShow = $this -> nbLinesToShow ;
2026-03-14 18:55:08 +00:00
// @phan-suppress-next-line PhanUndeclaredClass
/** @phpstan-ignore comparison.alwaysFalse */
if ( get_class ( $t ) === 'PHPUnit\Framework\Error\Notice' ) {
2024-02-22 01:54:37 +00:00
$nbLinesToShow = 3 ;
}
2024-02-16 22:26:32 +00:00
2024-03-02 11:42:20 +00:00
// Determine test information to show
2024-02-16 22:26:32 +00:00
2026-03-14 18:55:08 +00:00
// @phan-suppress-next-line PhanUndeclaredMethod
// @phpstan-ignore method.notFound
2024-02-24 13:12:32 +00:00
$failedTestMethod = $this -> getName ( false );
$className = get_called_class ();
// Get the test method's reflection
$reflectionMethod = new ReflectionMethod ( $className , $failedTestMethod );
// Get the test method's data set
2026-03-14 18:55:08 +00:00
// @phan-suppress-next-line PhanUndeclaredMethod
// @phpstan-ignore method.notFound
2024-02-24 13:12:32 +00:00
$argsText = $this -> getDataSetAsString ( true );
2024-03-01 19:39:52 +00:00
$totalLines = count ( $lines );
$first_line = max ( 0 , $totalLines - $nbLinesToShow );
// Get the last line of the log
$last_lines = array_slice ( $lines , $first_line , $nbLinesToShow );
2024-03-02 11:42:20 +00:00
// Show log information
2024-02-24 13:12:32 +00:00
print PHP_EOL ;
2024-03-01 19:39:52 +00:00
// Use GitHub Action compatible group output (:warning: arguments not encoded)
print " ##[group] $className :: $failedTestMethod failed - $argsText . " . PHP_EOL ;
2026-03-14 18:55:08 +00:00
// @phan-suppress-next-line PhanUndeclaredClassMethod
2024-03-02 15:38:53 +00:00
print " ## " . get_class ( $t ) . " : { $t -> getMessage () } " . PHP_EOL ;
2024-03-01 19:39:52 +00:00
2025-01-30 16:53:56 +00:00
// Show some information about where it happened
2026-03-14 18:55:08 +00:00
// @phan-suppress-next-line PhanUndeclaredClassMethod
2025-01-30 16:53:56 +00:00
foreach ( $t -> getTrace () as $idx => $trace ) {
if ( isset ( $trace [ 'file' ], $trace [ 'line' ]) // Only if we have a file name
&& ! preg_match ( '/(?:\bphar\b|Framework)/' , $trace [ 'file' ]) // Only if it's not in phpunit
) {
print " ## backtrace( $idx ): From { $trace [ 'file' ] } : { $trace [ 'line' ] } . " . PHP_EOL ;
}
}
2024-03-01 19:39:52 +00:00
if ( $nbLinesToShow ) {
2026-01-09 18:22:46 +00:00
print " \n " ;
2026-06-21 14:12:38 +00:00
print " ########## We output the last " . $nbLinesToShow . " lines of the file " . basename ( $this -> logfile ) . " for the failed test " . $failedTestMethod . " (file has " . $totalLines . " lines) " . PHP_EOL ;
2024-03-02 11:42:20 +00:00
$newLines = count ( $last_lines );
if ( $newLines > 0 ) {
// Show partial log file contents when requested.
print " ## Show last " . count ( $last_lines ) . " lines of dolibarr.log file ----- " . PHP_EOL ;
foreach ( $last_lines as $line ) {
print $line . PHP_EOL ;
}
2026-02-09 21:43:56 +00:00
print " ########## end of dolibarr.log for $className :: $failedTestMethod " . PHP_EOL ;
2024-03-02 11:42:20 +00:00
} else {
print " ## No new lines in 'dolibarr.log' since start of this test. " . PHP_EOL ;
2024-03-01 19:39:52 +00:00
}
2024-02-16 22:26:32 +00:00
}
2024-03-01 19:39:52 +00:00
print " ##[endgroup] " . PHP_EOL ;
2024-02-16 22:26:32 +00:00
2026-03-14 18:55:08 +00:00
// Print last line of file /var/log/apache2/travis_error_log (Unix only)
2026-06-21 14:03:55 +00:00
/* File travis_error_log seems not found on travis
2026-03-14 18:55:08 +00:00
if ( strtoupper ( substr ( PHP_OS , 0 , 3 )) !== 'WIN' ) {
$logFile = '/var/log/apache2/travis_error_log' ;
if ( file_exists ( $logFile ) && is_readable ( $logFile )) {
$lines = file ( $logFile , FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES );
$lastFiveLines = array_slice ( $lines , - 10 );
print " \n " ;
echo " Last 10 lines of $logFile : \n " ;
foreach ( $lastFiveLines as $line ) {
echo $line . " \n " ;
}
} else {
2026-05-07 07:36:02 +00:00
echo " File $logFile does not exist or is not readable. \n " ;
2026-01-09 18:22:46 +00:00
}
}
2026-06-21 14:03:55 +00:00
*/
// Try to output DB info
print " \n " ;
print " ########## We try to output some DB info " . PHP_EOL ;
$resql = $db -> query ( " SHOW ENGINE INNODB STATUS " );
if ( $resql ) {
$obj = $db -> fetch_object ( $resql );
print $obj -> Status . PHP_EOL ;
} else {
print $db -> lasterror () . PHP_EOL ;
}
print PHP_EOL ;
2026-01-09 18:22:46 +00:00
2026-03-14 18:55:08 +00:00
/** @phpstan-ignore method.notFound */
2024-02-16 22:26:32 +00:00
parent :: onNotSuccessfulTest ( $t );
}
/**
* Init phpunit tests
*
* @ return void
*/
protected function setUp () : void
{
global $conf , $user , $langs , $db ;
2024-02-19 14:28:21 +00:00
$conf = $this -> savconf ;
$user = $this -> savuser ;
$langs = $this -> savlangs ;
$db = $this -> savdb ;
2024-02-16 22:26:32 +00:00
2024-03-02 11:42:20 +00:00
// Record the filesize to determine which part of the log to show on error
2025-02-19 14:56:13 +00:00
if ( file_exists ( $this -> logfile )) {
$this -> logSizeAtSetup = ( int ) filesize ( $this -> logfile );
} else {
$this -> logSizeAtSetup = 0 ;
}
2024-03-02 11:42:20 +00:00
2024-02-24 13:12:32 +00:00
if (( int ) getenv ( 'PHPUNIT_DEBUG' ) > 0 ) {
2026-03-14 18:55:08 +00:00
// @phpstan-ignore method.notFound
2024-02-24 13:12:32 +00:00
print get_called_class () . '::' . $this -> getName ( false ) . " :: " . __FUNCTION__ . PHP_EOL ;
2024-02-23 16:43:18 +00:00
}
2024-02-16 22:26:32 +00:00
//print $db->getVersion()."\n";
}
/**
* End phpunit tests
*
* @ return void
*/
protected function tearDown () : void
{
2024-02-24 13:12:32 +00:00
if (( int ) getenv ( 'PHPUNIT_DEBUG' ) > 0 ) {
2026-03-14 18:55:08 +00:00
// @phpstan-ignore method.notFound
2024-02-24 13:12:32 +00:00
print get_called_class () . '::' . $this -> getName ( false ) . " :: " . __FUNCTION__ . PHP_EOL ;
2024-02-23 16:43:18 +00:00
}
2024-02-16 22:26:32 +00:00
}
/**
* tearDownAfterClass
*
* @ return void
*/
public static function tearDownAfterClass () : void
{
global $db ;
$db -> rollback ();
2024-02-24 13:12:32 +00:00
if (( int ) getenv ( 'PHPUNIT_DEBUG' ) > 0 ) {
print get_called_class () . " :: " . __FUNCTION__ . PHP_EOL ;
2024-02-23 16:43:18 +00:00
}
2024-02-16 22:26:32 +00:00
}
2024-02-23 16:43:18 +00:00
2024-03-31 14:12:55 +00:00
/**
* Call method , even if protected .
*
* @ param object $obj Object on which to call method
* @ param string $name Method to call
2026-03-14 18:55:08 +00:00
* @ param array < mixed > $args Arguments to provide in method call
2024-03-31 14:12:55 +00:00
* @ return mixed Return value
*/
public static function callMethod ( $obj , $name , array $args = [])
{
$class = new \ReflectionClass ( $obj );
$method = $class -> getMethod ( $name );
// If PHP is older then 8.1.0
if ( PHP_VERSION_ID < 80100 ) {
$method -> setAccessible ( true );
}
return $method -> invokeArgs ( $obj , $args );
}
/**
* Compare all public properties values of 2 objects
*
* @ param Object $oA Object operand 1
* @ param Object $oB Object operand 2
* @ param boolean $ignoretype False will not report diff if type of value differs
2026-03-14 18:55:08 +00:00
* @ param array < int | string > $fieldstoignorearray Array of fields to ignore in diff
* @ return array < mixed > Array with differences
2024-03-31 14:12:55 +00:00
*/
public function objCompare ( $oA , $oB , $ignoretype = true , $fieldstoignorearray = array ( 'id' ))
{
$retAr = array ();
if ( get_class ( $oA ) !== get_class ( $oB )) {
$retAr [] = " Supplied objects are not of same class. " ;
} else {
$oVarsA = get_object_vars ( $oA );
$oVarsB = get_object_vars ( $oB );
2026-01-29 10:25:33 +00:00
2024-03-31 14:12:55 +00:00
$aKeys = array_keys ( $oVarsA );
2026-01-29 10:25:33 +00:00
2024-03-31 14:12:55 +00:00
if ( method_exists ( $oA , 'deprecatedProperties' )) {
// Update exclusions
foreach ( self :: callMethod ( $oA , 'deprecatedProperties' ) as $deprecated => $new ) {
if ( in_array ( $deprecated , $fieldstoignorearray )) {
$fieldstoignorearray [] = $new ;
}
}
}
foreach ( $aKeys as $sKey ) {
if ( in_array ( $sKey , $fieldstoignorearray )) {
continue ;
}
2026-01-29 10:25:33 +00:00
2024-03-31 14:12:55 +00:00
if ( ! $ignoretype && ( $oVarsA [ $sKey ] !== $oVarsB [ $sKey ])) {
$retAr [] = get_class ( $oA ) . '::' . $sKey . ' : ' . ( is_object ( $oVarsA [ $sKey ]) ? get_class ( $oVarsA [ $sKey ]) : json_encode ( $oVarsA [ $sKey ])) . ' <> ' . ( is_object ( $oVarsB [ $sKey ]) ? get_class ( $oVarsB [ $sKey ]) : json_encode ( $oVarsB [ $sKey ]));
}
if ( $ignoretype && ( $oVarsA [ $sKey ] != $oVarsB [ $sKey ])) {
$retAr [] = get_class ( $oA ) . '::' . $sKey . ' : ' . ( is_object ( $oVarsA [ $sKey ]) ? get_class ( $oVarsA [ $sKey ]) : json_encode ( $oVarsA [ $sKey ])) . ' <> ' . ( is_object ( $oVarsB [ $sKey ]) ? get_class ( $oVarsB [ $sKey ]) : json_encode ( $oVarsB [ $sKey ]));
}
}
}
2026-01-29 10:25:33 +00:00
2024-03-31 14:12:55 +00:00
return $retAr ;
}
2024-02-23 16:43:18 +00:00
/**
* Map deprecated module names to new module names
*/
const DEPRECATED_MODULE_MAPPING = array (
'actioncomm' => 'agenda' ,
'adherent' => 'member' ,
'adherent_type' => 'member_type' ,
'banque' => 'bank' ,
'categorie' => 'category' ,
'commande' => 'order' ,
'contrat' => 'contract' ,
'entrepot' => 'stock' ,
2024-03-12 10:21:42 +00:00
'expedition' => 'shipping' ,
2024-02-23 16:43:18 +00:00
'facture' => 'invoice' ,
2024-02-28 21:47:28 +00:00
'fichinter' => 'intervention' ,
2024-02-23 16:43:18 +00:00
'product_fournisseur_price' => 'productsupplierprice' ,
'product_price' => 'productprice' ,
'projet' => 'project' ,
'propale' => 'propal' ,
'socpeople' => 'contact' ,
);
2024-02-28 21:47:28 +00:00
const EFFECTIVE_DEPRECATED_MODULE_MAPPING = array (
'adherent' => 'member' ,
'adherent_type' => 'member_type' ,
'banque' => 'bank' ,
'contrat' => 'contract' ,
'entrepot' => 'stock' ,
'ficheinter' => 'fichinter' ,
'projet' => 'project' ,
);
2024-02-23 16:43:18 +00:00
/**
* Map module names to the 'class' name ( the class is : mod < CLASSNAME > )
* Value is null when the module is not internal to the default
* Dolibarr setup .
*/
const VALID_MODULE_MAPPING = array (
'accounting' => 'Accounting' ,
'agenda' => 'Agenda' ,
'ai' => 'Ai' ,
'anothermodule' => null , // Not used in code, used in translations.lang
'api' => 'Api' ,
'asset' => 'Asset' ,
'bank' => 'Banque' ,
'barcode' => 'Barcode' ,
'blockedlog' => 'BlockedLog' ,
'bom' => 'Bom' ,
'bookcal' => 'BookCal' ,
'bookmark' => 'Bookmark' ,
'cashdesk' => null ,
'category' => 'Categorie' ,
'clicktodial' => 'ClickToDial' ,
2024-02-24 17:05:42 +00:00
'collab' => 'Collab' , // TODO: fill in proper name
2024-02-23 16:43:18 +00:00
'comptabilite' => 'Comptabilite' ,
'contact' => null , // TODO: fill in proper class
'contract' => 'Contrat' ,
'cron' => 'Cron' ,
'datapolicy' => 'DataPolicy' ,
2024-02-24 17:05:42 +00:00
'dav' => 'Dav' ,
2024-02-23 16:43:18 +00:00
'debugbar' => 'DebugBar' ,
2024-03-12 10:21:42 +00:00
'shipping' => 'Expedition' ,
2026-06-21 13:20:14 +00:00
'deplacement' => null ,
2024-02-24 17:05:42 +00:00
" documentgeneration " => 'DocumentGeneration' , // TODO: fill in proper name
2024-02-23 16:43:18 +00:00
'don' => 'Don' ,
'dynamicprices' => 'DynamicPrices' ,
'ecm' => 'ECM' ,
'ecotax' => null , // TODO: External module ?
'emailcollector' => 'EmailCollector' ,
'eventorganization' => 'EventOrganization' ,
'expensereport' => 'ExpenseReport' ,
'export' => 'Export' ,
2024-02-24 17:05:42 +00:00
'externalrss' => 'ExternalRss' , // TODO: fill in proper name
2024-02-23 16:43:18 +00:00
'fckeditor' => 'Fckeditor' ,
'fournisseur' => 'Fournisseur' ,
'ftp' => 'FTP' ,
2024-02-24 17:05:42 +00:00
'geoipmaxmind' => 'GeoIPMaxmind' , // TODO: fill in proper name
2024-02-23 16:43:18 +00:00
'google' => null , // External ?
'gravatar' => 'Gravatar' ,
'holiday' => 'Holiday' ,
'hrm' => 'HRM' ,
'import' => 'Import' ,
'incoterm' => 'Incoterm' ,
'intervention' => 'Ficheinter' ,
'intracommreport' => 'Intracommreport' ,
'invoice' => 'Facture' ,
'knowledgemanagement' => 'KnowledgeManagement' ,
'label' => 'Label' ,
'ldap' => 'Ldap' ,
'loan' => 'Loan' ,
'mailing' => 'Mailing' ,
'mailman' => null , // Same module as mailmanspip -> MailmanSpip ??
'mailmanspip' => 'MailmanSpip' ,
'margin' => 'Margin' ,
'member' => 'Adherent' ,
'memcached' => null , // TODO: External module?
'modulebuilder' => 'ModuleBuilder' ,
'mrp' => 'Mrp' ,
'multicompany' => null , // Not provided by default, no module tests
'multicurrency' => 'MultiCurrency' ,
'mymodule' => null , // modMyModule - Name used in module builder (avoid false positives)
'notification' => 'Notification' ,
'numberwords' => null , // Not provided by default, no module tests
2024-02-24 17:05:42 +00:00
'oauth' => 'Oauth' ,
2024-02-23 16:43:18 +00:00
'openstreetmap' => null , // External module?
'opensurvey' => 'OpenSurvey' ,
'order' => 'Commande' ,
'partnership' => 'Partnership' ,
'paymentbybanktransfer' => 'PaymentByBankTransfer' ,
'paypal' => 'Paypal' ,
'paypalplus' => null ,
'prelevement' => 'Prelevement' ,
2024-02-24 17:05:42 +00:00
'printing' => 'Printing' , // TODO: set proper name
2024-02-23 16:43:18 +00:00
'product' => 'Product' ,
'productbatch' => 'ProductBatch' ,
'productprice' => null ,
'productsupplierprice' => null ,
'project' => 'Projet' ,
'propal' => 'Propale' ,
2026-04-15 15:47:50 +00:00
'quickmemo' => 'QuickMemo' ,
2024-02-23 16:43:18 +00:00
'receiptprinter' => 'ReceiptPrinter' ,
'reception' => 'Reception' ,
'recruitment' => 'Recruitment' ,
'resource' => 'Resource' ,
'salaries' => 'Salaries' ,
'service' => 'Service' ,
'socialnetworks' => 'SocialNetworks' ,
'societe' => 'Societe' ,
'stock' => 'Stock' ,
'stocktransfer' => 'StockTransfer' ,
'stripe' => 'Stripe' ,
2025-05-10 00:44:31 +00:00
'subtotals' => 'Subtotals' ,
2024-02-23 16:43:18 +00:00
'supplier_invoice' => null , // Special case, uses invoice
'supplier_order' => null , // Special case, uses invoice
'supplier_proposal' => 'SupplierProposal' ,
'syslog' => 'Syslog' ,
'takepos' => 'TakePos' ,
'tax' => 'Tax' ,
'ticket' => 'Ticket' ,
'user' => 'User' ,
'variants' => 'Variants' ,
'webhook' => 'Webhook' ,
'webportal' => 'WebPortal' ,
'webservices' => 'WebServices' ,
'website' => 'Website' ,
'workflow' => 'Workflow' ,
'workstation' => 'Workstation' ,
'zapier' => 'Zapier' ,
);
2024-03-01 11:50:51 +00:00
2026-03-12 12:27:43 +00:00
/**
* Map module names to the 'class' name ( the class is : mod < CLASSNAME > )
* Value is null when the module is not internal to the default
* Dolibarr setup .
*/
const OTHER_MODULE_MAPPING = array (
'captureserver' => 'CaptureServer'
);
2024-03-04 19:13:34 +00:00
/**
* Run php script ( file ) using the php binary used for running phpunit .
*
* The PHP executable may not be in the path , or refer to an uncontrolled
* version .
* This ensures that the php script is properly run on multiple platforms .
*
* @ param string $phpScriptCommand The command and arguments are run by the php binary .
2026-03-14 18:55:08 +00:00
* @ param array < string > $output The output returned by the command
2024-03-04 19:13:34 +00:00
* @ param int $exitCode The exit code returned for the execution .
* @ return false | string False on failure , else last line if the output from the command
*/
2026-03-14 18:55:08 +00:00
protected function runPhpScript ( string $phpScriptCommand , & $output , & $exitCode )
2024-03-04 19:13:34 +00:00
{
$phpExecutable = PHP_BINARY ;
// Build the command to execute the PHP script
$command = " $phpExecutable $phpScriptCommand " ;
// Execute the command
return exec ( $command , $output , $exitCode );
}
2024-03-01 11:50:51 +00:00
/**
* Assert that a directory does not exist without triggering deprecation
*
* @ param string $directory The directory to test
* @ param string $message The message to show if the directory exists
*
* @ return void
*/
protected function assertDirectoryNotExistsCompat ( $directory , $message = '' )
{
2026-03-14 18:55:08 +00:00
// @phan-suppress-next-line PhanUndeclaredClassReference, PhanUndeclaredClassMethod
$phpunitVersion = class_exists ( '\PHPUnit\Runner\Version' ) ? \PHPUnit\Runner\Version :: id () : '9.0.0' ;
2024-03-01 11:50:51 +00:00
// Check if PHPUnit version is less than 9.0.0
if ( version_compare ( $phpunitVersion , '9.0.0' , '<' )) {
2026-03-14 18:55:08 +00:00
// @phan-suppress-next-line PhanUndeclaredMethod
/** @phpstan-ignore method.notFound */
2024-03-01 11:50:51 +00:00
$this -> assertDirectoryNotExists ( $directory , $message );
} else {
2026-03-14 18:55:08 +00:00
// @phan-suppress-next-line PhanUndeclaredMethod
/** @phpstan-ignore method.notFound */
2024-03-01 11:50:51 +00:00
$this -> assertDirectoryDoesNotExist ( $directory , $message );
}
}
2024-03-01 19:39:52 +00:00
/**
* Assert that a file does not exist without triggering deprecation
*
* @ param string $file The file to test
* @ param string $message The message to show if the directory exists
*
* @ return void
*/
protected function assertFileNotExistsCompat ( $file , $message = '' )
{
2026-03-14 18:55:08 +00:00
// @phan-suppress-next-line PhanUndeclaredClassReference, PhanUndeclaredClassMethod
$phpunitVersion = class_exists ( '\PHPUnit\Runner\Version' ) ? \PHPUnit\Runner\Version :: id () : '9.0.0' ;
2024-03-01 19:39:52 +00:00
// Check if PHPUnit version is less than 9.0.0
if ( version_compare ( $phpunitVersion , '9.0.0' , '<' )) {
2026-03-14 18:55:08 +00:00
// @phan-suppress-next-line PhanUndeclaredMethod
2024-03-01 19:39:52 +00:00
$this -> assertFileNotExists ( $file , $message );
} else {
2026-03-14 18:55:08 +00:00
// @phan-suppress-next-line PhanUndeclaredMethod
2024-03-01 19:39:52 +00:00
$this -> assertFileDoesNotExist ( $file , $message );
}
}
2024-03-03 16:01:17 +00:00
/**
* Skip test if test is not running on " Unix "
*
* @ param string $message Message to indicate which test requires " Unix "
*
* @ return bool True if this is not * nix , and fake assert generated
*/
protected function fakeAssertIfNotUnix ( $message )
{
if ( strtoupper ( substr ( PHP_OS , 0 , 3 )) === 'WIN' ) {
2026-03-14 18:55:08 +00:00
// @phan-suppress-next-line PhanUndeclaredMethod
// @phpstan-ignore method.notFound
2024-03-03 16:01:17 +00:00
$this -> assertTrue ( true , " Dummy test to not mark the test as risky " );
// $this->markTestSkipped("PHPUNIT is running on windows. $message");
return true ;
}
return false ;
}
2024-02-16 22:26:32 +00:00
}