AOTest::test_imgopt_lazyload_picture()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 21

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 0
dl 0
loc 21
rs 9.584
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
            'defer_not_aggregate' => $conf->get( 'autoptimize_js_defer_not_aggregate' ),
52
            'justhead'            => $conf->get( 'autoptimize_js_justhead' ),
53
            'forcehead'           => $conf->get( 'autoptimize_js_forcehead' ),
54
            'trycatch'            => $conf->get( 'autoptimize_js_trycatch' ),
55
            'js_exclude'          => $conf->get( 'autoptimize_js_exclude' ),
56
            'cdn_url'             => $conf->get( 'autoptimize_cdn_url' ),
57
            'include_inline'      => $conf->get( 'autoptimize_js_include_inline' ),
58
            'minify_excluded'     => $conf->get( 'autoptimize_minify_excluded' ),
59
        ];
60
    }
61
62
    /**
63
     * @return array
64
     */
65
    protected function get_urls()
66
    {
67
        static $site_url = null;
68
        if ( null === $site_url ) {
69
            $site_url = site_url();
70
        }
71
72
        static $cdn_url = null;
73
        if ( null === $cdn_url ) {
74
            $cdn_url = autoptimizeOptionWrapper::get_option( 'autoptimize_cdn_url' );
75
        }
76
77
        static $imgopt_host = null;
78
        if ( null === $imgopt_host ) {
79
            $optimizer   = new autoptimizeImages();
80
            $imgopt_host = rtrim( $optimizer->get_imgopt_host(), '/' );
81
        }
82
83
        static $urls = [];
84
85
        if ( empty( $urls ) ) {
86
            $parts = autoptimizeUtils::get_ao_wp_site_url_parts();
87
            $urls  = [
88
                'siteurl'    => $site_url,
89
                'prsiteurl'  => '//' . str_replace( array( 'http://', 'https://' ), '', $site_url ),
90
                'wwwsiteurl' => $parts['scheme'] . '://www.' . str_replace( 'www.', '', $parts['host'] ),
91
                'cdnurl'     => $cdn_url,
92
                'imgopthost' => $imgopt_host,
93
                'subfolder'  => '',
94
            ];
95
96
            if ( AO_TEST_SUBFOLDER_INSTALL ) {
97
                $urls['subfolder'] = 'wordpress/';
98
            }
99
        }
100
101
        return $urls;
102
    }
103
104
    /**
105
     * Runs before each test method.
106
     */
107
    public function setUp()
108
    {
109
        $this->ao = new autoptimizeMain( AUTOPTIMIZE_PLUGIN_VERSION, AUTOPTIMIZE_PLUGIN_FILE );
110
111
        parent::setUp();
112
    }
113
114
    /**
115
     * Runs after each test method.
116
     */
117
    public function tearDown()
118
    {
119
        // Making sure certain filters are removed after each test to ensure isolation.
120
        $filter_tags = array(
121
            'autoptimize_filter_noptimize',
122
            'autoptimize_filter_base_cdnurl',
123
            'autoptimize_filter_css_is_datauri_candidate',
124
            'autoptimize_filter_css_datauri_image',
125
            'autoptimize_filter_css_inlinesize',
126
            'autoptimize_filter_css_fonts_cdn',
127
        );
128
        foreach ( $filter_tags as $filter_tag ) {
129
            remove_all_filters( $filter_tag );
130
        }
131
132
        parent::tearDown();
133
    }
134
135
    protected function get_test_markup()
