<?php
/*
** Copyright (C) 2001-2025 Zabbix SIA
**
** This program is free software: you can redistribute it and/or modify it under the terms of
** the GNU Affero General Public License as published by the Free Software Foundation, version 3.
**
** This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
** without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
** See the GNU Affero General Public License for more details.
**
** You should have received a copy of the GNU Affero General Public License along with this program.
** If not, see <https://www.gnu.org/licenses/>.
**/


require_once dirname(__FILE__).'/../../include/CWebTest.php';
require_once dirname(__FILE__).'/../behaviors/CMessageBehavior.php';
require_once dirname(__FILE__).'/../behaviors/CTableBehavior.php';

/**
 * @backup config, widget, globalmacro
 *
 * @dataSource AllItemValueTypes, GlobalMacros
 *
 * @onBefore prepareDashboardData
 */
class testDashboardGaugeWidget extends testWidgets {

	/**
	 * Attach MessageBehavior and TableBehavior to the test.
	 *
	 * @return array
	 */
	public function getBehaviors() {
		return [
			CMessageBehavior::class,
			CTableBehavior::class
		];
	}

	const HOST = 'Host for all item value types';
	const DELETE_GAUGE = 'Gauge for deleting';
	const GAUGE_ITEM = 'Float item';
	const GAUGE_MACROFUNCTIONS = 'Gauge for macrofunctions';

	/**
	 * Id of the dashboard where gauge widget is created and updated.
	 *
	 * @var integer
	 */
	protected static $dashboardid;
	protected static $macrofunction_dashboardid;

	protected static $update_gauge = 'Gauge for updating';

	/**
	 * Get Thresholds table element with mapping set.
	 *
	 * @return CMultifieldTable
	 */
	protected function getThresholdsTable() {
		return $this->query('id:thresholds-table')->asMultifieldTable([
			'mapping' => [
				'' => [
					'name' => 'color',
					'selector' => 'class:color-picker',
					'class' => 'CColorPickerElement'
				],
				'Threshold' => [
					'name' => 'threshold',
					'selector' => 'xpath:./input',
					'class' => 'CElement'
				]
			]
		])->waitUntilVisible()->one();
	}

	public function prepareDashboardData() {
		$float_item_id =CDataHelper::get('AllItemValueTypes.itemids.Float item');

		// Add item data to move needle on Gauge.
		CDataHelper::addItemData($float_item_id, 50);

		$dashboards = CDataHelper::call('dashboard.create', [
			[
				'name' => 'Gauge widget dashboard',
				'auto_start' => 0,
				'pages' => [
					[
						'name' => 'Gauge test page',
						'widgets' => [
							[
								'type' => 'gauge',
								'name' => self::$update_gauge,
								'x' => 0,
								'y' => 0,
								'width' => 11,
								'height' => 5,
								'fields' => [
									[
										'type' => ZBX_WIDGET_FIELD_TYPE_ITEM,
										'name' => 'itemid',
										'value' => $float_item_id
									]
								]
							],
							[
								'type' => 'gauge',
								'name' => self::DELETE_GAUGE,
								'x' => 11,
								'y' => 0,
								'width' => 11,
								'height' => 5,
								'view_mode' => 0,
								'fields' => [
									[
										'type' => ZBX_WIDGET_FIELD_TYPE_ITEM,
										'name' => 'itemid',
										'value' => $float_item_id
									]
								]
							]
						]
					],
					[
						'name' => 'Screenshot page'
					]
				]
			],
			[
				'name' => 'Dashboard for macrofunctions',
				'auto_start' => 0,
				'pages' => [
					[
						'name' => 'Gauge for testing macrofunctions',
						'widgets' => [
							[
								'type' => 'gauge',
								'name' => self::GAUGE_MACROFUNCTIONS,
								'x' => 0,
								'y' => 0,
								'width' => 20,
								'height' => 6,
								'fields' => [
									[
										'type' => ZBX_WIDGET_FIELD_TYPE_ITEM,
										'name' => 'itemid',
										'value' => $float_item_id
									]
								]
							]
						]
					]
				]
			]
		]);

		$this->assertArrayHasKey('dashboardids', $dashboards);
		self::$dashboardid = $dashboards['dashboardids'][0];
		self::$macrofunction_dashboardid = $dashboards['dashboardids'][1];

		CDataHelper::call('usermacro.createglobal', [
			[
				'macro' => self::USER_MACRO,
				'value' => self::USER_MACRO_VALUE
			],
			[
				'macro' => self::USER_SECRET_MACRO,
				'type' => 1,
				'value' => self::USER_MACRO_VALUE
			],
			[
				'macro' => self::MACRO_CHAR,
				'value' => self::MACRO_CHAR_VALUE
			],
			[
				'macro' => self::MACRO_HTML_ENCODE,
				'value' => self::MACRO_HTML_ENCODE_VALUE
			],
			[
				'macro' => self::MACRO_HTML_DECODE,
				'value' => self::MACRO_HTML_DECODE_VALUE
			],
			[
				'macro' => self::MACRO_URL_ENCODE,
				'value' => self::MACRO_URL_ENCODE_VALUE
			],
			[
				'macro' => self::MACRO_URL_DECODE,
				'value' => self::MACRO_URL_DECODE_VALUE
			]
		]);
	}

