summaryrefslogtreecommitdiff
path: root/test/utils/python/testgen/mixins.py
blob: aa8943baf3c7bce14fc80edc24c7e14465cff036 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
#!/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)