<?php
/**
* SeekQuarry/Yioop --
* Open Source Pure PHP Search Engine, Crawler, and Indexer
*
* Copyright (C) 2009 - 2026 Chris Pollett chris@pollett.org
*
* LICENSE:
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* END LICENSE
*
* @author Chris Pollett chris@pollett.org
* @license https://www.gnu.org/licenses/ GPL3
* @link https://www.seekquarry.com/
* @copyright 2009 - 2026
* @filesource
*/
namespace seekquarry\yioop\tests;
use seekquarry\yioop\configs as C;
use seekquarry\yioop\library as L;
use seekquarry\yioop\library\UnitTest;
use seekquarry\yioop\models\LocaleModel;
/**
* LocaleModelTest checks how a site's locales sit over the locales that
* ship with Yioop. The shipped strings and resources are in src/locale.
* A site's folder of locales, the work directory's app/locale, holds only
* the strings and resource files the site changed. Each case builds such
* a site folder of its own under tests/test_files, so the work directory's own
* locales are not touched.
*/
class LocaleModelTest extends UnitTest
{
/**
* CHANGED_ID names a string a site changed: seekquarry.com words its
* activation request mail differently from the shipped string.
*/
const CHANGED_ID = "register_controller_admin_activation_request";
/**
* SITE_WORDING is the site's own wording of the CHANGED_ID string.
*/
const SITE_WORDING = "Seekquarry User Has Requested Activation";
/**
* $site_dir is the folder of locales a case writes, standing in for a
* site's app/locale.
* @var string
*/
public $site_dir;
/**
* $locale_model is the LocaleModel each case works with.
* @var LocaleModel
*/
public $locale_model;
/**
* setUp makes an empty folder of locales for the case under
* tests/test_files, with an en_US folder in it, and a LocaleModel.
*/
public function setUp()
{
$this->site_dir = C\TEST_DIR . "/test_files/locale_test_" . getmypid();
if (!is_dir($this->site_dir . "/en_US")) {
mkdir($this->site_dir . "/en_US", 0777, true);
}
$this->locale_model = new LocaleModel();
}
/**
* tearDown deletes the folder of locales setUp made.
*/
public function tearDown()
{
$this->locale_model->db->unlinkRecursive($this->site_dir, true);
}
/**
* siteCopyKeepsOnlyChangedStringsTestCase checks that rewriting a
* site's configure.ini keeps only strings that differ from the
* shipped ones. The site's file starts as an older copy of every
* string, holding one it changed and one that equals the shipped one.
* After updateLocale, only the changed string and the version line
* are left, and reading the locale gives the site's wording for the
* changed string and the shipped wording for the other.
*/
public function siteCopyKeepsOnlyChangedStringsTestCase()
{
$shipped = L\parse_ini_with_fallback(C\FALLBACK_LOCALE_DIR .
"/en_US/configure.ini")['strings'];
$same_id = "view_locale_version";
foreach ($shipped as $string_id => $value) {
if ($value !== "" && $string_id != self::CHANGED_ID &&
$string_id != "view_locale_version") {
$same_id = $string_id;
break;
}
}
file_put_contents($this->site_dir . "/en_US/configure.ini",
"[strings]\n" . self::CHANGED_ID . ' = "' . self::SITE_WORDING .
"\"\n$same_id = \"" . addslashes($shipped[$same_id]) . "\"\n");
$general_ini = L\parse_ini_with_fallback(C\FALLBACK_LOCALE_DIR .
"/general.ini");
$this->locale_model->updateLocale($general_ini,
[self::CHANGED_ID, $same_id, "view_locale_version"],
$this->site_dir, "en_US");
$kept = L\parse_ini_with_fallback($this->site_dir .
"/en_US/configure.ini")['strings'] ?? [];
$this->assertEqual(array_keys($kept),
[self::CHANGED_ID, "view_locale_version"],
"only the changed string and the version line are kept");
$read = L\localeConfigure("en_US", $this->site_dir)['strings'];
$this->assertEqual($read[self::CHANGED_ID], self::SITE_WORDING,
"the site's wording replaces the shipped one");
$this->assertEqual($read[$same_id], $shipped[$same_id],
"a string the site did not change is the shipped one");
}
/**
* shippedCopiesAreRemovedTestCase checks removeShippedCopies on site
* locale folders as earlier versions of Yioop left them. en_US has a
* resources folder holding only a copy of the shipped locale.js, and
* an old resources folder kept by an upgrade; both are deleted. de has
* a resources folder holding a copy of its shipped locale.js and a
* file the site made; that folder is left exactly as it is.
*/
public function shippedCopiesAreRemovedTestCase()
{
$copied = $this->site_dir . "/en_US/resources";
mkdir($copied);
mkdir($this->site_dir . "/en_US/resources1700000000old");
copy(C\FALLBACK_LOCALE_DIR . "/en_US/resources/locale.js",
"$copied/locale.js");
$changed = $this->site_dir . "/de/resources";
mkdir($changed, 0777, true);
copy(C\FALLBACK_LOCALE_DIR . "/de/resources/locale.js",
"$changed/locale.js");
file_put_contents("$changed/site_words.txt", "seekquarry\n");
$this->locale_model->removeShippedCopies($this->site_dir);
$this->assertFalse(is_dir($copied),
"a resources folder of copies only is deleted");
$this->assertFalse(is_dir($this->site_dir .
"/en_US/resources1700000000old"), "the old folder is deleted");
$this->assertEqual(array_values(array_diff(scandir($changed),
[".", ".."])), ["locale.js", "site_words.txt"],
"a resources folder holding a site's file is left as it is");
}
/**
* shippedLocalesAreNeverWrittenTestCase asks updateLocale to save a
* string into the locales that ship with Yioop, as a site with no
* work directory once did. The shipped configure.ini must be left
* with the same bytes.
*/
public function shippedLocalesAreNeverWrittenTestCase()
{
$shipped_name = C\FALLBACK_LOCALE_DIR . "/en_US/configure.ini";
$before = file_get_contents($shipped_name);
$general_ini = L\parse_ini_with_fallback(C\FALLBACK_LOCALE_DIR .
"/general.ini");
$this->locale_model->updateLocale($general_ini, [self::CHANGED_ID],
C\FALLBACK_LOCALE_DIR, "en_US",
["strings" => [self::CHANGED_ID => self::SITE_WORDING]]);
$after = file_get_contents($shipped_name);
if ($after !== $before) {
file_put_contents($shipped_name, $before);
}
$this->assertTrue($after === $before,
"the shipped configure.ini is unchanged");
}
}