	public function testDashboardGaugeWidget_Layout() {
		$this->page->login()->open('zabbix.php?action=dashboard.view&dashboardid='.self::$dashboardid);
		$dialog = CDashboardElement::find()->one()->edit()->addWidget();
		$form = $dialog->asForm();
		$this->assertEquals('Add widget', $dialog->getTitle());
		$form->fill(['Type' => CFormElement::RELOADABLE_FILL('Gauge')]);

		// Check default fields.
		$fields = [
			'Name' => ['value' => '', 'placeholder' => 'default', 'maxlength' => 255, 'enabled' => true, 'visible' => true],
			'Refresh interval' => ['value' => 'Default (1 minute)', 'enabled' => true, 'visible' => true],
			'Show header' => ['value' => true, 'enabled' => true, 'visible' => true],
			'id:itemid_ms' => ['value' => '', 'placeholder' => 'type here to search', 'enabled' => true, 'visible' => true],
			'Min' => ['value' => 0, 'maxlength' => 255, 'enabled' => true, 'visible' => true],
			'Max' => ['value' => 100, 'maxlength' => 255, 'enabled' => true, 'visible' => true],

			// Colors.
			'xpath:.//input[@id="value_arc_color"]/..' => ['color' => '', 'enabled' => true, 'visible' => true],
			'xpath:.//input[@id="empty_color"]/..' => ['color' => '', 'enabled' => true, 'visible' => true],
			'xpath:.//input[@id="bg_color"]/..' => ['color' => '', 'enabled' => true, 'visible' => true],

			// Show.
			'id:show_1' => ['value' => true, 'enabled' => true, 'visible' => true], // Show Description.
			'id:show_2' => ['value' => true, 'enabled' => true, 'visible' => true], // Show Value.
			'id:show_3' => ['value' => false, 'enabled' => true, 'visible' => true], // Show Needle.
			'id:show_4' => ['value' => true, 'enabled' => true, 'visible' => true], // Show Scale.
			'id:show_5' => ['value' => true, 'enabled' => true, 'visible' => true], // Show Value arc.

			'Angle' => ['value' => '180°', 'enabled' => true, 'labels' => ['180°', '270°'], 'visible' => false],

			// Description.
			'id:description' => ['value' => '{ITEM.NAME}', 'maxlength' => 2048, 'enabled' => true, 'visible' => false],
			'id:desc_size' => ['value' => '15', 'maxlength' => 3, 'enabled' => true, 'visible' => false],
			'id:desc_v_pos' => ['value' => 'Bottom', 'enabled' => true, 'labels' => ['Top', 'Bottom'], 'visible' => false],
			'id:desc_bold' => ['value' => false, 'enabled' => true, 'visible' => false],
			'xpath:.//input[@id="desc_color"]/..' =>  ['color' => '', 'enabled' => true, 'visible' => false],

			// Value.
			'id:decimal_places' => ['value' => 2, 'maxlength' => 2, 'enabled' => true, 'visible' => false],
			'id:value_bold' => ['value' => false, 'enabled' => true, 'visible' => false],
			'id:value_size' => ['value' => 25, 'maxlength' => 3, 'enabled' => true, 'visible' => false],
			'xpath:.//input[@id="value_color"]/..' => ['color' => '', 'enabled' => true, 'visible' => false],

			// Value arc.
			'id:value_arc_size' => ['value' => 20, 'maxlength' => 3, 'enabled' => true, 'visible' => false],

			// Units.
			'id:units_show' => ['value' => true, 'enabled' => true, 'visible' => false],
			'id:units' => ['value' => '', 'maxlength' => 255, 'enabled' => true, 'visible' => false],
			'id:units_size' => ['value' => 25, 'maxlength' => 3, 'enabled' => true, 'visible' => false],
			'id:units_pos' => ['value' => 'After value', 'enabled' => true, 'visible' => false],
			'id:units_bold' => ['value' => false, 'enabled' => true, 'visible' => false],
			'xpath:.//input[@id="units_color"]/..'=> ['color' => '', 'enabled' => true, 'visible' => false],

			// Needle.
			'xpath:.//input[@id="needle_color"]/..' => ['color' => '', 'enabled' => false, 'visible' => false],

			// Scale.
			'id:scale_show_units' => ['value' => true, 'enabled' => true, 'visible' => false],
			'id:scale_size' => ['value' => 15, 'maxlength' => 3, 'enabled' => true, 'visible' => false],
			'id:scale_decimal_places' => ['value' => 0, 'maxlength' => 2, 'enabled' => true, 'visible' => false],

			// Thresholds.
			'id:th_show_labels' => ['value' => false, 'enabled' => false, 'visible' => false],
			'id:th_show_arc' => ['value' => false, 'enabled' => false, 'visible' => false],
			'id:th_arc_size' => ['value' => 5, 'maxlength' => 3, 'enabled' => false, 'visible' => false],

			'id:override_hostid_ms' => [
				'value' => false, 'placeholder' => 'type here to search', 'enabled' => true, 'visible' => true
			]
		];

		$not_visible = [];
		foreach ($fields as $label => $attributes) {
			if (array_key_exists('color', $attributes)) {
				$this->assertEquals($attributes['color'], $form->query($label)->asColorPicker()->one()->getValue());
			}

			$field = $form->getField($label);
			$this->assertTrue($field->isEnabled($attributes['enabled']));
			$this->assertTrue($field->isVisible($attributes['visible']));

			if (array_key_exists('value', $attributes)) {
				$this->assertEquals($attributes['value'], $field->getValue());
			}

			if (array_key_exists('maxlength', $attributes)) {
				$this->assertEquals($attributes['maxlength'], $field->getAttribute('maxlength'));
			}

			if (array_key_exists('placeholder', $attributes)) {
				$this->assertEquals($attributes['placeholder'], $field->getAttribute('placeholder'));
			}

			if (array_key_exists('labels', $attributes)) {
				$this->assertEquals($attributes['labels'], $field->asSegmentedRadio()->getLabels()->asText());
			}

			// Show Needle is unchecked and Needle color remains invisible by default.
			if ($attributes['visible'] === false && $label !== 'xpath:.//input[@id="needle_color"]/..') {
				$not_visible[] = $label;
			}
		}

		// Check  Advanced configuration's fields visibility.
		$form->fill(['Advanced configuration' => true]);

		// Check hintboxes.
		$hints = [
			'Description' => "Supported macros:".
					"\n{HOST.*}".
					"\n{ITEM.*}".
					"\n{INVENTORY.*}".
					"\nUser macros",
			'Position' => 'Position is ignored for s, uptime and unixtime units.'
		];

		// Check Position dropdown options.
		$this->assertEquals(['Before value', 'Above value', 'After value', 'Below value'],
				$form->getField('id:units_pos')->getOptions()->asText()
		);

		foreach ($hints as $label => $text) {
			// Force click is needed because the label might be hidden under the scrolled part of the form.
			$form->getLabel($label)->query('xpath:./button[@data-hintbox]')->one()->click(true);
			$hint = $this->query('xpath://div[@data-hintboxid]')->waitUntilVisible();
			$this->assertEquals($text, $hint->one()->getText());
			$hint->one()->query('xpath:.//button[@class="btn-overlay-close"]')->one()->click();
			$hint->waitUntilNotPresent();
		}

		// Check visible fields.
		foreach ($not_visible as $visible_field) {
			$this->assertTrue($form->getField($visible_field)->isVisible());
		}

		// Check Threshold parameters.
		$threshold_field = $form->getField('Thresholds');
		$threshold_field->query('button:Add')->one()->waitUntilClickable()->click();
		$threshold_input ='id:thresholds_0_threshold';

		$inputs = [
			'xpath:.//input[@id="thresholds_0_color"]/..',
			$threshold_input,
			'button:Add',
			'button:Remove'
		];

		foreach ($inputs as $selector) {
			$this->assertTrue($threshold_field->query($selector)->one()->waitUntilVisible()->isEnabled());
		}

		$this->assertEquals(255, $form->getField($threshold_input)->getAttribute('maxlength'));
		$form->checkValue([$threshold_input => '']);

		// Fill Threshold field to enable other Threshold options.
		$form->getField($threshold_input)->type('123');

		foreach (['id:th_show_labels' => true, 'id:th_show_arc' => true, 'id:th_arc_size' => false] as $field => $status) {
			$this->assertTrue($form->getField($field)->isEnabled($status));
		}

		// Enable Show arc.
		$form->fill(['id:th_show_arc' => true]);
		$this->assertTrue($form->getField('id:th_arc_size')->isEnabled());

		// Uncheck Show arc for further checkboxes testing.
		$form->fill(['id:th_show_arc' => false]);

		// Check fields' labels and required fields.
		$this->assertEquals(['Type', 'Show header', 'Name', 'Refresh interval', 'Item', 'Min', 'Max', 'Colours',
				'Show', 'Override host', 'Advanced configuration', 'Angle', 'Description', 'Value', 'Value arc', 'Needle', 'Scale',
				'Thresholds'],
				$form->getLabels()->asText()
		);

		$this->assertEquals(['Item', 'Min', 'Max', 'Show', 'Description'], $form->getRequiredLabels());

		// Check visible and enabled fields dependency.
		$dependent_fields = [
			'id:units_show' => [ // Unnamed checkbox under Value field.
				'status' => false,
				'depending' => [
					'editable' => [
						'id:units',
						'id:units_size',
						'id:units_pos',
						'id:units_bold',
						'xpath:.//input[@id="units_color"]/..',
						'id:scale_show_units'
					]
				]
			],
			'id:show_1' => [ // Show Description.
				'status' => false,
				'depending' =>
					[
						'visible' => [
							'id:description',
							'id:desc_size', 'id:desc_v_pos',
							'id:desc_bold',
							'xpath:.//input[@id="desc_color"]/..'
						]
					]
			],
			'id:show_2' => [ // Show Value.
				'status' => false,
				'depending' => [
					'visible' => [
						'id:decimal_places',
						'id:value_bold',
						'id:value_size',
						'xpath:.//input[@id="value_color"]/..',
						'id:units_show',
						'id:units',
						'id:units_size',
						'id:units_pos', 'id:units_bold',
						'xpath:.//input[@id="value_color"]/..'
					]
				]
			],
			'id:show_3' => [ // Show Needle.
				'status' => true,
				'depending' => [
					'visible' => ['xpath:.//input[@id="needle_color"]/..']
				]
			],
			'id:show_4' => [ // Show Scale.
				'status' => false,
				'depending' => [
					'visible' => ['id:scale_show_units', 'id:scale_decimal_places', 'id:scale_size']
				]
			],
			'id:show_5' => [ // Show Value arc.
				'status' => false,
				'depending' => [
					'editable' => ['id:show_3', 'id:show_4'],
					'visible' => ['id:value_arc_size']
				]
			]
		];

		foreach ($dependent_fields as $switch => $parameters) {
			$form->fill([$switch => $parameters['status']]);

			foreach ($parameters['depending'] as $parameter => $labels) {
				foreach ($labels as $label) {
					$field = $form->getField($label);

					if ($parameter === 'editable') {
						$this->assertTrue($field->isEnabled($parameters['status']));
					}
					else {
						$this->assertTrue($field->isVisible($parameters['status']));
					}
				}
			}
		}

		// Check Show and Show arc dependency.
		foreach ([true, false] as $show_arc) {
			$form->fill(['id:th_show_arc' => $show_arc]);

			$show = [
				'id:show_1' => true, // Description.
				'id:show_2' => true, // Value.
				'id:show_3' => true, // Needle.
				'id:show_4' => true, // Scale.
				'id:show_5' => true  // Value arc.
			];

			if (!$show_arc)  {
				$show['id:show_3'] = false;
				$show['id:show_4'] = false;
			}

			foreach ($show as $field => $enabled) {
				$this->assertTrue($form->getField($field)->isEnabled($enabled));
			}
		}

		// Check Override host field.
		$override = $form->getField('Override host');
		$popup_menu = $override->query('xpath:.//button[contains(@class, "zi-chevron-down")]')->one();

		foreach ([$override->query('button:Select')->one(), $popup_menu] as $button) {
			$this->assertTrue($button->isClickable());
		}

		$menu = $popup_menu->asPopupButton()->getMenu();
		$this->assertEquals(['Widget', 'Dashboard'], $menu->getItems()->asText());
		$menu->select('Dashboard');
		$form->checkValue(['Override host' => 'Dashboard']);
		$this->assertTrue($override->query('xpath:.//span[@data-hintbox-contents="Dashboard is used as data source."]')
				->one()->isVisible()
		);

		$override->query('button:Select')->waitUntilCLickable()->one()->click();
		$dialogs = COverlayDialogElement::find()->all();
		$this->assertEquals('Widget', $dialogs->last()->getTitle());

		$dialog_count = $dialogs->count();
		for ($i = $dialog_count - 1; $i >= 0; $i--) {
			$dialogs->get($i)->close(true);
		}
	}

