public void does_not_publish_add_audit_on_error()
        {
            //setup
            var context = CreateUserContext();
            var mockPublisher = new Mock<IAuditEventPublisher>();

            //act
            Exception expectedException = null;
            using (var subject = new TestAuditableContext(GetEFConnectionString(), context, mockPublisher.Object, _defaultMockConfiguration.Object))
            {
                var invalidEntity = new Gender { Name = new string('x', 500) };
                subject.Genders.AddObject(invalidEntity);
                try
                {
                    subject.SaveChanges();
                }
                catch (Exception ex)
                {
                    expectedException = ex;
                }
            }

            Assert.IsNotNull(expectedException); //sanity check

            //assert
            mockPublisher.Verify(m => m.Publish(It.IsAny<AuditEvent>()), Times.Never());
        }
        public void tracks_updates_to_object_graph_child_in_context()
        {
            //setup
            var context = CreateUserContext();
            var mockPublisher = new Mock<IAuditEventPublisher>();
            var id = AddCountryAndReturnId();
            int stateId;

            //act
            using (var subject = new TestAuditableContext(GetEFConnectionString(), context, mockPublisher.Object, _defaultMockConfiguration.Object))
            {
                subject.ContextOptions.LazyLoadingEnabled = true;
                subject.ContextOptions.ProxyCreationEnabled = true;

                var objectSet = subject.CreateObjectSet<Country>();
                var country = objectSet.Single(c => c.Id == id);
                var state = country.States.ElementAt(0);
                stateId = state.Id;
                state.Name = Guid.NewGuid().ToString();
                subject.SaveChanges();
            }

            //assert
            mockPublisher.Verify
                (
                m => m.Publish
                    (
                        It.Is<AuditEvent>
                        (
                            auditEvent =>
                            EventMatchesContext(auditEvent, context)
                            &&
                            auditEvent.AuditEntities.Count() == 1
                            &&
                            auditEvent.AuditEntities[0].EntityType == typeof(State).Name
                            &&
                            auditEvent.AuditEntities[0].EntityIdentifier == stateId.ToString()
                            &&
                            auditEvent.AuditEntities[0].AuditEntityAction == AuditEntityAction.Update
                        )
                    ),
                    Times.Once()
                );
        }
        public void does_not_publish_read_audit_when_no_results()
        {
            //setup
            var context = CreateUserContext();
            var mockPublisher = new Mock<IAuditEventPublisher>();

            //act
            IEnumerable<Gender> result;
            using (var subject = new TestAuditableContext(GetEFConnectionString(), context, mockPublisher.Object, _defaultMockConfiguration.Object))
            {
                var badName = Guid.NewGuid().ToString();
                result = subject.Genders.Where(g => g.Name == badName).ToList();
            }

            Assert.AreEqual(0, result.Count()); //sanity check

            //assert
            mockPublisher.Verify(m => m.Publish(It.IsAny<AuditEvent>()), Times.Never());
        }
        public void publishes_add_audit()
        {
            //setup
            var context = CreateUserContext();
            var mockPublisher = new Mock<IAuditEventPublisher>();

            var entity = new ApplicationSetting();
            entity.ApplicationId = Guid.NewGuid().ToString();
            entity.KeyName = Guid.NewGuid().ToString();
            entity.Value = Guid.NewGuid().ToString();

            var expectedIdentifier = string.Concat(entity.ApplicationId, "|", entity.KeyName);

            //act
            using (var subject = new TestAuditableContext(GetEFConnectionString(), context, mockPublisher.Object, _defaultMockConfiguration.Object))
            {
                subject.ApplicationSettings.AddObject(entity);
                subject.SaveChanges();
            }

            //assert
            mockPublisher.Verify
                (
                m => m.Publish
                    (
                        It.Is<AuditEvent>
                        (
                            auditEvent =>
                            EventMatchesContext(auditEvent, context)
                            &&
                            auditEvent.AuditEntities.Count() == 1
                            &&
                            auditEvent.AuditEntities[0].AuditEntityAction == AuditEntityAction.Add
                            &&
                            !string.IsNullOrEmpty(auditEvent.AuditEntities[0].EntityIdentifier)
                            &&
                            auditEvent.AuditEntities[0].EntityIdentifier == expectedIdentifier
                        )
                    ),
                    Times.Once()
                );
        }
        public void publishes_delete_audit()
        {
            var context = CreateUserContext();
            var mockPublisher = new Mock<IAuditEventPublisher>();
            var id = AddGenderAndReturnId();

            //act
            using (var subject = new TestAuditableContext(GetEFConnectionString(), context, mockPublisher.Object, _defaultMockConfiguration.Object))
            {
                var currentEntity = subject.Genders.Single(g => g.Id == id);
                subject.DeleteObject(currentEntity);
                subject.SaveChanges();
            }

            //assert
            mockPublisher.Verify
                (
                m => m.Publish
                    (
                        It.Is<AuditEvent>
                        (
                            auditEvent =>
                            EventMatchesContext(auditEvent, context)
                            &&
                            auditEvent.AuditEntities.Count() == 1
                            &&
                            auditEvent.AuditEntities[0].AuditEntityAction == AuditEntityAction.Delete
                        )
                    ),
                    Times.Once()
                );
        }
        public void works_without_auditing()
        {
            int id;
            Exception noException = null;

            try
            {
                using (var subject = new TestAuditableContext(GetEFConnectionString()))
                {
                    var entity = new Gender { Name = Guid.NewGuid().ToString() };
                    subject.Genders.AddObject(entity);
                    subject.SaveChanges();
                    id = entity.Id;
                }

                Gender toUpdate;
                using (var subject = new TestAuditableContext(GetEFConnectionString()))
                {
                    toUpdate = subject.Genders.Single(g => g.Id == id);
                }
                toUpdate.Name = Guid.NewGuid().ToString();

                using (var subject = new TestAuditableContext(GetEFConnectionString()))
                {
                    var currentEntity = subject.Genders.Single(g => g.Id == id);
                    subject.Genders.ApplyCurrentValues(toUpdate);
                    subject.SaveChanges();
                }

                using (var subject = new TestAuditableContext(GetEFConnectionString()))
                {
                    var currentEntity = subject.Genders.Single(g => g.Id == id);
                    subject.DeleteObject(currentEntity);
                    subject.SaveChanges();
                }
            }
            catch (Exception ex)
            {
                noException = ex;
            }

            Assert.IsNull(noException);
        }
        public void does_not_publish_update_audit_on_error()
        {
            //setup
            var context = CreateUserContext();
            var mockPublisher = new Mock<IAuditEventPublisher>();
            var id = AddGenderAndReturnId();
            var toUpdate = GetGenderById(id);

            toUpdate.Name = new string('x', 500);

            Exception expectedException = null;
            //act
            using (var subject = new TestAuditableContext(GetEFConnectionString(), context, mockPublisher.Object, _defaultMockConfiguration.Object))
            {
                try
                {
                    var currentEntity = subject.Genders.Single(g => g.Id == id);
                    subject.Genders.ApplyCurrentValues(toUpdate);
                    subject.SaveChanges();
                }
                catch (Exception ex)
                {
                    expectedException = ex;
                }

            }

            Assert.IsNotNull(expectedException); //sanity check

            //assert
            mockPublisher.Verify(m => m.Publish(It.IsAny<AuditEvent>()), Times.Never());
        }
        public void honors_false_configuration_on_delete()
        {
            var context = CreateUserContext();
            var mockPublisher = new Mock<IAuditEventPublisher>();
            var mockConfig = new Mock<IAuditConfiguration>();
            mockConfig.Setup(m => m.ContainsEntityType(typeof(Gender))).Returns(false);

            var id = AddGenderAndReturnId();

            //act
            using (var subject = new TestAuditableContext(GetEFConnectionString(), context, mockPublisher.Object, mockConfig.Object))
            {
                var currentEntity = subject.Genders.Single(g => g.Id == id);
                subject.DeleteObject(currentEntity);
                subject.SaveChanges();
            }

            //assert
            mockPublisher.Verify(m => m.Publish(It.IsAny<AuditEvent>()), Times.Never());
        }
        public void tracks_updates_in_context()
        {
            //setup
            var context = CreateUserContext();
            var mockPublisher = new Mock<IAuditEventPublisher>();
            var id = AddGenderAndReturnId();

            //act
            using (var subject = new TestAuditableContext(GetEFConnectionString(), context, mockPublisher.Object, _defaultMockConfiguration.Object))
            {
                var objectSet = subject.CreateObjectSet<Gender>();
                var currentEntity = objectSet.Single(g => g.Id == id);
                currentEntity.Name = Guid.NewGuid().ToString();
                subject.SaveChanges();
            }

            //assert
            mockPublisher.Verify
                (
                m => m.Publish
                    (
                        It.Is<AuditEvent>
                        (
                            auditEvent =>
                            EventMatchesContext(auditEvent, context)
                            &&
                            auditEvent.AuditEntities.Count() == 1
                            &&
                            auditEvent.AuditEntities[0].AuditEntityAction == AuditEntityAction.Update
                        )
                    ),
                    Times.Once()
                );
        }
        public void publishes_read_audit_on_list()
        {
            //setup
            var context = CreateUserContext();
            var mockPublisher = new Mock<IAuditEventPublisher>();
            for (int x = 0; x < 10; x++)
            {
                AddGenderAndReturnId();
            }

            //act
            IEnumerable<Gender> result;
            using (var subject = new TestAuditableContext(GetEFConnectionString(), context, mockPublisher.Object, _defaultMockConfiguration.Object))
            {
                result = subject.Genders.ToList();
            }

            //assert
            mockPublisher.Verify
                (
                m => m.Publish
                    (
                        It.Is<AuditEvent>
                        (
                        auditEvent =>
                        EventMatchesContext(auditEvent, context)
                        &&
                        auditEvent.AuditEntities.Count() == result.Count()
                        )
                    ),
                    Times.Once()
                );
        }
        public void publishes_read_audit_on_single_entity()
        {
            //setup
            var context = CreateUserContext();
            var mockPublisher = new Mock<IAuditEventPublisher>();
            var id = AddGenderAndReturnId();

            //act
            Gender result;
            using (var subject = new TestAuditableContext(GetEFConnectionString(), context, mockPublisher.Object, _defaultMockConfiguration.Object))
            {
                result = subject.Genders.SingleOrDefault(g => g.Id == id);
            }

            //assert
            mockPublisher.Verify
                (
                m => m.Publish
                    (
                        It.Is<AuditEvent>
                        (
                        auditEvent =>
                        EventMatchesContext(auditEvent, context)
                        &&
                        auditEvent.AuditEntities.Count() == 1
                        )
                    ),
                    Times.Once()
                );
        }
        public void does_not_publish_update_audit_when_no_changes_to_entity()
        {
            //setup
            var context = CreateUserContext();
            var mockPublisher = new Mock<IAuditEventPublisher>();
            var id = AddGenderAndReturnId();
            var toUpdate = GetGenderById(id);

            //act
            using (var subject = new TestAuditableContext(GetEFConnectionString(), context, mockPublisher.Object, _defaultMockConfiguration.Object))
            {
                var currentEntity = subject.Genders.Single(g => g.Id == id);
                subject.Genders.ApplyCurrentValues(toUpdate);
                subject.SaveChanges();
            }

            //assert
            mockPublisher.Verify(m => m.Publish(It.IsAny<AuditEvent>()), Times.Never());
        }
        public void publishes_new_event_each_commit()
        {
            //setup
            var context = CreateUserContext();
            var mockPublisher = new Mock<IAuditEventPublisher>();

            var entityA = new Gender { Name = Guid.NewGuid().ToString() };
            var entityB = new Gender { Name = Guid.NewGuid().ToString() };

            //act
            using (var subject = new TestAuditableContext(GetEFConnectionString(), context, mockPublisher.Object, _defaultMockConfiguration.Object))
            {
                subject.Genders.AddObject(entityA);
                subject.SaveChanges();
                subject.Genders.AddObject(entityB);
                subject.SaveChanges();
            }

            //assert
            mockPublisher.Verify
                (
                m => m.Publish
                    (
                        It.Is<AuditEvent>
                        (
                            auditEvent =>
                            EventMatchesContext(auditEvent, context)
                            &&
                            auditEvent.AuditEntities.Count() == 1
                            &&
                            auditEvent.AuditEntities[0].AuditEntityAction == AuditEntityAction.Add
                            &&
                            auditEvent.AuditEntities[0].AuditEntityProperties.Count == _auditableGenderPropertyCount
                        )
                    ),
                    Times.Exactly(2)
                );
        }
        public void publishes_add_audit()
        {
            //setup
            var context = CreateUserContext();
            var mockPublisher = new Mock<IAuditEventPublisher>();

            var entity = new Gender { Name = Guid.NewGuid().ToString() };

            //act
            using (var subject = new TestAuditableContext(GetEFConnectionString(), context, mockPublisher.Object, _defaultMockConfiguration.Object))
            {
                subject.Genders.AddObject(entity);
                subject.SaveChanges();
            }

            //assert
            mockPublisher.Verify
                (
                m => m.Publish
                    (
                        It.Is<AuditEvent>
                        (
                            auditEvent =>
                            EventMatchesContext(auditEvent, context)
                            &&
                            auditEvent.AuditEntities.Count() == 1
                            &&
                            auditEvent.AuditEntities[0].AuditEntityAction == AuditEntityAction.Add
                            &&
                            !string.IsNullOrEmpty(auditEvent.AuditEntities[0].EntityIdentifier)
                            &&
                            auditEvent.AuditEntities[0].EntityIdentifier != "0"
                            &&
                            !auditEvent.AuditEntities[0].AuditEntityProperties
                                .Select(p => p.PropertyName)
                                    .Contains("Id")
                        )
                    ),
                    Times.Once()
                );
        }
        public void honors_true_configuration_when_adding()
        {
            //setup
            var context = CreateUserContext();
            var mockPublisher = new Mock<IAuditEventPublisher>();

            var mockConfig = new Mock<IAuditConfiguration>();
            mockConfig.Setup(m => m.ContainsEntityType(typeof(Gender))).Returns(true);

            //act
            using (var subject = new TestAuditableContext(GetEFConnectionString(), context, mockPublisher.Object, mockConfig.Object))
            {
                var entity = new Gender { Name = Guid.NewGuid().ToString() };
                subject.Genders.AddObject(entity);
                subject.SaveChanges();
            }

            //assert
            mockPublisher.Verify
                (
                m => m.Publish
                    (
                        It.Is<AuditEvent>
                        (
                            auditEvent =>
                            EventMatchesContext(auditEvent, context)
                            &&
                            auditEvent.AuditEntities.Count() == 1
                            &&
                            auditEvent.AuditEntities[0].AuditEntityAction == AuditEntityAction.Add
                        )
                    ),
                    Times.Once()
                );
        }
        public void honors_true_configuration_on_update()
        {
            //setup
            var context = CreateUserContext();
            var mockPublisher = new Mock<IAuditEventPublisher>();
            var mockConfig = new Mock<IAuditConfiguration>();
            mockConfig.Setup(m => m.ContainsEntityType(typeof(Gender))).Returns(true);

            var id = AddGenderAndReturnId();
            var toUpdate = GetGenderById(id);

            toUpdate.Name = Guid.NewGuid().ToString();

            //act
            using (var subject = new TestAuditableContext(GetEFConnectionString(), context, mockPublisher.Object, mockConfig.Object))
            {
                var currentEntity = subject.Genders.Single(g => g.Id == id);
                subject.Genders.ApplyCurrentValues(toUpdate);
                subject.SaveChanges();
            }

            //assert
            mockPublisher.Verify
                (
                m => m.Publish
                    (
                        It.Is<AuditEvent>
                        (
                            auditEvent =>
                            EventMatchesContext(auditEvent, context)
                            &&
                            auditEvent.AuditEntities.Count() == 1
                            &&
                            auditEvent.AuditEntities[0].AuditEntityAction == AuditEntityAction.Update
                        )
                    ),
                    Times.Once()
                );
        }
        public void honors_false_configuration_when_adding()
        {
            //setup
            var context = CreateUserContext();
            var mockPublisher = new Mock<IAuditEventPublisher>();

            var mockConfig = new Mock<IAuditConfiguration>();
            mockConfig.Setup(m => m.ContainsEntityType(typeof(Gender))).Returns(false);

            //act
            using (var subject = new TestAuditableContext(GetEFConnectionString(), context, mockPublisher.Object, mockConfig.Object))
            {
                var entity = new Gender { Name = Guid.NewGuid().ToString() };
                subject.Genders.AddObject(entity);
                subject.SaveChanges();
            }

            //assert
            mockPublisher.Verify(m => m.Publish(It.IsAny<AuditEvent>()), Times.Never());
        }
        public void honors_true_configuration_on_read()
        {
            //setup
            var context = CreateUserContext();
            var mockPublisher = new Mock<IAuditEventPublisher>();

            var mockConfig = new Mock<IAuditConfiguration>();
            mockConfig.Setup(m => m.ContainsEntityType(typeof(Gender))).Returns(true);
            mockConfig.Setup(m => m.IsReadAuditEnabled(typeof(Gender))).Returns(true);

            var id = AddGenderAndReturnId();

            //act
            Gender result;
            using (var subject = new TestAuditableContext(GetEFConnectionString(), context, mockPublisher.Object, mockConfig.Object))
            {
                result = subject.Genders.SingleOrDefault(g => g.Id == id);
            }

            //assert
            mockPublisher.Verify
                (
                m => m.Publish
                    (
                        It.Is<AuditEvent>
                        (
                        auditEvent =>
                        EventMatchesContext(auditEvent, context)
                        &&
                        auditEvent.AuditEntities.Count() == 1
                        )
                    ),
                    Times.Once()
                );
        }