utils/repo_contract/tests/test_gradle_blocks.py
Krzysztof kuhy Rudnicki d1ca1e3d5b
Some checks are pending
dependency freshness / dependencies on newest stable (push) Waiting to run
file length / file-length (push) Waiting to run
md-naming / markdown naming convention (push) Waiting to run
palette drift / palette (push) Waiting to run
repo-contract / repo contract (push) Waiting to run
shared gate tests / gate unit tests (push) Waiting to run
repo_contract: launcher gate (icon ink radius, compliant label, hidden debug variants) + hook_sync
Flutter repos now fail the repo contract when a launcher icon's ink is not on
the shared 340px circle (png_ink), the launcher label breaks the naming rule
(capital, ASCII letters, <= 10 chars, <= 522 wide in GoogleSansFlex), or an
applicationIdSuffix variant still carries the LAUNCHER category. hook_sync
rewrites a repo's stale repo-contract `files:` line to the widened template.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017k9j5dbjenpfZj7dh2faPN
2026-10-23 14:54:15 +02:00

137 lines
3.8 KiB
Python

"""Brace-matched gradle blocks: suffix variants and manifest placeholders."""
from __future__ import annotations
from repo_contract import gradle_blocks as gb
KTS = """
// a { comment } with braces
android {
namespace = "com.kuhy.demo" /* { block comment } */
defaultConfig {
applicationId = "com.kuhy.demo"
manifestPlaceholders["appLabel"] = "Demo"
versionName = "${flutter.versionName}"
}
flavorDimensions += "store"
productFlavors {
create("daily") {
dimension = "store"
manifestPlaceholders["appLabel"] =
"Daily"
}
create("sandbox") {
applicationIdSuffix = ".sandbox"
manifestPlaceholders["appLabel"] = "Demo SANDBOX"
}
}
buildTypes {
release {
signingConfig = signingConfigs.getByName("debug")
}
getByName("debug") {
applicationIdSuffix = ".debug"
}
}
}
"""
GROOVY = """
android {
defaultConfig {
manifestPlaceholders = [appLabel: 'Demo', other: "x"]
applicationIdSuffix ".everything"
}
buildTypes {
debug {
applicationIdSuffix '.debug'
manifestPlaceholders.appLabel = "Debug"
}
profile {
manifestPlaceholders.put("appLabel", labelFor("profile"))
}
}
productFlavors {
beta {
manifestPlaceholders += mapOf("appLabel" to "Beta")
}
}
}
"""
def test_comments_dropped_strings_kept() -> None:
text = "a = \"// not a comment\" // gone\nb = '/* kept */' /* gone */ c"
assert gb.strip_comments(text) == "a = \"// not a comment\" \nb = '/* kept */' c"
def test_escaped_and_triple_quoted_strings() -> None:
text = 'x = "a\\"{" \ny = """{ "quoted" }""" // c\nz { }'
paths = [b.path for b in gb.blocks(text)]
assert ("z",) in paths and len(paths) == 2
def test_block_paths() -> None:
paths = {b.path for b in gb.blocks(KTS)}
assert ("android", "productFlavors", "sandbox") in paths
assert ("android", "buildTypes", "debug") in paths
assert ("android", "buildTypes", "release") in paths
assert ("android", "defaultConfig") in paths
def test_braces_inside_strings_ignored() -> None:
blocks = gb.blocks('a { b = "${x}" }\n')
assert [b.path for b in blocks] == [("a",), ()]
def test_unbalanced_braces_tolerated() -> None:
assert [b.path for b in gb.blocks("}\na {\n b {\n")] == [
("a", "b"),
("a",),
(),
]
def test_unnamed_header() -> None:
assert gb.blocks("{ }")[0].path == ("?",)
def test_suffixed_variants_kts() -> None:
assert gb.suffixed_variants(KTS) == ["debug", "sandbox"]
def test_suffixed_variants_groovy_ignores_default_config() -> None:
assert gb.suffixed_variants(GROOVY) == ["debug"]
def test_placeholders_kts_every_block() -> None:
assert gb.placeholder_values(KTS, "appLabel") == [
("defaultConfig", "Demo"),
("productFlavors.daily", "Daily"),
("productFlavors.sandbox", "Demo SANDBOX"),
]
def test_placeholders_groovy_forms() -> None:
assert gb.placeholder_values(GROOVY, "appLabel") == [
("defaultConfig", "Demo"),
("buildTypes.debug", "Debug"),
("buildTypes.profile", None),
("productFlavors.beta", "Beta"),
]
def test_placeholder_templates_and_variables_are_not_literals() -> None:
text = 'android {\n manifestPlaceholders["l"] = "A$b"\n}\nmanifestPlaceholders["l"] = name\n'
assert gb.placeholder_values(text, "l") == [("top level", None), ("android", None)]
def test_placeholder_unterminated_string_is_not_literal() -> None:
assert gb.placeholder_values('manifestPlaceholders["l"] = "abc', "l") == [
("top level", None)
]
def test_placeholder_absent() -> None:
assert gb.placeholder_values(KTS, "missing") == []