public static string FormatLogEntry(LogEntry logEntry)
        {
            switch (logEntry.Type)
            {
                case LogEventType.UserLogIn:
                    return "logged in";

                case LogEventType.UserCreated:
                    var newUser = logEntry.Properties.First(p => p.PropertyType == LogPropertyType.Username);
                    return $"created account for {newUser.PropertyValue}";

                case LogEventType.UserUpdated:
                    var properties = logEntry.Properties.Where(p => p.PropertyType == LogPropertyType.PropertyChange).Select(p => p.PropertyValue).OrderBy(s => s).ToList();
                    var propString = string.Empty;
                    switch (properties.Count)
                    {
                        case 1:
                            propString = properties[0];
                            break;

                        case 2:
                            propString = $"{properties[0]} and {properties[1]}";
                            break;

                        default:
                            if (properties.Count > 2)
                                propString = $"{string.Join(", ", properties.Take(properties.Count - 1))} and {properties.Last()}";
                            break;
                    }

                    return $"changed {propString.ToLower()} for {logEntry.Properties.First(p => p.PropertyType == LogPropertyType.Username).PropertyValue}";

                case LogEventType.UserDeleted:
                    var oldUser = logEntry.Properties.First(p => p.PropertyType == LogPropertyType.Username);
                    return $"deleted account for {oldUser.PropertyValue}";

                case LogEventType.IMEIRegistered:
                    var imei = logEntry.Properties.First(p => p.PropertyType == LogPropertyType.IMEI).PropertyValue;
                    var callsign = logEntry.Properties.First(p => p.PropertyType == LogPropertyType.Callsign).PropertyValue;
                    var vehicle = logEntry.Properties.First(p => p.PropertyType == LogPropertyType.VehicleType).PropertyValue;
                    return $"linked {imei} to callsign {callsign} with type {vehicle}";

                case LogEventType.IMEIDeleted:
                    var oldIMEI = logEntry.Properties.First(p => p.PropertyType == LogPropertyType.IMEI).PropertyValue;
                    return $"deleted {oldIMEI}";

                case LogEventType.MapInUse:
                    var startDate = DateTimeOffset.Parse(logEntry.Properties.First(p => p.PropertyType == LogPropertyType.StartDate).PropertyValue);
                    return $"used the map between {startDate.ToString("g")} and {logEntry.Date.ToString("g")}";

                default:
                    return "unknown event logged";
            }
        }
        private bool CheckUserUpdatedLogEntry(LogEntry entry, string updatingUser, string updatedUser, IEnumerable<string> changes)
        {
            var properties = changes.Select(c => new LogEntryProperty { PropertyType = LogPropertyType.PropertyChange, PropertyValue = c }).ToList();
            properties.Add(new LogEntryProperty { PropertyType = LogPropertyType.Username, PropertyValue = updatedUser });

            CheckLogEntry(entry, LogEventType.UserUpdated, updatingUser, properties.ToArray());
            return true;
        }
 private bool CheckUserLoggedInEntry(LogEntry entry, string username)
 {
     CheckLogEntry(entry, LogEventType.UserLogIn, username);
     return true;
 }
 private bool CheckUserDeletedLogEntry(LogEntry entry, string deletingUser, string oldUser)
 {
     CheckLogEntry(entry, LogEventType.UserDeleted, deletingUser, new LogEntryProperty { PropertyType = LogPropertyType.Username, PropertyValue = oldUser });
     return true;
 }
 private bool CheckUserCreatedLogEntry(LogEntry entry, string creatingUser, string newUser)
 {
     CheckLogEntry(entry, LogEventType.UserCreated, creatingUser, new LogEntryProperty { PropertyType = LogPropertyType.Username, PropertyValue = newUser });
     return true;
 }
        private bool CheckMapLogEntry(LogEntry entry, string username, DateTimeOffset startDate)
        {
            CheckLogEntry(entry, LogEventType.MapInUse, username, new LogEntryProperty { PropertyType = LogPropertyType.StartDate, PropertyValue = startDate.ToString("O") });

            return true;
        }
        private bool CheckIMEIRegisteredLogEntry(LogEntry entry, string registeringUser, string imei, string callsign, VehicleType type)
        {
            CheckLogEntry(entry, LogEventType.IMEIRegistered, registeringUser, new LogEntryProperty { PropertyType = LogPropertyType.IMEI, PropertyValue = imei },
                new LogEntryProperty { PropertyValue = callsign, PropertyType = LogPropertyType.Callsign },
                new LogEntryProperty { PropertyType = LogPropertyType.VehicleType, PropertyValue = type.ToString() });

            return true;
        }
 private bool CheckIMEIDeletedLogEntry(LogEntry entry, string deletingUser, string imei)
 {
     CheckLogEntry(entry, LogEventType.IMEIDeleted, deletingUser, new LogEntryProperty { PropertyType = LogPropertyType.IMEI, PropertyValue = imei });
     return true;
 }
        private static void CheckLogEntry(LogEntry entry, LogEventType type, string sourceUser, params LogEntryProperty[] properties)
        {
            Assert.Equal(sourceUser, entry.SourceUser);
            Assert.Equal(type, entry.Type);

            foreach (var p in properties)
            {
                if (p.PropertyType == LogPropertyType.StartDate)
                    Assert.NotNull(entry.Properties.SingleOrDefault(lep => lep.PropertyType == p.PropertyType && Math.Abs((DateTimeOffset.ParseExact(lep.PropertyValue, "O", CultureInfo.InvariantCulture) - DateTimeOffset.ParseExact(p.PropertyValue, "O", CultureInfo.InvariantCulture)).TotalSeconds) < TimeTolerance));
                else
                    Assert.NotNull(entry.Properties.SingleOrDefault(lep => lep.PropertyType == p.PropertyType && lep.PropertyValue == p.PropertyValue));
            }

            Assert.Equal(properties.Length, entry.Properties.Count);
            Assert.True(Math.Abs((entry.Date - DateTimeOffset.Now).TotalSeconds) < TimeTolerance);
        }
        public async Task LogMapInUseUpdateGoodData()
        {
            LogEntries.Clear();

            var startDate = DateTimeOffset.Now.AddMinutes(-(LogService.MapUseTimeout - 1));

            var le = new LogEntry { Date = startDate, SourceUser = TestUsername, Type = LogEventType.MapInUse };
            le.Properties.Add(new LogEntryProperty { PropertyType = LogPropertyType.StartDate, PropertyValue = startDate.ToString("O") });

            LogEntries.Add(le);

            var logEntrySet = CreateMockLogEntrySet();
            var logPropertySet = CreateMockLogPropertySet();
            var context = CreateLoggingContext(logEntrySet.Object, logPropertySet.Object);

            var service = new LogService(context.Object);

            await service.LogMapInUse(TestUsername);

            logEntrySet.Verify(l => l.Add(It.IsAny<LogEntry>()), Times.Never);
            context.Verify(c => c.SaveChangesAsync());

            CheckMapLogEntry(le, TestUsername, startDate);
        }
        public async Task LogMapInUsePreviousGoodData()
        {
            LogEntries.Clear();

            var startDate = DateTimeOffset.Now.AddMinutes(-(LogService.MapUseTimeout + 1));

            var le = new LogEntry { Date = startDate, SourceUser = TestUsername, Type = LogEventType.MapInUse };
            le.Properties.Add(new LogEntryProperty { PropertyType = LogPropertyType.StartDate, PropertyValue = startDate.ToString("O") });

            LogEntries.Add(le);

            await LogMapInUse(TestUsername);
        }
        public async Task LogMapInUseOldDataButNoOldDate()
        {
            LogEntries.Clear();

            var startDate = DateTimeOffset.Now.AddMinutes(-(LogService.MapUseTimeout - 1));

            var le = new LogEntry { Date = startDate, SourceUser = TestUsername, Type = LogEventType.MapInUse };

            LogEntries.Add(le);

            await LogMapInUse(TestUsername);
        }