Skip to content

Commit

Permalink
Merge pull request beeware#1827 from mblahay/bug_1810
Browse files Browse the repository at this point in the history
Changes for bugfix 1810. Adding a validator for the formal name input…
  • Loading branch information
freakboy3742 authored May 22, 2024
2 parents 7ffbb0a + bda871e commit a1d5168
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 1 deletion.
1 change: 1 addition & 0 deletions changes/1810.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
The formal name of an app is now validated.
21 changes: 21 additions & 0 deletions src/briefcase/commands/new.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,26 @@ def make_app_name(self, formal_name):
# use a dummy app name as the suggestion.
return "myapp"

def validate_formal_name(self, candidate):
"""Determine if the formal name is valid.
A formal name is valid if it contains at least one identifier character.
:param candidate: The candidate name
:returns: True the formal name is valid.
:raises: ValueError if the name is not a valid formal name.
"""
if not make_class_name(candidate): # Check whether a class name may be derived
raise ValueError(
self.input.textwrap(
f"{candidate!r} is not a valid formal name.\n"
"\n"
"Formal names must include at least one valid Python identifier character."
)
)

return True

def _validate_existing_app_name(self, candidate):
"""Perform internal validation preventing the use of pre-existing app names.
Expand Down Expand Up @@ -459,6 +479,7 @@ def build_app_context(self, project_overrides: dict[str, str]) -> dict[str, str]
),
variable="formal name",
default="Hello World",
validator=self.validate_formal_name,
override_value=project_overrides.pop("formal_name", None),
)

Expand Down
6 changes: 5 additions & 1 deletion src/briefcase/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,11 @@ def make_class_name(formal_name):

# If the first character isn't in the 'start' character set,
# and it isn't already an underscore, prepend an underscore.
if unicodedata.category(class_name[0]) not in xid_start and class_name[0] != "_":
if (
class_name
and unicodedata.category(class_name[0]) not in xid_start
and class_name[0] != "_"
):
class_name = f"_{class_name}"

return class_name
Expand Down
48 changes: 48 additions & 0 deletions tests/commands/new/test_validate_formal_name.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import pytest


@pytest.mark.parametrize(
"name",
[
# Various forms of capitalization and alphanumeric
"Hello World",
"helloworld",
"helloWorld",
"hello42world",
"42helloworld",
# Names that include punctuation
"hello_world",
"hello-world",
"_helloworld",
"/helloworld",
"Hello / World!",
# Internationalized names that can be unicode-simplified
"Hallo Vögel",
"Bonjour Garçon",
# Internationalized names that cannot be unicode-simplified
"你好 世界!",
],
)
def test_valid_formal_name(new_command, name):
"""Test that valid formal names are accepted."""
assert new_command.validate_formal_name(name)


@pytest.mark.parametrize(
"name",
[
"", # Empty
" ", # Just a space
"\t", # Other whitespace characters
"/", # Just a slash
"'",
"\\",
"/'\\", # Multiple invalid characters
],
)
def test_invalid_formal_name(new_command, name, tmp_path):
"""Test that invalid app names are rejected."""
(tmp_path / "existing").mkdir()

with pytest.raises(ValueError):
new_command.validate_formal_name(name)

0 comments on commit a1d5168

Please sign in to comment.