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

Added test project & github action to run tests #1

Open
wants to merge 13 commits into
base: release/0.5.0
Choose a base branch
from
57 changes: 57 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# The name of the workflow.
mrpmorris marked this conversation as resolved.
Show resolved Hide resolved
# This is the name that's displayed for status
# badges (commonly embedded in README.md files).
name: tests

# Trigger this workflow on a push, or pull request to
# the production branch, when either C# or project files changed
on:
push:
pull_request:
branches: [ main ]
paths-ignore:
- 'README.md'

# Create an environment variable named DOTNET_VERSION
# and set it as "6.0.x"
env:
DOTNET_VERSION: '6.0.x' # The .NET SDK version to use

# Defines a single job named "build-and-test"
jobs:
build-and-test:

# When the workflow runs, this is the name that is logged
# This job will run three times, once for each "os" defined
name: build-and-test-${{matrix.os}}
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest]

# Each job run contains these five steps
steps:
# 1) Check out the source code so that the workflow can access it.
- uses: actions/checkout@v2

# 2) Set up the .NET CLI environment for the workflow to use.
# The .NET version is specified by the environment variable.
- name: Setup .NET
uses: actions/setup-dotnet@v1
with:
dotnet-version: ${{ env.DOTNET_VERSION }}

# 3) Restore the dependencies and tools of a project or solution.
- name: Install dependencies
working-directory: ./Source
run: dotnet restore

# 4) Build a project or solution and all of its dependencies.
- name: Build
working-directory: ./Source
run: dotnet build --configuration Debug --no-restore

# 5) Test a project or solution.
- name: Test
working-directory: ./Source
run: dotnet test --no-restore --verbosity normal
28 changes: 28 additions & 0 deletions Source/Morris.Reducible.Tests/Morris.Reducible.Tests.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<Nullable>enable</Nullable>

<IsPackable>false</IsPackable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.11.0" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.extensibility.core" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="3.1.0">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Morris.Reducible\Morris.Reducible.csproj" />
</ItemGroup>

</Project>
67 changes: 67 additions & 0 deletions Source/Morris.Reducible.Tests/ReducerTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
using Xunit;

