Skip to content

Commit

Permalink
Improved validating android package names
Browse files Browse the repository at this point in the history
  • Loading branch information
grzesiek2010 committed Oct 3, 2023
1 parent af0764c commit 6cab032
Show file tree
Hide file tree
Showing 4 changed files with 123 additions and 8 deletions.
31 changes: 31 additions & 0 deletions pyxform/validators/pyxform/android_package_name.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import re


def validate_android_package_name(name: str) -> str | None:
prefix = "Invalid Android package name - "

if not name.strip():
return f"{prefix}package name is missing."

if "." not in name:
return f"{prefix}the package name must have at least one '.' separator."

if name[-1] == ".":
return f"{prefix}the package name cannot end in a '.' separator."

segments = name.split(".")
if any(segment == "" for segment in segments):
return f"{prefix}package segments must be of non-zero length."

if any(segment.startswith("_") for segment in segments):
return f"{prefix}the character '_' cannot be the first character in a package name segment."

if any(segment[0].isdigit() for segment in segments):
return f"{prefix}a digit cannot be the first character in a package name segment."

pattern = re.compile(r"[^a-zA-Z0-9._]")
for segment in segments:
if pattern.search(segment):
return f"{prefix}the package name contains not allowed characters."

return None
11 changes: 5 additions & 6 deletions pyxform/xls2json.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
from pyxform.errors import PyXFormError
from pyxform.utils import PYXFORM_REFERENCE_REGEX, default_is_dynamic
from pyxform.validators.pyxform import parameters_generic, select_from_file_params
from pyxform.validators.pyxform.android_package_name import validate_android_package_name
from pyxform.validators.pyxform.translations_checks import SheetTranslations
from pyxform.xls2json_backends import csv_to_dict, xls_to_dict, xlsx_to_dict
from pyxform.xlsparseutils import find_sheet_misspellings, is_valid_xml_tag
Expand Down Expand Up @@ -1334,17 +1335,15 @@ def workbook_to_json(
if "app" in parameters.keys():
appearance = row.get("control", {}).get("appearance")
if appearance is None or appearance == "annotate":
android_package_regex_pattern = (
"^[a-z][a-z0-9_]*(\.[a-z0-9_]+)+[0-9a-z_]$"
)
app_package_name = str(parameters["app"])
if re.fullmatch(android_package_regex_pattern, app_package_name):
validation_result = validate_android_package_name(app_package_name)
if validation_result is None:
new_dict["control"] = new_dict.get("control", {})
new_dict["control"].update({"intent": app_package_name})
else:
aaa = (ROW_FORMAT_STRING % row_number) + " " + validation_result
raise PyXFormError(
(ROW_FORMAT_STRING % row_number)
+ " Invalid Android package name format."
(ROW_FORMAT_STRING % row_number) + " " + validation_result
)

parent_children_array.append(new_dict)
Expand Down
26 changes: 24 additions & 2 deletions tests/test_image_app_parameter.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"""
from tests.pyxform_test_case import PyxformTestCase


class TestImageAppParameter(PyxformTestCase):
def test_adding_valid_android_package_name_in_image_with_supported_appearances(self):
appearances = ("", "annotate")
Expand All @@ -22,19 +23,40 @@ def test_adding_valid_android_package_name_in_image_with_supported_appearances(s
],
)

def test_throwing_error_when_invalid_android_package_name_is_used(self):
def test_throwing_error_when_invalid_android_package_name_is_used_with_supported_appearances(
self,
):
appearances = ("", "annotate")
md = """
| survey | | | | | |
| | type | name | label | parameters | appearance |
| | image | my_image | Image | app=something | {case} |
"""
error__contains = (["[row = 2] Invalid Android package name format"],)
for case in appearances:
with self.subTest(msg=case):
self.assertPyxformXform(
name="data",
errored=True,
error__contains="[row : 2] Invalid Android package name - the package name must have at least one '.' separator.",
md=md.format(case=case),
xml__xpath_match=[
"/h:html/h:body/x:upload[not(@intent) and @mediatype='image/*' and @ref='/data/my_image']"
],
)

def test_ignoring_invalid_android_package_name_is_used_with_not_supported_appearances(
self,
):
appearances = ("signature", "draw", "new-front")
md = """
| survey | | | | | |
| | type | name | label | parameters | appearance |
| | image | my_image | Image | app=something | {case} |
"""
for case in appearances:
with self.subTest(msg=case):
self.assertPyxformXform(
name="data",
md=md.format(case=case),
xml__xpath_match=[
"/h:html/h:body/x:upload[not(@intent) and @mediatype='image/*' and @ref='/data/my_image']"
Expand Down
63 changes: 63 additions & 0 deletions tests/validators/pyxform/test_android_package_name.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
from pyxform.validators.pyxform.android_package_name import validate_android_package_name
from tests.pyxform_test_case import PyxformTestCase


class TestAndroidPackageNameValidator(PyxformTestCase):
def test_empty_package_name(self):
result = validate_android_package_name("")
self.assertEqual(
result, "Invalid Android package name - package name is missing."
)

def test_blank_package_name(self):
result = validate_android_package_name(" ")
self.assertEqual(
result, "Invalid Android package name - package name is missing."
)

def test_missing_separator(self):
result = validate_android_package_name("comexampleapp")
self.assertEqual(
result,
"Invalid Android package name - the package name must have at least one '.' separator.",
)

def test_invalid_start_with_underscore(self):
result = validate_android_package_name("_com.example.app")
expected_error = "Invalid Android package name - the character '_' cannot be the first character in a package name segment."
self.assertEqual(result, expected_error)

def test_invalid_start_with_digit(self):
result = validate_android_package_name("1com.example.app")
expected_error = "Invalid Android package name - a digit cannot be the first character in a package name segment."
self.assertEqual(result, expected_error)

def test_invalid_character(self):
result = validate_android_package_name("com.example.app$")
expected_error = "Invalid Android package name - the package name contains not allowed characters."
self.assertEqual(result, expected_error)

def test_package_name_segment_with_zero_length(self):
result = validate_android_package_name("com..app")
expected_error = (
"Invalid Android package name - package segments must be of non-zero length."
)
self.assertEqual(result, expected_error)

def test_separator_as_last_char_in_package_name(self):
result = validate_android_package_name("com.example.app.")
expected_error = "Invalid Android package name - the package name cannot end in a '.' separator."
self.assertEqual(result, expected_error)

def test_valid_package_name(self):
package_names = (
"com.zenstudios.zenpinball",
"com.outfit7.talkingtom",
"com.zeptolab.ctr2.f2p.google",
"com.ea.game.pvzfree_row",
"com.rovio.angrybirdsspace.premium",
)

for case in package_names:
result = validate_android_package_name(case)
self.assertIsNone(result)

0 comments on commit 6cab032

Please sign in to comment.