/*
* Copyright 2017 Hannes Dorfmann.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.hannesdorfmann.mosby3.mvi;
import android.support.annotation.NonNull;
import com.hannesdorfmann.mosby3.mvp.MvpView;
import io.reactivex.Observable;
import io.reactivex.functions.Consumer;
import io.reactivex.subjects.PublishSubject;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import org.junit.Assert;
import org.junit.Test;
import org.omg.CORBA.Object;
/**
* @author Hannes Dorfmann
*/
public class MviBasePresenterTest {
@Test public void bindIntentsAndUnbindIntentsOnlyOnce() {
final AtomicInteger bindInvocations = new AtomicInteger(0);
final AtomicInteger unbindInvocations = new AtomicInteger(0);
MvpView view = new MvpView() {
};
MviBasePresenter<MvpView, Object> presenter = new MviBasePresenter<MvpView, Object>() {
@Override protected void bindIntents() {
bindInvocations.incrementAndGet();
}
@Override protected void unbindIntents() {
super.unbindIntents();
unbindInvocations.incrementAndGet();
}
};
presenter.attachView(view);
presenter.detachView(true);
presenter.attachView(view);
presenter.detachView(true);
presenter.attachView(view);
presenter.detachView(false);
Assert.assertEquals(1, bindInvocations.get());
Assert.assertEquals(1, unbindInvocations.get());
}
@Test public void keepUnderlayingSubscriptions() {
final List<String> intentsData = new ArrayList<>();
final PublishSubject<String> businessLogic = PublishSubject.create();
KeepUndelyingSubscriptionsView view = new KeepUndelyingSubscriptionsView();
MviBasePresenter<KeepUndelyingSubscriptionsView, String> presenter =
new MviBasePresenter<KeepUndelyingSubscriptionsView, String>() {
@Override protected void bindIntents() {
intent(new ViewIntentBinder<KeepUndelyingSubscriptionsView, String>() {
@NonNull @Override
public Observable<String> bind(@NonNull KeepUndelyingSubscriptionsView view) {
return view.anIntent;
}
}).subscribe(new Consumer<String>() {
@Override public void accept(String s) throws Exception {
intentsData.add(s);
}
});
subscribeViewState(businessLogic,
new ViewStateConsumer<KeepUndelyingSubscriptionsView, String>() {
@Override public void accept(@NonNull KeepUndelyingSubscriptionsView view,
@NonNull String viewState) {
view.render(viewState);
}
});
}
};
view.anIntent.onNext("Should never hit the presenter because View not attached");
Assert.assertTrue(intentsData.isEmpty());
presenter.attachView(view);
view.anIntent.onNext("1 Intent");
Assert.assertEquals(Arrays.asList("1 Intent"), intentsData);
businessLogic.onNext("1 bl");
Assert.assertEquals(Arrays.asList("1 bl"), view.renderedModels);
businessLogic.onNext("2 bl");
Assert.assertEquals(Arrays.asList("1 bl", "2 bl"), view.renderedModels);
view.anIntent.onNext("2 Intent");
Assert.assertEquals(Arrays.asList("1 Intent", "2 Intent"), intentsData);
// Detach View temporarily
presenter.detachView(true);
Assert.assertFalse(view.anIntent.hasObservers());
businessLogic.onNext("3 bl");
Assert.assertEquals(Arrays.asList("1 bl", "2 bl"), view.renderedModels);
businessLogic.onNext("4 bl");
Assert.assertEquals(Arrays.asList("1 bl", "2 bl"), view.renderedModels);
view.anIntent.onNext("Doesn't hit presenter because view not attached to presenter");
Assert.assertEquals(Arrays.asList("1 Intent", "2 Intent"), intentsData);
// Reattach View
presenter.attachView(view); // This will call view.render() method
Assert.assertEquals(Arrays.asList("1 bl", "2 bl", "4 bl"), view.renderedModels);
view.anIntent.onNext("3 Intent");
Assert.assertEquals(Arrays.asList("1 Intent", "2 Intent", "3 Intent"), intentsData);
businessLogic.onNext("5 bl");
Assert.assertEquals(Arrays.asList("1 bl", "2 bl", "4 bl", "5 bl"), view.renderedModels);
// Detach View permanently
presenter.detachView(false);
Assert.assertFalse(businessLogic.hasObservers()); // No more observers
Assert.assertFalse(view.anIntent.hasObservers()); // No more observers
view.anIntent.onNext("This will never be delivered to presenter");
Assert.assertEquals(Arrays.asList("1 Intent", "2 Intent", "3 Intent"), intentsData);
businessLogic.onNext("This will never reach the view");
Assert.assertEquals(Arrays.asList("1 bl", "2 bl", "4 bl", "5 bl"), view.renderedModels);
}
@Test public void resetOnViewDetachedPermanently() {
final AtomicInteger bindInvocations = new AtomicInteger(0);
final AtomicInteger unbindInvocations = new AtomicInteger(0);
MvpView view = new MvpView() {
};
MviBasePresenter<MvpView, Object> presenter = new MviBasePresenter<MvpView, Object>() {
@Override protected void bindIntents() {
bindInvocations.incrementAndGet();
}
@Override protected void unbindIntents() {
super.unbindIntents();
unbindInvocations.incrementAndGet();
}
};
presenter.attachView(view);
presenter.detachView(false);
presenter.attachView(view);
presenter.detachView(true);
presenter.attachView(view);
presenter.detachView(false);
Assert.assertEquals(2, bindInvocations.get());
Assert.assertEquals(2, unbindInvocations.get());
}
private static class KeepUndelyingSubscriptionsView implements MvpView {
List<String> renderedModels = new ArrayList<>();
PublishSubject<String> anIntent = PublishSubject.create();
public void render(String model) {
renderedModels.add(model);
}
}
}