public async Task <IActionResult> Edit(int id, [Bind("Id,RaceId,VehicleId,HasTowStrap,AcceptableTireWear,AcceptableLift")] RaceVehicle raceVehicle) { if (id != raceVehicle.Id) { return(NotFound()); } if (ModelState.IsValid) { try { await _service.UpdateAsync(raceVehicle); } catch (Exception ex) { if (!RaceVehicleExists(raceVehicle.Id)) { return(NotFound()); } else { ModelState.AddModelError("", ex.Message); ViewData["RaceId"] = new SelectList(_context.Races, "Id", "Name", raceVehicle.RaceId); ViewData["VehicleId"] = new SelectList(_context.Vehicles, "Id", "VehicleAlias", raceVehicle.VehicleId); return(View(raceVehicle)); } } return(RedirectToAction(nameof(Index))); } ViewData["RaceId"] = new SelectList(_context.Races, "Id", "Name", raceVehicle.RaceId); ViewData["VehicleId"] = new SelectList(_context.Vehicles, "Id", "VehicleAlias", raceVehicle.VehicleId); return(View(raceVehicle)); }
public async Task RaceVehicle_Add_Success() { var raceVehicle = new RaceVehicle { RaceId = 2, VehicleId = 2, AcceptableLift = true, AcceptableTireWear = false, HasTowStrap = true }; await _service.AddAsync(raceVehicle); Assert.IsTrue((await _service.GetAllAsync()).Where(x => x.RaceId == raceVehicle.RaceId && x.VehicleId == raceVehicle.VehicleId).FirstOrDefault() != null); }
/// <summary> /// Processes custom business rules for adding a vehicle to a race /// </summary> /// <exception cref="Exception ex">Custom exception message that is used for validation feedback</exception> /// <param name="raceVehicle">The model of the record being handled</param> /// <param name="action">The action being made on the record to decide what to validate</param> internal async Task ValidateVehicle(RaceVehicle raceVehicle, string action = "add") { if (action == "add") { // Check if car is not already in race var duplicateRecord = await _context.RaceVehicles.Where(r => r.VehicleId == raceVehicle.VehicleId && r.RaceId == raceVehicle.RaceId).FirstOrDefaultAsync(); if (duplicateRecord != null) { throw new Exception("This vehicle is already present on this race"); } } // Get all vehicles currently in the race var vehiclesInRace = await _context.RaceVehicles.Where(r => r.RaceId == raceVehicle.RaceId).ToListAsync(); // Check for the count of vehicles, if we already have 5 for that race do not add the new one if (vehiclesInRace.Count == 5) { throw new Exception("Can't add more than 5 vehicles to a race"); } // Check inspection of vehicle with following criteria: // Truck Inspections: // Tow strap on the vehicle // Not lifted more than 5 inches // Car Inspections: // Tow strap on the vehicle // Less than 85 % tire wear var vehicleInfo = await _context.Vehicles.Include(v => v.VehicleType).Where(x => x.Id == raceVehicle.VehicleId).FirstOrDefaultAsync(); var vehicleType = vehicleInfo.VehicleType.Description; if (vehicleType == "Truck") { if (!raceVehicle.HasTowStrap || !raceVehicle.AcceptableLift) { throw new Exception("A truck needs to have a tow strap and cannot be lifted more than 5 inches to participate in the race"); } } else { if (!raceVehicle.HasTowStrap || !raceVehicle.AcceptableTireWear) { throw new Exception("A car needs to have a tow strap and cannot have less than 85% of tire wear to participate in the race"); } } }
public void RaceVehicle_Add_Fail_CarNoPassInspection(bool acceptableLift, bool acceptableTireWear, bool hasTowStrap) { var raceVehicle = new RaceVehicle { RaceId = 2, VehicleId = 3, AcceptableLift = acceptableLift, AcceptableTireWear = acceptableTireWear, HasTowStrap = hasTowStrap }; var ex = Assert.ThrowsAsync <Exception>(async() => await _service.AddAsync(raceVehicle)); Assert.That(ex.Message, Is.EqualTo("A car needs to have a tow strap and cannot have less than 85% of tire wear to participate in the race")); }
public void RaceVehicle_Add_Fail_MoreThanFiveVehicles() { var raceVehicle = new RaceVehicle { RaceId = 1, VehicleId = 6, AcceptableLift = true, AcceptableTireWear = false, HasTowStrap = true }; var ex = Assert.ThrowsAsync <Exception>(async() => await _service.AddAsync(raceVehicle)); Assert.That(ex.Message, Is.EqualTo("Can't add more than 5 vehicles to a race")); }
/// <summary> /// Updates a record from the database /// </summary> /// <param name="raceVehicle">A Race Vehicle model to be modified</param> public async Task UpdateAsync(RaceVehicle raceVehicle) { try { await ValidateVehicle(raceVehicle, "update"); var e = _context.Update(raceVehicle); e.State = EntityState.Modified; await _context.SaveChangesAsync(); } catch (Exception ex) { throw; // In here we would log the exception and return an error message to the user } }
/// <summary> /// Adds the record to the database /// </summary> /// <param name="raceVehicle">A Race Vehicle model</param> public async Task AddAsync(RaceVehicle raceVehicle) { try { await ValidateVehicle(raceVehicle); await _context.AddAsync(raceVehicle); await _context.SaveChangesAsync(); } catch (Exception ex) { throw; // In here we would log the exception and return an error message to the user } }
private decimal GetVehiclesRaceTimeInSeconds(RaceVehicle raceVehicle, DateTime leaderboardDate, DateTime raceStartAt) { var malfunction = raceVehicle.Malfunctions.FirstOrDefault(x => x.StartAt <= leaderboardDate && (x.EndAt == null || x.EndAt >= leaderboardDate)); double totalSecondsForRepairment = raceVehicle.Malfunctions.Where(x => x.StartAt <= leaderboardDate && x.EndAt.HasValue && x.EndAt <= leaderboardDate) .Sum(x => (x.EndAt.Value - x.StartAt).TotalSeconds); raceVehicle.MalfunctionStatus = MalfunctionStatus.None; if (malfunction != null) { totalSecondsForRepairment += (leaderboardDate - malfunction.StartAt).TotalSeconds; raceVehicle.MalfunctionStatus = (MalfunctionStatus)malfunction.Status; } return((decimal)(leaderboardDate - raceStartAt).TotalSeconds - (decimal)totalSecondsForRepairment); }
public async Task <IActionResult> Create([Bind("RaceId,VehicleId,HasTowStrap,AcceptableTireWear,AcceptableLift")] RaceVehicle raceVehicle) { if (ModelState.IsValid) { try { await _service.AddAsync(raceVehicle); return(RedirectToAction(nameof(Index))); } catch (Exception ex) { ModelState.AddModelError("", ex.Message); ViewData["RaceId"] = new SelectList(_context.Races, "Id", "Name", raceVehicle.RaceId); ViewData["VehicleId"] = new SelectList(_context.Vehicles, "Id", "VehicleAlias", raceVehicle.VehicleId); return(View(raceVehicle)); } } ViewData["RaceId"] = new SelectList(_context.Races, "Id", "Name", raceVehicle.RaceId); ViewData["VehicleId"] = new SelectList(_context.Vehicles, "Id", "VehicleAlias", raceVehicle.VehicleId); return(View(raceVehicle)); }
/// <summary> /// Creates an light malfunction for vehicle /// </summary> /// <param name="rand">Random object reference</param> /// <param name="startAt">Date from which malfunction can happen</param> /// <param name="vehicle">Vehicle for which malfunction is created</param> /// <param name="to">Number of seconds in which this malfunction can happen</param> /// <returns>New light malfunction</returns> private static MalfunctionStats CreateLightMalfunction(Random rand, DateTime startAt, RaceVehicle vehicle, int to) { MalfunctionStats malfunction = new MalfunctionStats(); int lightMalfunctionAt = rand.Next(to); malfunction.Status = (short)MalfunctionStatus.Light; malfunction.StartAt = startAt.AddSeconds(lightMalfunctionAt); malfunction.EndAt = malfunction.StartAt.AddHours(vehicle.VehicleTypeParameters.LightMalfunctionTime); return(malfunction); }
/// <summary> /// Creates a list of all malfunctions that will happen in the race. Recursive function that exits if heavy malfunction happens or vehicle ends the race. /// </summary> /// <param name="malfunctions"></param> /// <param name="rand"></param> /// <param name="raceStartAt"></param> /// <param name="raceEndsAt"></param> /// <param name="startAt"></param> /// <param name="endAt"></param> /// <param name="vehicle"></param> /// <returns></returns> private List <MalfunctionStats> CreateVehicleMalfunctions(List <MalfunctionStats> malfunctions, Random rand, DateTime raceStartAt, ref DateTime raceEndsAt, DateTime startAt, DateTime endAt, RaceVehicle vehicle) { if (startAt >= raceEndsAt) { return(malfunctions); } int hourInSeconds = 3600; if (endAt > raceEndsAt) { endAt = raceEndsAt; hourInSeconds = (int)(endAt - startAt).TotalSeconds; } var nextPeriodStart = endAt; if (rand.Next(100) < vehicle.VehicleTypeParameters.HeavyMalfunctionPercentage * 100) { var malfunction = CreateHeavyMalfunction(rand, startAt, hourInSeconds); malfunctions.Add(malfunction); raceEndsAt = malfunction.StartAt; return(malfunctions); } else if (rand.Next(100) < vehicle.VehicleTypeParameters.LightMalfunctionPercentage * 100) { var malfunction = CreateLightMalfunction(rand, startAt, vehicle, hourInSeconds); malfunctions.Add(malfunction); nextPeriodStart = malfunction.EndAt.Value; raceEndsAt = raceEndsAt.AddSeconds(vehicle.VehicleTypeParameters.LightMalfunctionTime * 3600); } return(CreateVehicleMalfunctions(malfunctions, rand, raceStartAt, ref raceEndsAt, nextPeriodStart, nextPeriodStart.AddHours(1), vehicle)); }
private void CalculateVehicleFinishStatistics(DateTime startDate, Random rand, int raceDistance, RaceVehicle vehicle) { decimal finishTimeSeconds = ((decimal)raceDistance / (decimal)vehicle.VehicleTypeParameters.TopSpeed) * 3600m; var raceEndsAt = startDate.AddSeconds((double)finishTimeSeconds); int finishTime = (int)finishTimeSeconds; vehicle.Malfunctions = CreateVehicleMalfunctions(new List <MalfunctionStats>(), rand, startDate, ref raceEndsAt, startDate, startDate.AddHours(1), vehicle); vehicle.EndsRaceAt = raceEndsAt; decimal totalSecondsForRepairment = vehicle.Malfunctions.Where(x => x.EndAt.HasValue) .Sum(x => (decimal)(x.EndAt.Value - x.StartAt).TotalSeconds); if (vehicle.Malfunctions.Any(x => x.Status == (short)MalfunctionStatus.Heavy)) { vehicle.FinishTime = null; decimal raceTimeInSeconds = (decimal)(raceEndsAt - startDate).TotalSeconds - totalSecondsForRepairment; decimal distance = (((decimal)vehicle.VehicleTypeParameters.TopSpeed * 1000m) / 3600m) * raceTimeInSeconds; vehicle.DistanceInMeters = distance; } else { vehicle.FinishTime = (decimal)(raceEndsAt - startDate).TotalSeconds; vehicle.DistanceInMeters = raceDistance * 1000; } }