diff --git a/BDD/BerlinClockFeatureSteps.cs b/BDD/BerlinClockFeatureSteps.cs
index 4390f3cb..f8cd7bf1 100644
--- a/BDD/BerlinClockFeatureSteps.cs
+++ b/BDD/BerlinClockFeatureSteps.cs
@@ -1,27 +1,26 @@
-using System;
-using TechTalk.SpecFlow;
+using TechTalk.SpecFlow;
using Microsoft.VisualStudio.TestTools.UnitTesting;
-using System.Linq;
+using BerlinClock.Converters;
namespace BerlinClock
{
[Binding]
public class TheBerlinClockSteps
{
- private ITimeConverter berlinClock = new TimeConverter();
- private String theTime;
+ private readonly ITimeConverter _berlinClock = new TimeConverter();
+ private string _theTime;
[When(@"the time is ""(.*)""")]
public void WhenTheTimeIs(string time)
{
- theTime = time;
+ _theTime = time;
}
[Then(@"the clock should look like")]
public void ThenTheClockShouldLookLike(string theExpectedBerlinClockOutput)
{
- Assert.AreEqual(berlinClock.convertTime(theTime), theExpectedBerlinClockOutput);
+ Assert.AreEqual(_berlinClock.ConvertTime(_theTime), theExpectedBerlinClockOutput);
}
}
diff --git a/BerlinClock.Tests/BerlinClock.Tests.csproj b/BerlinClock.Tests/BerlinClock.Tests.csproj
new file mode 100644
index 00000000..caebf629
--- /dev/null
+++ b/BerlinClock.Tests/BerlinClock.Tests.csproj
@@ -0,0 +1,76 @@
+
+
+
+
+
+
+ Debug
+ AnyCPU
+ {74F9D721-6839-4776-97C9-718145CED3D0}
+ Library
+ Properties
+ BerlinClock.Tests
+ BerlinClock.Tests
+ v4.5
+ 512
+ {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
+ 15.0
+ $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
+ $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages
+ False
+ UnitTest
+
+
+
+
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+
+
+
+ ..\packages\NUnit.3.12.0\lib\net45\nunit.framework.dll
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {0451204d-bf86-43e1-b560-fc9ac830b9a9}
+ BerlinClock
+
+
+
+
+
+
+
+ This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
+
+
+
+
+
\ No newline at end of file
diff --git a/BerlinClock.Tests/Builders/YellowLampRowBuilderTests.cs b/BerlinClock.Tests/Builders/YellowLampRowBuilderTests.cs
new file mode 100644
index 00000000..826bf54d
--- /dev/null
+++ b/BerlinClock.Tests/Builders/YellowLampRowBuilderTests.cs
@@ -0,0 +1,30 @@
+using BerlinClock.Builders;
+using BerlinClock.Models;
+using NUnit.Framework;
+
+namespace BerlinClock.Tests.Builders
+{
+ [TestFixture]
+ public class YellowLampRowBuilderTests
+ {
+ private YellowLampRowBuilder _sut;
+
+ [SetUp]
+ public void SetUp()
+ {
+ _sut = new YellowLampRowBuilder();
+ }
+
+ [Test]
+ public void Build_ShouldReturnDifferentResult_WhenOddAndEvenNumbersAreGiven()
+ {
+ var oddValue = 1;
+ var evenValue = 2;
+
+ var resultForOddValue = _sut.Build(new Time(0, 0, oddValue));
+ var resultForEvenValue = _sut.Build(new Time(0, 0, evenValue));
+
+ Assert.That(resultForEvenValue, Is.Not.EqualTo(resultForOddValue));
+ }
+ }
+}
diff --git a/BerlinClock.Tests/Extensions/IntExtensionsTests.cs b/BerlinClock.Tests/Extensions/IntExtensionsTests.cs
new file mode 100644
index 00000000..1d1034f0
--- /dev/null
+++ b/BerlinClock.Tests/Extensions/IntExtensionsTests.cs
@@ -0,0 +1,29 @@
+using BerlinClock.Extensions;
+using NUnit.Framework;
+
+namespace BerlinClock.Tests.Extensions
+{
+ [TestFixture]
+ public class IntExtensionsTests
+ {
+ [Test]
+ public void IsEven_ShouldReturnTrue_WhenEvenNumberIsGiven()
+ {
+ var evenNumber = 2;
+
+ var result = evenNumber.IsEven();
+
+ Assert.That(result, Is.True);
+ }
+
+ [Test]
+ public void IsEven_ShouldReturnFalse_WhenOddNumberIsGiven()
+ {
+ var oddNumber = 3;
+
+ var result = oddNumber.IsEven();
+
+ Assert.That(result, Is.False);
+ }
+ }
+}
diff --git a/BerlinClock.Tests/Extensions/StringExtensionsTests.cs b/BerlinClock.Tests/Extensions/StringExtensionsTests.cs
new file mode 100644
index 00000000..33c3c99e
--- /dev/null
+++ b/BerlinClock.Tests/Extensions/StringExtensionsTests.cs
@@ -0,0 +1,52 @@
+using BerlinClock.Extensions;
+using NUnit.Framework;
+
+namespace BerlinClock.Tests.Extensions
+{
+ [TestFixture]
+ public class StringExtensionsTests
+ {
+ private string _value;
+ private char _valueToReplace;
+ private char _newValue;
+
+ [SetUp]
+ public void SetUp()
+ {
+ _value = "OOOOOOO";
+ _valueToReplace = 'O';
+ _newValue = 'X';
+ }
+
+ [TestCase(null)]
+ [TestCase("")]
+ public void ReplaceEveryNthOccurence_ShouldReturnSameValue_WhenNullOrEmptyStringIsGiven(string value)
+ {
+ var result = value.ReplaceEveryNthOccurence(_valueToReplace, _newValue, 1);
+
+ Assert.That(result, Is.EqualTo(value));
+ }
+
+ [Test]
+ public void ReplaceEveryNthOccurence_ShouldNotReplaceAnyValue_WhenNValueIsOutOfRange()
+ {
+ var outOfRangeNValue = _value.Length + 1;
+
+ var result = _value.ReplaceEveryNthOccurence(_valueToReplace, _newValue, outOfRangeNValue);
+
+ Assert.That(result, Is.EqualTo(_value));
+ }
+
+ [Test]
+ public void ReplaceEveryNthOccurence_ShouldReplaceEvery3thOccurence_WhenValueOccurred()
+ {
+ var value = "OOROOOOOO";
+ var expectedValue = "OOROOXOOX";
+ var n = 3;
+
+ var result = value.ReplaceEveryNthOccurence(_valueToReplace, _newValue, n);
+
+ Assert.That(result, Is.EqualTo(expectedValue));
+ }
+ }
+}
diff --git a/BerlinClock.Tests/Parsers/TimeParserExtensions.cs b/BerlinClock.Tests/Parsers/TimeParserExtensions.cs
new file mode 100644
index 00000000..b59342d3
--- /dev/null
+++ b/BerlinClock.Tests/Parsers/TimeParserExtensions.cs
@@ -0,0 +1,47 @@
+using BerlinClock.Parsers;
+using NUnit.Framework;
+using System;
+
+namespace BerlinClock.Tests.Parsers
+{
+ [TestFixture]
+ public class TimeParserExtensions
+ {
+ private TimeParser _sut;
+
+ [SetUp]
+ public void SetUp()
+ {
+ _sut = new TimeParser();
+ }
+
+ [Test]
+ public void Parse_ShouldThrowException_WhenGivenValueIsNull()
+ {
+ Assert.Throws(() => _sut.Parse(null));
+ }
+
+ [Test]
+ public void Parse_ShouldThrowException_WhenWrongTimeFormatIsGiven()
+ {
+ var wrongTime = "123400";
+
+ Assert.Throws(() => _sut.Parse(wrongTime));
+ }
+
+ [Test]
+ public void Parse_ShouldCreateCorrectInstance_WhenCorrectTimeIsGiven()
+ {
+ var hour = 12;
+ var minute = 45;
+ var second = 30;
+ var timeValue = $"{hour}:{minute}:{second}";
+
+ var result = _sut.Parse(timeValue);
+
+ Assert.That(result.Hour, Is.EqualTo(hour));
+ Assert.That(result.Minute, Is.EqualTo(minute));
+ Assert.That(result.Second, Is.EqualTo(second));
+ }
+ }
+}
diff --git a/BerlinClock.Tests/Properties/AssemblyInfo.cs b/BerlinClock.Tests/Properties/AssemblyInfo.cs
new file mode 100644
index 00000000..0a3129db
--- /dev/null
+++ b/BerlinClock.Tests/Properties/AssemblyInfo.cs
@@ -0,0 +1,20 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+[assembly: AssemblyTitle("BerlinClock.Tests")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("BerlinClock.Tests")]
+[assembly: AssemblyCopyright("Copyright © 2020")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+[assembly: ComVisible(false)]
+
+[assembly: Guid("74f9d721-6839-4776-97c9-718145ced3d0")]
+
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/BerlinClock.Tests/Renderers/BerlinClockRowRendererTests.cs b/BerlinClock.Tests/Renderers/BerlinClockRowRendererTests.cs
new file mode 100644
index 00000000..77f76427
--- /dev/null
+++ b/BerlinClock.Tests/Renderers/BerlinClockRowRendererTests.cs
@@ -0,0 +1,79 @@
+using BerlinClock.Models;
+using BerlinClock.Renderers;
+using NUnit.Framework;
+using System;
+
+namespace BerlinClock.Tests.Renderers
+{
+ [TestFixture]
+ public class BerlinClockRowRendererTests
+ {
+ private BerlinClockRowRenderer _sut;
+
+ [SetUp]
+ public void SetUp()
+ {
+ _sut = new BerlinClockRowRenderer();
+ }
+
+ [Test]
+ public void Render_ShouldNotModifyResult_WhenAdditionalFormattingIsNull()
+ {
+ var expectedValue = "XO";
+ var request = new BerlinClockRendererRequest
+ {
+ AdditionalFormatting = null,
+ TurnedOnLampSign = 'X',
+ AmountOfTurnedOnLamps = 1,
+ AmountOfTurnedOffLamps = 1
+ };
+
+ var result = _sut.Render(request);
+
+ Assert.That(result, Is.EqualTo(expectedValue));
+ }
+
+ [Test]
+ public void Render_ShouldModifyResult_WhenAdditionalFormattingIsGiven()
+ {
+ var expectedValue = "TEST";
+ var request = new BerlinClockRendererRequest
+ {
+ AdditionalFormatting = (row) => expectedValue,
+ TurnedOnLampSign = 'X',
+ AmountOfTurnedOnLamps = 1,
+ AmountOfTurnedOffLamps = 1
+ };
+
+ var result = _sut.Render(request);
+
+ Assert.That(result, Is.EqualTo(expectedValue));
+ }
+
+ [Test]
+ public void Render_ShouldThrowException_WhenNegativeTurnedOnLampsValueIsGiven()
+ {
+ var request = new BerlinClockRendererRequest
+ {
+ TurnedOnLampSign = 'X',
+ AmountOfTurnedOnLamps = -1,
+ AmountOfTurnedOffLamps = 1
+ };
+
+ Assert.Throws(() => _sut.Render(request));
+ }
+
+ [Test]
+ public void Render_ShouldThrowException_WhenNegativeTurnedOffLampsValueIsGiven()
+ {
+ var request = new BerlinClockRendererRequest
+ {
+ TurnedOnLampSign = 'X',
+ AmountOfTurnedOnLamps = 1,
+ AmountOfTurnedOffLamps = -1
+ };
+
+ Assert.Throws(() => _sut.Render(request));
+ }
+ }
+}
diff --git a/BerlinClock.Tests/packages.config b/BerlinClock.Tests/packages.config
new file mode 100644
index 00000000..929338d9
--- /dev/null
+++ b/BerlinClock.Tests/packages.config
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/BerlinClock.csproj b/BerlinClock.csproj
index ac8af99d..2a9b8c49 100644
--- a/BerlinClock.csproj
+++ b/BerlinClock.csproj
@@ -50,14 +50,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
True
True
BerlinClockFeatureSteps.feature
-
-
+
+
diff --git a/BerlinClock.sln b/BerlinClock.sln
index 082911a2..1114bf1f 100644
--- a/BerlinClock.sln
+++ b/BerlinClock.sln
@@ -5,6 +5,8 @@ VisualStudioVersion = 12.0.21005.1
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BerlinClock", "BerlinClock.csproj", "{0451204D-BF86-43E1-B560-FC9AC830B9A9}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BerlinClock.Tests", "BerlinClock.Tests\BerlinClock.Tests.csproj", "{74F9D721-6839-4776-97C9-718145CED3D0}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -15,6 +17,10 @@ Global
{0451204D-BF86-43E1-B560-FC9AC830B9A9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0451204D-BF86-43E1-B560-FC9AC830B9A9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0451204D-BF86-43E1-B560-FC9AC830B9A9}.Release|Any CPU.Build.0 = Release|Any CPU
+ {74F9D721-6839-4776-97C9-718145CED3D0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {74F9D721-6839-4776-97C9-718145CED3D0}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {74F9D721-6839-4776-97C9-718145CED3D0}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {74F9D721-6839-4776-97C9-718145CED3D0}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/Builders/BerlinClockEntityBuilder.cs b/Builders/BerlinClockEntityBuilder.cs
new file mode 100644
index 00000000..95abd977
--- /dev/null
+++ b/Builders/BerlinClockEntityBuilder.cs
@@ -0,0 +1,46 @@
+using BerlinClock.Models;
+
+namespace BerlinClock.Builders
+{
+ public interface IBerlinClockEntityBuilder
+ {
+ BerlinClockEntity Build(Time time);
+ }
+
+ public class BerlinClockEntityBuilder : IBerlinClockEntityBuilder
+ {
+ private readonly IHourRowsBuilder _hourRowsBuilder;
+ private readonly IMinuteRowsBuilder _minuteRowsBuilder;
+ private readonly IYellowLampRowBuilder _yellowLampRowBuilder;
+
+ public BerlinClockEntityBuilder() : this(new HourRowsBuilder(), new MinuteRowsBuilder(),
+ new YellowLampRowBuilder())
+ {
+
+ }
+
+ public BerlinClockEntityBuilder(IHourRowsBuilder hourRowsBuilder, IMinuteRowsBuilder minuteRowsBuilder,
+ IYellowLampRowBuilder yellowLampRowBuilder)
+ {
+ _hourRowsBuilder = hourRowsBuilder;
+ _minuteRowsBuilder = minuteRowsBuilder;
+ _yellowLampRowBuilder = yellowLampRowBuilder;
+ }
+
+ public BerlinClockEntity Build(Time time)
+ {
+ var hourRows = _hourRowsBuilder.Build(time);
+ var minuteRows = _minuteRowsBuilder.Build(time);
+ var yellowLampRow = _yellowLampRowBuilder.Build(time);
+
+ return new BerlinClockEntity
+ {
+ YellowLampRow = yellowLampRow,
+ FirstHoursRow = hourRows.FirstRow,
+ SecondHoursRow = hourRows.SecondRow,
+ FirstMinutesRow = minuteRows.FirstRow,
+ SecondMinutesRow = minuteRows.SecondRow
+ };
+ }
+ }
+}
diff --git a/Builders/BerlinClockRowsBuilderBase.cs b/Builders/BerlinClockRowsBuilderBase.cs
new file mode 100644
index 00000000..e9b04fb8
--- /dev/null
+++ b/Builders/BerlinClockRowsBuilderBase.cs
@@ -0,0 +1,57 @@
+using BerlinClock.Models;
+using BerlinClock.Renderers;
+using System;
+
+namespace BerlinClock.Builders
+{
+ public interface IBerlinClockRowsBuilder
+ {
+ BerlinClockRows Build(Time time);
+ }
+
+ public abstract class BerlinClockRowsBuilderBase : IBerlinClockRowsBuilder
+ {
+ protected abstract int FirstRowLampsAmount { get; }
+ protected abstract int FirstRowLampValue { get; }
+ protected abstract int SecondRowLampsAmount { get; }
+ protected abstract int SecondRowLampValue { get; }
+ protected abstract char TurnedOnLampSign { get; }
+ protected virtual Func FirstRowAdditionalFormatting { get; }
+
+ private readonly IBerlinClockRowRenderer _berlinClockRowRenderer;
+
+ public BerlinClockRowsBuilderBase(IBerlinClockRowRenderer berlinClockRowRenderer)
+ {
+ _berlinClockRowRenderer = berlinClockRowRenderer;
+ }
+
+ public BerlinClockRows Build(Time time)
+ {
+ var timePart = ExtractTimePart(time);
+ var amountOfTurnedOnLampsAtFirstRow = timePart / FirstRowLampValue;
+ var amountOfTurnedOffLampsAtFirstRow = FirstRowLampsAmount - amountOfTurnedOnLampsAtFirstRow;
+
+ var amountOfTurnedOnLampsAtSecondRow = (timePart - (amountOfTurnedOnLampsAtFirstRow * FirstRowLampValue)) / SecondRowLampValue;
+ var amountOfTurnedOffLampsAtSecondRow = SecondRowLampsAmount - amountOfTurnedOnLampsAtSecondRow;
+
+ return new BerlinClockRows
+ {
+ FirstRow = _berlinClockRowRenderer.Render(new BerlinClockRendererRequest
+ {
+ AmountOfTurnedOnLamps = amountOfTurnedOnLampsAtFirstRow,
+ AmountOfTurnedOffLamps = amountOfTurnedOffLampsAtFirstRow,
+ TurnedOnLampSign = TurnedOnLampSign,
+ AdditionalFormatting = FirstRowAdditionalFormatting
+ }),
+ SecondRow = _berlinClockRowRenderer.Render(new BerlinClockRendererRequest
+ {
+ AmountOfTurnedOnLamps = amountOfTurnedOnLampsAtSecondRow,
+ AmountOfTurnedOffLamps = amountOfTurnedOffLampsAtSecondRow,
+ TurnedOnLampSign = TurnedOnLampSign
+ })
+ };
+ }
+
+ protected abstract int ExtractTimePart(Time time);
+ }
+}
diff --git a/Builders/HourRowsBuilder.cs b/Builders/HourRowsBuilder.cs
new file mode 100644
index 00000000..aaae68b5
--- /dev/null
+++ b/Builders/HourRowsBuilder.cs
@@ -0,0 +1,31 @@
+using BerlinClock.Models;
+using BerlinClock.Renderers;
+
+namespace BerlinClock.Builders
+{
+ public interface IHourRowsBuilder : IBerlinClockRowsBuilder
+ {
+
+ }
+
+ public class HourRowsBuilder : BerlinClockRowsBuilderBase, IHourRowsBuilder
+ {
+ public HourRowsBuilder() : this(new BerlinClockRowRenderer())
+ {
+
+ }
+ public HourRowsBuilder(IBerlinClockRowRenderer berlinClockRowRenderer) : base(berlinClockRowRenderer)
+ {
+ }
+
+ protected override char TurnedOnLampSign => 'R';
+ protected override int FirstRowLampsAmount => 4;
+ protected override int FirstRowLampValue => 5;
+ protected override int SecondRowLampsAmount => 4;
+ protected override int SecondRowLampValue => 1;
+ protected override int ExtractTimePart(Time time)
+ {
+ return time.Hour;
+ }
+ }
+}
diff --git a/Builders/MinuteRowsBuilder.cs b/Builders/MinuteRowsBuilder.cs
new file mode 100644
index 00000000..62b49da2
--- /dev/null
+++ b/Builders/MinuteRowsBuilder.cs
@@ -0,0 +1,42 @@
+using BerlinClock.Extensions;
+using BerlinClock.Models;
+using BerlinClock.Renderers;
+using System;
+
+namespace BerlinClock.Builders
+{
+ public interface IMinuteRowsBuilder : IBerlinClockRowsBuilder
+ {
+
+ }
+
+ public class MinuteRowsBuilder : BerlinClockRowsBuilderBase, IMinuteRowsBuilder
+ {
+ private const char QuarterSign = 'R';
+
+ public MinuteRowsBuilder() : this(new BerlinClockRowRenderer())
+ {
+
+ }
+
+ public MinuteRowsBuilder(IBerlinClockRowRenderer berlinClockRowRenderer) : base(berlinClockRowRenderer)
+ {
+ }
+
+ protected override int FirstRowLampsAmount => 11;
+ protected override int FirstRowLampValue => 5;
+ protected override int SecondRowLampsAmount => 4;
+ protected override int SecondRowLampValue => 1;
+ protected override char TurnedOnLampSign => 'Y';
+ protected override int ExtractTimePart(Time time)
+ {
+ return time.Minute;
+ }
+
+ protected override Func FirstRowAdditionalFormatting => (row) =>
+ {
+ var n = 3;
+ return row.ReplaceEveryNthOccurence(TurnedOnLampSign, QuarterSign, n);
+ };
+ }
+}
diff --git a/Builders/YellowLampRowBuilder.cs b/Builders/YellowLampRowBuilder.cs
new file mode 100644
index 00000000..96c2d213
--- /dev/null
+++ b/Builders/YellowLampRowBuilder.cs
@@ -0,0 +1,23 @@
+using BerlinClock.Extensions;
+using BerlinClock.Models;
+
+namespace BerlinClock.Builders
+{
+ public interface IYellowLampRowBuilder
+ {
+ char Build(Time time);
+ }
+
+ public class YellowLampRowBuilder : IYellowLampRowBuilder
+ {
+ private const char LampOnSign = 'Y';
+ private const char LampOffSign = 'O';
+
+ public char Build(Time time)
+ {
+ return time.Second.IsEven()
+ ? LampOnSign
+ : LampOffSign;
+ }
+ }
+}
diff --git a/Classes/ITimeConverter.cs b/Classes/ITimeConverter.cs
deleted file mode 100644
index 1d9e4c27..00000000
--- a/Classes/ITimeConverter.cs
+++ /dev/null
@@ -1,12 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-
-namespace BerlinClock
-{
- public interface ITimeConverter
- {
- String convertTime(String aTime);
- }
-}
diff --git a/Classes/TimeConverter.cs b/Classes/TimeConverter.cs
deleted file mode 100644
index dd5bf4e0..00000000
--- a/Classes/TimeConverter.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-
-namespace BerlinClock
-{
- public class TimeConverter : ITimeConverter
- {
- public string convertTime(string aTime)
- {
- throw new NotImplementedException();
- }
- }
-}
diff --git a/Converters/TimeConverter.cs b/Converters/TimeConverter.cs
new file mode 100644
index 00000000..cd5264fb
--- /dev/null
+++ b/Converters/TimeConverter.cs
@@ -0,0 +1,34 @@
+using BerlinClock.Builders;
+using BerlinClock.Parsers;
+
+namespace BerlinClock.Converters
+{
+ public interface ITimeConverter
+ {
+ string ConvertTime(string aTime);
+ }
+
+ public class TimeConverter : ITimeConverter
+ {
+ private readonly IBerlinClockEntityBuilder _berlinClockEntityBuilder;
+ private readonly ITimeParser _timeParser;
+
+ public TimeConverter() : this(new BerlinClockEntityBuilder(), new TimeParser())
+ {
+
+ }
+
+ public TimeConverter(IBerlinClockEntityBuilder berlinClockEntityBuilder, ITimeParser timeParser)
+ {
+ _berlinClockEntityBuilder = berlinClockEntityBuilder;
+ _timeParser = timeParser;
+ }
+
+ public string ConvertTime(string aTime)
+ {
+ var time = _timeParser.Parse(aTime);
+ var berlinClockEntity = _berlinClockEntityBuilder.Build(time);
+ return berlinClockEntity.ToString();
+ }
+ }
+}
diff --git a/Extensions/IntExtensions.cs b/Extensions/IntExtensions.cs
new file mode 100644
index 00000000..65411e57
--- /dev/null
+++ b/Extensions/IntExtensions.cs
@@ -0,0 +1,7 @@
+namespace BerlinClock.Extensions
+{
+ public static class IntExtensions
+ {
+ public static bool IsEven(this int value) => value % 2 == 0;
+ }
+}
diff --git a/Extensions/StringExtensions.cs b/Extensions/StringExtensions.cs
new file mode 100644
index 00000000..61a85a30
--- /dev/null
+++ b/Extensions/StringExtensions.cs
@@ -0,0 +1,19 @@
+using System;
+using System.Linq;
+
+namespace BerlinClock.Extensions
+{
+ public static class StringExtensions
+ {
+ public static string ReplaceEveryNthOccurence(this string value, char valueToReplace, char newValue, int n)
+ {
+ if (string.IsNullOrWhiteSpace(value))
+ return value;
+
+ var chars = value.Select((val, index) =>
+ val == valueToReplace && (index + 1) % n == 0 ? newValue : val);
+
+ return new string(chars.ToArray());
+ }
+ }
+}
diff --git a/Models/BerlinClockEntity.cs b/Models/BerlinClockEntity.cs
new file mode 100644
index 00000000..22316206
--- /dev/null
+++ b/Models/BerlinClockEntity.cs
@@ -0,0 +1,20 @@
+using System;
+
+namespace BerlinClock.Models
+{
+ public class BerlinClockEntity
+ {
+ public char YellowLampRow { get; set; }
+ public string FirstHoursRow { get; set; }
+ public string SecondHoursRow { get; set; }
+ public string FirstMinutesRow { get; set; }
+ public string SecondMinutesRow { get; set; }
+
+ public override string ToString()
+ {
+ return string.Join(Environment.NewLine, YellowLampRow,
+ FirstHoursRow, SecondHoursRow,
+ FirstMinutesRow, SecondMinutesRow);
+ }
+ }
+}
diff --git a/Models/BerlinClockRendererRequest.cs b/Models/BerlinClockRendererRequest.cs
new file mode 100644
index 00000000..09b7a992
--- /dev/null
+++ b/Models/BerlinClockRendererRequest.cs
@@ -0,0 +1,12 @@
+using System;
+
+namespace BerlinClock.Models
+{
+ public class BerlinClockRendererRequest
+ {
+ public int AmountOfTurnedOnLamps { get; set; }
+ public int AmountOfTurnedOffLamps { get; set; }
+ public char TurnedOnLampSign { get; set; }
+ public Func AdditionalFormatting { get; set; }
+ }
+}
diff --git a/Models/BerlinClockRows.cs b/Models/BerlinClockRows.cs
new file mode 100644
index 00000000..4bf6bd27
--- /dev/null
+++ b/Models/BerlinClockRows.cs
@@ -0,0 +1,8 @@
+namespace BerlinClock.Models
+{
+ public class BerlinClockRows
+ {
+ public string FirstRow { get; set; }
+ public string SecondRow { get; set; }
+ }
+}
diff --git a/Models/Time.cs b/Models/Time.cs
new file mode 100644
index 00000000..e5be78b1
--- /dev/null
+++ b/Models/Time.cs
@@ -0,0 +1,15 @@
+namespace BerlinClock.Models
+{
+ public struct Time
+ {
+ public Time(int hour, int minute, int second)
+ {
+ Hour = hour;
+ Minute = minute;
+ Second = second;
+ }
+ public int Hour { get; private set; }
+ public int Minute { get; private set; }
+ public int Second { get; private set; }
+ }
+}
diff --git a/Parsers/TimeParser.cs b/Parsers/TimeParser.cs
new file mode 100644
index 00000000..924a05fa
--- /dev/null
+++ b/Parsers/TimeParser.cs
@@ -0,0 +1,30 @@
+using BerlinClock.Models;
+using System;
+
+namespace BerlinClock.Parsers
+{
+ public interface ITimeParser
+ {
+ Time Parse(string time);
+ }
+
+ public class TimeParser : ITimeParser
+ {
+ private const char Separator = ':';
+ public Time Parse(string time)
+ {
+ if (time == null)
+ throw new Exception("Time must not be null");
+
+ var timeParts = time.Split(Separator);
+ if (timeParts.Length != 3)
+ throw new Exception("Wrong time format");
+
+ var hour = int.Parse(timeParts[0]);
+ var minute = int.Parse(timeParts[1]);
+ var second = int.Parse(timeParts[2]);
+
+ return new Time(hour, minute, second);
+ }
+ }
+}
diff --git a/Renderers/BerlinClockRowRenderer.cs b/Renderers/BerlinClockRowRenderer.cs
new file mode 100644
index 00000000..d6c2395e
--- /dev/null
+++ b/Renderers/BerlinClockRowRenderer.cs
@@ -0,0 +1,30 @@
+using BerlinClock.Models;
+using System;
+using System.Text;
+
+namespace BerlinClock.Renderers
+{
+ public interface IBerlinClockRowRenderer
+ {
+ string Render(BerlinClockRendererRequest request);
+ }
+
+ public class BerlinClockRowRenderer : IBerlinClockRowRenderer
+ {
+ private const char TurnedOffLampSign = 'O';
+
+ public string Render(BerlinClockRendererRequest request)
+ {
+ if (request.AmountOfTurnedOffLamps < 0 || request.AmountOfTurnedOnLamps < 0)
+ throw new Exception("Cannot render negative values");
+
+ var stringBuilder = new StringBuilder();
+ stringBuilder.Append(request.TurnedOnLampSign, request.AmountOfTurnedOnLamps);
+ stringBuilder.Append(TurnedOffLampSign, request.AmountOfTurnedOffLamps);
+
+ var row = stringBuilder.ToString();
+ return request.AdditionalFormatting != null
+ ? request.AdditionalFormatting(row) : row;
+ }
+ }
+}