Completed
Push — master ( 8a10f5...330c1d )
by Der Mundschenk
02:58
created

Transients_Test::setUp()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 3
nc 1
nop 0
dl 0
loc 6
rs 9.4285
c 0
b 0
f 0
1
<?php
2
/**
3
 * This file is part of mundschenk-at/wp-data-storage.
4
 *
5
 * Copyright 2017-2018 Peter Putzer.
6
 *
7
 * This program is free software; you can redistribute it and/or
8
 * modify it under the terms of the GNU General Public License
9
 * as published by the Free Software Foundation; either version 2
10
 * of the License, or ( at your option ) any later version.
11
 *
12
 * This program is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU General Public License
18
 * along with this program; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
20
 *
21
 * @package mundschenk-at/wp-data-storage/tests
22
 * @license http://www.gnu.org/licenses/gpl-2.0.html
23
 */
24
25
namespace Mundschenk\Data_Storage\Tests;
26
27
use Mundschenk\Data_Storage\Transients;
28
29
use Brain\Monkey\Actions;
30
use Brain\Monkey\Filters;
31
use Brain\Monkey\Functions;
32
33
use Mockery as m;
34
35
/**
36
 * Mundschenk\Data_Storage\Transients unit test for the singleton methods.
37
 *
38
 * @coversDefaultClass \Mundschenk\Data_Storage\Transients
39
 * @usesDefaultClass \Mundschenk\Data_Storage\Transients
40
 *
41
 * @uses ::__construct
42
 * @uses \Mundschenk\Data_Storage\Abstract_Cache::__construct
43
 */
