'App\Model\Table\MaterielsTable' ]; $this->Materiels = TableRegistry::get('Materiels', $config); $config = TableRegistry::exists('Suivis') ? [] : [ 'className' => 'App\Model\Table\SuivisTable' ]; $this->Suivis = TableRegistry::get('Suivis', $config); */ /* $this->ControllerApp = new AppController(); } public function tearDown() { //unset($this->Materiels); //unset($this->Suivis); unset($this->ControllerApp); parent::tearDown(); } */ public function setUp() { // (EP202010) // https://stackoverflow.com/questions/29748911/cakephp-connections-while-testing/45592461 /* * Some tables tests were getting default db instead of test db for no reason. * This solves the problem (we have a main test class from which we extend all tests, do some setting up. We put it there) */ TableRegistry::clear(); parent::setUp(); //$this->toto = 'titi'; // Check qu'on lit bien la table configurations de la BD de test !! $config = TableRegistry::exists('Configurations') ? [] : [ 'className' => 'App\Model\Table\ConfigurationsTable' ]; $confLabinvent = TableRegistry::getTableLocator()->get('Configurations', $config)->find()->first(); //assert($confLabinvent->ldap_authenticationType == 'uid', 'On ne lit pas la bonne configuration'); //debug($confLabinvent->ldap_authenticationType); $this->assertTextEquals('uid', $confLabinvent->ldap_authenticationType, 'On ne lit pas la bonne configuration'); $this->assertTextNotEquals('samaccountname', $confLabinvent->ldap_authenticationType, 'On ne lit pas la bonne configuration'); $this->assertTextEquals(1, $confLabinvent->test, 'On ne lit pas la bonne configuration'); $this->assertTextEquals(800, $confLabinvent->prix_inventaire_administratif, 'On ne lit pas la bonne configuration'); $this->assertTextEquals('TEST', $confLabinvent->labNameShort, 'On ne lit pas la bonne configuration'); } public function d($msg) { if ($this->DEBUG) pr($msg); } /* * On recupère une entité quelconque de la BD (fixture), peu importe ce que c'est car on va la modifier * Par défaut, on utilise la première entité de la BD (id 1) */ static protected function _getEntityIdOkForTesting() { return 1; } // To be overriden by subclasses protected function getNewEntityWithAllMandatoryFields() { throw new NotImplementedException(__METHOD__); } protected function getEntitiesName() { //throw new NotImplementedException("Méthode getEntitiesName() non implémentée !!"); $test_class_name = get_class($this); // MaterielsControllerTest, SurCategoriesControllerTest, ... //debug($test_class_name); $entities_name = explode('\\', substr($test_class_name,0,strpos($test_class_name, 'ControllerTest'))); //debug($entities_name); return $entities_name[count($entities_name)-1]; } protected function getNbEntitiesInFixture() { $entities_name = $this->getEntitiesName(); $nb = TableRegistry::getTableLocator()->get($entities_name)->find()->count(); //$this->d("nb entities in fixture: $nb"); return $nb; } protected function getNbEntitiesExpectedInIndexView() { return $this->getNbEntitiesInFixture(); } protected function getMaterielsTable() { //if (!$this->Materiels) $this->Materiels = TableRegistry::get('Materiels'); if (!$this->Materiels) $this->Materiels = TableRegistry::getTableLocator()->get('Materiels'); return $this->Materiels; /* $m = $this->Materiels->get($id); return $m; */ } protected function getMaterielsController() { // On est dans MaterielsControllerTest => on retourne le controleur courant if ($this->getEntitiesName()=='Materiels') return $this->_getController(); // Sinon, on retourne une instance spécifique pour les materiels if (!$this->controller_materiels_instance) $this->controller_materiels_instance = new MaterielsController(); return $this->controller_materiels_instance; } protected function _getController() { //if (!$this->controller_instance) $this->controller_instance = new MaterielsController(); $entities_name = $this->getEntitiesName(); // ex: 'Materiels', 'Suivis', 'SurCategories'... //$entities_name = 'SurCategories'; //debug("entities_name is $entities_name"); $controller_name = $this->_getControllerFullNameFromEntitiesName($entities_name); //debug("controller_name is $controller_name"); exit; if (!$this->controller_instance) $this->controller_instance = new $controller_name(); return $this->controller_instance; } protected static function _getControllerInstanceFromName($entities_name) { //$controller_name = $this->_getControllerFullNameFromEntitiesName($entities_name); $controller_name = self::_getControllerFullNameFromEntitiesName($entities_name); return new $controller_name(); } /* * $entities_name is 'Materiels', 'Suivis', 'SurCategories'... * @return : App\Controller\SurCategoriesController, ... */ private static function _getControllerFullNameFromEntitiesName($entities_name) { //$entities_name = ucfirst(strtolower($entities_name)); // Materiels, Suivis, Emprunts... //$entities_name = ucfirst(strtolower($entities_name)); // Materiels, Suivis, Emprunts... //$controller_name = 'App\\Controller\\'.$this->getEntitiesName().'Controller'; // ex: 'Materiels' ou 'Suivis'... return 'App\\Controller\\'.$entities_name.'Controller'; // ex: 'MaterielsController' ou 'SuivisController'... //$controller_name = 'App\\Controller\\'.$this->getEntitiesName().'Controller'; // ex: 'Materiels' ou 'Suivis'... } // This are data providers used for a lot of tests // See https://jtreminio.com/2013/03/unit-testing-tutorial-part-2-assertions-writing-a-useful-test-and-dataprovider public function dataProviderRoles4() { return $this->ROLES4; } public function dataProviderRoles5() { return $this->ROLES5; } // Idem dataProviderRoles5 mais avec USER_from_ldap en plus: public function dataProviderRoles6() { return $this->ROLES6; } protected function getActions() { //return ['toto']; return $this->_getController()->getActions(); } // Combinaison de roles (U,R,A,S) et statuts (C,V,T,A) public function dataProviderRoles4AndStatuses4() { $roles_and_statuses = []; foreach ($this->ROLES4 as $user_role) { //debug($user_role[0]); foreach ($this->MATOS_STATUSES as $matos_status) $roles_and_statuses[] = [$user_role[0], $matos_status[0]]; } //$this->d($roles_and_statuses); return $roles_and_statuses; } //public function dataProviderActionsAndRoles4($controller) { public function dataProviderActionsAndRoles4() { $actions_and_roles = []; $actions = $this->getActions(); //$actions = MaterielsController::getActions(); //$controller = 'App\\Controller\\'.$controller; //debug($this); //debug("controller is $controller_name"); exit; //$actions = $controller_name::getActions(); //$actions = SuivisController::getActions(); //debug($actions); exit; //debug("entities is : ".$this->getEntitiesName()); exit; //$actions = $this->getController()->getActions(); //debug("Liste des Actions à tester:");debug($actions); exit; //foreach ($actions as $a) echo("$a\n"); /* */ /* $actions = [ // CRUD 'add','add_by_copy', 'view','index','edit','delete', //'view', //'index', // Autres 'statusCreated', ]; */ $roles4 = [ /* */ 'user', 'resp', 'admin', 'super', ]; //$actions = ['delete']; //$actions = ['edit']; foreach ($actions as $action) //foreach ([0,1] as $i) { //foreach ([1] as $i) { //foreach ([0] as $i) { foreach ([0,1,2,3] as $i) { $item = [ $action, $roles4[$i], $this->ROLES4[$i][0] ]; //debug($item); $actions_and_roles[] = $item; } return $actions_and_roles; } /* FONCTIONS UTILITAIRES UTILISÉES PAR (tous) LES TESTS */ public static function getRoleLevel($role) { return AppController::getRoleLevel($role); } // Definition DIFFERENTE de celle de AppController public function getUserRole() { //return $this->ControllerMateriels->getUserRole(); if (! $this->CURRENT_ROLE) { $user = $this->getCurrentUser(); /* $user = TableRegistry::get('Users')->find()->where([ // username = LOGIN (ex: 'epallier') ; pour les tests : user1_SUPER, user5_USER, ... 'username' => $this->_session['Auth']['User']['uid'][0] //'username' => 'user1_SUPER' //'username' => $this->_session['Auth']['User']['cn'][0] ])->first(); */ // Unpriviledged user $role = $user ? $user['role'] : "Utilisateur"; $this->CURRENT_ROLE = $role; } return $this->CURRENT_ROLE; } protected function getCurrentUser() { if (! $this->CURRENT_USER) { $this->CURRENT_USER = TableRegistry::get('Users')->find()->where([ // username = LOGIN (ex: 'epallier') ; pour les tests : user1_SUPER, user5_USER, ... 'username' => $this->_session['Auth']['User']['uid'][0] //'username' => 'user1_SUPER' //'username' => $this->_session['Auth']['User']['cn'][0] ])->first(); } return $this->CURRENT_USER; } // MEME Definition de celle de AppController (mais n'utilise pas la meme fonction getUserRole()) public function userHasRole($expectedRole, $ORMORE=false) { $role = $this->getUserRole(); //debug($role); if (! $ORMORE) return ($role == $expectedRole); return ($this->getRoleLevel($role) >= $this->getRoleLevel($expectedRole)); } // MEME Definition de celle de AppController (mais n'utilise la meme fonction getUserRole()) public function userHasRoleAtLeast($expectedRole) { return $this->userHasRole($expectedRole, true); } // MEME Definition de celle de AppController (mais n'utilise la meme fonction getUserRole()) public function USER_IS_ADMIN_AT_LEAST() { return $this->userHasRoleAtLeast('Administration'); } public function USER_IS_RESP_AT_LEAST() { return $this->userHasRoleAtLeast('Responsable'); } public function USER_IS_SUPERADMIN() { return $this->userHasRole('Super Administrateur'); } //public function USER_IS_ADMIN_PLUS() { return $this->userHasRole('Administration Plus'); } public function USER_IS_ADMIN() { return $this->userHasRole('Administration'); } public function USER_IS_RESP() { return $this->userHasRole('Responsable'); } public function USER_IS_USER() { return $this->userHasRole('Utilisateur'); } /* public function USER_IS_ADMIN_AT_LEAST($role=null) { if (is_null($role)) { $role = $this->getUserRole(); $roles = ['Administration','Administration Plus','Super Administrateur']; } else { $roles = ['ADMIN','ADMINP','SUPER']; } return in_array($role, $roles); } */ public function authAs($role) { switch ($role) { case 'USER_from_ldap': $this->authUtilisateurFromLdap(); //$this->CURRENT_ROLE = 'Utilisateur'; break; case 'USER': $this->authUtilisateurFromTable(); //$this->CURRENT_ROLE = 'Utilisateur'; break; case 'RESP': $this->authResponsable(); //$this->CURRENT_ROLE = 'Responsable'; break; case 'ADMIN': $this->authAdmin(); //$this->CURRENT_ROLE = 'Administration'; break; /* case 'ADMINP': $this->authAdminPlus(); //$this->CURRENT_ROLE = 'Administration Plus'; break; */ case 'SUPER': $this->authSuperAdmin(); //$this->CURRENT_ROLE = 'Super Administrateur'; break; } } // authUser('login', 'Prenom', 'Nom'); // ex: $this->authUser('u1SUPER', 'user1', 'SUPER'); // ex: $this->authUser('user5_USER', 'test9', 'test0'); private function authUser($login, $givenName='test1', $name='test2') { $user = [ 'Auth' => [ 'User' => [ // Nom 'sn' => [ 0 => $name ], // Email (normalement prenom.nom@test.fr) 'mail' => [ 0 => 'testa@test.fr' ], // Prenom 'givenname' => [ 0 => $givenName ], // LOGIN (normalement epallier) /* 'cn' => [ 0 => $cn ], */ 'uid' => [ 0 => $login ], 'userpassword' => [ 0 => 'test' ] ] ] ]; $this->session($user); //$this->request->getSession()->write($user); $authType = [ 'authType' => 'cn' ]; $this->session($authType); //$this->request->getSession()->write($authType); (new UsersController())->statsUpdateForCurrentUserWhen($user['Auth']['User'],'sur login'); } public function authSuperAdmin() { //$this->authUser('login', 'Prenom', 'Nom'); $this->authUser('u1SUPER', 'user1', 'SUPER'); ///$this->authUser('user1_SUPER', 'user1', 'SUPER'); //$this->authUser('user1_SUPER', 'test1', 'test2'); //$this->authUser('testa', 'user1', 'SUPER'); } /* public function authSuperAdmin() { $user = [ 'Auth' => [ 'User' => [ 'sn' => [ 0 => 'test2' ], 'mail' => [ 0 => 'testa@test.fr' ], 'givenname' => [ 0 => 'test1' ], 'cn' => [ //0 => 'testa' 0 => 'user1_SUPER' ], 'userpassword' => [ 0 => 'test' ] ] ] ]; $this->session($user); $authType = [ 'authType' => 'cn' ]; $this->session($authType); } */ /* public function authAdminPlus() { /////$this->authUser('user2_ADMINPLUS', 'test3', 'test4'); $this->authUser('u2ADMINP', 'user2', 'ADMINP'); } */ /* $user = [ 'Auth' => [ 'User' => [ 'sn' => [ 0 => 'test4' ], 'mail' => [ 0 => 'testz@test.fr' ], 'givenname' => [ 0 => 'test3' ], 'cn' => [ //0 => 'testz' 0 => 'user2_ADMINPLUS' ], 'userpassword' => [ 0 => 'test' ] ] ] ]; $this->session($user); $authType = [ 'authType' => 'cn' ]; $this->session($authType); } */ public function dataProviderRoles2() { return $this->ROLES2; } public function authAdmin() { //////$this->authUser('user3_ADMIN', 'test5', 'test6'); $this->authUser('u3ADMIN', 'user3', 'ADMIN'); } /* $user = [ 'Auth' => [ 'User' => [ 'sn' => [ 0 => 'test6' ], 'mail' => [ 0 => 'teste@test.fr' ], 'givenname' => [ 0 => 'test5' ], 'cn' => [ //0 => 'teste' 0 => 'user3_ADMIN' ], 'userpassword' => [ 0 => 'test' ] ] ] ]; $this->session($user); $authType = [ 'authType' => 'cn' ]; $this->session($authType); } */ public function authResponsable() { ///////$this->authUser('user4_RESP', 'test7', 'test8'); $this->authUser('u4RESP', 'user4', 'RESP'); } /* $user = [ 'Auth' => [ 'User' => [ 'sn' => [ 0 => 'test8' ], 'mail' => [ 0 => 'testr@test.fr' ], 'givenname' => [ 0 => 'test7' ], 'cn' => [ //0 => 'testr' 0 => 'user4_RESP' ], 'userpassword' => [ 0 => 'test' ] ] ] ]; $this->session($user); $authType = [ 'authType' => 'cn' ]; $this->session($authType); } */ public function authUtilisateur() { $this->authUtilisateurFromTable(); } public function authUtilisateurFromTable() { /////$this->authUser('user5_USER', 'test9', 'test0'); $this->authUser('u5USER', 'user5', 'USER'); } public function authUtilisateurFromLdap() { //$this->authUser('_NouvelUtilisateur_username', 'NOUVEL', 'UTILISATEUR'); $this->authUser('_fake_ldap_user_', 'FAKE_LDAP', 'UTILISATEUR'); } /* $user = [ 'Auth' => [ 'User' => [ 'sn' => [ 0 => 'test0' ], 'mail' => [ 0 => 'testt@test.fr' ], 'givenname' => [ 0 => 'test9' ], 'cn' => [ //0 => 'testt' 0 => 'user5_USER' ], 'userpassword' => [ 0 => 'test' ] ] ] ]; $this->session($user); $authType = [ 'authType' => 'cn' ]; $this->session($authType); } */ //protected function assertResponseContainsIf($role, $condition, $content, $messageIfNot=null) { //protected function assertResponseContainsIf(string $role, bool $condition, array $contents, $testOpposite=true) { protected function assertResponseContainsIf($role, $condition, array $contents, $testOpposite=true) { if ($condition) { $messageOnFail = 'devrait avoir accès'; $assertMethod = 'assertResponseContains'; } else { if (!$testOpposite) return; $messageOnFail = 'ne devrait PAS avoir accès'; $assertMethod = 'assertResponseNotContains'; } foreach ($contents as $content=>$endmsg) $this->$assertMethod($content, "Le profil (rôle) $role $messageOnFail $endmsg"); /* $this->assertResponseContains($content, 'Le profil (rôle) '.$role.' devrait avoir accès à '. $messageIfNot); } else { $this->assertResponseNotContains($content, 'Le profil (rôle) '.$role.' ne devrait PAS avoir accès à '. $messageIfNot); } */ } // Test qu'on a bien le nb attendu d'entités dans la vue index protected function _testNbEntitiesInIndexView($entities_name, $nb_entities, $error_msg=null) { //$this->get('/emprunts/index'); $this->get("/$entities_name/index"); if (!$error_msg) $error_msg = "Le nombre des $entities_name dans la BD (tel qu'affiché par la vue index) devrait être de $nb_entities !"; $this->assertResponseContains("Liste des $entities_name ($nb_entities)", $error_msg); } // Ajout d'entités liées à un matériel, telles que suivis, emprunts, ou documents... protected function _testAddEntitiesRelatedToMateriel($entity_name, $nb_entities_in_fixture, $data) { $matos_created_id = 1; $matos_validated_id = 3; $entities_name = $entity_name.'s'; // Test qu'on a bien le nb d'entités de la fixture en BD $nb = $nb_entities_in_fixture; $this->_testNbEntitiesInIndexView($entities_name, $nb); /* //$this->get('/emprunts/index'); $this->get("/$entities_name/index"); $this->assertResponseContains("Liste des $entities_name ($nb)", "Le nombre initial (fixture) des $entities_name dans la BD devrait être de $nb !"); */ // Ajout d'une 1ère entité (matériel VALIDATED) => OK $data['materiel_id'] = $matos_validated_id; $this->assertTextEquals($data['materiel_id'], $matos_validated_id); //$this->post("/emprunts/add/$matos_validated_id", $data); $this->post("/$entities_name/add/$matos_validated_id", $data); $nb++; $this->_testNbEntitiesInIndexView($entities_name, $nb, "L'ajout d'un $entity_name (1) pour un materiel VALIDATED ne se fait pas correctement alors que ça devrait !"); return; /* $this->get("/$entities_name/index"); $this->assertResponseContains("Liste des $entities_name ($nb)", "L'ajout d'un $entity_name (1) pour un materiel VALIDATED ne se fait pas correctement alors que ça devrait !"); */ // Ajout d'une 2ème entité (matériel VALIDATED) => OK //$data['materiel_id'] = $matos_validated_id; //$this->assertTextEquals($data['materiel_id'], $matos_validated_id); $this->post("/$entities_name/add/$matos_validated_id", $data); $nb++; $this->_testNbEntitiesInIndexView($entities_name, $nb, "L'ajout d'un $entity_name (2) pour un materiel VALIDATED ne se fait pas correctement alors que ça devrait !"); /* $this->get("/$entities_name/index"); $this->assertResponseContains("Liste des $entities_name ($nb)", "L'ajout d'un $entity_name (2) pour un materiel VALIDATED ne se fait pas correctement alors que ça devrait !"); */ // Ajout d'une 3ème entité (matériel CREATED) => KO $data['materiel_id'] = $matos_created_id; $this->assertTextEquals($data['materiel_id'], $matos_created_id); $this->post("/$entities_name/add/$matos_created_id", $data); //$nb++; $this->_testNbEntitiesInIndexView($entities_name, $nb, "L'ajout d'un $entity_name (3) pour un materiel CREATED ne se fait pas correctement alors que ça ne devrait pas !"); /* $this->get("/$entities_name/index"); $this->assertResponseContains("Liste des $entities_name ($nb)", "L'ajout d'un $entity_name (3) pour un materiel CREATED se fait correctement alors que ça ne devrait pas !"); */ // Ajout d'une 4ème entité (matériel VALIDATED) => OK $data['materiel_id'] = $matos_validated_id; $this->assertTextEquals($data['materiel_id'], $matos_validated_id); $this->post("/$entities_name/add/$matos_validated_id", $data); $nb++; $this->_testNbEntitiesInIndexView($entities_name, $nb, "L'ajout d'un $entity_name (4) pour un materiel VALIDATED ne se fait pas correctement alors que ça devrait !"); /* $this->get("/$entities_name/index"); $this->assertResponseContains("Liste des $entities_name ($nb)", "L'ajout d'un $entity_name (4) pour un materiel VALIDATED ne se fait pas correctement alors que ça devrait !"); */ } // testAddEntitiesRelatedToMateriel protected function inflectEntityName($entities_name) { //$entities_name = strtolower($entities_name); switch ($entities_name) { case 'Materiel': $entities_name = 'Matériel'; break; case 'Materiels': $entities_name = 'Matériels'; break; case 'User': $entities_name = 'Utilisateur'; break; case 'Users': $entities_name = 'Utilisateurs'; break; case 'SurCategorie': $entities_name = 'Domaine'; break; case 'SurCategories': $entities_name = 'Domaines'; break; /* case 'materiel': $entities_name = 'matériel'; break; case 'materiels': $entities_name = 'matériels'; break; case 'user': $entities_name = 'utilisateur'; break; case 'users': $entities_name = 'utilisateurs'; break; case 'sur-categorie': $entities_name = 'domaine'; break; case 'sur-categories': $entities_name = 'domaines'; break; */ } // Par défaut, aucun changement (ex: 'suivis' => 'suivis') //return $entities_name; return lcfirst($entities_name); } protected function _checkNbEntitiesInIndexViewIsAsExpected($entities_name,$nbentities_expected) { //$this->get('/materiels/index'); //$entities_name = Inflector::dasherize($entities_name); //debug("entities1 $entities_name"); $this->get("/$entities_name/index"); //debug($_SESSION);return; $this->assertResponseOk(); $entities_name = $this->inflectEntityName($entities_name); //debug("entities2 $entities_name"); $this->assertResponseContains("Liste des $entities_name ($nbentities_expected)", "Le nombre d'entités dans la vue 'index' est incorrect"); } /** * * (EP 20200620) * * Test (automatique) de (presque) TOUTES les actions d'un controleur * * Appelé par chaque test de controleur en passant en paramètre $entities_name (et le reste par DataProvider) * * @return void * */ protected function _testAuthorizationsForAllControllerActions($action, $role_short, $role_long) { //protected function _testAuthorizationsForAllActionsOfController($entities_name, $action, $role_short, $role_long) { // Force le rechargement des entités materiel en BD (car on les modifie en cours de route) //AppController::forceReload(); $entities_name = $this->getEntitiesName(); //debug("entities0 $entities_name"); $IS_MATERIEL = ($entities_name=='Materiels'); //debug("entities_name is $entities_name"); /* //$controller_name = 'Materiels'; $controller_name = 'App\Controller\\'.$entities_name.'Controller'; //$mc = new MaterielsController(); $c = new $controller_name(); //$entity_name =$c->name; */ $c = $this->_getController(); // POUR CHAQUE $action et $role (fournis par le dataProvider) : $this->d("*******************"); //$this->d(" CONTROLEUR $c->name, ACTION $action, ROLE $role_short"); $this->d(" CONTROLEUR {$c->getName()}, ACTION $action, ROLE $role_short"); $this->d("*******************"); //$this->setUp(); //$this->authSuperAdmin(); $this->authAs($role_long); // NULL why ? //debug($_SESSION);return; $nbentities = $this->getNbEntitiesExpectedInIndexView(); // NULL why ? //debug($_SESSION);return; $this->_checkNbEntitiesInIndexViewIsAsExpected($entities_name, $nbentities); // pas NULL why ? //debug($_SESSION);return; // On recupère une entité quelconque de la BD (fixture), peu importe ce que c'est car on va la modifier $id = $this->_getEntityIdOkForTesting(); if (in_array($action, ['add','index'])) $id=null; // OU $id=0 ? $getpost = in_array($action, ['view', 'index', 'find', 'printLabelRuban']) ? 'get':'post'; $posted_data = []; if ($action=='add') $posted_data = $this->getNewEntityWithAllMandatoryFields(); // Si 'edit', on marque le materiel comme ayant été modifié (on change le nom) if ($action=='edit') { $e = $c->getEntity($id); $name_field = $c->getNameFieldLabel(); // On ajoute '(CHANGED)' à la fin du nom de l'entité pour vérifier ensuite qu'elle a bien été modifiée $posted_data = [ $name_field => $e->$name_field.' (CHANGED)' ]; } // Quel id pour le matos (associé) ? // Par défaut (pour MaterielsController) $matos_id et $id sont identiques (confondus) $matos_id = $id; $entities_related_to_materiel = ['Documents', 'Emprunts', 'Suivis']; // Entité associée à un matériel ? (Suivis, Emprunts, Documents...) //if (!$IS_MATERIEL && $action!='index') { if ( in_array($entities_name, $entities_related_to_materiel) && $action!='index' ) { //if ($action=='add') $related_matos_id = $this->getNewEntityWithAllMandatoryFields()->materiel_id; //$related_matos_id = $this->getMaterielsController()->_getEntityIdOkForTesting(); $actions_with_related_matos_id = ['add']; //if ($c->name == 'Documents') $actions_with_related_matos_id[] = ['admission','sortie']; if ($c->getName() == 'Documents') $actions_with_related_matos_id[] = ['admission','sortie']; if (in_array($action, $actions_with_related_matos_id)) { // id = celui du matos associé $id = MaterielsControllerTest::_getEntityIdOkForTesting(); if ($action == 'add') $posted_data['materiel_id'] = $id; $matos_id = $id; } else { // id = celui de l'entité (suivi, emprunt, document....) // matos_id = celui associé à l'entité $e = $this->_getController()->getEntity($id); if ($e->has('materiel_id')) $matos_id = $e->materiel_id; } } $access_condition = $c->getAccessConditionForActionAndRole($action,$role_short); //debug("Condition d'accès pour l'action $action et le rôle $role_short"); debug($access_condition); /* * * Test de l'accès à l'action : 3 GRANDS CAS POSSIBLES * */ // Force le rechargement des materiels car ils vont être modifiés par les tests AppController::forceReload(); /* if ($access_condition==='default') { debug("is default"); } */ // 1) ACCÈS AUTORISÉ if ($access_condition===0) { $this->d("is 0"); //if ($this->DEBUG) {debug($action); debug($id)}; $this->_testExecActionForId($action,$id,$getpost,$posted_data,true,$nbentities); } // 2) ACCÈS REFUSÉ elseif ($access_condition===-1) { $this->d("is -1"); $this->_testExecActionForId($action,$id,$getpost,$posted_data,false,$nbentities); } // 3) ACCÈS AUTORISÉ SOUS CONDITION // ATTENTION : toujours tester le cas où ca marche (AUTORISÉ) en dernier // Utile pour des actions telles que 'delete' !!! elseif (is_array($access_condition)) { $this->d("is array"); $access_condition_on_status = $access_condition[0]; $access_condition_on_belonging = $access_condition[1]; // 4 cas possibles : /* * a) [0,0] => idem cas 1) ci-dessus => accès autorisé (avec matos quelconque) */ //if ($access_condition_on_status===0 && $access_condition_on_belonging===0) { if ([$access_condition_on_status,$access_condition_on_belonging]===[0,0]) { $this->d("- is [0,0] => equivaut à 0"); $this->_testExecActionForId($action,$id,$getpost,$posted_data,true,$nbentities); } /* * b) [0,1] => on ne teste que l'appartenance, soit 2 tests : * - (1) on crée un materiel (T,F) => on teste que l'accès être bien AUTORISÉ * - (2) on crée un materiel (F,T) => on teste que l'accès être bien REFUSÉ, SAUF si le profil est RESP (AUTORISÉ) */ elseif ([$access_condition_on_status,$access_condition_on_belonging]===[0,1]) { $this->d("- is [0,1]"); //$m = $this->Materiels->get($id); // - (1) (T,F) $this->_updateMatosBelongingToCurrentUserAndInSameGroup($matos_id, true, false); $this->_testExecActionForId($action,$id,$getpost,$posted_data,true,$nbentities); // - (2) (F,T) $this->_updateMatosBelongingToCurrentUserAndInSameGroup($matos_id, false, true); // ok seulement pour RESP $this->_testExecActionForId($action,$id,$getpost,$posted_data,$this->USER_IS_RESP(),$nbentities); } /* * c) [*,0] => on ne teste que le statut, soit 2 tests : * - (1) on crée un matériel qui A le statut demandé => on teste que l'accès être bien AUTORISÉ * - (2) on crée un matériel qui n'A PAS le statut demandé => on teste que l'accès être bien REFUSÉ */ elseif (is_string($access_condition_on_status) && $access_condition_on_belonging===0) { $this->d("- is [*,0]"); //$m = $this->Materiels->get($id); // - (1) statut KO /* $this->_updateMatosWithStatusAs($id, $access_condition_on_status, false); $this->_testExecActionForId($action,$id,false); */ // - (2) statut OK $this->_updateMatosWithStatusAs($matos_id, $access_condition_on_status, true); $this->_testExecActionForId($action,$id,$getpost,$posted_data,true,$nbentities); } /* * d) [*,1] => Cas général, on teste les 2 conditions, soit 2x2=4 tests * Les 2 conditions (A-statut et B-appartenance) doivent être vérifiées : A && B (c'est un AND) * On va donc tester le couple (A,B), ce qui nous donne 3 cas : */ elseif (is_string($access_condition_on_status) && $access_condition_on_belonging===1) { $this->d("- is [*,1]"); //$m = $this->Materiels->get($id); // (1) (T,F) => accès REFUSÉ $this->d("(1 TF) should be KO"); $this->_updateMatosWithStatusAs($matos_id, $access_condition_on_status, true); $this->_updateMatosBelongingToCurrentUserAndInSameGroup($matos_id, false, false); $m = $this->Materiels->get($matos_id); $this->d("(1) id is $id, materiel (id, statut, nom_responsable, nom_createur) is : $m->id, $m->status, $m->nom_responsable, $m->nom_createur"); $this->_testExecActionForId($action,$id,$getpost,$posted_data,false,$nbentities); // (2) (F,T) => accès REFUSÉ $this->d("(2 FT) should be KO"); $this->_updateMatosWithStatusAs($matos_id, $access_condition_on_status, false); $this->_updateMatosBelongingToCurrentUserAndInSameGroup($matos_id, true, true); $m = $this->Materiels->get($matos_id); $this->d("(2) id is $id, materiel (id, statut, nom_responsable, nom_createur) is : $m->id, $m->status, $m->nom_responsable, $m->nom_createur"); $this->_testExecActionForId($action,$id,$getpost,$posted_data,false,$nbentities); // (3) (F,F) => accès REFUSÉ => inutile de tester ce cas // (4) (T,T) => accès AUTORISÉ $this->d("(3 TT) should be OK"); $this->_updateMatosWithStatusAs($matos_id, $access_condition_on_status, true); $this->_updateMatosBelongingToCurrentUserAndInSameGroup($matos_id, true, $this->USER_IS_RESP()); $m = $this->Materiels->get($matos_id); $this->d("(3) id is $id, materiel (id, statut, nom_responsable, nom_createur) is : $m->id, $m->status, $m->nom_responsable, $m->nom_createur"); $this->_testExecActionForId($action,$id,$getpost,$posted_data,true,$nbentities); } else throw new \ErrorException("La conditions d'accès $access_condition est incorrecte (1)"); } else throw new \ErrorException("La conditions d'accès $access_condition est incorrecte (2)"); } // testAuthorizationsForAllActionsOfController() protected function _updateMatosStatusAndBelongingWith($id, $status, $BELONGS=true, $SAMEGROUP=true) { $this->_updateMatosWithStatusAs($id, $status); $this->_updateMatosBelongingToCurrentUserAndInSameGroup($id, $BELONGS, $SAMEGROUP); } private function _updateMatosWithStatusAs($id, $status, $WITH_SAME_STATUS=true, $DO_SAVE=true) { //$mc = new MaterielsController(); $mc = $this->getMaterielsController(); $u = $this->getCurrentUser(); $m = $this->getMaterielsTable()->get($id); //$m = $this->getMateriel($id); //debug("statut:"); debug($status); $NOT = FALSE; // Statut commence par 'NOT' ? if (strpos($status,'NOT ') === 0) { $NOT = TRUE; // on prend le statut après le "NOT " : $status = substr($status,4); } // Condition de statut complexe ? (normalement de la forme "STATUS &&_ou_|| autre_condition") // => pour simplifier, on ne tient compte que du STATUS (donc le 1er argument) if ( (strpos($status,'&&')!==FALSE) || (strpos($status,'||')!==FALSE) ) { //debug("statut complexe '$status'"); $status = explode(' ', $status)[0]; //$status = $status[0]; //debug("=> simplifié en '$status'"); } //if ($mc->isStatus($status)) { if (! $mc->isStatus($status)) // On a un cas spécial, du style 'conf.hasPrinter' (sans statut avant, alors que ça pourrait être "VALIDATED && conf.hasPrinter") // Pour le moment, on ne le traite pas... //throw new \Exception("Le statut du matériel est incorrect !!!"); ; else { /* $m->status = $WITH_SAME_STATUS ? $status : $mc->getNextStatusFrom($status); if ($NOT) $m->status = $mc->getNextStatusFrom($status); */ // MEME statut (par défaut) ? $m->status = $status; //debug("bef: $m->status"); // ou STATUT différent ? if ( ($NOT && $WITH_SAME_STATUS) || (!$NOT && !$WITH_SAME_STATUS) ) $m->status = $mc->getNextStatusFrom($status); //debug("after: $m->status"); // On sauvegarde le matos modifié //if (! $this->Materiels->save($m)) //if ($DO_SAVE && !$this->getMaterielsTable()->save($m)) if ($DO_SAVE) if (! $this->getMaterielsTable()->save($m) ) throw new \Exception("La sauvegarde du materiel modifié ne se fait pas !!!"); //return $m; } //else throw new \Exception("Le statut du matériel est incorrect !!!"); return $m; } private function _updateMatosBelongingToCurrentUserAndInSameGroup($id, $BELONGS=true, $SAMEGROUP=true, $DO_SAVE=true) { $u = $this->getCurrentUser(); $m = $this->Materiels->get($id); // BELONGS ? $user_name = $BELONGS ? $u->nom : 'inconnu'; // 'user5 USER' $m->nom_responsable = $user_name; $m->nom_createur = $user_name; // SAME GROUP ? $WRONG_GROUP_ID = 2; $groupe_thematique_id = $SAMEGROUP ? $u->groupes_thematique_id : $WRONG_GROUP_ID; $groupe_metier_id = $SAMEGROUP ? $u->groupes_metier_id : $WRONG_GROUP_ID; $m->groupes_thematique_id = $groupe_thematique_id; $m->groupes_metier_id = $groupe_metier_id; //debug($matos); // On sauvegarde le matos modifié if ( $DO_SAVE && !$this->Materiels->save($m) ) throw new \Exception("La sauvegarde du materiel modifié ne se fait pas !!!"); return $m; } //private function _testExecActionForId($action,$id,$SHOULD_BE_SUCCESS) { private function _testExecActionForId($action,$id,$getpost,$posted_data,$SHOULD_BE_SUCCESS,$nbentities) { //debug($this->_flashMessages); //$entities = 'materiels'; //$entities_name = strtolower($this->getEntitiesName()); //$entities_name = Inflector::dasherize($this->getEntitiesName()); $entities_name = $this->getEntitiesName(); //$entities_name = $this->getEntitiesName(); //$IS_MATERIEL = ($entities_name=='materiels'); $IS_MATERIEL = ($entities_name=='Materiels'); //$getpost = in_array($action, ['add','add_by_copy','edit','delete', 'statusCreated']) ? 'post' : 'get'; //$getpost = in_array($action, ['view', 'index', 'find', 'printLabelRuban']) ? 'get':'post'; //$getpost = in_array($action, ['view', 'index', 'find']) ? 'get':'post'; //$this->post("/materiels/$action/$matos_id"); // Si 'add' ou 'index' => pas d'id //debug("0"); debug($_SESSION); //$data = ($action=='add') ? $this->newMaterielWithAllMandatoryFields : []; //$data = ($action=='add') ? $this->getNewEntityWithAllMandatoryFields() : []; /* $data = []; if ($action=='add') { $data = $this->getNewEntityWithAllMandatoryFields(); if ($entities_name != 'materiels') $data['materiel_id'] = $id; } */ $exec_action = $action; if ($action=='add_by_copy') $exec_action='add'; $full_action = "/$entities_name/$exec_action"; //if (! in_array($action, ['add', 'index'])) $full_action .= "/$id"; if (! ($action=='index' || ($action=='add' && $IS_MATERIEL)) ) $full_action .= "/$id"; $this->d("Execution action : \$this->$getpost($full_action, data); (avec data=)"); $this->d($posted_data); // GET if ($getpost=='get') $this->$getpost($full_action); // POST else $this->$getpost($full_action, $posted_data); /* if ($SUCCESS) $this->assertNoRedirect(); else $this->assertRedirect(); */ //$this->get('/materiels/view/2'); //$res = $this->_getBodyAsString(); //$res = $this->_getBodyAsString(); debug($res); //debug($this->_flashMessages); //debug($_SESSION); //debug($flash_message); // Normalement, l'action devrait avoir été autorisée if ($SHOULD_BE_SUCCESS) { $flash_message = null; $this->assertResponseSuccess(); //if ($entities_name=='materiels' && $action=='printLabelRuban') { if ($entities_name=='Materiels' && $action=='printLabelRuban') { /* $this->assertFileResponse('inventirap_label.label', 'pas de fichier généré'); $this->assertHeader('Content-type', 'application/xml'); $this->assertHeader('Content-Type', 'application/xml'); */ //var_dump($this->_getBodyAsString()); $filename = 'inventirap_label.label'; $this->assertHeader('Content-Disposition', 'attachment; filename="'.$filename.'"'); //$this->assertHeader('Content-Disposition', "attachment; filename='$filename'"); $msg_error = "L'action $action n'est pas autorisée (pour le role {$this->getUserRole()}) alors qu'elle devrait !!!"; // - DLS : /* $this->assertResponseContains("ContinuousLabel", $msg_error); $this->assertResponseContains("Landscape", $msg_error); */ // - DCD : $this->assertResponseContains("DYMOLabel", $msg_error); $this->assertResponseContains("19X7-TAPE BLACK/WHITE", $msg_error); // format 19mm $this->assertResponseContains("Landscape", $msg_error); } // GET if ($getpost == 'get') { $this->assertResponseOk(); $this->assertResponseNotEmpty(); $this->assertNoRedirect(); if (isset($_SESSION['Flash'])) { $flash_message = $_SESSION['Flash']; //$this->assertEquals([], $flash_message); } } // POST else { // Nom de l'entité au singulier et en minuscule $entity_name = substr($entities_name,0,-1); $entity_name = $this->inflectEntityName($entity_name); //if ($entity_name=='materiel') $entity_name='matériel'; $c = $this->_getController(); $article = $c->getArticle(); if ($entity_name=='domaine') $article='Le '; // "Le materiel/suivi/emprunt a bien été" $expected_flash_message = $article.$entity_name.' a bien été '; switch($action) { case 'add': case 'add_by_copy': $expected_flash_message .= 'ajouté'; // Vérifier la conséquence de l'action : 1 entité de plus //debug("entities_name4 is $entities_name"); $this->_checkNbEntitiesInIndexViewIsAsExpected($entities_name, $nbentities+1); break; case 'edit': $expected_flash_message .= 'modifié'; // Vérifier la conséquence de l'action : 1 entité de plus $e = $c->getEntity($id); $this->d("entity is"); $this->d($e); $name_field = $c->getNameFieldLabel(); $this->assertTrue(strpos($e->$name_field,'(CHANGED)')!==false, "L'entité n'a pas été modifiée (action 'edit')"); break; case 'delete': $expected_flash_message .= 'supprimé'; // Vérifier la conséquence de l'action : 1 entité de moins $this->_checkNbEntitiesInIndexViewIsAsExpected($entities_name, $nbentities-1); break; case 'statusCreated': $expected_flash_message .= 'rétrogradé au statut CREATED'; break; case 'statusValidated': $expected_flash_message .= 'validé'; break; case 'statusTobearchived': $expected_flash_message = "La sortie d'inventaire a bien été demandée"; break; case 'statusArchived': $expected_flash_message .= "archivé (sorti de l'inventaire)"; break; case 'setLabelIsPlaced': case 'setLabelIsNotPlaced': $verb = ($action=='setLabelIsPlaced') ? 'a' : "n'a pas"; $expected_flash_message = "Je prends note que l'étiquette $verb été collée sur le matériel"; break; } $flash_message = isset($_SESSION['Flash']) ? $_SESSION['Flash']['flash'][0]['message']:[]; //if ($flash_message==null) $flash_message = []; } $this->d("(2) action $action, flash is:");$this->d($flash_message); /* * Test flash message * (https://book.cakephp.org/3/en/development/testing.html#testing-flash-messages) * * If you want to assert the presence of flash messages in the session and not the rendered HTML, * you can use enableRetainFlashMessages() in your tests * to retain flash messages in the session so you can write assertions : * * $this->enableRetainFlashMessages(); */ if ($flash_message) { // Assert a flash message in the 'flash' key. // Test message partiel $this->assertTrue(strpos($flash_message, $expected_flash_message) === 0, "Le message flash est incorrect : ($flash_message) au lieu de ($expected_flash_message)"); // Test message complet $this->assertFlashMessage($expected_flash_message, 'flash'); //$this->assertEquals($expected_flash_message, $flash_message); } //$this->assertResponseContains("Matos Test 2 (C)", "L'action $action n'est pas autorisée (pour le role {$this->getUserRole()}) !!!"); // BUG !!!! pourquoi ça marche avec l'action 'view' ??? //$this->assertResponseContains("Désolé, vous n'êtes pas autorisé à accéder à cette zone", "(2)L'action $action n'est pas autorisée (pour le role {$this->getUserRole()}) !!!"); //$this->assertResponseNotContains("Désolé, vous n", "L'action $action n'est pas autorisée (pour le role {$this->getUserRole()}) alors qu'elle le devrait !"); } // Normalement, l'action devrait avoir été refusée else { // 1) Assert redirect //$this->assertRedirect(['controller' => 'Users', 'action' => 'login']); //$this->assertRedirect(['controller' => 'Pages', 'action' => 'home']); //$this->assertResponseSuccess(); $this->assertResponseEmpty(); //if (!in_array($action,['add_by_copy'])) $this->assertResponseEmpty(); //if ($getpost == 'get') $this->assertRedirect('/'); if (!in_array($action,['edit','delete'])) $this->assertRedirect('/'); // 2) Assert Flash error message (flash message in the 'flash' key) // Assert a flash messages uses the error element $this->assertFlashElement('Flash/error'); $expected_flash_message = "Désolé, vous n'êtes pas autorisé à accéder à cette zone."; //var_dump($flash_message); // Test message complet $this->assertFlashMessage($expected_flash_message, 'flash'); $this->assertSession($expected_flash_message, 'Flash.flash.0.message'); $flash_message = $_SESSION['Flash']['flash'][0]['message']; $this->assertEquals($expected_flash_message, $flash_message); //$this->assertTrue(strpos($flash_message, "Désolé, vous n'êtes pas") !== false); $this->assertTrue(strpos($flash_message, "Désolé, vous n'êtes pas") === 0); // BUG !!! why ??? //$this->assertResponseContains("Désolé", "L'action $action est autorisée (pour le role {$this->getUserRole()}) alors qu'elle ne le devrait pas !"); } } // _testExecActionForId() /* * Test générique de l'action delete (appelé par chaque controleur de test) */ protected function _testActionDeleteEntity($role) { $action = 'delete'; //$entities_name = strtolower($this->getEntitiesName()); $entities_name = $this->getEntitiesName(); $this->d("*******************"); $this->d(" CONTROLEUR $entities_name, ACTION $action, ROLE $role"); $this->d("*******************"); $this->authAs($role); $nbentities = $this->getNbEntitiesExpectedInIndexView(); $this->_checkNbEntitiesInIndexViewIsAsExpected($entities_name, $nbentities); $id = $this->_getEntityIdOkForTesting(); $this->post("$entities_name/delete/$id"); $nbentities--; $this->_checkNbEntitiesInIndexViewIsAsExpected($entities_name, $nbentities); } }