瀏覽代碼

A few additional PHPStan rules (#5388)

A subset of
https://github.com/phpstan/phpstan-strict-rules
Alexandre Alapetite 2 年之前
父節點
當前提交
6e2f2f1c1e
共有 66 個文件被更改,包括 478 次插入426 次删除
  1. 1 1
      app/Controllers/feedController.php
  2. 2 7
      app/Controllers/indexController.php
  3. 4 1
      app/Controllers/javascriptController.php
  4. 11 12
      app/Controllers/statsController.php
  5. 1 5
      app/Controllers/tagController.php
  6. 6 10
      app/Controllers/userController.php
  7. 1 0
      app/Mailers/UserMailer.php
  8. 1 0
      app/Models/ActionController.php
  9. 6 6
      app/Models/BooleanSearch.php
  10. 3 3
      app/Models/CategoryDAO.php
  11. 1 1
      app/Models/CategoryDAOSQLite.php
  12. 4 4
      app/Models/Context.php
  13. 2 2
      app/Models/DatabaseDAO.php
  14. 5 5
      app/Models/DatabaseDAOSQLite.php
  15. 9 9
      app/Models/Entry.php
  16. 1 1
      app/Models/EntryDAOSQLite.php
  17. 4 4
      app/Models/Feed.php
  18. 1 5
      app/Models/FeedDAO.php
  19. 1 1
      app/Models/FeedDAOSQLite.php
  20. 1 1
      app/Models/FormAuth.php
  21. 2 2
      app/Models/Search.php
  22. 3 3
      app/Models/Share.php
  23. 1 1
      app/Models/StatsDAO.php
  24. 1 1
      app/Models/TagDAO.php
  25. 1 1
      app/actualize_script.php
  26. 3 3
      app/install.php
  27. 2 2
      app/layout/aside_feed.phtml
  28. 1 1
      app/layout/header.phtml
  29. 1 1
      app/layout/nav_menu.phtml
  30. 1 1
      app/views/auth/index.phtml
  31. 6 6
      app/views/helpers/logs_pagination.phtml
  32. 1 1
      cli/_cli.php
  33. 1 1
      cli/do-install.php
  34. 1 1
      cli/i18n/I18nData.php
  35. 2 2
      cli/i18n/I18nUsageValidator.php
  36. 1 1
      cli/i18n/I18nValue.php
  37. 1 1
      cli/manipulate.translation.php
  38. 1 1
      cli/reconfigure.php
  39. 1 1
      cli/user-info.php
  40. 2 1
      composer.json
  41. 61 12
      composer.lock
  42. 1 1
      lib/Minz/Extension.php
  43. 2 1
      lib/Minz/ExtensionManager.php
  44. 1 1
      lib/Minz/Migrator.php
  45. 7 6
      lib/Minz/Pdo.php
  46. 2 2
      lib/Minz/Request.php
  47. 3 5
      lib/Minz/Translate.php
  48. 1 1
      lib/Minz/Url.php
  49. 1 1
      lib/Minz/View.php
  50. 0 1
      lib/composer.json
  51. 5 4
      lib/lib_rss.php
  52. 5 5
      p/api/greader.php
  53. 16 0
      phpstan.neon
  54. 17 16
      tests/app/Models/CategoryTest.php
  55. 8 8
      tests/app/Models/LogDAOTest.php
  56. 33 33
      tests/app/Models/SearchTest.php
  57. 37 39
      tests/app/Models/UserQueryTest.php
  58. 3 3
      tests/app/Utils/passwordUtilTest.php
  59. 19 19
      tests/cli/i18n/I18nCompletionValidatorTest.php
  60. 66 66
      tests/cli/i18n/I18nDataTest.php
  61. 2 2
      tests/cli/i18n/I18nFileTest.php
  62. 16 16
      tests/cli/i18n/I18nUsageValidatorTest.php
  63. 30 30
      tests/cli/i18n/I18nValueTest.php
  64. 1 1
      tests/lib/CssXPath/CssXPathTest.php
  65. 42 42
      tests/lib/Minz/MigratorTest.php
  66. 1 1
      tests/lib/PHPMailer/PHPMailerTest.php

+ 1 - 1
app/Controllers/feedController.php

@@ -348,7 +348,7 @@ class FreshRSS_feed_Controller extends FreshRSS_ActionController {
 		}
 
 		// Set maxFeeds to a minimum of 10
-		if (!is_int($maxFeeds) || $maxFeeds < 10) {
+		if ($maxFeeds < 10) {
 			$maxFeeds = 10;
 		}
 

+ 2 - 7
app/Controllers/indexController.php

@@ -192,13 +192,8 @@ class FreshRSS_index_Controller extends FreshRSS_ActionController {
 		}
 
 		$get = FreshRSS_Context::currentGet(true);
-		if (is_array($get)) {
-			$type = $get[0];
-			$id = (int)$get[1];
-		} else {
-			$type = $get;
-			$id = 0;
-		}
+		$type = (string)$get[0];
+		$id = (int)$get[1];
 
 		$catDAO = FreshRSS_Factory::createCategoryDao();
 		$categories = $catDAO->listCategories(true, true);

+ 4 - 1
app/Controllers/javascriptController.php

@@ -2,7 +2,10 @@
 
 class FreshRSS_javascript_Controller extends FreshRSS_ActionController {
 
-	/** @var FreshRSS_ViewJavascript */
+	/**
+	 * @var FreshRSS_ViewJavascript
+	 * @phpstan-ignore-next-line
+	 */
 	protected $view;
 
 	public function __construct() {

+ 11 - 12
app/Controllers/statsController.php

@@ -5,7 +5,10 @@
  */
 class FreshRSS_stats_Controller extends FreshRSS_ActionController {
 
-	/** @var FreshRSS_ViewStats */
+	/**
+	 * @var FreshRSS_ViewStats
+	 * @phpstan-ignore-next-line
+	 */
 	protected $view;
 
 	public function __construct() {
@@ -57,7 +60,7 @@ class FreshRSS_stats_Controller extends FreshRSS_ActionController {
 		$this->view->repartitions = $statsDAO->calculateEntryRepartition();
 
 		$entryCount = $statsDAO->calculateEntryCount();
-		if (is_array($entryCount) && count($entryCount) > 0) {
+		if (count($entryCount) > 0) {
 			$this->view->entryCount = $entryCount;
 			$this->view->average = round(array_sum(array_values($entryCount)) / count($entryCount), 2);
 		} else {
@@ -67,21 +70,17 @@ class FreshRSS_stats_Controller extends FreshRSS_ActionController {
 
 		$feedByCategory = [];
 		$feedByCategory_calculated = $statsDAO->calculateFeedByCategory();
-		if (is_array($feedByCategory_calculated)) {
-			for ($i = 0; $i < count($feedByCategory_calculated); $i++) {
-				$feedByCategory['label'][$i] = $feedByCategory_calculated[$i]['label'];
-				$feedByCategory['data'][$i] = $feedByCategory_calculated[$i]['data'];
-			}
+		for ($i = 0; $i < count($feedByCategory_calculated); $i++) {
+			$feedByCategory['label'][$i] = $feedByCategory_calculated[$i]['label'];
+			$feedByCategory['data'][$i] = $feedByCategory_calculated[$i]['data'];
 		}
 		$this->view->feedByCategory = $feedByCategory;
 
 		$entryByCategory = [];
 		$entryByCategory_calculated = $statsDAO->calculateEntryByCategory();
-		if (is_array($entryByCategory_calculated)) {
-			for ($i = 0; $i < count($entryByCategory_calculated); $i++) {
-				$entryByCategory['label'][$i] = $entryByCategory_calculated[$i]['label'];
-				$entryByCategory['data'][$i] = $entryByCategory_calculated[$i]['data'];
-			}
+		for ($i = 0; $i < count($entryByCategory_calculated); $i++) {
+			$entryByCategory['label'][$i] = $entryByCategory_calculated[$i]['label'];
+			$entryByCategory['data'][$i] = $entryByCategory_calculated[$i]['data'];
 		}
 		$this->view->entryByCategory = $entryByCategory;
 

+ 1 - 5
app/Controllers/tagController.php

@@ -96,12 +96,8 @@ class FreshRSS_tag_Controller extends FreshRSS_ActionController {
 		}
 
 		$name = Minz_Request::paramString('name');
-		$lengthOfName = 0;
-		if (is_string($name)) {
-			$lengthOfName = strlen($name);
-		}
 		$tagDAO = FreshRSS_Factory::createTagDao();
-		if ($lengthOfName > 0 && null === $tagDAO->searchByName($name)) {
+		if (strlen($name) > 0 && null === $tagDAO->searchByName($name)) {
 			$tagDAO->addTag(['name' => $name]);
 			Minz_Request::good(_t('feedback.tag.created', $name), ['c' => 'tag', 'a' => 'index']);
 		}

+ 6 - 10
app/Controllers/userController.php

@@ -41,11 +41,9 @@ class FreshRSS_user_Controller extends FreshRSS_ActionController {
 			$userConfig->passwordHash = $passwordHash;
 		}
 
-		if (is_array($userConfigUpdated)) {
-			foreach ($userConfigUpdated as $configName => $configValue) {
-				if ($configValue !== null) {
-					$userConfig->_param($configName, $configValue);
-				}
+		foreach ($userConfigUpdated as $configName => $configValue) {
+			if ($configValue !== null) {
+				$userConfig->_param($configName, $configValue);
 			}
 		}
 
@@ -224,9 +222,7 @@ class FreshRSS_user_Controller extends FreshRSS_ActionController {
 			}
 		}
 
-		if (is_array($userConfigOverride)) {
-			$userConfig = array_merge($userConfig, $userConfigOverride);
-		}
+		$userConfig = array_merge($userConfig, $userConfigOverride);
 
 		$ok = self::checkUsername($new_user_name);
 		$homeDir = join_path(DATA_PATH, 'users', $new_user_name);
@@ -234,11 +230,11 @@ class FreshRSS_user_Controller extends FreshRSS_ActionController {
 
 		if ($ok) {
 			$languages = Minz_Translate::availableLanguages();
-			if (empty($userConfig['language']) || !in_array($userConfig['language'], $languages)) {
+			if (empty($userConfig['language']) || !in_array($userConfig['language'], $languages, true)) {
 				$userConfig['language'] = 'en';
 			}
 
-			$ok &= !in_array(strtoupper($new_user_name), array_map('strtoupper', listUsers()));	//Not an existing user, case-insensitive
+			$ok &= !in_array(strtoupper($new_user_name), array_map('strtoupper', listUsers()), true);	//Not an existing user, case-insensitive
 
 			$configPath = join_path($homeDir, 'config.php');
 			$ok &= !file_exists($configPath);

+ 1 - 0
app/Mailers/UserMailer.php

@@ -7,6 +7,7 @@ class FreshRSS_User_Mailer extends Minz_Mailer {
 
 	/**
 	 * @var FreshRSS_View
+	 * @phpstan-ignore-next-line
 	 */
 	protected $view;
 

+ 1 - 0
app/Models/ActionController.php

@@ -4,6 +4,7 @@ class FreshRSS_ActionController extends Minz_ActionController {
 
 	/**
 	 * @var FreshRSS_View
+	 * @phpstan-ignore-next-line
 	 */
 	protected $view;
 }

+ 6 - 6
app/Models/BooleanSearch.php

@@ -43,12 +43,12 @@ class FreshRSS_BooleanSearch {
 	 */
 	private function parseUserQueryNames(string $input): string {
 		$all_matches = [];
-		if (preg_match_all('/\bsearch:(?P<delim>[\'"])(?P<search>.*)(?P=delim)/U', $input, $matches)) {
-			$all_matches[] = $matches;
+		if (preg_match_all('/\bsearch:(?P<delim>[\'"])(?P<search>.*)(?P=delim)/U', $input, $matchesFound)) {
+			$all_matches[] = $matchesFound;
 
 		}
-		if (preg_match_all('/\bsearch:(?P<search>[^\s"]*)/', $input, $matches)) {
-			$all_matches[] = $matches;
+		if (preg_match_all('/\bsearch:(?P<search>[^\s"]*)/', $input, $matchesFound)) {
+			$all_matches[] = $matchesFound;
 		}
 
 		if (!empty($all_matches)) {
@@ -82,8 +82,8 @@ class FreshRSS_BooleanSearch {
 	private function parseUserQueryIds(string $input): string {
 		$all_matches = [];
 
-		if (preg_match_all('/\bS:(?P<search>\d+)/', $input, $matches)) {
-			$all_matches[] = $matches;
+		if (preg_match_all('/\bS:(?P<search>\d+)/', $input, $matchesFound)) {
+			$all_matches[] = $matchesFound;
 		}
 
 		if (!empty($all_matches)) {

+ 3 - 3
app/Models/CategoryDAO.php

@@ -430,13 +430,13 @@ SQL;
 		$list = [];
 		$previousLine = [];
 		$feedsDao = [];
-		$feedDao = FreshRSS_Factory::createFeedDAO();
+		$feedDao = FreshRSS_Factory::createFeedDao();
 		foreach ($listDAO as $line) {
 			if (!empty($previousLine['c_id']) && $line['c_id'] !== $previousLine['c_id']) {
 				// End of the current category, we add it to the $list
 				$cat = new FreshRSS_Category(
 					$previousLine['c_name'],
-					$feedDao->daoToFeed($feedsDao, $previousLine['c_id'])
+					$feedDao::daoToFeed($feedsDao, $previousLine['c_id'])
 				);
 				$cat->_id($previousLine['c_id']);
 				$cat->_kind($previousLine['c_kind']);
@@ -454,7 +454,7 @@ SQL;
 		if ($previousLine != null) {
 			$cat = new FreshRSS_Category(
 				$previousLine['c_name'],
-				$feedDao->daoToFeed($feedsDao, $previousLine['c_id'])
+				$feedDao::daoToFeed($feedsDao, $previousLine['c_id'])
 			);
 			$cat->_id($previousLine['c_id']);
 			$cat->_kind($previousLine['c_kind']);

+ 1 - 1
app/Models/CategoryDAOSQLite.php

@@ -7,7 +7,7 @@ class FreshRSS_CategoryDAOSQLite extends FreshRSS_CategoryDAO {
 		if ($tableInfo = $this->pdo->query("PRAGMA table_info('category')")) {
 			$columns = $tableInfo->fetchAll(PDO::FETCH_COLUMN, 1);
 			foreach (['kind', 'lastUpdate', 'error', 'attributes'] as $column) {
-				if (!in_array($column, $columns)) {
+				if (!in_array($column, $columns, true)) {
 					return $this->addColumn($column);
 				}
 			}

+ 4 - 4
app/Models/Context.php

@@ -251,14 +251,14 @@ final class FreshRSS_Context {
 	 * Return the current get as a string or an array.
 	 *
 	 * If $array is true, the first item of the returned value is 'f' or 'c' or 't' and the second is the id.
-	 * @phpstan-return ($asArray is true ? array{'c'|'f'|'t',bool|int} : string)
+	 * @phpstan-return ($asArray is true ? array{'a'|'c'|'f'|'s'|'t'|'T',bool|int} : string)
 	 * @return string|array{string,bool|int}
 	 */
 	public static function currentGet(bool $asArray = false) {
 		if (self::$current_get['all']) {
-			return 'a';
+			return $asArray ? ['a', true] : 'a';
 		} elseif (self::$current_get['starred']) {
-			return 's';
+			return $asArray ? ['s', true] : 's';
 		} elseif (self::$current_get['feed']) {
 			if ($asArray) {
 				return array('f', self::$current_get['feed']);
@@ -278,7 +278,7 @@ final class FreshRSS_Context {
 				return 't_' . self::$current_get['tag'];
 			}
 		} elseif (self::$current_get['tags']) {
-			return 'T';
+			return $asArray ? ['T', true] : 'T';
 		}
 		return '';
 	}

+ 2 - 2
app/Models/DatabaseDAO.php

@@ -83,7 +83,7 @@ class FreshRSS_DatabaseDAO extends Minz_ModelPdo {
 
 		$ok = count($columns) === count($schema);
 		foreach ($columns as $c) {
-			$ok &= in_array($c['name'], $schema);
+			$ok &= in_array($c['name'], $schema, true);
 		}
 
 		return (bool)$ok;
@@ -131,7 +131,7 @@ class FreshRSS_DatabaseDAO extends Minz_ModelPdo {
 
 	/**
 	 * @param array<string,string|int|bool|null> $dao
-	 * @return array<string,string|int|bool|null>
+	 * @return array{'name':string,'type':string,'notnull':bool,'default':mixed}
 	 */
 	public function daoToSchema(array $dao): array {
 		return [

+ 5 - 5
app/Models/DatabaseDAOSQLite.php

@@ -50,14 +50,14 @@ class FreshRSS_DatabaseDAOSQLite extends FreshRSS_DatabaseDAO {
 	}
 
 	/**
-	 * @param array<string,string> $dao
-	 * @return array<string,string|bool>
+	 * @param array<string,string|int|bool|null> $dao
+	 * @return array{'name':string,'type':string,'notnull':bool,'default':mixed}
 	 */
 	public function daoToSchema(array $dao): array {
 		return [
-			'name'    => $dao['name'],
-			'type'    => strtolower($dao['type']),
-			'notnull' => $dao['notnull'] === '1' ? true : false,
+			'name'    => (string)$dao['name'],
+			'type'    => strtolower((string)$dao['type']),
+			'notnull' => $dao['notnull'] == '1' ? true : false,
 			'default' => $dao['dflt_value'],
 		];
 	}

+ 9 - 9
app/Models/Entry.php

@@ -156,9 +156,9 @@ class FreshRSS_Entry extends Minz_Model {
 
 		$content = $this->content;
 
-		$thumbnail = $this->attributes('thumbnail');
-		if (!empty($thumbnail['url'])) {
-			$elink = $thumbnail['url'];
+		$thumbnailAttribute = $this->attributes('thumbnail');
+		if (!empty($thumbnailAttribute['url'])) {
+			$elink = $thumbnailAttribute['url'];
 			if ($allowDuplicateEnclosures || !self::containsLink($content, $elink)) {
 			$content .= <<<HTML
 <figure class="enclosure">
@@ -243,7 +243,7 @@ HTML;
 			if ($searchEnclosures || $searchBodyImages) {
 				$dom = new DOMDocument();
 				$dom->loadHTML('<?xml version="1.0" encoding="UTF-8" ?>' . $this->content, LIBXML_NONET | LIBXML_NOERROR | LIBXML_NOWARNING);
-				$xpath = new DOMXpath($dom);
+				$xpath = new DOMXPath($dom);
 			}
 			if ($searchEnclosures) {
 				// Legacy code for database entries < FreshRSS 1.20.1
@@ -522,10 +522,10 @@ HTML;
 				// Searches are combined by OR and are not recursive
 				$ok = true;
 				if ($filter->getEntryIds()) {
-					$ok &= in_array($this->id, $filter->getEntryIds());
+					$ok &= in_array($this->id, $filter->getEntryIds(), true);
 				}
 				if ($ok && $filter->getNotEntryIds()) {
-					$ok &= !in_array($this->id, $filter->getNotEntryIds());
+					$ok &= !in_array($this->id, $filter->getNotEntryIds(), true);
 				}
 				if ($ok && $filter->getMinDate()) {
 					$ok &= strnatcmp($this->id, $filter->getMinDate() . '000000') >= 0;
@@ -552,10 +552,10 @@ HTML;
 					$ok &= $this->date > $filter->getNotMaxPubdate();
 				}
 				if ($ok && $filter->getFeedIds()) {
-					$ok &= in_array($this->feedId, $filter->getFeedIds());
+					$ok &= in_array($this->feedId, $filter->getFeedIds(), true);
 				}
 				if ($ok && $filter->getNotFeedIds()) {
-					$ok &= !in_array($this->feedId, $filter->getFeedIds());
+					$ok &= !in_array($this->feedId, $filter->getFeedIds(), true);
 				}
 				if ($ok && $filter->getAuthor()) {
 					foreach ($filter->getAuthor() as $author) {
@@ -719,7 +719,7 @@ HTML;
 							$filterednode->parentNode->removeChild($filterednode);
 						}
 					}
-					$content .= $doc->saveHtml($node) . "\n";
+					$content .= $doc->saveHTML($node) . "\n";
 				}
 			}
 			$html = trim(sanitizeHTML($content, $base));

+ 1 - 1
app/Models/EntryDAOSQLite.php

@@ -27,7 +27,7 @@ class FreshRSS_EntryDAOSQLite extends FreshRSS_EntryDAO {
 		if ($tableInfo = $this->pdo->query("PRAGMA table_info('entry')")) {
 			$columns = $tableInfo->fetchAll(PDO::FETCH_COLUMN, 1) ?: [];
 			foreach (['attributes'] as $column) {
-				if (!in_array($column, $columns)) {
+				if (!in_array($column, $columns, true)) {
 					return $this->addColumn($column);
 				}
 			}

+ 4 - 4
app/Models/Feed.php

@@ -504,7 +504,7 @@ class FreshRSS_Feed extends Minz_Model {
 					$text = html_only_entity_decode($category->get_label());
 					//Some feeds use a single category with comma-separated tags
 					$labels = explode(',', $text);
-					if (is_array($labels)) {
+					if (!empty($labels)) {
 						foreach ($labels as $label) {
 							$tags[] = trim($label);
 						}
@@ -892,7 +892,7 @@ class FreshRSS_Feed extends Minz_Model {
 	 */
 	public function _filtersAction(string $action, array $filters): void {
 		$action = trim($action);
-		if ($action == '' || !is_array($filters)) {
+		if ($action == '') {
 			return;
 		}
 		$filters = array_unique(array_map('trim', $filters));
@@ -969,8 +969,8 @@ class FreshRSS_Feed extends Minz_Model {
 		$hubFilename = PSHB_PATH . '/feeds/' . sha1($url) . '/!hub.json';
 		$hubFile = @file_get_contents($hubFilename);
 		$hubJson = $hubFile ? json_decode($hubFile, true) : array();
-		if (!isset($hubJson['error']) || $hubJson['error'] !== (bool)$error) {
-			$hubJson['error'] = (bool)$error;
+		if (!isset($hubJson['error']) || $hubJson['error'] !== $error) {
+			$hubJson['error'] = $error;
 			file_put_contents($hubFilename, json_encode($hubJson));
 			Minz_Log::warning('Set error to ' . ($error ? 1 : 0) . ' for ' . $url, PSHB_LOG);
 		}

+ 1 - 5
app/Models/FeedDAO.php

@@ -585,10 +585,6 @@ SQL;
 	public static function daoToFeed(array $listDAO, ?int $catID = null): array {
 		$list = array();
 
-		if (!is_array($listDAO)) {
-			$listDAO = array($listDAO);
-		}
-
 		foreach ($listDAO as $key => $dao) {
 			if (!isset($dao['name'])) {
 				continue;
@@ -611,7 +607,7 @@ SQL;
 			$myFeed->_lastUpdate($dao['lastUpdate'] ?? 0);
 			$myFeed->_priority($dao['priority'] ?? 10);
 			$myFeed->_pathEntries($dao['pathEntries'] ?? '');
-			$myFeed->_httpAuth(base64_decode($dao['httpAuth'] ?? ''));
+			$myFeed->_httpAuth(base64_decode($dao['httpAuth'] ?? '', true) ?: '');
 			$myFeed->_error($dao['error'] ?? 0);
 			$myFeed->_ttl($dao['ttl'] ?? FreshRSS_Feed::TTL_DEFAULT);
 			$myFeed->_attributes('', $dao['attributes'] ?? '');

+ 1 - 1
app/Models/FeedDAOSQLite.php

@@ -7,7 +7,7 @@ class FreshRSS_FeedDAOSQLite extends FreshRSS_FeedDAO {
 		if ($tableInfo = $this->pdo->query("PRAGMA table_info('feed')")) {
 			$columns = $tableInfo->fetchAll(PDO::FETCH_COLUMN, 1);
 			foreach (['attributes', 'kind'] as $column) {
-				if (!in_array($column, $columns)) {
+				if (!in_array($column, $columns, true)) {
 					return $this->addColumn($column);
 				}
 			}

+ 1 - 1
app/Models/FormAuth.php

@@ -21,7 +21,7 @@ class FreshRSS_FormAuth {
 		}
 
 		$token_file = DATA_PATH . '/tokens/' . $token . '.txt';
-		$mtime = @filemtime($token_file);
+		$mtime = @filemtime($token_file) ?: 0;
 		$limits = FreshRSS_Context::$system_conf->limits;
 		$cookie_duration = empty($limits['cookie_duration']) ? FreshRSS_Auth::DEFAULT_COOKIE_DURATION : $limits['cookie_duration'];
 		if ($mtime + $cookie_duration < time()) {

+ 2 - 2
app/Models/Search.php

@@ -142,7 +142,7 @@ class FreshRSS_Search {
 		return $this->label_ids;
 	}
 	/** @return array<int>|'*'|null */
-	public function getNotlabelIds() {
+	public function getNotLabelIds() {
 		return $this->not_label_ids;
 	}
 	/** @return array<string>|null */
@@ -150,7 +150,7 @@ class FreshRSS_Search {
 		return $this->label_names;
 	}
 	/** @return array<string>|null */
-	public function getNotlabelNames(): ?array {
+	public function getNotLabelNames(): ?array {
 		return $this->not_label_names;
 	}
 

+ 3 - 3
app/Models/Share.php

@@ -137,11 +137,11 @@ class FreshRSS_Share {
 		$this->isDeprecated = $isDeprecated;
 		$this->transforms = $transforms;
 
-		if (!in_array($form_type, array('simple', 'advanced'))) {
+		if (!in_array($form_type, ['simple', 'advanced'], true)) {
 			$form_type = 'simple';
 		}
 		$this->form_type = $form_type;
-		if (!in_array($method, array('GET', 'POST'))) {
+		if (!in_array($method, ['GET', 'POST'], true)) {
 			$method = 'GET';
 		}
 		$this->method = $method;
@@ -304,7 +304,7 @@ class FreshRSS_Share {
 	 * @return string the transformed data.
 	 */
 	private static function transform(string $data, array $transform): string {
-		if (!is_array($transform) || empty($transform)) {
+		if (empty($transform)) {
 			return $data;
 		}
 

+ 1 - 1
app/Models/StatsDAO.php

@@ -58,7 +58,7 @@ SQL;
 	 */
 	public function calculateEntryCount(): array {
 		$count = $this->initEntryCountArray();
-		$midnight = mktime(0, 0, 0);
+		$midnight = mktime(0, 0, 0) ?: 0;
 		$oldest = $midnight - (self::ENTRY_COUNT_PERIOD * 86400);
 
 		// Get stats per day for the last 30 days

+ 1 - 1
app/Models/TagDAO.php

@@ -378,7 +378,7 @@ INNER JOIN `_entrytag` et ON et.id_tag = t.id
 SQL;
 
 		$values = array();
-		if (is_array($entries) && count($entries) > 0) {
+		if (count($entries) > 0) {
 			if (count($entries) > FreshRSS_DatabaseDAO::MAX_VARIABLE_NUMBER) {
 				// Split a query with too many variables parameters
 				$idsChunks = array_chunk($entries, FreshRSS_DatabaseDAO::MAX_VARIABLE_NUMBER);

+ 1 - 1
app/actualize_script.php

@@ -42,7 +42,7 @@ function notice(string $message): void {
 // Avoid having multiple actualization processes at the same time
 $mutexFile = TMP_PATH . '/actualize.freshrss.lock';
 $mutexTtl = 900; // seconds (refreshed before each new feed)
-if (file_exists($mutexFile) && ((time() - @filemtime($mutexFile)) > $mutexTtl)) {
+if (file_exists($mutexFile) && ((time() - (@filemtime($mutexFile) ?: 0)) > $mutexTtl)) {
 	unlink($mutexFile);
 }
 

+ 3 - 3
app/install.php

@@ -31,7 +31,7 @@ function initTranslate(): void {
 		Minz_Session::_param('language', get_best_language());
 	}
 
-	if (!in_array(Minz_Session::param('language'), $available_languages)) {
+	if (!in_array(Minz_Session::param('language'), $available_languages, true)) {
 		Minz_Session::_param('language', 'en');
 	}
 
@@ -265,7 +265,7 @@ function checkStep(): void {
 /** @return array<string,string> */
 function checkStep0(): array {
 	$languages = Minz_Translate::availableLanguages();
-	$language = Minz_Session::param('language') != '' && in_array(Minz_Session::param('language'), $languages);
+	$language = Minz_Session::param('language') != '' && in_array(Minz_Session::param('language'), $languages, true);
 	$sessionWorking = Minz_Session::param('sessionWorking') === 'ok';
 
 	return array(
@@ -565,7 +565,7 @@ function printStep2(): void {
 }
 
 function no_auth(string $auth_type): bool {
-	return !in_array($auth_type, array('form', 'http_auth', 'none'));
+	return !in_array($auth_type, ['form', 'http_auth', 'none'], true);
 }
 
 function printStep3(): void {

+ 2 - 2
app/layout/aside_feed.phtml

@@ -46,7 +46,7 @@
 
 		<?php
 			$t_active = FreshRSS_Context::isCurrentGet('T');
-			$t_show = ($t_active && in_array(FreshRSS_Context::$user_conf->display_categories, [ 'active', 'remember' ])) || FreshRSS_Context::$user_conf->display_categories === 'all';
+			$t_show = ($t_active && in_array(FreshRSS_Context::$user_conf->display_categories, ['active', 'remember'], true)) || FreshRSS_Context::$user_conf->display_categories === 'all';
 		?>
 		<li id="tags" class="tree-folder category tags<?= $t_active ? ' active' : '' ?>" data-unread="<?= format_number($this->nbUnreadTags) ?>">
 			<div class="tree-folder-title">
@@ -81,7 +81,7 @@
 				$position = $cat->attributes('position');
 				if (!empty($feeds)) {
 					$c_active = FreshRSS_Context::isCurrentGet('c_' . $cat->id());
-					$c_show = ($c_active && in_array(FreshRSS_Context::$user_conf->display_categories, [ 'active', 'remember' ]))
+					$c_show = ($c_active && in_array(FreshRSS_Context::$user_conf->display_categories, ['active', 'remember'], true))
 						|| FreshRSS_Context::$user_conf->display_categories === 'all';
 		?>
 		<li id="c_<?= $cat->id() ?>" class="tree-folder category<?= $c_active ? ' active' : '' ?>"<?=

+ 1 - 1
app/layout/header.phtml

@@ -20,7 +20,7 @@
 					placeholder="<?= _t('gen.menu.search') ?>" />
 
 				<?php $param_a = Minz_Request::actionName(); ?>
-				<?php if (in_array($param_a, ['normal', 'global', 'reader'])) { ?>
+				<?php if (in_array($param_a, ['normal', 'global', 'reader'], true)) { ?>
 				<input type="hidden" name="a" value="<?= $param_a ?>" />
 				<?php } ?>
 

+ 1 - 1
app/layout/nav_menu.phtml

@@ -40,7 +40,7 @@
 					<span>
 						<form action="<?= _url('index', 'index') ?>" method="get">
 							<?php $param_a = Minz_Request::actionName(); ?>
-							<?php if (in_array($param_a, ['normal', 'global', 'reader'])) { ?>
+							<?php if (in_array($param_a, ['normal', 'global', 'reader'], true)) { ?>
 							<input type="hidden" name="a" value="<?= $param_a ?>" />
 							<?php } ?>
 

+ 1 - 1
app/views/auth/index.phtml

@@ -16,7 +16,7 @@
 			<label class="group-name" for="auth_type"><?= _t('admin.auth.type') ?></label>
 			<div class="group-controls">
 				<select id="auth_type" name="auth_type" required="required" data-leave-validation="<?= FreshRSS_Context::$system_conf->auth_type ?>">
-					<?php if (!in_array(FreshRSS_Context::$system_conf->auth_type, array('form', 'http_auth', 'none'))) { ?>
+					<?php if (!in_array(FreshRSS_Context::$system_conf->auth_type, ['form', 'http_auth', 'none'], true)) { ?>
 						<option selected="selected"></option>
 					<?php } ?>
 					<option value="form"<?= FreshRSS_Context::$system_conf->auth_type === 'form' ? ' selected="selected"' : '',

+ 6 - 6
app/views/helpers/logs_pagination.phtml

@@ -18,13 +18,13 @@
 
 		<?php $params[$getteur] = $this->currentPage - 1; ?>
 
-		
+
 		<li class="item pager-previous">
 			<?php if ($this->currentPage > 1) { ?>
 			<a href="<?= Minz_Url::display(array('c' => $c, 'a' => $a, 'params' => $params)) ?>">‹ <?= _t('conf.logs.pagination.previous') ?></a>
 			<?php } ?>
 		</li>
-		
+
 
 		<?php if ($this->currentPage - 2 > 1) { ?>
 		<li class="item">…</a></li>
@@ -32,7 +32,7 @@
 
 		<?php
 		for ($i = $this->currentPage - 2; $i <= $this->currentPage + 2; $i++) {
-			if($i > 0 && $i <= $this->nbPage) {
+			if ($i > 0 && $i <= $this->nbPage) {
 				$params[$getteur] = $i;
 				if ($i != $this->currentPage) {
 					$class = '';
@@ -46,18 +46,18 @@
 			}
 		} ?>
 
-		<?php if ($this->nbPage > $i - 1) { ?>
+		<?php if ($this->nbPage > $this->currentPage + 2) { ?>
 		<li class="item">…</a></li>
 		<?php } ?>
 
 		<?php $params[$getteur] = $this->currentPage + 1; ?>
-		
+
 		<li class="item pager-next">
 			<?php if ($this->currentPage < $this->nbPage) { ?>
 			<a href="<?= Minz_Url::display(array('c' => $c, 'a' => $a, 'params' => $params)) ?>"><?= _t('conf.logs.pagination.next') ?> ›</a>
 			<?php } ?>
 		</li>
-		
+
 		<?php $params[$getteur] = $this->nbPage; ?>
 		<li class="item pager-last">
 			<a href="<?= Minz_Url::display(array('c' => $c, 'a' => $a, 'params' => $params)) ?>"><?= _t('conf.logs.pagination.last') ?> »</a>

+ 1 - 1
cli/_cli.php

@@ -61,7 +61,7 @@ function performRequirementCheck(string $databaseType): void {
 	if ($requirements['all'] !== 'ok') {
 		$message = 'FreshRSS failed requirements:' . "\n";
 		foreach ($requirements as $requirement => $check) {
-			if ($check !== 'ok' && !in_array($requirement, array('all', 'pdo', 'message'))) {
+			if ($check !== 'ok' && !in_array($requirement, ['all', 'pdo', 'message'], true)) {
 				$message .= '• ' . $requirement . "\n";
 			}
 		}

+ 1 - 1
cli/do-install.php

@@ -80,7 +80,7 @@ if (!FreshRSS_user_Controller::checkUsername($options['default_user'])) {
 		. '”! Must be matching ' . FreshRSS_user_Controller::USERNAME_PATTERN);
 }
 
-if (isset($options['auth_type']) && !in_array($options['auth_type'], array('form', 'http_auth', 'none'))) {
+if (isset($options['auth_type']) && !in_array($options['auth_type'], ['form', 'http_auth', 'none'], true)) {
 	fail('FreshRSS invalid authentication method (auth_type must be one of { form, http_auth, none })');
 }
 

+ 1 - 1
cli/i18n/I18nData.php

@@ -236,7 +236,7 @@ class I18nData {
 	 * @throws Exception
 	 */
 	public function addValue(string $key, string $value, string $language): void {
-		if (!in_array($language, $this->getAvailableLanguages())) {
+		if (!in_array($language, $this->getAvailableLanguages(), true)) {
 			throw new Exception('The selected language does not exist.');
 		}
 		if (!array_key_exists($this->getFilenamePrefix($key), $this->data[static::REFERENCE_LANGUAGE]) ||

+ 2 - 2
cli/i18n/I18nUsageValidator.php

@@ -42,10 +42,10 @@ class I18nUsageValidator implements I18nValidatorInterface {
 		foreach ($this->reference as $file => $data) {
 			foreach ($data as $key => $value) {
 				$this->totalEntries++;
-				if (preg_match('/\._$/', $key) && in_array(preg_replace('/\._$/', '', $key), $this->code)) {
+				if (preg_match('/\._$/', $key) && in_array(preg_replace('/\._$/', '', $key), $this->code, true)) {
 					continue;
 				}
-				if (!in_array($key, $this->code)) {
+				if (!in_array($key, $this->code, true)) {
 					$this->result .= sprintf('Unused key %s - %s', $key, $value) . PHP_EOL;
 					$this->failedEntries++;
 					continue;

+ 1 - 1
cli/i18n/I18nValue.php

@@ -24,7 +24,7 @@ class I18nValue {
 		}
 
 		$state = array_shift($data);
-		if (in_array($state, self::STATES)) {
+		if (in_array($state, self::STATES, true)) {
 			$this->state = $state;
 		}
 	}

+ 1 - 1
cli/manipulate.translation.php

@@ -28,7 +28,7 @@ switch ($options['a']) {
 			$i18nData->addKey($options['k'], $options['v']);
 		} elseif (array_key_exists('l', $options)) {
 			$reference = null;
-			if (array_key_exists('o', $options) && is_string($options['o'])) {
+			if (array_key_exists('o', $options)) {
 				$reference = $options['o'];
 			}
 			$i18nData->addLanguage($options['l'], $reference);

+ 1 - 1
cli/reconfigure.php

@@ -59,7 +59,7 @@ if (!FreshRSS_user_Controller::checkUsername(FreshRSS_Context::$system_conf->def
 }
 
 if (isset(FreshRSS_Context::$system_conf->auth_type) &&
-	!in_array(FreshRSS_Context::$system_conf->auth_type, array('form', 'http_auth', 'none'))) {
+	!in_array(FreshRSS_Context::$system_conf->auth_type, ['form', 'http_auth', 'none'], true)) {
 	fail('FreshRSS invalid authentication method (auth_type must be one of { form, http_auth, none }: '
 		. FreshRSS_Context::$system_conf->auth_type);
 }

+ 1 - 1
cli/user-info.php

@@ -77,7 +77,7 @@ foreach ($users as $username) {
 		'reads' => (int)$nbEntries['read'],
 		'unreads' => (int)$nbEntries['unread'],
 		'favourites' => (int)$nbFavorites['all'],
-		'tags' => (int)$tagDAO->count(),
+		'tags' => $tagDAO->count(),
 		'lang' => FreshRSS_Context::$user_conf->language,
 		'mail_login' => FreshRSS_Context::$user_conf->mail_login,
 	);

+ 2 - 1
composer.json

@@ -49,8 +49,9 @@
         "ext-phar": "*",
         "ext-tokenizer": "*",
         "ext-xmlwriter": "*",
-        "phpstan/phpstan": "~1.10.14",
+        "phpstan/phpstan": "~1.10.15",
         "phpstan/phpstan-phpunit": "^1.3",
+        "phpstan/phpstan-strict-rules": "^1.5",
         "phpunit/phpunit": "^9",
         "squizlabs/php_codesniffer": "^3.7"
     },

+ 61 - 12
composer.lock

@@ -4,7 +4,7 @@
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
         "This file is @generated automatically"
     ],
-    "content-hash": "da6b81a8eb4aee9bc11ee8cc1707f018",
+    "content-hash": "c4967eaef46b8a5ffedabb60f795498f",
     "packages": [],
     "packages-dev": [
         {
@@ -305,16 +305,16 @@
         },
         {
             "name": "phpstan/phpstan",
-            "version": "1.10.14",
+            "version": "1.10.15",
             "source": {
                 "type": "git",
                 "url": "https://github.com/phpstan/phpstan.git",
-                "reference": "d232901b09e67538e5c86a724be841bea5768a7c"
+                "reference": "762c4dac4da6f8756eebb80e528c3a47855da9bd"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/phpstan/phpstan/zipball/d232901b09e67538e5c86a724be841bea5768a7c",
-                "reference": "d232901b09e67538e5c86a724be841bea5768a7c",
+                "url": "https://api.github.com/repos/phpstan/phpstan/zipball/762c4dac4da6f8756eebb80e528c3a47855da9bd",
+                "reference": "762c4dac4da6f8756eebb80e528c3a47855da9bd",
                 "shasum": ""
             },
             "require": {
@@ -363,7 +363,7 @@
                     "type": "tidelift"
                 }
             ],
-            "time": "2023-04-19T13:47:27+00:00"
+            "time": "2023-05-09T15:28:01+00:00"
         },
         {
             "name": "phpstan/phpstan-phpunit",
@@ -417,6 +417,55 @@
             },
             "time": "2023-03-25T19:42:13+00:00"
         },
+        {
+            "name": "phpstan/phpstan-strict-rules",
+            "version": "1.5.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/phpstan/phpstan-strict-rules.git",
+                "reference": "b21c03d4f6f3a446e4311155f4be9d65048218e6"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/b21c03d4f6f3a446e4311155f4be9d65048218e6",
+                "reference": "b21c03d4f6f3a446e4311155f4be9d65048218e6",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^7.2 || ^8.0",
+                "phpstan/phpstan": "^1.10"
+            },
+            "require-dev": {
+                "nikic/php-parser": "^4.13.0",
+                "php-parallel-lint/php-parallel-lint": "^1.2",
+                "phpstan/phpstan-deprecation-rules": "^1.1",
+                "phpstan/phpstan-phpunit": "^1.0",
+                "phpunit/phpunit": "^9.5"
+            },
+            "type": "phpstan-extension",
+            "extra": {
+                "phpstan": {
+                    "includes": [
+                        "rules.neon"
+                    ]
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "PHPStan\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "description": "Extra strict and opinionated rules for PHPStan",
+            "support": {
+                "issues": "https://github.com/phpstan/phpstan-strict-rules/issues",
+                "source": "https://github.com/phpstan/phpstan-strict-rules/tree/1.5.1"
+            },
+            "time": "2023-03-29T14:47:40+00:00"
+        },
         {
             "name": "phpunit/php-code-coverage",
             "version": "9.2.26",
@@ -1138,16 +1187,16 @@
         },
         {
             "name": "sebastian/diff",
-            "version": "4.0.4",
+            "version": "4.0.5",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/diff.git",
-                "reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d"
+                "reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/3461e3fccc7cfdfc2720be910d3bd73c69be590d",
-                "reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d",
+                "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/74be17022044ebaaecfdf0c5cd504fc9cd5a7131",
+                "reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131",
                 "shasum": ""
             },
             "require": {
@@ -1192,7 +1241,7 @@
             ],
             "support": {
                 "issues": "https://github.com/sebastianbergmann/diff/issues",
-                "source": "https://github.com/sebastianbergmann/diff/tree/4.0.4"
+                "source": "https://github.com/sebastianbergmann/diff/tree/4.0.5"
             },
             "funding": [
                 {
@@ -1200,7 +1249,7 @@
                     "type": "github"
                 }
             ],
-            "time": "2020-10-26T13:10:38+00:00"
+            "time": "2023-05-07T05:35:17+00:00"
         },
         {
             "name": "sebastian/environment",

+ 1 - 1
lib/Minz/Extension.php

@@ -153,7 +153,7 @@ abstract class Minz_Extension {
 
 	/** @param 'user'|'system' $type */
 	private function setType(string $type): void {
-		if (!in_array($type, ['user', 'system'])) {
+		if (!in_array($type, ['user', 'system'], true)) {
 			throw new Minz_ExtensionException('invalid `type` info', $this->name);
 		}
 		$this->type = $type;

+ 2 - 1
lib/Minz/ExtensionManager.php

@@ -324,7 +324,7 @@ final class Minz_ExtensionManager {
 	 *
 	 * @param string $hook_name the hook to call.
 	 * @param mixed ...$args additional parameters (for signature, please see self::$hook_list).
-	 * @return mixed|null final result of the called hook.
+	 * @return mixed|void|null final result of the called hook.
 	 */
 	public static function callHook(string $hook_name, ...$args) {
 		if (!isset(self::$hook_list[$hook_name])) {
@@ -343,6 +343,7 @@ final class Minz_ExtensionManager {
 		} elseif ($signature === 'NoneToNone') {
 			self::callNoneToNone($hook_name);
 		}
+		return;
 	}
 
 	/**

+ 1 - 1
lib/Minz/Migrator.php

@@ -250,7 +250,7 @@ class Minz_Migrator
 	public function migrate(): array {
 		$result = [];
 		foreach ($this->migrations() as $version => $callback) {
-			if (in_array($version, $this->applied_versions)) {
+			if (in_array($version, $this->applied_versions, true)) {
 				// the version is already applied so we skip this migration
 				continue;
 			}

+ 7 - 6
lib/Minz/Pdo.php

@@ -49,14 +49,15 @@ abstract class Minz_Pdo extends PDO {
 
 	// PHP8+: PDO::prepare(string $query, array $options = []): PDOStatement|false
 	/**
-	 * @param string $statement
-	 * @param array<int,string>|null $driver_options
+	 * @param string $query
+	 * @param array<int,string>|null $options
 	 * @return PDOStatement|false
+	 * @phpstan-ignore-next-line
 	 */
 	#[\ReturnTypeWillChange]
-	public function prepare($statement, $driver_options = []) {
-		$statement = $this->preSql($statement);
-		return parent::prepare($statement, $driver_options);
+	public function prepare($query, $options = []) {
+		$query = $this->preSql($query);
+		return parent::prepare($query, $options);
 	}
 
 	// PHP8+: PDO::exec(string $statement): int|false
@@ -74,6 +75,6 @@ abstract class Minz_Pdo extends PDO {
 	#[\ReturnTypeWillChange]
 	public function query(string $query, ?int $fetch_mode = null, ...$fetch_mode_args) {
 		$query = $this->preSql($query);
-		return $fetch_mode ? parent::query($query, $fetch_mode, ...$fetch_mode_args) : parent::query($query);
+		return $fetch_mode === null ? parent::query($query) : parent::query($query, $fetch_mode, ...$fetch_mode_args);
 	}
 }

+ 2 - 2
lib/Minz/Request.php

@@ -310,14 +310,14 @@ class Minz_Request {
 			return false;
 		}
 
-		$is_public = !in_array($host, array(
+		$is_public = !in_array($host, [
 			'localhost',
 			'localhost.localdomain',
 			'[::1]',
 			'ip6-localhost',
 			'localhost6',
 			'localhost6.localdomain6',
-		));
+		], true);
 
 		if ($is_public) {
 			$is_public &= !preg_match('/^(10|127|172[.]16|192[.]168)[.]/', $host);

+ 3 - 5
lib/Minz/Translate.php

@@ -76,9 +76,7 @@ class Minz_Translate {
 					$scan,
 					array('..', '.')
 				));
-				if (is_array($path_langs)) {
-					$list_langs = array_merge($list_langs, $path_langs);
-				}
+				$list_langs = array_merge($list_langs, $path_langs);
 			}
 		}
 
@@ -107,7 +105,7 @@ class Minz_Translate {
 			}
 		}
 
-		return $default ? $default : 'en';
+		return $default == null ? 'en' : $default;
 	}
 
 	/**
@@ -115,7 +113,7 @@ class Minz_Translate {
 	 * @param string $path a path containing i18n directories (e.g. ./en/, ./fr/).
 	 */
 	public static function registerPath(string $path): void {
-		if (!in_array($path, self::$path_list) && is_dir($path)) {
+		if (!in_array($path, self::$path_list, true) && is_dir($path)) {
 			self::$path_list[] = $path;
 			self::loadLang($path);
 		}

+ 1 - 1
lib/Minz/Url.php

@@ -137,7 +137,7 @@ class Minz_Url {
 	 */
 	public static function unserialize(string $url = ''): array {
 		try {
-			return json_decode(base64_decode($url), true, JSON_THROW_ON_ERROR) ?? [];
+			return json_decode(base64_decode($url, true) ?: '', true, JSON_THROW_ON_ERROR) ?? [];
 		} catch (\Throwable $exception) {
 			return [];
 		}

+ 1 - 1
lib/Minz/View.php

@@ -161,7 +161,7 @@ class Minz_View {
 	 * @param string|null $layout the layout name to use, false to use no layouts.
 	 */
 	public function _layout(?string $layout): void {
-		if ($layout) {
+		if ($layout != null) {
 			$this->layout_filename = self::LAYOUT_PATH_NAME . $layout . '.phtml';
 		} else {
 			$this->layout_filename = '';

+ 0 - 1
lib/composer.json

@@ -11,7 +11,6 @@
         }
     ],
     "require": {
-        "php": ">=7.2.0",
         "marienfressinaud/lib_opml": "0.5.1",
         "phpgt/cssxpath": "dev-master#4fbe420aba3d9e729940107ded4236a835a1a132",
         "phpmailer/phpmailer": "6.6.0"

+ 5 - 4
lib/lib_rss.php

@@ -224,7 +224,7 @@ function html_only_entity_decode(?string $text): string {
 function sensitive_log($log) {
 	if (is_array($log)) {
 		foreach ($log as $k => $v) {
-			if (in_array($k, ['api_key', 'Passwd', 'T'])) {
+			if (in_array($k, ['api_key', 'Passwd', 'T'], true)) {
 				$log[$k] = '██';
 			} elseif (is_array($v) || is_string($v)) {
 				$log[$k] = sensitive_log($v);
@@ -331,7 +331,7 @@ function customSimplePie(array $attributes = array()): SimplePie {
 
 /** @param string $data */
 function sanitizeHTML(string $data, string $base = '', ?int $maxLength = null): string {
-	if (!is_string($data) || ($maxLength !== null && $maxLength <= 0)) {
+	if ($data === '' || ($maxLength !== null && $maxLength <= 0)) {
 		return '';
 	}
 	if ($maxLength !== null) {
@@ -851,8 +851,9 @@ function errorMessageInfo(string $errorTitle, string $error = ''): string {
 
 	$message = '';
 	$details = '';
-	// Prevent empty tags by checking if error isn not empty first
-	if ($error) {
+	$error = trim($error);
+	// Prevent empty tags by checking if error is not empty first
+	if ($error !== '') {
 		$error = htmlspecialchars($error, ENT_NOQUOTES, 'UTF-8') . "\n";
 
 		// First line is the main message, other lines are the details

+ 5 - 5
p/api/greader.php

@@ -759,9 +759,9 @@ final class GReaderAPI {
 			$ids = [ 0 ];	//For News+ bug https://github.com/noinnion/newsplus/issues/84#issuecomment-57834632
 		}
 		$itemRefs = array();
-		foreach ($ids as $id) {
+		foreach ($ids as $entryId) {
 			$itemRefs[] = array(
-				'id' => '' . $id,	//64-bit decimal
+				'id' => '' . $entryId,	//64-bit decimal
 			);
 		}
 
@@ -769,9 +769,9 @@ final class GReaderAPI {
 			'itemRefs' => $itemRefs,
 		);
 		if (count($ids) >= $count) {
-			$id = end($ids);
-			if ($id != false) {
-				$response['continuation'] = '' . $id;
+			$entryId = end($ids);
+			if ($entryId != false) {
+				$response['continuation'] = '' . $entryId;
 			}
 		}
 

+ 16 - 0
phpstan.neon

@@ -26,11 +26,27 @@ parameters:
 		- COPY_SYSLOG_TO_STDERR
 		- DATA_PATH
 		- MAX_LOG_SIZE
+		- PUBLIC_RELATIVE
 		- SIMPLEPIE_SYSLOG_ENABLED
 		- STDERR
 		- STDOUT
 		- TMP_PATH
 		- USERS_PATH
+	strictRules:
+		allRules: false
+		booleansInConditions: false	# TODO pass
+		closureUsesThis: true
+		disallowedConstructs: false
+		disallowedLooseComparison: false
+		matchingInheritedMethodNames: true
+		noVariableVariables: false	# TODO pass
+		numericOperandsInArithmeticOperators: true
+		overwriteVariablesWithLoop: true
+		requireParentConstructorCall: true
+		strictCalls: true
+		switchConditionsMatchingType: true
+		uselessCast: true
 includes:
 	- vendor/phpstan/phpstan-phpunit/extension.neon
 	- vendor/phpstan/phpstan-phpunit/rules.neon
+	- vendor/phpstan/phpstan-strict-rules/rules.neon

+ 17 - 16
tests/app/Models/CategoryTest.php

@@ -4,8 +4,8 @@ class CategoryTest extends PHPUnit\Framework\TestCase {
 
 	public function test__construct_whenNoParameters_createsObjectWithDefaultValues(): void {
 		$category = new FreshRSS_Category();
-		$this->assertEquals(0, $category->id());
-		$this->assertEquals('', $category->name());
+		self::assertEquals(0, $category->id());
+		self::assertEquals('', $category->name());
 	}
 
 	/**
@@ -13,7 +13,7 @@ class CategoryTest extends PHPUnit\Framework\TestCase {
 	 */
 	public function test_name_whenValidValue_storesModifiedValue(string $input, string $expected): void {
 		$category = new FreshRSS_Category($input);
-		$this->assertEquals($expected, $category->name());
+		self::assertEquals($expected, $category->name());
 	}
 
 	/** @return array<array{string,string}> */
@@ -33,21 +33,21 @@ class CategoryTest extends PHPUnit\Framework\TestCase {
 		$feed_1 = $this->getMockBuilder(FreshRSS_Feed::class)
 			->disableOriginalConstructor()
 			->getMock();
-		$feed_1->expects($this->any())
+		$feed_1->expects(self::any())
 			->method('name')
 			->willReturn('AAA');
 
 		$feed_2 = $this->getMockBuilder(FreshRSS_Feed::class)
 			->disableOriginalConstructor()
 			->getMock();
-		$feed_2->expects($this->any())
+		$feed_2->expects(self::any())
 			->method('name')
 			->willReturn('ZZZ');
 
 		$feed_3 = $this->getMockBuilder(FreshRSS_Feed::class)
 			->disableOriginalConstructor()
 			->getMock();
-		$feed_3->expects($this->any())
+		$feed_3->expects(self::any())
 			->method('name')
 			->willReturn('lll');
 
@@ -58,25 +58,26 @@ class CategoryTest extends PHPUnit\Framework\TestCase {
 		]);
 		$feeds = $category->feeds();
 
-		$this->assertCount(3, $feeds);
-		$this->assertEquals('AAA', $feeds[0]->name());
-		$this->assertEquals('lll', $feeds[1]->name());
-		$this->assertEquals('ZZZ', $feeds[2]->name());
+		self::assertCount(3, $feeds);
+		self::assertEquals('AAA', $feeds[0]->name());
+		self::assertEquals('lll', $feeds[1]->name());
+		self::assertEquals('ZZZ', $feeds[2]->name());
 
+		/** @var FreshRSS_Feed&PHPUnit\Framework\MockObject\MockObject */
 		$feed_4 = $this->getMockBuilder(FreshRSS_Feed::class)
 			->disableOriginalConstructor()
 			->getMock();
-		$feed_4->expects($this->any())
+		$feed_4->expects(self::any())
 			->method('name')
 			->willReturn('BBB');
 
 		$category->addFeed($feed_4);
 		$feeds = $category->feeds();
 
-		$this->assertCount(4, $feeds);
-		$this->assertEquals('AAA', $feeds[0]->name());
-		$this->assertEquals('BBB', $feeds[1]->name());
-		$this->assertEquals('lll', $feeds[2]->name());
-		$this->assertEquals('ZZZ', $feeds[3]->name());
+		self::assertCount(4, $feeds);
+		self::assertEquals('AAA', $feeds[0]->name());
+		self::assertEquals('BBB', $feeds[1]->name());
+		self::assertEquals('lll', $feeds[2]->name());
+		self::assertEquals('ZZZ', $feeds[3]->name());
 	}
 }

+ 8 - 8
tests/app/Models/LogDAOTest.php

@@ -23,20 +23,20 @@ class LogDAOTest extends TestCase {
 	}
 
 	public function test_lines_is_array_and_truncate_function_work(): void {
-		$this->assertEquals(USERS_PATH . '/' . Minz_User::INTERNAL_USER . '/' . self::LOG_FILE_TEST, $this->logPath);
+		self::assertEquals(USERS_PATH . '/' . Minz_User::INTERNAL_USER . '/' . self::LOG_FILE_TEST, $this->logPath);
 
 		$line = $this->logDAO::lines(self::LOG_FILE_TEST);
 
-		$this->assertIsArray($line);
-		$this->assertCount(1, $line);
-		$this->assertInstanceOf(FreshRSS_Log::class, $line[0]);
-		$this->assertEquals('Wed, 08 Feb 2023 15:35:05 +0000', $line[0]->date());
-		$this->assertEquals('notice', $line[0]->level());
-		$this->assertEquals("Migration 2019_12_22_FooBar: OK", $line[0]->info());
+		self::assertIsArray($line);
+		self::assertCount(1, $line);
+		self::assertInstanceOf(FreshRSS_Log::class, $line[0]);
+		self::assertEquals('Wed, 08 Feb 2023 15:35:05 +0000', $line[0]->date());
+		self::assertEquals('notice', $line[0]->level());
+		self::assertEquals("Migration 2019_12_22_FooBar: OK", $line[0]->info());
 
 		$this->logDAO::truncate(self::LOG_FILE_TEST);
 
-		$this->assertStringContainsString('', file_get_contents($this->logPath) ?: '');
+		self::assertStringContainsString('', file_get_contents($this->logPath) ?: '');
 	}
 
 	protected function tearDown(): void {

+ 33 - 33
tests/app/Models/SearchTest.php

@@ -9,15 +9,15 @@ class SearchTest extends PHPUnit\Framework\TestCase {
 	 */
 	public function test__construct_whenInputIsEmpty_getsOnlyNullValues(?string $input): void {
 		$search = new FreshRSS_Search($input);
-		$this->assertEquals('', $search->getRawInput());
-		$this->assertNull($search->getIntitle());
-		$this->assertNull($search->getMinDate());
-		$this->assertNull($search->getMaxDate());
-		$this->assertNull($search->getMinPubdate());
-		$this->assertNull($search->getMaxPubdate());
-		$this->assertNull($search->getAuthor());
-		$this->assertNull($search->getTags());
-		$this->assertNull($search->getSearch());
+		self::assertEquals('', $search->getRawInput());
+		self::assertNull($search->getIntitle());
+		self::assertNull($search->getMinDate());
+		self::assertNull($search->getMaxDate());
+		self::assertNull($search->getMinPubdate());
+		self::assertNull($search->getMaxPubdate());
+		self::assertNull($search->getAuthor());
+		self::assertNull($search->getTags());
+		self::assertNull($search->getSearch());
 	}
 
 	/**
@@ -39,8 +39,8 @@ class SearchTest extends PHPUnit\Framework\TestCase {
 	 */
 	public function test__construct_whenInputContainsIntitle_setsIntitleProperty(string $input, ?array $intitle_value, ?array $search_value): void {
 		$search = new FreshRSS_Search($input);
-		$this->assertEquals($intitle_value, $search->getIntitle());
-		$this->assertEquals($search_value, $search->getSearch());
+		self::assertEquals($intitle_value, $search->getIntitle());
+		self::assertEquals($search_value, $search->getSearch());
 	}
 
 	/**
@@ -76,8 +76,8 @@ class SearchTest extends PHPUnit\Framework\TestCase {
 	 */
 	public function test__construct_whenInputContainsAuthor_setsAuthorValue(string $input, ?array $author_value, ?array $search_value): void {
 		$search = new FreshRSS_Search($input);
-		$this->assertEquals($author_value, $search->getAuthor());
-		$this->assertEquals($search_value, $search->getSearch());
+		self::assertEquals($author_value, $search->getAuthor());
+		self::assertEquals($search_value, $search->getSearch());
 	}
 
 	/**
@@ -113,8 +113,8 @@ class SearchTest extends PHPUnit\Framework\TestCase {
 	 */
 	public function test__construct_whenInputContainsInurl_setsInurlValue(string $input, ?array $inurl_value, ?array $search_value): void {
 		$search = new FreshRSS_Search($input);
-		$this->assertEquals($inurl_value, $search->getInurl());
-		$this->assertEquals($search_value, $search->getSearch());
+		self::assertEquals($inurl_value, $search->getInurl());
+		self::assertEquals($search_value, $search->getSearch());
 	}
 
 	/**
@@ -138,8 +138,8 @@ class SearchTest extends PHPUnit\Framework\TestCase {
 	 */
 	public function test__construct_whenInputContainsDate_setsDateValues(string $input, ?int $min_date_value, ?int $max_date_value): void {
 		$search = new FreshRSS_Search($input);
-		$this->assertEquals($min_date_value, $search->getMinDate());
-		$this->assertEquals($max_date_value, $search->getMaxDate());
+		self::assertEquals($min_date_value, $search->getMinDate());
+		self::assertEquals($max_date_value, $search->getMaxDate());
 	}
 
 	/**
@@ -161,8 +161,8 @@ class SearchTest extends PHPUnit\Framework\TestCase {
 	 */
 	public function test__construct_whenInputContainsPubdate_setsPubdateValues(string $input, ?int $min_pubdate_value, ?int $max_pubdate_value): void {
 		$search = new FreshRSS_Search($input);
-		$this->assertEquals($min_pubdate_value, $search->getMinPubdate());
-		$this->assertEquals($max_pubdate_value, $search->getMaxPubdate());
+		self::assertEquals($min_pubdate_value, $search->getMinPubdate());
+		self::assertEquals($max_pubdate_value, $search->getMaxPubdate());
 	}
 
 	/**
@@ -186,8 +186,8 @@ class SearchTest extends PHPUnit\Framework\TestCase {
 	 */
 	public function test__construct_whenInputContainsTags_setsTagsValue(string $input, ?array $tags_value, ?array $search_value): void {
 		$search = new FreshRSS_Search($input);
-		$this->assertEquals($tags_value, $search->getTags());
-		$this->assertEquals($search_value, $search->getSearch());
+		self::assertEquals($tags_value, $search->getTags());
+		self::assertEquals($search_value, $search->getSearch());
 	}
 
 	/**
@@ -218,16 +218,16 @@ class SearchTest extends PHPUnit\Framework\TestCase {
 			?int $max_date_value, ?array $intitle_value, ?array $inurl_value, ?int $min_pubdate_value,
 			?int $max_pubdate_value, ?array $tags_value, ?array $search_value): void {
 		$search = new FreshRSS_Search($input);
-		$this->assertEquals($author_value, $search->getAuthor());
-		$this->assertEquals($min_date_value, $search->getMinDate());
-		$this->assertEquals($max_date_value, $search->getMaxDate());
-		$this->assertEquals($intitle_value, $search->getIntitle());
-		$this->assertEquals($inurl_value, $search->getInurl());
-		$this->assertEquals($min_pubdate_value, $search->getMinPubdate());
-		$this->assertEquals($max_pubdate_value, $search->getMaxPubdate());
-		$this->assertEquals($tags_value, $search->getTags());
-		$this->assertEquals($search_value, $search->getSearch());
-		$this->assertEquals($input, $search->getRawInput());
+		self::assertEquals($author_value, $search->getAuthor());
+		self::assertEquals($min_date_value, $search->getMinDate());
+		self::assertEquals($max_date_value, $search->getMaxDate());
+		self::assertEquals($intitle_value, $search->getIntitle());
+		self::assertEquals($inurl_value, $search->getInurl());
+		self::assertEquals($min_pubdate_value, $search->getMinPubdate());
+		self::assertEquals($max_pubdate_value, $search->getMaxPubdate());
+		self::assertEquals($tags_value, $search->getTags());
+		self::assertEquals($search_value, $search->getSearch());
+		self::assertEquals($input, $search->getRawInput());
 	}
 
 	/** @return array<array<mixed>> */
@@ -290,8 +290,8 @@ class SearchTest extends PHPUnit\Framework\TestCase {
 	 */
 	public function test__construct_parentheses(string $input, string $sql, array $values): void {
 		list($filterValues, $filterSearch) = FreshRSS_EntryDAOPGSQL::sqlBooleanSearch('e.', new FreshRSS_BooleanSearch($input));
-		$this->assertEquals($sql, $filterSearch);
-		$this->assertEquals($values, $filterValues);
+		self::assertEquals($sql, $filterSearch);
+		self::assertEquals($values, $filterValues);
 	}
 
 	/** @return array<array<mixed>> */

+ 37 - 39
tests/app/Models/UserQueryTest.php

@@ -8,15 +8,15 @@ class UserQueryTest extends PHPUnit\Framework\TestCase {
 	public function test__construct_whenAllQuery_storesAllParameters(): void {
 		$query = array('get' => 'a');
 		$user_query = new FreshRSS_UserQuery($query);
-		$this->assertEquals('all', $user_query->getGetName());
-		$this->assertEquals('all', $user_query->getGetType());
+		self::assertEquals('all', $user_query->getGetName());
+		self::assertEquals('all', $user_query->getGetType());
 	}
 
 	public function test__construct_whenFavoriteQuery_storesFavoriteParameters(): void {
 		$query = array('get' => 's');
 		$user_query = new FreshRSS_UserQuery($query);
-		$this->assertEquals('favorite', $user_query->getGetName());
-		$this->assertEquals('favorite', $user_query->getGetType());
+		self::assertEquals('favorite', $user_query->getGetName());
+		self::assertEquals('favorite', $user_query->getGetType());
 	}
 
 	public function test__construct_whenCategoryQueryAndNoDao_throwsException(): void {
@@ -31,20 +31,20 @@ class UserQueryTest extends PHPUnit\Framework\TestCase {
 		$category_name = 'some category name';
 		/** @var FreshRSS_Category&PHPUnit\Framework\MockObject\MockObject */
 		$cat = $this->createMock(FreshRSS_Category::class);
-		$cat->expects($this->atLeastOnce())
+		$cat->expects(self::atLeastOnce())
 			->method('name')
 			->withAnyParameters()
 			->willReturn($category_name);
 		/** @var FreshRSS_CategoryDAO&PHPUnit\Framework\MockObject\MockObject */
 		$cat_dao = $this->createMock(FreshRSS_CategoryDAO::class);
-		$cat_dao->expects($this->atLeastOnce())
+		$cat_dao->expects(self::atLeastOnce())
 			->method('searchById')
 			->withAnyParameters()
 			->willReturn($cat);
 		$query = array('get' => 'c_1');
 		$user_query = new FreshRSS_UserQuery($query, null, $cat_dao);
-		$this->assertEquals($category_name, $user_query->getGetName());
-		$this->assertEquals('category', $user_query->getGetType());
+		self::assertEquals($category_name, $user_query->getGetName());
+		self::assertEquals('category', $user_query->getGetType());
 	}
 
 	public function test__construct_whenFeedQueryAndNoDao_throwsException(): void {
@@ -59,61 +59,60 @@ class UserQueryTest extends PHPUnit\Framework\TestCase {
 		$feed_name = 'some feed name';
 		/** @var FreshRSS_Feed&PHPUnit\Framework\MockObject\MockObject */
 		$feed = $this->createMock(FreshRSS_Feed::class);
-		$feed->expects($this->atLeastOnce())
+		$feed->expects(self::atLeastOnce())
 			->method('name')
 			->withAnyParameters()
 			->willReturn($feed_name);
 		/** @var FreshRSS_FeedDAO&PHPUnit\Framework\MockObject\MockObject */
 		$feed_dao = $this->createMock(FreshRSS_FeedDAO::class);
-		$feed_dao->expects($this->atLeastOnce())
+		$feed_dao->expects(self::atLeastOnce())
 			->method('searchById')
 			->withAnyParameters()
 			->willReturn($feed);
 		$query = array('get' => 'f_1');
 		$user_query = new FreshRSS_UserQuery($query, $feed_dao, null);
-		$this->assertEquals($feed_name, $user_query->getGetName());
-		$this->assertEquals('feed', $user_query->getGetType());
+		self::assertEquals($feed_name, $user_query->getGetName());
+		self::assertEquals('feed', $user_query->getGetType());
 	}
 
 	public function test__construct_whenUnknownQuery_doesStoreParameters(): void {
 		$query = array('get' => 'q');
 		$user_query = new FreshRSS_UserQuery($query);
-		$this->assertEmpty($user_query->getGetName());
-		$this->assertEmpty($user_query->getGetType());
+		self::assertEmpty($user_query->getGetName());
+		self::assertEmpty($user_query->getGetType());
 	}
 
 	public function test__construct_whenName_storesName(): void {
 		$name = 'some name';
 		$query = array('name' => $name);
 		$user_query = new FreshRSS_UserQuery($query);
-		$this->assertEquals($name, $user_query->getName());
+		self::assertEquals($name, $user_query->getName());
 	}
 
 	public function test__construct_whenOrder_storesOrder(): void {
 		$order = 'some order';
 		$query = array('order' => $order);
 		$user_query = new FreshRSS_UserQuery($query);
-		$this->assertEquals($order, $user_query->getOrder());
+		self::assertEquals($order, $user_query->getOrder());
 	}
 
 	public function test__construct_whenState_storesState(): void {
 		$state = FreshRSS_Entry::STATE_ALL;
 		$query = array('state' => $state);
 		$user_query = new FreshRSS_UserQuery($query);
-		$this->assertEquals($state, $user_query->getState());
+		self::assertEquals($state, $user_query->getState());
 	}
 
 	public function test__construct_whenUrl_storesUrl(): void {
 		$url = 'some url';
 		$query = array('url' => $url);
 		$user_query = new FreshRSS_UserQuery($query);
-		$this->assertEquals($url, $user_query->getUrl());
+		self::assertEquals($url, $user_query->getUrl());
 	}
 
 	public function testToArray_whenNoData_returnsEmptyArray(): void {
 		$user_query = new FreshRSS_UserQuery(array());
-		$this->assertIsIterable($user_query->toArray());
-		$this->assertCount(0, $user_query->toArray());
+		self::assertCount(0, $user_query->toArray());
 	}
 
 	public function testToArray_whenData_returnsArray(): void {
@@ -126,9 +125,8 @@ class UserQueryTest extends PHPUnit\Framework\TestCase {
 			'url' => 'some url',
 		);
 		$user_query = new FreshRSS_UserQuery($query);
-		$this->assertIsIterable($user_query->toArray());
-		$this->assertCount(6, $user_query->toArray());
-		$this->assertEquals($query, $user_query->toArray());
+		self::assertCount(6, $user_query->toArray());
+		self::assertEquals($query, $user_query->toArray());
 	}
 
 	public function testHasSearch_whenSearch_returnsTrue(): void {
@@ -136,30 +134,30 @@ class UserQueryTest extends PHPUnit\Framework\TestCase {
 			'search' => 'some search',
 		);
 		$user_query = new FreshRSS_UserQuery($query);
-		$this->assertTrue($user_query->hasSearch());
+		self::assertTrue($user_query->hasSearch());
 	}
 
 	public function testHasSearch_whenNoSearch_returnsFalse(): void {
 		$user_query = new FreshRSS_UserQuery(array());
-		$this->assertFalse($user_query->hasSearch());
+		self::assertFalse($user_query->hasSearch());
 	}
 
 	public function testHasParameters_whenAllQuery_returnsFalse(): void {
 		$query = array('get' => 'a');
 		$user_query = new FreshRSS_UserQuery($query);
-		$this->assertFalse($user_query->hasParameters());
+		self::assertFalse($user_query->hasParameters());
 	}
 
 	public function testHasParameters_whenNoParameter_returnsFalse(): void {
 		$query = array();
 		$user_query = new FreshRSS_UserQuery($query);
-		$this->assertFalse($user_query->hasParameters());
+		self::assertFalse($user_query->hasParameters());
 	}
 
 	public function testHasParameters_whenParameter_returnTrue(): void {
 		$query = array('get' => 's');
 		$user_query = new FreshRSS_UserQuery($query);
-		$this->assertTrue($user_query->hasParameters());
+		self::assertTrue($user_query->hasParameters());
 	}
 
 	public function testIsDeprecated_whenCategoryExists_returnFalse(): void {
@@ -167,25 +165,25 @@ class UserQueryTest extends PHPUnit\Framework\TestCase {
 		$cat = $this->createMock(FreshRSS_Category::class);
 		/** @var FreshRSS_CategoryDAO&PHPUnit\Framework\MockObject\MockObject */
 		$cat_dao = $this->createMock(FreshRSS_CategoryDAO::class);
-		$cat_dao->expects($this->atLeastOnce())
+		$cat_dao->expects(self::atLeastOnce())
 			->method('searchById')
 			->withAnyParameters()
 			->willReturn($cat);
 		$query = array('get' => 'c_1');
 		$user_query = new FreshRSS_UserQuery($query, null, $cat_dao);
-		$this->assertFalse($user_query->isDeprecated());
+		self::assertFalse($user_query->isDeprecated());
 	}
 
 	public function testIsDeprecated_whenCategoryDoesNotExist_returnTrue(): void {
 		/** @var FreshRSS_CategoryDAO&PHPUnit\Framework\MockObject\MockObject */
 		$cat_dao = $this->createMock(FreshRSS_CategoryDAO::class);
-		$cat_dao->expects($this->atLeastOnce())
+		$cat_dao->expects(self::atLeastOnce())
 			->method('searchById')
 			->withAnyParameters()
 			->willReturn(null);
 		$query = array('get' => 'c_1');
 		$user_query = new FreshRSS_UserQuery($query, null, $cat_dao);
-		$this->assertTrue($user_query->isDeprecated());
+		self::assertTrue($user_query->isDeprecated());
 	}
 
 	public function testIsDeprecated_whenFeedExists_returnFalse(): void {
@@ -193,43 +191,43 @@ class UserQueryTest extends PHPUnit\Framework\TestCase {
 		$feed = $this->createMock(FreshRSS_Feed::class);
 		/** @var FreshRSS_FeedDAO&PHPUnit\Framework\MockObject\MockObject */
 		$feed_dao = $this->createMock(FreshRSS_FeedDAO::class);
-		$feed_dao->expects($this->atLeastOnce())
+		$feed_dao->expects(self::atLeastOnce())
 			->method('searchById')
 			->withAnyParameters()
 			->willReturn($feed);
 		$query = array('get' => 'f_1');
 		$user_query = new FreshRSS_UserQuery($query, $feed_dao, null);
-		$this->assertFalse($user_query->isDeprecated());
+		self::assertFalse($user_query->isDeprecated());
 	}
 
 	public function testIsDeprecated_whenFeedDoesNotExist_returnTrue(): void {
 		/** @var FreshRSS_FeedDAO&PHPUnit\Framework\MockObject\MockObject */
 		$feed_dao = $this->createMock(FreshRSS_FeedDAO::class);
-		$feed_dao->expects($this->atLeastOnce())
+		$feed_dao->expects(self::atLeastOnce())
 			->method('searchById')
 			->withAnyParameters()
 			->willReturn(null);
 		$query = array('get' => 'f_1');
 		$user_query = new FreshRSS_UserQuery($query, $feed_dao, null);
-		$this->assertTrue($user_query->isDeprecated());
+		self::assertTrue($user_query->isDeprecated());
 	}
 
 	public function testIsDeprecated_whenAllQuery_returnFalse(): void {
 		$query = array('get' => 'a');
 		$user_query = new FreshRSS_UserQuery($query);
-		$this->assertFalse($user_query->isDeprecated());
+		self::assertFalse($user_query->isDeprecated());
 	}
 
 	public function testIsDeprecated_whenFavoriteQuery_returnFalse(): void {
 		$query = array('get' => 's');
 		$user_query = new FreshRSS_UserQuery($query);
-		$this->assertFalse($user_query->isDeprecated());
+		self::assertFalse($user_query->isDeprecated());
 	}
 
 	public function testIsDeprecated_whenUnknownQuery_returnFalse(): void {
 		$query = array('get' => 'q');
 		$user_query = new FreshRSS_UserQuery($query);
-		$this->assertFalse($user_query->isDeprecated());
+		self::assertFalse($user_query->isDeprecated());
 	}
 
 }

+ 3 - 3
tests/app/Utils/passwordUtilTest.php

@@ -6,7 +6,7 @@ class passwordUtilTest extends PHPUnit\Framework\TestCase {
 
 		$ok = FreshRSS_password_Util::check($password);
 
-		$this->assertTrue($ok);
+		self::assertTrue($ok);
 	}
 
 	public function testCheckReturnsFalseIfEmpty(): void {
@@ -14,7 +14,7 @@ class passwordUtilTest extends PHPUnit\Framework\TestCase {
 
 		$ok = FreshRSS_password_Util::check($password);
 
-		$this->assertFalse($ok);
+		self::assertFalse($ok);
 	}
 
 	public function testCheckReturnsFalseIfLessThan7Characters(): void {
@@ -22,6 +22,6 @@ class passwordUtilTest extends PHPUnit\Framework\TestCase {
 
 		$ok = FreshRSS_password_Util::check($password);
 
-		$this->assertFalse($ok);
+		self::assertFalse($ok);
 	}
 }

+ 19 - 19
tests/cli/i18n/I18nCompletionValidatorTest.php

@@ -16,23 +16,23 @@ class I18nCompletionValidatorTest extends PHPUnit\Framework\TestCase {
 	public function testDisplayReport(): void {
 		$validator = new I18nCompletionValidator([], []);
 
-		$this->assertEquals("There is no data.\n", $validator->displayReport());
+		self::assertEquals("There is no data.\n", $validator->displayReport());
 
 		$reflectionTotalEntries = new ReflectionProperty(I18nCompletionValidator::class, 'totalEntries');
 		$reflectionTotalEntries->setAccessible(true);
 		$reflectionTotalEntries->setValue($validator, 100);
 
-		$this->assertEquals("Translation is   0.0% complete.\n", $validator->displayReport());
+		self::assertEquals("Translation is   0.0% complete.\n", $validator->displayReport());
 
 		$reflectionPassEntries = new ReflectionProperty(I18nCompletionValidator::class, 'passEntries');
 		$reflectionPassEntries->setAccessible(true);
 		$reflectionPassEntries->setValue($validator, 25);
 
-		$this->assertEquals("Translation is  25.0% complete.\n", $validator->displayReport());
+		self::assertEquals("Translation is  25.0% complete.\n", $validator->displayReport());
 
 		$reflectionPassEntries->setValue($validator, 100);
 
-		$this->assertEquals("Translation is 100.0% complete.\n", $validator->displayReport());
+		self::assertEquals("Translation is 100.0% complete.\n", $validator->displayReport());
 
 		$reflectionPassEntries->setValue($validator, 200);
 
@@ -43,8 +43,8 @@ class I18nCompletionValidatorTest extends PHPUnit\Framework\TestCase {
 
 	public function testValidateWhenNoData(): void {
 		$validator = new I18nCompletionValidator([], []);
-		$this->assertTrue($validator->validate());
-		$this->assertEquals('', $validator->displayResult());
+		self::assertTrue($validator->validate());
+		self::assertEquals('', $validator->displayResult());
 	}
 
 	public function testValidateWhenKeyIsMissing(): void {
@@ -57,12 +57,12 @@ class I18nCompletionValidatorTest extends PHPUnit\Framework\TestCase {
 			],
 		], []);
 
-		$this->assertFalse($validator->validate());
-		$this->assertEquals("Missing key file1.l1.l2.k1\nMissing key file2.l1.l2.k1\n", $validator->displayResult());
+		self::assertFalse($validator->validate());
+		self::assertEquals("Missing key file1.l1.l2.k1\nMissing key file2.l1.l2.k1\n", $validator->displayResult());
 	}
 
 	public function testValidateWhenKeyIsIgnored(): void {
-		$this->value->expects($this->exactly(2))
+		$this->value->expects(self::exactly(2))
 			->method('isIgnore')
 			->willReturn(true);
 
@@ -82,15 +82,15 @@ class I18nCompletionValidatorTest extends PHPUnit\Framework\TestCase {
 			],
 		]);
 
-		$this->assertTrue($validator->validate());
-		$this->assertEquals('', $validator->displayResult());
+		self::assertTrue($validator->validate());
+		self::assertEquals('', $validator->displayResult());
 	}
 
 	public function testValidateWhenValueIsEqual(): void {
-		$this->value->expects($this->exactly(2))
+		$this->value->expects(self::exactly(2))
 			->method('isIgnore')
 			->willReturn(false);
-		$this->value->expects($this->exactly(2))
+		$this->value->expects(self::exactly(2))
 			->method('equal')
 			->willReturn(true);
 
@@ -110,15 +110,15 @@ class I18nCompletionValidatorTest extends PHPUnit\Framework\TestCase {
 			],
 		]);
 
-		$this->assertFalse($validator->validate());
-		$this->assertEquals("Untranslated key file1.l1.l2.k1 - \nUntranslated key file2.l1.l2.k1 - \n", $validator->displayResult());
+		self::assertFalse($validator->validate());
+		self::assertEquals("Untranslated key file1.l1.l2.k1 - \nUntranslated key file2.l1.l2.k1 - \n", $validator->displayResult());
 	}
 
 	public function testValidateWhenValueIsDifferent(): void {
-		$this->value->expects($this->exactly(2))
+		$this->value->expects(self::exactly(2))
 			->method('isIgnore')
 			->willReturn(false);
-		$this->value->expects($this->exactly(2))
+		$this->value->expects(self::exactly(2))
 			->method('equal')
 			->willReturn(false);
 
@@ -138,7 +138,7 @@ class I18nCompletionValidatorTest extends PHPUnit\Framework\TestCase {
 			],
 		]);
 
-		$this->assertTrue($validator->validate());
-		$this->assertEquals('', $validator->displayResult());
+		self::assertTrue($validator->validate());
+		self::assertEquals('', $validator->displayResult());
 	}
 }

+ 66 - 66
tests/cli/i18n/I18nDataTest.php

@@ -35,7 +35,7 @@ class I18nDataTest extends PHPUnit\Framework\TestCase {
 
 	public function testConstructWhenReferenceOnly(): void {
 		$data = new I18nData($this->referenceData);
-		$this->assertEquals($this->referenceData, $data->getData());
+		self::assertEquals($this->referenceData, $data->getData());
 	}
 
 	public function testConstructorWhenLanguageIsMissingFile(): void {
@@ -47,7 +47,7 @@ class I18nDataTest extends PHPUnit\Framework\TestCase {
 			],
 		]);
 		$data = new I18nData($rawData);
-		$this->assertEquals([
+		self::assertEquals([
 			'en' => [
 				'file1.php' => [
 					'file1.l1.l2.k1' => $this->value,
@@ -93,7 +93,7 @@ class I18nDataTest extends PHPUnit\Framework\TestCase {
 			],
 		]);
 		$data = new I18nData($rawData);
-		$this->assertEquals([
+		self::assertEquals([
 			'en' => [
 				'file1.php' => [
 					'file1.l1.l2.k1' => $this->value,
@@ -147,7 +147,7 @@ class I18nDataTest extends PHPUnit\Framework\TestCase {
 			],
 		]);
 		$data = new I18nData($rawData);
-		$this->assertEquals([
+		self::assertEquals([
 			'en' => [
 				'file1.php' => [
 					'file1.l1.l2.k1' => $this->value,
@@ -185,12 +185,12 @@ class I18nDataTest extends PHPUnit\Framework\TestCase {
 		$value = $this->getMockBuilder(I18nValue::class)
 			->disableOriginalConstructor()
 			->getMock();
-		$value->expects($this->exactly(2))
+		$value->expects(self::exactly(2))
 			->method('isIgnore')
 			->willReturn(true);
-		$value->expects($this->never())
+		$value->expects(self::never())
 			->method('markAsTodo');
-		$value->expects($this->exactly(3))
+		$value->expects(self::exactly(3))
 			->method('equal')
 			->with($value)
 			->willReturn(true);
@@ -210,12 +210,12 @@ class I18nDataTest extends PHPUnit\Framework\TestCase {
 		$value = $this->getMockBuilder(I18nValue::class)
 			->disableOriginalConstructor()
 			->getMock();
-		$value->expects($this->exactly(2))
+		$value->expects(self::exactly(2))
 			->method('isIgnore')
 			->willReturn(false);
-		$value->expects($this->exactly(2))
+		$value->expects(self::exactly(2))
 			->method('markAsTodo');
-		$value->expects($this->exactly(2))
+		$value->expects(self::exactly(2))
 			->method('equal')
 			->with($value)
 			->willReturn(true);
@@ -235,10 +235,10 @@ class I18nDataTest extends PHPUnit\Framework\TestCase {
 		$value = $this->getMockBuilder(I18nValue::class)
 			->disableOriginalConstructor()
 			->getMock();
-		$value->expects($this->once())
+		$value->expects(self::once())
 			->method('isTodo')
 			->willReturn(true);
-		$value->expects($this->once())
+		$value->expects(self::once())
 			->method('markAsDirty');
 
 		$rawData = array_merge($this->referenceData, [
@@ -255,10 +255,10 @@ class I18nDataTest extends PHPUnit\Framework\TestCase {
 		$value = $this->getMockBuilder(I18nValue::class)
 			->disableOriginalConstructor()
 			->getMock();
-		$value->expects($this->once())
+		$value->expects(self::once())
 			->method('isTodo')
 			->willReturn(false);
-		$value->expects($this->never())
+		$value->expects(self::never())
 			->method('markAsDirty');
 
 		$rawData = array_merge($this->referenceData, [
@@ -277,7 +277,7 @@ class I18nDataTest extends PHPUnit\Framework\TestCase {
 			'nl' => [],
 		]);
 		$data = new I18nData($rawData);
-		$this->assertEquals([
+		self::assertEquals([
 			'en',
 			'fr',
 			'nl',
@@ -291,7 +291,7 @@ class I18nDataTest extends PHPUnit\Framework\TestCase {
 			'de' => [],
 		]);
 		$data = new I18nData($rawData);
-		$this->assertEquals([
+		self::assertEquals([
 			'de',
 			'en',
 			'fr',
@@ -309,7 +309,7 @@ class I18nDataTest extends PHPUnit\Framework\TestCase {
 	public function testAddLanguageWhenNoReferenceProvided(): void {
 		$data = new I18nData($this->referenceData);
 		$data->addLanguage('fr');
-		$this->assertEquals([
+		self::assertEquals([
 			'en' => [
 				'file1.php' => [
 					'file1.l1.l2.k1' => $this->value,
@@ -346,7 +346,7 @@ class I18nDataTest extends PHPUnit\Framework\TestCase {
 	public function testAddLanguageWhenUnknownReferenceProvided(): void {
 		$data = new I18nData($this->referenceData);
 		$data->addLanguage('fr', 'unknown');
-		$this->assertEquals([
+		self::assertEquals([
 			'en' => [
 				'file1.php' => [
 					'file1.l1.l2.k1' => $this->value,
@@ -383,7 +383,7 @@ class I18nDataTest extends PHPUnit\Framework\TestCase {
 	public function testAddLanguageWhenKnownReferenceProvided(): void {
 		$data = new I18nData($this->referenceData);
 		$data->addLanguage('fr', 'en');
-		$this->assertEquals([
+		self::assertEquals([
 			'en' => [
 				'file1.php' => [
 					'file1.l1.l2.k1' => $this->value,
@@ -419,12 +419,12 @@ class I18nDataTest extends PHPUnit\Framework\TestCase {
 
 	public function testIsKnownWhenKeyExists(): void {
 		$data = new I18nData($this->referenceData);
-		$this->assertTrue($data->isKnown('file2.l1.l2.k2'));
+		self::assertTrue($data->isKnown('file2.l1.l2.k2'));
 	}
 
 	public function testIsKnownWhenKeyDoesNotExist(): void {
 		$data = new I18nData($this->referenceData);
-		$this->assertFalse($data->isKnown('file2.l1.l2.k3'));
+		self::assertFalse($data->isKnown('file2.l1.l2.k3'));
 	}
 
 	public function testAddKeyWhenKeyExists(): void {
@@ -440,13 +440,13 @@ class I18nDataTest extends PHPUnit\Framework\TestCase {
 		]);
 
 		$data = new I18nData($rawData);
-		$this->assertTrue($data->isKnown('file2.l1.l2.k1'));
-		$this->assertFalse($data->isKnown('file2.l1.l2.k1._'));
-		$this->assertFalse($data->isKnown('file2.l1.l2.k1.sk1'));
+		self::assertTrue($data->isKnown('file2.l1.l2.k1'));
+		self::assertFalse($data->isKnown('file2.l1.l2.k1._'));
+		self::assertFalse($data->isKnown('file2.l1.l2.k1.sk1'));
 		$data->addKey('file2.l1.l2.k1.sk1', 'value');
-		$this->assertFalse($data->isKnown('file2.l1.l2.k1'));
-		$this->assertTrue($data->isKnown('file2.l1.l2.k1._'));
-		$this->assertTrue($data->isKnown('file2.l1.l2.k1.sk1'));
+		self::assertFalse($data->isKnown('file2.l1.l2.k1'));
+		self::assertTrue($data->isKnown('file2.l1.l2.k1._'));
+		self::assertTrue($data->isKnown('file2.l1.l2.k1.sk1'));
 	}
 
 	public function testAddKeyWhenKeyIsParent(): void {
@@ -455,13 +455,13 @@ class I18nDataTest extends PHPUnit\Framework\TestCase {
 		]);
 
 		$data = new I18nData($rawData);
-		$this->assertFalse($data->isKnown('file1.l1.l2._'));
-		$this->assertTrue($data->isKnown('file1.l1.l2.k1'));
-		$this->assertTrue($data->isKnown('file1.l1.l2.k2'));
+		self::assertFalse($data->isKnown('file1.l1.l2._'));
+		self::assertTrue($data->isKnown('file1.l1.l2.k1'));
+		self::assertTrue($data->isKnown('file1.l1.l2.k2'));
 		$data->addKey('file1.l1.l2', 'value');
-		$this->assertTrue($data->isKnown('file1.l1.l2._'));
-		$this->assertTrue($data->isKnown('file1.l1.l2.k1'));
-		$this->assertTrue($data->isKnown('file1.l1.l2.k2'));
+		self::assertTrue($data->isKnown('file1.l1.l2._'));
+		self::assertTrue($data->isKnown('file1.l1.l2.k1'));
+		self::assertTrue($data->isKnown('file1.l1.l2.k2'));
 	}
 
 	public function testAddKey(): void {
@@ -474,16 +474,16 @@ class I18nDataTest extends PHPUnit\Framework\TestCase {
 		]);
 
 		$data = new I18nData($rawData);
-		$this->assertFalse($data->isKnown('file2.l1.l2.k3'));
+		self::assertFalse($data->isKnown('file2.l1.l2.k3'));
 		$data->addKey('file2.l1.l2.k3', 'value');
-		$this->assertTrue($data->isKnown('file2.l1.l2.k3'));
+		self::assertTrue($data->isKnown('file2.l1.l2.k3'));
 
 		$enValue = $getTargetedValue($data, 'en');
 		$frValue = $getTargetedValue($data, 'fr');
-		$this->assertInstanceOf(I18nValue::class, $enValue);
-		$this->assertEquals('value', $enValue->getValue());
-		$this->assertTrue($enValue->isTodo());
-		$this->assertEquals($frValue, $enValue);
+		self::assertInstanceOf(I18nValue::class, $enValue);
+		self::assertEquals('value', $enValue->getValue());
+		self::assertTrue($enValue->isTodo());
+		self::assertEquals($frValue, $enValue);
 	}
 
 	public function testAddValueWhenLanguageDoesNotExist(): void {
@@ -505,7 +505,7 @@ class I18nDataTest extends PHPUnit\Framework\TestCase {
 			return $data->getData()[$language]['file2.php']['file2.l1.l2.k2'];
 		};
 
-		$this->value->expects($this->atLeast(2))
+		$this->value->expects(self::atLeast(2))
 			->method('equal')
 			->with($this->value)
 			->willReturn(true);
@@ -520,12 +520,12 @@ class I18nDataTest extends PHPUnit\Framework\TestCase {
 		$afterEnValue = $getTargetedValue($data, 'en');
 		$afterFrValue = $getTargetedValue($data, 'fr');
 
-		$this->assertEquals($this->value, $beforeEnValue);
-		$this->assertEquals($this->value, $beforeFrValue);
-		$this->assertInstanceOf(I18nValue::class, $afterEnValue);
-		$this->assertEquals('new value', $afterEnValue->getValue());
-		$this->assertInstanceOf(I18nValue::class, $afterFrValue);
-		$this->assertEquals('new value', $afterFrValue->getValue());
+		self::assertEquals($this->value, $beforeEnValue);
+		self::assertEquals($this->value, $beforeFrValue);
+		self::assertInstanceOf(I18nValue::class, $afterEnValue);
+		self::assertEquals('new value', $afterEnValue->getValue());
+		self::assertInstanceOf(I18nValue::class, $afterFrValue);
+		self::assertEquals('new value', $afterFrValue->getValue());
 	}
 
 	public function testAddValueWhenLanguageIsReferenceAndValueInOtherLanguageHasChange(): void {
@@ -533,7 +533,7 @@ class I18nDataTest extends PHPUnit\Framework\TestCase {
 			return $data->getData()[$language]['file2.php']['file2.l1.l2.k2'];
 		};
 
-		$this->value->expects($this->any())
+		$this->value->expects(self::any())
 			->method('equal')
 			->with($this->value)
 			->willReturn(true);
@@ -556,11 +556,11 @@ class I18nDataTest extends PHPUnit\Framework\TestCase {
 		$afterEnValue = $getTargetedValue($data, 'en');
 		$afterFrValue = $getTargetedValue($data, 'fr');
 
-		$this->assertEquals($this->value, $beforeEnValue);
-		$this->assertEquals($value, $beforeFrValue);
-		$this->assertInstanceOf(I18nValue::class, $afterEnValue);
-		$this->assertEquals('new value', $afterEnValue->getValue());
-		$this->assertEquals($value, $afterFrValue);
+		self::assertEquals($this->value, $beforeEnValue);
+		self::assertEquals($value, $beforeFrValue);
+		self::assertInstanceOf(I18nValue::class, $afterEnValue);
+		self::assertEquals('new value', $afterEnValue->getValue());
+		self::assertEquals($value, $afterFrValue);
 	}
 
 	public function testAddValueWhenLanguageIsNotReference(): void {
@@ -578,11 +578,11 @@ class I18nDataTest extends PHPUnit\Framework\TestCase {
 		$afterEnValue = $getTargetedValue($data, 'en');
 		$afterFrValue = $getTargetedValue($data, 'fr');
 
-		$this->assertEquals($this->value, $beforeEnValue);
-		$this->assertEquals($this->value, $beforeFrValue);
-		$this->assertEquals($this->value, $afterEnValue);
-		$this->assertInstanceOf(I18nValue::class, $afterFrValue);
-		$this->assertEquals('new value', $afterFrValue->getValue());
+		self::assertEquals($this->value, $beforeEnValue);
+		self::assertEquals($this->value, $beforeFrValue);
+		self::assertEquals($this->value, $afterEnValue);
+		self::assertInstanceOf(I18nValue::class, $afterFrValue);
+		self::assertEquals('new value', $afterFrValue->getValue());
 	}
 
 	public function testRemoveKeyWhenKeyDoesNotExist(): void {
@@ -605,7 +605,7 @@ class I18nDataTest extends PHPUnit\Framework\TestCase {
 		]);
 		$data = new I18nData($rawData);
 		$data->removeKey('file2.l1.l2');
-		$this->assertEquals([
+		self::assertEquals([
 			'en' => [
 				'file1.php' => [
 					'file1.l1.l2.k1' => $this->value,
@@ -643,7 +643,7 @@ class I18nDataTest extends PHPUnit\Framework\TestCase {
 		]);
 		$data = new I18nData($rawData);
 		$data->removeKey('file3.l1.l2.k1');
-		$this->assertEquals([
+		self::assertEquals([
 			'en' => [
 				'file1.php' => [
 					'file1.l1.l2.k1' => $this->value,
@@ -679,9 +679,9 @@ class I18nDataTest extends PHPUnit\Framework\TestCase {
 		$value = $this->getMockBuilder(I18nValue::class)
 			->disableOriginalConstructor()
 			->getMock();
-		$value->expects($this->exactly(2))
+		$value->expects(self::exactly(2))
 			->method('unmarkAsIgnore');
-		$value->expects($this->once())
+		$value->expects(self::once())
 			->method('markAsIgnore');
 
 		$rawData = array_merge($this->referenceData, [
@@ -701,12 +701,12 @@ class I18nDataTest extends PHPUnit\Framework\TestCase {
 		$value = $this->getMockBuilder(I18nValue::class)
 			->disableOriginalConstructor()
 			->getMock();
-		$value->expects($this->exactly(2))
+		$value->expects(self::exactly(2))
 			->method('unmarkAsIgnore');
-			$value->expects($this->once())
+			$value->expects(self::once())
 			->method('markAsIgnore');
 
-		$this->value->expects($this->atLeast(2))
+		$this->value->expects(self::atLeast(2))
 			->method('equal')
 			->with($value)
 			->willReturn(true);
@@ -730,7 +730,7 @@ class I18nDataTest extends PHPUnit\Framework\TestCase {
 			'nl' => [],
 		]);
 		$data = new I18nData($rawData);
-		$this->assertEquals($this->referenceData['en'], $data->getLanguage('en'));
+		self::assertEquals($this->referenceData['en'], $data->getLanguage('en'));
 	}
 
 	public function testGetReferenceLanguage(): void {
@@ -739,6 +739,6 @@ class I18nDataTest extends PHPUnit\Framework\TestCase {
 			'nl' => [],
 		]);
 		$data = new I18nData($rawData);
-		$this->assertEquals($this->referenceData['en'], $data->getReferenceLanguage());
+		self::assertEquals($this->referenceData['en'], $data->getReferenceLanguage());
 	}
 }

+ 2 - 2
tests/cli/i18n/I18nFileTest.php

@@ -12,7 +12,7 @@ class I18nFileTest extends PHPUnit\Framework\TestCase {
 
 		$after = $this->computeFilesHash();
 
-		$this->assertEquals($before, $after);
+		self::assertEquals($before, $after);
 	}
 
 	/** @return array<string,string|false> */
@@ -30,7 +30,7 @@ class I18nFileTest extends PHPUnit\Framework\TestCase {
 					continue;
 				}
 
-				$hashes[$file->getPathName()] = sha1_file($file->getPathName());
+				$hashes[$file->getPathname()] = sha1_file($file->getPathname());
 			}
 		}
 

+ 16 - 16
tests/cli/i18n/I18nUsageValidatorTest.php

@@ -16,23 +16,23 @@ class I18nUsageValidatorTest extends PHPUnit\Framework\TestCase {
 	public function testDisplayReport(): void {
 		$validator = new I18nUsageValidator([], []);
 
-		$this->assertEquals("There is no data.\n", $validator->displayReport());
+		self::assertEquals("There is no data.\n", $validator->displayReport());
 
 		$reflectionTotalEntries = new ReflectionProperty(I18nUsageValidator::class, 'totalEntries');
 		$reflectionTotalEntries->setAccessible(true);
 		$reflectionTotalEntries->setValue($validator, 100);
 
-		$this->assertEquals("  0.0% of translation keys are unused.\n", $validator->displayReport());
+		self::assertEquals("  0.0% of translation keys are unused.\n", $validator->displayReport());
 
 		$reflectionFailedEntries = new ReflectionProperty(I18nUsageValidator::class, 'failedEntries');
 		$reflectionFailedEntries->setAccessible(true);
 		$reflectionFailedEntries->setValue($validator, 25);
 
-		$this->assertEquals(" 25.0% of translation keys are unused.\n", $validator->displayReport());
+		self::assertEquals(" 25.0% of translation keys are unused.\n", $validator->displayReport());
 
 		$reflectionFailedEntries->setValue($validator, 100);
 
-		$this->assertEquals("100.0% of translation keys are unused.\n", $validator->displayReport());
+		self::assertEquals("100.0% of translation keys are unused.\n", $validator->displayReport());
 
 		$reflectionFailedEntries->setValue($validator, 200);
 
@@ -43,8 +43,8 @@ class I18nUsageValidatorTest extends PHPUnit\Framework\TestCase {
 
 	public function testValidateWhenNoData(): void {
 		$validator = new I18nUsageValidator([], []);
-		$this->assertTrue($validator->validate());
-		$this->assertEquals('', $validator->displayResult());
+		self::assertTrue($validator->validate());
+		self::assertEquals('', $validator->displayResult());
 	}
 
 	public function testValidateWhenParentKeyExistsWithoutTransformation(): void {
@@ -59,8 +59,8 @@ class I18nUsageValidatorTest extends PHPUnit\Framework\TestCase {
 			'file1.l1.l2._',
 			'file2.l1.l2._',
 		]);
-		$this->assertTrue($validator->validate());
-		$this->assertEquals('', $validator->displayResult());
+		self::assertTrue($validator->validate());
+		self::assertEquals('', $validator->displayResult());
 	}
 
 	public function testValidateWhenParentKeyExistsWithTransformation(): void {
@@ -75,8 +75,8 @@ class I18nUsageValidatorTest extends PHPUnit\Framework\TestCase {
 			'file1.l1.l2',
 			'file2.l1.l2',
 		]);
-		$this->assertTrue($validator->validate());
-		$this->assertEquals('', $validator->displayResult());
+		self::assertTrue($validator->validate());
+		self::assertEquals('', $validator->displayResult());
 	}
 
 	public function testValidateWhenParentKeyDoesNotExist(): void {
@@ -88,8 +88,8 @@ class I18nUsageValidatorTest extends PHPUnit\Framework\TestCase {
 				'file2.l1.l2._' => $this->value,
 			],
 		], []);
-		$this->assertFalse($validator->validate());
-		$this->assertEquals("Unused key file1.l1.l2._ - \nUnused key file2.l1.l2._ - \n", $validator->displayResult());
+		self::assertFalse($validator->validate());
+		self::assertEquals("Unused key file1.l1.l2._ - \nUnused key file2.l1.l2._ - \n", $validator->displayResult());
 	}
 
 	public function testValidateWhenChildKeyExists(): void {
@@ -104,8 +104,8 @@ class I18nUsageValidatorTest extends PHPUnit\Framework\TestCase {
 			'file1.l1.l2.k1',
 			'file2.l1.l2.k1',
 		]);
-		$this->assertTrue($validator->validate());
-		$this->assertEquals('', $validator->displayResult());
+		self::assertTrue($validator->validate());
+		self::assertEquals('', $validator->displayResult());
 	}
 
 	public function testValidateWhenChildKeyDoesNotExist(): void {
@@ -117,7 +117,7 @@ class I18nUsageValidatorTest extends PHPUnit\Framework\TestCase {
 				'file2.l1.l2.k1' => $this->value,
 			],
 		], []);
-		$this->assertFalse($validator->validate());
-		$this->assertEquals("Unused key file1.l1.l2.k1 - \nUnused key file2.l1.l2.k1 - \n", $validator->displayResult());
+		self::assertFalse($validator->validate());
+		self::assertEquals("Unused key file1.l1.l2.k1 - \nUnused key file2.l1.l2.k1 - \n", $validator->displayResult());
 	}
 }

+ 30 - 30
tests/cli/i18n/I18nValueTest.php

@@ -5,55 +5,55 @@ require_once __DIR__ . '/../../../cli/i18n/I18nValue.php';
 class I18nValueTest extends PHPUnit\Framework\TestCase {
 	public function testConstructorWithoutState(): void {
 		$value = new I18nValue('some value');
-		$this->assertEquals('some value', $value->getValue());
-		$this->assertFalse($value->isIgnore());
-		$this->assertFalse($value->isTodo());
+		self::assertEquals('some value', $value->getValue());
+		self::assertFalse($value->isIgnore());
+		self::assertFalse($value->isTodo());
 	}
 
 	public function testConstructorWithUnknownState(): void {
 		$value = new I18nValue('some value -> unknown');
-		$this->assertEquals('some value', $value->getValue());
-		$this->assertFalse($value->isIgnore());
-		$this->assertFalse($value->isTodo());
+		self::assertEquals('some value', $value->getValue());
+		self::assertFalse($value->isIgnore());
+		self::assertFalse($value->isTodo());
 	}
 
 	public function testConstructorWithTodoState(): void {
 		$value = new I18nValue('some value -> todo');
-		$this->assertEquals('some value', $value->getValue());
-		$this->assertFalse($value->isIgnore());
-		$this->assertTrue($value->isTodo());
+		self::assertEquals('some value', $value->getValue());
+		self::assertFalse($value->isIgnore());
+		self::assertTrue($value->isTodo());
 	}
 
 	public function testConstructorWithIgnoreState(): void {
 		$value = new I18nValue('some value -> ignore');
-		$this->assertEquals('some value', $value->getValue());
-		$this->assertTrue($value->isIgnore());
-		$this->assertFalse($value->isTodo());
+		self::assertEquals('some value', $value->getValue());
+		self::assertTrue($value->isIgnore());
+		self::assertFalse($value->isTodo());
 	}
 
 	public function testClone(): void {
 		$value = new I18nValue('some value');
 		$clonedValue = clone $value;
-		$this->assertEquals('some value', $value->getValue());
-		$this->assertEquals('some value', $clonedValue->getValue());
-		$this->assertFalse($value->isIgnore());
-		$this->assertFalse($clonedValue->isIgnore());
-		$this->assertFalse($value->isTodo());
-		$this->assertTrue($clonedValue->isTodo());
+		self::assertEquals('some value', $value->getValue());
+		self::assertEquals('some value', $clonedValue->getValue());
+		self::assertFalse($value->isIgnore());
+		self::assertFalse($clonedValue->isIgnore());
+		self::assertFalse($value->isTodo());
+		self::assertTrue($clonedValue->isTodo());
 	}
 
 	public function testEqualWhenValueIsIdentical(): void {
 		$value = new I18nValue('some value');
 		$clonedValue = clone $value;
-		$this->assertTrue($value->equal($clonedValue));
-		$this->assertTrue($clonedValue->equal($value));
+		self::assertTrue($value->equal($clonedValue));
+		self::assertTrue($clonedValue->equal($value));
 	}
 
 	public function testEqualWhenValueIsDifferent(): void {
 		$value = new I18nValue('some value');
 		$otherValue = new I18nValue('some other value');
-		$this->assertFalse($value->equal($otherValue));
-		$this->assertFalse($otherValue->equal($value));
+		self::assertFalse($value->equal($otherValue));
+		self::assertFalse($otherValue->equal($value));
 	}
 
 	public function testStates(): void {
@@ -61,23 +61,23 @@ class I18nValueTest extends PHPUnit\Framework\TestCase {
 		$reflectionProperty->setAccessible(true);
 
 		$value = new I18nValue('some value');
-		$this->assertNull($reflectionProperty->getValue($value));
+		self::assertNull($reflectionProperty->getValue($value));
 		$value->markAsDirty();
-		$this->assertEquals('dirty', $reflectionProperty->getValue($value));
+		self::assertEquals('dirty', $reflectionProperty->getValue($value));
 		$value->unmarkAsIgnore();
-		$this->assertEquals('dirty', $reflectionProperty->getValue($value));
+		self::assertEquals('dirty', $reflectionProperty->getValue($value));
 		$value->markAsIgnore();
-		$this->assertEquals('ignore', $reflectionProperty->getValue($value));
+		self::assertEquals('ignore', $reflectionProperty->getValue($value));
 		$value->unmarkAsIgnore();
-		$this->assertNull($reflectionProperty->getValue($value));
+		self::assertNull($reflectionProperty->getValue($value));
 		$value->markAsTodo();
-		$this->assertEquals('todo', $reflectionProperty->getValue($value));
+		self::assertEquals('todo', $reflectionProperty->getValue($value));
 	}
 
 	public function testToString(): void {
 		$value = new I18nValue('some value');
-		$this->assertEquals('some value', $value->__toString());
+		self::assertEquals('some value', $value->__toString());
 		$value->markAsTodo();
-		$this->assertEquals('some value -> todo', $value->__toString());
+		self::assertEquals('some value -> todo', $value->__toString());
 	}
 }

+ 1 - 1
tests/lib/CssXPath/CssXPathTest.php

@@ -3,6 +3,6 @@
 class CssXPathTest extends PHPUnit\Framework\TestCase
 {
 	public function testCssXPathTranslatorClassExists(): void {
-		$this->assertTrue(class_exists('Gt\\CssXPath\\Translator'));
+		self::assertTrue(class_exists('Gt\\CssXPath\\Translator'));
 	}
 }

+ 42 - 42
tests/lib/Minz/MigratorTest.php

@@ -12,9 +12,9 @@ class MigratorTest extends TestCase
 		});
 
 		$migrations = $migrator->migrations();
-		$this->assertArrayHasKey('foo', $migrations);
+		self::assertArrayHasKey('foo', $migrations);
 		$result = $migrations['foo']();
-		$this->assertTrue($result);
+		self::assertTrue($result);
 	}
 
 	public function testAddMigrationFailsIfUncallableMigration(): void {
@@ -40,7 +40,7 @@ class MigratorTest extends TestCase
 
 		$migrations = $migrator->migrations();
 
-		$this->assertSame($expected_versions, array_keys($migrations));
+		self::assertSame($expected_versions, array_keys($migrations));
 	}
 
 	public function testSetAppliedVersions(): void {
@@ -51,7 +51,7 @@ class MigratorTest extends TestCase
 
 		$migrator->setAppliedVersions(['foo']);
 
-		$this->assertSame(['foo'], $migrator->appliedVersions());
+		self::assertSame(['foo'], $migrator->appliedVersions());
 	}
 
 	public function testSetAppliedVersionsTrimArgument(): void {
@@ -62,7 +62,7 @@ class MigratorTest extends TestCase
 
 		$migrator->setAppliedVersions(["foo\n"]);
 
-		$this->assertSame(['foo'], $migrator->appliedVersions());
+		self::assertSame(['foo'], $migrator->appliedVersions());
 	}
 
 	public function testSetAppliedVersionsFailsIfMigrationDoesNotExist(): void {
@@ -85,7 +85,7 @@ class MigratorTest extends TestCase
 
 		$versions = $migrator->versions();
 
-		$this->assertSame(['bar', 'foo'], $versions);
+		self::assertSame(['bar', 'foo'], $versions);
 	}
 
 	public function testMigrate(): void {
@@ -95,13 +95,13 @@ class MigratorTest extends TestCase
 			$spy = true;
 			return true;
 		});
-		$this->assertEmpty($migrator->appliedVersions());
+		self::assertEmpty($migrator->appliedVersions());
 
 		$result = $migrator->migrate();
 
-		$this->assertTrue($spy);
-		$this->assertSame(['foo'], $migrator->appliedVersions());
-		$this->assertSame([
+		self::assertTrue($spy);
+		self::assertSame(['foo'], $migrator->appliedVersions());
+		self::assertSame([
 			'foo' => true,
 		], $result);
 	}
@@ -119,8 +119,8 @@ class MigratorTest extends TestCase
 
 		$result = $migrator->migrate();
 
-		$this->assertSame(['1_foo', '2_foo'], $migrator->appliedVersions());
-		$this->assertSame([
+		self::assertSame(['1_foo', '2_foo'], $migrator->appliedVersions());
+		self::assertSame([
 			'1_foo' => true,
 			'2_foo' => true,
 		], $result);
@@ -137,8 +137,8 @@ class MigratorTest extends TestCase
 
 		$result = $migrator->migrate();
 
-		$this->assertFalse($spy);
-		$this->assertSame([], $result);
+		self::assertFalse($spy);
+		self::assertSame([], $result);
 	}
 
 	public function testMigrateCallNonAppliedBetweenTwoApplied(): void {
@@ -156,8 +156,8 @@ class MigratorTest extends TestCase
 
 		$result = $migrator->migrate();
 
-		$this->assertSame(['1_foo', '2_foo', '3_foo'], $migrator->appliedVersions());
-		$this->assertSame([
+		self::assertSame(['1_foo', '2_foo', '3_foo'], $migrator->appliedVersions());
+		self::assertSame([
 			'2_foo' => true,
 		], $result);
 	}
@@ -173,8 +173,8 @@ class MigratorTest extends TestCase
 
 		$result = $migrator->migrate();
 
-		$this->assertSame(['1_foo'], $migrator->appliedVersions());
-		$this->assertSame([
+		self::assertSame(['1_foo'], $migrator->appliedVersions());
+		self::assertSame([
 			'1_foo' => true,
 			'2_foo' => false,
 		], $result);
@@ -193,9 +193,9 @@ class MigratorTest extends TestCase
 
 		$result = $migrator->migrate();
 
-		$this->assertEmpty($migrator->appliedVersions());
-		$this->assertFalse($spy);
-		$this->assertSame([
+		self::assertEmpty($migrator->appliedVersions());
+		self::assertFalse($spy);
+		self::assertSame([
 			'1_foo' => false,
 		], $result);
 	}
@@ -208,8 +208,8 @@ class MigratorTest extends TestCase
 
 		$result = $migrator->migrate();
 
-		$this->assertEmpty($migrator->appliedVersions());
-		$this->assertSame([
+		self::assertEmpty($migrator->appliedVersions());
+		self::assertSame([
 			'foo' => 'Oops, it failed.',
 		], $result);
 	}
@@ -223,7 +223,7 @@ class MigratorTest extends TestCase
 
 		$upToDate = $migrator->upToDate();
 
-		$this->assertTrue($upToDate);
+		self::assertTrue($upToDate);
 	}
 
 	public function testUpToDateIfRemainingMigration(): void {
@@ -238,7 +238,7 @@ class MigratorTest extends TestCase
 
 		$upToDate = $migrator->upToDate();
 
-		$this->assertFalse($upToDate);
+		self::assertFalse($upToDate);
 	}
 
 	public function testUpToDateIfNoMigrations(): void {
@@ -246,7 +246,7 @@ class MigratorTest extends TestCase
 
 		$upToDate = $migrator->upToDate();
 
-		$this->assertTrue($upToDate);
+		self::assertTrue($upToDate);
 	}
 
 	public function testConstructorLoadsDirectory(): void {
@@ -256,47 +256,47 @@ class MigratorTest extends TestCase
 
 		$migrations = $migrator->migrations();
 
-		$this->assertSame($expected_versions, array_keys($migrations));
+		self::assertSame($expected_versions, array_keys($migrations));
 	}
 
 	public function testExecute(): void {
 		$migrations_path = TESTS_PATH . '/fixtures/migrations/';
 		$applied_migrations_path = tempnam('/tmp', 'applied_migrations.txt');
-		$this->assertIsString($applied_migrations_path);
+		self::assertIsString($applied_migrations_path);
 		$result = Minz_Migrator::execute($migrations_path, $applied_migrations_path);
 
-		$this->assertTrue($result);
+		self::assertTrue($result);
 		$versions = file_get_contents($applied_migrations_path);
-		$this->assertSame("2019_12_22_FooBar\n2019_12_23_Baz", $versions);
+		self::assertSame("2019_12_22_FooBar\n2019_12_23_Baz", $versions);
 		@unlink($applied_migrations_path);
 	}
 
 	public function testExecuteWithAlreadyAppliedMigration(): void {
 		$migrations_path = TESTS_PATH . '/fixtures/migrations/';
 		$applied_migrations_path = tempnam('/tmp', 'applied_migrations.txt');
-		$this->assertIsString($applied_migrations_path);
+		self::assertIsString($applied_migrations_path);
 		file_put_contents($applied_migrations_path, '2019_12_22_FooBar');
 
 		$result = Minz_Migrator::execute($migrations_path, $applied_migrations_path);
 
-		$this->assertTrue($result);
+		self::assertTrue($result);
 		$versions = file_get_contents($applied_migrations_path);
-		$this->assertSame("2019_12_22_FooBar\n2019_12_23_Baz", $versions);
+		self::assertSame("2019_12_22_FooBar\n2019_12_23_Baz", $versions);
 		@unlink($applied_migrations_path);
 	}
 
 	public function testExecuteWithAppliedMigrationInDifferentOrder(): void {
 		$migrations_path = TESTS_PATH . '/fixtures/migrations/';
 		$applied_migrations_path = tempnam('/tmp', 'applied_migrations.txt');
-		$this->assertIsString($applied_migrations_path);
+		self::assertIsString($applied_migrations_path);
 		file_put_contents($applied_migrations_path, "2019_12_23_Baz\n2019_12_22_FooBar");
 
 		$result = Minz_Migrator::execute($migrations_path, $applied_migrations_path);
 
-		$this->assertTrue($result);
+		self::assertTrue($result);
 		$versions = file_get_contents($applied_migrations_path);
 		// if the order changes, it probably means the first versions comparison test doesn’t work anymore
-		$this->assertSame("2019_12_23_Baz\n2019_12_22_FooBar", $versions);
+		self::assertSame("2019_12_23_Baz\n2019_12_22_FooBar", $versions);
 		@unlink($applied_migrations_path);
 	}
 
@@ -304,11 +304,11 @@ class MigratorTest extends TestCase
 		$migrations_path = TESTS_PATH . '/fixtures/migrations/';
 		$applied_migrations_path = tempnam('/tmp', 'applied_migrations.txt');
 		$expected_result = "Cannot open the {$applied_migrations_path} file";
-		$this->assertIsString($applied_migrations_path);
+		self::assertIsString($applied_migrations_path);
 		unlink($applied_migrations_path);
 		$result = Minz_Migrator::execute($migrations_path, $applied_migrations_path);
 
-		$this->assertSame($expected_result, $result);
+		self::assertSame($expected_result, $result);
 		@unlink($applied_migrations_path);
 	}
 
@@ -316,14 +316,14 @@ class MigratorTest extends TestCase
 		$migrations_path = TESTS_PATH . '/fixtures/migrations_with_failing/';
 		$applied_migrations_path = tempnam('/tmp', 'applied_migrations.txt');
 		$expected_result = 'A migration failed to be applied, please see previous logs.';
-		$this->assertIsString($applied_migrations_path);
+		self::assertIsString($applied_migrations_path);
 		$result = Minz_Migrator::execute($migrations_path, $applied_migrations_path);
-		$this->assertIsString($result);
+		self::assertIsString($result);
 		[$result,] = explode("\n", $result, 2);
 
-		$this->assertSame($expected_result, $result);
+		self::assertSame($expected_result, $result);
 		$versions = file_get_contents($applied_migrations_path);
-		$this->assertSame('2020_01_11_FooBar', $versions);
+		self::assertSame('2020_01_11_FooBar', $versions);
 		@unlink($applied_migrations_path);
 	}
 }

+ 1 - 1
tests/lib/PHPMailer/PHPMailerTest.php

@@ -3,6 +3,6 @@
 class PHPMailerTest extends PHPUnit\Framework\TestCase
 {
 	public function testPHPMailerClassExists(): void {
-		$this->assertTrue(class_exists('PHPMailer\\PHPMailer\\PHPMailer'));
+		self::assertTrue(class_exists('PHPMailer\\PHPMailer\\PHPMailer'));
 	}
 }