blob: c49c862464a557035b0b3fbb023b5cbc6cd989c1 [file] [log] [blame]
import re
import random
from pathlib import Path
from typing import Callable, Iterable
from cuj import CujGroup, CujStep, de_src
class RegexModify(CujGroup):
"""
A pair of CujSteps, where the fist modifies the file and the
second reverts it
Attributes:
file: the file to be edited and reverted
pattern: the string that will be replaced, only the FIRST occurrence will be replaced
replace: a function that generates the replacement string
modify_type: types of modification
"""
def __init__(
self, file: Path, pattern: str, replacer: Callable[[], str], modify_type: str
):
super().__init__(f"{modify_type} {de_src(file)}")
if not file.exists():
raise RuntimeError(f"{file} does not exist")
self.file = file
self.pattern = pattern
self.replacer = replacer
def get_steps(self) -> Iterable[CujStep]:
original_text: str
def modify():
nonlocal original_text
original_text = self.file.read_text()
modified_text = re.sub(
self.pattern,
self.replacer(),
original_text,
count=1,
flags=re.MULTILINE,
)
self.file.write_text(modified_text)
def revert():
self.file.write_text(original_text)
return [CujStep("", modify), CujStep("revert", revert)]
def modify_private_method(file: Path) -> CujGroup:
pattern = r"(private static boolean.*{)"
def replacement():
return r'\1 Log.d("Placeholder", "Placeholder{}");'.format(
random.randint(0, 10000000)
)
modify_type = "modify_private_method"
return RegexModify(file, pattern, replacement, modify_type)
def add_private_field(file: Path) -> CujGroup:
class_name = file.name.removesuffix('.java')
pattern = fr"(\bclass {class_name} [^{{]*{{)"
def replacement():
return f"\\1\nprivate static final int FOO = {random.randint(0, 10_000_000)};\n"
modify_type = "add_private_field"
return RegexModify(file, pattern, replacement, modify_type)
def add_public_api(file: Path) -> CujGroup:
class_name = file.name.removesuffix('.java')
pattern = fr"(\bclass {class_name} [^{{]*{{)"
def replacement():
return f"\\1\n@android.annotation.SuppressLint(\"UnflaggedApi\")\npublic static final int BAZ = {random.randint(0, 10_000_000)};\n"
modify_type = "add_public_api"
return RegexModify(file, pattern, replacement, modify_type)
def modify_resource(file: Path) -> CujGroup:
pattern = r">0<"
def replacement():
return r">" + str(random.randint(0, 10000000)) + r"<"
modify_type = "modify_resource"
return RegexModify(file, pattern, replacement, modify_type)
def add_resource(file: Path) -> CujGroup:
pattern = r"</resources>"
def replacement():
return (
r' <integer name="foo">'
+ str(random.randint(0, 10000000))
+ r"</integer>\n</resources>"
)
modify_type = "add_resource"
return RegexModify(file, pattern, replacement, modify_type)