Chromium Code Reviews| Index: recipe_engine/recipe_test_api.py |
| diff --git a/recipe_engine/recipe_test_api.py b/recipe_engine/recipe_test_api.py |
| index 9015267afb6ebfe730a8bb84ead952205403c470..d316cbfe23c645c6ee028b37049f7c74b1a884c2 100644 |
| --- a/recipe_engine/recipe_test_api.py |
| +++ b/recipe_engine/recipe_test_api.py |
| @@ -5,10 +5,10 @@ |
| import collections |
| import contextlib |
| -from .util import ModuleInjectionSite, static_call, static_wraps |
| +from .util import ModuleInjectionSite, Placeholder, static_call, static_wraps |
| from .types import freeze |
| -def combineify(name, dest, a, b): |
| +def combineify(name, dest, a, b, overwrite=False): |
| """ |
| Combines dictionary members in two objects into a third one using addition. |
| @@ -17,12 +17,16 @@ def combineify(name, dest, a, b): |
| dest - the destination object |
| a - the first source object |
| b - the second source object |
| + overwrite - whether to over write the value from a with the same key. |
|
iannucci
2016/03/10 03:17:42
So I think that now they're all named, there's no
stgao
2016/03/10 20:34:22
Unfortunately, we still have to do it this way, be
|
| """ |
| dest_dict = getattr(dest, name) |
| dest_dict.update(getattr(a, name)) |
| for k, v in getattr(b, name).iteritems(): |
| if k in dest_dict: |
| - dest_dict[k] += v |
| + if not overwrite: |
| + dest_dict[k] += v |
| + else: |
| + dest_dict[k] = v |
| else: |
| dest_dict[k] = v |
| @@ -38,9 +42,10 @@ class BaseTestData(object): |
| class PlaceholderTestData(BaseTestData): |
| - def __init__(self, data=None): |
| + def __init__(self, data=None, id=None): |
| super(PlaceholderTestData, self).__init__() |
| self.data = data |
| + self.id = id or Placeholder.DEFAULT_ID |
| def __repr__(self): |
| return "PlaceholderTestData(%r)" % (self.data,) |
| @@ -55,8 +60,8 @@ class StepTestData(BaseTestData): |
| """ |
| def __init__(self): |
| super(StepTestData, self).__init__() |
| - # { (module, placeholder) -> [data] } |
| - self.placeholder_data = collections.defaultdict(list) |
| + # { (module, placeholder, id) -> data } |
| + self.placeholder_data = {} |
| self.override = False |
| self._stdout = None |
| self._stderr = None |
| @@ -70,7 +75,7 @@ class StepTestData(BaseTestData): |
| ret = StepTestData() |
| - combineify('placeholder_data', ret, self, other) |
| + combineify('placeholder_data', ret, self, other, overwrite=True) |
| # pylint: disable=W0212 |
| ret._stdout = other._stdout or self._stdout |
| @@ -83,18 +88,13 @@ class StepTestData(BaseTestData): |
| return ret |
| def unwrap_placeholder(self): |
| - # {(module, placeholder): [data]} => data. |
| + # {(module, placeholder, id): data} => data. |
| assert len(self.placeholder_data) == 1 |
| - data_list = self.placeholder_data.items()[0][1] |
| - assert len(data_list) == 1 |
| - return data_list[0] |
| - |
| - def pop_placeholder(self, name_pieces): |
| - l = self.placeholder_data[name_pieces] |
| - if l: |
| - return l.pop(0) |
| - else: |
| - return PlaceholderTestData() |
| + return self.placeholder_data.values()[0] |
| + |
| + def pop_placeholder(self, module_name, placeholder_name, id): |
| + return self.placeholder_data.pop((module_name, placeholder_name, id), |
| + PlaceholderTestData()) |
| @property |
| def retcode(self): # pylint: disable=E0202 |
| @@ -257,7 +257,7 @@ class DisabledTestData(BaseTestData): |
| def __getattr__(self, name): |
| return self |
| - def pop_placeholder(self, _name_pieces): |
| + def pop_placeholder(self, _module_name, _placeholder_name, _id): |
| return self |
| def pop_step_test_data(self, _step_name, _step_test_data_fn): |
| @@ -288,42 +288,40 @@ def placeholder_step_data(func): |
| StepTestData() object. |
| The wrapped function may return either: |
| - * <placeholder data>, <retcode or None> |
| + * <placeholder data>, <retcode or None>, <id or None> |
| * StepTestData containing exactly one PlaceholderTestData and possible a |
| retcode. This is useful for returning the result of another method which |
| is wrapped with placeholder_step_data. |
| In either case, the wrapper function will return a StepTestData object with |
| the retcode and placeholder datum inserted with a name of: |
| - (<Test module name>, <wrapped function name>) |
| + (<Test module name>, <wrapped function name>, <id>) |
| Say you had a 'foo_module' with the following RecipeTestApi: |
| class FooTestApi(RecipeTestApi): |
| @placeholder_step_data |
| @staticmethod |
| - def cool_method(data, retcode=None): |
| - return ("Test data (%s)" % data), retcode |
| + def cool_method(data, retcode=None, id=None): |
| + return ("Test data (%s)" % data), retcode, id |
| @placeholder_step_data |
| - def other_method(self, retcode=None): |
| - return self.cool_method('hammer time', retcode) |
| + def other_method(self, retcode=None, id=None): |
| + return self.cool_method('hammer time', retcode=retcode, id=id) |
| - Code calling cool_method('hello') would get a StepTestData: |
| + Code calling cool_method('hello', id='cool1') would get a StepTestData: |
| StepTestData( |
| placeholder_data = { |
| - ('foo_module', 'cool_method'): [ |
| + ('foo_module', 'cool_method', 'cool1') : |
| PlaceholderTestData('Test data (hello)') |
| - ] |
| }, |
| retcode = None |
| ) |
| - Code calling other_method(50) would get a StepTestData: |
| + Code calling other_method(retcode=50, id='other1') would get a StepTestData: |
| StepTestData( |
| placeholder_data = { |
| - ('foo_module', 'other_method'): [ |
| + ('foo_module', 'other_method', 'other1'): |
| PlaceholderTestData('Test data (hammer time)') |
| - ] |
| }, |
| retcode = 50 |
| ) |
| @@ -343,11 +341,12 @@ def placeholder_step_data(func): |
| ) |
| placeholder_data, retcode = all_data[0], data.retcode |
| else: |
| - placeholder_data, retcode = data |
| - placeholder_data = PlaceholderTestData(placeholder_data) |
| + placeholder_data, retcode, id = data |
| + placeholder_data = PlaceholderTestData(placeholder_data, id=id) |
| ret = StepTestData() |
| - ret.placeholder_data[(mod_name, inner.__name__)].append(placeholder_data) |
| + key = (mod_name, inner.__name__, placeholder_data.id) |
| + ret.placeholder_data[key] = placeholder_data |
| ret.retcode = retcode |
| return ret |
| return inner |
| @@ -374,7 +373,7 @@ class RecipeTestApi(object): |
| the platform module's test_api for a good example of this. |
| step_data - Step-specific data. There are two major components to this. |
| retcode - The return code of the step |
| - placeholder_data - A mapping from placeholder name to the a list of |
| + placeholder_data - A mapping from placeholder name to the list of |
| PlaceholderTestData objects, one for each instance |
| of that kind of Placeholder in the step. |
| stdout, stderr - PlaceholderTestData objects for stdout and stderr. |