• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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