// Path: algoliasearch/src/main/java/com/algolia/search/saas/helpers/BrowseIterator.java
// public class BrowseIterator {
// 
//     /**
//      * Listener for {@link com.algolia.search.saas.helpers.BrowseIterator}.
//      */
//     public interface BrowseIteratorHandler {
//         /**
//          * Called at each batch of results.
//          *
//          * @param iterator The iterator where the results originate from.
//          * @param result   The results (in case of success).
//          * @param error    The error (in case of error).
//          */
//         void handleBatch(@NonNull BrowseIterator iterator, JSONObject result, AlgoliaException error);
//     }
// 
//     /** The index being browsed. */
//     private Index index;
// 
//     /** The query used to filter the results. */
//     private Query query;
// 
//     /** Listener. */
//     private BrowseIteratorHandler handler;
// 
//     /** Eventual request-specific options */
//     private @Nullable RequestOptions requestOptions;
// 
//     /** Cursor to use for the next call, if any. */
//     private String cursor;
// 
//     /** Whether the iteration has already started. */
//     private transient boolean started = false;
// 
//     /** Whether the iteration has been cancelled by the user. */
//     private transient boolean cancelled = false;
// 
//     /** The currently ongoing request, if any. */
//     private Request request;
// 
//     /**
//      * Construct a new browse iterator.
//      * NOTE: The iteration does not start automatically. You have to call `start()` explicitly.
//      *
//      * @param index   The index to be browsed.
//      * @param query   The query used to filter the results.
//      * @param handler Handler called for each batch of results.
//      */
//     public BrowseIterator(@NonNull Index index, @NonNull Query query, @NonNull BrowseIteratorHandler handler) {
//         this(index, query, null, handler);
//     }
// 
//     /**
//      * Construct a new browse iterator.
//      * NOTE: The iteration does not start automatically. You have to call `start()` explicitly.
//      *
//      * @param index          The index to be browsed.
//      * @param query          The query used to filter the results.
//      * @param requestOptions Request-specific options.
//      * @param handler        Handler called for each batch of results.
//      */
//     public BrowseIterator(@NonNull Index index, @NonNull Query query, @Nullable RequestOptions requestOptions, @NonNull BrowseIteratorHandler handler) {
//         this.index = index;
//         this.query = query;
//         this.handler = handler;
//         this.requestOptions = requestOptions;
//     }
// 
//     /**
//      * Start the iteration.
//      */
//     public void start() {
//         if (started) {
//             throw new IllegalStateException();
//         }
//         started = true;
//         request = index.browseAsync(query, requestOptions, completionHandler);
//     }
// 
//     /**
//      * Cancel the iteration.
//      * This cancels any currently ongoing request, and cancels the iteration.
//      * The listener will not be called after the iteration has been cancelled.
//      */
//     public void cancel() {
//         if (cancelled) {
//             return;
//         }
//         request.cancel();
//         request = null;
//         cancelled = true;
//     }
// 
//     /**
//      * Determine if there is more content to be browsed.
//      * WARNING: Can only be called from the handler, once the iteration has started.
//      */
//     public boolean hasNext() {
//         if (!started) {
//             throw new IllegalStateException();
//         }
//         return cursor != null;
//     }
// 
//     private void next() {
//         if (!hasNext()) {
//             throw new IllegalStateException();
//         }
//         request = index.browseFromAsync(cursor, requestOptions, completionHandler);
//     }
// 
//     private CompletionHandler completionHandler = new CompletionHandler() {
//         @Override
//         public void requestCompleted(JSONObject content, AlgoliaException error) {
//             if (!cancelled) {
//                 handler.handleBatch(BrowseIterator.this, content, error);
//                 if (error == null) {
//                     cursor = content.optString("cursor", null);
//                     if (!cancelled && hasNext()) {
//                         next();
//                     }
//                 }
//             }
//         }
//     };
// }


