Completed
Push — master ( 89a848...b1dea0 )
by frank
01:40
created

AOTest::test_is_plugin_active_utils_wrapper()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 0
dl 0
loc 6
rs 10
c 0
b 0
f 0
1
<?php
2
3
class AOTest extends WP_UnitTestcase
4
{
5
    /**
6
     * Plugin instance/fixture used in some tests.
7
     *
8
     * @var autoptimizeMain
9
     */
10
    protected $ao;
11
12
    protected static $flexible_url_parts_js = [
13
        'default'          => 'wp-content/cache/autoptimize/js/' . AUTOPTIMIZE_CACHEFILE_PREFIX,
14
        'custom'           => 'wp-content/c/ao/js/' . AUTOPTIMIZE_CACHEFILE_PREFIX,
15
        'multisite'        => 'wp-content/cache/autoptimize/1/js/' . AUTOPTIMIZE_CACHEFILE_PREFIX,
16
        'multisite_custom' => 'wp-content/c/ao/1/js/' . AUTOPTIMIZE_CACHEFILE_PREFIX,
17
    ];
18
19
    protected static $flexible_url_parts_css = [
20
        'default'          => 'wp-content/cache/autoptimize/css/' . AUTOPTIMIZE_CACHEFILE_PREFIX,
21
        'custom'           => 'wp-content/c/ao/css/' . AUTOPTIMIZE_CACHEFILE_PREFIX,
22
        'multisite'        => 'wp-content/cache/autoptimize/1/css/' . AUTOPTIMIZE_CACHEFILE_PREFIX,
23
        'multisite_custom' => 'wp-content/c/ao/1/css/' . AUTOPTIMIZE_CACHEFILE_PREFIX,
24
    ];
25
26
    protected function getAoStylesDefaultOptions()
27
    {
28
        $conf = autoptimizeConfig::instance();
29
30
        return [
31
            'aggregate'       => $conf->get( 'autoptimize_css_aggregate' ),
32
            'justhead'        => $conf->get( 'autoptimize_css_justhead' ),
33
            'datauris'        => $conf->get( 'autoptimize_css_datauris' ),
34
            'defer'           => $conf->get( 'autoptimize_css_defer' ),
35
            'defer_inline'    => $conf->get( 'autoptimize_css_defer_inline' ),
36
            'inline'          => $conf->get( 'autoptimize_css_inline' ),
37
            'css_exclude'     => $conf->get( 'autoptimize_css_exclude' ),
38
            'cdn_url'         => $conf->get( 'autoptimize_cdn_url' ),
39
            'include_inline'  => $conf->get( 'autoptimize_css_include_inline' ),
40
            'nogooglefont'    => $conf->get( 'autoptimize_css_nogooglefont' ),
41
            'minify_excluded' => $conf->get( 'autoptimize_minify_excluded' ),
42
        ];
43
    }
44
45
    protected function getAoScriptsDefaultOptions()
46
    {
47
        $conf = autoptimizeConfig::instance();
48
49
        return [
50
            'aggregate'       => $conf->get( 'autoptimize_js_aggregate' ),
51
            'justhead'        => $conf->get( 'autoptimize_js_justhead' ),
52
            'forcehead'       => $conf->get( 'autoptimize_js_forcehead' ),
53
            'trycatch'        => $conf->get( 'autoptimize_js_trycatch' ),
54
            'js_exclude'      => $conf->get( 'autoptimize_js_exclude' ),
55
            'cdn_url'         => $conf->get( 'autoptimize_cdn_url' ),
56
            'include_inline'  => $conf->get( 'autoptimize_js_include_inline' ),
57
            'minify_excluded' => $conf->get( 'autoptimize_minify_excluded' ),
58
        ];
59
    }
60
61
    /**
62
     * @return array
63
     */
64
    protected function get_urls()
65
    {
66
        static $site_url = null;
67
        if ( null === $site_url ) {
68
            $site_url = site_url();
69
        }
70
71
        static $cdn_url = null;
72
        if ( null === $cdn_url ) {
73
            $cdn_url = get_option( 'autoptimize_cdn_url' );
74
        }
75
76
        static $imgopt_host = null;
77
        if ( null === $imgopt_host ) {
78
            $optimizer   = new autoptimizeImages();
79
            $imgopt_host = rtrim( $optimizer->get_imgopt_host(), '/' );
80
        }
81
82
        static $urls = [];
83
84
        if ( empty( $urls ) ) {
85
            $parts = autoptimizeUtils::get_ao_wp_site_url_parts();
86
            $urls  = [
87
                'siteurl'    => $site_url,
88
                'prsiteurl'  => '//' . str_replace( array( 'http://', 'https://' ), '', $site_url ),
89
                'wwwsiteurl' => $parts['scheme'] . '://www.' . str_replace( 'www.', '', $parts['host'] ),
90
                'cdnurl'     => $cdn_url,
91
                'imgopthost' => $imgopt_host,
92
                'subfolder'  => '',
93
            ];
94
95
            if ( AO_TEST_SUBFOLDER_INSTALL ) {
96
                $urls['subfolder'] = 'wordpress/';
97
            }
98
        }
99
100
        return $urls;
101
    }
102
103
    /**
104
     * Runs before each test method.
105
     */
106
    public function setUp()
107
    {
108
        $this->ao = new autoptimizeMain( AUTOPTIMIZE_PLUGIN_VERSION, AUTOPTIMIZE_PLUGIN_FILE );
109
110
        parent::setUp();
111
    }
112
113
    /**
114
     * Runs after each test method.
115
     */
116
    public function tearDown()
117
    {
118
        // Making sure certain filters are removed after each test to ensure isolation.
119
        $filter_tags = array(
120
            'autoptimize_filter_noptimize',
121
            'autoptimize_filter_base_cdnurl',
122
            'autoptimize_filter_css_is_datauri_candidate',
123
            'autoptimize_filter_css_datauri_image',
124
            'autoptimize_filter_css_inlinesize',
125
            'autoptimize_filter_css_fonts_cdn',
126
        );
127
        foreach ( $filter_tags as $filter_tag ) {
128
            remove_all_filters( $filter_tag );
129
        }
130
131
        parent::tearDown();
132
    }
133
134
    protected function get_test_markup()
135
    {
136
        $siteurl = $this->get_urls()['siteurl'];
137
138
        $markup = <<<MARKUP
139
<!DOCTYPE html>
140
<!--[if lt IE 7]> <html class="no-svg no-js lt-ie9 lt-ie8 lt-ie7"  xmlns:fb="https://www.facebook.com/2008/fbml"  xmlns:og="http://ogp.me/ns#" lang="hr"> <![endif]-->
141
<!--[if IE 7]> <html class="no-svg no-js lt-ie9 lt-ie8"  xmlns:fb="https://www.facebook.com/2008/fbml"  xmlns:og="http://ogp.me/ns#" lang="hr"> <![endif]-->
142
<!--[if IE 8]> <html class="no-svg no-js lt-ie9"  xmlns:fb="https://www.facebook.com/2008/fbml"  xmlns:og="http://ogp.me/ns#" lang="hr"> <![endif]-->
143
<!--[if gt IE 8]><!--> <html class="no-svg no-js"  xmlns:fb="https://www.facebook.com/2008/fbml"  xmlns:og="http://ogp.me/ns#" lang="hr"> <!--<![endif]-->
144
<head>
145
<meta charset="utf-8">
146
<title>Mliječna juha od brokule &#9832; Kuhaj.hr</title>
147
<meta name="viewport" content="width=device-width,initial-scale=1">
148
<style type="text/css">
149
/* cdn rewrite tests */
150
151
.bg { background:url('img/something.svg'); }
152
.bg-no-quote { background: url(img/something.svg); }
153
.bg-double-quotes { background: url("img/something.svg"); }
154
155
.whitespaces { background : url   (  "../../somewhere-else/svg.svg" ) ; }
156
157
.host-relative { background: url("/img/something.svg"); }
158
.protocol-relative { background: url("//something/somewhere/example.png"); }
159
160
/* roboto-100 - latin-ext_latin */
161
@font-face {
162
    font-family: 'Roboto';
163
    font-style: normal;
164
    font-weight: 100;
165
    src: url('../fonts/roboto-v15-latin-ext_latin-100.eot'); /* IE9 Compat Modes */
166
    src: local('Roboto Thin'), local('Roboto-Thin'),
167
        url('../fonts/roboto-v15-latin-ext_latin-100.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
168
        url('../fonts/roboto-v15-latin-ext_latin-100.woff2') format('woff2'), /* Super Modern Browsers */
169
        url('../fonts/roboto-v15-latin-ext_latin-100.woff') format('woff'), /* Modern Browsers */
170
        url('../fonts/roboto-v15-latin-ext_latin-100.ttf') format('truetype'), /* Safari, Android, iOS */
171
        url('../fonts/roboto-v15-latin-ext_latin-100.svg#Roboto') format('svg'); /* Legacy iOS */
172
}
173
/* roboto-300 - latin-ext_latin */
174
@font-face {
175
    font-family: 'Roboto';
176
    font-style: normal;
177
    font-weight: 300;
178
    src: url('../fonts/roboto-v15-latin-ext_latin-300.eot'); /* IE9 Compat Modes */
179
    src: local('Roboto Light'), local('Roboto-Light'),
180
        url('../fonts/roboto-v15-latin-ext_latin-300.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
181
        url('../fonts/roboto-v15-latin-ext_latin-300.woff2') format('woff2'), /* Super Modern Browsers */
182
        url('../fonts/roboto-v15-latin-ext_latin-300.woff') format('woff'), /* Modern Browsers */
183
        url('../fonts/roboto-v15-latin-ext_latin-300.ttf') format('truetype'), /* Safari, Android, iOS */
184
        url('../fonts/roboto-v15-latin-ext_latin-300.svg#Roboto') format('svg'); /* Legacy iOS */
185
}
186
/* roboto-regular - latin-ext_latin */
187
@font-face {
188
    font-family: 'Roboto';
189
    font-style: normal;
190
    font-weight: 400;
191
    src: url('../fonts/roboto-v15-latin-ext_latin-regular.eot'); /* IE9 Compat Modes */
192
    src: local('Roboto'), local('Roboto-Regular'),
193
        url('../fonts/roboto-v15-latin-ext_latin-regular.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
194
        url('../fonts/roboto-v15-latin-ext_latin-regular.woff2') format('woff2'), /* Super Modern Browsers */
195
        url('../fonts/roboto-v15-latin-ext_latin-regular.woff') format('woff'), /* Modern Browsers */
196
        url('../fonts/roboto-v15-latin-ext_latin-regular.ttf') format('truetype'), /* Safari, Android, iOS */
197
        url('../fonts/roboto-v15-latin-ext_latin-regular.svg#Roboto') format('svg'); /* Legacy iOS */
198
}
199
/* roboto-500 - latin-ext_latin */
200
@font-face {
201
    font-family: 'Roboto';
202
    font-style: normal;
203
    font-weight: 500;
204
    src: url('../fonts/roboto-v15-latin-ext_latin-500.eot'); /* IE9 Compat Modes */
205
    src: local('Roboto Medium'), local('Roboto-Medium'),
206
        url('../fonts/roboto-v15-latin-ext_latin-500.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
207
        url('../fonts/roboto-v15-latin-ext_latin-500.woff2') format('woff2'), /* Super Modern Browsers */
208
        url('../fonts/roboto-v15-latin-ext_latin-500.woff') format('woff'), /* Modern Browsers */
209
        url('../fonts/roboto-v15-latin-ext_latin-500.ttf') format('truetype'), /* Safari, Android, iOS */
210
        url('../fonts/roboto-v15-latin-ext_latin-500.svg#Roboto') format('svg'); /* Legacy iOS */
211
}
212
</style>
213
    <!--[if lt IE 9]>
214
    <script src="$siteurl/wp-content/themes/my-theme/js/vendor/html5shiv-printshiv.min.js" type="text/javascript"></script>
215
    <![endif]-->
216
    <!--[if (gte IE 6)&(lte IE 8)]>
217
        <script type="text/javascript" src="$siteurl/wp-content/themes/my-theme/js/vendor/respond.min.js"></script>
218
    <![endif]-->
219
</head>
220
221
<body class="single single-post">
222
223
    <div id="fb-root"></div>
224
    <script>(function(d, s, id) {
225
        var js, fjs = d.getElementsByTagName(s)[0];
226
        if (d.getElementById(id)) return;
227
        js = d.createElement(s); js.id = id;
228
        js.src = "//connect.facebook.net/hr_HR/sdk.js#version=v2.0&xfbml=1&appId=";
229
        fjs.parentNode.insertBefore(js, fjs);
230
    }(document, 'script', 'facebook-jssdk'));</script>
231
    </script>
232
233
<script type='text/javascript' src='$siteurl/wp-content/plugins/ajax-load-more/core/js/ajax-load-more.min.js?ver=1.1'></script>
234
<script type='text/javascript' src='$siteurl/wp-content/plugins/wp-ga-social-tracking-js/ga-social-tracking.min.js'></script>
235
<script type='text/javascript' src='$siteurl/wp-content/themes/my-theme/js/vendor/alm-seo.js'></script>
236
<script type='text/javascript' src='$siteurl/wp-content/themes/my-theme/js/vendor/jquery.placeholder-2.1.1.min.js'></script>
237
<script type='text/javascript' src='$siteurl/wp-content/themes/my-theme/js/vendor/typeahead.bundle.min.js'></script>
238
<script type='text/javascript' src='$siteurl/wp-content/themes/my-theme/js/vendor/bootstrap-tagsinput.min.js'></script>
239
<script type='text/javascript' src='$siteurl/wp-content/themes/my-theme/js/m-mobilemenu.js'></script>
240
<script type='text/javascript' src='$siteurl/wp-content/themes/my-theme/js/main.js'></script>
241
<script type='text/javascript' src='$siteurl/wp-includes/js/comment-reply.min.js?ver=4.1.1'></script>
242
</body>
243
</html>
244
MARKUP;
245
246
        return $markup;
247
    }
248
249 View Code Duplication
    protected function get_test_markup_output()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
250
    {
251
        $key = 'default';
252
        if ( defined( 'CUSTOM_CONSTANTS_USED' ) && CUSTOM_CONSTANTS_USED ) {
253
            $key = 'custom';
254
        }
255
256
        $csspart = self::$flexible_url_parts_css[ $key ];
257
        $jspart  = self::$flexible_url_parts_js[ $key ];
258
259
        $csshash = '863f587e89f100b0223ddccc0dabc57a';
260
        if ( AO_TEST_SUBFOLDER_INSTALL ) {
261
            $csshash = '56398de576d59887e88e3011715250e0';
262
        }
263
264
        $urls      = $this->get_urls();
265
        $siteurl   = $urls['siteurl'];
266
        $cdnurl    = $urls['cdnurl'];
267
        $subfolder = $urls['subfolder'];
268
269
        $markup = <<<MARKUP
270
<!DOCTYPE html>
271
<!--[if lt IE 7]> <html class="no-svg no-js lt-ie9 lt-ie8 lt-ie7"  xmlns:fb="https://www.facebook.com/2008/fbml"  xmlns:og="http://ogp.me/ns#" lang="hr"> <![endif]-->
272
<!--[if IE 7]> <html class="no-svg no-js lt-ie9 lt-ie8"  xmlns:fb="https://www.facebook.com/2008/fbml"  xmlns:og="http://ogp.me/ns#" lang="hr"> <![endif]-->
273
<!--[if IE 8]> <html class="no-svg no-js lt-ie9"  xmlns:fb="https://www.facebook.com/2008/fbml"  xmlns:og="http://ogp.me/ns#" lang="hr"> <![endif]-->
274
<!--[if gt IE 8]><!--> <html class="no-svg no-js"  xmlns:fb="https://www.facebook.com/2008/fbml"  xmlns:og="http://ogp.me/ns#" lang="hr"> <!--<![endif]-->
275
<head>
276
<meta charset="utf-8">
277
<link type="text/css" media="all" href="${cdnurl}/${subfolder}${csspart}${csshash}.css" rel="stylesheet" /><title>Mliječna juha od brokule &#9832; Kuhaj.hr</title>
278
<meta name="viewport" content="width=device-width,initial-scale=1">
279
280
    <!--[if lt IE 9]>
281
    <script src="$siteurl/wp-content/themes/my-theme/js/vendor/html5shiv-printshiv.min.js" type="text/javascript"></script>
282
    <![endif]-->
283
    <!--[if (gte IE 6)&(lte IE 8)]>
284
        <script type="text/javascript" src="$siteurl/wp-content/themes/my-theme/js/vendor/respond.min.js"></script>
285
    <![endif]-->
286
</head>
287
288
<body class="single single-post">
289
290
    <div id="fb-root"></div>
291
    <script>(function(d, s, id) {
292
        var js, fjs = d.getElementsByTagName(s)[0];
293
        if (d.getElementById(id)) return;
294
        js = d.createElement(s); js.id = id;
295
        js.src = "//connect.facebook.net/hr_HR/sdk.js#version=v2.0&xfbml=1&appId=";
296
        fjs.parentNode.insertBefore(js, fjs);
297
    }(document, 'script', 'facebook-jssdk'));</script>
298
    </script>
299
300
<script type='text/javascript' src='$siteurl/wp-content/plugins/ajax-load-more/core/js/ajax-load-more.min.js?ver=1.1'></script>
301
<script type='text/javascript' src='$siteurl/wp-content/plugins/wp-ga-social-tracking-js/ga-social-tracking.min.js'></script>
302
<script type='text/javascript' src='$siteurl/wp-content/themes/my-theme/js/vendor/alm-seo.js'></script>
303
<script type='text/javascript' src='$siteurl/wp-content/themes/my-theme/js/vendor/jquery.placeholder-2.1.1.min.js'></script>
304
<script type='text/javascript' src='$siteurl/wp-content/themes/my-theme/js/vendor/typeahead.bundle.min.js'></script>
305
<script type='text/javascript' src='$siteurl/wp-content/themes/my-theme/js/vendor/bootstrap-tagsinput.min.js'></script>
306
<script type='text/javascript' src='$siteurl/wp-content/themes/my-theme/js/m-mobilemenu.js'></script>
307
<script type='text/javascript' src='$siteurl/wp-content/themes/my-theme/js/main.js'></script>
308
309
<script type="text/javascript" defer src="$cdnurl/${subfolder}${jspart}f452d67a906f6ee73da68e553e43da58.js"></script></body>
310
</html>
311
MARKUP;
312
313
        return $markup;
314
    }
315
316 View Code Duplication
    protected function get_test_markup_output_ms()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
317
    {
318
        $key = 'multisite';
319
        if ( defined( 'CUSTOM_CONSTANTS_USED' ) && CUSTOM_CONSTANTS_USED ) {
320
            $key = 'multisite_custom';
321
        }
322
323
        $csspart = self::$flexible_url_parts_css[ $key ];
324
        $jspart  = self::$flexible_url_parts_js[ $key ];
325
326
        $csshash = '863f587e89f100b0223ddccc0dabc57a';
327
        if ( AO_TEST_SUBFOLDER_INSTALL ) {
328
            $csshash = '56398de576d59887e88e3011715250e0';
329
        }
330
331
        $urls      = $this->get_urls();
332
        $siteurl   = $urls['siteurl'];
333
        $cdnurl    = $urls['cdnurl'];
334
        $subfolder = $urls['subfolder'];
335
336
        $markup = <<<MARKUP
337
<!DOCTYPE html>
338
<!--[if lt IE 7]> <html class="no-svg no-js lt-ie9 lt-ie8 lt-ie7"  xmlns:fb="https://www.facebook.com/2008/fbml"  xmlns:og="http://ogp.me/ns#" lang="hr"> <![endif]-->
339
<!--[if IE 7]> <html class="no-svg no-js lt-ie9 lt-ie8"  xmlns:fb="https://www.facebook.com/2008/fbml"  xmlns:og="http://ogp.me/ns#" lang="hr"> <![endif]-->
340
<!--[if IE 8]> <html class="no-svg no-js lt-ie9"  xmlns:fb="https://www.facebook.com/2008/fbml"  xmlns:og="http://ogp.me/ns#" lang="hr"> <![endif]-->
341
<!--[if gt IE 8]><!--> <html class="no-svg no-js"  xmlns:fb="https://www.facebook.com/2008/fbml"  xmlns:og="http://ogp.me/ns#" lang="hr"> <!--<![endif]-->
342
<head>
343
<meta charset="utf-8">
344
<link type="text/css" media="all" href="$cdnurl/${subfolder}${csspart}${csshash}.css" rel="stylesheet" /><title>Mliječna juha od brokule &#9832; Kuhaj.hr</title>
345
<meta name="viewport" content="width=device-width,initial-scale=1">
346
347
    <!--[if lt IE 9]>
348
    <script src="$siteurl/wp-content/themes/my-theme/js/vendor/html5shiv-printshiv.min.js" type="text/javascript"></script>
349
    <![endif]-->
350
    <!--[if (gte IE 6)&(lte IE 8)]>
351
        <script type="text/javascript" src="$siteurl/wp-content/themes/my-theme/js/vendor/respond.min.js"></script>
352
    <![endif]-->
353
</head>
354
355
<body class="single single-post">
356
357
    <div id="fb-root"></div>
358
    <script>(function(d, s, id) {
359
        var js, fjs = d.getElementsByTagName(s)[0];
360
        if (d.getElementById(id)) return;
361
        js = d.createElement(s); js.id = id;
362
        js.src = "//connect.facebook.net/hr_HR/sdk.js#version=v2.0&xfbml=1&appId=";
363
        fjs.parentNode.insertBefore(js, fjs);
364
    }(document, 'script', 'facebook-jssdk'));</script>
365
    </script>
366
367
<script type='text/javascript' src='$siteurl/wp-content/plugins/ajax-load-more/core/js/ajax-load-more.min.js?ver=1.1'></script>
368
<script type='text/javascript' src='$siteurl/wp-content/plugins/wp-ga-social-tracking-js/ga-social-tracking.min.js'></script>
369
<script type='text/javascript' src='$siteurl/wp-content/themes/my-theme/js/vendor/alm-seo.js'></script>
370
<script type='text/javascript' src='$siteurl/wp-content/themes/my-theme/js/vendor/jquery.placeholder-2.1.1.min.js'></script>
371
<script type='text/javascript' src='$siteurl/wp-content/themes/my-theme/js/vendor/typeahead.bundle.min.js'></script>
372
<script type='text/javascript' src='$siteurl/wp-content/themes/my-theme/js/vendor/bootstrap-tagsinput.min.js'></script>
373
<script type='text/javascript' src='$siteurl/wp-content/themes/my-theme/js/m-mobilemenu.js'></script>
374
<script type='text/javascript' src='$siteurl/wp-content/themes/my-theme/js/main.js'></script>
375
376
<script type="text/javascript" defer src="$cdnurl/${subfolder}${jspart}f452d67a906f6ee73da68e553e43da58.js"></script></body>
377
</html>
378
MARKUP;
379
380
        return $markup;
381
    }
382
383 View Code Duplication
    protected function get_test_markup_output_inline_defer()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
384
    {
385
        $key = 'default';
386
        if ( defined( 'CUSTOM_CONSTANTS_USED' ) && CUSTOM_CONSTANTS_USED ) {
387
            $key = 'custom';
388
        }
389
390
        $csspart = self::$flexible_url_parts_css[ $key ];
391
        $jspart  = self::$flexible_url_parts_js[ $key ];
392
393
        $csshash = '863f587e89f100b0223ddccc0dabc57a';
394
        if ( AO_TEST_SUBFOLDER_INSTALL ) {
395
            $csshash = '56398de576d59887e88e3011715250e0';
396
        }
397
398
        $urls      = $this->get_urls();
399
        $siteurl   = $urls['siteurl'];
400
        $cdnurl    = $urls['cdnurl'];
401
        $subfolder = $urls['subfolder'];
402
403
        $markup = <<<MARKUP
404
<!DOCTYPE html>
405
<!--[if lt IE 7]> <html class="no-svg no-js lt-ie9 lt-ie8 lt-ie7"  xmlns:fb="https://www.facebook.com/2008/fbml"  xmlns:og="http://ogp.me/ns#" lang="hr"> <![endif]-->
406
<!--[if IE 7]> <html class="no-svg no-js lt-ie9 lt-ie8"  xmlns:fb="https://www.facebook.com/2008/fbml"  xmlns:og="http://ogp.me/ns#" lang="hr"> <![endif]-->
407
<!--[if IE 8]> <html class="no-svg no-js lt-ie9"  xmlns:fb="https://www.facebook.com/2008/fbml"  xmlns:og="http://ogp.me/ns#" lang="hr"> <![endif]-->
408
<!--[if gt IE 8]><!--> <html class="no-svg no-js"  xmlns:fb="https://www.facebook.com/2008/fbml"  xmlns:og="http://ogp.me/ns#" lang="hr"> <!--<![endif]-->
409
<head>
410
<meta charset="utf-8">
411
<style type="text/css" id="aoatfcss" media="all">1</style><link rel="preload" as="style" media="all" href="$cdnurl/${subfolder}${csspart}{$csshash}.css" onload="this.onload=null;this.rel='stylesheet'" /><noscript id="aonoscrcss"><link type="text/css" media="all" href="$cdnurl/${subfolder}${csspart}${csshash}.css" rel="stylesheet" /></noscript><title>Mliječna juha od brokule &#9832; Kuhaj.hr</title>
412
<meta name="viewport" content="width=device-width,initial-scale=1">
413
414
    <!--[if lt IE 9]>
415
    <script src="$siteurl/wp-content/themes/my-theme/js/vendor/html5shiv-printshiv.min.js" type="text/javascript"></script>
416
    <![endif]-->
417
    <!--[if (gte IE 6)&(lte IE 8)]>
418
        <script type="text/javascript" src="$siteurl/wp-content/themes/my-theme/js/vendor/respond.min.js"></script>
419
    <![endif]-->
420
</head>
421
422
<body class="single single-post">
423
424
    <div id="fb-root"></div>
425
    <script>(function(d, s, id) {
426
        var js, fjs = d.getElementsByTagName(s)[0];
427
        if (d.getElementById(id)) return;
428
        js = d.createElement(s); js.id = id;
429
        js.src = "//connect.facebook.net/hr_HR/sdk.js#version=v2.0&xfbml=1&appId=";
430
        fjs.parentNode.insertBefore(js, fjs);
431
    }(document, 'script', 'facebook-jssdk'));</script>
432
    </script>
433
434
<script type='text/javascript' src='$siteurl/wp-content/plugins/ajax-load-more/core/js/ajax-load-more.min.js?ver=1.1'></script>
435
<script type='text/javascript' src='$siteurl/wp-content/plugins/wp-ga-social-tracking-js/ga-social-tracking.min.js'></script>
436
<script type='text/javascript' src='$siteurl/wp-content/themes/my-theme/js/vendor/alm-seo.js'></script>
437
<script type='text/javascript' src='$siteurl/wp-content/themes/my-theme/js/vendor/jquery.placeholder-2.1.1.min.js'></script>
438
<script type='text/javascript' src='$siteurl/wp-content/themes/my-theme/js/vendor/typeahead.bundle.min.js'></script>
439
<script type='text/javascript' src='$siteurl/wp-content/themes/my-theme/js/vendor/bootstrap-tagsinput.min.js'></script>
440
<script type='text/javascript' src='$siteurl/wp-content/themes/my-theme/js/m-mobilemenu.js'></script>
441
<script type='text/javascript' src='$siteurl/wp-content/themes/my-theme/js/main.js'></script>
442
443
<script type="text/javascript" defer src="$cdnurl/${subfolder}${jspart}f452d67a906f6ee73da68e553e43da58.js"></script><script data-cfasync='false'>!function(t){"use strict";t.loadCSS||(t.loadCSS=function(){});var e=loadCSS.relpreload={};if(e.support=function(){var e;try{e=t.document.createElement("link").relList.supports("preload")}catch(t){e=!1}return function(){return e}}(),e.bindMediaToggle=function(t){function e(){t.media=a}var a=t.media||"all";t.addEventListener?t.addEventListener("load",e):t.attachEvent&&t.attachEvent("onload",e),setTimeout(function(){t.rel="stylesheet",t.media="only x"}),setTimeout(e,3e3)},e.poly=function(){if(!e.support())for(var a=t.document.getElementsByTagName("link"),n=0;n<a.length;n++){var o=a[n];"preload"!==o.rel||"style"!==o.getAttribute("as")||o.getAttribute("data-loadcss")||(o.setAttribute("data-loadcss",!0),e.bindMediaToggle(o))}},!e.support()){e.poly();var a=t.setInterval(e.poly,500);t.addEventListener?t.addEventListener("load",function(){e.poly(),t.clearInterval(a)}):t.attachEvent&&t.attachEvent("onload",function(){e.poly(),t.clearInterval(a)})}"undefined"!=typeof exports?exports.loadCSS=loadCSS:t.loadCSS=loadCSS}("undefined"!=typeof global?global:this);</script></body>
444
</html>
445
MARKUP;
446
447
        return $markup;
448
    }
449
450 View Code Duplication
    protected function get_test_markup_output_inline_defer_ms()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
451
    {
452
        $key = 'multisite';
453
        if ( defined( 'CUSTOM_CONSTANTS_USED' ) && CUSTOM_CONSTANTS_USED ) {
454
            $key = 'multisite_custom';
455
        }
456
457
        $csspart = self::$flexible_url_parts_css[ $key ];
458
        $jspart  = self::$flexible_url_parts_js[ $key ];
459
460
        $csshash = '863f587e89f100b0223ddccc0dabc57a';
461
        if ( AO_TEST_SUBFOLDER_INSTALL ) {
462
            $csshash = '56398de576d59887e88e3011715250e0';
463
        }
464
465
        $urls      = $this->get_urls();
466
        $siteurl   = $urls['siteurl'];
467
        $cdnurl    = $urls['cdnurl'];
468
        $subfolder = $urls['subfolder'];
469
470
        $markup = <<<MARKUP
471
<!DOCTYPE html>
472
<!--[if lt IE 7]> <html class="no-svg no-js lt-ie9 lt-ie8 lt-ie7"  xmlns:fb="https://www.facebook.com/2008/fbml"  xmlns:og="http://ogp.me/ns#" lang="hr"> <![endif]-->
473
<!--[if IE 7]> <html class="no-svg no-js lt-ie9 lt-ie8"  xmlns:fb="https://www.facebook.com/2008/fbml"  xmlns:og="http://ogp.me/ns#" lang="hr"> <![endif]-->
474
<!--[if IE 8]> <html class="no-svg no-js lt-ie9"  xmlns:fb="https://www.facebook.com/2008/fbml"  xmlns:og="http://ogp.me/ns#" lang="hr"> <![endif]-->
475
<!--[if gt IE 8]><!--> <html class="no-svg no-js"  xmlns:fb="https://www.facebook.com/2008/fbml"  xmlns:og="http://ogp.me/ns#" lang="hr"> <!--<![endif]-->
476
<head>
477
<meta charset="utf-8">
478
<style type="text/css" id="aoatfcss" media="all">1</style><link rel="preload" as="style" media="all" href="$cdnurl/${subfolder}${csspart}${csshash}.css" onload="this.onload=null;this.rel='stylesheet'" /><noscript id="aonoscrcss"><link type="text/css" media="all" href="$cdnurl/${subfolder}${csspart}${csshash}.css" rel="stylesheet" /></noscript><title>Mliječna juha od brokule &#9832; Kuhaj.hr</title>
479
<meta name="viewport" content="width=device-width,initial-scale=1">
480
481
    <!--[if lt IE 9]>
482
    <script src="$siteurl/wp-content/themes/my-theme/js/vendor/html5shiv-printshiv.min.js" type="text/javascript"></script>
483
    <![endif]-->
484
    <!--[if (gte IE 6)&(lte IE 8)]>
485
        <script type="text/javascript" src="$siteurl/wp-content/themes/my-theme/js/vendor/respond.min.js"></script>
486
    <![endif]-->
487
</head>
488
489
<body class="single single-post">
490
491
    <div id="fb-root"></div>
492
    <script>(function(d, s, id) {
493
        var js, fjs = d.getElementsByTagName(s)[0];
494
        if (d.getElementById(id)) return;
495
        js = d.createElement(s); js.id = id;
496
        js.src = "//connect.facebook.net/hr_HR/sdk.js#version=v2.0&xfbml=1&appId=";
497
        fjs.parentNode.insertBefore(js, fjs);
498
    }(document, 'script', 'facebook-jssdk'));</script>
499
    </script>
500
501
<script type='text/javascript' src='$siteurl/wp-content/plugins/ajax-load-more/core/js/ajax-load-more.min.js?ver=1.1'></script>
502
<script type='text/javascript' src='$siteurl/wp-content/plugins/wp-ga-social-tracking-js/ga-social-tracking.min.js'></script>
503
<script type='text/javascript' src='$siteurl/wp-content/themes/my-theme/js/vendor/alm-seo.js'></script>
504
<script type='text/javascript' src='$siteurl/wp-content/themes/my-theme/js/vendor/jquery.placeholder-2.1.1.min.js'></script>
505
<script type='text/javascript' src='$siteurl/wp-content/themes/my-theme/js/vendor/typeahead.bundle.min.js'></script>
506
<script type='text/javascript' src='$siteurl/wp-content/themes/my-theme/js/vendor/bootstrap-tagsinput.min.js'></script>
507
<script type='text/javascript' src='$siteurl/wp-content/themes/my-theme/js/m-mobilemenu.js'></script>
508
<script type='text/javascript' src='$siteurl/wp-content/themes/my-theme/js/main.js'></script>
509
510
<script type="text/javascript" defer src="$cdnurl/${subfolder}${jspart}f452d67a906f6ee73da68e553e43da58.js"></script><script data-cfasync='false'>!function(t){"use strict";t.loadCSS||(t.loadCSS=function(){});var e=loadCSS.relpreload={};if(e.support=function(){var e;try{e=t.document.createElement("link").relList.supports("preload")}catch(t){e=!1}return function(){return e}}(),e.bindMediaToggle=function(t){function e(){t.media=a}var a=t.media||"all";t.addEventListener?t.addEventListener("load",e):t.attachEvent&&t.attachEvent("onload",e),setTimeout(function(){t.rel="stylesheet",t.media="only x"}),setTimeout(e,3e3)},e.poly=function(){if(!e.support())for(var a=t.document.getElementsByTagName("link"),n=0;n<a.length;n++){var o=a[n];"preload"!==o.rel||"style"!==o.getAttribute("as")||o.getAttribute("data-loadcss")||(o.setAttribute("data-loadcss",!0),e.bindMediaToggle(o))}},!e.support()){e.poly();var a=t.setInterval(e.poly,500);t.addEventListener?t.addEventListener("load",function(){e.poly(),t.clearInterval(a)}):t.attachEvent&&t.attachEvent("onload",function(){e.poly(),t.clearInterval(a)})}"undefined"!=typeof exports?exports.loadCSS=loadCSS:t.loadCSS=loadCSS}("undefined"!=typeof global?global:this);</script></body>
511
</html>
512
MARKUP;
513
514
        return $markup;
515
    }
516
517
    /**
518
     * @dataProvider provider_test_rewrite_markup_with_cdn
519
     */
520
    function test_rewrite_markup_with_cdn( $input, $expected )
521
    {
522
        $actual = $this->ao->end_buffering( $input );
523
524
        $this->assertEquals( $expected, $actual );
525
    }
526
527
    public function provider_test_rewrite_markup_with_cdn()
528
    {
529
        return array(
530
531
            array(
532
                // Input.
533
                $this->get_test_markup(),
534
                // Expected output.
535
                // TODO/FIXME: This seemed like the fastest way to get MS crude test to pass...
536
                ( is_multisite() ? $this->get_test_markup_output_ms() : $this->get_test_markup_output() ),
537
            ),
538
539
        );
540
    }
541
542
    public function test_rewrite_css_assets()
543
    {
544
        $urls   = $this->get_urls();
545
        $cdnurl = $urls['cdnurl'];
546
        $sub    = $urls['subfolder'];
547
548
        $css_in = <<<CSS
549
.bg { background:url('img/something.svg'); }
550
.bg-no-quote { background: url(img/something.svg); }
551
.bg-double-quotes { background: url("img/something.svg"); }
552
553
.whitespaces { background : url   (  "../../somewhere-else/svg.svg" ) ; }
554
555
.host-relative { background: url("/img/something.svg"); }
556
.protocol-relative { background: url("//something/somewhere/example.png"); }
557
558
@font-face {
559
  font-family: 'Roboto';
560
  font-style: normal;
561
  font-weight: 100;
562
  src: url('../fonts/roboto-v15-latin-ext_latin-100.eot'); /* IE9 Compat Modes */
563
  src: local('Roboto Thin'), local('Roboto-Thin'),
564
       url('../fonts/roboto-v15-latin-ext_latin-100.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
565
       url('../fonts/roboto-v15-latin-ext_latin-100.woff2') format('woff2'), /* Super Modern Browsers */
566
       url('../fonts/roboto-v15-latin-ext_latin-100.woff') format('woff'), /* Modern Browsers */
567
       url('../fonts/roboto-v15-latin-ext_latin-100.ttf') format('truetype'), /* Safari, Android, iOS */
568
       url('../fonts/roboto-v15-latin-ext_latin-100.svg#Roboto') format('svg'); /* Legacy iOS */
569
}
570
CSS;
571
572
        $css_expected = <<<CSS
573
.bg { background:url(img/something.svg); }
574
.bg-no-quote { background: url(img/something.svg); }
575
.bg-double-quotes { background: url(img/something.svg); }
576
577
.whitespaces { background : url   (  ../../somewhere-else/svg.svg) ; }
578
579
.host-relative { background: url(${cdnurl}/${sub}img/something.svg); }
580
.protocol-relative { background: url(//something/somewhere/example.png); }
581
582
@font-face {
583
  font-family: 'Roboto';
584
  font-style: normal;
585
  font-weight: 100;
586
  src: url('../fonts/roboto-v15-latin-ext_latin-100.eot'); /* IE9 Compat Modes */
587
  src: local('Roboto Thin'), local('Roboto-Thin'),
588
       url('../fonts/roboto-v15-latin-ext_latin-100.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
589
       url('../fonts/roboto-v15-latin-ext_latin-100.woff2') format('woff2'), /* Super Modern Browsers */
590
       url('../fonts/roboto-v15-latin-ext_latin-100.woff') format('woff'), /* Modern Browsers */
591
       url('../fonts/roboto-v15-latin-ext_latin-100.ttf') format('truetype'), /* Safari, Android, iOS */
592
       url('../fonts/roboto-v15-latin-ext_latin-100.svg#Roboto') format('svg'); /* Legacy iOS */
593
}
594
CSS;
595
596
        $instance = new autoptimizeStyles( $css_in );
597
        $instance->setOption( 'cdn_url', $cdnurl );
598
599
        $css_actual = $instance->rewrite_assets( $css_in );
600
601
        $this->assertEquals( $css_expected, $css_actual );
602
    }
603
604 View Code Duplication
    public function test_default_cssmin_minifier()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
605
    {
606
        $css = <<<CSS
607
.bg { background:url('img/something.svg'); }
608
.bg-no-quote { background: url(img/something.svg); }
609
.bg-double-quotes { background: url("img/something.svg"); }
610
611
.whitespaces { background : url   (  "../../somewhere-else/svg.svg" ) ; }
612
613
.host-relative { background: url("/img/something.svg"); }
614
.protocol-relative { background: url("//something/somewhere/example.png"); }
615
616
/* roboto-100 - latin-ext_latin */
617
@font-face {
618
  font-family: 'Roboto';
619
  font-style: normal;
620
  font-weight: 100;
621
  src: url(../fonts/roboto-v15-latin-ext_latin-100.eot); /* IE9 Compat Modes */
622
  src: local('Roboto Thin'), local('Roboto-Thin'),
623
       url(../fonts/roboto-v15-latin-ext_latin-100.eot?#iefix) format('embedded-opentype'), /* IE6-IE8 */
624
       url(../fonts/roboto-v15-latin-ext_latin-100.woff2) format('woff2'), /* Super Modern Browsers */
625
       url(../fonts/roboto-v15-latin-ext_latin-100.woff) format('woff'), /* Modern Browsers */
626
       url(../fonts/roboto-v15-latin-ext_latin-100.ttf) format('truetype'), /* Safari, Android, iOS */
627
       url(../fonts/roboto-v15-latin-ext_latin-100.svg#Roboto) format('svg'); /* Legacy iOS */
628
}
629
CSS;
630
631
        $expected = <<<CSS
632
.bg{background:url('img/something.svg')}.bg-no-quote{background:url(img/something.svg)}.bg-double-quotes{background:url("img/something.svg")}.whitespaces{background:url ("../../somewhere-else/svg.svg")}.host-relative{background:url("/img/something.svg")}.protocol-relative{background:url("//something/somewhere/example.png")}@font-face{font-family:'Roboto';font-style:normal;font-weight:100;src:url(../fonts/roboto-v15-latin-ext_latin-100.eot);src:local('Roboto Thin'),local('Roboto-Thin'),url(../fonts/roboto-v15-latin-ext_latin-100.eot?#iefix) format('embedded-opentype'),url(../fonts/roboto-v15-latin-ext_latin-100.woff2) format('woff2'),url(../fonts/roboto-v15-latin-ext_latin-100.woff) format('woff'),url(../fonts/roboto-v15-latin-ext_latin-100.ttf) format('truetype'),url(../fonts/roboto-v15-latin-ext_latin-100.svg#Roboto) format('svg')}
633
CSS;
634
635
        $instance = new autoptimizeStyles( $css );
636
        $minified = $instance->run_minifier_on( $css );
637
638
        $this->assertEquals( $expected, $minified );
639
    }
640
641
    /**
642
     * @dataProvider provider_test_should_aggregate_script_types
643
     */
644
    public function test_should_aggregate_script_types( $input, $expected )
645
    {
646
        $instance = new autoptimizeScripts( '' );
647
        $actual   = $instance->should_aggregate( $input );
648
649
        $this->assertEquals( $expected, $actual );
650
    }
651
652
    public function provider_test_should_aggregate_script_types()
653
    {
654
        return array(
655
            // No type attribute at all.
656
            array(
657
                // Input.
658
                '<script>var something=true</script>',
659
                // Expected output.
660
                true,
661
            ),
662
            // Case-insensitive.
663
            array(
664
                '<script type="text/ecmaScript">var something=true</script>',
665
                true,
666
            ),
667
            // Allowed/aggregated now (wasn't previously).
668
            array(
669
                '<script type="application/javascript">var something=true</script>',
670
                true,
671
            ),
672
            // Quotes shouldn't matter, nor should case-sensitivity.
673
            array(
674
                '<script type=\'text/JaVascriPt">var something=true</script>',
675
                true,
676
            ),
677
            // Liberal to whitespace around attribute names/values.
678
            array(
679
                '<script tYpe = text/javascript>var something=true</script>',
680
                true,
681
            ),
682
            // Something custom, should be ignored/skipped.
683
            array(
684
                '<script type=template/javascript>var something=true</script>',
685
                false,
686
            ),
687
            // Type attribute checking should be constrained to actual script
688
            // tag's type attribute only, regardless of any `type=` string
689
            // present in the actual inline script contents.
690
            array(
691
                // Since there's no type attribute, it should be aggregate by default.
692
                '<script>var type=something;</script>',
693
                true,
694
            ),
695
            // Application/ld+json should not be aggregated by default regardless
696
            // of spacing around attr/values.
697
            array(
698
                '<script type = "application/ld+json" >{   "@context": "" }',
699
                false,
700
            ),
701
            array(
702
                '<script type="application/ld+json">{   "@context": "" }',
703
                false,
704
            ),
705
        );
706
    }
707
708
    /**
709
     * @dataProvider provider_is_valid_buffer
710
     */
711
    public function test_valid_buffers( $input, $expected )
712
    {
713
        $actual = $this->ao->is_valid_buffer( $input );
714
715
        $this->assertEquals( $expected, $actual );
716
    }
717
718
    public function provider_is_valid_buffer()
719
    {
720
        return array(
721
            array(
722
                '<!doctype html>
723
<html ⚡>',
724
                false,
725
            ),
726
            array(
727
                '<!doctype html>
728
<html amp>',
729
                false,
730
            ),
731
            array(
732
                '<?xml version="1.0" encoding="UTF-8"?>
733
<xsl:stylesheet version="1.0"
734
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">',
735
                false,
736
            ),
737
            array(
738
                '<!doctype html>
739
<html>',
740
                true,
741
            ),
742
            array(
743
                '<html dir="ltr" amp>',
744
                false,
745
            ),
746
            array(
747
                '<html dir="ltr" ⚡>',
748
                false,
749
            ),
750
            array(
751
                '<html amp dir="ltr">',
752
                false,
753
            ),
754
            array(
755
                '<html ⚡ dir="ltr">',
756
                false,
757
            ),
758
            array(
759
                '<HTML ⚡ DIR="LTR">',
760
                false,
761
            ),
762
            array(
763
                '<HTML AMP DIR="LTR">',
764
                false,
765
            ),
766
            // @link https://github.com/futtta/autoptimize/commit/54385939db06f725fcafe68598cce6ed148ef6c1
767
            array(
768
                '<!doctype html>',
769
                true,
770
            ),
771
        );
772
    }
773
774
    /**
775
     * @dataProvider provider_is_amp_markup
776
     */
777
    public function test_autoptimize_is_amp_markup( $input, $expected )
778
    {
779
        $actual = autoptimizeMain::is_amp_markup( $input );
780
781
        $this->assertEquals( $expected, $actual );
782
    }
783
784
    public function provider_is_amp_markup()
785
    {
786
        return array(
787
            array(
788
                '<!doctype html>
789
<html ⚡>',
790
                true,
791
            ),
792
            array(
793
                '<!doctype html>
794
<html amp>',
795
                true,
796
            ),
797
            array(
798
                '<!doctype html>
799
<head>
800
<meta charset=utf-8>',
801
                false,
802
            ),
803
        );
804
    }
805
806
    /**
807
     * Test various conditions that can/should prevent autoptimize from buffering content.
808
     */
809 View Code Duplication
    public function test_skips_buffering_when_ao_noptimize_filter_is_true()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
810
    {
811
        // True => disable autoptimize.
812
        add_filter( 'autoptimize_filter_noptimize', '__return_true' );
813
814
        // Buffering should not run due to the above filter.
815
        $expected = false;
816
        $actual   = $this->ao->should_buffer( $doing_tests = true );
817
818
        $this->assertEquals( $expected, $actual );
819
    }
820
821 View Code Duplication
    public function test_does_buffering_when_ao_noptimize_filter_is_false()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
822
    {
823
        // False => disable noptimize, aka, run normally (weird, yes...).
824
        add_filter( 'autoptimize_filter_noptimize', '__return_false' );
825
826
        // Buffering should run because of above.
827
        $expected = true;
828
        $actual   = $this->ao->should_buffer( $doing_tests = true );
829
830
        $this->assertEquals( $expected, $actual );
831
    }
832
833
    public function test_ignores_ao_noptimize_qs_when_instructed()
834
    {
835
        // Should skip checking for the qs completely due to filter.
836
        add_filter( 'autoptimize_filter_honor_qs_noptimize', '__return_false' );
837
838
        /**
839
         * The above should then result in the "current" value being `false`
840
         * when passed to 'autoptimize_filter_noptimize' unless the DONOTMINIFY
841
         * constant is defined, which changes the result... Which basically
842
         * means this test changes its' expected result depending on the order
843
         * of tests execution and/or the environment, which is AAAARGGGGGGHHH...
844
         */
845
846
        $that = $this; // Makes it work on php 5.3!
847
        add_filter( 'autoptimize_filter_noptimize', function ( $current_value ) use ( $that ) {
848
            $expected = false;
849
            if ( defined( 'DONOTMINIFY' ) && DONOTMINIFY ) {
850
                $expected = true;
851
            }
852
853
            $that->assertEquals( $expected, $current_value );
854
        });
855
856
        $this->ao->should_buffer( $doing_tests = true );
857
    }
858
859
    public function test_wpengine_cache_flush()
860
    {
861
        // Creating a mock so that we can get past class_exists() and method_exists() checks present
862
        // in `autoptimizeCache::flushPageCache()`...
863
        $stub = $this->getMockBuilder( 'WpeCommon' )->disableAutoload()
0 ignored issues
show
Unused Code introduced by
$stub is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
864
                ->disableOriginalConstructor()->setMethods(
865
                    array(
866
                        'purge_varnish_cache',
867
                    )
868
                )
869
                ->getMock();
870
871
        $that = $this;
872
        add_filter( 'autoptimize_flush_wpengine_methods', function( $methods ) use ( $that ) {
873
            $expected_methods = array( 'purge_varnish_cache' );
874
            $that->assertEquals( $methods, $expected_methods );
875
876
            return $methods;
877
        });
878
879
        autoptimizeCache::flushPageCache();
880
    }
881
882
    /**
883
     * Tests the `autoptimize_flush_wpengine_aggressive` filter
884
     */
885
    public function test_wpengine_cache_flush_agressive()
886
    {
887
        // Creating a mock so that we can get past class_exists() and method_exists() checks `autoptimize_flush_pagecache()`...
888
        $stub = $this->getMockBuilder( 'WpeCommon' )->disableAutoload()
0 ignored issues
show
Unused Code introduced by
$stub is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
889
                ->disableOriginalConstructor()->setMethods(
890
                    array(
891
                        'purge_varnish_cache',
892
                        'purge_memcached',
893
                        'clear_maxcdn_cache',
894
                    )
895
                )
896
                ->getMock();
897
898
        add_filter( 'autoptimize_flush_wpengine_aggressive', function() {
899
            return true;
900
        });
901
902
        $that = $this;
903
        add_filter( 'autoptimize_flush_wpengine_methods', function( $methods ) use ( $that ) {
904
            $expected_methods = array(
905
                'purge_varnish_cache',
906
                'purge_memcached',
907
                'clear_maxcdn_cache',
908
            );
909
910
            $that->assertEquals( $methods, $expected_methods );
911
912
            return $methods;
913
        });
914
915
        autoptimizeCache::flushPageCache();
916
    }
917
918
    /**
919
     * @dataProvider provider_test_url_replace_cdn
920
     */
921
    public function test_url_replace_cdn( $cdn_url, $input, $expected )
922
    {
923
        $mock = $this->getMockBuilder( 'autoptimizeBase' )
924
                ->disableOriginalConstructor()
925
                ->getMockForAbstractClass();
926
927
        $mock->cdn_url = $cdn_url;
928
        $actual        = $mock->url_replace_cdn( $input );
929
        $this->assertEquals( $expected, $actual );
930
    }
931
932
    public function provider_test_url_replace_cdn()
933
    {
934
        $urls                 = $this->get_urls();
935
        $siteurl              = $urls['siteurl'];
936
        $wwwsiteurl           = $urls['wwwsiteurl'];
937
        $protorelativesiteurl = $urls['prsiteurl'];
938
        $subfolder            = $urls['subfolder'];
939
940
        return array(
941
            // Host-relative links get properly transformed...
942
            array(
943
                // CDN base url, url, expected result...
944
                'http://cdn-test.example.org',
945
                '/a.jpg',
946
                'http://cdn-test.example.org/' . $subfolder . 'a.jpg',
947
            ),
948
            // Full link with a matching AUTOPTIMIZE_WP_SITE_URL gets properly replaced...
949
            array(
950
                'http://cdn-test.example.org',
951
                $siteurl . '/wp-content/themes/something/example.svg',
952
                'http://cdn-test.example.org/' . $subfolder . 'wp-content/themes/something/example.svg',
953
            ),
954
            // Protocol-relative url with a "local" hostname that doesn't match example.org (AUTOPTIMIZE_WP_SITE_URL)...
955
            array(
956
                'http://cdn-test.example.org',
957
                '//something/somewhere.jpg',
958
                '//something/somewhere.jpg',
959
            ),
960
            // www.example.org does not match example.org (AUTOPTIMIZE_WP_SITE_URL) so it's left alone...
961
            array(
962
                'http://cdn-test.example.org',
963
                $wwwsiteurl . '/wp-content/themes/something/example.svg',
964
                $wwwsiteurl . '/wp-content/themes/something/example.svg',
965
            ),
966
            // SSL cdn url + host-relative link...
967
            array(
968
                'https://cdn.example.org',
969
                '/a.jpg',
970
                'https://cdn.example.org/' . $subfolder . 'a.jpg',
971
            ),
972
            // SSL cdn url + http site url that matches AUTOPTIMIZE_WP_SITE_URL is properly replaced...
973
            array(
974
                'https://cdn.example.org',
975
                $siteurl . '/wp-content/themes/something/example.svg',
976
                'https://cdn.example.org/' . $subfolder . 'wp-content/themes/something/example.svg',
977
            ),
978
            // Protocol-relative cdn url given with protocol relative link that matches AUTOPTIMIZE_WP_SITE_URL host...
979
            array(
980
                '//cdn.example.org',
981
                $protorelativesiteurl . '/something.jpg',
982
                '//cdn.example.org/' . $subfolder . 'something.jpg',
983
            ),
984
            // Protocol-relative cdn url given a http link that matches AUTOPTIMIZE_WP_SITE_URL host...
985
            array(
986
                '//cdn.example.org',
987
                $siteurl . '/something.png',
988
                '//cdn.example.org/' . $subfolder . 'something.png',
989
            ),
990
            // Protocol-relative cdn url with a host-relative link...
991
            array(
992
                '//cdn.example.org',
993
                '/a.jpg',
994
                '//cdn.example.org/' . $subfolder . 'a.jpg',
995
            ),
996
            // Testing cdn urls with an explicit port number...
997
            array(
998
                'http://cdn.com:8080',
999
                '/a.jpg',
1000
                'http://cdn.com:8080/' . $subfolder . 'a.jpg',
1001
            ),
1002
            array(
1003
                '//cdn.com:4433',
1004
                '/a.jpg',
1005
                '//cdn.com:4433/' . $subfolder . 'a.jpg',
1006
            ),
1007
            array(
1008
                '//cdn.com:4433',
1009
                $siteurl . '/something.jpg',
1010
                '//cdn.com:4433/' . $subfolder . 'something.jpg',
1011
            ),
1012
            array(
1013
                '//cdn.com:1234',
1014
                $protorelativesiteurl . '/something.jpg',
1015
                '//cdn.com:1234/' . $subfolder . 'something.jpg',
1016
            ),
1017
            // Relative links should not be touched by url_replace_cdn()...
1018
            array(
1019
                // Base cdn url.
1020
                'http://cdn-test.example.org',
1021
                // Url.
1022
                'a.jpg',
1023
                // Expected result.
1024
                'a.jpg',
1025
            ),
1026
            array(
1027
                'http://cdn-test.example.org',
1028
                './a.jpg',
1029
                './a.jpg',
1030
            ),
1031
            array(
1032
                'http://cdn-test.example.org',
1033
                '../something/somewhere.svg',
1034
                '../something/somewhere.svg',
1035
            ),
1036
            // These prove some weird combinations pre-2.4 remain working
1037
            // even though they are really strange...
1038
            array(
1039
                $siteurl, // example.org or http://localhost or http://localhost/wordpress
1040
                $siteurl . '/something.jpg',
1041
                $siteurl . '/something.jpg',
1042
            ),
1043
            // These shouldn't really be changed, or even if replacements do
1044
            // happen, they shouldn't be destructive...
1045
            array(
1046
                'http://localhost/wp',
1047
                'http://localhost/wp/something.jpg',
1048
                'http://localhost/wp/something.jpg',
1049
            ),
1050
            array(
1051
                'http://localhost',
1052
                'http://localhost/something.jpg',
1053
                'http://localhost/something.jpg',
1054
            ),
1055
            array(
1056
                'http://localhost',
1057
                'http://localhost/wordpress/something.jpg',
1058
                'http://localhost/wordpress/something.jpg',
1059
            ),
1060
            array(
1061
                'http://localhost/wordpress',
1062
                'http://localhost/wordpress/something.jpg',
1063
                'http://localhost/wordpress/something.jpg',
1064
            ),
1065
        );
1066
    }
1067
1068
    /**
1069
     * Tests `autoptimize_filter_base_cdnurl` filtering as described here:
1070
     * https://wordpress.org/support/topic/disable-cdn-of-ssl-pages
1071
     */
1072
    public function test_autoptimize_filter_base_cdnurl()
1073
    {
1074
        $urls = $this->get_urls();
1075
        $sub  = $urls['subfolder'];
1076
1077
        $test_link = '/a.jpg';
1078
        $cdn_url   = '//cdn.example.org';
1079
1080
        $with_ssl = function( $cdn ) {
0 ignored issues
show
Unused Code introduced by
The parameter $cdn is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1081
            return '';
1082
        };
1083
        $expected_with_ssl = '/a.jpg';
1084
1085
        $without_ssl = function( $cdn ) {
1086
            return $cdn;
1087
        };
1088
        $expected_without_ssl = '//cdn.example.org/' . $sub . 'a.jpg';
1089
1090
        // With a filter that returns something considered "empty", cdn replacement shouldn't occur...
1091
        add_filter( 'autoptimize_filter_base_cdnurl', $with_ssl );
1092
        $mock = $this->getMockBuilder( 'autoptimizeBase' )
1093
                ->disableOriginalConstructor()
1094
                ->getMockForAbstractClass();
1095
1096
        $mock->cdn_url   = $cdn_url;
1097
        $actual_with_ssl = $mock->url_replace_cdn( $test_link );
1098
        $this->assertEquals( $expected_with_ssl, $actual_with_ssl );
1099
        remove_filter( 'autoptimize_filter_base_cdnurl', $with_ssl );
1100
1101
        // With a filter that returns an actual cdn url, cdn replacement should occur.
1102
        add_filter( 'autoptimize_filter_base_cdnurl', $without_ssl );
1103
        $actual_without_ssl = $mock->url_replace_cdn( $test_link );
1104
        $this->assertEquals( $expected_without_ssl, $actual_without_ssl );
1105
    }
1106
1107
    public function provider_cssmin_issues()
1108
    {
1109
        return array(
1110
            // @link https://wordpress.org/support/topic/css-minify-breaks-calc-subtract-operation-in-css/?replies=2#post-6610027
1111
            array(
1112
                // Input.
1113
                'input { width: calc(33.33333% - ((0.75em*2)/3)); }',
1114
                // Expected output (ancient version of CSSmin returns 0.75, newer versions drop the 0).
1115
                'input{width:calc(33.33333% - ((.75em*2)/3))}',
1116
            ),
1117
            // Actual examples from above, but original wasn't really valid
1118
            // css input fully, but these tests used to work and we'd like to
1119
            // know if output changes with various CSSmin versions, for
1120
            // backcompat reasons if nothing else.
1121
            array(
1122
                // Input.
1123
                'width: calc(33.33333% - ((0.75em*2)/3));',
1124
                // Expected output.
1125
                'width:calc(33.33333% - ((0.75em*2)/3));',
1126
            ),
1127
            // @link https://github.com/tubalmartin/YUI-CSS-compressor-PHP-port/issues/22#issuecomment-251401341
1128
            array(
1129
                'input { width: calc(100% - (1em*1.5) - 2em); }',
1130
                'input{width:calc(100% - (1em*1.5) - 2em)}',
1131
            ),
1132
            // @link https://github.com/tubalmartin/YUI-CSS-compressor-PHP-port/issues/26
1133
            array(
1134
                '.px { flex: 1 1 0px; }, .percent {flex: 1 1 0%}',
1135
                '.px{flex:1 1 0px},.percent{flex:1 1 0%}',
1136
            ),
1137
        );
1138
    }
1139
1140
    /**
1141
     * @dataProvider provider_cssmin_issues
1142
     */
1143
    public function test_cssmin_issues( $input, $expected )
1144
    {
1145
        $minifier = new autoptimizeCSSmin( false ); // No need to raise limits for now.
1146
        $actual   = $minifier->run( $input );
1147
        $this->assertEquals( $expected, $actual );
1148
    }
1149
1150
    public function provider_getpath()
1151
    {
1152
        return array(
1153
            /**
1154
             * These all don't really exist, and getpath() returns false for
1155
             * non-existing files since upstream's 1386e4fe1d commit.
1156
             */
1157
            array(
1158
                'img/something.svg',
1159
                false,
1160
            ),
1161
            array(
1162
                '../../somewhere-else/svg.svg',
1163
                false,
1164
            ),
1165
            array(
1166
                '//something/somewhere/example.png',
1167
                false,
1168
            ),
1169
            // This file comes with core, so should exist...
1170
            array(
1171
                '/wp-includes/js/jquery/jquery.js',
1172
                WP_ROOT_DIR . '/wp-includes/js/jquery/jquery.js',
1173
            ),
1174
            // Empty $url should return false.
1175
            array(
1176
                '',
1177
                false,
1178
            ),
1179
            array(
1180
                false,
1181
                false,
1182
            ),
1183
            array(
1184
                null,
1185
                false,
1186
            ),
1187
            array(
1188
                0,
1189
                false,
1190
            ),
1191
        );
1192
    }
1193
1194
    /**
1195
     * @dataProvider provider_getpath
1196
     */
1197
    public function test_getpath( $input, $expected )
1198
    {
1199
        $mock = $this->getMockBuilder( 'autoptimizeBase' )->disableOriginalConstructor()->getMockForAbstractClass();
1200
1201
        $actual = $mock->getpath( $input );
1202
        $this->assertEquals( $expected, $actual );
1203
    }
1204
1205
    /**
1206
     * @link https://github.com/futtta/autoptimize/pull/81#issuecomment-278935307
1207
     */
1208
    public function test_fixurls_with_hash_only_urls()
1209
    {
1210
        $urls      = $this->get_urls();
1211
        $siteurl   = $urls['siteurl'];
0 ignored issues
show
Unused Code introduced by
$siteurl is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1212
        $subfolder = $urls['subfolder'];
0 ignored issues
show
Unused Code introduced by
$subfolder is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1213
1214
        $protorelativesiteurl = $urls['prsiteurl'];
1215
1216
        $css_orig     = <<<CSS
1217
header{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='90px' height='110px' viewBox='0 0 90 110'%3E%3Cstyle%3E.a%7Bstop-color:%23FFF;%7D.b%7Bstop-color:%23B2D235;%7D.c%7Bstop-color:%23BEE7FA;%7D.d%7Bfill:%23590C15;%7D%3C/style%3E%3ClinearGradient id='c' y2='135.4' gradientUnits='userSpaceOnUse' x2='209.1' gradientTransform='rotate(-1.467 -4082.888 7786.794)' y1='205.8' x1='262'%3E%3Cstop class='b' offset='0'/%3E%3Cstop class='b' offset='.48'/%3E%3Cstop stop-color='%23829D25' offset='1'/%3E%3C/linearGradient%3E%3Cpath stroke-width='.3' d='M77.3 45.4c-3-3.5-7.1-6.5-11.6-7.8-5.1-1.5-10-.1-14.9 1.5C52 35.4 54.3 29 60 24l-4.8-5.5c-3.4 3-5.8 6.3-7.5 9.4-1.7-4.3-4.1-8.4-7.5-12C33.4 8.6 24.3 4.7 15.1 4.2c-.2 9.3 3.1 18.6 9.9 25.9 5.2 5.6 11.8 9.2 18.7 10.8-2.5.2-4.9-.1-7.7-.9-5.2-1.4-10.5-2.8-15.8-1C10.6 42.3 4.5 51.9 4 61.7c-.5 11.6 3.8 23.8 9.9 33.5 3.9 6.3 9.6 13.7 17.7 13.4 3.8-.1 7-2.1 10.7-2.7 5.2-.8 9.1 1.2 14.1 1.8 16.4 2 24.4-23.6 26.4-35.9 1.2-9.1.8-19.1-5.5-26.4z' stroke='%233E6D1F' fill='url(%23c)'/%3E%3C/svg%3E")}
1218
section.clipped.clippedTop {clip-path:url("#clipPolygonTop")}
1219
section.clipped.clippedBottom {clip-path:url("#clipPolygonBottom")}
1220
.myimg {background-image: url("images/under-left-leaf.png"), url("images/over-blue-bird.png"), url("images/under-top.png"), url("images/bg-top-grunge.png");}
1221
CSS;
1222
        $css_expected = <<<CSS
1223
header{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='90px' height='110px' viewBox='0 0 90 110'%3E%3Cstyle%3E.a%7Bstop-color:%23FFF;%7D.b%7Bstop-color:%23B2D235;%7D.c%7Bstop-color:%23BEE7FA;%7D.d%7Bfill:%23590C15;%7D%3C/style%3E%3ClinearGradient id='c' y2='135.4' gradientUnits='userSpaceOnUse' x2='209.1' gradientTransform='rotate(-1.467 -4082.888 7786.794)' y1='205.8' x1='262'%3E%3Cstop class='b' offset='0'/%3E%3Cstop class='b' offset='.48'/%3E%3Cstop stop-color='%23829D25' offset='1'/%3E%3C/linearGradient%3E%3Cpath stroke-width='.3' d='M77.3 45.4c-3-3.5-7.1-6.5-11.6-7.8-5.1-1.5-10-.1-14.9 1.5C52 35.4 54.3 29 60 24l-4.8-5.5c-3.4 3-5.8 6.3-7.5 9.4-1.7-4.3-4.1-8.4-7.5-12C33.4 8.6 24.3 4.7 15.1 4.2c-.2 9.3 3.1 18.6 9.9 25.9 5.2 5.6 11.8 9.2 18.7 10.8-2.5.2-4.9-.1-7.7-.9-5.2-1.4-10.5-2.8-15.8-1C10.6 42.3 4.5 51.9 4 61.7c-.5 11.6 3.8 23.8 9.9 33.5 3.9 6.3 9.6 13.7 17.7 13.4 3.8-.1 7-2.1 10.7-2.7 5.2-.8 9.1 1.2 14.1 1.8 16.4 2 24.4-23.6 26.4-35.9 1.2-9.1.8-19.1-5.5-26.4z' stroke='%233E6D1F' fill='url(%23c)'/%3E%3C/svg%3E")}
1224
section.clipped.clippedTop {clip-path:url("#clipPolygonTop")}
1225
section.clipped.clippedBottom {clip-path:url("#clipPolygonBottom")}
1226
.myimg {background-image: url($protorelativesiteurl/wp-content/themes/my-theme/images/under-left-leaf.png), url($protorelativesiteurl/wp-content/themes/my-theme/images/over-blue-bird.png), url($protorelativesiteurl/wp-content/themes/my-theme/images/under-top.png), url($protorelativesiteurl/wp-content/themes/my-theme/images/bg-top-grunge.png);}
1227
CSS;
1228
1229
        $fixurls_result = autoptimizeStyles::fixurls( ABSPATH . 'wp-content/themes/my-theme/style.css', $css_orig );
1230
        $this->assertEquals( $css_expected, $fixurls_result );
1231
    }
1232
1233
    public function test_background_datauri_sprites_with_fixurls()
1234
    {
1235
        $css_orig     = <<<CSS
1236
.shadow { background:url(img/1x1.png) top center; }
1237
.shadow1 { background-image:url(img/1x1.png) 0 -767px repeat-x; }
1238
.shadow2 {background:url(img/1x1.png) top center}
1239
1240
.test { background:url(img/1x1.png) top center; }
1241
.test1 { background-image:url('img/1x1.png') 0 -767px repeat-x; }
1242
.test2 {background:url("img/1x1.png") top center}
1243
1244
header{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='90px' height='110px' viewBox='0 0 90 110'%3E%3Cstyle%3E.a%7Bstop-color:%23FFF;%7D.b%7Bstop-color:%23B2D235;%7D.c%7Bstop-color:%23BEE7FA;%7D.d%7Bfill:%23590C15;%7D%3C/style%3E%3ClinearGradient id='c' y2='135.4' gradientUnits='userSpaceOnUse' x2='209.1' gradientTransform='rotate(-1.467 -4082.888 7786.794)' y1='205.8' x1='262'%3E%3Cstop class='b' offset='0'/%3E%3Cstop class='b' offset='.48'/%3E%3Cstop stop-color='%23829D25' offset='1'/%3E%3C/linearGradient%3E%3Cpath stroke-width='.3' d='M77.3 45.4c-3-3.5-7.1-6.5-11.6-7.8-5.1-1.5-10-.1-14.9 1.5C52 35.4 54.3 29 60 24l-4.8-5.5c-3.4 3-5.8 6.3-7.5 9.4-1.7-4.3-4.1-8.4-7.5-12C33.4 8.6 24.3 4.7 15.1 4.2c-.2 9.3 3.1 18.6 9.9 25.9 5.2 5.6 11.8 9.2 18.7 10.8-2.5.2-4.9-.1-7.7-.9-5.2-1.4-10.5-2.8-15.8-1C10.6 42.3 4.5 51.9 4 61.7c-.5 11.6 3.8 23.8 9.9 33.5 3.9 6.3 9.6 13.7 17.7 13.4 3.8-.1 7-2.1 10.7-2.7 5.2-.8 9.1 1.2 14.1 1.8 16.4 2 24.4-23.6 26.4-35.9 1.2-9.1.8-19.1-5.5-26.4z' stroke='%233E6D1F' fill='url(%23c)'/%3E%3C/svg%3E")}
1245
1246
/*
1247
section.clipped.clippedTop {clip-path:url("#clipPolygonTop")}
1248
section.clipped.clippedBottom {clip-path:url("#clipPolygonBottom")}
1249
.myimg {background-image: url("images/under-left-leaf.png"), url("images/over-blue-bird.png"), url("images/under-top.png"), url("images/bg-top-grunge.png");}
1250
.something {
1251
    background:url(http://example.org/wp-content/themes/my-theme/images/nothing.png);
1252
}
1253
.something-else {background:url(wp-content/themes/my-theme/images/shadow.png) -100px 0 repeat-y;}
1254
.another-thing { background:url(/wp-content/themes/my-theme/images/shadow.png) 0 -767px repeat-x; }
1255
#whatevz {background:url(wp-content/themes/my-theme/images/shadow.png) center top no-repeat;}
1256
1257
.widget ul li { background:url(img/shadow.png) top center; }
1258
*/
1259
CSS;
1260
        $css_expected = <<<CSS
1261
.shadow { background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=) top center; }
1262
.shadow1 { background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=) 0 -767px repeat-x; }
1263
.shadow2 {background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=) top center}
1264
1265
.test { background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=) top center; }
1266
.test1 { background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=) 0 -767px repeat-x; }
1267
.test2 {background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=) top center}
1268
1269
header{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='90px' height='110px' viewBox='0 0 90 110'%3E%3Cstyle%3E.a%7Bstop-color:%23FFF;%7D.b%7Bstop-color:%23B2D235;%7D.c%7Bstop-color:%23BEE7FA;%7D.d%7Bfill:%23590C15;%7D%3C/style%3E%3ClinearGradient id='c' y2='135.4' gradientUnits='userSpaceOnUse' x2='209.1' gradientTransform='rotate(-1.467 -4082.888 7786.794)' y1='205.8' x1='262'%3E%3Cstop class='b' offset='0'/%3E%3Cstop class='b' offset='.48'/%3E%3Cstop stop-color='%23829D25' offset='1'/%3E%3C/linearGradient%3E%3Cpath stroke-width='.3' d='M77.3 45.4c-3-3.5-7.1-6.5-11.6-7.8-5.1-1.5-10-.1-14.9 1.5C52 35.4 54.3 29 60 24l-4.8-5.5c-3.4 3-5.8 6.3-7.5 9.4-1.7-4.3-4.1-8.4-7.5-12C33.4 8.6 24.3 4.7 15.1 4.2c-.2 9.3 3.1 18.6 9.9 25.9 5.2 5.6 11.8 9.2 18.7 10.8-2.5.2-4.9-.1-7.7-.9-5.2-1.4-10.5-2.8-15.8-1C10.6 42.3 4.5 51.9 4 61.7c-.5 11.6 3.8 23.8 9.9 33.5 3.9 6.3 9.6 13.7 17.7 13.4 3.8-.1 7-2.1 10.7-2.7 5.2-.8 9.1 1.2 14.1 1.8 16.4 2 24.4-23.6 26.4-35.9 1.2-9.1.8-19.1-5.5-26.4z' stroke='%233E6D1F' fill='url(%23c)'/%3E%3C/svg%3E")}
1270
1271
/*
1272
section.clipped.clippedTop {clip-path:url("#clipPolygonTop")}
1273
section.clipped.clippedBottom {clip-path:url("#clipPolygonBottom")}
1274
.myimg {background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=), url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=), url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=), url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=);}
1275
.something {
1276
    background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=);
1277
}
1278
.something-else {background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=) -100px 0 repeat-y;}
1279
.another-thing { background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=) 0 -767px repeat-x; }
1280
#whatevz {background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=) center top no-repeat;}
1281
1282
.widget ul li { background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=) top center; }
1283
*/
1284
CSS;
1285
1286
        // For test purposes, ALL images in the css are being inline with a 1x1 trans png string/datauri.
1287
        add_filter( 'autoptimize_filter_css_is_datauri_candidate', function( $is_candidate, $path ) {
0 ignored issues
show
Unused Code introduced by
The parameter $is_candidate is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $path is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1288
            return true;
1289
        }, 10, 2 );
1290
1291
        // For test purposes, ALL images in the css are being inline with a 1x1 trans png string/datauri.
1292 View Code Duplication
        add_filter( 'autoptimize_filter_css_datauri_image', function( $base64array, $path ) {
0 ignored issues
show
Unused Code introduced by
The parameter $base64array is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $path is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1293
            $head = 'data:image/png;base64,';
1294
            $data = 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=';
1295
1296
            $result['full']       = $head . $data;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$result was never initialized. Although not strictly required by PHP, it is generally a good practice to add $result = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
1297
            $result['base64data'] = $data;
1298
            return $result;
1299
        }, 10, 2 );
1300
1301
        $instance = new autoptimizeStyles( $css_orig );
1302
        $instance->setOption( 'datauris', true );
1303
1304
        $fixurls_result = autoptimizeStyles::fixurls( ABSPATH . 'wp-content/themes/my-theme/style.css', $css_orig );
1305
        $css_actual     = $instance->rewrite_assets( $fixurls_result );
1306
1307
        $this->assertEquals( $css_expected, $css_actual );
1308
    }
1309
1310
    /**
1311
     * Doing rewrite_assets() without calling fixurls() beforehand could
1312
     * cause wrong results if/when there's a (same) image referenced via
1313
     * root-relative and relative urls, i.e.,
1314
     * `/wp-content/themes/my-theme/images/shadow.png` and
1315
     * `wp-content/themes/my-theme/images/shadow.png` in test code below.
1316
     * That's because urls are not really "normalized" in rewrite_assets() at
1317
     * all, and replacements are done using simple string keys (based on url),
1318
     * so whenever the shorter url ends up being spotted first, the replacement
1319
     * was done in a way that leaves the first `/` character in place.
1320
     * Which could mean trouble, especially when doing inlining of smaller
1321
     * images.
1322
     * After sorting the replacements array in rewrite_assets() by string
1323
     * length in descending order, the problem goes away.
1324
     */
1325
    public function test_background_datauri_sprites_without_fixurls()
1326
    {
1327
        $css_orig     = <<<CSS
1328
.shadow { background:url(img/1x1.png) top center; }
1329
.shadow1 { background-image:url(img/1x1.png) 0 -767px repeat-x; }
1330
.shadow2 {background:url(img/1x1.png) top center}
1331
1332
.test { background:url(img/1x1.png) top center; }
1333
.test1 { background-image:url('img/1x1.png') 0 -767px repeat-x; }
1334
.test2 {background:url("img/1x1.png") top center}
1335
1336
section.clipped.clippedTop {clip-path:url("#clipPolygonTop")}
1337
section.clipped.clippedBottom {clip-path:url("#clipPolygonBottom")}
1338
.myimg {background-image: url("images/under-left-leaf.png"), url("images/over-blue-bird.png"), url("images/under-top.png"), url("images/bg-top-grunge.png");}
1339
.something {
1340
    background:url(http://example.org/wp-content/themes/my-theme/images/nothing.png);
1341
}
1342
.something-else {background:url(wp-content/themes/my-theme/images/shadow.png) -100px 0 repeat-y;}
1343
.another-thing { background:url(/wp-content/themes/my-theme/images/shadow.png) 0 -767px repeat-x; }
1344
#whatevz {background:url(wp-content/themes/my-theme/images/shadow.png) center top no-repeat;}
1345
1346
.widget ul li { background:url(img/shadow.png) top center; }
1347
CSS;
1348
        $css_expected = <<<CSS
1349
.shadow { background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=) top center; }
1350
.shadow1 { background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=) 0 -767px repeat-x; }
1351
.shadow2 {background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=) top center}
1352
1353
.test { background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=) top center; }
1354
.test1 { background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=) 0 -767px repeat-x; }
1355
.test2 {background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=) top center}
1356
1357
section.clipped.clippedTop {clip-path:url("#clipPolygonTop")}
1358
section.clipped.clippedBottom {clip-path:url("#clipPolygonBottom")}
1359
.myimg {background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=), url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=), url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=), url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=);}
1360
.something {
1361
    background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=);
1362
}
1363
.something-else {background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=) -100px 0 repeat-y;}
1364
.another-thing { background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=) 0 -767px repeat-x; }
1365
#whatevz {background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=) center top no-repeat;}
1366
1367
.widget ul li { background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=) top center; }
1368
CSS;
1369
1370
        // For test purposes, ALL images in the css are being inlined with a 1x1 trans png string/datauri.
