JustDummies

Juste des dummies, mais redoutablement efficaces.

Sections de la documentation

JD031 : PairedBoundsHaveARangeForm

PropriétéValeur
CatégorieConstraints (JustDummies.Constraints)
Sévérité🔵 Info
Activée par défautOui

Une chaîne déclare séparément les deux bornes inclusives d’un intervalle, alors que le même générateur nomme cet intervalle en un seul appel.

Rien n’est faux ici, et rien n’a besoin de changer. Les deux écritures se comportent à l’identique — la méthode d’intervalle est les deux bornes — et les déclarer séparément est décomposable exprès, pour qu’un helper partagé pose un plancher et qu’un site d’appel ajoute un plafond. Cette règle existe pour une seule raison : la forme intervalle est facile à manquer, et un lecteur qui écrit les bornes séparément n’apprend jamais qu’elle existe. Elle le dit là où vous pouvez agir (ADR-0077 ouvre un nouvel onglet).

Non conforme

string reference = Any.String().WithMinLength(8).WithMaxLength(20).Generate();
int    quantity  = Any.Int32().GreaterThanOrEqualTo(1).LessThanOrEqualTo(50).Generate();

Conforme

string reference = Any.String().WithLengthBetween(8, 20).Generate();
int    quantity  = Any.Int32().Between(1, 50).Generate();

Au-delà d’être plus courte, la forme intervalle se lit plus près de la façon dont la règle s’énonce à voix haute — « entre 8 et 20 caractères », et non « au moins 8, au plus 20 » — et elle porte une chose que la paire n’a pas : elle enregistre une seule contrainte, si bien qu’un conflit levé plus tard contre elle nomme l’intervalle que vous avez écrit plutôt qu’une de ses moitiés.

Les quatre vocabulaires

paire déclaréesignalée commegénérateurs
WithMinLength(a) + WithMaxLength(b)WithLengthBetween(a, b)AnyString
WithMinCount(a) + WithMaxCount(b)WithCountBetween(a, b)tous les générateurs de collections
GreaterThanOrEqualTo(a) + LessThanOrEqualTo(b)Between(a, b)les générateurs numériques et TimeSpan
AfterOrEqualTo(a) + BeforeOrEqualTo(b)Between(a, b)AnyDateOnly, AnyDateTime, AnyDateTimeOffset, AnyTimeOnly

L’appel signalé est toujours (minimum, maximum), quel que soit l’ordre dans lequel vous avez écrit les bornes ; le diagnostic se pose sur celle que vous avez écrite en premier.

Bornes inclusives uniquement — pourquoi la paire stricte est muette

Between est inclusive des deux côtés. GreaterThan / LessThan et After / Before sont strictes : ce ne sont donc pas la même contrainte, et elles n’ont pas de forme intervalle exacte :

int quantity = Any.Int32().GreaterThan(5).LessThan(10).Generate();      // muet : c'est Between(6, 9)
double ratio = Any.Double().GreaterThan(1.5).LessThan(9.5).Generate();  // muet : aucune forme Between n'existe

Sur un type entier l’intervalle existe, mais ses nombres ne sont pas ceux que vous avez écrits, et le signaler reviendrait à vous faire lire des bornes que vous n’avez jamais choisies. Sur un type flottant il n’y a pas de valeur suivante, donc aucune forme intervalle à nommer. Les paires mixtes — GreaterThan(a).LessThanOrEqualTo(b), After(a).BeforeOrEqualTo(b) — sont muettes pour la même raison. Inclusive plus inclusive uniquement. Toute autre combinaison est muette.

Ce qu’elle ne signale pas non plus

  • Des bornes qui ne sont pas dans la même chaîne. Les déclarer séparément est une fonctionnalité : un helper pose un plancher, un site d’appel ajoute un plafond. Seule une même chaîne fluente est appariée — jamais un générateur qui passe par une variable locale, un champ, un paramètre ou deux instructions.
  • Une borne déclarée deux fois. WithMinLength(8).WithMinLength(10).WithMaxLength(20) ne garde que le minimum le plus serré, donc WithLengthBetween(8, 20) serait plus large que ce que la chaîne tire. L’appariement est refusé plutôt que deviné.
  • Une borne atteinte par un alias. NonEmpty() est une longueur minimale de un et Positive() un minimum de un, donc Any.String().NonEmpty().WithMaxLength(20) déclare bien les deux bornes — et reste muette. Choisir l’alias dit sur l’intention quelque chose que la borne explicite ne dit pas.
  • Une taille exacte à côté de la paire. Une chaîne qui déclare aussi WithLength ou WithCount ne regarde pas cette règle.
  • Une chaîne déjà écrite comme un intervalle.

Pourquoi elle ne propose jamais WithLength ni WithCount

Une paire de bornes égales est signalée comme WithLengthBetween(8, 8), jamais comme WithLength(8). Ce n’est pas la même chose : WithLength fixe la longueur sans tirer, là où un minimum et un maximum de huit tirent tout de même sur un intervalle d’une seule valeur et consomment un tirage pour le faire. Sur un run amorcé, les deux écritures divergent à partir de ce point, et une graine rejouable est une garantie que cette bibliothèque n’échange pas contre une ligne plus courte (ADR-0049 ouvre un nouvel onglet). Toute forme que cette règle nomme est équivalente par construction — la méthode d’intervalle est implémentée comme les deux bornes qu’elle remplace — et c’est la condition qui la borne.

Pourquoi c’est une information, pas un avertissement

La forme à deux bornes est correcte et bénie par la documentation de la bibliothèque elle-même, qui énonce que l’intervalle et la paire se comportent à l’identique et que c’est précisément ce qui garde un intervalle décomposable. La promouvoir en avertissement dresserait les analyzers contre la documentation de l’API. Elle énonce un fait à peser, jamais un verdict — la même posture que JD024, JD029 et JD030. Là où vous avez écrit la paire exprès, faites-la taire sur place avec un [SuppressMessage] nommant JustDummiesRule.JD031 — voir JustDummies.DiagnosticCatalog.

Lire la source, ou la corriger là-bas ouvre un nouvel onglet· Repris depuis lib-v1.0.0-preview.6