Completed
Push — master ( 30a2f1...b54c71 )
by frank
47:02 queued 29:26
created

test_jsminphp_string_literal_minification()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 0
dl 0
loc 14
rs 9.7998
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
        ];
42
    }
43
44
    protected function getAoScriptsDefaultOptions()
45
    {
46
        $conf = autoptimizeConfig::instance();
47
48
        return [
49
            'aggregate'      => $conf->get( 'autoptimize_js_aggregate' ),
50
            'justhead'       => $conf->get( 'autoptimize_js_justhead' ),
51
            'forcehead'      => $conf->get( 'autoptimize_js_forcehead' ),
52
            'trycatch'       => $conf->get( 'autoptimize_js_trycatch' ),
53
            'js_exclude'     => $conf->get( 'autoptimize_js_exclude' ),
54
            'cdn_url'        => $conf->get( 'autoptimize_cdn_url' ),
55
            'include_inline' => $conf->get( 'autoptimize_js_include_inline' ),
56
        ];
57
    }
58
59
    /**
60
     * @return array
61
     */
62
    protected function get_urls()
63
    {
64
        static $site_url = null;
65
        if ( null === $site_url ) {
66
            $site_url = site_url();
67
        }
68
69
        static $cdn_url = null;
70
        if ( null === $cdn_url ) {
71
            $cdn_url = get_option( 'autoptimize_cdn_url' );
72
        }
73
74
        static $imgopt_host = null;
75
        if ( null === $imgopt_host ) {
76
            $imgopt_host = rtrim( autoptimizeExtra::get_imgopt_host_wrapper(), '/' );
77
        }
78
79
        static $urls = [];
80
81
        if ( empty( $urls ) ) {
82
            $parts = autoptimizeUtils::get_ao_wp_site_url_parts();
83
            $urls  = [
84
                'siteurl'    => $site_url,
85
                'prsiteurl'  => '//' . str_replace( array( 'http://', 'https://' ), '', $site_url ),
86
                'wwwsiteurl' => $parts['scheme'] . '://www.' . str_replace( 'www.', '', $parts['host'] ),
87
                'cdnurl'     => $cdn_url,
88
                'imgopthost' => $imgopt_host,
89
                'subfolder'  => '',
90
            ];
91
92
            if ( AO_TEST_SUBFOLDER_INSTALL ) {
93
                $urls['subfolder'] = 'wordpress/';
94
            }
95
        }
96
97
        return $urls;
98
    }
99
100
    /**
101
     * Runs before each test method.
102
     */
103
    public function setUp()
104
    {
105
        $this->ao = new autoptimizeMain( AUTOPTIMIZE_PLUGIN_VERSION, AUTOPTIMIZE_PLUGIN_FILE );
106
107
        parent::setUp();
108
    }
109
110
    /**
111
     * Runs after each test method.
112
     */
113
    public function tearDown()
114
    {
115
        // Making sure certain filters are removed after each test to ensure isolation.
116
        $filter_tags = array(
117
            'autoptimize_filter_noptimize',
118
            'autoptimize_filter_base_cdnurl',
119
            'autoptimize_filter_css_is_datauri_candidate',
120
            'autoptimize_filter_css_datauri_image',
121
            'autoptimize_filter_css_inlinesize',
122
            'autoptimize_filter_css_fonts_cdn',
123
        );
124
        foreach ( $filter_tags as $filter_tag ) {
125
            remove_all_filters( $filter_tag );
126
        }
127
128
        parent::tearDown();
129
    }
130
131
    protected function get_test_markup()
