Page « À propos » (/a-propos) : manuel annoncé à venir, contact, site de l'auteur, version publiée avec sa date de build, et licence AGPL v3 avec le lien vers le dépôt — l'AGPL attend que les utilisateurs d'un service en réseau puissent en obtenir la source, ce lien n'est donc pas un ornement. L'application ne connaissait pas sa version : elle vivait dans le manifeste du paquet et dans les tags git, jamais dans le binaire. `build/publier-release.sh` pose désormais `-p:Version` et `-p:MaBibliDateBuild` ; l'API rend les deux par `GET /api/version`. ⚠️ L'horodatage est le TÉMOIN de l'injection, et rien ne le calcule côté MSBuild. Sans lui, la version lue serait le « 1.0.0 » que le SDK pose par défaut : il se lirait comme une vraie version alors qu'il ne désigne rien, et c'est exactement la valeur qu'on ira chercher pour diagnostiquer un appareil au cache dépareillé. Mieux vaut ne rien annoncer — un binaire compilé à la main se déclare « version de développement », ce qui est vrai. Autres décisions : - l'entrée du menu est DÉTACHÉE des six destinations, par un filet au-dessus sur téléphone et à gauche en rangée sur PC : « À propos » est une annexe, pas une septième destination. Ses règles vivent en feuille GLOBALE, comme tout le menu — une règle scopée n'atteint pas ce que rend un NavLink ; - le « mailto: » reste un lien même hors-ligne : il ne charge aucune page et passe la main au client de messagerie, qui sait mettre un message en attente. Le site et le dépôt, eux, basculent en boutons désactivés portant leur motif, comme les liens d'export des envies ; - la version est un sixième instantané hors-ligne : on la lit justement quand quelque chose ne va pas, et un appareil qu'on soupçonne est souvent celui qui n'a plus de réseau. L'écran dit alors que c'est la dernière version vue du serveur. Le point de rupture de 40 rem reste identique dans les deux feuilles, et /a-propos est inscrite dans la table de remontée des routes. Vérifié en exécution, l'API lancée : sans injection `{"numero":null,"publiee":false}`, avec `-p:Version=0.4.1 -p:MaBibliDateBuild=…` `{"numero":"0.4.1","publiee":true}`. Le rendu des écrans n'a PAS été vérifié en navigateur. 618 tests au vert (605 avant). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
96 lines
3.7 KiB
C#
96 lines
3.7 KiB
C#
using System.Reflection;
|
|
using MaBibli.Api.Endpoints;
|
|
using MaBibli.Shared.Dtos;
|
|
|
|
namespace MaBibli.Tests;
|
|
|
|
/// <summary>
|
|
/// La version affichée par « À propos » est ce qu'on demandera à quelqu'un dont l'application se
|
|
/// comporte mal : elle doit être exacte ou absente, jamais approximative.
|
|
/// </summary>
|
|
public class VersionApplicationTests
|
|
{
|
|
[Fact]
|
|
public void Version_et_horodatage_injectes_donnent_une_version_publiee()
|
|
{
|
|
var version = VersionApplication.Depuis("0.4.0", "2026-08-21T10:30:00Z");
|
|
|
|
Assert.True(version.Publiee);
|
|
Assert.Equal("0.4.0", version.Numero);
|
|
Assert.Equal(
|
|
new DateTimeOffset(2026, 8, 21, 10, 30, 0, TimeSpan.Zero),
|
|
version.DateBuild!.Value.ToUniversalTime());
|
|
}
|
|
|
|
/// <summary>
|
|
/// ⚠️ Le cas qui justifie tout le mécanisme : sans injection, le SDK .NET pose « 1.0.0 »
|
|
/// dans l'assembly. Ce numéro se lirait comme une vraie version alors qu'il ne désigne rien.
|
|
/// </summary>
|
|
[Fact]
|
|
public void Sans_horodatage_le_numero_du_SDK_nest_PAS_annonce()
|
|
{
|
|
var version = VersionApplication.Depuis("1.0.0", null);
|
|
|
|
Assert.False(version.Publiee);
|
|
Assert.Null(version.Numero);
|
|
Assert.Null(version.DateBuild);
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData("")]
|
|
[InlineData(" ")]
|
|
[InlineData("pas une date")]
|
|
public void Un_horodatage_illisible_vaut_absence(string horodatage) =>
|
|
Assert.False(VersionApplication.Depuis("0.4.0", horodatage).Publiee);
|
|
|
|
/// <summary>Un horodatage sans version n'est pas une version : on n'invente pas le numéro.</summary>
|
|
[Theory]
|
|
[InlineData(null)]
|
|
[InlineData("")]
|
|
[InlineData(" ")]
|
|
public void Sans_numero_rien_nest_annonce(string? numero) =>
|
|
Assert.False(VersionApplication.Depuis(numero, "2026-08-21T10:30:00Z").Publiee);
|
|
|
|
/// <summary>
|
|
/// Le SDK ajoute parfois « +empreinte » à l'InformationalVersion (SourceRevisionId) : seule
|
|
/// la partie qui précède le « + » est un numéro de version lisible par un humain.
|
|
/// </summary>
|
|
[Fact]
|
|
public void L_empreinte_de_commit_est_retiree() =>
|
|
Assert.Equal(
|
|
"0.4.0",
|
|
VersionApplication.Depuis("0.4.0+9a3f21c", "2026-08-21T10:30:00Z").Numero);
|
|
|
|
/// <summary>Une date locale injectée est ramenée en UTC, comme toutes les dates du projet.</summary>
|
|
[Fact]
|
|
public void L_horodatage_est_ramene_en_UTC() =>
|
|
Assert.Equal(
|
|
new DateTimeOffset(2026, 8, 21, 8, 30, 0, TimeSpan.Zero),
|
|
VersionApplication.Depuis("0.4.0", "2026-08-21T10:30:00+02:00")!.DateBuild!.Value.ToUniversalTime());
|
|
|
|
/// <summary>
|
|
/// La lecture des attributs est branchée sur le bon assembly. Les tests ne sont pas compilés
|
|
/// par la chaîne de publication : elle doit donc rendre « version de développement », ce qui
|
|
/// est exactement le comportement attendu d'un binaire compilé à la main.
|
|
/// </summary>
|
|
[Fact]
|
|
public void La_lecture_de_lassembly_ne_leve_rien_et_ne_publie_rien()
|
|
{
|
|
var version = VersionEndpoints.Lire(typeof(VersionEndpoints).Assembly);
|
|
|
|
Assert.False(version.Publiee);
|
|
}
|
|
|
|
/// <summary>Une métadonnée bien nommée est bien lue, quel que soit l'assembly qui la porte.</summary>
|
|
[Fact]
|
|
public void La_metadonnee_MaBibliDateBuild_est_celle_qui_est_lue()
|
|
{
|
|
var assembly = typeof(VersionApplicationTests).Assembly;
|
|
|
|
// Aucun assembly de test ne la porte : la lecture doit rendre null, pas la première
|
|
// métadonnée venue (elles sont nombreuses, posées par le SDK).
|
|
Assert.Null(assembly.GetCustomAttributes<AssemblyMetadataAttribute>()
|
|
.FirstOrDefault(a => a.Key == "MaBibliDateBuild"));
|
|
}
|
|
}
|