Merge branch 'develop' into feature/fast-theme-compilation2

This commit is contained in:
odain-cbd
2020-08-17 00:18:15 +02:00
committed by GitHub
217 changed files with 4447 additions and 3598 deletions

View File

@@ -713,7 +713,7 @@ class ItopDataTestCase extends ItopTestCase
$iId = $oLnk->Get('functionalci_id');
if (!empty($aWaitedCIList))
{
$this->assertTrue(array_key_exists($iId, $aWaitedCIList));
$this->assertArrayHasKey($iId, $aWaitedCIList);
$this->assertEquals($aWaitedCIList[$iId], $oLnk->Get('impact_code'));
}
}
@@ -737,7 +737,7 @@ class ItopDataTestCase extends ItopTestCase
$iId = $oLnk->Get('contact_id');
if (!empty($aWaitedContactList))
{
$this->assertTrue(array_key_exists($iId, $aWaitedContactList));
$this->assertArrayHasKey($iId, $aWaitedContactList);
foreach ($aWaitedContactList[$iId] as $sAttCode => $oValue)
{
if (MetaModel::IsValidAttCode(get_class($oTicket), $sAttCode))
@@ -756,5 +756,29 @@ class ItopDataTestCase extends ItopTestCase
$this->iTestOrgId = $oOrg->GetKey();
}
/**
* Assert that a series of operations will trigger a given number of MySL queries
*
* @param $iExpectedCount Number of MySQL queries that should be executed
* @param callable $oFunction Operations to perform
*
* @throws \MySQLException
* @throws \MySQLQueryHasNoResultException
*/
protected static function assertDBQueryCount($iExpectedCount, callable $oFunction)
{
$iInitialCount = (int) CMDBSource::QueryToScalar("SHOW SESSION STATUS LIKE 'Queries'", 1);
$oFunction();
$iFinalCount = (int) CMDBSource::QueryToScalar("SHOW SESSION STATUS LIKE 'Queries'", 1);
$iCount = $iFinalCount - 1 - $iInitialCount;
if ($iCount != $iExpectedCount)
{
static::fail("Expected $iExpectedCount queries. $iCount have been executed.");
}
else
{
// Otherwise PHP Unit will consider that no assertion has been made
static::assertTrue(true);
}
}
}

View File

@@ -0,0 +1,68 @@
<?php
namespace Combodo\iTop\Test\UnitTest\Core;
use Combodo\iTop\Test\UnitTest\ItopTestCase;
use CSVParser;
class CSVParserTest extends ItopTestCase
{
protected function setUp()
{
parent::setUp();
require_once(APPROOT.'core/csvparser.class.inc.php');
require_once(APPROOT.'core/coreexception.class.inc.php');
}
public function testFile()
{
$sSeparator = ';';
$sDelimiter = '?';
$sDataFile = '?field1?;?field2?;?field3?
?line 0, col 0?;?line 0, col 1?;?line 0, col 2?
a;b;c
a;b;<NULL>
? a ? ; ? b ? ; ? c ?
a ; b ; c
??;??;??
;;
?a"?;?b?;?c?
?a1
a2?;?b?;?c?
?a1,a2?;?b?;?c?
?a?;?b?;?c1,",c2
,c3?
?a?;?b?;?ouf !?
spaces trimmed out ; 1234; mac@enroe.com ';
$aExpectedResult = array(
array('line 0, col 0', 'line 0, col 1', 'line 0, col 2'),
array('a', 'b', 'c'),
array('a', 'b', null),
array(' a ', ' b ', ' c '),
array('a', 'b', 'c'),
array('', '', ''),
array('', '', ''),
array('a"', 'b', 'c'),
array("a1\na2", 'b', 'c'),
array('a1,a2', 'b', 'c'),
array('a', 'b', "c1,\",c2\n,c3"),
array('a', 'b', 'ouf !'),
array('spaces trimmed out', '1234', 'mac@enroe.com'),
);
$oCSVParser = new CSVParser($sDataFile, $sSeparator, $sDelimiter);
$aData = $oCSVParser->ToArray(1, null, 0);
foreach ($aData as $iRow => $aRow)
{
foreach ($aRow as $iCol => $cellValue)
{
$this->assertSame($aExpectedResult[$iRow][$iCol], $cellValue, "Line $iRow, Column $iCol");
}
}
}
}

View File

@@ -48,6 +48,7 @@ class DBObjectTest extends ItopDataTestCase
/**
* Test default page name
* @covers DBObject::GetUIPage
*/
public function testGetUIPage()
{
@@ -81,6 +82,9 @@ class DBObjectTest extends ItopDataTestCase
array('PHP_INT_MIN', false));
}
/**
* @covers DBObject::GetOriginal
*/
public function testGetOriginal()
{
$oObject = $this->CreateUserRequest(190664);
@@ -88,4 +92,114 @@ class DBObjectTest extends ItopDataTestCase
static::assertNull($oObject->GetOriginal('sla_tto_passed'));
}
/**
* @covers DBObject::NewObject
* @covers DBObject::Get
* @covers DBObject::Set
*/
public function testAttributeRefresh_FriendlyName()
{
$oObject = \MetaModel::NewObject('Person', array('name' => 'Foo', 'first_name' => 'John', 'org_id' => 3, 'location_id' => 2));
static::assertEquals('John Foo', $oObject->Get('friendlyname'));
$oObject->Set('name', 'Who');
static::assertEquals('John Who', $oObject->Get('friendlyname'));
}
/**
* @covers MetaModel::GetObject
* @covers DBObject::Get
* @covers DBObject::Set
*/
public function testAttributeRefresh_FriendlyNameFromDB()
{
$oObject = \MetaModel::NewObject('Person', array('name' => 'Gary', 'first_name' => 'Romain', 'org_id' => 3, 'location_id' => 2));
$oObject->DBInsert();
$iObjKey = $oObject->GetKey();
$oObject = \MetaModel::GetObject('Person', $iObjKey);
static::assertEquals('Romain Gary', $oObject->Get('friendlyname'));
$oObject->Set('name', 'Duris');
static::assertEquals('Romain Duris', $oObject->Get('friendlyname'));
}
/**
* @covers DBObject::NewObject
* @covers DBObject::Get
* @covers DBObject::Set
*/
public function testAttributeRefresh_ObsolescenceFlag()
{
$oObject = \MetaModel::NewObject('Person', array('name' => 'Foo', 'first_name' => 'John', 'org_id' => 3, 'location_id' => 2));
static::assertEquals(false, (bool)$oObject->Get('obsolescence_flag'));
$oObject->Set('status', 'inactive');
static::assertEquals(true, (bool)$oObject->Get('obsolescence_flag'));
}
/**
* @covers DBObject::NewObject
* @covers DBObject::Get
* @covers DBObject::Set
*/
public function testAttributeRefresh_ExternalKeysAndFields()
{
static::assertDBQueryCount(0, function() use (&$oObject){
$oObject = \MetaModel::NewObject('Person', array('name' => 'Foo', 'first_name' => 'John', 'org_id' => 3, 'location_id' => 2));
});
static::assertDBQueryCount(2, function() use (&$oObject){
static::assertEquals('Demo', $oObject->Get('org_id_friendlyname'));
static::assertEquals('Grenoble', $oObject->Get('location_id_friendlyname'));
});
// External key given as an id
static::assertDBQueryCount(1, function() use (&$oObject){
$oObject->Set('org_id', 2);
static::assertEquals('IT Department', $oObject->Get('org_id_friendlyname'));
});
// External key given as an object
static::assertDBQueryCount(1, function() use (&$oBordeaux){
$oBordeaux = \MetaModel::GetObject('Location', 1);
});
static::assertDBQueryCount(0, function() use (&$oBordeaux, &$oObject){
$oObject->Set('location_id', $oBordeaux);
static::assertEquals('IT Department', $oObject->Get('org_id_friendlyname'));
static::assertEquals('IT Department', $oObject->Get('org_name'));
static::assertEquals('Bordeaux', $oObject->Get('location_id_friendlyname'));
});
}
public function testSetExtKeyUnsetDependentAttribute()
{
$oObject = \MetaModel::NewObject('Person', array('name' => 'Foo', 'first_name' => 'John', 'org_id' => 3, 'location_id' => 2));
$oOrg = \MetaModel::GetObject('Organization', 2);
$oObject->Set('org_id', $oOrg);
static::assertEquals(0, $oObject->Get('location_id'));
}
/**
* @group Integration
*/
public function testModelExpressions()
{
foreach (\MetaModel::GetClasses() as $sClass)
{
if (\MetaModel::IsAbstract($sClass)) continue;
$oObject = \MetaModel::NewObject($sClass);
foreach (\MetaModel::ListAttributeDefs($sClass) as $sAttCode => $oAttDef)
{
if ($oAttDef->IsBasedOnOQLExpression())
{
$this->debug("$sClass::$sAttCode");
static::assertDBQueryCount(0, function() use (&$oObject, &$oAttDef){
$oObject->EvaluateExpression($oAttDef->GetOQLExpression());
});
}
}
}
}
}

