From 53fc361af43263791e6015b85501012d62320da5 Mon Sep 17 00:00:00 2001 From: Helena Van Breugel Date: Sun, 14 May 2023 11:58:09 +0000 Subject: [PATCH] Resolve WES-187 "Unit tests justsign and spellingbee" --- .../ScriptableObjects/SignThemeList.asset | 2 +- Assets/Hangman/Scripts/HangmanController.cs | 7 +- .../Tests/PlayMode/HangmanPlaymodeTests.cs | 16 +- Assets/JustSign/Scripts/JustSignController.cs | 133 ++++--- .../Tests/PlayMode/JustSignControllerTests.cs | 342 ++++++++++++++++++ .../PlayMode/JustSignControllerTests.cs.meta | 11 + .../Tests/PlayMode/JustSignPlayMode.asmdef | 9 +- .../Scripts/AbstractMinigameController.cs | 2 +- .../Scripts/SpellingBeeController.cs | 34 +- .../Tests/PlayMode/GameEndedPanelTests.cs | 20 + .../PlayMode/SpellingBeeControllerTests.cs | 159 +++++++- 11 files changed, 655 insertions(+), 80 deletions(-) create mode 100644 Assets/JustSign/Tests/PlayMode/JustSignControllerTests.cs create mode 100644 Assets/JustSign/Tests/PlayMode/JustSignControllerTests.cs.meta diff --git a/Assets/Common/ScriptableObjects/SignThemeList.asset b/Assets/Common/ScriptableObjects/SignThemeList.asset index 36a9250..370bf3c 100644 --- a/Assets/Common/ScriptableObjects/SignThemeList.asset +++ b/Assets/Common/ScriptableObjects/SignThemeList.asset @@ -14,6 +14,7 @@ MonoBehaviour: m_EditorClassIdentifier: currentThemeIndex: 0 themes: + - {fileID: 11400000, guid: e02921b294fdad940b6e4d57e716d3bf, type: 2} - {fileID: 11400000, guid: dd48f91f5d3b2d041b08640872a65d9c, type: 2} - {fileID: 11400000, guid: 6abf76ea9ca532a44b852393ad2d219f, type: 2} - {fileID: 11400000, guid: 5755ca304d16d3449991668b383d7dd5, type: 2} @@ -21,4 +22,3 @@ MonoBehaviour: - {fileID: 11400000, guid: adc0467561c43494db61e303d4aeefee, type: 2} - {fileID: 11400000, guid: 40cf29fa07988ee4aa02e227c20df3a7, type: 2} - {fileID: 11400000, guid: 70b23bd64ac995b41ae7c26221a9d039, type: 2} - - {fileID: 11400000, guid: e02921b294fdad940b6e4d57e716d3bf, type: 2} diff --git a/Assets/Hangman/Scripts/HangmanController.cs b/Assets/Hangman/Scripts/HangmanController.cs index 81cfbe3..2356bd8 100644 --- a/Assets/Hangman/Scripts/HangmanController.cs +++ b/Assets/Hangman/Scripts/HangmanController.cs @@ -586,7 +586,8 @@ public class HangmanController : AbstractMinigameController /// /// The accuracy of the passed sign /// The name of the passed sign - protected override void ProcessMostProbableSign(float distance, string predictedSign) + + public override void ProcessMostProbableSign(float distance, string predictedSign) { // Grab the threshold for the most probable letter Learnable letter = fingerSpelling.learnables.Find((l) => l.name == predictedSign); @@ -744,10 +745,6 @@ public class HangmanController : AbstractMinigameController { return usedLettersText.text; } - public void ProcessSignForTests(float accuracy, string sign) - { - ProcessMostProbableSign(accuracy, sign); - } public float getCurrentTime() { return currentTime; diff --git a/Assets/Hangman/Tests/PlayMode/HangmanPlaymodeTests.cs b/Assets/Hangman/Tests/PlayMode/HangmanPlaymodeTests.cs index eef9f6c..8bb010b 100644 --- a/Assets/Hangman/Tests/PlayMode/HangmanPlaymodeTests.cs +++ b/Assets/Hangman/Tests/PlayMode/HangmanPlaymodeTests.cs @@ -215,7 +215,7 @@ public class HangmanPlaymodeTests // Wrong letter, but this one will be rejected while (hangmanController.getCurrentMode() != multiplayerConfirmInput) { - hangmanController.ProcessSignForTests(1, "Q"); + hangmanController.ProcessMostProbableSign(0.0001f, "Q"); yield return new WaitForSeconds(0.2f); } @@ -265,17 +265,17 @@ public class HangmanPlaymodeTests { hangmanController.SinglePlayer(); - hangmanController.ProcessSignForTests(0.001f, "A"); + hangmanController.ProcessMostProbableSign(0.001f, "A"); yield return new WaitForSeconds(0.2f); // The sign for A has been held for 0.2f seconds... Assert.IsTrue(hangmanController.getCurrentTime() >= 0.2f && hangmanController.getCurrentTime() <= 0.3f); - hangmanController.ProcessSignForTests(0.001f, "B"); + hangmanController.ProcessMostProbableSign(0.001f, "B"); yield return new WaitForSeconds(0.2f); // The sign changed so the time needs to be at 0.2f again Assert.IsTrue(hangmanController.getCurrentTime() >= 0.2f && hangmanController.getCurrentTime() <= 0.3f); - hangmanController.ProcessSignForTests(1000, "B"); + hangmanController.ProcessMostProbableSign(1000, "B"); yield return new WaitForSeconds(0.2f); // The sign changed is way above the threshold, time is no longer tracked and is reset Assert.IsTrue(hangmanController.getCurrentTime() == 0.0); @@ -285,13 +285,13 @@ public class HangmanPlaymodeTests float threshold = C.thresholdDistance; for (float i = 2 * threshold; i > threshold; i -= threshold / 6) { - hangmanController.ProcessSignForTests(i, "C"); + hangmanController.ProcessMostProbableSign(i, "C"); yield return new WaitForSeconds(0.01f); Assert.IsTrue(hangmanController.getCurrentTime() == 0.0); } // Check that the time rises above zero when you dip just below the threshold - hangmanController.ProcessSignForTests(threshold - 0.01f, "C"); + hangmanController.ProcessMostProbableSign(threshold - 0.01f, "C"); yield return new WaitForSeconds(0.01f); Assert.IsTrue(hangmanController.getCurrentTime() > 0.0); @@ -360,7 +360,7 @@ public class HangmanPlaymodeTests while (hangmanController.getCurrentMode() != multiplayerConfirmInput) { // Choose the letter by giving it a very small distance - hangmanController.ProcessSignForTests(0.001f, letter); + hangmanController.ProcessMostProbableSign(0.001f, letter); yield return new WaitForSeconds(0.2f); } @@ -377,7 +377,7 @@ public class HangmanPlaymodeTests while (!hangmanController.getUsedLetters().Contains(letter)) { // Choose the letter by giving it a very small distance - hangmanController.ProcessSignForTests(0.001f, letter); + hangmanController.ProcessMostProbableSign(0.001f, letter); yield return new WaitForSeconds(0.2f); } } diff --git a/Assets/JustSign/Scripts/JustSignController.cs b/Assets/JustSign/Scripts/JustSignController.cs index c5b969b..a48978f 100644 --- a/Assets/JustSign/Scripts/JustSignController.cs +++ b/Assets/JustSign/Scripts/JustSignController.cs @@ -276,6 +276,7 @@ public class JustSignController : AbstractMinigameController DestroySymbolAt(0); incorrectSigns++; timingFeedback.text = $"Te laat! \n {offscreenScore}"; + timingFeedback.color = new Color(0x10 / 255.0f, 0x10 / 255.0f, 0x10 / 255.0f); imageFeedback.sprite = tooLateSprite; } } @@ -360,25 +361,36 @@ public class JustSignController : AbstractMinigameController activeSymbols.Add(newSymbolObject); } + /// + /// Get the threshold for a given sign + /// + /// + /// + public float GetThreshold(string sign) + { + Learnable predSign = currentTheme.learnables.Find(l => l.name.ToUpper().Replace(" ", "-") == sign); + return predSign.thresholdDistance; + } + /// /// The logic to process the signs sent by the signPredictor /// /// The accuracy of the passed sign /// The name of the passed sign - protected override void ProcessMostProbableSign(float distance, string predictedSign) + public override void ProcessMostProbableSign(float distance, string predictedSign) { - Learnable predSign = currentTheme.learnables.Find(l => l.name.ToUpper().Replace(" ", "-") == predictedSign); - //Learnable predSign = currentTheme.learnables.Find(l => l.name == predictedSign); + float threshold = GetThreshold(predictedSign); + // If there is a feedback-object, we wil change its appearance if (feedbackText != null && feedbackProgressImage != null) { Color col; - if (distance < predSign.thresholdDistance) + if (distance < threshold) { feedbackText.text = $"Herkent '{predictedSign}'"; col = new Color(0x8b / 255.0f, 0xd4 / 255.0f, 0x5e / 255.0f); } - else if (distance < 1.5 * predSign.thresholdDistance) + else if (distance < 1.5 * threshold) { feedbackText.text = $"Lijkt op '{predictedSign}'"; col = new Color(0xf2 / 255.0f, 0x7f / 255.0f, 0x0c / 255.0f); @@ -394,7 +406,7 @@ public class JustSignController : AbstractMinigameController float oldValue = feedbackProgress.value; // use an exponential scale - float newValue = 1 - Mathf.Clamp(distance - predSign.thresholdDistance, 0.0f, 3.0f) / 3; + float newValue = 1 - Mathf.Clamp(distance - threshold, 0.0f, 3.0f) / 3; feedbackProgress.gameObject.Tween("FeedbackUpdate", oldValue, newValue, 0.2f, TweenScaleFunctions.CubicEaseInOut, (t) => { if (feedbackProgress != null) @@ -405,59 +417,68 @@ public class JustSignController : AbstractMinigameController } // The logic for the internal workings of the game - if (distance < predSign.thresholdDistance) + if (distance < threshold) { int matchedSymbolIndex = activeWords.IndexOf(predictedSign.ToUpper()); // Destroy the oldest symbol if the current input matches it if (0 <= matchedSymbolIndex) { - float x = activeSymbols[matchedSymbolIndex].transform.localPosition.x; - - // parameters to define the Perfect hit zone - float perfectRange = hitZonePerfect.sizeDelta.x; - float perfectCenter = hitZonePerfect.localPosition.x; - // parameters to define the Good hit zone - float goodRange = hitZoneGood.sizeDelta.x; - float goodCenter = hitZoneGood.localPosition.x; - // parameters to define the Meh hit zone - float mehRange = hitZoneMeh.sizeDelta.x; - float mehCenter = hitZoneMeh.localPosition.x; - - if (perfectCenter - perfectRange / 2 <= x && x <= perfectCenter + perfectRange / 2) - { - timingFeedback.text = $"Perfect! \n +{perfectScore}"; - imageFeedback.sprite = perfectSprite; - perfectSigns++; - timingFeedback.color = new Color(0x8b / 255.0f, 0xd4 / 255.0f, 0x5e / 255.0f); - } - else if (goodCenter - goodRange / 2 <= x && x <= goodCenter + goodRange / 2) - { - timingFeedback.text = $"Goed \n +{goodScore}"; - imageFeedback.sprite = goodSprite; - goodSigns++; - timingFeedback.color = new Color(0xf7 / 255.0f, 0xad / 255.0f, 0x19 / 255.0f); - } - else if (mehCenter - mehRange / 2 <= x && x <= mehCenter + mehRange / 2) - { - timingFeedback.text = $"Bijna... \n +{mehScore}"; - imageFeedback.sprite = mehSprite; - mehSigns++; - timingFeedback.color = new Color(0xf2 / 255.0f, 0x7f / 255.0f, 0x0c / 255.0f); - } - else - { - timingFeedback.text = $"Te vroeg! \n {terribleScore}"; - imageFeedback.sprite = terribleSprite; - terribleSigns++; - timingFeedback.color = new Color(0xf5 / 255.0f, 0x49 / 255.0f, 0x3d / 255.0f); - } - - DestroySymbolAt(matchedSymbolIndex); + MatchedSymbol(matchedSymbolIndex); } } } + /// + /// The logic to process a correct sign within the zones in the game + /// + /// + void MatchedSymbol(int index) + { + float x = activeSymbols[index].transform.localPosition.x; + + // parameters to define the Perfect hit zone + float perfectRange = hitZonePerfect.sizeDelta.x; + float perfectCenter = hitZonePerfect.localPosition.x; + // parameters to define the Good hit zone + float goodRange = hitZoneGood.sizeDelta.x; + float goodCenter = hitZoneGood.localPosition.x; + // parameters to define the Meh hit zone + float mehRange = hitZoneMeh.sizeDelta.x; + float mehCenter = hitZoneMeh.localPosition.x; + + if (perfectCenter - perfectRange / 2 <= x && x <= perfectCenter + perfectRange / 2) + { + timingFeedback.text = $"Perfect! \n +{perfectScore}"; + imageFeedback.sprite = perfectSprite; + perfectSigns++; + timingFeedback.color = new Color(0x8b / 255.0f, 0xd4 / 255.0f, 0x5e / 255.0f); + } + else if (goodCenter - goodRange / 2 <= x && x <= goodCenter + goodRange / 2) + { + timingFeedback.text = $"Goed \n +{goodScore}"; + imageFeedback.sprite = goodSprite; + goodSigns++; + timingFeedback.color = new Color(0xf7 / 255.0f, 0xad / 255.0f, 0x19 / 255.0f); + } + else if (mehCenter - mehRange / 2 <= x && x <= mehCenter + mehRange / 2) + { + timingFeedback.text = $"Bijna... \n +{mehScore}"; + imageFeedback.sprite = mehSprite; + mehSigns++; + timingFeedback.color = new Color(0xf2 / 255.0f, 0x7f / 255.0f, 0x0c / 255.0f); + } + else + { + timingFeedback.text = $"Te vroeg! \n {terribleScore}"; + imageFeedback.sprite = terribleSprite; + terribleSigns++; + timingFeedback.color = new Color(0xf5 / 255.0f, 0x49 / 255.0f, 0x3d / 255.0f); + } + + DestroySymbolAt(index); + } + /// /// The logic to set the scoreboard of justsign /// @@ -517,4 +538,18 @@ public class JustSignController : AbstractMinigameController DestroySymbolAt(0); } } + + /// + /// Get sign for the first active symbol + /// + /// + public string GetFirstSign() + { + if (activeSymbols.Count > 0) + { + TMP_Text text = activeSymbols[0].GetComponentInChildren(); + return text.text; + } + return null; + } } diff --git a/Assets/JustSign/Tests/PlayMode/JustSignControllerTests.cs b/Assets/JustSign/Tests/PlayMode/JustSignControllerTests.cs new file mode 100644 index 0000000..ff2e2d0 --- /dev/null +++ b/Assets/JustSign/Tests/PlayMode/JustSignControllerTests.cs @@ -0,0 +1,342 @@ +using NUnit.Framework; +using System.Collections; +using System.IO; +using UnityEditor; +using UnityEngine; +using UnityEngine.TestTools; + +public class JustSignControllerTests +{ + /// + /// Setup for testing Just Sign + /// + /// + [UnitySetUp] + public IEnumerator SetupFunction() + { + string path = $"{Application.persistentDataPath}/wesign_unit_test.json"; + string oneUser = $"{{\"version\":1027,\"users\":[{{\"entries\":[],\"username\":\"TEST\",\"avatarIndex\":0,\"playtime\":0.0,\"minigames\":[],\"courses\":[]}}],\"currentUser\":0,\"currentMinigame\":0,\"currentCourse\":0,\"currentTheme\":0}}"; + + File.WriteAllText(path, oneUser); + PersistentDataController.GetInstance().Load(); + AssetDatabase.LoadAssetAtPath("Assets/Accounts/ScriptableObjects/UserAvatarList.asset").Awake(); + + // Go to the minigame-selection scene to make sure that the minigameIndex is set correctly + SystemController.GetInstance().LoadNextScene("Common/Scenes/ListMinigamesScreen"); + yield return new WaitForSeconds(0.2f); + ListMinigamesScreen minigameScreen = GameObject.FindObjectOfType(); + minigameScreen.minigameList.SetCurrentMinigame(MinigameIndex.JUST_SIGN); + + SystemController.GetInstance().LoadNextScene("JustSign/Scenes/JustSignGame"); + yield return new WaitForSeconds(0.2f); + + // Fetch the SignPredictor and deactivate it, this stops the basic game-loop from happening + var signPredictor = GameObject.FindObjectOfType(); + GameObject signPredictorController = signPredictor.gameObject; + signPredictorController.SetActive(false); + yield return new WaitForSeconds(0.2f); + } + + /// + /// Tests a sign that is done too quickly, i.e., feedback during game and scoreboard after + /// + /// + [UnityTest] + public IEnumerator EarlyScoreTest() + { + JustSignController justSignController = GameObject.FindObjectOfType(); + + yield return new WaitForSeconds(5.0f); + + string currentSign = justSignController.GetFirstSign(); + justSignController.ProcessMostProbableSign(1.0f, currentSign); + + yield return new WaitForSeconds(0.2f); + + Assert.AreEqual("Te vroeg! \n -3", justSignController.timingFeedback.text); + Assert.AreEqual(-3, justSignController.CalculateScore()); + Assert.AreEqual("Score: -3", justSignController.scoreDisplay.text); + + justSignController.ActivateEnd(true); + + yield return new WaitForSeconds(0.2f); + JustSignGameEndedPanel justSignGameEndedPanel = GameObject.FindObjectOfType(); + Assert.NotNull(justSignGameEndedPanel); + Assert.AreEqual("0", justSignGameEndedPanel.perfectSignsText.text); + Assert.AreEqual("0", justSignGameEndedPanel.goodSignsText.text); + Assert.AreEqual("0", justSignGameEndedPanel.mehSignsText.text); + Assert.AreEqual("1", justSignGameEndedPanel.terribleSignsText.text); + Assert.AreEqual("0", justSignGameEndedPanel.notFoundSignsText.text); + Assert.AreEqual("Score: -3", justSignGameEndedPanel.scoreText.text); + string gpmText = (60f / 64).ToString("#") + " GPM"; + Assert.AreEqual(gpmText, justSignGameEndedPanel.gpmText.text); + } + + /// + /// Tests a sign that is done too late, i.e., feedback during game and scoreboard after + /// + /// + [UnityTest] + public IEnumerator TooLateScoreTest() + { + JustSignController justSignController = GameObject.FindObjectOfType(); + + yield return new WaitForSeconds(23.0f); + + Assert.AreEqual("Te laat! \n -5", justSignController.timingFeedback.text); + Assert.AreEqual(-5, justSignController.CalculateScore()); + Assert.AreEqual("Score: -5", justSignController.scoreDisplay.text); + + justSignController.ActivateEnd(true); + + yield return new WaitForSeconds(0.2f); + JustSignGameEndedPanel justSignGameEndedPanel = GameObject.FindObjectOfType(); + Assert.NotNull(justSignGameEndedPanel); + Assert.AreEqual("0", justSignGameEndedPanel.perfectSignsText.text); + Assert.AreEqual("0", justSignGameEndedPanel.goodSignsText.text); + Assert.AreEqual("0", justSignGameEndedPanel.mehSignsText.text); + Assert.AreEqual("0", justSignGameEndedPanel.terribleSignsText.text); + Assert.AreEqual("1", justSignGameEndedPanel.notFoundSignsText.text); + Assert.AreEqual("Score: -5", justSignGameEndedPanel.scoreText.text); + string gpmText = (0).ToString("#") + " GPM"; + Assert.AreEqual(gpmText, justSignGameEndedPanel.gpmText.text); + } + + /// + /// Tests a sign that is done in the meh-zone, i.e., feedback during game and scoreboard after + /// + /// + [UnityTest] + public IEnumerator MehScoreTest() + { + JustSignController justSignController = GameObject.FindObjectOfType(); + + yield return new WaitForSeconds(14.5f); + + string currentSign = justSignController.GetFirstSign(); + justSignController.ProcessMostProbableSign(1.0f, currentSign); + + yield return new WaitForSeconds(0.2f); + + Assert.AreEqual("Bijna... \n +10", justSignController.timingFeedback.text); + Assert.AreEqual(10, justSignController.CalculateScore()); + Assert.AreEqual("Score: 10", justSignController.scoreDisplay.text); + + justSignController.ActivateEnd(true); + + yield return new WaitForSeconds(0.2f); + JustSignGameEndedPanel justSignGameEndedPanel = GameObject.FindObjectOfType(); + Assert.NotNull(justSignGameEndedPanel); + Assert.AreEqual("0", justSignGameEndedPanel.perfectSignsText.text); + Assert.AreEqual("0", justSignGameEndedPanel.goodSignsText.text); + Assert.AreEqual("1", justSignGameEndedPanel.mehSignsText.text); + Assert.AreEqual("0", justSignGameEndedPanel.terribleSignsText.text); + Assert.AreEqual("0", justSignGameEndedPanel.notFoundSignsText.text); + Assert.AreEqual("Score: 10", justSignGameEndedPanel.scoreText.text); + string gpmText = (60f / 64).ToString("#") + " GPM"; + Assert.AreEqual(gpmText, justSignGameEndedPanel.gpmText.text); + } + + /// + /// Tests a sign that is done in the good-zone, i.e., feedback during game and scoreboard after + /// + /// + [UnityTest] + public IEnumerator GoodScoreTest() + { + JustSignController justSignController = GameObject.FindObjectOfType(); + + yield return new WaitForSeconds(17.5f); + + string currentSign = justSignController.GetFirstSign(); + justSignController.ProcessMostProbableSign(1.0f, currentSign); + + yield return new WaitForSeconds(0.2f); + + Assert.AreEqual("Goed \n +20", justSignController.timingFeedback.text); + Assert.AreEqual(20, justSignController.CalculateScore()); + Assert.AreEqual("Score: 20", justSignController.scoreDisplay.text); + + justSignController.ActivateEnd(true); + + yield return new WaitForSeconds(0.2f); + JustSignGameEndedPanel justSignGameEndedPanel = GameObject.FindObjectOfType(); + Assert.NotNull(justSignGameEndedPanel); + Assert.AreEqual("0", justSignGameEndedPanel.perfectSignsText.text); + Assert.AreEqual("1", justSignGameEndedPanel.goodSignsText.text); + Assert.AreEqual("0", justSignGameEndedPanel.mehSignsText.text); + Assert.AreEqual("0", justSignGameEndedPanel.terribleSignsText.text); + Assert.AreEqual("0", justSignGameEndedPanel.notFoundSignsText.text); + Assert.AreEqual("Score: 20", justSignGameEndedPanel.scoreText.text); + string gpmText = (60f / 64).ToString("#") + " GPM"; + Assert.AreEqual(gpmText, justSignGameEndedPanel.gpmText.text); + } + + /// + /// Tests a sign that is done in the perfect-zone, i.e., feedback during game and scoreboard after + /// + /// + [UnityTest] + public IEnumerator PerfectScoreTest() + { + JustSignController justSignController = GameObject.FindObjectOfType(); + + yield return new WaitForSeconds(19.0f); + + string currentSign = justSignController.GetFirstSign(); + justSignController.ProcessMostProbableSign(1.0f, currentSign); + + yield return new WaitForSeconds(0.2f); + + Assert.AreEqual("Perfect! \n +50", justSignController.timingFeedback.text); + Assert.AreEqual(50, justSignController.CalculateScore()); + Assert.AreEqual("Score: 50", justSignController.scoreDisplay.text); + + justSignController.ActivateEnd(true); + + yield return new WaitForSeconds(0.2f); + JustSignGameEndedPanel justSignGameEndedPanel = GameObject.FindObjectOfType(); + Assert.NotNull(justSignGameEndedPanel); + Assert.AreEqual("1", justSignGameEndedPanel.perfectSignsText.text); + Assert.AreEqual("0", justSignGameEndedPanel.goodSignsText.text); + Assert.AreEqual("0", justSignGameEndedPanel.mehSignsText.text); + Assert.AreEqual("0", justSignGameEndedPanel.terribleSignsText.text); + Assert.AreEqual("0", justSignGameEndedPanel.notFoundSignsText.text); + Assert.AreEqual("Score: 50", justSignGameEndedPanel.scoreText.text); + string gpmText = (60f / 64).ToString("#") + " GPM"; + Assert.AreEqual(gpmText, justSignGameEndedPanel.gpmText.text); + } + + /// + /// Tests the entire game, i.e., feedback during game and scoreboard after + /// + /// + [UnityTest] + public IEnumerator WalkthroughTest() + { + JustSignController justSignController = GameObject.FindObjectOfType(); + + yield return new WaitForSeconds(10.0f); + + string currentSign = justSignController.GetFirstSign(); + justSignController.ProcessMostProbableSign(1.0f, currentSign); + + Assert.AreEqual(justSignController.CalculateScore(), -3); + + yield return new WaitForSeconds(10.0f); + + currentSign = justSignController.GetFirstSign(); + justSignController.ProcessMostProbableSign(1.0f, currentSign); + + Assert.AreEqual(justSignController.CalculateScore(), 7); + + yield return new WaitForSeconds(6.0f); + + currentSign = justSignController.GetFirstSign(); + justSignController.ProcessMostProbableSign(1.0f, currentSign); + + Assert.AreEqual(justSignController.CalculateScore(), 27); + + yield return new WaitForSeconds(6.0f); + + currentSign = justSignController.GetFirstSign(); + justSignController.ProcessMostProbableSign(1.0f, currentSign); + + Assert.AreEqual(justSignController.CalculateScore(), 77); + + yield return new WaitForSeconds(10.0f); + + Assert.AreEqual(justSignController.CalculateScore(), 72); + + justSignController.ActivateEnd(true); + + yield return new WaitForSeconds(0.2f); + JustSignGameEndedPanel justSignGameEndedPanel = GameObject.FindObjectOfType(); + Assert.NotNull(justSignGameEndedPanel); + Assert.AreEqual("1", justSignGameEndedPanel.perfectSignsText.text); + Assert.AreEqual("1", justSignGameEndedPanel.goodSignsText.text); + Assert.AreEqual("1", justSignGameEndedPanel.mehSignsText.text); + Assert.AreEqual("1", justSignGameEndedPanel.terribleSignsText.text); + Assert.AreEqual("1", justSignGameEndedPanel.notFoundSignsText.text); + Assert.AreEqual("Score: 72", justSignGameEndedPanel.scoreText.text); + string gpmText = (60f * 4/ 64).ToString("#") + " GPM"; + Assert.AreEqual(gpmText, justSignGameEndedPanel.gpmText.text); + } + + /// + /// Tests if the game ends when the song does + /// + /// + [UnityTest] + public IEnumerator SongEndTest() + { + JustSignController justSignController = GameObject.FindObjectOfType(); + + yield return new WaitForSeconds(0.2f); + + Song song = justSignController.songList.songs[justSignController.songList.currentSongIndex]; + song.duration = 1; + + yield return new WaitForSeconds(1.2f); + + JustSignGameEndedPanel justSignGameEndedPanel = GameObject.FindObjectOfType(); + Assert.NotNull(justSignGameEndedPanel); + Assert.AreEqual("0", justSignGameEndedPanel.perfectSignsText.text); + Assert.AreEqual("0", justSignGameEndedPanel.goodSignsText.text); + Assert.AreEqual("0", justSignGameEndedPanel.mehSignsText.text); + Assert.AreEqual("0", justSignGameEndedPanel.terribleSignsText.text); + Assert.AreEqual("0", justSignGameEndedPanel.notFoundSignsText.text); + Assert.AreEqual("Score: 0", justSignGameEndedPanel.scoreText.text); + string gpmText = (0).ToString("#") + " GPM"; + Assert.AreEqual(gpmText, justSignGameEndedPanel.gpmText.text); + } + + /// + /// Tests the feedback in the game + /// + /// + [UnityTest] + public IEnumerator FeedbackTest() + { + JustSignController justSignController = GameObject.FindObjectOfType(); + + yield return new WaitForSeconds(5.0f); + + string currentSign = justSignController.GetFirstSign(); + float threshold = justSignController.GetThreshold(currentSign); + justSignController.ProcessMostProbableSign(0.9f * threshold, currentSign); + + yield return new WaitForSeconds(0.2f); + + Assert.Null(justSignController.GetFirstSign()); + Assert.AreEqual($"Herkent '{currentSign}'", justSignController.feedbackText.text); + Assert.AreEqual(new Color(0x8b / 255.0f, 0xd4 / 255.0f, 0x5e / 255.0f), justSignController.feedbackText.color); + + yield return new WaitForSeconds(5.0f); + + currentSign = justSignController.GetFirstSign(); + threshold = justSignController.GetThreshold(currentSign); + justSignController.ProcessMostProbableSign(1.2f * threshold, currentSign); + + yield return new WaitForSeconds(0.2f); + + Assert.AreEqual($"Lijkt op '{currentSign}'", justSignController.feedbackText.text); + Assert.AreEqual(new Color(0xf2 / 255.0f, 0x7f / 255.0f, 0x0c / 255.0f), justSignController.feedbackText.color); + + justSignController.ProcessMostProbableSign(3.0f * threshold, currentSign); + + yield return new WaitForSeconds(0.2f); + + Assert.AreEqual("Detecteren...", justSignController.feedbackText.text); + Assert.AreEqual(new Color(0xf5 / 255.0f, 0x49 / 255.0f, 0x3d / 255.0f), justSignController.feedbackText.color); + } + + /// + /// Cleanup after testing + /// + [TearDown] + public void TearDown_JustSignTests() + { + PersistentDataController.PATH = null; + } +} diff --git a/Assets/JustSign/Tests/PlayMode/JustSignControllerTests.cs.meta b/Assets/JustSign/Tests/PlayMode/JustSignControllerTests.cs.meta new file mode 100644 index 0000000..dd215de --- /dev/null +++ b/Assets/JustSign/Tests/PlayMode/JustSignControllerTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b3d310f7a3879a54fa36ab0d2e981f79 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/JustSign/Tests/PlayMode/JustSignPlayMode.asmdef b/Assets/JustSign/Tests/PlayMode/JustSignPlayMode.asmdef index 8c1b4c1..7d17cbe 100644 --- a/Assets/JustSign/Tests/PlayMode/JustSignPlayMode.asmdef +++ b/Assets/JustSign/Tests/PlayMode/JustSignPlayMode.asmdef @@ -4,7 +4,14 @@ "references": [ "UnityEngine.TestRunner", "UnityEditor.TestRunner", - "JustSignScripts" + "AccountsScripts", + "JustSignScripts", + "SignPredictor", + "MinigameScripts", + "Unity.TextMeshPro", + "CommonScripts", + "InterfacesScripts", + "ArchitectureScripts" ], "includePlatforms": [], "excludePlatforms": [], diff --git a/Assets/Minigames/Scripts/AbstractMinigameController.cs b/Assets/Minigames/Scripts/AbstractMinigameController.cs index 3950eb2..55c7ef8 100644 --- a/Assets/Minigames/Scripts/AbstractMinigameController.cs +++ b/Assets/Minigames/Scripts/AbstractMinigameController.cs @@ -152,7 +152,7 @@ public abstract class AbstractMinigameController : AbstractFeedback /// /// The accuracy of the passed sign /// The name of the passed sign - protected abstract void ProcessMostProbableSign(float accuracy, string predictedSign); + public abstract void ProcessMostProbableSign(float accuracy, string predictedSign); /// /// Each minigame has their own way of calculating their score diff --git a/Assets/SpellingBee/Scripts/SpellingBeeController.cs b/Assets/SpellingBee/Scripts/SpellingBeeController.cs index f1d865c..9fcae59 100644 --- a/Assets/SpellingBee/Scripts/SpellingBeeController.cs +++ b/Assets/SpellingBee/Scripts/SpellingBeeController.cs @@ -351,12 +351,12 @@ public partial class SpellingBeeController : AbstractMinigameController /// /// /// - private float GetTresholdPercentage(string sign) + public float GetThreshold(string sign) { Learnable letter = fingerspelling.learnables.Find(l => l.name == sign); return letter.thresholdDistance; } - + /// /// Function to get the current letter that needs to be signed /// @@ -369,6 +369,7 @@ public partial class SpellingBeeController : AbstractMinigameController } return null; } + /// /// Function to confirm your prediction and check if it is correct. /// @@ -388,13 +389,23 @@ public partial class SpellingBeeController : AbstractMinigameController /// /// The accuracy of the passed sign /// The name of the passed sign - protected override void ProcessMostProbableSign(float distance, string predictedSign) + public override void ProcessMostProbableSign(float distance, string predictedSign) { string currentSign = GetSign(); - float distPredictSign = distance; float distCurrentSign = signPredictor.learnableProbabilities[currentSign]; - float thresholdCurrentSign = GetTresholdPercentage(currentSign); - float thresholdPredictedSign = GetTresholdPercentage(predictedSign); + + ProcessCurrentAndPredicted(distance, predictedSign, distCurrentSign, currentSign); + } + + /// + /// The logic to process the current en predicted sign by the signPredictor + /// + /// The accuracy of the passed sign + /// The name of the passed sign + public void ProcessCurrentAndPredicted(float distPredictSign, string predictedSign, float distCurrentSign, string currentSign) + { + float thresholdCurrentSign = GetThreshold(currentSign); + float thresholdPredictedSign = GetThreshold(predictedSign); // If there is a feedback-object, we wil change its appearance if (feedbackText != null && feedbackProgressImage != null) @@ -534,4 +545,15 @@ public partial class SpellingBeeController : AbstractMinigameController gameIsActive = false; DeleteWord(); } + + /// + /// Skip to ending of game, used in testing to see if NextWord(), NextLetter() and ScoreBord work well together + /// + /// + public string SkipToEnd() + { + wordIndex = words.Count - 1; + currentWord = words[wordIndex].name; + return currentWord; + } } diff --git a/Assets/SpellingBee/Tests/PlayMode/GameEndedPanelTests.cs b/Assets/SpellingBee/Tests/PlayMode/GameEndedPanelTests.cs index 177b5e0..8a46d4d 100644 --- a/Assets/SpellingBee/Tests/PlayMode/GameEndedPanelTests.cs +++ b/Assets/SpellingBee/Tests/PlayMode/GameEndedPanelTests.cs @@ -7,6 +7,10 @@ using UnityEngine.TestTools; public class SpellingBeeGameEndedPanelTests { + /// + /// Setup for testing scoreboard of Spelling Bee + /// + /// [UnitySetUp] public IEnumerator SetupFunction() { @@ -27,6 +31,10 @@ public class SpellingBeeGameEndedPanelTests yield return new WaitForSeconds(0.2f); } + /// + /// Tests the scoreboard for Spelling Bee + /// + /// [UnityTest] public IEnumerator ScoreTest() { @@ -40,6 +48,9 @@ public class SpellingBeeGameEndedPanelTests spellingBeeController.ActivateEnd(true); + // Fetch the panel with the info for the fields and check if the controller has implemented them + var script = GameObject.FindObjectOfType(); + SpellingBeeGameEndedPanel SpellingBeeGameEndedPanel = (SpellingBeeGameEndedPanel)GameObject.FindObjectOfType(typeof(SpellingBeeGameEndedPanel)); Assert.NotNull(SpellingBeeGameEndedPanel); Assert.AreEqual("Score: 0", SpellingBeeGameEndedPanel.scoreText.text); @@ -49,4 +60,13 @@ public class SpellingBeeGameEndedPanelTests Assert.AreEqual("00:01", SpellingBeeGameEndedPanel.timeText.text); } + + /// + /// Cleanup after testing + /// + [TearDown] + public void TearDown_SpellingBeeScoreTests() + { + PersistentDataController.PATH = null; + } } diff --git a/Assets/SpellingBee/Tests/PlayMode/SpellingBeeControllerTests.cs b/Assets/SpellingBee/Tests/PlayMode/SpellingBeeControllerTests.cs index fd4120b..2220146 100644 --- a/Assets/SpellingBee/Tests/PlayMode/SpellingBeeControllerTests.cs +++ b/Assets/SpellingBee/Tests/PlayMode/SpellingBeeControllerTests.cs @@ -7,11 +7,15 @@ using UnityEngine.TestTools; public class SpellingBeeControllerTests { + /// + /// Setup for testing Spelling Bee + /// + /// [UnitySetUp] public IEnumerator SetupFunction() { string path = $"{Application.persistentDataPath}/wesign_unit_test.json"; - string oneUser = $"{{\"version\":{PersistentDataController.VERSION},\"users\":[{{\"entries\":[],\"username\":\"TEST\",\"avatarIndex\":0,\"playtime\":0.0,\"minigames\":[],\"courses\":[]}}],\"currentUser\":0,\"currentMinigame\":0,\"currentCourse\":0,\"currentTheme\":0}}"; + string oneUser = $"{{\"version\":1027,\"users\":[{{\"entries\":[],\"username\":\"TEST\",\"avatarIndex\":0,\"playtime\":0.0,\"minigames\":[],\"courses\":[]}}],\"currentUser\":0,\"currentMinigame\":0,\"currentCourse\":0,\"currentTheme\":0}}"; File.WriteAllText(path, oneUser); PersistentDataController.GetInstance().Load(); @@ -20,17 +24,27 @@ public class SpellingBeeControllerTests // Go to the minigame-selection scene to make sure that the minigameIndex is set correctly SystemController.GetInstance().LoadNextScene("Common/Scenes/ListMinigamesScreen"); yield return new WaitForSeconds(0.2f); - ListMinigamesScreen minigameScreen = (ListMinigamesScreen)GameObject.FindObjectOfType(typeof(ListMinigamesScreen)); + ListMinigamesScreen minigameScreen = GameObject.FindObjectOfType(); minigameScreen.minigameList.SetCurrentMinigame(MinigameIndex.SPELLING_BEE); SystemController.GetInstance().LoadNextScene("SpellingBee/Scenes/SpellingBeeGame"); yield return new WaitForSeconds(0.2f); + + // Fetch the SignPredictor and deactivate it, this stops the basic game-loop from happening + var signPredictor = GameObject.FindObjectOfType(); + GameObject signPredictorController = signPredictor.gameObject; + signPredictorController.SetActive(false); + yield return new WaitForSeconds(0.2f); } + /// + /// Tests the calculations of the score + /// + /// [UnityTest] public IEnumerator CheckScoreTest() { - SpellingBeeController spellingBeeController = (SpellingBeeController)GameObject.FindObjectOfType(typeof(SpellingBeeController)); + SpellingBeeController spellingBeeController = GameObject.FindObjectOfType(); yield return new WaitForSeconds(0.2f); Assert.AreEqual(0, spellingBeeController.CalculateScore()); spellingBeeController.NextWord(); @@ -39,40 +53,167 @@ public class SpellingBeeControllerTests Assert.AreEqual(10, spellingBeeController.CalculateScore()); } + /// + /// Tests the ending panel + /// + /// [UnityTest] public IEnumerator ActivateGameOverTest() { - SpellingBeeController spellingBeeController = (SpellingBeeController)GameObject.FindObjectOfType(typeof(SpellingBeeController)); + SpellingBeeController spellingBeeController = GameObject.FindObjectOfType(); spellingBeeController.ActivateEnd(false); yield return new WaitForSeconds(0.2f); - SpellingBeeGameEndedPanel SpellingBeeGameEndedPanel = (SpellingBeeGameEndedPanel)GameObject.FindObjectOfType(typeof(SpellingBeeGameEndedPanel)); + SpellingBeeGameEndedPanel SpellingBeeGameEndedPanel = GameObject.FindObjectOfType(); Assert.NotNull(SpellingBeeGameEndedPanel); Assert.AreEqual("VERLOREN", SpellingBeeGameEndedPanel.endText.text); } + /// + /// Tests the scoreboard in case of completion + /// + /// [UnityTest] public IEnumerator ActivateWinTests() { - SpellingBeeController spellingBeeController = (SpellingBeeController)GameObject.FindObjectOfType(typeof(SpellingBeeController)); + SpellingBeeController spellingBeeController = GameObject.FindObjectOfType(); spellingBeeController.ActivateEnd(true); yield return new WaitForSeconds(0.2f); - SpellingBeeGameEndedPanel SpellingBeeGameEndedPanel = (SpellingBeeGameEndedPanel)GameObject.FindObjectOfType(typeof(SpellingBeeGameEndedPanel)); + SpellingBeeGameEndedPanel SpellingBeeGameEndedPanel = GameObject.FindObjectOfType(); Assert.NotNull(SpellingBeeGameEndedPanel); Assert.AreEqual("GEWONNEN", SpellingBeeGameEndedPanel.endText.text); } + /// + /// Tests the scoreboard when timer goes off + /// + /// [UnityTest] public IEnumerator CheckGameOverTest() { - SpellingBeeController spellingBeeController = (SpellingBeeController)GameObject.FindObjectOfType(typeof(SpellingBeeController)); + SpellingBeeController spellingBeeController = GameObject.FindObjectOfType(); spellingBeeController.AddSeconds(-60); yield return new WaitForSeconds(0.1f); - SpellingBeeGameEndedPanel SpellingBeeGameEndedPanel = (SpellingBeeGameEndedPanel)GameObject.FindObjectOfType(typeof(SpellingBeeGameEndedPanel)); + SpellingBeeGameEndedPanel SpellingBeeGameEndedPanel = GameObject.FindObjectOfType(); Assert.NotNull(SpellingBeeGameEndedPanel); Assert.AreEqual("VERLOREN", SpellingBeeGameEndedPanel.endText.text); } + + /// + /// Tests the completion from a word and from the entire theme + scoreboard + /// + /// + [UnityTest] + public IEnumerator CheckGoToNextWord() + { + SpellingBeeController spellingBeeController = GameObject.FindObjectOfType(); + string word = spellingBeeController.SkipToEnd(); + + spellingBeeController.PredictSign(spellingBeeController.GetSign()); + + yield return new WaitForSeconds(0.2f); + + Assert.IsTrue(spellingBeeController.bonusTimeText.activeSelf); + + yield return new WaitForSeconds(1.0f); + + Assert.IsFalse(spellingBeeController.bonusTimeText.activeSelf); + + for (int i = 1; i < word.Length; i++) + { + spellingBeeController.NextLetter(false); + } + spellingBeeController.NextWord(); + yield return new WaitForSeconds(0.2f); + + SpellingBeeGameEndedPanel SpellingBeeGameEndedPanel = GameObject.FindObjectOfType(); + Assert.NotNull(SpellingBeeGameEndedPanel); + Assert.AreEqual("GEWONNEN", SpellingBeeGameEndedPanel.endText.text); + } + + /// + /// Tests the feedback in the game + /// + /// + [UnityTest] + public IEnumerator FeedbackTest() + { + SpellingBeeController spellingBeeController = GameObject.FindObjectOfType(); + + string sign = spellingBeeController.GetSign(); + float threshold = spellingBeeController.GetThreshold(sign); + spellingBeeController.ProcessCurrentAndPredicted(0.9f * threshold, sign, 0.9f * threshold, sign); + + yield return new WaitForSeconds(0.2f); + + Assert.AreEqual("Goed", spellingBeeController.feedbackText.text); + Assert.AreEqual(new Color(0x8b / 255.0f, 0xd4 / 255.0f, 0x5e / 255.0f), spellingBeeController.feedbackText.color); + Assert.AreEqual(new Color(0x8b / 255.0f, 0xd4 / 255.0f, 0x5e / 255.0f), spellingBeeController.scoreBonus.color); + + yield return new WaitForSeconds(0.2f); + + if (sign != spellingBeeController.GetSign()) + { + string expected = spellingBeeController.GetSign(); + float distance = 3.0f * spellingBeeController.GetThreshold(expected); + + spellingBeeController.ProcessCurrentAndPredicted(0.9f * threshold, sign, distance, expected); + + yield return new WaitForSeconds(2.5f); + + Assert.AreEqual($"Verkeerde gebaar: '{sign}'", spellingBeeController.feedbackText.text); + Assert.AreEqual(new Color(0xf5 / 255.0f, 0x49 / 255.0f, 0x3d / 255.0f), spellingBeeController.feedbackText.color); + + spellingBeeController.ProcessCurrentAndPredicted(0.9f * threshold, sign, distance, expected); + + Assert.AreEqual(new Color(0xf5 / 255.0f, 0x49 / 255.0f, 0x3d / 255.0f), spellingBeeController.scoreBonus.color); + } + + yield return new WaitForSeconds(0.2f); + + sign = spellingBeeController.GetSign(); + threshold = spellingBeeController.GetThreshold(sign); + spellingBeeController.ProcessCurrentAndPredicted(1.2f * threshold, sign, 1.2f * threshold, sign); + + yield return new WaitForSeconds(0.2f); + + Assert.AreEqual("Bijna...", spellingBeeController.feedbackText.text); + Assert.AreEqual(new Color(0xf2 / 255.0f, 0x7f / 255.0f, 0x0c / 255.0f), spellingBeeController.feedbackText.color); + + spellingBeeController.ProcessCurrentAndPredicted(3.0f * threshold, sign, 3.0f * threshold, sign); + + yield return new WaitForSeconds(0.2f); + + Assert.AreEqual("Detecteren...", spellingBeeController.feedbackText.text); + Assert.AreEqual(new Color(0xf5 / 255.0f, 0x49 / 255.0f, 0x3d / 255.0f), spellingBeeController.feedbackText.color); + + if (sign != spellingBeeController.GetSign()) + { + string expected = spellingBeeController.GetSign(); + float distance = 3.0f * spellingBeeController.GetThreshold(expected); + + spellingBeeController.ProcessCurrentAndPredicted(0.9f * threshold, sign, distance, expected); + + yield return new WaitForSeconds(2.5f); + + Assert.AreEqual($"Verkeerde gebaar: '{sign}'", spellingBeeController.feedbackText.text); + Assert.AreEqual(new Color(0xf5 / 255.0f, 0x49 / 255.0f, 0x3d / 255.0f), spellingBeeController.feedbackText.color); + + spellingBeeController.ProcessCurrentAndPredicted(0.9f * threshold, sign, distance, expected); + + Assert.AreEqual(new Color(0xf5 / 255.0f, 0x49 / 255.0f, 0x3d / 255.0f), spellingBeeController.scoreBonus.color); + } + } + + /// + /// Cleanup after testing + /// + [TearDown] + public void TearDown_SpellingBeeTests() + { + PersistentDataController.PATH = null; + } }