136
    {
137
        $siteurl = $this->get_urls()['siteurl'];
138
139
        $markup = <<<MARKUP
140
<!DOCTYPE html>
141
<!--[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]-->
142
<!--[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]-->
143
<!--[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]-->
144
<!--[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]-->
145
<head>
146
<meta charset="utf-8">
147
<title>Mliječna juha od brokule &#9832; Kuhaj.hr</title>
148
<meta name="viewport" content="width=device-width,initial-scale=1">
149
<style type="text/css">
150
/* cdn rewrite tests */
151
152
.bg { background:url('img/something.svg'); }
153
.bg-no-quote { background: url(img/something.svg); }
154
.bg-double-quotes { background: url("img/something.svg"); }
155
156
.whitespaces { background : url   (  "../../somewhere-else/svg.svg" ) ; }
157
158
.host-relative { background: url("/img/something.svg"); }
159
.protocol-relative { background: url("//something/somewhere/example.png"); }
160
161
/* roboto-100 - latin-ext_latin */
162
@font-face {
163
    font-family: 'Roboto';
164
    font-style: normal;
165
    font-weight: 100;
166
    src: url('../fonts/roboto-v15-latin-ext_latin-100.eot'); /* IE9 Compat Modes */
167
    src: local('Roboto Thin'), local('Roboto-Thin'),
168
        url('../fonts/roboto-v15-latin-ext_latin-100.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
169
        url('../fonts/roboto-v15-latin-ext_latin-100.woff2') format('woff2'), /* Super Modern Browsers */
170
        url('../fonts/roboto-v15-latin-ext_latin-100.woff') format('woff'), /* Modern Browsers */
171
        url('../fonts/roboto-v15-latin-ext_latin-100.ttf') format('truetype'), /* Safari, Android, iOS */
172
        url('../fonts/roboto-v15-latin-ext_latin-100.svg#Roboto') format('svg'); /* Legacy iOS */
173
}
174
/* roboto-300 - latin-ext_latin */
175
@font-face {
176
    font-family: 'Roboto';
177
    font-style: normal;
178
    font-weight: 300;
179
    src: url('../fonts/roboto-v15-latin-ext_latin-300.eot'); /* IE9 Compat Modes */
180
    src: local('Roboto Light'), local('Roboto-Light'),
181
        url('../fonts/roboto-v15-latin-ext_latin-300.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
182
        url('../fonts/roboto-v15-latin-ext_latin-300.woff2') format('woff2'), /* Super Modern Browsers */
183
        url('../fonts/roboto-v15-latin-ext_latin-300.woff') format('woff'), /* Modern Browsers */
184
        url('../fonts/roboto-v15-latin-ext_latin-300.ttf') format('truetype'), /* Safari, Android, iOS */
185
        url('../fonts/roboto-v15-latin-ext_latin-300.svg#Roboto') format('svg'); /* Legacy iOS */
186
}
187
/* roboto-regular - latin-ext_latin */
188
@font-face {
189
    font-family: 'Roboto';
190
    font-style: normal;
191
    font-weight: 400;
192
    src: url('../fonts/roboto-v15-latin-ext_latin-regular.eot'); /* IE9 Compat Modes */
193
    src: local('Roboto'), local('Roboto-Regular'),
194
        url('../fonts/roboto-v15-latin-ext_latin-regular.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
195
        url('../fonts/roboto-v15-latin-ext_latin-regular.woff2') format('woff2'), /* Super Modern Browsers */
196
        url('../fonts/roboto-v15-latin-ext_latin-regular.woff') format('woff'), /* Modern Browsers */
197
        url('../fonts/roboto-v15-latin-ext_latin-regular.ttf') format('truetype'), /* Safari, Android, iOS */
198
        url('../fonts/roboto-v15-latin-ext_latin-regular.svg#Roboto') format('svg'); /* Legacy iOS */
199
}
200
/* roboto-500 - latin-ext_latin */
201
@font-face {
202
    font-family: 'Roboto';
203
    font-style: normal;
204
    font-weight: 500;
205
    src: url('../fonts/roboto-v15-latin-ext_latin-500.eot'); /* IE9 Compat Modes */
206
    src: local('Roboto Medium'), local('Roboto-Medium'),
207
        url('../fonts/roboto-v15-latin-ext_latin-500.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
208
        url('../fonts/roboto-v15-latin-ext_latin-500.woff2') format('woff2'), /* Super Modern Browsers */
209
        url('../fonts/roboto-v15-latin-ext_latin-500.woff') format('woff'), /* Modern Browsers */
210
        url('../fonts/roboto-v15-latin-ext_latin-500.ttf') format('truetype'), /* Safari, Android, iOS */
211
        url('../fonts/roboto-v15-latin-ext_latin-500.svg#Roboto') format('svg'); /* Legacy iOS */
212
}
213
</style>
214
    <!--[if lt IE 9]>
215
    <script src="$siteurl/wp-content/themes/my-theme/js/vendor/html5shiv-printshiv.min.js" type="text/javascript"></script>
216
    <![endif]-->
217
    <!--[if (gte IE 6)&(lte IE 8)]>
218
        <script type="text/javascript" src="$siteurl/wp-content/themes/my-theme/js/vendor/respond.min.js"></script>
219
    <![endif]-->
220
<link rel='stylesheet' href='https://cdn.jsdelivr.net/npm/[email protected]/slick/slick.css'>
221
<link rel='stylesheet' media='print' href='https://justsome.url/print.css'>
222
</head>
223
224
<body class="single single-post">
225
226
    <div id="fb-root"></div>
227
    <script>(function(d, s, id) {
228
        var js, fjs = d.getElementsByTagName(s)[0];
229
        if (d.getElementById(id)) return;
230
        js = d.createElement(s); js.id = id;
231
        js.src = "//connect.facebook.net/hr_HR/sdk.js#version=v2.0&xfbml=1&appId=";
232
        fjs.parentNode.insertBefore(js, fjs);
233
    }(document, 'script', 'facebook-jssdk'));</script>
234
    </script>
235
236
<script type='text/javascript' src='$siteurl/wp-content/plugins/ajax-load-more/core/js/ajax-load-more.min.js?ver=1.1'></script>
237
<script type='text/javascript' src='$siteurl/wp-content/plugins/wp-ga-social-tracking-js/ga-social-tracking.min.js'></script>
238
<script type='text/javascript' src='$siteurl/wp-content/themes/my-theme/js/vendor/alm-seo.js'></script>
239
<script type='text/javascript' src='$siteurl/wp-content/themes/my-theme/js/vendor/jquery.placeholder-2.1.1.min.js'></script>
240
<script type='text/javascript' src='$siteurl/wp-content/themes/my-theme/js/vendor/typeahead.bundle.min.js'></script>
241
<script type='text/javascript' src='$siteurl/wp-content/themes/my-theme/js/vendor/bootstrap-tagsinput.min.js'></script>
242
<script type='text/javascript' src='$siteurl/wp-content/themes/my-theme/js/m-mobilemenu.js'></script>
243
<script type='text/javascript' src='$siteurl/wp-content/themes/my-theme/js/main.js'></script>
244
<script type='text/javascript' src='$siteurl/wp-includes/js/comment-reply.min.js?ver=4.1.1'></script>
245
</body>
246
</html>
247
MARKUP;
248
249
        return $markup;
250
    }
251
252 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...
253
    {
254
        $key = 'default';
255
        if ( defined( 'CUSTOM_CONSTANTS_USED' ) && CUSTOM_CONSTANTS_USED ) {
256
            $key = 'custom';
257
        }
258
259
        $csspart = self::$flexible_url_parts_css[ $key ];
260
        $jspart  = self::$flexible_url_parts_js[ $key ];
261
262
        $csshash = '863f587e89f100b0223ddccc0dabc57a';
263
        if ( AO_TEST_SUBFOLDER_INSTALL ) {
264
            $csshash = '56398de576d59887e88e3011715250e0';
265
        }
266
267
        $urls      = $this->get_urls();
268
            $siteurl   = $urls['siteurl'];
269
        $cdnurl    = $urls['cdnurl'];
270
        $subfolder = $urls['subfolder'];
271
272
        $markup = <<<MARKUP
273
<!DOCTYPE html>
274
<!--[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]-->
275
<!--[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]-->
276
<!--[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]-->
277
<!--[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]-->
278
<head>
279
<meta charset="utf-8">
280
<link media="all" href="${cdnurl}/${subfolder}${csspart}${csshash}.css" rel="stylesheet" /><title>Mliječna juha od brokule &#9832; Kuhaj.hr</title>
281
<meta name="viewport" content="width=device-width,initial-scale=1">
282
283
    <!--[if lt IE 9]>
284
    <script src="$siteurl/wp-content/themes/my-theme/js/vendor/html5shiv-printshiv.min.js" type="text/javascript"></script>
285
    <![endif]-->
286
    <!--[if (gte IE 6)&(lte IE 8)]>
287
        <script type="text/javascript" src="$siteurl/wp-content/themes/my-theme/js/vendor/respond.min.js"></script>
288
    <![endif]-->
289
<link rel='stylesheet' href='https://cdn.jsdelivr.net/npm/[email protected]/slick/slick.css'>
290
<link rel='stylesheet' media='print' href='https://justsome.url/print.css'>
291
</head>
292
293
<body class="single single-post">
294
295
    <div id="fb-root"></div>
296
    <script>(function(d, s, id) {
297
        var js, fjs = d.getElementsByTagName(s)[0];
298
        if (d.getElementById(id)) return;
299
        js = d.createElement(s); js.id = id;
300
        js.src = "//connect.facebook.net/hr_HR/sdk.js#version=v2.0&xfbml=1&appId=";
301
        fjs.parentNode.insertBefore(js, fjs);
302
    }(document, 'script', 'facebook-jssdk'));</script>
303
    </script>
304
305
<script type='text/javascript' src='$siteurl/wp-content/plugins/ajax-load-more/core/js/ajax-load-more.min.js?ver=1.1'></script>
306
<script type='text/javascript' src='$siteurl/wp-content/plugins/wp-ga-social-tracking-js/ga-social-tracking.min.js'></script>
307
<script type='text/javascript' src='$siteurl/wp-content/themes/my-theme/js/vendor/alm-seo.js'></script>
308
<script type='text/javascript' src='$siteurl/wp-content/themes/my-theme/js/vendor/jquery.placeholder-2.1.1.min.js'></script>
309
<script type='text/javascript' src='$siteurl/wp-content/themes/my-theme/js/vendor/typeahead.bundle.min.js'></script>
310
<script type='text/javascript' src='$siteurl/wp-content/themes/my-theme/js/vendor/bootstrap-tagsinput.min.js'></script>
311
<script type='text/javascript' src='$siteurl/wp-content/themes/my-theme/js/m-mobilemenu.js'></script>
312
<script type='text/javascript' src='$siteurl/wp-content/themes/my-theme/js/main.js'></script>
313
314
<script defer src="$cdnurl/${subfolder}${jspart}2d6e668fad0726747cb413ac61486ee0.js"></script></body>
315
</html>
316
MARKUP;
317
318
        return $markup;
319
    }
320
321 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...
322
    {
323
        $key = 'multisite';
324
        if ( defined( 'CUSTOM_CONSTANTS_USED' ) && CUSTOM_CONSTANTS_USED ) {
325
            $key = 'multisite_custom';
326
        }
327
328
        $csspart = self::$flexible_url_parts_css[ $key ];
329
        $jspart  = self::$flexible_url_parts_js[ $key ];
330
331
        $csshash = '863f587e89f100b0223ddccc0dabc57a';
332
        if ( AO_TEST_SUBFOLDER_INSTALL ) {
333
            $csshash = '56398de576d59887e88e3011715250e0';
334
        }
335
336
        $urls      = $this->get_urls();
337
        $siteurl   = $urls['siteurl'];
338
        $cdnurl    = $urls['cdnurl'];
339
        $subfolder = $urls['subfolder'];
340
341
        $markup = <<<MARKUP
342
<!DOCTYPE html>
343
<!--[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]-->
344
<!--[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]-->
345
<!--[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]-->
346
<!--[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]-->
347
<head>
348
<meta charset="utf-8">
349
<link media="all" href="$cdnurl/${subfolder}${csspart}${csshash}.css" rel="stylesheet" /><title>Mliječna juha od brokule &#9832; Kuhaj.hr</title>
350
<meta name="viewport" content="width=device-width,initial-scale=1">
351
352
    <!--[if lt IE 9]>
353
    <script src="$siteurl/wp-content/themes/my-theme/js/vendor/html5shiv-printshiv.min.js" type="text/javascript"></script>
354
    <![endif]-->
355
    <!--[if (gte IE 6)&(lte IE 8)]>
356
        <script type="text/javascript" src="$siteurl/wp-content/themes/my-theme/js/vendor/respond.min.js"></script>
357
    <![endif]-->
358
<link rel='stylesheet' href='https://cdn.jsdelivr.net/npm/[email protected]/slick/slick.css'>
359
<link rel='stylesheet' media='print' href='https://justsome.url/print.css'>
360
</head>
361
362
<body class="single single-post">
363
364
    <div id="fb-root"></div>
365
    <script>(function(d, s, id) {
366
        var js, fjs = d.getElementsByTagName(s)[0];
367
        if (d.getElementById(id)) return;
368
        js = d.createElement(s); js.id = id;
369
        js.src = "//connect.facebook.net/hr_HR/sdk.js#version=v2.0&xfbml=1&appId=";
370
        fjs.parentNode.insertBefore(js, fjs);
371
    }(document, 'script', 'facebook-jssdk'));</script>
372
    </script>
373
374
<script type='text/javascript' src='$siteurl/wp-content/plugins/ajax-load-more/core/js/ajax-load-more.min.js?ver=1.1'></script>
375
<script type='text/javascript' src='$siteurl/wp-content/plugins/wp-ga-social-tracking-js/ga-social-tracking.min.js'></script>
376
<script type='text/javascript' src='$siteurl/wp-content/themes/my-theme/js/vendor/alm-seo.js'></script>
377
<script type='text/javascript' src='$siteurl/wp-content/themes/my-theme/js/vendor/jquery.placeholder-2.1.1.min.js'></script>
378
<script type='text/javascript' src='$siteurl/wp-content/themes/my-theme/js/vendor/typeahead.bundle.min.js'></script>
379
<script type='text/javascript' src='$siteurl/wp-content/themes/my-theme/js/vendor/bootstrap-tagsinput.min.js'></script>
380
<script type='text/javascript' src='$siteurl/wp-content/themes/my-theme/js/m-mobilemenu.js'></script>
381
<script type='text/javascript' src='$siteurl/wp-content/themes/my-theme/js/main.js'></script>
382
383
<script defer src="$cdnurl/${subfolder}${jspart}2d6e668fad0726747cb413ac61486ee0.js"></script></body>
384
</html>
385
MARKUP;
386
387
        return $markup;
388
    }
389
390 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...
391
    {
392
        $key = 'default';
393
        if ( defined( 'CUSTOM_CONSTANTS_USED' ) && CUSTOM_CONSTANTS_USED ) {
394
            $key = 'custom';
395
        }
396
397
        $csspart = self::$flexible_url_parts_css[ $key ];
398
        $jspart  = self::$flexible_url_parts_js[ $key ];
399
400
        $csshash = '863f587e89f100b0223ddccc0dabc57a';
401
        if ( AO_TEST_SUBFOLDER_INSTALL ) {
402
            $csshash = '56398de576d59887e88e3011715250e0';
403
        }
404
405
        $urls      = $this->get_urls();
406
        $siteurl   = $urls['siteurl'];
407
        $cdnurl    = $urls['cdnurl'];
408
        $subfolder = $urls['subfolder'];
409
410
        $markup = <<<MARKUP
411
<!DOCTYPE html>
412
<!--[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]-->
413
<!--[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]-->
414
<!--[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]-->
415
<!--[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]-->
416
<head>
417
<meta charset="utf-8">
418
<style id="aoatfcss" media="all">1</style><link rel="stylesheet" media="print" href="$cdnurl/${subfolder}${csspart}{$csshash}.css" onload="this.onload=null;this.media='all';" /><noscript id="aonoscrcss"><link media="all" href="$cdnurl/${subfolder}${csspart}${csshash}.css" rel="stylesheet" /></noscript><title>Mliječna juha od brokule &#9832; Kuhaj.hr</title>
419
<meta name="viewport" content="width=device-width,initial-scale=1">
420
421
    <!--[if lt IE 9]>
422
    <script src="$siteurl/wp-content/themes/my-theme/js/vendor/html5shiv-printshiv.min.js" type="text/javascript"></script>
423
    <![endif]-->
424
    <!--[if (gte IE 6)&(lte IE 8)]>
425
        <script type="text/javascript" src="$siteurl/wp-content/themes/my-theme/js/vendor/respond.min.js"></script>
426
    <![endif]-->
427
<noscript><link media='all' rel='stylesheet' href='https://cdn.jsdelivr.net/npm/[email protected]/slick/slick.css'></noscript><link media='print' onload="this.onload=null;this.media='all';" rel='stylesheet' href='https://cdn.jsdelivr.net/npm/[email protected]/slick/slick.css'>
428
<link rel='stylesheet' media='print' href='https://justsome.url/print.css'>
429
</head>
430
431
<body class="single single-post">
432
433
    <div id="fb-root"></div>
434
    <script>(function(d, s, id) {
435
        var js, fjs = d.getElementsByTagName(s)[0];
436
        if (d.getElementById(id)) return;
437
        js = d.createElement(s); js.id = id;
438
        js.src = "//connect.facebook.net/hr_HR/sdk.js#version=v2.0&xfbml=1&appId=";
439
        fjs.parentNode.insertBefore(js, fjs);
440
    }(document, 'script', 'facebook-jssdk'));</script>
441
    </script>
442
443
<script type='text/javascript' src='$siteurl/wp-content/plugins/ajax-load-more/core/js/ajax-load-more.min.js?ver=1.1'></script>
444
<script type='text/javascript' src='$siteurl/wp-content/plugins/wp-ga-social-tracking-js/ga-social-tracking.min.js'></script>
445
<script type='text/javascript' src='$siteurl/wp-content/themes/my-theme/js/vendor/alm-seo.js'></script>
446
<script type='text/javascript' src='$siteurl/wp-content/themes/my-theme/js/vendor/jquery.placeholder-2.1.1.min.js'></script>
447
<script type='text/javascript' src='$siteurl/wp-content/themes/my-theme/js/vendor/typeahead.bundle.min.js'></script>
448
<script type='text/javascript' src='$siteurl/wp-content/themes/my-theme/js/vendor/bootstrap-tagsinput.min.js'></script>
449
<script type='text/javascript' src='$siteurl/wp-content/themes/my-theme/js/m-mobilemenu.js'></script>
450
<script type='text/javascript' src='$siteurl/wp-content/themes/my-theme/js/main.js'></script>
451
452
<script defer src="$cdnurl/${subfolder}${jspart}2d6e668fad0726747cb413ac61486ee0.js"></script></body>
453
</html>
454
MARKUP;
455
456
        return $markup;
457
    }
458
459 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...
460
    {
461
        $key = 'multisite';
462
        if ( defined( 'CUSTOM_CONSTANTS_USED' ) && CUSTOM_CONSTANTS_USED ) {
463
            $key = 'multisite_custom';
464
        }
465
466
        $csspart = self::$flexible_url_parts_css[ $key ];
467
        $jspart  = self::$flexible_url_parts_js[ $key ];
468
469
        $csshash = '863f587e89f100b0223ddccc0dabc57a';
470
        if ( AO_TEST_SUBFOLDER_INSTALL ) {
471
            $csshash = '56398de576d59887e88e3011715250e0';
472
        }
473
474
        $urls      = $this->get_urls();
475
        $siteurl   = $urls['siteurl'];
476
        $cdnurl    = $urls['cdnurl'];
477
        $subfolder = $urls['subfolder'];
478
479
        $markup = <<<MARKUP
480
<!DOCTYPE html>
481
<!--[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]-->
482
<!--[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]-->
483
<!--[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]-->
484
<!--[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]-->
485
<head>
486
<meta charset="utf-8">
487
<style id="aoatfcss" media="all">1</style><link rel="stylesheet" media="print" href="$cdnurl/${subfolder}${csspart}${csshash}.css" onload="this.onload=null;this.media='all';" /><noscript id="aonoscrcss"><link media="all" href="$cdnurl/${subfolder}${csspart}${csshash}.css" rel="stylesheet" /></noscript><title>Mliječna juha od brokule &#9832; Kuhaj.hr</title>
488
<meta name="viewport" content="width=device-width,initial-scale=1">
489
490
    <!--[if lt IE 9]>
491
    <script src="$siteurl/wp-content/themes/my-theme/js/vendor/html5shiv-printshiv.min.js" type="text/javascript"></script>
492
    <![endif]-->
493
    <!--[if (gte IE 6)&(lte IE 8)]>
494
        <script type="text/javascript" src="$siteurl/wp-content/themes/my-theme/js/vendor/respond.min.js"></script>
495
    <![endif]-->
496
<noscript><link media='all' rel='stylesheet' href='https://cdn.jsdelivr.net/npm/[email protected]/slick/slick.css'></noscript><link media='print' onload="this.onload=null;this.media='all';" rel='stylesheet' href='https://cdn.jsdelivr.net/npm/[email protected]/slick/slick.css'>
497
<link rel='stylesheet' media='print' href='https://justsome.url/print.css'>
498
</head>
499
500
<body class="single single-post">
501
502
    <div id="fb-root"></div>
503
    <script>(function(d, s, id) {
504
        var js, fjs = d.getElementsByTagName(s)[0];
505
        if (d.getElementById(id)) return;
506
        js = d.createElement(s); js.id = id;
507
        js.src = "//connect.facebook.net/hr_HR/sdk.js#version=v2.0&xfbml=1&appId=";
508
        fjs.parentNode.insertBefore(js, fjs);
509
    }(document, 'script', 'facebook-jssdk'));</script>
510
    </script>
511
512
<script type='text/javascript' src='$siteurl/wp-content/plugins/ajax-load-more/core/js/ajax-load-more.min.js?ver=1.1'></script>
513
<script type='text/javascript' src='$siteurl/wp-content/plugins/wp-ga-social-tracking-js/ga-social-tracking.min.js'></script>
514
<script type='text/javascript' src='$siteurl/wp-content/themes/my-theme/js/vendor/alm-seo.js'></script>
515
<script type='text/javascript' src='$siteurl/wp-content/themes/my-theme/js/vendor/jquery.placeholder-2.1.1.min.js'></script>
516
<script type='text/javascript' src='$siteurl/wp-content/themes/my-theme/js/vendor/typeahead.bundle.min.js'></script>
517
<script type='text/javascript' src='$siteurl/wp-content/themes/my-theme/js/vendor/bootstrap-tagsinput.min.js'></script>
518
<script type='text/javascript' src='$siteurl/wp-content/themes/my-theme/js/m-mobilemenu.js'></script>
519
<script type='text/javascript' src='$siteurl/wp-content/themes/my-theme/js/main.js'></script>
520
521
<script defer src="$cdnurl/${subfolder}${jspart}2d6e668fad0726747cb413ac61486ee0.js"></script></body>
522
</html>
523
MARKUP;
524
525
        return $markup;
526
    }
527
528
    /**
529
     * @dataProvider provider_test_rewrite_markup_with_cdn
530
     */
531
    function test_rewrite_markup_with_cdn( $input, $expected )
532
    {
533
        $actual = $this->ao->end_buffering( $input );
534
535
        $this->assertEquals( $expected, $actual );
536
    }
537
538
    public function provider_test_rewrite_markup_with_cdn()
539
    {
540
        return array(
541
542
            array(
543
                // Input.
544
                $this->get_test_markup(),
545
                // Expected output.
546
                // TODO/FIXME: This seemed like the fastest way to get MS crude test to pass...
547
                ( is_multisite() ? $this->get_test_markup_output_ms() : $this->get_test_markup_output() ),
548
            ),
549
550
        );
551
    }
552
553
    public function test_rewrite_css_assets()
554
    {
555
        $urls   = $this->get_urls();
556
        $cdnurl = $urls['cdnurl'];
557
        $sub    = $urls['subfolder'];
558
559
        $css_in = <<<CSS
560
.bg { background:url('img/something.svg'); }
561
.bg-no-quote { background: url(img/something.svg); }
562
.bg-double-quotes { background: url("img/something.svg"); }
563
564
.whitespaces { background : url   (  "../../somewhere-else/svg.svg" ) ; }
565
566
.host-relative { background: url("/img/something.svg"); }
567
.protocol-relative { background: url("//something/somewhere/example.png"); }
568
569
@font-face {
570
  font-family: 'Roboto';
571
  font-style: normal;
572
  font-weight: 100;
573
  src: url('../fonts/roboto-v15-latin-ext_latin-100.eot'); /* IE9 Compat Modes */
574
  src: local('Roboto Thin'), local('Roboto-Thin'),
575
       url('../fonts/roboto-v15-latin-ext_latin-100.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
576
       url('../fonts/roboto-v15-latin-ext_latin-100.woff2') format('woff2'), /* Super Modern Browsers */
577
       url('../fonts/roboto-v15-latin-ext_latin-100.woff') format('woff'), /* Modern Browsers */
578
       url('../fonts/roboto-v15-latin-ext_latin-100.ttf') format('truetype'), /* Safari, Android, iOS */
579
       url('../fonts/roboto-v15-latin-ext_latin-100.svg#Roboto') format('svg'); /* Legacy iOS */
580
}
581
CSS;
582
583
        $css_expected = <<<CSS
584
.bg { background:url(img/something.svg); }
585
.bg-no-quote { background: url(img/something.svg); }
586
.bg-double-quotes { background: url(img/something.svg); }
587
588
.whitespaces { background : url   (  ../../somewhere-else/svg.svg) ; }
589
590
.host-relative { background: url(${cdnurl}/${sub}img/something.svg); }
591
.protocol-relative { background: url(//something/somewhere/example.png); }
592
593
@font-face {
594
  font-family: 'Roboto';
595
  font-style: normal;
596
  font-weight: 100;
597
  src: url('../fonts/roboto-v15-latin-ext_latin-100.eot'); /* IE9 Compat Modes */
598
  src: local('Roboto Thin'), local('Roboto-Thin'),
599
       url('../fonts/roboto-v15-latin-ext_latin-100.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
600
       url('../fonts/roboto-v15-latin-ext_latin-100.woff2') format('woff2'), /* Super Modern Browsers */
601
       url('../fonts/roboto-v15-latin-ext_latin-100.woff') format('woff'), /* Modern Browsers */
602
       url('../fonts/roboto-v15-latin-ext_latin-100.ttf') format('truetype'), /* Safari, Android, iOS */
603
       url('../fonts/roboto-v15-latin-ext_latin-100.svg#Roboto') format('svg'); /* Legacy iOS */
604
}
605
CSS;
606
607
        $instance = new autoptimizeStyles( $css_in );
608
        $instance->setOption( 'cdn_url', $cdnurl );
609
610
        $css_actual = $instance->rewrite_assets( $css_in );
611
612
        $this->assertEquals( $css_expected, $css_actual );
613
    }
614
615 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...
616
    {
617
        $css = <<<CSS
618
.bg { background:url('img/something.svg'); }
619
.bg-no-quote { background: url(img/something.svg); }
620
.bg-double-quotes { background: url("img/something.svg"); }
621
622
.whitespaces { background : url   (  "../../somewhere-else/svg.svg" ) ; }
623
624
.host-relative { background: url("/img/something.svg"); }
625
.protocol-relative { background: url("//something/somewhere/example.png"); }
626
627
/* roboto-100 - latin-ext_latin */
628
@font-face {
629
  font-family: 'Roboto';
630
  font-style: normal;
631
  font-weight: 100;
632
  src: url(../fonts/roboto-v15-latin-ext_latin-100.eot); /* IE9 Compat Modes */
633
  src: local('Roboto Thin'), local('Roboto-Thin'),
634
       url(../fonts/roboto-v15-latin-ext_latin-100.eot?#iefix) format('embedded-opentype'), /* IE6-IE8 */
635
       url(../fonts/roboto-v15-latin-ext_latin-100.woff2) format('woff2'), /* Super Modern Browsers */
636
       url(../fonts/roboto-v15-latin-ext_latin-100.woff) format('woff'), /* Modern Browsers */
637
       url(../fonts/roboto-v15-latin-ext_latin-100.ttf) format('truetype'), /* Safari, Android, iOS */
638
       url(../fonts/roboto-v15-latin-ext_latin-100.svg#Roboto) format('svg'); /* Legacy iOS */
639
}
640
CSS;
641
642
        $expected = <<<CSS
643
.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')}
644
CSS;
645
646
        $instance = new autoptimizeStyles( $css );
647
        $minified = $instance->run_minifier_on( $css );
648
649
        $this->assertEquals( $expected, $minified );
650
    }
651
652
    /**
653
     * @dataProvider provider_test_should_aggregate_script_types
654
     */
655
    public function test_should_aggregate_script_types( $input, $expected )
656
    {
657
        $instance = new autoptimizeScripts( '' );
658
        $actual   = $instance->should_aggregate( $input );
659
660
        $this->assertEquals( $expected, $actual );
661
    }
662
663
    public function provider_test_should_aggregate_script_types()
664
    {
665
        return array(
666
            // No type attribute at all.
667
            array(
668
                // Input.
669
                '<script>var something=true</script>',
670
                // Expected output.
671
                true,
672
            ),
673
            // Case-insensitive.
674
            array(
675
                '<script type="text/ecmaScript">var something=true</script>',
676
                true,
677
            ),
678
            // Allowed/aggregated now (wasn't previously).
679
            array(
680
                '<script type="application/javascript">var something=true</script>',
681
                true,
682
            ),
683
            // Quotes shouldn't matter, nor should case-sensitivity.
684
            array(
685
                '<script type=\'text/JaVascriPt">var something=true</script>',
686
                true,
687
            ),
688
            // Liberal to whitespace around attribute names/values.
689
            array(
690
                '<script tYpe = text/javascript>var something=true</script>',
691
                true,
692
            ),
693
            // Something custom, should be ignored/skipped.
694
            array(
695
                '<script type=template/javascript>var something=true</script>',
696
                false,
697
            ),
698
            // Type attribute checking should be constrained to actual script
699
            // tag's type attribute only, regardless of any `type=` string
700
            // present in the actual inline script contents.
701
            array(
702
                // Since there's no type attribute, it should be aggregate by default.
703
                '<script>var type=something;</script>',
704
                true,
705
            ),
706
            // Application/ld+json should not be aggregated by default regardless
707
            // of spacing around attr/values.
708
            array(
709
                '<script type = "application/ld+json" >{   "@context": "" }',
710
                false,
711
            ),
712
            array(
713
                '<script type="application/ld+json">{   "@context": "" }',
714
                false,
715
            ),
716
        );
717
    }
718
719
    /**
720
     * @dataProvider provider_is_valid_buffer
721
     */
722
    public function test_valid_buffers( $input, $expected )
723
    {
724
        $actual = $this->ao->is_valid_buffer( $input );
725
726
        $this->assertEquals( $expected, $actual );
727
    }
728
729
    public function provider_is_valid_buffer()
730
    {
731
        return array(
732
            array(
733
                '<!doctype html>
734
<html ⚡>',
735
                false,
736
            ),
737
            array(
738
                '<!doctype html>
739
<html amp>',
740
                false,
741
            ),
742
            array(
743
                '<?xml version="1.0" encoding="UTF-8"?>
744
<xsl:stylesheet version="1.0"
745
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">',
746
                false,
747
            ),
748
            array(
749
                // adding doctype & html tags to make sure that this is falsed by the extended has_xsl_stylesheet test.
750
                '<?xml version="2.0" encoding="UTF-8"?>
751
<!doctype html><html>
752
<?xml-stylesheet type="text/xsl" ',
753
                false,
754
            ),
755
            array(
756
                '<!doctype html>
757
<html>',
758
                true,
759
            ),
760
            array(
761
                '<html dir="ltr" amp>',
762
                false,
763
            ),
764
            array(
765
                '<html dir="ltr" ⚡>',
766
                false,
767
            ),
768
            array(
769
                '<html amp dir="ltr">',
770
                false,
771
            ),
772
            array(
773
                '<html ⚡ dir="ltr">',
774
                false,
775
            ),
776
            array(
777
                '<HTML ⚡ DIR="LTR">',
778
                false,
779
            ),
780
            array(
781
                '<HTML AMP DIR="LTR">',
782
                false,
783
            ),
784
            // @link https://github.com/futtta/autoptimize/commit/54385939db06f725fcafe68598cce6ed148ef6c1
785
            array(
786
                '<!doctype html>',
787
                true,
788
            ),
789
        );
790
    }
791
792
    /**
793
     * @dataProvider provider_is_amp_markup
794
     */
795
    public function test_autoptimize_is_amp_markup( $input, $expected )
796
    {
797
        $actual = autoptimizeMain::is_amp_markup( $input );
798
799
        $this->assertEquals( $expected, $actual );
800
    }
801
802
    public function provider_is_amp_markup()
803
    {
804
        return array(
805
            array(
806
                '<!doctype html>
807
<html ⚡>',
808
                true,
809
            ),
810
            array(
811
                '<!doctype html>
812
<html amp>',
813
                true,
814
            ),
815
            array(
816
                '<!doctype html>
817
<head>
818
<meta charset=utf-8>',
819
                false,
820
            ),
821
        );
822
    }
823
824
    /**
825
     * Test various conditions that can/should prevent autoptimize from buffering content.
826
     */
827 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...
828
    {
829
        // True => disable autoptimize.
830
        add_filter( 'autoptimize_filter_noptimize', '__return_true' );
831
832
        // Buffering should not run due to the above filter.
833
        $expected = false;
834
        $actual   = $this->ao->should_buffer( $doing_tests = true );
835
836
        $this->assertEquals( $expected, $actual );
837
    }
838
839 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...
840
    {
841
        // False => disable noptimize, aka, run normally (weird, yes...).
842
        add_filter( 'autoptimize_filter_noptimize', '__return_false' );
843
844
        // Buffering should run because of above.
845
        $expected = true;
846
        $actual   = $this->ao->should_buffer( $doing_tests = true );
847
848
        $this->assertEquals( $expected, $actual );
849
    }
850
851
    public function test_ignores_ao_noptimize_qs_when_instructed()
852
    {
853
        // Should skip checking for the qs completely due to filter.
854
        add_filter( 'autoptimize_filter_honor_qs_noptimize', '__return_false' );
855
856
        /**
857
         * The above should then result in the "current" value being `false`
858
         * when passed to 'autoptimize_filter_noptimize' unless the DONOTMINIFY
859
         * constant is defined, which changes the result... Which basically
860
         * means this test changes its' expected result depending on the order
861
         * of tests execution and/or the environment, which is AAAARGGGGGGHHH...
862
         */
863
864
        $that = $this; // Makes it work on php 5.3!
865
        add_filter( 'autoptimize_filter_noptimize', function ( $current_value ) use ( $that ) {
866
            $expected = false;
867
            if ( defined( 'DONOTMINIFY' ) && DONOTMINIFY ) {
868
                $expected = true;
869
            }
870
871
            $that->assertEquals( $expected, $current_value );
872
        });
873
874
        $this->ao->should_buffer( $doing_tests = true );
875
    }
876
877
    public function test_wpengine_cache_flush()
878
    {
879
        // Creating a mock so that we can get past class_exists() and method_exists() checks present
880
        // in `autoptimizeCache::flushPageCache()`...
881
        $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...
882
                ->disableOriginalConstructor()->setMethods(
883
                    array(
884
                        'purge_varnish_cache',
885
                    )
886
                )
887
                ->getMock();
888
889
        $that = $this;
890
        add_filter( 'autoptimize_flush_wpengine_methods', function( $methods ) use ( $that ) {
891
            $expected_methods = array( 'purge_varnish_cache' );
892
            $that->assertEquals( $methods, $expected_methods );
893
894
            return $methods;
895
        });
896
897
        autoptimizeCache::flushPageCache();
898
    }
899
900
    /**
901
     * Tests the `autoptimize_flush_wpengine_aggressive` filter
902
     */
903
    public function test_wpengine_cache_flush_agressive()
904
    {
905
        // Creating a mock so that we can get past class_exists() and method_exists() checks `autoptimize_flush_pagecache()`...
906
        $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...
907
                ->disableOriginalConstructor()->setMethods(
908
                    array(
909
                        'purge_varnish_cache',
910
                        'purge_memcached',
911
                        'clear_maxcdn_cache',
912
                    )
913
                )
914
                ->getMock();
915
916
        add_filter( 'autoptimize_flush_wpengine_aggressive', function() {
917
            return true;
918
        });
919
920
        $that = $this;
921
        add_filter( 'autoptimize_flush_wpengine_methods', function( $methods ) use ( $that ) {
922
            $expected_methods = array(
923
                'purge_varnish_cache',
924
                'purge_memcached',
925
                'clear_maxcdn_cache',
926
            );
927
928
            $that->assertEquals( $methods, $expected_methods );
929
930
            return $methods;
931
        });
932
933
        autoptimizeCache::flushPageCache();
934
    }
935
936
    /**
937
     * @dataProvider provider_test_url_replace_cdn
938
     */
939
    public function test_url_replace_cdn( $cdn_url, $input, $expected )
940
    {
941
        $mock = $this->getMockBuilder( 'autoptimizeBase' )
942
                ->disableOriginalConstructor()
943
                ->getMockForAbstractClass();
944
945
        $mock->cdn_url = $cdn_url;
946
        $actual        = $mock->url_replace_cdn( $input );
947
        $this->assertEquals( $expected, $actual );
948
    }
949
950
    public function provider_test_url_replace_cdn()
951
    {
952
        $urls                 = $this->get_urls();
953
        $siteurl              = $urls['siteurl'];
954
        $wwwsiteurl           = $urls['wwwsiteurl'];
955
        $protorelativesiteurl = $urls['prsiteurl'];
956
        $subfolder            = $urls['subfolder'];
957
958
        return array(
959
            // Host-relative links get properly transformed...
960
            array(
961
                // CDN base url, url, expected result...
962
                'http://cdn-test.example.org',
963
                '/a.jpg',
964
                'http://cdn-test.example.org/' . $subfolder . 'a.jpg',
965
            ),
966
            // Full link with a matching AUTOPTIMIZE_WP_SITE_URL gets properly replaced...
967
            array(
968
                'http://cdn-test.example.org',
969
                $siteurl . '/wp-content/themes/something/example.svg',
970
                'http://cdn-test.example.org/' . $subfolder . 'wp-content/themes/something/example.svg',
971
            ),
972
            // Protocol-relative url with a "local" hostname that doesn't match example.org (AUTOPTIMIZE_WP_SITE_URL)...
973
            array(
974
                'http://cdn-test.example.org',
975
                '//something/somewhere.jpg',
976
                '//something/somewhere.jpg',
977
            ),
978
            // www.example.org does not match example.org (AUTOPTIMIZE_WP_SITE_URL) so it's left alone...
979
            array(
980
                'http://cdn-test.example.org',
981
                $wwwsiteurl . '/wp-content/themes/something/example.svg',
982
                $wwwsiteurl . '/wp-content/themes/something/example.svg',
983
            ),
984
            // SSL cdn url + host-relative link...
985
            array(
986
                'https://cdn.example.org',
987
                '/a.jpg',
988
                'https://cdn.example.org/' . $subfolder . 'a.jpg',
989
            ),
990
            // SSL cdn url + http site url that matches AUTOPTIMIZE_WP_SITE_URL is properly replaced...
991
            array(
992
                'https://cdn.example.org',
993
                $siteurl . '/wp-content/themes/something/example.svg',
994
                'https://cdn.example.org/' . $subfolder . 'wp-content/themes/something/example.svg',
995
            ),
996
            // Protocol-relative cdn url given with protocol relative link that matches AUTOPTIMIZE_WP_SITE_URL host...
997
            array(
998
                '//cdn.example.org',
999
                $protorelativesiteurl . '/something.jpg',
1000
                '//cdn.example.org/' . $subfolder . 'something.jpg',
1001
            ),
1002
            // Protocol-relative cdn url given a http link that matches AUTOPTIMIZE_WP_SITE_URL host...
1003
            array(
1004
                '//cdn.example.org',
1005
                $siteurl . '/something.png',
1006
                '//cdn.example.org/' . $subfolder . 'something.png',
1007
            ),
1008
            // Protocol-relative cdn url with a host-relative link...
1009
            array(
1010
                '//cdn.example.org',
1011
                '/a.jpg',
1012
                '//cdn.example.org/' . $subfolder . 'a.jpg',
1013
            ),
1014
            // Testing cdn urls with an explicit port number...
1015
            array(
1016
                'http://cdn.com:8080',
1017
                '/a.jpg',
1018
                'http://cdn.com:8080/' . $subfolder . 'a.jpg',
1019
            ),
1020
            array(
1021
                '//cdn.com:4433',
1022
                '/a.jpg',
1023
                '//cdn.com:4433/' . $subfolder . 'a.jpg',
1024
            ),
1025
            array(
1026
                '//cdn.com:4433',
1027
                $siteurl . '/something.jpg',
1028
                '//cdn.com:4433/' . $subfolder . 'something.jpg',
1029
            ),
1030
            array(
1031
                '//cdn.com:1234',
1032
                $protorelativesiteurl . '/something.jpg',
1033
                '//cdn.com:1234/' . $subfolder . 'something.jpg',
1034
            ),
1035
            // Relative links should not be touched by url_replace_cdn()...
1036
            array(
1037
                // Base cdn url.
1038
                'http://cdn-test.example.org',
1039
                // Url.
1040
                'a.jpg',
1041
                // Expected result.
1042
                'a.jpg',
1043
            ),
1044
            array(
1045
                'http://cdn-test.example.org',
1046
                './a.jpg',
1047
                './a.jpg',
1048
            ),
1049
            array(
1050
                'http://cdn-test.example.org',
1051
                '../something/somewhere.svg',
1052
                '../something/somewhere.svg',
1053
            ),
1054
            // These prove some weird combinations pre-2.4 remain working
1055
            // even though they are really strange...
1056
            array(
1057
                $siteurl, // example.org or http://localhost or http://localhost/wordpress
1058
                $siteurl . '/something.jpg',
1059
                $siteurl . '/something.jpg',
1060
            ),
1061
            // These shouldn't really be changed, or even if replacements do
1062
            // happen, they shouldn't be destructive...
1063
            array(
1064
                'http://localhost/wp',
1065
                'http://localhost/wp/something.jpg',
1066
                'http://localhost/wp/something.jpg',
1067
            ),
1068
            array(
1069
                'http://localhost',
1070
                'http://localhost/something.jpg',
1071
                'http://localhost/something.jpg',
1072
            ),
1073
            array(
1074
                'http://localhost',
1075
                'http://localhost/wordpress/something.jpg',
1076
                'http://localhost/wordpress/something.jpg',
1077
            ),
1078
            array(
1079
                'http://localhost/wordpress',
1080
                'http://localhost/wordpress/something.jpg',
1081
                'http://localhost/wordpress/something.jpg',
1082
            ),
1083
        );
1084
    }
1085
1086
    /**
1087
     * Tests `autoptimize_filter_base_cdnurl` filtering as described here:
1088
     * https://wordpress.org/support/topic/disable-cdn-of-ssl-pages
1089
     */
1090
    public function test_autoptimize_filter_base_cdnurl()
1091
    {
1092
        $urls = $this->get_urls();
1093
        $sub  = $urls['subfolder'];
1094
1095
        $test_link = '/a.jpg';
1096
        $cdn_url   = '//cdn.example.org';
1097
1098
        $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...
1099
            return '';
1100
        };
1101
        $expected_with_ssl = '/a.jpg';
1102
1103
        $without_ssl = function( $cdn ) {
1104
            return $cdn;
1105
        };
1106
        $expected_without_ssl = '//cdn.example.org/' . $sub . 'a.jpg';
1107
1108
        // With a filter that returns something considered "empty", cdn replacement shouldn't occur...
1109
        add_filter( 'autoptimize_filter_base_cdnurl', $with_ssl );
1110
        $mock = $this->getMockBuilder( 'autoptimizeBase' )
1111
                ->disableOriginalConstructor()
1112
                ->getMockForAbstractClass();
1113
1114
        $mock->cdn_url   = $cdn_url;
1115
        $actual_with_ssl = $mock->url_replace_cdn( $test_link );
1116
        $this->assertEquals( $expected_with_ssl, $actual_with_ssl );
1117
        remove_filter( 'autoptimize_filter_base_cdnurl', $with_ssl );
1118
1119
        // With a filter that returns an actual cdn url, cdn replacement should occur.
1120
        add_filter( 'autoptimize_filter_base_cdnurl', $without_ssl );
1121
        $actual_without_ssl = $mock->url_replace_cdn( $test_link );
1122
        $this->assertEquals( $expected_without_ssl, $actual_without_ssl );
1123
    }
1124
1125
    public function provider_cssmin_issues()
1126
    {
1127
        return array(
1128
            // @link https://wordpress.org/support/topic/css-minify-breaks-calc-subtract-operation-in-css/?replies=2#post-6610027
1129
            array(
1130
                // Input.
1131
                'input { width: calc(33.33333% - ((0.75em*2)/3)); }',
1132
                // Expected output (ancient version of CSSmin returns 0.75, newer versions drop the 0).
1133
                'input{width:calc(33.33333% - ((.75em*2)/3))}',
1134
            ),
1135
            // Actual examples from above, but original wasn't really valid
1136
            // css input fully, but these tests used to work and we'd like to
1137
            // know if output changes with various CSSmin versions, for
1138
            // backcompat reasons if nothing else.
1139
            array(
1140
                // Input.
1141
                'width: calc(33.33333% - ((0.75em*2)/3));',
1142
                // Expected output.
1143
                'width:calc(33.33333% - ((0.75em*2)/3));',
1144
            ),
1145
            // @link https://github.com/tubalmartin/YUI-CSS-compressor-PHP-port/issues/22#issuecomment-251401341
1146
            array(
1147
                'input { width: calc(100% - (1em*1.5) - 2em); }',
1148
                'input{width:calc(100% - (1em*1.5) - 2em)}',
1149
            ),
1150
            // @link https://github.com/tubalmartin/YUI-CSS-compressor-PHP-port/issues/26
1151
            array(
1152
                '.px { flex: 1 1 0px; }, .percent {flex: 1 1 0%}',
1153
                '.px{flex:1 1 0px},.percent{flex:1 1 0%}',
1154
            ),
1155
        );
1156
    }
1157
1158
    /**
1159
     * @dataProvider provider_cssmin_issues
1160
     */
1161
    public function test_cssmin_issues( $input, $expected )
1162
    {
1163
        $minifier = new autoptimizeCSSmin( false ); // No need to raise limits for now.
1164
        $actual   = $minifier->run( $input );
1165
        $this->assertEquals( $expected, $actual );
1166
    }
1167
1168
    public function provider_getpath()
1169
    {
1170
        return array(
1171
            /**
1172
             * These all don't really exist, and getpath() returns false for
1173
             * non-existing files since upstream's 1386e4fe1d commit.
1174
             */
1175
            array(
1176
                'img/something.svg',
1177
                false,
1178
            ),
1179
            array(
1180
                '../../somewhere-else/svg.svg',
1181
                false,
1182
            ),
1183
            array(
1184
                '//something/somewhere/example.png',
1185
                false,
1186
            ),
1187
            // This file comes with core, so should exist...
1188
            array(
1189
                '/wp-includes/js/jquery/jquery.js',
1190
                WP_ROOT_DIR . '/wp-includes/js/jquery/jquery.js',
1191
            ),
1192
            // This file comes with core as of 5.6, so should exist...
1193
            array(
1194
                '/wp-includes/js/jquery/jquery.min.js',
1195
                WP_ROOT_DIR . '/wp-includes/js/jquery/jquery.min.js',
1196
            ),
1197
            // Empty $url should return false.
1198
            array(
1199
                '',
1200
                false,
1201
            ),
1202
            array(
1203
                false,
1204
                false,
1205
            ),
1206
            array(
1207
                null,
1208
                false,
1209
            ),
1210
            array(
1211
                0,
1212
                false,
1213
            ),
1214
        );
1215
    }
1216
1217
    /**
1218
     * @dataProvider provider_getpath
1219
     */
1220
    public function test_getpath( $input, $expected )
1221
    {
1222
        $mock = $this->getMockBuilder( 'autoptimizeBase' )->disableOriginalConstructor()->getMockForAbstractClass();
1223
1224
        $actual = $mock->getpath( $input );
1225
        $this->assertEquals( $expected, $actual );
1226
    }
1227
1228
    /**
1229
     * @link https://github.com/futtta/autoptimize/pull/81#issuecomment-278935307
1230
     */
1231
    public function test_fixurls_with_hash_only_urls()
1232
    {
1233
        $urls      = $this->get_urls();
1234
        $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...
1235
        $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...
1236
1237
        $protorelativesiteurl = $urls['prsiteurl'];
1238
1239
        $css_orig     = <<<CSS
1240
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")}
1241
section.clipped.clippedTop {clip-path:url("#clipPolygonTop")}
1242
section.clipped.clippedBottom {clip-path:url("#clipPolygonBottom")}
1243
.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");}
1244
CSS;
1245
        $css_expected = <<<CSS
1246
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")}
1247
section.clipped.clippedTop {clip-path:url("#clipPolygonTop")}
1248
section.clipped.clippedBottom {clip-path:url("#clipPolygonBottom")}
1249
.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);}
1250
CSS;
1251
1252
        $fixurls_result = autoptimizeStyles::fixurls( ABSPATH . 'wp-content/themes/my-theme/style.css', $css_orig );
1253
        $this->assertEquals( $css_expected, $fixurls_result );
1254
    }
1255
1256
    public function test_background_datauri_sprites_with_fixurls()
1257
    {
1258
        $css_orig     = <<<CSS
1259
.shadow { background:url(img/1x1.png) top center; }
1260
.shadow1 { background-image:url(img/1x1.png) 0 -767px repeat-x; }
1261
.shadow2 {background:url(img/1x1.png) top center}
1262
1263
.test { background:url(img/1x1.png) top center; }
1264
.test1 { background-image:url('img/1x1.png') 0 -767px repeat-x; }
1265
.test2 {background:url("img/1x1.png") top center}
1266
1267
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")}
1268
1269
/*
1270
section.clipped.clippedTop {clip-path:url("#clipPolygonTop")}
1271
section.clipped.clippedBottom {clip-path:url("#clipPolygonBottom")}
1272
.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");}
1273
.something {
1274
    background:url(http://example.org/wp-content/themes/my-theme/images/nothing.png);
1275
}
1276
.something-else {background:url(wp-content/themes/my-theme/images/shadow.png) -100px 0 repeat-y;}
1277
.another-thing { background:url(/wp-content/themes/my-theme/images/shadow.png) 0 -767px repeat-x; }
1278
#whatevz {background:url(wp-content/themes/my-theme/images/shadow.png) center top no-repeat;}
1279
1280
.widget ul li { background:url(img/shadow.png) top center; }
1281
*/
1282
CSS;
1283
        $css_expected = <<<CSS
1284
.shadow { background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=) top center; }
1285
.shadow1 { background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=) 0 -767px repeat-x; }
1286
.shadow2 {background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=) top center}
1287
1288
.test { background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=) top center; }
1289
.test1 { background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=) 0 -767px repeat-x; }
1290
.test2 {background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=) top center}
1291
1292
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")}
1293
1294
/*
1295
section.clipped.clippedTop {clip-path:url("#clipPolygonTop")}
1296
section.clipped.clippedBottom {clip-path:url("#clipPolygonBottom")}
1297
.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=);}
1298
.something {
1299
    background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=);
1300
}
1301
.something-else {background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=) -100px 0 repeat-y;}
1302
.another-thing { background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=) 0 -767px repeat-x; }
1303
#whatevz {background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=) center top no-repeat;}
1304
1305
.widget ul li { background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=) top center; }
1306
*/
1307
CSS;
1308
1309
        // For test purposes, ALL images in the css are being inline with a 1x1 trans png string/datauri.
1310
        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...
1311
            return true;
1312
        }, 10, 2 );
