| #!/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) |