View File

@@ -0,0 +1,535 @@
<?php
namespace Combodo\iTop\Test\UnitTest\Core;
use CMDBSource;
use Combodo\iTop\Test\UnitTest\iTopDataTestCase;
use DateInterval;
use DateTime;
use Expression;
use FunctionExpression;
use MetaModel;
use ScalarExpression;
class ExpressionEvaluateTest extends iTopDataTestCase
{
const USE_TRANSACTION = false;
/**
* @covers Expression::GetParameters()
* @dataProvider GetParametersProvider
*
* @param $sExpression
* @param $sParentFilter
* @param $aExpectedParameters
*
* @throws \OQLException
*/
public function testGetParameters($sExpression, $sParentFilter, $aExpectedParameters)
{
$oExpression = Expression::FromOQL($sExpression);
$aParameters = $oExpression->GetParameters($sParentFilter);
sort($aExpectedParameters);
sort($aParameters);
static::assertEquals($aExpectedParameters, $aParameters);
}
public function GetParametersProvider()
{
return array(
array('1 AND 0 OR :hello + :world', null, array('hello', 'world')),
array('1 AND 0 OR :hello + :world', 'this', array()),
array(':this->left + :this->right', null, array('this->left', 'this->right')),
array(':this->left + :this->right', 'this', array('left', 'right')),
array(':this->left + :this->right', 'that', array()),
array(':this_left + :this_right', 'this', array()),
);
}
/**
* 100x quicker to execute than testExpressionEvaluate
*
* @covers Expression::Evaluate()
* @covers Expression::FromOQL()
* @relies-on-dataProvider VariousExpressions
* @throws \OQLException
*/
public function _testExpressionEvaluateAllAtOnce()
{
$aTestCases = $this->VariousExpressionsProvider();
foreach ($aTestCases as $sCaseId => $aTestArgs)
{
$this->debug("Case $sCaseId:");
$this->testVariousExpressions($aTestArgs[0], $aTestArgs[1]);
}
}
/**
* @covers Expression::Evaluate()
* @covers Expression::FromOQL()
* @dataProvider VariousExpressionsProvider
*
* @param string $sExpression
* @param string $expectedValue
*
* @throws \OQLException
* @throws \Exception
*/
public function testVariousExpressions($sExpression, $expectedValue)
{
$oExpression = Expression::FromOQL($sExpression);
$value = $oExpression->Evaluate(array());
static::assertEquals($expectedValue, $value);
}
public function VariousExpressionsProvider()
{
if (false)
{
$aExpressions = array(
// Test case to isolate for troubleshooting purposes
array('1+1', 2),
);
}
else
{
$aExpressions = array(
// The bare minimum
array('"blah"', 'blah'),
array('"\\\\"', '\\'),
// Arithmetics
array('2+2', 4),
array('2+2-2', 2),
array('2*(3+4)', 14),
array('(2*3)+4', 10),
array('2*3+4', 10),
// Strings
array("CONCAT('hello', 'world')", 'helloworld'),
// Not yet parsed - array("CONCAT_WS(' ', 'hello', 'world')", 'hello world'),
array("SUBSTR('abcdef', 2, 3)", 'bcd'),
array("TRIM(' Sin dolor ')", 'Sin dolor'),
// Comparison operators
array('1 = 1', 1),
array('1 != 1', 0),
array('0 = 1', 0),
array('0 != 1', 1),
array('2 > 1', 1),
array('2 < 1', 0),
array('1 > 2', 0),
array('2 > 1', 1),
array('2 >= 1', 1),
array('2 >= 2', 1),
array("'the quick brown dog' LIKE '%QUICK%'", 1),
array("'the quick brown dog' LIKE '%SLOW%'", 0),
array("'the quick brown dog' LIKE '%QU_CK%'", 1),
array("'the quick brown dog' LIKE '%QU_ICK%'", 0),
array('"400 (km/h)" LIKE "400%"', 1),
array('"400 (km/h)" LIKE "100%"', 0),
array('"2020-06-12" > "2020-06-11"', 1),
array('"2020-06-12" < "2020-06-11"', 0),
array('" 2020-06-12" > "2020-06-11"', 0), // Leading spaces => a string
array('" 2020-06-12 " > "2020-06-11"', 0), // Trailing spaces => a string
array('"2020-06-12 17:35:13" > "2020-06-12 17:35:12"', 1),
array('"2020-06-12 17:35:13" < "2020-06-12 17:35:12"', 0),
array('"2020-06-12 17:35:13" > "2020-06-12"', 1),
array('"2020-06-12 17:35:13" < "2020-06-12"', 0),
array('"2020-06-12 00:00:00" = "2020-06-12"', 0),
// Logical operators
array('0 AND 0', 0),
array('1 AND 0', 0),
array('0 AND 1', 0),
array('1 AND 1', 1),
array('0 OR 0', 0),
array('0 OR 1', 1),
array('1 OR 0', 1),
array('1 OR 1', 1),
array('1 AND 0 OR 1', 1),
// Casting
array('1 AND "blah"', 0),
array('1 AND "1"', 1),
array('1 AND "2"', 1),
array('1 AND "0"', 0),
array('1 AND "-1"', 1),
// Null
array('NULL', null),
array('1 AND NULL', null),
array('CONCAT("Great but...", NULL)', null),
array('COALESCE(NULL, 123)', 123),
array('COALESCE(321, 123)', 321),
array('ISNULL(NULL)', 1),
array('ISNULL(123)', 0),
// Date functions
array("DATE('2020-03-12 13:18:30')", '2020-03-12'),
array("DATE_FORMAT('2009-10-04 22:23:00', '%Y %m %d %H %i %s')", '2009 10 04 22 23 00'),
array("DATE(NOW()) = CURRENT_DATE()", 1), // Could fail if executed around midnight!
array("TO_DAYS('2020-01-02')", 737791),
array("FROM_DAYS(737791)", '2020-01-02'),
array("YEAR('2020-05-03')", 2020),
array("MONTH('2020-05-03')", 5),
array("DAY('2020-05-03')", 3),
array("DATE_ADD('2020-02-28 18:00:00', INTERVAL 1 HOUR)", '2020-02-28 19:00:00'),
array("DATE_ADD('2020-02-28 18:00:00', INTERVAL 1 DAY)", '2020-02-29 18:00:00'),
array("DATE_SUB('2020-03-01 18:00:00', INTERVAL 1 HOUR)", '2020-03-01 17:00:00'),
array("DATE_SUB('2020-03-01 18:00:00', INTERVAL 1 DAY)", '2020-02-29 18:00:00'),
// Misc. functions
array('IF(1, 123, 567)', 123),
array('IF(0, 123, 567)', 567),
array('ELT(3, "a", "b", "c")', 'c'),
array('ELT(0, "a", "b", "c")', null),
array('ELT(4, "a", "b", "c")', null),
array('INET_ATON("128.0.0.1")', 2147483649),
array('INET_NTOA(2147483649)', '128.0.0.1'),
);
}
// Build a comprehensive index
$aRet = array();
foreach ($aExpressions as $aExp)
{
$aRet[$aExp[0]] = $aExp;
}
return $aRet;
}
/**
* @covers Expression::Evaluate()
* @dataProvider NotYetParsableExpressionsProvider
*
* @param string $sExpression
* @param string $expectedValue
*/
public function testNotYetParsableExpressions($sExpression, $expectedValue)
{
$sNewExpression = "return $sExpression;";
$oExpression = eval($sNewExpression);
$res = $oExpression->Evaluate(array());
static::assertEquals($expectedValue, $res);
}
public function NotYetParsableExpressionsProvider()
{
$aExpressions = array(
array("new \\FunctionExpression('CONCAT_WS', array(new \\ScalarExpression(' '), new \\ScalarExpression('Hello'), new \ScalarExpression('world!')))", 'Hello world!'),
array("new \\ScalarExpression('windows\\system32')", 'windows\\system32'),
array("new \\BinaryExpression(new \\ScalarExpression('100%'), 'LIKE', new \\ScalarExpression('___\%'))", 1),
array("new \\BinaryExpression(new \ScalarExpression('1000'), 'LIKE', new \ScalarExpression('___\%'))", 0),
// Net yet parsed - array("TIME(NOW()) = CURRENT_TIME()", 1), // Not relevant
// Not yet parsed - array("DATE_ADD('2020-02-28 18:00:00', INTERVAL 1 WEEK)", '2020-03-06 18:00:00'),
// Not yet parsed - array("DATE_SUB('2020-03-01 18:00:00', INTERVAL 1 WEEK)", '2020-02-23 18:00:00'),
// Not yet parsed - array('ROUND(1.2345, 2)', 1.23),
// Not yet parsed - array('FLOOR(1.2)', 1),
);
// Build a comprehensive index
$aRet = array();
foreach ($aExpressions as $aExp)
{
$aRet[$aExp[0]] = $aExp;
}
return $aRet;
}
/**
* Check that the test data would give the same result when evaluated by MySQL
* It uses the data provider ExpressionProvider, and checks every test case in one single query
*
* @throws \MySQLException
*/
public function testMySQLEvaluateAllAtOnce()
{
// Expressions given as an OQL
$aTests = array_values($this->VariousExpressionsProvider());
// Expressions given as a PHP statement
foreach (array_values($this->NotYetParsableExpressionsProvider()) as $i => $aTest)
{
$sNewExpression = "return {$aTest[0]};";
$oExpression = eval($sNewExpression);
$sExpression = $oExpression->RenderExpression(true);
$aTests[] = array($sExpression, $aTest[1]);
}
$aExpressions = array();
foreach ($aTests as $i => $aTest)
{
$aExpressions[] = "{$aTest[0]} as test_$i";
}
$sSelects = implode(', ', $aExpressions);
$sQuery = "SELECT $sSelects";
$this->debug($sQuery);
$aResults = CMDBSource::QueryToArray($sQuery);
foreach ($aTests as $i => $aTest)
{
$value = $aResults[0]["test_$i"];
$expectedValue = $aTest[1];
$this->debug("Test #$i: {$aTests[$i][0]} => ".var_export($value, true));
static::assertEquals($expectedValue, $value);
}
}
/**
* @covers DBObject::EvaluateExpression
* @dataProvider ExpressionsWithObjectFieldsProvider
*
* @param $sClass
* @param $aValues
* @param $sExpression
* @param $expected
*
* @throws \CoreException
* @throws \OQLException
*/
public function testExpressionsWithObjectFields($sClass, $aValues, $sExpression, $expected)
{
$oObject = MetaModel::NewObject($sClass, $aValues);
$oExpression = Expression::FromOQL($sExpression);
$res = $oObject->EvaluateExpression($oExpression);
static::assertEquals($expected, $res);
}
public function ExpressionsWithObjectFieldsProvider()
{
return array(
array('Location', array('name' => 'Grenoble', 'org_id' => 2), 'org_id', 2),
array('Location', array('name' => 'Grenoble', 'org_id' => 2), 'CONCAT(SUBSTR(name, 4), " cause")', 'noble cause'),
);
}
/**
* @dataProvider ExpressionWithParametersProvider
*
* @param $sExpression
* @param $aParameters
* @param $expected
*
* @throws \OQLException
* @throws \Exception
*/
public function testExpressionWithParameters($sExpression, $aParameters, $expected)
{
$oExpression = Expression::FromOQL($sExpression);
$res = $oExpression->Evaluate($aParameters);
static::assertEquals($expected, $res);
}
public function ExpressionWithParametersProvider()
{
return array(
array('CONCAT(SUBSTR(name, 4), " cause")', array('name' => 'noble'), 'le cause'),
);
}
/**
* Check Expression::IfTrue
*
* @covers Expression::FromOQL
* @covers Expression::IsTrue
* @dataProvider TrueExpressionsProvider
*
* @param $sExpression
* @param $bExpectTrue
*
* @throws \OQLException
*/
public function testTrueExpressions($sExpression, $bExpectTrue)
{
$oExpression = Expression::FromOQL($sExpression);
$res = $oExpression->IsTrue();
if ($bExpectTrue)
{
static::assertTrue($res, 'arg: '.$sExpression);
}
else
{
static::assertFalse($res, 'arg: '.$sExpression);
}
}
public function TrueExpressionsProvider()
{
$aExpressions = array(
array('1', true),
array('0 OR 0', false),
array('1 AND 1', true),
array('1 AND (1 OR 0)', true)
);
// Build a comprehensive index
$aRet = array();
foreach ($aExpressions as $aExp)
{
$aRet[$aExp[0]] = $aExp;
}
return $aRet;
}
/**
* @covers FunctionExpression::Evaluate()
* @dataProvider TimeFormatsProvider
*
* @param $sFormat
* @param $bProcessed
* @param $sValueOrException
*
* @throws \CoreException
* @throws \MySQLException
* @throws \MySQLQueryHasNoResultException
* @throws \Exception
*/
public function testTimeFormat($sFormat, $bProcessed, $sValueOrException)
{
$sDate = '2009-06-04 21:23:24';
$oExpression = new FunctionExpression('DATE_FORMAT', array(new ScalarExpression($sDate), new ScalarExpression("%$sFormat")));
if ($bProcessed)
{
$sqlValue = CMDBSource::QueryToScalar("SELECT DATE_FORMAT('$sDate', '%$sFormat')");
static::assertEquals($sqlValue, $sValueOrException, 'Check test against MySQL');
$res = $oExpression->Evaluate(array());
static::assertEquals($sValueOrException, $res, 'Check evaluation');
}
else
{
static::expectException($sValueOrException);
$oExpression->Evaluate(array());
}
}
public function TimeFormatsProvider()
{
$aTests = array(
array('a', true, 'Thu'),
array('b', true, 'Jun'),
array('c', true, '6'),
array('D', true, '4th'),
array('d', true, '04'),
array('e', true, '4'),
array('f', false, 'NotYetEvaluatedExpression'), // microseconds: no way!
array('H', true, '21'),
array('h', true, '09'),
array('I', true, '09'),
array('i', true, '23'),
array('j', true, '155'), // day of the year
array('k', true, '21'),
array('l', true, '9'),
array('M', true, 'June'),
array('m', true, '06'),
array('p', true, 'PM'),
array('r', true, '09:23:24 PM'),
array('S', true, '24'),
array('s', true, '24'),
array('T', true, '21:23:24'),
array('U', false, 'NotYetEvaluatedExpression'), // Week sunday based (mode 0)
array('u', false, 'NotYetEvaluatedExpression'), // Week monday based (mode 1)
array('V', false, 'NotYetEvaluatedExpression'), // Week sunday based (mode 2)
array('v', true, '23'), // Week monday based (mode 3 - ISO-8601)
array('W', true, 'Thursday'),
array('w', true, '4'),
array('X', false, 'NotYetEvaluatedExpression'),
array('x', true, '2009'), // to be used with %v (ISO - 8601)
array('Y', true, '2009'),
array('y', true, '09'),
);
$aRes = array();
foreach ($aTests as $aTest)
{
$aRes["Format %{$aTest[0]}"] = $aTest;
}
return $aRes;
}
/**
* Systematically check all supported format specs, for a given date
*
* @covers FunctionExpression::Evaluate()
* @dataProvider EveryTimeFormatProvider
*
* @param $sDate
*
* @throws \CoreException
* @throws \MySQLException
* @throws \Exception
*/
public function testEveryTimeFormat($sDate)
{
$aFormats = $this->TimeFormatsProvider();
$aSelects = array();
foreach ($aFormats as $sFormatDesc => $aFormatSpec)
{
$sFormat = $aFormatSpec[0];
$bProcessed = $aFormatSpec[1];
if ($bProcessed)
{
$aSelects["%$sFormat"] = "DATE_FORMAT('$sDate', '%$sFormat') AS `$sFormat`";
}
}
$sSelects = "SELECT ".implode(', ', $aSelects);
$aRes = CMDBSource::QueryToArray($sSelects);
$aRow = $aRes[0];
foreach ($aFormats as $sFormatDesc => $aFormatSpec)
{
$sFormat = $aFormatSpec[0];
$bProcessed = $aFormatSpec[1];
if ($bProcessed)
{
$oExpression = new FunctionExpression('DATE_FORMAT', array(new ScalarExpression($sDate), new ScalarExpression("%$sFormat")));
$res = $oExpression->Evaluate(array());
static::assertEquals($aRow[$sFormat], $res, "Format %$sFormat not matching MySQL for '$sDate'");
}
}
}
public function EveryTimeFormatProvider()
{
return array(
array('1971-07-19 8:40:00'),
array('1999-12-31 23:59:59'),
array('2000-01-01 00:00:00'),
array('2009-06-04 21:23:24'),
array('2020-02-29 23:59:59'),
array('2030-10-21 23:59:59'),
array('2050-12-21 23:59:59'),
);
}
/**
* Systematically check all supported format specs, for a range of dates
*
* @covers FunctionExpression::Evaluate()
* @dataProvider EveryTimeFormatOnDateRangeProvider
*
* @param $sStartDate
* @param $sInterval
* @param $iRepeat
*
* @throws \CoreException
* @throws \MySQLException
* @throws \Exception
*/
public function testEveryTimeFormatOnDateRange($sStartDate, $sInterval, $iRepeat)
{
$oDate = new DateTime($sStartDate);
for ($i = 0 ; $i < $iRepeat ; $i++)
{
$sDate = date_format($oDate, 'Y-m-d, H:i:s');
$this->debug("Checking '$sDate'");
$this->testEveryTimeFormat($sDate);
$oDate->add(new DateInterval($sInterval));
}
}
public function EveryTimeFormatOnDateRangeProvider()
{
return array(
'10 years, day by day' => array('2000-01-01', 'P1D', 365 * 10),
'1 day, hour by hour' => array('2000-01-01 00:01:02', 'PT1H', 24),
'1 hour, minute by minute' => array('2000-01-01 00:01:02', 'PT1M', 60),
'1 minute, second by second' => array('2000-01-01 00:01:02', 'PT1S', 60),
);
}
}