1313
1314
        // For test purposes, ALL images in the css are being inline with a 1x1 trans png string/datauri.
1315 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...
1316
            $head = 'data:image/png;base64,';
1317
            $data = 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=';
1318
1319
            $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...
1320
            $result['base64data'] = $data;
1321
            return $result;
1322
        }, 10, 2 );
1323
1324
        $instance = new autoptimizeStyles( $css_orig );
1325
        $instance->setOption( 'datauris', true );
1326
1327
        $fixurls_result = autoptimizeStyles::fixurls( ABSPATH . 'wp-content/themes/my-theme/style.css', $css_orig );
1328
        $css_actual     = $instance->rewrite_assets( $fixurls_result );
1329
1330
        $this->assertEquals( $css_expected, $css_actual );
1331
    }
1332
1333
    /**
1334
     * Doing rewrite_assets() without calling fixurls() beforehand could
1335
     * cause wrong results if/when there's a (same) image referenced via
1336
     * root-relative and relative urls, i.e.,
1337
     * `/wp-content/themes/my-theme/images/shadow.png` and
1338
     * `wp-content/themes/my-theme/images/shadow.png` in test code below.
1339
     * That's because urls are not really "normalized" in rewrite_assets() at
1340
     * all, and replacements are done using simple string keys (based on url),
1341
     * so whenever the shorter url ends up being spotted first, the replacement
1342
     * was done in a way that leaves the first `/` character in place.
1343
     * Which could mean trouble, especially when doing inlining of smaller
1344
     * images.
1345
     * After sorting the replacements array in rewrite_assets() by string
1346
     * length in descending order, the problem goes away.
1347
     */
