From 0696942ad2756e05abc56ab3f102786adc689445 Mon Sep 17 00:00:00 2001
From: efalcy <stl@gresille.org>
Date: Thu, 12 Jun 2014 18:56:30 +0200
Subject: [PATCH] dev #1278 autoupdate cosmogramme script : migrate in opac
 (add controller and tag)

---
 .../DatabaseMigrationController.php           |  34 ++++
 .../scripts/database-migration/migrate.phtml  |   4 +
 console.php                                   |  15 +-
 cosmogramme/php/upgrade_db.php                | 106 +------------
 library/Class/Migration/Patchs.php            | 147 ++++++++++++++++++
 library/Class/Migration/ScriptPatchs.php      |  70 +++++++++
 library/Class/Systeme/Include.php             |  41 +++++
 library/Class/Testing/FileSystem.php          |   2 +-
 library/ZendAfi/View/Helper/TagMigration.php  |  99 ++++++++++++
 tests/library/Class/MigrationTest.php         | 141 +++++++++++++++++
 10 files changed, 553 insertions(+), 106 deletions(-)
 create mode 100644 application/modules/opac/controllers/DatabaseMigrationController.php
 create mode 100644 application/modules/opac/views/scripts/database-migration/migrate.phtml
 create mode 100644 library/Class/Migration/Patchs.php
 create mode 100644 library/Class/Migration/ScriptPatchs.php
 create mode 100644 library/Class/Systeme/Include.php
 create mode 100644 library/ZendAfi/View/Helper/TagMigration.php
 create mode 100644 tests/library/Class/MigrationTest.php

diff --git a/application/modules/opac/controllers/DatabaseMigrationController.php b/application/modules/opac/controllers/DatabaseMigrationController.php
new file mode 100644
index 00000000000..c3caa268a08
--- /dev/null
+++ b/application/modules/opac/controllers/DatabaseMigrationController.php
@@ -0,0 +1,34 @@
+<?php
+/**
+ * Copyright (c) 2012-2014, Agence Française Informatique (AFI). All rights reserved.
+ *
+ * AFI-OPAC 2.0 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.
+ *
+ * There are special exceptions to the terms and conditions of the AGPL as it
+ * is applied to this software (see README file).
+ *
+ * AFI-OPAC 2.0 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 AFI-OPAC 2.0; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA 
+ */
+
+
+class DatabaseMigrationController extends Zend_Controller_Action {
+	public function init() {
+//		$this->getHelper('ViewRenderer')->setNoRender();
+	}
+
+	public function migrateAction() {
+		xdebug_break();
+		$this->view->reprise=$this->_request->getParam('reprise',0);
+		$this->view->skip_php=$this->_request->getParam('skip_php',0);
+	}
+}
+?>
\ No newline at end of file
diff --git a/application/modules/opac/views/scripts/database-migration/migrate.phtml b/application/modules/opac/views/scripts/database-migration/migrate.phtml
new file mode 100644
index 00000000000..4562336cd6f
--- /dev/null
+++ b/application/modules/opac/views/scripts/database-migration/migrate.phtml
@@ -0,0 +1,4 @@
+<?php
+$this->tagMigration($this->reprise);
+
+?>
diff --git a/console.php b/console.php
index a16e66b8bed..7bbaad74b75 100644
--- a/console.php
+++ b/console.php
@@ -19,6 +19,19 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA 
  */
 
-require('includes.php');
+$base_path = realpath(dirname(__FILE__));
+set_include_path($base_path . '/library' . PATH_SEPARATOR .
+								 $base_path . '/library/storm/src' . PATH_SEPARATOR .
+								 $base_path . '/library/storm/zf/library' . PATH_SEPARATOR .
+								 get_include_path());
+
+define("BASE_URL", "/");
+
+include_once "local.php";
+include_once "fonctions/fonctions.php";
+require_once "Zend/Loader.php";
+require_once "library/startup.php";
+
 setupOpac();
+
 ?>