	public static function getWidgetCommonData() {
		return [
			// #0 Empty item.
			[
				[
					'expected' => TEST_BAD,
					'fields' => [
						'Item' => ''
					],
					'error' => 'Invalid parameter "Item": cannot be empty.'
				]
			],
			// #1 Both min and max equal zeros.
			[
				[
					'expected' => TEST_BAD,
					'fields' => [
						'Item' => self::GAUGE_ITEM,
						'Min' => 0,
						'Max' => 0
					],
					'error' => [
						'Invalid parameter "Max": value must be greater than "0".'
					]
				]
			],
			// #2 All fields are zeros.
			[
				[
					'expected' => TEST_BAD,
					'fields' => [
						'Item' => self::GAUGE_ITEM,
						'Min' => 0,
						'Max' => 0,
						'id:desc_size' => 0,
						'id:value_size' => 0,
						'id:value_arc_size' => 0,
						'id:units_size' => 0,
						'id:scale_size' => 0,
						'id:th_show_arc' => true,
						'id:th_arc_size' => 0
					],
					'Thresholds' => [
						['threshold' => '10']
					],
					'error' => [
						'Invalid parameter "Description: Size": value must be one of 1-100.',
						'Invalid parameter "Value: Size": value must be one of 1-100.',
						'Invalid parameter "Value arc: Size": value must be one of 1-100.',
						'Invalid parameter "Units: Size": value must be one of 1-100.',
						'Invalid parameter "Scale: Size": value must be one of 1-100.',
						'Invalid parameter "Arc size": value must be one of 1-100.'
					]
				]
			],
			// #3 Min and Max are the biggest possible.
			[
				[
					'expected' => TEST_BAD,
					'fields' => [
						'Item' => self::GAUGE_ITEM,
						'Min' => str_repeat(9,255),
						'Max' => str_repeat(9,255)
					],
					'error' => 'Invalid parameter "Max": value must be greater than "1.0E+255".'
				]
			],
			// #4 Min more than Max.
			[
				[
					'expected' => TEST_BAD,
					'fields' => [
						'Item' => self::GAUGE_ITEM,
						'Min' => 10,
						'Max' => 3
					],
					'error' => 'Invalid parameter "Max": value must be greater than "10".'
				]
			],
			// #5 All fields are empty.
			[
				[
					'expected' => TEST_BAD,
					'fields' => [
						'Item' => self::GAUGE_ITEM,
						'Min' => '',
						'Max' => '',
						'id:desc_size' => '',
						'id:decimal_places' => '',
						'id:value_size' => '',
						'id:value_arc_size' => '',
						'id:units_size' => '',
						'id:scale_size' => '',
						'id:scale_decimal_places' => '',
						'id:th_show_arc' => true,
						'id:th_arc_size' => ''
					],
					'Thresholds' => [
						['threshold' => '10']
					],
					'error' => [
						'Invalid parameter "Min": cannot be empty.',
						'Invalid parameter "Max": cannot be empty.',
						'Invalid parameter "Description: Size": value must be one of 1-100.',
						'Invalid parameter "Value: Size": value must be one of 1-100.',
						'Invalid parameter "Value arc: Size": value must be one of 1-100.',
						'Invalid parameter "Units: Size": value must be one of 1-100.',
						'Invalid parameter "Scale: Size": value must be one of 1-100.',
						'Invalid parameter "Arc size": value must be one of 1-100.'
					]
				]
			],
			// #6 Text in numeric fields.
			[
				[
					'expected' => TEST_BAD,
					'fields' => [
						'Item' => self::GAUGE_ITEM,
						'Min' => 'text',
						'Max' => 'test',
						'id:desc_size' => 'abc',
						'id:decimal_places' => 'abc',
						'id:value_size' => 'abc',
						'id:value_arc_size' => 'abc',
						'id:units_size' => 'abc',
						'id:scale_size' => 'abc',
						'id:scale_decimal_places' => 'abc',
						'id:th_show_arc' => true,
						'id:th_arc_size' => 'abc'
					],
					'Thresholds' => [
						['threshold' => 'test']
					],
					'error' => [
						'Invalid parameter "Min": a number is expected.',
						'Invalid parameter "Max": a number is expected.',
						'Invalid parameter "Description: Size": value must be one of 1-100.',
						'Invalid parameter "Value: Size": value must be one of 1-100.',
						'Invalid parameter "Value arc: Size": value must be one of 1-100.',
						'Invalid parameter "Units: Size": value must be one of 1-100.',
						'Invalid parameter "Scale: Size": value must be one of 1-100.',
						'Invalid parameter "Thresholds/1/threshold": a number is expected.',
						'Invalid parameter "Arc size": value must be one of 1-100.'
					]
				]
			],
			// #7 Mixed numbers and random text in numeric fields.
			[
				[
					'expected' => TEST_BAD,
					'fields' => [
						'Item' => self::GAUGE_ITEM,
						'Min' => '2t',
						'Max' => '3y',
						'id:desc_size' => '1a',
						'id:decimal_places' => '2b',
						'id:value_size' => '1a',
						'id:value_arc_size' => '1a',
						'id:units_size' => '1a',
						'id:scale_size' => '1a',
						'id:scale_decimal_places' => '2b',
						'id:th_show_arc' => true,
						'id:th_arc_size' => '1a'
					],
					'Thresholds' => [
						['threshold' => '1', 'color' => 'ERERER']
					],
					'error' => [
						'Invalid parameter "Min": a number is expected.',
						'Invalid parameter "Max": a number is expected.',
						'Invalid parameter "Thresholds/1/color": a hexadecimal colour code (6 symbols) is expected.'
					]
				]
			],
			// #8 2-bytes special characters.
			[
				[
					'expected' => TEST_BAD,
					'fields' => [
						'Item' => self::GAUGE_ITEM,
						'Min' => 'そこ',
						'Max' => 'ߘ',
						'id:desc_size' => '۞',
						'id:decimal_places' => 'Ֆ',
						'id:value_size' => '©',
						'id:value_arc_size' => 'ֈ',
						'id:units_size' => 'æ',
						'id:scale_size' => '߷',
						'id:scale_decimal_places' => '',
						'id:th_show_arc' => true,
						'id:th_arc_size' => 'Ä'
					],
					'Thresholds' => [
						['threshold' => 'ß']
					],
					'error' => [
						'Invalid parameter "Min": a number is expected.',
						'Invalid parameter "Max": a number is expected.',
						'Invalid parameter "Description: Size": value must be one of 1-100.',
						'Invalid parameter "Value: Size": value must be one of 1-100.',
						'Invalid parameter "Value arc: Size": value must be one of 1-100.',
						'Invalid parameter "Units: Size": value must be one of 1-100.',
						'Invalid parameter "Scale: Size": value must be one of 1-100.',
						'Invalid parameter "Thresholds/1/threshold": a number is expected.',
						'Invalid parameter "Arc size": value must be one of 1-100.'
					]
				]
			],
			// #9 4-bytes characters.
			[
				[
					'expected' => TEST_BAD,
					'fields' => [
						'Name' => '𒀐',
						'Item' => self::GAUGE_ITEM,
						'Min' => '😁',
						'Max' => '🙂',
						'id:desc_size' => '😅',
						'id:decimal_places' => '😘',
						'id:value_size' => '😒',
						'id:value_arc_size' => '😔',
						'id:units_size' => '🤢',
						'id:scale_size' => '😨',
						'id:scale_decimal_places' => '😩',
						'id:th_show_arc' => true,
						'id:th_arc_size' => '😽'
					],
					'Thresholds' => [
						['threshold' => '11']
					],
					'error' => [
						'Invalid parameter "Min": a number is expected.',
						'Invalid parameter "Max": a number is expected.',
						'Invalid parameter "Description: Size": value must be one of 1-100.',
						'Invalid parameter "Value: Size": value must be one of 1-100.',
						'Invalid parameter "Value arc: Size": value must be one of 1-100.',
						'Invalid parameter "Units: Size": value must be one of 1-100.',
						'Invalid parameter "Scale: Size": value must be one of 1-100.',
						'Invalid parameter "Arc size": value must be one of 1-100.'
					]
				]
			],
			// #10 Too big numbers in decimal places.
			[
				[
					'expected' => TEST_BAD,
					'fields' => [
						'Name' => 'Character in Threshold',
						'Item' => self::GAUGE_ITEM
					],
					'Thresholds' => [
						['threshold' => '😽']
					],
					'error' => [
						'Invalid parameter "Thresholds/1/threshold": a number is expected.'
					]
				]
			],
			// #11 Too big numbers in decimal places.
			[
				[
					'expected' => TEST_BAD,
					'fields' => [
						'Item' => self::GAUGE_ITEM,
						'id:decimal_places' => '900',
						'id:scale_decimal_places' => '900'
					],
					'error' => [
						'Invalid parameter "Decimal places": value must be one of 0-10.',
						'Invalid parameter "Decimal places": value must be one of 0-10.'
					]
				]
			],
			// #12
			[
				[
					'expected' => TEST_BAD,
					'fields' => [
						'Item' => self::GAUGE_ITEM,
						'id:show_1' => false, // Description.
						'id:show_2' => false, // Value.
						'id:show_3' => false, // Needle.
						'id:show_4' => false, // Scale.
						'id:show_5' => false  // Value arc.
					],
					'error' => [
						'Invalid parameter "Show": at least one option must be selected.'
					]
				]
			],
			// #13 All fields successful case.
			[
				[
					'fields' => [
						'Name' => '😁🙂𒀐',
						'Item' => self::GAUGE_ITEM,
						'Min' => 99,
						'Max' => 88888,
						'xpath:.//input[@id="value_arc_color"]/..' => '64B5F6',
						'xpath:.//input[@id="empty_color"]/..' => 'FFBF00',
						'xpath:.//input[@id="bg_color"]/..' => 'BA68C8',
						'Angle' => '270°',
						'id:description' => '𒀐 New test Description 😁🙂😁🙂',
						'id:desc_size' => 30,
						'id:desc_bold' => true,
						'id:desc_v_pos' => 'Top',
						'xpath:.//input[@id="desc_color"]/..' => 'FFB300',
						'id:decimal_places' => 10,
						'id:value_size' => 50,
						'id:value_bold' => true,
						'xpath:.//input[@id="value_color"]/..' => '283593',
						'id:show_5' => true, // Show Value arc.
						'id:value_arc_size' => 12,
						'id:units' => 'Bytes 𒀐  😁',
						'id:units_size' => 27,
						'id:units_bold' => true,
						'id:units_pos' => 'Above value',
						'xpath:.//input[@id="units_color"]/..' => '4E342E',
						'id:show_3' => true, // Show Needle.
						'xpath:.//input[@id="needle_color"]/..' => '4DD0E1',
						'id:scale_size' => 33,
						'id:scale_decimal_places' => 8,
						'id:th_show_arc' => true,
						'id:th_arc_size' => 85,
						'id:th_show_labels' => true,
						'Override host' => 'Dashboard'
					],
					'Thresholds' => [
						['threshold' => '555', 'color' => '1976D2']
					]
				]
			],
			// #14 Multiple thresholds.
			[
				[
					'fields' => [
						'Name' => 'Multiple thresholds',
						'Min' => 15,
						'Max' => 200,
						'Refresh interval' => '30 seconds',
						'Item' => self::GAUGE_ITEM,
						'id:units_pos' => 'Before value'
					],
					'Thresholds' => [
						['threshold' => '30', 'color' => '03A9F4'],
						['threshold' => '50', 'color' => '283593']
					]
				]
			],
			// #15 False default checkboxes.
			[
				[
					'fields' => [
						'Name' => 'False default checkboxes',
						'Item' => self::GAUGE_ITEM,
						'Show header' => false,
						'id:show_5' => true, // Show Value arc.
						'id:show_1' => false, // Show Description.
						'id:show_2' => false, // Show Value.
						'id:show_3' => false, // Show Needle.
						'id:show_4' => false // Show Scale.
					]
				]
			],
			// #16 False default checkboxes - vol.2.
			[
				[
					'fields' => [
						'Name' => 'False default checkboxes 2',
						'Item' => self::GAUGE_ITEM,
						'Show header' => false,
						'id:show_1' => true, // Show Description.
						'id:show_3' => false, // Show Needle.
						'id:show_4' => false, // Show Scale.
						'id:show_2' => false, // Show Value.
						'id:show_5' => false // Show Value arc.
					]
				]
			],
			// #17 False default checkboxes - vol.3.
			[
				[
					'fields' => [
						'Name' => 'False default checkboxes 3',
						'Item' => self::GAUGE_ITEM,
						'Show header' => false,
						'id:show_2' => true, // Show Value.
						'id:show_3' => false, // Show Needle.
						'id:show_4' => false, // Show Scale.
						'id:show_1' => false, // Show Description.
						'id:show_5' => false // Show Value arc.
					]
				]
			]
		];
	}

