Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add asBoolean|Byte|Short|Int|Long|Float|Double to String assertions #2580

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,23 @@

import static java.lang.String.format;
import static java.util.Objects.requireNonNull;
import static org.assertj.core.error.ShouldBeNumeric.shouldBeNumeric;

import java.util.Base64;
import java.util.Comparator;

import org.assertj.core.error.ShouldBeNumeric;
import org.assertj.core.internal.Comparables;
import org.assertj.core.internal.ComparatorBasedComparisonStrategy;
import org.assertj.core.internal.Failures;
import org.assertj.core.util.CheckReturnValue;
import org.assertj.core.util.VisibleForTesting;

public class AbstractStringAssert<SELF extends AbstractStringAssert<SELF>> extends AbstractCharSequenceAssert<SELF, String> {

@VisibleForTesting
Failures failures = Failures.instance();

protected AbstractStringAssert(String actual, Class<?> selfType) {
super(actual, selfType);
}
Expand Down Expand Up @@ -402,4 +408,196 @@ public SELF isEqualTo(String expectedStringTemplate, Object... args) {
public SELF isEqualTo(String expected) {
return super.isEqualTo(expected);
}

/**
* Parses the actual value as boolean, the parsed boolean becoming the new value under test.
* <p>
* Note that only when the string is equal to the string "true", ignoring case, and can have leading and trailing space, the parsed value will be {@code true}.
* Otherwise, the value will be {@code false}.
* <p>
* Examples:
* <pre><code class='java'>
* assertThat(&quot;truE&quot;).asBoolean().isTrue();
* assertThat(&quot;false&quot;).asBoolean().isFalse();
* assertThat(&quot;foo bar&quot;).asBoolean().isFalse();
* assertThat((String) null).asBoolean().isFalse();
* </code></pre>
*
* @return a new {@link BooleanAssert} instance whose value under test is the result of the parse.
*
* @since 3.25.0
*/
public AbstractBooleanAssert<?> asBoolean() {
return InstanceOfAssertFactories.BOOLEAN
.createAssert(Boolean.parseBoolean(actual))
.withAssertionState(myself);
}

/**
* Parses the actual value as byte, using radix 10, the parsed byte becoming the new value under test.
* <p>
* Examples:
* <pre><code class='java'>
* // assertion succeeds
* assertThat(&quot;127&quot;).asByte().isEqualTo((byte) 127);
*
* // assertion fails as the actual value is null or not a valid byte
* assertThat((String) null).asByte();
* assertThat(&quot;1L&quot;).asByte();
* </code></pre>
*
* @return a new {@link ByteAssert} instance whose value under test is the result of the parse.
* @throws AssertionError if the actual value is null or not a valid byte.
*
* @since 3.25.0
*/
public AbstractByteAssert<?> asByte() {
try {
return InstanceOfAssertFactories.BYTE
.createAssert(Byte.parseByte(actual))
.withAssertionState(myself);
} catch (NumberFormatException e) {
throw failures.failure(info, shouldBeNumeric(actual, ShouldBeNumeric.NumericType.BYTE));
}
}

/**
* Parses the actual value as short, using radix 10, the parsed short becoming the new value under test.
* <p>
* Examples:
* <pre><code class='java'>
* // assertion succeeds
* assertThat(&quot;32767&quot;).asShort().isEqualTo((short) 32767);
*
* // assertion fails as the actual value is null or not a valid short
* assertThat((String) null).asShort();
* assertThat(&quot;-32769&quot;).asShort();
* </code></pre>
*
* @return a new {@link ShortAssert} instance whose value under test is the result of the parse.
* @throws AssertionError if the actual value is null or not a valid short.
*
* @since 3.25.0
*/
public AbstractShortAssert<?> asShort() {
try {
return InstanceOfAssertFactories.SHORT
.createAssert(Short.parseShort(actual))
.withAssertionState(myself);
} catch (NumberFormatException e) {
throw failures.failure(info, shouldBeNumeric(actual, ShouldBeNumeric.NumericType.SHORT));
}
}

/**
* Parses the actual value as integer, using radix 10, the parsed integer becoming the new value under test.
* <p>
* Examples:
* <pre><code class='java'>
* // assertion succeeds
* assertThat(&quot;2147483647&quot;).asInt().isEqualTo(2147483647);
*
* // assertion fails as the actual value is null or not a valid int
* assertThat((String) null).asInt();
* assertThat(&quot;1e100&quot;).asInt();
* </code></pre>
*
* @return a new {@link IntegerAssert} instance whose value under test is the result of the parse.
* @throws AssertionError if the actual value is null or not a valid int.
*
* @since 3.25.0
*/
public AbstractIntegerAssert<?> asInt() {
try {
return InstanceOfAssertFactories.INTEGER
.createAssert(Integer.parseInt(actual))
.withAssertionState(myself);
} catch (NumberFormatException e) {
throw failures.failure(info, shouldBeNumeric(actual, ShouldBeNumeric.NumericType.INTEGER));
}
}

/**
* Parses the actual value as long, using radix 10, the parsed long becoming the new value under test.
* <p>
* Examples:
* <pre><code class='java'>
* // assertion succeeds
* assertThat(&quot;1&quot;).asLong().isEqualTo(1L);
*
* // assertion fails as the actual value is null or not a long
* assertThat((String) null).asLong();
* assertThat(&quot;1e100&quot;).asLong();
* </code></pre>
*
* @return a new {@link LongAssert} instance whose value under test is the result of the parse.
* @throws AssertionError if the actual value is null or not a valid long.
*
* @since 3.25.0
*/
public AbstractLongAssert<?> asLong() {
try {
return InstanceOfAssertFactories.LONG
.createAssert(Long.parseLong(actual))
.withAssertionState(myself);
} catch (NumberFormatException e) {
throw failures.failure(info, shouldBeNumeric(actual, ShouldBeNumeric.NumericType.LONG));
}
}

/**
* Parses the actual value as float, the parsed float becoming the new value under test.
* <p>
* Examples:
* <pre><code class='java'>
* // assertion succeeds
* assertThat(&quot;1.2f&quot;).asFloat().isCloseTo(1.2f, Percentage.withPercentage(0.01));
*
* // assertion fails as the actual value is null or not a float
* assertThat((String) null).asFloat();
* assertThat(&quot;foo&quot;).asFloat();
* </code></pre>
*
* @return a new {@link FloatAssert} instance whose value under test is the result of the parse.
* @throws AssertionError if the actual value is null or not a parseable float.
*
* @since 3.25.0
*/
public AbstractFloatAssert<?> asFloat() {
try {
return InstanceOfAssertFactories.FLOAT
.createAssert(Float.parseFloat(actual))
.withAssertionState(myself);
} catch (NumberFormatException | NullPointerException e) {
throw failures.failure(info, shouldBeNumeric(actual, ShouldBeNumeric.NumericType.FLOAT));
}
}

/**
* Parses the actual value as double, the parsed double becoming the new value under test.
* <p>
* Examples:
* <pre><code class='java'>
* // assertion succeeds
* assertThat(&quot;1.2e308&quot;).asDouble().isCloseTo(1.2e308, Percentage.withPercentage(0.001));
*
* // assertion fails as the actual value is null or not a double
* assertThat((String) null).asDouble();
* assertThat(&quot;foo&quot;).asDouble();
* </code></pre>
*
* @return a new {@link DoubleAssert} instance whose value under test is the result of the parse.
* @throws AssertionError if the actual value is null or not a parseable double.
*
* @since 3.25.0
*/
public AbstractDoubleAssert<?> asDouble() {
try {
return InstanceOfAssertFactories.DOUBLE
.createAssert(Double.parseDouble(actual))
.withAssertionState(myself);
} catch (NumberFormatException | NullPointerException e) {
throw failures.failure(info, shouldBeNumeric(actual, ShouldBeNumeric.NumericType.DOUBLE));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* Copyright 2012-2023 the original author or authors.
*/
package org.assertj.core.error;

import java.util.Objects;

/**
* Creates an error message that indicates an assertion that cast string
* to a number (byte, short, integer, long, float or double) failed.
*
* @author hezean
*/
public class ShouldBeNumeric extends BasicErrorMessageFactory {

public enum NumericType {
BYTE("byte"),
SHORT("short"),
INTEGER("int"),
LONG("long"),
FLOAT("float"),
DOUBLE("double"),
;

private final String typeName;

NumericType(String typeName) {
this.typeName = typeName;
}

@Override
public String toString() {
return typeName;
}
}

/**
* Creates a new <code>{@link ShouldBeNumeric}</code>.
* @param actual the actual value in the failed assertion.
* @param type the type expected to cast.
* @return the created {@code ErrorMessageFactory}.
*/
public static ErrorMessageFactory shouldBeNumeric(String actual, NumericType type) {
return new ShouldBeNumeric(actual, type);
}

private ShouldBeNumeric(String actual, NumericType type) {
super("%nExpecting %s to be a valid %s", actual, type);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* Copyright 2012-2023 the original author or authors.
*/
package org.assertj.core.api.string_;

import static org.assertj.core.api.BDDAssertions.then;

import org.assertj.core.api.StringAssert;
import org.assertj.core.api.StringAssertBaseTest;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.NullSource;
import org.junit.jupiter.params.provider.ValueSource;

/**
* Tests for <code>{@link StringAssert#asBoolean()}</code>.
*
* @author hezean
*/
class StringAssert_asBoolean_Test extends StringAssertBaseTest {

@Override
protected StringAssert invoke_api_method() {
assertions.asBoolean();
return null;
}

@Override
protected void verify_internal_effects() {
// Verify disabled as the asBoolean cast have no internal effect.
}

@Override
public void should_return_this() {
// Test disabled as the assertion does not return this.
}

@ParameterizedTest
@ValueSource(strings = { "true", "TruE" })
void should_parse_string_as_true_for_true_like_string(String string) {
// THEN
then(string).asBoolean().isTrue();
}

@ParameterizedTest
@NullSource
@ValueSource(strings = { " false", "foo bar" })
void should_parse_string_as_false_otherwise(String string) {
// THEN
then(string).asBoolean().isFalse();
}
}