132
    {
133
        $siteurl = $this->get_urls()['siteurl'];
134
135
        $markup = <<<MARKUP
136
<!DOCTYPE html>
137
<!--[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]-->
138
<!--[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]-->
139
<!--[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]-->
140
<!--[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]-->
141
<head>
142
<meta charset="utf-8">
143
<title>Mliječna juha od brokule &#9832; Kuhaj.hr</title>
144
<meta name="viewport" content="width=device-width,initial-scale=1">
145
<style type="text/css">
146
/* cdn rewrite tests */
147
148
.bg { background:url('img/something.svg'); }
149
.bg-no-quote { background: url(img/something.svg); }
150
.bg-double-quotes { background: url("img/something.svg"); }
151
152
.whitespaces { background : url   (  "../../somewhere-else/svg.svg" ) ; }
153
154
.host-relative { background: url("/img/something.svg"); }
155
.protocol-relative { background: url("//something/somewhere/example.png"); }
156
157
/* roboto-100 - latin-ext_latin */
158
@font-face {
159
    font-family: 'Roboto';
160
    font-style: normal;
161
    font-weight: 100;
162
    src: url('../fonts/roboto-v15-latin-ext_latin-100.eot'); /* IE9 Compat Modes */
163
    src: local('Roboto Thin'), local('Roboto-Thin'),
164
        url('../fonts/roboto-v15-latin-ext_latin-100.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
165
        url('../fonts/roboto-v15-latin-ext_latin-100.woff2') format('woff2'), /* Super Modern Browsers */
166
        url('../fonts/roboto-v15-latin-ext_latin-100.woff') format('woff'), /* Modern Browsers */
167
        url('../fonts/roboto-v15-latin-ext_latin-100.ttf') format('truetype'), /* Safari, Android, iOS */
168
        url('../fonts/roboto-v15-latin-ext_latin-100.svg#Roboto') format('svg'); /* Legacy iOS */
169
}
170
/* roboto-300 - latin-ext_latin */
171
@font-face {
172
    font-family: 'Roboto';
173
    font-style: normal;
174
    font-weight: 300;
175
    src: url('../fonts/roboto-v15-latin-ext_latin-300.eot'); /* IE9 Compat Modes */
176
    src: local('Roboto Light'), local('Roboto-Light'),
177
        url('../fonts/roboto-v15-latin-ext_latin-300.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
178
        url('../fonts/roboto-v15-latin-ext_latin-300.woff2') format('woff2'), /* Super Modern Browsers */
179
        url('../fonts/roboto-v15-latin-ext_latin-300.woff') format('woff'), /* Modern Browsers */
180
        url('../fonts/roboto-v15-latin-ext_latin-300.ttf') format('truetype'), /* Safari, Android, iOS */
181
        url('../fonts/roboto-v15-latin-ext_latin-300.svg#Roboto') format('svg'); /* Legacy iOS */
182
}
183
/* roboto-regular - latin-ext_latin */
184
@font-face {
185
    font-family: 'Roboto';
186
    font-style: normal;
187
    font-weight: 400;
188
    src: url('../fonts/roboto-v15-latin-ext_latin-regular.eot'); /* IE9 Compat Modes */
189
    src: local('Roboto'), local('Roboto-Regular'),
190
        url('../fonts/roboto-v15-latin-ext_latin-regular.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
191
        url('../fonts/roboto-v15-latin-ext_latin-regular.woff2') format('woff2'), /* Super Modern Browsers */
192
        url('../fonts/roboto-v15-latin-ext_latin-regular.woff') format('woff'), /* Modern Browsers */
193
        url('../fonts/roboto-v15-latin-ext_latin-regular.ttf') format('truetype'), /* Safari, Android, iOS */
194
        url('../fonts/roboto-v15-latin-ext_latin-regular.svg#Roboto') format('svg'); /* Legacy iOS */
195
}
196
/* roboto-500 - latin-ext_latin */
197
@font-face {
198
    font-family: 'Roboto';
199
    font-style: normal;
200
    font-weight: 500;
201
    src: url('../fonts/roboto-v15-latin-ext_latin-500.eot'); /* IE9 Compat Modes */
202
    src: local('Roboto Medium'), local('Roboto-Medium'),
203
        url('../fonts/roboto-v15-latin-ext_latin-500.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
204
        url('../fonts/roboto-v15-latin-ext_latin-500.woff2') format('woff2'), /* Super Modern Browsers */
205
        url('../fonts/roboto-v15-latin-ext_latin-500.woff') format('woff'), /* Modern Browsers */
206
        url('../fonts/roboto-v15-latin-ext_latin-500.ttf') format('truetype'), /* Safari, Android, iOS */
207
        url('../fonts/roboto-v15-latin-ext_latin-500.svg#Roboto') format('svg'); /* Legacy iOS */
208
}
209
</style>
210
    <!--[if lt IE 9]>
211
    <script src="$siteurl/wp-content/themes/my-theme/js/vendor/html5shiv-printshiv.min.js" type="text/javascript"></script>
212
    <![endif]-->
213
    <!--[if (gte IE 6)&(lte IE 8)]>
214
        <script type="text/javascript" src="$siteurl/wp-content/themes/my-theme/js/vendor/respond.min.js"></script>
215
    <![endif]-->
216
</head>
217
218
<body class="single single-post">
219
220
    <div id="fb-root"></div>
221
    <script>(function(d, s, id) {
222
        var js, fjs = d.getElementsByTagName(s)[0];
223
        if (d.getElementById(id)) return;
224
        js = d.createElement(s); js.id = id;
225
        js.src = "//connect.facebook.net/hr_HR/sdk.js#version=v2.0&xfbml=1&appId=";
226
        fjs.parentNode.insertBefore(js, fjs);
227
    }(document, 'script', 'facebook-jssdk'));</script>
228
    </script>
229
230
<script type='text/javascript' src='$siteurl/wp-content/plugins/ajax-load-more/core/js/ajax-load-more.min.js?ver=1.1'></script>
231
<script type='text/javascript' src='$siteurl/wp-content/plugins/wp-ga-social-tracking-js/ga-social-tracking.min.js'></script>
232
<script type='text/javascript' src='$siteurl/wp-content/themes/my-theme/js/vendor/alm-seo.js'></script>
233
<script type='text/javascript' src='$siteurl/wp-content/themes/my-theme/js/vendor/jquery.placeholder-2.1.1.min.js'></script>
234
<script type='text/javascript' src='$siteurl/wp-content/themes/my-theme/js/vendor/typeahead.bundle.min.js'></script>
235
<script type='text/javascript' src='$siteurl/wp-content/themes/my-theme/js/vendor/bootstrap-tagsinput.min.js'></script>
236
<script type='text/javascript' src='$siteurl/wp-content/themes/my-theme/js/m-mobilemenu.js'></script>
237
<script type='text/javascript' src='$siteurl/wp-content/themes/my-theme/js/main.js'></script>
238
<script type='text/javascript' src='$siteurl/wp-includes/js/comment-reply.min.js?ver=4.1.1'></script>
239
</body>
240
</html>
241
MARKUP;
242
243
        return $markup;
244
    }
245
246 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...
247
    {
248
        $key = 'default';
249
        if ( defined( 'CUSTOM_CONSTANTS_USED' ) && CUSTOM_CONSTANTS_USED ) {
250
            $key = 'custom';
251
        }
252
253
        $csspart = self::$flexible_url_parts_css[ $key ];
254
        $jspart  = self::$flexible_url_parts_js[ $key ];
255
256
        $csshash = '863f587e89f100b0223ddccc0dabc57a';
257
        if ( AO_TEST_SUBFOLDER_INSTALL ) {
258
            $csshash = '56398de576d59887e88e3011715250e0';
259
        }
260
261
        $urls      = $this->get_urls();
262
        $siteurl   = $urls['siteurl'];
263
        $cdnurl    = $urls['cdnurl'];
264
        $subfolder = $urls['subfolder'];
265
266
        $markup = <<<MARKUP
267
<!DOCTYPE html>
268
<!--[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]-->
269
<!--[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]-->
270
<!--[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]-->
271
<!--[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]-->
272
<head>
273
<meta charset="utf-8">
274
<link type="text/css" media="all" href="${cdnurl}/${subfolder}${csspart}${csshash}.css" rel="stylesheet" /><title>Mliječna juha od brokule &#9832; Kuhaj.hr</title>
275
<meta name="viewport" content="width=device-width,initial-scale=1">
276
277
    <!--[if lt IE 9]>
278
    <script src="$siteurl/wp-content/themes/my-theme/js/vendor/html5shiv-printshiv.min.js" type="text/javascript"></script>
279
    <![endif]-->
280
    <!--[if (gte IE 6)&(lte IE 8)]>
281
        <script type="text/javascript" src="$siteurl/wp-content/themes/my-theme/js/vendor/respond.min.js"></script>
282
    <![endif]-->
283
</head>
284
285
<body class="single single-post">
286
287
    <div id="fb-root"></div>
288
    <script>(function(d, s, id) {
289
        var js, fjs = d.getElementsByTagName(s)[0];
290
        if (d.getElementById(id)) return;
291
        js = d.createElement(s); js.id = id;
292
        js.src = "//connect.facebook.net/hr_HR/sdk.js#version=v2.0&xfbml=1&appId=";
293
        fjs.parentNode.insertBefore(js, fjs);
294
    }(document, 'script', 'facebook-jssdk'));</script>
295
    </script>
296
297
<script type='text/javascript' src='$siteurl/wp-content/plugins/ajax-load-more/core/js/ajax-load-more.min.js?ver=1.1'></script>
298
<script type='text/javascript' src='$siteurl/wp-content/plugins/wp-ga-social-tracking-js/ga-social-tracking.min.js'></script>
299
<script type='text/javascript' src='$siteurl/wp-content/themes/my-theme/js/vendor/alm-seo.js'></script>
300
<script type='text/javascript' src='$siteurl/wp-content/themes/my-theme/js/vendor/jquery.placeholder-2.1.1.min.js'></script>
301
<script type='text/javascript' src='$siteurl/wp-content/themes/my-theme/js/vendor/typeahead.bundle.min.js'></script>
302
<script type='text/javascript' src='$siteurl/wp-content/themes/my-theme/js/vendor/bootstrap-tagsinput.min.js'></script>
303
<script type='text/javascript' src='$siteurl/wp-content/themes/my-theme/js/m-mobilemenu.js'></script>
304
<script type='text/javascript' src='$siteurl/wp-content/themes/my-theme/js/main.js'></script>
305
306
<script type="text/javascript" defer src="$cdnurl/${subfolder}${jspart}730dfe55780a3a6fc98224e18fa27340.js"></script></body>
307
</html>
308
MARKUP;
309
310
        return $markup;
311
    }
312
313 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...
314
    {
315
        $key = 'multisite';
316
        if ( defined( 'CUSTOM_CONSTANTS_USED' ) && CUSTOM_CONSTANTS_USED ) {
317
            $key = 'multisite_custom';
318
        }
319
320
        $csspart = self::$flexible_url_parts_css[ $key ];
321
        $jspart  = self::$flexible_url_parts_js[ $key ];
322
323
        $csshash = '863f587e89f100b0223ddccc0dabc57a';
324
        if ( AO_TEST_SUBFOLDER_INSTALL ) {
325
            $csshash = '56398de576d59887e88e3011715250e0';
326
        }
327
328
        $urls      = $this->get_urls();
329
        $siteurl   = $urls['siteurl'];
330
        $cdnurl    = $urls['cdnurl'];
331
        $subfolder = $urls['subfolder'];
332
333
        $markup = <<<MARKUP
334
<!DOCTYPE html>
335
<!--[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]-->
336
<!--[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]-->
337
<!--[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]-->
338
<!--[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]-->
339
<head>
340
<meta charset="utf-8">
341
<link type="text/css" media="all" href="$cdnurl/${subfolder}${csspart}${csshash}.css" rel="stylesheet" /><title>Mliječna juha od brokule &#9832; Kuhaj.hr</title>
342
<meta name="viewport" content="width=device-width,initial-scale=1">
343
344
    <!--[if lt IE 9]>
345
    <script src="$siteurl/wp-content/themes/my-theme/js/vendor/html5shiv-printshiv.min.js" type="text/javascript"></script>
346
    <![endif]-->
347
    <!--[if (gte IE 6)&(lte IE 8)]>
348
        <script type="text/javascript" src="$siteurl/wp-content/themes/my-theme/js/vendor/respond.min.js"></script>
349
    <![endif]-->
350
</head>
351
352
<body class="single single-post">
353
354
    <div id="fb-root"></div>
355
    <script>(function(d, s, id) {
356
        var js, fjs = d.getElementsByTagName(s)[0];
357
        if (d.getElementById(id)) return;
358
        js = d.createElement(s); js.id = id;
359
        js.src = "//connect.facebook.net/hr_HR/sdk.js#version=v2.0&xfbml=1&appId=";
360
        fjs.parentNode.insertBefore(js, fjs);
361
    }(document, 'script', 'facebook-jssdk'));</script>
362
    </script>
363
364
<script type='text/javascript' src='$siteurl/wp-content/plugins/ajax-load-more/core/js/ajax-load-more.min.js?ver=1.1'></script>
365
<script type='text/javascript' src='$siteurl/wp-content/plugins/wp-ga-social-tracking-js/ga-social-tracking.min.js'></script>
366
<script type='text/javascript' src='$siteurl/wp-content/themes/my-theme/js/vendor/alm-seo.js'></script>
367
<script type='text/javascript' src='$siteurl/wp-content/themes/my-theme/js/vendor/jquery.placeholder-2.1.1.min.js'></script>
368
<script type='text/javascript' src='$siteurl/wp-content/themes/my-theme/js/vendor/typeahead.bundle.min.js'></script>
369
<script type='text/javascript' src='$siteurl/wp-content/themes/my-theme/js/vendor/bootstrap-tagsinput.min.js'></script>
370
<script type='text/javascript' src='$siteurl/wp-content/themes/my-theme/js/m-mobilemenu.js'></script>
371
<script type='text/javascript' src='$siteurl/wp-content/themes/my-theme/js/main.js'></script>
372
373
<script type="text/javascript" defer src="$cdnurl/${subfolder}${jspart}730dfe55780a3a6fc98224e18fa27340.js"></script></body>
374
</html>
375
MARKUP;
376
377
        return $markup;
378
    }
379
380 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...
381
    {
382
        $key = 'default';
383
        if ( defined( 'CUSTOM_CONSTANTS_USED' ) && CUSTOM_CONSTANTS_USED ) {
384
            $key = 'custom';
385
        }
386
387
        $csspart = self::$flexible_url_parts_css[ $key ];
388
        $jspart  = self::$flexible_url_parts_js[ $key ];
389
390
        $csshash = '863f587e89f100b0223ddccc0dabc57a';
391
        if ( AO_TEST_SUBFOLDER_INSTALL ) {
392
            $csshash = '56398de576d59887e88e3011715250e0';
393
        }
394
395
        $urls      = $this->get_urls();
396
        $siteurl   = $urls['siteurl'];
397
        $cdnurl    = $urls['cdnurl'];
398
        $subfolder = $urls['subfolder'];
399
400
        $markup = <<<MARKUP
401
<!DOCTYPE html>
402
<!--[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]-->
403
<!--[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]-->
404
<!--[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]-->
405
<!--[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]-->
406
<head>
407
<meta charset="utf-8">
408
<style type="text/css" id="aoatfcss" media="all">1</style><link rel="preload" as="style" media="all" href="$cdnurl/${subfolder}${csspart}{$csshash}.css" onload="this.onload=null;this.rel='stylesheet'" /><noscript id="aonoscrcss"><link type="text/css" media="all" href="$cdnurl/${subfolder}${csspart}${csshash}.css" rel="stylesheet" /></noscript><title>Mliječna juha od brokule &#9832; Kuhaj.hr</title>
409
<meta name="viewport" content="width=device-width,initial-scale=1">
410
411
    <!--[if lt IE 9]>
412
    <script src="$siteurl/wp-content/themes/my-theme/js/vendor/html5shiv-printshiv.min.js" type="text/javascript"></script>
413
    <![endif]-->
414
    <!--[if (gte IE 6)&(lte IE 8)]>
415
        <script type="text/javascript" src="$siteurl/wp-content/themes/my-theme/js/vendor/respond.min.js"></script>
416
    <![endif]-->
417
</head>
418
419
<body class="single single-post">
420
421
    <div id="fb-root"></div>
422
    <script>(function(d, s, id) {
423
        var js, fjs = d.getElementsByTagName(s)[0];
424
        if (d.getElementById(id)) return;
425
        js = d.createElement(s); js.id = id;
426
        js.src = "//connect.facebook.net/hr_HR/sdk.js#version=v2.0&xfbml=1&appId=";
427
        fjs.parentNode.insertBefore(js, fjs);
428
    }(document, 'script', 'facebook-jssdk'));</script>
429
    </script>
430
431
<script type='text/javascript' src='$siteurl/wp-content/plugins/ajax-load-more/core/js/ajax-load-more.min.js?ver=1.1'></script>
432
<script type='text/javascript' src='$siteurl/wp-content/plugins/wp-ga-social-tracking-js/ga-social-tracking.min.js'></script>
433
<script type='text/javascript' src='$siteurl/wp-content/themes/my-theme/js/vendor/alm-seo.js'></script>
434
<script type='text/javascript' src='$siteurl/wp-content/themes/my-theme/js/vendor/jquery.placeholder-2.1.1.min.js'></script>
435
<script type='text/javascript' src='$siteurl/wp-content/themes/my-theme/js/vendor/typeahead.bundle.min.js'></script>
436
<script type='text/javascript' src='$siteurl/wp-content/themes/my-theme/js/vendor/bootstrap-tagsinput.min.js'></script>
437
<script type='text/javascript' src='$siteurl/wp-content/themes/my-theme/js/m-mobilemenu.js'></script>
438
<script type='text/javascript' src='$siteurl/wp-content/themes/my-theme/js/main.js'></script>
439
440
<script type="text/javascript" defer src="$cdnurl/${subfolder}${jspart}730dfe55780a3a6fc98224e18fa27340.js"></script><script data-cfasync='false'>!function(t){"use strict";t.loadCSS||(t.loadCSS=function(){});var e=loadCSS.relpreload={};if(e.support=function(){var e;try{e=t.document.createElement("link").relList.supports("preload")}catch(t){e=!1}return function(){return e}}(),e.bindMediaToggle=function(t){function e(){t.media=a}var a=t.media||"all";t.addEventListener?t.addEventListener("load",e):t.attachEvent&&t.attachEvent("onload",e),setTimeout(function(){t.rel="stylesheet",t.media="only x"}),setTimeout(e,3e3)},e.poly=function(){if(!e.support())for(var a=t.document.getElementsByTagName("link"),n=0;n<a.length;n++){var o=a[n];"preload"!==o.rel||"style"!==o.getAttribute("as")||o.getAttribute("data-loadcss")||(o.setAttribute("data-loadcss",!0),e.bindMediaToggle(o))}},!e.support()){e.poly();var a=t.setInterval(e.poly,500);t.addEventListener?t.addEventListener("load",function(){e.poly(),t.clearInterval(a)}):t.attachEvent&&t.attachEvent("onload",function(){e.poly(),t.clearInterval(a)})}"undefined"!=typeof exports?exports.loadCSS=loadCSS:t.loadCSS=loadCSS}("undefined"!=typeof global?global:this);</script></body>
441
</html>
442
MARKUP;
443
444
        return $markup;
445
    }
446
447 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...
448
    {
449
        $key = 'multisite';
450
        if ( defined( 'CUSTOM_CONSTANTS_USED' ) && CUSTOM_CONSTANTS_USED ) {
451
            $key = 'multisite_custom';
452
        }
453
454
        $csspart = self::$flexible_url_parts_css[ $key ];
455
        $jspart  = self::$flexible_url_parts_js[ $key ];
456
457
        $csshash = '863f587e89f100b0223ddccc0dabc57a';
458
        if ( AO_TEST_SUBFOLDER_INSTALL ) {
459
            $csshash = '56398de576d59887e88e3011715250e0';
460
        }
461
462
        $urls      = $this->get_urls();
463
        $siteurl   = $urls['siteurl'];
464
        $cdnurl    = $urls['cdnurl'];
465
        $subfolder = $urls['subfolder'];
466
467
        $markup = <<<MARKUP
468
<!DOCTYPE html>
469
<!--[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]-->
470
<!--[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]-->
471
<!--[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]-->
472
<!--[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]-->
473
<head>
474
<meta charset="utf-8">
475
<style type="text/css" id="aoatfcss" media="all">1</style><link rel="preload" as="style" media="all" href="$cdnurl/${subfolder}${csspart}${csshash}.css" onload="this.onload=null;this.rel='stylesheet'" /><noscript id="aonoscrcss"><link type="text/css" media="all" href="$cdnurl/${subfolder}${csspart}${csshash}.css" rel="stylesheet" /></noscript><title>Mliječna juha od brokule &#9832; Kuhaj.hr</title>
476
<meta name="viewport" content="width=device-width,initial-scale=1">
477
478
    <!--[if lt IE 9]>
479
    <script src="$siteurl/wp-content/themes/my-theme/js/vendor/html5shiv-printshiv.min.js" type="text/javascript"></script>
480
    <![endif]-->
481
    <!--[if (gte IE 6)&(lte IE 8)]>
482
        <script type="text/javascript" src="$siteurl/wp-content/themes/my-theme/js/vendor/respond.min.js"></script>
483
    <![endif]-->
484
</head>
485
486
<body class="single single-post">
487
488
    <div id="fb-root"></div>
489
    <script>(function(d, s, id) {
490
        var js, fjs = d.getElementsByTagName(s)[0];
491
        if (d.getElementById(id)) return;
492
        js = d.createElement(s); js.id = id;
493
        js.src = "//connect.facebook.net/hr_HR/sdk.js#version=v2.0&xfbml=1&appId=";
494
        fjs.parentNode.insertBefore(js, fjs);
495
    }(document, 'script', 'facebook-jssdk'));</script>
496
    </script>
497
498
<script type='text/javascript' src='$siteurl/wp-content/plugins/ajax-load-more/core/js/ajax-load-more.min.js?ver=1.1'></script>
499
<script type='text/javascript' src='$siteurl/wp-content/plugins/wp-ga-social-tracking-js/ga-social-tracking.min.js'></script>
500
<script type='text/javascript' src='$siteurl/wp-content/themes/my-theme/js/vendor/alm-seo.js'></script>
501
<script type='text/javascript' src='$siteurl/wp-content/themes/my-theme/js/vendor/jquery.placeholder-2.1.1.min.js'></script>
502
<script type='text/javascript' src='$siteurl/wp-content/themes/my-theme/js/vendor/typeahead.bundle.min.js'></script>
503
<script type='text/javascript' src='$siteurl/wp-content/themes/my-theme/js/vendor/bootstrap-tagsinput.min.js'></script>
504
<script type='text/javascript' src='$siteurl/wp-content/themes/my-theme/js/m-mobilemenu.js'></script>
505
<script type='text/javascript' src='$siteurl/wp-content/themes/my-theme/js/main.js'></script>
506
507
<script type="text/javascript" defer src="$cdnurl/${subfolder}${jspart}730dfe55780a3a6fc98224e18fa27340.js"></script><script data-cfasync='false'>!function(t){"use strict";t.loadCSS||(t.loadCSS=function(){});var e=loadCSS.relpreload={};if(e.support=function(){var e;try{e=t.document.createElement("link").relList.supports("preload")}catch(t){e=!1}return function(){return e}}(),e.bindMediaToggle=function(t){function e(){t.media=a}var a=t.media||"all";t.addEventListener?t.addEventListener("load",e):t.attachEvent&&t.attachEvent("onload",e),setTimeout(function(){t.rel="stylesheet",t.media="only x"}),setTimeout(e,3e3)},e.poly=function(){if(!e.support())for(var a=t.document.getElementsByTagName("link"),n=0;n<a.length;n++){var o=a[n];"preload"!==o.rel||"style"!==o.getAttribute("as")||o.getAttribute("data-loadcss")||(o.setAttribute("data-loadcss",!0),e.bindMediaToggle(o))}},!e.support()){e.poly();var a=t.setInterval(e.poly,500);t.addEventListener?t.addEventListener("load",function(){e.poly(),t.clearInterval(a)}):t.attachEvent&&t.attachEvent("onload",function(){e.poly(),t.clearInterval(a)})}"undefined"!=typeof exports?exports.loadCSS=loadCSS:t.loadCSS=loadCSS}("undefined"!=typeof global?global:this);</script></body>
508
</html>
509
MARKUP;
510
511
        return $markup;
512
    }
513
514
    /**
515
     * @dataProvider provider_test_rewrite_markup_with_cdn
516
     */
517
    function test_rewrite_markup_with_cdn( $input, $expected )
518
    {
519
        $actual = $this->ao->end_buffering( $input );
520
521
        $this->assertEquals( $expected, $actual );
522
    }
523
524
    public function provider_test_rewrite_markup_with_cdn()
525
    {
526
        return array(
527
528
            array(
529
                // Input.
530
                $this->get_test_markup(),
531
                // Expected output.
532
                // TODO/FIXME: This seemed like the fastest way to get MS crude test to pass...
533
                ( is_multisite() ? $this->get_test_markup_output_ms() : $this->get_test_markup_output() ),
534
            ),
535
536
        );
537
    }
538
539
    public function test_rewrite_css_assets()
540
    {
541
        $urls   = $this->get_urls();
542
        $cdnurl = $urls['cdnurl'];
543
        $sub    = $urls['subfolder'];
544
545
        $css_in = <<<CSS
546
.bg { background:url('img/something.svg'); }
547
.bg-no-quote { background: url(img/something.svg); }
548
.bg-double-quotes { background: url("img/something.svg"); }
549
550
.whitespaces { background : url   (  "../../somewhere-else/svg.svg" ) ; }
551
552
.host-relative { background: url("/img/something.svg"); }
553
.protocol-relative { background: url("//something/somewhere/example.png"); }
554
555
@font-face {
556
  font-family: 'Roboto';
557
  font-style: normal;
558
  font-weight: 100;
559
  src: url('../fonts/roboto-v15-latin-ext_latin-100.eot'); /* IE9 Compat Modes */
560
  src: local('Roboto Thin'), local('Roboto-Thin'),
561
       url('../fonts/roboto-v15-latin-ext_latin-100.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
562
       url('../fonts/roboto-v15-latin-ext_latin-100.woff2') format('woff2'), /* Super Modern Browsers */
563
       url('../fonts/roboto-v15-latin-ext_latin-100.woff') format('woff'), /* Modern Browsers */
564
       url('../fonts/roboto-v15-latin-ext_latin-100.ttf') format('truetype'), /* Safari, Android, iOS */
565
       url('../fonts/roboto-v15-latin-ext_latin-100.svg#Roboto') format('svg'); /* Legacy iOS */
566
}
567
CSS;
568
569
        $css_expected = <<<CSS
570
.bg { background:url(img/something.svg); }
571
.bg-no-quote { background: url(img/something.svg); }
572
.bg-double-quotes { background: url(img/something.svg); }
573
574
.whitespaces { background : url   (  ../../somewhere-else/svg.svg) ; }
575
576
.host-relative { background: url(${cdnurl}/${sub}img/something.svg); }
577
.protocol-relative { background: url(//something/somewhere/example.png); }
578
579
@font-face {
580
  font-family: 'Roboto';
581
  font-style: normal;
582
  font-weight: 100;
583
  src: url('../fonts/roboto-v15-latin-ext_latin-100.eot'); /* IE9 Compat Modes */
584
  src: local('Roboto Thin'), local('Roboto-Thin'),
585
       url('../fonts/roboto-v15-latin-ext_latin-100.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
586
       url('../fonts/roboto-v15-latin-ext_latin-100.woff2') format('woff2'), /* Super Modern Browsers */
587
       url('../fonts/roboto-v15-latin-ext_latin-100.woff') format('woff'), /* Modern Browsers */
588
       url('../fonts/roboto-v15-latin-ext_latin-100.ttf') format('truetype'), /* Safari, Android, iOS */
589
       url('../fonts/roboto-v15-latin-ext_latin-100.svg#Roboto') format('svg'); /* Legacy iOS */
590
}
591
CSS;
592
593
        $instance = new autoptimizeStyles( $css_in );
594
        $instance->setOption( 'cdn_url', $cdnurl );
595
596
        $css_actual = $instance->rewrite_assets( $css_in );
597
598
        $this->assertEquals( $css_expected, $css_actual );
599
    }
600
601 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...
602
    {
603
        $css = <<<CSS
604
.bg { background:url('img/something.svg'); }
605
.bg-no-quote { background: url(img/something.svg); }
606
.bg-double-quotes { background: url("img/something.svg"); }
607
608
.whitespaces { background : url   (  "../../somewhere-else/svg.svg" ) ; }
609
610
.host-relative { background: url("/img/something.svg"); }
611
.protocol-relative { background: url("//something/somewhere/example.png"); }
612
613
/* roboto-100 - latin-ext_latin */
614
@font-face {
615
  font-family: 'Roboto';
616
  font-style: normal;
617
  font-weight: 100;
618
  src: url(../fonts/roboto-v15-latin-ext_latin-100.eot); /* IE9 Compat Modes */
619
  src: local('Roboto Thin'), local('Roboto-Thin'),
620
       url(../fonts/roboto-v15-latin-ext_latin-100.eot?#iefix) format('embedded-opentype'), /* IE6-IE8 */
621
       url(../fonts/roboto-v15-latin-ext_latin-100.woff2) format('woff2'), /* Super Modern Browsers */
622
       url(../fonts/roboto-v15-latin-ext_latin-100.woff) format('woff'), /* Modern Browsers */
623
       url(../fonts/roboto-v15-latin-ext_latin-100.ttf) format('truetype'), /* Safari, Android, iOS */
624
       url(../fonts/roboto-v15-latin-ext_latin-100.svg#Roboto) format('svg'); /* Legacy iOS */
625
}
626
CSS;
627
628
        $expected = <<<CSS
629
.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')}
630
CSS;
631
632
        $instance = new autoptimizeStyles( $css );
633
        $minified = $instance->run_minifier_on( $css );
634
635
        $this->assertEquals( $expected, $minified );
636
    }
637
638
    /**
639
     * @dataProvider provider_test_should_aggregate_script_types
640
     * @covers autoptimizeScripts::should_aggregate
641
     */
642
    public function test_should_aggregate_script_types( $input, $expected )
643
    {
644
        $instance = new autoptimizeScripts( '' );
645
        $actual   = $instance->should_aggregate( $input );
646
647
        $this->assertEquals( $expected, $actual );
648
    }
649
650
    public function provider_test_should_aggregate_script_types()
651
    {
652
        return array(
653
            // No type attribute at all.
654
            array(
655
                // Input.
656
                '<script>var something=true</script>',
657
                // Expected output.
658
                true,
659
            ),
660
            // Case-insensitive.
661
            array(
662
                '<script type="text/ecmaScript">var something=true</script>',
663
                true,
664
            ),
665
            // Allowed/aggregated now (wasn't previously).
666
            array(
667
                '<script type="application/javascript">var something=true</script>',
668
                true,
669
            ),
670
            // Quotes shouldn't matter, nor should case-sensitivity.
671
            array(
672
                '<script type=\'text/JaVascriPt">var something=true</script>',
673
                true,
674
            ),
675
            // Liberal to whitespace around attribute names/values.
676
            array(
677
                '<script tYpe = text/javascript>var something=true</script>',
678
                true,
679
            ),
680
            // Something custom, should be ignored/skipped.
681
            array(
682
                '<script type=template/javascript>var something=true</script>',
683
                false,
684
            ),
685
            // Type attribute checking should be constrained to actual script
686
            // tag's type attribute only, regardless of any `type=` string
687
            // present in the actual inline script contents.
688
            array(
689
                // Since there's no type attribute, it should be aggregate by default.
690
                '<script>var type=something;</script>',
691
                true,
692
            ),
693
            // Application/ld+json should not be aggregated by default regardless
694
            // of spacing around attr/values.
695
            array(
696
                '<script type = "application/ld+json" >{   "@context": "" }',
697
                false,
698
            ),
699
            array(
700
                '<script type="application/ld+json">{   "@context": "" }',
701
                false,
702
            ),
703
        );
704
    }
705
706
    /**
707
     * @dataProvider provider_is_valid_buffer
708
     * @covers autoptimizeMain::is_valid_buffer
709
     */
710
    public function test_valid_buffers( $input, $expected )
711
    {
712
        $actual = $this->ao->is_valid_buffer( $input );
713
714
        $this->assertEquals( $expected, $actual );
715
    }
716
717
    public function provider_is_valid_buffer()
718
    {
719
        return array(
720
            array(
721
                '<!doctype html>
722
<html ⚡>',
723
                false,
724
            ),
725
            array(
726
                '<!doctype html>
727
<html amp>',
728
                false,
729
            ),
730
            array(
731
                '<?xml version="1.0" encoding="UTF-8"?>
732
<xsl:stylesheet version="1.0"
733
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">',
734
                false,
735
            ),
736
            array(
737
                '<!doctype html>
738
<html>',
739
                true,
740
            ),
741
            array(
742
                '<html dir="ltr" amp>',
743
                false,
744
            ),
745
            array(
746
                '<html dir="ltr" ⚡>',
747
                false,
748
            ),
749
            array(
750
                '<html amp dir="ltr">',
751
                false,
752
            ),
753
            array(
754
                '<html ⚡ dir="ltr">',
755
                false,
756
            ),
757
            array(
758
                '<HTML ⚡ DIR="LTR">',
759
                false,
760
            ),
761
            array(
762
                '<HTML AMP DIR="LTR">',
763
                false,
764
            ),
765
            // @link https://github.com/futtta/autoptimize/commit/54385939db06f725fcafe68598cce6ed148ef6c1
766
            array(
767
                '<!doctype html>',
768
                true,
769
            ),
770
        );
771
    }
772
773
    /**
774
     * @dataProvider provider_is_amp_markup
775
     * @covers autoptimizeMain::is_amp_markup
776
     */
777
    public function test_autoptimize_is_amp_markup( $input, $expected )
778
    {
779
        $actual = autoptimizeMain::is_amp_markup( $input );
780
781
        $this->assertEquals( $expected, $actual );
782
    }
783
784
    public function provider_is_amp_markup()
785
    {
786
        return array(
787
            array(
788
                '<!doctype html>
789
<html ⚡>',
790
                true,
791
            ),
792
            array(
793
                '<!doctype html>
794
<html amp>',
795
                true,
796
            ),
797
            array(
798
                '<!doctype html>
799
<head>
800
<meta charset=utf-8>',
801
                false,
802
            ),
803
        );
804
    }
805
806
    /**
807
     * Test various conditions that can/should prevent autoptimize from buffering content.
808
     */
809 View Code Duplication
    public function test_skips_buffering_when_ao_noptimize_filter_is_true()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Loading history...
889
                ->disableOriginalConstructor()->setMethods(
890
                    array(
891
                        'purge_varnish_cache',
892
                        'purge_memcached',
893
                        'clear_maxcdn_cache',
894
                    )
895
                )
896
                ->getMock();
897
898
        add_filter( 'autoptimize_flush_wpengine_aggressive', function() {
899
            return true;
900
        });
901
902
        $that = $this;
903
        add_filter( 'autoptimize_flush_wpengine_methods', function( $methods ) use ( $that ) {
904
            $expected_methods = array(
905
                'purge_varnish_cache',
906
                'purge_memcached',
907
                'clear_maxcdn_cache',
908
            );
909
910
            $that->assertEquals( $methods, $expected_methods );
911
912
            return $methods;
913
        });
914
915
        autoptimizeCache::flushPageCache();
916
    }
917
918
    /**
919
     * @dataProvider provider_test_url_replace_cdn
920
     * @covers autoptimizeBase::url_replace_cdn
921
     */
922
    public function test_url_replace_cdn( $cdn_url, $input, $expected )
923
    {
924
        $mock = $this->getMockBuilder( 'autoptimizeBase' )
925
                ->disableOriginalConstructor()
926
                ->getMockForAbstractClass();
927
928
        $mock->cdn_url = $cdn_url;
929
        $actual        = $mock->url_replace_cdn( $input );
930
        $this->assertEquals( $expected, $actual );
931
    }
932
933
    public function provider_test_url_replace_cdn()
934
    {
935
        $urls                 = $this->get_urls();
936
        $siteurl              = $urls['siteurl'];
937
        $wwwsiteurl           = $urls['wwwsiteurl'];
938
        $protorelativesiteurl = $urls['prsiteurl'];
939
        $subfolder            = $urls['subfolder'];
940
941
        return array(
942
            // Host-relative links get properly transformed...
943
            array(
944
                // CDN base url, url, expected result...
945
                'http://cdn-test.example.org',
946
                '/a.jpg',
947
                'http://cdn-test.example.org/' . $subfolder . 'a.jpg',
948
            ),
949
            // Full link with a matching AUTOPTIMIZE_WP_SITE_URL gets properly replaced...
950
            array(
951
                'http://cdn-test.example.org',
952
                $siteurl . '/wp-content/themes/something/example.svg',
953
                'http://cdn-test.example.org/' . $subfolder . 'wp-content/themes/something/example.svg',
954
            ),
955
            // Protocol-relative url with a "local" hostname that doesn't match example.org (AUTOPTIMIZE_WP_SITE_URL)...
956
            array(
957
                'http://cdn-test.example.org',
958
                '//something/somewhere.jpg',
959
                '//something/somewhere.jpg',
960
            ),
961
            // www.example.org does not match example.org (AUTOPTIMIZE_WP_SITE_URL) so it's left alone...
962
            array(
963
                'http://cdn-test.example.org',
964
                $wwwsiteurl . '/wp-content/themes/something/example.svg',
965
                $wwwsiteurl . '/wp-content/themes/something/example.svg',
966
            ),
967
            // SSL cdn url + host-relative link...
968
            array(
969
                'https://cdn.example.org',
970
                '/a.jpg',
971
                'https://cdn.example.org/' . $subfolder . 'a.jpg',
972
            ),
973
            // SSL cdn url + http site url that matches AUTOPTIMIZE_WP_SITE_URL is properly replaced...
974
            array(
975
                'https://cdn.example.org',
976
                $siteurl . '/wp-content/themes/something/example.svg',
977
                'https://cdn.example.org/' . $subfolder . 'wp-content/themes/something/example.svg',
978
            ),
979
            // Protocol-relative cdn url given with protocol relative link that matches AUTOPTIMIZE_WP_SITE_URL host...
980
            array(
981
                '//cdn.example.org',
982
                $protorelativesiteurl . '/something.jpg',
983
                '//cdn.example.org/' . $subfolder . 'something.jpg',
984
            ),
985
            // Protocol-relative cdn url given a http link that matches AUTOPTIMIZE_WP_SITE_URL host...
986
            array(
987
                '//cdn.example.org',
988
                $siteurl . '/something.png',
989
                '//cdn.example.org/' . $subfolder . 'something.png',
990
            ),
991
            // Protocol-relative cdn url with a host-relative link...
992
            array(
993
                '//cdn.example.org',
994
                '/a.jpg',
995
                '//cdn.example.org/' . $subfolder . 'a.jpg',
996
            ),
997
            // Testing cdn urls with an explicit port number...
998
            array(
999
                'http://cdn.com:8080',
1000
                '/a.jpg',
1001
                'http://cdn.com:8080/' . $subfolder . 'a.jpg',
1002
            ),
1003
            array(
1004
                '//cdn.com:4433',
1005
                '/a.jpg',
1006
                '//cdn.com:4433/' . $subfolder . 'a.jpg',
1007
            ),
1008
            array(
1009
                '//cdn.com:4433',
1010
                $siteurl . '/something.jpg',
1011
                '//cdn.com:4433/' . $subfolder . 'something.jpg',
1012
            ),
1013
            array(
1014
                '//cdn.com:1234',
1015
                $protorelativesiteurl . '/something.jpg',
1016
                '//cdn.com:1234/' . $subfolder . 'something.jpg',
1017
            ),
1018
            // Relative links should not be touched by url_replace_cdn()...
1019
            array(
1020
                // Base cdn url.
1021
                'http://cdn-test.example.org',
1022
                // Url.
1023
                'a.jpg',
1024
                // Expected result.
1025
                'a.jpg',
1026
            ),
1027
            array(
1028
                'http://cdn-test.example.org',
1029
                './a.jpg',
1030
                './a.jpg',
1031
            ),
1032
            array(
1033
                'http://cdn-test.example.org',
1034
                '../something/somewhere.svg',
1035
                '../something/somewhere.svg',
1036
            ),
1037
            // These prove some weird combinations pre-2.4 remain working
1038
            // even though they are really strange...
1039
            array(
1040
                $siteurl, // example.org or http://localhost or http://localhost/wordpress
1041
                $siteurl . '/something.jpg',
1042
                $siteurl . '/something.jpg',
1043
            ),
1044
            // These shouldn't really be changed, or even if replacements do
1045
            // happen, they shouldn't be destructive...
1046
            array(
1047
                'http://localhost/wp',
1048
                'http://localhost/wp/something.jpg',
1049
                'http://localhost/wp/something.jpg',
1050
            ),
1051
            array(
1052
                'http://localhost',
1053
                'http://localhost/something.jpg',
1054
                'http://localhost/something.jpg',
1055
            ),
1056
            array(
1057
                'http://localhost',
1058
                'http://localhost/wordpress/something.jpg',
1059
                'http://localhost/wordpress/something.jpg',
1060
            ),
1061
            array(
1062
                'http://localhost/wordpress',
1063
                'http://localhost/wordpress/something.jpg',
1064
                'http://localhost/wordpress/something.jpg',
1065
            ),
1066
        );
1067
    }
1068
1069
    /**
1070
     * Tests `autoptimize_filter_base_cdnurl` filtering as described here:
1071
     * https://wordpress.org/support/topic/disable-cdn-of-ssl-pages
1072
     */
1073
    public function test_autoptimize_filter_base_cdnurl()
1074
    {
1075
        $urls = $this->get_urls();
1076
        $sub  = $urls['subfolder'];
1077
1078
        $test_link = '/a.jpg';
1079
        $cdn_url   = '//cdn.example.org';
1080
1081
        $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...
1082
            return '';
1083
        };
1084
        $expected_with_ssl = '/a.jpg';
1085
1086
        $without_ssl = function( $cdn ) {
1087
            return $cdn;
1088
        };
1089
        $expected_without_ssl = '//cdn.example.org/' . $sub . 'a.jpg';
1090
1091
        // With a filter that returns something considered "empty", cdn replacement shouldn't occur...
1092
        add_filter( 'autoptimize_filter_base_cdnurl', $with_ssl );
1093
        $mock = $this->getMockBuilder( 'autoptimizeBase' )
1094
                ->disableOriginalConstructor()
1095
                ->getMockForAbstractClass();
1096
1097
        $mock->cdn_url   = $cdn_url;
1098
        $actual_with_ssl = $mock->url_replace_cdn( $test_link );
1099
        $this->assertEquals( $expected_with_ssl, $actual_with_ssl );
1100
        remove_filter( 'autoptimize_filter_base_cdnurl', $with_ssl );
1101
1102
        // With a filter that returns an actual cdn url, cdn replacement should occur.
1103
        add_filter( 'autoptimize_filter_base_cdnurl', $without_ssl );
1104
        $actual_without_ssl = $mock->url_replace_cdn( $test_link );
1105
        $this->assertEquals( $expected_without_ssl, $actual_without_ssl );
1106
    }
1107
1108
    public function provider_cssmin_issues()
1109
    {
1110
        return array(
1111
            // @link https://wordpress.org/support/topic/css-minify-breaks-calc-subtract-operation-in-css/?replies=2#post-6610027
1112
            array(
1113
                // Input.
1114
                'input { width: calc(33.33333% - ((0.75em*2)/3)); }',
1115
                // Expected output (ancient version of CSSmin returns 0.75, newer versions drop the 0).
1116
                'input{width:calc(33.33333% - ((.75em*2)/3))}',
1117
            ),
1118
            // Actual examples from above, but original wasn't really valid
1119
            // css input fully, but these tests used to work and we'd like to
1120
            // know if output changes with various CSSmin versions, for
1121
            // backcompat reasons if nothing else.
1122
            array(
1123
                // Input.
1124
                'width: calc(33.33333% - ((0.75em*2)/3));',
1125
                // Expected output.
1126
                'width:calc(33.33333% - ((0.75em*2)/3));',
1127
            ),
1128
            // @link https://github.com/tubalmartin/YUI-CSS-compressor-PHP-port/issues/22#issuecomment-251401341
1129
            array(
1130
                'input { width: calc(100% - (1em*1.5) - 2em); }',
1131
                'input{width:calc(100% - (1em*1.5) - 2em)}',
1132
            ),
1133
            // @link https://github.com/tubalmartin/YUI-CSS-compressor-PHP-port/issues/26
1134
            array(
1135
                '.px { flex: 1 1 0px; }, .percent {flex: 1 1 0%}',
1136
                '.px{flex:1 1 0px},.percent{flex:1 1 0%}',
1137
            ),
1138
        );
1139
    }
1140
1141
    /**
1142
     * @dataProvider provider_cssmin_issues
1143
     */
1144
    public function test_cssmin_issues( $input, $expected )
1145
    {
1146
        $minifier = new autoptimizeCSSmin( false ); // No need to raise limits for now.
1147
        $actual   = $minifier->run( $input );
1148
        $this->assertEquals( $expected, $actual );
1149
    }
1150
1151
    public function provider_getpath()
1152
    {
1153
        return array(
1154
            /**
1155
             * These all don't really exist, and getpath() returns false for
1156
             * non-existing files since upstream's 1386e4fe1d commit.
1157
             */
1158
            array(
1159
                'img/something.svg',
1160
                false,
1161
            ),
1162
            array(
1163
                '../../somewhere-else/svg.svg',
1164
                false,
1165
            ),
1166
            array(
1167
                '//something/somewhere/example.png',
1168
                false,
1169
            ),
1170
            // This file comes with core, so should exist...
1171
            array(
1172
                '/wp-includes/js/jquery/jquery.js',
1173
                WP_ROOT_DIR . '/wp-includes/js/jquery/jquery.js',
1174
            ),
1175
            // Empty $url should return false.
1176
            array(
1177
                '',
1178
                false,
1179
            ),
1180
            array(
1181
                false,
1182
                false,
1183
            ),
1184
            array(
1185
                null,
1186
                false,
1187
            ),
1188
            array(
1189
                0,
1190
                false,
1191
            ),
1192
        );
1193
    }
1194
1195
    /**
1196
     * @dataProvider provider_getpath
1197
     * @covers autoptimizeBase::getpath
1198
     */
1199
    public function test_getpath( $input, $expected )
1200
    {
1201
        $mock = $this->getMockBuilder( 'autoptimizeBase' )->disableOriginalConstructor()->getMockForAbstractClass();
1202
1203
        $actual = $mock->getpath( $input );
1204
        $this->assertEquals( $expected, $actual );
1205
    }
1206
1207
    /**
1208
     * @link https://github.com/futtta/autoptimize/pull/81#issuecomment-278935307
1209
     */
1210
    public function test_fixurls_with_hash_only_urls()
1211
    {
1212
        $urls      = $this->get_urls();
1213
        $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...
1214
        $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...
1215
1216
        $protorelativesiteurl = $urls['prsiteurl'];
1217
1218
        $css_orig     = <<<CSS
1219
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")}
1220
section.clipped.clippedTop {clip-path:url("#clipPolygonTop")}
1221
section.clipped.clippedBottom {clip-path:url("#clipPolygonBottom")}
1222
.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");}
1223
CSS;
1224
        $css_expected = <<<CSS
1225
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")}
1226
section.clipped.clippedTop {clip-path:url("#clipPolygonTop")}
1227
section.clipped.clippedBottom {clip-path:url("#clipPolygonBottom")}
1228
.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);}
1229
CSS;
1230
1231
        $fixurls_result = autoptimizeStyles::fixurls( ABSPATH . 'wp-content/themes/my-theme/style.css', $css_orig );
1232
        $this->assertEquals( $css_expected, $fixurls_result );
1233
    }
1234
1235
    public function test_background_datauri_sprites_with_fixurls()
1236
    {
1237
        $css_orig     = <<<CSS
1238
.shadow { background:url(img/1x1.png) top center; }
1239
.shadow1 { background-image:url(img/1x1.png) 0 -767px repeat-x; }
1240
.shadow2 {background:url(img/1x1.png) top center}
1241
1242
.test { background:url(img/1x1.png) top center; }
1243
.test1 { background-image:url('img/1x1.png') 0 -767px repeat-x; }
1244
.test2 {background:url("img/1x1.png") top center}
1245
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
1248
/*
1249
section.clipped.clippedTop {clip-path:url("#clipPolygonTop")}
1250
section.clipped.clippedBottom {clip-path:url("#clipPolygonBottom")}
1251
.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");}
1252
.something {
1253
    background:url(http://example.org/wp-content/themes/my-theme/images/nothing.png);
1254
}
1255
.something-else {background:url(wp-content/themes/my-theme/images/shadow.png) -100px 0 repeat-y;}
1256
.another-thing { background:url(/wp-content/themes/my-theme/images/shadow.png) 0 -767px repeat-x; }
1257
#whatevz {background:url(wp-content/themes/my-theme/images/shadow.png) center top no-repeat;}
1258
1259
.widget ul li { background:url(img/shadow.png) top center; }
1260
*/
1261
CSS;
1262
        $css_expected = <<<CSS
1263
.shadow { background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=) top center; }
1264
.shadow1 { background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=) 0 -767px repeat-x; }
1265
.shadow2 {background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=) top center}
1266
1267
.test { background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=) top center; }
1268
.test1 { background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=) 0 -767px repeat-x; }
1269
.test2 {background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=) top center}
1270
1271
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")}
1272
1273
/*
1274
section.clipped.clippedTop {clip-path:url("#clipPolygonTop")}
1275
section.clipped.clippedBottom {clip-path:url("#clipPolygonBottom")}
1276
.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=);}
1277
.something {
1278
    background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=);
1279
}
1280
.something-else {background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=) -100px 0 repeat-y;}
1281
.another-thing { background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=) 0 -767px repeat-x; }
1282
#whatevz {background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=) center top no-repeat;}
1283
1284
.widget ul li { background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=) top center; }
1285
*/
1286
CSS;
1287
1288
        // For test purposes, ALL images in the css are being inline with a 1x1 trans png string/datauri.
1289
        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...
1290
            return true;
1291
        }, 10, 2 );
