From c43f6327b04704fbf73273ea6b53f020123aa55a Mon Sep 17 00:00:00 2001
From: Alex Arnaud <alex.arnaud@biblibre.com>
Date: Thu, 5 Jun 2014 18:32:17 +0200
Subject: [PATCH] rel #12691 : added index batch for autocomplete

---
 .../admin/controllers/BatchController.php     |  14 +++
 .../admin/views/scripts/batch/run-ajax.phtml  |  40 ++++++
 library/Class/Autocomplete/Index.php          | 119 ++++++++++++++++++
 library/Class/Autocomplete/IndexAuthor.php    |  31 +++++
 library/Class/Autocomplete/IndexNull.php      |  34 +++++
 library/Class/Autocomplete/IndexTitle.php     |  30 +++++
 library/Class/Batch.php                       |  13 +-
 library/Class/Batch/Abstract.php              |  15 ++-
 .../Class/Batch/AutocompleteRecordAuthor.php  |  36 ++++++
 .../Class/Batch/AutocompleteRecordTitle.php   |  36 ++++++
 library/Class/Testing/FileSystem.php          |   2 +-
 .../admin/controllers/BatchControllerTest.php |  19 ++-
 .../library/Class/Autocomplete/IndexTest.php  |  72 +++++++++++
 13 files changed, 454 insertions(+), 7 deletions(-)
 create mode 100644 application/modules/admin/views/scripts/batch/run-ajax.phtml
 create mode 100644 library/Class/Autocomplete/Index.php
 create mode 100644 library/Class/Autocomplete/IndexAuthor.php
 create mode 100644 library/Class/Autocomplete/IndexNull.php
 create mode 100644 library/Class/Autocomplete/IndexTitle.php
 create mode 100644 library/Class/Batch/AutocompleteRecordAuthor.php
 create mode 100644 library/Class/Batch/AutocompleteRecordTitle.php
 create mode 100644 tests/library/Class/Autocomplete/IndexTest.php

diff --git a/application/modules/admin/controllers/BatchController.php b/application/modules/admin/controllers/BatchController.php
index bcb9537cbfd..a71201e3967 100644
--- a/application/modules/admin/controllers/BatchController.php
+++ b/application/modules/admin/controllers/BatchController.php
@@ -48,6 +48,20 @@ class Admin_BatchController extends ZendAfi_Controller_Action {
 		$this->_helper->notify($this->_('Tâche executée'));
 		$this->_redirect('/admin/batch');
 	}
+
+
+	public function runAjaxAction() {
+		$batch = Class_Batch::find($this->_getParam('id'));
+		$this->view->titre = $this->view->_('Exécution du traitement "%s"', $batch->getLibelle());
+		$this->view->batch = $batch;
+	}
+
+
+	public function runStepAction() {
+		$this->_helper->json(
+			Class_Batch::find($this->_getParam('id'))
+			->runStep($this->_request->getParams()));
+	}
 }
 
 ?>
