diff --git a/App/Program.cs b/App/Program.cs index c4c26a8..5ce527e 100644 --- a/App/Program.cs +++ b/App/Program.cs @@ -1,22 +1,68 @@ -using System; - -namespace App -{ - public class Program - { - static void Main(string[] args) - { - Console.WriteLine("Run with `dotnet test` from CSharpInterview/AppTest"); - } - - public static string ConvertToTitleCase(string inpStr) - { - return inpStr; - } - - public static string ConvertUnixToDateString(long? inpUnixSeconds) - { - return inpUnixSeconds.ToString(); - } - } +using System; +using System.Text; +using System.Text.RegularExpressions; + +namespace App +{ + public class Program + { + static void Main(string[] args) + { + Console.WriteLine("Run with `dotnet test` from CSharpInterview/AppTest"); + } + + /// + /// Challenge 1 + /// Create a function that takes in a constant-formatted (all caps, words separated by underscores) string and returns the string in "title case" (see examples below). The function should + /// remove all non alphanumeric characters and replace them with spaces. But no spaces at the end of the result. A null input should throw an error. + /// + /// If you so choose feel free to leverage third party libraries to complete your solution. + /// + /// For example: "THIS_INPUT" should return "This Input" "CASE-THREE_extra[chars]///" should return "Case Three Extra Chars" + /// + public static string ConvertToTitleCase(string input) + { + + if (string.IsNullOrEmpty(input)) // Check for invalid input. + { + throw new ArgumentNullException("The input to this function cannot be null."); + } + + Regex Expression = new Regex("[^a-zA-Z0-9]"); + string[] Words = Expression.Replace(input, " ").Split(new char[] { ' ' }); // Use the regular expression to replace non-alphanumeric characters with space, and split into an array. + StringBuilder Result = new StringBuilder(); + foreach (string Word in Words) // Iterate through the words of the array. + { + if (!string.IsNullOrEmpty(Word)) // Only take action on words that are not empty. + { + Result.Append(Word[0].ToString().ToUpper() + Word.Substring(1).ToLower() + " "); // Append the capitalized first letter of the word, and the lowercase rest of the word. + } + } + return Result.ToString().Trim(); // Output the formatted list of words, trimmed to remove the trailing space. + } + + /// + /// Challenge 2 + /// Create a function that takes in a unix epoch time in seconds(long data type) and returns a String that is the input timestamp converted and formatted as month day, year (see below). + /// If no timestamp is given the function should return today’s date. If the input is null or has an incorrect type, an error should be thrown. + /// + /// If you so choose feel free to leverage third party libraries to complete your solution. + /// + /// For example, passing a unix epoch time 1499144400 in seconds (long data type) would return "July 4, 2017" in this date format(string data type). + /// + /// + /// I decided to omit checks for no timestamp given, since the unix epoch time is the number of seconds since 1-1-1970 (00:00 GMT), there is no such thing as a missing timestamp. All values + /// for the long data type, including negative and zero values, are valid unix timestamps, and this function will convert them accordingly. + /// + public static string ConvertUnixToDateString(long? unixTime) + { + if (unixTime == null) // Check for invalid input. + { + throw new ArgumentNullException("The input to this function cannot be null."); + } + + // Using DateTimeOffset, generate a DateTime object from the unixTime paramter. This is then converted to a string using a format code to get the desired format, and returned. + return DateTimeOffset.FromUnixTimeSeconds((long)unixTime).DateTime.ToString("MMMM d, yyyy"); + } + } } \ No newline at end of file diff --git a/AppTest/Program.Tests.cs b/AppTest/Program.Tests.cs index f948724..1be227c 100644 --- a/AppTest/Program.Tests.cs +++ b/AppTest/Program.Tests.cs @@ -1,78 +1,193 @@ -using System; -using App; -using Xunit; - -namespace AppTest -{ - public class ProgramTests - { - [Fact] - public void ConvertToTitleCase_Simple() - { - // Given - var testStr = "TITLE_CASE"; - - // When - var actual = Program.ConvertToTitleCase(testStr); - - // Then - var expected = "Title Case"; - Assert.Equal(expected, actual); - } - - [Fact] - public void ConvertToTitleCase_Numbers() - { - // Given - var testStr = "NUMBER_3"; - - // When - var actual = Program.ConvertToTitleCase(testStr); - - // Then - var expected = "Number 3"; - Assert.Equal(expected, actual); - } - - [Fact] - public void ConvertToTitleCase_OtherChars() - { - // Given - var testStr = " TRUTH-TRACK "; - - // When - var actual = Program.ConvertToTitleCase(testStr); - - // Then - var expected = "Truth Track"; - Assert.Equal(expected, actual); - } - - [Fact] - public void ConvertUnixToDateString_Simple() - { - // Given - var testStamp = 1604352245L; - - // When - var actual = Program.ConvertUnixToDateString(testStamp); - - // Then - var expected = "November 2, 2020"; - Assert.Equal(expected, actual); - } - - [Fact] - public void ConvertUnixToDateString_Null() - { - // Given - long? testStamp = null; - - // When - Action action = () => Program.ConvertUnixToDateString(testStamp); - - // Then - Assert.Throws(action); - } - } +using System; +using App; +using Xunit; + +namespace AppTest +{ + public class ProgramTests + { + [Fact] + public void ConvertToTitleCase_Simple() + { + // Given + var testStr = "TITLE_CASE"; + + // When + var actual = Program.ConvertToTitleCase(testStr); + + // Then + var expected = "Title Case"; + Assert.Equal(expected, actual); + } + + [Fact] + public void ConvertToTitleCase_Numbers() + { + // Given + var testStr = "NUMBER_3"; + + // When + var actual = Program.ConvertToTitleCase(testStr); + + // Then + var expected = "Number 3"; + Assert.Equal(expected, actual); + } + + [Fact] + public void ConvertToTitleCase_OtherChars() + { + // Given + var testStr = " TRUTH-TRACK "; + + // When + var actual = Program.ConvertToTitleCase(testStr); + + // Then + var expected = "Truth Track"; + Assert.Equal(expected, actual); + } + + [Fact] + public void ConvertToTitleCase_OtherChars2() + { + // Given + var testStr = "CASE-THREE_extra[chars]///"; + + // When + var actual = Program.ConvertToTitleCase(testStr); + + // Then + var expected = "Case Three Extra Chars"; + Assert.Equal(expected, actual); + } + + [Fact] + public void ConvertToTitleCase_Null() + { + // Given + string testStr = null; + + // When + Action action = () => Program.ConvertToTitleCase(testStr); + + // Then + Assert.Throws(action); + } + + // NOTE: I decided that an empty string should also throw an exception. + [Fact] + public void ConvertToTitleCase_Empty() + { + // Given + string testStr = string.Empty; + + // When + Action action = () => Program.ConvertToTitleCase(testStr); + + // Then + Assert.Throws(action); + } + + [Fact] + public void ConvertUnixToDateString_Simple() + { + // Given + var testStamp = 1604352245L; + + // When + var actual = Program.ConvertUnixToDateString(testStamp); + + // Then + var expected = "November 2, 2020"; + Assert.Equal(expected, actual); + } + + [Fact] + public void ConvertUnixToDateString_Null() + { + // Given + long? testStamp = null; + + // When + Action action = () => Program.ConvertUnixToDateString(testStamp); + + // Then + // NOTE: Modified this test to detect ArgumentNullException. + Assert.Throws(action); + } + + [Fact] + public void ConvertUnixToDateString_Original() + { + // Given + var testStamp = 1499144400; + + // When + var actual = Program.ConvertUnixToDateString(testStamp); + + // Then + var expected = "July 4, 2017"; + Assert.Equal(expected, actual); + } + + // Note: The following tests had their expected results generated using epochconverter.com. The assumption is that the time zone is GMT. + [Fact] + public void ConvertUnixToDateString_Zero() + { + // Given + var testStamp = 0; + + // When + var actual = Program.ConvertUnixToDateString(testStamp); + + // Then + var expected = "January 1, 1970"; + Assert.Equal(expected, actual); + } + + [Fact] + public void ConvertUnixToDateString_Negative() + { + // Given + var testStamp = -561600; + + // When + var actual = Program.ConvertUnixToDateString(testStamp); + + // Then + var expected = "December 25, 1969"; + Assert.Equal(expected, actual); + } + + // These datestamps are generated to be one second before and after midnight on May 21, 1982. This is to demonstrate that even a single digit difference in timestamp can result in a + // different date string. + [Fact] + public void ConvertUnixToDateString_OffByOne_1() + { + // Given + var testStamp = 390787200; + + // When + var actual = Program.ConvertUnixToDateString(testStamp); + + // Then + var expected = "May 21, 1982"; + Assert.Equal(expected, actual); + } + + [Fact] + public void ConvertUnixToDateString_OffByOne_2() + { + // Given + var testStamp = 390787199; + + // When + var actual = Program.ConvertUnixToDateString(testStamp); + + // Then + var expected = "May 20, 1982"; + Assert.Equal(expected, actual); + } + } } \ No newline at end of file