Test Setup Failed
Push — BoundedQuantityValue ( 1533af...50a07a )
by Daniel
05:04
created

QuantityHtmlFormatterTest::getInstance()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 3
rs 10
cc 1
eloc 2
nc 1
nop 1
1
<?php
2
3
namespace ValueFormatters\Test;
4
5
use DataValues\BoundedQuantityValue;
6
use DataValues\QuantityValue;
7
use ValueFormatters\DecimalFormatter;
8
use ValueFormatters\FormatterOptions;
9
use ValueFormatters\QuantityHtmlFormatter;
10
11
/**
12
 * @covers ValueFormatters\QuantityHtmlFormatter
13
 *
14
 * @license GPL-2.0+
15
 * @author Thiemo Mättig
16
 */
17
class QuantityHtmlFormatterTest extends ValueFormatterTestBase {
18
19
	/**
20
	 * @deprecated since DataValues Interfaces 0.2, just use getInstance.
21
	 */
22
	protected function getFormatterClass() {
23
		throw new \LogicException( 'Should not be called, use getInstance' );
24
	}
25
26
	/**
27
	 * @see ValueFormatterTestBase::getInstance
28
	 *
29
	 * @param FormatterOptions|null $options
30
	 *
31
	 * @return QuantityHtmlFormatter
32
	 */
33
	protected function getInstance( FormatterOptions $options = null ) {
34
		return $this->getQuantityHtmlFormatter( $options );
35
	}
36
37
	/**
38
	 * @param FormatterOptions|null $options
39
	 * @param DecimalFormatter|null $decimalFormatter
40
	 * @param string|null $quantityWithUnitFormat
41
	 *
42
	 * @return QuantityHtmlFormatter
43
	 */
44
	private function getQuantityHtmlFormatter(
45
		FormatterOptions $options = null,
46
		DecimalFormatter $decimalFormatter = null,
47
		$quantityWithUnitFormat = null
48
	) {
49
		$vocabularyUriFormatter = $this->getMock( 'ValueFormatters\ValueFormatter' );
50
		$vocabularyUriFormatter->expects( $this->any() )
51
			->method( 'format' )
52
			->will( $this->returnCallback( function( $unit ) {
53
				return $unit === '1' ? null : $unit;
54
			} ) );
55
56
		return new QuantityHtmlFormatter(
57
			$options,
58
			$decimalFormatter,
59
			$vocabularyUriFormatter,
60
			$quantityWithUnitFormat
61
		);
62
	}
63
64
	/**
65
	 * @see ValueFormatterTestBase::validProvider
66
	 */
67
	public function validProvider() {
68
		return array(
0 ignored issues
show
Bug Best Practice introduced by
The return type of return array('Unbounded,...on&lt;/b&gt;</span>')); (array<string,array<DataV...\QuantityValue|string>>) is incompatible with the return type declared by the abstract method ValueFormatters\Test\Val...TestBase::validProvider of type array[].

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
69
			'Unbounded, Unit 1' => array(
70
				QuantityValue::newFromNumber( '+2', '1' ),
71
				'2'
72
			),
73
			'Unbounded, String unit' => array(
74
				QuantityValue::newFromNumber( '+2', 'Ultrameter' ),
75
				'2 <span class="wb-unit">Ultrameter</span>'
76
			),
77
			'Bounded, Unit 1' => array(
78
				BoundedQuantityValue::newFromNumber( '+2', '1', '+3', '+1' ),
79
				'2±1'
80
			),
81
			'Bounded, String unit' => array(
82
				BoundedQuantityValue::newFromNumber( '+2', 'Ultrameter', '+3', '+1' ),
83
				'2±1 <span class="wb-unit">Ultrameter</span>'
84
			),
85
			'HTML injection' => array(
86
				BoundedQuantityValue::newFromNumber( '+2', '<b>injection</b>', '+2', '+2' ),
87
				'2±0 <span class="wb-unit">&lt;b&gt;injection&lt;/b&gt;</span>'
88
			),
89
		);
90
	}
91
92
	public function testFormatWithFormatString() {
93
		$formatter = $this->getQuantityHtmlFormatter( null, null, '$2&thinsp;$1' );
94
		$value = QuantityValue::newFromNumber( '+5', 'USD' );
95
		$formatted = $formatter->format( $value );
96
		$this->assertSame( '<span class="wb-unit">USD</span>&thinsp;5', $formatted );
97
	}
98
99
	/**
100
	 * @dataProvider applyUnitOptionProvider
101
	 */
102
	public function testGivenHtmlCharacters_formatEscapesHtmlCharacters(
103
		FormatterOptions $options = null,
104
		$unit,
105
		$expected
106
	) {
107
		$decimalFormatter = $this->getMock( 'ValueFormatters\DecimalFormatter' );
108
		$decimalFormatter->expects( $this->any() )
109
			->method( 'format' )
110
			->will( $this->returnValue( '<b>+2</b>' ) );
111
112
		$formatter = $this->getQuantityHtmlFormatter( $options, $decimalFormatter );
113
		$formatted = $formatter->format( QuantityValue::newFromNumber( '+2', $unit ) );
114
		$this->assertSame( $expected, $formatted );
115
	}
116
117
	public function applyUnitOptionProvider() {
118
		$noUnit = new FormatterOptions();
119
		$noUnit->setOption( QuantityHtmlFormatter::OPT_APPLY_UNIT, false );
120
121
		return array(
122
			'Disabled without unit' => array(
123
				$noUnit,
124
				'1',
125
				'&lt;b&gt;+2&lt;/b&gt;'
126
			),
127
			'Disabled with unit' => array(
128
				$noUnit,
129
				'<b>m</b>',
130
				'&lt;b&gt;+2&lt;/b&gt;'
131
			),
132
			'Default without unit' => array(
133
				null,
134
				'1',
135
				'&lt;b&gt;+2&lt;/b&gt;'
136
			),
137
			'Default with unit' => array(
138
				null,
139
				'<b>m</b>',
140
				'&lt;b&gt;+2&lt;/b&gt; <span class="wb-unit">&lt;b&gt;m&lt;/b&gt;</span>'
141
			),
142
		);
143
	}
144
145
}
146