1292
1293
        // For test purposes, ALL images in the css are being inline with a 1x1 trans png string/datauri.
1294 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...
1295
            $head = 'data:image/png;base64,';
1296
            $data = 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=';
1297
1298
            $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...
1299
            $result['base64data'] = $data;
1300
            return $result;
1301
        }, 10, 2 );
1302
1303
        $instance = new autoptimizeStyles( $css_orig );
1304
        $instance->setOption( 'datauris', true );
1305
1306
        $fixurls_result = autoptimizeStyles::fixurls( ABSPATH . 'wp-content/themes/my-theme/style.css', $css_orig );
1307
        $css_actual     = $instance->rewrite_assets( $fixurls_result );
1308
1309
        $this->assertEquals( $css_expected, $css_actual );
1310
    }
1311
1312
    /**
1313
     * Doing rewrite_assets() without calling fixurls() beforehand could
1314
     * cause wrong results if/when there's a (same) image referenced via
1315
     * root-relative and relative urls, i.e.,
1316
     * `/wp-content/themes/my-theme/images/shadow.png` and
1317
     * `wp-content/themes/my-theme/images/shadow.png` in test code below.
1318
     * That's because urls are not really "normalized" in rewrite_assets() at
1319
     * all, and replacements are done using simple string keys (based on url),
1320
     * so whenever the shorter url ends up being spotted first, the replacement
1321
     * was done in a way that leaves the first `/` character in place.
1322
     * Which could mean trouble, especially when doing inlining of smaller
1323
     * images.
1324
     * After sorting the replacements array in rewrite_assets() by string
1325
     * length in descending order, the problem goes away.
1326
     */