1371
        add_filter( 'autoptimize_filter_css_is_datauri_candidate', function( $is_candidate, $path ) {
0 ignored issues
show
Unused Code introduced by
The parameter $is_candidate is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $path is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1372
            return true;
1373
        }, 10, 2 );
1374
1375
        // For test purposes, ALL images in the css are being inlined with a 1x1 trans png string/datauri.
1376 View Code Duplication
        add_filter( 'autoptimize_filter_css_datauri_image', function( $base64array, $path ) {
0 ignored issues
show
Unused Code introduced by
The parameter $base64array is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $path is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1377
            $head = 'data:image/png;base64,';
1378
            $data = 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=';
1379
1380
            $result['full']       = $head . $data;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$result was never initialized. Although not strictly required by PHP, it is generally a good practice to add $result = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
1381
            $result['base64data'] = $data;
1382
            return $result;
1383
        }, 10, 2 );
1384
1385
        $instance = new autoptimizeStyles( $css_orig );
1386
        $instance->setOption( 'datauris', true );
1387
        $css_actual = $instance->rewrite_assets( $css_orig );
1388
        $this->assertEquals( $css_expected, $css_actual );
1389
    }
1390
1391
    /**
1392
     * Test css with fonts pointed to the CDN + cdn_url option is set.
1393
     */