\ No newline at end of file
diff --git a/application/modules/admin/views/scripts/batch/run-ajax.phtml b/application/modules/admin/views/scripts/batch/run-ajax.phtml
new file mode 100644
index 00000000000..45ccbae994b
--- /dev/null
+++ b/application/modules/admin/views/scripts/batch/run-ajax.phtml
@@ -0,0 +1,40 @@
+<div id="batchProgress">
+	<div id="batchProgressMessage"><?php echo $this->_('Initialisation du traitement');?></div>
+</div>
+<?php 
+Class_ScriptLoader::getInstance()
+->addInlineStyle('
+.ui-progressbar {
+  position: relative;
+}
+#batchProgressMessage {
+  position: absolute;
+  left: 15px;
+  top: 4px;
+  font-weight: bold;
+  text-shadow: 1px 1px 0 #fff;
+}
+')
+->addJQueryReady('
+$("#batchProgress").progressbar({
+    value:false,
+    change: function() {
+      $("#batchProgressMessage").text( $("#batchProgress").progressbar( "value" ) + "/" + $("#batchProgress").progressbar("option", "max") );
+    },});
+
+function runNext(done) {
+  $.getJSON("' . $this->url(['module' => 'admin',
+														 'controller' => 'batch', 
+														 'action' => 'run-step',
+														 'id' => $this->batch->getId()], 
+														null, true) . '/done/" + done, function(data) {
+   $("#batchProgress").progressbar("option", "max", data.total);
+   $("#batchProgress").progressbar("value", data.done);
+   if (data.done < data.total)
+     runNext(data.done, data.total);
+  });
+}
+
+runNext(0);
+');
+?>
diff --git a/library/Class/Autocomplete/Index.php b/library/Class/Autocomplete/Index.php
new file mode 100644
index 00000000000..bc499ba48e7
--- /dev/null
+++ b/library/Class/Autocomplete/Index.php
@@ -0,0 +1,119 @@
+<?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_Autocomplete_Index {
+	use Trait_StaticFileSystem;
+
+	protected $file_name;
+
+
+	public function getBasePath() {
+		return PATH_TEMP . 'autocomplete/';
+	}
+
+
+	public function getFilePath() {
+		return $this->getBasePath() . $this->file_name;
+	}
+
+	
+	public static function getClassFor($name) {
+		foreach (['Title' => new Class_Autocomplete_IndexTitle(),
+							'Author' => new Class_Autocomplete_IndexAuthor()
+
+							 ] as $k => $clazz) {
+			if ((0 === strpos(substr($name, 12), $k)))
+				return $clazz;
+		}
+		return new Class_Autocomplete_IndexNull();
+	}
+	
+
+	public static function getMethodFor($name) {
+		return (false === strpos($name, 'Page')) ? 'index' : 'indexPage';
+	}
+
+
+	public static function __callStatic($name, $args) {
+		$class = static::getClassFor($name);
+		$method = static::getMethodFor($name);
+		call_user_func_array([$class, $method], $args);
+	}
+
+
+	public function index($params=[]) {
+		$file_system = static::getFileSystem();
+		if (!$file_system->file_exists($this->getBasePath())
+				&& !$file_system->mkdir($this->getBasePath()))
+			return;
+
+		if (!empty($params) && isset($params['done']))
+			return $this->indexPage($params['done']);
+
+		$current = 0;
+		do {
+			$response = $this->indexPage($current);
+			if (0 == $response->done)
+				return;
+
+			$current = $response->done;
+			Class_Notice::clearCache();
+			Storm_Model_Loader::resetCache();
+			gc_collect_cycles();
+		} while($response->done < $response->total);
+	}
+
+
+	public function indexPage($done) {
+		$file_system = static::getFileSystem();
+		$mode = ($done > 0) ? 'a' : 'w';
+
+		$response = new stdClass;
+		if (false === ($file = $file_system->fopen($this->getFilePath(), $mode))) {
+			$response->done = 0;
+			$response->total= 0;
+			return $response;
+		}
+
+		$page_size = 1000;
+		$page = ($done/$page_size) + 1;
+		$response->total = Class_Notice::countBy([]);
+
+		$notices = Class_Notice::findAllBy(['limitPage' => [$page, $page_size]]);
+		foreach($notices as $notice)
+			$file_system->fwrite($file, $this->getRecordData($notice)."\n");
+		$file_system->fclose($file);
+
+		$response->done = ($response->total > $done + $page_size) ?
+			$done + $page_size :
+			$done + count($notices);
+
+		return $response;
+	}
+
+
+	protected function getRecordData($record) {
+		return '';
+	}
+}
+
+?>
\ No newline at end of file
diff --git a/library/Class/Autocomplete/IndexAuthor.php b/library/Class/Autocomplete/IndexAuthor.php
new file mode 100644
index 00000000000..850aa352db2
--- /dev/null
+++ b/library/Class/Autocomplete/IndexAuthor.php
@@ -0,0 +1,31 @@
+<?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_Autocomplete_IndexAuthor extends Class_Autocomplete_Index {
+	protected $file_name = 'authors';
+
+	protected function getRecordData($record) {
+		return $record->getAuteurPrincipal();
+	}
+}
+
+?>
\ No newline at end of file
diff --git a/library/Class/Autocomplete/IndexNull.php b/library/Class/Autocomplete/IndexNull.php
new file mode 100644
index 00000000000..ea62683c58e
--- /dev/null
+++ b/library/Class/Autocomplete/IndexNull.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 Class_Autocomplete_IndexNull extends Class_Autocomplete_Index {
+	public function index($params) {
+		return;
+	}
+
+	public function indexPage($done) {
+		$response->done = 0;
+		$response->total= 0;
+		return $response;		
+	}
+}
+?>
\ No newline at end of file
diff --git a/library/Class/Autocomplete/IndexTitle.php b/library/Class/Autocomplete/IndexTitle.php
new file mode 100644
index 00000000000..ab279edb8e1
--- /dev/null
+++ b/library/Class/Autocomplete/IndexTitle.php
@@ -0,0 +1,30 @@
+<?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_Autocomplete_IndexTitle extends Class_Autocomplete_Index {
+	protected $file_name = 'titles';
+
+	protected function getRecordData($record) {
+		return $record->getTitrePrincipal();
+	}
+}
+?>
\ No newline at end of file
diff --git a/library/Class/Batch.php b/library/Class/Batch.php
index ee0cadc207c..df2f91db0fc 100644
--- a/library/Class/Batch.php
+++ b/library/Class/Batch.php
@@ -27,7 +27,9 @@ class Class_BatchLoader extends Storm_Model_Loader{
 						'CORRECTION_PANIERS' => new Class_Batch_PanierNotice(),
 						'CART_REALLOCATION' => new Class_Batch_PanierUser(),
 						'COMMENT_REALLOCATION'=> new Class_Batch_AvisNotice(),
-						'INDEX_RESSOURCES_NUMERIQUES' => new Class_Batch_IndexRessourcesNumeriques()
+						'INDEX_RESSOURCES_NUMERIQUES' => new Class_Batch_IndexRessourcesNumeriques(),
+						'AUTOCOMPLETE_RECORD_TITLE' => new Class_Batch_AutocompleteRecordTitle(),
+						'AUTOCOMPLETE_RECORD_AUTHOR' => new Class_Batch_AutocompleteRecordAuthor()
 			]);
 	}
 
