|
62 | 62 | import java.util.List; |
63 | 63 | import java.util.Map; |
64 | 64 | import java.util.Objects; |
| 65 | +import java.util.Optional; |
65 | 66 | import java.util.Set; |
| 67 | +import java.util.TreeSet; |
66 | 68 | import java.util.concurrent.ThreadLocalRandom; |
67 | 69 | import java.util.function.Function; |
68 | 70 | import java.util.function.Supplier; |
@@ -431,7 +433,10 @@ private Map<String, Object> generateRow() |
431 | 433 | final Map<String, Object> newRow = new CaseInsensitiveHashMap<>(); |
432 | 434 | for (String columnName : _columns.keySet()) |
433 | 435 | { |
434 | | - _dataSuppliers.computeIfAbsent(columnName, k -> getDefaultDataSupplier(_columns.get(k))); |
| 436 | + if (!_dataSuppliers.containsKey(columnName)) |
| 437 | + { |
| 438 | + _dataSuppliers.put(columnName, getDefaultDataSupplier(_columns.get(columnName))); |
| 439 | + } |
435 | 440 |
|
436 | 441 | if (_autoGeneratedFields.contains(columnName)) |
437 | 442 | { |
@@ -622,22 +627,78 @@ public static String randomDomainName(@Nullable String namePart, @Nullable Integ |
622 | 627 | namePart = namePart == null ? "" : namePart; |
623 | 628 | DomainKind _domainKind = domainKind == null ? DomainKind.SampleSet : domainKind; |
624 | 629 | String charSet = ALPHANUMERIC_STRING + DOMAIN_SPECIAL_STRING; |
| 630 | + // Excluded characters for generation, spaces excluded for correct insertSpaces work |
| 631 | + String exclusion = " "; |
625 | 632 | int currentTries = 0; |
626 | | - RandomName randomName = randomName(namePart, getNumChars(numStartChars, 5), getNumChars(numEndChars, 50), charSet, null); |
| 633 | + RandomName randomName = randomName(namePart, getNumChars(numStartChars, 5), getNumChars(numEndChars, 50), charSet, exclusion); |
627 | 634 | while (isDomainAndFieldNameInvalid(_domainKind, randomName, null)) |
628 | 635 | { |
629 | | - randomName = randomName(namePart, getNumChars(numStartChars, 5), getNumChars(numEndChars, 50), charSet, null); |
| 636 | + randomName = randomName(namePart, getNumChars(numStartChars, 5), getNumChars(numEndChars, 50), charSet, exclusion); |
630 | 637 | if (++currentTries >= MAX_RANDOM_TRIES) |
631 | 638 | throw new IllegalStateException("Failed to generate a valid domain name after " + MAX_RANDOM_TRIES + " tries. Last generated name: " + randomName); |
632 | 639 | } |
633 | 640 |
|
634 | | - // Multiple spaces in the UI are collapsed into a single space. If we need to test for handling of multiple spaces, we'll not use this generator |
635 | | - String domainName = randomName.name().replaceAll("\\s+", " "); |
| 641 | + // Insert spaces every 8 chars (skipped for short names) and always one immediately before and after namePart. |
| 642 | + String domainName = insertSpaces(randomName.name(), namePart); |
636 | 643 |
|
637 | 644 | TestLogger.log("Generated random domain name for domainKind " + _domainKind + ": " + domainName); |
638 | 645 | return domainName; |
639 | 646 | } |
640 | 647 |
|
| 648 | + /** |
| 649 | + * Insert single spaces around {@code namePart} and at every 8th char (when {@code base.length() > 6}), |
| 650 | + * snapping inside-namePart positions to the nearest boundary. Skips any insertion that would land at |
| 651 | + * an edge, create a double space, or form a "space-dash-non-space" pattern. |
| 652 | + */ |
| 653 | + private static String insertSpaces(String base, String namePart) |
| 654 | + { |
| 655 | + int npStart = namePart.isEmpty() ? -1 : base.indexOf(namePart); |
| 656 | + int npEnd = npStart < 0 ? -1 : npStart + namePart.length(); |
| 657 | + |
| 658 | + // Indices in base before which a single space will be inserted. TreeSet auto-sorts and dedupes. |
| 659 | + Set<Integer> positions = new TreeSet<>(); |
| 660 | + |
| 661 | + // Mandatory: immediately before and after namePart. |
| 662 | + addIfSafe(positions, base, npStart); |
| 663 | + addIfSafe(positions, base, npEnd); |
| 664 | + |
| 665 | + // Every-8-chars step; positions strictly inside namePart snap to the nearest boundary. |
| 666 | + if (base.length() > 6) |
| 667 | + { |
| 668 | + for (int p = 8; p < base.length(); p += 8) |
| 669 | + { |
| 670 | + int snapped = p; |
| 671 | + if (npStart >= 0 && p > npStart && p < npEnd) |
| 672 | + snapped = (npEnd - p) <= (p - npStart) ? npEnd : npStart; |
| 673 | + addIfSafe(positions, base, snapped); |
| 674 | + } |
| 675 | + } |
| 676 | + |
| 677 | + // Drop positions that would form " -X" (space, dash, non-space). A dash followed by another |
| 678 | + // inserted space — or by end of string — is fine. |
| 679 | + positions.removeIf(p -> base.charAt(p) == '-' |
| 680 | + && p + 1 < base.length() |
| 681 | + && !positions.contains(p + 1) |
| 682 | + && base.charAt(p + 1) != ' '); |
| 683 | + |
| 684 | + StringBuilder sb = new StringBuilder(base.length() + positions.size()); |
| 685 | + for (int i = 0; i < base.length(); i++) |
| 686 | + { |
| 687 | + if (positions.contains(i)) |
| 688 | + sb.append(' '); |
| 689 | + sb.append(base.charAt(i)); |
| 690 | + } |
| 691 | + return sb.toString(); |
| 692 | + } |
| 693 | + |
| 694 | + /** Add {@code p} to {@code positions} only if inserting a space at {@code p} won't be at an edge of |
| 695 | + * {@code base} or sit next to an already-existing space (which would form a double space). */ |
| 696 | + private static void addIfSafe(Set<Integer> positions, String base, int p) |
| 697 | + { |
| 698 | + if (p > 0 && p < base.length() && base.charAt(p - 1) != ' ' && base.charAt(p) != ' ') |
| 699 | + positions.add(p); |
| 700 | + } |
| 701 | + |
641 | 702 | private static int getNumChars(Integer val, int max) |
642 | 703 | { |
643 | 704 | return val != null ? val : randomInt(0, max); |
|
0 commit comments