Merge "New lint checks for static Settings.* usages" into tm-qpr-dev

This commit is contained in:
TreeHugger Robot
2022-10-19 20:44:06 +00:00
committed by Android (Google) Code Review
12 changed files with 396 additions and 28 deletions

View File

@@ -0,0 +1,100 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.internal.systemui.lint
import com.android.tools.lint.detector.api.Category
import com.android.tools.lint.detector.api.Detector
import com.android.tools.lint.detector.api.Implementation
import com.android.tools.lint.detector.api.Issue
import com.android.tools.lint.detector.api.JavaContext
import com.android.tools.lint.detector.api.Scope
import com.android.tools.lint.detector.api.Severity
import com.android.tools.lint.detector.api.SourceCodeScanner
import com.intellij.psi.PsiMethod
import org.jetbrains.uast.UCallExpression
private const val CLASS_SETTINGS = "android.provider.Settings"
/**
* Detects usage of static methods in android.provider.Settings and suggests to use an injected
* settings provider instance instead.
*/
@Suppress("UnstableApiUsage")
class StaticSettingsProviderDetector : Detector(), SourceCodeScanner {
override fun getApplicableMethodNames(): List<String> {
return listOf(
"getFloat",
"getInt",
"getLong",
"getString",
"getUriFor",
"putFloat",
"putInt",
"putLong",
"putString"
)
}
override fun visitMethodCall(context: JavaContext, node: UCallExpression, method: PsiMethod) {
val evaluator = context.evaluator
val className = method.containingClass?.qualifiedName
if (
className != "$CLASS_SETTINGS.Global" &&
className != "$CLASS_SETTINGS.Secure" &&
className != "$CLASS_SETTINGS.System"
) {
return
}
if (!evaluator.isStatic(method)) {
return
}
val subclassName = className.substring(CLASS_SETTINGS.length + 1)
context.report(
ISSUE,
method,
context.getNameLocation(node),
"`@Inject` a ${subclassName}Settings instead"
)
}
companion object {
@JvmField
val ISSUE: Issue =
Issue.create(
id = "StaticSettingsProvider",
briefDescription = "Static settings provider usage",
explanation =
"""
Static settings provider methods, such as `Settings.Global.putInt()`, should \
not be used because they make testing difficult. Instead, use an injected \
settings provider. For example, instead of calling `Settings.Secure.getInt()`, \
annotate the class constructor with `@Inject` and add `SecureSettings` to the \
parameters.
""",
category = Category.CORRECTNESS,
priority = 8,
severity = Severity.WARNING,
implementation =
Implementation(
StaticSettingsProviderDetector::class.java,
Scope.JAVA_FILE_SCOPE
)
)
}
}

View File

@@ -36,6 +36,7 @@ class SystemUIIssueRegistry : IssueRegistry() {
RegisterReceiverViaContextDetector.ISSUE,
SoftwareBitmapDetector.ISSUE,
NonInjectedServiceDetector.ISSUE,
StaticSettingsProviderDetector.ISSUE
)
override val api: Int

View File

