1#!/usr/bin/python3 2# 3# Copyright (C) 2015 The Android Open Source Project 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16 17""" 18Common mixins and abstract base classes (ABCs) useful for writing test generators in python 19""" 20 21import abc 22import collections.abc 23import functools 24 25class Named(metaclass=abc.ABCMeta): 26 """ 27 An abc that defines a get_name method. 28 """ 29 30 @abc.abstractmethod 31 def get_name(self): 32 """ 33 Returns a unique name to use as the identity for implementing comparisons. 34 """ 35 pass 36 37class FileLike(metaclass=abc.ABCMeta): 38 """ 39 An abc that defines get_file_name and get_file_extension methods. 40 """ 41 42 @abc.abstractmethod 43 def get_file_name(self): 44 """Returns the filename this object represents""" 45 pass 46 47 @abc.abstractmethod 48 def get_file_extension(self): 49 """Returns the file extension of the file this object represents""" 50 pass 51 52@functools.lru_cache(maxsize=None) 53def get_file_extension_mixin(ext): 54 """ 55 Gets a mixin that defines get_file_name(self) in terms of get_name(self) with the 56 given file extension. 57 """ 58 59 class FExt(object): 60 """ 61 A mixin defining get_file_name(self) in terms of get_name(self) 62 """ 63 64 def get_file_name(self): 65 return self.get_name() + ext 66 67 def get_file_extension(self): 68 return ext 69 70 # Register the ABCs 71 Named.register(FExt) 72 FileLike.register(FExt) 73 74 return FExt 75 76class SmaliFileMixin(get_file_extension_mixin(".smali")): 77 """ 78 A mixin that defines that the file this class belongs to is get_name() + ".smali". 79 """ 80 pass 81 82class JavaFileMixin(get_file_extension_mixin(".java")): 83 """ 84 A mixin that defines that the file this class belongs to is get_name() + ".java". 85 """ 86 pass 87 88class NameComparableMixin(object): 89 """ 90 A mixin that defines the object comparison and related functionality in terms 91 of a get_name(self) function. 92 """ 93 94 def __lt__(self, other): 95 return self.get_name() < other.get_name() 96 97 def __gt__(self, other): 98 return self.get_name() > other.get_name() 99 100 def __eq__(self, other): 101 return self.get_name() == other.get_name() 102 103 def __le__(self, other): 104 return self.get_name() <= other.get_name() 105 106 def __ge__(self, other): 107 return self.get_name() >= other.get_name() 108 109 def __ne__(self, other): 110 return self.get_name() != other.get_name() 111 112 def __hash__(self): 113 return hash(self.get_name()) 114 115Named.register(NameComparableMixin) 116collections.abc.Hashable.register(NameComparableMixin) 117 118class DumpMixin(metaclass=abc.ABCMeta): 119 """ 120 A mixin to add support for dumping the string representation of an object to a 121 file. Requires the get_file_name(self) method be defined. 122 """ 123 124 @abc.abstractmethod 125 def __str__(self): 126 """ 127 Returns the data to be printed to a file by dump. 128 """ 129 pass 130 131 def dump(self, directory): 132 """ 133 Dump this object to a file in the given directory 134 """ 135 out_file = directory / self.get_file_name() 136 if out_file.exists(): 137 out_file.unlink() 138 with out_file.open('w') as out: 139 print(str(self), file=out) 140 141FileLike.register(DumpMixin) 142