1348
    public function test_background_datauri_sprites_without_fixurls()
1349
    {
1350
        $css_orig     = <<<CSS
1351
.shadow { background:url(img/1x1.png) top center; }
1352
.shadow1 { background-image:url(img/1x1.png) 0 -767px repeat-x; }
1353
.shadow2 {background:url(img/1x1.png) top center}
1354
1355
.test { background:url(img/1x1.png) top center; }
1356
.test1 { background-image:url('img/1x1.png') 0 -767px repeat-x; }
1357
.test2 {background:url("img/1x1.png") top center}
1358
1359
section.clipped.clippedTop {clip-path:url("#clipPolygonTop")}
1360
section.clipped.clippedBottom {clip-path:url("#clipPolygonBottom")}
1361
.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");}
1362
.something {
1363
    background:url(http://example.org/wp-content/themes/my-theme/images/nothing.png);
1364
}
1365
.something-else {background:url(wp-content/themes/my-theme/images/shadow.png) -100px 0 repeat-y;}
1366
.another-thing { background:url(/wp-content/themes/my-theme/images/shadow.png) 0 -767px repeat-x; }
1367
#whatevz {background:url(wp-content/themes/my-theme/images/shadow.png) center top no-repeat;}
1368
1369
.widget ul li { background:url(img/shadow.png) top center; }
1370
CSS;
1371
        $css_expected = <<<CSS
1372
.shadow { background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=) top center; }
1373
.shadow1 { background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=) 0 -767px repeat-x; }
1374
.shadow2 {background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=) top center}
1375
1376
.test { background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=) top center; }
1377
.test1 { background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=) 0 -767px repeat-x; }
1378
.test2 {background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=) top center}
1379
1380
section.clipped.clippedTop {clip-path:url("#clipPolygonTop")}
1381
section.clipped.clippedBottom {clip-path:url("#clipPolygonBottom")}
1382
.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=);}
1383
.something {
1384
    background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=);
1385
}
1386
.something-else {background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=) -100px 0 repeat-y;}
1387
.another-thing { background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=) 0 -767px repeat-x; }
1388
#whatevz {background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=) center top no-repeat;}
1389
1390
.widget ul li { background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=) top center; }
1391
CSS;
1392
1393
        // For test purposes, ALL images in the css are being inlined with a 1x1 trans png string/datauri.
1394
        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...
1395
            return true;
1396
        }, 10, 2 );
1397
1398
        // For test purposes, ALL images in the css are being inlined with a 1x1 trans png string/datauri.
1399 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...
1400
            $head = 'data:image/png;base64,';
1401
            $data = 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=';
1402
1403
            $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...
1404
            $result['base64data'] = $data;
1405
            return $result;
1406
        }, 10, 2 );
1407
1408
        $instance = new autoptimizeStyles( $css_orig );
1409
        $instance->setOption( 'datauris', true );
1410
        $css_actual = $instance->rewrite_assets( $css_orig );
1411
        $this->assertEquals( $css_expected, $css_actual );
1412
    }
1413
1414
    /**
1415
     * Test css with fonts pointed to the CDN + cdn_url option is set.
1416
     */
1417
    public function test_css_fonts_on_cdn_with_filter()