@@ -24,6 +24,47 @@ import org.intellij.lang.annotations.Language
@NonNull
private fun indentedJava(@NonNull @Language("JAVA") source: String) = java(source).indented()
internal val commonSettingsCode =
"""
public static float getFloat(ContentResolver cr, String name) { return 0.0f; }
public static long getLong(ContentResolver cr, String name) {
return 0L;
}
public static int getInt(ContentResolver cr, String name) {
return 0;
}
public static String getString(ContentResolver cr, String name) {
return "";
}
public static float getFloat(ContentResolver cr, String name, float def) {
return 0.0f;
}
public static long getLong(ContentResolver cr, String name, long def) {
return 0L;
}
public static int getInt(ContentResolver cr, String name, int def) {
return 0;
}
public static String getString(ContentResolver cr, String name, String def) {
return "";
}
public static boolean putFloat(ContentResolver cr, String name, float value) {
return true;
}
public static boolean putLong(ContentResolver cr, String name, long value) {
return true;
}
public static boolean putInt(ContentResolver cr, String name, int value) {
return true;
}
public static boolean putFloat(ContentResolver cr, String name) {
return true;
}
public static boolean putString(ContentResolver cr, String name, String value) {
return true;
}
"""
/*
* This file contains stubs of framework APIs and System UI classes for testing purposes only. The
* stubs are not used in the lint detectors themselves.
@@ -184,6 +225,30 @@ import static java.lang.annotation.RetentionPolicy.SOURCE;
@Target({METHOD,CONSTRUCTOR,TYPE,PARAMETER})
public @interface WorkerThread {
}
"""
),
indentedJava(
"""
package android.provider;
public class Settings {
public static final class Global {
public static final String UNLOCK_SOUND = "unlock_sound";
""" +
commonSettingsCode +
"""
}
public static final class Secure {
""" +
commonSettingsCode +
"""
}
public static final class System {
""" +
commonSettingsCode +
"""
}
}
"""
),
)

View File

@@ -16,18 +16,15 @@
package com.android.internal.systemui.lint
import com.android.tools.lint.checks.infrastructure.LintDetectorTest
import com.android.tools.lint.checks.infrastructure.TestFiles
import com.android.tools.lint.checks.infrastructure.TestLintTask
import com.android.tools.lint.detector.api.Detector
import com.android.tools.lint.detector.api.Issue
import org.junit.Test
@Suppress("UnstableApiUsage")
class BindServiceOnMainThreadDetectorTest : LintDetectorTest() {
class BindServiceOnMainThreadDetectorTest : SystemUILintDetectorTest() {
override fun getDetector(): Detector = BindServiceOnMainThreadDetector()
override fun lint(): TestLintTask = super.lint().allowMissingSdk(true)
override fun getIssues(): List<Issue> = listOf(BindServiceOnMainThreadDetector.ISSUE)

View File

@@ -16,18 +16,15 @@
package com.android.internal.systemui.lint
import com.android.tools.lint.checks.infrastructure.LintDetectorTest
import com.android.tools.lint.checks.infrastructure.TestFiles
import com.android.tools.lint.checks.infrastructure.TestLintTask
import com.android.tools.lint.detector.api.Detector
import com.android.tools.lint.detector.api.Issue
import org.junit.Test
@Suppress("UnstableApiUsage")
class BroadcastSentViaContextDetectorTest : LintDetectorTest() {
class BroadcastSentViaContextDetectorTest : SystemUILintDetectorTest() {
override fun getDetector(): Detector = BroadcastSentViaContextDetector()
override fun lint(): TestLintTask = super.lint().allowMissingSdk(true)
override fun getIssues(): List<Issue> = listOf(BroadcastSentViaContextDetector.ISSUE)

View File

@@ -16,18 +16,15 @@
package com.android.internal.systemui.lint
import com.android.tools.lint.checks.infrastructure.LintDetectorTest
import com.android.tools.lint.checks.infrastructure.TestFiles
import com.android.tools.lint.checks.infrastructure.TestLintTask
import com.android.tools.lint.detector.api.Detector
import com.android.tools.lint.detector.api.Issue
import org.junit.Test
@Suppress("UnstableApiUsage")
class NonInjectedMainThreadDetectorTest : LintDetectorTest() {
class NonInjectedMainThreadDetectorTest : SystemUILintDetectorTest() {
override fun getDetector(): Detector = NonInjectedMainThreadDetector()
override fun lint(): TestLintTask = super.lint().allowMissingSdk(true)
override fun getIssues(): List<Issue> = listOf(NonInjectedMainThreadDetector.ISSUE)

View File

@@ -16,18 +16,15 @@
package com.android.internal.systemui.lint
import com.android.tools.lint.checks.infrastructure.LintDetectorTest
import com.android.tools.lint.checks.infrastructure.TestFiles
import com.android.tools.lint.checks.infrastructure.TestLintTask
import com.android.tools.lint.detector.api.Detector
import com.android.tools.lint.detector.api.Issue
import org.junit.Test
@Suppress("UnstableApiUsage")
class NonInjectedServiceDetectorTest : LintDetectorTest() {
class NonInjectedServiceDetectorTest : SystemUILintDetectorTest() {
override fun getDetector(): Detector = NonInjectedServiceDetector()
override fun lint(): TestLintTask = super.lint().allowMissingSdk(true)
override fun getIssues(): List<Issue> = listOf(NonInjectedServiceDetector.ISSUE)
@Test

View File

@@ -16,18 +16,15 @@
package com.android.internal.systemui.lint
import com.android.tools.lint.checks.infrastructure.LintDetectorTest
import com.android.tools.lint.checks.infrastructure.TestFiles
import com.android.tools.lint.checks.infrastructure.TestLintTask
import com.android.tools.lint.detector.api.Detector
import com.android.tools.lint.detector.api.Issue
import org.junit.Test
@Suppress("UnstableApiUsage")
class RegisterReceiverViaContextDetectorTest : LintDetectorTest() {
class RegisterReceiverViaContextDetectorTest : SystemUILintDetectorTest() {
override fun getDetector(): Detector = RegisterReceiverViaContextDetector()
override fun lint(): TestLintTask = super.lint().allowMissingSdk(true)
override fun getIssues(): List<Issue> = listOf(RegisterReceiverViaContextDetector.ISSUE)

View File

@@ -16,18 +16,15 @@
package com.android.internal.systemui.lint
import com.android.tools.lint.checks.infrastructure.LintDetectorTest
import com.android.tools.lint.checks.infrastructure.TestFiles
import com.android.tools.lint.checks.infrastructure.TestLintTask
import com.android.tools.lint.detector.api.Detector
import com.android.tools.lint.detector.api.Issue
import org.junit.Test
@Suppress("UnstableApiUsage")
class SlowUserQueryDetectorTest : LintDetectorTest() {
class SlowUserQueryDetectorTest : SystemUILintDetectorTest() {
override fun getDetector(): Detector = SlowUserQueryDetector()
override fun lint(): TestLintTask = super.lint().allowMissingSdk(true)
override fun getIssues(): List<Issue> =
listOf(

View File

@@ -16,18 +16,15 @@
package com.android.internal.systemui.lint
import com.android.tools.lint.checks.infrastructure.LintDetectorTest
import com.android.tools.lint.checks.infrastructure.TestFiles
import com.android.tools.lint.checks.infrastructure.TestLintTask
import com.android.tools.lint.detector.api.Detector
import com.android.tools.lint.detector.api.Issue
import org.junit.Test
@Suppress("UnstableApiUsage")
class SoftwareBitmapDetectorTest : LintDetectorTest() {
class SoftwareBitmapDetectorTest : SystemUILintDetectorTest() {
override fun getDetector(): Detector = SoftwareBitmapDetector()
override fun lint(): TestLintTask = super.lint().allowMissingSdk(true)
override fun getIssues(): List<Issue> = listOf(SoftwareBitmapDetector.ISSUE)

View File

@@ -0,0 +1,208 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.internal.systemui.lint
import com.android.tools.lint.checks.infrastructure.TestFiles
import com.android.tools.lint.detector.api.Detector
import com.android.tools.lint.detector.api.Issue
import org.junit.Test
@Suppress("UnstableApiUsage")
class StaticSettingsProviderDetectorTest : SystemUILintDetectorTest() {
override fun getDetector(): Detector = StaticSettingsProviderDetector()
override fun getIssues(): List<Issue> = listOf(StaticSettingsProviderDetector.ISSUE)
@Test
fun testGetServiceWithString() {
lint()
.files(
TestFiles.java(
"""
package test.pkg;
import android.provider.Settings;
import android.provider.Settings.Global;
import android.provider.Settings.Secure;
public class TestClass {
public void getSystemServiceWithoutDagger(Context context) {
final ContentResolver cr = mContext.getContentResolver();
Global.getFloat(cr, Settings.Global.UNLOCK_SOUND);
Global.getInt(cr, Settings.Global.UNLOCK_SOUND);
Global.getLong(cr, Settings.Global.UNLOCK_SOUND);
Global.getString(cr, Settings.Global.UNLOCK_SOUND);
Global.getFloat(cr, Settings.Global.UNLOCK_SOUND, 1f);
Global.getInt(cr, Settings.Global.UNLOCK_SOUND, 1);
Global.getLong(cr, Settings.Global.UNLOCK_SOUND, 1L);
Global.getString(cr, Settings.Global.UNLOCK_SOUND, "1");
Global.putFloat(cr, Settings.Global.UNLOCK_SOUND, 1f);
Global.putInt(cr, Settings.Global.UNLOCK_SOUND, 1);
Global.putLong(cr, Settings.Global.UNLOCK_SOUND, 1L);
Global.putString(cr, Settings.Global.UNLOCK_SOUND, "1");
Secure.getFloat(cr, Settings.Secure.ASSIST_GESTURE_ENABLED);
Secure.getInt(cr, Settings.Secure.ASSIST_GESTURE_ENABLED);
Secure.getLong(cr, Settings.Secure.ASSIST_GESTURE_ENABLED);
Secure.getString(cr, Settings.Secure.ASSIST_GESTURE_ENABLED);
Secure.getFloat(cr, Settings.Secure.ASSIST_GESTURE_ENABLED, 1f);
Secure.getInt(cr, Settings.Secure.ASSIST_GESTURE_ENABLED, 1);
Secure.getLong(cr, Settings.Secure.ASSIST_GESTURE_ENABLED, 1L);
Secure.getString(cr, Settings.Secure.ASSIST_GESTURE_ENABLED, "1");
Secure.putFloat(cr, Settings.Secure.ASSIST_GESTURE_ENABLED, 1f);
Secure.putInt(cr, Settings.Secure.ASSIST_GESTURE_ENABLED, 1);
Secure.putLong(cr, Settings.Secure.ASSIST_GESTURE_ENABLED, 1L);
Secure.putString(cr, Settings.Secure.ASSIST_GESTURE_ENABLED, "1");
Settings.System.getFloat(cr, Settings.System.SCREEN_OFF_TIMEOUT);
Settings.System.getInt(cr, Settings.System.SCREEN_OFF_TIMEOUT);
Settings.System.getLong(cr, Settings.System.SCREEN_OFF_TIMEOUT);
Settings.System.getString(cr, Settings.System.SCREEN_OFF_TIMEOUT);
Settings.System.getFloat(cr, Settings.System.SCREEN_OFF_TIMEOUT, 1f);
Settings.System.getInt(cr, Settings.System.SCREEN_OFF_TIMEOUT, 1);
Settings.System.getLong(cr, Settings.System.SCREEN_OFF_TIMEOUT, 1L);
Settings.System.getString(cr, Settings.System.SCREEN_OFF_TIMEOUT, "1");
Settings.System.putFloat(cr, Settings.System.SCREEN_OFF_TIMEOUT, 1f);
Settings.System.putInt(cr, Settings.System.SCREEN_OFF_TIMEOUT, 1);
Settings.System.putLong(cr, Settings.System.SCREEN_OFF_TIMEOUT, 1L);
Settings.System.putString(cr, Settings.Global.UNLOCK_SOUND, "1");
}
}
"""
)
.indented(),
*stubs
)
.issues(StaticSettingsProviderDetector.ISSUE)
.run()
.expect(
"""
src/test/pkg/TestClass.java:10: Warning: @Inject a GlobalSettings instead [StaticSettingsProvider]
Global.getFloat(cr, Settings.Global.UNLOCK_SOUND);
~~~~~~~~
src/test/pkg/TestClass.java:11: Warning: @Inject a GlobalSettings instead [StaticSettingsProvider]
Global.getInt(cr, Settings.Global.UNLOCK_SOUND);
~~~~~~
src/test/pkg/TestClass.java:12: Warning: @Inject a GlobalSettings instead [StaticSettingsProvider]
Global.getLong(cr, Settings.Global.UNLOCK_SOUND);
~~~~~~~
src/test/pkg/TestClass.java:13: Warning: @Inject a GlobalSettings instead [StaticSettingsProvider]
Global.getString(cr, Settings.Global.UNLOCK_SOUND);
~~~~~~~~~
src/test/pkg/TestClass.java:14: Warning: @Inject a GlobalSettings instead [StaticSettingsProvider]
Global.getFloat(cr, Settings.Global.UNLOCK_SOUND, 1f);
~~~~~~~~
src/test/pkg/TestClass.java:15: Warning: @Inject a GlobalSettings instead [StaticSettingsProvider]
Global.getInt(cr, Settings.Global.UNLOCK_SOUND, 1);
~~~~~~
src/test/pkg/TestClass.java:16: Warning: @Inject a GlobalSettings instead [StaticSettingsProvider]
Global.getLong(cr, Settings.Global.UNLOCK_SOUND, 1L);
~~~~~~~
src/test/pkg/TestClass.java:17: Warning: @Inject a GlobalSettings instead [StaticSettingsProvider]
Global.getString(cr, Settings.Global.UNLOCK_SOUND, "1");
~~~~~~~~~
src/test/pkg/TestClass.java:18: Warning: @Inject a GlobalSettings instead [StaticSettingsProvider]
Global.putFloat(cr, Settings.Global.UNLOCK_SOUND, 1f);
~~~~~~~~
src/test/pkg/TestClass.java:19: Warning: @Inject a GlobalSettings instead [StaticSettingsProvider]
Global.putInt(cr, Settings.Global.UNLOCK_SOUND, 1);
~~~~~~
src/test/pkg/TestClass.java:20: Warning: @Inject a GlobalSettings instead [StaticSettingsProvider]
Global.putLong(cr, Settings.Global.UNLOCK_SOUND, 1L);
~~~~~~~
src/test/pkg/TestClass.java:21: Warning: @Inject a GlobalSettings instead [StaticSettingsProvider]
Global.putString(cr, Settings.Global.UNLOCK_SOUND, "1");
~~~~~~~~~
src/test/pkg/TestClass.java:23: Warning: @Inject a SecureSettings instead [StaticSettingsProvider]
Secure.getFloat(cr, Settings.Secure.ASSIST_GESTURE_ENABLED);
~~~~~~~~
src/test/pkg/TestClass.java:24: Warning: @Inject a SecureSettings instead [StaticSettingsProvider]
Secure.getInt(cr, Settings.Secure.ASSIST_GESTURE_ENABLED);
~~~~~~
src/test/pkg/TestClass.java:25: Warning: @Inject a SecureSettings instead [StaticSettingsProvider]
Secure.getLong(cr, Settings.Secure.ASSIST_GESTURE_ENABLED);
~~~~~~~
src/test/pkg/TestClass.java:26: Warning: @Inject a SecureSettings instead [StaticSettingsProvider]
Secure.getString(cr, Settings.Secure.ASSIST_GESTURE_ENABLED);
~~~~~~~~~
src/test/pkg/TestClass.java:27: Warning: @Inject a SecureSettings instead [StaticSettingsProvider]
Secure.getFloat(cr, Settings.Secure.ASSIST_GESTURE_ENABLED, 1f);
~~~~~~~~
src/test/pkg/TestClass.java:28: Warning: @Inject a SecureSettings instead [StaticSettingsProvider]
Secure.getInt(cr, Settings.Secure.ASSIST_GESTURE_ENABLED, 1);
~~~~~~
src/test/pkg/TestClass.java:29: Warning: @Inject a SecureSettings instead [StaticSettingsProvider]
Secure.getLong(cr, Settings.Secure.ASSIST_GESTURE_ENABLED, 1L);
~~~~~~~
src/test/pkg/TestClass.java:30: Warning: @Inject a SecureSettings instead [StaticSettingsProvider]
Secure.getString(cr, Settings.Secure.ASSIST_GESTURE_ENABLED, "1");
~~~~~~~~~
src/test/pkg/TestClass.java:31: Warning: @Inject a SecureSettings instead [StaticSettingsProvider]
Secure.putFloat(cr, Settings.Secure.ASSIST_GESTURE_ENABLED, 1f);
~~~~~~~~
src/test/pkg/TestClass.java:32: Warning: @Inject a SecureSettings instead [StaticSettingsProvider]
Secure.putInt(cr, Settings.Secure.ASSIST_GESTURE_ENABLED, 1);
~~~~~~
src/test/pkg/TestClass.java:33: Warning: @Inject a SecureSettings instead [StaticSettingsProvider]
Secure.putLong(cr, Settings.Secure.ASSIST_GESTURE_ENABLED, 1L);
~~~~~~~
src/test/pkg/TestClass.java:34: Warning: @Inject a SecureSettings instead [StaticSettingsProvider]
Secure.putString(cr, Settings.Secure.ASSIST_GESTURE_ENABLED, "1");
~~~~~~~~~
src/test/pkg/TestClass.java:36: Warning: @Inject a SystemSettings instead [StaticSettingsProvider]
Settings.System.getFloat(cr, Settings.System.SCREEN_OFF_TIMEOUT);
~~~~~~~~
src/test/pkg/TestClass.java:37: Warning: @Inject a SystemSettings instead [StaticSettingsProvider]
Settings.System.getInt(cr, Settings.System.SCREEN_OFF_TIMEOUT);
~~~~~~
src/test/pkg/TestClass.java:38: Warning: @Inject a SystemSettings instead [StaticSettingsProvider]
Settings.System.getLong(cr, Settings.System.SCREEN_OFF_TIMEOUT);
~~~~~~~
src/test/pkg/TestClass.java:39: Warning: @Inject a SystemSettings instead [StaticSettingsProvider]
Settings.System.getString(cr, Settings.System.SCREEN_OFF_TIMEOUT);
~~~~~~~~~
src/test/pkg/TestClass.java:40: Warning: @Inject a SystemSettings instead [StaticSettingsProvider]
Settings.System.getFloat(cr, Settings.System.SCREEN_OFF_TIMEOUT, 1f);
~~~~~~~~
src/test/pkg/TestClass.java:41: Warning: @Inject a SystemSettings instead [StaticSettingsProvider]
Settings.System.getInt(cr, Settings.System.SCREEN_OFF_TIMEOUT, 1);
~~~~~~
src/test/pkg/TestClass.java:42: Warning: @Inject a SystemSettings instead [StaticSettingsProvider]
Settings.System.getLong(cr, Settings.System.SCREEN_OFF_TIMEOUT, 1L);
~~~~~~~
src/test/pkg/TestClass.java:43: Warning: @Inject a SystemSettings instead [StaticSettingsProvider]
Settings.System.getString(cr, Settings.System.SCREEN_OFF_TIMEOUT, "1");
~~~~~~~~~
src/test/pkg/TestClass.java:44: Warning: @Inject a SystemSettings instead [StaticSettingsProvider]
Settings.System.putFloat(cr, Settings.System.SCREEN_OFF_TIMEOUT, 1f);
~~~~~~~~
src/test/pkg/TestClass.java:45: Warning: @Inject a SystemSettings instead [StaticSettingsProvider]
Settings.System.putInt(cr, Settings.System.SCREEN_OFF_TIMEOUT, 1);
~~~~~~
src/test/pkg/TestClass.java:46: Warning: @Inject a SystemSettings instead [StaticSettingsProvider]
Settings.System.putLong(cr, Settings.System.SCREEN_OFF_TIMEOUT, 1L);
~~~~~~~
src/test/pkg/TestClass.java:47: Warning: @Inject a SystemSettings instead [StaticSettingsProvider]
Settings.System.putString(cr, Settings.Global.UNLOCK_SOUND, "1");
~~~~~~~~~
0 errors, 36 warnings
"""
)
}
private val stubs = androidStubs
}

View File

@@ -0,0 +1,15 @@
package com.android.internal.systemui.lint
import com.android.tools.lint.checks.infrastructure.LintDetectorTest
import com.android.tools.lint.checks.infrastructure.TestLintTask
import java.io.File
@Suppress("UnstableApiUsage")
abstract class SystemUILintDetectorTest : LintDetectorTest() {
/**
* Customize the lint task to disable SDK usage completely. This ensures that running the tests
* in Android Studio has the same result as running the tests in atest
*/
override fun lint(): TestLintTask =
super.lint().allowMissingSdk(true).sdkHome(File("/dev/null"))
}