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