Home | History | Annotate | Download | only in testgen
      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 """
     18 Common mixins and abstract base classes (ABCs) useful for writing test generators in python
     19 """
     20 
     21 import abc
     22 import collections.abc
     23 import functools
     24 
     25 class 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 
     37 class 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)
     53 def 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 
     76 class 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 
     82 class 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 
     88 class 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 
    115 Named.register(NameComparableMixin)
    116 collections.abc.Hashable.register(NameComparableMixin)
    117 
    118 class 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 
    141 FileLike.register(DumpMixin)
    142