	public static function getWidgetCreateData() {
		return [
			// #18 Minimal required fields.
			[
				[
					'fields' => [
						'Item' => self::GAUGE_ITEM,
						'Advanced configuration' => false
					]
				]
			]
		];
	}

	/**
	 *
	 * @backupOnce widget
	 *
	 * @dataProvider getWidgetCommonData
	 * @dataProvider getWidgetCreateData
	 */
	public function testDashboardGaugeWidget_Create($data) {
		$this->checkFormGaugeWidget($data);
	}

	/**
	 * @dataProvider getWidgetCommonData
	 */
	public function testDashboardGaugeWidget_Update($data) {
		$this->checkFormGaugeWidget($data, true);
	}

	/**
	 * Function for checking Gauge widget form.
	 *
	 * @param array      $data      data provider
	 * @param boolean    $update    true if update scenario, false if create
	 */
	public function checkFormGaugeWidget($data, $update = false) {
		if (CTestArrayHelper::get($data, 'expected', TEST_GOOD) === TEST_BAD) {
			$old_hash = CDBHelper::getHash(self::SQL);
		}

		$this->page->login()->open('zabbix.php?action=dashboard.view&dashboardid='.self::$dashboardid);
		$dashboard = CDashboardElement::find()->one();
		$old_widget_count = $dashboard->getWidgets()->count();

		$form = $update
			? $dashboard->getWidget(self::$update_gauge)->edit()
			: $dashboard->edit()->addWidget()->asForm();

		COverlayDialogElement::find()->one();
		$form->fill(['Type' => CFormElement::RELOADABLE_FILL('Gauge')]);

		if ($update && CTestArrayHelper::get($data['fields'], 'Item') === '') {
			$form->getField('Item')->clear();
		}

		$form->fill(['Advanced configuration' => true]);

		if (array_key_exists('Thresholds', $data)) {
			// To update Thresholds previously saved values should be removed.
			if ($update) {
				$this->getThresholdsTable()->clear();
			}

			$this->getThresholdsTable()->fill($data['Thresholds']);
		}

		$form->fill($data['fields']);
		$form->submit();

		if (CTestArrayHelper::get($data, 'expected', TEST_GOOD) === TEST_BAD) {
			$this->assertMessage(TEST_BAD, null, $data['error']);

			// Check that DB hash is not changed.
			$this->assertEquals($old_hash, CDBHelper::getHash(self::SQL));
		}
		else {
			COverlayDialogElement::ensureNotPresent();

			/**
			 *  When name is absent in create scenario it remains default: host name + item name,
			 *  if name is absent in update scenario then previous name remains.
			 *  If name is empty string in both scenarios it is replaced by host name + item name.
			 */
			if (array_key_exists('Name', $data['fields'])) {
				$header = ($data['fields']['Name'] === '')
					? self::HOST.': '.$data['fields']['Item']
					: $data['fields']['Name'];
			}
			else {
				$header = $update ? self::$update_gauge : self::HOST.': '.$data['fields']['Item'];
			}

			$dashboard->getWidget($header);
			$dashboard->save();
			$this->assertMessage(TEST_GOOD, 'Dashboard updated');
			$this->assertEquals($old_widget_count + ($update ? 0 : 1), $dashboard->getWidgets()->count());
			$saved_form = $dashboard->getWidget($header)->edit();

			if (array_key_exists('Item', $data['fields'])) {
				$data['fields']['Item'] = self::HOST.': '.$data['fields']['Item'];
			}

			// Check that Advanced configuration is false by default.
			$saved_form->checkValue(['Advanced configuration' => false]);

			// Open Advanced configuration if it is not defined as false in data provider.
			if (CTestArrayHelper::get($data['fields'], 'Advanced configuration', true)) {
				$saved_form->fill(['Advanced configuration' => true]);
			}

			// Check saved fields in form.
			$saved_form->checkValue($data['fields']);

			if (array_key_exists('Thresholds', $data)) {
				$this->getThresholdsTable()->checkValue($data['Thresholds']);
			}

			// Check that widget is saved in DB.
			$this->assertEquals(1,
				CDBHelper::getCount('SELECT * FROM widget w'.
					' WHERE EXISTS ('.
						'SELECT NULL'.
						' FROM dashboard_page dp'.
						' WHERE w.dashboard_pageid=dp.dashboard_pageid'.
							' AND dp.dashboardid='.self::$dashboardid.
							' AND w.name ='.zbx_dbstr(CTestArrayHelper::get($data['fields'], 'Name', '')).')'
				));

			// Write new name to the updated widget name.
			if ($update) {
				self::$update_gauge = $header;
			}
		}

		COverlayDialogElement::find()->one()->close();
	}

