feat(entitlement): pivot to paid app ownership

Check Steam ownership of the paid app with BIsSubscribedApp; keep Debug fake ownership out of Release. Ref: https://partner.steamgames.com/doc/api/ISteamApps#BIsSubscribedApp
This commit is contained in:
2026-11-02 09:18:03 -08:00
parent 54902cb838
commit ff5e8d94ae
17 changed files with 229 additions and 217 deletions
+36 -19
View File
@@ -7,12 +7,10 @@ using ytLive.ViewModels;
namespace ytLive.Tests;
/// <summary>
/// The entitlement seam (2026-11-01): one question — "may this session emit Pro output?" — with a
/// Steam DLC rail, a Polar rail to come, and a fail-closed default.
/// Steam ownership is cached once into the app-wide binary flag.
///
/// <para>The rule that must never break: **no configured rail means the free profile**. A missing
/// DLC id, a missing Steam client or a thrown native load all resolve to false; none of them may
/// crash the app or quietly grant Pro.</para>
/// <para>The rule that must never break: a missing paid app ID, Steam client, or native library
/// fails closed.</para>
/// </summary>
// Shares the static MainViewModel.LayoutPathOverride with the sibling class; without a
// shared collection xUnit runs them in parallel and the two view models fight over one temp DB.
@@ -20,27 +18,44 @@ namespace ytLive.Tests;
public class EntitlementTests
{
[Fact]
public void No_configured_dlc_id_reads_as_no_entitlement()
public void No_configured_paid_app_id_reads_as_not_owned()
{
// The state before the Steamworks app exists: pure false, no native call attempted.
Assert.False(SteamEntitlement.NotConfigured().IsPro);
Assert.False(SteamEntitlement.NotConfigured().IsAppOwned);
}
[Fact]
public void A_steam_entitlement_without_a_client_is_the_free_tier_not_a_crash()
public void Steam_ownership_checks_the_paid_app_id()
{
// No steam_appid.txt in the test host and no client running: Init fails, we report false.
var entitlement = new SteamEntitlement(1234567u);
Assert.False(entitlement.IsPro);
const uint paidAppId = 1234567u;
uint queriedAppId = 0;
var entitlement = new SteamEntitlement(
paidAppId,
initializeSteam: () => true,
isAppSubscribed: appId =>
{
queriedAppId = appId;
return true;
},
shutdownSteam: () => { });
Assert.True(entitlement.IsAppOwned);
Assert.Equal(paidAppId, queriedAppId);
}
[Fact]
public void A_steam_entitlement_without_a_client_fails_closed()
{
var entitlement = new SteamEntitlement(1234567u, () => false, _ => true, () => { });
Assert.False(entitlement.IsAppOwned);
}
[Fact]
public void The_fake_reports_what_a_test_sets()
{
var fake = new FakeEntitlement(true);
Assert.True(fake.IsPro);
fake.IsPro = false;
Assert.False(fake.IsPro);
Assert.True(fake.IsAppOwned);
fake.IsAppOwned = false;
Assert.False(fake.IsAppOwned);
}
[Fact]
@@ -52,14 +67,16 @@ public class EntitlementTests
{
var vm = new MainViewModel();
// Default rail is NotConfigured → free output.
Assert.False(vm.HasProOutput);
vm.EntitlementOverride = new FakeEntitlement(true);
Assert.True(vm.IsAppOwned);
Assert.True(vm.HasProOutput);
vm.EntitlementOverride = new FakeEntitlement(false);
Assert.False(vm.IsAppOwned);
Assert.False(vm.HasProOutput);
vm.EntitlementOverride = new FakeEntitlement(true);
Assert.True(vm.IsAppOwned);
Assert.True(vm.HasProOutput);
}
finally
{