| #!/usr/bin/python3 |
| # |
| # Copyright (C) 2015 The Android Open Source Project |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); |
| # you may not use this file except in compliance with the License. |
| # You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| |
| """ |
| Common mixins and abstract base classes (ABCs) useful for writing test generators in python |
| """ |
| |
| import abc |
| import collections.abc |
| import functools |
| |
| class Named(metaclass=abc.ABCMeta): |
| """ |
| An abc that defines a get_name method. |
| """ |
| |
| @abc.abstractmethod |
| def get_name(self): |
| """ |
| Returns a unique name to use as the identity for implementing comparisons. |
| """ |
| pass |
| |
| class FileLike(metaclass=abc.ABCMeta): |
| """ |
| An abc that defines get_file_name and get_file_extension methods. |
| """ |
| |
| @abc.abstractmethod |
| def get_file_name(self): |
| """Returns the filename this object represents""" |
| pass |
| |
| @abc.abstractmethod |
| def get_file_extension(self): |
| """Returns the file extension of the file this object represents""" |
| pass |
| |
| @functools.lru_cache(maxsize=None) |
| def get_file_extension_mixin(ext): |
| """ |
| Gets a mixin that defines get_file_name(self) in terms of get_name(self) with the |
| given file extension. |
| """ |
| |
| class FExt(object): |
| """ |
| A mixin defining get_file_name(self) in terms of get_name(self) |
| """ |
| |
| def get_file_name(self): |
| return self.get_name() + ext |
| |
| def get_file_extension(self): |
| return ext |
| |
| # Register the ABCs |
| Named.register(FExt) |
| FileLike.register(FExt) |
| |
| return FExt |
| |
| class SmaliFileMixin(get_file_extension_mixin(".smali")): |
| """ |
| A mixin that defines that the file this class belongs to is get_name() + ".smali". |
| """ |
| pass |
| |
| class JavaFileMixin(get_file_extension_mixin(".java")): |
| """ |
| A mixin that defines that the file this class belongs to is get_name() + ".java". |
| """ |
| pass |
| |
| class NameComparableMixin(object): |
| """ |
| A mixin that defines the object comparison and related functionality in terms |
| of a get_name(self) function. |
| """ |
| |
| def __lt__(self, other): |
| return self.get_name() < other.get_name() |
| |
| def __gt__(self, other): |
| return self.get_name() > other.get_name() |
| |
| def __eq__(self, other): |
| return self.get_name() == other.get_name() |
| |
| def __le__(self, other): |
| return self.get_name() <= other.get_name() |
| |
| def __ge__(self, other): |
| return self.get_name() >= other.get_name() |
| |
| def __ne__(self, other): |
| return self.get_name() != other.get_name() |
| |
| def __hash__(self): |
| return hash(self.get_name()) |
| |
| Named.register(NameComparableMixin) |
| collections.abc.Hashable.register(NameComparableMixin) |
| |
| class DumpMixin(metaclass=abc.ABCMeta): |
| """ |
| A mixin to add support for dumping the string representation of an object to a |
| file. Requires the get_file_name(self) method be defined. |
| """ |
| |
| @abc.abstractmethod |
| def __str__(self): |
| """ |
| Returns the data to be printed to a file by dump. |
| """ |
| pass |
| |
| def dump(self, directory): |
| """ |
| Dump this object to a file in the given directory |
| """ |
| out_file = directory / self.get_file_name() |
| if out_file.exists(): |
| out_file.unlink() |
| with out_file.open('w') as out: |
| print(str(self), file=out) |
| |
| FileLike.register(DumpMixin) |