// Path: simple-stack/src/test/java/com/zhuinden/simplestack/helpers/ServiceProvider.java
// public class ServiceProvider
//         implements ScopedServices {
//     @Override
//     public void bindServices(@Nonnull ServiceBinder serviceBinder) {
//         Object key = serviceBinder.getKey();
//         if(key instanceof HasServices) {
//             ((HasServices) key).bindServices(serviceBinder);
//             return;
//         }
//         if(key instanceof HasParentServices) {
//             ((HasParentServices) key).bindServices(serviceBinder);
//             //noinspection UnnecessaryReturnStatement
//             return;
//         }
//     }
// }
// 
// Path: simple-stack/src/test/java/com/zhuinden/simplestack/helpers/TestKey.java
// public class TestKey
//         implements Parcelable {
//     public final String name;
// 
//     public TestKey(String name) {
//         this.name = name;
//     }
// 
//     protected TestKey(Parcel in) {
//         name = in.readString();
//     }
// 
//     public static final Creator<TestKey> CREATOR = new Creator<TestKey>() {
//         @Override
//         public TestKey createFromParcel(Parcel in) {
//             return new TestKey(in);
//         }
// 
//         @Override
//         public TestKey[] newArray(int size) {
//             return new TestKey[size];
//         }
//     };
// 
//     @Override
//     public boolean equals(Object o) {
//         if(this == o) {
//             return true;
//         }
//         if(o == null || getClass() != o.getClass()) {
//             return false;
//         }
//         TestKey key = (TestKey) o;
//         return name.equals(key.name);
//     }
// 
//     @Override
//     public int hashCode() {
//         return name.hashCode();
//     }
// 
//     @Override
//     public String toString() {
//         return String.format("%s{%h}", name, this);
//     }
// 
//     @Override
//     public int describeContents() {
//         return 0;
//     }
// 
//     @Override
//     public void writeToParcel(Parcel dest, int flags) {
//         dest.writeString(name);
//     }
// }
// 
// Path: simple-stack/src/test/java/com/zhuinden/simplestack/helpers/TestKeyWithExplicitParent.java
// public abstract class TestKeyWithExplicitParent extends TestKeyWithScope implements HasParentServices {
//     public TestKeyWithExplicitParent(String name) {
//         super(name);
//     }
// 
//     protected TestKeyWithExplicitParent(Parcel in) {
//         super(in);
//     }
// 
//     @Override
//     public final void bindServices(ServiceBinder serviceBinder) {
//         if(name.equals(serviceBinder.getScopeTag())) {
//             bindOwnServices(serviceBinder);
//         } else {
//             bindParentServices(serviceBinder);
//         }
//     }
// 
//     protected abstract void bindParentServices(ServiceBinder serviceBinder);
// 
//     protected abstract void bindOwnServices(ServiceBinder serviceBinder);
// }
// 
// Path: simple-stack/src/test/java/com/zhuinden/simplestack/helpers/TestKeyWithOnlyParentServices.java
// public abstract class TestKeyWithOnlyParentServices extends TestKey implements HasParentServices {
//     private final List<String> parentScopes;
// 
//     public TestKeyWithOnlyParentServices(String name, List<String> parentScopes) {
//         super(name);
//         this.parentScopes = parentScopes;
//     }
// 
//     @Nonnull
//     @Override
//     public List<String> getParentScopes() {
//         return parentScopes;
//     }
// }
// 
// Path: simple-stack/src/test/java/com/zhuinden/simplestack/helpers/TestKeyWithScope.java
// public abstract class TestKeyWithScope
//         extends TestKey
//         implements HasServices {
//     public TestKeyWithScope(String name) {
//         super(name);
//     }
// 
//     protected TestKeyWithScope(Parcel in) {
//         super(in);
//     }
// 
//     @Nonnull
//     @Override
//     public String getScopeTag() {
//         return name;
//     }
// }


