diff --git a/Minecraft-Realms-Emulator.sln b/Minecraft-Realms-Emulator.sln
index 5a31fd6..1735988 100644
--- a/Minecraft-Realms-Emulator.sln
+++ b/Minecraft-Realms-Emulator.sln
@@ -5,7 +5,9 @@ VisualStudioVersion = 17.8.34511.84
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Minecraft-Realms-Emulator", "Minecraft-Realms-Emulator\Minecraft-Realms-Emulator.csproj", "{A9A21AAF-EF1B-4723-9407-51FD6B831B98}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Panel", "Panel\Panel.csproj", "{DDDF0FE0-736D-47D5-8571-3DD7354B7917}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Panel", "Panel\Panel.csproj", "{DDDF0FE0-736D-47D5-8571-3DD7354B7917}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnitTests", "UnitTests\UnitTests.csproj", "{AFF83C8C-B6CA-4707-A26E-82002822F820}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -21,6 +23,10 @@ Global
{DDDF0FE0-736D-47D5-8571-3DD7354B7917}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DDDF0FE0-736D-47D5-8571-3DD7354B7917}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DDDF0FE0-736D-47D5-8571-3DD7354B7917}.Release|Any CPU.Build.0 = Release|Any CPU
+ {AFF83C8C-B6CA-4707-A26E-82002822F820}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {AFF83C8C-B6CA-4707-A26E-82002822F820}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {AFF83C8C-B6CA-4707-A26E-82002822F820}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {AFF83C8C-B6CA-4707-A26E-82002822F820}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/Minecraft-Realms-Emulator/Minecraft-Realms-Emulator.csproj b/Minecraft-Realms-Emulator/Minecraft-Realms-Emulator.csproj
index 4aa066a..19cd6c6 100644
--- a/Minecraft-Realms-Emulator/Minecraft-Realms-Emulator.csproj
+++ b/Minecraft-Realms-Emulator/Minecraft-Realms-Emulator.csproj
@@ -25,4 +25,8 @@
+
+
+
+
diff --git a/UnitTests/UnitTests.csproj b/UnitTests/UnitTests.csproj
new file mode 100644
index 0000000..f2563fc
--- /dev/null
+++ b/UnitTests/UnitTests.csproj
@@ -0,0 +1,31 @@
+
+
+
+ net8.0
+ enable
+ enable
+
+ false
+ true
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/UnitTests/WorldsControllerTests.cs b/UnitTests/WorldsControllerTests.cs
new file mode 100644
index 0000000..0ea035a
--- /dev/null
+++ b/UnitTests/WorldsControllerTests.cs
@@ -0,0 +1,220 @@
+using Microsoft.AspNetCore.Mvc.Testing;
+using Minecraft_Realms_Emulator.Entities;
+using Minecraft_Realms_Emulator.Requests;
+using Newtonsoft.Json;
+using System.Text;
+
+namespace UnitTests
+{
+ [TestClass]
+ public class WorldsControllerTests
+ {
+ [TestInitialize]
+ public void Setup()
+ {
+ Environment.SetEnvironmentVariable("CONNECTION_STRING", "User Id=postgres;Password=postgres;Server=localhost;Port=5432;Database=Minecraft-Realms-Emulator;");
+ }
+
+ [TestMethod]
+ public async Task GetWorlds_Always_ReturnsPlayerWorlds()
+ {
+ var factory = new WebApplicationFactory();
+ var client = factory.CreateClient();
+
+ client.DefaultRequestHeaders.Add("Cookie", "sid=token:fakeToken:069a79f444e94726a5befca90e38aaf5;user=testPlayer;version=1.21.1");
+
+ var response = await client.GetAsync("worlds");
+
+ Assert.IsTrue(response.IsSuccessStatusCode);
+ Assert.IsNotNull(await response.Content.ReadAsStringAsync());
+ }
+
+ [TestMethod]
+ public async Task GetWorldsSnapshot_Always_ReturnsPlayerWorlds()
+ {
+ var factory = new WebApplicationFactory();
+ var client = factory.CreateClient();
+
+ client.DefaultRequestHeaders.Add("Cookie", "sid=token:fakeToken:069a79f444e94726a5befca90e38aaf5;user=testPlayer;version=1.21.1");
+
+ var response = await client.GetAsync("worlds/listUserWorldsOfType/any");
+
+ Assert.IsTrue(response.IsSuccessStatusCode);
+ Assert.IsNotNull(await response.Content.ReadAsStringAsync());
+ }
+
+ [TestMethod]
+ public async Task GetPrereleaseWorlds_Always_ReturnsPrereleaseEligibleWorlds()
+ {
+ var factory = new WebApplicationFactory();
+ var client = factory.CreateClient();
+
+ client.DefaultRequestHeaders.Add("Cookie", "sid=token:fakeToken:069a79f444e94726a5befca90e38aaf5;user=testPlayer;version=1.21.1");
+ client.DefaultRequestHeaders.Add("Is-Prerelease", "true");
+
+ var response = await client.GetAsync("worlds/listPrereleaseEligibleWorlds");
+
+ Assert.IsTrue(response.IsSuccessStatusCode);
+ Assert.IsNotNull(await response.Content.ReadAsStringAsync());
+ }
+
+ [TestMethod]
+ public async Task GetWorldById_NotInitialized_ReturnsError()
+ {
+ var factory = new WebApplicationFactory();
+ var client = factory.CreateClient();
+
+ client.DefaultRequestHeaders.Add("Cookie", "sid=token:fakeToken:069a79f444e94726a5befca90e38aaf5;user=testPlayer;version=1.21.1");
+
+ var response = await client.GetAsync("worlds/1");
+
+ Assert.IsFalse(response.IsSuccessStatusCode);
+
+ string expectedResponse = "{\"errorCode\":400,\"errorMsg\":\"Initialize the world first\"}";
+
+ Assert.AreEqual(expectedResponse, await response.Content.ReadAsStringAsync());
+ }
+
+ [TestMethod]
+ public async Task Initialize_NotInitializedAndOwner_ReturnsWorld()
+ {
+ var factory = new WebApplicationFactory();
+ var client = factory.CreateClient();
+
+ client.DefaultRequestHeaders.Add("Cookie", "sid=token:fakeToken:069a79f444e94726a5befca90e38aaf5;user=testPlayer;version=1.21.1");
+
+ WorldCreateRequest request = new()
+ {
+ Name = "Testing",
+ Description = "Created by unit tests"
+ };
+
+ var content = new StringContent(JsonConvert.SerializeObject(request), Encoding.UTF8, "application/json");
+ var response = await client.PostAsync("worlds/1/initialize", content);
+
+ Assert.IsTrue(response.IsSuccessStatusCode);
+
+ var jsonResponse = JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync());
+
+ string expectedResponse = $"{{\"id\":1,\"subscription\":{{\"id\":1,\"worldId\":1,\"world\":null,\"startDate\":\"{jsonResponse.Subscription.StartDate.ToString("O")}\",\"subscriptionType\":\"NORMAL\"}},\"owner\":\"testPlayer\",\"ownerUUID\":\"069a79f444e94726a5befca90e38aaf5\",\"name\":\"Testing\",\"motd\":\"Created by unit tests\",\"state\":\"OPEN\",\"worldType\":\"NORMAL\",\"players\":[],\"maxPlayers\":10,\"minigame\":null,\"activeSlot\":1,\"slots\":[{{\"id\":1,\"world\":null,\"slotId\":1,\"slotName\":\"\",\"version\":\"1.21.1\",\"gameMode\":0,\"difficulty\":2,\"spawnProtection\":0,\"forceGameMode\":false,\"pvp\":true,\"spawnAnimals\":true,\"spawnMonsters\":true,\"spawnNPCs\":true,\"commandBlocks\":false}}],\"member\":false,\"parentWorld\":null}}";
+ Assert.AreEqual(expectedResponse, await response.Content.ReadAsStringAsync());
+ }
+
+ [TestMethod]
+ public async Task GetWorldById_IsInitializedAndOwner_ReturnsWorld()
+ {
+ var factory = new WebApplicationFactory();
+ var client = factory.CreateClient();
+
+ client.DefaultRequestHeaders.Add("Cookie", "sid=token:fakeToken:069a79f444e94726a5befca90e38aaf5;user=testPlayer;version=1.21.1");
+
+ var response = await client.GetAsync("worlds/1");
+ Assert.IsTrue(response.IsSuccessStatusCode);
+
+ string expectedResponse = "{\"remoteSubscriptionId\":\"00000000-0000-0000-0000-000000000000\",\"daysLeft\":30,\"expired\":false,\"expiredTrial\":false,\"compatibility\":\"COMPATIBLE\",\"slots\":[{\"slotId\":1,\"options\":\"{\\\"slotName\\\":\\\"\\\",\\\"gameMode\\\":0,\\\"difficulty\\\":2,\\\"spawnProtection\\\":0,\\\"forceGameMode\\\":false,\\\"pvp\\\":true,\\\"spawnAnimals\\\":true,\\\"spawnMonsters\\\":true,\\\"spawnNPCs\\\":true,\\\"commandBlocks\\\":false,\\\"version\\\":\\\"1.21.1\\\",\\\"compatibility\\\":\\\"COMPATIBLE\\\"}\"}],\"activeVersion\":\"1.21.1\",\"parentWorldId\":null,\"parentWorldName\":null,\"minigameId\":null,\"minigameName\":null,\"minigameImage\":null,\"id\":1,\"subscription\":null,\"owner\":\"testPlayer\",\"ownerUUID\":\"069a79f444e94726a5befca90e38aaf5\",\"name\":\"Testing\",\"motd\":\"Created by unit tests\",\"state\":\"OPEN\",\"worldType\":\"NORMAL\",\"players\":[],\"maxPlayers\":10,\"minigame\":null,\"activeSlot\":1,\"member\":false,\"parentWorld\":null}";
+ Assert.AreEqual(expectedResponse, await response.Content.ReadAsStringAsync());
+ }
+
+ [TestMethod]
+ public async Task GetWorldById_isInitializedAndNotOwner_ReturnsError()
+ {
+ var factory = new WebApplicationFactory();
+ var client = factory.CreateClient();
+
+ client.DefaultRequestHeaders.Add("Cookie", "sid=token:fakeToken:d33b406631524e31805528e304f7401f;user=testPlayer2;version=1.21.1");
+
+ var response = await client.GetAsync("worlds/1");
+
+ Assert.IsFalse(response.IsSuccessStatusCode);
+
+ string expectedResponse = "You don't own this world";
+ Assert.AreEqual(expectedResponse, await response.Content.ReadAsStringAsync());
+ }
+
+ [TestMethod]
+ public async Task GetWorldById_NotFound_ReturnsError()
+ {
+ var factory = new WebApplicationFactory();
+ var client = factory.CreateClient();
+
+ client.DefaultRequestHeaders.Add("Cookie", "sid=token:fakeToken:069a79f444e94726a5befca90e38aaf5;user=testPlayer;version=1.21.1");
+
+ var response = await client.GetAsync("worlds/2");
+
+ Assert.IsFalse(response.IsSuccessStatusCode);
+
+ string expectedResponse = "{\"errorCode\":404,\"errorMsg\":\"World not found\"}";
+ Assert.AreEqual(expectedResponse, await response.Content.ReadAsStringAsync());
+ }
+
+ [TestMethod]
+ public async Task Initialize_NotFound_ReturnsError()
+ {
+ var factory = new WebApplicationFactory();
+ var client = factory.CreateClient();
+
+ client.DefaultRequestHeaders.Add("Cookie", "sid=token:fakeToken:069a79f444e94726a5befca90e38aaf5;user=testPlayer;version=1.21.1");
+
+ WorldCreateRequest request = new()
+ {
+ Name = "Testing",
+ Description = "Created by unit tests"
+ };
+
+ var content = new StringContent(JsonConvert.SerializeObject(request), Encoding.UTF8, "application/json");
+ var response = await client.PostAsync("worlds/2/initialize", content);
+
+ Assert.IsFalse(response.IsSuccessStatusCode);
+
+ string expectedResponse = "{\"errorCode\":404,\"errorMsg\":\"World not found\"}";
+ Assert.AreEqual(expectedResponse, await response.Content.ReadAsStringAsync());
+ }
+
+ [TestMethod]
+ public async Task Initialize_AlreadyInitialized_ReturnsError()
+ {
+ var factory = new WebApplicationFactory();
+ var client = factory.CreateClient();
+
+ client.DefaultRequestHeaders.Add("Cookie", "sid=token:fakeToken:069a79f444e94726a5befca90e38aaf5;user=testPlayer;version=1.21.1");
+
+ WorldCreateRequest request = new()
+ {
+ Name = "Testing",
+ Description = "Created by unit tests"
+ };
+
+ var content = new StringContent(JsonConvert.SerializeObject(request), Encoding.UTF8, "application/json");
+ var response = await client.PostAsync("worlds/1/initialize", content);
+
+ Assert.IsFalse(response.IsSuccessStatusCode);
+
+ string expectedResponse = "{\"errorCode\":401,\"errorMsg\":\"World already initialized\"}";
+
+ Assert.AreEqual(expectedResponse, await response.Content.ReadAsStringAsync());
+ }
+ [TestMethod]
+ public async Task Initialize_NotOwner_ReturnsError()
+ {
+ var factory = new WebApplicationFactory();
+ var client = factory.CreateClient();
+
+ client.DefaultRequestHeaders.Add("Cookie", "sid=token:fakeToken:d33b406631524e31805528e304f7401f;user=testPlayer2;version=1.21.1");
+
+ WorldCreateRequest request = new()
+ {
+ Name = "Testing",
+ Description = "Created by unit tests"
+ };
+
+ var content = new StringContent(JsonConvert.SerializeObject(request), Encoding.UTF8, "application/json");
+ var response = await client.PostAsync("worlds/1/initialize", content);
+
+ Assert.IsFalse(response.IsSuccessStatusCode);
+
+ string expectedResponse = "You don't own this world";
+
+ Assert.AreEqual(expectedResponse, await response.Content.ReadAsStringAsync());
+ }
+ }
+}
\ No newline at end of file