\ No newline at end of file
diff --git a/cosmogramme/php/upgrade_db.php b/cosmogramme/php/upgrade_db.php
index b1a00dccf6d..c097913038f 100644
--- a/cosmogramme/php/upgrade_db.php
+++ b/cosmogramme/php/upgrade_db.php
@@ -7,109 +7,7 @@ require_once 'classes/classe_cosmopaths.php';
 $cosmo_path = new CosmoPaths();
 define('BASE_URL', $cosmo_path->getBaseUrl());
 
-require_once($basePath.'/../storm_init.php');
-
-$sql = Zend_Registry::get('sql');
-$patch_level = Class_CosmoVar::find("patch_level");
-
-function versionForFile($file) {
-	return (int)substr($file, -7, 3);
-}
-
-function extensionForFile($file) {
-	return substr($file, -4);
-}
-
-// Recup des patches a executer
-$path = realpath(dirname(__FILE__)).'/../sql/patch/';
-$handle = @opendir($path);
-if (!$handle) 
-	echo('Impossible d\'ouvrir le dossier : '.$path);
-
-$scripts = [];
-while (false !== ($fic = readdir($handle))) {
-	if (!in_array(extensionForFile($fic), ['.sql', '.php']))
-		continue;
-	$numero = versionForFile($fic);
-	if ($numero > $patch_level->getValeur()) 
-		$scripts[] = $path . $fic;
-}
-
-sort($scripts);
-closedir($handle);
-
-foreach($scripts as $script) {
-	$num_patch = versionForFile($script);
-	echo('Execution patch n° ' . $num_patch );
-		
-	switch(extensionForFile($script)) {
-	case '.php':
-		runPhpUpgrade($script);break;
-	case '.sql':
-		runSqlUpgrade($script, $sql);break;
-	}
-
-	// Ecrire le patch dans la base
-	$patch_level->setValeur($num_patch)->save();
-}
-echo('Mise à niveau de la base effectuée avec succès');
-exit;
-
-function runSqlUpgrade($script, $sql) {
-	$num_instruction = 0;
-	$data = file($script);
-
-	$instructions = [];
-	$contents = implode(' ', $data);
-	if (false !== strpos($contents, 'CREATE FUNCTION')) 
-		$instructions[] = $contents;
-	else {
-		$instruction = '';
-		foreach($data as $ligne) {
-			$ligne = trim($ligne);
-			if (!$ligne or substr($ligne,0,2)=="--") continue;
-				
-			$instruction.=$ligne.' ';
-			if(substr($ligne,-1)!=";")
-				continue;
-
-			$instructions[] = $instruction;
-			$instruction = '';
-		}
-	}
-
-
-	foreach($instructions as $instruction) {
-		echo($instruction."\n");
-		flush();
-		// Executer
-		$num_instruction++;
-
-		$sql->execute($instruction);
-
-	}
-}
-
-function runPhpUpgrade($script) {
-
-	set_error_handler(
-		function($no, $message, $file, $line, $context) {
-			echo('Erreur :'.$message 
-						. " \nfile : " . $file 
-						. " \nline : " . $line
-						);
-			die(255);
-		});
-
-	try {
-		include $script;
-	} catch (Exception $e) {
-		echo("Code : ".$e->getCode()."\n");
-		echo("Erreur :".$e->getMessage());
-
-		exit;
-	}
-}
-
 
+require_once($basePath.'/../storm_init.php');
+		(new Class_Migration_ScriptPatchs())->run();
 ?>
