yavsc/src/Yavsc.Org.Tests/NonRegression/UserDisplayHelpersTests.cs
Lum bbdcc7f2ad Blog: render user avatar through a null-safe helper
GET /BlogSpot/Details/1 retournait 500 (avec un 500-sur-500 sur
la page d'erreur elle-même) parce que DisplayTemplates
/ApplicationUser.cshtml faisait `var avuri = "/Avatars/" +
Model.UserName + ".s.png"` : avec <Nullable>enable</Nullable>,
Razor émet un null-check implicite sur Model.UserName et lève
NullReferenceException quand l'auteur n'a pas de UserName
posé (donnée héritée, user partiellement initialisé).

- UserDisplayHelpers.AvatarSrc : helper statique pur dans
  Yavsc.Abstract.Identity qui retourne
  YavscConstants.DefaultAvatar pour user null / UserName vide
  ou whitespace, et un path /avatars/<name>.s.png sinon.
- ApplicationUser.cshtml : utilise le helper.
- Tests : 4 cas (null, vide, whitespace, valide) dans
  Yavsc.Org.Tests/NonRegression.

Bonus : le path d'avatar passe de "/Avatars/" (S majuscule,
ne résolvait pas dans le middleware de fichiers statiques) à
YavscConstants.AvatarsPath ("/avatars" minuscule), pour fermer
l'autre trou que centraliser le calcul permettait de fixer
proprement.
2026-07-11 19:41:09 +01:00

63 lines
2.3 KiB
C#

using Xunit;
using Yavsc.Abstract;
using Yavsc.Abstract.Identity;
namespace Yavsc.Org.Tests.NonRegression;
/// <summary>
/// Régression sur le 500 <c>GET /BlogSpot/Details/{id}</c> : un
/// billet dont l'auteur a un <c>UserName</c> null ou absent faisait
/// lever <c>NullReferenceException</c> dans le display template
/// <c>ApplicationUser.cshtml</c> à l'évaluation de
/// <c>Model.UserName</c>. ASP.NET transforme en 500, et la page
/// d'erreur elle-même crash (ErrorViewModel manquant), donc on
/// ne voit rien — juste un 500 muet.
///
/// Le fix passe par <see cref="UserDisplayHelpers.AvatarSrc"/> qui
/// retourne <see cref="YavscConstants.DefaultAvatar"/> pour toute
/// donnée partielle. Ces tests couvrent les trois formes de
/// "donnée absente" : user null, UserName vide, UserName whitespace.
/// </summary>
public class UserDisplayHelpersTests
{
[Fact]
public void AvatarSrc_null_user_returns_default_avatar()
{
Assert.Equal(YavscConstants.DefaultAvatar, UserDisplayHelpers.AvatarSrc(null));
}
[Fact]
public void AvatarSrc_user_with_empty_UserName_returns_default_avatar()
{
var user = new FakeUser { UserName = "" };
Assert.Equal(YavscConstants.DefaultAvatar, UserDisplayHelpers.AvatarSrc(user));
}
[Fact]
public void AvatarSrc_user_with_whitespace_UserName_returns_default_avatar()
{
var user = new FakeUser { UserName = " " };
Assert.Equal(YavscConstants.DefaultAvatar, UserDisplayHelpers.AvatarSrc(user));
}
[Fact]
public void AvatarSrc_valid_user_returns_canonical_avatars_path()
{
var user = new FakeUser { UserName = "alice" };
// Le path doit matcher YavscConstants.AvatarsPath (minuscule),
// pas un /Avatars/ avec S majuscule qui ne résout pas
// dans le middleware de fichiers statiques.
var expected = $"{YavscConstants.AvatarsPath}/alice.s.png";
Assert.Equal(expected, UserDisplayHelpers.AvatarSrc(user));
}
private sealed class FakeUser : IApplicationUser
{
public string Id { get; set; } = "";
public string? UserName { get; set; }
public string? Avatar { get; set; }
public IAccountBalance? AccountBalance => null;
public string? DedicatedGoogleCalendar => null;
public ILocation? PostalAddress => null;
}
}