View File

@@ -277,5 +277,42 @@ class HTMLDOMSanitizerTest extends ItopTestCase
);
}
/**
* @dataProvider CallInlineImageProcessImageTagProvider
*/
public function testDoSanitizeCallInlineImageProcessImageTag($sHtml, $iExpectedCount)
{
require_once APPROOT.'test/core/sanitizer/InlineImageMock.php';
$oSanitizer = new HTMLDOMSanitizer();
$oSanitizer->DoSanitize($sHtml);
$iCalledCount = \InlineImage::GetCallCounter();
$this->assertEquals($iExpectedCount, $iCalledCount);
}
public function CallInlineImageProcessImageTagProvider()
{
return array(
'no image' => array(
'html' => '<p>bar</p>',
'expected' => 0,
),
'basic image' => array(
'html' => '<img />',
'expected' => 1,
),
'nested images within forbidden tags' => array(
'html' => '<html><body><img /><iframe baz="1"><div baz="baz"><article baz="1" biz="2">baz<img /><img /></article>rab</div> oof<img /></iframe><img /></body></html>',
'expected' => 2,
),
// This test will be restored with the ticket n°2556
// 'nested images within forbidden and removed tags' => array(
// 'html' => '<html><body><img /><iframe baz="1"><div baz="baz"><object baz="1" biz="2">baz<img /><img /></object>rab</div> oof<img /></iframe><img /></body></html>',
// 'expected' => 2,
// ),
);
}
}

