public void ActivityScheduleGrid_ValidSchedule_OnlyActivityDefinitionBlocks() { // Arrange - run schedule with successful data set List <ActivityDefinition> activityDefinitions = new List <ActivityDefinition>( _activityDefinitionService.GetActivityDefinition(DefaultSetName)); using (MemoryStream camperRequestStream = new MemoryStream(_validCamperRequestsBuffer)) { List <CamperRequests> camperRequests = CamperRequests.ReadCamperRequests( camperRequestStream, activityDefinitions); string scheduleId = "MySchedule"; _schedulerService.CreateSchedule(scheduleId, camperRequests, activityDefinitions); _localStorage.GetItemAsync <string>(Arg.Any <string>()) .Returns(Task.FromResult(scheduleId)); } // Act - load the grid component RenderedComponent <ActivityScheduleGrid> component = _host.AddComponent <ActivityScheduleGrid>(); // Assert List <HtmlNode> gridCells = component.FindAll("td") .Where(node => node.Attributes.AttributesWithName("data-name") .Any(a => a.Value.Equals("ActivityDefinition.Name"))).ToList(); Assert.That(gridCells, Has.Count.EqualTo(activityDefinitions.Count * 4), "Number of activity rows"); List <string> cellActivityNames = gridCells.Select(c => c.InnerText).Distinct().ToList(); Assert.That(cellActivityNames, Is.EquivalentTo(activityDefinitions.Select(ad => ad.Name)), "Activity row names"); }
public void ActivityScheduleGrid_ValidSchedule_NoCapacityErrorStyles() { // Arrange - run schedule with successful data set List <ActivityDefinition> activityDefinitions = new List <ActivityDefinition>( _activityDefinitionService.GetActivityDefinition(DefaultSetName)); using (MemoryStream camperRequestStream = new MemoryStream(_validCamperRequestsBuffer)) { List <CamperRequests> camperRequests = CamperRequests.ReadCamperRequests( camperRequestStream, activityDefinitions); string scheduleId = "MySchedule"; _schedulerService.CreateSchedule(scheduleId, camperRequests, activityDefinitions); _localStorage.GetItemAsync <string>(Arg.Any <string>()) .Returns(Task.FromResult(scheduleId)); } // Act - load the grid component RenderedComponent <ActivityScheduleGrid> component = _host.AddComponent <ActivityScheduleGrid>(); // Assert - none are marked over-subscribed or under-subscribed List <HtmlNode> countNodes = component.FindAll("td") .Where(node => node.Attributes.AttributesWithName("data-name") .Any(a => a.Value.Equals("AssignedCampers.Count"))).ToList(); List <string> countClass = countNodes .Select(node => node.Attributes["class"].Value) .ToList(); Assert.That(countClass, Has.None.Contains("capacity-over"), "Activity block styles"); Assert.That(countClass, Has.None.Contains("capacity-under"), "Activity block styles"); }
public async Task CamperScheduleGrid_SelectCamper_CamperActivitiesHilite() { // Arrange - run schedule with successful data set and load grid List <ActivityDefinition> activityDefinitions = new List <ActivityDefinition>( _activityDefinitionService.GetActivityDefinition(DefaultSetName)); List <ActivityDefinition> schedule; string scheduleId = "MySchedule"; using (MemoryStream camperRequestStream = new MemoryStream(_validCamperRequestsBuffer)) { List <CamperRequests> camperRequests = CamperRequests.ReadCamperRequests( camperRequestStream, activityDefinitions); schedule = _schedulerService.CreateSchedule(scheduleId, camperRequests, activityDefinitions); _localStorage.GetItemAsync <string>(Arg.Any <string>()) .Returns(Task.FromResult(scheduleId)); } RenderedComponent <CamperScheduleGrid> component = _host.AddComponent <CamperScheduleGrid>(); // Act - select a camper Camper selectedCamper = schedule.First().ScheduledBlocks.First() .AssignedCampers.First(); HtmlNode nameCell = component.FindAll("button") .First(node => node.InnerText.Equals(selectedCamper.FullName)); await nameCell.ClickAsync(); // Assert - load all the activity cells List <HtmlNode> activityCells = component.FindAll("select") .Where(node => node.Id.Contains('-')).ToList(); // Only Activity cells with an activity matching the selected camper in that slot // should have the selected-camper-activity List <HtmlNode> selectedActivityCells = activityCells.Where(node => node.Attributes.AttributesWithName("class") .Any(a => a.Value.Contains("selected-camper-activity"))).ToList(); Dictionary <int, string> selectedCamperActivities = selectedCamper.ScheduledBlocks .ToDictionary(b => b.TimeSlot, b => b.ActivityDefinition.Name); foreach (HtmlNode selectedActivityCell in selectedActivityCells) { int slotId = int.Parse(selectedActivityCell.Id.Split('-')[1]); Assert.That(selectedActivityCell.Attributes["value"].Value, Is.EqualTo(selectedCamperActivities[slotId]), $"{selectedActivityCell.Id}"); } List <HtmlNode> unselectedActivityCells = activityCells.Where(node => node.Attributes.AttributesWithName("class") .All(a => !a.Value.Contains("selected-camper-activity"))).ToList(); foreach (HtmlNode unselectedActivityCell in unselectedActivityCells) { int slotId = int.Parse(unselectedActivityCell.Id.Split('-')[1]); Assert.That(unselectedActivityCell.Attributes["value"].Value, Is.Not.EqualTo(selectedCamperActivities[slotId]), $"{unselectedActivityCell.Id}"); } }
public void CamperScheduleGrid_OverSubscribedSchedule_HasUnscheduledBlocks(int numberOfActivitiesToVerify) { // Arrange - run schedule with successful data set List <ActivityDefinition> activityDefinitions = new List <ActivityDefinition>( _activityDefinitionService.GetActivityDefinition(DefaultSetName)); List <ActivityDefinition> schedule; using (MemoryStream camperRequestStream = new MemoryStream(_overSubscribedCamperRequestsBuffer)) { List <CamperRequests> camperRequests = CamperRequests.ReadCamperRequests( camperRequestStream, activityDefinitions); string scheduleId = "MySchedule"; schedule = _schedulerService.CreateSchedule(scheduleId, camperRequests, activityDefinitions); _localStorage.GetItemAsync <string>(Arg.Any <string>()) .Returns(Task.FromResult(scheduleId)); } // Act - load the grid component RenderedComponent <CamperScheduleGrid> component = _host.AddComponent <CamperScheduleGrid>(); // Assert List <HtmlNode> nameCells = component.FindAll("td") .Where(node => node.Attributes.AttributesWithName("data-name") .Any(a => a.Value.Equals("FullName"))).ToList(); int numberOfCampers = 104; Assert.That(nameCells, Has.Count.EqualTo(numberOfCampers), "Number of camper rows"); ActivityDefinition unscheduledActivity = schedule.First(ad => ad.Name.Equals(SchedulerService.UnscheduledActivityName)); foreach (var activity in schedule.Take(numberOfActivitiesToVerify).Append(unscheduledActivity)) { for (int timeSlot = 0; timeSlot < ActivityBlock.MaximumTimeSlots; timeSlot++) { IActivityBlock activityBlock = activity.ScheduledBlocks.First( ab => ab.TimeSlot == timeSlot); foreach (var camper in activityBlock.AssignedCampers) { string camperSlotId = $"{camper.FullName}-{timeSlot}"; List <HtmlNode> camperSlotCells = component.FindAll("select") .Where(node => node.Attributes.AttributesWithName("id") .Any(a => a.Value.Equals(camperSlotId))).ToList(); Assert.That(camperSlotCells, Has.Count.EqualTo(1), $"Number of camper slots for Id = {camperSlotId}"); List <HtmlAttribute> valueAttributes = camperSlotCells[0].Attributes .AttributesWithName("value").ToList(); Assert.That(valueAttributes, Has.Count.EqualTo(1), $"Number of value attributes on selector for ID={camperSlotId}"); Assert.That(valueAttributes[0].Value, Is.EqualTo(activity.Name), "Selected activity"); } } } }
public void ReadCamperRequests_UnknownActivity_returnsNull() { // Act List <CamperRequests> camperRequests = CamperRequests.ReadCamperRequests(GoodFileLocation, ActivityDefinitionTests.IncompleteActivityDefinitions, _logger); // Assert Assert.That(camperRequests, Is.Null, "Return from ReadCamperRequests"); }
public void ReadCamperRequests_invalidRequestFile_returnsNull() { // Act List <CamperRequests> camperRequests = CamperRequests.ReadCamperRequests(BadContentFileLocation, ActivityDefinitionTests.DefaultActivityDefinitions, _logger); // Assert Assert.That(camperRequests, Is.Null, "Return from ReadCamperRequests"); }
public async Task ActivityScheduleGrid_SelectCamperActivity_AllActivitiesForCamperGroupHilited() { // Arrange - run schedule with successful data set List <ActivityDefinition> activityDefinitions = new List <ActivityDefinition>( _activityDefinitionService.GetActivityDefinition(DefaultSetName)); List <CamperRequests> camperRequests; string scheduleId = "MySchedule"; using (MemoryStream camperRequestStream = new MemoryStream(_validCamperRequestsBuffer)) { camperRequests = CamperRequests.ReadCamperRequests( camperRequestStream, activityDefinitions); _schedulerService.CreateSchedule(scheduleId, camperRequests, activityDefinitions); _localStorage.GetItemAsync <string>(Arg.Any <string>()) .Returns(Task.FromResult(scheduleId)); } // Find a camper in a camper group List <HashSet <Camper> > camperGroups = _schedulerService.GetCamperGroupsForScheduleId(scheduleId); HashSet <Camper> selectedCamperGroup = camperGroups.First(); // Pick a camper with a full name in the group Camper selectedCamper = selectedCamperGroup.First(c => !string.IsNullOrEmpty(c.FirstName)); RenderedComponent <ActivityScheduleGrid> component = _host.AddComponent <ActivityScheduleGrid>(); List <HtmlNode> camperActivityCells = component.FindAll("td") .Where(node => node.Attributes.AttributesWithName("title") .Any(a => a.Value.Equals(selectedCamper.FullName))).ToList(); Assert.That(camperActivityCells, Has.Count.EqualTo(4), "Number of camper activity cells"); // Act - Click on the block 0 for the next activity HtmlNode clickTarget = camperActivityCells.First(); await clickTarget.ClickAsync(); // Assert - schedule has camper selected Assert.That(component.Instance.SelectedCamperGroup, Is.EqualTo(selectedCamperGroup), "Selected Camper Group"); // Verify that all activity cells for the camper group are selected List <HtmlNode> selectedCamperGroupActivityCells = component.FindAll("td") .Where(node => node.Attributes.AttributesWithName("class") .Any(a => a.Value.Contains("selected-camper-group"))).ToList(); // The selected camper does not get selected-camper-group, only his peers Assert.That(selectedCamperGroupActivityCells, Has.Count.EqualTo(4 * (selectedCamperGroup.Count - 1)), "Selected activity cells"); // Check that each peer has 4 cells in the selected group set. foreach (Camper camper in selectedCamperGroup.Where(c => c != selectedCamper)) { Assert.That(selectedCamperGroupActivityCells.Count(c => c.Attributes["title"].Value.Split(',')[0].Equals(camper.LastName)), Is.EqualTo(4), $"Activities for camper {camper.FullName}"); } }
public void ReadCamperRequests_validInput_loadsList() { // Act List <CamperRequests> camperRequests = CamperRequests.ReadCamperRequests(GoodFileLocation, ActivityDefinitionTests.DefaultActivityDefinitions, _logger); // Assert Assert.That(camperRequests, Is.Not.Null, "Return from ReadCamperRequests"); Assert.That(camperRequests.Count, Is.EqualTo(98), "Number of camper requests"); }
public async Task CamperScheduleGrid_SelectCamper_CamperGroupRowsHilite() { // Arrange - run schedule with successful data set and load grid List <ActivityDefinition> activityDefinitions = new List <ActivityDefinition>( _activityDefinitionService.GetActivityDefinition(DefaultSetName)); List <ActivityDefinition> schedule; string scheduleId = "MySchedule"; using (MemoryStream camperRequestStream = new MemoryStream(_validCamperRequestsBuffer)) { List <CamperRequests> camperRequests = CamperRequests.ReadCamperRequests( camperRequestStream, activityDefinitions); schedule = _schedulerService.CreateSchedule(scheduleId, camperRequests, activityDefinitions); _localStorage.GetItemAsync <string>(Arg.Any <string>()) .Returns(Task.FromResult(scheduleId)); } RenderedComponent <CamperScheduleGrid> component = _host.AddComponent <CamperScheduleGrid>(); // Act - select a camper // Find a camper in a camper group List <HashSet <Camper> > camperGroups = _schedulerService.GetCamperGroupsForScheduleId(scheduleId); HashSet <Camper> selectedCamperGroup = camperGroups.First(); // Pick a camper with a full name in the group Camper selectedCamper = selectedCamperGroup.First(c => !string.IsNullOrEmpty(c.FirstName)); HtmlNode nameCell = component.FindAll("button") .First(node => node.InnerText.Equals(selectedCamper.FullName)); await nameCell.ClickAsync(); // Assert - load the row and verify it has the selected-camper-group class List <HtmlNode> selectedCamperGroupRows = component.FindAll("tr") .Where(node => node.Attributes.AttributesWithName("class") .Any(a => a.Value.Contains("selected-camper-group"))).ToList(); // The selected camper does not get selected-camper-group, only his peers Assert.That(selectedCamperGroupRows, Has.Count.EqualTo(selectedCamperGroup.Count - 1), "Selected camper group rows"); // Check that each peer has a row in the set. Need to strip it down to the last names // because the group has incomplete names List <string> selectedCamperGroupLastNames = selectedCamperGroupRows.Select(g => g.Elements("td").First(n => n.Attributes.Any(a => a.Name.Equals("data-name") && a.Value.Equals("FullName"))) .InnerText.Split(',')[0]).ToList(); foreach (Camper camper in selectedCamperGroup.Where(c => c != selectedCamper)) { Assert.That(selectedCamperGroupLastNames, Has.One.EqualTo(camper.LastName), "Camper row name"); } }
public void CamperScheduleGrid_ChangeCamperActivity_ScheduleIsUpdated(int camperIndex, int timeSlot) { // Arrange - run schedule with successful data set List <ActivityDefinition> activityDefinitions = new List <ActivityDefinition>( _activityDefinitionService.GetActivityDefinition(DefaultSetName)); List <ActivityDefinition> schedule; string scheduleId = "MySchedule"; using (MemoryStream camperRequestStream = new MemoryStream(_validCamperRequestsBuffer)) { List <CamperRequests> camperRequests = CamperRequests.ReadCamperRequests( camperRequestStream, activityDefinitions); schedule = _schedulerService.CreateSchedule(scheduleId, camperRequests, activityDefinitions); _localStorage.GetItemAsync <string>(Arg.Any <string>()) .Returns(Task.FromResult(scheduleId)); } // Act - load the grid component and update a camper RenderedComponent <CamperScheduleGrid> component = _host.AddComponent <CamperScheduleGrid>(); List <string> fullNames = component.FindAll("td") .Where(node => node.Attributes.AttributesWithName("data-name") .Any(a => a.Value.Equals("FullName"))) .Select(node => node.InnerText).ToList(); string camperSlotId = $"{fullNames[camperIndex]}-{timeSlot}"; List <HtmlNode> camperSlotCells = component.FindAll("select") .Where(node => node.Attributes.AttributesWithName("id") .Any(a => a.Value.Equals(camperSlotId))).ToList(); List <HtmlAttribute> valueAttributes = camperSlotCells[0].Attributes .AttributesWithName("value").ToList(); string originalActivityName = valueAttributes[0].Value; string updatedActivityName = schedule[0].Name == originalActivityName ? schedule[1].Name : schedule[0].Name; camperSlotCells[0].Change(updatedActivityName); // Assert // Reload the schedule and verify the camper has changed the activity. List <ActivityDefinition> updatedSchedule = _schedulerService.GetSchedule(scheduleId); Assert.That(updatedSchedule.First(ad => ad.Name.Equals(originalActivityName)) .ScheduledBlocks[timeSlot].AssignedCampers.Select(c => c.FullName), Has.None.EqualTo(fullNames[camperIndex]), "Source activity camper list"); Assert.That(updatedSchedule.First(ad => ad.Name.Equals(updatedActivityName)) .ScheduledBlocks[timeSlot].AssignedCampers.Select(c => c.FullName), Has.One.EqualTo(fullNames[camperIndex]), "Target activity camper list"); }
/// <summary> /// Generate a schedule from the built-in test data for camper requests. /// </summary> /// <returns>A successful schedule from the built-in test data</returns> private (List <ActivityDefinition> activityDefinitions, List <HashSet <Camper> > camperGroups) GenerateSchedule() { Assembly assembly = typeof(SchedulerServiceTests).Assembly; using (Stream camperRequestFile = assembly.GetManifestResourceStream( "ActivitySchedulerFrontEnd.Tests.CamperRequests.csv")) { List <ActivityDefinition> activityDefinitions = _activityDefinitionService.GetActivityDefinition( DefaultActivitySetName).ToList(); List <CamperRequests> camperRequests = CamperRequests.ReadCamperRequests(camperRequestFile, activityDefinitions); Scheduler.ScheduleActivities(camperRequests, false, _logger); List <HashSet <Camper> > camperGroups = CamperRequests.GenerateCamperMateGroups(camperRequests); // Activity definitions now has the schedule return(activityDefinitions, camperGroups); } }
public async Task ActivityScheduleGrid_SelectCamperActivity_AllActivitiesForCamperHilited() { // Arrange - run schedule with successful data set List <ActivityDefinition> activityDefinitions = new List <ActivityDefinition>( _activityDefinitionService.GetActivityDefinition(DefaultSetName)); List <CamperRequests> camperRequests; string scheduleId = "MySchedule"; using (MemoryStream camperRequestStream = new MemoryStream(_validCamperRequestsBuffer)) { camperRequests = CamperRequests.ReadCamperRequests( camperRequestStream, activityDefinitions); _schedulerService.CreateSchedule(scheduleId, camperRequests, activityDefinitions); _localStorage.GetItemAsync <string>(Arg.Any <string>()) .Returns(Task.FromResult(scheduleId)); } RenderedComponent <ActivityScheduleGrid> component = _host.AddComponent <ActivityScheduleGrid>(); List <HtmlNode> camperActivityCells = component.FindAll("td") .Where(node => node.Attributes.AttributesWithName("class") .Any(a => a.Value.Contains("activity-camper-cell"))).ToList(); Assert.That(camperActivityCells, Has.Count.EqualTo(camperRequests.Count() * 4), "Number of camper activity cells"); // Act - Click on the block 0 for the next activity HtmlNode clickTarget = camperActivityCells.First(); await clickTarget.ClickAsync(); // Assert - schedule has camper selected Assert.That(component.Instance.SelectedCamper?.FullName, Is.EqualTo(clickTarget.Attributes["title"].Value), "Selected Camper Name"); // Verify that all activity cells for the camper are selected List <HtmlNode> selectedCamperActivityCells = component.FindAll("td") .Where(node => node.Attributes.AttributesWithName("class") .Any(a => a.Value.Contains("selected-camper"))).ToList(); Assert.That(selectedCamperActivityCells, Has.Count.EqualTo(4), "Selected activity cells"); Assert.That(selectedCamperActivityCells.Select(c => c.Attributes["title"].Value), Has.All.EqualTo(component.Instance.SelectedCamper?.FullName), "Selected cell camper names"); }
public void ActivityScheduleGrid_OverSubscribedSchedule_HasUnscheduledBlocks() { // Arrange - run schedule with successful data set List <ActivityDefinition> activityDefinitions = new List <ActivityDefinition>( _activityDefinitionService.GetActivityDefinition(DefaultSetName)); using (MemoryStream camperRequestStream = new MemoryStream(_overSubscribedCamperRequestsBuffer)) { List <CamperRequests> camperRequests = CamperRequests.ReadCamperRequests( camperRequestStream, activityDefinitions); string scheduleId = "MySchedule"; _schedulerService.CreateSchedule(scheduleId, camperRequests, activityDefinitions); _localStorage.GetItemAsync <string>(Arg.Any <string>()) .Returns(Task.FromResult(scheduleId)); } // Act - load the grid component RenderedComponent <ActivityScheduleGrid> component = _host.AddComponent <ActivityScheduleGrid>(); // Assert - activity definition has a new activity for unscheduled List <string> originalActivityNames = _activityDefinitionService.GetActivityDefinition(DefaultSetName) .Select(ad => ad.Name).ToList(); List <string> addedActivityNames = activityDefinitions.Select(ad => ad.Name) .Except(originalActivityNames).ToList(); Assert.That(addedActivityNames, Has.Count.EqualTo(1), "Number of activity definitions added by scheduling"); Assert.That(addedActivityNames[0], Is.EqualTo(SchedulerService.UnscheduledActivityName), "Name of activity added by scheduling"); // Check that all of the activities included the added 1 are on the grid List <HtmlNode> gridCells = component.FindAll("td") .Where(node => node.Attributes.AttributesWithName("data-name") .Any(a => a.Value.Equals("ActivityDefinition.Name"))).ToList(); Assert.That(gridCells, Has.Count.EqualTo(activityDefinitions.Count * 4), "Number of activity rows"); List <string> cellActivityNames = gridCells.Select(c => c.InnerText).Distinct().ToList(); Assert.That(cellActivityNames, Is.EquivalentTo(activityDefinitions.Select(ad => ad.Name)), "Activity row names"); }
protected void SetUpApplicationServices() { LoadTestCamperRequests(); // Arrange - use constructor to create directory with 1 file. ILogger <ActivityDefinitionService> logger = Substitute.For <ILogger <ActivityDefinitionService> >(); ActivityDefinitionService activityDefinitionService = new ActivityDefinitionService(_applicationName, logger); // Create a couple copies of the default. List <string> expectedActivitySets = new List <string> { DefaultSetName, "AnotherSet", "OneMore" }; List <ActivityDefinition> activityDefinitions = new List <ActivityDefinition>( activityDefinitionService.GetActivityDefinition(DefaultSetName)); _expectedActivitySets.Add(DefaultSetName, new List <ActivityDefinition>(activityDefinitions)); foreach (string addSet in expectedActivitySets.Skip(1)) { activityDefinitions.RemoveAt(0); string content = ActivityDefinition.WriteActivityDefinitionsToString(activityDefinitions, logger); File.WriteAllText($"{ApplicationDirectoryInfo.FullName}\\{addSet}.xml", content); _expectedActivitySets.Add(addSet, new List <ActivityDefinition>(activityDefinitions)); } ISchedulerService preloadScheduler = new SchedulerService(_applicationName, Substitute.For <ILogger <SchedulerService> >()); using (MemoryStream camperRequestStream = new MemoryStream(_validCamperRequestsBuffer)) { activityDefinitions = activityDefinitionService.GetActivityDefinition( DefaultSetName).ToList(); List <CamperRequests> camperRequests = CamperRequests.ReadCamperRequests( camperRequestStream, activityDefinitions); preloadScheduler.CreateSchedule(PrebuiltScheduleId, camperRequests, activityDefinitions); } _schedulerService = new SchedulerService(_applicationName, Substitute.For <ILogger <SchedulerService> >()); _activityDefinitionService = new ActivityDefinitionService(_applicationName, logger); }
/// <summary> /// Create a camper with a set of requests. /// </summary> /// <param name="name">Text to create a camper name from</param> /// <param name="activityRequests">Set of activity requests</param> /// <param name="alternateActivity">An alternate activity</param> /// <returns></returns> private CamperRequests BuildCamper(string name, IEnumerable <ActivityDefinition> activityRequests, ActivityDefinition alternateActivity) { int rank = 1; var theCamper = new Camper { FirstName = $"{name}", LastName = $"{name}" }; var camperRequests = new CamperRequests { Camper = theCamper, ActivityRequests = new List <ActivityRequest>(activityRequests .Select(ar => new ActivityRequest { Rank = rank++, Activity = ar })), AlternateActivity = alternateActivity }; return(camperRequests); }
public List <ActivityDefinition> CreateSchedule(string scheduleId, List <CamperRequests> camperRequests, List <ActivityDefinition> activityDefinitions) { List <CamperRequests> unscheduledCamperRequests = Scheduler.ScheduleActivities(camperRequests, activityDefinitions, _logger); if (unscheduledCamperRequests.Any()) { // Put the unscheduled blocks into a special unscheduled activity ActivityDefinition unscheduledActivity = new ActivityDefinition { Name = UnscheduledActivityName, MaximumCapacity = int.MaxValue, OptimalCapacity = 0 }; unscheduledActivity.PreloadBlocks(); foreach (Camper unscheduledCamper in unscheduledCamperRequests.Select(cr => cr.Camper)) { int[] blockIds = { 0, 1, 2, 3 }; foreach (int unscheduledBlockId in blockIds .Except(unscheduledCamper.ScheduledBlocks.Select(b => b.TimeSlot))) { unscheduledActivity.TryAssignCamperToExistingActivityBlock(unscheduledCamper, false); } } // Put unscheduled activity at the top of the grid activityDefinitions.Insert(0, unscheduledActivity); } // Generate the schedule ID from the date. _schedulesById[scheduleId] = activityDefinitions; // Generate the camper groups List <HashSet <Camper> > camperGroups = CamperRequests.GenerateCamperMateGroups(camperRequests); _camperGroupsByScheduleId[scheduleId] = camperGroups; UpdateSchedule(scheduleId, activityDefinitions, camperGroups); return(activityDefinitions); }
public void ActivityScheduleGrid_StartDragOfCamper_PayloadUpdated() { // Arrange - run schedule with successful data set List <ActivityDefinition> activityDefinitions = new List <ActivityDefinition>( _activityDefinitionService.GetActivityDefinition(DefaultSetName)); List <CamperRequests> camperRequests; using (MemoryStream camperRequestStream = new MemoryStream(_validCamperRequestsBuffer)) { camperRequests = CamperRequests.ReadCamperRequests( camperRequestStream, activityDefinitions); string scheduleId = "MySchedule"; _schedulerService.CreateSchedule(scheduleId, camperRequests, activityDefinitions); _localStorage.GetItemAsync <string>(Arg.Any <string>()) .Returns(Task.FromResult(scheduleId)); } RenderedComponent <ActivityScheduleGrid> component = _host.AddComponent <ActivityScheduleGrid>(); // Act - Start a drag on a camper activity cell List <HtmlNode> camperActivityCells = component.FindAll("td") .Where(node => node.Attributes.AttributesWithName("class") .Any(a => a.Value.Contains("activity-camper-cell"))).ToList(); Assert.That(camperActivityCells, Has.Count.EqualTo(camperRequests.Count() * 4), "Number of camper activity cells"); camperActivityCells[0].TriggerEventAsync("ondragstart", new DragEventArgs()); // Assert - Grid pay load is set. // The first cell should be archery block 0 Assert.That(component.Instance.DragPayload.ActivityName, Is.EqualTo("Archery"), "Drag payload activity name"); Assert.That(component.Instance.DragPayload.TimeSlot, Is.EqualTo(0), "Drag pay load time slot"); Assert.That(component.Instance.DragPayload.CamperName, Is.Not.Null, "Drag pay load camper name"); }
public async Task CamperScheduleGrid_SelectCamper_CamperRowHilite() { // Arrange - run schedule with successful data set and load grid List <ActivityDefinition> activityDefinitions = new List <ActivityDefinition>( _activityDefinitionService.GetActivityDefinition(DefaultSetName)); List <ActivityDefinition> schedule; using (MemoryStream camperRequestStream = new MemoryStream(_validCamperRequestsBuffer)) { List <CamperRequests> camperRequests = CamperRequests.ReadCamperRequests( camperRequestStream, activityDefinitions); string scheduleId = "MySchedule"; schedule = _schedulerService.CreateSchedule(scheduleId, camperRequests, activityDefinitions); _localStorage.GetItemAsync <string>(Arg.Any <string>()) .Returns(Task.FromResult(scheduleId)); } RenderedComponent <CamperScheduleGrid> component = _host.AddComponent <CamperScheduleGrid>(); // Act - select a camper Camper selectedCamper = schedule.First().ScheduledBlocks.First() .AssignedCampers.First(); HtmlNode nameCell = component.FindAll("button") .First(node => node.InnerText.Equals(selectedCamper.FullName)); await nameCell.ClickAsync(); // Assert - load the row and verify it has the selected-camper class List <HtmlNode> selectedCamperRows = component.FindAll("tr") .Where(node => node.Attributes.AttributesWithName("class") .Any(a => a.Value.Contains("selected-camper"))).ToList(); Assert.That(selectedCamperRows, Has.Count.EqualTo(1), "Selected camper rows"); Assert.That(selectedCamperRows[0].Elements("td").First(n => n.Attributes.Any(a => a.Name.Equals("data-name") && a.Value.Equals("FullName"))).InnerText, Is.EqualTo(selectedCamper.FullName), "Camper row name"); }
public void GenerateCamperMateGroups_ValidInput_GeneratesExpectedList() { // Arrange load the known good camper list List <CamperRequests> camperRequests = CamperRequests.ReadCamperRequests(GoodFileLocation, ActivityDefinitionTests.DefaultActivityDefinitions, _logger); // Act - Generate the camper groups List <HashSet <Camper> > camperMateGroups = CamperRequests.GenerateCamperMateGroups(camperRequests); // Assert Assert.That(camperMateGroups, Is.Not.Null, "camperMateGroups"); List <HashSet <Camper> > expectedCamperMateGroups = new List <HashSet <Camper> > { { new HashSet <Camper> { new Camper { LastName = "A" }, new Camper { LastName = "S" }, new Camper { LastName = "E" }, new Camper { LastName = "O" }, new Camper { LastName = "X" }, new Camper { LastName = "AC" }, new Camper { LastName = "AM" }, new Camper { LastName = "AS" }, new Camper { LastName = "AX" }, new Camper { LastName = "BC" }, new Camper { LastName = "BF" }, new Camper { LastName = "BK" }, new Camper { LastName = "BN" }, new Camper { LastName = "CA" }, new Camper { LastName = "CH" }, new Camper { LastName = "CJ" }, new Camper { LastName = "CK" }, new Camper { LastName = "CR" }, new Camper { LastName = "D" }, new Camper { LastName = "R" }, new Camper { LastName = "AN" }, new Camper { LastName = "BG" }, new Camper { LastName = "CB" }, new Camper { LastName = "CL" } } }, { new HashSet <Camper> { new Camper { LastName = "B" }, new Camper { LastName = "U" }, new Camper { LastName = "V" }, new Camper { LastName = "Z" }, new Camper { LastName = "AA" }, new Camper { LastName = "AK" }, new Camper { LastName = "AT" }, new Camper { LastName = "BM" }, new Camper { LastName = "CG" }, new Camper { LastName = "CI" } } }, { new HashSet <Camper> { new Camper { LastName = "C" }, new Camper { LastName = "Y" }, new Camper { LastName = "T" }, new Camper { LastName = "AE" }, new Camper { LastName = "AH" }, new Camper { LastName = "AI" }, new Camper { LastName = "AR" }, new Camper { LastName = "AZ" }, new Camper { LastName = "BL" }, new Camper { LastName = "BR" }, new Camper { LastName = "CF" } } }, { new HashSet <Camper> { new Camper { LastName = "G" }, new Camper { LastName = "F" }, new Camper { LastName = "N" }, new Camper { LastName = "BD" }, new Camper { LastName = "BS" }, new Camper { LastName = "CC" }, new Camper { LastName = "CS" }, new Camper { LastName = "I" } } }, { new HashSet <Camper> { new Camper { LastName = "K" }, new Camper { LastName = "H" }, new Camper { LastName = "P" }, new Camper { LastName = "BE" }, new Camper { LastName = "BU" } } }, { new HashSet <Camper> { new Camper { LastName = "AB" }, new Camper { LastName = "W" }, new Camper { LastName = "AO" }, new Camper { LastName = "AP" } } } }; Assert.That(camperMateGroups.Count, Is.EqualTo(expectedCamperMateGroups.Count), "Number of camper mate groups"); foreach (var expectedCamperMateGroup in expectedCamperMateGroups) { bool foundMatch = false; foreach (var actualCamperMateGroup in camperMateGroups) { foundMatch = actualCamperMateGroup.SetEquals(expectedCamperMateGroup); if (foundMatch) { break; } } StringBuilder expectedCamperStringBuilder = new StringBuilder(); foreach (Camper expectedCamper in expectedCamperMateGroup) { if (expectedCamperStringBuilder.Length > 0) { expectedCamperStringBuilder.Append(','); } expectedCamperStringBuilder.Append(expectedCamper.LastName); } Assert.That(foundMatch, $"found match for {expectedCamperStringBuilder}"); } }
public void ActivityScheduleGrid_DropCamperInSameTimeSlot_CamperIsMoved() { // Arrange - run schedule with successful data set and start a drag List <ActivityDefinition> activityDefinitions = new List <ActivityDefinition>( _activityDefinitionService.GetActivityDefinition(DefaultSetName)); List <CamperRequests> camperRequests; string scheduleId = "MySchedule"; using (MemoryStream camperRequestStream = new MemoryStream(_validCamperRequestsBuffer)) { camperRequests = CamperRequests.ReadCamperRequests( camperRequestStream, activityDefinitions); _schedulerService.CreateSchedule(scheduleId, camperRequests, activityDefinitions); _localStorage.GetItemAsync <string>(Arg.Any <string>()) .Returns(Task.FromResult(scheduleId)); } RenderedComponent <ActivityScheduleGrid> component = _host.AddComponent <ActivityScheduleGrid>(); List <HtmlNode> camperActivityCells = component.FindAll("td") .Where(node => node.Attributes.AttributesWithName("class") .Any(a => a.Value.Contains("activity-camper-cell"))).ToList(); Assert.That(camperActivityCells, Has.Count.EqualTo(camperRequests.Count() * 4), "Number of camper activity cells"); // Gather up the activity block drop zones. List <HtmlNode> activityBlockCampers = component.FindAll("tr") .Where(node => node.Attributes.AttributesWithName("ondrop").Any()) .ToList(); Assert.That(activityBlockCampers, Has.Count.EqualTo(activityDefinitions.Count * 4), "Number of activity rows"); // Start a drag on a camper in the first activity block HtmlNode sourceCamperActivity = camperActivityCells.First( node => node.ParentNode.GetAttributeValue("id", "") == activityBlockCampers[0].GetAttributeValue("id", "NotDefined")); sourceCamperActivity.TriggerEventAsync("ondragstart", new DragEventArgs()); string camperName = component.Instance.DragPayload.CamperName; // Act - Drop on the block 0 for the next activity HtmlNode dropTarget = activityBlockCampers.First(n => n.GetAttributeValue("id", "") .Equals($"{activityDefinitions[1].Name}-0")); dropTarget.TriggerEventAsync("ondrop", new DragEventArgs()); // Assert - Grid pay load is reset. Assert.That(component.Instance.DragPayload.ActivityName, Is.EqualTo(null), "Drag payload activity"); Assert.That(component.Instance.DragPayload.CamperName, Is.EqualTo(null), "Drag payload camper"); Assert.That(component.Instance.DragPayload.TimeSlot, Is.EqualTo(0), "Drag payload time slot"); // Verify camper activities have not changed List <ActivityDefinition> schedule = _schedulerService.GetSchedule(scheduleId); ActivityDefinition sourceActivity = schedule.Find(ad => ad.Name.Equals(activityDefinitions[0].Name)); List <string> assignedCampersByName = sourceActivity.ScheduledBlocks[component.Instance.DragPayload.TimeSlot] .AssignedCampers.Select(c => c.FullName).ToList(); Assert.That(assignedCampersByName, Has.None.EqualTo(camperName), "Assigned campers on drag source"); ActivityDefinition targetActivity = schedule.Find(ad => ad.Name.Equals(activityDefinitions[1].Name)); assignedCampersByName = targetActivity.ScheduledBlocks[component.Instance.DragPayload.TimeSlot] .AssignedCampers.Select(c => c.FullName).ToList(); Assert.That(assignedCampersByName, Has.One.EqualTo(camperName), "Assigned campers on drop target"); }
static void Main(string[] args) { var logger = new LoggerConverter(NLog.Web.NLogBuilder .ConfigureNLog("nlog.config") .GetCurrentClassLogger()); Parser.Default.ParseArguments <Options>(args).WithParsed(opts => { var activityDefinitions = ActivityDefinition.ReadActivityDefinitions( opts.ActivityDefinitionsPath, logger); if (activityDefinitions == null) { Environment.Exit(-2); } logger.LogInformation($"Found {activityDefinitions.Count} activity definitions in the file: {opts.ActivityDefinitionsPath}"); var camperRequestsList = CamperRequests.ReadCamperRequests(opts.CamperRequestsPath, activityDefinitions, logger); if (camperRequestsList == null) { Environment.Exit(-2); } logger.LogInformation($"Found {camperRequestsList.Count} campers in the file: {opts.CamperRequestsPath}"); // Sort the campers by difficulty to resolve activity list. // Most difficult go first. camperRequestsList.Sort(); // Preload the activity blocks foreach (var activity in activityDefinitions) { activity.PreloadBlocks(); } List <CamperRequests> unsuccessfulCamperRequests = Scheduler.ScheduleActivities(camperRequestsList, opts.UseOptimalLimit, logger); if (opts.UseOptimalLimit && unsuccessfulCamperRequests.Any()) { logger.LogDebug($"Attempting to resolve {unsuccessfulCamperRequests.Count} " + $"unsuccessful camper requests using the activity maximum limits"); unsuccessfulCamperRequests = Scheduler.ScheduleActivities(unsuccessfulCamperRequests, false, logger); } foreach (var activity in activityDefinitions) { foreach (var activityBlock in activity.ScheduledBlocks) { logger.LogDebug($"Scheduled '{activity.Name}' " + $"in block {activityBlock.TimeSlot} " + $"with {activityBlock.AssignedCampers.Count} campers"); } } if (!String.IsNullOrWhiteSpace(opts.ActivityScheduleCsvPath)) { ActivityDefinition.WriteScheduleToCsvFile(activityDefinitions, opts.ActivityScheduleCsvPath, logger); logger.LogInformation($"Wrote the activity schedule file to '{opts.ActivityScheduleCsvPath}'"); } if (!String.IsNullOrWhiteSpace(opts.CamperScheduleCsvPath)) { Camper.WriteScheduleToCsvFile(camperRequestsList.Select(cr => cr.Camper), opts.CamperScheduleCsvPath, logger); logger.LogInformation($"Wrote the camper schedule file to '{opts.CamperScheduleCsvPath}'"); } Console.Out.WriteLine(); foreach (var unhappyCamper in unsuccessfulCamperRequests) { List <ActivityRequest> unscheduledActivities = unhappyCamper.UnscheduledActivities; if (unscheduledActivities.Any(ar => ar.Rank < 3)) { logger.LogInformation($"Failed to place {unhappyCamper.Camper} in {String.Join(',', unscheduledActivities.Select(ar => ar?.ToString()))} "); } else { logger.LogInformation($"Failed to place {unhappyCamper.Camper} in " + $"{String.Join(',', unscheduledActivities.Select(ar => ar?.ToString()))} " + $"or alternate '{unhappyCamper.AlternateActivity?.Name}'"); } } if (unsuccessfulCamperRequests.Count == 0) { logger.LogInformation($"Successfully scheduled {camperRequestsList.Count} " + $"campers into {activityDefinitions.Count} activities"); Environment.Exit(0); } else { logger.LogInformation($"Failed to schedule {unsuccessfulCamperRequests.Count} " + $"of {camperRequestsList.Count} campers into " + $"{activityDefinitions.Count} activities"); Environment.Exit(-4); } }).WithNotParsed(opts => { Environment.Exit(-1); }); }