Changeset 3196166
- Timestamp:
- 11/25/2024 07:44:33 AM (16 months ago)
- Location:
- tenweb-speed-optimizer/trunk
- Files:
-
- 22 edited
-
config.php (modified) (1 diff)
-
env.php (modified) (1 diff)
-
includes/OptimizerMain.php (modified) (1 diff)
-
readme.txt (modified) (2 diffs)
-
tenweb_speed_optimizer.php (modified) (1 diff)
-
vendor/10web/authorization/.gitignore (modified) (1 diff)
-
vendor/10web/authorization/src/Helper.php (modified) (4 diffs)
-
vendor/10web/authorization/src/ProductState.php (modified) (2 diffs)
-
vendor/10web/authorization/src/config/autoconnect_production.env.php (modified) (1 diff)
-
vendor/10web/authorization/src/config/local.env.php (modified) (1 diff)
-
vendor/10web/authorization/src/config/production.env.php (modified) (1 diff)
-
vendor/10web/authorization/src/config/staging.env.php (modified) (1 diff)
-
vendor/10web/authorization/src/config/testing.env.php (modified) (1 diff)
-
vendor/autoload.php (modified) (1 diff)
-
vendor/composer/autoload_real.php (modified) (2 diffs)
-
vendor/composer/autoload_static.php (modified) (2 diffs)
-
vendor/composer/installed.json (modified) (5 diffs)
-
vendor/composer/installed.php (modified) (5 diffs)
-
vendor/monperrus/crawler-user-agents/crawler-user-agents.json (modified) (1 diff)
-
vendor/monperrus/crawler-user-agents/validate.go (modified) (4 diffs)
-
vendor/monperrus/crawler-user-agents/validate_test.go (modified) (1 diff)
-
vendor/symfony/filesystem/Filesystem.php (modified) (3 diffs)
Legend:
- Unmodified
- Added
- Removed
-
tenweb-speed-optimizer/trunk/config.php
r3170042 r3196166 1 1 <?php 2 2 3 define('TENWEB_SO_VERSION', '2.30. 5');3 define('TENWEB_SO_VERSION', '2.30.7'); 4 4 define('TENWEB_SO_CONNECTED_FROM', 'speed_optimizer'); 5 5 define('TENWEB_SO_DIR', plugin_dir_path(TWO_PLUGIN_FILE)); -
tenweb-speed-optimizer/trunk/env.php
r3111518 r3196166 97 97 "us-west2" => "Los Angeles, California, USA" 98 98 ); 99 100 global $tenweb_firebaseConfig; 101 102 $tenweb_firebaseConfig = [ 103 'apiKey' => "AIzaSyADDO7CWkI1jd8HUXFVs7AwSt4z52i27Tc", 104 'authDomain'=> "copilote-prod-2096c.firebaseapp.com", 105 'projectId'=> "copilote-prod-2096c", 106 'storageBucket'=> "copilote-prod-2096c.appspot.com", 107 'messagingSenderId'=> "698503034199", 108 'appId'=> "1:698503034199:web:2282f40a461d9d95217a12", 109 'databaseURL' => "https://copilote-prod-2096c.firebaseio.com", 110 ]; 111 -
tenweb-speed-optimizer/trunk/includes/OptimizerMain.php
r3158582 r3196166 1091 1091 $delete_cache_db = OptimizerUtils::delete_all_cache_db(); 1092 1092 $delete_cache_file = OptimizerUtils::delete_all_cache_file($dir, [$dir, $dir . '/css', $dir . '/js']); 1093 OptimizerUtils::flushCloudflareCache(); 1093 1094 do_action('tenweb_purge_all_caches'); 1094 1095 -
tenweb-speed-optimizer/trunk/readme.txt
r3187477 r3196166 5 5 Tested up to: 6.7 6 6 Requires PHP: 7.4 7 Stable tag: 2.30. 57 Stable tag: 2.30.7 8 8 License: GPLv2 or later 9 9 License URI: http://www.gnu.org/licenses/gpl-2.0.html … … 273 273 == Changelog == 274 274 275 = 2.30.7 = 276 Fixed: Bug on Cloudflare cache flush 277 275 278 = 2.30.5 = 276 279 Improved: Integration with Breakdance builder -
tenweb-speed-optimizer/trunk/tenweb_speed_optimizer.php
r3170042 r3196166 4 4 * Plugin URI: https://10web.io/page-speed-booster/ 5 5 * Description: Optimize your website speed and performance with 10Web Booster by compressing CSS and JavaScript. 6 * Version: 2.30. 56 * Version: 2.30.7 7 7 * Author: 10Web - Website speed optimization team 8 8 * Author URI: https://10web.io/ -
tenweb-speed-optimizer/trunk/vendor/10web/authorization/.gitignore
r2753365 r3196166 1 1 /.idea/ 2 2 /vendor/ 3 .aider* 4 .env -
tenweb-speed-optimizer/trunk/vendor/10web/authorization/src/Helper.php
r2911090 r3196166 13 13 private static $instance; 14 14 private static $network_domain_id; 15 private static $auto_update_plugins; 15 16 private $login_instance; 16 17 public static $products_raw_data = array(); … … 719 720 self::$addons_state = array(); 720 721 self::$themes_state = array(); 722 self::$auto_update_plugins = get_site_option('auto_update_plugins', array()); 721 723 722 724 $site_installed_plugins = get_plugins(); … … 783 785 $state->set_tenweb_product(false); 784 786 $state->set_other_wp_info($file_name, $installed_plugin, self::get_installed_plugins_wp_info()); 787 //$state->set_is_autoupdate_enabled(in_array($file_name, self::$auto_update_plugins, true)); 788 785 789 786 790 self::$plugins_state[] = $state; … … 924 928 $state->set_is_paid($plugin_data['current_version']); 925 929 $state->set_other_wp_info($plugin_slug, $installed_plugin, $installed_plugins_info); 930 //$state->set_is_autoupdate_enabled(in_array($plugin_slug, self::$auto_update_plugins, true)); 926 931 927 932 -
tenweb-speed-optimizer/trunk/vendor/10web/authorization/src/ProductState.php
r2944643 r3196166 31 31 public $theme_errors = array();//@type array 32 32 33 public $is_autoupdate_enabled = 0;//@type int [0,1] 34 33 35 /** 34 36 * ProductState constructor. … … 154 156 } 155 157 158 public function set_is_autoupdate_enabled($is_autoupdate_enabled) 159 { 160 $this->is_autoupdate_enabled = (int)$is_autoupdate_enabled; 161 } 162 156 163 public function get_info() 157 164 { 158 165 $state = array( 159 'product_id' => $this->product_id, 160 'slug' => $this->slug, 161 'title' => $this->title, 162 'description' => $this->description, 163 'version' => $this->version, 164 'installed' => $this->installed ? 1 : 0, 165 'active' => $this->active ? 1 : 0, 166 'network_active' => $this->network_active ? 1 : 0, 167 'is_paid' => $this->is_paid ? 1 : 0, 168 'screenshot' => $this->screenshot, 169 'tenweb_product' => $this->tenweb_product ? 1 : 0, 170 'author' => $this->author, 171 'repo_version' => $this->repo_version 166 'product_id' => $this->product_id, 167 'slug' => $this->slug, 168 'title' => $this->title, 169 'description' => $this->description, 170 'version' => $this->version, 171 'installed' => $this->installed ? 1 : 0, 172 'active' => $this->active ? 1 : 0, 173 'network_active' => $this->network_active ? 1 : 0, 174 'is_paid' => $this->is_paid ? 1 : 0, 175 'screenshot' => $this->screenshot, 176 'tenweb_product' => $this->tenweb_product ? 1 : 0, 177 'author' => $this->author, 178 'repo_version' => $this->repo_version, 179 'autoupdate_enabled' => $this->is_autoupdate_enabled 172 180 ); 173 181 -
tenweb-speed-optimizer/trunk/vendor/10web/authorization/src/config/autoconnect_production.env.php
r3111518 r3196166 97 97 "us-west2" => "Los Angeles, California, USA" 98 98 ); 99 100 global $tenweb_firebaseConfig; 101 102 $tenweb_firebaseConfig = [ 103 'apiKey' => "AIzaSyBP3zPfSTMZxUqJsfmHMd6EJV2aITZ-3FY", 104 'authDomain'=> "copilot-dev-64f1d.firebaseapp.com", 105 'projectId'=> "copilot-dev-64f1d", 106 'storageBucket'=> "copilot-dev-64f1d.appspot.com", 107 'messagingSenderId'=> "101114320744", 108 'appId'=> "1:101114320744:web:3a98c2010c93b6e7a0a8dd", 109 'databaseURL' => "https://copilot-dev-64f1d.firebaseio.com", 110 ]; 111 -
tenweb-speed-optimizer/trunk/vendor/10web/authorization/src/config/local.env.php
r3111518 r3196166 97 97 "us-west2" => "Los Angeles, California, USA" 98 98 ); 99 100 global $tenweb_firebaseConfig; 101 102 $tenweb_firebaseConfig = [ 103 'apiKey' => "AIzaSyBP3zPfSTMZxUqJsfmHMd6EJV2aITZ-3FY", 104 'authDomain'=> "copilot-dev-64f1d.firebaseapp.com", 105 'projectId'=> "copilot-dev-64f1d", 106 'storageBucket'=> "copilot-dev-64f1d.appspot.com", 107 'messagingSenderId'=> "101114320744", 108 'appId'=> "1:101114320744:web:3a98c2010c93b6e7a0a8dd", 109 'databaseURL' => "https://copilot-dev-64f1d.firebaseio.com", 110 ]; 111 -
tenweb-speed-optimizer/trunk/vendor/10web/authorization/src/config/production.env.php
r3111518 r3196166 97 97 "us-west2" => "Los Angeles, California, USA" 98 98 ); 99 100 global $tenweb_firebaseConfig; 101 102 $tenweb_firebaseConfig = [ 103 'apiKey' => "AIzaSyADDO7CWkI1jd8HUXFVs7AwSt4z52i27Tc", 104 'authDomain'=> "copilote-prod-2096c.firebaseapp.com", 105 'projectId'=> "copilote-prod-2096c", 106 'storageBucket'=> "copilote-prod-2096c.appspot.com", 107 'messagingSenderId'=> "698503034199", 108 'appId'=> "1:698503034199:web:2282f40a461d9d95217a12", 109 'databaseURL' => "https://copilote-prod-2096c.firebaseio.com", 110 ]; 111 -
tenweb-speed-optimizer/trunk/vendor/10web/authorization/src/config/staging.env.php
r3111518 r3196166 96 96 "us-west2" => "Los Angeles, California, USA" 97 97 ); 98 99 global $tenweb_firebaseConfig; 100 101 $tenweb_firebaseConfig = [ 102 'apiKey' => "AIzaSyBP3zPfSTMZxUqJsfmHMd6EJV2aITZ-3FY", 103 'authDomain'=> "copilot-dev-64f1d.firebaseapp.com", 104 'projectId'=> "copilot-dev-64f1d", 105 'storageBucket'=> "copilot-dev-64f1d.appspot.com", 106 'messagingSenderId'=> "101114320744", 107 'appId'=> "1:101114320744:web:3a98c2010c93b6e7a0a8dd", 108 'databaseURL' => "https://copilot-dev-64f1d.firebaseio.com", 109 ]; 110 -
tenweb-speed-optimizer/trunk/vendor/10web/authorization/src/config/testing.env.php
r3111518 r3196166 97 97 "us-west2" => "Los Angeles, California, USA" 98 98 ); 99 100 global $tenweb_firebaseConfig; 101 102 $tenweb_firebaseConfig = [ 103 'apiKey' => "AIzaSyBP3zPfSTMZxUqJsfmHMd6EJV2aITZ-3FY", 104 'authDomain'=> "copilot-dev-64f1d.firebaseapp.com", 105 'projectId'=> "copilot-dev-64f1d", 106 'storageBucket'=> "copilot-dev-64f1d.appspot.com", 107 'messagingSenderId'=> "101114320744", 108 'appId'=> "1:101114320744:web:3a98c2010c93b6e7a0a8dd", 109 'databaseURL' => "https://copilot-dev-64f1d.firebaseio.com", 110 ]; -
tenweb-speed-optimizer/trunk/vendor/autoload.php
r3170042 r3196166 23 23 require_once __DIR__ . '/composer/autoload_real.php'; 24 24 25 return ComposerAutoloaderInit 124893b7c1f538d2a2a547c796c35cc0::getLoader();25 return ComposerAutoloaderInit32d2a2df551fda474f04e8446c5df1d0::getLoader(); -
tenweb-speed-optimizer/trunk/vendor/composer/autoload_real.php
r3170042 r3196166 3 3 // autoload_real.php @generated by Composer 4 4 5 class ComposerAutoloaderInit 124893b7c1f538d2a2a547c796c35cc05 class ComposerAutoloaderInit32d2a2df551fda474f04e8446c5df1d0 6 6 { 7 7 private static $loader; … … 25 25 require __DIR__ . '/platform_check.php'; 26 26 27 spl_autoload_register(array('ComposerAutoloaderInit 124893b7c1f538d2a2a547c796c35cc0', 'loadClassLoader'), true, true);27 spl_autoload_register(array('ComposerAutoloaderInit32d2a2df551fda474f04e8446c5df1d0', 'loadClassLoader'), true, true); 28 28 self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__)); 29 spl_autoload_unregister(array('ComposerAutoloaderInit 124893b7c1f538d2a2a547c796c35cc0', 'loadClassLoader'));29 spl_autoload_unregister(array('ComposerAutoloaderInit32d2a2df551fda474f04e8446c5df1d0', 'loadClassLoader')); 30 30 31 31 require __DIR__ . '/autoload_static.php'; 32 call_user_func(\Composer\Autoload\ComposerStaticInit 124893b7c1f538d2a2a547c796c35cc0::getInitializer($loader));32 call_user_func(\Composer\Autoload\ComposerStaticInit32d2a2df551fda474f04e8446c5df1d0::getInitializer($loader)); 33 33 34 34 $loader->register(true); 35 35 36 $filesToLoad = \Composer\Autoload\ComposerStaticInit 124893b7c1f538d2a2a547c796c35cc0::$files;36 $filesToLoad = \Composer\Autoload\ComposerStaticInit32d2a2df551fda474f04e8446c5df1d0::$files; 37 37 $requireFile = \Closure::bind(static function ($fileIdentifier, $file) { 38 38 if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) { -
tenweb-speed-optimizer/trunk/vendor/composer/autoload_static.php
r3170042 r3196166 5 5 namespace Composer\Autoload; 6 6 7 class ComposerStaticInit 124893b7c1f538d2a2a547c796c35cc07 class ComposerStaticInit32d2a2df551fda474f04e8446c5df1d0 8 8 { 9 9 public static $files = array ( … … 301 301 { 302 302 return \Closure::bind(function () use ($loader) { 303 $loader->prefixLengthsPsr4 = ComposerStaticInit 124893b7c1f538d2a2a547c796c35cc0::$prefixLengthsPsr4;304 $loader->prefixDirsPsr4 = ComposerStaticInit 124893b7c1f538d2a2a547c796c35cc0::$prefixDirsPsr4;305 $loader->prefixesPsr0 = ComposerStaticInit 124893b7c1f538d2a2a547c796c35cc0::$prefixesPsr0;306 $loader->classMap = ComposerStaticInit 124893b7c1f538d2a2a547c796c35cc0::$classMap;303 $loader->prefixLengthsPsr4 = ComposerStaticInit32d2a2df551fda474f04e8446c5df1d0::$prefixLengthsPsr4; 304 $loader->prefixDirsPsr4 = ComposerStaticInit32d2a2df551fda474f04e8446c5df1d0::$prefixDirsPsr4; 305 $loader->prefixesPsr0 = ComposerStaticInit32d2a2df551fda474f04e8446c5df1d0::$prefixesPsr0; 306 $loader->classMap = ComposerStaticInit32d2a2df551fda474f04e8446c5df1d0::$classMap; 307 307 308 308 }, null, ClassLoader::class); -
tenweb-speed-optimizer/trunk/vendor/composer/installed.json
r3158582 r3196166 148 148 "type": "git", 149 149 "url": "ssh://git@gitlab.10web.io:6202/10web-utils/tenweb-authorization.git", 150 "reference": " 7993a20e971e04412f6c11ac81339197fa51bfd5"151 }, 152 "time": "2024- 05-07T11:49:37+00:00",150 "reference": "16a820e0be9f95255404101d2d057394a5ae9d0d" 151 }, 152 "time": "2024-10-25T11:48:14+00:00", 153 153 "default-branch": true, 154 154 "type": "library", … … 537 537 "type": "git", 538 538 "url": "https://github.com/monperrus/crawler-user-agents.git", 539 "reference": " 6c0133b66cc2a01dc582a0efdcdddab6626b6f48"540 }, 541 "dist": { 542 "type": "zip", 543 "url": "https://api.github.com/repos/monperrus/crawler-user-agents/zipball/ 6c0133b66cc2a01dc582a0efdcdddab6626b6f48",544 "reference": " 6c0133b66cc2a01dc582a0efdcdddab6626b6f48",545 "shasum": "" 546 }, 547 "time": "2024- 09-25T08:31:49+00:00",539 "reference": "e464fa7cb22920f3927cd85d7de32aeedfbf6c85" 540 }, 541 "dist": { 542 "type": "zip", 543 "url": "https://api.github.com/repos/monperrus/crawler-user-agents/zipball/e464fa7cb22920f3927cd85d7de32aeedfbf6c85", 544 "reference": "e464fa7cb22920f3927cd85d7de32aeedfbf6c85", 545 "shasum": "" 546 }, 547 "time": "2024-10-23T05:56:48+00:00", 548 548 "default-branch": true, 549 549 "type": "library", … … 748 748 { 749 749 "name": "symfony/filesystem", 750 "version": "v5.4.4 4",751 "version_normalized": "5.4.4 4.0",750 "version": "v5.4.45", 751 "version_normalized": "5.4.45.0", 752 752 "source": { 753 753 "type": "git", 754 754 "url": "https://github.com/symfony/filesystem.git", 755 "reference": " 76c3818964e9d32be3862c9318ae3ba9aa280ddc"756 }, 757 "dist": { 758 "type": "zip", 759 "url": "https://api.github.com/repos/symfony/filesystem/zipball/ 76c3818964e9d32be3862c9318ae3ba9aa280ddc",760 "reference": " 76c3818964e9d32be3862c9318ae3ba9aa280ddc",755 "reference": "57c8294ed37d4a055b77057827c67f9558c95c54" 756 }, 757 "dist": { 758 "type": "zip", 759 "url": "https://api.github.com/repos/symfony/filesystem/zipball/57c8294ed37d4a055b77057827c67f9558c95c54", 760 "reference": "57c8294ed37d4a055b77057827c67f9558c95c54", 761 761 "shasum": "" 762 762 }, … … 770 770 "symfony/process": "^5.4|^6.4" 771 771 }, 772 "time": "2024- 09-16T14:52:48+00:00",772 "time": "2024-10-22T13:05:35+00:00", 773 773 "type": "library", 774 774 "installation-source": "dist", … … 798 798 "homepage": "https://symfony.com", 799 799 "support": { 800 "source": "https://github.com/symfony/filesystem/tree/v5.4.4 4"800 "source": "https://github.com/symfony/filesystem/tree/v5.4.45" 801 801 }, 802 802 "funding": [ -
tenweb-speed-optimizer/trunk/vendor/composer/installed.php
r3170042 r3196166 4 4 'pretty_version' => 'dev-master', 5 5 'version' => 'dev-master', 6 'reference' => ' dffc8d926b4028a66a9756d7f78e4d5f2a040e18',6 'reference' => '827ab9bc91d2cf6f4db1233d0b4587c3adf317e9', 7 7 'type' => 'project', 8 8 'install_path' => __DIR__ . '/../../', … … 69 69 'pretty_version' => 'dev-master', 70 70 'version' => 'dev-master', 71 'reference' => ' 7993a20e971e04412f6c11ac81339197fa51bfd5',71 'reference' => '16a820e0be9f95255404101d2d057394a5ae9d0d', 72 72 'type' => 'library', 73 73 'install_path' => __DIR__ . '/../10web/authorization', … … 134 134 'pretty_version' => 'dev-master', 135 135 'version' => 'dev-master', 136 'reference' => ' 6c0133b66cc2a01dc582a0efdcdddab6626b6f48',136 'reference' => 'e464fa7cb22920f3927cd85d7de32aeedfbf6c85', 137 137 'type' => 'library', 138 138 'install_path' => __DIR__ . '/../monperrus/crawler-user-agents', … … 163 163 'pretty_version' => 'dev-master', 164 164 'version' => 'dev-master', 165 'reference' => ' dffc8d926b4028a66a9756d7f78e4d5f2a040e18',165 'reference' => '827ab9bc91d2cf6f4db1233d0b4587c3adf317e9', 166 166 'type' => 'project', 167 167 'install_path' => __DIR__ . '/../../', … … 179 179 ), 180 180 'symfony/filesystem' => array( 181 'pretty_version' => 'v5.4.4 4',182 'version' => '5.4.4 4.0',183 'reference' => ' 76c3818964e9d32be3862c9318ae3ba9aa280ddc',181 'pretty_version' => 'v5.4.45', 182 'version' => '5.4.45.0', 183 'reference' => '57c8294ed37d4a055b77057827c67f9558c95c54', 184 184 'type' => 'library', 185 185 'install_path' => __DIR__ . '/../symfony/filesystem', -
tenweb-speed-optimizer/trunk/vendor/monperrus/crawler-user-agents/crawler-user-agents.json
r3158582 r3196166 4947 4947 "addition_date": "2024/08/30", 4948 4948 "instances": [] 4949 }, 4950 { 4951 "pattern": "facebookcatalog\\/", 4952 "addition_date": "2024/10/03", 4953 "instances": [ 4954 "facebookcatalog/1.0" 4955 ], 4956 "url": "https://developers.facebook.com/docs/sharing/webmasters/web-crawlers" 4957 }, 4958 { 4959 "pattern": "meta-externalagent\\/", 4960 "addition_date": "2024/10/03", 4961 "instances": [ 4962 "meta-externalagent/1.1 (+https://developers.facebook.com/docs/sharing/webmasters/crawler)", 4963 "meta-externalagent/1.1" 4964 ], 4965 "url": "https://developers.facebook.com/docs/sharing/webmasters/web-crawlers" 4966 }, 4967 { 4968 "pattern": "meta-externalfetcher\\/", 4969 "addition_date": "2024/10/03", 4970 "instances": [ 4971 "meta-externalfetcher/1.1 (+https://developers.facebook.com/docs/sharing/webmasters/crawler)", 4972 "meta-externalfetcher/1.1" 4973 ], 4974 "url": "https://developers.facebook.com/docs/sharing/webmasters/web-crawlers" 4975 }, 4976 { 4977 "pattern": "AcademicBotRTU", 4978 "addition_date": "2024/10/17", 4979 "instances": [ 4980 "AcademicBotRTU (https://academicbot.rtu.lv; mailto:caps@rtu.lv)" 4981 ], 4982 "url": "https://academicbot.rtu.lv" 4983 }, 4984 { 4985 "pattern": "KeybaseBot", 4986 "addition_date": "2024/10/21", 4987 "url": "https://book.keybase.io/docs/chat/link-previews", 4988 "instances": [ 4989 "Mozilla/5.0 (compatible; KeybaseBot; +https://keybase.io)" 4990 ] 4949 4991 } 4950 4992 ] -
tenweb-speed-optimizer/trunk/vendor/monperrus/crawler-user-agents/validate.go
r3111518 r3196166 3 3 import ( 4 4 _ "embed" 5 "encoding/hex" 5 6 "encoding/json" 6 7 "fmt" 8 "hash/maphash" 7 9 "regexp" 10 "regexp/syntax" 11 "strconv" 12 "strings" 8 13 "time" 14 "unicode" 9 15 ) 10 16 … … 27 33 } 28 34 29 // Private t ime needed to convert addition_date from/to the format used in JSON.35 // Private type needed to convert addition_date from/to the format used in JSON. 30 36 type jsonCrawler struct { 31 37 Pattern string `json:"pattern"` … … 81 87 }() 82 88 83 var regexps = func() []*regexp.Regexp { 84 regexps := make([]*regexp.Regexp, len(Crawlers)) 89 // analyzePattern expands a regular expression to the list of matching texts 90 // for plain search. The list is complete, i.e. iff a text matches the input 91 // pattern, then it contains at least one of the returned texts. If such a list 92 // can't be built, then the resulting list contains one element (main literal), 93 // it also returns built regexp object to run in this case. The main literal is 94 // a text that is contained in any matching text and is used to optimize search 95 // (pre-filter with this main literal before running a regexp). In the case such 96 // a main literal can't be found or the regexp is invalid, an error is returned. 97 func analyzePattern(pattern string) ([]string, *regexp.Regexp, error) { 98 re, err := syntax.Parse(pattern, syntax.Perl) 99 if err != nil { 100 return nil, nil, fmt.Errorf("re %q does not compile: %w", pattern, err) 101 } 102 re = re.Simplify() 103 104 // Try to convert it to the list of literals. 105 const maxLiterals = 100 106 literals, ok := literalizeRegexp(re, maxLiterals) 107 if ok { 108 return literals, nil, nil 109 } 110 111 // Fallback to using a regexp, but we need some string serving as 112 // an indicator of its possible presence. 113 mainLiteral := findLongestCommonLiteral(re) 114 const minLiteralLen = 3 115 if len(mainLiteral) < minLiteralLen { 116 return nil, nil, fmt.Errorf("re %q does not contain sufficiently long literal to serve an indicator. The longest literal is %q", pattern, mainLiteral) 117 } 118 119 return []string{mainLiteral}, regexp.MustCompile(pattern), nil 120 } 121 122 // literalizeRegexp expands a regexp to the list of matching sub-strings. 123 // Iff a text matches the regexp, it contains at least one of the returned 124 // texts. Argument maxLiterals regulates the maximum number of patterns to 125 // return. In case of an overflow or if it is impossible to build such a list 126 // from the regexp, false is returned. 127 func literalizeRegexp(re *syntax.Regexp, maxLiterals int) (literals []string, ok bool) { 128 switch re.Op { 129 case syntax.OpNoMatch: 130 return nil, true 131 132 case syntax.OpEmptyMatch: 133 return []string{""}, true 134 135 case syntax.OpLiteral: 136 return unwrapCase(re, []string{string(re.Rune)}, maxLiterals) 137 138 case syntax.OpCharClass: 139 count := 0 140 for i := 0; i < len(re.Rune); i += 2 { 141 first := re.Rune[i] 142 last := re.Rune[i+1] 143 count += int(last - first + 1) 144 } 145 146 if count > maxLiterals { 147 return nil, false 148 } 149 150 patterns := make([]string, 0, count) 151 for i := 0; i < len(re.Rune); i += 2 { 152 first := re.Rune[i] 153 last := re.Rune[i+1] 154 for r := first; r <= last; r++ { 155 patterns = append(patterns, string([]rune{r})) 156 } 157 } 158 159 return unwrapCase(re, patterns, maxLiterals) 160 161 case syntax.OpAnyCharNotNL, syntax.OpAnyChar: 162 // Not supported. 163 return nil, false 164 165 case syntax.OpBeginLine, syntax.OpBeginText: 166 return []string{"^"}, true 167 168 case syntax.OpEndLine, syntax.OpEndText: 169 return []string{"$"}, true 170 171 case syntax.OpWordBoundary, syntax.OpNoWordBoundary: 172 // Not supported. 173 return nil, false 174 175 case syntax.OpCapture: 176 subList, ok := literalizeRegexp(re.Sub[0], maxLiterals) 177 if !ok { 178 return nil, false 179 } 180 181 return unwrapCase(re, subList, maxLiterals) 182 183 case syntax.OpStar, syntax.OpPlus: 184 // Not supported. 185 return nil, false 186 187 case syntax.OpQuest: 188 if re.Flags&syntax.FoldCase != 0 { 189 return nil, false 190 } 191 192 subList, ok := literalizeRegexp(re.Sub[0], maxLiterals) 193 if !ok { 194 return nil, false 195 } 196 subList = append(subList, "") 197 198 return subList, true 199 200 case syntax.OpRepeat: 201 // Not supported. 202 return nil, false 203 204 case syntax.OpConcat: 205 if re.Flags&syntax.FoldCase != 0 { 206 return nil, false 207 } 208 209 matrix := make([][]string, len(re.Sub)) 210 for i, sub := range re.Sub { 211 subList, ok := literalizeRegexp(sub, maxLiterals) 212 if !ok { 213 return nil, false 214 } 215 matrix[i] = subList 216 } 217 218 return combinations(matrix, maxLiterals) 219 220 case syntax.OpAlternate: 221 results := []string{} 222 for _, sub := range re.Sub { 223 subList, ok := literalizeRegexp(sub, maxLiterals) 224 if !ok { 225 return nil, false 226 } 227 results = append(results, subList...) 228 } 229 230 if len(results) > maxLiterals { 231 return nil, false 232 } 233 234 return unwrapCase(re, results, maxLiterals) 235 236 default: 237 // Not supported. 238 return nil, false 239 } 240 } 241 242 // combinations produces all combination of elements of matrix. 243 // Each sub-slice of matrix contributes one part of a resulting string. 244 // If the number of combinations is larger than maxLiterals, the function 245 // returns false. 246 func combinations(matrix [][]string, maxLiterals int) ([]string, bool) { 247 if len(matrix) == 1 { 248 if len(matrix[0]) > maxLiterals { 249 return nil, false 250 } 251 252 return matrix[0], true 253 } 254 255 prefixes := matrix[0] 256 suffixes, ok := combinations(matrix[1:], maxLiterals) 257 if !ok { 258 return nil, false 259 } 260 261 size := len(prefixes) * len(suffixes) 262 if size > maxLiterals { 263 return nil, false 264 } 265 266 results := make([]string, 0, size) 267 for _, prefix := range prefixes { 268 for _, suffix := range suffixes { 269 results = append(results, prefix+suffix) 270 } 271 } 272 273 return results, true 274 } 275 276 // unwrapCase takes the regexp and the list of patterns expanded from it and 277 // further expands it for a case-insensitive regexp, if needed. Argument 278 // maxLiterals regulates the maximum number of patterns to return. In case of an 279 // overflow, false is returned. 280 func unwrapCase(re *syntax.Regexp, patterns []string, maxLiterals int) ([]string, bool) { 281 if re.Flags&syntax.FoldCase == 0 { 282 return patterns, true 283 } 284 285 results := []string{} 286 for _, pattern := range patterns { 287 matrix := make([][]string, len(pattern)) 288 for i, r := range pattern { 289 upper := unicode.ToUpper(r) 290 lower := unicode.ToLower(r) 291 matrix[i] = []string{ 292 string([]rune{upper}), 293 string([]rune{lower}), 294 } 295 } 296 297 patterns, ok := combinations(matrix, maxLiterals) 298 if !ok { 299 return nil, false 300 } 301 302 results = append(results, patterns...) 303 if len(results) > maxLiterals { 304 return nil, false 305 } 306 } 307 308 return results, true 309 } 310 311 // findLongestCommonLiteral finds the longest common literal in the regexp. It's 312 // such a string which is contained in any text matching the regexp. If such a 313 // literal can't be found, it returns an empty string. 314 func findLongestCommonLiteral(re *syntax.Regexp) string { 315 if re.Flags&syntax.FoldCase != 0 { 316 return "" 317 } 318 319 switch re.Op { 320 case syntax.OpNoMatch, syntax.OpEmptyMatch: 321 return "" 322 323 case syntax.OpLiteral: 324 return string(re.Rune) 325 326 case syntax.OpCharClass, syntax.OpAnyCharNotNL, syntax.OpAnyChar: 327 return "" 328 329 case syntax.OpBeginLine, syntax.OpBeginText: 330 return "^" 331 332 case syntax.OpEndLine, syntax.OpEndText: 333 return "$" 334 335 case syntax.OpWordBoundary, syntax.OpNoWordBoundary: 336 return "" 337 338 case syntax.OpCapture: 339 return findLongestCommonLiteral(re.Sub[0]) 340 341 case syntax.OpStar: 342 return "" 343 344 case syntax.OpPlus: 345 return findLongestCommonLiteral(re.Sub[0]) 346 347 case syntax.OpQuest: 348 return "" 349 350 case syntax.OpRepeat: 351 if re.Min >= 1 { 352 return findLongestCommonLiteral(re.Sub[0]) 353 } 354 355 return "" 356 357 case syntax.OpConcat: 358 longest := "" 359 for _, sub := range re.Sub { 360 str := findLongestCommonLiteral(sub) 361 if len(str) > len(longest) { 362 longest = str 363 } 364 } 365 366 return longest 367 368 case syntax.OpAlternate: 369 return "" 370 371 default: 372 return "" 373 } 374 } 375 376 type regexpPattern struct { 377 re *regexp.Regexp 378 index int 379 } 380 381 type matcher struct { 382 replacer *strings.Replacer 383 regexps []regexpPattern 384 } 385 386 var uniqueToken = hex.EncodeToString((&maphash.Hash{}).Sum(nil)) 387 388 const ( 389 uniqueTokenLen = 2 * 8 390 numLen = 5 391 literalLabel = '-' 392 regexpLabel = '*' 393 ) 394 395 var m = func() matcher { 396 if len(uniqueToken) != uniqueTokenLen { 397 panic("len(uniqueToken) != uniqueTokenLen") 398 } 399 400 regexps := []regexpPattern{} 401 oldnew := make([]string, 0, len(Crawlers)*2) 402 403 // Put re-based patterns to the end to prevent AdsBot-Google from 404 // shadowing AdsBot-Google-Mobile. 405 var oldnew2 []string 406 85 407 for i, crawler := range Crawlers { 86 regexps[i] = regexp.MustCompile(crawler.Pattern) 87 } 88 return regexps 408 literals, re, err := analyzePattern(crawler.Pattern) 409 if err != nil { 410 panic(err) 411 } 412 413 label := literalLabel 414 num := i 415 if re != nil { 416 label = regexpLabel 417 num = len(regexps) 418 regexps = append(regexps, regexpPattern{ 419 re: re, 420 index: i, 421 }) 422 } 423 424 replaceWith := fmt.Sprintf(" %s%c%0*d ", uniqueToken, label, numLen, num) 425 426 for _, literal := range literals { 427 if re != nil { 428 oldnew2 = append(oldnew2, literal, replaceWith) 429 } else { 430 oldnew = append(oldnew, literal, replaceWith) 431 } 432 } 433 } 434 oldnew = append(oldnew, oldnew2...) 435 436 // Allocate another array with regexps of exact size to save memory. 437 regexps2 := make([]regexpPattern, len(regexps)) 438 copy(regexps2, regexps) 439 440 r := strings.NewReplacer(oldnew...) 441 r.Replace("") // To cause internal build process. 442 443 return matcher{ 444 replacer: r, 445 regexps: regexps2, 446 } 89 447 }() 90 448 91 449 // Returns if User Agent string matches any of crawler patterns. 92 450 func IsCrawler(userAgent string) bool { 93 for _, re := range regexps { 94 if re.MatchString(userAgent) { 451 // This code is mostly copy-paste of MatchingCrawlers, 452 // but with early exit logic, so it works a but faster. 453 454 text := "^" + userAgent + "$" 455 replaced := m.replacer.Replace(text) 456 if replaced == text { 457 return false 458 } 459 460 for { 461 uniquePos := strings.Index(replaced, uniqueToken) 462 if uniquePos == -1 { 463 break 464 } 465 466 start := uniquePos + uniqueTokenLen + 1 467 if start+numLen >= len(replaced) { 468 panic("corrupt replaced: " + replaced) 469 } 470 471 label := replaced[start-1] 472 switch label { 473 case literalLabel: 95 474 return true 96 } 97 } 475 case regexpLabel: 476 // Rare case. Run regexp to confirm the match. 477 indexStr := replaced[start : start+numLen] 478 index, err := strconv.Atoi(indexStr) 479 if err != nil { 480 panic("corrupt replaced: " + replaced) 481 } 482 rp := m.regexps[index] 483 if rp.re.MatchString(userAgent) { 484 return true 485 } 486 default: 487 panic("corrupt replaced: " + replaced) 488 } 489 490 replaced = replaced[start+numLen:] 491 } 492 98 493 return false 99 494 } … … 101 496 // Finds all crawlers matching the User Agent and returns the list of their indices in Crawlers. 102 497 func MatchingCrawlers(userAgent string) []int { 498 text := "^" + userAgent + "$" 499 replaced := m.replacer.Replace(text) 500 if replaced == text { 501 return []int{} 502 } 503 103 504 indices := []int{} 104 for i, re := range regexps { 105 if re.MatchString(userAgent) { 106 indices = append(indices, i) 107 } 108 } 505 for { 506 uniquePos := strings.Index(replaced, uniqueToken) 507 if uniquePos == -1 { 508 break 509 } 510 511 start := uniquePos + uniqueTokenLen + 1 512 if start+numLen >= len(replaced) { 513 panic("corrupt replaced: " + replaced) 514 } 515 indexStr := replaced[start : start+numLen] 516 index, err := strconv.Atoi(indexStr) 517 if err != nil { 518 panic("corrupt replaced: " + replaced) 519 } 520 521 label := replaced[start-1] 522 switch label { 523 case literalLabel: 524 indices = append(indices, index) 525 case regexpLabel: 526 // Rare case. Run regexp to confirm the match. 527 rp := m.regexps[index] 528 if rp.re.MatchString(userAgent) { 529 indices = append(indices, rp.index) 530 } 531 default: 532 panic("corrupt replaced: " + replaced) 533 } 534 535 replaced = replaced[start+numLen:] 536 } 537 109 538 return indices 110 539 } -
tenweb-speed-optimizer/trunk/vendor/monperrus/crawler-user-agents/validate_test.go
r3111518 r3196166 5 5 "fmt" 6 6 "net/http" 7 "reflect" 8 "regexp/syntax" 9 "sort" 10 "strings" 7 11 "testing" 8 12 ) 13 14 // TestAnalyzePattern tests analyzePattern function on many cases, including 15 // edge cases. 16 func TestAnalyzePattern(t *testing.T) { 17 cases := []struct { 18 input string 19 wantError string 20 wantPatterns []string 21 wantRe bool 22 shouldMatchRe []string 23 shouldNotMatchRe []string 24 }{ 25 { 26 input: "simple phrase", 27 wantPatterns: []string{"simple phrase"}, 28 }, 29 { 30 input: "^begin anchor", 31 wantPatterns: []string{"^begin anchor"}, 32 }, 33 { 34 input: "end anchor$", 35 wantPatterns: []string{"end anchor$"}, 36 }, 37 { 38 input: "^both anchors$", 39 wantPatterns: []string{"^both anchors$"}, 40 }, 41 { 42 input: "(alter|nation)", 43 wantPatterns: []string{"alter", "nation"}, 44 }, 45 { 46 input: "too many [aA][lL][tT][eE][rR][nN][aA][tT][iI][oO][nN][sS]", 47 wantPatterns: []string{"too many "}, 48 wantRe: true, 49 shouldMatchRe: []string{"too many ALTERNATIONs"}, 50 shouldNotMatchRe: []string{"too many combinations "}, 51 }, 52 { 53 input: "(alter|nation) concatenation (alter|nation)", 54 wantPatterns: []string{ 55 "alter concatenation alter", 56 "alter concatenation nation", 57 "nation concatenation alter", 58 "nation concatenation nation", 59 }, 60 }, 61 { 62 input: "clas[sS] of [c]haract[eiu]rs", 63 wantPatterns: []string{ 64 "clasS of characters", 65 "clasS of charactirs", 66 "clasS of characturs", 67 "class of characters", 68 "class of charactirs", 69 "class of characturs", 70 }, 71 }, 72 { 73 input: "ranges [0-3]x[a-c]", 74 wantPatterns: []string{ 75 "ranges 0xa", "ranges 0xb", "ranges 0xc", 76 "ranges 1xa", "ranges 1xb", "ranges 1xc", 77 "ranges 2xa", "ranges 2xb", "ranges 2xc", 78 "ranges 3xa", "ranges 3xb", "ranges 3xc", 79 }, 80 }, 81 { 82 input: "Quest?", 83 wantPatterns: []string{"Ques", "Quest"}, 84 }, 85 { 86 input: "Q?ue(st)?", 87 wantPatterns: []string{"Que", "Quest", "ue", "uest"}, 88 }, 89 { 90 input: "too many combinations [0-9][a-z]", 91 wantPatterns: []string{"too many combinations "}, 92 wantRe: true, 93 shouldMatchRe: []string{"too many combinations 0a"}, 94 shouldNotMatchRe: []string{"too many combinations "}, 95 }, 96 { 97 input: "negation in char class [^x]", 98 wantPatterns: []string{"negation in char class "}, 99 wantRe: true, 100 shouldMatchRe: []string{"negation in char class y"}, 101 shouldNotMatchRe: []string{"negation in char class x"}, 102 }, 103 { 104 input: "any char .", 105 wantPatterns: []string{"any char "}, 106 wantRe: true, 107 shouldMatchRe: []string{"any char x"}, 108 shouldNotMatchRe: []string{"any char_x"}, 109 }, 110 { 111 input: `word \boundary`, 112 wantPatterns: []string{"oundary"}, 113 wantRe: true, 114 shouldMatchRe: []string{"word oundary"}, 115 shouldNotMatchRe: []string{"word boundary"}, 116 }, 117 { 118 input: "asterisk*", 119 wantPatterns: []string{"asteris"}, 120 wantRe: true, 121 shouldMatchRe: []string{"asteris", "asterisk", "asteriskk"}, 122 shouldNotMatchRe: []string{"asterik"}, 123 }, 124 { 125 input: "plus+", 126 wantPatterns: []string{"plu"}, 127 wantRe: true, 128 shouldMatchRe: []string{"plus", "pluss"}, 129 shouldNotMatchRe: []string{"plu"}, 130 }, 131 { 132 input: "repeat{3,5}$", 133 wantPatterns: []string{"repeattt$", "repeatttt$", "repeattttt$"}, 134 }, 135 { 136 input: "repeat{1,120}$", 137 wantPatterns: []string{"repea"}, 138 wantRe: true, 139 shouldMatchRe: []string{"repeattt", "repeatttt", "repeattttt"}, 140 shouldNotMatchRe: []string{"repea5"}, 141 }, 142 { 143 input: "broken re[", 144 wantError: "does not compile", 145 }, 146 { 147 input: "n?o? ?l?o?n?g? ?l?i?t?e?r?a?l?", 148 wantError: "does not contain sufficiently long literal", 149 }, 150 } 151 152 for _, tc := range cases { 153 tc := tc 154 155 t.Run(tc.input, func(t *testing.T) { 156 gotPatterns, re, err := analyzePattern(tc.input) 157 if tc.wantError != "" { 158 if err == nil { 159 t.Fatalf("expected to get an error, got success") 160 } 161 if !strings.Contains(err.Error(), tc.wantError) { 162 t.Fatalf("the error returned must contain text %q, got %q", tc.wantError, err.Error()) 163 } 164 165 return 166 } 167 168 if err != nil { 169 t.Fatalf("unexpected error: %v", err) 170 } 171 172 sort.Strings(tc.wantPatterns) 173 sort.Strings(gotPatterns) 174 if !reflect.DeepEqual(tc.wantPatterns, gotPatterns) { 175 t.Fatalf("returned list of patterns (%#v) does not match the expected value (%#v)", gotPatterns, tc.wantPatterns) 176 } 177 178 if !tc.wantRe { 179 if re != nil { 180 t.Fatalf("unexpectedly got a re") 181 } 182 183 return 184 } 185 186 if re == nil { 187 t.Fatalf("expected to get a re, got nil") 188 } 189 for _, text := range tc.shouldMatchRe { 190 if !re.MatchString(text) { 191 t.Fatalf("test %q must match against the re, but it doesn't", text) 192 } 193 } 194 for _, text := range tc.shouldNotMatchRe { 195 if re.MatchString(text) { 196 t.Fatalf("test %q must not match against the re, but it does", text) 197 } 198 } 199 }) 200 } 201 } 202 203 // TestLiteralizeRegexp tests expansion of a regexp to a list of literals. 204 func TestLiteralizeRegexp(t *testing.T) { 205 cases := []struct { 206 input string 207 maxLiterals int 208 wantOutput []string 209 wantOverflow bool 210 }{ 211 { 212 input: "simple phrase", 213 maxLiterals: 100, 214 wantOutput: []string{"simple phrase"}, 215 }, 216 { 217 input: "cases [1-2x-z]", 218 maxLiterals: 100, 219 wantOutput: []string{"cases 1", "cases 2", "cases x", "cases y", "cases z"}, 220 }, 221 { 222 input: "[Ii]gnore case", 223 maxLiterals: 100, 224 wantOutput: []string{"Ignore case", "ignore case"}, 225 }, 226 { 227 input: "overflow [1-2x-z]", 228 maxLiterals: 2, 229 wantOverflow: true, 230 }, 231 } 232 233 for _, tc := range cases { 234 tc := tc 235 236 t.Run(tc.input, func(t *testing.T) { 237 re, err := syntax.Parse(tc.input, syntax.Perl) 238 if err != nil { 239 t.Fatalf("failed to parse regexp %q: %v", tc.input, err) 240 } 241 242 gotPatterns, ok := literalizeRegexp(re, tc.maxLiterals) 243 if tc.wantOverflow { 244 if ok { 245 t.Fatalf("expected to get an overflow, got success") 246 } 247 248 return 249 } 250 251 if !ok { 252 t.Fatalf("unexpected overflow") 253 } 254 255 sort.Strings(tc.wantOutput) 256 sort.Strings(gotPatterns) 257 if !reflect.DeepEqual(tc.wantOutput, gotPatterns) { 258 t.Fatalf("returned list of patterns (%#v) does not match the expected value (%#v)", gotPatterns, tc.wantOutput) 259 } 260 }) 261 } 262 } 263 264 // TestCombinations tests combinations() function. 265 func TestCombinations(t *testing.T) { 266 cases := []struct { 267 name string 268 input [][]string 269 maxLiterals int 270 wantOutput []string 271 wantOverflow bool 272 }{ 273 { 274 name: "1x1", 275 input: [][]string{{"A"}, {"B"}}, 276 maxLiterals: 100, 277 wantOutput: []string{"AB"}, 278 }, 279 { 280 name: "0x1", 281 input: [][]string{{}, {"B"}}, 282 maxLiterals: 100, 283 wantOutput: []string{}, 284 }, 285 { 286 name: "1x2", 287 input: [][]string{{"A"}, {"1", "2"}}, 288 maxLiterals: 100, 289 wantOutput: []string{"A1", "A2"}, 290 }, 291 { 292 name: "2x2", 293 input: [][]string{{"A", "B"}, {"1", "2"}}, 294 maxLiterals: 100, 295 wantOutput: []string{"A1", "A2", "B1", "B2"}, 296 }, 297 { 298 name: "empty string as an option", 299 input: [][]string{{"A", ""}, {"1", "2"}}, 300 maxLiterals: 100, 301 wantOutput: []string{"A1", "A2", "1", "2"}, 302 }, 303 { 304 name: "overflow", 305 input: [][]string{{"A", "B"}, {"1", "2"}}, 306 maxLiterals: 3, 307 wantOverflow: true, 308 }, 309 } 310 311 for _, tc := range cases { 312 tc := tc 313 314 t.Run(tc.name, func(t *testing.T) { 315 gotPatterns, ok := combinations(tc.input, tc.maxLiterals) 316 if tc.wantOverflow { 317 if ok { 318 t.Fatalf("expected to get an overflow, got success") 319 } 320 321 return 322 } 323 324 if !ok { 325 t.Fatalf("unexpected overflow") 326 } 327 328 sort.Strings(tc.wantOutput) 329 sort.Strings(gotPatterns) 330 if !reflect.DeepEqual(tc.wantOutput, gotPatterns) { 331 t.Fatalf("returned list of patterns (%#v) does not match the expected value (%#v)", gotPatterns, tc.wantOutput) 332 } 333 }) 334 } 335 } 336 337 // TestUnwrapCase tests unwrapping literals of case-insensitive regexps. 338 func TestUnwrapCase(t *testing.T) { 339 cases := []struct { 340 name string 341 ignoreCase bool 342 inputPatterns []string 343 maxLiterals int 344 wantOutput []string 345 wantOverflow bool 346 }{ 347 { 348 name: "simple phrase", 349 inputPatterns: []string{"simple phrase"}, 350 maxLiterals: 100, 351 wantOutput: []string{"simple phrase"}, 352 }, 353 { 354 name: "ignore case", 355 ignoreCase: true, 356 inputPatterns: []string{"i"}, 357 maxLiterals: 100, 358 wantOutput: []string{"i", "I"}, 359 }, 360 { 361 name: "ignore case two letters", 362 ignoreCase: true, 363 inputPatterns: []string{"ic"}, 364 maxLiterals: 100, 365 wantOutput: []string{"IC", "Ic", "iC", "ic"}, 366 }, 367 { 368 name: "ignore case two words", 369 ignoreCase: true, 370 inputPatterns: []string{"i", "c"}, 371 maxLiterals: 100, 372 wantOutput: []string{"C", "I", "c", "i"}, 373 }, 374 { 375 name: "ignore case overflow", 376 ignoreCase: true, 377 inputPatterns: []string{"long text"}, 378 maxLiterals: 100, 379 wantOverflow: true, 380 }, 381 } 382 383 for _, tc := range cases { 384 tc := tc 385 386 t.Run(tc.name, func(t *testing.T) { 387 re := &syntax.Regexp{} 388 if tc.ignoreCase { 389 re.Flags = syntax.FoldCase 390 } 391 392 gotPatterns, ok := unwrapCase(re, tc.inputPatterns, tc.maxLiterals) 393 if tc.wantOverflow { 394 if ok { 395 t.Fatalf("expected to get an overflow, got success") 396 } 397 398 return 399 } 400 401 if !ok { 402 t.Fatalf("unexpected overflow") 403 } 404 405 sort.Strings(tc.wantOutput) 406 sort.Strings(gotPatterns) 407 if !reflect.DeepEqual(tc.wantOutput, gotPatterns) { 408 t.Fatalf("returned list of patterns (%#v) does not match the expected value (%#v)", gotPatterns, tc.wantOutput) 409 } 410 }) 411 } 412 } 413 414 // TestFindLongestCommonLiteral tests finding longest literal in a regexp. 415 func TestFindLongestCommonLiteral(t *testing.T) { 416 cases := []struct { 417 input string 418 wantOutput string 419 }{ 420 { 421 input: "simple phrase", 422 wantOutput: "simple phrase", 423 }, 424 { 425 input: "simple (phrase)?", 426 wantOutput: "simple ", 427 }, 428 { 429 input: "[iI]", 430 wantOutput: "", 431 }, 432 { 433 input: "[i]b", 434 wantOutput: "ib", 435 }, 436 { 437 input: "simple (phrase)+", 438 wantOutput: "simple ", 439 }, 440 { 441 input: "a*", 442 wantOutput: "", 443 }, 444 { 445 input: "(abc)|(ab)", 446 wantOutput: "", 447 }, 448 } 449 450 for _, tc := range cases { 451 tc := tc 452 453 t.Run(tc.input, func(t *testing.T) { 454 re, err := syntax.Parse(tc.input, syntax.Perl) 455 if err != nil { 456 t.Fatalf("failed to parse regexp %q: %v", tc.input, err) 457 } 458 459 gotOutput := findLongestCommonLiteral(re) 460 461 if gotOutput != tc.wantOutput { 462 t.Fatalf("returned value (%q) does not match the expected value (%q)", gotOutput, tc.wantOutput) 463 } 464 }) 465 } 466 } 9 467 10 468 func contains(list []int, value int) bool { -
tenweb-speed-optimizer/trunk/vendor/symfony/filesystem/Filesystem.php
r3158582 r3196166 45 45 46 46 $doCopy = true; 47 if (!$overwriteNewerFiles && null ===parse_url($originFile, \PHP_URL_HOST) && is_file($targetFile)) {47 if (!$overwriteNewerFiles && !parse_url($originFile, \PHP_URL_HOST) && is_file($targetFile)) { 48 48 $doCopy = filemtime($originFile) > filemtime($targetFile); 49 49 } … … 235 235 * 236 236 * This method always throws on Windows, as the underlying PHP function is not supported. 237 * 237 238 * @see https://www.php.net/chown 238 239 * … … 265 266 * 266 267 * This method always throws on Windows, as the underlying PHP function is not supported. 268 * 267 269 * @see https://www.php.net/chgrp 268 270 *
Note: See TracChangeset
for help on using the changeset viewer.