The first half of surge day 1. One question, "may this session emit Pro output?", with one method on the interface so nothing downstream knows which rail proved it. SteamEntitlement reads the lifetime SKU the way Valve intends: SteamAPI.Init() then SteamApps.BIsDlcInstalled(dlcAppId). Four different failure paths all resolve to the free tier rather than to Pro or to a crash — no DLC id configured, no Steam client, steam_api64.dll missing (a throw on first touch), and simply not owned. A copied folder run without Steam is the common case, not an exceptional one. NotConfigured() is the shipping default until Steamworks creates the DLC app; it answers false without ever touching the native library, so today's builds behave exactly as they did before this commit. HasProOutput is now IsPremium || DeveloperMode || rail, with an internal EntitlementOverride test seam (internal, because a public setter here is a licence bypass). Four tests: no id reads false, no client reads false without throwing, the fake reports what a test sets, and the view model takes its answer from the rail. Steamworks.NET 2024.8.0 added; the native DLL still comes from scripts/steam-sdk.sh, so the csproj change is three lines and no formatting churn.
68 lines
2.1 KiB
C#
68 lines
2.1 KiB
C#
using System;
|
|
using System.IO;
|
|
using Xunit;
|
|
using ytLive.Services.Entitlement;
|
|
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.
|
|
///
|
|
/// <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>
|
|
/// </summary>
|
|
public class EntitlementTests
|
|
{
|
|
[Fact]
|
|
public void No_configured_dlc_id_reads_as_no_entitlement()
|
|
{
|
|
// The state before the Steamworks app exists: pure false, no native call attempted.
|
|
Assert.False(SteamEntitlement.NotConfigured().IsPro);
|
|
}
|
|
|
|
[Fact]
|
|
public void A_steam_entitlement_without_a_client_is_the_free_tier_not_a_crash()
|
|
{
|
|
// 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);
|
|
}
|
|
|
|
[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);
|
|
}
|
|
|
|
[Fact]
|
|
public void The_view_model_takes_its_answer_from_the_rail()
|
|
{
|
|
var tempDb = Path.Combine(Path.GetTempPath(), $"llamacasty-entitlement-{Guid.NewGuid():N}.db");
|
|
MainViewModel.LayoutPathOverride = tempDb;
|
|
try
|
|
{
|
|
var vm = new MainViewModel();
|
|
|
|
// Default rail is NotConfigured → free output.
|
|
Assert.False(vm.HasProOutput);
|
|
|
|
vm.EntitlementOverride = new FakeEntitlement(true);
|
|
Assert.True(vm.HasProOutput);
|
|
|
|
vm.EntitlementOverride = new FakeEntitlement(false);
|
|
Assert.False(vm.HasProOutput);
|
|
}
|
|
finally
|
|
{
|
|
MainViewModel.LayoutPathOverride = null;
|
|
try { File.Delete(tempDb); } catch (IOException) { }
|
|
}
|
|
}
|
|
}
|