neutral names in docs, tests and comments (no real app or project names)
This commit is contained in:
parent
cba4660777
commit
6443a5c442
7 changed files with 28 additions and 28 deletions
|
|
@ -55,12 +55,12 @@ fn updater_has_a_real_minisign_key_and_only_storebound_dev() {
|
|||
#[test]
|
||||
fn open_deep_link_takes_one_plain_absolute_path() {
|
||||
let p = |s: &str| deep_link_open_path(&Url::parse(s).unwrap());
|
||||
let abs = if cfg!(windows) { "C:%5Cgames%5CDemo App" } else { "%2FUsers%2Fyou%2Fgames%2FDemo App" };
|
||||
let want = if cfg!(windows) { "C:\\games\\Demo App" } else { "/Users/you/games/Demo App" };
|
||||
let abs = if cfg!(windows) { "C:%5Cgames%5Cdemo-app" } else { "%2FUsers%2Fyou%2Fgames%2Fdemo-app" };
|
||||
let want = if cfg!(windows) { "C:\\games\\demo-app" } else { "/Users/you/games/demo-app" };
|
||||
assert_eq!(p(&format!("storebound://open?path={abs}")), Some(PathBuf::from(want)));
|
||||
assert_eq!(p(&format!("storebound://open/?path={abs}")), Some(PathBuf::from(want)));
|
||||
for bad in [
|
||||
"storebound://open?path=games%2FDemo App".to_string(),
|
||||
"storebound://open?path=games%2Fdemo-app".to_string(),
|
||||
"storebound://open?path=".to_string(),
|
||||
"storebound://open".to_string(),
|
||||
format!("storebound://open?path={abs}&path={abs}"),
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ fn ids_match_the_cli() {
|
|||
// cli/lib/workspace.ts accountId and cli/lib/registry.ts folderId give the same values
|
||||
assert_eq!(profiles::account_id(AccountKind::Apple, "acme"), "747351dbf2569d17");
|
||||
assert_eq!(profiles::account_id(AccountKind::Play, "default"), "82a8c2561d950999");
|
||||
assert_eq!(registry::folder_id("/w/Star Dash"), "f4994b9746e7eb18");
|
||||
assert_eq!(registry::folder_id("/w/star-dash"), "c27311c5023dc3ba");
|
||||
assert!(profiles::valid_name("default") && profiles::valid_name("acme-games.2") && !profiles::valid_name("../x") && !profiles::valid_name("-a"));
|
||||
assert_eq!(profiles::slug("Acme Games: Play!"), "acme-games-play");
|
||||
assert_eq!(profiles::slug("???"), "account");
|
||||
|
|
@ -133,19 +133,19 @@ fn project(id: &str, path: &str, play: Option<&str>) -> Project {
|
|||
fn the_folder_list_is_the_machines() {
|
||||
let dir = tempfile::tempdir().unwrap();
|
||||
let file = dir.path().join("projects.json");
|
||||
let mut st = State { projects: vec![project("aaaaaaaaaaaaaaaa", "/w/Star Dash", Some("acc"))], ..State::default() };
|
||||
let mut st = State { projects: vec![project("aaaaaaaaaaaaaaaa", "/w/star-dash", Some("acc"))], ..State::default() };
|
||||
// first start: the app's list becomes the shared one
|
||||
assert!(!registry::sync(&mut st, &file).unwrap());
|
||||
assert_eq!(registry::read(&file).unwrap()[0].id, "aaaaaaaaaaaaaaaa");
|
||||
// the CLI adds a folder (storebound desktop / apps add): the app shows it, the first keeps its accounts
|
||||
let mut list = registry::read(&file).unwrap();
|
||||
list.push(Entry { id: registry::folder_id("/w/a game"), path: "/w/a game".into(), name: "a game".into(), added: "t".into() });
|
||||
list.push(Entry { id: registry::folder_id("/w/demo-game"), path: "/w/demo-game".into(), name: "demo-game".into(), added: "t".into() });
|
||||
registry::write(&file, &list).unwrap();
|
||||
assert!(registry::sync(&mut st, &file).unwrap());
|
||||
assert_eq!(st.projects.iter().map(|p| p.path.as_str()).collect::<Vec<_>>(), vec!["/w/Star Dash", "/w/a game"]);
|
||||
assert_eq!(st.projects.iter().map(|p| p.path.as_str()).collect::<Vec<_>>(), vec!["/w/star-dash", "/w/demo-game"]);
|
||||
assert_eq!(st.projects[0].play_account.as_deref(), Some("acc"));
|
||||
// the CLI removes one (apps remove): it leaves the app with its overrides
|
||||
st.overrides.ignored.push(format!("project:{}", registry::folder_id("/w/a game")));
|
||||
st.overrides.ignored.push(format!("project:{}", registry::folder_id("/w/demo-game")));
|
||||
registry::write(&file, &list[..1]).unwrap();
|
||||
assert!(registry::sync(&mut st, &file).unwrap());
|
||||
assert_eq!(st.projects.len(), 1);
|
||||
|
|
@ -155,7 +155,7 @@ fn the_folder_list_is_the_machines() {
|
|||
registry::write(&file, &[list[0].clone(), Entry { id: registry::folder_id("/w/cli"), path: "/w/cli".into(), name: "cli".into(), added: String::new() }]).unwrap();
|
||||
registry::publish(&st, &file, &[]).unwrap();
|
||||
let paths: Vec<String> = registry::read(&file).unwrap().into_iter().map(|e| e.path).collect();
|
||||
assert_eq!(paths, vec!["/w/Star Dash", "/w/third", "/w/cli"]);
|
||||
assert_eq!(paths, vec!["/w/star-dash", "/w/third", "/w/cli"]);
|
||||
// bad entries are dropped, not the whole file
|
||||
assert_eq!(registry::parse(r#"{"projects":[{"path":"rel"},{"path":"/a","id":"XYZ"},{"path":"/a"}]}"#).iter().map(|e| e.id.clone()).collect::<Vec<_>>(), vec![registry::folder_id("/a")]);
|
||||
}
|
||||
|
|
@ -173,7 +173,7 @@ fn store_only_apps_join_their_profiles_account_and_survive_folder_writes() {
|
|||
assert_eq!(apps.iter().map(|a| a.app_id.as_str()).collect::<Vec<_>>(), vec!["6400000999", "com.example.legacy"]);
|
||||
assert_eq!(apps[1].bundle_id.as_deref(), Some("com.example.legacy"));
|
||||
// the app writes its folder list: the store-only entries stay
|
||||
let mut st = State { projects: vec![project("aaaaaaaaaaaaaaaa", "/w/Star Dash", None)], ..State::default() };
|
||||
let mut st = State { projects: vec![project("aaaaaaaaaaaaaaaa", "/w/star-dash", None)], ..State::default() };
|
||||
registry::publish(&st, &file, &[]).unwrap();
|
||||
assert_eq!(registry::read_store_apps(&file).len(), 2);
|
||||
assert!(registry::sync(&mut st, &file).is_ok());
|
||||
|
|
|
|||
|
|
@ -316,7 +316,7 @@ candidate on a tag (Jenkins still publishes site/, and `publish` storebound.dev/
|
|||
3. **Windows runner on the VDS (done).** Windows Server 2022 Standard (evaluation) in a KVM virtual machine, in
|
||||
Docker (`dockurr/windows:6.05`), `/srv/windows-runner/`. Forgejo runner 13.2.0 (`vds-windows`, label
|
||||
`windows:host`, capacity 1, job timeout 3 h), registered at the **CRT user level**: every CRT repository can use
|
||||
it (storebound, Demo App, ...).
|
||||
it (storebound, demo-app, ...).
|
||||
- **Resources:** 8 vCPUs, 12 GB RAM, a 150 GB disk (`storage/data.img`, sparse). `restart: unless-stopped`.
|
||||
- **Network:** nothing public. The web viewer (8006), RDP (3389) and the VM's OpenSSH (22, as host port 2223) are
|
||||
bound to 127.0.0.1 on the VDS; use an SSH tunnel (`ssh -L 8006:127.0.0.1:8006 root@<vds>`, then
|
||||
|
|
|
|||
|
|
@ -126,9 +126,9 @@ describe('the installed app', () => {
|
|||
expect(findInstalled('linux', {}, at([]), '/home/you', () => ['storeboundish.AppImage'])).toBeNull();
|
||||
});
|
||||
test('opened with the folder as a deep link, never through a shell', () => {
|
||||
const link = openFolderLink('/Users/you/games/Demo App & co');
|
||||
expect(link).toBe('storebound://open?path=%2FUsers%2Fyou%2Fgames%2FDemo App%20%26%20co');
|
||||
expect(new URL(link).searchParams.get('path')).toBe('/Users/you/games/Demo App & co');
|
||||
const link = openFolderLink('/Users/you/games/demo-app & co');
|
||||
expect(link).toBe('storebound://open?path=%2FUsers%2Fyou%2Fgames%2Fdemo-app%20%26%20co');
|
||||
expect(new URL(link).searchParams.get('path')).toBe('/Users/you/games/demo-app & co');
|
||||
expect(openCommand('darwin', { path: '/Applications/storebound.app', how: 'bundle' }, link)).toEqual(['open', '-b', 'dev.storebound.desktop', link]);
|
||||
expect(openCommand('darwin', { path: '/Applications/storebound.app', how: 'bundle' }, null)).toEqual(['open', '-b', 'dev.storebound.desktop']);
|
||||
expect(openCommand('win32', { path: 'C:\\x\\storebound-desktop.exe', how: 'exe' }, link)).toEqual(['C:\\x\\storebound-desktop.exe', link]);
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ describe('credentials: one machine, many projects', () => {
|
|||
writeFileSync(join(creds, 'default.json'), JSON.stringify({ ASC_KEY_ID: 'DEFAULT000', ASC_ISSUER_ID: 'iss', ASC_P8: PEM('x') }));
|
||||
expect(defaultProfile()).toBe('teamB');
|
||||
// the project's own keys beat the pointer; a profile the project names beats both; env beats all
|
||||
const a = project(base, 'Star Dash');
|
||||
const a = project(base, 'star-dash');
|
||||
expect(ascKey(a).keyId).toBe('ABCDE12345');
|
||||
const file = join(a, '.storebound', 'credentials.json');
|
||||
writeFileSync(file, JSON.stringify({ ...JSON.parse(readFileSync(file, 'utf8')), account: 'teamA' }));
|
||||
|
|
@ -84,7 +84,7 @@ describe('credentials: one machine, many projects', () => {
|
|||
}));
|
||||
|
||||
test('project-only values from the project, store keys from the profile, env over everything', () => machine(({ creds, base }) => {
|
||||
const a = project(base, 'Star Dash');
|
||||
const a = project(base, 'star-dash');
|
||||
// the project's own keys work without any profile
|
||||
expect(ascKey(a).keyId).toBe('ABCDE12345');
|
||||
mkdirSync(creds, { recursive: true });
|
||||
|
|
@ -113,7 +113,7 @@ describe('credentials: one machine, many projects', () => {
|
|||
}));
|
||||
|
||||
test('accounts import: two projects with the same Apple key and Play account -> one profile, 0600 files, projects stay valid', () => machine(({ creds, base }) => {
|
||||
const a = project(base, 'Star Dash'), b = project(base, 'a game');
|
||||
const a = project(base, 'star-dash'), b = project(base, 'demo-game');
|
||||
const dry = planImport(a);
|
||||
expect(dry.profile).toBe('default');
|
||||
expect(dry.reuse).toBe(false);
|
||||
|
|
@ -136,7 +136,7 @@ describe('credentials: one machine, many projects', () => {
|
|||
const projA = JSON.parse(readFileSync(join(a, '.storebound', 'credentials.json'), 'utf8'));
|
||||
expect(projA.account).toBe('default');
|
||||
expect(projA.ASC_KEY_ID).toBeUndefined();
|
||||
expect(projA.ANDROID_KEYSTORE).toBe('Star Dash.jks');
|
||||
expect(projA.ANDROID_KEYSTORE).toBe('star-dash.jks');
|
||||
expect(ascKey(a).pem).toContain('apple-secret-sentinel');
|
||||
expect(playServiceAccount(a).client_email).toBe('release@example.com');
|
||||
// the second project with the same account: the same profile, its files unchanged
|
||||
|
|
@ -145,7 +145,7 @@ describe('credentials: one machine, many projects', () => {
|
|||
expect(second.reuse).toBe(true);
|
||||
expect(second.writes.filter(w => w.path.startsWith(creds)).map(w => w.action)).toEqual(['same']);
|
||||
applyImport(second);
|
||||
expect(JSON.parse(readFileSync(join(b, '.storebound', 'credentials.json'), 'utf8')).ANDROID_KEYSTORE_PASSWORD).toBe('a game-pw');
|
||||
expect(JSON.parse(readFileSync(join(b, '.storebound', 'credentials.json'), 'utf8')).ANDROID_KEYSTORE_PASSWORD).toBe('demo-game-pw');
|
||||
expect(ascKey(b).keyId).toBe('ABCDE12345');
|
||||
// running it again changes nothing
|
||||
expect(planImport(b).writes.every(w => w.action === 'same')).toBe(true);
|
||||
|
|
@ -157,13 +157,13 @@ describe('credentials: one machine, many projects', () => {
|
|||
expect(third.profile).toBe('other-studio');
|
||||
applyImport(third);
|
||||
expect(ascKey(c).keyId).toBe('ZZZZZ99999');
|
||||
expect(ascKey(a).keyId).toBe('ABCDE12345'); // "account": "default" still points Star Dash at its own
|
||||
expect(ascKey(a).keyId).toBe('ABCDE12345'); // "account": "default" still points star-dash at its own
|
||||
expect(useProfile(c, 'default')).toContain('credentials.json');
|
||||
expect(() => useProfile(c, 'missing')).toThrow(/no profile/);
|
||||
}));
|
||||
|
||||
test('the import command prints paths and names, never key values', () => machine(({ base }) => {
|
||||
const a = project(base, 'Star Dash');
|
||||
const a = project(base, 'star-dash');
|
||||
const r = Bun.spawnSync(['bun', join(ROOT, 'cli', 'index.ts'), 'accounts', 'import', '--dry', '--dir', a], { env: { ...process.env, STOREBOUND_NO_NETWORK: '1' } });
|
||||
const out = r.stdout.toString() + r.stderr.toString();
|
||||
expect(r.exitCode).toBe(0);
|
||||
|
|
@ -179,14 +179,14 @@ describe('credentials: one machine, many projects', () => {
|
|||
describe('the machine\'s app folder list', () => {
|
||||
test('add, re-add, remove; ids are the desktop export ids; bad entries are dropped', () => machine(({ base }) => {
|
||||
const r0 = { version: 1 as const, projects: [] };
|
||||
const { registry, added } = withFolder(r0, '/w/Star Dash', 'Star Dash', 't');
|
||||
const { registry, added } = withFolder(r0, '/w/star-dash', 'Star Dash', 't');
|
||||
expect(added).toBe(true);
|
||||
expect(registry.projects[0]!.id).toBe(desktopProjectId('/w/Star Dash'));
|
||||
expect(withFolder(registry, '/w/Star Dash/', undefined, 't').added).toBe(false);
|
||||
expect(withoutFolder(registry, folderId('/w/Star Dash')).removed?.name).toBe('Star Dash');
|
||||
expect(registry.projects[0]!.id).toBe(desktopProjectId('/w/star-dash'));
|
||||
expect(withFolder(registry, '/w/star-dash/', undefined, 't').added).toBe(false);
|
||||
expect(withoutFolder(registry, folderId('/w/star-dash')).removed?.name).toBe('Star Dash');
|
||||
expect(parseRegistry('{"projects":[{"path":"relative"},{"path":"/a","id":"zz"},{"path":"/a"}]}').projects.map(p => [p.path, p.id])).toEqual([['/a', folderId('/a')]]);
|
||||
expect(parseRegistry('not json').projects).toEqual([]);
|
||||
const dir = project(base, 'a game');
|
||||
const dir = project(base, 'demo-game');
|
||||
expect(addFolder(dir).added).toBe(true);
|
||||
expect(addFolder(dir).added).toBe(false);
|
||||
expect(readRegistry().projects.map(p => p.path)).toEqual([dir]);
|
||||
|
|
|
|||
|
|
@ -317,7 +317,7 @@ describe('store-only apps in the machine list', () => {
|
|||
expect(reg.storeApps).toEqual([{ id: storeAppId('apple', '6400000999'), store: 'apple', appId: '6400000999', account: 'teamA', name: 'Demo App', bundleId: null, added: reg.storeApps![0]!.added }]);
|
||||
expect(reg.projects).toEqual([]);
|
||||
// a folder added later keeps the store-only entry
|
||||
const f = withFolder(reg, '/w/Star Dash', undefined, 't').registry;
|
||||
const f = withFolder(reg, '/w/star-dash', undefined, 't').registry;
|
||||
expect(f.storeApps).toHaveLength(1);
|
||||
expect(parseRegistry(JSON.stringify(f)).storeApps).toHaveLength(1);
|
||||
const again = await capture(() => apps(parseArgs(['add', '--store', 'apple', '--app-id', '6400000999', '--account', 'teamA', '--name', 'Demo App'], [])));
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ describe('template answers', () => {
|
|||
});
|
||||
|
||||
test('a config from before `unanswered` is recognised by the template values; [] means answered', () => {
|
||||
const legacy = { app: { name: 'Demo Blast', copyright: '2026 Example Studio' }, apple: { bundleId: 'x', info: { reviewNotes: 'mine', ageRating: { advertising: true } } },
|
||||
const legacy = { app: { name: 'DEMO BLAST', copyright: '2026 Example Studio' }, apple: { bundleId: 'x', info: { reviewNotes: 'mine', ageRating: { advertising: true } } },
|
||||
dataSafety: { collectsData: true, encryptedInTransit: true, accountCreation: ['PSL_ACM_NONE'], data: {
|
||||
PSL_APPROX_LOCATION: { shared: true, collect: ['analytics', 'advertising', 'fraud'], share: ['analytics', 'advertising', 'fraud'] },
|
||||
PSL_USER_INTERACTION: { shared: true, collect: ['analytics', 'advertising'], share: ['analytics', 'advertising'] },
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue