Skip to content

Instantly share code, notes, and snippets.

@davidwhitney
Created May 14, 2020 17:11
Show Gist options
  • Save davidwhitney/47d30b216bd3a9bfbf057db62f59deca to your computer and use it in GitHub Desktop.
Save davidwhitney/47d30b216bd3a9bfbf057db62f59deca to your computer and use it in GitHub Desktop.
Santa Kata
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