using System.Collections.Generic; using System.Text.RegularExpressions; using NUnit.Framework; using NightclubArcadia.Skills; using UnityEditor; using UnityEngine; namespace NightclubArcadia.Skills.Tests { public class SkillRosterTests { const string DatabasePath = "Assets/Skills/SkillDatabase.asset"; static readonly Regex IdPattern = new Regex(@"^[a-z][a-z0-9_]*$"); static readonly (string id, string displayName)[] ExpectedNames = { ("provenance", "PROVENANCE"), ("confluence", "CONFLUENCE"), ("house_pour", "HOUSE POUR"), ("long_shift", "THE LONG SHIFT"), ("facework", "FACEWORK"), ("placement", "PLACEMENT"), ("amnesty", "AMNESTY"), ("standing_order", "STANDING ORDER"), ("undisclosed", "UNDISCLOSED"), ("the_float", "THE FLOAT"), ("room_tone", "ROOM TONE"), }; SkillDatabase LoadDatabase() { var db = AssetDatabase.LoadAssetAtPath(DatabasePath); Assert.IsNotNull(db, $"Expected SkillDatabase at {DatabasePath}"); return db; } [Test] public void Roster_HasElevenSkills_WithValidIdsAndPairSymmetry() { var db = LoadDatabase(); Assert.AreEqual(11, db.All.Count); var byId = new Dictionary(); var axisCounts = new Dictionary(); var channelCounts = new Dictionary(); var firingSum = 0f; foreach (var skill in db.All) { Assert.IsNotNull(skill); Assert.IsTrue(IdPattern.IsMatch(skill.Id), $"Bad id '{skill.Id}'"); Assert.IsFalse(byId.ContainsKey(skill.Id), $"Duplicate id '{skill.Id}'"); byId[skill.Id] = skill; firingSum += skill.TargetFiringsPerHour; if (!axisCounts.ContainsKey(skill.Axis)) { axisCounts[skill.Axis] = 0; } axisCounts[skill.Axis]++; if (!channelCounts.ContainsKey(skill.PrimaryChannel)) { channelCounts[skill.PrimaryChannel] = 0; } channelCounts[skill.PrimaryChannel]++; } Assert.AreEqual(71f, firingSum, 0.001f); Assert.AreEqual(2, axisCounts[SkillAxis.Reason]); Assert.AreEqual(2, axisCounts[SkillAxis.Body]); Assert.AreEqual(2, axisCounts[SkillAxis.Social]); Assert.AreEqual(2, axisCounts[SkillAxis.Self]); Assert.AreEqual(3, axisCounts[SkillAxis.Specialist]); channelCounts.TryGetValue(TraceChannel.Physical, out var physical); channelCounts.TryGetValue(TraceChannel.Testimonial, out var testimonial); channelCounts.TryGetValue(TraceChannel.Behavioural, out var behavioural); channelCounts.TryGetValue(TraceChannel.Documentary, out var documentary); Assert.AreEqual(3, physical); Assert.AreEqual(3, testimonial); Assert.AreEqual(3, behavioural); Assert.AreEqual(2, documentary); foreach (var skill in byId.Values) { Assert.IsTrue(byId.ContainsKey(skill.OpposedTo), $"{skill.Id} opposedTo missing"); if (skill.AlliedWith != null) { foreach (var ally in skill.AlliedWith) { Assert.IsTrue(byId.ContainsKey(ally), $"{skill.Id} alliedWith '{ally}' missing"); } } var opposed = byId[skill.OpposedTo]; if (skill.Axis == SkillAxis.Specialist || opposed.Axis == SkillAxis.Specialist) { continue; } Assert.AreEqual( skill.Id, opposed.OpposedTo, $"Non-specialist opposedTo asymmetry: {skill.Id} ↔ {opposed.Id}"); } } [Test] public void Roster_DisplayNamesAreUppercaseBibleForms_IdsAreSnakeCase() { var db = LoadDatabase(); var byId = new Dictionary(); foreach (var skill in db.All) { byId[skill.Id] = skill; } foreach (var (id, displayName) in ExpectedNames) { Assert.IsTrue(byId.TryGetValue(id, out var skill), $"Missing skill '{id}'"); Assert.AreEqual(displayName, skill.DisplayName); Assert.AreNotEqual(displayName, skill.Id); } } } }