\ No newline at end of file
diff --git a/library/Class/Migration/Patchs.php b/library/Class/Migration/Patchs.php
new file mode 100644
index 00000000000..48680a97d9e
--- /dev/null
+++ b/library/Class/Migration/Patchs.php
@@ -0,0 +1,147 @@
+<?php
+/**
+ * Copyright (c) 2012-2014, Agence Française Informatique (AFI). All rights reserved.
+ *
+ * AFI-OPAC 2.0 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.
+ *
+ * There are special exceptions to the terms and conditions of the AGPL as it
+ * is applied to this software (see README file).
+ *
+ * AFI-OPAC 2.0 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 AFI-OPAC 2.0; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA 
+ */
+
+
+class Class_Migration_Patchs {
+	use Trait_StaticFileSystem;
+	const PATCH_PATH="./cosmogramme/sql/patch";
+	public $force=false;
+	function extensionForFile($file) {
+		return substr($file, -4);
+	}
+
+	function setForce($force) {
+		$this->force=$force;
+		return $this;
+	}
+	
+
+	function versionForFile($filename) {
+		return  (int)preg_replace('/.*\/patch_(.*)\.(php|sql)/', '\1', $filename);
+	}
+
+	public function getLastPatchNumber() {
+		$ids=[];
+		foreach (self::getFileSystem()->glob(self::PATCH_PATH."/patch_*") as $filename) {
+			$ids[]=$this->versionForFile($filename);
+		}
+		if (empty($ids))
+			return 0;
+		rsort($ids);
+		return $ids[0];
+	}
+
+	public function getMatchingPatchFiles($patch_level) {
+		$scripts=[];
+		foreach (self::getFileSystem()->glob(self::PATCH_PATH."/patch_*") as $filename) {
+			if (!in_array($this->extensionForFile($filename), ['.sql', '.php']))
+				continue;
+			$numero = $this->versionForFile($filename);
+			if ($numero > (int)$patch_level) 
+				$scripts[] = $filename;
+		}
+		sort($scripts);
+		return $scripts;
+	}
+
+
+	public function acceptVisitor($visitor) {
+		$basePath = dirname(realpath(__FILE__));
+	
+		$patch_level = Class_CosmoVar::find("patch_level");
+		$visitor->visitHeader($patch_level,$this->getLastPatchNumber());
+// Recup des patches a executer
+		$ok=true;
+		foreach($this->getMatchingPatchFiles($patch_level->getValeur()) as $script) {
+			$num_patch = $this->versionForFile($script);
+			echo('Execution patch n° ' . $num_patch );
+		
+			switch($this->extensionForFile($script)) {
+			case '.php':
+				$this->runPhpUpgrade($script,$visitor);break;
+			case '.sql':
+				$ok=$this->runSqlUpgrade($script, $visitor);break;
+			}
+			if ($ok) $patch_level->setValeur($num_patch)->save();
+			else return;
+		}
+		echo('Mise à niveau de la base effectuée avec succès');
+
+	}
+
+	
+	function runPhpUpgrade($script,$visitor) {
+		if ($visitor->visitIsForceUpgrade()) 
+			return ;
+		$visitor->visitPhpUpgrade($script);
+	}
+
+
+	function runSqlUpgrade($script,$visitor) {
+		xdebug_break();
+		$num_instruction = 0;
+		$data = self::getFileSystem()->file($script);
+
+		$instructions = [];
+		$contents = implode(' ', $data);
+		if (false !== strpos($contents, 'CREATE FUNCTION')) 
+			$instructions[] = $contents;
+		else {
+			$instruction = '';
+			foreach($data as $ligne) {
+				$ligne = trim($ligne);
+				if (!$ligne or substr($ligne,0,2)=="--") continue;
+				
+				$instruction.=$ligne.' ';
+				if(substr($ligne,-1)!=";")
+					continue;
+
+				$instructions[] = $instruction;
+				$instruction = '';
+			}
+		}
+
+		
+		foreach($instructions as $instruction) {
+			flush();
+			// Executer
+			$num_instruction++;
+
+			if ($visitor->visitSqlSkip())
+				continue;
+			try {
+				$sql = Zend_Registry::get('sql');
+				$sql->execute($instruction);
+
+			} catch(Exception $e)	{
+				$visitor->visitSqlException($e,$num_instruction);
+				if (!$this->force)
+					return false;
+			}
+		}
+				
+	
+		return true;
+	}
+
+
+}
+?>
\ No newline at end of file
diff --git a/library/Class/Migration/ScriptPatchs.php b/library/Class/Migration/ScriptPatchs.php
new file mode 100644
index 00000000000..bc2e3e0cdb1
--- /dev/null
+++ b/library/Class/Migration/ScriptPatchs.php
@@ -0,0 +1,70 @@
+<?php
+/**
+ * Copyright (c) 2012-2014, Agence Française Informatique (AFI). All rights reserved.
+ *
+ * AFI-OPAC 2.0 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.
+ *
+ * There are special exceptions to the terms and conditions of the AGPL as it
+ * is applied to this software (see README file).
+ *
+ * AFI-OPAC 2.0 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 AFI-OPAC 2.0; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA 
+ */
+
+
+class Class_Migration_ScriptPatchs {
+
+	public function run($force=false) {
+		$this->migration=(new Class_Migration_Patchs());
+		$this->migration->setForce($force)->acceptVisitor($this);
+	}
+
+ 	public function visitPhpUpgrade($script) {
+		set_error_handler(
+			function($no, $message, $file, $line, $context) {
+				echo('Erreur :'.$message 
+						 . " \nfile : " . $file 
+						 . " \nline : " . $line
+					);
+				die(255);
+			});
+
+		try {
+			Class_Systeme_Include::getInstance()->include_file($script);
+		} catch (Exception $e) {
+			echo("Code : ".$e->getCode()."\n");
+			echo("Erreur :".$e->getMessage());
+		
+			exit;
+		}
+
+	}
+
+ 	public function visitHeader($patch_level) {
+	}
+
+	public function visitDisplayInstruction($instruction) {
+		echo($instruction."\n");
+	}
+
+	public function visitSqlSkip() {
+		return false;
+	}
+	public function visitSqlException($e,$num_instruction) {
+			echo("Code : ".$e->getCode()."\n");
+			echo("Erreur :".$e->getMessage());
+	}
+
+	public function visitIsForceUpgrade() {
+		return $this->force;
+	}
+}
+?>
\ No newline at end of file
diff --git a/library/Class/Systeme/Include.php b/library/Class/Systeme/Include.php
new file mode 100644
index 00000000000..45d1f81d171
--- /dev/null
+++ b/library/Class/Systeme/Include.php
@@ -0,0 +1,41 @@
+<?php
+/**
+ * Copyright (c) 2012, Agence Française Informatique (AFI). All rights reserved.
+ *
+ * AFI-OPAC 2.0 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.
+ *
+ * There are special exceptions to the terms and conditions of the AGPL as it
+ * is applied to this software (see README file).
+ *
+ * AFI-OPAC 2.0 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 AFI-OPAC 2.0; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA 
+ */
+class Class_Systeme_Include {
+	protected static $_instance;
+
+	public static function setInstance($instance) {
+		static::$_instance = $instance;
+	}
+
+
+	public static function getInstance() {
+		if (!isset(static::$_instance))
+			static::$_instance = new self();
+		return static::$_instance;
+	}
+
+
+	public function include_file($file_path) {
+		include $file_path;
+	}
+}
+
+?>
diff --git a/library/Class/Testing/FileSystem.php b/library/Class/Testing/FileSystem.php
index 2db688b67ef..f62030d7550 100644
--- a/library/Class/Testing/FileSystem.php
+++ b/library/Class/Testing/FileSystem.php
@@ -23,7 +23,7 @@ class Class_Testing_FileSystem {
 	protected $_known_functions = ['rmdir', 'unlink', 'fopen', 'fseek', 'fgets',
 																 'filesize', 'fclose', 'ftell', 'fread', 'feof',
 																 'getcwd', 'file_exists', 'scandir', 'is_dir',
-																 'opendir', 'readdir', 'closedir', 'mkdir'];
+																 'opendir', 'readdir', 'closedir', 'mkdir','glob','file'];
 	
 	public function __call($name, $args) {
 		if (!in_array($name, $this->_known_functions))
diff --git a/library/ZendAfi/View/Helper/TagMigration.php b/library/ZendAfi/View/Helper/TagMigration.php
new file mode 100644
index 00000000000..1c9028cc385
--- /dev/null
+++ b/library/ZendAfi/View/Helper/TagMigration.php
@@ -0,0 +1,99 @@
+<?php
+/**
+ * Copyright (c) 2012-2014, Agence Française Informatique (AFI). All rights reserved.
+ *
+ * AFI-OPAC 2.0 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.
+ *
+ * There are special exceptions to the terms and conditions of the AGPL as it
+ * is applied to this software (see README file).
+ *
+ * AFI-OPAC 2.0 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 AFI-OPAC 2.0; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA 
+ */
+
+
+class ZendAfi_View_Helper_TagMigration extends Zend_View_Helper_HtmlElement {
+	protected $reprise;
+	protected $skip_php;
+	public  function tagMigration($reprise=false,$skip_php=false) {
+		$this->reprise=$reprise;
+		$this->skip_php=$skip_php;
+		(new Class_Migration_Patchs())->acceptVisitor($this);
+		
+	}
+ 	public function visitHeader($patch_level,$last_patch) {
+		print '<h1>Mise à niveau de la base de données</h1>';
+		print('<h3>Niveau de patch : ' . $patch_level->getValeur() . ' / ' . $last_patch . '</h3>');
+	}
+
+
+	public function visitPhpUpgrade($script) {
+		set_error_handler(
+			function($no, $message, $file, $line, $context) {
+				print('<h3 class="erreur">Erreur PHP</h3>');
+				print('<div class="erreur_sql">');
+				print("<b>Code : </b>".$no.BR);
+				print('<b>Erreur : </b>'.$message 
+							. ' file : ' . $file 
+							. ' line : ' . $line
+							.BR.BR);
+				print($this->view->tagAnchor($this->view->url(['skip_php' => 1]), "Ignorer l'erreur et continuer"));
+				
+				print('</div>');
+				die(255);
+			});
+
+		try {
+			include $script;
+		} catch (Exception $e) {
+			print('<h3 class="erreur">Erreur PHP</h3>');
+			print('<div class="erreur_sql">');
+			print("<b>Code : </b>".$e->getCode().BR);
+			print('<b>Erreur : </b>'.$e->getMessage().BR.BR);
+			print($this->view->tagAnchor($this->view->url(['skip_php' => 1]), "Ignorer l'erreur et continuer"));
+
+			print('</div>');
+			exit;
+		}
+
+	}
+
+	public function visitSqlSkip() {
+		if (isset($this->reprise) and ($this->reprise > 0) and ($this->reprise >= $num_instruction))
+			return true;
+		return false;
+	}
+
+	public function visitDisplayInstruction($instruction) {
+		print($instruction . BR);
+	}
+
+	public function visitSqlException($e,$num_instruction) {
+
+			print('<h3 class="erreur">Erreur SQL</h3>');
+			print('<div class="erreur_sql">');
+			print("<b>Code : </b>".$e->getCode().BR);
+			print('<b>Erreur : </b>'.$e->getMessage().BR.BR);
+			print($this->view->tagAnchor($this->view->url(['reprise' => $num_instruction]), "Ignorer l'erreur et continuer"));
+			print('</div>');
+
+		}
+
+		
+		public function visitIsForceUpgrade() {
+			if (!$this->skip_php)
+				return false;
+			$this->skip_php=0;
+			return true;
+		}
+	}
+}
+?>
\ No newline at end of file
diff --git a/tests/library/Class/MigrationTest.php b/tests/library/Class/MigrationTest.php
new file mode 100644
index 00000000000..ddec1d99256
--- /dev/null
+++ b/tests/library/Class/MigrationTest.php
@@ -0,0 +1,141 @@
+<?php
+/**
+ * Copyright (c) 2012-2014, Agence Française Informatique (AFI). All rights reserved.
+ *
+ * AFI-OPAC 2.0 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.
+ *
+ * There are special exceptions to the terms and conditions of the AGPL as it
+ * is applied to this software (see README file).
+ *
+ * AFI-OPAC 2.0 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 AFI-OPAC 2.0; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA 
+ */
+
+class Class_MigrationPatchsWithEmptyDirTest extends Storm_Test_ModelTestCase {
+	public function setup() {
+		$this->migration = new Class_Migration_Patchs();
+	  $this->fixture('Class_CosmoVar', ['id' => 1,
+																			'clef' => 'patch_level',
+																			'valeur' => 10 ] );
+		Class_Migration_Patchs::setFileSystem(Storm_Test_ObjectWrapper::mock()
+																					->whenCalled('glob')
+																					->answers([]
+																						));
+																					
+	}
+
+	
+	
+	/** @test */
+	public function lastPatchNumberShouldReturn0() {
+		$this->assertEquals('0',$this->migration->getLastPatchNumber());
+	}
+}
+
+
+class Class_MigrationPatchsTest extends Storm_Test_ModelTestCase {
+	public function setup() {
+		$this->migration = new Class_Migration_Patchs();
+	  $this->fixture('Class_CosmoVar', ['id' => 1,
+																			'clef' => 'patch_level',
+																			'valeur' => 10 ] );
+		Class_Migration_Patchs::setFileSystem(Storm_Test_ObjectWrapper::mock()
+																					->whenCalled('glob')
+																					->answers(['./cosmogramme/sql/patch/patch_03.sql',
+																										 './cosmogramme/sql/patch/patch_13.sql',
+																										 './cosmogramme/sql/patch/patch_10.sql',
+																										 './cosmogramme/sql/patch/patch_14.php',
+																										 './cosmogramme/sql/patch/patch_5.sql'
+																											]
+																						));
+																					
+	}
+
+	
+	
+	/** @test */
+	public function lastPatchNumberShouldReturn14() {
+		$this->assertEquals('14',$this->migration->getLastPatchNumber());
+	}
+
+	/** @test */
+	public function runPatchDirectoryShouldReturnScripts() {
+		$this->assertEquals(['./cosmogramme/sql/patch/patch_13.sql',
+												 './cosmogramme/sql/patch/patch_14.php'],
+												$this->migration->getMatchingPatchFiles(10));
+	}
+
+	
+
+}
+
+class Class_MigrationScriptPatchsTest extends Storm_Test_ModelTestCase {
+	
+	public function setup() {
+		$this->migration = new Class_Migration_ScriptPatchs();
+	  $this->fixture('Class_CosmoVar', [
+																			'id' => 'patch_level',
+																			'valeur' => 10 ] );
+		Class_Migration_Patchs::setFileSystem(Storm_Test_ObjectWrapper::mock()
+																					->whenCalled('glob')
+																					->answers(['./cosmogramme/sql/patch/patch_03.sql',
+																										 './cosmogramme/sql/patch/patch_13.sql',
+																										 './cosmogramme/sql/patch/patch_10.sql',
+																										 './cosmogramme/sql/patch/patch_14.php',
+																										 './cosmogramme/sql/patch/patch_12.sql',
+																										 './cosmogramme/sql/patch/patch_5.sql'
+																											])
+																					->whenCalled('file')
+																					->with('./cosmogramme/sql/patch/patch_14.sql')
+																					->answers([ 'update working;'])
+																					->whenCalled('file')
+																					->with('./cosmogramme/sql/patch/patch_13.sql')
+																					->answers(['update not working;',
+																										 '-- commented update;',
+																											'update working;'])
+																					->whenCalled('file')
+																					->with('./cosmogramme/sql/patch/patch_14.sql')
+																					->answers([ 'update working;'])
+																						);
+		$this->_mock_system_include = Storm_Test_ObjectWrapper::mock()
+			->whenCalled('include_file')
+			->answers(true);
+
+		$mock_sql = Storm_Test_ObjectWrapper::mock();
+		$mock_sql->whenCalled('execute')
+			->with('update not working; ')
+			->answers($this->throwException(new Exception('database error')))
+			->whenCalled('execute')
+			->with('update working; ')
+			->answers(true);
+		
+		Zend_Registry::set('sql', $mock_sql);
+
+		Class_Systeme_Include::setInstance($this->_mock_system_include);
+	}
+
+  /** @test */
+	public function runPatchShouldUpgradePatchLevelTo12() {
+		(new Class_Migration_ScriptPatchs())->run();
+		$this->assertEquals(12,Class_CosmoVar::find('patch_level')->getValeur());
+	}
+
+
+  /** @test */
+	public function runForcePatchShouldUpgradePatchLevelTo14() {
+		(new Class_Migration_ScriptPatchs())->run(true);
+		$this->assertEquals(14,Class_CosmoVar::find('patch_level')->getValeur());
+	}
+
+
+
+}
+?>
\ No newline at end of file
-- 
GitLab