| Index: third_party/recipe_engine/expect_tests/serialize.py
|
| diff --git a/third_party/recipe_engine/expect_tests/serialize.py b/third_party/recipe_engine/expect_tests/serialize.py
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..2d498d9d1c647151a2b85c10a8e90bf675703083
|
| --- /dev/null
|
| +++ b/third_party/recipe_engine/expect_tests/serialize.py
|
| @@ -0,0 +1,127 @@
|
| +# Copyright 2014 The Chromium Authors. All rights reserved.
|
| +# Use of this source code is governed by a BSD-style license that can be
|
| +# found in the LICENSE file.
|
| +
|
| +import difflib
|
| +import json
|
| +import os
|
| +import pprint
|
| +
|
| +from collections import OrderedDict
|
| +
|
| +try:
|
| + import yaml # pylint: disable=F0401
|
| +except ImportError:
|
| + yaml = None
|
| +
|
| +
|
| +NonExistant = object()
|
| +
|
| +
|
| +SUPPORTED_SERIALIZERS = {'json', 'yaml'}
|
| +SERIALIZERS = {}
|
| +
|
| +
|
| +# JSON support
|
| +def re_encode(obj):
|
| + if isinstance(obj, dict):
|
| + return {re_encode(k): re_encode(v) for k, v in obj.iteritems()}
|
| + elif isinstance(obj, list):
|
| + return [re_encode(i) for i in obj]
|
| + elif isinstance(obj, unicode):
|
| + return obj.encode('utf-8')
|
| + else:
|
| + return obj
|
| +
|
| +
|
| +SERIALIZERS['json'] = (
|
| + lambda s: re_encode(json.load(s)),
|
| + lambda data, stream: json.dump(
|
| + data, stream, sort_keys=True, indent=2, separators=(',', ': ')))
|
| +
|
| +
|
| +# YAML support
|
| +if yaml:
|
| + _YAMLSafeLoader = getattr(yaml, 'CSafeLoader', yaml.SafeLoader)
|
| + _YAMLSafeDumper = getattr(yaml, 'CSafeDumper', yaml.SafeDumper)
|
| +
|
| + MAPPING_TAG = yaml.resolver.BaseResolver.DEFAULT_MAPPING_TAG
|
| +
|
| + class OrderedLoader(_YAMLSafeLoader):
|
| + def __init__(self, *args, **kwargs): # pylint: disable=E1002
|
| + super(OrderedLoader, self).__init__(*args, **kwargs)
|
| + self.add_constructor(
|
| + MAPPING_TAG,
|
| + lambda loader, node: OrderedDict(loader.construct_pairs(node)))
|
| +
|
| + class OrderedDumper(_YAMLSafeDumper):
|
| + def __init__(self, *args, **kwargs): # pylint: disable=E1002
|
| + super(OrderedDumper, self).__init__(*args, **kwargs)
|
| + def _dict_representer(dumper, data):
|
| + return dumper.represent_mapping(MAPPING_TAG, data.items())
|
| + self.add_representer(OrderedDict, _dict_representer)
|
| +
|
| + SERIALIZERS['yaml'] = (
|
| + lambda stream: yaml.load(stream, OrderedLoader),
|
| + lambda data, stream: yaml.dump(
|
| + data, stream, OrderedDumper, default_flow_style=False,
|
| + encoding='utf-8'))
|
| +
|
| +
|
| +def GetCurrentData(test):
|
| + """
|
| + @type test: Test()
|
| + @returns: The deserialized data (or NonExistant), and a boolean indicating if
|
| + the current serialized data is in the same format which was
|
| + requested by |test|.
|
| + @rtype: (dict, bool)
|
| + """
|
| + for ext in sorted(SUPPORTED_SERIALIZERS, key=lambda s: s != test.ext):
|
| + path = test.expect_path(ext)
|
| + if path is None:
|
| + return None, True
|
| +
|
| + if ext not in SERIALIZERS and ext == test.ext:
|
| + raise Exception('The package to support %s is not installed.' % ext)
|
| + if os.path.exists(path):
|
| + try:
|
| + with open(path, 'rb') as f:
|
| + data = SERIALIZERS[ext][0](f)
|
| + except ValueError as err:
|
| + raise ValueError('Bad format of %s: %s' % (path, err))
|
| + return data, ext == test.ext
|
| + return NonExistant, True
|
| +
|
| +
|
| +def WriteNewData(test, data):
|
| + """
|
| + @type test: Test()
|
| + """
|
| + if data is None:
|
| + return
|
| + if test.ext not in SUPPORTED_SERIALIZERS:
|
| + raise Exception('%s is not a supported serializer.' % test.ext)
|
| + if test.ext not in SERIALIZERS:
|
| + raise Exception('The package to support %s is not installed.' % test.ext)
|
| + with open(test.expect_path(), 'wb') as f:
|
| + SERIALIZERS[test.ext][1](data, f)
|
| +
|
| +
|
| +def DiffData(old, new):
|
| + """
|
| + Takes old data and new data, then returns a textual diff as a list of lines.
|
| + @type old: dict
|
| + @type new: dict
|
| + @rtype: [str]
|
| + """
|
| + if old is NonExistant:
|
| + return new
|
| + if old == new:
|
| + return None
|
| + else:
|
| + return list(difflib.context_diff(
|
| + pprint.pformat(old).splitlines(),
|
| + pprint.pformat(new).splitlines(),
|
| + fromfile='expected', tofile='current',
|
| + n=4, lineterm=''
|
| + ))
|
|
|