OneBot: Leantime 改造版源码(BOM/Univer 表格/AI 接管/品牌替换等)
This commit is contained in:
61
tests/Unit/app/Core/UI/TemplateEscapeTest.php
Normal file
61
tests/Unit/app/Core/UI/TemplateEscapeTest.php
Normal file
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
namespace Unit\app\Core\UI;
|
||||
|
||||
use Leantime\Core\UI\Template;
|
||||
use Unit\TestCase;
|
||||
|
||||
/**
|
||||
* Regression tests for Template::escape() (#3636).
|
||||
*
|
||||
* escape() used htmlentities(), which converts non-ASCII to named entities on top of the
|
||||
* XSS-relevant characters. Nearly every call site renders through {{ }}, which escapes the
|
||||
* resulting ampersand a second time, so users with non-English data saw a literal
|
||||
* "Müller" in dropdowns, filters and Ideas.
|
||||
*
|
||||
* These pin both halves of the contract: non-ASCII survives, and the escaping is still as
|
||||
* strong as it was for the call sites that render through {!! !!}.
|
||||
*/
|
||||
class TemplateEscapeTest extends TestCase
|
||||
{
|
||||
private function escape(?string $value): string
|
||||
{
|
||||
// Built without the constructor: escape() only reaches convertRelativePaths(), which
|
||||
// depends on the BASE_URL constant rather than any instance state, so none of
|
||||
// Template's collaborators (session, db, theme) need to exist here.
|
||||
$template = (new \ReflectionClass(Template::class))->newInstanceWithoutConstructor();
|
||||
|
||||
return $template->escape($value);
|
||||
}
|
||||
|
||||
public function test_non_ascii_is_left_alone(): void
|
||||
{
|
||||
$this->assertSame('Müller', $this->escape('Müller'));
|
||||
$this->assertSame('Ä Ö Ü ä ö ü ß', $this->escape('Ä Ö Ü ä ö ü ß'));
|
||||
$this->assertStringNotContainsString(
|
||||
'ü',
|
||||
$this->escape('Müller'),
|
||||
'Umlauts must not be turned into named entities (#3636)'
|
||||
);
|
||||
}
|
||||
|
||||
public function test_xss_relevant_characters_are_still_escaped(): void
|
||||
{
|
||||
$this->assertSame('<script>alert(1)</script>', $this->escape('<script>alert(1)</script>'));
|
||||
$this->assertSame('" onerror="alert(1)', $this->escape('" onerror="alert(1)'));
|
||||
$this->assertSame('' onmouseover='x', $this->escape("' onmouseover='x"));
|
||||
$this->assertSame('a < b & c > d', $this->escape('a < b & c > d'));
|
||||
}
|
||||
|
||||
public function test_ampersand_is_escaped_exactly_once(): void
|
||||
{
|
||||
// The double-escape the user actually saw came from & being encoded here and again
|
||||
// by Blade. One pass here must produce exactly one &.
|
||||
$this->assertSame('Müller & Söhne', $this->escape('Müller & Söhne'));
|
||||
}
|
||||
|
||||
public function test_null_is_an_empty_string(): void
|
||||
{
|
||||
$this->assertSame('', $this->escape(null));
|
||||
}
|
||||
}
|
||||
112
tests/Unit/app/Core/UI/ThemeTest.php
Normal file
112
tests/Unit/app/Core/UI/ThemeTest.php
Normal file
@@ -0,0 +1,112 @@
|
||||
<?php
|
||||
|
||||
namespace Unit\app\Core\UI;
|
||||
|
||||
use Leantime\Core\Configuration\AppSettings;
|
||||
use Leantime\Core\Configuration\Environment;
|
||||
use Leantime\Core\Files\FileManager;
|
||||
use Leantime\Core\Language;
|
||||
use Leantime\Core\UI\Theme;
|
||||
use Leantime\Domain\Setting\Repositories\Setting;
|
||||
|
||||
class ThemeTest extends \Unit\TestCase
|
||||
{
|
||||
use \Codeception\Test\Feature\Stub;
|
||||
|
||||
/**
|
||||
* The test object
|
||||
*
|
||||
* @var Theme
|
||||
*/
|
||||
protected $theme;
|
||||
|
||||
protected $settingsRepoMock;
|
||||
|
||||
protected $languageMock;
|
||||
|
||||
protected $configMock;
|
||||
|
||||
protected $appSettingsMock;
|
||||
|
||||
protected $fileManagerMock;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
|
||||
parent::setUp();
|
||||
|
||||
if (! defined('BASE_URL')) {
|
||||
define('BASE_URL', 'http://localhost');
|
||||
}
|
||||
|
||||
$this->settingsRepoMock = $this->make(Setting::class, [
|
||||
|
||||
]);
|
||||
$this->languageMock = $this->make(Language::class, [
|
||||
|
||||
]);
|
||||
|
||||
$this->fileManagerMock = $this->make(FileManager::class, [
|
||||
|
||||
]);
|
||||
|
||||
$this->configMock = $this->make(Environment::class, [
|
||||
'primarycolor' => '#123',
|
||||
'secondarycolor' => '#123',
|
||||
|
||||
]);
|
||||
|
||||
$this->appSettingsMock = $this->make(AppSettings::class, [
|
||||
'appVersion' => '123',
|
||||
]);
|
||||
|
||||
}
|
||||
|
||||
protected function _after()
|
||||
{
|
||||
$this->theme = null;
|
||||
}
|
||||
|
||||
// Write tests below
|
||||
|
||||
/**
|
||||
* Test GetMenuTypes method
|
||||
*/
|
||||
public function test_get_default_color_scheme_with_color_env_set()
|
||||
{
|
||||
|
||||
// Load class to be tested
|
||||
$this->theme = new Theme(
|
||||
settingsRepo: $this->settingsRepoMock,
|
||||
language: $this->languageMock,
|
||||
config: $this->configMock,
|
||||
appSettings: $this->appSettingsMock,
|
||||
fileManager: $this->fileManagerMock
|
||||
);
|
||||
|
||||
$colorScheme = $this->theme->getColorScheme();
|
||||
$this->assertEquals('companyColors', $colorScheme);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test GetMenuTypes method
|
||||
*/
|
||||
public function test_get_default_color_scheme_without_env()
|
||||
{
|
||||
|
||||
$configMock = $this->make(Environment::class, []);
|
||||
|
||||
$theme = new Theme(
|
||||
settingsRepo: $this->settingsRepoMock,
|
||||
language: $this->languageMock,
|
||||
config: $configMock,
|
||||
appSettings: $this->appSettingsMock,
|
||||
fileManager: $this->fileManagerMock
|
||||
);
|
||||
|
||||
$colorScheme = $theme->getColorScheme();
|
||||
$this->assertEquals('themeDefault', $colorScheme);
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user