159 lines
5.4 KiB
C#
159 lines
5.4 KiB
C#
using Omika.App.Local.Models;
|
|
using Omika.App.Local.Services;
|
|
|
|
namespace Omika.Tests.Mobile;
|
|
|
|
/// <summary>
|
|
/// Tests du jeton de cible des modèles multilingues : lecture du fichier
|
|
/// <c>modele.json</c> d'un sens, validation (un jeton malformé est refusé, jamais
|
|
/// ignoré en silence) et composition du texte effectivement envoyé au modèle.
|
|
///
|
|
/// <para>
|
|
/// Le pipeline ONNX complet n'est pas exerçable ici : il exige un vocabulaire
|
|
/// SentencePiece réel et le moteur d'inférence. La preuve de bout en bout se fait
|
|
/// avec <c>Omika.LanguesProbe traduire --dossier <pack></c>, qui exécute le
|
|
/// vrai moteur sur un vrai pack.
|
|
/// </para>
|
|
/// </summary>
|
|
public class ModelePackMetadonneesTests
|
|
{
|
|
[Fact]
|
|
public void DepuisJson_JetonPresent_EstLuAvecSonModele()
|
|
{
|
|
string json = """
|
|
{
|
|
"version": 1,
|
|
"modeleSource": "Helsinki-NLP/opus-mt-tc-big-itc-itc",
|
|
"famille": "itc",
|
|
"jetonCible": ">>fra<<"
|
|
}
|
|
""";
|
|
|
|
ModelePackMetadonnees? metadonnees = ModelePackMetadonnees.DepuisJson(json);
|
|
|
|
Assert.NotNull(metadonnees);
|
|
Assert.True(metadonnees.AjouteUnJeton);
|
|
Assert.Equal(">>fra<<", metadonnees.JetonCible);
|
|
Assert.Equal("Helsinki-NLP/opus-mt-tc-big-itc-itc", metadonnees.ModeleSource);
|
|
Assert.Equal("itc", metadonnees.Famille);
|
|
Assert.Equal(1, metadonnees.Version);
|
|
}
|
|
|
|
[Fact]
|
|
public void DepuisJson_SansJeton_EstUnModeleDedie()
|
|
{
|
|
string json = """{ "modeleSource": "Helsinki-NLP/opus-mt-es-fr" }""";
|
|
|
|
ModelePackMetadonnees? metadonnees = ModelePackMetadonnees.DepuisJson(json);
|
|
|
|
Assert.NotNull(metadonnees);
|
|
Assert.False(metadonnees.AjouteUnJeton);
|
|
Assert.Equal(string.Empty, metadonnees.JetonCible);
|
|
}
|
|
|
|
[Fact]
|
|
public void DepuisJson_VersionAbsente_VautUn()
|
|
{
|
|
ModelePackMetadonnees? metadonnees = ModelePackMetadonnees.DepuisJson("""{ "jetonCible": ">>fra<<" }""");
|
|
|
|
Assert.NotNull(metadonnees);
|
|
Assert.Equal(1, metadonnees.Version);
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(null)]
|
|
[InlineData("")]
|
|
[InlineData(" ")]
|
|
public void DepuisJson_ContenuVide_EstTraiteCommeAbsent(string? json)
|
|
{
|
|
Assert.Null(ModelePackMetadonnees.DepuisJson(json));
|
|
}
|
|
|
|
[Fact]
|
|
public void DepuisJson_JetonEntoureDEspaces_EstNettoye()
|
|
{
|
|
ModelePackMetadonnees? metadonnees = ModelePackMetadonnees.DepuisJson("""{ "jetonCible": " >>fra<< " }""");
|
|
|
|
Assert.NotNull(metadonnees);
|
|
Assert.Equal(">>fra<<", metadonnees.JetonCible);
|
|
}
|
|
|
|
[Fact]
|
|
public void DepuisJson_JetonAvecEspaceInterne_EstRefuse()
|
|
{
|
|
// Un jeton contenant un espace serait découpé par le tokeniseur : le modèle
|
|
// ne le reconnaîtrait pas et produirait sa langue par défaut, sans erreur.
|
|
FormatException ex = Assert.Throws<FormatException>(
|
|
() => ModelePackMetadonnees.DepuisJson("""{ "jetonCible": ">>fra<< x" }"""));
|
|
|
|
Assert.Contains("espace", ex.Message, StringComparison.OrdinalIgnoreCase);
|
|
}
|
|
|
|
[Fact]
|
|
public void DepuisJson_JetonTropLong_EstRefuse()
|
|
{
|
|
string jeton = ">>" + new string('a', ModelePackMetadonnees.LongueurMaxJeton) + "<<";
|
|
|
|
FormatException ex = Assert.Throws<FormatException>(
|
|
() => ModelePackMetadonnees.DepuisJson($$"""{ "jetonCible": "{{jeton}}" }"""));
|
|
|
|
Assert.Contains("trop long", ex.Message, StringComparison.OrdinalIgnoreCase);
|
|
}
|
|
|
|
[Fact]
|
|
public void DepuisJson_VersionFuture_EstRefusee()
|
|
{
|
|
// Une version inconnue peut changer le SENS du champ : la lire à l'aveugle
|
|
// reviendrait à deviner.
|
|
FormatException ex = Assert.Throws<FormatException>(
|
|
() => ModelePackMetadonnees.DepuisJson("""{ "version": 99, "jetonCible": ">>fra<<" }"""));
|
|
|
|
Assert.Contains("version", ex.Message, StringComparison.OrdinalIgnoreCase);
|
|
}
|
|
|
|
[Fact]
|
|
public void DepuisJson_JsonInvalide_EstRefuse()
|
|
{
|
|
Assert.Throws<FormatException>(() => ModelePackMetadonnees.DepuisJson("{ pas du json"));
|
|
}
|
|
|
|
[Fact]
|
|
public void DepuisJson_ProprieteInconnue_EstIgnoree()
|
|
{
|
|
// Compatibilité ascendante : un pack plus récent peut ajouter des champs.
|
|
ModelePackMetadonnees? metadonnees = ModelePackMetadonnees.DepuisJson(
|
|
"""{ "jetonCible": ">>fra<<", "champFutur": 42 }""");
|
|
|
|
Assert.NotNull(metadonnees);
|
|
Assert.Equal(">>fra<<", metadonnees.JetonCible);
|
|
}
|
|
|
|
[Fact]
|
|
public void InsererJetonCible_AvecIdentifiant_LePlaceEnTete()
|
|
{
|
|
// Valeurs réelles d'opus-mt-tc-big-itc-itc : >>fra<< = 14666, et la suite
|
|
// d'identifiants du modèle (jamais ceux du .spm).
|
|
IReadOnlyList<int> ids = OnnxTranslationService.InsererJetonCible([6636, 5, 7228], 14666);
|
|
|
|
Assert.Equal([14666, 6636, 5, 7228], ids);
|
|
}
|
|
|
|
[Fact]
|
|
public void InsererJetonCible_SansIdentifiant_RendLaSequenceTelleQuelle()
|
|
{
|
|
IReadOnlyList<int> ids = OnnxTranslationService.InsererJetonCible([6636, 5], -1);
|
|
|
|
Assert.Equal([6636, 5], ids);
|
|
}
|
|
|
|
[Fact]
|
|
public void InsererJetonCible_NeModifiePasLaSequenceDOrigine()
|
|
{
|
|
int[] origine = [6636, 5];
|
|
IReadOnlyList<int> resultat = OnnxTranslationService.InsererJetonCible(origine, 14666);
|
|
|
|
Assert.Equal([6636, 5], origine);
|
|
Assert.NotSame(origine, resultat);
|
|
}
|
|
}
|