using MaBibli.Client.Services;
namespace MaBibli.Tests;
///
/// La flèche de retour du bandeau remonte d'un cran de route, et ne sort jamais de
/// l'application. Ces cas sont ceux qui ont été écrits noir sur blanc avant de coder.
///
public class RemonteeRoutesTests
{
[Theory]
// Fiche livre
[InlineData("/livres/3/edition", "/livres/3")]
[InlineData("/livres/3", "/")]
// Séries
[InlineData("/series/7/edition", "/series/7")]
[InlineData("/series/7/ordre", "/series/7")]
[InlineData("/series/7", "/series")]
[InlineData("/series", "/")]
// Envies
[InlineData("/souhaits/5/edition", "/souhaits")]
[InlineData("/souhaits/revues/5/edition", "/souhaits")]
[InlineData("/souhaits/ordre", "/souhaits")]
[InlineData("/souhaits/ajout", "/souhaits")]
[InlineData("/souhaits", "/")]
// Ajout d'un ouvrage
[InlineData("/ajout", "/")]
[InlineData("/ajout/isbn", "/")]
[InlineData("/ajout/manuel", "/")]
// Revues
[InlineData("/revues/ajout", "/revues")]
[InlineData("/revues/12/edition", "/revues/12")]
[InlineData("/revues/12", "/revues")]
[InlineData("/revues", "/")]
// Auteurs
[InlineData("/auteurs/5/bibliographie", "/auteurs")]
[InlineData("/auteurs", "/")]
// Le reste du menu
[InlineData("/prets", "/")]
// L'annexe du menu
[InlineData("/a-propos", "/")]
[InlineData("/", "/")]
public void Remonte_dun_cran(string chemin, string attendu) =>
Assert.Equal(attendu, RemonteeRoutes.Parent(chemin));
///
/// « ajout » n'est pas un identifiant : sans l'ordre de lecture de la table, il serait pris
/// pour la fiche d'une revue.
///
[Fact]
public void Ajout_de_revue_nest_pas_une_fiche() =>
Assert.Equal("/revues", RemonteeRoutes.Parent("/revues/ajout"));
/// La requête d'un filtre ou d'un tri ne change pas la parenté.
[Theory]
[InlineData("/?auteur=3", "/")]
[InlineData("/livres/3/edition?onglet=pret", "/livres/3")]
[InlineData("/auteurs/5/bibliographie#bas", "/auteurs")]
public void La_requete_et_le_fragment_sont_ignores(string chemin, string attendu) =>
Assert.Equal(attendu, RemonteeRoutes.Parent(chemin));
/// Le chemin peut arriver relatif à la base, sans barre oblique de tête.
[Theory]
[InlineData("livres/3/edition", "/livres/3")]
[InlineData("series/7/ordre", "/series/7")]
[InlineData("", "/")]
public void Un_chemin_relatif_est_accepte(string chemin, string attendu) =>
Assert.Equal(attendu, RemonteeRoutes.Parent(chemin));
/// Une barre oblique finale ne doit pas faire manquer la ligne de table.
[Fact]
public void La_barre_finale_est_ignoree() =>
Assert.Equal("/livres/3", RemonteeRoutes.Parent("/livres/3/edition/"));
///
/// Repli d'une route inconnue : la destination de menu de sa branche, jamais un chemin
/// deviné, et jamais rien d'externe.
///
[Theory]
[InlineData("/revues/12/inconnu", "/revues")]
[InlineData("/series/7/inconnu", "/series")]
[InlineData("/inconnu/total", "/")]
[InlineData("/livres", "/")]
public void Une_route_inconnue_retombe_sur_sa_branche(string chemin, string attendu) =>
Assert.Equal(attendu, RemonteeRoutes.Parent(chemin));
///
/// ⚠️ Le garde-fou du lot S : quoi qu'on lui donne, le retour reste dans l'application.
/// Une URL absolue ou un chemin protocolaire ne doit jamais ressortir tel quel.
///
[Theory]
[InlineData(null)]
[InlineData("")]
[InlineData(" ")]
[InlineData("https://exemple.test/livres/3")]
[InlineData("//exemple.test/")]
[InlineData("/livres/abc/edition")]
public void Ne_sort_jamais_de_lapplication(string? chemin)
{
var parent = RemonteeRoutes.Parent(chemin);
Assert.StartsWith("/", parent);
Assert.DoesNotContain("//", parent);
Assert.DoesNotContain(":", parent);
}
}