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