1327
    public function test_background_datauri_sprites_without_fixurls()
1328
    {
1329
        $css_orig     = <<<CSS
1330
.shadow { background:url(img/1x1.png) top center; }
1331
.shadow1 { background-image:url(img/1x1.png) 0 -767px repeat-x; }
1332
.shadow2 {background:url(img/1x1.png) top center}
1333
1334
.test { background:url(img/1x1.png) top center; }
1335
.test1 { background-image:url('img/1x1.png') 0 -767px repeat-x; }
1336
.test2 {background:url("img/1x1.png") top center}
1337
1338
section.clipped.clippedTop {clip-path:url("#clipPolygonTop")}
1339
section.clipped.clippedBottom {clip-path:url("#clipPolygonBottom")}
1340
.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");}
1341
.something {
1342
    background:url(http://example.org/wp-content/themes/my-theme/images/nothing.png);
1343
}
1344
.something-else {background:url(wp-content/themes/my-theme/images/shadow.png) -100px 0 repeat-y;}
1345
.another-thing { background:url(/wp-content/themes/my-theme/images/shadow.png) 0 -767px repeat-x; }
1346
#whatevz {background:url(wp-content/themes/my-theme/images/shadow.png) center top no-repeat;}
1347
1348
.widget ul li { background:url(img/shadow.png) top center; }
1349
CSS;
1350
        $css_expected = <<<CSS
1351
.shadow { background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=) top center; }
1352
.shadow1 { background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=) 0 -767px repeat-x; }
1353
.shadow2 {background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=) top center}
1354
1355
.test { background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=) top center; }
1356
.test1 { background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=) 0 -767px repeat-x; }
1357
.test2 {background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=) top center}
1358
1359
section.clipped.clippedTop {clip-path:url("#clipPolygonTop")}
1360
section.clipped.clippedBottom {clip-path:url("#clipPolygonBottom")}
1361
.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=);}
1362
.something {
1363
    background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=);
