using System.Collections; using System.Linq; using System.Reflection; using AutoFixture; using Equ; using FluentAssertions; using NUnit.Framework; using NzbDrone.Common.Extensions; using NzbDrone.Core.Datastore; using NzbDrone.Core.Music; using NzbDrone.Test.Common; namespace NzbDrone.Core.Test.MusicTests { [TestFixture] public class EntityFixture : LoggingTest { private Fixture _fixture = new Fixture(); private static bool IsNotMarkedAsIgnore(PropertyInfo propertyInfo) { return !propertyInfo.GetCustomAttributes(typeof(MemberwiseEqualityIgnoreAttribute), true).Any(); } public class EqualityPropertySource { public static IEnumerable TestCases { get { foreach (var property in typeof(T).GetProperties().Where(x => x.CanRead && x.CanWrite && IsNotMarkedAsIgnore(x))) { yield return new TestCaseData(property).SetName($"{{m}}_{property.Name}"); } } } } public class IgnoredPropertySource { public static IEnumerable TestCases { get { foreach (var property in typeof(T).GetProperties().Where(x => x.CanRead && x.CanWrite && !IsNotMarkedAsIgnore(x))) { yield return new TestCaseData(property).SetName($"{{m}}_{property.Name}"); } } } } [Test] public void two_equivalent_artist_metadata_should_be_equal() { var item1 = _fixture.Create(); var item2 = item1.JsonClone(); item1.Should().NotBeSameAs(item2); item1.Should().Be(item2); } [Test] [TestCaseSource(typeof(EqualityPropertySource), "TestCases")] public void two_different_artist_metadata_should_not_be_equal(PropertyInfo prop) { var item1 = _fixture.Create(); var item2 = item1.JsonClone(); var different = _fixture.Create(); // make item2 different in the property under consideration var differentEntry = prop.GetValue(different); prop.SetValue(item2, differentEntry); item1.Should().NotBeSameAs(item2); item1.Should().NotBe(item2); } [Test] public void metadata_and_db_fields_should_replicate_artist_metadata() { var item1 = _fixture.Create(); var item2 = _fixture.Create(); item1.Should().NotBe(item2); item1.UseMetadataFrom(item2); item1.UseDbFieldsFrom(item2); item1.Should().Be(item2); } private Track GivenTrack() { return _fixture.Build() .Without(x => x.AlbumRelease) .Without(x => x.ArtistMetadata) .Without(x => x.TrackFile) .Without(x => x.Artist) .Without(x => x.AlbumId) .Without(x => x.Album) .Create(); } [Test] public void two_equivalent_track_should_be_equal() { var item1 = GivenTrack(); var item2 = item1.JsonClone(); item1.Should().NotBeSameAs(item2); item1.Should().Be(item2); } [Test] [TestCaseSource(typeof(EqualityPropertySource), "TestCases")] public void two_different_tracks_should_not_be_equal(PropertyInfo prop) { var item1 = GivenTrack(); var item2 = item1.JsonClone(); var different = GivenTrack(); // make item2 different in the property under consideration var differentEntry = prop.GetValue(different); prop.SetValue(item2, differentEntry); item1.Should().NotBeSameAs(item2); item1.Should().NotBe(item2); } [Test] public void metadata_and_db_fields_should_replicate_track() { var item1 = GivenTrack(); var item2 = GivenTrack(); item1.Should().NotBe(item2); item1.UseMetadataFrom(item2); item1.UseDbFieldsFrom(item2); item1.Should().Be(item2); } private AlbumRelease GivenAlbumRelease() { return _fixture.Build() .Without(x => x.Album) .Without(x => x.Tracks) .Create(); } [Test] public void two_equivalent_album_releases_should_be_equal() { var item1 = GivenAlbumRelease(); var item2 = item1.JsonClone(); item1.Should().NotBeSameAs(item2); item1.Should().Be(item2); } [Test] [TestCaseSource(typeof(EqualityPropertySource), "TestCases")] public void two_different_album_releases_should_not_be_equal(PropertyInfo prop) { var item1 = GivenAlbumRelease(); var item2 = item1.JsonClone(); var different = GivenAlbumRelease(); // make item2 different in the property under consideration var differentEntry = prop.GetValue(different); prop.SetValue(item2, differentEntry); item1.Should().NotBeSameAs(item2); item1.Should().NotBe(item2); } [Test] public void metadata_and_db_fields_should_replicate_release() { var item1 = GivenAlbumRelease(); var item2 = GivenAlbumRelease(); item1.Should().NotBe(item2); item1.UseMetadataFrom(item2); item1.UseDbFieldsFrom(item2); item1.Should().Be(item2); } private Album GivenAlbum() { return _fixture.Build() .Without(x => x.ArtistMetadata) .Without(x => x.AlbumReleases) .Without(x => x.Artist) .Without(x => x.ArtistId) .Create(); } [Test] public void two_equivalent_albums_should_be_equal() { var item1 = GivenAlbum(); var item2 = item1.JsonClone(); item1.Should().NotBeSameAs(item2); item1.Should().Be(item2); } [Test] [TestCaseSource(typeof(EqualityPropertySource), "TestCases")] public void two_different_albums_should_not_be_equal(PropertyInfo prop) { var item1 = GivenAlbum(); var item2 = item1.JsonClone(); var different = GivenAlbum(); // make item2 different in the property under consideration if (prop.PropertyType == typeof(bool)) { prop.SetValue(item2, !(bool)prop.GetValue(item1)); } else { prop.SetValue(item2, prop.GetValue(different)); } item1.Should().NotBeSameAs(item2); item1.Should().NotBe(item2); } [Test] public void metadata_and_db_fields_should_replicate_album() { var item1 = GivenAlbum(); var item2 = GivenAlbum(); item1.Should().NotBe(item2); item1.UseMetadataFrom(item2); item1.UseDbFieldsFrom(item2); item1.Should().Be(item2); } private Artist GivenArtist() { return _fixture.Build() .With(x => x.Metadata, new LazyLoaded(_fixture.Create())) .Without(x => x.QualityProfile) .Without(x => x.MetadataProfile) .Without(x => x.Albums) .Without(x => x.Name) .Without(x => x.ForeignArtistId) .Create(); } [Test] public void two_equivalent_artists_should_be_equal() { var item1 = GivenArtist(); var item2 = item1.JsonClone(); item1.Should().NotBeSameAs(item2); item1.Should().Be(item2); } [Test] [TestCaseSource(typeof(EqualityPropertySource), "TestCases")] public void two_different_artists_should_not_be_equal(PropertyInfo prop) { var item1 = GivenArtist(); var item2 = item1.JsonClone(); var different = GivenArtist(); // make item2 different in the property under consideration if (prop.PropertyType == typeof(bool)) { prop.SetValue(item2, !(bool)prop.GetValue(item1)); } else { prop.SetValue(item2, prop.GetValue(different)); } item1.Should().NotBeSameAs(item2); item1.Should().NotBe(item2); } [Test] public void metadata_and_db_fields_should_replicate_artist() { var item1 = GivenArtist(); var item2 = GivenArtist(); item1.Should().NotBe(item2); item1.UseMetadataFrom(item2); item1.UseDbFieldsFrom(item2); item1.Should().Be(item2); } } }