1418
    {
1419
        $urls    = $this->get_urls();
1420
        $siteurl = $urls['siteurl'];
1421
        $cdnurl  = $urls['cdnurl'];
1422
        $sub     = $urls['subfolder'];
1423
1424
        $css_in = <<<CSS
1425
/* these should not be touched except for quotes removal */
1426
@font-face {
1427
  font-family: 'Roboto';
1428
  font-style: normal;
1429
  font-weight: 100;
1430
  src: url('../fonts/roboto-v15-latin-ext_latin-100.eot'); /* IE9 Compat Modes */
1431
  src: local('Roboto Thin'), local('Roboto-Thin'),
1432
       url('../fonts/roboto-v15-latin-ext_latin-100.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
1433
       url('../fonts/roboto-v15-latin-ext_latin-100.woff2') format('woff2'), /* Super Modern Browsers */
1434
       url('../fonts/roboto-v15-latin-ext_latin-100.woff') format('woff'), /* Modern Browsers */
1435
       url('../fonts/roboto-v15-latin-ext_latin-100.ttf') format('truetype'), /* Safari, Android, iOS */
1436
       url('../fonts/roboto-v15-latin-ext_latin-100.svg#Roboto') format('svg'); /* Legacy iOS */
1437
}
1438
@font-face {
1439
  font-family: 'Roboto';
1440
  font-style: normal;
1441
  font-weight: 100;
1442
  src: url('//fonts/roboto-v15-latin-ext_latin-100.eot'); /* IE9 Compat Modes */
1443
  src: local('Roboto Thin'), local('Roboto-Thin'),
1444
       url('//fonts/roboto-v15-latin-ext_latin-100.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
1445
       url('//fonts/roboto-v15-latin-ext_latin-100.woff2') format('woff2'), /* Super Modern Browsers */
1446
       url('//fonts/roboto-v15-latin-ext_latin-100.woff') format('woff'), /* Modern Browsers */
1447
       url('//fonts/roboto-v15-latin-ext_latin-100.ttf') format('truetype'), /* Safari, Android, iOS */
1448
       url('//fonts/roboto-v15-latin-ext_latin-100.svg#Roboto') format('svg'); /* Legacy iOS */
1449
}
1450
/* these will be replaced and quotes gone */
1451
@font-face {
1452
  font-family: 'Roboto';
1453
  font-style: normal;
1454
  font-weight: 100;
1455
  src: url('/fonts/roboto-v15-latin-ext_latin-100.eot'); /* IE9 Compat Modes */
1456
  src: local('Roboto Thin'), local('Roboto-Thin'),
1457
       url('/fonts/roboto-v15-latin-ext_latin-100.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
1458
       url('/fonts/roboto-v15-latin-ext_latin-100.woff2') format('woff2'), /* Super Modern Browsers */
1459
       url('/fonts/roboto-v15-latin-ext_latin-100.woff') format('woff'), /* Modern Browsers */
1460
       url('/fonts/roboto-v15-latin-ext_latin-100.ttf') format('truetype'), /* Safari, Android, iOS */
1461
       url('/fonts/roboto-v15-latin-ext_latin-100.svg#Roboto') format('svg'); /* Legacy iOS */
1462
}
1463
@font-face {
1464
  font-family: 'Roboto';
1465
  font-style: normal;
1466
  font-weight: 100;
1467
  src: url('$siteurl/wp-content/themes/mytheme/fonts/roboto-v15-latin-ext_latin-100.eot'); /* IE9 Compat Modes */
1468
  src: local('Roboto Thin'), local('Roboto-Thin'),
1469
       url('$siteurl/wp-content/themes/mytheme/fonts/roboto-v15-latin-ext_latin-100.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
1470
       url('$siteurl/wp-content/themes/mytheme/fonts/roboto-v15-latin-ext_latin-100.woff2') format('woff2'), /* Super Modern Browsers */
1471
       url('$siteurl/wp-content/themes/mytheme/fonts/roboto-v15-latin-ext_latin-100.woff') format('woff'), /* Modern Browsers */
1472
       url('$siteurl/wp-content/themes/mytheme/fonts/roboto-v15-latin-ext_latin-100.ttf') format('truetype'), /* Safari, Android, iOS */
1473
       url('$siteurl/wp-content/themes/mytheme/fonts/roboto-v15-latin-ext_latin-100.svg#Roboto') format('svg'); /* Legacy iOS */
1474
}
1475
CSS;
1476
1477
        $css_expected_fonts_cdn = <<<CSS
1478
/* these should not be touched except for quotes removal */
1479
@font-face {
1480
  font-family: 'Roboto';
1481
  font-style: normal;
1482
  font-weight: 100;
1483
  src: url(../fonts/roboto-v15-latin-ext_latin-100.eot); /* IE9 Compat Modes */
1484
  src: local('Roboto Thin'), local('Roboto-Thin'),
1485
       url(../fonts/roboto-v15-latin-ext_latin-100.eot?#iefix) format('embedded-opentype'), /* IE6-IE8 */
1486
       url(../fonts/roboto-v15-latin-ext_latin-100.woff2) format('woff2'), /* Super Modern Browsers */
1487
       url(../fonts/roboto-v15-latin-ext_latin-100.woff) format('woff'), /* Modern Browsers */
1488
       url(../fonts/roboto-v15-latin-ext_latin-100.ttf) format('truetype'), /* Safari, Android, iOS */
1489
       url(../fonts/roboto-v15-latin-ext_latin-100.svg#Roboto) format('svg'); /* Legacy iOS */
1490
}
1491
@font-face {
1492
  font-family: 'Roboto';
1493
  font-style: normal;
1494
  font-weight: 100;
1495
  src: url(//fonts/roboto-v15-latin-ext_latin-100.eot); /* IE9 Compat Modes */
1496
  src: local('Roboto Thin'), local('Roboto-Thin'),
1497
       url(//fonts/roboto-v15-latin-ext_latin-100.eot?#iefix) format('embedded-opentype'), /* IE6-IE8 */
1498
       url(//fonts/roboto-v15-latin-ext_latin-100.woff2) format('woff2'), /* Super Modern Browsers */
1499
       url(//fonts/roboto-v15-latin-ext_latin-100.woff) format('woff'), /* Modern Browsers */
1500
       url(//fonts/roboto-v15-latin-ext_latin-100.ttf) format('truetype'), /* Safari, Android, iOS */
1501
       url(//fonts/roboto-v15-latin-ext_latin-100.svg#Roboto) format('svg'); /* Legacy iOS */
1502
}
1503
/* these will be replaced and quotes gone */
1504
@font-face {
1505
  font-family: 'Roboto';
1506
  font-style: normal;
1507
  font-weight: 100;
1508
  src: url(${cdnurl}/${sub}fonts/roboto-v15-latin-ext_latin-100.eot); /* IE9 Compat Modes */
1509
  src: local('Roboto Thin'), local('Roboto-Thin'),
1510
       url(${cdnurl}/${sub}fonts/roboto-v15-latin-ext_latin-100.eot?#iefix) format('embedded-opentype'), /* IE6-IE8 */
1511
       url(${cdnurl}/${sub}fonts/roboto-v15-latin-ext_latin-100.woff2) format('woff2'), /* Super Modern Browsers */
1512
       url(${cdnurl}/${sub}fonts/roboto-v15-latin-ext_latin-100.woff) format('woff'), /* Modern Browsers */
1513
       url(${cdnurl}/${sub}fonts/roboto-v15-latin-ext_latin-100.ttf) format('truetype'), /* Safari, Android, iOS */
1514
       url(${cdnurl}/${sub}fonts/roboto-v15-latin-ext_latin-100.svg#Roboto) format('svg'); /* Legacy iOS */
1515
}
1516
@font-face {
1517
  font-family: 'Roboto';
1518
  font-style: normal;
1519
  font-weight: 100;
1520
  src: url(${cdnurl}/${sub}wp-content/themes/mytheme/fonts/roboto-v15-latin-ext_latin-100.eot); /* IE9 Compat Modes */
1521
  src: local('Roboto Thin'), local('Roboto-Thin'),
1522
       url(${cdnurl}/${sub}wp-content/themes/mytheme/fonts/roboto-v15-latin-ext_latin-100.eot?#iefix) format('embedded-opentype'), /* IE6-IE8 */
1523
       url(${cdnurl}/${sub}wp-content/themes/mytheme/fonts/roboto-v15-latin-ext_latin-100.woff2) format('woff2'), /* Super Modern Browsers */
1524
       url(${cdnurl}/${sub}wp-content/themes/mytheme/fonts/roboto-v15-latin-ext_latin-100.woff) format('woff'), /* Modern Browsers */
1525
       url(${cdnurl}/${sub}wp-content/themes/mytheme/fonts/roboto-v15-latin-ext_latin-100.ttf) format('truetype'), /* Safari, Android, iOS */
1526
       url(${cdnurl}/${sub}wp-content/themes/mytheme/fonts/roboto-v15-latin-ext_latin-100.svg#Roboto) format('svg'); /* Legacy iOS */
1527
}
1528
CSS;
1529
1530
        // Test with fonts pointed to the CDN + cdn option is set.
1531
        add_filter( 'autoptimize_filter_css_fonts_cdn', '__return_true' );
1532
        $instance = new autoptimizeStyles( $css_in );
1533
        $instance->setOption( 'cdn_url', $cdnurl );
1534
        $css_actual_fonts_cdn = $instance->rewrite_assets( $css_in );
1535
1536
        $this->assertEquals( $css_expected_fonts_cdn, $css_actual_fonts_cdn );
1537
    }
1538
1539
    /**
1540
     * Test css fonts not moved to cdn by default even if cdn_url option is set.
1541
     */
1542
    public function test_css_fonts_skipped_by_default_even_when_cdn_is_set()
1543
    {
1544
        $urls      = $this->get_urls();
1545
        $siteurl   = $urls['siteurl'];
1546
        $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...
1547
1548
        $css_in = <<<CSS
1549
/* these should not be changed, not even quotes */
1550
@font-face {
1551
  font-family: 'Roboto';
1552
  font-style: normal;
1553
  font-weight: 100;
1554
  src: url('../fonts/roboto-v15-latin-ext_latin-100.eot'); /* IE9 Compat Modes */
1555
  src: local('Roboto Thin'), local('Roboto-Thin'),
1556
       url('../fonts/roboto-v15-latin-ext_latin-100.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
1557
       url('../fonts/roboto-v15-latin-ext_latin-100.woff2') format('woff2'), /* Super Modern Browsers */
1558
       url('../fonts/roboto-v15-latin-ext_latin-100.woff') format('woff'), /* Modern Browsers */
1559
       url('../fonts/roboto-v15-latin-ext_latin-100.ttf') format('truetype'), /* Safari, Android, iOS */
1560
       url('../fonts/roboto-v15-latin-ext_latin-100.svg#Roboto') format('svg'); /* Legacy iOS */
1561
}
1562
@font-face {
1563
  font-family: 'Roboto';
1564
  font-style: normal;
1565
  font-weight: 100;
1566
  src: url('//fonts/roboto-v15-latin-ext_latin-100.eot'); /* IE9 Compat Modes */
1567
  src: local('Roboto Thin'), local('Roboto-Thin'),
1568
       url('//fonts/roboto-v15-latin-ext_latin-100.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
1569
       url('//fonts/roboto-v15-latin-ext_latin-100.woff2') format('woff2'), /* Super Modern Browsers */
1570
       url('//fonts/roboto-v15-latin-ext_latin-100.woff') format('woff'), /* Modern Browsers */
1571
       url('//fonts/roboto-v15-latin-ext_latin-100.ttf') format('truetype'), /* Safari, Android, iOS */
1572
       url('//fonts/roboto-v15-latin-ext_latin-100.svg#Roboto') format('svg'); /* Legacy iOS */
1573
}
1574
@font-face {
1575
  font-family: 'Roboto';
1576
  font-style: normal;
1577
  font-weight: 100;
1578
  src: url('/fonts/roboto-v15-latin-ext_latin-100.eot'); /* IE9 Compat Modes */
1579
  src: local('Roboto Thin'), local('Roboto-Thin'),
1580
       url('/fonts/roboto-v15-latin-ext_latin-100.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
1581
       url('/fonts/roboto-v15-latin-ext_latin-100.woff2') format('woff2'), /* Super Modern Browsers */
1582
       url('/fonts/roboto-v15-latin-ext_latin-100.woff') format('woff'), /* Modern Browsers */
1583
       url('/fonts/roboto-v15-latin-ext_latin-100.ttf') format('truetype'), /* Safari, Android, iOS */
1584
       url('/fonts/roboto-v15-latin-ext_latin-100.svg#Roboto') format('svg'); /* Legacy iOS */
1585
}
1586
@font-face {
1587
  font-family: 'Roboto';
1588
  font-style: normal;
1589
  font-weight: 100;
1590
  src: url('$siteurl/wp-content/themes/mytheme/fonts/roboto-v15-latin-ext_latin-100.eot'); /* IE9 Compat Modes */
1591
  src: local('Roboto Thin'), local('Roboto-Thin'),
1592
       url('$siteurl/wp-content/themes/mytheme/fonts/roboto-v15-latin-ext_latin-100.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
1593
       url('$siteurl/wp-content/themes/mytheme/fonts/roboto-v15-latin-ext_latin-100.woff2') format('woff2'), /* Super Modern Browsers */
1594
       url('$siteurl/wp-content/themes/mytheme/fonts/roboto-v15-latin-ext_latin-100.woff') format('woff'), /* Modern Browsers */
1595
       url('$siteurl/wp-content/themes/mytheme/fonts/roboto-v15-latin-ext_latin-100.ttf') format('truetype'), /* Safari, Android, iOS */
1596
       url('$siteurl/wp-content/themes/mytheme/fonts/roboto-v15-latin-ext_latin-100.svg#Roboto') format('svg'); /* Legacy iOS */
1597
}
1598
CSS;
1599
        // Expected without cdning fonts but cdn option is set.
1600
        $css_expected = <<<CSS
1601
/* these should not be changed, not even quotes */
1602
@font-face {
1603
  font-family: 'Roboto';
1604
  font-style: normal;
1605
  font-weight: 100;
1606
  src: url('../fonts/roboto-v15-latin-ext_latin-100.eot'); /* IE9 Compat Modes */
1607
  src: local('Roboto Thin'), local('Roboto-Thin'),
1608
       url('../fonts/roboto-v15-latin-ext_latin-100.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
1609
       url('../fonts/roboto-v15-latin-ext_latin-100.woff2') format('woff2'), /* Super Modern Browsers */
1610
       url('../fonts/roboto-v15-latin-ext_latin-100.woff') format('woff'), /* Modern Browsers */
1611
       url('../fonts/roboto-v15-latin-ext_latin-100.ttf') format('truetype'), /* Safari, Android, iOS */
1612
       url('../fonts/roboto-v15-latin-ext_latin-100.svg#Roboto') format('svg'); /* Legacy iOS */
1613
}
1614
@font-face {
1615
  font-family: 'Roboto';
1616
  font-style: normal;
1617
  font-weight: 100;
1618
  src: url('//fonts/roboto-v15-latin-ext_latin-100.eot'); /* IE9 Compat Modes */
1619
  src: local('Roboto Thin'), local('Roboto-Thin'),
1620
       url('//fonts/roboto-v15-latin-ext_latin-100.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
1621
       url('//fonts/roboto-v15-latin-ext_latin-100.woff2') format('woff2'), /* Super Modern Browsers */
1622
       url('//fonts/roboto-v15-latin-ext_latin-100.woff') format('woff'), /* Modern Browsers */
1623
       url('//fonts/roboto-v15-latin-ext_latin-100.ttf') format('truetype'), /* Safari, Android, iOS */
1624
       url('//fonts/roboto-v15-latin-ext_latin-100.svg#Roboto') format('svg'); /* Legacy iOS */
1625
}
1626
@font-face {
1627
  font-family: 'Roboto';
1628
  font-style: normal;
1629
  font-weight: 100;
1630
  src: url('/fonts/roboto-v15-latin-ext_latin-100.eot'); /* IE9 Compat Modes */
1631
  src: local('Roboto Thin'), local('Roboto-Thin'),
1632
       url('/fonts/roboto-v15-latin-ext_latin-100.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
1633
       url('/fonts/roboto-v15-latin-ext_latin-100.woff2') format('woff2'), /* Super Modern Browsers */
1634
       url('/fonts/roboto-v15-latin-ext_latin-100.woff') format('woff'), /* Modern Browsers */
1635
       url('/fonts/roboto-v15-latin-ext_latin-100.ttf') format('truetype'), /* Safari, Android, iOS */
1636
       url('/fonts/roboto-v15-latin-ext_latin-100.svg#Roboto') format('svg'); /* Legacy iOS */
1637
}
1638
@font-face {
1639
  font-family: 'Roboto';
1640
  font-style: normal;
1641
  font-weight: 100;
1642
  src: url('$siteurl/wp-content/themes/mytheme/fonts/roboto-v15-latin-ext_latin-100.eot'); /* IE9 Compat Modes */
1643
  src: local('Roboto Thin'), local('Roboto-Thin'),
1644
       url('$siteurl/wp-content/themes/mytheme/fonts/roboto-v15-latin-ext_latin-100.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
1645
       url('$siteurl/wp-content/themes/mytheme/fonts/roboto-v15-latin-ext_latin-100.woff2') format('woff2'), /* Super Modern Browsers */
1646
       url('$siteurl/wp-content/themes/mytheme/fonts/roboto-v15-latin-ext_latin-100.woff') format('woff'), /* Modern Browsers */
1647
       url('$siteurl/wp-content/themes/mytheme/fonts/roboto-v15-latin-ext_latin-100.ttf') format('truetype'), /* Safari, Android, iOS */
1648
       url('$siteurl/wp-content/themes/mytheme/fonts/roboto-v15-latin-ext_latin-100.svg#Roboto') format('svg'); /* Legacy iOS */
1649
}
1650
CSS;
1651
        // Test without moving fonts to CDN, but cdn option is set.
1652
        $instance = new autoptimizeStyles( $css_in );
1653
        $instance->setOption( 'cdn_url', $urls['cdnurl'] );
1654
        $css_actual = $instance->rewrite_assets( $css_in );
1655
        $this->assertEquals( $css_expected, $css_actual );
1656
    }
1657
1658
    public function test_assets_regex_replaces_multi_bg_images()
1659
    {
1660
        $urls   = $this->get_urls();
1661
        $sub    = $urls['subfolder'];
1662
        $cdnurl = $urls['cdnurl'];
1663
1664
        $in = <<<CSS
1665
body:after {
1666
  content: url(/img/close.png) url(/img/loading.gif) url(/img/prev.png) url(/img/next.png);
1667
}
1668
CSS;
1669
1670
        $expected = <<<CSS
1671
body:after {
1672
  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);
1673
}
1674
CSS;
1675
1676
        $instance = new autoptimizeStyles( $in );
1677
        $instance->setOption( 'cdn_url', $cdnurl );
1678
        $actual = $instance->rewrite_assets( $in );
1679
1680
        $this->assertEquals( $expected, $actual );
1681
    }
1682
1683
    public function test_at_supports_spacing_issue_110()
1684
    {
1685
        $in       = <<<CSS
1686
@supports (-webkit-filter: blur(3px)) or (filter: blur(3px)) {
1687
    .blur {
1688
        filter:blur(3px);
1689
    }
1690
}
1691
@supports((position:-webkit-sticky) or (position:sticky)) {
1692
    .sticky { position:sticky; }
1693
}
1694
CSS;
1695
        $expected = <<<CSS
1696
@supports (-webkit-filter:blur(3px)) or (filter:blur(3px)){.blur{filter:blur(3px)}}@supports((position:-webkit-sticky) or (position:sticky)){.sticky{position:sticky}}
1697
CSS;
1698
1699
        $instance = new autoptimizeStyles( $in );
1700
        $actual   = $instance->run_minifier_on( $in );
1701
1702
        $this->assertEquals( $expected, $actual );
1703
    }
1704
1705 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...
1706
    {
1707
        $urls   = $this->get_urls();
1708
        $sub    = $urls['subfolder'];
1709
        $cdnurl = $urls['cdnurl'];
1710
1711
        $in = <<<HTML
1712
<style type="text/css">
1713
@import url("foo.css?a&#038;b");
1714
@import url("bar.css");
1715
</style>
1716
HTML;
1717
1718
        $expected = '<style 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-->';
1719
1720
        $options = [
1721
            'autoptimizeStyles' => $this->getAoStylesDefaultOptions(),
1722
        ];
1723
1724
        $instance = new autoptimizeStyles( $in );
1725
        $instance->read( $options['autoptimizeStyles'] );
1726
        $instance->minify();
1727
        $instance->cache();
1728
        $actual = $instance->getcontent();
1729
        $this->assertEquals( $expected, $actual );
1730
    }
1731
1732
    public function test_fixurls_with_at_imports_and_media_queries()
1733
    {
1734
        $urls      = $this->get_urls();
1735
        $prsiteurl = $urls['prsiteurl'];
1736
        $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...
1737
1738
        $in  = '@import "foo.css"; @import "bar.css" (orientation:landscape);';
1739
        $exp = '@import url(' . $prsiteurl . '/wp-content/themes/my-theme/foo.css); @import url(' . $prsiteurl . '/wp-content/themes/my-theme/bar.css) (orientation:landscape);';
1740
1741
        $actual = autoptimizeStyles::fixurls( ABSPATH . 'wp-content/themes/my-theme/style.css', $in );
1742
        $this->assertEquals( $exp, $actual );
1743
    }
1744
1745 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...
1746
    {
1747
        $urls   = $this->get_urls();
1748
        $sub    = $urls['subfolder'];
1749
        $cdnurl = $urls['cdnurl'];
1750
1751
        $in = <<<HTML
1752
<style type="text/css">
1753
@import "foo.css"; @import "bar.css" (orientation:landscape);
1754
</style>
1755
HTML;
1756
1757
        $expected = '<style 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-->';
1758
1759
        $options = [
1760
            'autoptimizeStyles' => $this->getAoStylesDefaultOptions(),
1761
        ];
1762
1763
        $instance = new autoptimizeStyles( $in );
1764
        $instance->read( $options['autoptimizeStyles'] );
1765
        $instance->minify();
1766
        $instance->cache();
1767
1768
        $actual = $instance->getcontent();
1769
        $this->assertEquals( $expected, $actual );
1770
    }
1771
1772
    public function test_cache_size_checker_hooked_by_default()
1773
    {
1774
        $this->assertNotEmpty( autoptimizeCacheChecker::SCHEDULE_HOOK );
1775
1776
        // No schedule, because it's only added when is_admin() is true.
1777
        $this->assertEquals( false, wp_get_schedule( autoptimizeCacheChecker::SCHEDULE_HOOK ) );
1778
1779
        // Proving that setup() sets the schedule as needed.
1780
        $checker = new autoptimizeCacheChecker();
1781
        $checker->setup();
1782
        $this->assertEquals( 'twicedaily', wp_get_schedule( autoptimizeCacheChecker::SCHEDULE_HOOK ) );
1783
    }
1784
1785
    public function test_cache_size_checker_disabled_with_filter()
1786
    {
1787
        add_filter( 'autoptimize_filter_cachecheck_do', '__return_false' );
1788
1789
        $checker = new autoptimizeCacheChecker();
1790
        $checker->setup();
1791
        $this->assertEquals( false, wp_get_schedule( autoptimizeCacheChecker::SCHEDULE_HOOK ) );
1792
1793
        remove_all_filters( 'autoptimize_filter_cachecheck_do' );
1794
    }
1795
1796
    public function test_is_start_buffering_hooked_properly()
1797
    {
1798
        $instance = autoptimize();
1799
1800
        /**
1801
         * TODO/FIXME: ideally, we'd test all possible setups, but once we set
1802
         * a constant, there's no going back, unless we use runkit or somesuch:
1803
         * https://www.theaveragedev.com/mocking-constants-in-tests/.
1804
         */
1805
1806
        if ( defined( 'AUTOPTIMIZE_INIT_EARLIER' ) ) {
1807
            $this->assertEquals(
1808
                autoptimizeMain::INIT_EARLIER_PRIORITY,
1809
                has_action( 'init', array( $instance, 'start_buffering' ) )
1810
            );
1811
            $this->assertTrue( ! defined( 'AUTOPTIMIZE_HOOK_INTO' ) );
1812
        }
1813
1814
        /*
1815
        // AUTOPTIMIZE_HOOK_INTO only exists if AUTOPTIMIZE_INIT_EARLIER doesnt
1816
        $this->assertEquals(
1817
            autoptimizeMain::DEFAULT_HOOK_PRIORITY,
1818
            has_action( constant( 'AUTOPTIMIZE_HOOK_INTO' ), array( $instance, 'start_buffering' ) )
1819
        );
1820
        $this->assertFalse(
1821
            has_action( 'init', array( $instance, 'start_buffering' ) )
1822
        );
1823
        */
1824
    }
1825
1826
    public function test_inline_and_defer_markup()
1827
    {
1828
        add_filter( 'autoptimize_filter_css_defer', '__return_true' );
1829
        add_filter( 'autoptimize_filter_css_defer_inline', '__return_true' );
1830
1831
        $actual = $this->ao->end_buffering( $this->get_test_markup() );
1832
        if ( is_multisite() ) {
1833
            $this->assertEquals( $this->get_test_markup_output_inline_defer_ms(), $actual );
1834
        } else {
1835
            $this->assertEquals( $this->get_test_markup_output_inline_defer(), $actual );
1836
        }
1837
1838
        remove_all_filters( 'autoptimize_filter_css_defer' );
1839
        remove_all_filters( 'autoptimize_filter_css_defer_inline' );
1840
    }
1841
1842 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...
1843
    {
1844
        $opts = $this->getAoScriptsDefaultOptions();
1845
1846
        // Aggregating: true by default.
1847
        $scripts = new autoptimizeScripts( '' );
1848
        $scripts->read( $opts );
1849
        $this->assertTrue( $scripts->aggregating() );
1850
1851
        // Aggregating: option=true (dontaggregate=false by default).
1852
        $opts['aggregate'] = true;
1853
        $scripts           = new autoptimizeScripts( '' );
1854
        $scripts->read( $opts );
1855
        $this->assertTrue( $scripts->aggregating() );
1856
1857
        // Aggregating: option=true, dontaggregate=false explicit.
1858
        $opts['aggregate'] = true;
1859
        add_filter( 'autoptimize_filter_js_dontaggregate', '__return_false' );
1860
        $scripts = new autoptimizeScripts( '' );
1861
        $scripts->read( $opts );
1862
        $this->assertTrue( $scripts->aggregating() );
1863
        remove_all_filters( 'autoptimize_filter_js_dontaggregate' );
1864
1865
        // Not aggregating: option=true, dontaggregate=true.
1866
        $opts['aggregate'] = true;
1867
        add_filter( 'autoptimize_filter_js_dontaggregate', '__return_true' );
1868
        $scripts = new autoptimizeScripts( '' );
1869
        $scripts->read( $opts );
1870
        $this->assertFalse( $scripts->aggregating() );
1871
        remove_all_filters( 'autoptimize_filter_js_dontaggregate' );
1872
1873
        // Not aggregating: option=false, dontaggregate=false.
1874
        $opts['aggregate'] = false;
1875
        add_filter( 'autoptimize_filter_js_dontaggregate', '__return_false' );
1876
        $scripts = new autoptimizeScripts( '' );
1877
        $scripts->read( $opts );
1878
        $this->assertFalse( $scripts->aggregating() );
1879
        remove_all_filters( 'autoptimize_filter_js_dontaggregate' );
1880
1881
        // Not aggregating: option=false, dontaggregate=true.
1882
        $opts['aggregate'] = false;
1883
        add_filter( 'autoptimize_filter_js_dontaggregate', '__return_true' );
1884
        $scripts = new autoptimizeScripts( '' );
1885
        $scripts->read( $opts );
1886
        $this->assertFalse( $scripts->aggregating() );
1887
        remove_all_filters( 'autoptimize_filter_js_dontaggregate' );
1888
    }
1889
1890 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...
1891
    {
1892
        $opts = $this->getAoStylesDefaultOptions();
1893
1894
        // Aggregating: true by default.
1895
        $styles = new autoptimizeStyles( '' );
1896
        $this->assertTrue( $styles->aggregating() );
1897
1898
        // Aggregating: option=true (dontaggregate=false by default).
1899
        $opts['aggregate'] = true;
1900
        $styles            = new autoptimizeStyles( '' );
1901
        $styles->read( $opts );
1902
        $this->assertTrue( $styles->aggregating() );
1903
1904
        // Aggregating: option=true, dontaggregate=false explicit.
1905
        $opts['aggregate'] = true;
1906
        add_filter( 'autoptimize_filter_css_dontaggregate', '__return_false' );
1907
        $styles = new autoptimizeStyles( '' );
1908
        $styles->read( $opts );
1909
        $this->assertTrue( $styles->aggregating() );
1910
        remove_all_filters( 'autoptimize_filter_css_dontaggregate' );
1911
1912
        // Not aggregating: option=true, dontaggregate=true.
1913
        $opts['aggregate'] = true;
1914
        add_filter( 'autoptimize_filter_css_dontaggregate', '__return_true' );
1915
        $styles = new autoptimizeStyles( '' );
1916
        $styles->read( $opts );
1917
        $this->assertFalse( $styles->aggregating() );
1918
        remove_all_filters( 'autoptimize_filter_css_dontaggregate' );
1919
1920
        // Not aggregating: option=false, dontaggregate=false.
1921
        $opts['aggregate'] = false;
1922
        add_filter( 'autoptimize_filter_css_dontaggregate', '__return_false' );
1923
        $styles = new autoptimizeStyles( '' );
1924
        $styles->read( $opts );
1925
        $this->assertFalse( $styles->aggregating() );
1926
        remove_all_filters( 'autoptimize_filter_css_dontaggregate' );
1927
1928
        // Not aggregating: option=false, dontaggregate=true.
1929
        $opts['aggregate'] = false;
1930
        add_filter( 'autoptimize_filter_css_dontaggregate', '__return_true' );
1931
        $styles = new autoptimizeStyles( '' );
1932
        $styles->read( $opts );
1933
        $this->assertFalse( $styles->aggregating() );
1934
        remove_all_filters( 'autoptimize_filter_css_dontaggregate' );
1935
    }
1936
1937
    public function test_css_minify_single_with_cdning()
1938
    {
1939
        $pathname = dirname( __FILE__ ) . '/fixtures/minify-single.css';
1940
        $opts     = $this->getAoStylesDefaultOptions();
1941
        $styles   = new autoptimizeStyles( '' );
1942
        $styles->read( $opts );
1943
1944
        $url = $styles->minify_single( $pathname, $cache_miss = true );
1945
1946
        // Minified url filename + its pointed to cdn.
1947
        $this->assertContains( AUTOPTIMIZE_CACHE_CHILD_DIR, $url );
1948
        $this->assertContains( '/autoptimize_single_', $url );
1949
        $this->assertContains( $styles->cdn_url, $url );
1950
1951
        // Actual minified css contents are minified and cdn-ed.
1952
        $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 1944 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...
1953
        $contents = file_get_contents( $path );
1954
        $this->assertContains( $styles->cdn_url, $contents );
1955
        $this->assertContains( '.bg{background:url(' . $styles->cdn_url, $contents );
1956
    }
1957
1958
    public function test_ao_partners_instantiation_without_explicit_include()
1959
    {
1960
        $partners = new autoptimizePartners();
1961
        $this->assertTrue( $partners instanceof autoptimizePartners );
1962
    }
1963
1964 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...
1965
    {
1966
        $markup   = <<<MARKUP
1967
<script>
1968
<!-- End Support AJAX add to cart -->
1969
var a = "b";
1970
</script>
1971
MARKUP;
1972
        $expected = <<<MARKUP
1973
<script><!-- End Support AJAX add to cart -->
1974
var a = "b";</script>
1975
MARKUP;
1976
1977
        $markup2 = <<<MARKUP
1978
<script>
1979
var a = "b";
1980
<!-- End Support AJAX add to cart -->
1981
</script>
1982
MARKUP;
1983
1984
        $expected2 = <<<MARKUP
1985
<script>var a = "b";
1986
<!-- End Support AJAX add to cart --></script>
1987
MARKUP;
1988
1989
        // When keepcomments is true.
1990
        $options = [
1991
            'autoptimizeHTML' => [
1992
                'keepcomments' => true,
1993
            ],
1994
        ];
1995
1996
        $instance = new autoptimizeHTML( $markup );
1997
        $instance->read( $options['autoptimizeHTML'] );
1998
        $instance->minify();
1999
        $actual = $instance->getcontent();
2000
        $this->assertEquals( $expected, $actual );
2001
2002
        $instance = new autoptimizeHTML( $markup2 );
2003
        $instance->read( $options['autoptimizeHTML'] );
2004
        $instance->minify();
2005
        $actual2 = $instance->getcontent();
2006
        $this->assertEquals( $expected2, $actual2 );
2007
    }
2008
2009 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...
2010
    {
2011
        // Default case, html comments removed (keepcomments = false).
2012
        $markup1   = <<<MARKUP
2013
<script>
2014
var a = "b";
2015
<!-- End Support AJAX add to cart -->
2016
</script>
2017
MARKUP;
2018
        $expected1 = <<<MARKUP
2019
<script>var a = "b";
2020
<!-- End Support AJAX add to cart</script>
2021
MARKUP;
2022
2023
        $markup2   = <<<MARKUP
2024
<script>
2025
<!-- End Support AJAX add to cart -->
2026
var a = "b";
2027
</script>
2028
MARKUP;
2029
        $expected2 = <<<MARKUP
2030
<script>End Support AJAX add to cart -->
2031
var a = "b";</script>
2032
MARKUP;
2033
2034
        $options = [
2035
            'autoptimizeHTML' => [
2036
                'keepcomments' => false,
2037
            ],
2038
        ];
2039
2040
        $instance = new autoptimizeHTML( $markup1 );
2041
        $instance->read( $options['autoptimizeHTML'] );
2042
        $instance->minify();
2043
        $actual = $instance->getcontent();
2044
        $this->assertEquals( $expected1, $actual );
2045
2046
        $instance = new autoptimizeHTML( $markup2 );
2047
        $instance->read( $options['autoptimizeHTML'] );
2048
        $instance->minify();
2049
        $actual2 = $instance->getcontent();
2050
        $this->assertEquals( $expected2, $actual2 );
2051
    }
2052
2053 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...
2054
    {
2055
        $markup = <<<MARKUP
2056
<script>
2057
<!-- // invisible for old browsers
2058
var a = "z";
2059
// -->
2060
</script>
2061
MARKUP;
2062
2063
        $expected = <<<MARKUP
2064
<script>// invisible for old browsers
2065
var a = "z";</script>
2066
MARKUP;
2067
2068
        $options = [
2069
            'autoptimizeHTML' => [
2070
                'keepcomments' => false,
2071
            ],
2072
        ];
2073
2074
        $instance = new autoptimizeHTML( $markup );
2075
        $instance->read( $options['autoptimizeHTML'] );
2076
        $instance->minify();
2077
        $actual = $instance->getcontent();
2078
        $this->assertEquals( $expected, $actual );
2079
    }
2080
2081 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...
2082
    {
2083
        $markup = <<<MARKUP
2084
<script>
2085
<!-- // invisible for old browsers
2086
var a = "z";
2087
// -->
2088
</script>
2089
MARKUP;
2090
2091
        $expected = <<<MARKUP
2092
<script><!-- // invisible for old browsers
2093
var a = "z";
2094
// --></script>
2095
MARKUP;
2096
2097
        $options = [
2098
            'autoptimizeHTML' => [
2099
                'keepcomments' => true,
2100
            ],
2101
        ];
2102
2103
        $instance = new autoptimizeHTML( $markup );
2104
        $instance->read( $options['autoptimizeHTML'] );
2105
        $instance->minify();
2106
        $actual = $instance->getcontent();
2107
        $this->assertEquals( $expected, $actual );
2108
    }
2109
2110
    public function test_utils_mbstring_availabilty_overriding()
2111
    {
2112
        $orig     = autoptimizeUtils::mbstring_available();
2113
        $opposite = ! $orig;
2114
2115
        $this->assertSame( $orig, autoptimizeUtils::mbstring_available() );
2116
        // Override works...
2117
        $this->assertSame( $opposite, autoptimizeUtils::mbstring_available( $opposite ) );
2118
        // And override remains cached as the last version.
2119
        $this->assertSame( $opposite, autoptimizeUtils::mbstring_available() );
2120
    }
2121
2122
    public function test_utils_mbstring_basics()
2123
    {
2124
        // Turn on mbstring usage.
2125
        autoptimizeUtils::mbstring_available( true );
2126
2127
        $this->assertSame( 2, autoptimizeUtils::strlen( "\x00\xFF", 'ASCII' ) );
2128
        $this->assertSame( 2, autoptimizeUtils::strlen( "\x00\xFF", 'CP850' ) );
2129
        $this->assertSame( 3, autoptimizeUtils::strlen( '한국어' ) );
2130
2131
        $this->assertFalse( @autoptimizeUtils::strpos( 'abc', '' ) );
2132
        $this->assertFalse( @autoptimizeUtils::strpos( 'abc', 'a', -1 ) );
2133
        $this->assertFalse( autoptimizeUtils::strpos( 'abc', 'd' ) );
2134
        $this->assertFalse( autoptimizeUtils::strpos( 'abc', 'a', 3 ) );
2135
        $this->assertSame( 1, autoptimizeUtils::strpos( '한국어', '국' ) );
2136
    }
2137
2138
    /**
2139
     * @dataProvider provider_utils_substr_replace
2140
     */
2141
    function test_utils_substr_replace_basics_mbstring( $s, $repl, $start, $len, $expected )
2142
    {
2143
        // Force mbstring code path...
2144
        autoptimizeUtils::mbstring_available( true );
2145
        $this->assertEquals( $expected, autoptimizeUtils::substr_replace( $s, $repl, $start, $len ) );
2146
    }
2147
2148
    public function provider_utils_substr_replace()
2149
    {
2150
        $str  = 'try this';
2151
        $repl = 'bala ';
2152
2153
        return [
2154
            [
2155
                $str,
2156
                $repl,
2157
                2,
2158
                null,
2159
                'trbala ',
2160
            ],
2161
            [
2162
                $str,
2163
                $repl,
2164
                2,
2165
                3,
2166
                'trbala his',
2167
            ],
2168
            [
2169
                $str,
2170
                $repl,
2171
                2,
2172
                0,
2173
                'trbala y this',
2174
            ],
2175
            [
2176
                $str,
2177
                $repl,
2178
                2,
2179
                -2,
2180
                'trbala is',
2181
            ],
2182
        ];
2183
    }
2184
2185 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...
2186
    {
2187
        autoptimizeUtils::mbstring_available( false );
2188
2189
        $str = 'Ascii';
2190
2191
        $this->assertSame( 'Añ', autoptimizeUtils::substr_replace( $str, 'ñ', 1 ) );
2192
        $this->assertSame( 'ñcii', autoptimizeUtils::substr_replace( $str, 'ñ', 0, 2 ) );
2193
        $this->assertSame( 'Asñx', autoptimizeUtils::substr_replace( $str, 'ñx', 2, 3 ) );
2194
        $this->assertSame( 'Asz', autoptimizeUtils::substr_replace( $str, 'z', 2, 10 ) );
2195
        $this->assertSame( 'Añii', autoptimizeUtils::substr_replace( $str, 'ñ', 1, 2 ) );
2196
    }
2197
2198 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...
2199
    {
2200
        autoptimizeUtils::mbstring_available( true );
2201
2202
        $str = 'âønæë';
2203
2204
        $this->assertSame( 'âñ', autoptimizeUtils::substr_replace( $str, 'ñ', 1 ) ); // No length.
2205
        $this->assertSame( 'ñnæë', autoptimizeUtils::substr_replace( $str, 'ñ', 0, 2 ) );
2206
        $this->assertSame( 'âøñx', autoptimizeUtils::substr_replace( $str, 'ñx', 2, 3 ) );
2207
        $this->assertSame( 'âøz', autoptimizeUtils::substr_replace( $str, 'z', 2, 10 ) ); // Length larger than possible...
2208
        $this->assertSame( 'âñæë', autoptimizeUtils::substr_replace( $str, 'ñ', 1, 2 ) );
2209
    }
2210
2211 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...
2212
    {
2213
        // Disable mbstring which should fall ack to substr_replace...
2214
        autoptimizeUtils::mbstring_available( false );
2215
2216
        $str = 'Ascii';
2217
2218
        $this->assertSame( 'Añ', autoptimizeUtils::substr_replace( $str, 'ñ', 1 ) );
2219
        $this->assertSame( 'ñcii', autoptimizeUtils::substr_replace( $str, 'ñ', 0, 2 ) );
2220
        $this->assertSame( 'Asñx', autoptimizeUtils::substr_replace( $str, 'ñx', 2, 3 ) );
2221
        $this->assertSame( 'Asz', autoptimizeUtils::substr_replace( $str, 'z', 2, 10 ) );
2222
        $this->assertSame( 'Añii', autoptimizeUtils::substr_replace( $str, 'ñ', 1, 2 ) );
2223
    }
2224
2225
    function test_default_substr_replace_with_utf8_input_string()
2226
    {
2227
        // Disabling mbstring, falling back to substr_replace...
2228
        autoptimizeUtils::mbstring_available( false );
2229
2230
        // This is really impossible to make work properly, since
2231
        // any start/len parameters we give are working with bytes instead
2232
        // of characters, shit just breaks.
2233
        $str = 'âønæë';
2234
2235
        // $this->assertSame( '�ñ', autoptimizeUtils::substr_replace( $str, 'ñ', 1 ) ); // No length.
2236
        // $this->assertSame( 'ñ�næë', autoptimizeUtils::substr_replace( $str, 'ñ', 1, 2 ) );
2237
        $this->assertSame( 'ñønæë', autoptimizeUtils::substr_replace( $str, 'ñ', 0, 2 ) );
2238
        $this->assertSame( 'âñxæë', autoptimizeUtils::substr_replace( $str, 'ñx', 2, 3 ) );
2239
        $this->assertSame( 'âz', autoptimizeUtils::substr_replace( $str, 'z', 2, 10 ) ); // Length larger than possible...
2240
    }
2241
2242
    public function test_cache_fast_delete()
2243
    {
2244
        add_filter( 'autoptimize_filter_cache_clear_advanced', '__return_true' );
2245
2246
        $this->assertTrue( autoptimizeCache::clearall_actionless() );
2247
2248
        remove_all_filters( 'autoptimize_filter_cache_clear_advanced' );
2249
    }
2250
2251
    public function test_delete_advanced_cache_clear_artifacts()
2252
    {
2253
        add_filter( 'autoptimize_filter_cache_clear_advanced', '__return_true' );
2254
2255
        $this->assertTrue( autoptimizeCache::delete_advanced_cache_clear_artifacts() );
2256
2257
        remove_all_filters( 'autoptimize_filter_cache_clear_advanced' );
2258
    }
2259
2260
    public function provider_canonicalization()
2261
    {
2262
        return array(
2263
            array( '../common', 'common' ),
2264
            array( '../what-does-this-mean/really?/', 'what-does-this-mean/really?/' ),
2265
            array( '../../what/where/how', 'what/where/how' ),
2266
            array( '/../more.dots.please/', '/more.dots.please/' ),
2267
            array( '/../../what/where/how', '/what/where/how' ),
2268
            array( '/a/b/c/../../../d/e/file.txt', '/d/e/file.txt' ),
2269
            array( 'a/b/../c', 'a/c' ),
2270
            array( './../../etc/passwd', './etc/passwd' ),
2271
            array( '/var/.////./user/./././..//.//../////../././.././test/////', '/test/' ),
2272
            array( '/var/user/./././.././../.././././test/', '/test/' ),
2273
            array( '/hello/0//how/../are/../you', '/hello/0/you' ),
2274
            array( '', '' ),
2275
            array( '.', '.' ),
2276
            array( '..', '..' ),
2277
            array( './..', './..' ),
2278
            array( '../.', '.' ),
2279
            // This might be debatable...
2280
            array( '../..', '..' ),
2281
        );
2282
    }
2283
2284
    /**
2285
     * @dataProvider provider_canonicalization
2286
     */
2287
    public function test_path_canonicalize( $path, $canonicalized )
2288
    {
2289
        $this->assertSame( $canonicalized, autoptimizeUtils::path_canonicalize( $path ) );
2290
    }
2291
2292
    /**
2293
     * For a site in subfolder, CDN-rewrite used to magically include
2294
     * the subfolder when rewriting assets to CDN.
2295
     * That behavior can be turned off by returning false via
2296
     * `autoptimize_filter_cdn_magic_path_check`.
2297
     * If it's false, cdn-rewriting should not include subfolder even
2298
     * when the site is actually in a subfolder/subdirectory.
2299
     */
2300
    public function test_autoptimize_filter_cdn_magic_path_check()
2301
    {
2302
        $cdnurl = 'http://cdn.example.org';
2303
        add_filter( 'autoptimize_filter_cdn_magic_path_check', '__return_false', 10, 2 );
2304
2305
        // Even when site is in a subfolder, the resulting cdn-rewritten url
2306
        // should not magically include it, due to the above filter.
2307
        // The second parameter is here to force a cache miss and re-run
2308
        // the filter since we're using the same cdn url all over the place,
2309
        // but want to prove different things with it.
2310
        $this->assertSame( $cdnurl, autoptimizeUtils::tweak_cdn_url_if_needed( $cdnurl, true ) );
2311
2312
        remove_all_filters( 'autoptimize_filter_cdn_magic_path_check' );
2313
    }
2314
2315
    /**
2316
     * Test image optimization in autoptimizeImages.php.
2317
     *
2318
     * Default case: img with srcsets
2319
     */
2320
    public function test_imgopt()
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'] = '0';
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
<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" />
2335
MARKUP;
2336
        $instance = autoptimizeImages::instance();
2337
        $instance->set_options( $opts );
2338
        $actual = $instance->filter_optimize_images( $markup );
2339
        $this->assertEquals( $expected, $actual );
2340
    }
2341
    
2342
    /**
2343
     * Test image optimization in autoptimizeImages.php with one excluded image.
2344
     *
2345
     * Default case: img with srcsets
2346
     */
2347 View Code Duplication
    public function test_imgopt_exclusion()
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...
2348
    {
2349
        $urls                                        = $this->get_urls();
2350
        $siteurl                                     = $urls['siteurl'];
2351
        $imgopthost                                  = $urls['imgopthost'];
2352
        $opts                                        = autoptimizeImages::fetch_options();
2353
        $opts['autoptimize_imgopt_checkbox_field_1'] = '1';
2354
        $opts['autoptimize_imgopt_checkbox_field_3'] = '0';
2355
        $opts['autoptimize_imgopt_text_field_6']     = 'excluded.jpg';
2356
2357
        $markup = <<<MARKUP
2358
<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" />
2359
<img src='$siteurl/wp-content/excluded.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" />
2360
MARKUP;
2361
2362
        $expected = <<<MARKUP
2363
<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" />
2364
<img src='$siteurl/wp-content/excluded.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" />
2365
MARKUP;
2366
        $instance = autoptimizeImages::instance();
2367
        $instance->set_options( $opts );
2368
        $actual = $instance->filter_optimize_images( $markup, true );
2369
        $this->assertEquals( $expected, $actual );
2370
    }
2371
2372
    /**
2373
     * Test image optimization in autoptimizeImages.php.
2374
     *
2375
     * case: picture tag
2376
     */
2377 View Code Duplication
    public function test_imgopt_picture()
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...
2378
    {
2379
        $urls                                        = $this->get_urls();
2380
        $siteurl                                     = $urls['siteurl'];
2381
        $imgopthost                                  = $urls['imgopthost'];
2382
        $opts                                        = autoptimizeImages::fetch_options();
2383
        $opts['autoptimize_imgopt_checkbox_field_1'] = '1';
2384
        $opts['autoptimize_imgopt_checkbox_field_3'] = '0';
2385
2386
        $markup = <<<MARKUP
2387
<picture><source srcset="$siteurl/wp-content/image.jpg" media="(min-width: 800px)"><img src="$siteurl/wp-content/image.jpg"/></picture>
2388
MARKUP;
2389
2390
        $expected = <<<MARKUP
2391
<picture><source srcset="$imgopthost/client/q_glossy,ret_img/$siteurl/wp-content/image.jpg" media="(min-width: 800px)"><img src="$imgopthost/client/q_glossy,ret_img/$siteurl/wp-content/image.jpg"/></picture>
2392
MARKUP;
2393
        $instance = autoptimizeImages::instance();
2394
        $instance->set_options( $opts );
2395
        $actual = $instance->filter_optimize_images( $markup );
2396
        $this->assertEquals( $expected, $actual );
2397
    }
2398
2399
    /**
2400
     * Test image optimization & lazyload in autoptimizeImages.php.
2401
     *
2402
     * case: picture tag
2403
     */
2404
    public function test_imgopt_lazyload_picture()
2405
    {
2406
        $urls                                        = $this->get_urls();
2407
        $siteurl                                     = $urls['siteurl'];
2408
        $imgopthost                                  = $urls['imgopthost'];
2409
        $opts                                        = autoptimizeImages::fetch_options();
2410
        $opts['autoptimize_imgopt_checkbox_field_1'] = '1';
2411
        $opts['autoptimize_imgopt_checkbox_field_3'] = '1';
2412
2413
        $markup = <<<MARKUP
2414
<picture><source srcset="$siteurl/wp-content/image.jpg" media="(min-width: 800px)"><img src="$siteurl/wp-content/image.jpg"/></picture>
2415
MARKUP;
2416
2417
        $expected = <<<MARKUP
2418
<picture><source data-srcset="$imgopthost/client/q_glossy,ret_img/$siteurl/wp-content/image.jpg" media="(min-width: 800px)"><noscript><img src="$imgopthost/client/q_glossy,ret_img/$siteurl/wp-content/image.jpg"/></noscript><img class="lazyload" src='$imgopthost/client/q_lqip,ret_wait/$siteurl/wp-content/image.jpg' data-src="$imgopthost/client/q_glossy,ret_img/$siteurl/wp-content/image.jpg"/></picture>
2419
MARKUP;
2420
        $instance = autoptimizeImages::instance();
2421
        $instance->set_options( $opts );
2422
        $actual = $instance->filter_optimize_images( $markup );
2423
        $this->assertEquals( $expected, $actual );
2424
    }
2425
2426
    /**
2427
     * Test image optimization in autoptimizeImages.php.
2428
     *
2429
     * case: img with srcsets and lazyload
2430
     */
2431 View Code Duplication
    public function test_imgopt_with_lazyload()
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...
2432
    {
2433
        $urls                                        = $this->get_urls();
2434
        $siteurl                                     = $urls['siteurl'];
2435
        $imgopthost                                  = $urls['imgopthost'];
2436
        $opts                                        = autoptimizeImages::fetch_options();
2437
        $opts['autoptimize_imgopt_checkbox_field_1'] = '1';
2438
        $opts['autoptimize_imgopt_checkbox_field_3'] = '1';
2439
2440
        $markup = <<<MARKUP
2441
<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" />
2442
MARKUP;
2443
2444
        $expected = <<<MARKUP
2445
<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" data-sizes="(max-width: 300px) 100vw, 300px" />
2446
MARKUP;
2447
2448
        $instance = autoptimizeImages::instance();
2449
        $instance->set_options( $opts );
2450
        $actual = $instance->filter_optimize_images( $markup );
2451
        $this->assertEquals( $expected, $actual );
2452
    }
2453
2454
    /**
2455
     * Test image optimization in autoptimizeImages.php.
2456
     *
2457
     * case: background image in a style attribute
2458
     */
2459 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...
2460
    {
2461
        $urls                                        = $this->get_urls();
2462
        $siteurl                                     = $urls['siteurl'];
2463
        $imgopthost                                  = $urls['imgopthost'];
2464
        $opts                                        = autoptimizeImages::fetch_options();
2465
        $opts['autoptimize_imgopt_checkbox_field_1'] = '1';
2466
        $opts['autoptimize_imgopt_checkbox_field_3'] = '0';
2467
2468
        $markup = <<<MARKUP
2469
<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>
2470
MARKUP;
2471
2472
        $expected = <<<MARKUP
2473
<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>
2474
MARKUP;
2475
2476
        $instance = autoptimizeImages::instance();
2477
        $instance->set_options( $opts );
2478
        $actual = $instance->filter_optimize_images( $markup );
2479
        $this->assertEquals( $expected, $actual );
2480
    }
2481
2482
    /**
2483
     * Test lazyloading in autoptimizeImages.php.
2484
     *
2485
     * case: no image optimization
2486
     */
2487
    public function test_lazyload()
2488
    {
2489
        $urls                                        = $this->get_urls();
2490
        $siteurl                                     = $urls['siteurl'];
2491
        $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...
2492
        $opts                                        = autoptimizeImages::fetch_options();
2493
        $opts['autoptimize_imgopt_checkbox_field_3'] = '1';
2494
2495
        $markup = <<<MARKUP
2496
<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" />
2497
MARKUP;
2498
2499
        $expected = <<<MARKUP
2500
<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" data-sizes="(max-width: 300px) 100vw, 300px" />
2501
MARKUP;
2502
2503
        $instance = autoptimizeImages::instance();
2504
        $instance->set_options( $opts );
2505
        $actual = $instance->filter_lazyload_images( $markup );
2506
        $this->assertEquals( $expected, $actual );
2507
    }
2508
2509
    /**
2510
     * Test lazyload in autoptimizeImages.php.
2511
     *
2512
     * case: picture tag
2513
     */
2514 View Code Duplication
    public function test_picture_lazyload()
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...
2515
    {
2516
        $urls                                        = $this->get_urls();
2517
        $siteurl                                     = $urls['siteurl'];
2518
        $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...
2519
        $opts                                        = autoptimizeImages::fetch_options();
2520
        $opts['autoptimize_imgopt_checkbox_field_3'] = '1';
2521
2522
        $markup = <<<MARKUP
2523
<picture><source srcset="$siteurl/wp-content/image.jpg" media="(min-width: 800px)"><img src="$siteurl/wp-content/image.jpg"/></picture>
2524
MARKUP;
2525
2526
        $expected = <<<MARKUP
2527
<picture><source data-srcset="$siteurl/wp-content/image.jpg" media="(min-width: 800px)"><noscript><img src="$siteurl/wp-content/image.jpg"/></noscript><img class="lazyload" src='data:image/svg+xml,%3Csvg%20xmlns=%22http://www.w3.org/2000/svg%22%20viewBox=%220%200%20210%20140%22%3E%3C/svg%3E' data-src="$siteurl/wp-content/image.jpg"/></picture>
2528
MARKUP;
2529
2530
        $instance = autoptimizeImages::instance();
2531
        $instance->set_options( $opts );
2532
        $actual = $instance->filter_lazyload_images( $markup );
2533
        $this->assertEquals( $expected, $actual );
2534
    }
2535
2536
    /**
2537
     * Test lazyload in autoptimizeImages.php.
2538
     *
2539
     * case: picture tag
2540
     */
2541
    public function test_bgimg_lazyload()
2542
    {
2543
        $urls                                        = $this->get_urls();
2544
        $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...
2545
        $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...
2546
        $opts                                        = autoptimizeImages::fetch_options();
2547
        $opts['autoptimize_imgopt_checkbox_field_3'] = '1';
2548
2549
        $markup = <<<MARKUP
2550
<div id="just-an-id" style="height:250px;background-image: url(/wp-content/uploads/2018/05/DSC_1615-300x201.jpg);" class="hero background-image"></div>
2551
MARKUP;
2552
2553
        $expected = <<<MARKUP
2554
<div id="just-an-id" data-bg="/wp-content/uploads/2018/05/DSC_1615-300x201.jpg" style="height:250px;background-image: url(data:image/svg+xml,%3Csvg%20xmlns=%22http://www.w3.org/2000/svg%22%20viewBox=%220%200%20500%20300%22%3E%3C/svg%3E);" class="lazyload hero background-image"></div>
2555
MARKUP;
2556
2557
        $instance = autoptimizeImages::instance();
2558
        $instance->set_options( $opts );
2559
        $actual = $instance->filter_lazyload_images( $markup );
2560
        $this->assertEquals( $expected, $actual );
2561
    }
2562
2563
    /**
2564
     * Test image optimization in autoptimizeImages.php.
2565
     *
2566
     * Exception case: image served by .php, should not be proxied.
2567
     */
2568 View Code Duplication
    public function test_imgopt_php()
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...
2569
    {
2570
        $opts                                        = autoptimizeImages::fetch_options();
2571
        $opts['autoptimize_imgopt_checkbox_field_1'] = '1';
2572
        $opts['autoptimize_imgopt_checkbox_field_3'] = '0';
2573
2574
        $markup = <<<MARKUP
2575
<img src='/wp-content/plugins/imageplugin/image.php?id=16' width='400' height='200'>
2576
MARKUP;
2577
2578
        $instance = autoptimizeImages::instance();
2579
        $instance->set_options( $opts );
2580
        $actual = $instance->filter_optimize_images( $markup );
2581
2582
        // Expecting $markup since replacement should not happen.
2583
        $this->assertEquals( $markup, $actual );
2584
    }
2585
2586
    /**
2587
     * Test image optimization in autoptimizeImages.php.
2588
     *
2589
     * Alternate case: lazy loaded images with srcsets (using wp rocket variant HTML)
2590
     */
2591
    public function test_imgopt_alreadylazied()
2592
    {
2593
        $urls                                        = $this->get_urls();
2594
        $siteurl                                     = $urls['siteurl'];
2595
        $imgopthost                                  = $urls['imgopthost'];
2596
        $opts                                        = autoptimizeImages::fetch_options();
2597
        $opts['autoptimize_imgopt_checkbox_field_1'] = '1';
2598
        $opts['autoptimize_imgopt_checkbox_field_3'] = '0';
2599
2600
        $markup = <<<MARKUP
2601
<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" />
2602
MARKUP;
2603
2604
        $expected = <<<MARKUP
2605
<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" />
2606
MARKUP;
2607
2608
        $instance = autoptimizeImages::instance();
2609
        $instance->set_options( $opts );
2610
        $actual = $instance->filter_optimize_images( $markup );
2611
2612
        $this->assertEquals( $expected, $actual );
2613
    }
2614
2615
    /**
2616
     * Test image optimization when image urls have no explict host provided.
2617
     */
2618
    public function test_imgopt_url_normalize_root_relative()
2619
    {
2620
        $urls                                        = $this->get_urls();
2621
        $siteurl                                     = $urls['siteurl'];
2622
        $siteurlparsed                               = parse_url( $siteurl );
2623
        $sitedomain                                  = $siteurlparsed['scheme'] . '://' . $siteurlparsed['host'];
2624
        $imgopthost                                  = $urls['imgopthost'];
2625
        $opts                                        = autoptimizeImages::fetch_options();
2626
        $opts['autoptimize_imgopt_checkbox_field_1'] = '1';
2627
        $opts['autoptimize_imgopt_checkbox_field_3'] = '0';
2628
2629
        $markup = <<<MARKUP
2630
<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" />
2631
MARKUP;
2632
2633
        $expected = <<<MARKUP
2634
<img src='$imgopthost/client/q_glossy,ret_img,w_400,h_200/$sitedomain/wp-content/image.jpg' width='400' height='200' srcset="$imgopthost/client/q_glossy,ret_img,w_300/$sitedomain/wp-content/image-300X150.jpg 300w, $imgopthost/client/q_glossy,ret_img,w_600/$sitedomain/wp-content/image-600X300.jpg 600w" sizes="(max-width: 300px) 100vw, 300px" />
2635
MARKUP;
2636
2637
        $instance = autoptimizeImages::instance();
2638
        $instance->set_options( $opts );
2639
        $actual = $instance->filter_optimize_images( $markup );
2640
2641
        $this->assertEquals( $expected, $actual );
2642
    }
2643
2644
    /**
2645
     * Test image optimization when image urls have a protocol-relative url.
2646
     */
2647
    public function test_imgopt_url_normalize_protocol_relative()
2648
    {
2649
        $urls                                        = $this->get_urls();
2650
        $siteurl                                     = $urls['siteurl'];
2651
        $prsiteurl                                   = $urls['prsiteurl'];
2652
        $imgopthost                                  = $urls['imgopthost'];
2653
        $opts                                        = autoptimizeImages::fetch_options();
2654
        $opts['autoptimize_imgopt_checkbox_field_1'] = '1';
2655
        $opts['autoptimize_imgopt_checkbox_field_3'] = '0';
2656
2657
        $markup = <<<MARKUP
2658
<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" />
2659
MARKUP;
2660
2661
        $expected = <<<MARKUP
2662
<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" />
2663
MARKUP;
2664
2665
        $instance = autoptimizeImages::instance();
2666
        $instance->set_options( $opts );
2667
        $actual = $instance->filter_optimize_images( $markup );
2668
2669
        $this->assertEquals( $expected, $actual );
2670
    }
2671
2672
    /**
2673
     * @dataProvider provider_str_is_valid_regex
2674
     */
2675
    public function test_str_is_valid_regex( $str, $expected )
2676
    {
2677
        $actual = autoptimizeUtils::str_is_valid_regex( $str );
2678
2679
        $this->assertEquals( $expected, $actual );
2680
    }
2681
2682
    public function provider_str_is_valid_regex()
2683
    {
2684
        return [
2685
            [ '<!--[if', false ],
2686
            [ '&lt;--[if', false ],
2687
            [ '/booya/i', true ],
2688
            [ '~Valid(Regular)Expression~', true ],
2689
        ];
2690
    }
2691
2692
    /**
2693
     * @dataProvider provider_protocol_relative_tests
2694
     */
2695
    public function test_is_protocol_relative( $str, $expected )
2696
    {
2697
        $actual = autoptimizeUtils::is_protocol_relative( $str );
2698
2699
        $this->assertEquals( $expected, $actual );
2700
    }
2701
2702
    public function provider_protocol_relative_tests()
2703
    {
2704
        return [
2705
            [ '//something-that-might-be-an-url-but-isnt-really', true ],
2706
            [ '', false ],
2707
            [ null, false ],
2708
            [ 'booya/i', false ],
2709
            [ '/root-relative', false ],
2710
            [ 'http://what.ever/', false ],
2711
            [ 'https://booya.kasha', false ],
2712
            [ '1/', false ],
2713
        ];
2714
    }
2715
2716 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...
2717
    {
2718
        $css = <<<MARKUP
2719
img.centered, .aligncenter {
2720
    -webkit-box-shadow: none;
2721
    -moz-box-shadow: none;
2722
    box-shadow: none;
2723
MARKUP;
2724
2725
        $expected = 'img.centered,.aligncenter{-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}';
2726
2727
        $instance = new autoptimizeStyles( $css );
2728
        $minified = $instance->run_minifier_on( $css );
2729
2730
        $this->assertEquals( $expected, $minified );
2731
    }
2732
2733
    public function test_css_font_names_mangling()
2734
    {
2735
        // Properly quoted font names dont get mangled.
2736
        $css      = 'h2{font-family:"Archivo Black"}';
2737
        $instance = new autoptimizeStyles( $css );
2738
        $actual   = $instance->run_minifier_on( $css );
2739
        $this->assertEquals( $css, $actual );
2740
2741
        // When not quoted, 'Black' used to become '#000', but not anymore :) ...
2742
        $css_unquoted = 'h2{font-family:Archivo Black;}';
2743
        $expected     = 'h2{font-family:Archivo Black}';
2744
        $instance     = new autoptimizeStyles( $css_unquoted );
2745
        $actual       = $instance->run_minifier_on( $css_unquoted );
2746
        $this->assertEquals( $expected, $actual );
2747
2748
        $css_unquoted = 'h1{font:italic 1.2em Fira White,serif}';
2749
        $instance     = new autoptimizeStyles( $css_unquoted );
2750
        $actual       = $instance->run_minifier_on( $css_unquoted );
2751
        $this->assertEquals( $css_unquoted, $actual );
2752
    }
2753
2754
    public function test_is_plugin_active_utils_wrapper()
2755
    {
2756
        // Our plugin is loaded via "muplugins_loaded" filter in tests/bootstrap.php.
2757
        $this->assertFalse( autoptimizeUtils::is_plugin_active( 'autoptimize/autoptimize.php' ) );
2758
        $this->assertFalse( autoptimizeUtils::is_plugin_active( 'async-javascript/async-javascript.php' ) );
2759
    }
2760
2761
    public function test_jsminphp_string_literal_minification()
2762
    {
2763
        $js = '
2764
// comment
2765
`line
2766
break` + `he  llo`; foo`hel( \'\');lo`; `he\nl\`lo`; (`he${one + two}`)
2767
';
2768
2769
        $expected = '`line
2770
break`+`he  llo`;foo`hel( \'\');lo`;`he\nl\`lo`;(`he${one + two}`)';
2771
2772
        $actual = JSMin::minify( $js );
2773
        $this->assertEquals( $expected, $actual );
2774
    }
2775
2776
    /**
2777
     * Test preloading of resources (e.g. fonts).
2778
     */
2779 View Code Duplication
    public function test_preload()
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...
2780
    {
2781
        $opts                                   = autoptimizeExtra::fetch_options();
2782
        $opts['autoptimize_extra_text_field_7'] = 'https://whatever.com/fonts/openfuttta.woff2, https://whatever.com/css/openfuttta.css';
2783
2784
        $markup = <<<MARKUP
2785
<html><link rel="stylesheet" href="xyz.css">
2786
MARKUP;
2787
2788
        $expected = <<<MARKUP
2789
<html><link rel="preload" href="https://whatever.com/fonts/openfuttta.woff2" as="font" type="font/woff2" crossorigin><link rel="preload" href="https://whatever.com/css/openfuttta.css" as="style"><link rel="stylesheet" href="xyz.css">
2790
MARKUP;
2791
2792
        $instance = autoptimizeExtra::instance();
2793
        $instance->set_options( $opts );
2794
        $actual = $instance->filter_preload( $markup );
2795
        $this->assertEquals( $expected, $actual );
2796
    }
2797
2798
    /**
2799
     * Test preloading of resources (e.g. fonts).
2800
     */
2801 View Code Duplication
    public function test_preload_withqs()
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...
2802
    {
2803
        $opts                                   = autoptimizeExtra::fetch_options();
2804
        $opts['autoptimize_extra_text_field_7'] = 'https://whatever.com/fonts/openfuttta.woff2?123#abc, https://whatever.com/css/openfuttta.css?v=124';
2805
2806
        $markup = <<<MARKUP
2807
<html><link rel="stylesheet" href="xyz.css">
2808
MARKUP;
2809
2810
        $expected = <<<MARKUP
2811
<html><link rel="preload" href="https://whatever.com/fonts/openfuttta.woff2?123#abc" as="font" type="font/woff2" crossorigin><link rel="preload" href="https://whatever.com/css/openfuttta.css?v=124" as="style"><link rel="stylesheet" href="xyz.css">
2812
MARKUP;
2813
2814
        $instance = autoptimizeExtra::instance();
2815
        $instance->set_options( $opts );
2816
        $actual = $instance->filter_preload( $markup );
2817
        $this->assertEquals( $expected, $actual );
2818
    }
2819
2820
    /**
2821
     * Test aggregating Google Fonts.
2822
     */
2823 View Code Duplication
    public function test_google_font_aggregate_preload()
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...
2824
    {
2825
        $opts                                    = autoptimizeExtra::fetch_options();
2826
        $opts['autoptimize_extra_radio_field_4'] = '5';
2827
2828
        $markup = <<<MARKUP
2829
<link href='//fonts.googleapis.com/css?family=Open+Sans:300italic,400italic,600italic,400,300,600&subset=latin,cyrillic-ext,greek-ext,greek,vietnamese,latin-ext,cyrillic' rel='stylesheet' type='text/css'><link rel='stylesheet' type='text/css' href='https://fonts.googleapis.com/css2?family=Crimson+Pro:ital,wght@0,700;1,400'><link rel="dummy">
2830
MARKUP;
2831
2832
        $expected = <<<MARKUP
2833
<link rel="stylesheet" media="print" onload="this.onload=null;this.media='all';" id="ao_optimized_gfonts" href="https://fonts.googleapis.com/css?family=Open+Sans:300italic,400italic,600italic,400,300,600%7CCrimson+Pro:700,italic400&#038;subset=latin%2Ccyrillic-ext%2Cgreek-ext%2Cgreek%2Cvietnamese%2Clatin-ext%2Ccyrillic&amp;display=swap" /><link rel="dummy">
2834
MARKUP;
2835
2836
        $instance = autoptimizeExtra::instance();
2837
        $instance->set_options( $opts );
2838
        $actual = $instance->filter_optimize_google_fonts( $markup );
2839
        $this->assertEquals( $expected, $actual );
2840
    }
2841
2842
    /**
2843
     * Test network vs site settings: network only.
2844
     */
2845 View Code Duplication
    public function test_network_no_site_settings()
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...
2846
    {
2847
        if ( is_multisite() ) {
2848
            define( 'TEST_MULTISITE_FORCE_AO_ON_NETWORK', true );
2849
            // set options through WordPress core methods.
2850
            update_option( 'autoptimize_js_exclude', 'site' );
2851
            update_network_option( get_main_network_id(), 'autoptimize_js_exclude', 'network' );
2852
            update_network_option( get_main_network_id(), 'autoptimize_enable_site_config', '' );
2853
2854
            // and then try fetching them through optionwrapper.
2855
            $expected = 'network';
2856
            $actual   = autoptimizeOptionWrapper::get_option( 'autoptimize_js_exclude' );
2857
            $this->assertEquals( $expected, $actual );
2858
        } else {
2859
            $this->assertEquals( 1, 1 ); // just to ensure this isn't marked as a risky test.
2860
        }
2861
    }
2862
2863
    /**
2864
     * Test network vs site settings; per site.
2865
     */
2866 View Code Duplication
    public function test_network_per_site_settings()
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...
2867
    {
2868
        if ( is_multisite() ) {
2869
            // define of TEST_MULTISITE_FORCE_AO_ON_NETWORK not needed, done in previous test.
2870
            // set options through WordPress core methods.
2871
            update_option( 'autoptimize_js_exclude', 'site' );
2872
            update_network_option( get_main_network_id(), 'autoptimize_js_exclude', 'network' );
2873
            update_network_option( get_main_network_id(), 'autoptimize_enable_site_config', 'on' );
2874
2875
            // and then try fetching them through optionwrapper.
2876
            $expected = 'site';
2877
            $actual   = autoptimizeOptionWrapper::get_option( 'autoptimize_js_exclude' );
2878
            $this->assertEquals( $expected, $actual );
2879
        } else {
2880
            $this->assertEquals( 1, 1 ); // just to ensure this isn't marked as a risky test.
2881
        }
2882
    }
2883
}
2884