void testSetEndPosition_RestoreEndCursor_Reverse(bool unique) {
    auto harnessHelper = newHarnessHelper();
    auto opCtx = harnessHelper->newOperationContext();
    auto sorted = harnessHelper->newSortedDataInterface(unique,
                                                        {
                                                         {key1, loc1}, {key4, loc1},
                                                        });

    auto cursor = sorted->newCursor(opCtx.get(), false);
    cursor->setEndPosition(key3, true);

    ASSERT_EQ(cursor->seek(key4, true), IndexKeyEntry(key4, loc1));

    cursor->saveUnpositioned();
    insertToIndex(opCtx,
                  sorted,
                  {
                   {key2, loc1},  // in range
                   {key3, loc1},  // out of range
                  });
    cursor->restore();  // must restore end cursor even with saveUnpositioned().

    ASSERT_EQ(cursor->seek(key4, true), IndexKeyEntry(key4, loc1));
    ASSERT_EQ(cursor->next(), IndexKeyEntry(key3, loc1));
    ASSERT_EQ(cursor->next(), boost::none);
}
void testSetEndPosition_Seek_Reverse(bool unique, bool inclusive) {
    auto harnessHelper = newHarnessHelper();
    auto opCtx = harnessHelper->newOperationContext();
    auto sorted = harnessHelper->newSortedDataInterface(unique,
                                                        {
                                                         {key1, loc1},
                                                         {key2, loc1},
                                                         // No key3
                                                         {key4, loc1},
                                                        });

    auto cursor = sorted->newCursor(opCtx.get(), false);
    cursor->setEndPosition(key2, inclusive);

    // Directly seeking past end is considered out of range.
    ASSERT_EQ(cursor->seek(key1, true), boost::none);
    ASSERT_EQ(cursor->seekExact(key1), boost::none);

    // Seeking to key2 directly or indirectly is only returned if endPosition is inclusive.
    auto maybeKey2 = inclusive ? boost::make_optional(IndexKeyEntry(key2, loc1)) : boost::none;

    // direct
    ASSERT_EQ(cursor->seek(key2, true), maybeKey2);
    ASSERT_EQ(cursor->seekExact(key2), maybeKey2);

    // indirect
    ASSERT_EQ(cursor->seek(key3, true), maybeKey2);

    cursor->saveUnpositioned();
    removeFromIndex(opCtx, sorted, {{key2, loc1}});
    cursor->restore();

    ASSERT_EQ(cursor->seek(key3, true), boost::none);
    ASSERT_EQ(cursor->seek(key2, true), boost::none);
}
    // Ensure that SaveUnpositioned allows later use of the cursor.
    TEST(SortedDataInterface, SaveUnpositionedAndRestore) {
        auto harnessHelper = newHarnessHelper();
        auto opCtx = harnessHelper->newOperationContext();
        auto sorted = harnessHelper->newSortedDataInterface(false, {
            {key1, loc1},
            {key2, loc1},
            {key3, loc1},
        });

        auto cursor = sorted->newCursor(opCtx.get());

        ASSERT_EQ(cursor->seek(key2, true), IndexKeyEntry(key2, loc1));

        cursor->saveUnpositioned();
        removeFromIndex(opCtx, sorted, {{key2, loc1}});
        cursor->restore(opCtx.get());

        ASSERT_EQ(cursor->seek(key1, true), IndexKeyEntry(key1, loc1));

        cursor->saveUnpositioned();
        cursor->restore(opCtx.get());

        ASSERT_EQ(cursor->seek(key3, true), IndexKeyEntry(key3, loc1));
    }
        void save() override {
            // Keep original position if we haven't moved since the last restore.
            _opCtx = nullptr;
            if (_lastMoveWasRestore)
                return;

            if (_isEOF) {
                saveUnpositioned();
                return;
            }

            _savedAtEnd = false;
            _savedKey = _it->key.getOwned();
            _savedLoc = _it->loc;
            // Doing nothing with end cursor since it will do full reseek on restore.
        }