	public function testDashboardGaugeWidget_SimpleUpdate() {
		$this->checkNoChanges();
	}

	public static function getCancelData() {
		return [
			// #0 Cancel creating widget with saving the dashboard.
			[
				[
					'cancel_form' => true,
					'create_widget' => true,
					'save_dashboard' => true
				]
			],
			// #1 Cancel updating widget with saving the dashboard.
			[
				[
					'cancel_form' => true,
					'create_widget' => false,
					'save_dashboard' => true
				]
			],
			// #2 Create widget without saving the dashboard.
			[
				[
					'cancel_form' => false,
					'create_widget' => true,
					'save_dashboard' => false
				]
			],
			// #3 Update widget without saving the dashboard.
			[
				[
					'cancel_form' => false,
					'create_widget' => false,
					'save_dashboard' => false
				]
			]
		];
	}

	/**
	 * @dataProvider getCancelData
	 */
	public function testDashboardGaugeWidget_Cancel($data) {
		$this->checkNoChanges($data['cancel_form'], $data['create_widget'], $data['save_dashboard']);
	}

	/**
	 * Function for checking canceling form or submitting without any changes.
	 *
	 * @param boolean $cancel            true if cancel scenario, false if form is submitted
	 * @param boolean $create            true if create scenario, false if update
	 * @param boolean $save_dashboard    true if dashboard will be saved, false if not
	 */
	protected function checkNoChanges($cancel = false, $create = false, $save_dashboard = true) {
		$old_hash = CDBHelper::getHash(self::SQL);

		$this->page->login()->open('zabbix.php?action=dashboard.view&dashboardid='.self::$dashboardid);
		$dashboard = CDashboardElement::find()->one();
		$old_widget_count = $dashboard->getWidgets()->count();
		$dashboard->edit();

		$form = $create
			? $dashboard->addWidget()->asForm()
			: $dashboard->getWidget(self::$update_gauge)->edit();

		$dialog = COverlayDialogElement::find()->one()->waitUntilReady();

		if ($create) {
			$form->fill(['Type' => CFormElement::RELOADABLE_FILL('Gauge')]);
		}
		else {
			$values = $form->getValues();
		}

		if ($cancel || !$save_dashboard) {
			$form->fill(
				[
					'Name' => 'new name',
					'Refresh interval' => '10 minutes',
					'Item' => 'testFormItem4',
					'Min' => 10,
					'Max' => 300
				]
			);
		}

		if ($cancel) {
			$dialog->query('button:Cancel')->one()->click();
		}
		else {
			$form->submit();
		}

		COverlayDialogElement::ensureNotPresent();

		if (!$cancel) {
			$dashboard->getWidget($save_dashboard ? self::$update_gauge : 'new name')->waitUntilReady();
		}

		if ($save_dashboard) {
			$dashboard->save();
			$this->assertMessage(TEST_GOOD, 'Dashboard updated');
		}
		else {
			$dashboard->cancelEditing();
		}

		$this->assertEquals($old_widget_count, $dashboard->getWidgets()->count());

		// Check that updating widget form values did not change in frontend.
		if (!$create && !$save_dashboard) {
			$this->assertEquals($values, $dashboard->getWidget(self::$update_gauge)->edit()->getValues());
			COverlayDialogElement::find()->one()->close();
		}

		// Check that DB hash is not changed.
		$this->assertEquals($old_hash, CDBHelper::getHash(self::SQL));
	}

