Files
location-spoofer/Tests/update_and_contribution_contract_test.sh
T

84 lines
3.6 KiB
Bash

#!/usr/bin/env bash
set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
CONFIG="$ROOT/Shared/AppRemoteConfiguration.swift"
CONTENT="$ROOT/App/ContentView.swift"
MAP="$ROOT/App/MapHomeView.swift"
SETUP="$ROOT/App/FirstSetupView.swift"
SETTINGS="$ROOT/App/SettingsView.swift"
fail() {
echo "FAIL: $1" >&2
exit 1
}
python3 - "$ROOT/version.txt" <<'PY' || exit 1
import json
import sys
with open(sys.argv[1], encoding="utf-8") as handle:
config = json.load(handle)
assert config["latestVersion"] == "1.0.2"
assert config["minimumSupportedVersion"] == "1.0.0"
assert "shadowrocket" not in config["communityPromptClients"]
assert set(config["communityPromptClients"]) == {
"surge", "quantumultX", "loon", "stash", "egern"
}
PY
grep -q 'static let fallback = AppRemoteConfiguration' "$CONFIG" \
|| fail "the app must ship a built-in remote-configuration fallback"
grep -q 'timeoutIntervalForRequest = 1.5' "$CONFIG" \
|| fail "remote configuration requests must use a short timeout"
grep -q 'timeoutIntervalForResource = 2' "$CONFIG" \
|| fail "remote configuration resource loading must use a short timeout"
! grep -q 'data.count' "$CONFIG" \
|| fail "the client must not impose a remote configuration file-size limit"
grep -q 'docs/releases/v\\(version).md' "$CONFIG" \
|| fail "update notes must come from the archived release document"
grep -q '/releases/latest' "$CONFIG" \
|| fail "missing release notes must fall back to the latest Release page"
grep -q '.task { await checkForUpdates() }' "$CONTENT" \
|| fail "update detection must run asynchronously outside bootstrap"
! grep -A90 'private func bootstrap() async' "$CONTENT" | grep -q 'fetch()' \
|| fail "remote configuration must not block the startup gate"
grep -q '社区分享成功配置?' "$MAP" \
|| fail "non-Shadowrocket success must offer community contribution"
grep -q 'Button("去提交")' "$MAP" \
|| fail "community contribution prompt must expose the submit action"
grep -q 'Button("复制模板")' "$MAP" \
|| fail "community contribution prompt must expose an explicit copy action"
grep -q 'Button("取消", role: .cancel)' "$MAP" \
|| fail "the first community prompts must expose cancel"
grep -q 'Button("不再提示", role: .cancel)' "$MAP" \
|| fail "the third community prompt must allow permanent suppression"
grep -q '匿名收录,不在 README 展示投稿账号' "$MAP" \
|| fail "the contribution template must offer anonymous README attribution"
grep -q 'community-config,client-\\(client.rawValue)' "$MAP" \
|| fail "community submissions must be categorized by client labels"
grep -q 'UIPasteboard.general.string = communityContributionIssueBody' "$MAP" \
|| fail "the explicit copy action must copy the issue template"
! grep -A25 'private func openCommunityContributionIssue' "$MAP" | grep -q 'UIPasteboard.general.string' \
|| fail "opening GitHub must not copy the template automatically"
for obsolete in \
'我已配置,开始检测' \
'确认完成,重新检测' \
'下一步:导入配置' \
'我已导入,检测接口连接'; do
! grep -q "$obsolete" "$SETUP" \
|| fail "setup footer must not retain dynamic label: $obsolete"
done
test "$(grep -c 'actionLabel("完成")' "$SETUP")" -eq 4 \
|| fail "all setup footer primary actions must use the fixed 完成 label"
application_line="$(grep -n 'Section("应用")' "$SETTINGS" | head -n 1 | cut -d: -f1)"
certificate_line="$(grep -n 'Section("证书")' "$SETTINGS" | head -n 1 | cut -d: -f1)"
test "$application_line" -lt "$certificate_line" \
|| fail "the APP certificate reset section must appear below the application section"
echo "PASS: update and community contribution contract"