Refactor and update various components of EchoHub.Server

- Updated launchSettings.json for consistency.
- Refactored FileValidationHelper to improve image validation logic.
- Enhanced ServerDirectoryService for better connection handling and user count updates.
- Improved DatabaseSetup for legacy database handling and seeding default channels.
- Refined FirstRunSetup to ensure JWT secret generation.
- Removed appsettings.Development.json as it is no longer needed.
- Updated EchoHub.Tests project file for consistency.
- Added unit tests for FileValidationHelper and PresenceTracker with improved assertions.
- Updated ValidationConstantsTests to ensure regex validations are correct.
- Cleaned up solution file formatting for better readability.
This commit is contained in:
HueByte
2026-02-19 10:12:28 +01:00
parent 32e01e8d71
commit 9975f4e4be
57 changed files with 4401 additions and 4378 deletions
+25 -25
View File
@@ -1,25 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.*" />
<PackageReference Include="xunit" Version="2.*" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.*">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\EchoHub.Core\EchoHub.Core.csproj" />
<ProjectReference Include="..\EchoHub.Server\EchoHub.Server.csproj" />
</ItemGroup>
</Project>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.*" />
<PackageReference Include="xunit" Version="2.*" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.*">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\EchoHub.Core\EchoHub.Core.csproj" />
<ProjectReference Include="..\EchoHub.Server\EchoHub.Server.csproj" />
</ItemGroup>
</Project>
+56 -56
View File
@@ -1,56 +1,56 @@
using EchoHub.Server.Services;
using Xunit;
namespace EchoHub.Tests;
public class FileValidationHelperTests
{
[Fact]
public void IsValidImage_JpegMagicBytes_ReturnsTrue()
{
byte[] jpeg = [0xFF, 0xD8, 0xFF, 0xE0, 0x00, 0x10];
using var stream = new MemoryStream(jpeg);
Assert.True(FileValidationHelper.IsValidImage(stream));
}
[Fact]
public void IsValidImage_PngMagicBytes_ReturnsTrue()
{
byte[] png = [0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A];
using var stream = new MemoryStream(png);
Assert.True(FileValidationHelper.IsValidImage(stream));
}
[Fact]
public void IsValidImage_GifMagicBytes_ReturnsTrue()
{
byte[] gif = [0x47, 0x49, 0x46, 0x38, 0x39, 0x61];
using var stream = new MemoryStream(gif);
Assert.True(FileValidationHelper.IsValidImage(stream));
}
[Fact]
public void IsValidImage_WebpMagicBytes_ReturnsTrue()
{
byte[] webp = [0x52, 0x49, 0x46, 0x46, 0x00, 0x00, 0x00, 0x00, 0x57, 0x45, 0x42, 0x50];
using var stream = new MemoryStream(webp);
Assert.True(FileValidationHelper.IsValidImage(stream));
}
[Fact]
public void IsValidImage_RandomBytes_ReturnsFalse()
{
byte[] random = [0x00, 0x01, 0x02, 0x03, 0x04, 0x05];
using var stream = new MemoryStream(random);
Assert.False(FileValidationHelper.IsValidImage(stream));
}
[Fact]
public void IsValidImage_ResetsStreamPosition()
{
byte[] jpeg = [0xFF, 0xD8, 0xFF, 0xE0, 0x00, 0x10];
using var stream = new MemoryStream(jpeg);
FileValidationHelper.IsValidImage(stream);
Assert.Equal(0, stream.Position);
}
}
using EchoHub.Server.Services;
using Xunit;
namespace EchoHub.Tests;
public class FileValidationHelperTests
{
[Fact]
public void IsValidImage_JpegMagicBytes_ReturnsTrue()
{
byte[] jpeg = [0xFF, 0xD8, 0xFF, 0xE0, 0x00, 0x10];
using var stream = new MemoryStream(jpeg);
Assert.True(FileValidationHelper.IsValidImage(stream));
}
[Fact]
public void IsValidImage_PngMagicBytes_ReturnsTrue()
{
byte[] png = [0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A];
using var stream = new MemoryStream(png);
Assert.True(FileValidationHelper.IsValidImage(stream));
}
[Fact]
public void IsValidImage_GifMagicBytes_ReturnsTrue()
{
byte[] gif = [0x47, 0x49, 0x46, 0x38, 0x39, 0x61];
using var stream = new MemoryStream(gif);
Assert.True(FileValidationHelper.IsValidImage(stream));
}
[Fact]
public void IsValidImage_WebpMagicBytes_ReturnsTrue()
{
byte[] webp = [0x52, 0x49, 0x46, 0x46, 0x00, 0x00, 0x00, 0x00, 0x57, 0x45, 0x42, 0x50];
using var stream = new MemoryStream(webp);
Assert.True(FileValidationHelper.IsValidImage(stream));
}
[Fact]
public void IsValidImage_RandomBytes_ReturnsFalse()
{
byte[] random = [0x00, 0x01, 0x02, 0x03, 0x04, 0x05];
using var stream = new MemoryStream(random);
Assert.False(FileValidationHelper.IsValidImage(stream));
}
[Fact]
public void IsValidImage_ResetsStreamPosition()
{
byte[] jpeg = [0xFF, 0xD8, 0xFF, 0xE0, 0x00, 0x10];
using var stream = new MemoryStream(jpeg);
FileValidationHelper.IsValidImage(stream);
Assert.Equal(0, stream.Position);
}
}
+68 -68
View File
@@ -1,68 +1,68 @@
using EchoHub.Server.Services;
using Xunit;
namespace EchoHub.Tests;
public class PresenceTrackerTests
{
[Fact]
public void UserConnected_IsOnline_ReturnsTrue()
{
var tracker = new PresenceTracker();
tracker.UserConnected("conn1", Guid.NewGuid(), "alice");
Assert.True(tracker.IsOnline("alice"));
}
[Fact]
public void UserDisconnected_LastConnection_IsOnlineReturnsFalse()
{
var tracker = new PresenceTracker();
tracker.UserConnected("conn1", Guid.NewGuid(), "alice");
tracker.UserDisconnected("conn1");
Assert.False(tracker.IsOnline("alice"));
}
[Fact]
public void MultipleConnections_DisconnectOne_StillOnline()
{
var tracker = new PresenceTracker();
var userId = Guid.NewGuid();
tracker.UserConnected("conn1", userId, "alice");
tracker.UserConnected("conn2", userId, "alice");
tracker.UserDisconnected("conn1");
Assert.True(tracker.IsOnline("alice"));
}
[Fact]
public void JoinChannel_GetOnlineUsersInChannel_ReturnsUser()
{
var tracker = new PresenceTracker();
tracker.UserConnected("conn1", Guid.NewGuid(), "alice");
tracker.JoinChannel("alice", "general");
var users = tracker.GetOnlineUsersInChannel("general");
Assert.Contains("alice", users);
}
[Fact]
public void LeaveChannel_UserNoLongerInChannel()
{
var tracker = new PresenceTracker();
tracker.UserConnected("conn1", Guid.NewGuid(), "alice");
tracker.JoinChannel("alice", "general");
tracker.LeaveChannel("alice", "general");
var users = tracker.GetOnlineUsersInChannel("general");
Assert.DoesNotContain("alice", users);
}
[Fact]
public void GetChannelsForUser_ReturnsJoinedChannels()
{
var tracker = new PresenceTracker();
tracker.UserConnected("conn1", Guid.NewGuid(), "alice");
tracker.JoinChannel("alice", "general");
tracker.JoinChannel("alice", "random");
var channels = tracker.GetChannelsForUser("alice");
Assert.Contains("general", channels);
Assert.Contains("random", channels);
}
}
using EchoHub.Server.Services;
using Xunit;
namespace EchoHub.Tests;
public class PresenceTrackerTests
{
[Fact]
public void UserConnected_IsOnline_ReturnsTrue()
{
var tracker = new PresenceTracker();
tracker.UserConnected("conn1", Guid.NewGuid(), "alice");
Assert.True(tracker.IsOnline("alice"));
}
[Fact]
public void UserDisconnected_LastConnection_IsOnlineReturnsFalse()
{
var tracker = new PresenceTracker();
tracker.UserConnected("conn1", Guid.NewGuid(), "alice");
tracker.UserDisconnected("conn1");
Assert.False(tracker.IsOnline("alice"));
}
[Fact]
public void MultipleConnections_DisconnectOne_StillOnline()
{
var tracker = new PresenceTracker();
var userId = Guid.NewGuid();
tracker.UserConnected("conn1", userId, "alice");
tracker.UserConnected("conn2", userId, "alice");
tracker.UserDisconnected("conn1");
Assert.True(tracker.IsOnline("alice"));
}
[Fact]
public void JoinChannel_GetOnlineUsersInChannel_ReturnsUser()
{
var tracker = new PresenceTracker();
tracker.UserConnected("conn1", Guid.NewGuid(), "alice");
tracker.JoinChannel("alice", "general");
var users = tracker.GetOnlineUsersInChannel("general");
Assert.Contains("alice", users);
}
[Fact]
public void LeaveChannel_UserNoLongerInChannel()
{
var tracker = new PresenceTracker();
tracker.UserConnected("conn1", Guid.NewGuid(), "alice");
tracker.JoinChannel("alice", "general");
tracker.LeaveChannel("alice", "general");
var users = tracker.GetOnlineUsersInChannel("general");
Assert.DoesNotContain("alice", users);
}
[Fact]
public void GetChannelsForUser_ReturnsJoinedChannels()
{
var tracker = new PresenceTracker();
tracker.UserConnected("conn1", Guid.NewGuid(), "alice");
tracker.JoinChannel("alice", "general");
tracker.JoinChannel("alice", "random");
var channels = tracker.GetChannelsForUser("alice");
Assert.Contains("general", channels);
Assert.Contains("random", channels);
}
}
+46 -46
View File
@@ -1,46 +1,46 @@
using EchoHub.Core.Constants;
using Xunit;
namespace EchoHub.Tests;
public class ValidationConstantsTests
{
[Theory]
[InlineData("alice", true)]
[InlineData("Bob_123", true)]
[InlineData("user-name", true)]
[InlineData("abc", true)]
[InlineData("ab", false)]
[InlineData("", false)]
[InlineData("has space", false)]
[InlineData("has@symbol", false)]
public void UsernameRegex_ValidatesCorrectly(string input, bool expected)
{
var result = ValidationConstants.UsernameRegex().IsMatch(input);
Assert.Equal(expected, result);
}
[Theory]
[InlineData("general", true)]
[InlineData("my-channel_01", true)]
[InlineData("ab", true)]
[InlineData("a", false)]
[InlineData("has space", false)]
public void ChannelNameRegex_ValidatesCorrectly(string input, bool expected)
{
var result = ValidationConstants.ChannelNameRegex().IsMatch(input);
Assert.Equal(expected, result);
}
[Theory]
[InlineData("#FF0000", true)]
[InlineData("#aabbcc", true)]
[InlineData("FF0000", false)]
[InlineData("#FFF", false)]
[InlineData("#GGGGGG", false)]
public void HexColorRegex_ValidatesCorrectly(string input, bool expected)
{
var result = ValidationConstants.HexColorRegex().IsMatch(input);
Assert.Equal(expected, result);
}
}
using EchoHub.Core.Constants;
using Xunit;
namespace EchoHub.Tests;
public class ValidationConstantsTests
{
[Theory]
[InlineData("alice", true)]
[InlineData("Bob_123", true)]
[InlineData("user-name", true)]
[InlineData("abc", true)]
[InlineData("ab", false)]
[InlineData("", false)]
[InlineData("has space", false)]
[InlineData("has@symbol", false)]
public void UsernameRegex_ValidatesCorrectly(string input, bool expected)
{
var result = ValidationConstants.UsernameRegex().IsMatch(input);
Assert.Equal(expected, result);
}
[Theory]
[InlineData("general", true)]
[InlineData("my-channel_01", true)]
[InlineData("ab", true)]
[InlineData("a", false)]
[InlineData("has space", false)]
public void ChannelNameRegex_ValidatesCorrectly(string input, bool expected)
{
var result = ValidationConstants.ChannelNameRegex().IsMatch(input);
Assert.Equal(expected, result);
}
[Theory]
[InlineData("#FF0000", true)]
[InlineData("#aabbcc", true)]
[InlineData("FF0000", false)]
[InlineData("#FFF", false)]
[InlineData("#GGGGGG", false)]
public void HexColorRegex_ValidatesCorrectly(string input, bool expected)
{
var result = ValidationConstants.HexColorRegex().IsMatch(input);
Assert.Equal(expected, result);
}
}