	public function testDashboardGaugeWidget_Delete() {
		$this->page->login()->open('zabbix.php?action=dashboard.view&dashboardid='.self::$dashboardid);
		$dashboard = CDashboardElement::find()->one()->waitUntilReady()->edit();
		$widget = $dashboard->getWidget(self::DELETE_GAUGE);
		$this->assertTrue($widget->isEditable());
		$dashboard->deleteWidget(self::DELETE_GAUGE);
		$widget->waitUntilNotPresent();
		$dashboard->save();
		$this->page->waitUntilReady();
		$this->assertMessage(TEST_GOOD, 'Dashboard updated');

		// Check that widget is not present on dashboard and in DB.
		$this->assertFalse($dashboard->getWidget(self::DELETE_GAUGE, false)->isValid());
		$this->assertEquals(0, CDBHelper::getCount('SELECT * FROM widget_field wf'.
			' LEFT JOIN widget w'.
			' ON w.widgetid=wf.widgetid'.
			' WHERE w.name='.zbx_dbstr(self::DELETE_GAUGE)
		));
	}

	/**
	 * Test function for assuring that text, log, binary and char items are not available in Gauge widget.
	 */
	public function testDashboardGaugeWidget_CheckAvailableItems() {
		$url = 'zabbix.php?action=dashboard.view&dashboardid='.self::$dashboardid;
		$this->checkAvailableItems($url, 'Gauge');
	}