import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import static org.assertj.core.api.Assertions.assertThat;
import android.content.Context;
import android.os.Parcelable;
import android.view.View;
import com.zhuinden.simplestack.helpers.ServiceProvider;
import com.zhuinden.simplestack.helpers.TestKey;
import com.zhuinden.simplestack.helpers.TestKeyWithExplicitParent;
import com.zhuinden.simplestack.helpers.TestKeyWithOnlyParentServices;
import com.zhuinden.simplestack.helpers.TestKeyWithScope;
import com.zhuinden.statebundle.StateBundle;
import org.junit.Assert;
import org.junit.Test;
import org.mockito.Mockito;
        backstack.setup(History.of(firstKey, secondKey, thirdKey, key, lastKey));
        backstack.setStateChanger(new StateChanger() {
            @Override
            public void handleStateChange(@Nonnull StateChange stateChange, @Nonnull Callback completionCallback) {
                completionCallback.stateChangeComplete();
            }
        });

        backstack.exitScopeTo("blah", secondKey, StateChange.BACKWARD);

        assertThat(backstack.getHistory()).containsExactly(firstKey, secondKey);
    }

    @Test
    public void exitScopeToExitsExplicitScopeCorrectlyAndAppendsIfNotFound() {
        Backstack backstack = new Backstack();

        backstack.setScopedServices(new ServiceProvider());

        Object firstKey = new TestKey("firstKey");
        Object secondKey = new TestKey("secondKey");
        Object thirdKey = new TestKey("thirdKey");
        Object lastKey = new TestKey("lastKey");

        Object key = new TestKeyWithOnlyParentServices("key", History.of("blah")) {
            @Override
            public void bindServices(ServiceBinder serviceBinder) {
            }
        };

// Path: simple-stack/src/test/java/com/zhuinden/simplestack/helpers/ServiceProvider.java
// public class ServiceProvider
//         implements ScopedServices {
//     @Override
//     public void bindServices(@Nonnull ServiceBinder serviceBinder) {
//         Object key = serviceBinder.getKey();
//         if(key instanceof HasServices) {
//             ((HasServices) key).bindServices(serviceBinder);
//             return;
//         }
//         if(key instanceof HasParentServices) {
//             ((HasParentServices) key).bindServices(serviceBinder);
//             //noinspection UnnecessaryReturnStatement
//             return;
//         }
//     }
// }
// 
// Path: simple-stack/src/test/java/com/zhuinden/simplestack/helpers/TestKey.java
// public class TestKey
//         implements Parcelable {
//     public final String name;
// 
//     public TestKey(String name) {
//         this.name = name;
//     }
// 
//     protected TestKey(Parcel in) {
//         name = in.readString();
//     }
// 
//     public static final Creator<TestKey> CREATOR = new Creator<TestKey>() {
//         @Override
//         public TestKey createFromParcel(Parcel in) {
//             return new TestKey(in);
//         }
// 
//         @Override
//         public TestKey[] newArray(int size) {
//             return new TestKey[size];
//         }
//     };
// 
//     @Override
//     public boolean equals(Object o) {
//         if(this == o) {
//             return true;
//         }
//         if(o == null || getClass() != o.getClass()) {
//             return false;
//         }
//         TestKey key = (TestKey) o;
//         return name.equals(key.name);
//     }
// 
//     @Override
//     public int hashCode() {
//         return name.hashCode();
//     }
// 
//     @Override
//     public String toString() {
//         return String.format("%s{%h}", name, this);
//     }
// 
//     @Override
//     public int describeContents() {
//         return 0;
//     }
// 
//     @Override
//     public void writeToParcel(Parcel dest, int flags) {
//         dest.writeString(name);
//     }
// }
// 
// Path: simple-stack/src/test/java/com/zhuinden/simplestack/helpers/TestKeyWithExplicitParent.java
// public abstract class TestKeyWithExplicitParent extends TestKeyWithScope implements HasParentServices {
//     public TestKeyWithExplicitParent(String name) {
//         super(name);
//     }
// 
//     protected TestKeyWithExplicitParent(Parcel in) {
//         super(in);
//     }
// 
//     @Override
//     public final void bindServices(ServiceBinder serviceBinder) {
//         if(name.equals(serviceBinder.getScopeTag())) {
//             bindOwnServices(serviceBinder);
//         } else {
//             bindParentServices(serviceBinder);
//         }
//     }
// 
//     protected abstract void bindParentServices(ServiceBinder serviceBinder);
// 
//     protected abstract void bindOwnServices(ServiceBinder serviceBinder);
// }
// 
// Path: simple-stack/src/test/java/com/zhuinden/simplestack/helpers/TestKeyWithOnlyParentServices.java
// public abstract class TestKeyWithOnlyParentServices extends TestKey implements HasParentServices {
//     private final List<String> parentScopes;
// 
//     public TestKeyWithOnlyParentServices(String name, List<String> parentScopes) {
//         super(name);
//         this.parentScopes = parentScopes;
//     }
// 
//     @Nonnull
//     @Override
//     public List<String> getParentScopes() {
//         return parentScopes;
//     }
// }
// 
// Path: simple-stack/src/test/java/com/zhuinden/simplestack/helpers/TestKeyWithScope.java
// public abstract class TestKeyWithScope
//         extends TestKey
//         implements HasServices {
//     public TestKeyWithScope(String name) {
//         super(name);
//     }
// 
//     protected TestKeyWithScope(Parcel in) {
//         super(in);
//     }
// 
//     @Nonnull
//     @Override
//     public String getScopeTag() {
//         return name;
//     }
// }


// Path: simple-stack/src/test/java/com/zhuinden/simplestack/BackstackTest.java
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import static org.assertj.core.api.Assertions.assertThat;
import android.content.Context;
import android.os.Parcelable;
import android.view.View;
import com.zhuinden.simplestack.helpers.ServiceProvider;
import com.zhuinden.simplestack.helpers.TestKey;
import com.zhuinden.simplestack.helpers.TestKeyWithExplicitParent;
import com.zhuinden.simplestack.helpers.TestKeyWithOnlyParentServices;
import com.zhuinden.simplestack.helpers.TestKeyWithScope;
import com.zhuinden.statebundle.StateBundle;
import org.junit.Assert;
import org.junit.Test;
import org.mockito.Mockito;

        backstack.setup(History.of(firstKey, secondKey, thirdKey, key, lastKey));
        backstack.setStateChanger(new StateChanger() {
            @Override
            public void handleStateChange(@Nonnull StateChange stateChange, @Nonnull Callback completionCallback) {
                completionCallback.stateChangeComplete();
            }
        });

        backstack.exitScopeTo("blah", secondKey, StateChange.BACKWARD);

        assertThat(backstack.getHistory()).containsExactly(firstKey, secondKey);
    }

    @Test
    public void exitScopeToExitsExplicitScopeCorrectlyAndAppendsIfNotFound() {
        Backstack backstack = new Backstack();

        backstack.setScopedServices(new ServiceProvider());

        Object firstKey = new TestKey("firstKey");
        Object secondKey = new TestKey("secondKey");
        Object thirdKey = new TestKey("thirdKey");
        Object lastKey = new TestKey("lastKey");

        Object key = new TestKeyWithOnlyParentServices("key", History.of("blah")) {
            @Override
            public void bindServices(ServiceBinder serviceBinder) {
            }
        };

        Object targetKey = new TestKey("targetKey");