namespace Morris.Reducible.Tests
{
public class ReducerTests
{
private record CounterState(int Counter);
private record IncrementCounter(int Amount);


[Fact]
public void ReducerUpdatesStateWhenInvoked()
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Taking into account the filename is the Given, I like my test methods to be named WhenXxxxx_ThenYyyyyy

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated!

{
//Given
var initialState = new CounterState(0);
var action = new IncrementCounter(1);
var counterIncrementCounterReducer = Reducer
.Given<CounterState, IncrementCounter>()
.Then((state, delta) => (true, state with { Counter = state.Counter + delta.Amount}));

//When
(bool changed, var counterState) = counterIncrementCounterReducer.Invoke(initialState, action);
mrpmorris marked this conversation as resolved.
Show resolved Hide resolved
mrpmorris marked this conversation as resolved.
Show resolved Hide resolved

//Then
Assert.True(changed);
Assert.Equal(new CounterState(1), counterState);
}

[Fact]
public void ReducerUpdatesStateWhenInvokedWithPassingCondition()
{
//Given
var initialState = new CounterState(0);
var action = new IncrementCounter(1);
var counterIncrementCounterReducer = Reducer
.Given<CounterState, IncrementCounter>()
.When((state, delta) => state.Counter < 2)
.Then((state, delta) => state with { Counter = state.Counter + delta.Amount });

//When
(bool changed, var counterState) = counterIncrementCounterReducer.Invoke(initialState, action);

//Then
Assert.True(changed);
Assert.Equal(new CounterState(1), counterState);
}

[Fact]
public void ReducerDoesNotUpdateStateWhenInvokedWithFailingCondition()
{
//Given
var initialState = new CounterState(0);
var action = new IncrementCounter(1);
var counterIncrementCounterReducer = Reducer
.Given<CounterState, IncrementCounter>()
.When((state, delta) => state.Counter > 2)
.Then((state, delta) => state with { Counter = state.Counter + delta.Amount });

//When
(bool changed, var counterState) = counterIncrementCounterReducer.Invoke(initialState, action);

//Then
Assert.False(changed);
Assert.Equal(new CounterState(0), counterState);
}
}
}
6 changes: 6 additions & 0 deletions Source/Morris.Reducible.sln
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Docs", "Docs", "{047A19CC-B
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PolyMorphicReducers", "Tutorials\06-PolymorphicReducers\PolyMorphicReducers.csproj", "{7EFBF5C3-8A70-4E04-B5C1-75C3EA09A76D}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Morris.Reducible.Tests", "Morris.Reducible.Tests\Morris.Reducible.Tests.csproj", "{5522941C-7016-4634-8477-41B2274D1DBB}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -78,6 +80,10 @@ Global
{7EFBF5C3-8A70-4E04-B5C1-75C3EA09A76D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7EFBF5C3-8A70-4E04-B5C1-75C3EA09A76D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7EFBF5C3-8A70-4E04-B5C1-75C3EA09A76D}.Release|Any CPU.Build.0 = Release|Any CPU
{5522941C-7016-4634-8477-41B2274D1DBB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5522941C-7016-4634-8477-41B2274D1DBB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5522941C-7016-4634-8477-41B2274D1DBB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5522941C-7016-4634-8477-41B2274D1DBB}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
2 changes: 1 addition & 1 deletion Source/Morris.Reducible/Reducer.Builder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ namespace Morris.Reducible;

public static partial class Reducer
{
public static Builder<TState> New<TState>() => new Builder<TState>();
public static Builder<TState> New<TState>() => new();

public class Builder<TState>
{
Expand Down
14 changes: 5 additions & 9 deletions Source/Morris.Reducible/Reducer.ConditionBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ public class ConditionBuilder<TState, TDelta>
{
internal ConditionBuilder() { }

public ResultMapper<TState, TDelta> When(Func<TState, TDelta, bool> condition) => new ResultMapper<TState, TDelta>(condition);
public ResultMapper<TState, TDelta> When(Func<TState, TDelta, bool> condition) => new(condition);
mrpmorris marked this conversation as resolved.
Show resolved Hide resolved

public Func<TState, TDelta, Result<TState>> Then(Func<TState, TDelta, Result<TState>> reducer)
{
Expand All @@ -20,15 +20,11 @@ public Func<TState, TDelta, Result<TState>> Then(Func<TState, TDelta, Result<TSt
}

public ObjectResultMapper<TState, TSubState, TDelta> WhenReducedBy<TSubState>(
Func<TState, TSubState> subStateSelector,
Func<TSubState, TDelta, Result<TSubState>> reducer)
=>
new ObjectResultMapper<TState, TSubState, TDelta>(subStateSelector, reducer);
Func<TState, TSubState> subStateSelector, Func<TSubState, TDelta, Result<TSubState>> reducer) =>
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer all of the original code in this case.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reverted

new(subStateSelector, reducer);

public ImmutableArrayResultMapper<TState, TElement, TDelta> WhenReducedBy<TElement>(
Func<TState, ImmutableArray<TElement>> subStateSelector,
Func<TElement, TDelta, Result<TElement>> reducer)
=>
new ImmutableArrayResultMapper<TState, TElement, TDelta>(subStateSelector, reducer);
Func<TState, ImmutableArray<TElement>> subStateSelector, Func<TElement, TDelta, Result<TElement>> reducer) =>
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer the original code here too.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reverted

new(subStateSelector, reducer);
}
}
2 changes: 1 addition & 1 deletion Source/Morris.Reducible/Reducer.Result.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@ public static partial class Reducer
public record struct Result<TState>(bool Changed, TState State)
{
public static implicit operator (bool changed, TState state)(Result<TState> result) => (result.Changed, result.State);
public static implicit operator Result<TState>((bool changed, TState value) value) => new Result<TState>(value.changed, value.value);
public static implicit operator Result<TState>((bool changed, TState value) value) => new(value.changed, value.value);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is okay, but could you also change the parameter names to TState state and the param itself to tuple

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed

}
}
9 changes: 4 additions & 5 deletions Source/Morris.Reducible/Reducer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ namespace Morris.Reducible;

public static partial class Reducer
{
public static ConditionBuilder<TState, TDelta> Given<TState, TDelta>() => new ConditionBuilder<TState, TDelta>();
public static ConditionBuilder<TState, TDelta> Given<TState, TDelta>() => new();

public static Builder<TState> CreateBuilder<TState>() => new Builder<TState>();
public static Builder<TState> CreateBuilder<TState>() => new();

public static Func<TState, TDelta, Result<TState>> Combine<TState, TDelta>(params Func<TState, TDelta, Result<TState>>[] reducers)
{
Expand All @@ -23,10 +23,9 @@ public static Func<TState, TDelta, Result<TState>> Combine<TState, TDelta>(param
return (state, delta) =>
{
bool anyChanged = false;
for (int o = 0; o < allReducers.Length; o++)
foreach (var reducer in allReducers)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think a for loop is faster than a foreach

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reverted

{
(bool changed, state) = allReducers[o](state, delta);
anyChanged |= changed;
anyChanged |= reducer(state, delta).Changed;
mrpmorris marked this conversation as resolved.
Show resolved Hide resolved
}
return (anyChanged, state);
};
Expand Down