diff --git a/examples/csharp/csharp-courses_steps_csv-01_base/csharp-courses_steps_csv-01_base.sln b/examples/csharp/csharp-courses_steps_csv-01_base/csharp-courses_steps_csv-01_base.sln new file mode 100644 index 00000000..56a83fec --- /dev/null +++ b/examples/csharp/csharp-courses_steps_csv-01_base/csharp-courses_steps_csv-01_base.sln @@ -0,0 +1,56 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.6.30114.105 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{8B7D4918-2C37-4F16-B355-8EF19B1E23F8}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CoursesStepsCsv", "src\CoursesStepsCsv\CoursesStepsCsv.csproj", "{C6E9F888-08F3-4D4B-9AEB-919F615C988F}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{C8A13F5C-212F-4163-885A-01C093B26450}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CoursesStepsCsv.Tests", "test\CoursesStepsCsv.Tests\CoursesStepsCsv.Tests.csproj", "{C6D93799-5C86-410F-A957-1A531A757DAE}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {C6E9F888-08F3-4D4B-9AEB-919F615C988F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C6E9F888-08F3-4D4B-9AEB-919F615C988F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C6E9F888-08F3-4D4B-9AEB-919F615C988F}.Debug|x64.ActiveCfg = Debug|Any CPU + {C6E9F888-08F3-4D4B-9AEB-919F615C988F}.Debug|x64.Build.0 = Debug|Any CPU + {C6E9F888-08F3-4D4B-9AEB-919F615C988F}.Debug|x86.ActiveCfg = Debug|Any CPU + {C6E9F888-08F3-4D4B-9AEB-919F615C988F}.Debug|x86.Build.0 = Debug|Any CPU + {C6E9F888-08F3-4D4B-9AEB-919F615C988F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C6E9F888-08F3-4D4B-9AEB-919F615C988F}.Release|Any CPU.Build.0 = Release|Any CPU + {C6E9F888-08F3-4D4B-9AEB-919F615C988F}.Release|x64.ActiveCfg = Release|Any CPU + {C6E9F888-08F3-4D4B-9AEB-919F615C988F}.Release|x64.Build.0 = Release|Any CPU + {C6E9F888-08F3-4D4B-9AEB-919F615C988F}.Release|x86.ActiveCfg = Release|Any CPU + {C6E9F888-08F3-4D4B-9AEB-919F615C988F}.Release|x86.Build.0 = Release|Any CPU + {C6D93799-5C86-410F-A957-1A531A757DAE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C6D93799-5C86-410F-A957-1A531A757DAE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C6D93799-5C86-410F-A957-1A531A757DAE}.Debug|x64.ActiveCfg = Debug|Any CPU + {C6D93799-5C86-410F-A957-1A531A757DAE}.Debug|x64.Build.0 = Debug|Any CPU + {C6D93799-5C86-410F-A957-1A531A757DAE}.Debug|x86.ActiveCfg = Debug|Any CPU + {C6D93799-5C86-410F-A957-1A531A757DAE}.Debug|x86.Build.0 = Debug|Any CPU + {C6D93799-5C86-410F-A957-1A531A757DAE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C6D93799-5C86-410F-A957-1A531A757DAE}.Release|Any CPU.Build.0 = Release|Any CPU + {C6D93799-5C86-410F-A957-1A531A757DAE}.Release|x64.ActiveCfg = Release|Any CPU + {C6D93799-5C86-410F-A957-1A531A757DAE}.Release|x64.Build.0 = Release|Any CPU + {C6D93799-5C86-410F-A957-1A531A757DAE}.Release|x86.ActiveCfg = Release|Any CPU + {C6D93799-5C86-410F-A957-1A531A757DAE}.Release|x86.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {C6E9F888-08F3-4D4B-9AEB-919F615C988F} = {8B7D4918-2C37-4F16-B355-8EF19B1E23F8} + {C6D93799-5C86-410F-A957-1A531A757DAE} = {C8A13F5C-212F-4163-885A-01C093B26450} + EndGlobalSection +EndGlobal diff --git a/examples/csharp/csharp-courses_steps_csv-01_base/src/CoursesStepsCsv/CourseStepsGetController.cs b/examples/csharp/csharp-courses_steps_csv-01_base/src/CoursesStepsCsv/CourseStepsGetController.cs new file mode 100644 index 00000000..982f73b2 --- /dev/null +++ b/examples/csharp/csharp-courses_steps_csv-01_base/src/CoursesStepsCsv/CourseStepsGetController.cs @@ -0,0 +1,82 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text.Json; +using Microsoft.VisualBasic.FileIO; + +namespace CodelyTv.CoursesStepsCsv +{ + public sealed class CourseStepsGetController + { + private readonly Platform platform; + + public CourseStepsGetController(Platform platform) + { + this.platform = platform; + } + + public string Get(string courseId) + { + var csv = platform.FindCourseSteps(courseId); + + var results = "["; + + var lines = csv.Split(Environment.NewLine, StringSplitOptions.RemoveEmptyEntries); + + for (int i = 0; i < lines.Length; i++) + { + var row = lines[i].Split(','); + + var type = row[1]; + var duration = 0.0; + var points = 0.0; + + if (type == "video") + { + duration = int.Parse(row[3]) * 1.1; + } + + if (type == "quiz") + { + duration = int.Parse(row[2]) * 0.5; // 0.5 = time in minutes per question + } + + if (type != "video" && type != "quiz") + { + continue; + } + + if (type == "video") + { + points = int.Parse(row[3]) * 1.1 * 100; + } + + if (type == "quiz") + { + points = int.Parse(row[2]) * 0.5 * 10; + } + + var step = new Step + { + Id = row[0], + Type = row[1], + Duration = duration, + Points = points + }; + + results += JsonSerializer.Serialize(step, new JsonSerializerOptions + { + PropertyNamingPolicy = JsonNamingPolicy.CamelCase + }); + + if (i != lines.Length - 1) + { + results += ","; + } + } + results += "]"; + + return results; + } + } +} diff --git a/examples/csharp/csharp-courses_steps_csv-01_base/src/CoursesStepsCsv/CoursesStepsCsv.csproj b/examples/csharp/csharp-courses_steps_csv-01_base/src/CoursesStepsCsv/CoursesStepsCsv.csproj new file mode 100644 index 00000000..f208d303 --- /dev/null +++ b/examples/csharp/csharp-courses_steps_csv-01_base/src/CoursesStepsCsv/CoursesStepsCsv.csproj @@ -0,0 +1,7 @@ + + + + net5.0 + + + diff --git a/examples/csharp/csharp-courses_steps_csv-01_base/src/CoursesStepsCsv/Platform.cs b/examples/csharp/csharp-courses_steps_csv-01_base/src/CoursesStepsCsv/Platform.cs new file mode 100644 index 00000000..e9ef3120 --- /dev/null +++ b/examples/csharp/csharp-courses_steps_csv-01_base/src/CoursesStepsCsv/Platform.cs @@ -0,0 +1,9 @@ +using System; + +namespace CodelyTv.CoursesStepsCsv +{ + public interface Platform + { + string FindCourseSteps(string courseId); + } +} diff --git a/examples/csharp/csharp-courses_steps_csv-01_base/src/CoursesStepsCsv/Step.cs b/examples/csharp/csharp-courses_steps_csv-01_base/src/CoursesStepsCsv/Step.cs new file mode 100644 index 00000000..77a4b962 --- /dev/null +++ b/examples/csharp/csharp-courses_steps_csv-01_base/src/CoursesStepsCsv/Step.cs @@ -0,0 +1,11 @@ + +namespace CodelyTv.CoursesStepsCsv +{ + public sealed class Step + { + public string Id { get; set; } + public string Type { get; set; } + public double Duration { get; set; } + public double Points { get; set; } + } +} \ No newline at end of file diff --git a/examples/csharp/csharp-courses_steps_csv-01_base/test/CoursesStepsCsv.Tests/CourseStepsGetControllerShould.cs b/examples/csharp/csharp-courses_steps_csv-01_base/test/CoursesStepsCsv.Tests/CourseStepsGetControllerShould.cs new file mode 100644 index 00000000..2354645b --- /dev/null +++ b/examples/csharp/csharp-courses_steps_csv-01_base/test/CoursesStepsCsv.Tests/CourseStepsGetControllerShould.cs @@ -0,0 +1,63 @@ +using System; +using Xunit; +using Moq; + +namespace CodelyTv.CoursesStepsCsv.Tests +{ + public class CourseStepsGetControllerShould + { + private readonly Mock platform; + private readonly CourseStepsGetController courseStepsGetController; + public CourseStepsGetControllerShould() + { + platform = new Mock(); + courseStepsGetController = new CourseStepsGetController(platform.Object); + } + + [Fact] + public void ReturnEmptyStepList() + { + var courseId = "8fe17ce6-1d33-4b6b-a27c-4e0d1f870a19"; + var emptyCsv = ""; + + GivenPlatformReturnsCourseStepCsv(courseId, emptyCsv); + + var actualCourseSteps = courseStepsGetController.Get(courseId); + + Assert.Equal("[]", actualCourseSteps); + } + + [Fact] + public void ReturnExistingCourseSteps() + { + var courseId = "8fe17ce6-1d33-4b6b-a27c-4e0d1f870a19"; + var csv = String.Join( + Environment.NewLine, + "1,video,,13", + "2,quiz,5,"); + GivenPlatformReturnsCourseStepCsv(courseId, csv); + + var results = courseStepsGetController.Get(courseId); + + var expected = "[{\"id\":\"1\",\"type\":\"video\",\"duration\":14.3,\"points\":1430},{\"id\":\"2\",\"type\":\"quiz\",\"duration\":2.5,\"points\":25}]"; + Assert.Equal(expected, results); + } + + [Fact] + public void IgnoreStepsWithInvalidType() + { + var courseId = "8fe17ce6-1d33-4b6b-a27c-4e0d1f870a19"; + var csv = "1,survey,,13"; + GivenPlatformReturnsCourseStepCsv(courseId, csv); + + var results = courseStepsGetController.Get(courseId); + + Assert.Equal("[]", results); + } + + private void GivenPlatformReturnsCourseStepCsv(string courseId, string csv) + { + platform.Setup(x => x.FindCourseSteps(courseId)).Returns(csv); + } + } +} diff --git a/examples/csharp/csharp-courses_steps_csv-01_base/test/CoursesStepsCsv.Tests/CoursesStepsCsv.Tests.csproj b/examples/csharp/csharp-courses_steps_csv-01_base/test/CoursesStepsCsv.Tests/CoursesStepsCsv.Tests.csproj new file mode 100644 index 00000000..528458bd --- /dev/null +++ b/examples/csharp/csharp-courses_steps_csv-01_base/test/CoursesStepsCsv.Tests/CoursesStepsCsv.Tests.csproj @@ -0,0 +1,28 @@ + + + + net5.0 + CodelyTv.CoursesStepsCsv.Tests + + false + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + + diff --git a/examples/csharp/csharp-courses_steps_csv-02_semantics/csharp-courses_steps_csv-02_semantics.sln b/examples/csharp/csharp-courses_steps_csv-02_semantics/csharp-courses_steps_csv-02_semantics.sln new file mode 100644 index 00000000..56a83fec --- /dev/null +++ b/examples/csharp/csharp-courses_steps_csv-02_semantics/csharp-courses_steps_csv-02_semantics.sln @@ -0,0 +1,56 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.6.30114.105 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{8B7D4918-2C37-4F16-B355-8EF19B1E23F8}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CoursesStepsCsv", "src\CoursesStepsCsv\CoursesStepsCsv.csproj", "{C6E9F888-08F3-4D4B-9AEB-919F615C988F}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{C8A13F5C-212F-4163-885A-01C093B26450}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CoursesStepsCsv.Tests", "test\CoursesStepsCsv.Tests\CoursesStepsCsv.Tests.csproj", "{C6D93799-5C86-410F-A957-1A531A757DAE}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {C6E9F888-08F3-4D4B-9AEB-919F615C988F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C6E9F888-08F3-4D4B-9AEB-919F615C988F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C6E9F888-08F3-4D4B-9AEB-919F615C988F}.Debug|x64.ActiveCfg = Debug|Any CPU + {C6E9F888-08F3-4D4B-9AEB-919F615C988F}.Debug|x64.Build.0 = Debug|Any CPU + {C6E9F888-08F3-4D4B-9AEB-919F615C988F}.Debug|x86.ActiveCfg = Debug|Any CPU + {C6E9F888-08F3-4D4B-9AEB-919F615C988F}.Debug|x86.Build.0 = Debug|Any CPU + {C6E9F888-08F3-4D4B-9AEB-919F615C988F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C6E9F888-08F3-4D4B-9AEB-919F615C988F}.Release|Any CPU.Build.0 = Release|Any CPU + {C6E9F888-08F3-4D4B-9AEB-919F615C988F}.Release|x64.ActiveCfg = Release|Any CPU + {C6E9F888-08F3-4D4B-9AEB-919F615C988F}.Release|x64.Build.0 = Release|Any CPU + {C6E9F888-08F3-4D4B-9AEB-919F615C988F}.Release|x86.ActiveCfg = Release|Any CPU + {C6E9F888-08F3-4D4B-9AEB-919F615C988F}.Release|x86.Build.0 = Release|Any CPU + {C6D93799-5C86-410F-A957-1A531A757DAE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C6D93799-5C86-410F-A957-1A531A757DAE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C6D93799-5C86-410F-A957-1A531A757DAE}.Debug|x64.ActiveCfg = Debug|Any CPU + {C6D93799-5C86-410F-A957-1A531A757DAE}.Debug|x64.Build.0 = Debug|Any CPU + {C6D93799-5C86-410F-A957-1A531A757DAE}.Debug|x86.ActiveCfg = Debug|Any CPU + {C6D93799-5C86-410F-A957-1A531A757DAE}.Debug|x86.Build.0 = Debug|Any CPU + {C6D93799-5C86-410F-A957-1A531A757DAE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C6D93799-5C86-410F-A957-1A531A757DAE}.Release|Any CPU.Build.0 = Release|Any CPU + {C6D93799-5C86-410F-A957-1A531A757DAE}.Release|x64.ActiveCfg = Release|Any CPU + {C6D93799-5C86-410F-A957-1A531A757DAE}.Release|x64.Build.0 = Release|Any CPU + {C6D93799-5C86-410F-A957-1A531A757DAE}.Release|x86.ActiveCfg = Release|Any CPU + {C6D93799-5C86-410F-A957-1A531A757DAE}.Release|x86.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {C6E9F888-08F3-4D4B-9AEB-919F615C988F} = {8B7D4918-2C37-4F16-B355-8EF19B1E23F8} + {C6D93799-5C86-410F-A957-1A531A757DAE} = {C8A13F5C-212F-4163-885A-01C093B26450} + EndGlobalSection +EndGlobal diff --git a/examples/csharp/csharp-courses_steps_csv-02_semantics/src/CoursesStepsCsv/CourseStepsGetController.cs b/examples/csharp/csharp-courses_steps_csv-02_semantics/src/CoursesStepsCsv/CourseStepsGetController.cs new file mode 100644 index 00000000..a6f222a5 --- /dev/null +++ b/examples/csharp/csharp-courses_steps_csv-02_semantics/src/CoursesStepsCsv/CourseStepsGetController.cs @@ -0,0 +1,92 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text.Json; +using Microsoft.VisualBasic.FileIO; + +namespace CodelyTv.CoursesStepsCsv +{ + public sealed class CourseStepsGetController + { + private const double VIDEO_DURATION_PAUSES_MULTIPLIER = 1.1; + private const double QUIZ_TIME_PER_QUESTION_MULTIPLIER = 0.5; + private const int QUIZ_POINTS_PER_MINUTE = 10; + private const string STEP_TYPE_QUIZ = "quiz"; + private const string STEP_TYPE_VIDEO = "video"; + private const int VIDEO_POINTS_PER_MINUTE = 100; + private readonly Platform platform; + + public CourseStepsGetController(Platform platform) + { + this.platform = platform; + } + + public string Get(string courseId) + { + var csv = platform.FindCourseSteps(courseId); + + var results = "["; + + var lines = csv.Split(Environment.NewLine, StringSplitOptions.RemoveEmptyEntries); + + for (int i = 0; i < lines.Length; i++) + { + var row = lines[i].Split(','); + + var id = row[0]; + var type = row[1]; + int? quizTotalQuestions = string.IsNullOrEmpty(row[2]) ? null : int.Parse(row[2]); + int? videoDuration = string.IsNullOrEmpty(row[3]) ? null : int.Parse(row[3]); + + var stepDurationInMinutes = 0.0; + var points = 0.0; + + if (type == STEP_TYPE_VIDEO) + { + stepDurationInMinutes = videoDuration.Value * VIDEO_DURATION_PAUSES_MULTIPLIER; + } + + if (type == STEP_TYPE_QUIZ) + { + stepDurationInMinutes = quizTotalQuestions.Value * QUIZ_TIME_PER_QUESTION_MULTIPLIER; + } + + if (type != STEP_TYPE_VIDEO && type != STEP_TYPE_QUIZ) + { + continue; + } + + if (type == STEP_TYPE_VIDEO) + { + points = stepDurationInMinutes * VIDEO_POINTS_PER_MINUTE; + } + + if (type == STEP_TYPE_QUIZ) + { + points = stepDurationInMinutes * QUIZ_POINTS_PER_MINUTE; + } + + var step = new Step + { + Id = id, + Type = type, + Duration = stepDurationInMinutes, + Points = points + }; + + results += JsonSerializer.Serialize(step, new JsonSerializerOptions + { + PropertyNamingPolicy = JsonNamingPolicy.CamelCase + }); + + if (i != lines.Length - 1) + { + results += ","; + } + } + results += "]"; + + return results; + } + } +} diff --git a/examples/csharp/csharp-courses_steps_csv-02_semantics/src/CoursesStepsCsv/CoursesStepsCsv.csproj b/examples/csharp/csharp-courses_steps_csv-02_semantics/src/CoursesStepsCsv/CoursesStepsCsv.csproj new file mode 100644 index 00000000..f208d303 --- /dev/null +++ b/examples/csharp/csharp-courses_steps_csv-02_semantics/src/CoursesStepsCsv/CoursesStepsCsv.csproj @@ -0,0 +1,7 @@ + + + + net5.0 + + + diff --git a/examples/csharp/csharp-courses_steps_csv-02_semantics/src/CoursesStepsCsv/Platform.cs b/examples/csharp/csharp-courses_steps_csv-02_semantics/src/CoursesStepsCsv/Platform.cs new file mode 100644 index 00000000..e9ef3120 --- /dev/null +++ b/examples/csharp/csharp-courses_steps_csv-02_semantics/src/CoursesStepsCsv/Platform.cs @@ -0,0 +1,9 @@ +using System; + +namespace CodelyTv.CoursesStepsCsv +{ + public interface Platform + { + string FindCourseSteps(string courseId); + } +} diff --git a/examples/csharp/csharp-courses_steps_csv-02_semantics/src/CoursesStepsCsv/Step.cs b/examples/csharp/csharp-courses_steps_csv-02_semantics/src/CoursesStepsCsv/Step.cs new file mode 100644 index 00000000..77a4b962 --- /dev/null +++ b/examples/csharp/csharp-courses_steps_csv-02_semantics/src/CoursesStepsCsv/Step.cs @@ -0,0 +1,11 @@ + +namespace CodelyTv.CoursesStepsCsv +{ + public sealed class Step + { + public string Id { get; set; } + public string Type { get; set; } + public double Duration { get; set; } + public double Points { get; set; } + } +} \ No newline at end of file diff --git a/examples/csharp/csharp-courses_steps_csv-02_semantics/test/CoursesStepsCsv.Tests/CourseStepsGetControllerShould.cs b/examples/csharp/csharp-courses_steps_csv-02_semantics/test/CoursesStepsCsv.Tests/CourseStepsGetControllerShould.cs new file mode 100644 index 00000000..2354645b --- /dev/null +++ b/examples/csharp/csharp-courses_steps_csv-02_semantics/test/CoursesStepsCsv.Tests/CourseStepsGetControllerShould.cs @@ -0,0 +1,63 @@ +using System; +using Xunit; +using Moq; + +namespace CodelyTv.CoursesStepsCsv.Tests +{ + public class CourseStepsGetControllerShould + { + private readonly Mock platform; + private readonly CourseStepsGetController courseStepsGetController; + public CourseStepsGetControllerShould() + { + platform = new Mock(); + courseStepsGetController = new CourseStepsGetController(platform.Object); + } + + [Fact] + public void ReturnEmptyStepList() + { + var courseId = "8fe17ce6-1d33-4b6b-a27c-4e0d1f870a19"; + var emptyCsv = ""; + + GivenPlatformReturnsCourseStepCsv(courseId, emptyCsv); + + var actualCourseSteps = courseStepsGetController.Get(courseId); + + Assert.Equal("[]", actualCourseSteps); + } + + [Fact] + public void ReturnExistingCourseSteps() + { + var courseId = "8fe17ce6-1d33-4b6b-a27c-4e0d1f870a19"; + var csv = String.Join( + Environment.NewLine, + "1,video,,13", + "2,quiz,5,"); + GivenPlatformReturnsCourseStepCsv(courseId, csv); + + var results = courseStepsGetController.Get(courseId); + + var expected = "[{\"id\":\"1\",\"type\":\"video\",\"duration\":14.3,\"points\":1430},{\"id\":\"2\",\"type\":\"quiz\",\"duration\":2.5,\"points\":25}]"; + Assert.Equal(expected, results); + } + + [Fact] + public void IgnoreStepsWithInvalidType() + { + var courseId = "8fe17ce6-1d33-4b6b-a27c-4e0d1f870a19"; + var csv = "1,survey,,13"; + GivenPlatformReturnsCourseStepCsv(courseId, csv); + + var results = courseStepsGetController.Get(courseId); + + Assert.Equal("[]", results); + } + + private void GivenPlatformReturnsCourseStepCsv(string courseId, string csv) + { + platform.Setup(x => x.FindCourseSteps(courseId)).Returns(csv); + } + } +} diff --git a/examples/csharp/csharp-courses_steps_csv-02_semantics/test/CoursesStepsCsv.Tests/CoursesStepsCsv.Tests.csproj b/examples/csharp/csharp-courses_steps_csv-02_semantics/test/CoursesStepsCsv.Tests/CoursesStepsCsv.Tests.csproj new file mode 100644 index 00000000..528458bd --- /dev/null +++ b/examples/csharp/csharp-courses_steps_csv-02_semantics/test/CoursesStepsCsv.Tests/CoursesStepsCsv.Tests.csproj @@ -0,0 +1,28 @@ + + + + net5.0 + CodelyTv.CoursesStepsCsv.Tests + + false + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + + diff --git a/examples/csharp/csharp-courses_steps_csv-03_split_parsing_phase/csharp-courses_steps_csv-03_split_parsing_phase.sln b/examples/csharp/csharp-courses_steps_csv-03_split_parsing_phase/csharp-courses_steps_csv-03_split_parsing_phase.sln new file mode 100644 index 00000000..56a83fec --- /dev/null +++ b/examples/csharp/csharp-courses_steps_csv-03_split_parsing_phase/csharp-courses_steps_csv-03_split_parsing_phase.sln @@ -0,0 +1,56 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.6.30114.105 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{8B7D4918-2C37-4F16-B355-8EF19B1E23F8}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CoursesStepsCsv", "src\CoursesStepsCsv\CoursesStepsCsv.csproj", "{C6E9F888-08F3-4D4B-9AEB-919F615C988F}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{C8A13F5C-212F-4163-885A-01C093B26450}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CoursesStepsCsv.Tests", "test\CoursesStepsCsv.Tests\CoursesStepsCsv.Tests.csproj", "{C6D93799-5C86-410F-A957-1A531A757DAE}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {C6E9F888-08F3-4D4B-9AEB-919F615C988F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C6E9F888-08F3-4D4B-9AEB-919F615C988F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C6E9F888-08F3-4D4B-9AEB-919F615C988F}.Debug|x64.ActiveCfg = Debug|Any CPU + {C6E9F888-08F3-4D4B-9AEB-919F615C988F}.Debug|x64.Build.0 = Debug|Any CPU + {C6E9F888-08F3-4D4B-9AEB-919F615C988F}.Debug|x86.ActiveCfg = Debug|Any CPU + {C6E9F888-08F3-4D4B-9AEB-919F615C988F}.Debug|x86.Build.0 = Debug|Any CPU + {C6E9F888-08F3-4D4B-9AEB-919F615C988F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C6E9F888-08F3-4D4B-9AEB-919F615C988F}.Release|Any CPU.Build.0 = Release|Any CPU + {C6E9F888-08F3-4D4B-9AEB-919F615C988F}.Release|x64.ActiveCfg = Release|Any CPU + {C6E9F888-08F3-4D4B-9AEB-919F615C988F}.Release|x64.Build.0 = Release|Any CPU + {C6E9F888-08F3-4D4B-9AEB-919F615C988F}.Release|x86.ActiveCfg = Release|Any CPU + {C6E9F888-08F3-4D4B-9AEB-919F615C988F}.Release|x86.Build.0 = Release|Any CPU + {C6D93799-5C86-410F-A957-1A531A757DAE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C6D93799-5C86-410F-A957-1A531A757DAE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C6D93799-5C86-410F-A957-1A531A757DAE}.Debug|x64.ActiveCfg = Debug|Any CPU + {C6D93799-5C86-410F-A957-1A531A757DAE}.Debug|x64.Build.0 = Debug|Any CPU + {C6D93799-5C86-410F-A957-1A531A757DAE}.Debug|x86.ActiveCfg = Debug|Any CPU + {C6D93799-5C86-410F-A957-1A531A757DAE}.Debug|x86.Build.0 = Debug|Any CPU + {C6D93799-5C86-410F-A957-1A531A757DAE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C6D93799-5C86-410F-A957-1A531A757DAE}.Release|Any CPU.Build.0 = Release|Any CPU + {C6D93799-5C86-410F-A957-1A531A757DAE}.Release|x64.ActiveCfg = Release|Any CPU + {C6D93799-5C86-410F-A957-1A531A757DAE}.Release|x64.Build.0 = Release|Any CPU + {C6D93799-5C86-410F-A957-1A531A757DAE}.Release|x86.ActiveCfg = Release|Any CPU + {C6D93799-5C86-410F-A957-1A531A757DAE}.Release|x86.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {C6E9F888-08F3-4D4B-9AEB-919F615C988F} = {8B7D4918-2C37-4F16-B355-8EF19B1E23F8} + {C6D93799-5C86-410F-A957-1A531A757DAE} = {C8A13F5C-212F-4163-885A-01C093B26450} + EndGlobalSection +EndGlobal diff --git a/examples/csharp/csharp-courses_steps_csv-03_split_parsing_phase/src/CoursesStepsCsv/CourseStepsGetController.cs b/examples/csharp/csharp-courses_steps_csv-03_split_parsing_phase/src/CoursesStepsCsv/CourseStepsGetController.cs new file mode 100644 index 00000000..0c0afc40 --- /dev/null +++ b/examples/csharp/csharp-courses_steps_csv-03_split_parsing_phase/src/CoursesStepsCsv/CourseStepsGetController.cs @@ -0,0 +1,109 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text.Json; +using Microsoft.VisualBasic.FileIO; + +namespace CodelyTv.CoursesStepsCsv +{ + public sealed class CourseStepsGetController + { + private const double VIDEO_DURATION_PAUSES_MULTIPLIER = 1.1; + private const double QUIZ_TIME_PER_QUESTION_MULTIPLIER = 0.5; + private const int QUIZ_POINTS_PER_MINUTE = 10; + private const string STEP_TYPE_QUIZ = "quiz"; + private const string STEP_TYPE_VIDEO = "video"; + private const int VIDEO_POINTS_PER_MINUTE = 100; + private readonly Platform platform; + + public CourseStepsGetController(Platform platform) + { + this.platform = platform; + } + + public string Get(string courseId) + { + var csv = platform.FindCourseSteps(courseId); + List csvSteps = ParseCsv(csv); + + var results = "["; + + for (int i = 0; i < csvSteps.Count; i++) + { + var csvStep = csvSteps.ElementAt(i); + + var id = csvStep.StepId; + var type = csvStep.Type; + var quizTotalQuestions = csvStep.QuizTotalQuestions; + var videoDuration = csvStep.VideoDuration; + + var stepDurationInMinutes = 0.0; + var points = 0.0; + + if (type == STEP_TYPE_VIDEO) + { + stepDurationInMinutes = videoDuration.Value * VIDEO_DURATION_PAUSES_MULTIPLIER; + } + + if (type == STEP_TYPE_QUIZ) + { + stepDurationInMinutes = quizTotalQuestions.Value * QUIZ_TIME_PER_QUESTION_MULTIPLIER; + } + + if (type == STEP_TYPE_VIDEO) + { + points = stepDurationInMinutes * VIDEO_POINTS_PER_MINUTE; + } + + if (type == STEP_TYPE_QUIZ) + { + points = stepDurationInMinutes * QUIZ_POINTS_PER_MINUTE; + } + + var step = new Step(id, type, stepDurationInMinutes, points); + + results += JsonSerializer.Serialize(step, new JsonSerializerOptions + { + PropertyNamingPolicy = JsonNamingPolicy.CamelCase + }); + + if (i != csvSteps.Count - 1) + { + results += ","; + } + } + results += "]"; + + return results; + } + + private List ParseCsv(string csv) + { + var csvSteps = new List(); + + var lines = csv.Split(Environment.NewLine, StringSplitOptions.RemoveEmptyEntries); + + for (int i = 0; i < lines.Length; i++) + { + var row = lines[i].Split(','); + + var id = row[0]; + var type = row[1]; + int? quizTotalQuestions = string.IsNullOrEmpty(row[2]) ? null : int.Parse(row[2]); + int? videoDuration = string.IsNullOrEmpty(row[3]) ? null : int.Parse(row[3]); + + if (type != STEP_TYPE_VIDEO && type != STEP_TYPE_QUIZ) + { + continue; + } + + var csvStep = new CsvStep(id, type, quizTotalQuestions, videoDuration); + + csvSteps.Add(csvStep); + } + + return csvSteps; + } + } +} diff --git a/examples/csharp/csharp-courses_steps_csv-03_split_parsing_phase/src/CoursesStepsCsv/CoursesStepsCsv.csproj b/examples/csharp/csharp-courses_steps_csv-03_split_parsing_phase/src/CoursesStepsCsv/CoursesStepsCsv.csproj new file mode 100644 index 00000000..f208d303 --- /dev/null +++ b/examples/csharp/csharp-courses_steps_csv-03_split_parsing_phase/src/CoursesStepsCsv/CoursesStepsCsv.csproj @@ -0,0 +1,7 @@ + + + + net5.0 + + + diff --git a/examples/csharp/csharp-courses_steps_csv-03_split_parsing_phase/src/CoursesStepsCsv/CsvStep.cs b/examples/csharp/csharp-courses_steps_csv-03_split_parsing_phase/src/CoursesStepsCsv/CsvStep.cs new file mode 100644 index 00000000..57d508ee --- /dev/null +++ b/examples/csharp/csharp-courses_steps_csv-03_split_parsing_phase/src/CoursesStepsCsv/CsvStep.cs @@ -0,0 +1,19 @@ + +namespace CodelyTv.CoursesStepsCsv +{ + public sealed class CsvStep + { + public string StepId { get; } + public string Type { get; } + public double? QuizTotalQuestions { get; } + public double? VideoDuration { get; } + + public CsvStep(string stepId, string type, double? quizTotalQuestions, double? videoDuration) + { + StepId = stepId; + Type = type; + QuizTotalQuestions = quizTotalQuestions; + VideoDuration = videoDuration; + } + } +} \ No newline at end of file diff --git a/examples/csharp/csharp-courses_steps_csv-03_split_parsing_phase/src/CoursesStepsCsv/Platform.cs b/examples/csharp/csharp-courses_steps_csv-03_split_parsing_phase/src/CoursesStepsCsv/Platform.cs new file mode 100644 index 00000000..e9ef3120 --- /dev/null +++ b/examples/csharp/csharp-courses_steps_csv-03_split_parsing_phase/src/CoursesStepsCsv/Platform.cs @@ -0,0 +1,9 @@ +using System; + +namespace CodelyTv.CoursesStepsCsv +{ + public interface Platform + { + string FindCourseSteps(string courseId); + } +} diff --git a/examples/csharp/csharp-courses_steps_csv-03_split_parsing_phase/src/CoursesStepsCsv/Step.cs b/examples/csharp/csharp-courses_steps_csv-03_split_parsing_phase/src/CoursesStepsCsv/Step.cs new file mode 100644 index 00000000..6026404c --- /dev/null +++ b/examples/csharp/csharp-courses_steps_csv-03_split_parsing_phase/src/CoursesStepsCsv/Step.cs @@ -0,0 +1,19 @@ + +namespace CodelyTv.CoursesStepsCsv +{ + public sealed class Step + { + public string Id { get; } + public string Type { get; } + public double Duration { get; } + public double Points { get; } + + public Step(string id, string type, double duration, double points) + { + Id = id; + Type = type; + Duration = duration; + Points = points; + } + } +} \ No newline at end of file diff --git a/examples/csharp/csharp-courses_steps_csv-03_split_parsing_phase/test/CoursesStepsCsv.Tests/CourseStepsGetControllerShould.cs b/examples/csharp/csharp-courses_steps_csv-03_split_parsing_phase/test/CoursesStepsCsv.Tests/CourseStepsGetControllerShould.cs new file mode 100644 index 00000000..2354645b --- /dev/null +++ b/examples/csharp/csharp-courses_steps_csv-03_split_parsing_phase/test/CoursesStepsCsv.Tests/CourseStepsGetControllerShould.cs @@ -0,0 +1,63 @@ +using System; +using Xunit; +using Moq; + +namespace CodelyTv.CoursesStepsCsv.Tests +{ + public class CourseStepsGetControllerShould + { + private readonly Mock platform; + private readonly CourseStepsGetController courseStepsGetController; + public CourseStepsGetControllerShould() + { + platform = new Mock(); + courseStepsGetController = new CourseStepsGetController(platform.Object); + } + + [Fact] + public void ReturnEmptyStepList() + { + var courseId = "8fe17ce6-1d33-4b6b-a27c-4e0d1f870a19"; + var emptyCsv = ""; + + GivenPlatformReturnsCourseStepCsv(courseId, emptyCsv); + + var actualCourseSteps = courseStepsGetController.Get(courseId); + + Assert.Equal("[]", actualCourseSteps); + } + + [Fact] + public void ReturnExistingCourseSteps() + { + var courseId = "8fe17ce6-1d33-4b6b-a27c-4e0d1f870a19"; + var csv = String.Join( + Environment.NewLine, + "1,video,,13", + "2,quiz,5,"); + GivenPlatformReturnsCourseStepCsv(courseId, csv); + + var results = courseStepsGetController.Get(courseId); + + var expected = "[{\"id\":\"1\",\"type\":\"video\",\"duration\":14.3,\"points\":1430},{\"id\":\"2\",\"type\":\"quiz\",\"duration\":2.5,\"points\":25}]"; + Assert.Equal(expected, results); + } + + [Fact] + public void IgnoreStepsWithInvalidType() + { + var courseId = "8fe17ce6-1d33-4b6b-a27c-4e0d1f870a19"; + var csv = "1,survey,,13"; + GivenPlatformReturnsCourseStepCsv(courseId, csv); + + var results = courseStepsGetController.Get(courseId); + + Assert.Equal("[]", results); + } + + private void GivenPlatformReturnsCourseStepCsv(string courseId, string csv) + { + platform.Setup(x => x.FindCourseSteps(courseId)).Returns(csv); + } + } +} diff --git a/examples/csharp/csharp-courses_steps_csv-03_split_parsing_phase/test/CoursesStepsCsv.Tests/CoursesStepsCsv.Tests.csproj b/examples/csharp/csharp-courses_steps_csv-03_split_parsing_phase/test/CoursesStepsCsv.Tests/CoursesStepsCsv.Tests.csproj new file mode 100644 index 00000000..528458bd --- /dev/null +++ b/examples/csharp/csharp-courses_steps_csv-03_split_parsing_phase/test/CoursesStepsCsv.Tests/CoursesStepsCsv.Tests.csproj @@ -0,0 +1,28 @@ + + + + net5.0 + CodelyTv.CoursesStepsCsv.Tests + + false + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + + diff --git a/examples/csharp/csharp-courses_steps_csv-04_split_serialization_phase/csharp-courses_steps_csv-04_split_serialization_phase.sln b/examples/csharp/csharp-courses_steps_csv-04_split_serialization_phase/csharp-courses_steps_csv-04_split_serialization_phase.sln new file mode 100644 index 00000000..56a83fec --- /dev/null +++ b/examples/csharp/csharp-courses_steps_csv-04_split_serialization_phase/csharp-courses_steps_csv-04_split_serialization_phase.sln @@ -0,0 +1,56 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.6.30114.105 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{8B7D4918-2C37-4F16-B355-8EF19B1E23F8}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CoursesStepsCsv", "src\CoursesStepsCsv\CoursesStepsCsv.csproj", "{C6E9F888-08F3-4D4B-9AEB-919F615C988F}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{C8A13F5C-212F-4163-885A-01C093B26450}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CoursesStepsCsv.Tests", "test\CoursesStepsCsv.Tests\CoursesStepsCsv.Tests.csproj", "{C6D93799-5C86-410F-A957-1A531A757DAE}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {C6E9F888-08F3-4D4B-9AEB-919F615C988F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C6E9F888-08F3-4D4B-9AEB-919F615C988F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C6E9F888-08F3-4D4B-9AEB-919F615C988F}.Debug|x64.ActiveCfg = Debug|Any CPU + {C6E9F888-08F3-4D4B-9AEB-919F615C988F}.Debug|x64.Build.0 = Debug|Any CPU + {C6E9F888-08F3-4D4B-9AEB-919F615C988F}.Debug|x86.ActiveCfg = Debug|Any CPU + {C6E9F888-08F3-4D4B-9AEB-919F615C988F}.Debug|x86.Build.0 = Debug|Any CPU + {C6E9F888-08F3-4D4B-9AEB-919F615C988F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C6E9F888-08F3-4D4B-9AEB-919F615C988F}.Release|Any CPU.Build.0 = Release|Any CPU + {C6E9F888-08F3-4D4B-9AEB-919F615C988F}.Release|x64.ActiveCfg = Release|Any CPU + {C6E9F888-08F3-4D4B-9AEB-919F615C988F}.Release|x64.Build.0 = Release|Any CPU + {C6E9F888-08F3-4D4B-9AEB-919F615C988F}.Release|x86.ActiveCfg = Release|Any CPU + {C6E9F888-08F3-4D4B-9AEB-919F615C988F}.Release|x86.Build.0 = Release|Any CPU + {C6D93799-5C86-410F-A957-1A531A757DAE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C6D93799-5C86-410F-A957-1A531A757DAE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C6D93799-5C86-410F-A957-1A531A757DAE}.Debug|x64.ActiveCfg = Debug|Any CPU + {C6D93799-5C86-410F-A957-1A531A757DAE}.Debug|x64.Build.0 = Debug|Any CPU + {C6D93799-5C86-410F-A957-1A531A757DAE}.Debug|x86.ActiveCfg = Debug|Any CPU + {C6D93799-5C86-410F-A957-1A531A757DAE}.Debug|x86.Build.0 = Debug|Any CPU + {C6D93799-5C86-410F-A957-1A531A757DAE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C6D93799-5C86-410F-A957-1A531A757DAE}.Release|Any CPU.Build.0 = Release|Any CPU + {C6D93799-5C86-410F-A957-1A531A757DAE}.Release|x64.ActiveCfg = Release|Any CPU + {C6D93799-5C86-410F-A957-1A531A757DAE}.Release|x64.Build.0 = Release|Any CPU + {C6D93799-5C86-410F-A957-1A531A757DAE}.Release|x86.ActiveCfg = Release|Any CPU + {C6D93799-5C86-410F-A957-1A531A757DAE}.Release|x86.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {C6E9F888-08F3-4D4B-9AEB-919F615C988F} = {8B7D4918-2C37-4F16-B355-8EF19B1E23F8} + {C6D93799-5C86-410F-A957-1A531A757DAE} = {C8A13F5C-212F-4163-885A-01C093B26450} + EndGlobalSection +EndGlobal diff --git a/examples/csharp/csharp-courses_steps_csv-04_split_serialization_phase/src/CoursesStepsCsv/CourseStepsGetController.cs b/examples/csharp/csharp-courses_steps_csv-04_split_serialization_phase/src/CoursesStepsCsv/CourseStepsGetController.cs new file mode 100644 index 00000000..9f6ee88e --- /dev/null +++ b/examples/csharp/csharp-courses_steps_csv-04_split_serialization_phase/src/CoursesStepsCsv/CourseStepsGetController.cs @@ -0,0 +1,110 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text.Json; +using Microsoft.VisualBasic.FileIO; + +namespace CodelyTv.CoursesStepsCsv +{ + public sealed class CourseStepsGetController + { + private const double VIDEO_DURATION_PAUSES_MULTIPLIER = 1.1; + private const double QUIZ_TIME_PER_QUESTION_MULTIPLIER = 0.5; + private const int QUIZ_POINTS_PER_MINUTE = 10; + private const string STEP_TYPE_QUIZ = "quiz"; + private const string STEP_TYPE_VIDEO = "video"; + private const int VIDEO_POINTS_PER_MINUTE = 100; + private readonly Platform platform; + + public CourseStepsGetController(Platform platform) + { + this.platform = platform; + } + + public string Get(string courseId) + { + var csv = platform.FindCourseSteps(courseId); + List csvSteps = ParseCsv(csv); + List steps = CreateStepsFromPrimitives(csvSteps); + return ToJson(steps); + } + + private List ParseCsv(string csv) + { + var csvSteps = new List(); + + var lines = csv.Split(Environment.NewLine, StringSplitOptions.RemoveEmptyEntries); + + for (int i = 0; i < lines.Length; i++) + { + var row = lines[i].Split(','); + + var id = row[0]; + var type = row[1]; + int? quizTotalQuestions = string.IsNullOrEmpty(row[2]) ? null : int.Parse(row[2]); + int? videoDuration = string.IsNullOrEmpty(row[3]) ? null : int.Parse(row[3]); + + if (type != STEP_TYPE_VIDEO && type != STEP_TYPE_QUIZ) + { + continue; + } + + var csvStep = new CsvStep(id, type, quizTotalQuestions, videoDuration); + + csvSteps.Add(csvStep); + } + + return csvSteps; + } + + private static List CreateStepsFromPrimitives(List csvSteps) + { + var steps = new List(); + + csvSteps.ForEach(csvStep => + { + var id = csvStep.StepId; + var type = csvStep.Type; + var quizTotalQuestions = csvStep.QuizTotalQuestions; + var videoDuration = csvStep.VideoDuration; + + var stepDurationInMinutes = 0.0; + var points = 0.0; + + if (type == STEP_TYPE_VIDEO) + { + stepDurationInMinutes = videoDuration.Value * VIDEO_DURATION_PAUSES_MULTIPLIER; + } + + if (type == STEP_TYPE_QUIZ) + { + stepDurationInMinutes = quizTotalQuestions.Value * QUIZ_TIME_PER_QUESTION_MULTIPLIER; + } + + if (type == STEP_TYPE_VIDEO) + { + points = stepDurationInMinutes * VIDEO_POINTS_PER_MINUTE; + } + + if (type == STEP_TYPE_QUIZ) + { + points = stepDurationInMinutes * QUIZ_POINTS_PER_MINUTE; + } + + var step = new Step(id, type, stepDurationInMinutes, points); + + steps.Add(step); + }); + return steps; + } + + private static string ToJson(List steps) + { + return JsonSerializer.Serialize(steps, new JsonSerializerOptions + { + PropertyNamingPolicy = JsonNamingPolicy.CamelCase + }); + } + } +} diff --git a/examples/csharp/csharp-courses_steps_csv-04_split_serialization_phase/src/CoursesStepsCsv/CoursesStepsCsv.csproj b/examples/csharp/csharp-courses_steps_csv-04_split_serialization_phase/src/CoursesStepsCsv/CoursesStepsCsv.csproj new file mode 100644 index 00000000..f208d303 --- /dev/null +++ b/examples/csharp/csharp-courses_steps_csv-04_split_serialization_phase/src/CoursesStepsCsv/CoursesStepsCsv.csproj @@ -0,0 +1,7 @@ + + + + net5.0 + + + diff --git a/examples/csharp/csharp-courses_steps_csv-04_split_serialization_phase/src/CoursesStepsCsv/CsvStep.cs b/examples/csharp/csharp-courses_steps_csv-04_split_serialization_phase/src/CoursesStepsCsv/CsvStep.cs new file mode 100644 index 00000000..57d508ee --- /dev/null +++ b/examples/csharp/csharp-courses_steps_csv-04_split_serialization_phase/src/CoursesStepsCsv/CsvStep.cs @@ -0,0 +1,19 @@ + +namespace CodelyTv.CoursesStepsCsv +{ + public sealed class CsvStep + { + public string StepId { get; } + public string Type { get; } + public double? QuizTotalQuestions { get; } + public double? VideoDuration { get; } + + public CsvStep(string stepId, string type, double? quizTotalQuestions, double? videoDuration) + { + StepId = stepId; + Type = type; + QuizTotalQuestions = quizTotalQuestions; + VideoDuration = videoDuration; + } + } +} \ No newline at end of file diff --git a/examples/csharp/csharp-courses_steps_csv-04_split_serialization_phase/src/CoursesStepsCsv/Platform.cs b/examples/csharp/csharp-courses_steps_csv-04_split_serialization_phase/src/CoursesStepsCsv/Platform.cs new file mode 100644 index 00000000..e9ef3120 --- /dev/null +++ b/examples/csharp/csharp-courses_steps_csv-04_split_serialization_phase/src/CoursesStepsCsv/Platform.cs @@ -0,0 +1,9 @@ +using System; + +namespace CodelyTv.CoursesStepsCsv +{ + public interface Platform + { + string FindCourseSteps(string courseId); + } +} diff --git a/examples/csharp/csharp-courses_steps_csv-04_split_serialization_phase/src/CoursesStepsCsv/Step.cs b/examples/csharp/csharp-courses_steps_csv-04_split_serialization_phase/src/CoursesStepsCsv/Step.cs new file mode 100644 index 00000000..6026404c --- /dev/null +++ b/examples/csharp/csharp-courses_steps_csv-04_split_serialization_phase/src/CoursesStepsCsv/Step.cs @@ -0,0 +1,19 @@ + +namespace CodelyTv.CoursesStepsCsv +{ + public sealed class Step + { + public string Id { get; } + public string Type { get; } + public double Duration { get; } + public double Points { get; } + + public Step(string id, string type, double duration, double points) + { + Id = id; + Type = type; + Duration = duration; + Points = points; + } + } +} \ No newline at end of file diff --git a/examples/csharp/csharp-courses_steps_csv-04_split_serialization_phase/test/CoursesStepsCsv.Tests/CourseStepsGetControllerShould.cs b/examples/csharp/csharp-courses_steps_csv-04_split_serialization_phase/test/CoursesStepsCsv.Tests/CourseStepsGetControllerShould.cs new file mode 100644 index 00000000..2354645b --- /dev/null +++ b/examples/csharp/csharp-courses_steps_csv-04_split_serialization_phase/test/CoursesStepsCsv.Tests/CourseStepsGetControllerShould.cs @@ -0,0 +1,63 @@ +using System; +using Xunit; +using Moq; + +namespace CodelyTv.CoursesStepsCsv.Tests +{ + public class CourseStepsGetControllerShould + { + private readonly Mock platform; + private readonly CourseStepsGetController courseStepsGetController; + public CourseStepsGetControllerShould() + { + platform = new Mock(); + courseStepsGetController = new CourseStepsGetController(platform.Object); + } + + [Fact] + public void ReturnEmptyStepList() + { + var courseId = "8fe17ce6-1d33-4b6b-a27c-4e0d1f870a19"; + var emptyCsv = ""; + + GivenPlatformReturnsCourseStepCsv(courseId, emptyCsv); + + var actualCourseSteps = courseStepsGetController.Get(courseId); + + Assert.Equal("[]", actualCourseSteps); + } + + [Fact] + public void ReturnExistingCourseSteps() + { + var courseId = "8fe17ce6-1d33-4b6b-a27c-4e0d1f870a19"; + var csv = String.Join( + Environment.NewLine, + "1,video,,13", + "2,quiz,5,"); + GivenPlatformReturnsCourseStepCsv(courseId, csv); + + var results = courseStepsGetController.Get(courseId); + + var expected = "[{\"id\":\"1\",\"type\":\"video\",\"duration\":14.3,\"points\":1430},{\"id\":\"2\",\"type\":\"quiz\",\"duration\":2.5,\"points\":25}]"; + Assert.Equal(expected, results); + } + + [Fact] + public void IgnoreStepsWithInvalidType() + { + var courseId = "8fe17ce6-1d33-4b6b-a27c-4e0d1f870a19"; + var csv = "1,survey,,13"; + GivenPlatformReturnsCourseStepCsv(courseId, csv); + + var results = courseStepsGetController.Get(courseId); + + Assert.Equal("[]", results); + } + + private void GivenPlatformReturnsCourseStepCsv(string courseId, string csv) + { + platform.Setup(x => x.FindCourseSteps(courseId)).Returns(csv); + } + } +} diff --git a/examples/csharp/csharp-courses_steps_csv-04_split_serialization_phase/test/CoursesStepsCsv.Tests/CoursesStepsCsv.Tests.csproj b/examples/csharp/csharp-courses_steps_csv-04_split_serialization_phase/test/CoursesStepsCsv.Tests/CoursesStepsCsv.Tests.csproj new file mode 100644 index 00000000..528458bd --- /dev/null +++ b/examples/csharp/csharp-courses_steps_csv-04_split_serialization_phase/test/CoursesStepsCsv.Tests/CoursesStepsCsv.Tests.csproj @@ -0,0 +1,28 @@ + + + + net5.0 + CodelyTv.CoursesStepsCsv.Tests + + false + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + +