context: //
  //  SearchableRepositoryBaseQA.cs
  //
  //  Author:
  //       Giacomo Tesio <giacomo@tesio.it>
  //
  //  Copyright (c) 2010-2013 Giacomo Tesio
  //
  //  This file is part of Epic.NET.
  //
  //  Epic.NET is free software: you can redistribute it and/or modify
  //  it under the terms of the GNU Affero General Public License as published by
  //  the Free Software Foundation, either version 3 of the License, or
  //  (at your option) any later version.
  //
  //  Epic.NET is distributed in the hope that it will be useful,
  //  but WITHOUT ANY WARRANTY; without even the implied warranty of
  //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  //  GNU Affero General Public License for more details.
  //
  //  You should have received a copy of the GNU Affero General Public License
  //  along with this program.  If not, see <http://www.gnu.org/licenses/>.
  //
  using System;
  using NUnit.Framework;
  using Rhino.Mocks;
  using Epic.Collections;
  using Epic.Math;
  using Challenge00.DDDSample.Cargo;
  using System.Linq;
  using Epic.Specifications;
  using System.Collections.Generic;
  using Epic.Environment;
  
  namespace Epic.Query.Object.UnitTests
  {
      [TestFixture]
      public class SearchableRepositoryBaseQA : RhinoMocksFixtureBase
      {
          [Test]
          public void Initialize_withoutAnyArgument_throwsArgumentNullException()
          {
              // arrange:
              IIdentityMap<string, int> identityMap = GenerateStrictMock<IIdentityMap<string, int>>();
              IEntityLoader<string, int> loader = GenerateStrictMock<IEntityLoader<string, int>>();
              IMapping<string, int> identification = GenerateStrictMock<IMapping<string, int>>();
              string deferrerName = "Test";
  
              // assert:
              Assert.Throws<ArgumentNullException>(delegate {
                  new Fakes.FakeSearchableRepository<string, int>(null, loader, identification, deferrerName);
              });
              Assert.Throws<ArgumentNullException>(delegate {
                  new Fakes.FakeSearchableRepository<string, int>(identityMap, null, identification, deferrerName);
              }); 
              Assert.Throws<ArgumentNullException>(delegate {
                  new Fakes.FakeSearchableRepository<string, int>(identityMap, loader, null, deferrerName);
              });
              Assert.Throws<ArgumentNullException>(delegate {
                  new Fakes.FakeSearchableRepository<string, int>(identityMap, loader, identification, null);
              });
              Assert.Throws<ArgumentNullException>(delegate {
                  new Fakes.FakeSearchableRepository<string, int>(identityMap, loader, identification, string.Empty);
              });
          }
  
          [TestCase("dummy", "dummy")]
          [TestCase("dummy", 1)]
          public void Initialize_withEveryArgument_works<TEntity, TIdentity>(TEntity dummyEntity, TIdentity dummyId) where TEntity : class where TIdentity : IEquatable<TIdentity>
          {
              // arrange:
              IIdentityMap<TEntity, TIdentity> identityMap = GenerateStrictMock<IIdentityMap<TEntity, TIdentity>>();
              IEntityLoader<TEntity, TIdentity> loader = GenerateStrictMock<IEntityLoader<TEntity, TIdentity>>();
              IMapping<TEntity, TIdentity> identification = GenerateStrictMock<IMapping<TEntity, TIdentity>>();
              string deferrerName = "Test";
  
              // act:
              new Fakes.FakeSearchableRepository<TEntity, TIdentity>(identityMap, loader, identification, deferrerName);
          }
  
          [Test]
          public void ItemAccess_withoutAKey_throwsArgumentNullException()
          {
              // arrange:
              string deferrerName = "Test";
              IIdentityMap<ICargo, TrackingId> identityMap = GenerateStrictMock<IIdentityMap<ICargo, TrackingId>>();
              IEntityLoader<ICargo, TrackingId> loader = GenerateStrictMock<IEntityLoader<ICargo, TrackingId>>();
              IMapping<ICargo, TrackingId> identification = GenerateStrictMock<IMapping<ICargo, TrackingId>>();
              SearchableRepositoryBase<ICargo, TrackingId> toTest = new Fakes.FakeSearchableRepository<ICargo, TrackingId>(identityMap, loader, identification, deferrerName);
              TrackingId id = null;
  
              // assert:
              Assert.Throws<ArgumentNullException>(delegate {
                  ICargo c = toTest[id];
              });
          }
  
          [Test]
          public void GetItem_withUnknownEntity_retrieveTheEntityFromTheLoader()
          {
              // arrange:
              TrackingId id = new TrackingId("TEST");
              ICargo expectedResult = GenerateStrictMock<ICargo>();
              string deferrerName = "Test";
              IMapping<ICargo, TrackingId> identification = GenerateStrictMock<IMapping<ICargo, TrackingId>>();
              IIdentityMap<ICargo, TrackingId> identityMap = GenerateStrictMock<IIdentityMap<ICargo, TrackingId>>();
              identityMap.Expect(m => m.Knows(id)).Return(false).Repeat.Once();
              identityMap.Expect(m => m.Register(expectedResult)).Repeat.Once();
              identityMap.Expect(m => m[id]).Return(expectedResult).Repeat.Once();
              IEntityLoader<ICargo, TrackingId> loader = GenerateStrictMock<IEntityLoader<ICargo, TrackingId>>();
              loader.Expect(l => l.Load(new TrackingId[] { id })).Return(new ICargo[]{expectedResult}).Repeat.Once();
              Fakes.FakeSearchableRepository<ICargo, TrackingId> toTest = GeneratePartialMock<Fakes.FakeSearchableRepository<ICargo, TrackingId>>(identityMap, loader, identification, deferrerName);
              toTest.Expect(r => r.CallInstrument(ref expectedResult)).Repeat.Once();
  
              // act:
              ICargo result = toTest[id];
  
              // assert:
              Assert.AreSame(expectedResult, result);
          }
  
          [Test]
          public void GetItem_withUnknownEntity_rethrowExceptionsFromTheInfrastructure()
          {
              // arrange:
              TrackingId id = new TrackingId("TEST");
              string deferrerName = "Test";
              Exception loadingException = new Exception();
              IMapping<ICargo, TrackingId> identification = GenerateStrictMock<IMapping<ICargo, TrackingId>>();
              IIdentityMap<ICargo, TrackingId> identityMap = GenerateStrictMock<IIdentityMap<ICargo, TrackingId>>();
              identityMap.Expect(m => m.Knows(id)).Return(false).Repeat.Once();
              IEntityLoader<ICargo, TrackingId> loader = GenerateStrictMock<IEntityLoader<ICargo, TrackingId>>();
              loader.Expect(l => l.Load(new TrackingId[] { id })).Throw(loadingException).Repeat.Once();
              SearchableRepositoryBase<ICargo, TrackingId> toTest = new Fakes.FakeSearchableRepository<ICargo, TrackingId>(identityMap, loader, identification, deferrerName);
              
              // assert:
              Assert.Throws<KeyNotFoundException<TrackingId>>(delegate {
                  ICargo c = toTest[id];
              });
          }
  
          [Test]
          public void GetItem_withAKnownEntity_returnsTheEntityInTheMap()
          {
              // arrange:
              TrackingId id = new TrackingId("TEST");
              ICargo expectedResult = GenerateStrictMock<ICargo>();
              string deferrerName = "Test";
              IMapping<ICargo, TrackingId> identification = GenerateStrictMock<IMapping<ICargo, TrackingId>>();
              IIdentityMap<ICargo, TrackingId> identityMap = GenerateStrictMock<IIdentityMap<ICargo, TrackingId>>();
              identityMap.Expect(m => m.Knows(id)).Return(true).Repeat.Once();
              identityMap.Expect(m => m[id]).Return(expectedResult).Repeat.Once();
              IEntityLoader<ICargo, TrackingId> loader = GenerateStrictMock<IEntityLoader<ICargo, TrackingId>>();
              SearchableRepositoryBase<ICargo, TrackingId> toTest = new Fakes.FakeSearchableRepository<ICargo, TrackingId>(identityMap, loader, identification, deferrerName);
              
              // act:
              ICargo result = toTest[id];
              
              // assert:
              Assert.AreSame(expectedResult, result);
          }
  
          [Test]
          public void LoadingAsEntityLoader_asAnEntityLoader_loadsOnlyEntitiesUnknownToTheIdentityMapButReturnsAllEntitiesRequired()
          {
              // arrange:
              TrackingId id1 = new TrackingId("TEST1");
              TrackingId id2 = new TrackingId("TEST2");
              TrackingId id3 = new TrackingId("TEST3");
              TrackingId id4 = new TrackingId("TEST4");
              ICargo expectedResult1 = GenerateStrictMock<ICargo>();
              ICargo expectedResult2 = GenerateStrictMock<ICargo>();
              ICargo expectedResult3 = GenerateStrictMock<ICargo>();
              ICargo expectedResult4 = GenerateStrictMock<ICargo>();
              string deferrerName = "Test";
              IMapping<ICargo, TrackingId> identification = GenerateStrictMock<IMapping<ICargo, TrackingId>>();
              IIdentityMap<ICargo, TrackingId> identityMap = GenerateStrictMock<IIdentityMap<ICargo, TrackingId>>();
              identityMap.Expect(m => m.Knows(id1)).Return(true).Repeat.Once();
              identityMap.Expect(m => m[id1]).Return(expectedResult1).Repeat.Once();
              identityMap.Expect(m => m.Knows(id2)).Return(false).Repeat.Once();
              identityMap.Expect(m => m.Register(expectedResult2)).Repeat.Once();
              identityMap.Expect(m => m.Knows(id3)).Return(true).Repeat.Once();
              identityMap.Expect(m => m[id3]).Return(expectedResult3).Repeat.Once();
              identityMap.Expect(m => m.Knows(id4)).Return(false).Repeat.Once();
              identityMap.Expect(m => m.Register(expectedResult4)).Repeat.Once();
              IEntityLoader<ICargo, TrackingId> loader = GenerateStrictMock<IEntityLoader<ICargo, TrackingId>>();
              loader.Expect(l => l.Load(new TrackingId[] { id2, id4 })).Return(new ICargo[]{expectedResult2, expectedResult4}).Repeat.Once();
              Fakes.FakeSearchableRepository<ICargo, TrackingId> searchableRepo = GeneratePartialMock<Fakes.FakeSearchableRepository<ICargo, TrackingId>>(identityMap, loader, identification, deferrerName);
              searchableRepo.Expect(r => r.CallInstrument(ref expectedResult2)).Repeat.Once();
              searchableRepo.Expect(r => r.CallInstrument(ref expectedResult4)).Repeat.Once();
              IEntityLoader<ICargo, TrackingId> toTest = searchableRepo;
  
              // act:
              ICargo[] result = toTest.Load(new TrackingId[]{id1, id2, id3, id4}).ToArray();
  
              // assert:
              Assert.AreSame(expectedResult1, result[0]);
              Assert.AreSame(expectedResult2, result[1]);
              Assert.AreSame(expectedResult3, result[2]);
              Assert.AreSame(expectedResult4, result[3]);
          }
  
          [Test]
          public void LoadingAsEntityLoader_withoutIdentifiers_throwsArgumentNullException()
          {
              // arrange:
              string deferrerName = "Test";
              IMapping<ICargo, TrackingId> identification = GenerateStrictMock<IMapping<ICargo, TrackingId>>();
              IIdentityMap<ICargo, TrackingId> identityMap = GenerateStrictMock<IIdentityMap<ICargo, TrackingId>>();
              IEntityLoader<ICargo, TrackingId> loader = GenerateStrictMock<IEntityLoader<ICargo, TrackingId>>();
              Fakes.FakeSearchableRepository<ICargo, TrackingId> searchableRepo = GeneratePartialMock<Fakes.FakeSearchableRepository<ICargo, TrackingId>>(identityMap, loader, identification, deferrerName);
              IEntityLoader<ICargo, TrackingId> toTest = searchableRepo;
              
              // assert:
              Assert.Throws<ArgumentNullException>(delegate {
                  toTest.Load(null);
              });
          }
  
          [Test]
          public void LoadingAsEntityLoader_withoutIdentifiers_returnAnEmptyEnumeration()
          {
              // arrange:
              string deferrerName = "Test";
              IMapping<ICargo, TrackingId> identification = GenerateStrictMock<IMapping<ICargo, TrackingId>>();
              IIdentityMap<ICargo, TrackingId> identityMap = GenerateStrictMock<IIdentityMap<ICargo, TrackingId>>();
              IEntityLoader<ICargo, TrackingId> loader = GenerateStrictMock<IEntityLoader<ICargo, TrackingId>>();
              Fakes.FakeSearchableRepository<ICargo, TrackingId> searchableRepo = GeneratePartialMock<Fakes.FakeSearchableRepository<ICargo, TrackingId>>(identityMap, loader, identification, deferrerName);
              IEntityLoader<ICargo, TrackingId> toTest = searchableRepo;
              
              // act:
              var r = toTest.Load();
              
              // assert:
              CollectionAssert.IsEmpty(r);
          }
  
          [Test]
          public void Identify_withAnyEntity_callsTheIdentificationMapping()
          {
              // arrange:
              string deferrerName = "Test";
              TrackingId id = new TrackingId("TEST");
              ICargo cargo = GenerateStrictMock<ICargo>();
              IMapping<ICargo, TrackingId> identification = GenerateStrictMock<IMapping<ICargo, TrackingId>>();
              identification.Expect(i => i.ApplyTo(cargo)).Return(id).Repeat.Once();
              IIdentityMap<ICargo, TrackingId> identityMap = GenerateStrictMock<IIdentityMap<ICargo, TrackingId>>();
              IEntityLoader<ICargo, TrackingId> loader = GenerateStrictMock<IEntityLoader<ICargo, TrackingId>>();
              Fakes.FakeSearchableRepository<ICargo, TrackingId> toTest = GeneratePartialMock<Fakes.FakeSearchableRepository<ICargo, TrackingId>>(identityMap, loader, identification, deferrerName);
  
              // act:
  
gt:             var r = toTest.CallIdentify(cargo);