View File

@@ -83,4 +83,230 @@ class MetaModelTest extends ItopDataTestCase
),
);
}
/**
* @covers MetaModel::GetDependentAttributes()
* @dataProvider GetDependentAttributesProvider
*
* @param string $sClass
* @param string $sAttCode
* @param array $aExpectedAttCodes
*
* @throws \Exception
*/
public function testGetDependentAttributes($sClass, $sAttCode, array $aExpectedAttCodes)
{
$aRes = MetaModel::GetDependentAttributes($sClass, $sAttCode);
// The order doesn't matter
sort($aRes);
sort($aExpectedAttCodes);
static::assertEquals($aExpectedAttCodes, $aRes);
}
public function GetDependentAttributesProvider()
{
$aRawCases = array(
array('Person', 'org_id', array('location_id', 'org_name', 'org_id_friendlyname', 'org_id_obsolescence_flag')),
array('Person', 'name', array('friendlyname')),
array('Person', 'status', array('obsolescence_flag')),
);
$aRet = array();
foreach ($aRawCases as $i => $aData)
{
$aRet[$aData[0].'::'.$aData[1]] = $aData;
}
return $aRet;
}
/**
* @covers MetaModel::GetPrerequisiteAttributes()
* @dataProvider GetPrerequisiteAttributesProvider
*
* @param string $sClass
* @param string $sAttCode
* @param array $aExpectedAttCodes
*
* @throws \Exception
*/
public function testGetPrerequisiteAttributes($sClass, $sAttCode, array $aExpectedAttCodes)
{
$aRes = MetaModel::GetPrerequisiteAttributes($sClass, $sAttCode);
// The order doesn't matter
sort($aRes);
sort($aExpectedAttCodes);
static::assertEquals($aRes, $aExpectedAttCodes);
}
public function GetPrerequisiteAttributesProvider()
{
$aRawCases = array(
array('Person', 'friendlyname', array('name', 'first_name')),
array('Person', 'obsolescence_flag', array('status')),
array('Person', 'org_id_friendlyname', array('org_id')),
array('Person', 'org_id', array()),
array('Person', 'org_name', array('org_id')),
);
$aRet = array();
foreach ($aRawCases as $i => $aData)
{
$aRet[$aData[0].'::'.$aData[1]] = $aData;
}
return $aRet;
}
/**
* To be removed as soon as the dependencies on external fields are obsoleted
* @Group Integration
*/
public function testManualVersusAutomaticDependenciesOnExtKeys()
{
foreach (\MetaModel::GetClasses() as $sClass)
{
if (\MetaModel::IsAbstract($sClass)) continue;
foreach (\MetaModel::ListAttributeDefs($sClass) as $sAttCode => $oAttDef)
{
if (\MetaModel::GetAttributeOrigin($sClass, $sAttCode) != $sClass) continue;
if (!$oAttDef instanceof \AttributeExternalKey) continue;
$aManual = $oAttDef->Get('depends_on');
$aAuto = \MetaModel::GetPrerequisiteAttributes($sClass, $sAttCode);
// The order doesn't matter
sort($aAuto);
sort($aManual);
static::assertEquals($aManual, $aAuto, "Class: $sClass, Attribute: $sAttCode");
}
}
}
/**
* @dataProvider enumPluginsProvider
*
* @param $expectedResults
* @param $m_aExtensionClassNames
* @param $m_aExtensionClasses
* @param $interface
* @param null $sFilterInstanceOf
*/
public function testEnumPlugins($expectedInstanciationCalls, $expectedResults, $m_aExtensionClassNames, $m_aExtensionClasses, $interface, $sFilterInstanceOf=null)
{
$pluginInstanciationManager = new \PluginInstanciationManager();
$res = $pluginInstanciationManager->InstantiatePlugins($m_aExtensionClassNames, $interface);
$mPluginInstanciationManager = $this->createMock(\PluginInstanciationManager::class);
$mPluginInstanciationManager->expects($this->exactly($expectedInstanciationCalls))
->method('InstantiatePlugins')
->willReturn($res);
$m_PluginManager = new \PluginManager($m_aExtensionClassNames, $m_aExtensionClasses, $mPluginInstanciationManager);
//warning: called twice on purpose
$m_PluginManager->EnumPlugins($interface, $sFilterInstanceOf);
$pluginInstances = $m_PluginManager->EnumPlugins($interface, $sFilterInstanceOf);
$this->assertCount(sizeof($expectedResults), $pluginInstances);
foreach($pluginInstances as $pluginInstance)
{
if ($sFilterInstanceOf!==null)
{
$this->assertTrue($pluginInstance instanceof $sFilterInstanceOf);
}
}
$index=0;
foreach($expectedResults as $expectedInterface)
{
$this->assertTrue(is_a($pluginInstances[$index], $expectedInterface));
$index++;
}
}
public function enumPluginsProvider(){
$aInterfaces = [
"empty conf" => [ 0, [], [], [], 'Wizzard'],
"simple instance retrieval" => [ 1, [Gryffindor::class], [ 'Wizzard' => [ Gryffindor::class]], [], 'Wizzard'],
"check instanceof parameter" => [ 1, [Gryffindor::class, Slytherin::class], [ 'Wizzard' => [ Gryffindor::class, Slytherin::class]], [], 'Wizzard'],
"try to retrieve a non instanciable object" => [ 1, [Gryffindor::class], [ 'Wizzard' => [ Gryffindor::class, Muggle::class]], [], 'Wizzard', Gryffindor::class ],
];
return $aInterfaces;
}
/**
* @dataProvider getPluginsProvider
*
* @param $expectedInstanciationCalls
* @param $expectedResults
* @param $m_aExtensionClassNames
* @param $m_aExtensionClasses
* @param $interface
* @param $className
*/
public function testGetPlugins($expectedInstanciationCalls, $expectedResults, $m_aExtensionClassNames, $m_aExtensionClasses, $interface, $className)
{
$pluginInstanciationManager = new \PluginInstanciationManager();
$res = $pluginInstanciationManager->InstantiatePlugins($m_aExtensionClassNames, $interface);
$mPluginInstanciationManager = $this->createMock(\PluginInstanciationManager::class);
$mPluginInstanciationManager->expects($this->exactly($expectedInstanciationCalls))
->method('InstantiatePlugins')
->willReturn($res);
$m_PluginManager = new \PluginManager($m_aExtensionClassNames, $m_aExtensionClasses, $mPluginInstanciationManager);
//warning: called twice on purpose
$m_PluginManager->GetPlugins($interface, $className);
$pluginInstance = $m_PluginManager->GetPlugins($interface, $className);
if (sizeof($expectedResults)==0)
{
$this->assertNull($pluginInstance);
return;
}
$this->assertTrue($pluginInstance instanceof $className);
$this->assertTrue(is_a($pluginInstance, $expectedResults[0]));
}
public function getPluginsProvider(){
$aInterfaces = [
"empty conf" => [ 0, [], [], [], 'Wizzard', Gryffindor::class],
"simple instance retrieval" => [ 1, [Gryffindor::class], [ 'Wizzard' => [ Gryffindor::class]], [], 'Wizzard', Gryffindor::class],
"check instanceof parameter" => [ 1, [Gryffindor::class], [ 'Wizzard' => [ Gryffindor::class, Slytherin::class]], [], 'Wizzard', Gryffindor::class],
"try to retrieve a non instanciable object" => [ 1, [Gryffindor::class], [ 'Wizzard' => [ Gryffindor::class, Muggle::class]], [], 'Wizzard', Gryffindor::class ],
];
return $aInterfaces;
}
}
abstract class Wizzard
{
/**
* Wizzard constructor.
*/
public function __construct()
{
}
}
class Gryffindor extends Wizzard
{
}
class Hufflepuff extends Wizzard
{
}
class Ravenclaw extends Wizzard
{
}
class Slytherin extends Wizzard
{
}
class Muggle
{
}

