Skip to content

Commit

Permalink
Normalize non-breaking spaces like regular white spaces (#3120)
Browse files Browse the repository at this point in the history
Non-breaking spaces are now considered white spaces
during white space normalization. This introduces a
difference compared to `Character::isWhitespace`.
  • Loading branch information
maximedezette committed Oct 11, 2023
1 parent 2ee04f4 commit 4ba4718
Show file tree
Hide file tree
Showing 7 changed files with 118 additions and 23 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1622,7 +1622,7 @@ public SELF isNotEqualToIgnoringWhitespace(CharSequence expected) {
* To be exact, the following rules are applied:
* <ul>
* <li>all leading and trailing whitespace of both actual and expected strings are ignored</li>
* <li>any remaining whitespace, appearing within either string, is collapsed to a single space before comparison</li>
* <li>any remaining whitespace (including non-breaking spaces), appearing within either string, is collapsed to a single space before comparison</li>
* </ul>
* <p>
* Example:
Expand All @@ -1634,6 +1634,7 @@ public SELF isNotEqualToIgnoringWhitespace(CharSequence expected) {
* .isEqualToNormalizingWhitespace(" Game of Thrones ")
* .isEqualToNormalizingWhitespace("Game of\tThrones")
* .isEqualToNormalizingWhitespace("Game of Thrones");
* .isEqualToNormalizingWhitespace("Game\u00A0of Thrones");
*
* // assertions will fail
* assertThat("Game of Thrones").isEqualToNormalizingWhitespace("Game ofThrones");
Expand All @@ -1657,7 +1658,7 @@ public SELF isEqualToNormalizingWhitespace(CharSequence expected) {
* To be exact, the following rules are applied:
* <ul>
* <li>all leading and trailing whitespace of both actual and expected strings are ignored</li>
* <li>any remaining whitespace, appearing within either string, is collapsed to a single space before comparison</li>
* <li>any remaining whitespace (including non-breaking spaces), appearing within either string, is collapsed to a single space before comparison</li>
* </ul>
* <p>
* Example:
Expand Down Expand Up @@ -1686,11 +1687,11 @@ public SELF isNotEqualToNormalizingWhitespace(CharSequence expected) {

/**
* Verifies that the actual {@code CharSequence} is equal to the given one, after the punctuation
* of both strings have been normalized.
* of both strings has been normalized.
* <p>
* To be exact, the following rules are applied:
* <ul>
* <li>All punctuation of actual and expected strings are ignored and whitespaces are normalized</li>
* <li>All punctuation of actual and expected strings are ignored and whitespaces (including non-breaking spaces) are normalized</li>
* <li>Punctuation is any of the following character <b>{@code !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~}</b></li>
* </ul>
* <p>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,10 @@
import java.io.StringReader;
import java.text.Normalizer;
import java.util.Base64;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
Expand All @@ -106,6 +108,16 @@
*/
public class Strings {

private static final Set<Character> NON_BREAKING_SPACES;

static {
Set<Character> nonBreakingSpaces = new HashSet<>();
nonBreakingSpaces.add('\u00A0');
nonBreakingSpaces.add('\u2007');
nonBreakingSpaces.add('\u202F');
NON_BREAKING_SPACES = Collections.unmodifiableSet(nonBreakingSpaces);
}

private static final String EMPTY_STRING = "";
private static final Strings INSTANCE = new Strings();
private static final String PUNCTUATION_REGEX = "\\p{Punct}";
Expand Down Expand Up @@ -385,7 +397,7 @@ private static String normalizeWhitespace(CharSequence toNormalize) {
boolean lastWasSpace = true;
for (int i = 0; i < toNormalize.length(); i++) {
char c = toNormalize.charAt(i);
if (isWhitespace(c)) {
if (isWhitespace(c) || NON_BREAKING_SPACES.contains(c)) {
if (!lastWasSpace) result.append(' ');
lastWasSpace = true;
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@

import org.assertj.core.internal.Strings;

import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

/**
* Base class for {@link CharSequenceAssert} tests.
*
Expand All @@ -25,6 +29,17 @@
public abstract class CharSequenceAssertBaseTest extends BaseTestTemplate<CharSequenceAssert, CharSequence> {
protected Strings strings;

protected static final Set<Character> NON_BREAKING_SPACES;

static {
Set<Character> nonBreakingSpaces = new HashSet<>();
nonBreakingSpaces.add('\u00A0');
nonBreakingSpaces.add('\u2007');
nonBreakingSpaces.add('\u202F');

NON_BREAKING_SPACES = Collections.unmodifiableSet(nonBreakingSpaces);
}

@Override
protected CharSequenceAssert create_assertions() {
return new CharSequenceAssert("Yoda");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,17 @@
*/
package org.assertj.core.api.charsequence;

import static org.mockito.Mockito.verify;

import org.assertj.core.api.CharSequenceAssert;
import org.assertj.core.api.CharSequenceAssertBaseTest;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;

import java.util.stream.Stream;

import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.params.provider.Arguments.arguments;
import static org.mockito.Mockito.verify;

/**
* Created by harisha talanki on 2/29/20
Expand All @@ -32,4 +39,16 @@ protected void verify_internal_effects() {
verify(strings).assertEqualsNormalizingPunctuationAndWhitespace(getInfo(assertions), getActual(assertions),
"Game of Thrones");
}

@ParameterizedTest
@MethodSource("notEqualToNormalizingWhiteSpaceGenerator")
void should_pass_if_actual_is_equal_normalizing_breaking_spaces(String actual, String expected) {
assertThat(actual).isEqualToNormalizingPunctuationAndWhitespace(expected);
}

public static Stream<Arguments> notEqualToNormalizingWhiteSpaceGenerator() {
return NON_BREAKING_SPACES.stream()
.map(nonBreakingSpace -> arguments("my" + nonBreakingSpace
+ "foo bar", "my foo bar"));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,19 @@
*/
package org.assertj.core.api.charsequence;

import static org.mockito.Mockito.verify;

import org.assertj.core.api.CharSequenceAssert;
import org.assertj.core.api.CharSequenceAssertBaseTest;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;

import java.util.stream.Stream;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.assertj.core.error.ShouldNotBeEqualNormalizingWhitespace.shouldNotBeEqualNormalizingWhitespace;
import static org.junit.jupiter.params.provider.Arguments.arguments;
import static org.mockito.Mockito.verify;

/**
* Tests for <code>{@link org.assertj.core.api.CharSequenceAssert#isNotEqualToNormalizingWhitespace(CharSequence)}</code>.
Expand All @@ -33,4 +42,19 @@ protected CharSequenceAssert invoke_api_method() {
protected void verify_internal_effects() {
verify(strings).assertNotEqualsNormalizingWhitespace(getInfo(assertions), getActual(assertions), " my foo bar ");
}

@ParameterizedTest
@MethodSource("notEqualToNormalizingWhiteSpaceGenerator")
void should_fail_if_actual_is_equal_normalizing_breaking_spaces(String actual, String expected) {
assertThatExceptionOfType(AssertionError.class)
.isThrownBy(() -> assertThat(actual).isNotEqualToNormalizingWhitespace(expected))
.withMessage(shouldNotBeEqualNormalizingWhitespace(actual,
expected).create());
}

public static Stream<Arguments> notEqualToNormalizingWhiteSpaceGenerator() {
return NON_BREAKING_SPACES.stream()
.map(nonBreakingSpace -> arguments("my" + nonBreakingSpace
+ "foo bar", "my foo bar"));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@
import static org.assertj.core.test.TestData.someInfo;
import static org.mockito.Mockito.spy;

import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

import org.assertj.core.api.AssertionInfo;
import org.assertj.core.test.CaseInsensitiveStringComparator;
import org.junit.jupiter.api.BeforeEach;
Expand All @@ -38,6 +42,17 @@ public class StringsBaseTest {
protected ComparatorBasedComparisonStrategy comparisonStrategy;
protected Strings stringsWithCaseInsensitiveComparisonStrategy;

protected static final Set<Character> NON_BREAKING_SPACES;

static {
Set<Character> nonBreakingSpaces = new HashSet<>();
nonBreakingSpaces.add('\u00A0');
nonBreakingSpaces.add('\u2007');
nonBreakingSpaces.add('\u202F');

NON_BREAKING_SPACES = Collections.unmodifiableSet(nonBreakingSpaces);
}

@BeforeEach
public void setUp() {
failures = spy(new Failures());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,14 @@
package org.assertj.core.internal.strings;

import static java.lang.String.format;
import static java.util.stream.Stream.concat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.assertj.core.api.Assertions.assertThatNullPointerException;
import static org.assertj.core.error.ShouldBeEqualNormalizingWhitespace.shouldBeEqualNormalizingWhitespace;
import static org.assertj.core.internal.ErrorMessages.charSequenceToLookForIsNull;
import static org.assertj.core.test.CharArrays.arrayOf;
import static org.assertj.core.test.TestData.someInfo;
import static org.junit.jupiter.params.provider.Arguments.arguments;

import java.util.stream.Stream;

Expand All @@ -29,8 +31,6 @@
import org.junit.jupiter.params.provider.MethodSource;

/**
* Tests for <code>{@link org.assertj.core.internal.Strings#assertEqualsNormalizingWhitespace(org.assertj.core.api.AssertionInfo, CharSequence, CharSequence)} </code>.
*
* @author Alex Ruiz
* @author Joel Costigliola
* @author Alexander Bischof
Expand Down Expand Up @@ -69,17 +69,26 @@ void should_pass_if_both_Strings_are_equal_after_whitespace_is_normalized(String
strings.assertEqualsNormalizingWhitespace(someInfo(), actual, expected);
}

public static Stream<Arguments> equalNormalizingWhitespaceGenerator() {
return Stream.of(Arguments.of("my foo bar", "my foo bar"),
Arguments.of(" my foo bar ", "my foo bar"),
Arguments.of(" my\tfoo bar ", " my foo bar"),
Arguments.of(" my foo bar ", "my foo bar"),
Arguments.of(" my foo bar ", " my foo bar "),
Arguments.of(" ", " "),
Arguments.of(" my\tfoo bar ", new String(arrayOf(' ', 'm', 'y', ' ', 'f', 'o', 'o', ' ', 'b', 'a', 'r'))),
Arguments.of(" my\tfoo bar ", " my\tfoo bar "), // same
Arguments.of(null, null), // null
Arguments.of(" \t \t", " "),
Arguments.of(" abc", "abc "));
static Stream<Arguments> equalNormalizingWhitespaceGenerator() {
Stream<Arguments> regularWhiteSpaces = Stream.of(arguments("my foo bar", "my foo bar"),
arguments(" my foo bar ", "my foo bar"),
arguments(" my\tfoo bar ", " my foo bar"),
arguments(" my foo bar ", "my foo bar"),
arguments(" my foo bar ", " my foo bar "),
arguments(" ", " "),
arguments(" my\tfoo bar ",
new String(arrayOf(' ', 'm', 'y', ' ', 'f', 'o', 'o', ' ', 'b',
'a', 'r'))),
arguments(" my\tfoo bar ", " my\tfoo bar "), // same
arguments(null, null), // null
arguments(" \t \t", " "),
arguments(" abc", "abc "));

Stream<Arguments> nonBreakingSpaces = NON_BREAKING_SPACES.stream()
.map(nonBreakingSpace -> arguments("my" + nonBreakingSpace
+ "foo bar", "my foo bar"));

return concat(regularWhiteSpaces, nonBreakingSpaces);
}

}

0 comments on commit 4ba4718

Please sign in to comment.