Created
May 14, 2020 17:11
-
-
Save davidwhitney/47d30b216bd3a9bfbf057db62f59deca to your computer and use it in GitHub Desktop.
Santa Kata
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Runtime.InteropServices.ComTypes; | |
using NUnit.Framework; | |
namespace dojo6.Test.Unit | |
{ | |
public class FileParser | |
{ | |
public static IEnumerable<Person> Parse(string contents) | |
{ | |
return contents | |
.Split(Environment.NewLine, StringSplitOptions.RemoveEmptyEntries) | |
.Select(line => | |
{ | |
var parts = line.Split(new[] {'[', ']'}, StringSplitOptions.RemoveEmptyEntries); | |
return new Person(parts[0], parts[1]); | |
}); | |
} | |
} | |
public class Person | |
{ | |
public string Name { get; set; } | |
public string Email { get; set; } | |
public string FirstName => Name.Split(' ', StringSplitOptions.RemoveEmptyEntries).First(); | |
public string LastName => Name.Split(' ', StringSplitOptions.RemoveEmptyEntries).Last(); | |
public Person(string name, string email) | |
{ | |
Name = name; | |
Email = email; | |
} | |
} | |
[TestFixture] | |
public class FileParserTests | |
{ | |
private string inputTextFile = @" | |
Luke Skywalker[[email protected]] | |
Leia Skywalker[[email protected]] | |
Toula Portokalos[[email protected]] | |
Gus Portokalos[[email protected]] | |
Bruce Wayne[[email protected]] | |
Virgil Brigman[[email protected]] | |
Lindsey Brigman[[email protected]]".Trim(); | |
[Test] | |
public void Parse_FileContainsNothing_EmptyListCreate() | |
{ | |
var people = FileParser.Parse(""); | |
Assert.That(people.Count(), Is.EqualTo(0)); | |
} | |
[Test] | |
public void Parse_FileContainsPeople_ReturnsMoreThanZeroEntries() | |
{ | |
var people = FileParser.Parse(inputTextFile); | |
Assert.That(people.Count, Is.Not.EqualTo(0)); | |
} | |
[TestCase("Luke Skywalker[[email protected]]", "Luke Skywalker")] | |
[TestCase("Mark Skywalker[[email protected]]", "Mark Skywalker")] | |
public void Parse_FileContainsSinglePerson_NameIsCorrect(string line, string expectation) | |
{ | |
var people = FileParser.Parse(line).Single(); | |
Assert.That(people.Name, Is.EqualTo(expectation)); | |
} | |
[Test] | |
public void Parse_FileContainsMultiplePeople_NameIsCorrect() | |
{ | |
inputTextFile = @" | |
Luke Skywalker[[email protected]] | |
Leia Skywalker[[email protected]]".Trim(); | |
var people = FileParser.Parse(inputTextFile).ToList(); | |
Assert.That(people[0].Name, Is.EqualTo("Luke Skywalker")); | |
Assert.That(people[1].Name, Is.EqualTo("Leia Skywalker")); | |
} | |
[Test] | |
public void Parse_FileContainsMultiplePeople_EmailIsCorrect() | |
{ | |
inputTextFile = "Luke Skywalker[[email protected]]"; | |
var firstPerson = FileParser.Parse(inputTextFile).Single(); | |
Assert.That(firstPerson.Email, Is.EqualTo("[email protected]")); | |
} | |
} | |
[TestFixture] | |
public class Class1Tests | |
{ | |
private string inputTextFile = @" | |
Luke Skywalker[[email protected]] | |
Leia Skywalker[[email protected]] | |
Toula Portokalos[[email protected]] | |
Gus Portokalos[[email protected]] | |
Bruce Wayne[[email protected]] | |
Virgil Brigman[[email protected]] | |
Lindsey Brigman[[email protected]]".Trim(); | |
/* | |
As a user | |
When I pass a list of names in a file | |
Secret santas are allocated */ | |
[Test] | |
public void Allocate_PassedListOfOnePerson_CannotMatch() | |
{ | |
var instance = new SantasBag( | |
new Person("Bob", "[email protected]") | |
); | |
var ex = Assert.Throws<InvalidOperationException>(() => instance.Allocate()); | |
Assert.That(ex.Message, Is.EqualTo("Cannot allocate gift givers with only one gifter.")); | |
} | |
[Test] | |
public void Allocate_PassedListOfTwoPeople_HasAnEntryForEachPersonAsAGiftGiver() | |
{ | |
var instance = new SantasBag( | |
new Person("Bob", "[email protected]"), | |
new Person("Alice", "[email protected]") | |
); | |
var result = instance.Allocate(); | |
Assert.That(result.ContainsKey("Bob"), Is.True); | |
Assert.That(result.ContainsKey("Alice"), Is.True); | |
} | |
[Test] | |
public void Allocate_PassedListOfTwoPeople_PeopleDoNotGiftToThemselves() | |
{ | |
var instance = new SantasBag( | |
new Person("Bob", "[email protected]"), | |
new Person("Alice", "[email protected]") | |
); | |
var result = instance.Allocate(); | |
Assert.That(result["Alice"], Is.Not.EqualTo("Alice")); | |
Assert.That(result["Bob"], Is.Not.EqualTo("Bob")); | |
} | |
[Test] | |
public void Allocate_PassedListOfThreePeople_PeopleDoNotGiftToThemselves() | |
{ | |
var instance = new SantasBag( | |
new Person("Bob", "[email protected]"), | |
new Person("Alice", "[email protected]"), | |
new Person("Mike", "[email protected]") | |
); | |
var result = instance.Allocate(); | |
Assert.That(result["Alice"], Is.Not.EqualTo("Alice")); | |
Assert.That(result["Mike"], Is.Not.EqualTo("Mike")); | |
Assert.That(result["Bob"], Is.Not.EqualTo("Bob")); | |
} | |
[Test] | |
public void Allocate_PassedListOfTwoPeople_PeopleGiftToEachOther() | |
{ | |
var instance = new SantasBag( | |
new Person("Bob", "[email protected]"), | |
new Person("Alice", "[email protected]") | |
); | |
var result = instance.Allocate(); | |
Assert.That(result["Alice"], Is.EqualTo("Bob")); | |
Assert.That(result["Bob"], Is.EqualTo("Alice")); | |
} | |
[Test] | |
public void Allocate_PassedWholeFile_PeopleAllGetAllocated() | |
{ | |
var people = FileParser.Parse(inputTextFile); | |
var instance = new SantasBag(people.ToArray()); | |
var result = instance.Allocate(); | |
Assert.That(result.Count, Is.EqualTo(people.Count())); | |
} | |
[Test] | |
public void Allocate_TwoFamilyMembers_CannotBePaired() | |
{ | |
var instance = new SantasBag( | |
new Person("Bob Bobbins", "[email protected]"), | |
new Person("Alice Bobbins", "[email protected]") | |
); | |
var ex = Assert.Throws<NotSupportedException>(() => instance.Allocate()); | |
Assert.That(ex.Message, Is.EqualTo("Cannot match this set.")); | |
} | |
[Test] | |
public void Allocate_SomePeople_FamilyMembersCannotBePaired() | |
{ | |
var instance = new SantasBag( | |
new Person("Bob Bobbins", "[email protected]"), | |
new Person("Alice Bobbins", "[email protected]"), | |
new Person("John Johns", "[email protected]"), | |
new Person("Peter Parker", "[email protected]") | |
); | |
var result = instance.Allocate(); | |
Assert.That(result["Bob Bobbins"], Is.Not.EqualTo("Alice Bobbins")); | |
Assert.That(result["Bob Bobbins"], Is.Not.EqualTo("Bob Bobbins")); | |
Assert.That(result["Alice Bobbins"], Is.Not.EqualTo("Bob Bobbins")); | |
Assert.That(result["Alice Bobbins"], Is.Not.EqualTo("Alice Bobbins")); | |
} | |
[Test] | |
public void Allocate_OddNumbers_FamilyMembersCannotBePaired() | |
{ | |
var instance = new SantasBag( | |
new Person("Bob Bobbins", "[email protected]"), | |
new Person("Alice Bobbins", "[email protected]"), | |
new Person("John Johns", "[email protected]") | |
); | |
var ex = Assert.Throws<NotSupportedException>(() => instance.Allocate()); | |
Assert.That(ex.Message, Is.EqualTo("Cannot match this set.")); | |
} | |
[Test] | |
public void Allocate_PassedFourPeople_CandidatesCanAlwaysMatchRegardlessOfOrderInTheBag() | |
{ | |
var instance = new SantasBag( | |
new Person("John Johns", "[email protected]"), | |
new Person("Peter Parker", "[email protected]"), | |
new Person("Bob Bobbins", "[email protected]"), | |
new Person("Alice Bobbins", "[email protected]") | |
); | |
var result = instance.Allocate(); | |
Assert.That(result["Bob Bobbins"], Is.Not.EqualTo("Alice Bobbins")); | |
Assert.That(result["Bob Bobbins"], Is.Not.EqualTo("Bob Bobbins")); | |
Assert.That(result["Alice Bobbins"], Is.Not.EqualTo("Bob Bobbins")); | |
Assert.That(result["Alice Bobbins"], Is.Not.EqualTo("Alice Bobbins")); | |
} | |
} | |
public class SantasBag | |
{ | |
private readonly List<Person> _candidates; | |
public SantasBag(params Person[] candidates) => _candidates = candidates.ToList(); | |
public Dictionary<string, string> Allocate() | |
{ | |
if (_candidates.Count == 1) | |
{ | |
throw new InvalidOperationException("Cannot allocate gift givers with only one gifter."); | |
} | |
if (_candidates.Select(person => _candidates.Count(x => x.LastName == person.LastName)) | |
.Any(countOfPeopleWithThisSurname => countOfPeopleWithThisSurname > _candidates.Count / 2)) | |
{ | |
throw new NotSupportedException("Cannot match this set."); | |
} | |
var maxIterations = _candidates.Count * _candidates.Count; | |
var dictionary = new Dictionary<string, string>(); | |
var queue = new Queue<Person>(_candidates); | |
foreach (var candidate in _candidates) | |
{ | |
var iterations = 0; | |
var otherPerson = queue.Dequeue(); | |
while (candidate.Name == otherPerson.Name | |
|| candidate.LastName == otherPerson.LastName) | |
{ | |
queue.Enqueue(otherPerson); | |
otherPerson = queue.Dequeue(); | |
iterations++; | |
if (iterations > maxIterations) | |
{ | |
throw new NotSupportedException("Cannot match this set."); | |
} | |
} | |
dictionary.Add(candidate.Name, otherPerson.Name); | |
} | |
return dictionary; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment