fix: update equipment size matching pattern recognition and add integration tests
AS Talange CI/CD Pipeline / Build & Run Unit Tests (push) Successful in 4m14s
AS Talange CI/CD Pipeline / Deploy to Test Environment (push) Successful in 6m9s

- Prevent false positive regex matches by enforcing strict digit boundaries in Dotation.isSizeMatch
- Fix issue where 11/12ANS (Taille 152cm) mapped to 5/6ANS (Taille 116cm) due to 'Taille 1' tag matching '116cm'
- Add comprehensive integration test (DotationIntegrationTest) covering all Junior/Adult sizes, shoe sizes, and format variations
This commit is contained in:
2026-07-30 10:12:21 +02:00
parent da0443f655
commit df217bc923
3 changed files with 334 additions and 50 deletions
@@ -73,69 +73,83 @@ public class Dotation {
if (opt.equalsIgnoreCase(adh)) return true;
String optLower = opt.toLowerCase();
String adhLower = adh.toLowerCase();
String optNorm = opt.toLowerCase().replaceAll("\\s+", " ");
String adhNorm = adh.toLowerCase().replaceAll("\\s+", " ");
// Extract height numbers (116, 128, 140, 152, 164)
java.util.regex.Pattern numPattern = java.util.regex.Pattern.compile("\\b(116|128|140|152|164)\\b");
java.util.regex.Matcher adhNumMatcher = numPattern.matcher(adhLower);
java.util.regex.Matcher optNumMatcher = numPattern.matcher(optLower);
if (adhNumMatcher.find()) {
String num = adhNumMatcher.group(1);
if (optLower.contains(num)) {
return true;
}
} else if (optNumMatcher.find()) {
String num = optNumMatcher.group(1);
if (adhLower.contains(num)) {
return true;
}
}
if (optNorm.equals(adhNorm)) return true;
// Extract age patterns (5/6, 7/8, 9/10, 11/12, 13/14) or (5-6, 7-8, 9-10, 11-12, 13-14)
java.util.regex.Pattern agePattern = java.util.regex.Pattern.compile("\\b(5[/\\-]6|7[/\\-]8|9[/\\-]10|11[/\\-]12|13[/\\-]14)\\b");
java.util.regex.Matcher adhAge = agePattern.matcher(adhLower);
if (adhAge.find()) {
String ageKey = adhAge.group(1).replace("-", "/");
// 1. Age bracket matching: 5/6, 7/8, 9/10, 11/12, 13/14, 15/16
java.util.regex.Pattern agePattern = java.util.regex.Pattern.compile("(?<!\\d)(5[/\\-]6|7[/\\-]8|9[/\\-]10|11[/\\-]12|13[/\\-]14|15[/\\-]16)(?!\\d)");
java.util.regex.Matcher adhAgeMatcher = agePattern.matcher(adhNorm);
java.util.regex.Matcher optAgeMatcher = agePattern.matcher(optNorm);
boolean adhHasAge = adhAgeMatcher.find();
boolean optHasAge = optAgeMatcher.find();
if (adhHasAge && optHasAge) {
String adhAgeKey = adhAgeMatcher.group(1).replace("-", "/");
String optAgeKey = optAgeMatcher.group(1).replace("-", "/");
return adhAgeKey.equals(optAgeKey);
} else if (adhHasAge) {
String ageKey = adhAgeMatcher.group(1).replace("-", "/");
String altAgeKey = ageKey.replace("/", "-");
if (optLower.contains(ageKey) || optLower.contains(altAgeKey)) {
if (optNorm.contains(ageKey) || optNorm.contains(altAgeKey)) {
return true;
}
}
// Extract shoe sizes / pointures (27/30, 31/34, 35/38, 39/42, 43/46)
java.util.regex.Pattern ptPattern = java.util.regex.Pattern.compile("\\b(27[/\\-]30|31[/\\-]34|35[/\\-]38|39[/\\-]42|43[/\\-]46)\\b");
java.util.regex.Matcher adhPt = ptPattern.matcher(adhLower);
if (adhPt.find()) {
String ptKey = adhPt.group(1).replace("-", "/");
String altPtKey = ptKey.replace("/", "-");
if (optLower.contains(ptKey) || optLower.contains(altPtKey)) {
return true;
}
// 2. Height matching (3-digit numbers in cm, e.g. 115, 116, 126, 128, 138, 140, 150, 152, 162, 164, 176)
java.util.regex.Pattern heightPattern = java.util.regex.Pattern.compile("(?<!\\d)(115|116|126|128|138|140|150|152|162|164|176)(?!\\d)");
java.util.regex.Matcher adhHeightMatcher = heightPattern.matcher(adhNorm);
java.util.regex.Matcher optHeightMatcher = heightPattern.matcher(optNorm);
boolean adhHasHeight = adhHeightMatcher.find();
boolean optHasHeight = optHeightMatcher.find();
if (adhHasHeight && optHasHeight) {
int adhH = Integer.parseInt(adhHeightMatcher.group(1));
int optH = Integer.parseInt(optHeightMatcher.group(1));
return Math.abs(adhH - optH) <= 5;
}
// Extract "Taille X"
java.util.regex.Pattern tNumPattern = java.util.regex.Pattern.compile("taille\\s*([0-4])");
java.util.regex.Matcher adhTNum = tNumPattern.matcher(adhLower);
if (adhTNum.find()) {
String tNum = adhTNum.group(1);
if (optLower.contains("taille " + tNum) || optLower.contains("taille" + tNum) || optLower.equals(tNum)) {
return true;
}
// 3. Shoe size / pointure matching: 27/30, 31/34, 35/38, 39/42, 43/46
java.util.regex.Pattern shoePattern = java.util.regex.Pattern.compile("(?<!\\d)(27[/\\-]30|31[/\\-]34|35[/\\-]38|39[/\\-]42|43[/\\-]46)(?!\\d)");
java.util.regex.Matcher adhShoeMatcher = shoePattern.matcher(adhNorm);
java.util.regex.Matcher optShoeMatcher = shoePattern.matcher(optNorm);
boolean adhHasShoe = adhShoeMatcher.find();
boolean optHasShoe = optShoeMatcher.find();
if (adhHasShoe && optHasShoe) {
String adhShoeKey = adhShoeMatcher.group(1).replace("-", "/");
String optShoeKey = optShoeMatcher.group(1).replace("-", "/");
return adhShoeKey.equals(optShoeKey);
}
// Standalone letter sizes (XXL, XL, L, M, S, XS)
java.util.regex.Pattern letterPattern = java.util.regex.Pattern.compile("\\b(xxl|xl|l|m|s|xs)\\b");
java.util.regex.Matcher adhLetter = letterPattern.matcher(adhLower);
java.util.regex.Matcher optLetter = letterPattern.matcher(optLower);
if (adhLetter.find() && optLetter.find()) {
if (adhLetter.group(1).equals(optLetter.group(1))) {
return true;
}
// 4. Sock size tag matching: "taille 0", "taille 1", "taille 2", "taille 3", "taille 4"
java.util.regex.Pattern tNumPattern = java.util.regex.Pattern.compile("(?<![a-z0-9])taille\\s*([0-4])(?![0-9])");
java.util.regex.Matcher adhTNumMatcher = tNumPattern.matcher(adhNorm);
java.util.regex.Matcher optTNumMatcher = tNumPattern.matcher(optNorm);
boolean adhHasTNum = adhTNumMatcher.find();
boolean optHasTNum = optTNumMatcher.find();
if (adhHasTNum && optHasTNum) {
return adhTNumMatcher.group(1).equals(optTNumMatcher.group(1));
}
if (opt.length() >= 2 && adhLower.contains(optLower)) return true;
if (adh.length() >= 2 && optLower.contains(adhLower)) return true;
// 5. Letter size matching: XXL, XL, L, M, S, XS
java.util.regex.Pattern letterPattern = java.util.regex.Pattern.compile("(?<![a-z0-9])(xxl|xl|l|m|s|xs)(?![a-z0-9])");
java.util.regex.Matcher adhLetterMatcher = letterPattern.matcher(adhNorm);
java.util.regex.Matcher optLetterMatcher = letterPattern.matcher(optNorm);
boolean adhHasLetter = adhLetterMatcher.find();
boolean optHasLetter = optLetterMatcher.find();
if (adhHasLetter && optHasLetter) {
return adhLetterMatcher.group(1).equals(optLetterMatcher.group(1));
}
// Substring fallback only if neither age, height, shoe, tag, nor letter pattern were present
if (!adhHasAge && !optHasAge && !adhHasHeight && !optHasHeight && !adhHasShoe && !optHasShoe && !adhHasTNum && !optHasTNum && !adhHasLetter && !optHasLetter) {
if (optNorm.length() >= 2 && adhNorm.contains(optNorm)) return true;
if (adhNorm.length() >= 2 && optNorm.contains(adhNorm)) return true;
}
return false;
}