public async Task DowngradeToUnlist()
            {
                var existingVersion = "0.0.1";
                var existingLeaf    = new PackageDetailsCatalogLeaf
                {
                    CommitTimestamp = new DateTimeOffset(2018, 12, 1, 0, 0, 0, TimeSpan.Zero),
                    Url             = "http://example/leaf/0.0.1",
                    PackageId       = _packageId,
                    VerbatimVersion = existingVersion,
                    PackageVersion  = existingVersion,
                    Listed          = false,
                };

                _leaf.Listed           = false;
                _versionListDataResult = new ResultAndAccessCondition <VersionListData>(
                    new VersionListData(new Dictionary <string, VersionPropertiesData>
                {
                    { existingVersion, new VersionPropertiesData(listed: true, semVer2: false) },
                    { _packageVersion, new VersionPropertiesData(listed: true, semVer2: false) },
                }),
                    _versionListDataResult.AccessCondition);
                _latestCatalogLeaves = new LatestCatalogLeaves(
                    new HashSet <NuGetVersion>(),
                    new Dictionary <NuGetVersion, PackageDetailsCatalogLeaf>
                {
                    { NuGetVersion.Parse(existingVersion), existingLeaf },
                });

                var indexActions = await _target.AddCatalogEntriesAsync(
                    _packageId,
                    _latestEntries,
                    _entryToLeaf);

                Assert.Equal(4, indexActions.Search.Count);
                Assert.All(indexActions.Search, x => Assert.IsType <KeyedDocument>(x.Document));
                Assert.All(indexActions.Search, x => Assert.Equal(IndexActionType.Delete, x.ActionType));

                Assert.Equal(2, indexActions.Hijack.Count);
                var existing = indexActions.Hijack.Single(x => x.Document.Key == existingVersion);

                Assert.IsType <HijackDocument.Full>(existing.Document);
                Assert.Equal(IndexActionType.MergeOrUpload, existing.ActionType);
                var added = indexActions.Hijack.Single(x => x.Document.Key == _packageVersion);

                Assert.IsType <HijackDocument.Full>(added.Document);
                Assert.Equal(IndexActionType.MergeOrUpload, added.ActionType);

                Assert.Same(_versionListDataResult.AccessCondition, indexActions.VersionListDataResult.AccessCondition);
                var properties = indexActions.VersionListDataResult.Result.VersionProperties;

                Assert.Equal(
                    new[] { existingVersion, _packageVersion },
                    properties.Keys.ToArray());
                Assert.False(properties[existingVersion].Listed);
                Assert.False(properties[existingVersion].SemVer2);
                Assert.False(properties[_packageVersion].Listed);
                Assert.False(properties[_packageVersion].SemVer2);

                _ownerFetcher.Verify(x => x.GetOwnersOrEmptyAsync(It.IsAny <string>()), Times.Never);
            }
            public BaseFacts(ITestOutputHelper output)
            {
                _versionListDataClient = new Mock <IVersionListDataClient>();
                _leafFetcher           = new Mock <ICatalogLeafFetcher>();
                _ownerFetcher          = new Mock <IDatabaseAuxiliaryDataFetcher>();
                _search = new Mock <ISearchDocumentBuilder>();
                _hijack = new Mock <IHijackDocumentBuilder>();
                _logger = output.GetLogger <CatalogIndexActionBuilder>();

                _packageId = Data.PackageId;
                SetVersion("1.0.0");
                _versionListDataResult = new ResultAndAccessCondition <VersionListData>(
                    new VersionListData(new Dictionary <string, VersionPropertiesData>()),
                    AccessConditionWrapper.GenerateIfNotExistsCondition());
                _owners = Data.Owners;
                _latestCatalogLeaves = new LatestCatalogLeaves(
                    new HashSet <NuGetVersion>(),
                    new Dictionary <NuGetVersion, PackageDetailsCatalogLeaf>());

                _versionListDataClient
                .Setup(x => x.ReadAsync(It.IsAny <string>()))
                .ReturnsAsync(() => _versionListDataResult);

                _search
                .Setup(x => x.LatestFlagsOrNull(It.IsAny <VersionLists>(), It.IsAny <SearchFilters>()))
                .Returns <VersionLists, SearchFilters>((vl, sf) => new SearchDocument.LatestFlags(
                                                           vl.GetLatestVersionInfoOrNull(sf),
                                                           isLatestStable: true,
                                                           isLatest: true));
                _search
                .Setup(x => x.Keyed(It.IsAny <string>(), It.IsAny <SearchFilters>()))
                .Returns <string, SearchFilters>(
                    (i, sf) => new KeyedDocument {
                    Key = sf.ToString()
                });
                _search
                .Setup(x => x.UpdateVersionListFromCatalog(
                           It.IsAny <string>(),
                           It.IsAny <SearchFilters>(),
                           It.IsAny <DateTimeOffset>(),
                           It.IsAny <string>(),
                           It.IsAny <string[]>(),
                           It.IsAny <bool>(),
                           It.IsAny <bool>()))
                .Returns <string, SearchFilters, DateTimeOffset, string, string[], bool, bool>(
                    (i, ct, ci, sf, v, ls, l) => new SearchDocument.UpdateVersionList {
                    Key = sf.ToString()
                });
                _search
                .Setup(x => x.UpdateVersionListAndOwnersFromCatalog(
                           It.IsAny <string>(),
                           It.IsAny <SearchFilters>(),
                           It.IsAny <DateTimeOffset>(),
                           It.IsAny <string>(),
                           It.IsAny <string[]>(),
                           It.IsAny <bool>(),
                           It.IsAny <bool>(),
                           It.IsAny <string[]>()))
                .Returns <string, SearchFilters, DateTimeOffset, string, string[], bool, bool, string[]>(
                    (i, ct, ci, sf, v, ls, l, o) => new SearchDocument.UpdateVersionListAndOwners {
                    Key = sf.ToString()
                });
                _search
                .Setup(x => x.UpdateLatestFromCatalog(
                           It.IsAny <SearchFilters>(),
                           It.IsAny <string[]>(),
                           It.IsAny <bool>(),
                           It.IsAny <bool>(),
                           It.IsAny <string>(),
                           It.IsAny <string>(),
                           It.IsAny <PackageDetailsCatalogLeaf>(),
                           It.IsAny <string[]>()))
                .Returns <SearchFilters, string[], bool, bool, string, string, PackageDetailsCatalogLeaf, string[]>(
                    (sf, v, ls, l, nv, fv, lf, o) => new SearchDocument.UpdateLatest {
                    Key = sf.ToString()
                });

                _hijack
                .Setup(x => x.Keyed(It.IsAny <string>(), It.IsAny <string>()))
                .Returns <string, string>(
                    (i, v) => new KeyedDocument {
                    Key = v
                });
                _hijack
                .Setup(x => x.LatestFromCatalog(
                           It.IsAny <string>(),
                           It.IsAny <string>(),
                           It.IsAny <DateTimeOffset>(),
                           It.IsAny <string>(),
                           It.IsAny <HijackDocumentChanges>()))
                .Returns <string, string, DateTimeOffset, string, HijackDocumentChanges>(
                    (i, v, ct, ci, c) => new HijackDocument.Latest {
                    Key = v
                });
                _hijack
                .Setup(x => x.FullFromCatalog(It.IsAny <string>(), It.IsAny <HijackDocumentChanges>(), It.IsAny <PackageDetailsCatalogLeaf>()))
                .Returns <string, HijackDocumentChanges, PackageDetailsCatalogLeaf>(
                    (v, c, l) => new HijackDocument.Full {
                    Key = v
                });

                _leafFetcher
                .Setup(x => x.GetLatestLeavesAsync(It.IsAny <string>(), It.IsAny <IReadOnlyList <IReadOnlyList <NuGetVersion> > >()))
                .ReturnsAsync(() => _latestCatalogLeaves);

                _ownerFetcher
                .Setup(x => x.GetOwnersOrEmptyAsync(It.IsAny <string>()))
                .ReturnsAsync(() => _owners);

                _target = new CatalogIndexActionBuilder(
                    _versionListDataClient.Object,
                    _leafFetcher.Object,
                    _ownerFetcher.Object,
                    _search.Object,
                    _hijack.Object,
                    _logger);
            }
            public async Task DowngradeToDifferent()
            {
                var existingVersion1 = "0.0.1";
                var existingVersion2 = "0.0.2-alpha";
                var existingLeaf1    = new PackageDetailsCatalogLeaf
                {
                    CommitTimestamp = new DateTimeOffset(2018, 12, 1, 0, 0, 0, TimeSpan.Zero),
                    Url             = "http://example/leaf/0.0.1",
                    PackageId       = _packageId,
                    VerbatimVersion = existingVersion1,
                    PackageVersion  = existingVersion1,
                    Listed          = true,
                };
                var existingLeaf2 = new PackageDetailsCatalogLeaf
                {
                    CommitTimestamp = new DateTimeOffset(2018, 12, 1, 0, 0, 0, TimeSpan.Zero),
                    Url             = "http://example/leaf/0.0.2-alpha",
                    PackageId       = _packageId,
                    VerbatimVersion = existingVersion2,
                    PackageVersion  = existingVersion2,
                    Listed          = true,
                    IsPrerelease    = true,
                };

                _leaf.Listed           = false;
                _versionListDataResult = new ResultAndAccessCondition <VersionListData>(
                    new VersionListData(new Dictionary <string, VersionPropertiesData>
                {
                    { existingVersion1, new VersionPropertiesData(listed: true, semVer2: false) },
                    { existingVersion2, new VersionPropertiesData(listed: true, semVer2: false) },
                    { _packageVersion, new VersionPropertiesData(listed: true, semVer2: false) },
                }),
                    _versionListDataResult.AccessCondition);
                _latestCatalogLeaves = new LatestCatalogLeaves(
                    new HashSet <NuGetVersion>(),
                    new Dictionary <NuGetVersion, PackageDetailsCatalogLeaf>
                {
                    { NuGetVersion.Parse(existingVersion1), existingLeaf1 },
                    { NuGetVersion.Parse(existingVersion2), existingLeaf2 },
                });

                var indexActions = await _target.AddCatalogEntriesAsync(
                    _packageId,
                    _latestEntries,
                    _entryToLeaf);

                Assert.Equal(4, indexActions.Search.Count);
                Assert.All(indexActions.Search, x => Assert.IsType <SearchDocument.UpdateLatest>(x.Document));
                Assert.All(indexActions.Search, x => Assert.Equal(IndexActionType.MergeOrUpload, x.ActionType));

                Assert.Equal(3, indexActions.Hijack.Count);
                var existing1 = indexActions.Hijack.Single(x => x.Document.Key == existingVersion1);

                Assert.IsType <HijackDocument.Full>(existing1.Document);
                Assert.Equal(IndexActionType.MergeOrUpload, existing1.ActionType);
                var existing2 = indexActions.Hijack.Single(x => x.Document.Key == existingVersion2);

                Assert.IsType <HijackDocument.Full>(existing2.Document);
                Assert.Equal(IndexActionType.MergeOrUpload, existing2.ActionType);
                var added = indexActions.Hijack.Single(x => x.Document.Key == _packageVersion);

                Assert.IsType <HijackDocument.Full>(added.Document);
                Assert.Equal(IndexActionType.MergeOrUpload, added.ActionType);

                Assert.Same(_versionListDataResult.AccessCondition, indexActions.VersionListDataResult.AccessCondition);
                var properties = indexActions.VersionListDataResult.Result.VersionProperties;

                Assert.Equal(
                    new[] { existingVersion1, existingVersion2, _packageVersion },
                    properties.Keys.ToArray());
                Assert.True(properties[existingVersion1].Listed);
                Assert.False(properties[existingVersion1].SemVer2);
                Assert.True(properties[existingVersion2].Listed);
                Assert.False(properties[existingVersion2].SemVer2);
                Assert.False(properties[_packageVersion].Listed);
                Assert.False(properties[_packageVersion].SemVer2);

                _leafFetcher.Verify(
                    x => x.GetLatestLeavesAsync(
                        It.IsAny <string>(),
                        It.Is <IReadOnlyList <IReadOnlyList <NuGetVersion> > >(y => y.Count == 2)),
                    Times.Once);

                _ownerFetcher.Verify(x => x.GetOwnersOrEmptyAsync(It.IsAny <string>()), Times.Once);
                _ownerFetcher.Verify(x => x.GetOwnersOrEmptyAsync(_packageId), Times.Once);
            }