1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package androidx.core.view 18 19 import android.support.test.InstrumentationRegistry 20 import android.support.test.filters.SdkSuppress 21 import android.view.View 22 import android.view.ViewGroup 23 import android.widget.LinearLayout 24 import androidx.testutils.assertThrows 25 import androidx.testutils.fail 26 import com.google.common.truth.Truth.assertThat 27 import org.junit.Assert.assertEquals 28 import org.junit.Assert.assertFalse 29 import org.junit.Assert.assertSame 30 import org.junit.Assert.assertTrue 31 import org.junit.Test 32 33 class ViewGroupTest { 34 private val context = InstrumentationRegistry.getContext() 35 private val viewGroup = LinearLayout(context) 36 37 @Test fun get() { 38 val view1 = View(context) 39 viewGroup.addView(view1) 40 val view2 = View(context) 41 viewGroup.addView(view2) 42 43 assertSame(view1, viewGroup[0]) 44 assertSame(view2, viewGroup[1]) 45 46 assertThrows<IndexOutOfBoundsException> { 47 viewGroup[-1] 48 }.hasMessageThat().isEqualTo("Index: -1, Size: 2") 49 50 assertThrows<IndexOutOfBoundsException> { 51 viewGroup[2] 52 }.hasMessageThat().isEqualTo("Index: 2, Size: 2") 53 } 54 55 @Test fun contains() { 56 val view1 = View(context) 57 viewGroup.addView(view1) 58 assertTrue(view1 in viewGroup) 59 assertFalse(view1 !in viewGroup) 60 61 val view2 = View(context) 62 assertFalse(view2 in viewGroup) 63 assertTrue(view2 !in viewGroup) 64 } 65 66 @Test fun plusAssign() { 67 assertEquals(0, viewGroup.childCount) 68 69 val view1 = View(context) 70 viewGroup += view1 71 assertEquals(1, viewGroup.childCount) 72 assertSame(view1, viewGroup.getChildAt(0)) 73 74 val view2 = View(context) 75 viewGroup += view2 76 assertEquals(2, viewGroup.childCount) 77 assertSame(view2, viewGroup.getChildAt(1)) 78 } 79 80 @Test fun minusAssign() { 81 val view1 = View(context) 82 viewGroup.addView(view1) 83 val view2 = View(context) 84 viewGroup.addView(view2) 85 86 assertEquals(2, viewGroup.childCount) 87 88 viewGroup -= view2 89 assertEquals(1, viewGroup.childCount) 90 assertSame(view1, viewGroup.getChildAt(0)) 91 92 viewGroup -= view1 93 assertEquals(0, viewGroup.childCount) 94 } 95 96 @Test fun size() { 97 assertEquals(0, viewGroup.size) 98 99 viewGroup.addView(View(context)) 100 assertEquals(1, viewGroup.size) 101 102 viewGroup.addView(View(context)) 103 assertEquals(2, viewGroup.size) 104 105 viewGroup.removeViewAt(0) 106 assertEquals(1, viewGroup.size) 107 } 108 109 @Test fun isEmpty() { 110 assertTrue(viewGroup.isEmpty()) 111 viewGroup.addView(View(context)) 112 assertFalse(viewGroup.isEmpty()) 113 } 114 115 @Test fun isNotEmpty() { 116 assertFalse(viewGroup.isNotEmpty()) 117 viewGroup.addView(View(context)) 118 assertTrue(viewGroup.isNotEmpty()) 119 } 120 121 @Test fun forEach() { 122 viewGroup.forEach { 123 fail("Empty view group should not invoke lambda") 124 } 125 126 val view1 = View(context) 127 viewGroup.addView(view1) 128 val view2 = View(context) 129 viewGroup.addView(view2) 130 131 val views = mutableListOf<View>() 132 viewGroup.forEach { 133 views += it 134 } 135 assertThat(views).containsExactly(view1, view2) 136 } 137 138 @Test fun forEachIndexed() { 139 viewGroup.forEachIndexed { _, _ -> 140 fail("Empty view group should not invoke lambda") 141 } 142 143 val view1 = View(context) 144 viewGroup.addView(view1) 145 val view2 = View(context) 146 viewGroup.addView(view2) 147 148 val views = mutableListOf<View>() 149 viewGroup.forEachIndexed { index, view -> 150 assertEquals(index, views.size) 151 views += view 152 } 153 assertThat(views).containsExactly(view1, view2) 154 } 155 156 @Test fun iterator() { 157 val view1 = View(context) 158 viewGroup.addView(view1) 159 val view2 = View(context) 160 viewGroup.addView(view2) 161 162 val iterator = viewGroup.iterator() 163 assertTrue(iterator.hasNext()) 164 assertSame(view1, iterator.next()) 165 assertTrue(iterator.hasNext()) 166 assertSame(view2, iterator.next()) 167 assertFalse(iterator.hasNext()) 168 assertThrows<IndexOutOfBoundsException> { 169 iterator.next() 170 } 171 } 172 173 @Test fun iteratorRemoving() { 174 val view1 = View(context) 175 viewGroup.addView(view1) 176 val view2 = View(context) 177 viewGroup.addView(view2) 178 179 val iterator = viewGroup.iterator() 180 181 assertSame(view1, iterator.next()) 182 iterator.remove() 183 assertFalse(view1 in viewGroup) 184 assertEquals(1, viewGroup.childCount) 185 186 assertSame(view2, iterator.next()) 187 iterator.remove() 188 assertFalse(view2 in viewGroup) 189 assertEquals(0, viewGroup.childCount) 190 } 191 192 @Test fun iteratorForEach() { 193 val views = listOf(View(context), View(context)) 194 views.forEach(viewGroup::addView) 195 196 var index = 0 197 for (view in viewGroup) { 198 assertSame(views[index++], view) 199 } 200 } 201 202 @Test fun children() { 203 val views = listOf(View(context), View(context), View(context)) 204 views.forEach { viewGroup.addView(it) } 205 206 viewGroup.children.forEachIndexed { index, child -> 207 assertSame(views[index], child) 208 } 209 } 210 211 @Test fun setMargins() { 212 val layoutParams = ViewGroup.MarginLayoutParams(100, 200) 213 layoutParams.setMargins(42) 214 assertEquals(42, layoutParams.leftMargin) 215 assertEquals(42, layoutParams.topMargin) 216 assertEquals(42, layoutParams.rightMargin) 217 assertEquals(42, layoutParams.bottomMargin) 218 } 219 220 @Test fun updateMargins() { 221 val layoutParams = ViewGroup.MarginLayoutParams(100, 200) 222 layoutParams.updateMargins(top = 10, right = 20) 223 assertEquals(0, layoutParams.leftMargin) 224 assertEquals(10, layoutParams.topMargin) 225 assertEquals(20, layoutParams.rightMargin) 226 assertEquals(0, layoutParams.bottomMargin) 227 } 228 229 @Test fun updateMarginsNoOp() { 230 val layoutParams = ViewGroup.MarginLayoutParams(100, 200) 231 layoutParams.setMargins(10, 20, 30, 40) 232 layoutParams.updateMargins() 233 assertEquals(10, layoutParams.leftMargin) 234 assertEquals(20, layoutParams.topMargin) 235 assertEquals(30, layoutParams.rightMargin) 236 assertEquals(40, layoutParams.bottomMargin) 237 } 238 239 @SdkSuppress(minSdkVersion = 17) 240 @Test fun updateMarginsRelative() { 241 val layoutParams = ViewGroup.MarginLayoutParams(100, 200) 242 layoutParams.updateMarginsRelative(start = 10, end = 20) 243 assertEquals(0, layoutParams.leftMargin) 244 assertEquals(0, layoutParams.topMargin) 245 assertEquals(0, layoutParams.rightMargin) 246 assertEquals(0, layoutParams.bottomMargin) 247 assertEquals(10, layoutParams.marginStart) 248 assertEquals(20, layoutParams.marginEnd) 249 assertTrue(layoutParams.isMarginRelative) 250 } 251 252 @SdkSuppress(minSdkVersion = 17) 253 @Test fun updateMarginsRelativeNoOp() { 254 val layoutParams = ViewGroup.MarginLayoutParams(100, 200) 255 layoutParams.setMargins(10, 20, 30, 40) 256 layoutParams.updateMarginsRelative() 257 assertEquals(10, layoutParams.leftMargin) 258 assertEquals(20, layoutParams.topMargin) 259 assertEquals(30, layoutParams.rightMargin) 260 assertEquals(40, layoutParams.bottomMargin) 261 assertEquals(10, layoutParams.marginStart) 262 assertEquals(30, layoutParams.marginEnd) 263 } 264 } 265