	public static function getScreenshotsData() {
		return [
			// #0 Minimal settings with value.
			[
				[
					'screenshot_id' => 'Empty gauge with data',
					'fields' => [
						'Item' => self::GAUGE_ITEM
					]
				]
			],
			// #1 Minimal settings No data.
			[
				[
					'screenshot_id' => 'Empty gauge with no data',
					'fields' => [
						'Item' => 'Unsigned item'
					]
				]
			],
			// #2 All settings + Threshold default color.
			[
				[
					'screenshot_id' => 'Full gauge',
					'fields' => [
						'Name' => 'All settings',
						'Item' => self::GAUGE_ITEM,
						'Min' => 20,
						'Max' => 300,
						'xpath:.//input[@id="value_arc_color"]/..' => 'FFCDD2',
						'xpath:.//input[@id="empty_color"]/..' => '26C6DA',
						'xpath:.//input[@id="bg_color"]/..' => 'FFF9C4',
						'Angle' => '270°',
						'id:description' => 'Screenshot Description 😁🙂😁🙂',
						'id:desc_size' => 8,
						'id:desc_bold' => true,
						'id:desc_v_pos' => 'Top',
						'xpath:.//input[@id="desc_color"]/..' => '303F9F',
						'id:decimal_places' => 3,
						'id:value_size' => 17,
						'id:value_bold' => true,
						'xpath:.//input[@id="value_color"]/..' => '00796B',
						'id:show_5' => true, // Show Value arc.
						'id:value_arc_size' => 35,
						'id:units' => 'Bytes 😁',
						'id:units_size' => 12,
						'id:units_bold' => true,
						'id:units_pos' => 'Below value',
						'xpath:.//input[@id="units_color"]/..' => '6D4C41',
						'id:show_3' => true,
						'xpath:.//input[@id="needle_color"]/..' => 'FF0000',
						'id:scale_size' => 11,
						'id:scale_decimal_places' => 2,
						'id:th_show_arc' => true,
						'id:th_arc_size' => 40,
						'id:th_show_labels' => true
					],
					'Thresholds' => [
						['threshold' => '100']
					]
				]
			],
			// #3 Macros in description + Thresholds with color.
			[
				[
					'screenshot_id' => 'Gauge with two thresholds',
					'fields' => [
						'Name' => 'All settings + thresholds',
						'Item' => self::GAUGE_ITEM,
						'Min' => 1,
						'Max' => 300,
						'id:description' => '{HOST.NAME} {ITEM.NAME}',
						'id:desc_size' => 5,
						'id:th_show_arc' => true,
						'id:th_arc_size' => 40,
						'id:th_show_labels' => true
					],
					'Thresholds' => [
						['threshold' => '100', 'color' => '4000FF'],
						['threshold' => '200', 'color' => 'E91E63']
					]
				]
			],
			// #4 More macros in description.
			[
				[
					'screenshot_id' => 'More macros',
					'fields' => [
						'Name' => 'Macros',
						'Item' => self::GAUGE_ITEM,
						'id:description' => '{HOST.CONN} {ITEM.KEY}',
						'id:desc_size' => 5
					]
				]
			],
			// #5 User macros in description.
			[
				[
					'screenshot_id' => 'User macro',
					'fields' => [
						'Name' => 'User macro',
						'Item' => self::GAUGE_ITEM,
						'id:description' => '{$A} {INVENTORY.ALIAS}',
						'id:desc_size' => 5
					]
				]
			]
		];
	}

	/**
	 * Test function for assuring that form settings affect Gauge image.
	 *
	 * @dataProvider getScreenshotsData
	 */
	public function testDashboardGaugeWidget_Screenshots($data) {
		$this->page->login()->open('zabbix.php?action=dashboard.view&dashboardid='.self::$dashboardid);
		$dashboard = CDashboardElement::find()->one()->waitUntilReady();
		$dashboard->selectPage('Screenshot page');
		$dashboard->invalidate();
		$dialog = $dashboard->edit()->addWidget()->asForm();
		$dialog->fill([
			'Type' => CFormElement::RELOADABLE_FILL('Gauge'),
			'Advanced configuration' => true
		]);

		if (array_key_exists('Thresholds', $data)) {
			$this->getThresholdsTable()->fill($data['Thresholds']);
		}

		$dialog->fill($data['fields']);
		$dialog->submit();
		COverlayDialogElement::ensureNotPresent();

		$header = array_key_exists('Name', $data['fields'])
			? $data['fields']['Name']
			: self::HOST.': '.$data['fields']['Item'];

		// Wait until widget with header appears on the Dashboard.
		$dashboard->save();
		$widget = $dashboard->waitUntilReady()->getWidget($header)->waitUntilReady();
		$this->page->scrollDown();
		$this->page->removeFocus();

		// Wait until the gauge is animated.
		$this->query('xpath://div['.CXPathHelper::fromClass('is-ready').']')->waitUntilVisible();
		$this->assertScreenshot($widget->query('class:dashboard-grid-widget-container')->one(), $data['screenshot_id']);
	}