44
class Transients_Test extends TestCase {
45
46
	const PREFIX          = 'my_prefix_';
47
	const INCREMENTOR_KEY = self::PREFIX . 'transients_incrementor';
48
49
	/**
50
	 * Test fixture.
51
	 *
52
	 * @var \Mundschenk\Data_Storage\Transients
53
	 */
54
	protected $transients;
55
56
	/**
57
	 * Sets up the fixture, for example, opens a network connection.
58
	 * This method is called before a test is executed.
59
	 */
60
	protected function setUp() { // @codingStandardsIgnoreLine
61
		Functions\expect( 'get_transient' )->once()->with( self::INCREMENTOR_KEY )->andReturn( 999 );
62
63
		$this->transients = m::mock( Transients::class, [ self::PREFIX ] )->shouldAllowMockingProtectedMethods()->makePartial();
64
65
		parent::setUp();
66
	}
67
68
	/**
69
	 * Necesssary clean-up work.
70
	 */
71
	protected function tearDown() { // @codingStandardsIgnoreLine
72
		parent::tearDown();
73
	}
74
75
	/**
76
	 * Tests constructor.
77
	 *
78
	 * @covers ::__construct
79
	 *
80
	 * @uses \Mundschenk\Data_Storage\Abstract_Cache::__construct
81
	 */
82
	public function test___construct() {
83
		Functions\expect( 'get_transient' )->once()->with( 'some_prefix_transients_incrementor' )->andReturn( 0 );
84
85
		$transients = m::mock( Transients::class )->shouldAllowMockingProtectedMethods()->makePartial()
86
			->shouldReceive( 'invalidate' )->once()
87
			->getMock();
88
		$transients->__construct( 'some_prefix_' );
89
90
		$this->assertInstanceOf( Transients::class, $transients );
91
	}
92
93
	/**
94
	 * Provides data for testing invalidate.
95
	 *
96
	 * @return array
97
	 */
98
	public function provide_invalidate_data() {
99
		return [
100
			[ [ 'bar', 'baz' ], true ],
101
			[ [ 'bar', 'baz' ], false ],
102
		];
103
	}
104
105
	/**
106
	 * Tests invalidate.
107
	 *
108
	 * @dataProvider provide_invalidate_data
109
	 *
110
	 * @covers ::invalidate
111
	 *
112
	 * @uses ::get_key
113
	 *
114
	 * @param string[] $expected_keys        An array of transient keys.
115
	 * @param bool     $object_cache_enabled The result of wp_using_ext_object_cache().
116
	 */
117
	public function test_invalidate( $expected_keys, $object_cache_enabled ) {
118
119
		if ( ! $object_cache_enabled ) {
120
			$this->transients->shouldReceive( 'get_keys_from_database' )->once()->andReturn( $expected_keys );
121
122
			foreach ( $expected_keys as $raw_key ) {
123
				Functions\expect( 'delete_transient' )->once()->with( $raw_key );
124
			}
125
		}
126
127
		Functions\expect( 'set_transient' )->once()->with( self::INCREMENTOR_KEY, m::type( 'int' ) );
128
		Functions\expect( 'wp_using_ext_object_cache' )->once()->andReturn( $object_cache_enabled );
129
130
		$this->transients->invalidate();
131
132
		$this->assertTrue( true );
133
	}
134
135
	/**
136
	 * Tests get_keys_from_database.
137
	 *
138
	 * @covers ::get_keys_from_database
139
	 */
140
	public function test_get_keys_from_database() {
141
		$dummy_result = [ [ 'option_name' => Transients::TRANSIENT_SQL_PREFIX . 'typo_foobar' ] ];
142
143
		global $wpdb;
144
145
		if ( ! defined( 'ARRAY_A' ) ) {
146
			define( 'ARRAY_A', 'array' );
147
		}
148
149
		$wpdb          = m::mock( 'wpdb' ); // WPCS: override ok.
150
		$wpdb->options = 'wp_options';
151
		$wpdb->shouldReceive( 'prepare' )->with( m::type( 'string' ), Transients::TRANSIENT_SQL_PREFIX . self::PREFIX . '%' )->andReturn( 'fake SQL string' );
152
		$wpdb->shouldReceive( 'get_results' )->with( 'fake SQL string', ARRAY_A )->andReturn( $dummy_result );
153
154
		Functions\expect( 'wp_list_pluck' )->once()->with( $dummy_result, 'option_name' )->andReturn( [ 'typo_foobar' ] );
155
156
		$this->assertSame( [ 'typo_foobar' ], $this->transients->get_keys_from_database() );
157
	}
158
159
	/**
160
	 * Tests get.
161
	 *
162
	 * @covers ::get
163
	 */
164
	public function test_get() {
165
		$raw_key = 'foo';
166
		$key     = 'bar_foo';
167
168
		$this->transients->shouldReceive( 'get_key' )->once()->with( $raw_key )->andReturn( $key );
169
170
		Functions\expect( 'get_transient' )->once()->with( $key )->andReturn( 'bar' );
171
172
		$this->assertSame( 'bar', $this->transients->get( $raw_key ) );
173
	}
174
175
	/**
176
	 * Tests set.
177
	 *
178
	 * @covers ::set
179
	 */
180
	public function test_set() {
181
		$value    = 'bar';
182
		$raw_key  = 'foo';
183
		$key      = 'bar_foo';
184
		$duration = 99;
185
186
		$this->transients->shouldReceive( 'get_key' )->once()->with( $raw_key )->andReturn( $key );
187
188
		Functions\expect( 'set_transient' )->once()->with( $key, $value, $duration )->andReturn( true );
189
190
		$this->assertTrue( $this->transients->set( $raw_key, $value, $duration ) );
191
	}
192
193
	/**
194
	 * Tests set_large_object. Can't test the failing branch.
195
	 *
196
	 * @covers ::set_large_object
197
	 */
198
	public function test_set_large_object() {
199
		$value    = new \stdClass();
200
		$raw_key  = 'foo';
201
		$duration = 99;
202
203
		$this->transients->shouldReceive( 'set' )->once()->with( $raw_key, m::type( 'string' ), $duration )->andReturn( true );
204
205
		$this->assertTrue( $this->transients->set_large_object( $raw_key, $value, $duration ) );
206
	}
207
208
	/**
209
	 * Tests get_large_object.
210
	 *
211
	 * @covers ::get_large_object
212
	 */
213
	public function test_get_large_object() {
214
		$raw_key = 'foo';
215
216
		$this->transients->shouldReceive( 'get' )->once()->with( $raw_key )->andReturn( \base64_encode( \gzencode( \serialize( new \stdClass() ) ) ) ); // @codingStandardsIgnoreLine
217
		$this->transients->shouldReceive( 'maybe_fix_object' )->once()->with( m::type( \stdClass::class ) )->andReturnUsing( function( $object ) {
218
			return $object;
219
		} );
220
221
		$this->assertInstanceOf( \stdClass::class, $this->transients->get_large_object( $raw_key ) );
222
	}
223
224
	/**
225
	 * Tests get_large_object (but not found).
226
	 *
227
	 * @covers ::get_large_object
228
	 */
229
	public function test_get_large_object_not_found() {
230
		$raw_key = 'foo';
231
232
		$this->transients->shouldReceive( 'get' )->once()->with( $raw_key )->andReturn( false );
233
234
		$this->assertFalse( $this->transients->get_large_object( $raw_key ) );
235
	}
236
237
	/**
238
	 * Tests get_large_object with failing uncompress.
239
	 *
240
	 * @covers ::get_large_object
241
	 */
242
	public function test_get_large_object_uncompression_failing() {
243
		$raw_key = 'foo';
244
245
		$this->transients->shouldReceive( 'get' )->once()->with( $raw_key )->andReturn( \base64_encode( \serialize( new \stdClass() ) ) ); // @codingStandardsIgnoreLine
246
247
		$this->assertFalse( $this->transients->get_large_object( $raw_key ) );
248
	}
249
250
	/**
251
	 * Tests delete.
252
	 *
253
	 * @covers ::delete
254
	 *
255
	 * @uses ::get_key
256
	 */
257
	public function test_delete() {
258
		$raw_key = 'foo';
259
		$key     = $this->invokeMethod( $this->transients, 'get_key', [ $raw_key ] );
260
261
		Functions\expect( 'delete_transient' )->once()->with( $key )->andReturn( true );
262
263
		$this->assertTrue( $this->transients->delete( $raw_key ) );
264
	}
265
266
	/**
267
	 * Test maybe_fix_object.
268
	 *
269
	 * @covers ::maybe_fix_object
270
	 */
271
	public function test_maybe_fix_object() {
272
		$fake_object_string = 'O:16:"SomeMissingClass":1:{s:1:"a";s:1:"b";}';
273
		$fake_object        = unserialize( $fake_object_string ); // @codingStandardsIgnoreLine
274
275
		// Unfortunately, serialize and  unserialize cannot be mocked.
276
		$object = $this->invokeMethod( $this->transients, 'maybe_fix_object', [ $fake_object ] );
277
278
		$this->assertTrue( $object !== $fake_object );
279
	}
280
}
281