1# Copyright 2014 The Chromium Authors. All rights reserved. 2# Use of this source code is governed by a BSD-style license that can be 3# found in the LICENSE file. 4 5import functools 6import types 7 8 9def Cache(obj): 10 """Decorator for caching read-only properties. 11 12 Example usage (always returns the same Foo instance): 13 @Cache 14 def CreateFoo(): 15 return Foo() 16 17 If CreateFoo() accepts parameters, a separate cached value is maintained 18 for each unique parameter combination. 19 """ 20 cache = obj.__cache = {} 21 22 @functools.wraps(obj) 23 def Cacher(*args, **kwargs): 24 key = str(args) + str(kwargs) 25 if key not in cache: 26 cache[key] = obj(*args, **kwargs) 27 return cache[key] 28 return Cacher 29 30 31def Disabled(*args): 32 """Decorator for disabling tests/benchmarks. 33 34 May be used without args to unconditionally disable: 35 @Disabled # Unconditionally disabled. 36 37 If args are given, the test will be disabled if ANY of the args match the 38 browser type, OS name or OS version: 39 @Disabled('canary') # Disabled for canary browsers 40 @Disabled('win') # Disabled on Windows. 41 @Disabled('win', 'linux') # Disabled on both Windows and Linux. 42 @Disabled('mavericks') # Disabled on Mac Mavericks (10.9) only. 43 """ 44 def _Disabled(func): 45 if not isinstance(func, types.FunctionType): 46 func._disabled_strings = disabled_strings 47 return func 48 @functools.wraps(func) 49 def wrapper(*args, **kwargs): 50 func(*args, **kwargs) 51 wrapper._disabled_strings = disabled_strings 52 return wrapper 53 if len(args) == 1 and callable(args[0]): 54 disabled_strings = [] 55 return _Disabled(args[0]) 56 disabled_strings = list(args) 57 for disabled_string in disabled_strings: 58 # TODO(tonyg): Validate that these strings are recognized. 59 assert isinstance(disabled_string, str), '@Disabled accepts a list of strs' 60 return _Disabled 61 62 63def Enabled(*args): 64 """Decorator for enabling tests/benchmarks. 65 66 The test will be enabled if ANY of the args match the browser type, OS name 67 or OS version: 68 @Enabled('canary') # Enabled only for canary browsers 69 @Enabled('win') # Enabled only on Windows. 70 @Enabled('win', 'linux') # Enabled only on Windows or Linux. 71 @Enabled('mavericks') # Enabled only on Mac Mavericks (10.9). 72 """ 73 def _Enabled(func): 74 if not isinstance(func, types.FunctionType): 75 func._enabled_strings = enabled_strings 76 return func 77 @functools.wraps(func) 78 def wrapper(*args, **kwargs): 79 func(*args, **kwargs) 80 wrapper._enabled_strings = enabled_strings 81 return wrapper 82 assert args and not callable(args[0]), '@Enabled requires argumentas' 83 enabled_strings = list(args) 84 for enabled_string in enabled_strings: 85 # TODO(tonyg): Validate that these strings are recognized. 86 assert isinstance(enabled_string, str), '@Enabled accepts a list of strs' 87 return _Enabled 88 89 90# pylint: disable=W0212 91def IsEnabled(test, browser_type, platform): 92 """Returns True iff |test| is enabled given the |browser_type| and |platform|. 93 94 Use to respect the @Enabled / @Disabled decorators. 95 96 Args: 97 test: A function or class that may contain _disabled_strings and/or 98 _enabled_strings attributes. 99 browser_type: A string representing the --browser string. 100 platform: A platform.Platform instance for the target of |browser_type|. 101 """ 102 platform_attributes = [a.lower() for a in [ 103 browser_type, 104 platform.GetOSName(), 105 platform.GetOSVersionName(), 106 ]] 107 108 if hasattr(test, '__name__'): 109 name = test.__name__ 110 elif hasattr(test, '__class__'): 111 name = test.__class__.__name__ 112 else: 113 name = str(test) 114 115 if hasattr(test, '_disabled_strings'): 116 disabled_strings = test._disabled_strings 117 if not disabled_strings: 118 return False # No arguments to @Disabled means always disable. 119 for disabled_string in disabled_strings: 120 if disabled_string in platform_attributes: 121 print ( 122 'Skipping %s because it is disabled for %s. ' 123 'You are running %s.' % (name, 124 ' and '.join(disabled_strings), 125 ' '.join(platform_attributes))) 126 return False 127 128 if hasattr(test, '_enabled_strings'): 129 enabled_strings = test._enabled_strings 130 if not enabled_strings: 131 return True # No arguments to @Enabled means always enable. 132 for enabled_string in enabled_strings: 133 if enabled_string in platform_attributes: 134 return True 135 print ( 136 'Skipping %s because it is only enabled for %s. ' 137 'You are running %s.' % (name, 138 ' or '.join(enabled_strings), 139 ' '.join(platform_attributes))) 140 return False 141 142 return True 143