1364
}
1365
.something-else {background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=) -100px 0 repeat-y;}
1366
.another-thing { background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=) 0 -767px repeat-x; }
1367
#whatevz {background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=) center top no-repeat;}
1368
1369
.widget ul li { background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=) top center; }
1370
CSS;
1371
1372
        // For test purposes, ALL images in the css are being inlined with a 1x1 trans png string/datauri.
1373
        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...
1374
            return true;
1375
        }, 10, 2 );
1376
1377
        // For test purposes, ALL images in the css are being inlined with a 1x1 trans png string/datauri.
1378 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...
1379
            $head = 'data:image/png;base64,';
1380
            $data = 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=';
1381
1382
            $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...
1383
            $result['base64data'] = $data;
1384
            return $result;
1385
        }, 10, 2 );
1386
1387
        $instance = new autoptimizeStyles( $css_orig );
1388
        $instance->setOption( 'datauris', true );
1389
        $css_actual = $instance->rewrite_assets( $css_orig );
1390
        $this->assertEquals( $css_expected, $css_actual );
1391
    }
1392
1393
    /**
1394
     * Test css with fonts pointed to the CDN + cdn_url option is set.
1395
     */
1396
    public function test_css_fonts_on_cdn_with_filter()
1397
    {
1398
        $urls    = $this->get_urls();
1399
        $siteurl = $urls['siteurl'];
1400
        $cdnurl  = $urls['cdnurl'];
1401
        $sub     = $urls['subfolder'];
1402
1403
        $css_in = <<<CSS
1404
/* these should not be touched except for quotes removal */
1405
@font-face {
1406
  font-family: 'Roboto';
1407
  font-style: normal;
1408
  font-weight: 100;
1409
  src: url('../fonts/roboto-v15-latin-ext_latin-100.eot'); /* IE9 Compat Modes */
1410
  src: local('Roboto Thin'), local('Roboto-Thin'),
1411
       url('../fonts/roboto-v15-latin-ext_latin-100.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
1412
       url('../fonts/roboto-v15-latin-ext_latin-100.woff2') format('woff2'), /* Super Modern Browsers */
1413
       url('../fonts/roboto-v15-latin-ext_latin-100.woff') format('woff'), /* Modern Browsers */
1414
       url('../fonts/roboto-v15-latin-ext_latin-100.ttf') format('truetype'), /* Safari, Android, iOS */
1415
       url('../fonts/roboto-v15-latin-ext_latin-100.svg#Roboto') format('svg'); /* Legacy iOS */
1416
}
1417
@font-face {
1418
  font-family: 'Roboto';
1419
  font-style: normal;
1420
  font-weight: 100;
1421
  src: url('//fonts/roboto-v15-latin-ext_latin-100.eot'); /* IE9 Compat Modes */
1422
  src: local('Roboto Thin'), local('Roboto-Thin'),
1423
       url('//fonts/roboto-v15-latin-ext_latin-100.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
1424
       url('//fonts/roboto-v15-latin-ext_latin-100.woff2') format('woff2'), /* Super Modern Browsers */
1425
       url('//fonts/roboto-v15-latin-ext_latin-100.woff') format('woff'), /* Modern Browsers */
1426
       url('//fonts/roboto-v15-latin-ext_latin-100.ttf') format('truetype'), /* Safari, Android, iOS */
1427
       url('//fonts/roboto-v15-latin-ext_latin-100.svg#Roboto') format('svg'); /* Legacy iOS */
1428
}
1429
/* these will be replaced and quotes gone */
1430
@font-face {
1431
  font-family: 'Roboto';
1432
  font-style: normal;
1433
  font-weight: 100;
1434
  src: url('/fonts/roboto-v15-latin-ext_latin-100.eot'); /* IE9 Compat Modes */
1435
  src: local('Roboto Thin'), local('Roboto-Thin'),
1436
       url('/fonts/roboto-v15-latin-ext_latin-100.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
1437
       url('/fonts/roboto-v15-latin-ext_latin-100.woff2') format('woff2'), /* Super Modern Browsers */
1438
       url('/fonts/roboto-v15-latin-ext_latin-100.woff') format('woff'), /* Modern Browsers */
1439
       url('/fonts/roboto-v15-latin-ext_latin-100.ttf') format('truetype'), /* Safari, Android, iOS */
1440
       url('/fonts/roboto-v15-latin-ext_latin-100.svg#Roboto') format('svg'); /* Legacy iOS */
1441
}
1442
@font-face {
1443
  font-family: 'Roboto';
1444
  font-style: normal;
1445
  font-weight: 100;
1446
  src: url('$siteurl/wp-content/themes/mytheme/fonts/roboto-v15-latin-ext_latin-100.eot'); /* IE9 Compat Modes */
1447
  src: local('Roboto Thin'), local('Roboto-Thin'),
1448
       url('$siteurl/wp-content/themes/mytheme/fonts/roboto-v15-latin-ext_latin-100.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
1449
       url('$siteurl/wp-content/themes/mytheme/fonts/roboto-v15-latin-ext_latin-100.woff2') format('woff2'), /* Super Modern Browsers */
1450
       url('$siteurl/wp-content/themes/mytheme/fonts/roboto-v15-latin-ext_latin-100.woff') format('woff'), /* Modern Browsers */
1451
       url('$siteurl/wp-content/themes/mytheme/fonts/roboto-v15-latin-ext_latin-100.ttf') format('truetype'), /* Safari, Android, iOS */
1452
       url('$siteurl/wp-content/themes/mytheme/fonts/roboto-v15-latin-ext_latin-100.svg#Roboto') format('svg'); /* Legacy iOS */
1453
}
1454
CSS;
1455
1456
        $css_expected_fonts_cdn = <<<CSS
1457
/* these should not be touched except for quotes removal */
1458
@font-face {
1459
  font-family: 'Roboto';
1460
  font-style: normal;
1461
  font-weight: 100;
1462
  src: url(../fonts/roboto-v15-latin-ext_latin-100.eot); /* IE9 Compat Modes */
1463
  src: local('Roboto Thin'), local('Roboto-Thin'),
1464
       url(../fonts/roboto-v15-latin-ext_latin-100.eot?#iefix) format('embedded-opentype'), /* IE6-IE8 */
1465
       url(../fonts/roboto-v15-latin-ext_latin-100.woff2) format('woff2'), /* Super Modern Browsers */
1466
       url(../fonts/roboto-v15-latin-ext_latin-100.woff) format('woff'), /* Modern Browsers */
1467
       url(../fonts/roboto-v15-latin-ext_latin-100.ttf) format('truetype'), /* Safari, Android, iOS */
1468
       url(../fonts/roboto-v15-latin-ext_latin-100.svg#Roboto) format('svg'); /* Legacy iOS */
1469
}
1470
@font-face {
1471
  font-family: 'Roboto';
1472
  font-style: normal;
1473
  font-weight: 100;
1474
  src: url(//fonts/roboto-v15-latin-ext_latin-100.eot); /* IE9 Compat Modes */
1475
  src: local('Roboto Thin'), local('Roboto-Thin'),
1476
       url(//fonts/roboto-v15-latin-ext_latin-100.eot?#iefix) format('embedded-opentype'), /* IE6-IE8 */
1477
       url(//fonts/roboto-v15-latin-ext_latin-100.woff2) format('woff2'), /* Super Modern Browsers */
1478
       url(//fonts/roboto-v15-latin-ext_latin-100.woff) format('woff'), /* Modern Browsers */
1479
       url(//fonts/roboto-v15-latin-ext_latin-100.ttf) format('truetype'), /* Safari, Android, iOS */
1480
       url(//fonts/roboto-v15-latin-ext_latin-100.svg#Roboto) format('svg'); /* Legacy iOS */
1481
}
1482
/* these will be replaced and quotes gone */
1483
@font-face {
1484
  font-family: 'Roboto';
1485
  font-style: normal;
1486
  font-weight: 100;
1487
  src: url(${cdnurl}/${sub}fonts/roboto-v15-latin-ext_latin-100.eot); /* IE9 Compat Modes */
1488
  src: local('Roboto Thin'), local('Roboto-Thin'),
1489
       url(${cdnurl}/${sub}fonts/roboto-v15-latin-ext_latin-100.eot?#iefix) format('embedded-opentype'), /* IE6-IE8 */
1490
       url(${cdnurl}/${sub}fonts/roboto-v15-latin-ext_latin-100.woff2) format('woff2'), /* Super Modern Browsers */
1491
       url(${cdnurl}/${sub}fonts/roboto-v15-latin-ext_latin-100.woff) format('woff'), /* Modern Browsers */
1492
       url(${cdnurl}/${sub}fonts/roboto-v15-latin-ext_latin-100.ttf) format('truetype'), /* Safari, Android, iOS */
1493
       url(${cdnurl}/${sub}fonts/roboto-v15-latin-ext_latin-100.svg#Roboto) format('svg'); /* Legacy iOS */
1494
}
1495
@font-face {
1496
  font-family: 'Roboto';
1497
  font-style: normal;
1498
  font-weight: 100;
1499
  src: url(${cdnurl}/${sub}wp-content/themes/mytheme/fonts/roboto-v15-latin-ext_latin-100.eot); /* IE9 Compat Modes */
1500
  src: local('Roboto Thin'), local('Roboto-Thin'),
1501
       url(${cdnurl}/${sub}wp-content/themes/mytheme/fonts/roboto-v15-latin-ext_latin-100.eot?#iefix) format('embedded-opentype'), /* IE6-IE8 */
1502
       url(${cdnurl}/${sub}wp-content/themes/mytheme/fonts/roboto-v15-latin-ext_latin-100.woff2) format('woff2'), /* Super Modern Browsers */
1503
       url(${cdnurl}/${sub}wp-content/themes/mytheme/fonts/roboto-v15-latin-ext_latin-100.woff) format('woff'), /* Modern Browsers */
1504
       url(${cdnurl}/${sub}wp-content/themes/mytheme/fonts/roboto-v15-latin-ext_latin-100.ttf) format('truetype'), /* Safari, Android, iOS */
1505
       url(${cdnurl}/${sub}wp-content/themes/mytheme/fonts/roboto-v15-latin-ext_latin-100.svg#Roboto) format('svg'); /* Legacy iOS */
1506
}
1507
CSS;
1508
1509
        // Test with fonts pointed to the CDN + cdn option is set.
1510
        add_filter( 'autoptimize_filter_css_fonts_cdn', '__return_true' );
1511
        $instance = new autoptimizeStyles( $css_in );
1512
        $instance->setOption( 'cdn_url', $cdnurl );
1513
        $css_actual_fonts_cdn = $instance->rewrite_assets( $css_in );
1514
1515
        $this->assertEquals( $css_expected_fonts_cdn, $css_actual_fonts_cdn );
1516
    }
1517
1518
    /**
1519
     * Test css fonts not moved to cdn by default even if cdn_url option is set.
1520
     */
1521
    public function test_css_fonts_skipped_by_default_even_when_cdn_is_set()
1522
    {
1523
        $urls      = $this->get_urls();
1524
        $siteurl   = $urls['siteurl'];
1525
        $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...
1526
1527
        $css_in = <<<CSS
1528
/* these should not be changed, not even quotes */
1529
@font-face {
1530
  font-family: 'Roboto';
1531
  font-style: normal;
1532
  font-weight: 100;
1533
  src: url('../fonts/roboto-v15-latin-ext_latin-100.eot'); /* IE9 Compat Modes */
1534
  src: local('Roboto Thin'), local('Roboto-Thin'),
1535
       url('../fonts/roboto-v15-latin-ext_latin-100.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
1536
       url('../fonts/roboto-v15-latin-ext_latin-100.woff2') format('woff2'), /* Super Modern Browsers */
1537
       url('../fonts/roboto-v15-latin-ext_latin-100.woff') format('woff'), /* Modern Browsers */
1538
       url('../fonts/roboto-v15-latin-ext_latin-100.ttf') format('truetype'), /* Safari, Android, iOS */
1539
       url('../fonts/roboto-v15-latin-ext_latin-100.svg#Roboto') format('svg'); /* Legacy iOS */
1540
}
1541
@font-face {
1542
  font-family: 'Roboto';
1543
  font-style: normal;
1544
  font-weight: 100;
1545
  src: url('//fonts/roboto-v15-latin-ext_latin-100.eot'); /* IE9 Compat Modes */
1546
  src: local('Roboto Thin'), local('Roboto-Thin'),
1547
       url('//fonts/roboto-v15-latin-ext_latin-100.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
1548
       url('//fonts/roboto-v15-latin-ext_latin-100.woff2') format('woff2'), /* Super Modern Browsers */
1549
       url('//fonts/roboto-v15-latin-ext_latin-100.woff') format('woff'), /* Modern Browsers */
1550
       url('//fonts/roboto-v15-latin-ext_latin-100.ttf') format('truetype'), /* Safari, Android, iOS */
1551
       url('//fonts/roboto-v15-latin-ext_latin-100.svg#Roboto') format('svg'); /* Legacy iOS */
1552
}
1553
@font-face {
1554
  font-family: 'Roboto';
1555
  font-style: normal;
1556
  font-weight: 100;
1557
  src: url('/fonts/roboto-v15-latin-ext_latin-100.eot'); /* IE9 Compat Modes */
1558
  src: local('Roboto Thin'), local('Roboto-Thin'),
1559
       url('/fonts/roboto-v15-latin-ext_latin-100.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
1560
       url('/fonts/roboto-v15-latin-ext_latin-100.woff2') format('woff2'), /* Super Modern Browsers */
1561
       url('/fonts/roboto-v15-latin-ext_latin-100.woff') format('woff'), /* Modern Browsers */
1562
       url('/fonts/roboto-v15-latin-ext_latin-100.ttf') format('truetype'), /* Safari, Android, iOS */
1563
       url('/fonts/roboto-v15-latin-ext_latin-100.svg#Roboto') format('svg'); /* Legacy iOS */
1564
}
1565
@font-face {
1566
  font-family: 'Roboto';
1567
  font-style: normal;
1568
  font-weight: 100;
1569
  src: url('$siteurl/wp-content/themes/mytheme/fonts/roboto-v15-latin-ext_latin-100.eot'); /* IE9 Compat Modes */
1570
  src: local('Roboto Thin'), local('Roboto-Thin'),
1571
       url('$siteurl/wp-content/themes/mytheme/fonts/roboto-v15-latin-ext_latin-100.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
1572
       url('$siteurl/wp-content/themes/mytheme/fonts/roboto-v15-latin-ext_latin-100.woff2') format('woff2'), /* Super Modern Browsers */
1573
       url('$siteurl/wp-content/themes/mytheme/fonts/roboto-v15-latin-ext_latin-100.woff') format('woff'), /* Modern Browsers */
1574
       url('$siteurl/wp-content/themes/mytheme/fonts/roboto-v15-latin-ext_latin-100.ttf') format('truetype'), /* Safari, Android, iOS */
1575
       url('$siteurl/wp-content/themes/mytheme/fonts/roboto-v15-latin-ext_latin-100.svg#Roboto') format('svg'); /* Legacy iOS */
1576
}
1577
CSS;
1578
        // Expected without cdning fonts but cdn option is set.
1579
        $css_expected = <<<CSS
1580
/* these should not be changed, not even quotes */
1581
@font-face {
1582
  font-family: 'Roboto';
1583
  font-style: normal;
1584
  font-weight: 100;
1585
  src: url('../fonts/roboto-v15-latin-ext_latin-100.eot'); /* IE9 Compat Modes */
1586
  src: local('Roboto Thin'), local('Roboto-Thin'),
1587
       url('../fonts/roboto-v15-latin-ext_latin-100.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
1588
       url('../fonts/roboto-v15-latin-ext_latin-100.woff2') format('woff2'), /* Super Modern Browsers */
1589
       url('../fonts/roboto-v15-latin-ext_latin-100.woff') format('woff'), /* Modern Browsers */
1590
       url('../fonts/roboto-v15-latin-ext_latin-100.ttf') format('truetype'), /* Safari, Android, iOS */
1591
       url('../fonts/roboto-v15-latin-ext_latin-100.svg#Roboto') format('svg'); /* Legacy iOS */
1592
}
1593
@font-face {
1594
  font-family: 'Roboto';
1595
  font-style: normal;
1596
  font-weight: 100;
1597
  src: url('//fonts/roboto-v15-latin-ext_latin-100.eot'); /* IE9 Compat Modes */
1598
  src: local('Roboto Thin'), local('Roboto-Thin'),
1599
       url('//fonts/roboto-v15-latin-ext_latin-100.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
1600
       url('//fonts/roboto-v15-latin-ext_latin-100.woff2') format('woff2'), /* Super Modern Browsers */
1601
       url('//fonts/roboto-v15-latin-ext_latin-100.woff') format('woff'), /* Modern Browsers */
1602
       url('//fonts/roboto-v15-latin-ext_latin-100.ttf') format('truetype'), /* Safari, Android, iOS */
1603
       url('//fonts/roboto-v15-latin-ext_latin-100.svg#Roboto') format('svg'); /* Legacy iOS */
1604
}
1605
@font-face {
1606
  font-family: 'Roboto';
1607
  font-style: normal;
1608
  font-weight: 100;
1609
  src: url('/fonts/roboto-v15-latin-ext_latin-100.eot'); /* IE9 Compat Modes */
1610
  src: local('Roboto Thin'), local('Roboto-Thin'),
1611
       url('/fonts/roboto-v15-latin-ext_latin-100.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
1612
       url('/fonts/roboto-v15-latin-ext_latin-100.woff2') format('woff2'), /* Super Modern Browsers */
1613
       url('/fonts/roboto-v15-latin-ext_latin-100.woff') format('woff'), /* Modern Browsers */
1614
       url('/fonts/roboto-v15-latin-ext_latin-100.ttf') format('truetype'), /* Safari, Android, iOS */
1615
       url('/fonts/roboto-v15-latin-ext_latin-100.svg#Roboto') format('svg'); /* Legacy iOS */
1616
}
1617
@font-face {
1618
  font-family: 'Roboto';
1619
  font-style: normal;
1620
  font-weight: 100;
1621
  src: url('$siteurl/wp-content/themes/mytheme/fonts/roboto-v15-latin-ext_latin-100.eot'); /* IE9 Compat Modes */
1622
  src: local('Roboto Thin'), local('Roboto-Thin'),
1623
       url('$siteurl/wp-content/themes/mytheme/fonts/roboto-v15-latin-ext_latin-100.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
1624
       url('$siteurl/wp-content/themes/mytheme/fonts/roboto-v15-latin-ext_latin-100.woff2') format('woff2'), /* Super Modern Browsers */
1625
       url('$siteurl/wp-content/themes/mytheme/fonts/roboto-v15-latin-ext_latin-100.woff') format('woff'), /* Modern Browsers */
1626
       url('$siteurl/wp-content/themes/mytheme/fonts/roboto-v15-latin-ext_latin-100.ttf') format('truetype'), /* Safari, Android, iOS */
1627
       url('$siteurl/wp-content/themes/mytheme/fonts/roboto-v15-latin-ext_latin-100.svg#Roboto') format('svg'); /* Legacy iOS */
1628
}
1629
CSS;
1630
        // Test without moving fonts to CDN, but cdn option is set.
1631
        $instance = new autoptimizeStyles( $css_in );
1632
        $instance->setOption( 'cdn_url', $urls['cdnurl'] );
1633
        $css_actual = $instance->rewrite_assets( $css_in );
1634
        $this->assertEquals( $css_expected, $css_actual );
1635
    }
1636
1637
    public function test_assets_regex_replaces_multi_bg_images()
1638
    {
1639
        $urls   = $this->get_urls();
1640
        $sub    = $urls['subfolder'];
1641
        $cdnurl = $urls['cdnurl'];
1642
1643
        $in = <<<CSS
1644
body:after {
1645
  content: url(/img/close.png) url(/img/loading.gif) url(/img/prev.png) url(/img/next.png);
1646
}
1647
CSS;
1648
1649
        $expected = <<<CSS
1650
body:after {
1651
  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);
1652
}
1653
CSS;
1654
1655
        $instance = new autoptimizeStyles( $in );
1656
        $instance->setOption( 'cdn_url', $cdnurl );
1657
        $actual = $instance->rewrite_assets( $in );
1658
1659
        $this->assertEquals( $expected, $actual );
1660
    }
1661
1662
    public function test_at_supports_spacing_issue_110()
1663
    {
1664
        $in       = <<<CSS
1665
@supports (-webkit-filter: blur(3px)) or (filter: blur(3px)) {
1666
    .blur {
1667
        filter:blur(3px);
1668
    }
1669
}
1670
@supports((position:-webkit-sticky) or (position:sticky)) {
1671
    .sticky { position:sticky; }
1672
}
1673
CSS;
1674
        $expected = <<<CSS
1675
@supports (-webkit-filter:blur(3px)) or (filter:blur(3px)){.blur{filter:blur(3px)}}@supports((position:-webkit-sticky) or (position:sticky)){.sticky{position:sticky}}
1676
CSS;
1677
1678
        $instance = new autoptimizeStyles( $in );
1679
        $actual   = $instance->run_minifier_on( $in );
1680
1681
        $this->assertEquals( $expected, $actual );
1682
    }
1683
1684 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...
1685
    {
1686
        $urls   = $this->get_urls();
1687
        $sub    = $urls['subfolder'];
1688
        $cdnurl = $urls['cdnurl'];
1689
1690
        $in = <<<HTML
1691
<style type="text/css">
1692
@import url("foo.css?a&#038;b");
1693
@import url("bar.css");
1694
</style>
1695
HTML;
1696
1697
        $expected = '<style type="text/css" media="all">@import url(' . $cdnurl . '/' . $sub . 'foo.css?a&#038;b);@import url(' . $cdnurl . '/' . $sub . 'bar.css);</style><!--noptimize--><!-- Autoptimize found a problem with the HTML in your Theme, tag `title` missing --><!--/noptimize-->';
1698
1699
        $options = [
1700
            'autoptimizeStyles' => $this->getAoStylesDefaultOptions(),
1701
        ];
1702
1703
        $instance = new autoptimizeStyles( $in );
1704
        $instance->read( $options['autoptimizeStyles'] );
1705
        $instance->minify();
1706
        $instance->cache();
1707
        $actual = $instance->getcontent();
1708
        $this->assertEquals( $expected, $actual );
1709
    }
1710
1711
    public function test_fixurls_with_at_imports_and_media_queries()
1712
    {
1713
        $urls      = $this->get_urls();
1714
        $prsiteurl = $urls['prsiteurl'];
1715
        $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...
1716
1717
        $in  = '@import "foo.css"; @import "bar.css" (orientation:landscape);';
1718
        $exp = '@import url(' . $prsiteurl . '/wp-content/themes/my-theme/foo.css); @import url(' . $prsiteurl . '/wp-content/themes/my-theme/bar.css) (orientation:landscape);';
1719
1720
        $actual = autoptimizeStyles::fixurls( ABSPATH . 'wp-content/themes/my-theme/style.css', $in );
1721
        $this->assertEquals( $exp, $actual );
1722
    }
1723
1724 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...
1725
    {
1726
        $urls   = $this->get_urls();
1727
        $sub    = $urls['subfolder'];
1728
        $cdnurl = $urls['cdnurl'];
1729
1730
        $in = <<<HTML
1731
<style type="text/css">
1732
@import "foo.css"; @import "bar.css" (orientation:landscape);
1733
</style>
1734
HTML;
1735
1736
        $expected = '<style type="text/css" media="all">@import url(' . $cdnurl . '/' . $sub . 'foo.css);@import url(' . $cdnurl . '/' . $sub . 'bar.css) (orientation:landscape);</style><!--noptimize--><!-- Autoptimize found a problem with the HTML in your Theme, tag `title` missing --><!--/noptimize-->';
1737
1738
        $options = [
1739
            'autoptimizeStyles' => $this->getAoStylesDefaultOptions(),
1740
        ];
1741
1742
        $instance = new autoptimizeStyles( $in );
1743
        $instance->read( $options['autoptimizeStyles'] );
1744
        $instance->minify();
1745
        $instance->cache();
1746
1747
        $actual = $instance->getcontent();
1748
        $this->assertEquals( $expected, $actual );
1749
    }
1750
1751
    public function test_cache_size_checker_hooked_by_default()
1752
    {
1753
        $this->assertNotEmpty( autoptimizeCacheChecker::SCHEDULE_HOOK );
1754
1755
        // No schedule, because it's only added when is_admin() is true.
1756
        $this->assertEquals( false, wp_get_schedule( autoptimizeCacheChecker::SCHEDULE_HOOK ) );
1757
1758
        // Proving that setup() sets the schedule as needed.
1759
        $checker = new autoptimizeCacheChecker();
1760
        $checker->setup();
1761
        $this->assertEquals( 'twicedaily', wp_get_schedule( autoptimizeCacheChecker::SCHEDULE_HOOK ) );
1762
    }
1763
1764
    public function test_cache_size_checker_disabled_with_filter()
1765
    {
1766
        add_filter( 'autoptimize_filter_cachecheck_do', '__return_false' );
1767
1768
        $checker = new autoptimizeCacheChecker();
1769
        $checker->setup();
1770
        $this->assertEquals( false, wp_get_schedule( autoptimizeCacheChecker::SCHEDULE_HOOK ) );
1771
1772
        remove_all_filters( 'autoptimize_filter_cachecheck_do' );
1773
    }
1774
1775
    public function test_is_start_buffering_hooked_properly()
1776
    {
1777
        $instance = autoptimize();
1778
1779
        /**
1780
         * TODO/FIXME: ideally, we'd test all possible setups, but once we set
1781
         * a constant, there's no going back, unless we use runkit or somesuch:
1782
         * https://www.theaveragedev.com/mocking-constants-in-tests/.
1783
         */
1784
1785
        if ( defined( 'AUTOPTIMIZE_INIT_EARLIER' ) ) {
1786
            $this->assertEquals(
1787
                autoptimizeMain::INIT_EARLIER_PRIORITY,
1788
                has_action( 'init', array( $instance, 'start_buffering' ) )
1789
            );
1790
            $this->assertTrue( ! defined( 'AUTOPTIMIZE_HOOK_INTO' ) );
1791
        }
1792
1793
        /*
1794
        // AUTOPTIMIZE_HOOK_INTO only exists if AUTOPTIMIZE_INIT_EARLIER doesnt
1795
        $this->assertEquals(
1796
            autoptimizeMain::DEFAULT_HOOK_PRIORITY,
1797
            has_action( constant( 'AUTOPTIMIZE_HOOK_INTO' ), array( $instance, 'start_buffering' ) )
1798
        );
1799
        $this->assertFalse(
1800
            has_action( 'init', array( $instance, 'start_buffering' ) )
1801
        );
1802
        */
1803
    }
1804
1805
    public function test_inline_and_defer_markup()
1806
    {
1807
        add_filter( 'autoptimize_filter_css_defer', '__return_true' );
1808
        add_filter( 'autoptimize_filter_css_defer_inline', '__return_true' );
1809
1810
        $actual = $this->ao->end_buffering( $this->get_test_markup() );
1811
        if ( is_multisite() ) {
1812
            $this->assertEquals( $this->get_test_markup_output_inline_defer_ms(), $actual );
1813
        } else {
1814
            $this->assertEquals( $this->get_test_markup_output_inline_defer(), $actual );
1815
        }
1816
1817
        remove_all_filters( 'autoptimize_filter_css_defer' );
1818
        remove_all_filters( 'autoptimize_filter_css_defer_inline' );
1819
    }
1820
1821 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...
1822
    {
1823
        $opts = $this->getAoScriptsDefaultOptions();
1824
1825
        // Aggregating: true by default.
1826
        $scripts = new autoptimizeScripts( '' );
1827
        $scripts->read( $opts );
1828
        $this->assertTrue( $scripts->aggregating() );
1829
1830
        // Aggregating: option=true (dontaggregate=false by default).
1831
        $opts['aggregate'] = true;
1832
        $scripts           = new autoptimizeScripts( '' );
1833
        $scripts->read( $opts );
1834
        $this->assertTrue( $scripts->aggregating() );
1835
1836
        // Aggregating: option=true, dontaggregate=false explicit.
1837
        $opts['aggregate'] = true;
1838
        add_filter( 'autoptimize_filter_js_dontaggregate', '__return_false' );
1839
        $scripts = new autoptimizeScripts( '' );
1840
        $scripts->read( $opts );
1841
        $this->assertTrue( $scripts->aggregating() );
1842
        remove_all_filters( 'autoptimize_filter_js_dontaggregate' );
1843
1844
        // Not aggregating: option=true, dontaggregate=true.
1845
        $opts['aggregate'] = true;
1846
        add_filter( 'autoptimize_filter_js_dontaggregate', '__return_true' );
1847
        $scripts = new autoptimizeScripts( '' );
1848
        $scripts->read( $opts );
1849
        $this->assertFalse( $scripts->aggregating() );
1850
        remove_all_filters( 'autoptimize_filter_js_dontaggregate' );
1851
1852
        // Not aggregating: option=false, dontaggregate=false.
1853
        $opts['aggregate'] = false;
1854
        add_filter( 'autoptimize_filter_js_dontaggregate', '__return_false' );
1855
        $scripts = new autoptimizeScripts( '' );
1856
        $scripts->read( $opts );
1857
        $this->assertFalse( $scripts->aggregating() );
1858
        remove_all_filters( 'autoptimize_filter_js_dontaggregate' );
1859
1860
        // Not aggregating: option=false, dontaggregate=true.
1861
        $opts['aggregate'] = false;
1862
        add_filter( 'autoptimize_filter_js_dontaggregate', '__return_true' );
1863
        $scripts = new autoptimizeScripts( '' );
1864
        $scripts->read( $opts );
1865
        $this->assertFalse( $scripts->aggregating() );
1866
        remove_all_filters( 'autoptimize_filter_js_dontaggregate' );
1867
    }
1868
1869 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...
1870
    {
1871
        $opts = $this->getAoStylesDefaultOptions();
1872
1873
        // Aggregating: true by default.
1874
        $styles = new autoptimizeStyles( '' );
1875
        $this->assertTrue( $styles->aggregating() );
1876
1877
        // Aggregating: option=true (dontaggregate=false by default).
1878
        $opts['aggregate'] = true;
1879
        $styles            = new autoptimizeStyles( '' );
1880
        $styles->read( $opts );
1881
        $this->assertTrue( $styles->aggregating() );
1882
1883
        // Aggregating: option=true, dontaggregate=false explicit.
1884
        $opts['aggregate'] = true;
1885
        add_filter( 'autoptimize_filter_css_dontaggregate', '__return_false' );
1886
        $styles = new autoptimizeStyles( '' );
1887
        $styles->read( $opts );
1888
        $this->assertTrue( $styles->aggregating() );
1889
        remove_all_filters( 'autoptimize_filter_css_dontaggregate' );
1890
1891
        // Not aggregating: option=true, dontaggregate=true.
1892
        $opts['aggregate'] = true;
1893
        add_filter( 'autoptimize_filter_css_dontaggregate', '__return_true' );
1894
        $styles = new autoptimizeStyles( '' );
1895
        $styles->read( $opts );
1896
        $this->assertFalse( $styles->aggregating() );
1897
        remove_all_filters( 'autoptimize_filter_css_dontaggregate' );
1898
1899
        // Not aggregating: option=false, dontaggregate=false.
1900
        $opts['aggregate'] = false;
1901
        add_filter( 'autoptimize_filter_css_dontaggregate', '__return_false' );
1902
        $styles = new autoptimizeStyles( '' );
1903
        $styles->read( $opts );
1904
        $this->assertFalse( $styles->aggregating() );
1905
        remove_all_filters( 'autoptimize_filter_css_dontaggregate' );
1906
1907
        // Not aggregating: option=false, dontaggregate=true.
1908
        $opts['aggregate'] = false;
1909
        add_filter( 'autoptimize_filter_css_dontaggregate', '__return_true' );
1910
        $styles = new autoptimizeStyles( '' );
1911
        $styles->read( $opts );
1912
        $this->assertFalse( $styles->aggregating() );
1913
        remove_all_filters( 'autoptimize_filter_css_dontaggregate' );
1914
    }
1915
1916
    public function test_css_minify_single_with_cdning()
1917
    {
1918
        $pathname = dirname( __FILE__ ) . '/fixtures/minify-single.css';
1919
        $opts     = $this->getAoStylesDefaultOptions();
1920
        $styles   = new autoptimizeStyles( '' );
1921
        $styles->read( $opts );
1922
1923
        $url = $styles->minify_single( $pathname, $cache_miss = true );
1924
1925
        // Minified url filename + its pointed to cdn.
1926
        $this->assertContains( AUTOPTIMIZE_CACHE_CHILD_DIR, $url );
1927
        $this->assertContains( '/autoptimize_single_', $url );
1928
        $this->assertContains( $styles->cdn_url, $url );
1929
1930
        // Actual minified css contents are minified and cdn-ed.
1931
        $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 1923 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...
1932
        $contents = file_get_contents( $path );
1933
        $this->assertContains( $styles->cdn_url, $contents );
1934
        $this->assertContains( '.bg{background:url(' . $styles->cdn_url, $contents );
1935
    }
1936
1937
    public function test_ao_partners_instantiation_without_explicit_include()
1938
    {
1939
        $partners = new autoptimizePartners();
1940
        $this->assertTrue( $partners instanceof autoptimizePartners );
1941
    }
1942
1943 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...
1944
    {
1945
        $markup   = <<<MARKUP
1946
<script>
1947
<!-- End Support AJAX add to cart -->
1948
var a = "b";
1949
</script>
1950
MARKUP;
1951
        $expected = <<<MARKUP
1952
<script><!-- End Support AJAX add to cart -->
1953
var a = "b";</script>
1954
MARKUP;
1955
1956
        $markup2 = <<<MARKUP
1957
<script>
1958
var a = "b";
1959
<!-- End Support AJAX add to cart -->
1960
</script>
1961
MARKUP;
1962
1963
        $expected2 = <<<MARKUP
1964
<script>var a = "b";
1965
<!-- End Support AJAX add to cart --></script>
1966
MARKUP;
1967
1968
        // When keepcomments is true.
1969
        $options = [
1970
            'autoptimizeHTML' => [
1971
                'keepcomments' => true,
1972
            ],
1973
        ];
1974
1975
        $instance = new autoptimizeHTML( $markup );
1976
        $instance->read( $options['autoptimizeHTML'] );
1977
        $instance->minify();
1978
        $actual = $instance->getcontent();
1979
        $this->assertEquals( $expected, $actual );
1980
1981
        $instance = new autoptimizeHTML( $markup2 );
1982
        $instance->read( $options['autoptimizeHTML'] );
1983
        $instance->minify();
1984
        $actual2 = $instance->getcontent();
1985
        $this->assertEquals( $expected2, $actual2 );
1986
    }
1987
1988 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...
1989
    {
1990
        // Default case, html comments removed (keepcomments = false).
1991
        $markup1   = <<<MARKUP
1992
<script>
1993
var a = "b";
1994
<!-- End Support AJAX add to cart -->
1995
</script>
1996
MARKUP;
1997
        $expected1 = <<<MARKUP
1998
<script>var a = "b";
1999
<!-- End Support AJAX add to cart</script>
2000
MARKUP;
2001
2002
        $markup2   = <<<MARKUP
2003
<script>
2004
<!-- End Support AJAX add to cart -->
2005
var a = "b";
2006
</script>
2007
MARKUP;
2008
        $expected2 = <<<MARKUP
2009
<script>End Support AJAX add to cart -->
2010
var a = "b";</script>
2011
MARKUP;
2012
2013
        $options = [
2014
            'autoptimizeHTML' => [
2015
                'keepcomments' => false,
2016
            ],
2017
        ];
2018
2019
        $instance = new autoptimizeHTML( $markup1 );
2020
        $instance->read( $options['autoptimizeHTML'] );
2021
        $instance->minify();
2022
        $actual = $instance->getcontent();
2023
        $this->assertEquals( $expected1, $actual );
2024
2025
        $instance = new autoptimizeHTML( $markup2 );
2026
        $instance->read( $options['autoptimizeHTML'] );
2027
        $instance->minify();
2028
        $actual2 = $instance->getcontent();
2029
        $this->assertEquals( $expected2, $actual2 );
2030
    }
2031
2032 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...
2033
    {
2034
        $markup = <<<MARKUP
2035
<script>
2036
<!-- // invisible for old browsers
2037
var a = "z";
2038
// -->
2039
</script>
2040
MARKUP;
2041
2042
        $expected = <<<MARKUP
2043
<script>// invisible for old browsers
2044
var a = "z";</script>
2045
MARKUP;
2046
2047
        $options = [
2048
            'autoptimizeHTML' => [
2049
                'keepcomments' => false,
2050
            ],
2051
        ];
2052
2053
        $instance = new autoptimizeHTML( $markup );
2054
        $instance->read( $options['autoptimizeHTML'] );
2055
        $instance->minify();
2056
        $actual = $instance->getcontent();
2057
        $this->assertEquals( $expected, $actual );
2058
    }
2059
2060 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...
2061
    {
2062
        $markup = <<<MARKUP
2063
<script>
2064
<!-- // invisible for old browsers
2065
var a = "z";
2066
// -->
2067
</script>
2068
MARKUP;
2069
2070
        $expected = <<<MARKUP
2071
<script><!-- // invisible for old browsers
2072
var a = "z";
2073
// --></script>
2074
MARKUP;
2075
2076
        $options = [
2077
            'autoptimizeHTML' => [
2078
                'keepcomments' => true,
2079
            ],
2080
        ];
2081
2082
        $instance = new autoptimizeHTML( $markup );
2083
        $instance->read( $options['autoptimizeHTML'] );
2084
        $instance->minify();
2085
        $actual = $instance->getcontent();
2086
        $this->assertEquals( $expected, $actual );
2087
    }
2088
2089
    public function test_utils_mbstring_availabilty_overriding()
2090
    {
2091
        $orig     = autoptimizeUtils::mbstring_available();
2092
        $opposite = ! $orig;
2093
2094
        $this->assertSame( $orig, autoptimizeUtils::mbstring_available() );
2095
        // Override works...
2096
        $this->assertSame( $opposite, autoptimizeUtils::mbstring_available( $opposite ) );
2097
        // And override remains cached as the last version.
2098
        $this->assertSame( $opposite, autoptimizeUtils::mbstring_available() );
2099
    }
2100
2101
    public function test_utils_mbstring_basics()
2102
    {
2103
        // Turn on mbstring usage.
2104
        autoptimizeUtils::mbstring_available( true );
2105
2106
        $this->assertSame( 2, autoptimizeUtils::strlen( "\x00\xFF", 'ASCII' ) );
2107
        $this->assertSame( 2, autoptimizeUtils::strlen( "\x00\xFF", 'CP850' ) );
2108
        $this->assertSame( 3, autoptimizeUtils::strlen( '한국어' ) );
2109
2110
        $this->assertFalse( @autoptimizeUtils::strpos( 'abc', '' ) );
2111
        $this->assertFalse( @autoptimizeUtils::strpos( 'abc', 'a', -1 ) );
2112
        $this->assertFalse( autoptimizeUtils::strpos( 'abc', 'd' ) );
2113
        $this->assertFalse( autoptimizeUtils::strpos( 'abc', 'a', 3 ) );
2114
        $this->assertSame( 1, autoptimizeUtils::strpos( '한국어', '국' ) );
2115
    }
2116
2117
    /**
2118
     * @dataProvider provider_utils_substr_replace
2119
     */
2120
    function test_utils_substr_replace_basics_mbstring( $s, $repl, $start, $len, $expected )
2121
    {
2122
        // Force mbstring code path...
2123
        autoptimizeUtils::mbstring_available( true );
2124
        $this->assertEquals( $expected, autoptimizeUtils::substr_replace( $s, $repl, $start, $len ) );
2125
    }
2126
2127
    public function provider_utils_substr_replace()
2128
    {
2129
        $str  = 'try this';
2130
        $repl = 'bala ';
2131
2132
        return [
2133
            [
2134
                $str,
2135
                $repl,
2136
                2,
2137
                null,
2138
                'trbala ',
2139
            ],
2140
            [
2141
                $str,
2142
                $repl,
2143
                2,
2144
                3,
2145
                'trbala his',
2146
            ],
2147
            [
2148
                $str,
2149
                $repl,
2150
                2,
2151
                0,
2152
                'trbala y this',
2153
            ],
2154
            [
2155
                $str,
2156
                $repl,
2157
                2,
2158
                -2,
2159
                'trbala is',
2160
            ],
2161
        ];
2162
    }
2163
2164 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...
2165
    {
2166
        autoptimizeUtils::mbstring_available( false );
2167
2168
        $str = 'Ascii';
2169
2170
        $this->assertSame( 'Añ', autoptimizeUtils::substr_replace( $str, 'ñ', 1 ) );
2171
        $this->assertSame( 'ñcii', autoptimizeUtils::substr_replace( $str, 'ñ', 0, 2 ) );
2172
        $this->assertSame( 'Asñx', autoptimizeUtils::substr_replace( $str, 'ñx', 2, 3 ) );
2173
        $this->assertSame( 'Asz', autoptimizeUtils::substr_replace( $str, 'z', 2, 10 ) );
2174
        $this->assertSame( 'Añii', autoptimizeUtils::substr_replace( $str, 'ñ', 1, 2 ) );
2175
    }
2176
2177 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...
2178
    {
2179
        autoptimizeUtils::mbstring_available( true );
2180
2181
        $str = 'âønæë';
2182
2183
        $this->assertSame( 'âñ', autoptimizeUtils::substr_replace( $str, 'ñ', 1 ) ); // No length.
2184
        $this->assertSame( 'ñnæë', autoptimizeUtils::substr_replace( $str, 'ñ', 0, 2 ) );
2185
        $this->assertSame( 'âøñx', autoptimizeUtils::substr_replace( $str, 'ñx', 2, 3 ) );
2186
        $this->assertSame( 'âøz', autoptimizeUtils::substr_replace( $str, 'z', 2, 10 ) ); // Length larger than possible...
2187
        $this->assertSame( 'âñæë', autoptimizeUtils::substr_replace( $str, 'ñ', 1, 2 ) );
2188
    }
2189
2190 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...
2191
    {
2192
        // Disable mbstring which should fall ack to substr_replace...
2193
        autoptimizeUtils::mbstring_available( false );
2194
2195
        $str = 'Ascii';
2196
2197
        $this->assertSame( 'Añ', autoptimizeUtils::substr_replace( $str, 'ñ', 1 ) );
2198
        $this->assertSame( 'ñcii', autoptimizeUtils::substr_replace( $str, 'ñ', 0, 2 ) );
2199
        $this->assertSame( 'Asñx', autoptimizeUtils::substr_replace( $str, 'ñx', 2, 3 ) );
2200
        $this->assertSame( 'Asz', autoptimizeUtils::substr_replace( $str, 'z', 2, 10 ) );
2201
        $this->assertSame( 'Añii', autoptimizeUtils::substr_replace( $str, 'ñ', 1, 2 ) );
2202
    }
2203
2204
    function test_default_substr_replace_with_utf8_input_string()
2205
    {
2206
        // Disabling mbstring, falling back to substr_replace...
2207
        autoptimizeUtils::mbstring_available( false );
2208
2209
        // This is really impossible to make work properly, since
2210
        // any start/len parameters we give are working with bytes instead
2211
        // of characters, shit just breaks.
2212
        $str = 'âønæë';
2213
2214
        // $this->assertSame( '�ñ', autoptimizeUtils::substr_replace( $str, 'ñ', 1 ) ); // No length.
2215
        // $this->assertSame( 'ñ�næë', autoptimizeUtils::substr_replace( $str, 'ñ', 1, 2 ) );
2216
        $this->assertSame( 'ñønæë', autoptimizeUtils::substr_replace( $str, 'ñ', 0, 2 ) );
2217
        $this->assertSame( 'âñxæë', autoptimizeUtils::substr_replace( $str, 'ñx', 2, 3 ) );
2218
        $this->assertSame( 'âz', autoptimizeUtils::substr_replace( $str, 'z', 2, 10 ) ); // Length larger than possible...
2219
    }
2220
2221
    public function test_cache_fast_delete()
2222
    {
2223
        add_filter( 'autoptimize_filter_cache_clear_advanced', '__return_true' );
2224
2225
        autoptimizeCache::clearall_actionless();
2226
2227
        remove_all_filters( 'autoptimize_filter_cache_clear_advanced' );
2228
    }
2229
2230
    public function test_delete_advanced_cache_clear_artifacts()
2231
    {
2232
        $this->assertTrue( autoptimizeCache::delete_advanced_cache_clear_artifacts() );
2233
    }
2234
2235
    public function provider_canonicalization()
2236
    {
2237
        return array(
2238
            array( '../common', 'common' ),
2239
            array( '../what-does-this-mean/really?/', 'what-does-this-mean/really?/' ),
2240
            array( '../../what/where/how', 'what/where/how' ),
2241
            array( '/../more.dots.please/', '/more.dots.please/' ),
2242
            array( '/../../what/where/how', '/what/where/how' ),
2243
            array( '/a/b/c/../../../d/e/file.txt', '/d/e/file.txt' ),
2244
            array( 'a/b/../c', 'a/c' ),
2245
            array( './../../etc/passwd', './etc/passwd' ),
2246
            array( '/var/.////./user/./././..//.//../////../././.././test/////', '/test/' ),
2247
            array( '/var/user/./././.././../.././././test/', '/test/' ),
2248
            array( '/hello/0//how/../are/../you', '/hello/0/you' ),
2249
            array( '', '' ),
2250
            array( '.', '.' ),
2251
            array( '..', '..' ),
2252
            array( './..', './..' ),
2253
            array( '../.', '.' ),
2254
            // This might be debatable...
2255
            array( '../..', '..' ),
2256
        );
2257
    }
2258
2259
    /**
2260
     * @dataProvider provider_canonicalization
2261
     */
2262
    public function test_path_canonicalize( $path, $canonicalized )
2263
    {
2264
        $this->assertSame( $canonicalized, autoptimizeUtils::path_canonicalize( $path ) );
2265
    }
2266
2267
    /**
2268
     * For a site in subfolder, CDN-rewrite used to magically include
2269
     * the subfolder when rewriting assets to CDN.
2270
     * That behavior can be turned off by returning false via
2271
     * `autoptimize_filter_cdn_magic_path_check`.
2272
     * If it's false, cdn-rewriting should not include subfolder even
2273
     * when the site is actually in a subfolder/subdirectory.
2274
     */
2275
    public function test_autoptimize_filter_cdn_magic_path_check()
2276
    {
2277
        $cdnurl = 'http://cdn.example.org';
2278
        add_filter( 'autoptimize_filter_cdn_magic_path_check', '__return_false', 10, 2 );
2279
2280
        // Even when site is in a subfolder, the resulting cdn-rewritten url
2281
        // should not magically include it, due to the above filter.
2282
        // The second parameter is here to force a cache miss and re-run
2283
        // the filter since we're using the same cdn url all over the place,
2284
        // but want to prove different things with it.
2285
        $this->assertSame( $cdnurl, autoptimizeUtils::tweak_cdn_url_if_needed( $cdnurl, true ) );
2286
2287
        remove_all_filters( 'autoptimize_filter_cdn_magic_path_check' );
2288
    }
2289
2290
    /**
2291
     * Test image optimization in autoptimizeExtra.php.
2292
     *
2293
     * Default case: img with srcsets
2294
     */
2295 View Code Duplication
    public function test_extra_imgopt()
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...
2296
    {
2297
        $urls       = $this->get_urls();
2298
        $siteurl    = $urls['siteurl'];
2299
        $imgopthost = $urls['imgopthost'];
2300
2301
        $markup = <<<MARKUP
2302
<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" />
2303
MARKUP;
2304
2305
        $expected = <<<MARKUP
2306
<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" />
2307
MARKUP;
2308
2309
        $instance = new autoptimizeExtra();
2310
        $actual = $instance->filter_optimize_images( $markup );
2311
        $this->assertEquals( $expected, $actual );
2312
    }
2313
2314
    /**
2315
     * Test image optimization in autoptimizeExtra.php.
2316
     *
2317
     * Exception case: image served by .php, should not be proxied
2318
     */
2319
    public function test_extra_imgopt_php()
2320
    {
2321
        $siteurl = $this->get_urls()['siteurl'];
2322
2323
        $markup = <<<MARKUP
2324
<img src='$siteurl/wp-content/plugins/imageplugin/image.php?id=16' width='400' height='200'>
2325
MARKUP;
2326
2327
        $expected = <<<MARKUP
2328
<img src='$siteurl/wp-content/plugins/imageplugin/image.php?id=16' width='400' height='200'>
2329
MARKUP;
2330
2331
        $instance = new autoptimizeExtra();
2332
        $actual = $instance->filter_optimize_images( $markup );
2333
        $this->assertEquals( $expected, $actual );
2334
    }
2335
2336
    /**
2337
     * Test image optimization in autoptimizeExtra.php.
2338
     *
2339
     * Alternate case: lazy loaded images with srcsets (using wp rocket variant HTML)
2340
     */
2341 View Code Duplication
    public function test_extra_imgopt_lazy()
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...
2342
    {
2343
        $urls       = $this->get_urls();
2344
        $siteurl    = $urls['siteurl'];
2345
        $imgopthost = $urls['imgopthost'];
2346
2347
        $markup = <<<MARKUP
2348
<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" />
2349
MARKUP;
2350
2351
        $expected = <<<MARKUP
2352
<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" />
2353
MARKUP;
2354
2355
        $instance = new autoptimizeExtra();
2356
        $actual = $instance->filter_optimize_images( $markup );
2357
        $this->assertEquals( $expected, $actual );
2358
    }
2359
2360
    /**
2361
     * @dataProvider provider_str_is_valid_regex
2362
     */
2363
    public function test_str_is_valid_regex($str, $expected)
2364
    {
2365
        $actual = autoptimizeUtils::str_is_valid_regex($str);
2366
2367
        $this->assertEquals( $expected, $actual );
2368
    }
2369
2370
    public function provider_str_is_valid_regex()
2371
    {
2372
        return [
2373
            ['<!--[if', false],
2374
            ['&lt;--[if', false],
2375
            ['/booya/i', true],
2376
            ['~Valid(Regular)Expression~', true],
2377
        ];
2378
    }
2379
2380
    /**
2381
     * @dataProvider provider_protocol_relative_tests
2382
     */
2383
    public function test_is_protocol_relative( $str, $expected )
2384
    {
2385
        $actual = autoptimizeUtils::is_protocol_relative( $str );
2386
2387
        $this->assertEquals( $expected, $actual );
2388
    }
2389
2390
    public function provider_protocol_relative_tests()
2391
    {
2392
        return [
2393
            ['//something-that-might-be-an-url-but-isnt-really', true],
2394
            ['', false],
2395
            [null, false],
2396
            ['booya/i', false],
2397
            ['/root-relative', false],
2398
            ['http://what.ever/', false],
2399
            ['https://booya.kasha', false],
2400
        ];
2401
    }
2402
2403 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...
2404
    {
2405
        $css = <<<MARKUP
2406
img.centered, .aligncenter {
2407
    -webkit-box-shadow: none;
2408
    -moz-box-shadow: none;
2409
    box-shadow: none;
2410
MARKUP;
2411
2412
        $expected = 'img.centered,.aligncenter{-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}';
2413
2414
        $instance = new autoptimizeStyles( $css );
2415
        $minified = $instance->run_minifier_on( $css );
2416
2417
        $this->assertEquals( $expected, $minified );
2418
    }
2419
2420
    public function test_css_font_names_mangling()
2421
    {
2422
        // Properly quoted font names dont get mangled.
2423
        $css      = 'h2{font-family:"Archivo Black"}';
2424
        $instance = new autoptimizeStyles( $css );
2425
        $actual   = $instance->run_minifier_on( $css );
2426
        $this->assertEquals( $css, $actual );
2427
2428
        // When not quoted, 'Black' used to become '#000', but not anymore... :)
2429
        $css_unquoted = 'h2{font-family:Archivo Black;}';
2430
        $expected     = 'h2{font-family:Archivo Black}';
2431
        $instance     = new autoptimizeStyles( $css_unquoted );
2432
        $actual       = $instance->run_minifier_on( $css_unquoted );
2433
        $this->assertEquals( $expected, $actual );
2434
2435
        $css_unquoted = 'h1{font:italic 1.2em Fira White,serif}';
2436
        $instance     = new autoptimizeStyles( $css_unquoted );
2437
        $actual       = $instance->run_minifier_on( $css_unquoted );
2438
        $this->assertEquals( $css_unquoted, $actual );
2439
    }
2440
2441
    public function test_jsminphp_string_literal_minification()
2442
    {
2443
        $js = '
2444
// comment
2445
`line
2446
break` + `he  llo`; foo`hel( \'\');lo`; `he\nl\`lo`; (`he${one + two}`)
2447
';
2448
2449
        $expected = '`line
2450
break`+`he  llo`;foo`hel( \'\');lo`;`he\nl\`lo`;(`he${one + two}`)';
2451
2452
        $actual = JSMin::minify( $js );
2453
        $this->assertEquals( $expected, $actual );
2454
    }
2455
}
2456