From 8916ced0310cea63a171a30ef157b9a71bf1e887 Mon Sep 17 00:00:00 2001 From: xdrm-brackets Date: Wed, 20 Sep 2017 13:38:35 +0200 Subject: [PATCH] [kahlan:api/core/Request] tests + fixed Request --- build/api/core/Request.php | 86 +++++---- spec/build/api/core/RequestSpec.php | 281 ++++++++++++++++++++++++++++ 2 files changed, 332 insertions(+), 35 deletions(-) create mode 100644 spec/build/api/core/RequestSpec.php diff --git a/build/api/core/Request.php b/build/api/core/Request.php index 8a05a23..f908680 100644 --- a/build/api/core/Request.php +++ b/build/api/core/Request.php @@ -12,7 +12,7 @@ class Request{ // Constantes - private static function config_path(){ return __ROOT__.'/config/modules.json'; } + public static function config_path(){ return __ROOT__.'/config/modules.json'; } private static $default_options = [ 'download' => false ]; @@ -40,67 +40,90 @@ * @path Chemin de delegation ("module/methode") * @param Tableau associatif contenant les parametres utiles au traitement * - * @return status Retourne si oui ou non tout s'est bien passe + * @return instance Instance crée * */ public function __construct($path=null, $params=null){ + return $this->buildRequestObject($path, $params); + + } + + + + /* CONSTRUCTEUR D'UNE REQUETE DE MODULE (DELEGATION) + * + * @path Chemin de delegation ("module/methode") + * @param Tableau associatif contenant les parametres utiles au traitement + * + * @return status Retourne si oui ou non tout s'est bien passe + * + */ + private function buildRequestObject($path=null, $params=null){ /* [1] Initialisation =========================================================*/ /* (1) Erreur par défaut */ $this->error = new Error(Err::Success); /* (2) Si pas parametre manquant, on quitte */ - if( $path == null ){ - $this->error->set(Err::MissingPath); - return false; - } + if( $path == null ) + return $this->error->set(Err::MissingPath); /* [2] On met a jour la configuration =========================================================*/ - /* (1) Section Title */ - $this->modules = json_decode( file_get_contents(self::config_path()), true ); + /* (1) Vérification existence fichier config */ + if( !file_exists(self::config_path()) ) + return $this->error->set(Err::UnreachableResource); - /* (2) Gestion de l'erreur de parsage */ - if( $this->modules == null ){ - $this->error->set(Err::ParsingFailed, 'json'); - return false; - } + /* (2) Lecture fichier config */ + $conf = @file_get_contents(self::config_path()); + + /* (3) Si erreur lecture */ + if( $conf === false ) + return $this->error->set(Err::UnreachableResource); + + /* (4) Parsage json */ + $this->modules = json_decode( $conf, true ); + + /* (5) Gestion de l'erreur de parsage */ + if( $this->modules == null ) + return $this->error->set(Err::ParsingFailed, 'json'); /* [3] Verification des types des parametres =========================================================*/ - /* (1) Section Title */ - if( !is_string($path) ){ // Si le type est incorrect - $this->error->set(Err::WrongPathModule); - return false; // On retourne FALSE, si erreur - } + /* (1) Si path est une */ + if( !is_string($path) ) // Si le type est incorrect + return $this->error->set(Err::WrongPathModule); - /* (2) Section Title */ + /* (2) Formattage @params en tableau */ $params = (is_array($params)) ? $params : []; /* (3) On définit en constante la méthode HTTP */ + if( !isset($_SERVER['REQUEST_METHOD']) ) + return $this->error->set(Err::UnknownHttpMethod); + $this->http_method = strtoupper($_SERVER['REQUEST_METHOD']); /* [4] Verification du chemin (existence module+methode) =========================================================*/ if( !$this->checkPath($path) ) // Verification de la coherence du chemin + attribution - return false; + return false; // checkPath() sets the error itself /* [5] Verification des droits =========================================================*/ if( !$this->checkPermission() ) // Si on a pas les droits - return false; + return false; // checkPermission() sets the error itself /* [6] Verification des parametres (si @type est defini) =========================================================*/ if( !$this->checkParams($params) ) // Verification de tous les types - return false; + return false; // checkParams() sets the error itself /* [7] Récupèration des options @@ -115,7 +138,6 @@ $this->error->set(Err::Success); return true; // On retourne que tout s'est bien passe - } @@ -401,10 +423,8 @@ private function checkPath($path){ /* [1] Verification format general =========================================================*/ - if( !preg_match('#^([\w_-]+)/([\w_-]+)$#i', $path, $matches) ){ // Si mauvais format - $this->error->set(Err::WrongPathModule); - return false; - } + if( !preg_match('@^([\w_-]+)/([\w_-]+)$@i', $path, $matches) ) // Si mauvais format + return $this->error->set(Err::WrongPathModule); // On recupere les données de la regex $module = $matches[1]; @@ -413,18 +433,14 @@ /* [2] Verification de l'existence du module (conf) =========================================================*/ - if( !array_key_exists($module, $this->modules) ){ // Si le module n'est pas specifie dans la conf - $this->error->set(Err::UnknownModule, $module); - return false; // On retourne FALSE, si erreur - } + if( !array_key_exists($module, $this->modules) ) // Si le module n'est pas specifie dans la conf + return $this->error->set(Err::UnknownModule, $module); /* [3] Verification de l'existence de la methode (conf) =========================================================*/ - if( array_key_exists($method, $this->modules[$module]) === false ){ // Si la methode n'est pas specifie dans la conf - $this->error->set(Err::UnknownMethod, preg_replace('/\w+::/i', '', $method) ); - return false; // On retourne FALSE, si erreur - } + if( array_key_exists($method, $this->modules[$module]) === false ) // Si la methode n'est pas specifie dans la conf + return $this->error->set(Err::UnknownMethod, preg_replace('/\w+::/i', '', $method) ); diff --git a/spec/build/api/core/RequestSpec.php b/spec/build/api/core/RequestSpec.php new file mode 100644 index 0000000..bcc5028 --- /dev/null +++ b/spec/build/api/core/RequestSpec.php @@ -0,0 +1,281 @@ + 'POST' + ]; + }); + + describe('[check] config file', function(){ + + it('pass when config file exists', function(){ + + expect( file_exists(Request::config_path()) )->toBeTruthy(); + + }); + + it('pass when we can read the config file', function(){ + + expect( @file_get_contents(Request::config_path()) )->not->toBe(false); + + }); + + it('pass when the config file is valid json', function(){ + + $read = @file_get_contents(Request::config_path()); + expect($read)->not->toBe(false); + expect( json_decode($read, true) )->not->toBeNull(); + expect( json_decode($read, true) )->toBeA('array'); + + }); + + }); + + describe('__construct(@path, @params)', function(){ + + context('with argument combinations', function(){ + + it('fail if @path is missing', function(){ + + $req = new Request(); + + expect($req->error->get())->toBe(Err::MissingPath); + + }); + + it('fail if @path is not a string', function(){ + + expect('is_string')->toBeCalled(); + $req = new Request(1); + + expect($req->error->get())->toBe(Err::WrongPathModule); + + }); + + it('pass if @params is an array', function(){ + + unset($_SERVER); + expect('is_array')->toBeCalled(); + + $req = new Request('someString', ['a', 'b']); + + expect($req->error->get())->toBe(Err::UnknownHttpMethod); + + }); + + it('pass if @params is not an array (default: [])', function(){ + + unset($_SERVER); + + expect('is_array')->toBeCalled(); + + $types = [true, false, null, 1, 2.3, -1.2, 0, 'blabla']; + + foreach($types as $type){ + + $req = new Request('someString', true); + expect($req->error->get())->toBe(Err::UnknownHttpMethod); + + } + + }); + + }); + + + context('with config errors', function(){ + + it('fail if the config file exists', function(){ + + // Request::config_path -> 'aa' + allow(Request::class)->toReceive('::config_path')->andReturn('invalid_fname'); + expect(Request::config_path())->toBe('invalid_fname'); + + // file_exists -> false + allow('file_exists')->toBeCalled()->andReturn(false); + expect('file_exists')->toBeCalled(); + + $req = new Request('a/b'); + + expect($req->error->get())->toBe(Err::UnreachableResource); + + }); + + it('fail if the config file cannot be read', function(){ + + // file_get_contents -> false + allow('file_get_contents')->toBeCalled()->andReturn(false); + expect('file_get_contents')->toBeCalled(); + + $req = new Request('a/b'); + + expect($req->error->get())->toBe(Err::UnreachableResource); + + }); + + it('fail if the json format is not valid', function(){ + + // file_exists -> true + allow('file_exists')->toBeCalled()->andReturn(true); + expect('file_exists')->toBeCalled(); + + // file_get_contents -> false + allow('file_get_contents')->toBeCalled()->andReturn('{incorrect_json'); + expect('file_get_contents')->toBeCalled(); + + // json_decode -> called + expect('json_decode')->toBeCalled(); + + $req = new Request('a/b'); + + expect($req->error->get())->toBe(Err::ParsingFailed); + + }); + + }); + + context('with checks errors', function(){ + + it('fail with checkPath() fails', function(){ + + allow(Request::class)->toReceive('checkPath')->andRun(function(){ + $this->error->set(Err::UnknownError); + return false; + }); + + $req = new Request('a/b'); + + expect($req->error->get())->toBe(Err::UnknownError); + + }); + + it('fail with checkPermission() fails', function(){ + + // bypass checkPath(); + allow(Request::class)->toReceive('checkPath')->andReturn(true); + + allow(Request::class)->toReceive('checkPermission')->andRun(function(){ + $this->error->set(Err::UnknownError); + return false; + }); + + $req = new Request('a/b'); + + expect($req->error->get())->toBe(Err::UnknownError); + + }); + + it('fail with checkParams() fails', function(){ + + // bypass checkPath(); + checkPermission(); + allow(Request::class)->toReceive('checkPath')->andReturn(true); + allow(Request::class)->toReceive('checkPermission')->andReturn(true); + + allow(Request::class)->toReceive('checkParams')->andRun(function(){ + $this->error->set(Err::UnknownError); + return false; + }); + + $req = new Request('a/b'); + + expect($req->error->get())->toBe(Err::UnknownError); + + }); + + it('pass with all checks ok', function(){ + + // bypass all checks + allow(Request::class)->toReceive('checkPath')->andReturn(true); + allow(Request::class)->toReceive('checkPermission')->andReturn(true); + allow(Request::class)->toReceive('checkParams')->andReturn(true); + + // bypass buildOptions(); + allow(Request::class)->toReceive('buildOptions')->andReturn(true); + + $req = new Request('a/b'); + + expect($req->error->get())->toBe(Err::Success); + + }); + + }); + + }); + + + describe('checkPath(@path)', function(){ + + it('fail when wrong path format: \'module/method\'', function(){ + + $values = ['a-b', 'a /b', 'a/b ']; + + foreach($values as $value){ + + $req = new Request($value); + expect($req->error->get())->toBe(Err::WrongPathModule); + + } + + }); + + it('pass when valid path format: letter/number/-/_', function(){ + + $values = ['a_b-c/d-e_f', 'abc/def', '_a_/_b_']; + + foreach($values as $value){ + + $req = new Request($value); + expect($req->error->get())->not->toBe(Err::WrongPathModule); + + } + + }); + + it('fail when unknown module', function(){ + + allow('json_decode')->toBeCalled()->andReturn([ + 'mo-du_leA' => [], + 'moduleB' => [] + ]); + + $values = ['modulea/method', 'MODULEA/method', 'moduleC/method']; + + foreach($values as $value){ + + $req = new Request($value); + expect($req->error->get())->toBe(Err::UnknownModule); + + } + + }); + + it('fail when unknown method', function(){ + + allow('json_decode')->toBeCalled()->andReturn([ + 'mo-du_leA' => [ 'POST::me-th_odA' => [] ], + 'moduleB' => [] + ]); + + $values = ['mo-du_leA/me-thodA', 'mo-du_leA/meth_odA', 'mo-du_leA/me-th_oda']; + + foreach($values as $value){ + + $req = new Request($value); + expect($req->error->get())->toBe(Err::UnknownMethod); + + } + + }); + + }); + + }); \ No newline at end of file