View File

@@ -0,0 +1,39 @@
<?php
/**
* Copyright (C) 2010-2020 Combodo SARL
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with iTop. If not, see <http: *www.gnu.org/licenses/>
*
*/
/**
* Mock class used by @see \Combodo\iTop\Test\UnitTest\Core\HTMLDOMSanitizerTest
*
*/
class InlineImage
{
private static $iCallCounter = 0;
public static function ProcessImageTag(DOMNode $oNode)
{
self::$iCallCounter++;
}
public static function GetCallCounter()
{
return self::$iCallCounter;
}
}

View File

@@ -123,87 +123,6 @@ class TestSQLQuery extends TestScenarioOnDB
}
}
class TestCSVParser extends TestFunction
{
static public function GetName() {return 'Check CSV parsing';}
static public function GetDescription() {return 'Loads a set of CSV data';}
public function DoExecute()
{
$sDataFile = '?field1?;?field2?;?field3?
?a?;?b?;?c?
a;b;c
? a ? ; ? b ? ; ? c ?
a ; b ; c
??;??;??
;;
?a"?;?b?;?c?
?a1
a2?;?b?;?c?
?a1,a2?;?b?;?c?
?a?;?b?;?c1,",c2
,c3?
?a?;?b?;?ouf !?
Espace sur la fin ; 1234; e@taloc.com ';
self::DumpVariable($sDataFile);
$aExpectedResult = array(
//array('field1', 'field2', 'field3'),
array('a', 'b', 'c'),
array('a', 'b', 'c'),
array(' a ', ' b ', ' c '),
array('a', 'b', 'c'),
array('', '', ''),
array('', '', ''),
array('a"', 'b', 'c'),
array("a1\na2", 'b', 'c'),
array('a1,a2', 'b', 'c'),
array('a', 'b', "c1,\",c2\n,c3"),
array('a', 'b', 'ouf !'),
array('Espace sur la fin', '1234', 'e@taloc.com'),
);
$oCSVParser = new CSVParser($sDataFile, ';', '?');
$aData = $oCSVParser->ToArray(1, null, 0);
$iIssues = 0;
echo "<table border=\"1\">\n";
foreach ($aData as $iRow => $aRow)
{
echo "<tr>\n";
foreach ($aRow as $iCol => $sCell)
{
if (empty($sCell))
{
$sCellValue = '&nbsp;';
}
else
{
$sCellValue = htmlentities($sCell, ENT_QUOTES, 'UTF-8');
}
if (!isset($aExpectedResult[$iRow][$iCol]))
{
$iIssues++;
$sCellValue = "<span style =\"color: red; background-color: grey;\">$sCellValue</span>";
}
elseif ($aExpectedResult[$iRow][$iCol] != $sCell)
{
$iIssues++;
$sCellValue = "<span style =\"color: red; background-color: lightgrey;\">$sCellValue</span>, expecting '<span style =\"color: green; background-color: lightgrey;\">".$aExpectedResult[$iRow][$iCol]."</span>'";
}
echo "<td><pre>$sCellValue</pre></td>";
}
echo "</tr>\n";
}
echo "</table>\n";
return ($iIssues > 0);
}
}
class TestGenericItoMyModel extends TestBizModelGeneric
{
static public function GetName()
@@ -485,7 +404,7 @@ class TestMyBizModel extends TestBizModel
echo "Max depth = $iMaxDepth</br>\n";
$oObj = MetaModel::GetObject("cmdbContact", 18);
$aRels = $oObj->GetRelatedObjects("Potes", $iMaxDepth);
$aRels = $oObj->GetRelatedObjectsDown("Potes", $iMaxDepth);
echo $oObj->Get('name')." has some 'Potes'...</br>\n";
foreach ($aRels as $sClass => $aObjs)
{
@@ -581,391 +500,6 @@ class TestMyBizModel extends TestBizModel
}
///////////////////////////////////////////////////////////////////////////
// Test a complex biz model on the fly
///////////////////////////////////////////////////////////////////////////
abstract class MyFarm extends TestBizModel
{
static public function GetConfigFile() {return '/config-test-farm.php';}
protected function DoPrepare()
{
parent::DoPrepare();
$this->ResetDB();
MetaModel::DBCheckIntegrity();
}
protected function InsertMammal($sSpecies, $sSex, $iSpeed, $iMotherid, $iFatherId, $sName, $iHeight, $sBirth)
{
$oNew = MetaModel::NewObject('Mammal');
$oNew->Set('species', $sSpecies);
$oNew->Set('sex', $sSex);
$oNew->Set('speed', $iSpeed);
$oNew->Set('mother', $iMotherid);
$oNew->Set('father', $iFatherId);
$oNew->Set('name', $sName);
$oNew->Set('height', $iHeight);
$oNew->Set('birth', $sBirth);
return $this->ObjectToDB($oNew);
}
protected function InsertBird($sSpecies, $sSex, $iSpeed, $iMotherid, $iFatherId)
{
$oNew = MetaModel::NewObject('Bird');
$oNew->Set('species', $sSpecies);
$oNew->Set('sex', $sSex);
$oNew->Set('speed', $iSpeed);
$oNew->Set('mother', $iMotherid);
$oNew->Set('father', $iFatherId);
return $this->ObjectToDB($oNew);
}
protected function InsertFlyingBird($sSpecies, $sSex, $iSpeed, $iMotherid, $iFatherId, $iFlyingSpeed)
{
$oNew = MetaModel::NewObject('FlyingBird');
$oNew->Set('species', $sSpecies);
$oNew->Set('sex', $sSex);
$oNew->Set('speed', $iSpeed);
$oNew->Set('mother', $iMotherid);
$oNew->Set('father', $iFatherId);
$oNew->Set('flyingspeed', $iFlyingSpeed);
return $this->ObjectToDB($oNew);
}
private function InsertGroup($sName, $iLeaderId)
{
$oNew = MetaModel::NewObject('Group');
$oNew->Set('name', $sName);
$oNew->Set('leader', $iLeaderId);
$iId = $oNew->DBInsertNoReload();
return $iId;
}
}
class TestQueriesOnFarm extends MyFarm
{
static public function GetName()
{
return 'Farm test';
}
static public function GetDescription()
{
return 'A series of tests on the farm business model (SQL generation)';
}
protected function CheckQuery($sQuery, $bIsCorrectQuery)
{
if ($bIsCorrectQuery)
{
echo "<h4 style=\"color:green;\">$sQuery</h4>\n";
}
else
{
echo "<h4 style=\"color:red;\">$sQuery</h3>\n";
}
try
{
//$oOql = new OqlInterpreter($sQuery);
//$oTrash = $oOql->ParseQuery();
//self::DumpVariable($oTrash, true);
$oMyFilter = DBObjectSearch::FromOQL($sQuery);
}
catch (OQLException $oOqlException)
{
if ($bIsCorrectQuery)
{
echo "<p>More info on this unexpected failure:<br/>".$oOqlException->getHtmlDesc()."</p>\n";
throw $oOqlException;
return false;
}
else
{
// Everything is fine :-)
echo "<p>More info on this expected failure:\n";
echo "<ul>\n";
echo "<li>".get_class($oOqlException)."</li>\n";
echo "<li>".$oOqlException->getMessage()."</li>\n";
echo "<li>".$oOqlException->getHtmlDesc()."</li>\n";
echo "</ul>\n";
echo "</p>\n";
return true;
}
}
// The query was correctly parsed, was it expected to be correct ?
if (!$bIsCorrectQuery)
{
throw new UnitTestException("The query '$sQuery' was parsed with success, while it shouldn't (?)");
return false;
}
echo "<p>To OQL: ".$oMyFilter->ToOQL()."</p>";
$this->search_and_show_list($oMyFilter);
//echo "<p>first pass<p>\n";
//self::DumpVariable($oMyFilter, true);
$sQuery1 = $oMyFilter->MakeSelectQuery();
//echo "<p>second pass<p>\n";
//self::DumpVariable($oMyFilter, true);
//$sQuery1 = $oMyFilter->MakeSelectQuery();
$sSerialize = $oMyFilter->serialize();
echo "<p>Serialized:$sSerialize</p>\n";
$oFilter2 = DBObjectSearch::unserialize($sSerialize);
try
{
$sQuery2 = $oFilter2->MakeSelectQuery();
}
catch (Exception $e)
{
echo "<p>Could not compute the query after unserialize</p>\n";
echo "<p>Query 1: $sQuery1</p>\n";
MyHelpers::var_cmp_html($oMyFilter, $oFilter2);
throw $e;
}
//if ($oFilter2 != $oMyFilter) no, they may differ while the resulting query is the same!
if ($sQuery1 != $sQuery2)
{
echo "<p>serialize/unserialize mismatch :-(</p>\n";
MyHelpers::var_cmp_html($sQuery1, $sQuery2);
MyHelpers::var_cmp_html($oMyFilter, $oFilter2);
return false;
}
return true;
}
protected function DoExecute()
{
// $this->ReportError("Found two different OQL expression out of the (same?) filter: <em>$sExpr1</em> != <em>$sExpr2</em>");
// $this->ReportSuccess('Found '.$oSet->Count()." objects of class $sClassName");
echo "<h3>Create protagonists...</h3>";
$iId1 = $this->InsertMammal('human', 'male', 10, 0, 0, 'romanoff', 192, '1971-07-19');
$iId2 = $this->InsertMammal('human', 'female', 9, 0, 0, 'rouanita', 165, '1983-01-23');
$this->InsertMammal('human', 'female', 3, $iId2, $iId1, 'pomme', 169, '2008-02-23');
$this->InsertMammal('pig', 'female', 3, 0, 0, 'grouinkette', 85, '2006-06-01');
$this->InsertMammal('donkey', 'female', 3, 0, 0, 'muleta', 124, '2003-11-11');
$this->InsertBird('rooster', 'male', 12, 0, 0);
$this->InsertFlyingBird('pie', 'female', 11, 0, 0, 35);
// Benchmarking
//
if (false)
{
define ('COUNT_BENCHMARK', 10);
echo "<h3>Parsing a long query, ".COUNT_BENCHMARK." times</h3>";
$sQuery = "SELECT Animal AS Child JOIN Mammal AS Dad ON Child.father = Dad.id JOIN Animal AS Mum ON Child.mother = Mum.id WHERE Dad.birth < DATE_SUB(CURRENT_DATE(), INTERVAL 10 YEAR) AND Dad.height * 2 <= ROUND(TO_DAYS(Dad.birth) / (3 + 1) * 5 - 3)";
$fStart = MyHelpers::getmicrotime();
for($i=0 ; $i < COUNT_BENCHMARK ; $i++)
{
$oMyFilter = DBObjectSearch::FromOQL($sQuery);
}
$fDuration = MyHelpers::getmicrotime() - $fStart;
$fParsingDuration = $fDuration / COUNT_BENCHMARK;
echo "<p>Mean time by op: $fParsingDuration</p>";
}
echo "<h3>Test queries...</h3>";
$aQueries = array(
'SELECT Animal' => true,
'SELECT Animal WHERE Animal.pkey = 1' => false,
'SELECT Animal WHERE Animal.id = 1' => true,
'SELECT Aniiimal' => false,
'SELECTe Animal' => false,
'SELECT * FROM Animal' => false,
'SELECT Animal AS zoo WHERE zoo.species = \'human\'' => true,
'SELECT Animal AS zoo WHERE species = \'human\'' => true,
'SELECT Animal AS zoo WHERE espece = \'human\'' => false,
'SELECT Animal AS zoo WHERE zoo.species IN (\'human\', "pig")' => true,
'SELECT Animal AS zoo WHERE CONCATENATION(zoo.species, zoo.sex) LIKE "hum%male"' => false,
'SELECT Animal AS zoo WHERE CONCAT(zoo.species, zoo.sex) LIKE "hum%male"' => true,
'SELECT Animal AS zoo WHERE zoo.species NOT IN (\'human\', "pig")' => true,
'SELECT Animal AS zoo WHERE zoo.kind = \'human\'' => false,
'SELECT Animal WHERE Animal.species = \'human\' AND Animal.sex = \'female\'' => true,
'SELECT Mammal AS x WHERE (x.species = \'human\' AND x.name LIKE \'ro%\') OR (x.species = \'donkey\' AND x.name LIKE \'po%\')' => true,
'SELECT Mammal AS x WHERE x.species = \'human\' AND x.name LIKE \'ro%\' OR x.species = \'donkey\' AND x.name LIKE \'po%\'' => true,
'SELECT Mammal AS m WHERE MONTH(m.birth) = 7' => true,
'SELECT Mammal AS m WHERE DAY(m.birth) = 19' => true,
'SELECT Mammal AS m WHERE YEAR(m.birth) = 1971' => true,
'SELECT Mammal AS m WHERE m.birth < DATE_SUB(CURRENT_DATE(), INTERVAL 10 YEAR)' => true,
'SELECT Mammal AS m WHERE m.birth > DATE_SUB(NOW(), INTERVAL 2000 DAY)' => true,
'SELECT Mammal AS m WHERE (TO_DAYS(NOW()) - TO_DAYS(m.birth)) > 2000' => true,
'SELECT Mammal AS m WHERE m.name = IF(FLOOR(ROUND(m.height)) > 2, "pomme", "romain")' => true,
'SELECT Mammal AS m WHERE (1 + 2' => false,
'SELECT Mammal AS m WHERE (1 + 2 * 4 / 23) > 0' => true,
'SELECT Mammal AS m WHERE (4 / 23 * 2 + 1) > 0' => true,
'SELECT Mammal AS m WHERE 1/0' => true,
'SELECT Mammal AS m WHERE MONTH(m.birth) = 7' => true,
'SELECT Animal JOIN Group ON Group.leader = Animal.id' => true,
'SELECT Group JOIN Animal ON Group.leader = Animal.id' => true,
'SELECT Animal AS A JOIN Group AS G1 ON G1.leader = A.id' => true,
'SELECT Animal AS A JOIN Group AS G ON FooClass.leader = A.id' => false,
'SELECT Animal AS A JOIN Group AS G ON G.leader = FooClass.id' => false,
'SELECT Animal AS A JOIN Group AS G ON G.masterchief = A.id' => false,
'SELECT Animal AS A JOIN Group AS G ON A.id = G.leader' => false,
'SELECT Animal AS A JOIN Group AS G ON G.leader = A.id WHERE A.sex=\'male\' OR G.qwerty = 123' => false,
'SELECT Animal AS A JOIN Group AS G ON G.leader = A.id WHERE A.sex=\'male\' OR G.name LIKE "a%"' => true,
'SELECT Animal AS A JOIN Group AS G ON G.leader = A.id WHERE A.id = 1' => true,
'SELECT Animal AS A JOIN Group AS G ON G.leader = A.id WHERE id = 1' => false,
'SELECT Animal AS A JOIN Group AS G ON A.member = G.id' => false,
'SELECT Mammal AS M JOIN Group AS G ON M.member = G.id' => true,
'SELECT Mammal AS M JOIN Group AS G ON A.member = G.id' => false,
'SELECT Mammal AS myAlias JOIN Group AS myAlias ON myAlias.member = myAlias.id' => false,
'SELECT Mammal AS Mammal JOIN Group AS Mammal ON Mammal.member = Mammal.id' => false,
'SELECT Group AS G WHERE G.leader_name LIKE "%"' => true,
'SELECT Group AS G WHERE G.leader_speed < 100000' => true,
'SELECT Mammal AS M JOIN Group AS G ON M.member = G.id WHERE G.leader_name LIKE "%"' => true,
'SELECT Mammal AS M JOIN Group AS G ON M.member = G.id WHERE G.leader_speed < 100000' => true,
'SELECT Mammal AS Child JOIN Mammal AS Dad ON Child.father = Dad.id' => true,
'SELECT Mammal AS Child JOIN Animal AS Dad ON Child.father = Dad.id' => true,
'SELECT Animal AS Child JOIN Mammal AS Dad ON Child.father = Dad.id' => true,
'SELECT Animal AS Child JOIN Animal AS Dad ON Child.father = Dad.id' => true,
'SELECT Animal AS Dad JOIN Animal AS Child ON Child.father = Dad.id' => true,
'SELECT Animal AS Child JOIN Animal AS Dad ON Child.father = Dad.id JOIN Animal AS Mum ON Child.mother = Mum.id' => true,
'SELECT Animal AS Child JOIN Animal AS Dad ON Child.father = Dad.id JOIN Animal AS Mum ON Child.mother = Mum.id WHERE Dad.id = 1' => true,
'SELECT Animal AS Child JOIN Animal AS Dad ON Child.father = Dad.id JOIN Animal AS Mum ON Child.mother = Mum.id WHERE Dad.name = \'romanoff\'' => false,
'SELECT Animal AS Child JOIN Mammal AS Dad ON Child.father = Dad.id' => true,
'SELECT Animal AS Child JOIN Mammal AS Dad ON Child.father = Dad.id JOIN Animal AS Mum ON Child.mother = Mum.id WHERE Dad.name = \'romanoff\' OR Mum.speed = 0' => true,
'SELECT Animal AS Dad JOIN Animal AS Child ON Child.father = Dad.id JOIN Animal AS Mum ON Child.mother = Mum.id' => true,
'SELECT Mammal AS Dad JOIN Mammal AS Child ON Child.father = Dad.id' => true,
'SELECT Mammal AS Dad JOIN Mammal AS Child ON Child.father = Dad.id JOIN Mammal AS Mum ON Child.mother = Mum.id WHERE Dad.name = \'romanoff\' OR Mum.name=\'chloe\' OR Child.name=\'bizounours\'' => true,
// Specifying multiple objects
'SELECT Animal FROM Animal' => true,
'SELECT yelele FROM Animal' => false,
'SELECT Animal FROM Animal AS A' => false,
'SELECT A FROM Animal AS A' => true,
);
//$aQueries = array(
// 'SELECT Mammal AS M JOIN Group AS G ON M.member = G.id WHERE G.leader_name LIKE "%"' => true,
//);
foreach($aQueries as $sQuery => $bIsCorrect)
{
$this->CheckQuery($sQuery, $bIsCorrect);
}
return true;
}
}
///////////////////////////////////////////////////////////////////////////
// Test data load
///////////////////////////////////////////////////////////////////////////
class TestBulkChangeOnFarm extends TestBizModel
{
static public function GetName()
{
return 'Farm test - data load';
}
static public function GetDescription()
{
return 'Bulk load';
}
static public function GetConfigFile() {return '/config-test-farm.php';}
protected function DoPrepare()
{
parent::DoPrepare();
$this->ResetDB();
MetaModel::DBCheckIntegrity();
}
protected function DoExecute()
{
// $this->ReportError("Found two different OQL expression out of the (same?) filter: <em>$sExpr1</em> != <em>$sExpr2</em>");
// $this->ReportSuccess('Found '.$oSet->Count()." objects of class $sClassName");
$oParser = new CSVParser("denomination,hauteur,age
suzy,123,2009-01-01
chita,456,
", ',', '"');
$aData = $oParser->ToArray(1, array('_name', '_height', '_birth'));
self::DumpVariable($aData);
$oBulk = new BulkChange(
'Mammal',
$aData,
// attributes
array('name' => '_name', 'height' => '_height', 'birth' => '_birth'),
// ext keys
array(),
// reconciliation
array('name')
);
$oMyChange = MetaModel::NewObject("CMDBChange");
$oMyChange->Set("date", time());
$oMyChange->Set("userinfo", "Testor");
$iChangeId = $oMyChange->DBInsert();
// echo "Created new change: $iChangeId</br>";
echo "<h3>Planned for loading...</h3>";
$aRes = $oBulk->Process();
self::DumpVariable($aRes);
echo "<h3>Go for loading...</h3>";
$aRes = $oBulk->Process($oMyChange);
self::DumpVariable($aRes);
return;
$oRawData = array(
'Mammal',
array('species', 'sex', 'speed', 'mother', 'father', 'name', 'height', 'birth'),
"human,male,23,0,0,romulus,192,1971
human,male,23,0,0,remus,154,-50
human,male,23,0,0,julius,160,-49
human,female,23,0,0,cleopatra,142,-50
pig,female,23,0,0,confucius,50,2003"
);
}
}
///////////////////////////////////////////////////////////////////////////
// Test data load
///////////////////////////////////////////////////////////////////////////
class TestFullTextSearchOnFarm extends MyFarm
{
static public function GetName()
{
return 'Farm test - full text search';
}
static public function GetDescription()
{
return 'Focus on the full text search feature';
}
protected function DoExecute()
{
echo "<h3>Create protagonists...</h3>";
$iId1 = $this->InsertMammal('human', 'male', 10, 0, 0, 'romanoff', 192, '1971-07-19');
$iId2 = $this->InsertMammal('human', 'female', 9, 0, 0, 'rouanita', 165, '1983-01-23');
$this->InsertMammal('human', 'female', 3, $iId2, $iId1, 'pomme', 169, '2008-02-23');
$this->InsertMammal('pig', 'female', 3, 0, 0, 'grouinkette', 85, '2006-06-01');
$this->InsertMammal('donkey', 'female', 3, 0, 0, 'muleta', 124, '2003-11-11');
$this->InsertBird('rooster', 'male', 12, 0, 0);
$this->InsertFlyingBird('pie', 'female', 11, 0, 0, 35);
echo "<h3>Search...</h3>";
$oSearch = new DBObjectSearch('Mammal');
$oSearch->AddCondition_FullText('manof');
//$oResultSet = new DBObjectSet($oSearch);
$this->search_and_show_list($oSearch);
}
}
///////////////////////////////////////////////////////////////////////////
// Test queries
///////////////////////////////////////////////////////////////////////////