Skip to content

Commit

Permalink
Add unit test for MvpNullObjectBasePresenter
Browse files Browse the repository at this point in the history
  • Loading branch information
sockeqwe committed Jul 20, 2015
1 parent 8c77956 commit 400347b
Show file tree
Hide file tree
Showing 6 changed files with 159 additions and 9 deletions.
Original file line number Diff line number Diff line change
@@ -1,10 +1,32 @@
/*
* Copyright 2015. 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.mosby.mvp;

import java.util.HashMap;
import java.util.Map;

import static java.util.Collections.unmodifiableMap;

/**
* Helper class for default type values used by {@link NoOp}
* @author Jens Dirller
* @since 1.2.0
*/
final class Defaults {

private static final Map<Class<?>, Object> DEFAULTS =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@
* presenter before calling {@link #getView()} to access the view.
* </p>
*
* @param <V> type of the {@link MvpView}
* @author Hannes Dorfmann
* @see MvpNullObjectBasePresenter
* @since 1.0.0
*/
public class MvpBasePresenter<V extends MvpView> implements MvpPresenter<V> {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,23 @@
package com.hannesdorfmann.mosby.mvp;

/**
* A {@link MvpPresenter} implmenetation that implements the <a href="https://en.wikipedia.org/wiki/Null_Object_pattern">null
* object pattern</a> for the attached mvp view. So whenever the view gets detached from this
* presenter by calling{@link #detachView(boolean)}, a new "null object" view gets dynamically
* instantiated by using reflections and set as the current
* view (instead of null). The new "null object" view simply does nothing. This avoids null pointer
* exceptions and checks like {@code if (getView() != null)}
*
* @param <V> The type of the {@link MvpView}
* @author Jens Dirller , Hannes Dorfmann
* @see MvpBasePresenter
* @since 1.2.0
*/
public class MvpNullObjectBasePresenter<V extends MvpView> implements MvpPresenter<V> {

private V view;

@Override
public void attachView(V view) {
@Override public void attachView(V view) {
this.view = view;
}

Expand All @@ -16,8 +28,7 @@ protected V getView() {
return view;
}

@Override
public void detachView(boolean retainInstance) {
@Override public void detachView(boolean retainInstance) {
if (view != null) {
//noinspection unchecked
Class<V> viewClass = (Class<V>) view.getClass().getGenericInterfaces()[0];
Expand Down
32 changes: 27 additions & 5 deletions mvp-common/src/main/java/com/hannesdorfmann/mosby/mvp/NoOp.java
Original file line number Diff line number Diff line change
@@ -1,3 +1,20 @@
/*
* Copyright 2015. 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.mosby.mvp;

import java.lang.reflect.InvocationHandler;
Expand All @@ -6,6 +23,12 @@
import static com.hannesdorfmann.mosby.mvp.Defaults.defaultValue;
import static java.lang.reflect.Proxy.newProxyInstance;

/**
* Dynamically proxy to generate a new object instance for a given class by using reflections
*
* @author Jens Dirller
* @since 1.2.0
*/
final class NoOp {

private static final InvocationHandler DEFAULT_VALUE = new DefaultValueInvocationHandler();
Expand All @@ -14,15 +37,14 @@ private NoOp() {
// no instances
}

@SuppressWarnings("unchecked")
public static <T> T of(Class<T> interfaceClass) {
return (T) newProxyInstance(interfaceClass.getClassLoader(), new Class[] { interfaceClass }, DEFAULT_VALUE);
@SuppressWarnings("unchecked") public static <T> T of(Class<T> interfaceClass) {
return (T) newProxyInstance(interfaceClass.getClassLoader(), new Class[] { interfaceClass },
DEFAULT_VALUE);
}

private static class DefaultValueInvocationHandler implements InvocationHandler {

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
@Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return defaultValue(method.getReturnType());
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/*
* Copyright 2015. 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.mosby.mvp;

import java.util.Date;
import org.junit.Assert;
import org.junit.Test;

/**
* @author Hannes Dorfmann
*/
public class MvpNullObjectBasePresenterTest {

public interface TestView extends MvpView {
public void showFoo(TestData data);

public void showThat();
}

public class TestData {
int a;
String b;
Date date = new Date();
}

public class TestNullObjectPresenter
extends MvpNullObjectBasePresenter<MvpNullObjectBasePresenterTest.TestView> {

public void viewShowFoo(TestData data) {
getView().showFoo(data);
}

public void viewShowThat() {
getView().showThat();
}
}

@Test public void testAttachDetach() {

TestNullObjectPresenter presenter = new TestNullObjectPresenter();

try {
// NullPointer exception should be thrown
presenter.getView();
Assert.fail("Nullpointer Exception should be thrown but haven't");
} catch (NullPointerException e) {
// Expected exception
}

TestView view = new TestView() {
@Override public void showFoo(TestData data) {
}

@Override public void showThat() {
}
};

presenter.attachView(view);
Assert.assertNotNull(presenter.getView());
Assert.assertTrue(presenter.getView() == view);

// Test with retainInstance == false
presenter.detachView(false);
Assert.assertNotNull(presenter.getView());
Assert.assertTrue(presenter.getView() != view); // Null Object view

// Reattach real view
presenter.attachView(view);
Assert.assertNotNull(presenter.getView());
Assert.assertTrue(presenter.getView() == view);

// Test with retainInstance == true
presenter.detachView(true);
Assert.assertNotNull(presenter.getView());
Assert.assertTrue(presenter.getView() != view); // Null Object view
}

}

0 comments on commit 400347b

Please sign in to comment.