1394
    public function test_css_fonts_on_cdn_with_filter()
1395
    {
1396
        $urls    = $this->get_urls();
1397
        $siteurl = $urls['siteurl'];
1398
        $cdnurl  = $urls['cdnurl'];
1399
        $sub     = $urls['subfolder'];
1400
1401
        $css_in = <<<CSS
1402
/* these should not be touched except for quotes removal */
1403
@font-face {
1404
  font-family: 'Roboto';
1405
  font-style: normal;
1406
  font-weight: 100;
1407
  src: url('../fonts/roboto-v15-latin-ext_latin-100.eot'); /* IE9 Compat Modes */
1408
  src: local('Roboto Thin'), local('Roboto-Thin'),
1409
       url('../fonts/roboto-v15-latin-ext_latin-100.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
1410
       url('../fonts/roboto-v15-latin-ext_latin-100.woff2') format('woff2'), /* Super Modern Browsers */
1411
       url('../fonts/roboto-v15-latin-ext_latin-100.woff') format('woff'), /* Modern Browsers */
1412
       url('../fonts/roboto-v15-latin-ext_latin-100.ttf') format('truetype'), /* Safari, Android, iOS */
1413
       url('../fonts/roboto-v15-latin-ext_latin-100.svg#Roboto') format('svg'); /* Legacy iOS */
1414
}
1415
@font-face {
1416
  font-family: 'Roboto';
1417
  font-style: normal;
1418
  font-weight: 100;
1419
  src: url('//fonts/roboto-v15-latin-ext_latin-100.eot'); /* IE9 Compat Modes */
1420
  src: local('Roboto Thin'), local('Roboto-Thin'),
1421
       url('//fonts/roboto-v15-latin-ext_latin-100.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
1422
       url('//fonts/roboto-v15-latin-ext_latin-100.woff2') format('woff2'), /* Super Modern Browsers */
1423
       url('//fonts/roboto-v15-latin-ext_latin-100.woff') format('woff'), /* Modern Browsers */
1424
       url('//fonts/roboto-v15-latin-ext_latin-100.ttf') format('truetype'), /* Safari, Android, iOS */
1425
       url('//fonts/roboto-v15-latin-ext_latin-100.svg#Roboto') format('svg'); /* Legacy iOS */
1426
}
1427
/* these will be replaced and quotes gone */
1428
@font-face {
1429
  font-family: 'Roboto';
1430
  font-style: normal;
1431
  font-weight: 100;
1432
  src: url('/fonts/roboto-v15-latin-ext_latin-100.eot'); /* IE9 Compat Modes */
1433
  src: local('Roboto Thin'), local('Roboto-Thin'),
1434
       url('/fonts/roboto-v15-latin-ext_latin-100.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
1435
       url('/fonts/roboto-v15-latin-ext_latin-100.woff2') format('woff2'), /* Super Modern Browsers */
1436
       url('/fonts/roboto-v15-latin-ext_latin-100.woff') format('woff'), /* Modern Browsers */
1437
       url('/fonts/roboto-v15-latin-ext_latin-100.ttf') format('truetype'), /* Safari, Android, iOS */
1438
       url('/fonts/roboto-v15-latin-ext_latin-100.svg#Roboto') format('svg'); /* Legacy iOS */
1439
}
1440
@font-face {
1441
  font-family: 'Roboto';
1442
  font-style: normal;
1443
  font-weight: 100;
1444
  src: url('$siteurl/wp-content/themes/mytheme/fonts/roboto-v15-latin-ext_latin-100.eot'); /* IE9 Compat Modes */
1445
  src: local('Roboto Thin'), local('Roboto-Thin'),
1446
       url('$siteurl/wp-content/themes/mytheme/fonts/roboto-v15-latin-ext_latin-100.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
1447
       url('$siteurl/wp-content/themes/mytheme/fonts/roboto-v15-latin-ext_latin-100.woff2') format('woff2'), /* Super Modern Browsers */
1448
       url('$siteurl/wp-content/themes/mytheme/fonts/roboto-v15-latin-ext_latin-100.woff') format('woff'), /* Modern Browsers */
1449
       url('$siteurl/wp-content/themes/mytheme/fonts/roboto-v15-latin-ext_latin-100.ttf') format('truetype'), /* Safari, Android, iOS */
1450
       url('$siteurl/wp-content/themes/mytheme/fonts/roboto-v15-latin-ext_latin-100.svg#Roboto') format('svg'); /* Legacy iOS */
1451
}
1452
CSS;
1453
1454
        $css_expected_fonts_cdn = <<<CSS
1455
/* these should not be touched except for quotes removal */
1456
@font-face {
1457
  font-family: 'Roboto';
1458
  font-style: normal;
1459
  font-weight: 100;
1460
  src: url(../fonts/roboto-v15-latin-ext_latin-100.eot); /* IE9 Compat Modes */
1461
  src: local('Roboto Thin'), local('Roboto-Thin'),
1462
       url(../fonts/roboto-v15-latin-ext_latin-100.eot?#iefix) format('embedded-opentype'), /* IE6-IE8 */
1463
       url(../fonts/roboto-v15-latin-ext_latin-100.woff2) format('woff2'), /* Super Modern Browsers */
1464
       url(../fonts/roboto-v15-latin-ext_latin-100.woff) format('woff'), /* Modern Browsers */
1465
       url(../fonts/roboto-v15-latin-ext_latin-100.ttf) format('truetype'), /* Safari, Android, iOS */
1466
       url(../fonts/roboto-v15-latin-ext_latin-100.svg#Roboto) format('svg'); /* Legacy iOS */
1467
}
1468
@font-face {
1469
  font-family: 'Roboto';
1470
  font-style: normal;
1471
  font-weight: 100;
1472
  src: url(//fonts/roboto-v15-latin-ext_latin-100.eot); /* IE9 Compat Modes */
1473
  src: local('Roboto Thin'), local('Roboto-Thin'),
1474
       url(//fonts/roboto-v15-latin-ext_latin-100.eot?#iefix) format('embedded-opentype'), /* IE6-IE8 */
1475
       url(//fonts/roboto-v15-latin-ext_latin-100.woff2) format('woff2'), /* Super Modern Browsers */
1476
       url(//fonts/roboto-v15-latin-ext_latin-100.woff) format('woff'), /* Modern Browsers */
1477
       url(//fonts/roboto-v15-latin-ext_latin-100.ttf) format('truetype'), /* Safari, Android, iOS */
1478
       url(//fonts/roboto-v15-latin-ext_latin-100.svg#Roboto) format('svg'); /* Legacy iOS */
1479
}
1480
/* these will be replaced and quotes gone */
1481
@font-face {
1482
  font-family: 'Roboto';
1483
  font-style: normal;
1484
  font-weight: 100;
1485
  src: url(${cdnurl}/${sub}fonts/roboto-v15-latin-ext_latin-100.eot); /* IE9 Compat Modes */
1486
  src: local('Roboto Thin'), local('Roboto-Thin'),
1487
       url(${cdnurl}/${sub}fonts/roboto-v15-latin-ext_latin-100.eot?#iefix) format('embedded-opentype'), /* IE6-IE8 */
1488
       url(${cdnurl}/${sub}fonts/roboto-v15-latin-ext_latin-100.woff2) format('woff2'), /* Super Modern Browsers */
1489
       url(${cdnurl}/${sub}fonts/roboto-v15-latin-ext_latin-100.woff) format('woff'), /* Modern Browsers */
1490
       url(${cdnurl}/${sub}fonts/roboto-v15-latin-ext_latin-100.ttf) format('truetype'), /* Safari, Android, iOS */
1491
       url(${cdnurl}/${sub}fonts/roboto-v15-latin-ext_latin-100.svg#Roboto) format('svg'); /* Legacy iOS */
1492
}
1493
@font-face {
1494
  font-family: 'Roboto';
1495
  font-style: normal;
1496
  font-weight: 100;
1497
  src: url(${cdnurl}/${sub}wp-content/themes/mytheme/fonts/roboto-v15-latin-ext_latin-100.eot); /* IE9 Compat Modes */
1498
  src: local('Roboto Thin'), local('Roboto-Thin'),
1499
       url(${cdnurl}/${sub}wp-content/themes/mytheme/fonts/roboto-v15-latin-ext_latin-100.eot?#iefix) format('embedded-opentype'), /* IE6-IE8 */
1500
       url(${cdnurl}/${sub}wp-content/themes/mytheme/fonts/roboto-v15-latin-ext_latin-100.woff2) format('woff2'), /* Super Modern Browsers */
1501
       url(${cdnurl}/${sub}wp-content/themes/mytheme/fonts/roboto-v15-latin-ext_latin-100.woff) format('woff'), /* Modern Browsers */
1502
       url(${cdnurl}/${sub}wp-content/themes/mytheme/fonts/roboto-v15-latin-ext_latin-100.ttf) format('truetype'), /* Safari, Android, iOS */
1503
       url(${cdnurl}/${sub}wp-content/themes/mytheme/fonts/roboto-v15-latin-ext_latin-100.svg#Roboto) format('svg'); /* Legacy iOS */
1504
}
1505
CSS;
1506
1507
        // Test with fonts pointed to the CDN + cdn option is set.
1508
        add_filter( 'autoptimize_filter_css_fonts_cdn', '__return_true' );
1509
        $instance = new autoptimizeStyles( $css_in );
1510
        $instance->setOption( 'cdn_url', $cdnurl );
1511
        $css_actual_fonts_cdn = $instance->rewrite_assets( $css_in );
1512
1513
        $this->assertEquals( $css_expected_fonts_cdn, $css_actual_fonts_cdn );
1514
    }
1515
1516
    /**
1517
     * Test css fonts not moved to cdn by default even if cdn_url option is set.
1518
     */
1519
    public function test_css_fonts_skipped_by_default_even_when_cdn_is_set()
1520
    {
1521
        $urls      = $this->get_urls();
1522
        $siteurl   = $urls['siteurl'];
1523
        $subfolder = $urls['subfolder'];
0 ignored issues
show
Unused Code introduced by
$subfolder is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1524
1525
        $css_in = <<<CSS
1526
/* these should not be changed, not even quotes */
1527
@font-face {
1528
  font-family: 'Roboto';
1529
  font-style: normal;
1530
  font-weight: 100;
1531
  src: url('../fonts/roboto-v15-latin-ext_latin-100.eot'); /* IE9 Compat Modes */
1532
  src: local('Roboto Thin'), local('Roboto-Thin'),
1533
       url('../fonts/roboto-v15-latin-ext_latin-100.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
1534
       url('../fonts/roboto-v15-latin-ext_latin-100.woff2') format('woff2'), /* Super Modern Browsers */
1535
       url('../fonts/roboto-v15-latin-ext_latin-100.woff') format('woff'), /* Modern Browsers */
1536
       url('../fonts/roboto-v15-latin-ext_latin-100.ttf') format('truetype'), /* Safari, Android, iOS */
1537
       url('../fonts/roboto-v15-latin-ext_latin-100.svg#Roboto') format('svg'); /* Legacy iOS */
1538
}
1539
@font-face {
1540
  font-family: 'Roboto';
1541
  font-style: normal;
1542
  font-weight: 100;
1543
  src: url('//fonts/roboto-v15-latin-ext_latin-100.eot'); /* IE9 Compat Modes */
1544
  src: local('Roboto Thin'), local('Roboto-Thin'),
1545
       url('//fonts/roboto-v15-latin-ext_latin-100.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
1546
       url('//fonts/roboto-v15-latin-ext_latin-100.woff2') format('woff2'), /* Super Modern Browsers */
1547
       url('//fonts/roboto-v15-latin-ext_latin-100.woff') format('woff'), /* Modern Browsers */
1548
       url('//fonts/roboto-v15-latin-ext_latin-100.ttf') format('truetype'), /* Safari, Android, iOS */
1549
       url('//fonts/roboto-v15-latin-ext_latin-100.svg#Roboto') format('svg'); /* Legacy iOS */
1550
}
1551
@font-face {
1552
  font-family: 'Roboto';
1553
  font-style: normal;
1554
  font-weight: 100;
1555
  src: url('/fonts/roboto-v15-latin-ext_latin-100.eot'); /* IE9 Compat Modes */
1556
  src: local('Roboto Thin'), local('Roboto-Thin'),
1557
       url('/fonts/roboto-v15-latin-ext_latin-100.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
1558
       url('/fonts/roboto-v15-latin-ext_latin-100.woff2') format('woff2'), /* Super Modern Browsers */
1559
       url('/fonts/roboto-v15-latin-ext_latin-100.woff') format('woff'), /* Modern Browsers */
1560
       url('/fonts/roboto-v15-latin-ext_latin-100.ttf') format('truetype'), /* Safari, Android, iOS */
1561
       url('/fonts/roboto-v15-latin-ext_latin-100.svg#Roboto') format('svg'); /* Legacy iOS */
1562
}
1563
@font-face {
1564
  font-family: 'Roboto';
1565
  font-style: normal;
1566
  font-weight: 100;
1567
  src: url('$siteurl/wp-content/themes/mytheme/fonts/roboto-v15-latin-ext_latin-100.eot'); /* IE9 Compat Modes */
1568
  src: local('Roboto Thin'), local('Roboto-Thin'),
1569
       url('$siteurl/wp-content/themes/mytheme/fonts/roboto-v15-latin-ext_latin-100.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
1570
       url('$siteurl/wp-content/themes/mytheme/fonts/roboto-v15-latin-ext_latin-100.woff2') format('woff2'), /* Super Modern Browsers */
1571
       url('$siteurl/wp-content/themes/mytheme/fonts/roboto-v15-latin-ext_latin-100.woff') format('woff'), /* Modern Browsers */
1572
       url('$siteurl/wp-content/themes/mytheme/fonts/roboto-v15-latin-ext_latin-100.ttf') format('truetype'), /* Safari, Android, iOS */
1573
       url('$siteurl/wp-content/themes/mytheme/fonts/roboto-v15-latin-ext_latin-100.svg#Roboto') format('svg'); /* Legacy iOS */
1574
}
1575
CSS;
1576
        // Expected without cdning fonts but cdn option is set.
1577
        $css_expected = <<<CSS
1578
/* these should not be changed, not even quotes */
1579
@font-face {
1580
  font-family: 'Roboto';
1581
  font-style: normal;
1582
  font-weight: 100;
1583
  src: url('../fonts/roboto-v15-latin-ext_latin-100.eot'); /* IE9 Compat Modes */
1584
  src: local('Roboto Thin'), local('Roboto-Thin'),
1585
       url('../fonts/roboto-v15-latin-ext_latin-100.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
1586
       url('../fonts/roboto-v15-latin-ext_latin-100.woff2') format('woff2'), /* Super Modern Browsers */
1587
       url('../fonts/roboto-v15-latin-ext_latin-100.woff') format('woff'), /* Modern Browsers */
1588
       url('../fonts/roboto-v15-latin-ext_latin-100.ttf') format('truetype'), /* Safari, Android, iOS */
1589
       url('../fonts/roboto-v15-latin-ext_latin-100.svg#Roboto') format('svg'); /* Legacy iOS */
1590
}
1591
@font-face {
1592
  font-family: 'Roboto';
1593
  font-style: normal;
1594
  font-weight: 100;
1595
  src: url('//fonts/roboto-v15-latin-ext_latin-100.eot'); /* IE9 Compat Modes */
1596
  src: local('Roboto Thin'), local('Roboto-Thin'),
1597
       url('//fonts/roboto-v15-latin-ext_latin-100.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
1598
       url('//fonts/roboto-v15-latin-ext_latin-100.woff2') format('woff2'), /* Super Modern Browsers */
1599
       url('//fonts/roboto-v15-latin-ext_latin-100.woff') format('woff'), /* Modern Browsers */
1600
       url('//fonts/roboto-v15-latin-ext_latin-100.ttf') format('truetype'), /* Safari, Android, iOS */
1601
       url('//fonts/roboto-v15-latin-ext_latin-100.svg#Roboto') format('svg'); /* Legacy iOS */
1602
}
1603
@font-face {
1604
  font-family: 'Roboto';
1605
  font-style: normal;
1606
  font-weight: 100;
1607
  src: url('/fonts/roboto-v15-latin-ext_latin-100.eot'); /* IE9 Compat Modes */
1608
  src: local('Roboto Thin'), local('Roboto-Thin'),
1609
       url('/fonts/roboto-v15-latin-ext_latin-100.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
1610
       url('/fonts/roboto-v15-latin-ext_latin-100.woff2') format('woff2'), /* Super Modern Browsers */
1611
       url('/fonts/roboto-v15-latin-ext_latin-100.woff') format('woff'), /* Modern Browsers */
1612
       url('/fonts/roboto-v15-latin-ext_latin-100.ttf') format('truetype'), /* Safari, Android, iOS */
1613
       url('/fonts/roboto-v15-latin-ext_latin-100.svg#Roboto') format('svg'); /* Legacy iOS */
1614
}
1615
@font-face {
1616
  font-family: 'Roboto';
1617
  font-style: normal;
1618
  font-weight: 100;
1619
  src: url('$siteurl/wp-content/themes/mytheme/fonts/roboto-v15-latin-ext_latin-100.eot'); /* IE9 Compat Modes */
1620
  src: local('Roboto Thin'), local('Roboto-Thin'),
1621
       url('$siteurl/wp-content/themes/mytheme/fonts/roboto-v15-latin-ext_latin-100.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
1622
       url('$siteurl/wp-content/themes/mytheme/fonts/roboto-v15-latin-ext_latin-100.woff2') format('woff2'), /* Super Modern Browsers */
1623
       url('$siteurl/wp-content/themes/mytheme/fonts/roboto-v15-latin-ext_latin-100.woff') format('woff'), /* Modern Browsers */
1624
       url('$siteurl/wp-content/themes/mytheme/fonts/roboto-v15-latin-ext_latin-100.ttf') format('truetype'), /* Safari, Android, iOS */
1625
       url('$siteurl/wp-content/themes/mytheme/fonts/roboto-v15-latin-ext_latin-100.svg#Roboto') format('svg'); /* Legacy iOS */
1626
}
1627
CSS;
1628
        // Test without moving fonts to CDN, but cdn option is set.
1629
        $instance = new autoptimizeStyles( $css_in );
1630
        $instance->setOption( 'cdn_url', $urls['cdnurl'] );
1631
        $css_actual = $instance->rewrite_assets( $css_in );
1632
        $this->assertEquals( $css_expected, $css_actual );
1633
    }
1634
1635
    public function test_assets_regex_replaces_multi_bg_images()
1636
    {
1637
        $urls   = $this->get_urls();
1638
        $sub    = $urls['subfolder'];
1639
        $cdnurl = $urls['cdnurl'];
1640
1641
        $in = <<<CSS
1642
body:after {
1643
  content: url(/img/close.png) url(/img/loading.gif) url(/img/prev.png) url(/img/next.png);
1644
}
1645
CSS;
1646
1647
        $expected = <<<CSS
1648
body:after {
1649
  content: url($cdnurl/${sub}img/close.png) url($cdnurl/${sub}img/loading.gif) url($cdnurl/${sub}img/prev.png) url($cdnurl/${sub}img/next.png);
1650
}
1651
CSS;
1652
1653
        $instance = new autoptimizeStyles( $in );
1654
        $instance->setOption( 'cdn_url', $cdnurl );
1655
        $actual = $instance->rewrite_assets( $in );
1656
1657
        $this->assertEquals( $expected, $actual );
1658
    }
1659
1660
    public function test_at_supports_spacing_issue_110()
1661
    {
1662
        $in       = <<<CSS
1663
@supports (-webkit-filter: blur(3px)) or (filter: blur(3px)) {
1664
    .blur {
1665
        filter:blur(3px);
1666
    }
1667
}
1668
@supports((position:-webkit-sticky) or (position:sticky)) {
1669
    .sticky { position:sticky; }
1670
}
1671
CSS;
1672
        $expected = <<<CSS
1673
@supports (-webkit-filter:blur(3px)) or (filter:blur(3px)){.blur{filter:blur(3px)}}@supports((position:-webkit-sticky) or (position:sticky)){.sticky{position:sticky}}
1674
CSS;
1675
1676
        $instance = new autoptimizeStyles( $in );
1677
        $actual   = $instance->run_minifier_on( $in );
1678
1679
        $this->assertEquals( $expected, $actual );
1680
    }
1681
1682 View Code Duplication
    public function test_css_import_semicolon_url_issue_122()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1683
    {
1684
        $urls   = $this->get_urls();
1685
        $sub    = $urls['subfolder'];
1686
        $cdnurl = $urls['cdnurl'];
1687
1688
        $in = <<<HTML
1689
<style type="text/css">
1690
@import url("foo.css?a&#038;b");
1691
@import url("bar.css");
1692
</style>
1693
HTML;
1694
1695
        $expected = '<style type="text/css" media="all">@import url(' . $cdnurl . '/' . $sub . 'foo.css?a&#038;b);@import url(' . $cdnurl . '/' . $sub . 'bar.css);</style><!--noptimize--><!-- Autoptimize found a problem with the HTML in your Theme, tag `title` missing --><!--/noptimize-->';
1696
1697
        $options = [
1698
            'autoptimizeStyles' => $this->getAoStylesDefaultOptions(),
1699
        ];
1700
1701
        $instance = new autoptimizeStyles( $in );
1702
        $instance->read( $options['autoptimizeStyles'] );
1703
        $instance->minify();
1704
        $instance->cache();
1705
        $actual = $instance->getcontent();
1706
        $this->assertEquals( $expected, $actual );
1707
    }
1708
1709
    public function test_fixurls_with_at_imports_and_media_queries()
1710
    {
1711
        $urls      = $this->get_urls();
1712
        $prsiteurl = $urls['prsiteurl'];
1713
        $subfolder = $urls['subfolder'];
0 ignored issues
show
Unused Code introduced by
$subfolder is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1714
1715
        $in  = '@import "foo.css"; @import "bar.css" (orientation:landscape);';
1716
        $exp = '@import url(' . $prsiteurl . '/wp-content/themes/my-theme/foo.css); @import url(' . $prsiteurl . '/wp-content/themes/my-theme/bar.css) (orientation:landscape);';
1717
1718
        $actual = autoptimizeStyles::fixurls( ABSPATH . 'wp-content/themes/my-theme/style.css', $in );
1719
        $this->assertEquals( $exp, $actual );
1720
    }
1721
1722 View Code Duplication
    public function test_aostyles_at_imports_with_media_queries()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1723
    {
1724
        $urls   = $this->get_urls();
1725
        $sub    = $urls['subfolder'];
1726
        $cdnurl = $urls['cdnurl'];
1727
1728
        $in = <<<HTML
1729
<style type="text/css">
1730
@import "foo.css"; @import "bar.css" (orientation:landscape);
1731
</style>
1732
HTML;
1733
1734
        $expected = '<style type="text/css" media="all">@import url(' . $cdnurl . '/' . $sub . 'foo.css);@import url(' . $cdnurl . '/' . $sub . 'bar.css) (orientation:landscape);</style><!--noptimize--><!-- Autoptimize found a problem with the HTML in your Theme, tag `title` missing --><!--/noptimize-->';
1735
1736
        $options = [
1737
            'autoptimizeStyles' => $this->getAoStylesDefaultOptions(),
1738
        ];
1739
1740
        $instance = new autoptimizeStyles( $in );
1741
        $instance->read( $options['autoptimizeStyles'] );
1742
        $instance->minify();
1743
        $instance->cache();
1744
1745
        $actual = $instance->getcontent();
1746
        $this->assertEquals( $expected, $actual );
1747
    }
1748
1749
    public function test_cache_size_checker_hooked_by_default()
1750
    {
1751
        $this->assertNotEmpty( autoptimizeCacheChecker::SCHEDULE_HOOK );
1752
1753
        // No schedule, because it's only added when is_admin() is true.
1754
        $this->assertEquals( false, wp_get_schedule( autoptimizeCacheChecker::SCHEDULE_HOOK ) );
1755
1756
        // Proving that setup() sets the schedule as needed.
1757
        $checker = new autoptimizeCacheChecker();
1758
        $checker->setup();
1759
        $this->assertEquals( 'twicedaily', wp_get_schedule( autoptimizeCacheChecker::SCHEDULE_HOOK ) );
1760
    }
1761
1762
    public function test_cache_size_checker_disabled_with_filter()
1763
    {
1764
        add_filter( 'autoptimize_filter_cachecheck_do', '__return_false' );
1765
1766
        $checker = new autoptimizeCacheChecker();
1767
        $checker->setup();
1768
        $this->assertEquals( false, wp_get_schedule( autoptimizeCacheChecker::SCHEDULE_HOOK ) );
1769
1770
        remove_all_filters( 'autoptimize_filter_cachecheck_do' );
1771
    }
1772
1773
    public function test_is_start_buffering_hooked_properly()
1774
    {
1775
        $instance = autoptimize();
1776
1777
        /**
1778
         * TODO/FIXME: ideally, we'd test all possible setups, but once we set
1779
         * a constant, there's no going back, unless we use runkit or somesuch:
1780
         * https://www.theaveragedev.com/mocking-constants-in-tests/.
1781
         */
1782
1783
        if ( defined( 'AUTOPTIMIZE_INIT_EARLIER' ) ) {
1784
            $this->assertEquals(
1785
                autoptimizeMain::INIT_EARLIER_PRIORITY,
1786
                has_action( 'init', array( $instance, 'start_buffering' ) )
1787
            );
1788
            $this->assertTrue( ! defined( 'AUTOPTIMIZE_HOOK_INTO' ) );
1789
        }
1790
1791
        /*
1792
        // AUTOPTIMIZE_HOOK_INTO only exists if AUTOPTIMIZE_INIT_EARLIER doesnt
1793
        $this->assertEquals(
1794
            autoptimizeMain::DEFAULT_HOOK_PRIORITY,
1795
            has_action( constant( 'AUTOPTIMIZE_HOOK_INTO' ), array( $instance, 'start_buffering' ) )
1796
        );
1797
        $this->assertFalse(
1798
            has_action( 'init', array( $instance, 'start_buffering' ) )
1799
        );
1800
        */
1801
    }
1802
1803
    public function test_inline_and_defer_markup()
1804
    {
1805
        add_filter( 'autoptimize_filter_css_defer', '__return_true' );
1806
        add_filter( 'autoptimize_filter_css_defer_inline', '__return_true' );
1807
1808
        $actual = $this->ao->end_buffering( $this->get_test_markup() );
1809
        if ( is_multisite() ) {
1810
            $this->assertEquals( $this->get_test_markup_output_inline_defer_ms(), $actual );
1811
        } else {
1812
            $this->assertEquals( $this->get_test_markup_output_inline_defer(), $actual );
1813
        }
1814
1815
        remove_all_filters( 'autoptimize_filter_css_defer' );
1816
        remove_all_filters( 'autoptimize_filter_css_defer_inline' );
1817
    }
1818
1819 View Code Duplication
    public function test_js_aggregation_decision_and_dontaggregate_filter()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1820
    {
1821
        $opts = $this->getAoScriptsDefaultOptions();
1822
1823
        // Aggregating: true by default.
1824
        $scripts = new autoptimizeScripts( '' );
1825
        $scripts->read( $opts );
1826
        $this->assertTrue( $scripts->aggregating() );
1827
1828
        // Aggregating: option=true (dontaggregate=false by default).
1829
        $opts['aggregate'] = true;
1830
        $scripts           = new autoptimizeScripts( '' );
1831
        $scripts->read( $opts );
1832
        $this->assertTrue( $scripts->aggregating() );
1833
1834
        // Aggregating: option=true, dontaggregate=false explicit.
1835
        $opts['aggregate'] = true;
1836
        add_filter( 'autoptimize_filter_js_dontaggregate', '__return_false' );
1837
        $scripts = new autoptimizeScripts( '' );
1838
        $scripts->read( $opts );
1839
        $this->assertTrue( $scripts->aggregating() );
1840
        remove_all_filters( 'autoptimize_filter_js_dontaggregate' );
1841
1842
        // Not aggregating: option=true, dontaggregate=true.
1843
        $opts['aggregate'] = true;
1844
        add_filter( 'autoptimize_filter_js_dontaggregate', '__return_true' );
1845
        $scripts = new autoptimizeScripts( '' );
1846
        $scripts->read( $opts );
1847
        $this->assertFalse( $scripts->aggregating() );
1848
        remove_all_filters( 'autoptimize_filter_js_dontaggregate' );
1849
1850
        // Not aggregating: option=false, dontaggregate=false.
1851
        $opts['aggregate'] = false;
1852
        add_filter( 'autoptimize_filter_js_dontaggregate', '__return_false' );
1853
        $scripts = new autoptimizeScripts( '' );
1854
        $scripts->read( $opts );
1855
        $this->assertFalse( $scripts->aggregating() );
1856
        remove_all_filters( 'autoptimize_filter_js_dontaggregate' );
1857
1858
        // Not aggregating: option=false, dontaggregate=true.
1859
        $opts['aggregate'] = false;
1860
        add_filter( 'autoptimize_filter_js_dontaggregate', '__return_true' );
1861
        $scripts = new autoptimizeScripts( '' );
1862
        $scripts->read( $opts );
1863
        $this->assertFalse( $scripts->aggregating() );
1864
        remove_all_filters( 'autoptimize_filter_js_dontaggregate' );
1865
    }
1866
1867 View Code Duplication
    public function test_css_aggregation_decision_and_dontaggregate_filter()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1868
    {
1869
        $opts = $this->getAoStylesDefaultOptions();
1870
1871
        // Aggregating: true by default.
1872
        $styles = new autoptimizeStyles( '' );
1873
        $this->assertTrue( $styles->aggregating() );
1874
1875
        // Aggregating: option=true (dontaggregate=false by default).
1876
        $opts['aggregate'] = true;
1877
        $styles            = new autoptimizeStyles( '' );
1878
        $styles->read( $opts );
1879
        $this->assertTrue( $styles->aggregating() );
1880
1881
        // Aggregating: option=true, dontaggregate=false explicit.
1882
        $opts['aggregate'] = true;
1883
        add_filter( 'autoptimize_filter_css_dontaggregate', '__return_false' );
1884
        $styles = new autoptimizeStyles( '' );
1885
        $styles->read( $opts );
1886
        $this->assertTrue( $styles->aggregating() );
1887
        remove_all_filters( 'autoptimize_filter_css_dontaggregate' );
1888
1889
        // Not aggregating: option=true, dontaggregate=true.
1890
        $opts['aggregate'] = true;
1891
        add_filter( 'autoptimize_filter_css_dontaggregate', '__return_true' );
1892
        $styles = new autoptimizeStyles( '' );
1893
        $styles->read( $opts );
1894
        $this->assertFalse( $styles->aggregating() );
1895
        remove_all_filters( 'autoptimize_filter_css_dontaggregate' );
1896
1897
        // Not aggregating: option=false, dontaggregate=false.
1898
        $opts['aggregate'] = false;
1899
        add_filter( 'autoptimize_filter_css_dontaggregate', '__return_false' );
1900
        $styles = new autoptimizeStyles( '' );
1901
        $styles->read( $opts );
1902
        $this->assertFalse( $styles->aggregating() );
1903
        remove_all_filters( 'autoptimize_filter_css_dontaggregate' );
1904
1905
        // Not aggregating: option=false, dontaggregate=true.
1906
        $opts['aggregate'] = false;
1907
        add_filter( 'autoptimize_filter_css_dontaggregate', '__return_true' );
1908
        $styles = new autoptimizeStyles( '' );
1909
        $styles->read( $opts );
1910
        $this->assertFalse( $styles->aggregating() );
1911
        remove_all_filters( 'autoptimize_filter_css_dontaggregate' );
1912
    }
1913
1914
    public function test_css_minify_single_with_cdning()
1915
    {
1916
        $pathname = dirname( __FILE__ ) . '/fixtures/minify-single.css';
1917
        $opts     = $this->getAoStylesDefaultOptions();
1918
        $styles   = new autoptimizeStyles( '' );
1919
        $styles->read( $opts );
1920
1921
        $url = $styles->minify_single( $pathname, $cache_miss = true );
1922
1923
        // Minified url filename + its pointed to cdn.
1924
        $this->assertContains( AUTOPTIMIZE_CACHE_CHILD_DIR, $url );
1925
        $this->assertContains( '/autoptimize_single_', $url );
1926
        $this->assertContains( $styles->cdn_url, $url );
1927
1928
        // Actual minified css contents are minified and cdn-ed.
1929
        $path     = $styles->getpath( $url );
0 ignored issues
show
Security Bug introduced by
It seems like $url defined by $styles->minify_single($...me, $cache_miss = true) on line 1921 can also be of type false; however, autoptimizeBase::getpath() does only seem to accept string, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
1930
        $contents = file_get_contents( $path );
1931
        $this->assertContains( $styles->cdn_url, $contents );
1932
        $this->assertContains( '.bg{background:url(' . $styles->cdn_url, $contents );
1933
    }
1934
1935
    public function test_ao_partners_instantiation_without_explicit_include()
1936
    {
1937
        $partners = new autoptimizePartners();
1938
        $this->assertTrue( $partners instanceof autoptimizePartners );
1939
    }
1940
1941 View Code Duplication
    public function test_html_minify_keep_html_comments_inside_script_blocks()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1942
    {
1943
        $markup   = <<<MARKUP
1944
<script>
1945
<!-- End Support AJAX add to cart -->
1946
var a = "b";
1947
</script>
1948
MARKUP;
1949
        $expected = <<<MARKUP
1950
<script><!-- End Support AJAX add to cart -->
1951
var a = "b";</script>
1952
MARKUP;
1953
1954
        $markup2 = <<<MARKUP
1955
<script>
1956
var a = "b";
1957
<!-- End Support AJAX add to cart -->
1958
</script>
1959
MARKUP;
1960
1961
        $expected2 = <<<MARKUP
1962
<script>var a = "b";
1963
<!-- End Support AJAX add to cart --></script>
1964
MARKUP;
1965
1966
        // When keepcomments is true.
1967
        $options = [
1968
            'autoptimizeHTML' => [
1969
                'keepcomments' => true,
1970
            ],
1971
        ];
1972
1973
        $instance = new autoptimizeHTML( $markup );
1974
        $instance->read( $options['autoptimizeHTML'] );
1975
        $instance->minify();
1976
        $actual = $instance->getcontent();
1977
        $this->assertEquals( $expected, $actual );
1978
1979
        $instance = new autoptimizeHTML( $markup2 );
1980
        $instance->read( $options['autoptimizeHTML'] );
1981
        $instance->minify();
1982
        $actual2 = $instance->getcontent();
1983
        $this->assertEquals( $expected2, $actual2 );
1984
    }
1985
1986 View Code Duplication
    public function test_html_minify_remove_html_comments_inside_script_blocks()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1987
    {
1988
        // Default case, html comments removed (keepcomments = false).
1989
        $markup1   = <<<MARKUP
1990
<script>
1991
var a = "b";
1992
<!-- End Support AJAX add to cart -->
1993
</script>
1994
MARKUP;
1995
        $expected1 = <<<MARKUP
1996
<script>var a = "b";
1997
<!-- End Support AJAX add to cart</script>
1998
MARKUP;
1999
2000
        $markup2   = <<<MARKUP
2001
<script>
2002
<!-- End Support AJAX add to cart -->
2003
var a = "b";
2004
</script>
2005
MARKUP;
2006
        $expected2 = <<<MARKUP
2007
<script>End Support AJAX add to cart -->
2008
var a = "b";</script>
2009
MARKUP;
2010
2011
        $options = [
2012
            'autoptimizeHTML' => [
2013
                'keepcomments' => false,
2014
            ],
2015
        ];
2016
2017
        $instance = new autoptimizeHTML( $markup1 );
2018
        $instance->read( $options['autoptimizeHTML'] );
2019
        $instance->minify();
2020
        $actual = $instance->getcontent();
2021
        $this->assertEquals( $expected1, $actual );
2022
2023
        $instance = new autoptimizeHTML( $markup2 );
2024
        $instance->read( $options['autoptimizeHTML'] );
2025
        $instance->minify();
2026
        $actual2 = $instance->getcontent();
2027
        $this->assertEquals( $expected2, $actual2 );
2028
    }
2029
2030 View Code Duplication
    public function test_html_minify_html_comments_inside_script_blocks_old_school_pattern()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2031
    {
2032
        $markup = <<<MARKUP
2033
<script>
2034
<!-- // invisible for old browsers
2035
var a = "z";
2036
// -->
2037
</script>
2038
MARKUP;
2039
2040
        $expected = <<<MARKUP
2041
<script>// invisible for old browsers
2042
var a = "z";</script>
2043
MARKUP;
2044
2045
        $options = [
2046
            'autoptimizeHTML' => [
2047
                'keepcomments' => false,
2048
            ],
2049
        ];
2050
2051
        $instance = new autoptimizeHTML( $markup );
2052
        $instance->read( $options['autoptimizeHTML'] );
2053
        $instance->minify();
2054
        $actual = $instance->getcontent();
2055
        $this->assertEquals( $expected, $actual );
2056
    }
2057
2058 View Code Duplication
    public function test_html_minify_html_comments_inside_script_blocks_old_school_pattern_untouched()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2059
    {
2060
        $markup = <<<MARKUP
2061
<script>
2062
<!-- // invisible for old browsers
2063
var a = "z";
2064
// -->
2065
</script>
2066
MARKUP;
2067
2068
        $expected = <<<MARKUP
2069
<script><!-- // invisible for old browsers
2070
var a = "z";
2071
// --></script>
2072
MARKUP;
2073
2074
        $options = [
2075
            'autoptimizeHTML' => [
2076
                'keepcomments' => true,
2077
            ],
2078
        ];
2079
2080
        $instance = new autoptimizeHTML( $markup );
2081
        $instance->read( $options['autoptimizeHTML'] );
2082
        $instance->minify();
2083
        $actual = $instance->getcontent();
2084
        $this->assertEquals( $expected, $actual );
2085
    }
2086
2087
    public function test_utils_mbstring_availabilty_overriding()
2088
    {
2089
        $orig     = autoptimizeUtils::mbstring_available();
2090
        $opposite = ! $orig;
2091
2092
        $this->assertSame( $orig, autoptimizeUtils::mbstring_available() );
2093
        // Override works...
2094
        $this->assertSame( $opposite, autoptimizeUtils::mbstring_available( $opposite ) );
2095
        // And override remains cached as the last version.
2096
        $this->assertSame( $opposite, autoptimizeUtils::mbstring_available() );
2097
    }
2098
2099
    public function test_utils_mbstring_basics()
2100
    {
2101
        // Turn on mbstring usage.
2102
        autoptimizeUtils::mbstring_available( true );
2103
2104
        $this->assertSame( 2, autoptimizeUtils::strlen( "\x00\xFF", 'ASCII' ) );
2105
        $this->assertSame( 2, autoptimizeUtils::strlen( "\x00\xFF", 'CP850' ) );
2106
        $this->assertSame( 3, autoptimizeUtils::strlen( '한국어' ) );
2107
2108
        $this->assertFalse( @autoptimizeUtils::strpos( 'abc', '' ) );
2109
        $this->assertFalse( @autoptimizeUtils::strpos( 'abc', 'a', -1 ) );
2110
        $this->assertFalse( autoptimizeUtils::strpos( 'abc', 'd' ) );
2111
        $this->assertFalse( autoptimizeUtils::strpos( 'abc', 'a', 3 ) );
2112
        $this->assertSame( 1, autoptimizeUtils::strpos( '한국어', '국' ) );
2113
    }
2114
2115
    /**
2116
     * @dataProvider provider_utils_substr_replace
2117
     */
2118
    function test_utils_substr_replace_basics_mbstring( $s, $repl, $start, $len, $expected )
2119
    {
2120
        // Force mbstring code path...
2121
        autoptimizeUtils::mbstring_available( true );
2122
        $this->assertEquals( $expected, autoptimizeUtils::substr_replace( $s, $repl, $start, $len ) );
2123
    }
2124
2125
    public function provider_utils_substr_replace()
2126
    {
2127
        $str  = 'try this';
2128
        $repl = 'bala ';
2129
2130
        return [
2131
            [
2132
                $str,
2133
                $repl,
2134
                2,
2135
                null,
2136
                'trbala ',
2137
            ],
2138
            [
2139
                $str,
2140
                $repl,
2141
                2,
2142
                3,
2143
                'trbala his',
2144
            ],
2145
            [
2146
                $str,
2147
                $repl,
2148
                2,
2149
                0,
2150
                'trbala y this',
2151
            ],
2152
            [
2153
                $str,
2154
                $repl,
2155
                2,
2156
                -2,
2157
                'trbala is',
2158
            ],
2159
        ];
2160
    }
2161
2162 View Code Duplication
    function test_mb_substr_replace_with_ascii_input_string()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2163
    {
2164
        autoptimizeUtils::mbstring_available( false );
2165
2166
        $str = 'Ascii';
2167
2168
        $this->assertSame( 'Añ', autoptimizeUtils::substr_replace( $str, 'ñ', 1 ) );
2169
        $this->assertSame( 'ñcii', autoptimizeUtils::substr_replace( $str, 'ñ', 0, 2 ) );
2170
        $this->assertSame( 'Asñx', autoptimizeUtils::substr_replace( $str, 'ñx', 2, 3 ) );
2171
        $this->assertSame( 'Asz', autoptimizeUtils::substr_replace( $str, 'z', 2, 10 ) );
2172
        $this->assertSame( 'Añii', autoptimizeUtils::substr_replace( $str, 'ñ', 1, 2 ) );
2173
    }
2174
2175 View Code Duplication
    function test_mb_substr_replace_with_utf8_input_string()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2176
    {
2177
        autoptimizeUtils::mbstring_available( true );
2178
2179
        $str = 'âønæë';
2180
2181
        $this->assertSame( 'âñ', autoptimizeUtils::substr_replace( $str, 'ñ', 1 ) ); // No length.
2182
        $this->assertSame( 'ñnæë', autoptimizeUtils::substr_replace( $str, 'ñ', 0, 2 ) );
2183
        $this->assertSame( 'âøñx', autoptimizeUtils::substr_replace( $str, 'ñx', 2, 3 ) );
2184
        $this->assertSame( 'âøz', autoptimizeUtils::substr_replace( $str, 'z', 2, 10 ) ); // Length larger than possible...
2185
        $this->assertSame( 'âñæë', autoptimizeUtils::substr_replace( $str, 'ñ', 1, 2 ) );
2186
    }
2187
2188 View Code Duplication
    function test_default_substr_replace_with_ascii_input_string()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2189
    {
2190
        // Disable mbstring which should fall ack to substr_replace...
2191
        autoptimizeUtils::mbstring_available( false );
2192
2193
        $str = 'Ascii';
2194
2195
        $this->assertSame( 'Añ', autoptimizeUtils::substr_replace( $str, 'ñ', 1 ) );
2196
        $this->assertSame( 'ñcii', autoptimizeUtils::substr_replace( $str, 'ñ', 0, 2 ) );
2197
        $this->assertSame( 'Asñx', autoptimizeUtils::substr_replace( $str, 'ñx', 2, 3 ) );
2198
        $this->assertSame( 'Asz', autoptimizeUtils::substr_replace( $str, 'z', 2, 10 ) );
2199
        $this->assertSame( 'Añii', autoptimizeUtils::substr_replace( $str, 'ñ', 1, 2 ) );
2200
    }
2201
2202
    function test_default_substr_replace_with_utf8_input_string()
2203
    {
2204
        // Disabling mbstring, falling back to substr_replace...
2205
        autoptimizeUtils::mbstring_available( false );
2206
2207
        // This is really impossible to make work properly, since
2208
        // any start/len parameters we give are working with bytes instead
2209
        // of characters, shit just breaks.
2210
        $str = 'âønæë';
2211
2212
        // $this->assertSame( '�ñ', autoptimizeUtils::substr_replace( $str, 'ñ', 1 ) ); // No length.
2213
        // $this->assertSame( 'ñ�næë', autoptimizeUtils::substr_replace( $str, 'ñ', 1, 2 ) );
2214
        $this->assertSame( 'ñønæë', autoptimizeUtils::substr_replace( $str, 'ñ', 0, 2 ) );
2215
        $this->assertSame( 'âñxæë', autoptimizeUtils::substr_replace( $str, 'ñx', 2, 3 ) );
2216
        $this->assertSame( 'âz', autoptimizeUtils::substr_replace( $str, 'z', 2, 10 ) ); // Length larger than possible...
2217
    }
2218
2219
    public function test_cache_fast_delete()
2220
    {
2221
        add_filter( 'autoptimize_filter_cache_clear_advanced', '__return_true' );
2222
2223
        autoptimizeCache::clearall_actionless();
2224
2225
        remove_all_filters( 'autoptimize_filter_cache_clear_advanced' );
2226
    }
2227
2228
    public function test_delete_advanced_cache_clear_artifacts()
2229
    {
2230
        $this->assertTrue( autoptimizeCache::delete_advanced_cache_clear_artifacts() );
2231
    }
2232
2233
    public function provider_canonicalization()
2234
    {
2235
        return array(
2236
            array( '../common', 'common' ),
2237
            array( '../what-does-this-mean/really?/', 'what-does-this-mean/really?/' ),
2238
            array( '../../what/where/how', 'what/where/how' ),
2239
            array( '/../more.dots.please/', '/more.dots.please/' ),
2240
            array( '/../../what/where/how', '/what/where/how' ),
2241
            array( '/a/b/c/../../../d/e/file.txt', '/d/e/file.txt' ),
2242
            array( 'a/b/../c', 'a/c' ),
2243
            array( './../../etc/passwd', './etc/passwd' ),
2244
            array( '/var/.////./user/./././..//.//../////../././.././test/////', '/test/' ),
2245
            array( '/var/user/./././.././../.././././test/', '/test/' ),
2246
            array( '/hello/0//how/../are/../you', '/hello/0/you' ),
2247
            array( '', '' ),
2248
            array( '.', '.' ),
2249
            array( '..', '..' ),
2250
            array( './..', './..' ),
2251
            array( '../.', '.' ),
2252
            // This might be debatable...
2253
            array( '../..', '..' ),
2254
        );
2255
    }
2256
2257
    /**
2258
     * @dataProvider provider_canonicalization
2259
     */
2260
    public function test_path_canonicalize( $path, $canonicalized )
2261
    {
2262
        $this->assertSame( $canonicalized, autoptimizeUtils::path_canonicalize( $path ) );
2263
    }
2264
2265
    /**
2266
     * For a site in subfolder, CDN-rewrite used to magically include
2267
     * the subfolder when rewriting assets to CDN.
2268
     * That behavior can be turned off by returning false via
2269
     * `autoptimize_filter_cdn_magic_path_check`.
2270
     * If it's false, cdn-rewriting should not include subfolder even
2271
     * when the site is actually in a subfolder/subdirectory.
2272
     */
2273
    public function test_autoptimize_filter_cdn_magic_path_check()
2274
    {
2275
        $cdnurl = 'http://cdn.example.org';
2276
        add_filter( 'autoptimize_filter_cdn_magic_path_check', '__return_false', 10, 2 );
2277
2278
        // Even when site is in a subfolder, the resulting cdn-rewritten url
2279
        // should not magically include it, due to the above filter.
2280
        // The second parameter is here to force a cache miss and re-run
2281
        // the filter since we're using the same cdn url all over the place,
2282
        // but want to prove different things with it.
2283
        $this->assertSame( $cdnurl, autoptimizeUtils::tweak_cdn_url_if_needed( $cdnurl, true ) );
2284
2285
        remove_all_filters( 'autoptimize_filter_cdn_magic_path_check' );
2286
    }
2287
2288
    /**
2289
     * Test image optimization in autoptimizeImages.php.
2290
     *
2291
     * Default case: img with srcsets
2292
     */
2293
    public function test_imgopt()
2294
    {
2295
        $urls                                        = $this->get_urls();
2296
        $siteurl                                     = $urls['siteurl'];
2297
        $imgopthost                                  = $urls['imgopthost'];
2298
        $opts                                        = autoptimizeImages::fetch_options();
2299
        $opts['autoptimize_imgopt_checkbox_field_1'] = '1';
2300
        $opts['autoptimize_imgopt_checkbox_field_3'] = '0';
2301
2302
        $markup = <<<MARKUP
2303
<img src='$siteurl/wp-content/image.jpg' width='400' height='200' srcset="$siteurl/wp-content/image-300X150.jpg 300w, $siteurl/wp-content/image-600X300.jpg 600w" sizes="(max-width: 300px) 100vw, 300px" />
2304
MARKUP;
2305
2306
        $expected = <<<MARKUP
2307
<img src='$imgopthost/client/q_glossy,ret_img,w_400,h_200/$siteurl/wp-content/image.jpg' width='400' height='200' srcset="$imgopthost/client/q_glossy,ret_img,w_300/$siteurl/wp-content/image-300X150.jpg 300w, $imgopthost/client/q_glossy,ret_img,w_600/$siteurl/wp-content/image-600X300.jpg 600w" sizes="(max-width: 300px) 100vw, 300px" />
2308
MARKUP;
2309
        $instance = autoptimizeImages::instance();
2310
        $instance->set_options( $opts );
2311
        $actual = $instance->filter_optimize_images( $markup );
2312
        $this->assertEquals( $expected, $actual );
2313
    }
2314
2315
    /**
2316
     * Test image optimization in autoptimizeImages.php.
2317
     *
2318
     * case: img with srcsets and lazyload
2319
     */
2320
    public function test_imgopt_with_lazyload()
2321
    {
2322
        $urls                                        = $this->get_urls();
2323
        $siteurl                                     = $urls['siteurl'];
2324
        $imgopthost                                  = $urls['imgopthost'];
2325
        $opts                                        = autoptimizeImages::fetch_options();
2326
        $opts['autoptimize_imgopt_checkbox_field_1'] = '1';
2327
        $opts['autoptimize_imgopt_checkbox_field_3'] = '1';
2328
2329
        $markup = <<<MARKUP
2330
<img src='$siteurl/wp-content/image.jpg' width='400' height='200' srcset="$siteurl/wp-content/image-300X150.jpg 300w, $siteurl/wp-content/image-600X300.jpg 600w" sizes="(max-width: 300px) 100vw, 300px" />
2331
MARKUP;
2332
2333
        $expected = <<<MARKUP
2334
<noscript><img src='$imgopthost/client/q_glossy,ret_img,w_400,h_200/$siteurl/wp-content/image.jpg' width='400' height='200' srcset="$imgopthost/client/q_glossy,ret_img,w_300/$siteurl/wp-content/image-300X150.jpg 300w, $imgopthost/client/q_glossy,ret_img,w_600/$siteurl/wp-content/image-600X300.jpg 600w" sizes="(max-width: 300px) 100vw, 300px" /></noscript><img class="lazyload" src='$imgopthost/client/q_lqip,ret_wait,w_400,h_200/$siteurl/wp-content/image.jpg' data-src='$imgopthost/client/q_glossy,ret_img,w_400,h_200/$siteurl/wp-content/image.jpg' width='400' height='200' data-srcset="$imgopthost/client/q_glossy,ret_img,w_300/$siteurl/wp-content/image-300X150.jpg 300w, $imgopthost/client/q_glossy,ret_img,w_600/$siteurl/wp-content/image-600X300.jpg 600w" sizes="(max-width: 300px) 100vw, 300px" />
2335
MARKUP;
2336
2337
        $instance = autoptimizeImages::instance();
2338
        $instance->set_options( $opts );
2339
        $actual = $instance->filter_optimize_images( $markup );
2340
        $this->assertEquals( $expected, $actual );
2341
    }
2342
2343
    /**
2344
     * Test image optimization in autoptimizeImages.php.
2345
     *
2346
     * case: background image in a style attribute
2347
     */
2348 View Code Duplication
    public function test_imgopt_bgimg()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2349
    {
2350
        $urls                                        = $this->get_urls();
2351
        $siteurl                                     = $urls['siteurl'];
2352
        $imgopthost                                  = $urls['imgopthost'];
2353
        $opts                                        = autoptimizeImages::fetch_options();
2354
        $opts['autoptimize_imgopt_checkbox_field_1'] = '1';
2355
        $opts['autoptimize_imgopt_checkbox_field_3'] = '0';
2356
2357
        $markup = <<<MARKUP
2358
<div class="textwidget custom-html-widget"><div class="et_parallax_bg et_pb_parallax_css" style="height:200px; background-image: url($siteurl/wp-content/uploads/2018/05/DSC_1615-300x201.jpg);"></div>
2359
MARKUP;
2360
2361
        $expected = <<<MARKUP
2362
<div class="textwidget custom-html-widget"><div class="et_parallax_bg et_pb_parallax_css" style="height:200px; background-image: url($imgopthost/client/q_glossy,ret_img/$siteurl/wp-content/uploads/2018/05/DSC_1615-300x201.jpg);"></div>
2363
MARKUP;
2364
2365
        $instance = autoptimizeImages::instance();
2366
        $instance->set_options( $opts );
2367
        $actual = $instance->filter_optimize_images( $markup );
2368
        $this->assertEquals( $expected, $actual );
2369
    }
2370
2371
    /**
2372
     * Test lazyloading in autoptimizeImages.php.
2373
     *
2374
     * case: no image optimization
2375
     */
2376
    public function test_lazyload()
2377
    {
2378
        $urls                                        = $this->get_urls();
2379
        $siteurl                                     = $urls['siteurl'];
2380
        $imgopthost                                  = $urls['imgopthost'];
0 ignored issues
show
Unused Code introduced by
$imgopthost is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
2381
        $opts                                        = autoptimizeImages::fetch_options();
2382
        $opts['autoptimize_imgopt_checkbox_field_3'] = '1';
2383
2384
        $markup = <<<MARKUP
2385
<img src='$siteurl/wp-content/image.jpg' width='400' height='200' srcset="$siteurl/wp-content/image-300X150.jpg 300w, $siteurl/wp-content/image-600X300.jpg 600w" sizes="(max-width: 300px) 100vw, 300px" />
2386
MARKUP;
2387
2388
        $expected = <<<MARKUP
2389
<noscript><img src='$siteurl/wp-content/image.jpg' width='400' height='200' srcset="$siteurl/wp-content/image-300X150.jpg 300w, $siteurl/wp-content/image-600X300.jpg 600w" sizes="(max-width: 300px) 100vw, 300px" /></noscript><img class="lazyload" src='data:image/svg+xml,%3Csvg%20xmlns=%22http://www.w3.org/2000/svg%22%20viewBox=%220%200%20400%20200%22%3E%3C/svg%3E' data-src='$siteurl/wp-content/image.jpg' width='400' height='200' data-srcset="$siteurl/wp-content/image-300X150.jpg 300w, $siteurl/wp-content/image-600X300.jpg 600w" sizes="(max-width: 300px) 100vw, 300px" />
2390
MARKUP;
2391
2392
        $instance = autoptimizeImages::instance();
2393
        $instance->set_options( $opts );
2394
        $actual = $instance->filter_lazyload_images( $markup );
2395
        $this->assertEquals( $expected, $actual );
2396
    }
2397
2398
    /**
2399
     * Test image optimization in autoptimizeImages.php.
2400
     *
2401
     * Exception case: image served by .php, should not be proxied.
2402
     */
2403
    public function test_imgopt_php()
2404
    {
2405
        $opts                                        = autoptimizeImages::fetch_options();
2406
        $opts['autoptimize_imgopt_checkbox_field_1'] = '1';
2407
        $opts['autoptimize_imgopt_checkbox_field_3'] = '0';
2408
2409
        $markup = <<<MARKUP
2410
<img src='/wp-content/plugins/imageplugin/image.php?id=16' width='400' height='200'>
2411
MARKUP;
2412
2413
        $instance = autoptimizeImages::instance();
2414
        $instance->set_options( $opts );
2415
        $actual = $instance->filter_optimize_images( $markup );
2416
2417
        // Expecting $markup since replacement should not happen.
2418
        $this->assertEquals( $markup, $actual );
2419
    }
2420
2421
    /**
2422
     * Test image optimization in autoptimizeImages.php.
2423
     *
2424
     * Alternate case: lazy loaded images with srcsets (using wp rocket variant HTML)
2425
     */
2426
    public function test_imgopt_alreadylazied()
2427
    {
2428
        $urls                                        = $this->get_urls();
2429
        $siteurl                                     = $urls['siteurl'];
2430
        $imgopthost                                  = $urls['imgopthost'];
2431
        $opts                                        = autoptimizeImages::fetch_options();
2432
        $opts['autoptimize_imgopt_checkbox_field_1'] = '1';
2433
        $opts['autoptimize_imgopt_checkbox_field_3'] = '0';
2434
2435
        $markup = <<<MARKUP
2436
<img src="data:image/gif;base64,R0lGODdhAQABAPAAAP///wAAACwAAAAAAQABAEACAkQBADs=" data-lazy-src='$siteurl/wp-content/image.jpg' width='400' height='200' data-lazy-srcset="$siteurl/wp-content/image-300X150.jpg 300w, $siteurl/wp-content/image-600X300.jpg 600w" sizes="(max-width: 300px) 100vw, 300px" />
2437
MARKUP;
2438
2439
        $expected = <<<MARKUP
2440
<img src="data:image/gif;base64,R0lGODdhAQABAPAAAP///wAAACwAAAAAAQABAEACAkQBADs=" data-lazy-src='$imgopthost/client/q_glossy,ret_img,w_400,h_200/$siteurl/wp-content/image.jpg' width='400' height='200' data-lazy-srcset="$imgopthost/client/q_glossy,ret_img,w_300/$siteurl/wp-content/image-300X150.jpg 300w, $imgopthost/client/q_glossy,ret_img,w_600/$siteurl/wp-content/image-600X300.jpg 600w" sizes="(max-width: 300px) 100vw, 300px" />
2441
MARKUP;
2442
2443
        $instance = autoptimizeImages::instance();
2444
        $instance->set_options( $opts );
2445
        $actual = $instance->filter_optimize_images( $markup );
2446
2447
        $this->assertEquals( $expected, $actual );
2448
    }
2449
2450
    /**
2451
     * Test image optimization when image urls have no explict host provided.
2452
     */
2453 View Code Duplication
    public function test_imgopt_url_normalize_root_relative()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2454
    {
2455
        $urls                                        = $this->get_urls();
2456
        $siteurl                                     = $urls['siteurl'];
2457
        $imgopthost                                  = $urls['imgopthost'];
2458
        $opts                                        = autoptimizeImages::fetch_options();
2459
        $opts['autoptimize_imgopt_checkbox_field_1'] = '1';
2460
        $opts['autoptimize_imgopt_checkbox_field_3'] = '0';
2461
2462
        $markup = <<<MARKUP
2463
<img src='/wp-content/image.jpg' width='400' height='200' srcset="/wp-content/image-300X150.jpg 300w, /wp-content/image-600X300.jpg 600w" sizes="(max-width: 300px) 100vw, 300px" />
2464
MARKUP;
2465
2466
        $expected = <<<MARKUP
2467
<img src='$imgopthost/client/q_glossy,ret_img,w_400,h_200/$siteurl/wp-content/image.jpg' width='400' height='200' srcset="$imgopthost/client/q_glossy,ret_img,w_300/$siteurl/wp-content/image-300X150.jpg 300w, $imgopthost/client/q_glossy,ret_img,w_600/$siteurl/wp-content/image-600X300.jpg 600w" sizes="(max-width: 300px) 100vw, 300px" />
2468
MARKUP;
2469
2470
        $instance = autoptimizeImages::instance();
2471
        $instance->set_options( $opts );
2472
        $actual = $instance->filter_optimize_images( $markup );
2473
2474
        $this->assertEquals( $expected, $actual );
2475
    }
2476
2477
    /**
2478
     * Test image optimization when image urls have a protocol-relative url.
2479
     */
2480
    public function test_imgopt_url_normalize_protocol_relative()
2481
    {
2482
        $urls                                        = $this->get_urls();
2483
        $siteurl                                     = $urls['siteurl'];
2484
        $prsiteurl                                   = $urls['prsiteurl'];
2485
        $imgopthost                                  = $urls['imgopthost'];
2486
        $opts                                        = autoptimizeImages::fetch_options();
2487
        $opts['autoptimize_imgopt_checkbox_field_1'] = '1';
2488
        $opts['autoptimize_imgopt_checkbox_field_3'] = '0';
2489
2490
        $markup = <<<MARKUP
2491
<img src='$prsiteurl/wp-content/image.jpg' width='400' height='200' srcset="$prsiteurl/wp-content/image-300X150.jpg 300w, $prsiteurl/wp-content/image-600X300.jpg 600w" sizes="(max-width: 300px) 100vw, 300px" />
2492
MARKUP;
2493
2494
        $expected = <<<MARKUP
2495
<img src='$imgopthost/client/q_glossy,ret_img,w_400,h_200/$siteurl/wp-content/image.jpg' width='400' height='200' srcset="$imgopthost/client/q_glossy,ret_img,w_300/$siteurl/wp-content/image-300X150.jpg 300w, $imgopthost/client/q_glossy,ret_img,w_600/$siteurl/wp-content/image-600X300.jpg 600w" sizes="(max-width: 300px) 100vw, 300px" />
2496
MARKUP;
2497
2498
        $instance = autoptimizeImages::instance();
2499
        $instance->set_options( $opts );
2500
        $actual = $instance->filter_optimize_images( $markup );
2501
2502
        $this->assertEquals( $expected, $actual );
2503
    }
2504
2505
    /**
2506
     * @dataProvider provider_str_is_valid_regex
2507
     */
2508
    public function test_str_is_valid_regex( $str, $expected )
2509
    {
2510
        $actual = autoptimizeUtils::str_is_valid_regex( $str );
2511
2512
        $this->assertEquals( $expected, $actual );
2513
    }
2514
2515
    public function provider_str_is_valid_regex()
2516
    {
2517
        return [
2518
            [ '<!--[if', false ],
2519
            [ '&lt;--[if', false ],
2520
            [ '/booya/i', true ],
2521
            [ '~Valid(Regular)Expression~', true ],
2522
        ];
2523
    }
2524
2525
    /**
2526
     * @dataProvider provider_protocol_relative_tests
2527
     */
2528
    public function test_is_protocol_relative( $str, $expected )
2529
    {
2530
        $actual = autoptimizeUtils::is_protocol_relative( $str );
2531
2532
        $this->assertEquals( $expected, $actual );
2533
    }
2534
2535
    public function provider_protocol_relative_tests()
2536
    {
2537
        return [
2538
            [ '//something-that-might-be-an-url-but-isnt-really', true ],
2539
            [ '', false ],
2540
            [ null, false ],
2541
            [ 'booya/i', false ],
2542
            [ '/root-relative', false ],
2543
            [ 'http://what.ever/', false ],
2544
            [ 'https://booya.kasha', false ],
2545
            [ '1/', false ],
2546
        ];
2547
    }
2548
2549 View Code Duplication
    public function test_css_minifier_unmatched_parens()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2550
    {
2551
        $css = <<<MARKUP
2552
img.centered, .aligncenter {
2553
    -webkit-box-shadow: none;
2554
    -moz-box-shadow: none;
2555
    box-shadow: none;
2556
MARKUP;
2557
2558
        $expected = 'img.centered,.aligncenter{-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}';
2559
2560
        $instance = new autoptimizeStyles( $css );
2561
        $minified = $instance->run_minifier_on( $css );
2562
2563
        $this->assertEquals( $expected, $minified );
2564
    }
2565
2566
    public function test_css_font_names_mangling()
2567
    {
2568
        // Properly quoted font names dont get mangled.
2569
        $css      = 'h2{font-family:"Archivo Black"}';
2570
        $instance = new autoptimizeStyles( $css );
2571
        $actual   = $instance->run_minifier_on( $css );
2572
        $this->assertEquals( $css, $actual );
2573
2574
        // When not quoted, 'Black' used to become '#000', but not anymore... :)
2575
        $css_unquoted = 'h2{font-family:Archivo Black;}';
2576
        $expected     = 'h2{font-family:Archivo Black}';
2577
        $instance     = new autoptimizeStyles( $css_unquoted );
2578
        $actual       = $instance->run_minifier_on( $css_unquoted );
2579
        $this->assertEquals( $expected, $actual );
2580
2581
        $css_unquoted = 'h1{font:italic 1.2em Fira White,serif}';
2582
        $instance     = new autoptimizeStyles( $css_unquoted );
2583
        $actual       = $instance->run_minifier_on( $css_unquoted );
2584
        $this->assertEquals( $css_unquoted, $actual );
2585
    }
2586
2587
    public function test_is_plugin_active_utils_wrapper()
2588
    {
2589
        // Our plugin is loaded via "muplugins_loaded" filter in tests/bootstrap.php
2590
        $this->assertFalse( autoptimizeUtils::is_plugin_active( 'autoptimize/autoptimize.php' ) );
2591
        $this->assertFalse( autoptimizeUtils::is_plugin_active( 'async-javascript/async-javascript.php' ) );
2592
    }
2593
2594
    public function test_jsminphp_string_literal_minification()
2595
    {
2596
        $js = '
2597
// comment
2598
`line
2599
break` + `he  llo`; foo`hel( \'\');lo`; `he\nl\`lo`; (`he${one + two}`)
2600
';
2601
2602
        $expected = '`line
2603
break`+`he  llo`;foo`hel( \'\');lo`;`he\nl\`lo`;(`he${one + two}`)';
2604
2605
        $actual = JSMin::minify( $js );
2606
        $this->assertEquals( $expected, $actual );
2607
    }
2608
}
2609