	public static function getMacroFunctions() {
		return [
			'Incorrectly added parameter for non-argument macro functions' => [
					[
					'fields' => [
						'Advanced configuration' => true,
						'id:description' => '{{ITEM.NAME}.btoa(\)}, {'.self::USER_MACRO.'.htmldecode(test)}, '.
							'{'.self::USER_MACRO.'.htmlencode(test)}, {{ITEM.NAME}.lowercase([test])}, '.
							'{{ITEM.NAME}.uppercase([test])}, {{ITEM.NAME}.urldecode([test])}, '.
							'{'.self::USER_SECRET_MACRO.'.urlencode(\/)}',
						'id:desc_size' => 5
					],
					'result' => '*UNKNOWN*, *UNKNOWN*, *UNKNOWN*, *UNKNOWN*, *UNKNOWN*, *UNKNOWN*, *UNKNOWN*'
				]
			],
			'Secret macro value is not exposed when using macro functions' => [
					[
					'fields' => [
						'Advanced configuration' => true,
						'id:description' => '{'.self::USER_SECRET_MACRO.'.btoa()}, {'.self::USER_SECRET_MACRO.'.htmldecode()}, '.
							'{'.self::USER_SECRET_MACRO.'.htmlencode()}, {'.self::USER_SECRET_MACRO.'.lowercase()}, '.
							'{'.self::USER_SECRET_MACRO.'.uppercase()}, {'.self::USER_SECRET_MACRO.'.regrepl(a, b)}, '.
							'{'.self::USER_SECRET_MACRO.'.tr(a-z, b)}, {'.self::USER_SECRET_MACRO.'.urldecode()}, '.
							'{'.self::USER_SECRET_MACRO.'.urlencode()}',
						'id:desc_size' => 5
					],
					'result' => 'KioqKioq, ******, ******, ******, ******, ******, ******, ******, %2A%2A%2A%2A%2A%2A'
				]
			],
			'Built-in macros with non-argument macro functions' => [
				[
					'fields' => [
						'Advanced configuration' => true,
						'id:description' => '{{ITEM.NAME}.btoa()}, {{ITEM.NAME}.htmldecode()}, {{ITEM.NAME}.htmlencode()}, '.
							'{{ITEM.NAME}.lowercase()}, {{ITEM.NAME}.uppercase()}, {{ITEM.NAME}.urlencode()}, '.
							'{{ITEM.NAME}.urldecode()}',
						'id:desc_size' => 5
					],
					'result' => 'RmxvYXQgaXRlbQ==, Float item, Float item, float item, FLOAT ITEM, Float%20item, Float item'
				]
			],
			'User macros with non-argument macro functions' => [
				[
					'fields' => [
						'Advanced configuration' => true,
						'id:description' => '{'.self::USER_MACRO.'.btoa()}, {'.self::MACRO_HTML_ENCODE.'.htmlencode()}, '.
							'{'.self::MACRO_HTML_DECODE.'.htmldecode()}, {'.self::MACRO_URL_ENCODE.'.urlencode()}, '.
							'{'.self::MACRO_URL_DECODE.'.urldecode()}, {'.self::USER_MACRO.'.uppercase()}, '.
							'{'.self::USER_MACRO.'.lowercase()}',
						'id:desc_size' => 5
					],
					'result' => base64_encode(self::USER_MACRO_VALUE).', '.self::MACRO_HTML_DECODE_VALUE.', '.
						self::MACRO_HTML_ENCODE_VALUE.', '.self::MACRO_URL_DECODE_VALUE.', '.self::MACRO_URL_ENCODE_VALUE.
						', MACRO FUNCTION TEST 12345, macro function test 12345'
				]
			],
			'Incorrectly used parameters in regrepl(), tr(), regsub(), iregsub() macro functions' => [
				[
					'fields' => [
						'Advanced configuration' => true,
						'id:description' => '{'.self::USER_MACRO.'.regrepl()}, {'.self::MACRO_CHAR.'.regrepl([a])}, '.
							'{'.self::USER_MACRO.'.tr()}, {'.self::USER_MACRO.'.tr(z-a,Z-A)}, {'.self::USER_MACRO.'.tr(1,2,3)}'.
							', {'.self::USER_MACRO.'.regsub()}, {'.self::USER_MACRO.'.iregsub()}',
						'id:desc_size' => 5
					],
					'result' => '*UNKNOWN*, *UNKNOWN*, *UNKNOWN*, *UNKNOWN*, *UNKNOWN*, *UNKNOWN*, *UNKNOWN*'
				]
			],
			'Regrepl function - multibyte characters and case sensitive check' => [
				[
					'fields' => [
						'Advanced configuration' => true,
						'id:description' => '{'.self::USER_MACRO.'.regrepl([[:digit:]], /, [A-Z], \)}, '.
							'{'.self::MACRO_CHAR.'.regrepl(🌴, 🌝, [а-я], Q, \d, 🌞)}',
						'id:desc_size' => 5
					],
					'result' => '\acro function \est /////, 🌞🌞🌞 ЙQQQQЖŽzŠsšĒĀīī🌝 ₰₰₰'
				]
			],
			'Regrepl function with big amount of processed data' => [
				[
					'fields' => [
						'Advanced configuration' => true,
						'id:description' => '{'.self::USER_MACRO.''.
							'.regrepl(1{0}, test, 1{0}, test, 1{0},test, 1{0}, test, 1{0}, test, 1{0}, test)}',
						'id:desc_size' => 5
					],
					'result' => '*UNKNOWN*'
				]
			],
			'Macro functions tr(), uppercase(), lowercase() with non-ascii characters' => [
				[
					'fields' => [
						'Advanced configuration' => true,
						'id:description' => '{'.self::MACRO_CHAR.'.tr(0-9, Ī)}, {'.self::MACRO_CHAR.'.lowercase()}, '.
							'{'.self::MACRO_CHAR.'.uppercase()}',
						'id:desc_size' => 5
					],
					'result' => '??? ЙщфхжЖŽzŠsšĒĀīī🌴 ₰₰₰, 000 ЙщфхжЖŽzŠsšĒĀīī🌴 ₰₰₰, 000 ЙщфхжЖŽZŠSšĒĀīī🌴 ₰₰₰'
				]
			],
			'Macro function tr() - use of escaping and range' => [
				[
					'fields' => [
						'Advanced configuration' => true,
						'id:description' => '{'.self::MACRO_URL_ENCODE.'.tr("\/","\"")}, {'.self::MACRO_CHAR.'.tr(0-9abcA-L,*)}',
						'id:desc_size' => 5
					],
					'result' => 'h:""test.com"macro?functions=urlencode&urld=a🎸, *** ЙщфхжЖŽzŠsšĒĀīī🌴 ₰₰₰'
				]
			],
			'Macro functions regsub() / iregsub() - successful scenarios' => [
				[
					'fields' => [
						'Advanced configuration' => true,
						'id:description' => '{'.self::USER_MACRO.'.regsub(^[0-9]+, Problem)}, '.
							'{'.self::USER_MACRO.'.iregsub(^[0-9]+, Problem)}, '.
							'{'.self::USER_SECRET_MACRO.'.regsub(^[0-9]+, Problem)}, '.
							'{'.self::USER_SECRET_MACRO.'.iregsub(^[0-9]+, Problem)}, '.
							'{{ITEM.NAME}.regsub(Float, test)}, {{ITEM.NAME}.iregsub(Float, test)}',
						'id:desc_size' => 5
					],
					'result' => 'Problem, Problem, Problem, Problem, test, test'
				]
			]
			// TODO: Uncomment and check the test case, after ZBX-25420 fix.
//			'Macro functions regsub() / iregsub() - successful scenarios' => [
//				[
//					'fields' => [
//						'Advanced configuration' => true,
//						'id:description' => '{'.self::USER_MACRO.'.regsub(0, Problem)}, '.
//							'{'.self::USER_MACRO.'.iregsub(0, Problem)}, '.
//							'{'.self::USER_SECRET_MACRO.'.regsub(0, Problem)}, '.
//							'{'.self::USER_SECRET_MACRO.'.iregsub(0, Problem)}, '.
//							'{{ITEM.NAME}.regsub(0, test)}, {{ITEM.NAME}.iregsub(0, test)}',
//						'id:desc_size' => 5
//					],
//					'result' => ', , , , ,'
//				]
//			]
		];
	}

	/**
	 * @dataProvider getMacroFunctions
	 */
	public function testDashboardGaugeWidget_CheckMacroFunctions($data) {
		$this->setWidgetConfiguration(self::$macrofunction_dashboardid,
				self::GAUGE_MACROFUNCTIONS, $data['fields']
		);
		CDashboardElement::find()->one()->save()->waitUntilReady();

		// Check the resolution of macrofunction.
		$this->assertEquals($data['result'], $this->query('css:.svg-gauge-description')->one()->getText());
	}
}