Browse Source

Options.mergeWith does not mutate

Guy Carmeli 6 years ago
parent
commit
eb3340ce51

+ 9
- 5
lib/android/app/src/main/java/com/reactnativenavigation/parse/Options.java View File

@@ -1,5 +1,6 @@
1 1
 package com.reactnativenavigation.parse;
2 2
 
3
+import android.support.annotation.CheckResult;
3 4
 import android.support.annotation.NonNull;
4 5
 import android.text.TextUtils;
5 6
 
@@ -53,11 +54,14 @@ public class Options implements DEFAULT_VALUES {
53 54
         topTabOptions.tabIndex = i;
54 55
     }
55 56
 
56
-	public void mergeWith(final Options other) {
57
-        topBarOptions.mergeWith(other.topBarOptions);
58
-        topTabsOptions.mergeWith(other.topTabsOptions);
59
-        bottomTabOptions.mergeWith(other.bottomTabOptions);
60
-        bottomTabsOptions.mergeWith(other.bottomTabsOptions);
57
+    @CheckResult
58
+	public Options mergeWith(final Options other) {
59
+        Options result = new Options();
60
+        result.topBarOptions.mergeWith(other.topBarOptions);
61
+        result.topTabsOptions.mergeWith(other.topTabsOptions);
62
+        result.bottomTabOptions.mergeWith(other.bottomTabOptions);
63
+        result.bottomTabsOptions.mergeWith(other.bottomTabsOptions);
64
+        return result;
61 65
     }
62 66
 
63 67
     Options withDefaultOptions(final Options other) {

+ 5
- 0
lib/android/app/src/main/java/com/reactnativenavigation/parse/Text.java View File

@@ -4,4 +4,9 @@ public class Text extends Param<String> {
4 4
     public Text(String value) {
5 5
         super(value);
6 6
     }
7
+
8
+    @Override
9
+    public String toString() {
10
+        return hasValue() ? value : "No Value";
11
+    }
7 12
 }

+ 2
- 1
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/BottomTabsController.java View File

@@ -55,6 +55,7 @@ public class BottomTabsController extends ParentController implements AHBottomNa
55 55
 
56 56
     @Override
57 57
     public void applyOptions(Options options, ReactComponent childComponent) {
58
+        super.applyOptions(options, childComponent);
58 59
         int tabIndex = findTabContainingComponent(childComponent);
59 60
         if (tabIndex >= 0) new BottomTabOptionsPresenter(bottomTabs).present(options, tabIndex);
60 61
     }
@@ -123,7 +124,7 @@ public class BottomTabsController extends ParentController implements AHBottomNa
123 124
 
124 125
 	@Override
125 126
 	public void mergeOptions(Options options) {
126
-        this.options.mergeWith(options);
127
+        this.options = this.options.mergeWith(options);
127 128
         if (options.bottomTabsOptions.currentTabIndex != NO_INT_VALUE) {
128 129
             selectTabAtIndex(options.bottomTabsOptions.currentTabIndex);
129 130
         }

+ 6
- 6
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/ComponentViewController.java View File

@@ -27,7 +27,6 @@ public class ComponentViewController extends ViewController<ComponentLayout> imp
27 27
     @Override
28 28
     public void onViewAppeared() {
29 29
         super.onViewAppeared();
30
-        view.applyOptions(options);
31 30
         view.sendComponentStart();
32 31
     }
33 32
 
@@ -37,6 +36,11 @@ public class ComponentViewController extends ViewController<ComponentLayout> imp
37 36
         super.onViewDisappear();
38 37
     }
39 38
 
39
+    @Override
40
+    public void applyOptions(Options options) {
41
+        view.applyOptions(options);
42
+    }
43
+
40 44
     @Override
41 45
     protected boolean isViewShown() {
42 46
         return super.isViewShown() && view.isReady();
@@ -51,15 +55,11 @@ public class ComponentViewController extends ViewController<ComponentLayout> imp
51 55
 
52 56
     @Override
53 57
     public void mergeOptions(Options options) {
54
-        this.options.mergeWith(options);
58
+        this.options = this.options.mergeWith(options);
55 59
         view.applyOptions(this.options);
56 60
         applyOnParentController(parentController -> parentController.applyOptions(this.options, view));
57 61
     }
58 62
 
59
-    Options getOptions() {
60
-        return options;
61
-    }
62
-
63 63
     ReactComponent getComponent() {
64 64
         return view;
65 65
     }

+ 3
- 1
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/ParentController.java View File

@@ -1,6 +1,7 @@
1 1
 package com.reactnativenavigation.viewcontrollers;
2 2
 
3 3
 import android.app.Activity;
4
+import android.support.annotation.CallSuper;
4 5
 import android.support.annotation.NonNull;
5 6
 import android.support.annotation.Nullable;
6 7
 import android.support.v4.view.ViewPager;
@@ -55,8 +56,9 @@ public abstract class ParentController<T extends ViewGroup> extends ViewControll
55 56
         return false;
56 57
     }
57 58
 
59
+    @CallSuper
58 60
     public void applyOptions(Options options, ReactComponent childComponent) {
59
-
61
+        this.options = this.options.mergeWith(options);
60 62
     }
61 63
 
62 64
 	@Override

+ 3
- 2
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/StackController.java View File

@@ -36,8 +36,9 @@ public class StackController extends ParentController <StackLayout> {
36 36
 
37 37
     @Override
38 38
     public void applyOptions(Options options, ReactComponent component) {
39
-        stackLayout.applyOptions(options, component);
40
-        applyOnParentController(parentController -> ((ParentController) parentController).applyOptions(options, component));
39
+        super.applyOptions(options, component);
40
+        stackLayout.applyOptions(this.options, component);
41
+        applyOnParentController(parentController -> ((ParentController) parentController).applyOptions(this.options, component));
41 42
     }
42 43
 
43 44
     @Override

+ 3
- 0
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/ViewController.java View File

@@ -1,6 +1,7 @@
1 1
 package com.reactnativenavigation.viewcontrollers;
2 2
 
3 3
 import android.app.Activity;
4
+import android.support.annotation.CallSuper;
4 5
 import android.support.annotation.NonNull;
5 6
 import android.support.annotation.Nullable;
6 7
 import android.support.annotation.VisibleForTesting;
@@ -132,6 +133,7 @@ public abstract class ViewController<T extends ViewGroup> implements ViewTreeObs
132 133
 
133 134
     public void onViewAppeared() {
134 135
         isShown = true;
136
+        applyOptions(options);
135 137
         applyOnParentController(parentController -> {
136 138
             parentController.clearOptions();
137 139
             if (getView() instanceof ReactComponent) parentController.applyOptions(options, (ReactComponent) getView());
@@ -142,6 +144,7 @@ public abstract class ViewController<T extends ViewGroup> implements ViewTreeObs
142 144
         isShown = false;
143 145
     }
144 146
 
147
+    @CallSuper
145 148
     public void destroy() {
146 149
         if (isShown) {
147 150
             isShown = false;

+ 2
- 1
lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/toptabs/TopTabsController.java View File

@@ -69,7 +69,8 @@ public class TopTabsController extends ParentController<TopTabsViewPager> implem
69 69
 
70 70
     @Override
71 71
     public void applyOptions(Options options, ReactComponent childComponent) {
72
-        applyOnParentController(parentController -> ((ParentController) parentController).applyOptions(options, childComponent));
72
+        super.applyOptions(options, childComponent);
73
+        applyOnParentController(parentController -> ((ParentController) parentController).applyOptions(this.options, childComponent));
73 74
     }
74 75
 
75 76
     @Override

lib/android/app/src/test/java/com/reactnativenavigation/parse/NavigationOptionsTest.java → lib/android/app/src/test/java/com/reactnativenavigation/parse/OptionsTest.java View File

@@ -14,7 +14,7 @@ import org.mockito.*;
14 14
 import static com.reactnativenavigation.parse.Options.BooleanOptions.*;
15 15
 import static org.assertj.core.api.Java6Assertions.*;
16 16
 
17
-public class NavigationOptionsTest extends BaseTest {
17
+public class OptionsTest extends BaseTest {
18 18
 
19 19
     private static final String TITLE = "the title";
20 20
     private static final int TOP_BAR_BACKGROUND_COLOR = 0xff123456;
@@ -46,7 +46,7 @@ public class NavigationOptionsTest extends BaseTest {
46 46
     @Test
47 47
     public void parsesJson() throws Exception {
48 48
         JSONObject json = new JSONObject()
49
-                .put("topBar", createTopBar())
49
+                .put("topBar", createTopBar(TOP_BAR_HIDDEN))
50 50
                 .put("bottomTabs", createBottomTabs());
51 51
         Options result = Options.parse(mockLoader, json);
52 52
         assertResult(result);
@@ -77,14 +77,14 @@ public class NavigationOptionsTest extends BaseTest {
77 77
     }
78 78
 
79 79
     @NonNull
80
-    private JSONObject createTopBar() throws JSONException {
80
+    private JSONObject createTopBar(Options.BooleanOptions hidden) throws JSONException {
81 81
         return new JSONObject()
82 82
                 .put("title", "the title")
83 83
                 .put("backgroundColor", TOP_BAR_BACKGROUND_COLOR)
84 84
                 .put("textColor", TOP_BAR_TEXT_COLOR)
85 85
                 .put("textFontSize", TOP_BAR_FONT_SIZE)
86 86
                 .put("textFontFamily", TOP_BAR_FONT_FAMILY)
87
-                .put("hidden", TOP_BAR_HIDDEN)
87
+                .put("hidden", hidden)
88 88
                 .put("drawBehind", TOP_BAR_DRAW_BEHIND)
89 89
                 .put("hideOnScroll", TOP_BAR_HIDE_ON_SCROLL);
90 90
     }
@@ -110,16 +110,31 @@ public class NavigationOptionsTest extends BaseTest {
110 110
                 .put("tabBadge", BOTTOM_TABS_BADGE);
111 111
     }
112 112
 
113
+    @Test
114
+    public void mergeDoesNotMutate() throws Exception {
115
+        JSONObject json1 = new JSONObject();
116
+        json1.put("topBar", createTopBar(Options.BooleanOptions.True));
117
+        Options options1 = Options.parse(mockLoader, json1);
118
+
119
+
120
+        JSONObject json2 = new JSONObject();
121
+        json2.put("topBar", createTopBar(Options.BooleanOptions.False));
122
+        Options options2 = Options.parse(mockLoader, json2);
123
+
124
+        Options merged = options1.mergeWith(options2);
125
+        assertThat(options1.topBarOptions.hidden).isEqualTo(Options.BooleanOptions.True);
126
+        assertThat(merged.topBarOptions.hidden).isEqualTo(False);
127
+    }
128
+
113 129
     @Test
114 130
     public void mergeDefaultOptions() throws Exception {
115 131
         JSONObject json = new JSONObject();
116
-        json.put("topBar", createTopBar());
132
+        json.put("topBar", createTopBar(TOP_BAR_HIDDEN));
117 133
         json.put("bottomTabs", createBottomTabs());
118 134
         Options defaultOptions = Options.parse(mockLoader, json);
119 135
         Options options = new Options();
120 136
 
121
-        options.mergeWith(defaultOptions);
122
-        assertResult(options);
137
+        assertResult(options.mergeWith(defaultOptions));
123 138
     }
124 139
 
125 140
     @Test
@@ -130,7 +145,7 @@ public class NavigationOptionsTest extends BaseTest {
130 145
         Options defaultOptions = Options.parse(mockLoader, defaultJson);
131 146
 
132 147
         JSONObject json = new JSONObject()
133
-                .put("topBar", createTopBar())
148
+                .put("topBar", createTopBar(TOP_BAR_HIDDEN))
134 149
                 .put("bottomTabs", createBottomTabs());
135 150
         Options options = Options.parse(mockLoader, json);
136 151
         options.withDefaultOptions(defaultOptions);

+ 2
- 2
lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/NavigatorTest.java View File

@@ -217,14 +217,14 @@ public class NavigatorTest extends BaseTest {
217 217
     public void setOptions_CallsApplyNavigationOptions() {
218 218
         ComponentViewController componentVc = new SimpleComponentViewController(activity, "theId", new Options());
219 219
         componentVc.setParentController(parentController);
220
-        assertThat(componentVc.getOptions().topBarOptions.title.get("")).isEmpty();
220
+        assertThat(componentVc.options.topBarOptions.title.get("")).isEmpty();
221 221
         uut.setRoot(componentVc, new MockPromise());
222 222
 
223 223
         Options options = new Options();
224 224
         options.topBarOptions.title = new Text("new title");
225 225
 
226 226
         uut.setOptions("theId", options);
227
-        assertThat(componentVc.getOptions().topBarOptions.title.get()).isEqualTo("new title");
227
+        assertThat(componentVc.options.topBarOptions.title.get()).isEqualTo("new title");
228 228
     }
229 229
 
230 230
     @Test

+ 7
- 9
lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/OptionsApplyingTest.java View File

@@ -59,7 +59,7 @@ public class OptionsApplyingTest extends BaseTest {
59 59
 
60 60
     @Test
61 61
     public void initialOptionsAppliedOnAppear() throws Exception {
62
-        assertThat(uut.getOptions()).isSameAs(initialNavigationOptions);
62
+        assertThat(uut.options).isSameAs(initialNavigationOptions);
63 63
         initialNavigationOptions.topBarOptions.title = new Text("the title");
64 64
         StackController stackController = new StackController(activity, "stackId", new Options());
65 65
         stackController.animatePush(uut, new MockPromise() {});
@@ -72,12 +72,11 @@ public class OptionsApplyingTest extends BaseTest {
72 72
     @Test
73 73
     public void mergeNavigationOptionsUpdatesCurrentOptions() throws Exception {
74 74
         uut.ensureViewIsCreated();
75
-        assertThat(uut.getOptions().topBarOptions.title.get("")).isEmpty();
75
+        assertThat(uut.options.topBarOptions.title.get("")).isEmpty();
76 76
         Options options = new Options();
77 77
         options.topBarOptions.title = new Text("new title");
78 78
         uut.mergeOptions(options);
79
-        assertThat(uut.getOptions().topBarOptions.title.get()).isEqualTo("new title");
80
-        assertThat(uut.getOptions()).isSameAs(initialNavigationOptions);
79
+        assertThat(uut.options.topBarOptions.title.get()).isEqualTo("new title");
81 80
     }
82 81
 
83 82
     @Test
@@ -107,8 +106,7 @@ public class OptionsApplyingTest extends BaseTest {
107 106
 
108 107
     @Test
109 108
     public void appliesTopBarTextColor() throws Exception {
110
-        assertThat(uut.getOptions()).isSameAs(initialNavigationOptions);
111
-        initialNavigationOptions.topBarOptions.title = new Text("the title");
109
+        assertThat(uut.options).isSameAs(initialNavigationOptions);
112 110
         stackController.animatePush(uut, new MockPromise() {
113 111
             @Override
114 112
             public void resolve(@Nullable Object value) {
@@ -125,7 +123,7 @@ public class OptionsApplyingTest extends BaseTest {
125 123
 
126 124
     @Test
127 125
     public void appliesTopBarTextSize() throws Exception {
128
-        assertThat(uut.getOptions()).isSameAs(initialNavigationOptions);
126
+        assertThat(uut.options).isSameAs(initialNavigationOptions);
129 127
         initialNavigationOptions.topBarOptions.title = new Text("the title");
130 128
         uut.ensureViewIsCreated();
131 129
         uut.onViewAppeared();
@@ -141,7 +139,7 @@ public class OptionsApplyingTest extends BaseTest {
141 139
 
142 140
     @Test
143 141
     public void appliesTopBarHidden() throws Exception {
144
-        assertThat(uut.getOptions()).isSameAs(initialNavigationOptions);
142
+        assertThat(uut.options).isSameAs(initialNavigationOptions);
145 143
         initialNavigationOptions.topBarOptions.title = new Text("the title");
146 144
         uut.ensureViewIsCreated();
147 145
         uut.onViewAppeared();
@@ -156,7 +154,7 @@ public class OptionsApplyingTest extends BaseTest {
156 154
 
157 155
     @Test
158 156
     public void appliesDrawUnder() throws Exception {
159
-        assertThat(uut.getOptions()).isSameAs(initialNavigationOptions);
157
+        assertThat(uut.options).isSameAs(initialNavigationOptions);
160 158
         initialNavigationOptions.topBarOptions.title = new Text("the title");
161 159
         initialNavigationOptions.topBarOptions.drawBehind = Options.BooleanOptions.False;
162 160
         uut.ensureViewIsCreated();

+ 5
- 2
lib/android/app/src/test/java/com/reactnativenavigation/viewcontrollers/TopTabsViewControllerTest.java View File

@@ -21,6 +21,8 @@ import org.mockito.Mockito;
21 21
 import java.util.ArrayList;
22 22
 import java.util.List;
23 23
 
24
+import static org.mockito.ArgumentMatchers.any;
25
+import static org.mockito.ArgumentMatchers.eq;
24 26
 import static org.mockito.Mockito.spy;
25 27
 import static org.mockito.Mockito.times;
26 28
 import static org.mockito.Mockito.verify;
@@ -148,7 +150,8 @@ public class TopTabsViewControllerTest extends BaseTest {
148 150
         verify(tabControllers.get(0), times(1)).onViewAppeared();
149 151
         verify(tabControllers.get(1), times(0)).onViewAppeared();
150 152
 
151
-        verify(uut, times(1)).applyOptions(tabOptions.get(0), ((ComponentViewController) tabControllers.get(0)).getComponent());
153
+        ReactComponent comp = ((ComponentViewController) tabControllers.get(0)).getComponent();
154
+        verify(uut, times(1)).applyOptions(any(Options.class), eq(comp));
152 155
     }
153 156
 
154 157
     @Test
@@ -178,7 +181,7 @@ public class TopTabsViewControllerTest extends BaseTest {
178 181
 
179 182
         uut.onViewAppeared();
180 183
 
181
-        verify(topTabsLayout, times(1)).applyOptions(options);
184
+        verify(topTabsLayout, times(1)).applyOptions(any(Options.class));
182 185
     }
183 186
 
184 187
     private IReactView tab(TopTabsViewPager topTabs, final int index) {