Skip to content

Commit

Permalink
MutatesArgument Quality, closes 73 (#95)
Browse files Browse the repository at this point in the history
Provide a Quality of a non-pure Function that mutates its argument.
  • Loading branch information
dmfs authored Aug 20, 2023
1 parent b214bf2 commit 6964cdc
Show file tree
Hide file tree
Showing 4 changed files with 214 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package org.saynotobugs.confidence.quality.function;

import org.dmfs.jems2.Generator;
import org.dmfs.srcless.annotations.staticfactory.StaticFactories;
import org.saynotobugs.confidence.Assessment;
import org.saynotobugs.confidence.Description;
import org.saynotobugs.confidence.Quality;
import org.saynotobugs.confidence.assessment.AllPassed;
import org.saynotobugs.confidence.description.LiteralDescription;
import org.saynotobugs.confidence.description.Spaced;
import org.saynotobugs.confidence.description.Text;
import org.saynotobugs.confidence.description.Value;

import java.util.List;
import java.util.function.Consumer;
import java.util.function.Function;

/**
* {@link Quality} of a non-pure {@link Function} that mutates its argument when called.
* <h3>Examples</h3>
* <p>
* The following test ensures the function {@code list->list:add} adds an element to a given {@link List} and returns
* {@code true} when the list content has been changed.
* <pre>{@code
* assertThat(list -> list::add,
* mutatesArgument(
* ArrayList::new,
* soIt(iterates("a")),
* when(maps("a", to(true)))));
* }</pre>
* <p>
* A common use case is testing mutation of Constructor arguments of mutable classes.
* Consider a {@code ListAppender} {@link Consumer} that appends any value to the given list.
*
* <pre>{@code
* assertThat(list -> new ListAppender(list),
* mutatesArgument(
* ArrayList::new,
* soIt(iterates("a")),
* when(consumerThatAccepts("a"))));
* }</pre>
*/
@StaticFactories(value = "Core", packageName = "org.saynotobugs.confidence.quality")
public final class MutatesArgument<Argument, Type> implements Quality<Function<Argument, Type>>
{
private final Generator<? extends Argument> mArgumentGenerator;
private final Quality<? super Argument> mArgumentQuality;
private final Quality<? super Type> mDelegateQuality;


public MutatesArgument(
Generator<? extends Argument> argumentGenerator,
Quality<? super Argument> argumentQuality,
Quality<? super Type> delegateQuality)
{
mArgumentGenerator = argumentGenerator;
mArgumentQuality = argumentQuality;
mDelegateQuality = delegateQuality;
}


@Override
public Assessment assessmentOf(Function<Argument, Type> candidate)
{
Argument argument = mArgumentGenerator.next();
Assessment delegateAssessment = mDelegateQuality.assessmentOf(candidate.apply(argument));
return new AllPassed(
LiteralDescription.EMPTY,
LiteralDescription.SPACE,
mArgumentQuality.assessmentOf(argument),
delegateAssessment
);
}

@Override
public Description description()
{
return new Spaced(
new Text("mutates argument"),
new Value(mArgumentGenerator.next()),
mArgumentQuality.description(),
mDelegateQuality.description()
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* Copyright 2022 dmfs GmbH
*
*
* 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.
*
*/

package org.saynotobugs.confidence.quality.grammar;

import org.dmfs.srcless.annotations.staticfactory.StaticFactories;
import org.saynotobugs.confidence.Quality;
import org.saynotobugs.confidence.description.Spaced;
import org.saynotobugs.confidence.description.Text;
import org.saynotobugs.confidence.quality.composite.DescribedAs;
import org.saynotobugs.confidence.quality.composite.QualityComposition;


@StaticFactories(value = "Core", packageName = "org.saynotobugs.confidence.quality")
public final class When<T> extends QualityComposition<T>
{
public When(Quality<T> delegate)
{
super(new DescribedAs<>(d -> new Spaced(new Text("when"), d), d -> new Spaced(new Text("when"), d), delegate));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* Copyright 2023 dmfs GmbH
*
*
* 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.
*
*/

package org.saynotobugs.confidence.quality.function;

import org.junit.jupiter.api.Test;
import org.saynotobugs.confidence.quality.composite.AllOf;
import org.saynotobugs.confidence.quality.grammar.SoIt;
import org.saynotobugs.confidence.quality.grammar.To;
import org.saynotobugs.confidence.quality.grammar.When;
import org.saynotobugs.confidence.quality.iterable.Contains;
import org.saynotobugs.confidence.test.quality.Fails;
import org.saynotobugs.confidence.test.quality.HasDescription;
import org.saynotobugs.confidence.test.quality.Passes;

import java.util.ArrayList;

import static org.saynotobugs.confidence.Assertion.assertThat;

class MutatesArgumentTest
{
@Test
void test()
{
assertThat(new MutatesArgument<>(
ArrayList::new,
new SoIt<>(new Contains<>("a")),
new When<>(new Maps<>("a", new To<>(true)))),
new AllOf<>(
new Passes<>(list -> list::add),
new Fails<>(list -> list::remove, "but [ ] did not contain { \"a\" } when mapped \"a\" to <false>"),
new HasDescription("mutates argument [ ] so it contains { \"a\" } when maps \"a\" to <true>")
));
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* Copyright 2023 dmfs GmbH
*
*
* 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.
*
*/

package org.saynotobugs.confidence.quality.grammar;

import org.junit.jupiter.api.Test;
import org.saynotobugs.confidence.quality.composite.AllOf;
import org.saynotobugs.confidence.quality.object.EqualTo;
import org.saynotobugs.confidence.test.quality.Fails;
import org.saynotobugs.confidence.test.quality.HasDescription;
import org.saynotobugs.confidence.test.quality.Passes;

import static org.saynotobugs.confidence.Assertion.assertThat;

class WhenTest
{
@Test
void test()
{
assertThat(new When<>(new EqualTo<>("123")),
new AllOf<>(
new Passes<>("123"),
new Fails<>("1234", "when \"1234\""),
new HasDescription("when \"123\"")
));
}
}

0 comments on commit 6964cdc

Please sign in to comment.