1<?php
2// This file is part of Moodle - http://moodle.org/
3//
4// Moodle is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// Moodle is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
16
17/**
18 * Tests the user agent class.
19 *
20 * @package    core
21 * @copyright  2013 Sam Hemelryk
22 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23 */
24
25/**
26 * User agent test suite.
27 *
28 * @package    core
29 * @copyright  2013 Sam Hemelryk
30 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
31 */
32class core_useragent_testcase extends advanced_testcase {
33
34    /**
35     * Restores the user agent to the default one.
36     */
37    public function tearDown(): void {
38        core_useragent::instance(true);
39    }
40
41    public function user_agents_providers() {
42        // Note: When adding new entries to this list, please ensure that any new browser versions are added to the corresponding list.
43        // This ensures that regression tests are applied to all known user agents.
44        return array(
45            'Microsoft Edge for Windows 10 Desktop' => array(
46                'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36 Edge/12.10136',
47                array(
48                    'is_edge'                       => true,
49                    'check_edge_version'            => array(
50                        '12'                        => true,
51                    ),
52
53                    // Edge pretends to be WebKit.
54                    'is_webkit'                     => true,
55
56                    // Edge pretends to be Chrome.
57                    // Note: Because Edge pretends to be Chrome, it will not be picked up as a Safari browser.
58                    'is_chrome'                     => true,
59                    'check_chrome_version'          => array(
60                        '7'                         => true,
61                        '8'                         => true,
62                        '10'                        => true,
63                        '39'                        => true,
64                    ),
65
66                    'versionclasses'                => array(
67                        'edge',
68                    ),
69                ),
70            ),
71            'Microsoft Edge for Windows 10 Mobile' => array(
72                'Mozilla/5.0 (Windows Phone 10.0; Android 4.2.1; DEVICE INFO) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Mobile Safari/537.36 Edge/12.10136',
73                array(
74                    'is_edge'                       => true,
75                    'check_edge_version'              => array(
76                        '12'                        => true,
77                    ),
78
79                    // Edge pretends to be WebKit.
80                    'is_webkit'                     => true,
81
82                    // Mobile Edge pretends to be Android.
83                    'is_webkit_android'             => true,
84                    'check_webkit_android_version'  => array(
85                        '525'                       => true,
86                        '527'                       => true,
87                    ),
88
89                    // Edge pretends to be Chrome.
90                    // Note: Because Edge pretends to be Chrome, it will not be picked up as a Safari browser.
91                    'is_chrome'                     => true,
92                    'check_chrome_version'          => array(
93                        '7'                         => true,
94                        '8'                         => true,
95                        '10'                        => true,
96                        '39'                        => true,
97                    ),
98
99                    'versionclasses'                => array(
100                        'edge'
101                    ),
102
103                    'devicetype'                    => 'mobile',
104                ),
105            ),
106            // Windows 98; Internet Explorer 5.0.
107            array(
108                'Mozilla/4.0 (compatible; MSIE 5.00; Windows 98)',
109                array(
110                    // MSIE 5.0 is not considered a browser at all: known false results.
111                    'is_ie'                         => false,
112                    'check_ie_version'              => array(
113                        '0'                         => true,
114                        '5.0'                       => true,
115                    ),
116                    'versionclasses'                => array(
117                        // IE 5.0 is not considered a browser.
118                    ),
119
120                    // IE 5.0 is a legacy browser.
121                    'devicetype'                    => 'legacy',
122
123                    'supports_svg'                  => false,
124                    'supports_json_contenttype'     => false,
125                ),
126            ),
127
128            // Windows 2000; Internet Explorer 5.5.
129            array(
130                'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0)',
131                array(
132                    'is_ie'                         => true,
133                    'check_ie_version'              => array(
134                        '0'                         => true,
135                        '5.0'                       => true,
136                        '5.5'                       => true,
137                    ),
138                    'versionclasses'                => array(
139                        'ie',
140                    ),
141
142                    // IE 6.0 is a legacy browser.
143                    'devicetype'                    => 'legacy',
144
145                    'supports_svg'                  => false,
146                    'supports_json_contenttype'     => false,
147                ),
148            ),
149
150            // Windows XP SP2; Internet Explorer 6.0.
151            array(
152                'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)',
153                array(
154                    'is_ie'                         => true,
155                    'check_ie_version'              => array(
156                        '0'                         => true,
157                        '5.0'                       => true,
158                        '5.5'                       => true,
159                        '6.0'                       => true,
160                    ),
161                    'versionclasses'                => array(
162                        'ie',
163                        'ie6',
164                    ),
165
166                    // IE 7.0 is a legacy browser.
167                    'devicetype'                    => 'legacy',
168
169                    'supports_svg'                  => false,
170                    'supports_json_contenttype'     => false,
171                ),
172            ),
173
174            // Windows XP SP2; Internet Explorer 7.0.
175            array(
176                'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; YPC 3.0.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)',
177                array(
178                    'is_ie'                         => true,
179                    'check_ie_version'              => array(
180                        '0'                         => true,
181                        '5.0'                       => true,
182                        '5.5'                       => true,
183                        '6.0'                       => true,
184                        '7.0'                       => true,
185                    ),
186                    'versionclasses'                => array(
187                        'ie',
188                        'ie7',
189                    ),
190
191                    'supports_svg'                  => false,
192                    'supports_json_contenttype'     => false,
193                ),
194            ),
195
196            // Windows XP SP2; Internet Explorer 7.0; Meridio extension.
197            array(
198                'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Meridio for Excel 5.0.251; Meridio for PowerPoint 5.0.251; Meridio for Word 5.0.251; Meridio Protocol; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.04506.648; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)',
199                array(
200                    'is_ie'                         => true,
201                    'check_ie_version'              => array(
202                        '0'                         => true,
203                        '5.0'                       => true,
204                        '5.5'                       => true,
205                        '6.0'                       => true,
206                        '7.0'                       => true,
207                    ),
208                    'versionclasses'                => array(
209                        'ie',
210                        'ie7',
211                    ),
212
213                    'supports_svg'                  => false,
214                    'supports_json_contenttype'     => false,
215                ),
216            ),
217
218            // Windows Vista; Internet Explorer 8.0.
219            array(
220                'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 2.0.50727; .NET CLR 1.1.4322; .NET CLR 3.0.04506.30; .NET CLR 3.0.04506.648)',
221                array(
222                    'is_ie'                         => true,
223                    'check_ie_version'              => array(
224                        '0'                         => true,
225                        '5.0'                       => true,
226                        '5.5'                       => true,
227                        '6.0'                       => true,
228                        '7.0'                       => true,
229                        '8.0'                       => true,
230                    ),
231                    'versionclasses'                => array(
232                        'ie',
233                        'ie8',
234                    ),
235
236                    'supports_svg'                  => false,
237                ),
238            ),
239
240            // Windows 7; Internet Explorer 9.0.
241            array(
242                'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)',
243                array(
244                    'is_ie'                         => true,
245                    'check_ie_version'              => array(
246                        '0'                         => true,
247                        '5.0'                       => true,
248                        '5.5'                       => true,
249                        '6.0'                       => true,
250                        '7.0'                       => true,
251                        '8.0'                       => true,
252                        '9.0'                       => true,
253                    ),
254                    'versionclasses'                => array(
255                        'ie',
256                        'ie9',
257                    ),
258                ),
259            ),
260
261            // Windows 7; Internet Explorer 9.0i.
262            array(
263                'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0)',
264                array(
265                    'is_ie'                         => true,
266                    'check_ie_version'              => array(
267                        '0'                         => true,
268                        '5.0'                       => true,
269                        '5.5'                       => true,
270                        '6.0'                       => true,
271                        '7.0'                       => true,
272                        '8.0'                       => true,
273                        '9.0'                       => true,
274                    ),
275                    'versionclasses'                => array(
276                        'ie',
277                        'ie9',
278                    ),
279                    'iecompatibility'               => true,
280
281                    // IE 9 in Compatiblity mode does not support SVG.
282                    'supports_svg'                  => false,
283
284                    // IE in Compatiblity mode does not support JSON ContentType.
285                    'supports_json_contenttype'     => false,
286                ),
287            ),
288
289            // Windows 8; Internet Explorer 10.0.
290            array(
291                'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; Trident/6.0; Touch)',
292                array(
293                    'is_ie'                         => true,
294                    'check_ie_version'              => array(
295                        '0'                         => true,
296                        '5.0'                       => true,
297                        '5.5'                       => true,
298                        '6.0'                       => true,
299                        '7.0'                       => true,
300                        '8.0'                       => true,
301                        '9.0'                       => true,
302                        '10'                        => true,
303                    ),
304                    'versionclasses'                => array(
305                        'ie',
306                        'ie10',
307                    ),
308                ),
309            ),
310
311            // Windows 8; Internet Explorer 10.0i.
312            array(
313                'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.2; Trident/6.0; Touch; .NET4.0E; .NET4.0C; Tablet PC 2.0)',
314                array(
315                    'is_ie'                         => true,
316                    'check_ie_version'              => array(
317                        '0'                         => true,
318                        '5.0'                       => true,
319                        '5.5'                       => true,
320                        '6.0'                       => true,
321                        '7.0'                       => true,
322                        '8.0'                       => true,
323                        '9.0'                       => true,
324                        '10'                        => true,
325                    ),
326                    'iecompatibility'               => true,
327                    'versionclasses'                => array(
328                        'ie',
329                        'ie10',
330                    ),
331
332                    // IE in Compatiblity mode does not support JSON ContentType.
333                    'supports_json_contenttype'     => false,
334                ),
335            ),
336
337            // Windows 8.1; Internet Explorer 11.0.
338            array(
339                'Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0)',
340                array(
341                    'is_ie'                         => true,
342                    'check_ie_version'              => array(
343                        '0'                         => true,
344                        '5.0'                       => true,
345                        '5.5'                       => true,
346                        '6.0'                       => true,
347                        '7.0'                       => true,
348                        '8.0'                       => true,
349                        '9.0'                       => true,
350                        '10'                        => true,
351                        '11'                        => true,
352                    ),
353                    'versionclasses'                => array(
354                        'ie',
355                        'ie11',
356                    ),
357                ),
358            ),
359
360            // Windows 8.1; Internet Explorer 11.0i.
361            array(
362                ' Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.3; Trident/7.0; .NET4.0E; .NET4.0C)',
363                array(
364                    'is_ie'                         => true,
365                    'check_ie_version'              => array(
366                        '0'                         => true,
367                        '5.0'                       => true,
368                        '5.5'                       => true,
369                        '6.0'                       => true,
370                        '7.0'                       => true,
371                        '8.0'                       => true,
372                        '9.0'                       => true,
373                        '10'                        => true,
374                        '11'                        => true,
375                    ),
376                    'iecompatibility'               => true,
377                    'versionclasses'                => array(
378                        'ie',
379                        'ie11',
380                    ),
381
382                    // IE in Compatiblity mode does not support JSON ContentType.
383                    'supports_json_contenttype'     => false,
384                ),
385            ),
386
387            // Windows XP; Firefox 1.0.6.
388            array(
389                'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.10) Gecko/20050716 Firefox/1.0.6',
390                array(
391                    'is_firefox'                    => true,
392
393                    'is_gecko'                      => true,
394                    'check_gecko_version'           => array(
395                        '1'                         => true,
396                    ),
397
398                    'versionclasses'                => array(
399                        'gecko',
400                        'gecko17',
401                    ),
402                ),
403            ),
404
405            // Windows XP; Firefox 1.0.6.
406            array(
407                'Mozilla/5.0 (Windows; U; Windows NT 5.1; nl; rv:1.8) Gecko/20051107 Firefox/1.5',
408                array(
409                    'is_firefox'                    => true,
410                    'check_firefox_version'         => array(
411                        '1.5'                       => true,
412                    ),
413
414                    'is_gecko'                      => true,
415                    'check_gecko_version'           => array(
416                        '1'                         => true,
417                        '20030516'                  => true,
418                        '20051116'                  => true,
419                    ),
420
421                    'versionclasses'                => array(
422                        'gecko',
423                        'gecko18',
424                    ),
425                ),
426            ),
427
428            // Windows XP; Firefox 1.5.0.1.
429            array(
430                'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.8.0.1) Gecko/20060111 Firefox/1.5.0.1',
431                array(
432                    'is_firefox'                    => true,
433                    'check_firefox_version'         => array(
434                        '1.5'                       => true,
435                    ),
436
437                    'is_gecko'                      => true,
438                    'check_gecko_version'           => array(
439                        '1'                         => true,
440                        '20030516'                  => true,
441                        '20051116'                  => true,
442                    ),
443
444                    'versionclasses'                => array(
445                        'gecko',
446                        'gecko18',
447                    ),
448                ),
449            ),
450
451            // Windows XP; Firefox 2.0.
452            array(
453                'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.1) Gecko/20061204 Firefox/2.0.0.1',
454                array(
455                    'is_firefox'                    => true,
456                    'check_firefox_version'         => array(
457                        '1.5'                       => true,
458                    ),
459
460                    'is_gecko'                      => true,
461                    'check_gecko_version'           => array(
462                        '1'                         => true,
463                        '2'                         => true,
464                        '20030516'                  => true,
465                        '20051116'                  => true,
466                        '2006010100'                => true,
467                    ),
468
469                    'versionclasses'                => array(
470                        'gecko',
471                        'gecko18',
472                    ),
473                ),
474            ),
475
476            // Ubuntu Linux amd64; Firefox 2.0.
477            array(
478                'Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.1) Gecko/20060601 Firefox/2.0 (Ubuntu-edgy)',
479                array(
480                    'is_firefox'                    => true,
481                    'check_firefox_version'         => array(
482                        '1.5'                       => true,
483                    ),
484
485                    'is_gecko'                      => true,
486                    'check_gecko_version'           => array(
487                        '1'                         => true,
488                        '2'                         => true,
489                        '20030516'                  => true,
490                        '20051116'                  => true,
491                        '2006010100'                => true,
492                    ),
493
494                    'versionclasses'                => array(
495                        'gecko',
496                        'gecko18',
497                    ),
498                ),
499            ),
500
501            // SUSE; Firefox 3.0.6.
502            array(
503                'Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.0.6) Gecko/2009012700 SUSE/3.0.6-1.4 Firefox/3.0.6',
504                array(
505                    'is_firefox'                    => true,
506                    'check_firefox_version'         => array(
507                        '1.5'                       => true,
508                        '3.0'                       => true,
509                    ),
510
511                    'is_gecko'                      => true,
512                    'check_gecko_version'           => array(
513                        '1'                         => true,
514                        '2'                         => true,
515                        '20030516'                  => true,
516                        '20051116'                  => true,
517                        '2006010100'                => true,
518                    ),
519
520                    'versionclasses'                => array(
521                        'gecko',
522                        'gecko19',
523                    ),
524                ),
525            ),
526
527            // Linux i686; Firefox 3.6.
528            array(
529                'Mozilla/5.0 (X11; Linux i686; rv:2.0) Gecko/20100101 Firefox/3.6',
530                array(
531                    'is_firefox'                    => true,
532                    'check_firefox_version'         => array(
533                        '1.5'                       => true,
534                        '3.0'                       => true,
535                    ),
536
537                    'is_gecko'                      => true,
538                    'check_gecko_version'           => array(
539                        '1'                         => true,
540                        '2'                         => true,
541                        '20030516'                  => true,
542                        '20051116'                  => true,
543                        '2006010100'                => true,
544                        '3.6'                       => true,
545                        '20100101'                  => true,
546                    ),
547
548                    'versionclasses'                => array(
549                        'gecko',
550                        'gecko20',
551                    ),
552                ),
553            ),
554
555            // Windows; Firefox 11.0.
556            array(
557                'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:11.0) Gecko Firefox/11.0',
558                array(
559                    'is_firefox'                    => true,
560                    'check_firefox_version'         => array(
561                        '1.5'                       => true,
562                        '3.0'                       => true,
563                        '4'                         => true,
564                        '10'                        => true,
565                    ),
566
567                    'is_gecko'                      => true,
568                    'check_gecko_version'           => array(
569                        '1'                         => true,
570                        '2'                         => true,
571                        '20030516'                  => true,
572                        '20051116'                  => true,
573                        '2006010100'                => true,
574                        '20100101'                  => true,
575                        '3.6'                       => true,
576                        '4.0'                       => true,
577                    ),
578
579                    'versionclasses'                => array(
580                        'gecko',
581                    ),
582                ),
583            ),
584
585            // Windows; Firefox 15.0a2.
586            array(
587                'Mozilla/5.0 (Windows NT 6.1; rv:15.0) Gecko/20120716 Firefox/15.0a2',
588                array(
589                    'is_firefox'                    => true,
590                    'check_firefox_version'         => array(
591                        '1.5'                       => true,
592                        '3.0'                       => true,
593                        '4'                         => true,
594                        '10'                        => true,
595                        '15'                        => true,
596                    ),
597
598                    'is_gecko'                      => true,
599                    'check_gecko_version'           => array(
600                        '1'                         => true,
601                        '2'                         => true,
602                        '20030516'                  => true,
603                        '20051116'                  => true,
604                        '2006010100'                => true,
605                        '20100101'                  => true,
606                        '3.6'                       => true,
607                        '4.0'                       => true,
608                        '15.0'                      => true,
609                    ),
610
611                    'versionclasses'                => array(
612                        'gecko',
613                    ),
614                ),
615            ),
616
617            // Firefox 18; Mac OS X 10.
618            array(
619                'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:18.0) Gecko/18.0 Firefox/18.0',
620                array(
621                    'is_firefox'                    => true,
622                    'check_firefox_version'         => array(
623                        '1.5'                       => true,
624                        '3.0'                       => true,
625                        '4'                         => true,
626                        '10'                        => true,
627                        '15'                        => true,
628                        '18'                        => true,
629                    ),
630
631                    'is_gecko'                      => true,
632                    'check_gecko_version'           => array(
633                        '1'                         => true,
634                        '2'                         => true,
635                        '20030516'                  => true,
636                        '20051116'                  => true,
637                        '2006010100'                => true,
638                        '3.6'                       => true,
639                        '4.0'                       => true,
640                        '15.0'                      => true,
641                        '18.0'                      => true,
642                        '20100101'                  => true,
643                    ),
644
645                    'versionclasses'                => array(
646                        'gecko',
647                    ),
648                ),
649            ),
650
651            // Firefox 33; Mac OS X 10.10.
652            array(
653                'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:33.0) Gecko/20100101 Firefox/33.0',
654                array(
655                    'is_firefox'                    => true,
656                    'check_firefox_version'         => array(
657                        '1.5'                       => true,
658                        '3.0'                       => true,
659                        '4'                         => true,
660                        '10'                        => true,
661                        '15'                        => true,
662                        '18'                        => true,
663                        '19'                        => true,
664                        '33'                        => true,
665                    ),
666
667                    'is_gecko'                      => true,
668                    'check_gecko_version'           => array(
669                        '1'                         => true,
670                        '2'                         => true,
671                        '20030516'                  => true,
672                        '20051116'                  => true,
673                        '2006010100'                => true,
674                        '3.6'                       => true,
675                        '4.0'                       => true,
676                        '15.0'                      => true,
677                        '18.0'                      => true,
678                        '19.0'                      => true,
679                        '20100101'                  => true,
680                    ),
681
682                    'versionclasses'                => array(
683                        'gecko',
684                    ),
685                ),
686            ),
687
688            // SeaMonkey 2.0; Windows.
689            array(
690                'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1b3pre) Gecko/20081208 SeaMonkey/2.0',
691                array(
692                    'is_gecko'                      => true,
693                    'check_gecko_version'           => array(
694                        '1'                         => true,
695                        '2'                         => true,
696                        '20030516'                  => true,
697                        '20051106'                  => true,
698                        '20051116'                  => true,
699                        '2006010100'                => true,
700                    ),
701
702                    'versionclasses'                => array(
703                        'gecko',
704                        'gecko19',
705                    ),
706                ),
707            ),
708
709            // SeaMonkey 2.1; Linux.
710            array(
711                'Mozilla/5.0 (X11; Linux x86_64; rv:2.0.1) Gecko/20110609 Firefox/4.0.1 SeaMonkey/2.1',
712                array(
713                    'is_gecko'                      => true,
714                    'check_gecko_version'           => array(
715                        '1'                         => true,
716                        '2'                         => true,
717                        '20030516'                  => true,
718                        '20051116'                  => true,
719                        '2006010100'                => true,
720                        '20100101'                  => true,
721                        '3.6'                       => true,
722                        '4.0'                       => true,
723                    ),
724
725                    'is_firefox'                    => true,
726                    'check_firefox_version'         => array(
727                        '1.5'                       => true,
728                        '3.0'                       => true,
729                        '4'                         => true,
730                    ),
731
732                    'versionclasses'                => array(
733                        'gecko',
734                        'gecko20',
735                    ),
736                ),
737            ),
738
739            // SeaMonkey 2.3; FreeBSD.
740            array(
741                'Mozilla/5.0 (X11; FreeBSD amd64; rv:6.0) Gecko/20110818 Firefox/6.0 SeaMonkey/2.3',
742                array(
743                    'is_gecko'                      => true,
744                    'check_gecko_version'           => array(
745                        '1'                         => true,
746                        '2'                         => true,
747                        '20030516'                  => true,
748                        '20051116'                  => true,
749                        '2006010100'                => true,
750                        '20100101'                  => true,
751                        '3.6'                       => true,
752                        '4.0'                       => true,
753                    ),
754
755                    'is_firefox'                    => true,
756                    'check_firefox_version'         => array(
757                        '1.5'                       => true,
758                        '3.0'                       => true,
759                        '4'                         => true,
760                    ),
761
762                    'versionclasses'                => array(
763                        'gecko',
764                    ),
765                ),
766            ),
767
768            // Windows 7; MS Word 2010.
769            array(
770                'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.3; .NET4.0C; .NET4.0E; ms-office)',
771                array(
772                    'is_ie'                         => true,
773                    'check_ie_version'              => array(
774                        '0'                         => true,
775                        '5.0'                       => true,
776                        '5.5'                       => true,
777                        '6.0'                       => true,
778                        '7.0'                       => true,
779                        '8.0'                       => true,
780                    ),
781                    'iecompatibility'               => true,
782                    'versionclasses'                => array(
783                        'ie',
784                        'ie8',
785                    ),
786
787                    'is_msword'                     => true,
788
789                    'supports_svg'                  => false,
790                    'supports_json_contenttype'     => false,
791                ),
792            ),
793
794            // Windows 7; MS Outlook 2010.
795            array(
796                'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.3; .NET4.0C; .NET4.0E; Microsoft Outlook 14.0.7113; ms-office; MSOffice 14)',
797                array(
798                    'is_ie'                         => true,
799                    'check_ie_version'              => array(
800                        '0'                         => true,
801                        '5.0'                       => true,
802                        '5.5'                       => true,
803                        '6.0'                       => true,
804                        '7.0'                       => true,
805                        '8.0'                       => true,
806                    ),
807                    'iecompatibility'               => true,
808                    'versionclasses'                => array(
809                        'ie',
810                        'ie8',
811                    ),
812
813                    // Note: Outlook is deliberately not considered to be MS Word.
814                    'is_msword'                     => false,
815
816                    'supports_svg'                  => false,
817                    'supports_json_contenttype'     => false,
818                ),
819            ),
820
821            // Mac OS X; MS Word 14.
822            array(
823                'Mozilla/5.0 (Macintosh; Intel Mac OS X) Word/14.38.0',
824                array(
825                    'versionclasses'                => array(
826                    ),
827
828                    'is_msword'                     => true,
829                ),
830            ),
831
832            // Safari 312; Max OS X.
833            array(
834                'Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/312.1 (KHTML, like Gecko) Safari/312',
835                array(
836                    'is_safari'                     => true,
837                    'check_safari_version'          => array(
838                        '1'                         => true,
839                        '312'                       => true,
840                    ),
841
842                    'is_webkit'                     => true,
843
844                    'versionclasses'                => array(
845                        'safari',
846                    ),
847                ),
848            ),
849
850            // Safari 412; Max OS X.
851            array(
852                'Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/412 (KHTML, like Gecko) Safari/412',
853                array(
854                    'is_safari'                     => true,
855                    'check_safari_version'          => array(
856                        '1'                         => true,
857                        '312'                       => true,
858                    ),
859
860                    'is_webkit'                     => true,
861
862                    'versionclasses'                => array(
863                        'safari',
864                    ),
865                ),
866            ),
867
868            // Safari 2.0; Max OS X.
869            array(
870                'Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/412 (KHTML, like Gecko) Safari/412',
871                array(
872                    'is_safari'                     => true,
873                    'check_safari_version'          => array(
874                        '1'                         => true,
875                        '312'                       => true,
876                    ),
877
878                    'is_webkit'                     => true,
879
880                    'versionclasses'                => array(
881                        'safari',
882                    ),
883                ),
884            ),
885
886            // iOS Safari 528; iPhone.
887            array(
888                'Mozilla/5.0 (iPhone; U; CPU iPhone OS 3_1_2 like Mac OS X; cs-cz) AppleWebKit/528.18 (KHTML, like Gecko) Version/4.0 Mobile/7D11 Safari/528.16',
889                array(
890                    // Note: We do *not* identify mobile Safari as Safari.
891                    'is_safari_ios'                 => true,
892                    'is_ios'                        => true,
893                    'check_safari_ios_version'      => array(
894                        '527'                       => true,
895                    ),
896
897                    'is_webkit'                     => true,
898
899                    'versionclasses'                => array(
900                        'ios'
901                    ),
902
903                    'devicetype'                    => 'mobile',
904               ),
905            ),
906
907            // Safari; iPhone 6 Plus; iOS 8.1; Build 12B411.
908            array(
909                'Mozilla/5.0 (iPhone; CPU iPhone OS 10_10 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) Version/8.0 Mobile/12B411 Safari/600.1.4',
910                array(
911                    // Note: We do *not* identify mobile Safari as Safari.
912                    'is_safari_ios'                 => true,
913                    'is_ios'                        => true,
914                    'check_safari_ios_version'      => array(
915                        '527'                       => true,
916                        '590'                       => true,
917                        '600'                       => true,
918                    ),
919
920                    'is_webkit'                     => true,
921
922                    'versionclasses'                => array(
923                        'ios',
924                    ),
925
926                    'devicetype'                    => 'mobile',
927               ),
928            ),
929
930            // iOS Safari 533; iPad.
931            array(
932                'Mozilla/5.0 (iPad; U; CPU OS 4_2_1 like Mac OS X; en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8C148 Safari/6533.18.5',
933                array(
934                    // Note: We do *not* identify mobile Safari as Safari.
935                    'is_safari_ios'                 => true,
936                    'is_ios'                        => true,
937                    'check_safari_ios_version'      => array(
938                        '527'                       => true,
939                    ),
940
941                    'is_webkit'                     => true,
942
943                    'versionclasses'                => array(
944                        'ios',
945                    ),
946
947                    'devicetype'                    => 'tablet',
948               ),
949            ),
950
951            // Android WebKit 525; G1 Phone.
952            'Android WebKit 525; G1 Phone' => array(
953                'Mozilla/5.0 (Linux; U; Android 1.1; en-gb; dream) AppleWebKit/525.10+ (KHTML, like Gecko) Version/3.0.4 Mobile Safari/523.12.2 – G1 Phone',
954                array(
955                    'is_webkit_android'             => true,
956                    'check_webkit_android_version'  => array(
957                        '525'                       => true,
958                    ),
959
960                    'is_webkit'                     => true,
961
962                    'versionclasses'                => array(
963                        'android',
964                    ),
965
966                    'devicetype'                    => 'mobile',
967
968                    'supports_svg'                  => false,
969               ),
970            ),
971
972            // Android WebKit 530; Nexus.
973            'Android WebKit 530; Nexus' => array(
974                'Mozilla/5.0 (Linux; U; Android 2.1; en-us; Nexus One Build/ERD62) AppleWebKit/530.17 (KHTML, like Gecko) Version/4.0 Mobile Safari/530.17 –Nexus',
975                array(
976                    'is_webkit_android'             => true,
977                    'check_webkit_android_version'  => array(
978                        '525'                       => true,
979                        '527'                       => true,
980                    ),
981
982                    'is_webkit'                     => true,
983
984                    'versionclasses'                => array(
985                        'android',
986                    ),
987
988                    'devicetype'                    => 'mobile',
989
990                    'supports_svg'                  => false,
991               ),
992            ),
993
994            // Android WebKit 537; Samsung GT-9505.
995            array(
996                'Mozilla/5.0 (Linux; Android 4.3; it-it; SAMSUNG GT-I9505/I9505XXUEMJ7 Build/JSS15J) AppleWebKit/537.36 (KHTML, like Gecko) Version/1.5 Chrome/28.0.1500.94 Mobile Safari/537.36',
997                array(
998                    'is_webkit_android'             => true,
999                    'check_webkit_android_version'  => array(
1000                        '525'                       => true,
1001                        '527'                       => true,
1002                    ),
1003
1004                    'is_webkit'                     => true,
1005
1006                    'is_chrome'                     => true,
1007                    'check_chrome_version'          => array(
1008                        '7'                         => true,
1009                        '8'                         => true,
1010                        '10'                        => true,
1011                    ),
1012
1013                    'versionclasses'                => array(
1014                        'chrome',
1015                        'android',
1016                    ),
1017
1018                    'devicetype'                    => 'mobile',
1019                ),
1020            ),
1021
1022            // Android WebKit 537; Nexus 5.
1023            array(
1024                'Mozilla/5.0 (Linux; Android 5.0; Nexus 5 Build/LPX13D) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.102 Mobile Safari/537.36',
1025                array(
1026                    'is_webkit_android'             => true,
1027                    'check_webkit_android_version'  => array(
1028                        '525'                       => true,
1029                        '527'                       => true,
1030                    ),
1031
1032                    'is_webkit'                     => true,
1033
1034                    'is_chrome'                     => true,
1035                    'check_chrome_version'          => array(
1036                        '7'                         => true,
1037                        '8'                         => true,
1038                        '10'                        => true,
1039                    ),
1040
1041                    'versionclasses'                => array(
1042                        'chrome',
1043                        'android',
1044                    ),
1045
1046                    'devicetype'                    => 'mobile',
1047                ),
1048            ),
1049
1050            // Chrome 8; Mac OS X.
1051            array(
1052                'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_5; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.215 Safari/534.10',
1053                array(
1054                    'is_chrome'                     => true,
1055                    'check_chrome_version'          => array(
1056                        '7'                         => true,
1057                        '8'                         => true,
1058                    ),
1059
1060                    'is_webkit'                     => true,
1061
1062                    'versionclasses'                => array(
1063                        'chrome',
1064                    ),
1065                ),
1066            ),
1067
1068            // Chrome 39; Mac OS X.
1069            array(
1070                'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.71 Safari/537.36',
1071                array(
1072                    'is_chrome'                     => true,
1073                    'check_chrome_version'          => array(
1074                        '7'                         => true,
1075                        '8'                         => true,
1076                        '10'                        => true,
1077                        '39'                        => true,
1078                    ),
1079
1080                    'is_webkit'                     => true,
1081
1082                    'versionclasses'                => array(
1083                        'chrome',
1084                    ),
1085                ),
1086            ),
1087
1088            // Opera 8.51; Windows XP.
1089            array(
1090                'Opera/8.51 (Windows NT 5.1; U; en)',
1091                array(
1092                    'is_opera'                      => true,
1093                    'check_opera_version'           => array(
1094                        '8.0'                       => true,
1095                    ),
1096
1097                    'versionclasses'                => array(
1098                        'opera',
1099                    ),
1100
1101                    'supports_svg'                  => false,
1102               ),
1103            ),
1104
1105            // Opera 9.0; Windows XP.
1106            array(
1107                'Opera/9.0 (Windows NT 5.1; U; en)',
1108                array(
1109                    'is_opera'                      => true,
1110                    'check_opera_version'           => array(
1111                        '8.0'                       => true,
1112                        '9.0'                       => true,
1113                    ),
1114
1115                    'versionclasses'                => array(
1116                        'opera',
1117                    ),
1118
1119                    'supports_svg'                  => false,
1120               ),
1121            ),
1122
1123            // Opera 12.15 (Build 1748); Mac OS X.
1124            array(
1125                'Opera/9.80 (Macintosh; Intel Mac OS X 10.10.0; Edition MAS) Presto/2.12.388 Version/12.15',
1126                array(
1127                    'is_opera'                      => true,
1128                    'check_opera_version'           => array(
1129                        '8.0'                       => true,
1130                        '9.0'                       => true,
1131                        '10.0'                      => true,
1132                        '12.15'                     => true,
1133                    ),
1134
1135                    'versionclasses'                => array(
1136                        'opera',
1137                    ),
1138
1139                    'supports_svg'                  => false,
1140               ),
1141            ),
1142
1143            // Opera 9.0; Debian Linux.
1144            array(
1145                'Opera/9.01 (X11; Linux i686; U; en)',
1146                array(
1147                    'is_opera'                      => true,
1148                    'check_opera_version'           => array(
1149                        '8.0'                       => true,
1150                        '9.0'                       => true,
1151                    ),
1152
1153                    'versionclasses'                => array(
1154                        'opera',
1155                    ),
1156
1157                    'supports_svg'                  => false,
1158               ),
1159            ),
1160
1161            // Google web crawlers.
1162            array(
1163                'Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)',
1164                array(
1165                    'is_web_crawler'                => true,
1166                    'versionclasses'                => array(
1167                    ),
1168               ),
1169            ),
1170            array(
1171                'Googlebot/2.1 (+http://www.googlebot.com/bot.html)',
1172                array(
1173                    'is_web_crawler'                => true,
1174                    'versionclasses'                => array(
1175                    ),
1176               ),
1177            ),
1178            array(
1179                'Googlebot-Image/1.0',
1180                array(
1181                    'is_web_crawler'                => true,
1182                    'versionclasses'                => array(
1183                    ),
1184               ),
1185            ),
1186
1187            // Yahoo crawlers.
1188            // See https://help.yahoo.com/kb/slurp-crawling-page-sln22600.html.
1189            array(
1190                'Mozilla/5.0 (compatible; Yahoo! Slurp; http://help.yahoo.com/help/us/ysearch/slurp)',
1191                array(
1192                    'is_web_crawler'                => true,
1193                    'versionclasses'                => array(
1194                    ),
1195               ),
1196            ),
1197
1198            // Bing / MSN / AdIdx crawlers.
1199            // See http://www.bing.com/webmaster/help/which-crawlers-does-bing-use-8c184ec0.
1200            array(
1201                'Mozilla/5.0 (compatible; bingbot/2.0; +http://www.bing.com/bingbot.htm)',
1202                array(
1203                    'is_web_crawler'                => true,
1204                    'versionclasses'                => array(
1205                    ),
1206               ),
1207            ),
1208            array(
1209                'Mozilla/5.0 (compatible; bingbot/2.0 +http://www.bing.com/bingbot.htm)',
1210                array(
1211                    'is_web_crawler'                => true,
1212                    'versionclasses'                => array(
1213                    ),
1214               ),
1215            ),
1216            array(
1217                'Mozilla/5.0 (iPhone; CPU iPhone OS 7_0 like Mac OS X) AppleWebKit/537.51.1 (KHTML, like Gecko) Version/7.0 Mobile/11A465 Safari/9537.53 (compatible; bingbot/2.0; +http://www.bing.com/bingbot.htm)',
1218                array(
1219                    'is_web_crawler'                => true,
1220                    'is_webkit'                     => true,
1221                    'is_safari_ios'                 => true,
1222                    'is_ios'                        => true,
1223                    'check_safari_ios_version'      => array(
1224                        '527'                       => true,
1225                    ),
1226
1227                    'versionclasses'                => array(
1228                        'ios',
1229                    ),
1230
1231                    'devicetype'                    => 'mobile',
1232               ),
1233            ),
1234            array(
1235                'Mozilla/5.0 (Windows Phone 8.1; ARM; Trident/7.0; Touch; rv:11.0; IEMobile/11.0; NOKIA; Lumia 530) like Gecko (compatible; bingbot/2.0; +http://www.bing.com/bingbot.htm)',
1236                array(
1237                    'is_web_crawler'                => true,
1238                    'is_ie'                         => true,
1239                    'check_ie_version'              => array(
1240                        '0'                         => true,
1241                        '5.0'                       => true,
1242                        '5.5'                       => true,
1243                        '6.0'                       => true,
1244                        '7.0'                       => true,
1245                        '8.0'                       => true,
1246                        '9.0'                       => true,
1247                        '10'                        => true,
1248                        '11'                        => true,
1249                    ),
1250                    'versionclasses'                => array(
1251                        'ie',
1252                        'ie11',
1253                    ),
1254                    'devicetype'                    => 'mobile',
1255               ),
1256            ),
1257
1258            array(
1259                'msnbot/2.0b (+http://search.msn.com/msnbot.htm)',
1260                array(
1261                    'is_web_crawler'                => true,
1262                    'versionclasses'                => array(
1263                    ),
1264               ),
1265            ),
1266            array(
1267                'msnbot/2.1',
1268                array(
1269                    'is_web_crawler'                => true,
1270                    'versionclasses'                => array(
1271                    ),
1272               ),
1273            ),
1274            array(
1275                'msnbot-media/1.1 (+http://search.msn.com/msnbot.htm)',
1276                array(
1277                    'is_web_crawler'                => true,
1278                    'versionclasses'                => array(
1279                    ),
1280               ),
1281            ),
1282            array(
1283                'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534+ (KHTML, like Gecko) BingPreview/1.0b',
1284                array(
1285                    'is_web_crawler'                => true,
1286                    'is_webkit'                     => true,
1287                    'is_safari'                     => true,
1288                    'check_safari_version'          => array(
1289                        '1'                         => true,
1290                        '312'                       => true,
1291                        '500'                       => true,
1292                    ),
1293
1294                    'versionclasses'                => array(
1295                        'safari',
1296                    ),
1297               ),
1298            ),
1299            array(
1300                'Mozilla/5.0 (Windows Phone 8.1; ARM; Trident/7.0; Touch; rv:11.0; IEMobile/11.0; NOKIA; Lumia 530) like Gecko BingPreview/1.0b',
1301                array(
1302                    'is_web_crawler'                => true,
1303                    'is_ie'                         => true,
1304                    'check_ie_version'              => array(
1305                        '0'                         => true,
1306                        '5.0'                       => true,
1307                        '5.5'                       => true,
1308                        '6.0'                       => true,
1309                        '7.0'                       => true,
1310                        '8.0'                       => true,
1311                        '9.0'                       => true,
1312                        '10'                        => true,
1313                        '11'                        => true,
1314                    ),
1315                    'versionclasses'                => array(
1316                        'ie',
1317                        'ie11',
1318                    ),
1319                    'devicetype'                    => 'mobile',
1320               ),
1321            ),
1322
1323            // Yandex.
1324            // See http://help.yandex.com/search/robots/agent.xml.
1325            array(
1326                'Mozilla/5.0 (compatible; YandexBot/3.0; +http://yandex.com/bots)',
1327                array(
1328                    'is_web_crawler'                => true,
1329                    'versionclasses'                => array(
1330                    ),
1331               ),
1332            ),
1333            array(
1334                'Mozilla/5.0 (compatible; YandexImages/3.0; +http://yandex.com/bots)',
1335                array(
1336                    'is_web_crawler'                => true,
1337                    'versionclasses'                => array(
1338                    ),
1339               ),
1340            ),
1341
1342            // AltaVista.
1343            array(
1344                'AltaVista V2.0B crawler@evreka.com',
1345                array(
1346                    'is_web_crawler'                => true,
1347                    'versionclasses'                => array(
1348                    ),
1349               ),
1350            ),
1351
1352            // ZoomSpider.
1353            array(
1354                'ZoomSpider - wrensoft.com [ZSEBOT]',
1355                array(
1356                    'is_web_crawler'                => true,
1357                    'versionclasses'                => array(
1358                    ),
1359               ),
1360            ),
1361
1362            // Baidu.
1363            array(
1364                'Baiduspider+(+http://www.baidu.com/search/spider_jp.html)',
1365                array(
1366                    'is_web_crawler'                => true,
1367                    'versionclasses'                => array(
1368                    ),
1369               ),
1370            ),
1371            array(
1372                'Baiduspider+(+http://www.baidu.com/search/spider.htm)',
1373                array(
1374                    'is_web_crawler'                => true,
1375                    'versionclasses'                => array(
1376                    ),
1377               ),
1378            ),
1379
1380            // Ask.com.
1381            array(
1382                'User-Agent: Mozilla/2.0 (compatible; Ask Jeeves/Teoma)',
1383                array(
1384                    'is_web_crawler'                => true,
1385                    'versionclasses'                => array(
1386                    ),
1387               ),
1388            ),
1389
1390            // MoodleBot.
1391            array(
1392                'User-Agent: MoodleBot/3.8 (+https://moodle.org)',
1393                array(
1394                    'is_web_crawler'                => true,
1395                    'versionclasses'                => array(
1396                    ),
1397               ),
1398            ),
1399
1400            // Macos Desktop app.
1401            array(
1402                'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) moodlemobile/3.6.0 Chrome/69.0.3497.106 Electron/4.0.1 Safari/537.36 MoodleMobile',
1403                array(
1404                    'is_moodle_app'                => true,
1405                    'is_webkit'                    => true,
1406                    'is_chrome'                    => true,
1407                    'check_chrome_version'         => array(
1408                        '7'                        => true,
1409                        '8'                        => true,
1410                        '10'                       => true,
1411                        '39'                       => true,
1412                    ),
1413                    'versionclasses'               => array(
1414                        'chrome',
1415                    ),
1416               ),
1417            ),
1418
1419            // Linux Desktop app.
1420            array(
1421                'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) moodledesktop/3.6.0 Chrome/69.0.3497.106 Electron/4.0.1 Safari/537.36 MoodleMobile',
1422                array(
1423                    'is_moodle_app'                => true,
1424                    'is_webkit'                    => true,
1425                    'is_chrome'                    => true,
1426                    'check_chrome_version'         => array(
1427                        '7'                        => true,
1428                        '8'                        => true,
1429                        '10'                       => true,
1430                        '39'                       => true,
1431                    ),
1432                    'versionclasses'               => array(
1433                        'chrome',
1434                    ),
1435               ),
1436            ),
1437
1438            // Windows Desktop app.
1439            array(
1440                'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) moodledesktop/3.6.0 Chrome/69.0.3497.106 Electron/4.0.1 Safari/537.36 MoodleMobile',
1441                array(
1442                    'is_moodle_app'                => true,
1443                    'is_webkit'                    => true,
1444                    'is_chrome'                    => true,
1445                    'check_chrome_version'         => array(
1446                        '7'                        => true,
1447                        '8'                        => true,
1448                        '10'                       => true,
1449                        '39'                       => true,
1450                    ),
1451                    'versionclasses'               => array(
1452                        'chrome',
1453                    ),
1454               ),
1455            ),
1456
1457            // Android app.
1458            array(
1459                'Mozilla/5.0 (Linux; Android 7.1.1; Moto G Play Build/NPIS26.48-43-2; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/71.0.3578.99 Mobile Safari/537.36 MoodleMobile',
1460                array(
1461                    'is_moodle_app'                => true,
1462                    'is_webkit'                    => true,
1463                    'is_webkit_android'            => true,
1464                    'is_chrome'                    => true,
1465                    'check_chrome_version'         => array(
1466                        '7'                        => true,
1467                        '8'                        => true,
1468                        '10'                       => true,
1469                        '39'                       => true,
1470                    ),
1471                    'devicetype'                   => 'mobile',
1472                    'check_webkit_android_version' => array(
1473                        '525'                       => true,
1474                        '527'                       => true,
1475                    ),
1476                    'versionclasses'               => array(
1477                        'android',
1478                        'chrome'
1479                    ),
1480               ),
1481            ),
1482
1483            // Android app, user agent lower case.
1484            array(
1485                'Mozilla/5.0 (Linux; Android 7.1.1; Moto G Play Build/NPIS26.48-43-2; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/71.0.3578.99 Mobile Safari/537.36 moodlemobile',
1486                array(
1487                    'is_moodle_app'                => true,
1488                    'is_webkit'                    => true,
1489                    'is_webkit_android'            => true,
1490                    'is_chrome'                    => true,
1491                    'check_chrome_version'         => array(
1492                        '7'                        => true,
1493                        '8'                        => true,
1494                        '10'                       => true,
1495                        '39'                       => true,
1496                    ),
1497                    'devicetype'                   => 'mobile',
1498                    'check_webkit_android_version' => array(
1499                        '525'                       => true,
1500                        '527'                       => true,
1501                    ),
1502                    'versionclasses'               => array(
1503                        'android',
1504                        'chrome'
1505                    ),
1506               ),
1507            ),
1508
1509            // iOS (iPhone) app.
1510            array(
1511                'Mozilla/5.0 (iPhone; CPU OS 13_3_3 like Mac OS X) AppleWebKit/603.3.8 (KHTML, like Gecko) Mobile/14G60 MoodleMobile',
1512                array(
1513                    'is_moodle_app'                => true,
1514                    'is_ios'                       => true,
1515                    'is_webkit'                    => true,
1516                    'devicetype'                   => 'mobile',
1517                    'versionclasses'               => array(
1518                    ),
1519               ),
1520            ),
1521
1522            // iOS (iPad) app.
1523            array(
1524                'Mozilla/5.0 (iPad; CPU OS 12_1_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/16D39 MoodleMobile',
1525                array(
1526                    'is_moodle_app'                => true,
1527                    'is_ios'                       => true,
1528                    'is_webkit'                    => true,
1529                    'devicetype'                   => 'tablet',
1530                    'versionclasses'               => array(
1531                    ),
1532               ),
1533            ),
1534        );
1535    }
1536
1537    /**
1538     * Test instance generation.
1539     */
1540    public function test_instance() {
1541        $this->assertInstanceOf('core_useragent', core_useragent::instance());
1542        $this->assertInstanceOf('core_useragent', core_useragent::instance(true));
1543    }
1544
1545    /**
1546     * @dataProvider user_agents_providers
1547     */
1548    public function test_useragent_edge($useragent, $tests) {
1549        // Setup the core_useragent instance.
1550        core_useragent::instance(true, $useragent);
1551
1552        // Edge Tests.
1553        if (isset($tests['is_edge']) && $tests['is_edge']) {
1554            $this->assertTrue(core_useragent::is_edge());
1555        } else {
1556            $this->assertFalse(core_useragent::is_edge());
1557        }
1558
1559        $versions = array(
1560            // New versions of should be added here.
1561            '12'   => false,
1562        );
1563
1564        if (isset($tests['check_edge_version'])) {
1565            // The test provider has overwritten some of the above checks.
1566            // Must use the '+' operator, because array_merge will incorrectly rewrite the array keys for integer-based indexes.
1567            $versions = $tests['check_edge_version'] + $versions;
1568        }
1569
1570        foreach ($versions as $version => $result) {
1571            $this->assertEquals($result, core_useragent::check_edge_version($version),
1572                "Version incorrectly determined for Edge version '{$version}'");
1573        }
1574    }
1575
1576    /**
1577     * @dataProvider user_agents_providers
1578     */
1579    public function test_useragent_ie($useragent, $tests) {
1580        // Setup the core_useragent instance.
1581        core_useragent::instance(true, $useragent);
1582
1583        // IE Tests.
1584        if (isset($tests['is_ie']) && $tests['is_ie']) {
1585            $this->assertTrue(core_useragent::is_ie());
1586        } else {
1587            $this->assertFalse(core_useragent::is_ie());
1588        }
1589
1590        $versions = array(
1591            // New versions of should be added here.
1592            '0'    => false,
1593            '5.0'  => false,
1594            '5.5'  => false,
1595            '6.0'  => false,
1596            '7.0'  => false,
1597            '8.0'  => false,
1598            '9.0'  => false,
1599            '10'   => false,
1600            '11'   => false,
1601            '12'   => false,
1602            '13'   => false,
1603            '14'   => false,
1604        );
1605
1606        if (isset($tests['check_ie_version'])) {
1607            // The test provider has overwritten some of the above checks.
1608            // Must use the '+' operator, because array_merge will incorrectly rewrite the array keys for integer-based indexes.
1609            $versions = $tests['check_ie_version'] + $versions;
1610        }
1611
1612        foreach ($versions as $version => $result) {
1613            $this->assertEquals($result, core_useragent::check_ie_version($version),
1614                "Version incorrectly determined for IE version '{$version}'");
1615        }
1616
1617        // IE Compatibility mode.
1618        if (isset($tests['iecompatibility']) && $tests['iecompatibility']) {
1619            $this->assertTrue(core_useragent::check_ie_compatibility_view(), "IE Compability false negative");
1620        } else {
1621            $this->assertFalse(core_useragent::check_ie_compatibility_view(), "IE Compability false positive");
1622        }
1623
1624    }
1625
1626    /**
1627     * @dataProvider user_agents_providers
1628     */
1629    public function test_useragent_msword($useragent, $tests) {
1630        // Setup the core_useragent instance.
1631        core_useragent::instance(true, $useragent);
1632
1633        // MSWord Tests.
1634        if (isset($tests['is_msword']) && $tests['is_msword']) {
1635            $this->assertTrue(core_useragent::is_msword());
1636        } else {
1637            $this->assertFalse(core_useragent::is_msword());
1638        }
1639    }
1640
1641
1642    /**
1643     * @dataProvider user_agents_providers
1644     */
1645    public function test_useragent_supports($useragent, $tests) {
1646        // Setup the core_useragent instance.
1647        core_useragent::instance(true, $useragent);
1648
1649        // Supports SVG.
1650        if (!isset($tests['supports_svg']) || $tests['supports_svg']) {
1651            $this->assertTrue(core_useragent::supports_svg(),
1652                "SVG Support was not reported (and should have been)");
1653        } else {
1654            $this->assertFalse(core_useragent::supports_svg(),
1655                "SVG Support was reported (and should not have been)");
1656        }
1657
1658        // Supports JSON ContentType.
1659        if (!isset($tests['supports_json_contenttype']) || $tests['supports_json_contenttype']) {
1660            $this->assertTrue(core_useragent::supports_json_contenttype(),
1661                "JSON ContentType Support was not reported (and should have been)");
1662        } else {
1663            $this->assertFalse(core_useragent::supports_json_contenttype(),
1664                "JSON ContentType Support was reported (and should not have been)");
1665        }
1666    }
1667
1668    /**
1669     * @dataProvider user_agents_providers
1670     */
1671    public function test_useragent_webkit($useragent, $tests) {
1672        // Setup the core_useragent instance.
1673        core_useragent::instance(true, $useragent);
1674
1675        if (isset($tests['is_webkit']) && $tests['is_webkit']) {
1676            $this->assertTrue(core_useragent::is_webkit(),
1677                "Browser was not identified as a webkit browser");
1678            $this->assertTrue(core_useragent::check_webkit_version());
1679        } else {
1680            $this->assertFalse(core_useragent::is_webkit(),
1681                "Browser was incorrectly identified as a webkit browser");
1682            $this->assertFalse(core_useragent::check_webkit_version());
1683        }
1684
1685        $versions = array(
1686            // New versions should be added here.
1687        );
1688
1689        if (isset($tests['check_webkit_version'])) {
1690            // The test provider has overwritten some of the above checks.
1691            // Must use the '+' operator, because array_merge will incorrectly rewrite the array keys for integer-based indexes.
1692            $versions = $tests['check_webkit_version'] + $versions;
1693        }
1694
1695        foreach ($versions as $version => $result) {
1696            $this->assertEquals($result, core_useragent::check_webkit_version($version),
1697                "Version incorrectly determined for Webkit version '{$version}'");
1698        }
1699    }
1700
1701    /**
1702     * @dataProvider user_agents_providers
1703     */
1704    public function test_useragent_webkit_android($useragent, $tests) {
1705        // Setup the core_useragent instance.
1706        core_useragent::instance(true, $useragent);
1707
1708        if (isset($tests['is_webkit_android']) && $tests['is_webkit_android']) {
1709            $this->assertTrue(core_useragent::is_webkit_android(),
1710                "Browser was not identified as an Android webkit browser");
1711            $this->assertTrue(core_useragent::check_webkit_android_version());
1712        } else {
1713            $this->assertFalse(core_useragent::is_webkit_android(),
1714                "Browser was incorrectly identified as an Android webkit browser");
1715            $this->assertFalse(core_useragent::check_webkit_android_version());
1716        }
1717
1718        $versions = array(
1719            // New versions should be added here.
1720            '525'       => false,
1721            '527'       => false,
1722            '590'       => false,
1723        );
1724
1725        if (isset($tests['check_webkit_android_version'])) {
1726            // The test provider has overwritten some of the above checks.
1727            // Must use the '+' operator, because array_merge will incorrectly rewrite the array keys for integer-based indexes.
1728            $versions = $tests['check_webkit_android_version'] + $versions;
1729        }
1730
1731        foreach ($versions as $version => $result) {
1732            $this->assertEquals($result, core_useragent::check_webkit_android_version($version),
1733                "Version incorrectly determined for Android webkit version '{$version}'");
1734        }
1735    }
1736
1737    /**
1738     * @dataProvider user_agents_providers
1739     */
1740    public function test_useragent_chrome($useragent, $tests) {
1741        // Setup the core_useragent instance.
1742        core_useragent::instance(true, $useragent);
1743
1744        if (isset($tests['is_chrome']) && $tests['is_chrome']) {
1745            $this->assertTrue(core_useragent::is_chrome(),
1746                "Browser was not identified as a chrome browser");
1747            $this->assertTrue(core_useragent::check_chrome_version());
1748        } else {
1749            $this->assertFalse(core_useragent::is_chrome(),
1750                "Browser was incorrectly identified as a chrome browser");
1751            $this->assertFalse(core_useragent::check_chrome_version());
1752        }
1753
1754        $versions = array(
1755            // New versions should be added here.
1756            '7'         => false,
1757            '8'         => false,
1758            '10'        => false,
1759            '39'        => false,
1760        );
1761
1762        if (isset($tests['check_chrome_version'])) {
1763            // The test provider has overwritten some of the above checks.
1764            // Must use the '+' operator, because array_merge will incorrectly rewrite the array keys for integer-based indexes.
1765            $versions = $tests['check_chrome_version'] + $versions;
1766        }
1767
1768        foreach ($versions as $version => $result) {
1769            $this->assertEquals($result, core_useragent::check_chrome_version($version),
1770                "Version incorrectly determined for Chrome version '{$version}'");
1771        }
1772    }
1773
1774    /**
1775     * @dataProvider user_agents_providers
1776     */
1777    public function test_useragent_safari($useragent, $tests) {
1778        // Setup the core_useragent instance.
1779        core_useragent::instance(true, $useragent);
1780
1781        if (isset($tests['is_safari']) && $tests['is_safari']) {
1782            $this->assertTrue(core_useragent::is_safari(),
1783                "Browser was not identified as a safari browser");
1784            $this->assertTrue(core_useragent::check_safari_version());
1785        } else {
1786            $this->assertFalse(core_useragent::is_safari(),
1787                "Browser was incorrectly identified as a safari browser");
1788            $this->assertFalse(core_useragent::check_safari_version());
1789        }
1790
1791        // Check Safari (generic).
1792        $versions = array(
1793            // New versions should be added here.
1794            '1'         => false,
1795            '312'       => false,
1796            '500'       => false,
1797        );
1798
1799        if (isset($tests['check_safari_version'])) {
1800            // The test provider has overwritten some of the above checks.
1801            // Must use the '+' operator, because array_merge will incorrectly rewrite the array keys for integer-based indexes.
1802            $versions = $tests['check_safari_version'] + $versions;
1803        }
1804
1805        foreach ($versions as $version => $result) {
1806            $this->assertEquals($result, core_useragent::check_safari_version($version),
1807                "Version incorrectly determined for Safari (generic) version '{$version}'");
1808        }
1809    }
1810
1811    /**
1812     * @dataProvider user_agents_providers
1813     */
1814    public function test_useragent_ios_safari($useragent, $tests) {
1815        // Setup the core_useragent instance.
1816        core_useragent::instance(true, $useragent);
1817
1818        if (isset($tests['is_safari_ios']) && $tests['is_safari_ios']) {
1819            $this->assertTrue(core_useragent::is_safari_ios(),
1820                "Browser was not identified as an iOS safari browser");
1821            $this->assertTrue(core_useragent::check_safari_ios_version());
1822        } else {
1823            $this->assertFalse(core_useragent::is_safari_ios(),
1824                "Browser was incorrectly identified as an iOS safari browser");
1825            $this->assertFalse(core_useragent::check_safari_ios_version());
1826        }
1827
1828        // Check iOS Safari.
1829        $versions = array(
1830            // New versions should be added here.
1831            '527'       => false,
1832            '590'       => false,
1833            '600'       => false,
1834        );
1835
1836        if (isset($tests['check_safari_ios_version'])) {
1837            // The test provider has overwritten some of the above checks.
1838            // Must use the '+' operator, because array_merge will incorrectly rewrite the array keys for integer-based indexes.
1839            $versions = $tests['check_safari_ios_version'] + $versions;
1840        }
1841
1842        foreach ($versions as $version => $result) {
1843            $this->assertEquals($result, core_useragent::check_safari_ios_version($version),
1844                "Version incorrectly determined for iOS Safari version '{$version}'");
1845        }
1846    }
1847
1848    /**
1849     * @dataProvider user_agents_providers
1850     */
1851    public function test_useragent_ios($useragent, $tests) {
1852        // Setup the core_useragent instance.
1853        core_useragent::instance(true, $useragent);
1854
1855        if (isset($tests['is_ios']) && $tests['is_ios']) {
1856            $this->assertTrue(core_useragent::is_ios(),
1857                "Browser was not identified as an iOS device browser");
1858            // The iOS app is not Safari based.
1859            if (!isset($tests['is_moodle_app']) || !$tests['is_moodle_app']) {
1860                $this->assertTrue(core_useragent::check_safari_ios_version());
1861            }
1862        } else {
1863            $this->assertFalse(core_useragent::is_ios(),
1864                "Browser was incorrectly identified as an iOS device browser");
1865            $this->assertFalse(core_useragent::check_safari_ios_version());
1866        }
1867    }
1868
1869    /**
1870     * @dataProvider user_agents_providers
1871     */
1872    public function test_useragent_gecko($useragent, $tests) {
1873        // Setup the core_useragent instance.
1874        core_useragent::instance(true, $useragent);
1875
1876        if (isset($tests['is_gecko']) && $tests['is_gecko']) {
1877            $this->assertTrue(core_useragent::is_gecko(),
1878                "Browser was not identified as a gecko browser");
1879            $this->assertTrue(core_useragent::check_gecko_version());
1880        } else {
1881            $this->assertFalse(core_useragent::is_gecko(),
1882                "Browser was incorrectly identified as a gecko browser");
1883            $this->assertFalse(core_useragent::check_gecko_version());
1884        }
1885
1886        $versions = array(
1887            // New versions should be added here.
1888            '1'             => false,
1889            '2'             => false,
1890            '3.6'           => false,
1891            '4.0'           => false,
1892            '20030516'      => false,
1893            '20051116'      => false,
1894            '2006010100'    => false,
1895            '20100101'      => false,
1896            '15.0'          => false,
1897            '18.0'          => false,
1898            '19.0'          => false,
1899        );
1900
1901        if (isset($tests['check_gecko_version'])) {
1902            // The test provider has overwritten some of the above checks.
1903            // Must use the '+' operator, because array_merge will incorrectly rewrite the array keys for integer-based indexes.
1904            $versions = $tests['check_gecko_version'] + $versions;
1905        }
1906
1907        foreach ($versions as $version => $result) {
1908            $this->assertEquals($result, core_useragent::check_gecko_version($version),
1909                "Version incorrectly determined for Gecko version '{$version}'");
1910        }
1911    }
1912
1913    /**
1914     * @dataProvider user_agents_providers
1915     */
1916    public function test_useragent_firefox($useragent, $tests) {
1917        // Setup the core_useragent instance.
1918        core_useragent::instance(true, $useragent);
1919
1920        if (isset($tests['is_firefox']) && $tests['is_firefox']) {
1921            $this->assertTrue(core_useragent::is_firefox(),
1922                "Browser was not identified as a firefox browser");
1923            $this->assertTrue(core_useragent::check_firefox_version());
1924        } else {
1925            $this->assertFalse(core_useragent::is_firefox(),
1926                "Browser was incorrectly identified as a firefox browser");
1927            $this->assertFalse(core_useragent::check_firefox_version());
1928        }
1929
1930        $versions = array(
1931            // New versions should be added here.
1932            '1.5'       => false,
1933            '3.0'       => false,
1934            '4'         => false,
1935            '10'        => false,
1936            '15'        => false,
1937            '18'        => false,
1938            '19'        => false,
1939            '33'        => false,
1940        );
1941
1942        if (isset($tests['check_firefox_version'])) {
1943            // The test provider has overwritten some of the above checks.
1944            // Must use the '+' operator, because array_merge will incorrectly rewrite the array keys for integer-based indexes.
1945            $versions = $tests['check_firefox_version'] + $versions;
1946        }
1947
1948        foreach ($versions as $version => $result) {
1949            $this->assertEquals($result, core_useragent::check_firefox_version($version),
1950                "Version incorrectly determined for Firefox version '{$version}'");
1951        }
1952    }
1953
1954    /**
1955     * @dataProvider user_agents_providers
1956     */
1957    public function test_useragent_opera($useragent, $tests) {
1958        // Setup the core_useragent instance.
1959        core_useragent::instance(true, $useragent);
1960
1961        if (isset($tests['is_opera']) && $tests['is_opera']) {
1962            $this->assertTrue(core_useragent::is_opera(),
1963                "Browser was not identified as a opera browser");
1964            $this->assertTrue(core_useragent::check_opera_version());
1965        } else {
1966            $this->assertFalse(core_useragent::is_opera(),
1967                "Browser was incorrectly identified as a opera browser");
1968            $this->assertFalse(core_useragent::check_opera_version());
1969        }
1970
1971        $versions = array(
1972            // New versions should be added here.
1973            '8.0'       => false,
1974            '9.0'       => false,
1975            '10.0'      => false,
1976            '12.15'     => false,
1977        );
1978
1979        if (isset($tests['check_opera_version'])) {
1980            // The test provider has overwritten some of the above checks.
1981            // Must use the '+' operator, because array_merge will incorrectly rewrite the array keys for integer-based indexes.
1982            $versions = $tests['check_opera_version'] + $versions;
1983        }
1984
1985        foreach ($versions as $version => $result) {
1986            $this->assertEquals($result, core_useragent::check_opera_version($version),
1987                "Version incorrectly determined for Opera version '{$version}'");
1988        }
1989    }
1990
1991    /**
1992     * @dataProvider user_agents_providers
1993     */
1994    public function test_get_device_type($useragent, $tests) {
1995        // Setup the core_useragent instance.
1996        core_useragent::instance(true, $useragent);
1997
1998        $expected = 'default';
1999        if (isset($tests['devicetype'])) {
2000            $expected = $tests['devicetype'];
2001        }
2002
2003        $this->assertEquals($expected, core_useragent::get_device_type(),
2004            "Device Type was not correctly identified");
2005    }
2006
2007    /**
2008     * @dataProvider user_agents_providers
2009     */
2010    public function test_get_browser_version_classes($useragent, $tests) {
2011        // Setup the core_useragent instance.
2012        core_useragent::instance(true, $useragent);
2013
2014        $actual = core_useragent::get_browser_version_classes();
2015        foreach ($tests['versionclasses'] as $expectedclass) {
2016            $this->assertContains($expectedclass, $actual);
2017        }
2018        $this->assertCount(count($tests['versionclasses']), $actual);
2019    }
2020
2021    /**
2022     * @dataProvider user_agents_providers
2023     */
2024    public function test_useragent_web_crawler($useragent, $tests) {
2025        // Setup the core_useragent instance.
2026        core_useragent::instance(true, $useragent);
2027
2028        $expectation = isset($tests['is_web_crawler']) ? $tests['is_web_crawler'] : false;
2029        $this->assertSame($expectation, core_useragent::is_web_crawler());
2030    }
2031
2032    /**
2033     * @dataProvider user_agents_providers
2034     */
2035    public function test_useragent_moodle_app($useragent, $tests) {
2036        // Setup the core_useragent instance.
2037        core_useragent::instance(true, $useragent);
2038
2039        $expectation = isset($tests['is_moodle_app']) ? $tests['is_moodle_app'] : false;
2040        $this->assertSame($expectation, core_useragent::is_moodle_app());
2041    }
2042}
2043