using System; using System.Collections.Generic; using System.IO; using System.Threading; using System.Threading.Tasks; using GermanApp.Application.Services; using GermanApp.Domain.Interfaces; using Microsoft.Extensions.Logging; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; namespace GermanApp.Tests.Unit.Application.Services; [TestClass] public class AudioGenerationServiceTests { private Mock _mockTtsService; private Mock> _mockLogger; private AudioGenerationService _service; private readonly byte[] _sampleAudio = new byte[1000]; [TestInitialize] public void Setup() { _mockTtsService = new Mock(); _mockLogger = new Mock>(); _service = new AudioGenerationService( _mockTtsService.Object, _mockLogger.Object); // Initialize sample audio for (int i = 0; i < _sampleAudio.Length; i++) { _sampleAudio[i] = (byte)(i % 256); } } [TestCleanup] public void Cleanup() { // Clean up any temp files if (File.Exists("/tmp/test_output.wav")) { File.Delete("/tmp/test_output.wav"); } } [TestMethod] public async Task GenerateAudioAsync_WithValidText_ReturnsAudio() { // Arrange var text = "Hallo Welt"; var language = "de"; var speaker = "default"; var cancellationToken = CancellationToken.None; _mockTtsService.Setup(s => s.GenerateAudioAsync( text, speaker, language, cancellationToken)) .ReturnsAsync(_sampleAudio); // Act var result = await _service.GenerateAudioAsync( text, language, speaker, cancellationToken); // Assert Assert.IsNotNull(result); Assert.AreEqual(_sampleAudio.Length, result.Length); _mockTtsService.Verify(s => s.GenerateAudioAsync( text, speaker, language, cancellationToken), Times.Once); } [TestMethod] public async Task GenerateAudioAsync_WithDefaultLanguage_UsesGerman() { // Arrange var text = "Hallo Welt"; var speaker = "default"; var cancellationToken = CancellationToken.None; _mockTtsService.Setup(s => s.GenerateAudioAsync( text, speaker, "de", cancellationToken)) .ReturnsAsync(_sampleAudio); // Act var result = await _service.GenerateAudioAsync( text, speaker: speaker, cancellationToken: cancellationToken); // Assert Assert.IsNotNull(result); } [TestMethod] public async Task GenerateAudioAsync_WhenTtsThrows_ThrowsAiServiceException() { // Arrange var text = "Hallo Welt"; var cancellationToken = CancellationToken.None; _mockTtsService.Setup(s => s.GenerateAudioAsync( text, null, "de", cancellationToken)) .ThrowsAsync(new Exception("TTS Error")); // Act & Assert try { await _service.GenerateAudioAsync(text, cancellationToken: cancellationToken); Assert.Fail("Expected AiServiceException was not thrown"); } catch (AiServiceException) { // Expected } } [TestMethod] public async Task GenerateAudioToFileAsync_WithValidText_SavesFile() { // Arrange var text = "Hallo Welt"; var outputPath = "/tmp/test_output.wav"; var language = "de"; var speaker = "default"; var cancellationToken = CancellationToken.None; _mockTtsService.Setup(s => s.GenerateAudioToFileAsync( text, outputPath, speaker, language, cancellationToken)) .ReturnsAsync(outputPath); // Act var result = await _service.GenerateAudioToFileAsync( text, outputPath, language, speaker, cancellationToken); // Assert Assert.AreEqual(outputPath, result); _mockTtsService.Verify(s => s.GenerateAudioToFileAsync( text, outputPath, speaker, language, cancellationToken), Times.Once); } [TestMethod] public async Task GenerateAudioStreamAsync_WithValidText_ReturnsStream() { // Arrange var text = "Hallo Welt"; var language = "de"; var speaker = "default"; var cancellationToken = CancellationToken.None; var stream = new MemoryStream(_sampleAudio); _mockTtsService.Setup(s => s.GenerateAudioStreamAsync( text, speaker, language, cancellationToken)) .ReturnsAsync(stream); // Act var result = await _service.GenerateAudioStreamAsync( text, language, speaker, cancellationToken); // Assert Assert.IsNotNull(result); Assert.IsInstanceOfType(result, typeof(MemoryStream)); } [TestMethod] public async Task GenerateVocabularyAudioAsync_WithValidWord_ReturnsAudio() { // Arrange var word = "Apfel"; var language = "de"; var cancellationToken = CancellationToken.None; _mockTtsService.Setup(s => s.GenerateAudioAsync( word, null, language, cancellationToken)) .ReturnsAsync(_sampleAudio); // Act var result = await _service.GenerateVocabularyAudioAsync( word, language, null, cancellationToken); // Assert Assert.IsNotNull(result); Assert.AreEqual(_sampleAudio.Length, result.Length); } [TestMethod] public async Task GenerateLessonAudioAsync_WithValidParameters_ReturnsAudio() { // Arrange var lessonText = "Heute lernen wir neue Wörter."; var vocabularyWords = new List { "lernen", "Wörter", "heute" }; var language = "de"; var cancellationToken = CancellationToken.None; _mockTtsService.Setup(s => s.GenerateAudioAsync( It.IsAny(), null, language, cancellationToken)) .ReturnsAsync(_sampleAudio); // Act var result = await _service.GenerateLessonAudioAsync( lessonText, vocabularyWords, language, cancellationToken); // Assert Assert.IsNotNull(result); Assert.AreEqual(_sampleAudio.Length, result.Length); } [TestMethod] public async Task GenerateStoryAudioAsync_WithValidText_ReturnsAudio() { // Arrange var storyText = "Es war einmal ein kleiner Junge..."; var language = "de"; var speaker = "story-teller"; var cancellationToken = CancellationToken.None; _mockTtsService.Setup(s => s.GenerateAudioAsync( storyText, speaker, language, cancellationToken)) .ReturnsAsync(_sampleAudio); // Act var result = await _service.GenerateStoryAudioAsync( storyText, language, speaker, cancellationToken); // Assert Assert.IsNotNull(result); Assert.AreEqual(_sampleAudio.Length, result.Length); } [TestMethod] public async Task GenerateQuizAudioAsync_WithValidParameters_ReturnsAudio() { // Arrange var questionText = "Was ist die Hauptstadt von Deutschland?"; var options = new List { "Berlin", "München", "Hamburg", "Köln" }; var language = "de"; var cancellationToken = CancellationToken.None; _mockTtsService.Setup(s => s.GenerateAudioAsync( It.IsAny(), null, language, cancellationToken)) .ReturnsAsync(_sampleAudio); // Act var result = await _service.GenerateQuizAudioAsync( questionText, options, language, cancellationToken); // Assert Assert.IsNotNull(result); Assert.AreEqual(_sampleAudio.Length, result.Length); } [TestMethod] public async Task GenerateBatchAudioAsync_WithValidTexts_ReturnsAllFiles() { // Arrange var texts = new Dictionary { ["1"] = "Hallo", ["2"] = "Welt", ["3"] = "Test" }; var outputDirectory = "/tmp/audio"; var language = "de"; var cancellationToken = CancellationToken.None; _mockTtsService.Setup(s => s.GenerateAudioToFileAsync( It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) .ReturnsAsync((string text, string outputPath, string? speaker, string language, CancellationToken ct) => outputPath); // Act var result = await _service.GenerateBatchAudioAsync( texts, outputDirectory, language, cancellationToken); // Assert Assert.IsNotNull(result); Assert.AreEqual(3, result.Count); Assert.IsTrue(result.ContainsKey("1")); Assert.IsTrue(result.ContainsKey("2")); Assert.IsTrue(result.ContainsKey("3")); } [TestMethod] public async Task GetAvailableVoicesAsync_WithVoices_ReturnsList() { // Arrange var expectedVoices = new List { "de-female-1", "de-male-1", "default" }; var cancellationToken = CancellationToken.None; _mockTtsService.Setup(s => s.GetAvailableSpeakersAsync(cancellationToken)) .ReturnsAsync(expectedVoices); // Act var result = await _service.GetAvailableVoicesAsync(cancellationToken); // Assert Assert.IsNotNull(result); Assert.AreEqual(3, result.Count); CollectionAssert.AreEqual(expectedVoices, new List(result)); } [TestMethod] public async Task GetAvailableVoicesAsync_WhenServiceFails_ReturnsDefault() { // Arrange var cancellationToken = CancellationToken.None; _mockTtsService.Setup(s => s.GetAvailableSpeakersAsync(cancellationToken)) .ThrowsAsync(new Exception("Error")); // Act var result = await _service.GetAvailableVoicesAsync(cancellationToken); // Assert Assert.IsNotNull(result); Assert.AreEqual(1, result.Count); Assert.AreEqual("default", result[0]); } [TestMethod] public async Task GetModelInfoAsync_WithModelInfo_ReturnsTuple() { // Arrange var expectedModelName = "tts_models/de/deu/fairseq/vits"; var expectedModelPath = "/path/to/model"; _mockTtsService.Setup(s => s.GetModelInfoAsync()) .ReturnsAsync((expectedModelName, expectedModelPath)); // Act var result = await _service.GetModelInfoAsync(); // Assert Assert.IsNotNull(result); Assert.AreEqual(expectedModelName, result.Item1); Assert.AreEqual(expectedModelPath, result.Item2); } [TestMethod] public async Task GetModelInfoAsync_WhenServiceFails_ReturnsDefault() { // Arrange _mockTtsService.Setup(s => s.GetModelInfoAsync()) .ThrowsAsync(new Exception("Error")); // Act var result = await _service.GetModelInfoAsync(); // Assert Assert.IsNotNull(result); Assert.AreEqual("unknown", result.Item1); Assert.IsNull(result.Item2); } [TestMethod] public async Task TestServiceAsync_WithWorkingService_ReturnsTrue() { // Arrange var cancellationToken = CancellationToken.None; _mockTtsService.Setup(s => s.GenerateAudioAsync( "Hallo Welt", null, "de", cancellationToken)) .ReturnsAsync(_sampleAudio); // Act var result = await _service.TestServiceAsync(cancellationToken); // Assert Assert.IsTrue(result); } [TestMethod] public async Task TestServiceAsync_WithEmptyAudio_ReturnsFalse() { // Arrange var cancellationToken = CancellationToken.None; _mockTtsService.Setup(s => s.GenerateAudioAsync( "Hallo Welt", null, "de", cancellationToken)) .ReturnsAsync(new byte[0]); // Act var result = await _service.TestServiceAsync(cancellationToken); // Assert Assert.IsFalse(result); } [TestMethod] public async Task TestServiceAsync_WhenServiceFails_ReturnsFalse() { // Arrange var cancellationToken = CancellationToken.None; _mockTtsService.Setup(s => s.GenerateAudioAsync( "Hallo Welt", null, "de", cancellationToken)) .ThrowsAsync(new Exception("Error")); // Act var result = await _service.TestServiceAsync(cancellationToken); // Assert Assert.IsFalse(result); } }