import org.mockito.internal.util.reflection.Whitebox;
import org.robolectric.android.util.concurrent.RoboExecutorService;
import java.util.ArrayList;
import java.util.List;
import static junit.framework.Assert.fail;
import android.support.annotation.NonNull;
import com.algolia.search.saas.helpers.BrowseIterator;
import org.json.JSONArray;
import org.json.JSONObject;
import org.junit.Test;
        // WARNING: Robolectric cannot work with custom executors in `AsyncTask`, so we substitute the client's
        // executor with a Robolectric-compliant one.
        Whitebox.setInternalState(client, "searchExecutorService", new RoboExecutorService());
        indexName = Helpers.safeIndexName("àlgol?à-android");
        index = client.initIndex(indexName);

        objects = new ArrayList<JSONObject>();
        for (int i = 0; i < 1500; ++i) {
            objects.add(new JSONObject(String.format("{\"dummy\": %d}", i)));
        }
        JSONObject task = index.addObjects(new JSONArray(objects), /* requestOptions: */ null);
        index.waitTask(task.getString("taskID"));

        JSONArray objectIDs = task.getJSONArray("objectIDs");
        ids = new ArrayList<String>();
        for (int i = 0; i < objectIDs.length(); ++i) {
            ids.add(objectIDs.getString(i));
        }
    }

    @Override
    public void tearDown() throws Exception {
        client.deleteIndex(indexName, /* requestOptions: */ null);
    }

    @Test
    public void nominal() throws Exception {
        Query query = new Query();
        AssertBrowseHandler handler = new AssertBrowseHandler() {
            @Override
// Path: algoliasearch/src/main/java/com/algolia/search/saas/helpers/BrowseIterator.java
// public class BrowseIterator {
// 
//     /**
//      * Listener for {@link com.algolia.search.saas.helpers.BrowseIterator}.
//      */
//     public interface BrowseIteratorHandler {
//         /**
//          * Called at each batch of results.
//          *
//          * @param iterator The iterator where the results originate from.
//          * @param result   The results (in case of success).
//          * @param error    The error (in case of error).
//          */
//         void handleBatch(@NonNull BrowseIterator iterator, JSONObject result, AlgoliaException error);
//     }
// 
//     /** The index being browsed. */
//     private Index index;
// 
//     /** The query used to filter the results. */
//     private Query query;
// 
//     /** Listener. */
//     private BrowseIteratorHandler handler;
// 
//     /** Eventual request-specific options */
//     private @Nullable RequestOptions requestOptions;
// 
//     /** Cursor to use for the next call, if any. */
//     private String cursor;
// 
//     /** Whether the iteration has already started. */
//     private transient boolean started = false;
// 
//     /** Whether the iteration has been cancelled by the user. */
//     private transient boolean cancelled = false;
// 
//     /** The currently ongoing request, if any. */
//     private Request request;
// 
//     /**
//      * Construct a new browse iterator.
//      * NOTE: The iteration does not start automatically. You have to call `start()` explicitly.
//      *
//      * @param index   The index to be browsed.
//      * @param query   The query used to filter the results.
//      * @param handler Handler called for each batch of results.
//      */
//     public BrowseIterator(@NonNull Index index, @NonNull Query query, @NonNull BrowseIteratorHandler handler) {
//         this(index, query, null, handler);
//     }
// 
//     /**
//      * Construct a new browse iterator.
//      * NOTE: The iteration does not start automatically. You have to call `start()` explicitly.
//      *
//      * @param index          The index to be browsed.
//      * @param query          The query used to filter the results.
//      * @param requestOptions Request-specific options.
//      * @param handler        Handler called for each batch of results.
//      */
//     public BrowseIterator(@NonNull Index index, @NonNull Query query, @Nullable RequestOptions requestOptions, @NonNull BrowseIteratorHandler handler) {
//         this.index = index;
//         this.query = query;
//         this.handler = handler;
//         this.requestOptions = requestOptions;
//     }
// 
//     /**
//      * Start the iteration.
//      */
//     public void start() {
//         if (started) {
//             throw new IllegalStateException();
//         }
//         started = true;
//         request = index.browseAsync(query, requestOptions, completionHandler);
//     }
// 
//     /**
//      * Cancel the iteration.
//      * This cancels any currently ongoing request, and cancels the iteration.
//      * The listener will not be called after the iteration has been cancelled.
//      */
//     public void cancel() {
//         if (cancelled) {
//             return;
//         }
//         request.cancel();
//         request = null;
//         cancelled = true;
//     }
// 
//     /**
//      * Determine if there is more content to be browsed.
//      * WARNING: Can only be called from the handler, once the iteration has started.
//      */
//     public boolean hasNext() {
//         if (!started) {
//             throw new IllegalStateException();
//         }
//         return cursor != null;
//     }
// 
//     private void next() {
//         if (!hasNext()) {
//             throw new IllegalStateException();
//         }
//         request = index.browseFromAsync(cursor, requestOptions, completionHandler);
//     }
// 
//     private CompletionHandler completionHandler = new CompletionHandler() {
//         @Override
//         public void requestCompleted(JSONObject content, AlgoliaException error) {
//             if (!cancelled) {
//                 handler.handleBatch(BrowseIterator.this, content, error);
//                 if (error == null) {
//                     cursor = content.optString("cursor", null);
//                     if (!cancelled && hasNext()) {
//                         next();
//                     }
//                 }
//             }
//         }
//     };
// }


// Path: algoliasearch/src/test/java/com/algolia/search/saas/BrowseIteratorTest.java
import org.mockito.internal.util.reflection.Whitebox;
import org.robolectric.android.util.concurrent.RoboExecutorService;
import java.util.ArrayList;
import java.util.List;
import static junit.framework.Assert.fail;
import android.support.annotation.NonNull;
import com.algolia.search.saas.helpers.BrowseIterator;
import org.json.JSONArray;
import org.json.JSONObject;
import org.junit.Test;

        // WARNING: Robolectric cannot work with custom executors in `AsyncTask`, so we substitute the client's
        // executor with a Robolectric-compliant one.
        Whitebox.setInternalState(client, "searchExecutorService", new RoboExecutorService());
        indexName = Helpers.safeIndexName("àlgol?à-android");
        index = client.initIndex(indexName);

        objects = new ArrayList<JSONObject>();
        for (int i = 0; i < 1500; ++i) {
            objects.add(new JSONObject(String.format("{\"dummy\": %d}", i)));
        }
        JSONObject task = index.addObjects(new JSONArray(objects), /* requestOptions: */ null);
        index.waitTask(task.getString("taskID"));

        JSONArray objectIDs = task.getJSONArray("objectIDs");
        ids = new ArrayList<String>();
        for (int i = 0; i < objectIDs.length(); ++i) {
            ids.add(objectIDs.getString(i));
        }
    }

    @Override
    public void tearDown() throws Exception {
        client.deleteIndex(indexName, /* requestOptions: */ null);
    }

    @Test
    public void nominal() throws Exception {
        Query query = new Query();
        AssertBrowseHandler handler = new AssertBrowseHandler() {
            @Override
            void doHandleBatch(BrowseIterator iterator, JSONObject result, AlgoliaException error) {