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
 package com.reactnativenavigation.parse;
1
 package com.reactnativenavigation.parse;
2
 
2
 
3
+import android.support.annotation.CheckResult;
3
 import android.support.annotation.NonNull;
4
 import android.support.annotation.NonNull;
4
 import android.text.TextUtils;
5
 import android.text.TextUtils;
5
 
6
 
53
         topTabOptions.tabIndex = i;
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
     Options withDefaultOptions(final Options other) {
67
     Options withDefaultOptions(final Options other) {

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

4
     public Text(String value) {
4
     public Text(String value) {
5
         super(value);
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
 
55
 
56
     @Override
56
     @Override
57
     public void applyOptions(Options options, ReactComponent childComponent) {
57
     public void applyOptions(Options options, ReactComponent childComponent) {
58
+        super.applyOptions(options, childComponent);
58
         int tabIndex = findTabContainingComponent(childComponent);
59
         int tabIndex = findTabContainingComponent(childComponent);
59
         if (tabIndex >= 0) new BottomTabOptionsPresenter(bottomTabs).present(options, tabIndex);
60
         if (tabIndex >= 0) new BottomTabOptionsPresenter(bottomTabs).present(options, tabIndex);
60
     }
61
     }
123
 
124
 
124
 	@Override
125
 	@Override
125
 	public void mergeOptions(Options options) {
126
 	public void mergeOptions(Options options) {
126
-        this.options.mergeWith(options);
127
+        this.options = this.options.mergeWith(options);
127
         if (options.bottomTabsOptions.currentTabIndex != NO_INT_VALUE) {
128
         if (options.bottomTabsOptions.currentTabIndex != NO_INT_VALUE) {
128
             selectTabAtIndex(options.bottomTabsOptions.currentTabIndex);
129
             selectTabAtIndex(options.bottomTabsOptions.currentTabIndex);
129
         }
130
         }

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

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

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

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

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

36
 
36
 
37
     @Override
37
     @Override
38
     public void applyOptions(Options options, ReactComponent component) {
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
     @Override
44
     @Override

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

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

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

69
 
69
 
70
     @Override
70
     @Override
71
     public void applyOptions(Options options, ReactComponent childComponent) {
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
     @Override
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
 import static com.reactnativenavigation.parse.Options.BooleanOptions.*;
14
 import static com.reactnativenavigation.parse.Options.BooleanOptions.*;
15
 import static org.assertj.core.api.Java6Assertions.*;
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
     private static final String TITLE = "the title";
19
     private static final String TITLE = "the title";
20
     private static final int TOP_BAR_BACKGROUND_COLOR = 0xff123456;
20
     private static final int TOP_BAR_BACKGROUND_COLOR = 0xff123456;
46
     @Test
46
     @Test
47
     public void parsesJson() throws Exception {
47
     public void parsesJson() throws Exception {
48
         JSONObject json = new JSONObject()
48
         JSONObject json = new JSONObject()
49
-                .put("topBar", createTopBar())
49
+                .put("topBar", createTopBar(TOP_BAR_HIDDEN))
50
                 .put("bottomTabs", createBottomTabs());
50
                 .put("bottomTabs", createBottomTabs());
51
         Options result = Options.parse(mockLoader, json);
51
         Options result = Options.parse(mockLoader, json);
52
         assertResult(result);
52
         assertResult(result);
77
     }
77
     }
78
 
78
 
79
     @NonNull
79
     @NonNull
80
-    private JSONObject createTopBar() throws JSONException {
80
+    private JSONObject createTopBar(Options.BooleanOptions hidden) throws JSONException {
81
         return new JSONObject()
81
         return new JSONObject()
82
                 .put("title", "the title")
82
                 .put("title", "the title")
83
                 .put("backgroundColor", TOP_BAR_BACKGROUND_COLOR)
83
                 .put("backgroundColor", TOP_BAR_BACKGROUND_COLOR)
84
                 .put("textColor", TOP_BAR_TEXT_COLOR)
84
                 .put("textColor", TOP_BAR_TEXT_COLOR)
85
                 .put("textFontSize", TOP_BAR_FONT_SIZE)
85
                 .put("textFontSize", TOP_BAR_FONT_SIZE)
86
                 .put("textFontFamily", TOP_BAR_FONT_FAMILY)
86
                 .put("textFontFamily", TOP_BAR_FONT_FAMILY)
87
-                .put("hidden", TOP_BAR_HIDDEN)
87
+                .put("hidden", hidden)
88
                 .put("drawBehind", TOP_BAR_DRAW_BEHIND)
88
                 .put("drawBehind", TOP_BAR_DRAW_BEHIND)
89
                 .put("hideOnScroll", TOP_BAR_HIDE_ON_SCROLL);
89
                 .put("hideOnScroll", TOP_BAR_HIDE_ON_SCROLL);
90
     }
90
     }
110
                 .put("tabBadge", BOTTOM_TABS_BADGE);
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
     @Test
129
     @Test
114
     public void mergeDefaultOptions() throws Exception {
130
     public void mergeDefaultOptions() throws Exception {
115
         JSONObject json = new JSONObject();
131
         JSONObject json = new JSONObject();
116
-        json.put("topBar", createTopBar());
132
+        json.put("topBar", createTopBar(TOP_BAR_HIDDEN));
117
         json.put("bottomTabs", createBottomTabs());
133
         json.put("bottomTabs", createBottomTabs());
118
         Options defaultOptions = Options.parse(mockLoader, json);
134
         Options defaultOptions = Options.parse(mockLoader, json);
119
         Options options = new Options();
135
         Options options = new Options();
120
 
136
 
121
-        options.mergeWith(defaultOptions);
122
-        assertResult(options);
137
+        assertResult(options.mergeWith(defaultOptions));
123
     }
138
     }
124
 
139
 
125
     @Test
140
     @Test
130
         Options defaultOptions = Options.parse(mockLoader, defaultJson);
145
         Options defaultOptions = Options.parse(mockLoader, defaultJson);
131
 
146
 
132
         JSONObject json = new JSONObject()
147
         JSONObject json = new JSONObject()
133
-                .put("topBar", createTopBar())
148
+                .put("topBar", createTopBar(TOP_BAR_HIDDEN))
134
                 .put("bottomTabs", createBottomTabs());
149
                 .put("bottomTabs", createBottomTabs());
135
         Options options = Options.parse(mockLoader, json);
150
         Options options = Options.parse(mockLoader, json);
136
         options.withDefaultOptions(defaultOptions);
151
         options.withDefaultOptions(defaultOptions);

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

217
     public void setOptions_CallsApplyNavigationOptions() {
217
     public void setOptions_CallsApplyNavigationOptions() {
218
         ComponentViewController componentVc = new SimpleComponentViewController(activity, "theId", new Options());
218
         ComponentViewController componentVc = new SimpleComponentViewController(activity, "theId", new Options());
219
         componentVc.setParentController(parentController);
219
         componentVc.setParentController(parentController);
220
-        assertThat(componentVc.getOptions().topBarOptions.title.get("")).isEmpty();
220
+        assertThat(componentVc.options.topBarOptions.title.get("")).isEmpty();
221
         uut.setRoot(componentVc, new MockPromise());
221
         uut.setRoot(componentVc, new MockPromise());
222
 
222
 
223
         Options options = new Options();
223
         Options options = new Options();
224
         options.topBarOptions.title = new Text("new title");
224
         options.topBarOptions.title = new Text("new title");
225
 
225
 
226
         uut.setOptions("theId", options);
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
     @Test
230
     @Test

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

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

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

21
 import java.util.ArrayList;
21
 import java.util.ArrayList;
22
 import java.util.List;
22
 import java.util.List;
23
 
23
 
24
+import static org.mockito.ArgumentMatchers.any;
25
+import static org.mockito.ArgumentMatchers.eq;
24
 import static org.mockito.Mockito.spy;
26
 import static org.mockito.Mockito.spy;
25
 import static org.mockito.Mockito.times;
27
 import static org.mockito.Mockito.times;
26
 import static org.mockito.Mockito.verify;
28
 import static org.mockito.Mockito.verify;
148
         verify(tabControllers.get(0), times(1)).onViewAppeared();
150
         verify(tabControllers.get(0), times(1)).onViewAppeared();
149
         verify(tabControllers.get(1), times(0)).onViewAppeared();
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
     @Test
157
     @Test
178
 
181
 
179
         uut.onViewAppeared();
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
     private IReactView tab(TopTabsViewPager topTabs, final int index) {
187
     private IReactView tab(TopTabsViewPager topTabs, final int index) {