@@ -104,5 +106,14 @@ class Class_Batch extends Storm_Model_Abstract {
 		$this->setLastRun(date('Y-m-d H:i:s'))->save();
 		return $this;
 	}
+
+
+	public function runStep($params) {
+		if (!$batch = Class_Batch::getLoader()->getKnownType($this->getType()))
+			return;
+		$response = $batch->runStep($params);
+		$this->setLastRun(date('Y-m-d H:i:s'))->save();
+		return $response;
+	}
 }
 ?>
diff --git a/library/Class/Batch/Abstract.php b/library/Class/Batch/Abstract.php
index 2b2636dfc41..727267f57b7 100644
--- a/library/Class/Batch/Abstract.php
+++ b/library/Class/Batch/Abstract.php
@@ -20,11 +20,20 @@
  */
 
 
-abstract class Class_Batch_Abstract {
+class Class_Batch_Abstract {
 	use Trait_Translator;
 
-	abstract public function getLabel();
-	abstract public function run();
+	public function getLabel() {
+		return '';
+	}
+
+	public function run() {
+		return;
+	}
+
+	public function runStep($params) {
+		return;
+	}
 
 	public function isEnabled() {
 		return true;
diff --git a/library/Class/Batch/AutocompleteRecordAuthor.php b/library/Class/Batch/AutocompleteRecordAuthor.php
new file mode 100644
index 00000000000..4e36af0acad
--- /dev/null
+++ b/library/Class/Batch/AutocompleteRecordAuthor.php
@@ -0,0 +1,36 @@
+<?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_Batch_AutocompleteRecordAuthor extends Class_Batch_Abstract {
+	public function getLabel() {
+		return $this->_("Indexer les auteurs de notice pour l'autocompletion");
+	}
+
+	public function run() {
+		Class_Autocomplete_Index::indexRecordsAuthor();
+	}
+
+	public function runStep($params) {
+		return Class_Autocomplete_Index::indexRecordsAuthor($params);
+	}
+}
+?>
\ No newline at end of file
diff --git a/library/Class/Batch/AutocompleteRecordTitle.php b/library/Class/Batch/AutocompleteRecordTitle.php
new file mode 100644
index 00000000000..3c3ed072c70
--- /dev/null
+++ b/library/Class/Batch/AutocompleteRecordTitle.php
@@ -0,0 +1,36 @@
+<?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_Batch_AutocompleteRecordTitle extends Class_Batch_Abstract {
+	public function getLabel() {
+		return $this->_("Indexer les titres de notice pour l'autocompletion");
+	}
+
+	public function run() {
+		Class_Autocomplete_Index::indexRecordsTitle();
+	}
+
+	public function runStep($params) {
+		return Class_Autocomplete_Index::indexRecordsTitle($params);
+	}
+}
+?>
\ No newline at end of file
diff --git a/library/Class/Testing/FileSystem.php b/library/Class/Testing/FileSystem.php
index 2db688b67ef..f1c39bbf102 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', 'fwrite'];
 	
 	public function __call($name, $args) {
 		if (!in_array($name, $this->_known_functions))
diff --git a/tests/application/modules/admin/controllers/BatchControllerTest.php b/tests/application/modules/admin/controllers/BatchControllerTest.php
index 169c57cebac..4591cd22c82 100644
--- a/tests/application/modules/admin/controllers/BatchControllerTest.php
+++ b/tests/application/modules/admin/controllers/BatchControllerTest.php
@@ -99,20 +99,35 @@ class BatchControllerAddTest extends BatchControllerTestCase {
 		$this->assertXPath('//select[@name="type"]/option[@value="MOISSONNAGE_VODECLIC"][@label="Moissonner catalogue Vodeclic"][not(@selected)]',$this->_response->getBody());
 	}
 
-		/** @test */
+
+	/** @test */
 	public function selectElementShouldNotContainsMoissonnageArteVod(){
 		$this->assertNotXPath('//select[@name="type"]/option[@value="MOISSONNAGE_ARTEVOD"][@label="Moissonner catalogue ArteVOD"][not(@selected)]',$this->_response->getBody());
 	}
 
+
 	/** @test */
 	public function selectElementShouldNotContainsMoissonnageNumilog(){
 		$this->assertNotXPath('//select[@name="type"]/option[@value="MOISSONNAGE_NUMILOG"][@label="Moissonner catalogue Numilog"][not(@selected)]',$this->_response->getBody());
 	}
 
-/** @test */
+
+	/** @test */
 	public function selectElementShouldNotContainsMoissonnageToutApprendre(){
 		$this->assertNotXPath('//select[@name="type"]/option[@value="MOISSONNAGE_TOUTAPPRENDRE"][@label="Moissonner catalogue Tout apprendre"][not(@selected)]',$this->_response->getBody());
 	}
+
+
+	/** @test */
+	public function selectElementShouldContainsIndexAutocompleteRecordTitle(){
+		$this->assertXPath('//select[@name="type"]/option[@value="AUTOCOMPLETE_RECORD_TITLE"][@label="Indexer les titres de notice pour l\'autocompletion"][not(@selected)]',$this->_response->getBody());
+	}
+
+
+	/** @test */
+	public function selectElementShouldContainsIndexAutocompleteRecordAuthor(){
+		$this->assertXPath('//select[@name="type"]/option[@value="AUTOCOMPLETE_RECORD_AUTHOR"][@label="Indexer les auteurs de notice pour l\'autocompletion"][not(@selected)]',$this->_response->getBody());
+	}
 }
 
 
diff --git a/tests/library/Class/Autocomplete/IndexTest.php b/tests/library/Class/Autocomplete/IndexTest.php
new file mode 100644
index 00000000000..bb55c703b12
--- /dev/null
+++ b/tests/library/Class/Autocomplete/IndexTest.php
@@ -0,0 +1,72 @@
+<?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_Autocomplete_IndexTest extends Storm_Test_ModelTestCase{
+	protected $_file_system;
+
+	public function setUp() {
+		parent::setUp();
+		$this->_file_system = $this->mock()->whenCalled('fclose')->answers(true);
+		Class_Autocomplete_Index::setFileSystem($this->_file_system);
+		Class_Notice::beVolatile();
+	}
+
+
+	public function tearDown() {
+		Class_Autocomplete_Index::setFileSystem(null);
+		parent::tearDown();
+	}
+
+
+	/** @test */
+	public function whenDirectoryDoesNotExistsshouldCreateIndexFile() {
+		$this->_file_system
+			->whenCalled('file_exists')->answers(false)
+			->whenCalled('mkdir')->answers(true)
+			->whenCalled('fopen')->answers(null);
+
+		Class_Autocomplete_Index::indexRecordsTitle();
+
+		$this->assertTrue($this->_file_system->methodHasBeenCalled('mkdir'));
+	}
+
+
+
+	/** @test */
+	public function shouldWriteBoneOfMyBones() {
+		$handle = new stdClass;
+		$this->_file_system
+			->whenCalled('file_exists')->answers(true)
+			->whenCalled('fopen')->answers($handle)
+			->whenCalled('fwrite')->answers(null);
+
+		$this->fixture('Class_Notice',
+									 ['id' => 1301,
+									 'titre_principal' => 'Bone of my bones']);
+		
+		Class_Autocomplete_Index::indexRecordsTitle();
+
+		$this->assertTrue(
+			$this->_file_system->methodHasBeenCalledWithParams('fwrite', [$handle, "Bone of my bones\n"]));
+	}
+}
+?>
\ No newline at end of file
-- 
GitLab