ex-col-02-bucket-chain/BucketChain.Test/ChainTests.cs
github-classroom[bot] 593d8ebfea
Initial commit
2024-11-17 08:52:38 +00:00

153 lines
No EOL
5.9 KiB
C#

using FluentAssertions;
using Xunit;
namespace BucketChain.Test;
public sealed class ChainTests
{
private const double InitialFireSize = 10D;
private const double FireGrowthRate = 0.25D;
private const double WellSize = 20D;
private const double WellRefillRate = 0.5D;
private const double BucketSize = 1.5D;
[Fact]
public void Construction()
{
new Chain(10, 5, BucketSize, new Well(WellSize, WellRefillRate),
new Fire(InitialFireSize, FireGrowthRate), new Person())
.Should().NotBeNull("only sets private fields, not much to check here");
}
[Fact]
public void Operate_Minimal()
{
const double FireSize = 3D;
var (chain, fire, well, first) = CreateMinimalChain(2, 2,
2, FireSize);
// step 1
// new bucket handed to first person who filled it, then moved to second person
chain.Operate(1, out var error)
.Should().BeFalse("fire still burning");
error.Should().BeFalse("no problem so far");
first.HasBucket.Should().BeFalse("moved to second person already");
first.RightNeighbor?.HasBucket.Should().BeTrue("has the new bucket");
well.LitersRemaining.Should().BeApproximately(WellSize - BucketSize,
double.Epsilon, "bucket has been filled");
fire.Extinguished.Should().BeFalse("still burning");
fire.FireSize.Should().BeApproximately(FireSize + FireGrowthRate - BucketSize,
double.Epsilon, "fire grew, then got hit by the water in the bucket");
var wellSize = well.LitersRemaining;
var fireSize = fire.FireSize;
// step 2
// new bucket handed to first person who filled it, then moved to the second person
// empty bucket from previous step handed from second person to first
chain.Operate(2, out error)
.Should().BeFalse("fire still burning");
error.Should().BeFalse("no problem so far");
first.HasBucket.Should().BeTrue("there are now two buckets, has the one from step 1");
first.RightNeighbor?.HasBucket.Should().BeTrue("has the new bucket");
well.LitersRemaining.Should().BeApproximately(wellSize + WellRefillRate - BucketSize,
double.Epsilon, "well refilled, then bucket has been filled");
fire.Extinguished.Should().BeFalse("still burning");
fire.FireSize.Should().BeApproximately(fireSize + FireGrowthRate - BucketSize,
double.Epsilon, "fire grew, then got hit by the water in the bucket");
wellSize = well.LitersRemaining;
// step 3
// no new buckets added, existing two continue circulating
chain.Operate(3, out error)
.Should().BeTrue("fire extinguished");
error.Should().BeFalse("no problem so far");
well.LitersRemaining.Should().BeApproximately(wellSize + WellRefillRate - BucketSize,
double.Epsilon, "well refilled, then bucket has been filled");
fire.Extinguished.Should().BeTrue();
fire.FireSize.Should().BeApproximately(0D,
double.Epsilon, "fire extinguished, but size cannot become negative");
}
[Fact]
public void Operate_NotLongEnough()
{
const int Steps = 100;
var (chain, fire, _, _) = CreateMinimalChain(4, 3, 2);
for (var i = 0; i < Steps; i++)
{
chain.Operate(i + 1, out var error)
.Should().BeFalse("fire keeps burning");
error.Should().BeFalse("no error, chain is simply not long enough");
}
fire.Extinguished.Should().BeFalse();
fire.FireSize.Should().BeApproximately(InitialFireSize + FireGrowthRate * Steps,
2E-14, "fire keeps growing");
}
[Fact]
public void Operate_Initially_NotLongEnough()
{
const int FirstSteps = 5;
var (chain, fire, _, firstPerson) = CreateMinimalChain(4, 2, 2);
var initialSize = fire.FireSize;
for (var i = 0; i < FirstSteps; i++)
{
chain.Operate(i + 1, out var error)
.Should().BeFalse("fire keeps burning");
error.Should().BeFalse("no error, chain is simply not long enough");
}
fire.FireSize.Should().BeGreaterThan(initialSize, "fire grew");
// two additional people, but no more buckets, stays at 2
new Person().JoinChain(firstPerson, true);
new Person().JoinChain(firstPerson, true);
var s = FirstSteps;
while (!chain.Operate(++s, out var error))
{
fire.Extinguished.Should().BeFalse();
error.Should().BeFalse();
}
fire.FireSize.Should().BeApproximately(0D, double.Epsilon, "fire extinguished");
s.Should().Be(49);
}
[Fact]
public void StringRepresentation()
{
var (chain, fire, well, firstPerson) = CreateMinimalChain(4, 2, 1);
chain.Operate(1, out _);
chain.ToString()
.Should().Be($"{well} | {firstPerson} | {firstPerson.RightNeighbor} | ❔ | ❔ | {fire}");
}
private static (Chain Chain, Fire Fire, Well Well, Person FirstPerson) CreateMinimalChain(int requiredPeople,
int peopleCount, int buckets, double? initialFireSize = null)
{
var fire = new Fire(initialFireSize ?? InitialFireSize, FireGrowthRate);
var well = new Well(WellSize, WellRefillRate);
var firstPerson = CreatePeople();
var chain = new Chain(requiredPeople, buckets, BucketSize, well, fire, firstPerson);
return (chain, fire, well, firstPerson);
Person CreatePeople()
{
var first = new Person();
var prev = first;
for (var i = 1; i < peopleCount; i++)
{
var newPerson = new Person();
newPerson.JoinChain(prev, true);
prev = newPerson;
}
return first;
}
}
}