1 /* 2 * Copyright 2024 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 @file:Suppress("UnstableApiUsage") 18 19 package androidx.wear.protolayout.lint 20 21 import androidx.wear.protolayout.lint.ResponsiveLayoutDetector.Companion.EDGE_CONTENT_LAYOUT_ISSUE 22 import androidx.wear.protolayout.lint.ResponsiveLayoutDetector.Companion.PRIMARY_LAYOUT_ISSUE 23 import com.android.tools.lint.checks.infrastructure.LintDetectorTest 24 import org.junit.Test 25 import org.junit.runner.RunWith 26 import org.junit.runners.JUnit4 27 28 @RunWith(JUnit4::class) 29 class EdgeContentLayoutResponsiveDetectorTest : LintDetectorTest() { getDetectornull30 override fun getDetector() = ResponsiveLayoutDetector() 31 32 override fun getIssues() = mutableListOf(PRIMARY_LAYOUT_ISSUE, EDGE_CONTENT_LAYOUT_ISSUE) 33 34 private val deviceParametersStub = 35 java( 36 """ 37 package androidx.wear.protolayout; 38 public class DeviceParameters {} 39 """ 40 .trimIndent() 41 ) 42 43 private val edgeContentLayoutStub = 44 java( 45 """ 46 package androidx.wear.protolayout.material.layouts; 47 48 import androidx.wear.protolayout.DeviceParameters; 49 50 public class EdgeContentLayout { 51 public static class Builder { 52 public Builder(DeviceParameters deviceParameters) {} 53 public Builder() {} 54 55 public Builder setResponsiveContentInsetEnabled(boolean enabled) { 56 return this; 57 } 58 59 public EdgeContentLayout build() { 60 return new EdgeContentLayout(); 61 } 62 } 63 } 64 """ 65 .trimIndent() 66 ) 67 68 @Test 69 fun `edgeContentLayout with responsiveness doesn't report`() { 70 lint() 71 .files( 72 deviceParametersStub, 73 edgeContentLayoutStub, 74 kotlin( 75 """ 76 package foo 77 import androidx.wear.protolayout.material.layouts.EdgeContentLayout 78 79 val layout = EdgeContentLayout.Builder(null) 80 .setResponsiveContentInsetEnabled(true) 81 .build() 82 83 class Bar { 84 val layout = EdgeContentLayout.Builder(null) 85 .setResponsiveContentInsetEnabled(true) 86 .build() 87 88 fun build() { 89 val l = EdgeContentLayout.Builder(null) 90 .setResponsiveContentInsetEnabled(true) 91 return l.build() 92 } 93 94 fun update() { 95 return EdgeContentLayout.Builder() 96 .setResponsiveContentInsetEnabled(true) 97 } 98 99 fun build2() { 100 update().build() 101 } 102 103 fun callRandom() { 104 random(EdgeContentLayout.Builder().setResponsiveContentInsetEnabled(true)) 105 } 106 fun random(val l: EdgeContentLayout.Builder) {} 107 108 } 109 """ 110 ) 111 .indented() 112 ) 113 .issues(EDGE_CONTENT_LAYOUT_ISSUE) 114 .run() 115 .expectClean() 116 } 117 118 @Test 119 fun `edgeContentLayout without responsiveness requires and fixes setter`() { 120 lint() 121 .files( 122 deviceParametersStub, 123 edgeContentLayoutStub, 124 kotlin( 125 """ 126 package foo 127 import androidx.wear.protolayout.material.layouts.EdgeContentLayout 128 129 val layout = EdgeContentLayout.Builder(null) 130 .setResponsiveContentInsetEnabled(false) 131 .build() 132 133 class Bar { 134 val layout = EdgeContentLayout.Builder(null) 135 .build() 136 137 val layoutFalse = EdgeContentLayout.Builder(null) 138 .setResponsiveContentInsetEnabled(false) 139 .build() 140 141 fun buildFalse() { 142 val l = EdgeContentLayout.Builder(null) 143 .setResponsiveContentInsetEnabled(false) 144 return l.build() 145 } 146 147 fun update() { 148 val enabled = false 149 EdgeContentLayout.Builder().setResponsiveContentInsetEnabled(enabled) 150 } 151 152 fun build() { 153 update().build() 154 } 155 156 fun build2() { 157 return EdgeContentLayout.Builder().build() 158 } 159 160 fun doubleFalse() { 161 EdgeContentLayout.Builder() 162 .setResponsiveContentInsetEnabled(true) 163 .setResponsiveContentInsetEnabled(false) 164 } 165 166 fun callRandom() { 167 random(EdgeContentLayout.Builder()) 168 } 169 fun random(val l: EdgeContentLayout.Builder) {} 170 171 fun condition(val cond: Boolean) { 172 val e = EdgeContentLayout.Builder() 173 if (cond) { 174 e.setResponsiveContentInsetEnabled(false) 175 } else { 176 e.setResponsiveContentInsetEnabled(true) 177 } 178 } 179 } 180 """ 181 ) 182 .indented() 183 ) 184 // To confirm they are not mixed up. 185 .issues(EDGE_CONTENT_LAYOUT_ISSUE, PRIMARY_LAYOUT_ISSUE) 186 .run() 187 .expect( 188 """ 189 src/foo/Bar.kt:4: Warning: EdgeContentLayout used, but responsiveness isn't set: Please call 190 setResponsiveContentInsetEnabled(true) for the best results across 191 different screen sizes and update to the looks of layout. [ProtoLayoutEdgeContentLayoutResponsive] 192 val layout = EdgeContentLayout.Builder(null) 193 ~~~~~~~~~~~~~~~~~~~~~~~~~ 194 src/foo/Bar.kt:9: Warning: EdgeContentLayout used, but responsiveness isn't set: Please call 195 setResponsiveContentInsetEnabled(true) for the best results across 196 different screen sizes and update to the looks of layout. [ProtoLayoutEdgeContentLayoutResponsive] 197 val layout = EdgeContentLayout.Builder(null) 198 ~~~~~~~~~~~~~~~~~~~~~~~~~ 199 src/foo/Bar.kt:12: Warning: EdgeContentLayout used, but responsiveness isn't set: Please call 200 setResponsiveContentInsetEnabled(true) for the best results across 201 different screen sizes and update to the looks of layout. [ProtoLayoutEdgeContentLayoutResponsive] 202 val layoutFalse = EdgeContentLayout.Builder(null) 203 ~~~~~~~~~~~~~~~~~~~~~~~~~ 204 src/foo/Bar.kt:17: Warning: EdgeContentLayout used, but responsiveness isn't set: Please call 205 setResponsiveContentInsetEnabled(true) for the best results across 206 different screen sizes and update to the looks of layout. [ProtoLayoutEdgeContentLayoutResponsive] 207 val l = EdgeContentLayout.Builder(null) 208 ~~~~~~~~~~~~~~~~~~~~~~~~~ 209 src/foo/Bar.kt:24: Warning: EdgeContentLayout used, but responsiveness isn't set: Please call 210 setResponsiveContentInsetEnabled(true) for the best results across 211 different screen sizes and update to the looks of layout. [ProtoLayoutEdgeContentLayoutResponsive] 212 EdgeContentLayout.Builder().setResponsiveContentInsetEnabled(enabled) 213 ~~~~~~~~~~~~~~~~~~~~~~~~~ 214 src/foo/Bar.kt:32: Warning: EdgeContentLayout used, but responsiveness isn't set: Please call 215 setResponsiveContentInsetEnabled(true) for the best results across 216 different screen sizes and update to the looks of layout. [ProtoLayoutEdgeContentLayoutResponsive] 217 return EdgeContentLayout.Builder().build() 218 ~~~~~~~~~~~~~~~~~~~~~~~~~ 219 src/foo/Bar.kt:36: Warning: EdgeContentLayout used, but responsiveness isn't set: Please call 220 setResponsiveContentInsetEnabled(true) for the best results across 221 different screen sizes and update to the looks of layout. [ProtoLayoutEdgeContentLayoutResponsive] 222 EdgeContentLayout.Builder() 223 ~~~~~~~~~~~~~~~~~~~~~~~~~ 224 src/foo/Bar.kt:42: Warning: EdgeContentLayout used, but responsiveness isn't set: Please call 225 setResponsiveContentInsetEnabled(true) for the best results across 226 different screen sizes and update to the looks of layout. [ProtoLayoutEdgeContentLayoutResponsive] 227 random(EdgeContentLayout.Builder()) 228 ~~~~~~~~~~~~~~~~~~~~~~~~~ 229 src/foo/Bar.kt:47: Warning: EdgeContentLayout used, but responsiveness isn't set: Please call 230 setResponsiveContentInsetEnabled(true) for the best results across 231 different screen sizes and update to the looks of layout. [ProtoLayoutEdgeContentLayoutResponsive] 232 val e = EdgeContentLayout.Builder() 233 ~~~~~~~~~~~~~~~~~~~~~~~~~ 234 0 errors, 9 warnings 235 """ 236 .trimIndent() 237 ) 238 .expectFixDiffs( 239 """ 240 Fix for src/foo/Bar.kt line 4: Call setResponsiveContentInsetEnabled(true) on layouts: 241 @@ -5 +5 242 - .setResponsiveContentInsetEnabled(false) 243 + .setResponsiveContentInsetEnabled(true) 244 Fix for src/foo/Bar.kt line 9: Call setResponsiveContentInsetEnabled(true) on layouts: 245 @@ -9 +9 246 - val layout = EdgeContentLayout.Builder(null) 247 + val layout = EdgeContentLayout.Builder(null).setResponsiveContentInsetEnabled(true) 248 Fix for src/foo/Bar.kt line 12: Call setResponsiveContentInsetEnabled(true) on layouts: 249 @@ -13 +13 250 - .setResponsiveContentInsetEnabled(false) 251 + .setResponsiveContentInsetEnabled(true) 252 Fix for src/foo/Bar.kt line 17: Call setResponsiveContentInsetEnabled(true) on layouts: 253 @@ -18 +18 254 - .setResponsiveContentInsetEnabled(false) 255 + .setResponsiveContentInsetEnabled(true) 256 Fix for src/foo/Bar.kt line 24: Call setResponsiveContentInsetEnabled(true) on layouts: 257 @@ -24 +24 258 - EdgeContentLayout.Builder().setResponsiveContentInsetEnabled(enabled) 259 + EdgeContentLayout.Builder().setResponsiveContentInsetEnabled(true) 260 Fix for src/foo/Bar.kt line 32: Call setResponsiveContentInsetEnabled(true) on layouts: 261 @@ -32 +32 262 - return EdgeContentLayout.Builder().build() 263 + return EdgeContentLayout.Builder().setResponsiveContentInsetEnabled(true).build() 264 Fix for src/foo/Bar.kt line 36: Call setResponsiveContentInsetEnabled(true) on layouts: 265 @@ -38 +38 266 - .setResponsiveContentInsetEnabled(false) 267 + .setResponsiveContentInsetEnabled(true) 268 Fix for src/foo/Bar.kt line 42: Call setResponsiveContentInsetEnabled(true) on layouts: 269 @@ -42 +42 270 - random(EdgeContentLayout.Builder()) 271 + random(EdgeContentLayout.Builder().setResponsiveContentInsetEnabled(true)) 272 Fix for src/foo/Bar.kt line 47: Call setResponsiveContentInsetEnabled(true) on layouts: 273 @@ -49 +49 274 - e.setResponsiveContentInsetEnabled(false) 275 + e.setResponsiveContentInsetEnabled(true) 276 """ 277 .trimIndent() 278 ) 279 } 280 281 @Test 282 fun `edgeContentLayout with responsiveness doesn't report (Java)`() { 283 lint() 284 .files( 285 deviceParametersStub, 286 edgeContentLayoutStub, 287 java( 288 """ 289 package foo; 290 import androidx.wear.protolayout.material.layouts.EdgeContentLayout; 291 292 class Bar { 293 EdgeContentLayout layout = new EdgeContentLayout.Builder(null) 294 .setResponsiveContentInsetEnabled(true) 295 .build(); 296 297 EdgeContentLayout build() { 298 EdgeContentLayout l = new EdgeContentLayout.Builder(null) 299 .setResponsiveContentInsetEnabled(true); 300 return l.build(); 301 } 302 303 EdgeContentLayout update() { 304 return new EdgeContentLayout.Builder() 305 .setResponsiveContentInsetEnabled(true); 306 } 307 308 EdgeContentLayout build2() { 309 update().build(); 310 } 311 } 312 """ 313 ) 314 .indented() 315 ) 316 .issues(EDGE_CONTENT_LAYOUT_ISSUE) 317 .run() 318 .expectClean() 319 } 320 321 @Test edgeContentLayout without responsiveness requires and fixes setter (Java)null322 fun `edgeContentLayout without responsiveness requires and fixes setter (Java)`() { 323 lint() 324 .files( 325 deviceParametersStub, 326 edgeContentLayoutStub, 327 java( 328 """ 329 package foo; 330 import androidx.wear.protolayout.material.layouts.EdgeContentLayout; 331 332 class Bar { 333 EdgeContentLayout layout = new EdgeContentLayout.Builder(null) 334 .build(); 335 336 EdgeContentLayout layoutFalse = new EdgeContentLayout.Builder(null) 337 .setResponsiveContentInsetEnabled(false) 338 .build(); 339 340 EdgeContentLayout buildFalse() { 341 EdgeContentLayout l = new EdgeContentLayout.Builder(null) 342 .setResponsiveContentInsetEnabled(false); 343 return l.build(); 344 } 345 346 void update() { 347 boolean enabled = false; 348 new EdgeContentLayout.Builder().setResponsiveContentInsetEnabled(enabled); 349 } 350 351 void build() { 352 update().build(); 353 } 354 355 EdgeContentLayout build2() { 356 return new EdgeContentLayout.Builder().build(); 357 } 358 359 void doubleFalse() { 360 new EdgeContentLayout.Builder() 361 .setResponsiveContentInsetEnabled(true) 362 .setResponsiveContentInsetEnabled(false); 363 } 364 } 365 """ 366 ) 367 .indented() 368 ) 369 .issues(EDGE_CONTENT_LAYOUT_ISSUE) 370 .run() 371 .expect( 372 """ 373 src/foo/Bar.java:5: Warning: EdgeContentLayout used, but responsiveness isn't set: Please call 374 setResponsiveContentInsetEnabled(true) for the best results across 375 different screen sizes and update to the looks of layout. [ProtoLayoutEdgeContentLayoutResponsive] 376 EdgeContentLayout layout = new EdgeContentLayout.Builder(null) 377 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 378 src/foo/Bar.java:8: Warning: EdgeContentLayout used, but responsiveness isn't set: Please call 379 setResponsiveContentInsetEnabled(true) for the best results across 380 different screen sizes and update to the looks of layout. [ProtoLayoutEdgeContentLayoutResponsive] 381 EdgeContentLayout layoutFalse = new EdgeContentLayout.Builder(null) 382 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 383 src/foo/Bar.java:13: Warning: EdgeContentLayout used, but responsiveness isn't set: Please call 384 setResponsiveContentInsetEnabled(true) for the best results across 385 different screen sizes and update to the looks of layout. [ProtoLayoutEdgeContentLayoutResponsive] 386 EdgeContentLayout l = new EdgeContentLayout.Builder(null) 387 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 388 src/foo/Bar.java:20: Warning: EdgeContentLayout used, but responsiveness isn't set: Please call 389 setResponsiveContentInsetEnabled(true) for the best results across 390 different screen sizes and update to the looks of layout. [ProtoLayoutEdgeContentLayoutResponsive] 391 new EdgeContentLayout.Builder().setResponsiveContentInsetEnabled(enabled); 392 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 393 src/foo/Bar.java:28: Warning: EdgeContentLayout used, but responsiveness isn't set: Please call 394 setResponsiveContentInsetEnabled(true) for the best results across 395 different screen sizes and update to the looks of layout. [ProtoLayoutEdgeContentLayoutResponsive] 396 return new EdgeContentLayout.Builder().build(); 397 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 398 src/foo/Bar.java:32: Warning: EdgeContentLayout used, but responsiveness isn't set: Please call 399 setResponsiveContentInsetEnabled(true) for the best results across 400 different screen sizes and update to the looks of layout. [ProtoLayoutEdgeContentLayoutResponsive] 401 new EdgeContentLayout.Builder() 402 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 403 0 errors, 6 warnings 404 """ 405 .trimIndent() 406 ) 407 .expectFixDiffs( 408 """ 409 Fix for src/foo/Bar.java line 5: Call setResponsiveContentInsetEnabled(true) on layouts: 410 @@ -5 +5 411 - EdgeContentLayout layout = new EdgeContentLayout.Builder(null) 412 + EdgeContentLayout layout = new EdgeContentLayout.Builder(null).setResponsiveContentInsetEnabled(true) 413 Fix for src/foo/Bar.java line 8: Call setResponsiveContentInsetEnabled(true) on layouts: 414 @@ -9 +9 415 - .setResponsiveContentInsetEnabled(false) 416 + .setResponsiveContentInsetEnabled(true) 417 Fix for src/foo/Bar.java line 13: Call setResponsiveContentInsetEnabled(true) on layouts: 418 @@ -14 +14 419 - .setResponsiveContentInsetEnabled(false); 420 + .setResponsiveContentInsetEnabled(true); 421 Fix for src/foo/Bar.java line 20: Call setResponsiveContentInsetEnabled(true) on layouts: 422 @@ -20 +20 423 - new EdgeContentLayout.Builder().setResponsiveContentInsetEnabled(enabled); 424 + new EdgeContentLayout.Builder().setResponsiveContentInsetEnabled(true); 425 Fix for src/foo/Bar.java line 28: Call setResponsiveContentInsetEnabled(true) on layouts: 426 @@ -28 +28 427 - return new EdgeContentLayout.Builder().build(); 428 + return new EdgeContentLayout.Builder().setResponsiveContentInsetEnabled(true).build(); 429 Fix for src/foo/Bar.java line 32: Call setResponsiveContentInsetEnabled(true) on layouts: 430 @@ -34 +34 431 - .setResponsiveContentInsetEnabled(false); 432 + .setResponsiveContentInsetEnabled(true); 433 """ 434 .trimIndent() 435 ) 436 } 437 438 @Test edgeContentLayout false reportnull439 fun `edgeContentLayout false report`() { 440 lint() 441 .files( 442 deviceParametersStub, 443 edgeContentLayoutStub, 444 kotlin( 445 """ 446 package foo 447 import androidx.wear.protolayout.material.layouts.EdgeContentLayout 448 449 450 fun doubleTrue() { 451 EdgeContentLayout.Builder() 452 .setResponsiveContentInsetEnabled(false) 453 .setResponsiveContentInsetEnabled(true) 454 } 455 """ 456 ) 457 .indented() 458 ) 459 .issues(EDGE_CONTENT_LAYOUT_ISSUE) 460 .run() 461 .expect( 462 """ 463 src/foo/test.kt:6: Warning: EdgeContentLayout used, but responsiveness isn't set: Please call 464 setResponsiveContentInsetEnabled(true) for the best results across 465 different screen sizes and update to the looks of layout. [ProtoLayoutEdgeContentLayoutResponsive] 466 EdgeContentLayout.Builder() 467 ~~~~~~~~~~~~~~~~~~~~~~~~~ 468 0 errors, 1 warnings 469 """ 470 .trimIndent() 471 ) 472 .expectFixDiffs( 473 """ 474 Fix for src/foo/test.kt line 6: Call setResponsiveContentInsetEnabled(true) on layouts: 475 @@ -7 +7 476 - .setResponsiveContentInsetEnabled(false) 477 @@ -9 +8 478 + .setResponsiveContentInsetEnabled(true) 479 """ 480 .trimIndent() 481 ) 482 } 483 } 484